@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
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
3
|
+
import { runMigrations } from "../be/migrations/runner";
|
|
4
|
+
import { extractGitHubPullRequestUrls } from "../utils/github-pull-request";
|
|
5
|
+
|
|
6
|
+
const DB_PATH = "./test-task-pull-request-backfill-migration.sqlite";
|
|
7
|
+
const ECMASCRIPT_WHITESPACE_CODE_POINTS = [
|
|
8
|
+
9, 10, 11, 12, 13, 32, 160, 5760, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201,
|
|
9
|
+
8202, 8232, 8233, 8239, 8287, 12288, 65279,
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
async function removeDb(): Promise<void> {
|
|
13
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
14
|
+
try {
|
|
15
|
+
await Bun.file(DB_PATH + suffix).delete();
|
|
16
|
+
} catch (error) {
|
|
17
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
afterEach(removeDb);
|
|
23
|
+
|
|
24
|
+
describe("migration 135 task pull-request attachment backfill", () => {
|
|
25
|
+
test("applies fresh, backfills existing outputs, and replays idempotently", async () => {
|
|
26
|
+
await removeDb();
|
|
27
|
+
const db = new Database(DB_PATH, { create: true });
|
|
28
|
+
try {
|
|
29
|
+
runMigrations(db);
|
|
30
|
+
expect(
|
|
31
|
+
db.query<{ count: number }, []>("SELECT COUNT(*) AS count FROM task_attachments").get()
|
|
32
|
+
?.count,
|
|
33
|
+
).toBe(0);
|
|
34
|
+
db.run("DELETE FROM _migrations WHERE version = 135");
|
|
35
|
+
|
|
36
|
+
const now = new Date().toISOString();
|
|
37
|
+
const insertTask = db.prepare(
|
|
38
|
+
`INSERT INTO agent_tasks
|
|
39
|
+
(id, task, status, source, output, createdAt, lastUpdatedAt)
|
|
40
|
+
VALUES (?, 'fixture', 'completed', 'api', ?, ?, ?)`,
|
|
41
|
+
);
|
|
42
|
+
const firstTaskId = "11111111-1111-4111-8111-111111111111";
|
|
43
|
+
const secondTaskId = "22222222-2222-4222-8222-222222222222";
|
|
44
|
+
const thirdTaskId = "44444444-4444-4444-8444-444444444444";
|
|
45
|
+
const vcsOnlyTaskId = "66666666-6666-4666-8666-666666666666";
|
|
46
|
+
insertTask.run(
|
|
47
|
+
firstTaskId,
|
|
48
|
+
"Ignore https://notgithub.com/wrong/repo/pull/88. Shipped " +
|
|
49
|
+
"https://GitHub.com/desplega-ai/agent-swarm/pull/41/files and " +
|
|
50
|
+
"github.com/desplega-ai/docs/pull/9). Duplicate: " +
|
|
51
|
+
"https://github.com/desplega-ai/agent-swarm/pull/41#discussion",
|
|
52
|
+
now,
|
|
53
|
+
now,
|
|
54
|
+
);
|
|
55
|
+
insertTask.run(
|
|
56
|
+
secondTaskId,
|
|
57
|
+
"Existing https://github.com/desplega-ai/agent-swarm/pull/42. Reject " +
|
|
58
|
+
"https://github.com/org/repo/tree/pull/123 and " +
|
|
59
|
+
"https://github.com/org/repo/issues/1/pull/2 and " +
|
|
60
|
+
"https://_github.com/org/repo/pull/3 and " +
|
|
61
|
+
"https://evil.example/github.com/org/repo/pull/4 and " +
|
|
62
|
+
"https://github.com/org/repo/pull/123abc",
|
|
63
|
+
now,
|
|
64
|
+
now,
|
|
65
|
+
);
|
|
66
|
+
insertTask.run(
|
|
67
|
+
thirdTaskId,
|
|
68
|
+
"Valid output https://github.com/desplega-ai/agent-swarm/pull/43",
|
|
69
|
+
now,
|
|
70
|
+
now,
|
|
71
|
+
);
|
|
72
|
+
insertTask.run(vcsOnlyTaskId, "Completed through the historical VCS path", now, now);
|
|
73
|
+
db.run(
|
|
74
|
+
`UPDATE agent_tasks
|
|
75
|
+
SET vcsProvider = 'github', vcsRepo = 'desplega-ai/agent-swarm',
|
|
76
|
+
vcsNumber = 44, vcsUrl = 'https://github.com/desplega-ai/agent-swarm/pull/44'
|
|
77
|
+
WHERE id = ?`,
|
|
78
|
+
[vcsOnlyTaskId],
|
|
79
|
+
);
|
|
80
|
+
const existingId = "33333333-3333-4333-8333-333333333333";
|
|
81
|
+
db.run(
|
|
82
|
+
`INSERT INTO task_attachments
|
|
83
|
+
(id, task_id, name, kind, url, provider_id, provider_key, intent)
|
|
84
|
+
VALUES (?, ?, 'Caller supplied', 'url', ?, 'url', ?, 'review')`,
|
|
85
|
+
[
|
|
86
|
+
existingId,
|
|
87
|
+
secondTaskId,
|
|
88
|
+
"http://GitHub.com/desplega-ai/agent-swarm/pull/42/files",
|
|
89
|
+
"http://GitHub.com/desplega-ai/agent-swarm/pull/42/files",
|
|
90
|
+
],
|
|
91
|
+
);
|
|
92
|
+
db.run(
|
|
93
|
+
`INSERT INTO task_attachments
|
|
94
|
+
(id, task_id, name, kind, url, provider_id, provider_key, intent)
|
|
95
|
+
VALUES (?, ?, 'Malformed attachment', 'url', ?, 'url', ?, 'review')`,
|
|
96
|
+
[
|
|
97
|
+
"55555555-5555-4555-8555-555555555555",
|
|
98
|
+
thirdTaskId,
|
|
99
|
+
"https://github.com/desplega-ai/agent-swarm/pull/43abc",
|
|
100
|
+
"https://github.com/desplega-ai/agent-swarm/pull/43abc",
|
|
101
|
+
],
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
runMigrations(db);
|
|
105
|
+
|
|
106
|
+
const rows = db
|
|
107
|
+
.query<
|
|
108
|
+
{
|
|
109
|
+
id: string;
|
|
110
|
+
taskId: string;
|
|
111
|
+
name: string;
|
|
112
|
+
url: string;
|
|
113
|
+
providerId: string | null;
|
|
114
|
+
providerKey: string | null;
|
|
115
|
+
capabilities: Record<string, unknown> | null;
|
|
116
|
+
intent: string | null;
|
|
117
|
+
},
|
|
118
|
+
[]
|
|
119
|
+
>(
|
|
120
|
+
`SELECT id, task_id AS taskId, name, url,
|
|
121
|
+
provider_id AS providerId, provider_key AS providerKey,
|
|
122
|
+
json(capabilities) AS capabilities, intent
|
|
123
|
+
FROM task_attachments
|
|
124
|
+
ORDER BY task_id, url`,
|
|
125
|
+
)
|
|
126
|
+
.all();
|
|
127
|
+
expect(rows).toHaveLength(6);
|
|
128
|
+
expect(
|
|
129
|
+
rows.map((row) => ({
|
|
130
|
+
...row,
|
|
131
|
+
id: undefined,
|
|
132
|
+
capabilities: row.capabilities ? JSON.parse(String(row.capabilities)) : null,
|
|
133
|
+
})),
|
|
134
|
+
).toEqual([
|
|
135
|
+
{
|
|
136
|
+
id: undefined,
|
|
137
|
+
taskId: firstTaskId,
|
|
138
|
+
name: "GitHub pull request #41",
|
|
139
|
+
url: "https://github.com/desplega-ai/agent-swarm/pull/41",
|
|
140
|
+
providerId: "github",
|
|
141
|
+
providerKey: "https://github.com/desplega-ai/agent-swarm/pull/41",
|
|
142
|
+
capabilities: {
|
|
143
|
+
_agentSwarmGeneratedBy: "task-pull-request-recorder",
|
|
144
|
+
},
|
|
145
|
+
intent: "task-deliverable",
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: undefined,
|
|
149
|
+
taskId: firstTaskId,
|
|
150
|
+
name: "GitHub pull request #9",
|
|
151
|
+
url: "https://github.com/desplega-ai/docs/pull/9",
|
|
152
|
+
providerId: "github",
|
|
153
|
+
providerKey: "https://github.com/desplega-ai/docs/pull/9",
|
|
154
|
+
capabilities: {
|
|
155
|
+
_agentSwarmGeneratedBy: "task-pull-request-recorder",
|
|
156
|
+
},
|
|
157
|
+
intent: "task-deliverable",
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: undefined,
|
|
161
|
+
taskId: secondTaskId,
|
|
162
|
+
name: "Caller supplied",
|
|
163
|
+
url: "http://GitHub.com/desplega-ai/agent-swarm/pull/42/files",
|
|
164
|
+
providerId: "url",
|
|
165
|
+
providerKey: "http://GitHub.com/desplega-ai/agent-swarm/pull/42/files",
|
|
166
|
+
capabilities: null,
|
|
167
|
+
intent: "review",
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: undefined,
|
|
171
|
+
taskId: thirdTaskId,
|
|
172
|
+
name: "GitHub pull request #43",
|
|
173
|
+
url: "https://github.com/desplega-ai/agent-swarm/pull/43",
|
|
174
|
+
providerId: "github",
|
|
175
|
+
providerKey: "https://github.com/desplega-ai/agent-swarm/pull/43",
|
|
176
|
+
capabilities: {
|
|
177
|
+
_agentSwarmGeneratedBy: "task-pull-request-recorder",
|
|
178
|
+
},
|
|
179
|
+
intent: "task-deliverable",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
id: undefined,
|
|
183
|
+
taskId: thirdTaskId,
|
|
184
|
+
name: "Malformed attachment",
|
|
185
|
+
url: "https://github.com/desplega-ai/agent-swarm/pull/43abc",
|
|
186
|
+
providerId: "url",
|
|
187
|
+
providerKey: "https://github.com/desplega-ai/agent-swarm/pull/43abc",
|
|
188
|
+
capabilities: null,
|
|
189
|
+
intent: "review",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: undefined,
|
|
193
|
+
taskId: vcsOnlyTaskId,
|
|
194
|
+
name: "GitHub pull request #44",
|
|
195
|
+
url: "https://github.com/desplega-ai/agent-swarm/pull/44",
|
|
196
|
+
providerId: "github",
|
|
197
|
+
providerKey: "https://github.com/desplega-ai/agent-swarm/pull/44",
|
|
198
|
+
capabilities: {
|
|
199
|
+
_agentSwarmGeneratedBy: "task-pull-request-recorder",
|
|
200
|
+
},
|
|
201
|
+
intent: "task-deliverable",
|
|
202
|
+
},
|
|
203
|
+
]);
|
|
204
|
+
for (const row of rows) {
|
|
205
|
+
expect(row.id).toMatch(
|
|
206
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
expect(rows.find((row) => row.taskId === secondTaskId)?.id).toBe(existingId);
|
|
210
|
+
|
|
211
|
+
db.run("DELETE FROM _migrations WHERE version = 135");
|
|
212
|
+
runMigrations(db);
|
|
213
|
+
expect(
|
|
214
|
+
db.query<{ count: number }, []>("SELECT COUNT(*) AS count FROM task_attachments").get()
|
|
215
|
+
?.count,
|
|
216
|
+
).toBe(6);
|
|
217
|
+
} finally {
|
|
218
|
+
db.close();
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("deduplicates caller URLs ending in ECMAScript whitespace", async () => {
|
|
223
|
+
await removeDb();
|
|
224
|
+
const db = new Database(DB_PATH, { create: true });
|
|
225
|
+
try {
|
|
226
|
+
runMigrations(db);
|
|
227
|
+
db.run("DELETE FROM _migrations WHERE version = 135");
|
|
228
|
+
const now = new Date().toISOString();
|
|
229
|
+
const whitespaceCodePoints = [11, 12, 160];
|
|
230
|
+
|
|
231
|
+
whitespaceCodePoints.forEach((codePoint, index) => {
|
|
232
|
+
const suffix = String(index + 1).padStart(12, "0");
|
|
233
|
+
const taskId = `bbbbbbbb-bbbb-4bbb-8bbb-${suffix}`;
|
|
234
|
+
const canonicalUrl = `https://github.com/owner/repo/pull/${index + 1}`;
|
|
235
|
+
db.run(
|
|
236
|
+
`INSERT INTO agent_tasks
|
|
237
|
+
(id, task, status, source, output, createdAt, lastUpdatedAt)
|
|
238
|
+
VALUES (?, 'fixture', 'completed', 'api', ?, ?, ?)`,
|
|
239
|
+
[taskId, `Shipped ${canonicalUrl}`, now, now],
|
|
240
|
+
);
|
|
241
|
+
db.run(
|
|
242
|
+
`INSERT INTO task_attachments (id, task_id, name, kind, url)
|
|
243
|
+
VALUES (?, ?, 'Caller supplied', 'url', ?)`,
|
|
244
|
+
[
|
|
245
|
+
`cccccccc-cccc-4ccc-8ccc-${suffix}`,
|
|
246
|
+
taskId,
|
|
247
|
+
`${canonicalUrl}${String.fromCodePoint(codePoint)}`,
|
|
248
|
+
],
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
runMigrations(db);
|
|
253
|
+
|
|
254
|
+
expect(
|
|
255
|
+
db.query<{ count: number }, []>("SELECT COUNT(*) AS count FROM task_attachments").get()
|
|
256
|
+
?.count,
|
|
257
|
+
).toBe(whitespaceCodePoints.length);
|
|
258
|
+
expect(
|
|
259
|
+
db
|
|
260
|
+
.query<{ count: number }, []>(
|
|
261
|
+
"SELECT COUNT(*) AS count FROM task_attachments WHERE capabilities IS NOT NULL",
|
|
262
|
+
)
|
|
263
|
+
.get()?.count,
|
|
264
|
+
).toBe(0);
|
|
265
|
+
} finally {
|
|
266
|
+
db.close();
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test("matches the TypeScript extractor across host and token boundaries", async () => {
|
|
271
|
+
await removeDb();
|
|
272
|
+
const db = new Database(DB_PATH, { create: true });
|
|
273
|
+
try {
|
|
274
|
+
runMigrations(db);
|
|
275
|
+
db.run("DELETE FROM _migrations WHERE version = 135");
|
|
276
|
+
const fixtures = [
|
|
277
|
+
"https://evil.example/?next=github.com/o/r/pull/8",
|
|
278
|
+
"xhttps://github.com/o/r/pull/1",
|
|
279
|
+
"https://github.com/o/r/pull/8/files",
|
|
280
|
+
"github.com/o/r/pull/8",
|
|
281
|
+
"Shipped https://github.com/o/r/pull/8, with follow-up prose.",
|
|
282
|
+
"https://notgithub.com/o/r/pull/8",
|
|
283
|
+
"https://_github.com/o/r/pull/8",
|
|
284
|
+
"https://evil.example/github.com/o/r/pull/8",
|
|
285
|
+
"https://github.com/o/r/pull/123abc",
|
|
286
|
+
"https://github.com/o/r/pull/123.foo",
|
|
287
|
+
"https://github.com/o/r/pull/123,abc",
|
|
288
|
+
"https://github.com/o/./pull/1",
|
|
289
|
+
"https://github.com/../r/pull/1",
|
|
290
|
+
...ECMASCRIPT_WHITESPACE_CODE_POINTS.map(
|
|
291
|
+
(codePoint) => `done${String.fromCodePoint(codePoint)}https://github.com/o/r/pull/8`,
|
|
292
|
+
),
|
|
293
|
+
];
|
|
294
|
+
const now = new Date().toISOString();
|
|
295
|
+
const insertTask = db.prepare(
|
|
296
|
+
`INSERT INTO agent_tasks
|
|
297
|
+
(id, task, status, source, output, createdAt, lastUpdatedAt)
|
|
298
|
+
VALUES (?, 'fixture', 'completed', 'api', ?, ?, ?)`,
|
|
299
|
+
);
|
|
300
|
+
fixtures.forEach((fixture, index) => {
|
|
301
|
+
const suffix = String(index + 1).padStart(12, "0");
|
|
302
|
+
insertTask.run(`aaaaaaaa-aaaa-4aaa-8aaa-${suffix}`, fixture, now, now);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
runMigrations(db);
|
|
306
|
+
|
|
307
|
+
fixtures.forEach((fixture, index) => {
|
|
308
|
+
const suffix = String(index + 1).padStart(12, "0");
|
|
309
|
+
const taskId = `aaaaaaaa-aaaa-4aaa-8aaa-${suffix}`;
|
|
310
|
+
const count = db
|
|
311
|
+
.query<{ count: number }, [string]>(
|
|
312
|
+
"SELECT COUNT(*) AS count FROM task_attachments WHERE task_id = ?",
|
|
313
|
+
)
|
|
314
|
+
.get(taskId)?.count;
|
|
315
|
+
expect(Boolean(count)).toBe(extractGitHubPullRequestUrls(fixture).length > 0);
|
|
316
|
+
});
|
|
317
|
+
} finally {
|
|
318
|
+
db.close();
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
});
|
|
@@ -111,6 +111,7 @@ describe("Tool Annotations & Classification", () => {
|
|
|
111
111
|
"delete-page",
|
|
112
112
|
"unregister-service",
|
|
113
113
|
"slack-delete",
|
|
114
|
+
"slack-archive-channel",
|
|
114
115
|
];
|
|
115
116
|
|
|
116
117
|
for (const name of expectedDestructive) {
|
|
@@ -164,6 +165,9 @@ describe("Tool Annotations & Classification", () => {
|
|
|
164
165
|
"slack-read",
|
|
165
166
|
"slack-post",
|
|
166
167
|
"slack-start-thread",
|
|
168
|
+
"slack-create-channel",
|
|
169
|
+
"slack-invite-to-channel",
|
|
170
|
+
"slack-archive-channel",
|
|
167
171
|
"slack-upload-file",
|
|
168
172
|
"slack-download-file",
|
|
169
173
|
"slack-list-channels",
|
|
@@ -2,6 +2,12 @@ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
|
2
2
|
import { unlink } from "node:fs/promises";
|
|
3
3
|
import { createServer as createHttpServer, type Server } from "node:http";
|
|
4
4
|
import { closeDb, createAgent, getAgentById, initDb, updateAgentProfile } from "../be/db";
|
|
5
|
+
import type { Agent } from "../types";
|
|
6
|
+
import {
|
|
7
|
+
IDENTITY_MD_MAX_CHARS,
|
|
8
|
+
IdentityFieldBudgetError,
|
|
9
|
+
SOUL_MD_MAX_CHARS,
|
|
10
|
+
} from "../utils/identity-field-budget";
|
|
5
11
|
|
|
6
12
|
const TEST_DB_PATH = "./test-update-profile-api.sqlite";
|
|
7
13
|
const TEST_PORT = 13020;
|
|
@@ -72,30 +78,23 @@ async function handleRequest(
|
|
|
72
78
|
return { status: 400, body: { error: "Capabilities must be an array of strings" } };
|
|
73
79
|
}
|
|
74
80
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
let agent: Agent | null;
|
|
82
|
+
try {
|
|
83
|
+
agent = updateAgentProfile(agentId, {
|
|
84
|
+
role: body.role,
|
|
85
|
+
description: body.description,
|
|
86
|
+
capabilities: body.capabilities,
|
|
87
|
+
claudeMd: body.claudeMd,
|
|
88
|
+
soulMd: body.soulMd,
|
|
89
|
+
identityMd: body.identityMd,
|
|
90
|
+
});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (error instanceof IdentityFieldBudgetError) {
|
|
93
|
+
return { status: 400, body: { error: error.message } };
|
|
94
|
+
}
|
|
95
|
+
throw error;
|
|
88
96
|
}
|
|
89
97
|
|
|
90
|
-
const agent = updateAgentProfile(agentId, {
|
|
91
|
-
role: body.role,
|
|
92
|
-
description: body.description,
|
|
93
|
-
capabilities: body.capabilities,
|
|
94
|
-
claudeMd: body.claudeMd,
|
|
95
|
-
soulMd: body.soulMd,
|
|
96
|
-
identityMd: body.identityMd,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
98
|
if (!agent) {
|
|
100
99
|
return { status: 404, body: { error: "Agent not found" } };
|
|
101
100
|
}
|
|
@@ -487,9 +486,16 @@ describe("PUT /api/agents/:id/profile", () => {
|
|
|
487
486
|
expect(agent?.claudeMd).toBe(claudeMdContent);
|
|
488
487
|
});
|
|
489
488
|
|
|
490
|
-
test("should return
|
|
491
|
-
const
|
|
492
|
-
|
|
489
|
+
test("should return the ratchet reason if claudeMd exceeds its session budget", async () => {
|
|
490
|
+
const agentId = "test-agent-claudemd-over-budget";
|
|
491
|
+
createAgent({
|
|
492
|
+
id: agentId,
|
|
493
|
+
name: "Test Agent ClaudeMd Over Budget",
|
|
494
|
+
isLead: false,
|
|
495
|
+
status: "idle",
|
|
496
|
+
});
|
|
497
|
+
const largeContent = "a".repeat(20_001);
|
|
498
|
+
const response = await fetch(`${baseUrl}/api/agents/${agentId}/profile`, {
|
|
493
499
|
method: "PUT",
|
|
494
500
|
headers: { "Content-Type": "application/json" },
|
|
495
501
|
body: JSON.stringify({ claudeMd: largeContent }),
|
|
@@ -497,19 +503,27 @@ describe("PUT /api/agents/:id/profile", () => {
|
|
|
497
503
|
|
|
498
504
|
expect(response.status).toBe(400);
|
|
499
505
|
const data = (await response.json()) as { error?: string };
|
|
500
|
-
expect(data.error).toContain("
|
|
506
|
+
expect(data.error).toContain("claudeMd");
|
|
507
|
+
expect(data.error).toContain("current size 0");
|
|
508
|
+
expect(data.error).toContain("budget 20000");
|
|
509
|
+
expect(data.error).toContain("delta +20001");
|
|
510
|
+
expect(data.error).toBe(
|
|
511
|
+
"Update rejected for claudeMd: current size 0 characters, budget 20000 characters, delta +20001 characters." +
|
|
512
|
+
" The tail past the 20000-character cap is dropped from the base prompt and only reaches harnesses with a native CLAUDE.md loader." +
|
|
513
|
+
" Move durable content into memories and keep pointers to it in this field.",
|
|
514
|
+
);
|
|
501
515
|
});
|
|
502
516
|
|
|
503
|
-
test("should allow claudeMd at exactly
|
|
504
|
-
const agentId = "test-agent-claudemd-
|
|
517
|
+
test("should allow claudeMd at exactly its session budget", async () => {
|
|
518
|
+
const agentId = "test-agent-claudemd-budget";
|
|
505
519
|
createAgent({
|
|
506
520
|
id: agentId,
|
|
507
|
-
name: "Test Agent ClaudeMd
|
|
521
|
+
name: "Test Agent ClaudeMd Budget",
|
|
508
522
|
isLead: false,
|
|
509
523
|
status: "idle",
|
|
510
524
|
});
|
|
511
525
|
|
|
512
|
-
const exactContent = "a".repeat(
|
|
526
|
+
const exactContent = "a".repeat(20_000);
|
|
513
527
|
const response = await fetch(`${baseUrl}/api/agents/${agentId}/profile`, {
|
|
514
528
|
method: "PUT",
|
|
515
529
|
headers: { "Content-Type": "application/json" },
|
|
@@ -518,7 +532,7 @@ describe("PUT /api/agents/:id/profile", () => {
|
|
|
518
532
|
|
|
519
533
|
expect(response.status).toBe(200);
|
|
520
534
|
const data = (await response.json()) as { claudeMd?: string };
|
|
521
|
-
expect(data.claudeMd?.length).toBe(
|
|
535
|
+
expect(data.claudeMd?.length).toBe(20_000);
|
|
522
536
|
});
|
|
523
537
|
|
|
524
538
|
test("should allow clearing claudeMd by setting empty string", async () => {
|
|
@@ -607,9 +621,16 @@ describe("PUT /api/agents/:id/profile", () => {
|
|
|
607
621
|
expect(agent?.soulMd).toBe(soulContent);
|
|
608
622
|
});
|
|
609
623
|
|
|
610
|
-
test("should return 400 if soulMd exceeds
|
|
611
|
-
const
|
|
612
|
-
|
|
624
|
+
test("should return 400 if soulMd exceeds its session budget", async () => {
|
|
625
|
+
const agentId = "test-agent-soulmd-over-budget";
|
|
626
|
+
createAgent({
|
|
627
|
+
id: agentId,
|
|
628
|
+
name: "Test Agent SoulMd Over Budget",
|
|
629
|
+
isLead: false,
|
|
630
|
+
status: "idle",
|
|
631
|
+
});
|
|
632
|
+
const largeContent = "a".repeat(SOUL_MD_MAX_CHARS + 1);
|
|
633
|
+
const response = await fetch(`${baseUrl}/api/agents/${agentId}/profile`, {
|
|
613
634
|
method: "PUT",
|
|
614
635
|
headers: { "Content-Type": "application/json" },
|
|
615
636
|
body: JSON.stringify({ soulMd: largeContent }),
|
|
@@ -617,7 +638,7 @@ describe("PUT /api/agents/:id/profile", () => {
|
|
|
617
638
|
|
|
618
639
|
expect(response.status).toBe(400);
|
|
619
640
|
const data = (await response.json()) as { error?: string };
|
|
620
|
-
expect(data.error).toContain(
|
|
641
|
+
expect(data.error).toContain(`budget ${SOUL_MD_MAX_CHARS}`);
|
|
621
642
|
});
|
|
622
643
|
});
|
|
623
644
|
|
|
@@ -648,9 +669,16 @@ describe("PUT /api/agents/:id/profile", () => {
|
|
|
648
669
|
expect(agent?.identityMd).toBe(identityContent);
|
|
649
670
|
});
|
|
650
671
|
|
|
651
|
-
test("should return 400 if identityMd exceeds
|
|
652
|
-
const
|
|
653
|
-
|
|
672
|
+
test("should return 400 if identityMd exceeds its session budget", async () => {
|
|
673
|
+
const agentId = "test-agent-identitymd-over-budget";
|
|
674
|
+
createAgent({
|
|
675
|
+
id: agentId,
|
|
676
|
+
name: "Test Agent IdentityMd Over Budget",
|
|
677
|
+
isLead: false,
|
|
678
|
+
status: "idle",
|
|
679
|
+
});
|
|
680
|
+
const largeContent = "a".repeat(IDENTITY_MD_MAX_CHARS + 1);
|
|
681
|
+
const response = await fetch(`${baseUrl}/api/agents/${agentId}/profile`, {
|
|
654
682
|
method: "PUT",
|
|
655
683
|
headers: { "Content-Type": "application/json" },
|
|
656
684
|
body: JSON.stringify({ identityMd: largeContent }),
|
|
@@ -658,7 +686,7 @@ describe("PUT /api/agents/:id/profile", () => {
|
|
|
658
686
|
|
|
659
687
|
expect(response.status).toBe(400);
|
|
660
688
|
const data = (await response.json()) as { error?: string };
|
|
661
|
-
expect(data.error).toContain(
|
|
689
|
+
expect(data.error).toContain(`budget ${IDENTITY_MD_MAX_CHARS}`);
|
|
662
690
|
});
|
|
663
691
|
|
|
664
692
|
test("should preserve soulMd and identityMd when updating other fields", async () => {
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { afterAll, beforeAll, describe, expect, spyOn, test } from "bun:test";
|
|
2
|
-
import { unlink } from "node:fs/promises";
|
|
3
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
closeDb,
|
|
5
|
+
createAgent,
|
|
6
|
+
deleteAgent,
|
|
7
|
+
getAgentById,
|
|
8
|
+
getLatestContextVersion,
|
|
9
|
+
initDb,
|
|
10
|
+
} from "../be/db";
|
|
5
11
|
import { registerUpdateProfileTool } from "../tools/update-profile";
|
|
12
|
+
import { SOUL_MD_MAX_CHARS } from "../utils/identity-field-budget";
|
|
6
13
|
|
|
7
14
|
const TEST_DB_PATH = "./test-update-profile-auth.sqlite";
|
|
8
15
|
|
|
@@ -54,7 +61,7 @@ describe("update-profile authorization", () => {
|
|
|
54
61
|
beforeAll(async () => {
|
|
55
62
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
56
63
|
try {
|
|
57
|
-
await
|
|
64
|
+
await Bun.file(TEST_DB_PATH + suffix).delete();
|
|
58
65
|
} catch {
|
|
59
66
|
// File doesn't exist
|
|
60
67
|
}
|
|
@@ -75,7 +82,7 @@ describe("update-profile authorization", () => {
|
|
|
75
82
|
closeDb();
|
|
76
83
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
77
84
|
try {
|
|
78
|
-
await
|
|
85
|
+
await Bun.file(TEST_DB_PATH + suffix).delete();
|
|
79
86
|
} catch {
|
|
80
87
|
// ignore
|
|
81
88
|
}
|
|
@@ -208,6 +215,21 @@ describe("update-profile authorization", () => {
|
|
|
208
215
|
expect(agent?.setupScript).toBe(before);
|
|
209
216
|
});
|
|
210
217
|
|
|
218
|
+
test("rejected combined name and identity update leaves the name unchanged", async () => {
|
|
219
|
+
const before = getAgentById(WORKER_ID);
|
|
220
|
+
|
|
221
|
+
const result = await callUpdateProfile(server, WORKER_ID, {
|
|
222
|
+
name: "Partially Renamed Worker",
|
|
223
|
+
soulMd: "x".repeat(SOUL_MD_MAX_CHARS + 1),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
expect(result.structuredContent.success).toBe(false);
|
|
227
|
+
expect(result.structuredContent.message).toContain("Update rejected for soulMd");
|
|
228
|
+
const after = getAgentById(WORKER_ID);
|
|
229
|
+
expect(after?.name).toBe(before?.name);
|
|
230
|
+
expect(after?.soulMd).toBe(before?.soulMd);
|
|
231
|
+
});
|
|
232
|
+
|
|
211
233
|
test("logs setupScript audit diff for accepted updates", async () => {
|
|
212
234
|
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
213
235
|
|
|
@@ -227,4 +249,26 @@ describe("update-profile authorization", () => {
|
|
|
227
249
|
warnSpy.mockRestore();
|
|
228
250
|
}
|
|
229
251
|
});
|
|
252
|
+
|
|
253
|
+
test("missing self agent does not write supplied profile files", async () => {
|
|
254
|
+
const originalAgentId = process.env.AGENT_ID;
|
|
255
|
+
const writeSpy = spyOn(Bun, "write").mockImplementation(async () => 0);
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
process.env.AGENT_ID = WORKER_ID;
|
|
259
|
+
expect(deleteAgent(WORKER_ID)).toBe(true);
|
|
260
|
+
|
|
261
|
+
const result = await callUpdateProfile(server, WORKER_ID, {
|
|
262
|
+
soulMd: "must not reach the workspace",
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
expect(result.structuredContent.success).toBe(false);
|
|
266
|
+
expect(result.structuredContent.message).toContain("Agent not found");
|
|
267
|
+
expect(writeSpy).not.toHaveBeenCalled();
|
|
268
|
+
} finally {
|
|
269
|
+
writeSpy.mockRestore();
|
|
270
|
+
if (originalAgentId === undefined) delete process.env.AGENT_ID;
|
|
271
|
+
else process.env.AGENT_ID = originalAgentId;
|
|
272
|
+
}
|
|
273
|
+
});
|
|
230
274
|
});
|
|
@@ -158,3 +158,57 @@ describe("migration 127 user attribution backfill", () => {
|
|
|
158
158
|
}
|
|
159
159
|
});
|
|
160
160
|
});
|
|
161
|
+
|
|
162
|
+
describe("migration 136 requester provenance backfill", () => {
|
|
163
|
+
test("marks matching descendant requesters as inherited", async () => {
|
|
164
|
+
await removeDb();
|
|
165
|
+
const db = new Database(DB_PATH, { create: true });
|
|
166
|
+
try {
|
|
167
|
+
db.run(`CREATE TABLE agent_tasks (
|
|
168
|
+
id TEXT PRIMARY KEY,
|
|
169
|
+
parentTaskId TEXT,
|
|
170
|
+
requestedByUserId TEXT,
|
|
171
|
+
taskType TEXT,
|
|
172
|
+
tags TEXT,
|
|
173
|
+
created_by TEXT
|
|
174
|
+
)`);
|
|
175
|
+
db.run(`INSERT INTO agent_tasks
|
|
176
|
+
(id, parentTaskId, requestedByUserId, taskType, tags, created_by) VALUES
|
|
177
|
+
('root', NULL, 'user-a', 'heartbeat-checklist', '[]', NULL),
|
|
178
|
+
('child', 'root', 'user-a', NULL, '[]', NULL),
|
|
179
|
+
('grandchild', 'child', 'user-a', NULL, '[]', NULL),
|
|
180
|
+
('handoff', 'root', 'user-b', NULL, '[]', NULL),
|
|
181
|
+
('handoff-child', 'handoff', 'user-b', NULL, '[]', NULL),
|
|
182
|
+
('same-user-handoff', 'root', 'user-a', NULL, '[]', 'user-a'),
|
|
183
|
+
('same-user-handoff-child', 'same-user-handoff', 'user-a', NULL, '[]', NULL),
|
|
184
|
+
('unattributed-child', 'root', NULL, NULL, '[]', NULL),
|
|
185
|
+
('ordinary-root', NULL, 'user-a', NULL, '[]', NULL),
|
|
186
|
+
('ordinary-child', 'ordinary-root', 'user-a', NULL, '[]', NULL)`);
|
|
187
|
+
|
|
188
|
+
const migration = await Bun.file(
|
|
189
|
+
new URL("../be/migrations/136_task_requester_provenance.sql", import.meta.url),
|
|
190
|
+
).text();
|
|
191
|
+
db.exec(migration);
|
|
192
|
+
|
|
193
|
+
const rows = db
|
|
194
|
+
.query<{ id: string; inherited: number }, []>(
|
|
195
|
+
"SELECT id, requestedByUserIdInherited AS inherited FROM agent_tasks ORDER BY id",
|
|
196
|
+
)
|
|
197
|
+
.all();
|
|
198
|
+
expect(Object.fromEntries(rows.map((row) => [row.id, row.inherited]))).toEqual({
|
|
199
|
+
child: 1,
|
|
200
|
+
grandchild: 1,
|
|
201
|
+
handoff: 0,
|
|
202
|
+
"handoff-child": 0,
|
|
203
|
+
"ordinary-child": 0,
|
|
204
|
+
"ordinary-root": 0,
|
|
205
|
+
root: 0,
|
|
206
|
+
"same-user-handoff": 0,
|
|
207
|
+
"same-user-handoff-child": 0,
|
|
208
|
+
"unattributed-child": 0,
|
|
209
|
+
});
|
|
210
|
+
} finally {
|
|
211
|
+
db.close();
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
});
|