@wrongstack/core 0.306.4 → 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 (103) 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 +6011 -5894
  14. package/dist/coordination/mail-tools.d.ts +1 -1
  15. package/dist/coordination/mailbox-http-actor-query.d.ts +16 -0
  16. package/dist/coordination/mailbox-http-router.d.ts +0 -48
  17. package/dist/coordination/mailbox-http-sse.d.ts +12 -0
  18. package/dist/coordination/mailbox-message-types.d.ts +71 -0
  19. package/dist/coordination/mailbox-predicates.d.ts +13 -0
  20. package/dist/coordination/mailbox-project-server.js +1 -1
  21. package/dist/coordination/mailbox-session-sync.d.ts +8 -0
  22. package/dist/coordination/mailbox-types.d.ts +6 -793
  23. package/dist/core/agent-loop-context.d.ts +28 -0
  24. package/dist/core/agent-loop-detector.d.ts +25 -0
  25. package/dist/core/fallback-doctor.d.ts +72 -0
  26. package/dist/core/index.d.ts +1 -0
  27. package/dist/core/index.js +1159 -888
  28. package/dist/defaults/index.js +3579 -3545
  29. package/dist/execution/autonomy-brain-llm.d.ts +55 -0
  30. package/dist/execution/autonomy-brain.d.ts +3 -156
  31. package/dist/execution/compaction-budget.d.ts +38 -0
  32. package/dist/execution/compaction-core.d.ts +3 -170
  33. package/dist/execution/compaction-elision.d.ts +58 -0
  34. package/dist/execution/council-orchestrator-helpers.d.ts +39 -0
  35. package/dist/execution/council-orchestrator.d.ts +3 -42
  36. package/dist/execution/council-response-parser.d.ts +56 -0
  37. package/dist/execution/index.js +2415 -2443
  38. package/dist/execution/prompt-enhancer.js +11 -3
  39. package/dist/execution/tool-executor-guard.d.ts +18 -0
  40. package/dist/execution/tool-executor-runner.d.ts +12 -0
  41. package/dist/execution/tool-executor.d.ts +0 -75
  42. package/dist/goal/index.js +19 -6
  43. package/dist/hq/index.js +8 -2
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.js +7813 -7292
  46. package/dist/infrastructure/index.js +3 -1
  47. package/dist/kernel/events/agent-events.d.ts +2 -0
  48. package/dist/kernel/events/provider-events.d.ts +13 -0
  49. package/dist/plugin/index.js +2590 -2561
  50. package/dist/plugins/auto-review-config.d.ts +53 -0
  51. package/dist/plugins/auto-review-git.d.ts +19 -0
  52. package/dist/plugins/auto-review-plugin.d.ts +2 -140
  53. package/dist/plugins/review-finding-verification.d.ts +7 -0
  54. package/dist/prompts/index.d.ts +1 -0
  55. package/dist/prompts/prompt-journal.d.ts +94 -0
  56. package/dist/security/index.js +627 -652
  57. package/dist/security/permission-explain.d.ts +19 -0
  58. package/dist/security/permission-policy.d.ts +0 -101
  59. package/dist/security/yolo-risk.d.ts +5 -4
  60. package/dist/session-catalog/index.js +220 -212
  61. package/dist/session-catalog/project-server.js +227 -219
  62. package/dist/session-catalog/store-rebuild.d.ts +9 -0
  63. package/dist/session-catalog/store-schema.d.ts +48 -0
  64. package/dist/session-catalog/store.d.ts +0 -17
  65. package/dist/storage/director-state.d.ts +6 -0
  66. package/dist/storage/file-session-writer.d.ts +2 -58
  67. package/dist/storage/index.d.ts +2 -1
  68. package/dist/storage/index.js +2057 -1925
  69. package/dist/storage/orphan-lock-cleaner.d.ts +15 -0
  70. package/dist/storage/session-recovery.d.ts +9 -0
  71. package/dist/storage/session-store/rename-session.d.ts +16 -0
  72. package/dist/storage/session-store/resume-session.d.ts +26 -0
  73. package/dist/storage/session-store/session-store-clear.d.ts +11 -0
  74. package/dist/storage/session-store/session-store-index.d.ts +13 -0
  75. package/dist/storage/session-store.d.ts +1 -129
  76. package/dist/storage/session-summary-tracker.d.ts +39 -0
  77. package/dist/storage/session-write-buffer.d.ts +43 -0
  78. package/dist/storage/session-writer/session-writer-flush.d.ts +4 -0
  79. package/dist/storage/session-writer/session-writer-summary-tracker.d.ts +28 -0
  80. package/dist/tools/fallback-agent-model-assign-tool.d.ts +18 -0
  81. package/dist/tools/fallback-leader-model-set-tool.d.ts +18 -0
  82. package/dist/tools/fallback-manage-tools.d.ts +8 -45
  83. package/dist/tools/fallback-profile-manage-tool.d.ts +16 -0
  84. package/dist/tools/fallback-provider-key-set-tool.d.ts +17 -0
  85. package/dist/tools/fallback-provider-manage-tool.d.ts +26 -0
  86. package/dist/tools/index.js +5070 -5071
  87. package/dist/types/config/root.d.ts +7 -2
  88. package/dist/types/default-config.d.ts +1 -1
  89. package/dist/types/index.d.ts +54 -55
  90. package/dist/types/index.js +953 -932
  91. package/dist/types/runtime-capability-manifest.d.ts +5 -5
  92. package/dist/types/session-markers.d.ts +12 -0
  93. package/dist/types/session-markers.js +19 -0
  94. package/dist/worktree/worktree-manager.d.ts +1 -1
  95. package/instructions/coordination/subagent-baseline.md +2 -2
  96. package/instructions/llm/prompt-enhancer.md +2 -1
  97. package/instructions/sections/tool/common-patterns.md +21 -0
  98. package/instructions/sections/tool/delegation-compact.md +3 -1
  99. package/instructions/sections/tool/delegation-full.md +5 -1
  100. package/instructions/system-lite.md +28 -3
  101. package/instructions/system-pro.md +37 -8
  102. package/instructions/system.md +4 -2
  103. package/package.json +5 -5
@@ -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,174 +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
- * Every edit here rewrites a message the provider has already seen, so callers
68
- * must run this on a pressure-gated interval rather than per turn — see
69
- * `AutoCompactionMiddleware.shouldRunHygiene`.
70
- */
71
- export declare function eliseAcknowledgedToolResults(messages: readonly Message[], opts: {
72
- maxRetainedTokens: number;
73
- }): AcknowledgedToolResultElision;
74
- /**
75
- * Bound the number of acknowledged tool-protocol pairs retained in history.
76
- *
77
- * Raw payload elision bounds bytes, but every receipt still leaves an
78
- * assistant tool_use message and a user tool_result message behind. Long
79
- * autonomous sessions therefore continued to grow linearly in protocol
80
- * shells. This pass keeps the newest `maxPairs`, removes both halves of older
81
- * pairs, drops thinking that existed solely to authorize an omitted tool call,
82
- * and folds the count into one stable system digest. Surrounding assistant or
83
- * user text is preserved.
84
- */
85
- export declare function collapseAcknowledgedToolReceipts(messages: readonly Message[], opts: {
86
- maxPairs: number;
87
- }): AcknowledgedToolReceiptCollapse;
88
- /**
89
- * Elide oversized tool I/O that falls before the preserve window. Pure:
90
- * returns a fresh array (or the same reference when unchanged). Replaces the
91
- * duplicate copies that lived in all three compactors.
92
- */
93
- export declare function eliseOldToolResults(messages: readonly Message[], opts: {
94
- preserveK: number;
95
- eliseThreshold: number;
96
- }): EliseResult;
97
- export interface HardBudgetResult {
98
- /** New message array, or the same reference when nothing changed. */
99
- messages: Message[];
100
- changed: boolean;
101
- /** Estimated message tokens reclaimed (before − after). */
102
- saved: number;
103
- /** Number of content blocks elided or truncated. */
104
- trimmedBlocks: number;
105
- /** Number of whole messages dropped (last-resort Pass 4). */
106
- droppedMessages: number;
107
- /** True when the message array fits `budgetTokens` after trimming. */
108
- withinBudget: boolean;
109
- }
110
- /**
111
- * Last-resort trim that makes a request **structurally guaranteed** to fit its
112
- * budget. Call it after normal compaction when the message array still exceeds
113
- * the hard budget (a single huge paste, a preserved-window tool_result, or a
114
- * >1.5× token under-estimate). It escalates through four increasingly
115
- * destructive passes and stops the instant the array fits, so loss is
116
- * minimised:
117
- *
118
- * 1. Elide all old tool I/O before the preserve window (no threshold floor).
119
- * 2. Head/tail truncate large text in old messages.
120
- * 3. Head/tail truncate large text across the whole array (incl. preserved).
121
- * 4. Drop the oldest whole messages (never the last one) until it fits.
122
- *
123
- * A final `repairToolUseAdjacency` re-links any protocol pair Pass 4 orphaned.
124
- *
125
- * `budgetTokens` is the maximum tokens the **message array** may occupy — the
126
- * caller subtracts the system-prompt + tool-definition overhead from the
127
- * context window first, so this stays a pure function over `Message[]`.
128
- */
129
- export declare function enforceHardBudget(messages: readonly Message[], budgetTokens: number, opts: {
130
- preserveK: number;
131
- }): HardBudgetResult;
132
- export interface DedupResult {
133
- messages: Message[];
134
- changed: boolean;
135
- /** Estimated tokens reclaimed. */
136
- saved: number;
137
- /** Number of stale reads collapsed. */
138
- deduped: number;
139
- }
140
- /**
141
- * Collapse **superseded** reads of the same file. When a file is read
142
- * repeatedly (tracked in `repeatedReads` evidence), every read of it before
143
- * the preserve window that is *not* the newest occurrence is redundant — the
144
- * later read replaced it. This replaces those stale `tool_result` payloads
145
- * with a one-line marker (and elides the paired `tool_use` input), keeping the
146
- * newest read verbatim. Complements `eliseOldToolResults`, which only fires on
147
- * results ≥ `eliseThreshold`: many small-but-repeated reads slip under that bar
148
- * and accumulate, so this catches the pattern `eliseThreshold` misses.
149
- */
150
- export declare function dedupStaleReads(messages: readonly Message[], repeatedReads: readonly {
151
- file: string;
152
- count: number;
153
- }[], opts: {
154
- preserveK: number;
155
- }): DedupResult;
156
- /**
157
- * Lossless textual digest of a message range. Every text block is kept verbatim
158
- * (across all roles, so prior `system` digests fold forward and nothing
159
- * accumulates as loss). `tool_use` / `tool_result` blocks are counted and
160
- * replaced with a marker rather than serialized — their payload is already
161
- * persisted in the session log. Empty/tool-only messages are skipped.
162
- */
163
- export declare function buildLosslessDigest(messages: readonly Message[]): string;
164
- /**
165
- * Nearest safe cut boundary in [from, to]: the start of the exchange of the
166
- * closest user-with-text message. Returns -1 when no such boundary exists.
167
- */
168
- export declare function findSafeBoundary(messages: readonly Message[], from: number, to: number): number;
169
- /**
170
- * Walk backwards from a user message to find where its logical exchange began
171
- * (just after the last assistant message that made no tool calls).
172
- */
173
- export declare function findExchangeStart(messages: readonly Message[], userIndex: number): number;
174
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
@@ -1,19 +1,14 @@
1
1
  import type { FallbackProfileManager } from '../core/fallback-profile-manager.js';
2
2
  import type { Config } from '../types/config.js';
3
3
  import type { CouncilLLMCaller, CouncilQuestion, CouncilResult } from '../types/council.js';
4
+ import { COUNCIL_REFUSAL_OPTION_ID, DEFAULT_COUNCIL_MAX_CONCURRENCY, MAX_COUNCIL_CONCURRENCY } from './council-orchestrator-helpers.js';
4
5
  import { type CouncilPersonaRegistry } from './council-personas.js';
5
6
  import { type CouncilProfileRegistry } from './council-profiles.js';
6
- /** Synthetic ballot entry for "refuse every real option". */
7
- export declare const COUNCIL_REFUSAL_OPTION_ID = "council_refuse";
8
- export declare const DEFAULT_COUNCIL_MAX_CONCURRENCY = 3;
9
- export declare const MAX_COUNCIL_CONCURRENCY = 8;
7
+ export { COUNCIL_REFUSAL_OPTION_ID, DEFAULT_COUNCIL_MAX_CONCURRENCY, MAX_COUNCIL_CONCURRENCY, };
10
8
  export interface CouncilOrchestratorOptions {
11
9
  /**
12
10
  * Shared LLM caller used for every seat and the judge when no per-seat
13
- * caller is configured. Optional — supply `seatCaller` (per-seat callers)
14
- * and/or `judgeCaller` (separate judge caller) to route votes to different
15
- * providers. At least one of `caller`, `seatCaller`, or `judgeCaller`
16
- * must be provided; the constructor throws otherwise.
11
+ * caller is configured.
17
12
  */
18
13
  caller?: CouncilLLMCaller | undefined;
19
14
  personas?: CouncilPersonaRegistry | undefined;
@@ -21,25 +16,9 @@ export interface CouncilOrchestratorOptions {
21
16
  defaultProfile?: string | undefined;
22
17
  maxConcurrency?: number | undefined;
23
18
  refusalOptionId?: string | undefined;
24
- /** Live config accessor for fallback profile resolution. */
25
19
  getConfig?: (() => Config) | undefined;
26
- /**
27
- * Shared live FallbackProfileManager — required for reliable fallback
28
- * profile pre-resolution. Pass the runtime container's manager.
29
- */
30
20
  fallbackProfileManager?: FallbackProfileManager | undefined;
31
- /**
32
- * Per-seat LLM caller factory. When set, each seat gets its own caller
33
- * instead of the shared `caller`. The factory receives (seatIndex) and
34
- * returns a CouncilLLMCaller. Used by Brain council arbitration where
35
- * each voter has its own Provider instance.
36
- */
37
21
  seatCaller?: ((seatIndex: number) => CouncilLLMCaller) | undefined;
38
- /**
39
- * Separate caller for the judge seat. Required when `seatCaller` is set
40
- * because the judge uses the shared caller path. When absent and
41
- * `seatCaller` is set, the judge falls back to `seatCaller(0)`.
42
- */
43
22
  judgeCaller?: CouncilLLMCaller | undefined;
44
23
  }
45
24
  /** Provider-neutral Council runner backed by an injected one-shot LLM caller. */
@@ -54,32 +33,14 @@ export declare class CouncilOrchestrator {
54
33
  private readonly seatCaller;
55
34
  private readonly judgeCaller;
56
35
  constructor(opts: CouncilOrchestratorOptions);
57
- /**
58
- * Resolve the effective profile for a question. String ids and the default
59
- * go through the registry (already O(1)); ad-hoc config objects are
60
- * normalized on each call. Callers are allowed to reuse and mutate an
61
- * ad-hoc object between decisions, so object-identity caching would serve a
62
- * stale snapshot.
63
- */
64
36
  private resolveProfile;
65
37
  ask(question: CouncilQuestion): Promise<CouncilResult>;
66
38
  private callSeat;
67
39
  private resolveOptionQuestion;
68
40
  private resolveOpenQuestion;
69
41
  private callJudge;
70
- /**
71
- * Resolve the effective LLM caller for a call. Voter seats (defined
72
- * seatIndex) use `seatCaller(seatIndex)` when wired, otherwise the shared
73
- * `caller` — a seat never falls through to the judge caller. Judge seats
74
- * (seatIndex undefined) use `judgeCaller` if set, otherwise `seatCaller(0)`
75
- * if set, otherwise the shared `caller`.
76
- */
77
42
  private resolveCaller;
78
43
  private safeCall;
79
- /**
80
- * Resolve a CouncilModelTarget: pre-resolve fallbackProfile to fallbackModels
81
- * so the downstream caller only sees the resolved chain.
82
- */
83
44
  private resolveCouncilTarget;
84
45
  }
85
46
  //# sourceMappingURL=council-orchestrator.d.ts.map