summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorKit Langton <[email protected]>2026-04-13 14:54:01 -0400
committerGitHub <[email protected]>2026-04-13 14:54:01 -0400
commit14ccff40379b9dabd4e7276881f93939113b8b12 (patch)
treefd56e41e598b917d9ca3af06b5126d036a97f0f7
parent5b8b874732d7027564e69891561ceb3ebd65b845 (diff)
downloadopencode-14ccff40379b9dabd4e7276881f93939113b8b12.tar.gz
opencode-14ccff40379b9dabd4e7276881f93939113b8b12.zip
refactor(agent): remove async facade exports (#22341)
-rw-r--r--packages/opencode/src/acp/agent.ts6
-rw-r--r--packages/opencode/src/agent/agent.ts19
-rw-r--r--packages/opencode/src/cli/cmd/agent.ts7
-rw-r--r--packages/opencode/src/cli/cmd/debug/agent.ts2
-rw-r--r--packages/opencode/src/cli/cmd/run.ts18
-rw-r--r--packages/opencode/src/server/instance/index.ts2
-rw-r--r--packages/opencode/src/server/instance/session.ts5
-rw-r--r--packages/opencode/src/tool/registry.ts5
-rw-r--r--packages/opencode/test/agent/agent.test.ts89
-rw-r--r--packages/opencode/test/config/agent-color.test.ts9
-rw-r--r--packages/opencode/test/session/system.test.ts8
11 files changed, 87 insertions, 83 deletions
diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts
index 6e87e7642..73a7ebe48 100644
--- a/packages/opencode/src/acp/agent.ts
+++ b/packages/opencode/src/acp/agent.ts
@@ -40,6 +40,7 @@ import type { ACPConfig } from "./types"
import { Provider } from "../provider/provider"
import { ModelID, ProviderID } from "../provider/schema"
import { Agent as AgentModule } from "../agent/agent"
+import { AppRuntime } from "@/effect/app-runtime"
import { Installation } from "@/installation"
import { MessageV2 } from "@/session/message-v2"
import { Config } from "@/config/config"
@@ -1166,7 +1167,7 @@ export namespace ACP {
this.sessionManager.get(sessionId).modeId ||
(await (async () => {
if (!availableModes.length) return undefined
- const defaultAgentName = await AgentModule.defaultAgent()
+ const defaultAgentName = await AppRuntime.runPromise(AgentModule.Service.use((svc) => svc.defaultAgent()))
const resolvedModeId =
availableModes.find((mode) => mode.name === defaultAgentName)?.id ?? availableModes[0].id
this.sessionManager.setMode(sessionId, resolvedModeId)
@@ -1367,7 +1368,8 @@ export namespace ACP {
if (!current) {
this.sessionManager.setModel(session.id, model)
}
- const agent = session.modeId ?? (await AgentModule.defaultAgent())
+ const agent =
+ session.modeId ?? (await AppRuntime.runPromise(AgentModule.Service.use((svc) => svc.defaultAgent())))
const parts: Array<
| { type: "text"; text: string; synthetic?: boolean; ignored?: boolean }
diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts
index fd9ac43e8..cebcaa048 100644
--- a/packages/opencode/src/agent/agent.ts
+++ b/packages/opencode/src/agent/agent.ts
@@ -21,7 +21,6 @@ import { Plugin } from "@/plugin"
import { Skill } from "../skill"
import { Effect, Context, Layer } from "effect"
import { InstanceState } from "@/effect/instance-state"
-import { makeRuntime } from "@/effect/run-service"
export namespace Agent {
export const Info = z
@@ -404,22 +403,4 @@ export namespace Agent {
Layer.provide(Config.defaultLayer),
Layer.provide(Skill.defaultLayer),
)
-
- const { runPromise } = makeRuntime(Service, defaultLayer)
-
- export async function get(agent: string) {
- return runPromise((svc) => svc.get(agent))
- }
-
- export async function list() {
- return runPromise((svc) => svc.list())
- }
-
- export async function defaultAgent() {
- return runPromise((svc) => svc.defaultAgent())
- }
-
- export async function generate(input: { description: string; model?: { providerID: ProviderID; modelID: ModelID } }) {
- return runPromise((svc) => svc.generate(input))
- }
}
diff --git a/packages/opencode/src/cli/cmd/agent.ts b/packages/opencode/src/cli/cmd/agent.ts
index 70082c8e2..60f52e403 100644
--- a/packages/opencode/src/cli/cmd/agent.ts
+++ b/packages/opencode/src/cli/cmd/agent.ts
@@ -1,5 +1,6 @@
import { cmd } from "./cmd"
import * as prompts from "@clack/prompts"
+import { AppRuntime } from "@/effect/app-runtime"
import { UI } from "../ui"
import { Global } from "../../global"
import { Agent } from "../../agent/agent"
@@ -110,7 +111,9 @@ const AgentCreateCommand = cmd({
const spinner = prompts.spinner()
spinner.start("Generating agent configuration...")
const model = args.model ? Provider.parseModel(args.model) : undefined
- const generated = await Agent.generate({ description, model }).catch((error) => {
+ const generated = await AppRuntime.runPromise(
+ Agent.Service.use((svc) => svc.generate({ description, model })),
+ ).catch((error) => {
spinner.stop(`LLM failed to generate agent: ${error.message}`, 1)
if (isFullyNonInteractive) process.exit(1)
throw new UI.CancelledError()
@@ -220,7 +223,7 @@ const AgentListCommand = cmd({
await Instance.provide({
directory: process.cwd(),
async fn() {
- const agents = await Agent.list()
+ const agents = await AppRuntime.runPromise(Agent.Service.use((svc) => svc.list()))
const sortedAgents = agents.sort((a, b) => {
if (a.native !== b.native) {
return a.native ? -1 : 1
diff --git a/packages/opencode/src/cli/cmd/debug/agent.ts b/packages/opencode/src/cli/cmd/debug/agent.ts
index fbaf8d78d..51de43f67 100644
--- a/packages/opencode/src/cli/cmd/debug/agent.ts
+++ b/packages/opencode/src/cli/cmd/debug/agent.ts
@@ -35,7 +35,7 @@ export const AgentCommand = cmd({
async handler(args) {
await bootstrap(process.cwd(), async () => {
const agentName = args.name as string
- const agent = await Agent.get(agentName)
+ const agent = await AppRuntime.runPromise(Agent.Service.use((svc) => svc.get(agentName)))
if (!agent) {
process.stderr.write(
`Agent ${agentName} not found, run '${basename(process.execPath)} agent list' to get an agent list` + EOL,
diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts
index 04130aa95..17fc4bc08 100644
--- a/packages/opencode/src/cli/cmd/run.ts
+++ b/packages/opencode/src/cli/cmd/run.ts
@@ -27,6 +27,7 @@ import { SkillTool } from "../../tool/skill"
import { BashTool } from "../../tool/bash"
import { TodoWriteTool } from "../../tool/todo"
import { Locale } from "../../util/locale"
+import { AppRuntime } from "@/effect/app-runtime"
type ToolProps<T> = {
input: Tool.InferParameters<T>
@@ -573,6 +574,7 @@ export const RunCommand = cmd({
// Validate agent if specified
const agent = await (async () => {
if (!args.agent) return undefined
+ const name = args.agent
// When attaching, validate against the running server instead of local Instance state.
if (args.attach) {
@@ -590,12 +592,12 @@ export const RunCommand = cmd({
return undefined
}
- const agent = modes.find((a) => a.name === args.agent)
+ const agent = modes.find((a) => a.name === name)
if (!agent) {
UI.println(
UI.Style.TEXT_WARNING_BOLD + "!",
UI.Style.TEXT_NORMAL,
- `agent "${args.agent}" not found. Falling back to default agent`,
+ `agent "${name}" not found. Falling back to default agent`,
)
return undefined
}
@@ -604,20 +606,20 @@ export const RunCommand = cmd({
UI.println(
UI.Style.TEXT_WARNING_BOLD + "!",
UI.Style.TEXT_NORMAL,
- `agent "${args.agent}" is a subagent, not a primary agent. Falling back to default agent`,
+ `agent "${name}" is a subagent, not a primary agent. Falling back to default agent`,
)
return undefined
}
- return args.agent
+ return name
}
- const entry = await Agent.get(args.agent)
+ const entry = await AppRuntime.runPromise(Agent.Service.use((svc) => svc.get(name)))
if (!entry) {
UI.println(
UI.Style.TEXT_WARNING_BOLD + "!",
UI.Style.TEXT_NORMAL,
- `agent "${args.agent}" not found. Falling back to default agent`,
+ `agent "${name}" not found. Falling back to default agent`,
)
return undefined
}
@@ -625,11 +627,11 @@ export const RunCommand = cmd({
UI.println(
UI.Style.TEXT_WARNING_BOLD + "!",
UI.Style.TEXT_NORMAL,
- `agent "${args.agent}" is a subagent, not a primary agent. Falling back to default agent`,
+ `agent "${name}" is a subagent, not a primary agent. Falling back to default agent`,
)
return undefined
}
- return args.agent
+ return name
})()
const sessionID = await session(sdk)
diff --git a/packages/opencode/src/server/instance/index.ts b/packages/opencode/src/server/instance/index.ts
index 6d383afa7..86a18dc67 100644
--- a/packages/opencode/src/server/instance/index.ts
+++ b/packages/opencode/src/server/instance/index.ts
@@ -207,7 +207,7 @@ export const InstanceRoutes = (upgrade: UpgradeWebSocket): Hono =>
},
}),
async (c) => {
- const modes = await Agent.list()
+ const modes = await AppRuntime.runPromise(Agent.Service.use((svc) => svc.list()))
return c.json(modes)
},
)
diff --git a/packages/opencode/src/server/instance/session.ts b/packages/opencode/src/server/instance/session.ts
index b28db3a89..6f8feea8e 100644
--- a/packages/opencode/src/server/instance/session.ts
+++ b/packages/opencode/src/server/instance/session.ts
@@ -550,11 +550,12 @@ export const SessionRoutes = lazy(() =>
const session = await Session.get(sessionID)
await SessionRevert.cleanup(session)
const msgs = await Session.messages({ sessionID })
- let currentAgent = await Agent.defaultAgent()
+ const defaultAgent = await AppRuntime.runPromise(Agent.Service.use((svc) => svc.defaultAgent()))
+ let currentAgent = defaultAgent
for (let i = msgs.length - 1; i >= 0; i--) {
const info = msgs[i].info
if (info.role === "user") {
- currentAgent = info.agent || (await Agent.defaultAgent())
+ currentAgent = info.agent || defaultAgent
break
}
}
diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts
index 3ed9e4b18..d6daa87f5 100644
--- a/packages/opencode/src/tool/registry.ts
+++ b/packages/opencode/src/tool/registry.ts
@@ -121,6 +121,7 @@ export namespace ToolRegistry {
const greptool = yield* GrepTool
const patchtool = yield* ApplyPatchTool
const skilltool = yield* SkillTool
+ const agent = yield* Agent.Service
const state = yield* InstanceState.make<State>(
Effect.fn("ToolRegistry.state")(function* (ctx) {
@@ -140,8 +141,8 @@ export namespace ToolRegistry {
worktree: ctx.worktree,
}
const result = yield* Effect.promise(() => def.execute(args as any, pluginCtx))
- const agent = yield* Effect.promise(() => Agent.get(toolCtx.agent))
- const out = yield* truncate.output(result, {}, agent)
+ const info = yield* agent.get(toolCtx.agent)
+ const out = yield* truncate.output(result, {}, info)
return {
title: "",
output: out.truncated ? out.content : result,
diff --git a/packages/opencode/test/agent/agent.test.ts b/packages/opencode/test/agent/agent.test.ts
index 98a0fd4c6..409a0ed60 100644
--- a/packages/opencode/test/agent/agent.test.ts
+++ b/packages/opencode/test/agent/agent.test.ts
@@ -1,6 +1,7 @@
import { afterEach, test, expect } from "bun:test"
+import { Effect } from "effect"
import path from "path"
-import { tmpdir } from "../fixture/fixture"
+import { provideInstance, tmpdir } from "../fixture/fixture"
import { Instance } from "../../src/project/instance"
import { Agent } from "../../src/agent/agent"
import { Permission } from "../../src/permission"
@@ -11,6 +12,10 @@ function evalPerm(agent: Agent.Info | undefined, permission: string): Permission
return Permission.evaluate(permission, "*", agent.permission).action
}
+function load<A>(dir: string, fn: (svc: Agent.Interface) => Effect.Effect<A>) {
+ return Effect.runPromise(provideInstance(dir)(Agent.Service.use(fn)).pipe(Effect.provide(Agent.defaultLayer)))
+}
+
afterEach(async () => {
await Instance.disposeAll()
})
@@ -20,7 +25,7 @@ test("returns default native agents when no config", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const agents = await Agent.list()
+ const agents = await load(tmp.path, (svc) => svc.list())
const names = agents.map((a) => a.name)
expect(names).toContain("build")
expect(names).toContain("plan")
@@ -38,7 +43,7 @@ test("build agent has correct default properties", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(build).toBeDefined()
expect(build?.mode).toBe("primary")
expect(build?.native).toBe(true)
@@ -53,7 +58,7 @@ test("plan agent denies edits except .opencode/plans/*", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const plan = await Agent.get("plan")
+ const plan = await load(tmp.path, (svc) => svc.get("plan"))
expect(plan).toBeDefined()
// Wildcard is denied
expect(evalPerm(plan, "edit")).toBe("deny")
@@ -68,7 +73,7 @@ test("explore agent denies edit and write", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const explore = await Agent.get("explore")
+ const explore = await load(tmp.path, (svc) => svc.get("explore"))
expect(explore).toBeDefined()
expect(explore?.mode).toBe("subagent")
expect(evalPerm(explore, "edit")).toBe("deny")
@@ -84,7 +89,7 @@ test("explore agent asks for external directories and allows Truncate.GLOB", asy
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const explore = await Agent.get("explore")
+ const explore = await load(tmp.path, (svc) => svc.get("explore"))
expect(explore).toBeDefined()
expect(Permission.evaluate("external_directory", "/some/other/path", explore!.permission).action).toBe("ask")
expect(Permission.evaluate("external_directory", Truncate.GLOB, explore!.permission).action).toBe("allow")
@@ -97,7 +102,7 @@ test("general agent denies todo tools", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const general = await Agent.get("general")
+ const general = await load(tmp.path, (svc) => svc.get("general"))
expect(general).toBeDefined()
expect(general?.mode).toBe("subagent")
expect(general?.hidden).toBeUndefined()
@@ -111,7 +116,7 @@ test("compaction agent denies all permissions", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const compaction = await Agent.get("compaction")
+ const compaction = await load(tmp.path, (svc) => svc.get("compaction"))
expect(compaction).toBeDefined()
expect(compaction?.hidden).toBe(true)
expect(evalPerm(compaction, "bash")).toBe("deny")
@@ -137,7 +142,7 @@ test("custom agent from config creates new agent", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const custom = await Agent.get("my_custom_agent")
+ const custom = await load(tmp.path, (svc) => svc.get("my_custom_agent"))
expect(custom).toBeDefined()
expect(String(custom?.model?.providerID)).toBe("openai")
expect(String(custom?.model?.modelID)).toBe("gpt-4")
@@ -166,7 +171,7 @@ test("custom agent config overrides native agent properties", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(build).toBeDefined()
expect(String(build?.model?.providerID)).toBe("anthropic")
expect(String(build?.model?.modelID)).toBe("claude-3")
@@ -189,9 +194,9 @@ test("agent disable removes agent from list", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const explore = await Agent.get("explore")
+ const explore = await load(tmp.path, (svc) => svc.get("explore"))
expect(explore).toBeUndefined()
- const agents = await Agent.list()
+ const agents = await load(tmp.path, (svc) => svc.list())
const names = agents.map((a) => a.name)
expect(names).not.toContain("explore")
},
@@ -215,7 +220,7 @@ test("agent permission config merges with defaults", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(build).toBeDefined()
// Specific pattern is denied
expect(Permission.evaluate("bash", "rm -rf *", build!.permission).action).toBe("deny")
@@ -236,7 +241,7 @@ test("global permission config applies to all agents", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(build).toBeDefined()
expect(evalPerm(build, "bash")).toBe("deny")
},
@@ -255,8 +260,8 @@ test("agent steps/maxSteps config sets steps property", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
- const plan = await Agent.get("plan")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
+ const plan = await load(tmp.path, (svc) => svc.get("plan"))
expect(build?.steps).toBe(50)
expect(plan?.steps).toBe(100)
},
@@ -274,7 +279,7 @@ test("agent mode can be overridden", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const explore = await Agent.get("explore")
+ const explore = await load(tmp.path, (svc) => svc.get("explore"))
expect(explore?.mode).toBe("primary")
},
})
@@ -291,7 +296,7 @@ test("agent name can be overridden", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(build?.name).toBe("Builder")
},
})
@@ -308,7 +313,7 @@ test("agent prompt can be set from config", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(build?.prompt).toBe("Custom system prompt")
},
})
@@ -328,7 +333,7 @@ test("unknown agent properties are placed into options", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(build?.options.random_property).toBe("hello")
expect(build?.options.another_random).toBe(123)
},
@@ -351,7 +356,7 @@ test("agent options merge correctly", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(build?.options.custom_option).toBe(true)
expect(build?.options.another_option).toBe("value")
},
@@ -376,8 +381,8 @@ test("multiple custom agents can be defined", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const agentA = await Agent.get("agent_a")
- const agentB = await Agent.get("agent_b")
+ const agentA = await load(tmp.path, (svc) => svc.get("agent_a"))
+ const agentB = await load(tmp.path, (svc) => svc.get("agent_b"))
expect(agentA?.description).toBe("Agent A")
expect(agentA?.mode).toBe("subagent")
expect(agentB?.description).toBe("Agent B")
@@ -405,7 +410,7 @@ test("Agent.list keeps the default agent first and sorts the rest by name", asyn
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const names = (await Agent.list()).map((a) => a.name)
+ const names = (await load(tmp.path, (svc) => svc.list())).map((a) => a.name)
expect(names[0]).toBe("plan")
expect(names.slice(1)).toEqual(names.slice(1).toSorted((a, b) => a.localeCompare(b)))
},
@@ -417,7 +422,7 @@ test("Agent.get returns undefined for non-existent agent", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const nonExistent = await Agent.get("does_not_exist")
+ const nonExistent = await load(tmp.path, (svc) => svc.get("does_not_exist"))
expect(nonExistent).toBeUndefined()
},
})
@@ -428,7 +433,7 @@ test("default permission includes doom_loop and external_directory as ask", asyn
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(evalPerm(build, "doom_loop")).toBe("ask")
expect(evalPerm(build, "external_directory")).toBe("ask")
},
@@ -440,7 +445,7 @@ test("webfetch is allowed by default", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(evalPerm(build, "webfetch")).toBe("allow")
},
})
@@ -462,7 +467,7 @@ test("legacy tools config converts to permissions", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(evalPerm(build, "bash")).toBe("deny")
expect(evalPerm(build, "read")).toBe("deny")
},
@@ -484,7 +489,7 @@ test("legacy tools config maps write/edit/patch/multiedit to edit permission", a
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(evalPerm(build, "edit")).toBe("deny")
},
})
@@ -502,7 +507,7 @@ test("Truncate.GLOB is allowed even when user denies external_directory globally
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(Permission.evaluate("external_directory", Truncate.GLOB, build!.permission).action).toBe("allow")
expect(Permission.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("deny")
expect(Permission.evaluate("external_directory", "/some/other/path", build!.permission).action).toBe("deny")
@@ -526,7 +531,7 @@ test("Truncate.GLOB is allowed even when user denies external_directory per-agen
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(Permission.evaluate("external_directory", Truncate.GLOB, build!.permission).action).toBe("allow")
expect(Permission.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("deny")
expect(Permission.evaluate("external_directory", "/some/other/path", build!.permission).action).toBe("deny")
@@ -549,7 +554,7 @@ test("explicit Truncate.GLOB deny is respected", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
expect(Permission.evaluate("external_directory", Truncate.GLOB, build!.permission).action).toBe("deny")
expect(Permission.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("deny")
},
@@ -581,7 +586,7 @@ description: Permission skill.
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
const skillDir = path.join(tmp.path, ".opencode", "skill", "perm-skill")
const target = path.join(skillDir, "reference", "notes.md")
expect(Permission.evaluate("external_directory", target, build!.permission).action).toBe("allow")
@@ -597,7 +602,7 @@ test("defaultAgent returns build when no default_agent config", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const agent = await Agent.defaultAgent()
+ const agent = await load(tmp.path, (svc) => svc.defaultAgent())
expect(agent).toBe("build")
},
})
@@ -612,7 +617,7 @@ test("defaultAgent respects default_agent config set to plan", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const agent = await Agent.defaultAgent()
+ const agent = await load(tmp.path, (svc) => svc.defaultAgent())
expect(agent).toBe("plan")
},
})
@@ -632,7 +637,7 @@ test("defaultAgent respects default_agent config set to custom agent with mode a
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const agent = await Agent.defaultAgent()
+ const agent = await load(tmp.path, (svc) => svc.defaultAgent())
expect(agent).toBe("my_custom")
},
})
@@ -647,7 +652,7 @@ test("defaultAgent throws when default_agent points to subagent", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- await expect(Agent.defaultAgent()).rejects.toThrow('default agent "explore" is a subagent')
+ await expect(load(tmp.path, (svc) => svc.defaultAgent())).rejects.toThrow('default agent "explore" is a subagent')
},
})
})
@@ -661,7 +666,7 @@ test("defaultAgent throws when default_agent points to hidden agent", async () =
await Instance.provide({
directory: tmp.path,
fn: async () => {
- await expect(Agent.defaultAgent()).rejects.toThrow('default agent "compaction" is hidden')
+ await expect(load(tmp.path, (svc) => svc.defaultAgent())).rejects.toThrow('default agent "compaction" is hidden')
},
})
})
@@ -675,7 +680,9 @@ test("defaultAgent throws when default_agent points to non-existent agent", asyn
await Instance.provide({
directory: tmp.path,
fn: async () => {
- await expect(Agent.defaultAgent()).rejects.toThrow('default agent "does_not_exist" not found')
+ await expect(load(tmp.path, (svc) => svc.defaultAgent())).rejects.toThrow(
+ 'default agent "does_not_exist" not found',
+ )
},
})
})
@@ -691,7 +698,7 @@ test("defaultAgent returns plan when build is disabled and default_agent not set
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const agent = await Agent.defaultAgent()
+ const agent = await load(tmp.path, (svc) => svc.defaultAgent())
// build is disabled, so it should return plan (next primary agent)
expect(agent).toBe("plan")
},
@@ -711,7 +718,7 @@ test("defaultAgent throws when all primary agents are disabled", async () => {
directory: tmp.path,
fn: async () => {
// build and plan are disabled, no primary-capable agents remain
- await expect(Agent.defaultAgent()).rejects.toThrow("no primary visible agent found")
+ await expect(load(tmp.path, (svc) => svc.defaultAgent())).rejects.toThrow("no primary visible agent found")
},
})
})
diff --git a/packages/opencode/test/config/agent-color.test.ts b/packages/opencode/test/config/agent-color.test.ts
index 0dc2653c2..af9565cba 100644
--- a/packages/opencode/test/config/agent-color.test.ts
+++ b/packages/opencode/test/config/agent-color.test.ts
@@ -1,6 +1,7 @@
import { test, expect } from "bun:test"
+import { Effect } from "effect"
import path from "path"
-import { tmpdir } from "../fixture/fixture"
+import { provideInstance, tmpdir } from "../fixture/fixture"
import { Instance } from "../../src/project/instance"
import { Config } from "../../src/config/config"
import { Agent as AgentSvc } from "../../src/agent/agent"
@@ -8,6 +9,8 @@ import { Color } from "../../src/util/color"
import { AppRuntime } from "../../src/effect/app-runtime"
const load = () => AppRuntime.runPromise(Config.Service.use((svc) => svc.get()))
+const agent = <A>(dir: string, fn: (svc: AgentSvc.Interface) => Effect.Effect<A>) =>
+ Effect.runPromise(provideInstance(dir)(AgentSvc.Service.use(fn)).pipe(Effect.provide(AgentSvc.defaultLayer)))
test("agent color parsed from project config", async () => {
await using tmp = await tmpdir({
@@ -52,9 +55,9 @@ test("Agent.get includes color from config", async () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const plan = await AgentSvc.get("plan")
+ const plan = await agent(tmp.path, (svc) => svc.get("plan"))
expect(plan?.color).toBe("#A855F7")
- const build = await AgentSvc.get("build")
+ const build = await agent(tmp.path, (svc) => svc.get("build"))
expect(build?.color).toBe("accent")
},
})
diff --git a/packages/opencode/test/session/system.test.ts b/packages/opencode/test/session/system.test.ts
index 6f1047a97..33123acce 100644
--- a/packages/opencode/test/session/system.test.ts
+++ b/packages/opencode/test/session/system.test.ts
@@ -4,7 +4,11 @@ import { Effect } from "effect"
import { Agent } from "../../src/agent/agent"
import { Instance } from "../../src/project/instance"
import { SystemPrompt } from "../../src/session/system"
-import { tmpdir } from "../fixture/fixture"
+import { provideInstance, tmpdir } from "../fixture/fixture"
+
+function load<A>(dir: string, fn: (svc: Agent.Interface) => Effect.Effect<A>) {
+ return Effect.runPromise(provideInstance(dir)(Agent.Service.use(fn)).pipe(Effect.provide(Agent.defaultLayer)))
+}
describe("session.system", () => {
test("skills output is sorted by name and stable across calls", async () => {
@@ -38,7 +42,7 @@ description: ${description}
await Instance.provide({
directory: tmp.path,
fn: async () => {
- const build = await Agent.get("build")
+ const build = await load(tmp.path, (svc) => svc.get("build"))
const runSkills = Effect.gen(function* () {
const svc = yield* SystemPrompt.Service
return yield* svc.skills(build!)