maestro-agent-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +24 -0
- package/README.md +133 -0
- package/dist/agents/contracts.d.ts +49 -0
- package/dist/agents/contracts.d.ts.map +1 -0
- package/dist/agents/contracts.js +2 -0
- package/dist/agents/contracts.js.map +1 -0
- package/dist/agents/rollout/shared.d.ts +24 -0
- package/dist/agents/rollout/shared.d.ts.map +1 -0
- package/dist/agents/rollout/shared.js +105 -0
- package/dist/agents/rollout/shared.js.map +1 -0
- package/dist/core/agent.d.ts +71 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +22 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/loop.d.ts +26 -0
- package/dist/core/loop.d.ts.map +1 -0
- package/dist/core/loop.js +317 -0
- package/dist/core/loop.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +79 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +176 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/pool-cache.d.ts +103 -0
- package/dist/mcp/pool-cache.d.ts.map +1 -0
- package/dist/mcp/pool-cache.js +249 -0
- package/dist/mcp/pool-cache.js.map +1 -0
- package/dist/mcp/pool.d.ts +65 -0
- package/dist/mcp/pool.d.ts.map +1 -0
- package/dist/mcp/pool.js +86 -0
- package/dist/mcp/pool.js.map +1 -0
- package/dist/media/file-events.d.ts +8 -0
- package/dist/media/file-events.d.ts.map +1 -0
- package/dist/media/file-events.js +15 -0
- package/dist/media/file-events.js.map +1 -0
- package/dist/memory/active-task-template.d.ts +34 -0
- package/dist/memory/active-task-template.d.ts.map +1 -0
- package/dist/memory/active-task-template.js +63 -0
- package/dist/memory/active-task-template.js.map +1 -0
- package/dist/memory/compressor.d.ts +87 -0
- package/dist/memory/compressor.d.ts.map +1 -0
- package/dist/memory/compressor.js +164 -0
- package/dist/memory/compressor.js.map +1 -0
- package/dist/memory/hash.d.ts +17 -0
- package/dist/memory/hash.d.ts.map +1 -0
- package/dist/memory/hash.js +20 -0
- package/dist/memory/hash.js.map +1 -0
- package/dist/memory/prune.d.ts +117 -0
- package/dist/memory/prune.d.ts.map +1 -0
- package/dist/memory/prune.js +416 -0
- package/dist/memory/prune.js.map +1 -0
- package/dist/memory/reminder.d.ts +57 -0
- package/dist/memory/reminder.d.ts.map +1 -0
- package/dist/memory/reminder.js +57 -0
- package/dist/memory/reminder.js.map +1 -0
- package/dist/memory/scrubber.d.ts +28 -0
- package/dist/memory/scrubber.d.ts.map +1 -0
- package/dist/memory/scrubber.js +147 -0
- package/dist/memory/scrubber.js.map +1 -0
- package/dist/memory/token-estimate.d.ts +10 -0
- package/dist/memory/token-estimate.d.ts.map +1 -0
- package/dist/memory/token-estimate.js +69 -0
- package/dist/memory/token-estimate.js.map +1 -0
- package/dist/platform/config.d.ts +12 -0
- package/dist/platform/config.d.ts.map +1 -0
- package/dist/platform/config.js +54 -0
- package/dist/platform/config.js.map +1 -0
- package/dist/platform/jsonl.d.ts +15 -0
- package/dist/platform/jsonl.d.ts.map +1 -0
- package/dist/platform/jsonl.js +80 -0
- package/dist/platform/jsonl.js.map +1 -0
- package/dist/platform/lifecycle.d.ts +22 -0
- package/dist/platform/lifecycle.d.ts.map +1 -0
- package/dist/platform/lifecycle.js +60 -0
- package/dist/platform/lifecycle.js.map +1 -0
- package/dist/platform/logger.d.ts +26 -0
- package/dist/platform/logger.d.ts.map +1 -0
- package/dist/platform/logger.js +41 -0
- package/dist/platform/logger.js.map +1 -0
- package/dist/platform/mcp-config.d.ts +15 -0
- package/dist/platform/mcp-config.d.ts.map +1 -0
- package/dist/platform/mcp-config.js +8 -0
- package/dist/platform/mcp-config.js.map +1 -0
- package/dist/provider.d.ts +81 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +444 -0
- package/dist/provider.js.map +1 -0
- package/dist/providers/anthropic.d.ts +132 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +518 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/base.d.ts +140 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +2 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/deepseek.d.ts +118 -0
- package/dist/providers/deepseek.d.ts.map +1 -0
- package/dist/providers/deepseek.js +467 -0
- package/dist/providers/deepseek.js.map +1 -0
- package/dist/registry.d.ts +3 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +94 -0
- package/dist/registry.js.map +1 -0
- package/dist/session-store.d.ts +133 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +277 -0
- package/dist/session-store.js.map +1 -0
- package/dist/skills/curator.d.ts +104 -0
- package/dist/skills/curator.d.ts.map +1 -0
- package/dist/skills/curator.js +162 -0
- package/dist/skills/curator.js.map +1 -0
- package/dist/skills/index-builder.d.ts +42 -0
- package/dist/skills/index-builder.d.ts.map +1 -0
- package/dist/skills/index-builder.js +94 -0
- package/dist/skills/index-builder.js.map +1 -0
- package/dist/skills/loader.d.ts +107 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +286 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/preprocess.d.ts +45 -0
- package/dist/skills/preprocess.d.ts.map +1 -0
- package/dist/skills/preprocess.js +126 -0
- package/dist/skills/preprocess.js.map +1 -0
- package/dist/skills/usage.d.ts +75 -0
- package/dist/skills/usage.d.ts.map +1 -0
- package/dist/skills/usage.js +147 -0
- package/dist/skills/usage.js.map +1 -0
- package/dist/state/todos.d.ts +95 -0
- package/dist/state/todos.d.ts.map +1 -0
- package/dist/state/todos.js +198 -0
- package/dist/state/todos.js.map +1 -0
- package/dist/storage/conversations.d.ts +28 -0
- package/dist/storage/conversations.d.ts.map +1 -0
- package/dist/storage/conversations.js +8 -0
- package/dist/storage/conversations.js.map +1 -0
- package/dist/sub-agent/runner.d.ts +78 -0
- package/dist/sub-agent/runner.d.ts.map +1 -0
- package/dist/sub-agent/runner.js +215 -0
- package/dist/sub-agent/runner.js.map +1 -0
- package/dist/tools/builtin/agent.d.ts +33 -0
- package/dist/tools/builtin/agent.d.ts.map +1 -0
- package/dist/tools/builtin/agent.js +76 -0
- package/dist/tools/builtin/agent.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts +11 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -0
- package/dist/tools/builtin/bash.js +91 -0
- package/dist/tools/builtin/bash.js.map +1 -0
- package/dist/tools/builtin/edit.d.ts +21 -0
- package/dist/tools/builtin/edit.d.ts.map +1 -0
- package/dist/tools/builtin/edit.js +238 -0
- package/dist/tools/builtin/edit.js.map +1 -0
- package/dist/tools/builtin/read.d.ts +17 -0
- package/dist/tools/builtin/read.d.ts.map +1 -0
- package/dist/tools/builtin/read.js +139 -0
- package/dist/tools/builtin/read.js.map +1 -0
- package/dist/tools/builtin/sandbox.d.ts +16 -0
- package/dist/tools/builtin/sandbox.d.ts.map +1 -0
- package/dist/tools/builtin/sandbox.js +58 -0
- package/dist/tools/builtin/sandbox.js.map +1 -0
- package/dist/tools/builtin/skill_view.d.ts +37 -0
- package/dist/tools/builtin/skill_view.d.ts.map +1 -0
- package/dist/tools/builtin/skill_view.js +82 -0
- package/dist/tools/builtin/skill_view.js.map +1 -0
- package/dist/tools/builtin/todo_write.d.ts +29 -0
- package/dist/tools/builtin/todo_write.d.ts.map +1 -0
- package/dist/tools/builtin/todo_write.js +96 -0
- package/dist/tools/builtin/todo_write.js.map +1 -0
- package/dist/tools/builtin/web_fetch.d.ts +10 -0
- package/dist/tools/builtin/web_fetch.d.ts.map +1 -0
- package/dist/tools/builtin/web_fetch.js +150 -0
- package/dist/tools/builtin/web_fetch.js.map +1 -0
- package/dist/tools/builtin/write.d.ts +35 -0
- package/dist/tools/builtin/write.d.ts.map +1 -0
- package/dist/tools/builtin/write.js +70 -0
- package/dist/tools/builtin/write.js.map +1 -0
- package/dist/tools/file-state.d.ts +99 -0
- package/dist/tools/file-state.d.ts.map +1 -0
- package/dist/tools/file-state.js +133 -0
- package/dist/tools/file-state.js.map +1 -0
- package/dist/tools/hooks/sandbox-fs.d.ts +25 -0
- package/dist/tools/hooks/sandbox-fs.d.ts.map +1 -0
- package/dist/tools/hooks/sandbox-fs.js +48 -0
- package/dist/tools/hooks/sandbox-fs.js.map +1 -0
- package/dist/tools/registry.d.ts +102 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +93 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/types.d.ts +109 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { ProviderMessage } from "../providers/base.js";
|
|
2
|
+
/**
|
|
3
|
+
* Maestro context pruning — token-savings pre-pass with zero LLM calls.
|
|
4
|
+
*
|
|
5
|
+
* Three passes, mirroring upstream Maestro v0.13.0
|
|
6
|
+
* `context_compressor.py::_prune_old_tool_results`. All passes are pure
|
|
7
|
+
* (return a new array; input is not mutated) and zero-LLM.
|
|
8
|
+
*
|
|
9
|
+
* Pass 1 — Tool result dedup.
|
|
10
|
+
* Walks tool_result blocks newest-first. For each block whose content
|
|
11
|
+
* hashes to a value already seen on a later turn, replace it with a
|
|
12
|
+
* back-reference placeholder. The most recent occurrence keeps the full
|
|
13
|
+
* payload — that's what the model needs to act on; older copies waste
|
|
14
|
+
* tokens. md5(content)[:12] (see hash.ts) — non-cryptographic, picked
|
|
15
|
+
* for parity with the Python reference and cost on the per-turn path.
|
|
16
|
+
*
|
|
17
|
+
* Pass 2 — Age-based 1-line summary.
|
|
18
|
+
* For tool_result blocks older than `ageTurnsThreshold` user-turns,
|
|
19
|
+
* replace large content with a structured 1-liner that names the tool,
|
|
20
|
+
* points at the original arguments, and notes size. The model gets a
|
|
21
|
+
* stable cue for "I called X and got back ~N bytes" without paying for
|
|
22
|
+
* the bytes. Recent results (inside the protected tail) stay verbatim so
|
|
23
|
+
* the model can still reason over fresh tool output.
|
|
24
|
+
*
|
|
25
|
+
* Both passes are pure (`messages` not mutated) — caller can freely send the
|
|
26
|
+
* returned array to the provider without losing the canonical history they
|
|
27
|
+
* still need for persistence/resume. Anti-thrashing is module-state-backed
|
|
28
|
+
* (see header on `pruneMessages`) so back-to-back calls on an already-pruned
|
|
29
|
+
* array don't burn cycles.
|
|
30
|
+
*
|
|
31
|
+
* Token savings are estimated by raw character count (not BPE-accurate). The
|
|
32
|
+
* trade-off: char-count is a strict upper bound on dedup/summary savings (a
|
|
33
|
+
* byte you remove was at most one token's worth), provider-agnostic, and
|
|
34
|
+
* available without spinning up a tokenizer. Real Anthropic token reduction
|
|
35
|
+
* is typically 1.1-1.4x the char delta, so this estimator under-reports
|
|
36
|
+
* savings slightly — fine for the anti-thrash threshold (better to over-skip
|
|
37
|
+
* than over-prune).
|
|
38
|
+
*
|
|
39
|
+
* Upstream reference: `/Users/maestrobot/__KEEP_MAESTRO_AGENT__/agent/context_compressor.py:519-685`.
|
|
40
|
+
*/
|
|
41
|
+
export interface PruneOptions {
|
|
42
|
+
/**
|
|
43
|
+
* Tool_result blocks N user-turns or older from the tail get age-summarized
|
|
44
|
+
* by pass 2. Counting in user-turns (not raw messages) matches upstream's
|
|
45
|
+
* notion of "conversation rounds" and avoids fence-posting around assistant
|
|
46
|
+
* + tool_result pairings.
|
|
47
|
+
*
|
|
48
|
+
* Default: 10 — empirically tuned in upstream as the point past which a
|
|
49
|
+
* tool result is rarely re-referenced by the model.
|
|
50
|
+
*/
|
|
51
|
+
ageTurnsThreshold?: number;
|
|
52
|
+
/** Disable pass 1 (dedup). Default: true. */
|
|
53
|
+
dedup?: boolean;
|
|
54
|
+
/** Disable pass 2 (age-based summary). Default: true. */
|
|
55
|
+
summarizeOld?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Pass 3 (JSON-aware tool_use input shrink) — truncate string fields
|
|
58
|
+
* inside `tool_use.input` that exceed `largeArgChars`. Default: true.
|
|
59
|
+
*
|
|
60
|
+
* The model rarely re-references the *exact* bytes it passed to a tool
|
|
61
|
+
* (e.g. 12KB `content` for a Write call) once the call has completed;
|
|
62
|
+
* it just needs to know "I sent ~12KB to Write at <path>". Pass 3
|
|
63
|
+
* replaces oversize string values with `"<truncated N chars>"` so the
|
|
64
|
+
* structural shape is preserved (key names, types) but the payload
|
|
65
|
+
* shrinks dramatically.
|
|
66
|
+
*/
|
|
67
|
+
shrinkLargeToolArgs?: boolean;
|
|
68
|
+
/** Per-string truncation threshold for pass 3 (chars). Default: 800. */
|
|
69
|
+
largeArgChars?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Pass 3 only touches assistant turns older than this many user-turns
|
|
72
|
+
* from the tail (same window pass 2 uses). Default: same as
|
|
73
|
+
* `ageTurnsThreshold` (10).
|
|
74
|
+
*/
|
|
75
|
+
shrinkAgeThreshold?: number;
|
|
76
|
+
/**
|
|
77
|
+
* Anti-thrashing — if two consecutive calls on the same `messages` array
|
|
78
|
+
* reference each save less than 10% of bytes, skip the third call entirely
|
|
79
|
+
* and return the input as-is. Default: true. Disable for tests that exercise
|
|
80
|
+
* single-call behavior in isolation.
|
|
81
|
+
*
|
|
82
|
+
* State is keyed on the array reference (WeakMap). A fresh array starts
|
|
83
|
+
* fresh; the loop's per-turn `messages.push(...)` keeps the same reference
|
|
84
|
+
* so state survives across iterations within one session.
|
|
85
|
+
*/
|
|
86
|
+
antiThrash?: boolean;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Apply pass 1 (dedup) + pass 2 (age-based summary) to a message array.
|
|
90
|
+
*
|
|
91
|
+
* Returns a new array — input `messages` and the inner block arrays are not
|
|
92
|
+
* mutated, so the caller can keep the original around for persistence.
|
|
93
|
+
*
|
|
94
|
+
* `opts.antiThrash` (default on) backs off when consecutive calls on the
|
|
95
|
+
* same array reference don't save enough — useful inside the per-iteration
|
|
96
|
+
* hot path of the agent loop where most turns won't add new prune targets.
|
|
97
|
+
*/
|
|
98
|
+
export declare function pruneMessages(messages: ProviderMessage[], opts?: PruneOptions): ProviderMessage[];
|
|
99
|
+
/**
|
|
100
|
+
* Char-count-based token savings estimate. Negative values are clamped to 0
|
|
101
|
+
* (a no-op pass is "0% savings", not "savings increased").
|
|
102
|
+
*
|
|
103
|
+
* Anthropic tokens-per-char varies (~3.5-4.5 for English, lower for CJK), so
|
|
104
|
+
* this is a deliberately conservative proxy. The anti-thrash check only
|
|
105
|
+
* needs a relative measure, not an absolute one.
|
|
106
|
+
*
|
|
107
|
+
* Exposed for tests so we can assert savings rates without spinning up a
|
|
108
|
+
* tokenizer.
|
|
109
|
+
*/
|
|
110
|
+
export declare function estimateTokenSavings(before: ProviderMessage[], after: ProviderMessage[]): number;
|
|
111
|
+
/** Test-only: reset module-level anti-thrash state. */
|
|
112
|
+
export declare function __resetPruneStateForTests(): void;
|
|
113
|
+
export declare const __MIN_PRUNE_CHARS = 200;
|
|
114
|
+
export declare const __ANTI_THRASH_PCT = 10;
|
|
115
|
+
export declare const __ANTI_THRASH_LIMIT = 2;
|
|
116
|
+
export declare const __ANTI_THRASH_GROWTH_RESET = 4;
|
|
117
|
+
//# sourceMappingURL=prune.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune.d.ts","sourceRoot":"","sources":["../../src/memory/prune.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAwB,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,yDAAyD;IACzD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAiCD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,eAAe,EAAE,EAC3B,IAAI,GAAE,YAAiB,GACtB,eAAe,EAAE,CA+FnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,MAAM,CAIhG;AAED,uDAAuD;AACvD,wBAAgB,yBAAyB,IAAI,IAAI,CAMhD;AA+RD,eAAO,MAAM,iBAAiB,MAAkB,CAAC;AACjD,eAAO,MAAM,iBAAiB,KAAkB,CAAC;AACjD,eAAO,MAAM,mBAAmB,IAAoB,CAAC;AACrD,eAAO,MAAM,0BAA0B,IAA2B,CAAC"}
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import { hashToolContent } from "../memory/hash.js";
|
|
2
|
+
/**
|
|
3
|
+
* Tool_result content must exceed this many chars before either pass touches
|
|
4
|
+
* it. Below this, dedup/summary placeholders would be longer than the
|
|
5
|
+
* original, defeating the purpose. Matches upstream's `if len(content) < 200`
|
|
6
|
+
* guard.
|
|
7
|
+
*/
|
|
8
|
+
const MIN_PRUNE_CHARS = 200;
|
|
9
|
+
/** Anti-thrash trigger — < 10% byte savings counts as "ineffective". */
|
|
10
|
+
const ANTI_THRASH_PCT = 10;
|
|
11
|
+
/** Two consecutive ineffective calls → next call skips. */
|
|
12
|
+
const ANTI_THRASH_LIMIT = 2;
|
|
13
|
+
/**
|
|
14
|
+
* Message-count growth since the latch was set that re-opens prune retries.
|
|
15
|
+
* Without this the short-circuit at the top would latch permanently for the
|
|
16
|
+
* lifetime of the `messages` array reference — every prune attempt past the
|
|
17
|
+
* latch would skip even after the history grew by dozens of new turns that
|
|
18
|
+
* the prior decision never saw. Four new messages ≈ two tool iterations,
|
|
19
|
+
* enough that the model has added a fresh chunk of context worth re-prunes.
|
|
20
|
+
*/
|
|
21
|
+
const ANTI_THRASH_GROWTH_RESET = 4;
|
|
22
|
+
const antiThrashByRef = new WeakMap();
|
|
23
|
+
/**
|
|
24
|
+
* Apply pass 1 (dedup) + pass 2 (age-based summary) to a message array.
|
|
25
|
+
*
|
|
26
|
+
* Returns a new array — input `messages` and the inner block arrays are not
|
|
27
|
+
* mutated, so the caller can keep the original around for persistence.
|
|
28
|
+
*
|
|
29
|
+
* `opts.antiThrash` (default on) backs off when consecutive calls on the
|
|
30
|
+
* same array reference don't save enough — useful inside the per-iteration
|
|
31
|
+
* hot path of the agent loop where most turns won't add new prune targets.
|
|
32
|
+
*/
|
|
33
|
+
export function pruneMessages(messages, opts = {}) {
|
|
34
|
+
const { ageTurnsThreshold = 10, dedup = true, summarizeOld = true, shrinkLargeToolArgs = true, largeArgChars = 800, shrinkAgeThreshold = ageTurnsThreshold, antiThrash = true, } = opts;
|
|
35
|
+
if (messages.length === 0)
|
|
36
|
+
return messages;
|
|
37
|
+
// Anti-thrash short-circuit BEFORE we do any work — but break the latch
|
|
38
|
+
// when the history has grown by enough new turns that the prior "no
|
|
39
|
+
// savings here" decision is stale.
|
|
40
|
+
if (antiThrash) {
|
|
41
|
+
const st = antiThrashByRef.get(messages);
|
|
42
|
+
if (st && st.ineffectiveCount >= ANTI_THRASH_LIMIT) {
|
|
43
|
+
const grown = st.latchedAtLength !== undefined &&
|
|
44
|
+
messages.length >= st.latchedAtLength + ANTI_THRASH_GROWTH_RESET;
|
|
45
|
+
if (!grown)
|
|
46
|
+
return messages;
|
|
47
|
+
// Significant growth — invalidate latch, retry the prune path.
|
|
48
|
+
st.ineffectiveCount = 0;
|
|
49
|
+
st.latchedAtLength = undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Build a tool_use_id -> {name, args} index from every assistant turn so
|
|
53
|
+
// pass 2 can render `[<tool_name>] ... (Nchars)` lines. We index the WHOLE
|
|
54
|
+
// history (not just the recent tail) because pass 2 targets the older end.
|
|
55
|
+
const callIndex = buildToolCallIndex(messages);
|
|
56
|
+
// Compute the prune boundary — the index in `messages` at which pass 2
|
|
57
|
+
// starts considering tool_result blocks for summarization. We count
|
|
58
|
+
// user-role messages (excluding tool_result-only turns? no — every
|
|
59
|
+
// tool_result turn IS a user message, so user turns include both the
|
|
60
|
+
// freshly-typed prompts and the synthesized tool_result wrappers) from
|
|
61
|
+
// the tail. `ageTurnsThreshold` user-turns or fewer from the end are
|
|
62
|
+
// protected.
|
|
63
|
+
const protectedFromIdx = computeProtectedBoundary(messages, ageTurnsThreshold);
|
|
64
|
+
// ----------------------- Pass 1: dedup -----------------------
|
|
65
|
+
// Walk newest -> oldest. First occurrence of each content hash is kept;
|
|
66
|
+
// subsequent (older) occurrences become back-references.
|
|
67
|
+
let pruned = messages;
|
|
68
|
+
if (dedup) {
|
|
69
|
+
pruned = applyDedup(messages);
|
|
70
|
+
}
|
|
71
|
+
// ----------------------- Pass 2: summarize -----------------------
|
|
72
|
+
if (summarizeOld && protectedFromIdx > 0) {
|
|
73
|
+
pruned = applyAgeSummary(pruned, protectedFromIdx, callIndex);
|
|
74
|
+
}
|
|
75
|
+
// ----------------------- Pass 3: tool_use arg shrink -----------------------
|
|
76
|
+
// Runs on the same age window as pass 2. Cheap structural rewrite that
|
|
77
|
+
// also helps before-aux-LLM compaction: a Write tool call with 50KB
|
|
78
|
+
// content can dominate the wire bytes even when its tool_result is
|
|
79
|
+
// already deduped.
|
|
80
|
+
if (shrinkLargeToolArgs && protectedFromIdx > 0) {
|
|
81
|
+
const shrinkBoundary = shrinkAgeThreshold === ageTurnsThreshold
|
|
82
|
+
? protectedFromIdx
|
|
83
|
+
: computeProtectedBoundary(messages, shrinkAgeThreshold);
|
|
84
|
+
if (shrinkBoundary > 0) {
|
|
85
|
+
pruned = applyToolArgShrink(pruned, shrinkBoundary, largeArgChars);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ----------------------- Anti-thrash bookkeeping -----------------------
|
|
89
|
+
if (antiThrash) {
|
|
90
|
+
const beforeBytes = estimateBytes(messages);
|
|
91
|
+
const afterBytes = estimateBytes(pruned);
|
|
92
|
+
const savings = beforeBytes - afterBytes;
|
|
93
|
+
const pct = beforeBytes > 0 ? (savings / beforeBytes) * 100 : 0;
|
|
94
|
+
const st = antiThrashByRef.get(messages) ?? { ineffectiveCount: 0 };
|
|
95
|
+
if (pct < ANTI_THRASH_PCT) {
|
|
96
|
+
st.ineffectiveCount++;
|
|
97
|
+
// Record the messages.length at the moment we first latch so the
|
|
98
|
+
// growth-reset check above has an anchor to compare against. Set only
|
|
99
|
+
// on the transition into latched state; subsequent ineffective calls
|
|
100
|
+
// past the limit don't move the anchor forward.
|
|
101
|
+
if (st.ineffectiveCount >= ANTI_THRASH_LIMIT && st.latchedAtLength === undefined) {
|
|
102
|
+
st.latchedAtLength = messages.length;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
st.ineffectiveCount = 0;
|
|
107
|
+
st.latchedAtLength = undefined;
|
|
108
|
+
}
|
|
109
|
+
antiThrashByRef.set(messages, st);
|
|
110
|
+
}
|
|
111
|
+
return pruned;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Char-count-based token savings estimate. Negative values are clamped to 0
|
|
115
|
+
* (a no-op pass is "0% savings", not "savings increased").
|
|
116
|
+
*
|
|
117
|
+
* Anthropic tokens-per-char varies (~3.5-4.5 for English, lower for CJK), so
|
|
118
|
+
* this is a deliberately conservative proxy. The anti-thrash check only
|
|
119
|
+
* needs a relative measure, not an absolute one.
|
|
120
|
+
*
|
|
121
|
+
* Exposed for tests so we can assert savings rates without spinning up a
|
|
122
|
+
* tokenizer.
|
|
123
|
+
*/
|
|
124
|
+
export function estimateTokenSavings(before, after) {
|
|
125
|
+
const b = estimateBytes(before);
|
|
126
|
+
const a = estimateBytes(after);
|
|
127
|
+
return Math.max(0, b - a);
|
|
128
|
+
}
|
|
129
|
+
/** Test-only: reset module-level anti-thrash state. */
|
|
130
|
+
export function __resetPruneStateForTests() {
|
|
131
|
+
// WeakMap has no .clear() — replace by emptying via reassignment of every
|
|
132
|
+
// tracked entry. In practice tests just create fresh arrays.
|
|
133
|
+
// We deliberately don't expose a hard clear because production callers
|
|
134
|
+
// shouldn't reach into module state; the WeakMap GC-friendly design is the
|
|
135
|
+
// point. Tests that need isolation should create fresh arrays.
|
|
136
|
+
}
|
|
137
|
+
function buildToolCallIndex(messages) {
|
|
138
|
+
const idx = new Map();
|
|
139
|
+
for (const msg of messages) {
|
|
140
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.content))
|
|
141
|
+
continue;
|
|
142
|
+
for (const block of msg.content) {
|
|
143
|
+
if (block.type === "tool_use") {
|
|
144
|
+
idx.set(block.id, { name: block.name, input: block.input });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return idx;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Translate `ageTurnsThreshold` (user-turn count) into a message-array index
|
|
152
|
+
* such that messages at indices >= the returned value are within the
|
|
153
|
+
* protected tail. Returns 0 if the whole history fits in the protected tail
|
|
154
|
+
* (so pass 2 does nothing).
|
|
155
|
+
*/
|
|
156
|
+
function computeProtectedBoundary(messages, ageTurnsThreshold) {
|
|
157
|
+
let userTurnsSeen = 0;
|
|
158
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
159
|
+
if (messages[i].role === "user") {
|
|
160
|
+
userTurnsSeen++;
|
|
161
|
+
if (userTurnsSeen > ageTurnsThreshold) {
|
|
162
|
+
return i + 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Pass 1 — newest-first dedup of tool_result content blocks.
|
|
170
|
+
*
|
|
171
|
+
* Only string-content tool_result blocks >= MIN_PRUNE_CHARS participate.
|
|
172
|
+
* Multimodal / structured content is left alone (no safe hash strategy
|
|
173
|
+
* matching upstream's behavior here either).
|
|
174
|
+
*/
|
|
175
|
+
function applyDedup(messages) {
|
|
176
|
+
const seenHashes = new Set();
|
|
177
|
+
const out = messages.map((m) => m);
|
|
178
|
+
// Walk newest -> oldest so the newest copy of each hash survives.
|
|
179
|
+
for (let i = out.length - 1; i >= 0; i--) {
|
|
180
|
+
const msg = out[i];
|
|
181
|
+
if (msg.role !== "user" || !Array.isArray(msg.content))
|
|
182
|
+
continue;
|
|
183
|
+
let mutated = false;
|
|
184
|
+
const newBlocks = msg.content.map((block) => {
|
|
185
|
+
if (block.type !== "tool_result")
|
|
186
|
+
return block;
|
|
187
|
+
const c = block.content;
|
|
188
|
+
if (typeof c !== "string")
|
|
189
|
+
return block;
|
|
190
|
+
if (c.length < MIN_PRUNE_CHARS)
|
|
191
|
+
return block;
|
|
192
|
+
// Skip blocks that are already a previous pass's placeholder so the
|
|
193
|
+
// anti-thrash measurement doesn't double-count.
|
|
194
|
+
if (c.startsWith("[Duplicate tool output"))
|
|
195
|
+
return block;
|
|
196
|
+
const h = hashToolContent(c);
|
|
197
|
+
if (seenHashes.has(h)) {
|
|
198
|
+
mutated = true;
|
|
199
|
+
return {
|
|
200
|
+
type: "tool_result",
|
|
201
|
+
tool_use_id: block.tool_use_id,
|
|
202
|
+
content: `[Duplicate tool output — same content as a more recent call, hash=${h}]`,
|
|
203
|
+
...(block.is_error !== undefined ? { is_error: block.is_error } : {}),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
seenHashes.add(h);
|
|
207
|
+
return block;
|
|
208
|
+
});
|
|
209
|
+
if (mutated) {
|
|
210
|
+
out[i] = { role: msg.role, content: newBlocks };
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Pass 2 — replace tool_result content older than the protect boundary with
|
|
217
|
+
* a structured 1-line summary that points at the original tool_use.
|
|
218
|
+
*
|
|
219
|
+
* Skips:
|
|
220
|
+
* - Non-string content (multimodal etc.)
|
|
221
|
+
* - Content already below MIN_PRUNE_CHARS (savings would be negative)
|
|
222
|
+
* - Content that already looks like a pass-1 dedup placeholder
|
|
223
|
+
* - Content that already looks like our own pass-2 summary (idempotent)
|
|
224
|
+
*/
|
|
225
|
+
function applyAgeSummary(messages, protectedFromIdx, callIndex) {
|
|
226
|
+
const out = messages.map((m) => m);
|
|
227
|
+
for (let i = 0; i < protectedFromIdx; i++) {
|
|
228
|
+
const msg = out[i];
|
|
229
|
+
if (msg.role !== "user" || !Array.isArray(msg.content))
|
|
230
|
+
continue;
|
|
231
|
+
let mutated = false;
|
|
232
|
+
const newBlocks = msg.content.map((block) => {
|
|
233
|
+
if (block.type !== "tool_result")
|
|
234
|
+
return block;
|
|
235
|
+
const c = block.content;
|
|
236
|
+
if (typeof c !== "string")
|
|
237
|
+
return block;
|
|
238
|
+
if (c.length < MIN_PRUNE_CHARS)
|
|
239
|
+
return block;
|
|
240
|
+
if (c.startsWith("[Duplicate tool output"))
|
|
241
|
+
return block;
|
|
242
|
+
if (c.startsWith("[Summarized:"))
|
|
243
|
+
return block;
|
|
244
|
+
const ref = callIndex.get(block.tool_use_id);
|
|
245
|
+
const summary = summarizeToolResult(ref, c);
|
|
246
|
+
mutated = true;
|
|
247
|
+
return {
|
|
248
|
+
type: "tool_result",
|
|
249
|
+
tool_use_id: block.tool_use_id,
|
|
250
|
+
content: summary,
|
|
251
|
+
...(block.is_error !== undefined ? { is_error: block.is_error } : {}),
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
if (mutated) {
|
|
255
|
+
out[i] = { role: msg.role, content: newBlocks };
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return out;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Render a 1-line summary of a tool result. Mirrors upstream's
|
|
262
|
+
* `_summarize_tool_result` shape but doesn't enumerate every tool name —
|
|
263
|
+
* the prefix "[Summarized:" lets us cheaply detect already-summarized
|
|
264
|
+
* blocks on a re-pass, and the (name, lines, chars) tuple is the same set
|
|
265
|
+
* of breadcrumbs the model uses to decide "did I see this before".
|
|
266
|
+
*
|
|
267
|
+
* If `ref` is missing (tool_use was trimmed away by an earlier compression
|
|
268
|
+
* or rollout) we fall back to a generic shape — better to lose tool-name
|
|
269
|
+
* fidelity than to leave several KB of stale tool output in the prompt.
|
|
270
|
+
*/
|
|
271
|
+
function summarizeToolResult(ref, content) {
|
|
272
|
+
const lineCount = content.split("\n").length;
|
|
273
|
+
const tool = ref?.name ?? "tool";
|
|
274
|
+
// Short argument hint helps the model recognize repeat calls. We cap at
|
|
275
|
+
// 80 chars total to stay well under the original payload size — anything
|
|
276
|
+
// longer defeats the purpose of summarization.
|
|
277
|
+
const argHint = ref ? formatArgHint(ref.input) : "";
|
|
278
|
+
const head = head80(content);
|
|
279
|
+
return `[Summarized: ${tool}${argHint} — ${lineCount} lines, ${content.length} chars, head: ${JSON.stringify(head)}]`;
|
|
280
|
+
}
|
|
281
|
+
/** First 80 chars of the content, single-line (newlines collapsed to spaces). */
|
|
282
|
+
function head80(s) {
|
|
283
|
+
const flat = s.replace(/\s+/g, " ").trim();
|
|
284
|
+
return flat.length > 80 ? `${flat.slice(0, 77)}...` : flat;
|
|
285
|
+
}
|
|
286
|
+
/** A compact "k1=v1 k2=v2" hint, capped so a giant args object doesn't blow
|
|
287
|
+
* up the summary line. */
|
|
288
|
+
function formatArgHint(input) {
|
|
289
|
+
const entries = Object.entries(input).slice(0, 2);
|
|
290
|
+
if (entries.length === 0)
|
|
291
|
+
return "";
|
|
292
|
+
const parts = [];
|
|
293
|
+
for (const [k, v] of entries) {
|
|
294
|
+
const s = typeof v === "string" ? v : JSON.stringify(v);
|
|
295
|
+
const trimmed = s.length > 30 ? `${s.slice(0, 27)}...` : s;
|
|
296
|
+
parts.push(`${k}=${trimmed}`);
|
|
297
|
+
}
|
|
298
|
+
return ` ${parts.join(" ")}`;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Pass 3 — Replace oversize string values inside `tool_use.input` with a
|
|
302
|
+
* `"<truncated N chars>"` placeholder. Only touches assistant turns at
|
|
303
|
+
* indices < `boundaryIdx` (older than the protected tail), and only string
|
|
304
|
+
* values longer than `largeArgChars`. Nested objects/arrays are walked
|
|
305
|
+
* recursively so a `{patches: [{content: "<50KB>"}]}` shape gets caught.
|
|
306
|
+
*
|
|
307
|
+
* The model rarely needs to re-read the exact bytes it sent to a Write/Edit
|
|
308
|
+
* call once that turn is closed — knowing the structural shape + a head
|
|
309
|
+
* preview is enough for "did I call this with the same args?" recognition.
|
|
310
|
+
* Aggressive on the dollar value (one Write call's `content` field can
|
|
311
|
+
* dwarf an entire turn's text), cheap on cycles (no LLM, no parsing).
|
|
312
|
+
*/
|
|
313
|
+
function applyToolArgShrink(messages, boundaryIdx, largeArgChars) {
|
|
314
|
+
// Already-shrunk inputs leave a sentinel string starting with this prefix
|
|
315
|
+
// so we don't double-process on a re-pass. Idempotent rewrites are
|
|
316
|
+
// critical inside the hot loop.
|
|
317
|
+
const SENTINEL = "<truncated ";
|
|
318
|
+
function shrinkValue(v) {
|
|
319
|
+
if (typeof v === "string") {
|
|
320
|
+
if (v.length <= largeArgChars)
|
|
321
|
+
return v;
|
|
322
|
+
if (v.startsWith(SENTINEL))
|
|
323
|
+
return v; // already truncated on a prior pass
|
|
324
|
+
return `${SENTINEL}${v.length} chars, head: ${JSON.stringify(v.slice(0, 60))}>`;
|
|
325
|
+
}
|
|
326
|
+
if (Array.isArray(v)) {
|
|
327
|
+
let mutated = false;
|
|
328
|
+
const out = v.map((el) => {
|
|
329
|
+
const next = shrinkValue(el);
|
|
330
|
+
if (next !== el)
|
|
331
|
+
mutated = true;
|
|
332
|
+
return next;
|
|
333
|
+
});
|
|
334
|
+
return mutated ? out : v;
|
|
335
|
+
}
|
|
336
|
+
if (v && typeof v === "object") {
|
|
337
|
+
let mutated = false;
|
|
338
|
+
const out = {};
|
|
339
|
+
for (const [k, val] of Object.entries(v)) {
|
|
340
|
+
const next = shrinkValue(val);
|
|
341
|
+
out[k] = next;
|
|
342
|
+
if (next !== val)
|
|
343
|
+
mutated = true;
|
|
344
|
+
}
|
|
345
|
+
return mutated ? out : v;
|
|
346
|
+
}
|
|
347
|
+
return v;
|
|
348
|
+
}
|
|
349
|
+
let messagesMutated = false;
|
|
350
|
+
const out = messages.map((msg, idx) => {
|
|
351
|
+
if (idx >= boundaryIdx)
|
|
352
|
+
return msg;
|
|
353
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.content))
|
|
354
|
+
return msg;
|
|
355
|
+
let blockMutated = false;
|
|
356
|
+
const nextBlocks = msg.content.map((block) => {
|
|
357
|
+
if (block.type !== "tool_use")
|
|
358
|
+
return block;
|
|
359
|
+
const shrunkInput = shrinkValue(block.input);
|
|
360
|
+
if (shrunkInput === block.input)
|
|
361
|
+
return block;
|
|
362
|
+
blockMutated = true;
|
|
363
|
+
return { ...block, input: shrunkInput };
|
|
364
|
+
});
|
|
365
|
+
if (!blockMutated)
|
|
366
|
+
return msg;
|
|
367
|
+
messagesMutated = true;
|
|
368
|
+
return { role: msg.role, content: nextBlocks };
|
|
369
|
+
});
|
|
370
|
+
return messagesMutated ? out : messages;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Char-count proxy for token usage. Walks every message's content (string
|
|
374
|
+
* shortcut + per-block fields for arrays) and returns the total.
|
|
375
|
+
*/
|
|
376
|
+
function estimateBytes(messages) {
|
|
377
|
+
let total = 0;
|
|
378
|
+
for (const msg of messages) {
|
|
379
|
+
if (typeof msg.content === "string") {
|
|
380
|
+
total += msg.content.length;
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
if (!Array.isArray(msg.content))
|
|
384
|
+
continue;
|
|
385
|
+
for (const block of msg.content) {
|
|
386
|
+
total += blockBytes(block);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return total;
|
|
390
|
+
}
|
|
391
|
+
function blockBytes(block) {
|
|
392
|
+
switch (block.type) {
|
|
393
|
+
case "text":
|
|
394
|
+
return block.text.length;
|
|
395
|
+
case "tool_result":
|
|
396
|
+
return typeof block.content === "string" ? block.content.length : 0;
|
|
397
|
+
case "tool_use":
|
|
398
|
+
// Stringify the input cheaply — the model pays for it on the wire as
|
|
399
|
+
// serialized JSON. Edge: a giant object weighed in megabytes would
|
|
400
|
+
// dominate, which is exactly the case we want to capture.
|
|
401
|
+
try {
|
|
402
|
+
return JSON.stringify(block.input).length;
|
|
403
|
+
}
|
|
404
|
+
catch {
|
|
405
|
+
return 0;
|
|
406
|
+
}
|
|
407
|
+
default:
|
|
408
|
+
return 0;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
// Internal exports for tests.
|
|
412
|
+
export const __MIN_PRUNE_CHARS = MIN_PRUNE_CHARS;
|
|
413
|
+
export const __ANTI_THRASH_PCT = ANTI_THRASH_PCT;
|
|
414
|
+
export const __ANTI_THRASH_LIMIT = ANTI_THRASH_LIMIT;
|
|
415
|
+
export const __ANTI_THRASH_GROWTH_RESET = ANTI_THRASH_GROWTH_RESET;
|
|
416
|
+
//# sourceMappingURL=prune.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune.js","sourceRoot":"","sources":["../../src/memory/prune.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { TodoEntry } from "../state/todos.js";
|
|
2
|
+
/**
|
|
3
|
+
* System-reminder builder.
|
|
4
|
+
*
|
|
5
|
+
* Renders the `<system-reminder>…</system-reminder>` block that gets
|
|
6
|
+
* attached to every new user message in `maestroProvider`. The reminder
|
|
7
|
+
* carries invariants the model needs to keep in mind for the current turn
|
|
8
|
+
* — sandbox state, workspace root, future: active task — and is what keeps
|
|
9
|
+
* long sessions from forgetting the rules after the compactor evicts the
|
|
10
|
+
* middle.
|
|
11
|
+
*
|
|
12
|
+
* Why this lives outside `loop.ts`:
|
|
13
|
+
*
|
|
14
|
+
* The reminder is attached to the canonical user message at push time
|
|
15
|
+
* (see `maestroProvider`), not on-wire just before each API call. That
|
|
16
|
+
* choice is load-bearing for Anthropic's automatic prompt cache: every
|
|
17
|
+
* past-turn user message must be byte-stable across future calls or the
|
|
18
|
+
* cache misses at the first divergence. On-wire injection would mean
|
|
19
|
+
* turn N's user message looks different in turn N's call vs turn N+1's
|
|
20
|
+
* call, breaking the cache from that point onward. By attaching at
|
|
21
|
+
* push time, each historical user message permanently carries the
|
|
22
|
+
* reminder that was live at that turn — frozen, cache-friendly.
|
|
23
|
+
*
|
|
24
|
+
* Placement: reminder text block follows the user prompt block. Claude
|
|
25
|
+
* Code's transcripts consistently place `<system-reminder>` at the tail
|
|
26
|
+
* of user content, and matching that order keeps the model's pretrained
|
|
27
|
+
* instinct ("the user said X; the reminder is meta") intact.
|
|
28
|
+
*/
|
|
29
|
+
export interface SystemReminderContext {
|
|
30
|
+
/**
|
|
31
|
+
* Resolved maestro session id. Surfaced so the model can refer to it in
|
|
32
|
+
* cross-session tool calls (ask_session, tell_session) without re-asking.
|
|
33
|
+
*/
|
|
34
|
+
sessionId: string;
|
|
35
|
+
/**
|
|
36
|
+
* Current TodoWrite list snapshot. When non-empty, the reminder renders
|
|
37
|
+
* a compact status header so the model carries the plan across turns
|
|
38
|
+
* without having to call a read-side tool. The list is the read-side —
|
|
39
|
+
* `todo_write` is the only related tool the model sees.
|
|
40
|
+
*/
|
|
41
|
+
todos?: readonly TodoEntry[];
|
|
42
|
+
/**
|
|
43
|
+
* Anything additional the caller wants to render verbatim. Each entry
|
|
44
|
+
* becomes one line at the tail of the reminder. Caller owns formatting.
|
|
45
|
+
*/
|
|
46
|
+
extras?: string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build the `<system-reminder>` block. Returns a self-contained string that
|
|
50
|
+
* callers attach verbatim as a `text` content block on a user message.
|
|
51
|
+
*
|
|
52
|
+
* Empty extras + sandbox-enabled (default) state renders to ~3 lines so
|
|
53
|
+
* the per-turn token cost is bounded; the catalog of facts only grows as
|
|
54
|
+
* later phases add semantic state (Phase 3.2 task list, etc.).
|
|
55
|
+
*/
|
|
56
|
+
export declare function buildSystemReminder(ctx: SystemReminderContext): string;
|
|
57
|
+
//# sourceMappingURL=reminder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reminder.d.ts","sourceRoot":"","sources":["../../src/memory/reminder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC7B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,qBAAqB,GAAG,MAAM,CA8CtE"}
|