@desplega.ai/agent-swarm 1.158.0 → 1.159.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.
Files changed (272) hide show
  1. package/dist/{acp-adapter-xaq4n6pc.js → acp-adapter-qhch0n2v.js} +1 -1
  2. package/dist/{actions-p9hz5yat.js → actions-dtsh1mfb.js} +33 -29
  3. package/dist/{anthropic-messages-51pz26qe.js → anthropic-messages-f2h06k64.js} +8 -3
  4. package/dist/{app-g26wdcz6.js → app-y1b9srva.js} +10 -9
  5. package/dist/{assistant-wydfqkb3.js → assistant-31hwy5xj.js} +34 -30
  6. package/dist/{azure-openai-responses-8gksqtmz.js → azure-openai-responses-0k1mfax5.js} +12 -13
  7. package/dist/{boot-reembed-se8zmdcp.js → boot-reembed-48d2qpkt.js} +11 -11
  8. package/dist/{boot-reembed-g5ckg9yb.js → boot-reembed-w0bryhkr.js} +12 -12
  9. package/dist/{boot-scrub-logs-wfxqan61.js → boot-scrub-logs-t65wbrn7.js} +9 -8
  10. package/dist/{boot-seeds-s3q01xj3.js → boot-seeds-h7c32hvm.js} +12 -11
  11. package/dist/{claude-adapter-tv2x4f36.js → claude-adapter-1t6611ne.js} +26 -21
  12. package/dist/{claude-managed-adapter-41b2s7fd.js → claude-managed-adapter-werp659j.js} +4 -2
  13. package/dist/{claude-managed-setup-60g8aazx.js → claude-managed-setup-y6rdgbc1.js} +11 -2
  14. package/dist/claude-sdk-session-zhkyk8yw.js +29319 -0
  15. package/dist/{cli-vj6h9kc2.js → cli-0m7wct0d.js} +59 -1
  16. package/dist/{cli-wscdvcqz.js → cli-0n2e4x49.js} +1 -1
  17. package/dist/cli-0xqde53b.js +176 -0
  18. package/dist/{cli-xberxa1r.js → cli-10ym38qc.js} +2 -2
  19. package/dist/{cli-5b6b62tz.js → cli-13hw4z91.js} +1 -1
  20. package/dist/{cli-rqz8qbw7.js → cli-20035trh.js} +50 -18
  21. package/dist/{cli-k0g1sjzm.js → cli-31nkw3g3.js} +3 -3
  22. package/dist/cli-3gvrr8vj.js +1422 -0
  23. package/dist/{cli-c07r9a2m.js → cli-48527fpw.js} +9 -8
  24. package/dist/{cli-24k806sc.js → cli-4aj25szq.js} +2 -2
  25. package/dist/{cli-7gtvvpbh.js → cli-4tvgz99m.js} +7 -7
  26. package/dist/cli-503ya656.js +455 -0
  27. package/dist/{cli-cw9zck8j.js → cli-5f2hq128.js} +8 -4
  28. package/dist/{cli-s8eet254.js → cli-68bmme5p.js} +11078 -27833
  29. package/dist/{cli-ftfvggzx.js → cli-79aq9cgb.js} +794 -563
  30. package/dist/cli-7cxw8b60.js +14910 -0
  31. package/dist/cli-7kyk9jr3.js +22 -0
  32. package/dist/cli-7zttzetj.js +324 -0
  33. package/dist/{cli-y95wp3tg.js → cli-96qd5psa.js} +1 -1
  34. package/dist/{cli-g8djp6qe.js → cli-9yg65c1j.js} +22 -0
  35. package/dist/{cli-3gmcwfyx.js → cli-ardpzhjm.js} +5 -5
  36. package/dist/{cli-7s3syk22.js → cli-b6thtzac.js} +5 -5
  37. package/dist/{cli-00w2c66p.js → cli-bgv70kym.js} +13 -2
  38. package/dist/{cli-j55n64b6.js → cli-bv0a38v9.js} +163 -44
  39. package/dist/cli-ca2w7zv7.js +115 -0
  40. package/dist/cli-cpvsaqsw.js +333 -0
  41. package/dist/cli-cygyqj3b.js +754 -0
  42. package/dist/{cli-x24pshtq.js → cli-dvjpkkjd.js} +6 -6
  43. package/dist/{cli-5d10vd2m.js → cli-e0ndxhtk.js} +4 -4
  44. package/dist/{cli-4198qc9v.js → cli-e4xnc0qp.js} +15 -3
  45. package/dist/{cli-rjehvrts.js → cli-eg7cdg68.js} +8 -8
  46. package/dist/cli-ejpygnqz.js +3815 -0
  47. package/dist/{cli-fgqxwrpv.js → cli-fjtp3463.js} +1631 -127
  48. package/dist/{cli-zt1227k1.js → cli-fkqhbg8g.js} +5 -3
  49. package/dist/{cli-47m6dkd3.js → cli-g9df2m37.js} +409 -168
  50. package/dist/cli-gzyh0j0g.js +8455 -0
  51. package/dist/cli-hgqfttfc.js +183 -0
  52. package/dist/cli-hj65wsts.js +17755 -0
  53. package/dist/cli-j9z8mfx3.js +476 -0
  54. package/dist/{cli-aehm1rbq.js → cli-kc3dp84d.js} +1135 -61
  55. package/dist/{cli-h38x0qhg.js → cli-kdnehe0t.js} +4 -3
  56. package/dist/{cli-20cj37vt.js → cli-m4excttz.js} +136 -2216
  57. package/dist/{cli-8qmme6vd.js → cli-mg24hkt4.js} +2 -2
  58. package/dist/{cli-xhaeg2nc.js → cli-mzkqpxee.js} +1 -1
  59. package/dist/{cli-q67y4wzm.js → cli-phsaj4xq.js} +24 -2
  60. package/dist/{cli-pw9rj5t9.js → cli-pqetb83f.js} +1 -176
  61. package/dist/{cli-rj19hc34.js → cli-qjxy52w7.js} +1 -1
  62. package/dist/{cli-53sz8gkz.js → cli-qv4jv8bx.js} +1 -1
  63. package/dist/cli-qvnnx4ct.js +1051 -0
  64. package/dist/cli-rb9m6rpe.js +4980 -0
  65. package/dist/{cli-tt9k8r35.js → cli-rfezr056.js} +476 -909
  66. package/dist/{cli-ggm92wcn.js → cli-rgjprct3.js} +1 -0
  67. package/dist/{cli-9httdpyq.js → cli-rrqmqr1s.js} +1 -1
  68. package/dist/cli-rykfmgwg.js +102 -0
  69. package/dist/{cli-eetrvv91.js → cli-t3p77qk1.js} +1 -1
  70. package/dist/{cli-68w09sjw.js → cli-vn0qv9cj.js} +25 -88
  71. package/dist/{cli-987hg0aa.js → cli-vwbbaecp.js} +2 -2
  72. package/dist/cli-wd9hz40d.js +69 -0
  73. package/dist/{cli-j57qkrpq.js → cli-wgjx0q33.js} +13 -13
  74. package/dist/cli-xgpf00sk.js +2149 -0
  75. package/dist/{cli-mcnhgnn1.js → cli-ykk5jaax.js} +184 -26
  76. package/dist/{cli-aky8tctm.js → cli-z9x0sh1t.js} +3 -3
  77. package/dist/{cli-1hkrch3k.js → cli-zw65mab6.js} +5 -5
  78. package/dist/cli.js +38 -29
  79. package/dist/cloudflare-workers-ai-system-one-1sg586qv.js +46 -0
  80. package/dist/{codex-adapter-cnm8wk11.js → codex-adapter-jqfqqa21.js} +21 -14
  81. package/dist/{codex-hook-9hptmdhj.js → codex-hook-5eys3dya.js} +2 -2
  82. package/dist/{codex-session-runner-gfg547zj.js → codex-session-runner-zd341dsm.js} +21 -14
  83. package/dist/{commands-e3bn0p75.js → commands-vfsysz4s.js} +9 -8
  84. package/dist/{db-03v9kzr2.js → db-s3znhvbn.js} +15 -10
  85. package/dist/{dispatcher-nrmg8yht.js → dispatcher-5xn0c7rf.js} +32 -28
  86. package/dist/{dsh-adapter-k03nfqa6.js → dsh-adapter-894mgfvs.js} +3 -3
  87. package/dist/{e2b-93x1k0j5.js → e2b-ez07znam.js} +4 -3
  88. package/dist/execute-71ysgv35.js +965 -0
  89. package/dist/{google-generative-ai-bxmv50nc.js → google-generative-ai-1nfcdphp.js} +5 -4
  90. package/dist/{google-vertex-809af514.js → google-vertex-1tqcd7b1.js} +5 -4
  91. package/dist/{handlers-aqcedbyb.js → handlers-5w4jwycr.js} +35 -31
  92. package/dist/{hook-7vkskkre.js → hook-853bxrr6.js} +16 -13
  93. package/dist/{hook-ybvmrmhq.js → hook-z0hbxj85.js} +16 -13
  94. package/dist/{http-2eqa8t24.js → http-akc3wy3m.js} +600 -123
  95. package/dist/{index-f6cryxwe.js → index-4a5njnm1.js} +2 -59
  96. package/dist/{index-a3vn96n8.js → index-5sz16ksh.js} +187 -47
  97. package/dist/{index-c6zsv1bd.js → index-bjmjh9h4.js} +11 -11
  98. package/dist/{index-chgdkq36.js → index-cd151qkq.js} +32 -28
  99. package/dist/{index-x71bvq0p.js → index-k661dzzr.js} +33 -29
  100. package/dist/{index-1yks3qcr.js → index-ttpbhnjg.js} +32 -28
  101. package/dist/{keepalive-vtkf5n99.js → keepalive-8p9rpvz5.js} +11 -10
  102. package/dist/{lead-h3sp357x.js → lead-jp69z5h3.js} +49 -45
  103. package/dist/llama-cpp-classify-t2tccams.js +335 -0
  104. package/dist/{maintenance-jzeqtk3q.js → maintenance-fwx4ev0k.js} +12 -12
  105. package/dist/{mistral-conversations-zx0kn554.js → mistral-conversations-bhvwqcnk.js} +14 -17
  106. package/dist/{oauth-refresh-sweep-qp3dzmdp.js → oauth-refresh-sweep-cwcq1ctx.js} +10 -9
  107. package/dist/{onboard-tmsp0qbz.js → onboard-2b4q0t84.js} +6 -5
  108. package/dist/{openai-codex-responses-4vjqzvjp.js → openai-codex-responses-nekthgks.js} +21 -8
  109. package/dist/{openai-completions-9hjrqbw8.js → openai-completions-hxtzwj0s.js} +8 -11
  110. package/dist/{openai-responses-7b1pn0xt.js → openai-responses-w4r118w7.js} +22 -17
  111. package/dist/{opencode-adapter-x6x2da1z.js → opencode-adapter-zz7xvjj6.js} +6 -4
  112. package/dist/{openrouter-images-9f9ek4rw.js → openrouter-images-b6sqqjgn.js} +4 -6
  113. package/dist/{otel-impl-9mz73q65.js → otel-impl-g8rs4vwr.js} +1 -1
  114. package/dist/{pi-messages-txpjj39q.js → pi-messages-vxdt8v7j.js} +2 -1
  115. package/dist/{pi-mono-adapter-m6dvv0dz.js → pi-mono-adapter-n0me28wt.js} +29 -17
  116. package/dist/pricing-refresh-0v77385v.js +39 -0
  117. package/dist/{rbac-roles-c9wqz83x.js → rbac-roles-krjyazbj.js} +10 -9
  118. package/dist/{render-v2-gryrh9h8.js → render-v2-3wjsp9aw.js} +10 -9
  119. package/dist/runtime-ktjysacx.js +24 -0
  120. package/dist/{setup-q9720bt6.js → setup-yeqryke6.js} +6 -5
  121. package/dist/typesafe-system-one-96960jxp.js +27 -0
  122. package/dist/{virtual-modules-3htpgn8x.js → virtual-modules-dzdeq1sf.js} +21 -13
  123. package/dist/{work-objects-b76x7deb.js → work-objects-3pakpkw0.js} +35 -31
  124. package/dist/{worker-6vrxbv41.js → worker-85testgj.js} +49 -45
  125. package/openapi.json +863 -14
  126. package/package.json +9 -8
  127. package/src/be/db/agents.ts +20 -0
  128. package/src/be/db/tasks/human-free.ts +442 -0
  129. package/src/be/db/tasks/read.ts +56 -1
  130. package/src/be/db/tasks/write.ts +107 -11
  131. package/src/be/db.ts +89 -165
  132. package/src/be/harness-model-support.ts +182 -0
  133. package/src/be/human-free-drain.ts +67 -0
  134. package/src/be/migrations/182_task_human_free_flag.sql +63 -0
  135. package/src/be/migrations/183_human_free_reclassify_queue.sql +25 -0
  136. package/src/be/migrations/184_model_catalog.sql +120 -0
  137. package/src/be/model-catalog-store.ts +644 -0
  138. package/src/be/model-tier-keys.ts +31 -0
  139. package/src/be/model-tier-resolution.ts +489 -0
  140. package/src/be/model-validation.ts +112 -0
  141. package/src/be/models-catalog.ts +61 -7
  142. package/src/be/modelsdev-cache.json +82 -0
  143. package/src/be/modelsdev-cache.ts +2 -0
  144. package/src/be/pricing-refresh.ts +154 -12
  145. package/src/be/scripts/typecheck.ts +15 -0
  146. package/src/be/seed-scripts/catalog/task-failure-audit.ts +61 -9
  147. package/src/be/swarm-config-guard.ts +6 -0
  148. package/src/cli.tsx +10 -0
  149. package/src/commands/claude-managed-setup.ts +3 -1
  150. package/src/commands/runner.ts +76 -2
  151. package/src/extensions/contract-types.generated.ts +1 -1
  152. package/src/heartbeat/heartbeat.ts +64 -15
  153. package/src/heartbeat/templates.ts +2 -2
  154. package/src/http/agents.ts +49 -1
  155. package/src/http/index.ts +8 -0
  156. package/src/http/models-catalog.ts +357 -8
  157. package/src/http/poll.ts +45 -2
  158. package/src/http/schedules.ts +36 -6
  159. package/src/http/session-data.ts +2 -5
  160. package/src/http/stats.ts +6 -8
  161. package/src/http/tasks.ts +26 -1
  162. package/src/http/usage-cache.ts +56 -15
  163. package/src/http/workflows.ts +35 -8
  164. package/src/prompts/session-templates.ts +1 -0
  165. package/src/providers/claude-managed-models.ts +47 -161
  166. package/src/providers/codex-adapter.ts +4 -4
  167. package/src/providers/codex-models.ts +65 -198
  168. package/src/providers/reasoning-effort.ts +44 -140
  169. package/src/rbac/legacy-policy.ts +25 -0
  170. package/src/rbac/permissions.ts +10 -0
  171. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  172. package/src/scripts-runtime/types/stdlib.d.ts +15 -0
  173. package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
  174. package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
  175. package/src/server.ts +6 -0
  176. package/src/slack/message-text.ts +56 -2
  177. package/src/slack/thread-buffer.ts +10 -2
  178. package/src/tests/agents-list-model-display.test.ts +4 -6
  179. package/src/tests/base-prompt.test.ts +3 -0
  180. package/src/tests/claude-adapter.test.ts +10 -0
  181. package/src/tests/claude-managed-adapter.test.ts +12 -18
  182. package/src/tests/codex-adapter.test.ts +2 -1
  183. package/src/tests/codex-gpt6-release.test.ts +66 -5
  184. package/src/tests/context-window.test.ts +7 -5
  185. package/src/tests/db-extraction-contract.test.ts +1 -0
  186. package/src/tests/db-task-read-contract.test.ts +5 -1
  187. package/src/tests/db-task-write-contract.test.ts +4 -1
  188. package/src/tests/docs-index-footprint.test.js +3 -3
  189. package/src/tests/explicit-model-validation.test.ts +332 -0
  190. package/src/tests/harness-model-support.test.ts +374 -0
  191. package/src/tests/heartbeat-checklist-config.test.ts +71 -0
  192. package/src/tests/heartbeat-checklist.test.ts +4 -2
  193. package/src/tests/heartbeat-orphan-resume.test.ts +48 -0
  194. package/src/tests/human-free-flag.test.ts +279 -0
  195. package/src/tests/human-free-oracle.ts +57 -0
  196. package/src/tests/human-free-reclassify.test.ts +669 -0
  197. package/src/tests/migration-046-budgets.test.ts +3 -3
  198. package/src/tests/model-catalog-migration.test.ts +134 -0
  199. package/src/tests/model-catalog-table.test.ts +249 -0
  200. package/src/tests/model-catalog-write-access.test.ts +387 -0
  201. package/src/tests/model-tier-resolution.test.ts +519 -0
  202. package/src/tests/models-catalog.test.ts +1 -1
  203. package/src/tests/multi-runtime-enabled-stats.test.ts +65 -1
  204. package/src/tests/package-publish.test.ts +137 -36
  205. package/src/tests/pricing-routes.test.ts +2 -2
  206. package/src/tests/rbac-engine.test.ts +42 -2
  207. package/src/tests/reasoning-effort.test.ts +109 -0
  208. package/src/tests/refresh-modelsdev-carryforward.test.ts +5 -5
  209. package/src/tests/runtime-model-catalog.test.ts +86 -0
  210. package/src/tests/script-connections.test.ts +5 -0
  211. package/src/tests/seed-scripts.test.ts +89 -0
  212. package/src/tests/session-costs.test.ts +14 -11
  213. package/src/tests/slack-message-text.test.ts +101 -0
  214. package/src/tests/slack-thread-buffer-context.test.ts +93 -0
  215. package/src/tests/task-cascade-fail.test.ts +148 -2
  216. package/src/tests/tool-annotations.test.ts +1 -1
  217. package/src/tests/usage-cache.test.ts +166 -0
  218. package/src/tests/workflow-executors.test.ts +5 -2
  219. package/src/tests/workflow-system-one-decision-review.test.ts +1021 -0
  220. package/src/tests/workflow-system-one-decision-save-warnings.test.ts +365 -0
  221. package/src/tests/workflow-system-one-decision.test.ts +2063 -0
  222. package/src/tools/model-catalog/index.ts +137 -0
  223. package/src/tools/schedules/create-schedule.ts +16 -1
  224. package/src/tools/schedules/patch-schedule.ts +17 -0
  225. package/src/tools/schedules/update-schedule.ts +17 -0
  226. package/src/tools/send-task.ts +14 -0
  227. package/src/tools/task-action.ts +12 -0
  228. package/src/tools/tool-config.ts +3 -1
  229. package/src/tools/workflows/create-workflow.ts +9 -2
  230. package/src/tools/workflows/patch-workflow-node.ts +17 -7
  231. package/src/tools/workflows/patch-workflow.ts +9 -2
  232. package/src/tools/workflows/update-workflow.ts +9 -2
  233. package/src/types.ts +30 -1
  234. package/src/utils/context-window.ts +47 -53
  235. package/src/utils/harness-cli-version.ts +115 -0
  236. package/src/utils/harness-model-error.ts +33 -0
  237. package/src/utils/runtime-model-catalog.ts +137 -0
  238. package/src/workflows/approval-resolution.ts +39 -0
  239. package/src/workflows/definition.ts +7 -0
  240. package/src/workflows/engine.ts +69 -1
  241. package/src/workflows/executors/agent-task.ts +9 -0
  242. package/src/workflows/executors/base.ts +53 -0
  243. package/src/workflows/executors/human-in-the-loop.ts +8 -8
  244. package/src/workflows/executors/index.ts +1 -0
  245. package/src/workflows/executors/registry.ts +2 -0
  246. package/src/workflows/executors/system-one-decision.ts +1232 -0
  247. package/src/workflows/executors/system-one-providers.ts +301 -0
  248. package/src/workflows/executors/workflow-llm.ts +13 -1
  249. package/src/workflows/readiness.ts +86 -0
  250. package/src/workflows/recovery.ts +12 -12
  251. package/src/workflows/resume.ts +23 -9
  252. package/templates/schedules/daily-blocker-digest/content.md +4 -5
  253. package/templates/skills/agent-browser/SKILL.md +6 -5
  254. package/templates/skills/agent-browser/content.md +6 -5
  255. package/templates/skills/heartbeat-runbook/config.json +1 -1
  256. package/templates/skills/heartbeat-runbook/content.md +2 -2
  257. package/templates/skills/swarm-scripts/SKILL.md +1 -1
  258. package/templates/skills/swarm-scripts/content.md +1 -1
  259. package/templates/skills/workflow-iterate/content.md +81 -1
  260. package/templates/workflows/claude-code-changelog-watch/content.md +2 -0
  261. package/templates/workflows/pr-review-status-sweep/content.md +2 -0
  262. package/dist/claude-sdk-session-t442qz6f.js +0 -39108
  263. package/dist/cli-0xjkj1j7.js +0 -61
  264. package/dist/cli-65hjmev5.js +0 -1141
  265. package/dist/cli-aw1jwp1r.js +0 -14075
  266. package/dist/cli-h967nb6r.js +0 -6603
  267. package/dist/cli-vapyk8sw.js +0 -20
  268. package/dist/cli-ws6rqycm.js +0 -247
  269. package/dist/pricing-refresh-v1cbr9te.js +0 -27
  270. package/src/providers/modelsdev-reasoning.json +0 -6453
  271. package/dist/{codex-login-x3jk4etn.js → codex-login-he9vrn90.js} +3 -3
  272. package/dist/{index-f24115ge.js → index-2wsdsnmm.js} +3 -3
@@ -1,533 +1,3 @@
1
- import {
2
- resolveCodexPrompt
3
- } from "./cli-r94z9p1z.js";
4
- import {
5
- createSwarmEventHandler
6
- } from "./cli-hsxj0yar.js";
7
- import {
8
- readPkgVersion
9
- } from "./cli-2djtr51b.js";
10
- import {
11
- buildOtelTraceparentEnv
12
- } from "./cli-q2j38vre.js";
13
- import {
14
- CTX_MODE_NUDGE_EVERY
15
- } from "./cli-zm7njwzd.js";
16
- import {
17
- summarizeSession
18
- } from "./cli-cw9zck8j.js";
19
- import {
20
- CONTEXT_FORMULA,
21
- clampContextPercent,
22
- computeContextUsedUnified
23
- } from "./cli-0xjkj1j7.js";
24
- import {
25
- SessionErrorTracker
26
- } from "./cli-npssxgaz.js";
27
- import {
28
- applyReasoningEffort
29
- } from "./cli-h967nb6r.js";
30
- import {
31
- buildRatingsFromLlm,
32
- fetchRetrievalsForTask,
33
- getMemoryRaterNames,
34
- postRatings
35
- } from "./cli-tt9k8r35.js";
36
- import {
37
- CodexOAuthRefreshError,
38
- credentialsToAuthJson,
39
- getValidCodexOAuth
40
- } from "./cli-vhjwh6cz.js";
41
- import {
42
- swarmRuntimeInstanceId
43
- } from "./cli-re8z5p8p.js";
44
- import {
45
- detachedProcessGroup,
46
- registerProcessGroup,
47
- terminateProcessGroup
48
- } from "./cli-y89t4nca.js";
49
- import {
50
- getApiKey
51
- } from "./cli-f14fvzag.js";
52
- import {
53
- init_package,
54
- package_default
55
- } from "./cli-c07r9a2m.js";
56
- import {
57
- init_secret_scrubber,
58
- scrubSecrets
59
- } from "./cli-r2ap2czm.js";
60
- import {
61
- __require
62
- } from "./cli-bc05qbss.js";
63
-
64
- // src/providers/codex-adapter.ts
65
- import { existsSync as nodeExistsSync } from "node:fs";
66
- import { join as join2 } from "node:path";
67
- init_secret_scrubber();
68
-
69
- // src/providers/codex-agents-md.ts
70
- import { lstat, mkdir, readlink, realpath, symlink, unlink } from "node:fs/promises";
71
- import { homedir } from "node:os";
72
- import { dirname, join, resolve, sep } from "node:path";
73
- var BLOCK_OPEN = "<swarm_system_prompt>";
74
- var BLOCK_CLOSE = "</swarm_system_prompt>";
75
- var BLOCK_REGEX = /<swarm_system_prompt>[\s\S]*?<\/swarm_system_prompt>\n?/;
76
- var DEFAULT_STATE_DIR = join(homedir(), ".cache", "agent-swarm", "codex-agents-md");
77
- var NOOP_HANDLE = {
78
- cleanup: async () => {}
79
- };
80
- async function readIfExists(path) {
81
- const file = Bun.file(path);
82
- return await file.exists() ? await file.text() : null;
83
- }
84
- function recordPathFor(stateDir, realCwd) {
85
- const key = new Bun.CryptoHasher("sha256").update(realCwd).digest("hex");
86
- return join(stateDir, `${key}.json`);
87
- }
88
- async function readRecord(recordPath, realCwd) {
89
- try {
90
- const record = JSON.parse(await Bun.file(recordPath).text());
91
- if (record.cwd === realCwd && typeof record.linkTarget === "string") {
92
- return { cwd: record.cwd, linkTarget: record.linkTarget };
93
- }
94
- } catch {}
95
- return null;
96
- }
97
- async function inTreeTarget(realCwd, agentsMdPath, linkTarget) {
98
- const target = await realpath(resolve(dirname(agentsMdPath), linkTarget)).catch(() => null);
99
- const prefix = realCwd.endsWith(sep) ? realCwd : `${realCwd}${sep}`;
100
- if (target === null || !target.startsWith(prefix)) {
101
- return null;
102
- }
103
- const stat = await lstat(target).catch(() => null);
104
- return stat?.isFile() ? target : null;
105
- }
106
- async function restoreSymlink(agentsMdPath, realCwd, linkTarget) {
107
- const stat = await lstat(agentsMdPath).catch(() => null);
108
- const current = stat?.isFile() ? await Bun.file(agentsMdPath).text() : null;
109
- await unlink(agentsMdPath).catch(() => {});
110
- await symlink(linkTarget, agentsMdPath);
111
- if (current === null) {
112
- return;
113
- }
114
- const target = await inTreeTarget(realCwd, agentsMdPath, linkTarget);
115
- if (target === null) {
116
- return;
117
- }
118
- const stripped = current.replace(BLOCK_REGEX, "");
119
- if (stripped !== await Bun.file(target).text()) {
120
- await Bun.write(target, stripped);
121
- }
122
- }
123
- async function writeCodexAgentsMd(cwd, systemPrompt, options = {}) {
124
- if (!cwd || !systemPrompt) {
125
- return NOOP_HANDLE;
126
- }
127
- const agentsMdPath = join(cwd, "AGENTS.md");
128
- const claudeMdPath = join(cwd, "CLAUDE.md");
129
- const stateDir = options.stateDir ?? DEFAULT_STATE_DIR;
130
- const realCwd = await realpath(cwd).catch(() => resolve(cwd));
131
- const recordPath = recordPathFor(stateDir, realCwd);
132
- const block = `${BLOCK_OPEN}
133
- ${systemPrompt}
134
- ${BLOCK_CLOSE}`;
135
- let stat = await lstat(agentsMdPath).catch(() => null);
136
- const record = await readRecord(recordPath, realCwd);
137
- if (record) {
138
- if (stat?.isFile() && BLOCK_REGEX.test(await Bun.file(agentsMdPath).text())) {
139
- await restoreSymlink(agentsMdPath, realCwd, record.linkTarget);
140
- stat = await lstat(agentsMdPath);
141
- }
142
- await unlink(recordPath).catch(() => {});
143
- }
144
- if (stat?.isSymbolicLink()) {
145
- const linkTarget = await readlink(agentsMdPath);
146
- const target = await inTreeTarget(realCwd, agentsMdPath, linkTarget);
147
- const targetContent = target !== null ? await Bun.file(target).text() : "";
148
- await mkdir(stateDir, { recursive: true });
149
- await Bun.write(recordPath, JSON.stringify({ cwd: realCwd, linkTarget }));
150
- await unlink(agentsMdPath);
151
- await Bun.write(agentsMdPath, `${block}
152
- ${targetContent.replace(BLOCK_REGEX, "")}`);
153
- return {
154
- async cleanup() {
155
- try {
156
- await restoreSymlink(agentsMdPath, realCwd, linkTarget);
157
- await unlink(recordPath).catch(() => {});
158
- } catch {}
159
- }
160
- };
161
- }
162
- let createdFresh = false;
163
- let newContent;
164
- if (!stat) {
165
- const claudeContent = await readIfExists(claudeMdPath);
166
- newContent = claudeContent !== null ? `${block}
167
-
168
- ${claudeContent}` : `${block}
169
- `;
170
- createdFresh = true;
171
- } else {
172
- const existingContent = await Bun.file(agentsMdPath).text();
173
- if (BLOCK_REGEX.test(existingContent)) {
174
- newContent = existingContent.replace(BLOCK_REGEX, `${block}
175
- `);
176
- } else {
177
- newContent = `${block}
178
- ${existingContent}`;
179
- }
180
- }
181
- await Bun.write(agentsMdPath, newContent);
182
- return {
183
- async cleanup() {
184
- try {
185
- if (createdFresh) {
186
- await Bun.$`rm -f ${agentsMdPath}`.quiet().nothrow();
187
- return;
188
- }
189
- const currentFile = Bun.file(agentsMdPath);
190
- if (!await currentFile.exists()) {
191
- return;
192
- }
193
- const currentContent = await currentFile.text();
194
- const stripped = currentContent.replace(BLOCK_REGEX, "");
195
- await Bun.write(agentsMdPath, stripped);
196
- } catch {}
197
- }
198
- };
199
- }
200
-
201
- // src/providers/codex-app-server.ts
202
- init_package();
203
- init_secret_scrubber();
204
- var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
205
- var CLOSE_GRACE_MS = 250;
206
- var EXIT_STREAM_DRAIN_MS = 100;
207
- var MAX_STDOUT_LINE_LENGTH = 16 * 1024 * 1024;
208
- var MAX_STDERR_LINE_LENGTH = 64 * 1024;
209
- var MAX_STDERR_TAIL_LENGTH = 16 * 1024;
210
-
211
- class CodexAppServerRpcError extends Error {
212
- code;
213
- data;
214
- constructor(method, error) {
215
- super(`Codex app-server ${method} failed (${error.code}): ${error.message}`);
216
- this.name = "CodexAppServerRpcError";
217
- this.code = error.code;
218
- this.data = error.data;
219
- }
220
- }
221
-
222
- class CodexAppServer {
223
- proc;
224
- pending = new Map;
225
- notificationListeners = new Set;
226
- closeListeners = new Set;
227
- requestTimeoutMs;
228
- onStderr;
229
- ready;
230
- stderrDone;
231
- nextId = 0;
232
- stderrTail = "";
233
- initializedVersion;
234
- terminalError;
235
- closePromise;
236
- constructor(options) {
237
- this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
238
- if (!Number.isFinite(this.requestTimeoutMs) || this.requestTimeoutMs <= 0) {
239
- throw new Error("Codex app-server requestTimeoutMs must be a positive number");
240
- }
241
- this.onStderr = options.onStderr;
242
- const codexPath = options.codexPath ?? resolveCodexPath(options.env.PATH);
243
- const command = [codexPath, "app-server", "--listen", "stdio://"];
244
- const env = Object.fromEntries(Object.entries(options.env).filter((entry) => entry[1] !== undefined));
245
- this.proc = Bun.spawn(command, {
246
- env,
247
- stdin: "pipe",
248
- stdout: "pipe",
249
- stderr: "pipe"
250
- });
251
- this.consumeStdout().catch((error) => this.fail(asError(error)));
252
- this.stderrDone = this.consumeStderr().catch((error) => {
253
- this.fail(asError(error));
254
- });
255
- this.proc.exited.then(async (exitCode) => {
256
- await Promise.race([this.stderrDone, Bun.sleep(EXIT_STREAM_DRAIN_MS)]);
257
- if (this.closePromise)
258
- return;
259
- const suffix = this.stderrTail ? `: ${this.stderrTail}` : "";
260
- this.fail(new Error(`Codex app-server exited with code ${exitCode}${suffix}`));
261
- });
262
- this.ready = Promise.resolve().then(() => this.initialize());
263
- this.ready.catch(() => {});
264
- }
265
- async request(method, params) {
266
- await this.ready;
267
- return this.requestRaw(method, params);
268
- }
269
- get version() {
270
- return this.initializedVersion;
271
- }
272
- onNotification(listener) {
273
- this.notificationListeners.add(listener);
274
- return () => this.notificationListeners.delete(listener);
275
- }
276
- onClose(listener) {
277
- if (this.terminalError) {
278
- listener(this.terminalError);
279
- return () => {};
280
- }
281
- this.closeListeners.add(listener);
282
- return () => this.closeListeners.delete(listener);
283
- }
284
- close() {
285
- if (this.closePromise)
286
- return this.closePromise;
287
- this.rejectPending(new Error("Codex app-server closed"));
288
- this.closePromise = this.terminate();
289
- return this.closePromise;
290
- }
291
- async initialize() {
292
- const response = await this.requestRaw("initialize", {
293
- clientInfo: {
294
- name: "agent-swarm",
295
- title: "Agent Swarm",
296
- version: package_default.version
297
- },
298
- capabilities: {
299
- experimentalApi: false,
300
- requestAttestation: false
301
- }
302
- });
303
- if (typeof response.userAgent === "string") {
304
- this.initializedVersion = parseVersion(response.userAgent);
305
- }
306
- this.write({ method: "initialized" });
307
- }
308
- requestRaw(method, params) {
309
- if (this.terminalError)
310
- return Promise.reject(this.terminalError);
311
- if (this.closePromise)
312
- return Promise.reject(new Error("Codex app-server closed"));
313
- const id = this.nextId++;
314
- return new Promise((resolve2, reject) => {
315
- const timer = setTimeout(() => {
316
- this.pending.delete(id);
317
- reject(new Error(`Codex app-server ${method} timed out after ${this.requestTimeoutMs}ms`));
318
- }, this.requestTimeoutMs);
319
- this.pending.set(id, {
320
- method,
321
- resolve: resolve2,
322
- reject,
323
- timer
324
- });
325
- try {
326
- this.write(params === undefined ? { method, id } : { method, id, params });
327
- } catch (error) {
328
- clearTimeout(timer);
329
- this.pending.delete(id);
330
- reject(asError(error));
331
- }
332
- });
333
- }
334
- write(message) {
335
- if (this.terminalError)
336
- throw this.terminalError;
337
- if (this.closePromise)
338
- throw new Error("Codex app-server closed");
339
- const stdin = this.proc.stdin;
340
- stdin.write(`${JSON.stringify(message)}
341
- `);
342
- stdin.flush();
343
- }
344
- async consumeStdout() {
345
- await readLines(this.proc.stdout, MAX_STDOUT_LINE_LENGTH, (line) => this.handleLine(line));
346
- }
347
- async consumeStderr() {
348
- await readLines(this.proc.stderr, MAX_STDERR_LINE_LENGTH, (line) => {
349
- const scrubbed = scrubSecrets(line);
350
- this.stderrTail = `${this.stderrTail}${this.stderrTail ? `
351
- ` : ""}${scrubbed}`.slice(-MAX_STDERR_TAIL_LENGTH);
352
- if (!this.onStderr)
353
- return;
354
- try {
355
- this.onStderr(scrubbed);
356
- } catch (error) {
357
- console.error(`[codex-app-server] stderr listener failed: ${scrubSecrets(asError(error).message)}`);
358
- }
359
- });
360
- }
361
- handleLine(line) {
362
- let message;
363
- try {
364
- message = JSON.parse(line);
365
- } catch (error) {
366
- throw new Error("Codex app-server emitted malformed JSON", {
367
- cause: error
368
- });
369
- }
370
- if (!isRecord(message)) {
371
- throw new Error("Codex app-server emitted a non-object JSON message");
372
- }
373
- if (isRequestId(message.id)) {
374
- if (typeof message.method === "string") {
375
- this.rejectServerRequest(message.id, message.method);
376
- return;
377
- }
378
- this.handleResponse(message.id, message);
379
- return;
380
- }
381
- if (typeof message.method === "string") {
382
- const notification = {
383
- method: message.method,
384
- ...Object.hasOwn(message, "params") ? { params: message.params } : {},
385
- ...typeof message.emittedAtMs === "number" ? { emittedAtMs: message.emittedAtMs } : {}
386
- };
387
- for (const listener of this.notificationListeners) {
388
- try {
389
- listener(notification);
390
- } catch (error) {
391
- console.error(`[codex-app-server] notification listener failed: ${scrubSecrets(asError(error).message)}`);
392
- }
393
- }
394
- return;
395
- }
396
- throw new Error("Codex app-server emitted an invalid protocol message");
397
- }
398
- handleResponse(id, message) {
399
- const pending = this.pending.get(id);
400
- if (!pending)
401
- return;
402
- this.pending.delete(id);
403
- clearTimeout(pending.timer);
404
- if (isRpcError(message.error)) {
405
- pending.reject(new CodexAppServerRpcError(pending.method, message.error));
406
- return;
407
- }
408
- if (Object.hasOwn(message, "result")) {
409
- pending.resolve(message.result);
410
- return;
411
- }
412
- pending.reject(new Error(`Codex app-server returned an invalid response for ${pending.method}`));
413
- }
414
- rejectServerRequest(id, method) {
415
- this.write({
416
- id,
417
- error: {
418
- code: -32601,
419
- message: `Client does not support server request: ${method}`
420
- }
421
- });
422
- }
423
- fail(error) {
424
- if (this.terminalError || this.closePromise)
425
- return;
426
- this.terminalError = error;
427
- this.rejectPending(error);
428
- this.closePromise = this.terminate();
429
- for (const listener of this.closeListeners) {
430
- try {
431
- listener(error);
432
- } catch (listenerError) {
433
- console.error(`[codex-app-server] close listener failed: ${scrubSecrets(asError(listenerError).message)}`);
434
- }
435
- }
436
- this.closeListeners.clear();
437
- }
438
- rejectPending(error) {
439
- for (const pending of this.pending.values()) {
440
- clearTimeout(pending.timer);
441
- pending.reject(error);
442
- }
443
- this.pending.clear();
444
- }
445
- async terminate() {
446
- try {
447
- this.proc.stdin.end();
448
- } catch {}
449
- try {
450
- this.proc.kill("SIGTERM");
451
- } catch {
452
- return;
453
- }
454
- const exited = this.proc.exited.then(() => {
455
- return;
456
- });
457
- await Promise.race([exited, Bun.sleep(CLOSE_GRACE_MS)]);
458
- if (this.proc.exitCode === null) {
459
- try {
460
- this.proc.kill("SIGKILL");
461
- } catch {
462
- return;
463
- }
464
- await Promise.race([exited, Bun.sleep(CLOSE_GRACE_MS)]);
465
- }
466
- }
467
- }
468
- async function readLines(stream, maxLineLength, onLine) {
469
- const reader = stream.getReader();
470
- const decoder = new TextDecoder;
471
- let buffered = "";
472
- try {
473
- while (true) {
474
- const { done, value } = await reader.read();
475
- buffered += decoder.decode(value, { stream: !done });
476
- let newline = buffered.indexOf(`
477
- `);
478
- while (newline !== -1) {
479
- const line = buffered.slice(0, newline).replace(/\r$/, "");
480
- buffered = buffered.slice(newline + 1);
481
- if (line.length > maxLineLength) {
482
- throw new Error(`Codex app-server output line exceeded ${maxLineLength} characters`);
483
- }
484
- if (line)
485
- onLine(line);
486
- newline = buffered.indexOf(`
487
- `);
488
- }
489
- if (buffered.length > maxLineLength) {
490
- throw new Error(`Codex app-server output line exceeded ${maxLineLength} characters`);
491
- }
492
- if (done)
493
- break;
494
- }
495
- if (buffered) {
496
- const line = buffered.replace(/\r$/, "");
497
- if (line.length > maxLineLength) {
498
- throw new Error(`Codex app-server output line exceeded ${maxLineLength} characters`);
499
- }
500
- onLine(line);
501
- }
502
- } finally {
503
- reader.releaseLock();
504
- }
505
- }
506
- function resolveCodexPath(path) {
507
- const fromPath = Bun.which("codex", { PATH: path ?? process.env.PATH });
508
- if (fromPath)
509
- return fromPath;
510
- try {
511
- return Bun.resolveSync("@openai/codex/bin/codex.js", import.meta.dir);
512
- } catch {
513
- return "codex";
514
- }
515
- }
516
- function parseVersion(userAgent) {
517
- return userAgent.match(/\b\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?\b/)?.[0];
518
- }
519
- function isRecord(value) {
520
- return typeof value === "object" && value !== null && !Array.isArray(value);
521
- }
522
- function isRequestId(value) {
523
- return typeof value === "string" || typeof value === "number" && Number.isFinite(value);
524
- }
525
- function isRpcError(value) {
526
- return isRecord(value) && typeof value.code === "number" && Number.isFinite(value.code) && typeof value.message === "string";
527
- }
528
- function asError(value) {
529
- return value instanceof Error ? value : new Error(String(value));
530
- }
531
1
  // src/be/modelsdev-cache.json
532
2
  var modelsdev_cache_default = {
533
3
  subconscious: {
@@ -287635,6 +287105,88 @@ var modelsdev_cache_default = {
287635
287105
  cache_read: 2.5
287636
287106
  }
287637
287107
  },
287108
+ "gpt-6.1-sol": {
287109
+ id: "gpt-6.1-sol",
287110
+ name: "GPT-6.1 Sol",
287111
+ description: "Near-Astra performance for complex work at a lower cost",
287112
+ family: "gpt-sol",
287113
+ attachment: true,
287114
+ reasoning: true,
287115
+ reasoning_options: [
287116
+ {
287117
+ type: "effort",
287118
+ values: [
287119
+ "low",
287120
+ "medium",
287121
+ "high",
287122
+ "xhigh",
287123
+ "max"
287124
+ ]
287125
+ }
287126
+ ],
287127
+ tool_call: true,
287128
+ structured_output: true,
287129
+ temperature: false,
287130
+ knowledge: "2026-04-30",
287131
+ release_date: "2026-09-29",
287132
+ last_updated: "2026-09-29",
287133
+ modalities: {
287134
+ input: [
287135
+ "text",
287136
+ "image"
287137
+ ],
287138
+ output: [
287139
+ "text"
287140
+ ]
287141
+ },
287142
+ open_weights: false,
287143
+ limit: {
287144
+ context: 1050000,
287145
+ input: 922000,
287146
+ output: 128000
287147
+ },
287148
+ experimental: {
287149
+ modes: {
287150
+ fast: {
287151
+ cost: {
287152
+ input: 4,
287153
+ output: 20,
287154
+ cache_read: 0.2,
287155
+ cache_write: 5
287156
+ },
287157
+ provider: {
287158
+ body: {
287159
+ service_tier: "priority"
287160
+ }
287161
+ }
287162
+ }
287163
+ }
287164
+ },
287165
+ cost: {
287166
+ input: 2,
287167
+ output: 10,
287168
+ cache_read: 0.1,
287169
+ cache_write: 2.5,
287170
+ tiers: [
287171
+ {
287172
+ input: 4,
287173
+ output: 15,
287174
+ cache_read: 0.2,
287175
+ cache_write: 5,
287176
+ tier: {
287177
+ type: "context",
287178
+ size: 272000
287179
+ }
287180
+ }
287181
+ ],
287182
+ context_over_200k: {
287183
+ input: 4,
287184
+ output: 15,
287185
+ cache_read: 0.2,
287186
+ cache_write: 5
287187
+ }
287188
+ }
287189
+ },
287638
287190
  "gpt-6-sol": {
287639
287191
  id: "gpt-6-sol",
287640
287192
  name: "GPT-6 Sol",
@@ -333863,1699 +333415,67 @@ var modelsdev_cache_default = {
333863
333415
  }
333864
333416
  };
333865
333417
 
333866
- // src/providers/codex-models.ts
333867
- var CODEX_MODELS = [
333868
- "gpt-6-astra",
333869
- "gpt-6-sol",
333870
- "gpt-6-luna",
333871
- "gpt-5.6-sol",
333872
- "gpt-5.6-terra",
333873
- "gpt-5.6-luna",
333874
- "gpt-5.5",
333875
- "gpt-5.4",
333876
- "gpt-5.4-mini",
333877
- "gpt-5.3-codex",
333878
- "gpt-5.2-codex"
333879
- ];
333880
- var CODEX_DEFAULT_MODEL = "gpt-5.6-terra";
333881
- var CLAUDE_SHORTNAMES = {
333882
- fable: "gpt-5.6-sol",
333883
- opus: "gpt-5.6-sol",
333884
- sonnet: "gpt-5.6-terra",
333885
- haiku: "gpt-5.6-luna"
333886
- };
333887
- function resolveCodexModel(modelStr) {
333888
- if (!modelStr)
333889
- return CODEX_DEFAULT_MODEL;
333890
- const normalized = modelStr.toLowerCase();
333891
- return CLAUDE_SHORTNAMES[normalized] ?? normalized;
333892
- }
333893
- var MODELSDEV_OPENAI_MODELS = modelsdev_cache_default.openai?.models ?? {};
333894
- var FALLBACK_CODEX_MODEL_CONTEXT_WINDOWS = {
333895
- "gpt-6-astra": 1050000,
333896
- "gpt-6-sol": 1050000,
333897
- "gpt-6-luna": 1050000,
333898
- "gpt-5.6-sol": 1050000,
333899
- "gpt-5.6-terra": 1050000,
333900
- "gpt-5.6-luna": 1050000,
333901
- "gpt-5.5": 1050000,
333902
- "gpt-5.4": 1050000,
333903
- "gpt-5.4-mini": 400000,
333904
- "gpt-5.3-codex": 400000,
333905
- "gpt-5.2-codex": 200000
333906
- };
333907
- var CODEX_MODEL_CONTEXT_WINDOWS = Object.fromEntries(CODEX_MODELS.map((model) => [
333908
- model,
333909
- MODELSDEV_OPENAI_MODELS[model]?.limit?.context ?? FALLBACK_CODEX_MODEL_CONTEXT_WINDOWS[model]
333910
- ]));
333911
- function getCodexContextWindow(model) {
333912
- return CODEX_MODEL_CONTEXT_WINDOWS[model] ?? 200000;
333913
- }
333914
- var FALLBACK_CODEX_MODEL_PRICING = {
333915
- "gpt-6-astra": {
333916
- inputPerMillion: 10,
333917
- cachedInputPerMillion: 1,
333918
- outputPerMillion: 50
333919
- },
333920
- "gpt-6-sol": {
333921
- inputPerMillion: 2,
333922
- cachedInputPerMillion: 0.2,
333923
- outputPerMillion: 10
333924
- },
333925
- "gpt-6-luna": {
333926
- inputPerMillion: 0.1,
333927
- cachedInputPerMillion: 0.01,
333928
- outputPerMillion: 0.5
333929
- },
333930
- "gpt-5.6-sol": {
333931
- inputPerMillion: 4,
333932
- cachedInputPerMillion: 0.4,
333933
- outputPerMillion: 20
333934
- },
333935
- "gpt-5.6-terra": {
333936
- inputPerMillion: 2,
333937
- cachedInputPerMillion: 0.2,
333938
- outputPerMillion: 12
333939
- },
333940
- "gpt-5.6-luna": {
333941
- inputPerMillion: 0.2,
333942
- cachedInputPerMillion: 0.02,
333943
- outputPerMillion: 1.2
333944
- },
333945
- "gpt-5.5": {
333946
- inputPerMillion: 5,
333947
- cachedInputPerMillion: 0.5,
333948
- outputPerMillion: 30
333949
- },
333950
- "gpt-5.4": {
333951
- inputPerMillion: 2.5,
333952
- cachedInputPerMillion: 0.25,
333953
- outputPerMillion: 15
333954
- },
333955
- "gpt-5.4-mini": {
333956
- inputPerMillion: 0.75,
333957
- cachedInputPerMillion: 0.075,
333958
- outputPerMillion: 4.5
333959
- },
333960
- "gpt-5.3-codex": {
333961
- inputPerMillion: 1.75,
333962
- cachedInputPerMillion: 0.175,
333963
- outputPerMillion: 14
333964
- },
333965
- "gpt-5.2-codex": {
333966
- inputPerMillion: 1.75,
333967
- cachedInputPerMillion: 0.175,
333968
- outputPerMillion: 14
333969
- }
333970
- };
333971
- function getModelsDevCodexPricing(model) {
333972
- const cost = MODELSDEV_OPENAI_MODELS[model]?.cost;
333973
- if (typeof cost?.input !== "number" || typeof cost.cache_read !== "number" || typeof cost.output !== "number") {
333974
- return;
333975
- }
333976
- return {
333977
- inputPerMillion: cost.input,
333978
- cachedInputPerMillion: cost.cache_read,
333979
- outputPerMillion: cost.output
333980
- };
333981
- }
333982
- var CODEX_MODEL_PRICING = Object.fromEntries(CODEX_MODELS.map((model) => [
333983
- model,
333984
- getModelsDevCodexPricing(model) ?? FALLBACK_CODEX_MODEL_PRICING[model]
333985
- ]));
333986
- var _warnedUnknownCodexModels = new Set;
333987
- function computeCodexCostUsd(model, inputTokens, cachedInputTokens, outputTokens) {
333988
- const pricing = CODEX_MODEL_PRICING[model];
333989
- if (!pricing) {
333990
- if (!_warnedUnknownCodexModels.has(model)) {
333991
- _warnedUnknownCodexModels.add(model);
333992
- console.warn(`[codex] unpriced model ${JSON.stringify(model)} — adapter cost will report $0; ` + "server-side recompute will tag costSource='unpriced' if the pricing table has no rows.");
333993
- }
333994
- return 0;
333995
- }
333996
- const uncachedInput = Math.max(0, inputTokens - cachedInputTokens);
333997
- const inputCost = uncachedInput / 1e6 * pricing.inputPerMillion;
333998
- const cachedCost = cachedInputTokens / 1e6 * pricing.cachedInputPerMillion;
333999
- const outputCost = outputTokens / 1e6 * pricing.outputPerMillion;
334000
- return inputCost + cachedCost + outputCost;
334001
- }
334002
-
334003
- // src/providers/codex-oauth/home.ts
334004
- import os from "node:os";
334005
- function codexUserHome() {
334006
- return process.env.HOME || os.homedir();
334007
- }
334008
-
334009
- // src/providers/codex-swarm-events.ts
334010
- function createCodexSwarmEventHandler(opts) {
334011
- return createSwarmEventHandler({
334012
- ...opts,
334013
- sessionIdFallbackPrefix: "codex"
334014
- });
334015
- }
334016
-
334017
- // src/providers/codex-adapter.ts
334018
- function checkCodexCredentials(env, opts = {}) {
334019
- const homeDir = opts.homeDir ?? env.HOME ?? "/root";
334020
- const existsSync = opts.fs?.existsSync ?? nodeExistsSync;
334021
- const authFile = `${homeDir}/.codex/auth.json`;
334022
- if (existsSync(authFile)) {
334023
- return { ready: true, missing: [], satisfiedBy: "file" };
334024
- }
334025
- if (env.OPENAI_API_KEY || env.CODEX_OAUTH) {
334026
- return {
334027
- ready: true,
334028
- missing: [],
334029
- satisfiedBy: "side-effect-pending",
334030
- hint: "Credential present in env; entrypoint will materialise ~/.codex/auth.json on next boot."
334031
- };
334032
- }
334033
- if (Object.keys(env).some((k) => /^codex_oauth_\d+$/.test(k))) {
334034
- return {
334035
- ready: true,
334036
- missing: [],
334037
- satisfiedBy: "side-effect-pending",
334038
- hint: "Codex OAuth credential pool configured; runner will materialise auth.json per-task."
334039
- };
334040
- }
334041
- return {
334042
- ready: false,
334043
- missing: ["OPENAI_API_KEY", "CODEX_OAUTH", authFile],
334044
- hint: "Set OPENAI_API_KEY (entrypoint runs `codex login --with-api-key`), or store CODEX_OAUTH in swarm_config, or place a pre-authenticated `~/.codex/auth.json` in the worker home."
334045
- };
334046
- }
334047
- async function resolveCodexAuthMode(config, emit, deps = {}) {
334048
- const fsModule = await import("node:fs/promises");
334049
- const homedir2 = deps.homedir ?? codexUserHome;
334050
- const fs = deps.fs ?? {
334051
- readFile: (path, encoding) => fsModule.readFile(path, encoding),
334052
- mkdir: (path, opts) => fsModule.mkdir(path, opts),
334053
- writeFile: (path, data, opts) => fsModule.writeFile(path, data, opts)
334054
- };
334055
- const authJsonPath = join2(homedir2(), ".codex", "auth.json");
334056
- const readAuthMode = async () => {
334057
- try {
334058
- const raw = await fs.readFile(authJsonPath, "utf-8");
334059
- const parsed = JSON.parse(raw);
334060
- return typeof parsed.auth_mode === "string" ? parsed.auth_mode : null;
334061
- } catch {
334062
- return null;
334063
- }
334064
- };
334065
- let currentMode = await readAuthMode();
334066
- const slot = config.codexSlot ?? 0;
334067
- const isPoolSlot = config.codexSlot !== undefined;
334068
- if (config.apiUrl && config.apiKey && (currentMode !== "chatgpt" || isPoolSlot)) {
334069
- let oauthCreds = null;
334070
- try {
334071
- oauthCreds = await getValidCodexOAuth(config.apiUrl, config.apiKey, slot);
334072
- } catch (err) {
334073
- if (isPoolSlot) {
334074
- throw new Error(buildPoolRevalidationFailureReason(err, slot));
334075
- }
334076
- const message = err instanceof Error ? err.message : String(err);
334077
- emit({
334078
- type: "raw_stderr",
334079
- content: `[codex] OAuth revalidation failed (non-fatal, non-pool auth): ${message}
334080
- `
334081
- });
334082
- }
334083
- if (!oauthCreds && isPoolSlot) {
334084
- throw new Error(`[auth-error] Codex pool slot ${slot} revalidation failed: no credentials found in config store — the slot may have just been quarantined; re-run codex-login for this slot if this persists.`);
334085
- }
334086
- if (oauthCreds) {
334087
- try {
334088
- const authJson = credentialsToAuthJson(oauthCreds, {
334089
- includeRefreshToken: !isPoolSlot
334090
- });
334091
- await fs.mkdir(join2(homedir2(), ".codex"), { recursive: true, mode: 448 });
334092
- await fs.writeFile(authJsonPath, JSON.stringify(authJson, null, 2), { mode: 384 });
334093
- const verb = currentMode === null ? "Restored" : currentMode === "chatgpt" ? "Revalidated" : "Upgraded api-key auth.json to";
334094
- emit({
334095
- type: "raw_stderr",
334096
- content: `[codex] ${verb} OAuth credentials from config store
334097
- `
334098
- });
334099
- currentMode = "chatgpt";
334100
- } catch (err) {
334101
- const message = err instanceof Error ? err.message : String(err);
334102
- emit({
334103
- type: "raw_stderr",
334104
- content: `[codex] Failed to write auth.json: ${message}
334105
- `
334106
- });
334107
- }
334108
- }
334109
- }
334110
- return currentMode;
334111
- }
334112
- function buildPoolRevalidationFailureReason(err, slot) {
334113
- if (err instanceof CodexOAuthRefreshError) {
334114
- if (err.reason === "lock_timeout") {
334115
- return `[auth-error] Codex pool slot ${slot} [...${err.keySuffix}] revalidation failed: timed out waiting for the refresh lock — transient, will retry on next task.`;
334116
- }
334117
- return `[auth-error] Codex pool slot ${slot} [...${err.keySuffix}] revalidation failed: refresh rejected (${err.status ?? "unknown status"} ${err.body ?? ""}) — credential likely revoked; re-run codex-login for this slot.`;
334118
- }
334119
- const message = err instanceof Error ? err.message : String(err);
334120
- return `[auth-error] Codex pool slot ${slot} revalidation failed: ${message}`;
334121
- }
334122
- async function buildCodexConfig(config, model, emit) {
334123
- const mcpServers = {};
334124
- const runtimeInstanceId = swarmRuntimeInstanceId();
334125
- mcpServers["agent-swarm"] = {
334126
- url: `${config.apiUrl}/mcp`,
334127
- http_headers: {
334128
- Authorization: `Bearer ${config.apiKey}`,
334129
- "X-Agent-ID": config.agentId,
334130
- "X-Source-Task-Id": config.taskId ?? "",
334131
- ...runtimeInstanceId ? { "X-Runtime-Instance-ID": runtimeInstanceId } : {}
334132
- },
334133
- enabled: true,
334134
- startup_timeout_sec: 30,
334135
- tool_timeout_sec: 120
334136
- };
334137
- if (config.apiUrl && config.apiKey && config.agentId) {
334138
- try {
334139
- const res = await fetch(`${config.apiUrl}/api/agents/${config.agentId}/mcp-servers?resolveSecrets=true`, {
334140
- headers: {
334141
- Authorization: `Bearer ${config.apiKey}`,
334142
- "X-Agent-ID": config.agentId
334143
- }
334144
- });
334145
- if (res.ok) {
334146
- const data = await res.json();
334147
- for (const srv of data.servers ?? []) {
334148
- if (!srv.isActive || !srv.isEnabled)
334149
- continue;
334150
- if (srv.transport === "stdio") {
334151
- if (!srv.command)
334152
- continue;
334153
- let parsedArgs = [];
334154
- try {
334155
- parsedArgs = srv.args ? JSON.parse(srv.args) : [];
334156
- } catch {}
334157
- mcpServers[srv.name] = {
334158
- command: srv.command,
334159
- args: parsedArgs,
334160
- env: srv.resolvedEnv ?? {},
334161
- enabled: true,
334162
- startup_timeout_sec: 30,
334163
- tool_timeout_sec: 120
334164
- };
334165
- continue;
334166
- }
334167
- if (srv.transport === "http") {
334168
- if (!srv.url)
334169
- continue;
334170
- let parsedHeaders = {};
334171
- try {
334172
- parsedHeaders = srv.headers ? JSON.parse(srv.headers) : {};
334173
- } catch {}
334174
- mcpServers[srv.name] = {
334175
- url: srv.url,
334176
- http_headers: { ...parsedHeaders, ...srv.resolvedHeaders ?? {} },
334177
- enabled: true,
334178
- startup_timeout_sec: 30,
334179
- tool_timeout_sec: 120
334180
- };
334181
- continue;
334182
- }
334183
- if (srv.transport === "sse") {
334184
- emit({
334185
- type: "raw_stderr",
334186
- content: `[codex] Skipping MCP server "${srv.name}": SSE transport is not yet supported by Codex (tracked in openai/codex#2129).
334187
- `
334188
- });
334189
- }
334190
- }
334191
- } else {
334192
- emit({
334193
- type: "raw_stderr",
334194
- content: `[codex] Failed to fetch installed MCP servers: HTTP ${res.status}. Continuing with only the swarm MCP server.
334195
- `
334196
- });
334197
- }
334198
- } catch (err) {
334199
- const message = err instanceof Error ? err.message : String(err);
334200
- emit({
334201
- type: "raw_stderr",
334202
- content: `[codex] Failed to fetch installed MCP servers: ${message}. Continuing with only the swarm MCP server.
334203
- `
334204
- });
334205
- }
334206
- }
334207
- if (process.env.CONTEXT_MODE_DISABLED !== "true") {
334208
- mcpServers["context-mode"] = {
334209
- command: "context-mode",
334210
- enabled: true,
334211
- startup_timeout_sec: 30,
334212
- tool_timeout_sec: 120
334213
- };
334214
- }
334215
- const reasoningApplication = applyReasoningEffort("codex", model, config.reasoningEffort);
334216
- const reasoningConfig = reasoningApplication.kind === "codex-config" ? reasoningApplication.config : {};
334217
- return {
334218
- model,
334219
- approval_policy: "never",
334220
- sandbox_mode: "danger-full-access",
334221
- skip_git_repo_check: true,
334222
- show_raw_agent_reasoning: false,
334223
- features: { hooks: true, plugin_hooks: true },
334224
- mcp_servers: mcpServers,
334225
- ...reasoningConfig
334226
- };
333418
+ // src/utils/runtime-model-catalog.ts
333419
+ var SNAPSHOT = modelsdev_cache_default;
333420
+ var RUNTIME_CATALOG_TTL_MS = 10 * 60000;
333421
+ var FETCH_TIMEOUT_MS = 5000;
333422
+ var live = null;
333423
+ var liveAt = 0;
333424
+ var liveSource = null;
333425
+ var mergedSections = new Map;
333426
+ var inFlight = null;
333427
+ function setRuntimeModelCatalog(providers, at = Date.now(), source = "live") {
333428
+ live = providers;
333429
+ liveAt = at;
333430
+ liveSource = source;
333431
+ mergedSections.clear();
334227
333432
  }
334228
- function textInput(text) {
334229
- return [{ type: "text", text, text_elements: [] }];
334230
- }
334231
- function normalizeAppServerItem(raw) {
334232
- const id = typeof raw.id === "string" ? raw.id : "unknown";
334233
- switch (raw.type) {
334234
- case "agentMessage":
334235
- return { id, type: "agent_message", text: typeof raw.text === "string" ? raw.text : "" };
334236
- case "reasoning":
334237
- return {
334238
- id,
334239
- type: "reasoning",
334240
- summary: Array.isArray(raw.summary) ? raw.summary.filter((v) => typeof v === "string") : [],
334241
- content: Array.isArray(raw.content) ? raw.content.filter((v) => typeof v === "string") : []
334242
- };
334243
- case "plan":
334244
- return { id, type: "todo_list", items: typeof raw.text === "string" ? [raw.text] : [] };
334245
- case "commandExecution":
334246
- return {
334247
- id,
334248
- type: "command_execution",
334249
- command: typeof raw.command === "string" ? raw.command : "",
334250
- aggregated_output: typeof raw.aggregatedOutput === "string" ? raw.aggregatedOutput : null,
334251
- exit_code: typeof raw.exitCode === "number" ? raw.exitCode : null,
334252
- status: typeof raw.status === "string" ? raw.status : undefined
334253
- };
334254
- case "fileChange":
334255
- return {
334256
- id,
334257
- type: "file_change",
334258
- changes: Array.isArray(raw.changes) ? raw.changes.flatMap((change) => {
334259
- if (!change || typeof change !== "object")
334260
- return [];
334261
- const value = change;
334262
- const kindValue = value.kind;
334263
- const kind = typeof kindValue === "string" ? kindValue : kindValue && typeof kindValue === "object" ? kindValue.type : undefined;
334264
- return [
334265
- {
334266
- kind: typeof kind === "string" ? kind : "update",
334267
- path: typeof value.path === "string" ? value.path : ""
334268
- }
334269
- ];
334270
- }) : [],
334271
- status: typeof raw.status === "string" ? raw.status : undefined
334272
- };
334273
- case "mcpToolCall":
334274
- return {
334275
- id,
334276
- type: "mcp_tool_call",
334277
- server: typeof raw.server === "string" ? raw.server : "",
334278
- tool: typeof raw.tool === "string" ? raw.tool : "",
334279
- arguments: raw.arguments,
334280
- status: typeof raw.status === "string" ? raw.status : undefined,
334281
- result: raw.result,
334282
- error: raw.error
334283
- };
334284
- case "webSearch":
334285
- return { id, type: "web_search", query: typeof raw.query === "string" ? raw.query : "" };
334286
- default:
334287
- return {
334288
- id,
334289
- type: "unknown",
334290
- originalType: typeof raw.type === "string" ? raw.type : undefined,
334291
- value: raw
334292
- };
334293
- }
334294
- }
334295
- function normalizeUsage(raw) {
334296
- if (!raw || typeof raw !== "object")
334297
- return;
334298
- const value = raw;
334299
- return {
334300
- input_tokens: typeof value.inputTokens === "number" ? value.inputTokens : 0,
334301
- cached_input_tokens: typeof value.cachedInputTokens === "number" ? value.cachedInputTokens : 0,
334302
- cache_write_input_tokens: typeof value.cacheWriteInputTokens === "number" ? value.cacheWriteInputTokens : 0,
334303
- output_tokens: typeof value.outputTokens === "number" ? value.outputTokens : 0,
334304
- reasoning_output_tokens: typeof value.reasoningOutputTokens === "number" ? value.reasoningOutputTokens : 0
333433
+ function runtimeCatalogSection(provider) {
333434
+ const cached = mergedSections.get(provider);
333435
+ if (cached)
333436
+ return cached;
333437
+ const merged = {
333438
+ ...SNAPSHOT[provider]?.models ?? {},
333439
+ ...live?.[provider]?.models ?? {}
334305
333440
  };
333441
+ mergedSections.set(provider, merged);
333442
+ return merged;
334306
333443
  }
334307
- function subtractUsage(total, previous) {
334308
- return {
334309
- input_tokens: Math.max(0, total.input_tokens - (previous?.input_tokens ?? 0)),
334310
- cached_input_tokens: Math.max(0, total.cached_input_tokens - (previous?.cached_input_tokens ?? 0)),
334311
- cache_write_input_tokens: Math.max(0, total.cache_write_input_tokens - (previous?.cache_write_input_tokens ?? 0)),
334312
- output_tokens: Math.max(0, total.output_tokens - (previous?.output_tokens ?? 0)),
334313
- reasoning_output_tokens: Math.max(0, total.reasoning_output_tokens - (previous?.reasoning_output_tokens ?? 0))
334314
- };
333444
+ function runtimeCatalogModel(provider, modelId) {
333445
+ return runtimeCatalogSection(provider)[modelId];
334315
333446
  }
334316
-
334317
- class AppServerCodexThread {
334318
- client;
334319
- id;
334320
- get version() {
334321
- return this.client.version;
334322
- }
334323
- activeTurnId = null;
334324
- activePush = null;
334325
- activeFinish = null;
334326
- activeFail = null;
334327
- latestTotalUsage;
334328
- completedTotalUsage;
334329
- emittedThreadStart = false;
334330
- unsubscribe;
334331
- unsubscribeClose;
334332
- turnWaiters = [];
334333
- constructor(client, threadId) {
334334
- this.client = client;
334335
- this.id = threadId;
334336
- this.unsubscribe = client.onNotification((notification) => this.handleNotification(notification));
334337
- this.unsubscribeClose = client.onClose((error) => this.activeFail?.(error));
334338
- }
334339
- async runStreamed(input) {
334340
- if (this.activePush)
334341
- throw new Error("Codex turn already active");
334342
- const pending = [];
334343
- let wake = null;
334344
- let finished = false;
334345
- let failure = null;
334346
- const push = (event) => {
334347
- pending.push(event);
334348
- wake?.();
334349
- wake = null;
334350
- };
334351
- const finish = () => {
334352
- finished = true;
334353
- wake?.();
334354
- wake = null;
334355
- };
334356
- this.activePush = push;
334357
- this.activeFinish = finish;
334358
- this.activeFail = (error) => {
334359
- failure = error;
334360
- this.activePush = null;
334361
- this.activeFinish = null;
334362
- finish();
334363
- };
334364
- if (!this.emittedThreadStart) {
334365
- this.emittedThreadStart = true;
334366
- push({ type: "thread.started", thread_id: this.id });
334367
- }
333447
+ async function refreshRuntimeModelCatalog(opts) {
333448
+ const maxAge = opts.maxAgeMs ?? RUNTIME_CATALOG_TTL_MS;
333449
+ if (live && Date.now() - liveAt < maxAge)
333450
+ return true;
333451
+ if (inFlight)
333452
+ return inFlight;
333453
+ const doFetch = opts.fetchImpl ?? fetch;
333454
+ inFlight = (async () => {
334368
333455
  try {
334369
- const response = await this.client.request("turn/start", {
334370
- threadId: this.id,
334371
- input: textInput(input)
333456
+ const headers = {};
333457
+ if (opts.apiKey)
333458
+ headers.Authorization = `Bearer ${opts.apiKey}`;
333459
+ if (opts.agentId)
333460
+ headers["X-Agent-ID"] = opts.agentId;
333461
+ const res = await doFetch(`${opts.apiUrl}/api/models-catalog`, {
333462
+ headers,
333463
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
334372
333464
  });
334373
- if (!finished)
334374
- this.setActiveTurn(response.turn.id);
334375
- } catch (error) {
334376
- this.activePush = null;
334377
- this.activeFinish = null;
334378
- this.activeFail = null;
334379
- finish();
334380
- throw error;
334381
- }
334382
- const events = async function* () {
334383
- while (!finished || pending.length > 0) {
334384
- if (pending.length === 0) {
334385
- await new Promise((resolve2) => {
334386
- wake = resolve2;
334387
- });
334388
- continue;
334389
- }
334390
- yield pending.shift();
334391
- }
334392
- if (failure)
334393
- throw failure;
334394
- };
334395
- return { events: events() };
334396
- }
334397
- async steer(input) {
334398
- const turnId = this.activeTurnId ?? await new Promise((resolve2, reject) => this.turnWaiters.push({ resolve: resolve2, reject }));
334399
- await this.client.request("turn/steer", {
334400
- threadId: this.id,
334401
- expectedTurnId: turnId,
334402
- input: textInput(input)
334403
- });
334404
- }
334405
- async interrupt() {
334406
- if (!this.activeTurnId)
334407
- return;
334408
- await this.client.request("turn/interrupt", {
334409
- threadId: this.id,
334410
- turnId: this.activeTurnId
334411
- });
334412
- }
334413
- async close() {
334414
- for (const waiter of this.turnWaiters.splice(0)) {
334415
- waiter.reject(new Error("Codex session has completed"));
334416
- }
334417
- this.unsubscribe();
334418
- this.unsubscribeClose();
334419
- await this.client.close();
334420
- }
334421
- handleNotification(notification) {
334422
- const params = notification.params && typeof notification.params === "object" ? notification.params : {};
334423
- if (params.threadId !== undefined && params.threadId !== this.id)
334424
- return;
334425
- const push = this.activePush;
334426
- if (!push)
334427
- return;
334428
- switch (notification.method) {
334429
- case "turn/started": {
334430
- const turn = params.turn;
334431
- if (typeof turn?.id === "string")
334432
- this.setActiveTurn(turn.id);
334433
- push({ type: "turn.started", turn_id: this.activeTurnId ?? undefined });
334434
- break;
334435
- }
334436
- case "item/started":
334437
- case "item/completed": {
334438
- if (!params.item || typeof params.item !== "object")
334439
- break;
334440
- push({
334441
- type: notification.method === "item/started" ? "item.started" : "item.completed",
334442
- item: normalizeAppServerItem(params.item)
334443
- });
334444
- break;
334445
- }
334446
- case "item/agentMessage/delta":
334447
- if (typeof params.itemId === "string" && typeof params.delta === "string") {
334448
- push({ type: "message.delta", item_id: params.itemId, delta: params.delta });
334449
- }
334450
- break;
334451
- case "thread/tokenUsage/updated": {
334452
- const tokenUsage = params.tokenUsage;
334453
- this.latestTotalUsage = normalizeUsage(tokenUsage?.total);
334454
- break;
334455
- }
334456
- case "error": {
334457
- const error = params.error;
334458
- if (typeof error?.message === "string") {
334459
- push({
334460
- type: "error",
334461
- message: error.message,
334462
- willRetry: params.willRetry === true,
334463
- codexErrorInfo: typeof error.codexErrorInfo === "string" ? error.codexErrorInfo : null
334464
- });
334465
- }
334466
- break;
334467
- }
334468
- case "turn/completed": {
334469
- const turn = params.turn;
334470
- if (typeof turn?.id === "string" && this.activeTurnId && turn.id !== this.activeTurnId)
334471
- break;
334472
- const usage = this.latestTotalUsage ? subtractUsage(this.latestTotalUsage, this.completedTotalUsage) : undefined;
334473
- if (this.latestTotalUsage)
334474
- this.completedTotalUsage = this.latestTotalUsage;
334475
- if (turn?.status === "failed") {
334476
- push({
334477
- type: "turn.failed",
334478
- error: {
334479
- message: typeof turn.error?.message === "string" ? turn.error.message : "Codex turn failed",
334480
- codexErrorInfo: typeof turn.error?.codexErrorInfo === "string" ? turn.error.codexErrorInfo : null
334481
- },
334482
- usage
334483
- });
334484
- } else if (turn?.status === "interrupted") {
334485
- push({ type: "turn.interrupted", usage });
334486
- } else {
334487
- push({ type: "turn.completed", usage });
334488
- }
334489
- this.activeTurnId = null;
334490
- for (const waiter of this.turnWaiters.splice(0)) {
334491
- waiter.reject(new Error("Codex turn has completed"));
334492
- }
334493
- this.activePush = null;
334494
- this.activeFail = null;
334495
- this.activeFinish?.();
334496
- this.activeFinish = null;
334497
- break;
334498
- }
334499
- }
334500
- }
334501
- setActiveTurn(turnId) {
334502
- this.activeTurnId = turnId;
334503
- for (const waiter of this.turnWaiters.splice(0))
334504
- waiter.resolve(turnId);
334505
- }
334506
- }
334507
-
334508
- class CodexSession {
334509
- thread;
334510
- config;
334511
- agentsMdHandle;
334512
- resolvedModel;
334513
- contextWindow;
334514
- skillsDir;
334515
- summarizeDeps;
334516
- listeners = [];
334517
- eventQueue = [];
334518
- logFileHandle;
334519
- startedAt = Date.now();
334520
- completionPromise;
334521
- resolveCompletion;
334522
- abortController = null;
334523
- abortReason = "cancelled";
334524
- queuedPrompts = [];
334525
- transcript = [];
334526
- abortRef = { current: null };
334527
- _sessionId;
334528
- numTurns = 0;
334529
- accumulatedUsage = null;
334530
- aborted = false;
334531
- settled = false;
334532
- acceptsSteering = true;
334533
- errorTracker = new SessionErrorTracker;
334534
- appliedReasoningEffort;
334535
- pendingResult = null;
334536
- constructor(thread, config, agentsMdHandle, resolvedModel, initialEvents = [], skillsDir, summarizeDeps = {}) {
334537
- this.thread = thread;
334538
- this.config = config;
334539
- this.agentsMdHandle = agentsMdHandle;
334540
- this.resolvedModel = resolvedModel;
334541
- this.contextWindow = getCodexContextWindow(resolvedModel);
334542
- this.skillsDir = skillsDir ?? process.env.CODEX_SKILLS_DIR ?? join2(codexUserHome(), ".codex", "skills");
334543
- this.summarizeDeps = summarizeDeps;
334544
- this.logFileHandle = Bun.file(config.logFile).writer();
334545
- const reasoningApplication = applyReasoningEffort("codex", resolvedModel, config.reasoningEffort);
334546
- this.appliedReasoningEffort = reasoningApplication.kind === "codex-config" ? config.reasoningEffort ?? null : null;
334547
- this.completionPromise = new Promise((resolve2) => {
334548
- this.resolveCompletion = resolve2;
334549
- });
334550
- if (config.taskId && config.apiUrl && config.apiKey) {
334551
- this.listeners.push(createCodexSwarmEventHandler({
334552
- apiUrl: config.apiUrl,
334553
- apiKey: config.apiKey,
334554
- agentId: config.agentId,
334555
- taskId: config.taskId,
334556
- abortRef: this.abortRef
334557
- }));
334558
- }
334559
- for (const event of initialEvents) {
334560
- this.emit(event);
334561
- }
334562
- this.runSession();
334563
- }
334564
- get sessionId() {
334565
- return this._sessionId ?? this.thread.id ?? undefined;
334566
- }
334567
- onEvent(listener) {
334568
- this.listeners.push(listener);
334569
- for (const event of this.eventQueue) {
334570
- listener(event);
334571
- }
334572
- this.eventQueue.length = 0;
334573
- }
334574
- async waitForCompletion() {
334575
- return this.completionPromise;
334576
- }
334577
- emitTransportStderr(line) {
334578
- this.emit({ type: "raw_stderr", content: `${line}
334579
- ` });
334580
- }
334581
- async abort(reason) {
334582
- if (this.aborted || this.settled)
334583
- return;
334584
- this.aborted = true;
334585
- this.abortReason = reason ?? "cancelled";
334586
- if (this.abortController) {
334587
- this.abortController.abort(this.abortReason);
334588
- return;
334589
- }
334590
- try {
334591
- await this.thread.interrupt();
334592
- } catch (error) {
334593
- this.emit({
334594
- type: "raw_stderr",
334595
- content: `[codex] Failed to interrupt turn: ${String(error)}
334596
- `
334597
- });
334598
- }
334599
- }
334600
- async deliverSteering({ mode, text }) {
334601
- if (!this.acceptsSteering || this.settled || this.aborted) {
334602
- return { delivered: false, reason: "Codex session has completed" };
334603
- }
334604
- if (mode === "queue") {
334605
- return new Promise((resolve2) => this.queuedPrompts.push({ text, resolve: resolve2 }));
334606
- }
334607
- try {
334608
- await this.thread.steer(text);
334609
- return { delivered: true, mode: "steer" };
334610
- } catch (error) {
334611
- return { delivered: false, reason: scrubSecrets(String(error)) };
334612
- }
334613
- }
334614
- emit(event) {
334615
- const scrubbed = JSON.parse(scrubSecrets(JSON.stringify(event)));
334616
- try {
334617
- this.logFileHandle.write(`${JSON.stringify({ ...scrubbed, timestamp: new Date().toISOString() })}
334618
- `);
334619
- } catch {}
334620
- if (this.listeners.length > 0) {
334621
- for (const listener of this.listeners) {
334622
- try {
334623
- listener(scrubbed);
334624
- } catch {}
334625
- }
334626
- } else {
334627
- this.eventQueue.push(scrubbed);
334628
- }
334629
- }
334630
- settle(result) {
334631
- if (this.settled)
334632
- return;
334633
- this.settled = true;
334634
- for (const queued of this.queuedPrompts.splice(0)) {
334635
- queued.resolve({
334636
- delivered: false,
334637
- reason: "Codex session ended before the queued turn started"
334638
- });
334639
- }
334640
- this.pendingResult = { ...result, appliedReasoningEffort: this.appliedReasoningEffort };
334641
- }
334642
- buildCostData(usage, isError) {
334643
- const inputTokens = usage?.input_tokens ?? 0;
334644
- const cachedInputTokens = usage?.cached_input_tokens ?? 0;
334645
- const outputTokens = usage?.output_tokens ?? 0;
334646
- const reasoningOutputTokens = usage?.reasoning_output_tokens ?? 0;
334647
- return {
334648
- sessionId: "",
334649
- taskId: this.config.taskId,
334650
- agentId: this.config.agentId,
334651
- totalCostUsd: computeCodexCostUsd(this.resolvedModel, inputTokens, cachedInputTokens, outputTokens),
334652
- inputTokens,
334653
- outputTokens,
334654
- reasoningOutputTokens,
334655
- cacheReadTokens: cachedInputTokens,
334656
- cacheWriteTokens: usage?.cache_write_input_tokens,
334657
- durationMs: Date.now() - this.startedAt,
334658
- numTurns: this.numTurns,
334659
- model: this.resolvedModel,
334660
- isError,
334661
- provider: "codex"
334662
- };
334663
- }
334664
- toolNameForItem(item) {
334665
- switch (item.type) {
334666
- case "command_execution":
334667
- return "bash";
334668
- case "file_change": {
334669
- const first = item.changes[0];
334670
- if (!first)
334671
- return "Edit";
334672
- return first.kind === "add" ? "Write" : first.kind === "delete" ? "Delete" : "Edit";
334673
- }
334674
- case "mcp_tool_call":
334675
- return item.tool;
334676
- case "web_search":
334677
- return "WebSearch";
334678
- default:
334679
- return item.type;
334680
- }
334681
- }
334682
- toolArgsForItem(item) {
334683
- switch (item.type) {
334684
- case "command_execution":
334685
- return { command: item.command };
334686
- case "file_change":
334687
- return { changes: item.changes };
334688
- case "mcp_tool_call": {
334689
- const mcpItem = item;
334690
- return { server: mcpItem.server, tool: mcpItem.tool, arguments: mcpItem.arguments };
334691
- }
334692
- case "web_search":
334693
- return { query: item.query };
334694
- default:
334695
- return {};
334696
- }
334697
- }
334698
- isToolItem(item) {
334699
- return item.type === "command_execution" || item.type === "file_change" || item.type === "mcp_tool_call" || item.type === "web_search";
334700
- }
334701
- shortenItemResult(item) {
334702
- switch (item.type) {
334703
- case "command_execution": {
334704
- const cmd = item;
334705
- const stdout = (cmd.aggregated_output ?? "").slice(0, 500);
334706
- return `exit=${cmd.exit_code ?? "?"} status=${cmd.status ?? "?"} stdout=${stdout}`;
334707
- }
334708
- case "file_change": {
334709
- const fc = item;
334710
- const summarised = (fc.changes ?? []).slice(0, 5).map((c) => `${c.kind}:${c.path}`).join(",");
334711
- return `changes=[${summarised}]`;
334712
- }
334713
- case "mcp_tool_call": {
334714
- const mcp = item;
334715
- return `server=${mcp.server} tool=${mcp.tool} status=${mcp.status ?? "?"}`;
334716
- }
334717
- case "web_search": {
334718
- const ws = item;
334719
- return `query=${(ws.query ?? "").slice(0, 200)}`;
334720
- }
334721
- default:
334722
- return JSON.stringify(item).slice(0, 500);
334723
- }
334724
- }
334725
- handleEvent(event) {
334726
- this.emit({ type: "raw_log", content: JSON.stringify(event) });
334727
- switch (event.type) {
334728
- case "thread.started": {
334729
- this._sessionId = event.thread_id;
334730
- const codexVersion = this.thread.version ?? readPkgVersion("@openai/codex");
334731
- this.emit({
334732
- type: "session_init",
334733
- sessionId: event.thread_id,
334734
- provider: "codex",
334735
- ...codexVersion ? { harnessVariantMeta: { version: codexVersion } } : {}
334736
- });
334737
- break;
334738
- }
334739
- case "turn.started": {
334740
- this.numTurns += 1;
334741
- break;
334742
- }
334743
- case "item.started": {
334744
- if (this.isToolItem(event.item)) {
334745
- this.emit({
334746
- type: "tool_start",
334747
- toolCallId: event.item.id,
334748
- toolName: this.toolNameForItem(event.item),
334749
- args: this.toolArgsForItem(event.item)
334750
- });
334751
- this.transcript.push(`Tool[${this.toolNameForItem(event.item)}] started: ${JSON.stringify(this.toolArgsForItem(event.item)).slice(0, 500)}`);
334752
- }
334753
- break;
334754
- }
334755
- case "item.updated": {
334756
- const updatedItem = event.item;
334757
- if (updatedItem.type === "agent_message") {
334758
- const msg = updatedItem;
334759
- if (msg.text) {
334760
- this.emit({
334761
- type: "custom",
334762
- name: "codex.message_delta",
334763
- data: { itemId: updatedItem.id, text: msg.text }
334764
- });
334765
- }
334766
- }
334767
- break;
334768
- }
334769
- case "message.delta": {
334770
- this.emit({
334771
- type: "custom",
334772
- name: "codex.message_delta",
334773
- data: { itemId: event.item_id, text: event.delta }
334774
- });
334775
- break;
334776
- }
334777
- case "item.completed": {
334778
- const { item } = event;
334779
- if (this.isToolItem(item)) {
334780
- this.emit({
334781
- type: "tool_end",
334782
- toolCallId: item.id,
334783
- toolName: this.toolNameForItem(item),
334784
- result: item
334785
- });
334786
- this.transcript.push(`Tool[${this.toolNameForItem(item)}] completed: ${this.shortenItemResult(item)}`);
334787
- break;
334788
- }
334789
- switch (item.type) {
334790
- case "agent_message": {
334791
- const msg = item;
334792
- if (msg.text) {
334793
- this.emit({ type: "message", role: "assistant", content: msg.text });
334794
- this.transcript.push(`Assistant: ${msg.text}`);
334795
- }
334796
- break;
334797
- }
334798
- case "reasoning": {
334799
- const r = item;
334800
- const summary = Array.isArray(r.summary) ? r.summary.join(`
334801
- `) : r.summary;
334802
- const content = Array.isArray(r.content) ? r.content.join(`
334803
- `) : undefined;
334804
- const text = r.text || summary || content || "";
334805
- if (text) {
334806
- this.emit({
334807
- type: "custom",
334808
- name: "codex.reasoning",
334809
- data: { itemId: r.id, text }
334810
- });
334811
- }
334812
- break;
334813
- }
334814
- case "todo_list": {
334815
- const todo = item;
334816
- this.emit({
334817
- type: "custom",
334818
- name: "codex.todo_list",
334819
- data: { itemId: todo.id, items: todo.items ?? [] }
334820
- });
334821
- break;
334822
- }
334823
- case "error": {
334824
- const errItem = item;
334825
- this.emit({
334826
- type: "error",
334827
- message: this.formatTerminalError(errItem.message).message
334828
- });
334829
- break;
334830
- }
334831
- }
334832
- break;
334833
- }
334834
- case "turn.completed": {
334835
- this.accountUsage(event.usage);
334836
- break;
334837
- }
334838
- case "turn.failed": {
334839
- this.accountUsage(event.usage);
334840
- const { message } = this.formatTerminalError(event.error.message, event.error.codexErrorInfo);
334841
- this.emit({ type: "error", message });
334842
- break;
334843
- }
334844
- case "turn.interrupted":
334845
- this.accountUsage(event.usage);
334846
- break;
334847
- case "error": {
334848
- const { message } = this.formatTerminalError(event.message, event.codexErrorInfo);
334849
- if (event.willRetry === true) {
334850
- this.emit({ type: "raw_stderr", content: `[codex] ${message} (retrying)
334851
- ` });
334852
- } else {
334853
- this.emit({ type: "error", message });
334854
- }
334855
- break;
334856
- }
334857
- }
334858
- }
334859
- accountUsage(usage) {
334860
- if (!usage)
334861
- return;
334862
- this.accumulatedUsage = this.accumulatedUsage ? {
334863
- input_tokens: this.accumulatedUsage.input_tokens + usage.input_tokens,
334864
- cached_input_tokens: this.accumulatedUsage.cached_input_tokens + usage.cached_input_tokens,
334865
- cache_write_input_tokens: this.accumulatedUsage.cache_write_input_tokens + usage.cache_write_input_tokens,
334866
- output_tokens: this.accumulatedUsage.output_tokens + usage.output_tokens,
334867
- reasoning_output_tokens: this.accumulatedUsage.reasoning_output_tokens + usage.reasoning_output_tokens
334868
- } : usage;
334869
- const contextUsed = computeContextUsedUnified({
334870
- inputTokens: usage.input_tokens,
334871
- cacheReadTokens: 0,
334872
- cacheCreateTokens: 0,
334873
- outputTokens: usage.output_tokens
334874
- });
334875
- this.emit({
334876
- type: "context_usage",
334877
- contextUsedTokens: contextUsed,
334878
- contextTotalTokens: this.contextWindow,
334879
- contextPercent: clampContextPercent(contextUsed, this.contextWindow) ?? 0,
334880
- outputTokens: usage.output_tokens,
334881
- contextFormula: CONTEXT_FORMULA
334882
- });
334883
- }
334884
- formatTerminalError(raw, codexErrorInfo) {
334885
- const normalized = `${codexErrorInfo ?? ""} ${raw}`.toLowerCase();
334886
- const overflowPatterns = [
334887
- "context length exceeded",
334888
- "maximum context length",
334889
- "too many tokens",
334890
- "input too long",
334891
- "request too large",
334892
- "context_length_exceeded",
334893
- "contextwindowexceeded"
334894
- ];
334895
- if (overflowPatterns.some((p) => normalized.includes(p))) {
334896
- return {
334897
- message: `[context-overflow] Codex turn exceeded the model's context window for ${this.resolvedModel} (${this.contextWindow.toLocaleString()} tokens). Codex does not auto-compact conversation history like Claude does — start a fresh task or split the work into smaller turns. Original error: ${raw}`,
334898
- category: "context_overflow"
334899
- };
334900
- }
334901
- const usageLimitPatterns = ["usage limit", "upgrade to pro", "usagelimitexceeded"];
334902
- if (usageLimitPatterns.some((p) => normalized.includes(p))) {
334903
- return {
334904
- message: `[usage-limit] Codex account quota exhausted — upgrade plan or wait for monthly reset. Original error: ${raw}`,
334905
- category: "usage_limit"
334906
- };
334907
- }
334908
- const rateLimitPatterns = [
334909
- "rate limit",
334910
- "rate_limit",
334911
- "ratelimit",
334912
- "too many requests",
334913
- "http 429",
334914
- " 429 "
334915
- ];
334916
- if (rateLimitPatterns.some((p) => normalized.includes(p))) {
334917
- return {
334918
- message: `[rate-limit] Codex API rate limit hit. Original error: ${raw}`,
334919
- category: "rate_limit"
334920
- };
334921
- }
334922
- const authPatterns = [
334923
- "unauthorized",
334924
- "http 401",
334925
- " 401 ",
334926
- "invalid api key",
334927
- "invalid_api_key",
334928
- "missing api key",
334929
- "no api key",
334930
- "authentication failed",
334931
- "failed to refresh token",
334932
- "invalid 'refresh_token'"
334933
- ];
334934
- if (authPatterns.some((p) => normalized.includes(p))) {
334935
- return {
334936
- message: `[auth-error] Codex authentication failed — check OPENAI_API_KEY or ChatGPT login. Original error: ${raw}`,
334937
- category: "authentication_failed"
334938
- };
334939
- }
334940
- return { message: raw };
334941
- }
334942
- async runSession() {
334943
- this.abortController = new AbortController;
334944
- this.abortController.signal.addEventListener("abort", () => {
334945
- this.aborted = true;
334946
- if (typeof this.abortController?.signal.reason === "string") {
334947
- this.abortReason = this.abortController.signal.reason;
334948
- }
334949
- this.thread.interrupt().catch((error) => {
334950
- this.emit({
334951
- type: "raw_stderr",
334952
- content: `[codex] Failed to interrupt turn: ${String(error)}
334953
- `
334954
- });
334955
- });
334956
- }, { once: true });
334957
- this.abortRef.current = this.abortController;
334958
- let terminalError;
334959
- let sawTurnCompleted = false;
334960
- let sawTurnInterrupted = false;
334961
- try {
334962
- const resolvedPrompt = await resolveCodexPrompt(this.config.prompt, this.skillsDir, (event) => this.emit(event));
334963
- this.transcript = [`User: ${resolvedPrompt}`];
334964
- try {
334965
- let nextPrompt = resolvedPrompt;
334966
- let queuedPrompt;
334967
- while (nextPrompt !== undefined && !this.aborted && !terminalError && !sawTurnInterrupted) {
334968
- if (nextPrompt !== resolvedPrompt)
334969
- this.transcript.push(`User: ${nextPrompt}`);
334970
- const streamed = await this.thread.runStreamed(nextPrompt);
334971
- if (queuedPrompt) {
334972
- this.queuedPrompts.shift();
334973
- queuedPrompt.resolve({ delivered: true, mode: "queue" });
334974
- }
334975
- for await (const event of streamed.events) {
334976
- if (event.type === "turn.failed" || event.type === "turn.interrupted" || event.type === "error" && event.willRetry !== true) {
334977
- this.acceptsSteering = false;
334978
- }
334979
- this.handleEvent(event);
334980
- if (event.type === "turn.completed") {
334981
- sawTurnCompleted = true;
334982
- }
334983
- if (event.type === "turn.interrupted") {
334984
- sawTurnInterrupted = true;
334985
- }
334986
- if (event.type === "turn.failed" && !terminalError) {
334987
- terminalError = this.formatTerminalError(event.error.message, event.error.codexErrorInfo);
334988
- this.errorTracker.processCodexUsageLimitMessage(event.error.message);
334989
- }
334990
- if (event.type === "error" && event.willRetry !== true && !terminalError) {
334991
- terminalError = this.formatTerminalError(event.message, event.codexErrorInfo);
334992
- this.errorTracker.processCodexUsageLimitMessage(event.message);
334993
- }
334994
- }
334995
- queuedPrompt = this.queuedPrompts[0];
334996
- nextPrompt = queuedPrompt?.text;
334997
- }
334998
- } catch (err) {
334999
- this.acceptsSteering = false;
335000
- if (this.aborted || err instanceof Error && err.name === "AbortError") {
335001
- const cost2 = this.buildCostData(this.accumulatedUsage, true);
335002
- this.emit({ type: "result", cost: cost2, isError: true, errorCategory: "cancelled" });
335003
- this.settle({
335004
- exitCode: 130,
335005
- sessionId: this._sessionId,
335006
- cost: cost2,
335007
- isError: true,
335008
- failureReason: this.abortReason
335009
- });
335010
- return;
335011
- }
335012
- if (terminalError) {
335013
- const cost2 = this.buildCostData(this.accumulatedUsage, true);
335014
- this.emit({
335015
- type: "result",
335016
- cost: cost2,
335017
- isError: true,
335018
- errorCategory: terminalError.category ?? "turn_failed"
335019
- });
335020
- this.settle({
335021
- exitCode: 1,
335022
- sessionId: this._sessionId,
335023
- cost: cost2,
335024
- isError: true,
335025
- failureReason: terminalError.message,
335026
- rateLimitResetAt: this.errorTracker.getRateLimitResetAt(),
335027
- rateLimitWindows: this.errorTracker.getRateLimitWindows()
335028
- });
335029
- return;
335030
- }
335031
- throw err;
335032
- }
335033
- this.acceptsSteering = false;
335034
- if (this.aborted || sawTurnInterrupted) {
335035
- const cost2 = this.buildCostData(this.accumulatedUsage, true);
335036
- this.emit({ type: "result", cost: cost2, isError: true, errorCategory: "cancelled" });
335037
- this.settle({
335038
- exitCode: 130,
335039
- sessionId: this._sessionId,
335040
- cost: cost2,
335041
- isError: true,
335042
- failureReason: this.aborted ? this.abortReason : "Codex turn interrupted"
335043
- });
335044
- return;
335045
- }
335046
- const isError = Boolean(terminalError) || !sawTurnCompleted;
335047
- const cost = this.buildCostData(this.accumulatedUsage, isError);
335048
- this.emit({
335049
- type: "result",
335050
- cost,
335051
- isError,
335052
- errorCategory: terminalError ? terminalError.category ?? "turn_failed" : undefined
335053
- });
335054
- this.settle({
335055
- exitCode: isError ? 1 : 0,
335056
- sessionId: this._sessionId,
335057
- cost,
335058
- isError,
335059
- failureReason: terminalError?.message,
335060
- rateLimitResetAt: this.errorTracker.getRateLimitResetAt(),
335061
- rateLimitWindows: this.errorTracker.getRateLimitWindows()
335062
- });
335063
- } catch (err) {
335064
- this.acceptsSteering = false;
335065
- const message = err instanceof Error ? err.message : String(err);
335066
- this.emit({ type: "raw_stderr", content: `[codex] Error: ${message}
335067
- ` });
335068
- this.emit({ type: "error", message });
335069
- const cost = this.buildCostData(this.accumulatedUsage, true);
335070
- this.emit({ type: "result", cost, isError: true, errorCategory: "exception" });
335071
- this.settle({
335072
- exitCode: 1,
335073
- sessionId: this._sessionId,
335074
- cost,
335075
- isError: true,
335076
- failureReason: message,
335077
- rateLimitResetAt: this.errorTracker.getRateLimitResetAt(),
335078
- rateLimitWindows: this.errorTracker.getRateLimitWindows()
335079
- });
335080
- } finally {
335081
- const sessionWasAborted = this.aborted || this.abortController?.signal.aborted === true || this.pendingResult?.exitCode === 130;
335082
- if (process.env.SKIP_SESSION_SUMMARY !== "1" && !sessionWasAborted) {
335083
- try {
335084
- await this.summarizeAtEnd();
335085
- } catch (err) {
335086
- console.error("session_summary failed (codex):", err);
335087
- }
335088
- } else if (sessionWasAborted) {
335089
- console.debug("[codex] session aborted — skipping session_summary");
335090
- } else {
335091
- console.debug("session_summary skipped (codex): SKIP_SESSION_SUMMARY is set");
335092
- }
335093
- this.abortRef.current = null;
335094
- try {
335095
- await this.thread.close();
335096
- } catch (error) {
335097
- this.emit({
335098
- type: "raw_stderr",
335099
- content: `[codex] Failed to close app-server: ${String(error)}
335100
- `
335101
- });
335102
- }
335103
- try {
335104
- await this.logFileHandle.end();
335105
- } catch {}
335106
- await this.agentsMdHandle.cleanup();
335107
- const finalResult = this.pendingResult ?? {
335108
- exitCode: 1,
335109
- sessionId: this._sessionId,
335110
- cost: this.buildCostData(this.accumulatedUsage, true),
335111
- isError: true,
335112
- failureReason: "session did not settle"
335113
- };
335114
- this.resolveCompletion(finalResult);
335115
- }
335116
- }
335117
- async summarizeAtEnd() {
335118
- const transcriptStr = this.transcript.join(`
335119
- `).slice(-20000);
335120
- const { agentId, taskId, apiUrl, apiKey } = this.config;
335121
- if (!agentId || !taskId || !apiUrl || !apiKey) {
335122
- const missing = [
335123
- !agentId && "agent id",
335124
- !taskId && "task id",
335125
- !apiUrl && "API URL",
335126
- !apiKey && "API key"
335127
- ].filter(Boolean);
335128
- console.warn(`session_summary skipped (codex): missing ${missing.join(", ")}`);
335129
- return;
335130
- }
335131
- if (transcriptStr.length <= 100) {
335132
- console.warn(`session_summary skipped (codex): transcript too short (${transcriptStr.length} chars)`);
335133
- return;
335134
- }
335135
- const _runSummarize = this.summarizeDeps.runSummarize ?? summarizeSession;
335136
- const _fetchRetrievals = this.summarizeDeps.fetchRetrievalsForTask ?? fetchRetrievalsForTask;
335137
- const _postRatings = this.summarizeDeps.postRatings ?? postRatings;
335138
- const _buildRatings = this.summarizeDeps.buildRatingsFromLlm ?? buildRatingsFromLlm;
335139
- const wantRatings = getMemoryRaterNames().includes("llm");
335140
- const retrievals = wantRatings ? await _fetchRetrievals({ apiUrl, apiKey, agentId, taskId }).catch(() => []) : [];
335141
- const result = await _runSummarize({
335142
- harness: "codex",
335143
- transcript: transcriptStr,
335144
- retrievals,
335145
- taskContext: {
335146
- sourceTaskId: taskId,
335147
- agentId,
335148
- prompt: this.config.prompt
335149
- },
335150
- apiUrl,
335151
- apiKey,
335152
- env: this.config.env
335153
- });
335154
- if (!result) {
335155
- console.warn("session_summary skipped (codex): summarizer returned no result");
335156
- return;
335157
- }
335158
- const summary = result.summary.trim();
335159
- if (summary.length <= 20 || summary.toLowerCase().includes("no significant learnings")) {
335160
- console.debug(`session_summary skipped (codex): summary failed quality gate (${summary.length} chars)`);
335161
- return;
335162
- }
335163
- const indexResp = await fetch(`${apiUrl}/api/memory/index`, {
335164
- method: "POST",
335165
- headers: {
335166
- "Content-Type": "application/json",
335167
- Authorization: `Bearer ${apiKey}`,
335168
- "X-Agent-ID": agentId
335169
- },
335170
- body: JSON.stringify({
335171
- scope: "agent",
335172
- source: "session_summary",
335173
- sourceTaskId: taskId,
335174
- content: summary,
335175
- name: "session-summary",
335176
- agentId
335177
- })
335178
- });
335179
- if (!indexResp.ok) {
335180
- const text = await indexResp.text().catch(() => "");
335181
- console.error("session_summary: /api/memory/index POST failed (codex):", indexResp.status, text);
335182
- return;
335183
- }
335184
- if (wantRatings && result.ratings && result.ratings.length > 0) {
335185
- const ratingEvents = _buildRatings(result.ratings, retrievals);
335186
- if (ratingEvents.length > 0) {
335187
- await _postRatings({
335188
- apiUrl,
335189
- apiKey,
335190
- agentId,
335191
- taskId,
335192
- events: ratingEvents
335193
- }).catch((err) => console.error("session_summary: postRatings failed (codex):", err));
335194
- }
335195
- }
335196
- }
335197
- }
335198
- async function createInProcessCodexSession(config, opts = {}) {
335199
- const agentsMdHandle = await writeCodexAgentsMd(config.cwd, config.systemPrompt);
335200
- try {
335201
- const resolvedModel = resolveCodexModel(config.model);
335202
- const preSessionEvents = [];
335203
- const bufferedEmit = (event) => {
335204
- preSessionEvents.push(event);
335205
- };
335206
- const mergedConfig = await buildCodexConfig(config, resolvedModel, bufferedEmit);
335207
- const authMode = await resolveCodexAuthMode(config, bufferedEmit);
335208
- const env = {
335209
- PATH: process.env.PATH ?? "",
335210
- HOME: process.env.HOME ?? "",
335211
- ...authMode !== "chatgpt" && process.env.OPENAI_API_KEY ? { OPENAI_API_KEY: process.env.OPENAI_API_KEY } : {},
335212
- ...process.env.NODE_EXTRA_CA_CERTS ? { NODE_EXTRA_CA_CERTS: process.env.NODE_EXTRA_CA_CERTS } : {},
335213
- CONTEXT_MODE_EXTERNAL_MCP_NUDGE_EVERY: CTX_MODE_NUDGE_EVERY,
335214
- ...config.env ?? {},
335215
- ...buildOtelTraceparentEnv(config.env ?? process.env),
335216
- SWARM_CODEX_APP_SERVER: "1"
335217
- };
335218
- if (authMode === "chatgpt")
335219
- delete env.OPENAI_API_KEY;
335220
- const codexPathOverride = process.env.CODEX_PATH_OVERRIDE;
335221
- if (config.resumeSessionId) {
335222
- console.warn("[codex-adapter] resumeSessionId ignored — native resume is disabled by deprecation plan");
335223
- }
335224
- let thread;
335225
- let liveSession;
335226
- if (opts.threadFactory) {
335227
- thread = await opts.threadFactory({
335228
- config,
335229
- resolvedModel,
335230
- env,
335231
- codexConfig: mergedConfig
335232
- });
335233
- } else {
335234
- const appServerFactory = opts.appServerFactory ?? ((options) => new CodexAppServer(options));
335235
- const client = appServerFactory({
335236
- ...codexPathOverride ? { codexPath: codexPathOverride } : {},
335237
- env,
335238
- onStderr: (line) => {
335239
- if (liveSession)
335240
- liveSession.emitTransportStderr(line);
335241
- else
335242
- bufferedEmit({ type: "raw_stderr", content: `${line}
335243
- ` });
335244
- }
335245
- });
335246
- try {
335247
- const response = await client.request("thread/start", {
335248
- model: resolvedModel,
335249
- cwd: config.cwd,
335250
- approvalPolicy: "never",
335251
- sandbox: "danger-full-access",
335252
- config: mergedConfig,
335253
- ephemeral: true
335254
- });
335255
- thread = new AppServerCodexThread(client, response.thread.id);
335256
- } catch (error) {
335257
- await client.close();
335258
- throw error;
335259
- }
335260
- }
335261
- const session = new CodexSession(thread, config, agentsMdHandle, resolvedModel, preSessionEvents, opts.skillsDir, opts.summarizeDeps ?? {});
335262
- liveSession = session;
335263
- return session;
335264
- } catch (err) {
335265
- await agentsMdHandle.cleanup();
335266
- throw err;
335267
- }
335268
- }
335269
- function resolveCodexRunnerArgv() {
335270
- const override = process.env.AGENT_SWARM_CODEX_RUNNER_ARGV;
335271
- if (override) {
335272
- try {
335273
- const parsed = JSON.parse(override);
335274
- if (Array.isArray(parsed) && parsed.every((s) => typeof s === "string")) {
335275
- return parsed;
335276
- }
335277
- } catch {}
335278
- }
335279
- const execPath = process.execPath;
335280
- const scriptArg = process.argv[1];
335281
- if (scriptArg && /\.(t|j)sx?$/.test(scriptArg)) {
335282
- return [execPath, scriptArg, "codex-session-runner"];
335283
- }
335284
- return [execPath, "codex-session-runner"];
335285
- }
335286
-
335287
- class CodexSubprocessSession {
335288
- proc;
335289
- listeners = [];
335290
- eventQueue = [];
335291
- completionPromise;
335292
- _sessionId;
335293
- finished = false;
335294
- nextControlId = 0;
335295
- pendingSteering = new Map;
335296
- constructor(config, skillsDir) {
335297
- const argv = resolveCodexRunnerArgv();
335298
- const payload = {
335299
- config,
335300
- skillsDir,
335301
- parentOtelEnv: buildOtelTraceparentEnv(config.env ?? process.env)
335302
- };
335303
- const apiKey = getApiKey();
335304
- this.proc = registerProcessGroup(Bun.spawn(argv, {
335305
- detached: detachedProcessGroup,
335306
- env: {
335307
- PATH: process.env.PATH ?? "",
335308
- HOME: process.env.HOME ?? "",
335309
- ...process.env.NODE_EXTRA_CA_CERTS ? { NODE_EXTRA_CA_CERTS: process.env.NODE_EXTRA_CA_CERTS } : {},
335310
- ...process.env.MCP_BASE_URL ? { MCP_BASE_URL: process.env.MCP_BASE_URL } : {},
335311
- ...apiKey ? { AGENT_SWARM_API_KEY: apiKey, API_KEY: apiKey } : {},
335312
- ...process.env.OPENAI_API_KEY ? { OPENAI_API_KEY: process.env.OPENAI_API_KEY } : {},
335313
- ...process.env.OPENROUTER_API_KEY ? { OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY } : {},
335314
- ...process.env.ANTHROPIC_API_KEY ? { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY } : {},
335315
- ...process.env.CODEX_PATH_OVERRIDE ? { CODEX_PATH_OVERRIDE: process.env.CODEX_PATH_OVERRIDE } : {},
335316
- ...process.env.CODEX_SKILLS_DIR ? { CODEX_SKILLS_DIR: process.env.CODEX_SKILLS_DIR } : {},
335317
- CONTEXT_MODE_EXTERNAL_MCP_NUDGE_EVERY: CTX_MODE_NUDGE_EVERY,
335318
- ...process.env.SKIP_SESSION_SUMMARY ? { SKIP_SESSION_SUMMARY: process.env.SKIP_SESSION_SUMMARY } : {},
335319
- MEMORY_RATERS: getMemoryRaterNames().join(",")
335320
- },
335321
- stdin: "pipe",
335322
- stdout: "pipe",
335323
- stderr: "pipe"
335324
- }));
335325
- const stdin = this.proc.stdin;
335326
- stdin.write(`${JSON.stringify(payload)}
335327
- `);
335328
- this.completionPromise = this.processStreams().finally(() => this.finishSteering());
335329
- }
335330
- get sessionId() {
335331
- return this._sessionId;
335332
- }
335333
- onEvent(listener) {
335334
- this.listeners.push(listener);
335335
- for (const event of this.eventQueue) {
335336
- listener(event);
335337
- }
335338
- this.eventQueue.length = 0;
335339
- }
335340
- async waitForCompletion() {
335341
- return this.completionPromise;
335342
- }
335343
- async abort(reason) {
335344
- if (this.finished)
335345
- return;
335346
- try {
335347
- this.writeControl({ kind: "abort", reason });
335348
- let timer;
335349
- try {
335350
- await Promise.race([
335351
- this.completionPromise,
335352
- new Promise((resolve2) => {
335353
- timer = setTimeout(resolve2, 2000);
335354
- })
335355
- ]);
335356
- } finally {
335357
- clearTimeout(timer);
335358
- }
335359
- } finally {
335360
- if (!this.finished)
335361
- await terminateProcessGroup(this.proc.pid);
335362
- }
335363
- }
335364
- async deliverSteering(delivery) {
335365
- if (this.finished)
335366
- return { delivered: false, reason: "Codex session has completed" };
335367
- const id = ++this.nextControlId;
335368
- return new Promise((resolve2) => {
335369
- const timer = delivery.mode === "queue" ? undefined : setTimeout(() => {
335370
- this.pendingSteering.delete(id);
335371
- resolve2({ delivered: false, reason: "Codex steering request timed out" });
335372
- }, 35000);
335373
- this.pendingSteering.set(id, { resolve: resolve2, timer });
335374
- try {
335375
- this.writeControl({ kind: "steer", id, delivery });
335376
- } catch (error) {
335377
- clearTimeout(timer);
335378
- this.pendingSteering.delete(id);
335379
- resolve2({ delivered: false, reason: scrubSecrets(String(error)) });
335380
- }
335381
- });
335382
- }
335383
- writeControl(command) {
335384
- this.proc.stdin.write(`${JSON.stringify(command)}
335385
- `);
335386
- }
335387
- finishSteering() {
335388
- this.finished = true;
335389
- for (const { resolve: resolve2, timer } of this.pendingSteering.values()) {
335390
- clearTimeout(timer);
335391
- resolve2({ delivered: false, reason: "Codex session has completed" });
335392
- }
335393
- this.pendingSteering.clear();
335394
- }
335395
- emit(event) {
335396
- event = JSON.parse(scrubSecrets(JSON.stringify(event)));
335397
- if (event.type === "session_init" && event.sessionId) {
335398
- this._sessionId = event.sessionId;
335399
- }
335400
- if (this.listeners.length > 0) {
335401
- for (const listener of this.listeners) {
335402
- try {
335403
- listener(event);
335404
- } catch {}
335405
- }
335406
- } else {
335407
- this.eventQueue.push(event);
335408
- }
335409
- }
335410
- async processStreams() {
335411
- let result = null;
335412
- let partial = "";
335413
- let stderrTail = "";
335414
- const stdoutPromise = (async () => {
335415
- const stdout = this.proc.stdout;
335416
- if (!stdout)
335417
- return;
335418
- const decoder = new TextDecoder;
335419
- for await (const chunk of stdout) {
335420
- partial += decoder.decode(chunk, { stream: true });
335421
- const parts = partial.split(`
335422
- `);
335423
- partial = parts.pop() ?? "";
335424
- for (const line of parts) {
335425
- const trimmed = line.trim();
335426
- if (!trimmed)
335427
- continue;
335428
- this.handleLine(trimmed, (r) => {
335429
- result = r;
335430
- });
335431
- }
335432
- }
335433
- partial += decoder.decode();
335434
- if (partial.trim()) {
335435
- this.handleLine(partial.trim(), (r) => {
335436
- result = r;
335437
- });
335438
- partial = "";
335439
- }
335440
- })();
335441
- const stderrPromise = (async () => {
335442
- const stderr = this.proc.stderr;
335443
- if (!stderr)
335444
- return;
335445
- const decoder = new TextDecoder;
335446
- let pending = "";
335447
- const emitStderr = (line) => {
335448
- const text = scrubSecrets(line);
335449
- stderrTail = (stderrTail + text).slice(-2000);
335450
- this.emit({ type: "raw_stderr", content: text });
335451
- };
335452
- for await (const chunk of stderr) {
335453
- pending += decoder.decode(chunk, { stream: true });
335454
- let newline = pending.indexOf(`
335455
- `);
335456
- while (newline !== -1) {
335457
- emitStderr(pending.slice(0, newline + 1));
335458
- pending = pending.slice(newline + 1);
335459
- newline = pending.indexOf(`
335460
- `);
335461
- }
335462
- }
335463
- pending += decoder.decode();
335464
- if (pending)
335465
- emitStderr(pending);
335466
- })();
335467
- await Promise.all([stdoutPromise, stderrPromise]);
335468
- const exitCode = await this.proc.exited;
335469
- this.finishSteering();
335470
- await terminateProcessGroup(this.proc.pid);
335471
- if (result) {
335472
- return result;
335473
- }
335474
- const stderrHint = stderrTail.trim() ? `: stderr: ${stderrTail.trim().slice(-500)}` : "";
335475
- return {
335476
- exitCode: exitCode ?? 1,
335477
- sessionId: this._sessionId,
335478
- isError: true,
335479
- failureReason: `codex subprocess exited (code=${exitCode ?? "?"}) without a structured result${stderrHint}`
335480
- };
335481
- }
335482
- handleLine(line, setResult) {
335483
- let msg;
335484
- try {
335485
- msg = JSON.parse(scrubSecrets(line));
333465
+ if (!res.ok)
333466
+ return false;
333467
+ const body = await res.json();
333468
+ if (!body || typeof body.providers !== "object" || body.providers === null)
333469
+ return false;
333470
+ setRuntimeModelCatalog(body.providers, Date.now(), body.source ?? "live");
333471
+ return true;
335486
333472
  } catch {
335487
- this.emit({ type: "raw_stderr", content: `${line}
335488
- ` });
335489
- return;
335490
- }
335491
- if (msg.kind === "event" && msg.event) {
335492
- this.emit(msg.event);
335493
- return;
335494
- }
335495
- if (msg.kind === "result" && msg.result) {
335496
- this.finishSteering();
335497
- setResult(msg.result);
335498
- return;
335499
- }
335500
- if (msg.kind === "steering-result" && msg.id !== undefined && msg.delivery) {
335501
- const pending = this.pendingSteering.get(msg.id);
335502
- if (pending) {
335503
- clearTimeout(pending.timer);
335504
- this.pendingSteering.delete(msg.id);
335505
- pending.resolve(msg.delivery);
335506
- }
335507
- return;
335508
- }
335509
- if (msg.kind === "error" && msg.message) {
335510
- this.emit({ type: "error", message: msg.message });
335511
- setResult({
335512
- exitCode: 1,
335513
- sessionId: this._sessionId,
335514
- isError: true,
335515
- failureReason: msg.message
335516
- });
335517
- return;
335518
- }
335519
- }
335520
- }
335521
-
335522
- class CodexAdapter {
335523
- name = "codex";
335524
- traits = {
335525
- hasMcp: true,
335526
- nativeSkillDiscovery: false,
335527
- hasLocalEnvironment: true,
335528
- steerModes: ["steer", "queue"]
335529
- };
335530
- skillsDir;
335531
- summarizeDeps;
335532
- appServerFactory;
335533
- threadFactory;
335534
- bypassSubprocess;
335535
- constructor(opts = {}) {
335536
- this.skillsDir = opts.skillsDir;
335537
- this.summarizeDeps = opts.summarizeDeps ?? {};
335538
- this.bypassSubprocess = opts.bypassSubprocess ?? false;
335539
- this.appServerFactory = opts.appServerFactory;
335540
- this.threadFactory = opts.threadFactory;
335541
- }
335542
- async createSession(config) {
335543
- if (this.bypassSubprocess) {
335544
- return createInProcessCodexSession(config, {
335545
- skillsDir: this.skillsDir,
335546
- summarizeDeps: this.summarizeDeps,
335547
- appServerFactory: this.appServerFactory,
335548
- threadFactory: this.threadFactory
335549
- });
333473
+ return false;
333474
+ } finally {
333475
+ inFlight = null;
335550
333476
  }
335551
- return new CodexSubprocessSession(config, this.skillsDir);
335552
- }
335553
- async canResume(_sessionId) {
335554
- return false;
335555
- }
335556
- formatCommand(commandName) {
335557
- return `/${commandName}`;
335558
- }
333477
+ })();
333478
+ return inFlight;
335559
333479
  }
335560
333480
 
335561
- export { codexUserHome, checkCodexCredentials, resolveCodexAuthMode, buildCodexConfig, CodexSession, createInProcessCodexSession, resolveCodexRunnerArgv, CodexAdapter };
333481
+ export { setRuntimeModelCatalog, runtimeCatalogSection, runtimeCatalogModel, refreshRuntimeModelCatalog };