@sema-agent/core 7.17.7 → 7.19.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 (201) hide show
  1. package/CHANGELOG.md +233 -13
  2. package/dist/agents/send-message-tool.js +1 -0
  3. package/dist/agents/subagent.d.ts +1 -0
  4. package/dist/agents/subagent.js +5 -0
  5. package/dist/agents/teacher.js +1 -0
  6. package/dist/agents/verify.js +3 -0
  7. package/dist/brain/anthropic.js +6 -3
  8. package/dist/brain/open-responses.js +10 -4
  9. package/dist/brain/openai.js +5 -2
  10. package/dist/brain/reasoning.d.ts +13 -13
  11. package/dist/brain/reasoning.js +2 -2
  12. package/dist/brain/route-adjudicator.d.ts +18 -0
  13. package/dist/brain/route-adjudicator.js +16 -0
  14. package/dist/brain/stream-engine.js +2 -1
  15. package/dist/brain/stream-shared.d.ts +3 -0
  16. package/dist/brain/stream-shared.js +1 -0
  17. package/dist/core/agent-definition.d.ts +10 -0
  18. package/dist/core/artifact-host.d.ts +41 -4
  19. package/dist/core/artifact-host.js +18 -2
  20. package/dist/core/ask-origin.d.ts +16 -0
  21. package/dist/core/ask-origin.js +8 -0
  22. package/dist/core/auto-mode-arming.d.ts +6 -0
  23. package/dist/core/auto-mode-arming.js +5 -5
  24. package/dist/core/auto-mode-defaults.d.ts +43 -15
  25. package/dist/core/auto-mode-defaults.js +4 -1
  26. package/dist/core/auto-mode.d.ts +184 -59
  27. package/dist/core/auto-mode.js +188 -13
  28. package/dist/core/checkpoint-store.d.ts +23 -2
  29. package/dist/core/checkpoint-store.js +2 -2
  30. package/dist/core/engine-notice.d.ts +77 -1
  31. package/dist/core/engine-notice.js +7 -0
  32. package/dist/core/gate-fold.js +5 -1
  33. package/dist/core/gate-lanes.js +9 -8
  34. package/dist/core/gate-outcome.d.ts +42 -2
  35. package/dist/core/gate-outcome.js +23 -0
  36. package/dist/core/governance-codes.d.ts +1 -1
  37. package/dist/core/governance-codes.js +14 -0
  38. package/dist/core/hook-seats.d.ts +66 -0
  39. package/dist/core/hook-seats.js +37 -0
  40. package/dist/core/hooks.d.ts +1 -1
  41. package/dist/core/read-root-candidate.d.ts +12 -0
  42. package/dist/core/read-root-candidate.js +24 -0
  43. package/dist/core/roles.d.ts +9 -1
  44. package/dist/core/roles.js +4 -0
  45. package/dist/core/runner/advertised-writable-dirs.d.ts +8 -3
  46. package/dist/core/runner/assemble-result.d.ts +2 -1
  47. package/dist/core/runner/assemble-result.js +1 -1
  48. package/dist/core/runner/classifier-ladder.d.ts +227 -0
  49. package/dist/core/runner/classifier-ladder.js +214 -0
  50. package/dist/core/runner/contracts.d.ts +71 -13
  51. package/dist/core/runner/decide-continuation.d.ts +1 -3
  52. package/dist/core/runner/decide-continuation.js +1 -7
  53. package/dist/core/runner/deferral-census.d.ts +52 -0
  54. package/dist/core/runner/deferral-census.js +44 -0
  55. package/dist/core/runner/denial-limit-arms.js +2 -2
  56. package/dist/core/runner/derived-route-fallback.d.ts +8 -4
  57. package/dist/core/runner/derived-route-fallback.js +8 -3
  58. package/dist/core/runner/gate-exit.d.ts +12 -0
  59. package/dist/core/runner/gate-exit.js +6 -3
  60. package/dist/core/runner/prepare-artifact.d.ts +10 -2
  61. package/dist/core/runner/prepare-artifact.js +5 -4
  62. package/dist/core/runner/prepare-ask-lane.js +1 -0
  63. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
  64. package/dist/core/runner/prepare-caps-and-workflow.js +43 -55
  65. package/dist/core/runner/prepare-config-doors.d.ts +7 -1
  66. package/dist/core/runner/prepare-config-doors.js +13 -13
  67. package/dist/core/runner/prepare-defer-classify.d.ts +13 -19
  68. package/dist/core/runner/prepare-defer-classify.js +8 -3
  69. package/dist/core/runner/prepare-gate-stations.d.ts +26 -0
  70. package/dist/core/runner/prepare-gate-stations.js +1 -1
  71. package/dist/core/runner/prepare-hands-readface.d.ts +24 -7
  72. package/dist/core/runner/prepare-hands-readface.js +60 -24
  73. package/dist/core/runner/prepare-inherited-gate.d.ts +17 -4
  74. package/dist/core/runner/prepare-inherited-gate.js +10 -2
  75. package/dist/core/runner/prepare-lsp.d.ts +2 -2
  76. package/dist/core/runner/prepare-lsp.js +1 -1
  77. package/dist/core/runner/prepare-policy-chain.js +2 -0
  78. package/dist/core/runner/prepare-project-context.d.ts +5 -1
  79. package/dist/core/runner/prepare-project-context.js +7 -4
  80. package/dist/core/runner/prepare-prompt-inputs.d.ts +4 -2
  81. package/dist/core/runner/prepare-prompt-inputs.js +4 -1
  82. package/dist/core/runner/prepare-run-refs.d.ts +9 -1
  83. package/dist/core/runner/prepare-run-refs.js +3 -2
  84. package/dist/core/runner/prepare-suspend-saga.d.ts +5 -0
  85. package/dist/core/runner/prepare-suspend-saga.js +5 -2
  86. package/dist/core/runner/prepare-task.js +19 -14
  87. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +5 -0
  88. package/dist/core/runner/prepare-tool-disclosure-mount.js +10 -2
  89. package/dist/core/runner/prepare-turn-wiring.d.ts +8 -4
  90. package/dist/core/runner/prepare-turn-wiring.js +3 -2
  91. package/dist/core/runner/prepare-wiring-manifest.d.ts +5 -5
  92. package/dist/core/runner/prepare-wiring-manifest.js +5 -2
  93. package/dist/core/runner/resume-apply.js +3 -3
  94. package/dist/core/runner/resume-checkpoint-screen.js +7 -0
  95. package/dist/core/runner/run-harness-handlers.js +4 -1
  96. package/dist/core/runner/run-identity-wiring.js +6 -2
  97. package/dist/core/runner/run-leg.d.ts +2 -0
  98. package/dist/core/runner/run-leg.js +45 -45
  99. package/dist/core/runner/run-notification-lane.js +55 -27
  100. package/dist/core/runner/run-settle-and-teardown.js +1 -0
  101. package/dist/core/runner/run-terminal-adoption.js +16 -13
  102. package/dist/core/runner/run-turn-boundary.js +15 -5
  103. package/dist/core/runner/runtask.d.ts +6 -5
  104. package/dist/core/runner/runtask.js +26 -14
  105. package/dist/core/runner/skill-base-dir.d.ts +54 -0
  106. package/dist/core/runner/skill-base-dir.js +42 -0
  107. package/dist/core/runner/synthetic-tools.d.ts +83 -48
  108. package/dist/core/runner/synthetic-tools.js +69 -32
  109. package/dist/core/runner/tool-defer-gate.d.ts +22 -9
  110. package/dist/core/runner/tool-defer-gate.js +15 -5
  111. package/dist/core/runner/tool-disclosure.d.ts +5 -0
  112. package/dist/core/runner/tool-disclosure.js +2 -0
  113. package/dist/core/runner/tool-progress-lane.d.ts +42 -0
  114. package/dist/core/runner/tool-progress-lane.js +61 -0
  115. package/dist/core/runner/turn-attachments.d.ts +43 -12
  116. package/dist/core/runner/turn-attachments.js +58 -14
  117. package/dist/core/runner-deps.d.ts +48 -7
  118. package/dist/core/sensitive-path-policy.d.ts +58 -17
  119. package/dist/core/sensitive-path-policy.js +33 -5
  120. package/dist/core/skill-listing-budget.d.ts +112 -0
  121. package/dist/core/skill-listing-budget.js +58 -0
  122. package/dist/core/swappable-deps.d.ts +9 -7
  123. package/dist/core/swappable-deps.js +7 -3
  124. package/dist/core/task-event.d.ts +96 -29
  125. package/dist/core/task-notification.d.ts +142 -16
  126. package/dist/core/task-notification.js +106 -0
  127. package/dist/core/task-result.d.ts +9 -1
  128. package/dist/core/task-spec.d.ts +46 -3
  129. package/dist/core/tighten-task-spec.js +7 -5
  130. package/dist/core/tool-model-gate.d.ts +1 -1
  131. package/dist/core/tool-policy.d.ts +19 -4
  132. package/dist/core/tool-policy.js +6 -7
  133. package/dist/core/tool-search-setting.d.ts +78 -0
  134. package/dist/core/tool-search-setting.js +90 -0
  135. package/dist/core/tool-spec.d.ts +45 -4
  136. package/dist/core/types.d.ts +2 -2
  137. package/dist/core/types.js +1 -1
  138. package/dist/core/wiring-manifest.d.ts +46 -0
  139. package/dist/core/wiring-manifest.js +9 -1
  140. package/dist/core/write-protect.d.ts +8 -3
  141. package/dist/core/write-protect.js +8 -5
  142. package/dist/engine/execution-env/node-execution-env.js +10 -4
  143. package/dist/engine/harness/agent-harness.d.ts +42 -0
  144. package/dist/engine/harness/agent-harness.js +61 -29
  145. package/dist/engine/loop/agent-loop.d.ts +68 -3
  146. package/dist/engine/loop/agent-loop.js +109 -16
  147. package/dist/index.d.ts +13 -8
  148. package/dist/index.js +11 -7
  149. package/dist/internal/harness.d.ts +1 -1
  150. package/dist/orchestration/run-workflow-tool.d.ts +3 -0
  151. package/dist/orchestration/run-workflow-tool.js +6 -1
  152. package/dist/orchestration/workflow-governance.d.ts +7 -1
  153. package/dist/orchestration/workflow-governance.js +9 -5
  154. package/dist/orchestration/workflow-primitives.d.ts +3 -0
  155. package/dist/orchestration/workflow-primitives.js +6 -1
  156. package/dist/orchestration/workflow-types.d.ts +48 -13
  157. package/dist/orchestration/workflow-types.js +1 -1
  158. package/dist/orchestration/workflow.js +45 -17
  159. package/dist/prompt-assembly/epoch.js +2 -0
  160. package/dist/prompt-assembly/packs/sema-default.js +2 -2
  161. package/dist/prompt-assembly/section-usage.d.ts +26 -0
  162. package/dist/prompt-assembly/section-usage.js +10 -0
  163. package/dist/prompt-assembly/types.d.ts +8 -6
  164. package/dist/prompts/default.d.ts +13 -0
  165. package/dist/prompts/default.js +16 -8
  166. package/dist/tools/artifact/artifact-text.d.ts +10 -1
  167. package/dist/tools/artifact/artifact-text.js +6 -3
  168. package/dist/tools/artifact/artifact-tool.d.ts +12 -2
  169. package/dist/tools/artifact/artifact-tool.js +203 -70
  170. package/dist/tools/artifact/conformance.d.ts +56 -0
  171. package/dist/tools/artifact/conformance.js +349 -0
  172. package/dist/tools/artifact/local-stub.js +1 -1
  173. package/dist/tools/artifact/reject-breaker.d.ts +28 -0
  174. package/dist/tools/artifact/reject-breaker.js +42 -0
  175. package/dist/tools/fs/bash-lexer.d.ts +132 -0
  176. package/dist/tools/fs/bash-lexer.js +563 -0
  177. package/dist/tools/fs/bash-program-position.d.ts +142 -0
  178. package/dist/tools/fs/bash-program-position.js +125 -0
  179. package/dist/tools/fs/bash-readonly-classifier.d.ts +81 -16
  180. package/dist/tools/fs/bash-readonly-classifier.js +180 -558
  181. package/dist/tools/fs/containment-face.d.ts +89 -0
  182. package/dist/tools/fs/containment-face.js +81 -0
  183. package/dist/tools/fs/fs-bash.d.ts +46 -1
  184. package/dist/tools/fs/fs-bash.js +165 -25
  185. package/dist/tools/fs/fs-read.d.ts +1 -1
  186. package/dist/tools/fs/fs-search-tools.d.ts +3 -3
  187. package/dist/tools/fs/fs-write.d.ts +4 -3
  188. package/dist/tools/fs/fs-write.js +9 -9
  189. package/dist/tools/fs/index.d.ts +24 -5
  190. package/dist/tools/fs/index.js +18 -6
  191. package/dist/tools/fs/read-deny.d.ts +4 -3
  192. package/dist/tools/fs/repo-map.d.ts +2 -2
  193. package/dist/tools/fs/safety.d.ts +18 -3
  194. package/dist/tools/fs/safety.js +11 -4
  195. package/package.json +1 -1
  196. package/test/export-surface.snapshot.json +99 -13
  197. package/wire-changes/core@7.17.7.json +49 -0
  198. package/wire-changes/core@7.18.0.json +1273 -0
  199. package/wire-changes/core@7.19.0.json +457 -0
  200. package/dist/tools/fs/read-face.d.ts +0 -68
  201. package/dist/tools/fs/read-face.js +0 -47
@@ -1,5 +1,19 @@
1
- /** Hard cap on one classification round-trip when `AutoModeDeciderOptions.timeoutMs` is omitted. */
2
- export declare const AUTO_MODE_DEFAULT_TIMEOUT_MS = 15000;
1
+ /**
2
+ * Hard cap on one classification RUNG (both attempts) when `AutoModeDeciderOptions.timeoutMs` is omitted — CC
3
+ * 2.1.259's per-attempt classifier base (`j7e = 60000`; 2.1.250 `oue`, the same number), which upstream
4
+ * stretches to 120 s with prompt size and sema leaves to the deployment knob. The 15 s that stood here was
5
+ * never upstream's: live 2026-09-15 a thinking-by-default gateway answers in 5–165 s (Qwen 3.8 p50 11–24 s,
6
+ * kimi and GLM p50 ~10 s), so 15 s turned most classifications into `unavailable (timed out)`. Worst-case
7
+ * walk = this × rungs (2) = 120 s.
8
+ */
9
+ export declare const AUTO_MODE_DEFAULT_TIMEOUT_MS = 60000;
10
+ /**
11
+ * What an arming RECORDING that carries no `timeoutMs` meant when it was written: the default of its day. Every
12
+ * recipe minted since the deadline moved to 60 s MATERIALISES its bound, so an absent recorded knob dates the
13
+ * recording — the fold reads it as the 15 s it ran under, never as the current default
14
+ * (`auto_mode.arming.absent_timeout_reads_recorded_default`, on the fold).
15
+ */
16
+ export declare const AUTO_MODE_RECORDED_ABSENT_TIMEOUT_MS = 15000;
3
17
  /** Newest transcript entries in the classify window when `AutoModeWindowOptions.maxEntries` is omitted. */
4
18
  export declare const AUTO_MODE_DEFAULT_WINDOW_MAX_ENTRIES = 40;
5
19
  /** Per-entry excerpt cap when `AutoModeWindowOptions.maxCharsPerEntry` is omitted. */
@@ -17,25 +31,39 @@ export declare const AUTO_MODE_DEFAULT_WINDOW_MAX_CHARS = 2000;
17
31
  * parses as a block (the parser tolerates a missing tail), a truncated allow does not exist (it is
18
32
  * seven tokens), and the cap's job is to make a model that ignores the "no preamble" instruction —
19
33
  * or that reasons in-text — cost a bounded, quickly-detected contract failure instead of a slow one.
20
- * Paired with `reasoning:"off"` at the call: the cap hosts the ANSWER, so it applies only where the
21
- * wire can say off (`thinkingOffExpressible`); a model that thinks regardless keeps its own budget.
34
+ * Paired with `reasoning:"off"` at the call: the cap hosts the ANSWER, so it stands alone only where the
35
+ * wire SPELLS off (`thinkingOffSpelled`); every other seat adds a thinking allowance to it.
22
36
  */
23
37
  export declare const AUTO_MODE_CLASSIFIER_MAX_TOKENS = 256;
24
38
  /**
25
- * The output-budget ALLOWANCE for a classifier request that must think: added to the verdict cap when the
26
- * seat asks for `reasoning:"low"` instead of `"off"` — a model whose wire cannot say off (`reasoning:true`
27
- * with no off spelling on an effort-only wire, or the anthropic adaptive family), or an unknown model whose
28
- * capped off-request came back EMPTY at the cap (it reasoned anyway). The seat then pays for the lowest
29
- * reasoning tier plus the verdict, never for an open-ended budget.
39
+ * The output-budget ALLOWANCE for a classifier request whose thinking the wire could not turn OFF: added to
40
+ * the verdict cap when the seat asks for `reasoning:"low"` instead of `"off"` — a model whose wire has no off
41
+ * spelling (`reasoning:true` on an effort-only wire with no declared off, the anthropic adaptive family) and a
42
+ * model that declares NO reasoning (the wire then carries nothing and the request is the gateway's default,
43
+ * which on a default-on gateway is a think). The seat pays for the least the wire can grade plus the verdict,
44
+ * never for an open-ended budget.
30
45
  *
31
- * 2048 is anchored twice: CC 2.1.250 `E4` adds exactly this many tokens to the verdict cap for a model in
32
- * its `rejects_disabled_thinking` family (`BHe`); and it is 2 × `MIN_THINKING_TOKENS` (1024), so on the
33
- * anthropic BUDGET path a HARD cap of 256 + 2048 clears the cap-wins skip (`budgetCapSkipsThinking`) and
34
- * hosts a legal `low` budget (`1024 ≤ budget_tokens < max_tokens`) without the brain having to raise a cap
35
- * it refuses to raise. A model that spends more than this on thinking still answers nothing — that reply
36
- * is the contract failure it always was.
46
+ * 2048 is anchored twice: CC 2.1.259 `MU` adds exactly this many tokens to the verdict cap for a model in
47
+ * its `rejects_disabled_thinking` family (2.1.250 `E4`/`BHe`); and it is 2 × `MIN_THINKING_TOKENS` (1024), so
48
+ * on the anthropic BUDGET path a HARD cap of 256 + 2048 clears the cap-wins skip (`budgetCapSkipsThinking`)
49
+ * and hosts a legal `low` budget (`1024 ≤ budget_tokens < max_tokens`) without the brain having to raise a
50
+ * cap it refuses to raise. Live 2026-09-15: deepseek's default think fits it ~90–100% of the time; the tail
51
+ * is the re-ask seat's ({@link AUTO_MODE_CLASSIFIER_THINK_BUDGET_TOKENS}). What a cap can and cannot promise is
52
+ * the seat's contract (`classifier.budget_is_room`, on `classifierRungSeat`).
37
53
  */
38
54
  export declare const AUTO_MODE_CLASSIFIER_LOW_REASONING_BUDGET_TOKENS = 2048;
55
+ /**
56
+ * The RE-ASK seat's allowance — the room a rung gets ONCE after its first attempt produced no verdict: CC
57
+ * 2.1.259's stage-2 classifier cap (`max_tokens: 8192 + bn`). Live 2026-09-15 the thinking tail that overruns
58
+ * 2048 (deepseek 1–2 of 20, some past 4096; Qwen up to 6k) sits under it. One re-ask, never a loop.
59
+ */
60
+ export declare const AUTO_MODE_CLASSIFIER_THINK_BUDGET_TOKENS = 8192;
61
+ /**
62
+ * How many CONSECUTIVE no-verdict classifications on ONE model mint `classifier.contract_broken` (once per run
63
+ * per model): one is a fluke, two is a pattern, and at three the denial limit already hands the user a card —
64
+ * the operator line lands before that one.
65
+ */
66
+ export declare const AUTO_MODE_CLASSIFIER_CONTRACT_BROKEN_AFTER = 2;
39
67
  /** The sentinel a deployment puts INSIDE a paired rule list to splice the CC default rules back in at
40
68
  * that position (CC `XYt = "$defaults"`). It lives here, beside the other defaults, because the #503
41
69
  * recipe canonicalizer needs its VALUE and must not load the assembly face (and its SHA-locked assets)
@@ -1,8 +1,11 @@
1
- export const AUTO_MODE_DEFAULT_TIMEOUT_MS = 15_000;
1
+ export const AUTO_MODE_DEFAULT_TIMEOUT_MS = 60_000;
2
+ export const AUTO_MODE_RECORDED_ABSENT_TIMEOUT_MS = 15_000;
2
3
  export const AUTO_MODE_DEFAULT_WINDOW_MAX_ENTRIES = 40;
3
4
  export const AUTO_MODE_DEFAULT_WINDOW_MAX_CHARS = 2_000;
4
5
  export const AUTO_MODE_CLASSIFIER_MAX_TOKENS = 256;
5
6
  export const AUTO_MODE_CLASSIFIER_LOW_REASONING_BUDGET_TOKENS = 2048;
7
+ export const AUTO_MODE_CLASSIFIER_THINK_BUDGET_TOKENS = 8192;
8
+ export const AUTO_MODE_CLASSIFIER_CONTRACT_BROKEN_AFTER = 2;
6
9
  export const AUTO_MODE_DEFAULTS_SENTINEL = "$defaults";
7
10
  export const AUTO_MODE_DENIAL_LIMIT_DEFAULTS = Object.freeze({ maxConsecutive: 3, maxTotal: 20 });
8
11
  export const AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS = 120_000;
@@ -10,72 +10,179 @@ export declare const AUTO_MODE_UNAVAILABLE_CAUSES: readonly ["error", "timeout"]
10
10
  export type AutoModeUnavailableCause = (typeof AUTO_MODE_UNAVAILABLE_CAUSES)[number];
11
11
  /** Whether a value is a member of the unavailable-cause set — the screen a row reader applies to a stored word. */
12
12
  export declare function isAutoModeUnavailableCause(v: unknown): v is AutoModeUnavailableCause;
13
- /** The classifier's verdict over one pending `ask`. */
14
- export type AutoModeVerdict = {
13
+ /**
14
+ * HOW a reply failed to carry a verdict — the closed set behind `parse_error.form`. `missing` = the reader found
15
+ * NO answer (empty text, prose, an answer only inside a thinking block); `conflict` = it found TWO distinct
16
+ * `<block>` answers (raw or thinking-stripped). The split exists for the classify leg's re-ask: a missing
17
+ * answer is asked for again (CC 2.1.259 `Vrr` re-asks an unparseable reply), a conflict is not — it carries a
18
+ * `yes`, and a second attempt that answered `no` would erase it. Not on any wire face; the trace frame and the
19
+ * gate record keep the one word `parse_error`.
20
+ */
21
+ export declare const AUTO_MODE_PARSE_FAILURES: readonly ["missing", "conflict"];
22
+ export type AutoModeParseFailure = (typeof AUTO_MODE_PARSE_FAILURES)[number];
23
+ /** Whether a value is a member of the parse-failure set. */
24
+ export declare function isAutoModeParseFailure(v: unknown): v is AutoModeParseFailure;
25
+ /**
26
+ * WHY a classification moved DOWN the candidate ladder — the closed set behind
27
+ * {@link AutoModeClassifierRound}'s `fallback.cause`, i.e. the ways a candidate produces NO RULING
28
+ * ({@link rungDidNotRule}). Two words are the unavailable causes verbatim (the leg threw / rejected; the
29
+ * round-trip cap elapsed); `parse_error` is the candidate that ANSWERED without a verdict. A ruling is not a
30
+ * member: the ladder stops at a verdict either way.
31
+ */
32
+ export declare const AUTO_MODE_FALLBACK_CAUSES: readonly ["error", "timeout", "parse_error"];
33
+ export type AutoModeFallbackCause = (typeof AUTO_MODE_FALLBACK_CAUSES)[number];
34
+ /** Whether a value is a member of the fallback-cause set — the screen a row reader applies to a stored word. */
35
+ export declare function isAutoModeFallbackCause(v: unknown): v is AutoModeFallbackCause;
36
+ /**
37
+ * The deployment's answer to "what happens when the classifier seat does not rule?"
38
+ * (`RunnerDeps.autoMode.classifierFallback`) — the closed set behind the candidate ladder's LENGTH:
39
+ * `main` = [classifier seat, the run's main model]; `none` = [classifier seat].
40
+ */
41
+ export declare const AUTO_MODE_CLASSIFIER_FALLBACKS: readonly ["main", "none"];
42
+ export type AutoModeClassifierFallback = (typeof AUTO_MODE_CLASSIFIER_FALLBACKS)[number];
43
+ /** Whether a value is a member of the classifier-fallback set. */
44
+ export declare function isAutoModeClassifierFallback(v: unknown): v is AutoModeClassifierFallback;
45
+ /** Read the knob: absent ⇒ the default `main`; a member ⇒ itself; ANYTHING ELSE ⇒ a loud refusal carrying
46
+ * `config.auto_mode_classifier_fallback_invalid`. A typo'd knob must not read as the default: `"non"` would
47
+ * keep paying for the rung it meant to turn off. */
48
+ export declare function autoModeClassifierFallbackOf(v: unknown): AutoModeClassifierFallback;
49
+ /** The classifier's verdict over one pending `ask`. Every arm may carry the classification's model
50
+ * attribution ({@link AutoModeClassifierRound}), present iff the decider was wired with a candidate ladder. */
51
+ export type AutoModeVerdict = ({
15
52
  kind: "allow";
16
- }
53
+ } & AutoModeRoundAttributed)
17
54
  /** `category` is the matched BLOCK rule name (207 output contract); `reason` starts with `[Rule Name]`. */
18
- | {
55
+ | ({
19
56
  kind: "block";
20
57
  category: string;
21
58
  reason: string;
22
- }
59
+ } & AutoModeRoundAttributed)
23
60
  /** The classifier could not run: the model leg threw / rejected, or ran past the cap. NOT a decision — the
24
61
  * gate denies and says so ({@link classifierUnavailableDenyMessage}). */
25
- | {
62
+ | ({
26
63
  kind: "unavailable";
27
64
  cause: AutoModeUnavailableCause;
28
- }
65
+ } & AutoModeRoundAttributed)
29
66
  /** The model responded but not in the `<block>…` contract shape. Handled as a BLOCK with the CC
30
- * parse-failure sentence ({@link CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE}), counted by the denial limit. */
31
- | {
67
+ * parse-failure sentence ({@link classifierParseFailureDenyMessage}), counted by the denial limit. `form`
68
+ * says WHICH way the reply failed ({@link AutoModeParseFailure}): the classify leg re-asks a `missing`
69
+ * reply once and never a `conflict`. */
70
+ | ({
32
71
  kind: "parse_error";
33
72
  raw: string;
73
+ form: AutoModeParseFailure;
74
+ } & AutoModeRoundAttributed);
75
+ /** The member every verdict arm shares: WHICH MODEL this classification asked and which one answered. */
76
+ export interface AutoModeRoundAttributed {
77
+ /** Absent when the decider was given no candidate ladder (a hand-built decider, the cross-process rebuild's
78
+ * single fresh leg): it ran on whatever model the leg is bound to and can vouch for no name. Never faked. */
79
+ readonly classifier?: AutoModeClassifierRound;
80
+ }
81
+ /**
82
+ * WHICH MODEL answered one classification — the record a walk of the CANDIDATE LADDER
83
+ * ({@link AutoModeDeciderOptions.candidates}) hands its consumers: `modelRequested` = the ladder's FIRST rung
84
+ * (the seat the classification was for); `modelUsed` = the rung whose answer the gate acted on, and where NO
85
+ * candidate ruled, the last rung ATTEMPTED (stated, not implied by absence); `fallback` = present exactly
86
+ * when the ladder MOVED to reach `modelUsed` — which rung it left, which it arrived at, and why
87
+ * ({@link AutoModeFallbackCause}); absent = the first rung answered.
88
+ */
89
+ export interface AutoModeClassifierRound {
90
+ readonly modelRequested: string;
91
+ readonly modelUsed: string;
92
+ readonly fallback?: {
93
+ readonly from: string;
94
+ readonly to: string;
95
+ readonly cause: AutoModeFallbackCause;
96
+ };
97
+ }
98
+ /**
99
+ * The classify hook's word for "this classification was NEVER PUT TO A MODEL" — the failure is in assembling
100
+ * the QUESTION (the transcript window every rung shares), not in a rung's answer.
101
+ *
102
+ * WHY IT EXISTS. The ladder advances on "the rung produced no ruling", and a hook that rejects looks exactly
103
+ * like that. But a classification whose prompt could not be built fails IDENTICALLY on every rung (the build is one
104
+ * shared promise, by contract — "the same prompt, re-asked" is literal), so the walk recorded a fallback
105
+ * `{from: seat, to: main, cause: "error"}` and a deny sentence naming two models, for a classification in which NO
106
+ * MODEL WAS EVER DISPATCHED: a transcript-store outage read, on every face a person can see, as a broken
107
+ * classifier seat. The verdict is unchanged (fail-closed `unavailable`); what changes is that the record
108
+ * stops attributing it to models that were never asked.
109
+ *
110
+ * Carried as a `code` on the thrown error rather than a class so any classify hook — including one this
111
+ * package never constructed — can raise it without importing a constructor.
112
+ *
113
+ * WHAT IT DOES NOT COVER, stated: a build that OUTRUNS a rung's cap is still recorded as that rung's
114
+ * `timeout`. The cap bounds the whole classify call, assembly included, so at that point nothing distinguishes
115
+ * a slow transcript store from a slow model. Moving the per-classification build outside the rung cap is a
116
+ * seam change, filed for a later version.
117
+ */
118
+ export declare const AUTO_MODE_ROUND_NOT_ASKED_CODE = "auto_mode.round_not_asked";
119
+ /** Mint the marker above around whatever failed, keeping the original as `cause` for the host's own logs.
120
+ * TOTAL by construction: the failure it wraps is an arbitrary value, and an `instanceof` or a `.message` read
121
+ * on a revoked proxy (or a throwing getter) THROWS — which would replace the marker with an ordinary error and
122
+ * hand the walk back the attribution this whole seat exists to remove. So the detail is a guarded read that
123
+ * must already be a string, and the total describer otherwise. */
124
+ export declare function autoModeRoundNotAsked(reason: unknown): Error & {
125
+ code: string;
34
126
  };
127
+ /** Why a rung did not settle the classification, or `undefined` when it RULED and the ladder stops — the ONE
128
+ * predicate behind the advance (there is no `if (fallback)` arm anywhere). */
129
+ export declare function rungDidNotRule(v: AutoModeVerdict): AutoModeFallbackCause | undefined;
35
130
  /**
36
131
  * The model-facing deny text for an `unavailable` verdict — CC 2.1.250 `x1t`, with the parenthetical `EIt`
37
132
  * spells for the causes this engine distinguishes (a wall-clock / connection timeout reads " (timed out)";
38
- * an error of unknown kind reads nothing — CC spells HTTP statuses it has, and this decider does not). The
39
- * subject is the classifier itself rather than a model id: the decider does not know which model answered,
40
- * and the sentence must not name one it cannot vouch for. One writer for every deny site (the gate's own
41
- * station and the inherited-lane arms).
133
+ * an unknown kind reads nothing). The subject is the classifier itself rather than a model id: without a
134
+ * candidate ladder the decider cannot vouch for a name. One writer for every deny site. ROOT CAUSE, when
135
+ * `attribution.fallback` is present: the sentence names BOTH rungs that failed to answer; a ladder that did
136
+ * NOT move keeps the CC text byte for byte.
42
137
  */
43
- export declare function classifierUnavailableDenyMessage(toolName: string, cause: AutoModeUnavailableCause): string;
44
- /** The model-facing deny text for a `parse_error` verdict — CC 2.1.250 `Ure` over the R3t stem: the classifier
45
- * answered, but not with a verdict, and auto mode blocks what it could not evaluate. */
46
- export declare const CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE = "Auto mode could not evaluate this action and is blocking it for safety \u2014 the classifier's reply carried no verdict.";
138
+ export declare function classifierUnavailableDenyMessage(toolName: string, cause: AutoModeUnavailableCause, attribution?: AutoModeClassifierRound): string;
47
139
  /**
48
- * Parse the classifier's output contract — the CC 2.1.250 verdict reader (`wCe`, its thinking strip
49
- * `xCe`, its reason reader `yCe`) ported as is:
140
+ * The model-facing deny text for a `parse_error` verdict — CC 2.1.259 `i7t` stem ("Auto mode could not evaluate
141
+ * this action and is blocking it for safety"; 2.1.250 `Ure`): the classifier answered, but not with a verdict,
142
+ * and auto mode blocks what it could not evaluate. With a candidate ladder wired the tail NAMES the model whose
143
+ * reply carried no verdict (`attribution.modelUsed`) — a declared departure from upstream, whose card names no
144
+ * model: the person reading this card is the one who can change the catalog, and on a single-model deployment
145
+ * the name is the whole diagnosis. Without attribution the sentence is unchanged. The stem is a stable prefix
146
+ * either way; one writer for both deny sites.
147
+ */
148
+ export declare function classifierParseFailureDenyMessage(attribution?: AutoModeClassifierRound): string;
149
+ /**
150
+ * Parse the classifier's output contract — the CC 2.1.259 verdict reader (`MTt`, its thinking strip `QTt`, its
151
+ * reason reader `TTt`; unchanged from 2.1.250 `wCe`/`xCe`/`yCe`), plus ONE arm of sema's own:
50
152
  * blocked: `<block>yes</block><category>Rule Name</category><reason>[Rule Name] …</reason>`
51
153
  * allowed: `<block>no</block>`
52
154
  *
53
155
  * The verdict is the set of `<block>yes|no` hits, NOT a prefix match:
54
156
  * 1. CONFLICT, read on the RAW text (thinking included): `<block>(yes|no)\b` collected over the whole
55
- * response — more than one distinct answer ⇒ no verdict (`parse_error`). A scratch-space "yes"
56
- * contradicting a final "no" is a contradiction, not an allow.
57
- * 2. HITS, read on the text with `<thinking>` blocks removed (closed ones anywhere, then an unclosed
58
- * trailing one — a reasoning model's scratch space is not part of the verdict): `<block>(yes|no)\b`
59
- * with the closing tag OPTIONAL, at ANY position. Zero hits ⇒ `parse_error` (a reply that only
60
- * answered inside its thinking has no verdict); the one distinct answer ⇒ `no` = allow, `yes` = block.
157
+ * response — more than one distinct answer ⇒ no verdict (`parse_error`, form `conflict`). A scratch-space
158
+ * "yes" contradicting a final "no" is a contradiction, not an allow.
159
+ * 2. HITS, read on the text with thinking blocks removed ({@link stripThinking}): `<block>(yes|no)\b` with
160
+ * the closing tag OPTIONAL, at ANY position. Two distinct answers ⇒ `conflict`; the one distinct answer ⇒
161
+ * `no` = allow, `yes` = block.
162
+ * 3. BARE ANSWER (sema, ruled 2026-09-15 — small open models drop the tag; recorded as a divergence; a caller
163
+ * that knows the reply is not a complete answer passes `bareAnswer: false` and this arm is closed): zero
164
+ * hits AND the whole thinking-stripped text is an answer by {@link bareAnswerOf} ⇒ that word is the
165
+ * verdict (a bare `yes` blocks with empty category/reason) — unless a `<block>` answer inside the
166
+ * thinking disagrees with it (`conflict`). Zero hits and anything else — prose, a question with its
167
+ * answer, a reply that only answered inside its thinking — ⇒ `parse_error`, form `missing`.
61
168
  * So a preamble before the tag, prose after `<block>no`, a missing `</block>` and a reply that repeats
62
169
  * its answer all read as the answer they carry; the tag must be spelled `<block>yes` / `<block>no` with
63
170
  * no whitespace inside (the word-boundary form — `<block>yesterday` is not a hit) and case does not matter.
64
171
  *
65
172
  * A stated BLOCK stands with or without its tail: `<category>` (the BLOCK rule NAME the prompt asked
66
- * for, read case-insensitively as free text — the deployment authors those names, so there is no
67
- * fixed vocabulary to screen them against) and `<reason>` (first `<reason>…</reason>` pair on the
68
- * stripped text, the tag spelled as the prompt spells it, trimmed) are carried when present and `""`
69
- * when absent; the consumers render their
70
- * own fallback line from the tool name in that case. The block intent is unambiguous either way, and
71
- * downgrading a stated block to `parse_error` (a block with the generic parse-failure sentence instead
72
- * of the classifier's own reason) would lose the classifier's explicit verdict on the exact calls it flagged.
173
+ * for, read case-insensitively as free text — the deployment authors those names, so there is no fixed
174
+ * vocabulary to screen them against) and `<reason>` (first `<reason>…</reason>` pair on the stripped
175
+ * text, trimmed) are carried when present and `""` when absent; the consumers render their own fallback
176
+ * line from the tool name in that case. Downgrading a stated block to `parse_error` would lose the
177
+ * classifier's explicit verdict on the exact calls it flagged.
73
178
  *
74
- * `parse_error` is fail-closed: the gate handles it as a BLOCK (CC 2.1.250's own outcome for a reply with no
179
+ * `parse_error` is fail-closed: the gate handles it as a BLOCK (CC 2.1.259's own outcome for a reply with no
75
180
  * verdict) that the denial limit counts like any other — never a silent allow, and never a question handed
76
181
  * to a person on the classifier's behalf.
77
182
  */
78
- export declare function parseAutoModeResponse(text: string): AutoModeVerdict;
183
+ export declare function parseAutoModeResponse(text: string, options?: {
184
+ bareAnswer?: boolean;
185
+ }): AutoModeVerdict;
79
186
  /** What the decider hands the deployment's `classify` hook (the assembled prompt is the hook's job
80
187
  * when it owns assembly; when using {@link buildAutoModePrompt} the decider passes its output). */
81
188
  export interface AutoModeClassifyInput {
@@ -84,19 +191,42 @@ export interface AutoModeClassifyInput {
84
191
  /** The human-readable text of the ask being decided (policy/safety message), when present. */
85
192
  askMessage?: string;
86
193
  }
87
- /** The pluggable model leg: given the classify input, return the model's raw text response.
88
- * Deployment-injected (roster cheap tier per); MAY throw / reject — the decider fail-closes. */
89
- export type AutoModeClassifyFn = (input: AutoModeClassifyInput, signal?: AbortSignal) => Promise<string>;
194
+ /** One rung of the ladder, as the leg is told about it. `index` is the ADDRESS (a ladder may carry two rungs
195
+ * whose model id is the same string), while `model` is the NAME the record will carry. */
196
+ export interface AutoModeLadderRung {
197
+ readonly index: number;
198
+ readonly model: string;
199
+ }
200
+ /** The pluggable model leg: given the classify input and the RUNG the ladder is on, return that model's raw
201
+ * text response. Deployment-injected; MAY throw / reject — the decider fail-closes. A rejection carrying
202
+ * {@link AUTO_MODE_ROUND_NOT_ASKED_CODE} says the failure was in assembling the QUESTION rather than in this
203
+ * rung's answer, and stops the walk instead of blaming the next rung. `rung` is `undefined`
204
+ * for a decider wired with no ladder. Both trailing parameters are OPTIONAL, not `| undefined`: a caller
205
+ * INVOKING it with one or two arguments must keep compiling. */
206
+ export type AutoModeClassifyFn = (input: AutoModeClassifyInput, signal?: AbortSignal, rung?: AutoModeLadderRung) => Promise<string>;
90
207
  export interface AutoModeDeciderOptions {
91
208
  classify: AutoModeClassifyFn;
92
- /** Hard cap on one classification round-trip. Default 15_000 ms (sema 裁量 — CC's constant is not
93
- * established; a permission gate must not stall the whole run on a slow classifier). */
209
+ /**
210
+ * The CANDIDATE LADDER this decider walks, in order — the models a classification may be asked on, NOT a
211
+ * second way to say what `classify` says (that hook is the DISPATCH; this is the sequence it dispatches
212
+ * to). Rung 0 is the seat the classification is for; every later rung is consulted only when the one
213
+ * before it produced NO RULING ({@link rungDidNotRule}). The FIRST ruling ends the walk and is the
214
+ * verdict; when no rung rules, the LAST rung's own non-ruling verdict stands.
215
+ *
216
+ * Omitted = a one-rung anonymous ladder: the leg as wired, no attribution on the verdict. An EMPTY array,
217
+ * or a rung that is not a non-empty string, is REFUSED loudly at construction (a deployment that computed
218
+ * its ladder and got nothing has a bug, not a default). COST: {@link timeoutMs} bounds ONE rung, so the
219
+ * worst case is the cap times the rungs actually walked.
220
+ */
221
+ candidates?: readonly string[];
222
+ /** Hard cap on one classification round-trip — one LADDER RUNG, not the whole classification (see
223
+ * {@link candidates}). Default 15_000 ms: a permission gate must not stall the whole run on a slow classifier. */
94
224
  timeoutMs?: number;
95
225
  /**
96
- * Fired once per `decide` call with the verdict the gate is about to act on and the wall time it
97
- * waited (`ms`, integer ≥ 0; a timed-out round reads the deadline). `cause` is present iff the verdict
98
- * is `unavailable`. The engine's own wiring turns this into the `auto_mode.classified` trace frame; a
99
- * hand-built decider need not implement it. A throwing hook never breaks the gate.
226
+ * Fired once per `decide` call with the verdict the gate is about to act on and the wall time it waited
227
+ * (`ms`, integer ≥ 0; a timed-out classification reads the deadline, one that walked two rungs the whole
228
+ * walk). `cause` is present iff the verdict is `unavailable`; `classifier` iff a ladder was wired. A
229
+ * throwing hook never breaks the gate.
100
230
  */
101
231
  onClassified?: (info: AutoModeClassified) => void;
102
232
  }
@@ -110,16 +240,17 @@ export interface AutoModeClassified {
110
240
  cause?: Extract<AutoModeVerdict, {
111
241
  kind: "unavailable";
112
242
  }>["cause"];
243
+ /** The classification's model attribution, present exactly when the decider was wired with a candidate ladder
244
+ * ({@link AutoModeClassifierRound}) — the same object the verdict carries. */
245
+ classifier?: AutoModeClassifierRound;
113
246
  }
114
247
  export interface AutoModeDecider {
115
248
  /** Never rejects. Any internal failure surfaces as `unavailable`/`parse_error` (fail-closed). */
116
249
  decide(input: AutoModeClassifyInput, signal?: AbortSignal): Promise<AutoModeVerdict>;
117
250
  }
118
- /**
119
- * The per-run decider: timeout + fail-closed error mapping, and nothing carried between rounds. One instance
120
- * per run (it binds the run's model leg and assembled prompt); a round that failed says nothing about the
121
- * next one, which asks the model again.
122
- */
251
+ /** The per-run decider: timeout + fail-closed error mapping, nothing carried between rounds. One instance per
252
+ * run (it binds the run's model leg and assembled prompt); a round that failed says nothing about the next,
253
+ * which asks the model again. */
123
254
  export declare function createAutoModeDecider(opts: AutoModeDeciderOptions): AutoModeDecider;
124
255
  /** The deployment's bounds for the denial limit (`RunnerDeps.autoMode.denialLimit`). Every member
125
256
  * optional; an omitted member takes its CC default. A present member with a bad value is REFUSED
@@ -152,24 +283,18 @@ export interface DenialLimitCounts {
152
283
  * The DECISION-layer member of a denial-limit fallback ask (`PermissionResult` ask arm): the counts
153
284
  * that tripped the bound, and NOTHING about a window. A window is a fact of the ask's ROUTE — a live
154
285
  * function approver can count down, a durable park row and a headless deny cannot — and the route is
155
- * chosen downstream of the count, so the decision that carries these counts is by construction not in
156
- * a position to state one. The type says so: there is no window member to write here, and the only
286
+ * chosen downstream of the count. The type says so: there is no window member to write here, and the only
157
287
  * ways to reach a {@link DenialLimitFallback} (the member an {@link
158
288
  * import("./tool-policy.js").AskRequest} carries) are the two route stations,
159
- * {@link AutoModeDenialTracker.armTimedWindow} and {@link unarmedWindow}. A host that builds its own
160
- * gate adapter therefore cannot forward a decision's member straight into an approval request: the
161
- * compiler stops it and names the station it skipped.
289
+ * {@link AutoModeDenialTracker.armTimedWindow} and {@link unarmedWindow}.
162
290
  */
163
291
  export interface UnarmedDenialLimitFallback extends DenialLimitCounts {
164
292
  /** FORBIDDEN on a decision, and stated rather than merely omitted. Leaving the member out would only
165
293
  * stop a FRESH object literal (TypeScript's excess-property check); a policy that writes its window
166
294
  * through a `const`, an `as const`, or an annotated return type would still compile — and would then
167
- * have its number silently replaced at whichever route station the ask reached, turning a bounded
168
- * wait into an unbounded one with no diagnostic. `never` makes the old shape a compile error at the
169
- * policy boundary instead, so the retirement of the self-declared window is a migration a host is
170
- * TOLD about rather than one it discovers when nobody is auto-denied. (A host that casts past the
171
- * type still meets the route stations' runtime belt: they write the route's number, never the
172
- * decision's.) */
295
+ * have its number silently replaced at whichever route station the ask reached. `never` makes the old
296
+ * shape a compile error at the policy boundary instead. (A host that casts past the type still meets
297
+ * the route stations' runtime belt: they write the route's number, never the decision's.) */
173
298
  readonly autoDenyAfterMs?: never;
174
299
  }
175
300
  /** The REQUEST-layer member (`AskRequest`, a durable park row, a checkpoint summary's echo): the same