@desplega.ai/agent-swarm 1.131.1 → 1.134.0
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/README.md +3 -3
- package/dist/{actions-jgcy477k.js → actions-7kast243.js} +20 -18
- package/dist/{anthropic-messages-rjmd2e7n.js → anthropic-messages-706yad38.js} +33 -17
- package/dist/app-0g84t8wf.js +28 -0
- package/dist/{artifact-jysj3wrg.js → artifact-dje5ke4h.js} +37 -131
- package/dist/{assistant-f2vkk1hj.js → assistant-ac4htcky.js} +25 -22
- package/dist/{azure-openai-responses-c0yjmbfd.js → azure-openai-responses-be59fbsz.js} +13 -13
- package/dist/{boot-reembed-q7mp8hcr.js → boot-reembed-b1rcqn85.js} +13 -11
- package/dist/{boot-reembed-xmw8wcx6.js → boot-reembed-kw2541c4.js} +14 -12
- package/dist/{boot-scrub-logs-dsqrv79n.js → boot-scrub-logs-ja29t92g.js} +11 -9
- package/dist/{claude-adapter-q6x7yspx.js → claude-adapter-5cg1fv8s.js} +33 -29
- package/dist/{claude-managed-adapter-wsg37bt8.js → claude-managed-adapter-9z9sdytx.js} +9 -9
- package/dist/{claude-managed-setup-52z4mq9w.js → claude-managed-setup-3zqp51cr.js} +5 -5
- package/dist/{claude-1ex232fc.js → claude-wqn3dtca.js} +1 -1
- package/dist/{cli-4wgngmwv.js → cli-00w4hbam.js} +1 -1
- package/dist/{cli-er3a4bb0.js → cli-15429qdw.js} +6 -1
- package/dist/{cli-e5dabkx0.js → cli-1cwhyvta.js} +4 -4
- package/dist/{cli-zsspvvm2.js → cli-1ybr6vw2.js} +237 -237
- package/dist/{cli-xpxde7rm.js → cli-2wv4kj0e.js} +60 -31
- package/dist/cli-34w2584r.js +530 -0
- package/dist/{cli-se2p6rkb.js → cli-38taxznr.js} +6 -6
- package/dist/{cli-9sbhdpvb.js → cli-3cgfyfzm.js} +14 -14
- package/dist/{cli-5n6e5yfn.js → cli-3zmdzfjf.js} +79 -74
- package/dist/{cli-3ty0t082.js → cli-43x36mty.js} +197 -8
- package/dist/{cli-ycrnynpw.js → cli-480nehnh.js} +29 -22
- package/dist/{cli-0258203w.js → cli-492e7ap5.js} +140 -20
- package/dist/{cli-3fj60etf.js → cli-497b685t.js} +3 -3
- package/dist/{cli-pxfxkx5m.js → cli-4bap00k0.js} +1 -1
- package/dist/{cli-w2wxd56v.js → cli-4bc8vmhm.js} +848 -770
- package/dist/{cli-aca5pz9f.js → cli-589599p9.js} +1 -1
- package/dist/{cli-t930g0xh.js → cli-5tnr64pm.js} +1 -1
- package/dist/{cli-jxg3s9ey.js → cli-65d93ves.js} +7 -7
- package/dist/{cli-6dpytdr2.js → cli-6x363v1z.js} +2 -2
- package/dist/{cli-dxak0fqd.js → cli-787ph852.js} +11 -11
- package/dist/{cli-793jvbsh.js → cli-7bv8nckk.js} +16 -11
- package/dist/{cli-zyxs93y9.js → cli-7jcc9y1r.js} +3 -3
- package/dist/{cli-f1am9szv.js → cli-87t2gstf.js} +1 -1
- package/dist/{cli-9aryf9tv.js → cli-95m51ztz.js} +1 -1
- package/dist/{cli-4w4fmq9x.js → cli-9w49enmh.js} +2 -2
- package/dist/{cli-v69vk5h0.js → cli-9y5b02vr.js} +13 -13
- package/dist/{cli-x23me2mg.js → cli-a1rrkrb4.js} +1 -1
- package/dist/{cli-psrqtw2m.js → cli-a3pkfpqs.js} +2 -2
- package/dist/{cli-h0rgxd24.js → cli-a4ajmfvp.js} +6 -6
- package/dist/{cli-ygrbmjja.js → cli-aw8bb6sf.js} +6 -6
- package/dist/{cli-g74vpjp2.js → cli-brm3et47.js} +55 -22
- package/dist/{cli-czkae1fp.js → cli-c5ddbdfj.js} +9 -9
- package/dist/{cli-114fvtmj.js → cli-c79a9zrc.js} +1 -1
- package/dist/{cli-49n9f49x.js → cli-dx3dz0ms.js} +3 -3
- package/dist/{cli-6dp3ydxa.js → cli-e07exmsb.js} +18 -14
- package/dist/cli-et1bbwqf.js +13 -0
- package/dist/{cli-yazx6hap.js → cli-f3s9dry0.js} +14 -14
- package/dist/{cli-t8d349cy.js → cli-f4wj0s3m.js} +3 -3
- package/dist/{cli-d6n0thxw.js → cli-f64gdfxc.js} +1 -1
- package/dist/{cli-pwfsqc2x.js → cli-fyd58xgb.js} +55 -55
- package/dist/{cli-7dm2zqy2.js → cli-g0j14czv.js} +2 -2
- package/dist/{cli-b0p7rfnd.js → cli-g2p9bd1z.js} +14 -14
- package/dist/{cli-z905tvmm.js → cli-g814jbst.js} +2 -2
- package/dist/{cli-5dsbcjjw.js → cli-ghexzd2d.js} +970 -970
- package/dist/{cli-jvv0g8bh.js → cli-gpt9kf01.js} +15 -15
- package/dist/{cli-rgrfzg8z.js → cli-grt6qv91.js} +380 -380
- package/dist/{cli-wz9115x0.js → cli-gtafvdy0.js} +8 -8
- package/dist/{cli-q5dzzak0.js → cli-gy07xk4s.js} +2 -2
- package/dist/{cli-sy7jk3tx.js → cli-h0djenzm.js} +2 -2
- package/dist/{cli-nrkkknat.js → cli-h37gbjbf.js} +2 -281
- package/dist/{cli-jevgrb4w.js → cli-h39xxnq6.js} +1200 -491
- package/dist/{cli-gz9sbyk3.js → cli-jepmgn7r.js} +1 -1
- package/dist/{cli-ccf9vy7q.js → cli-jmvk6et8.js} +7 -7
- package/dist/{cli-2rk0cx7s.js → cli-jxj92gkt.js} +51 -41
- package/dist/{cli-bqw0mt1n.js → cli-k46t4664.js} +18 -3
- package/dist/{cli-50vbt00w.js → cli-m07313tr.js} +1153 -696
- package/dist/{cli-4j2mrzag.js → cli-mkq1rk7b.js} +1 -1
- package/dist/{cli-1z7048dy.js → cli-mnm7w46e.js} +1 -1
- package/dist/{cli-kd1ck4rx.js → cli-mp9sg4cg.js} +14 -8
- package/dist/{cli-jbcva0xj.js → cli-mrammd8c.js} +60 -35
- package/dist/cli-nanaxrz6.js +27 -0
- package/dist/{cli-p9swy5t3.js → cli-pq2ee5ja.js} +8 -6
- package/dist/{cli-2wadx7p2.js → cli-pt43pdp1.js} +2 -2
- package/dist/{cli-7sgrxg9a.js → cli-q6d0vvey.js} +4 -4
- package/dist/{cli-k9qkf1hw.js → cli-qf9kpsve.js} +9 -9
- package/dist/cli-qh4sqfws.js +15 -0
- package/dist/{cli-e15jhafb.js → cli-qntkxysp.js} +14 -14
- package/dist/{cli-sajgpkqg.js → cli-qs9hhsvb.js} +1723 -325
- package/dist/{cli-z2zcxes1.js → cli-qt5bt3vk.js} +1 -1
- package/dist/{cli-wx82tw1k.js → cli-qtekrty1.js} +3 -3
- package/dist/{cli-g1re8r05.js → cli-rh6f3s9n.js} +3 -3
- package/dist/{cli-n0krnc6d.js → cli-rzhcrw2p.js} +2 -2
- package/dist/{cli-gecy3z2s.js → cli-snw62ze5.js} +4 -4
- package/dist/{cli-n6h8qt8n.js → cli-snz3p4yf.js} +15 -10
- package/dist/{cli-r6kqqbj0.js → cli-tkf8n6cw.js} +11 -11
- package/dist/{cli-4rkfg1wx.js → cli-tkrr24mz.js} +14 -9
- package/dist/{cli-9dr5qzc0.js → cli-tv9f1kyb.js} +54 -43
- package/dist/{cli-gm9cbhbq.js → cli-vtz6yj3v.js} +28 -9
- package/dist/{cli-2f07m0xr.js → cli-wf86d5t7.js} +1 -1
- package/dist/{cli-7zd05xb4.js → cli-whrvct19.js} +45 -45
- package/dist/{cli-ap1czx8f.js → cli-wrrea8xm.js} +3 -3
- package/dist/{cli-57khth04.js → cli-xmyqv00z.js} +120 -4
- package/dist/{cli-cwy5hqbq.js → cli-yjmk7tzc.js} +1 -1
- package/dist/{cli-6pcz9h15.js → cli-zykjrwcx.js} +180 -394
- package/dist/cli.js +45 -45
- package/dist/{codex-adapter-htjkn22b.js → codex-adapter-hsq6mz3m.js} +21 -19
- package/dist/{codex-hook-hq54t9ft.js → codex-hook-8c500gq8.js} +8 -7
- package/dist/{codex-login-z6yhbkmk.js → codex-login-x7603481.js} +3 -3
- package/dist/{codex-session-runner-wjfc7smz.js → codex-session-runner-c1x3x143.js} +15 -13
- package/dist/{commands-xhrfwqsk.js → commands-rwtddtst.js} +11 -9
- package/dist/{db-anvwb22f.js → db-j2b355vz.js} +458 -444
- package/dist/{devin-adapter-v1sarqtw.js → devin-adapter-8qmhqpy3.js} +3 -3
- package/dist/{devtools-2y1r7yqk.js → devtools-j2rnj8w7.js} +4 -4
- package/dist/{e2b-jdkwemv2.js → e2b-znpx78eg.js} +16 -16
- package/dist/{es5-vjgtkgp6.js → es5-fmqrjzy3.js} +2 -2
- package/dist/{event-bus-axn823e9.js → event-bus-n8sb35pw.js} +4 -4
- package/dist/{getMachineId-bsd-6tc9wxdj.js → getMachineId-bsd-wpzbhkm6.js} +4 -4
- package/dist/{getMachineId-darwin-sjt9sgnc.js → getMachineId-darwin-45zabjy0.js} +4 -4
- package/dist/{getMachineId-linux-v5n18y9p.js → getMachineId-linux-warnp5pd.js} +3 -3
- package/dist/{getMachineId-unsupported-yrjyqw3d.js → getMachineId-unsupported-5spent2a.js} +3 -3
- package/dist/{getMachineId-win-w3r8063c.js → getMachineId-win-v4bvcw7a.js} +4 -4
- package/dist/{google-generative-ai-hysrd8qx.js → google-generative-ai-b0wzss55.js} +17 -14
- package/dist/{google-vertex-p5arrga0.js → google-vertex-e8q4dpya.js} +18 -15
- package/dist/{handlers-b9kbc621.js → handlers-hchgrxkh.js} +32 -29
- package/dist/{hook-xkvn6c5h.js → hook-p49egqc0.js} +66 -52
- package/dist/hook-spb00w76.js +34 -0
- package/dist/{http-9xh6ta4r.js → http-nh14kkms.js} +663 -181
- package/dist/index-1qthq7vc.js +6 -0
- package/dist/{index-0g68f0p6.js → index-20xqmn3v.js} +3 -3
- package/dist/{index-vdkr5z2w.js → index-3e03k6e4.js} +114 -114
- package/dist/{index-ywds4812.js → index-4cbyhq2g.js} +43 -41
- package/dist/index-67pzqfrb.js +36 -0
- package/dist/{index-bccrkdkn.js → index-7m8yxkw5.js} +16 -16
- package/dist/{index-eaxyqcmj.js → index-dvsk64sm.js} +163 -83
- package/dist/{index-dqkpnmqm.js → index-e19s2m8k.js} +18 -18
- package/dist/{index-j30k5zxn.js → index-emvxcy98.js} +16 -16
- package/dist/{index-7ndw6ecy.js → index-gqnmr60d.js} +9 -9
- package/dist/{index-9znhar3x.js → index-j02xvjtd.js} +184 -185
- package/dist/{index-1s2442yw.js → index-ns5kksc1.js} +7 -7
- package/dist/{index-dpy2hth8.js → index-pdxc8kfh.js} +71 -71
- package/dist/{index-z1m7pw0v.js → index-ptcqm8bc.js} +107 -107
- package/dist/{index-070v4eyb.js → index-pyp7rexm.js} +5 -6
- package/dist/{index-86znjz1p.js → index-shne41sd.js} +13 -13
- package/dist/{index-2qn2qndv.js → index-t36q2v4t.js} +183 -183
- package/dist/index-tcnvv8w6.js +7 -0
- package/dist/index-w91qbfv1.js +7 -0
- package/dist/{index-fzc0mwvj.js → index-yqweff5n.js} +32 -32
- package/dist/index-yrfphye1.js +39 -0
- package/dist/{keepalive-vc7s2aa6.js → keepalive-9k51nqhc.js} +21 -15
- package/dist/lead-2xq3dxbz.js +88 -0
- package/dist/maintenance-0c0g6nym.js +28 -0
- package/dist/mistral-conversations-2njwdwhj.js +717 -0
- package/dist/{multipart-parser-qaktc7p8.js → multipart-parser-6gftesw0.js} +2 -2
- package/dist/{oauth-refresh-sweep-yecgjpk4.js → oauth-refresh-sweep-273a64r2.js} +14 -12
- package/dist/{onboard-xj0f73f9.js → onboard-tsv9wwhz.js} +12 -12
- package/dist/{openai-codex-responses-5g27pd6f.js → openai-codex-responses-kt84eq86.js} +26 -26
- package/dist/{openai-completions-3vkmfz2a.js → openai-completions-mrypq7qp.js} +17 -16
- package/dist/{openai-responses-dg4t7j7a.js → openai-responses-qhrk21ez.js} +20 -17
- package/dist/{opencode-adapter-1gm38aba.js → opencode-adapter-rar9676j.js} +13 -11
- package/dist/{openrouter-images-g3gm8931.js → openrouter-images-684fysx9.js} +5 -5
- package/dist/{otel-impl-nxg0n0b3.js → otel-impl-wp1mfzd2.js} +752 -537
- package/dist/{photon_rs-ky7dj5qw.js → photon_rs-8dwt2pzy.js} +581 -581
- package/dist/{pi-messages-tqj8q6b9.js → pi-messages-txp9f97r.js} +7 -7
- package/dist/{pi-mono-adapter-4g5kby31.js → pi-mono-adapter-yz47kk8e.js} +1910 -1180
- package/dist/pricing-refresh-jw1yw2fn.js +22 -0
- package/dist/rbac-roles-dg964c8p.js +32 -0
- package/dist/{rbac-roles-1hcxdtg7.js → rbac-roles-p53cg5cv.js} +19 -17
- package/dist/{registry-02cy9z5z.js → registry-mh12y17v.js} +4 -4
- package/dist/render-v2-56vn2rk9.js +36 -0
- package/dist/seed-pricing-52xx6z63.js +19 -0
- package/dist/{setup-46xtgq3c.js → setup-e8gp79sy.js} +7 -7
- package/dist/token-util-zy908s1a.js +6 -0
- package/dist/{token-fxkn2zf2.js → token-xg5711x5.js} +4 -4
- package/dist/worker-s17f1g46.js +88 -0
- package/dist/{x-6mg4kfpe.js → x-xkfh0w0v.js} +5 -5
- package/openapi.json +566 -22
- package/package.json +6 -6
- package/src/be/budget-refusal-notify.ts +14 -7
- package/src/be/db-queries/task-artifacts.ts +182 -0
- package/src/be/db.ts +834 -171
- package/src/be/events.ts +5 -0
- package/src/be/migrations/131_session_logs_created_at_index.sql +2 -0
- package/src/be/migrations/132_multi_runtime_instances.sql +44 -0
- package/src/be/migrations/133_workflow_run_trigger_type.sql +12 -0
- package/src/be/migrations/135_backfill_task_pull_request_attachments.sql +228 -0
- package/src/be/migrations/136_task_requester_provenance.sql +37 -0
- package/src/be/migrations/137_memory_retrieval_composite_index.sql +1 -0
- package/src/be/migrations/runner.ts +17 -11
- package/src/be/multi-runtime.ts +430 -0
- package/src/be/scripts/extract-schema.ts +3 -1
- package/src/be/scripts/typecheck.ts +6 -2
- package/src/be/seed-prompt-templates.ts +25 -2
- package/src/be/seed-skills/index.ts +7 -0
- package/src/be/steering.ts +1 -1
- package/src/be/swarm-config-guard.ts +18 -0
- package/src/commands/credential-wait.ts +54 -0
- package/src/commands/onboard/steps/core-credentials.tsx +1 -1
- package/src/commands/onboard/steps/custom-templates.tsx +1 -1
- package/src/commands/onboard/steps/harness-credentials.tsx +1 -1
- package/src/commands/onboard/steps/health-check.tsx +1 -1
- package/src/commands/onboard/steps/start.tsx +1 -1
- package/src/commands/profile-sync-audit.ts +56 -0
- package/src/commands/profile-sync.ts +287 -15
- package/src/commands/provider-credentials.ts +46 -19
- package/src/commands/runner.ts +199 -33
- package/src/commands/templates.ts +22 -0
- package/src/github/handlers.ts +55 -9
- package/src/heartbeat/heartbeat.ts +109 -17
- package/src/hooks/hook.ts +49 -33
- package/src/http/active-sessions.ts +11 -1
- package/src/http/agents.ts +261 -30
- package/src/http/all-routes.ts +1 -0
- package/src/http/config.ts +13 -2
- package/src/http/core.ts +102 -4
- package/src/http/db-query-bounded.ts +313 -0
- package/src/http/db-query-shared.ts +249 -0
- package/src/http/db-query.ts +54 -42
- package/src/http/events.ts +2 -0
- package/src/http/index.ts +23 -2
- package/src/http/mcp-bridge.ts +37 -3
- package/src/http/mcp.ts +12 -0
- package/src/http/memory.ts +13 -2
- package/src/http/openapi.ts +1 -0
- package/src/http/poll.ts +70 -27
- package/src/http/prompt-templates.ts +36 -13
- package/src/http/route-def.ts +43 -9
- package/src/http/schedules.ts +2 -2
- package/src/http/scripts.ts +10 -1
- package/src/http/session-data.ts +44 -0
- package/src/http/tasks.ts +2 -2
- package/src/http/users.ts +74 -52
- package/src/http/webhooks.ts +5 -2
- package/src/http/workflows.ts +1 -4
- package/src/integrations/kapso/inbound.ts +1 -1
- package/src/jira/outbound.ts +39 -8
- package/src/jira/webhook-lifecycle.ts +13 -2
- package/src/linear/outbound.ts +43 -10
- package/src/oauth/keepalive.ts +13 -2
- package/src/prompts/base-prompt.ts +1 -1
- package/src/prompts/default-drift.ts +21 -0
- package/src/prompts/session-templates.ts +56 -7
- package/src/providers/claude-adapter.ts +6 -0
- package/src/providers/codex-adapter.ts +6 -0
- package/src/providers/opencode-adapter.ts +6 -0
- package/src/providers/pi-mono-adapter.ts +8 -0
- package/src/providers/pricing-sources.md +24 -0
- package/src/queue-stall-alarm.ts +216 -0
- package/src/rbac/legacy-policy.ts +3 -0
- package/src/rbac/permissions.ts +12 -0
- package/src/scheduler/scheduler.ts +7 -0
- package/src/script-workflows/executor.ts +2 -1
- package/src/scripts-runtime/executors/native.ts +2 -1
- package/src/scripts-runtime/executors/types.ts +5 -0
- package/src/scripts-runtime/loader.ts +5 -0
- package/src/scripts-runtime/sdk-allowlist.ts +3 -0
- package/src/scripts-runtime/swarm-config.ts +8 -0
- package/src/scripts-runtime/swarm-sdk.ts +7 -0
- package/src/scripts-runtime/types/stdlib.d.ts +4 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +4 -0
- package/src/server.ts +6 -0
- package/src/slack/channel-join.ts +22 -3
- package/src/slack/channel-lifecycle.ts +114 -0
- package/src/tests/budget-claim-gate.test.ts +20 -0
- package/src/tests/claude-adapter.test.ts +32 -0
- package/src/tests/codex-adapter.test.ts +30 -0
- package/src/tests/create-task-validation.test.ts +128 -0
- package/src/tests/credential-wait.test.ts +67 -1
- package/src/tests/db-query.test.ts +711 -2
- package/src/tests/heartbeat-checklist.test.ts +28 -0
- package/src/tests/http-api-integration.test.ts +81 -0
- package/src/tests/http-users.test.ts +166 -1
- package/src/tests/identity-field-budget.test.ts +176 -0
- package/src/tests/mcp-tools-user.test.ts +34 -0
- package/src/tests/mcp-user-route.test.ts +17 -0
- package/src/tests/metrics-http.test.ts +44 -0
- package/src/tests/migration-failure.test.ts +86 -0
- package/src/tests/multi-runtime-registration.test.ts +2810 -0
- package/src/tests/openapi-response-contract.test.ts +24 -0
- package/src/tests/openapi-route-headers.test.ts +83 -0
- package/src/tests/opencode-adapter.test.ts +40 -0
- package/src/tests/outbound-listener-rejection.test.ts +138 -0
- package/src/tests/pi-mono-adapter.test.ts +98 -0
- package/src/tests/preload.ts +2 -0
- package/src/tests/profile-sync-warning.test.ts +277 -0
- package/src/tests/profile-sync.test.ts +232 -6
- package/src/tests/prompt-template-resolver.test.ts +177 -6
- package/src/tests/prompt-template-session.test.ts +39 -3
- package/src/tests/queue-stall-alarm.test.ts +226 -0
- package/src/tests/rbac-charact-slack.test.ts +29 -0
- package/src/tests/rbac-engine.test.ts +3 -0
- package/src/tests/requester-comms.test.ts +32 -0
- package/src/tests/runner-requester-profile.test.ts +38 -0
- package/src/tests/schedule-target-type.test.ts +38 -0
- package/src/tests/script-connections.test.ts +13 -1
- package/src/tests/scripts-runtime-identity.test.ts +375 -0
- package/src/tests/scripts-runtime.test.ts +4 -3
- package/src/tests/sdk-allowlist.test.ts +47 -0
- package/src/tests/send-task-requested-by.test.ts +9 -0
- package/src/tests/session-costs.test.ts +506 -1
- package/src/tests/shutdown-error-scrubbing.test.ts +92 -0
- package/src/tests/slack-channel-lifecycle.test.ts +241 -0
- package/src/tests/slack-render-v2.test.ts +43 -0
- package/src/tests/steering-core.test.ts +28 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +22 -0
- package/src/tests/task-artifacts.test.ts +386 -0
- package/src/tests/task-attachments-schema.test.ts +17 -1
- package/src/tests/task-completion-idempotency.test.ts +57 -0
- package/src/tests/task-pull-request-backfill-migration.test.ts +321 -0
- package/src/tests/tool-annotations.test.ts +4 -0
- package/src/tests/update-profile-api.test.ts +67 -39
- package/src/tests/update-profile-auth.test.ts +48 -4
- package/src/tests/user-attribution-migration.test.ts +54 -0
- package/src/tests/user-identity.test.ts +72 -0
- package/src/tests/workflow-async-v2.test.ts +39 -1
- package/src/tests/workflow-http-v2.test.ts +3 -2
- package/src/tests/workflow-mcp-trigger-schema.test.ts +52 -3
- package/src/tests/workflow-retry-v2.test.ts +45 -1
- package/src/tools/db-query.ts +18 -8
- package/src/tools/get-task-details.ts +24 -3
- package/src/tools/manage-user.ts +36 -3
- package/src/tools/poll-task.ts +93 -14
- package/src/tools/script-common.ts +5 -0
- package/src/tools/send-task.ts +1 -4
- package/src/tools/slack-archive-channel.ts +70 -0
- package/src/tools/slack-create-channel.ts +74 -0
- package/src/tools/slack-invite-to-channel.ts +78 -0
- package/src/tools/store-progress.ts +13 -2
- package/src/tools/swarm-config/delete-config.ts +9 -0
- package/src/tools/swarm-config/set-config.ts +3 -2
- package/src/tools/task-action.ts +30 -0
- package/src/tools/task-tool-ctx.ts +8 -1
- package/src/tools/tool-config.ts +4 -1
- package/src/tools/update-profile.ts +16 -21
- package/src/tools/utils.ts +5 -0
- package/src/tools/workflows/trigger-workflow.ts +7 -1
- package/src/types.ts +165 -1
- package/src/utils/github-pull-request.ts +76 -0
- package/src/utils/identity-field-budget.ts +73 -0
- package/src/utils/multi-runtime.ts +20 -0
- package/src/utils/requester-comms.ts +24 -0
- package/src/workflows/engine.ts +22 -2
- package/src/workflows/resume.ts +19 -11
- package/src/workflows/retry-poller.ts +1 -0
- package/src/workflows/triggers.ts +4 -0
- package/templates/skills/db-query-guidance/config.json +14 -0
- package/templates/skills/db-query-guidance/content.md +57 -0
- package/dist/app-5da78bd4.js +0 -26
- package/dist/cli-3te4jdkm.js +0 -225
- package/dist/cli-bmze986d.js +0 -7
- package/dist/cli-kh3ba2zf.js +0 -607
- package/dist/hook-cgk4wxmx.js +0 -31
- package/dist/index-25wjsdv2.js +0 -34
- package/dist/index-76at2ymp.js +0 -7
- package/dist/index-hase6zbe.js +0 -6
- package/dist/index-vg4snay4.js +0 -36
- package/dist/index-vy8edt27.js +0 -7
- package/dist/lead-r2yqfmx7.js +0 -85
- package/dist/maintenance-mw70k468.js +0 -26
- package/dist/mistral-conversations-81fwav0j.js +0 -30578
- package/dist/otel-nqa12wf3.js +0 -3149
- package/dist/pricing-refresh-2cn6effr.js +0 -20
- package/dist/rbac-roles-vynday5g.js +0 -30
- package/dist/render-v2-tc0bh8kk.js +0 -34
- package/dist/seed-pricing-8kceb43f.js +0 -17
- package/dist/token-util-pqyc8kng.js +0 -6
- package/dist/worker-qrbz6hmv.js +0 -85
package/src/tools/poll-task.ts
CHANGED
|
@@ -2,18 +2,23 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { addMinutes } from "date-fns";
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
import {
|
|
5
|
+
getActiveTaskCount,
|
|
5
6
|
getAgentById,
|
|
6
7
|
getDb,
|
|
7
8
|
getOfferedTasksForAgent,
|
|
8
9
|
getPendingTaskForAgent,
|
|
9
10
|
getUnassignedTasksCount,
|
|
11
|
+
hasCapacity,
|
|
10
12
|
incrementEmptyPollCount,
|
|
11
13
|
MAX_EMPTY_POLLS,
|
|
12
14
|
resetEmptyPollCount,
|
|
13
15
|
startTask,
|
|
14
16
|
updateAgentStatus,
|
|
15
17
|
} from "@/be/db";
|
|
18
|
+
import { touchRuntimeInstance } from "@/be/multi-runtime";
|
|
16
19
|
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
20
|
+
import type { AgentTask } from "@/types";
|
|
21
|
+
import { isMultiRuntimeEnabled } from "@/utils/multi-runtime";
|
|
17
22
|
import { looseAgentTaskOutputSchema } from "./get-task-details";
|
|
18
23
|
|
|
19
24
|
const DEFAULT_POLL_INTERVAL_MS = 2000;
|
|
@@ -70,6 +75,28 @@ export const registerPollTaskTool = (server: McpServer) => {
|
|
|
70
75
|
// touching the bookkeeping path below.
|
|
71
76
|
const wasBudgetRefused: boolean = false;
|
|
72
77
|
|
|
78
|
+
// Second dispatch entrypoint alongside HTTP /api/poll, so it needs the
|
|
79
|
+
// same gate: a process whose runtime is gone must not pick up work
|
|
80
|
+
// beside its replacement. Touch validates ownership+liveness and
|
|
81
|
+
// refreshes it; it cannot revive a retired runtime.
|
|
82
|
+
if (
|
|
83
|
+
isMultiRuntimeEnabled() &&
|
|
84
|
+
!(
|
|
85
|
+
requestInfo.runtimeInstanceId &&
|
|
86
|
+
touchRuntimeInstance(requestInfo.runtimeInstanceId, agentId)
|
|
87
|
+
)
|
|
88
|
+
) {
|
|
89
|
+
return toolOk("No task available.", {
|
|
90
|
+
details: "No task available for this runtime.",
|
|
91
|
+
data: {
|
|
92
|
+
yourAgentId: requestInfo.agentId,
|
|
93
|
+
offeredTasks: [],
|
|
94
|
+
availableCount: 0,
|
|
95
|
+
waitedForSeconds: 0,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
73
100
|
const agent = getAgentById(agentId);
|
|
74
101
|
if (!agent) {
|
|
75
102
|
return toolErr(`Agent with ID "${agentId}" not found in the swarm.`, {
|
|
@@ -104,26 +131,78 @@ export const registerPollTaskTool = (server: McpServer) => {
|
|
|
104
131
|
// Poll for pending tasks
|
|
105
132
|
while (new Date() < maxTime) {
|
|
106
133
|
// Fetch and update in a single transaction to avoid race conditions
|
|
107
|
-
const
|
|
108
|
-
|
|
134
|
+
const outcome = getDb().transaction(
|
|
135
|
+
(): AgentTask | "at-capacity" | "runtime-unavailable" | null => {
|
|
136
|
+
// The entry gate only proves liveness when the long poll began;
|
|
137
|
+
// the runtime must be live at the exact moment work is acquired,
|
|
138
|
+
// so revalidate in the same transaction that can start the task.
|
|
139
|
+
// Touch refreshes an already-live row and cannot revive one.
|
|
140
|
+
if (
|
|
141
|
+
isMultiRuntimeEnabled() &&
|
|
142
|
+
!(
|
|
143
|
+
requestInfo.runtimeInstanceId &&
|
|
144
|
+
touchRuntimeInstance(requestInfo.runtimeInstanceId, agentId)
|
|
145
|
+
)
|
|
146
|
+
) {
|
|
147
|
+
return "runtime-unavailable";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const agentNow = getAgentById(agentId)!;
|
|
151
|
+
|
|
152
|
+
if (agentNow.status !== "busy") {
|
|
153
|
+
updateAgentStatus(agentId, "idle");
|
|
154
|
+
}
|
|
109
155
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
156
|
+
const pendingTask = getPendingTaskForAgent(agentId);
|
|
157
|
+
if (!pendingTask) return null;
|
|
113
158
|
|
|
114
|
-
|
|
115
|
-
|
|
159
|
+
// Logical capacity is decided inside the same transaction as the
|
|
160
|
+
// start transition: several runtimes of one agent race this
|
|
161
|
+
// dispatch, and a check outside it would let each of them start a
|
|
162
|
+
// task past the agent's limit. Same gate as HTTP /api/poll.
|
|
163
|
+
if (!hasCapacity(agentId)) return "at-capacity";
|
|
116
164
|
|
|
117
|
-
|
|
165
|
+
const maybeTask = startTask(pendingTask.id);
|
|
118
166
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
167
|
+
if (maybeTask) {
|
|
168
|
+
// Update automatically in case the agent forgets xd
|
|
169
|
+
updateAgentStatus(agentId, "busy");
|
|
170
|
+
}
|
|
123
171
|
|
|
124
|
-
|
|
125
|
-
|
|
172
|
+
return maybeTask;
|
|
173
|
+
},
|
|
174
|
+
)();
|
|
175
|
+
|
|
176
|
+
if (outcome === "runtime-unavailable") {
|
|
177
|
+
// The runtime was retired while this call waited: stop immediately
|
|
178
|
+
// rather than keep polling as it, and skip the exit counter — this
|
|
179
|
+
// is a refusal, not an empty poll.
|
|
180
|
+
return toolOk("No task available.", {
|
|
181
|
+
details: "No task available for this runtime.",
|
|
182
|
+
data: {
|
|
183
|
+
yourAgentId: requestInfo.agentId,
|
|
184
|
+
offeredTasks: [],
|
|
185
|
+
availableCount: 0,
|
|
186
|
+
waitedForSeconds: Math.round((Date.now() - now.getTime()) / 1000),
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (outcome === "at-capacity") {
|
|
192
|
+
// A capacity refusal is not an empty poll (refused ≠ empty, D-R3):
|
|
193
|
+
// return without advancing the exit counter.
|
|
194
|
+
return toolOk("No task available.", {
|
|
195
|
+
details: `You are at capacity (${getActiveTaskCount(agentId)} active task(s)). Complete a task before polling for more.`,
|
|
196
|
+
data: {
|
|
197
|
+
yourAgentId: requestInfo.agentId,
|
|
198
|
+
offeredTasks: [],
|
|
199
|
+
availableCount: getUnassignedTasksCount(),
|
|
200
|
+
waitedForSeconds: Math.round((Date.now() - now.getTime()) / 1000),
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
}
|
|
126
204
|
|
|
205
|
+
const startedTask = outcome;
|
|
127
206
|
if (startedTask) {
|
|
128
207
|
// Reset empty poll count when task is assigned
|
|
129
208
|
resetEmptyPollCount(agentId);
|
|
@@ -172,6 +172,11 @@ export async function proxyScriptsApi(args: {
|
|
|
172
172
|
if (args.requestInfo.sourceTaskId) {
|
|
173
173
|
headers["X-Source-Task-Id"] = args.requestInfo.sourceTaskId;
|
|
174
174
|
}
|
|
175
|
+
// Runtime identity is process context from the worker's MCP session — it
|
|
176
|
+
// rides the proxy like the agent identity, never as tool or script input.
|
|
177
|
+
if (args.requestInfo.runtimeInstanceId) {
|
|
178
|
+
headers["X-Runtime-Instance-ID"] = args.requestInfo.runtimeInstanceId;
|
|
179
|
+
}
|
|
175
180
|
const res = await fetch(`${apiBaseUrl()}${args.path}`, {
|
|
176
181
|
method: args.method,
|
|
177
182
|
headers,
|
package/src/tools/send-task.ts
CHANGED
|
@@ -223,11 +223,8 @@ export async function sendTaskHandler(
|
|
|
223
223
|
|
|
224
224
|
const creatorAgentId = ctx.kind === "owner" ? ctx.agentId : undefined;
|
|
225
225
|
const sourceTaskId = ctx.kind === "owner" ? ctx.sourceTaskId : undefined;
|
|
226
|
-
const callerTask = sourceTaskId ? getTaskById(sourceTaskId) : null;
|
|
227
226
|
const requestedByUserId =
|
|
228
|
-
ctx.kind === "user"
|
|
229
|
-
? ctx.userId
|
|
230
|
-
: (inputRequestedByUserId ?? callerTask?.requestedByUserId ?? undefined);
|
|
227
|
+
ctx.kind === "user" ? ctx.userId : (inputRequestedByUserId ?? undefined);
|
|
231
228
|
|
|
232
229
|
if (ctx.kind === "owner" && agentId === ctx.agentId) {
|
|
233
230
|
return toolErr("Cannot send a task to yourself, are you drunk?", {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { getAgentById } from "@/be/db";
|
|
4
|
+
import { can } from "@/rbac";
|
|
5
|
+
import { getSlackApp } from "@/slack/app";
|
|
6
|
+
import { slackMissingScopeMessage } from "@/slack/channel-join";
|
|
7
|
+
import { archiveChannel } from "@/slack/channel-lifecycle";
|
|
8
|
+
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
9
|
+
|
|
10
|
+
export const registerSlackArchiveChannelTool = (server: McpServer) => {
|
|
11
|
+
createToolRegistrar(server)(
|
|
12
|
+
"slack-archive-channel",
|
|
13
|
+
{
|
|
14
|
+
title: "Archive a Slack channel",
|
|
15
|
+
description:
|
|
16
|
+
"Archives a Slack channel. Channels that are already archived are treated as a successful no-op, while Slack's general channel cannot be archived. Requires lead privileges.",
|
|
17
|
+
annotations: { openWorldHint: true, destructiveHint: true },
|
|
18
|
+
|
|
19
|
+
inputSchema: z.object({
|
|
20
|
+
channelId: z.string().min(1).describe("The Slack channel ID to archive."),
|
|
21
|
+
}),
|
|
22
|
+
outputSchema: swarmToolOutputSchema({
|
|
23
|
+
channelId: z.string().optional(),
|
|
24
|
+
alreadyArchived: z.boolean().optional(),
|
|
25
|
+
}),
|
|
26
|
+
},
|
|
27
|
+
async ({ channelId }, requestInfo, _meta) => {
|
|
28
|
+
if (!requestInfo.agentId) {
|
|
29
|
+
return toolErr("Agent ID not found.");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const agent = getAgentById(requestInfo.agentId);
|
|
33
|
+
if (!agent) {
|
|
34
|
+
return toolErr("Agent not found.");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const decision = can({
|
|
38
|
+
principal: { kind: "agent", agentId: agent.id, isLead: agent.isLead },
|
|
39
|
+
verb: "integration.slack.channel.archive",
|
|
40
|
+
resource: { kind: "none" },
|
|
41
|
+
source: "mcp",
|
|
42
|
+
});
|
|
43
|
+
if (!decision.allow) {
|
|
44
|
+
return toolErr("Managing Slack channels requires lead privileges.");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const app = getSlackApp();
|
|
48
|
+
if (!app) {
|
|
49
|
+
return toolErr("Slack not configured.");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const result = await archiveChannel(app.client, channelId);
|
|
54
|
+
return toolOk(
|
|
55
|
+
result.alreadyArchived
|
|
56
|
+
? "Slack channel is already archived."
|
|
57
|
+
: "Slack channel archived successfully.",
|
|
58
|
+
{ data: { channelId, ...result } },
|
|
59
|
+
);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const missingScopeMessage = slackMissingScopeMessage(error);
|
|
62
|
+
if (missingScopeMessage) {
|
|
63
|
+
return toolErr(`Failed to archive Slack channel: ${missingScopeMessage}`);
|
|
64
|
+
}
|
|
65
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
66
|
+
return toolErr(`Failed to archive Slack channel: ${errorMsg}`);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { getAgentById } from "@/be/db";
|
|
4
|
+
import { can } from "@/rbac";
|
|
5
|
+
import { getSlackApp } from "@/slack/app";
|
|
6
|
+
import { slackMissingScopeMessage } from "@/slack/channel-join";
|
|
7
|
+
import { createChannel } from "@/slack/channel-lifecycle";
|
|
8
|
+
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
9
|
+
|
|
10
|
+
export const registerSlackCreateChannelTool = (server: McpServer) => {
|
|
11
|
+
createToolRegistrar(server)(
|
|
12
|
+
"slack-create-channel",
|
|
13
|
+
{
|
|
14
|
+
title: "Create a Slack channel",
|
|
15
|
+
description:
|
|
16
|
+
"Creates a public or private Slack channel. The supplied name is normalized to Slack's channel-name rules, and the normalized name is returned. Requires lead privileges.",
|
|
17
|
+
annotations: { openWorldHint: true },
|
|
18
|
+
|
|
19
|
+
inputSchema: z.object({
|
|
20
|
+
name: z.string().min(1).describe("The desired Slack channel name."),
|
|
21
|
+
isPrivate: z
|
|
22
|
+
.boolean()
|
|
23
|
+
.optional()
|
|
24
|
+
.default(false)
|
|
25
|
+
.describe("Whether to create a private channel. Defaults to false."),
|
|
26
|
+
}),
|
|
27
|
+
outputSchema: swarmToolOutputSchema({
|
|
28
|
+
channelId: z.string().optional(),
|
|
29
|
+
name: z.string().optional(),
|
|
30
|
+
isPrivate: z.boolean().optional(),
|
|
31
|
+
}),
|
|
32
|
+
},
|
|
33
|
+
async ({ name, isPrivate }, requestInfo, _meta) => {
|
|
34
|
+
if (!requestInfo.agentId) {
|
|
35
|
+
return toolErr("Agent ID not found.");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const agent = getAgentById(requestInfo.agentId);
|
|
39
|
+
if (!agent) {
|
|
40
|
+
return toolErr("Agent not found.");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const decision = can({
|
|
44
|
+
principal: { kind: "agent", agentId: agent.id, isLead: agent.isLead },
|
|
45
|
+
verb: "integration.slack.channel.create",
|
|
46
|
+
resource: { kind: "none" },
|
|
47
|
+
source: "mcp",
|
|
48
|
+
});
|
|
49
|
+
if (!decision.allow) {
|
|
50
|
+
return toolErr("Managing Slack channels requires lead privileges.");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const app = getSlackApp();
|
|
54
|
+
if (!app) {
|
|
55
|
+
return toolErr("Slack not configured.");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const result = await createChannel(app.client, { name, isPrivate });
|
|
60
|
+
return toolOk("Slack channel created successfully.", {
|
|
61
|
+
details: `Created Slack channel ${result.name} (${result.channelId}).`,
|
|
62
|
+
data: { ...result, isPrivate },
|
|
63
|
+
});
|
|
64
|
+
} catch (error) {
|
|
65
|
+
const missingScopeMessage = slackMissingScopeMessage(error);
|
|
66
|
+
if (missingScopeMessage) {
|
|
67
|
+
return toolErr(`Failed to create Slack channel: ${missingScopeMessage}`);
|
|
68
|
+
}
|
|
69
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
70
|
+
return toolErr(`Failed to create Slack channel: ${errorMsg}`);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
);
|
|
74
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { getAgentById } from "@/be/db";
|
|
4
|
+
import { can } from "@/rbac";
|
|
5
|
+
import { getSlackApp } from "@/slack/app";
|
|
6
|
+
import { slackMissingScopeMessage } from "@/slack/channel-join";
|
|
7
|
+
import { inviteToChannel } from "@/slack/channel-lifecycle";
|
|
8
|
+
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
9
|
+
|
|
10
|
+
export const registerSlackInviteToChannelTool = (server: McpServer) => {
|
|
11
|
+
createToolRegistrar(server)(
|
|
12
|
+
"slack-invite-to-channel",
|
|
13
|
+
{
|
|
14
|
+
title: "Invite users to a Slack channel",
|
|
15
|
+
description:
|
|
16
|
+
"Invites one or more workspace users to a Slack channel. Users who are already in the channel are treated as a successful no-op. Requires lead privileges.",
|
|
17
|
+
annotations: { openWorldHint: true },
|
|
18
|
+
|
|
19
|
+
inputSchema: z.object({
|
|
20
|
+
channelId: z.string().min(1).describe("The Slack channel ID."),
|
|
21
|
+
userIds: z
|
|
22
|
+
.array(z.string().min(1))
|
|
23
|
+
.min(1)
|
|
24
|
+
.max(100)
|
|
25
|
+
.describe("Slack user IDs to invite (up to 100)."),
|
|
26
|
+
}),
|
|
27
|
+
outputSchema: swarmToolOutputSchema({
|
|
28
|
+
channelId: z.string().optional(),
|
|
29
|
+
userIds: z.array(z.string()).optional(),
|
|
30
|
+
alreadyInChannel: z.boolean().optional(),
|
|
31
|
+
}),
|
|
32
|
+
},
|
|
33
|
+
async ({ channelId, userIds }, requestInfo, _meta) => {
|
|
34
|
+
if (!requestInfo.agentId) {
|
|
35
|
+
return toolErr("Agent ID not found.");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const agent = getAgentById(requestInfo.agentId);
|
|
39
|
+
if (!agent) {
|
|
40
|
+
return toolErr("Agent not found.");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const decision = can({
|
|
44
|
+
principal: { kind: "agent", agentId: agent.id, isLead: agent.isLead },
|
|
45
|
+
verb: "integration.slack.channel.invite",
|
|
46
|
+
resource: { kind: "none" },
|
|
47
|
+
source: "mcp",
|
|
48
|
+
});
|
|
49
|
+
if (!decision.allow) {
|
|
50
|
+
return toolErr("Managing Slack channels requires lead privileges.");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const app = getSlackApp();
|
|
54
|
+
if (!app) {
|
|
55
|
+
return toolErr("Slack not configured.");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const result = await inviteToChannel(app.client, channelId, userIds);
|
|
60
|
+
return toolOk(
|
|
61
|
+
result.alreadyInChannel
|
|
62
|
+
? "Users are already in the Slack channel."
|
|
63
|
+
: "Users invited to the Slack channel successfully.",
|
|
64
|
+
{
|
|
65
|
+
data: { channelId, userIds, ...result },
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
const missingScopeMessage = slackMissingScopeMessage(error);
|
|
70
|
+
if (missingScopeMessage) {
|
|
71
|
+
return toolErr(`Failed to invite users to Slack channel: ${missingScopeMessage}`);
|
|
72
|
+
}
|
|
73
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
74
|
+
return toolErr(`Failed to invite users to Slack channel: ${errorMsg}`);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
);
|
|
78
|
+
};
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import { createWorkerTaskFollowUp } from "@/tasks/worker-follow-up";
|
|
25
25
|
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
26
26
|
import { AgentTaskStatusSchema, AttachmentInputSchema, isTerminalTaskStatus } from "@/types";
|
|
27
|
+
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
27
28
|
|
|
28
29
|
// Phase 11: the `cost` / `costData` field was removed from this tool's input
|
|
29
30
|
// schema. Adapters (claude/codex/pi/opencode/devin/claude-managed) are the
|
|
@@ -400,7 +401,12 @@ export const registerStoreProgressTool = (server: McpServer) => {
|
|
|
400
401
|
} catch {
|
|
401
402
|
// Non-blocking — task completion memory failure should not affect task status
|
|
402
403
|
}
|
|
403
|
-
})()
|
|
404
|
+
})().catch((err) =>
|
|
405
|
+
console.error(
|
|
406
|
+
"[store-progress] task completion memory write failed:",
|
|
407
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
408
|
+
),
|
|
409
|
+
);
|
|
404
410
|
}
|
|
405
411
|
|
|
406
412
|
if (shouldRunTerminalSideEffects) {
|
|
@@ -436,7 +442,12 @@ export const registerStoreProgressTool = (server: McpServer) => {
|
|
|
436
442
|
err instanceof Error ? err.message : String(err),
|
|
437
443
|
);
|
|
438
444
|
}
|
|
439
|
-
})()
|
|
445
|
+
})().catch((err) =>
|
|
446
|
+
console.error(
|
|
447
|
+
"[store-progress] server rater run failed:",
|
|
448
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
449
|
+
),
|
|
450
|
+
);
|
|
440
451
|
}
|
|
441
452
|
|
|
442
453
|
// Create follow-up task for the lead when a worker task finishes.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import * as z from "zod";
|
|
3
3
|
import { deleteSwarmConfig, getAgentById, getSwarmConfigLookupById } from "@/be/db";
|
|
4
|
+
import { AGENT_MAX_TASKS_CONFIG_KEY, resetAgentMaxTasksMirror } from "@/be/multi-runtime";
|
|
4
5
|
import { scheduleIntegrationsReload } from "@/http/core";
|
|
5
6
|
import { can } from "@/rbac";
|
|
6
7
|
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
@@ -56,6 +57,14 @@ export const registerDeleteConfigTool = (server: McpServer) => {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
const deleted = deleteSwarmConfig(id);
|
|
60
|
+
if (
|
|
61
|
+
deleted &&
|
|
62
|
+
existing.scope === "agent" &&
|
|
63
|
+
existing.scopeId &&
|
|
64
|
+
existing.key === AGENT_MAX_TASKS_CONFIG_KEY
|
|
65
|
+
) {
|
|
66
|
+
resetAgentMaxTasksMirror(existing.scopeId);
|
|
67
|
+
}
|
|
59
68
|
if (!deleted) {
|
|
60
69
|
return toolErr(`Failed to delete config entry "${id}".`, {
|
|
61
70
|
data: { yourAgentId: requestInfo.agentId },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import * as z from "zod";
|
|
3
|
-
import { getAgentById, maskSecrets
|
|
3
|
+
import { getAgentById, maskSecrets } from "@/be/db";
|
|
4
|
+
import { upsertSwarmConfigWithPolicyMirror } from "@/be/multi-runtime";
|
|
4
5
|
import {
|
|
5
6
|
isReservedConfigKey,
|
|
6
7
|
reservedKeyError,
|
|
@@ -110,7 +111,7 @@ export const registerSetConfigTool = (server: McpServer) => {
|
|
|
110
111
|
return toolErr(validationError, { data: { yourAgentId: requestInfo.agentId } });
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
const config =
|
|
114
|
+
const config = upsertSwarmConfigWithPolicyMirror({
|
|
114
115
|
scope,
|
|
115
116
|
scopeId: scope === "global" ? null : scopeId,
|
|
116
117
|
key,
|
package/src/tools/task-action.ts
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
releaseTask,
|
|
28
28
|
updateTaskClaudeSessionId,
|
|
29
29
|
} from "@/be/db";
|
|
30
|
+
import { touchRuntimeInstance } from "@/be/multi-runtime";
|
|
30
31
|
import { assertOwnsTask, ownerCtx, type ToolCtx } from "@/tools/task-tool-ctx";
|
|
31
32
|
import {
|
|
32
33
|
createToolRegistrar,
|
|
@@ -42,6 +43,7 @@ import {
|
|
|
42
43
|
ReasoningEffortSchema,
|
|
43
44
|
splitLegacyModelAlias,
|
|
44
45
|
} from "@/types";
|
|
46
|
+
import { isMultiRuntimeEnabled } from "@/utils/multi-runtime";
|
|
45
47
|
import { looseAgentTaskOutputSchema } from "./get-task-details";
|
|
46
48
|
|
|
47
49
|
export const TaskActionSchema = z.enum([
|
|
@@ -140,6 +142,28 @@ function agentOnlyActionResult(): SwarmToolResult {
|
|
|
140
142
|
return toolErr("This action is only available to worker agents.");
|
|
141
143
|
}
|
|
142
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Work-acquisition gate shared by claim and accept — the same dispatch gate
|
|
147
|
+
* as HTTP poll and poll-task: a process whose runtime is gone must not take
|
|
148
|
+
* work beside its replacement. Identity travels as request context, never as
|
|
149
|
+
* a tool argument; touch refreshes liveness and cannot revive a retired
|
|
150
|
+
* runtime. Returns null when acquisition may proceed.
|
|
151
|
+
*/
|
|
152
|
+
function staleRuntimeResult(ctx: ToolCtx, agentId: string): TaskActionResult | null {
|
|
153
|
+
if (!isMultiRuntimeEnabled()) return null;
|
|
154
|
+
if (
|
|
155
|
+
ctx.kind === "owner" &&
|
|
156
|
+
ctx.runtimeInstanceId &&
|
|
157
|
+
touchRuntimeInstance(ctx.runtimeInstanceId, agentId)
|
|
158
|
+
) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
success: false,
|
|
163
|
+
message: "This runtime is no longer registered. Re-register before taking work.",
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
143
167
|
function taskActionResult(result: TaskActionResult, agentId?: string): SwarmToolResult {
|
|
144
168
|
const { refusalSideEffects: _omit, success, message, ...rest } = result;
|
|
145
169
|
const data = {
|
|
@@ -285,6 +309,8 @@ export async function taskActionHandler(
|
|
|
285
309
|
if (!taskId) {
|
|
286
310
|
return { success: false, message: "Task ID is required for 'claim' action." };
|
|
287
311
|
}
|
|
312
|
+
const staleClaimRuntime = staleRuntimeResult(ctx, agentId);
|
|
313
|
+
if (staleClaimRuntime) return staleClaimRuntime;
|
|
288
314
|
// Check capacity before claiming
|
|
289
315
|
if (!hasCapacity(agentId)) {
|
|
290
316
|
const activeCount = getActiveTaskCount(agentId);
|
|
@@ -388,6 +414,10 @@ export async function taskActionHandler(
|
|
|
388
414
|
if (!taskId) {
|
|
389
415
|
return { success: false, message: "Task ID is required for 'accept' action." };
|
|
390
416
|
}
|
|
417
|
+
// Accept is a work-acquisition transition too — gate it before the
|
|
418
|
+
// budget admission below so a retired process cannot take the offer.
|
|
419
|
+
const staleAcceptRuntime = staleRuntimeResult(ctx, agentId);
|
|
420
|
+
if (staleAcceptRuntime) return staleAcceptRuntime;
|
|
391
421
|
const existingTask = getTaskById(taskId);
|
|
392
422
|
if (!existingTask) {
|
|
393
423
|
return { success: false, message: `Task "${taskId}" not found.` };
|
|
@@ -3,13 +3,20 @@ import type { AgentTask, User } from "@/types";
|
|
|
3
3
|
import { type RequestInfo, type SwarmToolResult, toolErr } from "./utils";
|
|
4
4
|
|
|
5
5
|
export type ToolCtx =
|
|
6
|
-
| {
|
|
6
|
+
| {
|
|
7
|
+
kind: "owner";
|
|
8
|
+
agentId?: string;
|
|
9
|
+
runtimeInstanceId?: string;
|
|
10
|
+
sourceTaskId?: string;
|
|
11
|
+
sessionId?: string;
|
|
12
|
+
}
|
|
7
13
|
| { kind: "user"; userId: string; user: User; sessionId?: string };
|
|
8
14
|
|
|
9
15
|
export function ownerCtx(info: RequestInfo): ToolCtx {
|
|
10
16
|
return {
|
|
11
17
|
kind: "owner",
|
|
12
18
|
agentId: info.agentId,
|
|
19
|
+
runtimeInstanceId: info.runtimeInstanceId,
|
|
13
20
|
sourceTaskId: info.sourceTaskId,
|
|
14
21
|
sessionId: info.sessionId,
|
|
15
22
|
};
|
package/src/tools/tool-config.ts
CHANGED
|
@@ -87,7 +87,7 @@ export const DEFERRED_TOOLS = new Set([
|
|
|
87
87
|
"context-history",
|
|
88
88
|
"context-diff",
|
|
89
89
|
|
|
90
|
-
// Slack (
|
|
90
|
+
// Slack (12)
|
|
91
91
|
"slack-reply",
|
|
92
92
|
"slack-read",
|
|
93
93
|
"slack-upload-file",
|
|
@@ -95,6 +95,9 @@ export const DEFERRED_TOOLS = new Set([
|
|
|
95
95
|
"slack-list-channels",
|
|
96
96
|
"slack-post",
|
|
97
97
|
"slack-start-thread",
|
|
98
|
+
"slack-create-channel",
|
|
99
|
+
"slack-invite-to-channel",
|
|
100
|
+
"slack-archive-channel",
|
|
98
101
|
"slack-delete",
|
|
99
102
|
"slack-update",
|
|
100
103
|
|