Skip to content

fix(provider): propagate options.extraBody for openai-compatible providers#26233

Open
jeremy-newhouse wants to merge 1 commit into
anomalyco:devfrom
jeremy-newhouse:fix/openai-compatible-extra-body
Open

fix(provider): propagate options.extraBody for openai-compatible providers#26233
jeremy-newhouse wants to merge 1 commit into
anomalyco:devfrom
jeremy-newhouse:fix/openai-compatible-extra-body

Conversation

@jeremy-newhouse

@jeremy-newhouse jeremy-newhouse commented May 7, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #13584
Closes #23995
Closes #24264

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

provider.<id>.options.extraBody from opencode.json is silently dropped — extraBody is permitted by the schema's rest record but never read. Users of OpenAI-compatible servers (vLLM, NVIDIA NIM, SGLang, direct DashScope) can't pass server-specific body fields like chat_template_kwargs that those endpoints need.

The fix: read input.providerOptions.extraBody in ProviderTransform.options() and Object.assign it into result. Routing then matches the existing alibaba-cn enable_thinking=true block at transform.ts:1040 — which is proof the path reaches the wire (DashScope users rely on it). Also adds a typed extraBody field to Info.options for IDE completion.

Pattern matches #25573 (cf-ai-gateway fix); avoids the larger surface change in #6761 (closed without merge).

How did you verify your code works?

7 new unit tests in transform.test.ts: positive case, nested objects, undefined/null/array no-ops, non-clobbering of unrelated fields, explicit precedence (user extraBody overrides hardcoded blocks). Full provider suite passes (291/291).

End-to-end against vLLM serving Qwen3.6-35B-A3B (--reasoning-parser qwen3 --tool-call-parser qwen3_coder):

  • Vanilla v1.14.39 with extraBody.chat_template_kwargs.enable_thinking=false in opencode.json: agent loop dies — model emits EOS without finishing tool calls because enable_thinking=false never reaches vLLM and qwen3 produces runaway reasoning.
  • Same config + this patch: agent run finishes cleanly (537s, 5 commits in a multi-feature run, no hallucinations). Direct routing to vLLM verified — no proxy in the path.

Screenshots / recordings

n/a — not a UI change

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label May 7, 2026
…iders

opencode silently drops `provider.<id>.options.extraBody` from
opencode.json, so users of OpenAI-compatible servers (vLLM, SGLang,
NVIDIA NIM, direct DashScope) cannot pass server-specific
chat-completions body fields like `chat_template_kwargs`.

Concrete impact (vLLM + qwen3): without `chat_template_kwargs.enable_thinking=false`
on the wire, qwen3 produces pathological reasoning that consumes its
output budget and emits EOS without finishing tool calls; the agent
loop dies mid-flight. The harness today ships a Python wire proxy as
a stopgap.

Fix: read `input.providerOptions.extraBody` in
`ProviderTransform.options()` and merge into `result`. The fields then
ride the same path as the existing alibaba-cn `enable_thinking=true`
hardcoding (transform.ts:1040-1047) — `providerOptions()` wraps the
result under the SDK-recognized key for `@ai-sdk/openai-compatible`,
and the Vercel AI SDK serializes it onto the request body. The
alibaba-cn block proves this routing reaches the wire (DashScope
users rely on it).

Also adds a typed `extraBody` field on the `Info.options` schema for
documentation and IDE completion. The existing rest record on
`Info.options` already permits the field; this purely improves
discoverability.

Tests cover: positive case (qwen3 enable_thinking), nested objects,
undefined / null / array no-ops, non-clobbering of unrelated fields,
and explicit precedence (user config wins over hardcoded blocks).

Closes anomalyco#13584
Closes anomalyco#23995
Closes anomalyco#24264
@jeremy-newhouse jeremy-newhouse force-pushed the fix/openai-compatible-extra-body branch from 8551430 to cd2b14b Compare May 7, 2026 19:17
@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label May 7, 2026
@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@fungaren

fungaren commented Jun 2, 2026

Copy link
Copy Markdown

@adamdotdevin Very Very Very important feature for users who are using DeepSeek-V4 models :)

@fungaren

fungaren commented Jun 4, 2026

Copy link
Copy Markdown

@rekram1-node Hi, can you please help us to review and merge this PR? Thanks!

acje added a commit to acje/.config that referenced this pull request Jun 10, 2026
Three changes to the dramallama provider, all reversing breakage that left
the model returning blank responses with no error:

- baseURL: revert 127.0.0.1:8787 (headroom proxy, commit 9603a27) back to
  the direct https://aiapi.mattilsynet.no/v1 endpoint. The proxy was
  uninstalled, so requests hit a dead local port.
- thinking model: remove options.chat_template_kwargs.enable_thinking.
  opencode v1.17.1 silently drops this field for custom providers
  (transform.ts has no generic passthrough; fix is open PR anomalyco/opencode#26233),
  and Qwen3 on vLLM enables reasoning by default regardless, so the field
  was a no-op twice over.
- thinking model: raise limit.output 8000 -> 32000. Qwen3 spends the output
  budget on reasoning before emitting content; 8000 truncated mid-thought
  (finish_reason=length, content=null) which opencode renders as a blank
  message. Higher cap lets content survive the reasoning preamble.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants