@wrongstack/core 0.306.3 → 0.307.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.
Files changed (114) hide show
  1. package/dist/chronicle/index.js +957 -953
  2. package/dist/chronicle/metrics-ingest.d.ts +55 -0
  3. package/dist/chronicle/metrics-schema.d.ts +86 -0
  4. package/dist/chronicle/metrics-store.d.ts +5 -120
  5. package/dist/chronicle/project-server.js +1083 -1084
  6. package/dist/chronicle/sqlite-journal-quota.d.ts +39 -0
  7. package/dist/chronicle/sqlite-journal-schema.d.ts +25 -0
  8. package/dist/chronicle/sqlite-journal.d.ts +12 -177
  9. package/dist/coordination/agents/index.js +1738 -1690
  10. package/dist/coordination/agents/project-agent-capture.d.ts +48 -0
  11. package/dist/coordination/agents/project-agent-identity.d.ts +3 -129
  12. package/dist/coordination/agents/project-agent-roster.d.ts +17 -0
  13. package/dist/coordination/index.js +6103 -5890
  14. package/dist/coordination/mailbox-http-actor-query.d.ts +16 -0
  15. package/dist/coordination/mailbox-http-router.d.ts +0 -48
  16. package/dist/coordination/mailbox-http-sse.d.ts +12 -0
  17. package/dist/coordination/mailbox-message-types.d.ts +71 -0
  18. package/dist/coordination/mailbox-predicates.d.ts +13 -0
  19. package/dist/coordination/mailbox-project-server.js +1 -1
  20. package/dist/coordination/mailbox-session-sync.d.ts +8 -0
  21. package/dist/coordination/mailbox-types.d.ts +6 -793
  22. package/dist/core/agent-loop-context.d.ts +28 -0
  23. package/dist/core/agent-loop-detector.d.ts +25 -0
  24. package/dist/core/conversation-state.d.ts +1 -2
  25. package/dist/core/fallback-doctor.d.ts +72 -0
  26. package/dist/core/fallback-model.d.ts +19 -1
  27. package/dist/core/fallback-profile-manager.d.ts +21 -3
  28. package/dist/core/index.d.ts +2 -1
  29. package/dist/core/index.js +1143 -766
  30. package/dist/defaults/index.js +3833 -3595
  31. package/dist/execution/auto-compaction-middleware.d.ts +64 -0
  32. package/dist/execution/autonomy-brain-llm.d.ts +55 -0
  33. package/dist/execution/autonomy-brain.d.ts +3 -156
  34. package/dist/execution/compaction-budget.d.ts +38 -0
  35. package/dist/execution/compaction-core.d.ts +3 -166
  36. package/dist/execution/compaction-elision.d.ts +58 -0
  37. package/dist/execution/council-orchestrator-helpers.d.ts +39 -0
  38. package/dist/execution/council-orchestrator.d.ts +3 -42
  39. package/dist/execution/council-response-parser.d.ts +56 -0
  40. package/dist/execution/index.d.ts +1 -1
  41. package/dist/execution/index.js +10016 -9903
  42. package/dist/execution/prompt-enhancer.js +11 -3
  43. package/dist/execution/retry-policy.d.ts +27 -0
  44. package/dist/execution/tool-executor-guard.d.ts +18 -0
  45. package/dist/execution/tool-executor-runner.d.ts +12 -0
  46. package/dist/execution/tool-executor.d.ts +0 -75
  47. package/dist/goal/index.js +19 -6
  48. package/dist/hq/index.js +58 -17
  49. package/dist/index.d.ts +2 -1
  50. package/dist/index.js +8731 -7756
  51. package/dist/infrastructure/index.js +24 -1
  52. package/dist/kernel/events/agent-events.d.ts +2 -0
  53. package/dist/kernel/events/provider-events.d.ts +13 -0
  54. package/dist/plugin/index.js +2123 -1918
  55. package/dist/plugins/auto-review-config.d.ts +53 -0
  56. package/dist/plugins/auto-review-git.d.ts +19 -0
  57. package/dist/plugins/auto-review-plugin.d.ts +2 -140
  58. package/dist/plugins/review-finding-verification.d.ts +7 -0
  59. package/dist/prompts/index.d.ts +1 -0
  60. package/dist/prompts/prompt-journal.d.ts +94 -0
  61. package/dist/security/index.js +677 -667
  62. package/dist/security/permission-explain.d.ts +19 -0
  63. package/dist/security/permission-policy.d.ts +0 -101
  64. package/dist/security/yolo-risk.d.ts +5 -4
  65. package/dist/session-catalog/index.js +270 -227
  66. package/dist/session-catalog/project-server.js +277 -234
  67. package/dist/session-catalog/store-rebuild.d.ts +9 -0
  68. package/dist/session-catalog/store-schema.d.ts +48 -0
  69. package/dist/session-catalog/store.d.ts +0 -17
  70. package/dist/storage/cloud-config-sync/sanitize.d.ts +18 -0
  71. package/dist/storage/cloud-config-sync.d.ts +1 -1
  72. package/dist/storage/director-state.d.ts +6 -0
  73. package/dist/storage/file-session-writer.d.ts +2 -58
  74. package/dist/storage/index.d.ts +2 -1
  75. package/dist/storage/index.js +2121 -1736
  76. package/dist/storage/orphan-lock-cleaner.d.ts +15 -0
  77. package/dist/storage/provider-config-watcher.d.ts +9 -0
  78. package/dist/storage/session-recovery.d.ts +9 -0
  79. package/dist/storage/session-store/rename-session.d.ts +16 -0
  80. package/dist/storage/session-store/resume-session.d.ts +26 -0
  81. package/dist/storage/session-store/session-store-clear.d.ts +11 -0
  82. package/dist/storage/session-store/session-store-index.d.ts +13 -0
  83. package/dist/storage/session-store/strict-empty-check.d.ts +7 -0
  84. package/dist/storage/session-store.d.ts +2 -129
  85. package/dist/storage/session-summary-tracker.d.ts +39 -0
  86. package/dist/storage/session-write-buffer.d.ts +43 -0
  87. package/dist/storage/session-writer/session-writer-flush.d.ts +4 -0
  88. package/dist/storage/session-writer/session-writer-summary-tracker.d.ts +28 -0
  89. package/dist/tools/fallback-agent-model-assign-tool.d.ts +18 -0
  90. package/dist/tools/fallback-leader-model-set-tool.d.ts +18 -0
  91. package/dist/tools/fallback-manage-tools.d.ts +8 -45
  92. package/dist/tools/fallback-profile-manage-tool.d.ts +16 -0
  93. package/dist/tools/fallback-provider-key-set-tool.d.ts +17 -0
  94. package/dist/tools/fallback-provider-manage-tool.d.ts +26 -0
  95. package/dist/tools/index.d.ts +1 -1
  96. package/dist/tools/index.js +5150 -5090
  97. package/dist/types/config/root.d.ts +21 -2
  98. package/dist/types/default-config.d.ts +1 -1
  99. package/dist/types/index.d.ts +54 -55
  100. package/dist/types/index.js +953 -932
  101. package/dist/types/runtime-capability-manifest.d.ts +5 -5
  102. package/dist/types/session-markers.d.ts +12 -0
  103. package/dist/types/session-markers.js +19 -0
  104. package/dist/types/session.d.ts +7 -0
  105. package/dist/worktree/worktree-manager.d.ts +1 -1
  106. package/instructions/coordination/subagent-baseline.md +2 -2
  107. package/instructions/llm/prompt-enhancer.md +2 -1
  108. package/instructions/sections/tool/common-patterns.md +21 -0
  109. package/instructions/sections/tool/delegation-compact.md +3 -1
  110. package/instructions/sections/tool/delegation-full.md +5 -1
  111. package/instructions/system-lite.md +28 -3
  112. package/instructions/system-pro.md +37 -8
  113. package/instructions/system.md +4 -2
  114. package/package.json +5 -5
@@ -78,8 +78,19 @@ export declare class AutoCompactionMiddleware {
78
78
  * 1 / 2.5 = 0.4.
79
79
  */
80
80
  private static readonly GUARD_GATE_LOAD;
81
+ /**
82
+ * How much the context must grow between two history-rewriting hygiene
83
+ * passes, as a fraction of the available input window and as an absolute
84
+ * floor. Every pass rewrites already-transmitted messages, which forces the
85
+ * provider to re-cache the whole prompt; spacing the passes out is what lets
86
+ * the conversation prefix stay cached for the turns in between.
87
+ */
88
+ private static readonly HYGIENE_GROWTH_RATIO;
89
+ private static readonly HYGIENE_MIN_GROWTH_TOKENS;
81
90
  /** Tracks the most recent no-op attempt so we can avoid re-firing per turn. */
82
91
  private lastNoopAttempt;
92
+ /** Context size at the last hygiene pass; anchors the growth interval. */
93
+ private lastHygieneTokens;
83
94
  /**
84
95
  * Cached token estimate from the last handler() invocation. When the
85
96
  * message count and tool count haven't changed since the last estimate
@@ -128,6 +139,59 @@ export declare class AutoCompactionMiddleware {
128
139
  * tokens or compacting. */
129
140
  setEnabled(enabled: boolean): void;
130
141
  handler(): MiddlewareHandler<Context>;
142
+ /**
143
+ * Full-request token total for the current context.
144
+ *
145
+ * Reuses the last estimate when the context hasn't grown since the previous
146
+ * check — common in autonomous idle loops. The cached value is invalidated
147
+ * whenever messages or tools change.
148
+ *
149
+ * IMPORTANT: the cache is only valid for the deterministic
150
+ * `estimateRequestTokensCalibrated` path (messages+system+tools → fixed
151
+ * output). When a custom `_estimator` is provided (e.g. in tests with a
152
+ * mutable closure, or a dynamic policy provider), always call it fresh — the
153
+ * estimator owns its own semantics and the middleware cannot safely cache its
154
+ * result across calls.
155
+ */
156
+ private estimateContextTokens;
157
+ /**
158
+ * Never-undercount send guard.
159
+ *
160
+ * The calibrated estimate can under-count dense content (CJK, base64,
161
+ * minified) by >1.5×, which would let an over-limit request slip past the
162
+ * thresholds and reach the provider. Once the calibrated load is high enough
163
+ * that even the max density factor (2.5×) *could* overflow (load ≥ 1/2.5 =
164
+ * 0.4), re-check with the upper-bound estimator and escalate to whichever
165
+ * load is larger. Below 0.4 an overflow is arithmetically impossible, so the
166
+ * extra scan is skipped.
167
+ */
168
+ private applySendGuard;
169
+ /**
170
+ * Rewrite acknowledged tool protocol in place.
171
+ *
172
+ * Tool results are protocol inputs for the immediately following model
173
+ * response, not unlimited durable prompt memory. Once a later assistant
174
+ * message proves the provider consumed them, keep a mode-sized raw window and
175
+ * replace the rest with semantic head/tail receipts, then fold fully-aged
176
+ * pairs into the history digest.
177
+ *
178
+ * Every one of those edits touches a message the provider has already seen,
179
+ * so each call costs a full prompt re-cache — it belongs behind
180
+ * {@link shouldRunHygiene}, never on the per-turn path. Content staleness is
181
+ * not a reason to bypass that gate: the edit/replace tools guard against
182
+ * acting on an out-of-date read with their own mtime + sha-256 check.
183
+ *
184
+ * @returns whether the conversation was rewritten.
185
+ */
186
+ private runHistoryHygiene;
187
+ /**
188
+ * Whether the history-rewriting hygiene pass may run this turn.
189
+ *
190
+ * Hard pressure always runs it — staying under the window outranks caching.
191
+ * Otherwise it runs at most once per growth interval, so the conversation
192
+ * stays append-only (and therefore cacheable by the provider) in between.
193
+ */
194
+ private shouldRunHygiene;
131
195
  /**
132
196
  * H1: try to read a pre-computed token total from `ctx.lastRequestTokens`
133
197
  * (set by the agent loop's pre-flight or its restash in emitContextPct).
@@ -0,0 +1,55 @@
1
+ import type { BrainDecision, BrainDecisionRequest } from '../coordination/brain.js';
2
+ import type { EventBus } from '../kernel/events.js';
3
+ import type { Provider, ResponseFormat, Usage } from '../types/provider.js';
4
+ import type { BrainCircuitBreaker } from './brain-circuit.js';
5
+ export interface BrainLlmTarget {
6
+ provider: Provider;
7
+ model: string;
8
+ label?: string | undefined;
9
+ }
10
+ export interface BrainLlmCallResult {
11
+ text: string;
12
+ usage?: Usage | undefined;
13
+ stopReason?: string | undefined;
14
+ }
15
+ export declare const DEFAULT_BRAIN_MAX_TOKENS = 200;
16
+ export type BrainLlmDenyKind = 'unavailable' | 'unparseable' | 'refused';
17
+ export declare function markDenyKind(decision: BrainDecision, kind: BrainLlmDenyKind): BrainDecision;
18
+ export declare function readLlmDenyKind(decision: BrainDecision): BrainLlmDenyKind | undefined;
19
+ export declare function buildBrainUserMessage(request: BrainDecisionRequest): string;
20
+ export declare function withDecisionDigest(user: string, digest: string | undefined): string;
21
+ export declare function completeBrainLlm(target: BrainLlmTarget, input: {
22
+ system: string;
23
+ user: string;
24
+ timeoutMs: number;
25
+ maxTokens?: number | undefined;
26
+ signal?: AbortSignal | undefined;
27
+ }): Promise<string>;
28
+ export declare function completeBrainLlmDetailed(target: BrainLlmTarget, input: {
29
+ system: string;
30
+ user: string;
31
+ timeoutMs: number;
32
+ maxTokens?: number | undefined;
33
+ responseFormat?: ResponseFormat | undefined;
34
+ signal?: AbortSignal | undefined;
35
+ }): Promise<BrainLlmCallResult>;
36
+ export declare function extractUsage(result: unknown): Usage | undefined;
37
+ export declare function extractStopReason(result: unknown): string | undefined;
38
+ export declare function extractText(result: unknown): string;
39
+ export declare function extractConfidence(rawText: string): number | undefined;
40
+ export declare function isNonAnswer(text: string): boolean;
41
+ export interface BrainFreeTextEnvelope {
42
+ decision: string;
43
+ rationale?: string | undefined;
44
+ confidence?: number | undefined;
45
+ }
46
+ export declare function parseFreeTextDecision(rawText: string): BrainFreeTextEnvelope | null;
47
+ export declare function parseOptionDecision(rawText: string, options: NonNullable<BrainDecisionRequest['options']>): BrainDecision | null;
48
+ export declare function llmDecide(request: BrainDecisionRequest, targets: BrainLlmTarget[], timeoutMs: number, digest?: string | undefined, trace?: {
49
+ events: EventBus;
50
+ content: boolean;
51
+ } | undefined, maxTokens?: number | undefined, quality?: {
52
+ rejectUncertain: boolean;
53
+ minConfidence: number;
54
+ } | undefined, circuit?: BrainCircuitBreaker | undefined): Promise<BrainDecision>;
55
+ //# sourceMappingURL=autonomy-brain-llm.d.ts.map
@@ -19,25 +19,14 @@
19
19
  * ## Decision Logging
20
20
  * Every decision is emitted via `onDecision` callback with a human-readable
21
21
  * summary suitable for chat history and journal entries.
22
- *
23
- * Usage:
24
- * const brain = createAutonomyBrain({
25
- * provider, model, maxAutoRisk: 'high',
26
- * onDecision: (summary) => journal.push(summary),
27
- * });
28
22
  */
29
23
  import { type BrainArbiter, type BrainDecision, type BrainDecisionRequest } from '../coordination/brain.js';
30
24
  import { type BrainHeuristicsConfig } from '../coordination/brain-heuristics.js';
31
25
  import type { EventBus } from '../kernel/events.js';
32
- import type { Provider, ResponseFormat, Usage } from '../types/provider.js';
26
+ import type { Provider } from '../types/provider.js';
33
27
  import type { BrainCircuitBreaker } from './brain-circuit.js';
34
- /** One (provider, model) pair the Brain may call for a decision. */
35
- export interface BrainLlmTarget {
36
- provider: Provider;
37
- model: string;
38
- /** Display label for logs/status (e.g. "anthropic/claude-haiku"). */
39
- label?: string | undefined;
40
- }
28
+ import { type BrainLlmTarget, DEFAULT_BRAIN_MAX_TOKENS, readLlmDenyKind, buildBrainUserMessage, withDecisionDigest, completeBrainLlm, completeBrainLlmDetailed, extractConfidence, isNonAnswer, parseFreeTextDecision, parseOptionDecision } from './autonomy-brain-llm.js';
29
+ export { type BrainLlmTarget, DEFAULT_BRAIN_MAX_TOKENS, buildBrainUserMessage, withDecisionDigest, completeBrainLlm, completeBrainLlmDetailed, extractConfidence, isNonAnswer, parseFreeTextDecision, parseOptionDecision, readLlmDenyKind, };
41
30
  export interface AutonomyBrainOptions {
42
31
  /** LLM provider for decision-making. Ignored when `targets` is non-empty. */
43
32
  provider?: Provider | undefined;
@@ -107,21 +96,6 @@ export interface AutonomyBrainOptions {
107
96
  export type BrainAutoRisk = 'off' | 'low' | 'medium' | 'high' | 'all';
108
97
  /**
109
98
  * Resolve an autonomy ceiling to a level comparable against `RISK_LEVELS`.
110
- *
111
- * `RISK_LEVELS` is keyed by REQUEST risk (`low|medium|high|critical`), but a
112
- * ceiling is keyed by `BrainAutoRisk`, whose `'off'` and `'all'` values have
113
- * no entry there. Looking a ceiling up directly therefore silently produced
114
- * the fallback level — `'all'` resolved to `2` (= `high`), so
115
- * `createAutonomyBrain({ maxAutoRisk: 'all' })` auto-denied every `critical`
116
- * request despite being explicitly configured as permissive (see
117
- * `assembleBrainTiers`, which passes `'all'` precisely to keep the inner tier
118
- * ungated and let the tiered ceiling do the gating).
119
- *
120
- * Both the tiered arbiter and the single-LLM brain now share this one
121
- * resolver so the two ladders cannot drift apart again.
122
- *
123
- * @returns `-1` for `'off'` (nothing is auto-decidable), `3` for `'all'`
124
- * (including `critical`), otherwise the matching `RISK_LEVELS` entry.
125
99
  */
126
100
  export declare function resolveRiskCeiling(ceiling: BrainAutoRisk | undefined): number;
127
101
  export interface TieredBrainArbiterOptions {
@@ -163,23 +137,6 @@ export interface TieredBrainArbiterOptions {
163
137
  /**
164
138
  * The standard Brain positioning: policy first, LLM/council second,
165
139
  * escalation last.
166
- *
167
- * 1. POLICY — deterministic DefaultBrainArbiter (low-risk fast path,
168
- * fallback semantics). Denies and option-backed answers pass through
169
- * untouched. A fallback-produced `continue` answer (no optionId, the
170
- * request declared `fallback: 'continue'`) is only PROVISIONAL: it
171
- * means "nobody could decide", not "this is the right call", so the
172
- * LLM tier still gets consulted within the ceiling. Historically it
173
- * short-circuited here, which meant e.g. goal-completion checks never
174
- * reached the LLM at all.
175
- * 2. COUNCIL — requests at/above the council floor (default 'high') are
176
- * decided by the multi-LLM council when one is wired.
177
- * 3. LLM — everything else within the live ceiling goes to the
178
- * single-LLM autonomous brain. Only a real `answer` short-circuits;
179
- * denials/failures fall through.
180
- * 4. ESCALATION — anything left escalates. Callers wrap this in
181
- * `EscalationRoutingBrainArbiter` (interactive prompt or headless
182
- * terminal policy) or the legacy `HumanEscalatingBrainArbiter`.
183
140
  */
184
141
  export declare function createTieredBrainArbiter(opts: TieredBrainArbiterOptions): BrainArbiter;
185
142
  /**
@@ -193,116 +150,6 @@ export declare function createAutonomyBrain(opts: AutonomyBrainOptions): BrainAr
193
150
  export declare function formatDecisionSummary(decision: BrainDecision, request: BrainDecisionRequest): string;
194
151
  /**
195
152
  * Fast heuristic decisions that don't need an LLM call.
196
- *
197
- * Deliberately narrow: heuristics never fire on option-bearing requests
198
- * (options are control-plane input demanding a structured choice, not a
199
- * keyword guess) and the continue fast-path only fires when the caller
200
- * itself declared continue the safe fallback AND the question offers no
201
- * alternative — "Should we continue or stop?" must reach the LLM.
202
153
  */
203
154
  export declare function quickDecide(request: BrainDecisionRequest, heuristics?: BrainHeuristicsConfig | undefined): BrainDecision | null;
204
- /**
205
- * Render a decision request as the user message for a Brain LLM call.
206
- * Shared by the single-LLM tier and every council voter so all of them see
207
- * the same question/context/options shape.
208
- */
209
- export declare function buildBrainUserMessage(request: BrainDecisionRequest): string;
210
- /** Append a decision-history digest to a Brain user message (shared shape). */
211
- export declare function withDecisionDigest(user: string, digest: string | undefined): string;
212
- /**
213
- * One Brain LLM call against a single target. Throws on transport failure,
214
- * timeout, or abort — callers own the pool/fallback semantics.
215
- */
216
- export declare function completeBrainLlm(target: BrainLlmTarget, input: {
217
- system: string;
218
- user: string;
219
- timeoutMs: number;
220
- maxTokens?: number | undefined;
221
- /** External cancellation (e.g. a council's overall budget or user abort). */
222
- signal?: AbortSignal | undefined;
223
- }): Promise<string>;
224
- /** Text plus the observable call metadata a trace/quality gate needs. */
225
- interface BrainLlmCallResult {
226
- text: string;
227
- usage?: Usage | undefined;
228
- /**
229
- * `'max_tokens'` means the response was CUT OFF. With the default 200-token
230
- * budget a rationale can be truncated mid-sentence, and the free-text path
231
- * would happily turn that fragment into a decision — so callers must be
232
- * able to see it.
233
- */
234
- stopReason?: string | undefined;
235
- }
236
- /**
237
- * One Brain LLM call, returning the metadata `completeBrainLlm` discards.
238
- *
239
- * Usage was previously thrown away at this boundary, which is why the council
240
- * adapter reported hardcoded zero tokens for every seat and why "what do
241
- * Brain decisions cost" had no answer.
242
- *
243
- * The per-call timeout is composed with any caller-supplied `signal` so an
244
- * external abort (the council's overall budget, a user cancel) interrupts an
245
- * in-flight provider call instead of waiting out the per-call timeout.
246
- */
247
- export declare function completeBrainLlmDetailed(target: BrainLlmTarget, input: {
248
- system: string;
249
- user: string;
250
- timeoutMs: number;
251
- maxTokens?: number | undefined;
252
- /**
253
- * Wire-level response format (e.g. json_object). Callers that parse the
254
- * response as JSON (the council seats) must pass this through — prompt
255
- * wording alone does not put a provider into JSON mode.
256
- */
257
- responseFormat?: ResponseFormat | undefined;
258
- signal?: AbortSignal | undefined;
259
- }): Promise<BrainLlmCallResult>;
260
- /**
261
- * Output budget for a Brain decision call.
262
- *
263
- * Deliberately small — a Brain response is one decision plus a one-sentence
264
- * rationale, not prose. Raise it via `brain.llm.maxTokens` if truncation
265
- * shows up in the trace as `stopReason: 'max_tokens'`.
266
- */
267
- export declare const DEFAULT_BRAIN_MAX_TOKENS = 200;
268
- /**
269
- * Ask the LLM pool for a decision on complex questions. Targets are tried
270
- * in the given order; the first one that answers wins. Uses a carefully
271
- * crafted system prompt that establishes the brain's identity, purpose,
272
- * and decision-making framework.
273
- */
274
- type BrainLlmDenyKind =
275
- /** No target in the pool produced a response (transport/timeout). */
276
- 'unavailable'
277
- /** A response came back but carried no exact valid option id. */
278
- | 'unparseable'
279
- /** The model considered the question and refused. */
280
- | 'refused';
281
- /**
282
- * Read the reason a Brain LLM tier denied, when known. Returns undefined for
283
- * decisions that did not come from `llmDecide` (policy denials, council
284
- * denials, ledger-guard denials), which callers should treat as decided.
285
- */
286
- export declare function readLlmDenyKind(decision: BrainDecision): BrainLlmDenyKind | undefined;
287
- /** Read a self-reported confidence out of a raw response, if it carries one. */
288
- export declare function extractConfidence(rawText: string): number | undefined;
289
- /** Does this free-text response decline to decide? */
290
- export declare function isNonAnswer(text: string): boolean;
291
- /** Structured envelope a Brain LLM may return for an optionless question. */
292
- interface BrainFreeTextEnvelope {
293
- decision: string;
294
- rationale?: string | undefined;
295
- confidence?: number | undefined;
296
- }
297
- /**
298
- * Parse the optionless response.
299
- *
300
- * Accepts the structured envelope the prompt now asks for, and falls back to
301
- * bare prose so older/simpler models keep working. Returns null when the
302
- * model declined to decide — the caller must then fall through rather than
303
- * present the refusal as an answer.
304
- */
305
- export declare function parseFreeTextDecision(rawText: string): BrainFreeTextEnvelope | null;
306
- export declare function parseOptionDecision(rawText: string, options: NonNullable<BrainDecisionRequest['options']>): BrainDecision | null;
307
- export {};
308
155
  //# sourceMappingURL=autonomy-brain.d.ts.map
@@ -0,0 +1,38 @@
1
+ import type { Message } from '../types/messages.js';
2
+ export interface HardBudgetResult {
3
+ messages: Message[];
4
+ changed: boolean;
5
+ saved: number;
6
+ trimmedBlocks: number;
7
+ droppedMessages: number;
8
+ withinBudget: boolean;
9
+ }
10
+ export declare function headTailTruncate(text: string, keepHead: number, keepTail: number): string;
11
+ export declare function truncateMessageText(m: Message, keepHead: number, keepTail: number, minTokens: number): {
12
+ message: Message;
13
+ trimmed: number;
14
+ } | null;
15
+ export declare function elideMessageToolIo(m: Message): {
16
+ message: Message;
17
+ trimmed: number;
18
+ } | null;
19
+ export declare function enforceHardBudget(messages: readonly Message[], budgetTokens: number, opts: {
20
+ preserveK: number;
21
+ }, findPreserveStartFn?: (messages: readonly Message[], preserveK: number) => number): HardBudgetResult;
22
+ export interface DedupResult {
23
+ messages: Message[];
24
+ changed: boolean;
25
+ saved: number;
26
+ deduped: number;
27
+ }
28
+ export declare function dedupStaleReads(messages: readonly Message[], repeatedReads: readonly {
29
+ file: string;
30
+ count: number;
31
+ }[], opts: {
32
+ preserveK: number;
33
+ }, findPreserveStartFn?: (messages: readonly Message[], preserveK: number) => number): DedupResult;
34
+ export declare function buildLosslessDigest(messages: readonly Message[]): string;
35
+ export declare function hasTextContent(m: Message): boolean;
36
+ export declare function findSafeBoundary(messages: readonly Message[], from: number, to: number, hasTextContentFn?: (m: Message) => boolean): number;
37
+ export declare function findExchangeStart(messages: readonly Message[], userIndex: number): number;
38
+ //# sourceMappingURL=compaction-budget.d.ts.map
@@ -1,170 +1,7 @@
1
- import type { Logger } from '../types/logger.js';
2
- import type { Message } from '../types/messages.js';
3
1
  import { estimateMessageTokens } from '../utils/token-estimate.js';
4
2
  export { buildSmartDigest, type ContentScore, extractText, hasLargeToolResult, hasToolUse, scoreMessage, } from './compaction-scoring.js';
5
- /** Set the module-level compaction debug logger (called by compactor constructors). */
6
- export declare function setCompactionDebugLogger(logger: Logger | undefined): void;
7
- /**
8
- * Token estimate for a message array (text + tool I/O). Re-exported from the
9
- * canonical `token-estimate` helper so compactors and the context-pressure
10
- * monitor share one number.
11
- */
3
+ export { type AcknowledgedToolReceiptCollapse, type AcknowledgedToolResultElision, analyzeFileToolLifecycle, collapseAcknowledgedToolReceipts, compactionDebugEnabled, type CompactionMetrics, didFileMutationRun, eliseAcknowledgedToolResults, eliseOldToolResults, type EliseResult, emitCompactionMetrics, extractPathHints, type FileToolLifecycle, findPreserveStart, firstErrorLine, isElidedResultContent, isElidedToolInput, isFileMutationToolName, isReadToolName, normalizePathKey, readPathOf, safeToolResultString, sameFilePath, setCompactionDebugLogger, summarizeToolResultElision, summarizeToolUseInputElision, } from './compaction-elision.js';
4
+ export { buildLosslessDigest, type DedupResult, dedupStaleReads, elideMessageToolIo, enforceHardBudget, findExchangeStart, findSafeBoundary, type HardBudgetResult, hasTextContent, headTailTruncate, truncateMessageText, } from './compaction-budget.js';
5
+ export { CompactionSummaryCache, type CompactionSummaryCacheOptions, compactionSummaryKey, isPlaceholderSummary, PLACEHOLDER_SUMMARIES, } from './compaction-summary-cache.js';
12
6
  export declare const estimateMessages: typeof estimateMessageTokens;
13
- /**
14
- * Shared, pure compaction primitives.
15
- *
16
- * Before this module the three compactors (`HybridCompactor`,
17
- * `IntelligentCompactor`, `SelectiveCompactor`) each carried their own copies
18
- * of message-token estimation, tool-result elision, text detection and digest
19
- * rendering — with subtle divergences (notably Selective lacked the
20
- * tool_use/tool_result pair preservation, so it could elide the result of a
21
- * tool call it was supposed to keep). These helpers are the single source of
22
- * truth. They operate on plain `Message[]` and never touch `Context`/state, so
23
- * each compactor keeps its own `ctx.state.replaceMessages(...)` plumbing.
24
- */
25
- /** Does this message carry any non-empty text? */
26
- export declare function hasTextContent(m: Message): boolean;
27
- /**
28
- * Index where the preserved (recent) window starts. Walks back counting
29
- * user/assistant messages until `preserveK` are covered, then walks forward to
30
- * keep any tool_use/tool_result protocol pair intact — so a tool_result whose
31
- * tool_use is preserved is never elided.
32
- *
33
- * Instrumentation: emits `compaction.find_preserve_start.ended` with the
34
- * repair-loop block count so we can track whether protocol-pair repair is
35
- * scanning too much content.
36
- */
37
- export declare function findPreserveStart(messages: readonly Message[], preserveK: number): number;
38
- export interface EliseResult {
39
- /** New message array, or the same reference when nothing changed. */
40
- messages: Message[];
41
- /** Estimated tokens reclaimed. */
42
- saved: number;
43
- changed: boolean;
44
- }
45
- export interface AcknowledgedToolResultElision extends EliseResult {
46
- /** Raw tool-result blocks replaced with compact receipts. */
47
- elidedResults: number;
48
- /** Raw acknowledged tool I/O left verbatim after the pass. */
49
- retainedTokens: number;
50
- }
51
- export interface AcknowledgedToolReceiptCollapse extends EliseResult {
52
- /** Complete acknowledged tool exchanges folded into the bounded digest. */
53
- collapsedPairs: number;
54
- }
55
- /**
56
- * Bound raw tool I/O that the model has already consumed successfully.
57
- *
58
- * A result is acknowledged only when a later assistant message exists. The
59
- * trailing tool-result batch therefore stays verbatim until it has actually
60
- * reached the provider; retries and recovered sessions cannot lose the input
61
- * needed for their next request. Among acknowledged pairs, the newest raw
62
- * payloads share `maxRetainedTokens`; older or individually oversized pairs
63
- * become semantic receipts while their exact payload remains in the session
64
- * log. Tool ids and provider metadata stay intact so strict provider replay
65
- * adjacency remains valid.
66
- */
67
- export declare function eliseAcknowledgedToolResults(messages: readonly Message[], opts: {
68
- maxRetainedTokens: number;
69
- }): AcknowledgedToolResultElision;
70
- /**
71
- * Bound the number of acknowledged tool-protocol pairs retained in history.
72
- *
73
- * Raw payload elision bounds bytes, but every receipt still leaves an
74
- * assistant tool_use message and a user tool_result message behind. Long
75
- * autonomous sessions therefore continued to grow linearly in protocol
76
- * shells. This pass keeps the newest `maxPairs`, removes both halves of older
77
- * pairs, drops thinking that existed solely to authorize an omitted tool call,
78
- * and folds the count into one stable system digest. Surrounding assistant or
79
- * user text is preserved.
80
- */
81
- export declare function collapseAcknowledgedToolReceipts(messages: readonly Message[], opts: {
82
- maxPairs: number;
83
- }): AcknowledgedToolReceiptCollapse;
84
- /**
85
- * Elide oversized tool I/O that falls before the preserve window. Pure:
86
- * returns a fresh array (or the same reference when unchanged). Replaces the
87
- * duplicate copies that lived in all three compactors.
88
- */
89
- export declare function eliseOldToolResults(messages: readonly Message[], opts: {
90
- preserveK: number;
91
- eliseThreshold: number;
92
- }): EliseResult;
93
- export interface HardBudgetResult {
94
- /** New message array, or the same reference when nothing changed. */
95
- messages: Message[];
96
- changed: boolean;
97
- /** Estimated message tokens reclaimed (before − after). */
98
- saved: number;
99
- /** Number of content blocks elided or truncated. */
100
- trimmedBlocks: number;
101
- /** Number of whole messages dropped (last-resort Pass 4). */
102
- droppedMessages: number;
103
- /** True when the message array fits `budgetTokens` after trimming. */
104
- withinBudget: boolean;
105
- }
106
- /**
107
- * Last-resort trim that makes a request **structurally guaranteed** to fit its
108
- * budget. Call it after normal compaction when the message array still exceeds
109
- * the hard budget (a single huge paste, a preserved-window tool_result, or a
110
- * >1.5× token under-estimate). It escalates through four increasingly
111
- * destructive passes and stops the instant the array fits, so loss is
112
- * minimised:
113
- *
114
- * 1. Elide all old tool I/O before the preserve window (no threshold floor).
115
- * 2. Head/tail truncate large text in old messages.
116
- * 3. Head/tail truncate large text across the whole array (incl. preserved).
117
- * 4. Drop the oldest whole messages (never the last one) until it fits.
118
- *
119
- * A final `repairToolUseAdjacency` re-links any protocol pair Pass 4 orphaned.
120
- *
121
- * `budgetTokens` is the maximum tokens the **message array** may occupy — the
122
- * caller subtracts the system-prompt + tool-definition overhead from the
123
- * context window first, so this stays a pure function over `Message[]`.
124
- */
125
- export declare function enforceHardBudget(messages: readonly Message[], budgetTokens: number, opts: {
126
- preserveK: number;
127
- }): HardBudgetResult;
128
- export interface DedupResult {
129
- messages: Message[];
130
- changed: boolean;
131
- /** Estimated tokens reclaimed. */
132
- saved: number;
133
- /** Number of stale reads collapsed. */
134
- deduped: number;
135
- }
136
- /**
137
- * Collapse **superseded** reads of the same file. When a file is read
138
- * repeatedly (tracked in `repeatedReads` evidence), every read of it before
139
- * the preserve window that is *not* the newest occurrence is redundant — the
140
- * later read replaced it. This replaces those stale `tool_result` payloads
141
- * with a one-line marker (and elides the paired `tool_use` input), keeping the
142
- * newest read verbatim. Complements `eliseOldToolResults`, which only fires on
143
- * results ≥ `eliseThreshold`: many small-but-repeated reads slip under that bar
144
- * and accumulate, so this catches the pattern `eliseThreshold` misses.
145
- */
146
- export declare function dedupStaleReads(messages: readonly Message[], repeatedReads: readonly {
147
- file: string;
148
- count: number;
149
- }[], opts: {
150
- preserveK: number;
151
- }): DedupResult;
152
- /**
153
- * Lossless textual digest of a message range. Every text block is kept verbatim
154
- * (across all roles, so prior `system` digests fold forward and nothing
155
- * accumulates as loss). `tool_use` / `tool_result` blocks are counted and
156
- * replaced with a marker rather than serialized — their payload is already
157
- * persisted in the session log. Empty/tool-only messages are skipped.
158
- */
159
- export declare function buildLosslessDigest(messages: readonly Message[]): string;
160
- /**
161
- * Nearest safe cut boundary in [from, to]: the start of the exchange of the
162
- * closest user-with-text message. Returns -1 when no such boundary exists.
163
- */
164
- export declare function findSafeBoundary(messages: readonly Message[], from: number, to: number): number;
165
- /**
166
- * Walk backwards from a user message to find where its logical exchange began
167
- * (just after the last assistant message that made no tool calls).
168
- */
169
- export declare function findExchangeStart(messages: readonly Message[], userIndex: number): number;
170
7
  //# sourceMappingURL=compaction-core.d.ts.map
@@ -0,0 +1,58 @@
1
+ import type { ToolResultBlock, ToolUseBlock } from '../types/blocks.js';
2
+ import type { Logger } from '../types/logger.js';
3
+ import type { Message } from '../types/messages.js';
4
+ export interface CompactionMetrics {
5
+ messageCount: number;
6
+ preserveStart: number;
7
+ fastPathIterations: number;
8
+ fastPathInnerIterations: number;
9
+ fullPassIterations: number;
10
+ fullPassInnerIterations: number;
11
+ tokensSaved: number;
12
+ changed: boolean;
13
+ }
14
+ export declare function compactionDebugEnabled(): boolean;
15
+ export declare function setCompactionDebugLogger(logger: Logger | undefined): void;
16
+ export declare function emitCompactionMetrics(event: string, metrics: CompactionMetrics): void;
17
+ export interface EliseResult {
18
+ messages: Message[];
19
+ saved: number;
20
+ changed: boolean;
21
+ }
22
+ export interface AcknowledgedToolResultElision extends EliseResult {
23
+ elidedResults: number;
24
+ retainedTokens: number;
25
+ }
26
+ export interface AcknowledgedToolReceiptCollapse extends EliseResult {
27
+ collapsedPairs: number;
28
+ }
29
+ export interface FileToolLifecycle {
30
+ activeReadIds: Set<string>;
31
+ staleReadPaths: Map<string, string>;
32
+ }
33
+ export declare function isReadToolName(name: string): boolean;
34
+ export declare function isFileMutationToolName(name: string): boolean;
35
+ export declare function didFileMutationRun(use: ToolUseBlock): boolean;
36
+ export declare function sameFilePath(a: string, b: string): boolean;
37
+ export declare function readPathOf(input: Record<string, unknown> | undefined): string | undefined;
38
+ export declare function normalizePathKey(p: string): string;
39
+ export declare function analyzeFileToolLifecycle(messages: readonly Message[], acknowledgedBefore: number): FileToolLifecycle;
40
+ export declare function isElidedResultContent(content: string): boolean;
41
+ export declare function isElidedToolInput(input: Record<string, unknown> | undefined): boolean;
42
+ export declare function eliseAcknowledgedToolResults(messages: readonly Message[], opts: {
43
+ maxRetainedTokens: number;
44
+ }): AcknowledgedToolResultElision;
45
+ export declare function collapseAcknowledgedToolReceipts(messages: readonly Message[], opts: {
46
+ maxPairs: number;
47
+ }): AcknowledgedToolReceiptCollapse;
48
+ export declare function findPreserveStart(messages: readonly Message[], preserveK: number): number;
49
+ export declare function eliseOldToolResults(messages: readonly Message[], opts: {
50
+ preserveK: number;
51
+ eliseThreshold: number;
52
+ }, findPreserveStartFn?: (messages: readonly Message[], preserveK: number) => number): EliseResult;
53
+ export declare function summarizeToolUseInputElision(block: ToolUseBlock, tokens: number): Record<string, unknown>;
54
+ export declare function summarizeToolResultElision(block: ToolResultBlock, tokens: number): string;
55
+ export declare function safeToolResultString(content: unknown): string;
56
+ export declare function extractPathHints(content: unknown): string[];
57
+ export declare function firstErrorLine(content: unknown): string | undefined;
58
+ //# sourceMappingURL=compaction-elision.d.ts.map
@@ -0,0 +1,39 @@
1
+ import type { CouncilQuestion, CouncilResult, CouncilUsage, CouncilVoteResult, ResolvedCouncilProfile, ResolvedCouncilSeat } from '../types/council.js';
2
+ import type { OneShotLLMResult } from '../types/one-shot-llm.js';
3
+ export declare const COUNCIL_REFUSAL_OPTION_ID = "council_refuse";
4
+ export declare const DEFAULT_COUNCIL_MAX_CONCURRENCY = 3;
5
+ export declare const MAX_COUNCIL_CONCURRENCY = 8;
6
+ export declare const OVERALL_TIMEOUT_REASON = "Council overall timeout exceeded.";
7
+ export declare const CALL_CANCELLED_REASON = "Cancelled.";
8
+ export interface UsageAccumulator {
9
+ calls: number;
10
+ inputTokens: number;
11
+ outputTokens: number;
12
+ totalTokens: number;
13
+ }
14
+ export declare function validateConcurrency(value: number): number;
15
+ export declare function validateRefusalCollision(question: CouncilQuestion, refusalOptionId: string): void;
16
+ export declare function optionLabel(question: CouncilQuestion, optionId: string | undefined): string | undefined;
17
+ export declare function mapConcurrent<T, R>(items: readonly T[], concurrency: number, worker: (item: T, index: number) => Promise<R>): Promise<R[]>;
18
+ export declare function distinctTargetKeys(votes: readonly CouncilVoteResult[], profile: ResolvedCouncilProfile): string[];
19
+ export declare function distinctTargetCount(votes: readonly CouncilVoteResult[], profile: ResolvedCouncilProfile): number;
20
+ export declare function distinctnessWarnings(votes: readonly CouncilVoteResult[], profile: ResolvedCouncilProfile): string[];
21
+ export declare function cancelledVote(seat: ResolvedCouncilSeat): CouncilVoteResult;
22
+ export declare function callMetadata(result: OneShotLLMResult): Omit<CouncilVoteResult, 'seatId' | 'persona' | 'status'>;
23
+ export declare function addUsage(usage: UsageAccumulator, result: OneShotLLMResult): void;
24
+ export declare function usageResult(usage: UsageAccumulator, startedAt: number): CouncilUsage;
25
+ export declare function resultEnvelope(input: {
26
+ status: CouncilResult['status'];
27
+ answer?: string | undefined;
28
+ optionId?: string | undefined;
29
+ reason?: string | undefined;
30
+ resolution: CouncilResult['resolution'];
31
+ votes: CouncilVoteResult[];
32
+ profile: ResolvedCouncilProfile;
33
+ usage: UsageAccumulator;
34
+ startedAt: number;
35
+ warnings: string[];
36
+ errors: string[];
37
+ judgeUsed?: boolean | undefined;
38
+ }): CouncilResult;
39
+ //# sourceMappingURL=council-orchestrator-helpers.d.ts.map