Skip to content

Stateful responses API support#443

Merged
sidnarayanan merged 10 commits intomainfrom
stateful-responses
Apr 7, 2026
Merged

Stateful responses API support#443
sidnarayanan merged 10 commits intomainfrom
stateful-responses

Conversation

@sidnarayanan
Copy link
Copy Markdown
Collaborator

Better version of #389, don't need to make stateless assumption

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds opt-in support for OpenAI’s stateful Responses API to the lmi LiteLLM wrapper, enabling multi-turn continuity via previous_response_id rather than requiring a stateless full-history assumption.

Changes:

  • Introduces Responses API request/response conversion helpers and a new LiteLLMModel Responses API execution path (streaming + non-streaming).
  • Tracks and propagates response_id through LLMResult and Message.info for stateful follow-up calls.
  • Adds tests for delta detection, conversion/parsing helpers, and call behavior; introduces USE_RESPONSES_API env flag and adds orjson dependency.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/lmi/src/lmi/llms.py Adds Responses API conversion/parsing utilities and integrates a stateful Responses API call path (including streaming).
packages/lmi/src/lmi/types.py Extends LLMResult with response_id to support stateful multi-turn.
packages/lmi/src/lmi/constants.py Adds USE_RESPONSES_API env-controlled feature flag.
packages/lmi/tests/test_llms.py Adds unit tests covering Responses API helpers and stateful call behavior.
packages/lmi/pyproject.toml Adds orjson dependency to support litellm Responses API requirements.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/lmi/src/lmi/llms.py Outdated
Comment thread packages/lmi/src/lmi/llms.py
Comment thread packages/lmi/src/lmi/llms.py Outdated
Comment thread packages/lmi/src/lmi/llms.py
Comment thread packages/lmi/src/lmi/llms.py Outdated
Comment thread packages/lmi/src/lmi/llms.py Outdated
else:
converted.append(item)
return converted
except json.JSONDecodeError:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to just blow up here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is run over all tool responses, and it's very possible for a tool response to start with [ (I think InterpreterEnv might prepend [stdout]?).

I added a logger.warning instead of making it silent.

Copy link
Copy Markdown
Collaborator

@jamesbraza jamesbraza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! Huge win for us

Comment thread packages/lmi/src/lmi/llms.py Outdated
Comment on lines +91 to +99
def _convert_tool_response_content(content: str | None) -> str | list[dict[str, Any]]:
"""Convert tool response content to Responses API format.

Aviary stores images as JSON: [{"type": "image_url", "image_url": {"url": "..."}}]
Responses API expects: [{"type": "input_image", "image_url": "..."}]
"""
if not content:
return ""
if content.startswith("["):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we pass the entire ToolResponseMessage here, not just content?

The reason is, the if content.startswith("["): -- this can be better done with message.content_is_json_str

Also imo there may be other cases in the future where you need the full message to make a conversion.

My most ideal here is to make this a method of ToolResponseMessage. Then you can just do:

tool_response: ToolResponseMessage
tool_response.to_responses_api()

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is a good idea, I moved to it. However, I did not go so far as .to_responses_api() - that would have to be in aviary, and I don't want to upstream this logic that far.

Comment thread packages/lmi/src/lmi/llms.py Outdated
Comment thread packages/lmi/src/lmi/llms.py
Comment thread packages/lmi/src/lmi/llms.py
@sidnarayanan sidnarayanan merged commit 33e4ca4 into main Apr 7, 2026
7 checks passed
@sidnarayanan sidnarayanan deleted the stateful-responses branch April 7, 2026 21:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants