Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/core/src/v1/config/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const AgentSchema = Schema.StructWithRest(
}),
temperature: Schema.optional(Schema.Finite),
top_p: Schema.optional(Schema.Finite),
tool_choice: Schema.optional(Schema.Literals(["auto", "required", "none"])).annotate({
description: "How the model should select tools: auto, required, or none",
}),
prompt: Schema.optional(Schema.String),
tools: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)).annotate({
description: "@deprecated Use 'permission' field instead",
Expand Down Expand Up @@ -48,6 +51,7 @@ const KNOWN_KEYS = new Set([
"description",
"temperature",
"top_p",
"tool_choice",
"mode",
"hidden",
"color",
Expand Down
2 changes: 2 additions & 0 deletions packages/opencode/src/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const Info = Schema.Struct({
hidden: Schema.optional(Schema.Boolean),
topP: Schema.optional(Schema.Finite),
temperature: Schema.optional(Schema.Finite),
toolChoice: Schema.optional(Schema.Literals(["auto", "required", "none"])),
color: Schema.optional(Schema.String),
permission: PermissionV1.Ruleset,
model: Schema.optional(
Expand Down Expand Up @@ -282,6 +283,7 @@ export const layer = Layer.effect(
item.description = value.description ?? item.description
item.temperature = value.temperature ?? item.temperature
item.topP = value.top_p ?? item.topP
item.toolChoice = value.tool_choice ?? item.toolChoice
item.mode = value.mode ?? item.mode
item.color = value.color ?? item.color
item.hidden = value.hidden ?? item.hidden
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/session/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1343,7 +1343,7 @@ export const layer = Layer.effect(
messages: [...modelMsgs, ...(isLastStep ? [{ role: "assistant" as const, content: MAX_STEPS }] : [])],
tools,
model,
toolChoice: format.type === "json_schema" ? "required" : undefined,
toolChoice: format.type === "json_schema" ? "required" : agent.toolChoice,
})

if (structured !== undefined) {
Expand Down
19 changes: 19 additions & 0 deletions packages/opencode/test/agent/agent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,25 @@ it.instance("build agent has correct default properties", () =>
}),
)

it.instance(
"agent tool_choice config is applied to the agent",
() =>
Effect.gen(function* () {
const build = yield* load((svc) => svc.get("build"))
expect(build).toBeDefined()
expect(build?.toolChoice).toBe("required")
}),
{
config: {
agent: {
build: {
tool_choice: "required",
},
},
},
},
)

it.instance("plan agent denies edits except .opencode/plans/*", () =>
Effect.gen(function* () {
const plan = yield* load((svc) => svc.get("plan"))
Expand Down
22 changes: 22 additions & 0 deletions packages/web/src/content/docs/agents.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,28 @@ If no temperature is specified, OpenCode uses model-specific defaults; typically

---

### Tool choice

Control how the model decides whether to call a tool with the `tool_choice` config.

```json title="opencode.json"
{
"agent": {
"build": {
"tool_choice": "required"
}
}
}
```

- **`auto`**: The model decides whether to call a tool. This is the default.
- **`required`**: The model must call a tool. Useful for models that don't reliably emit tool calls on their own.
- **`none`**: The model is not allowed to call tools.

If not set, OpenCode lets the provider use its default behavior (`auto`).

---

### Max steps

Control the maximum number of agentic iterations an agent can perform before being forced to respond with text only. This allows users who wish to control costs to set a limit on agentic actions.
Expand Down
Loading