@sema-agent/core 7.7.0 → 7.8.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 (135) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/agents/agent-transcript-tool.js +2 -2
  3. package/dist/agents/list-agents-tool.js +2 -3
  4. package/dist/agents/observer.js +2 -2
  5. package/dist/agents/send-message-tool.js +2 -1
  6. package/dist/agents/subagent-steps.js +5 -4
  7. package/dist/agents/subagent.js +2 -3
  8. package/dist/core/ask-question.js +2 -2
  9. package/dist/core/checkpoint-store.d.ts +38 -4
  10. package/dist/core/context-edit.d.ts +0 -22
  11. package/dist/core/context-edit.js +2 -11
  12. package/dist/core/engine-notice.d.ts +6 -0
  13. package/dist/core/fs-write-gate-policy.d.ts +7 -1
  14. package/dist/core/fs-write-gate-policy.js +7 -7
  15. package/dist/core/gate-fold.js +2 -2
  16. package/dist/core/gate-lanes.js +4 -3
  17. package/dist/core/governance-codes.d.ts +1 -1
  18. package/dist/core/governance-codes.js +6 -0
  19. package/dist/core/hooks.d.ts +8 -2
  20. package/dist/core/hooks.js +1 -1
  21. package/dist/core/lsp.js +2 -2
  22. package/dist/core/mcp-server-spec.d.ts +17 -0
  23. package/dist/core/mcp.js +3 -1
  24. package/dist/core/memory-engine/tools.js +4 -12
  25. package/dist/core/permission-rules.d.ts +32 -2
  26. package/dist/core/permission-rules.js +43 -37
  27. package/dist/core/present-plan-tool.js +3 -4
  28. package/dist/core/runner/active-skill-scope.js +7 -4
  29. package/dist/core/runner/compaction-call-options.d.ts +1 -1
  30. package/dist/core/runner/contracts.d.ts +27 -3
  31. package/dist/core/runner/prepare-ask-lane.d.ts +1 -1
  32. package/dist/core/runner/prepare-caps-and-workflow.d.ts +5 -4
  33. package/dist/core/runner/prepare-caps-and-workflow.js +16 -11
  34. package/dist/core/runner/prepare-defer-classify.d.ts +5 -26
  35. package/dist/core/runner/prepare-defer-classify.js +10 -10
  36. package/dist/core/runner/prepare-delegation-surface.d.ts +5 -4
  37. package/dist/core/runner/prepare-delegation-surface.js +15 -17
  38. package/dist/core/runner/prepare-gate-stations.d.ts +4 -1
  39. package/dist/core/runner/prepare-gate-stations.js +3 -1
  40. package/dist/core/runner/prepare-hands-readface.d.ts +3 -2
  41. package/dist/core/runner/prepare-hands-readface.js +3 -2
  42. package/dist/core/runner/prepare-inherited-gate.d.ts +1 -1
  43. package/dist/core/runner/prepare-inherited-gate.js +1 -0
  44. package/dist/core/runner/prepare-lsp.d.ts +4 -3
  45. package/dist/core/runner/prepare-lsp.js +3 -2
  46. package/dist/core/runner/prepare-memory-engine-session.d.ts +4 -4
  47. package/dist/core/runner/prepare-memory-engine-session.js +4 -2
  48. package/dist/core/runner/prepare-offload-wrappers.js +7 -5
  49. package/dist/core/runner/prepare-park-ask.d.ts +4 -0
  50. package/dist/core/runner/prepare-park-ask.js +4 -1
  51. package/dist/core/runner/prepare-project-context.d.ts +5 -23
  52. package/dist/core/runner/prepare-project-context.js +7 -5
  53. package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
  54. package/dist/core/runner/prepare-protocol-tools.d.ts +5 -1
  55. package/dist/core/runner/prepare-protocol-tools.js +38 -21
  56. package/dist/core/runner/prepare-question-face.d.ts +4 -3
  57. package/dist/core/runner/prepare-question-face.js +5 -3
  58. package/dist/core/runner/prepare-run-refs.d.ts +16 -0
  59. package/dist/core/runner/prepare-run-refs.js +6 -0
  60. package/dist/core/runner/prepare-safety-scan.js +42 -2
  61. package/dist/core/runner/prepare-task.js +37 -19
  62. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +5 -2
  63. package/dist/core/runner/prepare-tool-disclosure-mount.js +3 -1
  64. package/dist/core/runner/prepare-wiring-manifest.d.ts +4 -0
  65. package/dist/core/runner/prepare-wiring-manifest.js +3 -8
  66. package/dist/core/runner/run-harness-handlers.d.ts +46 -0
  67. package/dist/core/runner/run-harness-handlers.js +345 -0
  68. package/dist/core/runner/run-turn-boundary.d.ts +69 -0
  69. package/dist/core/runner/run-turn-boundary.js +694 -0
  70. package/dist/core/runner/runtask.js +47 -1043
  71. package/dist/core/runner/session-rule-policy.js +9 -4
  72. package/dist/core/runner/synthetic-tools.js +5 -8
  73. package/dist/core/runner/tool-disclosure.d.ts +4 -0
  74. package/dist/core/runner/tool-disclosure.js +9 -5
  75. package/dist/core/runner/tool-end-body.js +3 -2
  76. package/dist/core/runner/tool-face-overlay.d.ts +40 -0
  77. package/dist/core/runner/tool-face-overlay.js +125 -0
  78. package/dist/core/runner/tool-output-projection.d.ts +10 -0
  79. package/dist/core/runner/tool-output-projection.js +33 -10
  80. package/dist/core/sensitive-path-policy.d.ts +3 -0
  81. package/dist/core/sensitive-path-policy.js +6 -5
  82. package/dist/core/shared-memory/tools.js +3 -6
  83. package/dist/core/store-contracts/checkpoint-store-contract.js +23 -0
  84. package/dist/core/task-event.d.ts +10 -0
  85. package/dist/core/task-registry.js +4 -5
  86. package/dist/core/task-spec.d.ts +8 -0
  87. package/dist/core/tool-catalog-entries.d.ts +48 -0
  88. package/dist/core/tool-catalog-entries.js +174 -0
  89. package/dist/core/tool-conformance.d.ts +22 -0
  90. package/dist/core/tool-conformance.js +37 -0
  91. package/dist/core/tool-face.d.ts +171 -0
  92. package/dist/core/tool-face.js +25 -0
  93. package/dist/core/tool-policy.d.ts +24 -0
  94. package/dist/core/tool-policy.js +4 -2
  95. package/dist/core/tool-registry.d.ts +114 -0
  96. package/dist/core/tool-registry.js +114 -0
  97. package/dist/core/tool-result-budget.d.ts +0 -3
  98. package/dist/core/tool-result-budget.js +4 -3
  99. package/dist/core/tool-result-store.d.ts +0 -18
  100. package/dist/core/tool-result-store.js +2 -18
  101. package/dist/core/tool-roster.d.ts +450 -0
  102. package/dist/core/tool-roster.js +497 -0
  103. package/dist/core/tool-spec.d.ts +54 -3
  104. package/dist/core/tools.js +7 -0
  105. package/dist/core/wiring-manifest.d.ts +13 -0
  106. package/dist/core/wiring-manifest.js +2 -1
  107. package/dist/core/write-protect.d.ts +2 -1
  108. package/dist/core/write-protect.js +5 -4
  109. package/dist/engine/compaction/utils.d.ts +6 -0
  110. package/dist/engine/compaction/utils.js +19 -19
  111. package/dist/engine/loop/types.d.ts +6 -0
  112. package/dist/index.d.ts +15 -4
  113. package/dist/index.js +15 -4
  114. package/dist/orchestration/goal.js +2 -1
  115. package/dist/orchestration/run-spec.js +3 -5
  116. package/dist/orchestration/run-workflow-tool.js +2 -2
  117. package/dist/prompt-assembly/event-registry.js +3 -3
  118. package/dist/prompt-assembly/tool-catalog.d.ts +2 -2
  119. package/dist/tools/fs/fs-bash.d.ts +1 -1
  120. package/dist/tools/fs/fs-bash.js +7 -11
  121. package/dist/tools/fs/fs-read.js +2 -2
  122. package/dist/tools/fs/fs-search-tools.d.ts +0 -7
  123. package/dist/tools/fs/fs-search-tools.js +3 -16
  124. package/dist/tools/fs/fs-write.js +4 -6
  125. package/dist/tools/fs/repo-map.js +2 -2
  126. package/dist/tools/fs/safety.d.ts +2 -1
  127. package/dist/tools/fs/safety.js +6 -5
  128. package/dist/tools/monitor.js +2 -2
  129. package/dist/tools/scheduler-tools.js +5 -8
  130. package/dist/tools/task-list.js +5 -8
  131. package/dist/tools/todo.js +2 -2
  132. package/dist/tools/web.js +3 -6
  133. package/dist/tools/worktree.js +3 -4
  134. package/package.json +4 -1
  135. package/test/export-surface.snapshot.json +147 -7
@@ -0,0 +1,114 @@
1
+ /**
2
+ * The static tool catalog's READ FACE (design/388 §2.1): `describeToolCatalog()` and the predicates
3
+ * every former name table is now DERIVED from. Readable without an env, a deps object or a tool
4
+ * instance — a host predicts a leg's roster from it (`predictMountedToolNames`), a policy module
5
+ * derives its covered set from it, a shell renders it.
6
+ *
7
+ * Every predicate here answers over DEFINITIONS and folds to names with "any definition under this
8
+ * name matches" — the rule that pins the two fail-open shapes a per-name table had (one name, two
9
+ * definitions; the table could only hold one).
10
+ *
11
+ * Layer-0 vocabulary: depends on the leaf catalog and the face vocabulary only.
12
+ */
13
+ import { type ToolCatalogEntry, type ToolMountTag, type ToolPathAccess } from "./tool-face.js";
14
+ /** The whole static catalog, one frozen row per definition (design/388 §2.1 `describeToolCatalog()`).
15
+ * Replaces the retired name-keyed exports `HAND_TOOL_EFFECTS` / `DEFAULT_BUDGET_EXEMPT_TOOLS` /
16
+ * `COMPACTABLE_TOOLS`: filter this instead (`e.mountedBy.includes("hands")`, `e.face.budgetExempt`,
17
+ * `e.face.compactable`). */
18
+ export declare function describeToolCatalog(): readonly ToolCatalogEntry[];
19
+ /** Every definition under a wire name (a name may carry more than one — the two shells). */
20
+ export declare function catalogEntriesNamed(name: string): readonly ToolCatalogEntry[];
21
+ /** Every wire name the catalog knows, aliases included (a set — the two shells fold to one name). */
22
+ export declare function catalogToolNames(): ReadonlySet<string>;
23
+ /** A-11/12/13/14 — tools this engine can CONFINE BY PATH on a write: `pathTarget.access ≠ read`.
24
+ * Today {Write, Edit, NotebookEdit}. */
25
+ export declare function pathConfinableWriteToolNames(): ReadonlySet<string>;
26
+ /** A-11 (the SECOND authorization domain) — the active-skill `allowPaths` face: confinable AND the
27
+ * definition opted into skill scoping. Today {Write, Edit} — NotebookEdit is deliberately outside. */
28
+ export declare function skillScopeWriteToolNames(): ReadonlySet<string>;
29
+ /** A-8 — every definition that names a path target at all (read or write): the file-tool glob lane. */
30
+ export declare function pathTargetingToolNames(): ReadonlySet<string>;
31
+ /** A-10 — the micro-compaction whitelist (`compactable: true`). */
32
+ export declare function compactableToolNames(): ReadonlySet<string>;
33
+ /** A-5 — the aggregate-budget exemptions (`budgetExempt: true`). */
34
+ export declare function budgetExemptToolNames(): ReadonlySet<string>;
35
+ /** The value a call's args carry under a path target: `param` first, then each alias, first non-empty string wins. */
36
+ export declare function pathTargetValue(args: unknown, pt: {
37
+ param: string;
38
+ aliases?: readonly string[];
39
+ }): string | undefined;
40
+ /** The path target of a wire name — the FIRST definition's (every definition under one name declares
41
+ * the same target; the conformance test pins that). */
42
+ /** A gated call as every fence sees it: the wire name, the args, and the OBJECT face a prepared leg stamped on the
43
+ * request (absent on a BARE request — a policy invoked outside a Runner). */
44
+ export interface ToolCallLike {
45
+ toolName: string;
46
+ args: unknown;
47
+ face?: {
48
+ pathTarget?: {
49
+ param: string;
50
+ aliases?: readonly string[];
51
+ access: ToolPathAccess;
52
+ };
53
+ } | undefined;
54
+ }
55
+ type CallPathTarget = {
56
+ param: string;
57
+ aliases?: readonly string[];
58
+ access: ToolPathAccess;
59
+ };
60
+ /**
61
+ * design/388 B6/B17 — the path target a PROTECTIVE fence reads (a deny-list judging a write's target: sensitive paths,
62
+ * frozen paths, write protection, the transcript gate; edit tracking): the object face's own declaration first, the
63
+ * catalog's declaration for the NAME as the FLOOR — for a bare request (a policy invoked outside a Runner) and for a
64
+ * face that declares none. Reading the catalog for an undeclared same-name tool can only TIGHTEN a deny-list (it adds
65
+ * a slot to judge — the pre-388 posture, never wider), which is exactly why this floor is wrong for a grant.
66
+ */
67
+ export declare function protectivePathTargetOf(call: ToolCallLike): CallPathTarget | undefined;
68
+ /**
69
+ * The path target a CONTAINMENT fence reads (a grant admitting a write BY its path: session `allowDirs`, the fs-write
70
+ * gate's accept/exempt dirs; the active-skill allowPaths face reads its own eligibility bit the same way): the object
71
+ * face's OWN declaration only — a same-name tool that declares no path target is an UNCONFIRMABLE write (the catalog's
72
+ * slot may not be the one it writes; a decoy in that slot would buy an admission), so the fence fails closed. A BARE
73
+ * request (no face at all — a policy invoked outside a Runner) reads the catalog for the name: the pre-388 reading, the
74
+ * documented migration seam for bare producers.
75
+ */
76
+ export declare function declaredPathTargetOf(call: ToolCallLike): CallPathTarget | undefined;
77
+ /** Is this call a write a PROTECTIVE fence judges (a protected target whose access ≠ read)? The name sets are its static view. */
78
+ export declare function isProtectedWrite(call: ToolCallLike): boolean;
79
+ /** Is this call a write a CONTAINMENT fence may ADMIT by its path (a declared target whose access ≠ read)? */
80
+ export declare function isDeclaredWrite(call: ToolCallLike): boolean;
81
+ /** design/388 A-18 — the file-op access a compaction summary records for a LIVE tool name: only the FILE families'
82
+ * path targets name a file (a search tool's `path` is a search ROOT, not a file the model read); every other name
83
+ * records nothing (retired spellings in persisted transcripts read the frozen history table at the call site). */
84
+ export declare function fileOpAccessOf(name: string): ToolPathAccess | undefined;
85
+ export declare function pathTargetOf(name: string): ToolCatalogEntry["face"]["pathTarget"];
86
+ /**
87
+ * The rule vocabulary of a wire name from the STATIC catalog: `primaryParams` = the declared primaries, else
88
+ * the path target's `param` + aliases; `params` = the declared vocabulary, else the path target's names —
89
+ * and UNDEFINED when the catalog cannot know the full vocabulary (a definition whose schema is built inside
90
+ * its factory and declares no `ruleFace.params`): the static half never claims a vocabulary it has not
91
+ * read, so the rule compiler judges only what it knows and the leg's roster (which reads the schema)
92
+ * judges the rest. `undefined` as a whole for a name with nothing to say.
93
+ */
94
+ export declare function catalogRuleFaceOf(name: string): {
95
+ primaryParams: string[];
96
+ params?: string[];
97
+ } | undefined;
98
+ /** A-1 / server B-1 — the hand band's declared effects by name (any `hands` definition; the WRITE shell
99
+ * wins the name when both are listed, matching the by-name table this replaces — the read-only shell's
100
+ * own instance carries `effect: "read"` and the effect roster reports THAT). */
101
+ export declare function handBandEffects(): ReadonlyMap<string, NonNullable<ToolCatalogEntry["face"]["effect"]>>;
102
+ /** A-3 / L4 — every `details.type` card the engine owns: the catalog's per-definition cards plus the
103
+ * engine-minted ones (protocol channels, fs refusals). */
104
+ export declare function engineCardTypes(): ReadonlySet<string>;
105
+ /**
106
+ * L3 — the STATIC PREDICTION of a leg's core-mounted names for a set of active mount conditions:
107
+ * every definition listed under at least one active tag. `scenario` and `optional` definitions mount
108
+ * only when the vector names their tag (a host factory / a per-task opt-in decides them). Names are
109
+ * folded (the two shells predict one `Bash`).
110
+ */
111
+ export declare function predictMountedToolNames(active: ReadonlySet<ToolMountTag>): ReadonlySet<string>;
112
+ /** The closed set as a Set, for callers that validate a tag read off the wire. */
113
+ export declare const TOOL_MOUNT_TAG_SET: ReadonlySet<string>;
114
+ export { HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND } from "./tool-face.js";
@@ -0,0 +1,114 @@
1
+ import { TOOL_MOUNT_TAGS } from "./tool-face.js";
2
+ import { ENGINE_CARDS, TOOL_CATALOG_ENTRIES } from "./tool-catalog-entries.js";
3
+ export function describeToolCatalog() {
4
+ return TOOL_CATALOG_ENTRIES;
5
+ }
6
+ export function catalogEntriesNamed(name) {
7
+ return TOOL_CATALOG_ENTRIES.filter((e) => e.name === name);
8
+ }
9
+ export function catalogToolNames() {
10
+ const out = new Set();
11
+ for (const e of TOOL_CATALOG_ENTRIES) {
12
+ out.add(e.name);
13
+ for (const a of e.face.aliases ?? [])
14
+ out.add(a);
15
+ }
16
+ return out;
17
+ }
18
+ const names = (pred) => {
19
+ const out = new Set();
20
+ for (const e of TOOL_CATALOG_ENTRIES)
21
+ if (pred(e))
22
+ out.add(e.name);
23
+ return out;
24
+ };
25
+ export function pathConfinableWriteToolNames() {
26
+ return names((e) => e.face.pathTarget !== undefined && e.face.pathTarget.access !== "read");
27
+ }
28
+ export function skillScopeWriteToolNames() {
29
+ return names((e) => e.face.pathTarget !== undefined && e.face.pathTarget.access !== "read" && e.face.pathTarget.skillScopeEligible === true);
30
+ }
31
+ export function pathTargetingToolNames() {
32
+ return names((e) => e.face.pathTarget !== undefined);
33
+ }
34
+ export function compactableToolNames() {
35
+ return names((e) => e.face.compactable === true);
36
+ }
37
+ export function budgetExemptToolNames() {
38
+ return names((e) => e.face.budgetExempt === true);
39
+ }
40
+ export function pathTargetValue(args, pt) {
41
+ if (args === null || typeof args !== "object")
42
+ return undefined;
43
+ const a = args;
44
+ for (const k of [pt.param, ...(pt.aliases ?? [])]) {
45
+ const v = a[k];
46
+ if (typeof v === "string" && v.length > 0)
47
+ return v;
48
+ }
49
+ return undefined;
50
+ }
51
+ export function protectivePathTargetOf(call) {
52
+ return call.face?.pathTarget ?? pathTargetOf(call.toolName);
53
+ }
54
+ export function declaredPathTargetOf(call) {
55
+ return call.face !== undefined ? call.face.pathTarget : pathTargetOf(call.toolName);
56
+ }
57
+ export function isProtectedWrite(call) {
58
+ const pt = protectivePathTargetOf(call);
59
+ return pt !== undefined && pt.access !== "read";
60
+ }
61
+ export function isDeclaredWrite(call) {
62
+ const pt = declaredPathTargetOf(call);
63
+ return pt !== undefined && pt.access !== "read";
64
+ }
65
+ export function fileOpAccessOf(name) {
66
+ for (const e of TOOL_CATALOG_ENTRIES) {
67
+ if (e.name === name && (e.face.family === "file-read" || e.face.family === "file-write") && e.face.pathTarget !== undefined)
68
+ return e.face.pathTarget.access;
69
+ }
70
+ return undefined;
71
+ }
72
+ export function pathTargetOf(name) {
73
+ for (const e of TOOL_CATALOG_ENTRIES)
74
+ if (e.name === name && e.face.pathTarget !== undefined)
75
+ return e.face.pathTarget;
76
+ return undefined;
77
+ }
78
+ export function catalogRuleFaceOf(name) {
79
+ for (const e of TOOL_CATALOG_ENTRIES) {
80
+ if (e.name !== name)
81
+ continue;
82
+ const pt = e.face.pathTarget;
83
+ const primary = e.face.ruleFace?.primaryParams ?? (pt !== undefined ? [pt.param, ...(pt.aliases ?? [])] : []);
84
+ const params = e.face.ruleFace?.params ?? (pt !== undefined ? [pt.param, ...(pt.aliases ?? [])] : undefined);
85
+ if (params === undefined && primary.length === 0)
86
+ continue;
87
+ return { primaryParams: [...primary], ...(params !== undefined ? { params: [...new Set([...params, ...primary])] } : {}) };
88
+ }
89
+ return undefined;
90
+ }
91
+ export function handBandEffects() {
92
+ const out = new Map();
93
+ for (const e of TOOL_CATALOG_ENTRIES) {
94
+ if (!e.mountedBy.includes("hands"))
95
+ continue;
96
+ const eff = e.face.effect ?? "write";
97
+ const prior = out.get(e.name);
98
+ if (prior === undefined || prior === "read")
99
+ out.set(e.name, eff);
100
+ }
101
+ return out;
102
+ }
103
+ export function engineCardTypes() {
104
+ const out = new Set(Object.keys(ENGINE_CARDS));
105
+ for (const e of TOOL_CATALOG_ENTRIES)
106
+ for (const card of e.cards)
107
+ out.add(card);
108
+ return out;
109
+ }
110
+ export function predictMountedToolNames(active) {
111
+ return names((e) => e.mountedBy.some((t) => active.has(t)));
112
+ }
113
+ export const TOOL_MOUNT_TAG_SET = new Set(TOOL_MOUNT_TAGS);
114
+ export { HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND } from "./tool-face.js";
@@ -46,8 +46,5 @@ export interface AggregateBudgetOptions {
46
46
  results: number;
47
47
  }) => void;
48
48
  }
49
- /** Default exemptions: tools whose result is self-bounded (read_file errors at its own token cap; the
50
- * offload reader pages small slices). grep/bash/glob/web_fetch/MCP are the risk sources, NOT exempt. */
51
- export declare const DEFAULT_BUDGET_EXEMPT_TOOLS: ReadonlySet<string>;
52
49
  /** Cap each over-budget turn-batch (run of consecutive tool_result messages). Request-only; see file docs. */
53
50
  export declare function capAggregateToolResults(messages: AgentMessage[], opts: AggregateBudgetOptions): Promise<AgentMessage[]>;
@@ -1,5 +1,6 @@
1
1
  import { isToolResult } from "./message-utils.js";
2
- import { buildPreview, buildToolResultRef, OFFLOAD_TOOL_NAME, PERSISTED_OUTPUT_PREFIX, toolResultContentSegment, toolResultProvenanceOf, } from "./tool-result-store.js";
2
+ import { buildPreview, buildToolResultRef, PERSISTED_OUTPUT_PREFIX, toolResultContentSegment, toolResultProvenanceOf, } from "./tool-result-store.js";
3
+ import { budgetExemptToolNames } from "./tool-registry.js";
3
4
  export const AGGREGATE_TOOL_RESULT_BUDGET_CHARS = 200_000;
4
5
  const HEAD = 1_000;
5
6
  const TAIL = 1_000;
@@ -33,10 +34,10 @@ function truncationPreview(full, head = HEAD, tail = TAIL) {
33
34
  `…[${total} chars total; ${tailStart - head} omitted to fit the per-turn result budget — re-run with a narrower query to see the rest.]\n` +
34
35
  `${full.slice(tailStart)}`);
35
36
  }
36
- export const DEFAULT_BUDGET_EXEMPT_TOOLS = new Set(["Read", OFFLOAD_TOOL_NAME]);
37
+ const CATALOG_BUDGET_EXEMPT_TOOLS = budgetExemptToolNames();
37
38
  export async function capAggregateToolResults(messages, opts) {
38
39
  const budget = opts.budgetChars ?? AGGREGATE_TOOL_RESULT_BUDGET_CHARS;
39
- const exempt = opts.exemptTools ?? DEFAULT_BUDGET_EXEMPT_TOOLS;
40
+ const exempt = opts.exemptTools ?? CATALOG_BUDGET_EXEMPT_TOOLS;
40
41
  let out;
41
42
  let i = 0;
42
43
  while (i < messages.length) {
@@ -446,24 +446,6 @@ export declare function offloadPagebackHint(ref: string, form: "preview" | "clea
446
446
  export declare const PERSISTED_OUTPUT_PREFIX = "<persisted-output ref=";
447
447
  /** Default per-result offload threshold (chars). ~5K tokens; configurable globally or per tool. */
448
448
  export declare const DEFAULT_TOOL_RESULT_THRESHOLD_CHARS = 20000;
449
- /**
450
- * CC 198 per-tool persistence thresholds, mirrored for the first-party mounts (PARITY-SPOT-USAGE-CONSTANTS
451
- * 2026-07-10 F1/F2). CC's GIa framework (pretty.js:286716-286721) resolves each tool's persist threshold as
452
- * `min(maxResultSizeChars, w6t=50000)`:
453
- * - Read declares `maxResultSizeChars: 1/0` (:478260) → **never persisted**. Read already owns its bound
454
- * (25K-token first-page auto-pagination) and the aggregate budget exempts it — wrapping it in offload
455
- * re-truncated a page the tool had already sized (the F1 two-layer inconsistency). Structural exemption:
456
- * applies even when a deployment sets an explicit global threshold.
457
- * - Bash 30000 (:335231) / Grep 20000 (:333220) / Monitor 1e4 (:450030); everything else first-party
458
- * declares 1e5 (Agent :453402, Glob :333570, TaskOutput :458260, …) → min(1e5, 50000) = 50000.
459
- * Unknown tools keep the deployment default ({@link DEFAULT_TOOL_RESULT_THRESHOLD_CHARS}) — we deliberately
460
- * do NOT mirror KIa's bare `$xa=400000` undeclared-tool fallback: our aggregate budget is 200K chars, so a
461
- * 400K inline result is unrepresentable anyway.
462
- */
463
- export declare function firstPartyOffloadPolicy(toolName: string): {
464
- offload?: boolean;
465
- offloadThresholdChars?: number;
466
- };
467
449
  /** Head+tail preview of an offloaded result, pointing at {@link OFFLOAD_TOOL_NAME} via `ref`. Exported so
468
450
  * the per-message aggregate budget (design/64 §17.2) produces the SAME preview format (deterministic →
469
451
  * byte-identical across queries → prompt-cache safe).
@@ -4,6 +4,7 @@ import { uuidv7 } from "../engine/session/uuid.js";
4
4
  import { defineTool, errorResult } from "./tools.js";
5
5
  import { deliverEngineNotice } from "./types.js";
6
6
  import { TOOL_SEARCH_NAME } from "./runner/tool-disclosure.js";
7
+ import { toolFace } from "./tool-catalog-entries.js";
7
8
  export const TOOL_RESULT_REF_CONFLICT_CODE = "tool_result.ref_conflict";
8
9
  export class ToolResultRefConflictError extends Error {
9
10
  ref;
@@ -202,22 +203,6 @@ export function offloadPagebackHint(ref, form, reachableTools) {
202
203
  }
203
204
  export const PERSISTED_OUTPUT_PREFIX = "<persisted-output ref=";
204
205
  export const DEFAULT_TOOL_RESULT_THRESHOLD_CHARS = 20_000;
205
- export function firstPartyOffloadPolicy(toolName) {
206
- switch (toolName) {
207
- case "Read":
208
- return { offload: false };
209
- case "Write":
210
- return { offload: false };
211
- case "Bash":
212
- return { offloadThresholdChars: 30_000 };
213
- case "Grep":
214
- return { offloadThresholdChars: 20_000 };
215
- case "Monitor":
216
- return { offloadThresholdChars: 10_000 };
217
- default:
218
- return { offloadThresholdChars: 50_000 };
219
- }
220
- }
221
206
  const PREVIEW_HEAD_CHARS = 1_000;
222
207
  const PREVIEW_TAIL_CHARS = 1_000;
223
208
  const READ_DEFAULT_LIMIT = 4_000;
@@ -398,7 +383,7 @@ async function offloadOversizedDetailStrings(details, store, thresholdChars, ses
398
383
  export function createReadToolResultTool(store) {
399
384
  return defineTool({
400
385
  name: OFFLOAD_TOOL_NAME,
401
- contract: { contractId: "core.read_tool_result@1", implementationRevision: "1" },
386
+ ...toolFace("read-tool-result"),
402
387
  description: `Read the full content of a tool result that was too large and persisted (you saw it as ` +
403
388
  `<persisted-output ref="..."> with a preview). Pass the ref; use offset/limit to page through it.`,
404
389
  parameters: Type.Object({
@@ -406,7 +391,6 @@ export function createReadToolResultTool(store) {
406
391
  offset: Type.Optional(Type.Number({ description: "Char offset to start at (default 0)." })),
407
392
  limit: Type.Optional(Type.Number({ description: `Max chars to return (default ${READ_DEFAULT_LIMIT}, capped ${READ_MAX_LIMIT}).` })),
408
393
  }),
409
- effect: "read",
410
394
  execute: async (args) => {
411
395
  const { ref, offset, limit } = args;
412
396
  const off = Math.max(0, intOr(offset, 0));