@desplega.ai/agent-swarm 2.7.4 → 2.7.6
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 +1 -1
- package/dist/acp-adapter-bp91d37f.js +15 -0
- package/dist/{actions-gfrr9vb7.js → actions-yj0eeaqh.js} +19 -18
- package/dist/{amp-adapter-0s58gm46.js → amp-adapter-4pg9h34q.js} +3 -3
- package/dist/{app-stvq692g.js → app-909e97cr.js} +3 -3
- package/dist/{assistant-5s37fr9n.js → assistant-qdyb5fyy.js} +32 -23
- package/dist/{boot-reembed-yzy1841n.js → boot-reembed-fk0s9z18.js} +1 -1
- package/dist/{boot-reembed-cv82gz7y.js → boot-reembed-gs1rzrnh.js} +1 -1
- package/dist/{boot-scrub-sweep-8k4q95ap.js → boot-scrub-sweep-4qfd4kfx.js} +4 -4
- package/dist/{boot-seeds-ftt9htah.js → boot-seeds-yr00k13d.js} +4 -4
- package/dist/{boxd-515v1t8z.js → boxd-vdmfssd9.js} +5 -5
- package/dist/{claude-adapter-t00wrzeh.js → claude-adapter-qta1f1xn.js} +7 -7
- package/dist/{claude-managed-adapter-g6vmjccb.js → claude-managed-adapter-dvs2xw5n.js} +2 -2
- package/dist/{claude-managed-setup-afpa82f7.js → claude-managed-setup-sc6j4dm0.js} +3 -3
- package/dist/{claude-sdk-session-vj0c2azx.js → claude-sdk-session-zgrz6yvc.js} +9175 -9076
- package/dist/{cli-gjr2y2xk.js → cli-0agcv1v5.js} +4 -1
- package/dist/{cli-edmm9d9y.js → cli-0at8w34w.js} +7 -7
- package/dist/{cli-a81qevyg.js → cli-0qatpy8q.js} +20 -36
- package/dist/{cli-bcz074zx.js → cli-0yv5z2pg.js} +1 -1
- package/dist/{cli-a4btqqft.js → cli-1b7btd38.js} +1 -1
- package/dist/{cli-a2jw6ee5.js → cli-1p89xny0.js} +1 -1
- package/dist/{cli-v726afdm.js → cli-2pnswgh8.js} +1 -1
- package/dist/{cli-jkt52mgt.js → cli-386tyxxg.js} +2 -2
- package/dist/{cli-az0bpf8p.js → cli-3ypk9vk1.js} +3 -3
- package/dist/{cli-wk9md5px.js → cli-436532ck.js} +4 -4
- package/dist/{cli-7n5sbw0z.js → cli-4necwtsv.js} +5 -5
- package/dist/cli-54t00gt8.js +151 -0
- package/dist/{cli-655xm9ms.js → cli-583frbyr.js} +1 -1
- package/dist/{cli-4r12t6w6.js → cli-5c4hjzne.js} +101 -4
- package/dist/{cli-hf6zt5m6.js → cli-69szn7w7.js} +17 -1
- package/dist/{cli-rtk9g7av.js → cli-73jzwksr.js} +6 -2
- package/dist/{cli-jg0nfda6.js → cli-75gkpjvw.js} +52 -21
- package/dist/{cli-wcmnan2g.js → cli-89knwags.js} +5 -5
- package/dist/{cli-pwyevs29.js → cli-8bc1w0tw.js} +22 -21
- package/dist/{cli-t282jgab.js → cli-8snvgs5r.js} +41 -16
- package/dist/{cli-vqgnyh76.js → cli-98rw5dt5.js} +15 -3
- package/dist/{cli-9cctx1tn.js → cli-a22h291q.js} +1 -1
- package/dist/{cli-ycm6180s.js → cli-a7v854rf.js} +5 -3
- package/dist/{cli-98pke4vk.js → cli-ae7mrdf9.js} +2 -2
- package/dist/{cli-je8yeyc5.js → cli-bjb3z51z.js} +5 -5
- package/dist/{cli-mc97xy2s.js → cli-c60vetmm.js} +16 -4
- package/dist/{cli-j4kw3rsx.js → cli-cm5yqn35.js} +18 -0
- package/dist/{cli-wndv9p7g.js → cli-decfb6v8.js} +6 -6
- package/dist/{cli-h55y2bjc.js → cli-dhar9qay.js} +2 -2
- package/dist/{cli-8yy525ad.js → cli-drr5v6av.js} +2 -2
- package/dist/{cli-5gr1g711.js → cli-dxae2yg7.js} +2 -2
- package/dist/{cli-pe09p6dv.js → cli-e3r2neck.js} +8 -7
- package/dist/{cli-13jvmew3.js → cli-ekwks2vs.js} +7 -7
- package/dist/{cli-jg4p5t36.js → cli-es6va8jk.js} +121 -51
- package/dist/{cli-j4kt1mpb.js → cli-faxe6thg.js} +3 -3
- package/dist/{cli-tzrpv5sc.js → cli-ftyxyspd.js} +1 -1
- package/dist/cli-fw2w0kva.js +47 -0
- package/dist/{cli-2dfbv8qr.js → cli-fy6x31ps.js} +1 -0
- package/dist/{cli-aq58fk5m.js → cli-g83s9ewh.js} +7 -1
- package/dist/cli-gdhpcbhf.js +55 -0
- package/dist/{cli-82jg7fp9.js → cli-he5nxaa8.js} +1 -1
- package/dist/{cli-8veytvbh.js → cli-he9wchme.js} +1 -1
- package/dist/{cli-k76tgq03.js → cli-hgaazk69.js} +2 -2
- package/dist/{cli-d2pzqej1.js → cli-hr2e2fft.js} +741 -7
- package/dist/{cli-dae4sbgy.js → cli-jm2vfpfd.js} +2 -2
- package/dist/{cli-1s1dqn1j.js → cli-k2gzwsj2.js} +297 -140
- package/dist/{cli-b1afgtj3.js → cli-kqdg1bsb.js} +3 -3
- package/dist/cli-m2z8jagn.js +12078 -0
- package/dist/{cli-mvckssyq.js → cli-m48g6p95.js} +5 -5
- package/dist/{cli-bwty35gx.js → cli-mthwvjre.js} +1 -1
- package/dist/{cli-41z8xwj0.js → cli-nhrvpaj7.js} +34 -8
- package/dist/{cli-ahd90bwt.js → cli-nwj0ee2w.js} +6 -6
- package/dist/{cli-kvtc7aez.js → cli-p5gp8pcx.js} +44 -14
- package/dist/{cli-avgcz4ra.js → cli-pd7vagab.js} +436 -171
- package/dist/{cli-zn15c46z.js → cli-q0k1w5zd.js} +1 -1
- package/dist/{cli-bq2pcphn.js → cli-rmmmrjkd.js} +1 -1
- package/dist/{cli-2qpvmmkw.js → cli-s0qnd4wv.js} +1 -1
- package/dist/{cli-kg8hchyg.js → cli-sa02jsqt.js} +1 -1
- package/dist/{cli-1yekbyqm.js → cli-shpbx5ee.js} +283 -82
- package/dist/{cli-9y354g3j.js → cli-srye3vdt.js} +1 -1
- package/dist/{cli-byqfbnjw.js → cli-svj5090z.js} +9 -9
- package/dist/{cli-gcbdjt47.js → cli-vfym7wmz.js} +6 -6
- package/dist/{cli-v1yw3wha.js → cli-vvpx3gsx.js} +4 -4
- package/dist/{cli-a1fhj4n9.js → cli-w6dt9ged.js} +2 -2
- package/dist/{cli-1gm8jcyr.js → cli-waqbxg08.js} +5232 -68
- package/dist/{cli-5hjced2v.js → cli-wp9sp1qb.js} +6 -6
- package/dist/{cli-eny54typ.js → cli-wx3rhnm0.js} +1 -1
- package/dist/{cli-s0exq74r.js → cli-xbbndvjy.js} +3 -3
- package/dist/{cli-f255yaqn.js → cli-xds5f77d.js} +3 -3
- package/dist/{cli-0sbkss7h.js → cli-xnqgpshy.js} +2 -2
- package/dist/{cli-0fgr1w9b.js → cli-xnrwazav.js} +20 -3
- package/dist/{cli-gf5hbmdr.js → cli-yjdgea32.js} +3 -3
- package/dist/{cli-cq1pf336.js → cli-yn4kxs06.js} +124 -11
- package/dist/{cli-224epwwf.js → cli-yx4kfngt.js} +3 -3
- package/dist/{cli-eqx6k993.js → cli-yy3rhsdw.js} +47 -13
- package/dist/{cli-36g23z21.js → cli-zbbwez0r.js} +4 -4
- package/dist/{cli-ktmvb20s.js → cli-zm72anhg.js} +12 -12
- package/dist/cli.js +26 -25
- package/dist/{codex-adapter-g0gctw29.js → codex-adapter-ayd1fb6h.js} +5 -5
- package/dist/{codex-hook-vrzz2xhr.js → codex-hook-9efm2x1m.js} +1 -1
- package/dist/{codex-login-0gg46ygn.js → codex-login-y0pmff1c.js} +1 -1
- package/dist/{codex-session-runner-dr2cxe1c.js → codex-session-runner-jesa32xc.js} +6 -6
- package/dist/{commands-1p07cvff.js → commands-hanewgf2.js} +9 -3
- package/dist/{controller-z0s7sv6r.js → controller-dt1n3c1q.js} +9 -4
- package/dist/{controllers-connect-x9kvvhyk.js → controllers-connect-xx8x64n5.js} +22 -21
- package/dist/{cursor-adapter-m5b98pvk.js → cursor-adapter-9s4dwwdw.js} +2 -2
- package/dist/{db-capk2raj.js → db-3vttcbv4.js} +3 -3
- package/dist/{db-rsh04kh3.js → db-9dv0g1ab.js} +12 -4
- package/dist/{devin-adapter-yxm87fe9.js → devin-adapter-r9phbnc9.js} +1 -1
- package/dist/{devtools-82fzqra8.js → devtools-qxfgbsqz.js} +1 -1
- package/dist/{dispatcher-304q6fwa.js → dispatcher-tx9hd1sv.js} +18 -17
- package/dist/{docker-7rxt0rry.js → docker-c1a3gqmf.js} +91 -24
- package/dist/{dsh-adapter-btewem0y.js → dsh-adapter-007y4ejs.js} +2 -2
- package/dist/{e2b-renc0k8q.js → e2b-a19d28rz.js} +4 -4
- package/dist/{e2b-7fc9b9bd.js → e2b-we6hs6q5.js} +6 -6
- package/dist/{easter-egg-3d-fm1p3n4d.js → easter-egg-3d-rgbrqb8s.js} +1 -1
- package/dist/{embedding-space-s68v49ct.js → embedding-space-ny1e2940.js} +6 -6
- package/dist/{embeddings-4ms3604w.js → embeddings-2t386t13.js} +1 -1
- package/dist/{event-bus-dfjx2qdh.js → event-bus-g0ka3pbw.js} +1 -1
- package/dist/{execute-mcdgccjs.js → execute-pksh0ceh.js} +1 -1
- package/dist/{external-channel-9dxwfztn.js → external-channel-phgmhmd7.js} +2 -2
- package/dist/fx-adapter-fy8rr921.js +18 -0
- package/dist/{google-generative-ai-yvmdxyxa.js → google-generative-ai-8y3m3k4b.js} +1 -1
- package/dist/{google-vertex-jrtdh9gs.js → google-vertex-w3v98n7b.js} +1 -1
- package/dist/{grok-adapter-05ecv4h0.js → grok-adapter-q0abvpaj.js} +8 -8
- package/dist/handlers-by3sfxyx.js +32 -0
- package/dist/{heartbeat-3n94heh3.js → heartbeat-kadyek8p.js} +21 -20
- package/dist/{hook-aadrn69x.js → hook-5zs3msf6.js} +6 -6
- package/dist/{hook-zxwje86c.js → hook-9k551xnj.js} +4 -4
- package/dist/{http-xzxk9mst.js → http-mhz9vw1f.js} +272 -103
- package/dist/index-4f2pvxae.js +37 -0
- package/dist/index-98gz7tmp.js +30 -0
- package/dist/{index-5rk6rfzr.js → index-fvzke5kx.js} +1 -1
- package/dist/index-k08z2cak.js +33 -0
- package/dist/{index-yqhz88yy.js → index-pxn30mse.js} +8 -8
- package/dist/{index-d34f6r87.js → index-q361cg2f.js} +1 -1
- package/dist/{index-9j4zwcht.js → index-rvr00sg7.js} +168 -675
- package/dist/{index-qeb82z37.js → index-vdygbq10.js} +1 -1
- package/dist/{keepalive-w4aakbyk.js → keepalive-w56f32cg.js} +4 -4
- package/dist/lead-enq35nqp.js +70 -0
- package/dist/{maintenance-hbptpk6p.js → maintenance-7mdgxcea.js} +1 -1
- package/dist/{oauth-refresh-sweep-217semrv.js → oauth-refresh-sweep-29txy9vk.js} +3 -3
- package/dist/{onboard-vz2s5df3.js → onboard-kpsrkarj.js} +5 -5
- package/dist/{opencode-adapter-gtfd7d7v.js → opencode-adapter-j25vm3rr.js} +5 -5
- package/dist/{otel-impl-aefave37.js → otel-impl-6kkct7a8.js} +2 -2
- package/dist/{pi-mono-adapter-f8h5yseh.js → pi-mono-adapter-exhkzhn2.js} +117 -23
- package/dist/{pricing-refresh-m1yhh9ya.js → pricing-refresh-n2x7jh6k.js} +3 -3
- package/dist/{rbac-roles-rrw8twdz.js → rbac-roles-81ypx6es.js} +1 -1
- package/dist/{rbac-roles-svj72cdf.js → rbac-roles-b5htkjby.js} +2 -2
- package/dist/{render-v2-amwbnfxh.js → render-v2-qn6jmpk4.js} +3 -3
- package/dist/{resume-9cd6wf6z.js → resume-wd30wx23.js} +7 -7
- package/dist/{runtime-fp4vrx7m.js → runtime-4hsg7h60.js} +1 -1
- package/dist/{session-access-21t6yjyg.js → session-access-5qvfevhk.js} +4 -4
- package/dist/{session-source-backfill-pxbzcsc6.js → session-source-backfill-n1czavbr.js} +3 -3
- package/dist/{setup-4592tqz4.js → setup-dnb56qy5.js} +3 -3
- package/dist/{virtual-modules-gzfnpmnz.js → virtual-modules-76xxv9fs.js} +2 -2
- package/dist/{work-objects-t9tcf174.js → work-objects-4n21tfkm.js} +21 -20
- package/dist/{worker-follow-up-q32jh4yk.js → worker-follow-up-77hvzxww.js} +18 -17
- package/dist/worker-gg1576j3.js +70 -0
- package/dist/{x-b6wxntdt.js → x-vmmye1kb.js} +2 -2
- package/openapi.json +189 -32
- package/package.json +8 -7
- package/src/be/db/script-runs.ts +23 -0
- package/src/be/db/session-summaries.ts +8 -2
- package/src/be/db/session-tree.ts +174 -61
- package/src/be/db/session-visibility.ts +5 -4
- package/src/be/db/tasks/read.ts +122 -3
- package/src/be/db-client.ts +8 -5
- package/src/be/db.ts +23 -8
- package/src/be/memory/providers/sqlite-store.ts +49 -12
- package/src/be/migrations/259_session_summaries_open_tasks.sql +111 -0
- package/src/be/migrations/260_runtime_pool_cache.sql +20 -0
- package/src/be/migrations/262_session_visibility_indexes.sql +18 -0
- package/src/be/migrations/263_task_list_filter_index.sql +11 -0
- package/src/be/migrations/264_slack_thread_cover_index.sql +9 -0
- package/src/be/migrations/266_script_runs_source_task.sql +11 -0
- package/src/be/model-validation.ts +5 -1
- package/src/be/pricing-normalize.ts +7 -2
- package/src/be/runtime-pools/cache-cleanup.ts +109 -0
- package/src/be/runtime-pools/db.ts +65 -6
- package/src/be/runtime-pools/remote-controller.ts +5 -0
- package/src/be/runtime-pools/supervisor.ts +33 -2
- package/src/be/scripts/typecheck.ts +23 -0
- package/src/be/seed/schedules-seeder.ts +135 -9
- package/src/be/seed/workflows-seeder.ts +65 -1
- package/src/be/seed-pricing.ts +23 -0
- package/src/be/seed-scripts/catalog/task-failure-audit.ts +5 -1
- package/src/be/steering.ts +50 -3
- package/src/be/swarm-config-guard.ts +1 -0
- package/src/commands/controller.ts +4 -0
- package/src/commands/entrypoint-api-readiness.ts +74 -0
- package/src/commands/provider-credentials.ts +29 -2
- package/src/commands/runner.ts +86 -5
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +27 -1
- package/src/extensions/dispatcher.ts +4 -0
- package/src/http/agents.ts +1 -0
- package/src/http/index.ts +1 -1
- package/src/http/list-total-cache.ts +14 -7
- package/src/http/mcp-bridge.ts +4 -0
- package/src/http/memory.ts +38 -9
- package/src/http/script-runs.ts +174 -5
- package/src/http/status.ts +10 -2
- package/src/http/tasks.ts +4 -2
- package/src/integrations/chat-sdk/inbound.ts +15 -5
- package/src/integrations/chat-sdk/steering.ts +3 -1
- package/src/kv-reserved-namespaces.ts +2 -0
- package/src/prompts/base-prompt.ts +4 -1
- package/src/prompts/session-templates.ts +26 -0
- package/src/providers/acp-adapter.ts +190 -26
- package/src/providers/acp-targets.ts +306 -6
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/codex-adapter.ts +9 -44
- package/src/providers/codex-oauth/flow.ts +24 -3
- package/src/providers/codex-oauth/storage.ts +56 -17
- package/src/providers/codex-oauth/subscription.ts +67 -0
- package/src/providers/fx-adapter.ts +211 -0
- package/src/providers/index.ts +5 -1
- package/src/providers/mcp-loopback-proxy.ts +94 -0
- package/src/providers/pi-mono-adapter.ts +98 -13
- package/src/providers/pricing-sources.md +8 -0
- package/src/providers/reasoning-effort.ts +17 -1
- package/src/providers/types.ts +2 -1
- package/src/runtime-providers/controller-protocol.ts +14 -1
- package/src/runtime-providers/controller.ts +5 -0
- package/src/runtime-providers/docker.ts +108 -23
- package/src/runtime-providers/types.ts +16 -0
- package/src/scheduler/scheduler.ts +36 -3
- package/src/script-workflows/workflow-ctx.ts +8 -0
- package/src/scripts-runtime/sdk-allowlist.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +27 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +33 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -0
- package/src/server-user.ts +1 -0
- package/src/server.ts +7 -0
- package/src/slack/assistant.ts +17 -1
- package/src/slack/commands.ts +5 -1
- package/src/slack/handlers.ts +53 -5
- package/src/slack/left-threads.ts +88 -0
- package/src/slack/steering.ts +3 -0
- package/src/slack/thread-buffer.ts +40 -16
- package/src/tasks/follow-up-redelegation-guard.ts +155 -0
- package/src/tests/acp-adapter.test.ts +79 -0
- package/src/tests/base-prompt.test.ts +12 -0
- package/src/tests/chat-sdk-inbound.test.ts +30 -0
- package/src/tests/chatgpt-subscription-model-groups.test.ts +62 -0
- package/src/tests/chatgpt-subscription-pi.test.ts +170 -0
- package/src/tests/chatgpt-subscription-session-bench.test.ts +198 -0
- package/src/tests/claude-artifacts-read-script.test.ts +209 -0
- package/src/tests/codex-oauth-credential-info.test.ts +40 -0
- package/src/tests/codex-oauth-refresh-egress.test.ts +194 -0
- package/src/tests/context-window.test.ts +7 -0
- package/src/tests/db-client.test.ts +21 -0
- package/src/tests/db-task-read-contract.test.ts +8 -2
- package/src/tests/db-task-write-contract.test.ts +5 -1
- package/src/tests/entrypoint-api-readiness.test.ts +416 -210
- package/src/tests/explicit-model-validation.test.ts +113 -8
- package/src/tests/extensions-run-context.test.ts +11 -0
- package/src/tests/extensions-steering.test.ts +353 -0
- package/src/tests/extensions-validate.test.ts +5 -0
- package/src/tests/fixtures/extensions/steering-policy/hooks.ts +39 -0
- package/src/tests/fixtures/extensions/steering-policy/manifest.json +7 -0
- package/src/tests/fixtures/fake-fx.ts +167 -0
- package/src/tests/fixtures/fx/acp-responses-recorded.json +157 -0
- package/src/tests/fixtures/fx/acp-updates-recorded.jsonl +15 -0
- package/src/tests/follow-up-redelivery-guard.test.ts +432 -202
- package/src/tests/fx-adapter.test.ts +771 -0
- package/src/tests/grok-adapter.test.ts +36 -0
- package/src/tests/list-total-cache.test.ts +27 -2
- package/src/tests/mcp-loopback-proxy.test.ts +193 -0
- package/src/tests/memory-fts-populate.test.ts +11 -9
- package/src/tests/memory-retrieval-purge.test.ts +80 -0
- package/src/tests/migration-260-runtime-pool-cache.test.ts +118 -0
- package/src/tests/model-tier-resolution.test.ts +3 -3
- package/src/tests/pricing-refresh.test.ts +5 -5
- package/src/tests/prompt-template-session.test.ts +5 -3
- package/src/tests/provider-registration.test.ts +2 -1
- package/src/tests/query-audit-plans.test.ts +30 -2
- package/src/tests/runtime-cache-cleanup.test.ts +367 -0
- package/src/tests/runtime-e2b-pools.test.ts +41 -0
- package/src/tests/runtime-pools-db.test.ts +98 -0
- package/src/tests/runtime-pools-http.test.ts +29 -0
- package/src/tests/runtime-providers-docker.test.ts +253 -0
- package/src/tests/runtime-remote-controller.test.ts +66 -2
- package/src/tests/runtime-supervisor.test.ts +66 -2
- package/src/tests/script-connections.test.ts +13 -0
- package/src/tests/script-runs-http.test.ts +684 -2
- package/src/tests/seed-model-profiles.test.ts +2 -2
- package/src/tests/seed-schedules.test.ts +138 -0
- package/src/tests/seed-scripts.test.ts +26 -0
- package/src/tests/session-cost-recompute-unit.test.ts +39 -0
- package/src/tests/session-costs-golden.test.ts +26 -0
- package/src/tests/session-summaries-plans.test.ts +120 -0
- package/src/tests/session-summaries.test.ts +72 -12
- package/src/tests/sessions-tree.test.ts +11 -3
- package/src/tests/slack-leave-thread.test.ts +571 -0
- package/src/tests/slack-render-v2-query-plans.test.ts +24 -2
- package/src/tests/status.test.ts +11 -0
- package/src/tests/tasks-readable-row.test.ts +155 -0
- package/src/tests/tool-annotations.test.ts +2 -1
- package/src/tests/workflow-engine-v2.test.ts +42 -0
- package/src/tests/workflow-script-principal.test.ts +207 -7
- package/src/tools/send-task.ts +35 -47
- package/src/tools/slack-leave-thread.ts +104 -0
- package/src/tools/steer-task.ts +3 -2
- package/src/tools/task-dedup.ts +45 -21
- package/src/tools/tool-config.ts +2 -1
- package/src/types.ts +57 -0
- package/src/utils/codex-auth-failure.ts +30 -0
- package/src/utils/context-window.ts +4 -1
- package/src/utils/credentials.ts +7 -0
- package/src/utils/fx-models.ts +43 -0
- package/src/workflows/cooldown.ts +3 -2
- package/src/workflows/engine.ts +24 -9
- package/templates/schedules/dreaming-daily/config.json +1 -1
- package/templates/schedules/dreaming-daily/content.md +6 -14
- package/templates/skills/composio-google-docs/content.md +10 -0
- package/templates/skills/script-workflows/content.md +19 -1
- package/templates/skills/swarm-docs/content.md +2 -0
- package/templates/skills/swarm-scripts/SKILL.md +2 -0
- package/templates/skills/swarm-scripts/content.md +2 -0
- package/templates/workflows/dreaming/content.md +5 -1
- package/dist/acp-adapter-96dc64m2.js +0 -15
- package/dist/cli-dznrgaep.js +0 -30
- package/dist/cli-w3hcrxht.js +0 -6985
- package/dist/handlers-jg7v74ty.js +0 -31
- package/dist/index-8c1zbz59.js +0 -29
- package/dist/index-8k8tmfxd.js +0 -32
- package/dist/index-hq617xdj.js +0 -36
- package/dist/lead-567kw7x3.js +0 -68
- package/dist/worker-fjdqra6q.js +0 -68
|
@@ -30,7 +30,11 @@ const REASON_PATTERNS: any[] = [
|
|
|
30
30
|
{ key: "context-window", re: /context (window|limit|saturat)|peakcontext|compact/i },
|
|
31
31
|
{ key: "reboot-sweep", re: /reboot sweep/i },
|
|
32
32
|
{ key: "not-found", re: /not found|404|missing|no such/i },
|
|
33
|
-
{
|
|
33
|
+
{
|
|
34
|
+
key: "output-limit",
|
|
35
|
+
re: /\bmax_(?:output_)?tokens\b|\b(?:maximum|max) output (?:length|tokens)\b|\boutput (?:token|length) limit\b/i,
|
|
36
|
+
},
|
|
37
|
+
{ key: "auth/credentials", re: /unauthorized|401|403|credential|\btoken\b|forbidden/i },
|
|
34
38
|
{ key: "ci/checks-failed", re: /\bci\b|check.?s? fail|lint|tsc|test.?s? fail/i },
|
|
35
39
|
{ key: "network", re: /network|econn|fetch failed|socket|dns|502|503|504/i },
|
|
36
40
|
{ key: "cancelled", re: /cancel|aborted/i },
|
package/src/be/steering.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { TaskSteerEvent } from "../extensions/contract";
|
|
1
3
|
import {
|
|
2
4
|
type Agent,
|
|
3
5
|
type AgentTask,
|
|
@@ -37,6 +39,20 @@ export class SteeringRequestError extends Error {
|
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
export class SteeringBlockedError extends SteeringRequestError {
|
|
43
|
+
constructor(
|
|
44
|
+
public readonly reason: string,
|
|
45
|
+
public readonly extension: { id: string; name: string },
|
|
46
|
+
) {
|
|
47
|
+
super(`Steering blocked by extension ${extension.name}: ${reason}`, 403);
|
|
48
|
+
this.name = "SteeringBlockedError";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const steeringModifySchema = z.strictObject({
|
|
53
|
+
message: z.string().refine((message) => message.trim().length > 0, "Message must not be empty"),
|
|
54
|
+
});
|
|
55
|
+
|
|
40
56
|
/** Server-side entry point for the global steering kill switch. */
|
|
41
57
|
export function isSteeringEnabled(): boolean {
|
|
42
58
|
return readSteeringEnabled();
|
|
@@ -51,6 +67,8 @@ export interface RequestSteeringArgs {
|
|
|
51
67
|
createdByKind?: SteeringMessage["createdByKind"];
|
|
52
68
|
createdByUserId?: string;
|
|
53
69
|
createdByAgentId?: string;
|
|
70
|
+
messageTimestamps?: string[];
|
|
71
|
+
slack?: TaskSteerEvent["slack"];
|
|
54
72
|
}
|
|
55
73
|
|
|
56
74
|
async function providerForTask(task: AgentTask): Promise<ProviderName> {
|
|
@@ -291,7 +309,36 @@ export async function requestSteering(args: RequestSteeringArgs): Promise<SteerR
|
|
|
291
309
|
|
|
292
310
|
const requestedMode = args.mode ?? "queue";
|
|
293
311
|
const onUnsupported = args.onUnsupported ?? "degrade";
|
|
294
|
-
|
|
312
|
+
// The dispatcher loads task/workflow assets; keep it off the HTTP boot import cycle.
|
|
313
|
+
const { dispatchPre, extensionIdForAgent } = await import("../extensions/dispatcher");
|
|
314
|
+
const preSteer = await dispatchPre(
|
|
315
|
+
"pre.task.steer",
|
|
316
|
+
{
|
|
317
|
+
task,
|
|
318
|
+
message: args.message,
|
|
319
|
+
mode: requestedMode,
|
|
320
|
+
source: args.source ?? "api",
|
|
321
|
+
sender: {
|
|
322
|
+
kind: args.createdByKind ?? "system",
|
|
323
|
+
userId: args.createdByUserId,
|
|
324
|
+
agentId: args.createdByAgentId,
|
|
325
|
+
},
|
|
326
|
+
messageTimestamps: args.messageTimestamps,
|
|
327
|
+
slack: args.slack,
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
skipExtensionId: extensionIdForAgent(args.createdByAgentId),
|
|
331
|
+
validateModify: (data) => steeringModifySchema.safeParse(data),
|
|
332
|
+
},
|
|
333
|
+
);
|
|
334
|
+
if (preSteer.action === "block") {
|
|
335
|
+
throw new SteeringBlockedError(preSteer.reason, preSteer.extension);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// A hook can outlive the running session. Decide delivery from the current task.
|
|
339
|
+
const currentTask = await getTaskById(args.taskId);
|
|
340
|
+
if (!currentTask) throw new SteeringRequestError("Task not found", 404);
|
|
341
|
+
const provider = await providerForTask(currentTask);
|
|
295
342
|
const supportedModes = PROVIDER_STEER_CAPABILITIES[provider];
|
|
296
343
|
|
|
297
344
|
if (onUnsupported === "fail" && !supportedModes.includes(requestedMode)) {
|
|
@@ -302,12 +349,12 @@ export async function requestSteering(args: RequestSteeringArgs): Promise<SteerR
|
|
|
302
349
|
);
|
|
303
350
|
}
|
|
304
351
|
|
|
305
|
-
const activeTask =
|
|
352
|
+
const activeTask = currentTask.status === "paused" ? await resumeTask(task.id) : currentTask;
|
|
306
353
|
if (!activeTask) {
|
|
307
354
|
throw new SteeringRequestError("Failed to resume paused task", 500);
|
|
308
355
|
}
|
|
309
356
|
|
|
310
|
-
const body = scrubSecrets(args.message);
|
|
357
|
+
const body = scrubSecrets(preSteer.action === "modify" ? preSteer.data.message : args.message);
|
|
311
358
|
// A task whose session hasn't started yet can still accept queued steering:
|
|
312
359
|
// the row stays `pending` and the worker delivers it once the session is
|
|
313
360
|
// live (the dispatch poll covers every active task). Interrupting a session
|
|
@@ -508,6 +508,7 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
|
|
|
508
508
|
"ADDITIVE_SLACK",
|
|
509
509
|
"SLACK_THREAD_FOLLOWUP_REQUIRE_MENTION",
|
|
510
510
|
"SLACK_THREAD_WAKE_ON_ANY_MESSAGE",
|
|
511
|
+
"SLACK_LEAVE_THREAD_DISABLE",
|
|
511
512
|
"RBAC_ENABLED",
|
|
512
513
|
"SEED_AUTOMATIONS_ENABLED",
|
|
513
514
|
"RBAC_AUDIT_DISABLED",
|
|
@@ -15,6 +15,10 @@ async function executeCommand(
|
|
|
15
15
|
command: ControllerCommand,
|
|
16
16
|
): Promise<unknown> {
|
|
17
17
|
switch (command.op) {
|
|
18
|
+
case "release-cache":
|
|
19
|
+
if (!controller.releaseCache) throw new Error("Controller does not support cache cleanup");
|
|
20
|
+
await controller.releaseCache(command.payload);
|
|
21
|
+
return {};
|
|
18
22
|
case "provision":
|
|
19
23
|
return await controller.provision(command.payload);
|
|
20
24
|
case "terminate":
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** Worker boot step; deliberately standalone so both worker images can run it before setup. */
|
|
2
|
+
export interface ApiReadinessDependencies {
|
|
3
|
+
fetch: (url: string, init: RequestInit) => Promise<Response>;
|
|
4
|
+
now: () => number;
|
|
5
|
+
sleep: (ms: number) => Promise<void>;
|
|
6
|
+
log: (message: string) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const defaults: ApiReadinessDependencies = {
|
|
10
|
+
fetch: (url, init) => fetch(url, init),
|
|
11
|
+
now: () => performance.now(),
|
|
12
|
+
sleep: (ms) => Bun.sleep(ms),
|
|
13
|
+
log: (message) => console.log(message),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** Poll the unauthenticated health endpoint before any provider reads configuration. */
|
|
17
|
+
export async function waitForApiReady(
|
|
18
|
+
baseUrl: string,
|
|
19
|
+
timeoutValue = "90",
|
|
20
|
+
dependencies: Partial<ApiReadinessDependencies> = {},
|
|
21
|
+
): Promise<boolean> {
|
|
22
|
+
const { fetch: probe, now, sleep, log } = { ...defaults, ...dependencies };
|
|
23
|
+
const raw = timeoutValue || "90";
|
|
24
|
+
const seconds = Number(raw);
|
|
25
|
+
if (!/^\d+$/.test(raw) || !Number.isSafeInteger(seconds) || seconds <= 0) {
|
|
26
|
+
log(
|
|
27
|
+
`[entrypoint] FATAL: WORKER_API_READY_TIMEOUT_SECONDS must be a positive integer, got '${raw}'; exiting.`,
|
|
28
|
+
);
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const url = `${baseUrl.replace(/\/$/, "")}/health`;
|
|
33
|
+
const deadline = now() + seconds * 1000;
|
|
34
|
+
log(`[entrypoint] Waiting for API readiness at ${url} (timeout ${raw}s)...`);
|
|
35
|
+
while (true) {
|
|
36
|
+
const controller = new AbortController();
|
|
37
|
+
const timer = setTimeout(
|
|
38
|
+
() => controller.abort(),
|
|
39
|
+
Math.min(3000, Math.max(1, deadline - now())),
|
|
40
|
+
);
|
|
41
|
+
try {
|
|
42
|
+
const response = await probe(url, { redirect: "manual", signal: controller.signal });
|
|
43
|
+
// curl -o /dev/null waited for the whole response, without retaining its body.
|
|
44
|
+
if (response.body) {
|
|
45
|
+
for await (const _chunk of response.body) {
|
|
46
|
+
// Discard health output, including error bodies, within the request timeout.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Match curl -f without -L: redirects are successful and are not followed.
|
|
50
|
+
if (response.status > 0 && response.status < 400 && now() <= deadline) {
|
|
51
|
+
log(`[entrypoint] API ready at ${url}`);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
// The API can still be booting; retry connection, HTTP and timeout failures alike.
|
|
56
|
+
} finally {
|
|
57
|
+
clearTimeout(timer);
|
|
58
|
+
}
|
|
59
|
+
if (now() >= deadline) {
|
|
60
|
+
log(`[entrypoint] FATAL: API readiness timed out after ${raw}s waiting for ${url}; exiting.`);
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
await sleep(Math.min(1000, deadline - now()));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (import.meta.main) {
|
|
68
|
+
process.exitCode = (await waitForApiReady(
|
|
69
|
+
Bun.argv[2] ?? "http://host.docker.internal:3013",
|
|
70
|
+
Bun.argv[3],
|
|
71
|
+
))
|
|
72
|
+
? 0
|
|
73
|
+
: 1;
|
|
74
|
+
}
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import {
|
|
22
22
|
openAICompatibleKeyVars,
|
|
23
|
+
openAICompatibleProvider,
|
|
23
24
|
openAICompatibleProviders,
|
|
24
25
|
providerBaseUrl,
|
|
25
26
|
providerKeyFromEnv,
|
|
@@ -34,6 +35,7 @@ import { hasCodexOAuthPoolSlots } from "../providers/codex-oauth/env-keys";
|
|
|
34
35
|
import { checkCursorCredentials } from "../providers/cursor-adapter";
|
|
35
36
|
import { checkDevinCredentials } from "../providers/devin-adapter";
|
|
36
37
|
import { checkDshCredentials } from "../providers/dsh-adapter";
|
|
38
|
+
import { checkFxCredentials } from "../providers/fx-adapter";
|
|
37
39
|
import { checkGrokCredentials } from "../providers/grok-adapter";
|
|
38
40
|
import { checkOpencodeCredentials } from "../providers/opencode-adapter";
|
|
39
41
|
import type { CredCheckOptions, CredStatus } from "../providers/types";
|
|
@@ -85,7 +87,8 @@ export type SupportedProvider =
|
|
|
85
87
|
| "dsh"
|
|
86
88
|
| "cursor"
|
|
87
89
|
| "amp"
|
|
88
|
-
| "grok"
|
|
90
|
+
| "grok"
|
|
91
|
+
| "fx";
|
|
89
92
|
|
|
90
93
|
/**
|
|
91
94
|
* True when the pi harness authenticates against Bedrock rather than a provider
|
|
@@ -158,6 +161,7 @@ export const REQUIRED_CRED_VARS_BY_PROVIDER: Record<SupportedProvider, readonly
|
|
|
158
161
|
amp: ["AMP_API_KEY"],
|
|
159
162
|
cursor: ["CURSOR_API_KEY"],
|
|
160
163
|
grok: ["XAI_API_KEY", "OPENROUTER_API_KEY"],
|
|
164
|
+
fx: ["OPENROUTER_API_KEY", "OPENAI_API_KEY", "AI_GATEWAY_API_KEY"],
|
|
161
165
|
};
|
|
162
166
|
|
|
163
167
|
type CredentialChecker = (
|
|
@@ -171,6 +175,7 @@ export const CREDENTIAL_PROVIDER_CHECKERS: Record<SupportedProvider, CredentialC
|
|
|
171
175
|
amp: (env) => checkAmpCredentials(env),
|
|
172
176
|
cursor: (env) => checkCursorCredentials(env),
|
|
173
177
|
grok: (env) => checkGrokCredentials(env),
|
|
178
|
+
fx: (env) => checkFxCredentials(env),
|
|
174
179
|
claude: (env) => checkClaudeCredentials(env),
|
|
175
180
|
"claude-managed": (env) => checkClaudeManagedCredentials(env),
|
|
176
181
|
codex: (env, opts) => checkCodexCredentials(env, opts),
|
|
@@ -383,6 +388,7 @@ function parseCodexOAuthAccess(blob: string | undefined): string | null {
|
|
|
383
388
|
* | `devin` | `DEVIN_API_KEY` (+ `DEVIN_API_BASE_URL` override) | `${baseUrl}/v3/self` |
|
|
384
389
|
* | `dsh` | `DEEPSEEK_API_KEY` → `OPENROUTER_API_KEY` | DeepSeek `/models`, or OpenRouter `/key` |
|
|
385
390
|
* | `amp` | `AMP_API_KEY` | `amp usage` (credit balance, no inference; 5s timeout) |
|
|
391
|
+
* | `fx` | `OPENROUTER_API_KEY` → `OPENAI_API_KEY` → `AI_GATEWAY_API_KEY` | OpenRouter `/key`, OpenAI `/v1/models`, or AI Gateway `/v1/models` |
|
|
386
392
|
*
|
|
387
393
|
* Returns `{ok: true, latency_ms}` on 2xx, `{ok: false, error, latency_ms}`
|
|
388
394
|
* otherwise. Errors are scrubbed via `scrubSecrets` before being returned.
|
|
@@ -639,12 +645,33 @@ export async function validateProviderCredentials(
|
|
|
639
645
|
latency_ms: Date.now() - startedAt,
|
|
640
646
|
};
|
|
641
647
|
}
|
|
648
|
+
case "fx": {
|
|
649
|
+
// Same keys as `checkFxCredentials`, probed in route-table order.
|
|
650
|
+
const openRouterKey = env.OPENROUTER_API_KEY?.trim();
|
|
651
|
+
if (openRouterKey) {
|
|
652
|
+
return checkEachKey("OPENROUTER_API_KEY", openRouterKey, checkOpenRouter);
|
|
653
|
+
}
|
|
654
|
+
const openAiKey = env.OPENAI_API_KEY?.trim();
|
|
655
|
+
if (openAiKey) return checkEachKey("OPENAI_API_KEY", openAiKey, checkOpenAiApiKey);
|
|
656
|
+
const gatewayKey = env.AI_GATEWAY_API_KEY?.trim();
|
|
657
|
+
const gateway = openAICompatibleProvider("vercel");
|
|
658
|
+
if (gatewayKey && gateway) {
|
|
659
|
+
return checkEachKey("AI_GATEWAY_API_KEY", gatewayKey, (member) =>
|
|
660
|
+
checkOpenAICompatibleProvider(gateway, member),
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
return {
|
|
664
|
+
ok: false,
|
|
665
|
+
error: "Set OPENROUTER_API_KEY, OPENAI_API_KEY or AI_GATEWAY_API_KEY for fx.",
|
|
666
|
+
latency_ms: Date.now() - startedAt,
|
|
667
|
+
};
|
|
668
|
+
}
|
|
642
669
|
case "acp":
|
|
643
670
|
return presenceCheckOk();
|
|
644
671
|
default:
|
|
645
672
|
return {
|
|
646
673
|
ok: false,
|
|
647
|
-
error: `Unknown provider "${provider}". Supported: claude, claude-managed, codex, devin, opencode, pi, acp, dsh, cursor, amp, grok.`,
|
|
674
|
+
error: `Unknown provider "${provider}". Supported: claude, claude-managed, codex, devin, opencode, pi, acp, dsh, cursor, amp, grok, fx.`,
|
|
648
675
|
latency_ms: Date.now() - startedAt,
|
|
649
676
|
};
|
|
650
677
|
}
|
package/src/commands/runner.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, statSync } from "node:fs";
|
|
2
2
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { isChatgptSubscriptionModel } from "@desplega/model-catalog";
|
|
3
4
|
import { deriveDefaultRoute } from "@desplega/model-routing";
|
|
4
5
|
import type { TemplateResponse } from "../../templates/schema.ts";
|
|
5
6
|
import {
|
|
@@ -1381,6 +1382,7 @@ const SWARM_TOOL_LABELS: Record<string, string | null> = {
|
|
|
1381
1382
|
"slack-list-channels": "💬 Listing Slack channels",
|
|
1382
1383
|
"slack-download-file": "📥 Downloading from Slack",
|
|
1383
1384
|
"slack-upload-file": "📤 Uploading to Slack",
|
|
1385
|
+
"slack-leave-thread": "💬 Leaving Slack thread",
|
|
1384
1386
|
// Tracker
|
|
1385
1387
|
"tracker-status": "📊 Checking tracker status",
|
|
1386
1388
|
"tracker-sync-status": "📊 Syncing tracker status",
|
|
@@ -2067,6 +2069,7 @@ export interface CodexOAuthCredentialInfo {
|
|
|
2067
2069
|
export async function resolveCodexOAuthCredentialInfo(
|
|
2068
2070
|
apiUrl?: string,
|
|
2069
2071
|
apiKey?: string,
|
|
2072
|
+
opts: { poolOnly?: boolean } = {},
|
|
2070
2073
|
): Promise<CodexOAuthCredentialInfo | null> {
|
|
2071
2074
|
// Pool path: enumerate slots from the config store, pick one with rate-limit
|
|
2072
2075
|
// awareness, materialise auth.json for the selected slot.
|
|
@@ -2114,9 +2117,12 @@ export async function resolveCodexOAuthCredentialInfo(
|
|
|
2114
2117
|
// Pool slots are shared across concurrent tasks: never hand the
|
|
2115
2118
|
// spawned Codex CLI a refresh token it could rotate outside the
|
|
2116
2119
|
// `/api/oauth/refresh-locks` lock (see `credentialsToAuthJson`).
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
+
// pi gets its credential from the adapter instead.
|
|
2121
|
+
if (!opts.poolOnly) {
|
|
2122
|
+
await materializeCodexAuthJson(selectedSlot, slotEntry.creds, {
|
|
2123
|
+
includeRefreshToken: false,
|
|
2124
|
+
});
|
|
2125
|
+
}
|
|
2120
2126
|
const authJson = credentialsToAuthJson(slotEntry.creds, {
|
|
2121
2127
|
includeRefreshToken: false,
|
|
2122
2128
|
});
|
|
@@ -2135,6 +2141,9 @@ export async function resolveCodexOAuthCredentialInfo(
|
|
|
2135
2141
|
}
|
|
2136
2142
|
}
|
|
2137
2143
|
|
|
2144
|
+
// pi subscription sessions run on a pool slot or not at all.
|
|
2145
|
+
if (opts.poolOnly) return null;
|
|
2146
|
+
|
|
2138
2147
|
// Fallback: read existing auth.json (single-credential or pre-pool deploy).
|
|
2139
2148
|
// NOT pool-backed — `authJsonToCredentialSelection`'s default `slot = 0` is
|
|
2140
2149
|
// bookkeeping only, not a real `codex_oauth_0` config-store entry. Callers
|
|
@@ -2284,6 +2293,40 @@ export async function reportKeyCompletionOutcome(opts: {
|
|
|
2284
2293
|
}
|
|
2285
2294
|
}
|
|
2286
2295
|
|
|
2296
|
+
/**
|
|
2297
|
+
* `adapter.createSession`, counting a Codex pool auth failure toward the bench
|
|
2298
|
+
* before rethrowing. A session that fails to start never reaches the
|
|
2299
|
+
* completion-time report, so without this a slot whose refresh is rejected at
|
|
2300
|
+
* startup (pi on the ChatGPT subscription, codex's in-process revalidation)
|
|
2301
|
+
* keeps being picked. Transient reasons are not counted
|
|
2302
|
+
* (`isCodexAuthFailureReason`).
|
|
2303
|
+
*/
|
|
2304
|
+
export async function createSessionReportingAuthFailure(
|
|
2305
|
+
adapter: { createSession(config: ProviderSessionConfig): Promise<ProviderSession> },
|
|
2306
|
+
config: ProviderSessionConfig,
|
|
2307
|
+
report:
|
|
2308
|
+
| {
|
|
2309
|
+
apiUrl: string;
|
|
2310
|
+
apiKey: string;
|
|
2311
|
+
credential: { keyType: string; keySuffix: string; keyIndex: number };
|
|
2312
|
+
taskId: string;
|
|
2313
|
+
}
|
|
2314
|
+
| undefined,
|
|
2315
|
+
): Promise<ProviderSession> {
|
|
2316
|
+
try {
|
|
2317
|
+
return await adapter.createSession(config);
|
|
2318
|
+
} catch (err) {
|
|
2319
|
+
if (report) {
|
|
2320
|
+
await reportKeyCompletionOutcome({
|
|
2321
|
+
...report,
|
|
2322
|
+
exitCode: 1,
|
|
2323
|
+
failureReason: err instanceof Error ? err.message : String(err),
|
|
2324
|
+
});
|
|
2325
|
+
}
|
|
2326
|
+
throw err;
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2287
2330
|
/**
|
|
2288
2331
|
* Supersede a task via the API (for graceful shutdown / context-limit /
|
|
2289
2332
|
* operator-triggered). Returns `{ ok: true, resumeTaskId }` on success.
|
|
@@ -4164,7 +4207,11 @@ export function implicitCloseActiveToolSpans(
|
|
|
4164
4207
|
return closed;
|
|
4165
4208
|
}
|
|
4166
4209
|
|
|
4167
|
-
|
|
4210
|
+
/**
|
|
4211
|
+
* Start a provider session for a task. The new-task and resumed-task paths of
|
|
4212
|
+
* the poll loop both start here; exported so tests can drive that boundary.
|
|
4213
|
+
*/
|
|
4214
|
+
export async function spawnProviderProcess(
|
|
4168
4215
|
adapter: Awaited<ReturnType<typeof createProviderAdapter>>,
|
|
4169
4216
|
opts: {
|
|
4170
4217
|
prompt: string;
|
|
@@ -4366,6 +4413,25 @@ async function spawnProviderProcess(
|
|
|
4366
4413
|
realTaskId,
|
|
4367
4414
|
).catch(() => {});
|
|
4368
4415
|
}
|
|
4416
|
+
} else if (adapter.name === "pi" && isChatgptSubscriptionModel(model)) {
|
|
4417
|
+
// An `openai-codex/<id>` model runs on the same pool, with the same slot
|
|
4418
|
+
// pick and usage bookkeeping. The adapter revalidates `codexSlot` through
|
|
4419
|
+
// the refresh lock and hands the harness the access token only
|
|
4420
|
+
// (`loadChatgptSubscriptionCredential`); no slot fails the session there.
|
|
4421
|
+
const oauthInfo = await resolveCodexOAuthCredentialInfo(opts.apiUrl, opts.apiKey, {
|
|
4422
|
+
poolOnly: true,
|
|
4423
|
+
});
|
|
4424
|
+
oauthSelection = oauthInfo?.selection;
|
|
4425
|
+
oauthIsPoolBacked = oauthInfo?.isPoolBacked ?? false;
|
|
4426
|
+
if (oauthSelection && realTaskId) {
|
|
4427
|
+
reportKeyUsage(
|
|
4428
|
+
opts.apiUrl,
|
|
4429
|
+
opts.apiKey,
|
|
4430
|
+
oauthSelection.keyType,
|
|
4431
|
+
oauthSelection,
|
|
4432
|
+
realTaskId,
|
|
4433
|
+
).catch(() => {});
|
|
4434
|
+
}
|
|
4369
4435
|
}
|
|
4370
4436
|
|
|
4371
4437
|
// Prompt-path skills can resolve inside createSession, before the event
|
|
@@ -4422,7 +4488,22 @@ async function spawnProviderProcess(
|
|
|
4422
4488
|
withSpan(
|
|
4423
4489
|
"worker.session.create",
|
|
4424
4490
|
async (span) => {
|
|
4425
|
-
const createdSession = await
|
|
4491
|
+
const createdSession = await createSessionReportingAuthFailure(
|
|
4492
|
+
adapter,
|
|
4493
|
+
config,
|
|
4494
|
+
oauthSelection && oauthIsPoolBacked && realTaskId
|
|
4495
|
+
? {
|
|
4496
|
+
apiUrl: opts.apiUrl,
|
|
4497
|
+
apiKey: opts.apiKey,
|
|
4498
|
+
credential: {
|
|
4499
|
+
keyType: oauthSelection.keyType,
|
|
4500
|
+
keySuffix: oauthSelection.keySuffix,
|
|
4501
|
+
keyIndex: oauthSelection.index,
|
|
4502
|
+
},
|
|
4503
|
+
taskId: realTaskId,
|
|
4504
|
+
}
|
|
4505
|
+
: undefined,
|
|
4506
|
+
);
|
|
4426
4507
|
span.setAttribute("agentswarm.provider.session_id", createdSession.sessionId || "pending");
|
|
4427
4508
|
return createdSession;
|
|
4428
4509
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// Generated by scripts/bundle-extension-types.ts. Do not edit.
|
|
2
2
|
// biome-ignore-all lint/suspicious/noTemplateCurlyInString: Type declarations contain literal template placeholders.
|
|
3
3
|
export const EXTENSION_TYPE_DEFINITIONS =
|
|
4
|
-
'// biome-ignore-all lint/suspicious/noConfusingVoidType: Extension handlers may explicitly return no result.\ndeclare module "swarm-extension" {\n export type CreateTaskOptions = {\n key?: string | undefined;\n agentId?: string | null | undefined;\n creatorAgentId?: string | undefined;\n source?:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "bitbucket"\n | "linear"\n | "jira"\n | "mcp"\n | "api"\n | "ui"\n | "system"\n | "comb"\n | "chat"\n | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n taskType?: string | undefined;\n tags?: string[] | undefined;\n priority?: number | undefined;\n dependsOn?: string[] | undefined;\n offeredTo?: string | undefined;\n status?: "draft" | "backlog" | "unassigned" | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n overrideSlackContext?: boolean | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | "bitbucket" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n profile?: string | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | undefined;\n workflowRunStepId?: string | undefined;\n sourceTaskId?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n inheritParentOutputSchema?: boolean | undefined;\n inheritParentRequester?: boolean | undefined;\n inheritParentRoutingAffinity?: boolean | undefined;\n inheritParentFollowUpConfig?: boolean | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n requestedByUserId?: string | undefined;\n contextKey?: string | undefined;\n bypassTrackerContextDedup?: boolean | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n };\n\n export type AgentTask = {\n id: string;\n key: string;\n agentId: string | null;\n task: string;\n status:\n | "draft"\n | "backlog"\n | "unassigned"\n | "offered"\n | "reviewing"\n | "pending"\n | "in_progress"\n | "paused"\n | "completed"\n | "failed"\n | "cancelled"\n | "superseded";\n source:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "bitbucket"\n | "linear"\n | "jira"\n | "mcp"\n | "api"\n | "ui"\n | "system"\n | "comb"\n | "chat";\n tags: string[];\n priority: number;\n dependsOn: string[];\n createdAt: string;\n lastUpdatedAt: string;\n slackReplySent: boolean;\n wasPaused: boolean;\n creatorAgentId?: string | undefined;\n title?: string | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n poolWakeAt?: string | undefined;\n taskType?: string | undefined;\n offeredTo?: string | undefined;\n offeredAt?: string | undefined;\n acceptedAt?: string | undefined;\n rejectionReason?: string | undefined;\n finishedAt?: string | undefined;\n notifiedAt?: string | undefined;\n failureReason?: string | undefined;\n output?: string | undefined;\n progress?: string | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n slackProgressMessageTs?: string | undefined;\n slackTreeRootMessageTs?: string | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | "bitbucket" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n claudeSessionId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n resolvedModel?: string | undefined;\n modelSource?: string | undefined;\n modelAlias?: string | undefined;\n resolvedEffort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n profile?: string | undefined;\n resolvedProfile?: string | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | null | undefined;\n workflowRunStepId?: string | null | undefined;\n contextKey?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n deferredAt?: string | undefined;\n compactionCount?: number | undefined;\n peakContextPercent?: number | undefined;\n peakContextTokens?: number | undefined;\n contextWindowSize?: number | undefined;\n credentialKeySuffix?: string | undefined;\n credentialKeyType?: string | undefined;\n requestedByUserId?: string | undefined;\n swarmVersion?: string | undefined;\n provider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n providerMeta?: Record<string, unknown> | undefined;\n harnessVariant?: string | undefined;\n harnessVariantMeta?: Record<string, unknown> | undefined;\n totalCostUsd?: number | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n routingAffinityInvalid?: boolean | undefined;\n };\n\n export type ActiveSession = {\n id: string;\n agentId: string;\n taskId: string | null;\n triggerType: string;\n inboxMessageId: string | null;\n taskDescription: string | null;\n runnerSessionId: string | null;\n providerSessionId: string | null;\n startedAt: string;\n lastHeartbeatAt: string;\n runtimeInstanceId?: string | null | undefined;\n };\n\n export type RequestInfo = {\n sessionId: string | undefined;\n agentId: string | undefined;\n runtimeInstanceId: string | undefined;\n sourceTaskId: string | undefined;\n contextKey: string | undefined;\n callOrigin: "mcp" | "extension" | "script-sdk";\n };\n\n import type { SwarmSdk } from "swarm-sdk";\n import type { z } from "zod";\n export type Runtime = "api" | "worker";\n export interface ExtensionScriptAsset {\n name: string;\n file: string;\n description: string;\n intent?: string;\n }\n export interface ExtensionScheduleAsset {\n name: string;\n description?: string;\n script: string;\n cronExpression?: string;\n intervalMs?: number;\n timezone?: string;\n args?: Record<string, unknown>;\n }\n export interface ExtensionWorkflowAsset {\n file: string;\n }\n export interface ExtensionSkillAsset {\n dir: string;\n }\n export interface ExtensionManifest {\n $schema?: string;\n name: string;\n description: string;\n version: string;\n runtime: Runtime;\n assets: {\n hooks: string;\n scripts?: readonly ExtensionScriptAsset[];\n schedules?: readonly ExtensionScheduleAsset[];\n workflows?: readonly ExtensionWorkflowAsset[];\n skills?: readonly ExtensionSkillAsset[];\n };\n homepage?: string;\n author?: string;\n }\n export interface HooksModule {\n default: SwarmExtension;\n config?: z.ZodTypeAny;\n }\n export interface ExtensionState {\n get<T = unknown>(key: string): Promise<T | null>;\n set<T>(key: string, value: T): Promise<void>;\n incr(key: string, by?: number): Promise<number>;\n del(key: string): Promise<void>;\n }\n export interface ExtensionLogger {\n debug(message: string, data?: unknown): void;\n info(message: string, data?: unknown): void;\n warn(message: string, data?: unknown): void;\n error(message: string, data?: unknown): void;\n }\n type ConfigFor<M extends ExtensionManifest> = M extends {\n config: infer C extends z.ZodTypeAny;\n }\n ? z.infer<C>\n : Record<string, unknown>;\n export interface ApiCtx<Config = Record<string, unknown>> {\n swarm: SwarmSdk;\n state: ExtensionState;\n config: Config;\n log: ExtensionLogger;\n signal: AbortSignal;\n event: {\n name: keyof SwarmEventMap;\n at: string;\n extension: {\n id: string;\n version: number;\n };\n };\n }\n export interface WorkerCtx<Config = Record<string, unknown>>\n extends Omit<ApiCtx<Config>, "swarm"> {\n swarm: SwarmSdk;\n worker: {\n agentId: string;\n taskId: string;\n harness: string;\n };\n }\n export type CtxFor<M extends ExtensionManifest> = M["runtime"] extends "api"\n ? ApiCtx<ConfigFor<M>>\n : WorkerCtx<ConfigFor<M>>;\n export type PreResult<Modify> =\n | void\n | {\n action: "continue";\n }\n | {\n action: "modify";\n data: Modify;\n }\n | {\n action: "block";\n reason: string;\n };\n export type TaskCreateOrigin =\n | "rest"\n | "app"\n | "mcp"\n | "slack"\n | "schedule"\n | "workflow"\n | "webhook"\n | "followUp"\n | `extension:${string}`;\n export interface TaskCreateEvent {\n options: CreateTaskOptions;\n description: string;\n origin: TaskCreateOrigin;\n requestInfo?: RequestInfo;\n /** Slack ingress metadata; not persisted or writable through modify. */\n slack?: {\n trigger: "mention" | "thread-buffer";\n messages: {\n ts: string;\n userId: string;\n text: string;\n }[];\n };\n }\n /** A pre.task.create hook blocked a task before it was created. */\n export interface TaskBlockedEvent {\n /** The extension that blocked, or whose model/agent rewrite was rejected. */\n extension: {\n id: string;\n name: string;\n };\n /** The scrubbed block reason. */\n reason: string;\n origin: TaskCreateOrigin;\n source?: AgentTask["source"];\n requester: {\n userId?: string;\n agentId?: string;\n slackUserId?: string;\n };\n context?: {\n contextKey?: string;\n scheduleId?: string;\n workflowRunId?: string;\n workflowRunStepId?: string;\n parentTaskId?: string;\n vcsRepo?: string;\n vcsNumber?: number;\n slackChannelId?: string;\n slackThreadTs?: string;\n };\n /** The original task description, scrubbed and cut to 500 characters. */\n description: string;\n }\n export type TaskCreateModify = Partial<\n Pick<\n CreateTaskOptions,\n | "agentId"\n | "creatorAgentId"\n | "source"\n | "taskType"\n | "tags"\n | "priority"\n | "dependsOn"\n | "offeredTo"\n | "vcsProvider"\n | "vcsRepo"\n | "vcsEventType"\n | "vcsNumber"\n | "vcsCommentId"\n | "vcsAuthor"\n | "vcsUrl"\n | "vcsInstallationId"\n | "vcsNodeId"\n | "agentmailInboxId"\n | "agentmailMessageId"\n | "agentmailThreadId"\n | "mentionMessageId"\n | "mentionChannelId"\n | "dir"\n | "model"\n | "modelTier"\n | "effort"\n | "outputSchema"\n | "followUpConfig"\n | "bypassTrackerContextDedup"\n >\n > & {\n description?: string;\n };\n export interface TaskFollowUpEvent {\n completedTask: AgentTask;\n status: "completed" | "failed";\n output?: string;\n failureReason?: string;\n workerAgentId: string;\n leadAgentId: string;\n summary: string;\n }\n export type TaskFollowUpModify = Partial<\n Pick<CreateTaskOptions, "agentId" | "priority" | "followUpConfig">\n > & {\n description?: string;\n };\n export interface SlackRouteEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n botMentioned: boolean;\n threadContext?: {\n channelId: string;\n threadTs: string;\n };\n }\n export interface SlackRouteModify {\n target:\n | {\n kind: "agent";\n agentId: string;\n }\n | {\n kind: "lead";\n }\n | {\n kind: "broadcast";\n };\n }\n /** A Chat SDK message after its thread buffer flushed, before routing. */\n export interface ChatRouteEvent {\n /** Adapter name, such as `telegram` or `slack`. */\n adapter: string;\n channelId: string;\n /** The Chat SDK thread id, prefixed with the adapter name. */\n threadId: string;\n /** The first buffered sender. */\n userId: string;\n userName?: string;\n /** The buffered messages, joined. */\n text: string;\n /** True for an @mention and for a reply to one of the bot\'s messages. */\n botMentioned: boolean;\n isDirectMessage: boolean;\n /** Platform chat type, such as Telegram `private`, `group`, `supergroup` or `channel`. */\n chatType?: string;\n /** Set for a Telegram supergroup with topics. */\n isForum?: boolean;\n /** A buffered message replies to one of the bot\'s own messages. */\n replyToBot: boolean;\n /** Set when earlier swarm tasks exist in this thread. */\n threadContext?: {\n adapter: string;\n threadId: string;\n };\n }\n export interface ChatRouteModify {\n target:\n | {\n kind: "agent";\n agentId: string;\n }\n | {\n kind: "lead";\n }\n | {\n kind: "broadcast";\n }\n | {\n kind: "workflow";\n workflowId: string;\n };\n }\n export type HeartbeatClassification = "no-session" | "stale-session" | "fresh-stalled";\n export type HeartbeatAction = "supersede-resume" | "fail" | "record";\n export interface HeartbeatRemediateEvent {\n task: AgentTask;\n session?: ActiveSession;\n classification: HeartbeatClassification;\n proposedAction: HeartbeatAction;\n reason: string;\n taskAgeMs: number;\n sessionHeartbeatAgeMs?: number;\n }\n export interface HeartbeatRemediateModify {\n proposedAction: HeartbeatAction;\n }\n export interface ToolCallEvent {\n tool: string;\n args: unknown;\n requestInfo: RequestInfo;\n }\n export interface ToolCallModify {\n args: unknown;\n }\n export interface TaskEvent {\n task: AgentTask;\n }\n export interface TaskCompletedEvent extends TaskEvent {\n output: string;\n }\n export interface TaskFailedEvent extends TaskEvent {\n failureReason: string;\n }\n export interface TaskSupersededEvent extends TaskEvent {\n supersededBy: string;\n }\n export interface TaskProgressEvent extends TaskEvent {\n progress: string;\n }\n export interface SlackMessageEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n taskId?: string;\n }\n /** A Chat SDK message the swarm received or sent. */\n export interface ChatMessageEvent {\n adapter: string;\n channelId: string;\n threadId: string;\n /** The sender, for an inbound message. */\n userId?: string;\n text: string;\n direction: "inbound" | "outbound";\n taskId?: string;\n messageId?: string;\n }\n /**\n * A person answered an approval request. Fires for workflow and standalone\n * requests. Timeouts and cancellations do not emit it today.\n */\n export interface ApprovalResolvedEvent {\n requestId: string;\n status: "approved" | "rejected" | "timeout" | "cancelled";\n responses: Record<string, unknown> | null;\n /** Set when a workflow human-in-the-loop step asked. Absent for a standalone request. */\n workflowRunId?: string;\n workflowRunStepId?: string;\n /** The task whose agent asked, for a standalone request. */\n sourceTaskId?: string;\n }\n /** A task was refused because a daily spend budget is used up. */\n export interface TaskBudgetRefusedEvent extends TaskEvent {\n /** The agent the task was refused for. */\n agentId: string;\n /** Which budget refused it. The matching spend and budget fields are set. */\n cause: "agent" | "global" | "user";\n agentSpendUsd?: number;\n agentBudgetUsd?: number;\n globalSpendUsd?: number;\n globalBudgetUsd?: number;\n userSpendUsd?: number;\n userBudgetUsd?: number;\n /** ISO 8601 time the daily budget resets. */\n resetAt: string;\n }\n /** An inbound AgentMail message. */\n export interface EmailReceivedEvent {\n inboxId: string;\n /** The From header as sent. */\n from: string;\n subject: string;\n /** The text body, or the HTML when there is no text, cut to 500 characters with `...` appended. */\n body: string;\n threadId: string;\n messageId: string;\n }\n /** An inbound Kapso (WhatsApp) message. */\n export interface KapsoMessageEvent {\n phoneNumberId: string;\n conversationId?: string;\n messageId: string;\n from?: string;\n /** Kapso message type, such as `text` or `image`. */\n type?: string;\n /** The text, or a placeholder naming the type for a non-text message. */\n text: string;\n }\n export type VcsProvider = "github" | "gitlab" | "azure-devops" | "bitbucket";\n /**\n * The provider object the event is about, as the provider names it. GitLab\n * calls a pull request a merge request, and a comment a `note`.\n */\n export type VcsEventKind =\n | "pull_request"\n | "merge_request"\n | "issue"\n | "issue_comment"\n | "note"\n | "pull_request_review"\n | "pipeline";\n /**\n * A webhook event from a connected code host. `action` is the provider\'s own\n * value: `opened`, `closed`, `synchronize`, `merge`, `created`, `commented`, or,\n * for a pipeline, its status such as `success` or `failed`. Fields a kind does\n * not carry are absent.\n */\n export interface VcsEvent {\n provider: VcsProvider;\n kind: VcsEventKind;\n action: string;\n /** `owner/name` on GitHub and GitLab, `workspace/repo_slug` on Bitbucket, the repository URL on Azure DevOps. */\n repo: string;\n /** The PR, merge request, or issue number. Absent for a pipeline outside a merge request. */\n number?: number;\n title?: string;\n body?: string | null;\n /** Login of the user behind the event. Set for pull requests, merge requests, and Azure DevOps comments. */\n author?: string;\n url?: string;\n merged?: boolean;\n changedFiles?: number;\n /** The review verdict, on a pull request review. */\n reviewState?: string;\n }\n export interface ToolCallCompletedEvent extends ToolCallEvent {\n result: unknown;\n durationMs: number;\n }\n export interface SwarmEventMap {\n "pre.task.create": {\n event: TaskCreateEvent;\n modify: TaskCreateModify;\n result: PreResult<TaskCreateModify>;\n };\n "pre.task.followUp": {\n event: TaskFollowUpEvent;\n modify: TaskFollowUpModify;\n result: PreResult<TaskFollowUpModify>;\n };\n "pre.slack.route": {\n event: SlackRouteEvent;\n modify: SlackRouteModify;\n result: PreResult<SlackRouteModify>;\n };\n "pre.chat.route": {\n event: ChatRouteEvent;\n modify: ChatRouteModify;\n result: PreResult<ChatRouteModify>;\n };\n "pre.heartbeat.remediate": {\n event: HeartbeatRemediateEvent;\n modify: HeartbeatRemediateModify;\n result: PreResult<HeartbeatRemediateModify>;\n };\n "pre.tool.call": {\n event: ToolCallEvent;\n modify: ToolCallModify;\n result: PreResult<ToolCallModify>;\n };\n "post.task.created": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.blocked": {\n event: TaskBlockedEvent;\n modify: never;\n result: void;\n };\n "post.task.completed": {\n event: TaskCompletedEvent;\n modify: never;\n result: void;\n };\n "post.task.failed": {\n event: TaskFailedEvent;\n modify: never;\n result: void;\n };\n "post.task.cancelled": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.superseded": {\n event: TaskSupersededEvent;\n modify: never;\n result: void;\n };\n "post.task.progress": {\n event: TaskProgressEvent;\n modify: never;\n result: void;\n };\n "post.slack.message": {\n event: SlackMessageEvent;\n modify: never;\n result: void;\n };\n "post.chat.message": {\n event: ChatMessageEvent;\n modify: never;\n result: void;\n };\n "post.approval.resolved": {\n event: ApprovalResolvedEvent;\n modify: never;\n result: void;\n };\n "post.task.budgetRefused": {\n event: TaskBudgetRefusedEvent;\n modify: never;\n result: void;\n };\n "post.email.received": {\n event: EmailReceivedEvent;\n modify: never;\n result: void;\n };\n "post.kapso.message": {\n event: KapsoMessageEvent;\n modify: never;\n result: void;\n };\n "post.vcs.event": {\n event: VcsEvent;\n modify: never;\n result: void;\n };\n "post.tool.call": {\n event: ToolCallCompletedEvent;\n modify: never;\n result: void;\n };\n }\n export interface ExtensionApi<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > {\n on<E extends keyof SwarmEventMap>(\n event: E,\n handler: (\n event: SwarmEventMap[E]["event"],\n ctx: CtxFor<M>,\n ) => Promise<SwarmEventMap[E]["result"]> | SwarmEventMap[E]["result"],\n opts?: {\n priority?: number;\n },\n ): void;\n }\n export type SwarmExtension<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > = (api: ExtensionApi<M>) => void;\n export { block, modify } from "./contract-runtime";\n}\n';
|
|
4
|
+
'// biome-ignore-all lint/suspicious/noConfusingVoidType: Extension handlers may explicitly return no result.\ndeclare module "swarm-extension" {\n export type CreateTaskOptions = {\n key?: string | undefined;\n agentId?: string | null | undefined;\n creatorAgentId?: string | undefined;\n source?:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "bitbucket"\n | "linear"\n | "jira"\n | "mcp"\n | "api"\n | "ui"\n | "system"\n | "comb"\n | "chat"\n | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n taskType?: string | undefined;\n tags?: string[] | undefined;\n priority?: number | undefined;\n dependsOn?: string[] | undefined;\n offeredTo?: string | undefined;\n status?: "draft" | "backlog" | "unassigned" | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n overrideSlackContext?: boolean | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | "bitbucket" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n profile?: string | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | undefined;\n workflowRunStepId?: string | undefined;\n sourceTaskId?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n inheritParentOutputSchema?: boolean | undefined;\n inheritParentRequester?: boolean | undefined;\n inheritParentRoutingAffinity?: boolean | undefined;\n inheritParentFollowUpConfig?: boolean | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n requestedByUserId?: string | undefined;\n contextKey?: string | undefined;\n bypassTrackerContextDedup?: boolean | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | "fx"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n };\n\n export type AgentTask = {\n id: string;\n key: string;\n agentId: string | null;\n task: string;\n status:\n | "draft"\n | "backlog"\n | "unassigned"\n | "offered"\n | "reviewing"\n | "pending"\n | "in_progress"\n | "paused"\n | "completed"\n | "failed"\n | "cancelled"\n | "superseded";\n source:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "bitbucket"\n | "linear"\n | "jira"\n | "mcp"\n | "api"\n | "ui"\n | "system"\n | "comb"\n | "chat";\n tags: string[];\n priority: number;\n dependsOn: string[];\n createdAt: string;\n lastUpdatedAt: string;\n slackReplySent: boolean;\n wasPaused: boolean;\n creatorAgentId?: string | undefined;\n title?: string | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n poolWakeAt?: string | undefined;\n taskType?: string | undefined;\n offeredTo?: string | undefined;\n offeredAt?: string | undefined;\n acceptedAt?: string | undefined;\n rejectionReason?: string | undefined;\n finishedAt?: string | undefined;\n notifiedAt?: string | undefined;\n failureReason?: string | undefined;\n output?: string | undefined;\n progress?: string | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n slackProgressMessageTs?: string | undefined;\n slackTreeRootMessageTs?: string | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | "bitbucket" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n claudeSessionId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n resolvedModel?: string | undefined;\n modelSource?: string | undefined;\n modelAlias?: string | undefined;\n resolvedEffort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n profile?: string | undefined;\n resolvedProfile?: string | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | null | undefined;\n workflowRunStepId?: string | null | undefined;\n contextKey?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n deferredAt?: string | undefined;\n compactionCount?: number | undefined;\n peakContextPercent?: number | undefined;\n peakContextTokens?: number | undefined;\n contextWindowSize?: number | undefined;\n credentialKeySuffix?: string | undefined;\n credentialKeyType?: string | undefined;\n requestedByUserId?: string | undefined;\n swarmVersion?: string | undefined;\n provider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | "fx"\n | undefined;\n providerMeta?: Record<string, unknown> | undefined;\n harnessVariant?: string | undefined;\n harnessVariantMeta?: Record<string, unknown> | undefined;\n totalCostUsd?: number | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | "fx"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n routingAffinityInvalid?: boolean | undefined;\n };\n\n export type ActiveSession = {\n id: string;\n agentId: string;\n taskId: string | null;\n triggerType: string;\n inboxMessageId: string | null;\n taskDescription: string | null;\n runnerSessionId: string | null;\n providerSessionId: string | null;\n startedAt: string;\n lastHeartbeatAt: string;\n runtimeInstanceId?: string | null | undefined;\n };\n\n export type SteerMode = "steer" | "queue";\n\n export type SteeringSource = "script" | "slack" | "mcp" | "api" | "ui" | "chat";\n\n export type RequestInfo = {\n sessionId: string | undefined;\n agentId: string | undefined;\n runtimeInstanceId: string | undefined;\n sourceTaskId: string | undefined;\n contextKey: string | undefined;\n callOrigin: "mcp" | "extension" | "script-sdk";\n };\n\n import type { SwarmSdk } from "swarm-sdk";\n import type { z } from "zod";\n export type Runtime = "api" | "worker";\n export interface ExtensionScriptAsset {\n name: string;\n file: string;\n description: string;\n intent?: string;\n }\n export interface ExtensionScheduleAsset {\n name: string;\n description?: string;\n script: string;\n cronExpression?: string;\n intervalMs?: number;\n timezone?: string;\n args?: Record<string, unknown>;\n }\n export interface ExtensionWorkflowAsset {\n file: string;\n }\n export interface ExtensionSkillAsset {\n dir: string;\n }\n export interface ExtensionManifest {\n $schema?: string;\n name: string;\n description: string;\n version: string;\n runtime: Runtime;\n assets: {\n hooks: string;\n scripts?: readonly ExtensionScriptAsset[];\n schedules?: readonly ExtensionScheduleAsset[];\n workflows?: readonly ExtensionWorkflowAsset[];\n skills?: readonly ExtensionSkillAsset[];\n };\n homepage?: string;\n author?: string;\n }\n export interface HooksModule {\n default: SwarmExtension;\n config?: z.ZodTypeAny;\n }\n export interface ExtensionState {\n get<T = unknown>(key: string): Promise<T | null>;\n set<T>(key: string, value: T): Promise<void>;\n incr(key: string, by?: number): Promise<number>;\n del(key: string): Promise<void>;\n }\n export interface ExtensionLogger {\n debug(message: string, data?: unknown): void;\n info(message: string, data?: unknown): void;\n warn(message: string, data?: unknown): void;\n error(message: string, data?: unknown): void;\n }\n type ConfigFor<M extends ExtensionManifest> = M extends {\n config: infer C extends z.ZodTypeAny;\n }\n ? z.infer<C>\n : Record<string, unknown>;\n export interface ApiCtx<Config = Record<string, unknown>> {\n swarm: SwarmSdk;\n state: ExtensionState;\n config: Config;\n log: ExtensionLogger;\n signal: AbortSignal;\n event: {\n name: keyof SwarmEventMap;\n at: string;\n extension: {\n id: string;\n version: number;\n };\n };\n }\n export interface WorkerCtx<Config = Record<string, unknown>>\n extends Omit<ApiCtx<Config>, "swarm"> {\n swarm: SwarmSdk;\n worker: {\n agentId: string;\n taskId: string;\n harness: string;\n };\n }\n export type CtxFor<M extends ExtensionManifest> = M["runtime"] extends "api"\n ? ApiCtx<ConfigFor<M>>\n : WorkerCtx<ConfigFor<M>>;\n export type PreResult<Modify> =\n | void\n | {\n action: "continue";\n }\n | {\n action: "modify";\n data: Modify;\n }\n | {\n action: "block";\n reason: string;\n };\n export type TaskCreateOrigin =\n | "rest"\n | "app"\n | "mcp"\n | "slack"\n | "schedule"\n | "workflow"\n | "webhook"\n | "followUp"\n | `extension:${string}`;\n export interface TaskCreateEvent {\n options: CreateTaskOptions;\n description: string;\n origin: TaskCreateOrigin;\n requestInfo?: RequestInfo;\n /** Slack ingress metadata; not persisted or writable through modify. */\n slack?: {\n trigger: "mention" | "thread-buffer";\n messages: {\n ts: string;\n userId: string;\n text: string;\n }[];\n };\n }\n /** A pre.task.create hook blocked a task before it was created. */\n export interface TaskBlockedEvent {\n /** The extension that blocked, or whose model/agent rewrite was rejected. */\n extension: {\n id: string;\n name: string;\n };\n /** The scrubbed block reason. */\n reason: string;\n origin: TaskCreateOrigin;\n source?: AgentTask["source"];\n requester: {\n userId?: string;\n agentId?: string;\n slackUserId?: string;\n };\n context?: {\n contextKey?: string;\n scheduleId?: string;\n workflowRunId?: string;\n workflowRunStepId?: string;\n parentTaskId?: string;\n vcsRepo?: string;\n vcsNumber?: number;\n slackChannelId?: string;\n slackThreadTs?: string;\n };\n /** The original task description, scrubbed and cut to 500 characters. */\n description: string;\n }\n export type TaskCreateModify = Partial<\n Pick<\n CreateTaskOptions,\n | "agentId"\n | "creatorAgentId"\n | "source"\n | "taskType"\n | "tags"\n | "priority"\n | "dependsOn"\n | "offeredTo"\n | "vcsProvider"\n | "vcsRepo"\n | "vcsEventType"\n | "vcsNumber"\n | "vcsCommentId"\n | "vcsAuthor"\n | "vcsUrl"\n | "vcsInstallationId"\n | "vcsNodeId"\n | "agentmailInboxId"\n | "agentmailMessageId"\n | "agentmailThreadId"\n | "mentionMessageId"\n | "mentionChannelId"\n | "dir"\n | "model"\n | "modelTier"\n | "effort"\n | "outputSchema"\n | "followUpConfig"\n | "bypassTrackerContextDedup"\n >\n > & {\n description?: string;\n };\n export interface TaskFollowUpEvent {\n completedTask: AgentTask;\n status: "completed" | "failed";\n output?: string;\n failureReason?: string;\n workerAgentId: string;\n leadAgentId: string;\n summary: string;\n }\n export interface TaskSteerEvent {\n task: AgentTask;\n message: string;\n mode: SteerMode;\n source: SteeringSource;\n sender: {\n kind: "user" | "agent" | "system";\n userId?: string;\n agentId?: string;\n };\n messageTimestamps?: string[];\n /** Slack ingress metadata; not persisted or writable through modify. */\n slack?: {\n channelId: string;\n threadTs: string;\n userId?: string;\n };\n }\n export interface TaskSteerModify {\n message: string;\n }\n export type TaskFollowUpModify = Partial<\n Pick<CreateTaskOptions, "agentId" | "priority" | "followUpConfig">\n > & {\n description?: string;\n };\n export interface SlackRouteEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n botMentioned: boolean;\n threadContext?: {\n channelId: string;\n threadTs: string;\n };\n }\n export interface SlackRouteModify {\n target:\n | {\n kind: "agent";\n agentId: string;\n }\n | {\n kind: "lead";\n }\n | {\n kind: "broadcast";\n };\n }\n /** A Chat SDK message after its thread buffer flushed, before routing. */\n export interface ChatRouteEvent {\n /** Adapter name, such as `telegram` or `slack`. */\n adapter: string;\n channelId: string;\n /** The Chat SDK thread id, prefixed with the adapter name. */\n threadId: string;\n /** The first buffered sender. */\n userId: string;\n userName?: string;\n /** The buffered messages, joined. */\n text: string;\n /** True for an @mention and for a reply to one of the bot\'s messages. */\n botMentioned: boolean;\n isDirectMessage: boolean;\n /** Platform chat type, such as Telegram `private`, `group`, `supergroup` or `channel`. */\n chatType?: string;\n /** Set for a Telegram supergroup with topics. */\n isForum?: boolean;\n /** A buffered message replies to one of the bot\'s own messages. */\n replyToBot: boolean;\n /** Set when earlier swarm tasks exist in this thread. */\n threadContext?: {\n adapter: string;\n threadId: string;\n };\n }\n export interface ChatRouteModify {\n target:\n | {\n kind: "agent";\n agentId: string;\n }\n | {\n kind: "lead";\n }\n | {\n kind: "broadcast";\n }\n | {\n kind: "workflow";\n workflowId: string;\n };\n }\n export type HeartbeatClassification = "no-session" | "stale-session" | "fresh-stalled";\n export type HeartbeatAction = "supersede-resume" | "fail" | "record";\n export interface HeartbeatRemediateEvent {\n task: AgentTask;\n session?: ActiveSession;\n classification: HeartbeatClassification;\n proposedAction: HeartbeatAction;\n reason: string;\n taskAgeMs: number;\n sessionHeartbeatAgeMs?: number;\n }\n export interface HeartbeatRemediateModify {\n proposedAction: HeartbeatAction;\n }\n export interface ToolCallEvent {\n tool: string;\n args: unknown;\n requestInfo: RequestInfo;\n }\n export interface ToolCallModify {\n args: unknown;\n }\n export interface TaskEvent {\n task: AgentTask;\n }\n export interface TaskCompletedEvent extends TaskEvent {\n output: string;\n }\n export interface TaskFailedEvent extends TaskEvent {\n failureReason: string;\n }\n export interface TaskSupersededEvent extends TaskEvent {\n supersededBy: string;\n }\n export interface TaskProgressEvent extends TaskEvent {\n progress: string;\n }\n export interface SlackMessageEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n taskId?: string;\n }\n /** A Chat SDK message the swarm received or sent. */\n export interface ChatMessageEvent {\n adapter: string;\n channelId: string;\n threadId: string;\n /** The sender, for an inbound message. */\n userId?: string;\n text: string;\n direction: "inbound" | "outbound";\n taskId?: string;\n messageId?: string;\n }\n /**\n * A person answered an approval request. Fires for workflow and standalone\n * requests. Timeouts and cancellations do not emit it today.\n */\n export interface ApprovalResolvedEvent {\n requestId: string;\n status: "approved" | "rejected" | "timeout" | "cancelled";\n responses: Record<string, unknown> | null;\n /** Set when a workflow human-in-the-loop step asked. Absent for a standalone request. */\n workflowRunId?: string;\n workflowRunStepId?: string;\n /** The task whose agent asked, for a standalone request. */\n sourceTaskId?: string;\n }\n /** A task was refused because a daily spend budget is used up. */\n export interface TaskBudgetRefusedEvent extends TaskEvent {\n /** The agent the task was refused for. */\n agentId: string;\n /** Which budget refused it. The matching spend and budget fields are set. */\n cause: "agent" | "global" | "user";\n agentSpendUsd?: number;\n agentBudgetUsd?: number;\n globalSpendUsd?: number;\n globalBudgetUsd?: number;\n userSpendUsd?: number;\n userBudgetUsd?: number;\n /** ISO 8601 time the daily budget resets. */\n resetAt: string;\n }\n /** An inbound AgentMail message. */\n export interface EmailReceivedEvent {\n inboxId: string;\n /** The From header as sent. */\n from: string;\n subject: string;\n /** The text body, or the HTML when there is no text, cut to 500 characters with `...` appended. */\n body: string;\n threadId: string;\n messageId: string;\n }\n /** An inbound Kapso (WhatsApp) message. */\n export interface KapsoMessageEvent {\n phoneNumberId: string;\n conversationId?: string;\n messageId: string;\n from?: string;\n /** Kapso message type, such as `text` or `image`. */\n type?: string;\n /** The text, or a placeholder naming the type for a non-text message. */\n text: string;\n }\n export type VcsProvider = "github" | "gitlab" | "azure-devops" | "bitbucket";\n /**\n * The provider object the event is about, as the provider names it. GitLab\n * calls a pull request a merge request, and a comment a `note`.\n */\n export type VcsEventKind =\n | "pull_request"\n | "merge_request"\n | "issue"\n | "issue_comment"\n | "note"\n | "pull_request_review"\n | "pipeline";\n /**\n * A webhook event from a connected code host. `action` is the provider\'s own\n * value: `opened`, `closed`, `synchronize`, `merge`, `created`, `commented`, or,\n * for a pipeline, its status such as `success` or `failed`. Fields a kind does\n * not carry are absent.\n */\n export interface VcsEvent {\n provider: VcsProvider;\n kind: VcsEventKind;\n action: string;\n /** `owner/name` on GitHub and GitLab, `workspace/repo_slug` on Bitbucket, the repository URL on Azure DevOps. */\n repo: string;\n /** The PR, merge request, or issue number. Absent for a pipeline outside a merge request. */\n number?: number;\n title?: string;\n body?: string | null;\n /** Login of the user behind the event. Set for pull requests, merge requests, and Azure DevOps comments. */\n author?: string;\n url?: string;\n merged?: boolean;\n changedFiles?: number;\n /** The review verdict, on a pull request review. */\n reviewState?: string;\n }\n export interface ToolCallCompletedEvent extends ToolCallEvent {\n result: unknown;\n durationMs: number;\n }\n export interface SwarmEventMap {\n "pre.task.create": {\n event: TaskCreateEvent;\n modify: TaskCreateModify;\n result: PreResult<TaskCreateModify>;\n };\n "pre.task.followUp": {\n event: TaskFollowUpEvent;\n modify: TaskFollowUpModify;\n result: PreResult<TaskFollowUpModify>;\n };\n "pre.task.steer": {\n event: TaskSteerEvent;\n modify: TaskSteerModify;\n result: PreResult<TaskSteerModify>;\n };\n "pre.slack.route": {\n event: SlackRouteEvent;\n modify: SlackRouteModify;\n result: PreResult<SlackRouteModify>;\n };\n "pre.chat.route": {\n event: ChatRouteEvent;\n modify: ChatRouteModify;\n result: PreResult<ChatRouteModify>;\n };\n "pre.heartbeat.remediate": {\n event: HeartbeatRemediateEvent;\n modify: HeartbeatRemediateModify;\n result: PreResult<HeartbeatRemediateModify>;\n };\n "pre.tool.call": {\n event: ToolCallEvent;\n modify: ToolCallModify;\n result: PreResult<ToolCallModify>;\n };\n "post.task.created": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.blocked": {\n event: TaskBlockedEvent;\n modify: never;\n result: void;\n };\n "post.task.completed": {\n event: TaskCompletedEvent;\n modify: never;\n result: void;\n };\n "post.task.failed": {\n event: TaskFailedEvent;\n modify: never;\n result: void;\n };\n "post.task.cancelled": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.superseded": {\n event: TaskSupersededEvent;\n modify: never;\n result: void;\n };\n "post.task.progress": {\n event: TaskProgressEvent;\n modify: never;\n result: void;\n };\n "post.slack.message": {\n event: SlackMessageEvent;\n modify: never;\n result: void;\n };\n "post.chat.message": {\n event: ChatMessageEvent;\n modify: never;\n result: void;\n };\n "post.approval.resolved": {\n event: ApprovalResolvedEvent;\n modify: never;\n result: void;\n };\n "post.task.budgetRefused": {\n event: TaskBudgetRefusedEvent;\n modify: never;\n result: void;\n };\n "post.email.received": {\n event: EmailReceivedEvent;\n modify: never;\n result: void;\n };\n "post.kapso.message": {\n event: KapsoMessageEvent;\n modify: never;\n result: void;\n };\n "post.vcs.event": {\n event: VcsEvent;\n modify: never;\n result: void;\n };\n "post.tool.call": {\n event: ToolCallCompletedEvent;\n modify: never;\n result: void;\n };\n }\n export interface ExtensionApi<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > {\n on<E extends keyof SwarmEventMap>(\n event: E,\n handler: (\n event: SwarmEventMap[E]["event"],\n ctx: CtxFor<M>,\n ) => Promise<SwarmEventMap[E]["result"]> | SwarmEventMap[E]["result"],\n opts?: {\n priority?: number;\n },\n ): void;\n }\n export type SwarmExtension<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > = (api: ExtensionApi<M>) => void;\n export { block, modify } from "./contract-runtime";\n}\n';
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
import type { SwarmSdk } from "swarm-sdk";
|
|
3
3
|
import type { z } from "zod";
|
|
4
4
|
import type { RequestInfo } from "../tools/utils";
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
ActiveSession,
|
|
7
|
+
AgentTask,
|
|
8
|
+
CreateTaskOptions,
|
|
9
|
+
SteeringSource,
|
|
10
|
+
SteerMode,
|
|
11
|
+
} from "../types";
|
|
6
12
|
|
|
7
13
|
export type Runtime = "api" | "worker";
|
|
8
14
|
|
|
@@ -193,6 +199,21 @@ export interface TaskFollowUpEvent {
|
|
|
193
199
|
summary: string;
|
|
194
200
|
}
|
|
195
201
|
|
|
202
|
+
export interface TaskSteerEvent {
|
|
203
|
+
task: AgentTask;
|
|
204
|
+
message: string;
|
|
205
|
+
mode: SteerMode;
|
|
206
|
+
source: SteeringSource;
|
|
207
|
+
sender: { kind: "user" | "agent" | "system"; userId?: string; agentId?: string };
|
|
208
|
+
messageTimestamps?: string[];
|
|
209
|
+
/** Slack ingress metadata; not persisted or writable through modify. */
|
|
210
|
+
slack?: { channelId: string; threadTs: string; userId?: string };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface TaskSteerModify {
|
|
214
|
+
message: string;
|
|
215
|
+
}
|
|
216
|
+
|
|
196
217
|
export type TaskFollowUpModify = Partial<
|
|
197
218
|
Pick<CreateTaskOptions, "agentId" | "priority" | "followUpConfig">
|
|
198
219
|
> & { description?: string };
|
|
@@ -422,6 +443,11 @@ export interface SwarmEventMap {
|
|
|
422
443
|
modify: TaskFollowUpModify;
|
|
423
444
|
result: PreResult<TaskFollowUpModify>;
|
|
424
445
|
};
|
|
446
|
+
"pre.task.steer": {
|
|
447
|
+
event: TaskSteerEvent;
|
|
448
|
+
modify: TaskSteerModify;
|
|
449
|
+
result: PreResult<TaskSteerModify>;
|
|
450
|
+
};
|
|
425
451
|
"pre.slack.route": {
|
|
426
452
|
event: SlackRouteEvent;
|
|
427
453
|
modify: SlackRouteModify;
|
|
@@ -157,6 +157,10 @@ export function runContext(event: keyof SwarmEventMap, payload: unknown): RunCon
|
|
|
157
157
|
subject =
|
|
158
158
|
`task ${stringField(payload, "completedTask", "id") ?? "?"} ${stringField(payload, "status") ?? ""}`.trim();
|
|
159
159
|
break;
|
|
160
|
+
case "pre.task.steer":
|
|
161
|
+
agentId = stringField(payload, "sender", "agentId");
|
|
162
|
+
subject = `${stringField(payload, "source") ?? "?"}: task ${stringField(payload, "task", "id") ?? "?"}`;
|
|
163
|
+
break;
|
|
160
164
|
case "pre.slack.route":
|
|
161
165
|
case "post.slack.message":
|
|
162
166
|
subject = `channel ${stringField(payload, "channelId") ?? "?"}: ${snippet(field(payload, "text"), 60)}`;
|
package/src/http/agents.ts
CHANGED
package/src/http/index.ts
CHANGED
|
@@ -877,7 +877,7 @@ httpServer
|
|
|
877
877
|
// Delete expired MCP overflow values (10-min tick, off the spill path)
|
|
878
878
|
startMcpOverflowSweep();
|
|
879
879
|
|
|
880
|
-
// Start expired-memory garbage collector (1-hour tick,
|
|
880
|
+
// Start expired-memory garbage collector (1-hour tick, first run 2 min after boot)
|
|
881
881
|
await startMemoryGc();
|
|
882
882
|
|
|
883
883
|
// Start the opt-in DB retention sweep after config hydration. Every key is
|