@warlock.js/ai 4.3.0 → 4.5.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 (541) hide show
  1. package/CHANGELOG.md +52 -48
  2. package/cjs/index.cjs +221 -14144
  3. package/cjs/src-C02yzsLs.cjs +22991 -0
  4. package/cjs/src-C02yzsLs.cjs.map +1 -0
  5. package/cjs/src-DFibP2FQ.cjs +30 -0
  6. package/esm/agent/agent-config.type.d.mts +90 -1
  7. package/esm/agent/agent-config.type.d.mts.map +1 -1
  8. package/esm/agent/agent-input-builder.mjs +27 -6
  9. package/esm/agent/agent-input-builder.mjs.map +1 -1
  10. package/esm/agent/agent.d.mts +40 -1
  11. package/esm/agent/agent.d.mts.map +1 -1
  12. package/esm/agent/agent.mjs +203 -30
  13. package/esm/agent/agent.mjs.map +1 -1
  14. package/esm/agent/index.d.mts +2 -1
  15. package/esm/agent/index.mjs +1 -0
  16. package/esm/agent/judge-config.type.d.mts +33 -0
  17. package/esm/agent/judge-config.type.d.mts.map +1 -0
  18. package/esm/agent/judge-config.type.mjs +13 -0
  19. package/esm/agent/judge-config.type.mjs.map +1 -0
  20. package/esm/ai-openai/src/embedder.mjs +4 -0
  21. package/esm/ai-openai/src/index.mjs +4 -0
  22. package/esm/ai-openai/src/model.mjs +5 -0
  23. package/esm/ai-openai/src/sdk.mjs +6 -0
  24. package/esm/ai-openai/src/utils/index.mjs +4 -0
  25. package/esm/ai-openai/src/utils/to-openai-tools.mjs +3 -0
  26. package/esm/ai-openai/src/utils/wrap-openai-error.mjs +4 -0
  27. package/esm/ai.d.mts +119 -53
  28. package/esm/ai.d.mts.map +1 -1
  29. package/esm/ai.mjs +43 -8
  30. package/esm/ai.mjs.map +1 -1
  31. package/esm/batch/batch.d.mts.map +1 -1
  32. package/esm/batch/batch.mjs +21 -1
  33. package/esm/batch/batch.mjs.map +1 -1
  34. package/esm/batch/batch.type.d.mts +11 -4
  35. package/esm/batch/batch.type.d.mts.map +1 -1
  36. package/esm/config.d.mts +39 -3
  37. package/esm/config.d.mts.map +1 -1
  38. package/esm/config.mjs +26 -2
  39. package/esm/config.mjs.map +1 -1
  40. package/esm/contracts/agent/agent-options.type.d.mts +11 -3
  41. package/esm/contracts/agent/agent-options.type.d.mts.map +1 -1
  42. package/esm/contracts/agent/eval.type.d.mts +43 -2
  43. package/esm/contracts/agent/eval.type.d.mts.map +1 -1
  44. package/esm/contracts/attachment-policy.type.d.mts +51 -0
  45. package/esm/contracts/attachment-policy.type.d.mts.map +1 -0
  46. package/esm/contracts/attachment.type.d.mts +16 -7
  47. package/esm/contracts/attachment.type.d.mts.map +1 -1
  48. package/esm/contracts/content-part.type.d.mts +14 -5
  49. package/esm/contracts/content-part.type.d.mts.map +1 -1
  50. package/esm/contracts/events/supervisor-events.type.d.mts.map +1 -1
  51. package/esm/contracts/index.d.mts +6 -4
  52. package/esm/contracts/model.contract.d.mts +11 -8
  53. package/esm/contracts/model.contract.d.mts.map +1 -1
  54. package/esm/contracts/orchestrator/index.d.mts +1 -0
  55. package/esm/contracts/orchestrator/orchestrator-config.type.d.mts +31 -2
  56. package/esm/contracts/orchestrator/orchestrator-config.type.d.mts.map +1 -1
  57. package/esm/contracts/orchestrator/session-lock.contract.d.mts +47 -0
  58. package/esm/contracts/orchestrator/session-lock.contract.d.mts.map +1 -0
  59. package/esm/contracts/planner/index.d.mts +1 -1
  60. package/esm/contracts/planner/planner-config.type.d.mts +31 -0
  61. package/esm/contracts/planner/planner-config.type.d.mts.map +1 -1
  62. package/esm/contracts/planner/planner-execute-options.type.d.mts +48 -1
  63. package/esm/contracts/planner/planner-execute-options.type.d.mts.map +1 -1
  64. package/esm/contracts/planner/planner-result.type.d.mts +19 -5
  65. package/esm/contracts/planner/planner-result.type.d.mts.map +1 -1
  66. package/esm/contracts/planner/planner.contract.d.mts +1 -1
  67. package/esm/contracts/result/agent-result.type.d.mts +6 -4
  68. package/esm/contracts/result/agent-result.type.d.mts.map +1 -1
  69. package/esm/contracts/result/base-report.type.d.mts +21 -3
  70. package/esm/contracts/result/base-report.type.d.mts.map +1 -1
  71. package/esm/contracts/result/base-report.type.mjs.map +1 -1
  72. package/esm/contracts/result/execution-report.type.d.mts +53 -1
  73. package/esm/contracts/result/execution-report.type.d.mts.map +1 -1
  74. package/esm/contracts/result/orchestrator-result.type.d.mts +15 -11
  75. package/esm/contracts/result/orchestrator-result.type.d.mts.map +1 -1
  76. package/esm/contracts/result/supervisor-result.type.d.mts +13 -1
  77. package/esm/contracts/result/supervisor-result.type.d.mts.map +1 -1
  78. package/esm/contracts/result/tool-call.type.d.mts +2 -2
  79. package/esm/contracts/result/tool-call.type.d.mts.map +1 -1
  80. package/esm/contracts/result/workflow-result.type.d.mts +1 -0
  81. package/esm/contracts/result/workflow-result.type.d.mts.map +1 -1
  82. package/esm/contracts/supervisor/supervisor-config.type.d.mts +29 -0
  83. package/esm/contracts/supervisor/supervisor-config.type.d.mts.map +1 -1
  84. package/esm/contracts/system-prompt.contract.d.mts +103 -1
  85. package/esm/contracts/system-prompt.contract.d.mts.map +1 -1
  86. package/esm/contracts/team/index.d.mts +1 -0
  87. package/esm/contracts/team/team-config.type.d.mts +127 -0
  88. package/esm/contracts/team/team-config.type.d.mts.map +1 -0
  89. package/esm/contracts/tool.contract.d.mts +4 -2
  90. package/esm/contracts/tool.contract.d.mts.map +1 -1
  91. package/esm/contracts/workflow/step.contract.d.mts +30 -5
  92. package/esm/contracts/workflow/step.contract.d.mts.map +1 -1
  93. package/esm/contracts/workflow/workflow.contract.d.mts +16 -0
  94. package/esm/contracts/workflow/workflow.contract.d.mts.map +1 -1
  95. package/esm/errors/error-code.type.d.mts +1 -1
  96. package/esm/errors/index.d.mts +1 -0
  97. package/esm/errors/index.mjs +1 -0
  98. package/esm/errors/outbound-policy-error.d.mts +27 -0
  99. package/esm/errors/outbound-policy-error.d.mts.map +1 -0
  100. package/esm/errors/outbound-policy-error.mjs +32 -0
  101. package/esm/errors/outbound-policy-error.mjs.map +1 -0
  102. package/esm/eval/dataset.d.mts +28 -0
  103. package/esm/eval/dataset.d.mts.map +1 -0
  104. package/esm/eval/dataset.mjs +112 -0
  105. package/esm/eval/dataset.mjs.map +1 -0
  106. package/esm/eval/dataset.type.d.mts +53 -0
  107. package/esm/eval/dataset.type.d.mts.map +1 -0
  108. package/esm/eval/eval-runner.d.mts.map +1 -1
  109. package/esm/eval/eval-runner.mjs +16 -2
  110. package/esm/eval/eval-runner.mjs.map +1 -1
  111. package/esm/eval/index.d.mts +20 -1
  112. package/esm/eval/index.d.mts.map +1 -1
  113. package/esm/eval/index.mjs +20 -2
  114. package/esm/eval/index.mjs.map +1 -1
  115. package/esm/eval/regression.d.mts +30 -0
  116. package/esm/eval/regression.d.mts.map +1 -0
  117. package/esm/eval/regression.mjs +51 -0
  118. package/esm/eval/regression.mjs.map +1 -0
  119. package/esm/eval/report-json.d.mts +30 -0
  120. package/esm/eval/report-json.d.mts.map +1 -0
  121. package/esm/eval/report-json.mjs +33 -0
  122. package/esm/eval/report-json.mjs.map +1 -0
  123. package/esm/eval/report-junit.d.mts +22 -0
  124. package/esm/eval/report-junit.d.mts.map +1 -0
  125. package/esm/eval/report-junit.mjs +60 -0
  126. package/esm/eval/report-junit.mjs.map +1 -0
  127. package/esm/guard/contracts/guard-options.type.d.mts +165 -0
  128. package/esm/guard/contracts/guard-options.type.d.mts.map +1 -0
  129. package/esm/guard/contracts/guardrail.contract.d.mts +78 -0
  130. package/esm/guard/contracts/guardrail.contract.d.mts.map +1 -0
  131. package/esm/guard/contracts/index.d.mts +4 -0
  132. package/esm/guard/contracts/openai-client.contract.d.mts +51 -0
  133. package/esm/guard/contracts/openai-client.contract.d.mts.map +1 -0
  134. package/esm/guard/contracts/verdict.type.d.mts +76 -0
  135. package/esm/guard/contracts/verdict.type.d.mts.map +1 -0
  136. package/esm/guard/detectors/index.d.mts +4 -0
  137. package/esm/guard/detectors/index.mjs +6 -0
  138. package/esm/guard/detectors/injection.d.mts +34 -0
  139. package/esm/guard/detectors/injection.d.mts.map +1 -0
  140. package/esm/guard/detectors/injection.mjs +254 -0
  141. package/esm/guard/detectors/injection.mjs.map +1 -0
  142. package/esm/guard/detectors/moderation.d.mts +32 -0
  143. package/esm/guard/detectors/moderation.d.mts.map +1 -0
  144. package/esm/guard/detectors/moderation.mjs +134 -0
  145. package/esm/guard/detectors/moderation.mjs.map +1 -0
  146. package/esm/guard/detectors/pii.d.mts +41 -0
  147. package/esm/guard/detectors/pii.d.mts.map +1 -0
  148. package/esm/guard/detectors/pii.mjs +199 -0
  149. package/esm/guard/detectors/pii.mjs.map +1 -0
  150. package/esm/guard/detectors/topic.d.mts +29 -0
  151. package/esm/guard/detectors/topic.d.mts.map +1 -0
  152. package/esm/guard/detectors/topic.mjs +99 -0
  153. package/esm/guard/detectors/topic.mjs.map +1 -0
  154. package/esm/guard/errors.d.mts +12 -0
  155. package/esm/guard/errors.d.mts.map +1 -0
  156. package/esm/guard/errors.mjs +18 -0
  157. package/esm/guard/errors.mjs.map +1 -0
  158. package/esm/guard/guard.d.mts +67 -0
  159. package/esm/guard/guard.d.mts.map +1 -0
  160. package/esm/guard/guard.mjs +209 -0
  161. package/esm/guard/guard.mjs.map +1 -0
  162. package/esm/guard/guardrail.d.mts +39 -0
  163. package/esm/guard/guardrail.d.mts.map +1 -0
  164. package/esm/guard/guardrail.mjs +22 -0
  165. package/esm/guard/guardrail.mjs.map +1 -0
  166. package/esm/human/contracts/approval.type.d.mts +154 -0
  167. package/esm/human/contracts/approval.type.d.mts.map +1 -0
  168. package/esm/human/contracts/human-approval.type.d.mts +38 -0
  169. package/esm/human/contracts/human-approval.type.d.mts.map +1 -0
  170. package/esm/human/contracts/index.d.mts +4 -0
  171. package/esm/human/contracts/interrupt-store.contract.d.mts +112 -0
  172. package/esm/human/contracts/interrupt-store.contract.d.mts.map +1 -0
  173. package/esm/human/contracts/resume.type.d.mts +77 -0
  174. package/esm/human/contracts/resume.type.d.mts.map +1 -0
  175. package/esm/human/errors.d.mts +84 -0
  176. package/esm/human/errors.d.mts.map +1 -0
  177. package/esm/human/errors.mjs +60 -0
  178. package/esm/human/errors.mjs.map +1 -0
  179. package/esm/human/human-approval.d.mts +57 -0
  180. package/esm/human/human-approval.d.mts.map +1 -0
  181. package/esm/human/human-approval.mjs +170 -0
  182. package/esm/human/human-approval.mjs.map +1 -0
  183. package/esm/human/policy.d.mts +55 -0
  184. package/esm/human/policy.d.mts.map +1 -0
  185. package/esm/human/policy.mjs +67 -0
  186. package/esm/human/policy.mjs.map +1 -0
  187. package/esm/human/register.mjs +37 -0
  188. package/esm/human/register.mjs.map +1 -0
  189. package/esm/human/resume-seed.mjs +53 -0
  190. package/esm/human/resume-seed.mjs.map +1 -0
  191. package/esm/human/resume.d.mts +54 -0
  192. package/esm/human/resume.d.mts.map +1 -0
  193. package/esm/human/resume.mjs +121 -0
  194. package/esm/human/resume.mjs.map +1 -0
  195. package/esm/human/stores/index.mjs +5 -0
  196. package/esm/human/stores/memory.d.mts +30 -0
  197. package/esm/human/stores/memory.d.mts.map +1 -0
  198. package/esm/human/stores/memory.mjs +91 -0
  199. package/esm/human/stores/memory.mjs.map +1 -0
  200. package/esm/human/stores/pg.d.mts +59 -0
  201. package/esm/human/stores/pg.d.mts.map +1 -0
  202. package/esm/human/stores/pg.mjs +220 -0
  203. package/esm/human/stores/pg.mjs.map +1 -0
  204. package/esm/human/stores/redis.d.mts +56 -0
  205. package/esm/human/stores/redis.d.mts.map +1 -0
  206. package/esm/human/stores/redis.mjs +201 -0
  207. package/esm/human/stores/redis.mjs.map +1 -0
  208. package/esm/index.d.mts +113 -22
  209. package/esm/index.mjs +82 -11
  210. package/esm/middleware/builtins/budget.mjs +6 -2
  211. package/esm/middleware/builtins/budget.mjs.map +1 -1
  212. package/esm/middleware/utils/extract-user-text.d.mts +8 -1
  213. package/esm/middleware/utils/extract-user-text.d.mts.map +1 -1
  214. package/esm/middleware/utils/extract-user-text.mjs +8 -1
  215. package/esm/middleware/utils/extract-user-text.mjs.map +1 -1
  216. package/esm/object-stream/index.d.mts +2 -0
  217. package/esm/object-stream/index.mjs +4 -0
  218. package/esm/object-stream/parse-partial-json.d.mts +22 -0
  219. package/esm/object-stream/parse-partial-json.d.mts.map +1 -0
  220. package/esm/object-stream/parse-partial-json.mjs +78 -0
  221. package/esm/object-stream/parse-partial-json.mjs.map +1 -0
  222. package/esm/object-stream/stream-object.d.mts +68 -0
  223. package/esm/object-stream/stream-object.d.mts.map +1 -0
  224. package/esm/object-stream/stream-object.mjs +104 -0
  225. package/esm/object-stream/stream-object.mjs.map +1 -0
  226. package/esm/observe/index.mjs +4 -0
  227. package/esm/observe/observer-registry.d.mts +30 -0
  228. package/esm/observe/observer-registry.d.mts.map +1 -0
  229. package/esm/observe/observer-registry.mjs +51 -0
  230. package/esm/observe/observer-registry.mjs.map +1 -0
  231. package/esm/observe/observer.contract.d.mts +40 -0
  232. package/esm/observe/observer.contract.d.mts.map +1 -0
  233. package/esm/observe/resolve-observers.d.mts +40 -0
  234. package/esm/observe/resolve-observers.d.mts.map +1 -0
  235. package/esm/observe/resolve-observers.mjs +73 -0
  236. package/esm/observe/resolve-observers.mjs.map +1 -0
  237. package/esm/orchestrator/execution.d.mts.map +1 -1
  238. package/esm/orchestrator/execution.mjs +5 -2
  239. package/esm/orchestrator/execution.mjs.map +1 -1
  240. package/esm/orchestrator/index.d.mts +1 -0
  241. package/esm/orchestrator/index.mjs +1 -0
  242. package/esm/orchestrator/orchestrator.d.mts.map +1 -1
  243. package/esm/orchestrator/orchestrator.mjs +39 -6
  244. package/esm/orchestrator/orchestrator.mjs.map +1 -1
  245. package/esm/orchestrator/session-lock.d.mts +25 -0
  246. package/esm/orchestrator/session-lock.d.mts.map +1 -0
  247. package/esm/orchestrator/session-lock.mjs +83 -0
  248. package/esm/orchestrator/session-lock.mjs.map +1 -0
  249. package/esm/planner/dag-scheduler.mjs +97 -0
  250. package/esm/planner/dag-scheduler.mjs.map +1 -0
  251. package/esm/planner/plan-prompt.d.mts +1 -1
  252. package/esm/planner/plan-prompt.d.mts.map +1 -1
  253. package/esm/planner/plan-prompt.mjs +2 -1
  254. package/esm/planner/plan-prompt.mjs.map +1 -1
  255. package/esm/planner/plan-schema.mjs +17 -14
  256. package/esm/planner/plan-schema.mjs.map +1 -1
  257. package/esm/planner/planner-run.d.mts.map +1 -1
  258. package/esm/planner/planner-run.mjs +300 -29
  259. package/esm/planner/planner-run.mjs.map +1 -1
  260. package/esm/planner/planner.mjs +1 -1
  261. package/esm/planner/planner.mjs.map +1 -1
  262. package/esm/prompt/errors.d.mts +57 -0
  263. package/esm/prompt/errors.d.mts.map +1 -0
  264. package/esm/prompt/errors.mjs +73 -0
  265. package/esm/prompt/errors.mjs.map +1 -0
  266. package/esm/prompt/index.d.mts +3 -0
  267. package/esm/prompt/index.mjs +4 -0
  268. package/esm/prompt/prompt-langfuse-sync.mjs +104 -0
  269. package/esm/prompt/prompt-langfuse-sync.mjs.map +1 -0
  270. package/esm/prompt/prompt-langfuse-sync.type.d.mts +32 -0
  271. package/esm/prompt/prompt-langfuse-sync.type.d.mts.map +1 -0
  272. package/esm/prompt/prompt-validate.mjs +170 -0
  273. package/esm/prompt/prompt-validate.mjs.map +1 -0
  274. package/esm/prompt/prompt.d.mts +54 -0
  275. package/esm/prompt/prompt.d.mts.map +1 -0
  276. package/esm/prompt/prompt.mjs +218 -0
  277. package/esm/prompt/prompt.mjs.map +1 -0
  278. package/esm/prompt/prompt.type.d.mts +174 -0
  279. package/esm/prompt/prompt.type.d.mts.map +1 -0
  280. package/esm/prompts/index.d.mts +3 -0
  281. package/esm/prompts/index.mjs +3 -0
  282. package/esm/prompts/prompts-manager.contract.d.mts +154 -0
  283. package/esm/prompts/prompts-manager.contract.d.mts.map +1 -0
  284. package/esm/prompts/prompts-manager.d.mts +38 -0
  285. package/esm/prompts/prompts-manager.d.mts.map +1 -0
  286. package/esm/prompts/prompts-manager.mjs +410 -0
  287. package/esm/prompts/prompts-manager.mjs.map +1 -0
  288. package/esm/prompts/prompts-manager.type.d.mts +172 -0
  289. package/esm/prompts/prompts-manager.type.d.mts.map +1 -0
  290. package/esm/prompts/prompts-validate.mjs +200 -0
  291. package/esm/prompts/prompts-validate.mjs.map +1 -0
  292. package/esm/rag/as-tool.mjs +48 -0
  293. package/esm/rag/as-tool.mjs.map +1 -0
  294. package/esm/rag/chunk/chunk.d.mts +24 -0
  295. package/esm/rag/chunk/chunk.d.mts.map +1 -0
  296. package/esm/rag/chunk/chunk.mjs +44 -0
  297. package/esm/rag/chunk/chunk.mjs.map +1 -0
  298. package/esm/rag/chunk/fixed.mjs +32 -0
  299. package/esm/rag/chunk/fixed.mjs.map +1 -0
  300. package/esm/rag/chunk/markdown.mjs +75 -0
  301. package/esm/rag/chunk/markdown.mjs.map +1 -0
  302. package/esm/rag/chunk/recursive.mjs +132 -0
  303. package/esm/rag/chunk/recursive.mjs.map +1 -0
  304. package/esm/rag/chunk/sentence.mjs +73 -0
  305. package/esm/rag/chunk/sentence.mjs.map +1 -0
  306. package/esm/rag/contracts/chunk-options.type.d.mts +35 -0
  307. package/esm/rag/contracts/chunk-options.type.d.mts.map +1 -0
  308. package/esm/rag/contracts/citation.type.d.mts +35 -0
  309. package/esm/rag/contracts/citation.type.d.mts.map +1 -0
  310. package/esm/rag/contracts/index.d.mts +4 -0
  311. package/esm/rag/contracts/rag-config.type.d.mts +68 -0
  312. package/esm/rag/contracts/rag-config.type.d.mts.map +1 -0
  313. package/esm/rag/contracts/rag-document.type.d.mts +21 -0
  314. package/esm/rag/contracts/rag-document.type.d.mts.map +1 -0
  315. package/esm/rag/hybrid/bm25.d.mts +23 -0
  316. package/esm/rag/hybrid/bm25.d.mts.map +1 -0
  317. package/esm/rag/hybrid/bm25.mjs +51 -0
  318. package/esm/rag/hybrid/bm25.mjs.map +1 -0
  319. package/esm/rag/hybrid/hybrid-rank.d.mts +33 -0
  320. package/esm/rag/hybrid/hybrid-rank.d.mts.map +1 -0
  321. package/esm/rag/hybrid/hybrid-rank.mjs +29 -0
  322. package/esm/rag/hybrid/hybrid-rank.mjs.map +1 -0
  323. package/esm/rag/hybrid/rrf.d.mts +25 -0
  324. package/esm/rag/hybrid/rrf.d.mts.map +1 -0
  325. package/esm/rag/hybrid/rrf.mjs +30 -0
  326. package/esm/rag/hybrid/rrf.mjs.map +1 -0
  327. package/esm/rag/index.d.mts +15 -0
  328. package/esm/rag/index.mjs +11 -0
  329. package/esm/rag/rag.d.mts +38 -0
  330. package/esm/rag/rag.d.mts.map +1 -0
  331. package/esm/rag/rag.mjs +126 -0
  332. package/esm/rag/rag.mjs.map +1 -0
  333. package/esm/rag/rerank/keyword-reranker.d.mts +32 -0
  334. package/esm/rag/rerank/keyword-reranker.d.mts.map +1 -0
  335. package/esm/rag/rerank/keyword-reranker.mjs +58 -0
  336. package/esm/rag/rerank/keyword-reranker.mjs.map +1 -0
  337. package/esm/rag/rerank/llm-reranker.d.mts +36 -0
  338. package/esm/rag/rerank/llm-reranker.d.mts.map +1 -0
  339. package/esm/rag/rerank/llm-reranker.mjs +85 -0
  340. package/esm/rag/rerank/llm-reranker.mjs.map +1 -0
  341. package/esm/rag/rerank/reranker.contract.d.mts +28 -0
  342. package/esm/rag/rerank/reranker.contract.d.mts.map +1 -0
  343. package/esm/rag/retrieve.mjs +68 -0
  344. package/esm/rag/retrieve.mjs.map +1 -0
  345. package/esm/rag/store/cache-vector-store.d.mts +27 -0
  346. package/esm/rag/store/cache-vector-store.d.mts.map +1 -0
  347. package/esm/rag/store/cache-vector-store.mjs +48 -0
  348. package/esm/rag/store/cache-vector-store.mjs.map +1 -0
  349. package/esm/rag/store/vector-store.contract.d.mts +38 -0
  350. package/esm/rag/store/vector-store.contract.d.mts.map +1 -0
  351. package/esm/rag/transforms/multi-query.d.mts +27 -0
  352. package/esm/rag/transforms/multi-query.d.mts.map +1 -0
  353. package/esm/rag/transforms/multi-query.mjs +41 -0
  354. package/esm/rag/transforms/multi-query.mjs.map +1 -0
  355. package/esm/security/index.mjs +5 -0
  356. package/esm/security/outbound-policy.d.mts +46 -0
  357. package/esm/security/outbound-policy.d.mts.map +1 -0
  358. package/esm/security/outbound-policy.mjs +187 -0
  359. package/esm/security/outbound-policy.mjs.map +1 -0
  360. package/esm/security/outbound-policy.type.d.mts +74 -0
  361. package/esm/security/outbound-policy.type.d.mts.map +1 -0
  362. package/esm/security/private-ip.d.mts +15 -0
  363. package/esm/security/private-ip.d.mts.map +1 -0
  364. package/esm/security/private-ip.mjs +48 -0
  365. package/esm/security/private-ip.mjs.map +1 -0
  366. package/esm/security/redact.d.mts +59 -0
  367. package/esm/security/redact.d.mts.map +1 -0
  368. package/esm/security/redact.mjs +122 -0
  369. package/esm/security/redact.mjs.map +1 -0
  370. package/esm/serve/serve.d.mts +50 -0
  371. package/esm/serve/serve.d.mts.map +1 -0
  372. package/esm/serve/serve.mjs +90 -0
  373. package/esm/serve/serve.mjs.map +1 -0
  374. package/esm/serve/sse.d.mts +20 -0
  375. package/esm/serve/sse.d.mts.map +1 -0
  376. package/esm/serve/sse.mjs +25 -0
  377. package/esm/serve/sse.mjs.map +1 -0
  378. package/esm/serve/stream-to-sse.d.mts +29 -0
  379. package/esm/serve/stream-to-sse.d.mts.map +1 -0
  380. package/esm/serve/stream-to-sse.mjs +37 -0
  381. package/esm/serve/stream-to-sse.mjs.map +1 -0
  382. package/esm/skills/catalog.d.mts +49 -0
  383. package/esm/skills/catalog.d.mts.map +1 -0
  384. package/esm/skills/catalog.mjs +140 -0
  385. package/esm/skills/catalog.mjs.map +1 -0
  386. package/esm/skills/contracts/skill-record.type.d.mts +37 -0
  387. package/esm/skills/contracts/skill-record.type.d.mts.map +1 -0
  388. package/esm/skills/contracts/skills-config.type.d.mts +108 -0
  389. package/esm/skills/contracts/skills-config.type.d.mts.map +1 -0
  390. package/esm/skills/contracts/skills-store.contract.d.mts +28 -0
  391. package/esm/skills/contracts/skills-store.contract.d.mts.map +1 -0
  392. package/esm/skills/contracts/skills.contract.d.mts +43 -0
  393. package/esm/skills/contracts/skills.contract.d.mts.map +1 -0
  394. package/esm/skills/index.d.mts +16 -0
  395. package/esm/skills/index.mjs +14 -0
  396. package/esm/skills/load-skill-tool.d.mts +38 -0
  397. package/esm/skills/load-skill-tool.d.mts.map +1 -0
  398. package/esm/skills/load-skill-tool.mjs +65 -0
  399. package/esm/skills/load-skill-tool.mjs.map +1 -0
  400. package/esm/skills/review-gate.d.mts +33 -0
  401. package/esm/skills/review-gate.d.mts.map +1 -0
  402. package/esm/skills/review-gate.mjs +60 -0
  403. package/esm/skills/review-gate.mjs.map +1 -0
  404. package/esm/skills/save-skill-tool.d.mts +39 -0
  405. package/esm/skills/save-skill-tool.d.mts.map +1 -0
  406. package/esm/skills/save-skill-tool.mjs +65 -0
  407. package/esm/skills/save-skill-tool.mjs.map +1 -0
  408. package/esm/skills/skills.d.mts +33 -0
  409. package/esm/skills/skills.d.mts.map +1 -0
  410. package/esm/skills/skills.mjs +109 -0
  411. package/esm/skills/skills.mjs.map +1 -0
  412. package/esm/skills/sources/directory-source.d.mts +19 -0
  413. package/esm/skills/sources/directory-source.d.mts.map +1 -0
  414. package/esm/skills/sources/directory-source.mjs +108 -0
  415. package/esm/skills/sources/directory-source.mjs.map +1 -0
  416. package/esm/skills/sources/index.d.mts +18 -0
  417. package/esm/skills/sources/index.d.mts.map +1 -0
  418. package/esm/skills/sources/index.mjs +27 -0
  419. package/esm/skills/sources/index.mjs.map +1 -0
  420. package/esm/skills/sources/parse-frontmatter.d.mts +27 -0
  421. package/esm/skills/sources/parse-frontmatter.d.mts.map +1 -0
  422. package/esm/skills/sources/parse-frontmatter.mjs +46 -0
  423. package/esm/skills/sources/parse-frontmatter.mjs.map +1 -0
  424. package/esm/skills/sources/store-source.d.mts +14 -0
  425. package/esm/skills/sources/store-source.d.mts.map +1 -0
  426. package/esm/skills/sources/store-source.mjs +15 -0
  427. package/esm/skills/sources/store-source.mjs.map +1 -0
  428. package/esm/skills/sources/url-source.d.mts +29 -0
  429. package/esm/skills/sources/url-source.d.mts.map +1 -0
  430. package/esm/skills/sources/url-source.mjs +117 -0
  431. package/esm/skills/sources/url-source.mjs.map +1 -0
  432. package/esm/skills/store/mock-skills-store.d.mts +57 -0
  433. package/esm/skills/store/mock-skills-store.d.mts.map +1 -0
  434. package/esm/skills/store/mock-skills-store.mjs +100 -0
  435. package/esm/skills/store/mock-skills-store.mjs.map +1 -0
  436. package/esm/skills/store/procedural-skill-store.d.mts +30 -0
  437. package/esm/skills/store/procedural-skill-store.d.mts.map +1 -0
  438. package/esm/skills/store/procedural-skill-store.mjs +125 -0
  439. package/esm/skills/store/procedural-skill-store.mjs.map +1 -0
  440. package/esm/supervisor/as-tool.mjs +2 -2
  441. package/esm/supervisor/as-tool.mjs.map +1 -1
  442. package/esm/supervisor/execution.d.mts.map +1 -1
  443. package/esm/supervisor/execution.mjs +31 -28
  444. package/esm/supervisor/execution.mjs.map +1 -1
  445. package/esm/supervisor/supervisor.d.mts.map +1 -1
  446. package/esm/supervisor/supervisor.mjs +8 -3
  447. package/esm/supervisor/supervisor.mjs.map +1 -1
  448. package/esm/system-prompt/index.d.mts +4 -0
  449. package/esm/system-prompt/system-prompt.d.mts +68 -4
  450. package/esm/system-prompt/system-prompt.d.mts.map +1 -1
  451. package/esm/system-prompt/system-prompt.mjs +89 -5
  452. package/esm/system-prompt/system-prompt.mjs.map +1 -1
  453. package/esm/team/gates.mjs +48 -0
  454. package/esm/team/gates.mjs.map +1 -0
  455. package/esm/team/index.d.mts +1 -0
  456. package/esm/team/index.mjs +3 -0
  457. package/esm/team/team.d.mts +42 -0
  458. package/esm/team/team.d.mts.map +1 -0
  459. package/esm/team/team.mjs +94 -0
  460. package/esm/team/team.mjs.map +1 -0
  461. package/esm/tool/executable-as-tool.d.mts.map +1 -1
  462. package/esm/tool/executable-as-tool.mjs +2 -2
  463. package/esm/tool/executable-as-tool.mjs.map +1 -1
  464. package/esm/tool/tool.d.mts.map +1 -1
  465. package/esm/tool/tool.mjs +2 -2
  466. package/esm/tool/tool.mjs.map +1 -1
  467. package/esm/utils/compute-cost.d.mts +17 -1
  468. package/esm/utils/compute-cost.d.mts.map +1 -1
  469. package/esm/utils/compute-cost.mjs +26 -1
  470. package/esm/utils/compute-cost.mjs.map +1 -1
  471. package/esm/utils/extract-json-lenient.d.mts +42 -0
  472. package/esm/utils/extract-json-lenient.d.mts.map +1 -0
  473. package/esm/utils/extract-json-lenient.mjs +97 -0
  474. package/esm/utils/extract-json-lenient.mjs.map +1 -0
  475. package/esm/utils/index.d.mts +4 -2
  476. package/esm/utils/index.mjs +3 -1
  477. package/esm/utils/json-schema.d.mts +1 -1
  478. package/esm/utils/prepare-attachment-part.d.mts +10 -1
  479. package/esm/utils/prepare-attachment-part.d.mts.map +1 -1
  480. package/esm/utils/prepare-attachment-part.mjs +103 -11
  481. package/esm/utils/prepare-attachment-part.mjs.map +1 -1
  482. package/esm/utils/resolve-attachment.d.mts +4 -3
  483. package/esm/utils/resolve-attachment.d.mts.map +1 -1
  484. package/esm/utils/resolve-attachment.mjs +4 -3
  485. package/esm/utils/resolve-attachment.mjs.map +1 -1
  486. package/esm/utils/run-context.d.mts +94 -0
  487. package/esm/utils/run-context.d.mts.map +1 -0
  488. package/esm/utils/run-context.mjs +98 -0
  489. package/esm/utils/run-context.mjs.map +1 -0
  490. package/esm/vcr/cassette-io.mjs +57 -0
  491. package/esm/vcr/cassette-io.mjs.map +1 -0
  492. package/esm/vcr/errors.d.mts +42 -0
  493. package/esm/vcr/errors.d.mts.map +1 -0
  494. package/esm/vcr/errors.mjs +37 -0
  495. package/esm/vcr/errors.mjs.map +1 -0
  496. package/esm/vcr/hash-request.d.mts +28 -0
  497. package/esm/vcr/hash-request.d.mts.map +1 -0
  498. package/esm/vcr/hash-request.mjs +118 -0
  499. package/esm/vcr/hash-request.mjs.map +1 -0
  500. package/esm/vcr/index.d.mts +4 -0
  501. package/esm/vcr/index.mjs +5 -0
  502. package/esm/vcr/vcr.d.mts +32 -0
  503. package/esm/vcr/vcr.d.mts.map +1 -0
  504. package/esm/vcr/vcr.mjs +248 -0
  505. package/esm/vcr/vcr.mjs.map +1 -0
  506. package/esm/vcr/vcr.type.d.mts +118 -0
  507. package/esm/vcr/vcr.type.d.mts.map +1 -0
  508. package/esm/workflow/as-tool.mjs +2 -2
  509. package/esm/workflow/as-tool.mjs.map +1 -1
  510. package/esm/workflow/engine.mjs +1 -0
  511. package/esm/workflow/engine.mjs.map +1 -1
  512. package/esm/workflow/step-runner.mjs +19 -20
  513. package/esm/workflow/step-runner.mjs.map +1 -1
  514. package/esm/workflow/workflow.d.mts.map +1 -1
  515. package/esm/workflow/workflow.mjs +8 -3
  516. package/esm/workflow/workflow.mjs.map +1 -1
  517. package/llms-full.txt +1683 -68
  518. package/llms.txt +16 -4
  519. package/package.json +7 -3
  520. package/skills/README.md +40 -4
  521. package/skills/ai-dx-helpers/SKILL.md +2 -2
  522. package/skills/approve-tool-calls/SKILL.md +134 -0
  523. package/skills/attach-ai-middleware/SKILL.md +1 -1
  524. package/skills/detect-and-redact-pii/SKILL.md +104 -0
  525. package/skills/durable-resume/SKILL.md +128 -0
  526. package/skills/escalate-block-to-human/SKILL.md +85 -0
  527. package/skills/eval-datasets-and-ci/SKILL.md +117 -0
  528. package/skills/guard-input-output/SKILL.md +117 -0
  529. package/skills/manage-prompts/SKILL.md +186 -0
  530. package/skills/observe-ai-flows/SKILL.md +94 -0
  531. package/skills/record-replay-llm/SKILL.md +92 -0
  532. package/skills/run-ai-agent/SKILL.md +26 -1
  533. package/skills/run-ai-rag/SKILL.md +139 -0
  534. package/skills/run-ai-team/SKILL.md +107 -0
  535. package/skills/run-orchestrator/SKILL.md +2 -0
  536. package/skills/run-planner/SKILL.md +73 -8
  537. package/skills/run-supervisor/SKILL.md +20 -1
  538. package/skills/use-runtime-skills/SKILL.md +106 -0
  539. package/skills/write-system-prompt/SKILL.md +30 -1
  540. package/cjs/index.cjs.map +0 -1
  541. package/esm/contracts/result/index.d.mts +0 -15
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: observe-ai-flows
3
+ description: 'The core Observer seam — a generic, tool-agnostic observability hook every flow routes its completed ExecutionReport through. Covers the per-flow `observe?: boolean | Observer` option on ai.agent / workflow / supervisor / team, the global registry (registerObserver / getObservers / setObserveAll / isObserveAll / clearObservers), resolveObservers / notifyObservers resolution, the opt-in AgentConfig.captureMessages → AgentReport.messages full-history capture, the onConfigApplied dependency-inversion seam, and that @warlock.js/ai-panoptic is the batteries-included Observer. Triggers: `Observer`, `observe`, `registerObserver`, `getObservers`, `setObserveAll`, `isObserveAll`, `clearObservers`, `resolveObservers`, `notifyObservers`, `FlowObserveOption`, `ExecutionReport`, `captureMessages`, `AgentReport.messages`, `CapturedMessage`, `onConfigApplied`, `observeAll`; ''observe an agent run'', ''send finished reports to a collector'', ''capture the full message history'', ''observe every flow by default'', ''wire panoptic / tracing''; typical import `import { ai, registerObserver } from "@warlock.js/ai"`. Skip: structured logging of events — `@warlock.js/ai/log-ai-calls/SKILL.md`; reading the report tree shape (trips / children) — `@warlock.js/ai/run-ai-agent/SKILL.md`; per-call cost / usage rollup — `@warlock.js/ai/handle-ai-errors/SKILL.md`. The batteries-included Observer is the `@warlock.js/ai-panoptic` package.'
4
+ ---
5
+
6
+ # The `Observer` seam — generic, tool-agnostic observability
7
+
8
+ Core defines a structural `Observer` and a tiny registry; it never imports any observability package (panoptic, OTel, Langfuse, …). A flow that resolves to "observed" hands its completed `ExecutionReport` to every registered observer. An observability tool **implements `Observer` and registers itself**, so `observe: true` / observe-all route reports without coupling core to the tool — the dependency inversion that keeps the two sides decoupled.
9
+
10
+ ```ts
11
+ export interface Observer {
12
+ collect(report: ExecutionReport): void | Promise<void>;
13
+ }
14
+ ```
15
+
16
+ `collect` may be sync or async — the flow awaits it. A throw is **swallowed** by the flow (never breaks the run), mirroring the existing `onUsage` / `onComplete` hooks.
17
+
18
+ ## Per-flow `observe` option
19
+
20
+ `observe?: boolean | Observer` (`FlowObserveOption`) is accepted on **`ai.agent`, `ai.workflow`, `ai.supervisor`, and `ai.team`** (a team forwards it verbatim to the supervisor it desugars into):
21
+
22
+ ```ts
23
+ const collector: Observer = { collect(report) { exporter.send(report); } };
24
+
25
+ ai.agent({ model, observe: true }); // → the globally registered observers, even if observe-all is off
26
+ ai.agent({ model, observe: false }); // → opt out entirely, even when observe-all is on
27
+ ai.agent({ model, observe: collector }); // → a flow-LOCAL collector; only this flow's report, only to it
28
+ ai.agent({ model }); // → undefined: follow the global observe-all flag
29
+ ```
30
+
31
+ Resolution (`resolveObservers(observe)`):
32
+
33
+ - `false` → `[]` (opted out).
34
+ - `true` → the globally registered observers.
35
+ - an `Observer` object → just that one (flow-local; the global observers are skipped).
36
+ - `undefined` → the global observers when observe-all is on, otherwise `[]`.
37
+
38
+ `notifyObservers(observe, report)` routes a completed report to each resolved observer, awaiting each `collect` (so async exporters finish before the flow returns) and swallowing any throw. The object form is typed as the structural `Observer` (NOT a panoptic-specific type), so a panoptic flow-local collector — which implements `Observer` — can be passed directly.
39
+
40
+ ## The global registry
41
+
42
+ ```ts
43
+ import {
44
+ registerObserver, getObservers, setObserveAll, isObserveAll, clearObservers,
45
+ } from "@warlock.js/ai";
46
+
47
+ registerObserver(collector); // an observability tool registers ONE collector when its config is applied
48
+ getObservers(); // read-only snapshot of the registered observers (do not mutate)
49
+
50
+ setObserveAll(true); // "observe every flow by default" — flows without their own `observe` get observed
51
+ isObserveAll(); // read the flag (default false — opt-in observability)
52
+
53
+ clearObservers(); // test-only: reset observers + the observe-all flag for spec isolation
54
+ ```
55
+
56
+ `observeAll` defaults to `false` (opt-in). A flow that never sets `observe` is observed **only** when observe-all is on; individual flows still opt out with `observe: false`.
57
+
58
+ ## Full-history capture — `captureMessages` → `AgentReport.messages`
59
+
60
+ Off by default. When `ai.agent({ captureMessages: true })` is set, the agent normalizes the real assembled turn array onto `AgentReport.messages` as a `CapturedMessage[]`:
61
+
62
+ ```ts
63
+ const { report } = await ai.agent({ model, tools, captureMessages: true }).execute("Go");
64
+ report.messages; // CapturedMessage[] — every role (system/user/assistant/tool), every trip
65
+ ```
66
+
67
+ A `CapturedMessage` is a JSON-safe projection: `{ role, content, toolCalls?, toolCallId? }` — `content` is always a string (tool results stringified), assistant turns that triggered tools carry `toolCalls`, tool-result turns carry the `toolCallId` they answer. Unlike `trips[].input` (which stubs non-first trips with `"[tool results]"`), this preserves the **real** turn array. Omitted ⇒ the field is **absent** and the report is byte-for-byte as before. Opt-in because messages can be large and sensitive (full prompts, tool inputs/outputs) — and **required for panoptic full-history capture**.
68
+
69
+ ## Callback sub-agents nest in the report tree
70
+
71
+ The `ExecutionReport` an observer receives reflects **full** lineage: a supervisor / team / orchestrator callback that calls `agent.execute()` directly auto-nests `callback → agent → tool` (via an ambient `RunFrame`), so usage / cost roll up and panoptic renders the sub-agent under its callback instead of as a lone `$0` span. No observer-side change is needed — the tree arrives already nested. A team's root span carries `type: "team"` (a first-class `ReportType`, not `"supervisor"`), so observers can distinguish, group, and label team runs as their own type. See [`@warlock.js/ai/run-supervisor/SKILL.md`](@warlock.js/ai/run-supervisor/SKILL.md).
72
+
73
+ ## The config seam — `onConfigApplied`
74
+
75
+ An observability tool reacts to its own augmented config slot without core importing it. Core lets tools attach an opaque slot (e.g. `panoptic?`) via declaration merging on `AIConfig`, then fires registered listeners after each `ai.config(...)` merge:
76
+
77
+ ```ts
78
+ import { onConfigApplied, getAIConfig } from "@warlock.js/ai";
79
+
80
+ onConfigApplied((config) => applyPanopticConfig(config.panoptic)); // react on every config merge
81
+ applyPanopticConfig(getAIConfig().panoptic); // catch a pre-set config
82
+ ```
83
+
84
+ A misbehaving listener's throw is swallowed (same swallow-on-throw discipline as the observer hooks). This mirrors the `Observer` registry's dependency inversion: a tool flips `setObserveAll(true)` and calls `registerObserver(...)` from inside its `onConfigApplied` listener.
85
+
86
+ ## The batteries-included Observer
87
+
88
+ `@warlock.js/ai-panoptic` is the shipped, full-featured `Observer` — install it, configure it via `ai.config({ panoptic })`, and it registers its collector + (optionally) flips observe-all for you. Core stays dependency-free; this skill documents the seam panoptic plugs into.
89
+
90
+ ## See also
91
+
92
+ - [`@warlock.js/ai/run-ai-agent/SKILL.md`](@warlock.js/ai/run-ai-agent/SKILL.md) — the `AgentReport` / `ExecutionReport` tree (`trips`, `children`) an observer receives
93
+ - [`@warlock.js/ai/log-ai-calls/SKILL.md`](@warlock.js/ai/log-ai-calls/SKILL.md) — event-level structured logging (vs. report-level observation)
94
+ - [`@warlock.js/ai/run-ai-team/SKILL.md`](@warlock.js/ai/run-ai-team/SKILL.md) — a team inherits `observe` through the supervisor it forwards to
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: record-replay-llm
3
+ description: 'Deterministic, offline LLM tests with ai.vcr(model,{path,mode}) — a record/replay decorator over ANY ModelContract that intercepts only complete()/stream(), delegates name/provider/capabilities/pricing to the inner model, and hashes each request against a JSON cassette on disk. Covers the three modes (record / replay / auto), the cassette format, save(), VcrCassetteMissError, streaming round-trip, hashOptions, and composing below fallbackModel. Triggers: `ai.vcr`, `vcr`, `VcrModel`, `VcrOptions`, `VcrMode`, `Cassette`, `CassetteEntry`, `VcrCassetteMissError`, `hashRequest`, `DEFAULT_HASH_OPTIONS`, `mode`, `path`, `hashOptions`, `save`, `cassette`, record, replay, cassette; ''record LLM responses for tests'', ''replay model calls offline in CI'', ''deterministic agent test without hitting the provider'', ''cassette for model calls''; typical import `import { ai } from "@warlock.js/ai"`. Skip: eval scoring + regression gating — `@warlock.js/ai/eval-datasets-and-ci/SKILL.md`; the Vitest matchers + mockRouter — `@warlock.js/ai/ai-dx-helpers/SKILL.md`; choosing a provider adapter — `@warlock.js/ai/pick-ai-provider/SKILL.md`; competing libs `nock`, `polly.js`.'
4
+ ---
5
+
6
+ # `ai.vcr()` — record / replay any model
7
+
8
+ `ai.vcr(model, { path, mode })` wraps any `ModelContract` in a record/replay decorator backed by a JSON cassette on disk. It intercepts only `complete()` / `stream()` — the single seam every agent trip funnels through — and delegates `name`, `provider`, `capabilities`, and `pricing` to the inner model untouched, so cost accounting and capability detection are unchanged. Depends only on `ModelContract`, so it works with **any** adapter.
9
+
10
+ ## Shape
11
+
12
+ ```ts
13
+ import { ai } from "@warlock.js/ai";
14
+ import { OpenAISDK } from "@warlock.js/ai-openai";
15
+
16
+ const openai = new OpenAISDK({ apiKey: process.env.OPENAI_API_KEY! });
17
+ const live = openai.model({ name: "gpt-4o-mini" });
18
+
19
+ const model = ai.vcr(live, {
20
+ path: "./cassettes/support.json", // cassette file (JSON); read on construct, written on save()
21
+ mode: "auto", // "record" | "replay" | "auto" (default)
22
+ });
23
+
24
+ const agent = ai.agent({ model, systemPrompt: "..." });
25
+ const result = await agent.execute("hi");
26
+
27
+ await model.save(); // first run records; later runs replay deterministically
28
+ ```
29
+
30
+ The returned `VcrModel` is a `ModelContract` plus `save(): Promise<void>` and a readonly `cassette` (exposed for assertions).
31
+
32
+ ## Modes — `VcrMode`
33
+
34
+ - **`record`** — always calls the inner model and appends a cassette entry. Never replays (the in-memory cassette starts empty, so a record run never accidentally replays a stale entry). Use to (re)capture a fresh cassette.
35
+ - **`replay`** — never calls the inner model. A cassette hit returns the stored response / re-yields its chunks / re-throws its error; a **miss throws `VcrCassetteMissError`** — never a silent live call. Use in CI for deterministic, offline tests.
36
+ - **`auto`** (default) — replay on a hit, record on a miss. The friendliest mode for local dev: records once, replays thereafter.
37
+
38
+ ## Request hashing — `hashOptions`
39
+
40
+ On each call VCR computes a stable hash over `{ messages, picked options }` and looks for a matching `CassetteEntry`. The hashed option fields default to:
41
+
42
+ ```ts
43
+ ["temperature", "maxTokens", "responseSchema", "tools", "reasoning"]
44
+ ```
45
+
46
+ (`DEFAULT_HASH_OPTIONS`). `signal` and unknown provider keys are **always excluded**, so an otherwise-identical logical call still matches. `tools` are hashed by name + description + input-schema shape, not object identity. Override `hashOptions` to widen / narrow what counts as "the same request". `hashRequest(messages, options, hashOptions)` is exported for direct use.
47
+
48
+ ## Cassette format
49
+
50
+ A `Cassette` is `{ version: 1, model, provider, entries: CassetteEntry[] }`. Each `CassetteEntry` is `{ requestHash, request: { messages, options? }, ... }` where **exactly one** of `response` / `chunks` / `error` is populated — mirroring the three outcomes of a model call (non-streaming reply, streamed chunk list, or a thrown provider error). The full `request` is stored verbatim for human readability and so the cassette can be re-hashed if the hashing format ever changes.
51
+
52
+ ## Streaming round-trip
53
+
54
+ ```ts
55
+ for await (const chunk of model.stream(messages)) {
56
+ // record mode: buffers each chunk into entry.chunks[] while re-emitting
57
+ // replay mode: re-yields the stored chunks in order (delta / tool-call / done sequence)
58
+ }
59
+ await model.save();
60
+ ```
61
+
62
+ Recorded chunks reproduce the exact `delta` / `tool-call` / `done` sequence on replay; a recorded error is re-thrown.
63
+
64
+ ## `VcrCassetteMissError`
65
+
66
+ ```ts
67
+ import { VcrCassetteMissError } from "@warlock.js/ai";
68
+
69
+ try {
70
+ await vcrModel.complete(messages);
71
+ } catch (error) {
72
+ if (error instanceof VcrCassetteMissError) {
73
+ console.error("Re-record the cassette:", error.path, error.requestHash);
74
+ }
75
+ }
76
+ ```
77
+
78
+ Thrown only in `replay` mode on a miss (code `"VCR_CASSETTE_MISS"`). It carries the looked-up `requestHash` and the cassette `path` so a failing CI run names exactly which call was not recorded. Extends `AIError` directly (not `ProviderError`) — a miss is a harness/config failure, not a provider failure. **The whole point:** `replay` never falls back to a live call, which would silently re-introduce non-determinism into a test that asked for the opposite. Re-record by running once in `record` / `auto`.
79
+
80
+ ## `save()` — flush new entries
81
+
82
+ `save()` writes newly recorded entries to `path`. It is a **no-op when nothing was recorded** (pure replay, or a record/auto run that only hit cached entries), so calling it unconditionally is safe.
83
+
84
+ ## Composition
85
+
86
+ VCR composes **below** `ai.fallbackModel` and works with any adapter. Wrap the live model in `vcr(...)`, then pass it anywhere a `ModelContract` is accepted (agent, planner, reranker, judge).
87
+
88
+ ## See also
89
+
90
+ - [`@warlock.js/ai/eval-datasets-and-ci/SKILL.md`](@warlock.js/ai/eval-datasets-and-ci/SKILL.md) — pair a cassette with a dataset for fully offline eval CI
91
+ - [`@warlock.js/ai/ai-dx-helpers/SKILL.md`](@warlock.js/ai/ai-dx-helpers/SKILL.md) — `ai.mockRouter` + Vitest matchers for the rest of the test surface
92
+ - [`@warlock.js/ai/pick-ai-provider/SKILL.md`](@warlock.js/ai/pick-ai-provider/SKILL.md) — the adapters whose models VCR wraps
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: run-ai-agent
3
- description: 'Build agents with ai.agent({...}) — the single-LLM-turn primitive. Covers execute / stream, attachments, structured output, placeholders, events, agent.eval scoring, and auto-adapting raw executables in tools:[]. Triggers: `ai.agent`, `agent.execute`, `agent.stream`, `agent.eval`, `AgentResult`, `AgentReport`, `AgentToolEntry`, `streamingToolGuard`, `attachments`, `repair`, `maxTrips`, `sessionId`, `spawnSubAgent`, `SpawnSubAgentSpec`; ''run an agent'', ''stream an agent response'', ''structured output schema'', ''pass image to agent'', ''evaluate an agent'', ''put a supervisor in tools'', ''cancel an agent run'', ''spawn a one-shot sub-agent with a per-task budget''; typical import `import { ai } from "@warlock.js/ai"`. Skip: tool definition — `@warlock.js/ai/define-ai-tool/SKILL.md`; workflows — `@warlock.js/ai/run-ai-workflow/SKILL.md`; eval matchers / batch / fallback detail — `@warlock.js/ai/ai-dx-helpers/SKILL.md`; competing libs `langchain`, `ai` (Vercel), raw `openai`.'
3
+ description: 'Build agents with ai.agent({...}) — the single-LLM-turn primitive. Covers execute / stream, attachments, structured output, placeholders, events, agent.eval scoring, the judge-safe preset for resilient LLM-as-judge / verdict classifiers (ai.agent.judge / judge: true — lenient JSON parse + repair + never-throw, for Nova-class models), and auto-adapting raw executables in tools:[]. Triggers: `ai.agent`, `ai.agent.judge`, `agent.execute`, `agent.stream`, `agent.eval`, `AgentResult`, `AgentReport`, `AgentToolEntry`, `JudgeConfig`, `JudgeAgentConfig`, `judge`, `repairAttempts`, `streamingToolGuard`, `attachments`, `repair`, `maxTrips`, `sessionId`, `spawnSubAgent`, `SpawnSubAgentSpec`; ''run an agent'', ''stream an agent response'', ''structured output schema'', ''pass image to agent'', ''evaluate an agent'', ''LLM-as-judge that survives malformed JSON'', ''grade with a Nova model without crashing'', ''put a supervisor in tools'', ''cancel an agent run'', ''spawn a one-shot sub-agent with a per-task budget''; typical import `import { ai } from "@warlock.js/ai"`. Skip: tool definition — `@warlock.js/ai/define-ai-tool/SKILL.md`; workflows — `@warlock.js/ai/run-ai-workflow/SKILL.md`; eval matchers / batch / fallback detail — `@warlock.js/ai/ai-dx-helpers/SKILL.md`; competing libs `langchain`, `ai` (Vercel), raw `openai`.'
4
4
  ---
5
5
 
6
6
  # `ai.agent()` — single-turn primitive
@@ -183,6 +183,31 @@ await myAgent.execute(input, {
183
183
 
184
184
  Disabled by default. Each repair attempt counts against `maxTrips`.
185
185
 
186
+ ## `judge` preset — resilient LLM-as-judge / verdict classifiers
187
+
188
+ For graders and verdict classifiers running on models that emit **corrupted** structured output — notably the Amazon Nova family, which wraps verdicts in fenced ` ```json ` blocks, prepends prose, or trails commentary — set `judge: true` (or a `JudgeConfig`). It turns on three behaviors at once:
189
+
190
+ ```ts
191
+ const grader = ai.agent.judge({
192
+ model: nova.model({ name: "amazon.nova-pro-v1:0" }),
193
+ systemPrompt: "Grade the answer. Respond with JSON only.",
194
+ output: verdictSchema,
195
+ });
196
+
197
+ const result = await grader.execute(prompt);
198
+ if (result.error) {
199
+ // graceful default — the judge couldn't produce a clean verdict
200
+ }
201
+ ```
202
+
203
+ 1. **Repair** — a couple of re-ask attempts by default (`repairAttempts`, defaults to `2`; bounded by `maxTrips`) when the verdict fails to parse / validate. The caller's per-call `options.repair` still wins.
204
+ 2. **Lenient verdict parsing** — extracts the first balanced JSON object / array (tolerating fenced blocks + surrounding prose) instead of the strict parser.
205
+ 3. **Never throws on a parse miss** — even an unparseable verdict yields a well-formed result (`result.error` populated, `result.data` undefined), so a flaky judge degrades instead of crashing the flow.
206
+
207
+ `ai.agent.judge(config, judge?)` is sugar for `ai.agent({ ...config, judge })`; the bare `ai.agent({ judge: true })` option does the same. `judge: {}` ≡ `judge: true` (every field falls back to its resilient default); `judge: { repairAttempts: 0 }` keeps the lenient parser + never-throw guarantee but disables repair.
208
+
209
+ **Trade-off — resilience over strictness.** The lenient parse can recover JSON the strict parser would (correctly) reject — leave `judge` **off** for normal structured output, where a hard parse failure is a useful signal. Off by default; omitting it parses strictly and never auto-enables repair, byte-for-byte as before. (This is the same Nova-safe judge the unified prompt `validate()` uses — see [`@warlock.js/ai/manage-prompts/SKILL.md`](@warlock.js/ai/manage-prompts/SKILL.md).)
210
+
186
211
  ## Pattern — image attachments
187
212
 
188
213
  ```ts
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: run-ai-rag
3
+ description: 'Retrieval-augmented generation with ai.rag({...}) — a chunk → embed → vector-store → retrieve → rerank → cite pipeline that reuses ai.embedder + a @warlock.js/cache CacheDriver. Covers index() / retrieve() / clear() / asTool(), chunking strategies (recursive | markdown | sentence | fixed), Citation / RetrievedChunk provenance, and the opt-in rerankers ai.rag.keywordReranker / ai.rag.llmReranker. Triggers: `ai.rag`, `rag.index`, `rag.retrieve`, `rag.clear`, `rag.asTool`, `RagConfig`, `RagDocument`, `RetrieveOptions`, `RetrieveResult`, `RetrievedChunk`, `Citation`, `ChunkOptions`, `ChunkType`, `ai.rag.keywordReranker`, `ai.rag.llmReranker`, `cacheVectorStore`, `VectorStore`, `topK`, `threshold`, `candidates`; ''build a knowledge base'', ''retrieve relevant chunks for a query'', ''cite the source of an answer'', ''chunk markdown for embedding'', ''rerank retrieval results'', ''expose retrieval as a tool''; typical import `import { ai } from "@warlock.js/ai"`. Skip: raw single-string embedding — `@warlock.js/ai/embed-text/SKILL.md`; exact + vector LLM-response cache — `@warlock.js/ai/attach-ai-middleware/SKILL.md` (ai.middleware.semanticCache); tool wiring — `@warlock.js/ai/define-ai-tool/SKILL.md`; competing libs `langchain`, `llamaindex`.'
4
+ ---
5
+
6
+ # `ai.rag()` — chunk → embed → retrieve → rerank → cite
7
+
8
+ A self-contained retrieval pipeline. It reuses the embedder you already have (`provider.embedder(...)`), a `@warlock.js/cache` vector-capable `CacheDriver` as the store, and the composite-as-tool engine for `asTool()`. Zero new dependencies. `ai.rag` is a native core verb — present the moment `@warlock.js/ai` is imported (no module augmentation, no side-effect import).
9
+
10
+ ## Factory shape
11
+
12
+ ```ts
13
+ import { ai } from "@warlock.js/ai";
14
+ import { MemoryCacheDriver } from "@warlock.js/cache";
15
+ import { OpenAISDK } from "@warlock.js/ai-openai";
16
+
17
+ const openai = new OpenAISDK({ apiKey: process.env.OPENAI_API_KEY! });
18
+
19
+ const kb = ai.rag({
20
+ name: "docs", // default "rag"
21
+ embedder: openai.embedder({ name: "text-embedding-3-small" }), // REQUIRED
22
+ store: new MemoryCacheDriver(), // or ai.config({ defaultStore })
23
+ namespace: "ai.rag.docs", // default `ai.rag.<name>`
24
+ chunk: { type: "markdown", size: 800, overlap: 120 }, // index() defaults
25
+ reranker: ai.rag.keywordReranker(), // OFF by default (cosine-only)
26
+ retrieve: { topK: 4, threshold: 0.5 }, // default retrieval knobs
27
+ });
28
+ ```
29
+
30
+ Resolution is **loud at construction** (mirrors `ai.memory`):
31
+
32
+ - `embedder` is **required** — a provider with no embedder must be caught here, not at first `index()`.
33
+ - `store` falls back to `ai.config({ defaultStore })`; if neither resolves, the factory throws.
34
+
35
+ ## Surface — `Rag`
36
+
37
+ ```ts
38
+ interface Rag {
39
+ readonly name: string;
40
+ index(docs: RagDocument[], chunk?: ChunkOptions): Promise<{ chunks: number }>;
41
+ retrieve(query: string, options?: RetrieveOptions): Promise<RetrieveResult>;
42
+ clear(): Promise<void>;
43
+ asTool(options?: RagAsToolOptions): ToolContract<{ query: string }, RetrieveResult>;
44
+ }
45
+ ```
46
+
47
+ ## `index()` — chunk, embed (batched), store
48
+
49
+ ```ts
50
+ await kb.index([
51
+ { id: "guide", text: longMarkdown, metadata: { url: "/guide" }, tags: ["frontend"] },
52
+ { id: "faq", text: faqText },
53
+ ]);
54
+ ```
55
+
56
+ A `RagDocument` is `{ id, text, metadata?, tags? }` — **you** load + parse documents to text (loaders are out of scope for v1). Each doc is split into chunks, embedded in sub-batches of 96 texts per `embedMany()` call (so one giant doc never blows the provider's per-request cap), and upserted. Returns the chunk count written. Empty / whitespace-only documents yield zero chunks — nothing is embedded. The per-call `chunk` arg overrides `config.chunk` for that index.
57
+
58
+ ## Chunking — `ChunkOptions`
59
+
60
+ All sizing is in **characters** (tokenizer-free; the embedder owns token counting). `chunk(text, options)` is also exported standalone.
61
+
62
+ ```ts
63
+ type ChunkType = "recursive" | "sentence" | "fixed" | "markdown";
64
+
65
+ {
66
+ type?: ChunkType, // default "recursive"
67
+ size?: number, // target chars per chunk, default 1000
68
+ overlap?: number, // chars carried between adjacent chunks, default 200
69
+ separators?: string[], // recursive only; default ["\n\n", "\n", ". ", " ", ""]
70
+ }
71
+ ```
72
+
73
+ - **`recursive`** (default) — separator-aware greedy packing, largest unit first.
74
+ - **`markdown`** — heading/section-aware, then recursive within each section.
75
+ - **`sentence`** — packs whole sentences up to `size`.
76
+ - **`fixed`** — back-to-back character windows.
77
+
78
+ Every chunk records its exact `[start, end)` span in the original text, so a `Citation.span` is precise.
79
+
80
+ ## `retrieve()` — embed query, fetch, rerank, slice, cite
81
+
82
+ ```ts
83
+ const { query, chunks } = await kb.retrieve("how do I configure caching?", {
84
+ topK: 4, // returned AFTER reranking. default 5
85
+ threshold: 0.5, // cosine floor at the store stage. default 0.5
86
+ candidates: 16, // pool fetched before rerank. default topK * 4 (clamped >= topK)
87
+ tags: ["frontend"], // restrict to chunks whose source had one of these tags
88
+ });
89
+
90
+ for (const hit of chunks) {
91
+ console.log(hit.score, hit.text);
92
+ console.log(hit.citation.sourceId, hit.citation.chunkIndex, hit.citation.span);
93
+ }
94
+ ```
95
+
96
+ `retrieve()` is **return-only** — it never auto-injects into a prompt. The caller formats the cited chunks (or uses `asTool()` for the agent loop). A `RetrievedChunk` carries `{ text, score, citation }`; the `Citation` is `{ sourceId, chunkIndex, span, score, metadata? }`. The reranker is **OFF by default** (cosine ranking only) unless `config.reranker` is set.
97
+
98
+ ## Rerankers — opt-in, on `ai.rag.*`
99
+
100
+ Both are exposed as namespaced helpers on the factory (`ai.rag.keywordReranker`, `ai.rag.llmReranker`).
101
+
102
+ ```ts
103
+ // Zero-dependency lexical reranker (BM25-lite keyword overlap).
104
+ ai.rag.keywordReranker({ weight: 0.5 }); // weight in [0,1]; 1 = pure keyword, 0 = keep cosine
105
+
106
+ // Model-backed reranker — one or more model calls per retrieval.
107
+ ai.rag.llmReranker({ model: openai.model({ name: "gpt-4o-mini" }), batchSize: 10 });
108
+ ```
109
+
110
+ - **`keywordReranker`** — blends lexical query-term overlap with the original cosine score by `weight`; ties keep the incoming cosine order. Costs nothing beyond string splits. Reach for it when embedding-only ranking buries a keyword-rich chunk.
111
+ - **`llmReranker`** — asks an LLM to grade each over-fetched candidate `0..1` and sorts by that. Candidates the model fails to score keep their cosine score, so a garbled reply degrades gracefully. Opt in only when precision beats latency/cost. Both implement the `RagReranker` contract, so you can write your own.
112
+
113
+ ## `asTool()` — drop retrieval into an agent's `tools: []`
114
+
115
+ ```ts
116
+ const agent = ai.agent({
117
+ model: openai.model({ name: "gpt-4o" }),
118
+ tools: [kb.asTool({ name: "search_docs", retrieve: { topK: 6 } })],
119
+ });
120
+ ```
121
+
122
+ Input is `{ query: string }`; output is the `RetrieveResult`. Default tool name is `retrieve_<rag.name>`; `description` and a per-tool `retrieve` override are optional. Built via the same composite-as-tool engine every other primitive uses.
123
+
124
+ ## `clear()`
125
+
126
+ ```ts
127
+ await kb.clear(); // drops every entry written under this rag's namespace
128
+ ```
129
+
130
+ ## Advanced
131
+
132
+ - `cacheVectorStore(driver)` + the `VectorStore` contract are exported for swapping in a custom store.
133
+ - A stored chunk's namespaced key is `${namespace}.${sourceId}.${chunkIndex}`.
134
+
135
+ ## See also
136
+
137
+ - [`@warlock.js/ai/embed-text/SKILL.md`](@warlock.js/ai/embed-text/SKILL.md) — the `sdk.embedder` primitive this consumes
138
+ - [`@warlock.js/ai/define-ai-tool/SKILL.md`](@warlock.js/ai/define-ai-tool/SKILL.md) — what `asTool()` produces
139
+ - [`@warlock.js/ai/run-ai-agent/SKILL.md`](@warlock.js/ai/run-ai-agent/SKILL.md) — wiring the retrieval tool into an agent
@@ -0,0 +1,107 @@
1
+ ---
2
+ name: run-ai-team
3
+ description: 'Manager-led multi-agent teams with ai.team({...}) — transparent sugar over ai.supervisor that maps a manager → route/router, members → intents, and a gate → evaluate, returning a REAL SupervisorContract (no new loop, no new contract). Covers the built-in gate strings "quality" (review-then-fix) and "verify" (test-then-fix), a custom gate function, role mapping (roles / gateKey), and the verbatim supervisor pass-throughs (goal / output / state / maxIterations / snapshotStore / on / observe). Triggers: `ai.team`, `TeamConfig`, `TeamGate`, `TeamGateFn`, `TeamMemberValue`, `manager`, `members`, `gate`, `roles`, `gateKey`, `buildQualityGate`, `buildVerifyGate`, `SupervisorContract`, `ReportType`; ''build a team of agents'', ''manager that delegates to members'', ''review then fix loop'', ''test then fix loop'', ''quality gate for a multi-agent run'', ''report type team''; typical import `import { ai } from "@warlock.js/ai"`. Skip: routing one input to a fixed roster directly — `@warlock.js/ai/run-supervisor/SKILL.md` (team is sugar over it); durable cross-turn sessions — `@warlock.js/ai/run-orchestrator/SKILL.md`; LLM-generated plans — `@warlock.js/ai/run-planner/SKILL.md`; competing libs `crewai`, `autogen`.'
4
+ ---
5
+
6
+ # `ai.team()` — manager + members + a quality gate
7
+
8
+ `ai.team(config)` is **thin, transparent sugar over `ai.supervisor`**. It builds a `SupervisorConfig` from the team-shaped config, calls `supervisor(...)`, and returns the **unchanged** `SupervisorContract<TOutput>` — the exact object `ai.supervisor` returns. So `ctx.intents.<member>.execute()`, `.asTool()`, `.resume()`, snapshots, and events all stay intact. `team()` owns no loop of its own.
9
+
10
+ The mapping:
11
+
12
+ | team field | becomes supervisor field |
13
+ | --- | --- |
14
+ | `manager` | `route` (deterministic `{ route }`) XOR `router` (an agent / `RouterEntry`) |
15
+ | `members` | `intents` |
16
+ | `gate` | `evaluate` |
17
+
18
+ Everything else passes through 1:1 — the sole exception is the report/result `type`, which is stamped `"team"` (see [Pass-throughs](#pass-throughs-verbatim-supervisor-semantics)).
19
+
20
+ ## Shape
21
+
22
+ ```ts
23
+ import { ai } from "@warlock.js/ai";
24
+ import { v } from "@warlock.js/seal";
25
+
26
+ const codeTeam = ai.team({
27
+ name: "code-team",
28
+ goal: "Ship a tested module that passes review.",
29
+ manager: techLeadRouter, // an agent / RouterEntry → router; or { route } → deterministic
30
+ members: { builder, reviewer, fixer }, // role-name → agent | workflow
31
+ gate: "quality", // "quality" | "verify" | (ctx) => EvaluateResult
32
+ output: v.object({ code: v.string() }),
33
+ maxIterations: 6, // default 10 (supervisor's)
34
+ });
35
+
36
+ const { data, report } = await codeTeam.execute("Build a debounce<T> utility.");
37
+ ```
38
+
39
+ A `member` is an `AgentContract` or a `WorkflowInstance` (the `TeamMemberValue` union — the autocomplete-friendly common case; callback / full-entry intent shapes still work when forwarded). The keys are both the role names the manager routes to AND the keys `ctx.intents.<role>` exposes (the supervisor escape hatch is preserved).
40
+
41
+ ## The manager — `route` XOR `router`
42
+
43
+ ```ts
44
+ // LLM-driven manager: an agent (or RouterEntry) → becomes SupervisorConfig.router
45
+ manager: techLeadRouter
46
+
47
+ // Deterministic manager: { route } → becomes SupervisorConfig.route
48
+ manager: { route: (ctx) => (ctx.iteration === 0 ? "builder" : "reviewer") }
49
+ ```
50
+
51
+ Exactly one form is forwarded — mutually exclusive, mirroring the supervisor's own `router` XOR `route` rule. A malformed manager surfaces the existing `SupervisorFailedError` downstream.
52
+
53
+ ## Gates — `"quality"` | `"verify"` | a function
54
+
55
+ A `gate` string selects a pre-built `evaluate` strategy; both desugar to a concrete `evaluate` callback that leans entirely on the already-shipped `EvaluateResult` semantics (`satisfied` terminates, `reassignTo` re-dispatches the fixer, `feedback` threads forward) — **no new termination or loop code**.
56
+
57
+ ### `gate: "quality"` — review-then-fix
58
+
59
+ After each iteration's members settle and merge into supervisor `state`, the gate reads `state.approved` (the `gateKey`, default `"approved"`). If truthy → `{ satisfied: true }`; otherwise → `{ reassignTo: "fixer", feedback: String(state.notes ?? "") }`. The reviewer's feedback (`state.notes`) threads into the next iteration.
60
+
61
+ ### `gate: "verify"` — test-then-fix
62
+
63
+ Identical shape but keyed on the tester's pass/fail slice `state.passed` (default `gateKey`) rather than a subjective score. On failure it re-dispatches the fixer; there is no feedback channel for a pass/fail signal, so none is threaded.
64
+
65
+ > The named member whose `output` schema writes the gate slice must produce a boolean into `gateKey`.
66
+
67
+ ### A custom gate (full escape hatch)
68
+
69
+ ```ts
70
+ gate: (ctx) => {
71
+ if (ctx.state.score >= 0.9) return { satisfied: true };
72
+ return { reassignTo: "fixer", feedback: ctx.state.review };
73
+ }
74
+ ```
75
+
76
+ Supplying a `TeamGateFn` instead of a string opts out of the sugar entirely while keeping the rest of `team()`'s wiring — it forwards straight to `SupervisorConfig.evaluate` with zero wrapping.
77
+
78
+ ## Role mapping — `roles` + `gateKey`
79
+
80
+ The string gates default to canonical role names. Override when your `members` keys differ:
81
+
82
+ ```ts
83
+ ai.team({
84
+ name: "qa-team",
85
+ manager,
86
+ members: { author, critic, patcher },
87
+ gate: "quality",
88
+ roles: { reviewer: "critic", fixer: "patcher" }, // map gate roles → your member keys
89
+ gateKey: "ok", // state slice the gate reads
90
+ });
91
+ ```
92
+
93
+ **Construction-time validation:** when the gate is a string, the resolved `fixer` (and, for `"quality"`, the `reviewer`) role is checked against `members`. A missing role throws an authoring-style `SupervisorFailedError` (`context: { authoring: true }`) immediately — rather than silently starving until `maxIterations`.
94
+
95
+ ## Pass-throughs (verbatim supervisor semantics)
96
+
97
+ `goal`, `output`, `state`, `maxIterations`, `snapshotStore`, `on`, `observe`, and `version` are forwarded unchanged. Because the returned object IS a supervisor, observability rides the same generic `Observer` seam every other flow uses (see `observe-ai-flows`), and snapshot resume works exactly as on a bare supervisor.
98
+
99
+ The one behavioural difference from a bare supervisor: a team stamps **`type: "team"`** on both its report (a first-class `ReportType`, was `"supervisor"`) and its result, so Panoptic and any `Observer` can distinguish, group, filter, and label team runs as their own type rather than folding them into plain supervisor runs. Everything else passes through 1:1.
100
+
101
+ A member callback that calls `agent.execute()` **directly** still nests `member → agent → tool` under the member span with usage rolled up — the same ambient-`RunFrame` auto-nesting as a bare supervisor. See [`@warlock.js/ai/run-supervisor/SKILL.md`](@warlock.js/ai/run-supervisor/SKILL.md).
102
+
103
+ ## See also
104
+
105
+ - [`@warlock.js/ai/run-supervisor/SKILL.md`](@warlock.js/ai/run-supervisor/SKILL.md) — the primitive team desugars into (intents, route/router, evaluate, ctx.intents)
106
+ - [`@warlock.js/ai/run-orchestrator/SKILL.md`](@warlock.js/ai/run-orchestrator/SKILL.md) — wrap a team in durable cross-turn session state
107
+ - [`@warlock.js/ai/observe-ai-flows/SKILL.md`](@warlock.js/ai/observe-ai-flows/SKILL.md) — the `observe` seam a team inherits
@@ -86,6 +86,8 @@ result.compaction; // CompactionResult when a turn compacted (and
86
86
 
87
87
  `report.children[]` carries ONLY the current turn's dispatched primitive reports. Full session history lives on `report.turns[]` — a `children[]` walker will NOT reach prior turns (intentional). Child `supervisor.*` / `agent.*` events bubble up unmodified under their own identity.
88
88
 
89
+ A turn callback that calls `agent.execute()` **directly** (not via `ctx.run` / `ctx.intents`) still nests `callback → agent → tool` inside the turn's report tree, with usage rolled up and the session's `sessionId` stamped onto the captured subtree — an ambient `RunFrame` handles the self-attach. See [`@warlock.js/ai/run-supervisor/SKILL.md`](@warlock.js/ai/run-supervisor/SKILL.md).
90
+
89
91
  **`awaiting-input` is the only non-terminal status across the unified result tree.** Code branching on `status === "completed"` MUST explicitly handle `"awaiting-input"` as a session-continues path, not a failure.
90
92
 
91
93
  ## `iterate` — single dispatch vs. internal supervisor
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: run-planner
3
- description: 'Goal-driven planning with ai.planner({...}) — an LLM GENERATES an ordered execution plan over your registered capabilities (agents / workflows / supervisors / tools), then the planner EXECUTES that plan step-by-step, threading each step output into the next, and returns the unified {data, report, usage, error} envelope with report.type "planner". A plan step may delegate via ai.spawnSubAgent({...}) — a GENERAL one-shot-agent helper (a fresh agent + optional per-task budget), covered fully in `@warlock.js/ai/run-ai-agent/SKILL.md`; it is not planner-specific and the planner engine does not require it. Triggers: `ai.planner`, `planner.execute`, `spawnSubAgent`, `PlannerConfig`, `PlannerCapability`, `PlannerResult`, `PlannerReport`, `PlannerPlan`, `PlannerStep`, `maxSteps`, `report.plan`, `report.executedSteps`; ''let the model plan the steps'', ''dynamic plan from a goal'', ''decompose a goal into capability calls'', ''spawn a sub-agent for a subtask''; typical import `import { ai } from "@warlock.js/ai"`. Skip: a FIXED known pipeline — `@warlock.js/ai/run-ai-workflow/SKILL.md`; routing one input to a specialist each turn — `@warlock.js/ai/run-supervisor/SKILL.md`; a single model + tools call — `@warlock.js/ai/run-ai-agent/SKILL.md`; competing libs `langgraph`, `crewai`.'
3
+ description: 'Goal-driven planning with ai.planner({...}) — an LLM GENERATES an ordered execution plan over your registered capabilities (agents / workflows / supervisors / tools), then the planner EXECUTES it, threading each step output into the next, and returns the unified {data, report, usage, error} envelope with report.type "planner". Supports DAG scheduling (dag:true + maxConcurrency off dependsOn), adaptive re-planning (replan:{maxReplans} + the onStep continue/abort/replan directive), and plan-only / approval (mode:"plan-only" → status "awaiting-approval" → approvedPlan). A plan step may delegate via ai.spawnSubAgent({...}) — a GENERAL one-shot-agent helper covered in `@warlock.js/ai/run-ai-agent/SKILL.md`; it is not planner-specific. Triggers: `ai.planner`, `planner.execute`, `spawnSubAgent`, `PlannerConfig`, `PlannerCapability`, `PlannerResult`, `PlannerReport`, `PlannerPlan`, `PlannerStep`, `PlannerStepDirective`, `PlannerPlanInvalidError`, `maxSteps`, `dag`, `maxConcurrency`, `dependsOn`, `replan`, `onStep`, `mode`, `approvedPlan`, `awaiting-approval`, `report.plan`, `report.executedSteps`; ''let the model plan the steps'', ''dynamic plan from a goal'', ''run independent steps in parallel'', ''re-plan when a step fails'', ''generate a plan for approval before running it''; typical import `import { ai } from "@warlock.js/ai"`. Skip: a FIXED known pipeline — `@warlock.js/ai/run-ai-workflow/SKILL.md`; routing one input to a specialist each turn — `@warlock.js/ai/run-supervisor/SKILL.md`; a single model + tools call — `@warlock.js/ai/run-ai-agent/SKILL.md`; competing libs `langgraph`, `crewai`.'
4
4
  ---
5
5
 
6
6
  # `ai.planner()` — LLM-generated, then executed, plans
@@ -12,16 +12,19 @@ A planner turns a free-form **goal** into an ordered **plan** the LLM writes its
12
12
  - **`agent`** — one model + tools, single task. No multi-step decomposition.
13
13
  - **`workflow`** — a FIXED pipeline you author by hand (`steps: [...]`). The steps are known at design time.
14
14
  - **`supervisor`** — routes one input to the right specialist each turn; loops on a quality verdict.
15
- - **`planner`** — the steps are NOT known in advance. The LLM generates the ordered plan from the goal, then the planner executes it. Bounded v1: strictly sequential, no DAG scheduling, no mid-plan re-planning.
15
+ - **`planner`** — the steps are NOT known in advance. The LLM generates the ordered plan from the goal, then the planner executes it. Sequential by default; opt into **DAG** scheduling, **adaptive re-planning**, and **plan-only / approval** as needed (below).
16
16
 
17
17
  ## Shape
18
18
 
19
19
  ```ts
20
20
  import { ai } from "@warlock.js/ai";
21
+ import { OpenAISDK } from "@warlock.js/ai-openai";
22
+
23
+ const openai = new OpenAISDK({ apiKey: process.env.OPENAI_API_KEY! });
21
24
 
22
25
  const research = ai.planner({
23
26
  name: "research-assistant",
24
- model: ai.openai.model({ name: "gpt-4o" }), // the plan-GENERATION brain
27
+ model: openai.model({ name: "gpt-4o" }), // the plan-GENERATION brain
25
28
  capabilities: [
26
29
  { name: "search", description: "Search the web for sources", executable: searchAgent },
27
30
  { name: "summarize", description: "Summarize text into bullet points", executable: summarizer },
@@ -42,19 +45,81 @@ for (const step of report.executedSteps) { // forensic, in execution order
42
45
  - `planner` lets you bring your own fully-configured planning agent (custom prompt, middleware). The planner injects the plan schema as that agent's per-call `output`.
43
46
  - A `capability` is `{ name, description, executable }`. The `name` is what the LLM references per step; the `description` is what it reads to pick. `executable` is any `ExecutableContract` (agent / workflow / supervisor / tool).
44
47
 
45
- ## Execution model (bounded v1)
48
+ ## Execution model
46
49
 
47
- 1. **Generate** — the planning agent is asked for a `{ steps, summary? }` plan via a generated schema whose `capability` field is an `enum` of your capability names.
48
- 2. **Execute** — steps run **strictly in array order**. Each completed step's output is threaded into the next step's input as "Context from earlier steps". `dependsOn` on a step is advisory metadata only recorded, not scheduled on.
50
+ 1. **Generate** — the planning agent is asked for a `{ steps, summary? }` plan via a generated schema whose `capability` field is an `enum` of your capability names. Each `PlannerStep` is `{ capability, input, id?, reason?, dependsOn? }`.
51
+ 2. **Execute** — by default steps run **strictly in array order**; each completed step's output is threaded into the next step's input as "Context from earlier steps". (Set `dag: true` to schedule on `dependsOn` insteadbelow.)
49
52
  3. **Finalize** — when `output` is set (factory or per-call), the LAST completed step's structured output is validated into `result.data`. A capability that should feed typed output to the planner's `output` should declare its own `output` schema (the planner reads `data`, falling back to an agent's raw `text`).
50
53
 
51
- `report.type === "planner"`; `report.children[]` carries every dispatched capability report (plus the planning trip), with usage rolled up. Lazy capability loading is **deferred** — every capability is fully constructed up front.
54
+ `report.type === "planner"`; `report.children[]` carries every dispatched capability report (plus the planning trip), with usage rolled up. `report.executedSteps` is the authoritative per-step record (`PlannerStepSnapshot[]`). Lazy capability loading is **deferred** — every capability is fully constructed up front.
55
+
56
+ ## DAG scheduling — `dag: true` + `maxConcurrency`
57
+
58
+ Run independent steps in parallel instead of array-order:
59
+
60
+ ```ts
61
+ const research = ai.planner({
62
+ name: "research",
63
+ model,
64
+ capabilities,
65
+ dag: true, // build a DAG from each step's `id` / `dependsOn`
66
+ maxConcurrency: 4, // max steps in flight at once. default 4
67
+ });
68
+ ```
69
+
70
+ With `dag: true` the planner builds a DAG from step `id` / `dependsOn`, runs each **ready level concurrently** (up to `maxConcurrency`), and feeds each step **only its dependencies' outputs** (not the whole prior transcript). A **cycle** or a `dependsOn` naming an unknown step raises a typed `PlannerPlanInvalidError` **before any step runs**. Default `false` ⇒ the strict array-order loop, byte-for-byte unchanged (where `dependsOn` is advisory-only metadata).
71
+
72
+ ## Adaptive re-planning — `replan: { maxReplans }` + `onStep`
73
+
74
+ When set, a **failed step** (or a `replan` verdict from the `onStep` hook) **revises the REMAINING plan** instead of aborting — re-asking the planning agent for a fresh plan seeded with the executed-step digest plus the feedback. Bounded by `maxReplans`; on exhaustion the run ends with the last failure.
75
+
76
+ ```ts
77
+ const planner = ai.planner({
78
+ name: "adaptive",
79
+ model,
80
+ capabilities,
81
+ replan: { maxReplans: 2 },
82
+ });
83
+
84
+ await planner.execute(goal, {
85
+ onStep: (snapshot, plan) => {
86
+ // fired after EACH step settles (both the sequential and the DAG path)
87
+ if (snapshot.status === "completed" && looksWrong(snapshot.output)) {
88
+ return { type: "replan", feedback: "The summary missed the pricing section." };
89
+ }
90
+ // return nothing / { type: "continue" } to proceed; { type: "abort" } to stop
91
+ },
92
+ });
93
+ ```
94
+
95
+ The `onStep` directive (`PlannerStepDirective`):
96
+
97
+ - `{ type: "continue" }` (or returning nothing) — proceed.
98
+ - `{ type: "abort" }` — stop; remaining steps recorded `skipped` (exactly as a failure aborts).
99
+ - `{ type: "replan"; feedback }` — re-plan the remainder, seeded with the digest + `feedback`. **A `replan` directive with no `replan` config is treated as `continue`** (no-op). Default off ⇒ a failure aborts exactly as before.
100
+
101
+ ## Plan-only / approval — `mode: "plan-only"` + `approvedPlan`
102
+
103
+ Generate (and validate) a plan, return it for human sign-off, then execute the approved plan in a follow-up call:
104
+
105
+ ```ts
106
+ // 1. Generate WITHOUT executing.
107
+ const draft = await planner.execute(goal, { mode: "plan-only" });
108
+ // draft.report.status === "awaiting-approval"; draft.plan carries the generated PlannerPlan.
109
+
110
+ // 2. (human reviews draft.plan) ... then execute it verbatim.
111
+ const final = await planner.execute(goal, { approvedPlan: draft.plan! });
112
+ ```
113
+
114
+ - `mode: "plan-only"` generates + validates the plan and returns **without executing** — `report.status === "awaiting-approval"` (a planner-specific NON-terminal status) and `result.plan` carries the generated plan.
115
+ - `approvedPlan` executes that exact plan, **skipping plan generation entirely**. It is still validated against the **live** capabilities, so a stale plan naming a capability the planner no longer has surfaces a `PlannerPlanInvalidError`.
116
+ - `mode: "plan-only"` **with** `approvedPlan` is contradictory — `approvedPlan` wins (the plan executes).
52
117
 
53
118
  ## Failure + cancellation
54
119
 
55
120
  `execute()` never throws — failures surface on `result.error`:
56
121
 
57
- - **`PlannerPlanInvalidError`** (`PLANNER_PLAN_INVALID`, category `schema`) — empty plan or a step naming an unknown capability; also a final-output validation failure.
122
+ - **`PlannerPlanInvalidError`** (`PLANNER_PLAN_INVALID`, category `schema`) — empty plan, a step naming an unknown capability, a DAG cycle, a `dependsOn` naming an unknown step, a stale `approvedPlan`, or a final-output validation failure.
58
123
  - **`PlannerCancelledError`** (`PLANNER_CANCELLED`, category `cancelled`) — the `AbortSignal` fired. `report.status === "cancelled"`, `report.cancelledAt` set; remaining steps are `skipped`.
59
124
  - A child capability's own error (agent / tool / provider) flows through unchanged on the failing step's snapshot and as `result.error`. The planner stops at the first failed step and marks the rest `skipped`.
60
125
  - **`PlannerFailedError`** is the base for the `PLANNER_*` family.