@desplega.ai/agent-swarm 1.172.0 → 2.0.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 +1 -1
- package/dist/{acp-adapter-fpecx1g1.js → acp-adapter-sj2g0m84.js} +18 -17
- package/dist/{actions-pw87a1a8.js → actions-fegk44gr.js} +65 -35
- package/dist/{amp-adapter-8jem2bc0.js → amp-adapter-ad8ft89x.js} +8 -7
- package/dist/{anthropic-messages-8ee2f22q.js → anthropic-messages-r6czkjv1.js} +7 -7
- package/dist/{app-wmf0m843.js → app-kfvgbvzy.js} +19 -13
- package/dist/{assistant-emp1e108.js → assistant-z7zdy9ja.js} +65 -38
- package/dist/{boot-reembed-1de4f4aj.js → boot-reembed-5c2z0mbe.js} +11 -9
- package/dist/{boot-reembed-4ymn9atn.js → boot-reembed-j8xa181e.js} +11 -9
- package/dist/{boot-scrub-sweep-adhk1s8c.js → boot-scrub-sweep-hnkn3rgt.js} +12 -10
- package/dist/{boot-seeds-8q637aew.js → boot-seeds-kwjq4d2z.js} +15 -13
- package/dist/{claude-adapter-t26cv8a4.js → claude-adapter-9vmvpvgd.js} +20 -19
- package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
- package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
- package/dist/{claude-sdk-session-gsfsh662.js → claude-sdk-session-9jye6cxr.js} +12698 -11995
- package/dist/{cli-k46r9hmk.js → cli-03gedhng.js} +16 -14
- package/dist/{cli-kb4ehzx5.js → cli-1e4b6bzh.js} +7 -7
- package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
- package/dist/cli-2m1ktfzz.js +17795 -0
- package/dist/{cli-8vs9trd4.js → cli-3dj8k4vy.js} +1 -1
- package/dist/{cli-zxm9p3x4.js → cli-3fbmmawm.js} +5 -5
- package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
- package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
- package/dist/{cli-6jb2rf77.js → cli-5t4f29ez.js} +3 -3
- package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
- package/dist/cli-6cvfxs8r.js +47 -0
- package/dist/{cli-pj6x9qce.js → cli-6jyj59nb.js} +2 -2
- package/dist/{cli-388egyf6.js → cli-6razj6t4.js} +2 -2
- package/dist/{cli-qsztpfry.js → cli-74ahz61x.js} +2 -2
- package/dist/{cli-4nz8p1p5.js → cli-7x0g4sn1.js} +15474 -16082
- package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
- package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
- package/dist/cli-9traj3dn.js +638 -0
- package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
- package/dist/{cli-bf7485pm.js → cli-apx87jne.js} +2 -2
- package/dist/{cli-ztrv9y21.js → cli-bzszjf2p.js} +3689 -1081
- package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
- package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
- package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
- package/dist/{cli-1hgat6pa.js → cli-d5f9ed5c.js} +5 -5
- package/dist/cli-e3g5mbkz.js +776 -0
- package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
- package/dist/{cli-j6kpj9az.js → cli-ee9gtz70.js} +1553 -68
- package/dist/{cli-e0a9sk00.js → cli-eejsgvm4.js} +4 -4
- package/dist/{cli-tgpfnm6r.js → cli-ef1hg1wv.js} +518 -59
- package/dist/cli-f527ce74.js +781 -0
- package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
- package/dist/cli-hjwmhcg1.js +10622 -0
- package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
- package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
- package/dist/{cli-4fnb6884.js → cli-hvqbtna4.js} +7 -1259
- package/dist/{cli-pstq9888.js → cli-j0pfptdp.js} +220 -103
- package/dist/cli-jta2eyzc.js +619 -0
- package/dist/{cli-esnpehf5.js → cli-k382tshb.js} +12 -13
- package/dist/cli-k3dp5tpf.js +263 -0
- package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
- package/dist/cli-kceah1eh.js +92 -0
- package/dist/{cli-prrt9fa0.js → cli-ke896fcf.js} +10 -10
- package/dist/{cli-nv4zd0b9.js → cli-kt6zqg0e.js} +6 -6
- package/dist/{cli-g6t9texm.js → cli-m50t4309.js} +5 -18
- package/dist/cli-n2wq4j7m.js +6985 -0
- package/dist/{cli-c2pq2rjb.js → cli-n3hzg89b.js} +46 -15
- package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
- package/dist/{cli-5rv1j9ga.js → cli-ne236afy.js} +53 -7
- package/dist/cli-p0sg24zp.js +16 -0
- package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
- package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
- package/dist/{cli-g4f5pj26.js → cli-q0ke1yww.js} +111 -25
- package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
- package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
- package/dist/{cli-gj81e47t.js → cli-r2pnvj8g.js} +2 -2
- package/dist/{cli-r8smj8b8.js → cli-r62a35ea.js} +19 -3
- package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
- package/dist/cli-rhs9pz33.js +294 -0
- package/dist/{cli-nyhb1r6x.js → cli-s2sp957d.js} +52 -29
- package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
- package/dist/{cli-xczpdp9e.js → cli-se8w6wny.js} +6 -6
- package/dist/cli-skxvvpap.js +10140 -0
- package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
- package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
- package/dist/{cli-cf69s3ew.js → cli-tr4sxp68.js} +3 -3
- package/dist/{cli-8hzfb6xz.js → cli-tsde1hdr.js} +15 -15
- package/dist/{cli-cceskcvt.js → cli-txqb9s38.js} +8 -8
- package/dist/{cli-aspcaef3.js → cli-v1yb0rqb.js} +6 -6
- package/dist/{cli-j1pmc07z.js → cli-vatyhshy.js} +268 -40
- package/dist/{cli-04emfe2q.js → cli-vdach5a9.js} +5 -5
- package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
- package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
- package/dist/{cli-hwwvy36w.js → cli-wayw93nt.js} +3 -3
- package/dist/cli-wmgrkscj.js +23254 -0
- package/dist/{cli-gp1rtyvk.js → cli-z5jjpaxw.js} +29 -6
- package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
- package/dist/cli.js +32 -48
- package/dist/{codex-adapter-m4tgdysy.js → codex-adapter-y81sssk0.js} +16 -15
- package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
- package/dist/{codex-session-runner-ymwzm6ea.js → codex-session-runner-8vx4j6a9.js} +16 -15
- package/dist/{commands-n0hshcvs.js → commands-kcpvpcrr.js} +21 -10
- package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
- package/dist/{controllers-connect-y07cqcvy.js → controllers-connect-kwpvj3rf.js} +45 -38
- package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
- package/dist/{db-hkqvrdcb.js → db-k8ankj20.js} +13 -11
- package/dist/{db-4w7tmt1g.js → db-ww5d7jq3.js} +29 -9
- package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
- package/dist/{dispatcher-5sd69y14.js → dispatcher-e8gq5m68.js} +41 -34
- package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
- package/dist/{dsh-adapter-2h8m4cab.js → dsh-adapter-3epjm3af.js} +7 -6
- package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
- package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
- package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
- package/dist/external-channel-h3359cwn.js +52 -0
- package/dist/{google-generative-ai-7pavrbv7.js → google-generative-ai-g8db7x0f.js} +5 -3
- package/dist/{google-vertex-3f1jk41f.js → google-vertex-r2692q0r.js} +5 -3
- package/dist/{grok-adapter-8m9yqzbq.js → grok-adapter-0d4x7gkx.js} +19 -18
- package/dist/{handlers-s20xr10r.js → handlers-an1gzv21.js} +44 -37
- package/dist/{heartbeat-3k31q4g2.js → heartbeat-6dakeb61.js} +46 -39
- package/dist/{hook-gdn6a2fn.js → hook-6v6cv6d5.js} +12 -24
- package/dist/{hook-ygwerrdh.js → hook-sa5xye4y.js} +13 -12
- package/dist/{http-jdteeg81.js → http-r7f3eky0.js} +1598 -279
- package/dist/index-52j1aja4.js +3465 -0
- package/dist/{index-e0snym4t.js → index-7ep4gzdk.js} +41 -34
- package/dist/index-9gw58n4k.js +193 -0
- package/dist/index-9j87mcm8.js +56305 -0
- package/dist/index-bsmcresk.js +79424 -0
- package/dist/index-mh85qhec.js +475 -0
- package/dist/{index-vm3bm9t7.js → index-rmpw9a8q.js} +41 -34
- package/dist/{index-6ksewd5y.js → index-s2wxgzr0.js} +1015 -732
- package/dist/{index-tsszt7g9.js → index-v1v6n7hg.js} +46 -39
- package/dist/index-we27kd31.js +12810 -0
- package/dist/{index-ffqzqgwb.js → index-zk96aq1k.js} +11 -9
- package/dist/{keepalive-jekc896t.js → keepalive-be9vwy5h.js} +13 -11
- package/dist/{lead-4k9s9szx.js → lead-0861cwrf.js} +64 -57
- package/dist/{maintenance-shazch4n.js → maintenance-mzzgc8bn.js} +11 -9
- package/dist/node-c9we95xf.js +1 -1
- package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
- package/dist/{oauth-refresh-sweep-5gb36kn8.js → oauth-refresh-sweep-cpdnfwdj.js} +12 -10
- package/dist/{onboard-ydrbnvww.js → onboard-fh8qs4r3.js} +11 -3
- package/dist/{opencode-adapter-5zh0he20.js → opencode-adapter-nm42wwj8.js} +19 -14
- package/dist/{otel-impl-6pf5cv86.js → otel-impl-x6c1c9g4.js} +248 -869
- package/dist/{pi-mono-adapter-ef9wwx9m.js → pi-mono-adapter-9n2ya240.js} +245 -107
- package/dist/{pricing-refresh-s52nsa5q.js → pricing-refresh-qb0rv0ap.js} +13 -11
- package/dist/{rbac-roles-aq3msh4e.js → rbac-roles-1gzdwbh1.js} +12 -10
- package/dist/{rbac-roles-q5gb5e8v.js → rbac-roles-3mraey52.js} +13 -11
- package/dist/{render-v2-pd1rg54q.js → render-v2-agpa45zz.js} +19 -13
- package/dist/{resume-gw4a2c6v.js → resume-x0ydy9s9.js} +27 -21
- package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
- package/dist/{setup-jda1ksdh.js → setup-as9ga0d6.js} +2 -2
- package/dist/{virtual-modules-b3ga2m65.js → virtual-modules-9gkxqrap.js} +7 -6
- package/dist/{work-objects-tb7ycye8.js → work-objects-y5g1y7ev.js} +49 -37
- package/dist/{worker-njjccz5d.js → worker-860c3e38.js} +64 -57
- package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
- package/openapi.json +951 -356
- package/package.json +12 -13
- package/src/apps/catalog.generated.json +1309 -53
- package/src/apps/page-validator.ts +93 -31
- package/src/azure-devops/api.ts +94 -18
- package/src/azure-devops/auth.ts +32 -0
- package/src/azure-devops/boards-sync.ts +708 -0
- package/src/azure-devops/handlers.ts +52 -8
- package/src/azure-devops/html.ts +26 -0
- package/src/azure-devops/index.ts +15 -0
- package/src/azure-devops/templates.ts +86 -0
- package/src/azure-devops/types.ts +65 -1
- package/src/be/config-refs.ts +60 -0
- package/src/be/db/page-versions.ts +15 -0
- package/src/be/db/runtime.ts +35 -8
- package/src/be/db/skill-name-resolution.ts +36 -0
- package/src/be/db/tasks/read.ts +230 -0
- package/src/be/db/tasks/write.ts +7 -0
- package/src/be/db.ts +74 -13
- package/src/be/migrations/213_script_connections_sql.sql +79 -0
- package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
- package/src/be/migrations/216_task_resolved_effort.sql +5 -0
- package/src/be/migrations/217_chat_sdk_state.sql +104 -0
- package/src/be/model-catalog-store.ts +5 -1
- package/src/be/model-tier-resolution.ts +12 -1
- package/src/be/model-validation.ts +5 -2
- package/src/be/models-catalog.ts +26 -1
- package/src/be/modelsdev-cache.json +198 -63
- package/src/be/modelsdev-cache.ts +9 -1
- package/src/be/script-connections.ts +47 -8
- package/src/be/script-credential-broker.ts +39 -2
- package/src/be/scripts/run-saved.ts +1 -0
- package/src/be/scripts/typecheck.ts +10 -8
- package/src/be/seed/runner.ts +13 -1
- package/src/be/seed/state-db.ts +5 -0
- package/src/be/seed/types.ts +6 -0
- package/src/be/seed-pricing.ts +19 -2
- package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
- package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
- package/src/be/seed-skills/bundled-files.generated.json +10 -18
- package/src/be/seed-skills/index.ts +107 -3
- package/src/be/sql-connections.ts +118 -0
- package/src/be/swarm-config-guard.ts +53 -0
- package/src/cli.tsx +0 -16
- package/src/commands/onboard/non-interactive.ts +4 -2
- package/src/commands/profile-sync.ts +5 -3
- package/src/commands/provider-credentials.ts +52 -6
- package/src/commands/runner.ts +196 -56
- package/src/e2b/env.ts +5 -0
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +45 -0
- package/src/extensions/dispatcher.ts +7 -0
- package/src/extensions/post-bridge.ts +40 -0
- package/src/github/handlers.ts +11 -4
- package/src/heartbeat/templates.ts +8 -5
- package/src/hooks/hook.ts +0 -26
- package/src/http/all-routes.ts +0 -1
- package/src/http/config.ts +36 -17
- package/src/http/core.ts +4 -0
- package/src/http/index.ts +14 -2
- package/src/http/integrations.ts +88 -1
- package/src/http/mcp-oauth.ts +6 -13
- package/src/http/mcp.ts +15 -5
- package/src/http/page-proxy.ts +2 -4
- package/src/http/pages-public.ts +6 -5
- package/src/http/pages.ts +5 -14
- package/src/http/poll.ts +28 -68
- package/src/http/requested-by.ts +54 -0
- package/src/http/route-def.ts +7 -6
- package/src/http/script-connection-proxy.ts +51 -4
- package/src/http/script-connections.ts +5 -2
- package/src/http/scripts.ts +1 -0
- package/src/http/session-cost-recompute.ts +12 -2
- package/src/http/session-data.ts +4 -0
- package/src/http/stats.ts +1 -30
- package/src/http/tasks.ts +61 -5
- package/src/http/utils.ts +14 -0
- package/src/http/webhooks.ts +183 -2
- package/src/http/x.ts +1 -0
- package/src/integrations/chat-sdk/adapters.ts +129 -0
- package/src/integrations/chat-sdk/attachments.ts +232 -0
- package/src/integrations/chat-sdk/background.ts +36 -0
- package/src/integrations/chat-sdk/commands.ts +194 -0
- package/src/integrations/chat-sdk/config.ts +198 -0
- package/src/integrations/chat-sdk/discord-api.ts +63 -0
- package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
- package/src/integrations/chat-sdk/handlers.ts +28 -0
- package/src/integrations/chat-sdk/inbound.ts +426 -0
- package/src/integrations/chat-sdk/limits.ts +48 -0
- package/src/integrations/chat-sdk/logger.ts +81 -0
- package/src/integrations/chat-sdk/outbound.ts +123 -0
- package/src/integrations/chat-sdk/relay.ts +172 -0
- package/src/integrations/chat-sdk/router.ts +169 -0
- package/src/integrations/chat-sdk/runtime.ts +351 -0
- package/src/integrations/chat-sdk/schema.ts +245 -0
- package/src/integrations/chat-sdk/state.ts +243 -0
- package/src/integrations/chat-sdk/status.ts +244 -0
- package/src/integrations/chat-sdk/steering.ts +58 -0
- package/src/integrations/chat-sdk/teams-origin.ts +77 -0
- package/src/integrations/chat-sdk/telegram-api.ts +56 -0
- package/src/integrations/chat-sdk/templates.ts +16 -0
- package/src/integrations/chat-sdk/test-hooks.ts +37 -0
- package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
- package/src/integrations/chat-sdk/typing.ts +65 -0
- package/src/jira/adf.ts +3 -1
- package/src/kv-reserved-namespaces.ts +2 -0
- package/src/oauth/mcp-wrapper.ts +10 -6
- package/src/otel-impl.ts +2 -1
- package/src/pages/version.ts +4 -5
- package/src/prompts/base-prompt.ts +111 -45
- package/src/providers/acp-target-catalog.ts +6 -0
- package/src/providers/acp-targets.ts +56 -3
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +27 -2
- package/src/providers/claude-flag-settings.ts +133 -0
- package/src/providers/claude-managed-adapter.ts +1 -1
- package/src/providers/claude-sdk-session.ts +7 -0
- package/src/providers/claude-session-events.ts +6 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/opencode-adapter.ts +268 -37
- package/src/providers/opencode-billing.ts +86 -0
- package/src/providers/opencode-swarm-plugin.ts +51 -0
- package/src/providers/pi-mono-adapter.ts +398 -153
- package/src/providers/pricing-sources.md +37 -3
- package/src/providers/reasoning-effort.ts +27 -0
- package/src/providers/types.ts +11 -2
- package/src/rbac/legacy-policy.ts +8 -2
- package/src/rbac/permissions.ts +21 -0
- package/src/scheduler/scheduler.ts +4 -2
- package/src/scripts-runtime/api-client.ts +15 -1
- package/src/scripts-runtime/api-types.ts +9 -1
- package/src/scripts-runtime/ctx.ts +1 -1
- package/src/scripts-runtime/loader.ts +19 -7
- package/src/scripts-runtime/mcp-client.ts +30 -19
- package/src/scripts-runtime/sdk-allowlist.ts +8 -6
- package/src/scripts-runtime/swarm-sdk.ts +0 -11
- package/src/scripts-runtime/types/stdlib.d.ts +27 -15
- package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
- package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
- package/src/server.ts +52 -18
- package/src/slack/actions.ts +29 -1
- package/src/slack/app.ts +14 -2
- package/src/slack/assistant.ts +36 -2
- package/src/slack/channel-join.ts +3 -16
- package/src/slack/commands.ts +9 -1
- package/src/slack/event-dedup.ts +1 -1
- package/src/slack/external-channel-egress.ts +113 -0
- package/src/slack/external-channel.ts +309 -0
- package/src/slack/handlers.ts +61 -0
- package/src/slack/render-v2.ts +40 -47
- package/src/slack/work-objects.ts +5 -0
- package/src/tasks/additive-buffer.ts +4 -2
- package/src/tasks/context-key.ts +94 -2
- package/src/tasks/model-pin.ts +67 -0
- package/src/tasks/worker-follow-up.ts +4 -31
- package/src/telemetry.ts +2 -1
- package/src/tests/acp-adapter.test.ts +42 -0
- package/src/tests/api-drain-worker-e2e.test.ts +1 -6
- package/src/tests/apps-catalog-feedback.test.ts +310 -0
- package/src/tests/apps-catalog-inputs.test.ts +70 -0
- package/src/tests/apps-catalog-table.test.ts +113 -0
- package/src/tests/azure-devops-boards-sync.test.ts +584 -0
- package/src/tests/azure-devops-html.test.ts +13 -0
- package/src/tests/azure-devops-webhook-malformed.test.ts +4 -0
- package/src/tests/base-prompt.test.ts +58 -54
- package/src/tests/chat-sdk-commands.test.ts +191 -0
- package/src/tests/chat-sdk-config.test.ts +334 -0
- package/src/tests/chat-sdk-discord-api.test.ts +68 -0
- package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
- package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
- package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
- package/src/tests/chat-sdk-harness.ts +146 -0
- package/src/tests/chat-sdk-inbound.test.ts +363 -0
- package/src/tests/chat-sdk-relay.test.ts +470 -0
- package/src/tests/chat-sdk-reload.test.ts +128 -0
- package/src/tests/chat-sdk-shutdown.test.ts +220 -0
- package/src/tests/chat-sdk-slack.test.ts +268 -0
- package/src/tests/chat-sdk-state.test.ts +163 -0
- package/src/tests/chat-sdk-status-route.test.ts +382 -0
- package/src/tests/chat-sdk-teams.test.ts +277 -0
- package/src/tests/chat-sdk-tools.test.ts +520 -0
- package/src/tests/chat-sdk-typing.test.ts +120 -0
- package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
- package/src/tests/claude-adapter-binary.test.ts +144 -0
- package/src/tests/claude-flag-settings.test.ts +114 -0
- package/src/tests/claude-managed-adapter.test.ts +1 -1
- package/src/tests/claude-sdk-lifecycle.test.ts +148 -1
- package/src/tests/claude-sdk-process.fixture.ts +7 -0
- package/src/tests/claude-thinking-tokens.test.ts +57 -0
- package/src/tests/claude-worker-parity.test.ts +2 -7
- package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
- package/src/tests/config-refs.test.ts +66 -0
- package/src/tests/context-key.test.ts +51 -0
- package/src/tests/cors-allowlist.test.ts +25 -0
- package/src/tests/create-page-tool.test.ts +18 -0
- package/src/tests/credential-check.test.ts +139 -0
- package/src/tests/credentials.test.ts +21 -0
- package/src/tests/db-runtime.test.ts +61 -0
- package/src/tests/db-task-read-contract.test.ts +20 -0
- package/src/tests/db-task-write-contract.test.ts +10 -0
- package/src/tests/deferred-task-wake.test.ts +52 -4
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/enabled-capabilities.test.ts +20 -0
- package/src/tests/entrypoint-api-readiness.test.ts +14 -8
- package/src/tests/entrypoint-config-env-export.test.ts +5 -2
- package/src/tests/entrypoint-export-to-env.test.ts +78 -0
- package/src/tests/explicit-model-validation.test.ts +105 -1
- package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
- package/src/tests/extensions-post-bridge.test.ts +51 -0
- package/src/tests/fetch-resolved-env.test.ts +128 -0
- package/src/tests/fixtures/azure-boards/workitem.commented.json +89 -0
- package/src/tests/fixtures/azure-boards/workitem.created.json +81 -0
- package/src/tests/fixtures/azure-boards/workitem.deleted.json +70 -0
- package/src/tests/fixtures/azure-boards/workitem.restored.json +82 -0
- package/src/tests/fixtures/azure-boards/workitem.updated.json +130 -0
- package/src/tests/fixtures/catalog-feedback-definition.json.txt +860 -0
- package/src/tests/fixtures/catalog-inputs-definition.json.txt +910 -0
- package/src/tests/fixtures/catalog-table-definition.json.txt +468 -0
- package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
- package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
- package/src/tests/fixtures/runner-identity-refresh.ts +3 -0
- package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
- package/src/tests/github-handlers.test.ts +35 -0
- package/src/tests/harness-provider-resolution.test.ts +12 -0
- package/src/tests/heartbeat-checklist.test.ts +3 -2
- package/src/tests/hook-runtime-close.test.ts +0 -2
- package/src/tests/http-api-integration.test.ts +0 -25
- package/src/tests/migration-046-budgets.test.ts +17 -16
- package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
- package/src/tests/model-tier-resolution.test.ts +93 -0
- package/src/tests/models-catalog.test.ts +42 -1
- package/src/tests/node-env-runtime.test.ts +98 -0
- package/src/tests/openai-compatible-providers.test.ts +134 -0
- package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
- package/src/tests/opencode-adapter.test.ts +348 -3
- package/src/tests/opencode-billing.test.ts +28 -0
- package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
- package/src/tests/opencode-shell-env.test.ts +145 -0
- package/src/tests/openrouter-base-url.test.ts +101 -151
- package/src/tests/page-proxy.test.ts +1 -1
- package/src/tests/pages-browser-sdk.test.ts +76 -0
- package/src/tests/pages-feedback.test.ts +1 -1
- package/src/tests/paused-tasks-requested-by.test.ts +102 -0
- package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
- package/src/tests/pi-mono-adapter.test.ts +385 -5
- package/src/tests/pi-shell-env.test.ts +170 -0
- package/src/tests/prompt-template-remaining.test.ts +35 -0
- package/src/tests/rbac-engine.test.ts +11 -3
- package/src/tests/runner-exit-after-tasks.test.ts +0 -4
- package/src/tests/runner-identity-refresh.test.ts +3 -0
- package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
- package/src/tests/script-connections-sql.test.ts +675 -0
- package/src/tests/script-connections.test.ts +7 -1
- package/src/tests/scripts-http.test.ts +201 -1
- package/src/tests/scripts-only-gating.test.ts +2 -3
- package/src/tests/scripts-runtime.test.ts +58 -40
- package/src/tests/secret-scrubber.test.ts +86 -0
- package/src/tests/seed-skills-bundled-files.test.ts +45 -53
- package/src/tests/seed-skills-retire.test.ts +182 -0
- package/src/tests/send-task-requester-gate.test.ts +58 -0
- package/src/tests/session-cost-recompute-unit.test.ts +94 -0
- package/src/tests/skill-get-name-resolution.test.ts +137 -0
- package/src/tests/slack-channel-join.test.ts +4 -1
- package/src/tests/slack-external-channel-config.test.ts +65 -0
- package/src/tests/slack-external-channel-egress.test.ts +237 -0
- package/src/tests/slack-external-channel-guard.test.ts +280 -0
- package/src/tests/slack-external-channel-tools.test.ts +173 -0
- package/src/tests/slack-external-channel.test.ts +370 -0
- package/src/tests/slack-render-v2.test.ts +86 -10
- package/src/tests/sonnet-5-5-registry.test.ts +9 -1
- package/src/tests/spec-base-url.test.ts +16 -1
- package/src/tests/swarm-config-export-to-env.test.ts +267 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
- package/src/tests/swarm-diff.test.ts +1 -1
- package/src/tests/task-model-effort-rerun.test.ts +164 -0
- package/src/tests/task-session-prompts.test.ts +132 -0
- package/src/tests/task-tool-manifest.test.ts +14 -0
- package/src/tests/task-tools-ctx.test.ts +2 -0
- package/src/tests/tool-annotations.test.ts +6 -6
- package/src/tests/ui-logs-parser.test.ts +43 -0
- package/src/tests/used-by-route.test.ts +6 -0
- package/src/tests/vendored-openapi.test.ts +16 -1
- package/src/tests/vercel-ai-gateway.test.ts +149 -0
- package/src/tests/workflow-swarm-script.test.ts +38 -0
- package/src/tests/workflow-wait-filter.test.ts +5 -3
- package/src/tools/chat-access.ts +41 -0
- package/src/tools/chat-open-dm.ts +59 -0
- package/src/tools/chat-post.ts +74 -0
- package/src/tools/chat-read-thread.ts +100 -0
- package/src/tools/chat-reply.ts +75 -0
- package/src/tools/create-page.ts +3 -13
- package/src/tools/defer-task.ts +17 -0
- package/src/tools/model-catalog/index.ts +2 -1
- package/src/tools/register-chat-channel.ts +139 -0
- package/src/tools/send-task.ts +24 -0
- package/src/tools/skills/skill-get.ts +17 -9
- package/src/tools/slack-post.ts +6 -0
- package/src/tools/slack-read.ts +8 -0
- package/src/tools/slack-reply.ts +6 -0
- package/src/tools/slack-start-thread.ts +6 -0
- package/src/tools/slack-update.ts +6 -0
- package/src/tools/slack-upload-file.ts +6 -0
- package/src/tools/swarm-config/get-config.ts +2 -1
- package/src/tools/swarm-config/list-config.ts +2 -1
- package/src/tools/swarm-config/set-config.ts +16 -3
- package/src/tools/tool-config.ts +8 -6
- package/src/types.ts +12 -2
- package/src/utils/config-env-export.ts +74 -0
- package/src/utils/credentials.test.ts +92 -0
- package/src/utils/credentials.ts +52 -4
- package/src/utils/harness-provider.ts +15 -6
- package/src/utils/node-env.ts +24 -0
- package/src/utils/runtime-model-catalog.ts +11 -1
- package/src/utils/secret-scrubber.ts +71 -2
- package/src/utils/task-tool-manifest.ts +19 -2
- package/src/workflows/executors/swarm-script.ts +1 -0
- package/templates/skills/agent-browser/SKILL.md +1 -1
- package/templates/skills/agent-browser/content.md +1 -1
- package/templates/skills/apps/SKILL.md +749 -0
- package/templates/skills/apps/content.md +60 -22
- package/templates/skills/chat-sdk/config.json +14 -0
- package/templates/skills/chat-sdk/content.md +84 -0
- package/templates/skills/composio-gmail/content.md +7 -0
- package/templates/skills/composio-google-docs/content.md +1 -1
- package/templates/skills/email-domain-health/config.json +14 -0
- package/templates/skills/email-domain-health/content.md +131 -0
- package/templates/skills/kv-storage/content.md +2 -2
- package/templates/skills/pages/content.md +8 -10
- package/templates/skills/qa-loom/config.json +14 -0
- package/templates/skills/qa-loom/content.md +187 -0
- package/templates/skills/qa-loom/files/build-loom.mjs +221 -0
- package/templates/skills/qa-loom/files/run-qa.sh +57 -0
- package/templates/skills/slack-interaction/content.md +4 -0
- package/templates/skills/swarm-extensions/content.md +2 -0
- package/templates/skills/swarm-scripts/SKILL.md +4 -2
- package/templates/skills/swarm-scripts/config.json +1 -1
- package/templates/skills/swarm-scripts/content.md +4 -2
- package/templates/skills/workflow-iterate/content.md +38 -0
- package/dist/artifact-eczsknc3.js +0 -3843
- package/dist/cli-9xsmdpdt.js +0 -56377
- package/dist/cli-bd957dgb.js +0 -153
- package/dist/cli-q51yprfq.js +0 -1104
- package/dist/cli-t1ze64h3.js +0 -811
- package/dist/index-9ch1n761.js +0 -1102
- package/src/artifact-sdk/index.ts +0 -2
- package/src/artifact-sdk/localtunnel.d.ts +0 -20
- package/src/artifact-sdk/port.ts +0 -12
- package/src/artifact-sdk/server.ts +0 -183
- package/src/artifact-sdk/tunnel.ts +0 -19
- package/src/commands/artifact.ts +0 -249
- package/src/http/ecosystem.ts +0 -77
- package/src/tests/artifact-commands.test.ts +0 -92
- package/src/tests/artifact-sdk.test.ts +0 -793
- package/src/tests/register-service-security.test.ts +0 -194
- package/src/tools/list-services.ts +0 -107
- package/src/tools/register-service.ts +0 -177
- package/src/tools/unregister-service.ts +0 -73
- package/src/tools/update-service-status.ts +0 -96
- package/templates/skills/artifacts/config.json +0 -14
- package/templates/skills/artifacts/content.md +0 -344
- package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
- package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
- package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
- package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
- package/dist/{azure-openai-responses-ap1gwxgr.js → azure-openai-responses-ygfreq4t.js} +5 -5
- package/dist/{cli-5rqrj7q0.js → cli-pw7ebjdt.js} +0 -0
- package/dist/{openai-codex-responses-33qhkkdy.js → openai-codex-responses-3bk0grnr.js} +4 -4
- package/dist/{openai-completions-s88xm3ns.js → openai-completions-5d4jpakc.js} +9 -9
- package/dist/{openai-responses-7xd2f2e2.js → openai-responses-krb51f59.js} +5 -5
- package/dist/{pi-messages-xszk613n.js → pi-messages-x9gzynm1.js} +3 -3
- /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
- /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test-only seams for the Chat SDK adapters. Production code never calls
|
|
3
|
+
* `setChatSdkTestHooks`, so every hook is unset in a running API. The
|
|
4
|
+
* operator schema rejects `webhookVerifier`, and this module is the only
|
|
5
|
+
* other way to set one.
|
|
6
|
+
*/
|
|
7
|
+
export interface ChatSdkTestHooks {
|
|
8
|
+
/**
|
|
9
|
+
* Replaces the Bot Framework JWT check of the Teams adapter. Tests cannot
|
|
10
|
+
* mint a Microsoft-signed token, so they inject `() => true`.
|
|
11
|
+
*/
|
|
12
|
+
teamsWebhookVerifier?: (request: Request, body: string) => boolean | Promise<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* Bot token factory for the Teams adapter, so an outbound send needs no
|
|
15
|
+
* MSAL call to login.microsoftonline.com.
|
|
16
|
+
*/
|
|
17
|
+
teamsToken?: () => string;
|
|
18
|
+
/**
|
|
19
|
+
* Skips the Discord Gateway loop. The loop logs in through `discord.js`
|
|
20
|
+
* against the real Discord API, which `apiUrl` does not redirect.
|
|
21
|
+
*/
|
|
22
|
+
disableDiscordGateway?: boolean;
|
|
23
|
+
/** Typing keepalive interval, shortened so a test sees several renewals. */
|
|
24
|
+
typingIntervalMs?: number;
|
|
25
|
+
/** Typing keepalive hard cap, shortened so a test can reach it. */
|
|
26
|
+
typingMaxMs?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let hooks: ChatSdkTestHooks = {};
|
|
30
|
+
|
|
31
|
+
export function setChatSdkTestHooks(next: ChatSdkTestHooks): void {
|
|
32
|
+
hooks = { ...next };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getChatSdkTestHooks(): Readonly<ChatSdkTestHooks> {
|
|
36
|
+
return hooks;
|
|
37
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Attachment } from "chat";
|
|
2
|
+
import { type AdditiveBuffer, createAdditiveBuffer } from "@/tasks/additive-buffer";
|
|
3
|
+
import { trackBackground } from "./background";
|
|
4
|
+
import { flushChatThread } from "./inbound";
|
|
5
|
+
import { stopTypingKeepalive } from "./typing";
|
|
6
|
+
|
|
7
|
+
/** One inbound message waiting in its thread's buffer. */
|
|
8
|
+
export interface ChatBufferedMessage {
|
|
9
|
+
messageId: string;
|
|
10
|
+
channelId: string;
|
|
11
|
+
/** Mention-stripped text. */
|
|
12
|
+
text: string;
|
|
13
|
+
userId: string;
|
|
14
|
+
userName?: string;
|
|
15
|
+
botMentioned: boolean;
|
|
16
|
+
isDirectMessage: boolean;
|
|
17
|
+
attachments: Attachment[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const DEFAULT_BUFFER_MS = 10_000;
|
|
21
|
+
|
|
22
|
+
function configuredBufferMs(): number {
|
|
23
|
+
const value = Number(process.env.CHAT_SDK_BUFFER_MS);
|
|
24
|
+
return Number.isFinite(value) && value > 0 ? value : DEFAULT_BUFFER_MS;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let buffer: AdditiveBuffer<ChatBufferedMessage> | undefined;
|
|
28
|
+
let bufferMs = 0;
|
|
29
|
+
/** Set while shutdown flushes every waiting thread; those flushes keep `dependsOn`. */
|
|
30
|
+
let draining = false;
|
|
31
|
+
/**
|
|
32
|
+
* Tail of each thread's flush chain. The additive buffer clears a key before
|
|
33
|
+
* it awaits `onFlush`, so a second flush of one thread can start while the
|
|
34
|
+
* first still routes, downloads files or creates its task. Chaining keeps the
|
|
35
|
+
* task order (and `dependsOn`) of one thread; different threads run in parallel.
|
|
36
|
+
*/
|
|
37
|
+
const flushChains = new Map<string, Promise<void>>();
|
|
38
|
+
|
|
39
|
+
/** Run `work` after every earlier flush of `threadId`. A failed flush does not block the next one. */
|
|
40
|
+
function runInThreadOrder(threadId: string, work: () => Promise<void>): Promise<void> {
|
|
41
|
+
const previous = flushChains.get(threadId) ?? Promise.resolve();
|
|
42
|
+
const run = previous.then(work);
|
|
43
|
+
const tail = run.catch(() => {});
|
|
44
|
+
flushChains.set(threadId, tail);
|
|
45
|
+
void tail.then(() => {
|
|
46
|
+
if (flushChains.get(threadId) === tail) flushChains.delete(threadId);
|
|
47
|
+
});
|
|
48
|
+
return run;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Keyed by the raw SDK `thread.id` (`<adapter>:<platform id>`, colons
|
|
53
|
+
* included); the key is never split. A changed `CHAT_SDK_BUFFER_MS` applies
|
|
54
|
+
* once no thread is waiting on the old timer.
|
|
55
|
+
*/
|
|
56
|
+
function getBuffer(): AdditiveBuffer<ChatBufferedMessage> {
|
|
57
|
+
const ms = configuredBufferMs();
|
|
58
|
+
if (!buffer || (ms !== bufferMs && buffer.keys().length === 0)) {
|
|
59
|
+
bufferMs = ms;
|
|
60
|
+
buffer = createAdditiveBuffer<ChatBufferedMessage>({
|
|
61
|
+
timeoutMs: ms,
|
|
62
|
+
label: "chat",
|
|
63
|
+
onFlush: async (items, threadId, reason) => {
|
|
64
|
+
// Read now: `draining` can change while this flush waits in the chain.
|
|
65
|
+
const immediate = reason === "manual" && !draining;
|
|
66
|
+
// Tracked so shutdown drains timer-driven flushes before the DB closes.
|
|
67
|
+
const work = runInThreadOrder(threadId, () => flushChatThread(threadId, items, immediate));
|
|
68
|
+
trackBackground(work);
|
|
69
|
+
// A failed flush created no task, so no relay will stop the indicator.
|
|
70
|
+
await work.catch(() => stopTypingKeepalive(threadId));
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return buffer;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Add a message to its thread's buffer and reset the debounce timer. */
|
|
78
|
+
export function bufferChatMessage(threadId: string, item: ChatBufferedMessage): void {
|
|
79
|
+
getBuffer().enqueue(threadId, item);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Flush now with no `dependsOn` (the `!now` command). */
|
|
83
|
+
export async function instantFlushChat(threadId: string): Promise<void> {
|
|
84
|
+
await getBuffer().instantFlush(threadId);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function isChatThreadBuffered(threadId: string): boolean {
|
|
88
|
+
return buffer?.isBuffered(threadId) ?? false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Shutdown: turn every waiting thread into its task instead of dropping it. */
|
|
92
|
+
export async function flushAllChatBuffers(): Promise<void> {
|
|
93
|
+
if (!buffer) return;
|
|
94
|
+
draining = true;
|
|
95
|
+
try {
|
|
96
|
+
for (const threadId of buffer.keys()) await buffer.instantFlush(threadId);
|
|
97
|
+
} finally {
|
|
98
|
+
draining = false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { errorMessage } from "./logger";
|
|
2
|
+
import { getChatInstance, isChatSdkStopping } from "./runtime";
|
|
3
|
+
import { assertTrustedChatTarget } from "./teams-origin";
|
|
4
|
+
import { getChatSdkTestHooks } from "./test-hooks";
|
|
5
|
+
|
|
6
|
+
/** Telegram shows one typing action for about 5 s, so renew it before that. */
|
|
7
|
+
const TYPING_INTERVAL_MS = 4_000;
|
|
8
|
+
/** Hard cap: a task that never relays must not show typing forever. */
|
|
9
|
+
const TYPING_MAX_MS = 15 * 60 * 1000;
|
|
10
|
+
|
|
11
|
+
const keepalives = new Map<string, ReturnType<typeof setInterval>>();
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Show the typing indicator in `threadId` until `stopTypingKeepalive`, the
|
|
15
|
+
* hard cap, or the adapter stops. Idempotent per thread id. Adapters without
|
|
16
|
+
* `startTyping` and untrusted Teams service URLs are skipped.
|
|
17
|
+
*/
|
|
18
|
+
export function startTypingKeepalive(adapter: string, threadId: string): void {
|
|
19
|
+
if (keepalives.has(threadId)) return;
|
|
20
|
+
// A shutdown flush creates tasks too; no indicator for a reply that comes after a restart.
|
|
21
|
+
if (isChatSdkStopping()) return;
|
|
22
|
+
// Typing sends the Teams bot token to the service URL in the thread id.
|
|
23
|
+
try {
|
|
24
|
+
assertTrustedChatTarget(threadId);
|
|
25
|
+
} catch {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (typeof getChatInstance(adapter)?.getAdapter(adapter)?.startTyping !== "function") return;
|
|
29
|
+
|
|
30
|
+
const hooks = getChatSdkTestHooks();
|
|
31
|
+
const maxMs = hooks.typingMaxMs ?? TYPING_MAX_MS;
|
|
32
|
+
const startedAt = Date.now();
|
|
33
|
+
let warned = false;
|
|
34
|
+
const sendTyping = async (): Promise<void> => {
|
|
35
|
+
const target = getChatInstance(adapter)?.getAdapter(adapter);
|
|
36
|
+
if (Date.now() - startedAt >= maxMs || typeof target?.startTyping !== "function") {
|
|
37
|
+
stopTypingKeepalive(threadId);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
await target.startTyping(threadId);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (warned) return;
|
|
44
|
+
warned = true;
|
|
45
|
+
console.warn(`[chat-sdk] Typing indicator failed for ${threadId}: ${errorMessage(error)}`);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const timer = setInterval(() => void sendTyping(), hooks.typingIntervalMs ?? TYPING_INTERVAL_MS);
|
|
49
|
+
timer.unref();
|
|
50
|
+
keepalives.set(threadId, timer);
|
|
51
|
+
void sendTyping();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function stopTypingKeepalive(threadId: string): void {
|
|
55
|
+
const timer = keepalives.get(threadId);
|
|
56
|
+
if (!timer) return;
|
|
57
|
+
clearInterval(timer);
|
|
58
|
+
keepalives.delete(threadId);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Stop every keepalive. For `stopChatSdk`. */
|
|
62
|
+
export function stopAllTypingKeepalives(): void {
|
|
63
|
+
for (const timer of keepalives.values()) clearInterval(timer);
|
|
64
|
+
keepalives.clear();
|
|
65
|
+
}
|
package/src/jira/adf.ts
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* debug line is emitted so unhandled cases surface during dev.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import { getNodeEnv } from "../utils/node-env";
|
|
17
|
+
|
|
16
18
|
type AdfNode = {
|
|
17
19
|
type?: string;
|
|
18
20
|
text?: string;
|
|
@@ -93,7 +95,7 @@ export function extractText(adf: unknown): string {
|
|
|
93
95
|
}
|
|
94
96
|
default: {
|
|
95
97
|
// Unknown node — descend into content if present.
|
|
96
|
-
if (
|
|
98
|
+
if (getNodeEnv() !== "production" && type) {
|
|
97
99
|
console.log(`[jira.adf] unknown node type: ${type}`);
|
|
98
100
|
}
|
|
99
101
|
for (const child of asNodeArray(node.content)) visit(child);
|
|
@@ -9,6 +9,8 @@ const RESERVED_FAMILIES = new Map([
|
|
|
9
9
|
// step-9: Comb's "Send to swarm" claims (`comb:sent`).
|
|
10
10
|
["comb", "namespace is reserved for Comb; use POST /api/comb/review-batches"],
|
|
11
11
|
["worker", "namespace is reserved for worker nudges"],
|
|
12
|
+
// Durable dedupe for SLACK_BLOCK_EXTERNAL_CHANNELS alerts (src/slack/external-channel.ts).
|
|
13
|
+
["slack-external-alert", "namespace is reserved for Slack external channel alerts"],
|
|
12
14
|
]);
|
|
13
15
|
|
|
14
16
|
export function isReservedNamespace(namespace: string): boolean {
|
package/src/oauth/mcp-wrapper.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as oauth from "oauth4webapi";
|
|
2
2
|
import { isEnvFlagEnabled } from "../utils/env-flag";
|
|
3
|
+
import { isDevOrTestNodeEnv } from "../utils/node-env";
|
|
3
4
|
import { registerVolatileSecret, scrubSecrets } from "../utils/secret-scrubber";
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -113,19 +114,22 @@ export function publicEndpointSsrfOptions(): SsrfGuardOptions {
|
|
|
113
114
|
// or the explicit override flag — may fetch private/insecure endpoints.
|
|
114
115
|
// Local dev entrypoints (`bun run dev:http` / `start:http`) set
|
|
115
116
|
// NODE_ENV=development.
|
|
116
|
-
const
|
|
117
|
-
const dev =
|
|
118
|
-
env === "development" || env === "test" || process.env.ALLOW_PRIVATE_NETWORK_URLS === "true";
|
|
117
|
+
const dev = isDevOrTestNodeEnv() || process.env.ALLOW_PRIVATE_NETWORK_URLS === "true";
|
|
119
118
|
return {
|
|
120
119
|
allowPrivateHosts: dev,
|
|
121
120
|
allowInsecure: dev,
|
|
122
121
|
};
|
|
123
122
|
}
|
|
124
123
|
|
|
125
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Guard for MCP OAuth endpoints (discovery, DCR, token exchange, refresh,
|
|
126
|
+
* revocation). http:// is allowed only in an explicit development/test
|
|
127
|
+
* environment; private hosts stay behind MCP_OAUTH_ALLOW_PRIVATE_HOSTS.
|
|
128
|
+
*/
|
|
129
|
+
export function mcpOAuthSsrfOptions(): SsrfGuardOptions {
|
|
126
130
|
return {
|
|
127
131
|
allowPrivateHosts: isEnvFlagEnabled("MCP_OAUTH_ALLOW_PRIVATE_HOSTS", false),
|
|
128
|
-
allowInsecure:
|
|
132
|
+
allowInsecure: isDevOrTestNodeEnv(),
|
|
129
133
|
};
|
|
130
134
|
}
|
|
131
135
|
|
|
@@ -144,7 +148,7 @@ async function safeFetch(
|
|
|
144
148
|
init?: RequestInit,
|
|
145
149
|
timeoutMs: number = DEFAULT_FETCH_TIMEOUT_MS,
|
|
146
150
|
): Promise<Response> {
|
|
147
|
-
assertUrlSafe(url,
|
|
151
|
+
assertUrlSafe(url, mcpOAuthSsrfOptions());
|
|
148
152
|
return fetch(url, { ...init, signal: init?.signal ?? AbortSignal.timeout(timeoutMs) });
|
|
149
153
|
}
|
|
150
154
|
|
package/src/otel-impl.ts
CHANGED
|
@@ -30,6 +30,7 @@ import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
|
30
30
|
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from "@opentelemetry/semantic-conventions";
|
|
31
31
|
import pkg from "../package.json";
|
|
32
32
|
import type { DbRetentionSweepMetric, SpanOptions, SwarmSpan, SwarmSpanKind } from "./otel";
|
|
33
|
+
import { getNodeEnv } from "./utils/node-env";
|
|
33
34
|
import { scrubSecrets } from "./utils/secret-scrubber";
|
|
34
35
|
|
|
35
36
|
type AttributeValue = string | number | boolean | string[] | number[] | boolean[];
|
|
@@ -174,7 +175,7 @@ export async function boot(serviceRole: string, options: BootOptions = {}): Prom
|
|
|
174
175
|
|
|
175
176
|
const configuredResourceAttributes = parseResourceAttributes();
|
|
176
177
|
const deploymentEnvironment =
|
|
177
|
-
configuredResourceAttributes["deployment.environment"] ||
|
|
178
|
+
configuredResourceAttributes["deployment.environment"] || getNodeEnv() || "development";
|
|
178
179
|
const serviceName = resolveServiceName(serviceRole);
|
|
179
180
|
sdk = new NodeSDK({
|
|
180
181
|
resource: resourceFromAttributes({
|
package/src/pages/version.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { createPageVersion, getPage
|
|
1
|
+
import { createPageVersion, getPage } from "../be/db";
|
|
2
|
+
import { getPageEditCounter } from "../be/db/page-versions";
|
|
2
3
|
import type { PageSnapshot, PageVersion } from "../types";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -8,7 +9,7 @@ import type { PageSnapshot, PageVersion } from "../types";
|
|
|
8
9
|
* Mirrors `snapshotWorkflow` (src/workflows/version.ts:13-44).
|
|
9
10
|
*
|
|
10
11
|
* 1. Load current page state
|
|
11
|
-
* 2. Get max version number for this page (page_versions
|
|
12
|
+
* 2. Get max version number for this page (MAX(page_versions.version))
|
|
12
13
|
* 3. Insert page_versions row with version+1 and the pre-update snapshot
|
|
13
14
|
*
|
|
14
15
|
* Throws on missing parent. Callers in HTTP handlers wrap this in a try/catch
|
|
@@ -24,9 +25,7 @@ export async function snapshotPage(
|
|
|
24
25
|
throw new Error(`Page ${pageId} not found — cannot create snapshot`);
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
const
|
|
28
|
-
const maxVersion = existingVersions.length > 0 ? existingVersions[0]!.version : 0;
|
|
29
|
-
const nextVersion = maxVersion + 1;
|
|
28
|
+
const nextVersion = await getPageEditCounter(pageId);
|
|
30
29
|
|
|
31
30
|
const snapshot: PageSnapshot = {
|
|
32
31
|
title: page.title,
|
|
@@ -8,11 +8,15 @@
|
|
|
8
8
|
* E outputs (gated on AGENT_FS_API_URL and the pages capability)
|
|
9
9
|
* H deployment-gated notes: slack, steering
|
|
10
10
|
* I tools and skills (harness tool discovery, skills, MCP server names)
|
|
11
|
-
* J agent notes: CLAUDE.md
|
|
12
|
-
* K repository (per task)
|
|
11
|
+
* J agent notes: CLAUDE.md, only when edited
|
|
13
12
|
*
|
|
14
|
-
* The runner appends the
|
|
15
|
-
*
|
|
13
|
+
* The runner appends the operator SYSTEM_PROMPT after this.
|
|
14
|
+
*
|
|
15
|
+
* Nothing here may vary per task, requester, or session: the provider caches
|
|
16
|
+
* the system prompt as a prefix, and one changed byte re-bills everything
|
|
17
|
+
* after it. Per-task context (repository, scripts-only Slack, requester
|
|
18
|
+
* profile, cwd warning) goes into the task prompt instead; see
|
|
19
|
+
* `getTaskContextPrompt` and the runner's `buildTaskSessionPrompts`.
|
|
16
20
|
*/
|
|
17
21
|
|
|
18
22
|
import type { ProviderTraits } from "../providers/types";
|
|
@@ -44,13 +48,28 @@ const BOOTSTRAP_TOTAL_MAX_CHARS = 120_000;
|
|
|
44
48
|
|
|
45
49
|
/**
|
|
46
50
|
* Per-section cap applied to the *repo* CLAUDE.md when it is inlined (opencode
|
|
47
|
-
* only). The agent-swarm OSS one is ~18 KB and the biggest
|
|
48
|
-
*
|
|
51
|
+
* only). The agent-swarm OSS one is ~18 KB and the biggest piece of the task
|
|
52
|
+
* context.
|
|
49
53
|
*/
|
|
50
54
|
const REPO_CLAUDE_MD_MAX_CHARS = 12_000;
|
|
51
55
|
|
|
52
|
-
/**
|
|
53
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Providers that get the agent's CLAUDE.md in the system prompt. Claude also
|
|
58
|
+
* keeps the editable copy at ~/.claude/CLAUDE.md but excludes it from its
|
|
59
|
+
* memory load (claude-flag-settings.ts), so it is read once, from the cached
|
|
60
|
+
* system prompt instead of an uncached message.
|
|
61
|
+
*/
|
|
62
|
+
const CLAUDE_MD_INJECT_PROVIDERS: ReadonlySet<string> = new Set([
|
|
63
|
+
"claude",
|
|
64
|
+
"codex",
|
|
65
|
+
"opencode",
|
|
66
|
+
"pi",
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
/** Where each provider's editable CLAUDE.md lives, for the truncation notice. */
|
|
70
|
+
function claudeMdSourcePath(provider: string): string {
|
|
71
|
+
return provider === "claude" ? "~/.claude/CLAUDE.md" : "/workspace/CLAUDE.md";
|
|
72
|
+
}
|
|
54
73
|
|
|
55
74
|
/** Providers that get the repo CLAUDE.md inlined until native loading is verified. */
|
|
56
75
|
const REPO_CLAUDE_MD_INLINE_PROVIDERS: ReadonlySet<string> = new Set(["opencode"]);
|
|
@@ -95,36 +114,61 @@ export type BasePromptArgs = {
|
|
|
95
114
|
soulMd?: string;
|
|
96
115
|
identityMd?: string;
|
|
97
116
|
claudeMd?: string;
|
|
98
|
-
repoContext?: {
|
|
99
|
-
claudeMd?: string | null;
|
|
100
|
-
clonePath: string;
|
|
101
|
-
warning?: string | null;
|
|
102
|
-
autoStashes?: { ref: string; message: string }[];
|
|
103
|
-
guidelines?: {
|
|
104
|
-
prChecks: string[];
|
|
105
|
-
mergeChecks: string[];
|
|
106
|
-
allowMerge?: boolean;
|
|
107
|
-
review: string[];
|
|
108
|
-
} | null;
|
|
109
|
-
};
|
|
110
|
-
/** Slack context from the current task, if present */
|
|
111
|
-
slackContext?: { channelId: string; threadTs?: string };
|
|
112
117
|
/** Pre-fetched skill summaries for the tools and skills section */
|
|
113
118
|
skillsSummary?: { name: string; description: string }[];
|
|
114
119
|
/** Names of the MCP servers connected for this agent */
|
|
115
120
|
mcpServers?: string[];
|
|
116
121
|
};
|
|
117
122
|
|
|
118
|
-
export
|
|
119
|
-
|
|
123
|
+
export type RepoContext = {
|
|
124
|
+
claudeMd?: string | null;
|
|
125
|
+
clonePath: string;
|
|
126
|
+
warning?: string | null;
|
|
127
|
+
autoStashes?: { ref: string; message: string }[];
|
|
128
|
+
guidelines?: {
|
|
129
|
+
prChecks: string[];
|
|
130
|
+
mergeChecks: string[];
|
|
131
|
+
allowMerge?: boolean;
|
|
132
|
+
review: string[];
|
|
133
|
+
} | null;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export type SlackTaskContext = { channelId: string; threadTs?: string };
|
|
137
|
+
|
|
138
|
+
/** Inputs for the per-task context that rides in the task prompt. */
|
|
139
|
+
export type TaskContextPromptArgs = Pick<
|
|
140
|
+
BasePromptArgs,
|
|
141
|
+
"role" | "traits" | "provider" | "scriptsOnly" | "serverCapabilities"
|
|
142
|
+
> & {
|
|
143
|
+
repoContext?: RepoContext;
|
|
144
|
+
/** Slack context from the current task, if present */
|
|
145
|
+
slackContext?: SlackTaskContext;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
function promptFlags(args: Pick<BasePromptArgs, "traits" | "provider" | "scriptsOnly">) {
|
|
120
149
|
const {
|
|
121
150
|
hasMcp = true,
|
|
122
151
|
hasToolSearch = false,
|
|
123
152
|
hasLocalEnvironment: hasLocalEnv = true,
|
|
124
153
|
nativeSkillDiscovery = true,
|
|
125
|
-
} = traits ?? {};
|
|
154
|
+
} = args.traits ?? {};
|
|
155
|
+
const scriptsOnly = args.scriptsOnly ?? process.env.SCRIPTS_ONLY_MCP === "true";
|
|
156
|
+
return {
|
|
157
|
+
hasMcp,
|
|
158
|
+
hasToolSearch,
|
|
159
|
+
hasLocalEnv,
|
|
160
|
+
nativeSkillDiscovery,
|
|
161
|
+
provider: args.provider ?? "claude",
|
|
162
|
+
// Experimental scripts-only MCP surface (code-mode).
|
|
163
|
+
scriptsOnlyMode: hasMcp && scriptsOnly,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
168
|
+
const { role, agentId, traits } = args;
|
|
169
|
+
const { hasMcp, hasToolSearch, hasLocalEnv, nativeSkillDiscovery, provider, scriptsOnlyMode } =
|
|
170
|
+
promptFlags(args);
|
|
126
171
|
const steerModes = traits?.steerModes ?? [];
|
|
127
|
-
const provider = args.provider ?? "claude";
|
|
128
172
|
|
|
129
173
|
const defaultsInput = {
|
|
130
174
|
name: args.name ?? agentId,
|
|
@@ -168,8 +212,6 @@ export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
|
168
212
|
|
|
169
213
|
// Experimental scripts-only MCP surface (code-mode): named swarm tools are
|
|
170
214
|
// not registered, so tell the agent everything goes through script-run.
|
|
171
|
-
const scriptsOnly = args.scriptsOnly ?? process.env.SCRIPTS_ONLY_MCP === "true";
|
|
172
|
-
const scriptsOnlyMode = hasMcp && scriptsOnly;
|
|
173
215
|
if (scriptsOnlyMode) {
|
|
174
216
|
const scriptsOnlyResult = await resolveTemplateAsync("system.agent.scripts_only_mode", {});
|
|
175
217
|
prompt += `\n${scriptsOnlyResult.text}`;
|
|
@@ -199,13 +241,6 @@ export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
|
199
241
|
const slackResult = await resolveTemplateAsync("system.agent.slack", {});
|
|
200
242
|
prompt += slackResult.text;
|
|
201
243
|
}
|
|
202
|
-
if (role !== "lead" && args.slackContext && scriptsOnlyMode && slackPromptToolsEnabled) {
|
|
203
|
-
const slackResult = await resolveTemplateAsync("system.agent.scripts_only_mode.slack", {
|
|
204
|
-
slackChannelId: args.slackContext.channelId,
|
|
205
|
-
slackThreadTs: args.slackContext.threadTs ?? "",
|
|
206
|
-
});
|
|
207
|
-
prompt += slackResult.text;
|
|
208
|
-
}
|
|
209
244
|
|
|
210
245
|
if (
|
|
211
246
|
hasMcp &&
|
|
@@ -244,9 +279,9 @@ export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
|
244
279
|
prompt += toolsResult.text;
|
|
245
280
|
}
|
|
246
281
|
|
|
247
|
-
// J. Agent notes (CLAUDE.md)
|
|
248
|
-
//
|
|
249
|
-
//
|
|
282
|
+
// J. Agent notes (CLAUDE.md), only when it differs from the generated
|
|
283
|
+
// default. Claude excludes both ~/.claude/CLAUDE.md and /workspace/CLAUDE.md
|
|
284
|
+
// from its memory load (claude-flag-settings.ts), so this is its only copy.
|
|
250
285
|
if (
|
|
251
286
|
hasLocalEnv &&
|
|
252
287
|
args.claudeMd &&
|
|
@@ -257,10 +292,42 @@ export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
|
257
292
|
BOOTSTRAP_MAX_CHARS,
|
|
258
293
|
Math.max(0, BOOTSTRAP_TOTAL_MAX_CHARS - prompt.length),
|
|
259
294
|
);
|
|
260
|
-
prompt += truncateSection(
|
|
295
|
+
prompt += truncateSection(
|
|
296
|
+
args.claudeMd,
|
|
297
|
+
"## Your notes (CLAUDE.md)",
|
|
298
|
+
claudeMdSourcePath(provider),
|
|
299
|
+
budget,
|
|
300
|
+
);
|
|
261
301
|
}
|
|
262
302
|
|
|
263
|
-
//
|
|
303
|
+
// Blocks start and end with a newline; collapse the seams to one blank line.
|
|
304
|
+
return prompt.replace(/\n{3,}/g, "\n\n");
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Per-task context that used to close the system prompt: the repository block
|
|
309
|
+
* and the scripts-only Slack note. It rides in the task prompt so the system
|
|
310
|
+
* prompt stays byte-identical across an agent's sessions. Empty when the task
|
|
311
|
+
* has neither.
|
|
312
|
+
*/
|
|
313
|
+
export const getTaskContextPrompt = async (args: TaskContextPromptArgs): Promise<string> => {
|
|
314
|
+
const { hasMcp, hasLocalEnv, provider, scriptsOnlyMode } = promptFlags(args);
|
|
315
|
+
let prompt = "";
|
|
316
|
+
|
|
317
|
+
if (
|
|
318
|
+
args.role !== "lead" &&
|
|
319
|
+
args.slackContext &&
|
|
320
|
+
scriptsOnlyMode &&
|
|
321
|
+
areSlackPromptToolsEnabled(process.env, args.serverCapabilities)
|
|
322
|
+
) {
|
|
323
|
+
const slackResult = await resolveTemplateAsync("system.agent.scripts_only_mode.slack", {
|
|
324
|
+
slackChannelId: args.slackContext.channelId,
|
|
325
|
+
slackThreadTs: args.slackContext.threadTs ?? "",
|
|
326
|
+
});
|
|
327
|
+
prompt += slackResult.text;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Repository. Never truncated except the inlined repo CLAUDE.md.
|
|
264
331
|
if (args.repoContext) {
|
|
265
332
|
const repoResult = await resolveTemplateAsync(
|
|
266
333
|
"system.agent.repository",
|
|
@@ -269,8 +336,7 @@ export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
|
269
336
|
prompt += repoResult.text;
|
|
270
337
|
}
|
|
271
338
|
|
|
272
|
-
|
|
273
|
-
return prompt.replace(/\n{3,}/g, "\n\n");
|
|
339
|
+
return prompt.replace(/\n{3,}/g, "\n\n").trim();
|
|
274
340
|
};
|
|
275
341
|
|
|
276
342
|
/**
|
|
@@ -331,7 +397,7 @@ function renderToolsAndSkillsVars(input: {
|
|
|
331
397
|
* the heading lives in the template, the per-task pieces are built here.
|
|
332
398
|
*/
|
|
333
399
|
function renderRepositoryVars(
|
|
334
|
-
repo:
|
|
400
|
+
repo: RepoContext,
|
|
335
401
|
ctx: { hasMcp: boolean; hasLocalEnv: boolean; provider: string },
|
|
336
402
|
): Record<string, string> {
|
|
337
403
|
const vars: Record<string, string> = {
|
|
@@ -432,7 +498,7 @@ export function truncateRepoClaudeMd(content: string, clonePath: string, budget:
|
|
|
432
498
|
function truncateSection(
|
|
433
499
|
content: string | undefined,
|
|
434
500
|
header: string,
|
|
435
|
-
|
|
501
|
+
sourcePath: string,
|
|
436
502
|
budget: number,
|
|
437
503
|
): string {
|
|
438
504
|
if (!content || budget <= 0) return "";
|
|
@@ -441,7 +507,7 @@ function truncateSection(
|
|
|
441
507
|
if (fullSection.length <= budget) return fullSection;
|
|
442
508
|
|
|
443
509
|
const headerStr = `\n\n${header}\n\n`;
|
|
444
|
-
const notice = `\n\n[...truncated, see
|
|
510
|
+
const notice = `\n\n[...truncated, see ${sourcePath} for full content]\n`;
|
|
445
511
|
const contentBudget = budget - headerStr.length - notice.length;
|
|
446
512
|
|
|
447
513
|
if (contentBudget > 0) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { openAICompatibleBaseUrlVars, openAICompatibleKeyVars } from "@desplega/model-catalog";
|
|
2
|
+
|
|
1
3
|
export const ACP_TARGET_IDS = [
|
|
2
4
|
"opencode",
|
|
3
5
|
"gemini",
|
|
@@ -40,6 +42,10 @@ export const ACP_TARGET_CATALOG: readonly AcpTargetCatalogEntry[] = [
|
|
|
40
42
|
"OPENAI_API_KEY",
|
|
41
43
|
"OPENROUTER_API_KEY",
|
|
42
44
|
"OPENROUTER_BASE_URL",
|
|
45
|
+
// OpenAI-compatible registry providers: keys (canonical and alias),
|
|
46
|
+
// then their `<ID>_BASE_URL` overrides.
|
|
47
|
+
...openAICompatibleKeyVars(),
|
|
48
|
+
...openAICompatibleBaseUrlVars(),
|
|
43
49
|
"GOOGLE_API_KEY",
|
|
44
50
|
"GEMINI_API_KEY",
|
|
45
51
|
"OPENCODE_CONFIG",
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { mkdir, mkdtemp, rm } from "node:fs/promises";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
baseUrlOverride,
|
|
6
|
+
normalizeGrokModel,
|
|
7
|
+
providerBaseUrl,
|
|
8
|
+
providerForModel,
|
|
9
|
+
} from "@desplega/model-catalog";
|
|
5
10
|
import { clampContextPercent, getContextWindowSize } from "../utils/context-window";
|
|
6
11
|
import {
|
|
7
12
|
ACP_TARGET_IDS,
|
|
@@ -9,7 +14,11 @@ import {
|
|
|
9
14
|
getAcpTargetCatalogEntry,
|
|
10
15
|
isAcpTarget,
|
|
11
16
|
} from "./acp-target-catalog";
|
|
12
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
applyOpenRouterBaseUrlOverride,
|
|
19
|
+
buildOpenAICompatibleProviderBlock,
|
|
20
|
+
type OpencodeConfig,
|
|
21
|
+
} from "./opencode-adapter";
|
|
13
22
|
import { applyReasoningEffort } from "./reasoning-effort";
|
|
14
23
|
import type { CostData, CostModelUsage, ProviderEvent, ProviderSessionConfig } from "./types";
|
|
15
24
|
|
|
@@ -140,10 +149,54 @@ function withOpencodeConfig(env: Record<string, string>, model: string): void {
|
|
|
140
149
|
}
|
|
141
150
|
}
|
|
142
151
|
if (model.trim()) value.model = model.trim();
|
|
152
|
+
withCustomProviderBlock(value as OpencodeConfig, model.trim(), env);
|
|
143
153
|
applyOpenRouterBaseUrlOverride(value as OpencodeConfig, env);
|
|
144
154
|
env[key] = JSON.stringify(value);
|
|
145
155
|
}
|
|
146
156
|
|
|
157
|
+
/**
|
|
158
|
+
* OpenCode ships no provider for a registry entry models.dev does not list
|
|
159
|
+
* (`catalog: "registry"`, e.g. `helmcode`), so its models need the custom
|
|
160
|
+
* block. The key stays an `{env:…}` reference: the ACP subprocess env is the
|
|
161
|
+
* forwarded per-task env, where the var holds one picked key, so no literal
|
|
162
|
+
* key lands in `OPENCODE_CONFIG_CONTENT`. A built-in registry provider
|
|
163
|
+
* (`nan`) only gets `options.baseURL` when `<ID>_BASE_URL` is set. Values the
|
|
164
|
+
* operator already set in `OPENCODE_CONFIG_CONTENT` win over the defaults.
|
|
165
|
+
*/
|
|
166
|
+
function withCustomProviderBlock(
|
|
167
|
+
config: OpencodeConfig,
|
|
168
|
+
model: string,
|
|
169
|
+
env: Record<string, string>,
|
|
170
|
+
): void {
|
|
171
|
+
const provider = providerForModel(model);
|
|
172
|
+
if (!provider) return;
|
|
173
|
+
const existing = config.provider?.[provider.id];
|
|
174
|
+
if (provider.catalog !== "registry") {
|
|
175
|
+
const baseURL = baseUrlOverride(provider, env);
|
|
176
|
+
if (!baseURL) return;
|
|
177
|
+
config.provider = {
|
|
178
|
+
...config.provider,
|
|
179
|
+
[provider.id]: { ...existing, options: { baseURL, ...existing?.options } },
|
|
180
|
+
};
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const block = buildOpenAICompatibleProviderBlock(
|
|
184
|
+
provider,
|
|
185
|
+
`{env:${provider.envVar}}`,
|
|
186
|
+
model.slice(provider.id.length + 1),
|
|
187
|
+
providerBaseUrl(provider, env),
|
|
188
|
+
);
|
|
189
|
+
config.provider = {
|
|
190
|
+
...config.provider,
|
|
191
|
+
[provider.id]: {
|
|
192
|
+
...block,
|
|
193
|
+
...existing,
|
|
194
|
+
options: { ...block.options, ...existing?.options },
|
|
195
|
+
models: { ...block.models, ...existing?.models },
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
147
200
|
function parseCommand(command: string, args: string | undefined): string[] {
|
|
148
201
|
const trimmed = command.trim();
|
|
149
202
|
if (!trimmed) {
|
|
@@ -252,7 +305,7 @@ const geminiTargetProfile: AcpTargetProfile = {
|
|
|
252
305
|
/**
|
|
253
306
|
* Copilot CLI has no system-prompt flag. Under `--acp` it reads custom
|
|
254
307
|
* instructions from the git root, the cwd, and every directory listed in
|
|
255
|
-
* COPILOT_CUSTOM_INSTRUCTIONS_DIRS. Verified against 1.0.
|
|
308
|
+
* COPILOT_CUSTOM_INSTRUCTIONS_DIRS. Verified against 1.0.97: from those extra
|
|
256
309
|
* directories it loads `.github/instructions/*.instructions.md`, but not
|
|
257
310
|
* `AGENTS.md`. So the swarm prompt goes into a per-task directory outside the
|
|
258
311
|
* repo, and the repo's own AGENTS.md is never touched.
|