cartethyia 2.7.4 → 2.7.5

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 (553) hide show
  1. package/.env.example +2 -0
  2. package/README.md +17 -5
  3. package/dist/dashboard/assets/{BannedPage-ChG5svFb.js → BannedPage-Cj15GsMp.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
  5. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +1 -0
  6. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolDetailPage-BIcWQun7.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
  8. package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
  9. package/dist/dashboard/assets/{CliToolsPage-Bf2VelDe.js → CliToolsPage-BIccZmeL.js} +1 -1
  10. package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
  11. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +1 -0
  12. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
  13. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js +1 -0
  14. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
  15. package/dist/dashboard/assets/{CustomizationPage-ggeMSjte.js → CustomizationPage-BKj_r0rp.js} +1 -1
  16. package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
  17. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js +656 -0
  18. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
  19. package/dist/dashboard/assets/{LoginPage-U6AKaJcF.js → LoginPage-DkXb6dx-.js} +1 -1
  20. package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-DnQPSIA8.js} +1 -1
  22. package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
  23. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +1 -0
  24. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +5 -0
  26. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
  27. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +1 -0
  28. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
  29. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +1 -0
  30. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
  31. package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-5SnUSy3j.js} +1 -1
  32. package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
  33. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +1 -0
  34. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
  35. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js +1 -0
  36. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
  37. package/dist/dashboard/assets/{SetupPage-f0DE1h0-.js → SetupPage-WTa0sktC.js} +1 -1
  38. package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-BfAb5-o_.js} +3 -3
  40. package/dist/dashboard/assets/StudioPage-BfAb5-o_.js.gz +0 -0
  41. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js +56 -0
  42. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js.gz +0 -0
  43. package/dist/dashboard/assets/api-keys-l29JROPv.js +1 -0
  44. package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
  45. package/dist/dashboard/assets/app--PJWq8_C.css +2 -0
  46. package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
  47. package/dist/dashboard/assets/assert-C0K-c4eo.js +1 -0
  48. package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-DfbhQU4k.js} +1 -1
  50. package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-DympBNq4.js → banner-BllT4LcF.js} +1 -1
  52. package/dist/dashboard/assets/banner-BllT4LcF.js.gz +0 -0
  53. package/dist/dashboard/assets/brand/login_register.jpg +0 -0
  54. package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
  55. package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
  56. package/dist/dashboard/assets/brand/og_image.jpg +0 -0
  57. package/dist/dashboard/assets/{card-ibRWU_uT.js → card-CtkX66Wd.js} +1 -1
  58. package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
  59. package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js +1 -0
  60. package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js.gz +0 -0
  61. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js +1 -0
  62. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
  63. package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-BQqBQd2n.js} +1 -1
  64. package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
  65. package/dist/dashboard/assets/{dialog-8fiE6tec.js → dialog-BEK7KP0H.js} +1 -1
  66. package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
  67. package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-BrTEZ8zu.js} +1 -1
  68. package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
  69. package/dist/dashboard/assets/entry-CHWxbS56.js +1 -0
  70. package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
  71. package/dist/dashboard/assets/{entry-BSAsYsmV.js → entry-EBHJ3DrE.js} +1 -1
  72. package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
  73. package/dist/dashboard/assets/entry-LCS85hiq.js +4 -0
  74. package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
  75. package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-BAACA727.js} +1 -1
  76. package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
  77. package/dist/dashboard/assets/{github-badge-CPK47xQx.js → github-badge-YSCE4UC2.js} +1 -1
  78. package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
  79. package/dist/dashboard/assets/{index-DBNPOfhV.js → index-FQlj0HUT.js} +2 -2
  80. package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
  81. package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-C4gU5iOL.js} +1 -1
  82. package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
  83. package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BHHX_Tmm.js} +1 -1
  84. package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
  85. package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-CajrYUnD.js} +1 -1
  86. package/dist/dashboard/assets/layout-CajrYUnD.js.gz +0 -0
  87. package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Bx2I7XUe.js} +1 -1
  88. package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
  89. package/dist/dashboard/assets/live-DNNqRbj2.js +1 -0
  90. package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
  91. package/dist/dashboard/assets/network-C5UBACrJ.js +1 -0
  92. package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
  93. package/dist/dashboard/assets/numbers-CUWAZK4J.js +2 -0
  94. package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
  95. package/dist/dashboard/assets/pagination-Xsi9Qx04.js +1 -0
  96. package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
  97. package/dist/dashboard/assets/quota-DvQbD_sr.js +1 -0
  98. package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
  99. package/dist/dashboard/assets/routing-in0f_IfK.js +1 -0
  100. package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
  101. package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BLULNqTp.js} +1 -1
  102. package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
  103. package/dist/dashboard/assets/settings-CcGczj6I.js +1 -0
  104. package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
  105. package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
  106. package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
  107. package/dist/dashboard/assets/{stack-DfgnFDWY.js → stack-D2lIR0tg.js} +1 -1
  108. package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
  109. package/dist/dashboard/assets/{state-CkfdYWel.js → state-DTARjfiW.js} +1 -1
  110. package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
  111. package/dist/dashboard/assets/{switch-SYm237HG.js → switch-c0oPSnqW.js} +1 -1
  112. package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
  113. package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-m8WGNPrz.js} +1 -1
  114. package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
  115. package/dist/dashboard/console-backgrounds.jpg +0 -0
  116. package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
  117. package/dist/dashboard/index.html +2 -2
  118. package/dist/dashboard/index.html.gz +0 -0
  119. package/dist/dashboard/precompressed-assets.json +56 -55
  120. package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
  121. package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
  122. package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
  123. package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
  124. package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
  125. package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
  126. package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
  127. package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
  128. package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
  129. package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
  130. package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
  131. package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
  132. package/package.json +4 -6
  133. package/scripts/cli/update.ts +15 -41
  134. package/src/boot/app.ts +58 -2
  135. package/src/boot/dependencies.ts +786 -732
  136. package/src/boot/lifecycle.ts +11 -12
  137. package/src/config/cooldowns.ts +34 -55
  138. package/src/config/network.ts +1 -1
  139. package/src/config/package-paths.ts +1 -1
  140. package/src/config/providers.ts +13 -14
  141. package/src/config/resources.ts +0 -5
  142. package/src/config/runtime.ts +2 -5
  143. package/src/config/spec.ts +26 -6
  144. package/src/console/api-keys/ban-constants.ts +38 -0
  145. package/src/console/api-keys/contracts.ts +71 -62
  146. package/src/console/api-keys/routes.ts +48 -12
  147. package/src/console/auth/access.ts +4 -4
  148. package/src/console/auth/account-reset.ts +1 -1
  149. package/src/console/auth/audit-recorder.ts +1 -1
  150. package/src/console/auth/lockout.ts +7 -3
  151. package/src/console/auth/row-coercion.ts +57 -12
  152. package/src/console/auth/session-resolver.ts +1 -1
  153. package/src/console/auth/session-service.ts +8 -2
  154. package/src/console/auth/session.ts +37 -31
  155. package/src/console/auth/setup-service.ts +4 -3
  156. package/src/console/auth/user-store.ts +1 -1
  157. package/src/console/backup/9router-map.ts +0 -3
  158. package/src/console/backup/contracts.ts +9 -9
  159. package/src/console/backup/export-endpoint.ts +5 -6
  160. package/src/console/backup/nine-router.ts +1 -7
  161. package/src/console/backup/routes.ts +29 -33
  162. package/src/console/backup/service.ts +468 -468
  163. package/src/console/backup/store.ts +47 -29
  164. package/src/console/backup/validate.ts +11 -1
  165. package/src/console/cli-tools/contracts.ts +7 -7
  166. package/src/console/cli-tools/injectors/cline.ts +110 -110
  167. package/src/console/cli-tools/injectors/codex.ts +181 -181
  168. package/src/console/cli-tools/injectors/copilot.ts +108 -108
  169. package/src/console/cli-tools/injectors/driver.ts +247 -247
  170. package/src/console/cli-tools/injectors/jcode.ts +115 -115
  171. package/src/console/cli-tools/injectors/openclaw.ts +161 -161
  172. package/src/console/cli-tools/injectors/opencode.ts +153 -153
  173. package/src/console/cli-tools/routes.ts +1 -1
  174. package/src/console/cli-tools/service.ts +1 -1
  175. package/src/console/cli-tools/store.ts +2 -2
  176. package/src/console/console-router.ts +32 -0
  177. package/src/console/dashboard-assets.ts +9 -9
  178. package/src/console/domain-registration.ts +16 -2
  179. package/src/console/inferhub/client.ts +0 -7
  180. package/src/console/inferhub/key-store.ts +1 -1
  181. package/src/console/inferhub/normalize.ts +2 -2
  182. package/src/console/inferhub/routes.ts +1 -1
  183. package/src/console/inferhub/types.ts +1 -1
  184. package/src/console/observability/contracts.ts +1 -1
  185. package/src/console/observability/live.ts +31 -18
  186. package/src/console/observability/logs.ts +1 -1
  187. package/src/console/observability/sse.ts +62 -8
  188. package/src/console/observability/store.ts +20 -4
  189. package/src/console/providers/catalog/catalog-projections.ts +1 -1
  190. package/src/console/providers/catalog/contracts.ts +39 -0
  191. package/src/console/providers/catalog/model-operations.ts +1 -1
  192. package/src/console/providers/catalog/provider-operations.ts +95 -17
  193. package/src/console/providers/catalog/public-model-store.ts +0 -0
  194. package/src/console/providers/catalog/routes.ts +27 -3
  195. package/src/console/providers/catalog/store.ts +147 -8
  196. package/src/console/providers/detail/routes.ts +1 -1
  197. package/src/console/providers/oauth/callback-listener.ts +100 -18
  198. package/src/console/providers/oauth/routes.ts +92 -13
  199. package/src/console/quota/account-quota-global.ts +41 -3
  200. package/src/console/quota/account-quota-shared.ts +10 -3
  201. package/src/console/quota/account-quota-tenant.ts +259 -66
  202. package/src/console/quota/daily-growth-job.ts +308 -0
  203. package/src/console/quota/native-identity.ts +2 -2
  204. package/src/console/quota/quota-view.ts +1 -1
  205. package/src/console/remote-support/routes.ts +1 -1
  206. package/src/console/remote-support/service.ts +2 -2
  207. package/src/console/routing/model/contracts.ts +1 -1
  208. package/src/console/routing/pools/contracts.ts +2 -2
  209. package/src/console/routing/pools/import-parse.ts +3 -3
  210. package/src/console/routing/pools/relay-deploy.ts +3 -3
  211. package/src/console/settings/contracts.ts +29 -2
  212. package/src/console/settings/store.ts +20 -0
  213. package/src/console/share/share-router.ts +100 -32
  214. package/src/console/share/share-stats.ts +4 -4
  215. package/src/console/share/share-usage.ts +1 -1
  216. package/src/console/shared/errors.ts +2 -2
  217. package/src/console/shared/object.ts +18 -0
  218. package/src/console/shared/read-through-cache.ts +4 -4
  219. package/src/console/shared/transaction.ts +14 -0
  220. package/src/console/system-prompt/contracts.ts +89 -12
  221. package/src/console/system-prompt/routes.ts +98 -45
  222. package/src/console/updates/apply-update.ts +244 -0
  223. package/src/console/updates/routes.ts +252 -97
  224. package/src/main.ts +11 -5
  225. package/src/network/http2-bidi.ts +1 -1
  226. package/src/network/ip-utils.ts +298 -0
  227. package/src/network/outbound-fetch.ts +1 -1
  228. package/src/network/pool/agent.ts +7 -6
  229. package/src/network/pool/byte-accounting.ts +1 -1
  230. package/src/network/pool/resolver.ts +16 -12
  231. package/src/network/pool/selector.ts +150 -136
  232. package/src/network/pool-health-machine.ts +1 -1
  233. package/src/network/rate-limit-verdict.ts +1 -1
  234. package/src/network/retry.ts +1 -1
  235. package/src/network/ssrf.ts +20 -71
  236. package/src/observability/event-log.ts +2 -2
  237. package/src/observability/event-query.ts +59 -291
  238. package/src/observability/log-sanitize.ts +1 -1
  239. package/src/observability/metrics.ts +4 -4
  240. package/src/observability/payload-capture.ts +6 -5
  241. package/src/observability/payload-store.ts +1 -1
  242. package/src/observability/runtime-metrics.ts +1 -1
  243. package/src/observability/telemetry-buffer.ts +12 -3
  244. package/src/observability/telemetry-reconciliation.ts +3 -3
  245. package/src/observability/token-speed.ts +1 -1
  246. package/src/persistence/connection-url.ts +1 -1
  247. package/src/persistence/db-handle.ts +1 -1
  248. package/src/persistence/db-pg.ts +2 -2
  249. package/src/persistence/db-sqlite.ts +3 -3
  250. package/src/persistence/dialect.ts +5 -1
  251. package/src/persistence/readiness.ts +1 -1
  252. package/src/persistence/redis.ts +1 -1
  253. package/src/persistence/schema.ts +113 -40
  254. package/src/persistence/shared-cache.ts +2 -2
  255. package/src/persistence/sort-order.ts +1 -1
  256. package/src/persistence/stores/api-key-store.ts +10 -1
  257. package/src/persistence/stores/share-store.ts +20 -8
  258. package/src/persistence/system-prompt-store.ts +63 -18
  259. package/src/persistence/tenant-preferences.ts +1 -1
  260. package/src/persistence/ttl-cache.ts +3 -3
  261. package/src/persistence/usage-flush.ts +7 -2
  262. package/src/protocol/canonical-model.ts +1 -1
  263. package/src/protocol/codecs.ts +6 -10
  264. package/src/protocol/dsml.ts +3 -49
  265. package/src/protocol/image-clamp.ts +2 -2
  266. package/src/protocol/reasoning-text.ts +1 -1
  267. package/src/protocol/reasoning.ts +7 -52
  268. package/src/protocol/registry.ts +50 -15
  269. package/src/protocol/request/chat.ts +46 -19
  270. package/src/protocol/request/codex.ts +1 -1
  271. package/src/protocol/request/messages.ts +46 -14
  272. package/src/protocol/request/responses.ts +19 -10
  273. package/src/protocol/response/chat.ts +25 -10
  274. package/src/protocol/response/codex.ts +1 -1
  275. package/src/protocol/response/messages.ts +1 -1
  276. package/src/protocol/response/omp-tool-call-markup.ts +1 -1
  277. package/src/protocol/response/responses.ts +1 -1
  278. package/src/protocol/sse-decoder.ts +50 -1
  279. package/src/protocol/stop-reason.ts +2 -2
  280. package/src/protocol/think-split.ts +347 -0
  281. package/src/protocol/translation/attachment-integrity.ts +3 -3
  282. package/src/protocol/translation/cache-controls.ts +8 -20
  283. package/src/protocol/translation/capabilities.ts +6 -6
  284. package/src/protocol/translation/dialect/deepseek.ts +10 -0
  285. package/src/protocol/translation/dialect/inband.ts +39 -0
  286. package/src/protocol/translation/dialect/model-thinking.ts +89 -0
  287. package/src/protocol/translation/dialect/qwen.ts +114 -0
  288. package/src/protocol/translation/dialect/resolver.ts +83 -0
  289. package/src/protocol/translation/dialect/rules.ts +93 -0
  290. package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
  291. package/src/protocol/translation/dialect/types.ts +58 -0
  292. package/src/protocol/translation/quirks.ts +18 -4
  293. package/src/protocol/translation/thinking.ts +12 -252
  294. package/src/protocol/translation/tool-id.ts +3 -3
  295. package/src/protocol/translation/tool-repair.ts +1 -1
  296. package/src/protocol/upstream/post-json.ts +6 -1
  297. package/src/providers/adapters/compatible-adapter.ts +42 -3
  298. package/src/providers/authentication/jwt-validator.ts +0 -5
  299. package/src/providers/authentication/oauth-client.ts +254 -253
  300. package/src/providers/authentication/oauth-flow-store.ts +42 -7
  301. package/src/providers/bundled-discovery-providers.ts +6 -30
  302. package/src/providers/configured-openai-providers.ts +82 -97
  303. package/src/providers/default-registry.ts +23 -35
  304. package/src/providers/discovery/catalog/catalog-format.ts +13 -2
  305. package/src/providers/discovery/discovery-types.ts +0 -1
  306. package/src/providers/discovery/openai-model-discovery.ts +2 -2
  307. package/src/providers/discovery/probe-phases.ts +48 -13
  308. package/src/providers/discovery/probing-service.ts +6 -8
  309. package/src/providers/integrations/agentrouter/agentrouter.ts +12 -2
  310. package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
  311. package/src/providers/integrations/antigravity/antigravity-protocol.ts +0 -14
  312. package/src/providers/integrations/antigravity/antigravity.ts +2 -2
  313. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
  314. package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
  315. package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
  316. package/src/providers/integrations/buddy/buddy-identity.ts +86 -0
  317. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
  318. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
  319. package/src/providers/integrations/buddy/codebuddy/provider.ts +4 -15
  320. package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
  321. package/src/providers/integrations/buddy/workbuddy/provider.ts +5 -9
  322. package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
  323. package/src/providers/integrations/claude/claude-cch.ts +148 -148
  324. package/src/providers/integrations/claude/fallback-credit.ts +3 -7
  325. package/src/providers/integrations/cline/cline.ts +1 -1
  326. package/src/providers/integrations/codex/codex-device-code.ts +101 -101
  327. package/src/providers/integrations/codex/codex-oauth.ts +0 -1
  328. package/src/providers/integrations/commandcode/commandcode.ts +75 -115
  329. package/src/providers/integrations/commandcode/quota.ts +131 -51
  330. package/src/providers/integrations/cursor/cursor-http2.ts +0 -3
  331. package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
  332. package/src/providers/integrations/cursor/cursor-request.ts +0 -87
  333. package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
  334. package/src/providers/integrations/cursor/cursor.ts +38 -5
  335. package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
  336. package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
  337. package/src/providers/integrations/factory/factory.ts +9 -9
  338. package/src/providers/integrations/github/github-discovery.ts +55 -10
  339. package/src/providers/integrations/github/github-oauth.ts +6 -5
  340. package/src/providers/integrations/github/github.ts +41 -14
  341. package/src/providers/integrations/grok/grok-oauth.ts +261 -261
  342. package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
  343. package/src/providers/integrations/grok/grok-quota.ts +16 -7
  344. package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
  345. package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
  346. package/src/providers/integrations/grok/grok.ts +86 -36
  347. package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
  348. package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
  349. package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
  350. package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
  351. package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
  352. package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
  353. package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
  354. package/src/providers/integrations/kiro/kiro-request.ts +8 -11
  355. package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
  356. package/src/providers/integrations/kiro/kiro.ts +81 -68
  357. package/src/providers/integrations/muse/muse-oauth.ts +0 -1
  358. package/src/providers/integrations/muse/muse-quota.ts +0 -4
  359. package/src/providers/integrations/opencode/fingerprint.ts +7 -5
  360. package/src/providers/integrations/opencode/provider.ts +17 -24
  361. package/src/providers/integrations/qoder/qoder-catalog.ts +85 -8
  362. package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
  363. package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
  364. package/src/providers/integrations/qoder/qoder-realm.ts +10 -31
  365. package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
  366. package/src/providers/integrations/qoder/qoder-umid.ts +21 -25
  367. package/src/providers/integrations/qoder/qoder-virtual.ts +12 -0
  368. package/src/providers/integrations/qoder/qoder.ts +354 -62
  369. package/src/providers/integrations/shared/connect.ts +0 -54
  370. package/src/providers/integrations/shared/hash.ts +15 -0
  371. package/src/providers/integrations/shared/session-cache.ts +136 -0
  372. package/src/providers/integrations/trae/trae-cache.ts +7 -87
  373. package/src/providers/integrations/trae/trae-catalog.ts +1 -6
  374. package/src/providers/integrations/trae/trae-protocol.ts +17 -8
  375. package/src/providers/integrations/trae/trae-realm.ts +0 -7
  376. package/src/providers/integrations/trae/trae.ts +53 -10
  377. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  378. package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
  379. package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
  380. package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
  381. package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
  382. package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
  383. package/src/providers/operations/account-error-classification.ts +131 -116
  384. package/src/providers/operations/account-health-service.ts +31 -39
  385. package/src/providers/operations/account-reset-service.ts +58 -1
  386. package/src/providers/operations/cli-platform.ts +31 -5
  387. package/src/providers/operations/client-version-resolver.ts +4 -6
  388. package/src/providers/operations/client-versions.ts +10 -7
  389. package/src/providers/operations/provider-catalog-seeder.ts +2 -0
  390. package/src/providers/operations/provider-catalog-service.ts +18 -2
  391. package/src/providers/operations/provider-credential-service.ts +19 -2
  392. package/src/providers/provider-contracts.ts +18 -7
  393. package/src/providers/provider-metadata.ts +17 -2
  394. package/src/providers/provider-model-definition.ts +22 -1
  395. package/src/providers/provider-probe.ts +4 -2
  396. package/src/providers/provider-usage.ts +81 -16
  397. package/src/providers/quota/cache.ts +29 -0
  398. package/src/providers/quota/quota-contracts.ts +4 -0
  399. package/src/providers/quota/refresh.ts +27 -4
  400. package/src/providers/quota/snapshot.ts +94 -0
  401. package/src/providers/search/search-provider.ts +1 -3
  402. package/src/providers/search/search-providers.ts +2 -1
  403. package/src/security/abuse.ts +4 -4
  404. package/src/security/admission/service.ts +2 -2
  405. package/src/security/admission/ttl.ts +61 -61
  406. package/src/security/api-key-auth.ts +16 -4
  407. package/src/security/client-router-fingerprint.ts +4 -4
  408. package/src/security/credential-codec.ts +3 -3
  409. package/src/security/csrf.ts +2 -2
  410. package/src/security/ip-boundary.ts +16 -189
  411. package/src/security/model-access-rule.ts +1 -1
  412. package/src/security/outbound-headers.ts +18 -0
  413. package/src/shared/invoke-guard.ts +47 -0
  414. package/src/transport/contracts.ts +13 -4
  415. package/src/transport/dispatch/attempt-finalize.ts +1 -1
  416. package/src/transport/dispatch/capture-policy.ts +34 -37
  417. package/src/transport/dispatch/empty-stream.ts +23 -20
  418. package/src/transport/dispatch/generation.ts +25 -45
  419. package/src/transport/dispatch/native-shared.ts +127 -0
  420. package/src/transport/dispatch/proxy-request.ts +3 -1
  421. package/src/transport/dispatch/responses-compact.ts +25 -46
  422. package/src/transport/dispatch/streaming/encoder.ts +18 -72
  423. package/src/transport/dispatch/streaming/finalize.ts +2 -2
  424. package/src/transport/dispatch/streaming/stream.ts +7 -3
  425. package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
  426. package/src/transport/dispatch/systemone.ts +20 -48
  427. package/src/transport/dispatch/token-count.ts +41 -38
  428. package/src/transport/dispatch/websearch.ts +19 -45
  429. package/src/transport/drain-endpoint.ts +1 -1
  430. package/src/transport/failure-policy.ts +6 -0
  431. package/src/transport/guards/auth-guard.ts +0 -6
  432. package/src/transport/guards/body-policy.ts +3 -3
  433. package/src/transport/guards/headroom-guard.ts +1 -1
  434. package/src/transport/guards/pipeline.ts +1 -1
  435. package/src/transport/guards/request-context.ts +12 -17
  436. package/src/transport/request/preparer.ts +286 -7
  437. package/src/transport/request/rtk/compress-request.ts +3 -3
  438. package/src/transport/request/rtk/rtk-constants.ts +2 -2
  439. package/src/transport/request/rtk/rtk-filters.ts +8 -8
  440. package/src/transport/request/state.ts +1 -13
  441. package/src/transport/request/system-prompt-injection.ts +74 -11
  442. package/src/transport/request/tenant-preferences.ts +22 -0
  443. package/src/transport/routing/candidate-index.ts +2 -2
  444. package/src/transport/routing/round-robin.ts +1 -1
  445. package/src/transport/routing/route-catalog.ts +17 -18
  446. package/src/transport/routing/route-model.ts +126 -33
  447. package/src/transport/routing/router.ts +152 -37
  448. package/src/transport/shutdown-notice.ts +2 -2
  449. package/src/transport/surface/adapters.ts +3 -3
  450. package/src/transport/surface/chat/encode.ts +7 -7
  451. package/src/transport/surface/chat/parse.ts +7 -7
  452. package/src/transport/surface/completion.ts +2 -2
  453. package/src/transport/surface/content-parts.ts +1 -1
  454. package/src/transport/surface/dialects.ts +2 -2
  455. package/src/transport/surface/messages/parse.ts +3 -3
  456. package/src/transport/surface/responses/adapter.ts +1 -1
  457. package/src/transport/surface/responses/errors.ts +0 -9
  458. package/src/transport/vision-handoff-cache.ts +58 -0
  459. package/src/transport/vision-handoff.ts +376 -0
  460. package/src/workers/account-identity-sweep.ts +2 -2
  461. package/src/workers/buddy-growth-tasks.ts +392 -346
  462. package/src/workers/daily-checkin.ts +102 -49
  463. package/src/workers/maintenance-lease.ts +2 -35
  464. package/src/workers/oauth-refresh-sweep.ts +8 -1
  465. package/src/workers/quota-refresh-sweep.ts +120 -82
  466. package/src/workers/scheduler.ts +67 -4
  467. package/src/workers/sweep-runner.ts +24 -5
  468. package/src/workers/zcode-gift-claim.ts +108 -0
  469. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
  470. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
  471. package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
  472. package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
  473. package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
  474. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js +0 -1
  475. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
  476. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +0 -1
  477. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
  478. package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
  479. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +0 -1
  480. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
  481. package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
  482. package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
  483. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +0 -1
  484. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
  485. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +0 -5
  486. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
  487. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
  488. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
  489. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +0 -1
  490. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
  491. package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
  492. package/dist/dashboard/assets/QuotaPage-L0skzML8.js +0 -1
  493. package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
  494. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +0 -1
  495. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
  496. package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
  497. package/dist/dashboard/assets/SortableList-ClzpwyET.js +0 -1
  498. package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
  499. package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
  500. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +0 -56
  501. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
  502. package/dist/dashboard/assets/api-keys-C38iXoO4.js +0 -1
  503. package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
  504. package/dist/dashboard/assets/app-a159k0ub.css +0 -2
  505. package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
  506. package/dist/dashboard/assets/assert-DbRA8EG2.js +0 -15
  507. package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
  508. package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
  509. package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
  510. package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
  511. package/dist/dashboard/assets/cli-tools-63qBGaRw.js +0 -1
  512. package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
  513. package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
  514. package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
  515. package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
  516. package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
  517. package/dist/dashboard/assets/entry-CiIQULZD.js +0 -4
  518. package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
  519. package/dist/dashboard/assets/entry-Daz0lJ-W.js +0 -1
  520. package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
  521. package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
  522. package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
  523. package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
  524. package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
  525. package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
  526. package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
  527. package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
  528. package/dist/dashboard/assets/live-DCQNZpF7.js +0 -1
  529. package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
  530. package/dist/dashboard/assets/network-9Yj2ZyLo.js +0 -1
  531. package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
  532. package/dist/dashboard/assets/numbers-CEagj6ZZ.js +0 -2
  533. package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
  534. package/dist/dashboard/assets/quota-Caw7wqci.js +0 -1
  535. package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
  536. package/dist/dashboard/assets/routing-CO9zCUus.js +0 -1
  537. package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
  538. package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
  539. package/dist/dashboard/assets/settings-jS3-PNSA.js +0 -1
  540. package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
  541. package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
  542. package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
  543. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
  544. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
  545. package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
  546. package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
  547. package/src/network/response-headers.ts +0 -39
  548. package/src/protocol/response/dsml.ts +0 -38
  549. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
  550. /package/dist/dashboard/assets/{app-BayTTy01.js → app-Bgd3zANQ.js} +0 -0
  551. /package/dist/dashboard/assets/{app-BayTTy01.js.gz → app-Bgd3zANQ.js.gz} +0 -0
  552. /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
  553. /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
@@ -1,6 +1,8 @@
1
1
  import type { CanonicalEvent, CanonicalRequest, WireFamily } from "./canonical-model";
2
+ import type { DialectPolicy } from "./translation/dialect/types";
3
+ import type { ThinkingConfig } from "./translation/dialect/thinking-ladder";
2
4
 
3
- export interface CodecContext {
5
+ interface CodecContext {
4
6
  readonly isOAuth?: boolean;
5
7
  readonly sessionId?: string;
6
8
  readonly supportsPromptCaching?: boolean;
@@ -13,6 +15,16 @@ export interface CodecContext {
13
15
  * deployment default; only wire encoders that clamp images read it.
14
16
  */
15
17
  readonly maxBytesOverride?: number;
18
+ /**
19
+ * Resolved wire dialect (see `translation/dialect`). Absent = the codec's
20
+ * own default behavior (today's exact bytes).
21
+ */
22
+ readonly dialectPolicy?: DialectPolicy;
23
+ /**
24
+ * Resolved thinking config (see `translation/dialect/thinking-ladder`).
25
+ * Absent = the codec's own default behavior (today's exact clamp/ladder).
26
+ */
27
+ readonly thinking?: ThinkingConfig;
16
28
  }
17
29
 
18
30
  /**
@@ -27,7 +39,13 @@ type CodecModule =
27
39
  readonly family: "messages";
28
40
  readonly encodeWireRequest: (
29
41
  request: CanonicalRequest,
30
- options?: { isOAuth?: boolean },
42
+ options?: {
43
+ readonly isOAuth?: boolean;
44
+ readonly maxBytesOverride?: number;
45
+ readonly dialectPolicy?: DialectPolicy;
46
+ readonly thinking?: ThinkingConfig;
47
+ readonly maxOutputTokens?: number;
48
+ },
31
49
  ) => Record<string, unknown>;
32
50
  readonly decodeWireResponse: (
33
51
  json: Record<string, unknown>,
@@ -48,6 +66,8 @@ type CodecModule =
48
66
  readonly supportsPromptCaching?: boolean;
49
67
  readonly tokenLimitField?: "max_tokens" | "max_completion_tokens";
50
68
  readonly promptCacheKey?: string;
69
+ readonly dialectPolicy?: DialectPolicy;
70
+ readonly thinking?: ThinkingConfig;
51
71
  },
52
72
  ) => Record<string, unknown>;
53
73
  readonly decodeWireResponse: (
@@ -58,6 +78,7 @@ type CodecModule =
58
78
  body: ReadableStream<Uint8Array>,
59
79
  request: CanonicalRequest,
60
80
  signal?: AbortSignal,
81
+ options?: { readonly dialectPolicy?: DialectPolicy },
61
82
  ) => AsyncIterable<CanonicalEvent>;
62
83
  }
63
84
  | {
@@ -67,6 +88,9 @@ type CodecModule =
67
88
  options?: {
68
89
  readonly supportsPromptCaching?: boolean;
69
90
  readonly promptCacheKey?: string;
91
+ readonly dialectPolicy?: DialectPolicy;
92
+ readonly thinking?: ThinkingConfig;
93
+ readonly maxOutputTokens?: number;
70
94
  },
71
95
  ) => Record<string, unknown>;
72
96
  readonly decodeWireResponse: (
@@ -89,8 +113,10 @@ type CodecModule =
89
113
  *
90
114
  * The dynamic import is awaited by the caller. Wire encoding happens before the
91
115
  * upstream request is issued, so the cost is paid once, on the first request,
92
- * and is subsequently free. `preloadCodecs()` warms it during boot to remove
93
- * even that first-request delay.
116
+ * The cost is paid once, on the first request for that family, because wire
117
+ * encoding happens before the upstream request is issued. There is no preload
118
+ * at boot: no family is knowable then, and eagerly loading all three codecs
119
+ * would defeat the ~50 MiB of resident memory this indirection removes.
94
120
  */
95
121
  const codecCache = new Map<WireFamily, Promise<CodecModule>>();
96
122
 
@@ -103,8 +129,8 @@ const codecCache = new Map<WireFamily, Promise<CodecModule>>();
103
129
  * a gateway instance only ever serves one family.
104
130
  *
105
131
  * The cost is paid once, on the first request for that family, because wire
106
- * encoding happens before the upstream request is issued. `preloadCodec()`
107
- * warms it during boot so even that first-request delay disappears.
132
+ * encoding happens before the upstream request is issued. No boot-time preload
133
+ * exists — see the note on `codecCache` above.
108
134
  */
109
135
  async function loadCodec(wireFamily: WireFamily): Promise<CodecModule> {
110
136
  const cached = codecCache.get(wireFamily);
@@ -127,15 +153,6 @@ async function loadCodec(wireFamily: WireFamily): Promise<CodecModule> {
127
153
  return promise;
128
154
  }
129
155
 
130
- /**
131
- * Warms the codec module for a wire family during boot so the first request
132
- * does not pay the dynamic-import cost. Safe to call concurrently; the cache
133
- * deduplicates.
134
- */
135
- export function preloadCodec(wireFamily: WireFamily): Promise<void> {
136
- return loadCodec(wireFamily).then(() => undefined);
137
- }
138
-
139
156
  export async function encodeWireRequest(
140
157
  wireFamily: WireFamily,
141
158
  request: CanonicalRequest,
@@ -148,6 +165,11 @@ export async function encodeWireRequest(
148
165
  ...(context?.maxBytesOverride === undefined
149
166
  ? {}
150
167
  : { maxBytesOverride: context.maxBytesOverride }),
168
+ ...(context?.maxOutputTokens === undefined
169
+ ? {}
170
+ : { maxOutputTokens: context.maxOutputTokens }),
171
+ ...(context?.dialectPolicy === undefined ? {} : { dialectPolicy: context.dialectPolicy }),
172
+ ...(context?.thinking === undefined ? {} : { thinking: context.thinking }),
151
173
  });
152
174
  }
153
175
  if (codec.family === "chat") {
@@ -164,6 +186,8 @@ export async function encodeWireRequest(
164
186
  ...(context?.promptCacheKey === undefined
165
187
  ? {}
166
188
  : { promptCacheKey: context.promptCacheKey }),
189
+ ...(context?.dialectPolicy === undefined ? {} : { dialectPolicy: context.dialectPolicy }),
190
+ ...(context?.thinking === undefined ? {} : { thinking: context.thinking }),
167
191
  });
168
192
  }
169
193
  return codec.encodeWireRequest(request, {
@@ -173,6 +197,11 @@ export async function encodeWireRequest(
173
197
  ...(context?.promptCacheKey === undefined
174
198
  ? {}
175
199
  : { promptCacheKey: context.promptCacheKey }),
200
+ ...(context?.maxOutputTokens === undefined
201
+ ? {}
202
+ : { maxOutputTokens: context.maxOutputTokens }),
203
+ ...(context?.dialectPolicy === undefined ? {} : { dialectPolicy: context.dialectPolicy }),
204
+ ...(context?.thinking === undefined ? {} : { thinking: context.thinking }),
176
205
  });
177
206
  }
178
207
 
@@ -206,6 +235,12 @@ export function decodeWireStream(
206
235
  yield* codec.decodeWireStream(body, context?.signal, context?.isOAuth ?? false);
207
236
  return;
208
237
  }
238
+ if (codec.family === "chat") {
239
+ yield* codec.decodeWireStream(body, request, context?.signal, {
240
+ ...(context?.dialectPolicy === undefined ? {} : { dialectPolicy: context.dialectPolicy }),
241
+ });
242
+ return;
243
+ }
209
244
  yield* codec.decodeWireStream(body, request, context?.signal);
210
245
  }
211
246
  return decode();
@@ -8,15 +8,19 @@ import { isWebSearchTool } from "../../protocol/translation/search";
8
8
  import { pickWireSupportedControls } from "../../protocol/translation/capabilities";
9
9
  import { normalizeWireMaxTokens } from "../../protocol/translation/normalize";
10
10
  import { resolveWireMaxTokens } from "../../protocol/translation/quirks";
11
- import {
12
- clampReasoningEffort,
13
- resolveSupportedReasoningEfforts,
14
- } from "../../protocol/translation/thinking";
11
+ import { DEFAULT_DIALECT_POLICIES } from "../../protocol/translation/dialect/rules";
12
+ import type { DialectPolicy } from "../../protocol/translation/dialect/types";
13
+ import type { ThinkingConfig } from "../../protocol/translation/dialect/thinking-ladder";
14
+ import { resolveThinkingForModel } from "../../protocol/translation/dialect/thinking-ladder";
15
+ import { clampThinkingLevelForModel } from "../../protocol/translation/dialect/model-thinking";
15
16
  import { isClaudeBillingHeaderText, resolveImageSource } from "../codecs";
16
17
  import { resolvePromptCacheKey } from "../../providers/operations/session-resolution";
17
18
  import { reasoningEffortFromIntent } from "../../protocol/reasoning";
18
19
  import { parseChatResponseToEvents, decodeChatSseStream } from "../response/chat";
19
20
 
21
+ /** Fallback when no resolved policy is supplied — today's exact behavior. */
22
+ const DEFAULT_CHAT_DIALECT_POLICY: DialectPolicy = DEFAULT_DIALECT_POLICIES.openai;
23
+
20
24
  /**
21
25
  * OpenAI `input_audio.format` accepts only the discrete ids `wav`/`mp3`, never a
22
26
  * MIME type. The canonical `audio` part carries a `media_type`; map it here and
@@ -182,15 +186,31 @@ export function canonicalToChatPayload(
182
186
  readonly tokenLimitField?: "max_tokens" | "max_completion_tokens";
183
187
  readonly maxOutputTokens?: number;
184
188
  readonly promptCacheKey?: string;
189
+ readonly dialectPolicy?: DialectPolicy;
190
+ readonly thinking?: ThinkingConfig;
185
191
  } = {},
186
192
  ): Record<string, unknown> {
193
+ const policy = options.dialectPolicy ?? DEFAULT_CHAT_DIALECT_POLICY;
194
+ const resolvedThinking = options.thinking ?? resolveThinkingForModel(request.model, "", "chat");
187
195
  const supportsPromptCaching = options.supportsPromptCaching ?? true;
188
- const tokenLimitField = options.tokenLimitField ?? "max_tokens";
196
+ const tokenLimitField = options.tokenLimitField ?? policy.maxTokensField;
197
+ const reasoningField = policy.reasoningContentField;
198
+ const carryReasoning = (has: boolean, text: string): Record<string, unknown> =>
199
+ has && reasoningField !== undefined ? { [reasoningField]: text } : {};
189
200
  const messages: Array<Record<string, unknown>> = [];
201
+ const systemTexts: string[] = [];
190
202
  if (request.system?.length) {
191
203
  for (const p of request.system) {
192
- if (p.kind === "text" && !isClaudeBillingHeaderText(p.text))
193
- messages.push({ role: "system", content: p.text });
204
+ if (p.kind === "text" && !isClaudeBillingHeaderText(p.text)) systemTexts.push(p.text);
205
+ }
206
+ }
207
+ if (systemTexts.length > 0) {
208
+ if (policy.supportsMultipleSystemMessages) {
209
+ for (const text of systemTexts) messages.push({ role: "system", content: text });
210
+ } else {
211
+ // Strict chat templates (Qwen Portal / Alibaba / MiniMax) accept a single
212
+ // system message; join the canonical system parts into one.
213
+ messages.push({ role: "system", content: systemTexts.join("\n") });
194
214
  }
195
215
  }
196
216
  if (request.instructions?.length) {
@@ -217,6 +237,12 @@ export function canonicalToChatPayload(
217
237
  (c): c is Extract<typeof c, { kind: "text" }> => c.kind === "text",
218
238
  );
219
239
  const content = textParts.length ? textParts.map((c) => c.text).join("\n") : null;
240
+ // DeepSeek V4 requires the assistant content field to be present on a
241
+ // tool-call turn; a null content would be rejected verbatim.
242
+ const effectiveContent =
243
+ policy.requiresAssistantContentForToolCalls && (content === null || content.length === 0)
244
+ ? ""
245
+ : content;
220
246
  // Reasoning must survive on a tool-call turn, not just on plain assistant
221
247
  // turns. Providers in thinking mode require the previous turn's reasoning
222
248
  // to be replayed, and the tool-call turn is exactly where a thinking
@@ -237,9 +263,9 @@ export function canonicalToChatPayload(
237
263
  const hasReasoning = m.content.some((c) => c.kind === "reasoning");
238
264
  messages.push({
239
265
  role: "assistant",
240
- content,
266
+ content: effectiveContent,
241
267
  tool_calls: toolCalls,
242
- ...(hasReasoning ? { reasoning_content: reasoningContent } : {}),
268
+ ...carryReasoning(hasReasoning, reasoningContent),
243
269
  });
244
270
  } else if (m.role === "tool") {
245
271
  for (const p of m.content) {
@@ -332,9 +358,7 @@ export function canonicalToChatPayload(
332
358
  messages.push({
333
359
  role: m.role,
334
360
  content: parts,
335
- ...(m.role === "assistant" && hasReasoning
336
- ? { reasoning_content: reasoningContent }
337
- : {}),
361
+ ...carryReasoning(m.role === "assistant" && hasReasoning, reasoningContent),
338
362
  });
339
363
  } else {
340
364
  // A user turn whose toolResult parts were all folded out above has
@@ -374,7 +398,7 @@ export function canonicalToChatPayload(
374
398
  messages.push({
375
399
  role: "assistant",
376
400
  content: "",
377
- reasoning_content: reasoningContent,
401
+ ...carryReasoning(true, reasoningContent),
378
402
  });
379
403
  continue;
380
404
  }
@@ -401,9 +425,7 @@ export function canonicalToChatPayload(
401
425
  messages.push({
402
426
  role: m.role,
403
427
  content,
404
- ...(m.role === "assistant" && hasReasoning
405
- ? { reasoning_content: reasoningContent }
406
- : {}),
428
+ ...carryReasoning(m.role === "assistant" && hasReasoning, reasoningContent),
407
429
  });
408
430
  }
409
431
  }
@@ -458,7 +480,7 @@ export function canonicalToChatPayload(
458
480
  };
459
481
  });
460
482
  }
461
- if (request.tool_choice) {
483
+ if (request.tool_choice && policy.supportsToolChoice) {
462
484
  if (typeof request.tool_choice === "object" && request.tool_choice.type === "allowed_tools") {
463
485
  payload["tool_choice"] = {
464
486
  type: "allowed_tools",
@@ -484,11 +506,16 @@ export function canonicalToChatPayload(
484
506
  // is what the Codex encoder already uses); deriving it here instead of in
485
507
  // each codec is what keeps a translated request from silently losing it.
486
508
  if (request.reasoning !== undefined) {
487
- const effort = clampReasoningEffort(
509
+ const effort = clampThinkingLevelForModel(
510
+ resolvedThinking,
488
511
  reasoningEffortFromIntent(request.reasoning),
489
- resolveSupportedReasoningEfforts(request.model, "chat"),
490
512
  );
491
513
  if (effort !== undefined) payload["reasoning_effort"] = effort;
514
+ // Qwen chat templates select thinking with `enable_thinking` (plus optional
515
+ // `thinking_budget`) instead of `reasoning_effort`.
516
+ if (policy.thinkingFormat === "qwen" && effort !== undefined) {
517
+ payload["enable_thinking"] = true;
518
+ }
492
519
  }
493
520
  // Stream controls the caller asked for are forwarded upstream so a
494
521
  // pass-through provider can honor them (the local encoder honors them too).
@@ -27,7 +27,7 @@ import {
27
27
  * `provider_options` key that opts one request into the Daybreak
28
28
  * `access_programs.cyber` member. See the UNCONFIRMED note at its use site.
29
29
  */
30
- export const CODEX_ACCESS_PROGRAMS_CYBER_OPTION = "codex_access_programs_cyber";
30
+ const CODEX_ACCESS_PROGRAMS_CYBER_OPTION = "codex_access_programs_cyber";
31
31
 
32
32
  /**
33
33
  * Removes `access_programs` from an already-built Codex Responses payload.
@@ -2,6 +2,7 @@
2
2
  * Canonical → Claude Messages request builder.
3
3
  */
4
4
  import { allParts, type CanonicalRequest, type ContentPart } from "../canonical-model";
5
+ import type { DialectPolicy } from "../translation/dialect/types";
5
6
  import { buildAnthropicThinkingPayload } from "../../protocol/reasoning";
6
7
  import { anthropicCacheControl } from "../../protocol/translation/cache-controls";
7
8
  import {
@@ -28,14 +29,17 @@ import {
28
29
  } from "../codecs";
29
30
  import { log } from "../../observability/logger";
30
31
  import { base64DecodedByteLength, clampImage } from "../image-clamp";
31
- import { clampReasoningEffort, claudeUsesAdaptiveThinking, LEVEL_TO_BUDGET, resolveSupportedReasoningEfforts } from "../../protocol/translation/thinking";
32
+ import { LEVEL_TO_BUDGET } from "../../protocol/translation/thinking";
33
+ import type { ThinkingConfig } from "../../protocol/translation/dialect/thinking-ladder";
34
+ import { clampThinkingLevelForModel } from "../../protocol/translation/dialect/model-thinking";
35
+ import { resolveThinkingForModel } from "../../protocol/translation/dialect/thinking-ladder";
32
36
  import { claudeResponseToEvents, parseClaudeSseStream } from "../response/messages";
33
37
 
34
38
  /**
35
39
  * Gateway default when the caller sent no max_tokens (Anthropic requires
36
40
  * the field). Explicit and warned at the call site — never silent.
37
41
  */
38
- export const ANTHROPIC_DEFAULT_MAX_TOKENS = WIRE_TOKEN_BOUNDS["messages"]?.defaultMaxTokens ?? 4_096;
42
+ const ANTHROPIC_DEFAULT_MAX_TOKENS = WIRE_TOKEN_BOUNDS["messages"]?.defaultMaxTokens ?? 4_096;
39
43
 
40
44
  /** Anthropic Messages' documented base64-image media-type allowlist. */
41
45
  const ANTHROPIC_IMAGE_MEDIA_TYPES = new Set([
@@ -556,7 +560,13 @@ export function claudeFallbacksChain(
556
560
 
557
561
  export function canonicalToClaudeMessagesPayload(
558
562
  request: CanonicalRequest,
559
- options: { isOAuth?: boolean; maxBytesOverride?: number } = {},
563
+ options: {
564
+ isOAuth?: boolean;
565
+ maxBytesOverride?: number;
566
+ dialectPolicy?: DialectPolicy;
567
+ thinking?: ThinkingConfig;
568
+ maxOutputTokens?: number;
569
+ } = {},
560
570
  ): ClaudeWireObject {
561
571
  const seen = new Map<string, number>();
562
572
  const idMap = new Map<string, string>();
@@ -653,7 +663,11 @@ export function canonicalToClaudeMessagesPayload(
653
663
  const normalizedControls = normalizeWireMaxTokens(request.generation_controls);
654
664
  const requestedMax = normalizedControls.max_tokens;
655
665
  const hasTools = (request.tools?.length ?? 0) > 0;
656
- let maxTokens = resolveWireMaxTokens("messages", { max_tokens: requestedMax }, { hasTools, isOAuth }) ?? ANTHROPIC_DEFAULT_MAX_TOKENS;
666
+ let maxTokens = resolveWireMaxTokens("messages", { max_tokens: requestedMax }, {
667
+ hasTools,
668
+ isOAuth,
669
+ ...(options.maxOutputTokens === undefined ? {} : { maxOutputTokens: options.maxOutputTokens }),
670
+ }) ?? ANTHROPIC_DEFAULT_MAX_TOKENS;
657
671
  if (requestedMax === undefined) {
658
672
  log.warn("claude: max_tokens absent, defaulting", {
659
673
  max_tokens: maxTokens,
@@ -665,21 +679,32 @@ export function canonicalToClaudeMessagesPayload(
665
679
  });
666
680
  }
667
681
  const thinkingEnabled = isThinkingEnabled(request);
682
+ // Real ceilings (P2-12): an impossible thinking budget surfaces as a typed
683
+ // local 400 instead of an over-ceiling max_tokens that 400s opaquely upstream.
684
+ // Non-OAuth caps at the model's catalog output limit (when known) so the
685
+ // thinking guard can fire instead of shipping an over-catalog-limit
686
+ // `max_tokens`; OAuth keeps its own ceiling per the table.
687
+ const maxAllowed = isOAuth
688
+ ? WIRE_TOKEN_BOUNDS["messages"]?.oauthCeiling ?? Number.MAX_SAFE_INTEGER
689
+ : options.maxOutputTokens ?? Number.MAX_SAFE_INTEGER;
668
690
  if (thinkingEnabled && request.reasoning?.budget_tokens !== undefined) {
669
691
  maxTokens = ensureMaxTokensForThinking(
670
692
  maxTokens,
671
693
  request.reasoning.budget_tokens,
672
- Number.MAX_SAFE_INTEGER,
694
+ maxAllowed,
673
695
  );
674
696
  }
675
697
  // Whether this model speaks adaptive thinking (`type: "adaptive"` +
676
698
  // `output_config.effort`) or budget thinking (`type: "enabled"` +
677
699
  // `budget_tokens`). The two generations reject each other's shape, so the
678
- // choice is made from the model id, not from the caller's canonical intent —
679
- // a chat/responses caller states only an effort, and a budget-era model
680
- // answers the adaptive shape with "adaptive thinking is not supported on this
681
- // model" (verified live: opus-4-5/sonnet-4-5/haiku-4-5).
682
- const adaptiveThinking = claudeUsesAdaptiveThinking(request.model);
700
+ // choice is made from the resolved thinking config, not from the caller's
701
+ // canonical intent — a chat/responses caller states only an effort, and a
702
+ // budget-era model answers the adaptive shape with "adaptive thinking is not
703
+ // supported on this model" (verified live: opus-4-5/sonnet-4-5/haiku-4-5).
704
+ // When no config is supplied (direct-route callers), fall back to resolving
705
+ // it from the model/wire — the resolved `mode` IS the generation answer.
706
+ const resolvedThinking = options.thinking ?? resolveThinkingForModel(request.model, "", "messages");
707
+ const adaptiveThinking = resolvedThinking.mode === "anthropic-adaptive";
683
708
  let effectiveBudgetTokens = request.reasoning?.budget_tokens;
684
709
  // Derive a budget from the level whenever a budget-era model is asked to
685
710
  // reason by effort alone. The gate is NOT `isThinkingEnabled`: a chat/responses
@@ -699,7 +724,13 @@ export function canonicalToClaudeMessagesPayload(
699
724
  if (!adaptiveThinking && effectiveBudgetTokens !== undefined) {
700
725
  // The upstream requires the budget to stay below `max_tokens`; raise
701
726
  // max_tokens to leave room for the answer rather than let it 400.
702
- maxTokens = ensureMaxTokensForThinking(maxTokens, effectiveBudgetTokens, Number.MAX_SAFE_INTEGER);
727
+ maxTokens = ensureMaxTokensForThinking(maxTokens, effectiveBudgetTokens, maxAllowed);
728
+ }
729
+ // Final clamp to the model's catalog output limit: thinking may have raised
730
+ // `max_tokens` (e.g. under an OAuth ceiling wider than the catalog limit), so
731
+ // the value that ships must never exceed what the model can actually emit.
732
+ if (options.maxOutputTokens !== undefined && maxTokens > options.maxOutputTokens) {
733
+ maxTokens = options.maxOutputTokens;
703
734
  }
704
735
  const payload: ClaudeWireObject = {
705
736
  model: request.model,
@@ -748,7 +779,8 @@ export function canonicalToClaudeMessagesPayload(
748
779
  }
749
780
  const parallelToolCallsDisabled =
750
781
  request.generation_controls.parallel_tool_calls === false;
751
- if (rawToolChoice !== undefined || parallelToolCallsDisabled) {
782
+ const supportsToolChoice = options.dialectPolicy?.supportsToolChoice ?? true;
783
+ if (supportsToolChoice && (rawToolChoice !== undefined || parallelToolCallsDisabled)) {
752
784
  const baseChoice = rawToolChoice as Record<string, unknown> | undefined;
753
785
  const choice: Record<string, unknown> = baseChoice
754
786
  ? { ...baseChoice }
@@ -835,9 +867,9 @@ export function canonicalToClaudeMessagesPayload(
835
867
  // is NOT a wire field — display rides on `thinking.display` above.
836
868
  // Clamp to the model's published ladder exactly like the chat/Responses
837
869
  // codecs: an out-of-ladder tier is an upstream 4xx.
838
- const effort = clampReasoningEffort(
870
+ const effort = clampThinkingLevelForModel(
871
+ resolvedThinking,
839
872
  request.reasoning.effort,
840
- resolveSupportedReasoningEfforts(request.model, "messages"),
841
873
  );
842
874
  const taskBudget = request.reasoning.task_budget;
843
875
  // `output_config.effort` rides every generation: budget-era models accept it
@@ -7,10 +7,10 @@ import { markLatestBreakpoint } from "../../protocol/translation/cache-controls"
7
7
  import { pickWireSupportedControls } from "../../protocol/translation/capabilities";
8
8
  import { normalizeGenerationControls } from "../../protocol/translation/normalize";
9
9
  import { resolveWireMaxTokens } from "../../protocol/translation/quirks";
10
- import {
11
- clampReasoningEffort,
12
- resolveSupportedReasoningEfforts,
13
- } from "../../protocol/translation/thinking";
10
+ import type { DialectPolicy } from "../../protocol/translation/dialect/types";
11
+ import type { ThinkingConfig } from "../../protocol/translation/dialect/thinking-ladder";
12
+ import { resolveThinkingForModel } from "../../protocol/translation/dialect/thinking-ladder";
13
+ import { clampThinkingLevelForModel } from "../../protocol/translation/dialect/model-thinking";
14
14
  import { isClaudeBillingHeaderText, resolveImageSource, resolveOutputVerbosity } from "../codecs";
15
15
  import { resolvePromptCacheKey } from "../../providers/operations/session-resolution";
16
16
  import { reasoningEffortFromIntent } from "../../protocol/reasoning";
@@ -27,7 +27,7 @@ const RESPONSES_CACHEABLE_BLOCK_TYPES: ReadonlySet<string> = new Set([
27
27
  ]);
28
28
 
29
29
  /** Marks the latest stable input block with an explicit prompt-cache breakpoint. */
30
- export function markLatestResponsesCacheBreakpoint(input: Array<Record<string, unknown>>): void {
30
+ function markLatestResponsesCacheBreakpoint(input: Array<Record<string, unknown>>): void {
31
31
  markLatestBreakpoint(input, {
32
32
  isInputItem: (item) =>
33
33
  item["type"] === "message" && (item["role"] === "user" || item["role"] === "developer"),
@@ -63,9 +63,13 @@ export function canonicalToResponsesPayload(
63
63
  options: {
64
64
  readonly supportsPromptCaching?: boolean;
65
65
  readonly promptCacheKey?: string;
66
+ readonly dialectPolicy?: DialectPolicy;
67
+ readonly thinking?: ThinkingConfig;
68
+ readonly maxOutputTokens?: number;
66
69
  } = {},
67
70
  ): Record<string, unknown> {
68
71
  const supportsPromptCaching = options.supportsPromptCaching ?? true;
72
+ const resolvedThinking = options.thinking ?? resolveThinkingForModel(request.model, "", "responses");
69
73
  const input: Array<Record<string, unknown>> = [];
70
74
  // `pending_safety_checks` have no canonical content-part representation, so
71
75
  // `parseResponsesRequest` retains them per-item in the scoped item-metadata
@@ -317,10 +321,7 @@ export function canonicalToResponsesPayload(
317
321
  // this wire. Codex already derives its tier this way.
318
322
  const requestedEffort = reasoningEffortFromIntent(request.reasoning);
319
323
  if (requestedEffort !== undefined) {
320
- const effort = clampReasoningEffort(
321
- requestedEffort,
322
- resolveSupportedReasoningEfforts(request.model, "responses"),
323
- );
324
+ const effort = clampThinkingLevelForModel(resolvedThinking, requestedEffort);
324
325
  if (effort !== undefined) reasoning.effort = effort;
325
326
  }
326
327
  if (request.reasoning.mode !== undefined) reasoning.mode = request.reasoning.mode;
@@ -328,6 +329,12 @@ export function canonicalToResponsesPayload(
328
329
  if (request.reasoning.summary_mode !== undefined)
329
330
  reasoning.summary = request.reasoning.summary_mode;
330
331
  else if (request.reasoning.summary !== undefined) reasoning.summary = request.reasoning.summary;
332
+ else if (requestedEffort !== undefined) reasoning.summary = "detailed";
333
+ // When the caller asked for reasoning effort but expressed no summary
334
+ // preference, request a detailed summary. Upstreams (GitHub Copilot's
335
+ // gpt-6-luna etc.) only stream `reasoning_summary_text` when the request
336
+ // asks for it — without this the reasoning is present on the wire yet
337
+ // never reaches the client.
331
338
  if (Object.keys(reasoning).length > 0) payload.reasoning = reasoning;
332
339
  }
333
340
  const picked = pickWireSupportedControls(normalizeGenerationControls(request.generation_controls), "responses");
@@ -338,7 +345,9 @@ export function canonicalToResponsesPayload(
338
345
  // Resolved unconditionally so the wire's `defaultMaxTokens` applies: an
339
346
  // omitted limit must reach the upstream as a real number, not as an absent
340
347
  // field (see the worked "wkwk" case in the WIRE_TOKEN_BOUNDS comment).
341
- const bounded = resolveWireMaxTokens("responses", { max_tokens: requested });
348
+ const bounded = resolveWireMaxTokens("responses", { max_tokens: requested }, {
349
+ ...(options.maxOutputTokens === undefined ? {} : { maxOutputTokens: options.maxOutputTokens }),
350
+ });
342
351
  if (bounded !== undefined) picked["max_output_tokens"] = bounded;
343
352
  Object.assign(payload, picked);
344
353
  // Responses top-level params carried as `extension:responses.<field>` and
@@ -9,13 +9,15 @@ import { gatewayErrorFromStreamError } from "../stream-error-frames";
9
9
  import { mergeResponsesUsage } from "./responses";
10
10
  import { usageFromProvider, readReasoningText } from "../../providers/provider-usage";
11
11
  import { createToolEmitLedger } from "../tool-identity";
12
- import { MimoThinkSplitter, stripThinkingTags } from "../../providers/integrations/xiaomi-mimo/think-stream";
13
- import { DsmlToolCallParser, parseDsmlToolCalls } from "./dsml";
12
+ import { ThinkSplitter, stripThinkingTags } from "../think-split";
13
+ import { DsmlStreamParser, parseDsmlToolCalls } from "../dsml";
14
14
  import {
15
15
  OmpToolCallMarkupParser,
16
16
  parseOmpToolCallMarkup,
17
17
  type OmpTextToolCall,
18
18
  } from "./omp-tool-call-markup";
19
+ import type { DialectPolicy } from "../translation/dialect/types";
20
+ import { QwenToolCallScanner } from "../translation/dialect/qwen";
19
21
 
20
22
 
21
23
  export function mapChatStopReason(
@@ -83,11 +85,16 @@ export function parseChatResponseToEvents(
83
85
  const contentWithoutMarkup = recoveredMarkup?.text ?? content;
84
86
  const recovered =
85
87
  typeof contentWithoutMarkup === "string"
86
- ? parseDsmlToolCalls(contentWithoutMarkup, declaredToolNames)
88
+ ? parseDsmlToolCalls(contentWithoutMarkup, { allowedNames: declaredToolNames })
87
89
  : undefined;
88
- const visible = recovered === undefined ? contentWithoutMarkup : recovered.text;
90
+ const visible =
91
+ recovered === undefined
92
+ ? contentWithoutMarkup
93
+ : "text" in recovered
94
+ ? recovered.text
95
+ : recovered.clean;
89
96
  if (typeof visible === "string" && visible.includes("<think")) {
90
- const think = new MimoThinkSplitter();
97
+ const think = new ThinkSplitter();
91
98
  const split = think.push(visible);
92
99
  const rest = think.flush();
93
100
  const reasoning = `${split.reasoning}${rest.reasoning}`;
@@ -237,10 +244,12 @@ export async function* decodeChatSseStream(
237
244
  body: ReadableStream<Uint8Array>,
238
245
  request: CanonicalRequest,
239
246
  signal?: AbortSignal,
247
+ options?: { readonly dialectPolicy?: DialectPolicy },
240
248
  ): AsyncIterable<CanonicalEvent> {
241
249
  let seq = 1;
242
250
  let finishReason: unknown;
243
251
  let rawUsage: Record<string, unknown> | undefined;
252
+ const inbandDialect = options?.dialectPolicy?.inband;
244
253
  // Last seen tool-call id (and name) per wire index. OpenAI streams the id
245
254
  // (and name) only on the first fragment of each call; later fragments carry
246
255
  // just `function.arguments`. Without this memory every continuation fragment
@@ -257,11 +266,11 @@ export async function* decodeChatSseStream(
257
266
  const recoveredMarkupCalls: OmpTextToolCall[] = [];
258
267
  // Single emission ledger: one entry per logical call.
259
268
  const ledger = createToolEmitLedger();
260
- const think = new MimoThinkSplitter();
269
+ const think = new ThinkSplitter();
261
270
  // Separate splitter for the reasoning channel: `reasoning_content` is its own
262
271
  // stream, and interleaving it into the answer splitter would let a tag in one
263
272
  // channel swallow the other's text.
264
- const reasoningThink = new MimoThinkSplitter();
273
+ const reasoningThink = new ThinkSplitter();
265
274
  const declaredToolNames = declaredToolNamesForRequest(request);
266
275
  const callableToolNames = callableToolNamesForRequest(request);
267
276
  const contentMarkup =
@@ -269,7 +278,13 @@ export async function* decodeChatSseStream(
269
278
  const reasoningMarkup =
270
279
  (request.tools?.length ?? 0) > 0 ? new OmpToolCallMarkupParser(declaredToolNames) : undefined;
271
280
  const dsmlMarkup =
272
- (request.tools?.length ?? 0) > 0 ? new DsmlToolCallParser(declaredToolNames) : undefined;
281
+ (request.tools?.length ?? 0) > 0 && inbandDialect !== "qwen"
282
+ ? new DsmlStreamParser({ allowedNames: declaredToolNames })
283
+ : undefined;
284
+ const qwenMarkup =
285
+ (request.tools?.length ?? 0) > 0 && inbandDialect === "qwen"
286
+ ? new QwenToolCallScanner(declaredToolNames)
287
+ : undefined;
273
288
  yield {
274
289
  type: "response_start",
275
290
  sequence_number: seq++,
@@ -315,7 +330,7 @@ export async function* decodeChatSseStream(
315
330
  const raw = delta["content"] as string;
316
331
  const markup = contentMarkup?.push(raw);
317
332
  if (markup !== undefined) recoveredMarkupCalls.push(...markup.calls);
318
- const recovered = dsmlMarkup?.push(markup?.text ?? raw);
333
+ const recovered = (qwenMarkup ?? dsmlMarkup)?.push(markup?.text ?? raw);
319
334
  const visible = recovered?.text ?? markup?.text ?? raw;
320
335
  const split = think.push(visible);
321
336
  if (split.reasoning.length > 0) {
@@ -500,7 +515,7 @@ export async function* decodeChatSseStream(
500
515
  }
501
516
  }
502
517
  }
503
- const dsmlMarkupTail = dsmlMarkup?.flush();
518
+ const dsmlMarkupTail = (qwenMarkup ?? dsmlMarkup)?.flush();
504
519
  if (dsmlMarkupTail !== undefined) {
505
520
  if (dsmlMarkupTail.text.length > 0) {
506
521
  const split = think.push(dsmlMarkupTail.text);
@@ -15,7 +15,7 @@ import { usageFromProvider, readResponsesReasoningDelta } from '../../providers/
15
15
  import { canonicalTerminal, decodeCodexToolCallId, isRecord, readOutputIndex } from '../codecs';
16
16
  import { gatewayErrorFromStreamError } from '../stream-error-frames';
17
17
 
18
- export function mapCodexStopReason(
18
+ function mapCodexStopReason(
19
19
  status: unknown,
20
20
  hasToolCall: boolean,
21
21
  endTurn?: unknown,
@@ -185,7 +185,7 @@ export function withClaudeFallbackSignal(
185
185
  return { ...(stopDetails ?? {}), [CANONICAL_SERVED_BY_FALLBACK_KEY]: true };
186
186
  }
187
187
 
188
- export function eventContent(
188
+ function eventContent(
189
189
  content: readonly ContentPart[],
190
190
  sequence: number,
191
191
  ): { events: CanonicalEvent[]; sequence: number } {
@@ -14,7 +14,7 @@ export interface OmpTextToolCall {
14
14
  }
15
15
 
16
16
  /** Text remaining after complete tool envelopes are removed. */
17
- export interface OmpTextToolCallResult {
17
+ interface OmpTextToolCallResult {
18
18
  readonly text: string;
19
19
  readonly calls: readonly OmpTextToolCall[];
20
20
  }
@@ -10,7 +10,7 @@ import { gatewayErrorFromStreamError } from "../stream-error-frames";
10
10
  import { usageFromProvider, readResponsesReasoningDelta } from "../../providers/provider-usage";
11
11
  import { createToolEmitLedger } from "../tool-identity";
12
12
 
13
- export function mapResponsesStopReason(
13
+ function mapResponsesStopReason(
14
14
  status: unknown,
15
15
  hasToolCall: boolean,
16
16
  ): "stop" | "length" | "tool_use" | "error" | undefined {