Repository navigation
Description
Description
Streaming from an OpenAI-Responses-compatible gateway that serializes the (optional) namespace field of a function_call item as JSON null fails on the first tool call:
AI.Error.InvalidProviderOutput: Invalid lunaroute/openai-responses stream event
[cause]: SchemaError: Expected string | undefined
at ["item"]["namespace"]
The session errors out (Failed to drain Session), so any tool call, including a subagent fan-out, is unusable with such a provider. Plain text turns work.
Cause: StreamItem in packages/ai/src/protocols/open-responses.ts decodes namespace as Schema.optional(Schema.String) (line 337 at v2.0.25, unchanged on dev and v2), while the neighbouring encrypted_content already uses optionalNull(...) and Event.item itself is optionalNull(StreamItem). Every Responses-based route shares this schema (openai-responses.ts reuses OpenResponses.protocol.stream.event), so @opencode/ai/providers/openai, …/openai-compatible/responses and the host-specific */responses packages are all affected.
Proposed fix: namespace: optionalNull(Schema.String) (and the same on the function_call item schema around line 208), treating null as absent where item.namespace is read (ToolStream.start / toolInputStart). Happy to send a PR if that is the preferred shape.
Related
Not a duplicate as far as I can tell. Nearest reports are about other parsers or frame classes: #40690 (chat parser rejected tool-call deltas, fixed in #40798), #50314 (data: null frames, fixed by dropping non-object payloads), #54102 (mixed LF/CRLF, fixed by the effect bump), #54330 (injected metadata frames, v1). #53405 recently widened OpenResponsesUsage to keep gateway fields, which is the same direction as this request.
Plugins
@lunaroute/opencode-extension (dev version for compatibility with opencode v2)
OpenCode version
2.0.25 (Homebrew)
Steps to reproduce
-
Run a minimal Responses-style server that streams one function call whose item carries
"namespace": null:// fake.cjs — node fake.cjs require("node:http").createServer((req, res) => { if (req.url === "/v1/models") return res.end(JSON.stringify({ data: [{ id: "m" }] })) const fc = { type: "function_call", id: "fc_1", call_id: "call_1", name: "glob", namespace: null, arguments: '{"pattern":"*.md"}' } const events = [ { type: "response.created", response: { id: "r1", output: [] } }, { type: "response.output_item.added", output_index: 0, item: { ...fc, arguments: "" } }, { type: "response.function_call_arguments.done", item_id: "fc_1", output_index: 0, arguments: fc.arguments }, { type: "response.output_item.done", output_index: 0, item: fc }, { type: "response.completed", response: { id: "r1", output: [fc], usage: { input_tokens: 1, output_tokens: 1 } } }, ] res.writeHead(200, { "content-type": "text/event-stream" }) for (const e of events) res.write(`event: ${e.type}\ndata: ${JSON.stringify(e)}\n\n`) res.end() }).listen(4599)
-
Point a provider at it in
opencode.json:{ "provider": { "fake": { "name": "Fake", "package": "@opencode/ai/providers/openai", "settings": { "baseURL": "http://127.0.0.1:4599/v1", "apiKey": "x" }, "models": { "m": { "name": "m" } } } } } -
Send any prompt to
fake/m. The first turn fails with the error above; the server log showsSchemaError: Expected string | undefined at ["item"]["namespace"]. -
Delete
namespace: nullfrom the item (or change it to a string) and the same stream parses, the tool runs, and the session continues.
Screenshot and/or share link
n/a (reproduced headlessly via opencode serve + the HTTP API; log excerpt above).
Operating System
macOS 27.0.1 (arm64)
Terminal
n/a (server-side parsing)
Activity
opencode-agent commentedon Oct 14, 2026
Thanks for the detailed report and the minimal server. I reproduced this on 2.0.25, and it still happens on the latest
dev(3943b84).What I did:
globfunction_callitem with"namespace": null, then replies with text once the tool result comes back.@opencode/ai/providers/openaiprovider at it and ranopencode run -m fake/m "list markdown files".Invalid fake/openai-responses stream event, the tool never runs, and the server log showsFailed to drain Session.OpenResponses.protocol.stream.eventondevgives the same error as yours:Expected string | undefined at ["item"]["namespace"].The script below reproduces it. Run it as is for the released version, or with
OC_DEV=<checkout>to run from source;NS=omitsends the stream without the field as a control.One small note on the steps: in v2 the config key is
providers, notprovider. Withprovideryou get an unrelated "Unsupported package" error instead.Related Responses-compatibility issues, not duplicates: #50314 (
data: nullframes), #43732 (a gateway sending"truncation": ""), #55357 (replayed reasoning items sent withoutid).Reproduction script (repro.sh)
Run it:
bash repro.shfix(ai): accept null namespace on function_call items
rekram1-node commentedon Oct 15, 2026
merged a fix, will prolly loosen some more areas that are too strict