Skip to content

Commit 55e209e

Browse files
kitlangtonmrsimpson
authored andcommitted
refactor(effect): build task tool from agent services (anomalyco#21017)
1 parent d1294b5 commit 55e209e

6 files changed

Lines changed: 627 additions & 211 deletions

File tree

packages/opencode/src/session/prompt.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,11 @@ NOTE: At any point in time through this workflow you should feel free to ask the
600600
subagent_type: task.agent,
601601
command: task.command,
602602
}
603-
yield* plugin.trigger("tool.execute.before", { tool: "task", sessionID, callID: part.id }, { args: taskArgs })
603+
yield* plugin.trigger(
604+
"tool.execute.before",
605+
{ tool: TaskTool.id, sessionID, callID: part.id },
606+
{ args: taskArgs },
607+
)
604608

605609
const taskAgent = yield* agents.get(task.agent)
606610
if (!taskAgent) {
@@ -679,7 +683,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
679683

680684
yield* plugin.trigger(
681685
"tool.execute.after",
682-
{ tool: "task", sessionID, callID: part.id, args: taskArgs },
686+
{ tool: TaskTool.id, sessionID, callID: part.id, args: taskArgs },
683687
result,
684688
)
685689

packages/opencode/src/tool/registry.ts

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ export namespace ToolRegistry {
5050
export interface Interface {
5151
readonly ids: () => Effect.Effect<string[]>
5252
readonly all: () => Effect.Effect<Tool.Def[]>
53+
readonly named: {
54+
task: Tool.Info
55+
read: Tool.Info
56+
}
5357
readonly tools: (model: {
5458
providerID: ProviderID
5559
modelID: ModelID
@@ -67,6 +71,7 @@ export namespace ToolRegistry {
6771
| Plugin.Service
6872
| Question.Service
6973
| Todo.Service
74+
| Agent.Service
7075
| LSP.Service
7176
| FileTime.Service
7277
| Instruction.Service
@@ -77,8 +82,10 @@ export namespace ToolRegistry {
7782
const config = yield* Config.Service
7883
const plugin = yield* Plugin.Service
7984

80-
const build = <T extends Tool.Info>(tool: T | Effect.Effect<T, never, any>) =>
81-
Effect.isEffect(tool) ? tool.pipe(Effect.flatMap(Tool.init)) : Tool.init(tool)
85+
const task = yield* TaskTool
86+
const read = yield* ReadTool
87+
const question = yield* QuestionTool
88+
const todo = yield* TodoWriteTool
8289

8390
const state = yield* InstanceState.make<State>(
8491
Effect.fn("ToolRegistry.state")(function* (ctx) {
@@ -90,11 +97,11 @@ export namespace ToolRegistry {
9097
parameters: z.object(def.args),
9198
description: def.description,
9299
execute: async (args, toolCtx) => {
93-
const pluginCtx = {
100+
const pluginCtx: PluginToolContext = {
94101
...toolCtx,
95102
directory: ctx.directory,
96103
worktree: ctx.worktree,
97-
} as unknown as PluginToolContext
104+
}
98105
const result = await def.execute(args as any, pluginCtx)
99106
const out = await Truncate.output(result, {}, await Agent.get(toolCtx.agent))
100107
return {
@@ -132,34 +139,50 @@ export namespace ToolRegistry {
132139
}
133140

134141
const cfg = yield* config.get()
135-
const question =
142+
const questionEnabled =
136143
["app", "cli", "desktop"].includes(Flag.OPENCODE_CLIENT) || Flag.OPENCODE_ENABLE_QUESTION_TOOL
137144

145+
const tool = yield* Effect.all({
146+
invalid: Tool.init(InvalidTool),
147+
bash: Tool.init(BashTool),
148+
read: Tool.init(read),
149+
glob: Tool.init(GlobTool),
150+
grep: Tool.init(GrepTool),
151+
edit: Tool.init(EditTool),
152+
write: Tool.init(WriteTool),
153+
task: Tool.init(task),
154+
fetch: Tool.init(WebFetchTool),
155+
todo: Tool.init(todo),
156+
search: Tool.init(WebSearchTool),
157+
code: Tool.init(CodeSearchTool),
158+
skill: Tool.init(SkillTool),
159+
patch: Tool.init(ApplyPatchTool),
160+
question: Tool.init(question),
161+
lsp: Tool.init(LspTool),
162+
plan: Tool.init(PlanExitTool),
163+
})
164+
138165
return {
139166
custom,
140-
builtin: yield* Effect.forEach(
141-
[
142-
InvalidTool,
143-
BashTool,
144-
ReadTool,
145-
GlobTool,
146-
GrepTool,
147-
EditTool,
148-
WriteTool,
149-
TaskTool,
150-
WebFetchTool,
151-
TodoWriteTool,
152-
WebSearchTool,
153-
CodeSearchTool,
154-
SkillTool,
155-
ApplyPatchTool,
156-
...(question ? [QuestionTool] : []),
157-
...(Flag.OPENCODE_EXPERIMENTAL_LSP_TOOL ? [LspTool] : []),
158-
...(Flag.OPENCODE_EXPERIMENTAL_PLAN_MODE && Flag.OPENCODE_CLIENT === "cli" ? [PlanExitTool] : []),
159-
],
160-
build,
161-
{ concurrency: "unbounded" },
162-
),
167+
builtin: [
168+
tool.invalid,
169+
...(questionEnabled ? [tool.question] : []),
170+
tool.bash,
171+
tool.read,
172+
tool.glob,
173+
tool.grep,
174+
tool.edit,
175+
tool.write,
176+
tool.task,
177+
tool.fetch,
178+
tool.todo,
179+
tool.search,
180+
tool.code,
181+
tool.skill,
182+
tool.patch,
183+
...(Flag.OPENCODE_EXPERIMENTAL_LSP_TOOL ? [tool.lsp] : []),
184+
...(Flag.OPENCODE_EXPERIMENTAL_PLAN_MODE && Flag.OPENCODE_CLIENT === "cli" ? [tool.plan] : []),
185+
],
163186
}
164187
}),
165188
)
@@ -208,7 +231,6 @@ export namespace ToolRegistry {
208231
id: tool.id,
209232
description: [
210233
output.description,
211-
// TODO: remove this hack
212234
tool.id === TaskTool.id ? yield* TaskDescription(input.agent) : undefined,
213235
tool.id === SkillTool.id ? yield* SkillDescription(input.agent) : undefined,
214236
]
@@ -223,7 +245,7 @@ export namespace ToolRegistry {
223245
)
224246
})
225247

226-
return Service.of({ ids, tools, all, fromID })
248+
return Service.of({ ids, all, named: { task, read }, tools, fromID })
227249
}),
228250
)
229251

@@ -234,6 +256,7 @@ export namespace ToolRegistry {
234256
Layer.provide(Plugin.defaultLayer),
235257
Layer.provide(Question.defaultLayer),
236258
Layer.provide(Todo.defaultLayer),
259+
Layer.provide(Agent.defaultLayer),
237260
Layer.provide(LSP.defaultLayer),
238261
Layer.provide(FileTime.defaultLayer),
239262
Layer.provide(Instruction.defaultLayer),

0 commit comments

Comments
 (0)