@desplega.ai/agent-swarm 1.149.1 → 1.151.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 +18 -3
- package/dist/{acp-adapter-vhkzfpjg.js → acp-adapter-ex8hzjfc.js} +5 -5
- package/dist/{actions-9d2694yk.js → actions-2bgpyhww.js} +39 -11
- package/dist/{app-fq2ggynt.js → app-1706zhr1.js} +7 -7
- package/dist/{artifact-gj9arwrr.js → artifact-td4q4dch.js} +1 -1
- package/dist/{assistant-edb6n9nn.js → assistant-bavke5p7.js} +44 -20
- package/dist/{azure-openai-responses-cqar64rc.js → azure-openai-responses-f38x2avq.js} +13 -13
- package/dist/{boot-reembed-msweabbp.js → boot-reembed-3cmrrmpa.js} +9 -9
- package/dist/{boot-reembed-q5wd3tha.js → boot-reembed-nafcmmmc.js} +14 -16
- package/dist/{boot-scrub-logs-3g1az933.js → boot-scrub-logs-cd6a2sq0.js} +5 -5
- package/dist/{claude-adapter-v3rnzsdc.js → claude-adapter-wfp2gzvz.js} +15 -16
- package/dist/{claude-managed-adapter-qvsmh6mv.js → claude-managed-adapter-dsmkcrjy.js} +3 -3
- package/dist/{claude-sdk-session-qxrpsna1.js → claude-sdk-session-bht9jjak.js} +15 -16
- package/dist/{cli-5m0qmvdp.js → cli-0qb1z6s2.js} +1 -1
- package/dist/{cli-9d8ntetj.js → cli-2658f6at.js} +1 -1
- package/dist/{cli-7evafqvy.js → cli-2tbvf1z1.js} +85 -69
- package/dist/{cli-k351hv5k.js → cli-3v9xhjcn.js} +24 -12
- package/dist/{cli-1ebpar1q.js → cli-4wppfkcm.js} +350 -20
- package/dist/{cli-4260r1tg.js → cli-5jd2z7av.js} +97 -84
- package/dist/{cli-cv7s5zdq.js → cli-5tpgq60f.js} +9865 -715
- package/dist/{cli-6skz3rk8.js → cli-7tgcstn2.js} +9 -4
- package/dist/{cli-01g3x1ca.js → cli-9004vfdf.js} +108 -56
- package/dist/{cli-1c94wvcw.js → cli-a1z3h107.js} +124 -99
- package/dist/{cli-9br8ypfv.js → cli-czjtgfys.js} +2 -2
- package/dist/{cli-5my3bjsd.js → cli-d3p82erb.js} +7 -7
- package/dist/{cli-e29gmdmw.js → cli-dv6cdjs2.js} +2 -1
- package/dist/{cli-wby1xnnb.js → cli-f1wky6zp.js} +1 -1
- package/dist/{cli-zvz62chv.js → cli-fm4ytsdk.js} +4 -4
- package/dist/{cli-tg8qj8ee.js → cli-frcta2w4.js} +6 -6
- package/dist/{cli-7xx10h0a.js → cli-g69fdc9g.js} +2 -2
- package/dist/{cli-cmp8g3sw.js → cli-gbfwcd3k.js} +44 -9
- package/dist/{handlers-nsg0bcye.js → cli-gjyvhmmh.js} +97 -45
- package/dist/{cli-08b07b4r.js → cli-ht5rs63n.js} +1 -1
- package/dist/{cli-jecc01cb.js → cli-j4nv2wqy.js} +2 -4
- package/dist/{cli-cd60fv6j.js → cli-j9xczhaq.js} +1 -1
- package/dist/cli-pf9q3696.js +172 -0
- package/dist/{cli-xm87hzbw.js → cli-pgj4a5fb.js} +1 -1
- package/dist/{cli-jezx9b9c.js → cli-ppm4975n.js} +9 -3
- package/dist/{cli-3z634pqe.js → cli-q88st9aj.js} +2 -2
- package/dist/{cli-3sysyjve.js → cli-r2q6pevn.js} +142 -49
- package/dist/{cli-07jd68a1.js → cli-re8z5p8p.js} +1 -1
- package/dist/{cli-qgd4sqz5.js → cli-s14agm5s.js} +121 -14
- package/dist/{cli-svbrpf5q.js → cli-sjaae6ff.js} +9872 -424
- package/dist/{cli-73gq0zxn.js → cli-vwm416m6.js} +13 -13
- package/dist/{cli-4wtq5jjv.js → cli-wbyk465z.js} +1 -1
- package/dist/{cli-3apbzgyk.js → cli-z61ykvam.js} +19 -14
- package/dist/{cli-e06a8a7y.js → cli-zkxymas5.js} +4 -3
- package/dist/cli.js +26 -25
- package/dist/{codex-adapter-jyw7a91z.js → codex-adapter-jjjk8w4m.js} +8 -9
- package/dist/{codex-hook-hfrt9shr.js → codex-hook-8jexc34x.js} +3 -3
- package/dist/{codex-session-runner-bmngj0s5.js → codex-session-runner-nd6ayxkx.js} +8 -9
- package/dist/{commands-n755g391.js → commands-9v4psyq1.js} +5 -5
- package/dist/{db-s1cgh5gv.js → db-wnt58tpe.js} +5 -5
- package/dist/dispatcher-05jh1aqk.js +74 -0
- package/dist/{e2b-p04vmtx0.js → e2b-413b8t4v.js} +1 -1
- package/dist/{google-generative-ai-tsskx7te.js → google-generative-ai-ndjmj5fa.js} +7 -7
- package/dist/{google-vertex-ppw8ydpa.js → google-vertex-fr665tqs.js} +10 -10
- package/dist/handlers-tw90pkh5.js +65 -0
- package/dist/{hook-jf0xe8zh.js → hook-123e2scb.js} +11 -12
- package/dist/{hook-h9cqrm8q.js → hook-sxe3r349.js} +11 -12
- package/dist/{http-nc6pydw5.js → http-ecsar8ez.js} +1442 -581
- package/dist/{index-ezxkds2n.js → index-16js521z.js} +335 -107
- package/dist/{index-769nc012.js → index-hw26vj40.js} +25 -19
- package/dist/{index-0wdy6gwc.js → index-nnrbpcjp.js} +25 -17
- package/dist/index-ymn7em0p.js +25 -0
- package/dist/{index-x1zcj09z.js → index-zj518gf9.js} +26 -20
- package/dist/{keepalive-nesm3xb6.js → keepalive-asqtcm4y.js} +7 -7
- package/dist/{lead-bwy6t2za.js → lead-xbfr7fvt.js} +40 -48
- package/dist/{maintenance-8w393zf0.js → maintenance-qma55qvw.js} +9 -9
- package/dist/{oauth-refresh-sweep-sh8xjy08.js → oauth-refresh-sweep-3s04c6qw.js} +6 -6
- package/dist/{onboard-25ps29h1.js → onboard-drskd386.js} +13 -4
- package/dist/{openai-codex-responses-g7w48y30.js → openai-codex-responses-wy6a43wd.js} +13 -13
- package/dist/{openai-responses-nmeyptke.js → openai-responses-6xwf7bzg.js} +19 -19
- package/dist/{opencode-adapter-dce4wskd.js → opencode-adapter-28axqa09.js} +4 -4
- package/dist/{otel-impl-b93gxnz5.js → otel-impl-943c96er.js} +1 -1
- package/dist/{pi-mono-adapter-zvshk5cj.js → pi-mono-adapter-jcqt71cg.js} +17 -19
- package/dist/{pricing-refresh-5v56x7gb.js → pricing-refresh-mx51az05.js} +7 -7
- package/dist/{rbac-roles-x55cnezn.js → rbac-roles-78baecqd.js} +13 -9
- package/dist/{rbac-roles-0p0s6pbj.js → rbac-roles-wcmrg6sv.js} +7 -7
- package/dist/{render-v2-hyd45w8b.js → render-v2-8zjntgf5.js} +7 -7
- package/dist/{seed-pricing-49gbgn96.js → seed-pricing-jqjs6cws.js} +6 -6
- package/dist/{setup-qvq64vzq.js → setup-4pks0vfk.js} +2 -2
- package/dist/work-objects-wangt792.js +165 -0
- package/dist/{worker-scj60cxg.js → worker-p2mr422x.js} +40 -48
- package/openapi.json +1365 -268
- package/package.json +4 -3
- package/src/agentmail/handlers.ts +95 -66
- package/src/be/budget-refusal-notify.ts +1 -0
- package/src/be/db/tasks/read.ts +3 -0
- package/src/be/db/tasks/write.ts +13 -1
- package/src/be/db-client.ts +5 -0
- package/src/be/db.ts +15 -5
- package/src/be/extensions/db.ts +461 -0
- package/src/be/extensions/validate.ts +107 -0
- package/src/be/memory/boot-reembed.ts +17 -12
- package/src/be/memory/index.ts +12 -0
- package/src/be/memory/providers/openai-embedding.ts +4 -0
- package/src/be/memory/types.ts +2 -0
- package/src/be/migrations/153_deferred_task_wait_members.sql +25 -0
- package/src/be/migrations/154_routing_source.sql +3 -0
- package/src/be/migrations/155_extensions.sql +66 -0
- package/src/be/migrations/156_inbox_item_state_read_at.sql +7 -0
- package/src/be/rbac-roles.ts +3 -2
- package/src/be/scripts/typecheck.ts +59 -41
- package/src/be/seed/schedules-seeder.ts +25 -2
- package/src/be/seed/workflows-seeder.ts +17 -0
- package/src/be/seed-scripts/catalog/delegate.ts +3 -1
- package/src/be/seed-skills/bundled-files.generated.json +1 -1
- package/src/be/seed-skills/index.ts +7 -0
- package/src/be/steering.ts +1 -0
- package/src/be/swarm-config-guard.ts +3 -1
- package/src/commands/credential-refresh.ts +70 -0
- package/src/commands/onboard/compose-generator.ts +14 -2
- package/src/commands/onboard/env-generator.ts +7 -0
- package/src/commands/provider-credentials.ts +2 -25
- package/src/commands/runner.ts +24 -57
- package/src/extensions/apply-task-create.ts +135 -0
- package/src/extensions/bundle-path.ts +10 -0
- package/src/extensions/contract-runtime.ts +7 -0
- package/src/extensions/contract-types.generated.ts +4 -0
- package/src/extensions/contract.ts +270 -0
- package/src/extensions/ctx.ts +186 -0
- package/src/extensions/dispatcher.ts +479 -0
- package/src/extensions/identity.ts +44 -0
- package/src/extensions/lifecycle.ts +281 -0
- package/src/extensions/loader.ts +207 -0
- package/src/extensions/post-bridge.ts +161 -0
- package/src/github/handlers.ts +185 -140
- package/src/gitlab/handlers.ts +97 -77
- package/src/heartbeat/heartbeat.ts +155 -83
- package/src/http/agents.ts +1 -1
- package/src/http/all-routes.ts +1 -0
- package/src/http/approval-requests.ts +1 -0
- package/src/http/apps.ts +14 -9
- package/src/http/config.ts +4 -1
- package/src/http/core.ts +38 -2
- package/src/http/extensions.ts +547 -0
- package/src/http/inbox-state.ts +2 -0
- package/src/http/index.ts +41 -3
- package/src/http/mcp-bridge.ts +96 -62
- package/src/http/mcp.ts +1 -1
- package/src/http/script-runs.ts +5 -0
- package/src/http/status.ts +6 -4
- package/src/http/tasks.ts +51 -30
- package/src/integrations/kapso/inbound.ts +15 -10
- package/src/jira/sync.ts +26 -16
- package/src/linear/sync.ts +26 -16
- package/src/prompts/session-templates.ts +18 -13
- package/src/providers/claude-adapter.ts +21 -8
- package/src/rbac/admission.ts +1 -1
- package/src/rbac/elevated-agents.ts +24 -0
- package/src/rbac/legacy-policy.ts +35 -6
- package/src/rbac/permissions.ts +8 -0
- package/src/scheduler/deferred-task-waits.ts +138 -27
- package/src/scheduler/schedule-task.ts +54 -24
- package/src/scheduler/scheduler.ts +108 -125
- package/src/scripts-runtime/executors/native.ts +5 -1
- package/src/scripts-runtime/executors/types.ts +5 -0
- package/src/scripts-runtime/import-allowlist.ts +79 -19
- package/src/scripts-runtime/sdk-allowlist.ts +4 -0
- package/src/scripts-runtime/swarm-config.ts +8 -0
- package/src/scripts-runtime/swarm-sdk.ts +3 -0
- package/src/scripts-runtime/types/stdlib.d.ts +16 -3
- package/src/scripts-runtime/types/swarm-extension.d.ts +562 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +16 -3
- package/src/server.ts +6 -0
- package/src/slack/HEURISTICS.md +3 -1
- package/src/slack/actions.ts +21 -16
- package/src/slack/app.ts +2 -0
- package/src/slack/assistant.ts +4 -12
- package/src/slack/blocks.ts +1 -1
- package/src/slack/handlers.ts +107 -19
- package/src/slack/inbound-files.ts +9 -5
- package/src/slack/render-v2.ts +188 -38
- package/src/slack/router.ts +13 -3
- package/src/slack/steering.ts +3 -3
- package/src/slack/thread-buffer.ts +66 -23
- package/src/slack/work-objects.test.ts +252 -0
- package/src/slack/work-objects.ts +118 -0
- package/src/tasks/errors.ts +9 -0
- package/src/tasks/sibling-awareness.ts +35 -1
- package/src/tasks/worker-follow-up.ts +67 -11
- package/src/tests/acp-adapter.test.ts +10 -10
- package/src/tests/agent-fs-live-url.test.ts +40 -0
- package/src/tests/agent-fs-provision-seeder.test.ts +12 -12
- package/src/tests/api-key-tracking.test.ts +18 -18
- package/src/tests/api-key.test.ts +4 -2
- package/src/tests/apps-rbac.test.ts +1 -1
- package/src/tests/apps-spike5.test.ts +1 -1
- package/src/tests/apps-sync-engine.test.ts +8 -8
- package/src/tests/apps-user-config.test.ts +1 -1
- package/src/tests/artifact-sdk.test.ts +8 -8
- package/src/tests/asset-key-mcp.test.ts +2 -0
- package/src/tests/automation-preflight-alert.test.ts +1 -1
- package/src/tests/base-prompt.test.ts +7 -6
- package/src/tests/budget-user-scope.test.ts +1 -1
- package/src/tests/budgets-routes.test.ts +1 -1
- package/src/tests/claude-adapter-binary.test.ts +22 -40
- package/src/tests/claude-adapter-otel.test.ts +13 -7
- package/src/tests/claude-adapter.test.ts +8 -6
- package/src/tests/claude-hook-credentials.test.ts +3 -3
- package/src/tests/claude-managed-adapter.test.ts +4 -4
- package/src/tests/claude-managed-setup.test.ts +3 -3
- package/src/tests/claude-sdk-lifecycle.test.ts +1 -1
- package/src/tests/claude-sdk-transport.test.ts +6 -6
- package/src/tests/claude-stop-hook.test.ts +8 -8
- package/src/tests/claude-worker-parity.test.ts +3 -3
- package/src/tests/codex-adapter-pool-auth-revalidate.test.ts +5 -5
- package/src/tests/codex-adapter.test.ts +7 -5
- package/src/tests/codex-app-server.test.ts +2 -2
- package/src/tests/codex-login.test.ts +15 -15
- package/src/tests/codex-oauth-credential-info.test.ts +4 -4
- package/src/tests/codex-oauth-keep-warm.test.ts +4 -4
- package/src/tests/codex-oauth-refresh-lock.test.ts +1 -1
- package/src/tests/codex-oauth-storage.test.ts +7 -7
- package/src/tests/codex-pool.test.ts +1 -1
- package/src/tests/codex-steering-hook.test.ts +1 -1
- package/src/tests/codex-swarm-events.test.ts +1 -1
- package/src/tests/config-api-only-keys.test.ts +1 -1
- package/src/tests/config-session-auth.test.ts +2 -2
- package/src/tests/connection-embedded-auth.test.ts +20 -18
- package/src/tests/core-auth.test.ts +1 -1
- package/src/tests/create-page-tool.test.ts +3 -3
- package/src/tests/credential-refresh.test.ts +115 -0
- package/src/tests/credential-wait.test.ts +2 -2
- package/src/tests/credentials.test.ts +6 -4
- package/src/tests/db-queries-oauth.test.ts +40 -40
- package/src/tests/defer-task.test.ts +73 -8
- package/src/tests/deferred-task-wait-migration.test.ts +64 -0
- package/src/tests/deferred-task-wake.test.ts +349 -8
- package/src/tests/devin-adapter.test.ts +1 -1
- package/src/tests/devin-api.test.ts +1 -1
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/e2b-dispatch.test.ts +21 -19
- package/src/tests/e2e-claude-transport.test.ts +3 -3
- package/src/tests/e2e-redact.test.ts +6 -6
- package/src/tests/ensure-token.test.ts +68 -68
- package/src/tests/entrypoint-api-readiness.test.ts +1 -1
- package/src/tests/entrypoint-codex-oauth-seed.test.ts +13 -13
- package/src/tests/env-flag.test.ts +1 -0
- package/src/tests/events-http.test.ts +1 -1
- package/src/tests/extensions-db.test.ts +216 -0
- package/src/tests/extensions-dispatcher.test.ts +275 -0
- package/src/tests/extensions-example-heartbeat-remediate.test.ts +69 -0
- package/src/tests/extensions-example-mcp-install.test.ts +63 -0
- package/src/tests/extensions-example-no-exclamation-marks.test.ts +72 -0
- package/src/tests/extensions-example-rewrite-and-suppress.test.ts +70 -0
- package/src/tests/extensions-example-route-slack-channel.test.ts +217 -0
- package/src/tests/extensions-heartbeat.test.ts +291 -0
- package/src/tests/extensions-http.test.ts +431 -0
- package/src/tests/extensions-lead-equivalence.test.ts +49 -0
- package/src/tests/extensions-lifecycle.test.ts +209 -0
- package/src/tests/extensions-loader.test.ts +95 -0
- package/src/tests/extensions-mcp-tools.test.ts +245 -0
- package/src/tests/extensions-pre-task.test.ts +487 -0
- package/src/tests/extensions-run-context.test.ts +41 -0
- package/src/tests/extensions-tool-call.test.ts +288 -0
- package/src/tests/extensions-validate.test.ts +196 -0
- package/src/tests/fixtures/extensions/bad-import/hooks.ts +8 -0
- package/src/tests/fixtures/extensions/bad-import/manifest.json +9 -0
- package/src/tests/fixtures/extensions/bad-return-shape/hooks.ts +10 -0
- package/src/tests/fixtures/extensions/bad-return-shape/manifest.json +9 -0
- package/src/tests/fixtures/extensions/block-tasks-from-source/hooks.ts +22 -0
- package/src/tests/fixtures/extensions/block-tasks-from-source/manifest.json +9 -0
- package/src/tests/fixtures/extensions/ignore-channel/hooks.ts +22 -0
- package/src/tests/fixtures/extensions/ignore-channel/manifest.json +9 -0
- package/src/tests/fixtures/extensions/load.ts +10 -0
- package/src/tests/fixtures/extensions/minimal/hooks.ts +7 -0
- package/src/tests/fixtures/extensions/minimal/manifest.json +9 -0
- package/src/tests/fixtures/extensions/never-fail-long-tasks/hooks.ts +11 -0
- package/src/tests/fixtures/extensions/never-fail-long-tasks/manifest.json +9 -0
- package/src/tests/fixtures/extensions/no-exclamation-marks/hooks.ts +23 -0
- package/src/tests/fixtures/extensions/no-exclamation-marks/manifest.json +9 -0
- package/src/tests/fixtures/extensions/post-logger/hooks.ts +9 -0
- package/src/tests/fixtures/extensions/post-logger/manifest.json +9 -0
- package/src/tests/fixtures/extensions/priority-a/hooks.ts +7 -0
- package/src/tests/fixtures/extensions/priority-a/manifest.json +9 -0
- package/src/tests/fixtures/extensions/priority-b/hooks.ts +7 -0
- package/src/tests/fixtures/extensions/priority-b/manifest.json +9 -0
- package/src/tests/fixtures/extensions/record-only-on-tag/hooks.ts +16 -0
- package/src/tests/fixtures/extensions/record-only-on-tag/manifest.json +9 -0
- package/src/tests/fixtures/extensions/reserved-assets/hooks.ts +5 -0
- package/src/tests/fixtures/extensions/reserved-assets/manifest.json +10 -0
- package/src/tests/fixtures/extensions/rewrite-progress-prefix/hooks.ts +22 -0
- package/src/tests/fixtures/extensions/rewrite-progress-prefix/manifest.json +9 -0
- package/src/tests/fixtures/extensions/rewrite-task-priority/hooks.ts +7 -0
- package/src/tests/fixtures/extensions/rewrite-task-priority/manifest.json +9 -0
- package/src/tests/fixtures/extensions/route-channel-to-agent/hooks.ts +26 -0
- package/src/tests/fixtures/extensions/route-channel-to-agent/manifest.json +9 -0
- package/src/tests/fixtures/extensions/slow/hooks.ts +10 -0
- package/src/tests/fixtures/extensions/slow/manifest.json +9 -0
- package/src/tests/fixtures/extensions/suppress-lead-follow-up/hooks.ts +12 -0
- package/src/tests/fixtures/extensions/suppress-lead-follow-up/manifest.json +9 -0
- package/src/tests/fixtures/extensions/throws/hooks.ts +12 -0
- package/src/tests/fixtures/extensions/throws/manifest.json +9 -0
- package/src/tests/fixtures/extensions/worker-runtime/hooks.ts +5 -0
- package/src/tests/fixtures/extensions/worker-runtime/manifest.json +9 -0
- package/src/tests/fs-routes.test.ts +1 -1
- package/src/tests/gitlab-auth.test.ts +10 -10
- package/src/tests/harness-provider-resolution.test.ts +8 -5
- package/src/tests/heartbeat-reroute-decision.test.ts +1 -0
- package/src/tests/helper-credentials.test.ts +137 -0
- package/src/tests/http/context-routes.test.ts +2 -2
- package/src/tests/http-api-integration.test.ts +5 -2
- package/src/tests/http-users.test.ts +1 -1
- package/src/tests/identity-refresh.test.ts +2 -2
- package/src/tests/internal-ai/complete-structured.test.ts +2 -2
- package/src/tests/internal-ai/credentials.test.ts +19 -17
- package/src/tests/jira-metadata.test.ts +1 -1
- package/src/tests/jira-oauth.test.ts +5 -5
- package/src/tests/jira-sync.test.ts +1 -1
- package/src/tests/jira-webhook-lifecycle.test.ts +3 -3
- package/src/tests/jira-webhook.test.ts +2 -2
- package/src/tests/kapso-inbound.test.ts +2 -2
- package/src/tests/kv-http.test.ts +1 -1
- package/src/tests/kv-namespace-resolution.test.ts +1 -1
- package/src/tests/kv-page-proxy.test.ts +2 -2
- package/src/tests/launch-password-rejection.test.ts +2 -2
- package/src/tests/linear-webhook.test.ts +1 -1
- package/src/tests/mcp-oauth-dcr-reuse.test.ts +6 -6
- package/src/tests/mcp-oauth-ensure-token.test.ts +28 -22
- package/src/tests/mcp-oauth-manual-client.test.ts +16 -12
- package/src/tests/mcp-oauth-queries.test.ts +35 -32
- package/src/tests/mcp-oauth-resolve-secrets.test.ts +8 -8
- package/src/tests/mcp-oauth-wrapper.test.ts +20 -20
- package/src/tests/mcp-user-route.test.ts +1 -1
- package/src/tests/memory-edges.test.ts +1 -1
- package/src/tests/memory-edit-authorization.test.ts +32 -0
- package/src/tests/memory-rate-endpoint.test.ts +1 -1
- package/src/tests/memory-rate-tool.test.ts +2 -2
- package/src/tests/memory-rater-e2e.test.ts +1 -1
- package/src/tests/memory-rater-llm-summarizer.test.ts +3 -3
- package/src/tests/memory-rater-llm.test.ts +1 -1
- package/src/tests/model-control.test.ts +3 -0
- package/src/tests/multi-runtime-enabled-stats.test.ts +2 -2
- package/src/tests/multi-runtime-registration.test.ts +111 -17
- package/src/tests/oauth-access-token-tool.test.ts +18 -18
- package/src/tests/oauth-callback-flow.test.ts +8 -8
- package/src/tests/oauth-credential-bindings.test.ts +29 -27
- package/src/tests/oauth-keepalive.test.ts +10 -10
- package/src/tests/oauth-presets.test.ts +13 -5
- package/src/tests/oauth-refresh-failure.test.ts +9 -9
- package/src/tests/oauth-refresh-sweep.test.ts +20 -13
- package/src/tests/oauth-wrapper.test.ts +1 -1
- package/src/tests/onboard-compose.test.ts +47 -3
- package/src/tests/onboard-env.test.ts +26 -26
- package/src/tests/onboard-non-interactive.test.ts +4 -4
- package/src/tests/opencode-adapter.test.ts +1 -1
- package/src/tests/opencode-plugin.test.ts +2 -2
- package/src/tests/otel-session-cost-metrics.test.ts +1 -1
- package/src/tests/page-proxy-authed.test.ts +2 -2
- package/src/tests/page-proxy.test.ts +2 -2
- package/src/tests/page-session.test.ts +7 -7
- package/src/tests/page-viewer-auth.test.ts +2 -2
- package/src/tests/pages-authed-mode.test.ts +1 -1
- package/src/tests/pages-http.test.ts +1 -1
- package/src/tests/pages-password-mode.test.ts +1 -1
- package/src/tests/pages-public-authed-401.test.ts +1 -1
- package/src/tests/pages-public-html.test.ts +2 -2
- package/src/tests/pages-view-count.test.ts +1 -1
- package/src/tests/pi-mono-adapter.test.ts +10 -10
- package/src/tests/pi-mono-extension.test.ts +2 -2
- package/src/tests/preload.ts +5 -0
- package/src/tests/pricing-routes.test.ts +1 -1
- package/src/tests/profile-sync-warning.test.ts +8 -8
- package/src/tests/profile-sync.test.ts +8 -8
- package/src/tests/prompt-template-session.test.ts +36 -5
- package/src/tests/provider-process-group.test.ts +95 -4
- package/src/tests/providers/pi-cost.test.ts +1 -1
- package/src/tests/queue-stall-alarm.test.ts +1 -1
- package/src/tests/rbac-admission.test.ts +19 -4
- package/src/tests/rbac-charact-http.test.ts +1 -1
- package/src/tests/rbac-e2e-helpers.ts +1 -1
- package/src/tests/rbac-engine.test.ts +39 -0
- package/src/tests/realtime-room-auth.test.ts +1 -1
- package/src/tests/realtime-room-surfaces.test.ts +1 -1
- package/src/tests/reload-config.test.ts +45 -1
- package/src/tests/routing-affinity-inventory.test.ts +1 -1
- package/src/tests/routing-reason-contract.test.ts +76 -3
- package/src/tests/routing-reason-inventory.test.ts +11 -6
- package/src/tests/routing-source.test.ts +53 -0
- package/src/tests/runner-agent-fs-provision-retry.test.ts +1 -1
- package/src/tests/runner-context-preamble.test.ts +1 -1
- package/src/tests/runner-deployment-resume.test.ts +1 -1
- package/src/tests/runner-fallback-output.test.ts +1 -1
- package/src/tests/runner-identity-refresh.test.ts +1 -1
- package/src/tests/runner-skills-refresh.test.ts +1 -1
- package/src/tests/schedule-target-type.test.ts +3 -3
- package/src/tests/scheduled-tasks.test.ts +14 -5
- package/src/tests/scheduler-occurrence.test.ts +347 -0
- package/src/tests/script-apis-mcp.test.ts +1 -1
- package/src/tests/script-connections-http.test.ts +61 -58
- package/src/tests/script-connections-mcp.test.ts +1 -1
- package/src/tests/script-connections.test.ts +3 -1
- package/src/tests/script-runs-http.test.ts +15 -7
- package/src/tests/script-workflows-runtime-e2e.test.ts +1 -1
- package/src/tests/scripts-boot-reembed.test.ts +4 -0
- package/src/tests/scripts-embeddings.test.ts +4 -0
- package/src/tests/scripts-external-api.test.ts +1 -1
- package/src/tests/scripts-http.test.ts +1 -1
- package/src/tests/scripts-import-allowlist.test.ts +44 -1
- package/src/tests/scripts-mcp-e2e.test.ts +81 -1
- package/src/tests/scripts-only-gating.test.ts +4 -2
- package/src/tests/scripts-retention.test.ts +1 -1
- package/src/tests/scripts-runtime-identity.test.ts +2 -2
- package/src/tests/scripts-runtime-secret-egress.test.ts +1 -1
- package/src/tests/scripts-runtime.test.ts +6 -4
- package/src/tests/scripts-typecheck.test.ts +21 -0
- package/src/tests/sdk-allowlist.test.ts +1 -1
- package/src/tests/secret-scrubber.test.ts +38 -31
- package/src/tests/seed-registry.test.ts +46 -8
- package/src/tests/seed-schedules.test.ts +44 -9
- package/src/tests/seed-workflows.test.ts +21 -9
- package/src/tests/send-task-output-schema.test.ts +9 -1
- package/src/tests/send-task-requested-by.test.ts +1 -0
- package/src/tests/send-task-slack-routing-guard.test.ts +2 -0
- package/src/tests/session-costs-codex-recompute.test.ts +1 -1
- package/src/tests/session-costs-golden.test.ts +2 -2
- package/src/tests/session-costs-model-key-normalize.test.ts +2 -2
- package/src/tests/session-costs-recompute-all-providers.test.ts +1 -1
- package/src/tests/session-tokens.test.ts +1 -1
- package/src/tests/shutdown-error-scrubbing.test.ts +1 -1
- package/src/tests/slack-blocks.test.ts +12 -1
- package/src/tests/slack-file-tools-attachments.test.ts +1 -1
- package/src/tests/slack-inbound-files.test.ts +222 -86
- package/src/tests/slack-reaction-config.test.ts +5 -4
- package/src/tests/slack-read-boundaries.test.ts +1 -1
- package/src/tests/slack-render-v2.test.ts +196 -4
- package/src/tests/slack-router.test.ts +17 -2
- package/src/tests/slack-steering.test.ts +19 -0
- package/src/tests/status.test.ts +19 -7
- package/src/tests/steering-core.test.ts +1 -1
- package/src/tests/steering-enabled.test.ts +6 -8
- package/src/tests/steering-transport.test.ts +4 -4
- package/src/tests/store-progress-output-guidance.test.ts +34 -0
- package/src/tests/swarm-tool-result-gate.test.ts +11 -11
- package/src/tests/swarm-x-tool.test.ts +7 -5
- package/src/tests/sync-ai-toolbox-skills.test.ts +19 -0
- package/src/tests/task-supersede-resume.test.ts +1 -1
- package/src/tests/task-tool-preload-mcp.test.ts +4 -1
- package/src/tests/task-tools-ctx.test.ts +2 -0
- package/src/tests/tasks-requested-by-filter.test.ts +2 -2
- package/src/tests/telemetry-init.test.ts +11 -3
- package/src/tests/tool-annotations.test.ts +1 -1
- package/src/tests/tool-output-agent-id.test.ts +1 -0
- package/src/tests/tool-registrar-no-input.test.ts +42 -1
- package/src/tests/tracker-fold.test.ts +7 -7
- package/src/tests/tracker-tools.test.ts +3 -3
- package/src/tests/ui-followup-lead-delegation.test.ts +1 -0
- package/src/tests/unified-oauth-migration.test.ts +5 -5
- package/src/tests/user-token-rest-auth.test.ts +1 -1
- package/src/tests/user-token-routes.test.ts +1 -1
- package/src/tests/whoami-route.test.ts +1 -1
- package/src/tests/workflow-agent-task.test.ts +15 -13
- package/src/tests/workflow-ctx.test.ts +1 -1
- package/src/tests/workflow-e2e.test.ts +1 -1
- package/src/tests/workflow-engine-v2.test.ts +3 -1
- package/src/tests/workflow-executors.test.ts +2 -2
- package/src/tests/workflow-http-v2.test.ts +8 -6
- package/src/tests/workflow-input-redaction.test.ts +7 -5
- package/src/tests/workflow-integration-io.test.ts +2 -2
- package/src/tests/workflow-llm.test.ts +5 -5
- package/src/tests/workflow-registry.test.ts +1 -1
- package/src/tests/workflow-swarm-script.test.ts +1 -1
- package/src/tests/workflow-triggers-v2.test.ts +23 -21
- package/src/tests/x-composio.test.ts +9 -7
- package/src/tests/x402-client.test.ts +1 -1
- package/src/tests/x402-config.test.ts +28 -41
- package/src/tools/defer-task.ts +156 -24
- package/src/tools/extension-common.ts +84 -0
- package/src/tools/extension-install.ts +65 -0
- package/src/tools/extension-list.ts +66 -0
- package/src/tools/script-common.ts +43 -18
- package/src/tools/send-task.ts +87 -105
- package/src/tools/skills/skill-publish.ts +1 -0
- package/src/tools/store-progress.ts +1 -1
- package/src/tools/task-action.ts +43 -22
- package/src/tools/task-tool-ctx.ts +2 -0
- package/src/tools/templates.ts +2 -1
- package/src/tools/tool-config.ts +3 -1
- package/src/tools/utils.ts +140 -16
- package/src/types.ts +144 -0
- package/src/utils/constants.ts +7 -1
- package/src/utils/credentials.test.ts +16 -16
- package/src/utils/multi-runtime.ts +2 -2
- package/src/utils/steering-enabled.ts +4 -4
- package/src/workflows/executors/agent-task.ts +18 -3
- package/templates/ai-toolbox.manifest.json +7 -1
- package/templates/extensions/README.md +17 -0
- package/templates/extensions/notify-on-complete/README.md +11 -0
- package/templates/extensions/notify-on-complete/hooks.ts +61 -0
- package/templates/extensions/notify-on-complete/manifest.json +7 -0
- package/templates/extensions/require-ticket-ref/README.md +11 -0
- package/templates/extensions/require-ticket-ref/hooks.ts +30 -0
- package/templates/extensions/require-ticket-ref/manifest.json +7 -0
- package/templates/extensions/require-verification-note/README.md +11 -0
- package/templates/extensions/require-verification-note/hooks.ts +32 -0
- package/templates/extensions/require-verification-note/manifest.json +7 -0
- package/templates/schedules/daily-hn-briefing/config.json +1 -1
- package/templates/schedules/gtm-weekly-review/config.json +1 -1
- package/templates/schedules/weekly-code-health-reports/config.json +1 -1
- package/templates/schedules/weekly-dependabot-triage/config.json +1 -1
- package/templates/schedules/weekly-dora-metrics/config.json +1 -1
- package/templates/schedules/weekly-harness-upgrade-check/config.json +1 -1
- package/templates/skills/delegate-work/files/scripts/codex-exec.sh +1 -1
- package/templates/skills/scheduling/content.md +2 -0
- package/templates/skills/serply-search/SKILL.md +95 -0
- package/templates/skills/serply-search/config.json +13 -0
- package/templates/skills/serply-search/content.md +90 -0
- package/templates/skills/swarm-extensions/config.json +14 -0
- package/templates/skills/swarm-extensions/content.md +120 -0
- package/templates/skills/swarm-scripts/SKILL.md +2 -2
- package/templates/skills/swarm-scripts/content.md +2 -2
- package/templates/workflows/claude-code-changelog-watch/config.json +1 -1
- package/templates/workflows/gsc-topic-miner/config.json +1 -1
- package/templates/workflows/linear-drain-loop/config.json +1 -1
- package/templates/workflows/llm-safe-release-context/config.json +1 -1
- package/templates/workflows/ralph-loop/config.json +1 -1
- package/dist/cli-7fehefdf.js +0 -562
- package/dist/cli-ayvy5kde.js +0 -164
- package/dist/cli-ddfw1mc4.js +0 -4322
- package/dist/cli-hzqmgcm2.js +0 -3066
- package/dist/cli-j4d4f6hv.js +0 -338
- package/dist/cli-qgm2pfpq.js +0 -6377
- package/dist/cli-sdzq01t9.js +0 -823
- package/dist/cli-xvkmedgn.js +0 -332
- package/dist/cli-y3pq4v9g.js +0 -664
- package/dist/{anthropic-messages-vs2rabzp.js → anthropic-messages-2y8nktar.js} +19 -19
- package/dist/{claude-managed-setup-f5pmsyrp.js → claude-managed-setup-48dwg9bv.js} +3 -3
- package/dist/{cli-81r683bv.js → cli-ch38q5z4.js} +0 -0
- package/dist/{cli-6664w7y4.js → cli-kj76p1ez.js} +8 -8
- package/dist/{cli-c71mg51n.js → cli-r2fpe7cx.js} +5 -5
- package/dist/{cli-4xz3pmrq.js → cli-y6x0gqtg.js} +16 -16
- package/dist/{index-aa3sa6s8.js → index-2wsdsnmm.js} +1 -1
- package/dist/{mistral-conversations-4ryk7h83.js → mistral-conversations-qhr84ph3.js} +9 -9
- package/dist/{openai-completions-0bqmsajw.js → openai-completions-32rdwmze.js} +19 -19
- package/dist/{openrouter-images-qx18fyp8.js → openrouter-images-9f9ek4rw.js} +3 -3
- package/dist/{pi-messages-79jvzz1d.js → pi-messages-b1mbr6gp.js} +4 -4
|
@@ -45,6 +45,8 @@ import {
|
|
|
45
45
|
expireStaleRuntimeInstances,
|
|
46
46
|
} from "../be/multi-runtime";
|
|
47
47
|
import { promotePendingSteeringForTask } from "../be/steering";
|
|
48
|
+
import type { HeartbeatAction, HeartbeatClassification } from "../extensions/contract";
|
|
49
|
+
import { dispatchPre, extensionIdForAgent } from "../extensions/dispatcher";
|
|
48
50
|
import { resolveTemplate } from "../prompts/resolver";
|
|
49
51
|
import {
|
|
50
52
|
createPoolStarvationDecisionTask,
|
|
@@ -159,6 +161,21 @@ export function maxResumeGenerations(): number {
|
|
|
159
161
|
|
|
160
162
|
export const RESUME_BUDGET_EXHAUSTED_REASON = "resume_budget_exhausted";
|
|
161
163
|
|
|
164
|
+
type StallClassification = HeartbeatClassification;
|
|
165
|
+
type RemediationAction = HeartbeatAction;
|
|
166
|
+
|
|
167
|
+
type RemediationDecision = { action: RemediationAction; reason: string };
|
|
168
|
+
|
|
169
|
+
interface RemediationFacts {
|
|
170
|
+
skipAutoResume: boolean;
|
|
171
|
+
alreadyResumed: boolean;
|
|
172
|
+
resumeBudgetExhausted: boolean;
|
|
173
|
+
supersedeReason: string;
|
|
174
|
+
legacyFailReason: string;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const REMEDIATION_ACTIONS = new Set<RemediationAction>(["supersede-resume", "fail", "record"]);
|
|
178
|
+
|
|
162
179
|
/**
|
|
163
180
|
* Grace window (minutes) a crash-recovery resume pinned to its original agent
|
|
164
181
|
* (DES-523 Phase 1) waits to be reclaimed before the reaper concludes the agent
|
|
@@ -206,6 +223,11 @@ const HEARTBEAT_CHECKLIST_DISABLE = Boolean(process.env.HEARTBEAT_CHECKLIST_DISA
|
|
|
206
223
|
|
|
207
224
|
export interface HeartbeatFindings {
|
|
208
225
|
stalledTasks: AgentTask[];
|
|
226
|
+
extensionSkipped: Array<{
|
|
227
|
+
taskId: string;
|
|
228
|
+
extension: { id: string; name: string };
|
|
229
|
+
reason: string;
|
|
230
|
+
}>;
|
|
209
231
|
autoFailedTasks: Array<{ taskId: string; agentId: string; reason: string }>;
|
|
210
232
|
autoResumedTasks: Array<{
|
|
211
233
|
taskId: string;
|
|
@@ -296,6 +318,7 @@ export async function preflightGate(): Promise<boolean> {
|
|
|
296
318
|
export async function codeLevelTriage(): Promise<HeartbeatFindings> {
|
|
297
319
|
const findings: HeartbeatFindings = {
|
|
298
320
|
stalledTasks: [],
|
|
321
|
+
extensionSkipped: [],
|
|
299
322
|
autoFailedTasks: [],
|
|
300
323
|
autoResumedTasks: [],
|
|
301
324
|
pinnedResumes: [],
|
|
@@ -377,131 +400,173 @@ async function detectAndRemediateStalledTasks(findings: HeartbeatFindings): Prom
|
|
|
377
400
|
continue;
|
|
378
401
|
}
|
|
379
402
|
|
|
403
|
+
let classification: StallClassification | undefined;
|
|
404
|
+
let remediationOpts: RemediationOptions | undefined;
|
|
405
|
+
let proposed: RemediationDecision | undefined;
|
|
406
|
+
|
|
380
407
|
if (!session) {
|
|
381
|
-
// Case A: No active session — worker is dead
|
|
382
408
|
if (taskAgeMs >= stallThresholdNoSessionMin() * 60 * 1000) {
|
|
383
|
-
|
|
409
|
+
classification = "no-session";
|
|
410
|
+
remediationOpts = {
|
|
384
411
|
supersedeReason:
|
|
385
412
|
"Auto-superseded by heartbeat: worker session not found (no active session for task)",
|
|
386
413
|
legacyFailReason:
|
|
387
414
|
"Auto-failed by heartbeat: worker session not found (no active session for task)",
|
|
388
415
|
shortLabel: "no active session",
|
|
389
|
-
}
|
|
416
|
+
};
|
|
417
|
+
proposed = await defaultRemediationDecision(task, remediationOpts);
|
|
390
418
|
}
|
|
391
419
|
} else {
|
|
392
420
|
const isStaleHeartbeat =
|
|
393
421
|
sessionHeartbeatAgeMs! >= stallThresholdStaleHeartbeatMin() * 60 * 1000;
|
|
394
422
|
|
|
395
423
|
if (isStaleHeartbeat) {
|
|
396
|
-
// Case B: Session exists but heartbeat is stale — worker likely crashed
|
|
397
424
|
if (taskAgeMs >= stallThresholdStaleHeartbeatMin() * 60 * 1000) {
|
|
398
|
-
|
|
425
|
+
classification = "stale-session";
|
|
426
|
+
remediationOpts = {
|
|
399
427
|
supersedeReason:
|
|
400
428
|
"Auto-superseded by heartbeat: worker session heartbeat is stale (likely crashed)",
|
|
401
429
|
legacyFailReason:
|
|
402
430
|
"Auto-failed by heartbeat: worker session heartbeat is stale (likely crashed)",
|
|
403
431
|
shortLabel: "stale session heartbeat",
|
|
404
432
|
cleanupActiveSession: true,
|
|
405
|
-
}
|
|
433
|
+
};
|
|
434
|
+
proposed = await defaultRemediationDecision(task, remediationOpts);
|
|
406
435
|
}
|
|
407
436
|
} else {
|
|
408
|
-
// Case C: Session exists and heartbeat is fresh — ambiguous
|
|
409
437
|
if (taskAgeMs >= stallThresholdMinutes() * 60 * 1000) {
|
|
410
|
-
|
|
438
|
+
classification = "fresh-stalled";
|
|
439
|
+
remediationOpts = {
|
|
440
|
+
supersedeReason:
|
|
441
|
+
"Auto-superseded by heartbeat: task stalled despite a fresh session heartbeat",
|
|
442
|
+
legacyFailReason:
|
|
443
|
+
"Auto-failed by heartbeat: task stalled despite a fresh session heartbeat",
|
|
444
|
+
shortLabel: "fresh session heartbeat",
|
|
445
|
+
};
|
|
446
|
+
proposed = {
|
|
447
|
+
action: "record",
|
|
448
|
+
reason: "Task stalled despite a fresh session heartbeat",
|
|
449
|
+
};
|
|
411
450
|
}
|
|
412
451
|
}
|
|
413
452
|
}
|
|
453
|
+
|
|
454
|
+
if (!classification || !remediationOpts || !proposed) continue;
|
|
455
|
+
|
|
456
|
+
const dispatched = await dispatchPre(
|
|
457
|
+
"pre.heartbeat.remediate",
|
|
458
|
+
{
|
|
459
|
+
task,
|
|
460
|
+
...(session ? { session } : {}),
|
|
461
|
+
classification,
|
|
462
|
+
proposedAction: proposed.action,
|
|
463
|
+
reason: proposed.reason,
|
|
464
|
+
taskAgeMs,
|
|
465
|
+
...(sessionHeartbeatAgeMs === null ? {} : { sessionHeartbeatAgeMs }),
|
|
466
|
+
},
|
|
467
|
+
{ skipExtensionId: extensionIdForAgent(task.creatorAgentId) },
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
if (dispatched.action === "block") {
|
|
471
|
+
findings.stalledTasks.push(task);
|
|
472
|
+
findings.extensionSkipped.push({
|
|
473
|
+
taskId: task.id,
|
|
474
|
+
extension: dispatched.extension,
|
|
475
|
+
reason: dispatched.reason,
|
|
476
|
+
});
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (dispatched.action === "modify") {
|
|
481
|
+
const action = dispatched.data.proposedAction;
|
|
482
|
+
if (isRemediationAction(action)) {
|
|
483
|
+
proposed = { ...proposed, action };
|
|
484
|
+
} else {
|
|
485
|
+
console.warn(
|
|
486
|
+
"[Heartbeat] Extension returned an invalid remediation action:",
|
|
487
|
+
scrubSecrets(String(action)),
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (proposed.action === "record") {
|
|
493
|
+
findings.stalledTasks.push(task);
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
await remediateCrashedWorkerTask(findings, task, remediationOpts, proposed);
|
|
414
498
|
}
|
|
415
499
|
}
|
|
416
500
|
|
|
501
|
+
function isRemediationAction(value: unknown): value is RemediationAction {
|
|
502
|
+
return typeof value === "string" && REMEDIATION_ACTIONS.has(value as RemediationAction);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function decideRemediation(task: AgentTask, facts: RemediationFacts): RemediationDecision {
|
|
506
|
+
if (task.workflowRunStepId != null) {
|
|
507
|
+
return { action: "fail", reason: "superseded_workflow_task" };
|
|
508
|
+
}
|
|
509
|
+
if (facts.skipAutoResume || facts.alreadyResumed) {
|
|
510
|
+
return { action: "fail", reason: facts.legacyFailReason };
|
|
511
|
+
}
|
|
512
|
+
if (facts.resumeBudgetExhausted) {
|
|
513
|
+
return { action: "fail", reason: RESUME_BUDGET_EXHAUSTED_REASON };
|
|
514
|
+
}
|
|
515
|
+
return { action: "supersede-resume", reason: facts.supersedeReason };
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
async function defaultRemediationDecision(
|
|
519
|
+
task: AgentTask,
|
|
520
|
+
opts: RemediationOptions,
|
|
521
|
+
): Promise<RemediationDecision> {
|
|
522
|
+
const skipAutoResume = SKIP_AUTO_RESUME_TYPES.has(task.taskType ?? "");
|
|
523
|
+
const isWorkflowStep = task.workflowRunStepId != null;
|
|
524
|
+
const alreadyResumed =
|
|
525
|
+
!skipAutoResume && !isWorkflowStep && (await hasNonTerminalResumeChild(task.id));
|
|
526
|
+
const resumeBudgetExhausted = getNextResumeGeneration(task) > maxResumeGenerations();
|
|
527
|
+
return decideRemediation(task, {
|
|
528
|
+
skipAutoResume,
|
|
529
|
+
alreadyResumed,
|
|
530
|
+
resumeBudgetExhausted,
|
|
531
|
+
supersedeReason: opts.supersedeReason,
|
|
532
|
+
legacyFailReason: opts.legacyFailReason,
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
interface RemediationOptions {
|
|
537
|
+
supersedeReason: string;
|
|
538
|
+
legacyFailReason: string;
|
|
539
|
+
shortLabel: string;
|
|
540
|
+
cleanupActiveSession?: boolean;
|
|
541
|
+
}
|
|
542
|
+
|
|
417
543
|
/**
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
* crashed worker's task gets a fresh "resume" sibling instead of being silently dropped.
|
|
544
|
+
* Applies a selected remediation action for a stalled task. Extensions can replace
|
|
545
|
+
* the selected action before this function runs.
|
|
421
546
|
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
* - a non-terminal child already exists — a prior sweep already created a resume,
|
|
425
|
-
* - `createResumeFollowUp` returns `workflow-skip` — workflow engine owns retries.
|
|
547
|
+
* The supersede and resume path gives crashed work a fresh sibling. The fail path keeps
|
|
548
|
+
* workflow ownership, excluded task types, idempotency, and resume-budget behavior.
|
|
426
549
|
*/
|
|
427
550
|
async function remediateCrashedWorkerTask(
|
|
428
551
|
findings: HeartbeatFindings,
|
|
429
552
|
task: AgentTask,
|
|
430
|
-
opts:
|
|
431
|
-
|
|
432
|
-
legacyFailReason: string;
|
|
433
|
-
shortLabel: string;
|
|
434
|
-
cleanupActiveSession?: boolean;
|
|
435
|
-
},
|
|
553
|
+
opts: RemediationOptions,
|
|
554
|
+
decision: RemediationDecision,
|
|
436
555
|
): Promise<void> {
|
|
437
556
|
if (!task.agentId) return; // Type guard — caller already checked.
|
|
438
557
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
// owns recovery. `createResumeFollowUp` would also bail with `workflow-skip`,
|
|
442
|
-
// but checking here avoids leaving the parent in `superseded` with a dangling
|
|
443
|
-
// dedicated-reason `failTask` no-op chasing it.
|
|
444
|
-
const isWorkflowStep = task.workflowRunStepId != null;
|
|
445
|
-
// Idempotency: if a non-terminal `resume` child already exists for this
|
|
446
|
-
// parent, a prior sweep already created the resume — fall back to the
|
|
447
|
-
// legacy fail path. We filter on `taskType = 'resume'` specifically (not
|
|
448
|
-
// any child task) because `send-task` auto-defaults `parentTaskId` to the
|
|
449
|
-
// caller's current task, so a crashed worker with delegated subtasks
|
|
450
|
-
// would otherwise be incorrectly skipped (PR #594 review).
|
|
451
|
-
const alreadyResumed =
|
|
452
|
-
!skipAutoResume && !isWorkflowStep && (await hasNonTerminalResumeChild(task.id));
|
|
453
|
-
|
|
454
|
-
if (isWorkflowStep) {
|
|
455
|
-
const failed = await failTask(task.id, "superseded_workflow_task");
|
|
558
|
+
if (decision.action === "fail") {
|
|
559
|
+
const failed = await failTask(task.id, decision.reason);
|
|
456
560
|
if (failed) {
|
|
457
561
|
findings.autoFailedTasks.push({
|
|
458
562
|
taskId: task.id,
|
|
459
563
|
agentId: task.agentId,
|
|
460
|
-
reason:
|
|
564
|
+
reason: decision.reason,
|
|
461
565
|
});
|
|
462
566
|
if (opts.cleanupActiveSession) await deleteActiveSession(task.id);
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
);
|
|
466
|
-
const remaining = await getActiveTaskCount(task.agentId);
|
|
467
|
-
if (remaining === 0) await restoreAgentIdleAfterRemediation(task.agentId);
|
|
468
|
-
}
|
|
469
|
-
return;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
if (skipAutoResume || alreadyResumed) {
|
|
473
|
-
const failed = await failTask(task.id, opts.legacyFailReason);
|
|
474
|
-
if (failed) {
|
|
475
|
-
findings.autoFailedTasks.push({
|
|
476
|
-
taskId: task.id,
|
|
477
|
-
agentId: task.agentId,
|
|
478
|
-
reason: opts.legacyFailReason,
|
|
479
|
-
});
|
|
480
|
-
if (opts.cleanupActiveSession) await deleteActiveSession(task.id);
|
|
481
|
-
console.log(
|
|
482
|
-
`[Heartbeat] Auto-failed task ${task.id.slice(0, 8)} — ${opts.shortLabel} (${
|
|
483
|
-
skipAutoResume ? "skipRetry taskType" : "resume already exists"
|
|
484
|
-
})`,
|
|
485
|
-
);
|
|
486
|
-
const remaining = await getActiveTaskCount(task.agentId);
|
|
487
|
-
if (remaining === 0) await restoreAgentIdleAfterRemediation(task.agentId);
|
|
488
|
-
}
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
const nextResumeGeneration = getNextResumeGeneration(task);
|
|
493
|
-
if (nextResumeGeneration > maxResumeGenerations()) {
|
|
494
|
-
const failed = await failTask(task.id, RESUME_BUDGET_EXHAUSTED_REASON);
|
|
495
|
-
if (failed) {
|
|
496
|
-
findings.autoFailedTasks.push({
|
|
497
|
-
taskId: task.id,
|
|
498
|
-
agentId: task.agentId,
|
|
499
|
-
reason: RESUME_BUDGET_EXHAUSTED_REASON,
|
|
500
|
-
});
|
|
501
|
-
if (opts.cleanupActiveSession) await deleteActiveSession(task.id);
|
|
502
|
-
console.warn(
|
|
503
|
-
`[Heartbeat] Auto-failed task ${task.id.slice(0, 8)} — ${RESUME_BUDGET_EXHAUSTED_REASON} (${opts.shortLabel})`,
|
|
504
|
-
);
|
|
567
|
+
const message = `[Heartbeat] Auto-failed task ${task.id.slice(0, 8)}: ${decision.reason} (${opts.shortLabel})`;
|
|
568
|
+
if (decision.reason === RESUME_BUDGET_EXHAUSTED_REASON) console.warn(message);
|
|
569
|
+
else console.log(message);
|
|
505
570
|
const remaining = await getActiveTaskCount(task.agentId);
|
|
506
571
|
if (remaining === 0) await restoreAgentIdleAfterRemediation(task.agentId);
|
|
507
572
|
}
|
|
@@ -511,7 +576,7 @@ async function remediateCrashedWorkerTask(
|
|
|
511
576
|
await beforeHeartbeatSupersedeForTests?.(task);
|
|
512
577
|
|
|
513
578
|
const superseded = await supersedeTask(task.id, {
|
|
514
|
-
reason:
|
|
579
|
+
reason: decision.reason,
|
|
515
580
|
resumeTaskId: null,
|
|
516
581
|
});
|
|
517
582
|
if (!superseded) {
|
|
@@ -539,7 +604,7 @@ async function remediateCrashedWorkerTask(
|
|
|
539
604
|
taskId: task.id,
|
|
540
605
|
resumeTaskId: resume.task.id,
|
|
541
606
|
agentId: task.agentId,
|
|
542
|
-
reason:
|
|
607
|
+
reason: decision.reason,
|
|
543
608
|
});
|
|
544
609
|
// Phase 1 (DES-523): when the resume pinned back to the original
|
|
545
610
|
// (stable-ID) agent, record it so the sweep summary surfaces the pin
|
|
@@ -766,6 +831,7 @@ export async function runRebootSweep(): Promise<void> {
|
|
|
766
831
|
: preferredAgentId === task.agentId
|
|
767
832
|
? "continuity"
|
|
768
833
|
: "reroute_fault",
|
|
834
|
+
routingSource: preferredAgentId === undefined ? undefined : "engine_default",
|
|
769
835
|
tags,
|
|
770
836
|
priority: task.priority,
|
|
771
837
|
source: task.source,
|
|
@@ -1375,6 +1441,7 @@ export async function checkHeartbeatChecklist(): Promise<void> {
|
|
|
1375
1441
|
await createTaskExtended(result.text, {
|
|
1376
1442
|
agentId: lead.id,
|
|
1377
1443
|
routingReason: "skill",
|
|
1444
|
+
routingSource: "engine_default",
|
|
1378
1445
|
taskType: "heartbeat-checklist",
|
|
1379
1446
|
tags: ["checklist", "auto-generated"],
|
|
1380
1447
|
priority: 60,
|
|
@@ -1401,6 +1468,7 @@ export async function runHeartbeatSweep(): Promise<void> {
|
|
|
1401
1468
|
if (!(await preflightGate())) {
|
|
1402
1469
|
const cleanupOnlyFindings: HeartbeatFindings = {
|
|
1403
1470
|
stalledTasks: [],
|
|
1471
|
+
extensionSkipped: [],
|
|
1404
1472
|
autoFailedTasks: [],
|
|
1405
1473
|
autoResumedTasks: [],
|
|
1406
1474
|
pinnedResumes: [],
|
|
@@ -1467,6 +1535,9 @@ function logFindings(findings: HeartbeatFindings): void {
|
|
|
1467
1535
|
if (findings.stalledTasks.length > 0) {
|
|
1468
1536
|
parts.push(`stalled=${findings.stalledTasks.length}`);
|
|
1469
1537
|
}
|
|
1538
|
+
if (findings.extensionSkipped.length > 0) {
|
|
1539
|
+
parts.push(`extension_skipped=${findings.extensionSkipped.length}`);
|
|
1540
|
+
}
|
|
1470
1541
|
if (findings.workerHealthFixes.length > 0) {
|
|
1471
1542
|
parts.push(`health_fixes=${findings.workerHealthFixes.length}`);
|
|
1472
1543
|
}
|
|
@@ -1592,6 +1663,7 @@ export async function createBootTriageTask(): Promise<void> {
|
|
|
1592
1663
|
await createTaskExtended(result.text, {
|
|
1593
1664
|
agentId: lead.id,
|
|
1594
1665
|
routingReason: "skill",
|
|
1666
|
+
routingSource: "engine_default",
|
|
1595
1667
|
taskType: "boot-triage",
|
|
1596
1668
|
tags: ["boot", "triage", "auto-generated"],
|
|
1597
1669
|
priority: 70, // Higher than regular checklist (60)
|
package/src/http/agents.ts
CHANGED
|
@@ -399,7 +399,7 @@ const listAgentRuntimeInstances = route({
|
|
|
399
399
|
pattern: ["api", "agents", null, "runtime-instances"],
|
|
400
400
|
summary: "List runtime instances serving an agent",
|
|
401
401
|
description:
|
|
402
|
-
"Read-only view of the worker processes currently registered for a logical agent. Rows exist only for multi-runtime registrations (MULTI_RUNTIME_ENABLED), so the list is empty
|
|
402
|
+
"Read-only view of the worker processes currently registered for a logical agent. Rows exist only for multi-runtime registrations (MULTI_RUNTIME_ENABLED), so the list is empty when the flag is disabled. `isLive` combines `status` with `lastSeenAt` freshness against the server's staleness cutoff (`staleThresholdMinutes`); `reportedSlots` is each process's self-reported capacity, distinct from the agent's logical `maxTasks` policy.",
|
|
403
403
|
tags: ["Agents"],
|
|
404
404
|
params: z.object({ id: z.string() }),
|
|
405
405
|
responses: {
|
package/src/http/all-routes.ts
CHANGED
|
@@ -386,6 +386,7 @@ export async function handleApprovalRequests(
|
|
|
386
386
|
await createTaskExtended(taskText, {
|
|
387
387
|
agentId: sourceTask.agentId,
|
|
388
388
|
routingReason: sourceTask.agentId ? "continuity" : undefined,
|
|
389
|
+
routingSource: sourceTask.agentId ? "engine_default" : undefined,
|
|
389
390
|
parentTaskId: updated.sourceTaskId,
|
|
390
391
|
source: "system",
|
|
391
392
|
taskType: "hitl-follow-up",
|
package/src/http/apps.ts
CHANGED
|
@@ -1410,15 +1410,20 @@ export async function handleApps(
|
|
|
1410
1410
|
action_name: parsed.params.name,
|
|
1411
1411
|
input_json: JSON.stringify(input),
|
|
1412
1412
|
});
|
|
1413
|
-
const task = await createTaskWithSiblingAwareness(
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1413
|
+
const task = await createTaskWithSiblingAwareness(
|
|
1414
|
+
taskPrompt.text,
|
|
1415
|
+
{
|
|
1416
|
+
source: "api",
|
|
1417
|
+
agentId: action.agentId ?? lead?.id,
|
|
1418
|
+
routingReason: action.agentId ? "human_pinned" : lead ? "skill" : undefined,
|
|
1419
|
+
routingSource: action.agentId || lead ? "engine_default" : undefined,
|
|
1420
|
+
// App-spawned tasks group under the app's asset namespace so a
|
|
1421
|
+
// swarm-tasks source can pull them back via config.assetKey.
|
|
1422
|
+
key: normalizeAssetKey(`shared/app:${app.id}/action:${parsed.params.name}/`),
|
|
1423
|
+
...(actor.startsWith("user:") ? { requestedByUserId: actor.slice("user:".length) } : {}),
|
|
1424
|
+
},
|
|
1425
|
+
{ origin: "app" },
|
|
1426
|
+
);
|
|
1422
1427
|
runActionRoute.respond(res, 200, { ok: true, taskId: task.id, status: task.status });
|
|
1423
1428
|
return true;
|
|
1424
1429
|
}
|
package/src/http/config.ts
CHANGED
|
@@ -310,7 +310,10 @@ export async function handleConfig(
|
|
|
310
310
|
}
|
|
311
311
|
const presence: Record<string, boolean> = {};
|
|
312
312
|
for (const key of keys) {
|
|
313
|
-
|
|
313
|
+
// Organization identity is trimmed by both /status and telemetry.
|
|
314
|
+
// Match that definition without changing presence semantics for secrets.
|
|
315
|
+
const value = key === "SWARM_ORG_NAME" ? process.env[key]?.trim() : process.env[key];
|
|
316
|
+
presence[key] = value !== undefined && value !== "";
|
|
314
317
|
}
|
|
315
318
|
envPresence.respond(res, 200, { presence });
|
|
316
319
|
return true;
|
package/src/http/core.ts
CHANGED
|
@@ -38,8 +38,10 @@ import { agentWithCapacity, getPathSegments, jsonError, parseQueryParams } from
|
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* Load global swarm_config entries into process.env.
|
|
41
|
-
* When override=
|
|
42
|
-
*
|
|
41
|
+
* When override=true (used at startup, on reload, and in createServer), DB
|
|
42
|
+
* values overwrite process.env, so a dashboard-saved value wins over the
|
|
43
|
+
* deployment env. When override=false, existing env vars take precedence
|
|
44
|
+
* (only used by callers that want env-first semantics; no boot path does).
|
|
43
45
|
* Reserved keys are filtered before decryption because they must remain
|
|
44
46
|
* environment-only, even if legacy rows still exist in the DB.
|
|
45
47
|
* Returns the list of keys that were set/updated.
|
|
@@ -139,6 +141,13 @@ export async function reloadGlobalConfigsAndIntegrations(): Promise<ReloadConfig
|
|
|
139
141
|
}
|
|
140
142
|
|
|
141
143
|
async function reloadGlobalConfigsAndIntegrationsInner(): Promise<ReloadConfigResult> {
|
|
144
|
+
// Lazy import keeps http/core out of the memory module-init graph (pulls
|
|
145
|
+
// in the OpenAI SDK). Read the pre-reload configured state first — the
|
|
146
|
+
// provider memoizes its API key at construction, so this reflects whatever
|
|
147
|
+
// key (if any) was live before we hydrate the new env below.
|
|
148
|
+
const { getEmbeddingProvider, resetEmbeddingProvider } = await import("../be/memory");
|
|
149
|
+
const wasEmbeddingsConfigured = getEmbeddingProvider().isConfigured();
|
|
150
|
+
|
|
142
151
|
const updated = await loadGlobalConfigsIntoEnv(true);
|
|
143
152
|
|
|
144
153
|
// File-storage provider selection reads process.env once and memoizes; the
|
|
@@ -149,8 +158,35 @@ async function reloadGlobalConfigsAndIntegrationsInner(): Promise<ReloadConfigRe
|
|
|
149
158
|
const { resetFileStorageProvider } = await import("../fs/registry");
|
|
150
159
|
resetFileStorageProvider();
|
|
151
160
|
|
|
161
|
+
// Same reasoning as the file-storage provider above: the embedding
|
|
162
|
+
// provider captures EMBEDDING_API_KEY/OPENAI_API_KEY once at construction,
|
|
163
|
+
// so a key set (or rotated) via config reload stays inert until this reset.
|
|
164
|
+
resetEmbeddingProvider();
|
|
165
|
+
const isEmbeddingsConfigured = getEmbeddingProvider().isConfigured();
|
|
166
|
+
|
|
152
167
|
const integrations: string[] = [];
|
|
153
168
|
|
|
169
|
+
if (isEmbeddingsConfigured) {
|
|
170
|
+
integrations.push("embeddings");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Off-to-on transition: existing rows written while no key resolved (or
|
|
174
|
+
// with a stale dimension) never got embedded. Kick off the same backfill
|
|
175
|
+
// boot runs, fire-and-forget — it batches, swallows per-batch errors, and
|
|
176
|
+
// is idempotent, so it's safe to not await here.
|
|
177
|
+
if (!wasEmbeddingsConfigured && isEmbeddingsConfigured) {
|
|
178
|
+
import("../be/memory/boot-reembed")
|
|
179
|
+
.then(({ runBootReembed }) => runBootReembed())
|
|
180
|
+
.catch((err) => {
|
|
181
|
+
console.error("[config-reload] memory backfill failed (non-fatal):", err);
|
|
182
|
+
});
|
|
183
|
+
import("../be/scripts/boot-reembed")
|
|
184
|
+
.then(({ runBootReembedScripts }) => runBootReembedScripts())
|
|
185
|
+
.catch((err) => {
|
|
186
|
+
console.error("[config-reload] script backfill failed (non-fatal):", err);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
154
190
|
resetAgentMail();
|
|
155
191
|
if (initAgentMail()) integrations.push("agentmail");
|
|
156
192
|
|