@desplega.ai/agent-swarm 1.169.0 → 1.171.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 +11 -2
- package/dist/{acp-adapter-m47zfx4a.js → acp-adapter-1z9p3fvx.js} +6 -6
- package/dist/{actions-ws7k3tvq.js → actions-rc2yjk8a.js} +31 -29
- package/dist/{amp-adapter-nvv8k8j5.js → amp-adapter-ypyf5s1x.js} +6 -6
- package/dist/{anthropic-messages-13yn502s.js → anthropic-messages-etkbxhhy.js} +11 -11
- package/dist/{app-80w6qspx.js → app-04ab2s0z.js} +9 -9
- package/dist/{artifact-fey7dvj9.js → artifact-eczsknc3.js} +6 -3
- package/dist/{assistant-jtq439kw.js → assistant-vhmjd8wf.js} +34 -32
- package/dist/{azure-openai-responses-9st34pfz.js → azure-openai-responses-xap57x4b.js} +7 -7
- package/dist/{boot-reembed-feda8wn8.js → boot-reembed-3p0m259x.js} +8 -8
- package/dist/{boot-reembed-3nc0aaed.js → boot-reembed-wew3gwk8.js} +8 -8
- package/dist/{boot-scrub-sweep-grsa2er0.js → boot-scrub-sweep-5ytwtq24.js} +9 -9
- package/dist/{boot-seeds-gcfgq44f.js → boot-seeds-s8p2xry8.js} +12 -12
- package/dist/{claude-adapter-pjv2q7t8.js → claude-adapter-akrzg6jh.js} +15 -15
- package/dist/{claude-managed-adapter-0wa8se82.js → claude-managed-adapter-kqqqhp2q.js} +2 -2
- package/dist/{claude-managed-setup-zxa9p9tx.js → claude-managed-setup-bnmjarjc.js} +11 -8
- package/dist/{claude-sdk-session-c9j6k9kx.js → claude-sdk-session-exq1jadx.js} +15 -15
- package/dist/{cli-a8vps458.js → cli-01qndrvw.js} +17274 -17242
- package/dist/{cli-rg1c8ccw.js → cli-0d2rqhvq.js} +497 -73
- package/dist/cli-0p3enk35.js +188 -0
- package/dist/cli-1srmzpr3.js +16 -0
- package/dist/{cli-zzev32jw.js → cli-231av4y6.js} +6 -6
- package/dist/{cli-kp3vfknv.js → cli-280gnz4v.js} +2 -2
- package/dist/{cli-mv2520nm.js → cli-2bw3w47j.js} +1 -1
- package/dist/{cli-km8559dm.js → cli-2qbs2tvf.js} +18 -10
- package/dist/{cli-efnd2kce.js → cli-2rbt7at8.js} +6 -1
- package/dist/{cli-xvc3q9br.js → cli-451ks6aw.js} +1 -1
- package/dist/{cli-jkfxpg1b.js → cli-4bm25xtw.js} +2 -2
- package/dist/{cli-zp38xvtm.js → cli-5rqrj7q0.js} +1 -1
- package/dist/{cli-km4x66j0.js → cli-5y67yrt6.js} +13 -13
- package/dist/{cli-qg2zhjfc.js → cli-62bwwc2q.js} +8 -8
- package/dist/{cli-s0k2j7q9.js → cli-6xxxb8qt.js} +10 -10
- package/dist/cli-6zx22mv6.js +0 -0
- package/dist/{cli-zp67qg5x.js → cli-7a0sde2x.js} +72 -1
- package/dist/{cli-v1w7pbd8.js → cli-7jykv7ef.js} +1 -1
- package/dist/{cli-rfphkzh5.js → cli-7pz3b7x5.js} +24 -4
- package/dist/{cli-mb75wpxf.js → cli-81r1wjyv.js} +1 -1
- package/dist/{cli-rbr91whd.js → cli-8mr695sb.js} +9 -5
- package/dist/{cli-f14fvzag.js → cli-a1b9b32n.js} +6 -1
- package/dist/cli-cd0hv9nh.js +32 -0
- package/dist/{cli-dv76vq5d.js → cli-ctret352.js} +685 -209
- package/dist/{cli-wt7ccy4r.js → cli-d161g69q.js} +9 -1
- package/dist/cli-db3m6zdt.js +362 -0
- package/dist/{cli-hf5s9pgf.js → cli-e3pmyt39.js} +1 -1
- package/dist/{cli-ysnkvdx6.js → cli-ec7hrgqp.js} +313 -91
- package/dist/{cli-m23r88re.js → cli-erbp6b4g.js} +3 -3
- package/dist/{cli-9k7mqz00.js → cli-ge593j7e.js} +30 -3
- package/dist/cli-h8w3fg83.js +17 -0
- package/dist/{cli-xvdgasgy.js → cli-hsem16hb.js} +114 -9
- package/dist/{cli-yvxfaem2.js → cli-hsk5gd15.js} +9 -5
- package/dist/{cli-7vz49g7h.js → cli-jxsgrnmq.js} +101 -4
- package/dist/{cli-b7y8113e.js → cli-k2v5x13t.js} +1 -1
- package/dist/{cli-bqrs5ycj.js → cli-m4csbs67.js} +2 -2
- package/dist/{cli-91r17hb1.js → cli-mzj3aqac.js} +3 -3
- package/dist/{cli-swrz3mj8.js → cli-n805bb98.js} +1 -1
- package/dist/{cli-sajr098b.js → cli-n8ybnv1k.js} +3 -3
- package/dist/{cli-e5qk3m2a.js → cli-nkjwe4z7.js} +19 -19
- package/dist/{cli-3ry5gx4f.js → cli-p2pjfq1r.js} +2 -2
- package/dist/{cli-61tbnjpf.js → cli-p8f7dqgt.js} +767 -541
- package/dist/{cli-r7eeddkq.js → cli-ph3145b7.js} +3 -3
- package/dist/cli-ppy4nnnh.js +168 -0
- package/dist/cli-r455yd58.js +832 -0
- package/dist/{cli-jv36y8wz.js → cli-rrbctenq.js} +1 -1
- package/dist/{cli-8xjst8q2.js → cli-s88my3br.js} +11 -11
- package/dist/{cli-vejds37t.js → cli-srmej5tp.js} +3 -3
- package/dist/{cli-eqfbsxsn.js → cli-tg8q0b5y.js} +14 -11
- package/dist/cli-w0zx9ya1.js +1351 -0
- package/dist/{cli-rh44xx46.js → cli-wfvedq5w.js} +15 -15
- package/dist/{cli-n4z21pt8.js → cli-x207g4w1.js} +1 -1
- package/dist/{cli-fyeft04q.js → cli-x3fy2tgp.js} +2 -2
- package/dist/{cli-7mhy3ths.js → cli-x61srfpp.js} +5 -5
- package/dist/{cli-w6xa5nf5.js → cli-y1j1ggbf.js} +8 -8
- package/dist/{cli-jvmtxqtc.js → cli-ywh2a87k.js} +7 -2
- package/dist/{cli-3qhyh31j.js → cli-ywm1azg9.js} +6 -0
- package/dist/{cli-z48ggfyq.js → cli-zxm9p3x4.js} +2 -2
- package/dist/cli.js +42 -24
- package/dist/{codex-adapter-0kpg09ca.js → codex-adapter-9ag75whm.js} +13 -13
- package/dist/{codex-hook-295jpbfa.js → codex-hook-7ba15hjd.js} +5 -3
- package/dist/{codex-login-g1cyt5zm.js → codex-login-841kv5fk.js} +7 -5
- package/dist/{codex-session-runner-8n672hxh.js → codex-session-runner-9fp7y4cf.js} +13 -13
- package/dist/{commands-mhmg5n0x.js → commands-d7eah0y9.js} +10 -10
- package/dist/controller-hq5ggpcp.js +193 -0
- package/dist/controllers-connect-8t0k65x2.js +265 -0
- package/dist/{cursor-adapter-wn8n5zzk.js → cursor-adapter-t4pr1m3c.js} +5 -5
- package/dist/db-2rmd23wq.js +71 -0
- package/dist/{db-wa6s1mwv.js → db-sp39qv72.js} +8 -8
- package/dist/{devin-adapter-bffjj5n4.js → devin-adapter-xgtj680j.js} +2 -2
- package/dist/{dispatcher-nhs2pkr8.js → dispatcher-g7fsybsd.js} +30 -28
- package/dist/docker-f503k9p0.js +201 -0
- package/dist/{dsh-adapter-5423p70m.js → dsh-adapter-2h8m4cab.js} +5 -5
- package/dist/e2b-66xra4az.js +202 -0
- package/dist/{e2b-nd50eccg.js → e2b-xwhyj8cw.js} +43 -527
- package/dist/{event-bus-vnfthafg.js → event-bus-vjtv82gm.js} +2 -2
- package/dist/{grok-adapter-28pkdt80.js → grok-adapter-1err1me7.js} +7 -7
- package/dist/{handlers-5rtf9nng.js → handlers-c7yggm37.js} +33 -31
- package/dist/heartbeat-dkm924fk.js +124 -0
- package/dist/{hook-qkm73zk6.js → hook-g8e7sfnf.js} +13 -13
- package/dist/{hook-krjfkpzy.js → hook-wgx4exw6.js} +20 -17
- package/dist/{http-a397xcn4.js → http-1d23k928.js} +1958 -205
- package/dist/{index-kqre45fr.js → index-gm10tmye.js} +30 -28
- package/dist/{index-rtxg15ah.js → index-q7cj9bn2.js} +39 -29
- package/dist/{index-vvsq7v45.js → index-va4zbvzp.js} +30 -28
- package/dist/{index-ac0v8v9d.js → index-vertaxs1.js} +8 -8
- package/dist/{index-ytdhtdry.js → index-y5vvczrs.js} +31 -22
- package/dist/{keepalive-psfh8ysx.js → keepalive-1jc5e7ct.js} +10 -10
- package/dist/{lead-m6rppjn7.js → lead-yxw2f1sg.js} +48 -46
- package/dist/{maintenance-41f837ke.js → maintenance-h7w2m10y.js} +8 -8
- package/dist/{node-8zkdq42h.js → node-c9we95xf.js} +9 -9
- package/dist/{oauth-refresh-sweep-6hr55hm8.js → oauth-refresh-sweep-wh9ypd1b.js} +9 -9
- package/dist/{onboard-ktrtd7cz.js → onboard-dfr9j762.js} +25 -15
- package/dist/{openai-codex-responses-jzxkta9b.js → openai-codex-responses-pgvtddvv.js} +3 -3
- package/dist/{openai-responses-m3g43rrt.js → openai-responses-9dyzwzkr.js} +9 -9
- package/dist/{opencode-adapter-yjyqynzf.js → opencode-adapter-f1zby94p.js} +3 -3
- package/dist/{otel-impl-dq4f2k3m.js → otel-impl-and31m5s.js} +5 -5
- package/dist/{pi-mono-adapter-e5v9w0hv.js → pi-mono-adapter-fx6k5wwh.js} +38 -27
- package/dist/{pricing-refresh-kmk7j1ra.js → pricing-refresh-23zr6j3w.js} +10 -10
- package/dist/{rbac-roles-9ykx9tc5.js → rbac-roles-nc7k9d0t.js} +10 -10
- package/dist/{rbac-roles-9w1dkkxd.js → rbac-roles-wnx35x4x.js} +11 -11
- package/dist/{render-v2-ycqm53np.js → render-v2-81cg1y52.js} +9 -9
- package/dist/{resume-cq2pkp8q.js → resume-d4b6j2n2.js} +16 -16
- package/dist/{setup-0dcmdvbn.js → setup-g68r1w28.js} +7 -5
- package/dist/static-t1gr2cr7.js +30 -0
- package/dist/{virtual-modules-1x9k4jcs.js → virtual-modules-rdjmcg7q.js} +3 -3
- package/dist/{work-objects-x01x2fh8.js → work-objects-0zzdnbt9.js} +35 -33
- package/dist/{worker-py1ssb1h.js → worker-p1g8qm6h.js} +48 -46
- package/dist/{x-ma4gnfgy.js → x-qfmygqqv.js} +2 -2
- package/openapi.json +3382 -167
- package/package.json +3 -3
- package/src/be/db/agents.ts +6 -0
- package/src/be/db/instance-signals.ts +30 -0
- package/src/be/db/tasks/read.ts +2 -0
- package/src/be/db/tasks/write.ts +39 -5
- package/src/be/db/workflow-runs.ts +22 -0
- package/src/be/db.ts +96 -40
- package/src/be/fleet-benchmark-stats.ts +39 -0
- package/src/be/migrations/205_favorites_per_dashboard_user.sql +29 -0
- package/src/be/migrations/206_runtime_pools.sql +62 -0
- package/src/be/migrations/207_runtime_session_tokens.sql +31 -0
- package/src/be/migrations/208_task_runtime_dispatch.sql +4 -0
- package/src/be/model-tier-resolution.ts +9 -2
- package/src/be/multi-runtime.ts +102 -13
- package/src/be/org-profile.ts +35 -0
- package/src/be/rbac-audit.ts +4 -0
- package/src/be/runtime-pools/controllers.ts +150 -0
- package/src/be/runtime-pools/db.ts +526 -0
- package/src/be/runtime-pools/demand.ts +65 -0
- package/src/be/runtime-pools/e2b-images.ts +109 -0
- package/src/be/runtime-pools/errors.ts +8 -0
- package/src/be/runtime-pools/lifecycle.ts +44 -0
- package/src/be/runtime-pools/reachability.ts +30 -0
- package/src/be/runtime-pools/recovery.ts +248 -0
- package/src/be/runtime-pools/remote-controller.ts +144 -0
- package/src/be/runtime-pools/routing.ts +304 -0
- package/src/be/runtime-pools/seed.ts +110 -0
- package/src/be/runtime-pools/supervisor.ts +981 -0
- package/src/be/runtime-pools/tokens.ts +57 -0
- package/src/be/scripts/typecheck.ts +48 -3
- package/src/be/secret-registry.ts +17 -1
- package/src/be/skill-usage.ts +467 -0
- package/src/be/swarm-config-guard.ts +59 -2
- package/src/be/telemetry-enable.ts +66 -0
- package/src/be/telemetry-ingest-anchor.ts +77 -0
- package/src/be/users.ts +173 -23
- package/src/be/worker-nudge-listener.ts +28 -0
- package/src/be/worker-nudges.ts +22 -0
- package/src/cli.tsx +22 -3
- package/src/commands/controller.ts +180 -0
- package/src/commands/onboard/non-interactive.ts +36 -12
- package/src/commands/onboard/types.ts +1 -1
- package/src/commands/onboard.tsx +3 -0
- package/src/commands/push-delivery.ts +230 -0
- package/src/commands/runner.ts +560 -276
- package/src/e2b/dispatch.ts +15 -1
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/fleet-benchmark.ts +157 -0
- package/src/heartbeat/heartbeat.ts +53 -135
- package/src/hooks/hook.ts +3 -2
- package/src/http/agents.ts +21 -0
- package/src/http/all-routes.ts +6 -0
- package/src/http/apps.ts +4 -2
- package/src/http/auth.ts +4 -7
- package/src/http/config.ts +58 -21
- package/src/http/controllers-connect.ts +206 -0
- package/src/http/core.ts +108 -14
- package/src/http/favorite-owner.ts +31 -1
- package/src/http/fleet-benchmark.ts +206 -0
- package/src/http/index.ts +38 -6
- package/src/http/mcp.ts +3 -8
- package/src/http/poll.ts +31 -2
- package/src/http/realtime.ts +1 -1
- package/src/http/request-principal.ts +2 -0
- package/src/http/runtime-pools.ts +527 -0
- package/src/http/session-data.ts +2 -0
- package/src/http/sessions.ts +100 -23
- package/src/http/skills.ts +173 -0
- package/src/http/status.ts +25 -1
- package/src/http/tasks.ts +14 -1
- package/src/http/telemetry-ui.ts +102 -0
- package/src/http/used-by.ts +140 -0
- package/src/http/utils.ts +7 -1
- package/src/http/workflows.ts +10 -2
- package/src/jira/app.ts +1 -2
- package/src/kv-reserved-namespaces.ts +1 -0
- package/src/linear/app.ts +1 -2
- package/src/providers/acp-target-catalog.ts +75 -1
- package/src/providers/acp-targets.ts +114 -0
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +1 -1
- package/src/providers/codex-adapter.ts +5 -1
- package/src/providers/opencode-adapter.ts +2 -1
- package/src/providers/pi-mono-adapter.ts +41 -26
- package/src/providers/pricing-sources.md +2 -0
- package/src/providers/skill-invoke.ts +39 -3
- package/src/rbac/legacy-policy.ts +8 -0
- package/src/rbac/permissions.ts +16 -0
- package/src/rbac/types.ts +2 -0
- package/src/realtime/auth.ts +13 -0
- package/src/realtime/channels.ts +24 -0
- package/src/realtime/transport.ts +94 -15
- package/src/realtime/worker-client.ts +176 -0
- package/src/runtime-providers/controller-protocol.ts +97 -0
- package/src/runtime-providers/controller.ts +86 -0
- package/src/runtime-providers/docker.ts +235 -0
- package/src/runtime-providers/e2b.ts +217 -0
- package/src/runtime-providers/index.ts +37 -0
- package/src/runtime-providers/static.ts +26 -0
- package/src/runtime-providers/types.ts +92 -0
- package/src/runtime-providers/worker-api-url.ts +11 -0
- package/src/scripts-runtime/sdk-allowlist.ts +6 -0
- package/src/scripts-runtime/types/stdlib.d.ts +15 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +1 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
- package/src/server.ts +12 -0
- package/src/slack/router.ts +7 -5
- package/src/tasks/worker-follow-up.ts +80 -52
- package/src/telemetry-context.ts +6 -0
- package/src/telemetry-contract/EVENTS.md +14 -1
- package/src/telemetry-contract/SOURCE.json +4 -4
- package/src/telemetry-contract/catalog.json +155 -0
- package/src/telemetry-contract/types.gen.ts +248 -4
- package/src/telemetry-ui-events.ts +130 -0
- package/src/telemetry.ts +43 -3
- package/src/tests/acp-adapter.test.ts +129 -0
- package/src/tests/claude-adapter.test.ts +6 -2
- package/src/tests/codex-adapter.test.ts +6 -2
- package/src/tests/config-internal-keys.test.ts +27 -0
- package/src/tests/config-session-auth.test.ts +19 -3
- package/src/tests/db-retention.test.ts +50 -10
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/e2b-dispatch.test.ts +28 -1
- package/src/tests/e2e-runtime-pools.test.ts +51 -0
- package/src/tests/entrypoint-acp-target-binary.test.ts +38 -1
- package/src/tests/favorites.test.ts +188 -0
- package/src/tests/fetch-resolved-env.test.ts +59 -1
- package/src/tests/fleet-benchmark.test.ts +453 -0
- package/src/tests/harness-model-support.test.ts +70 -2
- package/src/tests/heartbeat-orphan-resume.test.ts +24 -0
- package/src/tests/heartbeat-reboot-live.test.ts +31 -0
- package/src/tests/heartbeat-supersede-resume.test.ts +21 -0
- package/src/tests/hook-runtime-close.test.ts +64 -0
- package/src/tests/http-task-write-ownership.test.ts +8 -1
- package/src/tests/integration-disable-flags.test.ts +45 -0
- package/src/tests/migration-206-runtime-pools.test.ts +134 -0
- package/src/tests/migration-207-runtime-session-tokens.test.ts +45 -0
- package/src/tests/migration-208-task-runtime-dispatch.test.ts +30 -0
- package/src/tests/multi-runtime-registration.test.ts +219 -4
- package/src/tests/onboard-non-interactive.test.ts +104 -6
- package/src/tests/opencode-adapter.test.ts +6 -2
- package/src/tests/org-website.test.ts +115 -0
- package/src/tests/pi-mono-adapter.test.ts +74 -10
- package/src/tests/rbac-admission-e2e.test.ts +4 -4
- package/src/tests/rbac-engine.test.ts +8 -1
- package/src/tests/realtime-room-auth.test.ts +49 -0
- package/src/tests/repo-allow-merge-gate.test.ts +8 -1
- package/src/tests/runner-exit-after-tasks.test.ts +163 -0
- package/src/tests/runner-finish-retry.test.ts +466 -0
- package/src/tests/runner-harness-telemetry-env.test.ts +105 -0
- package/src/tests/runner-push-delivery.test.ts +670 -0
- package/src/tests/runner-slot-reconcile.test.ts +89 -1
- package/src/tests/runtime-child-token-cleanup.test.ts +172 -0
- package/src/tests/runtime-controller-token.test.ts +254 -0
- package/src/tests/runtime-demand.test.ts +119 -0
- package/src/tests/runtime-e2b-pools.test.ts +847 -0
- package/src/tests/runtime-pool-reachability.test.ts +328 -0
- package/src/tests/runtime-pool-routing.test.ts +817 -0
- package/src/tests/runtime-pools-db.test.ts +275 -0
- package/src/tests/runtime-pools-http.test.ts +506 -0
- package/src/tests/runtime-pools-ownership-guards.test.ts +235 -0
- package/src/tests/runtime-pools-seed.test.ts +203 -0
- package/src/tests/runtime-pools-test-utils.ts +128 -0
- package/src/tests/runtime-provider-registration.test.ts +133 -0
- package/src/tests/runtime-providers-docker.test.ts +400 -0
- package/src/tests/runtime-providers-e2b-transport.test.ts +50 -0
- package/src/tests/runtime-providers-e2b.test.ts +335 -0
- package/src/tests/runtime-recovery.test.ts +745 -0
- package/src/tests/runtime-remote-controller.test.ts +846 -0
- package/src/tests/runtime-supervisor-failures.test.ts +387 -0
- package/src/tests/runtime-supervisor.test.ts +1039 -0
- package/src/tests/runtime-token-auth.test.ts +897 -0
- package/src/tests/script-connections.test.ts +7 -0
- package/src/tests/secret-scrubber.test.ts +17 -2
- package/src/tests/session-costs-codex-recompute.test.ts +49 -0
- package/src/tests/session-tokens.test.ts +13 -3
- package/src/tests/skill-invoke.test.ts +142 -0
- package/src/tests/skill-usage-cohorts.test.ts +232 -0
- package/src/tests/skill-usage.test.ts +348 -0
- package/src/tests/slack-attachments-block.test.ts +23 -0
- package/src/tests/slack-render-v2.test.ts +6 -0
- package/src/tests/status-instance.test.ts +71 -0
- package/src/tests/task-supersede-resume.test.ts +87 -4
- package/src/tests/telemetry-enable.test.ts +113 -0
- package/src/tests/telemetry-ui-route.test.ts +195 -0
- package/src/tests/tool-annotations.test.ts +1 -1
- package/src/tests/used-by-route.test.ts +237 -0
- package/src/tests/worker-nudges.test.ts +653 -0
- package/src/tests/worker-realtime-client.test.ts +188 -0
- package/src/tests/workflow-sub-workflow.test.ts +22 -0
- package/src/tools/app-upsert.ts +1 -1
- package/src/tools/runtime-controller-list.ts +28 -0
- package/src/tools/runtime-pool-bind-agent.ts +29 -0
- package/src/tools/runtime-pool-common.ts +37 -0
- package/src/tools/runtime-pool-create-agent.ts +29 -0
- package/src/tools/runtime-pool-delete.ts +27 -0
- package/src/tools/runtime-pool-list.ts +27 -0
- package/src/tools/runtime-pool-upsert.ts +31 -0
- package/src/tools/script-common.ts +1 -1
- package/src/tools/send-task.ts +3 -2
- package/src/tools/tool-config.ts +6 -0
- package/src/types.ts +137 -2
- package/src/utils/config-secrets.ts +1 -0
- package/src/utils/lead-monitor-channels.ts +3 -0
- package/src/utils/org-website.ts +104 -0
- package/src/utils/request-auth-context.ts +10 -2
- package/src/utils/runtime-pools-flag.ts +11 -0
- package/src/utils/secret-scrubber.ts +9 -0
- package/src/utils/session-token-connections.ts +20 -0
- package/templates/skills/apps/content.md +1 -1
- package/templates/skills/code-quality/content.md +9 -1
- package/templates/skills/db-query-guidance/content.md +9 -0
- package/templates/skills/swarm-scripts/SKILL.md +1 -1
- package/templates/skills/swarm-scripts/content.md +1 -1
- package/templates/skills/work-on-task/SKILL.md +1 -1
- package/templates/skills/work-on-task/content.md +1 -1
- package/dist/{cli-qd97v6z2.js → cli-1qtgd1h1.js} +3 -3
- package/dist/{cli-cmxkbzzs.js → cli-j0w59p15.js} +6 -6
- package/dist/{google-generative-ai-b8zxrpax.js → google-generative-ai-pvhm0dq1.js} +1 -1
- package/dist/{google-vertex-nrdd697t.js → google-vertex-tek9sqe2.js} +4 -4
- package/dist/{mistral-conversations-059y51zt.js → mistral-conversations-rjxa9s1j.js} +3 -3
- package/dist/{openai-completions-663yncfq.js → openai-completions-44gb0zsk.js} +12 -12
|
@@ -3,44 +3,45 @@ import {
|
|
|
3
3
|
} from "./cli-x6z90nq9.js";
|
|
4
4
|
import {
|
|
5
5
|
checkCursorCredentials
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-231av4y6.js";
|
|
7
7
|
import {
|
|
8
8
|
checkGrokCredentials
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-280gnz4v.js";
|
|
10
10
|
import {
|
|
11
11
|
createSkillInvokeTracker,
|
|
12
12
|
isSkillLoaderCall,
|
|
13
13
|
skillFromToolArgs
|
|
14
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-ge593j7e.js";
|
|
15
15
|
import {
|
|
16
16
|
checkCodexCredentials,
|
|
17
17
|
codexUserHome
|
|
18
|
-
} from "./cli-
|
|
18
|
+
} from "./cli-2qbs2tvf.js";
|
|
19
19
|
import {
|
|
20
20
|
checkClaudeManagedCredentials
|
|
21
|
-
} from "./cli-
|
|
21
|
+
} from "./cli-k2v5x13t.js";
|
|
22
22
|
import {
|
|
23
23
|
checkDevinCredentials
|
|
24
|
-
} from "./cli-
|
|
24
|
+
} from "./cli-e3pmyt39.js";
|
|
25
25
|
import {
|
|
26
26
|
checkOpencodeCredentials
|
|
27
|
-
} from "./cli-
|
|
27
|
+
} from "./cli-ywh2a87k.js";
|
|
28
28
|
import {
|
|
29
29
|
checkDshCredentials
|
|
30
|
-
} from "./cli-
|
|
30
|
+
} from "./cli-zxm9p3x4.js";
|
|
31
31
|
import {
|
|
32
32
|
checkAmpCredentials,
|
|
33
33
|
liveTestAmpCredentials
|
|
34
|
-
} from "./cli-
|
|
34
|
+
} from "./cli-n8ybnv1k.js";
|
|
35
35
|
import {
|
|
36
|
+
isLeadChannelMonitoringEnabled,
|
|
36
37
|
isUnknownModelError,
|
|
37
38
|
renderMemoriesPrompt,
|
|
38
39
|
writeSkillsToFilesystem
|
|
39
|
-
} from "./cli-
|
|
40
|
+
} from "./cli-2rbt7at8.js";
|
|
40
41
|
import {
|
|
41
42
|
ACP_TARGET_IDS,
|
|
42
43
|
isAcpTarget
|
|
43
|
-
} from "./cli-
|
|
44
|
+
} from "./cli-7a0sde2x.js";
|
|
44
45
|
import {
|
|
45
46
|
CODEX_OAUTH_POOL_SLOTS_ENV,
|
|
46
47
|
countCodexOAuthPoolSlots,
|
|
@@ -49,7 +50,7 @@ import {
|
|
|
49
50
|
} from "./cli-bqjfjex4.js";
|
|
50
51
|
import {
|
|
51
52
|
checkClaudeCredentials
|
|
52
|
-
} from "./cli-
|
|
53
|
+
} from "./cli-62bwwc2q.js";
|
|
53
54
|
import {
|
|
54
55
|
getContextWindowSize
|
|
55
56
|
} from "./cli-7avy4v8w.js";
|
|
@@ -66,21 +67,18 @@ import {
|
|
|
66
67
|
isAzureDevOpsUrl,
|
|
67
68
|
parseAzureDevOpsRepoUrl,
|
|
68
69
|
resolveScriptsOnlyMode
|
|
69
|
-
} from "./cli-
|
|
70
|
-
import {
|
|
71
|
-
getApiKey
|
|
72
|
-
} from "./cli-f14fvzag.js";
|
|
70
|
+
} from "./cli-p8f7dqgt.js";
|
|
73
71
|
import {
|
|
74
72
|
terminateRegisteredProcessGroups
|
|
75
73
|
} from "./cli-zt3w1cn1.js";
|
|
76
74
|
import {
|
|
77
75
|
validateJsonSchema
|
|
78
|
-
} from "./cli-
|
|
76
|
+
} from "./cli-wfvedq5w.js";
|
|
79
77
|
import {
|
|
80
78
|
authJsonToCredentialSelection,
|
|
81
79
|
credentialsToAuthJson,
|
|
82
80
|
loadAllCodexOAuthSlots
|
|
83
|
-
} from "./cli-
|
|
81
|
+
} from "./cli-7jykv7ef.js";
|
|
84
82
|
import {
|
|
85
83
|
ensure,
|
|
86
84
|
initOtel,
|
|
@@ -90,25 +88,28 @@ import {
|
|
|
90
88
|
startSpan,
|
|
91
89
|
withSpan,
|
|
92
90
|
withSpanContext
|
|
93
|
-
} from "./cli-
|
|
91
|
+
} from "./cli-nkjwe4z7.js";
|
|
94
92
|
import {
|
|
93
|
+
MASKED_SECRET_VALUE,
|
|
95
94
|
initTelemetry,
|
|
96
95
|
init_api_drain,
|
|
97
96
|
init_codex_auth_failure,
|
|
97
|
+
init_config_secrets,
|
|
98
98
|
init_telemetry,
|
|
99
99
|
init_telemetry_context,
|
|
100
100
|
isApiDrainingResponse,
|
|
101
101
|
isCodexAuthFailureReason,
|
|
102
102
|
mapTriggerSurface,
|
|
103
103
|
telemetry
|
|
104
|
-
} from "./cli-
|
|
104
|
+
} from "./cli-0d2rqhvq.js";
|
|
105
105
|
import {
|
|
106
106
|
ProviderNameSchema,
|
|
107
|
+
WorkerNudgeSchema,
|
|
107
108
|
init_types,
|
|
108
109
|
isTerminalTaskStatus,
|
|
109
110
|
parseWorkerModelTierOverrides,
|
|
110
111
|
resolveTaskModelSelection
|
|
111
|
-
} from "./cli-
|
|
112
|
+
} from "./cli-hsem16hb.js";
|
|
112
113
|
import {
|
|
113
114
|
buildContextPreamble,
|
|
114
115
|
buildResumeContextPreamble,
|
|
@@ -130,7 +131,7 @@ import {
|
|
|
130
131
|
taskAttachmentFetchCommand,
|
|
131
132
|
writeIdentityBaselines,
|
|
132
133
|
writeProfileFileFromDb
|
|
133
|
-
} from "./cli-
|
|
134
|
+
} from "./cli-rrbctenq.js";
|
|
134
135
|
import {
|
|
135
136
|
init_steering_enabled,
|
|
136
137
|
isSteeringEnabled
|
|
@@ -168,10 +169,6 @@ import {
|
|
|
168
169
|
getOpenRouterBaseUrl,
|
|
169
170
|
init_openrouter_base_url
|
|
170
171
|
} from "./cli-a35hzdve.js";
|
|
171
|
-
import {
|
|
172
|
-
getMcpBaseUrl,
|
|
173
|
-
init_constants
|
|
174
|
-
} from "./cli-gd4favx9.js";
|
|
175
172
|
import {
|
|
176
173
|
harnessModelMismatch,
|
|
177
174
|
init_runtime_model_catalog,
|
|
@@ -179,11 +176,19 @@ import {
|
|
|
179
176
|
refreshRuntimeModelCatalog,
|
|
180
177
|
runtimeHarnessSections
|
|
181
178
|
} from "./cli-014vns2y.js";
|
|
179
|
+
import {
|
|
180
|
+
getMcpBaseUrl,
|
|
181
|
+
init_constants
|
|
182
|
+
} from "./cli-gd4favx9.js";
|
|
183
|
+
import {
|
|
184
|
+
getApiKey,
|
|
185
|
+
init_api_key
|
|
186
|
+
} from "./cli-a1b9b32n.js";
|
|
182
187
|
import {
|
|
183
188
|
init_secret_scrubber,
|
|
184
189
|
registerSensitiveKeyName,
|
|
185
190
|
scrubSecrets
|
|
186
|
-
} from "./cli-
|
|
191
|
+
} from "./cli-d161g69q.js";
|
|
187
192
|
import {
|
|
188
193
|
__require
|
|
189
194
|
} from "./cli-bc05qbss.js";
|
|
@@ -220,47 +225,47 @@ async function materializeCodexAuthJson(_slot, creds, deps = {}) {
|
|
|
220
225
|
async function createProviderAdapter(provider) {
|
|
221
226
|
switch (provider) {
|
|
222
227
|
case "claude": {
|
|
223
|
-
const { ClaudeAdapter } = await import("./claude-adapter-
|
|
228
|
+
const { ClaudeAdapter } = await import("./claude-adapter-akrzg6jh.js");
|
|
224
229
|
return new ClaudeAdapter;
|
|
225
230
|
}
|
|
226
231
|
case "pi": {
|
|
227
|
-
const { PiMonoAdapter } = await import("./pi-mono-adapter-
|
|
232
|
+
const { PiMonoAdapter } = await import("./pi-mono-adapter-fx6k5wwh.js");
|
|
228
233
|
return new PiMonoAdapter;
|
|
229
234
|
}
|
|
230
235
|
case "codex": {
|
|
231
|
-
const { CodexAdapter } = await import("./codex-adapter-
|
|
236
|
+
const { CodexAdapter } = await import("./codex-adapter-9ag75whm.js");
|
|
232
237
|
return new CodexAdapter;
|
|
233
238
|
}
|
|
234
239
|
case "claude-managed": {
|
|
235
|
-
const { ClaudeManagedAdapter } = await import("./claude-managed-adapter-
|
|
240
|
+
const { ClaudeManagedAdapter } = await import("./claude-managed-adapter-kqqqhp2q.js");
|
|
236
241
|
return new ClaudeManagedAdapter;
|
|
237
242
|
}
|
|
238
243
|
case "devin": {
|
|
239
|
-
const { DevinAdapter } = await import("./devin-adapter-
|
|
244
|
+
const { DevinAdapter } = await import("./devin-adapter-xgtj680j.js");
|
|
240
245
|
return new DevinAdapter;
|
|
241
246
|
}
|
|
242
247
|
case "opencode": {
|
|
243
|
-
const { OpencodeAdapter } = await import("./opencode-adapter-
|
|
248
|
+
const { OpencodeAdapter } = await import("./opencode-adapter-f1zby94p.js");
|
|
244
249
|
return new OpencodeAdapter;
|
|
245
250
|
}
|
|
246
251
|
case "dsh": {
|
|
247
|
-
const { DshAdapter } = await import("./dsh-adapter-
|
|
252
|
+
const { DshAdapter } = await import("./dsh-adapter-2h8m4cab.js");
|
|
248
253
|
return new DshAdapter;
|
|
249
254
|
}
|
|
250
255
|
case "amp": {
|
|
251
|
-
const { AmpAdapter } = await import("./amp-adapter-
|
|
256
|
+
const { AmpAdapter } = await import("./amp-adapter-ypyf5s1x.js");
|
|
252
257
|
return new AmpAdapter;
|
|
253
258
|
}
|
|
254
259
|
case "cursor": {
|
|
255
|
-
const { CursorAdapter } = await import("./cursor-adapter-
|
|
260
|
+
const { CursorAdapter } = await import("./cursor-adapter-t4pr1m3c.js");
|
|
256
261
|
return new CursorAdapter;
|
|
257
262
|
}
|
|
258
263
|
case "grok": {
|
|
259
|
-
const { GrokAdapter } = await import("./grok-adapter-
|
|
264
|
+
const { GrokAdapter } = await import("./grok-adapter-1err1me7.js");
|
|
260
265
|
return new GrokAdapter;
|
|
261
266
|
}
|
|
262
267
|
case "acp": {
|
|
263
|
-
const { ACPAdapter } = await import("./acp-adapter-
|
|
268
|
+
const { ACPAdapter } = await import("./acp-adapter-1z9p3fvx.js");
|
|
264
269
|
return new ACPAdapter;
|
|
265
270
|
}
|
|
266
271
|
default:
|
|
@@ -268,11 +273,174 @@ async function createProviderAdapter(provider) {
|
|
|
268
273
|
}
|
|
269
274
|
}
|
|
270
275
|
|
|
276
|
+
// src/realtime/worker-client.ts
|
|
277
|
+
init_types();
|
|
278
|
+
init_api_key();
|
|
279
|
+
init_secret_scrubber();
|
|
280
|
+
function workerReconnectDelay(attempt, random = Math.random()) {
|
|
281
|
+
return Math.min(30000, Math.max(1000, 1000 * 2 ** Math.min(attempt, 5) * (0.8 + random * 0.4)));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
class WorkerRealtimeClient {
|
|
285
|
+
config;
|
|
286
|
+
socket;
|
|
287
|
+
retry;
|
|
288
|
+
connectTimeout;
|
|
289
|
+
stopped = true;
|
|
290
|
+
connected = false;
|
|
291
|
+
connectedAt = 0;
|
|
292
|
+
disconnectedAt = Date.now();
|
|
293
|
+
attempt = 0;
|
|
294
|
+
listeners = new Set;
|
|
295
|
+
pending = new Map;
|
|
296
|
+
waiters = new Set;
|
|
297
|
+
constructor(config) {
|
|
298
|
+
this.config = config;
|
|
299
|
+
}
|
|
300
|
+
start() {
|
|
301
|
+
if (!this.stopped)
|
|
302
|
+
return;
|
|
303
|
+
this.stopped = false;
|
|
304
|
+
this.attempt = 0;
|
|
305
|
+
this.disconnectedAt = Date.now();
|
|
306
|
+
this.connect();
|
|
307
|
+
}
|
|
308
|
+
stop() {
|
|
309
|
+
this.stopped = true;
|
|
310
|
+
this.connected = false;
|
|
311
|
+
clearTimeout(this.retry);
|
|
312
|
+
clearTimeout(this.connectTimeout);
|
|
313
|
+
const socket = this.socket;
|
|
314
|
+
this.socket = undefined;
|
|
315
|
+
socket?.close();
|
|
316
|
+
this.pending.clear();
|
|
317
|
+
for (const waiter of this.waiters)
|
|
318
|
+
waiter.finish(null);
|
|
319
|
+
}
|
|
320
|
+
isConnected() {
|
|
321
|
+
return this.connected;
|
|
322
|
+
}
|
|
323
|
+
disconnectedSince() {
|
|
324
|
+
return this.disconnectedAt;
|
|
325
|
+
}
|
|
326
|
+
onNudge(fn) {
|
|
327
|
+
this.listeners.add(fn);
|
|
328
|
+
return () => this.listeners.delete(fn);
|
|
329
|
+
}
|
|
330
|
+
waitForNudge(kinds, timeoutMs) {
|
|
331
|
+
for (const [key, nudge] of this.pending) {
|
|
332
|
+
if (!kinds.includes(nudge.kind))
|
|
333
|
+
continue;
|
|
334
|
+
this.pending.delete(key);
|
|
335
|
+
return Promise.resolve(nudge);
|
|
336
|
+
}
|
|
337
|
+
if (this.stopped)
|
|
338
|
+
return Promise.resolve(null);
|
|
339
|
+
return new Promise((resolve) => {
|
|
340
|
+
const waiter = {
|
|
341
|
+
kinds,
|
|
342
|
+
finish: (nudge) => {
|
|
343
|
+
clearTimeout(timer);
|
|
344
|
+
this.waiters.delete(waiter);
|
|
345
|
+
resolve(nudge);
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
const timer = setTimeout(() => waiter.finish(null), timeoutMs);
|
|
349
|
+
this.waiters.add(waiter);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
emit(nudge) {
|
|
353
|
+
let delivered = this.listeners.size > 0;
|
|
354
|
+
for (const listener of this.listeners)
|
|
355
|
+
listener(nudge);
|
|
356
|
+
for (const waiter of this.waiters) {
|
|
357
|
+
if (!waiter.kinds.includes(nudge.kind))
|
|
358
|
+
continue;
|
|
359
|
+
delivered = true;
|
|
360
|
+
waiter.finish(nudge);
|
|
361
|
+
}
|
|
362
|
+
if (!delivered) {
|
|
363
|
+
this.pending.set(`${nudge.kind}:${nudge.taskId ?? ""}`, nudge);
|
|
364
|
+
if (this.pending.size > 128)
|
|
365
|
+
this.pending.delete(this.pending.keys().next().value);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
connect() {
|
|
369
|
+
if (this.stopped)
|
|
370
|
+
return;
|
|
371
|
+
const url = new URL("/api/realtime", this.config.apiUrl);
|
|
372
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
373
|
+
try {
|
|
374
|
+
const socket = new WebSocket(url, {
|
|
375
|
+
headers: {
|
|
376
|
+
Authorization: `Bearer ${this.config.apiKey ?? getApiKey()}`,
|
|
377
|
+
"X-Agent-ID": this.config.agentId,
|
|
378
|
+
"X-Runtime-Instance-ID": this.config.runtimeInstanceId
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
this.socket = socket;
|
|
382
|
+
this.connectTimeout = setTimeout(() => socket.close(), 15000);
|
|
383
|
+
socket.onopen = () => socket.send(JSON.stringify({
|
|
384
|
+
id: 1,
|
|
385
|
+
op: "subscribe",
|
|
386
|
+
namespace: `worker:${this.config.agentId}`,
|
|
387
|
+
name: "nudge"
|
|
388
|
+
}));
|
|
389
|
+
socket.onmessage = (event) => {
|
|
390
|
+
if (this.socket !== socket || this.stopped)
|
|
391
|
+
return;
|
|
392
|
+
try {
|
|
393
|
+
const frame = JSON.parse(String(event.data));
|
|
394
|
+
if (typeof frame.seq === "number")
|
|
395
|
+
socket.send(JSON.stringify({ ack: frame.seq }));
|
|
396
|
+
if (frame.id === 1 && frame.type === "result") {
|
|
397
|
+
clearTimeout(this.connectTimeout);
|
|
398
|
+
this.connected = true;
|
|
399
|
+
this.connectedAt = Date.now();
|
|
400
|
+
for (const kind of ["work", "config"])
|
|
401
|
+
this.emit({ v: 1, kind, at: new Date().toISOString() });
|
|
402
|
+
} else if (frame.id === 1 && frame.type === "error") {
|
|
403
|
+
console.warn(scrubSecrets("[worker-realtime] Subscription failed. Reconnecting."));
|
|
404
|
+
socket.close();
|
|
405
|
+
} else if (frame.type === "channel" && frame.namespace === `worker:${this.config.agentId}` && frame.name === "nudge") {
|
|
406
|
+
const parsed = WorkerNudgeSchema.safeParse(frame.data);
|
|
407
|
+
if (parsed.success)
|
|
408
|
+
this.emit(parsed.data);
|
|
409
|
+
}
|
|
410
|
+
} catch {}
|
|
411
|
+
};
|
|
412
|
+
socket.onerror = () => socket.close();
|
|
413
|
+
socket.onclose = () => {
|
|
414
|
+
if (this.socket !== socket)
|
|
415
|
+
return;
|
|
416
|
+
clearTimeout(this.connectTimeout);
|
|
417
|
+
if (this.connected) {
|
|
418
|
+
this.disconnectedAt = Date.now();
|
|
419
|
+
if (this.disconnectedAt - this.connectedAt >= 30000)
|
|
420
|
+
this.attempt = 0;
|
|
421
|
+
}
|
|
422
|
+
this.connected = false;
|
|
423
|
+
this.socket = undefined;
|
|
424
|
+
this.scheduleReconnect();
|
|
425
|
+
};
|
|
426
|
+
} catch {
|
|
427
|
+
this.scheduleReconnect();
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
scheduleReconnect() {
|
|
431
|
+
if (this.stopped)
|
|
432
|
+
return;
|
|
433
|
+
const delay = workerReconnectDelay(this.attempt++);
|
|
434
|
+
this.retry = setTimeout(() => this.connect(), delay);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
271
438
|
// src/commands/runner.ts
|
|
272
439
|
init_telemetry();
|
|
273
440
|
init_telemetry_context();
|
|
274
441
|
init_types();
|
|
275
442
|
init_api_drain();
|
|
443
|
+
init_api_key();
|
|
276
444
|
|
|
277
445
|
// src/utils/budget-backoff.ts
|
|
278
446
|
var BUDGET_BACKOFF_CAP_MS = 5 * 60 * 1000;
|
|
@@ -285,6 +453,7 @@ function computeBudgetBackoffMs(consecutiveRefusals, basePollMs) {
|
|
|
285
453
|
|
|
286
454
|
// src/commands/runner.ts
|
|
287
455
|
init_codex_auth_failure();
|
|
456
|
+
init_config_secrets();
|
|
288
457
|
init_constants();
|
|
289
458
|
init_credentials();
|
|
290
459
|
|
|
@@ -961,7 +1130,7 @@ var CREDENTIAL_PROVIDER_CHECKERS = {
|
|
|
961
1130
|
devin: (env) => checkDevinCredentials(env),
|
|
962
1131
|
opencode: (env, opts) => checkOpencodeCredentials(env, opts),
|
|
963
1132
|
pi: async (env, opts) => {
|
|
964
|
-
const { checkPiMonoCredentials } = await import("./pi-mono-adapter-
|
|
1133
|
+
const { checkPiMonoCredentials } = await import("./pi-mono-adapter-fx6k5wwh.js");
|
|
965
1134
|
return checkPiMonoCredentials(env, opts);
|
|
966
1135
|
},
|
|
967
1136
|
acp: (env) => {
|
|
@@ -1211,7 +1380,7 @@ async function validateProviderCredentials(provider, env = process.env, presence
|
|
|
1211
1380
|
latency_ms: Date.now() - startedAt
|
|
1212
1381
|
};
|
|
1213
1382
|
}
|
|
1214
|
-
const { liveTestCursorKey } = await import("./cursor-adapter-
|
|
1383
|
+
const { liveTestCursorKey } = await import("./cursor-adapter-t4pr1m3c.js");
|
|
1215
1384
|
const result = await liveTestCursorKey(apiKey);
|
|
1216
1385
|
return result.ok ? { ok: true, latency_ms: Date.now() - startedAt } : { ok: false, error: result.error, latency_ms: Date.now() - startedAt };
|
|
1217
1386
|
}
|
|
@@ -1556,6 +1725,150 @@ async function refreshIdentityIfChanged(ctx, cached) {
|
|
|
1556
1725
|
// src/commands/runner.ts
|
|
1557
1726
|
init_profile_sync();
|
|
1558
1727
|
|
|
1728
|
+
// src/commands/push-delivery.ts
|
|
1729
|
+
init_secret_scrubber();
|
|
1730
|
+
function resolveWorkerDeliveryMode(serverMode, isLead, env = process.env, pollRequired = false) {
|
|
1731
|
+
const mode = env.SWARM_DELIVERY_MODE === "push" || env.SWARM_DELIVERY_MODE === "poll" ? env.SWARM_DELIVERY_MODE : serverMode ?? "poll";
|
|
1732
|
+
if ((mode === "push" || pollRequired) && isLead && (pollRequired || isLeadChannelMonitoringEnabled(env))) {
|
|
1733
|
+
console.warn(scrubSecrets("[runner] LEAD_MONITOR_CHANNELS requires poll delivery. Using poll."));
|
|
1734
|
+
return "poll";
|
|
1735
|
+
}
|
|
1736
|
+
return mode;
|
|
1737
|
+
}
|
|
1738
|
+
function updateWorkerDeliveryMode(previousMode, registration, isLead, env = process.env) {
|
|
1739
|
+
const mode = resolveWorkerDeliveryMode(registration.deliveryMode, isLead, env, registration.pollRequired);
|
|
1740
|
+
if (mode !== previousMode) {
|
|
1741
|
+
const override = env.SWARM_DELIVERY_MODE;
|
|
1742
|
+
const source = override === "poll" || override === "push" ? `SWARM_DELIVERY_MODE override: ${override}` : registration.deliveryMode ? `register response: ${registration.deliveryMode}` : "register response omitted deliveryMode, default: poll";
|
|
1743
|
+
const required = isLead && (registration.pollRequired || isLeadChannelMonitoringEnabled(env)) ? ", LEAD_MONITOR_CHANNELS requires poll" : "";
|
|
1744
|
+
console.log(scrubSecrets(`[runner] Delivery mode: ${mode} (${source}${required}).`));
|
|
1745
|
+
}
|
|
1746
|
+
return mode;
|
|
1747
|
+
}
|
|
1748
|
+
function taskReconciliation(checks) {
|
|
1749
|
+
return {
|
|
1750
|
+
cancelTaskIds: checks.push && !checks.safety ? checks.cancelTaskIds : undefined,
|
|
1751
|
+
checkStatus: !checks.push || checks.safety
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1754
|
+
function shouldRunDeliveryLoop(mode, shuttingDown) {
|
|
1755
|
+
return mode !== "push" || !shuttingDown;
|
|
1756
|
+
}
|
|
1757
|
+
function deliverySchedule(options) {
|
|
1758
|
+
const blocked = options.draining || options.activeCount >= options.maxConcurrent;
|
|
1759
|
+
return {
|
|
1760
|
+
poll: !blocked && (!options.push || options.work),
|
|
1761
|
+
singlePoll: options.mode === "push",
|
|
1762
|
+
waitKind: options.push ? "push" : options.mode === "push" && !blocked ? "fallback" : "sleep",
|
|
1763
|
+
waitMs: blocked || options.push && options.activeCount > 0 ? 1000 : options.push ? Math.max(0, Math.min(resolvePushSafetyPollMs(), 30000 - ((options.now ?? Date.now()) - options.lastPushPingAt))) : options.pollInterval
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1766
|
+
function resolvePushSafetyPollMs(env = process.env) {
|
|
1767
|
+
const value = Number(env.RUNNER_PUSH_SAFETY_POLL_MS);
|
|
1768
|
+
return Number.isFinite(value) && value > 0 ? value : 30000;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
class RunnerPushDelivery {
|
|
1772
|
+
client;
|
|
1773
|
+
lastSafetyAt = -Infinity;
|
|
1774
|
+
fallback = false;
|
|
1775
|
+
work = true;
|
|
1776
|
+
config = false;
|
|
1777
|
+
cancel = new Set;
|
|
1778
|
+
steer = new Set;
|
|
1779
|
+
constructor(client) {
|
|
1780
|
+
this.client = client;
|
|
1781
|
+
client.onNudge((nudge) => this.receive(nudge));
|
|
1782
|
+
}
|
|
1783
|
+
receive(nudge) {
|
|
1784
|
+
if (nudge.kind === "work")
|
|
1785
|
+
this.work = true;
|
|
1786
|
+
if (nudge.kind === "config")
|
|
1787
|
+
this.config = true;
|
|
1788
|
+
if (nudge.kind === "cancel" && nudge.taskId)
|
|
1789
|
+
this.cancel.add(nudge.taskId);
|
|
1790
|
+
if (nudge.kind === "steer" && nudge.taskId)
|
|
1791
|
+
this.steer.add(nudge.taskId);
|
|
1792
|
+
}
|
|
1793
|
+
checks(mode, now = Date.now(), safetyMs = resolvePushSafetyPollMs()) {
|
|
1794
|
+
if (this.client.isConnected()) {
|
|
1795
|
+
if (this.fallback && mode === "push")
|
|
1796
|
+
console.log(scrubSecrets("[runner] Delivery mode: push (push socket reconnected)."));
|
|
1797
|
+
this.fallback = false;
|
|
1798
|
+
} else {
|
|
1799
|
+
if (mode === "push" && now - this.client.disconnectedSince() > 60000 && !this.fallback) {
|
|
1800
|
+
this.fallback = true;
|
|
1801
|
+
console.warn(scrubSecrets("[runner] Delivery mode: poll (push socket unavailable for 60 seconds). Using poll until reconnect."));
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
const push = mode === "push" && !this.fallback;
|
|
1805
|
+
const safety = push && now - this.lastSafetyAt >= safetyMs;
|
|
1806
|
+
if (safety)
|
|
1807
|
+
this.lastSafetyAt = now;
|
|
1808
|
+
if (safety)
|
|
1809
|
+
this.work = true;
|
|
1810
|
+
const checks = {
|
|
1811
|
+
push,
|
|
1812
|
+
safety,
|
|
1813
|
+
work: !push || this.work,
|
|
1814
|
+
config: !push || safety || this.config,
|
|
1815
|
+
cancelTaskIds: new Set(this.cancel),
|
|
1816
|
+
steerTaskIds: new Set(this.steer)
|
|
1817
|
+
};
|
|
1818
|
+
this.config = false;
|
|
1819
|
+
this.cancel.clear();
|
|
1820
|
+
this.steer.clear();
|
|
1821
|
+
return checks;
|
|
1822
|
+
}
|
|
1823
|
+
beginPoll() {
|
|
1824
|
+
this.work = false;
|
|
1825
|
+
}
|
|
1826
|
+
wakeWork() {
|
|
1827
|
+
this.work = true;
|
|
1828
|
+
}
|
|
1829
|
+
schedule(options) {
|
|
1830
|
+
return deliverySchedule({ ...options, work: this.work });
|
|
1831
|
+
}
|
|
1832
|
+
dispatchSteering(checks, taskId, dispatch) {
|
|
1833
|
+
if (checks.push && !checks.safety && !checks.steerTaskIds.has(taskId))
|
|
1834
|
+
return;
|
|
1835
|
+
if (!dispatch() && checks.push)
|
|
1836
|
+
this.steer.add(taskId);
|
|
1837
|
+
}
|
|
1838
|
+
async poll(singlePoll, fetch2) {
|
|
1839
|
+
if (singlePoll)
|
|
1840
|
+
this.beginPoll();
|
|
1841
|
+
let failed = false;
|
|
1842
|
+
const trigger = await fetch2(() => {
|
|
1843
|
+
failed = true;
|
|
1844
|
+
});
|
|
1845
|
+
if (singlePoll && (failed || trigger))
|
|
1846
|
+
this.wakeWork();
|
|
1847
|
+
return { trigger, failed };
|
|
1848
|
+
}
|
|
1849
|
+
async waitForSchedule(schedule, failed = false, pollInterval = 2000) {
|
|
1850
|
+
if (failed) {
|
|
1851
|
+
await Bun.sleep(pollInterval);
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
if (schedule.poll && schedule.waitKind === "push" && (this.work || this.config || this.cancel.size > 0 || this.steer.size > 0))
|
|
1855
|
+
return;
|
|
1856
|
+
const timeout = schedule.waitMs;
|
|
1857
|
+
if (schedule.waitKind === "push")
|
|
1858
|
+
await this.wait(timeout);
|
|
1859
|
+
else if (schedule.waitKind === "fallback")
|
|
1860
|
+
await this.client.waitForNudge(["work", "cancel", "steer", "config"], timeout);
|
|
1861
|
+
else
|
|
1862
|
+
await Bun.sleep(timeout);
|
|
1863
|
+
}
|
|
1864
|
+
async wait(timeoutMs) {
|
|
1865
|
+
const now = Date.now();
|
|
1866
|
+
const untilSafety = this.lastSafetyAt + resolvePushSafetyPollMs() - now;
|
|
1867
|
+
const untilFallback = !this.client.isConnected() && !this.fallback ? this.client.disconnectedSince() + 60001 - now : Infinity;
|
|
1868
|
+
await this.client.waitForNudge(["work", "cancel", "steer", "config"], Math.max(0, Math.min(timeoutMs, untilSafety, untilFallback)));
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1559
1872
|
// src/commands/resume-session.ts
|
|
1560
1873
|
var RESUME_DEPRECATED_REASON = "native resume deprecated — using context preamble";
|
|
1561
1874
|
function resolveResumeSession(_currentProvider, candidates) {
|
|
@@ -1922,11 +2235,23 @@ async function closeAgent(config, role) {
|
|
|
1922
2235
|
console.log(`[${role}] Marking agent as offline...`);
|
|
1923
2236
|
await fetch(`${config.apiUrl}/close`, {
|
|
1924
2237
|
method: "POST",
|
|
1925
|
-
headers
|
|
2238
|
+
headers: { ...headers, "Content-Type": "application/json" },
|
|
2239
|
+
body: JSON.stringify({ runtimeShutdown: true })
|
|
1926
2240
|
});
|
|
1927
2241
|
console.log(`[${role}] Agent marked as offline`);
|
|
1928
2242
|
} catch {}
|
|
1929
2243
|
}
|
|
2244
|
+
function resolveExitAfterTasks(env = process.env) {
|
|
2245
|
+
const raw = env.SWARM_EXIT_AFTER_TASKS?.trim();
|
|
2246
|
+
const value = Number(raw);
|
|
2247
|
+
return raw && Number.isInteger(value) && value > 0 ? value : null;
|
|
2248
|
+
}
|
|
2249
|
+
async function exitAfterTasksIfFinished(state, limit, shutdown) {
|
|
2250
|
+
if (limit === null || state.tasksProcessed < limit || state.activeTasks.size > 0)
|
|
2251
|
+
return false;
|
|
2252
|
+
await shutdown("SWARM_EXIT_AFTER_TASKS");
|
|
2253
|
+
return true;
|
|
2254
|
+
}
|
|
1930
2255
|
var deploymentMemoryRaters = process.env.MEMORY_RATERS;
|
|
1931
2256
|
var rowOverriddenBootEnv = new Map;
|
|
1932
2257
|
async function fetchResolvedEnv(apiUrl, apiKey, agentId, baseEnv = process.env, taskModel, sessionContext) {
|
|
@@ -1942,6 +2267,8 @@ async function fetchResolvedEnv(apiUrl, apiKey, agentId, baseEnv = process.env,
|
|
|
1942
2267
|
const headers = { "X-Agent-ID": agentId };
|
|
1943
2268
|
if (apiKey)
|
|
1944
2269
|
headers.Authorization = `Bearer ${apiKey}`;
|
|
2270
|
+
if (sessionContext?.taskId)
|
|
2271
|
+
headers["X-Source-Task-Id"] = sessionContext.taskId;
|
|
1945
2272
|
const url = `${apiUrl}/api/config/resolved?agentId=${encodeURIComponent(agentId)}&includeSecrets=true${repoId ? `&repoId=${encodeURIComponent(repoId)}` : ""}`;
|
|
1946
2273
|
const response = await fetch(url, { headers });
|
|
1947
2274
|
if (!response.ok) {
|
|
@@ -1954,8 +2281,13 @@ async function fetchResolvedEnv(apiUrl, apiKey, agentId, baseEnv = process.env,
|
|
|
1954
2281
|
env[key] = bootValue;
|
|
1955
2282
|
}
|
|
1956
2283
|
if (data.configs?.length) {
|
|
2284
|
+
const skippedSecretKeys = [];
|
|
1957
2285
|
scriptsOnlyConfigValue = data.configs.find((config) => config.key === "SCRIPTS_ONLY_MCP")?.value;
|
|
1958
2286
|
for (const config of data.configs) {
|
|
2287
|
+
if (config.isSecret && config.value === MASKED_SECRET_VALUE) {
|
|
2288
|
+
skippedSecretKeys.push(config.key);
|
|
2289
|
+
continue;
|
|
2290
|
+
}
|
|
1959
2291
|
if (isCodexOAuthConfigKey(config.key))
|
|
1960
2292
|
continue;
|
|
1961
2293
|
if (config.isSecret)
|
|
@@ -1966,6 +2298,9 @@ async function fetchResolvedEnv(apiUrl, apiKey, agentId, baseEnv = process.env,
|
|
|
1966
2298
|
}
|
|
1967
2299
|
env[config.key] = config.value;
|
|
1968
2300
|
}
|
|
2301
|
+
if (skippedSecretKeys.length) {
|
|
2302
|
+
console.warn(scrubSecrets(`[env-reload] Skipped masked secrets: ${skippedSecretKeys.join(", ")}`));
|
|
2303
|
+
}
|
|
1969
2304
|
console.log(`[env-reload] Loaded ${data.configs.length} config entries from API`);
|
|
1970
2305
|
}
|
|
1971
2306
|
const codexPoolSlots = countCodexOAuthPoolSlots(data.configs ?? []);
|
|
@@ -2407,7 +2742,37 @@ function jsonOutputCandidates(text) {
|
|
|
2407
2742
|
}
|
|
2408
2743
|
return [...new Set(candidates)];
|
|
2409
2744
|
}
|
|
2410
|
-
|
|
2745
|
+
function finalUpdateDeadline() {
|
|
2746
|
+
const maxSec = Number(process.env.RUNNER_FINISH_RETRY_MAX_SEC);
|
|
2747
|
+
return Date.now() + (Number.isFinite(maxSec) && maxSec > 0 ? maxSec : 300) * 1000;
|
|
2748
|
+
}
|
|
2749
|
+
async function postWithRetry(url, headers, body, deadline, label) {
|
|
2750
|
+
let delay = 1000;
|
|
2751
|
+
for (;; ) {
|
|
2752
|
+
try {
|
|
2753
|
+
const response = await fetch(url, {
|
|
2754
|
+
method: "POST",
|
|
2755
|
+
headers,
|
|
2756
|
+
body: JSON.stringify(body),
|
|
2757
|
+
signal: AbortSignal.timeout(Math.max(1, Math.min(30000, deadline - Date.now())))
|
|
2758
|
+
});
|
|
2759
|
+
if (response.status < 500)
|
|
2760
|
+
return response;
|
|
2761
|
+
throw new Error(`HTTP ${response.status}: ${scrubSecrets(await response.text()).slice(0, 300)}`);
|
|
2762
|
+
} catch (error) {
|
|
2763
|
+
const remaining = deadline - Date.now();
|
|
2764
|
+
if (remaining <= 0)
|
|
2765
|
+
throw error;
|
|
2766
|
+
const wait = Math.min(delay, remaining);
|
|
2767
|
+
console.warn(scrubSecrets(`[runner] ${label} failed. Retry in ${wait}ms: ${error}`));
|
|
2768
|
+
await Bun.sleep(wait);
|
|
2769
|
+
if (Date.now() >= deadline)
|
|
2770
|
+
throw error;
|
|
2771
|
+
delay = Math.min(30000, delay * 2);
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
async function ensureTaskFinished(config, role, taskId, exitCode, failureReason, providerOutput, provider, failureDiagnostics, finalProgress, retryDeadline) {
|
|
2411
2776
|
const headers = {
|
|
2412
2777
|
"X-Agent-ID": config.agentId,
|
|
2413
2778
|
"Content-Type": "application/json"
|
|
@@ -2463,11 +2828,15 @@ ${failureDiagnostics}`;
|
|
|
2463
2828
|
applyFallback(fallback);
|
|
2464
2829
|
}
|
|
2465
2830
|
try {
|
|
2466
|
-
const
|
|
2467
|
-
|
|
2468
|
-
headers,
|
|
2469
|
-
|
|
2470
|
-
|
|
2831
|
+
const deadline = retryDeadline ?? finalUpdateDeadline();
|
|
2832
|
+
if (finalProgress) {
|
|
2833
|
+
const progress = await postWithRetry(`${config.apiUrl}/api/tasks/${taskId}/progress`, headers, { progress: scrubSecrets(finalProgress) }, deadline, "Final task progress POST");
|
|
2834
|
+
if (progress.status === 401) {
|
|
2835
|
+
console.warn(`[${role}] Final task update rejected: HTTP 401`);
|
|
2836
|
+
return;
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
const response = await postWithRetry(`${config.apiUrl}/api/tasks/${taskId}/finish`, headers, body, deadline, "Final task finish POST");
|
|
2471
2840
|
if (response.ok) {
|
|
2472
2841
|
const result = await response.json();
|
|
2473
2842
|
if (result.alreadyFinished) {
|
|
@@ -2475,17 +2844,19 @@ ${failureDiagnostics}`;
|
|
|
2475
2844
|
} else {
|
|
2476
2845
|
console.log(`[${role}] Runner marked task ${taskId.slice(0, 8)} as ${status} (exit code: ${exitCode})`);
|
|
2477
2846
|
}
|
|
2847
|
+
} else if (response.status === 401) {
|
|
2848
|
+
console.warn(scrubSecrets(`[${role}] Task ${taskId.slice(0, 8)}: runtime token revoked or expired; giving up on finish`));
|
|
2478
2849
|
} else if (response.status === 409) {
|
|
2479
2850
|
const error = await response.text();
|
|
2480
|
-
console.warn(`[${role}] Runner result for task ${taskId.slice(0, 8)} was discarded because the task is already terminal; continuing: ${error}`);
|
|
2851
|
+
console.warn(scrubSecrets(`[${role}] Runner result for task ${taskId.slice(0, 8)} was discarded because the task is already terminal; continuing: ${error}`));
|
|
2481
2852
|
} else if (response.status === 404) {
|
|
2482
2853
|
console.log(`[${role}] Task ${taskId.slice(0, 8)} already finalized (not found), skipping`);
|
|
2483
2854
|
} else {
|
|
2484
2855
|
const error = await response.text();
|
|
2485
|
-
console.warn(`[${role}] Failed to finish task ${taskId.slice(0, 8)}: ${response.status} ${error}`);
|
|
2856
|
+
console.warn(scrubSecrets(`[${role}] Failed to finish task ${taskId.slice(0, 8)}: ${response.status} ${error}`));
|
|
2486
2857
|
}
|
|
2487
2858
|
} catch (err) {
|
|
2488
|
-
console.warn(`[${role}] Error finishing task ${taskId.slice(0, 8)}: ${err}`);
|
|
2859
|
+
console.warn(scrubSecrets(`[${role}] Error finishing task ${taskId.slice(0, 8)}: ${err}`));
|
|
2489
2860
|
}
|
|
2490
2861
|
}
|
|
2491
2862
|
async function reportKeyUsage(apiUrl, apiKey, keyType, selection, taskId) {
|
|
@@ -2750,12 +3121,13 @@ async function buildResumePrompt(task, fmt = (cmd) => `/${cmd}`, options) {
|
|
|
2750
3121
|
});
|
|
2751
3122
|
return result.text;
|
|
2752
3123
|
}
|
|
2753
|
-
function setupShutdownHandlers(role, apiConfig, getRunnerState) {
|
|
3124
|
+
function setupShutdownHandlers(role, apiConfig, getRunnerState, onShutdown) {
|
|
2754
3125
|
let shutdownInProgress = false;
|
|
2755
3126
|
const shutdown = async (signal, exitCode = 0) => {
|
|
2756
3127
|
if (shutdownInProgress)
|
|
2757
3128
|
return;
|
|
2758
3129
|
shutdownInProgress = true;
|
|
3130
|
+
onShutdown?.();
|
|
2759
3131
|
console.log(`
|
|
2760
3132
|
[${role}] Received ${signal}, shutting down...`);
|
|
2761
3133
|
const state = getRunnerState?.();
|
|
@@ -2804,15 +3176,13 @@ function setupShutdownHandlers(role, apiConfig, getRunnerState) {
|
|
|
2804
3176
|
await savePm2State(role);
|
|
2805
3177
|
process.exit(exitCode);
|
|
2806
3178
|
};
|
|
2807
|
-
const beginShutdown = (signal, exitCode = 0) => {
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
process.on("SIGINT", () => beginShutdown("SIGINT"));
|
|
2815
|
-
process.on("SIGTERM", () => beginShutdown("SIGTERM"));
|
|
3179
|
+
const beginShutdown = (signal, exitCode = 0) => shutdown(signal, exitCode).catch(async (error) => {
|
|
3180
|
+
console.error(`[${role}] Shutdown failed after ${signal}:`, error);
|
|
3181
|
+
await terminateRegisteredProcessGroups();
|
|
3182
|
+
process.exit(1);
|
|
3183
|
+
});
|
|
3184
|
+
process.on("SIGINT", () => void beginShutdown("SIGINT"));
|
|
3185
|
+
process.on("SIGTERM", () => void beginShutdown("SIGTERM"));
|
|
2816
3186
|
let fatalShutdownInProgress = false;
|
|
2817
3187
|
const fatalShutdown = (kind, error) => {
|
|
2818
3188
|
if (fatalShutdownInProgress)
|
|
@@ -2827,6 +3197,7 @@ function setupShutdownHandlers(role, apiConfig, getRunnerState) {
|
|
|
2827
3197
|
process.on("unhandledRejection", (reason) => {
|
|
2828
3198
|
fatalShutdown("Unhandled rejection", reason);
|
|
2829
3199
|
});
|
|
3200
|
+
return beginShutdown;
|
|
2830
3201
|
}
|
|
2831
3202
|
var LOG_BUFFER_SIZE = 50;
|
|
2832
3203
|
var LOG_FLUSH_INTERVAL_MS = 5000;
|
|
@@ -2862,7 +3233,7 @@ async function flushLogBuffer(buffer, opts) {
|
|
|
2862
3233
|
console.warn(`[runner] Error pushing logs: ${error}`);
|
|
2863
3234
|
}
|
|
2864
3235
|
}
|
|
2865
|
-
async function saveCostData(cost, apiUrl, apiKey) {
|
|
3236
|
+
async function saveCostData(cost, apiUrl, apiKey, deadline) {
|
|
2866
3237
|
const headers = {
|
|
2867
3238
|
"Content-Type": "application/json",
|
|
2868
3239
|
"X-Agent-ID": cost.agentId
|
|
@@ -2871,16 +3242,15 @@ async function saveCostData(cost, apiUrl, apiKey) {
|
|
|
2871
3242
|
headers.Authorization = `Bearer ${apiKey}`;
|
|
2872
3243
|
}
|
|
2873
3244
|
try {
|
|
2874
|
-
const
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
})
|
|
2879
|
-
if (!response.ok) {
|
|
3245
|
+
const body = { ...cost, id: crypto.randomUUID() };
|
|
3246
|
+
const response = await postWithRetry(`${apiUrl}/api/session-costs`, headers, body, deadline, "Session cost POST");
|
|
3247
|
+
if (response.status === 401) {
|
|
3248
|
+
console.warn("[runner] Cost data: runtime token revoked or expired. Cost saving stopped.");
|
|
3249
|
+
} else if (!response.ok) {
|
|
2880
3250
|
console.warn(`[runner] Failed to save cost data: ${response.status}`);
|
|
2881
3251
|
}
|
|
2882
3252
|
} catch (error) {
|
|
2883
|
-
console.warn(`[runner] Error saving cost data: ${error}`);
|
|
3253
|
+
console.warn(scrubSecrets(`[runner] Error saving cost data: ${error}`));
|
|
2884
3254
|
}
|
|
2885
3255
|
}
|
|
2886
3256
|
async function saveProviderSessionId(apiUrl, apiKey, taskId, claudeSessionId, provider, providerMeta, model, harnessVariant, harnessVariantMeta) {
|
|
@@ -3069,12 +3439,24 @@ async function removeActiveSession(config, taskId) {
|
|
|
3069
3439
|
const headers = { "X-Agent-ID": config.agentId };
|
|
3070
3440
|
if (config.apiKey)
|
|
3071
3441
|
headers.Authorization = `Bearer ${config.apiKey}`;
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3442
|
+
for (let attempt = 1;attempt <= 3; attempt++) {
|
|
3443
|
+
try {
|
|
3444
|
+
const response = await fetch(`${config.apiUrl}/api/active-sessions/by-task/${taskId}`, {
|
|
3445
|
+
method: "DELETE",
|
|
3446
|
+
headers,
|
|
3447
|
+
signal: AbortSignal.timeout(1000)
|
|
3448
|
+
});
|
|
3449
|
+
if (!response.ok)
|
|
3450
|
+
throw new Error(`HTTP ${response.status}`);
|
|
3451
|
+
return;
|
|
3452
|
+
} catch (error) {
|
|
3453
|
+
if (attempt === 3) {
|
|
3454
|
+
console.warn(scrubSecrets(`[runner] Active-session removal failed for task ${taskId} after 3 attempts: ${error instanceof Error ? error.message : String(error)}`));
|
|
3455
|
+
} else {
|
|
3456
|
+
await Bun.sleep(attempt * 100);
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3078
3460
|
}
|
|
3079
3461
|
async function cleanupActiveSessions(config) {
|
|
3080
3462
|
const headers = {
|
|
@@ -3239,10 +3621,16 @@ async function registerAgent(opts) {
|
|
|
3239
3621
|
}
|
|
3240
3622
|
try {
|
|
3241
3623
|
const body = await response.json();
|
|
3624
|
+
const deliveryMode = body.deliveryMode === "push" || body.deliveryMode === "poll" ? body.deliveryMode : undefined;
|
|
3625
|
+
const mode = {
|
|
3626
|
+
...deliveryMode ? { deliveryMode } : {},
|
|
3627
|
+
...typeof body.pollRequired === "boolean" ? { pollRequired: body.pollRequired } : {}
|
|
3628
|
+
};
|
|
3242
3629
|
const caps = body.enabledCapabilities;
|
|
3243
3630
|
if (Array.isArray(caps) && caps.every((c2) => typeof c2 === "string")) {
|
|
3244
|
-
return { serverCapabilities: caps };
|
|
3631
|
+
return { serverCapabilities: caps, ...mode };
|
|
3245
3632
|
}
|
|
3633
|
+
return mode;
|
|
3246
3634
|
} catch {}
|
|
3247
3635
|
return {};
|
|
3248
3636
|
}
|
|
@@ -3292,6 +3680,9 @@ async function pollForTriggerOnce(opts) {
|
|
|
3292
3680
|
});
|
|
3293
3681
|
if (!response.ok) {
|
|
3294
3682
|
console.warn(`[runner] Poll request failed: ${response.status}`);
|
|
3683
|
+
opts.onPollFailure?.();
|
|
3684
|
+
if (opts.singlePoll)
|
|
3685
|
+
return null;
|
|
3295
3686
|
await Bun.sleep(opts.pollInterval);
|
|
3296
3687
|
continue;
|
|
3297
3688
|
}
|
|
@@ -3304,8 +3695,11 @@ async function pollForTriggerOnce(opts) {
|
|
|
3304
3695
|
if (draining)
|
|
3305
3696
|
return null;
|
|
3306
3697
|
} catch (error) {
|
|
3307
|
-
console.warn(`[runner] Poll request error: ${error}`);
|
|
3698
|
+
console.warn(scrubSecrets(`[runner] Poll request error: ${error}`));
|
|
3699
|
+
opts.onPollFailure?.();
|
|
3308
3700
|
}
|
|
3701
|
+
if (opts.singlePoll)
|
|
3702
|
+
return null;
|
|
3309
3703
|
await Bun.sleep(opts.pollInterval);
|
|
3310
3704
|
}
|
|
3311
3705
|
return null;
|
|
@@ -3602,6 +3996,11 @@ function resolveSessionTelemetryEvent(result) {
|
|
|
3602
3996
|
return "failure";
|
|
3603
3997
|
return;
|
|
3604
3998
|
}
|
|
3999
|
+
function withHarnessTelemetryEnv(env) {
|
|
4000
|
+
if (env.DESPLEGA_TELEMETRY_ENV?.trim())
|
|
4001
|
+
return { ...env };
|
|
4002
|
+
return { ...env, DESPLEGA_TELEMETRY_ENV: "test" };
|
|
4003
|
+
}
|
|
3605
4004
|
function implicitCloseActiveToolSpans(activeToolSpans, now = Date.now()) {
|
|
3606
4005
|
let closed = 0;
|
|
3607
4006
|
for (const [toolCallId, active] of activeToolSpans) {
|
|
@@ -3626,6 +4025,7 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
|
|
|
3626
4025
|
try {
|
|
3627
4026
|
({ env: freshEnv, credentialSelections } = await fetchResolvedEnv(opts.apiUrl, opts.apiKey, opts.agentId, process.env, opts.resolvedModel || opts.model, {
|
|
3628
4027
|
repoId: sessionRepo?.id,
|
|
4028
|
+
taskId: realTaskId,
|
|
3629
4029
|
provider: adapter.name,
|
|
3630
4030
|
modelTier: opts.modelTier,
|
|
3631
4031
|
localBlocks: opts.localBlocks,
|
|
@@ -3703,7 +4103,7 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
|
|
|
3703
4103
|
additionalArgs: opts.additionalArgs,
|
|
3704
4104
|
resumeSessionId: opts.resumeSessionId,
|
|
3705
4105
|
iteration: opts.iteration,
|
|
3706
|
-
env: freshEnv,
|
|
4106
|
+
env: withHarnessTelemetryEnv(freshEnv),
|
|
3707
4107
|
codexSlot: oauthIsPoolBacked ? oauthSelection?.index : undefined,
|
|
3708
4108
|
contextKey: opts.contextKey,
|
|
3709
4109
|
reasoningEffort: reasoningEffortOverride,
|
|
@@ -3803,6 +4203,7 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
|
|
|
3803
4203
|
}
|
|
3804
4204
|
let lastProgressTime = 0;
|
|
3805
4205
|
const assistantTextHolder = {};
|
|
4206
|
+
const finalProgressHolder = {};
|
|
3806
4207
|
let lastContextPostTime = 0;
|
|
3807
4208
|
const CONTEXT_THROTTLE_MS = 30000;
|
|
3808
4209
|
let cumulativeProgressOutputTokens = 0;
|
|
@@ -3894,8 +4295,10 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
|
|
|
3894
4295
|
startedAt: Date.now()
|
|
3895
4296
|
});
|
|
3896
4297
|
const now = Date.now();
|
|
4298
|
+
const progress = toolCallToProgress(event.toolName, event.args);
|
|
4299
|
+
if (progress)
|
|
4300
|
+
finalProgressHolder.value = scrubSecrets(progress);
|
|
3897
4301
|
if (effectiveTaskId && opts.apiUrl && now - lastProgressTime >= PROGRESS_THROTTLE_MS) {
|
|
3898
|
-
const progress = toolCallToProgress(event.toolName, event.args);
|
|
3899
4302
|
if (progress) {
|
|
3900
4303
|
lastProgressTime = now;
|
|
3901
4304
|
updateProgressViaAPI(opts.apiUrl, opts.apiKey, effectiveTaskId, progress).catch(() => {});
|
|
@@ -4051,6 +4454,7 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
|
|
|
4051
4454
|
}));
|
|
4052
4455
|
break;
|
|
4053
4456
|
case "progress": {
|
|
4457
|
+
finalProgressHolder.value = scrubSecrets(event.message);
|
|
4054
4458
|
if (effectiveTaskId && opts.apiUrl) {
|
|
4055
4459
|
const now = Date.now();
|
|
4056
4460
|
if (now - lastProgressTime >= PROGRESS_THROTTLE_MS) {
|
|
@@ -4111,6 +4515,7 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
|
|
|
4111
4515
|
}
|
|
4112
4516
|
}
|
|
4113
4517
|
if (result.cost) {
|
|
4518
|
+
result.cost = { ...result.cost, taskId: realTaskId, sessionId: opts.runnerSessionId };
|
|
4114
4519
|
sessionSpan.setAttributes({
|
|
4115
4520
|
"gen_ai.response.model": result.cost.model,
|
|
4116
4521
|
"gen_ai.usage.input_tokens": result.cost.inputTokens ?? 0,
|
|
@@ -4134,11 +4539,6 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
|
|
|
4134
4539
|
numTurns: result.cost.numTurns,
|
|
4135
4540
|
isError: result.cost.isError
|
|
4136
4541
|
}, { userId: opts.requestedByUserId ?? null });
|
|
4137
|
-
try {
|
|
4138
|
-
await saveCostData({ ...result.cost, taskId: realTaskId, sessionId: opts.runnerSessionId }, opts.apiUrl, opts.apiKey);
|
|
4139
|
-
} catch (err) {
|
|
4140
|
-
console.warn(`[runner] Failed to save cost: ${err}`);
|
|
4141
|
-
}
|
|
4142
4542
|
}
|
|
4143
4543
|
if (result.cost && realTaskId) {
|
|
4144
4544
|
fetch(`${opts.apiUrl}/api/tasks/${realTaskId}/context`, {
|
|
@@ -4230,7 +4630,8 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
|
|
|
4230
4630
|
harnessProvider: opts.harnessProvider,
|
|
4231
4631
|
hasLocalEnvironment: adapter.traits.hasLocalEnvironment,
|
|
4232
4632
|
model: model || undefined,
|
|
4233
|
-
assistantText: assistantTextHolder
|
|
4633
|
+
assistantText: assistantTextHolder,
|
|
4634
|
+
finalProgress: finalProgressHolder
|
|
4234
4635
|
};
|
|
4235
4636
|
runningTaskForSessionInit = runningTask;
|
|
4236
4637
|
if (pendingHarnessVariant !== undefined) {
|
|
@@ -4294,7 +4695,7 @@ async function reconcileActiveTasks(state, role, opts) {
|
|
|
4294
4695
|
for (const [taskId, task] of state.activeTasks) {
|
|
4295
4696
|
if (task.result !== null)
|
|
4296
4697
|
continue;
|
|
4297
|
-
if (!opts.cancelledSignaled.has(taskId)) {
|
|
4698
|
+
if (!opts.cancelledSignaled.has(taskId) && (!opts.cancelTaskIds || opts.cancelTaskIds.has(taskId))) {
|
|
4298
4699
|
try {
|
|
4299
4700
|
if (await opts.isCancelled(taskId)) {
|
|
4300
4701
|
console.log(`[${role}] Task ${taskId.slice(0, 8)} was cancelled — sending SIGTERM to subprocess`);
|
|
@@ -4303,7 +4704,7 @@ async function reconcileActiveTasks(state, role, opts) {
|
|
|
4303
4704
|
}
|
|
4304
4705
|
} catch {}
|
|
4305
4706
|
}
|
|
4306
|
-
if (task.abortRequestedAt === undefined) {
|
|
4707
|
+
if (task.abortRequestedAt === undefined && opts.checkStatus !== false) {
|
|
4307
4708
|
const lastCheck = task.lastReconcileAt ?? task.startTime.getTime();
|
|
4308
4709
|
if (now() - lastCheck >= opts.intervalMs) {
|
|
4309
4710
|
task.lastReconcileAt = now();
|
|
@@ -4359,13 +4760,16 @@ async function checkCompletedProcesses(state, role, apiConfig, cancelledSignaled
|
|
|
4359
4760
|
model: task.model,
|
|
4360
4761
|
durationMs: Date.now() - task.startTime.getTime(),
|
|
4361
4762
|
assistantText: task.assistantText,
|
|
4763
|
+
finalProgress: task.finalProgress,
|
|
4362
4764
|
serverTerminalStatus: task.serverTerminalStatus
|
|
4363
4765
|
});
|
|
4364
4766
|
}
|
|
4365
4767
|
}
|
|
4366
|
-
|
|
4768
|
+
let credentialReports = Promise.resolve();
|
|
4769
|
+
const completions = await Promise.allSettled(completedTasks.map(async ({
|
|
4367
4770
|
taskId,
|
|
4368
4771
|
result,
|
|
4772
|
+
triggerType,
|
|
4369
4773
|
triggerSurface,
|
|
4370
4774
|
requestedByUserId,
|
|
4371
4775
|
cursorUpdates,
|
|
@@ -4377,131 +4781,149 @@ async function checkCompletedProcesses(state, role, apiConfig, cancelledSignaled
|
|
|
4377
4781
|
model,
|
|
4378
4782
|
durationMs,
|
|
4379
4783
|
assistantText,
|
|
4784
|
+
finalProgress,
|
|
4380
4785
|
serverTerminalStatus
|
|
4381
|
-
}
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
if (apiConfig) {
|
|
4387
|
-
removeActiveSession(apiConfig, taskId).catch((err) => console.error("[runner] active-session removal failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
4388
|
-
}
|
|
4389
|
-
if (serverTerminalStatus) {
|
|
4390
|
-
console.log(`[${role}] Task ${taskId.slice(0, 8)} was already ${serverTerminalStatus} server-side — slot released, server result kept`);
|
|
4391
|
-
state.tasksProcessed += 1;
|
|
4392
|
-
continue;
|
|
4393
|
-
}
|
|
4394
|
-
if (apiConfig && workingDir && !vcsDetectedTasks.has(taskId)) {
|
|
4395
|
-
await detectVcsForTask(apiConfig.apiUrl, apiConfig.apiKey, taskId, workingDir);
|
|
4396
|
-
}
|
|
4397
|
-
if (apiConfig) {
|
|
4398
|
-
let failureReason;
|
|
4399
|
-
if (result.exitCode !== 0 && result.failureReason) {
|
|
4400
|
-
failureReason = result.failureReason;
|
|
4401
|
-
console.log(`[${role}] Detected error for task ${taskId.slice(0, 8)}: ${failureReason}`);
|
|
4402
|
-
}
|
|
4403
|
-
reportHarnessModelOutcome({
|
|
4404
|
-
apiUrl: apiConfig.apiUrl,
|
|
4405
|
-
apiKey: apiConfig.apiKey,
|
|
4406
|
-
agentId: apiConfig.agentId,
|
|
4407
|
-
harness: harnessProvider,
|
|
4408
|
-
model,
|
|
4409
|
-
exitCode: result.exitCode,
|
|
4410
|
-
failureReason
|
|
4411
|
-
});
|
|
4412
|
-
if (credentialInfo) {
|
|
4786
|
+
}) => {
|
|
4787
|
+
const deadline = finalUpdateDeadline();
|
|
4788
|
+
const costSave = apiConfig && result.cost ? saveCostData(result.cost, apiConfig.apiUrl, apiConfig.apiKey, deadline) : Promise.resolve();
|
|
4789
|
+
const credentialReport = credentialReports.then(async () => {
|
|
4790
|
+
if (apiConfig && credentialInfo && !serverTerminalStatus) {
|
|
4413
4791
|
await reportKeyCompletionOutcome({
|
|
4414
4792
|
apiUrl: apiConfig.apiUrl,
|
|
4415
4793
|
apiKey: apiConfig.apiKey,
|
|
4416
4794
|
credential: credentialInfo,
|
|
4417
4795
|
taskId,
|
|
4418
4796
|
exitCode: result.exitCode,
|
|
4419
|
-
failureReason
|
|
4797
|
+
failureReason: result.exitCode !== 0 ? result.failureReason : undefined
|
|
4420
4798
|
});
|
|
4421
4799
|
}
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4800
|
+
});
|
|
4801
|
+
credentialReports = credentialReport.catch(() => {});
|
|
4802
|
+
try {
|
|
4803
|
+
vcsDetectedTasks.delete(taskId);
|
|
4804
|
+
vcsCheckTimestamps.delete(taskId);
|
|
4805
|
+
cancelledSignaled?.delete(taskId);
|
|
4806
|
+
if (serverTerminalStatus) {
|
|
4807
|
+
console.log(`[${role}] Task ${taskId.slice(0, 8)} was already ${serverTerminalStatus} server-side — slot released, server result kept`);
|
|
4808
|
+
return;
|
|
4431
4809
|
}
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
const sessionTriggerSurface = workerTriggerSurface(triggerSurface);
|
|
4445
|
-
const sessionActor = { userId: requestedByUserId ?? null };
|
|
4446
|
-
telemetry.taskEvent("session_completed", {
|
|
4447
|
-
taskId,
|
|
4448
|
-
trigger_surface: sessionTriggerSurface,
|
|
4449
|
-
agentId: apiConfig.agentId,
|
|
4450
|
-
provider: result.cost?.provider ?? harnessProvider,
|
|
4451
|
-
model: result.cost?.model ?? model ?? "unknown",
|
|
4452
|
-
harnessVariant,
|
|
4453
|
-
harnessVersion: typeof harnessVariantMeta?.version === "string" || typeof harnessVariantMeta?.version === "number" ? String(harnessVariantMeta.version) : undefined,
|
|
4454
|
-
exitCode: result.exitCode,
|
|
4455
|
-
isError: result.exitCode !== 0,
|
|
4456
|
-
durationMs
|
|
4457
|
-
}, sessionActor);
|
|
4458
|
-
const sessionTelemetryEvent = resolveSessionTelemetryEvent(result);
|
|
4459
|
-
if (sessionTelemetryEvent) {
|
|
4460
|
-
telemetry.session(sessionTelemetryEvent, {
|
|
4810
|
+
if (apiConfig && workingDir && !vcsDetectedTasks.has(taskId)) {
|
|
4811
|
+
await detectVcsForTask(apiConfig.apiUrl, apiConfig.apiKey, taskId, workingDir);
|
|
4812
|
+
}
|
|
4813
|
+
if (apiConfig) {
|
|
4814
|
+
let failureReason;
|
|
4815
|
+
if (result.exitCode !== 0 && result.failureReason) {
|
|
4816
|
+
failureReason = result.failureReason;
|
|
4817
|
+
console.log(`[${role}] Detected error for task ${taskId.slice(0, 8)}: ${failureReason}`);
|
|
4818
|
+
}
|
|
4819
|
+
reportHarnessModelOutcome({
|
|
4820
|
+
apiUrl: apiConfig.apiUrl,
|
|
4821
|
+
apiKey: apiConfig.apiKey,
|
|
4461
4822
|
agentId: apiConfig.agentId,
|
|
4823
|
+
harness: harnessProvider,
|
|
4824
|
+
model,
|
|
4825
|
+
exitCode: result.exitCode,
|
|
4826
|
+
failureReason
|
|
4827
|
+
});
|
|
4828
|
+
await credentialReport;
|
|
4829
|
+
let bridgeDiagnostics;
|
|
4830
|
+
if (result.exitCode !== 0 && harnessProvider === "claude" && workingDir) {
|
|
4831
|
+
bridgeDiagnostics = await getBridgeFailureDiagnostics(workingDir);
|
|
4832
|
+
if (bridgeDiagnostics?.artifactPath && result.sessionId) {
|
|
4833
|
+
console.log(`[${role}] Bridge failure artifact found: ${bridgeDiagnostics.artifactPath}`);
|
|
4834
|
+
updateHarnessVariantMeta(apiConfig.apiUrl, apiConfig.apiKey, taskId, result.sessionId, {
|
|
4835
|
+
failureArtifact: bridgeDiagnostics.artifactPath
|
|
4836
|
+
}).catch((err) => console.warn(`[runner] Failed to update harness variant meta: ${err}`));
|
|
4837
|
+
}
|
|
4838
|
+
}
|
|
4839
|
+
const bridgeFailureDiagnostics = bridgeDiagnostics?.paneTail != null ? `Claude bridge final tmux pane tail (${bridgeDiagnostics.artifactPath}):
|
|
4840
|
+
${bridgeDiagnostics.paneTail}` : undefined;
|
|
4841
|
+
await reportCredentialOutcomeThenFinish({
|
|
4842
|
+
apiUrl: apiConfig.apiUrl,
|
|
4843
|
+
apiKey: apiConfig.apiKey,
|
|
4844
|
+
credentialInfo,
|
|
4845
|
+
result,
|
|
4846
|
+
failureReason,
|
|
4847
|
+
model,
|
|
4848
|
+
codexCreditsExhaustedCooldownMs: state.codexCreditsExhaustedCooldownMs,
|
|
4849
|
+
modelWindowBlocks: state.modelWindowBlocks
|
|
4850
|
+
}, () => ensureTaskFinished(apiConfig, role, taskId, result.exitCode, failureReason, resolveProviderOutput(result, assistantText), harnessProvider, bridgeFailureDiagnostics, finalProgress?.value, deadline));
|
|
4851
|
+
const sessionTriggerSurface = workerTriggerSurface(triggerSurface);
|
|
4852
|
+
const sessionActor = { userId: requestedByUserId ?? null };
|
|
4853
|
+
telemetry.taskEvent("session_completed", {
|
|
4462
4854
|
taskId,
|
|
4463
4855
|
trigger_surface: sessionTriggerSurface,
|
|
4464
|
-
|
|
4856
|
+
agentId: apiConfig.agentId,
|
|
4465
4857
|
provider: result.cost?.provider ?? harnessProvider,
|
|
4466
4858
|
model: result.cost?.model ?? model ?? "unknown",
|
|
4467
|
-
|
|
4468
|
-
|
|
4859
|
+
harnessVariant,
|
|
4860
|
+
harnessVersion: typeof harnessVariantMeta?.version === "string" || typeof harnessVariantMeta?.version === "number" ? String(harnessVariantMeta.version) : undefined,
|
|
4861
|
+
exitCode: result.exitCode,
|
|
4862
|
+
isError: result.exitCode !== 0,
|
|
4863
|
+
durationMs
|
|
4469
4864
|
}, sessionActor);
|
|
4865
|
+
const sessionTelemetryEvent = resolveSessionTelemetryEvent(result);
|
|
4866
|
+
if (sessionTelemetryEvent) {
|
|
4867
|
+
telemetry.session(sessionTelemetryEvent, {
|
|
4868
|
+
agentId: apiConfig.agentId,
|
|
4869
|
+
taskId,
|
|
4870
|
+
trigger_surface: sessionTriggerSurface,
|
|
4871
|
+
errorCategory: normalizeSessionErrorCategory(result.errorCategory),
|
|
4872
|
+
provider: result.cost?.provider ?? harnessProvider,
|
|
4873
|
+
model: result.cost?.model ?? model ?? "unknown",
|
|
4874
|
+
durationMs: result.cost?.durationMs ?? durationMs,
|
|
4875
|
+
wasRateLimited: result.rateLimitResetAt != null
|
|
4876
|
+
}, sessionActor);
|
|
4877
|
+
}
|
|
4878
|
+
ensure({
|
|
4879
|
+
id: "worker_process_finished",
|
|
4880
|
+
flow: "task",
|
|
4881
|
+
runId: taskId,
|
|
4882
|
+
depIds: ["worker_process_spawned"],
|
|
4883
|
+
data: {
|
|
4884
|
+
taskId,
|
|
4885
|
+
agentId: apiConfig.agentId,
|
|
4886
|
+
role,
|
|
4887
|
+
exitCode: result.exitCode,
|
|
4888
|
+
success: result.exitCode === 0,
|
|
4889
|
+
failureReason
|
|
4890
|
+
},
|
|
4891
|
+
validator: (data) => data.exitCode === 0,
|
|
4892
|
+
filter: ({}, ctx) => ctx.deps.length > 0,
|
|
4893
|
+
conditions: [{ timeout_ms: 3600000 }]
|
|
4894
|
+
});
|
|
4895
|
+
if (cursorUpdates && cursorUpdates.length > 0 && result.exitCode === 0) {
|
|
4896
|
+
try {
|
|
4897
|
+
const headers = { "Content-Type": "application/json" };
|
|
4898
|
+
if (apiConfig.apiKey)
|
|
4899
|
+
headers.Authorization = `Bearer ${apiConfig.apiKey}`;
|
|
4900
|
+
await fetch(`${apiConfig.apiUrl}/api/channel-activity/commit-cursors`, {
|
|
4901
|
+
method: "POST",
|
|
4902
|
+
headers,
|
|
4903
|
+
body: JSON.stringify({ cursorUpdates })
|
|
4904
|
+
});
|
|
4905
|
+
console.log(`[${role}] Committed ${cursorUpdates.length} channel activity cursor(s) for task ${taskId.slice(0, 8)}`);
|
|
4906
|
+
} catch (err) {
|
|
4907
|
+
console.warn(`[${role}] Failed to commit channel activity cursors: ${err}`);
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4470
4910
|
}
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
role,
|
|
4481
|
-
exitCode: result.exitCode,
|
|
4482
|
-
success: result.exitCode === 0,
|
|
4483
|
-
failureReason
|
|
4484
|
-
},
|
|
4485
|
-
validator: (data) => data.exitCode === 0,
|
|
4486
|
-
filter: ({}, ctx) => ctx.deps.length > 0,
|
|
4487
|
-
conditions: [{ timeout_ms: 3600000 }]
|
|
4488
|
-
});
|
|
4489
|
-
if (cursorUpdates && cursorUpdates.length > 0 && result.exitCode === 0) {
|
|
4490
|
-
try {
|
|
4491
|
-
const headers = { "Content-Type": "application/json" };
|
|
4492
|
-
if (apiConfig.apiKey)
|
|
4493
|
-
headers.Authorization = `Bearer ${apiConfig.apiKey}`;
|
|
4494
|
-
await fetch(`${apiConfig.apiUrl}/api/channel-activity/commit-cursors`, {
|
|
4495
|
-
method: "POST",
|
|
4496
|
-
headers,
|
|
4497
|
-
body: JSON.stringify({ cursorUpdates })
|
|
4498
|
-
});
|
|
4499
|
-
console.log(`[${role}] Committed ${cursorUpdates.length} channel activity cursor(s) for task ${taskId.slice(0, 8)}`);
|
|
4500
|
-
} catch (err) {
|
|
4501
|
-
console.warn(`[${role}] Failed to commit channel activity cursors: ${err}`);
|
|
4911
|
+
} finally {
|
|
4912
|
+
try {
|
|
4913
|
+
await costSave;
|
|
4914
|
+
if (apiConfig)
|
|
4915
|
+
await removeActiveSession(apiConfig, taskId);
|
|
4916
|
+
} finally {
|
|
4917
|
+
state.activeTasks.delete(taskId);
|
|
4918
|
+
if (triggerType === "task_assigned" || triggerType === "task_resumed") {
|
|
4919
|
+
state.tasksProcessed += 1;
|
|
4502
4920
|
}
|
|
4503
4921
|
}
|
|
4504
4922
|
}
|
|
4923
|
+
}));
|
|
4924
|
+
for (const completion of completions) {
|
|
4925
|
+
if (completion.status === "rejected")
|
|
4926
|
+
console.warn(scrubSecrets(`[${role}] Task completion failed: ${completion.reason}`));
|
|
4505
4927
|
}
|
|
4506
4928
|
const localCompleted = completedTasks.filter((t) => t.hasLocalEnvironment);
|
|
4507
4929
|
if (apiConfig && localCompleted.length > 0) {
|
|
@@ -4744,10 +5166,12 @@ ${additionalSystemPrompt}` : basePrompt;
|
|
|
4744
5166
|
const defaultMaxTasks = isLead ? 2 : 1;
|
|
4745
5167
|
const templateMaxTasks = cachedTemplate?.config.agentDefaults?.maxTasks;
|
|
4746
5168
|
const maxConcurrent = resolveMaxConcurrent(process.env, templateMaxTasks, defaultMaxTasks);
|
|
4747
|
-
|
|
5169
|
+
const exitAfterTasks = resolveExitAfterTasks();
|
|
5170
|
+
console.log(`[${role}] Mode: runner-level delivery`);
|
|
4748
5171
|
console.log(`[${role}] Max concurrent tasks: ${maxConcurrent}`);
|
|
4749
5172
|
const state = {
|
|
4750
5173
|
activeTasks: new Map,
|
|
5174
|
+
deliveryMode: "poll",
|
|
4751
5175
|
maxConcurrent,
|
|
4752
5176
|
startedAt: Date.now(),
|
|
4753
5177
|
tasksProcessed: 0,
|
|
@@ -4767,10 +5191,38 @@ ${additionalSystemPrompt}` : basePrompt;
|
|
|
4767
5191
|
const HARNESS_RECONCILE_INTERVAL_MS = 1e4;
|
|
4768
5192
|
let lastServerCapsRefreshAt = 0;
|
|
4769
5193
|
const SERVER_CAPS_REFRESH_INTERVAL_MS = 300000;
|
|
4770
|
-
const runtimeInstanceId = crypto.randomUUID();
|
|
5194
|
+
const runtimeInstanceId = process.env.SWARM_RUNTIME_INSTANCE_ID || crypto.randomUUID();
|
|
4771
5195
|
process.env.SWARM_RUNTIME_INSTANCE_ID = runtimeInstanceId;
|
|
4772
5196
|
const apiConfig = { apiUrl, apiKey, agentId, runtimeInstanceId };
|
|
4773
|
-
|
|
5197
|
+
const pushDelivery = new RunnerPushDelivery(new WorkerRealtimeClient({ apiUrl, apiKey, agentId, runtimeInstanceId }));
|
|
5198
|
+
let shuttingDown = false;
|
|
5199
|
+
let lastPushPingAt = 0;
|
|
5200
|
+
let pushPingTimer;
|
|
5201
|
+
let lastLoggedDeliveryMode;
|
|
5202
|
+
const applyDeliveryMode = (registration) => {
|
|
5203
|
+
const mode = updateWorkerDeliveryMode(lastLoggedDeliveryMode, registration, isLead, process.env);
|
|
5204
|
+
lastLoggedDeliveryMode = mode;
|
|
5205
|
+
if (mode !== state.deliveryMode) {
|
|
5206
|
+
state.deliveryMode = mode;
|
|
5207
|
+
pushDelivery.wakeWork();
|
|
5208
|
+
clearInterval(pushPingTimer);
|
|
5209
|
+
if (mode === "push") {
|
|
5210
|
+
pushDelivery.client.start();
|
|
5211
|
+
lastPushPingAt = Date.now();
|
|
5212
|
+
pushPingTimer = setInterval(() => {
|
|
5213
|
+
lastPushPingAt = Date.now();
|
|
5214
|
+
pingServer(apiConfig, role).then((draining) => applyApiDrainSignal(state, role, draining));
|
|
5215
|
+
}, 30000);
|
|
5216
|
+
pushPingTimer.unref();
|
|
5217
|
+
} else
|
|
5218
|
+
pushDelivery.client.stop();
|
|
5219
|
+
}
|
|
5220
|
+
};
|
|
5221
|
+
const shutdown = setupShutdownHandlers(role, apiConfig, () => state, () => {
|
|
5222
|
+
shuttingDown = true;
|
|
5223
|
+
clearInterval(pushPingTimer);
|
|
5224
|
+
pushDelivery.client.stop();
|
|
5225
|
+
});
|
|
4774
5226
|
const agentName = process.env.AGENT_NAME || cachedTemplate?.config.displayName || `${role}-${agentId.slice(0, 8)}`;
|
|
4775
5227
|
const applySwarmConfigDrift = async (freshEnv, resolvedProvider, nextScriptsOnly) => {
|
|
4776
5228
|
let agentVisibleChanged = false;
|
|
@@ -4847,6 +5299,7 @@ ${additionalSystemPrompt}` : basePrompt;
|
|
|
4847
5299
|
});
|
|
4848
5300
|
lastServerCapsRefreshAt = Date.now();
|
|
4849
5301
|
await applyServerCapabilities(reg.serverCapabilities);
|
|
5302
|
+
applyDeliveryMode(reg);
|
|
4850
5303
|
};
|
|
4851
5304
|
const reregisterAgent = async () => {
|
|
4852
5305
|
try {
|
|
@@ -4870,6 +5323,7 @@ ${additionalSystemPrompt}` : basePrompt;
|
|
|
4870
5323
|
}), { label: role });
|
|
4871
5324
|
lastServerCapsRefreshAt = Date.now();
|
|
4872
5325
|
await applyServerCapabilities(reg.serverCapabilities);
|
|
5326
|
+
applyDeliveryMode(reg);
|
|
4873
5327
|
console.log(`[${role}] Registered as "${agentName}" (ID: ${agentId})`);
|
|
4874
5328
|
} catch (error) {
|
|
4875
5329
|
console.error(`[${role}] Failed to register: ${error}`);
|
|
@@ -5336,13 +5790,21 @@ ${additionalSystemPrompt}` : basePrompt;
|
|
|
5336
5790
|
let lastOrphanRecoveryAt = 0;
|
|
5337
5791
|
const ORPHAN_RECOVERY_INTERVAL_MS = 60000;
|
|
5338
5792
|
const taskReconcileIntervalMs = resolveTaskReconcileIntervalMs();
|
|
5339
|
-
while (
|
|
5340
|
-
|
|
5793
|
+
while (shouldRunDeliveryLoop(state.deliveryMode, shuttingDown)) {
|
|
5794
|
+
const deliveryChecks = pushDelivery.checks(state.deliveryMode ?? "poll");
|
|
5795
|
+
if (state.deliveryMode !== "push") {
|
|
5796
|
+
applyApiDrainSignal(state, role, await pingServer(apiConfig, role));
|
|
5797
|
+
}
|
|
5341
5798
|
if (state.apiDraining) {
|
|
5342
5799
|
await handOffTasksForApiDrain(state, role, apiConfig);
|
|
5343
5800
|
}
|
|
5801
|
+
const activeBeforeCompletion = state.activeTasks.size;
|
|
5344
5802
|
await checkCompletedProcesses(state, role, apiConfig, cancelledSignaled);
|
|
5345
|
-
if (
|
|
5803
|
+
if (state.activeTasks.size < activeBeforeCompletion)
|
|
5804
|
+
pushDelivery.wakeWork();
|
|
5805
|
+
if (await exitAfterTasksIfFinished(state, exitAfterTasks, shutdown))
|
|
5806
|
+
return;
|
|
5807
|
+
if (deliveryChecks.config && (deliveryChecks.push || Date.now() - lastHarnessReconcileAt > HARNESS_RECONCILE_INTERVAL_MS)) {
|
|
5346
5808
|
lastHarnessReconcileAt = Date.now();
|
|
5347
5809
|
try {
|
|
5348
5810
|
const {
|
|
@@ -5380,20 +5842,33 @@ ${additionalSystemPrompt}` : basePrompt;
|
|
|
5380
5842
|
cancelledSignaled,
|
|
5381
5843
|
isCancelled: (taskId) => fetchTaskCancelled(apiUrl, apiKey, agentId, taskId),
|
|
5382
5844
|
fetchStatus: (taskId) => fetchTaskStatus(apiUrl, apiKey, taskId),
|
|
5383
|
-
intervalMs: taskReconcileIntervalMs
|
|
5845
|
+
intervalMs: taskReconcileIntervalMs,
|
|
5846
|
+
...taskReconciliation(deliveryChecks)
|
|
5384
5847
|
});
|
|
5385
5848
|
}
|
|
5386
5849
|
if (steeringDispatchState && state.activeTasks.size > 0) {
|
|
5387
5850
|
const dispatchState = steeringDispatchState;
|
|
5388
5851
|
for (const [taskId, task] of state.activeTasks) {
|
|
5389
|
-
scheduleSteeringDispatch(apiConfig, taskId, task.session, dispatchState, (error) => {
|
|
5852
|
+
pushDelivery.dispatchSteering(deliveryChecks, taskId, () => scheduleSteeringDispatch(apiConfig, taskId, task.session, dispatchState, (error) => {
|
|
5390
5853
|
console.warn(`[${role}] Steering dispatch failed for task ${taskId.slice(0, 8)} (non-fatal): ${scrubSecrets(error.message)}`);
|
|
5391
|
-
});
|
|
5854
|
+
}));
|
|
5392
5855
|
}
|
|
5393
5856
|
}
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5857
|
+
const schedule = pushDelivery.schedule({
|
|
5858
|
+
mode: state.deliveryMode ?? "poll",
|
|
5859
|
+
push: deliveryChecks.push,
|
|
5860
|
+
activeCount: state.activeTasks.size,
|
|
5861
|
+
maxConcurrent: exitAfterTasks === null ? state.maxConcurrent : Math.min(state.maxConcurrent, Math.max(0, exitAfterTasks - state.tasksProcessed)),
|
|
5862
|
+
draining: state.apiDraining,
|
|
5863
|
+
lastPushPingAt,
|
|
5864
|
+
pollInterval: PollIntervalMs
|
|
5865
|
+
});
|
|
5866
|
+
if (!schedule.poll) {
|
|
5867
|
+
if (!state.apiDraining && state.activeTasks.size >= state.maxConcurrent) {
|
|
5868
|
+
console.log(`[${role}] At capacity (${state.activeTasks.size}/${state.maxConcurrent}), waiting for completion...`);
|
|
5869
|
+
}
|
|
5870
|
+
await pushDelivery.waitForSchedule(schedule);
|
|
5871
|
+
} else {
|
|
5397
5872
|
if (Date.now() - lastOrphanRecoveryAt > ORPHAN_RECOVERY_INTERVAL_MS) {
|
|
5398
5873
|
lastOrphanRecoveryAt = Date.now();
|
|
5399
5874
|
const recoveredOrphans = await recoverOrphanedInProgressTasks(apiConfig);
|
|
@@ -5403,16 +5878,18 @@ ${additionalSystemPrompt}` : basePrompt;
|
|
|
5403
5878
|
}
|
|
5404
5879
|
console.log(`[${role}] Polling for triggers (${state.activeTasks.size}/${state.maxConcurrent} active)...`);
|
|
5405
5880
|
const effectiveTimeout = state.activeTasks.size > 0 ? 5000 : PollTimeoutMs;
|
|
5406
|
-
const trigger = await pollForTrigger({
|
|
5881
|
+
const { trigger, failed } = await pushDelivery.poll(schedule.singlePoll, (onPollFailure) => pollForTrigger({
|
|
5407
5882
|
apiUrl,
|
|
5408
5883
|
apiKey,
|
|
5409
5884
|
agentId,
|
|
5410
5885
|
pollInterval: PollIntervalMs,
|
|
5411
5886
|
runtimeInstanceId,
|
|
5412
5887
|
pollTimeout: effectiveTimeout,
|
|
5888
|
+
singlePoll: schedule.singlePoll,
|
|
5889
|
+
onPollFailure,
|
|
5413
5890
|
harnessProvider: state.harnessProvider,
|
|
5414
5891
|
onApiDrainSignal: (draining) => applyApiDrainSignal(state, role, draining)
|
|
5415
|
-
});
|
|
5892
|
+
}));
|
|
5416
5893
|
if (trigger) {
|
|
5417
5894
|
if (trigger.type === "budget_refused") {
|
|
5418
5895
|
consecutiveBudgetRefusals++;
|
|
@@ -5691,10 +6168,9 @@ Note: The task requested working directory "${taskDir}" but it does not exist. F
|
|
|
5691
6168
|
}).catch((err) => console.error("[runner] active-session registration failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
5692
6169
|
}
|
|
5693
6170
|
console.log(`[${role}] Started task ${runningTask.taskId.slice(0, 8)} (${state.activeTasks.size}/${state.maxConcurrent} active, trigger: ${trigger.type})`);
|
|
6171
|
+
} else if (schedule.singlePoll) {
|
|
6172
|
+
await pushDelivery.waitForSchedule(schedule, failed, PollIntervalMs);
|
|
5694
6173
|
}
|
|
5695
|
-
} else {
|
|
5696
|
-
console.log(`[${role}] At capacity (${state.activeTasks.size}/${state.maxConcurrent}), waiting for completion...`);
|
|
5697
|
-
await Bun.sleep(1000);
|
|
5698
6174
|
}
|
|
5699
6175
|
}
|
|
5700
6176
|
}
|