Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
Prev Previous commit
Next Next commit
fix: fallback to first primary agent when default_agent invalid
  • Loading branch information
observerw committed Dec 10, 2025
commit c7ec35f5c41d95332adf5d53a40a5cde212901cc
22 changes: 14 additions & 8 deletions packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ export namespace Config {
return merged
}

function firstPrimaryAgent(agents: Record<string, Agent>): string {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't it still default to build if it is enabled tho, rather than arbitrary first agent

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

for (const [name, config] of Object.entries(agents)) {
if (config.mode !== "subagent" && !config.disable) {
return name
}
}
return "build"
}

export const state = Instance.state(async () => {
const auth = await Auth.all()
let result = await global()
Expand Down Expand Up @@ -128,14 +137,11 @@ export namespace Config {

if (!result.keybinds) result.keybinds = Info.shape.keybinds.parse({})

// Set defaultAgent if not specified
if (!result.default_agent) result.default_agent = "build"

// Validate that the default agent is not disabled
if (result.agent && result.agent[result.default_agent]?.disable) {
throw new Error(
`Cannot disable the default agent '${result.default_agent}'. Please either enable it or specify a different default agent in your configuration.`,
)
if (!result.default_agent || !(result.default_agent in result.agent)) {
log.warn(`default_agent not found in agents, selecting first primary agent`)
log.debug(`available agents: ${Object.keys(result.agent).join(", ")}`)
result.default_agent = firstPrimaryAgent(result.agent)
log.debug(`selected fallback agent: ${result.default_agent}`)
}

return {
Expand Down
31 changes: 15 additions & 16 deletions packages/opencode/test/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,18 +502,23 @@ test("deduplicates duplicate plugins from global and local configs", async () =>
})
})

test("sets default agent to 'build' when not specified", async () => {
test("uses specified default_agent when provided", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
await Bun.write(
path.join(dir, "opencode.json"),
JSON.stringify({
$schema: "https://opencode.ai/config.json",
default_agent: "custom",
agent: {
build: {
model: "test/model",
description: "build agent",
},
custom: {
model: "test/model",
description: "custom agent",
},
},
}),
)
Expand All @@ -523,27 +528,29 @@ test("sets default agent to 'build' when not specified", async () => {
directory: tmp.path,
fn: async () => {
const config = await Config.get()
expect(config.default_agent).toBe("build")
expect(config.default_agent).toBe("custom")
},
})
})

test("uses specified defaultAgent when provided", async () => {
test("falls back when default_agent is disabled", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
await Bun.write(
path.join(dir, "opencode.json"),
JSON.stringify({
$schema: "https://opencode.ai/config.json",
defaultAgent: "custom",
default_agent: "build",
agent: {
build: {
model: "test/model",
description: "build agent",
disable: true,
},
custom: {
model: "test/model",
description: "custom agent",
mode: "primary",
},
},
}),
Expand All @@ -559,31 +566,23 @@ test("uses specified defaultAgent when provided", async () => {
})
})

test("throws error when defaultAgent is disabled", async () => {
test("falls back when configured default_agent does not exist", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
await Bun.write(
path.join(dir, "opencode.json"),
JSON.stringify({
$schema: "https://opencode.ai/config.json",
defaultAgent: "build",
agent: {
build: {
model: "test/model",
description: "build agent",
disable: true,
},
},
default_agent: "nonexistent-agent",
}),
)
},
})
await Instance.provide({
directory: tmp.path,
fn: async () => {
expect(Config.get()).rejects.toThrow(
"Cannot disable the default agent 'build'. Please either enable it or specify a different default agent in your configuration.",
)
const config = await Config.get()
expect(config.default_agent).toBe("build")
},
})
})