@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.
- package/CHANGELOG.md +74 -0
- package/README.md +22 -2
- package/dist/client/api/client.d.ts +9 -4
- package/dist/client/api/client.d.ts.map +1 -1
- package/dist/client/api/client.js +9 -0
- package/dist/client/api/client.js.map +1 -1
- package/dist/client/api/keys.d.ts +3 -0
- package/dist/client/api/keys.d.ts.map +1 -1
- package/dist/client/api/keys.js +3 -0
- package/dist/client/api/keys.js.map +1 -1
- package/dist/client/api/runners.d.ts +8 -4
- package/dist/client/api/runners.d.ts.map +1 -1
- package/dist/client/api/runners.js +9 -0
- package/dist/client/api/runners.js.map +1 -1
- package/dist/client/chat/keys.d.ts.map +1 -1
- package/dist/client/chat/keys.js +2 -1
- package/dist/client/chat/keys.js.map +1 -1
- package/dist/client/chat/use-chat.d.ts.map +1 -1
- package/dist/client/chat/use-chat.js +8 -1
- package/dist/client/chat/use-chat.js.map +1 -1
- package/dist/client/components/quota-status.d.ts +16 -0
- package/dist/client/components/quota-status.d.ts.map +1 -0
- package/dist/client/components/quota-status.js +39 -0
- package/dist/client/components/quota-status.js.map +1 -0
- package/dist/client/components/runners-refresh.d.ts.map +1 -1
- package/dist/client/components/runners-refresh.js +1 -0
- package/dist/client/components/runners-refresh.js.map +1 -1
- package/dist/client/components/variables/variable-dialogs.d.ts.map +1 -1
- package/dist/client/components/variables/variable-dialogs.js +7 -7
- package/dist/client/components/variables/variable-dialogs.js.map +1 -1
- package/dist/client/config.d.ts +2 -0
- package/dist/client/config.d.ts.map +1 -1
- package/dist/client/config.js +2 -0
- package/dist/client/config.js.map +1 -1
- package/dist/client/hooks/use-quota-expiry.d.ts +7 -0
- package/dist/client/hooks/use-quota-expiry.d.ts.map +1 -0
- package/dist/client/hooks/use-quota-expiry.js +92 -0
- package/dist/client/hooks/use-quota-expiry.js.map +1 -0
- package/dist/client/kit.d.ts +5 -0
- package/dist/client/kit.d.ts.map +1 -1
- package/dist/client/kit.js +25 -0
- package/dist/client/kit.js.map +1 -1
- package/dist/client/lib/agents.d.ts +1 -1
- package/dist/client/lib/agents.d.ts.map +1 -1
- package/dist/client/lib/agents.js +2 -1
- package/dist/client/lib/agents.js.map +1 -1
- package/dist/client/lib/format.d.ts +3 -1
- package/dist/client/lib/format.d.ts.map +1 -1
- package/dist/client/lib/format.js +25 -0
- package/dist/client/lib/format.js.map +1 -1
- package/dist/client/lib/skill-settings-context.d.ts +9 -0
- package/dist/client/lib/skill-settings-context.d.ts.map +1 -0
- package/dist/client/lib/skill-settings-context.js +4 -0
- package/dist/client/lib/skill-settings-context.js.map +1 -0
- package/dist/client/lib/skill-settings.d.ts +12 -0
- package/dist/client/lib/skill-settings.d.ts.map +1 -0
- package/dist/client/lib/skill-settings.js +37 -0
- package/dist/client/lib/skill-settings.js.map +1 -0
- package/dist/client/locales/en-US.d.ts +1 -0
- package/dist/client/locales/en-US.d.ts.map +1 -1
- package/dist/client/locales/en-US.js +1 -0
- package/dist/client/locales/en-US.js.map +1 -1
- package/dist/client/locales/runtimes.en-US.d.ts +72 -0
- package/dist/client/locales/runtimes.en-US.d.ts.map +1 -1
- package/dist/client/locales/runtimes.en-US.js +73 -1
- package/dist/client/locales/runtimes.en-US.js.map +1 -1
- package/dist/client/locales/runtimes.zh-CN.d.ts.map +1 -1
- package/dist/client/locales/runtimes.zh-CN.js +72 -0
- package/dist/client/locales/runtimes.zh-CN.js.map +1 -1
- package/dist/client/locales/skills.en-US.d.ts +6 -0
- package/dist/client/locales/skills.en-US.d.ts.map +1 -1
- package/dist/client/locales/skills.en-US.js +6 -0
- package/dist/client/locales/skills.en-US.js.map +1 -1
- package/dist/client/locales/skills.zh-CN.d.ts.map +1 -1
- package/dist/client/locales/skills.zh-CN.js +6 -0
- package/dist/client/locales/skills.zh-CN.js.map +1 -1
- package/dist/client/locales/zh-CN.d.ts.map +1 -1
- package/dist/client/locales/zh-CN.js +1 -0
- package/dist/client/locales/zh-CN.js.map +1 -1
- package/dist/client/pages/agents/agent-dialog.d.ts.map +1 -1
- package/dist/client/pages/agents/agent-dialog.js +4 -4
- package/dist/client/pages/agents/agent-dialog.js.map +1 -1
- package/dist/client/pages/agents/runner-agents.d.ts.map +1 -1
- package/dist/client/pages/agents/runner-agents.js +23 -10
- package/dist/client/pages/agents/runner-agents.js.map +1 -1
- package/dist/client/pages/runtimes/connect.js.map +1 -1
- package/dist/client/pages/runtimes/index.d.ts.map +1 -1
- package/dist/client/pages/runtimes/index.js +1 -1
- package/dist/client/pages/runtimes/index.js.map +1 -1
- package/dist/client/pages/runtimes/quota-targets.d.ts +4 -0
- package/dist/client/pages/runtimes/quota-targets.d.ts.map +1 -0
- package/dist/client/pages/runtimes/quota-targets.js +18 -0
- package/dist/client/pages/runtimes/quota-targets.js.map +1 -0
- package/dist/client/pages/runtimes/quota.d.ts +17 -0
- package/dist/client/pages/runtimes/quota.d.ts.map +1 -0
- package/dist/client/pages/runtimes/quota.js +48 -0
- package/dist/client/pages/runtimes/quota.js.map +1 -0
- package/dist/client/pages/runtimes/runner-cells.d.ts +11 -4
- package/dist/client/pages/runtimes/runner-cells.d.ts.map +1 -1
- package/dist/client/pages/runtimes/runner-cells.js +2 -2
- package/dist/client/pages/runtimes/runner-cells.js.map +1 -1
- package/dist/client/pages/runtimes/runner-overview.d.ts +9 -0
- package/dist/client/pages/runtimes/runner-overview.d.ts.map +1 -0
- package/dist/client/pages/runtimes/runner-overview.js +109 -0
- package/dist/client/pages/runtimes/runner-overview.js.map +1 -0
- package/dist/client/pages/runtimes/runner-runs.d.ts +5 -0
- package/dist/client/pages/runtimes/runner-runs.d.ts.map +1 -0
- package/dist/client/pages/runtimes/runner-runs.js +35 -0
- package/dist/client/pages/runtimes/runner-runs.js.map +1 -0
- package/dist/client/pages/runtimes/runner-sheet.d.ts +2 -3
- package/dist/client/pages/runtimes/runner-sheet.d.ts.map +1 -1
- package/dist/client/pages/runtimes/runner-sheet.js +43 -171
- package/dist/client/pages/runtimes/runner-sheet.js.map +1 -1
- package/dist/client/pages/runtimes/runner-tools.d.ts +17 -0
- package/dist/client/pages/runtimes/runner-tools.d.ts.map +1 -0
- package/dist/client/pages/runtimes/runner-tools.js +75 -0
- package/dist/client/pages/runtimes/runner-tools.js.map +1 -0
- package/dist/client/pages/runtimes/runner-workspaces.d.ts +6 -0
- package/dist/client/pages/runtimes/runner-workspaces.d.ts.map +1 -0
- package/dist/client/pages/runtimes/runner-workspaces.js +37 -0
- package/dist/client/pages/runtimes/runner-workspaces.js.map +1 -0
- package/dist/client/pages/runtimes/tool-slots-fields.js +1 -1
- package/dist/client/pages/runtimes/tool-slots-fields.js.map +1 -1
- package/dist/client/pages/runtimes/workspace-diagnostics.d.ts +6 -4
- package/dist/client/pages/runtimes/workspace-diagnostics.d.ts.map +1 -1
- package/dist/client/pages/runtimes/workspace-diagnostics.js +61 -37
- package/dist/client/pages/runtimes/workspace-diagnostics.js.map +1 -1
- package/dist/client/pages/skills/detail/index.d.ts.map +1 -1
- package/dist/client/pages/skills/detail/index.js +11 -12
- package/dist/client/pages/skills/detail/index.js.map +1 -1
- package/dist/database/migrations/.manifest.json +4 -0
- package/dist/database/migrations/202610170001_ag_runner_quota.d.ts +4 -0
- package/dist/database/migrations/202610170001_ag_runner_quota.d.ts.map +1 -0
- package/dist/database/migrations/202610170001_ag_runner_quota.js +19 -0
- package/dist/database/migrations/202610170001_ag_runner_quota.js.map +1 -0
- package/dist/package.json +1 -1
- package/dist/server/cli/surface.d.ts.map +1 -1
- package/dist/server/cli/surface.js +4 -1
- package/dist/server/cli/surface.js.map +1 -1
- package/dist/server/composition.d.ts +2 -0
- package/dist/server/composition.d.ts.map +1 -1
- package/dist/server/composition.js +15 -4
- package/dist/server/composition.js.map +1 -1
- package/dist/server/core/agents/agent.service.d.ts.map +1 -1
- package/dist/server/core/agents/agent.service.js +5 -1
- package/dist/server/core/agents/agent.service.js.map +1 -1
- package/dist/server/core/agents/agent.store.d.ts +2 -0
- package/dist/server/core/agents/agent.store.d.ts.map +1 -1
- package/dist/server/core/agents/agent.store.js +10 -0
- package/dist/server/core/agents/agent.store.js.map +1 -1
- package/dist/server/core/agents/agent.views.d.ts.map +1 -1
- package/dist/server/core/agents/agent.views.js +2 -0
- package/dist/server/core/agents/agent.views.js.map +1 -1
- package/dist/server/core/agents/index.d.ts +1 -1
- package/dist/server/core/agents/index.d.ts.map +1 -1
- package/dist/server/core/agents/index.js +1 -1
- package/dist/server/core/agents/index.js.map +1 -1
- package/dist/server/core/brief/brief.js +2 -2
- package/dist/server/core/brief/brief.js.map +1 -1
- package/dist/server/core/callers/index.d.ts +9 -0
- package/dist/server/core/callers/index.d.ts.map +1 -1
- package/dist/server/core/callers/index.js +15 -0
- package/dist/server/core/callers/index.js.map +1 -1
- package/dist/server/core/conversations/chat-settings.d.ts.map +1 -1
- package/dist/server/core/conversations/chat-settings.js +12 -2
- package/dist/server/core/conversations/chat-settings.js.map +1 -1
- package/dist/server/core/conversations/conversation.service.d.ts +1 -1
- package/dist/server/core/conversations/conversation.service.d.ts.map +1 -1
- package/dist/server/core/conversations/conversation.service.js +32 -4
- package/dist/server/core/conversations/conversation.service.js.map +1 -1
- package/dist/server/core/reports/model-usage.d.ts.map +1 -1
- package/dist/server/core/reports/model-usage.js +42 -44
- package/dist/server/core/reports/model-usage.js.map +1 -1
- package/dist/server/core/reports/prices.d.ts.map +1 -1
- package/dist/server/core/reports/prices.js +29 -5
- package/dist/server/core/reports/prices.js.map +1 -1
- package/dist/server/core/reports/report.service.d.ts +4 -2
- package/dist/server/core/reports/report.service.d.ts.map +1 -1
- package/dist/server/core/reports/report.service.js +147 -68
- package/dist/server/core/reports/report.service.js.map +1 -1
- package/dist/server/core/runs/availability.d.ts +5 -1
- package/dist/server/core/runs/availability.d.ts.map +1 -1
- package/dist/server/core/runs/availability.js +8 -2
- package/dist/server/core/runs/availability.js.map +1 -1
- package/dist/server/core/runs/claim.d.ts +7 -48
- package/dist/server/core/runs/claim.d.ts.map +1 -1
- package/dist/server/core/runs/claim.js +93 -71
- package/dist/server/core/runs/claim.js.map +1 -1
- package/dist/server/core/runs/eligibility.d.ts +11 -1
- package/dist/server/core/runs/eligibility.d.ts.map +1 -1
- package/dist/server/core/runs/eligibility.js +38 -7
- package/dist/server/core/runs/eligibility.js.map +1 -1
- package/dist/server/core/runs/execution-view.d.ts +8 -0
- package/dist/server/core/runs/execution-view.d.ts.map +1 -1
- package/dist/server/core/runs/execution-view.js +9 -0
- package/dist/server/core/runs/execution-view.js.map +1 -1
- package/dist/server/core/runs/execution.d.ts +1 -1
- package/dist/server/core/runs/execution.d.ts.map +1 -1
- package/dist/server/core/runs/execution.js +8 -2
- package/dist/server/core/runs/execution.js.map +1 -1
- package/dist/server/core/runs/index.d.ts +3 -3
- package/dist/server/core/runs/index.d.ts.map +1 -1
- package/dist/server/core/runs/index.js +3 -3
- package/dist/server/core/runs/index.js.map +1 -1
- package/dist/server/core/runs/lifecycle.d.ts +9 -0
- package/dist/server/core/runs/lifecycle.d.ts.map +1 -1
- package/dist/server/core/runs/lifecycle.js +102 -18
- package/dist/server/core/runs/lifecycle.js.map +1 -1
- package/dist/server/core/runs/policy.d.ts +9 -2
- package/dist/server/core/runs/policy.d.ts.map +1 -1
- package/dist/server/core/runs/policy.js +17 -8
- package/dist/server/core/runs/policy.js.map +1 -1
- package/dist/server/core/runs/run.service.d.ts +11 -1
- package/dist/server/core/runs/run.service.d.ts.map +1 -1
- package/dist/server/core/runs/run.service.js +32 -2
- package/dist/server/core/runs/run.service.js.map +1 -1
- package/dist/server/core/runs/run.store.d.ts +5 -0
- package/dist/server/core/runs/run.store.d.ts.map +1 -1
- package/dist/server/core/runs/run.store.js +35 -11
- package/dist/server/core/runs/run.store.js.map +1 -1
- package/dist/server/core/runs/runner-view.d.ts +11 -1
- package/dist/server/core/runs/runner-view.d.ts.map +1 -1
- package/dist/server/core/runs/runner-view.js +51 -6
- package/dist/server/core/runs/runner-view.js.map +1 -1
- package/dist/server/core/runs/sweeper.d.ts.map +1 -1
- package/dist/server/core/runs/sweeper.js +12 -8
- package/dist/server/core/runs/sweeper.js.map +1 -1
- package/dist/server/core/runs/transitions.d.ts +5 -1
- package/dist/server/core/runs/transitions.d.ts.map +1 -1
- package/dist/server/core/runs/transitions.js +31 -11
- package/dist/server/core/runs/transitions.js.map +1 -1
- package/dist/server/core/runs/workload.d.ts +17 -6
- package/dist/server/core/runs/workload.d.ts.map +1 -1
- package/dist/server/core/runs/workload.js +186 -129
- package/dist/server/core/runs/workload.js.map +1 -1
- package/dist/server/core/skills/skill.service.d.ts.map +1 -1
- package/dist/server/core/skills/skill.service.js +44 -8
- package/dist/server/core/skills/skill.service.js.map +1 -1
- package/dist/server/core/transaction-read.d.ts +4 -0
- package/dist/server/core/transaction-read.d.ts.map +1 -0
- package/dist/server/core/transaction-read.js +30 -0
- package/dist/server/core/transaction-read.js.map +1 -0
- package/dist/server/core/variables/index.d.ts +1 -1
- package/dist/server/core/variables/index.d.ts.map +1 -1
- package/dist/server/core/variables/index.js.map +1 -1
- package/dist/server/core/variables/variable.service.d.ts +18 -0
- package/dist/server/core/variables/variable.service.d.ts.map +1 -1
- package/dist/server/core/variables/variable.service.js +95 -20
- package/dist/server/core/variables/variable.service.js.map +1 -1
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/kernel/events.d.ts +4 -2
- package/dist/server/kernel/events.d.ts.map +1 -1
- package/dist/server/kernel/events.js.map +1 -1
- package/dist/server/kernel/scopes.d.ts +6 -0
- package/dist/server/kernel/scopes.d.ts.map +1 -1
- package/dist/server/kernel/scopes.js.map +1 -1
- package/dist/server/online/services.d.ts.map +1 -1
- package/dist/server/online/services.js +101 -24
- package/dist/server/online/services.js.map +1 -1
- package/dist/server/providers/agents.d.ts +9 -1
- package/dist/server/providers/agents.d.ts.map +1 -1
- package/dist/server/providers/agents.js +3 -0
- package/dist/server/providers/agents.js.map +1 -1
- package/dist/server/providers/runners.d.ts +3 -1
- package/dist/server/providers/runners.d.ts.map +1 -1
- package/dist/server/providers/runners.js +12 -3
- package/dist/server/providers/runners.js.map +1 -1
- package/dist/server/routes/admin.d.ts +2 -0
- package/dist/server/routes/admin.d.ts.map +1 -1
- package/dist/server/routes/admin.js +18 -5
- package/dist/server/routes/admin.js.map +1 -1
- package/dist/server/routes/chat.d.ts.map +1 -1
- package/dist/server/routes/chat.js +27 -6
- package/dist/server/routes/chat.js.map +1 -1
- package/dist/server/routes/index.d.ts.map +1 -1
- package/dist/server/routes/index.js +3 -0
- package/dist/server/routes/index.js.map +1 -1
- package/dist/server/routes/runners/admin.d.ts.map +1 -1
- package/dist/server/routes/runners/admin.js +219 -25
- package/dist/server/routes/runners/admin.js.map +1 -1
- package/dist/server/routes/runners/install.d.ts.map +1 -1
- package/dist/server/routes/runners/install.js +7 -2
- package/dist/server/routes/runners/install.js.map +1 -1
- package/dist/server/routes/schemas.d.ts +13 -6
- package/dist/server/routes/schemas.d.ts.map +1 -1
- package/dist/server/routes/schemas.js +350 -66
- package/dist/server/routes/schemas.js.map +1 -1
- package/dist/server/runners/runner.service.d.ts +27 -3
- package/dist/server/runners/runner.service.d.ts.map +1 -1
- package/dist/server/runners/runner.service.js +336 -83
- package/dist/server/runners/runner.service.js.map +1 -1
- package/dist/server/runners/runner.store.d.ts +4 -2
- package/dist/server/runners/runner.store.d.ts.map +1 -1
- package/dist/server/runners/runner.store.js +24 -5
- package/dist/server/runners/runner.store.js.map +1 -1
- package/dist/server/runners/slots.d.ts +5 -2
- package/dist/server/runners/slots.d.ts.map +1 -1
- package/dist/server/runners/slots.js +3 -4
- package/dist/server/runners/slots.js.map +1 -1
- package/dist/shared/agents.d.ts +3 -0
- package/dist/shared/agents.d.ts.map +1 -1
- package/dist/shared/agents.js +0 -15
- package/dist/shared/agents.js.map +1 -1
- package/dist/shared/conversations.d.ts +6 -0
- package/dist/shared/conversations.d.ts.map +1 -1
- package/dist/shared/conversations.js.map +1 -1
- package/dist/shared/model-catalog.d.ts +5 -0
- package/dist/shared/model-catalog.d.ts.map +1 -1
- package/dist/shared/model-catalog.js +35 -1
- package/dist/shared/model-catalog.js.map +1 -1
- package/dist/shared/quota.d.ts +15 -0
- package/dist/shared/quota.d.ts.map +1 -0
- package/dist/shared/quota.js +2 -0
- package/dist/shared/quota.js.map +1 -0
- package/dist/shared/runners.d.ts +88 -5
- package/dist/shared/runners.d.ts.map +1 -1
- package/dist/shared/runners.js +126 -8
- package/dist/shared/runners.js.map +1 -1
- package/dist/shared/runs.d.ts +10 -0
- package/dist/shared/runs.d.ts.map +1 -1
- package/dist/shared/runs.js +22 -0
- package/dist/shared/runs.js.map +1 -1
- package/dist/shared/skills.d.ts +3 -1
- package/dist/shared/skills.d.ts.map +1 -1
- package/dist/shared/skills.js.map +1 -1
- package/package.json +14 -14
- 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'
|
|
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'
|
|
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":"
|
|
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
|
|
256
|
-
const
|
|
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
|
|
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
|
|
362
|
-
const
|
|
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
|
|
484
|
-
const
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
914
|
-
|
|
915
|
-
const
|
|
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.
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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;
|