use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)

kit/effectify-tool-registry
Kit Langton 2026-03-19 16:02:04 -04:00
parent d08c119743
commit 1af7d26a86
1 changed files with 29 additions and 19 deletions

View File

@ -30,7 +30,7 @@ import { Truncate } from "./truncate"
import { ApplyPatchTool } from "./apply_patch"
import { Glob } from "../util/glob"
import { pathToFileURL } from "url"
import { Effect, Layer, ServiceMap } from "effect"
import { Effect, Fiber, Layer, ServiceMap } from "effect"
import { InstanceContext } from "@/effect/instance-context"
import { runPromiseInstance } from "@/effect/runtime"
@ -55,29 +55,36 @@ export namespace ToolRegistry {
const custom: Tool.Info[] = []
yield* Effect.promise(async () => {
const matches = await Config.directories().then((dirs) =>
dirs.flatMap((dir) =>
Glob.scanSync("{tool,tools}/*.{js,ts}", { cwd: dir, absolute: true, dot: true, symlink: true }),
),
)
if (matches.length) await Config.waitForDependencies()
for (const match of matches) {
const namespace = path.basename(match, path.extname(match))
const mod = await import(pathToFileURL(match).href)
for (const [id, def] of Object.entries<ToolDefinition>(mod)) {
custom.push(fromPlugin(id === "default" ? namespace : `${namespace}_${id}`, def))
const load = Effect.fn("ToolRegistry.load")(function* () {
yield* Effect.promise(async () => {
const matches = await Config.directories().then((dirs) =>
dirs.flatMap((dir) =>
Glob.scanSync("{tool,tools}/*.{js,ts}", { cwd: dir, absolute: true, dot: true, symlink: true }),
),
)
if (matches.length) await Config.waitForDependencies()
for (const match of matches) {
const namespace = path.basename(match, path.extname(match))
const mod = await import(pathToFileURL(match).href)
for (const [id, def] of Object.entries<ToolDefinition>(mod)) {
custom.push(fromPlugin(id === "default" ? namespace : `${namespace}_${id}`, def))
}
}
}
const plugins = await Plugin.list()
for (const plugin of plugins) {
for (const [id, def] of Object.entries(plugin.tool ?? {})) {
custom.push(fromPlugin(id, def))
const plugins = await Plugin.list()
for (const plugin of plugins) {
for (const [id, def] of Object.entries(plugin.tool ?? {})) {
custom.push(fromPlugin(id, def))
}
}
}
})
})
const loadFiber = yield* load().pipe(
Effect.catchCause(() => Effect.void),
Effect.forkScoped,
)
function fromPlugin(id: string, def: ToolDefinition): Tool.Info {
return {
id,
@ -131,6 +138,7 @@ export namespace ToolRegistry {
}
const register = Effect.fn("ToolRegistry.register")(function* (tool: Tool.Info) {
yield* Fiber.join(loadFiber)
const idx = custom.findIndex((t) => t.id === tool.id)
if (idx >= 0) {
custom.splice(idx, 1, tool)
@ -140,6 +148,7 @@ export namespace ToolRegistry {
})
const ids = Effect.fn("ToolRegistry.ids")(function* () {
yield* Fiber.join(loadFiber)
const tools = yield* Effect.promise(() => all())
return tools.map((t) => t.id)
})
@ -148,6 +157,7 @@ export namespace ToolRegistry {
model: { providerID: ProviderID; modelID: ModelID },
agent?: Agent.Info,
) {
yield* Fiber.join(loadFiber)
const allTools = yield* Effect.promise(() => all())
return yield* Effect.promise(() =>
Promise.all(