@desplega.ai/agent-swarm 1.158.0 → 1.160.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{acp-adapter-xaq4n6pc.js → acp-adapter-2mjwcsfh.js} +124 -27
- package/dist/{actions-p9hz5yat.js → actions-e43rxskr.js} +35 -30
- package/dist/{anthropic-messages-51pz26qe.js → anthropic-messages-5qx80j9k.js} +106 -16
- package/dist/{app-g26wdcz6.js → app-mc7xfagn.js} +12 -10
- package/dist/{assistant-wydfqkb3.js → assistant-sedkzv3b.js} +42 -31
- package/dist/{azure-openai-responses-8gksqtmz.js → azure-openai-responses-nfb21z9a.js} +13 -14
- package/dist/{boot-reembed-se8zmdcp.js → boot-reembed-cqz9swn5.js} +13 -12
- package/dist/{boot-reembed-g5ckg9yb.js → boot-reembed-m3656j2n.js} +14 -13
- package/dist/{boot-scrub-logs-wfxqan61.js → boot-scrub-logs-xbxf5d7w.js} +11 -9
- package/dist/boot-seeds-gsetbs5y.js +28 -0
- package/dist/{claude-adapter-tv2x4f36.js → claude-adapter-dc6289mc.js} +28 -23
- package/dist/{claude-managed-adapter-41b2s7fd.js → claude-managed-adapter-naaw51me.js} +4 -3
- package/dist/{claude-managed-setup-60g8aazx.js → claude-managed-setup-eacvchx0.js} +12 -3
- package/dist/claude-sdk-session-bqp2xvym.js +29722 -0
- package/dist/{cli-987hg0aa.js → cli-0jwe9034.js} +2 -2
- package/dist/{cli-vj6h9kc2.js → cli-0m7wct0d.js} +59 -1
- package/dist/{cli-c07r9a2m.js → cli-0q3avq3s.js} +12 -11
- package/dist/{cli-19jenss3.js → cli-0wgxmwf6.js} +31 -10
- package/dist/cli-0x01kwrd.js +491 -0
- package/dist/cli-0xqde53b.js +176 -0
- package/dist/cli-10nhj6xq.js +8355 -0
- package/dist/{cli-tt9k8r35.js → cli-12tszpk9.js} +479 -910
- package/dist/{cli-5b6b62tz.js → cli-13hw4z91.js} +1 -1
- package/dist/{cli-cqt19wg6.js → cli-1a2j50m0.js} +11 -2
- package/dist/{cli-xberxa1r.js → cli-25fcq4b4.js} +2 -2
- package/dist/{cli-npssxgaz.js → cli-2pdaysab.js} +52 -2
- package/dist/cli-3qhyh31j.js +166 -0
- package/dist/cli-447dt1h3.js +3828 -0
- package/dist/cli-4derpgyk.js +115 -0
- package/dist/{cli-00w2c66p.js → cli-523679eh.js} +13 -2
- package/dist/{cli-y95wp3tg.js → cli-58e8yr0d.js} +1 -1
- package/dist/{cli-24k806sc.js → cli-5nbmpy8w.js} +3 -3
- package/dist/{cli-53sz8gkz.js → cli-6cs6wzxt.js} +1 -1
- package/dist/cli-741yb0xx.js +1027 -0
- package/dist/cli-74h9hscv.js +69 -0
- package/dist/cli-7cxw8b60.js +14910 -0
- package/dist/{cli-xhaeg2nc.js → cli-7e398j1h.js} +1 -1
- package/dist/cli-7kyk9jr3.js +22 -0
- package/dist/cli-89s4ngw3.js +183 -0
- package/dist/{cli-9b13ggd1.js → cli-89v6kyq7.js} +1 -0
- package/dist/{cli-ftfvggzx.js → cli-9hsgwz4w.js} +1045 -581
- package/dist/{cli-rqz8qbw7.js → cli-a8dvhzrt.js} +59 -20
- package/dist/{cli-j57qkrpq.js → cli-azhgzetg.js} +395 -56
- package/dist/cli-br0qdrnp.js +2150 -0
- package/dist/{cli-rj19hc34.js → cli-btfv8y88.js} +1 -1
- package/dist/{cli-8qmme6vd.js → cli-c8a36vcc.js} +2 -2
- package/dist/cli-cpvsaqsw.js +333 -0
- package/dist/cli-d5czme6m.js +17805 -0
- package/dist/{cli-h38x0qhg.js → cli-et8m9xsv.js} +4 -3
- package/dist/{cli-x24pshtq.js → cli-evvtk35y.js} +6 -6
- package/dist/{cli-7s3syk22.js → cli-f8gy6r2r.js} +5 -5
- package/dist/{cli-zt1227k1.js → cli-fkqhbg8g.js} +5 -3
- package/dist/{cli-9httdpyq.js → cli-g2whhdrf.js} +1 -1
- package/dist/cli-gt4hxb8p.js +99 -0
- package/dist/{cli-s8eet254.js → cli-jajnsm8q.js} +37184 -53838
- package/dist/{cli-7gtvvpbh.js → cli-jayjpjmb.js} +21 -12
- package/dist/{cli-68w09sjw.js → cli-jyk0ynw2.js} +27 -89
- package/dist/{cli-aehm1rbq.js → cli-jz4w45qt.js} +1152 -61
- package/dist/cli-kmcpfwn2.js +333856 -0
- package/dist/{cli-4198qc9v.js → cli-ktmyrtpn.js} +19 -3
- package/dist/{cli-j55n64b6.js → cli-mfe5btp9.js} +505 -189
- package/dist/{cli-q67y4wzm.js → cli-phsaj4xq.js} +24 -2
- package/dist/{cli-1hkrch3k.js → cli-pm1rst0h.js} +46 -7
- package/dist/{cli-pw9rj5t9.js → cli-pqetb83f.js} +1 -176
- package/dist/{cli-ggm92wcn.js → cli-ptr8h7kp.js} +20 -1
- package/dist/{cli-s8s499xy.js → cli-qbksc292.js} +3 -2
- package/dist/{cli-47m6dkd3.js → cli-qydf22qq.js} +597 -346
- package/dist/{cli-3gmcwfyx.js → cli-r1mxd1xh.js} +13 -6
- package/dist/cli-rb9m6rpe.js +4980 -0
- package/dist/cli-rykfmgwg.js +102 -0
- package/dist/{cli-5d10vd2m.js → cli-shkxm1vn.js} +6 -5
- package/dist/{cli-eetrvv91.js → cli-t3p77qk1.js} +1 -1
- package/dist/cli-tfky2838.js +756 -0
- package/dist/{cli-g8djp6qe.js → cli-tmqt7dpj.js} +40 -0
- package/dist/{cli-fgqxwrpv.js → cli-tpq83z89.js} +1631 -127
- package/dist/cli-trc24wk2.js +143 -0
- package/dist/{cli-aky8tctm.js → cli-tzx2ke1v.js} +3 -3
- package/dist/cli-v7fn5gms.js +1425 -0
- package/dist/{cli-wscdvcqz.js → cli-vctdqs5h.js} +1 -1
- package/dist/{cli-cw9zck8j.js → cli-xjcywfsf.js} +8 -4
- package/dist/{cli-k0g1sjzm.js → cli-ybgv4kw2.js} +18 -11
- package/dist/{cli-rjehvrts.js → cli-ydmcgve1.js} +8 -8
- package/dist/{cli-vhjwh6cz.js → cli-ygwm91nt.js} +1 -1
- package/dist/{cli-mcnhgnn1.js → cli-ykk5jaax.js} +184 -26
- package/dist/{cli-de1396j2.js → cli-ywybs5as.js} +7 -1
- package/dist/cli-zpep9q5e.js +491 -0
- package/dist/cli.js +41 -32
- package/dist/cloudflare-workers-ai-system-one-k6fbxw9d.js +46 -0
- package/dist/{codex-adapter-cnm8wk11.js → codex-adapter-nmxcatww.js} +26 -17
- package/dist/{codex-hook-9hptmdhj.js → codex-hook-20me6byw.js} +2 -2
- package/dist/{codex-login-x3jk4etn.js → codex-login-w6fz4xbz.js} +50 -5
- package/dist/{codex-session-runner-gfg547zj.js → codex-session-runner-90aa80ev.js} +24 -17
- package/dist/{commands-e3bn0p75.js → commands-8wcq1kn7.js} +11 -9
- package/dist/{db-03v9kzr2.js → db-j40kc4se.js} +25 -11
- package/dist/{devin-adapter-8vgkwh29.js → devin-adapter-dpsv6hd9.js} +1 -1
- package/dist/{dispatcher-nrmg8yht.js → dispatcher-4zqy768d.js} +34 -29
- package/dist/{dsh-adapter-k03nfqa6.js → dsh-adapter-mpnzgztj.js} +3 -3
- package/dist/{e2b-93x1k0j5.js → e2b-ez07znam.js} +4 -3
- package/dist/execute-6e7qeyk4.js +1017 -0
- package/dist/{google-generative-ai-bxmv50nc.js → google-generative-ai-k6n5nbpp.js} +6 -5
- package/dist/{google-vertex-809af514.js → google-vertex-44xxtcvp.js} +6 -5
- package/dist/{handlers-aqcedbyb.js → handlers-kjdce1w5.js} +37 -32
- package/dist/{hook-ybvmrmhq.js → hook-czx13n12.js} +19 -15
- package/dist/{hook-7vkskkre.js → hook-r2t4bqfg.js} +18 -14
- package/dist/{http-2eqa8t24.js → http-3bbb19be.js} +900 -145
- package/dist/{index-f6cryxwe.js → index-4a5njnm1.js} +2 -59
- package/dist/{index-x71bvq0p.js → index-668me3f0.js} +35 -30
- package/dist/{index-c6zsv1bd.js → index-7aj368tw.js} +13 -12
- package/dist/{index-1yks3qcr.js → index-fg0dsp6c.js} +34 -29
- package/dist/{index-chgdkq36.js → index-kkv84jq9.js} +34 -29
- package/dist/{index-a3vn96n8.js → index-zg7vp46x.js} +198 -54
- package/dist/{keepalive-vtkf5n99.js → keepalive-yra8dy57.js} +13 -11
- package/dist/{lead-h3sp357x.js → lead-va0pad2c.js} +54 -49
- package/dist/llama-cpp-classify-tgj35k8d.js +335 -0
- package/dist/{maintenance-jzeqtk3q.js → maintenance-hqewtmyg.js} +14 -13
- package/dist/{mistral-conversations-zx0kn554.js → mistral-conversations-pc3ntnxt.js} +14 -17
- package/dist/{oauth-refresh-sweep-qp3dzmdp.js → oauth-refresh-sweep-7rdt1m9n.js} +12 -10
- package/dist/{onboard-tmsp0qbz.js → onboard-j6ms6d0x.js} +6 -5
- package/dist/{openai-codex-responses-4vjqzvjp.js → openai-codex-responses-bbancrr0.js} +21 -8
- package/dist/{openai-completions-9hjrqbw8.js → openai-completions-jpaj5g2b.js} +9 -12
- package/dist/{openai-responses-7b1pn0xt.js → openai-responses-200k1wx4.js} +23 -18
- package/dist/{opencode-adapter-x6x2da1z.js → opencode-adapter-89rabkw2.js} +8 -7
- package/dist/{openrouter-images-9f9ek4rw.js → openrouter-images-8yx3487g.js} +5 -7
- package/dist/{otel-impl-9mz73q65.js → otel-impl-a792rjz0.js} +1 -1
- package/dist/{pi-messages-txpjj39q.js → pi-messages-vxdt8v7j.js} +2 -1
- package/dist/{pi-mono-adapter-m6dvv0dz.js → pi-mono-adapter-g7qzvr3v.js} +295 -70
- package/dist/pricing-refresh-wx0tp7cb.js +39 -0
- package/dist/quickjs-r1pq2107.wasm +0 -0
- package/dist/{rbac-roles-c9wqz83x.js → rbac-roles-8tzawacv.js} +12 -10
- package/dist/{render-v2-gryrh9h8.js → render-v2-mm7zswb8.js} +12 -10
- package/dist/runtime-zyssgse0.js +24 -0
- package/dist/{setup-q9720bt6.js → setup-8y70ys6t.js} +6 -5
- package/dist/typesafe-system-one-2ef30pec.js +27 -0
- package/dist/{virtual-modules-3htpgn8x.js → virtual-modules-6nmk7h3n.js} +22 -13
- package/dist/{work-objects-b76x7deb.js → work-objects-fg6xkb0n.js} +37 -32
- package/dist/{worker-6vrxbv41.js → worker-wmwhxsph.js} +54 -49
- package/openapi.json +1314 -91
- package/package.json +12 -11
- package/src/be/db/agents.ts +20 -0
- package/src/be/db/api-keys.ts +70 -0
- package/src/be/db/tasks/human-free.ts +442 -0
- package/src/be/db/tasks/read.ts +56 -1
- package/src/be/db/tasks/write.ts +107 -11
- package/src/be/db.ts +274 -188
- package/src/be/harness-model-support.ts +182 -0
- package/src/be/human-free-drain.ts +67 -0
- package/src/be/memory/providers/sqlite-store.ts +51 -15
- package/src/be/migrations/182_task_human_free_flag.sql +63 -0
- package/src/be/migrations/183_human_free_reclassify_queue.sql +25 -0
- package/src/be/migrations/184_model_catalog.sql +120 -0
- package/src/be/migrations/185_api_key_auth_failures.sql +6 -0
- package/src/be/migrations/186_api_key_seat_mismatch.sql +8 -0
- package/src/be/model-catalog-store.ts +644 -0
- package/src/be/model-tier-keys.ts +46 -0
- package/src/be/model-tier-resolution.ts +534 -0
- package/src/be/model-validation.ts +188 -0
- package/src/be/models-catalog.ts +61 -7
- package/src/be/modelsdev-cache.json +82 -0
- package/src/be/modelsdev-cache.ts +2 -0
- package/src/be/pricing-refresh.ts +154 -12
- package/src/be/scripts/typecheck.ts +15 -0
- package/src/be/seed/runner.ts +18 -12
- package/src/be/seed/types.ts +1 -0
- package/src/be/seed-scripts/catalog/task-failure-audit.ts +61 -9
- package/src/be/swarm-config-guard.ts +8 -0
- package/src/cli.tsx +10 -0
- package/src/commands/claude-managed-setup.ts +3 -1
- package/src/commands/codex-login.ts +67 -0
- package/src/commands/credential-outcome-report.ts +191 -0
- package/src/commands/rate-limit-outcome.ts +34 -4
- package/src/commands/runner.ts +357 -186
- package/src/commands/seat-mismatch-report.ts +46 -0
- package/src/extensions/apply-task-create.ts +27 -1
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/heartbeat/heartbeat.ts +79 -17
- package/src/heartbeat/templates.ts +2 -2
- package/src/http/agents.ts +62 -1
- package/src/http/api-keys.ts +140 -2
- package/src/http/codex-oauth-keep-warm.ts +3 -5
- package/src/http/index.ts +8 -0
- package/src/http/memory.ts +12 -5
- package/src/http/models-catalog.ts +357 -8
- package/src/http/poll.ts +54 -3
- package/src/http/schedules.ts +51 -6
- package/src/http/script-runs.ts +12 -0
- package/src/http/session-data.ts +2 -5
- package/src/http/stats.ts +6 -8
- package/src/http/status.ts +15 -1
- package/src/http/tasks.ts +90 -7
- package/src/http/usage-cache.ts +56 -15
- package/src/http/workflows.ts +46 -8
- package/src/mcp-client/http-client.ts +5 -0
- package/src/memory/recall-query.ts +74 -0
- package/src/prompts/base-prompt.ts +15 -4
- package/src/prompts/session-templates.ts +23 -1
- package/src/providers/acp-adapter.ts +1 -0
- package/src/providers/claude-adapter.ts +14 -5
- package/src/providers/claude-managed-adapter.ts +1 -0
- package/src/providers/claude-managed-models.ts +47 -161
- package/src/providers/claude-sdk-session.ts +3 -1
- package/src/providers/codex-adapter.ts +14 -14
- package/src/providers/codex-models.ts +65 -198
- package/src/providers/devin-adapter.ts +1 -0
- package/src/providers/dsh-adapter.ts +2 -1
- package/src/providers/harness-version.ts +83 -7
- package/src/providers/opencode-adapter.ts +53 -1
- package/src/providers/pi-binary-root/src/extensions/codemode/worker.ts +11 -0
- package/src/providers/pi-codemode-runtime.ts +17 -0
- package/src/providers/pi-mono-adapter.ts +361 -83
- package/src/providers/pi-mono-extension.ts +16 -1
- package/src/providers/reasoning-effort.ts +44 -140
- package/src/providers/types.ts +8 -0
- package/src/rbac/legacy-policy.ts +43 -0
- package/src/rbac/permissions.ts +15 -0
- package/src/scripts-runtime/sdk-allowlist.ts +4 -0
- package/src/scripts-runtime/types/stdlib.d.ts +15 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
- package/src/server.ts +6 -0
- package/src/slack/assistant.ts +13 -0
- package/src/slack/message-text.ts +56 -2
- package/src/slack/render-v2.ts +87 -37
- package/src/slack/session-status.ts +541 -0
- package/src/slack/thread-buffer.ts +10 -2
- package/src/tasks/sibling-awareness.ts +3 -2
- package/src/telemetry.ts +5 -4
- package/src/templates.d.ts +6 -0
- package/src/tests/agents-list-model-display.test.ts +4 -6
- package/src/tests/api-key-auth-failure-route.test.ts +142 -0
- package/src/tests/api-key-tracking.test.ts +368 -1
- package/src/tests/base-prompt.test.ts +43 -2
- package/src/tests/claude-adapter.test.ts +68 -0
- package/src/tests/claude-managed-adapter.test.ts +12 -18
- package/src/tests/codex-adapter.test.ts +2 -1
- package/src/tests/codex-auth-failure.test.ts +52 -0
- package/src/tests/codex-gpt6-release.test.ts +66 -5
- package/src/tests/codex-login.test.ts +116 -0
- package/src/tests/context-window.test.ts +7 -5
- package/src/tests/credential-exhaustion-policy.test.ts +118 -3
- package/src/tests/credential-outcome-report.test.ts +171 -0
- package/src/tests/credential-status-api.test.ts +103 -2
- package/src/tests/db-extraction-contract.test.ts +1 -0
- package/src/tests/db-task-read-contract.test.ts +10 -1
- package/src/tests/db-task-write-contract.test.ts +535 -2
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dokploy-deploy.test.ts +315 -0
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/explicit-model-validation.test.ts +583 -0
- package/src/tests/extensions-pre-task.test.ts +73 -0
- package/src/tests/fetch-resolved-env.test.ts +46 -0
- package/src/tests/hang-watchdog-worker.ts +47 -0
- package/src/tests/hang-watchdog.test.ts +45 -0
- package/src/tests/hang-watchdog.ts +30 -0
- package/src/tests/harness-model-guard.test.ts +123 -0
- package/src/tests/harness-model-support.test.ts +374 -0
- package/src/tests/harness-version.test.ts +70 -3
- package/src/tests/heartbeat-checklist-config.test.ts +71 -0
- package/src/tests/heartbeat-checklist.test.ts +4 -2
- package/src/tests/heartbeat-orphan-resume.test.ts +48 -0
- package/src/tests/http-task-write-ownership.test.ts +172 -0
- package/src/tests/human-free-flag.test.ts +279 -0
- package/src/tests/human-free-oracle.ts +57 -0
- package/src/tests/human-free-reclassify.test.ts +669 -0
- package/src/tests/memory-fts-populate.test.ts +139 -0
- package/src/tests/memory-http-recall-gating.test.ts +125 -1
- package/src/tests/migration-046-budgets.test.ts +3 -3
- package/src/tests/model-catalog-migration.test.ts +134 -0
- package/src/tests/model-catalog-table.test.ts +249 -0
- package/src/tests/model-catalog-write-access.test.ts +387 -0
- package/src/tests/model-rate-limit-windows.test.ts +19 -0
- package/src/tests/model-tier-resolution.test.ts +611 -0
- package/src/tests/models-catalog.test.ts +1 -1
- package/src/tests/multi-runtime-enabled-stats.test.ts +65 -1
- package/src/tests/opencode-adapter.test.ts +157 -2
- package/src/tests/package-publish.test.ts +137 -36
- package/src/tests/pi-codemode.test.ts +246 -0
- package/src/tests/pi-mono-adapter.test.ts +3 -0
- package/src/tests/pi-native-mcp.test.ts +193 -0
- package/src/tests/pi-tool-exposure.test.ts +374 -0
- package/src/tests/preload.ts +3 -0
- package/src/tests/pricing-routes.test.ts +2 -2
- package/src/tests/prompt-template-session.test.ts +5 -3
- package/src/tests/rate-limit-event.test.ts +65 -0
- package/src/tests/rate-limit-outcome.test.ts +90 -0
- package/src/tests/rbac-engine.test.ts +77 -3
- package/src/tests/reasoning-effort.test.ts +109 -0
- package/src/tests/refresh-modelsdev-carryforward.test.ts +5 -5
- package/src/tests/runner-key-completion-outcome.test.ts +112 -0
- package/src/tests/runner-key-outcome-late-reset.test.ts +224 -0
- package/src/tests/runner-registration-retry.test.ts +149 -0
- package/src/tests/runtime-model-catalog.test.ts +86 -0
- package/src/tests/script-connections.test.ts +9 -0
- package/src/tests/seat-mismatch-report.test.ts +85 -0
- package/src/tests/seed-scripts.test.ts +138 -0
- package/src/tests/seed.test.ts +25 -0
- package/src/tests/session-costs.test.ts +14 -11
- package/src/tests/slack-message-text.test.ts +101 -0
- package/src/tests/slack-render-v2.test.ts +96 -0
- package/src/tests/slack-session-status.test.ts +626 -0
- package/src/tests/slack-thread-buffer-context.test.ts +93 -0
- package/src/tests/status.test.ts +29 -0
- package/src/tests/steering-promotion.test.ts +51 -0
- package/src/tests/store-progress-ownership.test.ts +136 -0
- package/src/tests/subscription-plans.test.ts +28 -0
- package/src/tests/task-cascade-fail.test.ts +148 -2
- package/src/tests/task-citations.test.ts +3 -2
- package/src/tests/tool-annotations.test.ts +1 -1
- package/src/tests/usage-cache.test.ts +166 -0
- package/src/tests/workflow-agent-task.test.ts +30 -0
- package/src/tests/workflow-executors.test.ts +5 -2
- package/src/tests/workflow-system-one-decision-review.test.ts +1021 -0
- package/src/tests/workflow-system-one-decision-save-warnings.test.ts +365 -0
- package/src/tests/workflow-system-one-decision.test.ts +2063 -0
- package/src/tests/workflow-triggers-v2.test.ts +320 -0
- package/src/tools/model-catalog/index.ts +137 -0
- package/src/tools/schedules/create-schedule.ts +17 -2
- package/src/tools/schedules/patch-schedule.ts +31 -1
- package/src/tools/schedules/update-schedule.ts +31 -1
- package/src/tools/send-task.ts +18 -1
- package/src/tools/store-progress.ts +49 -4
- package/src/tools/task-action.ts +14 -1
- package/src/tools/tool-config.ts +3 -1
- package/src/tools/workflows/create-workflow.ts +17 -4
- package/src/tools/workflows/patch-workflow-node.ts +17 -7
- package/src/tools/workflows/patch-workflow.ts +9 -2
- package/src/tools/workflows/update-workflow.ts +17 -4
- package/src/types.ts +41 -1
- package/src/utils/codex-auth-failure.ts +34 -0
- package/src/utils/context-window.ts +47 -53
- package/src/utils/credentials.ts +72 -30
- package/src/utils/error-tracker.ts +80 -0
- package/src/utils/harness-cli-version.ts +115 -0
- package/src/utils/harness-model-error.ts +33 -0
- package/src/utils/model-rate-limit-windows.ts +12 -0
- package/src/utils/runtime-model-catalog.ts +152 -0
- package/src/utils/spawn-model-guard.ts +43 -0
- package/src/utils/subscription-plans.ts +22 -0
- package/src/workflows/approval-resolution.ts +39 -0
- package/src/workflows/definition.ts +7 -0
- package/src/workflows/engine.ts +69 -1
- package/src/workflows/executors/agent-task.ts +16 -6
- package/src/workflows/executors/base.ts +53 -0
- package/src/workflows/executors/human-in-the-loop.ts +8 -8
- package/src/workflows/executors/index.ts +1 -0
- package/src/workflows/executors/registry.ts +2 -0
- package/src/workflows/executors/system-one-decision.ts +1232 -0
- package/src/workflows/executors/system-one-providers.ts +301 -0
- package/src/workflows/executors/workflow-llm.ts +13 -1
- package/src/workflows/model-validation.ts +45 -0
- package/src/workflows/patch-definition.ts +5 -0
- package/src/workflows/readiness.ts +86 -0
- package/src/workflows/recovery.ts +12 -12
- package/src/workflows/resume.ts +23 -9
- package/src/workflows/triggers.ts +85 -0
- package/templates/schedules/daily-blocker-digest/content.md +4 -5
- package/templates/skills/agent-browser/SKILL.md +6 -5
- package/templates/skills/agent-browser/content.md +6 -5
- package/templates/skills/heartbeat-runbook/config.json +1 -1
- package/templates/skills/heartbeat-runbook/content.md +2 -2
- package/templates/skills/swarm-scripts/SKILL.md +1 -1
- package/templates/skills/swarm-scripts/content.md +1 -1
- package/templates/skills/workflow-iterate/content.md +82 -1
- package/templates/workflows/claude-code-changelog-watch/content.md +2 -0
- package/templates/workflows/pr-review-status-sweep/content.md +2 -0
- package/dist/boot-seeds-s3q01xj3.js +0 -26
- package/dist/claude-sdk-session-t442qz6f.js +0 -39108
- package/dist/cli-0xjkj1j7.js +0 -61
- package/dist/cli-20cj37vt.js +0 -335561
- package/dist/cli-2djtr51b.js +0 -48
- package/dist/cli-65hjmev5.js +0 -1141
- package/dist/cli-aw1jwp1r.js +0 -14075
- package/dist/cli-h967nb6r.js +0 -6603
- package/dist/cli-vapyk8sw.js +0 -20
- package/dist/cli-ws6rqycm.js +0 -247
- package/dist/pricing-refresh-v1cbr9te.js +0 -27
- package/src/providers/modelsdev-reasoning.json +0 -6453
- package/dist/{index-f24115ge.js → index-2wsdsnmm.js} +3 -3
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { unlink } from "node:fs/promises";
|
|
3
|
+
import { closeDb, createAgent, getDb, getDbClient, initDb } from "../be/db";
|
|
4
|
+
import {
|
|
5
|
+
FTS_DELETE_EXTRA_SQL,
|
|
6
|
+
FTS_MISSING_IDS_SQL,
|
|
7
|
+
SqliteMemoryStore,
|
|
8
|
+
} from "../be/memory/providers/sqlite-store";
|
|
9
|
+
|
|
10
|
+
const TEST_DB_PATH = "./test-memory-fts-populate.sqlite";
|
|
11
|
+
const agentId = "aaaa0000-0000-4000-8000-000000000171";
|
|
12
|
+
|
|
13
|
+
// The pre-fix backfill. Kept here as the positive control for the plan check:
|
|
14
|
+
// if SQLite ever stops reporting it as CORRELATED, the assertion below would
|
|
15
|
+
// pass vacuously, so the control has to fail first.
|
|
16
|
+
const QUADRATIC_BACKFILL_SQL = `INSERT INTO memory_fts(memory_id, name, content)
|
|
17
|
+
SELECT m.id, m.name, m.content
|
|
18
|
+
FROM agent_memory m
|
|
19
|
+
WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.memory_id = m.id)`;
|
|
20
|
+
|
|
21
|
+
// EXPLAIN goes through a prepared statement that is finalized right away: the
|
|
22
|
+
// client's cached `db.query()` statement for an EXPLAIN stays "in progress" and
|
|
23
|
+
// wedges the connection's next COMMIT.
|
|
24
|
+
function planOf(sql: string): string[] {
|
|
25
|
+
const stmt = getDb().prepare(`EXPLAIN QUERY PLAN ${sql}`);
|
|
26
|
+
try {
|
|
27
|
+
return (stmt.all() as { detail: string }[]).map((row) => row.detail);
|
|
28
|
+
} finally {
|
|
29
|
+
stmt.finalize();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function count(sql: string, params: string[] = []): Promise<number> {
|
|
34
|
+
return (await getDbClient().get<{ count: number }>(sql, params))?.count ?? -1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe("memory_fts boot backfill", () => {
|
|
38
|
+
let store: SqliteMemoryStore;
|
|
39
|
+
|
|
40
|
+
beforeAll(async () => {
|
|
41
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
42
|
+
try {
|
|
43
|
+
await unlink(TEST_DB_PATH + suffix);
|
|
44
|
+
} catch {}
|
|
45
|
+
}
|
|
46
|
+
initDb(TEST_DB_PATH);
|
|
47
|
+
await createAgent({ id: agentId, name: "FTS Populate Agent", isLead: false, status: "idle" });
|
|
48
|
+
store = new SqliteMemoryStore();
|
|
49
|
+
await store.whenFtsPopulated();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
afterAll(async () => {
|
|
53
|
+
closeDb();
|
|
54
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
55
|
+
try {
|
|
56
|
+
await unlink(TEST_DB_PATH + suffix);
|
|
57
|
+
} catch {}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("diff queries are not correlated against the UNINDEXED memory_id", async () => {
|
|
62
|
+
// Positive control: the old anti-join scans memory_fts once per memory.
|
|
63
|
+
expect(planOf(QUADRATIC_BACKFILL_SQL).join(" | ")).toContain("CORRELATED");
|
|
64
|
+
|
|
65
|
+
for (const sql of [FTS_MISSING_IDS_SQL, FTS_DELETE_EXTRA_SQL]) {
|
|
66
|
+
const plan = planOf(sql).join(" | ");
|
|
67
|
+
expect(plan).not.toContain("CORRELATED");
|
|
68
|
+
// Exactly one pass over memory_fts per statement.
|
|
69
|
+
expect(plan.match(/SCAN memory_fts/g)?.length).toBe(1);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("a new store backfills missing rows across batches and drops orphans", async () => {
|
|
74
|
+
const total = 1050; // crosses two 500-row batch boundaries
|
|
75
|
+
const seed = await store.store({
|
|
76
|
+
agentId,
|
|
77
|
+
scope: "agent",
|
|
78
|
+
name: "fts backfill 0",
|
|
79
|
+
content: "backfill-token-0",
|
|
80
|
+
source: "manual",
|
|
81
|
+
});
|
|
82
|
+
// Clone the seed row in one statement: 1,050 store() calls outrun the
|
|
83
|
+
// default test timeout, and the backfill only reads id/name/content.
|
|
84
|
+
const columns = (
|
|
85
|
+
await getDbClient().query<{ name: string }>("PRAGMA table_info(agent_memory)")
|
|
86
|
+
).map((col) => col.name);
|
|
87
|
+
const projection = columns
|
|
88
|
+
.map((col) => {
|
|
89
|
+
if (col === "id") return "'clone-' || n.i";
|
|
90
|
+
if (col === "name") return "'fts backfill ' || n.i";
|
|
91
|
+
if (col === "content") return "'backfill-token-' || n.i";
|
|
92
|
+
if (col === "key") return "'fts-backfill-' || n.i";
|
|
93
|
+
return `s."${col}"`;
|
|
94
|
+
})
|
|
95
|
+
.join(", ");
|
|
96
|
+
await getDbClient().run(
|
|
97
|
+
`WITH RECURSIVE n(i) AS (SELECT 1 UNION ALL SELECT i + 1 FROM n WHERE i < ?)
|
|
98
|
+
INSERT INTO agent_memory(${columns.map((col) => `"${col}"`).join(", ")})
|
|
99
|
+
SELECT ${projection} FROM n, agent_memory s WHERE s.id = ?`,
|
|
100
|
+
[total - 1, seed.id],
|
|
101
|
+
);
|
|
102
|
+
const ids = [seed.id];
|
|
103
|
+
expect(await count("SELECT COUNT(*) AS count FROM agent_memory")).toBe(total);
|
|
104
|
+
// Only the seed went through store(), so only it is indexed so far.
|
|
105
|
+
expect(await count("SELECT COUNT(*) AS count FROM memory_fts")).toBe(1);
|
|
106
|
+
await getDbClient().run(
|
|
107
|
+
"INSERT INTO memory_fts(memory_id, name, content) SELECT id, name, content FROM agent_memory WHERE id != ?",
|
|
108
|
+
[seed.id],
|
|
109
|
+
);
|
|
110
|
+
expect(await count("SELECT COUNT(*) AS count FROM memory_fts")).toBe(total);
|
|
111
|
+
|
|
112
|
+
// Simulate an index that lost most of its rows and gained an orphan.
|
|
113
|
+
await getDbClient().run("DELETE FROM memory_fts WHERE memory_id != ?", [ids[0] as string]);
|
|
114
|
+
await getDbClient().run(
|
|
115
|
+
"INSERT INTO memory_fts(memory_id, name, content) VALUES ('orphan-id', 'orphan', 'orphan')",
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const rebuilt = new SqliteMemoryStore();
|
|
119
|
+
await rebuilt.whenFtsPopulated();
|
|
120
|
+
|
|
121
|
+
expect(await count("SELECT COUNT(*) AS count FROM memory_fts")).toBe(total);
|
|
122
|
+
expect(await count("SELECT COUNT(DISTINCT memory_id) AS count FROM memory_fts")).toBe(total);
|
|
123
|
+
expect(
|
|
124
|
+
await count("SELECT COUNT(*) AS count FROM memory_fts WHERE memory_id = 'orphan-id'"),
|
|
125
|
+
).toBe(0);
|
|
126
|
+
expect(
|
|
127
|
+
await count("SELECT COUNT(*) AS count FROM memory_fts WHERE memory_fts MATCH ?", [
|
|
128
|
+
'"backfill-token-1049"',
|
|
129
|
+
]),
|
|
130
|
+
).toBe(1);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("a steady-state boot inserts nothing", async () => {
|
|
134
|
+
const before = await count("SELECT COUNT(*) AS count FROM memory_fts");
|
|
135
|
+
const again = new SqliteMemoryStore();
|
|
136
|
+
await again.whenFtsPopulated();
|
|
137
|
+
expect(await count("SELECT COUNT(*) AS count FROM memory_fts")).toBe(before);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -5,6 +5,9 @@ import type { IncomingMessage, ServerResponse } from "node:http";
|
|
|
5
5
|
import { Readable } from "node:stream";
|
|
6
6
|
import { closeDb, createAgent, getDbClient, initDb } from "../be/db";
|
|
7
7
|
import * as realMemoryModule from "../be/memory";
|
|
8
|
+
import { buildRecallQuery } from "../memory/recall-query";
|
|
9
|
+
import { getTemplateDefinition } from "../prompts/registry";
|
|
10
|
+
import "../tools/templates";
|
|
8
11
|
import { SIMILARITY_THRESHOLD } from "../prompts/memories";
|
|
9
12
|
import type { AgentMemory } from "../types";
|
|
10
13
|
|
|
@@ -72,11 +75,17 @@ function candidate(memoryFixture: AgentMemory, similarity: number) {
|
|
|
72
75
|
};
|
|
73
76
|
}
|
|
74
77
|
|
|
78
|
+
let embeddedQuery = "";
|
|
79
|
+
let searchedQuery = "";
|
|
80
|
+
|
|
75
81
|
mock.module("../be/memory", () => ({
|
|
76
82
|
getEmbeddingProvider: () => ({
|
|
77
83
|
name: "test-embedding",
|
|
78
84
|
dimensions: 3,
|
|
79
|
-
embed: async () =>
|
|
85
|
+
embed: async (query: string) => {
|
|
86
|
+
embeddedQuery = query;
|
|
87
|
+
return new Float32Array([1, 0, 0]);
|
|
88
|
+
},
|
|
80
89
|
embedBatch: async (texts: string[]) => texts.map(() => new Float32Array([1, 0, 0])),
|
|
81
90
|
}),
|
|
82
91
|
getMemoryStore: () => ({
|
|
@@ -104,6 +113,7 @@ mock.module("../be/memory", () => ({
|
|
|
104
113
|
_agentId: string,
|
|
105
114
|
options: import("../be/memory/types").MemorySearchOptions,
|
|
106
115
|
) => {
|
|
116
|
+
searchedQuery = options.queryText ?? "";
|
|
107
117
|
if (options.queryText === "document recall") {
|
|
108
118
|
return [candidate(memory, 0.95), candidate(memoryChunk, 0.9)];
|
|
109
119
|
}
|
|
@@ -324,3 +334,117 @@ describe("memory HTTP recall capture gating", () => {
|
|
|
324
334
|
expect(await countRetrievals()).toBe(0);
|
|
325
335
|
});
|
|
326
336
|
});
|
|
337
|
+
|
|
338
|
+
function workerWrapper(event: "completed" | "failed", task = "", output = ""): string {
|
|
339
|
+
return getTemplateDefinition(`task.worker.${event}`)!.defaultBody.replace(
|
|
340
|
+
/{{(\w+)}}/g,
|
|
341
|
+
(_, key) =>
|
|
342
|
+
({ task_desc: task, output_summary: output, failure_reason: output })[key as "task_desc"] ??
|
|
343
|
+
"",
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
describe("pre-task recall query", () => {
|
|
348
|
+
for (const event of ["completed", "failed"] as const) {
|
|
349
|
+
test(`${event} wrapper retains only task and output`, () => {
|
|
350
|
+
expect(buildRecallQuery(workerWrapper(event, "Fix memory recall", "Fixed the query"))).toBe(
|
|
351
|
+
"Fix memory recall\n\nFixed the query",
|
|
352
|
+
);
|
|
353
|
+
expect(buildRecallQuery(workerWrapper(event))).toBe("");
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
test("preserves output headings and embedded thread context once", () => {
|
|
358
|
+
const output =
|
|
359
|
+
"Result\n\nIMPORTANT: actual output heading\n<thread_context>Context</thread_context>";
|
|
360
|
+
expect(buildRecallQuery(workerWrapper("completed", "Task", output))).toBe(`Task\n\n${output}`);
|
|
361
|
+
expect(
|
|
362
|
+
buildRecallQuery(
|
|
363
|
+
workerWrapper(
|
|
364
|
+
"failed",
|
|
365
|
+
"Task",
|
|
366
|
+
"Reason\n\nDecide whether to reassign, retry, or handle the failure. Actual result",
|
|
367
|
+
),
|
|
368
|
+
),
|
|
369
|
+
).toContain("Actual result");
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test("creator instructions do not become recall content", () => {
|
|
373
|
+
for (const event of ["completed", "failed"] as const) {
|
|
374
|
+
const wrapper = workerWrapper(event).replace(
|
|
375
|
+
event === "completed" ? "Output:\n" : "Failure reason: ",
|
|
376
|
+
`${event === "completed" ? "Output:\n" : "Failure reason: "}\nAdditional instructions from the task creator:\nReview quickly\n`,
|
|
377
|
+
);
|
|
378
|
+
expect(buildRecallQuery(wrapper)).toBe("");
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
test("removes sibling context and preserves thread context", () => {
|
|
383
|
+
const thread = "<thread_context>Earlier user intent</thread_context>";
|
|
384
|
+
const query = `<sibling_tasks_in_progress>Unrelated task</sibling_tasks_in_progress>\n\n${workerWrapper("completed", "Fix recall", "Done")}\n\n${thread}`;
|
|
385
|
+
expect(buildRecallQuery(query)).toBe(`Fix recall\n\nDone\n\n${thread}`);
|
|
386
|
+
expect(buildRecallQuery(`User request\n${thread}`)).toBe(`User request\n${thread}`);
|
|
387
|
+
expect(buildRecallQuery("Worker task completed — partial text")).toBe(
|
|
388
|
+
"Worker task completed — partial text",
|
|
389
|
+
);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
test("bounds long ASCII and multilingual queries without splitting code points", () => {
|
|
393
|
+
expect(buildRecallQuery("a".repeat(40000))).toBe("a".repeat(8191));
|
|
394
|
+
const query = buildRecallQuery("你好🙂مرحبا".repeat(10000));
|
|
395
|
+
expect(Buffer.byteLength(query)).toBeLessThanOrEqual(8191);
|
|
396
|
+
expect(query).not.toContain("�");
|
|
397
|
+
expect(Buffer.from(query).toString("utf8")).toBe(query);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
test("bounds malformed near-wrappers before parsing", () => {
|
|
401
|
+
const malformed = workerWrapper("completed", "Task", '"\n\nOutput:\n'.repeat(200000)).replace(
|
|
402
|
+
'" for full details.',
|
|
403
|
+
'" missing suffix.',
|
|
404
|
+
);
|
|
405
|
+
const bounded = malformed.slice(0, 65536);
|
|
406
|
+
expect(buildRecallQuery(malformed)).toBe(buildRecallQuery(bounded));
|
|
407
|
+
expect(Buffer.byteLength(buildRecallQuery(malformed))).toBeLessThanOrEqual(8191);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test("long valid wrappers preserve content and truncate the embedding query", () => {
|
|
411
|
+
expect(buildRecallQuery(workerWrapper("completed", "Task", "a".repeat(20000)))).toBe(
|
|
412
|
+
`Task\n\n${"a".repeat(8185)}`,
|
|
413
|
+
);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
test("HTTP prompt recall uses content for embedding and text search only", async () => {
|
|
417
|
+
const original = workerWrapper("completed", "Fix recall", "Done");
|
|
418
|
+
await callMemoryRoute(
|
|
419
|
+
"POST",
|
|
420
|
+
"/api/memory/search",
|
|
421
|
+
["api", "memory", "search"],
|
|
422
|
+
{ query: original },
|
|
423
|
+
{ "x-memory-consumption": "prompt" },
|
|
424
|
+
);
|
|
425
|
+
expect(embeddedQuery).toBe("Fix recall\n\nDone");
|
|
426
|
+
expect(searchedQuery).toBe(embeddedQuery);
|
|
427
|
+
await callMemoryRoute("POST", "/api/memory/search", ["api", "memory", "search"], {
|
|
428
|
+
query: original,
|
|
429
|
+
});
|
|
430
|
+
expect(embeddedQuery).toBe(original);
|
|
431
|
+
expect(searchedQuery).toBe(original);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
test("blank wrapper skips search and retrieval records", async () => {
|
|
435
|
+
embeddedQuery = "untouched";
|
|
436
|
+
searchedQuery = "untouched";
|
|
437
|
+
const before = await countRetrievals();
|
|
438
|
+
const response = await callMemoryRoute(
|
|
439
|
+
"POST",
|
|
440
|
+
"/api/memory/search",
|
|
441
|
+
["api", "memory", "search"],
|
|
442
|
+
{ query: workerWrapper("completed"), intent: "pre-task memory recall" },
|
|
443
|
+
{ "x-memory-consumption": "prompt", "x-source-task-id": sourceTaskId },
|
|
444
|
+
);
|
|
445
|
+
expect(response.body.results).toEqual([]);
|
|
446
|
+
expect(embeddedQuery).toBe("untouched");
|
|
447
|
+
expect(searchedQuery).toBe("untouched");
|
|
448
|
+
expect(await countRetrievals()).toBe(before);
|
|
449
|
+
});
|
|
450
|
+
});
|
|
@@ -3,7 +3,7 @@ import { unlink } from "node:fs/promises";
|
|
|
3
3
|
import { closeDb, getDbClient, initDb } from "../be/db";
|
|
4
4
|
import { loadModelsDevCache } from "../be/modelsdev-cache";
|
|
5
5
|
import { seedPricingFromModelsDev } from "../be/seed-pricing";
|
|
6
|
-
import {
|
|
6
|
+
import { codexModelPricingTable } from "../providers/codex-models";
|
|
7
7
|
|
|
8
8
|
const TEST_DB_PATH = "./test-migration-046.sqlite";
|
|
9
9
|
|
|
@@ -133,7 +133,7 @@ describe("migration 046 — budgets and pricing", () => {
|
|
|
133
133
|
});
|
|
134
134
|
|
|
135
135
|
test("pricing seed includes every known Codex model/token class at effective_from=0", async () => {
|
|
136
|
-
const minimumCodexRows = Object.keys(
|
|
136
|
+
const minimumCodexRows = Object.keys(codexModelPricingTable()).length * 3;
|
|
137
137
|
|
|
138
138
|
const seedRows = await getDbClient().get<CountRow>(
|
|
139
139
|
"SELECT COUNT(*) as cnt FROM pricing WHERE provider = 'codex' AND effective_from = 0",
|
|
@@ -151,7 +151,7 @@ describe("migration 046 — budgets and pricing", () => {
|
|
|
151
151
|
// time comes from newer effective_from rows (runtime refresh); the
|
|
152
152
|
// worker-local table is advisory and agentswarm.cost.drift.usd is the
|
|
153
153
|
// watchdog. This test pins seed COVERAGE, not rate sync.
|
|
154
|
-
for (const model of Object.keys(
|
|
154
|
+
for (const model of Object.keys(codexModelPricingTable())) {
|
|
155
155
|
for (const tokenClass of ["input", "cached_input", "output"] as const) {
|
|
156
156
|
const row = await client.get<PricingRow>(
|
|
157
157
|
"SELECT * FROM pricing WHERE provider = 'codex' AND model = ? AND token_class = ? AND effective_from = ?",
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
3
|
+
import { runMigrations } from "../be/migrations/runner";
|
|
4
|
+
|
|
5
|
+
const DB_PATH = "./test-model-catalog-migration.sqlite";
|
|
6
|
+
|
|
7
|
+
async function removeDb(): Promise<void> {
|
|
8
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
9
|
+
try {
|
|
10
|
+
await Bun.file(DB_PATH + suffix).delete();
|
|
11
|
+
} catch (error) {
|
|
12
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
afterEach(removeDb);
|
|
18
|
+
|
|
19
|
+
function columnNames(db: Database, table: string): string[] {
|
|
20
|
+
return db
|
|
21
|
+
.query<{ name: string }, []>(`PRAGMA table_info(${table})`)
|
|
22
|
+
.all()
|
|
23
|
+
.map((column) => column.name);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function tableExists(db: Database, table: string): boolean {
|
|
27
|
+
return (
|
|
28
|
+
db
|
|
29
|
+
.query<{ name: string }, [string]>(
|
|
30
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name = ?",
|
|
31
|
+
)
|
|
32
|
+
.get(table) !== null
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe("migration 184 model catalog, tier resolution and harness support", () => {
|
|
37
|
+
test("upgrades a pre-184 database in place and keeps existing agent and task rows", async () => {
|
|
38
|
+
await removeDb();
|
|
39
|
+
const db = new Database(DB_PATH, { create: true });
|
|
40
|
+
try {
|
|
41
|
+
runMigrations(db);
|
|
42
|
+
|
|
43
|
+
// Roll the database back to the state before migration 184.
|
|
44
|
+
for (const table of [
|
|
45
|
+
"model_catalog",
|
|
46
|
+
"model_catalog_overlay",
|
|
47
|
+
"model_catalog_meta",
|
|
48
|
+
"model_alias_resolutions",
|
|
49
|
+
"harness_model_support",
|
|
50
|
+
]) {
|
|
51
|
+
db.run(`DROP TABLE ${table}`);
|
|
52
|
+
}
|
|
53
|
+
for (const column of ["resolvedModel", "modelSource", "modelAlias"]) {
|
|
54
|
+
db.run(`ALTER TABLE agent_tasks DROP COLUMN ${column}`);
|
|
55
|
+
}
|
|
56
|
+
for (const column of ["modelTierOverrides", "harnessCliVersion"]) {
|
|
57
|
+
db.run(`ALTER TABLE agents DROP COLUMN ${column}`);
|
|
58
|
+
}
|
|
59
|
+
db.run("DELETE FROM _migrations WHERE version = 184");
|
|
60
|
+
|
|
61
|
+
db.run(
|
|
62
|
+
`INSERT INTO agents (id, name, status, createdAt, lastUpdatedAt)
|
|
63
|
+
VALUES ('agent-1', 'worker', 'idle', '2026-09-01', '2026-09-01')`,
|
|
64
|
+
);
|
|
65
|
+
db.run(
|
|
66
|
+
`INSERT INTO agent_tasks (id, task, status, createdAt, lastUpdatedAt)
|
|
67
|
+
VALUES ('task-1', 'existing task', 'pending', '2026-09-01', '2026-09-01')`,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
runMigrations(db);
|
|
71
|
+
|
|
72
|
+
expect(
|
|
73
|
+
db
|
|
74
|
+
.query<{ version: number }, []>("SELECT version FROM _migrations WHERE version = 184")
|
|
75
|
+
.get(),
|
|
76
|
+
).not.toBeNull();
|
|
77
|
+
for (const table of [
|
|
78
|
+
"model_catalog",
|
|
79
|
+
"model_catalog_overlay",
|
|
80
|
+
"model_catalog_meta",
|
|
81
|
+
"model_alias_resolutions",
|
|
82
|
+
"harness_model_support",
|
|
83
|
+
]) {
|
|
84
|
+
expect(tableExists(db, table)).toBe(true);
|
|
85
|
+
}
|
|
86
|
+
expect(columnNames(db, "agent_tasks")).toEqual(
|
|
87
|
+
expect.arrayContaining(["resolvedModel", "modelSource", "modelAlias"]),
|
|
88
|
+
);
|
|
89
|
+
expect(columnNames(db, "agents")).toEqual(
|
|
90
|
+
expect.arrayContaining(["modelTierOverrides", "harnessCliVersion"]),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const task = db
|
|
94
|
+
.query<Record<string, unknown>, []>(
|
|
95
|
+
"SELECT task, resolvedModel, modelSource, modelAlias FROM agent_tasks WHERE id = 'task-1'",
|
|
96
|
+
)
|
|
97
|
+
.get();
|
|
98
|
+
expect(task).toEqual({
|
|
99
|
+
task: "existing task",
|
|
100
|
+
resolvedModel: null,
|
|
101
|
+
modelSource: null,
|
|
102
|
+
modelAlias: null,
|
|
103
|
+
});
|
|
104
|
+
const agent = db
|
|
105
|
+
.query<Record<string, unknown>, []>(
|
|
106
|
+
"SELECT name, modelTierOverrides, harnessCliVersion FROM agents WHERE id = 'agent-1'",
|
|
107
|
+
)
|
|
108
|
+
.get();
|
|
109
|
+
expect(agent).toEqual({ name: "worker", modelTierOverrides: null, harnessCliVersion: null });
|
|
110
|
+
} finally {
|
|
111
|
+
db.close();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("harness_model_support only accepts ok, unsupported and unknown", async () => {
|
|
116
|
+
await removeDb();
|
|
117
|
+
const db = new Database(DB_PATH, { create: true });
|
|
118
|
+
try {
|
|
119
|
+
runMigrations(db);
|
|
120
|
+
const insert = (status: string) =>
|
|
121
|
+
db.run(
|
|
122
|
+
`INSERT INTO harness_model_support (harness, cliVersion, modelId, status, checkedAt)
|
|
123
|
+
VALUES ('claude', '2.1.0', ?, ?, 1)`,
|
|
124
|
+
[`m-${status}`, status],
|
|
125
|
+
);
|
|
126
|
+
expect(() => insert("ok")).not.toThrow();
|
|
127
|
+
expect(() => insert("unsupported")).not.toThrow();
|
|
128
|
+
expect(() => insert("unknown")).not.toThrow();
|
|
129
|
+
expect(() => insert("maybe")).toThrow(/CHECK/);
|
|
130
|
+
} finally {
|
|
131
|
+
db.close();
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|