@the-open-engine/zeroshot 6.38.0 → 6.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/cli/event-copy.js +8 -7
  2. package/cli/event-copy.ts +12 -0
  3. package/cli/index.js +7 -31
  4. package/cli/json-export.js +61 -64
  5. package/cli/json-export.ts +112 -0
  6. package/cli/message-formatter-utils.js +68 -56
  7. package/cli/message-formatter-utils.ts +121 -0
  8. package/cli/message-formatters-normal.js +124 -259
  9. package/cli/message-formatters-normal.ts +250 -0
  10. package/cli/message-formatters-watch.js +81 -84
  11. package/cli/message-formatters-watch.ts +189 -0
  12. package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
  13. package/lib/agent-cli-provider/adapters/codex.js +3 -1
  14. package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
  15. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  16. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  17. package/lib/cluster/generated/protocol.d.cts +8 -0
  18. package/lib/cluster/generated/protocol.d.mts +8 -0
  19. package/lib/cluster/generated/protocol.d.ts +8 -0
  20. package/lib/clusters-registry.d.ts +23 -0
  21. package/lib/clusters-registry.js +17 -29
  22. package/lib/completion.d.ts +12 -0
  23. package/lib/completion.js +84 -94
  24. package/lib/compose-utils.d.ts +32 -0
  25. package/lib/compose-utils.js +57 -72
  26. package/lib/detached-startup.d.ts +83 -0
  27. package/lib/detached-startup.js +231 -302
  28. package/lib/docker-config.d.ts +43 -0
  29. package/lib/docker-config.js +150 -325
  30. package/lib/docker-env-auth.d.ts +17 -0
  31. package/lib/docker-env-auth.js +75 -0
  32. package/lib/git-remote-utils.d.ts +48 -0
  33. package/lib/git-remote-utils.js +147 -213
  34. package/lib/id-detector.d.ts +15 -0
  35. package/lib/id-detector.js +37 -41
  36. package/lib/path-check.d.ts +30 -0
  37. package/lib/path-check.js +42 -45
  38. package/lib/process-liveness.d.ts +16 -0
  39. package/lib/process-liveness.js +19 -12
  40. package/lib/provider-credential-path.d.ts +16 -0
  41. package/lib/provider-credential-path.js +31 -29
  42. package/lib/provider-defaults.d.ts +30 -0
  43. package/lib/provider-defaults.js +47 -42
  44. package/lib/provider-detection.d.ts +11 -0
  45. package/lib/provider-detection.js +91 -54
  46. package/lib/provider-names.d.ts +38 -0
  47. package/lib/provider-names.js +56 -64
  48. package/lib/repo-settings.d.ts +28 -0
  49. package/lib/repo-settings.js +83 -59
  50. package/lib/run-mode.d.ts +21 -0
  51. package/lib/run-mode.js +21 -20
  52. package/lib/run-plan.d.ts +28 -0
  53. package/lib/run-plan.js +17 -16
  54. package/lib/settings/claude-auth.d.ts +35 -0
  55. package/lib/settings/claude-auth.js +30 -47
  56. package/lib/settings-defaults.d.ts +20 -0
  57. package/lib/settings-defaults.js +149 -0
  58. package/lib/settings-error.d.ts +7 -0
  59. package/lib/settings-error.js +8 -0
  60. package/lib/settings-issue-providers.d.ts +10 -0
  61. package/lib/settings-issue-providers.js +12 -0
  62. package/lib/settings-models.d.ts +22 -0
  63. package/lib/settings-models.js +93 -0
  64. package/lib/settings-storage.d.ts +23 -0
  65. package/lib/settings-storage.js +205 -0
  66. package/lib/settings-validation.d.ts +7 -0
  67. package/lib/settings-validation.js +182 -0
  68. package/lib/settings.d.ts +29 -0
  69. package/lib/settings.js +41 -736
  70. package/lib/setup-apply-types.d.ts +66 -0
  71. package/lib/setup-apply-types.js +2 -0
  72. package/lib/setup-apply.d.ts +39 -0
  73. package/lib/setup-apply.js +267 -264
  74. package/lib/setup-journal.d.ts +41 -0
  75. package/lib/setup-journal.js +119 -76
  76. package/lib/setup-plan-types.d.ts +102 -0
  77. package/lib/setup-plan-types.js +2 -0
  78. package/lib/setup-plan.d.ts +30 -0
  79. package/lib/setup-plan.js +300 -324
  80. package/lib/setup-undo.d.ts +44 -0
  81. package/lib/setup-undo.js +61 -74
  82. package/lib/start-cluster-config.d.ts +26 -0
  83. package/lib/start-cluster-config.js +56 -0
  84. package/lib/start-cluster-environment.d.ts +40 -0
  85. package/lib/start-cluster-environment.js +134 -0
  86. package/lib/start-cluster-run-options.d.ts +53 -0
  87. package/lib/start-cluster-run-options.js +147 -0
  88. package/lib/start-cluster.d.ts +64 -0
  89. package/lib/start-cluster.js +98 -454
  90. package/lib/stream-json-parser.d.ts +17 -0
  91. package/lib/stream-json-parser.js +51 -52
  92. package/npm-shrinkwrap.json +2 -2
  93. package/package.json +12 -6
  94. package/scripts/postinstall.js +27 -0
  95. package/scripts/rust-distribution.js +23 -14
  96. package/src/agent/agent-command-proofs-context.js +35 -45
  97. package/src/agent/agent-command-proofs-context.ts +87 -0
  98. package/src/agent/agent-config-settings.js +19 -0
  99. package/src/agent/agent-config-settings.ts +41 -0
  100. package/src/agent/agent-config.js +122 -231
  101. package/src/agent/agent-config.ts +285 -0
  102. package/src/agent/agent-context-builder.js +38 -273
  103. package/src/agent/agent-context-builder.ts +51 -0
  104. package/src/agent/agent-context-environment-sections.js +105 -0
  105. package/src/agent/agent-context-environment-sections.ts +134 -0
  106. package/src/agent/agent-context-packs.js +165 -0
  107. package/src/agent/agent-context-packs.ts +296 -0
  108. package/src/agent/agent-context-prompt-sections.js +100 -0
  109. package/src/agent/agent-context-prompt-sections.ts +148 -0
  110. package/src/agent/agent-context-sections.js +25 -334
  111. package/src/agent/agent-context-sections.ts +36 -0
  112. package/src/agent/agent-context-sources.js +96 -149
  113. package/src/agent/agent-context-sources.ts +253 -0
  114. package/src/agent/agent-context-types.js +2 -0
  115. package/src/agent/agent-context-types.ts +132 -0
  116. package/src/agent/agent-context-validation-sections.js +73 -0
  117. package/src/agent/agent-context-validation-sections.ts +129 -0
  118. package/src/agent/agent-input-injector.js +99 -118
  119. package/src/agent/agent-input-injector.ts +195 -0
  120. package/src/agent/agent-liveness-poll.js +74 -78
  121. package/src/agent/agent-liveness-poll.ts +163 -0
  122. package/src/agent/agent-quality-gate-schema.js +77 -86
  123. package/src/agent/agent-quality-gate-schema.ts +135 -0
  124. package/src/agent/agent-quality-gates-context.js +44 -50
  125. package/src/agent/agent-quality-gates-context.ts +91 -0
  126. package/src/agent/agent-stuck-detector.js +171 -239
  127. package/src/agent/agent-stuck-detector.ts +288 -0
  128. package/src/agent/agent-trigger-evaluator.js +29 -46
  129. package/src/agent/agent-trigger-evaluator.ts +98 -0
  130. package/src/agent/context-metrics.js +110 -141
  131. package/src/agent/context-metrics.ts +261 -0
  132. package/src/agent/context-pack-builder.js +72 -358
  133. package/src/agent/context-pack-builder.ts +105 -0
  134. package/src/agent/context-pack-core.js +70 -0
  135. package/src/agent/context-pack-core.ts +96 -0
  136. package/src/agent/context-pack-selection.js +119 -0
  137. package/src/agent/context-pack-selection.ts +187 -0
  138. package/src/agent/context-pack-truncation.js +139 -0
  139. package/src/agent/context-pack-truncation.ts +208 -0
  140. package/src/agent/context-pack-types.js +2 -0
  141. package/src/agent/context-pack-types.ts +98 -0
  142. package/src/agent/context-replay-policy.js +30 -39
  143. package/src/agent/context-replay-policy.ts +71 -0
  144. package/src/agent/critical-agent-policy.js +6 -10
  145. package/src/agent/critical-agent-policy.ts +20 -0
  146. package/src/agent/guidance-queue.js +74 -87
  147. package/src/agent/guidance-queue.ts +166 -0
  148. package/src/agent/output-extraction-error-detail.js +45 -0
  149. package/src/agent/output-extraction-error-detail.ts +49 -0
  150. package/src/agent/output-extraction-failures.js +125 -0
  151. package/src/agent/output-extraction-failures.ts +149 -0
  152. package/src/agent/output-extraction-json.js +234 -0
  153. package/src/agent/output-extraction-json.ts +235 -0
  154. package/src/agent/output-extraction-pi.js +124 -0
  155. package/src/agent/output-extraction-pi.ts +137 -0
  156. package/src/agent/output-extraction-types.js +2 -0
  157. package/src/agent/output-extraction-types.ts +49 -0
  158. package/src/agent/output-extraction.js +17 -617
  159. package/src/agent/output-extraction.ts +30 -0
  160. package/src/agent/output-reformatter-errors.js +83 -0
  161. package/src/agent/output-reformatter-errors.ts +106 -0
  162. package/src/agent/output-reformatter-types.js +2 -0
  163. package/src/agent/output-reformatter-types.ts +86 -0
  164. package/src/agent/output-reformatter.js +140 -185
  165. package/src/agent/output-reformatter.ts +238 -0
  166. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  167. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  168. package/src/agent/pi-terminal-lifecycle.js +186 -206
  169. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  170. package/src/agent/provider-control-plane.js +22 -21
  171. package/src/agent/provider-control-plane.ts +52 -0
  172. package/src/agent/provider-terminal-failure-types.js +2 -0
  173. package/src/agent/provider-terminal-failure-types.ts +60 -0
  174. package/src/agent/provider-terminal-failure.js +194 -191
  175. package/src/agent/provider-terminal-failure.ts +262 -0
  176. package/src/agent/rate-limit-backoff.js +31 -74
  177. package/src/agent/rate-limit-backoff.ts +71 -0
  178. package/src/agent/schema-utils.js +85 -125
  179. package/src/agent/schema-utils.ts +148 -0
  180. package/src/agent/structured-output-error.js +34 -33
  181. package/src/agent/structured-output-error.ts +105 -0
  182. package/src/agent/validation-platform.js +27 -27
  183. package/src/agent/validation-platform.ts +49 -0
  184. package/src/agent-cli-provider/adapters/codex.ts +3 -1
  185. package/src/attach/attach-client.js +232 -405
  186. package/src/attach/attach-client.ts +300 -0
  187. package/src/attach/attach-server-cleanup.js +43 -0
  188. package/src/attach/attach-server-cleanup.ts +39 -0
  189. package/src/attach/attach-server-clients.js +117 -0
  190. package/src/attach/attach-server-clients.ts +122 -0
  191. package/src/attach/attach-server-events.js +38 -0
  192. package/src/attach/attach-server-events.ts +36 -0
  193. package/src/attach/attach-server-pty.js +45 -0
  194. package/src/attach/attach-server-pty.ts +64 -0
  195. package/src/attach/attach-server-runtime.js +73 -0
  196. package/src/attach/attach-server-runtime.ts +62 -0
  197. package/src/attach/attach-server-socket.js +28 -0
  198. package/src/attach/attach-server-socket.ts +23 -0
  199. package/src/attach/attach-server-types.js +2 -0
  200. package/src/attach/attach-server-types.ts +82 -0
  201. package/src/attach/attach-server.js +106 -523
  202. package/src/attach/attach-server.ts +158 -0
  203. package/src/attach/index.js +18 -35
  204. package/src/attach/index.ts +18 -0
  205. package/src/attach/protocol.js +95 -184
  206. package/src/attach/protocol.ts +181 -0
  207. package/src/attach/ring-buffer.js +76 -102
  208. package/src/attach/ring-buffer.ts +109 -0
  209. package/src/attach/send-input.js +64 -75
  210. package/src/attach/send-input.ts +94 -0
  211. package/src/attach/socket-discovery.js +164 -218
  212. package/src/attach/socket-discovery.ts +230 -0
  213. package/src/attach/socket-paths.js +42 -61
  214. package/src/attach/socket-paths.ts +81 -0
  215. package/src/claude-credentials.js +51 -54
  216. package/src/claude-credentials.ts +89 -0
  217. package/src/cluster/generated/protocol-schema.ts +1 -1
  218. package/src/cluster/generated/protocol.ts +2 -1
  219. package/src/command-proofs.js +110 -141
  220. package/src/command-proofs.ts +216 -0
  221. package/src/config-router.js +81 -73
  222. package/src/config-router.ts +131 -0
  223. package/src/copy-worker.js +53 -29
  224. package/src/copy-worker.ts +75 -0
  225. package/src/darwin-keychain-boundary.js +80 -111
  226. package/src/darwin-keychain-boundary.ts +148 -0
  227. package/src/guidance-topics.js +4 -5
  228. package/src/guidance-topics.ts +10 -0
  229. package/src/input-helpers.js +33 -54
  230. package/src/input-helpers.ts +58 -0
  231. package/src/ledger-sequence.js +45 -48
  232. package/src/ledger-sequence.ts +63 -0
  233. package/src/legacy-lib/clusters-registry.ts +40 -0
  234. package/src/legacy-lib/completion.ts +148 -0
  235. package/src/legacy-lib/compose-utils.ts +102 -0
  236. package/src/legacy-lib/detached-startup.ts +449 -0
  237. package/src/legacy-lib/docker-config.ts +282 -0
  238. package/src/legacy-lib/docker-env-auth.ts +116 -0
  239. package/src/legacy-lib/git-remote-utils.ts +244 -0
  240. package/src/legacy-lib/id-detector.ts +57 -0
  241. package/src/legacy-lib/js-yaml.d.ts +3 -0
  242. package/src/legacy-lib/omelette.d.ts +15 -0
  243. package/src/legacy-lib/path-check.ts +89 -0
  244. package/src/legacy-lib/process-liveness.ts +36 -0
  245. package/src/legacy-lib/provider-credential-path.ts +57 -0
  246. package/src/legacy-lib/provider-defaults.ts +114 -0
  247. package/src/legacy-lib/provider-detection.ts +67 -0
  248. package/src/legacy-lib/provider-names.ts +126 -0
  249. package/src/legacy-lib/repo-settings.ts +88 -0
  250. package/src/legacy-lib/run-mode.ts +58 -0
  251. package/src/legacy-lib/run-plan.ts +49 -0
  252. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  253. package/src/legacy-lib/settings-defaults.ts +212 -0
  254. package/src/legacy-lib/settings-error.ts +8 -0
  255. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  256. package/src/legacy-lib/settings-models.ts +124 -0
  257. package/src/legacy-lib/settings-storage.ts +277 -0
  258. package/src/legacy-lib/settings-validation.ts +220 -0
  259. package/src/legacy-lib/settings.ts +87 -0
  260. package/src/legacy-lib/setup-apply-types.ts +70 -0
  261. package/src/legacy-lib/setup-apply.ts +456 -0
  262. package/src/legacy-lib/setup-journal.ts +185 -0
  263. package/src/legacy-lib/setup-plan-types.ts +96 -0
  264. package/src/legacy-lib/setup-plan.ts +500 -0
  265. package/src/legacy-lib/setup-undo.ts +142 -0
  266. package/src/legacy-lib/start-cluster-config.ts +124 -0
  267. package/src/legacy-lib/start-cluster-environment.ts +165 -0
  268. package/src/legacy-lib/start-cluster-run-options.ts +279 -0
  269. package/src/legacy-lib/start-cluster.ts +237 -0
  270. package/src/legacy-lib/stream-json-parser.ts +88 -0
  271. package/src/message-buffer.js +55 -71
  272. package/src/message-buffer.ts +107 -0
  273. package/src/message-bus-bridge.js +92 -133
  274. package/src/message-bus-bridge.ts +149 -0
  275. package/src/name-generator-shared.js +220 -0
  276. package/src/name-generator-shared.ts +231 -0
  277. package/src/name-generator.js +8 -217
  278. package/src/name-generator.ts +27 -0
  279. package/src/omp-blob-root.js +83 -64
  280. package/src/omp-blob-root.ts +116 -0
  281. package/src/omp-config-overlay.js +65 -38
  282. package/src/omp-config-overlay.ts +110 -0
  283. package/src/omp-execution-fingerprint.js +38 -43
  284. package/src/omp-execution-fingerprint.ts +92 -0
  285. package/src/omp-session-limits.js +10 -15
  286. package/src/omp-session-limits.ts +53 -0
  287. package/src/omp-session-partition.js +2 -2
  288. package/src/omp-session-verifier.js +1 -1
  289. package/src/orchestrator.js +19 -4
  290. package/src/providers/anthropic/index.js +3 -1
  291. package/src/providers/anthropic/index.ts +13 -0
  292. package/src/providers/capabilities.js +19 -27
  293. package/src/providers/capabilities.ts +44 -0
  294. package/src/providers/google/index.js +3 -1
  295. package/src/providers/google/index.ts +13 -0
  296. package/src/providers/openai/index.js +3 -1
  297. package/src/providers/openai/index.ts +13 -0
  298. package/src/providers/opencode/index.js +3 -1
  299. package/src/providers/opencode/index.ts +13 -0
  300. package/src/quality-gates.js +67 -127
  301. package/src/quality-gates.ts +149 -0
  302. package/src/repo-settings-access.js +40 -0
  303. package/src/repo-settings-access.ts +64 -0
  304. package/src/schemas/sub-cluster.js +127 -183
  305. package/src/schemas/sub-cluster.ts +238 -0
  306. package/src/state-snapshot-normalization.js +224 -0
  307. package/src/state-snapshot-normalization.ts +222 -0
  308. package/src/state-snapshot.js +192 -359
  309. package/src/state-snapshot.ts +291 -0
  310. package/src/state-snapshotter.js +118 -130
  311. package/src/state-snapshotter.ts +167 -0
  312. package/src/sub-cluster-wrapper.js +4 -13
  313. package/src/task-run-model-args.js +87 -124
  314. package/src/task-run-model-args.ts +204 -0
  315. package/src/task-runner.js +5 -25
  316. package/src/task-runner.ts +28 -0
  317. package/src/task-startup-error.js +73 -58
  318. package/src/task-startup-error.ts +126 -0
  319. package/src/template-validation/consensus-gate-contracts.js +2 -0
  320. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  321. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  322. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  323. package/src/template-validation/consensus-gate-stage.js +34 -0
  324. package/src/template-validation/consensus-gate-stage.ts +56 -0
  325. package/src/template-validation/random-topology-contracts.js +2 -0
  326. package/src/template-validation/random-topology-contracts.ts +54 -0
  327. package/src/template-validation/random-topology-dispatch.js +25 -0
  328. package/src/template-validation/random-topology-dispatch.ts +33 -0
  329. package/src/template-validation/random-topology-message-loop.js +53 -0
  330. package/src/template-validation/random-topology-message-loop.ts +73 -0
  331. package/src/template-validation/random-topology-operations.js +79 -0
  332. package/src/template-validation/random-topology-operations.ts +101 -0
  333. package/src/template-validation/random-topology-runtime.js +25 -0
  334. package/src/template-validation/random-topology-runtime.ts +43 -0
  335. package/src/template-validation/random-topology-scenario.js +52 -0
  336. package/src/template-validation/random-topology-scenario.ts +57 -0
  337. package/src/template-validation/random-topology-schema.js +159 -0
  338. package/src/template-validation/random-topology-schema.ts +190 -0
  339. package/src/template-validation/random-topology-state.js +28 -0
  340. package/src/template-validation/random-topology-state.ts +30 -0
  341. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  342. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  343. package/src/template-validation/random-topology-trigger.js +75 -0
  344. package/src/template-validation/random-topology-trigger.ts +88 -0
  345. package/src/template-validation/report-formatter.js +40 -46
  346. package/src/template-validation/report-formatter.ts +101 -0
  347. package/src/template-validation/simulate-consensus-gates.js +111 -302
  348. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  349. package/src/template-validation/simulate-random-topology.js +26 -519
  350. package/src/template-validation/simulate-random-topology.ts +57 -0
  351. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  352. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  353. package/src/template-validation/simulation-agent-runtime.js +25 -0
  354. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  355. package/src/template-validation/simulation-agent.js +29 -0
  356. package/src/template-validation/simulation-agent.ts +73 -0
  357. package/src/template-validation/simulation-runtime.js +34 -0
  358. package/src/template-validation/simulation-runtime.ts +72 -0
  359. package/src/template-validation/two-stage-contracts.js +2 -0
  360. package/src/template-validation/two-stage-contracts.ts +41 -0
  361. package/src/template-validation/two-stage-inputs.js +21 -0
  362. package/src/template-validation/two-stage-inputs.ts +29 -0
  363. package/src/template-validation/two-stage-results.js +30 -0
  364. package/src/template-validation/two-stage-results.ts +40 -0
  365. package/src/template-validation/two-stage-scenario.js +86 -0
  366. package/src/template-validation/two-stage-scenario.ts +120 -0
  367. package/src/worktree-claude-config.js +182 -220
  368. package/src/worktree-claude-config.ts +272 -0
  369. package/src/worktree-tooling-env.js +103 -125
  370. package/src/worktree-tooling-env.ts +142 -0
  371. package/task-lib/completion.js +2 -3
  372. package/task-lib/completion.ts +9 -0
  373. package/task-lib/config.js +1 -4
  374. package/task-lib/config.ts +11 -0
  375. package/task-lib/name-generator.js +4 -226
  376. package/task-lib/name-generator.ts +11 -0
  377. package/task-lib/omp-session-cleanup.js +1 -1
  378. package/task-lib/omp-storage-root.js +8 -12
  379. package/task-lib/omp-storage-root.ts +62 -0
  380. package/task-lib/process-termination.js +143 -166
  381. package/task-lib/process-termination.ts +268 -0
@@ -1,264 +1,155 @@
1
- /**
2
- * AgentConfig - Agent configuration validation and defaults
3
- *
4
- * Provides:
5
- * - Config validation and normalization
6
- * - Default values for optional fields
7
- * - Model configuration setup
8
- * - Safety checks for test mode
9
- * - maxModel ceiling enforcement at config time
10
- */
11
-
12
- const { loadSettings, validateModelAgainstMax, VALID_MODELS } = require('../../lib/settings');
13
- const { applyValidatorQualityGateDefaults } = require('./agent-quality-gate-schema');
14
-
1
+ "use strict";
2
+ /** Agent configuration validation and defaults. */
3
+ const qualityGateSchema = require("./agent-quality-gate-schema");
4
+ const settingsFacade = require("./agent-config-settings");
15
5
  const VALID_LEVELS = ['level1', 'level2', 'level3'];
16
-
17
- // Default max iterations (high limit - let the user decide when to give up)
18
6
  const DEFAULT_MAX_ITERATIONS = 100;
19
-
20
- // Default timeout: 0 = no timeout (task runs until completion or explicit kill)
21
- // Use positive number for timeout in milliseconds
22
7
  const DEFAULT_TIMEOUT = 0;
23
-
24
- // Output-silence detection is opt-in because healthy provider operations may be quiet for
25
- // longer than the stale threshold. Explicit task timeouts remain independently supported.
26
- const DEFAULT_STALE_DURATION_MS = 30 * 60 * 1000; // 30 minutes before triggering analysis
8
+ const DEFAULT_STALE_DURATION_MS = 30 * 60 * 1000;
27
9
  const DEFAULT_LIVENESS_CHECK_ENABLED = false;
28
-
10
+ function isRecord(value) {
11
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
12
+ }
13
+ function isModelLevel(value) {
14
+ return value === 'level1' || value === 'level2' || value === 'level3';
15
+ }
16
+ const { loadSettings, validateModelAgainstMax, VALID_MODELS } = settingsFacade;
17
+ const { applyValidatorQualityGateDefaults } = qualityGateSchema;
29
18
  function applyOutputDefaults(config) {
30
- // CRITICAL: Enforce JSON schema output by default to prevent parse failures and crashes
31
- if (!config.outputFormat) {
32
- config.outputFormat = 'json';
33
- }
34
-
35
- // Map structuredOutput → jsonSchema (structuredOutput is the user-facing API name,
36
- // jsonSchema is the internal key used by task executor and CLI args).
37
- // Explicit jsonSchema takes precedence over structuredOutput.
38
- if (config.structuredOutput && !config.jsonSchema) {
39
- config.jsonSchema = config.structuredOutput;
40
- }
41
-
42
- // If outputFormat is json but no schema defined, use a minimal default schema
43
- if (config.outputFormat === 'json' && !config.jsonSchema) {
44
- config.jsonSchema = {
45
- type: 'object',
46
- properties: {
47
- summary: {
48
- type: 'string',
49
- description: 'Brief summary of what was done',
50
- },
51
- result: {
52
- type: 'string',
53
- description: 'Detailed result or output',
54
- },
55
- },
56
- required: ['summary', 'result'],
57
- };
58
- }
59
-
60
- applyValidatorQualityGateDefaults(config);
19
+ if (!config.outputFormat)
20
+ config.outputFormat = 'json';
21
+ if (config.structuredOutput && !config.jsonSchema)
22
+ config.jsonSchema = config.structuredOutput;
23
+ if (config.outputFormat === 'json' && !config.jsonSchema) {
24
+ config.jsonSchema = {
25
+ type: 'object',
26
+ properties: {
27
+ summary: { type: 'string', description: 'Brief summary of what was done' },
28
+ result: { type: 'string', description: 'Detailed result or output' },
29
+ },
30
+ required: ['summary', 'result'],
31
+ };
32
+ }
33
+ applyValidatorQualityGateDefaults(config);
61
34
  }
62
-
63
35
  function buildModelConfig(config) {
64
- if (config.modelRules) {
65
- return { type: 'rules', rules: config.modelRules };
66
- }
67
- return {
68
- type: 'static',
69
- model: config.model || null,
70
- modelLevel: config.modelLevel || null,
71
- };
36
+ if (config.modelRules)
37
+ return { type: 'rules', rules: config.modelRules };
38
+ return { type: 'static', model: config.model || null, modelLevel: config.modelLevel || null };
72
39
  }
73
-
74
40
  function applyStrictSchemaDefault(config, settings) {
75
- if (config.strictSchema === undefined) {
76
- config.strictSchema = settings.strictSchema !== false; // Default true if not set
77
- }
41
+ if (config.strictSchema === undefined)
42
+ config.strictSchema = settings.strictSchema !== false;
43
+ }
44
+ function errorMessage(error) {
45
+ return isRecord(error) ? error.message : undefined;
78
46
  }
79
-
80
47
  function validateStaticModelConfig(configId, modelConfig, maxModel, minModel) {
81
- if (modelConfig.model && VALID_MODELS.includes(modelConfig.model)) {
82
- try {
83
- validateModelAgainstMax(modelConfig.model, maxModel, minModel);
84
- } catch (error) {
85
- throw new Error(`Agent "${configId}": ${error.message}`);
48
+ if (modelConfig.model && VALID_MODELS.includes(modelConfig.model)) {
49
+ try {
50
+ validateModelAgainstMax(modelConfig.model, maxModel, minModel);
51
+ }
52
+ catch (error) {
53
+ throw new Error(`Agent "${configId}": ${String(errorMessage(error))}`);
54
+ }
55
+ }
56
+ if (modelConfig.modelLevel && !isModelLevel(modelConfig.modelLevel)) {
57
+ throw new Error(`Agent "${configId}": invalid modelLevel "${modelConfig.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`);
86
58
  }
87
- }
88
-
89
- if (modelConfig.modelLevel && !VALID_LEVELS.includes(modelConfig.modelLevel)) {
90
- throw new Error(
91
- `Agent "${configId}": invalid modelLevel "${modelConfig.modelLevel}". ` +
92
- `Valid: ${VALID_LEVELS.join(', ')}`
93
- );
94
- }
95
59
  }
96
-
97
60
  function validateModelRule(configId, rule, maxModel, minModel) {
98
- if (rule.model && VALID_MODELS.includes(rule.model)) {
99
- try {
100
- validateModelAgainstMax(rule.model, maxModel, minModel);
101
- } catch {
102
- throw new Error(
103
- `Agent "${configId}": modelRule "${rule.iterations}" requests "${rule.model}" ` +
104
- `but maxModel is "${maxModel}"${minModel ? ` and minModel is "${minModel}"` : ''}. ` +
105
- `Either adjust the rule's model or change maxModel/minModel settings.`
106
- );
61
+ if (rule.model && VALID_MODELS.includes(rule.model)) {
62
+ try {
63
+ validateModelAgainstMax(rule.model, maxModel, minModel);
64
+ }
65
+ catch {
66
+ throw new Error(`Agent "${configId}": modelRule "${String(rule.iterations)}" requests "${rule.model}" ` +
67
+ `but maxModel is "${maxModel}"${minModel ? ` and minModel is "${minModel}"` : ''}. ` +
68
+ `Either adjust the rule's model or change maxModel/minModel settings.`);
69
+ }
70
+ }
71
+ if (rule.modelLevel && !isModelLevel(rule.modelLevel)) {
72
+ throw new Error(`Agent "${configId}": modelRule "${String(rule.iterations)}" has invalid modelLevel ` +
73
+ `"${rule.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`);
107
74
  }
108
- }
109
-
110
- if (rule.modelLevel && !VALID_LEVELS.includes(rule.modelLevel)) {
111
- throw new Error(
112
- `Agent "${configId}": modelRule "${rule.iterations}" has invalid modelLevel ` +
113
- `"${rule.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`
114
- );
115
- }
116
75
  }
117
-
118
76
  function validateModelConfig(config, modelConfig, maxModel, minModel) {
119
- if (modelConfig.type === 'static') {
120
- validateStaticModelConfig(config.id, modelConfig, maxModel, minModel);
121
- return;
122
- }
123
-
124
- if (modelConfig.type === 'rules') {
125
- for (const rule of modelConfig.rules) {
126
- validateModelRule(config.id, rule, maxModel, minModel);
77
+ if (modelConfig.type === 'static') {
78
+ validateStaticModelConfig(config.id, modelConfig, maxModel, minModel);
79
+ }
80
+ else {
81
+ for (const rule of modelConfig.rules)
82
+ validateModelRule(config.id, rule, maxModel, minModel);
127
83
  }
128
- }
129
84
  }
130
-
131
85
  function buildInitialPromptRules(prompt) {
132
- if (prompt?.initial || prompt?.subsequent) {
86
+ if (!prompt.initial && !prompt.subsequent)
87
+ return null;
133
88
  const rules = [];
134
- if (prompt.initial) rules.push({ match: '1', system: prompt.initial });
135
- if (prompt.subsequent) rules.push({ match: '2+', system: prompt.subsequent });
89
+ if (prompt.initial)
90
+ rules.push({ match: '1', system: prompt.initial });
91
+ if (prompt.subsequent)
92
+ rules.push({ match: '2+', system: prompt.subsequent });
136
93
  return rules;
137
- }
138
-
139
- return null;
140
94
  }
141
-
142
95
  function buildPromptConfig(config) {
143
- const prompt = config.prompt;
144
- if (prompt?.iterations) {
145
- return { type: 'rules', rules: prompt.iterations };
146
- }
147
-
148
- const initialRules = buildInitialPromptRules(prompt);
149
- if (initialRules) {
150
- return { type: 'rules', rules: initialRules };
151
- }
152
-
153
- if (typeof prompt === 'string') {
154
- return { type: 'static', system: prompt };
155
- }
156
-
157
- if (prompt?.system) {
158
- return { type: 'static', system: prompt.system };
159
- }
160
-
161
- if (prompt) {
162
- throw new Error(`Agent "${config.id}": invalid prompt format`);
163
- }
164
-
165
- return null;
96
+ const prompt = config.prompt;
97
+ if (prompt && typeof prompt !== 'string' && prompt.iterations) {
98
+ return { type: 'rules', rules: prompt.iterations };
99
+ }
100
+ if (prompt && typeof prompt !== 'string') {
101
+ const initialRules = buildInitialPromptRules(prompt);
102
+ if (initialRules)
103
+ return { type: 'rules', rules: initialRules };
104
+ }
105
+ if (typeof prompt === 'string')
106
+ return { type: 'static', system: prompt };
107
+ if (prompt?.system)
108
+ return { type: 'static', system: prompt.system };
109
+ if (prompt)
110
+ throw new Error(`Agent "${config.id}": invalid prompt format`);
111
+ return null;
166
112
  }
167
-
168
113
  function normalizeTimeout(config) {
169
- if (config.timeout === undefined || config.timeout === null || config.timeout === '') {
170
- config.timeout = DEFAULT_TIMEOUT;
171
- } else {
172
- config.timeout = Number(config.timeout);
173
- }
174
-
175
- if (!Number.isFinite(config.timeout) || config.timeout < 0) {
176
- throw new Error(
177
- `Agent "${config.id}": timeout must be a non-negative number (got ${config.timeout}).`
178
- );
179
- }
180
-
181
- return config.timeout;
182
- }
183
-
184
- function buildNormalizedConfig(config, modelConfig, promptConfig) {
185
- return {
186
- ...config,
187
- modelConfig,
188
- promptConfig,
189
- maxIterations: config.maxIterations || DEFAULT_MAX_ITERATIONS,
190
- timeout: config.timeout,
191
- staleDuration: config.staleDuration || DEFAULT_STALE_DURATION_MS,
192
- enableLivenessCheck: config.enableLivenessCheck ?? DEFAULT_LIVENESS_CHECK_ENABLED,
193
- };
114
+ const timeout = config.timeout === undefined || config.timeout === null || config.timeout === ''
115
+ ? DEFAULT_TIMEOUT
116
+ : Number(config.timeout);
117
+ config.timeout = timeout;
118
+ if (!Number.isFinite(timeout) || timeout < 0) {
119
+ throw new Error(`Agent "${config.id}": timeout must be a non-negative number (got ${timeout}).`);
120
+ }
121
+ return timeout;
194
122
  }
195
-
196
123
  function assertTestModeSafety(config, options) {
197
- const executesTask = config.triggers?.some(
198
- (trigger) => !trigger.action || trigger.action === 'execute_task'
199
- );
200
- const hasMock = options.mockSpawnFn || options.taskRunner;
201
-
202
- if (options.testMode && !hasMock && executesTask) {
203
- throw new Error(
204
- `AgentWrapper: testMode=true but no mockSpawnFn/taskRunner provided for agent '${config.id}'. ` +
205
- `This would cause real Claude API calls. ABORTING.`
206
- );
207
- }
124
+ const executesTask = config.triggers?.some((trigger) => !trigger.action || trigger.action === 'execute_task');
125
+ if (options.testMode && !options.mockSpawnFn && !options.taskRunner && executesTask) {
126
+ throw new Error(`AgentWrapper: testMode=true but no mockSpawnFn/taskRunner provided for agent '${config.id}'. ` +
127
+ `This would cause real Claude API calls. ABORTING.`);
128
+ }
208
129
  }
209
-
210
- /**
211
- * Validate and normalize agent configuration
212
- * @param {Object} config - Raw agent configuration
213
- * @param {Object} options - Agent wrapper options
214
- * @returns {Object} Normalized configuration
215
- */
216
130
  function validateAgentConfig(config, options = {}) {
217
- applyOutputDefaults(config);
218
-
219
- // Model configuration: support both static model and dynamic rules
220
- // If no model specified, model is null - _selectModel() will use provider defaults
221
- const modelConfig = buildModelConfig(config);
222
-
223
- // COST CEILING/FLOOR ENFORCEMENT: Validate model(s) against maxModel and minModel at config time
224
- // Catches violations EARLY (config load) instead of at runtime (iteration N)
225
- const settings = loadSettings();
226
- const maxModel = settings.maxModel;
227
- const minModel = settings.minModel || null;
228
-
229
- // STRICT SCHEMA PROPAGATION: Issue #52 fix
230
- // If agent config doesn't explicitly set strictSchema, inherit from global settings
231
- // This allows `zeroshot settings set strictSchema false` to actually affect agents
232
- // Default behavior: strictSchema=true (reliable JSON output, no streaming)
233
- applyStrictSchemaDefault(config, settings);
234
- validateModelConfig(config, modelConfig, maxModel, minModel);
235
-
236
- // Prompt configuration: support static prompt OR iteration-based rules
237
- // Formats:
238
- // prompt: "string" -> static
239
- // prompt: { system: "string" } -> static
240
- // prompt: { initial: "...", subsequent: "..." } -> iteration 1 vs 2+
241
- // prompt: { iterations: [...] } -> full control
242
- const promptConfig = buildPromptConfig(config);
243
-
244
- // Default timeout to 0 (no timeout) if not specified
245
- // Use positive number for timeout in milliseconds
246
- // ROBUST: Handle undefined, null, AND string values from template resolution
247
- normalizeTimeout(config);
248
-
249
- // Build normalized config
250
- const normalizedConfig = buildNormalizedConfig(config, modelConfig, promptConfig);
251
-
252
- // SAFETY: In test mode, verify mock is provided for agents that execute tasks
253
- // Check if this agent executes tasks (vs orchestrator agents that only publish messages)
254
- assertTestModeSafety(config, options);
255
-
256
- return normalizedConfig;
131
+ applyOutputDefaults(config);
132
+ const modelConfig = buildModelConfig(config);
133
+ const settings = loadSettings();
134
+ const minModel = settings.minModel || null;
135
+ applyStrictSchemaDefault(config, settings);
136
+ validateModelConfig(config, modelConfig, settings.maxModel, minModel);
137
+ const promptConfig = buildPromptConfig(config);
138
+ const timeout = normalizeTimeout(config);
139
+ assertTestModeSafety(config, options);
140
+ return {
141
+ ...config,
142
+ modelConfig,
143
+ promptConfig,
144
+ maxIterations: config.maxIterations || DEFAULT_MAX_ITERATIONS,
145
+ timeout,
146
+ staleDuration: config.staleDuration || DEFAULT_STALE_DURATION_MS,
147
+ enableLivenessCheck: config.enableLivenessCheck ?? DEFAULT_LIVENESS_CHECK_ENABLED,
148
+ };
257
149
  }
258
-
259
150
  module.exports = {
260
- validateAgentConfig,
261
- DEFAULT_MAX_ITERATIONS,
262
- DEFAULT_STALE_DURATION_MS,
263
- DEFAULT_LIVENESS_CHECK_ENABLED,
151
+ validateAgentConfig,
152
+ DEFAULT_MAX_ITERATIONS,
153
+ DEFAULT_STALE_DURATION_MS,
154
+ DEFAULT_LIVENESS_CHECK_ENABLED,
264
155
  };
@@ -0,0 +1,285 @@
1
+ /** Agent configuration validation and defaults. */
2
+
3
+ import qualityGateSchema = require('./agent-quality-gate-schema');
4
+ import settingsFacade = require('./agent-config-settings');
5
+
6
+ type ModelLevel = 'level1' | 'level2' | 'level3';
7
+ type JsonSchemaType = 'array' | 'boolean' | 'integer' | 'number' | 'object' | 'string';
8
+
9
+ interface JsonSchema {
10
+ type?: JsonSchemaType;
11
+ description?: string;
12
+ enum?: string[];
13
+ items?: JsonSchema;
14
+ properties?: Record<string, JsonSchema>;
15
+ required?: string[];
16
+ anyOf?: JsonSchema[];
17
+ }
18
+
19
+ interface ModelRule extends Record<string, unknown> {
20
+ iterations?: unknown;
21
+ model?: string;
22
+ modelLevel?: string;
23
+ }
24
+
25
+ interface PromptRule extends Record<string, unknown> {}
26
+
27
+ interface PromptOptions extends Record<string, unknown> {
28
+ initial?: string;
29
+ subsequent?: string;
30
+ iterations?: PromptRule[];
31
+ system?: string;
32
+ }
33
+
34
+ interface AgentTrigger extends Record<string, unknown> {
35
+ action?: string;
36
+ }
37
+
38
+ interface AgentConfig extends Record<string, unknown> {
39
+ id: string;
40
+ outputFormat?: string;
41
+ structuredOutput?: JsonSchema;
42
+ jsonSchema?: JsonSchema;
43
+ modelRules?: ModelRule[];
44
+ model?: string;
45
+ modelLevel?: string;
46
+ strictSchema?: boolean;
47
+ prompt?: string | PromptOptions | null;
48
+ timeout?: number | string | null;
49
+ maxIterations?: number;
50
+ staleDuration?: number;
51
+ enableLivenessCheck?: boolean;
52
+ triggers?: AgentTrigger[];
53
+ role?: string;
54
+ requiredQualityGates?: unknown;
55
+ hooks?: {
56
+ onComplete?: {
57
+ config?: {
58
+ content?: {
59
+ data?: {
60
+ qualityGates?: unknown;
61
+ [key: string]: unknown;
62
+ };
63
+ };
64
+ };
65
+ };
66
+ };
67
+ }
68
+
69
+ interface AgentConfigOptions extends Record<string, unknown> {
70
+ mockSpawnFn?: unknown;
71
+ taskRunner?: unknown;
72
+ testMode?: boolean;
73
+ }
74
+
75
+ type SettingsRecord = ReturnType<typeof settingsFacade.loadSettings>;
76
+
77
+ interface StaticModelConfig {
78
+ type: 'static';
79
+ model: string | null;
80
+ modelLevel: string | null;
81
+ }
82
+
83
+ interface RulesModelConfig {
84
+ type: 'rules';
85
+ rules: ModelRule[];
86
+ }
87
+
88
+ type ModelConfig = StaticModelConfig | RulesModelConfig;
89
+ type PromptConfig =
90
+ | { type: 'static'; system: string }
91
+ | { type: 'rules'; rules: PromptRule[] }
92
+ | null;
93
+
94
+ type NormalizedAgentConfig = Omit<AgentConfig, 'timeout'> & {
95
+ modelConfig: ModelConfig;
96
+ promptConfig: PromptConfig;
97
+ maxIterations: number;
98
+ timeout: number;
99
+ staleDuration: number;
100
+ enableLivenessCheck: boolean;
101
+ };
102
+
103
+ const VALID_LEVELS: readonly ModelLevel[] = ['level1', 'level2', 'level3'];
104
+ const DEFAULT_MAX_ITERATIONS = 100;
105
+ const DEFAULT_TIMEOUT = 0;
106
+ const DEFAULT_STALE_DURATION_MS = 30 * 60 * 1000;
107
+ const DEFAULT_LIVENESS_CHECK_ENABLED = false;
108
+
109
+ function isRecord(value: unknown): value is Record<string, unknown> {
110
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
111
+ }
112
+
113
+ function isModelLevel(value: string): value is ModelLevel {
114
+ return value === 'level1' || value === 'level2' || value === 'level3';
115
+ }
116
+
117
+ const { loadSettings, validateModelAgainstMax, VALID_MODELS } = settingsFacade;
118
+ const { applyValidatorQualityGateDefaults } = qualityGateSchema;
119
+
120
+ function applyOutputDefaults(config: AgentConfig): void {
121
+ if (!config.outputFormat) config.outputFormat = 'json';
122
+ if (config.structuredOutput && !config.jsonSchema) config.jsonSchema = config.structuredOutput;
123
+ if (config.outputFormat === 'json' && !config.jsonSchema) {
124
+ config.jsonSchema = {
125
+ type: 'object',
126
+ properties: {
127
+ summary: { type: 'string', description: 'Brief summary of what was done' },
128
+ result: { type: 'string', description: 'Detailed result or output' },
129
+ },
130
+ required: ['summary', 'result'],
131
+ };
132
+ }
133
+ applyValidatorQualityGateDefaults(config);
134
+ }
135
+
136
+ function buildModelConfig(config: AgentConfig): ModelConfig {
137
+ if (config.modelRules) return { type: 'rules', rules: config.modelRules };
138
+ return { type: 'static', model: config.model || null, modelLevel: config.modelLevel || null };
139
+ }
140
+
141
+ function applyStrictSchemaDefault(config: AgentConfig, settings: SettingsRecord): void {
142
+ if (config.strictSchema === undefined) config.strictSchema = settings.strictSchema !== false;
143
+ }
144
+
145
+ function errorMessage(error: unknown): unknown {
146
+ return isRecord(error) ? error.message : undefined;
147
+ }
148
+
149
+ function validateStaticModelConfig(
150
+ configId: string,
151
+ modelConfig: StaticModelConfig,
152
+ maxModel: string,
153
+ minModel: string | null
154
+ ): void {
155
+ if (modelConfig.model && VALID_MODELS.includes(modelConfig.model)) {
156
+ try {
157
+ validateModelAgainstMax(modelConfig.model, maxModel, minModel);
158
+ } catch (error: unknown) {
159
+ throw new Error(`Agent "${configId}": ${String(errorMessage(error))}`);
160
+ }
161
+ }
162
+ if (modelConfig.modelLevel && !isModelLevel(modelConfig.modelLevel)) {
163
+ throw new Error(
164
+ `Agent "${configId}": invalid modelLevel "${modelConfig.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`
165
+ );
166
+ }
167
+ }
168
+
169
+ function validateModelRule(
170
+ configId: string,
171
+ rule: ModelRule,
172
+ maxModel: string,
173
+ minModel: string | null
174
+ ): void {
175
+ if (rule.model && VALID_MODELS.includes(rule.model)) {
176
+ try {
177
+ validateModelAgainstMax(rule.model, maxModel, minModel);
178
+ } catch {
179
+ throw new Error(
180
+ `Agent "${configId}": modelRule "${String(rule.iterations)}" requests "${rule.model}" ` +
181
+ `but maxModel is "${maxModel}"${minModel ? ` and minModel is "${minModel}"` : ''}. ` +
182
+ `Either adjust the rule's model or change maxModel/minModel settings.`
183
+ );
184
+ }
185
+ }
186
+ if (rule.modelLevel && !isModelLevel(rule.modelLevel)) {
187
+ throw new Error(
188
+ `Agent "${configId}": modelRule "${String(rule.iterations)}" has invalid modelLevel ` +
189
+ `"${rule.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`
190
+ );
191
+ }
192
+ }
193
+
194
+ function validateModelConfig(
195
+ config: AgentConfig,
196
+ modelConfig: ModelConfig,
197
+ maxModel: string,
198
+ minModel: string | null
199
+ ): void {
200
+ if (modelConfig.type === 'static') {
201
+ validateStaticModelConfig(config.id, modelConfig, maxModel, minModel);
202
+ } else {
203
+ for (const rule of modelConfig.rules) validateModelRule(config.id, rule, maxModel, minModel);
204
+ }
205
+ }
206
+
207
+ function buildInitialPromptRules(prompt: PromptOptions): PromptRule[] | null {
208
+ if (!prompt.initial && !prompt.subsequent) return null;
209
+ const rules: PromptRule[] = [];
210
+ if (prompt.initial) rules.push({ match: '1', system: prompt.initial });
211
+ if (prompt.subsequent) rules.push({ match: '2+', system: prompt.subsequent });
212
+ return rules;
213
+ }
214
+
215
+ function buildPromptConfig(config: AgentConfig): PromptConfig {
216
+ const prompt = config.prompt;
217
+ if (prompt && typeof prompt !== 'string' && prompt.iterations) {
218
+ return { type: 'rules', rules: prompt.iterations };
219
+ }
220
+ if (prompt && typeof prompt !== 'string') {
221
+ const initialRules = buildInitialPromptRules(prompt);
222
+ if (initialRules) return { type: 'rules', rules: initialRules };
223
+ }
224
+ if (typeof prompt === 'string') return { type: 'static', system: prompt };
225
+ if (prompt?.system) return { type: 'static', system: prompt.system };
226
+ if (prompt) throw new Error(`Agent "${config.id}": invalid prompt format`);
227
+ return null;
228
+ }
229
+
230
+ function normalizeTimeout(config: AgentConfig): number {
231
+ const timeout =
232
+ config.timeout === undefined || config.timeout === null || config.timeout === ''
233
+ ? DEFAULT_TIMEOUT
234
+ : Number(config.timeout);
235
+ config.timeout = timeout;
236
+ if (!Number.isFinite(timeout) || timeout < 0) {
237
+ throw new Error(
238
+ `Agent "${config.id}": timeout must be a non-negative number (got ${timeout}).`
239
+ );
240
+ }
241
+ return timeout;
242
+ }
243
+
244
+ function assertTestModeSafety(config: AgentConfig, options: AgentConfigOptions): void {
245
+ const executesTask = config.triggers?.some(
246
+ (trigger) => !trigger.action || trigger.action === 'execute_task'
247
+ );
248
+ if (options.testMode && !options.mockSpawnFn && !options.taskRunner && executesTask) {
249
+ throw new Error(
250
+ `AgentWrapper: testMode=true but no mockSpawnFn/taskRunner provided for agent '${config.id}'. ` +
251
+ `This would cause real Claude API calls. ABORTING.`
252
+ );
253
+ }
254
+ }
255
+
256
+ function validateAgentConfig(
257
+ config: AgentConfig,
258
+ options: AgentConfigOptions = {}
259
+ ): NormalizedAgentConfig {
260
+ applyOutputDefaults(config);
261
+ const modelConfig = buildModelConfig(config);
262
+ const settings = loadSettings();
263
+ const minModel = settings.minModel || null;
264
+ applyStrictSchemaDefault(config, settings);
265
+ validateModelConfig(config, modelConfig, settings.maxModel, minModel);
266
+ const promptConfig = buildPromptConfig(config);
267
+ const timeout = normalizeTimeout(config);
268
+ assertTestModeSafety(config, options);
269
+ return {
270
+ ...config,
271
+ modelConfig,
272
+ promptConfig,
273
+ maxIterations: config.maxIterations || DEFAULT_MAX_ITERATIONS,
274
+ timeout,
275
+ staleDuration: config.staleDuration || DEFAULT_STALE_DURATION_MS,
276
+ enableLivenessCheck: config.enableLivenessCheck ?? DEFAULT_LIVENESS_CHECK_ENABLED,
277
+ };
278
+ }
279
+
280
+ export = {
281
+ validateAgentConfig,
282
+ DEFAULT_MAX_ITERATIONS,
283
+ DEFAULT_STALE_DURATION_MS,
284
+ DEFAULT_LIVENESS_CHECK_ENABLED,
285
+ };