clanka 0.0.28 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Agent.d.ts +87 -40
- package/dist/Agent.d.ts.map +1 -1
- package/dist/Agent.js +154 -94
- package/dist/Agent.js.map +1 -1
- package/dist/AgentExecutor.d.ts +165 -0
- package/dist/AgentExecutor.d.ts.map +1 -0
- package/dist/AgentExecutor.js +121 -0
- package/dist/AgentExecutor.js.map +1 -0
- package/dist/AgentTools.d.ts +14 -132
- package/dist/AgentTools.d.ts.map +1 -1
- package/dist/AgentTools.js +10 -12
- package/dist/AgentTools.js.map +1 -1
- package/dist/OutputFormatter.d.ts.map +1 -1
- package/dist/OutputFormatter.js +18 -0
- package/dist/OutputFormatter.js.map +1 -1
- package/dist/WebToMarkdown.d.ts.map +1 -1
- package/dist/WebToMarkdown.js +1 -1
- package/dist/WebToMarkdown.js.map +1 -1
- package/dist/WebToMarkdown.test.d.ts +2 -0
- package/dist/WebToMarkdown.test.d.ts.map +1 -0
- package/dist/WebToMarkdown.test.js +37 -0
- package/dist/WebToMarkdown.test.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/Agent.ts +290 -215
- package/src/AgentExecutor.ts +245 -0
- package/src/AgentTools.ts +25 -22
- package/src/OutputFormatter.ts +18 -0
- package/src/WebToMarkdown.test.ts +65 -0
- package/src/WebToMarkdown.ts +1 -0
- package/src/index.ts +4 -4
- package/dist/Agent.test.d.ts +0 -2
- package/dist/Agent.test.d.ts.map +0 -1
- package/dist/Agent.test.js +0 -111
- package/dist/Agent.test.js.map +0 -1
- package/dist/AgentTools.test.d.ts +0 -2
- package/dist/AgentTools.test.d.ts.map +0 -1
- package/dist/AgentTools.test.js +0 -714
- package/dist/AgentTools.test.js.map +0 -1
- package/dist/DuckDuckGo.d.ts +0 -28
- package/dist/DuckDuckGo.d.ts.map +0 -1
- package/dist/DuckDuckGo.js +0 -131
- package/dist/DuckDuckGo.js.map +0 -1
- package/dist/Executor.d.ts +0 -20
- package/dist/Executor.d.ts.map +0 -1
- package/dist/Executor.js +0 -98
- package/dist/Executor.js.map +0 -1
- package/dist/GithubCopilot.d.ts +0 -11
- package/dist/GithubCopilot.d.ts.map +0 -1
- package/dist/GithubCopilot.js +0 -14
- package/dist/GithubCopilot.js.map +0 -1
- package/dist/GithubCopilotAuth.d.ts +0 -57
- package/dist/GithubCopilotAuth.d.ts.map +0 -1
- package/dist/GithubCopilotAuth.js +0 -218
- package/dist/GithubCopilotAuth.js.map +0 -1
- package/dist/GithubCopilotAuth.test.d.ts +0 -2
- package/dist/GithubCopilotAuth.test.d.ts.map +0 -1
- package/dist/GithubCopilotAuth.test.js +0 -267
- package/dist/GithubCopilotAuth.test.js.map +0 -1
- package/dist/MockSearch.d.ts +0 -12
- package/dist/MockSearch.d.ts.map +0 -1
- package/dist/MockSearch.js +0 -4
- package/dist/MockSearch.js.map +0 -1
- package/dist/ai.d.ts +0 -2
- package/dist/ai.d.ts.map +0 -1
- package/dist/ai.js +0 -29
- package/dist/ai.js.map +0 -1
- package/dist/examples/cli.mjs +0 -68514
- package/src/Agent.test.ts +0 -159
- package/src/Executor.ts +0 -151
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
Cause,
|
|
6
|
+
Console,
|
|
7
|
+
Effect,
|
|
8
|
+
Exit,
|
|
9
|
+
Fiber,
|
|
10
|
+
FileSystem,
|
|
11
|
+
Layer,
|
|
12
|
+
Option,
|
|
13
|
+
Path,
|
|
14
|
+
pipe,
|
|
15
|
+
Queue,
|
|
16
|
+
Scope,
|
|
17
|
+
ServiceMap,
|
|
18
|
+
Stream,
|
|
19
|
+
} from "effect"
|
|
20
|
+
import { Tool, Toolkit } from "effect/unstable/ai"
|
|
21
|
+
import * as NodeConsole from "node:console"
|
|
22
|
+
import * as NodeVm from "node:vm"
|
|
23
|
+
import { Writable } from "node:stream"
|
|
24
|
+
import {
|
|
25
|
+
AgentToolHandlers,
|
|
26
|
+
AgentTools,
|
|
27
|
+
CurrentDirectory,
|
|
28
|
+
SubagentExecutor,
|
|
29
|
+
TaskCompleter,
|
|
30
|
+
} from "./AgentTools.ts"
|
|
31
|
+
import { ToolkitRenderer } from "./ToolkitRenderer.ts"
|
|
32
|
+
import type { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
|
|
33
|
+
import type { HttpClient } from "effect/unstable/http/HttpClient"
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @since 1.0.0
|
|
37
|
+
* @category Services
|
|
38
|
+
*/
|
|
39
|
+
export class AgentExecutor extends ServiceMap.Service<
|
|
40
|
+
AgentExecutor,
|
|
41
|
+
{
|
|
42
|
+
readonly toolsDts: Effect.Effect<string>
|
|
43
|
+
readonly agentsMd: Effect.Effect<Option.Option<string>>
|
|
44
|
+
execute(options: {
|
|
45
|
+
readonly script: string
|
|
46
|
+
readonly onTaskComplete: (summary: string) => Effect.Effect<void>
|
|
47
|
+
readonly onSubagent: (message: string) => Effect.Effect<string>
|
|
48
|
+
}): Stream.Stream<string>
|
|
49
|
+
}
|
|
50
|
+
>()("clanka/AgentExecutor") {}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @since 1.0.0
|
|
54
|
+
* @category Constructors
|
|
55
|
+
*/
|
|
56
|
+
export const makeLocal = Effect.fnUntraced(function* <
|
|
57
|
+
Toolkit extends Toolkit.Any = never,
|
|
58
|
+
>(options: {
|
|
59
|
+
readonly directory: string
|
|
60
|
+
readonly tools?: Toolkit | undefined
|
|
61
|
+
}): Effect.fn.Return<
|
|
62
|
+
AgentExecutor["Service"],
|
|
63
|
+
never,
|
|
64
|
+
| ToolkitRenderer
|
|
65
|
+
| FileSystem.FileSystem
|
|
66
|
+
| Path.Path
|
|
67
|
+
| Tool.HandlersFor<typeof AgentTools.tools>
|
|
68
|
+
| Exclude<
|
|
69
|
+
Toolkit extends Toolkit.Toolkit<infer T>
|
|
70
|
+
? Tool.HandlersFor<T> | Tool.HandlerServices<T[keyof T]>
|
|
71
|
+
: never,
|
|
72
|
+
CurrentDirectory | SubagentExecutor | TaskCompleter
|
|
73
|
+
>
|
|
74
|
+
> {
|
|
75
|
+
const fs = yield* FileSystem.FileSystem
|
|
76
|
+
const pathService = yield* Path.Path
|
|
77
|
+
const renderer = yield* ToolkitRenderer
|
|
78
|
+
const AllTools = Toolkit.merge(
|
|
79
|
+
AgentTools,
|
|
80
|
+
(options.tools as unknown as Toolkit.Toolkit<{}>) ?? Toolkit.empty,
|
|
81
|
+
)
|
|
82
|
+
const tools = yield* AllTools
|
|
83
|
+
const toolsDts = Effect.succeed(renderer.render(AllTools))
|
|
84
|
+
|
|
85
|
+
const services = yield* Effect.services()
|
|
86
|
+
|
|
87
|
+
const toolEntries = Object.entries(tools.tools).map(([name, tool]) => {
|
|
88
|
+
const handler = services.mapUnsafe.get(tool.id) as Tool.Handler<string>
|
|
89
|
+
return {
|
|
90
|
+
name,
|
|
91
|
+
services: ServiceMap.merge(services, handler.services),
|
|
92
|
+
handler: handler.handler,
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
const execute = Effect.fnUntraced(function* (opts: {
|
|
97
|
+
readonly script: string
|
|
98
|
+
readonly onTaskComplete: (summary: string) => Effect.Effect<void>
|
|
99
|
+
readonly onSubagent: (message: string) => Effect.Effect<string>
|
|
100
|
+
}) {
|
|
101
|
+
const output = yield* Queue.unbounded<string, Cause.Done>()
|
|
102
|
+
const console = yield* makeConsole(output)
|
|
103
|
+
const handlerScope = Scope.makeUnsafe("parallel")
|
|
104
|
+
const trackFiber = Fiber.runIn(handlerScope)
|
|
105
|
+
|
|
106
|
+
const taskServices = ServiceMap.make(
|
|
107
|
+
TaskCompleter,
|
|
108
|
+
opts.onTaskComplete,
|
|
109
|
+
).pipe(
|
|
110
|
+
ServiceMap.add(CurrentDirectory, options.directory),
|
|
111
|
+
ServiceMap.add(SubagentExecutor, opts.onSubagent),
|
|
112
|
+
ServiceMap.add(Console.Console, console),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
yield* Effect.gen(function* () {
|
|
116
|
+
const console = yield* Console.Console
|
|
117
|
+
let running = 0
|
|
118
|
+
|
|
119
|
+
const vmScript = new NodeVm.Script(`async function main() {
|
|
120
|
+
${opts.script}
|
|
121
|
+
}`)
|
|
122
|
+
const sandbox: ScriptSandbox = {
|
|
123
|
+
main: defaultMain,
|
|
124
|
+
console,
|
|
125
|
+
fetch,
|
|
126
|
+
process: undefined,
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
for (let i = 0; i < toolEntries.length; i++) {
|
|
130
|
+
const { name, handler, services } = toolEntries[i]!
|
|
131
|
+
const runFork = Effect.runForkWith(
|
|
132
|
+
ServiceMap.merge(services, taskServices),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
136
|
+
sandbox[name] = function (params: any) {
|
|
137
|
+
running++
|
|
138
|
+
const fiber = trackFiber(runFork(handler(params, {})))
|
|
139
|
+
return new Promise((resolve, reject) => {
|
|
140
|
+
fiber.addObserver((exit) => {
|
|
141
|
+
running--
|
|
142
|
+
if (exit._tag === "Success") {
|
|
143
|
+
return resolve(exit.value)
|
|
144
|
+
}
|
|
145
|
+
if (Cause.hasInterruptsOnly(exit.cause)) return
|
|
146
|
+
reject(Cause.squash(exit.cause))
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
vmScript.runInNewContext(sandbox, {
|
|
153
|
+
timeout: 1000,
|
|
154
|
+
})
|
|
155
|
+
yield* Effect.promise(sandbox.main)
|
|
156
|
+
while (true) {
|
|
157
|
+
yield* Effect.yieldNow
|
|
158
|
+
if (running === 0) break
|
|
159
|
+
}
|
|
160
|
+
}).pipe(
|
|
161
|
+
Effect.ensuring(Scope.close(handlerScope, Exit.void)),
|
|
162
|
+
Effect.catchCause(Effect.logFatal),
|
|
163
|
+
Effect.provideService(Console.Console, console),
|
|
164
|
+
Effect.ensuring(Queue.end(output)),
|
|
165
|
+
Effect.forkScoped,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return Stream.fromQueue(output)
|
|
169
|
+
}, Stream.unwrap)
|
|
170
|
+
|
|
171
|
+
return AgentExecutor.of({
|
|
172
|
+
toolsDts,
|
|
173
|
+
agentsMd: pipe(
|
|
174
|
+
fs.readFileString(pathService.join(options.directory, "AGENTS.md")),
|
|
175
|
+
Effect.option,
|
|
176
|
+
),
|
|
177
|
+
execute,
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @since 1.0.0
|
|
183
|
+
* @category Layers
|
|
184
|
+
*/
|
|
185
|
+
export const layerLocal = <Toolkit extends Toolkit.Any = never>(options: {
|
|
186
|
+
readonly directory: string
|
|
187
|
+
readonly tools?: Toolkit | undefined
|
|
188
|
+
}): Layer.Layer<
|
|
189
|
+
AgentExecutor,
|
|
190
|
+
never,
|
|
191
|
+
| FileSystem.FileSystem
|
|
192
|
+
| Path.Path
|
|
193
|
+
| ChildProcessSpawner
|
|
194
|
+
| HttpClient
|
|
195
|
+
| Exclude<
|
|
196
|
+
Toolkit extends Toolkit.Toolkit<infer T>
|
|
197
|
+
? Tool.HandlersFor<T> | Tool.HandlerServices<T[keyof T]>
|
|
198
|
+
: never,
|
|
199
|
+
CurrentDirectory | SubagentExecutor | TaskCompleter
|
|
200
|
+
>
|
|
201
|
+
> =>
|
|
202
|
+
Layer.effect(AgentExecutor, makeLocal(options)).pipe(
|
|
203
|
+
Layer.provide([AgentToolHandlers, ToolkitRenderer.layer]),
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
// ------------------------------------------
|
|
207
|
+
// Internal
|
|
208
|
+
// -------------------------------------------
|
|
209
|
+
|
|
210
|
+
interface ScriptSandbox {
|
|
211
|
+
main: () => Promise<void>
|
|
212
|
+
console: Console.Console
|
|
213
|
+
[toolName: string]: unknown
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const defaultMain = () => Promise.resolve()
|
|
217
|
+
|
|
218
|
+
const makeConsole = Effect.fn(function* (
|
|
219
|
+
queue: Queue.Queue<string, Cause.Done>,
|
|
220
|
+
) {
|
|
221
|
+
const writable = new QueueWriteStream(queue)
|
|
222
|
+
const newConsole = new NodeConsole.Console(writable)
|
|
223
|
+
yield* Effect.addFinalizer(() => {
|
|
224
|
+
writable.end()
|
|
225
|
+
return Effect.void
|
|
226
|
+
})
|
|
227
|
+
return newConsole
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
class QueueWriteStream extends Writable {
|
|
231
|
+
readonly queue: Queue.Enqueue<string, Cause.Done>
|
|
232
|
+
constructor(queue: Queue.Enqueue<string, Cause.Done>) {
|
|
233
|
+
super()
|
|
234
|
+
this.queue = queue
|
|
235
|
+
}
|
|
236
|
+
_write(
|
|
237
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
238
|
+
chunk: any,
|
|
239
|
+
_encoding: BufferEncoding,
|
|
240
|
+
callback: (error?: Error | null) => void,
|
|
241
|
+
): void {
|
|
242
|
+
Queue.offerUnsafe(this.queue, chunk.toString())
|
|
243
|
+
callback()
|
|
244
|
+
}
|
|
245
|
+
}
|
package/src/AgentTools.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import {
|
|
5
5
|
Array,
|
|
6
6
|
Data,
|
|
7
|
-
Deferred,
|
|
8
7
|
Effect,
|
|
9
8
|
FileSystem,
|
|
10
9
|
Layer,
|
|
@@ -20,6 +19,7 @@ import * as Glob from "glob"
|
|
|
20
19
|
import { parsePatch, patchChunks } from "./ApplyPatch.ts"
|
|
21
20
|
import * as ExaSearch from "./ExaSearch.ts"
|
|
22
21
|
import * as WebToMarkdown from "./WebToMarkdown.ts"
|
|
22
|
+
import type { HttpClient } from "effect/unstable/http/HttpClient"
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* @since 1.0.0
|
|
@@ -34,32 +34,28 @@ export class CurrentDirectory extends ServiceMap.Service<
|
|
|
34
34
|
* @since 1.0.0
|
|
35
35
|
* @category Context
|
|
36
36
|
*/
|
|
37
|
-
export class
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
>()("clanka/AgentTools/
|
|
37
|
+
export class TaskCompleter extends ServiceMap.Service<
|
|
38
|
+
TaskCompleter,
|
|
39
|
+
(output: string) => Effect.Effect<void>
|
|
40
|
+
>()("clanka/AgentTools/TaskCompleter") {}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* @since 1.0.0
|
|
44
44
|
* @category Context
|
|
45
45
|
*/
|
|
46
|
-
export class
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
>()("clanka/AgentTools/SubagentContext") {}
|
|
46
|
+
export class SubagentExecutor extends ServiceMap.Service<
|
|
47
|
+
SubagentExecutor,
|
|
48
|
+
(prompt: string) => Effect.Effect<string>
|
|
49
|
+
>()("clanka/AgentTools/SubagentExecutor") {}
|
|
52
50
|
|
|
53
51
|
/**
|
|
54
52
|
* @since 1.0.0
|
|
55
53
|
* @category Context
|
|
56
54
|
*/
|
|
57
55
|
export const makeContextNoop = (cwd?: string) =>
|
|
58
|
-
|
|
59
|
-
spawn: () => Effect.die("Not implemented"),
|
|
60
|
-
}).pipe(
|
|
56
|
+
SubagentExecutor.serviceMap(() => Effect.die("Not implemented")).pipe(
|
|
61
57
|
ServiceMap.add(CurrentDirectory, cwd ?? "/"),
|
|
62
|
-
ServiceMap.add(
|
|
58
|
+
ServiceMap.add(TaskCompleter, () => Effect.void),
|
|
63
59
|
)
|
|
64
60
|
|
|
65
61
|
/**
|
|
@@ -176,7 +172,7 @@ export const AgentTools = Toolkit.make(
|
|
|
176
172
|
identifier: "task",
|
|
177
173
|
}),
|
|
178
174
|
success: Schema.String,
|
|
179
|
-
dependencies: [
|
|
175
|
+
dependencies: [SubagentExecutor],
|
|
180
176
|
}),
|
|
181
177
|
Tool.make("webSearch", {
|
|
182
178
|
description: "Search the web for recent information.",
|
|
@@ -202,7 +198,7 @@ export const AgentTools = Toolkit.make(
|
|
|
202
198
|
parameters: Schema.String.annotate({
|
|
203
199
|
identifier: "output",
|
|
204
200
|
}),
|
|
205
|
-
dependencies: [
|
|
201
|
+
dependencies: [TaskCompleter],
|
|
206
202
|
}),
|
|
207
203
|
)
|
|
208
204
|
|
|
@@ -525,12 +521,12 @@ export const AgentToolHandlersNoDeps = AgentTools.toLayer(
|
|
|
525
521
|
}, Effect.orDie),
|
|
526
522
|
delegate: Effect.fn("AgentTools.delegate")(function* (prompt) {
|
|
527
523
|
yield* Effect.logInfo(`Calling "delegate"`)
|
|
528
|
-
const
|
|
529
|
-
return yield*
|
|
524
|
+
const spawn = yield* SubagentExecutor
|
|
525
|
+
return yield* spawn(prompt)
|
|
530
526
|
}, Effect.orDie),
|
|
531
527
|
taskComplete: Effect.fn("AgentTools.taskComplete")(function* (message) {
|
|
532
|
-
const deferred = yield*
|
|
533
|
-
yield*
|
|
528
|
+
const deferred = yield* TaskCompleter
|
|
529
|
+
yield* deferred(message)
|
|
534
530
|
}),
|
|
535
531
|
})
|
|
536
532
|
}),
|
|
@@ -540,7 +536,14 @@ export const AgentToolHandlersNoDeps = AgentTools.toLayer(
|
|
|
540
536
|
* @since 1.0.0
|
|
541
537
|
* @category Layers
|
|
542
538
|
*/
|
|
543
|
-
export const AgentToolHandlers
|
|
539
|
+
export const AgentToolHandlers: Layer.Layer<
|
|
540
|
+
Tool.HandlersFor<typeof AgentTools.tools>,
|
|
541
|
+
never,
|
|
542
|
+
| FileSystem.FileSystem
|
|
543
|
+
| Path.Path
|
|
544
|
+
| ChildProcessSpawner.ChildProcessSpawner
|
|
545
|
+
| HttpClient
|
|
546
|
+
> = AgentToolHandlersNoDeps.pipe(
|
|
544
547
|
Layer.provide([ExaSearch.layer, WebToMarkdown.layer]),
|
|
545
548
|
)
|
|
546
549
|
|
package/src/OutputFormatter.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { Effect, Layer, PubSub, Semaphore, ServiceMap, Stream } from "effect"
|
|
5
5
|
import { type Output, AgentFinished } from "./Agent.ts"
|
|
6
6
|
import chalk from "chalk"
|
|
7
|
+
import type { Prompt } from "effect/unstable/ai"
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @since 1.0.0
|
|
@@ -26,6 +27,9 @@ export const pretty: OutputFormatter = (stream) =>
|
|
|
26
27
|
output = output.part
|
|
27
28
|
}
|
|
28
29
|
switch (output._tag) {
|
|
30
|
+
case "AgentStart": {
|
|
31
|
+
return `${chalkAgentHeading(`${subagentIcon} Agent #${output.id} starting (${output.modelAndProvider})`)}\n\n${promptToString(output.prompt)}\n\n`
|
|
32
|
+
}
|
|
29
33
|
case "SubagentStart": {
|
|
30
34
|
return `${chalkSubagentHeading(`${subagentIcon} Subagent #${output.id} starting (${output.modelAndProvider})`)}
|
|
31
35
|
|
|
@@ -73,6 +77,20 @@ ${output.summary}\n\n`
|
|
|
73
77
|
),
|
|
74
78
|
)
|
|
75
79
|
|
|
80
|
+
const promptToString = (prompt: Prompt.Prompt): string => {
|
|
81
|
+
let textParts: string[] = []
|
|
82
|
+
for (const message of prompt.content) {
|
|
83
|
+
if (message.role !== "user") continue
|
|
84
|
+
let content = message.content
|
|
85
|
+
for (const part of content) {
|
|
86
|
+
if (part.type !== "text") continue
|
|
87
|
+
textParts.push(part.text)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return textParts.join("\n")
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const chalkAgentHeading = chalk.bold.green
|
|
76
94
|
const chalkScriptHeading = chalk.bold.blue
|
|
77
95
|
const chalkSubagentHeading = chalk.bold.magenta
|
|
78
96
|
const chalkReasoningHeading = chalk.bold.yellow
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { assert, describe, it } from "@effect/vitest"
|
|
2
|
+
import { Effect, Ref } from "effect"
|
|
3
|
+
import {
|
|
4
|
+
HttpClient,
|
|
5
|
+
HttpClientRequest,
|
|
6
|
+
HttpClientResponse,
|
|
7
|
+
} from "effect/unstable/http"
|
|
8
|
+
import * as WebToMarkdown from "./WebToMarkdown.ts"
|
|
9
|
+
|
|
10
|
+
describe("WebToMarkdown", () => {
|
|
11
|
+
it.effect("convertUrl follows redirects", () =>
|
|
12
|
+
Effect.gen(function* () {
|
|
13
|
+
const requests = yield* Ref.make<Array<string>>([])
|
|
14
|
+
const client = HttpClient.make(
|
|
15
|
+
(request: HttpClientRequest.HttpClientRequest) =>
|
|
16
|
+
Effect.gen(function* () {
|
|
17
|
+
yield* Ref.update(requests, (current) => [...current, request.url])
|
|
18
|
+
|
|
19
|
+
if (request.url === "https://example.com/start") {
|
|
20
|
+
return HttpClientResponse.fromWeb(
|
|
21
|
+
request,
|
|
22
|
+
new Response(null, {
|
|
23
|
+
status: 302,
|
|
24
|
+
headers: { location: "/article" },
|
|
25
|
+
}),
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (request.url === "https://example.com/article") {
|
|
30
|
+
return HttpClientResponse.fromWeb(
|
|
31
|
+
request,
|
|
32
|
+
new Response("<main><h1>Hello</h1><p>World</p></main>", {
|
|
33
|
+
status: 200,
|
|
34
|
+
headers: { "content-type": "text/html" },
|
|
35
|
+
}),
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return HttpClientResponse.fromWeb(
|
|
40
|
+
request,
|
|
41
|
+
new Response("not found", { status: 404 }),
|
|
42
|
+
)
|
|
43
|
+
}),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
const { markdown, seen } = yield* Effect.gen(function* () {
|
|
47
|
+
const webToMarkdown = yield* WebToMarkdown.WebToMarkdown
|
|
48
|
+
const markdown = yield* webToMarkdown.convertUrl(
|
|
49
|
+
"https://example.com/start",
|
|
50
|
+
)
|
|
51
|
+
const seen = yield* Ref.get(requests)
|
|
52
|
+
return { markdown, seen }
|
|
53
|
+
}).pipe(
|
|
54
|
+
Effect.provide(WebToMarkdown.layer),
|
|
55
|
+
Effect.provideService(HttpClient.HttpClient, client),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
assert.deepStrictEqual(seen, [
|
|
59
|
+
"https://example.com/start",
|
|
60
|
+
"https://example.com/article",
|
|
61
|
+
])
|
|
62
|
+
assert.strictEqual(markdown.trim(), "Hello\n=====\n\nWorld")
|
|
63
|
+
}),
|
|
64
|
+
)
|
|
65
|
+
})
|
package/src/WebToMarkdown.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -6,22 +6,22 @@ export * as Agent from "./Agent.ts"
|
|
|
6
6
|
/**
|
|
7
7
|
* @since 1.0.0
|
|
8
8
|
*/
|
|
9
|
-
export * as
|
|
9
|
+
export * as AgentExecutor from "./AgentExecutor.ts"
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @since 1.0.0
|
|
13
13
|
*/
|
|
14
|
-
export * as
|
|
14
|
+
export * as AgentTools from "./AgentTools.ts"
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* @since 1.0.0
|
|
18
18
|
*/
|
|
19
|
-
export * as
|
|
19
|
+
export * as Codex from "./Codex.ts"
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* @since 1.0.0
|
|
23
23
|
*/
|
|
24
|
-
export * as
|
|
24
|
+
export * as Copilot from "./Copilot.ts"
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* @since 1.0.0
|
package/dist/Agent.test.d.ts
DELETED
package/dist/Agent.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Agent.test.d.ts","sourceRoot":"","sources":["../src/Agent.test.ts"],"names":[],"mappings":""}
|
package/dist/Agent.test.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { NodeServices } from "@effect/platform-node";
|
|
2
|
-
import { Effect, Layer, Stream } from "effect";
|
|
3
|
-
import { describe, it } from "@effect/vitest";
|
|
4
|
-
import { expect } from "vitest";
|
|
5
|
-
import { AgentModelConfig, make } from "./Agent.js";
|
|
6
|
-
import { pretty } from "./OutputFormatter.js";
|
|
7
|
-
import { LanguageModel, Prompt } from "effect/unstable/ai";
|
|
8
|
-
import * as Model from "effect/unstable/ai/Model";
|
|
9
|
-
import { Executor } from "./Executor.js";
|
|
10
|
-
import { ToolkitRenderer } from "./ToolkitRenderer.js";
|
|
11
|
-
import { AgentToolHandlersTest } from "./AgentTools.js";
|
|
12
|
-
const usage = {
|
|
13
|
-
inputTokens: {
|
|
14
|
-
uncached: undefined,
|
|
15
|
-
total: undefined,
|
|
16
|
-
cacheRead: undefined,
|
|
17
|
-
cacheWrite: undefined,
|
|
18
|
-
},
|
|
19
|
-
outputTokens: {
|
|
20
|
-
total: undefined,
|
|
21
|
-
text: undefined,
|
|
22
|
-
reasoning: undefined,
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
const promptText = (prompt) => prompt.content
|
|
26
|
-
.flatMap((message) => {
|
|
27
|
-
if (typeof message.content === "string") {
|
|
28
|
-
return [message.content];
|
|
29
|
-
}
|
|
30
|
-
return message.content.flatMap((part) => {
|
|
31
|
-
switch (part.type) {
|
|
32
|
-
case "text":
|
|
33
|
-
case "reasoning":
|
|
34
|
-
return [part.text];
|
|
35
|
-
default:
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
})
|
|
40
|
-
.join("\n");
|
|
41
|
-
const scriptResponse = (script) => Stream.fromIterable([
|
|
42
|
-
{ type: "text-start", id: "script" },
|
|
43
|
-
{ type: "text-delta", id: "script", delta: script },
|
|
44
|
-
{ type: "text-end", id: "script" },
|
|
45
|
-
{
|
|
46
|
-
type: "finish",
|
|
47
|
-
reason: "stop",
|
|
48
|
-
usage,
|
|
49
|
-
response: undefined,
|
|
50
|
-
},
|
|
51
|
-
]);
|
|
52
|
-
const TestModel = Model.make("test-provider", "test-model", Layer.effect(LanguageModel.LanguageModel, LanguageModel.make({
|
|
53
|
-
generateText: () => Effect.succeed([]),
|
|
54
|
-
streamText: ({ prompt }) => {
|
|
55
|
-
const text = promptText(prompt);
|
|
56
|
-
if (text.includes("grandchild task")) {
|
|
57
|
-
return scriptResponse([
|
|
58
|
-
'console.log("grandchild output")',
|
|
59
|
-
'await taskComplete("grandchild summary")',
|
|
60
|
-
].join("\n"));
|
|
61
|
-
}
|
|
62
|
-
if (text.includes("child task")) {
|
|
63
|
-
return scriptResponse([
|
|
64
|
-
'const result = await delegate("grandchild task")',
|
|
65
|
-
"await taskComplete(`child summary: ${result}`)",
|
|
66
|
-
].join("\n"));
|
|
67
|
-
}
|
|
68
|
-
return scriptResponse([
|
|
69
|
-
'const result = await delegate("child task")',
|
|
70
|
-
"await taskComplete(`root summary: ${result}`)",
|
|
71
|
-
].join("\n"));
|
|
72
|
-
},
|
|
73
|
-
})));
|
|
74
|
-
describe("Agent", () => {
|
|
75
|
-
it.effect("forwards nested subagent output", () => Effect.gen(function* () {
|
|
76
|
-
const seen = [];
|
|
77
|
-
const agent = yield* make({
|
|
78
|
-
directory: process.cwd(),
|
|
79
|
-
prompt: "root task",
|
|
80
|
-
});
|
|
81
|
-
const output = yield* agent.output.pipe(Stream.tap((part) => Effect.sync(() => {
|
|
82
|
-
switch (part._tag) {
|
|
83
|
-
case "SubagentStart":
|
|
84
|
-
case "SubagentComplete":
|
|
85
|
-
seen.push(`${part._tag}:${part.id}`);
|
|
86
|
-
break;
|
|
87
|
-
case "SubagentPart":
|
|
88
|
-
seen.push(`${part._tag}:${part.id}:${part.part._tag}`);
|
|
89
|
-
break;
|
|
90
|
-
default:
|
|
91
|
-
seen.push(part._tag);
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
})), pretty, Stream.mkString);
|
|
95
|
-
expect(seen).toContain("SubagentStart:1");
|
|
96
|
-
expect(seen).toContain("SubagentStart:2");
|
|
97
|
-
expect(seen).toContain("SubagentPart:2:ScriptStart");
|
|
98
|
-
expect(seen).toContain("SubagentPart:2:ScriptOutput");
|
|
99
|
-
expect(seen).toContain("SubagentComplete:2");
|
|
100
|
-
expect(seen).toContain("SubagentComplete:1");
|
|
101
|
-
expect(output).toContain("Subagent #1 starting");
|
|
102
|
-
expect(output).toContain("Subagent #2 starting");
|
|
103
|
-
expect(output).toContain("grandchild output");
|
|
104
|
-
expect(output).toContain("Subagent #2 complete");
|
|
105
|
-
expect(output).toContain("Task complete:");
|
|
106
|
-
expect(output).toContain("root summary: child summary: grandchild summary");
|
|
107
|
-
}).pipe(Effect.provide(Layer.mergeAll(AgentToolHandlersTest, TestModel, AgentModelConfig.layer({
|
|
108
|
-
supportsNoTools: true,
|
|
109
|
-
}), Executor.layer, ToolkitRenderer.layer).pipe(Layer.provideMerge(NodeServices.layer)))));
|
|
110
|
-
});
|
|
111
|
-
//# sourceMappingURL=Agent.test.js.map
|
package/dist/Agent.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Agent.test.js","sourceRoot":"","sources":["../src/Agent.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AgentTools.test.d.ts","sourceRoot":"","sources":["../src/AgentTools.test.ts"],"names":[],"mappings":""}
|