cartethyia 2.7.3 → 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 (625) hide show
  1. package/.env.example +2 -0
  2. package/README.md +17 -5
  3. package/dist/dashboard/assets/{BannedPage-2TJD37Hb.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-xefJNRmJ.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
  8. package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
  9. package/dist/dashboard/assets/{CliToolsPage-Rj9iHQ3F.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-BKj_r0rp.js +1 -0
  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-C4w7vea-.js → LoginPage-DkXb6dx-.js} +1 -1
  20. package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-BtPcAfot.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-5SnUSy3j.js +9 -0
  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-BQS0Rx_u.js → SetupPage-WTa0sktC.js} +1 -1
  38. package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-TP7voAQ0.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-C0YYuZJ4.js → assert-C0K-c4eo.js} +1 -1
  48. package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-B_DMpMJN.js → badge-DfbhQU4k.js} +1 -1
  50. package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-DMrMPmth.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-Be5Uzamx.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-muFRphDu.js → cli-tools-CQXVMn4P.js} +1 -1
  62. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
  63. package/dist/dashboard/assets/{clipboard-button-DOfrVmsi.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-C9omdjQt.js → dialog-BEK7KP0H.js} +1 -1
  66. package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
  67. package/dist/dashboard/assets/{drawer-Bm8WKaGY.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-q5HwZ8nN.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-BTScrQpe.js → formatters-BAACA727.js} +1 -1
  76. package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
  77. package/dist/dashboard/assets/{github-badge-Orjuzemr.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-cPrX5vn6.js → index-FQlj0HUT.js} +2 -2
  80. package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
  81. package/dist/dashboard/assets/{inline-Dvux8w-0.js → inline-C4gU5iOL.js} +1 -1
  82. package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
  83. package/dist/dashboard/assets/{input-CU1Rgf3p.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-C_7A6H55.js → layout-CajrYUnD.js} +1 -1
  86. package/dist/dashboard/assets/{layout-C_7A6H55.js.gz → layout-CajrYUnD.js.gz} +0 -0
  87. package/dist/dashboard/assets/{list-row-CzFvogbj.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/minimize-2-BTmMTK4o.js +1 -0
  92. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
  93. package/dist/dashboard/assets/{mutation-JJGQm8TD.js → mutation-Rr0TIvcj.js} +1 -1
  94. package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
  95. package/dist/dashboard/assets/network-C5UBACrJ.js +1 -0
  96. package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
  97. package/dist/dashboard/assets/numbers-CUWAZK4J.js +2 -0
  98. package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
  99. package/dist/dashboard/assets/pagination-Xsi9Qx04.js +1 -0
  100. package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
  101. package/dist/dashboard/assets/{query-keys-CLaNz8Xz.js → query-keys-BloKtaXJ.js} +1 -1
  102. package/dist/dashboard/assets/query-keys-BloKtaXJ.js.gz +0 -0
  103. package/dist/dashboard/assets/quota-DvQbD_sr.js +1 -0
  104. package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
  105. package/dist/dashboard/assets/{routing-BEH32QOC.js → routing-in0f_IfK.js} +1 -1
  106. package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
  107. package/dist/dashboard/assets/{select-B3iTetHN.js → select-BLULNqTp.js} +2 -2
  108. package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
  109. package/dist/dashboard/assets/settings-CcGczj6I.js +1 -0
  110. package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
  111. package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
  112. package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
  113. package/dist/dashboard/assets/{stack-KrOrm7JZ.js → stack-D2lIR0tg.js} +1 -1
  114. package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
  115. package/dist/dashboard/assets/{state-DLS7IDMy.js → state-DTARjfiW.js} +1 -1
  116. package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
  117. package/dist/dashboard/assets/{switch-42ItvbAs.js → switch-c0oPSnqW.js} +1 -1
  118. package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
  119. package/dist/dashboard/assets/{useMutation-Dmnfh1Ue.js → useMutation-m8WGNPrz.js} +1 -1
  120. package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
  121. package/dist/dashboard/console-backgrounds.jpg +0 -0
  122. package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
  123. package/dist/dashboard/index.html +2 -2
  124. package/dist/dashboard/index.html.gz +0 -0
  125. package/dist/dashboard/precompressed-assets.json +59 -57
  126. package/migrations/full-postgres/0027_qoder_identity_genuine_seed.sql +9 -10
  127. package/migrations/full-postgres/0032_add_provider_pool_accounts.sql +53 -0
  128. package/migrations/full-postgres/0033_add_api_key_ban.sql +9 -0
  129. package/migrations/full-postgres/0034_add_api_key_ban_until.sql +7 -0
  130. package/migrations/full-postgres/0035_align_pool_account_status_enum.sql +21 -0
  131. package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
  132. package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
  133. package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
  134. package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
  135. package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
  136. package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
  137. package/migrations/lite-sqlite3/0027_qoder_identity_genuine_seed.sql +9 -10
  138. package/migrations/lite-sqlite3/0032_add_provider_pool_accounts.sql +44 -0
  139. package/migrations/lite-sqlite3/0033_add_api_key_ban.sql +8 -0
  140. package/migrations/lite-sqlite3/0034_add_api_key_ban_until.sql +5 -0
  141. package/migrations/lite-sqlite3/0035_align_pool_account_status_enum.sql +6 -0
  142. package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
  143. package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
  144. package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
  145. package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
  146. package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
  147. package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
  148. package/package.json +4 -5
  149. package/scripts/cli/update.ts +15 -41
  150. package/src/boot/app.ts +67 -10
  151. package/src/boot/dependencies.ts +786 -732
  152. package/src/boot/lifecycle.ts +11 -12
  153. package/src/config/cooldowns.ts +34 -55
  154. package/src/config/network.ts +8 -4
  155. package/src/config/package-paths.ts +1 -1
  156. package/src/config/providers.ts +13 -14
  157. package/src/config/resources.ts +0 -5
  158. package/src/config/runtime.ts +2 -5
  159. package/src/config/spec.ts +26 -6
  160. package/src/console/api-keys/ban-constants.ts +38 -0
  161. package/src/console/api-keys/contracts.ts +92 -31
  162. package/src/console/api-keys/routes.ts +131 -6
  163. package/src/console/audit/routes.ts +3 -3
  164. package/src/console/auth/access.ts +4 -4
  165. package/src/console/auth/account-reset.ts +5 -5
  166. package/src/console/auth/audit-recorder.ts +1 -1
  167. package/src/console/auth/lockout.ts +7 -3
  168. package/src/console/auth/row-coercion.ts +57 -12
  169. package/src/console/auth/session-resolver.ts +1 -1
  170. package/src/console/auth/session-service.ts +8 -2
  171. package/src/console/auth/session.ts +40 -34
  172. package/src/console/auth/setup-service.ts +4 -3
  173. package/src/console/auth/user-store.ts +1 -1
  174. package/src/console/backup/9router-map.ts +0 -3
  175. package/src/console/backup/contracts.ts +11 -9
  176. package/src/console/backup/export-endpoint.ts +11 -12
  177. package/src/console/backup/nine-router.ts +1 -7
  178. package/src/console/backup/routes.ts +32 -36
  179. package/src/console/backup/service.ts +468 -468
  180. package/src/console/backup/store.ts +47 -29
  181. package/src/console/backup/validate.ts +11 -1
  182. package/src/console/cli-tools/contracts.ts +7 -7
  183. package/src/console/cli-tools/injectors/cline.ts +110 -110
  184. package/src/console/cli-tools/injectors/codex.ts +181 -181
  185. package/src/console/cli-tools/injectors/copilot.ts +108 -108
  186. package/src/console/cli-tools/injectors/driver.ts +247 -247
  187. package/src/console/cli-tools/injectors/jcode.ts +115 -115
  188. package/src/console/cli-tools/injectors/openclaw.ts +161 -161
  189. package/src/console/cli-tools/injectors/opencode.ts +153 -153
  190. package/src/console/cli-tools/routes.ts +4 -4
  191. package/src/console/cli-tools/service.ts +1 -1
  192. package/src/console/cli-tools/store.ts +2 -2
  193. package/src/console/console-router-guards.ts +2 -2
  194. package/src/console/console-router.ts +36 -4
  195. package/src/console/dashboard-assets.ts +9 -9
  196. package/src/console/data-management/routes.ts +3 -3
  197. package/src/console/domain-registration.ts +18 -4
  198. package/src/console/inferhub/client.ts +0 -7
  199. package/src/console/inferhub/key-store.ts +1 -1
  200. package/src/console/inferhub/normalize.ts +2 -2
  201. package/src/console/inferhub/routes.ts +1 -1
  202. package/src/console/inferhub/types.ts +1 -1
  203. package/src/console/observability/contracts.ts +5 -1
  204. package/src/console/observability/live.ts +34 -21
  205. package/src/console/observability/logs.ts +4 -4
  206. package/src/console/observability/performance.ts +3 -3
  207. package/src/console/observability/routes.ts +3 -3
  208. package/src/console/observability/sse.ts +62 -8
  209. package/src/console/observability/store.ts +36 -20
  210. package/src/console/providers/catalog/catalog-projections.ts +1 -1
  211. package/src/console/providers/catalog/contracts.ts +82 -22
  212. package/src/console/providers/catalog/model-operations.ts +1 -1
  213. package/src/console/providers/catalog/provider-operations.ts +110 -17
  214. package/src/console/providers/catalog/public-model-store.ts +0 -0
  215. package/src/console/providers/catalog/routes.ts +30 -6
  216. package/src/console/providers/catalog/store-helpers.ts +349 -326
  217. package/src/console/providers/catalog/store.ts +1662 -1292
  218. package/src/console/providers/detail/routes.ts +4 -4
  219. package/src/console/providers/oauth/callback-listener.ts +100 -18
  220. package/src/console/providers/oauth/routes.ts +95 -16
  221. package/src/console/quota/account-quota-global.ts +41 -3
  222. package/src/console/quota/account-quota-shared.ts +10 -3
  223. package/src/console/quota/account-quota-tenant.ts +285 -67
  224. package/src/console/quota/account-test-egress.ts +4 -4
  225. package/src/console/quota/daily-growth-job.ts +308 -0
  226. package/src/console/quota/native-identity.ts +2 -2
  227. package/src/console/quota/quota-view.ts +1 -1
  228. package/src/console/remote-support/routes.ts +1 -1
  229. package/src/console/remote-support/service.ts +2 -2
  230. package/src/console/routing/model/contracts.ts +1 -1
  231. package/src/console/routing/model/routes.ts +3 -3
  232. package/src/console/routing/pools/contracts.ts +13 -10
  233. package/src/console/routing/pools/import-parse.ts +3 -3
  234. package/src/console/routing/pools/operations.ts +14 -7
  235. package/src/console/routing/pools/probe-verdict.ts +8 -3
  236. package/src/console/routing/pools/relay-deploy.ts +12 -12
  237. package/src/console/routing/pools/routes.ts +3 -3
  238. package/src/console/routing/pools/store.ts +21 -1
  239. package/src/console/settings/contracts.ts +29 -2
  240. package/src/console/settings/routes.ts +3 -3
  241. package/src/console/settings/store.ts +20 -0
  242. package/src/console/share/share-router.ts +112 -44
  243. package/src/console/share/share-stats.ts +109 -39
  244. package/src/console/share/share-usage.ts +1 -1
  245. package/src/console/shared/errors.ts +2 -2
  246. package/src/console/shared/object.ts +18 -0
  247. package/src/console/shared/read-through-cache.ts +42 -6
  248. package/src/console/shared/transaction.ts +14 -0
  249. package/src/console/system-prompt/contracts.ts +89 -12
  250. package/src/console/system-prompt/routes.ts +98 -45
  251. package/src/console/updates/apply-update.ts +244 -0
  252. package/src/console/updates/routes.ts +256 -98
  253. package/src/main.ts +11 -5
  254. package/src/network/http2-bidi.ts +1 -1
  255. package/src/network/ip-utils.ts +298 -0
  256. package/src/network/outbound-fetch.ts +76 -5
  257. package/src/network/pool/agent.ts +7 -6
  258. package/src/network/pool/byte-accounting.ts +1 -1
  259. package/src/network/pool/resolver.ts +55 -51
  260. package/src/network/pool/selector.ts +150 -136
  261. package/src/network/pool-cooldown-store.ts +71 -16
  262. package/src/network/pool-health-machine.ts +22 -2
  263. package/src/network/rate-limit-verdict.ts +68 -0
  264. package/src/network/retry.ts +1 -1
  265. package/src/network/ssrf.ts +24 -75
  266. package/src/observability/event-log.ts +2 -2
  267. package/src/observability/event-query.ts +286 -214
  268. package/src/observability/log-sanitize.ts +1 -1
  269. package/src/observability/metrics.ts +4 -4
  270. package/src/observability/payload-capture.ts +6 -5
  271. package/src/observability/payload-store.ts +1 -1
  272. package/src/observability/runtime-metrics.ts +1 -1
  273. package/src/observability/telemetry-buffer.ts +12 -3
  274. package/src/observability/telemetry-reconciliation.ts +3 -3
  275. package/src/observability/telemetry-status.ts +1 -1
  276. package/src/observability/token-speed.ts +1 -1
  277. package/src/persistence/connection-url.ts +1 -1
  278. package/src/persistence/db-handle.ts +1 -1
  279. package/src/persistence/db-pg.ts +2 -2
  280. package/src/persistence/db-sqlite.ts +10 -5
  281. package/src/persistence/dialect.ts +5 -1
  282. package/src/persistence/readiness.ts +19 -7
  283. package/src/persistence/redis.ts +1 -1
  284. package/src/persistence/schema.ts +177 -45
  285. package/src/persistence/shared-cache.ts +2 -2
  286. package/src/persistence/sort-order.ts +1 -1
  287. package/src/persistence/stores/api-key-store.ts +109 -4
  288. package/src/persistence/stores/share-store.ts +20 -8
  289. package/src/persistence/stores/telemetry-store.ts +1 -1
  290. package/src/persistence/system-prompt-store.ts +63 -18
  291. package/src/persistence/tenant-preferences.ts +1 -1
  292. package/src/persistence/ttl-cache.ts +3 -3
  293. package/src/persistence/usage-flush.ts +7 -2
  294. package/src/protocol/canonical-model.ts +1 -1
  295. package/src/protocol/codecs.ts +12 -16
  296. package/src/protocol/dsml.ts +3 -49
  297. package/src/protocol/gateway-error.ts +6 -3
  298. package/src/protocol/image-clamp.ts +2 -2
  299. package/src/protocol/image-generation.ts +2 -2
  300. package/src/protocol/reasoning-text.ts +1 -1
  301. package/src/protocol/reasoning.ts +7 -52
  302. package/src/protocol/registry.ts +50 -15
  303. package/src/protocol/request/chat.ts +46 -19
  304. package/src/protocol/request/codex.ts +1 -1
  305. package/src/protocol/request/messages.ts +46 -14
  306. package/src/protocol/request/responses.ts +19 -10
  307. package/src/protocol/response/chat.ts +27 -12
  308. package/src/protocol/response/codex.ts +2 -2
  309. package/src/protocol/response/gemini.ts +1 -1
  310. package/src/protocol/response/messages.ts +6 -6
  311. package/src/protocol/response/omp-tool-call-markup.ts +1 -1
  312. package/src/protocol/response/responses.ts +3 -3
  313. package/src/protocol/sse-decoder.ts +64 -4
  314. package/src/protocol/stop-reason.ts +2 -2
  315. package/src/protocol/think-split.ts +347 -0
  316. package/src/protocol/translation/attachment-integrity.ts +3 -3
  317. package/src/protocol/translation/cache-controls.ts +8 -20
  318. package/src/protocol/translation/capabilities.ts +8 -8
  319. package/src/protocol/translation/dialect/deepseek.ts +10 -0
  320. package/src/protocol/translation/dialect/inband.ts +39 -0
  321. package/src/protocol/translation/dialect/model-thinking.ts +89 -0
  322. package/src/protocol/translation/dialect/qwen.ts +114 -0
  323. package/src/protocol/translation/dialect/resolver.ts +83 -0
  324. package/src/protocol/translation/dialect/rules.ts +93 -0
  325. package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
  326. package/src/protocol/translation/dialect/types.ts +58 -0
  327. package/src/protocol/translation/quirks.ts +18 -4
  328. package/src/protocol/translation/thinking.ts +12 -252
  329. package/src/protocol/translation/tool-id.ts +3 -3
  330. package/src/protocol/translation/tool-repair.ts +1 -1
  331. package/src/protocol/upstream/post-json.ts +6 -1
  332. package/src/protocol/upstream/send-claude-messages.ts +3 -3
  333. package/src/providers/adapters/base-adapter.ts +1 -1
  334. package/src/providers/adapters/compatible-adapter.ts +44 -5
  335. package/src/providers/authentication/jwt-validator.ts +0 -5
  336. package/src/providers/authentication/oauth-client.ts +254 -253
  337. package/src/providers/authentication/oauth-flow-store.ts +42 -7
  338. package/src/providers/authentication/oauth-refresh-service.ts +2 -2
  339. package/src/providers/bundled-discovery-providers.ts +6 -30
  340. package/src/providers/configured-openai-providers.ts +82 -97
  341. package/src/providers/configured-provider.ts +1 -1
  342. package/src/providers/default-registry.ts +23 -35
  343. package/src/providers/discovery/catalog/catalog-format.ts +13 -2
  344. package/src/providers/discovery/discovery-types.ts +0 -1
  345. package/src/providers/discovery/openai-model-discovery.ts +2 -2
  346. package/src/providers/discovery/probe-phases.ts +50 -15
  347. package/src/providers/discovery/probing-service.ts +18 -20
  348. package/src/providers/integrations/agentrouter/agentrouter.ts +14 -5
  349. package/src/providers/integrations/alibabacp/alibabacp.ts +2 -2
  350. package/src/providers/integrations/anthropic.ts +4 -11
  351. package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
  352. package/src/providers/integrations/antigravity/antigravity-protocol.ts +0 -14
  353. package/src/providers/integrations/antigravity/antigravity.ts +15 -26
  354. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +2 -2
  355. package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
  356. package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
  357. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +37 -6
  358. package/src/providers/integrations/buddy/buddy-identity.ts +108 -1
  359. package/src/providers/integrations/buddy/buddy-media.ts +16 -16
  360. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
  361. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
  362. package/src/providers/integrations/buddy/codebuddy/provider.ts +5 -16
  363. package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
  364. package/src/providers/integrations/buddy/workbuddy/provider.ts +6 -10
  365. package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
  366. package/src/providers/integrations/claude/claude-betas.ts +1 -1
  367. package/src/providers/integrations/claude/claude-cch.ts +148 -148
  368. package/src/providers/integrations/claude/claude-credentials.ts +1 -1
  369. package/src/providers/integrations/claude/claude-slow-lane-retry.ts +1 -1
  370. package/src/providers/integrations/claude/claude.ts +3 -10
  371. package/src/providers/integrations/claude/fallback-credit.ts +3 -7
  372. package/src/providers/integrations/cline/cline.ts +2 -2
  373. package/src/providers/integrations/cloudflareai/cloudflareai.ts +4 -7
  374. package/src/providers/integrations/codex/codex-device-code.ts +101 -101
  375. package/src/providers/integrations/codex/codex-errors.ts +1 -1
  376. package/src/providers/integrations/codex/codex-oauth.ts +0 -1
  377. package/src/providers/integrations/codex/codex.ts +14 -15
  378. package/src/providers/integrations/commandcode/commandcode.ts +76 -116
  379. package/src/providers/integrations/commandcode/quota.ts +132 -48
  380. package/src/providers/integrations/cursor/cursor-http2.ts +11 -14
  381. package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
  382. package/src/providers/integrations/cursor/cursor-request.ts +0 -87
  383. package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
  384. package/src/providers/integrations/cursor/cursor.ts +53 -20
  385. package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
  386. package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
  387. package/src/providers/integrations/factory/factory.ts +13 -13
  388. package/src/providers/integrations/gemini.ts +11 -11
  389. package/src/providers/integrations/github/github-discovery.ts +55 -10
  390. package/src/providers/integrations/github/github-oauth.ts +6 -5
  391. package/src/providers/integrations/github/github.ts +47 -20
  392. package/src/providers/integrations/grok/grok-oauth.ts +261 -261
  393. package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
  394. package/src/providers/integrations/grok/grok-quota.ts +16 -7
  395. package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
  396. package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
  397. package/src/providers/integrations/grok/grok.ts +88 -42
  398. package/src/providers/integrations/inferhub.ts +4 -11
  399. package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
  400. package/src/providers/integrations/kimi/kimi.ts +4 -11
  401. package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
  402. package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
  403. package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
  404. package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
  405. package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
  406. package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
  407. package/src/providers/integrations/kiro/kiro-request.ts +8 -11
  408. package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
  409. package/src/providers/integrations/kiro/kiro.ts +91 -78
  410. package/src/providers/integrations/muse/muse-oauth.ts +0 -1
  411. package/src/providers/integrations/muse/muse-quota.ts +0 -4
  412. package/src/providers/integrations/muse/muse.ts +6 -9
  413. package/src/providers/integrations/opencode/fingerprint.ts +7 -5
  414. package/src/providers/integrations/opencode/provider.ts +17 -24
  415. package/src/providers/integrations/perplexity.ts +2 -2
  416. package/src/providers/integrations/qoder/qoder-catalog.ts +132 -17
  417. package/src/providers/integrations/qoder/qoder-checkin.ts +26 -8
  418. package/src/providers/integrations/qoder/qoder-native-identity-store.ts +9 -8
  419. package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
  420. package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
  421. package/src/providers/integrations/qoder/qoder-realm.ts +22 -28
  422. package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
  423. package/src/providers/integrations/qoder/qoder-umid.ts +33 -38
  424. package/src/providers/integrations/qoder/qoder-virtual.ts +14 -2
  425. package/src/providers/integrations/qoder/qoder.ts +521 -63
  426. package/src/providers/integrations/shared/connect.ts +0 -54
  427. package/src/providers/integrations/shared/hash.ts +15 -0
  428. package/src/providers/integrations/shared/session-cache.ts +136 -0
  429. package/src/providers/integrations/tokenharbor.ts +2 -2
  430. package/src/providers/integrations/trae/trae-cache.ts +7 -87
  431. package/src/providers/integrations/trae/trae-catalog.ts +1 -6
  432. package/src/providers/integrations/trae/trae-protocol.ts +17 -8
  433. package/src/providers/integrations/trae/trae-realm.ts +0 -7
  434. package/src/providers/integrations/trae/trae.ts +59 -19
  435. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  436. package/src/providers/integrations/zcode/oauth.ts +1 -1
  437. package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
  438. package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
  439. package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
  440. package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
  441. package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
  442. package/src/providers/operations/account-error-classification.ts +131 -116
  443. package/src/providers/operations/account-health-service.ts +31 -39
  444. package/src/providers/operations/account-reset-service.ts +58 -1
  445. package/src/providers/operations/cli-platform.ts +31 -5
  446. package/src/providers/operations/client-version-resolver.ts +4 -6
  447. package/src/providers/operations/client-versions.ts +10 -7
  448. package/src/providers/operations/provider-catalog-seeder.ts +2 -0
  449. package/src/providers/operations/provider-catalog-service.ts +22 -6
  450. package/src/providers/operations/provider-credential-service.ts +35 -6
  451. package/src/providers/operations/upstream-deadline.ts +3 -3
  452. package/src/providers/provider-contracts.ts +65 -10
  453. package/src/providers/provider-credential-resolver.ts +1 -1
  454. package/src/providers/provider-metadata.ts +17 -2
  455. package/src/providers/provider-model-definition.ts +22 -1
  456. package/src/providers/provider-probe.ts +4 -2
  457. package/src/providers/provider-registry.ts +4 -4
  458. package/src/providers/provider-usage.ts +81 -16
  459. package/src/providers/quota/cache.ts +29 -0
  460. package/src/providers/quota/quota-contracts.ts +28 -10
  461. package/src/providers/quota/refresh.ts +29 -6
  462. package/src/providers/quota/snapshot.ts +94 -0
  463. package/src/providers/search/search-provider.ts +6 -8
  464. package/src/providers/search/search-providers.ts +2 -1
  465. package/src/security/abuse.ts +8 -8
  466. package/src/security/admission/reasons.ts +17 -17
  467. package/src/security/admission/service.ts +2 -2
  468. package/src/security/admission/ttl.ts +61 -61
  469. package/src/security/api-key-auth.ts +20 -8
  470. package/src/security/client-router-fingerprint.ts +4 -4
  471. package/src/security/credential-codec.ts +3 -3
  472. package/src/security/csrf.ts +2 -2
  473. package/src/security/ip-boundary.ts +16 -189
  474. package/src/security/model-access-rule.ts +1 -1
  475. package/src/security/outbound-headers.ts +18 -0
  476. package/src/shared/coerce.ts +19 -0
  477. package/src/shared/invoke-guard.ts +47 -0
  478. package/src/transport/contracts.ts +13 -4
  479. package/src/transport/dispatch/attempt-finalize.ts +5 -4
  480. package/src/transport/dispatch/attempt-loop.ts +10 -7
  481. package/src/transport/dispatch/capture-policy.ts +34 -37
  482. package/src/transport/dispatch/empty-stream.ts +28 -25
  483. package/src/transport/dispatch/generation.ts +33 -53
  484. package/src/transport/dispatch/leases.ts +8 -8
  485. package/src/transport/dispatch/native-shared.ts +127 -0
  486. package/src/transport/dispatch/proxy-request.ts +10 -8
  487. package/src/transport/dispatch/responses-compact.ts +35 -56
  488. package/src/transport/dispatch/retry-policy.ts +4 -67
  489. package/src/transport/dispatch/stream-bridge.ts +1 -1
  490. package/src/transport/dispatch/streaming/encoder.ts +18 -72
  491. package/src/transport/dispatch/streaming/finalize.ts +11 -10
  492. package/src/transport/dispatch/streaming/stream.ts +7 -3
  493. package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
  494. package/src/transport/dispatch/systemone.ts +27 -55
  495. package/src/transport/dispatch/token-count.ts +49 -46
  496. package/src/transport/dispatch/websearch.ts +24 -50
  497. package/src/transport/drain-endpoint.ts +3 -3
  498. package/src/transport/failure-policy.ts +19 -6
  499. package/src/transport/guards/auth-guard.ts +6 -11
  500. package/src/transport/guards/body-policy.ts +7 -7
  501. package/src/transport/guards/error-lifecycle.ts +18 -3
  502. package/src/transport/guards/guard-errors.ts +7 -3
  503. package/src/transport/guards/headroom-guard.ts +2 -2
  504. package/src/transport/guards/pipeline.ts +7 -7
  505. package/src/transport/guards/readiness-guard.ts +16 -2
  506. package/src/transport/guards/request-context.ts +15 -20
  507. package/src/transport/request/preparer.ts +306 -27
  508. package/src/transport/request/rtk/compress-request.ts +3 -3
  509. package/src/transport/request/rtk/rtk-constants.ts +2 -2
  510. package/src/transport/request/rtk/rtk-filters.ts +8 -8
  511. package/src/transport/request/state.ts +5 -20
  512. package/src/transport/request/system-prompt-injection.ts +74 -11
  513. package/src/transport/request/tenant-preferences.ts +22 -0
  514. package/src/transport/routing/candidate-index.ts +2 -2
  515. package/src/transport/routing/round-robin.ts +1 -1
  516. package/src/transport/routing/route-catalog.ts +113 -19
  517. package/src/transport/routing/route-model.ts +131 -38
  518. package/src/transport/routing/router.ts +154 -39
  519. package/src/transport/shutdown-notice.ts +21 -9
  520. package/src/transport/surface/adapters.ts +3 -3
  521. package/src/transport/surface/chat/encode.ts +7 -7
  522. package/src/transport/surface/chat/parse.ts +7 -7
  523. package/src/transport/surface/completion.ts +3 -3
  524. package/src/transport/surface/content-parts.ts +1 -1
  525. package/src/transport/surface/dialects.ts +2 -2
  526. package/src/transport/surface/messages/encode.ts +1 -1
  527. package/src/transport/surface/messages/parse.ts +3 -3
  528. package/src/transport/surface/responses/adapter.ts +1 -1
  529. package/src/transport/surface/responses/errors.ts +0 -9
  530. package/src/transport/vision-handoff-cache.ts +58 -0
  531. package/src/transport/vision-handoff.ts +376 -0
  532. package/src/workers/account-identity-sweep.ts +2 -2
  533. package/src/workers/buddy-growth-tasks.ts +392 -346
  534. package/src/workers/daily-checkin.ts +102 -49
  535. package/src/workers/maintenance-lease.ts +2 -35
  536. package/src/workers/oauth-refresh-sweep.ts +8 -1
  537. package/src/workers/quota-refresh-sweep.ts +120 -82
  538. package/src/workers/scheduler.ts +67 -4
  539. package/src/workers/sweep-runner.ts +24 -5
  540. package/src/workers/zcode-gift-claim.ts +108 -0
  541. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
  542. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
  543. package/dist/dashboard/assets/BannedPage-2TJD37Hb.js.gz +0 -0
  544. package/dist/dashboard/assets/CliToolDetailPage-xefJNRmJ.js.gz +0 -0
  545. package/dist/dashboard/assets/CliToolsPage-Rj9iHQ3F.js.gz +0 -0
  546. package/dist/dashboard/assets/CombosPage-JEbYJFxw.js +0 -1
  547. package/dist/dashboard/assets/CombosPage-JEbYJFxw.js.gz +0 -0
  548. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js +0 -1
  549. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js.gz +0 -0
  550. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js +0 -1
  551. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js.gz +0 -0
  552. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js +0 -1
  553. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js.gz +0 -0
  554. package/dist/dashboard/assets/LoginPage-C4w7vea-.js.gz +0 -0
  555. package/dist/dashboard/assets/ModelPicker-BtPcAfot.js.gz +0 -0
  556. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js +0 -1
  557. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js.gz +0 -0
  558. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js +0 -4
  559. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js.gz +0 -0
  560. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
  561. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
  562. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js +0 -1
  563. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js.gz +0 -0
  564. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js +0 -9
  565. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js.gz +0 -0
  566. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js +0 -1
  567. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js.gz +0 -0
  568. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js +0 -1
  569. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js.gz +0 -0
  570. package/dist/dashboard/assets/SetupPage-BQS0Rx_u.js.gz +0 -0
  571. package/dist/dashboard/assets/SortableList-BAL5npBC.js +0 -1
  572. package/dist/dashboard/assets/SortableList-BAL5npBC.js.gz +0 -0
  573. package/dist/dashboard/assets/StudioPage-TP7voAQ0.js.gz +0 -0
  574. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js +0 -56
  575. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js.gz +0 -0
  576. package/dist/dashboard/assets/api-keys-MbI7e7rt.js +0 -1
  577. package/dist/dashboard/assets/api-keys-MbI7e7rt.js.gz +0 -0
  578. package/dist/dashboard/assets/app-B2vyPoII.css +0 -2
  579. package/dist/dashboard/assets/app-B2vyPoII.css.gz +0 -0
  580. package/dist/dashboard/assets/assert-C0YYuZJ4.js.gz +0 -0
  581. package/dist/dashboard/assets/badge-B_DMpMJN.js.gz +0 -0
  582. package/dist/dashboard/assets/banner-DMrMPmth.js.gz +0 -0
  583. package/dist/dashboard/assets/card-Be5Uzamx.js.gz +0 -0
  584. package/dist/dashboard/assets/cli-tools-muFRphDu.js.gz +0 -0
  585. package/dist/dashboard/assets/clipboard-button-DOfrVmsi.js.gz +0 -0
  586. package/dist/dashboard/assets/dialog-C9omdjQt.js.gz +0 -0
  587. package/dist/dashboard/assets/drawer-Bm8WKaGY.js.gz +0 -0
  588. package/dist/dashboard/assets/entry-DS90gUks.js +0 -1
  589. package/dist/dashboard/assets/entry-DS90gUks.js.gz +0 -0
  590. package/dist/dashboard/assets/entry-j40LJotO.js +0 -4
  591. package/dist/dashboard/assets/entry-j40LJotO.js.gz +0 -0
  592. package/dist/dashboard/assets/entry-q5HwZ8nN.js.gz +0 -0
  593. package/dist/dashboard/assets/formatters-BTScrQpe.js.gz +0 -0
  594. package/dist/dashboard/assets/github-badge-Orjuzemr.js.gz +0 -0
  595. package/dist/dashboard/assets/index-cPrX5vn6.js.gz +0 -0
  596. package/dist/dashboard/assets/inline-Dvux8w-0.js.gz +0 -0
  597. package/dist/dashboard/assets/input-CU1Rgf3p.js.gz +0 -0
  598. package/dist/dashboard/assets/list-row-CzFvogbj.js.gz +0 -0
  599. package/dist/dashboard/assets/live-KaG15HLQ.js +0 -1
  600. package/dist/dashboard/assets/live-KaG15HLQ.js.gz +0 -0
  601. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +0 -1
  602. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
  603. package/dist/dashboard/assets/mutation-JJGQm8TD.js.gz +0 -0
  604. package/dist/dashboard/assets/numbers-BNDZnsUE.js +0 -2
  605. package/dist/dashboard/assets/numbers-BNDZnsUE.js.gz +0 -0
  606. package/dist/dashboard/assets/query-keys-CLaNz8Xz.js.gz +0 -0
  607. package/dist/dashboard/assets/quota-DZGyp0N5.js +0 -1
  608. package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
  609. package/dist/dashboard/assets/routing-BEH32QOC.js.gz +0 -0
  610. package/dist/dashboard/assets/select-B3iTetHN.js.gz +0 -0
  611. package/dist/dashboard/assets/settings-Dt3Eqbnq.js +0 -1
  612. package/dist/dashboard/assets/settings-Dt3Eqbnq.js.gz +0 -0
  613. package/dist/dashboard/assets/stack-KrOrm7JZ.js.gz +0 -0
  614. package/dist/dashboard/assets/state-DLS7IDMy.js.gz +0 -0
  615. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
  616. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
  617. package/dist/dashboard/assets/switch-42ItvbAs.js.gz +0 -0
  618. package/dist/dashboard/assets/useMutation-Dmnfh1Ue.js.gz +0 -0
  619. package/src/network/response-headers.ts +0 -39
  620. package/src/protocol/response/dsml.ts +0 -38
  621. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
  622. /package/dist/dashboard/assets/{app-wvwCi4Eh.js → app-Bgd3zANQ.js} +0 -0
  623. /package/dist/dashboard/assets/{app-wvwCi4Eh.js.gz → app-Bgd3zANQ.js.gz} +0 -0
  624. /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
  625. /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Qwen chat-template in-band tool calls.
3
+ *
4
+ * Qwen3-family models emit tool calls as JSON blocks inside the text stream
5
+ * when the server's structured tool parser is not in use:
6
+ *
7
+ * <tool_call>
8
+ * {"name": "web_search", "arguments": {"query": "..."}}
9
+ * </tool_call>
10
+ *
11
+ * The scanner recovers complete blocks into canonical tool calls and leaves the
12
+ * rest as text, mirroring the DSML/OMP scanners used for other families.
13
+ */
14
+ import type { InbandScanner, InbandScanResult } from "./inband";
15
+
16
+ const OPEN_TAG = "<tool_call>";
17
+ const CLOSE_TAG = "</tool_call>";
18
+
19
+ export class QwenToolCallScanner implements InbandScanner {
20
+ readonly #allowedNames: ReadonlySet<string>;
21
+ #pending = "";
22
+ #sequence = 0;
23
+
24
+ constructor(allowedNames: ReadonlySet<string>) {
25
+ this.#allowedNames = allowedNames;
26
+ }
27
+
28
+ push(chunk: string): InbandScanResult {
29
+ this.#pending += chunk;
30
+ let cursor = 0;
31
+ let text = "";
32
+ const calls: Array<InbandScanResult["calls"][number]> = [];
33
+ for (;;) {
34
+ const open = this.#pending.indexOf(OPEN_TAG, cursor);
35
+ if (open < 0) {
36
+ // Hold a possible pending opener at the tail; settle everything before it.
37
+ text += this.#pending.slice(cursor, this.#settledEnd(this.#pending.length));
38
+ cursor = this.#settledEnd(this.#pending.length);
39
+ break;
40
+ }
41
+ text += this.#pending.slice(cursor, open);
42
+ const bodyStart = open + OPEN_TAG.length;
43
+ const close = this.#pending.indexOf(CLOSE_TAG, bodyStart);
44
+ if (close < 0) {
45
+ // Unterminated block: hold from the opener on and settle what preceded it.
46
+ cursor = open;
47
+ break;
48
+ }
49
+ const inner = this.#pending.slice(bodyStart, close).trim();
50
+ const parsed = parseToolCall(inner);
51
+ if (parsed !== undefined) {
52
+ if (this.#allowedNames.has(parsed.name)) {
53
+ calls.push({
54
+ id: `call_qwen_${this.#sequence++}`,
55
+ name: parsed.name,
56
+ arguments: parsed.arguments,
57
+ });
58
+ } else {
59
+ // An undeclared tool is model text, not authority to invoke it.
60
+ text += this.#pending.slice(open, close + CLOSE_TAG.length);
61
+ }
62
+ } else {
63
+ text += this.#pending.slice(open, close + CLOSE_TAG.length);
64
+ }
65
+ cursor = close + CLOSE_TAG.length;
66
+ }
67
+ this.#pending = this.#pending.slice(cursor);
68
+ return { text, calls };
69
+ }
70
+
71
+ flush(): InbandScanResult {
72
+ const pending = this.#pending;
73
+ this.#pending = "";
74
+ if (isPossibleOpener(pending)) return { text: "", calls: [] };
75
+ return { text: pending, calls: [] };
76
+ }
77
+
78
+ #settledEnd(end: number): number {
79
+ // Keep a trailing fragment that could be the start of an opener.
80
+ const tail = this.#pending.slice(0, end);
81
+ const maxPrefix = Math.min(OPEN_TAG.length - 1, tail.length);
82
+ for (let len = maxPrefix; len > 0; len -= 1) {
83
+ if (OPEN_TAG.startsWith(tail.slice(-len))) return end - len;
84
+ }
85
+ return end;
86
+ }
87
+ }
88
+
89
+ function parseToolCall(inner: string): { readonly name: string; readonly arguments: string } | undefined {
90
+ if (inner.length === 0) return undefined;
91
+ let value: unknown;
92
+ try {
93
+ value = JSON.parse(inner);
94
+ } catch {
95
+ return undefined;
96
+ }
97
+ if (typeof value !== "object" || value === null) return undefined;
98
+ const record = value as Record<string, unknown>;
99
+ const name = typeof record["name"] === "string" ? record["name"] : undefined;
100
+ if (name === undefined || name.length === 0) return undefined;
101
+ const args = record["arguments"] ?? record["parameters"] ?? {};
102
+ let argsText: string;
103
+ try {
104
+ argsText = typeof args === "string" ? args : JSON.stringify(args);
105
+ } catch {
106
+ argsText = "{}";
107
+ }
108
+ return { name, arguments: argsText };
109
+ }
110
+
111
+ function isPossibleOpener(value: string): boolean {
112
+ if (value.length < OPEN_TAG.length) return OPEN_TAG.startsWith(value);
113
+ return value.startsWith(OPEN_TAG) && !value.includes(CLOSE_TAG);
114
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Dialect resolver — pure, never throws, always returns a policy.
3
+ *
4
+ * Precedence:
5
+ * 1. explicit DB override (`models.dialect`; passed as `override`)
6
+ * 2. explicit `ModelDefinition.dialect` (passed as `declared`)
7
+ * 3. heuristic rules (`DIALECT_RULES`)
8
+ * 4. family default (`anthropic` for messages, `openai` otherwise)
9
+ *
10
+ * The default policies reproduce today's exact behavior: a request with no
11
+ * dialect set encodes byte-identically to before this layer existed.
12
+ */
13
+ import type { WireFamily } from "../../canonical-model";
14
+ import { DEFAULT_DIALECT_POLICIES, DIALECT_RULES } from "./rules";
15
+ import type { DialectId, DialectPolicy } from "./types";
16
+ import { BoundedLruMap } from "../../../transport/routing/bounded-lru";
17
+
18
+ /** Known dialect ids, for validating loose DB/string overrides. */
19
+ const KNOWN_DIALECT_IDS = new Set<string>(Object.keys(DEFAULT_DIALECT_POLICIES));
20
+
21
+ /**
22
+ * Memoization for `resolveDialect` (mirrors THINKING_RESOLVE_CACHE). The key
23
+ * concatenates every argument, all of which are value types, so it is
24
+ * collision-safe. The cache is a {@link BoundedLruMap}: the key space is
25
+ * bounded by the model catalog, but a request can name an arbitrary model
26
+ * string, so an unbounded map would pin an entry for every miss forever.
27
+ */
28
+ const DIALECT_RESOLVE_CACHE_MAX_ENTRIES = 1024;
29
+ const DIALECT_RESOLVE_CACHE = new BoundedLruMap<string, DialectPolicy>(
30
+ DIALECT_RESOLVE_CACHE_MAX_ENTRIES,
31
+ );
32
+
33
+ export function resolveDialect(
34
+ modelId: string,
35
+ providerId: string,
36
+ wireFamily: WireFamily,
37
+ override?: string | null,
38
+ declared?: DialectId,
39
+ ): DialectPolicy {
40
+ const key = `${modelId.toLowerCase()}|${providerId}|${wireFamily}|${override ?? ""}|${declared ?? ""}`;
41
+ const cached = DIALECT_RESOLVE_CACHE.get(key);
42
+ if (cached !== undefined) return cached;
43
+ const policy = resolveDialectUncached(modelId, providerId, wireFamily, override, declared);
44
+ DIALECT_RESOLVE_CACHE.set(key, policy);
45
+ return policy;
46
+ }
47
+
48
+ function resolveDialectUncached(
49
+ modelId: string,
50
+ providerId: string,
51
+ wireFamily: WireFamily,
52
+ override?: string | null,
53
+ declared?: DialectId,
54
+ ): DialectPolicy {
55
+ const id = pickDialect(modelId, providerId, wireFamily, override, declared);
56
+ const policy = DEFAULT_DIALECT_POLICIES[id];
57
+ if (policy !== undefined) return policy;
58
+
59
+ // An unknown dialect id (e.g. from a future DB row) falls back to the
60
+ // family default — never throw, never invent behavior.
61
+ return DEFAULT_DIALECT_POLICIES[familyDefault(wireFamily)];
62
+ }
63
+
64
+ function pickDialect(
65
+ modelId: string,
66
+ providerId: string,
67
+ wireFamily: WireFamily,
68
+ override?: string | null,
69
+ declared?: DialectId,
70
+ ): DialectId {
71
+ if (override !== undefined && override !== null && KNOWN_DIALECT_IDS.has(override)) {
72
+ return override as DialectId;
73
+ }
74
+ if (declared !== undefined) return declared;
75
+ for (const rule of DIALECT_RULES) {
76
+ if (rule.match(modelId, providerId, wireFamily)) return rule.dialect;
77
+ }
78
+ return familyDefault(wireFamily);
79
+ }
80
+
81
+ function familyDefault(wireFamily: WireFamily): DialectId {
82
+ return wireFamily === "messages" ? "anthropic" : "openai";
83
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Dialect policies & heuristic rules.
3
+ *
4
+ * The default policies are frozen to today's behavior — they are the baseline
5
+ * the golden tests assert against. A dialect not listed here falls back to the
6
+ * family default in `resolver.ts`.
7
+ */
8
+ import type { WireFamily } from "../../canonical-model";
9
+ import type { DialectId, DialectPolicy } from "./types";
10
+
11
+ /** The generic OpenAI-compatible default — mirrors current `chat` wire behavior. */
12
+ const OPENAI_POLICY: DialectPolicy = {
13
+ reasoningContentField: "reasoning_content",
14
+ maxTokensField: "max_tokens",
15
+ stripSpecialTokens: false,
16
+ supportsMultipleSystemMessages: true,
17
+ supportsToolChoice: true,
18
+ requiresAssistantContentForToolCalls: false,
19
+ allowsSyntheticReasoningContent: true,
20
+ thinkingFormat: "openai",
21
+ inband: null,
22
+ };
23
+
24
+ /** The generic Anthropic/Messages default. */
25
+ const ANTHROPIC_POLICY: DialectPolicy = {
26
+ maxTokensField: "max_tokens",
27
+ stripSpecialTokens: false,
28
+ supportsMultipleSystemMessages: true,
29
+ supportsToolChoice: true,
30
+ requiresAssistantContentForToolCalls: false,
31
+ allowsSyntheticReasoningContent: true,
32
+ thinkingFormat: "openai",
33
+ inband: null,
34
+ };
35
+
36
+ /** DeepSeek: `reasoning_content`, `max_tokens`, no tool_choice, DSML in-band. */
37
+ const DEEPSEEK_POLICY: DialectPolicy = {
38
+ reasoningContentField: "reasoning_content",
39
+ maxTokensField: "max_tokens",
40
+ stripSpecialTokens: "deepseek",
41
+ supportsMultipleSystemMessages: true,
42
+ supportsToolChoice: false,
43
+ requiresAssistantContentForToolCalls: true,
44
+ allowsSyntheticReasoningContent: false,
45
+ thinkingFormat: "deepseek",
46
+ inband: "deepseek",
47
+ };
48
+
49
+ /** Qwen: `enable_thinking` + `<tool_call>` chat template, strict system cardinality. */
50
+ const QWEN_POLICY: DialectPolicy = {
51
+ reasoningContentField: "reasoning_content",
52
+ maxTokensField: "max_tokens",
53
+ stripSpecialTokens: false,
54
+ supportsMultipleSystemMessages: false,
55
+ supportsToolChoice: true,
56
+ requiresAssistantContentForToolCalls: false,
57
+ allowsSyntheticReasoningContent: true,
58
+ thinkingFormat: "qwen",
59
+ inband: "qwen",
60
+ };
61
+
62
+ /** Resolved policy per dialect id. A missing id falls back in `resolver.ts`. */
63
+ export const DEFAULT_DIALECT_POLICIES: Readonly<Record<DialectId, DialectPolicy>> = {
64
+ openai: OPENAI_POLICY,
65
+ anthropic: ANTHROPIC_POLICY,
66
+ deepseek: DEEPSEEK_POLICY,
67
+ qwen: QWEN_POLICY,
68
+ kimi: OPENAI_POLICY,
69
+ glm: OPENAI_POLICY,
70
+ minimax: OPENAI_POLICY,
71
+ gemini: OPENAI_POLICY,
72
+ };
73
+
74
+ interface DialectRule {
75
+ readonly dialect: DialectId;
76
+ readonly match: (modelId: string, providerId: string, wireFamily: WireFamily) => boolean;
77
+ }
78
+
79
+ /**
80
+ * Heuristic rules (used only when no DB override and no explicit
81
+ * `ModelDefinition.dialect` exists). Declarative and provider/model-id based,
82
+ * matching the precedent of `src/protocol/translation/quirks.ts`.
83
+ */
84
+ export const DIALECT_RULES: readonly DialectRule[] = [
85
+ {
86
+ dialect: "deepseek",
87
+ match: (_modelId, providerId) => providerId.toLowerCase() === "deepseek",
88
+ },
89
+ {
90
+ dialect: "qwen",
91
+ match: (modelId) => /qwen|portal|alibaba|qwq/i.test(modelId),
92
+ },
93
+ ];
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Data-driven thinking/effort ladder for a model + wire family.
3
+ *
4
+ * Replaces the old `resolveSupportedReasoningEfforts` if-chain and
5
+ * `claudeUsesAdaptiveThinking` string matching with a declarative rule table,
6
+ * following the oh-my-pi pattern: a model's reasoning ladder is data (a
7
+ * `ThinkingConfig`), not code. Adding a new model generation is a table row,
8
+ * not another `if (id.includes(...))`.
9
+ *
10
+ * Precedence:
11
+ * 1. explicit declared efforts (catalog `ModelDefinition.reasoningEfforts`)
12
+ * 2. first matching rule in `THINKING_LADDER_RULES`
13
+ * 3. family default (extended ladder, per-family transport mode)
14
+ */
15
+ import type { WireFamily } from "../../canonical-model";
16
+ import {
17
+ REASONING_EFFORT_LADDER,
18
+ type ReasoningEffortLevel,
19
+ } from "../thinking";
20
+ import { BoundedLruMap } from "../../../transport/routing/bounded-lru";
21
+
22
+ /** How a reasoning effort is transported on the wire. */
23
+ export type ThinkingControlMode =
24
+ | "effort" // OpenAI-style `reasoning_effort` / `reasoning.effort`
25
+ | "budget" // Anthropic budget-era: `thinking.enabled` + `budget_tokens` (+ `output_config.effort`)
26
+ | "anthropic-adaptive" // Anthropic adaptive-era: `thinking.adaptive` + `output_config.effort`
27
+ | "google-level"; // Gemini: effort affects the output floor only
28
+
29
+ /**
30
+ * Resolved reasoning config for one model + wire family. The codecs read this
31
+ * instead of re-deriving ladders from model-id heuristics per request.
32
+ */
33
+ export interface ThinkingConfig {
34
+ /** Which wire field/transport the effort rides on. */
35
+ readonly mode: ThinkingControlMode;
36
+ /** Supported efforts, canonical ladder order, never empty. */
37
+ readonly efforts: readonly ReasoningEffortLevel[];
38
+ /** Default effort when the caller expresses none (e.g. DeepSeek forces high). */
39
+ readonly defaultLevel?: ReasoningEffortLevel;
40
+ /** True when the upstream rejects off/omitted efforts → clamp up to the floor. */
41
+ readonly requiresEffort?: boolean;
42
+ }
43
+
44
+ /** Optional model-declared thinking override (compile-time, persisted catalog). */
45
+ export interface ThinkingModelDecl {
46
+ readonly efforts?: readonly string[];
47
+ readonly mode?: ThinkingControlMode;
48
+ }
49
+
50
+ /** DeepSeek's default effort, owned here so rule table and helpers agree. */
51
+ export const DEEPSEEK_DEFAULT_EFFORT = "high" as const;
52
+
53
+ /** Responses-wire default: no `max` tier (OpenAI/OpenCode/Azure). */
54
+ const RESPONSES_WIRE_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
55
+ "minimal",
56
+ "low",
57
+ "medium",
58
+ "high",
59
+ "xhigh",
60
+ ];
61
+
62
+ /** Full 6-tier scale (Claude, MiMo, Kimi, DeepSeek). */
63
+ const EXTENDED_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
64
+ "minimal",
65
+ "low",
66
+ "medium",
67
+ "high",
68
+ "xhigh",
69
+ "max",
70
+ ];
71
+
72
+ /** Standard 4-tier scale (Gemini, Qwen). */
73
+ const BASE_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
74
+ "minimal",
75
+ "low",
76
+ "medium",
77
+ "high",
78
+ ];
79
+
80
+ /** `mimo-v2.6` rejects every effort outside this set (live 500s). */
81
+ const MIMO_V26_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = ["low", "medium", "high"];
82
+
83
+ /** Mercury chat ladder: `{instant, low, medium, high}` (live 400s outside). */
84
+ const INCEPTION_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
85
+ "instant",
86
+ "low",
87
+ "medium",
88
+ "high",
89
+ ];
90
+
91
+ /** OpenAI 5.6/6/daybreak + new-gen Claude adaptive: `low..max`, no `minimal`. */
92
+ const LOW_TO_MAX_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
93
+ "low",
94
+ "medium",
95
+ "high",
96
+ "xhigh",
97
+ "max",
98
+ ];
99
+
100
+ /** `gpt-5.5` rows: neither `minimal` nor `max`. */
101
+ const GPT55_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
102
+ "low",
103
+ "medium",
104
+ "high",
105
+ "xhigh",
106
+ ];
107
+
108
+ /** Claude adaptive 4.6 pair: `low..high`. */
109
+ const CLAUDE_ADAPTIVE_46_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
110
+ "low",
111
+ "medium",
112
+ "high",
113
+ ];
114
+
115
+ interface ThinkingLadderRule {
116
+ readonly id?: RegExp;
117
+ readonly provider?: RegExp;
118
+ readonly wireFamily?: WireFamily;
119
+ readonly efforts: readonly ReasoningEffortLevel[];
120
+ readonly mode?: ThinkingControlMode;
121
+ readonly defaultLevel?: ReasoningEffortLevel;
122
+ readonly requiresEffort?: boolean;
123
+ /** True when `id` expects the dot → dash normalized id (Claude generations). */
124
+ readonly normalizeClaudeId?: boolean;
125
+ }
126
+
127
+ /**
128
+ * Rule table — the declarative replacement for the previous if-chain.
129
+ * First match wins; `wireFamily` rules must precede family-agnostic ones so
130
+ * the Responses wire keeps its cap (`no max`) even over Claude-family model
131
+ * ids, exactly like the old `wireFamily === "responses"` early return.
132
+ *
133
+ * Claude generation rules use `normalizeClaudeId` and match against the
134
+ * dot-tolerant form (`claude-opus-4.6` → `claude-opus-4-6`), mirroring the
135
+ * removed `claudeUsesAdaptiveThinking` behavior.
136
+ */
137
+ export const THINKING_LADDER_RULES: readonly ThinkingLadderRule[] = [
138
+ // --- Responses wire (cap at `xhigh` unless a generation ladder says otherwise) ---
139
+ { wireFamily: "responses", id: /gpt-5\.5/, efforts: GPT55_SUPPORTED_EFFORTS },
140
+ { wireFamily: "responses", id: /gpt-5\.6|gpt-6|daybreak/, efforts: LOW_TO_MAX_SUPPORTED_EFFORTS },
141
+ { wireFamily: "responses", efforts: RESPONSES_WIRE_SUPPORTED_EFFORTS },
142
+ // --- Family heuristics (chat/messages/gemini) ---
143
+ { id: /muse/, efforts: RESPONSES_WIRE_SUPPORTED_EFFORTS },
144
+ { id: /gemini/, efforts: BASE_SUPPORTED_EFFORTS, mode: "google-level" },
145
+ { id: /mimo-v2\.6/, efforts: MIMO_V26_SUPPORTED_EFFORTS },
146
+ {
147
+ id: /mercury/,
148
+ wireFamily: "chat",
149
+ efforts: INCEPTION_SUPPORTED_EFFORTS,
150
+ },
151
+ // Claude adaptive 4.6 pair: `low..high`, no `xhigh`/`max`.
152
+ {
153
+ id: /opus-4-6|sonnet-4-6/,
154
+ normalizeClaudeId: true,
155
+ efforts: CLAUDE_ADAPTIVE_46_SUPPORTED_EFFORTS,
156
+ mode: "anthropic-adaptive",
157
+ },
158
+ // New-gen Claude adaptive: `low..max`.
159
+ {
160
+ id: /fable|mythos|opus-5|sonnet-5|opus-4-7|opus-4-8/,
161
+ normalizeClaudeId: true,
162
+ efforts: LOW_TO_MAX_SUPPORTED_EFFORTS,
163
+ mode: "anthropic-adaptive",
164
+ },
165
+ // Budget-era Claude rows: `minimal..xhigh`, no `max`.
166
+ {
167
+ id: /opus-4-5|sonnet-4-5|haiku-4-5|opus-4-1|opus-4-0|sonnet-4-0/,
168
+ normalizeClaudeId: true,
169
+ efforts: RESPONSES_WIRE_SUPPORTED_EFFORTS,
170
+ },
171
+ // Any other Claude row: extended ladder, budget-era transport.
172
+ { id: /claude/, efforts: EXTENDED_SUPPORTED_EFFORTS },
173
+ ];
174
+
175
+ function familyDefaultMode(wireFamily: WireFamily): ThinkingControlMode {
176
+ if (wireFamily === "messages") return "budget";
177
+ if (wireFamily === "gemini") return "google-level";
178
+ return "effort";
179
+ }
180
+
181
+ /**
182
+ * Resolves the thinking config for a model + wire family. Pure, never throws,
183
+ * always returns a config (the family default is the floor).
184
+ *
185
+ * The rule table is deterministic and the codecs call this once per encode, so
186
+ * the no-declared-efforts result (the common case) is memoized per
187
+ * model/wire/provider key. Declared efforts bypass the cache because the
188
+ * `declared` object identity changes per call.
189
+ *
190
+ * The cache is a {@link BoundedLruMap}: the key space is bounded by the model
191
+ * catalog, but a request can name an arbitrary model string, so an unbounded
192
+ * map would pin an entry for every miss forever. The bound keeps memory flat
193
+ * while hot models stay resident.
194
+ */
195
+ const THINKING_RESOLVE_CACHE_MAX_ENTRIES = 1024;
196
+ const THINKING_RESOLVE_CACHE = new BoundedLruMap<string, ThinkingConfig>(
197
+ THINKING_RESOLVE_CACHE_MAX_ENTRIES,
198
+ );
199
+
200
+ export function resolveThinkingForModel(
201
+ modelId: string,
202
+ providerId: string,
203
+ wireFamily: WireFamily,
204
+ declared?: ThinkingModelDecl,
205
+ ): ThinkingConfig {
206
+ const id = modelId.toLowerCase();
207
+
208
+ // Declared efforts (catalog `reasoningEfforts`) win when present and valid.
209
+ if (declared?.efforts !== undefined && declared.efforts.length > 0) {
210
+ const filtered = declared.efforts.filter((e): e is ReasoningEffortLevel =>
211
+ REASONING_EFFORT_LADDER.includes(e as ReasoningEffortLevel),
212
+ );
213
+ if (filtered.length > 0) {
214
+ return {
215
+ mode: declared.mode ?? familyDefaultMode(wireFamily),
216
+ efforts: filtered,
217
+ };
218
+ }
219
+ }
220
+
221
+ const cacheKey = `${id}|${providerId}|${wireFamily}`;
222
+ const cached = THINKING_RESOLVE_CACHE.get(cacheKey);
223
+ if (cached !== undefined) return cached;
224
+
225
+ for (const rule of THINKING_LADDER_RULES) {
226
+ if (rule.wireFamily !== undefined && rule.wireFamily !== wireFamily) continue;
227
+ if (rule.id !== undefined) {
228
+ const source = rule.normalizeClaudeId === true ? id.replaceAll(".", "-") : id;
229
+ if (!rule.id.test(source)) continue;
230
+ }
231
+ if (rule.provider !== undefined && !rule.provider.test(providerId)) continue;
232
+ const resolved: ThinkingConfig = {
233
+ mode: rule.mode ?? familyDefaultMode(wireFamily),
234
+ efforts: rule.efforts,
235
+ ...(rule.defaultLevel === undefined ? {} : { defaultLevel: rule.defaultLevel }),
236
+ ...(rule.requiresEffort === undefined ? {} : { requiresEffort: rule.requiresEffort }),
237
+ };
238
+ THINKING_RESOLVE_CACHE.set(cacheKey, resolved);
239
+ return resolved;
240
+ }
241
+
242
+ const fallback: ThinkingConfig = { mode: familyDefaultMode(wireFamily), efforts: EXTENDED_SUPPORTED_EFFORTS };
243
+ THINKING_RESOLVE_CACHE.set(cacheKey, fallback);
244
+ return fallback;
245
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Wire dialect layer — the per-provider dial that sits *below* `WireFamily`.
3
+ *
4
+ * `WireFamily` names the transport envelope (chat / responses / messages /
5
+ * gemini). A dialect names the *dial* that family speaks for one provider or
6
+ * model family: DeepSeek's `reasoning_content` + DSML in-band tool calls,
7
+ * Qwen's `enable_thinking` + `<tool_call>` chat template, Anthropic's native
8
+ * Messages vocabulary, and the generic OpenAI-compatible default.
9
+ *
10
+ * The split matters because "canonical forces everything through one general
11
+ * shape" is what made the pipeline fragile: quirks unique to a family
12
+ * (reasoning field names, system-message cardinality, tool_choice support,
13
+ * in-band tool markup) had nowhere to live except ad-hoc `if (providerId ===
14
+ * …)` branches inside generic codecs. Here they are a resolved policy object
15
+ * the codecs read, exactly like oh-my-pi's `OpenAICompatPolicy`.
16
+ */
17
+
18
+ /** A wire dialect. `"openai"`/`"anthropic"` are the generic defaults for each
19
+ * `WireFamily`; the rest are family-specific dialects. */
20
+ export type DialectId =
21
+ | "openai" // OpenAI-compatible generik (default wire chat)
22
+ | "anthropic" // Anthropic-compatible/ Claude-native dialect: signature thinking, cache-control
23
+ | "deepseek" // DSML + reasoning_content + max_tokens + strip tokens
24
+ | "qwen" // enable_thinking + <tool_call> + strict chat template
25
+ | "kimi"
26
+ | "glm"
27
+ | "minimax"
28
+ | "gemini"; // extensibel
29
+
30
+ /** Resolved policy consumed by the wire codecs. Every field has a safe
31
+ * default matching today's behavior; absent values fall back to it. */
32
+ export interface DialectPolicy {
33
+ /** Which wire field carries a previous assistant turn's reasoning. None when
34
+ * the wire has no reasoning side-channel (e.g. strict non-reasoning
35
+ * upstreams that reject the extra field). Default `"reasoning_content"` —
36
+ * the Chat wire's side channel, matching current behavior. */
37
+ readonly reasoningContentField?: "reasoning_content" | "reasoning" | "reasoning_text";
38
+ /** Which token-limit field the upstream accepts. Default `"max_tokens"`. */
39
+ readonly maxTokensField: "max_tokens" | "max_completion_tokens";
40
+ /** When truthy, strip the named family's special tokens from the stream. */
41
+ readonly stripSpecialTokens: "deepseek" | false;
42
+ /** False collapses multiple `system` messages into one (strict chat templates,
43
+ * e.g. Qwen Portal / Alibaba / MiniMax). */
44
+ readonly supportsMultipleSystemMessages: boolean;
45
+ /** False drops `tool_choice` entirely (DeepSeek rejects it). */
46
+ readonly supportsToolChoice: boolean;
47
+ /** True requires every tool-call assistant turn to also carry text content
48
+ * (DeepSeek V4 validates the exact content). */
49
+ readonly requiresAssistantContentForToolCalls: boolean;
50
+ /** False rejects synthetic reasoning placeholders on a tool-call turn
51
+ * (DeepSeek V4 validates the exact value). */
52
+ readonly allowsSyntheticReasoningContent: boolean;
53
+ /** How a reasoning effort is encoded on the wire. */
54
+ readonly thinkingFormat: "openai" | "qwen" | "deepseek" | "chat-template";
55
+ /** In-band tool-call codec to use (DSML / `<tool_call>` …), or null for
56
+ * structured-only tool calls. */
57
+ readonly inband: DialectId | null;
58
+ }
@@ -32,7 +32,7 @@ export interface ParamQuirk {
32
32
  }
33
33
 
34
34
  /** Per-wire output-token policy, in one table instead of per-builder branches. */
35
- export interface WireTokenBound {
35
+ interface WireTokenBound {
36
36
  /** Default when the caller sent no limit (undefined = leave absent). */
37
37
  readonly defaultMaxTokens?: number;
38
38
  /** Floor applied to any positive caller value below it (wire minimum). */
@@ -66,6 +66,13 @@ const DEFAULT_OUTPUT_TOKENS = 32_000;
66
66
  * Output-token bounds per wire family. Chat has no global ceiling: a model's
67
67
  * catalog output limit is the ceiling, and an unknown model passes the
68
68
  * caller's value through. Messages keeps its Anthropic floors and OAuth cap.
69
+ *
70
+ * The ceiling only ever comes from `options.maxOutputTokens` (the model's
71
+ * catalog output limit, supplied by the compatible adapter from
72
+ * `candidate.output_limit`). When it is omitted there is nothing to clamp to,
73
+ * which is intentional pass-through: a direct codec caller without a catalog
74
+ * limit is unbounded, and an unknown model passes the caller's value through by
75
+ * design — the bound table supplies floors/defaults, never an invented ceiling.
69
76
  */
70
77
  export const WIRE_TOKEN_BOUNDS: Readonly<Record<string, WireTokenBound>> = {
71
78
  chat: { minTokens: 16, defaultMaxTokens: DEFAULT_OUTPUT_TOKENS },
@@ -73,7 +80,14 @@ export const WIRE_TOKEN_BOUNDS: Readonly<Record<string, WireTokenBound>> = {
73
80
  responses: { minTokens: 16, defaultMaxTokens: DEFAULT_OUTPUT_TOKENS },
74
81
  };
75
82
 
76
- /** Resolves the output-token value for one wire from caller controls. */
83
+ /**
84
+ * Resolves the output-token value for one wire from caller controls.
85
+ *
86
+ * Clamping to a ceiling happens only when `options.maxOutputTokens` (the
87
+ * model's catalog limit) is present. An omitted `maxOutputTokens` means
88
+ * pass-through by design: a direct codec caller without a catalog limit is
89
+ * unbounded, and this function never fabricates a ceiling on its own.
90
+ */
77
91
  export function resolveWireMaxTokens(
78
92
  wire: string,
79
93
  controls: { max_tokens?: number | undefined },
@@ -120,7 +134,7 @@ function modelGeneration(modelId: string): { family: string; major: number; mino
120
134
  }
121
135
 
122
136
  /** True when the model rejects `temperature`/`top_p`/`top_k` at any thinking setting. */
123
- export function rejectsSamplingParams(modelId: string): boolean {
137
+ function rejectsSamplingParams(modelId: string): boolean {
124
138
  const generation = modelGeneration(modelId);
125
139
  if (generation === undefined) return false;
126
140
  // Opus turns strict at 4.7; the other families at 5.0.
@@ -157,7 +171,7 @@ const PARAM_QUIRKS: readonly ParamQuirk[] = [
157
171
  ];
158
172
 
159
173
  /** Finds the first quirk matching the provider/model pair, or undefined. */
160
- export function findParamQuirk(
174
+ function findParamQuirk(
161
175
  providerId: string,
162
176
  modelId: string,
163
177
  ): ParamQuirk | undefined {