@iislee/opencodex 2.11.0 → 2.35.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 (733) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +117 -22
  3. package/bin/ocx.mjs +245 -88
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-Be1sDpWw.css +1 -0
  6. package/gui/dist/assets/index-D4OKgUV4.js +114 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +21 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +475 -62
  44. package/src/adapters/base.ts +82 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +637 -0
  48. package/src/adapters/cursor/call-id.ts +44 -0
  49. package/src/adapters/cursor/catalog.ts +541 -0
  50. package/src/adapters/cursor/checkpoint-store.ts +308 -0
  51. package/src/adapters/cursor/cursor-errors.ts +144 -6
  52. package/src/adapters/cursor/discovery.ts +122 -14
  53. package/src/adapters/cursor/effort-map.ts +106 -4
  54. package/src/adapters/cursor/envelope-echo.ts +290 -0
  55. package/src/adapters/cursor/framing.ts +39 -0
  56. package/src/adapters/cursor/h2-pool.ts +123 -0
  57. package/src/adapters/cursor/http1-bidi.ts +361 -0
  58. package/src/adapters/cursor/images.ts +704 -0
  59. package/src/adapters/cursor/live-models.ts +180 -59
  60. package/src/adapters/cursor/live-transport.ts +623 -170
  61. package/src/adapters/cursor/message-mapper.ts +4 -1
  62. package/src/adapters/cursor/native-exec-common.ts +23 -2
  63. package/src/adapters/cursor/native-exec-desktop.ts +23 -0
  64. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  65. package/src/adapters/cursor/native-exec-network.ts +1 -1
  66. package/src/adapters/cursor/native-exec-shell.ts +5 -3
  67. package/src/adapters/cursor/native-exec.ts +121 -14
  68. package/src/adapters/cursor/protobuf-events.ts +829 -11
  69. package/src/adapters/cursor/protobuf-request.ts +447 -75
  70. package/src/adapters/cursor/request-builder.ts +271 -35
  71. package/src/adapters/cursor/tool-definitions.ts +252 -12
  72. package/src/adapters/cursor/tool-result-normalize.ts +115 -0
  73. package/src/adapters/cursor/transport.ts +22 -0
  74. package/src/adapters/cursor/types.ts +48 -1
  75. package/src/adapters/cursor.ts +336 -39
  76. package/src/adapters/exec-tool-result-normalize.ts +99 -0
  77. package/src/adapters/google-antigravity-replay.ts +713 -41
  78. package/src/adapters/google-antigravity-wire.ts +48 -10
  79. package/src/adapters/google-errors.ts +44 -12
  80. package/src/adapters/google-http.ts +38 -10
  81. package/src/adapters/google-tool-schema.ts +80 -15
  82. package/src/adapters/google-truncation.ts +11 -0
  83. package/src/adapters/google.ts +742 -86
  84. package/src/adapters/identity.ts +39 -6
  85. package/src/adapters/image.ts +1 -1
  86. package/src/adapters/kiro-constants.ts +27 -0
  87. package/src/adapters/kiro-errors.ts +11 -0
  88. package/src/adapters/kiro-events.ts +19 -1
  89. package/src/adapters/kiro-thinking.ts +18 -2
  90. package/src/adapters/kiro-tools.ts +65 -17
  91. package/src/adapters/kiro.ts +270 -73
  92. package/src/adapters/mimo-free.ts +17 -0
  93. package/src/adapters/openai-chat-url.ts +11 -0
  94. package/src/adapters/openai-chat.ts +1377 -344
  95. package/src/adapters/openai-responses-url.ts +16 -0
  96. package/src/adapters/openai-responses.ts +1164 -64
  97. package/src/adapters/registry.ts +175 -0
  98. package/src/adapters/responses-tool-schema.ts +67 -0
  99. package/src/adapters/run-turn-queue.ts +36 -1
  100. package/src/adapters/tool-call-id.ts +119 -0
  101. package/src/adapters/tool-catalog-nudge.ts +105 -21
  102. package/src/adapters/xai-tool-schema.ts +436 -0
  103. package/src/adapters/xai-web-search.ts +186 -0
  104. package/src/bridge.ts +512 -92
  105. package/src/chat/inbound.ts +57 -20
  106. package/src/chat/outbound.ts +97 -33
  107. package/src/claude/agents-inject.ts +40 -10
  108. package/src/claude/context-windows.ts +37 -14
  109. package/src/claude/desktop-3p.ts +243 -9
  110. package/src/claude/gateway-cache.ts +41 -4
  111. package/src/claude/inbound.ts +72 -3
  112. package/src/claude/model-info.ts +38 -15
  113. package/src/claude/outbound.ts +88 -21
  114. package/src/cli/access.ts +46 -3
  115. package/src/cli/account-api.ts +150 -19
  116. package/src/cli/account-auth.ts +33 -6
  117. package/src/cli/account-catalog-refresh.ts +14 -0
  118. package/src/cli/account-extended.ts +648 -28
  119. package/src/cli/account-main.ts +317 -0
  120. package/src/cli/account.ts +97 -19
  121. package/src/cli/agent.ts +53 -2
  122. package/src/cli/alias.ts +66 -0
  123. package/src/cli/capabilities-command.ts +94 -0
  124. package/src/cli/capabilities.ts +496 -0
  125. package/src/cli/claude-agent-startup-sync.ts +73 -0
  126. package/src/cli/claude-desktop.ts +60 -15
  127. package/src/cli/claude.ts +129 -35
  128. package/src/cli/codex-log-guard-doctor.ts +103 -0
  129. package/src/cli/codex-shim-autorestore.ts +2 -0
  130. package/src/cli/codex-shim-readiness.ts +76 -0
  131. package/src/cli/combo.ts +8 -0
  132. package/src/cli/config-command.ts +74 -10
  133. package/src/cli/dispatch.ts +821 -0
  134. package/src/cli/doctor.ts +440 -56
  135. package/src/cli/ensure-desired-integrations.ts +152 -0
  136. package/src/cli/export-command.ts +46 -20
  137. package/src/cli/help.ts +34 -274
  138. package/src/cli/index.ts +417 -528
  139. package/src/cli/init.ts +5 -17
  140. package/src/cli/inspect.ts +230 -0
  141. package/src/cli/integrations.ts +120 -2
  142. package/src/cli/lab.ts +607 -0
  143. package/src/cli/launcher-context.ts +77 -0
  144. package/src/cli/minimax.ts +497 -0
  145. package/src/cli/models-runtime.ts +130 -2
  146. package/src/cli/models.ts +118 -16
  147. package/src/cli/observe.ts +123 -11
  148. package/src/cli/opencode.ts +4 -2
  149. package/src/cli/provider-runtime.ts +34 -3
  150. package/src/cli/provider.ts +25 -3
  151. package/src/cli/ready.ts +301 -0
  152. package/src/cli/registry.ts +476 -0
  153. package/src/cli/root.ts +86 -0
  154. package/src/cli/route-policy.ts +92 -0
  155. package/src/cli/runtime-api.ts +57 -10
  156. package/src/cli/star-prompt.ts +71 -15
  157. package/src/cli/status.ts +51 -4
  158. package/src/cli/storage.ts +234 -0
  159. package/src/cli/system-command.ts +16 -0
  160. package/src/cli/system-restart-client.ts +146 -0
  161. package/src/cli/tray-proxy.ts +153 -6
  162. package/src/cli/usage-report.ts +184 -0
  163. package/src/cli/v2.ts +137 -18
  164. package/src/cli/version-skew.ts +46 -0
  165. package/src/cli.ts +1 -1
  166. package/src/clients/config-export.ts +1442 -23
  167. package/src/clients/effective-status.ts +30 -2
  168. package/src/clients/probes/cline.ts +81 -0
  169. package/src/codex/account-label.ts +35 -1
  170. package/src/codex/account-lifecycle.ts +130 -13
  171. package/src/codex/account-namespaces.ts +49 -3
  172. package/src/codex/account-pause.ts +2 -1
  173. package/src/codex/account-priority.ts +84 -0
  174. package/src/codex/account-store.ts +29 -2
  175. package/src/codex/account-usability.ts +25 -2
  176. package/src/codex/admission.ts +256 -0
  177. package/src/codex/affinity-debug.ts +162 -0
  178. package/src/codex/app-server-processes.ts +570 -107
  179. package/src/codex/app-server-restart-service.ts +232 -0
  180. package/src/codex/auth-api.ts +893 -246
  181. package/src/codex/auth-collision.ts +5 -3
  182. package/src/codex/auth-context.ts +348 -32
  183. package/src/codex/autostart-health.ts +24 -1
  184. package/src/codex/catalog/account-models.ts +67 -0
  185. package/src/codex/catalog/aggregation.ts +86 -10
  186. package/src/codex/catalog/bundled.ts +331 -33
  187. package/src/codex/catalog/effort.ts +138 -32
  188. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  189. package/src/codex/catalog/kinds.ts +2 -0
  190. package/src/codex/catalog/metadata.ts +555 -45
  191. package/src/codex/catalog/native-models.ts +75 -0
  192. package/src/codex/catalog/parsing.ts +269 -30
  193. package/src/codex/catalog/provider-fetch.ts +1626 -144
  194. package/src/codex/catalog/sync.ts +1576 -187
  195. package/src/codex/catalog-admission.ts +199 -0
  196. package/src/codex/catalog-refresh-status.ts +105 -0
  197. package/src/codex/catalog-write-serialization.ts +242 -0
  198. package/src/codex/catalog.ts +6 -3
  199. package/src/codex/codex-write-lock.ts +386 -0
  200. package/src/codex/convergence-types.ts +614 -0
  201. package/src/codex/convergence.ts +676 -0
  202. package/src/codex/coordinator-doctor.ts +332 -0
  203. package/src/codex/custom-model-catalog-migration.ts +176 -0
  204. package/src/codex/desired-state.ts +230 -0
  205. package/src/codex/desktop-app-restart.ts +355 -0
  206. package/src/codex/features.ts +636 -39
  207. package/src/codex/generation.ts +202 -0
  208. package/src/codex/history-job.ts +436 -0
  209. package/src/codex/history-lock.ts +242 -0
  210. package/src/codex/history-manifest.ts +112 -0
  211. package/src/codex/history-migration-guardian.ts +30 -24
  212. package/src/codex/history-provider.ts +1016 -235
  213. package/src/codex/history-transition.ts +105 -0
  214. package/src/codex/history-worker.ts +223 -0
  215. package/src/codex/inject-coordination.ts +373 -0
  216. package/src/codex/inject.ts +1114 -152
  217. package/src/codex/injected-marker.ts +37 -3
  218. package/src/codex/integration-record.ts +266 -0
  219. package/src/codex/internal/catalog-writer.ts +203 -0
  220. package/src/codex/internal/history-writer.ts +81 -0
  221. package/src/codex/journal.ts +66 -4
  222. package/src/codex/log-guard/inspect.ts +524 -0
  223. package/src/codex/log-guard/lock.ts +150 -0
  224. package/src/codex/log-guard/maintenance.ts +403 -0
  225. package/src/codex/log-guard/path-safety.ts +88 -0
  226. package/src/codex/log-guard/policy.ts +44 -0
  227. package/src/codex/log-guard/processes.ts +205 -0
  228. package/src/codex/log-guard/protection.ts +489 -0
  229. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  230. package/src/codex/main-account-cache.ts +24 -0
  231. package/src/codex/main-account.ts +29 -1
  232. package/src/codex/management-convergence.ts +167 -0
  233. package/src/codex/model-cache.ts +56 -10
  234. package/src/codex/model-entitlements.ts +360 -0
  235. package/src/codex/native-main-admission.ts +47 -0
  236. package/src/codex/native-main-auth-temp.ts +187 -0
  237. package/src/codex/native-main-claim.ts +178 -0
  238. package/src/codex/native-main-lock-file.ts +162 -0
  239. package/src/codex/native-main-owner.ts +329 -0
  240. package/src/codex/native-profile-api.ts +247 -0
  241. package/src/codex/native-profile-manager.ts +1531 -0
  242. package/src/codex/native-profile-processes.ts +121 -0
  243. package/src/codex/native-profile-recovery.ts +99 -0
  244. package/src/codex/native-profile-stage-store.ts +387 -0
  245. package/src/codex/native-profile-startup.ts +622 -0
  246. package/src/codex/native-profile-store.ts +855 -0
  247. package/src/codex/native-profile-types.ts +120 -0
  248. package/src/codex/native-residue.ts +675 -0
  249. package/src/codex/paths.ts +80 -1
  250. package/src/codex/plan-from-token.ts +140 -0
  251. package/src/codex/plan.ts +40 -0
  252. package/src/codex/plugins-doctor.ts +1 -1
  253. package/src/codex/pool-rotation.ts +74 -4
  254. package/src/codex/project-config-warnings.ts +20 -6
  255. package/src/codex/prompt-journal.ts +352 -0
  256. package/src/codex/prompt-layers.ts +1313 -0
  257. package/src/codex/prompt-lock.ts +143 -0
  258. package/src/codex/prompt-text-probe.ts +238 -0
  259. package/src/codex/quota-rejection.ts +298 -0
  260. package/src/codex/quota.ts +264 -21
  261. package/src/codex/refresh.ts +11 -2
  262. package/src/codex/reset-credit-recovery.ts +1044 -0
  263. package/src/codex/routing.ts +514 -94
  264. package/src/codex/runtime.ts +159 -38
  265. package/src/codex/shim.ts +1065 -31
  266. package/src/codex/subagent-model-fallback.ts +437 -43
  267. package/src/codex/sync.ts +191 -2
  268. package/src/codex/transition-state.ts +720 -0
  269. package/src/codex/upstream-host-health.ts +368 -0
  270. package/src/codex/user-identity.ts +557 -0
  271. package/src/codex/warmup.ts +187 -81
  272. package/src/codex/write-coordination.ts +114 -0
  273. package/src/combos/failover.ts +47 -0
  274. package/src/combos/index.ts +4 -0
  275. package/src/combos/request.ts +32 -0
  276. package/src/combos/types.ts +91 -9
  277. package/src/compatibility/index.ts +26 -0
  278. package/src/compatibility/manifest.ts +253 -0
  279. package/src/compatibility/openai-responses.ts +121 -0
  280. package/src/config/atomic-write.ts +219 -0
  281. package/src/config/paths.ts +40 -0
  282. package/src/config/process-state.ts +309 -0
  283. package/src/config/provider-name.ts +24 -0
  284. package/src/config/provider-validation.ts +177 -0
  285. package/src/config/rebase-provenance.ts +68 -0
  286. package/src/config.ts +1713 -709
  287. package/src/generated/compatibility-version.json +3324 -0
  288. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  289. package/src/grok/inject.ts +16 -5
  290. package/src/grok/inspect.ts +45 -0
  291. package/src/grok/sync.ts +2 -2
  292. package/src/images/loop.ts +157 -33
  293. package/src/images/plan.ts +24 -13
  294. package/src/integrations/config-io.ts +269 -0
  295. package/src/integrations/journal.ts +315 -0
  296. package/src/integrations/merge.ts +135 -0
  297. package/src/integrations/mutation-flight.ts +71 -0
  298. package/src/integrations/native/ownership-preflight.ts +202 -0
  299. package/src/integrations/omp-yaml-source.ts +358 -0
  300. package/src/integrations/owned-refresh.ts +74 -0
  301. package/src/integrations/ownership-policy.ts +160 -0
  302. package/src/integrations/ownership.ts +155 -0
  303. package/src/integrations/registry.ts +166 -0
  304. package/src/integrations/serialize.ts +314 -0
  305. package/src/integrations/state.ts +433 -0
  306. package/src/integrations/store.ts +103 -0
  307. package/src/integrations/writer-lock.ts +98 -0
  308. package/src/integrations/writer.ts +715 -0
  309. package/src/lab/artifacts/sanitize.ts +586 -0
  310. package/src/lab/artifacts/secure-fs.ts +475 -0
  311. package/src/lab/artifacts/store.ts +310 -0
  312. package/src/lab/automation/budgets.ts +78 -0
  313. package/src/lab/automation/config-persistence.ts +256 -0
  314. package/src/lab/automation/constants.ts +39 -0
  315. package/src/lab/automation/cooldown.ts +103 -0
  316. package/src/lab/automation/dispatch.ts +211 -0
  317. package/src/lab/automation/index.ts +13 -0
  318. package/src/lab/automation/orchestrator.ts +499 -0
  319. package/src/lab/automation/persistence.ts +512 -0
  320. package/src/lab/automation/planner.ts +371 -0
  321. package/src/lab/automation/policy.ts +136 -0
  322. package/src/lab/automation/queue.ts +191 -0
  323. package/src/lab/automation/recovery.ts +24 -0
  324. package/src/lab/automation/route-context.ts +21 -0
  325. package/src/lab/automation/run-key.ts +44 -0
  326. package/src/lab/automation/runs-query.ts +34 -0
  327. package/src/lab/automation/types.ts +160 -0
  328. package/src/lab/conformance/assertion.ts +325 -0
  329. package/src/lab/conformance/digest.ts +22 -0
  330. package/src/lab/conformance/executor.ts +741 -0
  331. package/src/lab/conformance/fixture-provider.ts +27 -0
  332. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  333. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  334. package/src/lab/conformance/harness-budget.ts +47 -0
  335. package/src/lab/conformance/index.ts +5 -0
  336. package/src/lab/conformance/jcs.ts +64 -0
  337. package/src/lab/conformance/json-pointer.ts +39 -0
  338. package/src/lab/conformance/manifest.ts +180 -0
  339. package/src/lab/conformance/mcp-stub.ts +179 -0
  340. package/src/lab/conformance/negative-controls.ts +164 -0
  341. package/src/lab/conformance/observation.ts +355 -0
  342. package/src/lab/conformance/runner.ts +68 -0
  343. package/src/lab/conformance/sse-normalize.ts +59 -0
  344. package/src/lab/conformance/suite-manifest.ts +78 -0
  345. package/src/lab/conformance/types.ts +214 -0
  346. package/src/lab/constants.ts +126 -0
  347. package/src/lab/digest.ts +64 -0
  348. package/src/lab/events/errors.ts +9 -0
  349. package/src/lab/events/limits.ts +117 -0
  350. package/src/lab/events/types.ts +229 -0
  351. package/src/lab/events/validate.ts +781 -0
  352. package/src/lab/fabric/constants.ts +40 -0
  353. package/src/lab/fabric/executor.ts +492 -0
  354. package/src/lab/fabric/index.ts +80 -0
  355. package/src/lab/fabric/manifest.ts +222 -0
  356. package/src/lab/fabric/observe.ts +489 -0
  357. package/src/lab/fabric/patch.ts +79 -0
  358. package/src/lab/fabric/producer-child.ts +139 -0
  359. package/src/lab/fabric/producer-isolate.ts +276 -0
  360. package/src/lab/fabric/producer-protocol.ts +61 -0
  361. package/src/lab/fabric/scratch.ts +439 -0
  362. package/src/lab/fabric/subject.ts +106 -0
  363. package/src/lab/fabric/types.ts +134 -0
  364. package/src/lab/fabric/verifier.ts +98 -0
  365. package/src/lab/index.ts +54 -0
  366. package/src/lab/ledger/artifact-refs.ts +127 -0
  367. package/src/lab/ledger/invalidation.ts +136 -0
  368. package/src/lab/ledger/purge.ts +310 -0
  369. package/src/lab/ledger/store.ts +532 -0
  370. package/src/lab/live/credential-lease.ts +53 -0
  371. package/src/lab/live/destination.ts +155 -0
  372. package/src/lab/live/executor.ts +336 -0
  373. package/src/lab/live/inert-tools.ts +56 -0
  374. package/src/lab/live/manifest.ts +85 -0
  375. package/src/lab/live/mcp-loopback.ts +57 -0
  376. package/src/lab/live/runner.ts +19 -0
  377. package/src/lab/live/sandbox.ts +61 -0
  378. package/src/lab/live/suite-manifest.ts +41 -0
  379. package/src/lab/live/transport.ts +118 -0
  380. package/src/lab/live/types.ts +197 -0
  381. package/src/lab/observe/from-conformance.ts +301 -0
  382. package/src/lab/observe/from-live.ts +117 -0
  383. package/src/lab/paths.ts +153 -0
  384. package/src/lab/projection/rebuild.ts +495 -0
  385. package/src/lab/projection/schema.ts +135 -0
  386. package/src/lab/projection/verdicts.ts +474 -0
  387. package/src/lab/projection/verification.ts +412 -0
  388. package/src/lab/public/bundle.ts +217 -0
  389. package/src/lab/public/community-authority.ts +175 -0
  390. package/src/lab/public/community-files.ts +29 -0
  391. package/src/lab/public/community.ts +479 -0
  392. package/src/lab/public/file-safety.ts +155 -0
  393. package/src/lab/public/ids.ts +26 -0
  394. package/src/lab/public/index.ts +16 -0
  395. package/src/lab/public/mutation-lock.ts +424 -0
  396. package/src/lab/public/operator.ts +353 -0
  397. package/src/lab/public/origin-purge.ts +79 -0
  398. package/src/lab/public/origin.ts +203 -0
  399. package/src/lab/public/privacy.ts +143 -0
  400. package/src/lab/public/private-file.ts +261 -0
  401. package/src/lab/public/project.ts +124 -0
  402. package/src/lab/public/purge-test-fault.ts +21 -0
  403. package/src/lab/public/purge.ts +223 -0
  404. package/src/lab/public/registry.ts +44 -0
  405. package/src/lab/public/revocation.ts +252 -0
  406. package/src/lab/public/signature.ts +243 -0
  407. package/src/lab/public/storage.ts +105 -0
  408. package/src/lab/public/strict-json.ts +206 -0
  409. package/src/lab/public/time.ts +26 -0
  410. package/src/lab/public/types.ts +172 -0
  411. package/src/lab/public/validate.ts +391 -0
  412. package/src/lab/query/catalog.ts +101 -0
  413. package/src/lab/query/connection.ts +107 -0
  414. package/src/lab/query/constants.ts +4 -0
  415. package/src/lab/query/cursor.ts +132 -0
  416. package/src/lab/query/dto-map.ts +277 -0
  417. package/src/lab/query/errors.ts +22 -0
  418. package/src/lab/query/freshness.ts +53 -0
  419. package/src/lab/query/index.ts +45 -0
  420. package/src/lab/query/latest-observation.ts +59 -0
  421. package/src/lab/query/passive-production.ts +159 -0
  422. package/src/lab/query/queries.ts +444 -0
  423. package/src/lab/query/types.ts +266 -0
  424. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  425. package/src/lab/subject/installation-salt.ts +112 -0
  426. package/src/lab/subject/protocol-subject.ts +80 -0
  427. package/src/lab/subject/route-subject.ts +74 -0
  428. package/src/lib/admin-secrets.ts +24 -0
  429. package/src/lib/app-owned-memory-stores.ts +22 -0
  430. package/src/lib/bounded-body.ts +167 -11
  431. package/src/lib/bun-runtime.ts +125 -12
  432. package/src/lib/bun-stream-caps.ts +13 -9
  433. package/src/lib/codex-restart-contract.ts +120 -0
  434. package/src/lib/config-ownership.ts +26 -2
  435. package/src/lib/destination-policy.ts +65 -1
  436. package/src/lib/errors.ts +80 -5
  437. package/src/lib/fabric-task-execution-authority.ts +7 -0
  438. package/src/lib/fabric-task-host.ts +29 -0
  439. package/src/lib/lab-activation.ts +223 -0
  440. package/src/lib/lab-live-execution-authority.ts +13 -0
  441. package/src/lib/lab-live-host.ts +30 -0
  442. package/src/lib/lab-live-pinned-sender.ts +56 -0
  443. package/src/lib/lab-live-route-production.ts +130 -0
  444. package/src/lib/lab-passive-linker-registration.ts +26 -0
  445. package/src/lib/local-management-attestation.ts +51 -0
  446. package/src/lib/local-management-capability.ts +100 -0
  447. package/src/lib/local-provider-reload-contract.ts +100 -0
  448. package/src/lib/optional-shutdown-hooks.ts +57 -0
  449. package/src/lib/package-tree-integrity.ts +101 -0
  450. package/src/lib/pinned-http.ts +145 -26
  451. package/src/lib/process-control.ts +6 -2
  452. package/src/lib/provider-outbound.ts +49 -9
  453. package/src/lib/redact.ts +419 -3
  454. package/src/lib/self-launch-argv.ts +15 -0
  455. package/src/lib/server-resource-ownership.ts +71 -0
  456. package/src/lib/service-secrets.ts +15 -0
  457. package/src/lib/shadow-call.ts +35 -4
  458. package/src/lib/sse-decoder.ts +41 -0
  459. package/src/lib/state-store-registrations.ts +10 -2
  460. package/src/lib/system-restart-contract.ts +73 -0
  461. package/src/lib/token-estimate.ts +19 -2
  462. package/src/lib/tool-argument-integers.ts +253 -0
  463. package/src/lib/translator-budget.ts +44 -0
  464. package/src/lib/upstream-http-version.ts +57 -0
  465. package/src/lib/upstream-reachability.ts +95 -0
  466. package/src/lib/upstream-retry.ts +156 -3
  467. package/src/lib/windows-atomic-replace.ts +155 -0
  468. package/src/lib/windows-elevation.ts +70 -2
  469. package/src/lib/windows-secret-acl.ts +409 -69
  470. package/src/lib/windows-service-wrappers.ts +72 -0
  471. package/src/lib/windows-text.ts +106 -0
  472. package/src/lib/windows-user-principal.ts +341 -0
  473. package/src/lib/winsw.ts +33 -5
  474. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  475. package/src/oauth/account-import/index.ts +15 -0
  476. package/src/oauth/account-import/parser.ts +83 -0
  477. package/src/oauth/account-import/registry.ts +18 -0
  478. package/src/oauth/account-import/service.ts +75 -0
  479. package/src/oauth/account-import/types.ts +91 -0
  480. package/src/oauth/anthropic.ts +12 -1
  481. package/src/oauth/callback-server.ts +30 -4
  482. package/src/oauth/chatgpt.ts +12 -1
  483. package/src/oauth/cline.ts +203 -0
  484. package/src/oauth/command-code.ts +239 -0
  485. package/src/oauth/cursor.ts +46 -5
  486. package/src/oauth/generic-account-failover.ts +231 -0
  487. package/src/oauth/google-antigravity.ts +35 -3
  488. package/src/oauth/health.ts +20 -12
  489. package/src/oauth/index.ts +462 -71
  490. package/src/oauth/key-providers.ts +25 -0
  491. package/src/oauth/kimi.ts +25 -3
  492. package/src/oauth/kiro.ts +95 -6
  493. package/src/oauth/local-token-detect.ts +13 -2
  494. package/src/oauth/log.ts +3 -1
  495. package/src/oauth/login-cli.ts +88 -28
  496. package/src/oauth/nous.ts +798 -0
  497. package/src/oauth/open-browser-choice.ts +26 -0
  498. package/src/oauth/store.ts +133 -26
  499. package/src/oauth/token-guardian.ts +9 -3
  500. package/src/oauth/types.ts +15 -0
  501. package/src/pi/models.ts +2 -2
  502. package/src/providers/alibaba-region-migration.ts +1 -1
  503. package/src/providers/antigravity-models.ts +521 -31
  504. package/src/providers/auto-compact-budget.ts +65 -0
  505. package/src/providers/base-url-choices.ts +10 -0
  506. package/src/providers/codex-capacity.ts +292 -0
  507. package/src/providers/command-code-efforts.ts +176 -0
  508. package/src/providers/context-cap.ts +26 -8
  509. package/src/providers/cursor-pool.ts +72 -0
  510. package/src/providers/default-aliases.ts +65 -0
  511. package/src/providers/derive.ts +281 -6
  512. package/src/providers/fastwire.ts +507 -0
  513. package/src/providers/free-directory.ts +10 -7
  514. package/src/providers/google-vertex-location.ts +14 -0
  515. package/src/providers/key-failover.ts +71 -3
  516. package/src/providers/label.ts +35 -2
  517. package/src/providers/model-discovery-limits.ts +16 -0
  518. package/src/providers/model-discovery.ts +115 -22
  519. package/src/providers/model-presets.ts +119 -0
  520. package/src/providers/model-rename-migration.ts +255 -0
  521. package/src/providers/model-rename-startup.ts +28 -0
  522. package/src/providers/new-model-policy.ts +146 -0
  523. package/src/providers/openai-sidecar.ts +72 -4
  524. package/src/providers/openai-tier-startup.ts +31 -2
  525. package/src/providers/openai-tiers.ts +119 -4
  526. package/src/providers/openai-virtual-models.ts +1 -0
  527. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  528. package/src/providers/provider-id-rewrite.ts +30 -0
  529. package/src/providers/quota.ts +1379 -40
  530. package/src/providers/registry.ts +1545 -112
  531. package/src/providers/request-pacing.ts +310 -0
  532. package/src/providers/service-tier.ts +277 -0
  533. package/src/providers/slug-codec.ts +94 -6
  534. package/src/providers/static-model-discovery.ts +86 -0
  535. package/src/providers/xai-responses-opt-in.ts +15 -0
  536. package/src/providers/xai-transport.ts +32 -4
  537. package/src/reasoning-effort.ts +68 -3
  538. package/src/responses/apply-patch-envelope.ts +63 -0
  539. package/src/responses/code-mode-helper-compat.ts +50 -0
  540. package/src/responses/compaction.ts +26 -1
  541. package/src/responses/custom-tool-compat.ts +384 -0
  542. package/src/responses/hosted-tool-policy.ts +9 -0
  543. package/src/responses/namespace-tool-compat.ts +435 -0
  544. package/src/responses/parser.ts +225 -38
  545. package/src/responses/provider-continuation.ts +98 -0
  546. package/src/responses/provider-opaque-metadata.ts +73 -0
  547. package/src/responses/reasoning-envelope.ts +9 -1
  548. package/src/responses/reasoning-replay-cache.ts +504 -0
  549. package/src/responses/schema.ts +12 -2
  550. package/src/responses/spill-store.ts +75 -10
  551. package/src/responses/state.ts +659 -31
  552. package/src/responses/thought-signature-replay.ts +364 -0
  553. package/src/responses/tool-search-compat.ts +301 -0
  554. package/src/responses/truncated-stop-reason.ts +60 -0
  555. package/src/responses/turn-termination.ts +107 -0
  556. package/src/router.ts +405 -31
  557. package/src/routing/analytics.ts +379 -0
  558. package/src/routing/capability.ts +244 -0
  559. package/src/routing/compatibility/assemble.ts +73 -0
  560. package/src/routing/compatibility/behavior.ts +278 -0
  561. package/src/routing/compatibility/catalog.ts +99 -0
  562. package/src/routing/compatibility/endpoint.ts +52 -0
  563. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  564. package/src/routing/compatibility/policy.ts +181 -0
  565. package/src/routing/compatibility/provider-slot.ts +56 -0
  566. package/src/routing/compatibility/reader.ts +110 -0
  567. package/src/routing/compatibility/subject.ts +191 -0
  568. package/src/routing/compatibility/types.ts +64 -0
  569. package/src/routing/compatibility/version.ts +104 -0
  570. package/src/routing/cost.ts +77 -0
  571. package/src/routing/evaluator.ts +495 -0
  572. package/src/routing/health.ts +412 -0
  573. package/src/routing/history/cursor.ts +43 -0
  574. package/src/routing/history/indexer.ts +605 -0
  575. package/src/routing/history/schema.ts +72 -0
  576. package/src/routing/profile-namespace.ts +15 -0
  577. package/src/routing/profile.ts +547 -0
  578. package/src/routing/quota.ts +155 -0
  579. package/src/routing/request-evidence.ts +45 -0
  580. package/src/routing/trace.ts +776 -0
  581. package/src/server/adapter-resolve.ts +2 -29
  582. package/src/server/auth-cors.ts +289 -48
  583. package/src/server/background-lifecycle.ts +182 -0
  584. package/src/server/chat-completions.ts +154 -72
  585. package/src/server/chat-native-sse.ts +331 -0
  586. package/src/server/chat-native.ts +445 -0
  587. package/src/server/claude-messages.ts +160 -44
  588. package/src/server/direct-local-http.ts +347 -0
  589. package/src/server/effort-policy.ts +18 -0
  590. package/src/server/github-copilot-responses-repair.ts +338 -0
  591. package/src/server/gui-static.ts +39 -10
  592. package/src/server/images.ts +94 -12
  593. package/src/server/index.ts +1021 -190
  594. package/src/server/lifecycle.ts +336 -14
  595. package/src/server/live.ts +136 -17
  596. package/src/server/local-management-read-client.ts +90 -0
  597. package/src/server/local-provider-reload-client.ts +137 -0
  598. package/src/server/management/agent-settings-routes.ts +433 -116
  599. package/src/server/management/api-key-usage.ts +31 -5
  600. package/src/server/management/body.ts +6 -0
  601. package/src/server/management/codex-prompt-routes.ts +570 -0
  602. package/src/server/management/combo-routes.ts +64 -25
  603. package/src/server/management/config-routes.ts +511 -51
  604. package/src/server/management/context.ts +89 -2
  605. package/src/server/management/integration-routes.ts +498 -0
  606. package/src/server/management/lab-automation-routes.ts +206 -0
  607. package/src/server/management/lab-routes.ts +563 -0
  608. package/src/server/management/logs-usage-routes.ts +127 -52
  609. package/src/server/management/model-routes.ts +461 -133
  610. package/src/server/management/model-rows.ts +167 -0
  611. package/src/server/management/native-integration-routes.ts +770 -0
  612. package/src/server/management/oauth-account-routes.ts +90 -8
  613. package/src/server/management/provider-capability-config.ts +48 -0
  614. package/src/server/management/provider-routes.ts +836 -159
  615. package/src/server/management/request-history-routes.ts +191 -0
  616. package/src/server/management/route-registry.ts +332 -0
  617. package/src/server/management/routing-analytics-routes.ts +74 -0
  618. package/src/server/management/routing-profile-routes.ts +380 -0
  619. package/src/server/management/shared.ts +27 -11
  620. package/src/server/management/sidebar-routes.ts +47 -31
  621. package/src/server/management/storage-log-guard-routes.ts +186 -0
  622. package/src/server/management/sync-response.ts +69 -0
  623. package/src/server/management/system-restart.ts +289 -33
  624. package/src/server/management/system-routes.ts +77 -0
  625. package/src/server/management/usage-summary-cache.ts +9 -1
  626. package/src/server/management/vision-sidecar-options.ts +167 -0
  627. package/src/server/management/web-search-sidecar-options.ts +120 -0
  628. package/src/server/management-api.ts +126 -23
  629. package/src/server/management-auth.ts +220 -5
  630. package/src/server/passive-route-linker.ts +66 -0
  631. package/src/server/port-reclaim.ts +1 -1
  632. package/src/server/ports.ts +41 -1
  633. package/src/server/proxy-liveness.ts +161 -10
  634. package/src/server/readiness.ts +99 -0
  635. package/src/server/relay-eager.ts +221 -54
  636. package/src/server/relay.ts +479 -87
  637. package/src/server/request-decompress.ts +113 -6
  638. package/src/server/request-log-conversation.ts +51 -0
  639. package/src/server/request-log.ts +298 -31
  640. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  641. package/src/server/responses/agent-task-recovery.ts +465 -0
  642. package/src/server/responses/codex-auth-error.ts +55 -0
  643. package/src/server/responses/collaboration.ts +239 -36
  644. package/src/server/responses/combo-stream-preflight.ts +178 -0
  645. package/src/server/responses/compact.ts +444 -72
  646. package/src/server/responses/core.ts +3579 -436
  647. package/src/server/responses/empty-completion-guard.ts +333 -0
  648. package/src/server/responses/encrypted-payload.ts +62 -39
  649. package/src/server/responses/fetch-helpers.ts +89 -99
  650. package/src/server/responses/input-admission.ts +187 -0
  651. package/src/server/responses/pacing-overload.ts +13 -0
  652. package/src/server/responses/passthrough-error.ts +33 -9
  653. package/src/server/responses/policy-fallback.ts +178 -0
  654. package/src/server/responses/responses-field-backfill.ts +343 -0
  655. package/src/server/responses/terminal-guard.ts +26 -5
  656. package/src/server/responses/upstream-error.ts +5 -0
  657. package/src/server/responses/ws-upstream.ts +381 -0
  658. package/src/server/responses-custom-tool-repair.ts +363 -0
  659. package/src/server/responses-item-id-repair.ts +54 -6
  660. package/src/server/responses-json-events.ts +90 -0
  661. package/src/server/responses-model-rewrite.ts +29 -0
  662. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  663. package/src/server/responses-snapshot-repair.ts +621 -0
  664. package/src/server/responses-terminal-repair.ts +363 -0
  665. package/src/server/responses-tool-search-repair.ts +267 -0
  666. package/src/server/responses-undeclared-tool-guard.ts +376 -0
  667. package/src/server/responses.ts +18 -2
  668. package/src/server/search.ts +78 -13
  669. package/src/server/sse-frame-buffer.ts +319 -0
  670. package/src/server/sse-payload-rewrite.ts +110 -22
  671. package/src/server/startup-action-control.ts +8 -1
  672. package/src/server/startup-health-cache.ts +19 -1
  673. package/src/server/system-env.ts +80 -9
  674. package/src/server/ws-bridge.ts +53 -40
  675. package/src/service-manager-probe.ts +892 -0
  676. package/src/service.ts +1153 -94
  677. package/src/sidecar/auth.ts +92 -0
  678. package/src/sidecar/candidates.ts +83 -0
  679. package/src/storage/cleanup.ts +2 -2
  680. package/src/storage/policy-job.ts +14 -4
  681. package/src/storage/policy.ts +88 -23
  682. package/src/storage/scanner.ts +1 -1
  683. package/src/storage/worker-lifecycle.ts +14 -14
  684. package/src/tray/windows-tray.ps1 +83 -9
  685. package/src/tray/windows.ts +43 -16
  686. package/src/types/accounts.ts +37 -0
  687. package/src/types/config.ts +911 -0
  688. package/src/types/provider.ts +614 -0
  689. package/src/types/request.ts +397 -0
  690. package/src/types/tools.ts +236 -0
  691. package/src/types/wire.ts +80 -0
  692. package/src/types.ts +107 -1237
  693. package/src/update/index.ts +37 -23
  694. package/src/update/job.ts +445 -68
  695. package/src/update/notify.ts +12 -6
  696. package/src/update/npm-cache-preflight.d.mts +47 -0
  697. package/src/update/npm-cache-preflight.mjs +201 -0
  698. package/src/update/transactional-install.d.mts +22 -0
  699. package/src/update/transactional-install.mjs +266 -0
  700. package/src/usage/cost.ts +0 -0
  701. package/src/usage/expected-prices.ts +287 -16
  702. package/src/usage/log.ts +666 -50
  703. package/src/usage/summary.ts +388 -17
  704. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  705. package/src/usage/user-cost-overlays.ts +314 -0
  706. package/src/vision/anthropic-describe.ts +10 -6
  707. package/src/vision/backends.ts +97 -0
  708. package/src/vision/describe.ts +27 -16
  709. package/src/vision/eligibility.ts +250 -0
  710. package/src/vision/index.ts +238 -24
  711. package/src/vision/reasoning.ts +55 -0
  712. package/src/vision/routed-describe.ts +175 -0
  713. package/src/vision/timeout-bounds.ts +9 -0
  714. package/src/web-search/anthropic-executor.ts +13 -7
  715. package/src/web-search/backends.ts +108 -0
  716. package/src/web-search/exa-executor.ts +119 -0
  717. package/src/web-search/executor.ts +21 -6
  718. package/src/web-search/gemini-executor.ts +141 -0
  719. package/src/web-search/index.ts +150 -15
  720. package/src/web-search/loop.ts +284 -54
  721. package/src/web-search/parse.ts +125 -30
  722. package/src/web-search/sources.ts +60 -0
  723. package/src/web-search/xai-executor.ts +219 -0
  724. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  725. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  726. package/gui/dist/provider-icons/antigravity.svg +0 -1
  727. package/gui/dist/provider-icons/claude.svg +0 -1
  728. package/gui/dist/provider-icons/copilot.svg +0 -1
  729. package/gui/dist/provider-icons/cursor.svg +0 -2
  730. package/gui/dist/provider-icons/gemini.svg +0 -1
  731. package/gui/dist/provider-icons/grok-color.svg +0 -1
  732. package/gui/dist/provider-icons/kiro.svg +0 -14
  733. package/src/cli/internal-dispatch.ts +0 -20
@@ -2,19 +2,26 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import type { ResponsesTerminalStatus } from "../bridge";
3
3
  import {
4
4
  classifyError,
5
+ CYBER_POLICY_ERROR_CODE,
5
6
  httpStatusFromTerminalError as httpStatusFromClassifiedTerminalError,
6
7
  isClientClosedMessage,
8
+ isCyberPolicyCode,
9
+ isCyberPolicyMessage,
7
10
  } from "../lib/errors";
8
11
  import { CODEX_CONFIG_PATH, readRootTomlString } from "../codex/paths";
9
12
  import { readCodexCatalogPath } from "../codex/catalog";
10
- import type { OcxUsage } from "../types";
13
+ import type { AttemptTierOutcome, OcxUsage } from "../types";
14
+ import { normalizeRouteDecisionTrace, type RouteDecisionTraceV1 } from "../routing/trace";
11
15
  import type { AdapterRequest } from "../adapters/base";
12
- import { redactSecretString } from "../lib/redact";
16
+ import type { AdapterTierMetadata } from "../providers/fastwire";
17
+ import { redactSecretString, sanitizeLogMetadataString } from "../lib/redact";
13
18
  import {
14
19
  appendUsageEntry,
15
20
  isKnownAdmissionKind,
16
21
  isKnownInboundProtocol,
17
22
  isKnownUsageSurface,
23
+ isCodexUsageAccountLogLabel,
24
+ isValidReasoningWireValue,
18
25
  readRecentUsageEntries,
19
26
  usageForFinalLog,
20
27
  usageStatusForFinalLog,
@@ -33,6 +40,10 @@ import {
33
40
  } from "../usage/debug";
34
41
  import { matchesLogConversationId } from "./request-log-conversation";
35
42
  import { enforceAppOwnedMemoryBudget, type RetainedStoreSnapshot } from "../lib/app-owned-memory";
43
+ import { capEstimateAtContextWindow } from "../lib/token-estimate";
44
+ import { inferCursorContextWindow } from "../adapters/cursor/discovery";
45
+ import { KIRO_MODEL_CONTEXT_WINDOWS, normalizeKiroModelId } from "../providers/kiro-models";
46
+ import { modelRecordValue } from "../reasoning-effort";
36
47
 
37
48
  export interface RequestLogContext {
38
49
  model: string;
@@ -52,20 +63,38 @@ export interface RequestLogContext {
52
63
  * product: widening that enum would merge Responses and Chat Completions,
53
64
  * since both leave it undefined. */
54
65
  inboundProtocol?: "responses" | "chat" | "messages";
66
+ /**
67
+ * Set when an adapter answered the turn locally and no upstream request was made
68
+ * (`ProviderAdapter.localTerminal`). A fixed identifier naming the code path, never
69
+ * conversation-derived: it exists so a request log showing zero sends is explainable
70
+ * rather than looking like a lost request.
71
+ */
72
+ localTerminalReason?: string;
73
+ /** Stable non-PII Codex Pool account identity for durable usage attribution. */
74
+ accountLogLabel?: string;
55
75
  requestedModel?: string;
76
+ /** User-facing alias selector when routing resolved one; native model remains `model`. */
77
+ requestedAlias?: string;
78
+ /** Original bare helper model when the opt-in shadow-call route rewrote this request. */
79
+ shadowCallRewrittenFrom?: string;
56
80
  /** Internal structural combo identity; omitted from RequestLogEntry/JSONL. */
57
81
  comboId?: string;
58
82
  requestedEffort?: string;
59
83
  effectiveEffort?: string;
60
84
  reasoningWireField?: string;
61
- reasoningWireValue?: string | number;
85
+ reasoningWireValue?: string | number | boolean;
86
+ callerServiceTier?: string;
62
87
  requestedServiceTier?: string;
63
88
  requestedSpeedLabel?: string;
64
89
  configuredServiceTier?: string;
65
90
  configuredSpeedLabel?: string;
66
91
  modelSupportsServiceTier?: boolean;
67
92
  responseServiceTier?: string;
93
+ /** Final-attempt tier summary; attempt rows remain the accounting source of truth. */
94
+ tierOutcome?: AttemptTierOutcome;
68
95
  resolvedModel?: string;
96
+ /** Internal: client-facing response metadata must not replace the physical routed model. */
97
+ preserveResolvedModelFromRoute?: boolean;
69
98
  usage?: OcxUsage;
70
99
  usageLogInputTokens?: number;
71
100
  attempts?: PersistedUsageAttempt[];
@@ -73,6 +102,8 @@ export interface RequestLogContext {
73
102
  activeAttempt?: PersistedUsageAttempt;
74
103
  /** Internal wall-clock origin for the committed final attempt; never persisted. */
75
104
  activeAttemptStartedAt?: number;
105
+ /** Internal adapter response observer paired with activeAttempt.tierOutcome. */
106
+ activeTierMetadata?: AdapterTierMetadata;
76
107
  usageDebugBodyKind?: UsageDebugBodyKind;
77
108
  usageDebugBodySample?: string;
78
109
  usageDebugContentType?: string;
@@ -90,11 +121,15 @@ export interface RequestLogContext {
90
121
  upstreamError?: string;
91
122
  /** HTTP status derived from a terminal `response.failed` SSE payload (429/401/503/etc.). */
92
123
  terminalHttpStatus?: number;
124
+ /** Recognized structured terminal code whose exact identity must survive status mapping. */
125
+ terminalErrorCode?: typeof CYBER_POLICY_ERROR_CODE;
93
126
  /** Structured reason from `response.incomplete`; internal-only input to log classification. */
94
127
  terminalIncompleteReason?: string;
95
128
  affinity?: "reused" | "new_bind" | "rebound" | "cleared";
96
129
  transportPhase?: "pre_headers" | "mid_stream" | "terminal_sse";
97
130
  terminalSource?: "upstream" | "synthetic";
131
+ /** Bounded route-decision trace (RI-01); never contains secrets. */
132
+ routeDecision?: RouteDecisionTraceV1;
98
133
  }
99
134
 
100
135
  export interface RequestLogEntry {
@@ -105,6 +140,12 @@ export interface RequestLogEntry {
105
140
  /** TTFT: ms from request start to the first non-empty model output delta; unset for non-streaming/tool-only. */
106
141
  firstOutputMs?: number;
107
142
  surface?: "claude" | "claude-desktop" | "grok";
143
+ /**
144
+ * Set when the proxy answered this turn locally and sent nothing upstream. Without it a zero-send
145
+ * row is indistinguishable from a request that vanished. A fixed adapter-supplied identifier,
146
+ * never conversation-derived.
147
+ */
148
+ localTerminalReason?: string;
108
149
  /** The matched configured key's id. Set ONLY for admissionKind "configured" —
109
150
  * never a sentinel, so a hand-edited entry whose id happens to be "loopback"
110
151
  * cannot absorb unrelated traffic. */
@@ -115,19 +156,25 @@ export interface RequestLogEntry {
115
156
  * product: widening that enum would merge Responses and Chat Completions,
116
157
  * since both leave it undefined. */
117
158
  inboundProtocol?: "responses" | "chat" | "messages";
159
+ accountLogLabel?: string;
118
160
  /** Best-effort chat/session correlation for Logs grouping (#330). */
119
161
  conversationId?: string;
120
162
  requestedModel?: string;
163
+ requestedAlias?: string;
164
+ /** Original bare helper model when the opt-in shadow-call route rewrote this request. */
165
+ shadowCallRewrittenFrom?: string;
121
166
  requestedEffort?: string;
122
167
  effectiveEffort?: string;
123
168
  reasoningWireField?: string;
124
- reasoningWireValue?: string | number;
169
+ reasoningWireValue?: string | number | boolean;
170
+ callerServiceTier?: string;
125
171
  requestedServiceTier?: string;
126
172
  requestedSpeedLabel?: string;
127
173
  configuredServiceTier?: string;
128
174
  configuredSpeedLabel?: string;
129
175
  modelSupportsServiceTier?: boolean;
130
176
  responseServiceTier?: string;
177
+ tierOutcome?: AttemptTierOutcome;
131
178
  resolvedModel?: string;
132
179
  status: number;
133
180
  durationMs: number;
@@ -146,6 +193,8 @@ export interface RequestLogEntry {
146
193
  transportPhase?: "pre_headers" | "mid_stream" | "terminal_sse";
147
194
  /** Whether the terminal came from a real upstream SSE event or a proxy synthetic tail. */
148
195
  terminalSource?: "upstream" | "synthetic";
196
+ /** Bounded route-decision trace (RI-01); never contains secrets. */
197
+ routeDecision?: RouteDecisionTraceV1;
149
198
  }
150
199
 
151
200
  const requestLog: RequestLogEntry[] = [];
@@ -214,6 +263,7 @@ function asCloseReason(value: string | undefined): RequestLogEntry["closeReason"
214
263
  export function requestLogEntryFromPersistedUsage(entry: PersistedUsageEntry): RequestLogEntry {
215
264
  const terminalStatus = asTerminalStatus(entry.terminalStatus);
216
265
  const closeReason = asCloseReason(entry.closeReason);
266
+ const routeDecision = normalizeRouteDecisionTraceForLog(entry.routeDecision);
217
267
  return {
218
268
  requestId: entry.requestId,
219
269
  timestamp: entry.timestamp,
@@ -222,11 +272,19 @@ export function requestLogEntryFromPersistedUsage(entry: PersistedUsageEntry): R
222
272
  ...(entry.firstOutputMs !== undefined ? { firstOutputMs: entry.firstOutputMs } : {}),
223
273
  ...(isKnownUsageSurface(entry.surface) ? { surface: entry.surface } : {}),
224
274
  ...(entry.conversationId ? { conversationId: entry.conversationId } : {}),
275
+ ...(isCodexUsageAccountLogLabel(entry.accountLogLabel)
276
+ ? { accountLogLabel: entry.accountLogLabel }
277
+ : {}),
225
278
  ...(entry.requestedModel ? { requestedModel: entry.requestedModel } : {}),
279
+ ...(entry.requestedAlias ? { requestedAlias: entry.requestedAlias } : {}),
280
+ ...(entry.shadowCallRewrittenFrom
281
+ ? { shadowCallRewrittenFrom: entry.shadowCallRewrittenFrom }
282
+ : {}),
226
283
  ...(entry.requestedEffort ? { requestedEffort: entry.requestedEffort } : {}),
227
284
  ...(entry.effectiveEffort ? { effectiveEffort: entry.effectiveEffort } : {}),
228
285
  ...(entry.reasoningWireField ? { reasoningWireField: entry.reasoningWireField } : {}),
229
286
  ...(entry.reasoningWireValue !== undefined ? { reasoningWireValue: entry.reasoningWireValue } : {}),
287
+ ...(entry.callerServiceTier ? { callerServiceTier: entry.callerServiceTier } : {}),
230
288
  ...(entry.requestedServiceTier ? { requestedServiceTier: entry.requestedServiceTier } : {}),
231
289
  ...(entry.requestedSpeedLabel ? { requestedSpeedLabel: entry.requestedSpeedLabel } : {}),
232
290
  ...(entry.configuredServiceTier ? { configuredServiceTier: entry.configuredServiceTier } : {}),
@@ -235,6 +293,7 @@ export function requestLogEntryFromPersistedUsage(entry: PersistedUsageEntry): R
235
293
  ? { modelSupportsServiceTier: entry.modelSupportsServiceTier }
236
294
  : {}),
237
295
  ...(entry.responseServiceTier ? { responseServiceTier: entry.responseServiceTier } : {}),
296
+ ...(entry.tierOutcome ? { tierOutcome: entry.tierOutcome } : {}),
238
297
  ...(entry.resolvedModel ? { resolvedModel: entry.resolvedModel } : {}),
239
298
  status: entry.status,
240
299
  durationMs: entry.durationMs,
@@ -245,10 +304,22 @@ export function requestLogEntryFromPersistedUsage(entry: PersistedUsageEntry): R
245
304
  usageStatus: entry.usageStatus,
246
305
  ...(entry.usage ? { usage: entry.usage } : {}),
247
306
  ...(entry.totalTokens !== undefined ? { totalTokens: entry.totalTokens } : {}),
248
- ...(entry.attempts?.length ? { attempts: entry.attempts } : {}),
307
+ ...(entry.attempts !== undefined ? { attempts: entry.attempts } : {}),
308
+ ...(routeDecision ? { routeDecision } : {}),
249
309
  };
250
310
  }
251
311
 
312
+ /**
313
+ * Hydration guard: persisted traces are re-normalized before they enter the
314
+ * in-memory ring buffer so a hand-edited or corrupt row cannot poison the DTO.
315
+ * A row that fails validation is dropped, never forwarded unvalidated.
316
+ */
317
+ function normalizeRouteDecisionTraceForLog(
318
+ entry: RouteDecisionTraceV1 | undefined,
319
+ ): RouteDecisionTraceV1 | null {
320
+ return entry ? normalizeRouteDecisionTrace(entry) : null;
321
+ }
322
+
252
323
  /**
253
324
  * Seed the in-memory Logs ring buffer from usage.jsonl so GUI /api/logs survives
254
325
  * `ocx stop` / `ocx start` (process restart). Idempotent per process; no-ops when
@@ -281,6 +352,20 @@ export function hydrateRequestLogsFromDisk(
281
352
  }
282
353
 
283
354
  export function addRequestLog(entry: RequestLogEntry) {
355
+ // Sanitize ONCE, at the ingress, and use that one value for both destinations.
356
+ //
357
+ // `addFinalRequestLog` is not the only way in: `addRequestLog` is exported and callable
358
+ // directly, and it retained the caller's entry verbatim in the in-memory ring while only the
359
+ // field-by-field disk projection below saw a sanitized value. That split let `/api/logs`
360
+ // serve a raw upstream-supplied marker — a newline in it can forge a record boundary in a
361
+ // line-oriented viewer — while `usage.jsonl` looked clean, which is the worst shape for a
362
+ // sanitization bug because the safe surface is the one you check.
363
+ const shadowCallRewrittenFrom = sanitizeLogMetadataString(entry.shadowCallRewrittenFrom);
364
+ const retained: RequestLogEntry = shadowCallRewrittenFrom === entry.shadowCallRewrittenFrom
365
+ ? entry
366
+ : { ...entry, ...(shadowCallRewrittenFrom ? { shadowCallRewrittenFrom } : {}) };
367
+ if (!shadowCallRewrittenFrom && retained !== entry) delete retained.shadowCallRewrittenFrom;
368
+ entry = retained;
284
369
  retainRequestLogEntry(entry);
285
370
  try {
286
371
  // Failure diagnostics survive the 200-entry ring buffer by riding the persisted
@@ -306,13 +391,21 @@ export function addRequestLog(entry: RequestLogEntry) {
306
391
  ...(entry.apiKeyId ? { apiKeyId: entry.apiKeyId } : {}),
307
392
  ...(isKnownAdmissionKind(entry.admissionKind) ? { admissionKind: entry.admissionKind } : {}),
308
393
  ...(isKnownInboundProtocol(entry.inboundProtocol) ? { inboundProtocol: entry.inboundProtocol } : {}),
394
+ ...(isCodexUsageAccountLogLabel(entry.accountLogLabel)
395
+ ? { accountLogLabel: entry.accountLogLabel }
396
+ : {}),
309
397
  ...(entry.conversationId ? { conversationId: entry.conversationId } : {}),
310
398
  ...(entry.resolvedModel ? { resolvedModel: entry.resolvedModel } : {}),
311
399
  ...(entry.requestedModel ? { requestedModel: entry.requestedModel } : {}),
400
+ ...(entry.requestedAlias ? { requestedAlias: entry.requestedAlias } : {}),
401
+ ...(entry.shadowCallRewrittenFrom
402
+ ? { shadowCallRewrittenFrom: entry.shadowCallRewrittenFrom }
403
+ : {}),
312
404
  ...(entry.requestedEffort ? { requestedEffort: entry.requestedEffort } : {}),
313
405
  ...(entry.effectiveEffort ? { effectiveEffort: entry.effectiveEffort } : {}),
314
406
  ...(entry.reasoningWireField ? { reasoningWireField: entry.reasoningWireField } : {}),
315
407
  ...(entry.reasoningWireValue !== undefined ? { reasoningWireValue: entry.reasoningWireValue } : {}),
408
+ ...(entry.callerServiceTier ? { callerServiceTier: entry.callerServiceTier } : {}),
316
409
  ...(entry.requestedServiceTier ? { requestedServiceTier: entry.requestedServiceTier } : {}),
317
410
  ...(entry.requestedSpeedLabel ? { requestedSpeedLabel: entry.requestedSpeedLabel } : {}),
318
411
  ...(entry.configuredServiceTier ? { configuredServiceTier: entry.configuredServiceTier } : {}),
@@ -321,14 +414,16 @@ export function addRequestLog(entry: RequestLogEntry) {
321
414
  ? { modelSupportsServiceTier: entry.modelSupportsServiceTier }
322
415
  : {}),
323
416
  ...(entry.responseServiceTier ? { responseServiceTier: entry.responseServiceTier } : {}),
417
+ ...(entry.tierOutcome ? { tierOutcome: entry.tierOutcome } : {}),
324
418
  status: entry.status,
325
419
  durationMs: entry.durationMs,
326
420
  ...(entry.firstOutputMs !== undefined ? { firstOutputMs: entry.firstOutputMs } : {}),
327
421
  usageStatus: entry.usageStatus,
328
422
  ...(entry.usage ? { usage: entry.usage } : {}),
329
423
  ...(entry.totalTokens !== undefined ? { totalTokens: entry.totalTokens } : {}),
330
- ...(entry.attempts?.length ? { attempts: entry.attempts } : {}),
424
+ ...(entry.attempts !== undefined ? { attempts: entry.attempts } : {}),
331
425
  ...failureDiagnostics,
426
+ ...(entry.routeDecision ? { routeDecision: entry.routeDecision } : {}),
332
427
  });
333
428
  } catch {
334
429
  /* request logging must never fail a user request */
@@ -399,12 +494,11 @@ export function recordAdapterReasoning(
399
494
  const reasoning = raw as Record<string, unknown>;
400
495
  if (typeof reasoning.effectiveEffort !== "string" || !reasoning.effectiveEffort
401
496
  || (reasoning.wireField !== "reasoning_effort"
497
+ && reasoning.wireField !== "reasoning.enabled"
498
+ && reasoning.wireField !== "reasoning.effort"
402
499
  && reasoning.wireField !== "thinking_budget"
403
500
  && reasoning.wireField !== "thinking.type")
404
- || (!(typeof reasoning.wireValue === "string" && reasoning.wireValue)
405
- && !(typeof reasoning.wireValue === "number"
406
- && Number.isFinite(reasoning.wireValue)
407
- && reasoning.wireValue >= 0))) {
501
+ || !isValidReasoningWireValue(reasoning.wireField, reasoning.wireValue)) {
408
502
  return;
409
503
  }
410
504
 
@@ -425,12 +519,55 @@ export function recordAdapterReasoning(
425
519
  }
426
520
  }
427
521
 
428
- export function requestLogErrorCode(status: number, upstreamError?: string): string | undefined {
522
+ /** Attach the serializing adapter's tier observation to the active durable attempt. */
523
+ export function recordAdapterTier(
524
+ logCtx: RequestLogContext,
525
+ request: AdapterRequest,
526
+ ): void {
527
+ recordAdapterTierMetadata(logCtx, request.tierLog);
528
+ }
529
+
530
+ /** Attach adapter-owned metadata for transports that expose no AdapterRequest (runTurn). */
531
+ export function recordAdapterTierMetadata(
532
+ logCtx: RequestLogContext,
533
+ metadata: AdapterTierMetadata | undefined,
534
+ ): void {
535
+ delete logCtx.tierOutcome;
536
+ delete logCtx.activeTierMetadata;
537
+ const attempt = logCtx.activeAttempt;
538
+ if (attempt) delete attempt.tierOutcome;
539
+
540
+ try {
541
+ const outcome = metadata?.outcome;
542
+ if (!metadata || !outcome) return;
543
+ logCtx.tierOutcome = outcome;
544
+ logCtx.activeTierMetadata = metadata;
545
+ if (attempt) attempt.tierOutcome = outcome;
546
+ } catch {
547
+ // Request logging is best-effort and must not affect request delivery.
548
+ }
549
+ }
550
+
551
+ export function requestLogErrorCode(
552
+ status: number,
553
+ upstreamError?: string,
554
+ terminalErrorCode?: string,
555
+ ): string | undefined {
429
556
  if (status >= 200 && status < 400) return undefined;
557
+ // A structured terminal code is authoritative even when the provider message is localized,
558
+ // generic, or absent. Only preserve the one narrowly recognized policy code here: broadly
559
+ // forwarding arbitrary upstream codes would change unrelated request-log taxonomy.
560
+ if (isCyberPolicyCode(terminalErrorCode)) return CYBER_POLICY_ERROR_CODE;
561
+ const classifiedCode = upstreamError?.trim()
562
+ ? classifyError(status, "upstream_error", upstreamError).code
563
+ : undefined;
430
564
  // Defense in depth: mid-stream web-search aborts used to land as 502 with this message.
431
- if (status === 499 || (upstreamError?.trim() && classifyError(status, "upstream_error", upstreamError).code === "client_closed_request")) {
565
+ if (status === 499 || classifiedCode === "client_closed_request") {
432
566
  return "client_closed_request";
433
567
  }
568
+ // Keep the high-confidence message fallback for runtimes/providers that stripped the
569
+ // structured code before emitting response.failed.
570
+ if (classifiedCode === CYBER_POLICY_ERROR_CODE) return CYBER_POLICY_ERROR_CODE;
434
571
  if (status === 400 || status === 409) return "invalid_request_error";
435
572
  if (status === 401) return "invalid_api_key";
436
573
  if (status === 403) {
@@ -493,9 +630,19 @@ export function applyResponseLogMetadata(logCtx: RequestLogContext, payload: unk
493
630
  : payload;
494
631
  if (!source || typeof source !== "object") return;
495
632
  const model = (source as { model?: unknown }).model;
496
- if (typeof model === "string" && model.trim()) logCtx.resolvedModel = model;
633
+ if (
634
+ !logCtx.preserveResolvedModelFromRoute
635
+ && typeof model === "string"
636
+ && model.trim()
637
+ ) logCtx.resolvedModel = model;
497
638
  const serviceTier = (source as { service_tier?: unknown }).service_tier;
498
- if (typeof serviceTier === "string" && serviceTier.trim()) logCtx.responseServiceTier = serviceTier;
639
+ if (typeof serviceTier === "string" && serviceTier.trim()) {
640
+ const sanitized = sanitizeLogMetadataString(serviceTier);
641
+ if (sanitized) logCtx.responseServiceTier = sanitized;
642
+ logCtx.activeTierMetadata?.observeResponseServiceTier(serviceTier);
643
+ } else if (Object.prototype.hasOwnProperty.call(source, "service_tier")) {
644
+ logCtx.activeTierMetadata?.observeResponseServiceTier(serviceTier);
645
+ }
499
646
  const usage = usageFromResponsesPayload((source as { usage?: unknown }).usage);
500
647
  if (usage && !logCtx.usageFromBridge) {
501
648
  logCtx.usage = usage;
@@ -561,6 +708,7 @@ export function inspectResponseLogJson(logCtx: RequestLogContext, text: string):
561
708
  try {
562
709
  applyResponseLogMetadata(logCtx, JSON.parse(text));
563
710
  } catch {
711
+ logCtx.activeTierMetadata?.markResponseUnparseable();
564
712
  /* body may not be JSON; request log metadata is best-effort only */
565
713
  }
566
714
  captureUpstreamError(logCtx, text);
@@ -591,6 +739,7 @@ export function inspectResponseLogSsePayloadParsed(
591
739
  const debugEnabled = isUsageDebugEnabled();
592
740
  const sseAlreadyMarked = logCtx.usageDebugBodyKind === "sse";
593
741
  if (parsed !== undefined) applyResponseLogMetadata(logCtx, parsed);
742
+ else logCtx.activeTierMetadata?.markResponseUnparseable();
594
743
  captureUpstreamErrorParsed(logCtx, payload, parsed);
595
744
  if (debugEnabled) {
596
745
  if (!sseAlreadyMarked) {
@@ -634,7 +783,7 @@ function captureUpstreamErrorParsed(
634
783
  last_error?: { message?: unknown };
635
784
  response?: {
636
785
  error?: { type?: unknown; code?: unknown; message?: unknown };
637
- incomplete_details?: { reason?: unknown };
786
+ incomplete_details?: { reason?: unknown; message?: unknown };
638
787
  };
639
788
  };
640
789
  captureTerminalHttpStatus(logCtx, json);
@@ -648,7 +797,8 @@ function captureUpstreamErrorParsed(
648
797
  if (logCtx.upstreamError) return;
649
798
  const message = json?.error?.message
650
799
  ?? json?.last_error?.message
651
- ?? json?.response?.error?.message;
800
+ ?? json?.response?.error?.message
801
+ ?? json?.response?.incomplete_details?.message;
652
802
  if (typeof message === "string" && message.trim()) {
653
803
  logCtx.upstreamError = redactSecretString(message).slice(0, 500);
654
804
  return;
@@ -687,17 +837,43 @@ function captureTerminalHttpStatus(
687
837
  logCtx: RequestLogContext,
688
838
  json: {
689
839
  type?: unknown;
690
- response?: { error?: { type?: unknown; code?: unknown; message?: unknown } };
840
+ code?: unknown;
841
+ message?: unknown;
842
+ error?: { type?: unknown; code?: unknown; message?: unknown };
843
+ last_error?: { type?: unknown; code?: unknown; message?: unknown };
844
+ response?: {
845
+ error?: { type?: unknown; code?: unknown; message?: unknown };
846
+ incomplete_details?: { code?: unknown; message?: unknown };
847
+ };
691
848
  },
692
849
  ): void {
693
850
  if (logCtx.terminalHttpStatus !== undefined) return;
694
- if (json.type !== "response.failed") return;
695
- const error = json.response?.error;
696
- if (!error || typeof error !== "object") return;
851
+ const type = json.type;
852
+ if (type !== "response.failed" && type !== "response.incomplete" && type !== "error") return;
853
+ const responseError = json.response?.error;
854
+ const responseDetails = json.response?.incomplete_details;
855
+ const candidates = [json.error, json.last_error, responseError, responseDetails, json];
856
+ const policy = candidates.some(candidate => (
857
+ candidate?.code === null || typeof candidate?.code === "string"
858
+ ) && isCyberPolicyCode(candidate.code as string | null | undefined))
859
+ || candidates.some(candidate => (
860
+ typeof candidate?.message === "string"
861
+ && candidate.message.trim().length > 0
862
+ && isCyberPolicyMessage(candidate.message)
863
+ ));
864
+ if (policy) {
865
+ logCtx.terminalErrorCode = CYBER_POLICY_ERROR_CODE;
866
+ logCtx.terminalHttpStatus = 400;
867
+ return;
868
+ }
869
+ if (type !== "response.failed" || !responseError || typeof responseError !== "object") return;
870
+ const responseCode = responseError.code === null || typeof responseError.code === "string"
871
+ ? responseError.code
872
+ : undefined;
697
873
  logCtx.terminalHttpStatus = httpStatusFromTerminalError({
698
- type: typeof error.type === "string" ? error.type : undefined,
699
- code: error.code === null || typeof error.code === "string" ? error.code : undefined,
700
- message: typeof error.message === "string" ? error.message : undefined,
874
+ type: typeof responseError.type === "string" ? responseError.type : undefined,
875
+ code: responseCode,
876
+ message: typeof responseError.message === "string" ? responseError.message : undefined,
701
877
  });
702
878
  }
703
879
 
@@ -752,7 +928,11 @@ export function addFinalRequestLog(
752
928
  const effectiveStatus = status >= 500 && logCtx.upstreamError && isClientClosedMessage(logCtx.upstreamError)
753
929
  ? 499
754
930
  : status;
755
- const errorCode = requestLogErrorCode(effectiveStatus, logCtx.upstreamError);
931
+ const errorCode = requestLogErrorCode(
932
+ effectiveStatus,
933
+ logCtx.upstreamError,
934
+ logCtx.terminalErrorCode,
935
+ );
756
936
  // A response.failed whose classified status is 499 is still a client cancel, not an upstream
757
937
  // terminal failure — keep /api/logs closeReason aligned with that.
758
938
  const closeReason = effectiveStatus === 499
@@ -765,22 +945,35 @@ export function addFinalRequestLog(
765
945
  Date.now() - (logCtx.activeAttemptStartedAt ?? start),
766
946
  logCtx.usage,
767
947
  );
948
+ // The final row and its active physical attempt describe the same terminal. Preserve the
949
+ // semantic code on both so detailed attempt telemetry cannot regress to a generic status code.
950
+ if (errorCode) logCtx.activeAttempt.errorCode = errorCode;
951
+ else delete logCtx.activeAttempt.errorCode;
768
952
  }
769
953
  const existing = finalizedUsage(
770
954
  logCtx.providerAdapter ?? logCtx.provider,
771
955
  logCtx.usage,
772
956
  logCtx.usageLogInputTokens,
957
+ contextWindowForModel(logCtx.providerAdapter ?? logCtx.provider, logCtx.model),
958
+ logCtx.localTerminalReason !== undefined,
773
959
  );
774
960
  const attempts = logCtx.attempts?.map(attempt => ({
775
961
  ...attempt,
776
962
  recoveryKinds: [...attempt.recoveryKinds],
777
963
  ...(attempt.usage ? { usage: { ...attempt.usage } } : {}),
964
+ ...(attempt.tierOutcome ? { tierOutcome: { ...attempt.tierOutcome } } : {}),
778
965
  }));
779
966
  const isCombo = logCtx.comboId !== undefined && (attempts?.length ?? 0) > 0;
780
967
  const aggregate = isCombo ? aggregateAttemptUsage(attempts ?? []) : null;
781
968
  const loggedUsage = aggregate?.usage ?? existing.usage;
782
969
  const usageStatus = aggregate?.status ?? existing.status;
783
970
  const totalTokens = aggregate?.totalTokens ?? existing.totalTokens;
971
+ // Sanitize at the logging layer, not only at the one call site that populates this today.
972
+ // The value originates in an upstream-supplied model id, so an unsanitized newline would
973
+ // let a single field forge a record boundary in any line-oriented log viewer. Doing it here
974
+ // means a future caller cannot reintroduce the hole by forgetting to sanitize first, and
975
+ // the in-memory /api/logs row matches what usage.jsonl already stores.
976
+ const shadowCallRewrittenFrom = sanitizeLogMetadataString(logCtx.shadowCallRewrittenFrom);
784
977
  addLog({
785
978
  requestId,
786
979
  timestamp: start,
@@ -790,18 +983,30 @@ export function addFinalRequestLog(
790
983
  ...(logCtx.apiKeyId ? { apiKeyId: logCtx.apiKeyId } : {}),
791
984
  ...(logCtx.admissionKind ? { admissionKind: logCtx.admissionKind } : {}),
792
985
  ...(logCtx.inboundProtocol ? { inboundProtocol: logCtx.inboundProtocol } : {}),
986
+ ...(logCtx.localTerminalReason
987
+ ? { localTerminalReason: sanitizeLogMetadataString(logCtx.localTerminalReason) }
988
+ : {}),
989
+ ...(isCodexUsageAccountLogLabel(logCtx.accountLogLabel)
990
+ ? { accountLogLabel: logCtx.accountLogLabel }
991
+ : {}),
793
992
  ...(logCtx.conversationId ? { conversationId: logCtx.conversationId } : {}),
794
993
  ...(logCtx.requestedModel ? { requestedModel: logCtx.requestedModel } : {}),
994
+ ...(logCtx.requestedAlias ? { requestedAlias: logCtx.requestedAlias } : {}),
995
+ ...(shadowCallRewrittenFrom ? { shadowCallRewrittenFrom } : {}),
795
996
  ...(logCtx.requestedEffort ? { requestedEffort: logCtx.requestedEffort } : {}),
796
997
  ...(logCtx.effectiveEffort ? { effectiveEffort: logCtx.effectiveEffort } : {}),
797
998
  ...(logCtx.reasoningWireField ? { reasoningWireField: logCtx.reasoningWireField } : {}),
798
999
  ...(logCtx.reasoningWireValue !== undefined ? { reasoningWireValue: logCtx.reasoningWireValue } : {}),
1000
+ ...(logCtx.callerServiceTier ? { callerServiceTier: logCtx.callerServiceTier } : {}),
799
1001
  ...(logCtx.requestedServiceTier ? { requestedServiceTier: logCtx.requestedServiceTier } : {}),
800
1002
  ...(logCtx.requestedSpeedLabel ? { requestedSpeedLabel: logCtx.requestedSpeedLabel } : {}),
801
1003
  ...(logCtx.configuredServiceTier ? { configuredServiceTier: logCtx.configuredServiceTier } : {}),
802
1004
  ...(logCtx.configuredSpeedLabel ? { configuredSpeedLabel: logCtx.configuredSpeedLabel } : {}),
803
1005
  ...(logCtx.modelSupportsServiceTier !== undefined ? { modelSupportsServiceTier: logCtx.modelSupportsServiceTier } : {}),
804
1006
  ...(logCtx.responseServiceTier ? { responseServiceTier: logCtx.responseServiceTier } : {}),
1007
+ ...((attempts?.at(-1)?.tierOutcome ?? logCtx.tierOutcome)
1008
+ ? { tierOutcome: attempts?.at(-1)?.tierOutcome ?? { ...logCtx.tierOutcome! } }
1009
+ : {}),
805
1010
  ...(logCtx.resolvedModel ? { resolvedModel: logCtx.resolvedModel } : {}),
806
1011
  status: effectiveStatus,
807
1012
  durationMs: Date.now() - start,
@@ -813,10 +1018,11 @@ export function addFinalRequestLog(
813
1018
  usageStatus,
814
1019
  ...(loggedUsage ? { usage: loggedUsage } : {}),
815
1020
  ...(totalTokens !== undefined ? { totalTokens } : {}),
816
- ...(attempts?.length ? { attempts } : {}),
1021
+ ...(attempts !== undefined ? { attempts } : {}),
817
1022
  ...(logCtx.affinity ? { affinity: logCtx.affinity } : {}),
818
1023
  ...(logCtx.transportPhase ? { transportPhase: logCtx.transportPhase } : {}),
819
1024
  ...(logCtx.terminalSource ? { terminalSource: logCtx.terminalSource } : {}),
1025
+ ...(logCtx.routeDecision ? { routeDecision: logCtx.routeDecision } : {}),
820
1026
  });
821
1027
  if (isUsageDebugEnabled()) {
822
1028
  appendUsageDebug({
@@ -844,6 +1050,15 @@ export function filterRequestLogs(logs: RequestLogEntry[], params: URLSearchPara
844
1050
  if (conversationId) {
845
1051
  filtered = filtered.filter(entry => matchesLogConversationId(entry.conversationId, conversationId));
846
1052
  }
1053
+ // #2704: there was no `model` clause at all, so `?model=x` was ACCEPTED and silently
1054
+ // ignored -- worse than an error, because it yields wrong conclusions from output that
1055
+ // looks correct. Attempts are matched for the same reason `provider` matches them: a
1056
+ // request that failed over should be findable by the model that actually served it.
1057
+ const model = params.get("model")?.trim();
1058
+ if (model) {
1059
+ filtered = filtered.filter(entry => entry.model === model
1060
+ || entry.attempts?.some(attempt => attempt.model === model));
1061
+ }
847
1062
  const status = params.get("status")?.trim().toLowerCase();
848
1063
  if (status) {
849
1064
  filtered = /^[1-5]xx$/.test(status)
@@ -887,27 +1102,70 @@ interface FinalizedUsageResult {
887
1102
  totalTokens?: number;
888
1103
  }
889
1104
 
1105
+ /**
1106
+ * Context window for the routed model, used to cap the token estimate (codex-router PR #140):
1107
+ * a request the provider answered cannot have exceeded the window, so the estimate must never
1108
+ * claim it did. The family is picked by the route ADAPTER, not the model id alone, because
1109
+ * claude-family ids are shared between Kiro and Cursor with different windows. Kiro "auto" is
1110
+ * a router with no fixed window and is never guessed; unknown adapters/models stay uncapped.
1111
+ */
1112
+ function contextWindowForModel(adapter: string, modelId: string | undefined): number | undefined {
1113
+ if (!modelId) return undefined;
1114
+ if (adapter === "kiro" || adapter.startsWith("kiro-")) {
1115
+ const normalized = normalizeKiroModelId(modelId);
1116
+ if (normalized === "auto") return undefined;
1117
+ return modelRecordValue(KIRO_MODEL_CONTEXT_WINDOWS, modelId)
1118
+ ?? modelRecordValue(KIRO_MODEL_CONTEXT_WINDOWS, normalized);
1119
+ }
1120
+ if (adapter === "cursor" || adapter.startsWith("cursor-")) {
1121
+ return inferCursorContextWindow(modelId);
1122
+ }
1123
+ return undefined;
1124
+ }
1125
+
890
1126
  function finalizedUsage(
891
1127
  adapter: string,
892
1128
  usage: OcxUsage | undefined,
893
1129
  inputTokenEstimate: number | undefined,
1130
+ contextWindow: number | undefined,
1131
+ locallyAnswered = false,
894
1132
  ): FinalizedUsageResult {
1133
+ // The ESTIMATE itself is capped at the model's context window (codex-router PR #140). The
1134
+ // combined value below keeps its max(inputTokens, estimate) behavior — a provider-reported
1135
+ // positive count is never reduced by this cap, only the estimate that could substitute it.
895
1136
  const estimate = typeof inputTokenEstimate === "number"
896
1137
  && Number.isFinite(inputTokenEstimate)
897
1138
  && inputTokenEstimate >= 0
898
- ? inputTokenEstimate
1139
+ ? capEstimateAtContextWindow(inputTokenEstimate, contextWindow)
899
1140
  : undefined;
900
- const finalUsage = usageForFinalLog(adapter, usage);
1141
+ const finalUsage = usageForFinalLog(adapter, usage, locallyAnswered);
901
1142
  const usageFallback = !finalUsage && estimate !== undefined
902
1143
  ? { inputTokens: estimate, outputTokens: 0, estimated: true }
903
1144
  : undefined;
904
- const loggedUsage = finalUsage && estimate !== undefined
1145
+ const combinedInputTokens = finalUsage && estimate !== undefined
1146
+ ? Math.max(finalUsage.inputTokens, estimate)
1147
+ : undefined;
1148
+ const loggedUsage = finalUsage && combinedInputTokens !== undefined
905
1149
  ? {
906
1150
  ...finalUsage,
907
- inputTokens: Math.max(finalUsage.inputTokens, estimate),
1151
+ inputTokens: combinedInputTokens,
1152
+ totalTokens: combinedInputTokens + finalUsage.outputTokens,
908
1153
  estimated: true,
909
1154
  }
910
- : (finalUsage ?? usageFallback);
1155
+ : finalUsage
1156
+ // When the adapter alone produced an estimated count and no local estimate
1157
+ // exists, cap it at the context window — an adapter estimate above the window
1158
+ // misleads the usage dashboard. The combined branch (above) already caps the
1159
+ // ESTIMATE via capEstimateAtContextWindow, and Math.max preserves a real
1160
+ // provider-reported count, so it needs no further reduction.
1161
+ ? (finalUsage.estimated && contextWindow !== undefined && finalUsage.inputTokens > contextWindow
1162
+ ? {
1163
+ ...finalUsage,
1164
+ inputTokens: contextWindow,
1165
+ totalTokens: contextWindow + finalUsage.outputTokens,
1166
+ }
1167
+ : finalUsage)
1168
+ : usageFallback;
911
1169
  const totalTokens = usageTotalTokens(loggedUsage);
912
1170
  return {
913
1171
  status: usageStatusForFinalLog(loggedUsage),
@@ -939,10 +1197,12 @@ export function sealRequestAttemptIdentity(
939
1197
  attempt: PersistedUsageAttempt | undefined,
940
1198
  provider: string,
941
1199
  adapter: string,
1200
+ accountLogLabel?: string,
942
1201
  ): void {
943
1202
  if (!attempt) return;
944
1203
  attempt.provider = provider;
945
1204
  attempt.adapter = adapter;
1205
+ if (isCodexUsageAccountLogLabel(accountLogLabel)) attempt.accountLogLabel = accountLogLabel;
946
1206
  }
947
1207
 
948
1208
  export function noteAttemptSend(
@@ -955,7 +1215,12 @@ export function noteAttemptSend(
955
1215
  if (typeof inputTokenEstimate === "number"
956
1216
  && Number.isFinite(inputTokenEstimate)
957
1217
  && inputTokenEstimate >= 0) {
958
- attempt.inputTokenEstimate = inputTokenEstimate;
1218
+ // Store the ESTIMATE field already capped at the model's window (codex-router PR #140):
1219
+ // what gets persisted, and later merged into usage, never claims a count above the window.
1220
+ attempt.inputTokenEstimate = capEstimateAtContextWindow(
1221
+ inputTokenEstimate,
1222
+ contextWindowForModel(attempt.adapter, attempt.model),
1223
+ );
959
1224
  }
960
1225
  if (recovery && !attempt.recoveryKinds.includes(recovery)) {
961
1226
  attempt.recoveryKinds.push(recovery);
@@ -972,6 +1237,8 @@ export function finishRequestAttempt(
972
1237
  attempt.adapter,
973
1238
  usage ?? attempt.usage,
974
1239
  attempt.inputTokenEstimate,
1240
+ contextWindowForModel(attempt.adapter, attempt.model),
1241
+ attempt.locallyAnswered === true,
975
1242
  );
976
1243
  attempt.status = status;
977
1244
  attempt.durationMs = Math.max(0, durationMs);