@yansigit/opencodex 2.31.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 (826) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/LICENSE +21 -0
  3. package/README.md +303 -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 +587 -0
  9. package/bin/package-main.mjs +9 -0
  10. package/gui/dist/assets/index-BNJ7r4Gd.js +102 -0
  11. package/gui/dist/assets/index-CGoDO3uO.css +1 -0
  12. package/gui/dist/favicon.png +0 -0
  13. package/gui/dist/icons.svg +24 -0
  14. package/gui/dist/index.html +25 -0
  15. package/gui/dist/logo.png +0 -0
  16. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  17. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  18. package/gui/dist/provider-icons/claude-color.svg +1 -0
  19. package/gui/dist/provider-icons/cline-color.svg +16 -0
  20. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  21. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  22. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  23. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  24. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  25. package/gui/dist/provider-icons/discord.svg +1 -0
  26. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  27. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  28. package/gui/dist/provider-icons/gemini-color.svg +1 -0
  29. package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
  30. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
  31. package/gui/dist/provider-icons/grok.svg +1 -0
  32. package/gui/dist/provider-icons/groq-color.svg +1 -0
  33. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  34. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  35. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  36. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  37. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  38. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  39. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  40. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  41. package/gui/dist/provider-icons/openai.svg +1 -0
  42. package/gui/dist/provider-icons/opencode.svg +2 -0
  43. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  44. package/gui/dist/provider-icons/pi.svg +21 -0
  45. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  46. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  47. package/gui/dist/provider-icons/telegram.svg +1 -0
  48. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  49. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  50. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  51. package/package.json +108 -0
  52. package/src/AGENTS.md +28 -0
  53. package/src/adapters/anthropic-image-guard.ts +251 -0
  54. package/src/adapters/anthropic-image-normalize.ts +518 -0
  55. package/src/adapters/anthropic-output-schema.ts +137 -0
  56. package/src/adapters/anthropic.ts +1327 -0
  57. package/src/adapters/azure.ts +36 -0
  58. package/src/adapters/base.ts +121 -0
  59. package/src/adapters/client-fingerprint.ts +65 -0
  60. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  61. package/src/adapters/command-code.ts +601 -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/checkpoint-store.ts +303 -0
  65. package/src/adapters/cursor/cursor-errors.ts +288 -0
  66. package/src/adapters/cursor/discovery.ts +333 -0
  67. package/src/adapters/cursor/effort-map.ts +151 -0
  68. package/src/adapters/cursor/exec-policy.ts +88 -0
  69. package/src/adapters/cursor/framing.ts +250 -0
  70. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  71. package/src/adapters/cursor/h2-pool.ts +123 -0
  72. package/src/adapters/cursor/http1-bidi.ts +361 -0
  73. package/src/adapters/cursor/images.ts +704 -0
  74. package/src/adapters/cursor/kv-store.ts +52 -0
  75. package/src/adapters/cursor/live-models.ts +269 -0
  76. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  77. package/src/adapters/cursor/live-transport.ts +1653 -0
  78. package/src/adapters/cursor/mcp-config.ts +42 -0
  79. package/src/adapters/cursor/mcp-manager.ts +333 -0
  80. package/src/adapters/cursor/message-mapper.ts +49 -0
  81. package/src/adapters/cursor/native-exec-common.ts +76 -0
  82. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  83. package/src/adapters/cursor/native-exec-fs.ts +332 -0
  84. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  85. package/src/adapters/cursor/native-exec-network.ts +43 -0
  86. package/src/adapters/cursor/native-exec-shell.ts +547 -0
  87. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  88. package/src/adapters/cursor/native-exec.ts +663 -0
  89. package/src/adapters/cursor/protobuf-events.ts +1381 -0
  90. package/src/adapters/cursor/protobuf-request.ts +1032 -0
  91. package/src/adapters/cursor/request-builder.ts +461 -0
  92. package/src/adapters/cursor/thread-continuity.ts +67 -0
  93. package/src/adapters/cursor/tool-definitions.ts +735 -0
  94. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  95. package/src/adapters/cursor/transport-retry.ts +132 -0
  96. package/src/adapters/cursor/transport.ts +79 -0
  97. package/src/adapters/cursor/types.ts +79 -0
  98. package/src/adapters/cursor.ts +322 -0
  99. package/src/adapters/google-antigravity-hosts.ts +48 -0
  100. package/src/adapters/google-antigravity-replay.ts +827 -0
  101. package/src/adapters/google-antigravity-tools.ts +105 -0
  102. package/src/adapters/google-antigravity-wire.ts +141 -0
  103. package/src/adapters/google-errors.ts +92 -0
  104. package/src/adapters/google-http.ts +460 -0
  105. package/src/adapters/google-tool-schema.ts +238 -0
  106. package/src/adapters/google-truncation.ts +24 -0
  107. package/src/adapters/google-wire-compiler.ts +232 -0
  108. package/src/adapters/google.ts +1377 -0
  109. package/src/adapters/identity.ts +77 -0
  110. package/src/adapters/image.ts +23 -0
  111. package/src/adapters/kiro-constants.ts +16 -0
  112. package/src/adapters/kiro-errors.ts +208 -0
  113. package/src/adapters/kiro-events.ts +197 -0
  114. package/src/adapters/kiro-images.ts +129 -0
  115. package/src/adapters/kiro-retry.ts +312 -0
  116. package/src/adapters/kiro-thinking.ts +112 -0
  117. package/src/adapters/kiro-tool-fallback.ts +36 -0
  118. package/src/adapters/kiro-tools.ts +224 -0
  119. package/src/adapters/kiro-truncation.ts +33 -0
  120. package/src/adapters/kiro-wire.ts +129 -0
  121. package/src/adapters/kiro.ts +1936 -0
  122. package/src/adapters/mimo-free.ts +280 -0
  123. package/src/adapters/openai-chat-url.ts +11 -0
  124. package/src/adapters/openai-chat.ts +1980 -0
  125. package/src/adapters/openai-responses-url.ts +16 -0
  126. package/src/adapters/openai-responses.ts +1911 -0
  127. package/src/adapters/registry.ts +175 -0
  128. package/src/adapters/responses-tool-schema.ts +67 -0
  129. package/src/adapters/run-turn-queue.ts +114 -0
  130. package/src/adapters/tool-call-id.ts +119 -0
  131. package/src/adapters/tool-catalog-nudge.ts +154 -0
  132. package/src/adapters/upstream-http-error.ts +48 -0
  133. package/src/adapters/xai-web-search.ts +185 -0
  134. package/src/bridge.ts +1986 -0
  135. package/src/chat/inbound.ts +319 -0
  136. package/src/chat/outbound.ts +821 -0
  137. package/src/claude/agents-inject.ts +266 -0
  138. package/src/claude/alias.ts +149 -0
  139. package/src/claude/auth-detect.ts +229 -0
  140. package/src/claude/auth-mode-migration.ts +32 -0
  141. package/src/claude/auth-mode.ts +62 -0
  142. package/src/claude/context-windows.ts +205 -0
  143. package/src/claude/desktop-3p-guard.ts +35 -0
  144. package/src/claude/desktop-3p-paths.ts +84 -0
  145. package/src/claude/desktop-3p.ts +615 -0
  146. package/src/claude/desktop-health.ts +26 -0
  147. package/src/claude/desktop-profile.ts +263 -0
  148. package/src/claude/gateway-cache.ts +107 -0
  149. package/src/claude/inbound-debug.ts +163 -0
  150. package/src/claude/inbound.ts +578 -0
  151. package/src/claude/model-info.ts +174 -0
  152. package/src/claude/outbound.ts +926 -0
  153. package/src/cli/access.ts +108 -0
  154. package/src/cli/account-api.ts +302 -0
  155. package/src/cli/account-auth.ts +250 -0
  156. package/src/cli/account-catalog-refresh.ts +14 -0
  157. package/src/cli/account-extended.ts +737 -0
  158. package/src/cli/account-main.ts +317 -0
  159. package/src/cli/account.ts +299 -0
  160. package/src/cli/agent-driven.ts +70 -0
  161. package/src/cli/agent.ts +290 -0
  162. package/src/cli/catalog-prewarm.ts +27 -0
  163. package/src/cli/claude-agent-startup-sync.ts +73 -0
  164. package/src/cli/claude-desktop.ts +213 -0
  165. package/src/cli/claude.ts +355 -0
  166. package/src/cli/codex-log-guard-doctor.ts +103 -0
  167. package/src/cli/codex-shim-autorestore.ts +47 -0
  168. package/src/cli/codex-shim-readiness.ts +76 -0
  169. package/src/cli/combo.ts +127 -0
  170. package/src/cli/config-command.ts +209 -0
  171. package/src/cli/debug.ts +228 -0
  172. package/src/cli/dispatch.ts +585 -0
  173. package/src/cli/doctor.ts +1202 -0
  174. package/src/cli/ensure-desired-integrations.ts +152 -0
  175. package/src/cli/export-command.ts +213 -0
  176. package/src/cli/help.ts +101 -0
  177. package/src/cli/index.ts +973 -0
  178. package/src/cli/init.ts +211 -0
  179. package/src/cli/integrations.ts +260 -0
  180. package/src/cli/interactive-confirm.ts +133 -0
  181. package/src/cli/lab.ts +607 -0
  182. package/src/cli/launcher-context.ts +77 -0
  183. package/src/cli/minimax.ts +497 -0
  184. package/src/cli/models-runtime.ts +245 -0
  185. package/src/cli/models.ts +422 -0
  186. package/src/cli/observe.ts +206 -0
  187. package/src/cli/opencode.ts +588 -0
  188. package/src/cli/provider-replit.ts +232 -0
  189. package/src/cli/provider-runtime.ts +179 -0
  190. package/src/cli/provider.ts +492 -0
  191. package/src/cli/ready.ts +301 -0
  192. package/src/cli/registry.ts +422 -0
  193. package/src/cli/replit-gateway-key-input.ts +138 -0
  194. package/src/cli/root.ts +86 -0
  195. package/src/cli/route-policy.ts +92 -0
  196. package/src/cli/runtime-api.ts +328 -0
  197. package/src/cli/star-prompt.ts +211 -0
  198. package/src/cli/status-oauth.ts +78 -0
  199. package/src/cli/status.ts +328 -0
  200. package/src/cli/system-command.ts +112 -0
  201. package/src/cli/system-restart-client.ts +146 -0
  202. package/src/cli/tray-proxy.ts +199 -0
  203. package/src/cli/v2.ts +268 -0
  204. package/src/cli.ts +10 -0
  205. package/src/clients/config-export.ts +1704 -0
  206. package/src/codex/account-id.ts +34 -0
  207. package/src/codex/account-label.ts +47 -0
  208. package/src/codex/account-lifecycle.ts +172 -0
  209. package/src/codex/account-namespace-match.ts +63 -0
  210. package/src/codex/account-namespaces.ts +195 -0
  211. package/src/codex/account-pause.ts +20 -0
  212. package/src/codex/account-priority.ts +83 -0
  213. package/src/codex/account-runtime-state.ts +31 -0
  214. package/src/codex/account-store.ts +544 -0
  215. package/src/codex/account-usability.ts +43 -0
  216. package/src/codex/admission.ts +256 -0
  217. package/src/codex/affinity-debug.ts +162 -0
  218. package/src/codex/agent-roles-sync.ts +225 -0
  219. package/src/codex/agent-roles.ts +238 -0
  220. package/src/codex/app-server-processes.ts +1143 -0
  221. package/src/codex/app-server-restart-service.ts +232 -0
  222. package/src/codex/auth-api.ts +2147 -0
  223. package/src/codex/auth-collision.ts +109 -0
  224. package/src/codex/auth-context.ts +665 -0
  225. package/src/codex/autostart-health.ts +156 -0
  226. package/src/codex/catalog/account-models.ts +67 -0
  227. package/src/codex/catalog/aggregation.ts +436 -0
  228. package/src/codex/catalog/bundled.ts +549 -0
  229. package/src/codex/catalog/effort.ts +446 -0
  230. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  231. package/src/codex/catalog/kinds.ts +2 -0
  232. package/src/codex/catalog/metadata.ts +664 -0
  233. package/src/codex/catalog/native-models.ts +72 -0
  234. package/src/codex/catalog/parsing.ts +650 -0
  235. package/src/codex/catalog/provider-fetch.ts +2064 -0
  236. package/src/codex/catalog/sync.ts +1883 -0
  237. package/src/codex/catalog-admission.ts +199 -0
  238. package/src/codex/catalog-refresh-status.ts +105 -0
  239. package/src/codex/catalog-write-serialization.ts +242 -0
  240. package/src/codex/catalog.ts +14 -0
  241. package/src/codex/codex-write-lock.ts +384 -0
  242. package/src/codex/convergence-types.ts +614 -0
  243. package/src/codex/convergence.ts +651 -0
  244. package/src/codex/coordinator-doctor.ts +332 -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/exec-invocation.ts +22 -0
  249. package/src/codex/features.ts +1566 -0
  250. package/src/codex/generation.ts +202 -0
  251. package/src/codex/history-job.ts +407 -0
  252. package/src/codex/history-lock.ts +242 -0
  253. package/src/codex/history-migration-guardian.ts +108 -0
  254. package/src/codex/history-provider.ts +979 -0
  255. package/src/codex/history-transition.ts +105 -0
  256. package/src/codex/history-worker.ts +220 -0
  257. package/src/codex/home.ts +206 -0
  258. package/src/codex/inject-coordination.ts +290 -0
  259. package/src/codex/inject.ts +1733 -0
  260. package/src/codex/injected-marker.ts +106 -0
  261. package/src/codex/integration-record.ts +266 -0
  262. package/src/codex/internal/catalog-writer.ts +203 -0
  263. package/src/codex/internal/history-writer.ts +80 -0
  264. package/src/codex/journal.ts +225 -0
  265. package/src/codex/log-guard/inspect.ts +506 -0
  266. package/src/codex/log-guard/lock.ts +150 -0
  267. package/src/codex/log-guard/maintenance.ts +403 -0
  268. package/src/codex/log-guard/path-safety.ts +88 -0
  269. package/src/codex/log-guard/policy.ts +44 -0
  270. package/src/codex/log-guard/processes.ts +205 -0
  271. package/src/codex/log-guard/protection.ts +489 -0
  272. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  273. package/src/codex/main-account-cache.ts +56 -0
  274. package/src/codex/main-account.ts +68 -0
  275. package/src/codex/management-convergence.ts +167 -0
  276. package/src/codex/model-cache.ts +273 -0
  277. package/src/codex/model-entitlements.ts +353 -0
  278. package/src/codex/native-main-admission.ts +47 -0
  279. package/src/codex/native-main-auth-temp.ts +187 -0
  280. package/src/codex/native-main-claim.ts +178 -0
  281. package/src/codex/native-main-lock-file.ts +162 -0
  282. package/src/codex/native-main-owner.ts +329 -0
  283. package/src/codex/native-profile-api.ts +247 -0
  284. package/src/codex/native-profile-manager.ts +1531 -0
  285. package/src/codex/native-profile-processes.ts +121 -0
  286. package/src/codex/native-profile-recovery.ts +99 -0
  287. package/src/codex/native-profile-stage-store.ts +387 -0
  288. package/src/codex/native-profile-startup.ts +492 -0
  289. package/src/codex/native-profile-store.ts +855 -0
  290. package/src/codex/native-profile-types.ts +120 -0
  291. package/src/codex/native-residue.ts +682 -0
  292. package/src/codex/paths.ts +144 -0
  293. package/src/codex/plan-from-token.ts +140 -0
  294. package/src/codex/plan.ts +40 -0
  295. package/src/codex/plugins-doctor.ts +242 -0
  296. package/src/codex/pool-rotation.ts +295 -0
  297. package/src/codex/project-config-warnings.ts +425 -0
  298. package/src/codex/prompt-journal.ts +352 -0
  299. package/src/codex/prompt-layers.ts +967 -0
  300. package/src/codex/prompt-lock.ts +143 -0
  301. package/src/codex/quota-rejection.ts +298 -0
  302. package/src/codex/quota.ts +573 -0
  303. package/src/codex/refresh.ts +62 -0
  304. package/src/codex/reset-credit-recovery.ts +1044 -0
  305. package/src/codex/routing.ts +1888 -0
  306. package/src/codex/runtime.ts +659 -0
  307. package/src/codex/shim.ts +2170 -0
  308. package/src/codex/subagent-defaults.ts +550 -0
  309. package/src/codex/subagent-model-fallback.ts +784 -0
  310. package/src/codex/sync.ts +319 -0
  311. package/src/codex/transition-state.ts +612 -0
  312. package/src/codex/upstream-host-health.ts +368 -0
  313. package/src/codex/user-identity.ts +557 -0
  314. package/src/codex/warmup.ts +298 -0
  315. package/src/codex/websocket-registry.ts +100 -0
  316. package/src/codex/write-coordination.ts +114 -0
  317. package/src/combos/failover.ts +160 -0
  318. package/src/combos/index.ts +45 -0
  319. package/src/combos/request.ts +94 -0
  320. package/src/combos/resolve.ts +232 -0
  321. package/src/combos/types.ts +398 -0
  322. package/src/config/provider-name.ts +24 -0
  323. package/src/config.ts +4041 -0
  324. package/src/fork/register.ts +3 -0
  325. package/src/generated/compatibility-version.json +3116 -0
  326. package/src/generated/model-metadata.ts +106 -0
  327. package/src/github/star-state.ts +203 -0
  328. package/src/grok/inject.ts +530 -0
  329. package/src/grok/inspect.ts +45 -0
  330. package/src/grok/status.ts +121 -0
  331. package/src/grok/sync.ts +66 -0
  332. package/src/images/artifacts.ts +516 -0
  333. package/src/images/fulfill-video.ts +163 -0
  334. package/src/images/fulfill.ts +149 -0
  335. package/src/images/index.ts +4 -0
  336. package/src/images/loop.ts +955 -0
  337. package/src/images/plan.ts +143 -0
  338. package/src/images/synthetic-tool.ts +133 -0
  339. package/src/images/types.ts +41 -0
  340. package/src/images/xai-client.ts +141 -0
  341. package/src/images/xai-video-client.ts +163 -0
  342. package/src/index.ts +22 -0
  343. package/src/integrations/config-io.ts +269 -0
  344. package/src/integrations/journal.ts +315 -0
  345. package/src/integrations/merge.ts +135 -0
  346. package/src/integrations/mutation-flight.ts +71 -0
  347. package/src/integrations/native/ownership-preflight.ts +202 -0
  348. package/src/integrations/omp-yaml-source.ts +358 -0
  349. package/src/integrations/owned-refresh.ts +74 -0
  350. package/src/integrations/ownership.ts +111 -0
  351. package/src/integrations/registry.ts +159 -0
  352. package/src/integrations/serialize.ts +314 -0
  353. package/src/integrations/state.ts +361 -0
  354. package/src/integrations/store.ts +103 -0
  355. package/src/integrations/writer-lock.ts +98 -0
  356. package/src/integrations/writer.ts +691 -0
  357. package/src/lab/artifacts/sanitize.ts +586 -0
  358. package/src/lab/artifacts/secure-fs.ts +475 -0
  359. package/src/lab/artifacts/store.ts +310 -0
  360. package/src/lab/automation/budgets.ts +78 -0
  361. package/src/lab/automation/config-persistence.ts +256 -0
  362. package/src/lab/automation/constants.ts +39 -0
  363. package/src/lab/automation/cooldown.ts +103 -0
  364. package/src/lab/automation/dispatch.ts +211 -0
  365. package/src/lab/automation/index.ts +13 -0
  366. package/src/lab/automation/orchestrator.ts +499 -0
  367. package/src/lab/automation/persistence.ts +512 -0
  368. package/src/lab/automation/planner.ts +371 -0
  369. package/src/lab/automation/policy.ts +136 -0
  370. package/src/lab/automation/queue.ts +191 -0
  371. package/src/lab/automation/recovery.ts +24 -0
  372. package/src/lab/automation/route-context.ts +21 -0
  373. package/src/lab/automation/run-key.ts +44 -0
  374. package/src/lab/automation/runs-query.ts +34 -0
  375. package/src/lab/automation/types.ts +160 -0
  376. package/src/lab/conformance/assertion.ts +325 -0
  377. package/src/lab/conformance/digest.ts +22 -0
  378. package/src/lab/conformance/executor.ts +741 -0
  379. package/src/lab/conformance/fixture-provider.ts +27 -0
  380. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  381. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  382. package/src/lab/conformance/harness-budget.ts +47 -0
  383. package/src/lab/conformance/index.ts +5 -0
  384. package/src/lab/conformance/jcs.ts +64 -0
  385. package/src/lab/conformance/json-pointer.ts +39 -0
  386. package/src/lab/conformance/manifest.ts +180 -0
  387. package/src/lab/conformance/mcp-stub.ts +179 -0
  388. package/src/lab/conformance/negative-controls.ts +164 -0
  389. package/src/lab/conformance/observation.ts +355 -0
  390. package/src/lab/conformance/runner.ts +68 -0
  391. package/src/lab/conformance/sse-normalize.ts +59 -0
  392. package/src/lab/conformance/suite-manifest.ts +78 -0
  393. package/src/lab/conformance/types.ts +214 -0
  394. package/src/lab/constants.ts +126 -0
  395. package/src/lab/digest.ts +64 -0
  396. package/src/lab/events/errors.ts +9 -0
  397. package/src/lab/events/limits.ts +117 -0
  398. package/src/lab/events/types.ts +229 -0
  399. package/src/lab/events/validate.ts +781 -0
  400. package/src/lab/fabric/constants.ts +40 -0
  401. package/src/lab/fabric/executor.ts +492 -0
  402. package/src/lab/fabric/index.ts +80 -0
  403. package/src/lab/fabric/manifest.ts +222 -0
  404. package/src/lab/fabric/observe.ts +489 -0
  405. package/src/lab/fabric/patch.ts +79 -0
  406. package/src/lab/fabric/producer-child.ts +139 -0
  407. package/src/lab/fabric/producer-isolate.ts +276 -0
  408. package/src/lab/fabric/producer-protocol.ts +61 -0
  409. package/src/lab/fabric/scratch.ts +439 -0
  410. package/src/lab/fabric/subject.ts +106 -0
  411. package/src/lab/fabric/types.ts +134 -0
  412. package/src/lab/fabric/verifier.ts +98 -0
  413. package/src/lab/index.ts +54 -0
  414. package/src/lab/ledger/artifact-refs.ts +127 -0
  415. package/src/lab/ledger/invalidation.ts +136 -0
  416. package/src/lab/ledger/purge.ts +310 -0
  417. package/src/lab/ledger/store.ts +532 -0
  418. package/src/lab/live/credential-lease.ts +53 -0
  419. package/src/lab/live/destination.ts +155 -0
  420. package/src/lab/live/executor.ts +336 -0
  421. package/src/lab/live/inert-tools.ts +56 -0
  422. package/src/lab/live/manifest.ts +85 -0
  423. package/src/lab/live/mcp-loopback.ts +57 -0
  424. package/src/lab/live/runner.ts +19 -0
  425. package/src/lab/live/sandbox.ts +61 -0
  426. package/src/lab/live/suite-manifest.ts +41 -0
  427. package/src/lab/live/transport.ts +118 -0
  428. package/src/lab/live/types.ts +197 -0
  429. package/src/lab/observe/from-conformance.ts +301 -0
  430. package/src/lab/observe/from-live.ts +117 -0
  431. package/src/lab/paths.ts +153 -0
  432. package/src/lab/projection/rebuild.ts +495 -0
  433. package/src/lab/projection/schema.ts +135 -0
  434. package/src/lab/projection/verdicts.ts +474 -0
  435. package/src/lab/projection/verification.ts +412 -0
  436. package/src/lab/public/bundle.ts +217 -0
  437. package/src/lab/public/community-authority.ts +175 -0
  438. package/src/lab/public/community-files.ts +29 -0
  439. package/src/lab/public/community.ts +479 -0
  440. package/src/lab/public/file-safety.ts +155 -0
  441. package/src/lab/public/ids.ts +26 -0
  442. package/src/lab/public/index.ts +16 -0
  443. package/src/lab/public/mutation-lock.ts +424 -0
  444. package/src/lab/public/operator.ts +353 -0
  445. package/src/lab/public/origin-purge.ts +79 -0
  446. package/src/lab/public/origin.ts +203 -0
  447. package/src/lab/public/privacy.ts +143 -0
  448. package/src/lab/public/private-file.ts +261 -0
  449. package/src/lab/public/project.ts +124 -0
  450. package/src/lab/public/purge-test-fault.ts +21 -0
  451. package/src/lab/public/purge.ts +223 -0
  452. package/src/lab/public/registry.ts +44 -0
  453. package/src/lab/public/revocation.ts +252 -0
  454. package/src/lab/public/signature.ts +243 -0
  455. package/src/lab/public/storage.ts +105 -0
  456. package/src/lab/public/strict-json.ts +206 -0
  457. package/src/lab/public/time.ts +26 -0
  458. package/src/lab/public/types.ts +172 -0
  459. package/src/lab/public/validate.ts +391 -0
  460. package/src/lab/query/catalog.ts +101 -0
  461. package/src/lab/query/connection.ts +107 -0
  462. package/src/lab/query/constants.ts +4 -0
  463. package/src/lab/query/cursor.ts +132 -0
  464. package/src/lab/query/dto-map.ts +277 -0
  465. package/src/lab/query/errors.ts +22 -0
  466. package/src/lab/query/freshness.ts +53 -0
  467. package/src/lab/query/index.ts +45 -0
  468. package/src/lab/query/latest-observation.ts +59 -0
  469. package/src/lab/query/passive-production.ts +159 -0
  470. package/src/lab/query/queries.ts +444 -0
  471. package/src/lab/query/types.ts +266 -0
  472. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  473. package/src/lab/subject/installation-salt.ts +112 -0
  474. package/src/lab/subject/protocol-subject.ts +80 -0
  475. package/src/lab/subject/route-subject.ts +74 -0
  476. package/src/lib/abort.ts +146 -0
  477. package/src/lib/admin-secrets.ts +25 -0
  478. package/src/lib/admission.ts +83 -0
  479. package/src/lib/app-owned-memory-stores.ts +195 -0
  480. package/src/lib/app-owned-memory.ts +265 -0
  481. package/src/lib/bounded-body.ts +346 -0
  482. package/src/lib/bun-binary-validator.d.mts +3 -0
  483. package/src/lib/bun-binary-validator.mjs +18 -0
  484. package/src/lib/bun-runtime.ts +184 -0
  485. package/src/lib/bun-stream-caps.ts +130 -0
  486. package/src/lib/codex-restart-contract.ts +120 -0
  487. package/src/lib/config-ownership.ts +364 -0
  488. package/src/lib/crash-guard.ts +344 -0
  489. package/src/lib/debug-log-buffer.ts +83 -0
  490. package/src/lib/debug-settings.ts +108 -0
  491. package/src/lib/debug.ts +31 -0
  492. package/src/lib/destination-policy.ts +380 -0
  493. package/src/lib/errors.ts +406 -0
  494. package/src/lib/eventstream-decoder.ts +253 -0
  495. package/src/lib/fabric-task-execution-authority.ts +7 -0
  496. package/src/lib/fabric-task-host.ts +29 -0
  497. package/src/lib/gcp-adc.ts +341 -0
  498. package/src/lib/injection-debug-log.ts +58 -0
  499. package/src/lib/lab-activation.ts +223 -0
  500. package/src/lib/lab-live-execution-authority.ts +13 -0
  501. package/src/lib/lab-live-host.ts +30 -0
  502. package/src/lib/lab-live-pinned-sender.ts +56 -0
  503. package/src/lib/lab-live-route-production.ts +130 -0
  504. package/src/lib/lab-passive-linker-registration.ts +26 -0
  505. package/src/lib/local-management-attestation.ts +51 -0
  506. package/src/lib/local-management-capability.ts +100 -0
  507. package/src/lib/local-provider-reload-contract.ts +100 -0
  508. package/src/lib/open-url.ts +25 -0
  509. package/src/lib/optional-shutdown-hooks.ts +57 -0
  510. package/src/lib/pinned-http.ts +270 -0
  511. package/src/lib/privacy.ts +20 -0
  512. package/src/lib/process-control.ts +168 -0
  513. package/src/lib/provider-outbound.ts +210 -0
  514. package/src/lib/provider-url.ts +14 -0
  515. package/src/lib/proxy-env.ts +18 -0
  516. package/src/lib/redact.ts +521 -0
  517. package/src/lib/retry-after.ts +55 -0
  518. package/src/lib/self-launch-argv.ts +15 -0
  519. package/src/lib/server-resource-ownership.ts +71 -0
  520. package/src/lib/service-secrets.ts +25 -0
  521. package/src/lib/shadow-call.ts +61 -0
  522. package/src/lib/sidecar-tracker.ts +52 -0
  523. package/src/lib/sse-decoder.ts +364 -0
  524. package/src/lib/state-store-registrations.ts +119 -0
  525. package/src/lib/state-store-sweeper.ts +184 -0
  526. package/src/lib/system-restart-contract.ts +73 -0
  527. package/src/lib/test-home-guard.ts +90 -0
  528. package/src/lib/token-estimate.ts +86 -0
  529. package/src/lib/tool-argument-integers.ts +202 -0
  530. package/src/lib/translator-budget.ts +400 -0
  531. package/src/lib/upstream-http-version.ts +57 -0
  532. package/src/lib/upstream-reachability.ts +95 -0
  533. package/src/lib/upstream-retry.ts +392 -0
  534. package/src/lib/win-exec.ts +115 -0
  535. package/src/lib/win-paths.ts +68 -0
  536. package/src/lib/windows-atomic-replace.ts +156 -0
  537. package/src/lib/windows-elevation.ts +773 -0
  538. package/src/lib/windows-secret-acl.ts +854 -0
  539. package/src/lib/windows-service-wrappers.ts +72 -0
  540. package/src/lib/windows-text.ts +106 -0
  541. package/src/lib/windows-user-principal.ts +341 -0
  542. package/src/lib/winsw.ts +403 -0
  543. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  544. package/src/oauth/account-import/index.ts +15 -0
  545. package/src/oauth/account-import/parser.ts +83 -0
  546. package/src/oauth/account-import/registry.ts +18 -0
  547. package/src/oauth/account-import/service.ts +75 -0
  548. package/src/oauth/account-import/types.ts +91 -0
  549. package/src/oauth/anthropic-routing.ts +594 -0
  550. package/src/oauth/anthropic.ts +188 -0
  551. package/src/oauth/antigravity-routing.ts +151 -0
  552. package/src/oauth/callback-server.ts +300 -0
  553. package/src/oauth/chatgpt.ts +161 -0
  554. package/src/oauth/command-code.ts +239 -0
  555. package/src/oauth/cursor.ts +252 -0
  556. package/src/oauth/github-copilot.ts +428 -0
  557. package/src/oauth/google-antigravity.ts +262 -0
  558. package/src/oauth/health.ts +407 -0
  559. package/src/oauth/index.ts +1504 -0
  560. package/src/oauth/key-providers.ts +124 -0
  561. package/src/oauth/kimi.ts +227 -0
  562. package/src/oauth/kiro-credentials.ts +726 -0
  563. package/src/oauth/kiro.ts +621 -0
  564. package/src/oauth/local-token-detect.ts +130 -0
  565. package/src/oauth/log.ts +50 -0
  566. package/src/oauth/login-cli.ts +223 -0
  567. package/src/oauth/nous.ts +798 -0
  568. package/src/oauth/pkce.ts +15 -0
  569. package/src/oauth/store.ts +728 -0
  570. package/src/oauth/token-guardian.ts +309 -0
  571. package/src/oauth/types.ts +62 -0
  572. package/src/oauth/xai.ts +241 -0
  573. package/src/providers/alibaba-region-backup.ts +75 -0
  574. package/src/providers/alibaba-region-migration.ts +156 -0
  575. package/src/providers/alibaba-region-startup.ts +36 -0
  576. package/src/providers/antigravity-models.ts +695 -0
  577. package/src/providers/antigravity-quota.ts +216 -0
  578. package/src/providers/api-keys.ts +140 -0
  579. package/src/providers/base-url-choices.ts +74 -0
  580. package/src/providers/codex-capacity.ts +292 -0
  581. package/src/providers/command-code-efforts.ts +144 -0
  582. package/src/providers/context-cap.ts +82 -0
  583. package/src/providers/cursor-pool.ts +72 -0
  584. package/src/providers/derive.ts +586 -0
  585. package/src/providers/fastwire.ts +501 -0
  586. package/src/providers/free-directory.ts +187 -0
  587. package/src/providers/github-copilot-transport.ts +56 -0
  588. package/src/providers/google-vertex-location.ts +14 -0
  589. package/src/providers/key-failover.ts +271 -0
  590. package/src/providers/kiro-models.ts +67 -0
  591. package/src/providers/label.ts +19 -0
  592. package/src/providers/model-discovery-limits.ts +16 -0
  593. package/src/providers/model-discovery.ts +449 -0
  594. package/src/providers/model-rename-migration.ts +255 -0
  595. package/src/providers/model-rename-startup.ts +28 -0
  596. package/src/providers/openai-sidecar.ts +243 -0
  597. package/src/providers/openai-tier-startup.ts +56 -0
  598. package/src/providers/openai-tiers.ts +423 -0
  599. package/src/providers/openai-virtual-models.ts +83 -0
  600. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  601. package/src/providers/openrouter-routing.ts +102 -0
  602. package/src/providers/provider-id-rewrite.ts +185 -0
  603. package/src/providers/quota.ts +2345 -0
  604. package/src/providers/registry.ts +2918 -0
  605. package/src/providers/replit/constants.ts +27 -0
  606. package/src/providers/replit/derive.ts +85 -0
  607. package/src/providers/replit/headers.ts +28 -0
  608. package/src/providers/replit/origin.ts +55 -0
  609. package/src/providers/replit/pair-install-response.ts +72 -0
  610. package/src/providers/replit/probe.ts +199 -0
  611. package/src/providers/replit/setup.ts +350 -0
  612. package/src/providers/request-pacing.ts +310 -0
  613. package/src/providers/service-tier.ts +277 -0
  614. package/src/providers/slug-codec.ts +103 -0
  615. package/src/providers/static-model-discovery.ts +86 -0
  616. package/src/providers/xai-responses-opt-in.ts +15 -0
  617. package/src/providers/xai-transport.ts +148 -0
  618. package/src/reasoning-effort.ts +183 -0
  619. package/src/responses/compaction.ts +142 -0
  620. package/src/responses/custom-tool-compat.ts +266 -0
  621. package/src/responses/hosted-tool-policy.ts +9 -0
  622. package/src/responses/namespace-tool-compat.ts +355 -0
  623. package/src/responses/parser.ts +838 -0
  624. package/src/responses/provider-continuation.ts +98 -0
  625. package/src/responses/provider-opaque-metadata.ts +73 -0
  626. package/src/responses/reasoning-envelope.ts +60 -0
  627. package/src/responses/reasoning-replay-cache.ts +426 -0
  628. package/src/responses/schema.ts +165 -0
  629. package/src/responses/spill-store.ts +459 -0
  630. package/src/responses/state.ts +1433 -0
  631. package/src/responses/thought-signature-replay.ts +347 -0
  632. package/src/responses/tool-groups.ts +19 -0
  633. package/src/responses/tool-search-compat.ts +301 -0
  634. package/src/responses/truncated-stop-reason.ts +60 -0
  635. package/src/router.ts +761 -0
  636. package/src/routing/analytics.ts +378 -0
  637. package/src/routing/capability.ts +244 -0
  638. package/src/routing/compatibility/assemble.ts +73 -0
  639. package/src/routing/compatibility/behavior.ts +278 -0
  640. package/src/routing/compatibility/catalog.ts +99 -0
  641. package/src/routing/compatibility/endpoint.ts +52 -0
  642. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  643. package/src/routing/compatibility/policy.ts +181 -0
  644. package/src/routing/compatibility/provider-slot.ts +56 -0
  645. package/src/routing/compatibility/reader.ts +110 -0
  646. package/src/routing/compatibility/subject.ts +191 -0
  647. package/src/routing/compatibility/types.ts +64 -0
  648. package/src/routing/compatibility/version.ts +104 -0
  649. package/src/routing/cost.ts +77 -0
  650. package/src/routing/evaluator.ts +495 -0
  651. package/src/routing/health.ts +412 -0
  652. package/src/routing/history/cursor.ts +43 -0
  653. package/src/routing/history/indexer.ts +605 -0
  654. package/src/routing/history/schema.ts +72 -0
  655. package/src/routing/profile-namespace.ts +15 -0
  656. package/src/routing/profile.ts +547 -0
  657. package/src/routing/quota.ts +145 -0
  658. package/src/routing/request-evidence.ts +45 -0
  659. package/src/routing/trace.ts +776 -0
  660. package/src/server/adapter-resolve.ts +53 -0
  661. package/src/server/auth-cors.ts +751 -0
  662. package/src/server/background-lifecycle.ts +182 -0
  663. package/src/server/chat-completions.ts +442 -0
  664. package/src/server/chat-native-sse.ts +331 -0
  665. package/src/server/chat-native.ts +426 -0
  666. package/src/server/claude-messages.ts +1030 -0
  667. package/src/server/direct-local-http.ts +347 -0
  668. package/src/server/effort-policy.ts +190 -0
  669. package/src/server/github-copilot-responses-repair.ts +338 -0
  670. package/src/server/gui-static.ts +152 -0
  671. package/src/server/image-retry.ts +42 -0
  672. package/src/server/images.ts +568 -0
  673. package/src/server/index.ts +1813 -0
  674. package/src/server/lifecycle.ts +498 -0
  675. package/src/server/live.ts +717 -0
  676. package/src/server/local-management-read-client.ts +90 -0
  677. package/src/server/local-provider-reload-client.ts +137 -0
  678. package/src/server/management/agent-settings-routes.ts +1433 -0
  679. package/src/server/management/api-access.ts +141 -0
  680. package/src/server/management/api-key-usage.ts +193 -0
  681. package/src/server/management/body.ts +41 -0
  682. package/src/server/management/combo-routes.ts +263 -0
  683. package/src/server/management/config-routes.ts +835 -0
  684. package/src/server/management/context.ts +113 -0
  685. package/src/server/management/integration-routes.ts +498 -0
  686. package/src/server/management/lab-automation-routes.ts +206 -0
  687. package/src/server/management/lab-routes.ts +563 -0
  688. package/src/server/management/logs-usage-routes.ts +586 -0
  689. package/src/server/management/model-routes.ts +560 -0
  690. package/src/server/management/model-rows.ts +163 -0
  691. package/src/server/management/native-integration-routes.ts +769 -0
  692. package/src/server/management/oauth-account-routes.ts +637 -0
  693. package/src/server/management/provider-capability-config.ts +48 -0
  694. package/src/server/management/provider-routes.ts +1033 -0
  695. package/src/server/management/replit-provider-routes.ts +86 -0
  696. package/src/server/management/request-history-routes.ts +191 -0
  697. package/src/server/management/routing-analytics-routes.ts +74 -0
  698. package/src/server/management/routing-profile-routes.ts +385 -0
  699. package/src/server/management/shared.ts +286 -0
  700. package/src/server/management/sidebar-routes.ts +106 -0
  701. package/src/server/management/storage-log-guard-routes.ts +186 -0
  702. package/src/server/management/sync-response.ts +69 -0
  703. package/src/server/management/system-restart.ts +435 -0
  704. package/src/server/management/system-routes.ts +194 -0
  705. package/src/server/management/usage-summary-cache.ts +94 -0
  706. package/src/server/management/vision-sidecar-options.ts +167 -0
  707. package/src/server/management/web-search-sidecar-options.ts +120 -0
  708. package/src/server/management-api.ts +314 -0
  709. package/src/server/management-auth.ts +482 -0
  710. package/src/server/memory-watchdog.ts +156 -0
  711. package/src/server/passive-route-linker.ts +66 -0
  712. package/src/server/port-reclaim.ts +307 -0
  713. package/src/server/ports.ts +156 -0
  714. package/src/server/proxy-liveness.ts +328 -0
  715. package/src/server/readiness.ts +99 -0
  716. package/src/server/relay-eager.ts +353 -0
  717. package/src/server/relay.ts +1209 -0
  718. package/src/server/request-decompress.ts +239 -0
  719. package/src/server/request-log-conversation.ts +168 -0
  720. package/src/server/request-log.ts +1259 -0
  721. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  722. package/src/server/responses/agent-task-recovery.ts +465 -0
  723. package/src/server/responses/collaboration.ts +551 -0
  724. package/src/server/responses/compact.ts +771 -0
  725. package/src/server/responses/core.ts +5389 -0
  726. package/src/server/responses/empty-completion-guard.ts +276 -0
  727. package/src/server/responses/encrypted-payload.ts +331 -0
  728. package/src/server/responses/fetch-helpers.ts +232 -0
  729. package/src/server/responses/input-admission.ts +185 -0
  730. package/src/server/responses/pacing-overload.ts +13 -0
  731. package/src/server/responses/passthrough-error.ts +78 -0
  732. package/src/server/responses/policy-fallback.ts +178 -0
  733. package/src/server/responses/responses-field-backfill.ts +251 -0
  734. package/src/server/responses/terminal-guard.ts +251 -0
  735. package/src/server/responses/upstream-error.ts +53 -0
  736. package/src/server/responses/ws-upstream.ts +308 -0
  737. package/src/server/responses-custom-tool-repair.ts +282 -0
  738. package/src/server/responses-image-gen-repair.ts +132 -0
  739. package/src/server/responses-item-id-repair.ts +272 -0
  740. package/src/server/responses-json-events.ts +90 -0
  741. package/src/server/responses-model-rewrite.ts +29 -0
  742. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  743. package/src/server/responses-snapshot-repair.ts +621 -0
  744. package/src/server/responses-terminal-repair.ts +342 -0
  745. package/src/server/responses-tool-search-repair.ts +267 -0
  746. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  747. package/src/server/responses.ts +25 -0
  748. package/src/server/search.ts +201 -0
  749. package/src/server/sse-frame-buffer.ts +292 -0
  750. package/src/server/sse-payload-rewrite.ts +263 -0
  751. package/src/server/startup-action-control.ts +315 -0
  752. package/src/server/startup-health-cache.ts +131 -0
  753. package/src/server/system-env.ts +484 -0
  754. package/src/server/windows-tcp-drop.ts +184 -0
  755. package/src/server/windows-tray-control.ts +41 -0
  756. package/src/server/ws-bridge.ts +472 -0
  757. package/src/service-manager-probe.ts +892 -0
  758. package/src/service.ts +3575 -0
  759. package/src/sidecar/auth.ts +92 -0
  760. package/src/sidecar/candidates.ts +83 -0
  761. package/src/stall-timeout.ts +20 -0
  762. package/src/storage/cleanup-job.ts +57 -0
  763. package/src/storage/cleanup.ts +3085 -0
  764. package/src/storage/policy-job.ts +457 -0
  765. package/src/storage/policy-scheduler.ts +40 -0
  766. package/src/storage/policy-worker.ts +59 -0
  767. package/src/storage/policy.ts +527 -0
  768. package/src/storage/restore-job.ts +299 -0
  769. package/src/storage/restore-worker.ts +58 -0
  770. package/src/storage/scanner.ts +238 -0
  771. package/src/storage/storage-mutation-coordinator.ts +139 -0
  772. package/src/storage/worker-lifecycle.ts +215 -0
  773. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  774. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  775. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  776. package/src/tray/assets/opencodex-tray.png +0 -0
  777. package/src/tray/windows-tray.ps1 +364 -0
  778. package/src/tray/windows.ts +757 -0
  779. package/src/types/accounts.ts +37 -0
  780. package/src/types/config.ts +876 -0
  781. package/src/types/provider.ts +545 -0
  782. package/src/types/request.ts +384 -0
  783. package/src/types/tools.ts +131 -0
  784. package/src/types/wire.ts +80 -0
  785. package/src/types.ts +106 -0
  786. package/src/update/badge.ts +72 -0
  787. package/src/update/index.ts +415 -0
  788. package/src/update/job.ts +1887 -0
  789. package/src/update/notify.ts +263 -0
  790. package/src/update/npm-cache-preflight.d.mts +47 -0
  791. package/src/update/npm-cache-preflight.mjs +201 -0
  792. package/src/update/npm-invocation.d.mts +23 -0
  793. package/src/update/npm-invocation.mjs +94 -0
  794. package/src/update/transactional-install.d.mts +22 -0
  795. package/src/update/transactional-install.mjs +259 -0
  796. package/src/update/tray-update-plan.d.mts +18 -0
  797. package/src/update/tray-update-plan.mjs +38 -0
  798. package/src/usage/cost.ts +625 -0
  799. package/src/usage/debug.ts +97 -0
  800. package/src/usage/expected-prices.ts +416 -0
  801. package/src/usage/log.ts +1223 -0
  802. package/src/usage/summary.ts +753 -0
  803. package/src/usage/totals.ts +14 -0
  804. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  805. package/src/usage/user-cost-overlays.ts +314 -0
  806. package/src/vision/anthropic-describe.ts +189 -0
  807. package/src/vision/backends.ts +97 -0
  808. package/src/vision/describe.ts +131 -0
  809. package/src/vision/eligibility.ts +250 -0
  810. package/src/vision/index.ts +681 -0
  811. package/src/vision/reasoning.ts +55 -0
  812. package/src/vision/routed-describe.ts +175 -0
  813. package/src/vision/timeout-bounds.ts +9 -0
  814. package/src/web-search/anthropic-executor.ts +195 -0
  815. package/src/web-search/backends.ts +108 -0
  816. package/src/web-search/exa-executor.ts +88 -0
  817. package/src/web-search/executor.ts +113 -0
  818. package/src/web-search/format-result.ts +89 -0
  819. package/src/web-search/gemini-executor.ts +141 -0
  820. package/src/web-search/index.ts +331 -0
  821. package/src/web-search/loop.ts +896 -0
  822. package/src/web-search/parse.ts +315 -0
  823. package/src/web-search/progress-stream.ts +342 -0
  824. package/src/web-search/sources.ts +60 -0
  825. package/src/web-search/synthetic-tool.ts +47 -0
  826. package/src/web-search/xai-executor.ts +219 -0
@@ -0,0 +1,625 @@
1
+ /**
2
+ * Cost estimation core (devlog/_plan/260720_toks_speed_price_columns/010).
3
+ *
4
+ * All prices are display-time ESTIMATES (~$), never billing reproductions:
5
+ * - cache detail comes from provider usage as-reported (no session heuristics);
6
+ * - matching is exact native provider/model ID via the jawcode alias table
7
+ * (no fuzzy, no case-fold, no resolvedModel/requestedModel fallback);
8
+ * - user-configured provider overlay wins, then jawcode nonzero price, then the expected-price overlay
9
+ * (verified / verified-derived only), otherwise null => UI shows em dash;
10
+ * - combo sums per-attempt costs and fails closed when any attempt is unpriced.
11
+ */
12
+ import {
13
+ findVendorCostByModelId,
14
+ getModelMetadata,
15
+ resolveMetadataProvider,
16
+ } from "../generated/model-metadata";
17
+ import type { AttemptTierOutcome, OcxUsage } from "../types";
18
+ import { baseProviderLabel, canonicalUsageProviderLabel } from "../providers/label";
19
+ import type { PersistedUsageAttempt, UsageStatus } from "./log";
20
+ import { canonicalAntigravityUsageModel } from "../providers/antigravity-models";
21
+ import { activeConfiguredProviders, activeUserCostOverlays, userCostOverlayVersion } from "./user-cost-overlays";
22
+ import {
23
+ EXPECTED_PRICE_OVERLAYS,
24
+ findExpectedPriceOverlay,
25
+ findVerifiedPriceOverride,
26
+ findPriorityPricingRule,
27
+ findContextTier,
28
+ isLongContext,
29
+ type Cost4,
30
+ type ExpectedPriceOverlay,
31
+ type ExpectedPriceStatus,
32
+ } from "./expected-prices";
33
+
34
+ /** Published long-context pricing band (#908). */
35
+ export type ContextTierName = "long";
36
+
37
+ /**
38
+ * Service-tier provenance. `effectiveServiceTier()` collapses these with `??`,
39
+ * but long-context exclusivity needs to know WHICH source supplied "priority":
40
+ * OpenAI does not serve long context in Fast mode, so a >272k request that was
41
+ * merely TAGGED priority was necessarily downgraded and must still be priced at
42
+ * the long rate. Only a response-confirmed Fast tier suppresses the context tier.
43
+ */
44
+ export interface ServiceTierContext {
45
+ responseServiceTier?: string;
46
+ requestedServiceTier?: string;
47
+ configuredServiceTier?: string;
48
+ tierOutcome?: AttemptTierOutcome;
49
+ }
50
+
51
+ export interface CostTokens {
52
+ input: number;
53
+ output: number;
54
+ cacheRead: number;
55
+ cacheWrite: number;
56
+ }
57
+
58
+ export interface CostBreakdown {
59
+ input: number;
60
+ output: number;
61
+ cacheRead: number;
62
+ cacheWrite: number;
63
+ total: number;
64
+ }
65
+
66
+ export interface MatchedPrice {
67
+ provider: string;
68
+ modelId: string;
69
+ jawcodeProvider?: string;
70
+ cost4: Cost4;
71
+ source: "jawcode" | "expected" | "user";
72
+ sourceRef?: string;
73
+ verifiedAt?: string;
74
+ status: "verified" | "verified-derived";
75
+ }
76
+
77
+ export interface AttemptCostEstimate {
78
+ ordinal: number;
79
+ provider: string;
80
+ model: string;
81
+ tokens: CostTokens;
82
+ price: MatchedPrice;
83
+ cost: CostBreakdown;
84
+ estimated: boolean;
85
+ /** Applied provider priority-tier multiplier (undefined or 1 = standard). */
86
+ priorityMultiplier?: number;
87
+ /** Set when the published long-context rate was applied (#908). */
88
+ contextTier?: ContextTierName;
89
+ /** The numeric estimate is a known floor because the exact Priority price is unavailable. */
90
+ priorityLowerBound?: boolean;
91
+ }
92
+
93
+ export interface CostEstimate {
94
+ tokens: CostTokens;
95
+ cost: CostBreakdown;
96
+ estimated: boolean;
97
+ attempts?: AttemptCostEstimate[];
98
+ price?: MatchedPrice;
99
+ /** Applied provider priority-tier multiplier (undefined or 1 = standard). */
100
+ priorityMultiplier?: number;
101
+ /** Set when any priced attempt used the published long-context rate (#908). */
102
+ contextTier?: ContextTierName;
103
+ /** The aggregate is a known floor because every priced attempt is a lower bound. */
104
+ priorityLowerBound?: boolean;
105
+ }
106
+
107
+ function finiteNonNegative(value: number): boolean {
108
+ return Number.isFinite(value) && value >= 0;
109
+ }
110
+
111
+ function validCost4(cost: Cost4 | undefined): cost is Cost4 {
112
+ return !!cost
113
+ && finiteNonNegative(cost.input)
114
+ && finiteNonNegative(cost.output)
115
+ && finiteNonNegative(cost.cacheRead)
116
+ && finiteNonNegative(cost.cacheWrite);
117
+ }
118
+
119
+ function hasNonZeroCost(cost: Cost4): boolean {
120
+ return cost.input !== 0 || cost.output !== 0
121
+ || cost.cacheRead !== 0 || cost.cacheWrite !== 0;
122
+ }
123
+
124
+ /**
125
+ * Normalize inclusive OcxUsage (types.ts: inputTokens INCLUDES cache read/write)
126
+ * into jawcode CostTokens (input = uncached prompt only) without double-charging.
127
+ *
128
+ * Canonical-first with a single legacy retry: the canonical contract says
129
+ * `cachedInputTokens` is read-only tokens, but legacy claude-route rows stored
130
+ * read+write combined there (devlog 070). The two shapes are indistinguishable
131
+ * by fields alone, so we apply the canonical reading first and only when it
132
+ * produces an impossible R+W>I do we retry the legacy recovery
133
+ * (cached - creation). If both readings are contradictory, fail closed (null).
134
+ */
135
+ export function normalizeCostTokens(usage: OcxUsage): CostTokens | null {
136
+ const input = usage.inputTokens;
137
+ const output = usage.outputTokens;
138
+ const cacheWrite = usage.cacheCreationInputTokens ?? 0;
139
+ const primaryRead = usage.cacheReadInputTokens ?? usage.cachedInputTokens ?? 0;
140
+ const candidates: number[] = [primaryRead];
141
+ if (typeof usage.cacheReadInputTokens !== "number"
142
+ && typeof usage.cachedInputTokens === "number"
143
+ && typeof usage.cacheCreationInputTokens === "number") {
144
+ candidates.push(Math.max(0, usage.cachedInputTokens - usage.cacheCreationInputTokens));
145
+ }
146
+ for (const cacheRead of candidates) {
147
+ if (![input, output, cacheRead, cacheWrite].every(finiteNonNegative)) return null;
148
+ if (cacheRead + cacheWrite > input) continue;
149
+ return {
150
+ input: Math.max(0, input - cacheRead - cacheWrite),
151
+ output,
152
+ cacheRead,
153
+ cacheWrite,
154
+ };
155
+ }
156
+ return null;
157
+ }
158
+
159
+ /** jawcode unit convention: USD per 1M tokens (jawcode stats/db.ts calculateCatalogCost). */
160
+ export function calculateCost(tokens: CostTokens, cost4: Cost4): CostBreakdown {
161
+ const input = cost4.input * tokens.input / 1_000_000;
162
+ const output = cost4.output * tokens.output / 1_000_000;
163
+ const cacheRead = cost4.cacheRead * tokens.cacheRead / 1_000_000;
164
+ const cacheWrite = cost4.cacheWrite * tokens.cacheWrite / 1_000_000;
165
+ return { input, output, cacheRead, cacheWrite, total: input + output + cacheRead + cacheWrite };
166
+ }
167
+
168
+ /**
169
+ * Fixed priority: user-configured provider overlay -> jawcode exact (provider
170
+ * bundle) nonzero -> overlay verified -> overlay verified-derived -> jawcode
171
+ * model-level vendor price (cross-provider fallback: a model follows its official
172
+ * vendor price — WP5 policy, e.g. kiro/claude-opus-4-6 uses the anthropic price)
173
+ * -> null. All-zero rows are overlay candidates (zero is "not billable here",
174
+ * not "free").
175
+ */
176
+ export function resolveMatchedPrice(
177
+ provider: string,
178
+ modelId: string,
179
+ overlays: readonly ExpectedPriceOverlay[] = EXPECTED_PRICE_OVERLAYS,
180
+ userOverlays: readonly ExpectedPriceOverlay[] = activeUserCostOverlays(),
181
+ ): MatchedPrice | null {
182
+ // User-configured overlays are keyed by the EXACT configured provider name.
183
+ // A provider that literally exists in config.providers keeps its own pricing
184
+ // namespace: a real custom provider can legitimately end with a label-shaped
185
+ // suffix (e.g. acme-pabcdef) and must not inherit the base provider's user
186
+ // overlay. Only NON-configured names (generated account log labels) collapse
187
+ // to their label base. chatgpt/openai-multi are the same OpenAI usage surface
188
+ // and always canonicalize to openai.
189
+ const collapsed = baseProviderLabel(provider);
190
+ if (collapsed !== provider && (canonicalUsageProviderLabel(provider) !== provider || !activeConfiguredProviders().has(provider))) {
191
+ const exactUserOverlay = userOverlayMatch(provider, modelId, userOverlays);
192
+ if (exactUserOverlay) return exactUserOverlay;
193
+ // Pool/account log suffixes (e.g. google-antigravity-p442fff) must collapse
194
+ // before the compiled/overlay lookup; configured providers keep their own
195
+ // namespace above.
196
+ provider = collapsed;
197
+ }
198
+ // Memoize by (provider, model): usage summaries iterate hundreds of thousands of
199
+ // rows that share a handful of provider/model keys, so resolving each time would
200
+ // dominate /api/usage latency (WP6 audit). The compiled overlays are static;
201
+ // user overlays get a NEW array identity + version bump on every config refresh,
202
+ // so memoized rows never go stale.
203
+ if (overlays === EXPECTED_PRICE_OVERLAYS && userOverlays === activeUserCostOverlays()) {
204
+ const cacheKey = `${userCostOverlayVersion()} ${provider} ${modelId}`;
205
+ if (!priceMemo.has(cacheKey)) {
206
+ if (priceMemo.size >= 512) priceMemo.clear();
207
+ priceMemo.set(cacheKey, resolveMatchedPriceInner(provider, modelId, overlays, userOverlays));
208
+ }
209
+ return priceMemo.get(cacheKey)!;
210
+ }
211
+ return resolveMatchedPriceInner(provider, modelId, overlays, userOverlays);
212
+ }
213
+
214
+ const priceMemo = new Map<string, MatchedPrice | null>();
215
+
216
+ /**
217
+ * Resolution wrapper: exact provider/model lookup first, then the Antigravity
218
+ * base-model fallback for collapsed wire ids. Never falls through to the
219
+ * cross-provider vendor price at this level.
220
+ */
221
+ function resolveMatchedPriceInner(
222
+ provider: string,
223
+ modelId: string,
224
+ overlays: readonly ExpectedPriceOverlay[],
225
+ userOverlays: readonly ExpectedPriceOverlay[],
226
+ ): MatchedPrice | null {
227
+ const direct = resolveMatchedPriceExact(provider, modelId, overlays, userOverlays);
228
+ if (direct) return direct;
229
+ // Antigravity historical/wire ids often lack an exact overlay; fall back to the
230
+ // picker/call base model so collapsed usage rows still get a price.
231
+ if (provider === "google-antigravity" || provider.startsWith("google-antigravity")) {
232
+ const base = canonicalAntigravityUsageModel(modelId);
233
+ if (base !== modelId) return resolveMatchedPriceExact(provider, base, overlays, userOverlays);
234
+ }
235
+ return null;
236
+ }
237
+
238
+ /**
239
+ * Exact provider/model price lookup: user-configured `modelCosts` first, then
240
+ * an exact official correction, the jawcode provider bundle, the expected-price overlay, then the
241
+ * model-level vendor fallback. All-zero rows fall through ("not billable").
242
+ */
243
+ function resolveMatchedPriceExact(
244
+ provider: string,
245
+ modelId: string,
246
+ overlays: readonly ExpectedPriceOverlay[],
247
+ userOverlays: readonly ExpectedPriceOverlay[],
248
+ ): MatchedPrice | null {
249
+ // User-configured provider overlay wins over every compiled catalog: the
250
+ // operator's explicit price is authoritative for the ~$ estimate.
251
+ const userOverlay = userOverlayMatch(provider, modelId, userOverlays);
252
+ if (userOverlay) return userOverlay;
253
+ const verifiedOverride = overlays === EXPECTED_PRICE_OVERLAYS
254
+ ? findVerifiedPriceOverride(provider, modelId)
255
+ : undefined;
256
+ if (verifiedOverride && validCost4(verifiedOverride.cost4) && hasNonZeroCost(verifiedOverride.cost4)) {
257
+ return {
258
+ provider,
259
+ modelId,
260
+ cost4: verifiedOverride.cost4,
261
+ source: "expected",
262
+ sourceRef: verifiedOverride.source,
263
+ verifiedAt: verifiedOverride.verifiedAt,
264
+ status: "verified",
265
+ };
266
+ }
267
+ const metadataProvider = resolveMetadataProvider(provider);
268
+ const bundled = metadataProvider
269
+ ? getModelMetadata(metadataProvider, modelId)
270
+ : undefined;
271
+ if (bundled?.cost && validCost4(bundled.cost) && hasNonZeroCost(bundled.cost)) {
272
+ return {
273
+ provider,
274
+ modelId,
275
+ jawcodeProvider: metadataProvider,
276
+ cost4: bundled.cost,
277
+ source: "jawcode",
278
+ status: "verified",
279
+ };
280
+ }
281
+ const overlay = findExpectedPriceOverlay(provider, modelId, overlays);
282
+ if (!overlay || !validCost4(overlay.cost4) || !hasNonZeroCost(overlay.cost4)) {
283
+ return resolveModelLevelPrice(provider, modelId);
284
+ }
285
+ if (overlay.status === "unverified") return null;
286
+ return {
287
+ provider,
288
+ modelId,
289
+ ...(metadataProvider ? { jawcodeProvider: metadataProvider } : {}),
290
+ cost4: overlay.cost4,
291
+ source: "expected",
292
+ sourceRef: overlay.source,
293
+ verifiedAt: overlay.verifiedAt,
294
+ status: overlay.status,
295
+ };
296
+ }
297
+
298
+ /** User-configured overlay match (all-zero rows fall through like any other source). */
299
+ function userOverlayMatch(
300
+ provider: string,
301
+ modelId: string,
302
+ userOverlays: readonly ExpectedPriceOverlay[],
303
+ ): MatchedPrice | null {
304
+ const overlay = findExpectedPriceOverlay(provider, modelId, userOverlays);
305
+ if (!overlay || !validCost4(overlay.cost4) || !hasNonZeroCost(overlay.cost4)) return null;
306
+ return {
307
+ provider,
308
+ modelId,
309
+ cost4: overlay.cost4,
310
+ source: "user",
311
+ sourceRef: overlay.source,
312
+ verifiedAt: overlay.verifiedAt,
313
+ status: "verified",
314
+ };
315
+ }
316
+
317
+ function resolveModelLevelPrice(provider: string, modelId: string): MatchedPrice | null {
318
+ // Exact first; then dot->dash variant for providers that spell vendor ids with
319
+ // dots where the catalog uses dashes (kiro "claude-opus-4.6" vs anthropic
320
+ // "claude-opus-4-6"). No fuzzy matching beyond this one normalization.
321
+ const found = findVendorCostByModelId(modelId)
322
+ ?? (modelId.includes(".") ? findVendorCostByModelId(modelId.replaceAll(".", "-")) : undefined);
323
+ if (!found) return null;
324
+ return {
325
+ provider,
326
+ modelId,
327
+ jawcodeProvider: found.provider,
328
+ cost4: found.cost,
329
+ source: "jawcode",
330
+ status: "verified-derived",
331
+ };
332
+ }
333
+
334
+ function isEstimated(usage: OcxUsage, usageStatus: UsageStatus, priceStatus: ExpectedPriceStatus | "verified"): boolean {
335
+ return usage.estimated === true || usageStatus === "estimated" || priceStatus === "verified-derived";
336
+ }
337
+
338
+ /**
339
+ * Resolve the effective service tier from persisted log fields.
340
+ * Priority: responseServiceTier (server-confirmed) > requestedServiceTier
341
+ * (client-sent, pre-rewrite) > configuredServiceTier (config.fastMode injection).
342
+ */
343
+ export function effectiveServiceTier(entry: {
344
+ responseServiceTier?: string;
345
+ requestedServiceTier?: string;
346
+ configuredServiceTier?: string;
347
+ }): string | undefined {
348
+ return entry.responseServiceTier ?? entry.requestedServiceTier ?? entry.configuredServiceTier;
349
+ }
350
+
351
+ /**
352
+ * Accepts either the collapsed tier scalar or the full provenance record.
353
+ * A bare string carries no provenance, so it cannot confirm Fast: callers that
354
+ * need long-context exclusivity to be correct must pass the record.
355
+ */
356
+ export type ServiceTierInput = string | ServiceTierContext;
357
+
358
+ /**
359
+ * Narrow a persisted log entry to just its tier provenance. Prefer this over
360
+ * `effectiveServiceTier()` at estimator call sites: the collapsed scalar cannot
361
+ * distinguish a response-confirmed Fast request from a merely requested one,
362
+ * and long-context exclusivity depends on that distinction.
363
+ */
364
+ export function serviceTierContext(entry: ServiceTierContext): ServiceTierContext {
365
+ if (entry.tierOutcome) {
366
+ return { ...serviceTierContextFromOutcome(entry.tierOutcome), tierOutcome: entry.tierOutcome };
367
+ }
368
+ return {
369
+ responseServiceTier: entry.responseServiceTier,
370
+ requestedServiceTier: entry.requestedServiceTier,
371
+ configuredServiceTier: entry.configuredServiceTier,
372
+ };
373
+ }
374
+
375
+ /** Convert one adapter-observed attempt outcome into the existing pricing provenance shape. */
376
+ export function serviceTierContextFromOutcome(outcome: AttemptTierOutcome): ServiceTierContext {
377
+ if (outcome.canonical === "priority" && outcome.confirmation === "confirmed") {
378
+ return { responseServiceTier: "priority" };
379
+ }
380
+ if (outcome.responseServiceTier !== undefined) {
381
+ return { responseServiceTier: outcome.responseServiceTier };
382
+ }
383
+ if (outcome.canonical === "priority" && outcome.confirmation === "assumed") {
384
+ return { requestedServiceTier: "priority" };
385
+ }
386
+ // An unclassified route makes no canonical Fast claim, but its adapter can still prove that
387
+ // it serialized a caller tier. Preserve that wire evidence instead of discarding the legacy
388
+ // top-level pricing signal merely because B0 added an outcome row.
389
+ if (
390
+ outcome.fastOutcome === "unknown"
391
+ && outcome.wireKind === "service-tier"
392
+ && typeof outcome.wireValue === "string"
393
+ ) {
394
+ return { requestedServiceTier: outcome.wireValue };
395
+ }
396
+ return {};
397
+ }
398
+
399
+ function tierScalar(tier?: ServiceTierInput): string | undefined {
400
+ return typeof tier === "string" ? tier : tier && effectiveServiceTier(tier);
401
+ }
402
+
403
+ /** True only when the UPSTREAM RESPONSE confirmed the Fast tier (see ServiceTierContext). */
404
+ function isConfirmedFast(tier?: ServiceTierInput): boolean {
405
+ return typeof tier === "object" && tier.responseServiceTier === "priority";
406
+ }
407
+
408
+ /**
409
+ * Apply the published long-context rate when raw prompt size crosses the vendor
410
+ * threshold. Returns [effectiveCost4, tierName].
411
+ *
412
+ * `rawInputTokens` MUST be `usage.inputTokens` (total prompt size), never the
413
+ * normalized billable input — normalization subtracts cache read/write, so a
414
+ * cache-heavy long prompt would fall below the boundary and under-bill.
415
+ *
416
+ * A provider's declaration decides how a response-confirmed priority tier relates to this band.
417
+ * OpenAI declares the bands exclusive. xAI publishes neither a combined rate nor an exclusion,
418
+ * so its long-context rate remains the known lower bound instead of inventing a stacked multiplier.
419
+ */
420
+ function applyContextTier(
421
+ cost4: Cost4,
422
+ provider: string,
423
+ modelId: string,
424
+ rawInputTokens: number | undefined,
425
+ tier?: ServiceTierInput,
426
+ ): [Cost4, ContextTierName | undefined, boolean] {
427
+ if (rawInputTokens === undefined) return [cost4, undefined, false];
428
+ const rule = findContextTier(baseProviderLabel(provider), modelId);
429
+ if (!rule || !isLongContext(rule, rawInputTokens)) return [cost4, undefined, false];
430
+ const confirmedFast = isConfirmedFast(tier);
431
+ if (confirmedFast && rule.confirmedPriorityRelation === "exclusive") {
432
+ return [cost4, undefined, false];
433
+ }
434
+ return [{
435
+ input: cost4.input * rule.multiplier.input,
436
+ output: cost4.output * rule.multiplier.output,
437
+ cacheRead: cost4.cacheRead * rule.multiplier.cacheRead,
438
+ cacheWrite: cost4.cacheWrite * rule.multiplier.cacheWrite,
439
+ }, "long", confirmedFast && rule.confirmedPriorityRelation === "lower-bound"];
440
+ }
441
+
442
+ /**
443
+ * Apply a declared provider/model priority-tier multiplier to a Cost4 when applicable.
444
+ * Returns [effectiveCost4, multiplier]. Multiplier is 1 (no-op) when:
445
+ * - serviceTier is not "priority"
446
+ * - no exact provider/model rule exists
447
+ */
448
+ function applyPriorityMultiplier(
449
+ cost4: Cost4,
450
+ provider: string,
451
+ modelId: string,
452
+ serviceTier?: ServiceTierInput,
453
+ ): [Cost4, number] {
454
+ if (tierScalar(serviceTier) !== "priority") return [cost4, 1];
455
+ const base = baseProviderLabel(provider);
456
+ const rule = findPriorityPricingRule(base, modelId);
457
+ if (rule?.requiresResponseConfirmation && !isConfirmedFast(serviceTier)) return [cost4, 1];
458
+ const multiplier = rule?.multiplier ?? 1;
459
+ if (multiplier === 1) return [cost4, 1];
460
+ return [{
461
+ input: cost4.input * multiplier,
462
+ output: cost4.output * multiplier,
463
+ cacheRead: cost4.cacheRead * multiplier,
464
+ cacheWrite: cost4.cacheWrite * multiplier,
465
+ }, multiplier];
466
+ }
467
+
468
+ /**
469
+ * OpenRouter confirms the actual endpoint tier and documents priority as higher cost, but this
470
+ * branch does not bundle its provider-specific priority endpoint prices. A confirmed canonical
471
+ * priority result can therefore use the standard price only as a provable lower bound. Do not
472
+ * extend this to flex (cheaper) or to other providers without the same pricing contract.
473
+ *
474
+ * An ASSUMED priority attempt needs the same marker for a different reason. There the provider
475
+ * never echoed a tier at all, so the standard price is not merely a lower bound on a known
476
+ * premium — it is a floor under an outcome we did not observe. Returning it unmarked reports a
477
+ * definite standard cost for a request that may well have been billed as priority, which is the
478
+ * one thing a cost estimate must never do.
479
+ */
480
+ function isOpenRouterPriorityLowerBound(
481
+ provider: string,
482
+ outcome: AttemptTierOutcome | undefined,
483
+ ): boolean {
484
+ return baseProviderLabel(provider) === "openrouter"
485
+ && outcome?.canonical === "priority"
486
+ && outcome.fastOutcome === "applied"
487
+ && (outcome.confirmation === "confirmed" || outcome.confirmation === "assumed");
488
+ }
489
+
490
+ /**
491
+ * Per-attempt cost estimate: tokens normalized, price resolved (user overlay →
492
+ * catalogs), priority/long-context tiers applied. Null when usage or price is
493
+ * missing so combos can fail closed.
494
+ */
495
+ export function estimateAttemptCost(
496
+ attempt: Pick<PersistedUsageAttempt, "ordinal" | "provider" | "model" | "usage" | "usageStatus" | "tierOutcome">,
497
+ overlays: readonly ExpectedPriceOverlay[] = EXPECTED_PRICE_OVERLAYS,
498
+ serviceTier?: ServiceTierInput,
499
+ userOverlays: readonly ExpectedPriceOverlay[] = activeUserCostOverlays(),
500
+ ): AttemptCostEstimate | null {
501
+ if (!attempt.usage) return null;
502
+ const tokens = normalizeCostTokens(attempt.usage);
503
+ if (!tokens) return null;
504
+ const price = resolveMatchedPrice(attempt.provider, attempt.model, overlays, userOverlays);
505
+ if (!price) return null;
506
+ const attemptServiceTier = attempt.tierOutcome
507
+ ? serviceTierContextFromOutcome(attempt.tierOutcome)
508
+ : serviceTier;
509
+ const [tieredCost4, contextTier, contextPriorityLowerBound] = applyContextTier(
510
+ price.cost4, attempt.provider, attempt.model, attempt.usage.inputTokens, attemptServiceTier,
511
+ );
512
+ // A published long-context row owns the numeric estimate. OpenAI declares that band
513
+ // exclusive with Fast; xAI's confirmed combination is deliberately left unmultiplied
514
+ // and marked as a lower bound because no combined price has been published.
515
+ const [effectiveCost4, multiplier] = contextTier
516
+ ? [tieredCost4, 1] as const
517
+ : applyPriorityMultiplier(tieredCost4, attempt.provider, attempt.model, attemptServiceTier);
518
+ const priorityLowerBound = contextPriorityLowerBound
519
+ || isOpenRouterPriorityLowerBound(attempt.provider, attempt.tierOutcome);
520
+ return {
521
+ ordinal: attempt.ordinal,
522
+ provider: attempt.provider,
523
+ model: attempt.model,
524
+ tokens,
525
+ price,
526
+ cost: calculateCost(tokens, effectiveCost4),
527
+ estimated: isEstimated(attempt.usage, attempt.usageStatus, price.status),
528
+ ...(multiplier !== 1 ? { priorityMultiplier: multiplier } : {}),
529
+ ...(contextTier ? { contextTier } : {}),
530
+ ...(priorityLowerBound ? { priorityLowerBound: true } : {}),
531
+ };
532
+ }
533
+
534
+ /**
535
+ * Combo: price every attempt with its own rate and sum. Fail closed — if ANY
536
+ * attempt is unpriced or unnormalizable, return null rather than a partial sum.
537
+ */
538
+ export function estimateComboCost(
539
+ attempts: readonly Pick<PersistedUsageAttempt, "ordinal" | "provider" | "model" | "usage" | "usageStatus" | "tierOutcome">[],
540
+ overlays: readonly ExpectedPriceOverlay[] = EXPECTED_PRICE_OVERLAYS,
541
+ serviceTier?: ServiceTierInput,
542
+ userOverlays: readonly ExpectedPriceOverlay[] = activeUserCostOverlays(),
543
+ ): CostEstimate | null {
544
+ if (attempts.length === 0) return null;
545
+ const estimates: AttemptCostEstimate[] = [];
546
+ for (const attempt of attempts) {
547
+ const estimate = estimateAttemptCost(attempt, overlays, serviceTier, userOverlays);
548
+ if (!estimate) return null;
549
+ estimates.push(estimate);
550
+ }
551
+ const tokens: CostTokens = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
552
+ const cost: CostBreakdown = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 };
553
+ for (const est of estimates) {
554
+ tokens.input += est.tokens.input;
555
+ tokens.output += est.tokens.output;
556
+ tokens.cacheRead += est.tokens.cacheRead;
557
+ tokens.cacheWrite += est.tokens.cacheWrite;
558
+ cost.input += est.cost.input;
559
+ cost.output += est.cost.output;
560
+ cost.cacheRead += est.cost.cacheRead;
561
+ cost.cacheWrite += est.cost.cacheWrite;
562
+ cost.total += est.cost.total;
563
+ }
564
+ return {
565
+ tokens,
566
+ cost,
567
+ estimated: estimates.some(est => est.estimated),
568
+ attempts: estimates,
569
+ ...(estimates.some(est => est.priorityMultiplier && est.priorityMultiplier !== 1)
570
+ ? { priorityMultiplier: estimates.find(est => est.priorityMultiplier)?.priorityMultiplier }
571
+ : {}),
572
+ ...(estimates.some(est => est.contextTier) ? { contextTier: "long" as const } : {}),
573
+ ...(estimates.every(est => est.priorityLowerBound === true)
574
+ ? { priorityLowerBound: true as const }
575
+ : {}),
576
+ };
577
+ }
578
+
579
+ /** Single-target request cost estimate (non-combo). */
580
+ export function estimateRequestCost(
581
+ input: {
582
+ provider: string;
583
+ model: string;
584
+ usage?: OcxUsage;
585
+ usageStatus: UsageStatus;
586
+ serviceTier?: ServiceTierInput;
587
+ },
588
+ overlays: readonly ExpectedPriceOverlay[] = EXPECTED_PRICE_OVERLAYS,
589
+ userOverlays: readonly ExpectedPriceOverlay[] = activeUserCostOverlays(),
590
+ ): CostEstimate | null {
591
+ if (!input.usage) return null;
592
+ const tokens = normalizeCostTokens(input.usage);
593
+ if (!tokens) return null;
594
+ const price = resolveMatchedPrice(input.provider, input.model, overlays, userOverlays);
595
+ if (!price) return null;
596
+ const [tieredCost4, contextTier, contextPriorityLowerBound] = applyContextTier(
597
+ price.cost4, input.provider, input.model, input.usage.inputTokens, input.serviceTier,
598
+ );
599
+ const [effectiveCost4, multiplier] = contextTier
600
+ ? [tieredCost4, 1] as const
601
+ : applyPriorityMultiplier(tieredCost4, input.provider, input.model, input.serviceTier);
602
+ const priorityLowerBound = contextPriorityLowerBound || isOpenRouterPriorityLowerBound(
603
+ input.provider,
604
+ typeof input.serviceTier === "object" ? input.serviceTier.tierOutcome : undefined,
605
+ );
606
+ return {
607
+ tokens,
608
+ price,
609
+ cost: calculateCost(tokens, effectiveCost4),
610
+ estimated: isEstimated(input.usage, input.usageStatus, price.status),
611
+ ...(multiplier !== 1 ? { priorityMultiplier: multiplier } : {}),
612
+ ...(contextTier ? { contextTier } : {}),
613
+ ...(priorityLowerBound ? { priorityLowerBound: true } : {}),
614
+ };
615
+ }
616
+
617
+ /**
618
+ * End-to-end output rate: outputTokens / wall-clock seconds (jawcode/OpenRouter
619
+ * convention — TTFT is NOT subtracted; it is a separate metric, WP4).
620
+ */
621
+ export function tokensPerSecond(outputTokens: number, durationMs: number): number | null {
622
+ if (!finiteNonNegative(outputTokens) || !finiteNonNegative(durationMs)) return null;
623
+ if (outputTokens <= 0 || durationMs <= 0) return null;
624
+ return outputTokens / (durationMs / 1_000);
625
+ }