@sanctuary-framework/mcp-server 1.2.4 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -252,6 +252,43 @@ interface ApprovalChannelConfig {
252
252
  webhook_url?: string;
253
253
  webhook_secret?: string;
254
254
  }
255
+ /**
256
+ * WP-V1.3-10 Upsilon-2: cross-harness approval-redirect mode.
257
+ *
258
+ * `mode` selects how the underlying channel and the aggregator interact when
259
+ * a Tier 1/2 approval fires for a wrapped agent:
260
+ *
261
+ * - `replace`: the underlying channel is bypassed; the gate's
262
+ * `requestApproval()` blocks awaiting the operator's decision through
263
+ * the aggregator HTTP `approve`/`deny` routes (or any other surface that
264
+ * calls `aggregator.resolve()`). Default behavior when redirect is
265
+ * enabled.
266
+ * - `notify`: both the underlying channel AND the aggregator run; the
267
+ * first decision wins. Right shape for harnesses (e.g. Mastra) where
268
+ * full local-prompt suppression is not viable, so the operator still
269
+ * sees the prompt locally but ALSO can resolve from the unified inbox.
270
+ *
271
+ * `per_agent` is a stub for v1.4 multi-agent fortresses: a map of
272
+ * `agent_id -> {enabled, mode}` overrides. v1.x ignores this field; the
273
+ * fortress-level `enabled` + `mode` apply to every wrapped agent in the
274
+ * fortress (which is currently single-agent in practice). v1.4 adds
275
+ * agent-id propagation through the gate signature and consults this map.
276
+ */
277
+ interface ApprovalRedirectPerAgentOverride {
278
+ enabled?: boolean;
279
+ mode?: "replace" | "notify";
280
+ }
281
+ interface ApprovalRedirectConfig {
282
+ /** Master toggle. When false, redirect-mode is off across the fortress. */
283
+ enabled: boolean;
284
+ /** How the underlying channel and the aggregator coexist. */
285
+ mode: "replace" | "notify";
286
+ /**
287
+ * Per-agent overrides. v1.x stub — populated entries are validated and
288
+ * persisted but not enforced. Reserved for v1.4 multi-agent fortresses.
289
+ */
290
+ per_agent?: Record<string, ApprovalRedirectPerAgentOverride>;
291
+ }
255
292
  /** Complete Principal Policy */
256
293
  interface PrincipalPolicy {
257
294
  version: number;
@@ -270,6 +307,13 @@ interface PrincipalPolicy {
270
307
  * days when absent; values <= 0 fall back to the default.
271
308
  */
272
309
  concierge_memory_retention_days?: number;
310
+ /**
311
+ * WP-V1.3-10 Upsilon-2: cross-harness approval-redirect mode. Optional;
312
+ * defaults to `{ enabled: false, mode: "replace" }` (preserves legacy
313
+ * behavior). Operator-toggled via `sanctuary agents config <tenant>
314
+ * --approval-redirect=<bool>` or by editing principal-policy.yaml.
315
+ */
316
+ approval_redirect?: ApprovalRedirectConfig;
273
317
  }
274
318
  /** Approval request sent to the human */
275
319
  interface ApprovalRequest {
@@ -5183,6 +5227,24 @@ interface ReadThreadOptions {
5183
5227
  /** Cap the number of turns returned (oldest-first within the bundle). */
5184
5228
  limit?: number;
5185
5229
  }
5230
+ /**
5231
+ * Stable failure-reason enum for `readThreadStrict` (WP-V1.3-9 Tau-2).
5232
+ * Mirrors the shape carried by `operator_concierge_memory_read_failed`
5233
+ * audit payloads so the service emits the cause verbatim.
5234
+ */
5235
+ type ConciergeMemoryReadFailure = "decrypt_failed" | "schema_mismatch" | "oversize_bundle" | "io_failed" | "unknown";
5236
+ /**
5237
+ * Discriminated result for `readThreadStrict`. The fold-read path uses
5238
+ * this so an empty thread (no bundle) does not look the same as a
5239
+ * corrupted bundle (which must trigger graceful degradation).
5240
+ */
5241
+ type ReadThreadStrictResult = {
5242
+ ok: true;
5243
+ turns: ConciergeTurn[];
5244
+ } | {
5245
+ ok: false;
5246
+ reason: ConciergeMemoryReadFailure;
5247
+ };
5186
5248
  interface ListThreadsOptions {
5187
5249
  /** Cap the number of summaries returned. */
5188
5250
  limit?: number;
@@ -5210,6 +5272,21 @@ declare class ConciergeMemoryStore {
5210
5272
  * audit events; the caller (HTTP route handler) owns audit semantics.
5211
5273
  */
5212
5274
  readThread(threadId: string, opts?: ReadThreadOptions): Promise<ConciergeTurn[]>;
5275
+ /**
5276
+ * Read turns with explicit failure surfacing (WP-V1.3-9 Tau-2). Where
5277
+ * `readThread` collapses every failure mode to an empty array, this
5278
+ * variant returns a discriminated result so the multi-turn fold path
5279
+ * can degrade cleanly + emit `operator_concierge_memory_read_failed`
5280
+ * with a concrete cause.
5281
+ *
5282
+ * - No bundle on disk → `{ ok: true, turns: [] }` (a fresh thread).
5283
+ * - Bundle present, decode + decrypt + schema check pass → ok with turns.
5284
+ * - Bundle present, oversize → `{ ok: false, reason: "oversize_bundle" }`.
5285
+ * - Bundle present, decryption fails → `{ ok: false, reason: "decrypt_failed" }`.
5286
+ * - Bundle present, schema mismatch (version / thread_id) → `schema_mismatch`.
5287
+ * - Storage IO error → `io_failed`.
5288
+ */
5289
+ readThreadStrict(threadId: string, opts?: ReadThreadOptions): Promise<ReadThreadStrictResult>;
5213
5290
  /**
5214
5291
  * Enumerate concierge threads in this fortress with summary metadata.
5215
5292
  * Sorted newest-first by last_turn_at.
@@ -5342,13 +5419,48 @@ interface OperatorChatServiceDeps {
5342
5419
  /**
5343
5420
  * WP-V1.3-9 Tau-1: optional foundation memory store. When wired,
5344
5421
  * `sendConcierge` dual-writes each operator+concierge turn pair into
5345
- * the memory store under a session-scoped thread_id. Read-side wiring
5346
- * (substrate-selector context-fold) lands in Tau-2.
5422
+ * the memory store under a session-scoped thread_id. Tau-2 adds a
5423
+ * read-fold path that surfaces the prior turns to the substrate so
5424
+ * the concierge maintains coherence across a multi-turn session.
5347
5425
  *
5348
5426
  * Omit at construction time to disable memory-side persistence; the
5349
5427
  * existing `OperatorChatStore` write keeps working unchanged.
5350
5428
  */
5351
5429
  conciergeMemory?: ConciergeMemoryStore;
5430
+ /**
5431
+ * WP-V1.3-9 Tau-2: maximum prior turns folded into the substrate
5432
+ * context per round-trip. Defaults to
5433
+ * `DEFAULT_CONCIERGE_HISTORY_WINDOW_TURNS` (10). The current operator
5434
+ * turn is always present; this caps history only.
5435
+ */
5436
+ conciergeHistoryWindowTurns?: number;
5437
+ /**
5438
+ * WP-V1.3-9 Tau-2: prior turns older than this many milliseconds are
5439
+ * excluded from the active fold even when they remain on disk.
5440
+ * Defaults to `DEFAULT_CONCIERGE_HISTORY_FRESHNESS_MS` (24h).
5441
+ */
5442
+ conciergeHistoryFreshnessMs?: number;
5443
+ /**
5444
+ * WP-V1.3-9 Tau-2: rough token budget for the prior-conversation
5445
+ * portion of the substrate context. Estimated as ~4 chars per token.
5446
+ * Defaults to `DEFAULT_CONCIERGE_HISTORY_TOKEN_BUDGET` (500). The
5447
+ * static reference block + fortress sections are NOT subject to this
5448
+ * budget; only the prior-conversation fold is pruned oldest-first.
5449
+ */
5450
+ conciergeHistoryTokenBudget?: number;
5451
+ /**
5452
+ * WP-V1.3-9 Tau-2: how long an active session may stay quiet before
5453
+ * the next `sendConcierge` allocates a fresh thread_id. Defaults to
5454
+ * `DEFAULT_CONCIERGE_SESSION_TTL_MS` (24h). Does not delete the prior
5455
+ * thread; it remains readable through the memory store.
5456
+ */
5457
+ conciergeSessionTtlMs?: number;
5458
+ /**
5459
+ * Optional clock for the session-TTL + freshness checks. Tests inject
5460
+ * a deterministic clock; production lets the default `Date.now`-based
5461
+ * implementation run.
5462
+ */
5463
+ conciergeClock?: () => number;
5352
5464
  }
5353
5465
  declare class OperatorChatService {
5354
5466
  private store;
@@ -5359,6 +5471,11 @@ declare class OperatorChatService {
5359
5471
  private piiFilter?;
5360
5472
  private conciergeMaxTokens;
5361
5473
  private memory?;
5474
+ private historyWindowTurns;
5475
+ private historyFreshnessMs;
5476
+ private historyTokenBudget;
5477
+ private sessionTtlMs;
5478
+ private clock;
5362
5479
  /**
5363
5480
  * In-memory thread_id assigned to the active concierge session.
5364
5481
  * The first sendConcierge call after construction allocates a fresh
@@ -5366,6 +5483,14 @@ declare class OperatorChatService {
5366
5483
  * folds the prior turns into context. Cleared by `resetConciergeMemoryThread`.
5367
5484
  */
5368
5485
  private activeMemoryThreadId?;
5486
+ /**
5487
+ * Wall-clock ms of the most recent sendConcierge that touched the
5488
+ * active session thread. Drives the WP-V1.3-9 Tau-2 session-TTL
5489
+ * check: a fresh sendConcierge after `sessionTtlMs` of quiet
5490
+ * allocates a new thread_id even though the prior one is still
5491
+ * readable from the memory store.
5492
+ */
5493
+ private lastInteractionAt?;
5369
5494
  constructor(deps: OperatorChatServiceDeps);
5370
5495
  /**
5371
5496
  * Operator submit on the concierge surface. Persists the operator's
@@ -5378,6 +5503,13 @@ declare class OperatorChatService {
5378
5503
  * operator sees on the page (no silent dropping).
5379
5504
  */
5380
5505
  sendConcierge(query: string): Promise<ConciergeResponse>;
5506
+ /**
5507
+ * Emit the WP-V1.3-9 Tau-2 graceful-degradation audit event. Pulled
5508
+ * out of `sendConcierge` so the read-fold path stays readable. Emits
5509
+ * with `result: "failure"` since the concierge fell back to
5510
+ * single-turn mode for this round-trip.
5511
+ */
5512
+ private emitMemoryReadFailed;
5381
5513
  /**
5382
5514
  * Read the persisted concierge thread, oldest message first. Returns
5383
5515
  * an empty array when no thread exists yet.
@@ -5424,6 +5556,11 @@ declare class OperatorChatService {
5424
5556
  * ## Sanctuary reference
5425
5557
  * <static domain reference block>
5426
5558
  *
5559
+ * ## Prior conversation ← WP-V1.3-9 Tau-2, when present
5560
+ * OPERATOR: ...
5561
+ * CONCIERGE: ...
5562
+ * ---
5563
+ *
5427
5564
  * ## Recent activity
5428
5565
  * <recentActivity output>
5429
5566
  *
@@ -5433,8 +5570,22 @@ declare class OperatorChatService {
5433
5570
  * ## Open inbox
5434
5571
  * <openInbox output>
5435
5572
  * ```
5573
+ *
5574
+ * The substrate selector ships a `context: string` shape (not a
5575
+ * messages array), so multi-turn coherence is folded as a structured
5576
+ * prior-conversation section with explicit OPERATOR / CONCIERGE
5577
+ * boundaries. Coordinator-CTO guidance: prefer messages-array shape
5578
+ * if available; the v1.2 selector does not expose one, so structured
5579
+ * serialization is the canonical path for v1.3.
5436
5580
  */
5437
5581
  private assembleConciergeContext;
5582
+ /**
5583
+ * Render the prior-conversation section with token-budget enforcement
5584
+ * (WP-V1.3-9 Tau-2). Drops oldest turns first when the rendered
5585
+ * section exceeds `historyTokenBudget`. Returns an empty string when
5586
+ * the input is empty or when the budget excludes every turn.
5587
+ */
5588
+ private formatPriorTurnsSection;
5438
5589
  private emit;
5439
5590
  }
5440
5591
 
package/dist/index.d.ts CHANGED
@@ -252,6 +252,43 @@ interface ApprovalChannelConfig {
252
252
  webhook_url?: string;
253
253
  webhook_secret?: string;
254
254
  }
255
+ /**
256
+ * WP-V1.3-10 Upsilon-2: cross-harness approval-redirect mode.
257
+ *
258
+ * `mode` selects how the underlying channel and the aggregator interact when
259
+ * a Tier 1/2 approval fires for a wrapped agent:
260
+ *
261
+ * - `replace`: the underlying channel is bypassed; the gate's
262
+ * `requestApproval()` blocks awaiting the operator's decision through
263
+ * the aggregator HTTP `approve`/`deny` routes (or any other surface that
264
+ * calls `aggregator.resolve()`). Default behavior when redirect is
265
+ * enabled.
266
+ * - `notify`: both the underlying channel AND the aggregator run; the
267
+ * first decision wins. Right shape for harnesses (e.g. Mastra) where
268
+ * full local-prompt suppression is not viable, so the operator still
269
+ * sees the prompt locally but ALSO can resolve from the unified inbox.
270
+ *
271
+ * `per_agent` is a stub for v1.4 multi-agent fortresses: a map of
272
+ * `agent_id -> {enabled, mode}` overrides. v1.x ignores this field; the
273
+ * fortress-level `enabled` + `mode` apply to every wrapped agent in the
274
+ * fortress (which is currently single-agent in practice). v1.4 adds
275
+ * agent-id propagation through the gate signature and consults this map.
276
+ */
277
+ interface ApprovalRedirectPerAgentOverride {
278
+ enabled?: boolean;
279
+ mode?: "replace" | "notify";
280
+ }
281
+ interface ApprovalRedirectConfig {
282
+ /** Master toggle. When false, redirect-mode is off across the fortress. */
283
+ enabled: boolean;
284
+ /** How the underlying channel and the aggregator coexist. */
285
+ mode: "replace" | "notify";
286
+ /**
287
+ * Per-agent overrides. v1.x stub — populated entries are validated and
288
+ * persisted but not enforced. Reserved for v1.4 multi-agent fortresses.
289
+ */
290
+ per_agent?: Record<string, ApprovalRedirectPerAgentOverride>;
291
+ }
255
292
  /** Complete Principal Policy */
256
293
  interface PrincipalPolicy {
257
294
  version: number;
@@ -270,6 +307,13 @@ interface PrincipalPolicy {
270
307
  * days when absent; values <= 0 fall back to the default.
271
308
  */
272
309
  concierge_memory_retention_days?: number;
310
+ /**
311
+ * WP-V1.3-10 Upsilon-2: cross-harness approval-redirect mode. Optional;
312
+ * defaults to `{ enabled: false, mode: "replace" }` (preserves legacy
313
+ * behavior). Operator-toggled via `sanctuary agents config <tenant>
314
+ * --approval-redirect=<bool>` or by editing principal-policy.yaml.
315
+ */
316
+ approval_redirect?: ApprovalRedirectConfig;
273
317
  }
274
318
  /** Approval request sent to the human */
275
319
  interface ApprovalRequest {
@@ -5183,6 +5227,24 @@ interface ReadThreadOptions {
5183
5227
  /** Cap the number of turns returned (oldest-first within the bundle). */
5184
5228
  limit?: number;
5185
5229
  }
5230
+ /**
5231
+ * Stable failure-reason enum for `readThreadStrict` (WP-V1.3-9 Tau-2).
5232
+ * Mirrors the shape carried by `operator_concierge_memory_read_failed`
5233
+ * audit payloads so the service emits the cause verbatim.
5234
+ */
5235
+ type ConciergeMemoryReadFailure = "decrypt_failed" | "schema_mismatch" | "oversize_bundle" | "io_failed" | "unknown";
5236
+ /**
5237
+ * Discriminated result for `readThreadStrict`. The fold-read path uses
5238
+ * this so an empty thread (no bundle) does not look the same as a
5239
+ * corrupted bundle (which must trigger graceful degradation).
5240
+ */
5241
+ type ReadThreadStrictResult = {
5242
+ ok: true;
5243
+ turns: ConciergeTurn[];
5244
+ } | {
5245
+ ok: false;
5246
+ reason: ConciergeMemoryReadFailure;
5247
+ };
5186
5248
  interface ListThreadsOptions {
5187
5249
  /** Cap the number of summaries returned. */
5188
5250
  limit?: number;
@@ -5210,6 +5272,21 @@ declare class ConciergeMemoryStore {
5210
5272
  * audit events; the caller (HTTP route handler) owns audit semantics.
5211
5273
  */
5212
5274
  readThread(threadId: string, opts?: ReadThreadOptions): Promise<ConciergeTurn[]>;
5275
+ /**
5276
+ * Read turns with explicit failure surfacing (WP-V1.3-9 Tau-2). Where
5277
+ * `readThread` collapses every failure mode to an empty array, this
5278
+ * variant returns a discriminated result so the multi-turn fold path
5279
+ * can degrade cleanly + emit `operator_concierge_memory_read_failed`
5280
+ * with a concrete cause.
5281
+ *
5282
+ * - No bundle on disk → `{ ok: true, turns: [] }` (a fresh thread).
5283
+ * - Bundle present, decode + decrypt + schema check pass → ok with turns.
5284
+ * - Bundle present, oversize → `{ ok: false, reason: "oversize_bundle" }`.
5285
+ * - Bundle present, decryption fails → `{ ok: false, reason: "decrypt_failed" }`.
5286
+ * - Bundle present, schema mismatch (version / thread_id) → `schema_mismatch`.
5287
+ * - Storage IO error → `io_failed`.
5288
+ */
5289
+ readThreadStrict(threadId: string, opts?: ReadThreadOptions): Promise<ReadThreadStrictResult>;
5213
5290
  /**
5214
5291
  * Enumerate concierge threads in this fortress with summary metadata.
5215
5292
  * Sorted newest-first by last_turn_at.
@@ -5342,13 +5419,48 @@ interface OperatorChatServiceDeps {
5342
5419
  /**
5343
5420
  * WP-V1.3-9 Tau-1: optional foundation memory store. When wired,
5344
5421
  * `sendConcierge` dual-writes each operator+concierge turn pair into
5345
- * the memory store under a session-scoped thread_id. Read-side wiring
5346
- * (substrate-selector context-fold) lands in Tau-2.
5422
+ * the memory store under a session-scoped thread_id. Tau-2 adds a
5423
+ * read-fold path that surfaces the prior turns to the substrate so
5424
+ * the concierge maintains coherence across a multi-turn session.
5347
5425
  *
5348
5426
  * Omit at construction time to disable memory-side persistence; the
5349
5427
  * existing `OperatorChatStore` write keeps working unchanged.
5350
5428
  */
5351
5429
  conciergeMemory?: ConciergeMemoryStore;
5430
+ /**
5431
+ * WP-V1.3-9 Tau-2: maximum prior turns folded into the substrate
5432
+ * context per round-trip. Defaults to
5433
+ * `DEFAULT_CONCIERGE_HISTORY_WINDOW_TURNS` (10). The current operator
5434
+ * turn is always present; this caps history only.
5435
+ */
5436
+ conciergeHistoryWindowTurns?: number;
5437
+ /**
5438
+ * WP-V1.3-9 Tau-2: prior turns older than this many milliseconds are
5439
+ * excluded from the active fold even when they remain on disk.
5440
+ * Defaults to `DEFAULT_CONCIERGE_HISTORY_FRESHNESS_MS` (24h).
5441
+ */
5442
+ conciergeHistoryFreshnessMs?: number;
5443
+ /**
5444
+ * WP-V1.3-9 Tau-2: rough token budget for the prior-conversation
5445
+ * portion of the substrate context. Estimated as ~4 chars per token.
5446
+ * Defaults to `DEFAULT_CONCIERGE_HISTORY_TOKEN_BUDGET` (500). The
5447
+ * static reference block + fortress sections are NOT subject to this
5448
+ * budget; only the prior-conversation fold is pruned oldest-first.
5449
+ */
5450
+ conciergeHistoryTokenBudget?: number;
5451
+ /**
5452
+ * WP-V1.3-9 Tau-2: how long an active session may stay quiet before
5453
+ * the next `sendConcierge` allocates a fresh thread_id. Defaults to
5454
+ * `DEFAULT_CONCIERGE_SESSION_TTL_MS` (24h). Does not delete the prior
5455
+ * thread; it remains readable through the memory store.
5456
+ */
5457
+ conciergeSessionTtlMs?: number;
5458
+ /**
5459
+ * Optional clock for the session-TTL + freshness checks. Tests inject
5460
+ * a deterministic clock; production lets the default `Date.now`-based
5461
+ * implementation run.
5462
+ */
5463
+ conciergeClock?: () => number;
5352
5464
  }
5353
5465
  declare class OperatorChatService {
5354
5466
  private store;
@@ -5359,6 +5471,11 @@ declare class OperatorChatService {
5359
5471
  private piiFilter?;
5360
5472
  private conciergeMaxTokens;
5361
5473
  private memory?;
5474
+ private historyWindowTurns;
5475
+ private historyFreshnessMs;
5476
+ private historyTokenBudget;
5477
+ private sessionTtlMs;
5478
+ private clock;
5362
5479
  /**
5363
5480
  * In-memory thread_id assigned to the active concierge session.
5364
5481
  * The first sendConcierge call after construction allocates a fresh
@@ -5366,6 +5483,14 @@ declare class OperatorChatService {
5366
5483
  * folds the prior turns into context. Cleared by `resetConciergeMemoryThread`.
5367
5484
  */
5368
5485
  private activeMemoryThreadId?;
5486
+ /**
5487
+ * Wall-clock ms of the most recent sendConcierge that touched the
5488
+ * active session thread. Drives the WP-V1.3-9 Tau-2 session-TTL
5489
+ * check: a fresh sendConcierge after `sessionTtlMs` of quiet
5490
+ * allocates a new thread_id even though the prior one is still
5491
+ * readable from the memory store.
5492
+ */
5493
+ private lastInteractionAt?;
5369
5494
  constructor(deps: OperatorChatServiceDeps);
5370
5495
  /**
5371
5496
  * Operator submit on the concierge surface. Persists the operator's
@@ -5378,6 +5503,13 @@ declare class OperatorChatService {
5378
5503
  * operator sees on the page (no silent dropping).
5379
5504
  */
5380
5505
  sendConcierge(query: string): Promise<ConciergeResponse>;
5506
+ /**
5507
+ * Emit the WP-V1.3-9 Tau-2 graceful-degradation audit event. Pulled
5508
+ * out of `sendConcierge` so the read-fold path stays readable. Emits
5509
+ * with `result: "failure"` since the concierge fell back to
5510
+ * single-turn mode for this round-trip.
5511
+ */
5512
+ private emitMemoryReadFailed;
5381
5513
  /**
5382
5514
  * Read the persisted concierge thread, oldest message first. Returns
5383
5515
  * an empty array when no thread exists yet.
@@ -5424,6 +5556,11 @@ declare class OperatorChatService {
5424
5556
  * ## Sanctuary reference
5425
5557
  * <static domain reference block>
5426
5558
  *
5559
+ * ## Prior conversation ← WP-V1.3-9 Tau-2, when present
5560
+ * OPERATOR: ...
5561
+ * CONCIERGE: ...
5562
+ * ---
5563
+ *
5427
5564
  * ## Recent activity
5428
5565
  * <recentActivity output>
5429
5566
  *
@@ -5433,8 +5570,22 @@ declare class OperatorChatService {
5433
5570
  * ## Open inbox
5434
5571
  * <openInbox output>
5435
5572
  * ```
5573
+ *
5574
+ * The substrate selector ships a `context: string` shape (not a
5575
+ * messages array), so multi-turn coherence is folded as a structured
5576
+ * prior-conversation section with explicit OPERATOR / CONCIERGE
5577
+ * boundaries. Coordinator-CTO guidance: prefer messages-array shape
5578
+ * if available; the v1.2 selector does not expose one, so structured
5579
+ * serialization is the canonical path for v1.3.
5436
5580
  */
5437
5581
  private assembleConciergeContext;
5582
+ /**
5583
+ * Render the prior-conversation section with token-budget enforcement
5584
+ * (WP-V1.3-9 Tau-2). Drops oldest turns first when the rendered
5585
+ * section exceeds `historyTokenBudget`. Returns an empty string when
5586
+ * the input is empty or when the budget excludes every turn.
5587
+ */
5588
+ private formatPriorTurnsSection;
5438
5589
  private emit;
5439
5590
  }
5440
5591