@desplega.ai/agent-swarm 2.7.5 → 2.7.7
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/dist/{acp-adapter-g3ads55s.js → acp-adapter-7b4vk3h5.js} +5 -4
- package/dist/{actions-zwfykqqk.js → actions-3tt153af.js} +18 -17
- package/dist/{amp-adapter-z3s0ssdt.js → amp-adapter-njpts0yr.js} +1 -1
- package/dist/{anthropic-messages-x4q6rfq5.js → anthropic-messages-xey2skwx.js} +7 -7
- package/dist/{app-vmp4fgep.js → app-nky4378f.js} +3 -3
- package/dist/{assistant-vwde653f.js → assistant-jnb669pa.js} +24 -22
- package/dist/{azure-openai-responses-s1w5n70z.js → azure-openai-responses-26t7j9ra.js} +5 -5
- package/dist/{boot-reembed-375t7tbk.js → boot-reembed-9mgvaztt.js} +1 -1
- package/dist/{boot-reembed-gq9rcpnj.js → boot-reembed-qs2djdej.js} +1 -1
- package/dist/{boot-scrub-sweep-nd938kyf.js → boot-scrub-sweep-yjpdj7s1.js} +3 -3
- package/dist/{boot-seeds-aykx51v3.js → boot-seeds-5cm6ambd.js} +4 -4
- package/dist/{boxd-k1j26g3h.js → boxd-nv507va8.js} +5 -5
- package/dist/{claude-adapter-8j4hm099.js → claude-adapter-fn287zmm.js} +5 -4
- package/dist/{claude-managed-setup-0wyynpn1.js → claude-managed-setup-wtdz2mj2.js} +1 -1
- package/dist/{claude-sdk-session-q6wj5hmy.js → claude-sdk-session-x91kqyhm.js} +9677 -9514
- package/dist/{cli-j3jvnpe8.js → cli-08bmz9z9.js} +1 -1
- package/dist/{cli-gjr2y2xk.js → cli-0agcv1v5.js} +4 -1
- package/dist/{cli-y24sc29k.js → cli-1c6tzt8g.js} +30 -8
- package/dist/{cli-mjzynrse.js → cli-35rsp8ye.js} +1 -1
- package/dist/{cli-rpm2sgv0.js → cli-3fg0bdcv.js} +19 -2
- package/dist/{cli-nn4d8dne.js → cli-5b456bpf.js} +2 -2
- package/dist/{cli-bhjt02p8.js → cli-5jnhv72d.js} +1 -1
- package/dist/{cli-fqzx7gwa.js → cli-5zx699j9.js} +2 -2
- package/dist/{cli-hf6zt5m6.js → cli-69szn7w7.js} +17 -1
- package/dist/{cli-vqypxzh4.js → cli-6g0hb4cp.js} +8 -8
- package/dist/{cli-tqgg40ek.js → cli-6pfd54vx.js} +9 -8
- package/dist/{cli-bsn8nhrq.js → cli-6vcp76qk.js} +3 -3
- package/dist/{cli-zppwg9p9.js → cli-72v799xn.js} +1 -1
- package/dist/cli-82j36f2m.js +45 -0
- package/dist/{cli-hn9hxmz9.js → cli-8305gbq0.js} +29 -16
- package/dist/{cli-z8eh3ex8.js → cli-8sckt74b.js} +8 -8
- package/dist/{cli-bnz7a7qf.js → cli-95jzxcp3.js} +1 -1
- package/dist/{cli-0bxqnvq9.js → cli-adeegh7d.js} +29 -7
- package/dist/{cli-g61qxmge.js → cli-afkqkrtw.js} +3 -3
- package/dist/{cli-7a42nfy0.js → cli-ayayvfg4.js} +24 -4
- package/dist/{cli-bqt1mptt.js → cli-az48n0nr.js} +4 -4
- package/dist/{cli-z6jkx23q.js → cli-bfv7vdg6.js} +9 -9
- package/dist/{cli-pywf3eh5.js → cli-caj33vcq.js} +5 -5
- package/dist/{cli-5pag6rmn.js → cli-cb2a8pna.js} +1 -1
- package/dist/{cli-wvaawacd.js → cli-cppkf404.js} +5236 -72
- package/dist/{cli-mry0qzym.js → cli-ddaanqkd.js} +123 -10
- package/dist/{cli-0gey5fzy.js → cli-e0kmphd6.js} +2 -2
- package/dist/{cli-zh3fp8v2.js → cli-e46hg0xw.js} +1 -1
- package/dist/{cli-jm2vfpfd.js → cli-e5bzrn01.js} +1 -1
- package/dist/{cli-qxnf8z2z.js → cli-excnnjg2.js} +165 -153
- package/dist/{cli-71ptav7x.js → cli-ferkkrg9.js} +1 -1
- package/dist/{cli-vpf89f34.js → cli-fmjd0t1y.js} +3 -3
- package/dist/{cli-rm6hqj3z.js → cli-fyt2g4wd.js} +33 -139
- package/dist/cli-g08zdaec.js +55 -0
- package/dist/{cli-ehq736cn.js → cli-g7s47cc5.js} +4 -4
- package/dist/{cli-82ae98pz.js → cli-gz6q4eve.js} +3 -3
- package/dist/{cli-82jg7fp9.js → cli-he5nxaa8.js} +1 -1
- package/dist/{cli-rqkxrmgw.js → cli-je518txm.js} +39 -14
- package/dist/{cli-8hs41zy2.js → cli-jtjtabxe.js} +1 -1
- package/dist/{cli-611a1294.js → cli-k0wwfqbg.js} +18 -1
- package/dist/{cli-nzxr556s.js → cli-k1nje3v3.js} +38 -43
- package/dist/{cli-3h4nhjn8.js → cli-k8196sh2.js} +9 -7
- package/dist/{cli-afrrppsw.js → cli-k899ehvh.js} +2 -2
- package/dist/{cli-0731hvbw.js → cli-m0da8j35.js} +23 -9
- package/dist/cli-m2z8jagn.js +12078 -0
- package/dist/{cli-8veytvbh.js → cli-mkk9rnzz.js} +5 -5
- package/dist/{cli-7wspm5gm.js → cli-n6bv12jn.js} +528 -6
- package/dist/{cli-spknvxbq.js → cli-nmzhp1b5.js} +14 -12
- package/dist/{cli-p599f1qm.js → cli-p82cnnjq.js} +1 -1
- package/dist/{cli-xtjhfmpc.js → cli-pc6n7fre.js} +1 -1
- package/dist/{cli-vbyfwh92.js → cli-pjctyea3.js} +2 -2
- package/dist/{cli-nmbmy64z.js → cli-pq73h5mz.js} +3 -3
- package/dist/{cli-aa6yxc7m.js → cli-pz4rk021.js} +1 -1
- package/dist/{cli-7wcyk2s5.js → cli-q3tkegby.js} +1 -1
- package/dist/cli-qghe0h66.js +67 -0
- package/dist/{cli-6s7vdcta.js → cli-qh4d4tvk.js} +4 -4
- package/dist/{cli-mmwm7zbf.js → cli-rtt8g4v9.js} +1 -1
- package/dist/{cli-kg8hchyg.js → cli-sa02jsqt.js} +1 -1
- package/dist/{cli-1h3wcpbw.js → cli-snpj5zbj.js} +2 -2
- package/dist/{cli-a7v854rf.js → cli-tgrv9cjx.js} +263 -12
- package/dist/{cli-a47xy8eq.js → cli-vz22fyqv.js} +186 -54
- package/dist/{cli-1ayk1eas.js → cli-wk5yrfwd.js} +285 -42
- package/dist/{cli-1338796d.js → cli-ws19768n.js} +1755 -119
- package/dist/{cli-70r77n04.js → cli-xae4g51r.js} +1 -1
- package/dist/{cli-gf5hbmdr.js → cli-yjdgea32.js} +3 -3
- package/dist/{cli-xbkdm710.js → cli-yndmfxb3.js} +3 -3
- package/dist/{cli-rhw40jgb.js → cli-yyj3j5m4.js} +2 -2
- package/dist/cli.js +26 -25
- package/dist/{cloudflare-workers-ai-system-one-bm60fjm0.js → cloudflare-workers-ai-system-one-ef2a980q.js} +2 -2
- package/dist/{codex-adapter-q6k3gnyg.js → codex-adapter-cf2yxe9m.js} +3 -2
- package/dist/{codex-hook-9efm2x1m.js → codex-hook-a0c6g6t6.js} +1 -1
- package/dist/{codex-session-runner-3mwmk3d9.js → codex-session-runner-6vfzdgbd.js} +3 -2
- package/dist/{commands-evrenjn9.js → commands-t3mfy7vn.js} +9 -3
- package/dist/{controller-xjp8vswh.js → controller-q7xrbaz0.js} +8 -3
- package/dist/{controllers-connect-pp5jnxvc.js → controllers-connect-c6nm70kg.js} +20 -19
- package/dist/{cursor-adapter-yf47w4t0.js → cursor-adapter-ftd81ga8.js} +1 -1
- package/dist/{db-zxpw6aht.js → db-dk572x25.js} +3 -3
- package/dist/{db-rgfsh91f.js → db-vemtpmcc.js} +14 -4
- package/dist/{devtools-82fzqra8.js → devtools-qxfgbsqz.js} +1 -1
- package/dist/{dispatcher-smasgws7.js → dispatcher-kh7ecxh9.js} +17 -16
- package/dist/{docker-rrjhaqt9.js → docker-c1a3gqmf.js} +89 -22
- package/dist/{dsh-adapter-ftyy8dnp.js → dsh-adapter-v8628r89.js} +1 -1
- package/dist/{e2b-w1p0bnpm.js → e2b-fr12yccx.js} +5 -5
- package/dist/{e2b-qcaj675y.js → e2b-x6ywzak3.js} +3 -3
- package/dist/{easter-egg-3d-yyts7p16.js → easter-egg-3d-nenw4x63.js} +1 -1
- package/dist/{embedding-space-1z0mbg95.js → embedding-space-0jepb239.js} +6 -6
- package/dist/{embeddings-ygeg7tm7.js → embeddings-xxt49yxg.js} +1 -1
- package/dist/{execute-14qhqp4d.js → execute-1mhw6e4x.js} +1 -1
- package/dist/{external-channel-ttgrs3sx.js → external-channel-55v12e60.js} +2 -2
- package/dist/{fx-adapter-gt6pncj2.js → fx-adapter-bs8wqrk5.js} +6 -5
- package/dist/{google-generative-ai-yvmdxyxa.js → google-generative-ai-v94hr7h0.js} +5 -5
- package/dist/{google-vertex-jrtdh9gs.js → google-vertex-g7vr6cf8.js} +5 -5
- package/dist/{grok-adapter-sm4m5k4g.js → grok-adapter-gpjqmkcq.js} +6 -5
- package/dist/handlers-zxmp1ta4.js +32 -0
- package/dist/{heartbeat-qahz4p62.js → heartbeat-k42svnr0.js} +20 -19
- package/dist/{hook-4fd5wq5w.js → hook-114m7hap.js} +4 -3
- package/dist/{hook-kj3d398m.js → hook-6nphweh0.js} +24 -9
- package/dist/{http-1ted0j1k.js → http-r8cc4wz7.js} +1196 -211
- package/dist/index-a8phxqnk.js +37 -0
- package/dist/{index-q4b917zs.js → index-e3s8wmxy.js} +1 -1
- package/dist/{index-6rq3r5zb.js → index-fpk4bcd9.js} +1 -1
- package/dist/{index-5rk6rfzr.js → index-fvzke5kx.js} +1 -1
- package/dist/index-k6h00t4c.js +30 -0
- package/dist/{index-7v51awbn.js → index-nh3wyqdt.js} +1027 -577
- package/dist/{index-yqhz88yy.js → index-pxn30mse.js} +8 -8
- package/dist/index-xrz7te8h.js +33 -0
- package/dist/{keepalive-6cf311t5.js → keepalive-x060nt9p.js} +3 -3
- package/dist/lead-956sd2yc.js +71 -0
- package/dist/{maintenance-a4bm1bmt.js → maintenance-2xxfexhf.js} +1 -1
- package/dist/{mistral-conversations-4pmwj1c0.js → mistral-conversations-3gjpdb4b.js} +4 -4
- package/dist/{oauth-refresh-sweep-3h0dfw1k.js → oauth-refresh-sweep-fckc4ar5.js} +2 -2
- package/dist/{onboard-myn5hraa.js → onboard-zc48j237.js} +5 -5
- package/dist/{openai-codex-responses-44j573nm.js → openai-codex-responses-8pbxq9h5.js} +5 -5
- package/dist/{openai-completions-a4gee2a8.js → openai-completions-rm00s912.js} +4 -4
- package/dist/{openai-decisions-w4qkrcar.js → openai-decisions-8v957r2r.js} +1 -1
- package/dist/{openai-responses-rbp6h5kr.js → openai-responses-agxpf96k.js} +5 -5
- package/dist/{opencode-adapter-p2nkb5am.js → opencode-adapter-r690h1cr.js} +4 -3
- package/dist/{otel-impl-a1a0ef6b.js → otel-impl-r5xbh81q.js} +4 -4
- package/dist/{pi-mono-adapter-rzmpb72a.js → pi-mono-adapter-c7v8sdec.js} +7 -6
- package/dist/{pricing-refresh-83drrnxj.js → pricing-refresh-3pmre11v.js} +3 -3
- package/dist/{rbac-roles-s8y6ecb5.js → rbac-roles-3vbshwsb.js} +1 -1
- package/dist/{rbac-roles-0fb6e7pj.js → rbac-roles-910mmkgz.js} +2 -2
- package/dist/{render-v2-twmbgrz4.js → render-v2-pxykkbab.js} +3 -3
- package/dist/{resume-zfqc36xj.js → resume-adda0bwy.js} +6 -6
- package/dist/{runtime-qwggdpqr.js → runtime-fnbm7stk.js} +1 -1
- package/dist/{session-access-sc9pn9da.js → session-access-2fvamrdc.js} +4 -4
- package/dist/{session-source-backfill-qh07xr8g.js → session-source-backfill-08xvv0sm.js} +2 -2
- package/dist/{setup-4fr0m7a1.js → setup-1aqmvmh1.js} +3 -3
- package/dist/{typesafe-system-one-5mavm259.js → typesafe-system-one-0bmqcxfg.js} +2 -2
- package/dist/{virtual-modules-fh4ha15b.js → virtual-modules-d2pjk9j1.js} +5 -5
- package/dist/{work-objects-0wr8zxct.js → work-objects-9s0yrm5j.js} +20 -19
- package/dist/{worker-follow-up-ktyyazyp.js → worker-follow-up-3q78fqmr.js} +17 -16
- package/dist/worker-y15hy08h.js +71 -0
- package/openapi.json +289 -4
- package/package.json +9 -8
- package/src/apps/definition.ts +6 -5
- package/src/be/db/page-theme-tokens.ts +12 -0
- package/src/be/db/script-runs.ts +23 -0
- package/src/be/db/tasks/read.ts +131 -4
- package/src/be/db/tasks/write.ts +19 -0
- package/src/be/db-client.ts +114 -11
- package/src/be/db.ts +49 -6
- package/src/be/memory/providers/sqlite-store.ts +49 -12
- 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/migrations/269_pages_design_system.sql +23 -0
- 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 +22 -0
- package/src/be/seed/schedules-seeder.ts +0 -10
- package/src/be/seed-scripts/catalog/catalog-report.inline.ts +2 -0
- package/src/be/seed-scripts/catalog/catalog-report.ts +2 -0
- package/src/be/seed-scripts/catalog/memory-eval.ts +2 -0
- package/src/be/seed-scripts/catalog/swarm-update-check.ts +150 -0
- package/src/be/seed-scripts/catalog/task-failure-audit.ts +5 -1
- package/src/be/seed-scripts/index.ts +9 -0
- package/src/be/seed-skills/bundled-files.generated.json +3 -3
- package/src/be/swarm-config-guard.ts +32 -0
- package/src/be/task-auto-title-listener.ts +127 -0
- package/src/commands/controller.ts +4 -0
- package/src/commands/entrypoint-api-readiness.ts +74 -0
- package/src/commands/onboard/agent-fs-version.ts +1 -1
- package/src/commands/profile-sync.ts +151 -16
- package/src/commands/runner.ts +15 -7
- package/src/hooks/hook.ts +20 -9
- package/src/http/index.ts +4 -1
- package/src/http/list-total-cache.ts +14 -7
- package/src/http/memory.ts +38 -9
- package/src/http/pages-public.ts +93 -129
- package/src/http/pages.ts +94 -21
- package/src/http/script-runs.ts +174 -5
- package/src/http/status.ts +10 -2
- package/src/http/tasks.ts +4 -2
- package/src/pages/browser-sdk.ts +48 -21
- package/src/pages/color-literals.ts +115 -0
- package/src/pages/page-head.ts +766 -0
- package/src/pages/version.ts +3 -0
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/codex-adapter.ts +1 -0
- package/src/providers/codex-app-server.ts +27 -1
- package/src/providers/fx-adapter.ts +1 -1
- package/src/providers/pi-mono-extension.ts +30 -15
- 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/script-workflows/workflow-ctx.ts +8 -0
- package/src/scripts-runtime/types/stdlib.d.ts +22 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +22 -0
- package/src/server-user.ts +1 -0
- package/src/slack/commands.ts +5 -1
- package/src/slack/handlers.ts +37 -2
- package/src/slack/left-threads.ts +27 -4
- package/src/tasks/follow-up-gate.ts +318 -0
- package/src/tasks/follow-up-redelegation-guard.ts +155 -0
- package/src/tasks/worker-follow-up.ts +21 -1
- package/src/tests/claude-artifacts-read-script.test.ts +209 -0
- package/src/tests/codex-app-server.test.ts +59 -0
- package/src/tests/codex-gateway-route.test.ts +50 -1
- package/src/tests/create-page-tool.test.ts +501 -0
- package/src/tests/db-client-busy-retry.test.ts +81 -0
- package/src/tests/db-client.test.ts +21 -0
- package/src/tests/db-task-read-contract.test.ts +9 -2
- package/src/tests/db-task-write-contract.test.ts +7 -1
- package/src/tests/db-tasks-read.test.ts +21 -0
- package/src/tests/entrypoint-api-readiness.test.ts +416 -210
- package/src/tests/explicit-model-validation.test.ts +14 -8
- package/src/tests/fixtures/pages/head-v1.html +56 -0
- package/src/tests/follow-up-gate-shadow.test.ts +513 -0
- package/src/tests/follow-up-redelivery-guard.test.ts +432 -202
- package/src/tests/identity-field-budget.test.ts +1 -1
- package/src/tests/internal-ai/credentials.test.ts +62 -0
- package/src/tests/internal-ai/task-title.test.ts +283 -0
- package/src/tests/list-total-cache.test.ts +27 -2
- package/src/tests/memory-fts-populate.test.ts +11 -9
- package/src/tests/memory-retrieval-purge.test.ts +80 -0
- package/src/tests/merge-gate-detect-changes.test.ts +145 -0
- package/src/tests/migration-260-runtime-pool-cache.test.ts +118 -0
- package/src/tests/page-proxy.test.ts +1 -1
- package/src/tests/page-session-dev-cookie.test.ts +188 -0
- package/src/tests/pages-frame-ancestors.test.ts +28 -1
- package/src/tests/pages-head-v2.test.ts +534 -0
- package/src/tests/pages-http.test.ts +330 -0
- package/src/tests/pages-public-html.test.ts +43 -0
- package/src/tests/pages-storage.test.ts +182 -0
- package/src/tests/pages-versioning.test.ts +72 -0
- package/src/tests/profile-sync-stale-writeback.test.ts +334 -0
- package/src/tests/profile-sync.test.ts +11 -15
- package/src/tests/query-audit-plans.test.ts +27 -0
- 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/scheduled-task-required-params-migration.test.ts +3 -1
- package/src/tests/script-connections.test.ts +13 -0
- package/src/tests/script-runs-http.test.ts +684 -2
- package/src/tests/seed-registry.test.ts +28 -6
- package/src/tests/seed-schedules.test.ts +61 -8
- package/src/tests/seed-scripts.test.ts +168 -2
- package/src/tests/slack-leave-thread.test.ts +145 -5
- package/src/tests/slack-render-v2-query-plans.test.ts +24 -2
- package/src/tests/status.test.ts +11 -0
- package/src/tests/swarm-diff.test.ts +121 -2
- package/src/tests/task-auto-title-config-guard.test.ts +37 -0
- package/src/tests/task-auto-title-listener.test.ts +165 -0
- package/src/tests/tasks-readable-row.test.ts +155 -0
- package/src/tests/theme-import.test.ts +758 -0
- package/src/tests/themes-page-theme.test.ts +155 -0
- package/src/tests/themes-presets.test.ts +172 -0
- package/src/tests/workflow-script-principal.test.ts +2 -1
- package/src/themes/classics.ts +949 -0
- package/src/themes/import.ts +420 -0
- package/src/themes/page-fields.ts +40 -0
- package/src/themes/page-theme.ts +102 -0
- package/src/themes/presets.ts +561 -0
- package/src/themes/tokens.ts +218 -0
- package/src/tools/app-upsert.ts +1 -1
- package/src/tools/create-page.ts +118 -12
- package/src/tools/send-task.ts +35 -47
- package/src/tools/slack-leave-thread.ts +1 -1
- package/src/tools/task-dedup.ts +45 -21
- package/src/tools/utils.ts +33 -0
- package/src/types.ts +83 -3
- package/src/utils/constants.ts +19 -0
- package/src/utils/follow-up-gate-schedule-ids.ts +13 -0
- package/src/utils/internal-ai/credentials.ts +146 -93
- package/src/utils/internal-ai/index.ts +10 -0
- package/src/utils/internal-ai/models.ts +18 -0
- package/src/utils/internal-ai/task-title.ts +282 -0
- package/src/utils/page-session.ts +37 -0
- package/templates/schedules/daily-status-report/content.md +88 -2
- package/templates/schedules/daily-swarm-update-check/content.md +16 -40
- package/templates/skills/apps/SKILL.md +1 -1
- package/templates/skills/apps/content.md +1 -1
- package/templates/skills/composio-google-docs/content.md +10 -0
- package/templates/skills/heartbeat-runbook/content.md +1 -1
- package/templates/skills/pages/config.json +1 -1
- package/templates/skills/pages/content.md +539 -86
- package/templates/skills/pages/files/examples/annotated-pr.html +21 -12
- package/templates/skills/pages/files/examples/multiplayer-board.html +41 -41
- package/templates/skills/pages/files/examples/report-page.html +125 -124
- package/templates/skills/script-workflows/content.md +19 -1
- package/templates/skills/swarm-docs/content.md +1 -0
- package/templates/skills/swarm-scripts/SKILL.md +2 -0
- package/templates/skills/swarm-scripts/content.md +2 -0
- package/dist/cli-2pnswgh8.js +0 -189
- package/dist/cli-dznrgaep.js +0 -30
- package/dist/cli-w3hcrxht.js +0 -6985
- package/dist/handlers-vwmba1m2.js +0 -31
- package/dist/index-5r71rf98.js +0 -32
- package/dist/index-anmwxs87.js +0 -29
- package/dist/index-spp0ra5c.js +0 -36
- package/dist/lead-fjy418cw.js +0 -69
- package/dist/worker-0c5tyzqe.js +0 -69
- package/templates/schedules/daily-workflow-health-audit/config.json +0 -19
- package/templates/schedules/daily-workflow-health-audit/content.md +0 -191
package/src/pages/version.ts
CHANGED
|
@@ -35,6 +35,9 @@ export async function snapshotPage(
|
|
|
35
35
|
passwordHash: page.passwordHash,
|
|
36
36
|
body: page.body,
|
|
37
37
|
needsCredentials: page.needsCredentials,
|
|
38
|
+
theme: page.theme,
|
|
39
|
+
themeTokens: page.themeTokens,
|
|
40
|
+
designVersion: page.designVersion,
|
|
38
41
|
};
|
|
39
42
|
|
|
40
43
|
return createPageVersion({
|
|
@@ -45,7 +45,7 @@ import type {
|
|
|
45
45
|
* default; the image installs exactly this version and the per-task settings
|
|
46
46
|
* set `amp.updates.mode: "disabled"`. Bump it deliberately, with a live run.
|
|
47
47
|
*/
|
|
48
|
-
export const AMP_PACKAGE = "@ampcode/cli@0.0.
|
|
48
|
+
export const AMP_PACKAGE = "@ampcode/cli@0.0.1793450357-gd44904";
|
|
49
49
|
|
|
50
50
|
/** MCP server name. Amp exposes its tools as `agent_swarm` / `store_progress` (dashes become underscores). */
|
|
51
51
|
const AMP_MCP_SERVER_NAME = "agent-swarm";
|
|
@@ -2053,6 +2053,7 @@ export async function createInProcessCodexSession(
|
|
|
2053
2053
|
const appServerFactory = opts.appServerFactory ?? ((options) => new CodexAppServer(options));
|
|
2054
2054
|
const client = appServerFactory({
|
|
2055
2055
|
...(codexPathOverride ? { codexPath: codexPathOverride } : {}),
|
|
2056
|
+
...(gateway ? { configOverrides: codexGatewayConfig(gateway) } : {}),
|
|
2056
2057
|
env,
|
|
2057
2058
|
onStderr: (line) => {
|
|
2058
2059
|
if (liveSession) liveSession.emitTransportStderr(line);
|
|
@@ -26,6 +26,7 @@ export interface CodexAppServerOptions {
|
|
|
26
26
|
env: Readonly<Record<string, string | undefined>>;
|
|
27
27
|
requestTimeoutMs?: number;
|
|
28
28
|
onStderr?: (line: string) => void;
|
|
29
|
+
configOverrides?: Readonly<Record<string, CodexConfigValue | undefined>>;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
type PendingRequest = {
|
|
@@ -53,6 +54,25 @@ export class CodexAppServerRpcError extends Error {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
/** `-c key=<TOML value>` pairs, one per top-level key; tables become inline tables. */
|
|
58
|
+
export function configOverrideArgs(
|
|
59
|
+
overrides: Readonly<Record<string, CodexConfigValue | undefined>> = {},
|
|
60
|
+
): string[] {
|
|
61
|
+
return Object.entries(overrides).flatMap(([key, value]) =>
|
|
62
|
+
value === undefined ? [] : ["-c", `${key}=${tomlValue(value)}`],
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function tomlValue(value: CodexConfigValue): string {
|
|
67
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
68
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
69
|
+
if (Array.isArray(value)) return `[${value.map(tomlValue).join(", ")}]`;
|
|
70
|
+
const fields = Object.entries(value as Record<string, CodexConfigValue | undefined>).flatMap(
|
|
71
|
+
([key, field]) => (field === undefined ? [] : [`${JSON.stringify(key)} = ${tomlValue(field)}`]),
|
|
72
|
+
);
|
|
73
|
+
return `{ ${fields.join(", ")} }`;
|
|
74
|
+
}
|
|
75
|
+
|
|
56
76
|
/** Thin JSONL client for one `codex app-server --listen stdio://` process. */
|
|
57
77
|
export class CodexAppServer {
|
|
58
78
|
private readonly proc: ReturnType<typeof Bun.spawn>;
|
|
@@ -79,7 +99,13 @@ export class CodexAppServer {
|
|
|
79
99
|
this.onStderr = options.onStderr;
|
|
80
100
|
|
|
81
101
|
const codexPath = options.codexPath ?? resolveCodexPath(options.env.PATH);
|
|
82
|
-
const command = [
|
|
102
|
+
const command = [
|
|
103
|
+
codexPath,
|
|
104
|
+
...configOverrideArgs(options.configOverrides),
|
|
105
|
+
"app-server",
|
|
106
|
+
"--listen",
|
|
107
|
+
"stdio://",
|
|
108
|
+
];
|
|
83
109
|
|
|
84
110
|
const env = Object.fromEntries(
|
|
85
111
|
Object.entries(options.env).filter(
|
|
@@ -21,7 +21,7 @@ import type {
|
|
|
21
21
|
* Dockerfile.worker; bump the two together). Every ACP shape this adapter
|
|
22
22
|
* relies on was measured against it.
|
|
23
23
|
*/
|
|
24
|
-
export const FX_PINNED_VERSION = "0.0.
|
|
24
|
+
export const FX_PINNED_VERSION = "0.0.16";
|
|
25
25
|
|
|
26
26
|
/** OpenAI's Chat Completions prefix; fx appends `/chat/completions`. */
|
|
27
27
|
export const FX_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
@@ -8,6 +8,13 @@
|
|
|
8
8
|
|
|
9
9
|
import type { ExtensionFactory, McpServerConfig } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
import { buildRatingsFromLlm, fetchRetrievalsForTask, postRatings } from "../be/memory/raters/llm";
|
|
11
|
+
import {
|
|
12
|
+
advanceIdentityBaselines,
|
|
13
|
+
contentSha256,
|
|
14
|
+
PROFILE_FILE_IO,
|
|
15
|
+
type ProfileFileIO,
|
|
16
|
+
readIdentityBaselines,
|
|
17
|
+
} from "../commands/profile-sync";
|
|
11
18
|
import { checkToolLoop, clearToolHistory } from "../hooks/tool-loop-detection";
|
|
12
19
|
import { renderGoalReminder } from "../prompts/goal-reminder";
|
|
13
20
|
import { isSessionSummarySkipped } from "../utils/env-flag";
|
|
@@ -100,11 +107,16 @@ export async function fetchTaskDetails(
|
|
|
100
107
|
}
|
|
101
108
|
}
|
|
102
109
|
|
|
103
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Sync identity files (SOUL.md, IDENTITY.md, TOOLS.md) to server. A file whose
|
|
112
|
+
* hash still equals its baseline was not edited and is skipped, so a stale copy
|
|
113
|
+
* never overwrites a DB-side edit made during the session.
|
|
114
|
+
*/
|
|
104
115
|
export async function syncIdentityFilesToServer(
|
|
105
116
|
config: SwarmHooksConfig,
|
|
106
117
|
changeSource: "self_edit" | "session_sync" = "session_sync",
|
|
107
118
|
signal?: AbortSignal,
|
|
119
|
+
io: ProfileFileIO = PROFILE_FILE_IO,
|
|
108
120
|
): Promise<void> {
|
|
109
121
|
const updates: Record<string, string> = {};
|
|
110
122
|
const paths: Record<string, string> = {
|
|
@@ -112,15 +124,14 @@ export async function syncIdentityFilesToServer(
|
|
|
112
124
|
identityMd: "/workspace/IDENTITY.md",
|
|
113
125
|
toolsMd: "/workspace/TOOLS.md",
|
|
114
126
|
};
|
|
127
|
+
const baselines = await readIdentityBaselines(io.readFile);
|
|
115
128
|
|
|
116
129
|
for (const [key, path] of Object.entries(paths)) {
|
|
117
130
|
try {
|
|
118
|
-
const
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
updates[key] = content;
|
|
123
|
-
}
|
|
131
|
+
const content = await io.readFile(path);
|
|
132
|
+
if (content === undefined || baselines?.[key] === contentSha256(content)) continue;
|
|
133
|
+
if (content.trim() && content.length <= 65536) {
|
|
134
|
+
updates[key] = content;
|
|
124
135
|
}
|
|
125
136
|
} catch {
|
|
126
137
|
/* skip */
|
|
@@ -130,28 +141,27 @@ export async function syncIdentityFilesToServer(
|
|
|
130
141
|
if (Object.keys(updates).length === 0) return;
|
|
131
142
|
|
|
132
143
|
try {
|
|
133
|
-
await fetch(`${config.apiUrl}/api/agents/${config.agentId}/profile`, {
|
|
144
|
+
const resp = await fetch(`${config.apiUrl}/api/agents/${config.agentId}/profile`, {
|
|
134
145
|
method: "PUT",
|
|
135
146
|
headers: apiHeaders(config),
|
|
136
147
|
body: JSON.stringify({ ...updates, changeSource }),
|
|
137
148
|
signal,
|
|
138
149
|
});
|
|
150
|
+
if (resp.ok) await advanceIdentityBaselines(updates, io);
|
|
139
151
|
} catch {
|
|
140
152
|
/* silently fail */
|
|
141
153
|
}
|
|
142
154
|
}
|
|
143
155
|
|
|
144
156
|
/** Sync setup script to server */
|
|
145
|
-
async function syncSetupScriptToServer(
|
|
157
|
+
export async function syncSetupScriptToServer(
|
|
146
158
|
config: SwarmHooksConfig,
|
|
147
159
|
changeSource: "self_edit" | "session_sync" = "session_sync",
|
|
160
|
+
io: ProfileFileIO = PROFILE_FILE_IO,
|
|
148
161
|
): Promise<void> {
|
|
149
162
|
try {
|
|
150
|
-
const
|
|
151
|
-
if (!(
|
|
152
|
-
|
|
153
|
-
const raw = await file.text();
|
|
154
|
-
if (!raw.trim()) return;
|
|
163
|
+
const raw = await io.readFile("/workspace/start-up.sh");
|
|
164
|
+
if (!raw?.trim()) return;
|
|
155
165
|
|
|
156
166
|
const markerStart = "# === Agent-managed setup (from DB) ===";
|
|
157
167
|
const markerEnd = "# === End agent-managed setup ===";
|
|
@@ -166,12 +176,17 @@ async function syncSetupScriptToServer(
|
|
|
166
176
|
}
|
|
167
177
|
|
|
168
178
|
if (!content || content.length > 65536) return;
|
|
179
|
+
const baselines = await readIdentityBaselines(io.readFile);
|
|
180
|
+
if (baselines?.setupScript === contentSha256(content)) return;
|
|
169
181
|
|
|
170
|
-
await fetch(`${config.apiUrl}/api/agents/${config.agentId}/profile`, {
|
|
182
|
+
const resp = await fetch(`${config.apiUrl}/api/agents/${config.agentId}/profile`, {
|
|
171
183
|
method: "PUT",
|
|
172
184
|
headers: apiHeaders(config),
|
|
173
185
|
body: JSON.stringify({ setupScript: content, changeSource }),
|
|
174
186
|
});
|
|
187
|
+
if (resp.ok) {
|
|
188
|
+
await advanceIdentityBaselines({ setupScript: content }, io);
|
|
189
|
+
}
|
|
175
190
|
} catch {
|
|
176
191
|
/* silently fail */
|
|
177
192
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { RuntimeProviderKindSchema } from "../types";
|
|
2
|
+
import { RuntimePoolCacheSchema, RuntimeProviderKindSchema } from "../types";
|
|
3
3
|
|
|
4
4
|
export const CONTROLLER_PROTOCOL_VERSION = 1;
|
|
5
5
|
export const CONTROLLER_COMMAND_TIMEOUT_MS = 60_000;
|
|
@@ -16,6 +16,7 @@ const traitsSchema = z.object({
|
|
|
16
16
|
canProvision: z.boolean(),
|
|
17
17
|
ephemeralDisk: z.boolean(),
|
|
18
18
|
supportsPause: z.boolean(),
|
|
19
|
+
persistentCache: z.boolean().optional(),
|
|
19
20
|
maxTtlSec: z.number().positive().optional(),
|
|
20
21
|
maxContinuousSec: z.number().positive().optional(),
|
|
21
22
|
});
|
|
@@ -31,9 +32,21 @@ const provisionSchema = z.object({
|
|
|
31
32
|
.object({ cpu: z.number().positive().optional(), memoryMb: z.number().positive().optional() })
|
|
32
33
|
.optional(),
|
|
33
34
|
ttlSec: z.number().positive().optional(),
|
|
35
|
+
cache: RuntimePoolCacheSchema.extend({
|
|
36
|
+
key: z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_.-]+$/),
|
|
37
|
+
}).optional(),
|
|
34
38
|
});
|
|
35
39
|
const command = { type: z.literal("cmd"), id: z.string().min(1) };
|
|
36
40
|
export const ControllerCommandSchema = z.discriminatedUnion("op", [
|
|
41
|
+
z.object({
|
|
42
|
+
...command,
|
|
43
|
+
op: z.literal("release-cache"),
|
|
44
|
+
payload: z.object({
|
|
45
|
+
key: z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_.-]+$/),
|
|
46
|
+
poolId: z.string().min(1),
|
|
47
|
+
ownerId: z.string().min(1),
|
|
48
|
+
}),
|
|
49
|
+
}),
|
|
37
50
|
z.object({ ...command, op: z.literal("provision"), payload: provisionSchema }),
|
|
38
51
|
z.object({
|
|
39
52
|
...command,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
2
2
|
import type {
|
|
3
3
|
ProvisionRequest,
|
|
4
|
+
RuntimeCacheReference,
|
|
4
5
|
RuntimeHandle,
|
|
5
6
|
RuntimeProvider,
|
|
6
7
|
RuntimeProviderTraits,
|
|
@@ -25,6 +26,7 @@ export interface ControllerCommands {
|
|
|
25
26
|
terminate(handle: RuntimeHandle, reason: string): Promise<void>;
|
|
26
27
|
status(handles: RuntimeHandle[]): Promise<Record<string, RuntimeStatus>>;
|
|
27
28
|
list(ownerId: string): Promise<RuntimeHandle[]>;
|
|
29
|
+
releaseCache?(cache: RuntimeCacheReference): Promise<void>;
|
|
28
30
|
renew?(handle: RuntimeHandle, ttlSec: number): Promise<{ endAt: string }>;
|
|
29
31
|
pause?(handle: RuntimeHandle): Promise<void>;
|
|
30
32
|
resume?(handle: RuntimeHandle): Promise<void>;
|
|
@@ -36,6 +38,7 @@ export class BuiltinController implements ControllerCommands {
|
|
|
36
38
|
readonly renew?: ControllerCommands["renew"];
|
|
37
39
|
readonly pause?: ControllerCommands["pause"];
|
|
38
40
|
readonly resume?: ControllerCommands["resume"];
|
|
41
|
+
readonly releaseCache?: ControllerCommands["releaseCache"];
|
|
39
42
|
|
|
40
43
|
constructor(
|
|
41
44
|
readonly id: string,
|
|
@@ -47,6 +50,8 @@ export class BuiltinController implements ControllerCommands {
|
|
|
47
50
|
this.workerApiUrl = workerApiUrl;
|
|
48
51
|
if (provider.renew)
|
|
49
52
|
this.renew = (handle, ttlSec) => this.call(() => provider.renew!(target, handle, ttlSec));
|
|
53
|
+
if (provider.releaseCache)
|
|
54
|
+
this.releaseCache = (cache) => this.call(() => provider.releaseCache!(target, cache));
|
|
50
55
|
if (provider.pause) this.pause = (handle) => this.call(() => provider.pause!(target, handle));
|
|
51
56
|
if (provider.resume)
|
|
52
57
|
this.resume = (handle) => this.call(() => provider.resume!(target, handle));
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type ConfigStatus,
|
|
5
5
|
type ProvisionRequest,
|
|
6
6
|
RUNTIME_LABELS,
|
|
7
|
+
type RuntimeCacheReference,
|
|
7
8
|
type RuntimeHandle,
|
|
8
9
|
type RuntimeProvider,
|
|
9
10
|
type RuntimeStatus,
|
|
@@ -63,6 +64,22 @@ class DockerApiError extends Error {
|
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
function isCacheMountError(error: unknown): boolean {
|
|
68
|
+
return error instanceof DockerApiError && /\b(?:mount\w*|volume\w*)\b/i.test(error.message);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
type CacheVolume = { Name: string; Labels?: Record<string, string> };
|
|
72
|
+
|
|
73
|
+
function assertCacheOwner(volume: CacheVolume, cache: RuntimeCacheReference): void {
|
|
74
|
+
if (
|
|
75
|
+
volume.Name !== cache.key ||
|
|
76
|
+
volume.Labels?.[RUNTIME_LABELS.owner] !== cache.ownerId ||
|
|
77
|
+
volume.Labels?.[RUNTIME_LABELS.poolId] !== cache.poolId ||
|
|
78
|
+
volume.Labels?.["swarm.cache"] !== "true"
|
|
79
|
+
)
|
|
80
|
+
throw new Error(`Cache volume ${cache.key} is not owned by this swarm and pool`);
|
|
81
|
+
}
|
|
82
|
+
|
|
66
83
|
async function dockerApi<T>(
|
|
67
84
|
target: RuntimeTargetConfig,
|
|
68
85
|
method: string,
|
|
@@ -119,7 +136,12 @@ async function dockerApi<T>(
|
|
|
119
136
|
|
|
120
137
|
export class DockerRuntimeProvider implements RuntimeProvider {
|
|
121
138
|
readonly kind = "docker" as const;
|
|
122
|
-
readonly traits = {
|
|
139
|
+
readonly traits = {
|
|
140
|
+
canProvision: true,
|
|
141
|
+
ephemeralDisk: true,
|
|
142
|
+
supportsPause: false,
|
|
143
|
+
persistentCache: true,
|
|
144
|
+
};
|
|
123
145
|
|
|
124
146
|
checkConfig(target: RuntimeTargetConfig): ConfigStatus {
|
|
125
147
|
try {
|
|
@@ -132,6 +154,29 @@ export class DockerRuntimeProvider implements RuntimeProvider {
|
|
|
132
154
|
|
|
133
155
|
async provision(target: RuntimeTargetConfig, req: ProvisionRequest): Promise<RuntimeHandle> {
|
|
134
156
|
try {
|
|
157
|
+
let cacheWarning: string | undefined;
|
|
158
|
+
let cacheMount: { Type: "volume"; Source: string; Target: string } | undefined;
|
|
159
|
+
if (req.cache) {
|
|
160
|
+
try {
|
|
161
|
+
const volume = await dockerApi<CacheVolume>(target, "POST", "/volumes/create", {
|
|
162
|
+
Name: req.cache.key,
|
|
163
|
+
Labels: {
|
|
164
|
+
[RUNTIME_LABELS.owner]: req.ownerId,
|
|
165
|
+
[RUNTIME_LABELS.poolId]: req.poolId,
|
|
166
|
+
"swarm.cache": "true",
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
// Docker reuses an existing name without replacing its labels.
|
|
170
|
+
assertCacheOwner(volume, {
|
|
171
|
+
key: req.cache.key,
|
|
172
|
+
poolId: req.poolId,
|
|
173
|
+
ownerId: req.ownerId,
|
|
174
|
+
});
|
|
175
|
+
cacheMount = { Type: "volume", Source: req.cache.key, Target: req.cache.mountPath };
|
|
176
|
+
} catch (error) {
|
|
177
|
+
cacheWarning = redactWithEnv(scrubSecrets(String(error)), req.env);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
135
180
|
const path = `/containers/create?name=${encodeURIComponent(`swarm-rt-${req.runtimeId}`)}`;
|
|
136
181
|
const body = {
|
|
137
182
|
Image: req.image,
|
|
@@ -154,40 +199,80 @@ export class DockerRuntimeProvider implements RuntimeProvider {
|
|
|
154
199
|
NetworkMode: target.DOCKER_NETWORK,
|
|
155
200
|
Memory: req.resources?.memoryMb ? req.resources.memoryMb * 1024 * 1024 : undefined,
|
|
156
201
|
NanoCpus: req.resources?.cpu ? Math.round(req.resources.cpu * 1e9) : undefined,
|
|
202
|
+
...(cacheMount ? { Mounts: [cacheMount] } : {}),
|
|
157
203
|
},
|
|
158
204
|
};
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
205
|
+
const createAndStart = async (): Promise<string> => {
|
|
206
|
+
let created: { Id: string };
|
|
207
|
+
try {
|
|
208
|
+
created = await dockerApi(target, "POST", path, body);
|
|
209
|
+
} catch (err) {
|
|
210
|
+
if (
|
|
211
|
+
!(err instanceof DockerApiError) ||
|
|
212
|
+
err.statusCode !== 404 ||
|
|
213
|
+
!err.message.includes("No such image")
|
|
214
|
+
)
|
|
215
|
+
throw err;
|
|
216
|
+
const pullParams = new URLSearchParams({ fromImage: req.image });
|
|
217
|
+
if (
|
|
218
|
+
!req.image.includes("@") &&
|
|
219
|
+
req.image.lastIndexOf(":") <= req.image.lastIndexOf("/")
|
|
220
|
+
) {
|
|
221
|
+
pullParams.set("tag", "latest");
|
|
222
|
+
}
|
|
223
|
+
await dockerApi(target, "POST", `/images/create?${pullParams}`, undefined, true);
|
|
224
|
+
created = await dockerApi(target, "POST", path, body);
|
|
169
225
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
226
|
+
try {
|
|
227
|
+
await dockerApi(target, "POST", `/containers/${created.Id}/start`);
|
|
228
|
+
} catch (err) {
|
|
229
|
+
try {
|
|
230
|
+
await dockerApi(target, "DELETE", `/containers/${created.Id}?force=true&v=true`);
|
|
231
|
+
} catch (cleanupError) {
|
|
232
|
+
if (
|
|
233
|
+
cacheMount &&
|
|
234
|
+
isCacheMountError(err) &&
|
|
235
|
+
!(cleanupError instanceof DockerApiError && cleanupError.statusCode === 404)
|
|
236
|
+
)
|
|
237
|
+
throw new Error(
|
|
238
|
+
`${String(err)}; failed-start cleanup failed: ${String(cleanupError)}`,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
throw err;
|
|
173
242
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
243
|
+
return created.Id;
|
|
244
|
+
};
|
|
245
|
+
let externalId: string;
|
|
177
246
|
try {
|
|
178
|
-
await
|
|
247
|
+
externalId = await createAndStart();
|
|
179
248
|
} catch (err) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
249
|
+
if (!cacheMount || !isCacheMountError(err)) throw err;
|
|
250
|
+
cacheWarning = redactWithEnv(scrubSecrets(String(err)), req.env);
|
|
251
|
+
delete body.HostConfig.Mounts;
|
|
252
|
+
externalId = await createAndStart();
|
|
184
253
|
}
|
|
185
|
-
return {
|
|
254
|
+
return {
|
|
255
|
+
kind: "docker",
|
|
256
|
+
externalId,
|
|
257
|
+
...(cacheWarning ? { meta: { cacheWarning } } : {}),
|
|
258
|
+
};
|
|
186
259
|
} catch (err) {
|
|
187
260
|
throw new Error(redactWithEnv(String(err), req.env));
|
|
188
261
|
}
|
|
189
262
|
}
|
|
190
263
|
|
|
264
|
+
async releaseCache(target: RuntimeTargetConfig, cache: RuntimeCacheReference): Promise<void> {
|
|
265
|
+
const path = `/volumes/${encodeURIComponent(cache.key)}`;
|
|
266
|
+
try {
|
|
267
|
+
const volume = await dockerApi<CacheVolume>(target, "GET", path);
|
|
268
|
+
assertCacheOwner(volume, cache);
|
|
269
|
+
// A volume still attached to any container must remain intact (Docker returns 409).
|
|
270
|
+
await dockerApi(target, "DELETE", path);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
if (!(error instanceof DockerApiError && error.statusCode === 404)) throw error;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
191
276
|
async terminate(target: RuntimeTargetConfig, handle: RuntimeHandle): Promise<void> {
|
|
192
277
|
try {
|
|
193
278
|
// v=true also removes the container's anonymous volumes (the worker image declares
|
|
@@ -19,6 +19,8 @@ export interface RuntimeProviderTraits {
|
|
|
19
19
|
ephemeralDisk: boolean;
|
|
20
20
|
/** Provider can pause and resume a runtime. */
|
|
21
21
|
supportsPause: boolean;
|
|
22
|
+
/** Can mount a persistent cache shared by all runtimes of one pool. */
|
|
23
|
+
persistentCache?: boolean;
|
|
22
24
|
/** Provider hard cap on runtime lifetime, if any. */
|
|
23
25
|
maxTtlSec?: number;
|
|
24
26
|
/** Continuous runtime limit for the configured infrastructure tier. */
|
|
@@ -45,11 +47,23 @@ export interface ProvisionRequest {
|
|
|
45
47
|
/** Worker env: MCP_BASE_URL, AGENT_ID, API key or scoped token, pool env. */
|
|
46
48
|
env: Record<string, string>;
|
|
47
49
|
resources?: { cpu?: number; memoryMb?: number };
|
|
50
|
+
/** Provider-neutral cache identity, allocated by the API rather than the operator. */
|
|
51
|
+
cache?: { key: string; mountPath: string };
|
|
48
52
|
ttlSec?: number;
|
|
49
53
|
/** Ownership labels, used by list() to find runtimes this swarm started. */
|
|
50
54
|
labels: Record<string, string>;
|
|
51
55
|
}
|
|
52
56
|
|
|
57
|
+
export interface RuntimeCacheReference {
|
|
58
|
+
key: string;
|
|
59
|
+
poolId: string;
|
|
60
|
+
ownerId: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function poolCacheKey(poolId: string, generation?: string): string {
|
|
64
|
+
return `swarm-cache-${poolId}${generation ? `-${generation}` : ""}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
53
67
|
export interface RuntimeHandle {
|
|
54
68
|
kind: RuntimeProviderKind;
|
|
55
69
|
/** Container id, sandbox id, or pod name. */
|
|
@@ -74,6 +88,8 @@ export interface RuntimeProvider {
|
|
|
74
88
|
status(target: RuntimeTargetConfig, handle: RuntimeHandle): Promise<RuntimeStatus>;
|
|
75
89
|
/** Every runtime this swarm owns on the target, found by labels. Used to reap orphans. */
|
|
76
90
|
list(target: RuntimeTargetConfig, ownerId: string): Promise<RuntimeHandle[]>;
|
|
91
|
+
/** Remove an owned pool cache after its runtimes stop; never force detach. */
|
|
92
|
+
releaseCache?(target: RuntimeTargetConfig, cache: RuntimeCacheReference): Promise<void>;
|
|
77
93
|
renew?(
|
|
78
94
|
target: RuntimeTargetConfig,
|
|
79
95
|
handle: RuntimeHandle,
|
|
@@ -44,6 +44,14 @@ type AgentTaskConfig = {
|
|
|
44
44
|
parentTaskId?: string;
|
|
45
45
|
requestedByUserId?: string;
|
|
46
46
|
outputSchema?: Record<string, unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* Dispatch even when the follow-up re-delegation guard blocks this step.
|
|
49
|
+
* The guard applies only to a run launched from a follow-up task in a Slack
|
|
50
|
+
* thread, and decides once for the whole run at its first new step: it
|
|
51
|
+
* blocks a repeat of work already completed in the thread, or a run past the
|
|
52
|
+
* thread's dispatch cap. A blocked run's later new steps are blocked too.
|
|
53
|
+
*/
|
|
54
|
+
allowRedelegation?: boolean;
|
|
47
55
|
/**
|
|
48
56
|
* Block until the dispatched task reaches a terminal status and journal
|
|
49
57
|
* its real output. Defaults to `true` — this is the natural semantic for
|
|
@@ -63,6 +63,8 @@ declare module "swarm-sdk" {
|
|
|
63
63
|
parentTaskId?: string;
|
|
64
64
|
requestedByUserId?: string;
|
|
65
65
|
outputSchema?: Record<string, unknown>;
|
|
66
|
+
/** Dispatch even when the follow-up re-delegation guard blocks this step (a run launched from a follow-up task in a Slack thread, checked at its first new step). */
|
|
67
|
+
allowRedelegation?: boolean;
|
|
66
68
|
/** Wait for the dispatched task to reach a terminal status before resolving. Default: true. */
|
|
67
69
|
waitForCompletion?: boolean;
|
|
68
70
|
/** Max ms to wait for a terminal status before throwing. Default: 2h. Only used when waitForCompletion is true. */
|
|
@@ -760,6 +762,26 @@ declare module "swarm-sdk" {
|
|
|
760
762
|
label: string,
|
|
761
763
|
config: { prompt: string; model?: string; schema?: Record<string, unknown> },
|
|
762
764
|
): Promise<unknown>;
|
|
765
|
+
/**
|
|
766
|
+
* Dispatch a task and journal its result under `label`.
|
|
767
|
+
*
|
|
768
|
+
* Resolves to the task's OUTPUT on success: the stored output string (JSON
|
|
769
|
+
* text under `outputSchema`, so parse it yourself), or `null` when the task
|
|
770
|
+
* stored none. It is never a task record: on a string, `result.taskId` and
|
|
771
|
+
* `result.status` are undefined; on `null`, reading them throws a TypeError.
|
|
772
|
+
* Other shapes:
|
|
773
|
+
* - `failOnTaskFailure: false` and the task ends failed/cancelled/superseded:
|
|
774
|
+
* `{ taskId, status: "failed", error }`.
|
|
775
|
+
* - `waitForCompletion: false`: the first call still waits up to ~30s while
|
|
776
|
+
* the server polls the task. Done in that window: the output, as on
|
|
777
|
+
* success. Failed or cancelled in that window: throws, or
|
|
778
|
+
* `{ taskId, status: "failed", error }` with `failOnTaskFailure: false`.
|
|
779
|
+
* Still running: `{ taskId, status }`.
|
|
780
|
+
*
|
|
781
|
+
* To get a step's task id, query by its context key:
|
|
782
|
+
* `SELECT id, status, output FROM agent_tasks WHERE contextKey = 'script-run:<runId>:<label>'
|
|
783
|
+
* AND taskType = 'script-run-step' ORDER BY createdAt DESC, rowid DESC LIMIT 1`.
|
|
784
|
+
*/
|
|
763
785
|
agentTask(label: string, config: AgentTaskStepConfig): Promise<unknown>;
|
|
764
786
|
swarmScript(
|
|
765
787
|
label: string,
|
|
@@ -45,6 +45,8 @@ declare module "swarm-sdk" {
|
|
|
45
45
|
parentTaskId?: string;
|
|
46
46
|
requestedByUserId?: string;
|
|
47
47
|
outputSchema?: Record<string, unknown>;
|
|
48
|
+
/** Dispatch even when the follow-up re-delegation guard blocks this step (a run launched from a follow-up task in a Slack thread, checked at its first new step). */
|
|
49
|
+
allowRedelegation?: boolean;
|
|
48
50
|
/** Wait for the dispatched task to reach a terminal status before resolving. Default: true. */
|
|
49
51
|
waitForCompletion?: boolean;
|
|
50
52
|
/** Max ms to wait for a terminal status before throwing. Default: 2h. Only used when waitForCompletion is true. */
|
|
@@ -742,6 +744,26 @@ declare module "swarm-sdk" {
|
|
|
742
744
|
label: string,
|
|
743
745
|
config: { prompt: string; model?: string; schema?: Record<string, unknown> },
|
|
744
746
|
): Promise<unknown>;
|
|
747
|
+
/**
|
|
748
|
+
* Dispatch a task and journal its result under `label`.
|
|
749
|
+
*
|
|
750
|
+
* Resolves to the task's OUTPUT on success: the stored output string (JSON
|
|
751
|
+
* text under `outputSchema`, so parse it yourself), or `null` when the task
|
|
752
|
+
* stored none. It is never a task record: on a string, `result.taskId` and
|
|
753
|
+
* `result.status` are undefined; on `null`, reading them throws a TypeError.
|
|
754
|
+
* Other shapes:
|
|
755
|
+
* - `failOnTaskFailure: false` and the task ends failed/cancelled/superseded:
|
|
756
|
+
* `{ taskId, status: "failed", error }`.
|
|
757
|
+
* - `waitForCompletion: false`: the first call still waits up to ~30s while
|
|
758
|
+
* the server polls the task. Done in that window: the output, as on
|
|
759
|
+
* success. Failed or cancelled in that window: throws, or
|
|
760
|
+
* `{ taskId, status: "failed", error }` with `failOnTaskFailure: false`.
|
|
761
|
+
* Still running: `{ taskId, status }`.
|
|
762
|
+
*
|
|
763
|
+
* To get a step's task id, query by its context key:
|
|
764
|
+
* `SELECT id, status, output FROM agent_tasks WHERE contextKey = 'script-run:<runId>:<label>'
|
|
765
|
+
* AND taskType = 'script-run-step' ORDER BY createdAt DESC, rowid DESC LIMIT 1`.
|
|
766
|
+
*/
|
|
745
767
|
agentTask(label: string, config: AgentTaskStepConfig): Promise<unknown>;
|
|
746
768
|
swarmScript(
|
|
747
769
|
label: string,
|
package/src/server-user.ts
CHANGED
package/src/slack/commands.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { App } from "@slack/bolt";
|
|
|
2
2
|
import { getAllAgents, getAllTasks } from "../be/db";
|
|
3
3
|
import { isEnvFlagEnabled } from "../utils/env-flag";
|
|
4
4
|
import { EXTERNAL_CHANNEL_BLOCKED_REPLY, shouldBlockChannel } from "./external-channel";
|
|
5
|
+
import { isSlackLeaveThreadDisabled } from "./left-threads";
|
|
5
6
|
|
|
6
7
|
export function registerCommandHandler(app: App): void {
|
|
7
8
|
app.command("/agent-swarm-status", async ({ ack, respond, command, client }) => {
|
|
@@ -88,9 +89,12 @@ export function registerCommandHandler(app: App): void {
|
|
|
88
89
|
• Follow-up tasks auto-depend on the active task in the thread for natural sequencing`);
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
const leaveLine = isSlackLeaveThreadDisabled()
|
|
93
|
+
? ""
|
|
94
|
+
: "\n• `!leave` in a thread - Make the swarm ignore that thread until someone @mentions it";
|
|
91
95
|
sections.push(`*Commands:*
|
|
92
96
|
• \`/agent-swarm-status\` - Show all agents and their current status
|
|
93
|
-
• \`/agent-swarm-help\` - Show this help message`);
|
|
97
|
+
• \`/agent-swarm-help\` - Show this help message${leaveLine}`);
|
|
94
98
|
|
|
95
99
|
const blocks = [
|
|
96
100
|
{
|
package/src/slack/handlers.ts
CHANGED
|
@@ -52,7 +52,13 @@ import {
|
|
|
52
52
|
leaveExternalChannel,
|
|
53
53
|
shouldBlockChannel,
|
|
54
54
|
} from "./external-channel";
|
|
55
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
isSlackLeaveThreadCommand,
|
|
57
|
+
isSlackLeaveThreadDisabled,
|
|
58
|
+
leaveSlackThread,
|
|
59
|
+
SLACK_LEFT_THREAD_CONFIRMATION,
|
|
60
|
+
shouldSkipLeftSlackThread,
|
|
61
|
+
} from "./left-threads";
|
|
56
62
|
import {
|
|
57
63
|
collectSlackMessageFiles,
|
|
58
64
|
extractSlackMessageText,
|
|
@@ -491,7 +497,36 @@ export function registerMessageHandler(app: App): void {
|
|
|
491
497
|
// Check if bot was mentioned (in original text only)
|
|
492
498
|
const botMentioned = !!cachedBotUserId && !!msg.text?.includes(`<@${cachedBotUserId}>`);
|
|
493
499
|
|
|
494
|
-
//
|
|
500
|
+
// `!leave` in a thread the swarm is in: a human makes the swarm leave it,
|
|
501
|
+
// in code, with no workflow event, buffering, task, or model call.
|
|
502
|
+
// Any task bound to the thread counts, assigned or not, as does a thread
|
|
503
|
+
// the swarm started. Checked before the left-thread gate so `@bot !leave`
|
|
504
|
+
// leaves rather than rejoining. The confirmation is ephemeral, to the
|
|
505
|
+
// sender only.
|
|
506
|
+
if (
|
|
507
|
+
msg.thread_ts &&
|
|
508
|
+
!isSlackLeaveThreadDisabled() &&
|
|
509
|
+
isSlackLeaveThreadCommand(msg.text, cachedBotUserId) &&
|
|
510
|
+
((await getMostRecentTaskInThread(msg.channel, msg.thread_ts)) !== null ||
|
|
511
|
+
(await wasThreadStartedBySwarm(client, msg.channel, msg.thread_ts)))
|
|
512
|
+
) {
|
|
513
|
+
noteSlackInboundSideEffect("thread_leave");
|
|
514
|
+
await leaveSlackThread(msg.channel, msg.thread_ts, { slackUserId: msg.user });
|
|
515
|
+
console.log(`[Slack] Left thread ${msg.channel}/${msg.thread_ts}: !leave from ${msg.user}`);
|
|
516
|
+
try {
|
|
517
|
+
await client.chat.postEphemeral({
|
|
518
|
+
channel: msg.channel,
|
|
519
|
+
user: msg.user,
|
|
520
|
+
thread_ts: msg.thread_ts,
|
|
521
|
+
text: SLACK_LEFT_THREAD_CONFIRMATION,
|
|
522
|
+
});
|
|
523
|
+
} catch (error) {
|
|
524
|
+
console.error("[Slack] Failed to confirm !leave:", error);
|
|
525
|
+
}
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// A thread the swarm left (slack-leave-thread or `!leave`) stays silent until someone
|
|
495
530
|
// @mentions the bot. Checked before the workflow event, buffering, routing,
|
|
496
531
|
// or any AI call.
|
|
497
532
|
if (await shouldSkipLeftSlackThread(msg.channel, msg.thread_ts, botMentioned)) {
|