@sema-agent/core 7.14.0 → 7.16.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 (136) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/core/ask-origin.d.ts +2 -2
  3. package/dist/core/checkpoint-store.d.ts +14 -15
  4. package/dist/core/governance-codes.js +2 -0
  5. package/dist/core/hooks.d.ts +4 -3
  6. package/dist/core/memory-engine/delegation-settlement.d.ts +37 -12
  7. package/dist/core/memory-engine/delegation-settlement.js +128 -39
  8. package/dist/core/memory-engine/engine.d.ts +9 -8
  9. package/dist/core/memory-engine/engine.js +115 -120
  10. package/dist/core/memory-engine/file-backend.d.ts +17 -5
  11. package/dist/core/memory-engine/file-backend.js +78 -34
  12. package/dist/core/memory-engine/index.d.ts +2 -2
  13. package/dist/core/memory-engine/index.js +2 -2
  14. package/dist/core/memory-engine/layout.d.ts +152 -54
  15. package/dist/core/memory-engine/layout.js +441 -104
  16. package/dist/core/memory-engine/types.d.ts +8 -3
  17. package/dist/core/memory-engine/types.js +5 -0
  18. package/dist/core/runner/abort-race.d.ts +3 -3
  19. package/dist/core/runner/active-skill-scope.d.ts +2 -2
  20. package/dist/core/runner/assemble-result.d.ts +29 -29
  21. package/dist/core/runner/checkpoint-scope.d.ts +4 -4
  22. package/dist/core/runner/clock-and-limits.d.ts +3 -3
  23. package/dist/core/runner/compaction-call-options.d.ts +11 -11
  24. package/dist/core/runner/compaction-knobs.d.ts +4 -4
  25. package/dist/core/runner/compaction-seams.d.ts +5 -5
  26. package/dist/core/runner/contracts.d.ts +224 -226
  27. package/dist/core/runner/decide-continuation.d.ts +6 -6
  28. package/dist/core/runner/denial-limit-arms.d.ts +8 -8
  29. package/dist/core/runner/derived-route-fallback.d.ts +2 -2
  30. package/dist/core/runner/gate-exit.d.ts +6 -6
  31. package/dist/core/runner/git-status-frame.d.ts +7 -7
  32. package/dist/core/runner/inherited-ask-grants.d.ts +6 -6
  33. package/dist/core/runner/memory-capture-optout.d.ts +1 -1
  34. package/dist/core/runner/memory-consolidation-driver.d.ts +4 -4
  35. package/dist/core/runner/memory-consolidation.d.ts +6 -6
  36. package/dist/core/runner/park-commit.d.ts +6 -6
  37. package/dist/core/runner/permission-rule-lanes.d.ts +22 -20
  38. package/dist/core/runner/permission-rule-lanes.js +1 -1
  39. package/dist/core/runner/prepare-acquire-reconcile.d.ts +4 -4
  40. package/dist/core/runner/prepare-ask-lane.d.ts +3 -3
  41. package/dist/core/runner/prepare-boundary-parks.d.ts +3 -3
  42. package/dist/core/runner/prepare-caps-and-workflow.d.ts +5 -5
  43. package/dist/core/runner/prepare-config-doors.d.ts +21 -21
  44. package/dist/core/runner/prepare-context-lane.d.ts +6 -6
  45. package/dist/core/runner/prepare-defer-classify.d.ts +3 -3
  46. package/dist/core/runner/prepare-defer-classify.js +12 -10
  47. package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
  48. package/dist/core/runner/prepare-file-history.d.ts +2 -2
  49. package/dist/core/runner/prepare-gate-stations.d.ts +8 -9
  50. package/dist/core/runner/prepare-gate-stations.js +2 -2
  51. package/dist/core/runner/prepare-hands-readface.d.ts +41 -41
  52. package/dist/core/runner/prepare-hands-readface.js +27 -29
  53. package/dist/core/runner/prepare-inherited-gate.d.ts +6 -6
  54. package/dist/core/runner/prepare-listings.d.ts +3 -3
  55. package/dist/core/runner/prepare-lsp.d.ts +3 -3
  56. package/dist/core/runner/prepare-memory-engine-session.d.ts +5 -5
  57. package/dist/core/runner/prepare-memory.js +6 -7
  58. package/dist/core/runner/prepare-offload-wrappers.d.ts +2 -2
  59. package/dist/core/runner/prepare-park-ask.d.ts +11 -12
  60. package/dist/core/runner/prepare-park-ask.js +3 -3
  61. package/dist/core/runner/prepare-policy-chain.d.ts +6 -6
  62. package/dist/core/runner/prepare-policy-chain.js +2 -2
  63. package/dist/core/runner/prepare-prompt-inputs.d.ts +5 -5
  64. package/dist/core/runner/prepare-protocol-tools.d.ts +1 -1
  65. package/dist/core/runner/prepare-question-face.d.ts +4 -4
  66. package/dist/core/runner/prepare-run-refs.d.ts +11 -11
  67. package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
  68. package/dist/core/runner/prepare-suspend-saga.d.ts +4 -4
  69. package/dist/core/runner/prepare-task.d.ts +12 -12
  70. package/dist/core/runner/prepare-task.js +5 -7
  71. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +2 -3
  72. package/dist/core/runner/prepare-wiring-manifest.d.ts +4 -4
  73. package/dist/core/runner/prepare-workspace-restore.d.ts +1 -1
  74. package/dist/core/runner/remote-env-retry.d.ts +3 -3
  75. package/dist/core/runner/resume-admission.d.ts +1 -1
  76. package/dist/core/runner/resume-claim.d.ts +1 -1
  77. package/dist/core/runner/resume-internals-and-config.d.ts +1 -1
  78. package/dist/core/runner/resume-policy-outcome.d.ts +1 -1
  79. package/dist/core/runner/resume-preflight.d.ts +1 -1
  80. package/dist/core/runner/resume-review-outcome.d.ts +1 -1
  81. package/dist/core/runner/run-brain-sinks.d.ts +1 -1
  82. package/dist/core/runner/run-clock-and-content.d.ts +4 -4
  83. package/dist/core/runner/run-compaction-machinery.d.ts +3 -3
  84. package/dist/core/runner/run-git-lane.d.ts +1 -1
  85. package/dist/core/runner/run-harness-handlers.d.ts +2 -2
  86. package/dist/core/runner/run-identity-wiring.d.ts +4 -4
  87. package/dist/core/runner/run-leg.d.ts +3 -3
  88. package/dist/core/runner/run-notification-lane.d.ts +2 -2
  89. package/dist/core/runner/run-reasoning-seat.d.ts +2 -2
  90. package/dist/core/runner/run-settle-and-teardown.d.ts +4 -4
  91. package/dist/core/runner/run-telemetry-and-budget-seats.d.ts +2 -2
  92. package/dist/core/runner/run-terminal-adoption.d.ts +5 -5
  93. package/dist/core/runner/runtask.d.ts +14 -14
  94. package/dist/core/runner/session-file-state-replay.d.ts +3 -3
  95. package/dist/core/runner/session-rule-policy.d.ts +2 -2
  96. package/dist/core/runner/steer-admission.d.ts +2 -2
  97. package/dist/core/runner/stream-halt-verbs.d.ts +1 -1
  98. package/dist/core/runner/stream-reap.d.ts +1 -1
  99. package/dist/core/runner/synthetic-tools.d.ts +8 -8
  100. package/dist/core/runner/teardown-bounded.d.ts +2 -2
  101. package/dist/core/runner/tool-defer-gate.d.ts +86 -0
  102. package/dist/core/runner/tool-defer-gate.js +57 -0
  103. package/dist/core/runner/tool-disclosure.d.ts +33 -69
  104. package/dist/core/runner/tool-disclosure.js +0 -43
  105. package/dist/core/runner/tool-end-body.d.ts +3 -3
  106. package/dist/core/runner/tool-face-overlay.d.ts +2 -2
  107. package/dist/core/runner/tool-output-projection.d.ts +2 -2
  108. package/dist/core/runner/turn-attachments.d.ts +53 -53
  109. package/dist/core/runner/usage-accounting.d.ts +4 -4
  110. package/dist/core/runner/workspace-path.d.ts +1 -1
  111. package/dist/core/runner-deps.d.ts +16 -9
  112. package/dist/core/task-spec.d.ts +8 -2
  113. package/dist/core/tool-spec.d.ts +7 -4
  114. package/dist/core/types.d.ts +1 -1
  115. package/dist/engine/llm/types.d.ts +1 -1
  116. package/dist/index.d.ts +4 -4
  117. package/dist/index.js +3 -3
  118. package/dist/tools/fs/bash-readonly-classifier.d.ts +40 -40
  119. package/dist/tools/fs/encoding.d.ts +31 -40
  120. package/dist/tools/fs/fs-bash.d.ts +76 -35
  121. package/dist/tools/fs/fs-bash.js +86 -29
  122. package/dist/tools/fs/fs-pdf.d.ts +8 -8
  123. package/dist/tools/fs/fs-search-tools.d.ts +4 -4
  124. package/dist/tools/fs/fs-shared.d.ts +144 -158
  125. package/dist/tools/fs/fs-write.d.ts +8 -8
  126. package/dist/tools/fs/gh-rate-limit.d.ts +13 -14
  127. package/dist/tools/fs/index.d.ts +74 -78
  128. package/dist/tools/fs/notebook.d.ts +24 -25
  129. package/dist/tools/fs/pdf.d.ts +3 -3
  130. package/dist/tools/fs/read-deny.d.ts +22 -22
  131. package/dist/tools/fs/read-face.d.ts +21 -24
  132. package/dist/tools/fs/repo-map.d.ts +8 -8
  133. package/dist/tools/fs/safety.d.ts +116 -129
  134. package/dist/tools/fs/search.d.ts +63 -71
  135. package/package.json +5 -2
  136. package/test/export-surface.snapshot.json +9 -1
@@ -0,0 +1,57 @@
1
+ import { DEFAULT_CHARS_PER_TOKEN } from "../../internal/harness.js";
2
+ export const DEFER_THRESHOLD_FRACTION = 0.1;
3
+ const CHARS_PER_TOKEN = DEFAULT_CHARS_PER_TOKEN;
4
+ function inlinedChars(t) {
5
+ let schema = "";
6
+ try {
7
+ schema = JSON.stringify(t.parameters) ?? "";
8
+ }
9
+ catch {
10
+ schema = "";
11
+ }
12
+ return t.name.length + t.description.length + schema.length;
13
+ }
14
+ export const DEFER_MODE_INVALID_CODE = "config.defer_mode_invalid";
15
+ export function deferralGate(opts) {
16
+ if (opts.deferMode !== undefined && opts.deferMode !== "auto") {
17
+ const e = new Error(`RunnerDeps.deferMode: invalid value ${JSON.stringify(opts.deferMode)} — expected "auto" or omitted; a bad value refuses loudly, nothing falls back to a default.`);
18
+ e.code = DEFER_MODE_INVALID_CODE;
19
+ throw e;
20
+ }
21
+ const pinned = new Set(opts.alwaysLoadNames ?? []);
22
+ for (const s of opts.specs) {
23
+ if (s.alwaysLoad === true)
24
+ pinned.add(s.name);
25
+ }
26
+ const explicit = new Set();
27
+ for (const name of opts.callerDeferNames ?? [])
28
+ if (!pinned.has(name))
29
+ explicit.add(name);
30
+ const gated = new Set();
31
+ const select = (name) => {
32
+ if (!pinned.has(name) && !explicit.has(name))
33
+ gated.add(name);
34
+ };
35
+ for (const s of opts.specs)
36
+ if (s.defer === true || opts.deferMode === "auto")
37
+ select(s.name);
38
+ for (const name of opts.protocolToolNames)
39
+ select(name);
40
+ for (const name of opts.builtinDeferNames ?? [])
41
+ select(name);
42
+ let gatedChars = 0;
43
+ for (const t of opts.fullTools)
44
+ if (gated.has(t.name))
45
+ gatedChars += inlinedChars(t);
46
+ const windowTokens = Math.max(0, opts.model.contextTokens ?? opts.model.contextWindow ?? 0);
47
+ const thresholdChars = Math.floor(windowTokens * DEFER_THRESHOLD_FRACTION) * CHARS_PER_TOKEN;
48
+ return { explicit, gated, gatedChars, thresholdChars, open: gatedChars >= thresholdChars };
49
+ }
50
+ export function classifyDeferred(opts) {
51
+ const gate = deferralGate(opts);
52
+ const deferred = new Set(gate.explicit);
53
+ if (gate.open)
54
+ for (const n of gate.gated)
55
+ deferred.add(n);
56
+ return deferred;
57
+ }
@@ -1,10 +1,7 @@
1
1
  import { type TSchema } from "typebox";
2
2
  import type { AgentMessage, AgentTool, AgentToolResult, AgentToolUpdateCallback, ToolExecutionMode } from "../../internal/harness-types.js";
3
- import type { Model } from "../../internal/llm.js";
4
- import type { ToolSpec } from "../types.js";
5
- import type { ToolFingerprintInput } from "../cache-break-detector.js";
6
3
  /**
7
- * Deferred-tool dynamic disclosure (design/36). A deployment with hundreds of tools / several MCP
4
+ * Deferred-tool dynamic disclosure. A deployment with hundreds of tools / several MCP
8
5
  * servers can't inline every full JSON Schema into every request — turn-1 cache-creation tokens
9
6
  * explode and any tool-description drift breaks the prefix cache. Instead, deferred tools ship as
10
7
  * lightweight placeholders ({name, one-line hint, empty params}); a resident `tool_search` lets the
@@ -13,13 +10,13 @@ import type { ToolFingerprintInput } from "../cache-break-detector.js";
13
10
  * announces them via the search's own result content (tail of the log; the cache prefix is untouched).
14
11
  *
15
12
  * This module is pure tool/registry logic: prepare-task owns the harness wiring and supplies a
16
- * `rematerialize` callback (which calls `harness.setTools` + refreshes the design/31 fingerprint).
13
+ * `rematerialize` callback (which calls `harness.setTools` + refreshes the fingerprint).
17
14
  */
18
15
  export declare const TOOL_SEARCH_NAME = "ToolSearch";
19
- /** Default keyword-search result cap (design/116 W1-2 = CC ToolSearchTool.ts:28-32 `max_results` default 5). */
16
+ /** Default keyword-search result cap (CC ToolSearchTool.ts:28-32 `max_results` default 5). */
20
17
  export declare const TOOL_SEARCH_DEFAULT_MAX_RESULTS = 5;
21
18
  /**
22
- * design/168 — how many times in a row ONE placeholder may answer the IDENTICAL invalid-arguments
19
+ * How many times in a row ONE placeholder may answer the IDENTICAL invalid-arguments
23
20
  * shape before the lane declares the loop unproductive and stops re-teaching. Three, because the
24
21
  * corrective round is worth paying for twice (the first rejection hands over the schema; a second
25
22
  * covers a model that needed the restatement) and a third identical failure is evidence that the
@@ -46,49 +43,16 @@ export interface DeferredToolInfo {
46
43
  /** First line of a description, trimmed to a single short hint for a placeholder / announcement. */
47
44
  export declare function deferHint(description: string, max?: number): string;
48
45
  /**
49
- * Neutralize a tool name before it appears in ANY model-facing text (design/36 minor #5). A tool name is
46
+ * Neutralize a tool name before it appears in ANY model-facing text. A tool name is
50
47
  * externally influenced — an untrusted MCP server can return one containing newlines (to inject a fake
51
48
  * `<system-reminder>`/instruction line), backticks/quotes (to corrupt the JSON or markdown the model is
52
49
  * told to emit), or angle brackets (to break a delimiter). Strip control chars, CR/LF, `` ` ``, `"`, `<`, `>`.
53
50
  * For a normal name (`[A-Za-z0-9_.-]`, incl. MCP `server__tool`) this is a no-op.
54
51
  *
55
52
  * MUST wrap a tool name at EVERY site where it reaches the model — placeholder text, the search tool's
56
- * announcement, anywhere. A bare interpolation is a prompt-injection hole (council BUG, design/36).
53
+ * announcement, anywhere. A bare interpolation is a prompt-injection hole.
57
54
  */
58
55
  export declare function safeName(name: string): string;
59
- /**
60
- * Decide which tool names are deferred. THIS CONTRACT IS THE SINGLE AUTHORITY on the default-mode
61
- * source list (TaskSpec/RunnerDeps JSDoc points here), so every arm the body implements is named:
62
- * deterministic by default = explicit `ToolSpec.defer === true`, plus every REMOTE-PROTOCOL tool name
63
- * (MCP servers AND A2A peers — most numerous / most drift-prone), plus `deferNames`, i.e. the
64
- * already-mounted wire names from `TaskSpec.deferTools` and from BUILT-INS that declare their own
65
- * `defer` (a built-in ToolSpec never reaches `specs`, so its declared deferral has to arrive here as a
66
- * mounted name — this is why the shared-memory pair defaults to deferred). With `deferMode: "auto"`, ADDITIONALLY
67
- * defer the remaining user tools when their combined inlined schema would exceed ~10% of the model's
68
- * context window — an explicit opt-in (council minor #6), because an implicit threshold makes the same
69
- * TaskSpec yield different tools[] across models/contexts. Explicit `defer` always wins — except
70
- * against an alwaysLoad pin (RB-400-a), which exempts a name from every deferral source.
71
- */
72
- export declare function classifyDeferred(opts: {
73
- specs: ReadonlyArray<ToolSpec>;
74
- /** Every namespaced tool a remote protocol materialized for this task (MCP servers AND A2A peers —
75
- * the caller unions them). The constant-defer arm is about the SHAPE of a remote roster (many tools,
76
- * schemas the deployment does not control, drift between tasks), which is the same for every protocol
77
- * in the table: naming one protocol here left the next one inlined by omission, with nobody deciding
78
- * that. Only an alwaysLoad pin exempts a name. */
79
- protocolToolNames: ReadonlyArray<string>;
80
- fullTools: ReadonlyArray<ToolFingerprintInput>;
81
- deferMode?: "auto";
82
- model: Model;
83
- /** TaskSpec.deferTools — defer ALREADY-MOUNTED tools by wire name (built-ins included;
84
- * `ToolSpec.defer` only reaches caller specs). Caller pre-filters to mounted names. */
85
- deferNames?: ReadonlyArray<string>;
86
- /** RB-400-a — inline-pin names (`TaskSpec.alwaysLoadTools` + the MCP tools whose server declared
87
- * `_meta["anthropic/alwaysLoad"]`, caller-collected; A2A has no such per-skill declaration, so the
88
- * task-level list is a peer's only inline-keep channel): exempt from EVERY deferral source below.
89
- * `ToolSpec.alwaysLoad` rides the specs directly and needs no entry here. */
90
- alwaysLoadNames?: ReadonlyArray<string>;
91
- }): Set<string>;
92
56
  /** Build the registry the search ranks over (deferred tools only — non-deferred are already visible). */
93
57
  export declare function buildDeferredRegistry(deferred: ReadonlySet<string>, tools: ReadonlyArray<{
94
58
  name: string;
@@ -96,7 +60,7 @@ export declare function buildDeferredRegistry(deferred: ReadonlySet<string>, too
96
60
  aliases?: readonly string[];
97
61
  }>): Map<string, DeferredToolInfo>;
98
62
  /**
99
- * RB-403 — the direct-call lane a placeholder may carry. The upstream defer gate is SHAPE
63
+ * The direct-call lane a placeholder may carry. The upstream defer gate is SHAPE
100
64
  * validation, not activation state: a call whose arguments validate against the REAL tool's
101
65
  * declared schema runs the real tool directly (activation is only about whether the model has
102
66
  * been SHOWN the schema, never an execution gate). Governance cannot be laundered through this
@@ -106,7 +70,7 @@ export declare function buildDeferredRegistry(deferred: ReadonlySet<string>, too
106
70
  */
107
71
  export interface PlaceholderDirectCall {
108
72
  /**
109
- * RB-414 — resolve the real tool AT CALL TIME, never from a prepare-time snapshot. The mounted
73
+ * Resolve the real tool AT CALL TIME, never from a prepare-time snapshot. The mounted
110
74
  * roster is a LIVE array: an MCP refresh splices a server's name domain out and pushes freshly
111
75
  * materialized tool objects back in, so a Map captured when the placeholder was built would hand
112
76
  * this lane the WITHDRAWN object (stale schema shape gate, stale transport client) long after the
@@ -115,19 +79,19 @@ export interface PlaceholderDirectCall {
115
79
  */
116
80
  resolveReal: () => PlaceholderDirectTarget | undefined;
117
81
  /**
118
- * RB-415① — the scheduling declaration this placeholder carries while it stands in for the real
82
+ * The scheduling declaration this placeholder carries while it stands in for the real
119
83
  * tool. Mirrors the REAL tool's own `executionMode` (see the mirror rationale in
120
84
  * {@link createPlaceholderTool}); absent ⇒ the engine's fail-closed default, exactly as it would
121
85
  * be for the real tool once activated.
122
86
  */
123
87
  executionMode?: ToolExecutionMode;
124
88
  /**
125
- * design/168 — does THIS name sit on the static face right now, i.e. will it never be swapped for
89
+ * Does THIS name sit on the static face right now, i.e. will it never be swapped for
126
90
  * the real tool's declaration? The lane's model-facing rejection text reads it to say where the
127
91
  * schema it hands back actually lives (this result only, versus this result AND every later
128
92
  * request's tools block). Absent ⇒ the swap posture.
129
93
  *
130
- * A FUNCTION, evaluated per call, for the same reason `resolveReal` is (RB-414): the answer is not
94
+ * A FUNCTION, evaluated per call, for the same reason `resolveReal` is: the answer is not
131
95
  * a prepare-time constant. The run-wide strategy is, but the per-tool exemption on top of it reads
132
96
  * the LIVE roster — an MCP refresh can replace a tool with a declaration that no longer fits the
133
97
  * result-text carrier (or one that now does), and a boolean captured when the placeholder was built
@@ -137,9 +101,9 @@ export interface PlaceholderDirectCall {
137
101
  /**
138
102
  * Activation side effects (active-set add + rematerialize + boundary delta announcement).
139
103
  * Idempotent; awaited BEFORE the invoke so the next boundary already shows the full schema.
140
- * RB-415② — MUST be atomic: a thrown rematerialize has to leave the active set as it found it.
104
+ * MUST be atomic: a thrown rematerialize has to leave the active set as it found it.
141
105
  *
142
- * RB-431 — returns the announcement text this activation has to CARRY, or `undefined` when it has
106
+ * Returns the announcement text this activation has to CARRY, or `undefined` when it has
143
107
  * none (already active, or nothing rides on this name). The ToolSearch lane announces on its own
144
108
  * result content; a direct call makes no ToolSearch call at all, so a face whose only carrier is
145
109
  * that result — today the agent-type roster of a deferred delegation tool — had no way to reach
@@ -154,13 +118,13 @@ export interface PlaceholderDirectTarget {
154
118
  /** The REAL tool's declared parameter schema — the shape gate for a direct call. */
155
119
  parameters: TSchema;
156
120
  /** Invoke the real tool; the result passes through VERBATIM (structured details intact).
157
- * RB-416 — `onUpdate` is part of the contract: the engine hands every execute a progress sink,
121
+ * `onUpdate` is part of the contract: the engine hands every execute a progress sink,
158
122
  * and dropping it here silently mutes streaming progress (MCP `notifications/progress`) for any
159
123
  * tool reached through this lane, while the SAME tool streams normally once activated. */
160
124
  invoke: (toolCallId: string, params: unknown, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<unknown>) => Promise<AgentToolResult<unknown>>;
161
125
  }
162
126
  /**
163
- * design/168 — can the STATIC face carry this declaration at all? Static's only in-context schema
127
+ * Can the STATIC face carry this declaration at all? Static's only in-context schema
164
128
  * carrier is result TEXT, so a declaration that cannot be serialized, or that the model-facing error
165
129
  * bound would truncate into non-JSON, has no carrier there. Such a tool is exempted per-tool from the
166
130
  * static face (it materializes into the tools block on activation, the swap way) rather than being
@@ -169,20 +133,20 @@ export interface PlaceholderDirectTarget {
169
133
  */
170
134
  export declare function staticSchemaRenderable(schema: TSchema | undefined): boolean;
171
135
  /** A placeholder AgentTool for a deferred tool: visible name + hint, empty params. Without `direct`,
172
- * every call is the teaching rejection; with it, a schema-valid call runs the real tool (RB-403). */
136
+ * every call is the teaching rejection; with it, a schema-valid call runs the real tool. */
173
137
  export declare function createPlaceholderTool(info: DeferredToolInfo, direct?: PlaceholderDirectCall): AgentTool;
174
138
  /** Keyword score of a query against a deferred tool: name hits weigh more than description/hint hits. */
175
139
  export declare function scoreToolMatch(query: string, info: DeferredToolInfo): number;
176
- /** The argument shapes `tool_search` accepts (design/116 W1-2, CC-canonical): `query` (+ optional
177
- * `max_results`). RB-482 #5 (ruled 2026-08-03): the pre-design/116 `select` ARRAY arm is retired —
178
- * durable-replay compat was already sacrificed by the RB-476-A ruling (replay resolution included);
140
+ /** The argument shapes `tool_search` accepts (CC-canonical): `query` (+ optional
141
+ * `max_results`). The pre-keyword-search `select` ARRAY arm is retired —
142
+ * durable-replay compat was already sacrificed by a prior ruling (replay resolution included);
179
143
  * the CC-canonical `select:A,B,C` string prefix inside `query` is the live selection form. */
180
144
  export interface ToolSearchArgs {
181
145
  query?: string;
182
146
  max_results?: number;
183
147
  }
184
148
  /**
185
- * Resolve a tool_search request to deferred-tool names (design/116 W1-2, CC ToolSearchTool.ts form).
149
+ * Resolve a tool_search request to deferred-tool names (CC ToolSearchTool.ts form).
186
150
  * Query forms, checked in order:
187
151
  * ① `select:A,B,C` prefix (case-insensitive prefix, CC ToolSearchTool.ts:363) — comma-split EXACT
188
152
  * name activation against the registry's names; misses are reported in `missing` (never silently
@@ -190,7 +154,7 @@ export interface ToolSearchArgs {
190
154
  * ② bare tool name (case-insensitive equality, CC:199-204) — selects that tool directly; handles
191
155
  * models sending a name instead of the select: prefix (seen from subagents/post-compaction).
192
156
  * ③ keyword search — scored matches capped at `max_results` (CC default 5).
193
- * RB-482 #5: the pre-design/116 `select` ARRAY arm is retired (see {@link ToolSearchArgs}) — a stale
157
+ * The pre-keyword-search `select` ARRAY arm is retired (see {@link ToolSearchArgs}) — a stale
194
158
  * replayed array argument now resolves like an empty query (nothing matched, honestly).
195
159
  */
196
160
  export declare function resolveToolSearchDetailed(args: ToolSearchArgs, registry: ReadonlyMap<string, DeferredToolInfo>): {
@@ -201,16 +165,16 @@ export declare function resolveToolSearchDetailed(args: ToolSearchArgs, registry
201
165
  * {@link extractDiscoveredToolNames} (and kept as the stable exported signature). */
202
166
  export declare function resolveToolSearch(args: ToolSearchArgs, registry: ReadonlyMap<string, DeferredToolInfo>): string[];
203
167
  /**
204
- * Stateless recompute of the activated-tool set from the message log (design/36 §2.3). The in-process
168
+ * Stateless recompute of the activated-tool set from the message log. The in-process
205
169
  * `active` Set is the primary source within one process, but a RESUMED session (new process) starts with
206
170
  * an empty Set — without this, previously-activated tools would revert to placeholders. Two carriers,
207
171
  * both deterministic and both replayed here:
208
172
  *
209
173
  * ① every prior `tool_search` call's arguments, re-resolved through `resolveToolSearch` — unless that
210
- * call's OWN result carries the error flag (RB-450 S4: a denied/blocked search never reached execute
174
+ * call's OWN result carries the error flag (a denied/blocked search never reached execute
211
175
  * and staged nothing; a call with no result at all keeps the historic credit);
212
- * ② RB-431 — a SUCCESSFUL call on a deferred name, which is an activation in its own right: the
213
- * RB-403 direct lane runs `activate()` BEFORE it invokes the real tool, so a result that came back
176
+ * ② A SUCCESSFUL call on a deferred name, which is an activation in its own right: the
177
+ * direct lane runs `activate()` BEFORE it invokes the real tool, so a result that came back
214
178
  * without an error flag can only have come from a call that passed the shape gate and activated.
215
179
  * No new carrier had to be minted for this: the toolCall part and its result are already in the
216
180
  * transcript. Before this arm, a direct activation left NO trace at all — the next leg reverted the
@@ -223,14 +187,14 @@ export declare function resolveToolSearch(args: ToolSearchArgs, registry: Readon
223
187
  * denial or hook block, an abort, invalid arguments — is flagged as an error, and none of them activated
224
188
  * anything. It is an UNDER-approximation in one direction only: an activation whose real tool then failed
225
189
  * (or threw) is not counted, so that name reverts to a placeholder and the model re-activates on demand —
226
- * self-healing, exactly like the design/116 keyword-cap note below, never a widening. The shape-INVALID
190
+ * self-healing, exactly like the keyword-cap note below, never a widening. The shape-INVALID
227
191
  * direct call (ruled 2026-08-03) activates too and is flagged as an error, so it lands in that same
228
192
  * under-approximated class by construction: within the process the in-memory `active` set carries it, and
229
193
  * a replay that loses it costs the corrected call — which succeeds, and is itself carrier ②. The one way to
230
194
  * self-declare a positive is a deployment `tool_result` hook that rewrites a rejection's error flag to false,
231
195
  * which is the deployment editing its own transcript.
232
196
  *
233
- * design/116 W1-2 note: pre-116 checkpoints whose KEYWORD queries activated up to 25 tools re-derive at
197
+ * Pre-116 checkpoints whose KEYWORD queries activated up to 25 tools re-derive at
234
198
  * the new default cap (5) — the extra tools revert to placeholders, which is self-healing (the model
235
199
  * re-activates on demand), never a widening. Exact-name and `select:`-prefix activations replay unchanged.
236
200
  *
@@ -244,14 +208,14 @@ export declare function extractDiscoveredToolNames(messages: ReadonlyArray<Agent
244
208
  /**
245
209
  * Build the resident `tool_search` tool. On a search that NEWLY activates deferred tools it (1) adds them
246
210
  * to the monotonic `active` Set, (2) calls `rematerialize` (prepare-task swaps placeholders→full schema
247
- * via `harness.setTools` and refreshes the design/31 fingerprint), and (3) returns the "now available"
211
+ * via `harness.setTools` and refreshes the fingerprint), and (3) returns the "now available"
248
212
  * announcement as its OWN result content — the delta lands at the tail of the log, never in the cache prefix.
249
213
  */
250
214
  export declare function createToolSearchTool(opts: {
251
215
  registry: ReadonlyMap<string, DeferredToolInfo>;
252
216
  active: Set<string>;
253
217
  rematerialize: (active: ReadonlySet<string>) => Promise<void>;
254
- /** RB-28 terminal fix — listing ride-along on the design/36 channel: when an activation newly
218
+ /** Listing ride-along on the deferred-tool channel: when an activation newly
255
219
  * materializes a listing-bearing tool (the deferred delegation tool whose description points at an
256
220
  * agent-types listing that the deferred leg's boundary producer never ships), the caller returns
257
221
  * the listing text here and it rides THIS search's own result content — tail of the log, cache
@@ -262,12 +226,12 @@ export declare function createToolSearchTool(opts: {
262
226
  * "Workflow is already available — call it" instead of a generic not-found that reads as absence
263
227
  * (observed: the model treated the miss as unavailability and only recovered by guessing). */
264
228
  mountedNames?: () => ReadonlySet<string>;
265
- /** DD-5 — whether the placeholders on this task carry the RB-403 direct-call lane
229
+ /** Whether the placeholders on this task carry the direct-call lane
266
230
  * (`TaskSpec.deferSelfResolve` not disabled). Selects which of the two teaching postures below is
267
231
  * true for this task; defaults to the direct-lane posture, matching the spec field's own default. */
268
232
  directCallEnabled?: boolean;
269
- /** RB-450 S3 — run this tool's activation critical section on the CALLER's serializer instead of a
270
- * private one. The `active` set and `rematerialize` are shared with the RB-403 direct-call lane,
233
+ /** Run this tool's activation critical section on the CALLER's serializer instead of a
234
+ * private one. The `active` set and `rematerialize` are shared with the direct-call lane,
271
235
  * which activates from a placeholder's own execute; both lanes must queue on ONE section or a
272
236
  * concurrent batch lets the direct lane stage a name while this section is still pending (and
273
237
  * vice versa, so a rollback here cannot be observed as "already active" there). Absent ⇒ a private
@@ -283,7 +247,7 @@ export declare function createToolSearchTool(opts: {
283
247
  */
284
248
  isMounted?: (name: string) => boolean;
285
249
  serializeActivation?: <T>(section: () => Promise<T>) => Promise<T>;
286
- /** design/168 "static" materialization (ruled 2026-08-05): resolve a deferred name's REAL declared
250
+ /** Resolve a deferred name's REAL declared
287
251
  * parameter schema, read from the live roster at call time. Presence switches this face to the
288
252
  * static posture: activation never swaps the placeholder in the tools block, so the result text
289
253
  * BELOW is the schema's only in-context carrier — each matched tool's schema is inlined into the
@@ -2,11 +2,8 @@ import { Type } from "typebox";
2
2
  import { Value } from "typebox/value";
3
3
  import { defineTool, errorResult } from "../tools.js";
4
4
  import { formatZodValidationError, truncateError } from "../tool-errors.js";
5
- import { DEFAULT_CHARS_PER_TOKEN } from "../../internal/harness.js";
6
5
  import { toolFace } from "../tool-catalog-entries.js";
7
6
  export const TOOL_SEARCH_NAME = "ToolSearch";
8
- const DEFER_AUTO_FRACTION = 0.1;
9
- const CHARS_PER_TOKEN = DEFAULT_CHARS_PER_TOKEN;
10
7
  export const TOOL_SEARCH_DEFAULT_MAX_RESULTS = 5;
11
8
  const MAX_QUERY_RESULTS = 25;
12
9
  export const DEFERRED_NO_PROGRESS_LIMIT = 3;
@@ -19,46 +16,6 @@ export function deferHint(description, max = 120) {
19
16
  export function safeName(name) {
20
17
  return name.replace(/[\x00-\x1f<>"`]/g, "");
21
18
  }
22
- function inlinedChars(t) {
23
- let schema = "";
24
- try {
25
- schema = JSON.stringify(t.parameters) ?? "";
26
- }
27
- catch {
28
- schema = "";
29
- }
30
- return t.description.length + schema.length;
31
- }
32
- export function classifyDeferred(opts) {
33
- const pinned = new Set(opts.alwaysLoadNames ?? []);
34
- for (const s of opts.specs) {
35
- if (s.alwaysLoad === true)
36
- pinned.add(s.name);
37
- }
38
- const deferred = new Set();
39
- for (const s of opts.specs) {
40
- if (s.defer === true && !pinned.has(s.name))
41
- deferred.add(s.name);
42
- }
43
- for (const name of opts.protocolToolNames)
44
- if (!pinned.has(name))
45
- deferred.add(name);
46
- for (const name of opts.deferNames ?? [])
47
- if (!pinned.has(name))
48
- deferred.add(name);
49
- if (opts.deferMode === "auto") {
50
- const callerNames = new Set(opts.specs.map((s) => s.name));
51
- const candidates = opts.fullTools.filter((t) => !deferred.has(t.name) && !pinned.has(t.name) && callerNames.has(t.name));
52
- const inlineFace = opts.fullTools.filter((t) => !deferred.has(t.name));
53
- const total = inlineFace.reduce((n, t) => n + inlinedChars(t), 0);
54
- const window = (opts.model.contextTokens ?? opts.model.contextWindow ?? 0) * CHARS_PER_TOKEN;
55
- if (window > 0 && total > DEFER_AUTO_FRACTION * window) {
56
- for (const t of candidates)
57
- deferred.add(t.name);
58
- }
59
- }
60
- return deferred;
61
- }
62
19
  export function buildDeferredRegistry(deferred, tools) {
63
20
  const reg = new Map();
64
21
  for (const t of tools) {
@@ -17,13 +17,13 @@ import { type McpDelivered } from "../mcp-failure.js";
17
17
  import type { RecoveredOrphan } from "../session-reconcile.js";
18
18
  import { type StructuredProjector } from "./tool-output-projection.js";
19
19
  import type { WriteFamily } from "./turn-attachments.js";
20
- /** design/134 §3.1b — derive the thin `response` digest from a harness tool result: model-facing text
20
+ /** Derive the thin `response` digest from a harness tool result: model-facing text
21
21
  * content only (never `details` — the H4 thin-projection discipline), capped with a truncation note. */
22
22
  export declare function batchResponseDigest(result: unknown): string | undefined;
23
23
  /** The `tool_end` body fields projected from a harness tool result — output/truncated/totalChars via
24
24
  * {@link toolOutputFrom} and the CC card via the LEG's projector (`Prepared.structuredProjector`: the engine card set
25
25
  * ∪ the caller rows' declared `renderHints.resultCards`, an undeclared type dropped and announced once per leg —
26
- * design/388 L4; handed in because the once-per-leg state lives on the leg). Single construction point for BOTH
26
+ * handed in because the once-per-leg state lives on the leg. Single construction point for BOTH
27
27
  * the live loop's frames and the resumed batch's frames (`resolvePendingCall` + the deferred-sibling
28
28
  * close): the resumed frames used to carry only `isError`, so a client rendering tool output from frames
29
29
  * showed an empty body for every durable-approved call. Same projection = same source as the transcript.
@@ -72,7 +72,7 @@ export declare function reconciledToolEndBody(orphan: Pick<RecoveredOrphan, "tex
72
72
  /** task #51 F2/F3 — the CANONICAL write-tool → reminder-window mapping (CC qFm :480253-480254
73
73
  * `a.name === bD || a.name === hF` = TaskCreate/TaskUpdate; BFm :480217-480219 = TodoWrite). Live
74
74
  * deployment-alias resolution happens at the call sites (run-local `writeFamilyOf` over the mounted
75
- * roster); retired-name normalization is gone (RB-476-A, 5.0.0). */
75
+ * roster); retired-name normalization is gone. */
76
76
  export declare function writeFamilyOfCanonical(name: string): WriteFamily | undefined;
77
77
  /** A `toolResult` transcript message (text content). Used by the resume engine to close pending calls. */
78
78
  export declare function toolResultMsg(toolCallId: string, toolName: string, text: string, isError: boolean): AgentMessage;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * design/388 §1.1 / §2.7 — the MCP `toolFaces` OVERLAY: a deployment's per-tool face declaration for a
2
+ * The MCP `toolFaces` OVERLAY: a deployment's per-tool face declaration for a
3
3
  * protocol tool that has no `ToolSpec` of its own (`McpServerSpec.toolFaces`, keyed by the server's RAW
4
4
  * tool name like `allowTools` / `toolAxes`). Validated against the MATERIALIZED schema at every listing
5
5
  * (the first mount and every RefreshMcpTools): `pathTarget.param` must be a top-level property; an
@@ -16,7 +16,7 @@ import type { AgentTool } from "../../internal/harness-types.js";
16
16
  import type { McpServerSpec } from "../mcp-server-spec.js";
17
17
  import { type ToolApprovalCard } from "../tool-face.js";
18
18
  import { type EngineNotice } from "../engine-notice.js";
19
- /** The keys each specialised approval card needs on the call (design/388 §2.5 boundary ①: the SHELL owns the
19
+ /** The keys each specialised approval card needs on the call (the SHELL owns the
20
20
  * card's full schema; this is the pre-filter the overlay is validated against). */
21
21
  export declare const APPROVAL_CARD_REQUIRED_KEYS: Readonly<Record<ToolApprovalCard, readonly string[]>>;
22
22
  export type McpToolFace = NonNullable<McpServerSpec["toolFaces"]>[string];
@@ -1,5 +1,5 @@
1
1
  /**
2
- * design/157 B15 一期 (R4 相位抽取) — the `tool_end` output/structured projection, verbatim from
2
+ * The `tool_end` output/structured projection, verbatim from
3
3
  * `runtask.ts`'s runLocked R4 phase. Pure functions over the harness `AgentToolResult`: zero closure
4
4
  * state, zero runtask coupling — the ONLY module-level input is the size cap below. Event-sequence
5
5
  * snapshot pin (recorded before/after the move, byte-equal) guards the projection semantics.
@@ -14,7 +14,7 @@ export declare const toolOutputFrom: (result: unknown) => {
14
14
  * as a parameter — there is no module-level card set to fall back to. */
15
15
  export type StructuredProjector = (result: unknown) => unknown;
16
16
  /**
17
- * L4's run-time half (design/388 §2.4): a per-leg projector — the engine card set plus the leg's declared
17
+ * L4's run-time half: a per-leg projector — the engine card set plus the leg's declared
18
18
  * caller cards — that DROPS an undeclared `details.type` and announces it ONCE per leg
19
19
  * (`config.tool_card_undeclared`, audience operator). With no options it is the engine set alone, unannounced —
20
20
  * the shape a caller outside a leg (a test, a fixture) uses.