@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
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Extension,
|
|
3
|
+
ExtensionManifest,
|
|
4
|
+
ExtensionRun,
|
|
5
|
+
ExtensionStatus,
|
|
6
|
+
ExtensionVersion,
|
|
7
|
+
} from "../../types";
|
|
8
|
+
import { computeContentHash, getDbClient } from "../db";
|
|
9
|
+
|
|
10
|
+
type ExtensionRow = Omit<Extension, "enabled"> & { enabled: number };
|
|
11
|
+
type ExtensionVersionRow = ExtensionVersion;
|
|
12
|
+
type ExtensionRunRow = ExtensionRun;
|
|
13
|
+
|
|
14
|
+
export type InstallExtensionArgs = {
|
|
15
|
+
manifest: ExtensionManifest;
|
|
16
|
+
files: Record<string, string>;
|
|
17
|
+
priority?: number;
|
|
18
|
+
config?: Record<string, unknown>;
|
|
19
|
+
agentId?: string | null;
|
|
20
|
+
createdBy?: string | null;
|
|
21
|
+
activate?: boolean;
|
|
22
|
+
changeReason?: string | null;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type InstallExtensionResult = {
|
|
26
|
+
extension: Extension;
|
|
27
|
+
isNew: boolean;
|
|
28
|
+
contentDeduped: boolean;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function rowToExtension(row: ExtensionRow): Extension {
|
|
32
|
+
return {
|
|
33
|
+
...row,
|
|
34
|
+
enabled: row.enabled === 1,
|
|
35
|
+
lastError: row.lastError ?? null,
|
|
36
|
+
agentId: row.agentId ?? null,
|
|
37
|
+
createdByAgentId: row.createdByAgentId ?? null,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function canonicalFiles(files: Record<string, string>): Record<string, string> {
|
|
42
|
+
return Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b)));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function bundleContentHash(manifest: ExtensionManifest, files: Record<string, string>): string {
|
|
46
|
+
return computeContentHash(JSON.stringify({ manifest, files: canonicalFiles(files) }));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function installExtension(
|
|
50
|
+
args: InstallExtensionArgs,
|
|
51
|
+
): Promise<InstallExtensionResult> {
|
|
52
|
+
const files = canonicalFiles(args.files);
|
|
53
|
+
const manifestJson = JSON.stringify(args.manifest);
|
|
54
|
+
const filesJson = JSON.stringify(files);
|
|
55
|
+
const contentHash = bundleContentHash(args.manifest, files);
|
|
56
|
+
const actor = args.createdBy ?? null;
|
|
57
|
+
|
|
58
|
+
return await getDbClient().transaction(async (tx) => {
|
|
59
|
+
const existingRow = await tx.get<ExtensionRow>("SELECT * FROM extensions WHERE name = ?", [
|
|
60
|
+
args.manifest.name,
|
|
61
|
+
]);
|
|
62
|
+
const existing = existingRow ? rowToExtension(existingRow) : null;
|
|
63
|
+
const now = new Date().toISOString();
|
|
64
|
+
|
|
65
|
+
if (!existing) {
|
|
66
|
+
const id = crypto.randomUUID();
|
|
67
|
+
const row = await tx.get<ExtensionRow>(
|
|
68
|
+
`INSERT INTO extensions (
|
|
69
|
+
id, name, description, runtime, manifestJson, contentHash, version,
|
|
70
|
+
activeVersion, enabled, priority, configJson, status,
|
|
71
|
+
consecutiveFailures, lastError, agentId, createdByAgentId,
|
|
72
|
+
created_by, updated_by, createdAt, updatedAt
|
|
73
|
+
) VALUES (?, ?, ?, ?, ?, ?, 1, 1, 0, ?, ?, 'disabled', 0, NULL, NULL, ?, ?, ?, ?, ?)
|
|
74
|
+
RETURNING *`,
|
|
75
|
+
[
|
|
76
|
+
id,
|
|
77
|
+
args.manifest.name,
|
|
78
|
+
args.manifest.description,
|
|
79
|
+
args.manifest.runtime,
|
|
80
|
+
manifestJson,
|
|
81
|
+
contentHash,
|
|
82
|
+
args.priority ?? 100,
|
|
83
|
+
JSON.stringify(args.config ?? {}),
|
|
84
|
+
args.agentId ?? null,
|
|
85
|
+
actor,
|
|
86
|
+
actor,
|
|
87
|
+
now,
|
|
88
|
+
now,
|
|
89
|
+
],
|
|
90
|
+
);
|
|
91
|
+
if (!row) throw new Error("Failed to insert extension");
|
|
92
|
+
|
|
93
|
+
for (const [path, content] of Object.entries(files)) {
|
|
94
|
+
await tx.run(
|
|
95
|
+
`INSERT INTO extension_files (
|
|
96
|
+
id, extensionId, path, content, contentHash, created_by, updated_by
|
|
97
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
98
|
+
[crypto.randomUUID(), id, path, content, computeContentHash(content), actor, actor],
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
await tx.run(
|
|
103
|
+
`INSERT INTO extension_versions (
|
|
104
|
+
id, extensionId, version, manifestJson, filesJson, contentHash,
|
|
105
|
+
changedByAgentId, changedAt, changeReason, created_by, updated_by
|
|
106
|
+
) VALUES (?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
107
|
+
[
|
|
108
|
+
crypto.randomUUID(),
|
|
109
|
+
id,
|
|
110
|
+
manifestJson,
|
|
111
|
+
filesJson,
|
|
112
|
+
contentHash,
|
|
113
|
+
args.agentId ?? null,
|
|
114
|
+
now,
|
|
115
|
+
args.changeReason ?? "Initial installation",
|
|
116
|
+
actor,
|
|
117
|
+
actor,
|
|
118
|
+
],
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
return { extension: rowToExtension(row), isNew: true, contentDeduped: false };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (existing.contentHash === contentHash) {
|
|
125
|
+
const row = await tx.get<ExtensionRow>(
|
|
126
|
+
`UPDATE extensions SET
|
|
127
|
+
priority = ?, configJson = ?, activeVersion = ?, updated_by = ?, updatedAt = ?
|
|
128
|
+
WHERE id = ?
|
|
129
|
+
RETURNING *`,
|
|
130
|
+
[
|
|
131
|
+
args.priority ?? existing.priority,
|
|
132
|
+
args.config === undefined ? existing.configJson : JSON.stringify(args.config),
|
|
133
|
+
args.activate ? existing.version : existing.activeVersion,
|
|
134
|
+
actor,
|
|
135
|
+
now,
|
|
136
|
+
existing.id,
|
|
137
|
+
],
|
|
138
|
+
);
|
|
139
|
+
if (!row) throw new Error("Failed to update extension metadata");
|
|
140
|
+
return { extension: rowToExtension(row), isNew: false, contentDeduped: true };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const newVersion = existing.version + 1;
|
|
144
|
+
const row = await tx.get<ExtensionRow>(
|
|
145
|
+
`UPDATE extensions SET
|
|
146
|
+
description = ?, runtime = ?, manifestJson = ?, contentHash = ?, version = ?,
|
|
147
|
+
activeVersion = ?, priority = ?, configJson = ?, updated_by = ?, updatedAt = ?
|
|
148
|
+
WHERE id = ?
|
|
149
|
+
RETURNING *`,
|
|
150
|
+
[
|
|
151
|
+
args.manifest.description,
|
|
152
|
+
args.manifest.runtime,
|
|
153
|
+
manifestJson,
|
|
154
|
+
contentHash,
|
|
155
|
+
newVersion,
|
|
156
|
+
args.activate ? newVersion : existing.activeVersion,
|
|
157
|
+
args.priority ?? existing.priority,
|
|
158
|
+
args.config === undefined ? existing.configJson : JSON.stringify(args.config),
|
|
159
|
+
actor,
|
|
160
|
+
now,
|
|
161
|
+
existing.id,
|
|
162
|
+
],
|
|
163
|
+
);
|
|
164
|
+
if (!row) throw new Error("Failed to update extension");
|
|
165
|
+
|
|
166
|
+
await tx.run("DELETE FROM extension_files WHERE extensionId = ?", [existing.id]);
|
|
167
|
+
for (const [path, content] of Object.entries(files)) {
|
|
168
|
+
await tx.run(
|
|
169
|
+
`INSERT INTO extension_files (
|
|
170
|
+
id, extensionId, path, content, contentHash, created_by, updated_by
|
|
171
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
172
|
+
[
|
|
173
|
+
crypto.randomUUID(),
|
|
174
|
+
existing.id,
|
|
175
|
+
path,
|
|
176
|
+
content,
|
|
177
|
+
computeContentHash(content),
|
|
178
|
+
actor,
|
|
179
|
+
actor,
|
|
180
|
+
],
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
await tx.run(
|
|
185
|
+
`INSERT INTO extension_versions (
|
|
186
|
+
id, extensionId, version, manifestJson, filesJson, contentHash,
|
|
187
|
+
changedByAgentId, changedAt, changeReason, created_by, updated_by
|
|
188
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
189
|
+
[
|
|
190
|
+
crypto.randomUUID(),
|
|
191
|
+
existing.id,
|
|
192
|
+
newVersion,
|
|
193
|
+
manifestJson,
|
|
194
|
+
filesJson,
|
|
195
|
+
contentHash,
|
|
196
|
+
args.agentId ?? null,
|
|
197
|
+
now,
|
|
198
|
+
args.changeReason ?? null,
|
|
199
|
+
actor,
|
|
200
|
+
actor,
|
|
201
|
+
],
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
return { extension: rowToExtension(row), isNew: false, contentDeduped: false };
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export async function getExtensionFiles(extensionId: string): Promise<Record<string, string>> {
|
|
209
|
+
const rows = await getDbClient().query<{ path: string; content: string }>(
|
|
210
|
+
"SELECT path, content FROM extension_files WHERE extensionId = ? ORDER BY path",
|
|
211
|
+
[extensionId],
|
|
212
|
+
);
|
|
213
|
+
return Object.fromEntries(rows.map((row) => [row.path, row.content]));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export async function getExtensionById(id: string): Promise<Extension | null> {
|
|
217
|
+
const row = await getDbClient().get<ExtensionRow>("SELECT * FROM extensions WHERE id = ?", [id]);
|
|
218
|
+
return row ? rowToExtension(row) : null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export async function getExtensionByName(name: string): Promise<Extension | null> {
|
|
222
|
+
const row = await getDbClient().get<ExtensionRow>("SELECT * FROM extensions WHERE name = ?", [
|
|
223
|
+
name,
|
|
224
|
+
]);
|
|
225
|
+
return row ? rowToExtension(row) : null;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export async function listExtensions(): Promise<Extension[]> {
|
|
229
|
+
const rows = await getDbClient().query<ExtensionRow>(
|
|
230
|
+
"SELECT * FROM extensions ORDER BY priority ASC, name ASC",
|
|
231
|
+
);
|
|
232
|
+
return rows.map(rowToExtension);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export async function listExtensionVersions(extensionId: string): Promise<ExtensionVersion[]> {
|
|
236
|
+
return await getDbClient().query<ExtensionVersionRow>(
|
|
237
|
+
"SELECT * FROM extension_versions WHERE extensionId = ? ORDER BY version DESC",
|
|
238
|
+
[extensionId],
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export async function getExtensionVersion(
|
|
243
|
+
extensionId: string,
|
|
244
|
+
version: number,
|
|
245
|
+
): Promise<ExtensionVersion | null> {
|
|
246
|
+
return (
|
|
247
|
+
(await getDbClient().get<ExtensionVersionRow>(
|
|
248
|
+
"SELECT * FROM extension_versions WHERE extensionId = ? AND version = ?",
|
|
249
|
+
[extensionId, version],
|
|
250
|
+
)) ?? null
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export async function activateExtensionVersionSnapshot(
|
|
255
|
+
extensionId: string,
|
|
256
|
+
version: number,
|
|
257
|
+
updatedBy?: string | null,
|
|
258
|
+
): Promise<Extension | null> {
|
|
259
|
+
return await getDbClient().transaction(async (tx) => {
|
|
260
|
+
const snapshot = await tx.get<ExtensionVersionRow>(
|
|
261
|
+
"SELECT * FROM extension_versions WHERE extensionId = ? AND version = ?",
|
|
262
|
+
[extensionId, version],
|
|
263
|
+
);
|
|
264
|
+
if (!snapshot) return null;
|
|
265
|
+
|
|
266
|
+
const manifest = JSON.parse(snapshot.manifestJson) as ExtensionManifest;
|
|
267
|
+
const files = JSON.parse(snapshot.filesJson) as Record<string, string>;
|
|
268
|
+
const now = new Date().toISOString();
|
|
269
|
+
const row = await tx.get<ExtensionRow>(
|
|
270
|
+
`UPDATE extensions SET
|
|
271
|
+
description = ?, runtime = ?, manifestJson = ?, contentHash = ?, activeVersion = ?,
|
|
272
|
+
updated_by = ?, updatedAt = ?
|
|
273
|
+
WHERE id = ?
|
|
274
|
+
RETURNING *`,
|
|
275
|
+
[
|
|
276
|
+
manifest.description,
|
|
277
|
+
manifest.runtime,
|
|
278
|
+
snapshot.manifestJson,
|
|
279
|
+
snapshot.contentHash,
|
|
280
|
+
version,
|
|
281
|
+
updatedBy ?? null,
|
|
282
|
+
now,
|
|
283
|
+
extensionId,
|
|
284
|
+
],
|
|
285
|
+
);
|
|
286
|
+
if (!row) return null;
|
|
287
|
+
|
|
288
|
+
await tx.run("DELETE FROM extension_files WHERE extensionId = ?", [extensionId]);
|
|
289
|
+
for (const [path, content] of Object.entries(files)) {
|
|
290
|
+
await tx.run(
|
|
291
|
+
`INSERT INTO extension_files (
|
|
292
|
+
id, extensionId, path, content, contentHash, created_by, updated_by
|
|
293
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
294
|
+
[
|
|
295
|
+
crypto.randomUUID(),
|
|
296
|
+
extensionId,
|
|
297
|
+
path,
|
|
298
|
+
content,
|
|
299
|
+
computeContentHash(content),
|
|
300
|
+
updatedBy ?? null,
|
|
301
|
+
updatedBy ?? null,
|
|
302
|
+
],
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
return rowToExtension(row);
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export async function updateExtensionMeta(
|
|
310
|
+
id: string,
|
|
311
|
+
args: {
|
|
312
|
+
priority?: number;
|
|
313
|
+
config?: Record<string, unknown>;
|
|
314
|
+
description?: string;
|
|
315
|
+
updatedBy?: string | null;
|
|
316
|
+
},
|
|
317
|
+
): Promise<Extension | null> {
|
|
318
|
+
const sets: string[] = [];
|
|
319
|
+
const values: Array<string | number | null> = [];
|
|
320
|
+
if (args.priority !== undefined) {
|
|
321
|
+
sets.push("priority = ?");
|
|
322
|
+
values.push(args.priority);
|
|
323
|
+
}
|
|
324
|
+
if (args.config !== undefined) {
|
|
325
|
+
sets.push("configJson = ?");
|
|
326
|
+
values.push(JSON.stringify(args.config));
|
|
327
|
+
}
|
|
328
|
+
if (args.description !== undefined) {
|
|
329
|
+
sets.push("description = ?");
|
|
330
|
+
values.push(args.description);
|
|
331
|
+
}
|
|
332
|
+
if (sets.length === 0) return getExtensionById(id);
|
|
333
|
+
|
|
334
|
+
sets.push("updated_by = ?", "updatedAt = ?");
|
|
335
|
+
values.push(args.updatedBy ?? null, new Date().toISOString(), id);
|
|
336
|
+
const row = await getDbClient().get<ExtensionRow>(
|
|
337
|
+
`UPDATE extensions SET ${sets.join(", ")} WHERE id = ? RETURNING *`,
|
|
338
|
+
values,
|
|
339
|
+
);
|
|
340
|
+
return row ? rowToExtension(row) : null;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export async function setExtensionState(
|
|
344
|
+
id: string,
|
|
345
|
+
args: {
|
|
346
|
+
enabled?: boolean;
|
|
347
|
+
status?: ExtensionStatus;
|
|
348
|
+
activeVersion?: number;
|
|
349
|
+
agentId?: string | null;
|
|
350
|
+
consecutiveFailures?: number;
|
|
351
|
+
lastError?: string | null;
|
|
352
|
+
updatedBy?: string | null;
|
|
353
|
+
},
|
|
354
|
+
): Promise<Extension | null> {
|
|
355
|
+
const sets: string[] = [];
|
|
356
|
+
const values: Array<string | number | null> = [];
|
|
357
|
+
const fields = [
|
|
358
|
+
["enabled", args.enabled === undefined ? undefined : args.enabled ? 1 : 0],
|
|
359
|
+
["status", args.status],
|
|
360
|
+
["activeVersion", args.activeVersion],
|
|
361
|
+
["agentId", args.agentId],
|
|
362
|
+
["consecutiveFailures", args.consecutiveFailures],
|
|
363
|
+
["lastError", args.lastError],
|
|
364
|
+
] as const;
|
|
365
|
+
for (const [column, value] of fields) {
|
|
366
|
+
if (value !== undefined) {
|
|
367
|
+
sets.push(`${column} = ?`);
|
|
368
|
+
values.push(value);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (sets.length === 0) return getExtensionById(id);
|
|
372
|
+
|
|
373
|
+
sets.push("updated_by = ?", "updatedAt = ?");
|
|
374
|
+
values.push(args.updatedBy ?? null, new Date().toISOString(), id);
|
|
375
|
+
const row = await getDbClient().get<ExtensionRow>(
|
|
376
|
+
`UPDATE extensions SET ${sets.join(", ")} WHERE id = ? RETURNING *`,
|
|
377
|
+
values,
|
|
378
|
+
);
|
|
379
|
+
return row ? rowToExtension(row) : null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export async function recordExtensionFailure(
|
|
383
|
+
id: string,
|
|
384
|
+
lastError: string,
|
|
385
|
+
maxConsecutiveFailures: number,
|
|
386
|
+
): Promise<Extension | null> {
|
|
387
|
+
const row = await getDbClient().get<ExtensionRow>(
|
|
388
|
+
`UPDATE extensions SET
|
|
389
|
+
consecutiveFailures = consecutiveFailures + 1,
|
|
390
|
+
lastError = ?,
|
|
391
|
+
enabled = CASE WHEN consecutiveFailures + 1 >= ? THEN 0 ELSE enabled END,
|
|
392
|
+
status = CASE
|
|
393
|
+
WHEN consecutiveFailures + 1 >= ? THEN 'auto-disabled'
|
|
394
|
+
ELSE status
|
|
395
|
+
END,
|
|
396
|
+
updatedAt = ?
|
|
397
|
+
WHERE id = ?
|
|
398
|
+
RETURNING *`,
|
|
399
|
+
[lastError, maxConsecutiveFailures, maxConsecutiveFailures, new Date().toISOString(), id],
|
|
400
|
+
);
|
|
401
|
+
return row ? rowToExtension(row) : null;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export async function deleteExtension(id: string): Promise<boolean> {
|
|
405
|
+
const result = await getDbClient().run("DELETE FROM extensions WHERE id = ?", [id]);
|
|
406
|
+
return result.changes > 0;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export async function insertExtensionRun(args: {
|
|
410
|
+
extensionId: string;
|
|
411
|
+
version: number;
|
|
412
|
+
event: string;
|
|
413
|
+
action: ExtensionRun["action"];
|
|
414
|
+
durationMs?: number | null;
|
|
415
|
+
message?: string | null;
|
|
416
|
+
agentId?: string | null;
|
|
417
|
+
subject?: string | null;
|
|
418
|
+
}): Promise<ExtensionRun> {
|
|
419
|
+
const row = await getDbClient().get<ExtensionRunRow>(
|
|
420
|
+
`INSERT INTO extension_runs (
|
|
421
|
+
id, extensionId, version, event, action, durationMs, message, agentId, subject, createdAt
|
|
422
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
|
|
423
|
+
[
|
|
424
|
+
crypto.randomUUID(),
|
|
425
|
+
args.extensionId,
|
|
426
|
+
args.version,
|
|
427
|
+
args.event,
|
|
428
|
+
args.action,
|
|
429
|
+
args.durationMs ?? null,
|
|
430
|
+
args.message ?? null,
|
|
431
|
+
args.agentId ?? null,
|
|
432
|
+
args.subject ?? null,
|
|
433
|
+
new Date().toISOString(),
|
|
434
|
+
],
|
|
435
|
+
);
|
|
436
|
+
if (!row) throw new Error("Failed to insert extension run");
|
|
437
|
+
return row;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export async function pruneExtensionRuns(extensionId: string, keep = 500): Promise<void> {
|
|
441
|
+
await getDbClient().run(
|
|
442
|
+
`DELETE FROM extension_runs
|
|
443
|
+
WHERE extensionId = ? AND id IN (
|
|
444
|
+
SELECT id FROM extension_runs
|
|
445
|
+
WHERE extensionId = ?
|
|
446
|
+
ORDER BY createdAt DESC, rowid DESC
|
|
447
|
+
LIMIT -1 OFFSET ?
|
|
448
|
+
)`,
|
|
449
|
+
[extensionId, extensionId, keep],
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export async function listExtensionRuns(extensionId: string, limit = 100): Promise<ExtensionRun[]> {
|
|
454
|
+
return await getDbClient().query<ExtensionRunRow>(
|
|
455
|
+
`SELECT * FROM extension_runs
|
|
456
|
+
WHERE extensionId = ?
|
|
457
|
+
ORDER BY createdAt DESC, rowid DESC
|
|
458
|
+
LIMIT ?`,
|
|
459
|
+
[extensionId, Math.max(1, Math.min(500, limit))],
|
|
460
|
+
);
|
|
461
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { isSafeBundlePath } from "../../extensions/bundle-path";
|
|
2
|
+
import { EXTENSION_TYPE_DEFINITIONS } from "../../extensions/contract-types.generated";
|
|
3
|
+
import { checkImportAllowlist } from "../../scripts-runtime/import-allowlist";
|
|
4
|
+
import { type ExtensionManifest, ExtensionManifestSchema } from "../../types";
|
|
5
|
+
import {
|
|
6
|
+
SCRIPT_SDK_TYPES,
|
|
7
|
+
SCRIPT_STDLIB_MODULE_TYPES,
|
|
8
|
+
typecheckWithAmbient,
|
|
9
|
+
} from "../scripts/typecheck";
|
|
10
|
+
|
|
11
|
+
export type BundleValidationResult =
|
|
12
|
+
| { ok: true; manifest: ExtensionManifest }
|
|
13
|
+
| { ok: false; diagnostics: string[] };
|
|
14
|
+
|
|
15
|
+
export async function validateBundle(input: {
|
|
16
|
+
manifest: unknown;
|
|
17
|
+
files: Record<string, string>;
|
|
18
|
+
}): Promise<BundleValidationResult> {
|
|
19
|
+
const parsedManifest = ExtensionManifestSchema.safeParse(input.manifest);
|
|
20
|
+
const pathDiagnostics = Object.keys(input.files)
|
|
21
|
+
.filter((path) => !isSafeBundlePath(path))
|
|
22
|
+
.map((path) => `Unsafe bundle file path: ${JSON.stringify(path)}`);
|
|
23
|
+
if (!parsedManifest.success) {
|
|
24
|
+
return {
|
|
25
|
+
ok: false,
|
|
26
|
+
diagnostics: [
|
|
27
|
+
...pathDiagnostics,
|
|
28
|
+
...parsedManifest.error.issues.map(
|
|
29
|
+
(issue) => `${issue.path.join(".") || "manifest"}: ${issue.message}`,
|
|
30
|
+
),
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (pathDiagnostics.length > 0) return { ok: false, diagnostics: pathDiagnostics };
|
|
35
|
+
|
|
36
|
+
const manifest = parsedManifest.data;
|
|
37
|
+
if (manifest.runtime === "worker") {
|
|
38
|
+
return { ok: false, diagnostics: ['runtime "worker" is not supported in v1'] };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const asset of ["skills", "workflows", "schedules"] as const) {
|
|
42
|
+
if ((manifest.assets[asset]?.length ?? 0) > 0) {
|
|
43
|
+
return { ok: false, diagnostics: [`assets.${asset} is not supported in v1`] };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const hookPath = manifest.assets.hooks;
|
|
48
|
+
if (!(hookPath in input.files)) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
diagnostics: [`assets.hooks "${hookPath}" does not name a file in files`],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const extraPaths = Object.keys(input.files).filter((path) => path !== hookPath);
|
|
55
|
+
if (extraPaths.length > 0) {
|
|
56
|
+
return {
|
|
57
|
+
ok: false,
|
|
58
|
+
diagnostics: [
|
|
59
|
+
`Only the hooks asset is supported in v1. Unexpected files: ${extraPaths.join(", ")}`,
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const source = input.files[hookPath]!;
|
|
65
|
+
const imports = checkImportAllowlist(source, {
|
|
66
|
+
allowedBare: ["swarm-extension", "zod", "stdlib"],
|
|
67
|
+
allowRelative: false,
|
|
68
|
+
strictDynamic: true,
|
|
69
|
+
});
|
|
70
|
+
if (!imports.ok) return { ok: false, diagnostics: [imports.diagnostic] };
|
|
71
|
+
|
|
72
|
+
const typecheck = await typecheckWithAmbient({
|
|
73
|
+
source,
|
|
74
|
+
modules: {
|
|
75
|
+
"swarm-extension": EXTENSION_TYPE_DEFINITIONS,
|
|
76
|
+
"swarm-sdk": SCRIPT_SDK_TYPES,
|
|
77
|
+
stdlib: SCRIPT_STDLIB_MODULE_TYPES,
|
|
78
|
+
},
|
|
79
|
+
checkFile: `/// <reference path="./runtime-globals.d.ts" />
|
|
80
|
+
import * as hooks from "./user-script";
|
|
81
|
+
import type { SwarmExtension } from "swarm-extension";
|
|
82
|
+
import type { ZodTypeAny } from "zod";
|
|
83
|
+
const manifest = ${JSON.stringify(manifest)} as const;
|
|
84
|
+
type Manifest = typeof hooks extends { config: infer Config extends ZodTypeAny }
|
|
85
|
+
? typeof manifest & { config: Config }
|
|
86
|
+
: typeof manifest;
|
|
87
|
+
const _extension: SwarmExtension<Manifest> = hooks.default;
|
|
88
|
+
type ConfigIsValid = typeof hooks extends { config: infer Config }
|
|
89
|
+
? Config extends ZodTypeAny ? true : false
|
|
90
|
+
: true;
|
|
91
|
+
const _configIsValid: ConfigIsValid = true;
|
|
92
|
+
void _extension;
|
|
93
|
+
void _configIsValid;
|
|
94
|
+
`,
|
|
95
|
+
});
|
|
96
|
+
if (!typecheck.ok) {
|
|
97
|
+
return {
|
|
98
|
+
ok: false,
|
|
99
|
+
diagnostics: typecheck.structured.map(
|
|
100
|
+
(diagnostic) =>
|
|
101
|
+
`${diagnostic.file}:${diagnostic.line}:${diagnostic.column} TS${diagnostic.code}: ${diagnostic.message}`,
|
|
102
|
+
),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { ok: true, manifest };
|
|
107
|
+
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Backfill: detect agent_memory rows with no embedding at all (never
|
|
3
|
+
* embedded — e.g. every row written while no key was configured) or a
|
|
4
|
+
* wrong-dimension embedding (not 512d — legacy rows), and re-embed them in
|
|
5
|
+
* the background. Runs once per boot, and again whenever a config reload
|
|
6
|
+
* turns embeddings on for the first time (see scheduleIntegrationsReload in
|
|
7
|
+
* src/http/core.ts). Async/non-blocking, idempotent, no-op when the DB is
|
|
8
|
+
* clean or no key resolves.
|
|
5
9
|
*
|
|
6
10
|
* This is the app-level equivalent of a forward-only migration — SQL can't
|
|
7
|
-
* call OpenAI, so the backfill runs at startup
|
|
11
|
+
* call OpenAI, so the backfill runs at startup (and on the on-transition)
|
|
12
|
+
* instead.
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
15
|
import { getDbClient } from "@/be/db";
|
|
@@ -13,13 +18,13 @@ import { getEmbeddingProvider, getMemoryStore } from "./index";
|
|
|
13
18
|
|
|
14
19
|
const VECTOR_BYTES = EMBEDDING_DIMENSIONS * Float32Array.BYTES_PER_ELEMENT;
|
|
15
20
|
const BATCH_SIZE = 20;
|
|
21
|
+
const INVALID_EMBEDDING_WHERE = `embedding IS NULL OR length(embedding) != ${VECTOR_BYTES}`;
|
|
16
22
|
|
|
17
23
|
export async function runBootReembed(): Promise<void> {
|
|
18
24
|
const invalidCount =
|
|
19
25
|
(
|
|
20
26
|
await getDbClient().get<{ count: number }>(
|
|
21
|
-
`SELECT COUNT(*) as count FROM agent_memory
|
|
22
|
-
WHERE embedding IS NOT NULL AND length(embedding) != ${VECTOR_BYTES}`,
|
|
27
|
+
`SELECT COUNT(*) as count FROM agent_memory WHERE ${INVALID_EMBEDDING_WHERE}`,
|
|
23
28
|
)
|
|
24
29
|
)?.count ?? 0;
|
|
25
30
|
|
|
@@ -31,17 +36,18 @@ export async function runBootReembed(): Promise<void> {
|
|
|
31
36
|
const testEmbed = await provider.embed("test");
|
|
32
37
|
if (!testEmbed) {
|
|
33
38
|
console.warn(
|
|
34
|
-
`[boot-reembed] skipped: ${invalidCount} wrong-dimension rows found but no OpenAI key configured`,
|
|
39
|
+
`[boot-reembed] skipped: ${invalidCount} missing/wrong-dimension rows found but no OpenAI key configured`,
|
|
35
40
|
);
|
|
36
41
|
return;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
console.log(
|
|
44
|
+
console.log(
|
|
45
|
+
`[boot-reembed] starting: ${invalidCount} rows missing or with wrong embedding dimensions`,
|
|
46
|
+
);
|
|
40
47
|
|
|
41
48
|
const store = getMemoryStore();
|
|
42
49
|
const rows = await getDbClient().query<{ id: string; content: string }>(
|
|
43
|
-
`SELECT id, content FROM agent_memory
|
|
44
|
-
WHERE embedding IS NOT NULL AND length(embedding) != ${VECTOR_BYTES}`,
|
|
50
|
+
`SELECT id, content FROM agent_memory WHERE ${INVALID_EMBEDDING_WHERE}`,
|
|
45
51
|
);
|
|
46
52
|
|
|
47
53
|
let reembedded = 0;
|
|
@@ -69,8 +75,7 @@ export async function runBootReembed(): Promise<void> {
|
|
|
69
75
|
const afterInvalid =
|
|
70
76
|
(
|
|
71
77
|
await getDbClient().get<{ count: number }>(
|
|
72
|
-
`SELECT COUNT(*) as count FROM agent_memory
|
|
73
|
-
WHERE embedding IS NOT NULL AND length(embedding) != ${VECTOR_BYTES}`,
|
|
78
|
+
`SELECT COUNT(*) as count FROM agent_memory WHERE ${INVALID_EMBEDDING_WHERE}`,
|
|
74
79
|
)
|
|
75
80
|
)?.count ?? 0;
|
|
76
81
|
|
package/src/be/memory/index.ts
CHANGED
|
@@ -12,6 +12,18 @@ export function getEmbeddingProvider(): EmbeddingProvider {
|
|
|
12
12
|
return embeddingProvider;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Drop the memoized embedding provider so the next `getEmbeddingProvider()`
|
|
17
|
+
* re-reads process.env. The provider captures its API key once at
|
|
18
|
+
* construction (see OpenAIEmbeddingProvider), so without a reset here a key
|
|
19
|
+
* set after boot (or after the first embed attempt) stays inert until the
|
|
20
|
+
* process restarts. Called from the config reload path — mirrors
|
|
21
|
+
* `resetFileStorageProvider` in src/fs/registry.ts.
|
|
22
|
+
*/
|
|
23
|
+
export function resetEmbeddingProvider(): void {
|
|
24
|
+
embeddingProvider = null;
|
|
25
|
+
}
|
|
26
|
+
|
|
15
27
|
export function getMemoryStore(): MemoryStore {
|
|
16
28
|
if (!memoryStore) {
|
|
17
29
|
const { SqliteMemoryStore } =
|
|
@@ -28,6 +28,10 @@ export class OpenAIEmbeddingProvider implements EmbeddingProvider {
|
|
|
28
28
|
: (process.env.EMBEDDING_MODEL ?? DEFAULT_EMBEDDING_MODEL);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
isConfigured(): boolean {
|
|
32
|
+
return !!this.apiKey;
|
|
33
|
+
}
|
|
34
|
+
|
|
31
35
|
private getClient(): OpenAI | null {
|
|
32
36
|
if (!this.apiKey) return null;
|
|
33
37
|
if (!this.client)
|
package/src/be/memory/types.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface EmbeddingProvider {
|
|
|
9
9
|
readonly dimensions: number;
|
|
10
10
|
embed(text: string): Promise<Float32Array | null>;
|
|
11
11
|
embedBatch(texts: string[]): Promise<(Float32Array | null)[]>;
|
|
12
|
+
/** True when the provider has a usable API key — no network call. */
|
|
13
|
+
isConfigured(): boolean;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
// ============================================================================
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- One claim and deadline per wait; each member independently follows deferrals.
|
|
2
|
+
ALTER TABLE deferred_task_waits ADD COLUMN mode TEXT NOT NULL DEFAULT 'all'
|
|
3
|
+
CHECK (mode IN ('all', 'any'));
|
|
4
|
+
|
|
5
|
+
CREATE TABLE deferred_task_wait_members (
|
|
6
|
+
scheduleId TEXT NOT NULL REFERENCES deferred_task_waits(scheduleId) ON DELETE CASCADE,
|
|
7
|
+
taskId TEXT NOT NULL,
|
|
8
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
9
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
10
|
+
created_by TEXT,
|
|
11
|
+
updated_by TEXT,
|
|
12
|
+
PRIMARY KEY (scheduleId, taskId)
|
|
13
|
+
);
|
|
14
|
+
CREATE INDEX idx_deferred_task_wait_members_task ON deferred_task_wait_members(taskId);
|
|
15
|
+
|
|
16
|
+
-- Preserve pending and fired legacy waits, including already-retargeted IDs.
|
|
17
|
+
INSERT INTO deferred_task_wait_members
|
|
18
|
+
(scheduleId, taskId, created_at, updated_at, created_by, updated_by)
|
|
19
|
+
SELECT scheduleId, taskId, created_at, updated_at, created_by, updated_by
|
|
20
|
+
FROM deferred_task_waits;
|
|
21
|
+
|
|
22
|
+
DROP INDEX idx_deferred_task_waits_pending;
|
|
23
|
+
ALTER TABLE deferred_task_waits DROP COLUMN taskId;
|
|
24
|
+
CREATE INDEX idx_deferred_task_waits_pending
|
|
25
|
+
ON deferred_task_waits(scheduleId) WHERE status = 'pending';
|