@remodex/rmx 1.0.2

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 (588) hide show
  1. package/AGENTS_INSTALL.md +91 -0
  2. package/LICENSE +21 -0
  3. package/README.md +242 -0
  4. package/assets/architecture.png +0 -0
  5. package/assets/banner.png +0 -0
  6. package/assets/claude-code-models.gif +0 -0
  7. package/assets/codex-app-picker.png +0 -0
  8. package/bin/ocx.mjs +584 -0
  9. package/bin/package-main.mjs +9 -0
  10. package/gui/dist/assets/index-CZqebSPQ.css +1 -0
  11. package/gui/dist/assets/index-CkETtt7P.js +71 -0
  12. package/gui/dist/favicon.png +0 -0
  13. package/gui/dist/fonts/google-sans-cyrillic.woff2 +0 -0
  14. package/gui/dist/fonts/google-sans-latin.woff2 +0 -0
  15. package/gui/dist/icons.svg +24 -0
  16. package/gui/dist/index.html +25 -0
  17. package/gui/dist/logo.png +0 -0
  18. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  19. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  20. package/gui/dist/provider-icons/claude-color.svg +1 -0
  21. package/gui/dist/provider-icons/cline-color.svg +16 -0
  22. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  23. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  24. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  25. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  26. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  27. package/gui/dist/provider-icons/discord.svg +1 -0
  28. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  29. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  30. package/gui/dist/provider-icons/gemini-color.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.svg +1 -0
  34. package/gui/dist/provider-icons/groq-color.svg +1 -0
  35. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  36. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  37. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  38. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  39. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  40. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  41. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  42. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  43. package/gui/dist/provider-icons/openai.svg +1 -0
  44. package/gui/dist/provider-icons/opencode.svg +2 -0
  45. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  46. package/gui/dist/provider-icons/pi.svg +21 -0
  47. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  48. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  49. package/gui/dist/provider-icons/telegram.svg +1 -0
  50. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  51. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  52. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  53. package/package.json +118 -0
  54. package/src/AGENTS.md +28 -0
  55. package/src/adapters/anthropic-image-guard.ts +251 -0
  56. package/src/adapters/anthropic-image-normalize.ts +518 -0
  57. package/src/adapters/anthropic.ts +1205 -0
  58. package/src/adapters/azure.ts +36 -0
  59. package/src/adapters/base.ts +83 -0
  60. package/src/adapters/client-fingerprint.ts +59 -0
  61. package/src/adapters/command-code.ts +453 -0
  62. package/src/adapters/cursor/arg-codec.ts +38 -0
  63. package/src/adapters/cursor/arg-normalize.ts +104 -0
  64. package/src/adapters/cursor/cursor-errors.ts +165 -0
  65. package/src/adapters/cursor/discovery.ts +276 -0
  66. package/src/adapters/cursor/effort-map.ts +139 -0
  67. package/src/adapters/cursor/exec-policy.ts +88 -0
  68. package/src/adapters/cursor/framing.ts +250 -0
  69. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  70. package/src/adapters/cursor/kv-store.ts +52 -0
  71. package/src/adapters/cursor/live-models.ts +153 -0
  72. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  73. package/src/adapters/cursor/live-transport.ts +1235 -0
  74. package/src/adapters/cursor/mcp-config.ts +42 -0
  75. package/src/adapters/cursor/mcp-manager.ts +333 -0
  76. package/src/adapters/cursor/message-mapper.ts +49 -0
  77. package/src/adapters/cursor/native-exec-common.ts +59 -0
  78. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  79. package/src/adapters/cursor/native-exec-fs.ts +332 -0
  80. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  81. package/src/adapters/cursor/native-exec-network.ts +43 -0
  82. package/src/adapters/cursor/native-exec-shell.ts +548 -0
  83. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  84. package/src/adapters/cursor/native-exec.ts +604 -0
  85. package/src/adapters/cursor/protobuf-events.ts +735 -0
  86. package/src/adapters/cursor/protobuf-request.ts +719 -0
  87. package/src/adapters/cursor/request-builder.ts +280 -0
  88. package/src/adapters/cursor/thread-continuity.ts +67 -0
  89. package/src/adapters/cursor/tool-definitions.ts +621 -0
  90. package/src/adapters/cursor/transport-retry.ts +132 -0
  91. package/src/adapters/cursor/transport.ts +57 -0
  92. package/src/adapters/cursor/types.ts +59 -0
  93. package/src/adapters/cursor.ts +196 -0
  94. package/src/adapters/google-antigravity-replay.ts +520 -0
  95. package/src/adapters/google-antigravity-wire.ts +140 -0
  96. package/src/adapters/google-errors.ts +85 -0
  97. package/src/adapters/google-http.ts +100 -0
  98. package/src/adapters/google-tool-schema.ts +173 -0
  99. package/src/adapters/google-truncation.ts +24 -0
  100. package/src/adapters/google-wire-compiler.ts +232 -0
  101. package/src/adapters/google.ts +859 -0
  102. package/src/adapters/identity.ts +77 -0
  103. package/src/adapters/image.ts +23 -0
  104. package/src/adapters/kiro-constants.ts +16 -0
  105. package/src/adapters/kiro-errors.ts +208 -0
  106. package/src/adapters/kiro-events.ts +197 -0
  107. package/src/adapters/kiro-images.ts +129 -0
  108. package/src/adapters/kiro-retry.ts +312 -0
  109. package/src/adapters/kiro-thinking.ts +104 -0
  110. package/src/adapters/kiro-tool-fallback.ts +36 -0
  111. package/src/adapters/kiro-tools.ts +224 -0
  112. package/src/adapters/kiro-truncation.ts +33 -0
  113. package/src/adapters/kiro-wire.ts +129 -0
  114. package/src/adapters/kiro.ts +1924 -0
  115. package/src/adapters/mimo-free.ts +263 -0
  116. package/src/adapters/openai-chat.ts +1265 -0
  117. package/src/adapters/openai-responses.ts +1309 -0
  118. package/src/adapters/run-turn-queue.ts +114 -0
  119. package/src/adapters/tool-catalog-nudge.ts +71 -0
  120. package/src/adapters/upstream-http-error.ts +48 -0
  121. package/src/android-remote/assets.ts +218 -0
  122. package/src/android-remote/attachments.ts +168 -0
  123. package/src/android-remote/auth.ts +237 -0
  124. package/src/android-remote/cloudflare-provisioning.ts +409 -0
  125. package/src/android-remote/cloudflare-secret.ts +106 -0
  126. package/src/android-remote/cloudflare-tunnel.ts +488 -0
  127. package/src/android-remote/cloudflared.ts +286 -0
  128. package/src/android-remote/codex-app-server.ts +565 -0
  129. package/src/android-remote/desktop-history-page.ts +936 -0
  130. package/src/android-remote/desktop-ipc.ts +3643 -0
  131. package/src/android-remote/desktop-ownership-store.ts +98 -0
  132. package/src/android-remote/desktop-project-registration.ts +129 -0
  133. package/src/android-remote/desktop-session-stream.ts +1110 -0
  134. package/src/android-remote/desktop-workspace-state.ts +443 -0
  135. package/src/android-remote/file-change-parser.ts +112 -0
  136. package/src/android-remote/gateway.ts +9108 -0
  137. package/src/android-remote/mutation-store.ts +299 -0
  138. package/src/android-remote/projection.ts +1780 -0
  139. package/src/android-remote/queued-turn-store.ts +248 -0
  140. package/src/android-remote/session-command-recovery.ts +1384 -0
  141. package/src/android-remote/store.ts +466 -0
  142. package/src/android-remote/thread-reconciliation.ts +133 -0
  143. package/src/android-remote/thread-source-paths.ts +307 -0
  144. package/src/android-remote/thread-stream.ts +546 -0
  145. package/src/android-remote/turn-activity.ts +235 -0
  146. package/src/android-remote/user-message-identity.ts +94 -0
  147. package/src/bridge.ts +1793 -0
  148. package/src/chat/inbound.ts +295 -0
  149. package/src/chat/outbound.ts +821 -0
  150. package/src/claude/agents-inject.ts +267 -0
  151. package/src/claude/alias.ts +149 -0
  152. package/src/claude/auth-detect.ts +229 -0
  153. package/src/claude/auth-mode-migration.ts +32 -0
  154. package/src/claude/auth-mode.ts +62 -0
  155. package/src/claude/context-windows.ts +189 -0
  156. package/src/claude/desktop-3p-guard.ts +35 -0
  157. package/src/claude/desktop-3p-paths.ts +84 -0
  158. package/src/claude/desktop-3p.ts +601 -0
  159. package/src/claude/desktop-health.ts +26 -0
  160. package/src/claude/desktop-profile.ts +263 -0
  161. package/src/claude/gateway-cache.ts +70 -0
  162. package/src/claude/inbound-debug.ts +163 -0
  163. package/src/claude/inbound.ts +519 -0
  164. package/src/claude/model-info.ts +154 -0
  165. package/src/claude/outbound.ts +898 -0
  166. package/src/cli/access.ts +108 -0
  167. package/src/cli/account-api.ts +296 -0
  168. package/src/cli/account-auth.ts +250 -0
  169. package/src/cli/account-catalog-refresh.ts +14 -0
  170. package/src/cli/account-extended.ts +476 -0
  171. package/src/cli/account-main.ts +317 -0
  172. package/src/cli/account.ts +297 -0
  173. package/src/cli/agent-driven.ts +70 -0
  174. package/src/cli/agent.ts +184 -0
  175. package/src/cli/catalog-prewarm.ts +27 -0
  176. package/src/cli/claude-desktop.ts +211 -0
  177. package/src/cli/claude.ts +302 -0
  178. package/src/cli/codex-shim-autorestore.ts +45 -0
  179. package/src/cli/codex-shim-readiness.ts +69 -0
  180. package/src/cli/combo.ts +124 -0
  181. package/src/cli/config-command.ts +183 -0
  182. package/src/cli/debug.ts +228 -0
  183. package/src/cli/desktop-first-run.ts +25 -0
  184. package/src/cli/doctor.ts +1022 -0
  185. package/src/cli/export-command.ts +201 -0
  186. package/src/cli/help.ts +370 -0
  187. package/src/cli/index.ts +1565 -0
  188. package/src/cli/init.ts +224 -0
  189. package/src/cli/integrations.ts +225 -0
  190. package/src/cli/interactive-confirm.ts +133 -0
  191. package/src/cli/internal-dispatch.ts +35 -0
  192. package/src/cli/launcher-context.ts +77 -0
  193. package/src/cli/models-runtime.ts +224 -0
  194. package/src/cli/models.ts +340 -0
  195. package/src/cli/observe.ts +170 -0
  196. package/src/cli/opencode.ts +587 -0
  197. package/src/cli/provider-runtime.ts +179 -0
  198. package/src/cli/provider.ts +476 -0
  199. package/src/cli/ready.ts +301 -0
  200. package/src/cli/route-policy.ts +92 -0
  201. package/src/cli/runtime-api.ts +328 -0
  202. package/src/cli/star-prompt.ts +211 -0
  203. package/src/cli/status-oauth.ts +78 -0
  204. package/src/cli/status.ts +321 -0
  205. package/src/cli/system-command.ts +196 -0
  206. package/src/cli/system-restart-client.ts +146 -0
  207. package/src/cli/tray-proxy.ts +205 -0
  208. package/src/cli/v2.ts +200 -0
  209. package/src/cli.ts +10 -0
  210. package/src/clients/config-export.ts +1109 -0
  211. package/src/codex/account-id.ts +34 -0
  212. package/src/codex/account-label.ts +34 -0
  213. package/src/codex/account-lifecycle.ts +172 -0
  214. package/src/codex/account-namespace-match.ts +63 -0
  215. package/src/codex/account-namespaces.ts +195 -0
  216. package/src/codex/account-pause.ts +20 -0
  217. package/src/codex/account-priority.ts +83 -0
  218. package/src/codex/account-runtime-state.ts +31 -0
  219. package/src/codex/account-store.ts +517 -0
  220. package/src/codex/account-usability.ts +40 -0
  221. package/src/codex/admission.ts +263 -0
  222. package/src/codex/app-server-processes.ts +799 -0
  223. package/src/codex/auth-api.ts +2098 -0
  224. package/src/codex/auth-collision.ts +107 -0
  225. package/src/codex/auth-context.ts +480 -0
  226. package/src/codex/autostart-health.ts +156 -0
  227. package/src/codex/catalog/account-models.ts +67 -0
  228. package/src/codex/catalog/aggregation.ts +471 -0
  229. package/src/codex/catalog/bundled.ts +533 -0
  230. package/src/codex/catalog/effort.ts +432 -0
  231. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  232. package/src/codex/catalog/kinds.ts +2 -0
  233. package/src/codex/catalog/metadata.ts +287 -0
  234. package/src/codex/catalog/native-models.ts +7 -0
  235. package/src/codex/catalog/parsing.ts +503 -0
  236. package/src/codex/catalog/provider-fetch.ts +2267 -0
  237. package/src/codex/catalog/sync.ts +1606 -0
  238. package/src/codex/catalog-admission.ts +197 -0
  239. package/src/codex/catalog-refresh-status.ts +87 -0
  240. package/src/codex/catalog-write-serialization.ts +242 -0
  241. package/src/codex/catalog.ts +15 -0
  242. package/src/codex/codex-write-lock.ts +384 -0
  243. package/src/codex/convergence-types.ts +593 -0
  244. package/src/codex/convergence.ts +580 -0
  245. package/src/codex/custom-model-catalog-migration.ts +176 -0
  246. package/src/codex/data/upstream-models.json +830 -0
  247. package/src/codex/desired-state.ts +230 -0
  248. package/src/codex/desktop-client-processes.ts +521 -0
  249. package/src/codex/exec-invocation.ts +22 -0
  250. package/src/codex/features.ts +1091 -0
  251. package/src/codex/generation.ts +202 -0
  252. package/src/codex/history-job.ts +347 -0
  253. package/src/codex/history-lock.ts +242 -0
  254. package/src/codex/history-migration-guardian.ts +115 -0
  255. package/src/codex/history-provider.ts +1075 -0
  256. package/src/codex/history-transition.ts +105 -0
  257. package/src/codex/history-worker.ts +204 -0
  258. package/src/codex/home.ts +206 -0
  259. package/src/codex/inject-coordination.ts +257 -0
  260. package/src/codex/inject.ts +1857 -0
  261. package/src/codex/injected-marker.ts +79 -0
  262. package/src/codex/integration-record.ts +266 -0
  263. package/src/codex/internal/catalog-writer.ts +203 -0
  264. package/src/codex/internal/history-writer.ts +105 -0
  265. package/src/codex/journal.ts +172 -0
  266. package/src/codex/main-account-cache.ts +56 -0
  267. package/src/codex/main-account.ts +40 -0
  268. package/src/codex/management-convergence.ts +114 -0
  269. package/src/codex/model-cache.ts +267 -0
  270. package/src/codex/native-main-admission.ts +47 -0
  271. package/src/codex/native-main-auth-temp.ts +187 -0
  272. package/src/codex/native-main-claim.ts +167 -0
  273. package/src/codex/native-main-lock-file.ts +162 -0
  274. package/src/codex/native-main-owner.ts +329 -0
  275. package/src/codex/native-profile-api.ts +247 -0
  276. package/src/codex/native-profile-manager.ts +1531 -0
  277. package/src/codex/native-profile-processes.ts +121 -0
  278. package/src/codex/native-profile-recovery.ts +99 -0
  279. package/src/codex/native-profile-stage-store.ts +387 -0
  280. package/src/codex/native-profile-startup.ts +348 -0
  281. package/src/codex/native-profile-store.ts +855 -0
  282. package/src/codex/native-profile-types.ts +120 -0
  283. package/src/codex/native-residue.ts +691 -0
  284. package/src/codex/paths.ts +78 -0
  285. package/src/codex/plugins-doctor.ts +242 -0
  286. package/src/codex/pool-rotation.ts +295 -0
  287. package/src/codex/project-config-warnings.ts +426 -0
  288. package/src/codex/prompt-journal.ts +311 -0
  289. package/src/codex/prompt-layers.ts +967 -0
  290. package/src/codex/prompt-lock.ts +143 -0
  291. package/src/codex/provider-adoption.ts +242 -0
  292. package/src/codex/quota-rejection.ts +224 -0
  293. package/src/codex/quota.ts +494 -0
  294. package/src/codex/refresh.ts +60 -0
  295. package/src/codex/routing.ts +1855 -0
  296. package/src/codex/runtime.ts +659 -0
  297. package/src/codex/shim.ts +1215 -0
  298. package/src/codex/subagent-defaults.ts +557 -0
  299. package/src/codex/subagent-model-fallback.ts +560 -0
  300. package/src/codex/sync.ts +238 -0
  301. package/src/codex/transition-state.ts +612 -0
  302. package/src/codex/upstream-host-health.ts +368 -0
  303. package/src/codex/user-identity.ts +374 -0
  304. package/src/codex/warmup.ts +192 -0
  305. package/src/codex/websocket-registry.ts +100 -0
  306. package/src/codex/write-coordination.ts +114 -0
  307. package/src/combos/failover.ts +140 -0
  308. package/src/combos/index.ts +44 -0
  309. package/src/combos/request.ts +64 -0
  310. package/src/combos/resolve.ts +232 -0
  311. package/src/combos/types.ts +392 -0
  312. package/src/config.ts +3270 -0
  313. package/src/generated/model-metadata.ts +144 -0
  314. package/src/github/star-state.ts +203 -0
  315. package/src/grok/inject.ts +540 -0
  316. package/src/grok/inspect.ts +45 -0
  317. package/src/grok/status.ts +127 -0
  318. package/src/grok/sync.ts +66 -0
  319. package/src/images/artifacts.ts +516 -0
  320. package/src/images/fulfill-video.ts +163 -0
  321. package/src/images/fulfill.ts +149 -0
  322. package/src/images/index.ts +4 -0
  323. package/src/images/loop.ts +922 -0
  324. package/src/images/plan.ts +133 -0
  325. package/src/images/synthetic-tool.ts +133 -0
  326. package/src/images/types.ts +41 -0
  327. package/src/images/xai-client.ts +141 -0
  328. package/src/images/xai-video-client.ts +163 -0
  329. package/src/index.ts +22 -0
  330. package/src/integrations/config-io.ts +151 -0
  331. package/src/integrations/journal.ts +315 -0
  332. package/src/integrations/merge.ts +135 -0
  333. package/src/integrations/native/ownership-preflight.ts +202 -0
  334. package/src/integrations/ownership.ts +111 -0
  335. package/src/integrations/registry.ts +108 -0
  336. package/src/integrations/serialize.ts +235 -0
  337. package/src/integrations/state.ts +290 -0
  338. package/src/integrations/store.ts +103 -0
  339. package/src/integrations/writer.ts +492 -0
  340. package/src/lib/abort.ts +146 -0
  341. package/src/lib/admin-secrets.ts +25 -0
  342. package/src/lib/admission.ts +83 -0
  343. package/src/lib/app-owned-memory-stores.ts +173 -0
  344. package/src/lib/app-owned-memory.ts +265 -0
  345. package/src/lib/bounded-body.ts +242 -0
  346. package/src/lib/bun-binary-validator.d.mts +3 -0
  347. package/src/lib/bun-binary-validator.mjs +18 -0
  348. package/src/lib/bun-runtime.ts +184 -0
  349. package/src/lib/bun-stream-caps.ts +127 -0
  350. package/src/lib/config-ownership.ts +438 -0
  351. package/src/lib/crash-guard.ts +344 -0
  352. package/src/lib/debug-log-buffer.ts +83 -0
  353. package/src/lib/debug-settings.ts +108 -0
  354. package/src/lib/debug.ts +31 -0
  355. package/src/lib/destination-policy.ts +316 -0
  356. package/src/lib/errors.ts +364 -0
  357. package/src/lib/eventstream-decoder.ts +253 -0
  358. package/src/lib/gcp-adc.ts +341 -0
  359. package/src/lib/injection-debug-log.ts +58 -0
  360. package/src/lib/local-management-attestation.ts +51 -0
  361. package/src/lib/open-url.ts +25 -0
  362. package/src/lib/pinned-http.ts +182 -0
  363. package/src/lib/privacy.ts +20 -0
  364. package/src/lib/process-control.ts +168 -0
  365. package/src/lib/provider-environment.ts +470 -0
  366. package/src/lib/provider-outbound.ts +203 -0
  367. package/src/lib/provider-url.ts +14 -0
  368. package/src/lib/proxy-env.ts +18 -0
  369. package/src/lib/redact.ts +510 -0
  370. package/src/lib/remodex-home.ts +616 -0
  371. package/src/lib/retry-after.ts +55 -0
  372. package/src/lib/service-secrets.ts +178 -0
  373. package/src/lib/shadow-call.ts +54 -0
  374. package/src/lib/sidecar-tracker.ts +52 -0
  375. package/src/lib/sse-decoder.ts +364 -0
  376. package/src/lib/state-store-registrations.ts +109 -0
  377. package/src/lib/state-store-sweeper.ts +184 -0
  378. package/src/lib/system-restart-contract.ts +73 -0
  379. package/src/lib/test-home-guard.ts +98 -0
  380. package/src/lib/token-estimate.ts +69 -0
  381. package/src/lib/translator-budget.ts +366 -0
  382. package/src/lib/upstream-reachability.ts +91 -0
  383. package/src/lib/upstream-retry.ts +508 -0
  384. package/src/lib/win-exec.ts +115 -0
  385. package/src/lib/win-paths.ts +68 -0
  386. package/src/lib/windows-elevation.ts +705 -0
  387. package/src/lib/windows-secret-acl.ts +817 -0
  388. package/src/lib/windows-user-principal.ts +283 -0
  389. package/src/lib/winsw.ts +402 -0
  390. package/src/model-sources.ts +73 -0
  391. package/src/oauth/anthropic-routing.ts +594 -0
  392. package/src/oauth/anthropic.ts +177 -0
  393. package/src/oauth/callback-server.ts +294 -0
  394. package/src/oauth/chatgpt.ts +150 -0
  395. package/src/oauth/command-code.ts +239 -0
  396. package/src/oauth/cursor.ts +231 -0
  397. package/src/oauth/github-copilot.ts +428 -0
  398. package/src/oauth/google-antigravity.ts +230 -0
  399. package/src/oauth/health.ts +443 -0
  400. package/src/oauth/index.ts +1280 -0
  401. package/src/oauth/key-providers.ts +128 -0
  402. package/src/oauth/kimi.ts +213 -0
  403. package/src/oauth/kiro-credentials.ts +726 -0
  404. package/src/oauth/kiro.ts +621 -0
  405. package/src/oauth/local-token-detect.ts +121 -0
  406. package/src/oauth/log.ts +48 -0
  407. package/src/oauth/login-cli.ts +163 -0
  408. package/src/oauth/pkce.ts +15 -0
  409. package/src/oauth/store.ts +655 -0
  410. package/src/oauth/token-guardian.ts +309 -0
  411. package/src/oauth/types.ts +62 -0
  412. package/src/oauth/xai.ts +241 -0
  413. package/src/providers/alibaba-region-backup.ts +75 -0
  414. package/src/providers/alibaba-region-migration.ts +156 -0
  415. package/src/providers/alibaba-region-startup.ts +36 -0
  416. package/src/providers/antigravity-models.ts +317 -0
  417. package/src/providers/api-keys.ts +140 -0
  418. package/src/providers/base-url-choices.ts +64 -0
  419. package/src/providers/codex-capacity.ts +288 -0
  420. package/src/providers/command-code-efforts.ts +85 -0
  421. package/src/providers/context-cap.ts +73 -0
  422. package/src/providers/derive.ts +451 -0
  423. package/src/providers/free-directory.ts +187 -0
  424. package/src/providers/github-copilot-transport.ts +56 -0
  425. package/src/providers/google-vertex-location.ts +14 -0
  426. package/src/providers/key-failover.ts +271 -0
  427. package/src/providers/kiro-models.ts +67 -0
  428. package/src/providers/label.ts +19 -0
  429. package/src/providers/model-discovery-limits.ts +16 -0
  430. package/src/providers/model-discovery.ts +361 -0
  431. package/src/providers/openai-sidecar.ts +235 -0
  432. package/src/providers/openai-tier-startup.ts +27 -0
  433. package/src/providers/openai-tiers.ts +301 -0
  434. package/src/providers/openai-virtual-models.ts +83 -0
  435. package/src/providers/openrouter-routing.ts +102 -0
  436. package/src/providers/provider-id-rewrite.ts +179 -0
  437. package/src/providers/quota.ts +1942 -0
  438. package/src/providers/reasoning-capabilities.ts +336 -0
  439. package/src/providers/registry.ts +2375 -0
  440. package/src/providers/slug-codec.ts +74 -0
  441. package/src/providers/xai-transport.ts +149 -0
  442. package/src/reasoning-effort.ts +243 -0
  443. package/src/responses/compaction.ts +124 -0
  444. package/src/responses/hosted-tool-policy.ts +9 -0
  445. package/src/responses/parser.ts +714 -0
  446. package/src/responses/reasoning-envelope.ts +60 -0
  447. package/src/responses/reasoning-replay-cache.ts +106 -0
  448. package/src/responses/schema.ts +159 -0
  449. package/src/responses/spill-store.ts +431 -0
  450. package/src/responses/state.ts +1039 -0
  451. package/src/responses/tool-groups.ts +19 -0
  452. package/src/router.ts +802 -0
  453. package/src/routing/analytics.ts +377 -0
  454. package/src/routing/capability.ts +205 -0
  455. package/src/routing/cost.ts +77 -0
  456. package/src/routing/evaluator.ts +444 -0
  457. package/src/routing/health.ts +401 -0
  458. package/src/routing/history/cursor.ts +43 -0
  459. package/src/routing/history/indexer.ts +605 -0
  460. package/src/routing/history/schema.ts +72 -0
  461. package/src/routing/profile-namespace.ts +15 -0
  462. package/src/routing/profile.ts +424 -0
  463. package/src/routing/quota.ts +145 -0
  464. package/src/routing/request-evidence.ts +45 -0
  465. package/src/routing/trace.ts +686 -0
  466. package/src/server/adapter-resolve.ts +83 -0
  467. package/src/server/auth-cors.ts +606 -0
  468. package/src/server/chat-completions.ts +379 -0
  469. package/src/server/claude-messages.ts +980 -0
  470. package/src/server/effort-policy.ts +251 -0
  471. package/src/server/github-copilot-responses-repair.ts +338 -0
  472. package/src/server/gui-static.ts +152 -0
  473. package/src/server/image-retry.ts +42 -0
  474. package/src/server/images.ts +485 -0
  475. package/src/server/index.ts +1633 -0
  476. package/src/server/lifecycle.ts +482 -0
  477. package/src/server/live.ts +609 -0
  478. package/src/server/management/agent-settings-routes.ts +1180 -0
  479. package/src/server/management/android-remote-routes.ts +390 -0
  480. package/src/server/management/api-access.ts +141 -0
  481. package/src/server/management/api-key-usage.ts +167 -0
  482. package/src/server/management/body.ts +35 -0
  483. package/src/server/management/combo-routes.ts +244 -0
  484. package/src/server/management/config-routes.ts +602 -0
  485. package/src/server/management/context.ts +88 -0
  486. package/src/server/management/integration-routes.ts +538 -0
  487. package/src/server/management/logs-usage-routes.ts +516 -0
  488. package/src/server/management/model-routes.ts +519 -0
  489. package/src/server/management/model-rows.ts +143 -0
  490. package/src/server/management/native-integration-routes.ts +781 -0
  491. package/src/server/management/oauth-account-routes.ts +573 -0
  492. package/src/server/management/provider-routes.ts +781 -0
  493. package/src/server/management/request-history-routes.ts +191 -0
  494. package/src/server/management/routing-analytics-routes.ts +74 -0
  495. package/src/server/management/routing-profile-routes.ts +384 -0
  496. package/src/server/management/shared.ts +277 -0
  497. package/src/server/management/sidebar-routes.ts +106 -0
  498. package/src/server/management/sync-response.ts +69 -0
  499. package/src/server/management/system-restart.ts +433 -0
  500. package/src/server/management/system-routes.ts +141 -0
  501. package/src/server/management/usage-summary-cache.ts +86 -0
  502. package/src/server/management-api.ts +269 -0
  503. package/src/server/management-auth.ts +353 -0
  504. package/src/server/memory-watchdog.ts +156 -0
  505. package/src/server/port-reclaim.ts +307 -0
  506. package/src/server/ports.ts +156 -0
  507. package/src/server/proxy-liveness.ts +326 -0
  508. package/src/server/proxy-stop.ts +92 -0
  509. package/src/server/readiness.ts +99 -0
  510. package/src/server/relay-eager.ts +353 -0
  511. package/src/server/relay.ts +1179 -0
  512. package/src/server/request-decompress.ts +132 -0
  513. package/src/server/request-log-conversation.ts +168 -0
  514. package/src/server/request-log.ts +1072 -0
  515. package/src/server/responses/collaboration.ts +409 -0
  516. package/src/server/responses/compact.ts +710 -0
  517. package/src/server/responses/core.ts +3561 -0
  518. package/src/server/responses/encrypted-payload.ts +308 -0
  519. package/src/server/responses/fetch-helpers.ts +171 -0
  520. package/src/server/responses/passthrough-error.ts +78 -0
  521. package/src/server/responses/policy-fallback.ts +152 -0
  522. package/src/server/responses/terminal-guard.ts +230 -0
  523. package/src/server/responses/upstream-error.ts +48 -0
  524. package/src/server/responses-image-gen-repair.ts +132 -0
  525. package/src/server/responses-item-id-repair.ts +272 -0
  526. package/src/server/responses-json-events.ts +52 -0
  527. package/src/server/responses-model-rewrite.ts +29 -0
  528. package/src/server/responses-snapshot-repair.ts +621 -0
  529. package/src/server/responses.ts +10 -0
  530. package/src/server/search.ts +181 -0
  531. package/src/server/sse-frame-buffer.ts +292 -0
  532. package/src/server/sse-payload-rewrite.ts +263 -0
  533. package/src/server/startup-action-control.ts +308 -0
  534. package/src/server/startup-health-cache.ts +119 -0
  535. package/src/server/system-env.ts +418 -0
  536. package/src/server/windows-tcp-drop.ts +184 -0
  537. package/src/server/windows-tray-control.ts +41 -0
  538. package/src/server/ws-bridge.ts +470 -0
  539. package/src/service-manager-probe.ts +824 -0
  540. package/src/service.ts +3011 -0
  541. package/src/stall-timeout.ts +20 -0
  542. package/src/storage/cleanup-job.ts +57 -0
  543. package/src/storage/cleanup.ts +3085 -0
  544. package/src/storage/policy-job.ts +457 -0
  545. package/src/storage/policy-scheduler.ts +40 -0
  546. package/src/storage/policy-worker.ts +59 -0
  547. package/src/storage/policy.ts +527 -0
  548. package/src/storage/restore-job.ts +299 -0
  549. package/src/storage/restore-worker.ts +58 -0
  550. package/src/storage/scanner.ts +238 -0
  551. package/src/storage/storage-mutation-coordinator.ts +139 -0
  552. package/src/storage/worker-lifecycle.ts +215 -0
  553. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  554. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  555. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  556. package/src/tray/assets/opencodex-tray.png +0 -0
  557. package/src/tray/windows-tray.ps1 +364 -0
  558. package/src/tray/windows.ts +738 -0
  559. package/src/types.ts +1531 -0
  560. package/src/update/badge.ts +72 -0
  561. package/src/update/desktop-release.ts +1620 -0
  562. package/src/update/index.ts +402 -0
  563. package/src/update/job.ts +1906 -0
  564. package/src/update/notify.ts +261 -0
  565. package/src/update/npm-cache-preflight.d.mts +47 -0
  566. package/src/update/npm-cache-preflight.mjs +201 -0
  567. package/src/update/npm-invocation.d.mts +23 -0
  568. package/src/update/npm-invocation.mjs +94 -0
  569. package/src/update/tray-update-plan.d.mts +18 -0
  570. package/src/update/tray-update-plan.mjs +38 -0
  571. package/src/usage/cost.ts +0 -0
  572. package/src/usage/debug.ts +97 -0
  573. package/src/usage/expected-prices.ts +283 -0
  574. package/src/usage/log.ts +695 -0
  575. package/src/usage/summary.ts +585 -0
  576. package/src/usage/totals.ts +14 -0
  577. package/src/vision/anthropic-describe.ts +185 -0
  578. package/src/vision/describe.ts +127 -0
  579. package/src/vision/index.ts +558 -0
  580. package/src/vision/reasoning.ts +55 -0
  581. package/src/web-search/anthropic-executor.ts +189 -0
  582. package/src/web-search/executor.ts +105 -0
  583. package/src/web-search/format-result.ts +89 -0
  584. package/src/web-search/index.ts +196 -0
  585. package/src/web-search/loop.ts +791 -0
  586. package/src/web-search/parse.ts +235 -0
  587. package/src/web-search/progress-stream.ts +342 -0
  588. package/src/web-search/synthetic-tool.ts +47 -0
@@ -0,0 +1,710 @@
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 { NoEligiblePolicyCandidateError, routeModel } from "../../router";
13
+ import { evidenceFromBody } from "../../routing/request-evidence";
14
+ import {
15
+ advanceComboAfterFailure,
16
+ comboDefaultEffort,
17
+ comboFailureDecision,
18
+ comboIdFromRawBody,
19
+ concreteComboRequestBody,
20
+ getCombo,
21
+ isComboTargetInCooldown,
22
+ NoAvailableComboTargetsError,
23
+ noteComboSuccess,
24
+ parseRetryAfterMs,
25
+ pickComboTarget,
26
+ targetKey,
27
+ } from "../../combos";
28
+ import { isInjectionDebugEnabled } from "../../lib/debug-settings";
29
+ import { injectionDebugLog } from "../../lib/injection-debug-log";
30
+ import { modelInList, namespacedToolName } from "../../types";
31
+ import type { AdapterEvent, CodexAccountMode, OcxConfig, OcxParsedRequest, OcxProviderConfig, OcxProviderContinuationState, OcxUsage } from "../../types";
32
+ import {
33
+ forceRefreshOAuthAccessSnapshot,
34
+ getOAuthCredentialApiBaseUrl,
35
+ getOAuthCredentialProjectId,
36
+ getValidAccessTokenSnapshot,
37
+ type OAuthAccessSnapshot,
38
+ UnsupportedOAuthProviderError,
39
+ } from "../../oauth";
40
+ import { buildWebSearchTool, planWebSearch, runWithWebSearch, shouldResolveOpenAiWebSearchSidecar } from "../../web-search";
41
+ import { describeImagesInPlace, planVisionSidecar, shouldResolveOpenAiVisionSidecar, stripImagesInPlace } from "../../vision";
42
+ import { createAdapterEventQueue, preflightAdapterEvents } from "../../adapters/run-turn-queue";
43
+ import {
44
+ applyCodexAuthContextToProvider,
45
+ CodexAccountCooldownError,
46
+ codexMainProfileDrainingResponse,
47
+ cooldownErrorResponse,
48
+ CodexAuthContextError,
49
+ CodexDirectAuthenticationError,
50
+ CodexMainProfileDrainingError,
51
+ CodexPoolAuthenticationError,
52
+ CodexThreadAffinityExpiredError,
53
+ headersForCodexAuthContext,
54
+ isCodexAuthContextUsable,
55
+ resolveCodexAuthContext,
56
+ codexProbeLeaseId,
57
+ codexProbeQuotaScope,
58
+ releaseCodexAuthContextProbeLease,
59
+ type CodexAuthContext,
60
+ } from "../../codex/auth-context";
61
+ import {
62
+ formatCodexProviderForLog,
63
+ recordCodexUpstreamOutcome,
64
+ type CodexUpstreamOutcome,
65
+ } from "../../codex/routing";
66
+ import {
67
+ fetchWithResetRetry,
68
+ fetchWithTransientRetry,
69
+ applyUpstreamRecoveryInit,
70
+ type UpstreamSendRecovery,
71
+ } from "../../lib/upstream-retry";
72
+ import { classifyTransportFailureKind, transportErrorCode } from "../../lib/upstream-reachability";
73
+ import {
74
+ acquireUpstreamHostAdmission,
75
+ disableUpstreamHostCircuitForKey,
76
+ normalizeUpstreamHostCircuitThreshold,
77
+ recordUpstreamHostFailure,
78
+ releaseUpstreamHostAdmission,
79
+ resetUpstreamHostHealth,
80
+ upstreamHostHealthKey,
81
+ type UpstreamHostAdmissionLease,
82
+ } from "../../codex/upstream-host-health";
83
+ import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "../auth-cors";
84
+ import { listOpenAiForwardSidecarCandidates, resolveFirstUsableOpenAiSidecar, type ResolvedOpenAiForwardSidecar } from "../../providers/openai-sidecar";
85
+ import { isCanonicalOpenAiForwardProvider, supportsNativeResponsesCompactEndpoint } from "../../providers/openai-tiers";
86
+ import { slugsEquivalent } from "../../providers/slug-codec";
87
+ import { applyOpenAiVirtualModel, resolveOpenAiCompactModel } from "../../providers/openai-virtual-models";
88
+ import { isUsageDebugEnabled } from "../../usage/debug";
89
+ import { readJsonRequestBody, DecompressedBodyTooLargeError, UnsupportedContentEncodingError } from "../request-decompress";
90
+ import { resolveAdapter, resolveWireProtocolOverride } from "../adapter-resolve";
91
+ import { hasKeyPoolFailover, rotateProviderTransportOn429 } from "../../providers/key-failover";
92
+ import { shouldAttemptImageTierRetry } from "../image-retry";
93
+ import { resolveProviderTransport } from "../../providers/xai-transport";
94
+ import type { WsData } from "../ws-bridge";
95
+ import { codexAccountSelectionForTurn, registerTurn, trackStreamLifetime, unregisterTurn } from "../lifecycle";
96
+ import type { AdmissionLease } from "../../lib/admission";
97
+ import { redactSecretString } from "../../lib/redact";
98
+ import { readBoundedResponseBody } from "../../lib/bounded-body";
99
+ import { supportedLadderFor } from "../effort-policy";
100
+ import {
101
+ beginRequestAttempt,
102
+ catalogModelSupportsServiceTier,
103
+ finishRequestAttempt,
104
+ inspectResponseLogJson,
105
+ noteAttemptSend,
106
+ readConfiguredCodexServiceTier,
107
+ requestLogSpeedLabel,
108
+ sealRequestAttemptIdentity,
109
+ usageFromResponsesPayload,
110
+ type RequestLogContext,
111
+ } from "../request-log";
112
+ import type { AttemptRecoveryKind } from "../../usage/log";
113
+ import {
114
+ consumeForInspection,
115
+ consumeForResponseLogMetadata,
116
+ markNativePassthroughSseResponse,
117
+ relaySseWithFailedTail,
118
+ relayWithAbort,
119
+ sanitizePassthroughHeaders,
120
+ } from "../relay";
121
+ import { hasResponsesItemIdRepair, relaySseWithResponsesItemIdRepair } from "../responses-item-id-repair";
122
+ import type { EffectiveSubagentRoster, SpawnAgentSurface } from "../../codex/catalog";
123
+
124
+ import {
125
+ decodeRequestErrorResponse,
126
+ handleResponses,
127
+ preAuthUpstreamHostCircuitKey,
128
+ upstreamHostCircuitOpenResponse,
129
+ usesCodexForwardPoolAuth,
130
+ } from "./core";
131
+ import { fetchWithHeaderTimeout, providerFetch, safeHostLabel, safeOriginLabel } from "./fetch-helpers";
132
+
133
+ export const COMPACT_RESPONSE_MAX_BYTES = 32 * 1024 * 1024;
134
+
135
+ export function compactResponseTooLargeError(): Response {
136
+ return new Response(JSON.stringify({
137
+ error: {
138
+ message: "Compact response exceeded 32 MiB",
139
+ type: "compact_response_too_large",
140
+ code: "compact_response_too_large",
141
+ },
142
+ }), { status: 502, headers: { "Content-Type": "application/json" } });
143
+ }
144
+
145
+
146
+
147
+ /**
148
+ * Resolve one eligible pool account other than `excludeAccountId`, and build everything
149
+ * the alternate send needs. Returns null when no alternate exists or construction fails,
150
+ * in which case the caller keeps the first account's rejection intact.
151
+ *
152
+ * Mirrors the auth resolution the native compact branch already does for the first
153
+ * account, so the alternate is built the same way rather than through a second,
154
+ * divergent path.
155
+ */
156
+ async function resolveAlternateCompactContext(args: {
157
+ req: Request;
158
+ config: OcxConfig;
159
+ route: { provider: OcxProviderConfig; codexAccountMode?: CodexAccountMode };
160
+ selectedModelId: string | undefined;
161
+ excludeAccountId: string | null;
162
+ turnAdmissionLease?: AdmissionLease;
163
+ }): Promise<{ authCtx: CodexAuthContext; provider: OcxProviderConfig; headers: Headers } | null> {
164
+ const { req, config, route, selectedModelId, excludeAccountId, turnAdmissionLease } = args;
165
+ if (!route.codexAccountMode || !excludeAccountId) return null;
166
+ try {
167
+ const authCtx = await resolveCodexAuthContext(req.headers, config, route.codexAccountMode, {
168
+ ...(selectedModelId ? { modelId: selectedModelId } : {}),
169
+ excludeAccountId,
170
+ beginCodexAccountSelection: codexAccountSelectionForTurn(turnAdmissionLease),
171
+ });
172
+ if (!authCtx.accountId || authCtx.accountId === excludeAccountId) return null;
173
+ const provider = applyCodexAuthContextToProvider(route.provider, authCtx, route.codexAccountMode);
174
+ const headers = new Headers({ "content-type": "application/json" });
175
+ const selected = headersForCodexAuthContext(req.headers, authCtx);
176
+ for (const name of FORWARD_HEADERS) {
177
+ const value = selected.get(name);
178
+ if (value) headers.set(name, value);
179
+ }
180
+ const override = (provider as { _codexAccountOverride?: { accessToken: string; chatgptAccountId: string } })._codexAccountOverride;
181
+ if (override) {
182
+ headers.set("authorization", `Bearer ${override.accessToken}`);
183
+ headers.set("chatgpt-account-id", override.chatgptAccountId);
184
+ }
185
+ if (provider.apiKey) headers.set("authorization", `Bearer ${resolveEnvValue(provider.apiKey)}`);
186
+ return { authCtx, provider, headers };
187
+ } catch (err) {
188
+ if (err instanceof CodexMainProfileDrainingError) {
189
+ // The native-main fence can start after account A has already rejected the
190
+ // request. Treat the now-fenced main profile as no alternate and preserve A's
191
+ // real rejection instead of replacing it with a synthetic drain response.
192
+ return null;
193
+ }
194
+ // No eligible alternate (all cooled, affinity expired, reauth needed) — the caller
195
+ // returns the first account's rejection unchanged, which is today's behavior.
196
+ return null;
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Headers a client needs to back off correctly after a pool rejection. The buffered
202
+ * response is rebuilt from scratch, so anything not listed here is dropped — which is
203
+ * what silently discarded `Retry-After` and the reset hints from a 429 before.
204
+ * Deliberately narrow: no hop-by-hop headers, no content-length (the buffered body sets
205
+ * its own), no cookies.
206
+ */
207
+ const COMPACT_PASSTHROUGH_HEADERS = [
208
+ "retry-after",
209
+ "x-codex-primary-reset-at",
210
+ "x-codex-secondary-reset-at",
211
+ "x-codex-tertiary-reset-at",
212
+ // A relayed 3xx keeps its Location so the client can follow it (#914).
213
+ "location",
214
+ ];
215
+
216
+ function compactResponseHeaders(upstream: Response): Headers {
217
+ const headers = new Headers({ "Content-Type": upstream.headers.get("content-type") ?? "application/json" });
218
+ for (const name of COMPACT_PASSTHROUGH_HEADERS) {
219
+ const value = upstream.headers.get(name);
220
+ if (value) headers.set(name, value);
221
+ }
222
+ return headers;
223
+ }
224
+
225
+ export async function bufferCompactResponse(upstream: Response, signal: AbortSignal): Promise<Response> {
226
+ const reader = upstream.body?.getReader();
227
+ const headers = compactResponseHeaders(upstream);
228
+ if (!reader) return new Response(null, { status: upstream.status, statusText: upstream.statusText, headers });
229
+ const declaredLength = Number(upstream.headers.get("content-length"));
230
+ if (Number.isFinite(declaredLength) && declaredLength > COMPACT_RESPONSE_MAX_BYTES) {
231
+ await reader.cancel("compact_response_too_large").catch(() => undefined);
232
+ return compactResponseTooLargeError();
233
+ }
234
+ const chunks: Uint8Array[] = [];
235
+ let total = 0;
236
+ try {
237
+ while (true) {
238
+ if (signal.aborted) {
239
+ await reader.cancel(signal.reason).catch(() => undefined);
240
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
241
+ }
242
+ const { done, value } = await reader.read();
243
+ if (done) break;
244
+ total += value.byteLength;
245
+ if (total > COMPACT_RESPONSE_MAX_BYTES) {
246
+ await reader.cancel("compact_response_too_large").catch(() => undefined);
247
+ return compactResponseTooLargeError();
248
+ }
249
+ chunks.push(value);
250
+ }
251
+ } catch {
252
+ if (signal.aborted) return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
253
+ return formatErrorResponse(502, "upstream_error", "Failed to read compact response");
254
+ }
255
+ const body = new Uint8Array(total);
256
+ let offset = 0;
257
+ for (const chunk of chunks) {
258
+ body.set(chunk, offset);
259
+ offset += chunk.byteLength;
260
+ }
261
+ return new Response(body, { status: upstream.status, statusText: upstream.statusText, headers });
262
+ }
263
+
264
+
265
+
266
+ export async function handleResponsesCompact(
267
+ req: Request,
268
+ config: OcxConfig,
269
+ logCtx: RequestLogContext,
270
+ turnAdmissionLease?: AdmissionLease,
271
+ ): Promise<Response> {
272
+ let body: unknown;
273
+ try {
274
+ body = await readJsonRequestBody(req);
275
+ } catch (err) {
276
+ return decodeRequestErrorResponse(err, "responses-compact");
277
+ }
278
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
279
+ return formatErrorResponse(400, "invalid_request_error", "Invalid compaction request body");
280
+ }
281
+ const raw = body as { model?: unknown; input?: unknown };
282
+ if (typeof raw.model !== "string" || raw.model.length === 0) {
283
+ return formatErrorResponse(400, "invalid_request_error", "compaction request requires a model");
284
+ }
285
+
286
+ let route;
287
+ try {
288
+ // Compact requests route through the same policy evaluation as normal
289
+ // turns, so body-derived evidence (tools/image) must reach the first
290
+ // evaluation too - not only the later handleResponses dispatch.
291
+ route = routeModel(config, raw.model, evidenceFromBody(raw));
292
+ } catch (err) {
293
+ if (err instanceof NoEligiblePolicyCandidateError) {
294
+ // Persist the evaluation trace (per-candidate exclusions + the
295
+ // no-eligible reason) so a failed compact policy request stays
296
+ // auditable, matching the other request handlers.
297
+ logCtx.routeDecision = err.trace;
298
+ }
299
+ return formatErrorResponse(404, "invalid_request_error", err instanceof Error ? err.message : String(err));
300
+ }
301
+ const selectedModelId = route.modelId;
302
+ logCtx.requestedModel = raw.model;
303
+ logCtx.model = selectedModelId;
304
+ logCtx.routeDecision = route.routeDecision;
305
+ logCtx.provider = route.codexAccountNamespace
306
+ ? `${route.providerName}-${route.codexAccountNamespace}`
307
+ : route.providerName;
308
+ logCtx.providerAdapter = route.provider.adapter;
309
+ const virtual = resolveOpenAiCompactModel(route.providerName, selectedModelId);
310
+ if (virtual) {
311
+ route.modelId = virtual.wireModelId;
312
+ logCtx.model = virtual.selectedModelId;
313
+ logCtx.resolvedModel = virtual.wireModelId;
314
+ } else {
315
+ logCtx.resolvedModel = route.modelId;
316
+ }
317
+
318
+ if (route.codexAccountMode === "direct") {
319
+ try { validateForwardAdmissionCredential(req.headers, config); }
320
+ catch (err) {
321
+ if (err instanceof ForwardAdmissionCredentialError) return formatErrorResponse(401, "authentication_error", err.message);
322
+ throw err;
323
+ }
324
+ }
325
+
326
+ // Native /responses/compact exists on the canonical ChatGPT backend and on the
327
+ // official OpenAI API. Any other Responses-shaped gateway must take the routed
328
+ // summarizer path below, or compaction fails against an endpoint it never had (#422).
329
+ if (supportsNativeResponsesCompactEndpoint(route.providerName, route.provider)) {
330
+ if (req.signal.aborted) {
331
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
332
+ }
333
+ // The enclosing native-compact guard already restricts this path to
334
+ // supported backends, so compact intentionally does not require the
335
+ // regular Responses adapter check here.
336
+ const preAuthCompactHostKey = preAuthUpstreamHostCircuitKey(route, config, {
337
+ requireResponsesAdapter: false,
338
+ });
339
+ let compactHostAdmissionLease: UpstreamHostAdmissionLease | null = null;
340
+ let authCtx: CodexAuthContext = { kind: "main", accountId: null };
341
+ if (preAuthCompactHostKey) {
342
+ const admission = acquireUpstreamHostAdmission(
343
+ preAuthCompactHostKey,
344
+ config.upstreamHostCircuitThreshold,
345
+ );
346
+ if (admission.kind === "blocked") {
347
+ return upstreamHostCircuitOpenResponse(admission.retryAfterSeconds);
348
+ }
349
+ compactHostAdmissionLease = admission.lease;
350
+ }
351
+ try {
352
+ // Native ChatGPT/OpenAI model: forward the compact request verbatim to the real backend.
353
+ // Resolve the SAME pool/thread auth context as /v1/responses — forwarding the caller's raw
354
+ // headers would run compaction on the wrong account (or 401) whenever a pool account is
355
+ // active for this thread while normal turns succeed.
356
+ let compactProvider = route.provider;
357
+ const headers = new Headers({ "content-type": "application/json" });
358
+ try {
359
+ if (route.codexAccountMode) {
360
+ authCtx = await resolveCodexAuthContext(req.headers, config, route.codexAccountMode, {
361
+ accountId: route.codexAccountId,
362
+ modelId: selectedModelId,
363
+ beginCodexAccountSelection: codexAccountSelectionForTurn(turnAdmissionLease),
364
+ });
365
+ const selected = headersForCodexAuthContext(req.headers, authCtx);
366
+ compactProvider = applyCodexAuthContextToProvider(route.provider, authCtx, route.codexAccountMode);
367
+ for (const name of FORWARD_HEADERS) {
368
+ const value = selected.get(name);
369
+ if (value) headers.set(name, value);
370
+ }
371
+ const override = (compactProvider as { _codexAccountOverride?: { accessToken: string; chatgptAccountId: string } })._codexAccountOverride;
372
+ if (override) {
373
+ headers.set("authorization", `Bearer ${override.accessToken}`);
374
+ headers.set("chatgpt-account-id", override.chatgptAccountId);
375
+ }
376
+ }
377
+ } catch (err) {
378
+ if (err instanceof CodexAccountCooldownError) {
379
+ return cooldownErrorResponse(err, Date.now(), route.codexAccountNamespace);
380
+ }
381
+ if (err instanceof CodexMainProfileDrainingError) return codexMainProfileDrainingResponse();
382
+ if (err instanceof CodexThreadAffinityExpiredError) {
383
+ return formatErrorResponse(409, "invalid_request_error", "Codex thread account affinity expired; start a new session");
384
+ }
385
+ if (err instanceof CodexAuthContextError) {
386
+ return formatErrorResponse(401, "authentication_error", "Selected Codex account needs reauthentication");
387
+ }
388
+ if (err instanceof CodexPoolAuthenticationError || err instanceof CodexDirectAuthenticationError) {
389
+ return formatErrorResponse(401, "authentication_error", err.message);
390
+ }
391
+ throw err;
392
+ }
393
+ const base = (compactProvider.baseUrl ?? "").replace(/\/$/, "");
394
+ if (compactProvider.authMode !== "forward" && compactProvider.apiKey) {
395
+ headers.set("authorization", `Bearer ${resolveEnvValue(compactProvider.apiKey)}`);
396
+ }
397
+ const { reasoning: _reasoning, ...compactBodyRaw } = raw as typeof raw & { reasoning?: unknown };
398
+ // The regular /v1/responses path applies sanitizeReasoningInputContent via the adapter's
399
+ // buildRequest, but the compact endpoint forwards directly. Apply the same sanitizer here
400
+ // so routed-model reasoning items (reasoning_text content) don't 400 the ChatGPT backend.
401
+ const compactBody = sanitizeReasoningInputContent(compactBodyRaw) as typeof compactBodyRaw;
402
+ const compactUrl = `${base}/responses/compact`;
403
+ const actualCompactHostKey = upstreamHostHealthKey(
404
+ route.providerName,
405
+ safeOriginLabel(compactUrl),
406
+ );
407
+ const compactHostKey = compactProvider.authMode === "forward"
408
+ ? actualCompactHostKey
409
+ : null;
410
+ const compactHostCircuitEnabled = compactHostKey !== null
411
+ && normalizeUpstreamHostCircuitThreshold(config.upstreamHostCircuitThreshold) > 0;
412
+ if (compactHostKey !== null && !compactHostCircuitEnabled) {
413
+ disableUpstreamHostCircuitForKey(actualCompactHostKey);
414
+ }
415
+ if (compactHostAdmissionLease && compactHostAdmissionLease.key !== compactHostKey) {
416
+ releaseCodexAuthContextProbeLease(authCtx);
417
+ return formatErrorResponse(502, "upstream_error", "Provider host changed after circuit admission");
418
+ }
419
+ if (req.signal.aborted) {
420
+ releaseCodexAuthContextProbeLease(authCtx);
421
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
422
+ }
423
+ if (!compactHostAdmissionLease && compactHostCircuitEnabled) {
424
+ const admission = acquireUpstreamHostAdmission(
425
+ compactHostKey!,
426
+ config.upstreamHostCircuitThreshold,
427
+ );
428
+ if (admission.kind === "blocked") {
429
+ releaseCodexAuthContextProbeLease(authCtx);
430
+ return upstreamHostCircuitOpenResponse(admission.retryAfterSeconds);
431
+ }
432
+ compactHostAdmissionLease = admission.lease;
433
+ }
434
+ const settleObservedCompactHostResponse = (): void => {
435
+ if (compactHostCircuitEnabled) {
436
+ resetUpstreamHostHealth(actualCompactHostKey, compactHostAdmissionLease);
437
+ } else {
438
+ resetUpstreamHostHealth(actualCompactHostKey);
439
+ }
440
+ compactHostAdmissionLease = null;
441
+ };
442
+ const compactThreadId = req.headers.get("x-codex-parent-thread-id");
443
+ const connectMs = config.connectTimeoutMs ?? 200_000;
444
+ // Takes its context explicitly: the alternate-account flow below records a rejection
445
+ // against A while promoting B, then records B's own outcome. A closure over a single
446
+ // `authCtx` cannot express either.
447
+ const recordCompactPoolOutcome = (
448
+ ctx: CodexAuthContext,
449
+ outcome: CodexUpstreamOutcome,
450
+ meta: {
451
+ retryAfter?: string | null;
452
+ resetAt?: unknown | unknown[];
453
+ promoteAccountId?: string;
454
+ } = {},
455
+ ) => {
456
+ if (!usesCodexForwardPoolAuth(ctx, route.provider)) return;
457
+ recordCodexUpstreamOutcome(config, ctx.accountId, outcome, {
458
+ ...meta,
459
+ threadId: compactThreadId,
460
+ fixedAccount: ctx.fixedAccount,
461
+ modelId: selectedModelId,
462
+ probeLeaseId: codexProbeLeaseId(ctx),
463
+ probeQuotaScope: codexProbeQuotaScope(ctx),
464
+ writerGeneration: ctx.kind === "pool" || ctx.kind === "main-pool"
465
+ ? ctx.writerGeneration
466
+ : undefined,
467
+ });
468
+ };
469
+ // Two recovery modes, mirroring retryCodexPoolOnAlternateAccount() on the regular
470
+ // path (core.ts:396). The first account keeps the full ladder — transient-5xx retry
471
+ // wrapping reset retry — because those retries happen before any alternate is even
472
+ // considered. The alternate is one bounded send: a second ladder would multiply the
473
+ // work an already-rejecting pool is doing.
474
+ const sendCompactAttempt = (
475
+ sendProvider: OcxProviderConfig,
476
+ sendHeaders: Headers,
477
+ recovery: "normal" | "single",
478
+ ): Promise<Response> => {
479
+ const doFetch = (upstreamRecovery?: UpstreamSendRecovery) => fetchWithHeaderTimeout(
480
+ compactUrl,
481
+ applyUpstreamRecoveryInit({
482
+ method: "POST",
483
+ headers: sendHeaders,
484
+ body: JSON.stringify({ ...compactBody, model: route.modelId }),
485
+ }, upstreamRecovery),
486
+ req.signal,
487
+ connectMs,
488
+ false,
489
+ providerFetch(sendProvider),
490
+ // Every credential-bearing forward send gets manual redirects, not only
491
+ // pool sends: direct mode carries the caller's credential too (#914).
492
+ sendProvider.authMode === "forward",
493
+ ).then(res => {
494
+ // Every real attempt response — including an intermediate 5xx the retry
495
+ // wrapper replaces — proves the host was reached (#914 review).
496
+ settleObservedCompactHostResponse();
497
+ return res;
498
+ });
499
+ return recovery === "single"
500
+ ? doFetch()
501
+ : fetchWithTransientRetry(doFetch, { abortSignal: req.signal, label: safeHostLabel(compactUrl) });
502
+ };
503
+
504
+ // The account each outcome belongs to. Reassigned only when the alternate send below
505
+ // actually happens, so every recorder call names the context that produced it.
506
+ let outcomeCtx = authCtx;
507
+ let upstream: Response;
508
+ try {
509
+ // Same connect timeout + keep-alive reset + transient-5xx recovery as /v1/responses —
510
+ // compact hits the same ChatGPT host and must soft-avoid / clear affinity (#186).
511
+ upstream = await sendCompactAttempt(compactProvider, headers, "normal");
512
+ } catch (err) {
513
+ if (req.signal.aborted) {
514
+ recordCompactPoolOutcome(outcomeCtx, 499);
515
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
516
+ }
517
+ const outcome = classifyTransportFailureKind(err);
518
+ // Host-level evidence stands regardless of pool membership (#914 review).
519
+ if (outcome === "connect_neutral") {
520
+ if (compactHostCircuitEnabled) {
521
+ recordUpstreamHostFailure(actualCompactHostKey, {
522
+ code: transportErrorCode(err),
523
+ threshold: config.upstreamHostCircuitThreshold,
524
+ lease: compactHostAdmissionLease,
525
+ });
526
+ } else {
527
+ recordUpstreamHostFailure(actualCompactHostKey, { code: transportErrorCode(err) });
528
+ }
529
+ } else {
530
+ releaseUpstreamHostAdmission(compactHostAdmissionLease);
531
+ }
532
+ compactHostAdmissionLease = null;
533
+ recordCompactPoolOutcome(outcomeCtx, outcome);
534
+ return formatErrorResponse(502, "upstream_error", "Failed to connect to compact upstream");
535
+ }
536
+
537
+ // Bounded same-request alternate: the regular /v1/responses path already does this
538
+ // (core.ts:319-423) and recognizes exactly 429/402. Without it a pool rejection
539
+ // surfaces to the client, which retries the compact task OUTSIDE the logical request
540
+ // — reporting exhausted retries while another pool account sat idle (#913).
541
+ if (
542
+ (upstream.status === 429 || upstream.status === 402)
543
+ && usesCodexForwardPoolAuth(authCtx, route.provider)
544
+ && !authCtx.fixedAccount
545
+ && route.codexAccountMode
546
+ && !req.signal.aborted
547
+ ) {
548
+ const firstRetryAfter = upstream.headers.get("retry-after");
549
+ const firstResetAt = [
550
+ upstream.headers.get("x-codex-primary-reset-at"),
551
+ upstream.headers.get("x-codex-secondary-reset-at"),
552
+ upstream.headers.get("x-codex-tertiary-reset-at"),
553
+ ].filter(Boolean);
554
+ // Build the alternate COMPLETELY before cancelling the first body: if construction
555
+ // throws, the first rejection is still intact and can be returned to the client.
556
+ const alternate = await resolveAlternateCompactContext({
557
+ req,
558
+ config,
559
+ route,
560
+ selectedModelId,
561
+ excludeAccountId: authCtx.accountId,
562
+ turnAdmissionLease,
563
+ });
564
+ // Resolution can await a credential refresh, so the client may have gone away
565
+ // while we were choosing B. Re-check before spending anything: recording A,
566
+ // cancelling its body, and sending B are all observable side effects, and B's
567
+ // quota is not ours to spend on a request nobody is waiting for.
568
+ if (alternate && req.signal.aborted) {
569
+ releaseCodexAuthContextProbeLease(alternate.authCtx);
570
+ recordCompactPoolOutcome(outcomeCtx, 499);
571
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
572
+ }
573
+ if (alternate) {
574
+ // Same order the regular path uses (core.ts:349-357): a 429/402 carries the
575
+ // quota snapshot that produced it, so refresh A's cache before recording its
576
+ // rejection. Skipping this leaves quota-strategy routing and the dashboard
577
+ // reading numbers from before the account ran out.
578
+ if (authCtx.kind === "pool" || authCtx.kind === "main-pool") {
579
+ const { applyAccountQuotaFromUpstreamHeaders } = await import("../../codex/auth-api");
580
+ applyAccountQuotaFromUpstreamHeaders(
581
+ authCtx.accountId,
582
+ upstream.headers,
583
+ authCtx.writerGeneration,
584
+ );
585
+ }
586
+ recordCompactPoolOutcome(authCtx, upstream.status, {
587
+ retryAfter: firstRetryAfter,
588
+ resetAt: firstResetAt,
589
+ ...(alternate.authCtx.accountId ? { promoteAccountId: alternate.authCtx.accountId } : {}),
590
+ });
591
+ await upstream.body?.cancel().catch(() => undefined);
592
+ outcomeCtx = alternate.authCtx;
593
+ try {
594
+ upstream = await sendCompactAttempt(alternate.provider, alternate.headers, "single");
595
+ } catch (err) {
596
+ if (req.signal.aborted) {
597
+ recordCompactPoolOutcome(outcomeCtx, 499);
598
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
599
+ }
600
+ const outcome = classifyTransportFailureKind(err);
601
+ // Host-level evidence stands regardless of pool membership (#914 review).
602
+ if (outcome === "connect_neutral") {
603
+ if (compactHostCircuitEnabled) {
604
+ recordUpstreamHostFailure(actualCompactHostKey, {
605
+ code: transportErrorCode(err),
606
+ threshold: config.upstreamHostCircuitThreshold,
607
+ lease: compactHostAdmissionLease,
608
+ });
609
+ } else {
610
+ recordUpstreamHostFailure(actualCompactHostKey, { code: transportErrorCode(err) });
611
+ }
612
+ } else {
613
+ releaseUpstreamHostAdmission(compactHostAdmissionLease);
614
+ }
615
+ compactHostAdmissionLease = null;
616
+ recordCompactPoolOutcome(outcomeCtx, outcome);
617
+ return formatErrorResponse(502, "upstream_error", "Failed to connect to compact upstream");
618
+ }
619
+ }
620
+ }
621
+ const retryAfter = upstream.headers.get("retry-after");
622
+ const resetAt = [
623
+ upstream.headers.get("x-codex-primary-reset-at"),
624
+ upstream.headers.get("x-codex-secondary-reset-at"),
625
+ upstream.headers.get("x-codex-tertiary-reset-at"),
626
+ ].filter(Boolean);
627
+ const buffered = await bufferCompactResponse(upstream, req.signal);
628
+ // Record pool health only after the body is fully delivered (or definitively failed).
629
+ // A premature 200 would clear soft-avoid while the client still sees a buffer 502.
630
+ if (buffered.status === 499) {
631
+ recordCompactPoolOutcome(outcomeCtx, 499);
632
+ return buffered;
633
+ }
634
+ // Always record the real upstream status: a local buffering failure after a
635
+ // 200 upstream response must not soft-avoid a healthy account or rotate a thread.
636
+ recordCompactPoolOutcome(outcomeCtx, upstream.status, { retryAfter, resetAt });
637
+ // Lift usage and response metadata from the buffered upstream JSON into the
638
+ // request log; the routed branch gets the same through handleResponses. The
639
+ // synthetic buffer errors are not upstream bodies and stay uninspected.
640
+ if (buffered.ok) inspectResponseLogJson(logCtx, await buffered.clone().text());
641
+ return buffered;
642
+ } finally {
643
+ releaseUpstreamHostAdmission(compactHostAdmissionLease);
644
+ releaseCodexAuthContextProbeLease(authCtx);
645
+ }
646
+ }
647
+
648
+ // ROUTED model: run the v2 synthetic-compaction turn internally (appends COMPACT_PROMPT, no
649
+ // tools) and decode the resulting ocx1 envelope into plain v1 replacement-history items.
650
+ const inputItems = Array.isArray(raw.input) ? (raw.input as unknown[]) : [];
651
+ const internalBody = {
652
+ ...raw,
653
+ stream: false,
654
+ input: [...inputItems, { type: "compaction_trigger" }],
655
+ };
656
+ const internalHeaders = new Headers({ "content-type": "application/json" });
657
+ for (const name of FORWARD_HEADERS) {
658
+ const value = req.headers.get(name);
659
+ if (value) internalHeaders.set(name, value);
660
+ }
661
+ const internalReq = new Request("http://localhost/v1/responses", {
662
+ method: "POST",
663
+ headers: internalHeaders,
664
+ body: JSON.stringify(internalBody),
665
+ });
666
+ const response = await handleResponses(internalReq, config, logCtx, { abortSignal: req.signal, turnAdmissionLease });
667
+ if (!response.ok) return response;
668
+ let json: { output?: unknown[]; status?: unknown; error?: unknown };
669
+ try {
670
+ json = await response.json() as { output?: unknown[]; status?: unknown; error?: unknown };
671
+ } catch {
672
+ return formatErrorResponse(502, "server_error", "compaction turn returned a non-JSON response");
673
+ }
674
+ // The internal turn answers 200 even when it failed or was truncated, so the body
675
+ // has to be inspected. Reporting a failure beats installing "(no summary
676
+ // available)" as replacement history and silently losing the conversation (#422).
677
+ if (json.error) {
678
+ const message = typeof json.error === "string"
679
+ ? json.error
680
+ : (json.error as { message?: unknown })?.message;
681
+ return formatErrorResponse(502, "upstream_error", typeof message === "string" ? message : "compaction turn failed");
682
+ }
683
+ if (json.status !== "completed") {
684
+ return formatErrorResponse(
685
+ 502,
686
+ "upstream_error",
687
+ `compaction turn did not complete (status: ${String(json.status ?? "unknown")})`,
688
+ );
689
+ }
690
+ const compactionItems = (json.output ?? []).filter(
691
+ (item): item is { type: string; encrypted_content?: string } =>
692
+ !!item && typeof item === "object" && (item as { type?: string }).type === "compaction",
693
+ );
694
+ if (compactionItems.length !== 1) {
695
+ return formatErrorResponse(
696
+ 502,
697
+ "invalid_response_error",
698
+ `compaction turn produced ${compactionItems.length} compaction items, expected exactly 1`,
699
+ );
700
+ }
701
+ const encrypted = compactionItems[0]!.encrypted_content;
702
+ const decoded = typeof encrypted === "string" ? decodeCompactionSummary(encrypted) : null;
703
+ // An empty `ocx1:` envelope decodes to "" rather than null, so length is what matters.
704
+ if (decoded === null || decoded.trim().length === 0) {
705
+ return formatErrorResponse(502, "invalid_response_error", "compaction turn produced an empty summary");
706
+ }
707
+ const summary = decoded;
708
+ const output = buildCompactV1Output(extractCompactUserMessages(inputItems), summary);
709
+ return new Response(JSON.stringify({ output }), { headers: { "Content-Type": "application/json" } });
710
+ }