@capybara-hq/kernel 0.0.0-stage → 0.1.0-rc.1

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 (637) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +20 -2
  4. package/bootstrap.json +26 -0
  5. package/dist/admin/admin.controller.d.ts +139 -0
  6. package/dist/admin/admin.controller.js +238 -0
  7. package/dist/admin/extensions.controller.d.ts +100 -0
  8. package/dist/admin/extensions.controller.js +226 -0
  9. package/dist/admin/setup.controller.d.ts +36 -0
  10. package/dist/admin/setup.controller.js +106 -0
  11. package/dist/admin/setup.service.d.ts +47 -0
  12. package/dist/admin/setup.service.js +90 -0
  13. package/dist/agents/agents.controller.d.ts +205 -0
  14. package/dist/agents/agents.controller.js +144 -0
  15. package/dist/agents/agents.service.d.ts +177 -0
  16. package/dist/agents/agents.service.js +677 -0
  17. package/dist/agents/definition.d.ts +198 -0
  18. package/dist/agents/definition.js +152 -0
  19. package/dist/agents/models.controller.d.ts +13 -0
  20. package/dist/agents/models.controller.js +31 -0
  21. package/dist/agents/templates.controller.d.ts +15 -0
  22. package/dist/agents/templates.controller.js +37 -0
  23. package/dist/agents/templates.d.ts +83 -0
  24. package/dist/agents/templates.js +173 -0
  25. package/dist/catalog/admin-catalog.controller.d.ts +143 -0
  26. package/dist/catalog/admin-catalog.controller.js +245 -0
  27. package/dist/catalog/catalog.service.d.ts +430 -0
  28. package/dist/catalog/catalog.service.js +882 -0
  29. package/dist/catalog/claude/agents.d.ts +27 -0
  30. package/dist/catalog/claude/agents.js +270 -0
  31. package/dist/catalog/claude/commands.d.ts +50 -0
  32. package/dist/catalog/claude/commands.js +179 -0
  33. package/dist/catalog/claude/manifest.d.ts +69 -0
  34. package/dist/catalog/claude/manifest.js +134 -0
  35. package/dist/catalog/claude/marketplace.d.ts +35 -0
  36. package/dist/catalog/claude/marketplace.js +194 -0
  37. package/dist/catalog/claude/mcp.d.ts +33 -0
  38. package/dist/catalog/claude/mcp.js +226 -0
  39. package/dist/catalog/claude/report.d.ts +86 -0
  40. package/dist/catalog/claude/report.js +121 -0
  41. package/dist/catalog/claude/translate.d.ts +56 -0
  42. package/dist/catalog/claude/translate.js +857 -0
  43. package/dist/catalog/cli.d.ts +46 -0
  44. package/dist/catalog/cli.js +211 -0
  45. package/dist/catalog/git-source.d.ts +127 -0
  46. package/dist/catalog/git-source.js +520 -0
  47. package/dist/catalog/marketplace-fetch.d.ts +99 -0
  48. package/dist/catalog/marketplace-fetch.js +203 -0
  49. package/dist/catalog/marketplaces.controller.d.ts +97 -0
  50. package/dist/catalog/marketplaces.controller.js +197 -0
  51. package/dist/catalog/marketplaces.service.d.ts +340 -0
  52. package/dist/catalog/marketplaces.service.js +1217 -0
  53. package/dist/catalog/org-catalog.controller.d.ts +128 -0
  54. package/dist/catalog/org-catalog.controller.js +277 -0
  55. package/dist/catalog/org-catalog.service.d.ts +246 -0
  56. package/dist/catalog/org-catalog.service.js +625 -0
  57. package/dist/catalog/plugin-import.d.ts +436 -0
  58. package/dist/catalog/plugin-import.js +1069 -0
  59. package/dist/catalog/plugin-install.d.ts +447 -0
  60. package/dist/catalog/plugin-install.js +1333 -0
  61. package/dist/catalog/plugin-package.d.ts +143 -0
  62. package/dist/catalog/plugin-package.js +382 -0
  63. package/dist/catalog/plugin-upgrade.d.ts +222 -0
  64. package/dist/catalog/plugin-upgrade.js +1219 -0
  65. package/dist/catalog/requests.service.d.ts +162 -0
  66. package/dist/catalog/requests.service.js +504 -0
  67. package/dist/catalog/schema-path.d.ts +7 -0
  68. package/dist/catalog/schema-path.js +63 -0
  69. package/dist/catalog/upgrade-targets.d.ts +59 -0
  70. package/dist/catalog/upgrade-targets.js +90 -0
  71. package/dist/catalog/versions.d.ts +31 -0
  72. package/dist/catalog/versions.js +44 -0
  73. package/dist/channels/actions.d.ts +37 -0
  74. package/dist/channels/actions.js +121 -0
  75. package/dist/channels/cards.d.ts +44 -0
  76. package/dist/channels/cards.js +156 -0
  77. package/dist/channels/connections.controller.d.ts +59 -0
  78. package/dist/channels/connections.controller.js +115 -0
  79. package/dist/channels/connections.service.d.ts +187 -0
  80. package/dist/channels/connections.service.js +534 -0
  81. package/dist/channels/features.d.ts +12 -0
  82. package/dist/channels/features.js +22 -0
  83. package/dist/channels/inbound.d.ts +120 -0
  84. package/dist/channels/inbound.js +332 -0
  85. package/dist/channels/outbound.d.ts +140 -0
  86. package/dist/channels/outbound.js +1126 -0
  87. package/dist/channels/phrases.d.ts +100 -0
  88. package/dist/channels/phrases.js +81 -0
  89. package/dist/channels/supervisor.d.ts +182 -0
  90. package/dist/channels/supervisor.js +625 -0
  91. package/dist/channels/threads.d.ts +29 -0
  92. package/dist/channels/threads.js +104 -0
  93. package/dist/channels/webhook-url.d.ts +16 -0
  94. package/dist/channels/webhook-url.js +34 -0
  95. package/dist/channels/webhook.controller.d.ts +19 -0
  96. package/dist/channels/webhook.controller.js +72 -0
  97. package/dist/channels/webhook.d.ts +73 -0
  98. package/dist/channels/webhook.js +274 -0
  99. package/dist/config/docs.d.ts +9 -0
  100. package/dist/config/docs.js +85 -0
  101. package/dist/config/env.d.ts +6 -0
  102. package/dist/config/env.js +73 -0
  103. package/dist/config/fields.d.ts +42 -0
  104. package/dist/config/fields.js +214 -0
  105. package/dist/config/file-source.d.ts +3 -0
  106. package/dist/config/file-source.js +31 -0
  107. package/dist/config/load.d.ts +20 -0
  108. package/dist/config/load.js +98 -0
  109. package/dist/config/nacos-source.d.ts +31 -0
  110. package/dist/config/nacos-source.js +229 -0
  111. package/dist/config/schema.d.ts +237 -0
  112. package/dist/config/schema.js +1192 -0
  113. package/dist/config/sources.d.ts +18 -0
  114. package/dist/config/sources.js +59 -0
  115. package/dist/config/types.d.ts +9 -0
  116. package/dist/config/types.js +7 -0
  117. package/dist/conversations/artifacts.d.ts +52 -0
  118. package/dist/conversations/artifacts.js +137 -0
  119. package/dist/conversations/attachments.controller.d.ts +28 -0
  120. package/dist/conversations/attachments.controller.js +96 -0
  121. package/dist/conversations/attachments.service.d.ts +180 -0
  122. package/dist/conversations/attachments.service.js +578 -0
  123. package/dist/conversations/conversations.controller.d.ts +288 -0
  124. package/dist/conversations/conversations.controller.js +607 -0
  125. package/dist/conversations/conversations.service.d.ts +321 -0
  126. package/dist/conversations/conversations.service.js +754 -0
  127. package/dist/conversations/event-log.d.ts +122 -0
  128. package/dist/conversations/event-log.js +259 -0
  129. package/dist/conversations/events.d.ts +856 -0
  130. package/dist/conversations/events.js +639 -0
  131. package/dist/conversations/files.d.ts +92 -0
  132. package/dist/conversations/files.js +213 -0
  133. package/dist/conversations/outputs-read.d.ts +34 -0
  134. package/dist/conversations/outputs-read.js +37 -0
  135. package/dist/conversations/queue.d.ts +169 -0
  136. package/dist/conversations/queue.js +527 -0
  137. package/dist/conversations/sandbox-status.d.ts +21 -0
  138. package/dist/conversations/sandbox-status.js +24 -0
  139. package/dist/conversations/selection.d.ts +46 -0
  140. package/dist/conversations/selection.js +75 -0
  141. package/dist/conversations/titles.d.ts +93 -0
  142. package/dist/conversations/titles.js +423 -0
  143. package/dist/ctx/bus.d.ts +16 -0
  144. package/dist/ctx/bus.js +101 -0
  145. package/dist/ctx/create-ctx.d.ts +109 -0
  146. package/dist/ctx/create-ctx.js +592 -0
  147. package/dist/ctx/kv.d.ts +4 -0
  148. package/dist/ctx/kv.js +31 -0
  149. package/dist/ctx/lock.d.ts +4 -0
  150. package/dist/ctx/lock.js +39 -0
  151. package/dist/ctx/namespace.d.ts +6 -0
  152. package/dist/ctx/namespace.js +12 -0
  153. package/dist/ctx/queue.d.ts +25 -0
  154. package/dist/ctx/queue.js +151 -0
  155. package/dist/ctx/secrets.d.ts +45 -0
  156. package/dist/ctx/secrets.js +175 -0
  157. package/dist/db/kernel-schema.d.ts +1122 -0
  158. package/dist/db/kernel-schema.js +5 -0
  159. package/dist/db/migrator.d.ts +28 -0
  160. package/dist/db/migrator.js +140 -0
  161. package/dist/db/pool.d.ts +21 -0
  162. package/dist/db/pool.js +28 -0
  163. package/dist/db/sql-statements.d.ts +34 -0
  164. package/dist/db/sql-statements.js +168 -0
  165. package/dist/errors.d.ts +211 -0
  166. package/dist/errors.js +213 -0
  167. package/dist/evals/budget.d.ts +61 -0
  168. package/dist/evals/budget.js +181 -0
  169. package/dist/evals/diff.d.ts +55 -0
  170. package/dist/evals/diff.js +133 -0
  171. package/dist/evals/judge.d.ts +53 -0
  172. package/dist/evals/judge.js +149 -0
  173. package/dist/evals/plan.d.ts +47 -0
  174. package/dist/evals/plan.js +77 -0
  175. package/dist/evals/reconstruct.d.ts +137 -0
  176. package/dist/evals/reconstruct.js +322 -0
  177. package/dist/evals/recorded-tools.d.ts +54 -0
  178. package/dist/evals/recorded-tools.js +167 -0
  179. package/dist/evals/run-replay.d.ts +86 -0
  180. package/dist/evals/run-replay.js +502 -0
  181. package/dist/evals/runs.controller.d.ts +100 -0
  182. package/dist/evals/runs.controller.js +199 -0
  183. package/dist/evals/runs.service.d.ts +275 -0
  184. package/dist/evals/runs.service.js +836 -0
  185. package/dist/evals/sets.controller.d.ts +61 -0
  186. package/dist/evals/sets.controller.js +183 -0
  187. package/dist/evals/sets.service.d.ts +128 -0
  188. package/dist/evals/sets.service.js +558 -0
  189. package/dist/evals/snapshot.d.ts +76 -0
  190. package/dist/evals/snapshot.js +207 -0
  191. package/dist/evals/step-replay.d.ts +113 -0
  192. package/dist/evals/step-replay.js +181 -0
  193. package/dist/evals/trajectory.controller.d.ts +41 -0
  194. package/dist/evals/trajectory.controller.js +88 -0
  195. package/dist/evals/trajectory.d.ts +144 -0
  196. package/dist/evals/trajectory.js +338 -0
  197. package/dist/evals/trajectory.service.d.ts +108 -0
  198. package/dist/evals/trajectory.service.js +323 -0
  199. package/dist/evals/worker.d.ts +101 -0
  200. package/dist/evals/worker.js +790 -0
  201. package/dist/extensions/admin-ops.d.ts +105 -0
  202. package/dist/extensions/admin-ops.js +353 -0
  203. package/dist/extensions/admin-view.d.ts +79 -0
  204. package/dist/extensions/admin-view.js +327 -0
  205. package/dist/extensions/approvals.d.ts +119 -0
  206. package/dist/extensions/approvals.js +205 -0
  207. package/dist/extensions/blobs.d.ts +45 -0
  208. package/dist/extensions/blobs.js +160 -0
  209. package/dist/extensions/bootstrap.d.ts +176 -0
  210. package/dist/extensions/bootstrap.js +535 -0
  211. package/dist/extensions/cli.d.ts +61 -0
  212. package/dist/extensions/cli.js +165 -0
  213. package/dist/extensions/config-json-schema.d.ts +9 -0
  214. package/dist/extensions/config-json-schema.js +73 -0
  215. package/dist/extensions/deployment-config.d.ts +138 -0
  216. package/dist/extensions/deployment-config.js +394 -0
  217. package/dist/extensions/enabled.d.ts +31 -0
  218. package/dist/extensions/enabled.js +55 -0
  219. package/dist/extensions/hooks.d.ts +161 -0
  220. package/dist/extensions/hooks.js +425 -0
  221. package/dist/extensions/host.d.ts +577 -0
  222. package/dist/extensions/host.js +2071 -0
  223. package/dist/extensions/inflight.d.ts +69 -0
  224. package/dist/extensions/inflight.js +277 -0
  225. package/dist/extensions/installs.d.ts +166 -0
  226. package/dist/extensions/installs.js +253 -0
  227. package/dist/extensions/instance.d.ts +167 -0
  228. package/dist/extensions/instance.js +329 -0
  229. package/dist/extensions/ledger.d.ts +30 -0
  230. package/dist/extensions/ledger.js +50 -0
  231. package/dist/extensions/lifecycle.d.ts +80 -0
  232. package/dist/extensions/lifecycle.js +152 -0
  233. package/dist/extensions/migrate-lock.d.ts +51 -0
  234. package/dist/extensions/migrate-lock.js +100 -0
  235. package/dist/extensions/org-config.controller.d.ts +24 -0
  236. package/dist/extensions/org-config.controller.js +59 -0
  237. package/dist/extensions/org-config.d.ts +169 -0
  238. package/dist/extensions/org-config.js +520 -0
  239. package/dist/extensions/package.d.ts +115 -0
  240. package/dist/extensions/package.js +246 -0
  241. package/dist/extensions/permission-set.d.ts +117 -0
  242. package/dist/extensions/permission-set.js +184 -0
  243. package/dist/extensions/permission-view.d.ts +194 -0
  244. package/dist/extensions/permission-view.js +284 -0
  245. package/dist/extensions/registry.d.ts +24 -0
  246. package/dist/extensions/registry.js +56 -0
  247. package/dist/extensions/resolve.d.ts +12 -0
  248. package/dist/extensions/resolve.js +71 -0
  249. package/dist/extensions/sources.d.ts +69 -0
  250. package/dist/extensions/sources.js +120 -0
  251. package/dist/extensions/sync.d.ts +40 -0
  252. package/dist/extensions/sync.js +242 -0
  253. package/dist/files/previewers.controller.d.ts +46 -0
  254. package/dist/files/previewers.controller.js +105 -0
  255. package/dist/files/previewers.d.ts +100 -0
  256. package/dist/files/previewers.js +250 -0
  257. package/dist/http/api.module.d.ts +114 -0
  258. package/dist/http/api.module.js +448 -0
  259. package/dist/http/app.d.ts +77 -0
  260. package/dist/http/app.js +220 -0
  261. package/dist/http/error.filter.d.ts +21 -0
  262. package/dist/http/error.filter.js +85 -0
  263. package/dist/http/gateway.module.d.ts +15 -0
  264. package/dist/http/gateway.module.js +13 -0
  265. package/dist/http/health.controller.d.ts +26 -0
  266. package/dist/http/health.controller.js +79 -0
  267. package/dist/http/nest-logger.d.ts +20 -0
  268. package/dist/http/nest-logger.js +28 -0
  269. package/dist/http/plugin-dispatch.d.ts +68 -0
  270. package/dist/http/plugin-dispatch.js +200 -0
  271. package/dist/http/tokens.d.ts +131 -0
  272. package/dist/http/tokens.js +131 -0
  273. package/dist/http/zod.pipe.d.ts +8 -0
  274. package/dist/http/zod.pipe.js +14 -0
  275. package/dist/identity/accounts.d.ts +93 -0
  276. package/dist/identity/accounts.js +367 -0
  277. package/dist/identity/api-tokens.d.ts +73 -0
  278. package/dist/identity/api-tokens.js +197 -0
  279. package/dist/identity/audit.d.ts +23 -0
  280. package/dist/identity/audit.js +41 -0
  281. package/dist/identity/auth.controller.d.ts +40 -0
  282. package/dist/identity/auth.controller.js +130 -0
  283. package/dist/identity/auth.guard.d.ts +41 -0
  284. package/dist/identity/auth.guard.js +162 -0
  285. package/dist/identity/binding.d.ts +47 -0
  286. package/dist/identity/binding.js +84 -0
  287. package/dist/identity/cookies.d.ts +16 -0
  288. package/dist/identity/cookies.js +32 -0
  289. package/dist/identity/credential-check.d.ts +17 -0
  290. package/dist/identity/credential-check.js +24 -0
  291. package/dist/identity/enterprise-admin.d.ts +14 -0
  292. package/dist/identity/enterprise-admin.js +27 -0
  293. package/dist/identity/external.d.ts +106 -0
  294. package/dist/identity/external.js +337 -0
  295. package/dist/identity/hash.d.ts +2 -0
  296. package/dist/identity/hash.js +3 -0
  297. package/dist/identity/login.d.ts +6 -0
  298. package/dist/identity/login.js +20 -0
  299. package/dist/identity/me.controller.d.ts +61 -0
  300. package/dist/identity/me.controller.js +159 -0
  301. package/dist/identity/passwords.d.ts +6 -0
  302. package/dist/identity/passwords.js +37 -0
  303. package/dist/identity/principal.d.ts +56 -0
  304. package/dist/identity/principal.js +38 -0
  305. package/dist/identity/rate-limit.d.ts +55 -0
  306. package/dist/identity/rate-limit.js +121 -0
  307. package/dist/identity/sessions.d.ts +84 -0
  308. package/dist/identity/sessions.js +306 -0
  309. package/dist/identity/settings.d.ts +121 -0
  310. package/dist/identity/settings.js +248 -0
  311. package/dist/identity/sso.controller.d.ts +59 -0
  312. package/dist/identity/sso.controller.js +192 -0
  313. package/dist/identity/sso.d.ts +83 -0
  314. package/dist/identity/sso.js +202 -0
  315. package/dist/inbox/inbox.service.d.ts +43 -0
  316. package/dist/inbox/inbox.service.js +57 -0
  317. package/dist/index.d.ts +69 -0
  318. package/dist/index.js +67 -0
  319. package/dist/kernel.d.ts +259 -0
  320. package/dist/kernel.js +1326 -0
  321. package/dist/log-config.d.ts +9 -0
  322. package/dist/log-config.js +27 -0
  323. package/dist/log-context.d.ts +32 -0
  324. package/dist/log-context.js +40 -0
  325. package/dist/log-loki.d.ts +34 -0
  326. package/dist/log-loki.js +145 -0
  327. package/dist/log.d.ts +79 -0
  328. package/dist/log.js +303 -0
  329. package/dist/models/prices.d.ts +53 -0
  330. package/dist/models/prices.js +121 -0
  331. package/dist/models/purposes.controller.d.ts +19 -0
  332. package/dist/models/purposes.controller.js +56 -0
  333. package/dist/models/purposes.d.ts +140 -0
  334. package/dist/models/purposes.js +267 -0
  335. package/dist/net/proxy.d.ts +44 -0
  336. package/dist/net/proxy.js +162 -0
  337. package/dist/net/public-address.d.ts +60 -0
  338. package/dist/net/public-address.js +272 -0
  339. package/dist/net/safe-fetch.d.ts +38 -0
  340. package/dist/net/safe-fetch.js +140 -0
  341. package/dist/orgs/directory-sync.controller.d.ts +14 -0
  342. package/dist/orgs/directory-sync.controller.js +40 -0
  343. package/dist/orgs/directory-sync.d.ts +166 -0
  344. package/dist/orgs/directory-sync.js +558 -0
  345. package/dist/orgs/invitations.controller.d.ts +58 -0
  346. package/dist/orgs/invitations.controller.js +137 -0
  347. package/dist/orgs/invitations.service.d.ts +80 -0
  348. package/dist/orgs/invitations.service.js +217 -0
  349. package/dist/orgs/members.service.d.ts +63 -0
  350. package/dist/orgs/members.service.js +234 -0
  351. package/dist/orgs/offboarding.d.ts +141 -0
  352. package/dist/orgs/offboarding.js +398 -0
  353. package/dist/orgs/org-lock.d.ts +32 -0
  354. package/dist/orgs/org-lock.js +46 -0
  355. package/dist/orgs/org.guard.d.ts +35 -0
  356. package/dist/orgs/org.guard.js +95 -0
  357. package/dist/orgs/orgs.controller.d.ts +78 -0
  358. package/dist/orgs/orgs.controller.js +192 -0
  359. package/dist/orgs/orgs.service.d.ts +61 -0
  360. package/dist/orgs/orgs.service.js +209 -0
  361. package/dist/orgs/roles.d.ts +13 -0
  362. package/dist/orgs/roles.js +58 -0
  363. package/dist/orgs/settings.controller.d.ts +20 -0
  364. package/dist/orgs/settings.controller.js +53 -0
  365. package/dist/orgs/settings.service.d.ts +120 -0
  366. package/dist/orgs/settings.service.js +178 -0
  367. package/dist/packages/npm.d.ts +50 -0
  368. package/dist/packages/npm.js +218 -0
  369. package/dist/packages/provenance.d.ts +47 -0
  370. package/dist/packages/provenance.js +147 -0
  371. package/dist/packages/tgz.d.ts +76 -0
  372. package/dist/packages/tgz.js +225 -0
  373. package/dist/runtime/abort.d.ts +32 -0
  374. package/dist/runtime/abort.js +71 -0
  375. package/dist/runtime/checkpointer.d.ts +32 -0
  376. package/dist/runtime/checkpointer.js +243 -0
  377. package/dist/runtime/context/build.d.ts +254 -0
  378. package/dist/runtime/context/build.js +693 -0
  379. package/dist/runtime/context/claude-tools.d.ts +11 -0
  380. package/dist/runtime/context/claude-tools.js +24 -0
  381. package/dist/runtime/context/compaction.d.ts +26 -0
  382. package/dist/runtime/context/compaction.js +195 -0
  383. package/dist/runtime/context/pairing.d.ts +11 -0
  384. package/dist/runtime/context/pairing.js +82 -0
  385. package/dist/runtime/context/reminders.d.ts +5 -0
  386. package/dist/runtime/context/reminders.js +11 -0
  387. package/dist/runtime/context/skills.d.ts +105 -0
  388. package/dist/runtime/context/skills.js +283 -0
  389. package/dist/runtime/context/tokens.d.ts +19 -0
  390. package/dist/runtime/context/tokens.js +104 -0
  391. package/dist/runtime/conversation-lock.d.ts +40 -0
  392. package/dist/runtime/conversation-lock.js +97 -0
  393. package/dist/runtime/hook-calls.d.ts +84 -0
  394. package/dist/runtime/hook-calls.js +136 -0
  395. package/dist/runtime/langgraph-loop.d.ts +52 -0
  396. package/dist/runtime/langgraph-loop.js +247 -0
  397. package/dist/runtime/loop.d.ts +93 -0
  398. package/dist/runtime/loop.js +7 -0
  399. package/dist/runtime/maintenance.d.ts +80 -0
  400. package/dist/runtime/maintenance.js +148 -0
  401. package/dist/runtime/media-cache.d.ts +21 -0
  402. package/dist/runtime/media-cache.js +51 -0
  403. package/dist/runtime/model-call.d.ts +176 -0
  404. package/dist/runtime/model-call.js +1049 -0
  405. package/dist/runtime/providers.d.ts +86 -0
  406. package/dist/runtime/providers.js +224 -0
  407. package/dist/runtime/quota.d.ts +29 -0
  408. package/dist/runtime/quota.js +70 -0
  409. package/dist/runtime/run-finish.d.ts +45 -0
  410. package/dist/runtime/run-finish.js +69 -0
  411. package/dist/runtime/run-queue.d.ts +121 -0
  412. package/dist/runtime/run-queue.js +493 -0
  413. package/dist/runtime/run-worker.d.ts +138 -0
  414. package/dist/runtime/run-worker.js +806 -0
  415. package/dist/runtime/stream.controller.d.ts +34 -0
  416. package/dist/runtime/stream.controller.js +122 -0
  417. package/dist/runtime/stream.d.ts +63 -0
  418. package/dist/runtime/stream.js +262 -0
  419. package/dist/runtime/subagents/child.d.ts +80 -0
  420. package/dist/runtime/subagents/child.js +225 -0
  421. package/dist/runtime/subagents/definition.d.ts +103 -0
  422. package/dist/runtime/subagents/definition.js +392 -0
  423. package/dist/runtime/subagents/dispatch.d.ts +69 -0
  424. package/dist/runtime/subagents/dispatch.js +502 -0
  425. package/dist/runtime/subagents/limits.d.ts +23 -0
  426. package/dist/runtime/subagents/limits.js +34 -0
  427. package/dist/runtime/subagents/org-agents.d.ts +50 -0
  428. package/dist/runtime/subagents/org-agents.js +70 -0
  429. package/dist/runtime/subagents/preamble.d.ts +7 -0
  430. package/dist/runtime/subagents/preamble.js +11 -0
  431. package/dist/runtime/subagents/progress.d.ts +26 -0
  432. package/dist/runtime/subagents/progress.js +36 -0
  433. package/dist/runtime/subagents/roster.d.ts +55 -0
  434. package/dist/runtime/subagents/roster.js +111 -0
  435. package/dist/runtime/subagents/skill-fork.d.ts +123 -0
  436. package/dist/runtime/subagents/skill-fork.js +259 -0
  437. package/dist/runtime/usage-report.d.ts +163 -0
  438. package/dist/runtime/usage-report.js +551 -0
  439. package/dist/runtime/waits.d.ts +233 -0
  440. package/dist/runtime/waits.js +883 -0
  441. package/dist/sandbox/leases.d.ts +169 -0
  442. package/dist/sandbox/leases.js +515 -0
  443. package/dist/sandbox/lifecycle.d.ts +21 -0
  444. package/dist/sandbox/lifecycle.js +68 -0
  445. package/dist/sandbox/sandbox.service.d.ts +249 -0
  446. package/dist/sandbox/sandbox.service.js +908 -0
  447. package/dist/skills/catalog.d.ts +149 -0
  448. package/dist/skills/catalog.js +405 -0
  449. package/dist/skills/changes.controller.d.ts +56 -0
  450. package/dist/skills/changes.controller.js +136 -0
  451. package/dist/skills/changes.service.d.ts +175 -0
  452. package/dist/skills/changes.service.js +805 -0
  453. package/dist/skills/invocable.controller.d.ts +23 -0
  454. package/dist/skills/invocable.controller.js +50 -0
  455. package/dist/skills/invocation-keys.d.ts +23 -0
  456. package/dist/skills/invocation-keys.js +44 -0
  457. package/dist/skills/invoke.d.ts +135 -0
  458. package/dist/skills/invoke.js +286 -0
  459. package/dist/skills/package.d.ts +87 -0
  460. package/dist/skills/package.js +227 -0
  461. package/dist/skills/skills.controller.d.ts +40 -0
  462. package/dist/skills/skills.controller.js +110 -0
  463. package/dist/skills/skills.service.d.ts +192 -0
  464. package/dist/skills/skills.service.js +567 -0
  465. package/dist/storage/prefix.d.ts +36 -0
  466. package/dist/storage/prefix.js +104 -0
  467. package/dist/storage/purge.d.ts +27 -0
  468. package/dist/storage/purge.js +75 -0
  469. package/dist/storage/storage.service.d.ts +44 -0
  470. package/dist/storage/storage.service.js +145 -0
  471. package/dist/text.d.ts +13 -0
  472. package/dist/text.js +13 -0
  473. package/dist/tools/approvals.controller.d.ts +53 -0
  474. package/dist/tools/approvals.controller.js +128 -0
  475. package/dist/tools/approvals.service.d.ts +172 -0
  476. package/dist/tools/approvals.service.js +568 -0
  477. package/dist/tools/breaker.d.ts +28 -0
  478. package/dist/tools/breaker.js +72 -0
  479. package/dist/tools/builtins/agent.d.ts +81 -0
  480. package/dist/tools/builtins/agent.js +223 -0
  481. package/dist/tools/builtins/ask-user.d.ts +28 -0
  482. package/dist/tools/builtins/ask-user.js +139 -0
  483. package/dist/tools/builtins/read-tool-output.d.ts +18 -0
  484. package/dist/tools/builtins/read-tool-output.js +108 -0
  485. package/dist/tools/builtins/sandbox/bash.d.ts +16 -0
  486. package/dist/tools/builtins/sandbox/bash.js +137 -0
  487. package/dist/tools/builtins/sandbox/common.d.ts +116 -0
  488. package/dist/tools/builtins/sandbox/common.js +306 -0
  489. package/dist/tools/builtins/sandbox/deliver.d.ts +5 -0
  490. package/dist/tools/builtins/sandbox/deliver.js +180 -0
  491. package/dist/tools/builtins/sandbox/edit.d.ts +4 -0
  492. package/dist/tools/builtins/sandbox/edit.js +98 -0
  493. package/dist/tools/builtins/sandbox/glob-match.d.ts +25 -0
  494. package/dist/tools/builtins/sandbox/glob-match.js +240 -0
  495. package/dist/tools/builtins/sandbox/glob.d.ts +4 -0
  496. package/dist/tools/builtins/sandbox/glob.js +104 -0
  497. package/dist/tools/builtins/sandbox/grep.d.ts +9 -0
  498. package/dist/tools/builtins/sandbox/grep.js +133 -0
  499. package/dist/tools/builtins/sandbox/index.d.ts +12 -0
  500. package/dist/tools/builtins/sandbox/index.js +27 -0
  501. package/dist/tools/builtins/sandbox/names.d.ts +7 -0
  502. package/dist/tools/builtins/sandbox/names.js +20 -0
  503. package/dist/tools/builtins/sandbox/read.d.ts +8 -0
  504. package/dist/tools/builtins/sandbox/read.js +121 -0
  505. package/dist/tools/builtins/sandbox/write.d.ts +4 -0
  506. package/dist/tools/builtins/sandbox/write.js +88 -0
  507. package/dist/tools/builtins/skill-load.d.ts +53 -0
  508. package/dist/tools/builtins/skill-load.js +446 -0
  509. package/dist/tools/builtins/skill-write.d.ts +59 -0
  510. package/dist/tools/builtins/skill-write.js +244 -0
  511. package/dist/tools/builtins/tool-search.d.ts +31 -0
  512. package/dist/tools/builtins/tool-search.js +171 -0
  513. package/dist/tools/connector-content.controller.d.ts +34 -0
  514. package/dist/tools/connector-content.controller.js +78 -0
  515. package/dist/tools/connector-content.d.ts +104 -0
  516. package/dist/tools/connector-content.js +267 -0
  517. package/dist/tools/connectors.controller.d.ts +210 -0
  518. package/dist/tools/connectors.controller.js +234 -0
  519. package/dist/tools/connectors.service.d.ts +303 -0
  520. package/dist/tools/connectors.service.js +1102 -0
  521. package/dist/tools/credentials.d.ts +139 -0
  522. package/dist/tools/credentials.js +351 -0
  523. package/dist/tools/drift.d.ts +141 -0
  524. package/dist/tools/drift.js +539 -0
  525. package/dist/tools/elicitation.d.ts +81 -0
  526. package/dist/tools/elicitation.js +266 -0
  527. package/dist/tools/endpoint.d.ts +18 -0
  528. package/dist/tools/endpoint.js +115 -0
  529. package/dist/tools/info.d.ts +67 -0
  530. package/dist/tools/info.js +113 -0
  531. package/dist/tools/naming.d.ts +27 -0
  532. package/dist/tools/naming.js +47 -0
  533. package/dist/tools/oauth/discovery.d.ts +65 -0
  534. package/dist/tools/oauth/discovery.js +307 -0
  535. package/dist/tools/oauth/flow.d.ts +63 -0
  536. package/dist/tools/oauth/flow.js +237 -0
  537. package/dist/tools/oauth/oauth.controller.d.ts +31 -0
  538. package/dist/tools/oauth/oauth.controller.js +95 -0
  539. package/dist/tools/oauth/tokens.d.ts +111 -0
  540. package/dist/tools/oauth/tokens.js +258 -0
  541. package/dist/tools/outputs.d.ts +61 -0
  542. package/dist/tools/outputs.js +156 -0
  543. package/dist/tools/pipeline.d.ts +322 -0
  544. package/dist/tools/pipeline.js +1236 -0
  545. package/dist/tools/policy.d.ts +60 -0
  546. package/dist/tools/policy.js +236 -0
  547. package/dist/tools/questions.controller.d.ts +24 -0
  548. package/dist/tools/questions.controller.js +58 -0
  549. package/dist/tools/questions.service.d.ts +103 -0
  550. package/dist/tools/questions.service.js +295 -0
  551. package/dist/tools/redact.d.ts +20 -0
  552. package/dist/tools/redact.js +60 -0
  553. package/dist/tools/registry.d.ts +246 -0
  554. package/dist/tools/registry.js +481 -0
  555. package/dist/tools/resources.d.ts +16 -0
  556. package/dist/tools/resources.js +76 -0
  557. package/dist/tools/specs.d.ts +14 -0
  558. package/dist/tools/specs.js +31 -0
  559. package/dist/tools/validate.d.ts +20 -0
  560. package/dist/tools/validate.js +183 -0
  561. package/dist/tools/view.d.ts +43 -0
  562. package/dist/tools/view.js +225 -0
  563. package/dist/ui/embed-token.d.ts +31 -0
  564. package/dist/ui/embed-token.js +132 -0
  565. package/dist/ui/registry.d.ts +58 -0
  566. package/dist/ui/registry.js +90 -0
  567. package/dist/ui/ui-stream.d.ts +37 -0
  568. package/dist/ui/ui-stream.js +162 -0
  569. package/dist/ui/views.controller.d.ts +81 -0
  570. package/dist/ui/views.controller.js +261 -0
  571. package/dist/ui/views.d.ts +155 -0
  572. package/dist/ui/views.js +306 -0
  573. package/dist/version.d.ts +5 -0
  574. package/dist/version.js +6 -0
  575. package/package.json +69 -3
  576. package/src/migrations/0001_init.sql +8 -0
  577. package/src/migrations/0002_secrets.sql +8 -0
  578. package/src/migrations/0003_identity.sql +117 -0
  579. package/src/migrations/0004_plugin_org_config_nullable.sql +3 -0
  580. package/src/migrations/0005_agents.sql +27 -0
  581. package/src/migrations/0006_conversations.sql +37 -0
  582. package/src/migrations/0007_checkpoints.sql +26 -0
  583. package/src/migrations/0008_runs_trigger_seq.sql +3 -0
  584. package/src/migrations/0009_runs_active_unique.sql +4 -0
  585. package/src/migrations/0010_tools.sql +125 -0
  586. package/src/migrations/0011_approvals_spec.sql +10 -0
  587. package/src/migrations/0012_run_waits.sql +24 -0
  588. package/src/migrations/0013_app_tools_source.sql +4 -0
  589. package/src/migrations/0014_tool_specs.sql +8 -0
  590. package/src/migrations/0015_tool_drift.sql +20 -0
  591. package/src/migrations/0016_plugin_permissions.sql +11 -0
  592. package/src/migrations/0017_identity_sources.sql +6 -0
  593. package/src/migrations/0018_channels.sql +74 -0
  594. package/src/migrations/0019_identity_trust.sql +17 -0
  595. package/src/migrations/0020_channel_card_lookup.sql +10 -0
  596. package/src/migrations/0021_org_storage_purge.sql +9 -0
  597. package/src/migrations/0022_attachments.sql +29 -0
  598. package/src/migrations/0023_sandboxes.sql +37 -0
  599. package/src/migrations/0024_skills.sql +46 -0
  600. package/src/migrations/0025_skills_catalog_idx.sql +6 -0
  601. package/src/migrations/0026_skill_changes.sql +34 -0
  602. package/src/migrations/0027_model_prices.sql +18 -0
  603. package/src/migrations/0028_evals.sql +105 -0
  604. package/src/migrations/0029_model_purposes.sql +18 -0
  605. package/src/migrations/0030_plugin_installs.sql +73 -0
  606. package/src/migrations/0031_plugin_snapshot_source.sql +6 -0
  607. package/src/migrations/0032_plugin_deployment_configs.sql +10 -0
  608. package/src/migrations/0033_rename_apps_to_connectors.sql +25 -0
  609. package/src/migrations/0034_directory.sql +49 -0
  610. package/src/migrations/0035_catalogs.sql +40 -0
  611. package/src/migrations/0036_app_import_staging.sql +17 -0
  612. package/src/migrations/0037_directory_installs.sql +92 -0
  613. package/src/migrations/0038_channel_inbound_mode.sql +6 -0
  614. package/src/migrations/0039_channel_card_pending.sql +8 -0
  615. package/src/migrations/0040_usage_report_sweep.sql +10 -0
  616. package/src/migrations/0041_rename_plugins_to_extensions.sql +38 -0
  617. package/src/migrations/0042_rename_directory_to_catalog.sql +80 -0
  618. package/src/migrations/0043_rename_app_installs_to_plugin_installs.sql +20 -0
  619. package/src/migrations/0044_catalog_one_kind.sql +90 -0
  620. package/src/migrations/0045_plugin_dependencies.sql +9 -0
  621. package/src/migrations/0046_git_sources.sql +25 -0
  622. package/src/migrations/0047_marketplace_entry_heads.sql +7 -0
  623. package/src/migrations/0048_marketplace_entry_trees.sql +8 -0
  624. package/src/migrations/0049_plugin_upgrades.sql +37 -0
  625. package/src/migrations/0050_bootstrap.sql +53 -0
  626. package/src/migrations/0051_claude_compat.sql +26 -0
  627. package/src/migrations/0052_conversations_account_agent_idx.sql +5 -0
  628. package/src/migrations/0053_subagents.sql +73 -0
  629. package/src/migrations/0054_subagent_wait_expiry.sql +7 -0
  630. package/src/migrations/0055_subagent_parent_indexes.sql +10 -0
  631. package/src/migrations/0056_approval_reason.sql +3 -0
  632. package/src/migrations/0057_conversation_titles.sql +11 -0
  633. package/src/migrations/0058_conversation_selection.sql +4 -0
  634. package/src/migrations/0059_conversation_queue.sql +22 -0
  635. package/src/migrations/0060_file_previewers.sql +10 -0
  636. package/src/migrations/0061_queue_selection.sql +5 -0
  637. package/src/migrations/0062_queued_skill.sql +8 -0
@@ -0,0 +1,806 @@
1
+ import { hostname } from "node:os";
2
+ import { DelayedError, Worker } from "bullmq";
3
+ import { sql } from "kysely";
4
+ import { normalizeStoredDefinition } from "../agents/definition.js";
5
+ import { effectiveDefinition, NO_SELECTION, readSelection, sameModel, sameSelection, } from "../conversations/selection.js";
6
+ import { ApiError } from "../errors.js";
7
+ import { withJobContext } from "../log-context.js";
8
+ import { pinnedFailureText, recordSkillsCatalog } from "../skills/catalog.js";
9
+ import { RunError } from "./model-call.js";
10
+ import { ProviderListError } from "./providers.js";
11
+ import { ORG_QUOTA_LEASE_MS, orgRunLimit } from "./quota.js";
12
+ import { finishRun, TERMINAL_STATUSES } from "./run-finish.js";
13
+ import { bullConnection, RUN_QUEUE_NAME, SUBAGENT_RUN_QUEUE_NAME, } from "./run-queue.js";
14
+ import { dispatchOfChildRun } from "./subagents/child.js";
15
+ import { childRunDefinition } from "./subagents/definition.js";
16
+ import { forkBoundary } from "./subagents/skill-fork.js";
17
+ /** 会话锁被占用时任务延后的时间。 */
18
+ const LOCK_BUSY_DELAY_MS = 1000;
19
+ /** 组织配额已满时任务延后的时间。 */
20
+ const QUOTA_FULL_DELAY_MS = 2000;
21
+ /** BullMQ stalled 检测允许的最大次数(超过则任务失败)。 */
22
+ const MAX_STALLED_COUNT = 3;
23
+ /** 停机时等待任务结束后处理(ensureRun 等)的最短时间。 */
24
+ const FOLLOW_UP_MIN_WAIT_MS = 250;
25
+ /** 读插话的分页大小。 */
26
+ const READ_PAGE = 500;
27
+ /**
28
+ * 任务结束后的 ensureRun 失败时的重试间隔(首次之外再试 3 次)。用进程内定时器:这是本进程刚完成的任务的
29
+ * 后续处理,由 close() 跟踪并限时;全部失败也不会让会话永远卡住——打开 SSE / 读事件时会再次 ensureRun。
30
+ */
31
+ const ENSURE_RETRY_DELAYS_MS = [200, 1000, 3000];
32
+ const noopSink = () => { };
33
+ /** 任务回到队列:延后 delayMs 再处理(不计入 attempts)。 */
34
+ async function requeue(job, token, delayMs) {
35
+ await job.moveToDelayed(Date.now() + delayMs, token);
36
+ throw new DelayedError();
37
+ }
38
+ /**
39
+ * 运行 worker(只在含 `worker` 角色的进程启动):领取 `cap-kernel-runs` 的任务,取会话锁与组织配额,
40
+ * 调用 AgentLoop,按结果写终态事件并推进 `consumed_seq`;结束后再调用一次 `ensureRun` 处理
41
+ * 运行期间到达但没被吸收的消息(Review Focus 2)。
42
+ */
43
+ export class RunWorker {
44
+ d;
45
+ /** One BullMQ worker per run queue: conversation runs and sub-agent runs (spec §7.4). */
46
+ workers = [];
47
+ /** 传给 Worker 的连接:BullMQ 不关闭调用方传入的连接,close() 时自己关。 */
48
+ conn;
49
+ active = new Map();
50
+ /** 进行中的「任务结束后」处理(完成后的 ensureRun、失败标记):停机时等它们做完再关闭队列。 */
51
+ followUps = new Set();
52
+ closing = false;
53
+ /** close() 开始时触发:ensureRun 重试不再等待退避间隔。 */
54
+ closingSignal = new AbortController();
55
+ constructor(d) {
56
+ this.d = d;
57
+ }
58
+ start() {
59
+ if (this.workers.length > 0)
60
+ return;
61
+ const runtime = this.d.config().runtime;
62
+ this.conn = bullConnection(this.d.redisUrl, this.d.log);
63
+ for (const queue of [RUN_QUEUE_NAME, SUBAGENT_RUN_QUEUE_NAME]) {
64
+ const worker = new Worker(queue, (job, token) => withJobContext(queue, job, () => this.process(job, token)), {
65
+ // the worker name is recorded on the job (BullMQ processedBy): which replica ran it
66
+ name: `${hostname()}-${process.pid}`,
67
+ connection: this.conn,
68
+ concurrency: runtime.workerConcurrency,
69
+ lockDuration: runtime.jobLockMs,
70
+ stalledInterval: runtime.stalledIntervalMs,
71
+ maxStalledCount: MAX_STALLED_COUNT,
72
+ });
73
+ // ensureRun after a run goes after its job completed and left the queue: when the latest
74
+ // unconsumed message is this run's own trigger (e.g. a run ended by its deadline without
75
+ // absorbing it, R34), the new job has this job's id and would be dropped as a duplicate
76
+ // while this one is still active. Relies on BullMQ moving the job to completed (deleted by
77
+ // removeOnComplete) before emitting "completed" (pinned by the R34 test).
78
+ worker.on("completed", (job, result) => {
79
+ if (result !== "ensure")
80
+ return;
81
+ const { conversationId, runId } = job.data;
82
+ this.track(this.ensureAfterRun(conversationId, runId));
83
+ });
84
+ worker.on("error", (err) => this.d.log.error("run worker error", { err, queue }));
85
+ worker.on("failed", (job, err) => {
86
+ this.d.log.error("run job failed", { jobId: job?.id, runId: job?.data.runId, err });
87
+ if (job) {
88
+ this.track(this.onJobFailed(job.data, err).catch((e) => this.d.log.error("cannot mark failed run job", { runId: job.data.runId, err: e })));
89
+ }
90
+ });
91
+ this.workers.push(worker);
92
+ }
93
+ }
94
+ /** Stops the active children of a finished run (see {@link RunWorkerDeps.stopChildren}). */
95
+ async stopChildren(runId) {
96
+ if (!this.d.stopChildren)
97
+ return;
98
+ try {
99
+ await this.d.stopChildren(runId);
100
+ }
101
+ catch (err) {
102
+ this.d.log.error("cannot stop the sub-agents of a finished run", { runId, err });
103
+ }
104
+ }
105
+ /** Reports a finished sub-agent run to its parent (see {@link RunWorkerDeps.onChildFinished}). */
106
+ async childFinished(runId) {
107
+ if (!this.d.onChildFinished)
108
+ return;
109
+ try {
110
+ await this.d.onChildFinished(runId);
111
+ }
112
+ catch (err) {
113
+ this.d.log.error("cannot report finished sub-agent run to its parent", { runId, err });
114
+ }
115
+ }
116
+ /**
117
+ * 任务结束后的 ensureRun,失败按 {@link ENSURE_RETRY_DELAYS_MS} 退避重试;停机开始后不再等待间隔
118
+ * (剩余的尝试立即进行,close() 以剩余预算为限等待)。全部失败只记日志,不抛出。
119
+ */
120
+ async ensureAfterRun(conversationId, runId) {
121
+ for (let attempt = 0;; attempt++) {
122
+ try {
123
+ await this.d.hooks?.beforeEnsureRun?.(conversationId, attempt);
124
+ await this.d.queue.ensureRun(conversationId);
125
+ return;
126
+ }
127
+ catch (err) {
128
+ const delay = ENSURE_RETRY_DELAYS_MS[attempt];
129
+ if (delay === undefined) {
130
+ this.d.log.error("ensureRun after run failed; giving up", {
131
+ conversationId,
132
+ runId,
133
+ attempts: attempt + 1,
134
+ err,
135
+ });
136
+ return;
137
+ }
138
+ this.d.log.warn("ensureRun after run failed; retrying", {
139
+ conversationId,
140
+ runId,
141
+ attempt,
142
+ err,
143
+ });
144
+ await this.retryDelay(delay);
145
+ }
146
+ }
147
+ }
148
+ /** 等待 ms 毫秒;停机开始时立即返回。 */
149
+ retryDelay(ms) {
150
+ const signal = this.closingSignal.signal;
151
+ if (signal.aborted)
152
+ return Promise.resolve();
153
+ return new Promise((resolve) => {
154
+ const done = () => {
155
+ clearTimeout(t);
156
+ signal.removeEventListener("abort", done);
157
+ resolve();
158
+ };
159
+ const t = setTimeout(done, ms);
160
+ t.unref();
161
+ signal.addEventListener("abort", done, { once: true });
162
+ });
163
+ }
164
+ /** 登记一个任务结束后的处理,做完自动移除。 */
165
+ track(p) {
166
+ this.followUps.add(p);
167
+ void p.finally(() => this.followUps.delete(p));
168
+ }
169
+ /**
170
+ * BullMQ 判定任务失败(R29):stalled 次数超过上限(持有者反复崩溃),或处理函数在自己的终态处理之外抛错。
171
+ * 运行若仍未结束:清理死去持有者留下的会话锁,写 `run_failed`(stalled → `run.stalled`,
172
+ * 其他 → `run.internal`),status 置为 failed,consumed_seq 至少推进到触发消息,删除 checkpoint,然后 ensureRun(带重试)。
173
+ */
174
+ async onJobFailed(data, err) {
175
+ const { runId, conversationId } = data;
176
+ const stalled = /stalled/i.test(err.message);
177
+ await this.d.lock.releaseFor(conversationId, runId);
178
+ // 运行已进入 waiting(暂停后任务才失败):它有自己的续跑路径(人工决定 / 超时任务),不标记失败。
179
+ const cur = await this.d.db
180
+ .selectFrom("runs")
181
+ .select("status")
182
+ .where("id", "=", runId)
183
+ .executeTakeFirst();
184
+ if (cur?.status === "waiting") {
185
+ this.d.log.warn("run job failed after the run was suspended; leaving it waiting", { runId });
186
+ return;
187
+ }
188
+ await this.finish(conversationId, runId, "failed", null, {
189
+ type: "run_failed",
190
+ payload: {
191
+ error: stalled
192
+ ? {
193
+ code: "run.stalled",
194
+ message: "The run was interrupted too many times and will not continue",
195
+ }
196
+ : { code: "run.internal", message: "The run failed unexpectedly" },
197
+ },
198
+ }, false);
199
+ await this.dropCheckpoints(runId);
200
+ // the kind is not loaded here: both are no-ops for the other kind
201
+ await this.childFinished(runId);
202
+ await this.stopChildren(runId);
203
+ await this.ensureAfterRun(conversationId, runId);
204
+ }
205
+ /**
206
+ * 优雅停机:停止领取新任务 → 向本进程的运行发停机信号(loop 在下一个步骤边界返回 `interrupted`,
207
+ * 任务回到队列)→ 在 budgetMs 内等它们结束。超出预算的运行放弃执行(停止续租会话锁、强制关闭
208
+ * worker,不再续任务锁),由 BullMQ 的 stalled 机制交给其他 worker 续跑。
209
+ */
210
+ async close(budgetMs) {
211
+ const workers = this.workers;
212
+ if (workers.length === 0)
213
+ return;
214
+ const deadline = Date.now() + Math.max(0, budgetMs);
215
+ this.workers = [];
216
+ this.closing = true;
217
+ this.closingSignal.abort();
218
+ await Promise.all(workers.map((w) => w.pause(true).catch((err) => this.d.log.warn("run worker pause failed", { err }))));
219
+ for (const a of this.active.values())
220
+ a.shutdown.abort();
221
+ const all = Promise.all([...this.active.values()].map((a) => a.done));
222
+ let timer;
223
+ const finished = await Promise.race([
224
+ all.then(() => true),
225
+ new Promise((resolve) => {
226
+ timer = setTimeout(() => resolve(false), Math.max(0, budgetMs));
227
+ timer.unref();
228
+ }),
229
+ ]);
230
+ clearTimeout(timer);
231
+ if (!finished) {
232
+ for (const [runId, a] of this.active) {
233
+ a.abandoned = true;
234
+ a.lease.abandon();
235
+ a.stopTimers();
236
+ this.d.log.warn("run did not reach a step boundary before shutdown; leaving it to another worker", {
237
+ runId,
238
+ });
239
+ }
240
+ }
241
+ await Promise.all(workers.map((w) => w.close(!finished)));
242
+ // 关闭期间完成 / 失败的任务登记的后续处理(ensureRun 等)要在调用方关闭运行队列之前做完,
243
+ // 否则投递半途被打断,待处理的消息无人处理。以剩余预算为限(至少留一点时间)。
244
+ if (this.followUps.size > 0) {
245
+ let t;
246
+ await Promise.race([
247
+ Promise.allSettled([...this.followUps]),
248
+ new Promise((resolve) => {
249
+ t = setTimeout(resolve, Math.max(FOLLOW_UP_MIN_WAIT_MS, deadline - Date.now()));
250
+ t.unref();
251
+ }),
252
+ ]);
253
+ clearTimeout(t);
254
+ }
255
+ const conn = this.conn;
256
+ this.conn = undefined;
257
+ if (conn)
258
+ await conn.quit().catch(() => conn.disconnect());
259
+ }
260
+ async process(job, token) {
261
+ const { runId, conversationId } = job.data;
262
+ if (this.closing)
263
+ return requeue(job, token, 0);
264
+ const run = await this.d.db
265
+ .selectFrom("runs")
266
+ .select([
267
+ "id",
268
+ "status",
269
+ "agent_version",
270
+ "trigger_account_id",
271
+ "trigger_seq",
272
+ "started_at",
273
+ "waited_ms",
274
+ ])
275
+ .where("id", "=", runId)
276
+ .executeTakeFirst();
277
+ // 重复投递的任务发现运行已不存在或已结束(例如上一个处理者写完终态后、做后续检查前崩溃):
278
+ // 仍做一次结束后的 ensureRun,避免那时到达的消息无人处理。
279
+ if (!run || TERMINAL_STATUSES.has(run.status)) {
280
+ await this.dropCheckpoints(runId);
281
+ // a sub-agent run whose finisher may have crashed before reporting to the parent (idempotent)
282
+ if (run)
283
+ await this.childFinished(runId);
284
+ return "ensure";
285
+ }
286
+ // 运行在等人处理(例如暂停后本任务被 stalled 机制重新投递):不执行,续跑由处理 / 超时发起的新任务负责。
287
+ if (run.status === "waiting")
288
+ return;
289
+ const conv = await this.d.db
290
+ .selectFrom("conversations")
291
+ .select(["org_id", "agent_id", "kind"])
292
+ .where("id", "=", conversationId)
293
+ .executeTakeFirst();
294
+ if (!conv)
295
+ return;
296
+ // 会话锁 TTL 与任务锁一致:持有者崩溃后,任务被判定 stalled 时会话锁也差不多同时过期。
297
+ const lease = await this.d.lock.acquire(conversationId, runId, this.d.hooks?.lockTtlMs ?? this.d.config().runtime.jobLockMs);
298
+ if (!lease)
299
+ return requeue(job, token, LOCK_BUSY_DELAY_MS);
300
+ // A sub-agent stopped while still queued (its parent's stop or wait timeout) ends here, before
301
+ // taking an org run slot: under a full quota it would otherwise wait for a slot only to be
302
+ // aborted, and its parent would stay waiting meanwhile (final review m7)
303
+ if (conv.kind === "subagent" && run.status === "queued") {
304
+ const stop = await this.d.abort.requested(runId);
305
+ if (stop !== null) {
306
+ try {
307
+ await this.finish(conversationId, runId, "aborted", null, {
308
+ type: "run_aborted",
309
+ payload: {
310
+ byAccountId: stop.byAccountId,
311
+ reason: "user",
312
+ ...(stop.detail !== undefined && { detail: stop.detail }),
313
+ },
314
+ });
315
+ }
316
+ finally {
317
+ await lease
318
+ .release()
319
+ .catch((err) => this.d.log.warn("conversation lock release failed", { runId, err }));
320
+ }
321
+ await this.dropCheckpoints(runId);
322
+ await this.childFinished(runId);
323
+ return "ensure";
324
+ }
325
+ }
326
+ let settle;
327
+ const state = {
328
+ shutdown: new AbortController(),
329
+ abandoned: false,
330
+ leaseLost: false,
331
+ lease,
332
+ stopTimers: () => { },
333
+ done: new Promise((r) => {
334
+ settle = r;
335
+ }),
336
+ };
337
+ this.active.set(runId, state);
338
+ // 停机开始后才登记的运行(close() 的快照之后):同样在步骤边界停下。
339
+ if (this.closing)
340
+ state.shutdown.abort();
341
+ // 锁丢失(R27):走与停机相同的路径——loop 在下一个步骤边界返回 interrupted,任务回到队列。
342
+ lease.onLost(() => {
343
+ state.leaseLost = true;
344
+ state.shutdown.abort();
345
+ });
346
+ let entered = false;
347
+ let delayMs = null;
348
+ try {
349
+ const limit = await orgRunLimit(this.d.settings, this.d.config, conv.org_id);
350
+ entered = await this.d.quota.tryEnter(conv.org_id, runId, limit, ORG_QUOTA_LEASE_MS);
351
+ if (!entered) {
352
+ delayMs = QUOTA_FULL_DELAY_MS;
353
+ }
354
+ else {
355
+ // 运行开始执行(含续跑、stalled 后接手):通知旁路(渠道出站投递据此把输出投到 IM),失败不影响运行
356
+ try {
357
+ this.d.onRunStart?.(conversationId);
358
+ }
359
+ catch (err) {
360
+ this.d.log.warn("onRunStart hook failed", { conversationId, err });
361
+ }
362
+ const r = await this.execute(run, { id: conversationId, ...conv }, state).catch(async (err) => {
363
+ if (state.abandoned)
364
+ return "abandoned";
365
+ if (state.leaseLost)
366
+ return "interrupted";
367
+ // 编排自身出错(如写事件失败):尽力把运行标记为失败,避免会话卡在 running。
368
+ this.d.log.error("run orchestration failed", { conversationId, runId, err });
369
+ await this.finish(conversationId, runId, "failed", null, {
370
+ type: "run_failed",
371
+ payload: { error: { code: "run.internal", message: "The run failed unexpectedly" } },
372
+ }).catch((e) => this.d.log.error("cannot mark run as failed", { runId, err: e }));
373
+ return "broken";
374
+ });
375
+ if (r === "interrupted")
376
+ delayMs = 0;
377
+ }
378
+ }
379
+ finally {
380
+ state.stopTimers();
381
+ if (!state.abandoned) {
382
+ if (entered) {
383
+ await this.d.quota
384
+ .leave(conv.org_id, runId)
385
+ .catch((err) => this.d.log.warn("org quota leave failed", { runId, err }));
386
+ }
387
+ // 锁已丢失时不释放(已不属于本运行;RELEASE 虽比对 runId,这里也不再触碰)。
388
+ if (!state.leaseLost) {
389
+ await lease
390
+ .release()
391
+ .catch((err) => this.d.log.warn("conversation lock release failed", { runId, err }));
392
+ }
393
+ }
394
+ this.active.delete(runId);
395
+ settle();
396
+ }
397
+ if (state.abandoned)
398
+ return;
399
+ if (delayMs !== null)
400
+ return requeue(job, token, delayMs);
401
+ // 暂停:会话锁与配额已释放,checkpoint 保留;置 waiting 并投递超时任务。任务就此完成,不 ensureRun
402
+ // (等待期间的新消息在续跑后作为插话吸收)。
403
+ if (state.suspended) {
404
+ await this.d.waits.suspend(runId, conversationId, state.suspended.waitingFor, state.suspended.abort);
405
+ return;
406
+ }
407
+ // 运行已到达终态(broken 时已尽力标记失败):checkpoint 只用于续跑,删除。
408
+ await this.dropCheckpoints(runId);
409
+ if (conv.kind === "subagent")
410
+ await this.childFinished(runId);
411
+ else
412
+ await this.stopChildren(runId);
413
+ return "ensure";
414
+ }
415
+ async execute(run, conv, state) {
416
+ const runId = run.id;
417
+ const conversationId = conv.id;
418
+ const runtime = this.d.config().runtime;
419
+ let agent;
420
+ // a chat run's saved agent version, under the conversation's model switch (UI refresh B); a
421
+ // sub-agent has none: it never takes a selection
422
+ let saved;
423
+ let maxSteps = runtime.maxSteps;
424
+ let parent;
425
+ if (conv.kind === "subagent") {
426
+ // a sub-agent runs its effective definition frozen at dispatch, never agent_versions
427
+ // (spec §6.3), and works for the parent call that dispatched this run
428
+ const started = await this.d.eventLog.findByIdem(conversationId, "subagent_started");
429
+ if (started?.type !== "subagent_started") {
430
+ throw new Error(`sub-agent conversation ${conversationId} has no subagent_started`);
431
+ }
432
+ // a follow-up runs with its task message's narrowing (final review I1): the frozen tools
433
+ // and org skills the current version still allows, recorded at its dispatch
434
+ const trigger = (await this.d.eventLog.readAfter(conversationId, Number(run.trigger_seq) - 1, 1))[0];
435
+ agent = childRunDefinition(normalizeStoredDefinition(started.payload.definition), trigger?.type === "user_message" && trigger.seq === Number(run.trigger_seq)
436
+ ? trigger.payload.dispatch?.narrowed
437
+ : undefined);
438
+ maxSteps = Math.min(started.payload.maxSteps, runtime.maxSteps);
439
+ const row = await dispatchOfChildRun(this.d.db, runId);
440
+ const otherAgent = started.payload.template.source === "agent";
441
+ parent = row
442
+ ? {
443
+ conversationId: row.parentConversationId,
444
+ runId: row.parentRunId,
445
+ callId: row.parentCallId,
446
+ otherAgent,
447
+ }
448
+ : {
449
+ conversationId: started.payload.parent.conversationId,
450
+ runId: started.payload.parent.runId,
451
+ callId: started.payload.parent.callId,
452
+ otherAgent,
453
+ };
454
+ }
455
+ else {
456
+ const version = await this.d.db
457
+ .selectFrom("agent_versions")
458
+ .select("definition")
459
+ .where("agent_id", "=", conv.agent_id)
460
+ .where("version", "=", run.agent_version)
461
+ .executeTakeFirstOrThrow();
462
+ saved = normalizeStoredDefinition(version.definition);
463
+ agent = saved;
464
+ }
465
+ let startedAt = run.started_at;
466
+ // The model / effort switch in effect (UI refresh B): the latest `model_switched` before this
467
+ // run's `run_started`, read under the conversation lock when the run starts, so a replay
468
+ // (`selectionAt`) sees exactly what the run used.
469
+ // A sub-agent (no `saved`) runs its frozen definition as is.
470
+ const existingStart = await this.d.eventLog.findByIdem(conversationId, `run_started:${runId}`);
471
+ if (existingStart && saved !== undefined) {
472
+ agent = effectiveDefinition(saved, await readSelection(this.d.db, conversationId, existingStart.seq));
473
+ }
474
+ if (run.status === "queued" || startedAt === null) {
475
+ if (!existingStart) {
476
+ if (saved !== undefined)
477
+ await this.fallBackIfUnavailable(conversationId, runId, saved);
478
+ const toSeq = await this.d.db.transaction().execute(async (t) => {
479
+ await t
480
+ .selectFrom("conversations")
481
+ .select("id")
482
+ .where("id", "=", conversationId)
483
+ .forUpdate()
484
+ .execute();
485
+ if (saved !== undefined) {
486
+ agent = effectiveDefinition(saved, await readSelection(t, conversationId));
487
+ }
488
+ const [ev] = await this.d.eventLog.append(conversationId, [
489
+ {
490
+ type: "run_started",
491
+ runId,
492
+ idemKey: `run_started:${runId}`,
493
+ payload: {
494
+ agentVersion: run.agent_version,
495
+ model: agent.model,
496
+ triggerAccountId: run.trigger_account_id,
497
+ },
498
+ },
499
+ ], t);
500
+ return ev?.seq;
501
+ });
502
+ if (toSeq !== undefined)
503
+ await this.d.eventLog.notify(conversationId, toSeq);
504
+ }
505
+ // 技能目录快照(Ruling M17):在置为 running 之前写,崩溃重试时仍走这里(幂等键去重)
506
+ try {
507
+ await recordSkillsCatalog({
508
+ db: this.d.db,
509
+ eventLog: this.d.eventLog,
510
+ log: this.d.log,
511
+ ...(this.d.storage !== undefined && { storage: this.d.storage }),
512
+ }, {
513
+ orgId: conv.org_id,
514
+ agentId: conv.agent_id,
515
+ conversationId,
516
+ runId,
517
+ agent,
518
+ });
519
+ }
520
+ catch (e) {
521
+ // Pinned skill bodies could not be read (Decision 9), or the pinned skills kept changing
522
+ // while they were read (`conflict`): fail before any model request. A transient failure
523
+ // or a conflict is fixed by sending again; a permanent one names the skill for the owner
524
+ // (`recordSkillsCatalog` already logged it at error). Other errors take the generic path.
525
+ if (!(e instanceof ApiError) ||
526
+ (e.code !== "storage.unavailable" && e.code !== "conflict")) {
527
+ throw e;
528
+ }
529
+ this.d.log.warn("skills catalog not recorded at run start", {
530
+ conversationId,
531
+ runId,
532
+ code: e.code,
533
+ err: e,
534
+ });
535
+ const message = e.code === "conflict" ? e.message : pinnedFailureText(e);
536
+ await this.finish(conversationId, runId, "failed", null, {
537
+ type: "run_failed",
538
+ payload: { error: { code: e.code, message } },
539
+ });
540
+ return "finished";
541
+ }
542
+ const updated = await this.d.db
543
+ .updateTable("runs")
544
+ .set({ status: "running", started_at: sql `COALESCE(started_at, now())` })
545
+ .where("id", "=", runId)
546
+ .returning("started_at")
547
+ .executeTakeFirstOrThrow();
548
+ startedAt = updated.started_at;
549
+ }
550
+ // 截止时间以首次开始为准:停机后在其他 worker 续跑也不重新计时;等人处理的时长(waited_ms)不计入。
551
+ const deadline = startedAt.getTime() + Number(run.waited_ms) + runtime.maxRunSeconds * 1000;
552
+ const ac = new AbortController();
553
+ let abortedBy;
554
+ let abortDetail;
555
+ let deadlineHit = false;
556
+ const deadlineTimer = setTimeout(() => {
557
+ deadlineHit = true;
558
+ ac.abort();
559
+ }, Math.max(0, deadline - Date.now()));
560
+ const quotaTimer = setInterval(() => {
561
+ this.d.quota
562
+ .renew(conv.org_id, runId, ORG_QUOTA_LEASE_MS)
563
+ .then((ok) => {
564
+ if (!ok)
565
+ this.d.log.warn("org quota lease lost", { runId, orgId: conv.org_id });
566
+ })
567
+ .catch((err) => this.d.log.warn("org quota renew failed", { runId, err }));
568
+ }, ORG_QUOTA_LEASE_MS / 3);
569
+ quotaTimer.unref();
570
+ state.stopTimers = () => {
571
+ clearTimeout(deadlineTimer);
572
+ clearInterval(quotaTimer);
573
+ };
574
+ let unwatch;
575
+ try {
576
+ unwatch = await this.d.abort.watch(runId, (by, detail) => {
577
+ abortedBy = by;
578
+ abortDetail = detail;
579
+ ac.abort();
580
+ });
581
+ // 取得会话锁之后再读 consumed_seq(锁内不会有别的运行推进它)。
582
+ const { consumed_seq } = await this.d.db
583
+ .selectFrom("conversations")
584
+ .select("consumed_seq")
585
+ .where("id", "=", conversationId)
586
+ .executeTakeFirstOrThrow();
587
+ const startConsumed = Number(consumed_seq);
588
+ let absorbed = startConsumed;
589
+ const pendingUserMessages = async (afterSeq) => {
590
+ // loop 声明已吸收到 afterSeq(续跑时来自 checkpoint,可能包含之前进程吸收的消息)。
591
+ absorbed = Math.max(absorbed, afterSeq);
592
+ const out = [];
593
+ let after = Math.max(afterSeq, startConsumed);
594
+ for (;;) {
595
+ const page = await this.d.eventLog.readAfter(conversationId, after, READ_PAGE);
596
+ for (const e of page)
597
+ if (e.type === "user_message")
598
+ out.push(e);
599
+ const last = page.at(-1);
600
+ if (page.length < READ_PAGE || !last)
601
+ break;
602
+ after = last.seq;
603
+ }
604
+ // phase D run boundary: a fork invocation is absorbed only by the run it triggers, so it
605
+ // always starts its own run (a chat's only; a child's task message is never cut)
606
+ const kept = conv.kind === "chat" ? forkBoundary(out, Number(run.trigger_seq)) : out;
607
+ for (const e of kept)
608
+ absorbed = Math.max(absorbed, e.seq);
609
+ return kept;
610
+ };
611
+ let outcome;
612
+ try {
613
+ outcome = await this.d.loop.run({
614
+ orgId: conv.org_id,
615
+ conversationId,
616
+ runId,
617
+ agentId: conv.agent_id,
618
+ triggerAccountId: run.trigger_account_id,
619
+ agent,
620
+ agentVersion: run.agent_version,
621
+ signal: ac.signal,
622
+ shutdown: state.shutdown.signal,
623
+ sink: this.d.sinkFor?.(conversationId) ?? noopSink,
624
+ pendingUserMessages,
625
+ limits: { maxSteps, deadline },
626
+ // a sub-agent's conversation fires hooks like a chat, with `parent` set (spec §11)
627
+ conversationKind: conv.kind === "eval" ? "eval" : conv.kind === "subagent" ? "subagent" : "chat",
628
+ ...(parent !== undefined && { parent }),
629
+ });
630
+ }
631
+ catch (e) {
632
+ if (state.abandoned)
633
+ return "abandoned";
634
+ if (state.leaseLost)
635
+ return "interrupted";
636
+ const err = e instanceof RunError ? e : new RunError("run.internal", "The run failed unexpectedly");
637
+ if (!(e instanceof RunError)) {
638
+ this.d.log.error("agent loop threw", { conversationId, runId, err: e });
639
+ }
640
+ // 失败也推进 consumed_seq 到已吸收的位置:否则结束时的 ensureRun 会对同一条消息无限重试;
641
+ // 用户看到 run_failed 后可以重发。
642
+ await this.finish(conversationId, runId, "failed", absorbed, {
643
+ type: "run_failed",
644
+ payload: { error: { code: err.code, message: err.message } },
645
+ });
646
+ return "finished";
647
+ }
648
+ if (state.abandoned)
649
+ return "abandoned";
650
+ // 锁在运行中丢失:无论 loop 返回什么都不写终态,任务回到队列由持锁者续跑。
651
+ if (state.leaseLost)
652
+ return "interrupted";
653
+ // loop 因截止时间停下但按中止返回:按超时收尾。
654
+ if (outcome.kind === "aborted" && abortedBy === undefined && deadlineHit) {
655
+ outcome = { kind: "max_duration", consumedUpToSeq: absorbed };
656
+ }
657
+ switch (outcome.kind) {
658
+ case "interrupted":
659
+ return "interrupted";
660
+ case "suspended":
661
+ // 暂停与用户中止同时发生:仍先置 waiting,再按「等待中中止」取消等待并结束(见 Waits.suspend)。
662
+ state.suspended = {
663
+ waitingFor: outcome.waitingFor,
664
+ ...(abortedBy !== undefined && {
665
+ abort: {
666
+ byAccountId: abortedBy,
667
+ ...(abortDetail !== undefined && { detail: abortDetail }),
668
+ },
669
+ }),
670
+ };
671
+ return "suspended";
672
+ case "aborted":
673
+ await this.finish(conversationId, runId, "aborted", absorbed, {
674
+ type: "run_aborted",
675
+ payload: {
676
+ byAccountId: abortedBy ?? null,
677
+ reason: "user",
678
+ ...(abortDetail !== undefined && { detail: abortDetail }),
679
+ },
680
+ });
681
+ break;
682
+ case "max_duration": {
683
+ // 超时只消费 loop 实际吸收的消息,不按触发消息兜底(R34):截止时间可能在第一次吸收之前就已过
684
+ // (如续跑时已超过 started_at + maxRunSeconds),这些消息没有被回复,留给结束后的 ensureRun 起新一轮。
685
+ const consumed = Math.max(outcome.consumedUpToSeq, startConsumed);
686
+ await this.finish(conversationId, runId, "completed", consumed, { type: "run_finished", payload: { reason: outcome.kind, consumedUpToSeq: consumed } }, true, false);
687
+ this.completed(conversationId);
688
+ break;
689
+ }
690
+ default: {
691
+ // completed / max_steps / budget: the loop always absorbed the trigger message; still
692
+ // floor to it
693
+ const consumed = Math.max(outcome.consumedUpToSeq, Number(run.trigger_seq));
694
+ await this.finish(conversationId, runId, "completed", consumed, {
695
+ type: "run_finished",
696
+ payload: { reason: outcome.kind, consumedUpToSeq: consumed },
697
+ });
698
+ this.completed(conversationId);
699
+ }
700
+ }
701
+ return "finished";
702
+ }
703
+ finally {
704
+ state.stopTimers();
705
+ await unwatch?.().catch((err) => this.d.log.warn("abort unwatch failed", { runId, err }));
706
+ }
707
+ }
708
+ completed(conversationId) {
709
+ try {
710
+ this.d.onRunCompleted?.(conversationId);
711
+ }
712
+ catch (err) {
713
+ this.d.log.warn("onRunCompleted hook failed", { conversationId, err });
714
+ }
715
+ }
716
+ /**
717
+ * When the conversation was switched to a model that no longer resolves (provider disabled,
718
+ * model removed), writes `model_switched { model: null, effort: null, reason: "unavailable" }`
719
+ * for this run (idempotent) and clears the cached selection: the run and the next ones use the
720
+ * agent's model. A provider that only failed to list its models is not "gone" (the run's ladder
721
+ * handles it).
722
+ */
723
+ async fallBackIfUnavailable(conversationId, runId, agent) {
724
+ if (!this.d.models)
725
+ return;
726
+ const sel = await readSelection(this.d.db, conversationId);
727
+ if (sel.model === null || sameModel(sel.model, agent.model))
728
+ return;
729
+ try {
730
+ await this.d.models.resolve(sel.model);
731
+ return;
732
+ }
733
+ catch (e) {
734
+ if (e instanceof ProviderListError)
735
+ return;
736
+ if (!(e instanceof ApiError && e.code === "agent.model_unavailable"))
737
+ throw e;
738
+ }
739
+ this.d.log.warn("switched-to model unavailable; falling back to the agent's model", {
740
+ conversationId,
741
+ runId,
742
+ model: sel.model,
743
+ });
744
+ const ev = await this.d.db.transaction().execute(async (t) => {
745
+ // re-check under the row lock: a person who switched again since the read above wins
746
+ await t
747
+ .selectFrom("conversations")
748
+ .select("id")
749
+ .where("id", "=", conversationId)
750
+ .forUpdate()
751
+ .executeTakeFirst();
752
+ if (!sameSelection(await readSelection(t, conversationId), sel))
753
+ return null;
754
+ const [written] = await this.d.eventLog.append(conversationId, [
755
+ {
756
+ type: "model_switched",
757
+ runId,
758
+ idemKey: `model_fallback:${runId}`,
759
+ payload: { model: null, effort: null, byAccountId: null, reason: "unavailable" },
760
+ },
761
+ ], t);
762
+ await t
763
+ .updateTable("conversations")
764
+ .set({ selection: JSON.stringify(NO_SELECTION) })
765
+ .where("id", "=", conversationId)
766
+ .execute();
767
+ return written ?? null;
768
+ });
769
+ if (ev === null)
770
+ return;
771
+ await this.d.eventLog.notify(conversationId, ev.seq);
772
+ await this.d.eventLog.publishChanged(conversationId, "selection");
773
+ }
774
+ /** 删除已结束运行的 checkpoint thread(失败只记日志)。 */
775
+ async dropCheckpoints(runId) {
776
+ await this.d.checkpoints
777
+ ?.deleteThread(runId)
778
+ .catch((err) => this.d.log.warn("checkpoint delete failed", { runId, err }));
779
+ }
780
+ /**
781
+ * 写终态(见 `finishRun`:运行仍未结束才写,同一事务内推进 `consumed_seq` 并更新 `runs.status`),
782
+ * 提交后发布会话通知,然后调用测试钩子。返回终态事件 seq;运行已是终态 → null。
783
+ */
784
+ async finish(conversationId, runId, status, consumed, event, hook = true, floorToTrigger = true) {
785
+ const stopOpen = this.d.stopOpenCalls;
786
+ let fire = () => { };
787
+ const toSeq = await finishRun(this.d.db, this.d.eventLog, {
788
+ conversationId,
789
+ runId,
790
+ status,
791
+ consumed,
792
+ event,
793
+ floorToTrigger,
794
+ ...(stopOpen !== undefined && {
795
+ beforeTerminal: async (t) => {
796
+ fire = (await stopOpen(t, runId)).fire;
797
+ },
798
+ }),
799
+ });
800
+ if (toSeq !== null)
801
+ fire();
802
+ if (hook)
803
+ await this.d.hooks?.beforeRelease?.(runId, conversationId);
804
+ return toSeq;
805
+ }
806
+ }