anomalyco / anomalyco/opencode

[BUG] OpenAI Responses: assistant messages sent as {role:"assistant", content:[{type:"output_text"}]} rejected by strict OpenAI-compatible servers

Open
#42,613 4 comments 0 reactions 1 assignee View on GitHub

@kitlangton is already working on this.

Since Aug 14, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Summary

When a conversation history contains an assistant text message and opencode sends it
to an OpenAI Responses (/responses) endpoint, the request body uses:

{"role": "assistant", "content": [{"type": "output_text", "text": "..."}]}

This shape is not valid per OpenAI's Responses input schema. Real api.openai.com
tolerates it, but strict OpenAI-compatible servers that validate with the official
OpenAI SDK types (e.g. a self-hosted Qwen server exposing /v1/responses) reject it
with a 422/400 validation error, so switching a session to such a model fails.

Environment

  • opencode 1.18.18 (Snap, stable)
  • Default runtime (AI SDK path), @ai-sdk/openai 3.0.84
  • Server: self-hosted OpenAI-compatible /v1/responses endpoint (validates with
    openai Python SDK pydantic types)

Repro

  1. Configure a custom provider/model pointing at an OpenAI-compatible /responses
    server.
  2. Switch an existing session to that model so the history (including prior
    assistant text) is resent.
  3. The request fails with a pydantic ValidationError on the input array, e.g.:
loc: ('body', 'input', 'list[union[EasyInputMessageParam, Message, ResponseOutputMessageParam, ...]]', 2, 'ResponseFunctionToolCallParam', 'call_id')
msg: 'Field required'
input: {'role': 'assistant', 'content': [{'type': 'output_text', 'text': '...'}]}

Root cause

@ai-sdk/openai builds assistant input items as
{ role: "assistant", content: [{ type: "output_text", text }], id }
(convertToOpenAIResponsesMessages, dist/index.js ~3127).

Per the official OpenAI schema (openai-python types):

  • EasyInputMessageParam allows role: "assistant" but content must be
    str | list[input_text | input_image | input_file]output_text is not
    a valid easy-input content part.
  • output_text is only valid inside a full output item
    { type: "message", role: "assistant", id, status, content: [...] }
    (ResponseOutputMessageParam, where type/id/status are required).

OpenAI's own API is lenient and accepts the non-conformant shape, which is why
this has gone unnoticed. The same bug also exists in the native llm protocol
(packages/llm/src/protocols/openai-responses.ts, lowerMessages).

Proposed fix

Emit assistant text as an easy-input message with input_text parts:

{"role": "assistant", "content": [{"type": "input_text", "text": "..."}]}

or, when an item id is available, the complete
{"type": "message", "role": "assistant", "id", "status": "completed", "content": [{"type": "output_text", "text": "..."}]}.

A local fix for the native protocol is ready and tests pass
(59 tests, packages/llm). The AI SDK path will additionally need a fix in
vercel/ai (or a bumped @ai-sdk/openai) to fix the released builds.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.