@sema-agent/core 5.47.0 → 5.49.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 (73) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/dist/agents/agent-transcript-tool.d.ts +4 -0
  3. package/dist/agents/agent-transcript-tool.js +10 -3
  4. package/dist/agents/send-message-tool.d.ts +43 -1
  5. package/dist/agents/send-message-tool.js +50 -11
  6. package/dist/agents/subagent.d.ts +18 -0
  7. package/dist/agents/subagent.js +102 -2
  8. package/dist/agents/teacher.d.ts +25 -1
  9. package/dist/agents/teacher.js +85 -12
  10. package/dist/config/defaults.d.ts +20 -0
  11. package/dist/config/defaults.js +5 -0
  12. package/dist/core/background-agent-store.d.ts +1 -0
  13. package/dist/core/background-agent-store.js +14 -0
  14. package/dist/core/mcp.d.ts +6 -1
  15. package/dist/core/mcp.js +34 -7
  16. package/dist/core/memory-engine/delegation-settlement.d.ts +27 -0
  17. package/dist/core/memory-engine/delegation-settlement.js +31 -4
  18. package/dist/core/memory-engine/dual-root.js +11 -0
  19. package/dist/core/memory-engine/engine.d.ts +6 -1
  20. package/dist/core/memory-engine/engine.js +136 -21
  21. package/dist/core/memory-engine/memory-backend-contract.js +33 -0
  22. package/dist/core/memory-engine/origin-clearance.d.ts +19 -0
  23. package/dist/core/memory-engine/origin-clearance.js +10 -0
  24. package/dist/core/memory-engine/provenance-wording.d.ts +15 -1
  25. package/dist/core/memory-engine/provenance-wording.js +1 -0
  26. package/dist/core/memory-engine/tools.js +6 -4
  27. package/dist/core/reminder-disclosure.d.ts +90 -0
  28. package/dist/core/reminder-disclosure.js +64 -0
  29. package/dist/core/runner/prepare-acquire-reconcile.d.ts +6 -0
  30. package/dist/core/runner/prepare-acquire-reconcile.js +1 -1
  31. package/dist/core/runner/prepare-hands-readface.d.ts +4 -0
  32. package/dist/core/runner/prepare-hands-readface.js +1 -0
  33. package/dist/core/runner/prepare-task.d.ts +15 -0
  34. package/dist/core/runner/prepare-task.js +51 -33
  35. package/dist/core/runner/runtask.d.ts +26 -1
  36. package/dist/core/runner/runtask.js +21 -3
  37. package/dist/core/session-store.d.ts +59 -1
  38. package/dist/core/session-store.js +82 -14
  39. package/dist/core/session.d.ts +83 -1
  40. package/dist/core/strategy-store.d.ts +180 -3
  41. package/dist/core/strategy-store.js +172 -23
  42. package/dist/core/task-registry-agent.d.ts +28 -0
  43. package/dist/core/task-registry-agent.js +63 -2
  44. package/dist/core/task-registry.d.ts +21 -0
  45. package/dist/core/task-registry.js +4 -1
  46. package/dist/core/types.d.ts +66 -0
  47. package/dist/core/untrusted-text.d.ts +63 -0
  48. package/dist/core/untrusted-text.js +48 -0
  49. package/dist/core/wiring-manifest.d.ts +35 -0
  50. package/dist/core/wiring-manifest.js +21 -1
  51. package/dist/engine/harness/types.d.ts +36 -1
  52. package/dist/index.d.ts +7 -6
  53. package/dist/index.js +6 -5
  54. package/dist/internal/harness-types.d.ts +1 -0
  55. package/dist/stores/file/file-snapshot-store.js +7 -1
  56. package/dist/stores/file/index.d.ts +27 -3
  57. package/dist/stores/file/index.js +36 -1
  58. package/dist/stores/file/session-policy-store.d.ts +0 -13
  59. package/dist/stores/file/session-policy-store.js +7 -1
  60. package/dist/stores/file/session-store.d.ts +22 -5
  61. package/dist/stores/file/session-store.js +80 -13
  62. package/dist/stores/file/strategy-store.d.ts +97 -0
  63. package/dist/stores/file/strategy-store.js +340 -0
  64. package/dist/tools/fs/fs-pdf.d.ts +12 -1
  65. package/dist/tools/fs/fs-pdf.js +17 -3
  66. package/dist/tools/fs/fs-read.d.ts +2 -1
  67. package/dist/tools/fs/fs-read.js +33 -5
  68. package/dist/tools/fs/fs-shared.d.ts +6 -2
  69. package/dist/tools/fs/index.d.ts +7 -0
  70. package/dist/tools/fs/index.js +1 -1
  71. package/dist/tools/web.js +21 -2
  72. package/package.json +3 -2
  73. package/test/export-surface.snapshot.json +22 -1
@@ -7,6 +7,23 @@ import { delimitUntrusted } from "./untrusted-text.js";
7
7
  import { boundedRedactedSummary } from "./untrusted-egress.js";
8
8
  import { mintCompletionId, commitCompletionIdIfEmpty, clipTaskOutput, assertOwnership, sleepPollStep, alreadyTerminalStopNote, canAccess, normalizeAgentName, closestName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE, BG_AGENT_REAP_STOP_ERROR, } from "./task-registry-shared.js";
9
9
  import { buildToolResultRef, OFFLOAD_TOOL_NAME, toolResultProvenanceOf } from "./tool-result-store.js";
10
+ export function activeDelegationHandlesLane(core, scope, rootSessionId) {
11
+ const out = [];
12
+ for (const h of core.handles.values()) {
13
+ if (h.type !== "background_agent")
14
+ continue;
15
+ if (h.status !== "running" && h.status !== "pending")
16
+ continue;
17
+ if (h.scope !== scope)
18
+ continue;
19
+ const bh = h;
20
+ const root = bh.rootSessionId ?? bh.parentSessionId ?? (bh.sessionScoped ? bh.owner : undefined);
21
+ if (root !== rootSessionId)
22
+ continue;
23
+ out.push(h.id);
24
+ }
25
+ return out;
26
+ }
10
27
  export function ensureDurableHeartbeatLane(core) {
11
28
  if (core.durableHeartbeatTimer !== undefined)
12
29
  return;
@@ -170,7 +187,7 @@ export async function reapDurableAgentsLane(core, scope, deps, policy) {
170
187
  await deps.store.reap(scope, now, { staleRunningMaxAgeMs: policy.staleRunningMaxAgeMs });
171
188
  }
172
189
  if (policy.maxAgeMs === undefined && policy.keep === undefined)
173
- return { rowsReaped: 0, sessionsReleased: 0, skippedNoSessions: 0 };
190
+ return { rowsReaped: 0, sessionsReleased: 0, skippedNoSessions: 0, orphanPlacedReleased: 0 };
174
191
  const terminal = (await deps.store.listByScope(scope)).filter((r) => r.status !== "running" && r.status !== "parked");
175
192
  terminal.sort((a, b) => b.spawnedAt - a.spawnedAt);
176
193
  const doomed = new Map();
@@ -239,7 +256,51 @@ export async function reapDurableAgentsLane(core, scope, deps, policy) {
239
256
  core.reapedHandles.delete(r.handle);
240
257
  }
241
258
  }
242
- return { rowsReaped, sessionsReleased, skippedNoSessions };
259
+ let orphanPlacedReleased = 0;
260
+ if (policy.maxAgeMs !== undefined && deps.sessions !== undefined && typeof deps.sessions.listPlaced === "function") {
261
+ let placed = [];
262
+ try {
263
+ placed = await deps.sessions.listPlaced("subagent", { olderThanMs: policy.maxAgeMs, scope });
264
+ }
265
+ catch {
266
+ placed = [];
267
+ }
268
+ for (const p of placed) {
269
+ if ("tupleIncomplete" in p)
270
+ continue;
271
+ if (p.scope !== scope)
272
+ continue;
273
+ if (core.claimingHandles.has(p.handle) || core.reapingHandles.has(p.handle))
274
+ continue;
275
+ let row;
276
+ try {
277
+ row = await deps.store.get(p.handle, scope);
278
+ }
279
+ catch {
280
+ continue;
281
+ }
282
+ if (row !== null)
283
+ continue;
284
+ const inProc = core.handles.get(p.handle);
285
+ if (inProc !== undefined && (inProc.status === "running" || inProc.status === "pending" || inProc.status === "parked"))
286
+ continue;
287
+ try {
288
+ await deps.sessions.unpin?.(p.sessionId);
289
+ await deps.sessions.release(p.sessionId);
290
+ orphanPlacedReleased++;
291
+ }
292
+ catch {
293
+ }
294
+ if (deps.mailbox !== undefined) {
295
+ try {
296
+ await deps.mailbox.drop(scope, p.handle);
297
+ }
298
+ catch {
299
+ }
300
+ }
301
+ }
302
+ }
303
+ return { rowsReaped, sessionsReleased, skippedNoSessions, orphanPlacedReleased };
243
304
  }
244
305
  export function releaseDurableTranscriptAnchorLane(core, id) {
245
306
  const handle = core.handles.get(id);
@@ -166,9 +166,24 @@ export declare class TaskRegistry {
166
166
  endDurableClaim(id: string): void;
167
167
  reapDurableAgents(scope: string, deps: {
168
168
  store: BackgroundAgentStore;
169
+ /** `listPlaced` (subagent transcript persistence, optional) arms the partition-orphan leg —
170
+ * see {@link reapDurableAgentsLane}. Pass the deployment's SessionStore directly (the
171
+ * TtlSessionStore over a placement-capable repo exposes it). */
169
172
  sessions?: {
170
173
  unpin?(sessionId: string): unknown;
171
174
  release(sessionId: string): Promise<void> | void;
175
+ listPlaced?(kind: "subagent", opts?: {
176
+ olderThanMs?: number;
177
+ scope?: string;
178
+ }): Promise<Array<{
179
+ sessionId: string;
180
+ placedAt: number;
181
+ } & ({
182
+ scope: string;
183
+ handle: string;
184
+ } | {
185
+ tupleIncomplete: true;
186
+ })>>;
172
187
  };
173
188
  /** design/151 §7.7 (F-13) — the row's mailbox dies with the row: a WINNING delete also drops
174
189
  * the (scope, handle) mailbox (advisory — a mailbox fault never blocks the reap; an orphaned
@@ -186,6 +201,7 @@ export declare class TaskRegistry {
186
201
  rowsReaped: number;
187
202
  sessionsReleased: number;
188
203
  skippedNoSessions: number;
204
+ orphanPlacedReleased: number;
189
205
  }>;
190
206
  releaseDurableTranscriptAnchor(id: string): void;
191
207
  bindBackgroundAgentSession(id: string, sessionId: string): void;
@@ -270,6 +286,11 @@ export declare class TaskRegistry {
270
286
  /** #258 — the row's current stop-cycle counter, read by the spawn lanes right after registering to
271
287
  * thread into the child's `RunInternals.cycleSeq`; see {@link backgroundAgentCycleSeqLane}. */
272
288
  backgroundAgentCycleSeq(id: string): number | undefined;
289
+ /** Subagent transcript persistence (delegation entry caps) — one delegation tree's ACTIVE
290
+ * (running/pending) a* handles in THIS process, keyed `(scope, rootSessionId)`; SYNCHRONOUS by
291
+ * contract (the caps check and the registration form one atomic segment). See
292
+ * {@link activeDelegationHandlesLane}. */
293
+ activeDelegationHandles(scope: string, rootSessionId: string): string[];
273
294
  /** ASYNC (revive arbitration) — the durable half is a guarded ownership claim on the row (awaited before the
274
295
  * in-memory flip), so this leg and a cross-process claim arbitrate in one domain instead of both
275
296
  * believing they own the cycle. See {@link reviveBackgroundAgentLane}. */
@@ -10,7 +10,7 @@ import { registerWorkflowLane, pollWorkflowLane, stopWorkflowLane } from "./task
10
10
  import { mintCompletionId, canAccessWorkflowRun, formatWorkflowRun, clipTaskOutput, assertOwnership, sleepPollStep, statusFromBackground, rollSpoolText, accountDroppedBytes, renderSpoolBody, spoolDropNote, droppedGapNote, alreadyTerminalStopNote, terminalTaskSummary, TASK_OUTPUT_MAX_CHARS, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccess, DURABLE_AGENT_HANDLE_RE, } from "./task-registry-shared.js";
11
11
  export { normalizeAgentName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE, BG_AGENT_REAP_STOP_ERROR } from "./task-registry-shared.js";
12
12
  import { TASK_OUTPUT_TOOL_NAME, TASK_STOP_TOOL_NAME, TASK_OUTPUT_CONTRACT, TASK_STOP_CONTRACT, TASK_OUTPUT_MISSING_ID_MESSAGE, TASK_STOP_MISSING_ID_MESSAGE, TASK_STOP_PARAMS, resolveTaskIdArg, REGISTRY_TASK_TOOL_CAPS, composeTaskOutputDescription, composeTaskOutputParams, composeTaskStopDescription, } from "./task-tool-shape.js";
13
- import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, recordBackgroundAgentOrgAdmissionLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, backgroundAgentCycleSeqLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
13
+ import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, recordBackgroundAgentOrgAdmissionLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, backgroundAgentCycleSeqLane, activeDelegationHandlesLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
14
14
  export { canAccessWorkflowRun, clipTaskOutput, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE };
15
15
  const BLOCK_DEFAULT_TIMEOUT_MS = 30_000;
16
16
  const BLOCK_MAX_TIMEOUT_MS = 600_000;
@@ -194,6 +194,9 @@ export class TaskRegistry {
194
194
  backgroundAgentCycleSeq(id) {
195
195
  return backgroundAgentCycleSeqLane(this.core, id);
196
196
  }
197
+ activeDelegationHandles(scope, rootSessionId) {
198
+ return activeDelegationHandlesLane(this.core, scope, rootSessionId);
199
+ }
197
200
  reviveBackgroundAgent(id, access, abort) {
198
201
  return reviveBackgroundAgentLane(this.core, id, access, abort);
199
202
  }
@@ -643,6 +643,27 @@ export interface ToolExecuteContext {
643
643
  * Undefined when the tool runs outside a Runner task.
644
644
  */
645
645
  reminderMark?: string;
646
+ /**
647
+ * design/319 (B ticket) — the RUNNING task's reminder-disclosure trigger counters
648
+ * ({@link import("./reminder-disclosure.js").ReminderDisclosureCounts}), Runner-filled on the same
649
+ * trusted seat as {@link reminderMark}. Caller-mounted verbatim outlets that run the
650
+ * detect-and-disclose pipeline (the web tools' exact-mark defuse arm) bump their `<outlet>.<form>`
651
+ * keys here; the Runner folds the non-zero result into
652
+ * `TaskResult.stats.mechanisms.reminderDisclosures`. Mutable by design (a counter seat), but only
653
+ * ever additive — never a decision input. Undefined outside a Runner task.
654
+ */
655
+ reminderDisclosureCounts?: import("./reminder-disclosure.js").ReminderDisclosureCounts;
656
+ /**
657
+ * Subagent transcript persistence — the RESOLVED delegation entry caps for this run
658
+ * ({@link RunnerDeps.delegationEntryCaps} after prepare's loud validation; both members always
659
+ * present). Runner-filled trusted seat, never a model argument — the Agent tool's background lane
660
+ * reads it at its registration point. Undefined outside a Runner task (the lane then applies the
661
+ * exported defaults itself, so a directly-driven tool is bounded too).
662
+ */
663
+ delegationEntryCaps?: {
664
+ maxConcurrent: number;
665
+ maxCumulativePerSession: number;
666
+ };
646
667
  /**
647
668
  * Report usage spent in a nested run this tool spawned (e.g. a sub-agent). The Runner accumulates
648
669
  * it into the parent task's `TaskResult.stats.nested`, so delegated cost — the multi-agent "~15×"
@@ -3295,6 +3316,15 @@ export interface TaskResult {
3295
3316
  reps: number;
3296
3317
  segment: string;
3297
3318
  }>;
3319
+ /** design/319 (B ticket, G9② observation seat) — reminder-disclosure trigger counts for the
3320
+ * leg, keyed `<outlet>.<form>`: outlets `read` / `notebook` / `pdf` / `mcp` / `webFetch` /
3321
+ * `webSearch`; forms `bare` (bare-form trailer appended), `marked` (marked-form trailer —
3322
+ * never throttled), `bare_throttled` (a bare trailer suppressed by the 60s per-key window),
3323
+ * `defused` (an MCP/web segment's exact-mark bytes were rewritten — the lane's one sanctioned
3324
+ * byte change, always paired with a `marked` disclosure). Present only when ≥1 key is
3325
+ * non-zero. This is the D-4/D-6 re-ruling data (defuse/trailer widening to Read/Bash/Grep):
3326
+ * a reading, never a gate. */
3327
+ reminderDisclosures?: Record<string, number>;
3298
3328
  };
3299
3329
  /**
3300
3330
  * design/91 — **human-review burden** (design/89 §2.4 C2 axis). The wall-clock time a task spent waiting
@@ -4700,6 +4730,11 @@ export interface EngineNotice {
4700
4730
  * `detail: { total, stripped: [{ key, reason }], omitted? }`, the rendered key list bounded in count
4701
4731
  * and length because the names come from the untrusted script. One aggregated notice per governed
4702
4732
  * child build, not de-duplicated across builds: each spec is a distinct fact.
4733
+ * - `"config.models_swapped"` — `Runner.swapModels` replaced the model catalog generation
4734
+ * (zero-restart model switching). `detail: { models, tiers }` — key COUNTS only, never the
4735
+ * catalog itself. In-flight tasks finish on the models they resolved at prepare (natural
4736
+ * snapshot); every later prepare resolves against the new generation. A failed swap (illegal
4737
+ * tier binding) throws atomically and mints nothing.
4703
4738
  * - `"config.read_face_deployment_clamped"` (#237) — a deployment-wide `readFace: "open"` is not
4704
4739
  * in force beside a read-only (verifier) mount: it clamps to "roots" without throwing
4705
4740
  * (stricter-wins; the clamp verdict stands, only its occurrence was undisclosed). Announced
@@ -4800,6 +4835,15 @@ export interface EngineNotice {
4800
4835
  * mark would have carried, neutralized/length-bounded (tool and agent-type names are
4801
4836
  * host/model-controlled inputs).
4802
4837
  *
4838
+ * - `"delegation.transcript_integrity"` (subagent transcript persistence) — a durable agent row
4839
+ * with a BOUND transcript sessionId met a session store that attests `not_found` for it: the
4840
+ * deployment's declared transcript durability is being contradicted by reality. Announced at
4841
+ * most once per (scope, handle, process) — `detail: { handle, scope? }`, scope = the resolved
4842
+ * access scope of the read that found the gap — from the continuation read faces (SendMessage preflight /
4843
+ * AgentTranscript's durable leg); the per-call honest refusals are unchanged, and the declared
4844
+ * tier is NOT auto-downgraded (declaration-制 — observation reports, it never re-adjudicates);
4845
+ * `detail: { handle }`.
4846
+ *
4803
4847
  * Deliberately NOT a notice family: brain retry/reconnect liveness (a rate limit, a 5xx, a
4804
4848
  * transient network failure being retried). Those are per-attempt liveness frames with their own
4805
4849
  * frequency semantics and ride the wire `status` channel ({@link BrainStatus}), whose sink the
@@ -5305,6 +5349,28 @@ export interface RunnerDeps {
5305
5349
  * Same single-instance pairing discipline as `backgroundAgentStore` (RB-37): a deployment that
5306
5350
  * composes its own tools must thread the SAME instance everywhere. */
5307
5351
  mailboxStore?: import("./mailbox-store.js").MailboxStore;
5352
+ /**
5353
+ * Subagent transcript persistence — the delegation ENTRY caps (CC parity values: 20 concurrent /
5354
+ * 200 cumulative per session tree; defaults exported as `DELEGATION_MAX_CONCURRENT_DEFAULT` /
5355
+ * `DELEGATION_MAX_PER_SESSION_DEFAULT`). Key = `(scope, rootSessionId)`, full depth (grandchildren
5356
+ * share the tree's pool). `maxConcurrent` bounds running/pending a* handles in this process's
5357
+ * registry (parked does not burn a slot — a suspension is not concurrency; a revival claim counts
5358
+ * like a spawn); `maxCumulativePerSession` bounds the RETAINED-WINDOW cumulative count (registry-
5359
+ * retained + store-retained rows — a reaped row returns its quota; deliberately NOT CC's lifetime-
5360
+ * monotonic session counter, which would require a persistent counting surface this economic bound
5361
+ * does not justify — registered divergence). Refusals are coded (`delegation.concurrency_cap` /
5362
+ * `delegation.session_cap`) with the current value and this knob's name in the text.
5363
+ *
5364
+ * BAD VALUES REFUSE LOUDLY at prepare (`config.delegation_entry_caps`, the #123 posture): a
5365
+ * non-positive/non-integer/NaN member, or a resolved pair where `maxConcurrent` exceeds
5366
+ * `maxCumulativePerSession` (you cannot run more at once than you may ever create) — never a
5367
+ * silent fold to the defaults. Per-replica bound (multi-replica deployments are each honestly
5368
+ * bounded; row-level CAS owns correctness, this cap owns economics).
5369
+ */
5370
+ delegationEntryCaps?: {
5371
+ maxConcurrent?: number;
5372
+ maxCumulativePerSession?: number;
5373
+ };
5308
5374
  /** design/176 — deployment tuning for the always-on peer-message admission gate (SendMessage entry
5309
5375
  * judgment: rate/dedup/hop-chain/queue bounds). Per-field range-validated against the upstream
5310
5376
  * table with out-of-range values falling back to that field's default; there is NO off switch —
@@ -16,6 +16,69 @@
16
16
  * own (instructions and data share one channel). The real boundary is decorrelation + reading the objective
17
17
  * artifact (the diff / working tree) rather than the worker's self-report (design/53 §3, design/54 §3).
18
18
  */
19
+ /** design/319 (B ticket) — what one reminder-shaped scan of an external projection found. */
20
+ export interface ReminderShapedScan {
21
+ /** ≥1 reminder-shaped tag (open or close; attribute/case/whitespace tolerant) is present. */
22
+ hit: boolean;
23
+ /** Some reminder-shaped TAG's own bytes contain the session's exact mark value — the strongest
24
+ * verdict (a full scan decides this, never the first match: a bare decoy ahead of a marked
25
+ * forgery must still be judged marked). `false` whenever `mark` is `undefined`. */
26
+ hadCurrentMark: boolean;
27
+ }
28
+ /**
29
+ * design/319 (B ticket) — the ONE detection predicate for reminder-shaped text in EXTERNAL data
30
+ * (the Read/notebook/PDF/MCP disclosure trailers and the MCP/web exact-mark defuse all judge with
31
+ * THIS scan). It reads the same {@link SYSTEM_REMINDER} regex the neutralizer rewrites with, so
32
+ * "what gets defused on contained lanes" and "what gets disclosed on verbatim lanes" can never
33
+ * drift apart — do not hand-copy the tag pattern anywhere else (same single-source discipline as
34
+ * {@link defuseFenceMarkers}). Attribute-tolerant / case-insensitive / tag-internal whitespace
35
+ * tolerant by construction; a tag the regex does not recognize is NOT a hit (the residual gap
36
+ * between this grammar and what a model might read as authority is an accepted, documented
37
+ * residual — same class as the Unicode-lookalike note on {@link defuseFenceMarkers}).
38
+ *
39
+ * The scan is read-only over the FINALIZED projection (post concatenation/truncation, pre any
40
+ * trusted tail) — callers must scan BEFORE any byte-changing transform (design/319 §3e four-step
41
+ * order): a defused/neutralized projection no longer carries the exact mark, so scanning after
42
+ * would misreport a marked forgery as the bare form (the lying-disclosure shape).
43
+ */
44
+ export declare function scanReminderShaped(text: string, mark: string | undefined): ReminderShapedScan;
45
+ /**
46
+ * design/319 §3b (B ticket) — EXACT-MARK defuse for the MCP-success/web outlets: insert a ZWSP
47
+ * inside every occurrence of the session's exact mark value so the bytes no longer spell the
48
+ * current mark. This is the ONE sanctioned byte change on those lanes (their zero-byte-change
49
+ * invariant's single exception): a server/page legitimately producing the 22-char session mark has
50
+ * definitionally zero probability — the value lives only in this session's prompt and checkpoint —
51
+ * so an occurrence is either a forgery or a leak echo, and defusing it turns a silent authority
52
+ * forgery into a visible mismatch (the accepted failure direction; a legitimate round-trip echo of
53
+ * a leaked mark defuses too, and the next hop then fails loudly instead of re-arming the forgery).
54
+ * NEVER applied on Read/Bash/Grep (the strong quote-back lanes stay verbatim — ruled, observation
55
+ * seat only). Idempotent: the rewritten text no longer contains the exact mark (ZWSP is not a
56
+ * base64url character, so the insertion can also never synthesize a new occurrence).
57
+ */
58
+ export declare function defuseExactMark(text: string, mark: string): string;
59
+ /**
60
+ * design/319 §3b — the SEGMENT form of {@link defuseExactMark} (adversarial round: a server can
61
+ * split the mark across adjacent MCP text blocks; the block seam is invisible in the model-facing
62
+ * concatenation, so a per-segment defuse would be a bypass). Judged over the JOINED projection and
63
+ * the ZWSP insertion mapped back into the owning segment, so the post-defuse concatenation NEVER
64
+ * contains the exact mark — including occurrences that straddle one or more seams (one ZWSP inside
65
+ * the occurrence's span breaks it wherever the split fell). Returns the same array (`changed:
66
+ * false`) when the joined projection has no occurrence; otherwise fresh segment strings whose
67
+ * concatenation equals the single-string form's output byte for byte (it IS the single-string
68
+ * form's implementation).
69
+ *
70
+ * OVERLAP-AWARE (adversarial round 2): a BORDERED mark (first character = last character — ~1/64
71
+ * random mints) admits overlapping occurrences (`mark + mark.slice(1)` carries two, one starting on
72
+ * the other's final character), so enumeration advances ONE character per match, never by the mark
73
+ * length — a skip-by-length walk defused the first and left the second exact while the trailer
74
+ * claimed neutralization. Every enumerated occurrence gets a ZWSP inside its own span; ZWSP is not
75
+ * a base64url character, so insertions can never synthesize a new occurrence and the result is
76
+ * idempotent (no exact mark survives ⇒ a second pass is byte-identical).
77
+ */
78
+ export declare function defuseExactMarkInSegments(segments: readonly string[], mark: string): {
79
+ segments: string[];
80
+ changed: boolean;
81
+ };
19
82
  /**
20
83
  * Neutralize structural break-out sequences in UNTRUSTED text so it can't escape its framing into
21
84
  * model-facing instructions. Always neutralizes `<system-reminder>` / `</system-reminder>` (the codebase's
@@ -12,6 +12,54 @@ function breakoutRe(extraTags) {
12
12
  }
13
13
  return re;
14
14
  }
15
+ export function scanReminderShaped(text, mark) {
16
+ let hit = false;
17
+ let hadCurrentMark = false;
18
+ for (const m of text.matchAll(SYSTEM_REMINDER)) {
19
+ hit = true;
20
+ if (mark !== undefined && m[0].includes(mark)) {
21
+ hadCurrentMark = true;
22
+ break;
23
+ }
24
+ if (mark === undefined)
25
+ break;
26
+ }
27
+ return { hit, hadCurrentMark };
28
+ }
29
+ export function defuseExactMark(text, mark) {
30
+ return defuseExactMarkInSegments([text], mark).segments[0];
31
+ }
32
+ export function defuseExactMarkInSegments(segments, mark) {
33
+ const joined = segments.join("");
34
+ if (mark.length === 0 || !joined.includes(mark))
35
+ return { segments: [...segments], changed: false };
36
+ const positions = [];
37
+ for (let at = joined.indexOf(mark); at !== -1; at = joined.indexOf(mark, at + 1))
38
+ positions.push(at + 1);
39
+ const out = [];
40
+ let start = 0;
41
+ let pi = 0;
42
+ for (const seg of segments) {
43
+ const end = start + seg.length;
44
+ if (pi >= positions.length || positions[pi] > end) {
45
+ out.push(seg);
46
+ }
47
+ else {
48
+ const parts = [];
49
+ let prev = 0;
50
+ while (pi < positions.length && positions[pi] > start && positions[pi] <= end) {
51
+ const local = positions[pi] - start;
52
+ parts.push(seg.slice(prev, local), ZWSP);
53
+ prev = local;
54
+ pi++;
55
+ }
56
+ parts.push(seg.slice(prev));
57
+ out.push(parts.join(""));
58
+ }
59
+ start = end;
60
+ }
61
+ return { segments: out, changed: true };
62
+ }
15
63
  export function sanitizeUntrustedText(text, extraTags = []) {
16
64
  return text.replace(breakoutRe(extraTags), (m) => m.replace("<", "<" + ZWSP));
17
65
  }
@@ -126,9 +126,18 @@ export interface WiringManifest {
126
126
  session: {
127
127
  store: ManifestDurability;
128
128
  };
129
+ /** `subagentTranscripts` — subagent transcript persistence: the deployment-level delegation-
130
+ * transcript durability TIER, a pure declaration read ({@link resolveSubagentTranscriptTier}):
131
+ * `none` = no agent-row store (pre-151 in-memory lifecycle); `rows` = rows + terminal snapshots
132
+ * survive a restart, transcripts follow the session store's fate; `full` = the C18 promise —
133
+ * a completed/failed/killed(non-user) subagent minted through the deps-visible assembly is
134
+ * continuable across a process restart. A statement about the DEPS-VISIBLE assembly only: a
135
+ * caller-mounted Agent tool over its own runner is outside this manifest's sight (per-read
136
+ * honest degrade + the integrity notice own that case, never a fabricated tier). */
129
137
  fleet: {
130
138
  backgroundAgentStore: boolean;
131
139
  hostChildEventSink: boolean;
140
+ subagentTranscripts: SubagentTranscriptTier;
132
141
  };
133
142
  /** design/179 — the persisted allow-rule seam. The ONE loosening seam in the assembly, so its presence
134
143
  * is a fact an operator has to be able to read off the manifest rather than infer. `false` on a
@@ -201,6 +210,11 @@ export interface WiringFacts {
201
210
  checkpointDurability?: StoreDurability;
202
211
  sessionDurability: StoreDurability;
203
212
  backgroundAgentStoreWired: boolean;
213
+ /** Subagent transcript persistence — the declared delegation-transcript tier (see
214
+ * {@link WiringManifest.fleet}). Optional for external `deriveWiringManifest` callers: absent
215
+ * derives fail-closed from `backgroundAgentStoreWired` alone (`rows`/`none` — under-promise,
216
+ * never `full`); the engine's own halves always pass the resolved value. */
217
+ subagentTranscriptTier?: SubagentTranscriptTier;
204
218
  /** design/179 — a persisted allow-rule store provider is wired. */
205
219
  permissionRuleStoreWired: boolean;
206
220
  /** design/182 §9 — the deployment declared that it drives cloud sync for that store. */
@@ -227,6 +241,27 @@ export type StaticWiringSpec = Pick<TaskSpec, "onAsk" | "onQuestion" | "checkpoi
227
241
  export declare function resolveDeclaredDurability(store: {
228
242
  readonly durability?: StoreDurability;
229
243
  } | undefined, storeName: string): StoreDurability;
244
+ /** Subagent transcript persistence — the deployment-level delegation-transcript durability tier
245
+ * (see {@link WiringManifest.fleet}). */
246
+ export type SubagentTranscriptTier = "none" | "rows" | "full";
247
+ /**
248
+ * Subagent transcript persistence — the ONE deployment-level tier derivation (pure declaration
249
+ * read, no probing, no class-name sniffing — the wiring-manifest posture): `none` without an
250
+ * agent-row store; with one, `full` iff the session store DECLARES its subagent placement
251
+ * partition durable, else `rows`. A junk placement declaration is refused loudly
252
+ * (`config.store_durability_invalid` — the resolveDeclaredDurability rule: an unparseable
253
+ * declaration silently folded to either arm would make the manifest lie in whichever direction the
254
+ * fold picked). This is the DEPLOYMENT-level judgment only; the per-handle "did this row's
255
+ * transcript actually land" question belongs to `durableAgentRowProbe` (the S1b release-flip gate)
256
+ * — two different questions, deliberately two named faces (do not merge them back into one).
257
+ */
258
+ export declare function resolveSubagentTranscriptTier(agentStoreWired: boolean, sessionStore: {
259
+ readonly placements?: {
260
+ subagent?: {
261
+ durability: StoreDurability;
262
+ };
263
+ };
264
+ } | undefined): SubagentTranscriptTier;
230
265
  /**
231
266
  * The ONE `ask.effective` derivation (design/173 codex 5) — shared by the effective manifest AND
232
267
  * the posture door (`config.interaction_posture`), so "what does the door require" and "what does
@@ -14,6 +14,21 @@ export function resolveDeclaredDurability(store, storeName) {
14
14
  throw e;
15
15
  }
16
16
  const manifestDurabilityOf = (d) => (d === "durable" ? "declared_durable" : "process_local");
17
+ export function resolveSubagentTranscriptTier(agentStoreWired, sessionStore) {
18
+ if (!agentStoreWired)
19
+ return "none";
20
+ const declared = sessionStore?.placements?.subagent?.durability;
21
+ if (declared === undefined)
22
+ return "rows";
23
+ if (declared === "durable")
24
+ return "full";
25
+ if (declared === "process-local")
26
+ return "rows";
27
+ const e = new Error(`sessionStore.placements.subagent.durability declares ${JSON.stringify(declared)} — not a recognized ` +
28
+ `StoreDurability ("durable" | "process-local"). Fix the declaration; an unparseable durability cannot be folded to either arm.`);
29
+ e.code = "config.store_durability_invalid";
30
+ throw e;
31
+ }
17
32
  export function deriveAskEffective(form, parkEffective) {
18
33
  switch (form) {
19
34
  case "callback":
@@ -85,7 +100,11 @@ export function deriveWiringManifest(facts) {
85
100
  elicit: { seamWired: facts.elicitSeamWired, serversOptedIn: facts.elicitServersOptedIn },
86
101
  parkLane,
87
102
  session: { store: manifestDurabilityOf(facts.sessionDurability) },
88
- fleet: { backgroundAgentStore: facts.backgroundAgentStoreWired, hostChildEventSink: facts.hostChildEventSinkWired },
103
+ fleet: {
104
+ backgroundAgentStore: facts.backgroundAgentStoreWired,
105
+ hostChildEventSink: facts.hostChildEventSinkWired,
106
+ subagentTranscripts: facts.subagentTranscriptTier ?? (facts.backgroundAgentStoreWired ? "rows" : "none"),
107
+ },
89
108
  permissionRules: {
90
109
  storeWired: facts.permissionRuleStoreWired,
91
110
  syncWired: facts.permissionRuleSyncWired,
@@ -182,6 +201,7 @@ export function describeStaticWiring(deps, spec = {}) {
182
201
  ...(capable ? { checkpointDurability: resolveDeclaredDurability(checkpointStore, "checkpointStore") } : {}),
183
202
  sessionDurability: resolveDeclaredDurability(deps.sessionStore, "sessionStore"),
184
203
  backgroundAgentStoreWired: deps.backgroundAgentStore !== undefined,
204
+ subagentTranscriptTier: resolveSubagentTranscriptTier(deps.backgroundAgentStore !== undefined, deps.sessionStore),
185
205
  permissionRuleStoreWired: deps.permissionRuleStore !== undefined,
186
206
  permissionRuleSyncWired: deps.permissionRuleSyncWired === true,
187
207
  permissionRuleOrgGoverned: deps.permissionRuleOrg !== undefined,
@@ -157,7 +157,7 @@ export declare class CompactionError extends Error {
157
157
  code: CompactionErrorCode;
158
158
  constructor(code: CompactionErrorCode, message: string, cause?: Error);
159
159
  }
160
- export type SessionErrorCode = "not_found" | "invalid_session" | "invalid_entry" | "invalid_fork_target" | "storage" | "conflict" | "unknown";
160
+ export type SessionErrorCode = "not_found" | "invalid_session" | "invalid_entry" | "invalid_fork_target" | "storage" | "conflict" | "placement_refused" | "unknown";
161
161
  /** Error thrown by session storage, repositories, and session tree operations. */
162
162
  export declare class SessionError extends Error {
163
163
  /** Session subsystem error code. */
@@ -170,6 +170,30 @@ export declare class AgentHarnessError extends Error {
170
170
  code: AgentHarnessErrorCode;
171
171
  constructor(code: AgentHarnessErrorCode, message: string, cause?: Error);
172
172
  }
173
+ /**
174
+ * The PERSISTED placement tuple of a session created into a placement partition (subagent
175
+ * transcript persistence — the durable half of the delegation continuation contract). Written ONCE
176
+ * at creation (first-write immutable: a later acquire never rewrites it) and carried on
177
+ * {@link SessionMetadata.placement}. The FULL tuple is persisted, not just a tag: `scope`+`handle`
178
+ * are the row-store join key the retention orchestration needs after a restart (a bare label could
179
+ * not tell "no row" from "a row in another tenant"), and `placedAt` anchors the age-based GC arm.
180
+ * A tuple missing either join half is treated by consumers as INCOMPLETE (fail-closed: never
181
+ * age-reaped, reported as such by placed listings).
182
+ */
183
+ export interface SessionPlacementRecord {
184
+ /** The one placement kind this contract defines today. */
185
+ kind: "subagent";
186
+ /** Tenant scope of the owning durable agent row (row-store join key half 1). */
187
+ scope?: string;
188
+ /** The spawning host session (partition/retrieval metadata — authorization stays on the row predicate). */
189
+ parentSessionId?: string;
190
+ /** The delegation tree's root host session (fixed point; enumeration anchor). */
191
+ rootSessionId?: string;
192
+ /** The durable agent row key (`a…` handle; row-store join key half 2). */
193
+ handle?: string;
194
+ /** Epoch ms the placement was created (stamped by the store at creation). */
195
+ placedAt: number;
196
+ }
173
197
  /** Metadata for one filesystem object in a {@link FileSystem}. */
174
198
  export interface FileInfo {
175
199
  /** Basename of {@link path}. */
@@ -644,6 +668,10 @@ export interface SessionMetadata {
644
668
  * fork lineage (e.g. reap forks whose parent is gone/expired). Absent on a non-forked session and on
645
669
  * forked sessions persisted before this field shipped. */
646
670
  forkedFrom?: string;
671
+ /** Subagent transcript persistence — the placement tuple this session was CREATED into (see
672
+ * {@link SessionPlacementRecord}). Absent on every ordinary (host-lane) session; a repo that does
673
+ * not understand placement never surfaces it (additive, old readers tolerate). */
674
+ placement?: SessionPlacementRecord;
647
675
  }
648
676
  export interface JsonlSessionMetadata extends SessionMetadata {
649
677
  cwd: string;
@@ -796,6 +824,13 @@ export interface Session<TMetadata extends SessionMetadata = SessionMetadata> {
796
824
  }
797
825
  export interface SessionCreateOptions {
798
826
  id?: string;
827
+ /** Subagent transcript persistence — create this session INTO a placement partition. The repo
828
+ * stamps `placedAt` and persists the tuple on its meta record (first-write immutable). A repo
829
+ * that does not understand placement IGNORES this key (legal degrade — the session is then an
830
+ * ordinary one; the store-level `placements` declaration is what promises understanding). */
831
+ placement?: Omit<SessionPlacementRecord, "placedAt"> & {
832
+ placedAt?: number;
833
+ };
799
834
  }
800
835
  export interface SessionForkOptions {
801
836
  entryId?: string;
package/dist/index.d.ts CHANGED
@@ -40,7 +40,7 @@ export type { RepetitionEvent, RepetitionInspection } from "./brain/repetition.j
40
40
  export { computeCostMicroUsd, modelCostToPricing, type ModelPricing, type TokenCounts, } from "./core/pricing.js";
41
41
  export { cacheFamilyOf, promptTokensOf, uncachedInputTokensOf, type CacheFamily } from "./core/runner/usage-accounting.js";
42
42
  export { emitTrace, type ToolDisclosureManifest, type TraceEvent, type TracerHook } from "./core/trace.js";
43
- export { InMemoryStrategyStore, type StrategyStore, type StoredStrategy } from "./core/strategy-store.js";
43
+ export { InMemoryStrategyStore, seedStrategies, type StrategyStore, type StoredStrategy, type StrategyOrigin, type StrategyStoreIncident, type SeedStrategyEntry, type SeedStrategiesReport, } from "./core/strategy-store.js";
44
44
  export { createSqlTool, validateReadOnlySql, type SqlToolOptions } from "./tools/sql.js";
45
45
  export { runWithTeacher, parseTeacherAdvice, TEACHER_PROMPT, type TeacherConfig, type TeacherAdvice, type EscalationRecord, type EscalationTrigger, type TeacherRunResult, } from "./agents/teacher.js";
46
46
  export { runWithVerification, resumeWithVerification, verifyCompleted, runDeveloperTask, VERIFICATION_PROMPT, STATIC_VERIFICATION_PROMPT, VerdictSchema, type Verdict, type VerifyConfig, type UnverifiedReason, type VerificationOutcome, type VerificationResult, type DeveloperTaskConfig, } from "./agents/verify.js";
@@ -64,7 +64,7 @@ export { GOVERNANCE_CODES, governanceRetryClass, type GovernanceCode, type Gover
64
64
  export { NOTICE_AUDIENCE, noticeAudienceOf } from "./core/governance-codes.js";
65
65
  export { TtlSessionStore, type TtlSessionStoreOptions, type EvictPolicy } from "./core/session-store.js";
66
66
  export { reconcileInterruptedSession, findOrphanToolCalls, type OrphanToolCall, type ReconcileReport, } from "./core/session-reconcile.js";
67
- export { StoredSession, InMemorySessionRepo, InMemorySessionStorage, BaseSessionStorage, leafIdAfterEntry, validateEntriesForImport, StreamingImportValidator, boundedTail, SessionError, isSessionConflict, hasSessionFork, uuidv7, type Session, type SessionStore, type AcquiredSession, type SessionStoreSummary, type SessionStorage, type SessionRepo, type SessionMetadata, type SessionTreeEntry, type SessionWriteOptions, } from "./core/session.js";
67
+ export { StoredSession, InMemorySessionRepo, InMemorySessionStorage, BaseSessionStorage, leafIdAfterEntry, validateEntriesForImport, StreamingImportValidator, boundedTail, SessionError, isSessionConflict, hasSessionFork, uuidv7, type Session, type SessionStore, type AcquiredSession, type SessionStoreSummary, type SessionStorage, type SessionRepo, type SessionMetadata, type SessionTreeEntry, type SessionWriteOptions, type SessionPlacement, type SessionPlacementRecord, type PlacedSessionRow, } from "./core/session.js";
68
68
  export { warmResume } from "./core/warm-resume.js";
69
69
  export { StubExecutionEnv } from "./core/stub-env.js";
70
70
  export { NodeExecutionEnv, FileError, ExecutionError } from "./internal/harness.js";
@@ -102,7 +102,7 @@ export { ENV_LIFETIME_SUSPEND_MARGIN_MS, USAGE_WINDOW_REAP_MARGIN_MS } from "./c
102
102
  export { InMemoryFileSnapshotStore, DEFAULT_SNAPSHOT_BOUNDS } from "./core/file-snapshot-store.js";
103
103
  export { captureManifest, applyManifest } from "./core/file-snapshot-store.js";
104
104
  export type { FileSnapshotStore, FileSnapshotResult, FileSnapshotError, FileSnapshotBounds } from "./core/file-snapshot-store.js";
105
- export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileFileSnapshotStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, type FileStorageBackendOptions, type FileStorageCorruptReadInfo, type FileSessionRepoOptions, type FileFileSnapshotStoreOptions, type FileCheckpointStoreOptions, } from "./stores/file/index.js";
105
+ export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileFileSnapshotStore, FileStrategyStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, type FileStorageBackendOptions, type FileStorageCorruptReadInfo, type FileStrategyStoreOptions, type FileSessionRepoOptions, type FileFileSnapshotStoreOptions, type FileCheckpointStoreOptions, } from "./stores/file/index.js";
106
106
  export { CacheBreakDetector, type CacheBreakFinding, type ToolFingerprintInput } from "./core/cache-break-detector.js";
107
107
  export { maybeCompact, type MaybeCompactOptions, type CompactionWindowSafetyInfo } from "./core/auto-compaction.js";
108
108
  export { brainToRuntime } from "./core/runtime.js";
@@ -111,7 +111,7 @@ export { createFsWriteGatePolicy, type FsWriteGatePolicyOptions } from "./core/f
111
111
  export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
112
112
  export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
113
113
  export { renderTaskNotificationXml, taskNotificationDedupKey, isDelegatedAgentTerminal, SystemInjectionQueue, type TaskNotificationPayload, type TaskNotificationStatus, type ExternalNotificationInput, type SystemInjection, type SystemInjectionPriority, } from "./core/task-notification.js";
114
- export { describeStaticWiring, deriveWiringManifest, deriveAskEffective, resolveDeclaredDurability, resolveAskSeamForm, resolveQuestionSeam, countElicitOptIns, type WiringManifest, type WiringFacts, type WiringLegKind, type AskSeamForm, type AskEffective, type QuestionChannelState, type SeamProvenance, type ParkLaneReason, type ManifestDurability, type StaticWiringDeps, type StaticWiringSpec, } from "./core/wiring-manifest.js";
114
+ export { describeStaticWiring, deriveWiringManifest, deriveAskEffective, resolveDeclaredDurability, resolveSubagentTranscriptTier, type SubagentTranscriptTier, resolveAskSeamForm, resolveQuestionSeam, countElicitOptIns, type WiringManifest, type WiringFacts, type WiringLegKind, type AskSeamForm, type AskEffective, type QuestionChannelState, type SeamProvenance, type ParkLaneReason, type ManifestDurability, type StaticWiringDeps, type StaticWiringSpec, } from "./core/wiring-manifest.js";
115
115
  export { probeParkRoundTrip, durableParkGapOf, durableParkGapFor, PARK_SELFCHECK_SCOPE_PREFIX, type ParkSelfCheckResult, type ParkProbeFinding, type ParkProbeFindingCode, } from "./core/park-selfcheck.js";
116
116
  export { type StoreDurability } from "./core/checkpoint-store.js";
117
117
  export { type StoreFidelity } from "./core/checkpoint-store.js";
@@ -234,10 +234,11 @@ export { summarizeRedactions } from "./core/untrusted-egress.js";
234
234
  export { MemoryRosterStore, FileRosterStore, type RosterStore, type RosterEntry, type RosterAccess, type RosterGcOptions } from "./agents/roster-store.js";
235
235
  export { CONFIG_CATALOG_VERSION, describeConfigCatalog, resolveEffectiveConfig, type ConfigKnob, type ConfigOverrideDeclaration, type ConfigProvenance, type EffectiveConfigField, } from "./config/catalog.js";
236
236
  export { normalizeAgentName } from "./core/task-registry.js";
237
+ export { DELEGATION_MAX_CONCURRENT_DEFAULT, DELEGATION_MAX_PER_SESSION_DEFAULT, ORPHAN_ADOPT_WINDOW_MS_DEFAULT, ORPHAN_ADOPT_MAX_DEFAULT, SUBAGENT_TRANSCRIPT_RETENTION_DAYS_DEFAULT, } from "./config/defaults.js";
237
238
  export { COORDINATOR_ROLE_PROMPT, TEAMMATE_COMMUNICATION_ADDENDUM, TEAMMATE_TASK_LIST_ADDENDUM } from "./prompts/coordinator.js";
238
- export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, type SubagentToolOptions, type SubagentSpawnContext, type SubagentSteerHandle, type SubagentStep, type SubagentEditedFile, } from "./agents/subagent.js";
239
+ export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, type SubagentToolOptions, resolveDelegationEntryCaps, type ResolvedDelegationEntryCaps, type SubagentSpawnContext, type SubagentSteerHandle, type SubagentStep, type SubagentEditedFile, } from "./agents/subagent.js";
239
240
  export { getSessionRetainLedger, releaseSessionRetainLedger, } from "./agents/retain-ledger.js";
240
- export { createSendMessageTool, SEND_MESSAGE_TOOL_NAME, type SendMessageToolOptions } from "./agents/send-message-tool.js";
241
+ export { createSendMessageTool, createAgentContinuationVerb, SEND_MESSAGE_TOOL_NAME, type SendMessageToolOptions, type AgentContinuationReceipt } from "./agents/send-message-tool.js";
241
242
  export { createPeerAdmission, peerAdmissionFor, judgePeerAdmission, resolvePeerAdmissionConfig, PEER_ADMISSION_DEFAULTS, PEER_HOP_CHAIN_WINDOW, PEER_MESSAGE_NOTICE, createPeerSelfRef, createPeerInboundChainRef, peerAxisToken, appendHopToken, type PeerAdmission, type PeerAdmissionConfig, type PeerAdmissionOptions, type PeerAdmissionRequest, type PeerAdmissionVerdict, type PeerAdmissionRefusal, type PeerRefusalCode, type PeerAxisTag, type PeerIdentity, type PeerSelfRef, type PeerInboundChainRef, } from "./agents/peer-admission.js";
242
243
  export { createAgentTranscriptTool, AGENT_TRANSCRIPT_TOOL_NAME, type AgentTranscriptToolOptions, } from "./agents/agent-transcript-tool.js";
243
244
  export { defineAgent } from "./agents/agent-definition.js";