@@ -33,6 +33,7 @@ import { Effect, Layer, ServiceMap } from "effect"
3333import { InstanceState } from "@/effect/instance-state"
3434import { makeRuntime } from "@/effect/run-service"
3535import { Env } from "../env"
36+ import { Question } from "../question"
3637
3738export namespace ToolRegistry {
3839 const log = Log . create ( { service : "tool.registry" } )
@@ -42,8 +43,12 @@ export namespace ToolRegistry {
4243 }
4344
4445 export interface Interface {
45- readonly register : ( tool : Tool . Info ) => Effect . Effect < void >
4646 readonly ids : ( ) => Effect . Effect < string [ ] >
47+ readonly named : {
48+ task : Tool . Info
49+ read : Tool . Info
50+ edit : Tool . Info
51+ }
4752 readonly tools : (
4853 model : { providerID : ProviderID ; modelID : ModelID } ,
4954 agent ?: Agent . Info ,
@@ -52,12 +57,15 @@ export namespace ToolRegistry {
5257
5358 export class Service extends ServiceMap . Service < Service , Interface > ( ) ( "@opencode/ToolRegistry" ) { }
5459
55- export const layer : Layer . Layer < Service , never , Config . Service | Plugin . Service > = Layer . effect (
60+ export const layer : Layer . Layer < Service , never , Config . Service | Plugin . Service | Question . Service > = Layer . effect (
5661 Service ,
5762 Effect . gen ( function * ( ) {
5863 const config = yield * Config . Service
5964 const plugin = yield * Plugin . Service
6065
66+ const build = < T extends Tool . Info > ( tool : T | Effect . Effect < T , never , any > ) =>
67+ Effect . isEffect ( tool ) ? tool : Effect . succeed ( tool )
68+
6169 const state = yield * InstanceState . make < State > (
6270 Effect . fn ( "ToolRegistry.state" ) ( function * ( ctx ) {
6371 const custom : Tool . Info [ ] = [ ]
@@ -112,43 +120,52 @@ export namespace ToolRegistry {
112120 } ) ,
113121 )
114122
123+ const invalid = yield * build ( InvalidTool )
124+ const ask = yield * build ( QuestionTool )
125+ const bash = yield * build ( BashTool )
126+ const read = yield * build ( ReadTool )
127+ const glob = yield * build ( GlobTool )
128+ const grep = yield * build ( GrepTool )
129+ const edit = yield * build ( EditTool )
130+ const write = yield * build ( WriteTool )
131+ const task = yield * build ( TaskTool )
132+ const fetch = yield * build ( WebFetchTool )
133+ const todo = yield * build ( TodoWriteTool )
134+ const search = yield * build ( WebSearchTool )
135+ const code = yield * build ( CodeSearchTool )
136+ const skill = yield * build ( SkillTool )
137+ const patch = yield * build ( ApplyPatchTool )
138+ const lsp = yield * build ( LspTool )
139+ const batch = yield * build ( BatchTool )
140+ const plan = yield * build ( PlanExitTool )
141+
115142 const all = Effect . fn ( "ToolRegistry.all" ) ( function * ( custom : Tool . Info [ ] ) {
116143 const cfg = yield * config . get ( )
117144 const question = [ "app" , "cli" , "desktop" ] . includes ( Flag . OPENCODE_CLIENT ) || Flag . OPENCODE_ENABLE_QUESTION_TOOL
118145
119146 return [
120- InvalidTool ,
121- ...( question ? [ QuestionTool ] : [ ] ) ,
122- BashTool ,
123- ReadTool ,
124- GlobTool ,
125- GrepTool ,
126- EditTool ,
127- WriteTool ,
128- TaskTool ,
129- WebFetchTool ,
130- TodoWriteTool ,
131- WebSearchTool ,
132- CodeSearchTool ,
133- SkillTool ,
134- ApplyPatchTool ,
135- ...( Flag . OPENCODE_EXPERIMENTAL_LSP_TOOL ? [ LspTool ] : [ ] ) ,
136- ...( cfg . experimental ?. batch_tool === true ? [ BatchTool ] : [ ] ) ,
137- ...( Flag . OPENCODE_EXPERIMENTAL_PLAN_MODE && Flag . OPENCODE_CLIENT === "cli" ? [ PlanExitTool ] : [ ] ) ,
147+ invalid ,
148+ ...( question ? [ ask ] : [ ] ) ,
149+ bash ,
150+ read ,
151+ glob ,
152+ grep ,
153+ edit ,
154+ write ,
155+ task ,
156+ fetch ,
157+ todo ,
158+ search ,
159+ code ,
160+ skill ,
161+ patch ,
162+ ...( Flag . OPENCODE_EXPERIMENTAL_LSP_TOOL ? [ lsp ] : [ ] ) ,
163+ ...( cfg . experimental ?. batch_tool === true ? [ batch ] : [ ] ) ,
164+ ...( Flag . OPENCODE_EXPERIMENTAL_PLAN_MODE && Flag . OPENCODE_CLIENT === "cli" ? [ plan ] : [ ] ) ,
138165 ...custom ,
139166 ]
140167 } )
141168
142- const register = Effect . fn ( "ToolRegistry.register" ) ( function * ( tool : Tool . Info ) {
143- const s = yield * InstanceState . get ( state )
144- const idx = s . custom . findIndex ( ( t ) => t . id === tool . id )
145- if ( idx >= 0 ) {
146- s . custom . splice ( idx , 1 , tool )
147- return
148- }
149- s . custom . push ( tool )
150- } )
151-
152169 const ids = Effect . fn ( "ToolRegistry.ids" ) ( function * ( ) {
153170 const s = yield * InstanceState . get ( state )
154171 const tools = yield * all ( s . custom )
@@ -196,12 +213,18 @@ export namespace ToolRegistry {
196213 )
197214 } )
198215
199- return Service . of ( { register , ids , tools } )
216+ return Service . of ( { ids , named : { task , read , edit } , tools } )
200217 } ) ,
201218 )
202219
203220 export const defaultLayer = Layer . unwrap (
204- Effect . sync ( ( ) => layer . pipe ( Layer . provide ( Config . defaultLayer ) , Layer . provide ( Plugin . defaultLayer ) ) ) ,
221+ Effect . sync ( ( ) =>
222+ layer . pipe (
223+ Layer . provide ( Config . defaultLayer ) ,
224+ Layer . provide ( Plugin . defaultLayer ) ,
225+ Layer . provide ( Question . defaultLayer ) ,
226+ ) ,
227+ ) ,
205228 )
206229
207230 const { runPromise } = makeRuntime ( Service , defaultLayer )
0 commit comments