@iislee/opencodex 2.11.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 (476) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +225 -0
  3. package/assets/architecture.png +0 -0
  4. package/assets/banner.png +0 -0
  5. package/assets/claude-code-models.gif +0 -0
  6. package/assets/codex-app-picker.png +0 -0
  7. package/bin/ocx.mjs +451 -0
  8. package/bin/package-main.mjs +9 -0
  9. package/gui/dist/assets/index-DTpMHS4F.js +67 -0
  10. package/gui/dist/assets/index-ZNVDE3C7.css +1 -0
  11. package/gui/dist/favicon.png +0 -0
  12. package/gui/dist/icons.svg +24 -0
  13. package/gui/dist/index.html +25 -0
  14. package/gui/dist/logo.png +0 -0
  15. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  16. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  17. package/gui/dist/provider-icons/antigravity.svg +1 -0
  18. package/gui/dist/provider-icons/claude-color.svg +1 -0
  19. package/gui/dist/provider-icons/claude.svg +1 -0
  20. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  21. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  22. package/gui/dist/provider-icons/copilot.svg +1 -0
  23. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  24. package/gui/dist/provider-icons/cursor.svg +2 -0
  25. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  26. package/gui/dist/provider-icons/discord.svg +1 -0
  27. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  28. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  29. package/gui/dist/provider-icons/gemini-color.svg +1 -0
  30. package/gui/dist/provider-icons/gemini.svg +1 -0
  31. package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
  32. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
  33. package/gui/dist/provider-icons/grok-color.svg +1 -0
  34. package/gui/dist/provider-icons/grok.svg +1 -0
  35. package/gui/dist/provider-icons/groq-color.svg +1 -0
  36. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  37. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  38. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  39. package/gui/dist/provider-icons/kiro.svg +14 -0
  40. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  41. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  42. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  43. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  44. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  45. package/gui/dist/provider-icons/openai.svg +1 -0
  46. package/gui/dist/provider-icons/opencode.svg +1 -0
  47. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  48. package/gui/dist/provider-icons/pi.svg +21 -0
  49. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  50. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  51. package/gui/dist/provider-icons/telegram.svg +1 -0
  52. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  53. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  54. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  55. package/package.json +102 -0
  56. package/src/AGENTS.md +28 -0
  57. package/src/adapters/anthropic-image-guard.ts +251 -0
  58. package/src/adapters/anthropic-image-normalize.ts +518 -0
  59. package/src/adapters/anthropic.ts +1003 -0
  60. package/src/adapters/azure.ts +36 -0
  61. package/src/adapters/base.ts +72 -0
  62. package/src/adapters/client-fingerprint.ts +59 -0
  63. package/src/adapters/cursor/arg-codec.ts +38 -0
  64. package/src/adapters/cursor/arg-normalize.ts +104 -0
  65. package/src/adapters/cursor/cursor-errors.ts +165 -0
  66. package/src/adapters/cursor/discovery.ts +276 -0
  67. package/src/adapters/cursor/effort-map.ts +127 -0
  68. package/src/adapters/cursor/exec-policy.ts +88 -0
  69. package/src/adapters/cursor/framing.ts +211 -0
  70. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  71. package/src/adapters/cursor/kv-store.ts +52 -0
  72. package/src/adapters/cursor/live-models.ts +153 -0
  73. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  74. package/src/adapters/cursor/live-transport.ts +1214 -0
  75. package/src/adapters/cursor/mcp-config.ts +42 -0
  76. package/src/adapters/cursor/mcp-manager.ts +333 -0
  77. package/src/adapters/cursor/message-mapper.ts +49 -0
  78. package/src/adapters/cursor/native-exec-common.ts +55 -0
  79. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  80. package/src/adapters/cursor/native-exec-fs.ts +329 -0
  81. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  82. package/src/adapters/cursor/native-exec-network.ts +43 -0
  83. package/src/adapters/cursor/native-exec-shell.ts +548 -0
  84. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  85. package/src/adapters/cursor/native-exec.ts +576 -0
  86. package/src/adapters/cursor/protobuf-events.ts +563 -0
  87. package/src/adapters/cursor/protobuf-request.ts +714 -0
  88. package/src/adapters/cursor/request-builder.ts +255 -0
  89. package/src/adapters/cursor/thread-continuity.ts +67 -0
  90. package/src/adapters/cursor/tool-definitions.ts +505 -0
  91. package/src/adapters/cursor/transport-retry.ts +132 -0
  92. package/src/adapters/cursor/transport.ts +57 -0
  93. package/src/adapters/cursor/types.ts +52 -0
  94. package/src/adapters/cursor.ts +196 -0
  95. package/src/adapters/google-antigravity-replay.ts +303 -0
  96. package/src/adapters/google-antigravity-wire.ts +108 -0
  97. package/src/adapters/google-errors.ts +85 -0
  98. package/src/adapters/google-http.ts +100 -0
  99. package/src/adapters/google-tool-schema.ts +173 -0
  100. package/src/adapters/google-truncation.ts +13 -0
  101. package/src/adapters/google-wire-compiler.ts +232 -0
  102. package/src/adapters/google.ts +758 -0
  103. package/src/adapters/identity.ts +44 -0
  104. package/src/adapters/image.ts +23 -0
  105. package/src/adapters/kiro-constants.ts +16 -0
  106. package/src/adapters/kiro-errors.ts +197 -0
  107. package/src/adapters/kiro-events.ts +179 -0
  108. package/src/adapters/kiro-images.ts +129 -0
  109. package/src/adapters/kiro-retry.ts +312 -0
  110. package/src/adapters/kiro-thinking.ts +96 -0
  111. package/src/adapters/kiro-tool-fallback.ts +36 -0
  112. package/src/adapters/kiro-tools.ts +215 -0
  113. package/src/adapters/kiro-truncation.ts +33 -0
  114. package/src/adapters/kiro-wire.ts +129 -0
  115. package/src/adapters/kiro.ts +1898 -0
  116. package/src/adapters/mimo-free.ts +263 -0
  117. package/src/adapters/openai-chat.ts +1005 -0
  118. package/src/adapters/openai-responses.ts +1137 -0
  119. package/src/adapters/run-turn-queue.ts +114 -0
  120. package/src/adapters/tool-catalog-nudge.ts +71 -0
  121. package/src/adapters/upstream-http-error.ts +48 -0
  122. package/src/bridge.ts +1619 -0
  123. package/src/chat/inbound.ts +295 -0
  124. package/src/chat/outbound.ts +765 -0
  125. package/src/claude/agents-inject.ts +243 -0
  126. package/src/claude/alias.ts +149 -0
  127. package/src/claude/auth-detect.ts +229 -0
  128. package/src/claude/auth-mode-migration.ts +32 -0
  129. package/src/claude/auth-mode.ts +62 -0
  130. package/src/claude/context-windows.ts +189 -0
  131. package/src/claude/desktop-3p-guard.ts +35 -0
  132. package/src/claude/desktop-3p-paths.ts +84 -0
  133. package/src/claude/desktop-3p.ts +381 -0
  134. package/src/claude/desktop-health.ts +26 -0
  135. package/src/claude/desktop-profile.ts +263 -0
  136. package/src/claude/gateway-cache.ts +70 -0
  137. package/src/claude/inbound-debug.ts +163 -0
  138. package/src/claude/inbound.ts +509 -0
  139. package/src/claude/model-info.ts +151 -0
  140. package/src/claude/outbound.ts +872 -0
  141. package/src/cli/access.ts +108 -0
  142. package/src/cli/account-api.ts +268 -0
  143. package/src/cli/account-auth.ts +223 -0
  144. package/src/cli/account-extended.ts +350 -0
  145. package/src/cli/account.ts +275 -0
  146. package/src/cli/agent-driven.ts +70 -0
  147. package/src/cli/agent.ts +184 -0
  148. package/src/cli/catalog-prewarm.ts +27 -0
  149. package/src/cli/claude-desktop.ts +188 -0
  150. package/src/cli/claude.ts +286 -0
  151. package/src/cli/codex-shim-autorestore.ts +45 -0
  152. package/src/cli/combo.ts +119 -0
  153. package/src/cli/config-command.ts +145 -0
  154. package/src/cli/debug.ts +228 -0
  155. package/src/cli/doctor.ts +930 -0
  156. package/src/cli/export-command.ts +187 -0
  157. package/src/cli/help.ts +354 -0
  158. package/src/cli/index.ts +1113 -0
  159. package/src/cli/init.ts +224 -0
  160. package/src/cli/integrations.ts +142 -0
  161. package/src/cli/interactive-confirm.ts +133 -0
  162. package/src/cli/internal-dispatch.ts +20 -0
  163. package/src/cli/models-runtime.ts +212 -0
  164. package/src/cli/models.ts +336 -0
  165. package/src/cli/observe.ts +117 -0
  166. package/src/cli/opencode.ts +586 -0
  167. package/src/cli/pi.ts +188 -0
  168. package/src/cli/provider-runtime.ts +162 -0
  169. package/src/cli/provider.ts +463 -0
  170. package/src/cli/runtime-api.ts +325 -0
  171. package/src/cli/star-prompt.ts +155 -0
  172. package/src/cli/status-oauth.ts +78 -0
  173. package/src/cli/status.ts +321 -0
  174. package/src/cli/sync-cloud.ts +283 -0
  175. package/src/cli/system-command.ts +112 -0
  176. package/src/cli/tray-proxy.ts +52 -0
  177. package/src/cli/v2.ts +173 -0
  178. package/src/cli.ts +10 -0
  179. package/src/clients/config-export.ts +377 -0
  180. package/src/clients/effective-status.ts +385 -0
  181. package/src/clients/probes/agy.ts +55 -0
  182. package/src/clients/probes/cc-switch.ts +110 -0
  183. package/src/clients/probes/claude.ts +90 -0
  184. package/src/clients/probes/codex.ts +125 -0
  185. package/src/clients/probes/grok.ts +29 -0
  186. package/src/clients/probes/opencode.ts +109 -0
  187. package/src/clients/probes/paseo.ts +55 -0
  188. package/src/clients/probes/pi.ts +55 -0
  189. package/src/cloud/onedrive-auth.ts +666 -0
  190. package/src/cloud/onedrive-graph.ts +108 -0
  191. package/src/cloud/settings.ts +75 -0
  192. package/src/cloud/sync.ts +212 -0
  193. package/src/cloud/types.ts +56 -0
  194. package/src/cloud/vault.ts +89 -0
  195. package/src/codex/account-id.ts +34 -0
  196. package/src/codex/account-label.ts +34 -0
  197. package/src/codex/account-lifecycle.ts +55 -0
  198. package/src/codex/account-namespace-match.ts +63 -0
  199. package/src/codex/account-namespaces.ts +149 -0
  200. package/src/codex/account-pause.ts +20 -0
  201. package/src/codex/account-runtime-state.ts +31 -0
  202. package/src/codex/account-store.ts +517 -0
  203. package/src/codex/account-usability.ts +20 -0
  204. package/src/codex/app-server-processes.ts +756 -0
  205. package/src/codex/auth-api.ts +1540 -0
  206. package/src/codex/auth-collision.ts +107 -0
  207. package/src/codex/auth-context.ts +352 -0
  208. package/src/codex/autostart-health.ts +149 -0
  209. package/src/codex/catalog/aggregation.ts +378 -0
  210. package/src/codex/catalog/bundled.ts +251 -0
  211. package/src/codex/catalog/effort.ts +355 -0
  212. package/src/codex/catalog/metadata.ts +180 -0
  213. package/src/codex/catalog/parsing.ts +456 -0
  214. package/src/codex/catalog/provider-fetch.ts +902 -0
  215. package/src/codex/catalog/sync.ts +620 -0
  216. package/src/codex/catalog.ts +12 -0
  217. package/src/codex/data/upstream-models.json +830 -0
  218. package/src/codex/exec-invocation.ts +22 -0
  219. package/src/codex/features.ts +969 -0
  220. package/src/codex/history-migration-guardian.ts +102 -0
  221. package/src/codex/history-provider.ts +776 -0
  222. package/src/codex/home.ts +206 -0
  223. package/src/codex/inject.ts +799 -0
  224. package/src/codex/injected-marker.ts +72 -0
  225. package/src/codex/journal.ts +163 -0
  226. package/src/codex/main-account-cache.ts +32 -0
  227. package/src/codex/main-account.ts +40 -0
  228. package/src/codex/model-cache.ts +227 -0
  229. package/src/codex/paths.ts +65 -0
  230. package/src/codex/plugins-doctor.ts +242 -0
  231. package/src/codex/pool-rotation.ts +225 -0
  232. package/src/codex/project-config-warnings.ts +411 -0
  233. package/src/codex/quota.ts +411 -0
  234. package/src/codex/refresh.ts +53 -0
  235. package/src/codex/routing.ts +1477 -0
  236. package/src/codex/runtime.ts +538 -0
  237. package/src/codex/shim.ts +1189 -0
  238. package/src/codex/subagent-defaults.ts +550 -0
  239. package/src/codex/subagent-model-fallback.ts +469 -0
  240. package/src/codex/sync.ts +130 -0
  241. package/src/codex/warmup.ts +192 -0
  242. package/src/codex/websocket-registry.ts +100 -0
  243. package/src/combos/failover.ts +140 -0
  244. package/src/combos/index.ts +41 -0
  245. package/src/combos/request.ts +62 -0
  246. package/src/combos/resolve.ts +232 -0
  247. package/src/combos/types.ts +326 -0
  248. package/src/config.ts +2356 -0
  249. package/src/generated/jawcode-model-metadata.ts +104 -0
  250. package/src/github/star-state.ts +203 -0
  251. package/src/grok/inject.ts +545 -0
  252. package/src/grok/status.ts +121 -0
  253. package/src/grok/sync.ts +103 -0
  254. package/src/grok/usage-hook/report.mjs +348 -0
  255. package/src/grok/usage-hook.ts +278 -0
  256. package/src/images/artifacts.ts +516 -0
  257. package/src/images/fulfill-video.ts +163 -0
  258. package/src/images/fulfill.ts +149 -0
  259. package/src/images/index.ts +4 -0
  260. package/src/images/loop.ts +829 -0
  261. package/src/images/plan.ts +133 -0
  262. package/src/images/synthetic-tool.ts +133 -0
  263. package/src/images/types.ts +41 -0
  264. package/src/images/xai-client.ts +141 -0
  265. package/src/images/xai-video-client.ts +163 -0
  266. package/src/index.ts +22 -0
  267. package/src/lib/abort.ts +146 -0
  268. package/src/lib/admin-secrets.ts +25 -0
  269. package/src/lib/admission.ts +83 -0
  270. package/src/lib/app-owned-memory-stores.ts +173 -0
  271. package/src/lib/app-owned-memory.ts +265 -0
  272. package/src/lib/bounded-body.ts +202 -0
  273. package/src/lib/bun-binary-validator.d.mts +3 -0
  274. package/src/lib/bun-binary-validator.mjs +18 -0
  275. package/src/lib/bun-runtime.ts +71 -0
  276. package/src/lib/bun-stream-caps.ts +126 -0
  277. package/src/lib/config-ownership.ts +360 -0
  278. package/src/lib/crash-guard.ts +344 -0
  279. package/src/lib/debug-log-buffer.ts +83 -0
  280. package/src/lib/debug-settings.ts +108 -0
  281. package/src/lib/debug.ts +31 -0
  282. package/src/lib/destination-policy.ts +316 -0
  283. package/src/lib/errors.ts +364 -0
  284. package/src/lib/eventstream-decoder.ts +253 -0
  285. package/src/lib/gcp-adc.ts +341 -0
  286. package/src/lib/injection-debug-log.ts +58 -0
  287. package/src/lib/open-url.ts +25 -0
  288. package/src/lib/pinned-http.ts +151 -0
  289. package/src/lib/privacy.ts +20 -0
  290. package/src/lib/process-control.ts +165 -0
  291. package/src/lib/provider-outbound.ts +170 -0
  292. package/src/lib/provider-url.ts +14 -0
  293. package/src/lib/proxy-env.ts +18 -0
  294. package/src/lib/redact.ts +105 -0
  295. package/src/lib/retry-after.ts +55 -0
  296. package/src/lib/service-secrets.ts +25 -0
  297. package/src/lib/shadow-call.ts +30 -0
  298. package/src/lib/sidecar-tracker.ts +52 -0
  299. package/src/lib/sse-decoder.ts +323 -0
  300. package/src/lib/state-store-registrations.ts +109 -0
  301. package/src/lib/state-store-sweeper.ts +184 -0
  302. package/src/lib/test-home-guard.ts +90 -0
  303. package/src/lib/token-estimate.ts +69 -0
  304. package/src/lib/translator-budget.ts +356 -0
  305. package/src/lib/upstream-retry.ts +239 -0
  306. package/src/lib/win-exec.ts +115 -0
  307. package/src/lib/win-paths.ts +68 -0
  308. package/src/lib/windows-elevation.ts +705 -0
  309. package/src/lib/windows-secret-acl.ts +514 -0
  310. package/src/lib/winsw.ts +375 -0
  311. package/src/oauth/anthropic-routing.ts +594 -0
  312. package/src/oauth/anthropic.ts +177 -0
  313. package/src/oauth/callback-server.ts +294 -0
  314. package/src/oauth/chatgpt.ts +150 -0
  315. package/src/oauth/cursor.ts +211 -0
  316. package/src/oauth/github-copilot.ts +428 -0
  317. package/src/oauth/google-antigravity.ts +230 -0
  318. package/src/oauth/health.ts +399 -0
  319. package/src/oauth/index.ts +1174 -0
  320. package/src/oauth/key-providers.ts +108 -0
  321. package/src/oauth/kimi.ts +213 -0
  322. package/src/oauth/kiro-credentials.ts +726 -0
  323. package/src/oauth/kiro.ts +577 -0
  324. package/src/oauth/local-token-detect.ts +121 -0
  325. package/src/oauth/log.ts +48 -0
  326. package/src/oauth/login-cli.ts +163 -0
  327. package/src/oauth/pkce.ts +15 -0
  328. package/src/oauth/store.ts +630 -0
  329. package/src/oauth/token-guardian.ts +303 -0
  330. package/src/oauth/types.ts +62 -0
  331. package/src/oauth/xai.ts +241 -0
  332. package/src/pi/extensions.ts +72 -0
  333. package/src/pi/home.ts +42 -0
  334. package/src/pi/index.ts +40 -0
  335. package/src/pi/models.ts +278 -0
  336. package/src/pi/packages.ts +219 -0
  337. package/src/pi/settings.ts +365 -0
  338. package/src/pi/status.ts +68 -0
  339. package/src/pi/sync.ts +75 -0
  340. package/src/providers/alibaba-region-backup.ts +75 -0
  341. package/src/providers/alibaba-region-migration.ts +156 -0
  342. package/src/providers/alibaba-region-startup.ts +36 -0
  343. package/src/providers/antigravity-models.ts +205 -0
  344. package/src/providers/api-keys.ts +140 -0
  345. package/src/providers/base-url-choices.ts +64 -0
  346. package/src/providers/context-cap.ts +65 -0
  347. package/src/providers/derive.ts +339 -0
  348. package/src/providers/free-directory.ts +184 -0
  349. package/src/providers/github-copilot-transport.ts +56 -0
  350. package/src/providers/key-failover.ts +203 -0
  351. package/src/providers/kiro-models.ts +67 -0
  352. package/src/providers/label.ts +19 -0
  353. package/src/providers/model-discovery.ts +356 -0
  354. package/src/providers/openai-sidecar.ts +175 -0
  355. package/src/providers/openai-tier-startup.ts +27 -0
  356. package/src/providers/openai-tiers.ts +301 -0
  357. package/src/providers/openai-virtual-models.ts +82 -0
  358. package/src/providers/openrouter-routing.ts +102 -0
  359. package/src/providers/provider-id-rewrite.ts +150 -0
  360. package/src/providers/quota.ts +1260 -0
  361. package/src/providers/registry.ts +1600 -0
  362. package/src/providers/slug-codec.ts +67 -0
  363. package/src/providers/xai-transport.ts +141 -0
  364. package/src/reasoning-effort.ts +135 -0
  365. package/src/responses/compaction.ts +117 -0
  366. package/src/responses/parser.ts +656 -0
  367. package/src/responses/reasoning-envelope.ts +52 -0
  368. package/src/responses/schema.ts +159 -0
  369. package/src/responses/spill-store.ts +394 -0
  370. package/src/responses/state.ts +895 -0
  371. package/src/responses/tool-groups.ts +19 -0
  372. package/src/router.ts +425 -0
  373. package/src/server/adapter-resolve.ts +80 -0
  374. package/src/server/auth-cors.ts +530 -0
  375. package/src/server/chat-completions.ts +368 -0
  376. package/src/server/claude-messages.ts +914 -0
  377. package/src/server/effort-policy.ts +172 -0
  378. package/src/server/gui-static.ts +123 -0
  379. package/src/server/image-retry.ts +42 -0
  380. package/src/server/images.ts +476 -0
  381. package/src/server/index.ts +1126 -0
  382. package/src/server/lifecycle.ts +227 -0
  383. package/src/server/live.ts +598 -0
  384. package/src/server/management/agent-settings-routes.ts +1169 -0
  385. package/src/server/management/api-access.ts +141 -0
  386. package/src/server/management/api-key-usage.ts +167 -0
  387. package/src/server/management/body.ts +35 -0
  388. package/src/server/management/clients-routes.ts +63 -0
  389. package/src/server/management/cloud-sync-routes.ts +266 -0
  390. package/src/server/management/combo-routes.ts +220 -0
  391. package/src/server/management/config-routes.ts +422 -0
  392. package/src/server/management/context.ts +31 -0
  393. package/src/server/management/logs-usage-routes.ts +707 -0
  394. package/src/server/management/model-routes.ts +525 -0
  395. package/src/server/management/oauth-account-routes.ts +563 -0
  396. package/src/server/management/provider-routes.ts +556 -0
  397. package/src/server/management/shared.ts +277 -0
  398. package/src/server/management/sidebar-routes.ts +90 -0
  399. package/src/server/management/system-restart.ts +179 -0
  400. package/src/server/management/system-routes.ts +117 -0
  401. package/src/server/management/usage-summary-cache.ts +86 -0
  402. package/src/server/management-api.ts +215 -0
  403. package/src/server/management-auth.ts +267 -0
  404. package/src/server/memory-watchdog.ts +156 -0
  405. package/src/server/port-reclaim.ts +307 -0
  406. package/src/server/ports.ts +116 -0
  407. package/src/server/proxy-liveness.ts +201 -0
  408. package/src/server/relay-eager.ts +313 -0
  409. package/src/server/relay.ts +1049 -0
  410. package/src/server/request-decompress.ts +132 -0
  411. package/src/server/request-log-conversation.ts +168 -0
  412. package/src/server/request-log.ts +1046 -0
  413. package/src/server/responses/collaboration.ts +354 -0
  414. package/src/server/responses/compact.ts +384 -0
  415. package/src/server/responses/core.ts +2758 -0
  416. package/src/server/responses/encrypted-payload.ts +308 -0
  417. package/src/server/responses/fetch-helpers.ts +157 -0
  418. package/src/server/responses/passthrough-error.ts +78 -0
  419. package/src/server/responses/terminal-guard.ts +230 -0
  420. package/src/server/responses/upstream-error.ts +48 -0
  421. package/src/server/responses-image-gen-repair.ts +132 -0
  422. package/src/server/responses-item-id-repair.ts +224 -0
  423. package/src/server/responses.ts +9 -0
  424. package/src/server/search.ts +136 -0
  425. package/src/server/sse-payload-rewrite.ts +175 -0
  426. package/src/server/startup-action-control.ts +308 -0
  427. package/src/server/startup-health-cache.ts +113 -0
  428. package/src/server/system-env.ts +413 -0
  429. package/src/server/windows-tcp-drop.ts +184 -0
  430. package/src/server/windows-tray-control.ts +41 -0
  431. package/src/server/ws-bridge.ts +471 -0
  432. package/src/service.ts +2554 -0
  433. package/src/stall-timeout.ts +20 -0
  434. package/src/storage/cleanup-job.ts +57 -0
  435. package/src/storage/cleanup.ts +3085 -0
  436. package/src/storage/policy-job.ts +457 -0
  437. package/src/storage/policy-scheduler.ts +40 -0
  438. package/src/storage/policy-worker.ts +59 -0
  439. package/src/storage/policy.ts +527 -0
  440. package/src/storage/restore-job.ts +299 -0
  441. package/src/storage/restore-worker.ts +58 -0
  442. package/src/storage/scanner.ts +238 -0
  443. package/src/storage/storage-mutation-coordinator.ts +139 -0
  444. package/src/storage/worker-lifecycle.ts +215 -0
  445. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  446. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  447. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  448. package/src/tray/assets/opencodex-tray.png +0 -0
  449. package/src/tray/windows-tray.ps1 +290 -0
  450. package/src/tray/windows.ts +730 -0
  451. package/src/types.ts +1237 -0
  452. package/src/update/badge.ts +72 -0
  453. package/src/update/index.ts +407 -0
  454. package/src/update/job.ts +1520 -0
  455. package/src/update/notify.ts +257 -0
  456. package/src/update/npm-invocation.d.mts +23 -0
  457. package/src/update/npm-invocation.mjs +94 -0
  458. package/src/update/tray-update-plan.d.mts +18 -0
  459. package/src/update/tray-update-plan.mjs +38 -0
  460. package/src/usage/cost.ts +0 -0
  461. package/src/usage/debug.ts +97 -0
  462. package/src/usage/expected-prices.ts +164 -0
  463. package/src/usage/log.ts +658 -0
  464. package/src/usage/summary.ts +585 -0
  465. package/src/usage/totals.ts +14 -0
  466. package/src/vision/anthropic-describe.ts +185 -0
  467. package/src/vision/describe.ts +125 -0
  468. package/src/vision/index.ts +467 -0
  469. package/src/web-search/anthropic-executor.ts +189 -0
  470. package/src/web-search/executor.ts +105 -0
  471. package/src/web-search/format-result.ts +89 -0
  472. package/src/web-search/index.ts +196 -0
  473. package/src/web-search/loop.ts +664 -0
  474. package/src/web-search/parse.ts +220 -0
  475. package/src/web-search/progress-stream.ts +342 -0
  476. package/src/web-search/synthetic-tool.ts +47 -0
@@ -0,0 +1,308 @@
1
+ import type { Server } from "bun";
2
+ import { bridgeToResponsesSSE, buildResponseJSON, formatErrorResponse, type ResponsesTerminalStatus } from "../../bridge";
3
+ import {
4
+ getConfigPath,
5
+ multiAgentGuidanceEnabled,
6
+ resolveEnvValue,
7
+ } from "../../config";
8
+ import { parseRequest } from "../../responses/parser";
9
+ import { buildCompactV1Output, COMPACT_PROMPT, decodeCompactionSummary, extractCompactUserMessages } from "../../responses/compaction";
10
+ import { FORWARD_HEADERS, sanitizeReasoningInputContent } from "../../adapters/openai-responses";
11
+ import { expandPreviousResponseInput, previousResponseProviderState, rememberResponseState } from "../../responses/state";
12
+ import { routeModel } from "../../router";
13
+ import {
14
+ advanceComboAfterFailure,
15
+ comboDefaultEffort,
16
+ comboFailureDecision,
17
+ comboIdFromRawBody,
18
+ concreteComboRequestBody,
19
+ getCombo,
20
+ isComboTargetInCooldown,
21
+ NoAvailableComboTargetsError,
22
+ noteComboSuccess,
23
+ parseRetryAfterMs,
24
+ pickComboTarget,
25
+ targetKey,
26
+ } from "../../combos";
27
+ import { isInjectionDebugEnabled } from "../../lib/debug-settings";
28
+ import { injectionDebugLog } from "../../lib/injection-debug-log";
29
+ import { modelInList, namespacedToolName } from "../../types";
30
+ import type { AdapterEvent, OcxConfig, OcxParsedRequest, OcxProviderConfig, OcxProviderContinuationState, OcxUsage } from "../../types";
31
+ import {
32
+ forceRefreshOAuthAccessSnapshot,
33
+ getOAuthCredentialApiBaseUrl,
34
+ getOAuthCredentialProjectId,
35
+ getValidAccessTokenSnapshot,
36
+ type OAuthAccessSnapshot,
37
+ UnsupportedOAuthProviderError,
38
+ } from "../../oauth";
39
+ import { buildWebSearchTool, planWebSearch, runWithWebSearch, shouldResolveOpenAiWebSearchSidecar } from "../../web-search";
40
+ import { describeImagesInPlace, planVisionSidecar, shouldResolveOpenAiVisionSidecar, stripImagesInPlace } from "../../vision";
41
+ import { createAdapterEventQueue, preflightAdapterEvents } from "../../adapters/run-turn-queue";
42
+ import {
43
+ applyCodexAuthContextToProvider,
44
+ CodexAccountCooldownError,
45
+ CodexAuthContextError,
46
+ CodexDirectAuthenticationError,
47
+ CodexPoolAuthenticationError,
48
+ CodexThreadAffinityExpiredError,
49
+ headersForCodexAuthContext,
50
+ isCodexAuthContextUsable,
51
+ resolveCodexAuthContext,
52
+ type CodexAuthContext,
53
+ } from "../../codex/auth-context";
54
+ import {
55
+ formatCodexProviderForLog,
56
+ recordCodexUpstreamOutcome,
57
+ type CodexUpstreamOutcome,
58
+ } from "../../codex/routing";
59
+ import { fetchWithResetRetry, fetchWithTransientRetry, applyUpstreamRecoveryInit } from "../../lib/upstream-retry";
60
+ import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "../auth-cors";
61
+ import { listOpenAiForwardSidecarCandidates, resolveFirstUsableOpenAiSidecar, type ResolvedOpenAiForwardSidecar } from "../../providers/openai-sidecar";
62
+ import { isCanonicalOpenAiForwardProvider } from "../../providers/openai-tiers";
63
+ import { slugsEquivalent } from "../../providers/slug-codec";
64
+ import { applyOpenAiVirtualModel, resolveOpenAiCompactModel } from "../../providers/openai-virtual-models";
65
+ import { isUsageDebugEnabled } from "../../usage/debug";
66
+ import { readJsonRequestBody, DecompressedBodyTooLargeError, UnsupportedContentEncodingError } from "../request-decompress";
67
+ import { resolveAdapter, resolveWireProtocolOverride } from "../adapter-resolve";
68
+ import { hasKeyPoolFailover, rotateProviderTransportOn429 } from "../../providers/key-failover";
69
+ import { shouldAttemptImageTierRetry } from "../image-retry";
70
+ import { resolveProviderTransport } from "../../providers/xai-transport";
71
+ import type { WsData } from "../ws-bridge";
72
+ import { registerTurn, trackStreamLifetime, unregisterTurn } from "../lifecycle";
73
+ import { redactSecretString } from "../../lib/redact";
74
+ import { readBoundedResponseBody } from "../../lib/bounded-body";
75
+ import { supportedLadderFor } from "../effort-policy";
76
+ import {
77
+ beginRequestAttempt,
78
+ catalogModelSupportsServiceTier,
79
+ finishRequestAttempt,
80
+ inspectResponseLogJson,
81
+ noteAttemptSend,
82
+ readConfiguredCodexServiceTier,
83
+ requestLogSpeedLabel,
84
+ sealRequestAttemptIdentity,
85
+ usageFromResponsesPayload,
86
+ type RequestLogContext,
87
+ } from "../request-log";
88
+ import type { AttemptRecoveryKind } from "../../usage/log";
89
+ import {
90
+ consumeForInspection,
91
+ consumeForResponseLogMetadata,
92
+ markNativePassthroughSseResponse,
93
+ relaySseWithFailedTail,
94
+ relayWithAbort,
95
+ sanitizePassthroughHeaders,
96
+ } from "../relay";
97
+ import { hasResponsesItemIdRepair, relaySseWithResponsesItemIdRepair } from "../responses-item-id-repair";
98
+ import type { EffectiveSubagentRoster, SpawnAgentSurface } from "../../codex/catalog";
99
+
100
+
101
+ export function looksLikeBackendCiphertext(payload: string): boolean {
102
+ return payload.length >= 64 && /^[A-Za-z0-9+/=_-]+$/.test(payload);
103
+ }
104
+
105
+
106
+
107
+ /**
108
+ * Backend-minted ciphertext runs are Fernet tokens (base64url, version byte 0x80).
109
+ * Used to carve embedded blobs out of MIXED slots: plugin hooks may prepend
110
+ * plaintext control metadata to a task body that is already backend-encrypted.
111
+ */
112
+ const FERNET_TOKEN_CANDIDATE = /g[A-Za-z0-9_-]{97,}={0,2}/g;
113
+ const FERNET_TOKEN_BOUNDARY_CHAR = /[A-Za-z0-9_=-]/;
114
+
115
+ interface FernetTokenRun {
116
+ index: number;
117
+ token: string;
118
+ }
119
+
120
+ /**
121
+ * Validate only the key-independent Fernet wire structure. Authenticity cannot be
122
+ * checked without the backend key, but a real token must still be canonical base64url
123
+ * containing version(1) + timestamp(8) + IV(16) + AES-CBC ciphertext(16*n) + HMAC(32).
124
+ * Timestamp freshness is deliberately not enforced: old history can contain valid tokens.
125
+ */
126
+ function isStructurallyValidFernetToken(token: string): boolean {
127
+ if (token.length < 100 || token.length % 4 !== 0) return false;
128
+ if (!/^[A-Za-z0-9_-]+={0,2}$/.test(token)) return false;
129
+
130
+ const unpadded = token.replace(/=+$/, "");
131
+ const paddingLength = token.length - unpadded.length;
132
+ const expectedPadding = (4 - (unpadded.length % 4)) % 4;
133
+ if (expectedPadding > 2 || paddingLength !== expectedPadding) return false;
134
+
135
+ let decoded: Buffer;
136
+ try {
137
+ decoded = Buffer.from(unpadded, "base64url");
138
+ } catch {
139
+ return false;
140
+ }
141
+ if (decoded.toString("base64url") !== unpadded) return false;
142
+ if (decoded.length < 73 || decoded[0] !== 0x80) return false;
143
+
144
+ const ciphertextLength = decoded.length - 57;
145
+ return ciphertextLength >= 16 && ciphertextLength % 16 === 0;
146
+ }
147
+
148
+ /** Maximal, boundary-delimited and structurally valid Fernet runs embedded in a slot. */
149
+ function fernetTokenRuns(payload: string): FernetTokenRun[] {
150
+ const runs: FernetTokenRun[] = [];
151
+ for (const match of payload.matchAll(FERNET_TOKEN_CANDIDATE)) {
152
+ const index = match.index ?? 0;
153
+ const token = match[0];
154
+ const before = index > 0 ? payload[index - 1] : undefined;
155
+ const after = payload[index + token.length];
156
+ if (before && FERNET_TOKEN_BOUNDARY_CHAR.test(before)) continue;
157
+ if (after && FERNET_TOKEN_BOUNDARY_CHAR.test(after)) continue;
158
+ if (!isStructurallyValidFernetToken(token)) continue;
159
+ runs.push({ index, token });
160
+ }
161
+ return runs;
162
+ }
163
+
164
+ function textWithoutFernetRuns(payload: string, runs: readonly FernetTokenRun[]): string {
165
+ let last = 0;
166
+ let text = "";
167
+ for (const run of runs) {
168
+ text += `${payload.slice(last, run.index)}\n\n`;
169
+ last = run.index + run.token.length;
170
+ }
171
+ return `${text}${payload.slice(last)}`;
172
+ }
173
+
174
+ export const AGENT_MESSAGE_ROUTING_ENVELOPE = /(?:^|\n)Message Type\s*:\s*NEW_TASK[^\n]*\nTask name\s*:[^\n]*\nSender\s*:[^\n]*\nPayload\s*:\s*(?:\n|$)/gi;
175
+
176
+ // CXC is the compatibility-hook control namespace. Strip only the tagged paragraph:
177
+ // later untagged paragraphs may be genuine task text. Repeated CXC paragraphs are
178
+ // removed independently, and a following routing envelope remains available to the
179
+ // envelope stripper below.
180
+ export const AGENT_MESSAGE_CONTROL_PREAMBLE = /(?:^|\n)\[CXC-[A-Z0-9-]+\][^\n]*(?:\n(?!\n|Message Type\s*:)[^\n]*)*(?=\n{2,}|\nMessage Type\s*:|$)/gi;
181
+
182
+ export function hasUnreadableEncryptedAgentTask(input: unknown): boolean {
183
+ if (!Array.isArray(input)) return false;
184
+
185
+ // codex-rs appends one NEW_TASK agent_message at the current input tail. Historical
186
+ // agent messages may be adjacent in full-history bodies; they must not poison the
187
+ // later task. compaction_trigger/additional_tools are trailing metadata rather than
188
+ // a newer user turn.
189
+ let index = input.length - 1;
190
+ while (index >= 0) {
191
+ const item = input[index];
192
+ const type = item && typeof item === "object" ? (item as { type?: unknown }).type : undefined;
193
+ if (type !== "compaction_trigger" && type !== "additional_tools") break;
194
+ index -= 1;
195
+ }
196
+ const item = input[index];
197
+ if (!item || typeof item !== "object" || (item as { type?: unknown }).type !== "agent_message") {
198
+ return false;
199
+ }
200
+
201
+ const content = (item as { content?: unknown }).content;
202
+ if (!Array.isArray(content)) return false;
203
+
204
+ let hasFernetTask = false;
205
+ const readableParts: string[] = [];
206
+ for (const part of content) {
207
+ if (!part || typeof part !== "object") continue;
208
+ const record = part as { type?: unknown; text?: unknown; encrypted_content?: unknown };
209
+ if (
210
+ (record.type === "input_text" || record.type === "text")
211
+ && typeof record.text === "string"
212
+ ) {
213
+ readableParts.push(record.text);
214
+ continue;
215
+ }
216
+ if (record.type !== "encrypted_content" || typeof record.encrypted_content !== "string") {
217
+ continue;
218
+ }
219
+
220
+ const runs = fernetTokenRuns(record.encrypted_content);
221
+ if (runs.length > 0) hasFernetTask = true;
222
+ readableParts.push(textWithoutFernetRuns(record.encrypted_content, runs));
223
+ }
224
+
225
+ if (!hasFernetTask) return false;
226
+ const readableTask = readableParts
227
+ .join("\n\n")
228
+ .replace(AGENT_MESSAGE_CONTROL_PREAMBLE, "\n")
229
+ .replace(AGENT_MESSAGE_ROUTING_ENVELOPE, "\n")
230
+ .trim();
231
+ return readableTask.length === 0;
232
+ }
233
+
234
+
235
+
236
+ export function encryptedSlotParts(payload: string): Array<Record<string, string>> {
237
+ const parts: Array<Record<string, string>> = [];
238
+ let last = 0;
239
+ for (const run of fernetTokenRuns(payload)) {
240
+ const before = payload.slice(last, run.index);
241
+ if (before.trim().length > 0) parts.push({ type: "input_text", text: before });
242
+ parts.push({ type: "encrypted_content", encrypted_content: run.token });
243
+ last = run.index + run.token.length;
244
+ }
245
+ const rest = payload.slice(last);
246
+ if (rest.trim().length > 0) parts.push({ type: "input_text", text: rest });
247
+ return parts.length > 0 ? parts : [{ type: "input_text", text: payload }];
248
+ }
249
+
250
+
251
+
252
+ export function hasEncryptedContentPart(content: unknown): boolean {
253
+ return Array.isArray(content) && content.some(part => (
254
+ part && typeof part === "object"
255
+ && (part as { type?: unknown }).type === "encrypted_content"
256
+ ));
257
+ }
258
+
259
+
260
+
261
+ export function sanitizeEncryptedContentInPlace(input: unknown): number {
262
+ if (!Array.isArray(input)) return 0;
263
+ let rewritten = 0;
264
+ const visit = (node: unknown): number => {
265
+ const before = rewritten;
266
+ if (Array.isArray(node)) {
267
+ for (let i = 0; i < node.length; i += 1) {
268
+ const child = node[i] as unknown;
269
+ if (
270
+ child && typeof child === "object"
271
+ && (child as { type?: unknown }).type === "encrypted_content"
272
+ && typeof (child as { encrypted_content?: unknown }).encrypted_content === "string"
273
+ ) {
274
+ const payload = (child as { encrypted_content: string }).encrypted_content;
275
+ if (!looksLikeBackendCiphertext(payload)) {
276
+ const parts = encryptedSlotParts(payload);
277
+ node.splice(i, 1, ...parts);
278
+ i += parts.length - 1;
279
+ rewritten += 1;
280
+ continue;
281
+ }
282
+ }
283
+ const childRewrites = visit(child);
284
+ if (
285
+ childRewrites > 0
286
+ && child && typeof child === "object"
287
+ && (child as { type?: unknown }).type === "agent_message"
288
+ && !hasEncryptedContentPart((child as { content?: unknown }).content)
289
+ ) {
290
+ const message = child as { type: string; role?: string; id?: unknown; author?: unknown; recipient?: unknown };
291
+ message.type = "message";
292
+ message.role = "user";
293
+ delete message.id;
294
+ delete message.author;
295
+ delete message.recipient;
296
+ }
297
+ }
298
+ return rewritten - before;
299
+ }
300
+ if (node && typeof node === "object") {
301
+ for (const value of Object.values(node)) visit(value);
302
+ }
303
+ return rewritten - before;
304
+ };
305
+ visit(input);
306
+ return rewritten;
307
+ }
308
+
@@ -0,0 +1,157 @@
1
+ import type { Server } from "bun";
2
+ import { bridgeToResponsesSSE, buildResponseJSON, formatErrorResponse, type ResponsesTerminalStatus } from "../../bridge";
3
+ import {
4
+ getConfigPath,
5
+ multiAgentGuidanceEnabled,
6
+ resolveEnvValue,
7
+ } from "../../config";
8
+ import { parseRequest } from "../../responses/parser";
9
+ import { buildCompactV1Output, COMPACT_PROMPT, decodeCompactionSummary, extractCompactUserMessages } from "../../responses/compaction";
10
+ import { FORWARD_HEADERS, sanitizeReasoningInputContent } from "../../adapters/openai-responses";
11
+ import { expandPreviousResponseInput, previousResponseProviderState, rememberResponseState } from "../../responses/state";
12
+ import { routeModel } from "../../router";
13
+ import {
14
+ advanceComboAfterFailure,
15
+ comboDefaultEffort,
16
+ comboFailureDecision,
17
+ comboIdFromRawBody,
18
+ concreteComboRequestBody,
19
+ getCombo,
20
+ isComboTargetInCooldown,
21
+ NoAvailableComboTargetsError,
22
+ noteComboSuccess,
23
+ parseRetryAfterMs,
24
+ pickComboTarget,
25
+ targetKey,
26
+ } from "../../combos";
27
+ import { isInjectionDebugEnabled } from "../../lib/debug-settings";
28
+ import { injectionDebugLog } from "../../lib/injection-debug-log";
29
+ import { modelInList, namespacedToolName } from "../../types";
30
+ import type { AdapterEvent, OcxConfig, OcxParsedRequest, OcxProviderConfig, OcxProviderContinuationState, OcxUsage } from "../../types";
31
+ import {
32
+ forceRefreshOAuthAccessSnapshot,
33
+ getOAuthCredentialApiBaseUrl,
34
+ getOAuthCredentialProjectId,
35
+ getValidAccessTokenSnapshot,
36
+ type OAuthAccessSnapshot,
37
+ UnsupportedOAuthProviderError,
38
+ } from "../../oauth";
39
+ import { buildWebSearchTool, planWebSearch, runWithWebSearch, shouldResolveOpenAiWebSearchSidecar } from "../../web-search";
40
+ import { describeImagesInPlace, planVisionSidecar, shouldResolveOpenAiVisionSidecar, stripImagesInPlace } from "../../vision";
41
+ import { createAdapterEventQueue, preflightAdapterEvents } from "../../adapters/run-turn-queue";
42
+ import {
43
+ applyCodexAuthContextToProvider,
44
+ CodexAccountCooldownError,
45
+ CodexAuthContextError,
46
+ CodexDirectAuthenticationError,
47
+ CodexPoolAuthenticationError,
48
+ CodexThreadAffinityExpiredError,
49
+ headersForCodexAuthContext,
50
+ isCodexAuthContextUsable,
51
+ resolveCodexAuthContext,
52
+ type CodexAuthContext,
53
+ } from "../../codex/auth-context";
54
+ import {
55
+ formatCodexProviderForLog,
56
+ recordCodexUpstreamOutcome,
57
+ type CodexUpstreamOutcome,
58
+ } from "../../codex/routing";
59
+ import { fetchWithResetRetry, fetchWithTransientRetry, applyUpstreamRecoveryInit } from "../../lib/upstream-retry";
60
+ import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "../auth-cors";
61
+ import { listOpenAiForwardSidecarCandidates, resolveFirstUsableOpenAiSidecar, type ResolvedOpenAiForwardSidecar } from "../../providers/openai-sidecar";
62
+ import { isCanonicalOpenAiForwardProvider } from "../../providers/openai-tiers";
63
+ import { slugsEquivalent } from "../../providers/slug-codec";
64
+ import { applyOpenAiVirtualModel, resolveOpenAiCompactModel } from "../../providers/openai-virtual-models";
65
+ import { isUsageDebugEnabled } from "../../usage/debug";
66
+ import { readJsonRequestBody, DecompressedBodyTooLargeError, UnsupportedContentEncodingError } from "../request-decompress";
67
+ import { resolveAdapter, resolveWireProtocolOverride } from "../adapter-resolve";
68
+ import { hasKeyPoolFailover, rotateProviderTransportOn429 } from "../../providers/key-failover";
69
+ import { shouldAttemptImageTierRetry } from "../image-retry";
70
+ import { resolveProviderTransport } from "../../providers/xai-transport";
71
+ import type { WsData } from "../ws-bridge";
72
+ import { registerTurn, trackStreamLifetime, unregisterTurn } from "../lifecycle";
73
+ import { redactSecretString } from "../../lib/redact";
74
+ import { readBoundedResponseBody } from "../../lib/bounded-body";
75
+ import { supportedLadderFor } from "../effort-policy";
76
+ import {
77
+ beginRequestAttempt,
78
+ catalogModelSupportsServiceTier,
79
+ finishRequestAttempt,
80
+ inspectResponseLogJson,
81
+ noteAttemptSend,
82
+ readConfiguredCodexServiceTier,
83
+ requestLogSpeedLabel,
84
+ sealRequestAttemptIdentity,
85
+ usageFromResponsesPayload,
86
+ type RequestLogContext,
87
+ } from "../request-log";
88
+ import type { AttemptRecoveryKind } from "../../usage/log";
89
+ import {
90
+ consumeForInspection,
91
+ consumeForResponseLogMetadata,
92
+ markNativePassthroughSseResponse,
93
+ relaySseWithFailedTail,
94
+ relayWithAbort,
95
+ sanitizePassthroughHeaders,
96
+ } from "../relay";
97
+ import { hasResponsesItemIdRepair, relaySseWithResponsesItemIdRepair } from "../responses-item-id-repair";
98
+ import type { EffectiveSubagentRoster, SpawnAgentSurface } from "../../codex/catalog";
99
+
100
+
101
+ export function disableResponsesRequestTimeout(req: Request, server: Pick<Server<WsData>, "timeout"> | undefined): boolean {
102
+ if (!server) return false;
103
+ try {
104
+ server.timeout(req, 0);
105
+ return true;
106
+ } catch {
107
+ return false;
108
+ }
109
+ }
110
+
111
+
112
+
113
+ export function safeHostLabel(url: string): string {
114
+ try {
115
+ return new URL(url).host;
116
+ } catch {
117
+ return "upstream";
118
+ }
119
+ }
120
+
121
+
122
+
123
+ export function providerFetch(provider: OcxProviderConfig): typeof globalThis.fetch {
124
+ return (provider as OcxProviderConfig & { fetch?: typeof globalThis.fetch }).fetch ?? globalThis.fetch;
125
+ }
126
+
127
+
128
+
129
+ export async function fetchWithHeaderTimeout(
130
+ url: string,
131
+ init: Omit<RequestInit, "signal">,
132
+ abortSignal: AbortSignal,
133
+ timeoutMs: number,
134
+ preferIdentityEncoding = false,
135
+ executor: typeof globalThis.fetch = globalThis.fetch,
136
+ ): Promise<Response> {
137
+ const timeout = new AbortController();
138
+ const timer = setTimeout(() => {
139
+ if (!timeout.signal.aborted) timeout.abort(new DOMException("Timeout elapsed", "TimeoutError"));
140
+ }, timeoutMs);
141
+ const headers = new Headers(init.headers);
142
+ // Compressed SSE can be held until the decompressor has a complete block. Streaming calls
143
+ // default to identity for low-latency frame delivery, while an explicit caller choice wins.
144
+ if (preferIdentityEncoding && !headers.has("accept-encoding")) {
145
+ headers.set("accept-encoding", "identity");
146
+ }
147
+ try {
148
+ return await executor(url, {
149
+ ...init,
150
+ headers,
151
+ signal: AbortSignal.any([abortSignal, timeout.signal]),
152
+ });
153
+ } finally {
154
+ clearTimeout(timer);
155
+ }
156
+ }
157
+
@@ -0,0 +1,78 @@
1
+ import { formatErrorResponse } from "../../bridge";
2
+ import {
3
+ resolveClientRetryAfter,
4
+ validateClientRetryAfterHeader,
5
+ } from "../../lib/retry-after";
6
+
7
+ /**
8
+ * Passthrough adapters historically relayed upstream non-2xx bodies verbatim.
9
+ * Codex maps an *empty* body to the literal client string "Unknown error"
10
+ * (UnexpectedResponseError) — issue #452. Only empty bodies need wrapping.
11
+ *
12
+ * Non-empty bodies (including ChatGPT `{detail: ...}` account-model 400s and
13
+ * HTML/text errors) must keep their original bytes and headers so pool-retry
14
+ * activation and client diagnostics stay honest.
15
+ *
16
+ * Retry-After is validated independently of the body path:
17
+ * - valid upstream values are preserved
18
+ * - missing/malformed values are replaced when resolveClientRetryAfter yields a value
19
+ * - malformed/expired values are removed when the resolver returns undefined
20
+ * (e.g. quota-exhausted 429s must not keep junk headers or get the synthetic "2")
21
+ */
22
+ export function formatPassthroughUpstreamError(
23
+ status: number,
24
+ bodyText: string,
25
+ options?: {
26
+ statusText?: string;
27
+ headers?: Headers;
28
+ now?: number;
29
+ },
30
+ ): Response {
31
+ const trimmed = bodyText.trim();
32
+ const now = options?.now ?? Date.now();
33
+ const upstreamRetryAfter = options?.headers?.get("retry-after")?.trim() || undefined;
34
+ const originalValid = validateClientRetryAfterHeader(upstreamRetryAfter, now);
35
+ const resolved = resolveClientRetryAfter({
36
+ status,
37
+ message: trimmed || `Provider error ${status}: (empty body)`,
38
+ upstreamRetryAfter,
39
+ now,
40
+ });
41
+
42
+ if (trimmed) {
43
+ const needsSet = resolved !== undefined && upstreamRetryAfter !== resolved;
44
+ const needsDelete = resolved === undefined
45
+ && upstreamRetryAfter !== undefined
46
+ && originalValid === undefined;
47
+
48
+ if (!needsSet && !needsDelete) {
49
+ return new Response(bodyText, {
50
+ status,
51
+ ...(options?.statusText ? { statusText: options.statusText } : {}),
52
+ ...(options?.headers ? { headers: options.headers } : { headers: { "Content-Type": "application/json" } }),
53
+ });
54
+ }
55
+
56
+ const headers = options?.headers
57
+ ? new Headers(options.headers)
58
+ : new Headers({ "Content-Type": "application/json" });
59
+ if (needsSet) headers.set("Retry-After", resolved!);
60
+ else headers.delete("Retry-After");
61
+ return new Response(bodyText, {
62
+ status,
63
+ ...(options?.statusText ? { statusText: options.statusText } : {}),
64
+ headers,
65
+ });
66
+ }
67
+
68
+ const response = formatErrorResponse(
69
+ status,
70
+ "upstream_error",
71
+ `Provider error ${status}: (empty body)`,
72
+ resolved !== undefined ? { retryAfter: resolved } : undefined,
73
+ );
74
+ const headers = new Headers(response.headers);
75
+ headers.set("Content-Type", "application/json");
76
+ if (resolved !== undefined) headers.set("Retry-After", resolved);
77
+ return new Response(response.body, { status: response.status, headers });
78
+ }