@nocobase/app-plugin-agents 0.1.0-beta.11 → 0.1.0-beta.13

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 (330) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/README.md +22 -2
  3. package/dist/client/api/client.d.ts +9 -4
  4. package/dist/client/api/client.d.ts.map +1 -1
  5. package/dist/client/api/client.js +9 -0
  6. package/dist/client/api/client.js.map +1 -1
  7. package/dist/client/api/keys.d.ts +3 -0
  8. package/dist/client/api/keys.d.ts.map +1 -1
  9. package/dist/client/api/keys.js +3 -0
  10. package/dist/client/api/keys.js.map +1 -1
  11. package/dist/client/api/runners.d.ts +8 -4
  12. package/dist/client/api/runners.d.ts.map +1 -1
  13. package/dist/client/api/runners.js +9 -0
  14. package/dist/client/api/runners.js.map +1 -1
  15. package/dist/client/chat/keys.d.ts.map +1 -1
  16. package/dist/client/chat/keys.js +2 -1
  17. package/dist/client/chat/keys.js.map +1 -1
  18. package/dist/client/chat/use-chat.d.ts.map +1 -1
  19. package/dist/client/chat/use-chat.js +8 -1
  20. package/dist/client/chat/use-chat.js.map +1 -1
  21. package/dist/client/components/quota-status.d.ts +16 -0
  22. package/dist/client/components/quota-status.d.ts.map +1 -0
  23. package/dist/client/components/quota-status.js +39 -0
  24. package/dist/client/components/quota-status.js.map +1 -0
  25. package/dist/client/components/runners-refresh.d.ts.map +1 -1
  26. package/dist/client/components/runners-refresh.js +1 -0
  27. package/dist/client/components/runners-refresh.js.map +1 -1
  28. package/dist/client/components/variables/variable-dialogs.d.ts.map +1 -1
  29. package/dist/client/components/variables/variable-dialogs.js +7 -7
  30. package/dist/client/components/variables/variable-dialogs.js.map +1 -1
  31. package/dist/client/config.d.ts +2 -0
  32. package/dist/client/config.d.ts.map +1 -1
  33. package/dist/client/config.js +2 -0
  34. package/dist/client/config.js.map +1 -1
  35. package/dist/client/hooks/use-quota-expiry.d.ts +7 -0
  36. package/dist/client/hooks/use-quota-expiry.d.ts.map +1 -0
  37. package/dist/client/hooks/use-quota-expiry.js +92 -0
  38. package/dist/client/hooks/use-quota-expiry.js.map +1 -0
  39. package/dist/client/kit.d.ts +5 -0
  40. package/dist/client/kit.d.ts.map +1 -1
  41. package/dist/client/kit.js +25 -0
  42. package/dist/client/kit.js.map +1 -1
  43. package/dist/client/lib/agents.d.ts +1 -1
  44. package/dist/client/lib/agents.d.ts.map +1 -1
  45. package/dist/client/lib/agents.js +2 -1
  46. package/dist/client/lib/agents.js.map +1 -1
  47. package/dist/client/lib/format.d.ts +3 -1
  48. package/dist/client/lib/format.d.ts.map +1 -1
  49. package/dist/client/lib/format.js +25 -0
  50. package/dist/client/lib/format.js.map +1 -1
  51. package/dist/client/lib/skill-settings-context.d.ts +9 -0
  52. package/dist/client/lib/skill-settings-context.d.ts.map +1 -0
  53. package/dist/client/lib/skill-settings-context.js +4 -0
  54. package/dist/client/lib/skill-settings-context.js.map +1 -0
  55. package/dist/client/lib/skill-settings.d.ts +12 -0
  56. package/dist/client/lib/skill-settings.d.ts.map +1 -0
  57. package/dist/client/lib/skill-settings.js +37 -0
  58. package/dist/client/lib/skill-settings.js.map +1 -0
  59. package/dist/client/locales/en-US.d.ts +1 -0
  60. package/dist/client/locales/en-US.d.ts.map +1 -1
  61. package/dist/client/locales/en-US.js +1 -0
  62. package/dist/client/locales/en-US.js.map +1 -1
  63. package/dist/client/locales/runtimes.en-US.d.ts +72 -0
  64. package/dist/client/locales/runtimes.en-US.d.ts.map +1 -1
  65. package/dist/client/locales/runtimes.en-US.js +73 -1
  66. package/dist/client/locales/runtimes.en-US.js.map +1 -1
  67. package/dist/client/locales/runtimes.zh-CN.d.ts.map +1 -1
  68. package/dist/client/locales/runtimes.zh-CN.js +72 -0
  69. package/dist/client/locales/runtimes.zh-CN.js.map +1 -1
  70. package/dist/client/locales/skills.en-US.d.ts +6 -0
  71. package/dist/client/locales/skills.en-US.d.ts.map +1 -1
  72. package/dist/client/locales/skills.en-US.js +6 -0
  73. package/dist/client/locales/skills.en-US.js.map +1 -1
  74. package/dist/client/locales/skills.zh-CN.d.ts.map +1 -1
  75. package/dist/client/locales/skills.zh-CN.js +6 -0
  76. package/dist/client/locales/skills.zh-CN.js.map +1 -1
  77. package/dist/client/locales/zh-CN.d.ts.map +1 -1
  78. package/dist/client/locales/zh-CN.js +1 -0
  79. package/dist/client/locales/zh-CN.js.map +1 -1
  80. package/dist/client/pages/agents/agent-dialog.d.ts.map +1 -1
  81. package/dist/client/pages/agents/agent-dialog.js +4 -4
  82. package/dist/client/pages/agents/agent-dialog.js.map +1 -1
  83. package/dist/client/pages/agents/runner-agents.d.ts.map +1 -1
  84. package/dist/client/pages/agents/runner-agents.js +23 -10
  85. package/dist/client/pages/agents/runner-agents.js.map +1 -1
  86. package/dist/client/pages/runtimes/connect.js.map +1 -1
  87. package/dist/client/pages/runtimes/index.d.ts.map +1 -1
  88. package/dist/client/pages/runtimes/index.js +1 -1
  89. package/dist/client/pages/runtimes/index.js.map +1 -1
  90. package/dist/client/pages/runtimes/quota-targets.d.ts +4 -0
  91. package/dist/client/pages/runtimes/quota-targets.d.ts.map +1 -0
  92. package/dist/client/pages/runtimes/quota-targets.js +18 -0
  93. package/dist/client/pages/runtimes/quota-targets.js.map +1 -0
  94. package/dist/client/pages/runtimes/quota.d.ts +17 -0
  95. package/dist/client/pages/runtimes/quota.d.ts.map +1 -0
  96. package/dist/client/pages/runtimes/quota.js +48 -0
  97. package/dist/client/pages/runtimes/quota.js.map +1 -0
  98. package/dist/client/pages/runtimes/runner-cells.d.ts +11 -4
  99. package/dist/client/pages/runtimes/runner-cells.d.ts.map +1 -1
  100. package/dist/client/pages/runtimes/runner-cells.js +2 -2
  101. package/dist/client/pages/runtimes/runner-cells.js.map +1 -1
  102. package/dist/client/pages/runtimes/runner-overview.d.ts +9 -0
  103. package/dist/client/pages/runtimes/runner-overview.d.ts.map +1 -0
  104. package/dist/client/pages/runtimes/runner-overview.js +109 -0
  105. package/dist/client/pages/runtimes/runner-overview.js.map +1 -0
  106. package/dist/client/pages/runtimes/runner-runs.d.ts +5 -0
  107. package/dist/client/pages/runtimes/runner-runs.d.ts.map +1 -0
  108. package/dist/client/pages/runtimes/runner-runs.js +35 -0
  109. package/dist/client/pages/runtimes/runner-runs.js.map +1 -0
  110. package/dist/client/pages/runtimes/runner-sheet.d.ts +2 -3
  111. package/dist/client/pages/runtimes/runner-sheet.d.ts.map +1 -1
  112. package/dist/client/pages/runtimes/runner-sheet.js +43 -171
  113. package/dist/client/pages/runtimes/runner-sheet.js.map +1 -1
  114. package/dist/client/pages/runtimes/runner-tools.d.ts +17 -0
  115. package/dist/client/pages/runtimes/runner-tools.d.ts.map +1 -0
  116. package/dist/client/pages/runtimes/runner-tools.js +75 -0
  117. package/dist/client/pages/runtimes/runner-tools.js.map +1 -0
  118. package/dist/client/pages/runtimes/runner-workspaces.d.ts +6 -0
  119. package/dist/client/pages/runtimes/runner-workspaces.d.ts.map +1 -0
  120. package/dist/client/pages/runtimes/runner-workspaces.js +37 -0
  121. package/dist/client/pages/runtimes/runner-workspaces.js.map +1 -0
  122. package/dist/client/pages/runtimes/tool-slots-fields.js +1 -1
  123. package/dist/client/pages/runtimes/tool-slots-fields.js.map +1 -1
  124. package/dist/client/pages/runtimes/workspace-diagnostics.d.ts +6 -4
  125. package/dist/client/pages/runtimes/workspace-diagnostics.d.ts.map +1 -1
  126. package/dist/client/pages/runtimes/workspace-diagnostics.js +61 -37
  127. package/dist/client/pages/runtimes/workspace-diagnostics.js.map +1 -1
  128. package/dist/client/pages/skills/detail/index.d.ts.map +1 -1
  129. package/dist/client/pages/skills/detail/index.js +11 -12
  130. package/dist/client/pages/skills/detail/index.js.map +1 -1
  131. package/dist/database/migrations/.manifest.json +4 -0
  132. package/dist/database/migrations/202610170001_ag_runner_quota.d.ts +4 -0
  133. package/dist/database/migrations/202610170001_ag_runner_quota.d.ts.map +1 -0
  134. package/dist/database/migrations/202610170001_ag_runner_quota.js +19 -0
  135. package/dist/database/migrations/202610170001_ag_runner_quota.js.map +1 -0
  136. package/dist/package.json +1 -1
  137. package/dist/server/cli/surface.d.ts.map +1 -1
  138. package/dist/server/cli/surface.js +4 -1
  139. package/dist/server/cli/surface.js.map +1 -1
  140. package/dist/server/composition.d.ts +2 -0
  141. package/dist/server/composition.d.ts.map +1 -1
  142. package/dist/server/composition.js +15 -4
  143. package/dist/server/composition.js.map +1 -1
  144. package/dist/server/core/agents/agent.service.d.ts.map +1 -1
  145. package/dist/server/core/agents/agent.service.js +5 -1
  146. package/dist/server/core/agents/agent.service.js.map +1 -1
  147. package/dist/server/core/agents/agent.store.d.ts +2 -0
  148. package/dist/server/core/agents/agent.store.d.ts.map +1 -1
  149. package/dist/server/core/agents/agent.store.js +10 -0
  150. package/dist/server/core/agents/agent.store.js.map +1 -1
  151. package/dist/server/core/agents/agent.views.d.ts.map +1 -1
  152. package/dist/server/core/agents/agent.views.js +2 -0
  153. package/dist/server/core/agents/agent.views.js.map +1 -1
  154. package/dist/server/core/agents/index.d.ts +1 -1
  155. package/dist/server/core/agents/index.d.ts.map +1 -1
  156. package/dist/server/core/agents/index.js +1 -1
  157. package/dist/server/core/agents/index.js.map +1 -1
  158. package/dist/server/core/brief/brief.js +2 -2
  159. package/dist/server/core/brief/brief.js.map +1 -1
  160. package/dist/server/core/callers/index.d.ts +9 -0
  161. package/dist/server/core/callers/index.d.ts.map +1 -1
  162. package/dist/server/core/callers/index.js +15 -0
  163. package/dist/server/core/callers/index.js.map +1 -1
  164. package/dist/server/core/conversations/chat-settings.d.ts.map +1 -1
  165. package/dist/server/core/conversations/chat-settings.js +12 -2
  166. package/dist/server/core/conversations/chat-settings.js.map +1 -1
  167. package/dist/server/core/conversations/conversation.service.d.ts +1 -1
  168. package/dist/server/core/conversations/conversation.service.d.ts.map +1 -1
  169. package/dist/server/core/conversations/conversation.service.js +32 -4
  170. package/dist/server/core/conversations/conversation.service.js.map +1 -1
  171. package/dist/server/core/reports/model-usage.d.ts.map +1 -1
  172. package/dist/server/core/reports/model-usage.js +42 -44
  173. package/dist/server/core/reports/model-usage.js.map +1 -1
  174. package/dist/server/core/reports/prices.d.ts.map +1 -1
  175. package/dist/server/core/reports/prices.js +29 -5
  176. package/dist/server/core/reports/prices.js.map +1 -1
  177. package/dist/server/core/reports/report.service.d.ts +4 -2
  178. package/dist/server/core/reports/report.service.d.ts.map +1 -1
  179. package/dist/server/core/reports/report.service.js +147 -68
  180. package/dist/server/core/reports/report.service.js.map +1 -1
  181. package/dist/server/core/runs/availability.d.ts +5 -1
  182. package/dist/server/core/runs/availability.d.ts.map +1 -1
  183. package/dist/server/core/runs/availability.js +8 -2
  184. package/dist/server/core/runs/availability.js.map +1 -1
  185. package/dist/server/core/runs/claim.d.ts +7 -48
  186. package/dist/server/core/runs/claim.d.ts.map +1 -1
  187. package/dist/server/core/runs/claim.js +93 -71
  188. package/dist/server/core/runs/claim.js.map +1 -1
  189. package/dist/server/core/runs/eligibility.d.ts +11 -1
  190. package/dist/server/core/runs/eligibility.d.ts.map +1 -1
  191. package/dist/server/core/runs/eligibility.js +38 -7
  192. package/dist/server/core/runs/eligibility.js.map +1 -1
  193. package/dist/server/core/runs/execution-view.d.ts +8 -0
  194. package/dist/server/core/runs/execution-view.d.ts.map +1 -1
  195. package/dist/server/core/runs/execution-view.js +9 -0
  196. package/dist/server/core/runs/execution-view.js.map +1 -1
  197. package/dist/server/core/runs/execution.d.ts +1 -1
  198. package/dist/server/core/runs/execution.d.ts.map +1 -1
  199. package/dist/server/core/runs/execution.js +8 -2
  200. package/dist/server/core/runs/execution.js.map +1 -1
  201. package/dist/server/core/runs/index.d.ts +3 -3
  202. package/dist/server/core/runs/index.d.ts.map +1 -1
  203. package/dist/server/core/runs/index.js +3 -3
  204. package/dist/server/core/runs/index.js.map +1 -1
  205. package/dist/server/core/runs/lifecycle.d.ts +9 -0
  206. package/dist/server/core/runs/lifecycle.d.ts.map +1 -1
  207. package/dist/server/core/runs/lifecycle.js +102 -18
  208. package/dist/server/core/runs/lifecycle.js.map +1 -1
  209. package/dist/server/core/runs/policy.d.ts +9 -2
  210. package/dist/server/core/runs/policy.d.ts.map +1 -1
  211. package/dist/server/core/runs/policy.js +17 -8
  212. package/dist/server/core/runs/policy.js.map +1 -1
  213. package/dist/server/core/runs/run.service.d.ts +11 -1
  214. package/dist/server/core/runs/run.service.d.ts.map +1 -1
  215. package/dist/server/core/runs/run.service.js +32 -2
  216. package/dist/server/core/runs/run.service.js.map +1 -1
  217. package/dist/server/core/runs/run.store.d.ts +5 -0
  218. package/dist/server/core/runs/run.store.d.ts.map +1 -1
  219. package/dist/server/core/runs/run.store.js +35 -11
  220. package/dist/server/core/runs/run.store.js.map +1 -1
  221. package/dist/server/core/runs/runner-view.d.ts +11 -1
  222. package/dist/server/core/runs/runner-view.d.ts.map +1 -1
  223. package/dist/server/core/runs/runner-view.js +51 -6
  224. package/dist/server/core/runs/runner-view.js.map +1 -1
  225. package/dist/server/core/runs/sweeper.d.ts.map +1 -1
  226. package/dist/server/core/runs/sweeper.js +12 -8
  227. package/dist/server/core/runs/sweeper.js.map +1 -1
  228. package/dist/server/core/runs/transitions.d.ts +5 -1
  229. package/dist/server/core/runs/transitions.d.ts.map +1 -1
  230. package/dist/server/core/runs/transitions.js +31 -11
  231. package/dist/server/core/runs/transitions.js.map +1 -1
  232. package/dist/server/core/runs/workload.d.ts +17 -6
  233. package/dist/server/core/runs/workload.d.ts.map +1 -1
  234. package/dist/server/core/runs/workload.js +186 -129
  235. package/dist/server/core/runs/workload.js.map +1 -1
  236. package/dist/server/core/skills/skill.service.d.ts.map +1 -1
  237. package/dist/server/core/skills/skill.service.js +44 -8
  238. package/dist/server/core/skills/skill.service.js.map +1 -1
  239. package/dist/server/core/transaction-read.d.ts +4 -0
  240. package/dist/server/core/transaction-read.d.ts.map +1 -0
  241. package/dist/server/core/transaction-read.js +30 -0
  242. package/dist/server/core/transaction-read.js.map +1 -0
  243. package/dist/server/core/variables/index.d.ts +1 -1
  244. package/dist/server/core/variables/index.d.ts.map +1 -1
  245. package/dist/server/core/variables/index.js.map +1 -1
  246. package/dist/server/core/variables/variable.service.d.ts +18 -0
  247. package/dist/server/core/variables/variable.service.d.ts.map +1 -1
  248. package/dist/server/core/variables/variable.service.js +95 -20
  249. package/dist/server/core/variables/variable.service.js.map +1 -1
  250. package/dist/server/index.d.ts +2 -0
  251. package/dist/server/index.d.ts.map +1 -1
  252. package/dist/server/index.js +2 -0
  253. package/dist/server/index.js.map +1 -1
  254. package/dist/server/kernel/events.d.ts +4 -2
  255. package/dist/server/kernel/events.d.ts.map +1 -1
  256. package/dist/server/kernel/events.js.map +1 -1
  257. package/dist/server/kernel/scopes.d.ts +6 -0
  258. package/dist/server/kernel/scopes.d.ts.map +1 -1
  259. package/dist/server/kernel/scopes.js.map +1 -1
  260. package/dist/server/online/services.d.ts.map +1 -1
  261. package/dist/server/online/services.js +101 -24
  262. package/dist/server/online/services.js.map +1 -1
  263. package/dist/server/providers/agents.d.ts +9 -1
  264. package/dist/server/providers/agents.d.ts.map +1 -1
  265. package/dist/server/providers/agents.js +3 -0
  266. package/dist/server/providers/agents.js.map +1 -1
  267. package/dist/server/providers/runners.d.ts +3 -1
  268. package/dist/server/providers/runners.d.ts.map +1 -1
  269. package/dist/server/providers/runners.js +12 -3
  270. package/dist/server/providers/runners.js.map +1 -1
  271. package/dist/server/routes/admin.d.ts +2 -0
  272. package/dist/server/routes/admin.d.ts.map +1 -1
  273. package/dist/server/routes/admin.js +18 -5
  274. package/dist/server/routes/admin.js.map +1 -1
  275. package/dist/server/routes/chat.d.ts.map +1 -1
  276. package/dist/server/routes/chat.js +27 -6
  277. package/dist/server/routes/chat.js.map +1 -1
  278. package/dist/server/routes/index.d.ts.map +1 -1
  279. package/dist/server/routes/index.js +3 -0
  280. package/dist/server/routes/index.js.map +1 -1
  281. package/dist/server/routes/runners/admin.d.ts.map +1 -1
  282. package/dist/server/routes/runners/admin.js +219 -25
  283. package/dist/server/routes/runners/admin.js.map +1 -1
  284. package/dist/server/routes/runners/install.d.ts.map +1 -1
  285. package/dist/server/routes/runners/install.js +7 -2
  286. package/dist/server/routes/runners/install.js.map +1 -1
  287. package/dist/server/routes/schemas.d.ts +13 -6
  288. package/dist/server/routes/schemas.d.ts.map +1 -1
  289. package/dist/server/routes/schemas.js +350 -66
  290. package/dist/server/routes/schemas.js.map +1 -1
  291. package/dist/server/runners/runner.service.d.ts +27 -3
  292. package/dist/server/runners/runner.service.d.ts.map +1 -1
  293. package/dist/server/runners/runner.service.js +336 -83
  294. package/dist/server/runners/runner.service.js.map +1 -1
  295. package/dist/server/runners/runner.store.d.ts +4 -2
  296. package/dist/server/runners/runner.store.d.ts.map +1 -1
  297. package/dist/server/runners/runner.store.js +24 -5
  298. package/dist/server/runners/runner.store.js.map +1 -1
  299. package/dist/server/runners/slots.d.ts +5 -2
  300. package/dist/server/runners/slots.d.ts.map +1 -1
  301. package/dist/server/runners/slots.js +3 -4
  302. package/dist/server/runners/slots.js.map +1 -1
  303. package/dist/shared/agents.d.ts +3 -0
  304. package/dist/shared/agents.d.ts.map +1 -1
  305. package/dist/shared/agents.js +0 -15
  306. package/dist/shared/agents.js.map +1 -1
  307. package/dist/shared/conversations.d.ts +6 -0
  308. package/dist/shared/conversations.d.ts.map +1 -1
  309. package/dist/shared/conversations.js.map +1 -1
  310. package/dist/shared/model-catalog.d.ts +5 -0
  311. package/dist/shared/model-catalog.d.ts.map +1 -1
  312. package/dist/shared/model-catalog.js +35 -1
  313. package/dist/shared/model-catalog.js.map +1 -1
  314. package/dist/shared/quota.d.ts +15 -0
  315. package/dist/shared/quota.d.ts.map +1 -0
  316. package/dist/shared/quota.js +2 -0
  317. package/dist/shared/quota.js.map +1 -0
  318. package/dist/shared/runners.d.ts +88 -5
  319. package/dist/shared/runners.d.ts.map +1 -1
  320. package/dist/shared/runners.js +126 -8
  321. package/dist/shared/runners.js.map +1 -1
  322. package/dist/shared/runs.d.ts +10 -0
  323. package/dist/shared/runs.d.ts.map +1 -1
  324. package/dist/shared/runs.js +22 -0
  325. package/dist/shared/runs.js.map +1 -1
  326. package/dist/shared/skills.d.ts +3 -1
  327. package/dist/shared/skills.d.ts.map +1 -1
  328. package/dist/shared/skills.js.map +1 -1
  329. package/package.json +14 -14
  330. package/skills/nocobase-app-plugin-agents/references/runners.md +12 -0
@@ -1,50 +1,8 @@
1
- /**
2
- * Claiming: handing queued runs to a runner that fits them, within each agent's concurrency limit, one run per
3
- * (agent, subject, thread) at a time, through the runners' one long-poll (`routes/runners/runner.ts`), which hands
4
- * out jobs from the same slots. A runner fits a run when it has the agent's
5
- * tool enabled (on the web), installed and signed in, the agent names no runner or names it, it is shared with the
6
- * team or belongs to the person who woke the agent, its features cover what the run requires (worked out from the
7
- * payload: checkouts, directories, skills, secrets), its owner's local policy (`Runner.policy`) lets it take the
8
- * agent's runs on the run's subject and repositories, and it has a free slot. A working directory that is a directory
9
- * on one runner pins the run to that runner, one run at a time per directory. A run's variables go to the runner that
10
- * takes it, personal ones included, unless one of them is for team runners only (`teamRunnersOnly`): then only a team
11
- * runner takes the run, and the variables that asked for one are noted on it (`teamOnlyVariables`), so its wait says
12
- * which.
13
- *
14
- * A slot is free for a run when the runner's total has room and so does the coding tool it runs with: the tool's limit
15
- * (`Runner.toolSlots`, never above the total) over the runs of that tool the runner holds here, and what the runner
16
- * said it can still take of that tool across every application (`ClaimRequest.tools`). The run takes the first of its
17
- * agent's entries whose tool the runner runs and has room for, so an agent listing two tools runs with the second while
18
- * the first is full; a run none of whose tools has room is passed over for the runs behind it.
19
- *
20
- * Variables are checked and opened in the claim's own transaction, on its connection: which ones the assembled payload
21
- * gets, whether any is for team runners only, and their values, so what the runner receives is what was checked. The
22
- * names taken from the runner go in `workspace.passthrough`, without values.
23
- *
24
- * A claim is one transaction per run. It first writes the agent's row (`lockAgentForClaim`): on databases with row
25
- * locks, concurrent claims for the same agent wait there, so the concurrency count read next is current. The run is
26
- * then taken with a guarded update (`status = 'queued'`), so two runners can never take the same run. The payload is
27
- * assembled in the same transaction; if assembly fails the transaction rolls back, the run stays queued, and the
28
- * failure is counted (`claimFailures`) until the run fails `setupFailed`.
29
- *
30
- * Portable by design: the database layer offers no `FOR UPDATE SKIP LOCKED` or advisory locks, and the guarded update
31
- * plus the agent-row write give the same guarantees on every dialect (SQLite serializes writers anyway).
32
- *
33
- * Polls are the hot path: every runner walks the same candidates, so a write per candidate is a write per candidate per
34
- * runner per poll. Everything that rules a candidate out is read outside any transaction — identity, `fits()`, slots,
35
- * concurrency and comment consent — and a transaction opens only for the run about to be claimed. The agent row is
36
- * the only row a claim locks with a self-update, and only in that final transaction after `fits()` (or when a stale
37
- * identity has to be repaired first, which current work never needs). PostgreSQL runs at READ COMMITTED, where each
38
- * statement sees the latest committed rows, so no transaction needs no-op writes to refresh a snapshot; comment
39
- * consent needs no chain lock, because confirmation is final and rejection or Run as me end the chain's queued runs,
40
- * which the guarded update sees. A new write or lock here needs a measured reason (`tests/claim-concurrency.test.ts`
41
- * counts them, and the lock waits on PostgreSQL).
42
-
43
- */
44
1
  import { type AgentTool, type RunApp, type RunnerFeature, type RunPayload, type RunSkill, type WorkspaceDir } from '@nocobase/agent-protocol';
45
2
  import type { DistService } from '../../distribution/index.js';
46
3
  import { type Runner } from '../../../shared/runners.js';
47
4
  import type { DatabaseConnection } from '@nocobase/db';
5
+ import type { Slots } from '../../runners/slots.js';
48
6
  import type { Agent, RunnerModelEntry } from '../../../shared/agents.js';
49
7
  import type { BriefLayers } from '../../../shared/briefs.js';
50
8
  import type { Run, ModelSelectionWait } from '../../../shared/runs.js';
@@ -96,6 +54,7 @@ export interface ClaimDeps extends TransitionDeps {
96
54
  /** The tarballs the application serves, for a `served` CLI. */
97
55
  readonly dist?: Pick<DistService, 'find'>;
98
56
  /** What a runner holds now (its slots); runs and jobs share them. */
57
+ readonly slotsHeld: Slots['held'];
99
58
  readonly slotsUsed: (conn: DatabaseConnection, runnerId: string) => Promise<number>;
100
59
  /** Sections the application adds to every brief's context layer. */
101
60
  readonly sections?: BriefSectionRegistry;
@@ -111,21 +70,21 @@ export interface ClaimDeps extends TransitionDeps {
111
70
  * The entry `runner` takes a run of `agent` with: the first whose tool it has enabled, installed and signed in, with
112
71
  * the entry's model among those it reports (`runsEntry`). Null when it has none of them.
113
72
  */
114
- export declare function pickEntry(runner: Runner, agent: Pick<Agent, 'modelEntries'>): RunnerModelEntry | null;
73
+ export declare function pickEntry(runner: Runner, agent: Pick<Agent, 'modelEntries'>, now: number): RunnerModelEntry | null;
115
74
  /**
116
75
  * The entry `runner` takes a run of `agent` with when some of its tools are full: the first whose tool it runs and
117
76
  * `open` says has room. Null when none has.
118
77
  */
119
- export declare function pickOpenEntry(runner: Runner, agent: Pick<Agent, 'modelEntries'>, open: (tool: AgentTool) => boolean): RunnerModelEntry | null;
78
+ export declare function pickOpenEntry(runner: Runner, agent: Pick<Agent, 'modelEntries'>, open: (tool: AgentTool) => boolean, now: number): RunnerModelEntry | null;
120
79
  /** Whether `runner` has one of `agent`'s tools and models enabled, installed, signed in and reported. */
121
- export declare function hasTool(runner: Runner, agent: Pick<Agent, 'modelEntries'>): boolean;
80
+ export declare function hasTool(runner: Runner, agent: Pick<Agent, 'modelEntries'>, now: number): boolean;
122
81
  /**
123
82
  * Whether `runner` may run work of `agent` as `actorUserId` that needs `requires`, before any lock is taken and before
124
83
  * a payload is known: the agent enabled, its tool and model reported there, its owner's policy, and trust.
125
84
  */
126
- export declare function fitsActor(runner: Runner, agent: Agent, actorUserId: string, requires: readonly RunnerFeature[]): boolean;
85
+ export declare function fitsActor(runner: Runner, agent: Agent, actorUserId: string, requires: readonly RunnerFeature[], now: number): boolean;
127
86
  /** Whether `runner` may run `run` of `agent`, before any lock is taken and before its payload is known. */
128
- export declare function fits(runner: Runner, agent: Agent, run: RunRecord): boolean;
87
+ export declare function fits(runner: Runner, agent: Agent, run: RunRecord, now: number): boolean;
129
88
  /** The runner features a payload needs. */
130
89
  export declare function payloadRequires(dirs: readonly WorkspaceDir[], skills: number, variables: number, workspaceKey?: boolean): RunnerFeature[];
131
90
  /** The working directories as a runner receives them: without what only the server uses. */
@@ -1 +1 @@
1
- {"version":3,"file":"claim.d.ts","sourceRoot":"","sources":["../../../../server/core/runs/claim.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claim.d.ts","sourceRoot":"","sources":["../../../../server/core/runs/claim.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- import { GLOBAL_SKILL_TARGET } from '../../../shared/skills.js';
2
1
  /**
3
2
  * Claiming: handing queued runs to a runner that fits them, within each agent's concurrency limit, one run per
4
3
  * (agent, subject, thread) at a time, through the runners' one long-poll (`routes/runners/runner.ts`), which hands
@@ -42,6 +41,7 @@ import { GLOBAL_SKILL_TARGET } from '../../../shared/skills.js';
42
41
  * counts them, and the lock waits on PostgreSQL).
43
42
 
44
43
  */
44
+ import { GLOBAL_SKILL_TARGET } from '../../../shared/skills.js';
45
45
  import { ANNOUNCED_FAILURES, isProtocolSupported, policyAllowsAgent, policyAllowsRepo, policyAllowsSubject, TIMINGS, } from '@nocobase/agent-protocol';
46
46
  import { runnerLowOnDisk, runsEntry, toolLimit, supportsWorkspaceKey, } from '../../../shared/runners.js';
47
47
  import { queueStart } from './selection.js';
@@ -50,7 +50,7 @@ import { later } from '../../kernel/clock.js';
50
50
  import { notFound } from '../../kernel/errors.js';
51
51
  import { runSecretsKey } from '../../kernel/redaction.js';
52
52
  import { cleanList, covers, jsonObject } from '../../kernel/values.js';
53
- import { findAgent, lockAgentForClaim } from '../agents/index.js';
53
+ import { findAgent, findAgents, lockAgentForClaim } from '../agents/index.js';
54
54
  import { joinBrief, renderBrief } from '../brief/index.js';
55
55
  import { cliPackageFor } from './cli-package.js';
56
56
  import { executionHistory } from './execution.js';
@@ -58,7 +58,6 @@ import { describeVariables, variableRefs, } from '../variables/index.js';
58
58
  import { mountsFor, prepareExtensions, repoAccessFor, sessionKeyOf, withSections, } from './extensions.js';
59
59
  import { MAX_CLAIM_FAILURES, toolPolicyFor } from './policy.js';
60
60
  import { mintRunToken } from './run-tokens.js';
61
- import { runsHeldByTool } from './runner-view.js';
62
61
  import { ACTIVE, countActive, eventsRepo, findRunRecord, markDelivered, pendingInputs, runsOfKey, runsRepo, inputsRepo, sessionsRepo, toInput, toExecutions, toRun, } from './run.store.js';
63
62
  import { dropInputs } from './input-gate.js';
64
63
  import { finishRun } from './transitions.js';
@@ -107,25 +106,25 @@ function toolRoom(tools) {
107
106
  * The entry `runner` takes a run of `agent` with: the first whose tool it has enabled, installed and signed in, with
108
107
  * the entry's model among those it reports (`runsEntry`). Null when it has none of them.
109
108
  */
110
- export function pickEntry(runner, agent) {
111
- return agent.modelEntries.find((entry) => runsEntry(runner, entry)) ?? null;
109
+ export function pickEntry(runner, agent, now) {
110
+ return (agent.modelEntries.find((entry) => runsEntry(runner, entry, now)) ?? null);
112
111
  }
113
112
  /**
114
113
  * The entry `runner` takes a run of `agent` with when some of its tools are full: the first whose tool it runs and
115
114
  * `open` says has room. Null when none has.
116
115
  */
117
- export function pickOpenEntry(runner, agent, open) {
118
- return (agent.modelEntries.find((entry) => runsEntry(runner, entry) && open(entry.tool)) ?? null);
116
+ export function pickOpenEntry(runner, agent, open, now) {
117
+ return (agent.modelEntries.find((entry) => runsEntry(runner, entry, now) && open(entry.tool)) ?? null);
119
118
  }
120
119
  /** Whether `runner` has one of `agent`'s tools and models enabled, installed, signed in and reported. */
121
- export function hasTool(runner, agent) {
122
- return pickEntry(runner, agent) !== null;
120
+ export function hasTool(runner, agent, now) {
121
+ return pickEntry(runner, agent, now) !== null;
123
122
  }
124
123
  /**
125
124
  * Whether `runner` may run work of `agent` as `actorUserId` that needs `requires`, before any lock is taken and before
126
125
  * a payload is known: the agent enabled, its tool and model reported there, its owner's policy, and trust.
127
126
  */
128
- export function fitsActor(runner, agent, actorUserId, requires) {
127
+ export function fitsActor(runner, agent, actorUserId, requires, now) {
129
128
  if (agent.status !== 'enabled' || runnerLowOnDisk(runner))
130
129
  return false;
131
130
  if (!isProtocolSupported(runner.protocolVersion) ||
@@ -134,15 +133,15 @@ export function fitsActor(runner, agent, actorUserId, requires) {
134
133
  return false;
135
134
  if (!covers(runner.features, requires))
136
135
  return false;
137
- if (!hasTool(runner, agent))
136
+ if (!hasTool(runner, agent, now))
138
137
  return false;
139
138
  if (!policyAllowsAgent(runner.policy, agent))
140
139
  return false;
141
140
  return runner.trust === 'team' || runner.ownerUserId === actorUserId;
142
141
  }
143
142
  /** Whether `runner` may run `run` of `agent`, before any lock is taken and before its payload is known. */
144
- export function fits(runner, agent, run) {
145
- return fitsActor(runner, agent, run.actorUserId, toRun(run).requires);
143
+ export function fits(runner, agent, run, now) {
144
+ return fitsActor(runner, agent, run.actorUserId, toRun(run).requires, now);
146
145
  }
147
146
  /** The runner features a payload needs. */
148
147
  export function payloadRequires(dirs, skills, variables, workspaceKey = false) {
@@ -247,30 +246,46 @@ async function settleClaimInputs(conn, pending, effective, now) {
247
246
  }
248
247
  export function createClaimService(deps) {
249
248
  const { tx, clock } = deps;
249
+ /** Reuse only identical ordered targets, within this attempt and connection. */
250
+ function claimResources(conn, runId) {
251
+ const cache = new Map();
252
+ return (agent, assembly) => {
253
+ const skills = skillTargets(agent, assembly);
254
+ const variables = variableTargets(agent, assembly);
255
+ const key = JSON.stringify([skills, variables]);
256
+ let result = cache.get(key);
257
+ if (!result) {
258
+ result = (async () => ({
259
+ skills: await deps.skills.forRun(conn, skills, runId),
260
+ variables: await deps.variables.prepareRun(conn, variables),
261
+ }))();
262
+ cache.set(key, result);
263
+ }
264
+ return result;
265
+ };
266
+ }
250
267
  /** Database reads only; used by the actual claim and ordered-model diagnostics. */
251
- async function assemblyCompatibility(conn, run, agent, runner, assembly) {
268
+ async function assemblyCompatibility(conn, run, agent, runner, assembly, resources = claimResources(conn, run.id)) {
252
269
  if (!isProtocolSupported(runner.protocolVersion) ||
253
270
  (assembly.workspaceKey && !supportsWorkspaceKey(runner)))
254
271
  return 'incompatible';
255
- const skills = await deps.skills.forRun(conn, skillTargets(agent, assembly), run.id);
256
- const targets = variableTargets(agent, assembly);
257
- const names = await deps.variables.namesOf(conn, targets);
272
+ const { skills, variables } = await resources(agent, assembly);
273
+ const names = variables.names;
258
274
  if (!covers(runner.features, [
259
275
  ...run.requires,
260
276
  ...payloadRequires(payloadDirs(assembly.dirs), skills.length, names.length, Boolean(assembly.workspaceKey)),
261
277
  ]))
262
278
  return 'incompatible';
263
- if (!fitsActor(runner, agent, run.actorUserId, run.requires) ||
279
+ if (!fitsActor(runner, agent, run.actorUserId, run.requires, clock.now().getTime()) ||
264
280
  !policyAllowsSubject(runner.policy, assembly.subject.key) ||
265
281
  assembly.dirs.some((dir) => (dir.kind === 'repo' && !policyAllowsRepo(runner.policy, dir.url)) ||
266
282
  (dir.kind === 'directory' && dir.runnerId !== runner.id)))
267
283
  return 'restricted';
268
- if (runner.trust !== 'team' &&
269
- (await deps.variables.teamOnly(conn, targets)).length > 0)
284
+ if (runner.trust !== 'team' && variables.teamOnly.length > 0)
270
285
  return 'restricted';
271
286
  return 'ready';
272
287
  }
273
- async function selectionFacts(conn, run, agent, requirePolicy = true, trust) {
288
+ async function selectionFacts(conn, run, agent, requirePolicy = true, trust, resources = claimResources(conn, run.id)) {
274
289
  const policy = await deps.selectionPolicies?.forRun(conn, run);
275
290
  if ((requirePolicy && !policy) || !deps.runners)
276
291
  return null;
@@ -299,7 +314,7 @@ export function createClaimService(deps) {
299
314
  new Date(runner.lastSeenAt).getTime() + TIMINGS.offlineAfterMs >
300
315
  now.getTime());
301
316
  const installed = connected.filter((runner) => runner.tools.some((tool) => tool.kind === entry.tool));
302
- const usable = installed.filter((runner) => runsEntry(runner, entry));
317
+ const usable = installed.filter((runner) => runsEntry(runner, entry, clock.now().getTime()));
303
318
  const online = usable.filter((runner) => runner.trust === 'team' || runner.ownerUserId === run.actorUserId);
304
319
  const compatible = [];
305
320
  const loads = [];
@@ -339,7 +354,7 @@ export function createClaimService(deps) {
339
354
  });
340
355
  continue;
341
356
  }
342
- const reason = await assemblyCompatibility(conn, run, single, runner, assembly);
357
+ const reason = await assemblyCompatibility(conn, run, single, runner, assembly, resources);
343
358
  if (reason !== 'ready') {
344
359
  incompatible ||= reason === 'incompatible';
345
360
  loads.push({
@@ -350,7 +365,8 @@ export function createClaimService(deps) {
350
365
  });
351
366
  continue;
352
367
  }
353
- const requiredVariables = await deps.variables.passthroughOf(conn, variableTargets(single, assembly));
368
+ const requiredVariables = (await resources(single, assembly)).variables
369
+ .passthrough;
354
370
  if (requiredVariables.length > 0 && runner.variables == null) {
355
371
  unknown = true;
356
372
  continue;
@@ -358,8 +374,9 @@ export function createClaimService(deps) {
358
374
  if (requiredVariables.some((name) => !runner.variables?.includes(name)))
359
375
  continue;
360
376
  compatible.push(runner);
361
- const byTool = await runsHeldByTool(conn, runner.id);
362
- const used = await deps.slotsUsed(conn, runner.id);
377
+ const held = await deps.slotsHeld(conn, runner.id);
378
+ const byTool = held.byTool ?? {};
379
+ const used = held.jobs + held.runs;
363
380
  const directory = directoryKeyOf(runner.id, payloadDirs(assembly.dirs));
364
381
  const blockedDirectory = directory !== null &&
365
382
  (await directoryBusy(conn, runner.id, run.id, directory));
@@ -448,7 +465,7 @@ export function createClaimService(deps) {
448
465
  entries,
449
466
  };
450
467
  }
451
- async function assemble({ conn }, run, agent, runner, inputs, leaseExpiresAt, prepared, entry) {
468
+ async function assemble({ conn }, run, agent, runner, inputs, leaseExpiresAt, prepared, entry, resources = claimResources(conn, run.id)) {
452
469
  const binding = deps.subjects.get(run.subjectKind);
453
470
  if (!binding)
454
471
  throw new Error(`No context provider is registered for subjects of kind "${run.subjectKind}".`);
@@ -463,7 +480,7 @@ export function createClaimService(deps) {
463
480
  };
464
481
  const assembly = await binding.context.assemble(conn, claim, prepared.get('subject'));
465
482
  // workspace.key is required for coordinating runs; old runners must not silently ignore it.
466
- if ((await assemblyCompatibility(conn, toRun(run), agent, runner, assembly)) === 'incompatible')
483
+ if ((await assemblyCompatibility(conn, toRun(run), agent, runner, assembly, resources)) === 'incompatible')
467
484
  throw new NotForThisRunner();
468
485
  inputs = assembly.inputs ?? inputs;
469
486
  const effectiveClaim = { ...claim, inputs };
@@ -480,9 +497,8 @@ export function createClaimService(deps) {
480
497
  if (directoryKey !== null &&
481
498
  (await directoryBusy(conn, runner.id, run.id, directoryKey)))
482
499
  throw new NotForThisRunner();
483
- const skills = await deps.skills.forRun(conn, skillTargets(agent, assembly), run.id);
484
- const variables = variableTargets(agent, assembly);
485
- const names = await deps.variables.namesOf(conn, variables);
500
+ const { skills, variables } = await resources(agent, assembly);
501
+ const names = variables.names;
486
502
  const requires = cleanList([
487
503
  ...view.requires,
488
504
  ...payloadRequires(dirs, skills.length, names.length, Boolean(assembly.workspaceKey)),
@@ -491,19 +507,19 @@ export function createClaimService(deps) {
491
507
  throw new NotForThisRunner();
492
508
  // A variable for team runners only keeps a personal runner off the run.
493
509
  if (names.length > 0 && runner.trust !== 'team') {
494
- const teamOnly = await deps.variables.teamOnly(conn, variables);
510
+ const teamOnly = variables.teamOnly;
495
511
  if (teamOnly.length > 0)
496
512
  throw new TeamRunnersOnly(teamOnly);
497
513
  }
498
514
  const env = names.length > 0
499
- ? await deps.variables.forRun(conn, variables, {
515
+ ? await variables.deliver({
500
516
  runId: run.id,
501
517
  runnerId: runner.id,
502
518
  })
503
519
  : [];
504
520
  // Variables taken from the runner: names only. A runner that does not provide one fails the run while preparing
505
521
  // it, saying how to provide it; runners are not chosen by them.
506
- const passthrough = await deps.variables.passthroughOf(conn, variables);
522
+ const passthrough = variables.passthrough;
507
523
  const nowText = clock.now().toISOString();
508
524
  const clean = await consumeReset(conn, { kind: run.subjectKind, id: run.subjectId }, run.id, nowText);
509
525
  const session = await sessionsRepo(conn).findOne({
@@ -853,8 +869,6 @@ export function createClaimService(deps) {
853
869
  const conn = tx.read();
854
870
  // Rules that do not depend on who the run acts as come first, and settle the rest of the pass: an agent at its
855
871
  // limit is checked once per poll, not once per queued run.
856
- if ((await deps.slotsUsed(conn, runner.id)) >= runner.slots)
857
- return { kind: 'full', scope: 'runner' };
858
872
  if ((await countActive(conn, 'agentId', agent.id)) >= agent.maxConcurrentRuns)
859
873
  return { kind: 'full', scope: 'agent' };
860
874
  // Repair pre-upgrade queued work before even checking personal runner ownership. Reading first keeps a poll over
@@ -873,7 +887,7 @@ export function createClaimService(deps) {
873
887
  candidate = current;
874
888
  }
875
889
  // Avoid assembling or asking authorization when a cheap claim rule already rules this work out.
876
- if (!fits(runner, agent, candidate) ||
890
+ if (!fits(runner, agent, candidate, clock.now().getTime()) ||
877
891
  (await runsOfKey(conn, candidate, ACTIVE)).length > 0)
878
892
  return { kind: 'skipped' };
879
893
  const consent = await commentConsentFor(conn, runner, candidate);
@@ -891,6 +905,7 @@ export function createClaimService(deps) {
891
905
  }
892
906
  }
893
907
  let taken;
908
+ let runnerFull = false;
894
909
  try {
895
910
  taken = await tx.run(async (unit) => {
896
911
  const { conn } = unit;
@@ -908,50 +923,54 @@ export function createClaimService(deps) {
908
923
  agent.maxConcurrentRuns)
909
924
  return null;
910
925
  // Slots are shared with the jobs the runner holds.
911
- if ((await deps.slotsUsed(conn, runner.id)) >= runner.slots)
926
+ const held = await deps.slotsHeld(conn, runner.id);
927
+ if (held.runs + held.jobs >= runner.slots) {
928
+ runnerFull = true;
912
929
  return null;
913
- // The first of the agent's tools with room, by its limit here and by what the runner said it can take.
914
- const byTool = await runsHeldByTool(conn, runner.id);
915
- const current = await findRunRecord(conn, candidate.id);
930
+ }
931
+ // Total and per-tool room come from the same locked snapshot.
932
+ const byTool = held.byTool ?? {};
933
+ const current = identity;
916
934
  if (!current ||
917
935
  current.status !== 'queued' ||
918
936
  (current.availableAt &&
919
937
  new Date(current.availableAt).getTime() > now.getTime()))
920
938
  return null;
921
- const entry = pickOpenEntry(runner, agent, (tool) => (byTool[tool] ?? 0) < toolLimit(runner, tool) && reported.has(tool));
939
+ const entry = pickOpenEntry(runner, agent, (tool) => (byTool[tool] ?? 0) < toolLimit(runner, tool) && reported.has(tool), now.getTime());
922
940
  if (!entry)
923
941
  return null;
924
942
  const busy = await runsOfKey(conn, candidate, ACTIVE);
925
943
  if (busy.length > 0)
926
944
  return null;
927
- const leaseExpiresAt = later(now, TIMINGS.leaseMs);
945
+ const leaseExpiresAt = later(now, TIMINGS.startTimeoutMs);
946
+ const dispatchValues = {
947
+ status: 'dispatched',
948
+ failureReason: null,
949
+ failureDetail: null,
950
+ runnerId: runner.id,
951
+ // Brief providers observe this reservation inside the claim transaction.
952
+ // Replace a previous attempt's tool before computing the roster.
953
+ tool: entry.tool,
954
+ leaseExpiresAt,
955
+ dispatchedAt: nowText,
956
+ lastActivityAt: nowText,
957
+ availableAt: null,
958
+ updatedAt: nowText,
959
+ ...(consent.confirmedByUserId
960
+ ? { confirmedByUserId: consent.confirmedByUserId }
961
+ : {}),
962
+ };
928
963
  const claimed = await runsRepo(conn).updateMany({
929
964
  filter: (f) => f.and([
930
965
  f.string('id').eq(candidate.id),
931
966
  f.string('status').eq('queued'),
932
967
  f.string('actorUserId').eq(candidate.actorUserId),
933
968
  ]),
934
- values: {
935
- status: 'dispatched',
936
- failureReason: null,
937
- failureDetail: null,
938
- runnerId: runner.id,
939
- // Brief providers observe this reservation inside the claim transaction.
940
- // Replace a previous attempt's tool before computing the roster.
941
- tool: entry.tool,
942
- leaseExpiresAt,
943
- dispatchedAt: nowText,
944
- lastActivityAt: nowText,
945
- availableAt: null,
946
- updatedAt: nowText,
947
- ...(consent.confirmedByUserId
948
- ? { confirmedByUserId: consent.confirmedByUserId }
949
- : {}),
950
- },
969
+ values: dispatchValues,
951
970
  });
952
971
  if (claimed.updatedCount !== 1)
953
972
  return null;
954
- const run = (await findRunRecord(conn, candidate.id));
973
+ const run = { ...current, ...dispatchValues };
955
974
  const pending = (await pendingInputs(conn, run.id)).filter((input) => !run.commentRootRunId ||
956
975
  input.type !== 'comment' ||
957
976
  jsonObject(input.payload).commentRootRunId === run.commentRootRunId);
@@ -962,7 +981,8 @@ export function createClaimService(deps) {
962
981
  return null;
963
982
  // Admission must precede preflight assembly: a missing or obsolete
964
983
  // subject is cancelled normally, rather than counted as setup failure.
965
- const selection = await selectionFacts(conn, toRun(current), agent);
984
+ const resources = claimResources(conn, run.id);
985
+ const selection = await selectionFacts(conn, toRun(current), agent, true, undefined, resources);
966
986
  const elapsed = Math.max(0, (now.getTime() - queueStart(toRun(current))) / 1000);
967
987
  const preferredAvailable = (selection?.entries[0]?.compatibleCount ?? 0) > 0 ||
968
988
  selection?.entries[0]?.reason === 'unknown' ||
@@ -983,7 +1003,7 @@ export function createClaimService(deps) {
983
1003
  waitedSeconds: elapsed,
984
1004
  };
985
1005
  }
986
- assembled = await assemble(unit, run, agent, runner, pending.map(toInput), leaseExpiresAt, prepared, entry);
1006
+ assembled = await assemble(unit, run, agent, runner, pending.map(toInput), leaseExpiresAt, prepared, entry, resources);
987
1007
  }
988
1008
  catch (error) {
989
1009
  if (error instanceof NotForThisRunner)
@@ -1050,7 +1070,9 @@ export function createClaimService(deps) {
1050
1070
  }
1051
1071
  if (!taken) {
1052
1072
  await discardRepoAccess(candidate, prepared);
1053
- return { kind: 'skipped' };
1073
+ return runnerFull
1074
+ ? { kind: 'full', scope: 'runner' }
1075
+ : { kind: 'skipped' };
1054
1076
  }
1055
1077
  // After the claim commits, never inside it: decisions settle the request before touching runs, so a claim that
1056
1078
  // held its run while waiting for the request could deadlock with them. A request left pending by a crash here is
@@ -1119,21 +1141,21 @@ export function createClaimService(deps) {
1119
1141
  return null;
1120
1142
  const conn = tx.read();
1121
1143
  const queued = await candidates();
1122
- const agents = new Map();
1144
+ const agents = await findAgents(conn, queued
1145
+ .filter((candidate) => !seen.has(candidate.id))
1146
+ .map((candidate) => candidate.agentId));
1123
1147
  const full = new Set();
1124
1148
  for (const candidate of queued) {
1125
1149
  if (seen.has(candidate.id) || full.has(candidate.agentId))
1126
1150
  continue;
1127
1151
  seen.add(candidate.id);
1128
- if (!agents.has(candidate.agentId))
1129
- agents.set(candidate.agentId, await findAgent(conn, candidate.agentId));
1130
1152
  const agent = agents.get(candidate.agentId);
1131
1153
  if (!agent ||
1132
1154
  (!deps.subjects.get(candidate.subjectKind)?.actsAs &&
1133
- !fits(runner, agent, candidate)))
1155
+ !fits(runner, agent, candidate, clock.now().getTime())))
1134
1156
  continue;
1135
1157
  // None of its tools has room on the runner's side: the runs behind it may still fit.
1136
- if (!pickOpenEntry(runner, agent, (tool) => reported.has(tool)))
1158
+ if (!pickOpenEntry(runner, agent, (tool) => reported.has(tool), clock.now().getTime()))
1137
1159
  continue;
1138
1160
  try {
1139
1161
  const result = await attempt(runner, agent, candidate, reported);
@@ -1203,13 +1225,13 @@ export function createClaimService(deps) {
1203
1225
  async claim(runner, free, tools) {
1204
1226
  if (runner.status !== 'online' || runnerLowOnDisk(runner))
1205
1227
  return [];
1206
- if ((await deps.slotsUsed(tx.read(), runner.id)) >= runner.slots)
1207
- return [];
1208
1228
  const payloads = [];
1209
1229
  const seen = new Set();
1210
1230
  const limit = Math.min(free, runner.slots);
1211
1231
  const reported = toolRoom(tools);
1212
1232
  while (payloads.length < limit) {
1233
+ if ((await deps.slotsUsed(tx.read(), runner.id)) >= runner.slots)
1234
+ break;
1213
1235
  const payload = await claimOne(runner, seen, reported);
1214
1236
  if (!payload)
1215
1237
  break;