Repository navigation
Conversation
10 tasks
injectResponsesInputSystem and containsPromptInResponsesInput both required
item.type === "message" to recognise a message item. The Responses API lets an
input[] message item leave `type` off — it defaults to "message" — and native
clients do. Such a system item was therefore invisible to the injector, which
fell through to its else branch and prepended a second system message beside
the one already there:
input: [{ role: "system", content: [{type:"input_text", text:"you are a helper"}] },
{ role: "user", content: [{type:"input_text", text:"hi"}] }]
-> 3 items, two of them role:"system", the original never appended to
The repo already reads an absent type as a message in three other places:
open-sse/executors/codex.js:53 item.role === "system" && (!item.type || item.type === "message")
open-sse/executors/grok-cli.js:79 item.role === "user" && (!type || type === "message")
open-sse/rtk/headroom.js:96 typeof item.type === "string" && item.type !== "message"
and tests/unit/continuity-strip.test.js builds its own fixture without the
field. systemInject.js was the outlier, so the fix follows the existing idiom
rather than introducing a new one.
The scan in containsPromptInResponsesInput is fixed alongside it. That half is
narrower than it looks: appendToResponsesMessage already dedups, so the scan
only decides the case where the prompt sits in a different system item than the
one findIndex returns. A test covers exactly that case.
ntdatt812
force-pushed
the
fix/untyped-responses-message-item
branch
from
September 9, 2026 03:31
bfd079a to
cc19c1a
Compare
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.
injectResponsesInputSystemandcontainsPromptInResponsesInputboth requireitem.type === "message"to recognise a message item in a Responsesinput[]. That field is optional — it defaults to"message"— and native clients leave it off. A system item written that way is invisible to the injector, so it falls through to the else branch and prepends a second system message beside the one already there.Measured on
master(90b52e06), running the injector directly:Two
role:"system"items go upstream, and the caller's own system prompt is never appended to. This only reaches native-passthrough traffic: bodies this repo builds itself always stamp the field (translator/request/openai-responses.js:369), which is why nothing caught it.Why "no type means message" is this repo's existing reading
Three other call sites already treat an absent type that way:
open-sse/executors/codex.jsitem.role === "system" && (!item.type || item.type === "message")open-sse/executors/grok-cli.jsitem.role === "user" && (!type || type === "message")open-sse/rtk/headroom.jstypeof item.type === "string" && item.type !== "message"— an item with no type string is not excludedand
tests/unit/continuity-strip.test.js:21builds its own fixture without the field.systemInject.jswas the outlier, so the fix follows the existing idiom instead of inventing a new one.On the second half of the diff
I fixed the scan in
containsPromptInResponsesInputalongside it, and it is narrower than it looks.appendToResponsesMessagealready dedups (c.some(b => b && b.text === prompt), anddedupStringAppendfor the string case), so the scan only decides the case where the prompt sits in a different system item than the onefindIndexreturns. The fifth test covers exactly that case, and it is the only one that fails if that half is reverted. Saying so explicitly in case you would rather drop it — the first half stands on its own.Tests
Six tests in
tests/unit/system-inject-untyped-item.test.js, including the two negatives that keep the change honest: afunction_callitem carrying a strayrolefield is still skipped, and a body with no system item at all still gets one prepended.Mutation-checked in both directions:
findIndexhalfcontainsPromptInResponsesInputhalfSuite
npx vitest run tests/unit --config tests/vitest.config.jsmaster(90b52e06)Same 75 by name, compared as a set rather than a count — no new failures, and the six added tests account for the delta. Those 75 are pre-existing on a clean
mastercheckout on this host (Windows, Node 24); I have not touched them.