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.
This commit is contained in:
Kit Langton
2026-04-11 13:47:26 -04:00
parent 3729fd5706
commit a550ebf682
6 changed files with 18 additions and 31 deletions

View File

@@ -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 = {

View File

@@ -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 () => {

View File

@@ -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())))

View File

@@ -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 (;;) {

View File

@@ -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<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []

View File

@@ -26,10 +26,9 @@ async function withFetch(fetch: (req: Request) => Response | Promise<Response>,
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("<svg")
expect(result.attachments).toBeUndefined()
},
@@ -92,7 +97,10 @@ describe("tool.webfetch", () => {
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()
},