mirror of
https://github.com/sst/opencode.git
synced 2025-12-23 10:11:41 +00:00
core: add verification that at least 1 primary agent is enabled, add regression tests (#5881)
This commit is contained in:
parent
cfaac9f2e1
commit
d3922f0965
3 changed files with 186 additions and 0 deletions
|
|
@ -262,6 +262,14 @@ export namespace Agent {
|
|||
}
|
||||
}
|
||||
|
||||
const hasPrimaryAgents = Object.values(result).filter((a) => a.mode !== "subagent" && !a.hidden).length > 0
|
||||
if (!hasPrimaryAgents) {
|
||||
throw new Config.InvalidError({
|
||||
path: "config",
|
||||
message: "No primary agents are available. Please configure at least one agent with mode 'primary' or 'all'.",
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
})
|
||||
|
||||
|
|
|
|||
146
packages/opencode/test/agent/agent.test.ts
Normal file
146
packages/opencode/test/agent/agent.test.ts
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
import { test, expect } from "bun:test"
|
||||
import path from "path"
|
||||
import fs from "fs/promises"
|
||||
import { tmpdir } from "../fixture/fixture"
|
||||
import { Instance } from "../../src/project/instance"
|
||||
import { Agent } from "../../src/agent/agent"
|
||||
|
||||
test("loads built-in agents when no custom agents configured", async () => {
|
||||
await using tmp = await tmpdir()
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const agents = await Agent.list()
|
||||
const names = agents.map((a) => a.name)
|
||||
expect(names).toContain("build")
|
||||
expect(names).toContain("plan")
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("custom subagent works alongside built-in primary agents", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
const opencodeDir = path.join(dir, ".opencode")
|
||||
await fs.mkdir(opencodeDir, { recursive: true })
|
||||
const agentDir = path.join(opencodeDir, "agent")
|
||||
await fs.mkdir(agentDir, { recursive: true })
|
||||
|
||||
await Bun.write(
|
||||
path.join(agentDir, "helper.md"),
|
||||
`---
|
||||
model: test/model
|
||||
mode: subagent
|
||||
---
|
||||
Helper subagent prompt`,
|
||||
)
|
||||
},
|
||||
})
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const agents = await Agent.list()
|
||||
const helper = agents.find((a) => a.name === "helper")
|
||||
expect(helper).toBeDefined()
|
||||
expect(helper?.mode).toBe("subagent")
|
||||
|
||||
// Built-in primary agents should still exist
|
||||
const build = agents.find((a) => a.name === "build")
|
||||
expect(build).toBeDefined()
|
||||
expect(build?.mode).toBe("primary")
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("throws error when all primary agents are 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",
|
||||
agent: {
|
||||
build: { disable: true },
|
||||
plan: { disable: true },
|
||||
},
|
||||
}),
|
||||
)
|
||||
},
|
||||
})
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
try {
|
||||
await Agent.list()
|
||||
expect(true).toBe(false) // should not reach here
|
||||
} catch (e: any) {
|
||||
expect(e.data?.message).toContain("No primary agents are available")
|
||||
}
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("does not throw when at least one primary agent remains", 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",
|
||||
agent: {
|
||||
build: { disable: true },
|
||||
},
|
||||
}),
|
||||
)
|
||||
},
|
||||
})
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const agents = await Agent.list()
|
||||
const plan = agents.find((a) => a.name === "plan")
|
||||
expect(plan).toBeDefined()
|
||||
expect(plan?.mode).toBe("primary")
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("custom primary agent satisfies requirement when built-ins disabled", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
const opencodeDir = path.join(dir, ".opencode")
|
||||
await fs.mkdir(opencodeDir, { recursive: true })
|
||||
const agentDir = path.join(opencodeDir, "agent")
|
||||
await fs.mkdir(agentDir, { recursive: true })
|
||||
|
||||
await Bun.write(
|
||||
path.join(agentDir, "custom.md"),
|
||||
`---
|
||||
model: test/model
|
||||
mode: primary
|
||||
---
|
||||
Custom primary agent`,
|
||||
)
|
||||
|
||||
await Bun.write(
|
||||
path.join(dir, "opencode.json"),
|
||||
JSON.stringify({
|
||||
$schema: "https://opencode.ai/config.json",
|
||||
agent: {
|
||||
build: { disable: true },
|
||||
plan: { disable: true },
|
||||
},
|
||||
}),
|
||||
)
|
||||
},
|
||||
})
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const agents = await Agent.list()
|
||||
const custom = agents.find((a) => a.name === "custom")
|
||||
expect(custom).toBeDefined()
|
||||
expect(custom?.mode).toBe("primary")
|
||||
},
|
||||
})
|
||||
})
|
||||
|
|
@ -450,6 +450,38 @@ test("merges plugin arrays from global and local configs", async () => {
|
|||
})
|
||||
})
|
||||
|
||||
test("does not error when only custom agent is a subagent", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
const opencodeDir = path.join(dir, ".opencode")
|
||||
await fs.mkdir(opencodeDir, { recursive: true })
|
||||
const agentDir = path.join(opencodeDir, "agent")
|
||||
await fs.mkdir(agentDir, { recursive: true })
|
||||
|
||||
await Bun.write(
|
||||
path.join(agentDir, "helper.md"),
|
||||
`---
|
||||
model: test/model
|
||||
mode: subagent
|
||||
---
|
||||
Helper subagent prompt`,
|
||||
)
|
||||
},
|
||||
})
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const config = await Config.get()
|
||||
expect(config.agent?.["helper"]).toEqual({
|
||||
name: "helper",
|
||||
model: "test/model",
|
||||
mode: "subagent",
|
||||
prompt: "Helper subagent prompt",
|
||||
})
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("deduplicates duplicate plugins from global and local configs", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue