@vercel/factory 0.0.13 → 0.0.15

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 (458) hide show
  1. package/README.md +307 -1
  2. package/dist/agent-routes.d.mts +69 -0
  3. package/dist/agent-routes.mjs +64 -0
  4. package/dist/agent-routes.mjs.map +1 -0
  5. package/dist/api-contracts.d.mts +1749 -0
  6. package/dist/api-contracts.mjs +118 -0
  7. package/dist/api-contracts.mjs.map +1 -0
  8. package/dist/api-images.d.mts +30 -0
  9. package/dist/api-images.mjs +28 -0
  10. package/dist/api-images.mjs.map +1 -0
  11. package/dist/api-task-graph.mjs +57 -0
  12. package/dist/api-task-graph.mjs.map +1 -0
  13. package/dist/api.d.mts +77 -0
  14. package/dist/api.mjs +1087 -0
  15. package/dist/api.mjs.map +1 -0
  16. package/dist/approval-access.d.mts +39 -0
  17. package/dist/approval-access.mjs +62 -0
  18. package/dist/approval-access.mjs.map +1 -0
  19. package/dist/approval-contracts.d.mts +692 -0
  20. package/dist/approval-contracts.mjs +27 -0
  21. package/dist/approval-contracts.mjs.map +1 -0
  22. package/dist/approval.d.mts +49 -0
  23. package/dist/approval.mjs +39 -0
  24. package/dist/approval.mjs.map +1 -0
  25. package/dist/blob/artifacts.d.mts +37 -0
  26. package/dist/blob/artifacts.mjs +45 -0
  27. package/dist/blob/artifacts.mjs.map +1 -0
  28. package/dist/blob/index.d.mts +44 -8
  29. package/dist/blob/index.mjs +159 -35
  30. package/dist/blob/index.mjs.map +1 -1
  31. package/dist/budget.d.mts +108 -0
  32. package/dist/budget.mjs +141 -0
  33. package/dist/budget.mjs.map +1 -0
  34. package/dist/budgets.d.mts +4 -0
  35. package/dist/budgets.mjs +4 -0
  36. package/dist/build-factory.d.mts +6 -4
  37. package/dist/build-factory.mjs +2 -1
  38. package/dist/build-factory.mjs.map +1 -1
  39. package/dist/change-verification/brief.d.mts +9 -0
  40. package/dist/change-verification/brief.mjs +13 -0
  41. package/dist/change-verification/brief.mjs.map +1 -0
  42. package/dist/change-verification/dispatch.d.mts +24 -0
  43. package/dist/change-verification/dispatch.mjs +45 -0
  44. package/dist/change-verification/dispatch.mjs.map +1 -0
  45. package/dist/change-verification/eve-tool.d.mts +60 -0
  46. package/dist/change-verification/eve-tool.mjs +101 -0
  47. package/dist/change-verification/eve-tool.mjs.map +1 -0
  48. package/dist/changes/eve-record-change.d.mts +56 -0
  49. package/dist/changes/eve-record-change.mjs +97 -0
  50. package/dist/changes/eve-record-change.mjs.map +1 -0
  51. package/dist/changes/presentation.d.mts +14 -0
  52. package/dist/changes.d.mts +23 -0
  53. package/dist/changes.mjs +29 -0
  54. package/dist/changes.mjs.map +1 -0
  55. package/dist/client-events.d.mts +18 -0
  56. package/dist/client-events.mjs +41 -0
  57. package/dist/client-events.mjs.map +1 -0
  58. package/dist/client-stream.d.mts +28 -0
  59. package/dist/client-stream.mjs +204 -0
  60. package/dist/client-stream.mjs.map +1 -0
  61. package/dist/client-transcript.d.mts +41 -0
  62. package/dist/client-transcript.mjs +229 -0
  63. package/dist/client-transcript.mjs.map +1 -0
  64. package/dist/client.d.mts +234 -0
  65. package/dist/client.mjs +258 -0
  66. package/dist/client.mjs.map +1 -0
  67. package/dist/code-review/contracts.d.mts +26 -0
  68. package/dist/code-review/eve-post-review.d.mts +70 -0
  69. package/dist/code-review/eve-post-review.mjs +183 -0
  70. package/dist/code-review/eve-post-review.mjs.map +1 -0
  71. package/dist/code-review/eve-review-comments.d.mts +64 -0
  72. package/dist/code-review/eve-review-comments.mjs +159 -0
  73. package/dist/code-review/eve-review-comments.mjs.map +1 -0
  74. package/dist/code-review/github-contracts.d.mts +10 -0
  75. package/dist/code-review/github-reporter.d.mts +44 -0
  76. package/dist/code-review/github-reporter.mjs +260 -0
  77. package/dist/code-review/github-reporter.mjs.map +1 -0
  78. package/dist/code-review/preparation.d.mts +34 -0
  79. package/dist/code-review/preparation.mjs +23 -0
  80. package/dist/code-review/preparation.mjs.map +1 -0
  81. package/dist/code-review/stall.d.mts +17 -0
  82. package/dist/code-review/stall.mjs +30 -0
  83. package/dist/code-review/stall.mjs.map +1 -0
  84. package/dist/code-review.d.mts +6 -0
  85. package/dist/code-review.mjs +5 -0
  86. package/dist/communication.d.mts +9 -0
  87. package/dist/communication.mjs +9 -0
  88. package/dist/connectors/github.d.mts +26 -0
  89. package/dist/connectors/github.mjs +55 -0
  90. package/dist/connectors/github.mjs.map +1 -0
  91. package/dist/connectors/index.d.mts +35 -2
  92. package/dist/connectors/index.mjs +4 -26
  93. package/dist/connectors/index.mjs.map +1 -1
  94. package/dist/connectors/outbox.d.mts +34 -0
  95. package/dist/connectors/outbox.mjs +50 -0
  96. package/dist/connectors/outbox.mjs.map +1 -0
  97. package/dist/connectors/slack-approval-blocks.mjs +136 -0
  98. package/dist/connectors/slack-approval-blocks.mjs.map +1 -0
  99. package/dist/connectors/slack-approvals.d.mts +29 -0
  100. package/dist/connectors/slack-approvals.mjs +346 -0
  101. package/dist/connectors/slack-approvals.mjs.map +1 -0
  102. package/dist/connectors/slack.d.mts +35 -41
  103. package/dist/connectors/slack.mjs +13 -69
  104. package/dist/connectors/slack.mjs.map +1 -1
  105. package/dist/deepsec/eve-tool.d.mts +110 -0
  106. package/dist/deepsec/eve-tool.mjs +164 -0
  107. package/dist/deepsec/eve-tool.mjs.map +1 -0
  108. package/dist/deepsec/finding.d.mts +84 -0
  109. package/dist/deepsec/finding.mjs +56 -0
  110. package/dist/deepsec/finding.mjs.map +1 -0
  111. package/dist/deepsec.d.mts +3 -0
  112. package/dist/delivery-metrics/metrics.d.mts +93 -0
  113. package/dist/delivery-metrics/metrics.mjs +200 -0
  114. package/dist/delivery-metrics/metrics.mjs.map +1 -0
  115. package/dist/delivery-metrics.d.mts +2 -0
  116. package/dist/delivery-metrics.mjs +2 -0
  117. package/dist/dispatch.d.mts +81 -0
  118. package/dist/dispatch.mjs +140 -0
  119. package/dist/dispatch.mjs.map +1 -0
  120. package/dist/errors.d.mts +15 -0
  121. package/dist/errors.mjs +38 -0
  122. package/dist/errors.mjs.map +1 -0
  123. package/dist/eve/index.d.mts +143 -1561
  124. package/dist/eve/index.mjs +244 -1063
  125. package/dist/eve/index.mjs.map +1 -1
  126. package/dist/eve/invoke.d.mts +144 -0
  127. package/dist/eve/invoke.mjs +241 -0
  128. package/dist/eve/invoke.mjs.map +1 -0
  129. package/dist/eve/session-client.d.mts +68 -0
  130. package/dist/eve/session-client.mjs +131 -0
  131. package/dist/eve/session-client.mjs.map +1 -0
  132. package/dist/eve/task-execution.mjs +18 -0
  133. package/dist/eve/task-execution.mjs.map +1 -0
  134. package/dist/eve/task-session.d.mts +87 -0
  135. package/dist/eve/task-session.mjs +203 -0
  136. package/dist/eve/task-session.mjs.map +1 -0
  137. package/dist/eve/transcript.d.mts +37 -0
  138. package/dist/eve/transcript.mjs +65 -0
  139. package/dist/eve/transcript.mjs.map +1 -0
  140. package/dist/execution-public.d.mts +8 -0
  141. package/dist/execution-public.mjs +7 -0
  142. package/dist/execution.d.mts +75 -0
  143. package/dist/execution.mjs +153 -0
  144. package/dist/execution.mjs.map +1 -0
  145. package/dist/finding-remediation/admission.d.mts +51 -0
  146. package/dist/finding-remediation/admission.mjs +87 -0
  147. package/dist/finding-remediation/admission.mjs.map +1 -0
  148. package/dist/finding-remediation/brief.d.mts +14 -0
  149. package/dist/finding-remediation/brief.mjs +25 -0
  150. package/dist/finding-remediation/brief.mjs.map +1 -0
  151. package/dist/finding-remediation/eve-tool.d.mts +29 -0
  152. package/dist/finding-remediation/eve-tool.mjs +34 -0
  153. package/dist/finding-remediation/eve-tool.mjs.map +1 -0
  154. package/dist/findings/fingerprint.d.mts +14 -0
  155. package/dist/findings/fingerprint.mjs +28 -0
  156. package/dist/findings/fingerprint.mjs.map +1 -0
  157. package/dist/findings.d.mts +6 -0
  158. package/dist/findings.mjs +6 -0
  159. package/dist/github-app.d.mts +54 -0
  160. package/dist/github-app.mjs +121 -0
  161. package/dist/github-app.mjs.map +1 -0
  162. package/dist/github-publication.d.mts +198 -0
  163. package/dist/github-publication.mjs +429 -0
  164. package/dist/github-publication.mjs.map +1 -0
  165. package/dist/github-transfer.d.mts +72 -0
  166. package/dist/github-transfer.mjs +125 -0
  167. package/dist/github-transfer.mjs.map +1 -0
  168. package/dist/github.d.mts +406 -2
  169. package/dist/github.mjs +250 -37
  170. package/dist/github.mjs.map +1 -1
  171. package/dist/image-input.d.mts +51 -0
  172. package/dist/image-input.mjs +63 -0
  173. package/dist/image-input.mjs.map +1 -0
  174. package/dist/index.d.mts +14 -314
  175. package/dist/index.mjs +14 -1124
  176. package/dist/intake-contracts.d.mts +56 -0
  177. package/dist/intake-contracts.mjs +33 -0
  178. package/dist/intake-contracts.mjs.map +1 -0
  179. package/dist/integrations/deepsec.d.mts +4 -0
  180. package/dist/integrations/deepsec.mjs +3 -0
  181. package/dist/integrations/github.d.mts +11 -0
  182. package/dist/integrations/github.mjs +9 -0
  183. package/dist/integrations/slack.d.mts +3 -0
  184. package/dist/integrations/slack.mjs +3 -0
  185. package/dist/integrations/vercel.d.mts +3 -0
  186. package/dist/integrations/vercel.mjs +3 -0
  187. package/dist/merge-resolution/contracts.d.mts +17 -0
  188. package/dist/merge-resolution/contracts.mjs +19 -0
  189. package/dist/merge-resolution/contracts.mjs.map +1 -0
  190. package/dist/merge-resolution/eve-tools.d.mts +46 -0
  191. package/dist/merge-resolution/eve-tools.mjs +117 -0
  192. package/dist/merge-resolution/eve-tools.mjs.map +1 -0
  193. package/dist/multi-repository-changes/coordination.d.mts +49 -0
  194. package/dist/multi-repository-changes/coordination.mjs +115 -0
  195. package/dist/multi-repository-changes/coordination.mjs.map +1 -0
  196. package/dist/planning/cancellation.mjs +82 -0
  197. package/dist/planning/cancellation.mjs.map +1 -0
  198. package/dist/planning/configuration.d.mts +23 -0
  199. package/dist/planning/configuration.mjs +56 -0
  200. package/dist/planning/configuration.mjs.map +1 -0
  201. package/dist/planning/contracts.d.mts +136 -0
  202. package/dist/planning/contracts.mjs +42 -0
  203. package/dist/planning/contracts.mjs.map +1 -0
  204. package/dist/planning/dependencies.mjs +44 -0
  205. package/dist/planning/dependencies.mjs.map +1 -0
  206. package/dist/planning/effects.mjs +122 -0
  207. package/dist/planning/effects.mjs.map +1 -0
  208. package/dist/planning/reconcile.mjs +273 -0
  209. package/dist/planning/reconcile.mjs.map +1 -0
  210. package/dist/planning/runtime.d.mts +27 -0
  211. package/dist/planning/runtime.mjs +25 -0
  212. package/dist/planning/runtime.mjs.map +1 -0
  213. package/dist/planning/state.mjs +92 -0
  214. package/dist/planning/state.mjs.map +1 -0
  215. package/dist/planning/turns.mjs +262 -0
  216. package/dist/planning/turns.mjs.map +1 -0
  217. package/dist/planning/validation.mjs +106 -0
  218. package/dist/planning/validation.mjs.map +1 -0
  219. package/dist/postgres/index.d.mts +7 -1
  220. package/dist/postgres/index.mjs +7 -3
  221. package/dist/postgres/index.mjs.map +1 -1
  222. package/dist/presets/software-development/approval.d.mts +14 -0
  223. package/dist/presets/software-development/approval.mjs +21 -0
  224. package/dist/presets/software-development/approval.mjs.map +1 -0
  225. package/dist/presets/software-development/deepsec-brief.d.mts +8 -0
  226. package/dist/presets/software-development/deepsec-brief.mjs +14 -0
  227. package/dist/presets/software-development/deepsec-brief.mjs.map +1 -0
  228. package/dist/presets/software-development/dispatch.d.mts +53 -0
  229. package/dist/presets/software-development/dispatch.mjs +66 -0
  230. package/dist/presets/software-development/dispatch.mjs.map +1 -0
  231. package/dist/presets/software-development/eve-delegation-policy.d.mts +7 -0
  232. package/dist/presets/software-development/eve-delegation-policy.mjs +34 -0
  233. package/dist/presets/software-development/eve-delegation-policy.mjs.map +1 -0
  234. package/dist/presets/software-development/eve.d.mts +18 -0
  235. package/dist/presets/software-development/eve.mjs +19 -0
  236. package/dist/presets/software-development/eve.mjs.map +1 -0
  237. package/dist/presets/software-development/finish-task-policy.d.mts +7 -0
  238. package/dist/presets/software-development/finish-task-policy.mjs +9 -0
  239. package/dist/presets/software-development/finish-task-policy.mjs.map +1 -0
  240. package/dist/presets/software-development/recovery.d.mts +32 -0
  241. package/dist/presets/software-development/recovery.mjs +120 -0
  242. package/dist/presets/software-development/recovery.mjs.map +1 -0
  243. package/dist/presets/software-development/task-communication.d.mts +23 -0
  244. package/dist/presets/software-development/task-communication.mjs +120 -0
  245. package/dist/presets/software-development/task-communication.mjs.map +1 -0
  246. package/dist/presets/software-development.d.mts +9 -0
  247. package/dist/presets/software-development.mjs +9 -0
  248. package/dist/pull-requests/contracts.d.mts +72 -0
  249. package/dist/pull-requests/eve-fetch.d.mts +57 -0
  250. package/dist/pull-requests/eve-fetch.mjs +151 -0
  251. package/dist/pull-requests/eve-fetch.mjs.map +1 -0
  252. package/dist/pull-requests/github-label-manager.d.mts +27 -0
  253. package/dist/pull-requests/github-label-manager.mjs +40 -0
  254. package/dist/pull-requests/github-label-manager.mjs.map +1 -0
  255. package/dist/pull-requests/github-publisher.d.mts +53 -0
  256. package/dist/pull-requests/github-publisher.mjs +345 -0
  257. package/dist/pull-requests/github-publisher.mjs.map +1 -0
  258. package/dist/pull-requests.d.mts +5 -0
  259. package/dist/pull-requests.mjs +4 -0
  260. package/dist/receipts.d.mts +4 -0
  261. package/dist/receipts.mjs +3 -0
  262. package/dist/repositories.d.mts +18 -0
  263. package/dist/repositories.mjs +33 -0
  264. package/dist/repositories.mjs.map +1 -0
  265. package/dist/sandbox/command.d.mts +18 -0
  266. package/dist/sandbox/execution-abort.d.mts +16 -0
  267. package/dist/sandbox/execution-abort.mjs +49 -0
  268. package/dist/sandbox/execution-abort.mjs.map +1 -0
  269. package/dist/sandbox/execution-environment.d.mts +25 -0
  270. package/dist/sandbox/execution-run-ledger.d.mts +115 -0
  271. package/dist/sandbox/execution-run-ledger.mjs +209 -0
  272. package/dist/sandbox/execution-run-ledger.mjs.map +1 -0
  273. package/dist/sandbox/execution.d.mts +54 -0
  274. package/dist/sandbox/execution.mjs +228 -0
  275. package/dist/sandbox/execution.mjs.map +1 -0
  276. package/dist/sandbox/harness-runner.d.mts +79 -0
  277. package/dist/sandbox/harness-runner.mjs +162 -0
  278. package/dist/sandbox/harness-runner.mjs.map +1 -0
  279. package/dist/sandbox/index.d.mts +9 -0
  280. package/dist/sandbox/index.mjs +7 -0
  281. package/dist/sandbox/task-environment.d.mts +50 -0
  282. package/dist/sandbox/task-environment.mjs +140 -0
  283. package/dist/sandbox/task-environment.mjs.map +1 -0
  284. package/dist/sandbox/workspace.d.mts +29 -0
  285. package/dist/sandbox/workspace.mjs +28 -0
  286. package/dist/sandbox/workspace.mjs.map +1 -0
  287. package/dist/schema/agent-route.d.mts +22 -0
  288. package/dist/schema/agent-route.mjs +15 -0
  289. package/dist/schema/agent-route.mjs.map +1 -0
  290. package/dist/schema/answer.d.mts +23 -0
  291. package/dist/schema/answer.mjs +21 -0
  292. package/dist/schema/answer.mjs.map +1 -0
  293. package/dist/schema/budget.d.mts +38 -0
  294. package/dist/schema/budget.mjs +30 -0
  295. package/dist/schema/budget.mjs.map +1 -0
  296. package/dist/schema/catalog.mjs +72 -0
  297. package/dist/schema/catalog.mjs.map +1 -0
  298. package/dist/schema/change.d.mts +117 -0
  299. package/dist/schema/change.mjs +68 -0
  300. package/dist/schema/change.mjs.map +1 -0
  301. package/dist/schema/common.d.mts +33 -0
  302. package/dist/{id-DwCihQr4.mjs → schema/common.mjs} +7 -14
  303. package/dist/schema/common.mjs.map +1 -0
  304. package/dist/schema/communication.d.mts +52 -0
  305. package/dist/schema/communication.mjs +35 -0
  306. package/dist/schema/communication.mjs.map +1 -0
  307. package/dist/schema/execution.d.mts +101 -0
  308. package/dist/schema/execution.mjs +86 -0
  309. package/dist/schema/execution.mjs.map +1 -0
  310. package/dist/schema/factory-config.d.mts +95 -0
  311. package/dist/schema/factory-config.mjs +60 -0
  312. package/dist/schema/factory-config.mjs.map +1 -0
  313. package/dist/schema/finding.d.mts +125 -0
  314. package/dist/schema/finding.mjs +67 -0
  315. package/dist/schema/finding.mjs.map +1 -0
  316. package/dist/schema/id.d.mts +43 -0
  317. package/dist/schema/id.mjs +32 -0
  318. package/dist/schema/id.mjs.map +1 -0
  319. package/dist/schema/outbox.d.mts +240 -0
  320. package/dist/schema/outbox.mjs +53 -0
  321. package/dist/schema/outbox.mjs.map +1 -0
  322. package/dist/schema/question-route.mjs +16 -0
  323. package/dist/schema/question-route.mjs.map +1 -0
  324. package/dist/schema/receipt.d.mts +81 -0
  325. package/dist/schema/receipt.mjs +94 -0
  326. package/dist/schema/receipt.mjs.map +1 -0
  327. package/dist/schema/repository.d.mts +26 -0
  328. package/dist/schema/repository.mjs +25 -0
  329. package/dist/schema/repository.mjs.map +1 -0
  330. package/dist/schema/session.d.mts +135 -0
  331. package/dist/schema/session.mjs +53 -0
  332. package/dist/schema/session.mjs.map +1 -0
  333. package/dist/schema/signal.d.mts +105 -0
  334. package/dist/schema/signal.mjs +81 -0
  335. package/dist/schema/signal.mjs.map +1 -0
  336. package/dist/schema/stored-session.mjs +10 -0
  337. package/dist/schema/stored-session.mjs.map +1 -0
  338. package/dist/schema/stored-task.mjs +20 -0
  339. package/dist/schema/stored-task.mjs.map +1 -0
  340. package/dist/schema/task-effect.d.mts +39 -0
  341. package/dist/schema/task-effect.mjs +29 -0
  342. package/dist/schema/task-effect.mjs.map +1 -0
  343. package/dist/schema/task-graph.d.mts +3134 -0
  344. package/dist/schema/task-graph.mjs +97 -0
  345. package/dist/schema/task-graph.mjs.map +1 -0
  346. package/dist/schema/task-message.d.mts +254 -0
  347. package/dist/schema/task-message.mjs +189 -0
  348. package/dist/schema/task-message.mjs.map +1 -0
  349. package/dist/schema/task.d.mts +272 -0
  350. package/dist/schema/task.mjs +199 -0
  351. package/dist/schema/task.mjs.map +1 -0
  352. package/dist/schema/transcript.d.mts +170 -0
  353. package/dist/schema/transcript.mjs +86 -0
  354. package/dist/schema/transcript.mjs.map +1 -0
  355. package/dist/schema/transitions.d.mts +50 -0
  356. package/dist/schema/transitions.mjs +303 -0
  357. package/dist/schema/transitions.mjs.map +1 -0
  358. package/dist/schema/work.d.mts +101 -0
  359. package/dist/schema/work.mjs +102 -0
  360. package/dist/schema/work.mjs.map +1 -0
  361. package/dist/signal-triage.d.mts +20 -0
  362. package/dist/signal-triage.mjs +85 -0
  363. package/dist/signal-triage.mjs.map +1 -0
  364. package/dist/signals.d.mts +19 -0
  365. package/dist/signals.mjs +19 -0
  366. package/dist/signals.mjs.map +1 -0
  367. package/dist/stall.d.mts +38 -0
  368. package/dist/stall.mjs +79 -0
  369. package/dist/stall.mjs.map +1 -0
  370. package/dist/storage.d.mts +4 -0
  371. package/dist/storage.mjs +4 -0
  372. package/dist/store/driver.d.mts +65 -0
  373. package/dist/store/driver.mjs +42 -0
  374. package/dist/store/driver.mjs.map +1 -0
  375. package/dist/store/engine.d.mts +485 -0
  376. package/dist/store/engine.mjs +2175 -0
  377. package/dist/store/engine.mjs.map +1 -0
  378. package/dist/store/memory.d.mts +7 -0
  379. package/dist/store/memory.mjs +52 -0
  380. package/dist/store/memory.mjs.map +1 -0
  381. package/dist/store/task-effects.d.mts +38 -0
  382. package/dist/store/task-effects.mjs +118 -0
  383. package/dist/store/task-effects.mjs.map +1 -0
  384. package/dist/store/task-graphs.d.mts +60 -0
  385. package/dist/store/task-graphs.mjs +212 -0
  386. package/dist/store/task-graphs.mjs.map +1 -0
  387. package/dist/store/task-messages.d.mts +136 -0
  388. package/dist/store/task-messages.mjs +475 -0
  389. package/dist/store/task-messages.mjs.map +1 -0
  390. package/dist/store/task-work.d.mts +65 -0
  391. package/dist/store/task-work.mjs +134 -0
  392. package/dist/store/task-work.mjs.map +1 -0
  393. package/dist/store/work-notifications.d.mts +19 -0
  394. package/dist/store/work-notifications.mjs +48 -0
  395. package/dist/store/work-notifications.mjs.map +1 -0
  396. package/dist/sweep.d.mts +57 -0
  397. package/dist/sweep.mjs +143 -0
  398. package/dist/sweep.mjs.map +1 -0
  399. package/dist/task-communication.d.mts +35 -0
  400. package/dist/task-communication.mjs +47 -0
  401. package/dist/task-communication.mjs.map +1 -0
  402. package/dist/task-graph-view.d.mts +264 -0
  403. package/dist/task-graph-view.mjs +17 -0
  404. package/dist/task-graph-view.mjs.map +1 -0
  405. package/dist/task-message-processing.d.mts +60 -0
  406. package/dist/task-message-processing.mjs +200 -0
  407. package/dist/task-message-processing.mjs.map +1 -0
  408. package/dist/task-protocols.d.mts +80 -0
  409. package/dist/task-protocols.mjs +47 -0
  410. package/dist/task-protocols.mjs.map +1 -0
  411. package/dist/tasks.d.mts +17 -0
  412. package/dist/tasks.mjs +17 -0
  413. package/dist/vercel-git.d.mts +21 -0
  414. package/dist/vercel-git.mjs +112 -0
  415. package/dist/vercel-git.mjs.map +1 -0
  416. package/dist/vercel.d.mts +33 -2
  417. package/dist/vercel.mjs +48 -3
  418. package/dist/vercel.mjs.map +1 -1
  419. package/dist/work-triage/eve-tool.d.mts +29 -0
  420. package/dist/work-triage/eve-tool.mjs +32 -0
  421. package/dist/work-triage/eve-tool.mjs.map +1 -0
  422. package/dist/work-triage/find-existing-work.d.mts +32 -0
  423. package/dist/work-triage/find-existing-work.mjs +31 -0
  424. package/dist/work-triage/find-existing-work.mjs.map +1 -0
  425. package/dist/work-triage/github.d.mts +15 -0
  426. package/dist/work-triage/github.mjs +14 -0
  427. package/dist/work-triage/github.mjs.map +1 -0
  428. package/dist/work-triage.d.mts +3 -0
  429. package/dist/work-triage.mjs +3 -0
  430. package/dist/workflows.d.mts +48 -0
  431. package/dist/workflows.mjs +86 -0
  432. package/dist/workflows.mjs.map +1 -0
  433. package/dist/workspace-diff-assembly.d.mts +33 -0
  434. package/dist/workspace-diff-assembly.mjs +95 -0
  435. package/dist/workspace-diff-assembly.mjs.map +1 -0
  436. package/dist/workspace-diff.d.mts +90 -0
  437. package/dist/workspace-diff.mjs +61 -0
  438. package/dist/workspace-diff.mjs.map +1 -0
  439. package/dist/workspace-snapshot.d.mts +26 -0
  440. package/dist/workspace-snapshot.mjs +80 -0
  441. package/dist/workspace-snapshot.mjs.map +1 -0
  442. package/package.json +129 -40
  443. package/dist/approval-CwhTP1XB.mjs +0 -269
  444. package/dist/approval-CwhTP1XB.mjs.map +0 -1
  445. package/dist/change-CzEAoFVE.mjs +0 -620
  446. package/dist/change-CzEAoFVE.mjs.map +0 -1
  447. package/dist/dispatch-B77cuPxh.d.mts +0 -713
  448. package/dist/driver-BJutB0PE.d.mts +0 -34
  449. package/dist/driver-Bbd25rNM.mjs +0 -23
  450. package/dist/driver-Bbd25rNM.mjs.map +0 -1
  451. package/dist/factory-config-BJcjsPKl.mjs +0 -86
  452. package/dist/factory-config-BJcjsPKl.mjs.map +0 -1
  453. package/dist/factory-config-D2yU3G0c.d.mts +0 -58
  454. package/dist/github-DXsxboUL.d.mts +0 -271
  455. package/dist/id-DwCihQr4.mjs.map +0 -1
  456. package/dist/index-Cy4jfXh5.d.mts +0 -67
  457. package/dist/index.mjs.map +0 -1
  458. package/dist/signal-CHVEmzvI.d.mts +0 -59
@@ -0,0 +1,241 @@
1
+ import { changeIdSchema, repositoryIdsSchema, signalIdSchema, taskIdSchema } from "../schema/id.mjs";
2
+ import { agentRouteBindingSchema, parseAgentRouteBinding } from "../schema/agent-route.mjs";
3
+ import { optionalTaskIdForSession, replyToForSession, repositoryIdsForSession } from "./task-session.mjs";
4
+ import { routeTaskWork } from "../agent-routes.mjs";
5
+ import { dispatchTask } from "../dispatch.mjs";
6
+ import { startEveSession } from "./session-client.mjs";
7
+ import { z } from "zod";
8
+ import { defineTool } from "eve/tools";
9
+ //#region src/eve/invoke.ts
10
+ /**
11
+ * A tool that lets one agent hand work to another, NMA-style: the caller
12
+ * decides to invoke; trusted code owns the how. The handoff is recorded as a
13
+ * factory task (single-winner dispatch, receipts), then a fresh session is
14
+ * started on the target agent carrying only the task id — never the caller's
15
+ * context. The session start is create-once on the task attempt, so a retried
16
+ * launch cannot duplicate that attempt while a later attempt starts fresh.
17
+ */
18
+ function createInvokeAgentTool(stores, options) {
19
+ const doFetch = options.fetch ?? fetch;
20
+ return defineTool({
21
+ description: `${options.description} Hands the work to a separate agent in a fresh session; you will not see its reasoning. Returns the handoff task id.`,
22
+ inputSchema: z.object({
23
+ repositoryIds: repositoryIdsSchema,
24
+ parentTaskId: taskIdSchema.optional().describe("Your own task, when this work continues it."),
25
+ changeId: changeIdSchema.optional().describe("The change the target agent should work on."),
26
+ channel: z.string().min(1).describe("Reply connector, e.g. github."),
27
+ address: z.string().min(1).describe("Reply address, e.g. acme/web#41."),
28
+ brief: z.string().min(1).max(4e3).describe("What the target agent needs to know. Facts and references only, not your reasoning.")
29
+ }),
30
+ async execute(input) {
31
+ const taskInput = {
32
+ repositoryIds: input.repositoryIds,
33
+ kind: options.route.taskKind,
34
+ work: routeTaskWork({
35
+ route: options.route,
36
+ title: input.brief.trim().slice(0, 256),
37
+ input: { brief: input.brief }
38
+ }),
39
+ changeId: input.changeId,
40
+ replyTo: {
41
+ channel: input.channel,
42
+ address: input.address
43
+ }
44
+ };
45
+ const task = await stores.tasks.create(input.parentTaskId === void 0 ? {
46
+ ...taskInput,
47
+ origin: { operator: "factory" }
48
+ } : {
49
+ ...taskInput,
50
+ origin: {},
51
+ parentTaskId: input.parentTaskId
52
+ });
53
+ const running = await dispatchTask(stores, {
54
+ taskId: task.id,
55
+ route: options.route,
56
+ maxLaunchAttempts: 1,
57
+ budget: options.budget?.(),
58
+ launch: async (dispatched) => {
59
+ const headers = new Headers(await options.headers?.(dispatched));
60
+ headers.set("content-type", "application/json");
61
+ const token = await options.token?.();
62
+ if (token !== void 0) headers.set("authorization", `Bearer ${token}`);
63
+ const message = [
64
+ `You are assigned factory task ${dispatched.id}.`,
65
+ input.changeId === void 0 ? null : `Change under review: ${input.changeId}.`,
66
+ `Reply address: ${input.channel} ${input.address}.`,
67
+ "",
68
+ input.brief,
69
+ "",
70
+ "Read the task with get_task first, do the work, and record the outcome with your factory tools."
71
+ ].filter((line) => line !== null).join("\n");
72
+ return startEveSession({
73
+ agentUrl: options.targetUrl(),
74
+ agentName: "target agent",
75
+ headers,
76
+ message,
77
+ operationId: `factory-task:${dispatched.id}:${dispatched.attempt}`,
78
+ fetch: doFetch
79
+ });
80
+ }
81
+ });
82
+ return {
83
+ taskId: running.id,
84
+ kind: running.kind,
85
+ state: running.state
86
+ };
87
+ }
88
+ });
89
+ }
90
+ /**
91
+ * Give a conversational agent one bounded delegation surface backed by the
92
+ * application's route registry. The caller selects a declared route; trusted
93
+ * code owns task creation, budget enforcement, and the fresh target session.
94
+ */
95
+ function createDelegateAgentTool(stores, options) {
96
+ const doFetch = options.fetch ?? fetch;
97
+ const routeSummary = options.routes.routes.map((route) => `${route.id}@${route.version}: ${route.description}`).join("\n");
98
+ return defineTool({
99
+ description: "Delegate durable work to one registered specialist. Select only a listed route; the specialist runs independently and reports its result through Factory.\n" + routeSummary,
100
+ inputSchema: z.object({
101
+ route: agentRouteBindingSchema.describe("Exact route id and version listed in this tool's description."),
102
+ repositoryIds: repositoryIdsSchema.refine((repositoryIds) => new Set(repositoryIds).size === repositoryIds.length, "Repository ids must be unique."),
103
+ signalId: signalIdSchema.optional().describe("Pending external signal this delegation accepts."),
104
+ parentTaskId: taskIdSchema.optional().describe("Existing task this work continues."),
105
+ changeId: changeIdSchema.optional().describe("Existing change the specialist should inspect."),
106
+ channel: z.string().min(1).describe("Originating conversation channel."),
107
+ address: z.string().min(1).describe("Originating conversation reply address."),
108
+ brief: z.string().min(1).max(4e3).describe("Facts and desired outcome, without hidden reasoning.")
109
+ }),
110
+ async execute(input, ctx) {
111
+ const route = options.routes.get(input.route);
112
+ if (route === void 0) throw new Error(`Unknown agent route ${input.route.id}@${input.route.version}.`);
113
+ const replyTo = {
114
+ channel: input.channel,
115
+ address: input.address
116
+ };
117
+ const auth = ctx.session.auth.initiator;
118
+ const attributes = auth?.attributes;
119
+ const boundRepositoryIds = repositoryIdsForSession(auth);
120
+ if (boundRepositoryIds !== null && input.repositoryIds.some((id) => !boundRepositoryIds.includes(id))) throw new Error("Delegation includes a repository outside the connector-authenticated context.");
121
+ const boundReplyTo = replyToForSession(auth);
122
+ if (boundReplyTo !== null && (boundReplyTo.channel !== replyTo.channel || boundReplyTo.address !== replyTo.address)) throw new Error("Delegation reply address does not match the authenticated conversation.");
123
+ for (const repositoryId of input.repositoryIds) {
124
+ const repository = await stores.repositories.get(repositoryId);
125
+ if (repository === null || !repository.enabled) throw new Error(`Repository ${repositoryId} is not enabled in this factory.`);
126
+ }
127
+ const boundChange = changeIdSchema.safeParse(attributes?.factoryChangeId);
128
+ if (attributes?.factoryChangeId !== void 0 && !boundChange.success) throw new Error("Connector-authenticated change context is invalid.");
129
+ if (input.changeId !== void 0 && boundChange.success && input.changeId !== boundChange.data) throw new Error("Delegated change does not match the connector-authenticated context.");
130
+ const changeId = input.changeId ?? (boundChange.success ? boundChange.data : void 0);
131
+ if (changeId !== void 0) {
132
+ if (input.repositoryIds.length !== 1) throw new Error("Delegating work on an existing Change requires exactly one repository.");
133
+ const change = await stores.changes.get(changeId);
134
+ if (change === null || change.repositoryId !== input.repositoryIds[0] || change.state !== "verifying" && change.state !== "ready") throw new Error(`Change ${changeId} is not an open pull request in the selected repository.`);
135
+ }
136
+ if (input.signalId !== void 0) {
137
+ const signal = await stores.signals.get(input.signalId);
138
+ if (signal === null) throw new Error(`Signal ${input.signalId} does not exist.`);
139
+ if (!input.repositoryIds.includes(signal.repositoryId) || signal.replyTo.channel !== replyTo.channel || signal.replyTo.address !== replyTo.address) throw new Error("Delegation does not match the signal's authenticated repository and reply address.");
140
+ if (signal.outcome === "pending") await stores.signals.decide(signal.id, {
141
+ outcome: "accepted",
142
+ reason: `Foreman selected ${route.id}.`
143
+ });
144
+ else if (signal.outcome !== "accepted") throw new Error(`Signal ${signal.id} is already ${signal.outcome}.`);
145
+ }
146
+ let parentTaskId = input.parentTaskId;
147
+ const boundTaskId = optionalTaskIdForSession(auth);
148
+ if (boundTaskId !== null && boundReplyTo?.channel === "api") {
149
+ const boundTask = await stores.tasks.get(boundTaskId);
150
+ if (boundTask?.area === "conversation") {
151
+ if (parentTaskId !== void 0 && parentTaskId !== boundTask.id) throw new Error("Follow-up delegation must name its authenticated conversation task as parent.");
152
+ parentTaskId = boundTask.id;
153
+ }
154
+ }
155
+ const operator = ctx.session.auth.initiator?.principalId ?? "foreman";
156
+ const workflowResult = await options.workflow?.({
157
+ stores,
158
+ route,
159
+ repositoryIds: input.repositoryIds,
160
+ signalId: input.signalId,
161
+ parentTaskId,
162
+ changeId,
163
+ replyTo,
164
+ brief: input.brief,
165
+ operator,
166
+ dispatch: (task) => dispatchRouteTask(stores, options, doFetch, route, task, changeId, input.brief)
167
+ });
168
+ if (workflowResult !== void 0 && workflowResult !== null) return workflowResult;
169
+ const taskInput = {
170
+ repositoryIds: input.repositoryIds,
171
+ kind: route.taskKind,
172
+ work: routeTaskWork({
173
+ route,
174
+ title: input.brief.trim().slice(0, 256),
175
+ input: { brief: input.brief }
176
+ }),
177
+ replyTo,
178
+ changeId,
179
+ ...input.signalId === void 0 ? {} : { dedupeKey: `route:${input.signalId}:${route.id}:${route.version}` }
180
+ };
181
+ const task = await stores.tasks.create(parentTaskId !== void 0 ? {
182
+ ...taskInput,
183
+ parentTaskId,
184
+ origin: {}
185
+ } : input.signalId !== void 0 ? {
186
+ ...taskInput,
187
+ origin: { signalId: input.signalId }
188
+ } : {
189
+ ...taskInput,
190
+ origin: { operator }
191
+ });
192
+ const running = task.state === "queued" ? await dispatchRouteTask(stores, options, doFetch, route, task, changeId, input.brief) : task;
193
+ return {
194
+ taskId: running.id,
195
+ route: parseAgentRouteBinding({
196
+ id: route.id,
197
+ version: route.version
198
+ }),
199
+ agent: route.agent,
200
+ state: running.state
201
+ };
202
+ }
203
+ });
204
+ }
205
+ async function dispatchRouteTask(stores, options, doFetch, route, task, changeId, brief) {
206
+ return dispatchTask(stores, {
207
+ taskId: task.id,
208
+ route,
209
+ maxLaunchAttempts: options.maxLaunchAttempts?.(route) ?? 1,
210
+ budget: options.budget?.(route),
211
+ launch: async (dispatched) => {
212
+ if (options.launch) return options.launch({
213
+ task: dispatched,
214
+ route,
215
+ brief
216
+ });
217
+ const headers = new Headers(await options.headers?.(dispatched, route));
218
+ headers.set("content-type", "application/json");
219
+ const token = await options.token?.(route);
220
+ if (token !== void 0) headers.set("authorization", `Bearer ${token}`);
221
+ const message = [
222
+ `You are assigned factory task ${dispatched.id} through route ${route.id}.`,
223
+ changeId === void 0 ? null : `Change under review: ${changeId}.`,
224
+ brief,
225
+ "Read the task first and return exactly one bounded Factory outcome."
226
+ ].filter((line) => line !== null).join("\n\n");
227
+ return startEveSession({
228
+ agentUrl: options.targetUrl(route),
229
+ agentName: route.agent,
230
+ headers,
231
+ message,
232
+ operationId: `factory-task:${dispatched.id}:${dispatched.attempt}`,
233
+ fetch: doFetch
234
+ });
235
+ }
236
+ });
237
+ }
238
+ //#endregion
239
+ export { createDelegateAgentTool, createInvokeAgentTool };
240
+
241
+ //# sourceMappingURL=invoke.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoke.mjs","names":[],"sources":["../../src/eve/invoke.ts"],"sourcesContent":["import { defineTool, type ToolContext, type ToolDefinition } from \"eve/tools\";\nimport { z } from \"zod\";\nimport {\n agentRouteBindingSchema,\n parseAgentRouteBinding,\n routeTaskWork,\n type AgentRoute,\n type AgentRouteBinding,\n type AgentRouteRegistry,\n} from \"../agent-routes\";\nimport { dispatchTask, type DispatchBudget } from \"../dispatch\";\nimport type { MaybePromise, ReplyTo } from \"../schema/common\";\nimport {\n changeIdSchema,\n repositoryIdsSchema,\n signalIdSchema,\n taskIdSchema,\n type ChangeId,\n type RepositoryId,\n type RepositoryIds,\n type SignalId,\n type TaskId,\n} from \"../schema/id\";\nimport type { ExecutionReference, Task, TaskKind, TaskState } from \"../schema/task\";\nimport type { FactoryStores } from \"../store/engine\";\nimport {\n optionalTaskIdForSession,\n repositoryIdsForSession,\n replyToForSession,\n} from \"./task-session\";\nimport { startEveSession } from \"./session-client\";\n\n/** Graph, receipt, and Task capabilities required by the fixed-route invocation tool. */\nexport type InvokeAgentToolStores = Pick<FactoryStores, \"graphs\" | \"receipts\" | \"tasks\">;\n\n/** Durable capabilities required by route-based agent delegation. */\nexport type DelegateAgentToolStores = Pick<\n FactoryStores,\n \"changes\" | \"graphs\" | \"receipts\" | \"repositories\" | \"signals\" | \"tasks\" | \"work\"\n>;\n\n/** Configures one fixed agent handoff route and its authenticated Eve session boundary. */\nexport interface InvokeAgentToolOptions {\n /** Application-selected exact route for this handoff. */\n route: AgentRoute;\n /** Model-facing description of what the target agent does and when to invoke it. */\n description: string;\n /**\n * Base URL of the target agent's eve transport, e.g.\n * `https://factory.example.com/eve/agents/verifier`. Resolved at call time so\n * a deployment can derive it from its own origin.\n */\n targetUrl: () => string;\n /** Bearer token for the target agent's eve channel, when it requires auth. */\n token?: () => MaybePromise<string | undefined>;\n /** Extra headers for the session request, e.g. a deployment protection bypass. */\n headers?: (task: Task) => MaybePromise<HeadersInit>;\n /**\n * Reserve-before-execution limits for the handoff dispatch, resolved at\n * call time. Without it, handoff tasks run outside the budget.\n */\n budget?: () => DispatchBudget | undefined;\n fetch?: typeof fetch;\n}\n\n/** Scope, lineage, reply destination, and brief supplied to a fixed-route handoff. */\nexport interface InvokeAgentToolInput {\n repositoryIds: RepositoryIds;\n parentTaskId?: TaskId;\n changeId?: ChangeId;\n channel: string;\n address: string;\n brief: string;\n}\n\n/** Durable Task identity and lifecycle returned after a fixed-route handoff launches. */\nexport interface InvokeAgentToolResult {\n readonly taskId: TaskId;\n readonly kind: TaskKind;\n readonly state: TaskState;\n}\n\n/** Eve tool that launches work through one configured exact agent route. */\nexport interface InvokeAgentTool extends ToolDefinition<\n InvokeAgentToolInput,\n InvokeAgentToolResult\n> {\n execute(input: InvokeAgentToolInput, ctx: ToolContext): Promise<InvokeAgentToolResult>;\n}\n\ninterface DelegateAgentToolCommonOptions {\n routes: AgentRouteRegistry;\n /** Retry bound for application-owned routes with a reconciler; default is one launch. */\n maxLaunchAttempts?: (route: AgentRoute) => number;\n budget?: (route: AgentRoute) => DispatchBudget | undefined;\n /** Application workflow policy that may replace single-task delegation. */\n workflow?: DelegateWorkflowPolicy;\n}\n\n/** Identifies one validated delegated Task launch on its exact registered route. */\nexport interface DelegateAgentLaunchInput {\n readonly task: Task;\n readonly route: AgentRoute;\n readonly brief: string;\n}\n\n/** Delegation mode whose application owns the provider launch boundary. */\ninterface DelegateAgentCustomLaunchOptions extends DelegateAgentToolCommonOptions {\n /** Application execution boundary, after route, scope, approval, and budget validation. */\n launch(input: DelegateAgentLaunchInput): Promise<ExecutionReference>;\n targetUrl?: never;\n token?: never;\n headers?: never;\n fetch?: never;\n}\n\n/** Delegation mode that starts a fresh session through an Eve HTTP endpoint. */\ninterface DelegateAgentEveLaunchOptions extends DelegateAgentToolCommonOptions {\n launch?: never;\n targetUrl(route: AgentRoute): string;\n token?: (route: AgentRoute) => MaybePromise<string | undefined>;\n headers?: (task: Task, route: AgentRoute) => MaybePromise<HeadersInit>;\n fetch?: typeof fetch;\n}\n\n/** Configures route-based delegation with one explicit launch mode and workflow policy. */\nexport type DelegateAgentToolOptions =\n | DelegateAgentCustomLaunchOptions\n | DelegateAgentEveLaunchOptions;\n\n/** Exact route, scope, provenance, and brief supplied to bounded agent delegation. */\nexport interface DelegateAgentToolInput {\n route: AgentRouteBinding;\n repositoryIds: RepositoryIds;\n signalId?: SignalId;\n parentTaskId?: TaskId;\n changeId?: ChangeId;\n channel: string;\n address: string;\n brief: string;\n}\n\n/** Trusted context supplied to an application-owned delegation workflow policy. */\nexport interface DelegateWorkflowInput {\n stores: DelegateAgentToolStores;\n route: AgentRoute;\n repositoryIds: readonly RepositoryId[];\n signalId?: SignalId;\n parentTaskId?: TaskId;\n changeId?: ChangeId;\n replyTo: ReplyTo;\n brief: string;\n operator: string;\n dispatch(task: Task): Promise<Task>;\n}\n\n/** Identifies the durable work and exact agent route selected by a delegation policy. */\nexport interface DelegateWorkflowResult {\n readonly taskId: TaskId;\n readonly childTaskIds?: readonly TaskId[];\n readonly route: AgentRouteBinding;\n readonly agent: string;\n readonly state: Task[\"state\"];\n}\n\n/** Eve tool that delegates durable work through a registered exact agent route. */\nexport interface DelegateAgentTool extends ToolDefinition<\n DelegateAgentToolInput,\n DelegateWorkflowResult\n> {\n execute(input: DelegateAgentToolInput, ctx: ToolContext): Promise<DelegateWorkflowResult>;\n}\n\n/** Application policy that may replace ordinary single-Task delegation with a workflow. */\nexport type DelegateWorkflowPolicy = (\n input: DelegateWorkflowInput,\n) => Promise<DelegateWorkflowResult | null>;\n\n/**\n * A tool that lets one agent hand work to another, NMA-style: the caller\n * decides to invoke; trusted code owns the how. The handoff is recorded as a\n * factory task (single-winner dispatch, receipts), then a fresh session is\n * started on the target agent carrying only the task id — never the caller's\n * context. The session start is create-once on the task attempt, so a retried\n * launch cannot duplicate that attempt while a later attempt starts fresh.\n */\nexport function createInvokeAgentTool(\n stores: InvokeAgentToolStores,\n options: InvokeAgentToolOptions,\n): InvokeAgentTool {\n const doFetch = options.fetch ?? fetch;\n return defineTool({\n description: `${options.description} Hands the work to a separate agent in a fresh session; you will not see its reasoning. Returns the handoff task id.`,\n inputSchema: z.object({\n repositoryIds: repositoryIdsSchema,\n parentTaskId: taskIdSchema.optional().describe(\"Your own task, when this work continues it.\"),\n changeId: changeIdSchema.optional().describe(\"The change the target agent should work on.\"),\n channel: z.string().min(1).describe(\"Reply connector, e.g. github.\"),\n address: z.string().min(1).describe(\"Reply address, e.g. acme/web#41.\"),\n brief: z\n .string()\n .min(1)\n .max(4000)\n .describe(\n \"What the target agent needs to know. Facts and references only, not your reasoning.\",\n ),\n }),\n async execute(input) {\n const taskInput = {\n repositoryIds: input.repositoryIds,\n kind: options.route.taskKind,\n work: routeTaskWork({\n route: options.route,\n title: input.brief.trim().slice(0, 256),\n input: {\n brief: input.brief,\n },\n }),\n changeId: input.changeId,\n replyTo: { channel: input.channel, address: input.address },\n };\n const task = await stores.tasks.create(\n input.parentTaskId === undefined\n ? { ...taskInput, origin: { operator: \"factory\" } }\n : { ...taskInput, origin: {}, parentTaskId: input.parentTaskId },\n );\n\n const running = await dispatchTask(stores, {\n taskId: task.id,\n route: options.route,\n // Handoffs are launched by the caller, not the sweep, so a refused\n // session must fail now — no sweep would pick a re-queued handoff up.\n maxLaunchAttempts: 1,\n budget: options.budget?.(),\n launch: async (dispatched) => {\n const headers = new Headers(await options.headers?.(dispatched));\n headers.set(\"content-type\", \"application/json\");\n const token = await options.token?.();\n if (token !== undefined) {\n headers.set(\"authorization\", `Bearer ${token}`);\n }\n const message = [\n `You are assigned factory task ${dispatched.id}.`,\n input.changeId === undefined ? null : `Change under review: ${input.changeId}.`,\n `Reply address: ${input.channel} ${input.address}.`,\n \"\",\n input.brief,\n \"\",\n \"Read the task with get_task first, do the work, and record the outcome with your factory tools.\",\n ]\n .filter((line) => line !== null)\n .join(\"\\n\");\n return startEveSession({\n agentUrl: options.targetUrl(),\n agentName: \"target agent\",\n headers,\n message,\n operationId: `factory-task:${dispatched.id}:${dispatched.attempt}`,\n fetch: doFetch,\n });\n },\n });\n\n return { taskId: running.id, kind: running.kind, state: running.state };\n },\n });\n}\n\n/**\n * Give a conversational agent one bounded delegation surface backed by the\n * application's route registry. The caller selects a declared route; trusted\n * code owns task creation, budget enforcement, and the fresh target session.\n */\nexport function createDelegateAgentTool(\n stores: DelegateAgentToolStores,\n options: DelegateAgentToolOptions,\n): DelegateAgentTool {\n const doFetch = options.fetch ?? fetch;\n const routeSummary = options.routes.routes\n .map((route) => `${route.id}@${route.version}: ${route.description}`)\n .join(\"\\n\");\n return defineTool({\n description:\n \"Delegate durable work to one registered specialist. Select only a listed route; \" +\n \"the specialist runs independently and reports its result through Factory.\\n\" +\n routeSummary,\n inputSchema: z.object({\n route: agentRouteBindingSchema.describe(\n \"Exact route id and version listed in this tool's description.\",\n ),\n repositoryIds: repositoryIdsSchema.refine(\n (repositoryIds) => new Set(repositoryIds).size === repositoryIds.length,\n \"Repository ids must be unique.\",\n ),\n signalId: signalIdSchema\n .optional()\n .describe(\"Pending external signal this delegation accepts.\"),\n parentTaskId: taskIdSchema.optional().describe(\"Existing task this work continues.\"),\n changeId: changeIdSchema\n .optional()\n .describe(\"Existing change the specialist should inspect.\"),\n channel: z.string().min(1).describe(\"Originating conversation channel.\"),\n address: z.string().min(1).describe(\"Originating conversation reply address.\"),\n brief: z\n .string()\n .min(1)\n .max(4000)\n .describe(\"Facts and desired outcome, without hidden reasoning.\"),\n }),\n async execute(input, ctx) {\n const route = options.routes.get(input.route);\n if (route === undefined) {\n throw new Error(`Unknown agent route ${input.route.id}@${input.route.version}.`);\n }\n const replyTo = { channel: input.channel, address: input.address };\n const auth = ctx.session.auth.initiator;\n const attributes = auth?.attributes;\n const boundRepositoryIds = repositoryIdsForSession(auth);\n if (\n boundRepositoryIds !== null &&\n input.repositoryIds.some((id) => !boundRepositoryIds.includes(id))\n ) {\n throw new Error(\n \"Delegation includes a repository outside the connector-authenticated context.\",\n );\n }\n const boundReplyTo = replyToForSession(auth);\n if (\n boundReplyTo !== null &&\n (boundReplyTo.channel !== replyTo.channel || boundReplyTo.address !== replyTo.address)\n ) {\n throw new Error(\"Delegation reply address does not match the authenticated conversation.\");\n }\n for (const repositoryId of input.repositoryIds) {\n const repository = await stores.repositories.get(repositoryId);\n if (repository === null || !repository.enabled) {\n throw new Error(`Repository ${repositoryId} is not enabled in this factory.`);\n }\n }\n const boundChange = changeIdSchema.safeParse(attributes?.factoryChangeId);\n if (attributes?.factoryChangeId !== undefined && !boundChange.success) {\n throw new Error(\"Connector-authenticated change context is invalid.\");\n }\n if (\n input.changeId !== undefined &&\n boundChange.success &&\n input.changeId !== boundChange.data\n ) {\n throw new Error(\"Delegated change does not match the connector-authenticated context.\");\n }\n const changeId = input.changeId ?? (boundChange.success ? boundChange.data : undefined);\n if (changeId !== undefined) {\n if (input.repositoryIds.length !== 1) {\n throw new Error(\"Delegating work on an existing Change requires exactly one repository.\");\n }\n const change = await stores.changes.get(changeId);\n if (\n change === null ||\n change.repositoryId !== input.repositoryIds[0] ||\n (change.state !== \"verifying\" && change.state !== \"ready\")\n ) {\n throw new Error(\n `Change ${changeId} is not an open pull request in the selected repository.`,\n );\n }\n }\n if (input.signalId !== undefined) {\n const signal = await stores.signals.get(input.signalId);\n if (signal === null) throw new Error(`Signal ${input.signalId} does not exist.`);\n if (\n !input.repositoryIds.includes(signal.repositoryId) ||\n signal.replyTo.channel !== replyTo.channel ||\n signal.replyTo.address !== replyTo.address\n ) {\n throw new Error(\n \"Delegation does not match the signal's authenticated repository and reply address.\",\n );\n }\n if (signal.outcome === \"pending\") {\n await stores.signals.decide(signal.id, {\n outcome: \"accepted\",\n ...{\n reason: `Foreman selected ${route.id}.`,\n },\n });\n } else if (signal.outcome !== \"accepted\") {\n throw new Error(`Signal ${signal.id} is already ${signal.outcome}.`);\n }\n }\n let parentTaskId = input.parentTaskId;\n const boundTaskId = optionalTaskIdForSession(auth);\n if (boundTaskId !== null && boundReplyTo?.channel === \"api\") {\n const boundTask = await stores.tasks.get(boundTaskId);\n if (boundTask?.area === \"conversation\") {\n if (parentTaskId !== undefined && parentTaskId !== boundTask.id)\n throw new Error(\n \"Follow-up delegation must name its authenticated conversation task as parent.\",\n );\n parentTaskId = boundTask.id;\n }\n }\n const initiator = ctx.session.auth.initiator;\n const operator = initiator?.principalId ?? \"foreman\";\n const workflowResult = await options.workflow?.({\n stores,\n route,\n repositoryIds: input.repositoryIds,\n signalId: input.signalId,\n parentTaskId,\n changeId,\n replyTo,\n brief: input.brief,\n operator,\n dispatch: (task) =>\n dispatchRouteTask(stores, options, doFetch, route, task, changeId, input.brief),\n });\n if (workflowResult !== undefined && workflowResult !== null) return workflowResult;\n const taskInput = {\n repositoryIds: input.repositoryIds,\n kind: route.taskKind,\n work: routeTaskWork({\n route: route,\n title: input.brief.trim().slice(0, 256),\n input: { brief: input.brief },\n }),\n replyTo,\n changeId,\n ...(input.signalId === undefined\n ? {}\n : { dedupeKey: `route:${input.signalId}:${route.id}:${route.version}` }),\n };\n const task = await stores.tasks.create(\n parentTaskId !== undefined\n ? { ...taskInput, parentTaskId, origin: {} }\n : input.signalId !== undefined\n ? { ...taskInput, origin: { signalId: input.signalId } }\n : { ...taskInput, origin: { operator } },\n );\n const running =\n task.state === \"queued\"\n ? await dispatchRouteTask(stores, options, doFetch, route, task, changeId, input.brief)\n : task;\n return {\n taskId: running.id,\n route: parseAgentRouteBinding({ id: route.id, version: route.version }),\n agent: route.agent,\n state: running.state,\n };\n },\n });\n}\n\nasync function dispatchRouteTask(\n stores: DelegateAgentToolStores,\n options: DelegateAgentToolOptions,\n doFetch: typeof fetch,\n route: AgentRoute,\n task: Task,\n changeId: ChangeId | undefined,\n brief: string,\n): Promise<Task> {\n return dispatchTask(stores, {\n taskId: task.id,\n route,\n maxLaunchAttempts: options.maxLaunchAttempts?.(route) ?? 1,\n budget: options.budget?.(route),\n launch: async (dispatched) => {\n if (options.launch) return options.launch({ task: dispatched, route, brief });\n const headers = new Headers(await options.headers?.(dispatched, route));\n headers.set(\"content-type\", \"application/json\");\n const token = await options.token?.(route);\n if (token !== undefined) headers.set(\"authorization\", `Bearer ${token}`);\n const message = [\n `You are assigned factory task ${dispatched.id} through route ${route.id}.`,\n changeId === undefined ? null : `Change under review: ${changeId}.`,\n brief,\n \"Read the task first and return exactly one bounded Factory outcome.\",\n ]\n .filter((line) => line !== null)\n .join(\"\\n\\n\");\n return startEveSession({\n agentUrl: options.targetUrl(route),\n agentName: route.agent,\n headers,\n message,\n operationId: `factory-task:${dispatched.id}:${dispatched.attempt}`,\n fetch: doFetch,\n });\n },\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { ExecutionReference } from "../schema/task.mjs";
2
+ import { MaybePromise } from "../schema/common.mjs";
3
+ //#region src/eve/session-client.d.ts
4
+ /** The minimal event shape consumed from an Eve session stream. */
5
+ interface EveSessionEvent {
6
+ type: string;
7
+ data?: unknown;
8
+ }
9
+ /** Identifies and bounds a direct read of one Eve session event stream. */
10
+ interface EveSessionStreamInput {
11
+ agentUrl: string;
12
+ sessionId: string;
13
+ headers: HeadersInit;
14
+ signal: AbortSignal;
15
+ startIndex: number;
16
+ follow: boolean;
17
+ }
18
+ /** Injectable reader for an Eve session's ordered event stream. */
19
+ type EveSessionStream = (input: EveSessionStreamInput) => AsyncIterable<EveSessionEvent>;
20
+ /** Configures an idempotent request to start or reconnect to an Eve session. */
21
+ interface StartEveSessionOptions {
22
+ agentUrl: string;
23
+ message: unknown;
24
+ operationId: string;
25
+ headers?: MaybePromise<HeadersInit>;
26
+ fetch?: typeof globalThis.fetch;
27
+ timeoutMs?: number;
28
+ agentName?: string;
29
+ }
30
+ /** Start or reconnect to an Eve session through its idempotent HTTP boundary. */
31
+ declare function startEveSession(options: StartEveSessionOptions): Promise<ExecutionReference>;
32
+ /** Configures forwarding an authorized HTTP request to one exact Eve session. */
33
+ interface ForwardEveSessionRequestOptions {
34
+ agentUrl: string;
35
+ sessionId: string;
36
+ path: string;
37
+ source: Request;
38
+ headers?: MaybePromise<HeadersInit>;
39
+ fetch?: typeof globalThis.fetch;
40
+ }
41
+ /** Forward one authorized Factory API request to its exact Eve session. */
42
+ declare function forwardEveSessionRequest(options: ForwardEveSessionRequestOptions): Promise<Response>;
43
+ /** Configures cancellation and provider-stream confirmation for one exact Eve session. */
44
+ interface CancelEveSessionOptions {
45
+ agentUrl: string;
46
+ sessionId: string;
47
+ headers?: MaybePromise<HeadersInit>;
48
+ fetch?: typeof globalThis.fetch;
49
+ requestTimeoutMs?: number;
50
+ confirmationTimeoutMs?: number;
51
+ stream?: EveSessionStream;
52
+ }
53
+ /** Request cancellation and confirm the exact Eve session has stopped running. */
54
+ declare function cancelEveSession(options: CancelEveSessionOptions): Promise<void>;
55
+ /** Configures a bounded scan for the response from the latest completed Eve turn. */
56
+ interface ReadCompletedEveTurnOptions {
57
+ agentUrl: string;
58
+ sessionId: string;
59
+ headers?: MaybePromise<HeadersInit>;
60
+ timeoutMs?: number;
61
+ maxEvents?: number;
62
+ stream?: EveSessionStream;
63
+ }
64
+ /** Read the response from the latest fully completed Eve turn, if one exists. */
65
+ declare function readCompletedEveTurn(options: ReadCompletedEveTurnOptions): Promise<string | null>;
66
+ //#endregion
67
+ export { CancelEveSessionOptions, EveSessionEvent, EveSessionStream, EveSessionStreamInput, ForwardEveSessionRequestOptions, ReadCompletedEveTurnOptions, StartEveSessionOptions, cancelEveSession, forwardEveSessionRequest, readCompletedEveTurn, startEveSession };
68
+ //# sourceMappingURL=session-client.d.mts.map
@@ -0,0 +1,131 @@
1
+ import { ExecutionLaunchPendingError } from "../dispatch.mjs";
2
+ import { Client } from "eve/client";
3
+ //#region src/eve/session-client.ts
4
+ /** Start or reconnect to an Eve session through its idempotent HTTP boundary. */
5
+ async function startEveSession(options) {
6
+ const response = await (options.fetch ?? globalThis.fetch)(`${options.agentUrl.replace(/\/+$/u, "")}/eve/v1/session`, {
7
+ method: "POST",
8
+ headers: jsonHeaders(await options.headers),
9
+ body: JSON.stringify({
10
+ message: options.message,
11
+ operationId: options.operationId
12
+ }),
13
+ signal: AbortSignal.timeout(options.timeoutMs ?? 2e4),
14
+ redirect: "error"
15
+ });
16
+ if (!response.ok) {
17
+ await response.body?.cancel();
18
+ throw new Error(`${options.agentName ?? "Eve agent"} refused the session: ${response.status}`);
19
+ }
20
+ const body = await response.json().catch(() => null);
21
+ if (typeof body === "object" && body !== null && "sessionId" in body && typeof body.sessionId === "string" && body.sessionId !== "") return {
22
+ provider: "eve",
23
+ sessionId: body.sessionId
24
+ };
25
+ throw new ExecutionLaunchPendingError(`${options.agentName ?? "Eve agent"} accepted the request but returned no session ID`);
26
+ }
27
+ /** Forward one authorized Factory API request to its exact Eve session. */
28
+ async function forwardEveSessionRequest(options) {
29
+ if (!options.path.startsWith("/") || options.path.startsWith("//")) throw new Error("Eve session forwarding requires an absolute path suffix.");
30
+ return (options.fetch ?? globalThis.fetch)(`${options.agentUrl.replace(/\/+$/u, "")}/eve/v1/session/${encodeURIComponent(options.sessionId)}${options.path}`, {
31
+ method: options.source.method,
32
+ headers: jsonHeaders(await options.headers),
33
+ ...options.source.method === "POST" ? { body: await options.source.text() } : {},
34
+ signal: options.source.signal,
35
+ redirect: "error"
36
+ });
37
+ }
38
+ /** Request cancellation and confirm the exact Eve session has stopped running. */
39
+ async function cancelEveSession(options) {
40
+ const headers = await options.headers;
41
+ const response = await (options.fetch ?? globalThis.fetch)(`${options.agentUrl.replace(/\/+$/u, "")}/eve/v1/session/${encodeURIComponent(options.sessionId)}/cancel`, {
42
+ method: "POST",
43
+ headers: jsonHeaders(headers),
44
+ body: "{}",
45
+ redirect: "error",
46
+ signal: AbortSignal.timeout(options.requestTimeoutMs ?? 1e4)
47
+ });
48
+ if (!response.ok) {
49
+ await response.body?.cancel();
50
+ throw new Error(`Eve execution cancellation refused: ${response.status}`);
51
+ }
52
+ const result = await response.json().catch(() => null);
53
+ if (typeof result === "object" && result !== null && "status" in result && result.status === "no_active_turn") return;
54
+ const signal = AbortSignal.timeout(options.confirmationTimeoutMs ?? 5e3);
55
+ for await (const event of (options.stream ?? streamEveSession)({
56
+ agentUrl: options.agentUrl,
57
+ sessionId: options.sessionId,
58
+ headers: headers ?? {},
59
+ signal,
60
+ startIndex: -1,
61
+ follow: true
62
+ })) {
63
+ if ([
64
+ "session.waiting",
65
+ "session.completed",
66
+ "session.failed"
67
+ ].includes(event.type)) return;
68
+ break;
69
+ }
70
+ throw new Error("Eve execution cancellation is not yet confirmed by the provider stream");
71
+ }
72
+ /** Read the response from the latest fully completed Eve turn, if one exists. */
73
+ async function readCompletedEveTurn(options) {
74
+ const headers = await options.headers ?? {};
75
+ let response = null;
76
+ let turnId;
77
+ let completed = false;
78
+ let count = 0;
79
+ for await (const event of (options.stream ?? streamEveSession)({
80
+ agentUrl: options.agentUrl,
81
+ sessionId: options.sessionId,
82
+ headers,
83
+ signal: AbortSignal.timeout(options.timeoutMs ?? 1e4),
84
+ startIndex: 0,
85
+ follow: false
86
+ })) {
87
+ if (++count > (options.maxEvents ?? 1e4)) return null;
88
+ const data = eventData(event);
89
+ if (event.type === "turn.started") {
90
+ turnId = typeof data.turnId === "string" ? data.turnId : void 0;
91
+ response = null;
92
+ completed = false;
93
+ }
94
+ if (event.type === "message.completed" && data.turnId === turnId && typeof data.message === "string") response = data.message;
95
+ if (event.type === "turn.completed" && data.turnId === turnId) completed = true;
96
+ if ([
97
+ "turn.failed",
98
+ "turn.cancelled",
99
+ "session.failed"
100
+ ].includes(event.type)) completed = false;
101
+ }
102
+ return completed && response?.trim() ? response : null;
103
+ }
104
+ async function* streamEveSession(input) {
105
+ const client = new Client({
106
+ host: input.agentUrl.replace(/\/+$/u, ""),
107
+ headers: Object.fromEntries(new Headers(input.headers).entries()),
108
+ redirect: "error"
109
+ });
110
+ for await (const event of client.sessions.attach(input.sessionId).stream({
111
+ startIndex: input.startIndex,
112
+ follow: input.follow,
113
+ streamReconnectPolicy: { reconnect: false },
114
+ signal: input.signal
115
+ })) yield {
116
+ type: event.type,
117
+ ..."data" in event ? { data: event.data } : {}
118
+ };
119
+ }
120
+ function eventData(event) {
121
+ return typeof event.data === "object" && event.data !== null && !Array.isArray(event.data) ? event.data : {};
122
+ }
123
+ function jsonHeaders(input) {
124
+ const headers = new Headers(input);
125
+ if (!headers.has("content-type")) headers.set("content-type", "application/json");
126
+ return Object.fromEntries(headers.entries());
127
+ }
128
+ //#endregion
129
+ export { cancelEveSession, forwardEveSessionRequest, readCompletedEveTurn, startEveSession };
130
+
131
+ //# sourceMappingURL=session-client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-client.mjs","names":[],"sources":["../../src/eve/session-client.ts"],"sourcesContent":["import { Client } from \"eve/client\";\nimport { ExecutionLaunchPendingError } from \"../dispatch\";\nimport type { MaybePromise } from \"../schema/common\";\nimport type { ExecutionReference } from \"../schema/task\";\n\n/** The minimal event shape consumed from an Eve session stream. */\nexport interface EveSessionEvent {\n type: string;\n data?: unknown;\n}\n\n/** Identifies and bounds a direct read of one Eve session event stream. */\nexport interface EveSessionStreamInput {\n agentUrl: string;\n sessionId: string;\n headers: HeadersInit;\n signal: AbortSignal;\n startIndex: number;\n follow: boolean;\n}\n\n/** Injectable reader for an Eve session's ordered event stream. */\nexport type EveSessionStream = (input: EveSessionStreamInput) => AsyncIterable<EveSessionEvent>;\n\n/** Configures an idempotent request to start or reconnect to an Eve session. */\nexport interface StartEveSessionOptions {\n agentUrl: string;\n message: unknown;\n operationId: string;\n headers?: MaybePromise<HeadersInit>;\n fetch?: typeof globalThis.fetch;\n timeoutMs?: number;\n agentName?: string;\n}\n\n/** Start or reconnect to an Eve session through its idempotent HTTP boundary. */\nexport async function startEveSession(\n options: StartEveSessionOptions,\n): Promise<ExecutionReference> {\n const response = await (options.fetch ?? globalThis.fetch)(\n `${options.agentUrl.replace(/\\/+$/u, \"\")}/eve/v1/session`,\n {\n method: \"POST\",\n headers: jsonHeaders(await options.headers),\n body: JSON.stringify({ message: options.message, operationId: options.operationId }),\n signal: AbortSignal.timeout(options.timeoutMs ?? 20_000),\n redirect: \"error\",\n },\n );\n if (!response.ok) {\n await response.body?.cancel();\n throw new Error(`${options.agentName ?? \"Eve agent\"} refused the session: ${response.status}`);\n }\n const body: unknown = await response.json().catch(() => null);\n if (\n typeof body === \"object\" &&\n body !== null &&\n \"sessionId\" in body &&\n typeof body.sessionId === \"string\" &&\n body.sessionId !== \"\"\n ) {\n return { provider: \"eve\", sessionId: body.sessionId };\n }\n throw new ExecutionLaunchPendingError(\n `${options.agentName ?? \"Eve agent\"} accepted the request but returned no session ID`,\n );\n}\n\n/** Configures forwarding an authorized HTTP request to one exact Eve session. */\nexport interface ForwardEveSessionRequestOptions {\n agentUrl: string;\n sessionId: string;\n path: string;\n source: Request;\n headers?: MaybePromise<HeadersInit>;\n fetch?: typeof globalThis.fetch;\n}\n\n/** Forward one authorized Factory API request to its exact Eve session. */\nexport async function forwardEveSessionRequest(\n options: ForwardEveSessionRequestOptions,\n): Promise<Response> {\n if (!options.path.startsWith(\"/\") || options.path.startsWith(\"//\")) {\n throw new Error(\"Eve session forwarding requires an absolute path suffix.\");\n }\n return (options.fetch ?? globalThis.fetch)(\n `${options.agentUrl.replace(/\\/+$/u, \"\")}/eve/v1/session/${encodeURIComponent(options.sessionId)}${options.path}`,\n {\n method: options.source.method,\n headers: jsonHeaders(await options.headers),\n ...(options.source.method === \"POST\" ? { body: await options.source.text() } : {}),\n signal: options.source.signal,\n redirect: \"error\",\n },\n );\n}\n\n/** Configures cancellation and provider-stream confirmation for one exact Eve session. */\nexport interface CancelEveSessionOptions {\n agentUrl: string;\n sessionId: string;\n headers?: MaybePromise<HeadersInit>;\n fetch?: typeof globalThis.fetch;\n requestTimeoutMs?: number;\n confirmationTimeoutMs?: number;\n stream?: EveSessionStream;\n}\n\n/** Request cancellation and confirm the exact Eve session has stopped running. */\nexport async function cancelEveSession(options: CancelEveSessionOptions): Promise<void> {\n const headers = await options.headers;\n const response = await (options.fetch ?? globalThis.fetch)(\n `${options.agentUrl.replace(/\\/+$/u, \"\")}/eve/v1/session/${encodeURIComponent(options.sessionId)}/cancel`,\n {\n method: \"POST\",\n headers: jsonHeaders(headers),\n body: \"{}\",\n redirect: \"error\",\n signal: AbortSignal.timeout(options.requestTimeoutMs ?? 10_000),\n },\n );\n if (!response.ok) {\n await response.body?.cancel();\n throw new Error(`Eve execution cancellation refused: ${response.status}`);\n }\n const result: unknown = await response.json().catch(() => null);\n if (\n typeof result === \"object\" &&\n result !== null &&\n \"status\" in result &&\n result.status === \"no_active_turn\"\n ) {\n return;\n }\n const signal = AbortSignal.timeout(options.confirmationTimeoutMs ?? 5_000);\n for await (const event of (options.stream ?? streamEveSession)({\n agentUrl: options.agentUrl,\n sessionId: options.sessionId,\n headers: headers ?? {},\n signal,\n startIndex: -1,\n follow: true,\n })) {\n if ([\"session.waiting\", \"session.completed\", \"session.failed\"].includes(event.type)) return;\n break;\n }\n throw new Error(\"Eve execution cancellation is not yet confirmed by the provider stream\");\n}\n\n/** Configures a bounded scan for the response from the latest completed Eve turn. */\nexport interface ReadCompletedEveTurnOptions {\n agentUrl: string;\n sessionId: string;\n headers?: MaybePromise<HeadersInit>;\n timeoutMs?: number;\n maxEvents?: number;\n stream?: EveSessionStream;\n}\n\n/** Read the response from the latest fully completed Eve turn, if one exists. */\nexport async function readCompletedEveTurn(\n options: ReadCompletedEveTurnOptions,\n): Promise<string | null> {\n const headers = (await options.headers) ?? {};\n let response: string | null = null;\n let turnId: string | undefined;\n let completed = false;\n let count = 0;\n for await (const event of (options.stream ?? streamEveSession)({\n agentUrl: options.agentUrl,\n sessionId: options.sessionId,\n headers,\n signal: AbortSignal.timeout(options.timeoutMs ?? 10_000),\n startIndex: 0,\n follow: false,\n })) {\n if (++count > (options.maxEvents ?? 10_000)) return null;\n const data = eventData(event);\n if (event.type === \"turn.started\") {\n turnId = typeof data.turnId === \"string\" ? data.turnId : undefined;\n response = null;\n completed = false;\n }\n if (\n event.type === \"message.completed\" &&\n data.turnId === turnId &&\n typeof data.message === \"string\"\n ) {\n response = data.message;\n }\n if (event.type === \"turn.completed\" && data.turnId === turnId) completed = true;\n if ([\"turn.failed\", \"turn.cancelled\", \"session.failed\"].includes(event.type)) {\n completed = false;\n }\n }\n return completed && response?.trim() ? response : null;\n}\n\nasync function* streamEveSession(input: EveSessionStreamInput): AsyncIterable<EveSessionEvent> {\n const client = new Client({\n host: input.agentUrl.replace(/\\/+$/u, \"\"),\n headers: Object.fromEntries(new Headers(input.headers).entries()),\n redirect: \"error\",\n });\n for await (const event of client.sessions.attach(input.sessionId).stream({\n startIndex: input.startIndex,\n follow: input.follow,\n streamReconnectPolicy: { reconnect: false },\n signal: input.signal,\n })) {\n yield { type: event.type, ...(\"data\" in event ? { data: event.data } : {}) };\n }\n}\n\nfunction eventData(event: EveSessionEvent): Record<string, unknown> {\n return typeof event.data === \"object\" && event.data !== null && !Array.isArray(event.data)\n ? (event.data as Record<string, unknown>)\n : {};\n}\n\nfunction jsonHeaders(input?: HeadersInit): Record<string, string> {\n const headers = new Headers(input);\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n return Object.fromEntries(headers.entries());\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { factoryTaskAttemptAttribute, factoryTaskAttribute, taskBindingForSession } from "./task-session.mjs";
2
+ //#region src/eve/task-execution.ts
3
+ async function requireTaskExecution(stores, ctx, requestedTaskId) {
4
+ const auth = ctx.session?.auth;
5
+ const binding = taskBindingForSession(auth?.initiator);
6
+ if (binding.taskId !== requestedTaskId) throw new Error("Task does not match the authenticated session");
7
+ for (const key of [factoryTaskAttribute, factoryTaskAttemptAttribute]) {
8
+ const current = auth?.current?.attributes[key];
9
+ if (current !== void 0 && current !== auth?.initiator?.attributes[key]) throw new Error("Task binding does not match the current authentication");
10
+ }
11
+ const task = await stores.tasks.get(binding.taskId);
12
+ if (task?.state !== "running" || task.attempt !== binding.attempt || task.execution?.provider !== "eve" || task.execution.sessionId !== ctx.session.id) throw new Error("Task execution is missing, inactive, or replaced");
13
+ return task;
14
+ }
15
+ //#endregion
16
+ export { requireTaskExecution };
17
+
18
+ //# sourceMappingURL=task-execution.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-execution.mjs","names":[],"sources":["../../src/eve/task-execution.ts"],"sourcesContent":["import type { SessionContext } from \"eve/context\";\nimport type { TaskId } from \"../schema/id\";\nimport type { FactoryStores } from \"../store/engine\";\nimport {\n factoryTaskAttribute,\n factoryTaskAttemptAttribute,\n taskBindingForSession,\n} from \"./task-session\";\n\nexport async function requireTaskExecution(\n stores: Pick<FactoryStores, \"tasks\">,\n ctx: Pick<SessionContext, \"session\">,\n requestedTaskId: TaskId,\n) {\n const auth = ctx.session?.auth;\n const binding = taskBindingForSession(auth?.initiator);\n if (binding.taskId !== requestedTaskId) {\n throw new Error(\"Task does not match the authenticated session\");\n }\n for (const key of [factoryTaskAttribute, factoryTaskAttemptAttribute]) {\n const current = auth?.current?.attributes[key];\n if (current !== undefined && current !== auth?.initiator?.attributes[key]) {\n throw new Error(\"Task binding does not match the current authentication\");\n }\n }\n const task = await stores.tasks.get(binding.taskId);\n if (\n task?.state !== \"running\" ||\n task.attempt !== binding.attempt ||\n task.execution?.provider !== \"eve\" ||\n task.execution.sessionId !== ctx.session.id\n ) {\n throw new Error(\"Task execution is missing, inactive, or replaced\");\n }\n return task;\n}\n"],"mappings":";;AASA,eAAsB,qBACpB,QACA,KACA,iBACA;CACA,MAAM,OAAO,IAAI,SAAS;CAC1B,MAAM,UAAU,sBAAsB,MAAM,SAAS;CACrD,IAAI,QAAQ,WAAW,iBACrB,MAAM,IAAI,MAAM,+CAA+C;CAEjE,KAAK,MAAM,OAAO,CAAC,sBAAsB,2BAA2B,GAAG;EACrE,MAAM,UAAU,MAAM,SAAS,WAAW;EAC1C,IAAI,YAAY,KAAA,KAAa,YAAY,MAAM,WAAW,WAAW,MACnE,MAAM,IAAI,MAAM,wDAAwD;CAE5E;CACA,MAAM,OAAO,MAAM,OAAO,MAAM,IAAI,QAAQ,MAAM;CAClD,IACE,MAAM,UAAU,aAChB,KAAK,YAAY,QAAQ,WACzB,KAAK,WAAW,aAAa,SAC7B,KAAK,UAAU,cAAc,IAAI,QAAQ,IAEzC,MAAM,IAAI,MAAM,kDAAkD;CAEpE,OAAO;AACT"}
@@ -0,0 +1,87 @@
1
+ import { RepositoryId, TaskId } from "../schema/id.mjs";
2
+ import { ReplyTo } from "../schema/common.mjs";
3
+ import { TaskAttemptRef } from "../schema/execution.mjs";
4
+ import { AuthFn } from "eve/channels/auth";
5
+ import { SessionContext } from "eve/context";
6
+ //#region src/eve/task-session.d.ts
7
+ /** HTTP header that carries the authenticated Factory Task ID into an Eve session. */
8
+ declare const factoryTaskHeader = "x-factory-task-id";
9
+ /** Eve authentication attribute that stores the bound Factory Task ID. */
10
+ declare const factoryTaskAttribute = "factoryTaskId";
11
+ /** HTTP header that carries the Task attempt fence into an Eve session. */
12
+ declare const factoryTaskAttemptHeader = "x-factory-task-attempt";
13
+ /** Eve authentication attribute that stores the bound Task attempt fence. */
14
+ declare const factoryTaskAttemptAttribute = "factoryTaskAttempt";
15
+ /** HTTP header that carries the authenticated repository authorization envelope. */
16
+ declare const factoryRepositoryIdsHeader = "x-factory-repository-ids";
17
+ /** HTTP header that carries the authenticated conversation reply channel. */
18
+ declare const factoryReplyChannelHeader = "x-factory-reply-channel";
19
+ /** HTTP header that carries the authenticated conversation reply address. */
20
+ declare const factoryReplyAddressHeader = "x-factory-reply-address";
21
+ /** Eve authentication attribute that stores the authorized repository IDs. */
22
+ declare const factoryRepositoryIdsAttribute = "factoryRepositoryIds";
23
+ /** Eve authentication attribute that stores the conversation reply channel. */
24
+ declare const factoryReplyChannelAttribute = "factoryReplyChannel";
25
+ /** Eve authentication attribute that stores the conversation reply address. */
26
+ declare const factoryReplyAddressAttribute = "factoryReplyAddress";
27
+ type SessionInitiator = SessionContext["session"]["auth"]["initiator"];
28
+ type AuthenticatedSessionInitiator = NonNullable<SessionInitiator>;
29
+ /** The repository authorization envelope and reply destination bound to a conversation. */
30
+ interface FactoryConversationSessionBinding {
31
+ repositoryIds: readonly RepositoryId[];
32
+ replyTo: ReplyTo;
33
+ }
34
+ /** Test whether authenticated Eve session state declares a Factory Task binding. */
35
+ declare function hasFactoryTaskBinding(auth: SessionInitiator): boolean;
36
+ /** Encode a Task ID and attempt fence as headers for an Eve session request. */
37
+ declare function taskHeaders(task: TaskAttemptRef): Record<string, string>;
38
+ /** Encode a conversation's repository scope and reply destination as Eve request headers. */
39
+ declare function conversationHeaders(input: {
40
+ repositoryIds: readonly RepositoryId[];
41
+ replyTo: ReplyTo;
42
+ }): Record<string, string>;
43
+ /** Add a validated Task ID and attempt fence to an authenticated Eve initiator. */
44
+ declare function taskSessionAuth(auth: AuthenticatedSessionInitiator, task: TaskAttemptRef): AuthenticatedSessionInitiator;
45
+ /** Require valid Factory Task headers and bind them into the authenticated Eve initiator. */
46
+ declare function withFactoryTask(authenticate: AuthFn<Request>): AuthFn<Request>;
47
+ /** Bind optional Task and conversation headers while rejecting partial or malformed context. */
48
+ declare function withOptionalFactoryTask(authenticate: AuthFn<Request>): AuthFn<Request>;
49
+ /** Read the required Factory Task ID from authenticated Eve session state. */
50
+ declare function requireTaskIdForSession(auth: SessionInitiator): TaskId;
51
+ /** Read an optional Task ID from authenticated session state, rejecting malformed values. */
52
+ declare function optionalTaskIdForSession(auth: SessionInitiator): TaskId | null;
53
+ /** Read the complete, attempt-fenced Task binding established by Factory authentication. */
54
+ declare function taskBindingForSession(auth: SessionInitiator): TaskAttemptRef;
55
+ /** Read the repository authorization envelope, or null when the session has none. */
56
+ declare function repositoryIdsForSession(auth: SessionInitiator): readonly RepositoryId[] | null;
57
+ /** Read the authenticated reply destination, or null when the session has none. */
58
+ declare function replyToForSession(auth: SessionInitiator): ReplyTo | null;
59
+ /** Read the complete conversation binding, rejecting partial authentication state. */
60
+ declare function conversationBindingForSession(auth: SessionInitiator): FactoryConversationSessionBinding | null;
61
+ /** Authenticated conversation authority assembled from both initiator and current session state. */
62
+ interface ConversationBinding {
63
+ replyTo: ReplyTo;
64
+ /**
65
+ * Repository envelopes the binding carries: the initiator's, plus the current
66
+ * auth's when it restates one. Admitted work must sit inside every envelope.
67
+ */
68
+ repositoryEnvelopes: readonly (readonly RepositoryId[])[];
69
+ parentTask?: TaskAttemptRef;
70
+ }
71
+ /**
72
+ * Read and validate the conversation binding carried on a session's auth pair.
73
+ * The initiator's attributes are authoritative; any binding attribute the
74
+ * current auth restates must agree with them. This is the only reader of the
75
+ * binding attribute encoding; callers never touch `attributes` themselves.
76
+ *
77
+ * Distinct from `conversationBindingForSession`, which reads the initiator
78
+ * alone: admission needs every envelope the pair carries, so that work cannot
79
+ * be admitted into a repository only one side of the pair authorizes.
80
+ */
81
+ declare function conversationBinding(auth: {
82
+ initiator: AuthenticatedSessionInitiator;
83
+ current: AuthenticatedSessionInitiator;
84
+ }): ConversationBinding;
85
+ //#endregion
86
+ export { ConversationBinding, FactoryConversationSessionBinding, conversationBinding, conversationBindingForSession, conversationHeaders, factoryReplyAddressAttribute, factoryReplyAddressHeader, factoryReplyChannelAttribute, factoryReplyChannelHeader, factoryRepositoryIdsAttribute, factoryRepositoryIdsHeader, factoryTaskAttemptAttribute, factoryTaskAttemptHeader, factoryTaskAttribute, factoryTaskHeader, hasFactoryTaskBinding, optionalTaskIdForSession, replyToForSession, repositoryIdsForSession, requireTaskIdForSession, taskBindingForSession, taskHeaders, taskSessionAuth, withFactoryTask, withOptionalFactoryTask };
87
+ //# sourceMappingURL=task-session.d.mts.map