From a550ebf6821225757f0b70b16ff493dc08ea216a Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Sat, 11 Apr 2026 13:47:26 -0400 Subject: [PATCH] refactor(tool): yield Truncate and Agent in Tool.define, close over in wrap Services are resolved at define-time (in registry context), passed into wrap as closed-over values. Info.init() and Tool.init() stay R=never. Tests updated to provide Truncate.defaultLayer and Agent.defaultLayer. --- .../opencode/test/tool/apply_patch.test.ts | 9 +-------- packages/opencode/test/tool/edit.test.ts | 10 +--------- packages/opencode/test/tool/grep.test.ts | 4 +--- packages/opencode/test/tool/question.test.ts | 4 +--- packages/opencode/test/tool/skill.test.ts | 4 +--- packages/opencode/test/tool/webfetch.test.ts | 18 +++++++++++++----- 6 files changed, 18 insertions(+), 31 deletions(-) diff --git a/packages/opencode/test/tool/apply_patch.test.ts b/packages/opencode/test/tool/apply_patch.test.ts index 03220ea3b1..d65b1126c4 100644 --- a/packages/opencode/test/tool/apply_patch.test.ts +++ b/packages/opencode/test/tool/apply_patch.test.ts @@ -14,14 +14,7 @@ import { tmpdir } from "../fixture/fixture" import { SessionID, MessageID } from "../../src/session/schema" const runtime = ManagedRuntime.make( - Layer.mergeAll( - LSP.defaultLayer, - AppFileSystem.defaultLayer, - Format.defaultLayer, - Bus.layer, - Truncate.defaultLayer, - Agent.defaultLayer, - ), + Layer.mergeAll(LSP.defaultLayer, AppFileSystem.defaultLayer, Format.defaultLayer, Bus.layer, Truncate.defaultLayer, Agent.defaultLayer), ) const baseCtx = { diff --git a/packages/opencode/test/tool/edit.test.ts b/packages/opencode/test/tool/edit.test.ts index e3f28df35d..c19c22d2c5 100644 --- a/packages/opencode/test/tool/edit.test.ts +++ b/packages/opencode/test/tool/edit.test.ts @@ -36,15 +36,7 @@ async function touch(file: string, time: number) { } const runtime = ManagedRuntime.make( - Layer.mergeAll( - LSP.defaultLayer, - FileTime.defaultLayer, - AppFileSystem.defaultLayer, - Format.defaultLayer, - Bus.layer, - Truncate.defaultLayer, - Agent.defaultLayer, - ), + Layer.mergeAll(LSP.defaultLayer, FileTime.defaultLayer, AppFileSystem.defaultLayer, Format.defaultLayer, Bus.layer, Truncate.defaultLayer, Agent.defaultLayer), ) afterAll(async () => { diff --git a/packages/opencode/test/tool/grep.test.ts b/packages/opencode/test/tool/grep.test.ts index 4715ad9251..926b26003c 100644 --- a/packages/opencode/test/tool/grep.test.ts +++ b/packages/opencode/test/tool/grep.test.ts @@ -9,9 +9,7 @@ import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" import { Truncate } from "../../src/tool/truncate" import { Agent } from "../../src/agent/agent" -const runtime = ManagedRuntime.make( - Layer.mergeAll(CrossSpawnSpawner.defaultLayer, Truncate.defaultLayer, Agent.defaultLayer), -) +const runtime = ManagedRuntime.make(Layer.mergeAll(CrossSpawnSpawner.defaultLayer, Truncate.defaultLayer, Agent.defaultLayer)) function initGrep() { return runtime.runPromise(GrepTool.pipe(Effect.flatMap((info) => info.init()))) diff --git a/packages/opencode/test/tool/question.test.ts b/packages/opencode/test/tool/question.test.ts index eb69f1d966..4b94552368 100644 --- a/packages/opencode/test/tool/question.test.ts +++ b/packages/opencode/test/tool/question.test.ts @@ -21,9 +21,7 @@ const ctx = { ask: () => Effect.void, } -const it = testEffect( - Layer.mergeAll(Question.defaultLayer, CrossSpawnSpawner.defaultLayer, Truncate.defaultLayer, Agent.defaultLayer), -) +const it = testEffect(Layer.mergeAll(Question.defaultLayer, CrossSpawnSpawner.defaultLayer, Truncate.defaultLayer, Agent.defaultLayer)) const pending = Effect.fn("QuestionToolTest.pending")(function* (question: Question.Interface) { for (;;) { diff --git a/packages/opencode/test/tool/skill.test.ts b/packages/opencode/test/tool/skill.test.ts index a3873dbebe..85af7f3789 100644 --- a/packages/opencode/test/tool/skill.test.ts +++ b/packages/opencode/test/tool/skill.test.ts @@ -152,9 +152,7 @@ Use this skill. await Instance.provide({ directory: tmp.path, fn: async () => { - const runtime = ManagedRuntime.make( - Layer.mergeAll(Skill.defaultLayer, Ripgrep.defaultLayer, Truncate.defaultLayer, Agent.defaultLayer), - ) + const runtime = ManagedRuntime.make(Layer.mergeAll(Skill.defaultLayer, Ripgrep.defaultLayer, Truncate.defaultLayer, Agent.defaultLayer)) const info = await runtime.runPromise(SkillTool) const tool = await runtime.runPromise(info.init()) const requests: Array> = [] diff --git a/packages/opencode/test/tool/webfetch.test.ts b/packages/opencode/test/tool/webfetch.test.ts index 7d2ff1dcab..789d2ca474 100644 --- a/packages/opencode/test/tool/webfetch.test.ts +++ b/packages/opencode/test/tool/webfetch.test.ts @@ -26,10 +26,9 @@ async function withFetch(fetch: (req: Request) => Response | Promise, await fn(server.url) } -function exec(args: { url: string; format: "text" | "markdown" | "html" }) { +function initTool() { return WebFetchTool.pipe( Effect.flatMap((info) => info.init()), - Effect.flatMap((tool) => tool.execute(args, ctx)), Effect.provide(Layer.mergeAll(FetchHttpClient.layer, Truncate.defaultLayer, Agent.defaultLayer)), Effect.runPromise, ) @@ -44,7 +43,10 @@ describe("tool.webfetch", () => { await Instance.provide({ directory: projectRoot, fn: async () => { - const result = await exec({ url: new URL("/image.png", url).toString(), format: "markdown" }) + const webfetch = await initTool() + const result = await Effect.runPromise( + webfetch.execute({ url: new URL("/image.png", url).toString(), format: "markdown" }, ctx), + ) expect(result.output).toBe("Image fetched successfully") expect(result.attachments).toBeDefined() expect(result.attachments?.length).toBe(1) @@ -72,7 +74,10 @@ describe("tool.webfetch", () => { await Instance.provide({ directory: projectRoot, fn: async () => { - const result = await exec({ url: new URL("/image.svg", url).toString(), format: "html" }) + const webfetch = await initTool() + const result = await Effect.runPromise( + webfetch.execute({ url: new URL("/image.svg", url).toString(), format: "html" }, ctx), + ) expect(result.output).toContain(" { await Instance.provide({ directory: projectRoot, fn: async () => { - const result = await exec({ url: new URL("/file.txt", url).toString(), format: "text" }) + const webfetch = await initTool() + const result = await Effect.runPromise( + webfetch.execute({ url: new URL("/file.txt", url).toString(), format: "text" }, ctx), + ) expect(result.output).toBe("hello from webfetch") expect(result.attachments).toBeUndefined() },