fix(responses): done-event repair must not clobber tool-call identity (#244) - #246
Merged
Merged
Conversation
…#244) The 0.7.7 #244 repair delta forwarded id: firstString(call_id, item_id). The real luna function_call_arguments.done event carries only item_id (fc_1) — never call_id — so the accumulator adopted the item id, replacing the real call_* id captured from output_item.added. Item ids are reused across turns: two turns both carrying fc_1 produced two function_call items against one function_call_output at the gateway, which rejects the request with 400 "No tool output found for function call call_*". Three-layer fix: - done event forwards id only when a real call_id is present (arguments- only repair — the #244 arguments fix is preserved) - ToolCallAccumulator captures the id once, never overwritten by later fragments - pairResponsesFunctionCallItems collapses duplicate function_call items sharing a call_id, self-healing histories poisoned by 0.7.7 Proven empirically against the captured luna event shapes: part id stays call_* end to end. 4 regression tests; 493/493 pass. Version bump 0.7.8. Docs: docs/issues/108, doc 107 annotated, CHANGELOG 0.7.8, devlog, ARCHITECTURE-MAP.
Post-fix audit found the #244-followup fallback (firstString(call_id, item_id)) in two more places: the output_item.added handler and the normalizeResponsesFullResponse function_call mapping. Both now derive call identity from call_id only — item ids (fc_*) are reused across turns and must never become call identity. Gateways that send call_id (all known real shapes) are unaffected. Adds 2 regression tests and a 17-check pre-release E2E simulating the full tool-call loop: whitespace preservation, wire pairing per turn, cross-turn item-id reuse, and poisoned-history self-heal. 495/495 unit tests, lint 7/7, retry E2E 9/9.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #244. Fixes the 0.7.7 regression reported in this comment: after updating, every OpenAI-model request fails with
400 No tool output found for function call call_*.Root cause
The #244 fix (0.7.7) added a
response.function_call_arguments.donerepair delta withid: firstString(call_id, item_id). The real luna done event carries onlyitem_id(fc_1) — nevercall_id— so the accumulator adopted the item id, REPLACING the realcall_*id captured fromoutput_item.added. Item ids are reused across turns: two turns both carryingfc_1produced twofunction_callitems against onefunction_call_outputat the gateway, which rejects the whole request.Proven empirically by replaying the captured luna event shapes: part id came out
fc_1instead ofcall_Vf1vzJwf5xa44CfwtrzYe4y7.Fix (3 layers + identity rule)
src/core/routing.tsidonly when a realcall_idis present — repair is arguments-onlysrc/toolCallAccumulator.tssrc/responsesRequest.tspairResponsesFunctionCallItemscollapses duplicatefunction_callitems sharing a call_id — histories poisoned by 0.7.7 recover without clearing the chatIdentity rule enforced on every Responses entry point:
output_item.addedandnormalizeResponsesFullResponseno longer fall back toitem.ideither.The original #244 arguments-whitespace fix is preserved and pinned by test.
Verification
src/test/issue244-followup-regression.test.ts(identity preserved, round-trip pairing, arguments repair preserved, poisoned-history dedupe, added-handler id rule, full-response id rule)tmp/e2e-issue244-prerelease.mjs): full tool-call loop over the captured luna shapes — whitespace preserved, wire pairing 1:1 per turn, cross-turn item-id reuse clean, poisoned history self-healsNotes for merge
Per repo policy: merge commit (
gh pr merge --merge), no squash.