clanka 0.3.1 → 0.5.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/Acp.d.ts.map +1 -1
- package/dist/Acp.js +3 -0
- package/dist/Acp.js.map +1 -1
- package/dist/Acp.test.js +58 -0
- package/dist/Acp.test.js.map +1 -1
- package/dist/Agent.d.ts +2 -2
- package/dist/Agent.d.ts.map +1 -1
- package/dist/Agent.js +86 -8
- package/dist/Agent.js.map +1 -1
- package/dist/Agent.test.js +671 -0
- package/dist/Agent.test.js.map +1 -1
- package/dist/AgentExecutor.d.ts +15 -4
- package/dist/AgentExecutor.d.ts.map +1 -1
- package/dist/AgentExecutor.js +43 -7
- package/dist/AgentExecutor.js.map +1 -1
- package/dist/AgentOutput.d.ts +49 -4
- package/dist/AgentOutput.d.ts.map +1 -1
- package/dist/AgentOutput.js +45 -0
- package/dist/AgentOutput.js.map +1 -1
- package/dist/AgentSkills.d.ts +56 -0
- package/dist/AgentSkills.d.ts.map +1 -0
- package/dist/AgentSkills.js +126 -0
- package/dist/AgentSkills.js.map +1 -0
- package/dist/AgentSkills.test.d.ts +2 -0
- package/dist/AgentSkills.test.d.ts.map +1 -0
- package/dist/AgentSkills.test.js +356 -0
- package/dist/AgentSkills.test.js.map +1 -0
- package/dist/AgentTools.d.ts +32 -1
- package/dist/AgentTools.d.ts.map +1 -1
- package/dist/AgentTools.js +26 -10
- package/dist/AgentTools.js.map +1 -1
- package/dist/Codex.js +1 -1
- package/dist/Codex.js.map +1 -1
- package/dist/Compaction.d.ts +342 -0
- package/dist/Compaction.d.ts.map +1 -0
- package/dist/Compaction.js +566 -0
- package/dist/Compaction.js.map +1 -0
- package/dist/Compaction.test.d.ts +2 -0
- package/dist/Compaction.test.d.ts.map +1 -0
- package/dist/Compaction.test.js +576 -0
- package/dist/Compaction.test.js.map +1 -0
- package/dist/CompactionTransport.test.d.ts +2 -0
- package/dist/CompactionTransport.test.d.ts.map +1 -0
- package/dist/CompactionTransport.test.js +123 -0
- package/dist/CompactionTransport.test.js.map +1 -0
- package/dist/Copilot.d.ts.map +1 -1
- package/dist/Copilot.js +7 -2
- package/dist/Copilot.js.map +1 -1
- package/dist/OutputFormatter.d.ts.map +1 -1
- package/dist/OutputFormatter.js +9 -0
- package/dist/OutputFormatter.js.map +1 -1
- package/dist/cli.js +13 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/Acp.test.ts +85 -0
- package/src/Acp.ts +2 -0
- package/src/Agent.test.ts +994 -0
- package/src/Agent.ts +129 -7
- package/src/AgentExecutor.ts +76 -32
- package/src/AgentOutput.ts +58 -0
- package/src/AgentSkills.test.ts +652 -0
- package/src/AgentSkills.ts +155 -0
- package/src/AgentTools.ts +34 -10
- package/src/Codex.ts +3 -1
- package/src/Compaction.test.ts +824 -0
- package/src/Compaction.ts +788 -0
- package/src/CompactionTransport.test.ts +228 -0
- package/src/Copilot.ts +8 -1
- package/src/OutputFormatter.ts +9 -0
- package/src/cli.ts +26 -5
- package/src/index.ts +6 -0
package/src/Agent.ts
CHANGED
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
import * as Model from "effect/unstable/ai/Model"
|
|
5
5
|
import type * as Response from "effect/unstable/ai/Response"
|
|
6
6
|
import * as AgentExecutor from "./AgentExecutor.ts"
|
|
7
|
+
import * as AgentSkills from "./AgentSkills.ts"
|
|
7
8
|
import { stripWrappingCodeFence } from "./ScriptExtraction.ts"
|
|
8
9
|
import type * as Path from "effect/Path"
|
|
9
10
|
import type * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner"
|
|
10
11
|
import type * as HttpClient from "effect/unstable/http/HttpClient"
|
|
11
12
|
import type {
|
|
12
13
|
CurrentDirectory,
|
|
14
|
+
DirectoryChanger,
|
|
13
15
|
SubagentExecutor,
|
|
14
16
|
TaskCompleter,
|
|
15
17
|
} from "./AgentTools.ts"
|
|
@@ -36,6 +38,8 @@ import * as Duration from "effect/Duration"
|
|
|
36
38
|
import * as Cause from "effect/Cause"
|
|
37
39
|
import * as Latch from "effect/Latch"
|
|
38
40
|
import * as Clock from "effect/Clock"
|
|
41
|
+
import * as Exit from "effect/Exit"
|
|
42
|
+
import * as Compaction from "./Compaction.ts"
|
|
39
43
|
import {
|
|
40
44
|
ScriptEnd,
|
|
41
45
|
ScriptOutput,
|
|
@@ -52,6 +56,9 @@ import {
|
|
|
52
56
|
ScriptStart,
|
|
53
57
|
ScriptDelta,
|
|
54
58
|
AgentStart,
|
|
59
|
+
ExecuteOutputCapped,
|
|
60
|
+
CompactionStarted,
|
|
61
|
+
CompactionEnded,
|
|
55
62
|
} from "./AgentOutput.ts"
|
|
56
63
|
|
|
57
64
|
/**
|
|
@@ -187,6 +194,9 @@ ${content}
|
|
|
187
194
|
const conversationMode = yield* ConversationMode
|
|
188
195
|
const turnTimeout = yield* TurnTimeout
|
|
189
196
|
let finalSummary = Option.none<string>()
|
|
197
|
+
// `inputTokens.total` from the most recent finish part; undefined until
|
|
198
|
+
// the first response and after every compaction.
|
|
199
|
+
let lastContextTokens: number | undefined = undefined
|
|
190
200
|
|
|
191
201
|
const output = yield* Queue.make<Output, AgentFinished | AiError.AiError>()
|
|
192
202
|
let inputTokens = 0
|
|
@@ -319,6 +329,50 @@ ${content}
|
|
|
319
329
|
}
|
|
320
330
|
})
|
|
321
331
|
|
|
332
|
+
// Compaction. `compactWithEvents` applies a successful rewrite and closes
|
|
333
|
+
// the progress event on every exit: success, failure, timeout, interrupt.
|
|
334
|
+
let compactionStarted = false
|
|
335
|
+
const onCompactionStart = (reason: Compaction.CompactionReason) =>
|
|
336
|
+
Effect.sync(() => {
|
|
337
|
+
compactionStarted = true
|
|
338
|
+
maybeSend({ agentId, part: new CompactionStarted({ reason }) })
|
|
339
|
+
})
|
|
340
|
+
const compactWithEvents = <E, R>(
|
|
341
|
+
reason: Compaction.CompactionReason,
|
|
342
|
+
compaction: Effect.Effect<
|
|
343
|
+
Option.Option<Compaction.CompactionResult>,
|
|
344
|
+
E,
|
|
345
|
+
R
|
|
346
|
+
>,
|
|
347
|
+
) =>
|
|
348
|
+
Effect.suspend(() => {
|
|
349
|
+
compactionStarted = false
|
|
350
|
+
return compaction
|
|
351
|
+
}).pipe(
|
|
352
|
+
Effect.onExit((exit) =>
|
|
353
|
+
Effect.sync(() => {
|
|
354
|
+
if (!compactionStarted) return
|
|
355
|
+
const result = Exit.isSuccess(exit) ? exit.value : Option.none()
|
|
356
|
+
let tokensBefore: number
|
|
357
|
+
let tokensAfter: number
|
|
358
|
+
if (Option.isSome(result)) {
|
|
359
|
+
MutableRef.set(prompt, result.value.prompt)
|
|
360
|
+
lastContextTokens = undefined
|
|
361
|
+
tokensBefore = result.value.tokensBefore
|
|
362
|
+
tokensAfter = result.value.tokensAfter
|
|
363
|
+
} else {
|
|
364
|
+
tokensBefore = tokensAfter = Compaction.estimateTokens(
|
|
365
|
+
prompt.current,
|
|
366
|
+
)
|
|
367
|
+
}
|
|
368
|
+
maybeSend({
|
|
369
|
+
agentId,
|
|
370
|
+
part: new CompactionEnded({ reason, tokensBefore, tokensAfter }),
|
|
371
|
+
})
|
|
372
|
+
}),
|
|
373
|
+
),
|
|
374
|
+
)
|
|
375
|
+
|
|
322
376
|
// Script execution
|
|
323
377
|
const executeScript = Effect.fnUntraced(function* (script: string) {
|
|
324
378
|
yield* toolLatchAcquire
|
|
@@ -335,8 +389,20 @@ ${content}
|
|
|
335
389
|
}),
|
|
336
390
|
Stream.mkString,
|
|
337
391
|
)
|
|
392
|
+
// Always-on cap on what enters the Prompt. The ScriptOutput event keeps
|
|
393
|
+
// the full output for display; the formatter applies its own truncation.
|
|
394
|
+
const capped = Compaction.capOutput(output)
|
|
395
|
+
if (capped.capped) {
|
|
396
|
+
maybeSend({
|
|
397
|
+
agentId,
|
|
398
|
+
part: new ExecuteOutputCapped({
|
|
399
|
+
charsBefore: capped.charsBefore,
|
|
400
|
+
charsAfter: capped.charsAfter,
|
|
401
|
+
}),
|
|
402
|
+
})
|
|
403
|
+
}
|
|
338
404
|
maybeSend({ agentId, part: new ScriptOutput({ output }) })
|
|
339
|
-
return output
|
|
405
|
+
return capped.output
|
|
340
406
|
}, Effect.ensuring(toolLatchRelease))
|
|
341
407
|
|
|
342
408
|
if (!modelConfig.systemPromptTransform) {
|
|
@@ -369,12 +435,29 @@ ${content}
|
|
|
369
435
|
pendingMessages.clear()
|
|
370
436
|
}
|
|
371
437
|
|
|
438
|
+
// Threshold compaction before the next model call
|
|
439
|
+
yield* compactWithEvents(
|
|
440
|
+
"threshold",
|
|
441
|
+
Compaction.compactIfNeeded({
|
|
442
|
+
prompt: prompt.current,
|
|
443
|
+
contextTokens: lastContextTokens,
|
|
444
|
+
onStart: onCompactionStart,
|
|
445
|
+
}).pipe(Effect.timeout(turnTimeout)),
|
|
446
|
+
).pipe(
|
|
447
|
+
Effect.catchTag("TimeoutError", (error) =>
|
|
448
|
+
Effect.logWarning(
|
|
449
|
+
"Compaction timed out, continuing with the uncompacted prompt",
|
|
450
|
+
error,
|
|
451
|
+
),
|
|
452
|
+
),
|
|
453
|
+
)
|
|
454
|
+
|
|
372
455
|
// oxlint-disable-next-line typescript/no-explicit-any
|
|
373
456
|
let response = Array.empty<Response.StreamPart<any>>()
|
|
374
457
|
let reasoningStarted = false
|
|
375
458
|
let hadReasoningDelta = false
|
|
376
459
|
let hadToolCall = false
|
|
377
|
-
|
|
460
|
+
const runModel = pipe(
|
|
378
461
|
Stream.suspend(() =>
|
|
379
462
|
ai.streamText({ prompt: prompt.current, toolkit: singleTool }),
|
|
380
463
|
),
|
|
@@ -431,6 +514,7 @@ ${content}
|
|
|
431
514
|
outputTokens += usage.outputTokens.total
|
|
432
515
|
}
|
|
433
516
|
if (usage.inputTokens.total !== undefined) {
|
|
517
|
+
lastContextTokens = usage.inputTokens.total
|
|
434
518
|
inputTokens += usage.inputTokens.total
|
|
435
519
|
maybeSend({
|
|
436
520
|
agentId,
|
|
@@ -449,6 +533,12 @@ ${content}
|
|
|
449
533
|
}
|
|
450
534
|
return Effect.void
|
|
451
535
|
}),
|
|
536
|
+
modelConfig.systemPromptTransform
|
|
537
|
+
? (effect) => modelConfig.systemPromptTransform!(system, effect)
|
|
538
|
+
: identity,
|
|
539
|
+
)
|
|
540
|
+
const attempt = pipe(
|
|
541
|
+
runModel,
|
|
452
542
|
Effect.raceFirst(turnTimeoutEffect),
|
|
453
543
|
Effect.retry({
|
|
454
544
|
while: (err) => {
|
|
@@ -468,6 +558,9 @@ ${content}
|
|
|
468
558
|
response = []
|
|
469
559
|
return true
|
|
470
560
|
}
|
|
561
|
+
// Never retry a context-length error as is: the overflow
|
|
562
|
+
// handler below compacts first.
|
|
563
|
+
if (Compaction.isContextLengthError(err)) return false
|
|
471
564
|
if (err.isRetryable) {
|
|
472
565
|
maybeSend({ agentId, part: new ErrorRetry({ error: err }) })
|
|
473
566
|
switch (err.reason._tag) {
|
|
@@ -488,9 +581,33 @@ ${content}
|
|
|
488
581
|
schedule: retryPolicy,
|
|
489
582
|
}),
|
|
490
583
|
Effect.catchTag("TimeoutError", Effect.die),
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
584
|
+
)
|
|
585
|
+
// Overflow: compact once, retry the attempt once, then fail.
|
|
586
|
+
yield* attempt.pipe(
|
|
587
|
+
Effect.catchIf(
|
|
588
|
+
(err): err is AiError.AiError =>
|
|
589
|
+
Compaction.isContextLengthError(err),
|
|
590
|
+
(err) =>
|
|
591
|
+
Effect.gen(function* () {
|
|
592
|
+
response = []
|
|
593
|
+
const compacted = yield* compactWithEvents(
|
|
594
|
+
"overflow",
|
|
595
|
+
Compaction.compact({
|
|
596
|
+
prompt: prompt.current,
|
|
597
|
+
reason: "overflow",
|
|
598
|
+
onStart: onCompactionStart,
|
|
599
|
+
}).pipe(
|
|
600
|
+
Effect.timeout(turnTimeout),
|
|
601
|
+
Effect.retry({
|
|
602
|
+
while: (error) => error._tag === "TimeoutError",
|
|
603
|
+
times: 1,
|
|
604
|
+
}),
|
|
605
|
+
Effect.catchTag("TimeoutError", Effect.die),
|
|
606
|
+
),
|
|
607
|
+
)
|
|
608
|
+
return Option.isSome(compacted) ? yield* attempt : yield* err
|
|
609
|
+
}),
|
|
610
|
+
),
|
|
494
611
|
)
|
|
495
612
|
MutableRef.update(
|
|
496
613
|
prompt,
|
|
@@ -620,7 +737,12 @@ ${capabilities.toolsDts}
|
|
|
620
737
|
|
|
621
738
|
/** The global Fetch API available for making HTTP requests. */
|
|
622
739
|
declare const fetch: typeof globalThis.fetch
|
|
623
|
-
|
|
740
|
+
\`\`\`${Option.match(AgentSkills.renderCatalog(capabilities.skills), {
|
|
741
|
+
onNone: () => "",
|
|
742
|
+
onSome: (catalog) => `
|
|
743
|
+
|
|
744
|
+
${catalog}`,
|
|
745
|
+
})}`
|
|
624
746
|
|
|
625
747
|
class ScriptExecutor extends Context.Service<
|
|
626
748
|
ScriptExecutor,
|
|
@@ -671,7 +793,7 @@ export const layerLocal = <Toolkit extends Toolkit.Any = never>(options: {
|
|
|
671
793
|
Toolkit extends Toolkit.Toolkit<infer T>
|
|
672
794
|
? Tool.HandlersFor<T> | Tool.HandlerServices<T[keyof T]>
|
|
673
795
|
: never,
|
|
674
|
-
CurrentDirectory | SubagentExecutor | TaskCompleter
|
|
796
|
+
CurrentDirectory | DirectoryChanger | SubagentExecutor | TaskCompleter
|
|
675
797
|
>
|
|
676
798
|
> => layer.pipe(Layer.provide(AgentExecutor.layerLocal(options)))
|
|
677
799
|
|
package/src/AgentExecutor.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
4
|
import * as NodeConsole from "node:console"
|
|
5
|
+
import * as NodeOs from "node:os"
|
|
5
6
|
import * as NodeVm from "node:vm"
|
|
6
7
|
import { Writable } from "node:stream"
|
|
7
8
|
import {
|
|
@@ -9,10 +10,12 @@ import {
|
|
|
9
10
|
AgentTools,
|
|
10
11
|
AgentToolsWithSearch,
|
|
11
12
|
CurrentDirectory,
|
|
13
|
+
DirectoryChanger,
|
|
12
14
|
SubagentExecutor,
|
|
13
15
|
TaskCompleter,
|
|
14
16
|
} from "./AgentTools.ts"
|
|
15
17
|
import { ToolkitRenderer } from "./ToolkitRenderer.ts"
|
|
18
|
+
import * as AgentSkills from "./AgentSkills.ts"
|
|
16
19
|
import type * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner"
|
|
17
20
|
import type * as HttpClient from "effect/unstable/http/HttpClient"
|
|
18
21
|
import * as Context from "effect/Context"
|
|
@@ -69,6 +72,13 @@ export class Capabilities extends Schema.Class<Capabilities>("Capabilities")({
|
|
|
69
72
|
toolsDts: Schema.String,
|
|
70
73
|
agentsMd: Schema.Option(Schema.String),
|
|
71
74
|
supportsSearch: Schema.Boolean,
|
|
75
|
+
/**
|
|
76
|
+
* Skills available on the executor filesystem.
|
|
77
|
+
*/
|
|
78
|
+
skills: Schema.Array(AgentSkills.Skill).pipe(
|
|
79
|
+
Schema.withDecodingDefaultKey(Effect.succeed([])),
|
|
80
|
+
Schema.withConstructorDefault(Effect.succeed([])),
|
|
81
|
+
),
|
|
72
82
|
}) {}
|
|
73
83
|
|
|
74
84
|
/**
|
|
@@ -91,12 +101,22 @@ export const makeLocal = Effect.fnUntraced(function* <
|
|
|
91
101
|
Toolkit extends Toolkit.Toolkit<infer T>
|
|
92
102
|
? Tool.HandlersFor<T> | Tool.HandlerServices<T[keyof T]>
|
|
93
103
|
: never,
|
|
94
|
-
CurrentDirectory | SubagentExecutor | TaskCompleter
|
|
104
|
+
CurrentDirectory | DirectoryChanger | SubagentExecutor | TaskCompleter
|
|
95
105
|
>
|
|
96
106
|
> {
|
|
97
107
|
const fs = yield* FileSystem.FileSystem
|
|
98
108
|
const pathService = yield* Path.Path
|
|
99
109
|
const renderer = yield* ToolkitRenderer
|
|
110
|
+
let currentDirectory = pathService.resolve(options.directory)
|
|
111
|
+
const changeDirectory = Effect.fnUntraced(function* (directory: string) {
|
|
112
|
+
const target = pathService.resolve(currentDirectory, directory)
|
|
113
|
+
const info = yield* fs.stat(target)
|
|
114
|
+
if (info.type !== "Directory") {
|
|
115
|
+
return yield* Effect.die(new Error(`Not a directory: ${target}`))
|
|
116
|
+
}
|
|
117
|
+
currentDirectory = target
|
|
118
|
+
return target
|
|
119
|
+
}, Effect.orDie)
|
|
100
120
|
const search = yield* Effect.serviceOption(SemanticSearch)
|
|
101
121
|
const hasSearch = Option.isSome(search)
|
|
102
122
|
const AllTools = Toolkit.merge(
|
|
@@ -133,7 +153,7 @@ export const makeLocal = Effect.fnUntraced(function* <
|
|
|
133
153
|
|
|
134
154
|
const taskServices = Context.empty().pipe(
|
|
135
155
|
Context.add(TaskCompleter, opts.onTaskComplete),
|
|
136
|
-
Context.add(
|
|
156
|
+
Context.add(DirectoryChanger, changeDirectory),
|
|
137
157
|
Context.add(SubagentExecutor, opts.onSubagent),
|
|
138
158
|
Context.add(Console.Console, console),
|
|
139
159
|
Context.add(References.CurrentLogAnnotations, {}),
|
|
@@ -156,12 +176,13 @@ export const makeLocal = Effect.fnUntraced(function* <
|
|
|
156
176
|
|
|
157
177
|
for (let i = 0; i < toolEntries.length; i++) {
|
|
158
178
|
const { name, handler, services } = toolEntries[i]!
|
|
159
|
-
const
|
|
160
|
-
Context.merge(services, taskServices),
|
|
161
|
-
)
|
|
179
|
+
const toolServices = Context.merge(services, taskServices)
|
|
162
180
|
|
|
163
181
|
// oxlint-disable-next-line typescript/no-explicit-any
|
|
164
182
|
sandbox[name] = function (params: any) {
|
|
183
|
+
const runFork = Effect.runForkWith(
|
|
184
|
+
Context.add(toolServices, CurrentDirectory, currentDirectory),
|
|
185
|
+
)
|
|
165
186
|
running++
|
|
166
187
|
const fiber = trackFiber(runFork(handler(params, {})))
|
|
167
188
|
return new Promise((resolve, reject) => {
|
|
@@ -201,40 +222,53 @@ export const makeLocal = Effect.fnUntraced(function* <
|
|
|
201
222
|
const agentsMd = yield* Effect.option(
|
|
202
223
|
fs.readFileString(pathService.join(options.directory, "AGENTS.md")),
|
|
203
224
|
)
|
|
225
|
+
const skills = yield* AgentSkills.discover({
|
|
226
|
+
directory: options.directory,
|
|
227
|
+
homeDirectory: homeDirectory(),
|
|
228
|
+
}).pipe(
|
|
229
|
+
Effect.provideService(FileSystem.FileSystem, fs),
|
|
230
|
+
Effect.provideService(Path.Path, pathService),
|
|
231
|
+
)
|
|
204
232
|
return new Capabilities({
|
|
205
233
|
toolsDts,
|
|
206
234
|
agentsMd,
|
|
207
235
|
supportsSearch: hasSearch,
|
|
236
|
+
skills,
|
|
208
237
|
})
|
|
209
238
|
}),
|
|
210
239
|
execute,
|
|
211
|
-
executeUnsafe: (opts) =>
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
240
|
+
executeUnsafe: (opts) =>
|
|
241
|
+
Effect.suspend(() => {
|
|
242
|
+
const tool = tools.tools[opts.tool as keyof typeof tools.tools]
|
|
243
|
+
if (!tool) {
|
|
244
|
+
return Effect.die(new Error(`Unknown tool: ${opts.tool}`))
|
|
245
|
+
}
|
|
246
|
+
const handler = services.mapUnsafe.get(tool.id) as Tool.Handler<string>
|
|
247
|
+
if (!handler) {
|
|
248
|
+
return Effect.die(new Error(`Unknown tool: ${opts.tool}`))
|
|
249
|
+
}
|
|
217
250
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
251
|
+
const taskServices = handler.context.pipe(
|
|
252
|
+
Context.add(TaskCompleter, () => Effect.void),
|
|
253
|
+
Context.add(CurrentDirectory, currentDirectory),
|
|
254
|
+
Context.add(DirectoryChanger, changeDirectory),
|
|
255
|
+
Context.add(SubagentExecutor, () => Effect.succeed("")),
|
|
256
|
+
Context.add(References.CurrentLogAnnotations, {}),
|
|
257
|
+
Option.isSome(search)
|
|
258
|
+
? Context.add(SemanticSearch, search.value)
|
|
259
|
+
: identity,
|
|
260
|
+
)
|
|
227
261
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
262
|
+
const encodeSuccess = Schema.encodeUnknownEffect(
|
|
263
|
+
Schema.toCodecJson(tool.successSchema as Schema.Top),
|
|
264
|
+
)
|
|
265
|
+
return pipe(
|
|
266
|
+
handler.handler(opts.params, {}),
|
|
267
|
+
Effect.flatMap(encodeSuccess),
|
|
268
|
+
Effect.provideContext(taskServices),
|
|
269
|
+
Effect.orDie,
|
|
270
|
+
) as Effect.Effect<Schema.Json>
|
|
271
|
+
}),
|
|
238
272
|
})
|
|
239
273
|
})
|
|
240
274
|
|
|
@@ -302,7 +336,7 @@ export const layerLocal = <Toolkit extends Toolkit.Any = never>(options: {
|
|
|
302
336
|
Toolkit extends Toolkit.Toolkit<infer T>
|
|
303
337
|
? Tool.HandlersFor<T> | Tool.HandlerServices<T[keyof T]>
|
|
304
338
|
: never,
|
|
305
|
-
CurrentDirectory | SubagentExecutor | TaskCompleter
|
|
339
|
+
CurrentDirectory | DirectoryChanger | SubagentExecutor | TaskCompleter
|
|
306
340
|
>
|
|
307
341
|
> =>
|
|
308
342
|
Layer.effect(AgentExecutor, makeLocal(options)).pipe(
|
|
@@ -342,7 +376,7 @@ export const layerRpcServer = <Toolkit extends Toolkit.Any = never>(options: {
|
|
|
342
376
|
Toolkit extends Toolkit.Toolkit<infer T>
|
|
343
377
|
? Tool.HandlersFor<T> | Tool.HandlerServices<T[keyof T]>
|
|
344
378
|
: never,
|
|
345
|
-
CurrentDirectory | SubagentExecutor | TaskCompleter
|
|
379
|
+
CurrentDirectory | DirectoryChanger | SubagentExecutor | TaskCompleter
|
|
346
380
|
>
|
|
347
381
|
> =>
|
|
348
382
|
RpcServer.layer(Rpcs, {
|
|
@@ -500,6 +534,16 @@ const compileScript = (script: string): NodeVm.Script => {
|
|
|
500
534
|
|
|
501
535
|
const defaultMain = () => Promise.resolve()
|
|
502
536
|
|
|
537
|
+
const homeDirectory = (): Option.Option<string> => {
|
|
538
|
+
const fromEnv = process.env.HOME
|
|
539
|
+
if (fromEnv) return Option.some(fromEnv)
|
|
540
|
+
try {
|
|
541
|
+
return Option.some(NodeOs.homedir())
|
|
542
|
+
} catch {
|
|
543
|
+
return Option.none()
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
503
547
|
const makeConsole = Effect.fn(function* (
|
|
504
548
|
queue: Queue.Queue<string, Cause.Done>,
|
|
505
549
|
) {
|
package/src/AgentOutput.ts
CHANGED
|
@@ -138,6 +138,58 @@ export class SubagentComplete extends Schema.TaggedClass<SubagentComplete>()(
|
|
|
138
138
|
},
|
|
139
139
|
) {}
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Emitted when an `execute` result exceeded the always-on output cap and was
|
|
143
|
+
* shortened before being appended to the Prompt.
|
|
144
|
+
*
|
|
145
|
+
* @since 1.0.0
|
|
146
|
+
* @category Output
|
|
147
|
+
*/
|
|
148
|
+
export class ExecuteOutputCapped extends Schema.TaggedClass<ExecuteOutputCapped>()(
|
|
149
|
+
"ExecuteOutputCapped",
|
|
150
|
+
{
|
|
151
|
+
charsBefore: Schema.Number,
|
|
152
|
+
charsAfter: Schema.Number,
|
|
153
|
+
},
|
|
154
|
+
) {}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* @since 1.0.0
|
|
158
|
+
* @category Output
|
|
159
|
+
*/
|
|
160
|
+
export const CompactionReason = Schema.Literals(["threshold", "overflow"])
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Emitted when auto-compaction begins. `reason` is `threshold` when the
|
|
164
|
+
* context token count crossed the configured limit before a model call, and
|
|
165
|
+
* `overflow` when a context-length error from the provider triggered it.
|
|
166
|
+
*
|
|
167
|
+
* @since 1.0.0
|
|
168
|
+
* @category Output
|
|
169
|
+
*/
|
|
170
|
+
export class CompactionStarted extends Schema.TaggedClass<CompactionStarted>()(
|
|
171
|
+
"CompactionStarted",
|
|
172
|
+
{
|
|
173
|
+
reason: CompactionReason,
|
|
174
|
+
},
|
|
175
|
+
) {}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Emitted when auto-compaction finished and the Prompt was rewritten.
|
|
179
|
+
* `tokensBefore` / `tokensAfter` are estimates.
|
|
180
|
+
*
|
|
181
|
+
* @since 1.0.0
|
|
182
|
+
* @category Output
|
|
183
|
+
*/
|
|
184
|
+
export class CompactionEnded extends Schema.TaggedClass<CompactionEnded>()(
|
|
185
|
+
"CompactionEnded",
|
|
186
|
+
{
|
|
187
|
+
reason: CompactionReason,
|
|
188
|
+
tokensBefore: Schema.Number,
|
|
189
|
+
tokensAfter: Schema.Number,
|
|
190
|
+
},
|
|
191
|
+
) {}
|
|
192
|
+
|
|
141
193
|
export type ContentPart =
|
|
142
194
|
| ReasoningStart
|
|
143
195
|
| ReasoningDelta
|
|
@@ -148,6 +200,9 @@ export type ContentPart =
|
|
|
148
200
|
| ScriptOutput
|
|
149
201
|
| Usage
|
|
150
202
|
| ErrorRetry
|
|
203
|
+
| ExecuteOutputCapped
|
|
204
|
+
| CompactionStarted
|
|
205
|
+
| CompactionEnded
|
|
151
206
|
|
|
152
207
|
export const ContentPart = Schema.Union([
|
|
153
208
|
ReasoningStart,
|
|
@@ -159,6 +214,9 @@ export const ContentPart = Schema.Union([
|
|
|
159
214
|
ScriptOutput,
|
|
160
215
|
Usage,
|
|
161
216
|
ErrorRetry,
|
|
217
|
+
ExecuteOutputCapped,
|
|
218
|
+
CompactionStarted,
|
|
219
|
+
CompactionEnded,
|
|
162
220
|
])
|
|
163
221
|
|
|
164
222
|
/**
|