@zaly/agent 0.1.1 → 0.2.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-BRENvuvx.mjs → agent-DlhEEMPU.mjs} +98 -25
- package/dist/agent-DlhEEMPU.mjs.map +1 -0
- package/dist/{compactions-HFjEgrv3.mjs → compactions-BpvQk4CG.mjs} +24 -14
- package/dist/compactions-BpvQk4CG.mjs.map +1 -0
- package/dist/index.d.mts +11 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{masker-DEgR_ntk.mjs → masker-B97uwYXG.mjs} +2 -2
- package/dist/{masker-DEgR_ntk.mjs.map → masker-B97uwYXG.mjs.map} +1 -1
- package/dist/{session-C8zqqbPE.mjs → session-CUE48QWX.mjs} +79 -44
- package/dist/session-CUE48QWX.mjs.map +1 -0
- package/dist/{session-Cq52cam5.d.mts → session-DY9mF9Vb.d.mts} +18 -9
- package/dist/session-DY9mF9Vb.d.mts.map +1 -0
- package/dist/session.d.mts +1 -1
- package/dist/session.mjs +1 -1
- package/dist/{src-C04Qk9KE.mjs → src-DJoqT9yP.mjs} +5 -5
- package/dist/{src-C04Qk9KE.mjs.map → src-DJoqT9yP.mjs.map} +1 -1
- package/dist/{subagent-BbcxLzgC.mjs → subagent-D-TYaX38.mjs} +2 -2
- package/dist/{subagent-BbcxLzgC.mjs.map → subagent-D-TYaX38.mjs.map} +1 -1
- package/package.json +3 -3
- package/dist/agent-BRENvuvx.mjs.map +0 -1
- package/dist/compactions-HFjEgrv3.mjs.map +0 -1
- package/dist/session-C8zqqbPE.mjs.map +0 -1
- package/dist/session-Cq52cam5.d.mts.map +0 -1
|
@@ -41,8 +41,8 @@ var TokenUsage = class {
|
|
|
41
41
|
get reasoning() {
|
|
42
42
|
return this.last.reasoning ?? 0;
|
|
43
43
|
}
|
|
44
|
-
add(count) {
|
|
45
|
-
this.#last = count;
|
|
44
|
+
add(count, opts = {}) {
|
|
45
|
+
if (opts.current ?? true) this.#last = count;
|
|
46
46
|
this.#total = addUsage(this.#total, count);
|
|
47
47
|
}
|
|
48
48
|
resetLast() {
|
|
@@ -240,6 +240,10 @@ var Agent = class extends Emitter {
|
|
|
240
240
|
#pauseRequested;
|
|
241
241
|
#running;
|
|
242
242
|
#usage;
|
|
243
|
+
#contextEpoch = 0;
|
|
244
|
+
#requestEpoch = 0;
|
|
245
|
+
#compaction;
|
|
246
|
+
#compactionAttempt;
|
|
243
247
|
/** Pending future-injects scheduled via `scheduleWakeup`. Cleared
|
|
244
248
|
* whenever the loop becomes active for any reason — the scheduled
|
|
245
249
|
* inject was a fallback "wake me up at time T if nothing else does,"
|
|
@@ -286,6 +290,8 @@ var Agent = class extends Emitter {
|
|
|
286
290
|
this.#ctx.on("session", () => this.reset());
|
|
287
291
|
}
|
|
288
292
|
async reset() {
|
|
293
|
+
this.#compactionAttempt = void 0;
|
|
294
|
+
this.#contextEpoch++;
|
|
289
295
|
this.stop({
|
|
290
296
|
abort: true,
|
|
291
297
|
reason: "reset"
|
|
@@ -320,7 +326,7 @@ var Agent = class extends Emitter {
|
|
|
320
326
|
const childDepth = overrides.depth ?? this.depth + 1;
|
|
321
327
|
let tools = [...this.tools].filter((t) => t.name !== "skill");
|
|
322
328
|
if (childDepth >= this.maxDepth) tools = tools.filter((t) => t.name !== "subagent");
|
|
323
|
-
const { createAgent } = await import("./src-
|
|
329
|
+
const { createAgent } = await import("./src-DJoqT9yP.mjs").then((n) => n._);
|
|
324
330
|
const ret = await createAgent({
|
|
325
331
|
cwd: this.cwd,
|
|
326
332
|
depth: childDepth,
|
|
@@ -577,6 +583,10 @@ var Agent = class extends Emitter {
|
|
|
577
583
|
}
|
|
578
584
|
async #collect() {
|
|
579
585
|
this.#abortController = new AbortController();
|
|
586
|
+
const epoch = this.#contextEpoch;
|
|
587
|
+
this.#requestEpoch = epoch;
|
|
588
|
+
const usage = this.#usage;
|
|
589
|
+
const session = this.session;
|
|
580
590
|
const context = {
|
|
581
591
|
cacheKey: this.ctx.session.id,
|
|
582
592
|
messages: [...this.ctx.messages],
|
|
@@ -587,13 +597,29 @@ var Agent = class extends Emitter {
|
|
|
587
597
|
await this.emitSerial("context", context);
|
|
588
598
|
const model = this.model;
|
|
589
599
|
if (!model) throw new Error("model must be loaded to collect");
|
|
590
|
-
|
|
600
|
+
const message = await model.stream(context, this.#streamOpts());
|
|
601
|
+
if (this.session !== session) throw new DOMException("Request session changed", "AbortError");
|
|
602
|
+
return {
|
|
603
|
+
epoch,
|
|
604
|
+
message,
|
|
605
|
+
usage
|
|
606
|
+
};
|
|
591
607
|
}
|
|
592
|
-
#
|
|
593
|
-
const
|
|
594
|
-
if (
|
|
595
|
-
const
|
|
596
|
-
|
|
608
|
+
#maybeCompact(opts = {}) {
|
|
609
|
+
const config = toValue(this.#opts.compaction);
|
|
610
|
+
if (config?.enabled === false) return;
|
|
611
|
+
const ratio = this.pressure.ratio;
|
|
612
|
+
if (!opts.backgroundOnly && ratio >= (config?.threshold ?? .95)) return this.#compact({ trigger: "auto" });
|
|
613
|
+
if (config?.backgroundEnabled === false || this.#pauseRequested !== void 0) return;
|
|
614
|
+
if (ratio < (config?.backgroundThreshold ?? .9)) return;
|
|
615
|
+
if (this.#compaction && !this.#compaction.controller.signal.aborted && this.#compaction.session === this.session) return;
|
|
616
|
+
const session = this.session;
|
|
617
|
+
const messageId = session.messages.at(-1)?.id;
|
|
618
|
+
if (this.#compactionAttempt?.session === session && this.#compactionAttempt.messageId === messageId) return;
|
|
619
|
+
return this.#compact({
|
|
620
|
+
background: true,
|
|
621
|
+
trigger: "auto"
|
|
622
|
+
});
|
|
597
623
|
}
|
|
598
624
|
#streamOpts() {
|
|
599
625
|
const base = this.#opts.request ?? {};
|
|
@@ -618,7 +644,8 @@ var Agent = class extends Emitter {
|
|
|
618
644
|
/** Run exactly one step. Useful for tests and custom drivers
|
|
619
645
|
* that want to interleave logic between steps. */
|
|
620
646
|
async step() {
|
|
621
|
-
|
|
647
|
+
const compaction = this.#maybeCompact();
|
|
648
|
+
if (compaction) await compaction;
|
|
622
649
|
if (this.#notifyQueue.length > 0) this.#injectQueue.push({
|
|
623
650
|
content: this.#notifyQueue.splice(0),
|
|
624
651
|
role: "system"
|
|
@@ -627,7 +654,9 @@ var Agent = class extends Emitter {
|
|
|
627
654
|
this.#setStatus("streaming");
|
|
628
655
|
let collected;
|
|
629
656
|
try {
|
|
630
|
-
|
|
657
|
+
const response = await this.#collect();
|
|
658
|
+
collected = response.message;
|
|
659
|
+
response.usage.add(collected.meta.usage, { current: response.epoch === this.#contextEpoch });
|
|
631
660
|
} catch (error) {
|
|
632
661
|
const err = toError(error);
|
|
633
662
|
const overflow = isContextOverflow({ message: err.message });
|
|
@@ -642,7 +671,6 @@ var Agent = class extends Emitter {
|
|
|
642
671
|
}
|
|
643
672
|
};
|
|
644
673
|
}
|
|
645
|
-
this.#usage.add(collected.meta.usage);
|
|
646
674
|
const result = {
|
|
647
675
|
finishReason: collected.meta.finishReason,
|
|
648
676
|
message: collected,
|
|
@@ -657,6 +685,7 @@ var Agent = class extends Emitter {
|
|
|
657
685
|
};
|
|
658
686
|
const calls = await this.#parseToolCalls(collected);
|
|
659
687
|
await this.session.add(collected);
|
|
688
|
+
this.#maybeCompact({ backgroundOnly: true });
|
|
660
689
|
if (calls.length === 0) return {
|
|
661
690
|
kind: "natural",
|
|
662
691
|
...result
|
|
@@ -679,20 +708,60 @@ var Agent = class extends Emitter {
|
|
|
679
708
|
}
|
|
680
709
|
return calls;
|
|
681
710
|
}
|
|
682
|
-
|
|
711
|
+
/** Apply compaction before resolving, or start it without waiting when background is true. */
|
|
712
|
+
async compact(opts = {}) {
|
|
713
|
+
return this.#compact(opts);
|
|
714
|
+
}
|
|
715
|
+
async #compact(opts = {}) {
|
|
716
|
+
let job = this.#compaction;
|
|
717
|
+
if (job && (job.session !== this.session || job.controller.signal.aborted)) job = void 0;
|
|
718
|
+
if (!job) {
|
|
719
|
+
const session = this.session;
|
|
720
|
+
const controller = new AbortController();
|
|
721
|
+
const pressure = this.pressure;
|
|
722
|
+
this.#compactionAttempt = {
|
|
723
|
+
messageId: session.messages.at(-1)?.id,
|
|
724
|
+
session
|
|
725
|
+
};
|
|
726
|
+
const applied = () => {
|
|
727
|
+
if (this.session !== session) return;
|
|
728
|
+
this.#contextEpoch++;
|
|
729
|
+
this.#usage.resetLast();
|
|
730
|
+
};
|
|
731
|
+
session.on("compact", applied);
|
|
732
|
+
const promise = (async () => {
|
|
733
|
+
try {
|
|
734
|
+
const { Compaction } = await import("./compactions-BpvQk4CG.mjs");
|
|
735
|
+
controller.signal.throwIfAborted();
|
|
736
|
+
const config = toValue(this.#opts.compaction);
|
|
737
|
+
const signal = config?.signal ? AbortSignal.any([controller.signal, config.signal]) : controller.signal;
|
|
738
|
+
await new Compaction(this, {
|
|
739
|
+
...config,
|
|
740
|
+
signal,
|
|
741
|
+
trigger: opts.trigger ?? config?.trigger ?? "manual"
|
|
742
|
+
}).compact(pressure);
|
|
743
|
+
} finally {
|
|
744
|
+
session.off("compact", applied);
|
|
745
|
+
if (this.#compaction?.controller === controller) this.#compaction = void 0;
|
|
746
|
+
}
|
|
747
|
+
})();
|
|
748
|
+
job = {
|
|
749
|
+
controller,
|
|
750
|
+
promise,
|
|
751
|
+
session
|
|
752
|
+
};
|
|
753
|
+
this.#compaction = job;
|
|
754
|
+
promise.catch((error) => {
|
|
755
|
+
if (!controller.signal.aborted) this.#opts.logger?.child("compaction").error(error);
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
if (opts.background) return;
|
|
683
759
|
const prev = this.#status;
|
|
684
|
-
const pressure = this.pressure;
|
|
685
760
|
this.#setStatus("compacting");
|
|
686
|
-
this.#usage.resetLast();
|
|
687
761
|
try {
|
|
688
|
-
|
|
689
|
-
const opts = {
|
|
690
|
-
...toValue(this.#opts.compaction),
|
|
691
|
-
signal: this.#abortController?.signal
|
|
692
|
-
};
|
|
693
|
-
await new Compaction(this, opts).compact(pressure);
|
|
762
|
+
await job.promise;
|
|
694
763
|
} finally {
|
|
695
|
-
this.#setStatus(prev);
|
|
764
|
+
if (this.#status === "compacting") this.#setStatus(prev);
|
|
696
765
|
}
|
|
697
766
|
}
|
|
698
767
|
async #runTools(calls) {
|
|
@@ -758,7 +827,10 @@ var Agent = class extends Emitter {
|
|
|
758
827
|
* stream or tool calls are left to run to completion */
|
|
759
828
|
stop(opts = {}) {
|
|
760
829
|
this.#pauseRequested ??= opts.reason ?? "stop";
|
|
761
|
-
if (opts.abort ?? true)
|
|
830
|
+
if (opts.abort ?? true) {
|
|
831
|
+
this.#abortController?.abort(opts.reason);
|
|
832
|
+
this.#compaction?.controller.abort(opts.reason);
|
|
833
|
+
}
|
|
762
834
|
}
|
|
763
835
|
async start() {
|
|
764
836
|
if (this.#started) return;
|
|
@@ -791,8 +863,9 @@ var Agent = class extends Emitter {
|
|
|
791
863
|
if (outcome.kind === "natural") return { kind: "natural" };
|
|
792
864
|
if (outcome.kind === "context-overflow") {
|
|
793
865
|
if (toValue(this.#opts.compaction)?.enabled === false) return { kind: "context-overflow" };
|
|
866
|
+
if (this.#requestEpoch !== this.#contextEpoch) continue;
|
|
794
867
|
this.#opts.logger?.child("compaction").warn(`context overflow detected (size ${this.contextSize}, limit ${this.pressure.limit}); running compaction`);
|
|
795
|
-
await this
|
|
868
|
+
await this.#compact({ trigger: "auto" });
|
|
796
869
|
continue;
|
|
797
870
|
}
|
|
798
871
|
const stop = this.#stopPolicy.detect();
|
|
@@ -895,4 +968,4 @@ var Agent = class extends Emitter {
|
|
|
895
968
|
};
|
|
896
969
|
export { Agent };
|
|
897
970
|
|
|
898
|
-
//# sourceMappingURL=agent-
|
|
971
|
+
//# sourceMappingURL=agent-DlhEEMPU.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-DlhEEMPU.mjs","names":[],"sources":["../src/utils/usage.ts","../src/stop.ts","../src/agent.ts"],"sourcesContent":["import type { Message, TokenCount, Usage } from \"@zaly/ai\"\n\n/** Sum two Usages. Optional fields are only present in the result\n * when at least one input had them set, so callers can tell \"no\n * reasoning happened this turn\" apart from \"0 reasoning tokens.\" */\nexport function addUsage(a: Usage, b: Usage): Usage {\n const out: Usage = {\n input: a.input + b.input,\n output: a.output + b.output,\n }\n if (a.cacheRead !== undefined || b.cacheRead !== undefined) {\n out.cacheRead = (a.cacheRead ?? 0) + (b.cacheRead ?? 0)\n }\n if (a.cacheWrite !== undefined || b.cacheWrite !== undefined) {\n out.cacheWrite = (a.cacheWrite ?? 0) + (b.cacheWrite ?? 0)\n }\n if (a.reasoning !== undefined || b.reasoning !== undefined) {\n out.reasoning = (a.reasoning ?? 0) + (b.reasoning ?? 0)\n }\n if (a.cost || b.cost) out.cost = addUsage(a.cost ?? empty(), b.cost ?? empty())\n return out\n}\n\nexport class TokenUsage implements Usage {\n #last: Usage = empty()\n #total: Usage = empty()\n\n constructor(messages?: readonly Message[]) {\n for (const m of messages ?? [])\n if (m.role === \"assistant\" && m.meta?.usage) this.add(m.meta.usage)\n }\n\n get cost(): Usage {\n return this.total.cost ?? empty()\n }\n\n get input(): number {\n return this.last.input\n }\n\n get output(): number {\n return this.last.output\n }\n\n get cacheRead(): number {\n return this.last.cacheRead ?? 0\n }\n\n get cacheWrite(): number {\n return this.last.cacheWrite ?? 0\n }\n\n get reasoning(): number {\n return this.last.reasoning ?? 0\n }\n\n add(count: Usage, opts: { current?: boolean } = {}): void {\n if (opts.current ?? true) this.#last = count\n this.#total = addUsage(this.#total, count)\n }\n\n resetLast(): void {\n this.#last = empty()\n }\n\n get last(): Usage {\n return this.#last\n }\n\n get total(): Usage {\n return this.#total\n }\n\n get contextSize(): number {\n return (\n this.last.input + this.last.output + (this.last.cacheRead ?? 0) + (this.last.cacheWrite ?? 0)\n )\n }\n}\n\nfunction empty(): TokenCount {\n return { input: 0, output: 0 }\n}\n","import type { TokenCount, ToolCallPart } from \"@zaly/ai\"\nimport type { Emitter, Envelope } from \"@zaly/shared\"\nimport type { AgentEvents, AgentStopKind } from \"./events.ts\"\n\nimport { safeStringify } from \"@zaly/shared\"\nimport { addUsage } from \"./utils/usage.ts\"\n\n/** Caps + heuristics that can end a run early. Wired into the\n * `AgentSession` loop via a single `detect()` call after each step. */\nexport interface StopOptions {\n /** Hard ceiling on provider round-trips per `run()`. Default: 50. */\n maxSteps?: number\n /** Cumulative token cap across the whole `run()`\n * (`totalUsage.input + totalUsage.output`). */\n tokenBudget?: number\n /** Bail after this many consecutive failing tool calls. A successful\n * tool result resets the streak. */\n maxToolErrors?: number\n\n // ── Loop detection ──────────────────────────────────────────────────\n // Two cheap heuristics over the running tool-call history. Hash is\n // `name + JSON.stringify(params)`; property order matters (rare false\n // negative if the model alternates key order on the same logical call,\n // accepted in exchange for a much cheaper hash). Set either limit to\n // `Infinity` to disable that arm.\n\n /** Same `(name, params)` appearing N times in a row → loop. Catches\n * the most common failure mode: re-calling `read_file` with the same\n * path expecting different output. Default 3. */\n loopConsecutive?: number\n /** Bounded window for duplicate detection. Default 10. */\n loopWindow?: number\n /** Within the window, this many duplicates of one call → loop.\n * Catches alternation patterns (`A B A B …`) the consecutive arm\n * alone won't see. Default 4. */\n loopWindowRepeats?: number\n}\n\n/**\n * Subscribes to an `AgentEvent` stream, accumulates the bookkeeping\n * the loop needs to make stop-or-continue decisions, and exposes a\n * single `detect()` to consult after each step.\n *\n * Lives outside `AgentSession` so concerns separate cleanly:\n * - the session owns conversation, queues, status, and loop control;\n * - the policy owns counters and the rules that act on them.\n *\n * Wire it up via `attach(session)` (returns an unsubscribe), or feed\n * events manually with `handle(event)` for custom drivers.\n */\nexport class StopPolicy {\n readonly #opts: StopOptions\n\n #steps = 0\n #consecutiveErrors = 0\n #calls: ToolCallPart[] = []\n #usage: TokenCount = { input: 0, output: 0 }\n #totalUsage: TokenCount = { input: 0, output: 0 }\n\n constructor(opts: StopOptions = {}) {\n this.#opts = opts\n }\n\n // ── Read ──────────────────────────────────────────────────────────────\n\n /** Token usage from the most recent step's response. */\n get usage(): TokenCount {\n return this.#usage\n }\n /** Cumulative token usage across every step in the current run. */\n get totalUsage(): TokenCount {\n return this.#totalUsage\n }\n get steps(): number {\n return this.#steps\n }\n get consecutiveErrors(): number {\n return this.#consecutiveErrors\n }\n /** Tool-call history fed to the loop detector. Read-only. */\n get calls(): readonly ToolCallPart[] {\n return this.#calls\n }\n\n // ── Wiring ────────────────────────────────────────────────────────────\n\n /** Subscribe to an emitter. To detach later, register the listener\n * yourself and pass the same fn to `emitter.off(fn)`:\n *\n * const handler = (e) => policy.handle(e)\n * emitter.all(handler)\n * // later:\n * emitter.off(handler) */\n attach(emitter: Emitter<AgentEvents>): void {\n emitter.onAny((event) => this.handle(event))\n }\n\n /** Feed a single event into the policy. Public so custom drivers\n * can drive it without going through `attach`. */\n handle(event: Envelope<AgentEvents>): void {\n switch (event.type) {\n case \"step-end\": {\n this.#steps++\n break\n }\n case \"tool-call\": {\n this.#calls.push(event.call)\n break\n }\n case \"tool-result\": {\n this.#consecutiveErrors = event.result.isError ? this.#consecutiveErrors + 1 : 0\n break\n }\n case \"stream-event\": {\n if (event.event.type === \"finish\") {\n this.#usage = event.event.usage\n this.#totalUsage = addUsage(this.#totalUsage, event.event.usage)\n }\n break\n }\n // status / stop — no policy state to update.\n }\n }\n\n /** Reset per-run counters. Token totals (`usage` / `totalUsage`)\n * persist unless `keepUsage: false` is passed — billing-style\n * displays usually want them sticky across resets. */\n reset(opts: { keepUsage?: boolean } = {}): void {\n this.#steps = 0\n this.#consecutiveErrors = 0\n this.#calls = []\n if (opts.keepUsage === false) {\n this.#usage = { input: 0, output: 0 }\n this.#totalUsage = { input: 0, output: 0 }\n }\n }\n\n /** Decide whether the loop should stop. Returns the stop reason or\n * `undefined` to continue. Order matters — `loop-detected` wins\n * over `max-tool-errors` if both fire, since a model in a tight\n * loop is the more pressing thing to surface. */\n detect(): AgentStopKind | undefined {\n if (this.#opts.maxSteps !== undefined && this.#steps >= this.#opts.maxSteps) {\n return \"max-steps\"\n }\n if (this.#detectLoop()) {\n return \"loop-detected\"\n }\n if (\n this.#opts.maxToolErrors !== undefined &&\n this.#consecutiveErrors >= this.#opts.maxToolErrors\n ) {\n return \"max-tool-errors\"\n }\n if (\n this.#opts.tokenBudget !== undefined &&\n this.#totalUsage.input + this.#totalUsage.output > this.#opts.tokenBudget\n ) {\n return \"token-budget\"\n }\n return undefined\n }\n\n // ── Loop detection internals ─────────────────────────────────────────\n\n #detectLoop(): boolean {\n const calls = this.#calls\n if (calls.length === 0) return false\n\n const consecutive = this.#opts.loopConsecutive ?? 3\n if (Number.isFinite(consecutive) && calls.length >= consecutive) {\n const last = hashCall(calls[calls.length - 1])\n let run = 1\n for (let i = calls.length - 2; i >= 0 && run < consecutive; i--) {\n if (hashCall(calls[i]) === last) run++\n else break\n }\n if (run >= consecutive) return true\n }\n\n const window = this.#opts.loopWindow ?? 10\n const windowRepeats = this.#opts.loopWindowRepeats ?? 4\n if (Number.isFinite(windowRepeats) && calls.length >= windowRepeats) {\n const slice = calls.slice(Math.max(0, calls.length - window))\n const counts = new Map<string, number>()\n for (const call of slice) {\n const h = hashCall(call)\n const next = (counts.get(h) ?? 0) + 1\n if (next >= windowRepeats) return true\n counts.set(h, next)\n }\n }\n\n return false\n }\n}\n\nfunction hashCall(call: ToolCallPart): string {\n return `${call.name}\\0${safeStringify(call.params)}`\n}\n","// oxlint-disable no-await-in-loop\nimport type {\n AssistantMessage,\n Content,\n Context,\n Message,\n MetaOf,\n MetaPart,\n Model,\n ModelStreamOptions,\n ParamsOf,\n TokenCount,\n Tool,\n ToolCallPart,\n ToolContext,\n ToolResult,\n} from \"@zaly/ai\"\nimport type { AgentContext } from \"./ctx.ts\"\nimport type { AgentEvents, AgentStatus, AgentStop, AgentStopKind } from \"./events.ts\"\nimport type { Session } from \"./session/session.ts\"\nimport type { AgentOptions, ContextPressure, SendMode, StepResult, TurnResult } from \"./types.ts\"\n\nimport { AiError, isContextOverflow, runTool } from \"@zaly/ai\"\nimport { Emitter, toValue, toError } from \"@zaly/shared\"\nimport { StopPolicy } from \"./stop.ts\"\nimport { Tasks, taskCompletionMessage, taskInfoPart } from \"./tasks.ts\"\nimport { TokenUsage } from \"./utils/usage.ts\"\nimport { uuidv7 } from \"./utils/uuid.ts\"\n\nconst PRESSURE_LEVELS = [0.75, 0.85, 0.95] as const\n\n/**\n * Long-lived agent — drives the multi-turn loop, owns the run-time\n * status / queues, and delegates conversation state to a `Session`.\n *\n * Typical interactive use:\n *\n * ```ts\n * const agent = await Agent.load({ model, tools })\n * agent.session.on(\"node\", (e) => render(e))\n * agent.send({ role: \"user\", content: \"hi\" }) // auto-runs\n * // …user types again later…\n * agent.send({ role: \"user\", content: \"follow-up\" }) // queues if running\n * ```\n *\n * Headless / one-shot use is just a thin wrapper on top — see\n * `runAgent` in the test helpers.\n */\nexport class Agent extends Emitter<AgentEvents> {\n readonly #opts: AgentOptions\n readonly #ctx: AgentContext\n readonly #stopPolicy: StopPolicy\n readonly #tasks: Tasks\n /** Nesting depth — see `AgentOptions.depth`. Read-only; subagents pass\n * `parent.depth + 1` when constructing their child. */\n readonly depth: number\n /** Cap on `depth` — see `AgentOptions.maxDepth`. */\n readonly maxDepth: number\n #started = false\n\n #parent?: Agent\n\n #injectQueue: Message[] = []\n #appendQueue: Message[][] = []\n #notifyQueue: MetaPart[] = []\n\n #status: AgentStatus = \"idle\"\n #abortController?: AbortController\n #pauseRequested?: string\n #running?: Promise<AgentStopKind>\n #usage: TokenUsage\n #contextEpoch = 0\n #requestEpoch = 0\n #compaction?: { session: Session; controller: AbortController; promise: Promise<void> }\n #compactionAttempt?: { session: Session; messageId?: string }\n\n /** Pending future-injects scheduled via `scheduleWakeup`. Cleared\n * whenever the loop becomes active for any reason — the scheduled\n * inject was a fallback \"wake me up at time T if nothing else does,\"\n * and once something else has, the timer is moot. Hints from cancelled\n * wakeups carry over as a system message so the intent doesn't\n * evaporate. */\n readonly #wakeups = new Map<string, { timer: ReturnType<typeof setTimeout>; hint?: string }>()\n\n #lastStop?: AgentStop\n\n /** Synchronous, low-level constructor. Prefer `Agent.load(opts)` —\n * it runs the same construction *plus* any async setup (resolving\n * `session: SessionOptions` to a built `Session`, skills discovery,\n * future warm-ups). The constructor is `protected` so test doubles /\n * subclasses can still call `super(init)` directly; they're\n * responsible for providing a pre-built `Session` on `init.session`. */\n public constructor(ctx: AgentContext) {\n super()\n const opts = ctx.opts\n this.#ctx = ctx\n this.#opts = ctx.opts\n this.depth = opts.depth ?? 0\n this.maxDepth = opts.maxDepth ?? 2\n\n // Note: session.update() + initial messages are committed\n // asynchronously from `Agent.load`, NOT here. Constructors can't\n // be async; deferring those writes until after construction also\n // gives consumers a window to subscribe to session events before\n // the first node fires.\n\n this.#tasks = new Tasks()\n this.#tasks.$tools = async () => this.tools\n this.#tasks.heartbeatMs = opts.heartbeatMs\n this.#tasks.onEmitError = (error) => opts.logger?.child(\"tasks\").error(error)\n // Post-round task completions inject a system message into the next\n // step, surfacing the result to the model. Round-internal completions\n // are folded into the round's returned parts and don't fire here.\n this.#tasks.on(\"task-done\", ({ task }) => {\n this.send(taskCompletionMessage(task))\n })\n // Heartbeats keep the agent loop alive while long-running tasks are\n // in flight. Each pulse injects a small system note listing what's\n // still going. Tasks with incremental output ready to read get a\n // `*new*` marker so the model knows to call `task_poll` if it cares.\n this.#tasks.on(\"heartbeat\", ({ running }) => {\n this.send({\n content: [{ content: [taskInfoPart(running)], tag: \"heartbeat\", type: \"meta\" }],\n role: \"system\",\n })\n })\n\n this.#stopPolicy = new StopPolicy(opts.stop)\n this.#stopPolicy.attach(this)\n this.onEmitError = (error) => opts.logger?.child(\"events\").error(error)\n this.#ctx.attach(this)\n\n // Seed usage\n this.#usage = new TokenUsage(this.messages)\n this.#ctx.on(\"session\", () => this.reset())\n }\n\n async reset(): Promise<void> {\n this.#compactionAttempt = undefined\n this.#contextEpoch++\n this.stop({ abort: true, reason: \"reset\" })\n await this.waitIdle()\n await this.#tasks.killAll()\n this.#cancelAllWakeups()\n this.#usage = new TokenUsage(this.messages)\n this.#stopPolicy.reset({ keepUsage: false })\n this.#injectQueue = []\n this.#appendQueue = []\n this.#notifyQueue = []\n this.#wakeups.clear()\n this.#stop(\"natural\")\n }\n\n /** Spawn a child agent that inherits this agent's runtime defaults —\n * cwd, model, permissions, full effective tool list (user tools +\n * the loaded skill tool), `depth + 1`, and `maxDepth`. Pass\n * `overrides` to specialize: typical ones are `prompt` (the child\n * has its own role), `session` (the child writes to its own JSONL),\n * and `tools` (curated subset).\n *\n * Used by the `subagent` tool for delegation; equally useful for\n * ad-hoc parallel-agent patterns (multiple children working on\n * pieces of a task in parallel).\n *\n * Depth cap: when the child would be at `maxDepth`, the `subagent`\n * tool is filtered out of its inherited tool list so recursion\n * bottoms out cleanly. The model just doesn't see the tool — no\n * error path. */\n async child(overrides: Partial<AgentOptions> = {}): Promise<Agent> {\n const childDepth = overrides.depth ?? this.depth + 1\n // Inherit the *effective* step tool list (includes the loaded\n // `skill` tool). The child opts out of its own skill scan since\n // the catalog is shared.\n\n let tools = [...this.tools].filter((t) => t.name !== \"skill\")\n if (childDepth >= this.maxDepth) tools = tools.filter((t) => t.name !== \"subagent\")\n const { createAgent } = await import(\"./ctx.ts\")\n\n const ret = await createAgent({\n cwd: this.cwd,\n depth: childDepth,\n mask: this.#opts.mask,\n maxDepth: this.maxDepth,\n model: this.model,\n // Inherit the parent's `notify` setting so test roots that\n // disable the notifier (`notify: false`) propagate that to\n // children — otherwise spawning a child would silently re-enable\n // session-started / time / etc. injections that the harness\n // explicitly opted out of.\n notify: this.#opts.notify,\n permissions: await this.ctx.permissions(),\n skills: this.#ctx.skills, // shared catalog; child doesn't reload\n // Propagate the swarm so the child + every grandchild address\n // each other through the same registry. Override-able via\n // `overrides.swarm` if a caller wants the child outside the\n // tree (rare).\n swarm: await this.#ctx.swarm(),\n tools,\n ...overrides,\n })\n ret.#parent = this\n // Children are spawned ready — subagent dispatch typically calls\n // `.send()` immediately after, and inspecting `child.tools` /\n // `child.prompt` before sending should just work.\n await ret.start()\n return ret\n }\n\n // ── Read ──────────────────────────────────────────────────────────────\n\n /** Active conversation — delegates to the underlying `Session`. */\n get messages(): readonly Message[] {\n return this.session.messages\n }\n\n get status(): AgentStatus {\n return this.#status\n }\n\n get cwd(): string {\n return this.#ctx.cwd\n }\n\n get model(): Model | undefined {\n return this.#ctx.model\n }\n\n get session(): Session {\n return this.#ctx.session\n }\n\n get signal(): AbortSignal | undefined {\n return this.#abortController?.signal\n }\n\n /** Token usage from the most recent step's response. Drives\n * `contextSize` and any \"this turn used N tokens\" UI. */\n get usage(): TokenUsage {\n return this.#usage\n }\n\n /** Cumulative token usage across every step in the current run.\n * Useful for billing-style displays. */\n get totalUsage(): TokenCount {\n return this.#usage.total\n }\n /** Logical size of the current conversation in tokens — what the\n * next request will send as input. Equals the last step's\n * `input + output` (since the model's reply becomes part of the\n * next prompt). Returns 0 before any step has run. */\n get contextSize(): number {\n return this.#usage.contextSize\n }\n\n get pressure(): ContextPressure {\n const used = this.contextSize\n const limit = this.model?.spec.contextSize ?? 0\n const ratio = limit > 0 ? used / limit : 0\n const level = PRESSURE_LEVELS.findLast((t) => ratio >= t) ?? 0\n return { level, limit, ratio, used }\n }\n\n get lastStop(): AgentStop | undefined {\n return this.#lastStop\n }\n\n get steps(): number {\n return this.#stopPolicy.steps\n }\n\n get parent(): Agent | undefined {\n return this.#parent\n }\n\n get tools() {\n return this.#ctx.tools\n }\n\n get prompt() {\n return this.#ctx.prompt\n }\n\n get ctx(): AgentContext {\n return this.#ctx\n }\n\n /** Long-running task registry — exposed for the TUI / introspection\n * tools (`task_list`, etc.). Mutating directly is a foot-gun;\n * prefer the agent's higher-level surface. */\n get tasks(): Tasks {\n return this.#tasks\n }\n\n // ── Input ────────────────────────────────────────────────────────────\n\n #enqueue(message: Message | Message[], opts: { mode?: SendMode } = {}): void {\n const messages = Array.isArray(message) ? message : [message]\n if (!messages.length) return\n for (const m of messages) m.id ??= uuidv7()\n if (opts.mode === \"append\") this.#appendQueue.push(messages)\n else this.#injectQueue.push(...messages)\n void this.emit(\"pending\", { messages })\n }\n\n /** Queue messages and start/resume the loop when idle or paused.\n * `inject` (default) delivers before the next model step without\n * interrupting an active response or tool batch. `append` waits until\n * the current turn finishes naturally and no injections remain.\n * Injections batch in queue order; appends run one send() submission\n * at a time, keeping each submission's messages together.\n * With `run: false`, only enqueue; omit messages to start/resume\n * processing already queued work. */\n send(message?: Message | Message[], opts: { mode?: SendMode; run?: boolean } = {}): void {\n this.#enqueue(message ?? [], opts)\n if (opts.run === false) return\n if (this.#status === \"idle\" || this.#status === \"paused\") void this.run()\n }\n\n async useTool<T extends Tool = Tool>(\n name: T[\"name\"],\n params: ParamsOf<T>,\n msg: string,\n opts: { hidden?: boolean } = {}\n ): Promise<{\n call: ToolCallPart<T[\"name\"], ParamsOf<T>>\n result: ToolResult<MetaOf<T>>\n messages: [Message<\"system\">, Message<\"assistant\">, Message<\"tool\">]\n }> {\n const tool = this.tools.find((t) => t.name === name) as T | undefined\n if (!tool) throw new Error(`cannot inject tool use: no tool named \"${name}\"`)\n\n const id = uuidv7()\n const call: ToolCallPart = { id, name, params, type: \"tool-call\" }\n const result = await runTool(tool, params, await this.#toolContext(), { preflight: false })\n const messages: [Message<\"system\">, Message<\"assistant\">, Message<\"tool\">] = [\n {\n content: [\n {\n content: msg,\n data: { tool: name },\n tag: \"user-tool-use\",\n type: \"meta\",\n },\n ],\n role: \"system\",\n },\n {\n content: [call],\n role: \"assistant\",\n },\n {\n content: [\n {\n content: result.content,\n error: result.error,\n id,\n isError: result.isError,\n meta: result.meta,\n name,\n type: \"tool-result\",\n },\n ],\n role: \"tool\",\n },\n ]\n\n if (opts.hidden) for (const m of messages) m.hidden = true\n\n return { call, messages, result: result as ToolResult<MetaOf<T>> }\n }\n\n notify(type: string, data: Content | Record<string, unknown>): void {\n const meta: MetaPart =\n typeof data === \"string\" || Array.isArray(data)\n ? { content: data, tag: type, type: \"meta\" }\n : { data, tag: type, type: \"meta\" }\n this.#notifyQueue.push(meta)\n }\n\n /** Schedule a one-shot wake-up at `delayMs` from now. The agent will\n * receive a system message at that time IF nothing else has woken\n * the loop in the meantime — task-done injects, heartbeats, and user\n * messages all auto-cancel pending wakeups (their job was to ensure\n * the agent gets a turn; if it's already getting one, the timer is\n * redundant).\n *\n * Cancelled wakeups don't silently disappear — their `hint`s, if any,\n * are folded into a system message that lands in the next step\n * alongside whatever woke the loop. The model sees the hints with a\n * `status=\"cancelled\"` marker so it knows the timer didn't fire.\n *\n * Returns the wakeup id (mostly for telemetry / TUI display — the\n * model can't usefully cancel it later, since by the time it has a\n * turn to call cancel, the wakeup has either fired or been cancelled\n * for it). */\n scheduleWakeup(opts: { delayMs: number; hint?: string }): string {\n const id = uuidv7()\n const timer = setTimeout(() => {\n this.#wakeups.delete(id)\n this.send({\n content: [{ data: { hint: opts.hint, id }, tag: \"wakeup\", type: \"meta\" }],\n role: \"system\",\n })\n }, opts.delayMs)\n timer.unref()\n this.#wakeups.set(id, { hint: opts.hint, timer })\n return id\n }\n\n /** Cancel all pending wakeups, surfacing their hints as a single\n * system message so the model can see what was queued. Called from\n * `#setStatus` whenever the agent transitions to `streaming` — that's\n * the unambiguous \"loop is active\" signal. */\n #cancelAllWakeups(): void {\n if (this.#wakeups.size === 0) return\n const carried: { id: string; hint: string }[] = []\n for (const [id, { hint, timer }] of this.#wakeups) {\n clearTimeout(timer)\n if (hint) carried.push({ hint, id })\n }\n this.#wakeups.clear()\n if (carried.length > 0) {\n const parts: MetaPart[] = carried.map((c) => ({\n data: { hint: c.hint, id: c.id, status: \"cancelled\" as const },\n tag: \"wakeup\",\n type: \"meta\",\n }))\n this.#injectQueue.push({ content: parts, role: \"system\" })\n }\n }\n\n // ── Loop control ─────────────────────────────────────────────────────\n\n /** Drive steps until the agent goes idle (no queued messages and\n * the model stopped naturally) or hits a non-recoverable stop.\n * Doubles as a resume from `paused` — drains queued messages and\n * picks the loop back up. If a run is already in flight, returns\n * the existing promise. */\n run(): Promise<AgentStopKind> {\n if (this.#running) return this.#running\n this.#pauseRequested = undefined\n this.#abortController = undefined\n this.#running = this.#loop()\n .catch((error) => {\n this.#opts.logger?.child(\"run\").error(error)\n return this.#stop(\n error instanceof Error && error.name === \"AbortError\" ? \"aborted\" : \"error\",\n error\n )\n })\n .finally(() => {\n this.#abortController = undefined\n this.#running = undefined\n })\n return this.#running\n }\n\n async #collect() {\n this.#abortController = new AbortController()\n const epoch = this.#contextEpoch\n this.#requestEpoch = epoch\n const usage = this.#usage\n const session = this.session\n const context = {\n cacheKey: this.ctx.session.id,\n messages: [...this.ctx.messages],\n prompt: this.prompt,\n sessionId: this.ctx.session.id,\n tools: this.tools,\n } satisfies Context\n await this.emitSerial(\"context\", context)\n const model = this.model\n if (!model) throw new Error(\"model must be loaded to collect\")\n const message = await model.stream(context, this.#streamOpts())\n if (this.session !== session) throw new DOMException(\"Request session changed\", \"AbortError\")\n return { epoch, message, usage }\n }\n\n #maybeCompact(opts: { backgroundOnly?: boolean } = {}): Promise<void> | undefined {\n const config = toValue(this.#opts.compaction)\n if (config?.enabled === false) return\n const ratio = this.pressure.ratio\n\n if (!opts.backgroundOnly && ratio >= (config?.threshold ?? 0.95))\n return this.#compact({ trigger: \"auto\" })\n\n if (config?.backgroundEnabled === false || this.#pauseRequested !== undefined) return\n if (ratio < (config?.backgroundThreshold ?? 0.9)) return\n if (\n this.#compaction &&\n !this.#compaction.controller.signal.aborted &&\n this.#compaction.session === this.session\n )\n return\n const session = this.session\n const messageId = session.messages.at(-1)?.id\n if (\n this.#compactionAttempt?.session === session &&\n this.#compactionAttempt.messageId === messageId\n )\n return\n return this.#compact({ background: true, trigger: \"auto\" })\n }\n\n #streamOpts(): ModelStreamOptions {\n const base = this.#opts.request ?? {}\n return {\n ...base,\n onEvent: (event) => {\n void this.emit(\"stream-event\", { event })\n try {\n void this.#opts.onEvent?.(event)\n } catch (error) {\n this.#opts.logger?.child(\"stream\").error(error)\n }\n },\n onUpdate: this.#opts.onUpdate,\n reasoning: { ...base.reasoning, effort: this.#ctx.reasoning },\n signal: this.#abortController?.signal,\n }\n }\n\n /** Run exactly one step. Useful for tests and custom drivers\n * that want to interleave logic between steps. */\n async step(): Promise<StepResult> {\n const compaction = this.#maybeCompact()\n if (compaction) await compaction\n // Drain the notify queue into the inject queue as a single system message\n if (this.#notifyQueue.length > 0) {\n this.#injectQueue.push({\n content: this.#notifyQueue.splice(0),\n role: \"system\",\n })\n }\n\n // Drain injections from send(), notifications, wakeups, and hooks.\n // Sequential await preserves queue order in the session.\n for (const m of this.#injectQueue.splice(0)) await this.session.add(m)\n\n this.#setStatus(\"streaming\")\n\n let collected: AssistantMessage\n\n try {\n const response = await this.#collect()\n collected = response.message\n response.usage.add(collected.meta.usage, { current: response.epoch === this.#contextEpoch })\n } catch (error) {\n const err = toError(error)\n const overflow = isContextOverflow({ message: err.message })\n if (overflow) this.#opts.logger?.warn(\"Context overflow detected:\", err)\n return {\n error: err,\n finishReason: overflow ? \"length\" : \"error\",\n kind: overflow ? \"context-overflow\" : \"error\",\n usage: { input: 0, output: 0 },\n }\n }\n\n const result: Omit<StepResult, \"kind\"> = {\n finishReason: collected.meta.finishReason,\n message: collected,\n usage: collected.meta.usage,\n }\n\n // Silent-overflow check BEFORE committing the message — gives the\n // session a chance to drop it and retry on a compacted history.\n if (\n this.#opts.contextLimit !== undefined &&\n isContextOverflow({\n contextLimit: this.#opts.contextLimit,\n // Total prompt size = uncached input + cached reads + cached\n // writes. `usage.input` is uncached-only; the cache fields are\n // separate billing tiers that still occupy the context window.\n usageInput:\n result.usage.input + (result.usage.cacheRead ?? 0) + (result.usage.cacheWrite ?? 0),\n })\n )\n return { kind: \"context-overflow\", ...result }\n\n const calls = await this.#parseToolCalls(collected)\n await this.session.add(collected)\n void this.#maybeCompact({ backgroundOnly: true })\n\n if (calls.length === 0) return { kind: \"natural\", ...result }\n\n return {\n kind: \"tool-calls\",\n toolMessage: await this.#runTools(calls),\n ...result,\n }\n }\n\n async #parseToolCalls(message: Message): Promise<ToolCallPart[]> {\n if (typeof message.content === \"string\") return []\n const calls = message.content.filter((p): p is ToolCallPart => p.type === \"tool-call\")\n for (const call of calls) {\n const tool = this.tools.find((t) => t.name === call.name)\n if (!tool) continue\n try {\n call.params = (await tool.validator.cleanParams(call.params)) ?? call.params\n } catch {}\n }\n return calls\n }\n\n /** Apply compaction before resolving, or start it without waiting when background is true. */\n async compact(opts: { background?: boolean } = {}): Promise<void> {\n return this.#compact(opts)\n }\n\n async #compact(opts: { background?: boolean; trigger?: \"manual\" | \"auto\" } = {}): Promise<void> {\n let job = this.#compaction\n if (job && (job.session !== this.session || job.controller.signal.aborted)) job = undefined\n if (!job) {\n const session = this.session\n const controller = new AbortController()\n const pressure = this.pressure\n this.#compactionAttempt = { messageId: session.messages.at(-1)?.id, session }\n const applied = () => {\n if (this.session !== session) return\n this.#contextEpoch++\n this.#usage.resetLast()\n }\n session.on(\"compact\", applied)\n const promise = (async () => {\n try {\n const { Compaction } = await import(\"./compaction/compactions.ts\")\n controller.signal.throwIfAborted()\n const config = toValue(this.#opts.compaction)\n const signal = config?.signal\n ? AbortSignal.any([controller.signal, config.signal])\n : controller.signal\n const compactor = new Compaction(this, {\n ...config,\n signal,\n trigger: opts.trigger ?? config?.trigger ?? \"manual\",\n })\n await compactor.compact(pressure)\n } finally {\n session.off(\"compact\", applied)\n if (this.#compaction?.controller === controller) this.#compaction = undefined\n }\n })()\n job = { controller, promise, session }\n this.#compaction = job\n // Background callers do not await the job, but blocking callers still receive its error.\n void promise.catch((error) => {\n if (!controller.signal.aborted) this.#opts.logger?.child(\"compaction\").error(error)\n })\n }\n if (opts.background) return\n const prev = this.#status\n this.#setStatus(\"compacting\")\n try {\n await job.promise\n } finally {\n if (this.#status === \"compacting\") this.#setStatus(prev)\n }\n }\n\n async #runTools(calls: ToolCallPart[]) {\n this.#setStatus(\"running-tools\")\n void this.emit(\"tool-calls\", { calls })\n for (const call of calls) void this.emit(\"tool-call\", { call })\n\n const emitted = new Set<string>()\n // The whole batch — including streamable promotion, parallel chains,\n // grace timing, and ownerRound suppression — lives in Tasks.run().\n // What lands back here is a 1:1 array of result parts ready to commit.\n // The skill tool (when active) is passed via `extraTools` so dispatch\n // can resolve `name: \"skill\"` calls without polluting `tasks.tools`.\n const resultParts = await this.#tasks.run(calls, await this.#toolContext(), {\n onResult: (call, result) => {\n emitted.add(call.id)\n void this.emit(\"tool-result\", { call, result })\n },\n })\n\n for (let i = 0; i < calls.length; i++) {\n const call = calls[i]\n const part = resultParts[i]\n if (emitted.has(call.id)) continue\n void this.emit(\"tool-result\", {\n call,\n result: {\n content: part.content,\n error: part.error,\n isError: part.isError ?? false,\n meta: part.meta,\n },\n })\n }\n const message: Message<\"tool\"> = { content: resultParts, role: \"tool\" }\n await this.session.add(message)\n return message\n }\n\n /** Resolve when the agent is in a quiescent state — `idle` or\n * `paused`. If a run is currently in flight (or was just kicked off\n * synchronously by `send` / `inject` / a wakeup), waits for it to\n * settle before returning the final status. If no run is in flight,\n * resolves immediately with the current status.\n *\n * Use this in REPL-style drivers to await the loop without racing\n * with internally-triggered runs (the wakeup timer, heartbeat, or\n * task-completion injects all spawn `void this.run()` independently\n * of caller-driven `await agent.run()`). The `#running` promise is\n * set synchronously inside `run()` before any await point, so this\n * catches every kicked-off cycle including the one `send` just fired.\n *\n * Errors from the loop are swallowed — callers read `agent.lastError`\n * / `agent.lastStopReason` for diagnostics. The point of `waitIdle`\n * is just to know \"the loop is no longer driving.\" */\n async waitIdle(timeout?: number): Promise<AgentStatus> {\n if (!this.#running) return this.#status\n const wait = [this.#running.catch(() => undefined)]\n if (timeout !== undefined) wait.push(new Promise((resolve) => setTimeout(resolve, timeout)))\n await Promise.race(wait)\n return this.#status\n }\n\n /** Stop the loop with a custom reason.\n * When `abort: true` (the default), also trigger the abort signal so any\n * in-flight stream or tool calls can react to the stop.\n * When `abort: false`, the agent still stops immediately, but any active\n * stream or tool calls are left to run to completion */\n stop(opts: { abort?: boolean; reason?: string } = {}): void {\n this.#pauseRequested ??= opts.reason ?? \"stop\"\n if (opts.abort ?? true) {\n this.#abortController?.abort(opts.reason)\n this.#compaction?.controller.abort(opts.reason)\n }\n }\n\n async start() {\n if (this.#started) return\n this.#started = true\n await this.emit(\"start\")\n }\n\n get started() {\n return this.#started\n }\n\n // ── Internals ────────────────────────────────────────────────────────\n\n async #turn(): Promise<TurnResult> {\n for (let step = 1; ; step++) {\n if (this.#abortController?.signal.aborted)\n return { kind: \"aborted\", reason: this.#abortController.signal.reason }\n if (this.#pauseRequested !== undefined)\n return { kind: \"paused\", reason: this.#pauseRequested }\n\n void this.emit(\"step-start\", { step })\n const outcome = await this.step()\n void this.emit(\"step-end\", { outcome: outcome.kind, step })\n\n if (outcome.kind === \"error\") {\n return {\n kind: outcome.error?.name === \"AbortError\" ? \"aborted\" : \"error\",\n reason: outcome.error,\n }\n }\n\n if (outcome.kind === \"natural\") {\n return { kind: \"natural\" }\n }\n\n if (outcome.kind === \"context-overflow\") {\n // Auto-compaction also gates the overflow recovery path. With\n // `auto: false`, overflow stops cleanly instead of attempting\n // a recovery the user explicitly opted out of.\n if (toValue(this.#opts.compaction)?.enabled === false) return { kind: \"context-overflow\" }\n // A background summary may already have replaced the rejected context.\n if (this.#requestEpoch !== this.#contextEpoch) continue\n // Compactor mutates the conversation; the rejected message is\n // not committed — next step retries on the compacted state.\n this.#opts.logger\n ?.child(\"compaction\")\n .warn(\n `context overflow detected (size ${this.contextSize}, limit ${this.pressure.limit}); running compaction`\n )\n await this.#compact({ trigger: \"auto\" })\n continue\n }\n\n // outcome.kind === \"tool-calls\" — consult the policy.\n const stop = this.#stopPolicy.detect()\n if (stop) return { kind: stop }\n }\n }\n\n async #loop(): Promise<AgentStopKind> {\n if (!this.#started) await this.start()\n // Reset per-run counters (steps, consecutive errors, call history).\n // Token totals stay sticky across resets — they're billing-style\n // displays, not per-turn caps.\n this.#stopPolicy.reset()\n for (let turn = 1; ; turn++) {\n // Start one append submission only after pending injections have settled.\n if (this.#injectQueue.length === 0)\n for (const m of this.#appendQueue.shift() ?? []) await this.session.add(m)\n\n void this.emit(\"turn-start\", { turn })\n const result = await this.#turn()\n const reason = result.reason ? toError(result.reason).message : undefined\n void this.emit(\"turn-end\", { outcome: result.kind, reason, turn })\n\n // If the model stopped naturally but there are still queued messages,\n // keep the loop alive to process them.\n if (\n result.kind === \"natural\" &&\n (this.#injectQueue.length > 0 || this.#appendQueue.length > 0)\n )\n continue\n\n return this.#stop(result.kind, result.reason)\n }\n }\n\n #stop(kind: AgentStopKind, reason?: unknown): AgentStopKind {\n this.#lastStop = {\n error: reason instanceof Error ? reason : undefined,\n kind,\n reason: reason === undefined ? undefined : toError(reason).message,\n }\n this.#setStatus(kind === \"natural\" ? \"idle\" : \"paused\")\n void this.emit(\"stop\", {\n status: this.#status,\n usage: this.usage,\n ...this.#lastStop,\n })\n return kind\n }\n\n /** Build the per-step `ToolContext` handed to each tool. The session\n * cwd, an abort signal scoped to the in-flight stream, and the\n * long-running spawn registry are all surfaced here. */\n async #toolContext(): Promise<ToolContext> {\n const masker = await this.#ctx.masker()\n return {\n agent: this,\n bash: this.#opts.bash,\n cwd: this.cwd,\n isMasked: (msgId: string, partIdx?: number) => masker?.isMasked(msgId, partIdx) ?? false,\n messages: this.session.messages,\n need: (scope, input) => this.#need(scope, input),\n perms: await this.ctx.permissions(),\n sessionDir: this.session.dir,\n signal: this.#abortController?.signal,\n swarm: () => this.#ctx.swarm(),\n tasks: this.#tasks,\n }\n }\n\n /** Implementation of `ctx.need(scope, input)`. Resolves on `allow`,\n * throws a `PERMISSION_DENIED` `AiError` on `deny`, and escalates\n * `ask` to `AgentOptions.allow` (treating it as `deny` when no\n * callback is configured). */\n async #need(scope: string, input: string): Promise<void> {\n const perms = await this.ctx.permissions()\n const r = perms.validate(scope, input)\n if (r.verdict === \"allow\") return\n if (r.verdict === \"ask\" && this.#opts.allow) {\n const ok = await this.#opts.allow({\n ask: r.ask,\n input,\n reason: r.reason,\n scope,\n suggestions: r.suggestions,\n })\n if (ok) return\n }\n throw new AiError({\n code: \"PERMISSION_DENIED\",\n data: { input, scope, suggestions: r.suggestions, verdict: r.verdict },\n message: r.reason,\n // `ask` verdicts that the user denied this turn are retryable —\n // they may add a rule later. Hard `deny` is not.\n retryable: r.verdict === \"ask\",\n })\n }\n\n /** Tear down session-scoped resources. Called on agent disposal — the\n * agent doesn't auto-dispose today, so callers (TUI on quit, headless\n * runner on completion) should invoke this explicitly. */\n async dispose(): Promise<void> {\n this.clearListeners()\n this.#cancelAllWakeups()\n await this.#tasks.killAll()\n }\n\n #setStatus(status: AgentStatus): void {\n const prev = this.#status\n if (prev === status) return\n // Cancel wakeups only when an EXTERNAL wake-up brings the loop back\n // to active (idle/paused → streaming). Mid-turn transitions\n // (running-tools → streaming) are the same turn continuing — a\n // wakeup the model just scheduled mid-tool-call would otherwise be\n // killed before it ever fires. The \"external wake-up\" cases that\n // *should* cancel: a `task-done` inject, a heartbeat, a user\n // message — all route through `inject` → `send` → `run` from the\n // idle/paused state, hitting this branch correctly.\n if (status === \"streaming\" && (prev === \"idle\" || prev === \"paused\")) {\n this.#cancelAllWakeups()\n }\n this.#status = status\n void this.emit(\"status\", { status })\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as extractConversation, c as formatFileUsage, i as extractBashUsage, l as messageTail, o as extractFileUsage, s as formatBashUsage } from "./src-
|
|
1
|
+
import { a as extractConversation, c as formatFileUsage, i as extractBashUsage, l as messageTail, o as extractFileUsage, s as formatBashUsage } from "./src-DJoqT9yP.mjs";
|
|
2
2
|
import { toXml } from "@zaly/ai";
|
|
3
3
|
// src/compaction/prompt.ts
|
|
4
4
|
const SYSTEM_PROMPT = `Summarize the supplied conversation into a structured context checkpoint for your future self to resume the work. Do not continue the conversation or answer questions in it.
|
|
@@ -32,9 +32,11 @@ const SUMMARY_PROMPT = `Create the context checkpoint summary now, using the for
|
|
|
32
32
|
/** Shown to the resumed agent, not the summarizer. */
|
|
33
33
|
const SUMMARY_HEADER = `The older conversation has been compacted into the summary below. Recent messages follow verbatim and may supersede it. Use both to continue where the conversation left off without repeating completed work.
|
|
34
34
|
|
|
35
|
-
File and command usage tables cover the
|
|
35
|
+
File and command usage tables cover the summarized history and are navigation aids, not evidence of results. If necessary information is missing, consult the referenced artifacts or ask rather than guess.`;
|
|
36
36
|
// src/compaction/compactions.ts
|
|
37
37
|
const defaults = {
|
|
38
|
+
backgroundEnabled: true,
|
|
39
|
+
backgroundThreshold: .9,
|
|
38
40
|
bash: {
|
|
39
41
|
limit: 50,
|
|
40
42
|
minCount: 2,
|
|
@@ -65,16 +67,21 @@ var Compaction = class {
|
|
|
65
67
|
};
|
|
66
68
|
}
|
|
67
69
|
async compact(pressure) {
|
|
68
|
-
const { session } = this.#agent;
|
|
70
|
+
const { session, model } = this.#agent;
|
|
71
|
+
if (!model) throw new Error("model must be loaded to compact");
|
|
69
72
|
const masker = await this.#agent.ctx.masker();
|
|
70
|
-
const
|
|
73
|
+
const snapshot = [...session.messages];
|
|
74
|
+
const messages = masker ? await masker.mask(snapshot, pressure) : snapshot;
|
|
71
75
|
const now = performance.now();
|
|
72
76
|
const tail = messageTail(messages, { keepTokens: this.#opts.keepTokens });
|
|
73
77
|
const older = tail.length > 0 ? messages.slice(0, -tail.length) : messages;
|
|
74
78
|
if (older.length === 0) return;
|
|
79
|
+
const to = older.at(-1)?.id;
|
|
80
|
+
const from = older[0].id;
|
|
81
|
+
if (!to || !from) throw new Error("Compaction snapshot messages must have IDs");
|
|
75
82
|
const conversation = extractConversation(older, { maxToolResultLen: this.#opts.maxToolResultLen });
|
|
76
|
-
const bashUsage = formatBashUsage(extractBashUsage(
|
|
77
|
-
const fileUsage = formatFileUsage(extractFileUsage(
|
|
83
|
+
const bashUsage = formatBashUsage(extractBashUsage(older, this.#opts.bash));
|
|
84
|
+
const fileUsage = formatFileUsage(extractFileUsage(older, this.#opts.files));
|
|
78
85
|
const request = {
|
|
79
86
|
content: [
|
|
80
87
|
{
|
|
@@ -96,7 +103,10 @@ var Compaction = class {
|
|
|
96
103
|
],
|
|
97
104
|
role: "user"
|
|
98
105
|
};
|
|
99
|
-
|
|
106
|
+
this.#opts.signal?.throwIfAborted();
|
|
107
|
+
const summary = await this.#summarize(request, model, session.id);
|
|
108
|
+
this.#opts.signal?.throwIfAborted();
|
|
109
|
+
if (this.#agent.session !== session) throw new Error("Compaction session changed");
|
|
100
110
|
const summaryMessage = {
|
|
101
111
|
content: [
|
|
102
112
|
{
|
|
@@ -121,20 +131,20 @@ var Compaction = class {
|
|
|
121
131
|
};
|
|
122
132
|
await session.compact({
|
|
123
133
|
durationMs: Math.round(performance.now() - now),
|
|
124
|
-
|
|
134
|
+
from,
|
|
135
|
+
preTokens: pressure.used,
|
|
136
|
+
signal: this.#opts.signal,
|
|
125
137
|
summary: summaryMessage,
|
|
126
|
-
|
|
138
|
+
to,
|
|
127
139
|
trigger: this.#opts.trigger
|
|
128
140
|
});
|
|
129
141
|
masker?.reset();
|
|
130
142
|
}
|
|
131
|
-
async #summarize(message) {
|
|
132
|
-
const model = this.#agent.model;
|
|
133
|
-
if (!model) throw new Error("model must be loaded to compact");
|
|
143
|
+
async #summarize(message, model, sessionId) {
|
|
134
144
|
const m = await model.stream({
|
|
135
145
|
messages: [message],
|
|
136
146
|
prompt: [SYSTEM_PROMPT],
|
|
137
|
-
sessionId
|
|
147
|
+
sessionId
|
|
138
148
|
}, {
|
|
139
149
|
caching: false,
|
|
140
150
|
maxTokens: this.#opts.summaryTokens,
|
|
@@ -147,4 +157,4 @@ var Compaction = class {
|
|
|
147
157
|
};
|
|
148
158
|
export { Compaction };
|
|
149
159
|
|
|
150
|
-
//# sourceMappingURL=compactions-
|
|
160
|
+
//# sourceMappingURL=compactions-BpvQk4CG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compactions-BpvQk4CG.mjs","names":[],"sources":["../src/compaction/prompt.ts","../src/compaction/compactions.ts"],"sourcesContent":["/* Prompts for generating a checkpoint and framing it for the resumed agent. */\n\nexport const SYSTEM_PROMPT = `Summarize the supplied conversation into a structured context checkpoint for your future self to resume the work. Do not continue the conversation or answer questions in it.\n\nUse this format, omitting empty sections:\n\n## Goal\nWhat the user is trying to accomplish and what they have authorized.\n\n## Constraints & Preferences\nImportant requirements, boundaries, and user corrections.\n\n## Progress\nCompleted work, work in progress, and blockers. Include outstanding tasks or tool results needed to resume.\n\n## Key Decisions\nWhat was chosen or rejected, with brief rationale.\n\n## Next Steps\nWhat remains to be done, in order. Do not invent work if the task is complete.\n\n## Critical Context\nEssential data, references, and artifact paths, with a brief explanation of why they matter.\n\nBe concise and readable. Preserve exact paths, identifiers, commands, and errors when needed to continue accurately. Distinguish verified results from proposals and uncertainty; do not infer missing tool results.\n\nSummarize user intent rather than listing every message. File and command usage tables are included separately: do not reproduce their inventories or infer outcomes from them. Mention only files and commands whose significance needs explaining.\n\nConsolidate previous summaries with newer evidence, removing repetition and superseded state while retaining relevant constraints and decisions.`\n\nexport const SUMMARY_PROMPT = `Create the context checkpoint summary now, using the format above. Output only the summary.`\n\nexport const PREVIOUS_SUMMARY_PROMPT = `Incorporate this prior summary into the new checkpoint, retaining relevant context and updating superseded state from the conversation.`\n\n/** Shown to the resumed agent, not the summarizer. */\nexport const SUMMARY_HEADER = `The older conversation has been compacted into the summary below. Recent messages follow verbatim and may supersede it. Use both to continue where the conversation left off without repeating completed work.\n\nFile and command usage tables cover the summarized history and are navigation aids, not evidence of results. If necessary information is missing, consult the referenced artifacts or ask rather than guess.`\n","import type { Message, ReasoningEffort } from \"@zaly/ai\"\nimport type { Agent } from \"../agent.ts\"\nimport type { ContextPressure } from \"../types.ts\"\nimport type { ToolStatOptions } from \"./utils.ts\"\n\nimport { toXml } from \"@zaly/ai\"\nimport { SUMMARY_HEADER, SUMMARY_PROMPT, SYSTEM_PROMPT } from \"./prompt.ts\"\nimport {\n extractBashUsage,\n extractConversation,\n extractFileUsage,\n formatBashUsage,\n formatFileUsage,\n messageTail,\n} from \"./utils.ts\"\n\nexport type CompactionOptions = {\n enabled: boolean\n threshold?: number\n /** Prepare and apply automatic compaction without pausing the foreground loop. */\n backgroundEnabled?: boolean\n backgroundThreshold?: number\n /** Existing messages up to this many tokens will be preserved in the context */\n keepTokens: number\n maxToolResultLen: number\n summaryTokens: number\n bash: ToolStatOptions\n files: ToolStatOptions\n signal?: AbortSignal\n reasoning?: ReasoningEffort\n trigger?: \"manual\" | \"auto\"\n}\n\nconst defaults: CompactionOptions = {\n backgroundEnabled: true,\n backgroundThreshold: 0.9,\n bash: { limit: 50, minCount: 2, minScore: 0.5, sort: \"score\" },\n enabled: true,\n files: { limit: 50, minCount: 1, minScore: 0.5, sort: \"score\" },\n keepTokens: 20_000,\n maxToolResultLen: 2000,\n reasoning: \"low\",\n summaryTokens: 10_000,\n threshold: 0.95,\n}\n\nexport class Compaction {\n #opts: CompactionOptions\n #agent: Agent\n\n constructor(agent: Agent, opts: Partial<CompactionOptions> = {}) {\n this.#agent = agent\n this.#opts = { ...defaults, ...opts }\n }\n\n async compact(pressure: ContextPressure): Promise<void> {\n const { session, model } = this.#agent\n if (!model) throw new Error(\"model must be loaded to compact\")\n\n const masker = await this.#agent.ctx.masker()\n\n const snapshot = [...session.messages]\n const messages = masker ? await masker.mask(snapshot, pressure) : snapshot\n\n const now = performance.now()\n\n const tail = messageTail(messages, { keepTokens: this.#opts.keepTokens })\n const older = tail.length > 0 ? messages.slice(0, -tail.length) : messages\n\n if (older.length === 0) return\n const to = older.at(-1)?.id\n const from = older[0].id\n if (!to || !from) throw new Error(\"Compaction snapshot messages must have IDs\")\n\n const conversation = extractConversation(\n // Conversation summary is based on the older messages, not the tail — the tail is what we keep\n older,\n { maxToolResultLen: this.#opts.maxToolResultLen }\n )\n\n const bashUsage = formatBashUsage(extractBashUsage(older, this.#opts.bash))\n const fileUsage = formatFileUsage(extractFileUsage(older, this.#opts.files))\n\n const request: Message<\"user\"> = {\n content: [\n { text: conversation, type: \"text\" },\n { text: fileUsage, type: \"text\" },\n { text: bashUsage, type: \"text\" },\n { text: SUMMARY_PROMPT, type: \"text\" },\n ],\n role: \"user\",\n }\n\n this.#opts.signal?.throwIfAborted()\n const summary = await this.#summarize(request, model, session.id)\n this.#opts.signal?.throwIfAborted()\n if (this.#agent.session !== session) throw new Error(\"Compaction session changed\")\n // The bash + file usage tables are deterministic, ground-truth signals\n // — pricier to ask the model to reproduce than to copy verbatim. Carry\n // them through to the resumed agent so it has the same working-set\n // visibility the summarizer had, without paying for output tokens.\n const summaryMessage: Message<\"system\"> = {\n content: [\n { text: SUMMARY_HEADER, type: \"text\" },\n { text: toXml(summary, \"compaction-summary\", { indent: false }), type: \"text\" },\n { text: fileUsage, type: \"text\" },\n { text: bashUsage, type: \"text\" },\n ],\n meta: { kind: \"compaction-summary\" },\n role: \"system\",\n }\n await session.compact({\n durationMs: Math.round(performance.now() - now),\n from,\n preTokens: pressure.used,\n signal: this.#opts.signal,\n summary: summaryMessage,\n to,\n trigger: this.#opts.trigger,\n })\n masker?.reset()\n }\n\n async #summarize(\n message: Message<\"user\">,\n model: NonNullable<Agent[\"model\"]>,\n sessionId: string\n ): Promise<string> {\n const m = await model.stream(\n {\n messages: [message],\n prompt: [SYSTEM_PROMPT],\n sessionId,\n },\n {\n caching: false,\n maxTokens: this.#opts.summaryTokens,\n reasoning: this.#opts.reasoning ? { effort: this.#opts.reasoning } : undefined,\n signal: this.#opts.signal,\n }\n )\n if (typeof m.content === \"string\") return m.content\n const parts = m.content.filter((p) => p.type === \"text\").map((p) => p.text)\n return parts.join(\"\\n\")\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { p as SessionOptions, t as Session } from "./session-
|
|
1
|
+
import { p as SessionOptions, t as Session } from "./session-DY9mF9Vb.mjs";
|
|
2
2
|
import { Emitter, Envelope, MaybeGetter } from "@zaly/shared";
|
|
3
3
|
import { BaseCollection } from "@zaly/shared/collection";
|
|
4
4
|
import { AnyKey } from "@zaly/shared/registry";
|
|
@@ -704,7 +704,9 @@ declare class TokenUsage implements Usage {
|
|
|
704
704
|
get cacheRead(): number;
|
|
705
705
|
get cacheWrite(): number;
|
|
706
706
|
get reasoning(): number;
|
|
707
|
-
add(count: Usage
|
|
707
|
+
add(count: Usage, opts?: {
|
|
708
|
+
current?: boolean;
|
|
709
|
+
}): void;
|
|
708
710
|
resetLast(): void;
|
|
709
711
|
get last(): Usage;
|
|
710
712
|
get total(): Usage;
|
|
@@ -836,7 +838,10 @@ declare class Agent extends Emitter<AgentEvents> {
|
|
|
836
838
|
/** Run exactly one step. Useful for tests and custom drivers
|
|
837
839
|
* that want to interleave logic between steps. */
|
|
838
840
|
step(): Promise<StepResult>;
|
|
839
|
-
|
|
841
|
+
/** Apply compaction before resolving, or start it without waiting when background is true. */
|
|
842
|
+
compact(opts?: {
|
|
843
|
+
background?: boolean;
|
|
844
|
+
}): Promise<void>;
|
|
840
845
|
/** Resolve when the agent is in a quiescent state — `idle` or
|
|
841
846
|
* `paused`. If a run is currently in flight (or was just kicked off
|
|
842
847
|
* synchronously by `send` / `inject` / a wakeup), waits for it to
|
|
@@ -935,6 +940,9 @@ export declare function formatFileUsage(files: FileUsage[]): string;
|
|
|
935
940
|
type CompactionOptions = {
|
|
936
941
|
enabled: boolean;
|
|
937
942
|
threshold?: number;
|
|
943
|
+
/** Prepare and apply automatic compaction without pausing the foreground loop. */
|
|
944
|
+
backgroundEnabled?: boolean;
|
|
945
|
+
backgroundThreshold?: number;
|
|
938
946
|
/** Existing messages up to this many tokens will be preserved in the context */
|
|
939
947
|
keepTokens: number;
|
|
940
948
|
maxToolResultLen: number;
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":["TokenCount","TokenCount","builtin","TokenCount","TokenCount","builtin"],"sources":["../src/events.ts","../src/masker.ts","../src/permissions/types.ts","../src/permissions/presets.ts","../src/permissions/manager.ts","../src/skills.ts","../src/swarm.ts","../src/ctx.ts","../src/tasks.ts","../src/utils/usage.ts","../src/agent.ts","../src/compaction/utils.ts","../src/compaction/compactions.ts","../src/notify.ts","../src/permissions/handlers/registry.ts","../src/stop.ts","../src/types.ts","../src/prompt/registry.ts","../src/tools/registry.ts","../src/tools/bash.ts","../src/tools/read.ts","../src/tools/edit.ts","../src/tools/fetch.ts","../src/tools/find.ts","../src/tools/grep.ts","../src/tools/write.ts","../src/utils/uuid.ts","../src/commands.ts","../src/context/tokens.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":["TokenCount","TokenCount","builtin","TokenCount","TokenCount","builtin"],"sources":["../src/events.ts","../src/masker.ts","../src/permissions/types.ts","../src/permissions/presets.ts","../src/permissions/manager.ts","../src/skills.ts","../src/swarm.ts","../src/ctx.ts","../src/tasks.ts","../src/utils/usage.ts","../src/agent.ts","../src/compaction/utils.ts","../src/compaction/compactions.ts","../src/notify.ts","../src/permissions/handlers/registry.ts","../src/stop.ts","../src/types.ts","../src/prompt/registry.ts","../src/tools/registry.ts","../src/tools/bash.ts","../src/tools/read.ts","../src/tools/edit.ts","../src/tools/fetch.ts","../src/tools/find.ts","../src/tools/grep.ts","../src/tools/write.ts","../src/utils/uuid.ts","../src/commands.ts","../src/context/tokens.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as extractConversation, c as formatFileUsage, d as Commands, f as toolCollection, g as createAgent, h as promptRegistry, i as extractBashUsage, l as messageTail, m as promptCollection, n as formatTokenStats, o as extractFileUsage, p as toolRegistry, r as tokenStats, s as formatBashUsage, t as estimatePart, u as Skills } from "./src-
|
|
1
|
+
import { a as extractConversation, c as formatFileUsage, d as Commands, f as toolCollection, g as createAgent, h as promptRegistry, i as extractBashUsage, l as messageTail, m as promptCollection, n as formatTokenStats, o as extractFileUsage, p as toolRegistry, r as tokenStats, s as formatBashUsage, t as estimatePart, u as Skills } from "./src-DJoqT9yP.mjs";
|
|
2
2
|
import { t as handlerRegistry } from "./registry-CntkeXlo.mjs";
|
|
3
3
|
import { n as isUuidv7Like, r as uuidv7, t as isUuidv7 } from "./uuid-rfbQ9ad2.mjs";
|
|
4
4
|
export { Commands, Skills, createAgent, estimatePart, extractBashUsage, extractConversation, extractFileUsage, formatBashUsage, formatFileUsage, formatTokenStats, handlerRegistry, isUuidv7, isUuidv7Like, messageTail, promptCollection, promptRegistry, tokenStats, toolCollection, toolRegistry, uuidv7 };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as tokenStats, t as estimatePart } from "./src-
|
|
1
|
+
import { r as tokenStats, t as estimatePart } from "./src-DJoqT9yP.mjs";
|
|
2
2
|
import { safeStringify, toValue } from "@zaly/shared";
|
|
3
3
|
import { isAttachment, safeParseToolParams } from "@zaly/ai";
|
|
4
4
|
// src/context/scoring.ts
|
|
@@ -391,4 +391,4 @@ var Masker = class {
|
|
|
391
391
|
};
|
|
392
392
|
export { Masker };
|
|
393
393
|
|
|
394
|
-
//# sourceMappingURL=masker-
|
|
394
|
+
//# sourceMappingURL=masker-B97uwYXG.mjs.map
|