@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
|
@@ -1,139 +1,73 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Codex
|
|
3
|
-
* and https://developers.openai.com/api/docs/deprecations as of 2026-09-23.
|
|
2
|
+
* Codex model facts, read from the model catalog (model-catalog phase 4).
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* There is no hand-maintained Codex allowlist, context-window table or price
|
|
5
|
+
* table any more: every lookup reads the runtime catalog
|
|
6
|
+
* (`src/utils/runtime-model-catalog.ts` — the API's `model_catalog` + overlay
|
|
7
|
+
* rows, pulled over HTTP; the vendored models.dev snapshot offline). A new
|
|
8
|
+
* OpenAI model is therefore listed, windowed and priced as soon as it lands
|
|
9
|
+
* in `model_catalog`, with no code change and no redeploy.
|
|
8
10
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* Which OpenAI SKUs count as Codex-drivable is a rule, not a list:
|
|
12
|
+
* `isHarnessCatalogModel("codex", ...)` in `@desplega/model-catalog`.
|
|
13
|
+
*
|
|
14
|
+
* Kept separate from the adapter so the onboarding UI and model selector can
|
|
15
|
+
* import it without pulling in the SDK.
|
|
12
16
|
*/
|
|
13
|
-
import
|
|
17
|
+
import { harnessModelIds } from "@desplega/model-catalog";
|
|
18
|
+
import { DEFAULT_MODEL_TIER_MAP } from "../types";
|
|
19
|
+
import { runtimeCatalogModel, runtimeCatalogSection } from "../utils/runtime-model-catalog";
|
|
20
|
+
|
|
21
|
+
/** Codex models from the catalog, newest first. Drives selectors and pricing tests. */
|
|
22
|
+
export function listCodexModels(): string[] {
|
|
23
|
+
return harnessModelIds("codex", runtimeCatalogSection("openai"));
|
|
24
|
+
}
|
|
14
25
|
|
|
15
26
|
/**
|
|
16
|
-
*
|
|
17
|
-
* the
|
|
18
|
-
*
|
|
19
|
-
* SDK, so new OpenAI models work without a code change.
|
|
27
|
+
* The baseline default when neither MODEL_OVERRIDE nor task.model is set:
|
|
28
|
+
* the codex `regular` tier default (operators move it with
|
|
29
|
+
* `MODEL_TIER_CODEX_REGULAR`, resolved server-side at claim time).
|
|
20
30
|
*/
|
|
21
|
-
export const
|
|
22
|
-
"gpt-6-astra", // most capable model for complex reasoning, coding, and agentic work
|
|
23
|
-
"gpt-6-sol", // complex coding and agentic workflows
|
|
24
|
-
"gpt-6-luna", // focused, high-volume tasks
|
|
25
|
-
"gpt-5.6-sol", // frontier GPT-5.6 tier for complex reasoning/coding
|
|
26
|
-
"gpt-5.6-terra", // balanced GPT-5.6 tier
|
|
27
|
-
"gpt-5.6-luna", // fast/cheap GPT-5.6 tier for high-volume workloads
|
|
28
|
-
"gpt-5.5", // previous frontier coding/professional-work model
|
|
29
|
-
"gpt-5.4", // previous mainline reasoning model w/ frontier coding
|
|
30
|
-
"gpt-5.4-mini", // faster/cheaper
|
|
31
|
-
"gpt-5.3-codex", // coding-specialized legacy model
|
|
32
|
-
"gpt-5.2-codex", // legacy — scheduled for retirement, see openai deprecations page
|
|
33
|
-
] as const;
|
|
34
|
-
|
|
35
|
-
export type CodexModel = (typeof CODEX_MODELS)[number];
|
|
36
|
-
|
|
37
|
-
/** The baseline default when neither MODEL_OVERRIDE nor task.model is set. */
|
|
38
|
-
export const CODEX_DEFAULT_MODEL: CodexModel = "gpt-5.6-terra";
|
|
31
|
+
export const CODEX_DEFAULT_MODEL: string = DEFAULT_MODEL_TIER_MAP.codex.regular;
|
|
39
32
|
|
|
40
33
|
/**
|
|
41
|
-
*
|
|
42
|
-
* to
|
|
43
|
-
*
|
|
34
|
+
* Claude-style shortnames (that flow through MODEL_OVERRIDE / task.model)
|
|
35
|
+
* map to the codex tier with the same intent, so a task authored for Claude
|
|
36
|
+
* works unchanged when pointed at a Codex worker.
|
|
44
37
|
*/
|
|
45
|
-
const
|
|
46
|
-
fable: "
|
|
47
|
-
opus: "
|
|
48
|
-
sonnet: "
|
|
49
|
-
haiku: "
|
|
50
|
-
};
|
|
38
|
+
const CLAUDE_SHORTNAME_TIER = {
|
|
39
|
+
fable: "ultra",
|
|
40
|
+
opus: "smart",
|
|
41
|
+
sonnet: "regular",
|
|
42
|
+
haiku: "smol",
|
|
43
|
+
} as const;
|
|
51
44
|
|
|
52
45
|
/**
|
|
53
46
|
* Resolve a model string (shortname or full Codex model id) into the literal
|
|
54
47
|
* id we hand to the Codex SDK. Behavior:
|
|
55
48
|
* - empty/undefined → `CODEX_DEFAULT_MODEL`
|
|
56
|
-
* - claude shortname (opus/sonnet/haiku) →
|
|
49
|
+
* - claude shortname (opus/sonnet/haiku/fable) → codex tier default
|
|
57
50
|
* - anything else → passthrough (lowercased), so new OpenAI models work
|
|
58
51
|
* without a code change. The SDK is the source of truth for validity.
|
|
59
52
|
*/
|
|
60
53
|
export function resolveCodexModel(modelStr: string | undefined): string {
|
|
61
54
|
if (!modelStr) return CODEX_DEFAULT_MODEL;
|
|
62
55
|
const normalized = modelStr.toLowerCase();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
interface ModelsDevOpenAiModel {
|
|
67
|
-
limit?: {
|
|
68
|
-
context?: number;
|
|
69
|
-
};
|
|
70
|
-
cost?: {
|
|
71
|
-
input?: number;
|
|
72
|
-
cache_read?: number;
|
|
73
|
-
output?: number;
|
|
74
|
-
};
|
|
56
|
+
const tier = CLAUDE_SHORTNAME_TIER[normalized as keyof typeof CLAUDE_SHORTNAME_TIER];
|
|
57
|
+
return tier ? DEFAULT_MODEL_TIER_MAP.codex[tier] : normalized;
|
|
75
58
|
}
|
|
76
59
|
|
|
77
|
-
const
|
|
78
|
-
(
|
|
79
|
-
modelsDevCache as {
|
|
80
|
-
openai?: {
|
|
81
|
-
models?: Record<string, ModelsDevOpenAiModel>;
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
).openai?.models ?? {};
|
|
85
|
-
|
|
86
|
-
const FALLBACK_CODEX_MODEL_CONTEXT_WINDOWS: Record<CodexModel, number> = {
|
|
87
|
-
"gpt-6-astra": 1_050_000,
|
|
88
|
-
"gpt-6-sol": 1_050_000,
|
|
89
|
-
"gpt-6-luna": 1_050_000,
|
|
90
|
-
"gpt-5.6-sol": 1_050_000,
|
|
91
|
-
"gpt-5.6-terra": 1_050_000,
|
|
92
|
-
"gpt-5.6-luna": 1_050_000,
|
|
93
|
-
"gpt-5.5": 1_050_000,
|
|
94
|
-
"gpt-5.4": 1_050_000,
|
|
95
|
-
"gpt-5.4-mini": 400_000,
|
|
96
|
-
"gpt-5.3-codex": 400_000,
|
|
97
|
-
"gpt-5.2-codex": 200_000,
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Per-model approximate context window (tokens). The Codex SDK does not
|
|
102
|
-
* expose these at runtime, so we read the vendored models.dev cache used by
|
|
103
|
-
* the pricing seeder and fall back only for legacy/incomplete cache entries.
|
|
104
|
-
* The values are used by the `context_usage` percent calculation inside
|
|
105
|
-
* `CodexSession`.
|
|
106
|
-
*/
|
|
107
|
-
export const CODEX_MODEL_CONTEXT_WINDOWS: Record<CodexModel, number> = Object.fromEntries(
|
|
108
|
-
CODEX_MODELS.map((model) => [
|
|
109
|
-
model,
|
|
110
|
-
MODELSDEV_OPENAI_MODELS[model]?.limit?.context ?? FALLBACK_CODEX_MODEL_CONTEXT_WINDOWS[model],
|
|
111
|
-
]),
|
|
112
|
-
) as Record<CodexModel, number>;
|
|
60
|
+
const UNKNOWN_CONTEXT_WINDOW = 200_000;
|
|
113
61
|
|
|
114
62
|
/**
|
|
115
|
-
*
|
|
116
|
-
* (passthrough strings) get
|
|
117
|
-
* even on a model id we haven't catalogued yet.
|
|
63
|
+
* Context window in tokens for a Codex model, from the catalog. Unknown
|
|
64
|
+
* models (passthrough strings) get 200k — keeps `context_usage` finite.
|
|
118
65
|
*/
|
|
119
66
|
export function getCodexContextWindow(model: string): number {
|
|
120
|
-
|
|
67
|
+
const context = runtimeCatalogModel("openai", model)?.limit?.context;
|
|
68
|
+
return typeof context === "number" && context > 0 ? context : UNKNOWN_CONTEXT_WINDOW;
|
|
121
69
|
}
|
|
122
70
|
|
|
123
|
-
/**
|
|
124
|
-
* Per-model pricing in USD per million tokens, sourced from the vendored
|
|
125
|
-
* models.dev cache (`src/be/modelsdev-cache.json`). The fallback below mirrors
|
|
126
|
-
* that snapshot for known models and covers legacy models that models.dev no
|
|
127
|
-
* longer lists.
|
|
128
|
-
*
|
|
129
|
-
* The Codex SDK does NOT report dollar cost in `Usage`, so this map is what
|
|
130
|
-
* powers `totalCostUsd` on the `result` event. Refresh models.dev whenever
|
|
131
|
-
* OpenAI changes pricing or adds new models.
|
|
132
|
-
*
|
|
133
|
-
* `gpt-5.2-codex` is not on the current pricing page (legacy / retired); it
|
|
134
|
-
* inherits the `gpt-5.3-codex` rate as a best-effort fallback so old tasks
|
|
135
|
-
* pinned to it still report a non-zero cost instead of silently $0.
|
|
136
|
-
*/
|
|
137
71
|
export interface CodexModelPricing {
|
|
138
72
|
/** USD per million input tokens (uncached). */
|
|
139
73
|
inputPerMillion: number;
|
|
@@ -144,99 +78,33 @@ export interface CodexModelPricing {
|
|
|
144
78
|
}
|
|
145
79
|
|
|
146
80
|
/**
|
|
147
|
-
*
|
|
148
|
-
* the
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* table unreachable when both agree.
|
|
81
|
+
* Per-model pricing from the catalog (USD per million tokens). Advisory only:
|
|
82
|
+
* the canonical price is the API server's recompute against the pricing
|
|
83
|
+
* table (`agentswarm.cost.drift.usd` watches the divergence). A catalog row
|
|
84
|
+
* without a cache-read price bills cached input at 10% of input, OpenAI's
|
|
85
|
+
* standard discount.
|
|
153
86
|
*/
|
|
154
|
-
export
|
|
155
|
-
"
|
|
156
|
-
|
|
157
|
-
cachedInputPerMillion: 1.0,
|
|
158
|
-
outputPerMillion: 50.0,
|
|
159
|
-
},
|
|
160
|
-
"gpt-6-sol": {
|
|
161
|
-
inputPerMillion: 2.0,
|
|
162
|
-
cachedInputPerMillion: 0.2,
|
|
163
|
-
outputPerMillion: 10.0,
|
|
164
|
-
},
|
|
165
|
-
"gpt-6-luna": {
|
|
166
|
-
inputPerMillion: 0.1,
|
|
167
|
-
cachedInputPerMillion: 0.01,
|
|
168
|
-
outputPerMillion: 0.5,
|
|
169
|
-
},
|
|
170
|
-
"gpt-5.6-sol": {
|
|
171
|
-
inputPerMillion: 4.0,
|
|
172
|
-
cachedInputPerMillion: 0.4,
|
|
173
|
-
outputPerMillion: 20.0,
|
|
174
|
-
},
|
|
175
|
-
"gpt-5.6-terra": {
|
|
176
|
-
inputPerMillion: 2.0,
|
|
177
|
-
cachedInputPerMillion: 0.2,
|
|
178
|
-
outputPerMillion: 12.0,
|
|
179
|
-
},
|
|
180
|
-
"gpt-5.6-luna": {
|
|
181
|
-
inputPerMillion: 0.2,
|
|
182
|
-
cachedInputPerMillion: 0.02,
|
|
183
|
-
outputPerMillion: 1.2,
|
|
184
|
-
},
|
|
185
|
-
"gpt-5.5": {
|
|
186
|
-
inputPerMillion: 5.0,
|
|
187
|
-
cachedInputPerMillion: 0.5,
|
|
188
|
-
outputPerMillion: 30.0,
|
|
189
|
-
},
|
|
190
|
-
"gpt-5.4": {
|
|
191
|
-
inputPerMillion: 2.5,
|
|
192
|
-
cachedInputPerMillion: 0.25,
|
|
193
|
-
outputPerMillion: 15.0,
|
|
194
|
-
},
|
|
195
|
-
"gpt-5.4-mini": {
|
|
196
|
-
inputPerMillion: 0.75,
|
|
197
|
-
cachedInputPerMillion: 0.075,
|
|
198
|
-
outputPerMillion: 4.5,
|
|
199
|
-
},
|
|
200
|
-
"gpt-5.3-codex": {
|
|
201
|
-
inputPerMillion: 1.75,
|
|
202
|
-
cachedInputPerMillion: 0.175,
|
|
203
|
-
outputPerMillion: 14.0,
|
|
204
|
-
},
|
|
205
|
-
// Legacy — not on the current pricing page; inherit from gpt-5.3-codex.
|
|
206
|
-
"gpt-5.2-codex": {
|
|
207
|
-
inputPerMillion: 1.75,
|
|
208
|
-
cachedInputPerMillion: 0.175,
|
|
209
|
-
outputPerMillion: 14.0,
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
function getModelsDevCodexPricing(model: CodexModel): CodexModelPricing | undefined {
|
|
214
|
-
const cost = MODELSDEV_OPENAI_MODELS[model]?.cost;
|
|
215
|
-
if (
|
|
216
|
-
typeof cost?.input !== "number" ||
|
|
217
|
-
typeof cost.cache_read !== "number" ||
|
|
218
|
-
typeof cost.output !== "number"
|
|
219
|
-
) {
|
|
220
|
-
return undefined;
|
|
221
|
-
}
|
|
87
|
+
export function getCodexModelPricing(model: string): CodexModelPricing | undefined {
|
|
88
|
+
const cost = runtimeCatalogModel("openai", model)?.cost;
|
|
89
|
+
if (typeof cost?.input !== "number" || typeof cost.output !== "number") return undefined;
|
|
222
90
|
return {
|
|
223
91
|
inputPerMillion: cost.input,
|
|
224
|
-
cachedInputPerMillion: cost.cache_read,
|
|
92
|
+
cachedInputPerMillion: typeof cost.cache_read === "number" ? cost.cache_read : cost.input / 10,
|
|
225
93
|
outputPerMillion: cost.output,
|
|
226
94
|
};
|
|
227
95
|
}
|
|
228
96
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
)
|
|
97
|
+
/** Priced Codex models, keyed by id (every `listCodexModels()` entry the catalog prices). */
|
|
98
|
+
export function codexModelPricingTable(): Record<string, CodexModelPricing> {
|
|
99
|
+
const table: Record<string, CodexModelPricing> = {};
|
|
100
|
+
for (const model of listCodexModels()) {
|
|
101
|
+
const pricing = getCodexModelPricing(model);
|
|
102
|
+
if (pricing) table[model] = pricing;
|
|
103
|
+
}
|
|
104
|
+
return table;
|
|
105
|
+
}
|
|
235
106
|
|
|
236
|
-
/**
|
|
237
|
-
* Phase 6 — one-warning-per-process tracking so unknown models log once
|
|
238
|
-
* instead of spamming the worker log on every turn.
|
|
239
|
-
*/
|
|
107
|
+
/** One warning per model per process, so unpriced models don't spam the log. */
|
|
240
108
|
const _warnedUnknownCodexModels = new Set<string>();
|
|
241
109
|
|
|
242
110
|
/**
|
|
@@ -245,10 +113,9 @@ const _warnedUnknownCodexModels = new Set<string>();
|
|
|
245
113
|
* + uncached), so we subtract `cached_input_tokens` before billing the
|
|
246
114
|
* uncached portion at the full rate.
|
|
247
115
|
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
* such rows `costSource='unpriced'`, which surfaces as a yellow UI badge.
|
|
116
|
+
* Returns 0 for models the catalog does not price AND logs a one-time
|
|
117
|
+
* warning. The server-side recompute tags such rows `costSource='unpriced'`,
|
|
118
|
+
* which surfaces as a yellow UI badge.
|
|
252
119
|
*/
|
|
253
120
|
export function computeCodexCostUsd(
|
|
254
121
|
model: string,
|
|
@@ -256,13 +123,13 @@ export function computeCodexCostUsd(
|
|
|
256
123
|
cachedInputTokens: number,
|
|
257
124
|
outputTokens: number,
|
|
258
125
|
): number {
|
|
259
|
-
const pricing =
|
|
126
|
+
const pricing = getCodexModelPricing(model);
|
|
260
127
|
if (!pricing) {
|
|
261
128
|
if (!_warnedUnknownCodexModels.has(model)) {
|
|
262
129
|
_warnedUnknownCodexModels.add(model);
|
|
263
130
|
console.warn(
|
|
264
131
|
`[codex] unpriced model ${JSON.stringify(model)} — adapter cost will report $0; ` +
|
|
265
|
-
"
|
|
132
|
+
"add it to the model catalog (refresh or overlay row). Server-side recompute will tag costSource='unpriced' if the pricing table has no rows.",
|
|
266
133
|
);
|
|
267
134
|
}
|
|
268
135
|
return 0;
|
|
@@ -21,7 +21,7 @@ import type {
|
|
|
21
21
|
} from "./types";
|
|
22
22
|
|
|
23
23
|
// npm's `latest` is older and lacks the JSON/stdin contract used here.
|
|
24
|
-
export const DSH_PACKAGE = "@deepseek-ai/dsh@0.
|
|
24
|
+
export const DSH_PACKAGE = "@deepseek-ai/dsh@0.2.0-rc.2";
|
|
25
25
|
|
|
26
26
|
export function checkDshCredentials(env: Record<string, string | undefined>): CredStatus {
|
|
27
27
|
return env.DEEPSEEK_API_KEY?.trim() || env.OPENROUTER_API_KEY?.trim()
|
|
@@ -163,6 +163,7 @@ export class DshAdapter implements ProviderAdapter {
|
|
|
163
163
|
readonly name = "dsh";
|
|
164
164
|
readonly traits: ProviderTraits = {
|
|
165
165
|
hasMcp: false,
|
|
166
|
+
hasToolSearch: false,
|
|
166
167
|
nativeSkillDiscovery: false,
|
|
167
168
|
hasLocalEnvironment: true,
|
|
168
169
|
steerModes: [],
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
3
|
+
import { delimiter, dirname, join } from "node:path";
|
|
2
4
|
|
|
3
|
-
type PackageJson = { version?: unknown };
|
|
5
|
+
type PackageJson = { name?: unknown; version?: unknown };
|
|
4
6
|
|
|
5
7
|
type ReadPkgVersionOptions = {
|
|
6
8
|
requirePackageJson?: (specifier: string) => PackageJson;
|
|
7
9
|
spawn?: typeof spawnSync;
|
|
10
|
+
/** Version of the package that owns `command` on PATH, or undefined. No process is spawned. */
|
|
11
|
+
readInstalledVersion?: (command: string, packageName: string) => string | undefined;
|
|
8
12
|
};
|
|
9
13
|
|
|
10
14
|
const cliVersionCommands: Record<string, { command: string; args: string[] }> = {
|
|
@@ -12,6 +16,9 @@ const cliVersionCommands: Record<string, { command: string; args: string[] }> =
|
|
|
12
16
|
"@opencode-ai/sdk": { command: "opencode", args: ["--version"] },
|
|
13
17
|
};
|
|
14
18
|
|
|
19
|
+
// The CLI does not change under a running process, so spawn it at most once.
|
|
20
|
+
const spawnedCliVersions = new Map<string, string | undefined>();
|
|
21
|
+
|
|
15
22
|
function normalizeVersion(value: unknown): string | undefined {
|
|
16
23
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
17
24
|
}
|
|
@@ -20,19 +27,87 @@ function parseCliVersion(output: string): string | undefined {
|
|
|
20
27
|
return output.match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?/)?.[0];
|
|
21
28
|
}
|
|
22
29
|
|
|
23
|
-
function
|
|
24
|
-
const
|
|
25
|
-
|
|
30
|
+
function findOnPath(command: string): string | undefined {
|
|
31
|
+
for (const dir of (process.env.PATH ?? "").split(delimiter)) {
|
|
32
|
+
if (!dir) continue;
|
|
33
|
+
const candidate = join(dir, command);
|
|
34
|
+
if (existsSync(candidate)) return candidate;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Reads the version of the npm package a CLI shim belongs to by walking up from the shim's real
|
|
41
|
+
* path to the package.json that names `packageName`. `pi --version` prints exactly that file's
|
|
42
|
+
* `version`, so this gives the same answer without starting a process.
|
|
43
|
+
*/
|
|
44
|
+
export function readInstalledCliPackageVersion(
|
|
45
|
+
command: string,
|
|
46
|
+
packageName: string,
|
|
47
|
+
): string | undefined {
|
|
48
|
+
const binPath = findOnPath(command);
|
|
49
|
+
if (!binPath) return undefined;
|
|
50
|
+
|
|
51
|
+
let dir: string;
|
|
52
|
+
try {
|
|
53
|
+
dir = dirname(realpathSync(binPath));
|
|
54
|
+
} catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (;;) {
|
|
59
|
+
try {
|
|
60
|
+
const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")) as PackageJson;
|
|
61
|
+
if (pkg.name === packageName) return normalizeVersion(pkg.version);
|
|
62
|
+
} catch {
|
|
63
|
+
// No package.json at this level, or not valid JSON: keep walking up.
|
|
64
|
+
}
|
|
65
|
+
const parent = dirname(dir);
|
|
66
|
+
if (parent === dir) return undefined;
|
|
67
|
+
dir = parent;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
26
70
|
|
|
71
|
+
function spawnCliVersion(
|
|
72
|
+
packageName: string,
|
|
73
|
+
command: { command: string; args: string[] },
|
|
74
|
+
spawn: typeof spawnSync,
|
|
75
|
+
): string | undefined {
|
|
76
|
+
// Only the real spawnSync is cached; an injected one (tests) must run every call.
|
|
77
|
+
const cacheable = spawn === spawnSync;
|
|
78
|
+
if (cacheable && spawnedCliVersions.has(packageName)) return spawnedCliVersions.get(packageName);
|
|
79
|
+
|
|
80
|
+
let version: string | undefined;
|
|
27
81
|
try {
|
|
28
82
|
const result = spawn(command.command, command.args, {
|
|
29
83
|
encoding: "utf8",
|
|
30
84
|
stdio: ["ignore", "pipe", "pipe"],
|
|
85
|
+
timeout: 5_000,
|
|
86
|
+
killSignal: "SIGKILL",
|
|
31
87
|
});
|
|
32
|
-
|
|
88
|
+
version = parseCliVersion(`${result.stdout ?? ""}\n${result.stderr ?? ""}`);
|
|
33
89
|
} catch {
|
|
34
|
-
|
|
90
|
+
version = undefined;
|
|
35
91
|
}
|
|
92
|
+
if (cacheable) spawnedCliVersions.set(packageName, version);
|
|
93
|
+
return version;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function readCliVersion(
|
|
97
|
+
packageName: string,
|
|
98
|
+
spawn: typeof spawnSync,
|
|
99
|
+
readInstalledVersion: NonNullable<ReadPkgVersionOptions["readInstalledVersion"]>,
|
|
100
|
+
): string | undefined {
|
|
101
|
+
const command = cliVersionCommands[packageName];
|
|
102
|
+
if (!command) return undefined;
|
|
103
|
+
|
|
104
|
+
// Prefer reading the installed package: a synchronous spawn blocks this thread for the whole
|
|
105
|
+
// child run, and on Bun 1.4.0 a `pi --version` spawnSync intermittently never returns (the child
|
|
106
|
+
// exits and stays a zombie while the parent spins), which wedged CI test workers for 20 minutes.
|
|
107
|
+
const installed = readInstalledVersion(command.command, packageName);
|
|
108
|
+
if (installed) return installed;
|
|
109
|
+
|
|
110
|
+
return spawnCliVersion(packageName, command, spawn);
|
|
36
111
|
}
|
|
37
112
|
|
|
38
113
|
export function readPkgVersion(
|
|
@@ -40,9 +115,10 @@ export function readPkgVersion(
|
|
|
40
115
|
{
|
|
41
116
|
requirePackageJson = (specifier) => require(specifier) as PackageJson,
|
|
42
117
|
spawn = spawnSync,
|
|
118
|
+
readInstalledVersion = readInstalledCliPackageVersion,
|
|
43
119
|
}: ReadPkgVersionOptions = {},
|
|
44
120
|
): string | undefined {
|
|
45
|
-
const cliVersion = readCliVersion(packageName, spawn);
|
|
121
|
+
const cliVersion = readCliVersion(packageName, spawn, readInstalledVersion);
|
|
46
122
|
if (cliVersion) return cliVersion;
|
|
47
123
|
|
|
48
124
|
try {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { existsSync, mkdirSync } from "node:fs";
|
|
12
12
|
import { join } from "node:path";
|
|
13
|
-
import type { AssistantMessage, Config, Event as OpencodeEvent } from "@opencode-ai/sdk";
|
|
13
|
+
import type { AssistantMessage, Config, Event as OpencodeEvent, TextPart } from "@opencode-ai/sdk";
|
|
14
14
|
import { createOpencode } from "@opencode-ai/sdk";
|
|
15
15
|
import {
|
|
16
16
|
CONTEXT_FORMULA,
|
|
@@ -301,6 +301,13 @@ export class OpencodeSession implements ProviderSession {
|
|
|
301
301
|
// Keep the latest snapshot per message so those replays do not double-count.
|
|
302
302
|
private finalizedMessages = new Map<string, FinalizedMessageUsage>();
|
|
303
303
|
private missingMessageIdCounter = 0;
|
|
304
|
+
// Assistant text for the runner's final-message capture (`trackAssistantText`),
|
|
305
|
+
// which is how codex tasks with an outputSchema get their final message
|
|
306
|
+
// validated. Text parts stream in around the message's own updates, so buffer
|
|
307
|
+
// the latest snapshot per part and emit per message once its role is known.
|
|
308
|
+
private textParts = new Map<string, Map<string, string>>();
|
|
309
|
+
private assistantMessageIds = new Set<string>();
|
|
310
|
+
private emittedText = new Map<string, string>();
|
|
304
311
|
private startedAt = Date.now();
|
|
305
312
|
private model: string;
|
|
306
313
|
private agentId: string;
|
|
@@ -462,6 +469,7 @@ export class OpencodeSession implements ProviderSession {
|
|
|
462
469
|
case "message.updated": {
|
|
463
470
|
const msg = ev.properties.info;
|
|
464
471
|
if (!isAssistantMessage(msg) || msg.sessionID !== this._sessionId) break;
|
|
472
|
+
if (typeof msg.id === "string") this.assistantMessageIds.add(msg.id);
|
|
465
473
|
// Phase 9 fix: opencode fires `message.updated` repeatedly during a single
|
|
466
474
|
// assistant turn (streaming text deltas, tool transitions, etc.) and only
|
|
467
475
|
// populates `tokens`/`cost` on the FINAL update once `time.completed` is
|
|
@@ -487,6 +495,7 @@ export class OpencodeSession implements ProviderSession {
|
|
|
487
495
|
cacheReadTokens: msg.tokens?.cache?.read ?? 0,
|
|
488
496
|
cacheWriteTokens: msg.tokens?.cache?.write ?? 0,
|
|
489
497
|
});
|
|
498
|
+
this.emitAssistantText(msg.id);
|
|
490
499
|
if (!this.model && msg.modelID) this.model = msg.modelID;
|
|
491
500
|
|
|
492
501
|
// Emit context_usage so the runner can POST /api/tasks/:id/context
|
|
@@ -521,6 +530,12 @@ export class OpencodeSession implements ProviderSession {
|
|
|
521
530
|
}
|
|
522
531
|
|
|
523
532
|
case "message.part.updated": {
|
|
533
|
+
// Text parts are matched to this session by their own `sessionID`
|
|
534
|
+
// (checked in `recordTextPart`), not by the tool branch's check below.
|
|
535
|
+
if (ev.properties.part?.type === "text") {
|
|
536
|
+
this.recordTextPart(ev.properties.part);
|
|
537
|
+
break;
|
|
538
|
+
}
|
|
524
539
|
// Bridge opencode's part.state lifecycle to swarm's tool_start/tool_end
|
|
525
540
|
// so the dashboard's Activity timeline mirrors what other providers
|
|
526
541
|
// emit. We fire tool_start the first time we see a tool part (any
|
|
@@ -612,6 +627,36 @@ export class OpencodeSession implements ProviderSession {
|
|
|
612
627
|
}
|
|
613
628
|
}
|
|
614
629
|
|
|
630
|
+
/** Keep the latest snapshot of a text part (`part.text` is cumulative). */
|
|
631
|
+
private recordTextPart(part: TextPart): void {
|
|
632
|
+
// Synthetic and ignored parts are opencode-injected context, not model output.
|
|
633
|
+
if (part.sessionID !== this._sessionId || part.synthetic || part.ignored) return;
|
|
634
|
+
if (typeof part.messageID !== "string" || typeof part.id !== "string") return;
|
|
635
|
+
let parts = this.textParts.get(part.messageID);
|
|
636
|
+
if (!parts) {
|
|
637
|
+
parts = new Map();
|
|
638
|
+
this.textParts.set(part.messageID, parts);
|
|
639
|
+
}
|
|
640
|
+
parts.set(part.id, part.text ?? "");
|
|
641
|
+
// A part can land after its message was finalized; re-emit the fuller text.
|
|
642
|
+
if (this.finalizedMessages.has(part.messageID)) this.emitAssistantText(part.messageID);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Emit an assistant message's text as a normal `message` event. Only assistant
|
|
647
|
+
* messages qualify, and unchanged text is not re-emitted (opencode replays
|
|
648
|
+
* finalized snapshots). The runner keeps the last non-empty one.
|
|
649
|
+
*/
|
|
650
|
+
private emitAssistantText(messageId: string): void {
|
|
651
|
+
if (!this.assistantMessageIds.has(messageId)) return;
|
|
652
|
+
const parts = this.textParts.get(messageId);
|
|
653
|
+
if (!parts) return;
|
|
654
|
+
const text = [...parts.values()].join("").trim();
|
|
655
|
+
if (!text || this.emittedText.get(messageId) === text) return;
|
|
656
|
+
this.emittedText.set(messageId, text);
|
|
657
|
+
this.emit({ type: "message", role: "assistant", content: text, messageId });
|
|
658
|
+
}
|
|
659
|
+
|
|
615
660
|
private emitError(message: string): void {
|
|
616
661
|
const errorEvent: ProviderEvent = { type: "error", message };
|
|
617
662
|
for (const l of this.listeners) l(errorEvent);
|
|
@@ -719,6 +764,7 @@ export class OpencodeAdapter implements ProviderAdapter {
|
|
|
719
764
|
|
|
720
765
|
readonly traits: ProviderTraits = {
|
|
721
766
|
hasMcp: true,
|
|
767
|
+
hasToolSearch: false,
|
|
722
768
|
// Same inline-resolver pattern as codex (`resolveSlashSkillPrompt`) — no
|
|
723
769
|
// ambient skill awareness, so the system prompt enumerates them.
|
|
724
770
|
nativeSkillDiscovery: false,
|
|
@@ -760,6 +806,12 @@ export class OpencodeAdapter implements ProviderAdapter {
|
|
|
760
806
|
headers: {
|
|
761
807
|
Authorization: `Bearer ${config.apiKey}`,
|
|
762
808
|
"X-Agent-ID": config.agentId,
|
|
809
|
+
// Per-task identity, same as claude/codex. Without it `store-progress`
|
|
810
|
+
// has no default task, so the model must hand-type a UUID and can
|
|
811
|
+
// copy a sibling's or parent's id from the prompt. The config file
|
|
812
|
+
// and `opencode serve` are already per task, so this is not shared.
|
|
813
|
+
"X-Source-Task-Id": taskId,
|
|
814
|
+
...(config.contextKey ? { "X-Context-Key": config.contextKey } : {}),
|
|
763
815
|
...(runtimeInstanceId ? { "X-Runtime-Instance-ID": runtimeInstanceId } : {}),
|
|
764
816
|
},
|
|
765
817
|
},
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codemode sandbox worker for the compiled agent-swarm binary.
|
|
3
|
+
*
|
|
4
|
+
* In a Bun binary, pi's `getCodemodeWorkerUrl()` loads the worker from
|
|
5
|
+
* `./src/extensions/codemode/worker.js` next to the executable. The build
|
|
6
|
+
* passes this file as an extra entrypoint with
|
|
7
|
+
* `--root ./src/providers/pi-binary-root`, which embeds it at that path.
|
|
8
|
+
* Keep the Dockerfile.worker compile line and both package.json
|
|
9
|
+
* build:binary scripts in sync.
|
|
10
|
+
*/
|
|
11
|
+
import "@earendil-works/pi-codemode/worker";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Point pi's codemode at the QuickJS wasm that `bun build --compile` embeds.
|
|
3
|
+
*
|
|
4
|
+
* pi resolves the wasm with `createRequire(import.meta.url).resolve(...)`
|
|
5
|
+
* unless an embedded path was set, and that resolve fails inside a compiled
|
|
6
|
+
* binary's `$bunfs`. pi's own Bun binary sets the path in its entry
|
|
7
|
+
* (dist/bun/runtime-setup.js); our binary has a different entry, so this
|
|
8
|
+
* module does the same. Outside a binary, the import is the file on disk.
|
|
9
|
+
*
|
|
10
|
+
* `setEmbeddedQuickJSWasmPath` is not in the package `exports` map, so the
|
|
11
|
+
* import goes through the file path. It is the same module instance pi's
|
|
12
|
+
* codemode reads, and tsc fails if pi moves or drops it.
|
|
13
|
+
*/
|
|
14
|
+
import quickjsWasmPath from "quickjs-wasi/quickjs.wasm" with { type: "file" };
|
|
15
|
+
import { setEmbeddedQuickJSWasmPath } from "../../node_modules/@earendil-works/pi-coding-agent/dist/config.js";
|
|
16
|
+
|
|
17
|
+
setEmbeddedQuickJSWasmPath(quickjsWasmPath);
|