forked from anomalyco/opencode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtool-define.test.ts
More file actions
104 lines (88 loc) · 3.12 KB
/
tool-define.test.ts
File metadata and controls
104 lines (88 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { describe, expect } from "bun:test"
import { Effect, Layer, Schema } from "effect"
import { Agent } from "../../src/agent/agent"
import { MessageID, SessionID } from "../../src/session/schema"
import { Tool } from "@/tool/tool"
import { Truncate } from "@/tool/truncate"
import { testEffect } from "../lib/effect"
const it = testEffect(Layer.mergeAll(Truncate.defaultLayer, Agent.defaultLayer))
const params = Schema.Struct({ input: Schema.String })
function makeTool(id: string, executeFn?: () => void) {
return {
description: "test tool",
parameters: params,
execute() {
executeFn?.()
return Effect.succeed({ title: "test", output: "ok", metadata: {} })
},
}
}
describe("Tool.define", () => {
it.effect("object-defined tool does not mutate the original init object", () =>
Effect.gen(function* () {
const original = makeTool("test")
const originalExecute = original.execute
const info = yield* Tool.define("test-tool", Effect.succeed(original))
yield* info.init()
yield* info.init()
yield* info.init()
expect(original.execute).toBe(originalExecute)
}),
)
it.effect("effect-defined tool returns fresh objects and is unaffected", () =>
Effect.gen(function* () {
const info = yield* Tool.define(
"test-fn-tool",
Effect.succeed(() => Effect.succeed(makeTool("test"))),
)
const first = yield* info.init()
const second = yield* info.init()
expect(first).not.toBe(second)
}),
)
it.effect("object-defined tool returns distinct objects per init() call", () =>
Effect.gen(function* () {
const info = yield* Tool.define("test-copy", Effect.succeed(makeTool("test")))
const first = yield* info.init()
const second = yield* info.init()
expect(first).not.toBe(second)
}),
)
it.effect("execute receives decoded parameters", () =>
Effect.gen(function* () {
const parameters = Schema.Struct({
count: Schema.NumberFromString.pipe(Schema.optional, Schema.withDecodingDefaultType(Effect.succeed(5))),
})
const calls: Array<Schema.Schema.Type<typeof parameters>> = []
const info = yield* Tool.define(
"test-decoded",
Effect.succeed({
description: "test tool",
parameters,
execute(args: Schema.Schema.Type<typeof parameters>) {
calls.push(args)
return Effect.succeed({ title: "test", output: "ok", metadata: { truncated: false } })
},
}),
)
const ctx: Tool.Context = {
sessionID: SessionID.descending(),
messageID: MessageID.ascending(),
agent: "build",
abort: new AbortController().signal,
messages: [],
metadata() {
return Effect.void
},
ask() {
return Effect.void
},
}
const tool = yield* info.init()
const execute = tool.execute as unknown as (args: unknown, ctx: Tool.Context) => ReturnType<typeof tool.execute>
yield* execute({}, ctx)
yield* execute({ count: "7" }, ctx)
expect(calls).toEqual([{ count: 5 }, { count: 7 }])
}),
)
})