@bastani/atomic 0.9.40 → 0.9.41-alpha.2

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 (323) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +1 -1
  3. package/dist/builtin/intercom/CHANGELOG.md +12 -0
  4. package/dist/builtin/intercom/README.md +1 -1
  5. package/dist/builtin/intercom/broker/broker.ts +24 -21
  6. package/dist/builtin/intercom/broker/client.ts +97 -6
  7. package/dist/builtin/intercom/broker/list-reply.ts +53 -0
  8. package/dist/builtin/intercom/index.bundle.mjs +278 -46
  9. package/dist/builtin/intercom/package.json +2 -2
  10. package/dist/builtin/intercom/recoverable-disconnect.ts +27 -1
  11. package/dist/builtin/intercom/types.ts +8 -1
  12. package/dist/builtin/mcp/package.json +1 -1
  13. package/dist/builtin/subagents/CHANGELOG.md +14 -0
  14. package/dist/builtin/subagents/README.md +14 -0
  15. package/dist/builtin/subagents/package.json +3 -3
  16. package/dist/builtin/subagents/src/extension/index.bundle.mjs +99 -19
  17. package/dist/builtin/web-access/package.json +2 -2
  18. package/dist/builtin/workflows/CHANGELOG.md +33 -0
  19. package/dist/builtin/workflows/README.md +2 -0
  20. package/dist/builtin/workflows/builtin/adversarial-verification.js +2 -2
  21. package/dist/builtin/workflows/builtin/{chunk-qjqn389g.js → chunk-2jfst7e4.js} +72 -10
  22. package/dist/builtin/workflows/builtin/{chunk-4bwtzyjq.js → chunk-49kkbdpr.js} +1 -1
  23. package/dist/builtin/workflows/builtin/{chunk-qdd897wm.js → chunk-apagcs4r.js} +1 -1
  24. package/dist/builtin/workflows/builtin/{chunk-454hz1qt.js → chunk-dcxscfnb.js} +1 -1
  25. package/dist/builtin/workflows/builtin/{chunk-bjva9j5k.js → chunk-hx8v4p97.js} +1 -1
  26. package/dist/builtin/workflows/builtin/{chunk-85mx6wcf.js → chunk-k5q3t7je.js} +1 -1
  27. package/dist/builtin/workflows/builtin/{chunk-8kkv04hz.js → chunk-n2gkzkty.js} +1 -1
  28. package/dist/builtin/workflows/builtin/{chunk-y45tkftg.js → chunk-txbc93t6.js} +1 -1
  29. package/dist/builtin/workflows/builtin/{chunk-x0vvjyzg.js → chunk-w4xp1w1f.js} +1 -1
  30. package/dist/builtin/workflows/builtin/{chunk-5eh0brtd.js → chunk-z3pajrfs.js} +1 -1
  31. package/dist/builtin/workflows/builtin/classify-and-act.js +2 -2
  32. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +2 -2
  33. package/dist/builtin/workflows/builtin/generate-and-filter.js +2 -2
  34. package/dist/builtin/workflows/builtin/goal.js +2 -2
  35. package/dist/builtin/workflows/builtin/index.js +10 -10
  36. package/dist/builtin/workflows/builtin/loop-until-done.js +2 -2
  37. package/dist/builtin/workflows/builtin/open-claude-design.js +2 -2
  38. package/dist/builtin/workflows/builtin/ralph.js +2 -2
  39. package/dist/builtin/workflows/builtin/tournament.js +2 -2
  40. package/dist/builtin/workflows/package.json +2 -2
  41. package/dist/builtin/workflows/src/authoring.d.ts +1 -1
  42. package/dist/builtin/workflows/src/durable/journal/internal.d.ts +16 -0
  43. package/dist/builtin/workflows/src/durable/journal/legacy-journal-tables.d.ts +9 -0
  44. package/dist/builtin/workflows/src/durable/journal/sql-run-journal.d.ts +6 -0
  45. package/dist/builtin/workflows/src/extension/index.bundle.mjs +950 -116
  46. package/dist/builtin/workflows/src/index.js +806 -131
  47. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +17 -1
  48. package/dist/cli/credential-print.d.ts.map +1 -1
  49. package/dist/cli/credential-print.js +1 -1
  50. package/dist/cli/credential-print.js.map +1 -1
  51. package/dist/config.d.ts +1 -0
  52. package/dist/config.d.ts.map +1 -1
  53. package/dist/config.js +1 -0
  54. package/dist/config.js.map +1 -1
  55. package/dist/core/agent-session-extension-bindings.d.ts +2 -1
  56. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  57. package/dist/core/agent-session-extension-bindings.js +33 -18
  58. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  59. package/dist/core/agent-session-methods.d.ts +2 -1
  60. package/dist/core/agent-session-methods.d.ts.map +1 -1
  61. package/dist/core/agent-session-methods.js.map +1 -1
  62. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  63. package/dist/core/agent-session-prompt.js +114 -21
  64. package/dist/core/agent-session-prompt.js.map +1 -1
  65. package/dist/core/agent-session-runtime.d.ts +1 -1
  66. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  67. package/dist/core/agent-session-runtime.js +6 -0
  68. package/dist/core/agent-session-runtime.js.map +1 -1
  69. package/dist/core/agent-session-state.d.ts +19 -1
  70. package/dist/core/agent-session-state.d.ts.map +1 -1
  71. package/dist/core/agent-session-state.js +41 -6
  72. package/dist/core/agent-session-state.js.map +1 -1
  73. package/dist/core/auth-storage-backends.d.ts +3 -1
  74. package/dist/core/auth-storage-backends.d.ts.map +1 -1
  75. package/dist/core/auth-storage-backends.js +79 -12
  76. package/dist/core/auth-storage-backends.js.map +1 -1
  77. package/dist/core/client-identity.d.ts +8 -0
  78. package/dist/core/client-identity.d.ts.map +1 -0
  79. package/dist/core/client-identity.js +16 -0
  80. package/dist/core/client-identity.js.map +1 -0
  81. package/dist/core/compaction/planner-outcome.d.ts.map +1 -1
  82. package/dist/core/compaction/planner-outcome.js +2 -1
  83. package/dist/core/compaction/planner-outcome.js.map +1 -1
  84. package/dist/core/execution-model-router.d.ts +18 -0
  85. package/dist/core/execution-model-router.d.ts.map +1 -1
  86. package/dist/core/execution-model-router.js +14 -8
  87. package/dist/core/execution-model-router.js.map +1 -1
  88. package/dist/core/extension-oauth-refresh-rejection.d.ts +12 -0
  89. package/dist/core/extension-oauth-refresh-rejection.d.ts.map +1 -0
  90. package/dist/core/extension-oauth-refresh-rejection.js +70 -0
  91. package/dist/core/extension-oauth-refresh-rejection.js.map +1 -0
  92. package/dist/core/extension-startup-failure.d.ts +30 -0
  93. package/dist/core/extension-startup-failure.d.ts.map +1 -0
  94. package/dist/core/extension-startup-failure.js +62 -0
  95. package/dist/core/extension-startup-failure.js.map +1 -0
  96. package/dist/core/extensions/context-types.d.ts +2 -0
  97. package/dist/core/extensions/context-types.d.ts.map +1 -1
  98. package/dist/core/extensions/context-types.js.map +1 -1
  99. package/dist/core/extensions/provider-types.d.ts +2 -0
  100. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  101. package/dist/core/extensions/provider-types.js.map +1 -1
  102. package/dist/core/extensions/runner-context.d.ts +1 -0
  103. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  104. package/dist/core/extensions/runner-context.js +8 -0
  105. package/dist/core/extensions/runner-context.js.map +1 -1
  106. package/dist/core/extensions/runner.d.ts +1 -0
  107. package/dist/core/extensions/runner.d.ts.map +1 -1
  108. package/dist/core/extensions/runner.js +3 -0
  109. package/dist/core/extensions/runner.js.map +1 -1
  110. package/dist/core/extensions/runtime-types.d.ts +1 -0
  111. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  112. package/dist/core/extensions/runtime-types.js.map +1 -1
  113. package/dist/core/extensions/workflow-run-control-hub.d.ts +1 -0
  114. package/dist/core/extensions/workflow-run-control-hub.d.ts.map +1 -1
  115. package/dist/core/extensions/workflow-run-control-hub.js +3 -0
  116. package/dist/core/extensions/workflow-run-control-hub.js.map +1 -1
  117. package/dist/core/extensions/workflow-run-control.d.ts +8 -0
  118. package/dist/core/extensions/workflow-run-control.d.ts.map +1 -1
  119. package/dist/core/extensions/workflow-run-control.js.map +1 -1
  120. package/dist/core/model-config.d.ts +28 -0
  121. package/dist/core/model-config.d.ts.map +1 -1
  122. package/dist/core/model-fallback-failures.d.ts.map +1 -1
  123. package/dist/core/model-fallback-failures.js +12 -0
  124. package/dist/core/model-fallback-failures.js.map +1 -1
  125. package/dist/core/model-resolver-defaults.js +1 -1
  126. package/dist/core/model-resolver-defaults.js.map +1 -1
  127. package/dist/core/model-runtime-streaming.d.ts.map +1 -1
  128. package/dist/core/model-runtime-streaming.js +9 -3
  129. package/dist/core/model-runtime-streaming.js.map +1 -1
  130. package/dist/core/model-runtime.d.ts +5 -0
  131. package/dist/core/model-runtime.d.ts.map +1 -1
  132. package/dist/core/model-runtime.js +6 -0
  133. package/dist/core/model-runtime.js.map +1 -1
  134. package/dist/core/provider-composer-internal.d.ts +8 -6
  135. package/dist/core/provider-composer-internal.d.ts.map +1 -1
  136. package/dist/core/provider-composer-internal.js +21 -8
  137. package/dist/core/provider-composer-internal.js.map +1 -1
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +12 -4
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/storage/session/sql-session-store.d.ts +35 -0
  142. package/dist/core/storage/session/sql-session-store.d.ts.map +1 -1
  143. package/dist/core/storage/session/sql-session-store.js +158 -42
  144. package/dist/core/storage/session/sql-session-store.js.map +1 -1
  145. package/dist/core/structured-output/deadline.d.ts +40 -0
  146. package/dist/core/structured-output/deadline.d.ts.map +1 -0
  147. package/dist/core/structured-output/deadline.js +110 -0
  148. package/dist/core/structured-output/deadline.js.map +1 -0
  149. package/dist/core/structured-output/index.d.ts.map +1 -1
  150. package/dist/core/structured-output/index.js +103 -47
  151. package/dist/core/structured-output/index.js.map +1 -1
  152. package/dist/core/structured-output/rejection-detail.d.ts +9 -0
  153. package/dist/core/structured-output/rejection-detail.d.ts.map +1 -0
  154. package/dist/core/structured-output/rejection-detail.js +129 -0
  155. package/dist/core/structured-output/rejection-detail.js.map +1 -0
  156. package/dist/core/structured-output/types.d.ts +8 -1
  157. package/dist/core/structured-output/types.d.ts.map +1 -1
  158. package/dist/core/structured-output/types.js.map +1 -1
  159. package/dist/core/tasks/completion.d.ts +7 -1
  160. package/dist/core/tasks/completion.d.ts.map +1 -1
  161. package/dist/core/tasks/completion.js +28 -6
  162. package/dist/core/tasks/completion.js.map +1 -1
  163. package/dist/core/tasks/contracts.d.ts +6 -1
  164. package/dist/core/tasks/contracts.d.ts.map +1 -1
  165. package/dist/core/tasks/contracts.js.map +1 -1
  166. package/dist/core/tasks/pause.d.ts +2 -1
  167. package/dist/core/tasks/pause.d.ts.map +1 -1
  168. package/dist/core/tasks/pause.js +3 -2
  169. package/dist/core/tasks/pause.js.map +1 -1
  170. package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
  171. package/dist/core/tools/bash-pty-native.js +10 -5
  172. package/dist/core/tools/bash-pty-native.js.map +1 -1
  173. package/dist/core/tools/bash.d.ts.map +1 -1
  174. package/dist/core/tools/bash.js +16 -32
  175. package/dist/core/tools/bash.js.map +1 -1
  176. package/dist/core/tools/grep.js +1 -1
  177. package/dist/core/tools/grep.js.map +1 -1
  178. package/dist/core/tools/kill.d.ts.map +1 -1
  179. package/dist/core/tools/kill.js +17 -3
  180. package/dist/core/tools/kill.js.map +1 -1
  181. package/dist/core/tools/shell-task-render.d.ts +55 -0
  182. package/dist/core/tools/shell-task-render.d.ts.map +1 -0
  183. package/dist/core/tools/shell-task-render.js +123 -0
  184. package/dist/core/tools/shell-task-render.js.map +1 -0
  185. package/dist/core/tools/shell-task-status.d.ts +52 -0
  186. package/dist/core/tools/shell-task-status.d.ts.map +1 -0
  187. package/dist/core/tools/shell-task-status.js +184 -0
  188. package/dist/core/tools/shell-task-status.js.map +1 -0
  189. package/dist/core/tools/structured-output.d.ts +5 -0
  190. package/dist/core/tools/structured-output.d.ts.map +1 -1
  191. package/dist/core/tools/structured-output.js +3 -0
  192. package/dist/core/tools/structured-output.js.map +1 -1
  193. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  194. package/dist/extensions/codemode/execute.js +134 -57
  195. package/dist/extensions/codemode/execute.js.map +1 -1
  196. package/dist/extensions/mcp/config.d.ts.map +1 -1
  197. package/dist/extensions/mcp/config.js +3 -2
  198. package/dist/extensions/mcp/config.js.map +1 -1
  199. package/dist/index-extensions.d.ts +1 -0
  200. package/dist/index-extensions.d.ts.map +1 -1
  201. package/dist/index-extensions.js +3 -0
  202. package/dist/index-extensions.js.map +1 -1
  203. package/dist/index.d.ts +3 -1
  204. package/dist/index.d.ts.map +1 -1
  205. package/dist/index.js +3 -1
  206. package/dist/index.js.map +1 -1
  207. package/dist/main.d.ts.map +1 -1
  208. package/dist/main.js +19 -6
  209. package/dist/main.js.map +1 -1
  210. package/dist/modes/interactive/components/task-row.d.ts.map +1 -1
  211. package/dist/modes/interactive/components/task-row.js +11 -1
  212. package/dist/modes/interactive/components/task-row.js.map +1 -1
  213. package/dist/modes/interactive/interactive-auth-routing.js +12 -10
  214. package/dist/modes/interactive/interactive-auth-routing.js.map +1 -1
  215. package/dist/modes/interactive/interactive-extension-custom-ui.js +20 -30
  216. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
  217. package/dist/modes/interactive/interactive-extension-dialogs.js +23 -96
  218. package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  219. package/dist/modes/interactive/interactive-extension-runtime.js +7 -8
  220. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  221. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  222. package/dist/modes/interactive/interactive-input-handling.js +27 -4
  223. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  224. package/dist/modes/interactive/interactive-mode-base.d.ts +20 -10
  225. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  226. package/dist/modes/interactive/interactive-mode-base.js +40 -5
  227. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  228. package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
  229. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  230. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  231. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  232. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -4
  233. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  234. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  235. package/dist/modes/interactive/interactive-mode-types.d.ts +4 -1
  236. package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
  237. package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
  238. package/dist/modes/interactive/interactive-prompt-restore.d.ts +3 -0
  239. package/dist/modes/interactive/interactive-prompt-restore.d.ts.map +1 -1
  240. package/dist/modes/interactive/interactive-prompt-restore.js +9 -1
  241. package/dist/modes/interactive/interactive-prompt-restore.js.map +1 -1
  242. package/dist/modes/interactive/interactive-prompt-turn.js +30 -2
  243. package/dist/modes/interactive/interactive-prompt-turn.js.map +1 -1
  244. package/dist/modes/interactive/interactive-queueing.js +43 -8
  245. package/dist/modes/interactive/interactive-queueing.js.map +1 -1
  246. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  247. package/dist/modes/interactive/interactive-startup.js +12 -3
  248. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  249. package/dist/modes/interactive/theme/color-utils.d.ts +6 -1
  250. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
  251. package/dist/modes/interactive/theme/color-utils.js +39 -17
  252. package/dist/modes/interactive/theme/color-utils.js.map +1 -1
  253. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  254. package/dist/modes/interactive/theme/theme-class.js +2 -2
  255. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  256. package/dist/modes/interactive/theme/theme-tokens.d.ts +6 -0
  257. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -1
  258. package/dist/modes/interactive/theme/theme-tokens.js +7 -3
  259. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -1
  260. package/dist/modes/interactive-engine/isolated-auth.d.ts +3 -0
  261. package/dist/modes/interactive-engine/isolated-auth.d.ts.map +1 -1
  262. package/dist/modes/interactive-engine/isolated-auth.js +13 -1
  263. package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
  264. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  265. package/dist/modes/interactive-engine/isolated-runtime.js +11 -2
  266. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  267. package/dist/modes/interactive-engine/remote-model-catalog.d.ts +8 -0
  268. package/dist/modes/interactive-engine/remote-model-catalog.d.ts.map +1 -1
  269. package/dist/modes/interactive-engine/remote-model-catalog.js +54 -0
  270. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  271. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  272. package/dist/modes/rpc/rpc-command-handler.js +4 -13
  273. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  274. package/dist/modes/rpc/rpc-model-catalog.d.ts +9 -0
  275. package/dist/modes/rpc/rpc-model-catalog.d.ts.map +1 -0
  276. package/dist/modes/rpc/rpc-model-catalog.js +19 -0
  277. package/dist/modes/rpc/rpc-model-catalog.js.map +1 -0
  278. package/dist/modes/rpc/rpc-provider-auth.d.ts.map +1 -1
  279. package/dist/modes/rpc/rpc-provider-auth.js +2 -6
  280. package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
  281. package/dist/modes/rpc/rpc-types.d.ts +6 -0
  282. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  283. package/dist/modes/rpc/rpc-types.js.map +1 -1
  284. package/dist/utils/changelog.d.ts +6 -0
  285. package/dist/utils/changelog.d.ts.map +1 -1
  286. package/dist/utils/changelog.js +11 -0
  287. package/dist/utils/changelog.js.map +1 -1
  288. package/dist/utils/clipboard.d.ts.map +1 -1
  289. package/dist/utils/clipboard.js +4 -0
  290. package/dist/utils/clipboard.js.map +1 -1
  291. package/dist/utils/tools-manager.d.ts.map +1 -1
  292. package/dist/utils/tools-manager.js +3 -2
  293. package/dist/utils/tools-manager.js.map +1 -1
  294. package/docs/background-tasks.md +5 -3
  295. package/docs/codemode.md +2 -2
  296. package/docs/custom-provider/oauth.md +42 -1
  297. package/docs/custom-provider/registration.md +2 -0
  298. package/docs/environment-variables.md +1 -0
  299. package/docs/extensions/api-reference.md +3 -4
  300. package/docs/extensions/authoring.md +1 -1
  301. package/docs/extensions/events.md +1 -1
  302. package/docs/models-configuration.md +9 -0
  303. package/docs/models.md +3 -1
  304. package/docs/providers.md +4 -4
  305. package/docs/rpc/protocol.md +4 -2
  306. package/docs/sdk/reference.md +2 -0
  307. package/docs/sdk/structured-decisions.md +7 -5
  308. package/docs/sdk.md +5 -2
  309. package/docs/settings.md +4 -2
  310. package/docs/subagents/reference.md +1 -1
  311. package/docs/subagents.md +15 -1
  312. package/docs/themes/reference.md +3 -1
  313. package/docs/usage.md +3 -1
  314. package/docs/workflows/api-reference.md +28 -0
  315. package/docs/workflows/authoring.md +1 -1
  316. package/docs/workflows/operations.md +2 -2
  317. package/npm-shrinkwrap.json +67 -54
  318. package/package.json +6 -6
  319. package/schemas/models.schema.json +21 -0
  320. package/dist/core/provider-attribution.d.ts +0 -4
  321. package/dist/core/provider-attribution.d.ts.map +0 -1
  322. package/dist/core/provider-attribution.js +0 -87
  323. package/dist/core/provider-attribution.js.map +0 -1
@@ -0,0 +1,110 @@
1
+ import { SETTINGS_DEFAULTS } from "../settings-defaults.js";
2
+ /** The largest delay `setTimeout` honors; a larger one fires immediately. */
3
+ const MAX_DEADLINE_MS = 2_147_483_647;
4
+ const CANCELLED_MESSAGE = "Structured output cancelled; no decision was accepted.";
5
+ export class StructuredOutputDeadlineError extends Error {
6
+ constructor(timeoutMs, attempts) {
7
+ super(`Structured output decision exceeded its ${timeoutMs}ms deadline; no decision was accepted.${attempts ? ` ${attempts}` : ""}`);
8
+ this.name = "StructuredOutputDeadlineError";
9
+ }
10
+ }
11
+ /** The failure for an aborted decision: the deadline error when the deadline fired, otherwise a plain cancellation. */
12
+ export function abortFailure(signal) {
13
+ return signal.reason instanceof StructuredOutputDeadlineError ? signal.reason : new Error(CANCELLED_MESSAGE);
14
+ }
15
+ export function validateTimeoutOverride(value) {
16
+ if (value === undefined)
17
+ return;
18
+ if (!Number.isSafeInteger(value) || value <= 0) {
19
+ throw new Error("Structured output timeoutMs must be a positive integer.");
20
+ }
21
+ }
22
+ /**
23
+ * The wall-clock limit for one decision: an explicit `timeoutMs`, else the session's `httpIdleTimeoutMs`, else that
24
+ * setting's default. Like the provider clients, an idle timeout of `0` (disabled) becomes the largest timer delay.
25
+ */
26
+ export function resolveDecisionDeadlineMs(timeoutMs, httpIdleTimeoutMs) {
27
+ validateTimeoutOverride(timeoutMs);
28
+ const requested = timeoutMs ?? httpIdleTimeoutMs ?? SETTINGS_DEFAULTS.httpIdleTimeoutMs;
29
+ return requested === 0 ? MAX_DEADLINE_MS : Math.min(requested, MAX_DEADLINE_MS);
30
+ }
31
+ function formatDuration(milliseconds) {
32
+ const ms = Math.round(milliseconds);
33
+ if (ms < 1_000)
34
+ return `${ms}ms`;
35
+ if (ms < 60_000)
36
+ return `${(ms / 1_000).toFixed(1)}s`;
37
+ const totalSeconds = Math.round(ms / 1_000);
38
+ const hours = Math.floor(totalSeconds / 3_600);
39
+ const minutes = Math.floor((totalSeconds % 3_600) / 60);
40
+ const pad = (value) => String(value).padStart(2, "0");
41
+ const clock = hours > 0 ? `${hours}h${pad(minutes)}m` : `${minutes}m`;
42
+ return `${clock}${pad(totalSeconds % 60)}s`;
43
+ }
44
+ /** One model request, from send to response; transport retries and their waits are not part of it. Records only the stop reason and timing, never content. */
45
+ export class DecisionAttempt {
46
+ startedAt = performance.now();
47
+ endedAt;
48
+ stopReason;
49
+ settle(stopReason) {
50
+ this.endedAt ??= performance.now();
51
+ if (stopReason !== undefined)
52
+ this.stopReason = stopReason;
53
+ }
54
+ describe(now) {
55
+ const outcome = this.endedAt === undefined
56
+ ? "still generating"
57
+ : this.stopReason === undefined
58
+ ? "no response"
59
+ : `stopReason=${this.stopReason}`;
60
+ return `${outcome} ${formatDuration((this.endedAt ?? now) - this.startedAt)}`;
61
+ }
62
+ }
63
+ /** How every generation of one decision ended and how long it took, across repairs, retries and candidates. */
64
+ export class DecisionTrace {
65
+ attempts = [];
66
+ get size() {
67
+ return this.attempts.length;
68
+ }
69
+ begin() {
70
+ const attempt = new DecisionAttempt();
71
+ this.attempts.push(attempt);
72
+ return attempt;
73
+ }
74
+ /** Mark every generation still in flight as ended without a response. */
75
+ settleOpen() {
76
+ for (const attempt of this.attempts)
77
+ attempt.settle();
78
+ }
79
+ /** The attempts from `first` onward, numbered from 1, or an empty string when there are none. */
80
+ describe(first = 0) {
81
+ const now = performance.now();
82
+ const shown = this.attempts.slice(first);
83
+ if (shown.length === 0)
84
+ return "";
85
+ return `Attempts: ${shown.map((attempt, index) => `${index + 1}) ${attempt.describe(now)}`).join("; ")}.`;
86
+ }
87
+ }
88
+ /**
89
+ * Run a whole decision under one wall-clock limit. `run` receives a signal that aborts with the caller's reason when
90
+ * the caller aborts and with a {@link StructuredOutputDeadlineError} when the limit passes, so the existing abort
91
+ * plumbing cancels the in-flight generation. The timer is always released.
92
+ */
93
+ export async function withinDecisionDeadline(callerSignal, timeoutMs, run) {
94
+ const controller = new AbortController();
95
+ const trace = new DecisionTrace();
96
+ const forwardCallerAbort = () => controller.abort(callerSignal?.reason);
97
+ if (callerSignal?.aborted)
98
+ forwardCallerAbort();
99
+ else
100
+ callerSignal?.addEventListener("abort", forwardCallerAbort, { once: true });
101
+ const timer = setTimeout(() => controller.abort(new StructuredOutputDeadlineError(timeoutMs, trace.describe())), timeoutMs);
102
+ try {
103
+ return await run({ signal: controller.signal, trace });
104
+ }
105
+ finally {
106
+ clearTimeout(timer);
107
+ callerSignal?.removeEventListener("abort", forwardCallerAbort);
108
+ }
109
+ }
110
+ //# sourceMappingURL=deadline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deadline.js","sourceRoot":"","sources":["../../../src/core/structured-output/deadline.ts"],"names":[],"mappings":"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","sourcesContent":["import { SETTINGS_DEFAULTS } from \"../settings-defaults.ts\";\n\n/** The largest delay `setTimeout` honors; a larger one fires immediately. */\nconst MAX_DEADLINE_MS = 2_147_483_647;\n\nconst CANCELLED_MESSAGE = \"Structured output cancelled; no decision was accepted.\";\n\nexport class StructuredOutputDeadlineError extends Error {\n\tconstructor(timeoutMs: number, attempts: string) {\n\t\tsuper(\n\t\t\t`Structured output decision exceeded its ${timeoutMs}ms deadline; no decision was accepted.${attempts ? ` ${attempts}` : \"\"}`,\n\t\t);\n\t\tthis.name = \"StructuredOutputDeadlineError\";\n\t}\n}\n\n/** The failure for an aborted decision: the deadline error when the deadline fired, otherwise a plain cancellation. */\nexport function abortFailure(signal: AbortSignal): Error {\n\treturn signal.reason instanceof StructuredOutputDeadlineError ? signal.reason : new Error(CANCELLED_MESSAGE);\n}\n\nexport function validateTimeoutOverride(value: number | undefined): void {\n\tif (value === undefined) return;\n\tif (!Number.isSafeInteger(value) || value <= 0) {\n\t\tthrow new Error(\"Structured output timeoutMs must be a positive integer.\");\n\t}\n}\n\n/**\n * The wall-clock limit for one decision: an explicit `timeoutMs`, else the session's `httpIdleTimeoutMs`, else that\n * setting's default. Like the provider clients, an idle timeout of `0` (disabled) becomes the largest timer delay.\n */\nexport function resolveDecisionDeadlineMs(timeoutMs: number | undefined, httpIdleTimeoutMs?: number): number {\n\tvalidateTimeoutOverride(timeoutMs);\n\tconst requested = timeoutMs ?? httpIdleTimeoutMs ?? SETTINGS_DEFAULTS.httpIdleTimeoutMs;\n\treturn requested === 0 ? MAX_DEADLINE_MS : Math.min(requested, MAX_DEADLINE_MS);\n}\n\nfunction formatDuration(milliseconds: number): string {\n\tconst ms = Math.round(milliseconds);\n\tif (ms < 1_000) return `${ms}ms`;\n\tif (ms < 60_000) return `${(ms / 1_000).toFixed(1)}s`;\n\tconst totalSeconds = Math.round(ms / 1_000);\n\tconst hours = Math.floor(totalSeconds / 3_600);\n\tconst minutes = Math.floor((totalSeconds % 3_600) / 60);\n\tconst pad = (value: number) => String(value).padStart(2, \"0\");\n\tconst clock = hours > 0 ? `${hours}h${pad(minutes)}m` : `${minutes}m`;\n\treturn `${clock}${pad(totalSeconds % 60)}s`;\n}\n\n/** One model request, from send to response; transport retries and their waits are not part of it. Records only the stop reason and timing, never content. */\nexport class DecisionAttempt {\n\treadonly startedAt = performance.now();\n\tendedAt: number | undefined;\n\tstopReason: string | undefined;\n\n\tsettle(stopReason?: string): void {\n\t\tthis.endedAt ??= performance.now();\n\t\tif (stopReason !== undefined) this.stopReason = stopReason;\n\t}\n\n\tdescribe(now: number): string {\n\t\tconst outcome =\n\t\t\tthis.endedAt === undefined\n\t\t\t\t? \"still generating\"\n\t\t\t\t: this.stopReason === undefined\n\t\t\t\t\t? \"no response\"\n\t\t\t\t\t: `stopReason=${this.stopReason}`;\n\t\treturn `${outcome} ${formatDuration((this.endedAt ?? now) - this.startedAt)}`;\n\t}\n}\n\n/** How every generation of one decision ended and how long it took, across repairs, retries and candidates. */\nexport class DecisionTrace {\n\tprivate readonly attempts: DecisionAttempt[] = [];\n\n\tget size(): number {\n\t\treturn this.attempts.length;\n\t}\n\n\tbegin(): DecisionAttempt {\n\t\tconst attempt = new DecisionAttempt();\n\t\tthis.attempts.push(attempt);\n\t\treturn attempt;\n\t}\n\n\t/** Mark every generation still in flight as ended without a response. */\n\tsettleOpen(): void {\n\t\tfor (const attempt of this.attempts) attempt.settle();\n\t}\n\n\t/** The attempts from `first` onward, numbered from 1, or an empty string when there are none. */\n\tdescribe(first = 0): string {\n\t\tconst now = performance.now();\n\t\tconst shown = this.attempts.slice(first);\n\t\tif (shown.length === 0) return \"\";\n\t\treturn `Attempts: ${shown.map((attempt, index) => `${index + 1}) ${attempt.describe(now)}`).join(\"; \")}.`;\n\t}\n}\n\nexport interface DecisionRun {\n\treadonly signal: AbortSignal;\n\treadonly trace: DecisionTrace;\n}\n\n/**\n * Run a whole decision under one wall-clock limit. `run` receives a signal that aborts with the caller's reason when\n * the caller aborts and with a {@link StructuredOutputDeadlineError} when the limit passes, so the existing abort\n * plumbing cancels the in-flight generation. The timer is always released.\n */\nexport async function withinDecisionDeadline<T>(\n\tcallerSignal: AbortSignal | undefined,\n\ttimeoutMs: number,\n\trun: (decision: DecisionRun) => Promise<T>,\n): Promise<T> {\n\tconst controller = new AbortController();\n\tconst trace = new DecisionTrace();\n\tconst forwardCallerAbort = () => controller.abort(callerSignal?.reason);\n\tif (callerSignal?.aborted) forwardCallerAbort();\n\telse callerSignal?.addEventListener(\"abort\", forwardCallerAbort, { once: true });\n\tconst timer = setTimeout(\n\t\t() => controller.abort(new StructuredOutputDeadlineError(timeoutMs, trace.describe())),\n\t\ttimeoutMs,\n\t);\n\ttry {\n\t\treturn await run({ signal: controller.signal, trace });\n\t} finally {\n\t\tclearTimeout(timer);\n\t\tcallerSignal?.removeEventListener(\"abort\", forwardCallerAbort);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/structured-output/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAQ/C,OAAO,KAAK,EAGX,qBAAqB,EAErB,uBAAuB,EACvB,sBAAsB,EACtB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,qBAAqB,EACrB,2BAA2B,EAC3B,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,GACtB,MAAM,YAAY,CAAC;AA8OpB,wBAAsB,wBAAwB,CAAC,CAAC,SAAS,OAAO,EAC/D,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GACjC,OAAO,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAyE5C;AA8JD,6GAA6G;AAC7G,wBAAsB,UAAU,CAAC,CAAC,SAAS,OAAO,EACjD,OAAO,EAAE,qBAAqB,CAAC,CAAC,CAAC;AACjC,iGAAiG;AACjG,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,GAC9C,OAAO,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAU5C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/structured-output/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAU/C,OAAO,KAAK,EAGX,qBAAqB,EAErB,uBAAuB,EACvB,sBAAsB,EACtB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,qBAAqB,EACrB,2BAA2B,EAC3B,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,GACtB,MAAM,YAAY,CAAC;AAkRpB,wBAAsB,wBAAwB,CAAC,CAAC,SAAS,OAAO,EAC/D,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GACjC,OAAO,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAM5C;AAkQD,6GAA6G;AAC7G,wBAAsB,UAAU,CAAC,CAAC,SAAS,OAAO,EACjD,OAAO,EAAE,qBAAqB,CAAC,CAAC,CAAC;AACjC,iGAAiG;AACjG,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,GAC9C,OAAO,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAa5C"}
@@ -4,7 +4,9 @@ import { raceWithAbortSignal } from "../../utils/abort.js";
4
4
  import { reportModelRoutingDebug } from "../model-routing-debug.js";
5
5
  import { STRUCTURED_OUTPUT_TOOL_NAME } from "../tools/structured-output.js";
6
6
  import { compileChoiceSchema } from "./choice-schema.js";
7
+ import { abortFailure, resolveDecisionDeadlineMs, withinDecisionDeadline } from "./deadline.js";
7
8
  import { InvalidDecisionOutputError } from "./invalid-output.js";
9
+ import { describeSchemaErrors, schemaMismatchMessage, unparseableArgumentsMessage } from "./rejection-detail.js";
8
10
  import { resolveRouterModel } from "./resolver.js";
9
11
  export { resolveRouterModel } from "./resolver.js";
10
12
  const DEFAULT_DECISION_RETRY = Object.freeze({ enabled: true, maxRetries: 3, baseDelayMs: 2000 });
@@ -45,7 +47,7 @@ function validateState(state) {
45
47
  throw new Error("Structured output requires a nonempty named state object containing the task and relevant context text.");
46
48
  }
47
49
  }
48
- async function inferChat(request, model, signal, assertActive) {
50
+ async function inferChat(request, model, signal, assertActive, trace) {
49
51
  // Anthropic catalog configuration may opt into server-side fallback. A decision must not.
50
52
  const decisionModel = model.api === "anthropic-messages"
51
53
  ? { ...model, compat: { ...model.compat, allowedFallbackModels: [] } }
@@ -58,34 +60,44 @@ async function inferChat(request, model, signal, assertActive) {
58
60
  let response;
59
61
  assertActive();
60
62
  try {
61
- response = await retryAssistantCall(() => request.modelRegistry
62
- .streamSimple(decisionModel, {
63
- systemPrompt: `${STRUCTURED_DECISION_POLICY}\n\n${request.instructions}\n\nCall ${STRUCTURED_OUTPUT_TOOL_NAME} exactly once with the decision. Do not use prose or other tools.`,
64
- messages: [
65
- {
66
- role: "user",
67
- content: JSON.stringify(Object.keys(request.classifier.questions).length
68
- ? { state: request.state, questions: request.classifier.questions }
69
- : { state: request.state }),
70
- timestamp: Date.now(),
71
- },
72
- ],
73
- tools: [
74
- {
75
- name: tool.name,
76
- description: tool.description,
77
- parameters: tool.parameters,
78
- constrainedSampling: { type: "json_schema", strict: "prefer" },
79
- },
80
- ],
81
- }, {
82
- signal,
83
- maxRetries: 0,
84
- transport: "sse",
85
- toolChoice: "auto",
86
- ...(request.maxTokens === undefined ? {} : { maxTokens: request.maxTokens }),
87
- })
88
- .result(), request.retry ?? DEFAULT_DECISION_RETRY, signal);
63
+ response = await retryAssistantCall(() => {
64
+ const attempt = trace.begin();
65
+ return request.modelRegistry
66
+ .streamSimple(decisionModel, {
67
+ systemPrompt: `${STRUCTURED_DECISION_POLICY}\n\n${request.instructions}\n\nCall ${STRUCTURED_OUTPUT_TOOL_NAME} exactly once with the decision. Do not use prose or other tools.`,
68
+ messages: [
69
+ {
70
+ role: "user",
71
+ content: JSON.stringify(Object.keys(request.classifier.questions).length
72
+ ? { state: request.state, questions: request.classifier.questions }
73
+ : { state: request.state }),
74
+ timestamp: Date.now(),
75
+ },
76
+ ],
77
+ tools: [
78
+ {
79
+ name: tool.name,
80
+ description: tool.description,
81
+ parameters: tool.parameters,
82
+ constrainedSampling: { type: "json_schema", strict: "prefer" },
83
+ },
84
+ ],
85
+ }, {
86
+ signal,
87
+ maxRetries: 0,
88
+ transport: "sse",
89
+ toolChoice: "auto",
90
+ ...(request.maxTokens === undefined ? {} : { maxTokens: request.maxTokens }),
91
+ })
92
+ .result()
93
+ .then((message) => {
94
+ attempt.settle(message.stopReason);
95
+ return message;
96
+ }, (error) => {
97
+ attempt.settle();
98
+ throw error;
99
+ });
100
+ }, request.retry ?? DEFAULT_DECISION_RETRY, signal);
89
101
  }
90
102
  catch (error) {
91
103
  signal.throwIfAborted();
@@ -116,6 +128,11 @@ async function inferChat(request, model, signal, assertActive) {
116
128
  error.usage = { inputTokens: response.usage.input, outputTokens: response.usage.output };
117
129
  throw error;
118
130
  }
131
+ if (calls[0].argumentsError) {
132
+ const error = new InvalidDecisionOutputError(unparseableArgumentsMessage(calls[0].argumentsError));
133
+ error.usage = { inputTokens: response.usage.input, outputTokens: response.usage.output };
134
+ throw error;
135
+ }
119
136
  // These are result arguments, never executable tool calls. Strict validation happens below.
120
137
  return {
121
138
  value: calls[0].arguments,
@@ -126,7 +143,7 @@ async function inferChat(request, model, signal, assertActive) {
126
143
  }
127
144
  function assertNotCancelled(signal) {
128
145
  if (signal?.aborted)
129
- throw new Error("Structured output cancelled; no decision was accepted.");
146
+ throw abortFailure(signal);
130
147
  }
131
148
  function resolveCandidate(id, request) {
132
149
  if (typeof id !== "string" || !id.trim() || id.trim() !== id || id === "auto")
@@ -145,6 +162,14 @@ function resolveCandidate(id, request) {
145
162
  return { kind: "classifier", fullId: id, model: classifier };
146
163
  throw new Error(`Structured output model is unavailable or not a chat or classifier model: ${id}`);
147
164
  }
165
+ function resolveCandidateOutcome(id, request) {
166
+ try {
167
+ return { candidate: resolveCandidate(id, request) };
168
+ }
169
+ catch (error) {
170
+ return { id, failure: error instanceof Error ? error : new Error(String(error)) };
171
+ }
172
+ }
148
173
  class ClassifierDecisionError extends Error {
149
174
  /** Status and error type only; provider bodies can echo private state. */
150
175
  detail;
@@ -156,7 +181,7 @@ class ClassifierDecisionError extends Error {
156
181
  }
157
182
  }
158
183
  const CLASSIFIER_ABORTED = "Structured output classifier request was aborted; no fallback was attempted.";
159
- async function inferClassifier(request, selected, signal) {
184
+ async function inferClassifier(request, selected, signal, trace) {
160
185
  const classify = request.modelRegistry.classify;
161
186
  if (!classify)
162
187
  throw new ClassifierDecisionError();
@@ -169,6 +194,7 @@ async function inferClassifier(request, selected, signal) {
169
194
  },
170
195
  ]));
171
196
  let result;
197
+ const attempt = trace.begin();
172
198
  try {
173
199
  result = await classify.call(request.modelRegistry, selected.model, { state: request.state, questions }, {
174
200
  signal,
@@ -184,6 +210,7 @@ async function inferClassifier(request, selected, signal) {
184
210
  signal.throwIfAborted();
185
211
  if (!result || typeof result !== "object")
186
212
  throw new ClassifierDecisionError();
213
+ attempt.settle(result.stopReason);
187
214
  if (result.stopReason === "aborted")
188
215
  throw new TerminalDecisionError(CLASSIFIER_ABORTED);
189
216
  if (result.stopReason !== "stop")
@@ -209,6 +236,11 @@ async function inferClassifier(request, selected, signal) {
209
236
  return { value, model: selected.fullId, responseModel: result.model, usage: { inputTokens: 0, outputTokens: 0 } };
210
237
  }
211
238
  export async function generateStructuredOutput(request) {
239
+ assertNotCancelled(request.signal);
240
+ const timeoutMs = resolveDecisionDeadlineMs(request.timeoutMs);
241
+ return withinDecisionDeadline(request.signal, timeoutMs, ({ signal, trace }) => generateWithinDeadline({ ...request, signal }, trace));
242
+ }
243
+ async function generateWithinDeadline(request, trace) {
212
244
  assertNotCancelled(request.signal);
213
245
  const current = request.currentModel;
214
246
  if (current && (current.id === "auto" || !isModelType(current, "chat")))
@@ -219,6 +251,7 @@ export async function generateStructuredOutput(request) {
219
251
  throw new Error("Structured output requires complete judgment instructions.");
220
252
  const snapshot = {
221
253
  ...request,
254
+ trace,
222
255
  state: jsonSnapshot(request.state),
223
256
  schema: jsonSnapshot(request.schema),
224
257
  instructions: request.instructions,
@@ -230,12 +263,20 @@ export async function generateStructuredOutput(request) {
230
263
  ];
231
264
  if (!ids[0])
232
265
  throw new Error("Structured output requires model or currentModel.");
233
- const selected = [...new Set(ids)].map((id) => resolveCandidate(id, request));
266
+ const resolutions = [...new Set(ids)].map((id) => resolveCandidateOutcome(id, request));
267
+ const resolutionFailures = resolutions.filter((resolution) => "failure" in resolution);
268
+ if (resolutionFailures.length === resolutions.length)
269
+ throw resolutionFailures[0].failure;
234
270
  const choices = compileChoiceSchema(snapshot.schema);
235
271
  const modelAttempts = [];
236
272
  let lastDiagnostic;
237
- for (const candidate of selected) {
273
+ for (const resolution of resolutions) {
238
274
  assertNotCancelled(request.signal);
275
+ if ("failure" in resolution) {
276
+ modelAttempts.push({ model: resolution.id, error: resolution.failure.message });
277
+ continue;
278
+ }
279
+ const candidate = resolution.candidate;
239
280
  if (candidate.kind === "classifier" && !choices) {
240
281
  modelAttempts.push({
241
282
  model: candidate.fullId,
@@ -274,7 +315,10 @@ export async function generateStructuredOutput(request) {
274
315
  : "Structured output inference failed; no fallback was attempted.");
275
316
  }
276
317
  lastDiagnostic = error instanceof OutputRepairExhaustedError ? error : undefined;
277
- modelAttempts.push({ model: candidate.fullId, error: "Structured output inference failed." });
318
+ modelAttempts.push({
319
+ model: candidate.fullId,
320
+ error: error instanceof OutputRepairExhaustedError ? error.message : "Structured output inference failed.",
321
+ });
278
322
  }
279
323
  }
280
324
  if (lastDiagnostic)
@@ -301,7 +345,7 @@ class TerminalDecisionError extends Error {
301
345
  class CandidateProviderError extends Error {
302
346
  }
303
347
  async function inferDecision(request, repairs, validateDecision, fallbackModel) {
304
- request.signal?.throwIfAborted();
348
+ request.signal.throwIfAborted();
305
349
  validateMaxTokensOverride(request.maxTokens);
306
350
  validateState(request.state);
307
351
  if (!request.instructions?.trim())
@@ -340,13 +384,15 @@ async function inferDecision(request, repairs, validateDecision, fallbackModel)
340
384
  }
341
385
  let fallback;
342
386
  const controller = new AbortController();
343
- const abort = () => controller.abort(new Error("Structured output cancelled; no decision was accepted."));
344
- request.signal?.addEventListener("abort", abort, { once: true });
387
+ const abort = () => controller.abort(abortFailure(request.signal));
388
+ request.signal.addEventListener("abort", abort, { once: true });
345
389
  const assertActive = () => controller.signal.throwIfAborted();
346
390
  try {
347
- if (request.signal?.aborted)
391
+ if (request.signal.aborted)
348
392
  abort();
349
393
  const usage = { inputTokens: 0, outputTokens: 0 };
394
+ let rejection;
395
+ let firstAttempt = request.trace.size;
350
396
  for (let attempt = 0;;) {
351
397
  assertActive();
352
398
  const current = {
@@ -354,12 +400,12 @@ async function inferDecision(request, repairs, validateDecision, fallbackModel)
354
400
  model: selected,
355
401
  instructions: attempt === 0
356
402
  ? snapshot.instructions
357
- : `${snapshot.instructions}\n\nThe previous response failed output validation. Return a complete valid decision satisfying the original schema, candidates and constraints. Do not change the task or invent values.`,
403
+ : `${snapshot.instructions}\n\nThe previous response failed output validation${rejection ? `: ${rejection}` : "."} Return a complete valid decision satisfying the original schema, candidates and constraints. Do not change the task or invent values.`,
358
404
  };
359
405
  try {
360
406
  const result = await raceWithAbortSignal(selected.kind === "classifier"
361
- ? inferClassifier(current, selected, controller.signal)
362
- : inferChat(current, selected.model, controller.signal, assertActive), controller.signal);
407
+ ? inferClassifier(current, selected, controller.signal, request.trace)
408
+ : inferChat(current, selected.model, controller.signal, assertActive, request.trace), controller.signal);
363
409
  assertActive();
364
410
  usage.inputTokens += result.usage.inputTokens;
365
411
  usage.outputTokens += result.usage.outputTokens;
@@ -372,12 +418,14 @@ async function inferDecision(request, repairs, validateDecision, fallbackModel)
372
418
  }
373
419
  if (request.candidateFallback && selected.kind === "chat")
374
420
  omitOptionalNulls(value, snapshot.schema);
375
- if (!Check(snapshot.schema, value) || (validateDecision && !validateDecision(value)))
376
- throw new InvalidDecisionOutputError("Invalid structured output: response does not match the decision schema.");
421
+ const matchesSchema = Check(snapshot.schema, value);
422
+ if (!matchesSchema || (validateDecision && !validateDecision(value)))
423
+ throw new InvalidDecisionOutputError(schemaMismatchMessage(matchesSchema ? [] : describeSchemaErrors(snapshot.schema, value)));
377
424
  assertActive();
378
425
  return { ...result, value, usage, ...(fallback ? { fallback } : {}) };
379
426
  }
380
427
  catch (error) {
428
+ request.trace.settleOpen();
381
429
  assertActive();
382
430
  if (selected.kind === "classifier" &&
383
431
  fallbackChat &&
@@ -394,7 +442,9 @@ async function inferDecision(request, repairs, validateDecision, fallbackModel)
394
442
  };
395
443
  reportModelRoutingDebug(`Classifier routing failed${error instanceof ClassifierDecisionError && error.detail ? ` (${error.detail})` : ""}; falling back to current chat model ${fallback.to} for this routing decision.`);
396
444
  selected = { kind: "chat", fullId: fallback.to, model: fallbackChat };
445
+ rejection = undefined;
397
446
  attempt = 0;
447
+ firstAttempt = request.trace.size;
398
448
  continue;
399
449
  }
400
450
  if (!(error instanceof InvalidDecisionOutputError))
@@ -404,17 +454,22 @@ async function inferDecision(request, repairs, validateDecision, fallbackModel)
404
454
  usage.outputTokens += error.usage.outputTokens;
405
455
  }
406
456
  if (attempt < repairs) {
457
+ rejection = error.message;
407
458
  attempt++;
408
459
  continue;
409
460
  }
410
461
  const scope = request.candidateFallback ? "Structured" : fallback ? "Chat fallback" : "Routing";
411
- const message = `${error.message} ${repairs ? `${scope} output repair exhausted after ${repairs + 1} attempts.` : "No repair request was made."}`;
462
+ const exhaustion = repairs
463
+ ? `${scope} output repair exhausted after ${repairs + 1} attempts.`
464
+ : "No repair request was made.";
465
+ const attempts = request.trace.describe(firstAttempt);
466
+ const message = `${error.message} ${exhaustion}${attempts ? ` ${attempts}` : ""}`;
412
467
  throw request.candidateFallback ? new OutputRepairExhaustedError(message) : new Error(message);
413
468
  }
414
469
  }
415
470
  }
416
471
  finally {
417
- request.signal?.removeEventListener("abort", abort);
472
+ request.signal.removeEventListener("abort", abort);
418
473
  }
419
474
  }
420
475
  /** Resolve only prerequisite routing inference. Does not execute the selected action or alter chat/tools. */
@@ -422,12 +477,13 @@ export async function routeModel(request,
422
477
  /** Pure correlated-field validation against original candidates, never live admission checks. */
423
478
  validateDecision) {
424
479
  request.signal?.throwIfAborted();
425
- const { settings, currentModel, ...inference } = request;
480
+ const { settings, currentModel, timeoutMs, ...inference } = request;
426
481
  const model = resolveRouterModel({ settings, currentModel, modelRegistry: request.modelRegistry });
427
482
  const fallback = model.kind !== "chat" && currentModel && currentModel.id !== "auto" && isModelType(currentModel, "chat")
428
483
  ? currentModel
429
484
  : undefined;
430
485
  const retry = inference.retry ?? settings.getRetrySettings?.() ?? DEFAULT_DECISION_RETRY;
431
- return inferDecision({ ...inference, model, retry }, 3, validateDecision, fallback);
486
+ const deadlineMs = resolveDecisionDeadlineMs(timeoutMs, settings.getHttpIdleTimeoutMs?.());
487
+ return withinDecisionDeadline(request.signal, deadlineMs, ({ signal, trace }) => inferDecision({ ...inference, model, retry, signal, trace }, 3, validateDecision, fallback));
432
488
  }
433
489
  //# sourceMappingURL=index.js.map