Skip to content

Send assistant messages in Responses requests - #401

Merged
mattt merged 5 commits into
mainfrom
mattt/responses-assistant-messages
Nov 6, 2026
Merged

mattt merged 5 commits into
mainfrom
mattt/responses-assistant-messages

Conversation

@mattt

@mattt mattt commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

The OpenAI Responses and Open Responses request builders dropped every assistant message, so in a multi-turn session the model saw only the user's side of the conversation. Both builders now send each earlier answer as an input item, and a tool round's text stays with that round's calls, so a later turn sends each piece of text once, including after a model handoff or from a saved transcript. A transcript saved by 1.1.1 replays a tool round's text in the response rather than with the calls. Replay also now follows history edits: if a response has changed, or a finished turn has no response, only the current text and the calls are sent. This applies to Chat Completions and Gemini as well, where an edited answer could otherwise still send the original text. In Gemini, an edited answer is sent without its old text signature, and a tool round's unsigned text is no longer sent twice. Text that a model wrote after a function call replays before that call, and a cancelled turn replays its calls and outputs without the round's text.

mattt added 5 commits November 6, 2026 01:59
The OpenAI Responses and Open Responses builders dropped every assistant
message, so a later turn showed the model only the user's side.
Send each answer as an input item, and keep a tool round's text with its calls
so that replay sends each piece of text once, in order.
Replay used a response's metadata even after a caller edited the response,
so removed text could reach the server. Apply the metadata only to a response
that is unchanged since it was written; otherwise send its segments, and the
turn's tool rounds send only their calls.
A handoff also lost text that no tool round carried. Keep that text on the response.
Gemini restored stored text parts and their signatures without checking the
response's current segments, so an edited answer still sent the original text.
Use stored parts only for text the segments still contain.
A stopped structured stream's JSON was both the response and the tool round's
text, so it could be sent twice or survive an edit. Treat it as the response's.
A stopped string stream marked its response with the OpenAI metadata keys, so
Chat Completions, Responses, and Open Responses replayed an empty response and
dropped the round's text. Gemini's replay doesn't need the marker for a string
response, so leave it out. Add tests of several tool rounds in one turn.
A stop returns the round's JSON as the response, but the tool round kept the
same text in its metadata. Rebuilding or removing the response discarded the
marker that replay used to clean it up, so the original text was still sent.
Don't keep the text on the round, and remove the marker and that cleanup.
@mattt
mattt merged commit 489c5a9 into main Nov 6, 2026
12 checks passed
@mattt
mattt deleted the mattt/responses-assistant-messages branch November 6, 2026 15:18
mattt added a commit to gtokman/AnyLanguageModel that referenced this pull request Nov 6, 2026
Replay treated each prompt as the start of a turn, so a message from
pendingMessages(in:) ended the turn early. The rounds before the message lost
their text on a later turn, which breaks "each piece of text is sent once and
in order" from huggingface#401. Mark these prompts, and keep the mark in saved transcripts,
because a prompt's position can't separate them from a later turn's prompt.
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.

1 participant