Repository navigation
Description
Summary
At v2 HEAD (v2-test, 529d55b1c3), toolChoice is fully plumbed through the internal LLM layer (packages/core/src/aisdk.ts:421, packages/opencode/src/session/llm.ts:47/234/319, native-request/native-runtime, provider-specific lowerings) but is not wired to either the config layer or the HTTP prompt API. packages/opencode/src/session/prompt.ts:1285 still hard-codes it:
toolChoice: format.type === "json_schema" ? "required" : undefined,PromptInput (packages/opencode/src/session/prompt.ts:1499) exposed via the HTTP POST /session/:id/prompt endpoint (packages/opencode/src/server/routes/instance/httpapi/groups/session.ts:302) has no toolChoice field either.
Net effect: providers always get "auto" for regular turns. Models that follow auto conservatively (Kimi K3 in particular) frequently answer from context instead of invoking a tool that is available.
Not a duplicate — an update
- [FEATURE]: Expose toolChoice as a configurable agent option in opencode.json #14090 was closed as completed but the completion didn't actually land.
- opencode Agent config is silently ignored — opencode always sends (1.17.7) #32465 (open) reports it silently ignored in 1.17.7.
- fix(opencode): honor agent tool_choice config #32521 and fix(agent): apply configured tool_choice to model requests #32518 (parallel PRs targeting
dev) both closed by automated 1-month cleanup with no review, not by rejection. - Nothing in v2 has this wired.
Filing fresh against v2 HEAD, referencing the above.
Reproduction (v2 daemon + runtime MCP)
Environment: opencode v2 daemon (v2-test, 529d55b1c3), kimi-for-coding/k3, a remote MCP registered via POST /mcp exposing one tool (update_field).
Client sends a user turn like:
"My favorite color is blue. Record it now via update_field (field=\"favorite_color\", value=\"blue\") before replying."
Even with a strict system prompt ("You MUST call update_field before replying. This is mandatory."), Kimi K3 replies "Got it — blue is a great choice" with zero tool calls. Anthropic models on the same MCP entry invoke the tool reliably.
Daemon logs confirm the MCP entry is connected, initialize + tools/list complete cleanly, and update_field is in the returned tool list. The model just declines to call it.
Directly hitting our controller with a synthetic tools/call mutates state correctly, proving the transport is fine — the model simply never emits the call.
Ask
Two-part, both small:
1) Config path. Re-land the fix from #32521/#32518 against v2: add tool_choice: \"auto\" | \"required\" | \"none\" to the agent v2 config schema, map it onto AgentInfo.toolChoice, and use it at prompt.ts:1285 instead of the current ternary. Backwards compatible when unset.
2) HTTP path. Add optional toolChoice: \"auto\" | \"required\" | \"none\" to PromptInput (prompt.ts:1499) so external orchestrators calling POST /session/:id/prompt (runtime MCP bridges like ours, subagent runners) can force tool invocation per-turn without editing global config. Precedence: request > agent config > current default.
The plumbing already exists internally; both changes are essentially the missing edges of a wire that's otherwise complete.
Why this matters more than it used to
v2 promotes runtime MCP as a core feature (#37308). Runtime MCP orchestrators are exactly the callers that need per-turn toolChoice: \"required\" — they know the current turn is a form-fill / structured-mutation step where a tool call is not optional. Without the HTTP surface, orchestrators can't reliably drive Kimi (or any model that's conservative under auto) through MCP-mediated flows.
Willing to help
Happy to open a PR against v2 if there's interest — the diff is small and follows the shape of the two closed PRs. Would appreciate a signal that a review will land before the auto-cleanup fires again.
Activity
github-actions commentedon Sep 17, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.