@sema-agent/core 7.52.0 → 7.53.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 (191) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/README.md +3 -1
  3. package/dist/agents/cross-session-envelope.d.ts +8 -0
  4. package/dist/agents/cross-session-envelope.js +6 -0
  5. package/dist/agents/cross-session-judge.d.ts +21 -1
  6. package/dist/agents/cross-session-judge.js +8 -0
  7. package/dist/agents/cross-session-ref.d.ts +5 -0
  8. package/dist/agents/cross-session-ref.js +1 -0
  9. package/dist/agents/org-delivery-gate.d.ts +122 -0
  10. package/dist/agents/org-delivery-gate.js +69 -0
  11. package/dist/agents/peer-held-queue.d.ts +9 -4
  12. package/dist/agents/peer-held-queue.js +6 -5
  13. package/dist/agents/peer-session-drain.d.ts +35 -5
  14. package/dist/agents/peer-session-drain.js +271 -180
  15. package/dist/agents/read-inbox-tool.d.ts +7 -0
  16. package/dist/agents/read-inbox-tool.js +5 -1
  17. package/dist/agents/subagent.d.ts +3 -0
  18. package/dist/agents/subagent.js +99 -72
  19. package/dist/agents/tool-filter.d.ts +18 -0
  20. package/dist/agents/tool-filter.js +6 -0
  21. package/dist/brain/anthropic.d.ts +6 -1
  22. package/dist/brain/anthropic.js +4 -4
  23. package/dist/brain/model-presets.js +2 -1
  24. package/dist/brain/route-adjudicator.d.ts +6 -0
  25. package/dist/brain/routing.d.ts +24 -1
  26. package/dist/brain/routing.js +54 -19
  27. package/dist/brain/timeout.js +5 -4
  28. package/dist/core/a2a.d.ts +5 -2
  29. package/dist/core/a2a.js +30 -13
  30. package/dist/core/allow-entry.d.ts +2 -1
  31. package/dist/core/allow-entry.js +2 -2
  32. package/dist/core/auto-compaction.d.ts +57 -0
  33. package/dist/core/auto-compaction.js +28 -2
  34. package/dist/core/checkpoint-store.d.ts +29 -20
  35. package/dist/core/checkpoint-store.js +3 -3
  36. package/dist/core/compliance.js +3 -1
  37. package/dist/core/effective-path-target.d.ts +25 -6
  38. package/dist/core/effective-path-target.js +24 -2
  39. package/dist/core/engine-notice.d.ts +13 -2
  40. package/dist/core/gate-fold.js +3 -2
  41. package/dist/core/gate-lanes.js +11 -13
  42. package/dist/core/gate-outcome.d.ts +11 -6
  43. package/dist/core/governance-codes.d.ts +3 -1
  44. package/dist/core/governance-codes.js +3 -0
  45. package/dist/core/hands-band-screen.d.ts +7 -0
  46. package/dist/core/hands-band-screen.js +32 -0
  47. package/dist/core/hooks.d.ts +7 -5
  48. package/dist/core/hooks.js +5 -3
  49. package/dist/core/locked-config.d.ts +84 -32
  50. package/dist/core/locked-config.js +128 -42
  51. package/dist/core/mcp-probe.js +1 -1
  52. package/dist/core/mcp-server-spec.d.ts +88 -10
  53. package/dist/core/mcp-server-spec.js +183 -33
  54. package/dist/core/mcp.d.ts +21 -14
  55. package/dist/core/mcp.js +55 -51
  56. package/dist/core/memory-engine/engine.d.ts +14 -19
  57. package/dist/core/memory-engine/engine.js +7 -5
  58. package/dist/core/mode-policy.d.ts +3 -18
  59. package/dist/core/mode-policy.js +2 -16
  60. package/dist/core/mods/kernel/dispatch.js +13 -15
  61. package/dist/core/mods/kernel/events.d.ts +9 -6
  62. package/dist/core/mods/kernel/events.js +2 -2
  63. package/dist/core/mods/kernel/receive.d.ts +39 -10
  64. package/dist/core/mods/kernel/receive.js +119 -54
  65. package/dist/core/mods/kernel/site-rules.d.ts +80 -15
  66. package/dist/core/mods/kernel/site-rules.js +232 -40
  67. package/dist/core/mods/stations.d.ts +0 -6
  68. package/dist/core/mods/stations.js +0 -7
  69. package/dist/core/mounted-mcp.d.ts +57 -0
  70. package/dist/core/mounted-mcp.js +71 -2
  71. package/dist/core/own-property-receipt.d.ts +13 -0
  72. package/dist/core/own-property-receipt.js +3 -1
  73. package/dist/core/parent-spec-seat.d.ts +2 -2
  74. package/dist/core/permission-rule-model.d.ts +58 -9
  75. package/dist/core/permission-rule-model.js +81 -7
  76. package/dist/core/permission-rule-org.d.ts +163 -33
  77. package/dist/core/permission-rule-org.js +205 -71
  78. package/dist/core/permission-rules.d.ts +7 -1
  79. package/dist/core/permission-rules.js +37 -8
  80. package/dist/core/retention.js +7 -2
  81. package/dist/core/retired-keys.d.ts +8 -2
  82. package/dist/core/retired-keys.js +12 -1
  83. package/dist/core/roles.js +60 -10
  84. package/dist/core/rule-lane-reads.js +1 -1
  85. package/dist/core/runner/contracts.d.ts +1 -0
  86. package/dist/core/runner/gate-exit.js +4 -3
  87. package/dist/core/runner/mcp-redial.d.ts +52 -10
  88. package/dist/core/runner/mcp-redial.js +38 -9
  89. package/dist/core/runner/permission-rule-lanes.d.ts +5 -2
  90. package/dist/core/runner/permission-rule-lanes.js +22 -10
  91. package/dist/core/runner/person-path-rows.d.ts +3 -1
  92. package/dist/core/runner/person-path-rows.js +2 -2
  93. package/dist/core/runner/prepare-config-doors.d.ts +48 -2
  94. package/dist/core/runner/prepare-config-doors.js +161 -145
  95. package/dist/core/runner/prepare-defer-classify.js +4 -7
  96. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
  97. package/dist/core/runner/prepare-delegation-surface.js +7 -5
  98. package/dist/core/runner/prepare-hands-readface.d.ts +1 -1
  99. package/dist/core/runner/prepare-hands-readface.js +2 -1
  100. package/dist/core/runner/prepare-inherited-gate.js +2 -2
  101. package/dist/core/runner/prepare-listings.d.ts +1 -1
  102. package/dist/core/runner/prepare-listings.js +4 -2
  103. package/dist/core/runner/prepare-memory-engine-session.d.ts +0 -6
  104. package/dist/core/runner/prepare-memory-engine-session.js +19 -6
  105. package/dist/core/runner/prepare-memory.d.ts +3 -2
  106. package/dist/core/runner/prepare-memory.js +6 -2
  107. package/dist/core/runner/prepare-offload-wrappers.d.ts +4 -4
  108. package/dist/core/runner/prepare-offload-wrappers.js +2 -1
  109. package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
  110. package/dist/core/runner/prepare-policy-chain.js +12 -12
  111. package/dist/core/runner/prepare-project-context.d.ts +1 -1
  112. package/dist/core/runner/prepare-project-context.js +6 -4
  113. package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
  114. package/dist/core/runner/prepare-prompt-assembly.js +20 -16
  115. package/dist/core/runner/prepare-prompt-inputs.d.ts +12 -6
  116. package/dist/core/runner/prepare-prompt-inputs.js +6 -3
  117. package/dist/core/runner/prepare-protocol-tools.d.ts +7 -5
  118. package/dist/core/runner/prepare-protocol-tools.js +19 -12
  119. package/dist/core/runner/prepare-question-face.d.ts +4 -2
  120. package/dist/core/runner/prepare-question-face.js +4 -3
  121. package/dist/core/runner/prepare-task.js +10 -10
  122. package/dist/core/runner/prepare-wiring-manifest.d.ts +8 -3
  123. package/dist/core/runner/prepare-wiring-manifest.js +8 -5
  124. package/dist/core/runner/resume-admission.d.ts +4 -1
  125. package/dist/core/runner/resume-admission.js +7 -5
  126. package/dist/core/runner/resume-internals-and-config.d.ts +3 -3
  127. package/dist/core/runner/resume-internals-and-config.js +3 -8
  128. package/dist/core/runner/retired-runner-deps.d.ts +5 -6
  129. package/dist/core/runner/retired-runner-deps.js +1 -4
  130. package/dist/core/runner/run-leg.js +42 -12
  131. package/dist/core/runner/run-recovery-lanes.js +5 -3
  132. package/dist/core/runner/run-terminal-adoption.js +6 -5
  133. package/dist/core/runner/run-turn-boundary.js +9 -3
  134. package/dist/core/runner/runtask.js +1 -1
  135. package/dist/core/runner/skills-seat.d.ts +15 -0
  136. package/dist/core/runner/skills-seat.js +57 -0
  137. package/dist/core/runner/sub-agent-deny-lists.d.ts +13 -11
  138. package/dist/core/runner/sub-agent-deny-lists.js +7 -5
  139. package/dist/core/runner/synthetic-tools.d.ts +5 -2
  140. package/dist/core/runner/synthetic-tools.js +2 -12
  141. package/dist/core/runner-deps.d.ts +29 -14
  142. package/dist/core/session-policy-store.d.ts +19 -0
  143. package/dist/core/session-policy-store.js +22 -2
  144. package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
  145. package/dist/core/task-event.d.ts +38 -2
  146. package/dist/core/task-notification.js +2 -2
  147. package/dist/core/task-spec.d.ts +1 -1
  148. package/dist/core/tool-policy.d.ts +3 -0
  149. package/dist/core/tool-policy.js +10 -4
  150. package/dist/core/types.d.ts +2 -2
  151. package/dist/core/types.js +1 -1
  152. package/dist/core/untrusted-text.d.ts +16 -0
  153. package/dist/core/untrusted-text.js +7 -2
  154. package/dist/core/user-attachment.d.ts +13 -2
  155. package/dist/core/user-attachment.js +47 -41
  156. package/dist/core/wiring-manifest.d.ts +4 -2
  157. package/dist/engine/harness/agent-harness.js +2 -1
  158. package/dist/engine/harness/types.d.ts +3 -0
  159. package/dist/engine/loop/agent-loop.d.ts +12 -1
  160. package/dist/engine/loop/agent-loop.js +17 -5
  161. package/dist/engine/loop/types.d.ts +7 -1
  162. package/dist/index.d.ts +15 -9
  163. package/dist/index.js +12 -6
  164. package/dist/internal/harness.d.ts +1 -0
  165. package/dist/internal/harness.js +1 -0
  166. package/dist/orchestration/goal.d.ts +24 -1
  167. package/dist/orchestration/goal.js +3 -2
  168. package/dist/prompt-assembly/artifact-store.d.ts +44 -9
  169. package/dist/prompt-assembly/artifact-store.js +38 -12
  170. package/dist/prompt-assembly/artifact.d.ts +12 -11
  171. package/dist/prompt-assembly/artifact.js +52 -21
  172. package/dist/prompt-assembly/assemble.d.ts +2 -0
  173. package/dist/prompt-assembly/assemble.js +2 -1
  174. package/dist/prompt-assembly/catalog/index.js +2 -1
  175. package/dist/prompt-assembly/catalog/memory.d.ts +13 -0
  176. package/dist/prompt-assembly/catalog/memory.js +6 -0
  177. package/dist/prompt-assembly/catalog/schema.d.ts +16 -2
  178. package/dist/prompt-assembly/composer.d.ts +2 -0
  179. package/dist/prompt-assembly/composer.js +1 -1
  180. package/dist/prompt-assembly/overlay.d.ts +21 -11
  181. package/dist/prompt-assembly/overlay.js +55 -17
  182. package/dist/prompt-assembly/select.d.ts +21 -6
  183. package/dist/prompt-assembly/select.js +39 -2
  184. package/dist/prompts/default.d.ts +0 -11
  185. package/dist/prompts/default.js +0 -3
  186. package/dist/stores/file/permission-rule-store.d.ts +1 -1
  187. package/dist/stores/file/permission-rule-store.js +2 -1
  188. package/dist/tools/artifact/artifact-tool.js +4 -3
  189. package/package.json +1 -1
  190. package/test/export-surface.snapshot.json +65 -5
  191. package/wire-changes/core@7.53.0.json +1946 -0
@@ -16,7 +16,7 @@ import { boundInputHashOf } from "./canonical-json.js";
16
16
  import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY } from "./untrusted-text.js";
17
17
  import { describeRejectedValue } from "./tool-search-setting.js";
18
18
  import { egressText, egressThrownText } from "./untrusted-egress.js";
19
- import { assertNoRetiredToolPolicyKeys, RETIRED_DECISION_MEMBERS } from "./retired-keys.js";
19
+ import { assertNoRetiredKeys, assertNoRetiredToolPolicyKeys, RETIRED_DECISION_MEMBERS, RETIRED_TOOL_POLICY_KEYS } from "./retired-keys.js";
20
20
  import { isEngineRefusal, nestedRecordsOf, receiveContract, receiveNestedRecords, refusedOutOfContract, screenContractValues } from "./decision-receipt.js";
21
21
  export { isEngineRefusal } from "./decision-receipt.js";
22
22
  import { isNamespacedCoveringRuleName, namespacedRuleNameCovers } from "./permission-rules.js";
@@ -148,7 +148,7 @@ export function decisionText(d) {
148
148
  }
149
149
  const TOOL_POLICY_CARRIED_MEMBERS = ["projection", "pathRules", "writeGuardRows", "nameSets"];
150
150
  export function carriedMembersOf(p) {
151
- assertNoRetiredToolPolicyKeys(p);
151
+ assertNoRetiredKeys(p, RETIRED_TOOL_POLICY_KEYS, "ToolPolicy");
152
152
  const out = {};
153
153
  const carry = (k) => {
154
154
  const v = p[k];
@@ -612,8 +612,7 @@ export function combinePolicies(...policies) {
612
612
  continue;
613
613
  }
614
614
  if (d.updatedInput !== undefined) {
615
- const reread = withArgsReading(current, d.updatedInput, signal);
616
- current = Object.freeze(reread !== undefined ? await reread : { ...current, args: d.updatedInput });
615
+ current = Object.freeze(await withArgsReading(current, d.updatedInput, signal));
617
616
  rewrite = d;
618
617
  stated = d.action === "allow" ? d.decisionReason : undefined;
619
618
  }
@@ -915,6 +914,13 @@ export function ownArgs(v, root = "args") {
915
914
  const copy = tryCloneArgs(v);
916
915
  return copy.ok ? ownedCopy(copy.value, root) : { ...copy, reason: `unclonable value: ${copy.reason}` };
917
916
  }
917
+ export function ownedReading(read) {
918
+ return (args) => {
919
+ const out = read(args);
920
+ const owned = ownArgs(out);
921
+ return owned.ok ? owned.value : out;
922
+ };
923
+ }
918
924
  function ownedCopy(fresh, root) {
919
925
  const pending = [[fresh, root]];
920
926
  for (let next = pending.pop(); next !== undefined; next = pending.pop()) {
@@ -18,8 +18,8 @@ export type { PermissionMode } from "./ask-origin.js";
18
18
  export type { ToolEffect, ToolContentOrigin, ReversibilityVerdict, ReadRootGrantCandidate, ToolSpec, ToolReturn, NestedUsage, NestedUsageAccum, ToolExecuteContext } from "./tool-spec.js";
19
19
  export type { BeforeWriteRequest, BeforeWriteResult, BeforeWriteHook, TrackEditRequest, TrackEditResult, TrackFileEditHook, FileEditedNotice, FileEditedHook, HandsBandOptions } from "./hands-band.js";
20
20
  export type { AgentDefinition, SkillSpec } from "./agent-definition.js";
21
- export type { McpServerSpec, A2aServerSpec, McpElicitRequest, McpElicitResponse, OnElicit, McpRevocationLedger, McpMountIdentity, McpToolAxesRead } from "./mcp-server-spec.js";
22
- export { readMcpToolAxes } from "./mcp-server-spec.js";
21
+ export type { McpServerSpec, A2aServerSpec, McpElicitRequest, McpElicitResponse, OnElicit, McpRevocationLedger, McpMountIdentity, DeclarationFault, DeclarationPathRule, DeclarationRead, ToolAxesRead, ToolAxesSurface } from "./mcp-server-spec.js";
22
+ export { DECLARATION_PATH_RULES, declarationFaultOf, declarerWord, readMcpToolAxes, readToolAxes, receiveDeclaration, toolAxesRefusal } from "./mcp-server-spec.js";
23
23
  export type { TaskLimits } from "./task-limits.js";
24
24
  export type { TaskStatus, RemoteEnvFailureNote, EffectiveMemoryScopes, TaskResult, HumanReviewGateRow } from "./task-result.js";
25
25
  export type { TerminalCause, PausedCause } from "./terminal-cause.js";
@@ -1,5 +1,5 @@
1
1
  export { MODEL_ROLES } from "./model-seat.js";
2
- export { readMcpToolAxes } from "./mcp-server-spec.js";
2
+ export { DECLARATION_PATH_RULES, declarationFaultOf, declarerWord, readMcpToolAxes, readToolAxes, receiveDeclaration, toolAxesRefusal } from "./mcp-server-spec.js";
3
3
  export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
4
4
  export { __resetMalformedDelegationSeatAnnouncement, backgroundChildTerminal, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
5
5
  export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
@@ -397,6 +397,12 @@ export declare function defuseControlChars(text: string): string;
397
397
  * Defense-in-depth, NOT a guarantee (same posture as the rest of this module).
398
398
  */
399
399
  export declare function inlineUntrusted(text: string, maxLen?: number): string;
400
+ /** The mark a cut text ends in: {@link inlineUntrusted}'s, and a notice's machine-read rule text's
401
+ * ({@link import("./permission-rule-model.js").noticeRuleText}) — one ellipsis, spelled once. */
402
+ export declare const INLINE_TRUNCATION_MARK = "\u2026";
403
+ /** The code points {@link inlineUntrusted} may return beyond its content cap: the one truncation mark. The longest result for a cap
404
+ * of `maxLen` is `maxLen` plus this. */
405
+ export declare const INLINE_TRUNCATION_MARK_CODEPOINTS: number;
400
406
  /** The per-ENTRY ceiling inside a `ProbeCause` operand family (checkpoint-store's
401
407
  * structured probe account), sized like the descriptor's own `touchedPaths` entries (the same thing
402
408
  * on the same card). Per entry, not per cause: that is the whole point of the structured shape —
@@ -414,6 +420,16 @@ export declare const PROBE_CAUSE_PATH_MAX = 200;
414
420
  * (tools/fs) and must fit every load-bearing part inside this bound, the gate, the persist boundary — and
415
421
  * a value import from tools/fs into checkpoint-store closes an ESM cycle. */
416
422
  export declare const PROBE_REASON_MAX = 200;
423
+ /**
424
+ * Whether `text` is a probe's one-sentence account the engine itself could have minted: every mint passes the sentence through
425
+ * {@link inlineUntrusted} at {@link PROBE_REASON_MAX}, so the longest one is the cap's content plus the truncation ellipsis
426
+ * ({@link INLINE_TRUNCATION_MARK_CODEPOINTS}), counted in code points. A host that relays the sentence (`RiskDescriptor.probeReason`,
427
+ * `AskRequest.probeReason`) and meets a longer one has met text the engine did not mint (a third-party producer, a generation
428
+ * with another cap) — to be dropped whole, not cut, because a cut is another sentence. The bound lives here once; a host asks, it does not count.
429
+ * The question is total: a value that is not a string is not a sentence the engine mints (every mint is a string), so it answers
430
+ * `false` — the relay's answer to it, dropping it whole, is the same as to an over-long one.
431
+ */
432
+ export declare function isMintableProbeReason(text: unknown): boolean;
417
433
  /** The one body bound every "reviewer note" relay passes to {@link delimitUntrusted} — the decider's
418
434
  * free text attached to a deny (sync `AskOutcome.reason` and the durable `ResumeOutcome` `reason`
419
435
  * legs alike). A note is steering, not payload: unbounded it can flood the transcript/context the
@@ -568,18 +568,23 @@ const LABEL_MAX = 160;
568
568
  export function inlineUntrusted(text, maxLen = LABEL_MAX) {
569
569
  const oneLine = text.replace(/[\s\u0000-\u001f\u007f-\u009f]+/g, " ").trim();
570
570
  const cps = [...oneLine];
571
- const capped = cps.length > maxLen ? cps.slice(0, maxLen).join("") + "…" : oneLine;
571
+ const capped = cps.length > maxLen ? cps.slice(0, maxLen).join("") + INLINE_TRUNCATION_MARK : oneLine;
572
572
  const out = neutralizeForFence(capped);
573
573
  if (maxLen <= 0)
574
574
  return "";
575
575
  const outCps = [...out];
576
- return outCps.length > maxLen + 1 ? outCps.slice(0, maxLen).join("") + "…" : out;
576
+ return outCps.length > maxLen + INLINE_TRUNCATION_MARK_CODEPOINTS ? outCps.slice(0, maxLen).join("") + INLINE_TRUNCATION_MARK : out;
577
577
  }
578
+ export const INLINE_TRUNCATION_MARK = "…";
579
+ export const INLINE_TRUNCATION_MARK_CODEPOINTS = [...INLINE_TRUNCATION_MARK].length;
578
580
  function sanitizeLabel(label) {
579
581
  return inlineUntrusted(label, LABEL_MAX);
580
582
  }
581
583
  export const PROBE_CAUSE_PATH_MAX = 200;
582
584
  export const PROBE_REASON_MAX = 200;
585
+ export function isMintableProbeReason(text) {
586
+ return typeof text === "string" && [...text].length <= PROBE_REASON_MAX + INLINE_TRUNCATION_MARK_CODEPOINTS;
587
+ }
583
588
  export const REVIEWER_NOTE_MAX_BODY = 2048;
584
589
  export function delimitUntrusted(label, text, maxBody) {
585
590
  return delimitUntrustedWithClip(label, text, maxBody).text;
@@ -73,9 +73,20 @@ export type ScreenedUserAttachment = {
73
73
  readonly data: string;
74
74
  readonly mimeType: string;
75
75
  };
76
- /** The door's refusal: one code, the field named first. */
77
- export declare function userAttachmentRefusal(field: string, detail: string): Error & {
76
+ /**
77
+ * The field a refusal names, as one value: `path` is the field path the sentence opens with, and `index` the attachment's
78
+ * position in the seat (0-based, the `[i]` of that path) — present exactly when the sentence names one attachment; a refusal of
79
+ * the seat as a whole (not a list, too many, a resume, the window) has no index. Built only by {@link SEAT_REF} /
80
+ * {@link entryRef} / {@link memberRef}, so the index and the path can never name two attachments.
81
+ */
82
+ export interface UserAttachmentFieldRef {
83
+ readonly path: string;
84
+ readonly index?: number;
85
+ }
86
+ /** The door's refusal: one code, the field named first in the sentence and again in `detail` ({@link UserAttachmentFieldRef}). */
87
+ export declare function userAttachmentRefusal(at: UserAttachmentFieldRef, problem: string): Error & {
78
88
  code: "config.user_attachment_invalid";
89
+ detail: UserAttachmentFieldRef;
79
90
  };
80
91
  /**
81
92
  * The door: screen the seat's value (synchronous; the caller's object is read once, member by member, before the
@@ -24,12 +24,16 @@ export const USER_ATTACHMENT_SEAT = Object.freeze({
24
24
  supplies: USER_ATTACHMENT_SUPPLIES,
25
25
  limits: Object.freeze({ maxEntries: USER_ATTACHMENTS_MAX, maxRenderedTextChars: MAX_READ_OUTPUT_CHARS }),
26
26
  });
27
- export function userAttachmentRefusal(field, detail) {
28
- const e = new Error(`${field}: ${detail}`);
27
+ export function userAttachmentRefusal(at, problem) {
28
+ const e = new Error(`${at.path}: ${problem}`);
29
29
  e.code = "config.user_attachment_invalid";
30
+ e.detail = { path: at.path, ...(at.index !== undefined ? { index: at.index } : {}) };
30
31
  return e;
31
32
  }
32
33
  const SEAT_FIELD = "TaskSpec.userAttachments";
34
+ const SEAT_REF = { path: SEAT_FIELD };
35
+ const entryRef = (index) => ({ path: `${SEAT_FIELD}[${index}]`, index });
36
+ const memberRef = (at, member) => ({ ...at, path: `${at.path}.${member}` });
33
37
  const isPlainObject = (v) => {
34
38
  if (v === null || typeof v !== "object" || Array.isArray(v))
35
39
  return false;
@@ -45,85 +49,87 @@ export function screenUserAttachments(seat, opts) {
45
49
  if (seat === undefined)
46
50
  return undefined;
47
51
  if (!Array.isArray(seat))
48
- throw userAttachmentRefusal(SEAT_FIELD, "must be an array of attachments.");
52
+ throw userAttachmentRefusal(SEAT_REF, "must be an array of attachments.");
49
53
  const entries = [...seat];
50
54
  if (entries.length === 0)
51
55
  return undefined;
52
56
  if (entries.length > USER_ATTACHMENTS_MAX)
53
- throw userAttachmentRefusal(SEAT_FIELD, `${entries.length} attachments, over the ${USER_ATTACHMENTS_MAX} one objective may carry.`);
57
+ throw userAttachmentRefusal(SEAT_REF, `${entries.length} attachments, over the ${USER_ATTACHMENTS_MAX} one objective may carry.`);
54
58
  if (opts.resumeLeg)
55
- throw userAttachmentRefusal(SEAT_FIELD, "a durable resume continues the parked run and sends no new human message, so it cannot carry attachments — declare them on a new objective.");
56
- return entries.map((raw, i) => screenEntry(raw, `${SEAT_FIELD}[${i}]`));
59
+ throw userAttachmentRefusal(SEAT_REF, "a durable resume continues the parked run and sends no new human message, so it cannot carry attachments — declare them on a new objective.");
60
+ return entries.map((raw, i) => screenEntry(raw, entryRef(i)));
57
61
  }
58
- function screenLabel(v, field) {
62
+ function screenLabel(v, at) {
59
63
  if (typeof v !== "string" || v.length === 0)
60
- throw userAttachmentRefusal(field, "must be a non-empty string.");
64
+ throw userAttachmentRefusal(at, "must be a non-empty string.");
61
65
  if (v.length > USER_ATTACHMENT_LABEL_MAX)
62
- throw userAttachmentRefusal(field, `${v.length} characters, over the ${USER_ATTACHMENT_LABEL_MAX}-character limit.`);
66
+ throw userAttachmentRefusal(at, `${v.length} characters, over the ${USER_ATTACHMENT_LABEL_MAX}-character limit.`);
63
67
  return v;
64
68
  }
65
- function screenPositiveInt(v, field) {
69
+ function screenPositiveInt(v, at) {
66
70
  if (typeof v !== "number" || !Number.isInteger(v) || v < 1)
67
- throw userAttachmentRefusal(field, "must be an integer of at least 1.");
71
+ throw userAttachmentRefusal(at, "must be an integer of at least 1.");
68
72
  return v;
69
73
  }
70
- function onlyMembers(o, allowed, field) {
74
+ function onlyMembers(o, allowed, at) {
71
75
  for (const k of Object.keys(o))
72
76
  if (!allowed.includes(k))
73
- throw userAttachmentRefusal(`${field}.${k}`, `is not a member of this attachment (allowed: ${allowed.join(", ")}).`);
77
+ throw userAttachmentRefusal(memberRef(at, k), `is not a member of this attachment (allowed: ${allowed.join(", ")}).`);
74
78
  }
75
- function screenEntry(raw, field) {
79
+ function screenEntry(raw, at) {
76
80
  if (!isPlainObject(raw))
77
- throw userAttachmentRefusal(field, "must be a plain object: { path } (a workspace file), { name, text } (host text) or { name, image } (a host image).");
81
+ throw userAttachmentRefusal(at, "must be a plain object: { path } (a workspace file), { name, text } (host text) or { name, image } (a host image).");
78
82
  const arms = ["path", "text", "image"].filter((k) => Object.prototype.hasOwnProperty.call(raw, k));
79
83
  const arm = arms[0];
80
84
  if (arm === undefined || arms.length !== 1) {
81
- throw userAttachmentRefusal(field, arm === undefined ? "names no attachment: give exactly one of `path`, `text` or `image`." : `mixes ${arms.map((a) => `\`${a}\``).join(" and ")}: give exactly one of \`path\`, \`text\` or \`image\`.`);
85
+ throw userAttachmentRefusal(at, arm === undefined ? "names no attachment: give exactly one of `path`, `text` or `image`." : `mixes ${arms.map((a) => `\`${a}\``).join(" and ")}: give exactly one of \`path\`, \`text\` or \`image\`.`);
82
86
  }
83
87
  switch (arm) {
84
88
  case "path": {
85
- onlyMembers(raw, ["path", "lines"], field);
86
- const path = screenLabel(raw.path, `${field}.path`);
89
+ onlyMembers(raw, ["path", "lines"], at);
90
+ const path = screenLabel(raw.path, memberRef(at, "path"));
87
91
  const linesRaw = raw.lines;
88
92
  if (linesRaw === undefined)
89
93
  return { supply: "path", path };
94
+ const linesAt = memberRef(at, "lines");
90
95
  if (!isPlainObject(linesRaw))
91
- throw userAttachmentRefusal(`${field}.lines`, "must be { start, end? }.");
92
- onlyMembers(linesRaw, ["start", "end"], `${field}.lines`);
93
- const start = screenPositiveInt(linesRaw.start, `${field}.lines.start`);
96
+ throw userAttachmentRefusal(linesAt, "must be { start, end? }.");
97
+ onlyMembers(linesRaw, ["start", "end"], linesAt);
98
+ const start = screenPositiveInt(linesRaw.start, memberRef(linesAt, "start"));
94
99
  const endRaw = linesRaw.end;
95
100
  if (endRaw === undefined)
96
101
  return { supply: "path", path, lines: { start } };
97
- const end = screenPositiveInt(endRaw, `${field}.lines.end`);
102
+ const end = screenPositiveInt(endRaw, memberRef(linesAt, "end"));
98
103
  if (end < start)
99
- throw userAttachmentRefusal(`${field}.lines.end`, `${end} is before the start line ${start}.`);
104
+ throw userAttachmentRefusal(memberRef(linesAt, "end"), `${end} is before the start line ${start}.`);
100
105
  return { supply: "path", path, lines: { start, end } };
101
106
  }
102
107
  case "text": {
103
- onlyMembers(raw, ["name", "text", "startLine"], field);
104
- const name = screenLabel(raw.name, `${field}.name`);
108
+ onlyMembers(raw, ["name", "text", "startLine"], at);
109
+ const name = screenLabel(raw.name, memberRef(at, "name"));
105
110
  const text = raw.text;
106
111
  if (typeof text !== "string" || text.length === 0)
107
- throw userAttachmentRefusal(`${field}.text`, "must be a non-empty string.");
108
- const startLine = raw.startLine === undefined ? 1 : screenPositiveInt(raw.startLine, `${field}.startLine`);
112
+ throw userAttachmentRefusal(memberRef(at, "text"), "must be a non-empty string.");
113
+ const startLine = raw.startLine === undefined ? 1 : screenPositiveInt(raw.startLine, memberRef(at, "startLine"));
109
114
  const rendered = renderNumbered(text, startLine);
110
115
  if (rendered.length > MAX_READ_OUTPUT_CHARS)
111
- throw userAttachmentRefusal(`${field}.text`, `renders to ${rendered.length} characters with line numbers, over the ${MAX_READ_OUTPUT_CHARS}-character limit a read may deliver — send a part of it.`);
116
+ throw userAttachmentRefusal(memberRef(at, "text"), `renders to ${rendered.length} characters with line numbers, over the ${MAX_READ_OUTPUT_CHARS}-character limit a read may deliver — send a part of it.`);
112
117
  return { supply: "content_text", name, text, startLine, rendered };
113
118
  }
114
119
  case "image": {
115
- onlyMembers(raw, ["name", "image"], field);
116
- const name = screenLabel(raw.name, `${field}.name`);
120
+ onlyMembers(raw, ["name", "image"], at);
121
+ const name = screenLabel(raw.name, memberRef(at, "name"));
117
122
  const img = raw.image;
123
+ const imageAt = memberRef(at, "image");
118
124
  if (!isPlainObject(img))
119
- throw userAttachmentRefusal(`${field}.image`, "must be { data, mimeType } (base64 bytes and the image's type).");
120
- onlyMembers(img, ["data", "mimeType"], `${field}.image`);
125
+ throw userAttachmentRefusal(imageAt, "must be { data, mimeType } (base64 bytes and the image's type).");
126
+ onlyMembers(img, ["data", "mimeType"], imageAt);
121
127
  const data = img.data;
122
128
  const mimeType = img.mimeType;
123
129
  if (typeof data !== "string" || data.length === 0)
124
- throw userAttachmentRefusal(`${field}.image.data`, "must be a non-empty base64 string.");
130
+ throw userAttachmentRefusal(memberRef(imageAt, "data"), "must be a non-empty base64 string.");
125
131
  if (typeof mimeType !== "string" || !ADMITTED_IMAGE_MIME_TYPES.includes(mimeType)) {
126
- throw userAttachmentRefusal(`${field}.image.mimeType`, `must be one of ${ADMITTED_IMAGE_MIME_TYPES.join(", ")}.`);
132
+ throw userAttachmentRefusal(memberRef(imageAt, "mimeType"), `must be one of ${ADMITTED_IMAGE_MIME_TYPES.join(", ")}.`);
127
133
  }
128
134
  return { supply: "content_image", name, data, mimeType };
129
135
  }
@@ -132,7 +138,7 @@ function screenEntry(raw, field) {
132
138
  export function refuseUserAttachmentPathsWithoutWorkspace(screened) {
133
139
  const i = screened?.findIndex((a) => a.supply === "path") ?? -1;
134
140
  if (i >= 0)
135
- throw userAttachmentRefusal(`${SEAT_FIELD}[${i}].path`, "this run has no workspace (its hand tools are off), so the engine has no file to read — send the file's bytes as a `text` or `image` entry instead.");
141
+ throw userAttachmentRefusal(memberRef(entryRef(i), "path"), "this run has no workspace (its hand tools are off), so the engine has no file to read — send the file's bytes as a `text` or `image` entry instead.");
136
142
  }
137
143
  export function userAttachmentDeclarations(screened) {
138
144
  return screened.map((a, i) => a.supply === "path"
@@ -149,16 +155,16 @@ export async function admitUserAttachmentImages(screened) {
149
155
  out.set(i + 1, admitted.block);
150
156
  continue;
151
157
  }
152
- const field = `${SEAT_FIELD}[${i}].image`;
158
+ const imageAt = memberRef(entryRef(i), "image");
153
159
  switch (admitted.reason) {
154
160
  case "mime_unsupported":
155
- throw userAttachmentRefusal(`${field}.mimeType`, `must be one of ${ADMITTED_IMAGE_MIME_TYPES.join(", ")}.`);
161
+ throw userAttachmentRefusal(memberRef(imageAt, "mimeType"), `must be one of ${ADMITTED_IMAGE_MIME_TYPES.join(", ")}.`);
156
162
  case "magic_mismatch":
157
- throw userAttachmentRefusal(`${field}.data`, `does not begin with a ${a.mimeType} signature (empty, mis-declared, or not base64) — refused rather than sent.`);
163
+ throw userAttachmentRefusal(memberRef(imageAt, "data"), `does not begin with a ${a.mimeType} signature (empty, mis-declared, or not base64) — refused rather than sent.`);
158
164
  case "raw_too_large":
159
- throw userAttachmentRefusal(`${field}.data`, `${admitted.rawBytes} bytes, over the ${admitted.cap}-byte cap.`);
165
+ throw userAttachmentRefusal(memberRef(imageAt, "data"), `${admitted.rawBytes} bytes, over the ${admitted.cap}-byte cap.`);
160
166
  case "base64_too_large":
161
- throw userAttachmentRefusal(`${field}.data`, `base64 of ${admitted.base64.length} characters, over the API's 5 MB image limit — shrink the image first.`);
167
+ throw userAttachmentRefusal(memberRef(imageAt, "data"), `base64 of ${admitted.base64.length} characters, over the API's 5 MB image limit — shrink the image first.`);
162
168
  }
163
169
  }
164
170
  return out;
@@ -395,7 +401,7 @@ function refuseFramesOverWindow(frames, model, window) {
395
401
  if (tokens <= budget)
396
402
  return;
397
403
  const n = frames.length;
398
- throw userAttachmentRefusal(SEAT_FIELD, `the ${n} ${n === 1 ? "attachment" : "attachments"} and the objective come to about ${tokens} tokens, over the ${budget} tokens one request can hold on this model — to send it the engine would have to drop the objective or some of the attachments. Nothing was sent; attach fewer or smaller parts.`);
404
+ throw userAttachmentRefusal(SEAT_REF, `the ${n} ${n === 1 ? "attachment" : "attachments"} and the objective come to about ${tokens} tokens, over the ${budget} tokens one request can hold on this model — to send it the engine would have to drop the objective or some of the attachments. Nothing was sent; attach fewer or smaller parts.`);
399
405
  }
400
406
  export async function readObjectiveAttachments(prepared, inputId, blocked, window) {
401
407
  if (blocked || prepared.userAttachments === undefined)
@@ -113,8 +113,7 @@ export interface AutoModeArmFact {
113
113
  * One declared MCP server's materialization result for THIS leg — the per-server connection-state
114
114
  * read face on {@link WiringManifest.mcp}. `status` is the connect-time verdict of this leg's
115
115
  * materialize (a snapshot, never a heartbeat — the same semantics as `MaterializedMcp.statuses`,
116
- * which it is projected from): `connected` (tools listed; `toolCount` = the mounted roster size after
117
- * intake), `failed` (the connect or the tool listing threw — `errorCode`/`delivered`/`httpStatus` are the
116
+ * which it is projected from): `connected` (tools listed; `toolCount` = see the field), `failed` (the connect or the tool listing threw — `errorCode`/`delivered`/`httpStatus` are the
118
117
  * failure record spread flat (see the MCP failure vocabulary's `McpFailure`), `error` the
119
118
  * neutralized, length-bounded remote text), `skipped` (declared on the spec but this leg produced no
120
119
  * status for it — the materialization did not reach it). `source` is the DECLARING side's own label
@@ -130,6 +129,9 @@ export interface WiringManifestMcpEntry {
130
129
  delivered?: McpDelivered;
131
130
  httpStatus?: number;
132
131
  error?: string;
132
+ /** How many of the server's tools the roster the row is read against holds: a run's roster (the valve and the deployment's
133
+ * `toolFaces` overlay applied — a tool either one leaves off is not counted), or, for `probeMcpServers` (no run, so no lists),
134
+ * what its own dial would mount. `0` on `failed` and on `skipped` (no connection, so nothing held). */
133
135
  toolCount: number;
134
136
  /**
135
137
  * The engine's last liveness OBSERVATION about this server as of this leg's materialize — a per-leg
@@ -670,13 +670,14 @@ export class AgentHarness {
670
670
  },
671
671
  };
672
672
  },
673
- beforeToolCall: async ({ toolCall, args }, signal) => {
673
+ beforeToolCall: async ({ toolCall, args, readArguments }, signal) => {
674
674
  const result = await this.emitHook({
675
675
  type: "tool_call",
676
676
  toolCallId: toolCall.id,
677
677
  toolName: toolCall.name,
678
678
  input: args,
679
679
  ...(signal !== undefined ? { signal } : {}),
680
+ ...(readArguments !== undefined ? { readArguments } : {}),
680
681
  });
681
682
  return result;
682
683
  },
@@ -1185,6 +1185,9 @@ export interface ToolCallEvent {
1185
1185
  * emits that carry no per-call signal; a subscriber gating a wait on it must then fall back to
1186
1186
  * whatever run-level signal it already holds (the historical shape, byte-identical). */
1187
1187
  signal?: AbortSignal;
1188
+ /** The loop's reading of this call's arguments ({@link BeforeToolCallContext.readArguments}), handed on verbatim: a
1189
+ * subscriber that rewrites the call reads the rewrite through it before judging it. */
1190
+ readArguments?: (args: unknown) => unknown;
1188
1191
  }
1189
1192
  export interface ToolResultEvent {
1190
1193
  type: "tool_result";
@@ -23,7 +23,7 @@
23
23
  */
24
24
  import type { AssistantMessage, ToolResultMessage } from "../llm/index.js";
25
25
  import { type AgentCoreStreamRuntimeDeps } from "./runtime-deps.js";
26
- import type { AfterToolCallResult, AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, AgentToolResult, HaltRemainingDirective, StreamFn } from "./types.js";
26
+ import type { AfterToolCallResult, AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, AgentTool, AgentToolCall, AgentToolResult, HaltRemainingDirective, StreamFn } from "./types.js";
27
27
  /** Callback used by synchronous loop runners to publish agent lifecycle events. */
28
28
  export type AgentEventSink = (event: AgentEvent) => Promise<void> | void;
29
29
  /** Named reasons the loop goes around again. Assertable in tests via the trace sink. */
@@ -159,6 +159,17 @@ export type ExecutedToolCallOutcome = {
159
159
  result: AgentToolResult<unknown>;
160
160
  isError: boolean;
161
161
  };
162
+ /**
163
+ * THE reading a value gets on its way to becoming a call's arguments: the tool's own preparation (`prepareArguments` —
164
+ * a default filled in, an alias folded), then the schema's coercions ({@link validateToolArguments}). The loop reads the
165
+ * model's call through it before the gate, hands the same reading to the gate (`BeforeToolCallContext.readArguments`)
166
+ * so every rewrite is judged as it will run, and reads the gate's output through the same two steps once more — refusing
167
+ * an output they would move. A preparation that throws throws here too (the value cannot be read: whoever adopts it
168
+ * refuses it, as the loop refuses a model call whose preparation throws). A value that does not VALIDATE is handed back as
169
+ * given: nothing invalid runs (the loop's own reading of the gate's output throws on it), and a judge of it judges bytes
170
+ * that never execute.
171
+ */
172
+ export declare function readToolCallArguments(tool: AgentTool, toolCall: AgentToolCall, args: unknown): unknown;
162
173
  /**
163
174
  * How many tool names an unknown-tool miss spells out. A miss is a NAME problem: seeing a couple of dozen
164
175
  * real names is what lets a model spot the one it meant, while a full listing grows with the deployment
@@ -1215,6 +1215,15 @@ function prepareToolCallArguments(tool, toolCall) {
1215
1215
  arguments: preparedArguments,
1216
1216
  };
1217
1217
  }
1218
+ export function readToolCallArguments(tool, toolCall, args) {
1219
+ const prepared = prepareToolCallArguments(tool, { ...toolCall, arguments: structuredClone(args) });
1220
+ try {
1221
+ return validateToolArguments(tool, prepared);
1222
+ }
1223
+ catch {
1224
+ return args;
1225
+ }
1226
+ }
1218
1227
  export const ROSTER_LISTING_MAX = 25;
1219
1228
  export const ROSTER_SEARCH_HINT_NAME = "ToolSearch";
1220
1229
  function formatRosterRecovery(availableTools) {
@@ -1332,6 +1341,7 @@ async function prepareToolCall(currentContext, assistantMessage, toolCall, confi
1332
1341
  toolCall,
1333
1342
  args: finalArgs,
1334
1343
  context: currentContext,
1344
+ readArguments: (args) => readToolCallArguments(tool, toolCall, args),
1335
1345
  }, signal);
1336
1346
  if (signal?.aborted) {
1337
1347
  return {
@@ -1347,11 +1357,13 @@ async function prepareToolCall(currentContext, assistantMessage, toolCall, confi
1347
1357
  }
1348
1358
  return { kind: "immediate", result: blocked, isError: true };
1349
1359
  }
1350
- if (beforeResult?.updatedInput !== undefined) {
1351
- finalArgs = validateToolArguments(tool, {
1352
- ...preparedToolCall,
1353
- arguments: beforeResult.updatedInput,
1354
- });
1360
+ const rewritten = beforeResult?.updatedInput;
1361
+ if (rewritten !== undefined) {
1362
+ const judged = structuredClone(rewritten);
1363
+ finalArgs = validateToolArguments(tool, prepareToolCallArguments(tool, { ...preparedToolCall, arguments: structuredClone(judged) }));
1364
+ if (!sameToolArgs(finalArgs, judged)) {
1365
+ throw new Error(`the arguments cleared for "${tool.name}" are not the ones it would run: its reading of them (argument preparation, schema coercions) changes them, and that form was never judged — not executed`);
1366
+ }
1355
1367
  if (!sameToolArgs(validatedArgs, finalArgs)) {
1356
1368
  const rewrittenRefusal = await runInputValidation(tool, finalArgs, toolCall.id, signal, config.onToolInputValidationFault);
1357
1369
  if (rewrittenRefusal !== undefined)
@@ -64,7 +64,9 @@ export type AgentToolCall = Extract<AssistantMessage["content"][number], {
64
64
  * loop replaces the validated args with `updatedInput` and **re-runs `validateToolArguments` on it**
65
65
  * before execution, so a rewrite can never carry across schema-invalid args into `tool.execute()`. This is
66
66
  * the generic carrier the higher layer uses for arg redaction/clamping (design/37); the loop itself
67
- * stays policy-agnostic. `block` wins over `updatedInput` if both are set.
67
+ * stays policy-agnostic. `block` wins over `updatedInput` if both are set. The rewrite must already be in
68
+ * the form the tool runs (read through {@link BeforeToolCallContext.readArguments}); one that reading would
69
+ * still move is refused, never silently re-read — what runs is what the gate judged.
68
70
  *
69
71
  * Keep in sync with the harness hook result `ToolCallResult` (harness/types.ts), which the harness's
70
72
  * `beforeToolCall` callback returns verbatim.
@@ -133,6 +135,10 @@ export interface BeforeToolCallContext {
133
135
  args: unknown;
134
136
  /** Current agent context at the time the tool call is prepared. */
135
137
  context: AgentContext;
138
+ /** The reading the loop gave `args` and will give any `updatedInput`: the tool's `prepareArguments`, then the schema's
139
+ * coercions (a value that does not validate comes back as given). A gate that rewrites the call reads the rewrite
140
+ * through it before judging it, so what it judges is what runs; the loop refuses an `updatedInput` this reading moves. */
141
+ readArguments?: (args: unknown) => unknown;
136
142
  }
137
143
  /** Context passed to `afterToolCall`. */
138
144
  export interface AfterToolCallContext {
package/dist/index.d.ts CHANGED
@@ -112,7 +112,7 @@ export type { RemoteExecutionEnv, WorkspaceHandle, SnapshotId, SessionToken, San
112
112
  export { addWorktree, pruneWorktrees, WORKTREE_PARENT, type AddWorktreeOptions } from "./core/git-worktree-env.js";
113
113
  export { runExecGate } from "./core/exec-gate.js";
114
114
  export type { ExecStep, ExecStepResult, ExecGateResult, ExecGateOptions } from "./core/exec-gate.js";
115
- export { sanitizeUntrustedText, delimitUntrusted, inlineUntrusted } from "./core/untrusted-text.js";
115
+ export { sanitizeUntrustedText, delimitUntrusted, inlineUntrusted, isMintableProbeReason } from "./core/untrusted-text.js";
116
116
  export { mintReminderMark, isValidReminderMark, openSystemReminder, mintSystemReminder, reminderMarkDeclaration } from "./core/reminder-mint.js";
117
117
  export { deriveInvariants, checkInvariants } from "./core/property-harness.js";
118
118
  export type { InvariantKind, FunctionContract, Invariant, InvariantViolation, CheckResult, } from "./core/property-harness.js";
@@ -144,7 +144,7 @@ export { DEFAULT_FILE_HISTORY_BOUNDARY_KEEP, resolveFileHistoryRetention, fileHi
144
144
  export type { FileHistoryRetentionPolicy } from "./core/file-history-retention.js";
145
145
  export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileFileHistoryStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, FileStoreLockError, type FileStoreLockErrorCode, processFingerprint, isProcessLive, type ProcessFingerprint, type FileStorageBackendOptions, type FileStorageCorruptReadInfo, type FileFileHistoryStoreOptions, type FileSessionRepoOptions, type FileCheckpointStoreOptions, } from "./stores/file/index.js";
146
146
  export { CacheBreakDetector, type CacheBreakFinding, type ToolFingerprintInput } from "./core/cache-break-detector.js";
147
- export { maybeCompact, type MaybeCompactOptions, type CompactionWindowSafetyInfo } from "./core/auto-compaction.js";
147
+ export { maybeCompact, type MaybeCompactOptions, type CompactionPassStart, type CompactionWindowSafetyInfo } from "./core/auto-compaction.js";
148
148
  export type { CompactionEffect } from "./core/frame-settlement.js";
149
149
  export { brainToRuntime } from "./core/runtime.js";
150
150
  export { createSensitivePathPolicy, RECOMMENDED_SENSITIVE_PATTERNS } from "./core/sensitive-path-policy.js";
@@ -277,9 +277,10 @@ export { consolidateScope, advanceCursorAfterInline, type ConsolidateScopeDeps,
277
277
  export { resolveMemoryConsolidationDriver, autoRunOnRecommendationEffective, // the ONE arming reading (`memory.auto_consolidation.arming_has_one_resolver`) — the seat's absence is not "off"
278
278
  type MemoryConsolidationDriverDeps, } from "./core/runner/memory-consolidation-driver.js";
279
279
  export { DEFAULT_COMPACTION_INSTRUCTIONS } from "./core/auto-compaction.js";
280
- export { DEFAULT_SYSTEM_PROMPT, CODE_AGENT_PROMPT, SUBAGENT_PROMPT, CODE_SYSTEM_PROMPT, MEMORY_GUIDANCE, MEMORY_SAFETY, MEMORY_HYGIENE, NO_PERSISTENT_MEMORY_NOTICE, OUTPUT_EFFICIENCY, CYBER_RISK, HARNESS_SECTION_ANCHOR, URL_SAFETY, SUMMARIZE_TOOL_RESULTS, EXECUTION_ENVIRONMENT, EXECUTION_ENVIRONMENT_OPEN_READS, executionEnvironmentBlockFor, buildEnvironmentContext, buildGitSnapshot, buildScratchpadSection, GIT_STATUS_MAX_CHARS, formatLocalDate, type EnvironmentFacts, type PromptBlock, } from "./prompts/default.js";
280
+ export { DEFAULT_SYSTEM_PROMPT, CODE_AGENT_PROMPT, SUBAGENT_PROMPT, CODE_SYSTEM_PROMPT, MEMORY_GUIDANCE, MEMORY_SAFETY, MEMORY_HYGIENE, OUTPUT_EFFICIENCY, CYBER_RISK, HARNESS_SECTION_ANCHOR, URL_SAFETY, SUMMARIZE_TOOL_RESULTS, EXECUTION_ENVIRONMENT, EXECUTION_ENVIRONMENT_OPEN_READS, executionEnvironmentBlockFor, buildEnvironmentContext, buildGitSnapshot, buildScratchpadSection, GIT_STATUS_MAX_CHARS, formatLocalDate, type EnvironmentFacts, type PromptBlock, } from "./prompts/default.js";
281
281
  export { SUPERVISOR_PROMPT, ORCHESTRATION_GUIDANCE, ORCHESTRATION_AWARENESS, GOAL_COMPLETION_GUIDANCE } from "./prompts/supervisor.js";
282
282
  export { OVERLAY_SOURCE_ORDER, type ChainLink as PromptChainLink, type PromptOverlay, type SupersededOverlay } from "./prompt-assembly/overlay.js";
283
+ export { PROMPT_BINDING_LIST_MAX, PROMPT_BINDING_MAX_CHARS } from "./prompt-assembly/overlay.js";
283
284
  export { BANDS as PROMPT_BANDS } from "./prompt-assembly/bands.js";
284
285
  export { OVERLAY_OPS, HOST_ROLES, HOST_FORMS, type OverlayOp as PromptOverlayOp, type OverlaySource as PromptOverlaySource, type HostRole as PromptHostRole, type HostForm as PromptHostForm, type VariantWhen as PromptVariantWhen } from "./prompt-assembly/catalog/schema.js";
285
286
  export { SEMA_DEFAULT_CATALOG, catalogText } from "./prompt-assembly/catalog/index.js";
@@ -288,7 +289,7 @@ export { attachToolContract, getToolContract, hasToolContract, computeShapeDiges
288
289
  export { normalizePromptEpoch, promptIdentityOf, PROMPT_EPOCH_ACTIVATIONS, PROMPT_EPOCH_CHANGES, type PromptEpochDescriptor, type PromptEpochActivation, type PromptEpochChange, type PromptIdentityLayers, type StoredPromptEpoch, } from "./prompt-assembly/epoch.js";
289
290
  export { ARTIFACT_LIMITS, buildPromptArtifact, computeArtifactDigest, requiresOf, unmetRequirements, verifyPromptArtifact, type ArtifactVerifyCode, type ArtifactVerifyResult, type PromptArtifact, type PromptArtifactEvidence, type PromptArtifactPayload, type PromptArtifactRequires, type PublishedPromptArtifact, } from "./prompt-assembly/artifact.js";
290
291
  export { buildTurnPromptSnapshot, loweringRecordFor, LOWERING_VERSION, PREFIX_INPUT_CLASSIFICATION, type CacheIdentityElements, type LoweringRecord, type PrefixInputClass, type RawPrefixInputs, type TurnPromptSnapshot, } from "./prompt-assembly/turn-snapshot.js";
291
- export { CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore, type PromptArtifactSource, type PromptArtifactStore, type PromptSourceState, type PromptSourceStateStore, } from "./prompt-assembly/artifact-store.js";
292
+ export { CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore, type OnArtifactRefused, type PromptArtifactSource, type PromptArtifactStore, type PromptSourceState, type PromptSourceStateStore, type StoredArtifactRefusal, } from "./prompt-assembly/artifact-store.js";
292
293
  export { stripEngineMetadata } from "./internal/llm.js";
293
294
  export { EVENT_PROMPT_REGISTRY, eventDefaultOn, type CompiledEventPrompt, type EventDedupe, type EventDefaultPolicy } from "./prompt-assembly/event-registry.js";
294
295
  export { OUTPUT_STYLE_NAME_MAX } from "./core/output-style.js";
@@ -366,6 +367,11 @@ export { TEAM_ROLES, DIRECTION_RELATIONS, teamRoleOf, mayDirect, type TeamRole,
366
367
  export { createListAgentsTool, LIST_AGENTS_TOOL_NAME, LIST_AGENTS_TOOL_ALIAS, LIST_AGENTS_MAX_RESULT_CHARS, PEER_LISTING_FRESH_WINDOW_MS, isFreshPeerRow, type ListAgentsToolOptions, type ListAgentsRow } from "./agents/list-agents-tool.js";
367
368
  export { CROSS_SESSION_CLASSIFIER_RULE } from "./agents/cross-session-envelope.js";
368
369
  export { PEER_SESSION_ID_UNGRAMMATICAL_CODE, PEER_RESUPPLY_CAP, type PeerLaneMountVerdict, type PeerInboundDisposition } from "./agents/peer-session-drain.js";
370
+ export { ORG_DELIVERY_REFUSAL_CODES, isOrgDeliveryRefusalCode, mintCrossPrincipalRecord, isGateMintedRecord, PRINCIPAL_INBOX_TRIAGE_POLICIES, principalInboxTriagePolicy, principalInboxSideEffectKey, principalInboxConsumerOf, PRINCIPAL_INBOX_CONSUMER_INVALID_CODE, type PrincipalInboxConsumer, type OrgDeliveryGate, type OrgAuthenticatedSender, type CrossPrincipalBody, type OrgDeliveryOutcome, type OrgDeliveryRefusalCode, type PrincipalInboxTriagePolicy, } from "./agents/org-delivery-gate.js";
371
+ export { PRINCIPAL_INBOX_HANDLE } from "./agents/cross-session-ref.js";
372
+ export { CROSS_PRINCIPAL_MESSAGE_NOTICE } from "./agents/cross-session-envelope.js";
373
+ export { principalInboundLayers } from "./agents/cross-session-judge.js";
374
+ export { PRINCIPAL_INBOX_UNMINTED_CAUSE } from "./agents/peer-session-drain.js";
369
375
  export { renderCrossSessionMessageFrame, renderCrossSessionNoticeLine } from "./core/task-notification.js";
370
376
  export { PEER_HELD_QUEUE_CAP, PEER_IDLE_SUBSCRIPTION_TTL_MS, PEER_IDLE_SUBSCRIBER_TABLE_CAP, PEER_IDLE_OUTSTANDING_CAP, PEER_IDLE_PRIORS_KEPT, PEER_IDLE_FIRE_DEBOUNCE_MS, PEER_IDLE_HELD_BACKOFF_MS, PEER_IDLE_LABEL_MAX, CROSS_SESSION_DIALOG_EXPIRY_VALUES, CROSS_SESSION_DIALOG_EXPIRY_DEFAULT, resolveCrossSessionDialogExpiry, PEER_HELD_REVIEW_CAUSES, PEER_DELIVERY_RECEIPT_STATES, isPeerDeliveryReceiptState, PEER_DROP_REASONS, peerRecipientSuffix, renderCrossSessionDeliveryNotice, describePeerDropReasons, renderCrossSessionDroppedNotice, PEER_IDLE_NOTICE_KINDS, isPeerIdleNoticeKind, PEER_IDLE_UNAVAILABLE_CAUSES, peerIdleNoticeLabel, formatPeerNoticeClock, renderCrossSessionIdleNotice, describePeerIdleSubscription, type CrossSessionDialogExpiry, type ResolvedCrossSessionDialogExpiry, type PeerDeliveryReceiptState, type PeerDropReason, type PeerIdleNoticeKind, type PeerIdleNoticeFields, } from "./agents/peer-notices.js";
371
377
  export { createPeerHeldQueue, peerHeldQueueFor, peerHeldQueueIfAny, peerHeldQueueKey, realPeerClock, type PeerInboundHoldCause, type PeerHeldEntry, type PeerHeldSettlement, type PeerHeldSettleReason, type PeerHeldSettleOutcome, type PeerClock, type PeerHeldQueueSink, type PeerHeldQueueConfig, type PeerHeldQueue, } from "./agents/peer-held-queue.js";
@@ -378,17 +384,17 @@ export { builtinAgentDefinitions, BUILTIN_READONLY_DENY_TOOLS, EXPLORE_WHEN_TO_U
378
384
  export { createTaskServer, type TaskServerOptions, type TaskRequestBody, } from "./server/http.js";
379
385
  export { clearStaleToolResults, editBudget, type ContextEditOptions, } from "./core/context-edit.js";
380
386
  export { createOpenAIBrain, type OpenAIBrainConfig } from "./brain/openai.js";
381
- export { createAnthropicBrain, type AnthropicBrainConfig } from "./brain/anthropic.js";
387
+ export { createAnthropicBrain, ANTHROPIC_DEFAULT_BASE_URL, type AnthropicBrainConfig } from "./brain/anthropic.js";
382
388
  export { createOpenResponsesBrain, type OpenResponsesBrainConfig } from "./brain/open-responses.js";
383
389
  export { FABLE_5_COMPAT, fable5Model } from "./brain/model-presets.js";
384
390
  export { createFailoverBrain } from "./brain/failover.js";
385
- export { createRoutingBrain, type RoutingBrainOptions } from "./brain/routing.js";
391
+ export { createRoutingBrain, brainLaneOf, type RoutingBrainOptions } from "./brain/routing.js";
386
392
  export { repairTextToolCalls } from "./brain/tool-call-repair.js";
387
393
  export { createCircuitBreakerBrain, type CircuitBreakerOptions, type BreakerState, type BreakerSnapshot, type BreakerPhase, CIRCUIT_OPEN_MARKER, } from "./brain/circuit-breaker.js";
388
394
  export { createDegradingBrain, readDegradation, DEGRADED_DIAGNOSTIC_TYPE, type DegradingBrainOptions, type DegradeReason, type DegradationInfo, } from "./brain/degrading.js";
389
395
  export { retryBackoffMs, parseRetryAfter } from "./brain/retry.js";
390
396
  export { WAITING_FIRST_TOKEN_AFTER_MS, WAITING_FIRST_TOKEN_EVERY_MS } from "./brain/stream-engine.js";
391
- export { adjudicateModelRoute, resolveRouteCredential, routeRefusalText, routePairingStatus, routeKeyOf, displayUrlOf, resolveRequestRoot, resolveRequestRootOf, joinRequestUrl, hasAuthCarrier, __resetCredentialOriginBindings, type RoutePairingStatus, } from "./brain/route-adjudicator.js";
397
+ export { adjudicateModelRoute, resolveRouteCredential, admitRouteRequest, routeRefusalText, routePairingStatus, routeKeyOf, displayUrlOf, resolveRequestRoot, resolveRequestRootOf, joinRequestUrl, hasAuthCarrier, __resetCredentialOriginBindings, type RoutePairingStatus, } from "./brain/route-adjudicator.js";
392
398
  export { ROUTE_CREDENTIAL_SOURCES, ROUTE_CARRIERS, ROUTE_CARRIER_BAGS, REQUEST_ROOT_ORIGINS, ROUTE_CREDENTIAL_PAIRING, requestRouteOf, routePairingRowOf, type RequestRoute, type RouteCarrier, type RouteCarrierBag, type RequestRootOrigin, type RouteCredentialPairingRow, } from "./brain/request-route.js";
393
399
  export type { RouteAdjudication, RouteCredential, RouteCredentialSource, RoutePairingConfig, RoutePairingPosture, RouteRefusalCode, RouteRefusalDetail, } from "./internal/llm.js";
394
400
  export { ROUTE_ADJUDICATION_CONFORMANCE_CORPUS, type RouteAdjudicationVector } from "./brain/route-conformance.js";
@@ -405,5 +411,5 @@ export { RULE_OFFERS_ABSENCES, type RuleOffersAbsence } from "./core/ask-origin.
405
411
  export { BOUND_GRANT_ABSENCES, type BoundGrantAbsence } from "./core/skill-grant-binding.js";
406
412
  export { DISPOSABLE_PROMPT_SECTIONS, type DisposablePromptSection, type PromptSectionEntry, type PromptSectionAuthor, type McpInstructionsEntry } from "./core/prompt-section-seat.js";
407
413
  export type { McpRevocationLedger, McpMountIdentity } from "./core/mcp-server-spec.js";
408
- export { readMcpToolAxes } from "./core/mcp-server-spec.js";
409
- export type { McpToolAxesRead } from "./core/mcp-server-spec.js";
414
+ export { readToolAxes, readMcpToolAxes } from "./core/mcp-server-spec.js";
415
+ export type { ToolAxesRead, ToolAxesSurface } from "./core/mcp-server-spec.js";