@vercel/factory 0.0.14 → 0.0.16

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 (510) hide show
  1. package/CHANGELOG.md +356 -0
  2. package/README.md +96 -2
  3. package/dist/agent-routes.d.mts +113 -0
  4. package/dist/agent-routes.mjs +91 -0
  5. package/dist/agent-routes.mjs.map +1 -0
  6. package/dist/api-contracts.d.mts +1768 -0
  7. package/dist/api-contracts.mjs +119 -0
  8. package/dist/api-contracts.mjs.map +1 -0
  9. package/dist/api-images.d.mts +30 -0
  10. package/dist/api-images.mjs +28 -0
  11. package/dist/api-images.mjs.map +1 -0
  12. package/dist/api-task-graph.mjs +57 -0
  13. package/dist/api-task-graph.mjs.map +1 -0
  14. package/dist/api.d.mts +111 -216
  15. package/dist/api.mjs +1063 -99
  16. package/dist/api.mjs.map +1 -1
  17. package/dist/approval-access.d.mts +39 -0
  18. package/dist/approval-access.mjs +62 -0
  19. package/dist/approval-access.mjs.map +1 -0
  20. package/dist/approval-contracts.d.mts +698 -0
  21. package/dist/approval-contracts.mjs +27 -0
  22. package/dist/approval-contracts.mjs.map +1 -0
  23. package/dist/approval.d.mts +49 -0
  24. package/dist/approval.mjs +39 -0
  25. package/dist/approval.mjs.map +1 -0
  26. package/dist/blob/artifacts.d.mts +37 -0
  27. package/dist/blob/artifacts.mjs +45 -0
  28. package/dist/blob/artifacts.mjs.map +1 -0
  29. package/dist/blob/index.d.mts +84 -12
  30. package/dist/blob/index.mjs +179 -45
  31. package/dist/blob/index.mjs.map +1 -1
  32. package/dist/budget.d.mts +115 -0
  33. package/dist/budget.mjs +147 -0
  34. package/dist/budget.mjs.map +1 -0
  35. package/dist/budgets.d.mts +4 -0
  36. package/dist/budgets.mjs +4 -0
  37. package/dist/build-factory.d.mts +7 -4
  38. package/dist/build-factory.mjs +2 -1
  39. package/dist/build-factory.mjs.map +1 -1
  40. package/dist/change-verification/brief.d.mts +9 -0
  41. package/dist/change-verification/brief.mjs +13 -0
  42. package/dist/change-verification/brief.mjs.map +1 -0
  43. package/dist/change-verification/dispatch.d.mts +37 -0
  44. package/dist/change-verification/dispatch.mjs +83 -0
  45. package/dist/change-verification/dispatch.mjs.map +1 -0
  46. package/dist/change-verification/eve-tool.d.mts +61 -0
  47. package/dist/change-verification/eve-tool.mjs +89 -0
  48. package/dist/change-verification/eve-tool.mjs.map +1 -0
  49. package/dist/change-verification/result.mjs +130 -0
  50. package/dist/change-verification/result.mjs.map +1 -0
  51. package/dist/changes/eve-record-change.d.mts +56 -0
  52. package/dist/changes/eve-record-change.mjs +131 -0
  53. package/dist/changes/eve-record-change.mjs.map +1 -0
  54. package/dist/changes/presentation.d.mts +14 -0
  55. package/dist/changes.d.mts +24 -0
  56. package/dist/changes.mjs +29 -0
  57. package/dist/changes.mjs.map +1 -0
  58. package/dist/client-events.d.mts +25 -0
  59. package/dist/client-events.mjs +45 -0
  60. package/dist/client-events.mjs.map +1 -0
  61. package/dist/client-stream.d.mts +28 -0
  62. package/dist/client-stream.mjs +210 -0
  63. package/dist/client-stream.mjs.map +1 -0
  64. package/dist/client-transcript.d.mts +41 -0
  65. package/dist/client-transcript.mjs +233 -0
  66. package/dist/client-transcript.mjs.map +1 -0
  67. package/dist/client.d.mts +343 -0
  68. package/dist/client.mjs +366 -0
  69. package/dist/client.mjs.map +1 -0
  70. package/dist/code-review/contracts.d.mts +27 -0
  71. package/dist/code-review/eve-post-review.d.mts +70 -0
  72. package/dist/code-review/eve-post-review.mjs +195 -0
  73. package/dist/code-review/eve-post-review.mjs.map +1 -0
  74. package/dist/code-review/eve-review-comments.d.mts +75 -0
  75. package/dist/code-review/eve-review-comments.mjs +193 -0
  76. package/dist/code-review/eve-review-comments.mjs.map +1 -0
  77. package/dist/code-review/github-contracts.d.mts +10 -0
  78. package/dist/code-review/github-reporter.d.mts +46 -0
  79. package/dist/code-review/github-reporter.mjs +262 -0
  80. package/dist/code-review/github-reporter.mjs.map +1 -0
  81. package/dist/code-review/preparation.d.mts +34 -0
  82. package/dist/code-review/preparation.mjs +23 -0
  83. package/dist/code-review/preparation.mjs.map +1 -0
  84. package/dist/code-review/stall.d.mts +17 -0
  85. package/dist/code-review/stall.mjs +30 -0
  86. package/dist/code-review/stall.mjs.map +1 -0
  87. package/dist/code-review.d.mts +7 -0
  88. package/dist/code-review.mjs +5 -0
  89. package/dist/communication.d.mts +9 -0
  90. package/dist/communication.mjs +9 -0
  91. package/dist/connectors/github.d.mts +26 -0
  92. package/dist/connectors/github.mjs +55 -0
  93. package/dist/connectors/github.mjs.map +1 -0
  94. package/dist/connectors/index.d.mts +35 -3
  95. package/dist/connectors/index.mjs +3 -52
  96. package/dist/connectors/index.mjs.map +1 -1
  97. package/dist/connectors/outbox.d.mts +34 -0
  98. package/dist/connectors/outbox.mjs +50 -0
  99. package/dist/connectors/outbox.mjs.map +1 -0
  100. package/dist/connectors/slack-approval-blocks.mjs +136 -0
  101. package/dist/connectors/slack-approval-blocks.mjs.map +1 -0
  102. package/dist/connectors/slack-approvals.d.mts +29 -0
  103. package/dist/connectors/slack-approvals.mjs +346 -0
  104. package/dist/connectors/slack-approvals.mjs.map +1 -0
  105. package/dist/connectors/slack.d.mts +35 -52
  106. package/dist/connectors/slack.mjs +13 -85
  107. package/dist/connectors/slack.mjs.map +1 -1
  108. package/dist/deepsec/eve-tool.d.mts +110 -0
  109. package/dist/deepsec/eve-tool.mjs +166 -0
  110. package/dist/deepsec/eve-tool.mjs.map +1 -0
  111. package/dist/deepsec/finding.d.mts +84 -0
  112. package/dist/deepsec/finding.mjs +56 -0
  113. package/dist/deepsec/finding.mjs.map +1 -0
  114. package/dist/deepsec.d.mts +3 -0
  115. package/dist/delivery-metrics/metrics.d.mts +93 -0
  116. package/dist/delivery-metrics/metrics.mjs +200 -0
  117. package/dist/delivery-metrics/metrics.mjs.map +1 -0
  118. package/dist/delivery-metrics.d.mts +2 -0
  119. package/dist/delivery-metrics.mjs +2 -0
  120. package/dist/dispatch.d.mts +152 -0
  121. package/dist/dispatch.mjs +199 -0
  122. package/dist/dispatch.mjs.map +1 -0
  123. package/dist/errors.d.mts +15 -0
  124. package/dist/errors.mjs +38 -0
  125. package/dist/errors.mjs.map +1 -0
  126. package/dist/eve/index.d.mts +209 -1277
  127. package/dist/eve/index.mjs +312 -1073
  128. package/dist/eve/index.mjs.map +1 -1
  129. package/dist/eve/invoke.d.mts +144 -0
  130. package/dist/eve/invoke.mjs +254 -0
  131. package/dist/eve/invoke.mjs.map +1 -0
  132. package/dist/eve/session-client.d.mts +186 -0
  133. package/dist/eve/session-client.mjs +245 -0
  134. package/dist/eve/session-client.mjs.map +1 -0
  135. package/dist/eve/task-execution.d.mts +380 -0
  136. package/dist/eve/task-execution.mjs +73 -0
  137. package/dist/eve/task-execution.mjs.map +1 -0
  138. package/dist/eve/task-session.d.mts +129 -0
  139. package/dist/eve/task-session.mjs +245 -0
  140. package/dist/eve/task-session.mjs.map +1 -0
  141. package/dist/eve/transcript.d.mts +37 -0
  142. package/dist/eve/transcript.mjs +69 -0
  143. package/dist/eve/transcript.mjs.map +1 -0
  144. package/dist/execution-public.d.mts +8 -0
  145. package/dist/execution-public.mjs +7 -0
  146. package/dist/execution.d.mts +183 -0
  147. package/dist/execution.mjs +223 -0
  148. package/dist/execution.mjs.map +1 -0
  149. package/dist/finding-remediation/admission.d.mts +53 -0
  150. package/dist/finding-remediation/admission.mjs +90 -0
  151. package/dist/finding-remediation/admission.mjs.map +1 -0
  152. package/dist/finding-remediation/brief.d.mts +14 -0
  153. package/dist/finding-remediation/brief.mjs +25 -0
  154. package/dist/finding-remediation/brief.mjs.map +1 -0
  155. package/dist/finding-remediation/eve-tool.d.mts +29 -0
  156. package/dist/finding-remediation/eve-tool.mjs +34 -0
  157. package/dist/finding-remediation/eve-tool.mjs.map +1 -0
  158. package/dist/findings/fingerprint.d.mts +14 -0
  159. package/dist/findings/fingerprint.mjs +28 -0
  160. package/dist/findings/fingerprint.mjs.map +1 -0
  161. package/dist/findings.d.mts +7 -0
  162. package/dist/findings.mjs +6 -0
  163. package/dist/github-app.d.mts +54 -0
  164. package/dist/github-app.mjs +121 -0
  165. package/dist/github-app.mjs.map +1 -0
  166. package/dist/github-publication.d.mts +199 -0
  167. package/dist/github-publication.mjs +442 -0
  168. package/dist/github-publication.mjs.map +1 -0
  169. package/dist/github-transfer.d.mts +81 -0
  170. package/dist/github-transfer.mjs +273 -0
  171. package/dist/github-transfer.mjs.map +1 -0
  172. package/dist/github.d.mts +446 -2
  173. package/dist/github.mjs +357 -56
  174. package/dist/github.mjs.map +1 -1
  175. package/dist/image-input.d.mts +51 -0
  176. package/dist/image-input.mjs +63 -0
  177. package/dist/image-input.mjs.map +1 -0
  178. package/dist/inbox-activity.d.mts +53 -0
  179. package/dist/inbox-activity.mjs +41 -0
  180. package/dist/inbox-activity.mjs.map +1 -0
  181. package/dist/index.d.mts +16 -484
  182. package/dist/index.mjs +15 -522
  183. package/dist/intake-contracts.d.mts +55 -0
  184. package/dist/intake-contracts.mjs +33 -0
  185. package/dist/intake-contracts.mjs.map +1 -0
  186. package/dist/integrations/deepsec.d.mts +5 -0
  187. package/dist/integrations/deepsec.mjs +3 -0
  188. package/dist/integrations/github.d.mts +11 -0
  189. package/dist/integrations/github.mjs +9 -0
  190. package/dist/integrations/slack.d.mts +5 -0
  191. package/dist/integrations/slack.mjs +5 -0
  192. package/dist/integrations/vercel.d.mts +5 -0
  193. package/dist/integrations/vercel.mjs +4 -0
  194. package/dist/merge-resolution/contracts.d.mts +17 -0
  195. package/dist/merge-resolution/contracts.mjs +19 -0
  196. package/dist/merge-resolution/contracts.mjs.map +1 -0
  197. package/dist/merge-resolution/eve-tools.d.mts +47 -0
  198. package/dist/merge-resolution/eve-tools.mjs +122 -0
  199. package/dist/merge-resolution/eve-tools.mjs.map +1 -0
  200. package/dist/model-settings.d.mts +41 -0
  201. package/dist/model-settings.mjs +35 -0
  202. package/dist/model-settings.mjs.map +1 -0
  203. package/dist/multi-repository-changes/coordination.d.mts +49 -0
  204. package/dist/multi-repository-changes/coordination.mjs +115 -0
  205. package/dist/multi-repository-changes/coordination.mjs.map +1 -0
  206. package/dist/planning/cancellation.mjs +82 -0
  207. package/dist/planning/cancellation.mjs.map +1 -0
  208. package/dist/planning/configuration.d.mts +23 -0
  209. package/dist/planning/configuration.mjs +56 -0
  210. package/dist/planning/configuration.mjs.map +1 -0
  211. package/dist/planning/contracts.d.mts +136 -0
  212. package/dist/planning/contracts.mjs +42 -0
  213. package/dist/planning/contracts.mjs.map +1 -0
  214. package/dist/planning/dependencies.mjs +44 -0
  215. package/dist/planning/dependencies.mjs.map +1 -0
  216. package/dist/planning/effects.mjs +122 -0
  217. package/dist/planning/effects.mjs.map +1 -0
  218. package/dist/planning/reconcile.mjs +279 -0
  219. package/dist/planning/reconcile.mjs.map +1 -0
  220. package/dist/planning/runtime.d.mts +27 -0
  221. package/dist/planning/runtime.mjs +25 -0
  222. package/dist/planning/runtime.mjs.map +1 -0
  223. package/dist/planning/state.mjs +92 -0
  224. package/dist/planning/state.mjs.map +1 -0
  225. package/dist/planning/turns.mjs +262 -0
  226. package/dist/planning/turns.mjs.map +1 -0
  227. package/dist/planning/validation.mjs +106 -0
  228. package/dist/planning/validation.mjs.map +1 -0
  229. package/dist/postgres/index.d.mts +48 -1
  230. package/dist/postgres/index.mjs +45 -3
  231. package/dist/postgres/index.mjs.map +1 -1
  232. package/dist/presets/software-development/approval.d.mts +14 -0
  233. package/dist/presets/software-development/approval.mjs +21 -0
  234. package/dist/presets/software-development/approval.mjs.map +1 -0
  235. package/dist/presets/software-development/deepsec-brief.d.mts +8 -0
  236. package/dist/presets/software-development/deepsec-brief.mjs +14 -0
  237. package/dist/presets/software-development/deepsec-brief.mjs.map +1 -0
  238. package/dist/presets/software-development/dispatch.d.mts +56 -0
  239. package/dist/presets/software-development/dispatch.mjs +67 -0
  240. package/dist/presets/software-development/dispatch.mjs.map +1 -0
  241. package/dist/presets/software-development/eve-delegation-policy.d.mts +7 -0
  242. package/dist/presets/software-development/eve-delegation-policy.mjs +34 -0
  243. package/dist/presets/software-development/eve-delegation-policy.mjs.map +1 -0
  244. package/dist/presets/software-development/eve.d.mts +18 -0
  245. package/dist/presets/software-development/eve.mjs +19 -0
  246. package/dist/presets/software-development/eve.mjs.map +1 -0
  247. package/dist/presets/software-development/finish-task-policy.d.mts +7 -0
  248. package/dist/presets/software-development/finish-task-policy.mjs +9 -0
  249. package/dist/presets/software-development/finish-task-policy.mjs.map +1 -0
  250. package/dist/presets/software-development/recovery.d.mts +32 -0
  251. package/dist/presets/software-development/recovery.mjs +120 -0
  252. package/dist/presets/software-development/recovery.mjs.map +1 -0
  253. package/dist/presets/software-development/task-communication.d.mts +24 -0
  254. package/dist/presets/software-development/task-communication.mjs +157 -0
  255. package/dist/presets/software-development/task-communication.mjs.map +1 -0
  256. package/dist/presets/software-development.d.mts +10 -0
  257. package/dist/presets/software-development.mjs +9 -0
  258. package/dist/pull-requests/contracts.d.mts +72 -0
  259. package/dist/pull-requests/eve-fetch.d.mts +57 -0
  260. package/dist/pull-requests/eve-fetch.mjs +151 -0
  261. package/dist/pull-requests/eve-fetch.mjs.map +1 -0
  262. package/dist/pull-requests/github-label-manager.d.mts +27 -0
  263. package/dist/pull-requests/github-label-manager.mjs +40 -0
  264. package/dist/pull-requests/github-label-manager.mjs.map +1 -0
  265. package/dist/pull-requests/github-publisher.d.mts +67 -0
  266. package/dist/pull-requests/github-publisher.mjs +405 -0
  267. package/dist/pull-requests/github-publisher.mjs.map +1 -0
  268. package/dist/pull-requests.d.mts +6 -0
  269. package/dist/pull-requests.mjs +4 -0
  270. package/dist/receipts.d.mts +4 -0
  271. package/dist/receipts.mjs +3 -0
  272. package/dist/repositories.d.mts +18 -0
  273. package/dist/repositories.mjs +33 -0
  274. package/dist/repositories.mjs.map +1 -0
  275. package/dist/sandbox/command.d.mts +18 -0
  276. package/dist/sandbox/execution-abort.d.mts +16 -0
  277. package/dist/sandbox/execution-abort.mjs +49 -0
  278. package/dist/sandbox/execution-abort.mjs.map +1 -0
  279. package/dist/sandbox/execution-environment.d.mts +25 -0
  280. package/dist/sandbox/execution-run-ledger.d.mts +115 -0
  281. package/dist/sandbox/execution-run-ledger.mjs +209 -0
  282. package/dist/sandbox/execution-run-ledger.mjs.map +1 -0
  283. package/dist/sandbox/execution.d.mts +54 -0
  284. package/dist/sandbox/execution.mjs +228 -0
  285. package/dist/sandbox/execution.mjs.map +1 -0
  286. package/dist/sandbox/harness-runner.d.mts +79 -0
  287. package/dist/sandbox/harness-runner.mjs +162 -0
  288. package/dist/sandbox/harness-runner.mjs.map +1 -0
  289. package/dist/sandbox/index.d.mts +10 -0
  290. package/dist/sandbox/index.mjs +7 -0
  291. package/dist/sandbox/task-environment.d.mts +50 -0
  292. package/dist/sandbox/task-environment.mjs +140 -0
  293. package/dist/sandbox/task-environment.mjs.map +1 -0
  294. package/dist/sandbox/workspace.d.mts +29 -0
  295. package/dist/sandbox/workspace.mjs +28 -0
  296. package/dist/sandbox/workspace.mjs.map +1 -0
  297. package/dist/schema/agent-route.d.mts +40 -0
  298. package/dist/schema/agent-route.mjs +33 -0
  299. package/dist/schema/agent-route.mjs.map +1 -0
  300. package/dist/schema/answer.d.mts +23 -0
  301. package/dist/schema/answer.mjs +21 -0
  302. package/dist/schema/answer.mjs.map +1 -0
  303. package/dist/schema/budget.d.mts +38 -0
  304. package/dist/schema/budget.mjs +30 -0
  305. package/dist/schema/budget.mjs.map +1 -0
  306. package/dist/schema/catalog.mjs +72 -0
  307. package/dist/schema/catalog.mjs.map +1 -0
  308. package/dist/schema/change.d.mts +117 -0
  309. package/dist/schema/change.mjs +68 -0
  310. package/dist/schema/change.mjs.map +1 -0
  311. package/dist/schema/common.d.mts +33 -0
  312. package/dist/{id-BLIkCVue.mjs → schema/common.mjs} +7 -16
  313. package/dist/schema/common.mjs.map +1 -0
  314. package/dist/schema/communication.d.mts +52 -0
  315. package/dist/{communication-Kd9nU5RP.mjs → schema/communication.mjs} +8 -3
  316. package/dist/schema/communication.mjs.map +1 -0
  317. package/dist/schema/execution.d.mts +101 -0
  318. package/dist/schema/execution.mjs +86 -0
  319. package/dist/schema/execution.mjs.map +1 -0
  320. package/dist/schema/factory-config.d.mts +122 -0
  321. package/dist/schema/factory-config.mjs +90 -0
  322. package/dist/schema/factory-config.mjs.map +1 -0
  323. package/dist/schema/finding.d.mts +125 -0
  324. package/dist/schema/finding.mjs +67 -0
  325. package/dist/schema/finding.mjs.map +1 -0
  326. package/dist/schema/id.d.mts +43 -0
  327. package/dist/schema/id.mjs +32 -0
  328. package/dist/schema/id.mjs.map +1 -0
  329. package/dist/schema/outbox.d.mts +240 -0
  330. package/dist/schema/outbox.mjs +53 -0
  331. package/dist/schema/outbox.mjs.map +1 -0
  332. package/dist/schema/question-route.mjs +16 -0
  333. package/dist/schema/question-route.mjs.map +1 -0
  334. package/dist/schema/receipt.d.mts +81 -0
  335. package/dist/schema/receipt.mjs +94 -0
  336. package/dist/schema/receipt.mjs.map +1 -0
  337. package/dist/schema/repository.d.mts +30 -0
  338. package/dist/schema/repository.mjs +29 -0
  339. package/dist/schema/repository.mjs.map +1 -0
  340. package/dist/schema/session.d.mts +136 -0
  341. package/dist/schema/session.mjs +54 -0
  342. package/dist/schema/session.mjs.map +1 -0
  343. package/dist/schema/signal.d.mts +105 -0
  344. package/dist/schema/signal.mjs +81 -0
  345. package/dist/schema/signal.mjs.map +1 -0
  346. package/dist/schema/slack-pr-notifications.d.mts +12 -0
  347. package/dist/schema/slack-pr-notifications.mjs +11 -0
  348. package/dist/schema/slack-pr-notifications.mjs.map +1 -0
  349. package/dist/schema/stored-session.mjs +10 -0
  350. package/dist/schema/stored-session.mjs.map +1 -0
  351. package/dist/schema/stored-task.mjs +20 -0
  352. package/dist/schema/stored-task.mjs.map +1 -0
  353. package/dist/schema/task-effect.d.mts +39 -0
  354. package/dist/schema/task-effect.mjs +29 -0
  355. package/dist/schema/task-effect.mjs.map +1 -0
  356. package/dist/schema/task-graph.d.mts +3173 -0
  357. package/dist/schema/task-graph.mjs +97 -0
  358. package/dist/schema/task-graph.mjs.map +1 -0
  359. package/dist/schema/task-message.d.mts +254 -0
  360. package/dist/schema/task-message.mjs +189 -0
  361. package/dist/schema/task-message.mjs.map +1 -0
  362. package/dist/schema/task.d.mts +273 -0
  363. package/dist/schema/task.mjs +200 -0
  364. package/dist/schema/task.mjs.map +1 -0
  365. package/dist/schema/transcript.d.mts +176 -0
  366. package/dist/schema/transcript.mjs +87 -0
  367. package/dist/schema/transcript.mjs.map +1 -0
  368. package/dist/schema/transitions.d.mts +50 -0
  369. package/dist/schema/transitions.mjs +303 -0
  370. package/dist/schema/transitions.mjs.map +1 -0
  371. package/dist/schema/work.d.mts +150 -0
  372. package/dist/schema/work.mjs +102 -0
  373. package/dist/schema/work.mjs.map +1 -0
  374. package/dist/session-previews.d.mts +76 -0
  375. package/dist/session-previews.mjs +55 -0
  376. package/dist/session-previews.mjs.map +1 -0
  377. package/dist/session-review.d.mts +120 -0
  378. package/dist/session-review.mjs +79 -0
  379. package/dist/session-review.mjs.map +1 -0
  380. package/dist/signal-triage.d.mts +20 -0
  381. package/dist/signal-triage.mjs +85 -0
  382. package/dist/signal-triage.mjs.map +1 -0
  383. package/dist/signals.d.mts +20 -0
  384. package/dist/signals.mjs +19 -0
  385. package/dist/signals.mjs.map +1 -0
  386. package/dist/stall.d.mts +41 -0
  387. package/dist/stall.mjs +83 -0
  388. package/dist/stall.mjs.map +1 -0
  389. package/dist/storage.d.mts +4 -0
  390. package/dist/storage.mjs +4 -0
  391. package/dist/store/driver.d.mts +65 -0
  392. package/dist/store/driver.mjs +42 -0
  393. package/dist/store/driver.mjs.map +1 -0
  394. package/dist/store/engine.d.mts +683 -0
  395. package/dist/store/engine.mjs +2309 -0
  396. package/dist/store/engine.mjs.map +1 -0
  397. package/dist/store/memory.d.mts +24 -0
  398. package/dist/store/memory.mjs +69 -0
  399. package/dist/store/memory.mjs.map +1 -0
  400. package/dist/store/slack-pr-notifications.d.mts +44 -0
  401. package/dist/store/slack-pr-notifications.mjs +121 -0
  402. package/dist/store/slack-pr-notifications.mjs.map +1 -0
  403. package/dist/store/task-effects.d.mts +38 -0
  404. package/dist/store/task-effects.mjs +118 -0
  405. package/dist/store/task-effects.mjs.map +1 -0
  406. package/dist/store/task-graphs.d.mts +60 -0
  407. package/dist/store/task-graphs.mjs +212 -0
  408. package/dist/store/task-graphs.mjs.map +1 -0
  409. package/dist/store/task-messages.d.mts +136 -0
  410. package/dist/store/task-messages.mjs +475 -0
  411. package/dist/store/task-messages.mjs.map +1 -0
  412. package/dist/store/task-work.d.mts +180 -0
  413. package/dist/store/task-work.mjs +137 -0
  414. package/dist/store/task-work.mjs.map +1 -0
  415. package/dist/store/work-notifications.d.mts +19 -0
  416. package/dist/store/work-notifications.mjs +48 -0
  417. package/dist/store/work-notifications.mjs.map +1 -0
  418. package/dist/sweep.d.mts +79 -0
  419. package/dist/sweep.mjs +171 -0
  420. package/dist/sweep.mjs.map +1 -0
  421. package/dist/task-communication.d.mts +35 -0
  422. package/dist/task-communication.mjs +47 -0
  423. package/dist/task-communication.mjs.map +1 -0
  424. package/dist/task-graph-view.d.mts +267 -0
  425. package/dist/task-graph-view.mjs +17 -0
  426. package/dist/task-graph-view.mjs.map +1 -0
  427. package/dist/task-message-processing.d.mts +60 -0
  428. package/dist/task-message-processing.mjs +200 -0
  429. package/dist/task-message-processing.mjs.map +1 -0
  430. package/dist/task-protocols.d.mts +80 -0
  431. package/dist/task-protocols.mjs +47 -0
  432. package/dist/task-protocols.mjs.map +1 -0
  433. package/dist/tasks.d.mts +17 -0
  434. package/dist/tasks.mjs +17 -0
  435. package/dist/vercel-git.d.mts +53 -0
  436. package/dist/vercel-git.mjs +344 -0
  437. package/dist/vercel-git.mjs.map +1 -0
  438. package/dist/vercel-github-api.d.mts +103 -0
  439. package/dist/vercel-github-api.mjs +363 -0
  440. package/dist/vercel-github-api.mjs.map +1 -0
  441. package/dist/vercel.d.mts +34 -2
  442. package/dist/vercel.mjs +49 -3
  443. package/dist/vercel.mjs.map +1 -1
  444. package/dist/work-triage/eve-tool.d.mts +29 -0
  445. package/dist/work-triage/eve-tool.mjs +32 -0
  446. package/dist/work-triage/eve-tool.mjs.map +1 -0
  447. package/dist/work-triage/find-existing-work.d.mts +32 -0
  448. package/dist/work-triage/find-existing-work.mjs +31 -0
  449. package/dist/work-triage/find-existing-work.mjs.map +1 -0
  450. package/dist/work-triage/github.d.mts +15 -0
  451. package/dist/work-triage/github.mjs +14 -0
  452. package/dist/work-triage/github.mjs.map +1 -0
  453. package/dist/work-triage.d.mts +4 -0
  454. package/dist/work-triage.mjs +3 -0
  455. package/dist/workflows.d.mts +146 -0
  456. package/dist/workflows.mjs +139 -0
  457. package/dist/workflows.mjs.map +1 -0
  458. package/dist/workspace-diff-assembly.d.mts +33 -0
  459. package/dist/workspace-diff-assembly.mjs +95 -0
  460. package/dist/workspace-diff-assembly.mjs.map +1 -0
  461. package/dist/workspace-diff.d.mts +90 -0
  462. package/dist/workspace-diff.mjs +61 -0
  463. package/dist/workspace-diff.mjs.map +1 -0
  464. package/dist/workspace-files-git.d.mts +15 -0
  465. package/dist/workspace-files-git.mjs +61 -0
  466. package/dist/workspace-files-git.mjs.map +1 -0
  467. package/dist/workspace-files.d.mts +107 -0
  468. package/dist/workspace-files.mjs +74 -0
  469. package/dist/workspace-files.mjs.map +1 -0
  470. package/dist/workspace-snapshot.d.mts +26 -0
  471. package/dist/workspace-snapshot.mjs +80 -0
  472. package/dist/workspace-snapshot.mjs.map +1 -0
  473. package/docs/getting-started.md +104 -0
  474. package/docs/index.md +100 -0
  475. package/docs/recipes/cancellation.md +215 -0
  476. package/docs/recipes/custom-workflow.md +153 -0
  477. package/docs/recipes/dependent-tasks.md +207 -0
  478. package/docs/recipes/eve-agent.md +277 -0
  479. package/docs/recipes/human-input.md +204 -0
  480. package/docs/recipes/persistence-recovery.md +268 -0
  481. package/docs/recipes/retry-recovery.md +241 -0
  482. package/docs/recipes/task-messaging.md +215 -0
  483. package/docs/recipes/typed-eve-result.md +161 -0
  484. package/docs/runtime-integration.md +137 -0
  485. package/package.json +142 -46
  486. package/dist/approval-JX2Px9IC.mjs +0 -132
  487. package/dist/approval-JX2Px9IC.mjs.map +0 -1
  488. package/dist/budget-DzSiIA4t.mjs +0 -42
  489. package/dist/budget-DzSiIA4t.mjs.map +0 -1
  490. package/dist/change-D2U6v7Ek.mjs +0 -554
  491. package/dist/change-D2U6v7Ek.mjs.map +0 -1
  492. package/dist/communication-Kd9nU5RP.mjs.map +0 -1
  493. package/dist/coordination-Cq08hb1l.mjs +0 -76
  494. package/dist/coordination-Cq08hb1l.mjs.map +0 -1
  495. package/dist/dispatch-BaZS3PT8.d.mts +0 -76
  496. package/dist/driver-BC0Mt5KG.d.mts +0 -34
  497. package/dist/driver-Bbd25rNM.mjs +0 -23
  498. package/dist/driver-Bbd25rNM.mjs.map +0 -1
  499. package/dist/engine-DFHU2Pe-.d.mts +0 -781
  500. package/dist/engine-WaUM2cGA.mjs +0 -1068
  501. package/dist/engine-WaUM2cGA.mjs.map +0 -1
  502. package/dist/factory-config-BoRXOw43.mjs +0 -50
  503. package/dist/factory-config-BoRXOw43.mjs.map +0 -1
  504. package/dist/factory-config-D2yU3G0c.d.mts +0 -58
  505. package/dist/github-C5HNBN6p.d.mts +0 -279
  506. package/dist/id-BLIkCVue.mjs.map +0 -1
  507. package/dist/index-Bw6hggoH.d.mts +0 -40
  508. package/dist/index.mjs.map +0 -1
  509. package/dist/task-CcOyOJ3k.mjs +0 -154
  510. package/dist/task-CcOyOJ3k.mjs.map +0 -1
@@ -0,0 +1,207 @@
1
+ # Coordinate dependent Eve agents
2
+
3
+ Use graph dependencies when one Eve agent must finish before another can run. The application
4
+ creates the graph and owns the parent workflow. A scheduled `sweepQueued` pass starts only ready
5
+ route-bound Tasks; each agent then reads its inputs and completes its own Task through authenticated
6
+ Eve tools.
7
+
8
+ ## Run the recipe
9
+
10
+ Save this as `dependent-tasks.mts` in an ESM project with `@vercel/factory`, `eve`, and `zod`
11
+ installed. Injected `fetch` responses stand in for Eve accepting each session.
12
+
13
+ <!-- runnable-example:start -->
14
+
15
+ ```ts
16
+ import type { ToolContext } from "eve/tools";
17
+ import { z } from "zod";
18
+ import {
19
+ createTaskTools,
20
+ factoryTaskAttemptAttribute,
21
+ factoryTaskAttribute,
22
+ startEveSession,
23
+ taskHeaders,
24
+ } from "@vercel/factory";
25
+ import { sweepQueued, type TaskLauncher } from "@vercel/factory/execution";
26
+ import { createInMemoryDriver, createStores } from "@vercel/factory/storage";
27
+ import { taskIdSchema, type Task } from "@vercel/factory/tasks";
28
+ import { parseAgentRouteBinding, routeKey, taskWork } from "@vercel/factory/workflows";
29
+
30
+ const stores = createStores({ driver: createInMemoryDriver() });
31
+ const repository = await stores.repositories.put({
32
+ schemaVersion: 1,
33
+ id: "repo_recipe02",
34
+ slug: "example/project",
35
+ defaultBranch: "main",
36
+ enabled: true,
37
+ dependsOn: [],
38
+ connectedAt: new Date().toISOString(),
39
+ });
40
+ const prepareRoute = parseAgentRouteBinding({ id: "preparer", version: 1 });
41
+ const consumeRoute = parseAgentRouteBinding({ id: "consumer", version: 1 });
42
+ const consumeInputSchema = z.strictObject({ dependencyTaskId: taskIdSchema });
43
+ const taskOutputSchema = z.strictObject({ summary: z.string().min(1) });
44
+ const launchedAgents: string[] = [];
45
+
46
+ function launchEveAgent(agent: string): TaskLauncher {
47
+ return (claimed) =>
48
+ startEveSession({
49
+ agentUrl: `https://factory.example/eve/agents/${agent}`,
50
+ message: `Work Task ${claimed.id}`,
51
+ operationId: `factory-task:${claimed.id}:${claimed.attempt}`,
52
+ headers: taskHeaders({ taskId: claimed.id, attempt: claimed.attempt }),
53
+ fetch: async () => {
54
+ launchedAgents.push(agent);
55
+ return Response.json({ sessionId: `ses_${agent}_${claimed.attempt}` });
56
+ },
57
+ });
58
+ }
59
+
60
+ function toolContext(task: Task): ToolContext {
61
+ if (task.execution?.provider !== "eve") throw new Error("Expected an Eve execution");
62
+ return {
63
+ session: {
64
+ id: task.execution.sessionId,
65
+ auth: {
66
+ initiator: {
67
+ attributes: {
68
+ [factoryTaskAttribute]: task.id,
69
+ [factoryTaskAttemptAttribute]: String(task.attempt),
70
+ },
71
+ },
72
+ },
73
+ },
74
+ } as unknown as ToolContext;
75
+ }
76
+
77
+ const base = {
78
+ repositoryIds: [repository.id] as const,
79
+ kind: "example",
80
+ origin: { operator: "local:recipe" },
81
+ replyTo: { channel: "local", address: "dependent-tasks" },
82
+ } as const;
83
+ const root = await stores.tasks.create({
84
+ ...base,
85
+ work: taskWork({ title: "Coordinate two agents" }),
86
+ dedupeKey: "dependency-root",
87
+ });
88
+ await stores.tasks.transition(root.id, "running");
89
+ const prepare = await stores.tasks.create({
90
+ ...base,
91
+ parentTaskId: root.id,
92
+ work: { ...taskWork({ title: "Prepare input" }), route: prepareRoute },
93
+ dedupeKey: "prepare",
94
+ });
95
+ const consume = await stores.tasks.create({
96
+ ...base,
97
+ parentTaskId: root.id,
98
+ work: {
99
+ ...taskWork({
100
+ title: "Consume prepared input",
101
+ input: { dependencyTaskId: prepare.id },
102
+ }),
103
+ route: consumeRoute,
104
+ },
105
+ dependencies: [prepare.id],
106
+ dedupeKey: "consume",
107
+ });
108
+ const launchers = {
109
+ [routeKey(prepareRoute)]: launchEveAgent("preparer"),
110
+ [routeKey(consumeRoute)]: launchEveAgent("consumer"),
111
+ };
112
+
113
+ const firstSweep = await sweepQueued(stores, {
114
+ launchers,
115
+ tasks: [prepare, consume],
116
+ });
117
+ const runningPrepare = await stores.tasks.get(prepare.id);
118
+ if (
119
+ runningPrepare?.state !== "running" ||
120
+ firstSweep.dispatched[0] !== prepare.id ||
121
+ firstSweep.skipped.find((item) => item.taskId === consume.id)?.reasonCode !==
122
+ "dependencies_unsatisfied"
123
+ ) {
124
+ throw new Error("The first sweep did not launch only the ready preparer");
125
+ }
126
+
127
+ const tools = createTaskTools(stores);
128
+ const prepared = await tools.finish_task.execute(
129
+ { taskId: prepare.id, summary: "Prepared incident context" },
130
+ toolContext(runningPrepare),
131
+ );
132
+ if (!prepared.finished) throw new Error(prepared.reason);
133
+
134
+ const secondSweep = await sweepQueued(stores, { launchers });
135
+ const runningConsume = await stores.tasks.get(consume.id);
136
+ if (
137
+ runningConsume?.state !== "running" ||
138
+ secondSweep.dispatched[0] !== consume.id ||
139
+ launchedAgents.join(",") !== "preparer,consumer"
140
+ ) {
141
+ throw new Error("The consumer did not launch after its dependency succeeded");
142
+ }
143
+
144
+ const consumerAssignment = await tools.get_task.execute(
145
+ { taskId: runningConsume.id },
146
+ toolContext(runningConsume),
147
+ );
148
+ if (!("id" in consumerAssignment)) throw new Error("The consumer assignment is missing");
149
+ const { dependencyTaskId } = consumeInputSchema.parse(consumerAssignment.work.input);
150
+ const dependency = await tools.get_task.execute(
151
+ { taskId: dependencyTaskId },
152
+ toolContext(runningConsume),
153
+ );
154
+ if (
155
+ !("id" in dependency) ||
156
+ dependency.state !== "succeeded" ||
157
+ dependency.id !== dependencyTaskId
158
+ ) {
159
+ throw new Error("The consumer could not read the dependency result");
160
+ }
161
+ const preparedOutput = taskOutputSchema.parse(dependency.workResult?.output);
162
+ const consumed = await tools.finish_task.execute(
163
+ { taskId: consume.id, summary: `Used: ${preparedOutput.summary}` },
164
+ toolContext(runningConsume),
165
+ );
166
+ if (!consumed.finished) throw new Error(consumed.reason);
167
+ const consumedTask = await stores.tasks.get(consume.id);
168
+ const consumedOutput = taskOutputSchema.parse(consumedTask?.workResult?.output);
169
+
170
+ const completedRoot = await stores.work.complete({
171
+ task: { taskId: root.id, attempt: root.attempt },
172
+ output: {
173
+ prepared: preparedOutput.summary,
174
+ consumed: consumedOutput.summary,
175
+ },
176
+ });
177
+ const graph = await stores.graphs.get(root.id);
178
+ const consumeNode = graph?.nodes.find((node) => node.taskId === consume.id);
179
+ if (
180
+ completedRoot.state !== "succeeded" ||
181
+ consumeNode?.sealed !== true ||
182
+ consumeNode.dependencies[0] !== prepare.id
183
+ ) {
184
+ throw new Error("Expected a completed parent and sealed dependency edge");
185
+ }
186
+
187
+ console.log(
188
+ JSON.stringify({
189
+ root: completedRoot.state,
190
+ dependency: (await stores.tasks.get(prepare.id))?.state,
191
+ dependent: (await stores.tasks.get(consume.id))?.state,
192
+ launchedAgents,
193
+ }),
194
+ );
195
+ ```
196
+
197
+ <!-- runnable-example:end -->
198
+
199
+ The scheduler calls `sweepQueued`; applications provide exact launchers keyed by `routeKey` and
200
+ run another pass after completion, recovery, approval, or human input can make queued work ready.
201
+ Overlapping sweeps are safe because dispatch uses a single-winner transition.
202
+
203
+ The consumer first reads its own assignment, takes the persisted dependency Task ID from
204
+ `work.input`, and then reads that Task's validated result through `get_task`. Its completion and the
205
+ parent's aggregate output are derived from that result. Parentage defines the graph hierarchy;
206
+ dependencies define execution order inside that graph, but dependency edges alone do not tell the
207
+ model which result to read.
@@ -0,0 +1,277 @@
1
+ # Run an Eve agent as a Factory Task
2
+
3
+ Use this pattern for the normal Factory execution path: an application creates a
4
+ route-bound Task, Factory starts an Eve session for that route, and the Eve agent uses Factory
5
+ hooks and tools to report progress and finish the Task.
6
+
7
+ Factory does not replace the agent definition in `agent.ts`. Eve still owns the model loop,
8
+ prompts, tools, and session. Factory adds durable work state around that session: routing,
9
+ attempts, dependencies, budgets, receipts, and a validated result.
10
+
11
+ ## Mount Factory in the Eve agent
12
+
13
+ Keep the runtime pieces in the normal Eve filesystem layout, all importing the same application
14
+ store singleton:
15
+
16
+ ```text
17
+ agents/worker/
18
+ agent.ts
19
+ instructions.md
20
+ channels/eve.ts
21
+ hooks/factory.ts
22
+ tools/get_task.ts
23
+ tools/finish_task.ts
24
+ lib/stores.ts
25
+ lib/launchers.ts
26
+ schedules/dispatch.ts
27
+ ```
28
+
29
+ `agent.ts` selects the Eve model. `instructions.md` tells the model to read its Task before acting
30
+ and to finish only after satisfying the stored completion criteria:
31
+
32
+ ```ts
33
+ // agents/worker/agent.ts
34
+ import { defineAgent } from "eve";
35
+
36
+ export default defineAgent({ model: "anthropic/claude-sonnet-5" });
37
+ ```
38
+
39
+ The channel authenticates the Task headers that the trusted launcher sends when it starts the
40
+ session:
41
+
42
+ ```ts
43
+ // agents/worker/channels/eve.ts
44
+ import { withFactoryTask } from "@vercel/factory";
45
+ import { localDev, vercelOidc } from "eve/channels/auth";
46
+ import { eveChannel } from "eve/channels/eve";
47
+
48
+ export default eveChannel({
49
+ auth: [withFactoryTask(vercelOidc()), withFactoryTask(localDev())],
50
+ });
51
+ ```
52
+
53
+ Mount the Factory hook beside the agent's other Eve hooks:
54
+
55
+ ```ts
56
+ // agents/worker/hooks/factory.ts
57
+ import { createFactoryHooks } from "@vercel/factory";
58
+ import { stores } from "../../../lib/stores";
59
+
60
+ export default createFactoryHooks(stores, {
61
+ presentQuestion: async (input) => {
62
+ // Send input.question to the operator surface used by this application.
63
+ },
64
+ }).factory;
65
+ ```
66
+
67
+ Expose the Task tools that the agent needs. The exact set is an application policy; most workers
68
+ need `get_task` and `finish_task`:
69
+
70
+ ```ts
71
+ // agents/worker/tools/get_task.ts
72
+ import { createTaskTools } from "@vercel/factory";
73
+ import { stores } from "../../../lib/stores";
74
+
75
+ export default createTaskTools(stores).get_task;
76
+ ```
77
+
78
+ ```ts
79
+ // agents/worker/tools/finish_task.ts
80
+ import { createTaskTools } from "@vercel/factory";
81
+ import { stores } from "../../../lib/stores";
82
+
83
+ export default createTaskTools(stores).finish_task;
84
+ ```
85
+
86
+ `withFactoryTask` binds the Eve session to one exact Task attempt. Mutating tools such as
87
+ `finish_task` and `request_human_input` recheck that binding against the current persisted Eve
88
+ execution. `get_task` is a read API that accepts a Task ID; expose it only when the agent is allowed
89
+ to inspect Tasks in the application. `lib/stores.ts` must create one Blob- or Postgres-backed store
90
+ configuration shared by the launcher, hooks, and tools; the in-memory store below is only for the
91
+ self-checking example.
92
+
93
+ ## Dispatch the route and start Eve
94
+
95
+ The application maps each route binding to an Eve agent URL. `dispatchTask` claims the Task attempt
96
+ before calling `startEveSession`, then records the returned Eve session ID on the Task.
97
+
98
+ The following self-checking program uses an injected `fetch` response, so it proves the public
99
+ integration contract without credentials or a running Eve server.
100
+
101
+ <!-- runnable-example:start -->
102
+
103
+ ```ts
104
+ import { defineAgent } from "eve";
105
+ import type { AuthFn } from "eve/channels/auth";
106
+ import { eveChannel } from "eve/channels/eve";
107
+ import type { ToolContext } from "eve/tools";
108
+ import {
109
+ createFactoryHooks,
110
+ createTaskTools,
111
+ factoryTaskAttemptAttribute,
112
+ factoryTaskAttribute,
113
+ startEveSession,
114
+ taskHeaders,
115
+ withFactoryTask,
116
+ } from "@vercel/factory";
117
+ import { dispatchTask } from "@vercel/factory/execution";
118
+ import { createInMemoryDriver, createStores } from "@vercel/factory/storage";
119
+ import { parseAgentRouteBinding, taskWork } from "@vercel/factory/workflows";
120
+
121
+ const stores = createStores({ driver: createInMemoryDriver() });
122
+ const route = parseAgentRouteBinding({ id: "worker", version: 1 });
123
+ const task = await stores.tasks.create({
124
+ repositoryIds: ["repo_eve001"],
125
+ kind: "example",
126
+ origin: { operator: "local:recipe" },
127
+ replyTo: { channel: "local", address: "eve-agent" },
128
+ work: {
129
+ ...taskWork({
130
+ title: "Summarize the incident",
131
+ input: { incidentId: "inc_123" },
132
+ }),
133
+ route,
134
+ },
135
+ });
136
+ const otherTask = await stores.tasks.create({
137
+ repositoryIds: ["repo_eve001"],
138
+ kind: "example",
139
+ origin: { operator: "local:recipe" },
140
+ replyTo: { channel: "local", address: "eve-agent" },
141
+ work: taskWork({ title: "A different assignment" }),
142
+ });
143
+
144
+ const baseAuth: AuthFn<Request> = () => ({
145
+ attributes: {},
146
+ authenticator: "recipe",
147
+ principalId: "factory",
148
+ principalType: "runtime",
149
+ });
150
+ const workerAgent = defineAgent({ model: "anthropic/claude-sonnet-5" });
151
+ const workerChannel = eveChannel({ auth: [withFactoryTask(baseAuth)] });
152
+ let authenticatedTaskId: unknown;
153
+ let authenticatedAttempt: unknown;
154
+
155
+ const running = await dispatchTask(stores, {
156
+ taskId: task.id,
157
+ route,
158
+ launch: (claimed) =>
159
+ startEveSession({
160
+ agentUrl: "https://factory.example/eve/agents/worker",
161
+ message: `Work Task ${claimed.id}`,
162
+ operationId: `factory-task:${claimed.id}:${claimed.attempt}`,
163
+ headers: taskHeaders({
164
+ taskId: claimed.id,
165
+ attempt: claimed.attempt,
166
+ }),
167
+ fetch: async (input, init) => {
168
+ const request = new Request(input, init);
169
+ const authenticated = await withFactoryTask(baseAuth)(request);
170
+ authenticatedTaskId = authenticated?.attributes[factoryTaskAttribute];
171
+ authenticatedAttempt = authenticated?.attributes[factoryTaskAttemptAttribute];
172
+ return Response.json({ sessionId: "ses_recipe" });
173
+ },
174
+ }),
175
+ });
176
+
177
+ const tools = createTaskTools(stores);
178
+ const hooks = createFactoryHooks(stores, {
179
+ presentQuestion: async () => {},
180
+ });
181
+
182
+ if (
183
+ running.state !== "running" ||
184
+ running.execution?.provider !== "eve" ||
185
+ running.execution.sessionId !== "ses_recipe"
186
+ ) {
187
+ throw new Error("Dispatch did not record the Eve session");
188
+ }
189
+ if (authenticatedTaskId !== task.id || authenticatedAttempt !== String(running.attempt)) {
190
+ throw new Error("The Eve channel did not authenticate the Task attempt");
191
+ }
192
+ if (hooks.factory.events?.["turn.failed"] === undefined) {
193
+ throw new Error("The Factory lifecycle hook was not created");
194
+ }
195
+ if (workerAgent === undefined || workerChannel === undefined) {
196
+ throw new Error("The Eve agent and authenticated channel were not assembled");
197
+ }
198
+
199
+ const toolContext = {
200
+ session: {
201
+ id: running.execution.sessionId,
202
+ auth: {
203
+ initiator: {
204
+ attributes: {
205
+ [factoryTaskAttribute]: running.id,
206
+ [factoryTaskAttemptAttribute]: String(running.attempt),
207
+ },
208
+ },
209
+ },
210
+ },
211
+ } as unknown as ToolContext;
212
+ const assignment = await tools.get_task.execute({ taskId: running.id }, toolContext);
213
+ if (!("id" in assignment) || assignment.id !== running.id) {
214
+ throw new Error("The Eve agent could not read its assignment");
215
+ }
216
+
217
+ let foreignCompletionRejected = false;
218
+ try {
219
+ await tools.finish_task.execute(
220
+ { taskId: otherTask.id, summary: "Completed a different Task" },
221
+ toolContext,
222
+ );
223
+ } catch {
224
+ foreignCompletionRejected = true;
225
+ }
226
+ const finish = await tools.finish_task.execute(
227
+ { taskId: running.id, summary: "Incident inc_123 was summarized" },
228
+ toolContext,
229
+ );
230
+ const completed = await stores.tasks.get(running.id);
231
+ if (
232
+ !foreignCompletionRejected ||
233
+ !finish.finished ||
234
+ completed?.state !== "succeeded" ||
235
+ JSON.stringify(completed.workResult?.output) !==
236
+ JSON.stringify({ summary: "Incident inc_123 was summarized" })
237
+ ) {
238
+ throw new Error("Expected authenticated, attempt-fenced Task completion");
239
+ }
240
+
241
+ console.log(
242
+ JSON.stringify({
243
+ taskId: completed.id,
244
+ attempt: completed.attempt,
245
+ sessionId: running.execution.sessionId,
246
+ state: completed.state,
247
+ }),
248
+ );
249
+ ```
250
+
251
+ <!-- runnable-example:end -->
252
+
253
+ In production, omit the injected `fetch`. Eve accepts the session, runs the agent, and invokes the
254
+ mounted hooks. The agent reads its assignment with `get_task` and submits the generic `task@1`
255
+ output with `finish_task`. Factory rejects mutating tool calls whose authenticated session, Task ID,
256
+ or attempt no longer matches the current Task. Use the
257
+ [typed Eve result recipe](./typed-eve-result.md) when a workflow has its own output schema.
258
+
259
+ `taskHeaders(...)` supplies only the Factory Task binding. A protected Vercel deployment commonly
260
+ needs both an `Authorization: Bearer <OIDC token>` header for the Eve channel's `vercelOidc()`
261
+ authentication and `x-vercel-protection-bypass` to pass Deployment Protection. The bypass is not an
262
+ Eve identity. Add whichever layers the deployment actually requires in the trusted launcher, and
263
+ never expose either credential to the agent or its tools.
264
+
265
+ ## Let hooks own session lifecycle events
266
+
267
+ `createFactoryHooks` translates Eve events into durable Task changes:
268
+
269
+ - step events record Task usage, and terminal turn events settle measured cost;
270
+ - a completed turn that leaves work unresolved creates a QuestionTask, suspends the Task, and calls
271
+ `presentQuestion`;
272
+ - `turn.failed` and `session.failed` requeue eligible Tasks with a new attempt;
273
+ - `turn.cancelled` cancels the matching Task attempt.
274
+
275
+ The application must run its recovery launcher after a Task is requeued. See
276
+ [Retry and recover a failed attempt](./retry-recovery.md) for the attempt-fencing rules, and
277
+ [Coordinate dependent Eve agents](./dependent-tasks.md) for multi-agent work.
@@ -0,0 +1,204 @@
1
+ # Pause an Eve Task for human input
2
+
3
+ An Eve specialist asks through `request_human_input`. Factory persists a QuestionTask, moves the
4
+ specialist Task to `needs_human`, and calls the application's presenter. A reply from the same
5
+ authenticated conversation completes the QuestionTask and queues a fresh specialist attempt.
6
+
7
+ ## Run the recipe
8
+
9
+ Save this as `human-input.mts` in an ESM project with `@vercel/factory`, `eve`, and `zod`
10
+ installed.
11
+
12
+ <!-- runnable-example:start -->
13
+
14
+ ```ts
15
+ import type { ToolContext } from "eve/tools";
16
+ import {
17
+ createTaskTools,
18
+ factoryReplyAddressAttribute,
19
+ factoryReplyChannelAttribute,
20
+ factoryTaskAttemptAttribute,
21
+ factoryTaskAttribute,
22
+ startEveSession,
23
+ taskHeaders,
24
+ } from "@vercel/factory";
25
+ import { sweepQueued } from "@vercel/factory/execution";
26
+ import { createInMemoryDriver, createStores } from "@vercel/factory/storage";
27
+ import type { Task } from "@vercel/factory/tasks";
28
+ import { parseAgentRouteBinding, routeKey, taskWork } from "@vercel/factory/workflows";
29
+
30
+ const stores = createStores({ driver: createInMemoryDriver() });
31
+ const repository = await stores.repositories.put({
32
+ schemaVersion: 1,
33
+ id: "repo_human01",
34
+ slug: "example/project",
35
+ defaultBranch: "main",
36
+ enabled: true,
37
+ dependsOn: [],
38
+ connectedAt: new Date().toISOString(),
39
+ });
40
+ const route = parseAgentRouteBinding({ id: "worker", version: 1 });
41
+ const startedSessions: string[] = [];
42
+ const assignmentMessages: string[] = [];
43
+ const launchers = {
44
+ [routeKey(route)]: async (claimed: Task) => {
45
+ const answers = (
46
+ await Promise.all((claimed.answerEventIds ?? []).map((id) => stores.answers.get(id)))
47
+ ).flatMap((event) => (event === null ? [] : [`${event.question}\nAnswer: ${event.answer}`]));
48
+ const message = [
49
+ `Work Task ${claimed.id}`,
50
+ answers.length === 0 ? undefined : `Human answers:\n${answers.join("\n\n")}`,
51
+ ]
52
+ .filter((part) => part !== undefined)
53
+ .join("\n\n");
54
+ assignmentMessages.push(message);
55
+ return startEveSession({
56
+ agentUrl: "https://factory.example/eve/agents/worker",
57
+ message,
58
+ operationId: `factory-task:${claimed.id}:${claimed.attempt}`,
59
+ headers: taskHeaders({ taskId: claimed.id, attempt: claimed.attempt }),
60
+ fetch: async () => {
61
+ const sessionId = `ses_human_${claimed.attempt}`;
62
+ startedSessions.push(sessionId);
63
+ return Response.json({ sessionId });
64
+ },
65
+ });
66
+ },
67
+ };
68
+ const task = await stores.tasks.create({
69
+ repositoryIds: [repository.id],
70
+ kind: "example",
71
+ origin: { operator: "local:recipe" },
72
+ replyTo: { channel: "github", address: "example/project#42" },
73
+ work: {
74
+ ...taskWork({ title: "Deploy to the selected environment" }),
75
+ route,
76
+ },
77
+ });
78
+ await sweepQueued(stores, { launchers });
79
+ const firstAttempt = await stores.tasks.get(task.id);
80
+ if (firstAttempt?.state !== "running" || firstAttempt.execution?.provider !== "eve") {
81
+ throw new Error("The first Eve attempt did not start");
82
+ }
83
+
84
+ function workerContext(running: Task): ToolContext {
85
+ if (running.execution?.provider !== "eve") throw new Error("Expected an Eve execution");
86
+ return {
87
+ session: {
88
+ id: running.execution.sessionId,
89
+ auth: {
90
+ initiator: {
91
+ attributes: {
92
+ [factoryTaskAttribute]: running.id,
93
+ [factoryTaskAttemptAttribute]: String(running.attempt),
94
+ },
95
+ },
96
+ },
97
+ },
98
+ } as unknown as ToolContext;
99
+ }
100
+
101
+ const presented: string[] = [];
102
+ const tools = createTaskTools(stores, {
103
+ presentQuestion: async (questionTask) => {
104
+ presented.push(questionTask.id);
105
+ },
106
+ });
107
+ const question = await tools.request_human_input.execute(
108
+ {
109
+ parentTaskId: firstAttempt.id,
110
+ question: {
111
+ text: "Which environment should receive the deployment?",
112
+ options: ["staging", "production"],
113
+ },
114
+ },
115
+ workerContext(firstAttempt),
116
+ );
117
+ const waiting = await stores.tasks.get(task.id);
118
+ if (
119
+ question.state !== "needs_human" ||
120
+ waiting?.state !== "needs_human" ||
121
+ waiting.questionTaskId !== question.id ||
122
+ presented[0] !== question.id
123
+ ) {
124
+ throw new Error("The question was not persisted and presented");
125
+ }
126
+
127
+ const conversationContext = {
128
+ session: {
129
+ id: "ses_operator_reply",
130
+ auth: {
131
+ initiator: {
132
+ principalId: "operator",
133
+ attributes: {
134
+ [factoryReplyChannelAttribute]: task.replyTo.channel,
135
+ [factoryReplyAddressAttribute]: task.replyTo.address,
136
+ },
137
+ },
138
+ current: {
139
+ principalId: "operator",
140
+ attributes: {
141
+ [factoryReplyChannelAttribute]: task.replyTo.channel,
142
+ [factoryReplyAddressAttribute]: task.replyTo.address,
143
+ },
144
+ },
145
+ },
146
+ },
147
+ } as unknown as ToolContext;
148
+ const answered = await tools.answer_question.execute(
149
+ { questionTaskId: question.id, answer: "staging" },
150
+ conversationContext,
151
+ );
152
+ if (
153
+ answered.questionTask.state !== "succeeded" ||
154
+ answered.parentTask?.state !== "queued" ||
155
+ answered.parentTask.attempt !== 2
156
+ ) {
157
+ throw new Error("The authenticated answer did not queue a replacement attempt");
158
+ }
159
+
160
+ await sweepQueued(stores, { launchers });
161
+ const replacement = await stores.tasks.get(task.id);
162
+ const resumedAssignment = assignmentMessages[1];
163
+ if (
164
+ replacement?.state !== "running" ||
165
+ replacement.attempt !== 2 ||
166
+ resumedAssignment === undefined ||
167
+ !resumedAssignment.includes("Which environment should receive the deployment?") ||
168
+ !resumedAssignment.includes("Answer: staging")
169
+ ) {
170
+ throw new Error("The resumed Eve attempt did not start");
171
+ }
172
+ const selectedEnvironment = resumedAssignment.match(/Answer: (staging|production)/u)?.[1];
173
+ if (selectedEnvironment === undefined)
174
+ throw new Error("The replacement assignment lost the answer");
175
+ const finish = await tools.finish_task.execute(
176
+ { taskId: replacement.id, summary: `Deployed to ${selectedEnvironment}` },
177
+ workerContext(replacement),
178
+ );
179
+ if (!finish.finished) throw new Error(finish.reason);
180
+ const completed = await stores.tasks.get(task.id);
181
+ if (completed?.state !== "succeeded" || startedSessions.length !== 2) {
182
+ throw new Error("The resumed Task did not complete");
183
+ }
184
+
185
+ console.log(
186
+ JSON.stringify({
187
+ answer: answered.answerEvent.answer,
188
+ attempts: completed.attempt,
189
+ state: completed.state,
190
+ }),
191
+ );
192
+ ```
193
+
194
+ <!-- runnable-example:end -->
195
+
196
+ The original Eve session cannot resume the Task: answering increments the attempt, and the next
197
+ `sweepQueued` pass starts a replacement session on the same exact route. Build every replacement
198
+ assignment from the parent's immutable `answerEventIds`, as shown here, so the new Eve session sees
199
+ the question and authenticated answer. Present the persisted QuestionTask through the parent
200
+ Task's `replyTo` channel, and invoke `answer_question` only from that conversation's authenticated
201
+ callback.
202
+
203
+ Use `closingOptions` for answers that mean retrying cannot help. Choosing one cancels the parent
204
+ instead of queuing another attempt.