@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
@@ -1,7 +1,7 @@
1
1
  import { decodeEventStream } from "../lib/eventstream-decoder";
2
2
  import { estimateTokens } from "../lib/token-estimate";
3
3
  import { debugProviderDiagnostic } from "../lib/debug";
4
- import { resolveKiroApiRegion, resolveKiroProfileArn } from "../oauth/kiro";
4
+ import { resolveKiroApiRegion, resolveKiroRequestProfile } from "../oauth/kiro";
5
5
  import { KIRO_MODEL_CONTEXT_WINDOWS, normalizeKiroModelId } from "../providers/kiro-models";
6
6
  import { modelRecordValue } from "../reasoning-effort";
7
7
  import { parseKiroEvent } from "./kiro-events";
@@ -19,6 +19,8 @@ import { createKiroToolNameRegistry, fallbackToolUseId, fingerprint, invocationI
19
19
  import { namespacedToolName } from "../types";
20
20
  import {
21
21
  isTranslatorBudgetExceededError,
22
+ releaseTranslatedEvent,
23
+ retainTranslatedEvent,
22
24
  type TranslatorBudget,
23
25
  } from "../lib/translator-budget";
24
26
  import type {
@@ -31,17 +33,21 @@ import type {
31
33
  OcxTextContent,
32
34
  OcxToolCall,
33
35
  OcxToolResultMessage,
36
+ OcxTool,
34
37
  OcxUsage,
35
38
  } from "../types";
39
+ import { hasRecordedTrailingDeliveredFinalAnswer } from "../responses/turn-termination";
36
40
  import type { ProviderAdapter } from "./base";
37
41
  import type { AdapterFetchContext, AdapterRequest } from "./base";
38
42
  import { extractKiroImages, normalizeKiroImages, type KiroImage } from "./kiro-images";
39
43
  import { sniffImageDimensions } from "./anthropic-image-guard";
40
44
  import { fetchKiroWithRetry, noteKiroTransientThrottle } from "./kiro-retry";
41
45
  import { convertKiroToolContext } from "./kiro-tools";
42
- import { neutralizeIdentity } from "./identity";
43
- import { buildNonOpenAIToolCatalogNudgeFromNames } from "./tool-catalog-nudge";
46
+ import { normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize";
47
+ import { identifyRoutedModel } from "./identity";
48
+ import { buildNonOpenAIToolCatalogNudgeFromNames, isBareShellBridgeTool, isCodexCodeModeExecTool } from "./tool-catalog-nudge";
44
49
  import {
50
+ KIRO_ANSWER_DELIVERED_MESSAGE,
45
51
  KIRO_COMPLETION_INSTRUCTIONS,
46
52
  KIRO_COMPLETION_RETRY_MESSAGE,
47
53
  KIRO_COMPLETION_TOOL_NAME,
@@ -99,7 +105,11 @@ interface KiroUserInputMessage {
99
105
  }
100
106
  interface KiroHistoryEntry {
101
107
  userInputMessage?: KiroUserInputMessage;
102
- assistantResponseMessage?: { content: string; toolUses?: KiroToolUse[] };
108
+ assistantResponseMessage?: {
109
+ content: string;
110
+ toolUses?: KiroToolUse[];
111
+ reasoningContent?: { redactedContent: string };
112
+ };
103
113
  }
104
114
 
105
115
  function kiroToolWireNames(tools: readonly unknown[]): string[] {
@@ -312,21 +322,78 @@ function validateKiroCapabilities(parsed: OcxParsedRequest): void {
312
322
  if (choice !== undefined && choice !== "auto" && choice !== "none") {
313
323
  throw new Error("Kiro supports only automatic tool choice or tool_choice:none");
314
324
  }
315
- if (parsed.options.parallelToolCalls === true) {
316
- throw new Error("Kiro does not support parallel tool calls");
317
- }
318
325
  if (parsed.options.serviceTier !== undefined) {
319
326
  throw new Error("Kiro does not support service tiers");
320
327
  }
321
- const raw = parsed._rawBody as Record<string, unknown> | undefined;
322
- if (parsed._structuredOutput || raw?.text !== undefined) {
323
- throw new Error("Kiro does not support Responses text controls or structured output");
328
+ // Structured output is a real contract Kiro cannot honour: the wire has no
329
+ // schema-constrained response mode, so a caller expecting parseable JSON would receive
330
+ // prose and fail downstream. Refuse it.
331
+ //
332
+ // The rest of the Responses `text` object is not that. `text.verbosity` is a length
333
+ // preference and `text.format: {type:"text"}` is ordinary prose — the default output
334
+ // mode, which no capability flag governs and every correct client may send. Testing
335
+ // `_rawBody.text !== undefined` refused those turns for the mere PRESENCE of the key,
336
+ // the same mistake db040e70f removed one condition earlier where a permissive
337
+ // `parallel_tool_calls` hint was read as a requirement.
338
+ //
339
+ // Nothing needs stripping the way openai-responses strips a no-op verbosity:
340
+ // buildKiroPayload composes conversationState field by field from `parsed` and never
341
+ // spreads `_rawBody`, so a tolerated control is dropped by construction. The test
342
+ // asserts that absence so it stays true.
343
+ if (parsed._structuredOutput) {
344
+ throw new Error("Kiro does not support Responses structured output");
324
345
  }
325
346
  }
326
347
 
327
348
  type KiroTurn =
328
- | { kind: "user"; content: string; images: KiroImage[]; toolResults: KiroToolResult[] }
329
- | { kind: "assistant"; content: string; toolUses: KiroToolUse[] };
349
+ | {
350
+ kind: "user";
351
+ content: string;
352
+ images: KiroImage[];
353
+ toolResults: KiroToolResult[];
354
+ /**
355
+ * True only for the proxy-generated acknowledgement that follows a delivered final answer.
356
+ * A flag rather than a content comparison: a real user message may legitimately quote the
357
+ * same sentence, and treating that as internal state would strip its thinking tags and
358
+ * completion retry.
359
+ */
360
+ answerDeliveredAck?: boolean;
361
+ }
362
+ | {
363
+ kind: "assistant";
364
+ content: string;
365
+ toolUses: KiroToolUse[];
366
+ redactedReasoning?: string;
367
+ /**
368
+ * True when this assistant turn was the DELIVERED final answer (Responses
369
+ * `phase: "final_answer"`). A trailing assistant turn normally means the model stopped
370
+ * mid-task and needs a continuation prompt, but a delivered final answer already ended its
371
+ * turn — prompting it again restarts finished work as if a goal were still open.
372
+ */
373
+ finalAnswer?: boolean;
374
+ };
375
+
376
+ /**
377
+ * True when the LAST content-bearing message is an assistant final answer that closed its turn.
378
+ *
379
+ * Mirrors the turn-merge rule: a tool call in that message, or any later user/tool-result message,
380
+ * means work continued, so the turn is no longer terminal. Empty assistant messages are skipped
381
+ * rather than treated as continuation, since they carry no visible turn.
382
+ */
383
+ function hasTrailingDeliveredFinalAnswer(messages: readonly OcxMessage[], parsed?: OcxParsedRequest): boolean {
384
+ for (let i = messages.length - 1; i >= 0; i--) {
385
+ const msg = messages[i];
386
+ if (msg.role !== "assistant") return false;
387
+ const aMsg = msg as OcxAssistantMessage;
388
+ const hasToolCall = (aMsg.content ?? []).some(part => part.type === "toolCall");
389
+ if (hasToolCall) return false;
390
+ const hasText = (aMsg.content ?? []).some(part => part.type === "text" && part.text.trim());
391
+ if (!hasText) continue;
392
+ return aMsg.phase === "final_answer"
393
+ || (parsed !== undefined && hasRecordedTrailingDeliveredFinalAnswer(parsed, messages));
394
+ }
395
+ return false;
396
+ }
330
397
 
331
398
  function appendTurnText(target: string, next: string): string {
332
399
  if (!next) return target;
@@ -381,9 +448,21 @@ function validateKiroConversationState(history: KiroHistoryEntry[], currentMessa
381
448
  function boundedInjectedInstruction(text: string, used: { value: number }): string | undefined {
382
449
  const remaining = MAX_KIRO_INJECTED_INSTRUCTION_CHARS - used.value;
383
450
  if (remaining <= 0 || !text) return undefined;
384
- const result = text.length <= remaining ? text : text.slice(0, remaining);
451
+ let result = text.length <= remaining ? text : text.slice(0, remaining);
452
+ // Never end the slice on a lone high surrogate: encoding it substitutes
453
+ // U+FFFD into the injected instruction. One step back keeps a valid pair
454
+ // out instead of a broken half.
455
+ if (result.length > 0) {
456
+ const last = result.charCodeAt(result.length - 1);
457
+ if (last >= 0xd800 && last <= 0xdbff) result = result.slice(0, -1);
458
+ }
385
459
  used.value += result.length;
386
- return result;
460
+ return result.length > 0 ? result : undefined;
461
+ }
462
+
463
+ /** Test-only: exercise the surrogate-safe instruction bound directly. */
464
+ export function boundedInjectedInstructionForTests(text: string, used: { value: number }): string | undefined {
465
+ return boundedInjectedInstruction(text, used);
387
466
  }
388
467
 
389
468
  function kiroCompletionTool(): Record<string, unknown> {
@@ -423,22 +502,66 @@ export function buildKiroPayload(
423
502
  const registry = createKiroToolNameRegistry();
424
503
  const toolContext = convertKiroToolContext(parsed, registry);
425
504
  const ordinaryTools = toolContext.tools;
505
+ // A turn whose history already ENDS with a delivered final answer has nothing to complete.
506
+ // Leaving completion "required" here would keep advertising codex_kiro_final_answer with its
507
+ // instructions, so the model answers again, or replies with ordinary text and trips the
508
+ // `needsFallback` retry, which ends its payload with KIRO_COMPLETION_RETRY_MESSAGE and reopens
509
+ // the finished task. Suppressing the mode is what actually closes that loop; the neutral
510
+ // acknowledgement below only stops the resume wording.
511
+ //
512
+ // Read from parsed messages because `completionMode` is needed to build the tool catalog, which
513
+ // happens before the turn list exists. `forcedCompletionMode` still wins: the fallback retry
514
+ // passes "text_fallback" explicitly and must not be silently downgraded.
515
+ const trailingDeliveredAnswer = hasTrailingDeliveredFinalAnswer(kiroPayloadMessages(parsed), parsed);
426
516
  const completionMode: KiroCompletionMode = forcedCompletionMode
427
- ?? (ordinaryTools.length > 0 ? "required" : "disabled");
517
+ ?? (ordinaryTools.length > 0 && !trailingDeliveredAnswer ? "required" : "disabled");
428
518
  const kiroTools = completionMode === "disabled"
429
519
  ? ordinaryTools
430
520
  : [...ordinaryTools, kiroCompletionTool()];
431
521
  const nameMap = toolContext.nameMap;
432
522
  const systemParts: string[] = [];
433
523
  const injectedChars = { value: 0 };
434
- // Neutralize Codex's GPT-5 identity line so a routed Kiro model never misreports as GPT-5/OpenAI
435
- // and the proxy identity never leaks upstream.
436
- if (parsed.context.systemPrompt?.length) systemParts.push(neutralizeIdentity(parsed.context.systemPrompt.join("\n\n")));
524
+ // Name the Kiro model id actually sent on the wire without leaking the proxy identity upstream.
525
+ if (parsed.context.systemPrompt?.length) {
526
+ systemParts.push(identifyRoutedModel(parsed.context.systemPrompt.join("\n\n"), modelId));
527
+ }
437
528
  for (const addition of toolContext.systemAdditions) {
438
529
  const boundedAddition = boundedInjectedInstruction(addition, injectedChars);
439
530
  if (boundedAddition) systemParts.push(boundedAddition);
440
531
  }
441
- const toolCatalogNudge = buildNonOpenAIToolCatalogNudgeFromNames(kiroToolWireNames(kiroTools));
532
+ // Kiro renames tools to satisfy its wire constraints, so resolve neighbor names through the
533
+ // registry's existing aliases; a bare-name comparison would forbid tools this turn actually
534
+ // advertises. Read the recorded mapping instead of calling `alias()`, which would REGISTER a
535
+ // name for a tool that was never advertised and pollute the collision domain.
536
+ const advertisedAlias = new Map<string, string>();
537
+ for (const [alias, wireName] of registry.nameMap) advertisedAlias.set(wireName, alias);
538
+ // Code mode is decided on the EMITTED catalog, not the requested list.
539
+ //
540
+ // `freeform` only exists on the requested tool objects -- `kiroToolWireNames` has already
541
+ // reduced the emitted catalog to strings -- so the predicates must read the objects. But the
542
+ // SHAPE that matters is the one the model receives: the count/byte budget can drop a requested
543
+ // `exec_command` while `exec` survives, and scanning the requested list would then find a shell
544
+ // bridge the model cannot call and suppress code mode for a catalog that is code-mode-shaped.
545
+ // Intersecting the two keeps `tool_choice: "none"` and budget omission correct for free: both
546
+ // empty the emitted set, so nothing can be named.
547
+ const emittedToolNames = new Set(kiroToolWireNames(kiroTools));
548
+ const emittedAlias = (tool: OcxTool): string | undefined => {
549
+ const wireName = namespacedToolName(tool.namespace, tool.name);
550
+ // Read the recorded mapping; `registry.alias()` would REGISTER a name here.
551
+ const alias = advertisedAlias.get(wireName) ?? wireName;
552
+ return emittedToolNames.has(alias) ? alias : undefined;
553
+ };
554
+ const requestedTools = parsed.context.tools ?? [];
555
+ const emittedCodeModeExec = requestedTools.find(tool => isCodexCodeModeExecTool(tool) && emittedAlias(tool));
556
+ const emittedShellBridge = requestedTools.some(tool => isBareShellBridgeTool(tool) && emittedAlias(tool));
557
+ const codeModeExecName = emittedCodeModeExec && !emittedShellBridge
558
+ ? emittedAlias(emittedCodeModeExec)
559
+ : undefined;
560
+ const toolCatalogNudge = buildNonOpenAIToolCatalogNudgeFromNames(
561
+ kiroToolWireNames(kiroTools),
562
+ name => advertisedAlias.get(name) ?? name,
563
+ codeModeExecName,
564
+ );
442
565
  const boundedNudge = toolCatalogNudge ? boundedInjectedInstruction(toolCatalogNudge, injectedChars) : undefined;
443
566
  if (boundedNudge) systemParts.push(boundedNudge);
444
567
  if (completionMode !== "disabled") {
@@ -458,13 +581,24 @@ export function buildKiroPayload(
458
581
  turns.push({ kind: "user", content, images: [...images], toolResults: [...toolResults] });
459
582
  }
460
583
  };
461
- const pushAssistant = (content: string, toolUses: KiroToolUse[]): void => {
584
+ const pushAssistant = (content: string, toolUses: KiroToolUse[], redactedReasoning?: string, finalAnswer?: boolean): void => {
462
585
  const last = turns.at(-1);
463
586
  if (last?.kind === "assistant") {
464
587
  last.content = appendTurnText(last.content, content);
465
588
  last.toolUses.push(...toolUses);
589
+ // Merged turns keep the newest blob: it covers the reasoning up to the merged turn's end.
590
+ if (redactedReasoning) last.redactedReasoning = redactedReasoning;
591
+ // A merged turn is final only if its LAST component was: commentary appended after a final
592
+ // answer means the model kept working, so the turn is no longer terminal.
593
+ last.finalAnswer = finalAnswer === true;
466
594
  } else {
467
- turns.push({ kind: "assistant", content, toolUses: [...toolUses] });
595
+ turns.push({
596
+ kind: "assistant",
597
+ content,
598
+ toolUses: [...toolUses],
599
+ ...(redactedReasoning ? { redactedReasoning } : {}),
600
+ ...(finalAnswer ? { finalAnswer: true } : {}),
601
+ });
468
602
  }
469
603
  };
470
604
 
@@ -494,14 +628,24 @@ export function buildKiroPayload(
494
628
  const hasReasoning = aMsg.content.some(part => part.type === "thinking" && part.thinking.trim());
495
629
  if (hasReasoning) continue;
496
630
  }
497
- pushAssistant(text, toolUses);
631
+ // `phase` survives the Responses round trip (parser.ts assistant branch), so a replayed
632
+ // final answer is identifiable here rather than guessed from turn position.
633
+ pushAssistant(text, toolUses, aMsg.kiroRedactedReasoning, aMsg.phase === "final_answer" && toolUses.length === 0);
498
634
  } else if (msg.role === "toolResult") {
499
635
  const tr = msg as OcxToolResultMessage;
500
636
  if (tr.containsEncryptedContent) {
501
637
  throw new Error(`Kiro cannot translate encrypted output for tool call ${JSON.stringify(tr.toolCallId)}`);
502
638
  }
503
639
  const text = userContentText(tr.content);
504
- const resultText = text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE;
640
+ // An empty code-mode exec result needs the SPECIFIC reason, not the generic fallback: the
641
+ // model otherwise reads a blank result, concludes its earlier context was lost, and restarts
642
+ // the task instead of calling text()/notify(). Checked before `text.trim()` because the
643
+ // wrapper form ("Script completed\nWall time ...\nOutput:\n") is non-blank and would
644
+ // otherwise pass through as if it were real output.
645
+ const resultText = normalizeEmptyExecToolResultText(text, {
646
+ toolName: tr.toolName,
647
+ toolNamespace: tr.toolNamespace,
648
+ }) ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE);
505
649
  const images = extractKiroImages(tr.content);
506
650
  const toolUseId = normalizeToolId(tr.toolCallId);
507
651
  if (!priorCalls.has(toolUseId)) {
@@ -522,12 +666,23 @@ export function buildKiroPayload(
522
666
  if (turns.length === 0 || turns[0].kind === "assistant") {
523
667
  turns.unshift({ kind: "user", content: KIRO_CONTINUATION_MESSAGE, images: [], toolResults: [] });
524
668
  }
525
- if (turns.at(-1)?.kind === "assistant") {
669
+ // Kiro requires the request to end with a user turn, so a trailing assistant turn always gets
670
+ // one appended (the pop below throws otherwise). What that turn SAYS is the load-bearing part.
671
+ //
672
+ // Normally a trailing assistant turn means the model stopped mid-task, and a continuation/retry
673
+ // prompt is correct. A DELIVERED final answer is the exception: the turn already ended, and
674
+ // telling that model to "continue" or to call the completion tool again reopens finished work —
675
+ // the completed-task-behaves-like-an-open-goal loop. It gets a neutral acknowledgement instead:
676
+ // structurally valid, but carrying no instruction to resume.
677
+ const trailing = turns.at(-1);
678
+ if (trailing?.kind === "assistant") {
679
+ const resumeText = completionMode === "text_fallback" ? KIRO_COMPLETION_RETRY_MESSAGE : KIRO_CONTINUATION_MESSAGE;
526
680
  turns.push({
527
681
  kind: "user",
528
- content: completionMode === "text_fallback" ? KIRO_COMPLETION_RETRY_MESSAGE : KIRO_CONTINUATION_MESSAGE,
682
+ content: trailing.finalAnswer ? KIRO_ANSWER_DELIVERED_MESSAGE : resumeText,
529
683
  images: [],
530
684
  toolResults: [],
685
+ ...(trailing.finalAnswer ? { answerDeliveredAck: true } : {}),
531
686
  });
532
687
  }
533
688
 
@@ -543,11 +698,14 @@ export function buildKiroPayload(
543
698
 
544
699
  const currentTurn = turns.pop();
545
700
  if (!currentTurn || currentTurn.kind !== "user") throw new Error("Kiro request must end with a user turn");
701
+ // Survives the pop as state, so the checks below never infer intent from user-supplied text.
702
+ const answerDeliveredAck = currentTurn.answerDeliveredAck === true;
546
703
  const toEntry = (turn: KiroTurn): KiroHistoryEntry => turn.kind === "assistant"
547
704
  ? {
548
705
  assistantResponseMessage: {
549
706
  content: turn.content,
550
707
  ...(turn.toolUses.length > 0 ? { toolUses: turn.toolUses } : {}),
708
+ ...(turn.redactedReasoning ? { reasoningContent: { redactedContent: turn.redactedReasoning } } : {}),
551
709
  },
552
710
  }
553
711
  : {
@@ -572,10 +730,17 @@ export function buildKiroPayload(
572
730
  currentUim.userInputMessageContext = { ...(currentUim.userInputMessageContext ?? {}), tools: kiroTools };
573
731
  }
574
732
  if (completionMode === "text_fallback") {
575
- if (currentUim.content !== KIRO_COMPLETION_RETRY_MESSAGE) {
733
+ // Never append the retry instruction onto the answer-delivered acknowledgement: it exists
734
+ // precisely to avoid asking a finished turn for another completion call, and appending here
735
+ // would reinstate the loop it prevents.
736
+ if (currentUim.content !== KIRO_COMPLETION_RETRY_MESSAGE && !answerDeliveredAck) {
576
737
  currentUim.content = appendTurnText(currentUim.content, KIRO_COMPLETION_RETRY_MESSAGE);
577
738
  }
578
- } else if (!currentUim.userInputMessageContext?.toolResults && currentUim.content !== KIRO_CONTINUATION_MESSAGE) {
739
+ } else if (
740
+ !currentUim.userInputMessageContext?.toolResults
741
+ && currentUim.content !== KIRO_CONTINUATION_MESSAGE
742
+ && !answerDeliveredAck
743
+ ) {
579
744
  currentUim.content = injectKiroThinkingTags(currentUim.content, parsed);
580
745
  }
581
746
 
@@ -607,8 +772,8 @@ export function buildKiroPayload(
607
772
 
608
773
  // Stream parsing (shared by parseStream + parseResponse)
609
774
  // CodeWhisperer GenerateAssistantResponse ALWAYS returns an AWS eventstream body (there is no
610
- // non-streaming mode), so both the streaming bridge and the non-streaming web-search sidecar loop
611
- // decode the same way — parseResponse just collects what parseStream yields.
775
+ // non-streaming wire mode), so the streaming bridge and non-streaming Responses path decode the
776
+ // same way — parseResponse just collects what parseStream yields.
612
777
  interface KiroAttemptParseResult {
613
778
  terminal?: AdapterEvent;
614
779
  needsFallback?: boolean;
@@ -830,16 +995,12 @@ async function* parseKiroAttempt(
830
995
  );
831
996
  let handedOff = false;
832
997
  try {
833
- let next = await attempt.next();
834
- while (!next.done) {
835
- yield next.value;
836
- next = await attempt.next();
837
- }
998
+ const result = yield* attempt;
838
999
  for (const event of deferred.splice(0)) {
839
1000
  try { yield event; } finally { retention.releaseEvent(event); }
840
1001
  }
841
1002
  handedOff = true;
842
- return { ...next.value, releaseRetained: () => retention.releaseAll() };
1003
+ return { ...result, releaseRetained: () => retention.releaseAll() };
843
1004
  } finally {
844
1005
  if (!handedOff) retention.releaseAll();
845
1006
  }
@@ -868,6 +1029,12 @@ async function* parseKiroAttemptEvents(
868
1029
  }
869
1030
 
870
1031
  let open: { id: string; name: string; chunks: string[]; completion: boolean } | null = null;
1032
+ let openCallId: string | undefined;
1033
+ const closeOpenCall = () => {
1034
+ if (!openCallId) return;
1035
+ budget.closeCall(openCallId);
1036
+ openCallId = undefined;
1037
+ };
871
1038
  let outputChars = "";
872
1039
  let outputCharsBytes = 0;
873
1040
  let contextUsagePercentage: number | undefined;
@@ -1080,7 +1247,7 @@ async function* parseKiroAttemptEvents(
1080
1247
  if (!open) return { events: [] };
1081
1248
  const tool = open;
1082
1249
  open = null;
1083
- budget.closeCall(tool.id);
1250
+ closeOpenCall();
1084
1251
  const input = tool.chunks.join("");
1085
1252
  if (!isCompleteKiroToolInput(input)) {
1086
1253
  return { events: [], terminal: protocolTerminal(kiroTruncationErrorMessage("incomplete tool input JSON"), tool.completion) };
@@ -1170,6 +1337,12 @@ async function* parseKiroAttemptEvents(
1170
1337
  if (ev.data) {
1171
1338
  yield* emitRetained(stage({ type: "reasoning_raw_delta", text: ev.data }));
1172
1339
  }
1340
+ if (ev.redactedContent) {
1341
+ yield* emitRetained(stage({ type: "kiro_redacted_reasoning", data: ev.redactedContent }));
1342
+ }
1343
+ break;
1344
+ case "context_usage":
1345
+ if (ev.contextUsagePercentage > 0) contextUsagePercentage = ev.contextUsagePercentage;
1173
1346
  break;
1174
1347
  case "tool": {
1175
1348
  for (const contentEvent of thinking.flush()) {
@@ -1186,11 +1359,12 @@ async function* parseKiroAttemptEvents(
1186
1359
  if (started.terminal) return { assistantText, sawReasoning, terminal: started.terminal };
1187
1360
  open = started.tool!;
1188
1361
  budget.openCall(open.id);
1362
+ openCallId = open.id;
1189
1363
  } else if (
1190
1364
  (ev.toolUseId && ev.toolUseId !== open.id)
1191
1365
  || (ev.name && open.name !== "unknown" && ev.name !== open.name)
1192
1366
  ) {
1193
- budget.closeCall(open.id);
1367
+ closeOpenCall();
1194
1368
  open = null;
1195
1369
  return { assistantText, sawReasoning, terminal: protocolTerminal(kiroTruncationErrorMessage("tool input changed identity before stop")) };
1196
1370
  }
@@ -1454,7 +1628,7 @@ async function* parseKiroAttemptEvents(
1454
1628
  };
1455
1629
  } catch (err) {
1456
1630
  if (isTranslatorBudgetExceededError(err)) {
1457
- if (open) budget.closeCall(open.id);
1631
+ closeOpenCall();
1458
1632
  return {
1459
1633
  assistantText,
1460
1634
  sawReasoning,
@@ -1496,6 +1670,9 @@ async function* parseKiroAttemptEvents(
1496
1670
  usage: usage(),
1497
1671
  },
1498
1672
  };
1673
+ } finally {
1674
+ thinking.dispose();
1675
+ closeOpenCall();
1499
1676
  }
1500
1677
  }
1501
1678
 
@@ -1512,7 +1689,7 @@ export async function* parseKiroStream(
1512
1689
  contextInputEstimate?: number,
1513
1690
  ): AsyncGenerator<AdapterEvent> {
1514
1691
  const contextWindowState: KiroContextWindowState = { value: contextWindow };
1515
- const first = parseKiroAttempt(
1692
+ const firstResult = yield* parseKiroAttempt(
1516
1693
  response,
1517
1694
  budget,
1518
1695
  completionMode,
@@ -1524,12 +1701,6 @@ export async function* parseKiroStream(
1524
1701
  contextInputEstimate,
1525
1702
  false,
1526
1703
  );
1527
- let firstNext = await first.next();
1528
- while (!firstNext.done) {
1529
- yield firstNext.value;
1530
- firstNext = await first.next();
1531
- }
1532
- const firstResult = firstNext.value;
1533
1704
  try {
1534
1705
  if (!firstResult.needsFallback) {
1535
1706
  if (firstResult.terminal) yield firstResult.terminal;
@@ -1607,7 +1778,7 @@ export async function* parseKiroStream(
1607
1778
  return;
1608
1779
  }
1609
1780
 
1610
- const second = parseKiroAttempt(
1781
+ const secondResult = yield* parseKiroAttempt(
1611
1782
  fallback.response,
1612
1783
  budget,
1613
1784
  "text_fallback",
@@ -1621,12 +1792,6 @@ export async function* parseKiroStream(
1621
1792
  // A zero-output transport failure here must stay non-retryable to avoid duplicating that text.
1622
1793
  priorEmittedOutput,
1623
1794
  );
1624
- let secondNext = await second.next();
1625
- while (!secondNext.done) {
1626
- yield secondNext.value;
1627
- secondNext = await second.next();
1628
- }
1629
- const secondResult = secondNext.value;
1630
1795
  try {
1631
1796
  if (!secondResult.terminal) {
1632
1797
  yield retryableKiroIncomplete(
@@ -1695,12 +1860,19 @@ export function createKiroAdapter(provider: OcxProviderConfig): ProviderAdapter
1695
1860
  throw new Error("kiro token missing — run ocx login kiro");
1696
1861
  }
1697
1862
  const region = resolveKiroApiRegion(parsed._kiroAuthContext);
1698
- const resolvedProfileArn = resolveKiroProfileArn(parsed._kiroAuthContext);
1863
+ // Request-scoped: an AWS Builder ID account has no profile of its own and resolves to Kiro's
1864
+ // fixed service profile here, without that value ever becoming the account's stored identity.
1865
+ const requestProfile = resolveKiroRequestProfile(parsed._kiroAuthContext);
1866
+ const resolvedProfileArn = requestProfile.profileArn;
1699
1867
  const isApiKey = provider.apiKey.trim().startsWith("ksk_");
1700
1868
  const profileArn = isApiKey ? undefined : resolvedProfileArn;
1701
- // Builder ID and Kiro API keys have no profile ARN and are accepted only on Kiro's CLI
1702
- // request path. Enterprise profiles retain the existing IDE-shaped request.
1703
- const wireClient: KiroWireClient = isApiKey || !profileArn ? "cli" : "ide";
1869
+ // Builder ID and Kiro API keys are accepted only on Kiro's CLI request path; enterprise
1870
+ // profiles retain the IDE-shaped request. Builder ID now carries a profile ARN, so a truthy
1871
+ // `profileArn` no longer implies "enterprise". The wire path reads the resolver's own verdict
1872
+ // rather than re-deriving it, so the accountless path — where the auth type comes from the
1873
+ // local import, not the request context — cannot send the fallback inside an IDE-shaped call.
1874
+ const isBuilderId = requestProfile.builderIdFallback;
1875
+ const wireClient: KiroWireClient = isApiKey || isBuilderId || !profileArn ? "cli" : "ide";
1704
1876
  const fp = fingerprint().slice(0, 64);
1705
1877
  const headers: Record<string, string> = wireClient === "cli" ? {
1706
1878
  authorization: `Bearer ${provider.apiKey}`,
@@ -1832,6 +2004,24 @@ export function createKiroAdapter(provider: OcxProviderConfig): ProviderAdapter
1832
2004
 
1833
2005
  return {
1834
2006
  name: "kiro",
2007
+ // A replayed history that already ENDS with a delivered final answer has nothing to ask Kiro.
2008
+ // Before this hook the adapter still appended a trailing user turn — a neutral acknowledgement,
2009
+ // but structurally still a prompt — and performed a real inference, so the model answered the
2010
+ // closed task again and the finished turn behaved like a still-open goal.
2011
+ //
2012
+ // Suppressing the completion contract (above) removed the instruction to complete; it could not
2013
+ // remove the inference. This is the boundary: no request is built, nothing is sent, and no token
2014
+ // estimate is recorded.
2015
+ //
2016
+ // The forced-fallback build is deliberately NOT consulted here: this hook runs on the inbound
2017
+ // turn only, and the adapter-owned bounded retry passes "text_fallback" through `build`
2018
+ // directly, never through this path.
2019
+ localTerminal(parsed: OcxParsedRequest) {
2020
+ return hasTrailingDeliveredFinalAnswer(kiroPayloadMessages(parsed), parsed)
2021
+ ? { reason: "kiro_final_answer_already_delivered" }
2022
+ : undefined;
2023
+ },
2024
+
1835
2025
  async buildRequest(parsed: OcxParsedRequest, incoming) {
1836
2026
  const built = await build(parsed);
1837
2027
  modelId = parsed.modelId;
@@ -1874,25 +2064,32 @@ export function createKiroAdapter(provider: OcxProviderConfig): ProviderAdapter
1874
2064
  return safeKiroHttpErrorMessage(status, headers, payloadText);
1875
2065
  },
1876
2066
 
1877
- // Non-streaming path used by the web-search sidecar loop (loop.ts runs each iteration
1878
- // non-streamed so it can inspect tool calls). CW only ever event-streams, so we drain the
1879
- // same decoder into an array. Without this, any Codex request that includes the web_search
1880
- // tool failed with "web-search sidecar requires a non-streaming adapter" (kiro-only).
2067
+ // Kiro always returns an event stream, including for non-streaming Responses requests. Drain
2068
+ // the decoder into a budget-owned batch so an upstream stream cannot grow this array without
2069
+ // bound while the caller waits for the complete JSON response.
1881
2070
  async parseResponse(response: Response, budget: TranslatorBudget): Promise<AdapterEvent[]> {
1882
2071
  const events: AdapterEvent[] = [];
1883
- for await (const e of parseKiroStream(
1884
- response,
1885
- budget,
1886
- modelId,
1887
- inputTokens,
1888
- contextWindow,
1889
- toolNameMap,
1890
- conversationId,
1891
- completionMode,
1892
- completionMode === "required" ? fallbackFactory : undefined,
1893
- contextInputEstimate,
1894
- )) events.push(e);
1895
- return events;
2072
+ try {
2073
+ for await (const e of parseKiroStream(
2074
+ response,
2075
+ budget,
2076
+ modelId,
2077
+ inputTokens,
2078
+ contextWindow,
2079
+ toolNameMap,
2080
+ conversationId,
2081
+ completionMode,
2082
+ completionMode === "required" ? fallbackFactory : undefined,
2083
+ contextInputEstimate,
2084
+ )) {
2085
+ retainTranslatedEvent(e, budget, events.at(-1));
2086
+ events.push(e);
2087
+ }
2088
+ return events;
2089
+ } catch (error) {
2090
+ for (const event of events) releaseTranslatedEvent(event, budget);
2091
+ throw error;
2092
+ }
1896
2093
  },
1897
2094
  };
1898
2095
  }
@@ -40,6 +40,18 @@ function randomUserAgent(): string {
40
40
  return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)]!;
41
41
  }
42
42
 
43
+ function isCanonicalMimoFreeEndpoint(baseUrl: string): boolean {
44
+ try {
45
+ const actual = new URL(baseUrl.trim());
46
+ const expected = new URL(MIMO_CHAT_URL);
47
+ actual.pathname = actual.pathname.replace(/\/+$/, "") || "/";
48
+ expected.pathname = expected.pathname.replace(/\/+$/, "") || "/";
49
+ return actual.toString().replace(/\/$/, "") === expected.toString().replace(/\/$/, "");
50
+ } catch {
51
+ return false;
52
+ }
53
+ }
54
+
43
55
  /**
44
56
  * Anonymous per-install client id for the bootstrap `client` field. A random UUID
45
57
  * persisted under the config dir (OPENCODEX_HOME-aware) — deliberately NOT derived
@@ -194,6 +206,11 @@ export function injectMimoSystemMarker(body: unknown): unknown {
194
206
  * On 401/403, flushes the JWT cache and retries once via fetchResponse.
195
207
  */
196
208
  export function createMimoFreeAdapter(provider: OcxProviderConfig): ProviderAdapter {
209
+ if (!isCanonicalMimoFreeEndpoint(provider.baseUrl)) {
210
+ throw new Error(
211
+ "The mimo-free adapter only supports the canonical Xiaomi MiMo Free endpoint. Use openai-chat for a custom endpoint.",
212
+ );
213
+ }
197
214
  const base = createOpenAIChatAdapter(provider);
198
215
  // Per-adapter session-affinity id (random, per process instance).
199
216
  const sessionId = `ses_${Math.random().toString(36).slice(2, 26)}`;
@@ -0,0 +1,11 @@
1
+ const TRAILING_SLASHES = /\/+$/;
2
+ const TRAILING_CHAT_COMPLETIONS = /\/chat\/completions\/?$/;
3
+
4
+ /** Build the openai-chat send URL from a configured baseUrl.
5
+ * Accepts /v1, /v1/, /v1/chat/completions, and /v1/chat/completions/.
6
+ */
7
+ export function openaiChatCompletionsUrl(baseUrl: string): string {
8
+ const trimmed = baseUrl.trim().replace(TRAILING_SLASHES, "");
9
+ const withoutEndpoint = trimmed.replace(TRAILING_CHAT_COMPLETIONS, "");
10
+ return `${withoutEndpoint}/chat/completions`;
11
+ }