@sema-agent/core 5.20.0 → 5.21.1

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 (313) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/agents/agent-definition.d.ts +7 -0
  3. package/dist/agents/agent-transcript-tool.d.ts +30 -0
  4. package/dist/agents/builtin-agents.d.ts +60 -0
  5. package/dist/agents/cascade.d.ts +107 -0
  6. package/dist/agents/cumulative-stats.d.ts +56 -0
  7. package/dist/agents/observer.d.ts +162 -0
  8. package/dist/agents/peer-admission.d.ts +95 -0
  9. package/dist/agents/repair-loop.d.ts +226 -0
  10. package/dist/agents/retain-ledger.d.ts +141 -0
  11. package/dist/agents/roster-store.d.ts +105 -0
  12. package/dist/agents/send-message-tool.d.ts +92 -0
  13. package/dist/agents/session-util.d.ts +5 -0
  14. package/dist/agents/subagent-steps.d.ts +66 -0
  15. package/dist/agents/subagent.d.ts +600 -0
  16. package/dist/agents/suspend-guard.d.ts +29 -0
  17. package/dist/agents/teacher.d.ts +75 -0
  18. package/dist/agents/team.d.ts +120 -1
  19. package/dist/agents/tool-filter.d.ts +34 -0
  20. package/dist/agents/verify.d.ts +198 -0
  21. package/dist/bench/metrics.d.ts +455 -0
  22. package/dist/brain/anthropic.d.ts +30 -0
  23. package/dist/brain/circuit-breaker.d.ts +33 -0
  24. package/dist/brain/context-overflow.d.ts +60 -3
  25. package/dist/brain/degrading.d.ts +67 -0
  26. package/dist/brain/errors.d.ts +42 -0
  27. package/dist/brain/failover.d.ts +15 -0
  28. package/dist/brain/media-degrade.d.ts +39 -0
  29. package/dist/brain/model-presets.d.ts +31 -0
  30. package/dist/brain/open-responses.d.ts +19 -0
  31. package/dist/brain/openai.d.ts +46 -0
  32. package/dist/brain/reasoning.d.ts +106 -1
  33. package/dist/brain/repetition.d.ts +83 -0
  34. package/dist/brain/request-params.d.ts +56 -0
  35. package/dist/brain/retry.d.ts +46 -0
  36. package/dist/brain/routing.d.ts +12 -0
  37. package/dist/brain/status-sink.d.ts +30 -1
  38. package/dist/brain/stream-engine.d.ts +147 -0
  39. package/dist/brain/stream-shared.d.ts +34 -0
  40. package/dist/brain/terminal-cause.d.ts +31 -0
  41. package/dist/brain/timeout.d.ts +107 -0
  42. package/dist/brain/tool-call-id.d.ts +20 -0
  43. package/dist/brain/tool-call-repair.d.ts +13 -0
  44. package/dist/config/catalog.d.ts +47 -0
  45. package/dist/config/defaults.d.ts +33 -0
  46. package/dist/core/a2a-task-state.d.ts +53 -0
  47. package/dist/core/a2a.d.ts +51 -0
  48. package/dist/core/arg-summary.d.ts +62 -0
  49. package/dist/core/ask-question.d.ts +272 -2
  50. package/dist/core/auto-compaction.d.ts +467 -0
  51. package/dist/core/auto-compaction.js +20 -6
  52. package/dist/core/auto-mode-prompt-assets.d.ts +8 -0
  53. package/dist/core/auto-mode-prompt.d.ts +27 -0
  54. package/dist/core/auto-mode.d.ts +54 -3
  55. package/dist/core/auto-promote.d.ts +100 -0
  56. package/dist/core/background-agent-store.d.ts +292 -0
  57. package/dist/core/background-shell.d.ts +110 -0
  58. package/dist/core/cache-break-detector.d.ts +34 -0
  59. package/dist/core/canonical-json.d.ts +57 -0
  60. package/dist/core/checkpoint-store.d.ts +1574 -16
  61. package/dist/core/compliance.d.ts +30 -0
  62. package/dist/core/consolidate-scope.d.ts +75 -0
  63. package/dist/core/context-edit.d.ts +99 -0
  64. package/dist/core/context-guard.d.ts +46 -0
  65. package/dist/core/exec-gate.d.ts +44 -0
  66. package/dist/core/exec-output-tail.d.ts +61 -0
  67. package/dist/core/file-snapshot-store.d.ts +104 -0
  68. package/dist/core/fs-write-gate-policy.d.ts +36 -0
  69. package/dist/core/git-worktree-env.d.ts +31 -0
  70. package/dist/core/governance-codes.d.ts +19 -0
  71. package/dist/core/hooks.d.ts +608 -1
  72. package/dist/core/human-input-projection.d.ts +37 -0
  73. package/dist/core/human-input-projection.js +13 -0
  74. package/dist/core/image-downsample.d.ts +74 -0
  75. package/dist/core/locked-config.d.ts +37 -0
  76. package/dist/core/lsp-diagnostics.d.ts +77 -0
  77. package/dist/core/lsp-protocol.d.ts +29 -0
  78. package/dist/core/lsp-session.d.ts +60 -1
  79. package/dist/core/lsp.d.ts +150 -1
  80. package/dist/core/mailbox-store.d.ts +57 -0
  81. package/dist/core/mcp.d.ts +381 -0
  82. package/dist/core/media-byte-cap.d.ts +21 -0
  83. package/dist/core/memory-admission.d.ts +71 -0
  84. package/dist/core/memory-engine/content-origin.d.ts +64 -0
  85. package/dist/core/memory-engine/data-plane.d.ts +43 -0
  86. package/dist/core/memory-engine/dual-root.d.ts +24 -0
  87. package/dist/core/memory-engine/engine.d.ts +230 -0
  88. package/dist/core/memory-engine/engine.js +103 -35
  89. package/dist/core/memory-engine/file-backend.d.ts +155 -0
  90. package/dist/core/memory-engine/frontmatter.d.ts +16 -0
  91. package/dist/core/memory-engine/layout.d.ts +217 -0
  92. package/dist/core/memory-engine/memory-backend-contract.d.ts +12 -0
  93. package/dist/core/memory-engine/migrate.d.ts +9 -0
  94. package/dist/core/memory-engine/scan.d.ts +12 -0
  95. package/dist/core/memory-engine/scope-contract.d.ts +61 -1
  96. package/dist/core/memory-engine/sync-client.d.ts +87 -0
  97. package/dist/core/memory-engine/sync.d.ts +60 -0
  98. package/dist/core/memory-engine/tools.d.ts +41 -0
  99. package/dist/core/memory-engine/types.d.ts +188 -0
  100. package/dist/core/memory-recall.d.ts +141 -0
  101. package/dist/core/memory-vector.d.ts +20 -0
  102. package/dist/core/memory.d.ts +458 -0
  103. package/dist/core/message-utils.d.ts +6 -0
  104. package/dist/core/oracle-isolation.d.ts +69 -0
  105. package/dist/core/permission-rule-consent.d.ts +138 -0
  106. package/dist/core/permission-rule-model.d.ts +122 -0
  107. package/dist/core/permission-rule-store.d.ts +119 -3
  108. package/dist/core/permission-rules.d.ts +87 -1
  109. package/dist/core/present-plan-tool.d.ts +20 -0
  110. package/dist/core/pricing.d.ts +26 -0
  111. package/dist/core/property-harness.d.ts +86 -0
  112. package/dist/core/protocol-naming.d.ts +38 -0
  113. package/dist/core/protocol-table.d.ts +61 -0
  114. package/dist/core/push-queue.d.ts +1 -0
  115. package/dist/core/remote-env.d.ts +383 -1
  116. package/dist/core/retention-policy.d.ts +33 -0
  117. package/dist/core/retention.d.ts +51 -0
  118. package/dist/core/roles.d.ts +59 -0
  119. package/dist/core/runner/active-skill-scope.d.ts +34 -0
  120. package/dist/core/runner/assemble-result.d.ts +134 -0
  121. package/dist/core/runner/compaction-call-options.d.ts +97 -1
  122. package/dist/core/runner/grounding-signal.d.ts +10 -0
  123. package/dist/core/runner/image.d.ts +17 -0
  124. package/dist/core/runner/image.js +29 -15
  125. package/dist/core/runner/memory-consolidation.d.ts +60 -0
  126. package/dist/core/runner/prepare-memory.d.ts +59 -0
  127. package/dist/core/runner/prepare-task.d.ts +1011 -2
  128. package/dist/core/runner/prepare-task.js +12 -11
  129. package/dist/core/runner/prompt-suggestions.d.ts +7 -0
  130. package/dist/core/runner/runtask.d.ts +304 -3
  131. package/dist/core/runner/session-file-state-replay.d.ts +49 -0
  132. package/dist/core/runner/session-rule-policy.d.ts +58 -0
  133. package/dist/core/runner/strict-output-schema.d.ts +18 -3
  134. package/dist/core/runner/synthetic-tools.d.ts +113 -0
  135. package/dist/core/runner/teardown-bounded.d.ts +34 -0
  136. package/dist/core/runner/tool-disclosure.d.ts +227 -0
  137. package/dist/core/runner/tool-output-projection.d.ts +6 -0
  138. package/dist/core/runner/turn-attachments.d.ts +634 -0
  139. package/dist/core/runner/usage-accounting.d.ts +32 -0
  140. package/dist/core/runtime.d.ts +9 -0
  141. package/dist/core/safe-notify.d.ts +64 -0
  142. package/dist/core/safety-axis-vocab.d.ts +23 -0
  143. package/dist/core/safety-merge-corpus.d.ts +37 -0
  144. package/dist/core/scheduler.d.ts +121 -0
  145. package/dist/core/secret-env.d.ts +32 -0
  146. package/dist/core/select-model.d.ts +15 -0
  147. package/dist/core/sensitive-path-policy.d.ts +42 -0
  148. package/dist/core/session-policy-store.d.ts +94 -0
  149. package/dist/core/session-reconcile.d.ts +80 -0
  150. package/dist/core/session-store.d.ts +85 -0
  151. package/dist/core/session.d.ts +153 -0
  152. package/dist/core/shared-memory/contract.d.ts +22 -0
  153. package/dist/core/shared-memory/normalize.d.ts +123 -2
  154. package/dist/core/shared-memory/tools.d.ts +14 -0
  155. package/dist/core/shared-memory/types.d.ts +105 -0
  156. package/dist/core/shutdown-debug.d.ts +6 -0
  157. package/dist/core/side-query.d.ts +38 -0
  158. package/dist/core/side-query.js +6 -1
  159. package/dist/core/skill-tool-specifier.d.ts +72 -0
  160. package/dist/core/skills-directory.d.ts +100 -1
  161. package/dist/core/spec-contract.d.ts +89 -0
  162. package/dist/core/store-contracts/background-agent-store-contract.d.ts +31 -0
  163. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +26 -0
  164. package/dist/core/store-contracts/contract-harness.d.ts +20 -0
  165. package/dist/core/store-contracts/contract-kit-version.d.ts +27 -0
  166. package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +8 -0
  167. package/dist/core/store-contracts/mailbox-store-contract.d.ts +42 -0
  168. package/dist/core/store-contracts/tool-result-store-contract.d.ts +13 -0
  169. package/dist/core/strategy-store.d.ts +37 -0
  170. package/dist/core/stub-env.d.ts +7 -0
  171. package/dist/core/surrogate-safe-slice.d.ts +35 -0
  172. package/dist/core/task-notification.d.ts +202 -0
  173. package/dist/core/task-outcome.d.ts +53 -0
  174. package/dist/core/task-registry-agent.d.ts +337 -1
  175. package/dist/core/task-registry-monitor.d.ts +12 -0
  176. package/dist/core/task-registry-shared.d.ts +540 -0
  177. package/dist/core/task-registry.d.ts +343 -0
  178. package/dist/core/task-registry.js +13 -2
  179. package/dist/core/task-tool-shape.d.ts +44 -0
  180. package/dist/core/tighten-task-spec.d.ts +21 -0
  181. package/dist/core/tool-detach.d.ts +21 -0
  182. package/dist/core/tool-errors.d.ts +131 -0
  183. package/dist/core/tool-errors.js +4 -0
  184. package/dist/core/tool-name-aliases.d.ts +27 -0
  185. package/dist/core/tool-policy.d.ts +555 -0
  186. package/dist/core/tool-result-budget.d.ts +32 -0
  187. package/dist/core/tool-result-store.d.ts +174 -1
  188. package/dist/core/tools.d.ts +45 -0
  189. package/dist/core/trace.d.ts +323 -0
  190. package/dist/core/types.d.ts +3859 -2
  191. package/dist/core/untrusted-egress.d.ts +8 -0
  192. package/dist/core/untrusted-text.d.ts +156 -0
  193. package/dist/core/usage-window-store.d.ts +95 -0
  194. package/dist/core/version.d.ts +1 -0
  195. package/dist/core/warm-resume.d.ts +17 -0
  196. package/dist/core/wiring-manifest.d.ts +169 -0
  197. package/dist/core/with-retry.d.ts +24 -0
  198. package/dist/core/workflow-journal-store.d.ts +160 -0
  199. package/dist/core/workflow-run-store-contract.d.ts +25 -0
  200. package/dist/core/workflow-run-store.d.ts +119 -0
  201. package/dist/engine/compaction/compaction.d.ts +256 -1
  202. package/dist/engine/compaction/utils.d.ts +94 -0
  203. package/dist/engine/execution-env/kill-tree.d.ts +29 -0
  204. package/dist/engine/execution-env/node-execution-env.d.ts +94 -0
  205. package/dist/engine/harness/agent-harness.d.ts +116 -0
  206. package/dist/engine/harness/agent-harness.js +3 -14
  207. package/dist/engine/harness/messages.d.ts +15 -0
  208. package/dist/engine/harness/types.d.ts +464 -2
  209. package/dist/engine/llm/diagnostics.d.ts +4 -0
  210. package/dist/engine/llm/event-stream.d.ts +3 -0
  211. package/dist/engine/llm/index.d.ts +7 -0
  212. package/dist/engine/llm/types.d.ts +500 -3
  213. package/dist/engine/llm/validation.d.ts +3 -0
  214. package/dist/engine/loop/agent-loop.d.ts +87 -2
  215. package/dist/engine/loop/runtime-deps.d.ts +7 -0
  216. package/dist/engine/loop/types.d.ts +424 -0
  217. package/dist/engine/lsp/frame-decoder.d.ts +13 -0
  218. package/dist/engine/lsp/node-lsp-manager.d.ts +107 -0
  219. package/dist/engine/lsp/stdio-lsp-transport.d.ts +7 -0
  220. package/dist/engine/session/import-validate.d.ts +27 -0
  221. package/dist/engine/session/log-digest.d.ts +93 -0
  222. package/dist/engine/session/memory-repo.d.ts +6 -0
  223. package/dist/engine/session/memory-storage.d.ts +2 -0
  224. package/dist/engine/session/session.d.ts +75 -0
  225. package/dist/engine/session/storage-base.d.ts +8 -0
  226. package/dist/fixtures/index.d.ts +36 -0
  227. package/dist/index.d.ts +16 -1
  228. package/dist/index.js +0 -1
  229. package/dist/internal/harness-types.d.ts +6 -0
  230. package/dist/internal/harness.d.ts +11 -0
  231. package/dist/internal/llm.d.ts +6 -0
  232. package/dist/orchestration/builtin-workflows.d.ts +53 -0
  233. package/dist/orchestration/dev-vm-script-runner.d.ts +19 -0
  234. package/dist/orchestration/goal.d.ts +57 -0
  235. package/dist/orchestration/goal.js +3 -0
  236. package/dist/orchestration/run-spec.d.ts +42 -0
  237. package/dist/orchestration/run-workflow-tool.d.ts +169 -0
  238. package/dist/orchestration/workflow-governance.d.ts +61 -0
  239. package/dist/orchestration/workflow-meta.d.ts +28 -0
  240. package/dist/orchestration/workflow-observe.d.ts +60 -0
  241. package/dist/orchestration/workflow-primitives.d.ts +23 -1
  242. package/dist/orchestration/workflow-sandbox-conformance.d.ts +38 -0
  243. package/dist/orchestration/workflow-script-runner.d.ts +88 -0
  244. package/dist/orchestration/workflow-script-store.d.ts +98 -0
  245. package/dist/orchestration/workflow-size-guideline.d.ts +67 -0
  246. package/dist/orchestration/workflow-types.d.ts +169 -2
  247. package/dist/orchestration/workflow.d.ts +358 -0
  248. package/dist/prompt-assembly/artifact-store.d.ts +33 -0
  249. package/dist/prompt-assembly/artifact.d.ts +25 -0
  250. package/dist/prompt-assembly/assemble.d.ts +20 -0
  251. package/dist/prompt-assembly/composer.d.ts +29 -0
  252. package/dist/prompt-assembly/epoch.d.ts +55 -1
  253. package/dist/prompt-assembly/event-registry.d.ts +35 -0
  254. package/dist/prompt-assembly/explain.d.ts +12 -0
  255. package/dist/prompt-assembly/tool-catalog.d.ts +38 -0
  256. package/dist/prompt-assembly/turn-snapshot.d.ts +40 -0
  257. package/dist/prompt-assembly/types.d.ts +115 -0
  258. package/dist/prompts/coordinator.d.ts +27 -0
  259. package/dist/prompts/default.d.ts +539 -0
  260. package/dist/prompts/simple-sections.d.ts +45 -0
  261. package/dist/prompts/supervisor.d.ts +66 -0
  262. package/dist/scenarios/env.d.ts +28 -0
  263. package/dist/scenarios/full-body.d.ts +50 -0
  264. package/dist/scenarios/scenario-registry.d.ts +60 -0
  265. package/dist/scenarios/teacher-quickstart.d.ts +27 -0
  266. package/dist/server/http.d.ts +17 -0
  267. package/dist/stores/cc/lockfile.d.ts +6 -0
  268. package/dist/stores/cc/mailbox-store.d.ts +8 -0
  269. package/dist/stores/cc/roster-adapter.d.ts +4 -0
  270. package/dist/stores/cc/sidecar-transcript.d.ts +66 -0
  271. package/dist/stores/file/background-agent-store.d.ts +24 -0
  272. package/dist/stores/file/checkpoint-store.d.ts +38 -0
  273. package/dist/stores/file/file-snapshot-store.d.ts +25 -0
  274. package/dist/stores/file/fs-atomic.d.ts +155 -0
  275. package/dist/stores/file/index.d.ts +89 -0
  276. package/dist/stores/file/mailbox-store.d.ts +36 -0
  277. package/dist/stores/file/memory-store.d.ts +82 -0
  278. package/dist/stores/file/permission-rule-store.d.ts +79 -0
  279. package/dist/stores/file/session-policy-store.d.ts +28 -0
  280. package/dist/stores/file/session-store.d.ts +40 -0
  281. package/dist/stores/file/shared-ledger.d.ts +83 -0
  282. package/dist/stores/file/tool-result-store.d.ts +11 -0
  283. package/dist/stores/file/usage-window-store.d.ts +18 -0
  284. package/dist/stores/file/workflow-journal-store.d.ts +100 -0
  285. package/dist/stores/file/workflow-run-store.d.ts +11 -0
  286. package/dist/tools/fs/bash-readonly-classifier.d.ts +282 -0
  287. package/dist/tools/fs/encoding.d.ts +60 -0
  288. package/dist/tools/fs/fs-bash.d.ts +133 -0
  289. package/dist/tools/fs/fs-pdf.d.ts +28 -0
  290. package/dist/tools/fs/fs-search-tools.d.ts +5 -0
  291. package/dist/tools/fs/fs-search-tools.js +0 -1
  292. package/dist/tools/fs/fs-shared.d.ts +360 -0
  293. package/dist/tools/fs/fs-write.d.ts +16 -0
  294. package/dist/tools/fs/gh-rate-limit.d.ts +22 -0
  295. package/dist/tools/fs/index.d.ts +79 -0
  296. package/dist/tools/fs/notebook.d.ts +56 -0
  297. package/dist/tools/fs/pdf.d.ts +70 -0
  298. package/dist/tools/fs/pdf.js +8 -2
  299. package/dist/tools/fs/repo-map.d.ts +10 -0
  300. package/dist/tools/fs/safety.d.ts +376 -0
  301. package/dist/tools/fs/search.d.ts +131 -0
  302. package/dist/tools/loop-tick.d.ts +24 -0
  303. package/dist/tools/monitor.d.ts +55 -0
  304. package/dist/tools/scheduler-tools.d.ts +51 -0
  305. package/dist/tools/sql-adapters.d.ts +18 -0
  306. package/dist/tools/sql.d.ts +25 -0
  307. package/dist/tools/task-list.d.ts +77 -0
  308. package/dist/tools/todo.d.ts +8 -0
  309. package/dist/tools/web.d.ts +184 -0
  310. package/dist/tools/worktree.d.ts +81 -0
  311. package/package.json +2 -2
  312. package/dist/tools/gitea-issue.d.ts +0 -13
  313. package/dist/tools/gitea-issue.js +0 -75
@@ -1,32 +1,137 @@
1
1
  import type { ThinkingLevel } from "../internal/harness-types.js";
2
+ /**
3
+ * Unified reasoning-intensity abstraction (design/96 S3).
4
+ *
5
+ * The intensity a caller requests IS a {@link ThinkingLevel} — we reuse the existing 7-tier vendor scale
6
+ * (`off | minimal | low | medium | high | xhigh | max`) rather than forking a parallel "fast/standard/deep"
7
+ * enum, so there is ONE knob, not two that must be kept in sync. This module is the single place that maps a
8
+ * requested intensity to what a given endpoint can ACTUALLY honor, and reports the EFFECTIVE intensity — so a
9
+ * request that can't be honored as asked ("high" on a binary enable-only provider like qwen/zai, or
10
+ * "xhigh"/"max" on an endpoint whose `reasoning_effort` only accepts up to "high") is observable rather than
11
+ * silently swallowed or 422'd (design/96 §E honesty red-line; design/46 anti-drift).
12
+ *
13
+ * The brain (openai.ts / anthropic.ts) consumes this. Surfacing the effective intensity to a task result is a
14
+ * later config-domain slice (design/96 S6); here it is a pure, tested mapping.
15
+ */
2
16
  export type ReasoningIntensity = ThinkingLevel;
17
+ /** Type guard: is `v` one of the 7 {@link ThinkingLevel} tiers? (A legacy/unknown reasoning string is not.) */
3
18
  export declare function isThinkingLevel(v: unknown): v is ThinkingLevel;
19
+ /** Ordinal rank of a level (`off`=0 … `max`=6). */
4
20
  export declare function rankOf(level: ThinkingLevel): number;
21
+ /**
22
+ * The `reasoning_effort` tiers an OpenAI-family endpoint accepts by DEFAULT. Conservative on purpose: a value
23
+ * the endpoint rejects 422s the whole request, so we ship the set stock OpenAI takes
24
+ * (`minimal | low | medium | high`) and clamp anything higher ("xhigh"/"max") down to "high". An endpoint that
25
+ * genuinely accepts a higher tier declares it via `compat.reasoningEffortLevels`.
26
+ */
5
27
  export declare const DEFAULT_EFFORT_LEVELS: readonly ThinkingLevel[];
6
- export type ReasoningFormat = "openai" | "openrouter" | "deepseek" | "together" | "zai" | "qwen" | "qwen-chat-template" | "budget" | "effort";
28
+ /**
29
+ * The per-provider thinking wire format (mirrors `compat.thinkingFormat`). `"budget"` is the synthetic tag for
30
+ * Anthropic's extended-thinking budget path (no `thinkingFormat` — the anthropic brain doesn't read one), kept
31
+ * here so {@link resolveReasoning} can report ONE endpoint discriminant across both brain families.
32
+ */
33
+ export type ReasoningFormat = "openai" | "openrouter" | "deepseek" | "together" | "zai" | "qwen" | "qwen-chat-template" | "budget"
34
+ /** Anthropic `output_config.effort` (CC 2.1.198 / Fable-5 class, design/119): the tier is a named
35
+ * effort string, clamped to `compat.effortLevels` — the anthropic-side twin of the OpenAI
36
+ * `reasoning_effort` path (thinking FORM is `thinkingMode`; effort carries the intensity). */
37
+ | "effort";
38
+ /** How a requested intensity resolved against one endpoint's real capability. */
7
39
  export interface ReasoningResolution {
40
+ /** The level the caller asked for. */
8
41
  requested: ThinkingLevel;
42
+ /** The level actually in effect after mapping to what the endpoint accepts. */
9
43
  effective: ThinkingLevel;
44
+ /**
45
+ * True when the endpoint varies behavior by intensity (effort tiers / token budget). False = binary
46
+ * enable-only (qwen / zai / qwen-chat-template, or an effort endpoint that declares
47
+ * `supportsReasoningEffort:false`): thinking is on or off and the tier is NOT honored — read this alongside
48
+ * {@link effective}, which then echoes the request as intent only.
49
+ */
10
50
  graded: boolean;
51
+ /** True when {@link effective} differs from {@link requested} (the request couldn't be honored exactly). */
11
52
  clamped: boolean;
12
53
  }
54
+ /**
55
+ * A {@link ReasoningResolution} enriched with the endpoint discriminant, for observability (design/96 S6).
56
+ * The brain consumes only the {@link ReasoningResolution} fields to shape the request; `format`/`endpoint`
57
+ * are reported (e.g. a `reasoning.resolved` trace event) so a deployment can see WHY a tier was downgraded
58
+ * (binary provider) or clamped (effort-set cap) rather than the resolution being silently swallowed (§E honesty).
59
+ */
13
60
  export interface ResolvedReasoning extends ReasoningResolution {
61
+ /** The wire format the request will use (the load-bearing reason for `graded`/`clamped`). */
14
62
  format: ReasoningFormat;
63
+ /** A coarse endpoint label for the trace (`model.api` — e.g. `openai-completions`, `anthropic-messages`). */
15
64
  endpoint: string;
16
65
  }
66
+ /**
67
+ * Resolve a requested intensity against a model END-TO-END, dispatching on its wire format the SAME way the
68
+ * brains do — so a trace event and the actual provider request can never drift (design/96 S6). This is the
69
+ * single observability-side resolver: the runner calls it at task start to emit `reasoning.resolved`; the
70
+ * brains keep calling {@link resolveEffort}/{@link resolveBinary}/{@link reasoningBudgetShare} on the hot path.
71
+ *
72
+ * - Anthropic (`api === "anthropic-messages"`) → budget-based: the tier sets a budget share, so it's a real
73
+ * gradient (`graded:true`) and never tier-clamped (`clamped:false`); reported as `format:"budget"`.
74
+ * - Binary enable-only formats (qwen / zai / qwen-chat-template) → `graded:false` (tier not honored).
75
+ * - An effort endpoint with `supportsReasoningEffort:false` → `graded:false` (enable key only, no effort tier).
76
+ * - Otherwise effort-based → clamp DOWN to the endpoint's `reasoningEffortLevels` (default minimal|low|medium|high).
77
+ *
78
+ * `off`/falsy never enables thinking, so it resolves trivially (no clamp, graded:true) — the caller decides
79
+ * whether to emit at all.
80
+ */
17
81
  export declare function resolveReasoning(requested: ThinkingLevel, model: {
18
82
  api?: string;
19
83
  reasoning?: boolean;
20
84
  compat?: unknown;
21
85
  }): ResolvedReasoning;
86
+ /**
87
+ * Resolve a requested intensity for an effort-based endpoint (`reasoning_effort` / `reasoning.effort`). Picks
88
+ * the requested tier when supported; otherwise the highest supported tier ≤ requested (clamp DOWN, never
89
+ * silently up); if none is ≤ requested (the endpoint's set is entirely higher — unusual), the lowest supported
90
+ * tier. Never returns a value outside `allowed`, so the brain can't emit a tier the endpoint would 422.
91
+ */
22
92
  export declare function resolveEffort(requested: ThinkingLevel, allowed?: readonly ThinkingLevel[]): ReasoningResolution;
93
+ /**
94
+ * Resolve a requested intensity for a binary enable-only endpoint (qwen / zai / qwen-chat-template): the
95
+ * provider only takes an on/off switch, so the intensity tier is NOT honored as a gradient. `graded: false`
96
+ * is the load-bearing honesty signal.
97
+ */
23
98
  export declare function resolveBinary(requested: ThinkingLevel): ReasoningResolution;
99
+ /**
100
+ * Extended-thinking budget as a FRACTION of `max_tokens` per intensity tier, for budget-based endpoints
101
+ * (Anthropic). Lets a higher intensity actually buy a larger thinking budget — before this, the budget was a
102
+ * fixed share regardless of the requested tier, so the intensity had no effect on Anthropic (design/96 §D/§E).
103
+ * The brain clamps the resulting budget to Anthropic's `[1024, max_tokens-1]` window; an explicit
104
+ * `thinkingBudgetTokens` / `thinkingBudgetShare` in config still overrides this table.
105
+ */
24
106
  export declare const REASONING_BUDGET_SHARE: Record<ThinkingLevel, number>;
107
+ /** The extended-thinking budget share for a given intensity tier (see {@link REASONING_BUDGET_SHARE}). */
25
108
  export declare function reasoningBudgetShare(level: ThinkingLevel): number;
109
+ /**
110
+ * design/96 §D (S4) — a user-facing NAMED reasoning tier, DISTINCT from the raw 7-tier {@link ThinkingLevel}
111
+ * ({@link ReasoningIntensity}). A profile maps it to engine flags via {@link resolveReasoningProfile}. This is
112
+ * the "ultracode" parity axis: a high tier (`ultra`) buys both a higher thinking level AND a thoroughness/
113
+ * self-verify prompt nudge.
114
+ */
26
115
  export type ReasoningTier = "off" | "fast" | "standard" | "deep" | "ultra";
116
+ /** The engine flags a {@link ReasoningTier} resolves to (design/96 §D table). A profile may override the
117
+ * default; core ships sane defaults. */
27
118
  export interface ReasoningProfileFlags {
119
+ /** The vendor thinking level to run at (clamped per-endpoint downstream by {@link resolveEffort}). */
28
120
  thinking: ThinkingLevel;
121
+ /**
122
+ * Compose `ORCHESTRATION_AWARENESS` — a high-tier thoroughness/self-verify nudge. 🔴 NOT the `run_workflow`
123
+ * tool (that is gated by a hard sandbox, S8 §6.3); this is purely about how the model reasons. Independent
124
+ * of self-orchestration (a task can be both).
125
+ */
29
126
  awarenessGuidance: boolean;
127
+ /** Advisory HINT that goal mode suits this tier. Core NEVER forces intensity→mode (constitution: the
128
+ * mapping is profile data); a profile/caller decides whether to actually run `runGoal`. */
30
129
  goalSuggested: boolean;
31
130
  }
131
+ /**
132
+ * design/96 §D (S4) — map a named {@link ReasoningTier} to its engine {@link ReasoningProfileFlags} (default
133
+ * mapping). G2 (clay): the intensity→capability mapping is PROFILE-layer data — core gives this primitive +
134
+ * a sane default; a profile/scenario layer calls it (and may override the table) to set a task's `thinking` +
135
+ * prompt flags. Core never forces it. Returns a fresh COPY (callers may mutate).
136
+ */
32
137
  export declare function resolveReasoningProfile(tier: ReasoningTier): ReasoningProfileFlags;
@@ -1,15 +1,98 @@
1
+ /**
2
+ * Detect **degenerate repetition** — the most common LLM failure mode: a model that gets stuck
3
+ * emitting the same character or short phrase forever (often with no punctuation), e.g. `啊啊啊啊…`
4
+ * or `the answer is the answer is the answer is…`. Brains poll this over the growing output and, on a
5
+ * hit, **cancel the stream** and mark the turn errored, so the loop doesn't keep paying for garbage and
6
+ * downstream (e.g. a team member) treats it as a failed turn rather than a real statement.
7
+ *
8
+ * Only an *exact* tail repetition trips it (character-for-character). The original header claimed
9
+ * normal code "won't false-positive" because repeated structure differs in content — **falsified in
10
+ * the field** (docs/DEADTARGET-WINNING-AVG-COREWARS-2026-07-10.md §〇-3): legitimate code repeats the
11
+ * SAME line verbatim (redcode boot blocks `mov <bootsrc, {bootdst` ×6-8, SQL fixture rows, ASCII-art
12
+ * banners), landed exactly in the rule-2 window, and the cut stream three-struck whole TB tasks dead.
13
+ * Hence two structural allowances, both bounded so true runaway loops are still caught:
14
+ * - rule 1 exempts short symbol runs (ASCII dividers) — a run of a non-letter/digit char only
15
+ * counts as degenerate past `CHAR_RUN_SYMBOL`;
16
+ * - rule 2 exempts *code-line-shaped* units (full-line repeats carrying operand/structure chars or
17
+ * indentation) unless the loop SATURATES the inspection window AND is `SATURATION_REPS` deep in the
18
+ * output — no legitimate boot block is 16+ identical lines deep with nothing after it.
19
+ *
20
+ * Known residual (HRD-BRN-2): rule 2 itself never fires for a unit longer than ~66 chars, because reaching
21
+ * `MIN_REPS` inside the fixed 400-char window requires `p ≤ WINDOW/MIN_REPS`. That is rule 2's general
22
+ * geometry (it applies to prose units too), not the code-line allowance, and widening it means growing
23
+ * the window — deliberately left alone rather than traded for false cuts on long legitimate lines.
24
+ */
25
+ /**
26
+ * The errorMessage a brain stamps on a turn it cut off for degenerate repetition — the human-readable
27
+ * DISPLAY text, and nothing more. It is a single exported constant so the brains do not each invent their
28
+ * own wording, but it is no longer the cross-layer signal: since RB-482 #12 the detection contract is
29
+ * `AssistantMessage.errorKind === "degenerate"` (read via `isDegenerateCutMessage` in
30
+ * ./terminal-cause.js), which `assembleResult` maps to `errorCode="output.degenerate"` + salvages the
31
+ * turn text (design/39). Reword this freely; do NOT match on it. Wording: the output is salvaged now,
32
+ * not discarded.
33
+ */
1
34
  export declare const DEGENERATE_MESSAGE = "degenerate repetition detected \u2014 the model looped on the same text; output cut off at the repetition";
35
+ /**
36
+ * One detector hit — either the event that CUT a stream (`degenerate`) or a repetition that landed in
37
+ * a detection window but was SPARED by a 2e1c161 structural allowance (code-line shape / divider run).
38
+ * Spared events are the RSI raw material for judging whether the allowance is too wide or too narrow
39
+ * (clay 2026-07-10: the detector must report counts AND the detected segment, not just a boolean).
40
+ */
2
41
  export interface RepetitionEvent {
42
+ /** Which rule's window the repetition landed in: rule 1 (`char-run`) or rule 2 (`unit-loop`). */
3
43
  rule: "char-run" | "unit-loop";
44
+ /** Repeating-unit length in chars (1 for a char run). */
4
45
  period: number;
46
+ /** How many times the unit repeated (the run length for a char run). */
5
47
  reps: number;
48
+ /** Sample of the repeated unit/tail, truncated to ≤{@link SEGMENT_MAX} chars. */
6
49
  segment: string;
7
50
  }
51
+ /** Structured result of one detector pass over a (growing) output tail. */
8
52
  export interface RepetitionInspection {
53
+ /** True ⇒ a degenerate loop tripped — the caller should cut the stream (same verdict as `looksDegenerate`). */
9
54
  degenerate: boolean;
55
+ /** The event that tripped; present iff `degenerate`. */
10
56
  cut?: RepetitionEvent;
57
+ /** Allowance-spared hits (at most one per rule per pass — the smallest period is the fundamental one). */
11
58
  spared: RepetitionEvent[];
12
59
  }
60
+ /**
61
+ * Structured detector pass: same verdict as {@link looksDegenerate}, plus WHAT hit (`cut`) and what
62
+ * the 2e1c161 allowances spared. Spared collection is bounded: at most one `char-run` and one
63
+ * `unit-loop` event per pass (rule 2 keeps the smallest period — the fundamental unit — so a p and
64
+ * its 2p/3p multiples don't report the same loop several times).
65
+ */
13
66
  export declare function inspectDegenerate(text: string): RepetitionInspection;
14
67
  export declare function looksDegenerate(text: string): boolean;
68
+ /**
69
+ * T1-4 (brain stream-layer truncation): drop the degenerate TAIL off the text face that tripped a
70
+ * cut, keeping ONE instance of the repeating unit, so the salvaged prefix lands in the final
71
+ * assistant content / `salvagedOutput` without hundreds of chars of loop garbage (which the loop's
72
+ * bounded degenerate-recovery continue would otherwise re-feed the model as context — the very text
73
+ * it must not repeat).
74
+ *
75
+ * Always-on by design (no opt-out flag). The honest argument (fable review tightened the original
76
+ * "zero information loss" claim):
77
+ * - everything removed is a byte-identical duplicate of the unit that is KEPT, so no UNIQUE text is
78
+ * ever swallowed (a non-repeating tail never matches and is returned unchanged). What CAN be lost
79
+ * is a repetition COUNT: if the legitimate text immediately before the loop happened to end with
80
+ * the same unit repeated (e.g. an intentional "very very" directly abutting a "very"-loop), those
81
+ * legitimate repeats fold into the loop and collapse to the single kept instance. This only ever
82
+ * happens on a stream the detector ALREADY cut as degenerate, and the alternative is worse (the
83
+ * full loop tail re-fed to the model);
84
+ * - most legitimate verbatim repetition (code lines, dividers) never gets here at all — the 2e1c161
85
+ * allowances spare it upstream, and a spared stream is never cut;
86
+ * - the loop may have grown far past the 400-char inspection window before the poll fired; the
87
+ * scan below strips ALL trailing repeats (and one trailing PARTIAL unit from post-cut buffered
88
+ * deltas), not just the reps the window measured.
89
+ *
90
+ * Fail-safe floor: the trim only fires when the tail ends with ≥2 exact repeats of the cut event's
91
+ * unit — a WRONG-face call (e.g. the cut tripped in thinking, this is the text face) is structurally
92
+ * a no-op unless that face coincidentally ends with ≥2 exact unit repeats (in which case those — and
93
+ * any partial-unit suffix stripped with them — fold like any other repeats; same bounded cost as
94
+ * above). Thinking/reasoning faces are deliberately never trimmed by the brains: anthropic thinking
95
+ * blocks are signature-sealed for replay (mutating them invalidates the signature), and neither face
96
+ * reaches `salvagedOutput`.
97
+ */
15
98
  export declare function trimDegenerateTail(text: string, cut: RepetitionEvent): string;
@@ -1,9 +1,65 @@
1
+ /**
2
+ * Request-parameter passthrough (design/40). A deployment can set official provider params it wants but
3
+ * core doesn't model as first-class fields (OpenAI `frequency_penalty`/`presence_penalty`/`top_p`/`seed`/
4
+ * `logit_bias`; Anthropic `top_k`/`top_p`/`stop_sequences`; …) via `Model.extraBody`, and core merges them
5
+ * into the brain's request body. Anchored at the **Model** level (not per-turn) so the serialized body
6
+ * stays byte-stable across turns → the prefix cache holds (design/9/31).
7
+ *
8
+ * Symmetric: each brain owns its structural + tuning keys (`reserved`) and ALWAYS wins — `extraBody` can
9
+ * only supply the long tail, never clobber `messages`/`tools`/`temperature`/etc. Stripping is the safety
10
+ * enforcement (the brains are standalone-usable); `prepareTask` separately warns on a collision (it has
11
+ * `onError`, the brain doesn't — council design/40).
12
+ */
13
+ /** OpenAI request-body keys core owns; `extraBody` cannot override these. */
1
14
  export declare const OPENAI_RESERVED: ReadonlySet<string>;
15
+ /** Anthropic request-body keys core owns; `extraBody` cannot override these. (Note the asymmetry vs
16
+ * OpenAI — e.g. `stop`/`stop_sequences` is NOT reserved here because the Anthropic brain never sets it.) */
2
17
  export declare const ANTHROPIC_RESERVED: ReadonlySet<string>;
18
+ /**
19
+ * Open Responses request-body keys core owns; `extraBody` cannot override these (design/163).
20
+ *
21
+ * The last three are NOT keys the adapter sets — they are keys it must be IMPOSSIBLE to set. The
22
+ * Open Responses lane is stateless by contract (this engine is the transcript authority), and
23
+ * `extraBody` is the only other path to the request body, so `store` / `previous_response_id` /
24
+ * `conversation` are reserved purely to close it. A deployment that sets one gets the design/40
25
+ * collision warning at load and a stripped key on the wire, never a silently server-linked turn.
26
+ */
3
27
  export declare const RESPONSES_RESERVED: ReadonlySet<string>;
28
+ /** Reserved set for a model's API. */
4
29
  export declare function reservedFor(api: string): ReadonlySet<string>;
30
+ /**
31
+ * Merge `extraBody` into a brain's already-built request `body`, dropping any key the brain owns so core
32
+ * always wins. Returns a NEW object (passthrough keys first, then core keys) when `extraBody` is set; the
33
+ * exact `body` reference (no allocation, byte-identical serialization) when it isn't — so an existing
34
+ * deployment with no `extraBody` is unaffected.
35
+ */
5
36
  export declare function applyExtraBody(body: Record<string, unknown>, extraBody: Record<string, unknown> | undefined, reserved: ReadonlySet<string>): Record<string, unknown>;
37
+ /**
38
+ * [1282] per-call auth REPLACES construction-time auth: drop every auth-bearing header
39
+ * (case-insensitive `authorization` / `x-api-key`) from an already-merged header bag. Called by a
40
+ * brain's buildRequest ONLY when a per-call `options.apiKey` is present — the brain then re-emits
41
+ * the credential in its own wire posture (anthropic `x-api-key`, openai `Bearer`), making the
42
+ * per-call key the request's single credential. Case-insensitivity matters twice: a
43
+ * construction-time `Authorization` (capital A) is what boot env tokens ship, and a case-variant
44
+ * duplicate would otherwise ride the wire alongside the hard-locked lowercase form (fetch Headers
45
+ * folds duplicates into one comma-joined value — broken auth both ways).
46
+ */
6
47
  export declare function stripAuthHeaders(headers: Record<string, string>): void;
48
+ /**
49
+ * The output-cap key(s) each lane's wire form uses. A lane's set is exactly the keys THAT lane's
50
+ * endpoint reads — a stray cap key belonging to another wire form is inert there and must not be
51
+ * mistaken for a bound this request carries.
52
+ */
7
53
  export declare const OUTPUT_CAP_KEYS: Readonly<Record<"openai" | "anthropic" | "responses", readonly string[]>>;
54
+ /**
55
+ * The per-request output cap a FINAL (post-`extraBody`) request body actually carries — the SMALLEST
56
+ * of the lane's cap keys that is present and usable, or `undefined` when none is.
57
+ *
58
+ * Read off the merged body rather than off the knob the adapter set, because those are not the same
59
+ * thing: `extraBody` can contribute a cap under a spelling the adapter did not choose, and a
60
+ * consumer that treats the adapter's own number as "the cap on the wire" would be wrong about a
61
+ * request that carries two. Smallest wins so a consumer reasoning about the bound stays conservative.
62
+ */
8
63
  export declare function effectiveOutputCap(body: Record<string, unknown>, keys: readonly string[]): number | undefined;
64
+ /** Names in `extraBody` that collide with a reserved (core-owned) key — for a load-time warning. */
9
65
  export declare function reservedCollisions(extraBody: Record<string, unknown> | undefined, reserved: ReadonlySet<string>): string[];
@@ -1,8 +1,54 @@
1
+ /**
2
+ * Transient-failure retry backoff (RB-420-b, CC 2.1.220 parity).
3
+ *
4
+ * The shape is **increasing exponential + light additive jitter**, not full jitter:
5
+ * `min(base * 2^attempt, 32s)` plus up to 25% of that. Full jitter (`random(0, exp)`) made the Nth
6
+ * wait routinely SHORTER than the first, which destroys the one property a rate-limited provider
7
+ * needs from a client — that each successive attempt backs further off. The 25% additive spread is
8
+ * still enough de-synchronization to keep many clients from re-converging into a thundering herd.
9
+ *
10
+ * Provider wait hints ride at ONE layer above the computed value, both as a FLOOR
11
+ * (`max(hint, computed)`) — retrying before the server said just gets rejected again, but a hint must
12
+ * never SHORTEN a backoff we already escalated past it:
13
+ * - `Retry-After` (delta-seconds or HTTP-date), on any retryable response.
14
+ * - `anthropic-ratelimit-unified-reset` (an absolute epoch-seconds stamp of when the rate-limit window
15
+ * reopens), read only off a 429 — it is a rate-limit signal.
16
+ * When both are present the larger wins. Both are clamped so a hostile/buggy value
17
+ * (`Retry-After: 2147483647`, a reset stamp years out) cannot pin the caller for hours.
18
+ */
19
+ /** Parse a `Retry-After` header (delta-seconds or HTTP-date) to ms; undefined if absent/unparseable. */
1
20
  export declare function parseRetryAfter(res: Response | undefined): number | undefined;
21
+ /**
22
+ * Parse `anthropic-ratelimit-unified-reset` — an ABSOLUTE epoch-seconds stamp of when the unified
23
+ * rate-limit window reopens — into ms from now. Undefined when absent, unparseable, or already past
24
+ * (a stale stamp carries no wait, so the caller falls back to its computed backoff).
25
+ */
2
26
  export declare function parseRateLimitReset(res: Response | undefined): number | undefined;
27
+ /**
28
+ * A single provider wait hint after clamping, carrying enough of its own history to disclose a
29
+ * truncation: `rawMs` is only set when the response actually asked for more than {@link
30
+ * MAX_HEADER_WAIT_MS} and the hint was cut down to it.
31
+ */
3
32
  export interface ProviderWaitHint {
33
+ /** The value honored (post-clamp), ms. */
4
34
  readonly ms: number;
35
+ /** The value the response asked for, ms — present only when it exceeded the clamp. */
5
36
  readonly rawMs?: number;
6
37
  }
38
+ /** The larger of the response's two wait hints, each clamped; undefined when the response carries
39
+ * neither (or only stale/unparseable ones). Exported so a caller can disclose a truncation instead
40
+ * of silently honoring less than the response asked for.
41
+ *
42
+ * Ranks by the CLAMPED `ms` first (that is the value actually honored — unchanged from before this
43
+ * hint carried `rawMs`), but a tie there is broken by the UNCLAMPED value: two hints can clamp to the
44
+ * same 60s ceiling while asking for very different waits (`Retry-After: 60` vs a reset a day out), and
45
+ * picking whichever came first would silently return the one with no `rawMs` — reporting the smaller
46
+ * ask as if nothing had been truncated at all, even though the pair's honored wait is identical either
47
+ * way. */
7
48
  export declare function providerWaitHint(res: Response | undefined): ProviderWaitHint | undefined;
49
+ /**
50
+ * Backoff (ms) for retry `attempt` (0-based) of a transient failure: an increasing capped exponential
51
+ * plus ≤25% additive jitter, floored by the response's provider wait hints (see the module note).
52
+ * `rand` is injectable for deterministic tests.
53
+ */
8
54
  export declare function retryBackoffMs(baseDelayMs: number, attempt: number, res?: Response, rand?: () => number): number;
@@ -1,6 +1,18 @@
1
1
  import type { Brain } from "../core/types.js";
2
2
  export interface RoutingBrainOptions {
3
+ /** Which field of the Model selects the route. Default "provider". */
3
4
  by?: "provider" | "api";
5
+ /** Brain used when no route matches. If omitted, an unmatched model yields an error. */
4
6
  fallback?: Brain;
5
7
  }
8
+ /**
9
+ * Route to different brains by a Model field (default `model.provider`). Lets one Runner serve
10
+ * multiple providers/gateways; compose with `createFailoverBrain` for per-route failover.
11
+ *
12
+ * @example
13
+ * createRoutingBrain({
14
+ * "vllm": createOpenAIBrain({ baseUrl: VLLM }),
15
+ * "openai": createOpenAIBrain({ baseUrl: OPENAI, apiKey }),
16
+ * }, { fallback: createOpenAIBrain({ baseUrl: VLLM }) });
17
+ */
6
18
  export declare function createRoutingBrain(routes: Record<string, Brain>, opts?: RoutingBrainOptions): Brain;
@@ -1,6 +1,29 @@
1
1
  import type { BrainStatus } from "../core/types.js";
2
+ /** Run `fn` with a per-task brain-status sink in scope. ALS propagates it through the async brain calls
3
+ * inside `fn` (the harness's prompt → brain.stream → connect/retry loop), so {@link emitBrainStatus}
4
+ * reaches THIS task's sink and nothing else. */
2
5
  export declare function runWithStatusSink<T>(emit: (s: BrainStatus) => void, fn: () => Promise<T>): Promise<T>;
6
+ /**
7
+ * Report a brain-layer liveness status to the active per-task sink, if any. A no-op outside a
8
+ * {@link runWithStatusSink} scope (e.g. compaction's `complete`, or a brain used standalone).
9
+ *
10
+ * HRD-BRN-6: swallow-guarded, like its sibling {@link emitBrainTelemetry} — an ADVISORY frame must never
11
+ * change a brain call's outcome. It could: the emit forwards straight into deployment-supplied code, and
12
+ * the circuit breaker's fast-fail emits the `circuit_open` frame from a void-ed async IIFE BEFORE the
13
+ * error terminal is pushed, so a throwing sink took the whole call down (`result()` pending forever plus
14
+ * an unhandled rejection) instead of costing one status frame. `stream-engine.ts` already wrapped its own
15
+ * call site for this exact reason and states the contract ("an advisory frame must never break a settled
16
+ * call"); the guard belongs HERE so every call site inherits it rather than each remembering.
17
+ */
3
18
  export declare function emitBrainStatus(status: BrainStatus): void;
19
+ /**
20
+ * Silent-fallback telemetry (service [398] C1/C4/C5/C6) — the brain→runner TELEMETRY channel, a
21
+ * SECOND ALS sink parallel to the status one. Statuses are user-facing liveness frames (wire
22
+ * `status` events); telemetry is operator-facing fallback accounting the Runner bridges to trace
23
+ * events (`brain.failover` / `breaker.transition` / `brain.retry` / `vision.placeholder`). Kept
24
+ * separate so widening telemetry never bloats the shell-visible status vocabulary. Same contract:
25
+ * fire-and-forget, no-op outside a {@link runWithBrainTelemetry} scope, MUST NOT throw.
26
+ */
4
27
  export type BrainTelemetry = {
5
28
  kind: "failover";
6
29
  servedIndex: number;
@@ -18,9 +41,15 @@ export type BrainTelemetry = {
18
41
  } | {
19
42
  kind: "vision_placeholder";
20
43
  count: number;
21
- } | {
44
+ }
45
+ /** PDF read: a `document` content block was substituted with a text placeholder because the serving
46
+ * API/model cannot take native document input (openai brain always; anthropic brain when the model
47
+ * declares no vision). Silent quality loss → frame (same [398] C4 discipline as vision_placeholder). */
48
+ | {
22
49
  kind: "document_placeholder";
23
50
  count: number;
24
51
  };
52
+ /** Run `fn` with a per-task brain-telemetry sink in scope (Runner-side; compose with runWithStatusSink). */
25
53
  export declare function runWithBrainTelemetry<T>(emit: (t: BrainTelemetry) => void, fn: () => Promise<T>): Promise<T>;
54
+ /** Report a brain-layer fallback/telemetry event to the active per-task sink, if any. */
26
55
  export declare function emitBrainTelemetry(t: BrainTelemetry): void;
@@ -1,47 +1,194 @@
1
1
  import { type AssistantMessage, type Model, createAssistantMessageEventStream } from "../internal/llm.js";
2
2
  import { type BrainTimeoutConfig } from "./timeout.js";
3
+ /**
4
+ * Shared streaming engine for the OpenAI- and Anthropic-shaped brains (design/32, consolidation).
5
+ *
6
+ * It owns the **bug-prone machinery that was duplicated verbatim** across `openai.ts` and
7
+ * `anthropic.ts` — the connect-timeout + retry loop, the three-tier timer logic (first-token + idle
8
+ * watchdog) with their flag resets, the SSE read loop + line framing, the one-shot cleanup, and the
9
+ * `.catch/.finally` error wrapping. Centralizing the timer logic is the point: the same first-token /
10
+ * idle reset bug was fixed twice (1.38.2 / 1.40.2) precisely because this lived in two copies.
11
+ *
12
+ * Each provider keeps its OWN request-shaping (`buildRequest`) and SSE parsing + finalization
13
+ * (`makeParser`) — those genuinely differ (chat-completions deltas vs typed content-block events,
14
+ * thinking signatures, per-provider usage/finish-reason) and stay verbatim in the adapters, so this
15
+ * refactor is behavior-preserving (safety net: resilience/streaming/brain tests).
16
+ */
3
17
  export interface StreamEngineConfig extends BrainTimeoutConfig {
18
+ /**
19
+ * Retries for transient failures (network / 5xx / 429) BEFORE the body streams, and for the
20
+ * mid-stream tier-C re-send that shares this budget. Absent ⇒ {@link resolveMaxRetries} (the
21
+ * `SEMA_MAX_RETRIES` env, else 10). An explicit value here is authoritative and NOT clamped —
22
+ * deployment sovereignty, same posture as the timeout fields. Sovereignty covers a chosen NUMBER: a
23
+ * non-finite value (CLS-A-8) falls back to the env/default instead of disabling the budget.
24
+ */
4
25
  maxRetries?: number;
26
+ /** First-retry backoff ms; each further attempt doubles it (capped, +≤25% jitter). Default 500. */
5
27
  retryDelayMs?: number;
6
28
  }
29
+ /**
30
+ * Resolve the transient-failure retry budget — explicit config > `SEMA_MAX_RETRIES` env > default 10
31
+ * (the same three-level shape as the shell's timeout caps). A non-numeric, negative, or empty env
32
+ * value is ignored rather than silently meaning "zero retries"; an oversized one is clamped.
33
+ */
7
34
  export declare function resolveMaxRetries(configured: number | undefined): number;
35
+ /**
36
+ * Is `rebuilt` still THE SAME REQUEST as `original`, differing only in the output cap and the values
37
+ * that follow from it (ruled 2026-08-05)?
38
+ *
39
+ * `buildRequest` re-reads the adapter's model, config, options and context, so a re-shaped re-send is
40
+ * only trustworthy to the extent that those did not move underneath it. Rather than deep-copying all
41
+ * of them, the two built requests are compared directly: same destination, same headers, and a body
42
+ * identical outside {@link SSERequest.capDerivedPaths}. That covers a changed model id, prompt, tool
43
+ * set, temperature, reasoning posture, or passthrough parameter with one rule instead of a list of
44
+ * things to remember.
45
+ *
46
+ * Conservative on anything it cannot read: a body that is not a JSON object compares by exact string,
47
+ * so an unparseable pair declines rather than being waved through.
48
+ */
8
49
  export declare function sameRequestModuloCap(original: SSERequest, rebuilt: SSERequest, imposedCap: number): boolean;
50
+ /**
51
+ * CC parity (`Q1b`, ruled 2026-08-05) — read the provider's EXPLICIT retry verdict off the response.
52
+ *
53
+ * The status code is an inference about whether a re-send can help; this header is the provider
54
+ * SAYING so, and it outranks the inference in BOTH directions:
55
+ * - `x-should-retry: true` — retry even a status the predicate calls terminal (the upstream knows
56
+ * the condition is transient, e.g. a fenced-off shard behind a 4xx).
57
+ * - `x-should-retry: false` — do NOT retry even a 5xx/429/408/409. Without this, a provider that
58
+ * has already decided the request is unservable is re-sent the same request up to the whole
59
+ * budget (10 by default), which costs the caller and the upstream alike for a known-refused call.
60
+ *
61
+ * Returns `undefined` for an absent header AND for any value other than the two exact tokens — "no
62
+ * opinion", so the status-code predicate decides and the pre-existing behavior is byte-identical.
63
+ * Exact-match (no case folding / trimming) is deliberate: it mirrors CC's comparison, and `Headers`
64
+ * already normalizes surrounding whitespace, so anything else reaching here is a value we did not
65
+ * define and must not guess at.
66
+ *
67
+ * Tolerates a `doFetch` (BYOM injection point) whose Response-shaped return has no usable `headers`.
68
+ */
9
69
  export declare function shouldRetryHeaderVerdict(res: Response | undefined): boolean | undefined;
10
70
  export interface SSERequest {
11
71
  url: string;
12
72
  headers: Record<string, string>;
13
73
  body: string;
74
+ /**
75
+ * The per-request output cap this request ACTUALLY carries on the wire, when the adapter sets one
76
+ * (the adapters disagree on the body key, so the engine cannot read it off `body`). Absent means
77
+ * "no cap sent" or "this adapter does not report it".
78
+ *
79
+ * The context-overflow recovery needs it because the number the PROVIDER echoes back in its error
80
+ * is not evidence of what was sent: a stale or malformed 400 reporting a larger cap than the
81
+ * request carried would otherwise let the recovery "lower" the cap to a value ABOVE the caller's
82
+ * own explicit bound. It doubles as the check that an adapter honored an imposed cap at all.
83
+ */
14
84
  outputCapTokens?: number;
85
+ /**
86
+ * The body PATHS this adapter may legitimately re-derive when the engine imposes a different output
87
+ * cap — the cap's own key(s), plus anything computed from it. Dotted for nested leaves
88
+ * (`"thinking.budget_tokens"`), deliberately: naming the whole `thinking` object would excuse a
89
+ * change of reasoning MODE as if it followed from the cap, when only the budget does.
90
+ *
91
+ * The engine uses this to check that a re-shaped re-send is still THE SAME REQUEST. `buildRequest`
92
+ * re-reads the adapter's model/config/options/context, so a deployment that changes any of them
93
+ * while a call is in flight could otherwise turn "lower the cap and try again" into a request with
94
+ * a different model id, prompt, tool set, or reasoning posture. Everything outside these paths must
95
+ * come back identical; an adapter that declares nothing therefore permits no body change at all.
96
+ */
15
97
  capDerivedPaths?: readonly string[];
98
+ /**
99
+ * Called by the engine once, if and only if THIS request becomes the one that is sent.
100
+ *
101
+ * `buildRequest` is also called SPECULATIVELY — the context-overflow recovery builds a candidate
102
+ * and may then decline it. Any bookkeeping the adapter keeps for its own later diagnostics (which
103
+ * output cap actually went out, which knob supplied it, whether thinking was requested) therefore
104
+ * belongs here rather than in the build: assigned during a build, a rejected candidate's numbers
105
+ * would outlive it and be reported against the request that really was sent.
106
+ */
16
107
  onCommitted?: () => void;
17
108
  }
109
+ /**
110
+ * Per-attempt request overrides the ENGINE imposes on a re-send (ruled 2026-08-05). Absent — which is
111
+ * every ordinary build — the adapter shapes its request exactly as before, byte for byte.
112
+ *
113
+ * An adapter MUST honor every field it can express. Ignoring one is not silent: the only producer is
114
+ * the context-overflow recovery, whose no-progress guard sees the unchanged cap come back in the next
115
+ * provider error and fails loud with the original failure instead of looping.
116
+ */
18
117
  export interface BuildRequestOverrides {
118
+ /**
119
+ * The per-request output cap to send, outranking every caller/model knob for THIS attempt. Set when
120
+ * the provider reported that `input + max_tokens` exceeds the context limit; whichever body key the
121
+ * adapter uses for the cap (`max_tokens` / `max_completion_tokens` / `max_output_tokens`) must carry
122
+ * this value, and any field derived from the cap must be re-derived from it — the point of routing
123
+ * this through the adapter rather than patching the serialized body.
124
+ */
19
125
  maxOutputTokens?: number;
20
126
  }
127
+ /** Controls that the engine passes to the per-stream parser. */
21
128
  export interface StreamControls {
22
129
  out: ReturnType<typeof createAssistantMessageEventStream>;
130
+ /** Shared mutable partial-snapshot message; the parser mutates `content` and emits `{ ...partial }`. */
23
131
  partial: AssistantMessage;
132
+ /** Call on every CONTENT delta (text/thinking/tool input) — resets the first-token + idle watchdogs. */
24
133
  sawContentToken(): void;
134
+ /** Cancel the underlying stream (e.g. degenerate-repetition cutoff). The read loop then ends. */
25
135
  cancel(): void;
26
136
  }
27
137
  export interface StreamParser {
138
+ /** Handle one raw SSE line (`data: {...}`); parse, emit events, call `ctrl.sawContentToken()` on content. */
28
139
  onLine(line: string): void;
140
+ /** Build + emit the final `done`/`error` message after the stream ends. */
29
141
  finalize(): void;
142
+ /**
143
+ * design/124 §0.5-2: introspection for the mid-stream failure tiering. Read directly off the
144
+ * parser's accumulated state (cheap, no side effects):
145
+ * - `hasSubstantiveText` — non-blank answer text (or a streamed refusal) has been emitted → tier A
146
+ * (partial finalize) territory.
147
+ * - `hasCompletedToolCall` — at least one tool call CLOSED successfully (a `toolcall_end` was
148
+ * emitted, so an in-stream executor may already be running it) → tier A; also the retry-safety
149
+ * assertion (§0.5-4): a re-send is FORBIDDEN once this is true (double execution).
150
+ * - `hasOnlyThinking` — thinking streamed but nothing substantive (no non-blank text, no completed
151
+ * tool call) → tier B (seal + whole-turn retry). A dangling tool-call accumulation alongside the
152
+ * thinking does not veto this (nothing was admitted; the retry's snapshot replacement drops it).
153
+ */
30
154
  snapshot(): {
31
155
  hasSubstantiveText: boolean;
32
156
  hasCompletedToolCall: boolean;
33
157
  hasOnlyThinking: boolean;
34
158
  };
159
+ /**
160
+ * design/124 §0.5-2 tier B: seal the UI stream before a whole-turn retry — emit `thinking_end` for
161
+ * any OPEN thinking block (the block state is parser-private; the engine cannot emit a correct
162
+ * close). The retry attempt's parser may then legally REOPEN a thinking block at the SAME
163
+ * contentIndex — consumers render by partial snapshot (replacement semantics), so index reuse is
164
+ * part of the event contract (see AssistantMessageEvent thinking_start note). Idempotent.
165
+ */
35
166
  sealForRetry(): void;
36
167
  }
168
+ /**
169
+ * Run one streaming request end-to-end and drive the provider `parser`. Returns a fresh event stream;
170
+ * never throws (errors are pushed as `error` events, mirroring the Brain contract).
171
+ */
37
172
  export declare function runStreamingBrain(args: {
38
173
  model: Model;
39
174
  doFetch: typeof fetch;
40
175
  signal?: AbortSignal;
41
176
  config: StreamEngineConfig;
177
+ /** HTTP error message prefix (e.g. "gateway" / "anthropic"). */
42
178
  httpLabel: string;
179
+ /** Build the one request. May throw (→ surfaced as an error event). Called again with
180
+ * {@link BuildRequestOverrides} when the engine re-shapes a re-send (context-overflow recovery). */
43
181
  buildRequest: (overrides?: BuildRequestOverrides) => SSERequest;
182
+ /** Create the per-stream parser once the partial + controls exist. */
44
183
  makeParser: (ctrl: StreamControls) => StreamParser;
184
+ /**
185
+ * 1.296 件A — per-call ADVISORY stall watchdogs (`StreamOptions.stallTimeouts`). Priority chain:
186
+ * brain construction-time config (`BrainTimeoutConfig.connectTimeoutMs`/`firstTokenTimeoutMs`/
187
+ * `idleTimeoutMs`) wins whenever PRESENT — including an explicit 0/negative, which means
188
+ * "deliberately disabled" — and only an ABSENT (undefined) field adopts the advisory value; both
189
+ * absent ⇒ off. `connectMs` bounds the fetch→response-headers wait: the engine's post-headers
190
+ * timers can't see a gateway that never returns headers.
191
+ */
45
192
  stallTimeouts?: {
46
193
  connectMs?: number;
47
194
  firstTokenMs?: number;