cartethyia 2.6.7 → 2.7.1

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 (335) hide show
  1. package/.env.example +1 -7
  2. package/README.md +25 -2
  3. package/dist/dashboard/assets/{BannedPage-Dskhyp0l.js → BannedPage-D-J75hBM.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-D-J75hBM.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolDetailPage--SJhk7qQ.js → CliToolDetailPage-CVe6RaBH.js} +1 -1
  6. package/dist/dashboard/assets/CliToolDetailPage-CVe6RaBH.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-C203VT-c.js → CliToolsPage-Dd8ZSamp.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-Dd8ZSamp.js.gz +0 -0
  9. package/dist/dashboard/assets/{CombosPage-BcS7kGG1.js → CombosPage-QoJ6foxo.js} +1 -1
  10. package/dist/dashboard/assets/CombosPage-QoJ6foxo.js.gz +0 -0
  11. package/dist/dashboard/assets/ConsoleLogPage-DpNRay4C.js +1 -0
  12. package/dist/dashboard/assets/ConsoleLogPage-DpNRay4C.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-uujbBYwC.js → CustomizationPage-CKUFTcW4.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-CKUFTcW4.js.gz +0 -0
  15. package/dist/dashboard/assets/HealthEventsModal-CzSLiDzr.js +1 -0
  16. package/dist/dashboard/assets/HealthEventsModal-CzSLiDzr.js.gz +0 -0
  17. package/dist/dashboard/assets/LoginPage-DubdQcvX.js +1 -0
  18. package/dist/dashboard/assets/LoginPage-DubdQcvX.js.gz +0 -0
  19. package/dist/dashboard/assets/{ModelPicker-CA1kLs45.js → ModelPicker-BH8Tehdi.js} +1 -1
  20. package/dist/dashboard/assets/ModelPicker-BH8Tehdi.js.gz +0 -0
  21. package/dist/dashboard/assets/OverviewPage-DuWzAQFL.js +1 -0
  22. package/dist/dashboard/assets/OverviewPage-DuWzAQFL.js.gz +0 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-BKEKe2Fm.js +4 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-BKEKe2Fm.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +1 -0
  26. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
  27. package/dist/dashboard/assets/ProvidersPage-Bwotu8UJ.js +1 -0
  28. package/dist/dashboard/assets/ProvidersPage-Bwotu8UJ.js.gz +0 -0
  29. package/dist/dashboard/assets/ProxyPage-D7hpWbg9.js +9 -0
  30. package/dist/dashboard/assets/ProxyPage-D7hpWbg9.js.gz +0 -0
  31. package/dist/dashboard/assets/{QuotaPage-BueSWX5D.js → QuotaPage-ATpaxrbl.js} +1 -1
  32. package/dist/dashboard/assets/QuotaPage-ATpaxrbl.js.gz +0 -0
  33. package/dist/dashboard/assets/SettingsPage-CETophpx.js +1 -0
  34. package/dist/dashboard/assets/SettingsPage-CETophpx.js.gz +0 -0
  35. package/dist/dashboard/assets/SetupPage-BdgECjqq.js +1 -0
  36. package/dist/dashboard/assets/SetupPage-BdgECjqq.js.gz +0 -0
  37. package/dist/dashboard/assets/{SortableList-DrKeMcGN.js → SortableList-CAK-EN9z.js} +1 -1
  38. package/dist/dashboard/assets/SortableList-CAK-EN9z.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-qjuYtccc.js → StudioPage-B7W2_RhT.js} +3 -3
  40. package/dist/dashboard/assets/StudioPage-B7W2_RhT.js.gz +0 -0
  41. package/dist/dashboard/assets/UsagePage-6T4EFDjW.js +56 -0
  42. package/dist/dashboard/assets/UsagePage-6T4EFDjW.js.gz +0 -0
  43. package/dist/dashboard/assets/{api-keys-C23S9sgp.js → api-keys-CUi6UXsR.js} +1 -1
  44. package/dist/dashboard/assets/api-keys-CUi6UXsR.js.gz +0 -0
  45. package/dist/dashboard/assets/app-KvsUJUMF.css +2 -0
  46. package/dist/dashboard/assets/app-KvsUJUMF.css.gz +0 -0
  47. package/dist/dashboard/assets/{assert-DU6qrMA_.js → assert-67xXH5rf.js} +1 -1
  48. package/dist/dashboard/assets/assert-67xXH5rf.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-Bkz_-RrM.js → badge-DC2L43Mj.js} +1 -1
  50. package/dist/dashboard/assets/badge-DC2L43Mj.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-C-7y3VKV.js → banner-BBVcb0J3.js} +1 -1
  52. package/dist/dashboard/assets/banner-BBVcb0J3.js.gz +0 -0
  53. package/dist/dashboard/assets/{card-BOPBuBzD.js → card-Cca1XC6G.js} +1 -1
  54. package/dist/dashboard/assets/card-Cca1XC6G.js.gz +0 -0
  55. package/dist/dashboard/assets/{cli-tools-BaFUuFFF.js → cli-tools-KvsWa1Jl.js} +1 -1
  56. package/dist/dashboard/assets/cli-tools-KvsWa1Jl.js.gz +0 -0
  57. package/dist/dashboard/assets/{clipboard-button-e-Mlk0FH.js → clipboard-button-DUzEbynq.js} +1 -1
  58. package/dist/dashboard/assets/clipboard-button-DUzEbynq.js.gz +0 -0
  59. package/dist/dashboard/assets/{dialog-Iec_ywbD.js → dialog-DFvWhwTa.js} +1 -1
  60. package/dist/dashboard/assets/dialog-DFvWhwTa.js.gz +0 -0
  61. package/dist/dashboard/assets/{drawer-Bs8MIIHc.js → drawer-CFM2sMX1.js} +1 -1
  62. package/dist/dashboard/assets/drawer-CFM2sMX1.js.gz +0 -0
  63. package/dist/dashboard/assets/{entry-DOddwoc0.js → entry-BLBLxX0h.js} +3 -3
  64. package/dist/dashboard/assets/entry-BLBLxX0h.js.gz +0 -0
  65. package/dist/dashboard/assets/{entry-DcobaKFu.js → entry-Bqy8RFvM.js} +1 -1
  66. package/dist/dashboard/assets/entry-Bqy8RFvM.js.gz +0 -0
  67. package/dist/dashboard/assets/{entry-BRszm4_Z.js → entry-_xHo5x6r.js} +1 -1
  68. package/dist/dashboard/assets/entry-_xHo5x6r.js.gz +0 -0
  69. package/dist/dashboard/assets/formatters-mpBPqAQ8.js +1 -0
  70. package/dist/dashboard/assets/formatters-mpBPqAQ8.js.gz +0 -0
  71. package/dist/dashboard/assets/{github-badge-BuDsrsPn.js → github-badge-C9e8Ts7e.js} +1 -1
  72. package/dist/dashboard/assets/github-badge-C9e8Ts7e.js.gz +0 -0
  73. package/dist/dashboard/assets/{index-BeLRhsmt.js → index-D6QzEC_n.js} +2 -2
  74. package/dist/dashboard/assets/index-D6QzEC_n.js.gz +0 -0
  75. package/dist/dashboard/assets/{inline-DToMICwl.js → inline-BFUcvllj.js} +1 -1
  76. package/dist/dashboard/assets/inline-BFUcvllj.js.gz +0 -0
  77. package/dist/dashboard/assets/{input-WlyHWeG2.js → input-C_ILAvBb.js} +1 -1
  78. package/dist/dashboard/assets/input-C_ILAvBb.js.gz +0 -0
  79. package/dist/dashboard/assets/{layout-DaJ5baJr.js → layout-CBIyT6Rt.js} +1 -1
  80. package/dist/dashboard/assets/layout-CBIyT6Rt.js.gz +0 -0
  81. package/dist/dashboard/assets/{list-row-B3oSK13z.js → list-row-ebJ_-Nsb.js} +1 -1
  82. package/dist/dashboard/assets/list-row-ebJ_-Nsb.js.gz +0 -0
  83. package/dist/dashboard/assets/{live-ta6GMb-8.js → live-D0mm--ME.js} +1 -1
  84. package/dist/dashboard/assets/live-D0mm--ME.js.gz +0 -0
  85. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +1 -0
  86. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
  87. package/dist/dashboard/assets/{mutation-g_fduiNw.js → mutation-sMD965oO.js} +1 -1
  88. package/dist/dashboard/assets/mutation-sMD965oO.js.gz +0 -0
  89. package/dist/dashboard/assets/{numbers-Dulqgys5.js → numbers-BO9dKaFr.js} +1 -1
  90. package/dist/dashboard/assets/numbers-BO9dKaFr.js.gz +0 -0
  91. package/dist/dashboard/assets/providers/inception.svg +5 -0
  92. package/dist/dashboard/assets/providers/inception.svg.gz +0 -0
  93. package/dist/dashboard/assets/{query-keys-UETqfytp.js → query-keys-CfL_Zdoh.js} +1 -1
  94. package/dist/dashboard/assets/query-keys-CfL_Zdoh.js.gz +0 -0
  95. package/dist/dashboard/assets/{routing-BPUo-W8d.js → routing-BnIpi1IJ.js} +1 -1
  96. package/dist/dashboard/assets/routing-BnIpi1IJ.js.gz +0 -0
  97. package/dist/dashboard/assets/{select-BfZ3SCTM.js → select-Cj5Nw43g.js} +1 -1
  98. package/dist/dashboard/assets/select-Cj5Nw43g.js.gz +0 -0
  99. package/dist/dashboard/assets/settings-BAFhDgX8.js +1 -0
  100. package/dist/dashboard/assets/settings-BAFhDgX8.js.gz +0 -0
  101. package/dist/dashboard/assets/{stack-B1w5BM0u.js → stack-EMrOMt4I.js} +1 -1
  102. package/dist/dashboard/assets/stack-EMrOMt4I.js.gz +0 -0
  103. package/dist/dashboard/assets/{state-DhZBfWgx.js → state-CWoo7ty5.js} +1 -1
  104. package/dist/dashboard/assets/state-CWoo7ty5.js.gz +0 -0
  105. package/dist/dashboard/assets/{switch-yD7D99Lg.js → switch-CCjT6IkF.js} +1 -1
  106. package/dist/dashboard/assets/switch-CCjT6IkF.js.gz +0 -0
  107. package/dist/dashboard/assets/{useMutation-EDFRkn1i.js → useMutation-DjkLHUcE.js} +1 -1
  108. package/dist/dashboard/assets/useMutation-DjkLHUcE.js.gz +0 -0
  109. package/dist/dashboard/index.html +1 -1
  110. package/dist/dashboard/index.html.gz +0 -0
  111. package/dist/dashboard/precompressed-assets.json +55 -54
  112. package/migrations/full-postgres/0024_add_pool_provider_cooldowns.sql +12 -0
  113. package/migrations/full-postgres/0025_add_pool_random_strategy.sql +3 -0
  114. package/migrations/lite-sqlite3/0024_add_pool_provider_cooldowns.sql +12 -0
  115. package/migrations/lite-sqlite3/0025_add_pool_random_strategy.sql +20 -0
  116. package/package.json +1 -1
  117. package/scripts/cli/console-menu.ts +5 -2
  118. package/scripts/cli/tray.ts +21 -6
  119. package/src/boot/app.ts +24 -62
  120. package/src/boot/dependencies.ts +732 -750
  121. package/src/config/cooldowns.ts +16 -0
  122. package/src/config/providers.ts +13 -1
  123. package/src/config/resources.ts +13 -80
  124. package/src/config/security.ts +2 -38
  125. package/src/config/spec.ts +16 -23
  126. package/src/console/console-router.ts +7 -7
  127. package/src/console/domain-registration.ts +19 -12
  128. package/src/console/providers/catalog/catalog-projections.ts +2 -6
  129. package/src/console/providers/catalog/contracts.ts +19 -0
  130. package/src/console/providers/catalog/provider-operations.ts +38 -0
  131. package/src/console/providers/catalog/routes.ts +14 -0
  132. package/src/console/providers/catalog/store-helpers.ts +326 -0
  133. package/src/console/providers/catalog/store.ts +1292 -1563
  134. package/src/console/quota/account-quota-global.ts +2 -2
  135. package/src/console/quota/account-quota-shared.ts +1 -1
  136. package/src/console/quota/account-quota-tenant.ts +35 -12
  137. package/src/console/quota/quota-view.ts +2 -2
  138. package/src/console/remote-support/contracts.ts +3 -1
  139. package/src/console/remote-support/service.ts +115 -6
  140. package/src/console/routing/pools/contracts.ts +41 -1
  141. package/src/console/routing/pools/operations.ts +183 -4
  142. package/src/console/routing/pools/relay-deploy.ts +17 -4
  143. package/src/console/routing/pools/routes.ts +30 -0
  144. package/src/console/routing/pools/store.ts +98 -8
  145. package/src/main.ts +16 -2
  146. package/src/network/outbound-fetch.ts +226 -365
  147. package/src/network/pool/agent.ts +8 -0
  148. package/src/network/pool/pool-state.ts +7 -0
  149. package/src/network/pool/selector.ts +110 -2
  150. package/src/network/pool-cooldown-store.ts +252 -0
  151. package/src/network/pool-health-machine.ts +5 -3
  152. package/src/network/pool-health.ts +36 -9
  153. package/src/observability/event-query.ts +57 -0
  154. package/src/observability/metrics.ts +15 -5
  155. package/src/observability/runtime-metrics.ts +30 -15
  156. package/src/persistence/health-event-flush.ts +2 -0
  157. package/src/persistence/schema.ts +19 -0
  158. package/src/persistence/usage-flush.ts +8 -3
  159. package/src/protocol/canonical-model.ts +1 -1
  160. package/src/protocol/dsml.ts +377 -0
  161. package/src/protocol/gateway-error.ts +0 -1
  162. package/src/{providers/provider-reasoning.ts → protocol/reasoning.ts} +10 -9
  163. package/src/protocol/request/chat.ts +7 -7
  164. package/src/protocol/request/codex.ts +2 -2
  165. package/src/protocol/request/gemini.ts +1 -1
  166. package/src/protocol/request/messages.ts +6 -6
  167. package/src/protocol/request/responses.ts +7 -7
  168. package/src/protocol/response/dsml.ts +12 -133
  169. package/src/{transport → protocol}/translation/attachment-integrity.ts +2 -2
  170. package/src/{transport → protocol}/translation/cache-controls.ts +1 -1
  171. package/src/{transport → protocol}/translation/capabilities.ts +2 -2
  172. package/src/{transport → protocol}/translation/normalize.ts +1 -1
  173. package/src/{transport → protocol}/translation/quirks.ts +1 -1
  174. package/src/{transport → protocol}/translation/search.ts +1 -1
  175. package/src/{transport → protocol}/translation/thinking.ts +23 -1
  176. package/src/{transport → protocol}/translation/tool-id.ts +1 -1
  177. package/src/{transport → protocol}/translation/tool-repair.ts +2 -2
  178. package/src/protocol/upstream-parsing.ts +176 -0
  179. package/src/providers/adapters/compatible-adapter.ts +11 -2
  180. package/src/providers/authentication/oauth-refresh-service.ts +9 -5
  181. package/src/providers/default-registry.ts +21 -5
  182. package/src/providers/discovery/probe-phases.ts +16 -3
  183. package/src/providers/discovery/probing-service.ts +4 -1
  184. package/src/providers/integrations/anthropic.ts +1 -1
  185. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -4
  186. package/src/providers/integrations/buddy/buddy-chat-shared.ts +141 -8
  187. package/src/providers/integrations/buddy/buddy-checkin.ts +5 -1
  188. package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -82
  189. package/src/providers/integrations/buddy/buddy-identity.ts +25 -0
  190. package/src/providers/integrations/buddy/buddy-server-tools.ts +240 -0
  191. package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +36 -0
  192. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +6 -31
  193. package/src/providers/integrations/buddy/codebuddy/provider.ts +2 -0
  194. package/src/providers/integrations/buddy/codebuddy/shared.ts +19 -4
  195. package/src/providers/integrations/buddy/turing-device-token.ts +262 -0
  196. package/src/providers/integrations/buddy/workbuddy/provider.ts +2 -0
  197. package/src/providers/integrations/buddy/workbuddy/shared.ts +56 -3
  198. package/src/providers/integrations/claude/claude.ts +1 -1
  199. package/src/providers/integrations/cloudflareai/cloudflareai.ts +1 -1
  200. package/src/providers/integrations/codex/codex-errors.ts +1 -1
  201. package/src/providers/integrations/codex/codex.ts +1 -1
  202. package/src/providers/integrations/commandcode/commandcode.ts +134 -104
  203. package/src/providers/integrations/commandcode/discovery.ts +6 -5
  204. package/src/providers/integrations/factory/factory.ts +1 -1
  205. package/src/providers/integrations/github/github.ts +1 -1
  206. package/src/providers/integrations/grok/grok.ts +1 -1
  207. package/src/providers/integrations/inception/provider.ts +91 -0
  208. package/src/providers/integrations/inferhub.ts +1 -1
  209. package/src/providers/integrations/kiro/kiro-request.ts +1 -1
  210. package/src/providers/integrations/mistral.ts +193 -19
  211. package/src/providers/integrations/opencode/fingerprint.ts +19 -2
  212. package/src/providers/integrations/opencode/prompt.ts +111 -0
  213. package/src/providers/integrations/opencode/provider.ts +101 -23
  214. package/src/providers/integrations/opencode/tool-definitions.ts +4 -4
  215. package/src/providers/integrations/qoder/qoder-checkin.ts +303 -0
  216. package/src/providers/integrations/qoder/qoder.ts +1641 -884
  217. package/src/providers/integrations/shared/install-id.ts +2 -1
  218. package/src/providers/integrations/trae/trae-cache.ts +110 -0
  219. package/src/providers/integrations/trae/trae-oauth.ts +29 -4
  220. package/src/providers/integrations/trae/trae-protocol.ts +2 -1
  221. package/src/providers/integrations/trae/trae.ts +106 -23
  222. package/src/providers/operations/account-error-classification.ts +1660 -0
  223. package/src/providers/operations/account-health-service.ts +621 -2097
  224. package/src/providers/operations/account-reset-service.ts +2 -0
  225. package/src/providers/provider-contracts.ts +0 -2
  226. package/src/providers/provider-metadata.ts +25 -4
  227. package/src/providers/provider-probe.ts +2 -2
  228. package/src/{console → providers}/quota/cache.ts +1 -1
  229. package/src/{console → providers}/quota/refresh.ts +5 -5
  230. package/src/security/abuse.ts +17 -0
  231. package/src/transport/dispatch/attempt-finalize.ts +114 -12
  232. package/src/transport/dispatch/attempt-loop.ts +3 -0
  233. package/src/transport/dispatch/empty-stream.ts +224 -217
  234. package/src/transport/dispatch/generation.ts +37 -55
  235. package/src/transport/dispatch/handler-deps.ts +32 -0
  236. package/src/transport/dispatch/leases.ts +9 -4
  237. package/src/transport/dispatch/proxy-request.ts +6 -30
  238. package/src/transport/dispatch/responses-compact.ts +22 -43
  239. package/src/transport/dispatch/streaming/finalize.ts +3 -0
  240. package/src/transport/dispatch/streaming/stream.ts +0 -8
  241. package/src/transport/dispatch/systemone.ts +22 -42
  242. package/src/transport/dispatch/token-count.ts +23 -39
  243. package/src/transport/dispatch/upstream.ts +1 -3
  244. package/src/transport/dispatch/websearch.ts +22 -41
  245. package/src/transport/failure-policy.ts +59 -178
  246. package/src/transport/guards/abuse-guard.ts +10 -0
  247. package/src/transport/guards/auth-guard.ts +0 -18
  248. package/src/transport/guards/error-lifecycle.ts +1 -1
  249. package/src/transport/guards/pipeline.ts +0 -6
  250. package/src/transport/guards/request-context.ts +18 -91
  251. package/src/transport/request/degradation.ts +20 -1
  252. package/src/transport/request/inflight.ts +4 -95
  253. package/src/transport/request/preparer.ts +6 -6
  254. package/src/transport/request/state.ts +66 -38
  255. package/src/transport/request/tenant-preferences.ts +1 -1
  256. package/src/transport/routing/route-catalog.ts +41 -31
  257. package/src/transport/routing/router.ts +2 -2
  258. package/src/transport/surface/messages/parse.ts +1 -1
  259. package/src/workers/buddy-growth-tasks.ts +346 -425
  260. package/src/workers/daily-checkin.ts +17 -6
  261. package/src/workers/quota-refresh-sweep.ts +2 -2
  262. package/src/workers/scheduler.ts +17 -1
  263. package/dist/dashboard/assets/BannedPage-Dskhyp0l.js.gz +0 -0
  264. package/dist/dashboard/assets/CliToolDetailPage--SJhk7qQ.js.gz +0 -0
  265. package/dist/dashboard/assets/CliToolsPage-C203VT-c.js.gz +0 -0
  266. package/dist/dashboard/assets/CombosPage-BcS7kGG1.js.gz +0 -0
  267. package/dist/dashboard/assets/ConsoleLogPage-ChmiSLwO.js +0 -1
  268. package/dist/dashboard/assets/ConsoleLogPage-ChmiSLwO.js.gz +0 -0
  269. package/dist/dashboard/assets/CustomizationPage-uujbBYwC.js.gz +0 -0
  270. package/dist/dashboard/assets/HealthEventsModal-fKAWd-OQ.js +0 -1
  271. package/dist/dashboard/assets/HealthEventsModal-fKAWd-OQ.js.gz +0 -0
  272. package/dist/dashboard/assets/LoginPage-DoOUthbG.js +0 -1
  273. package/dist/dashboard/assets/LoginPage-DoOUthbG.js.gz +0 -0
  274. package/dist/dashboard/assets/ModelPicker-CA1kLs45.js.gz +0 -0
  275. package/dist/dashboard/assets/OverviewPage-C5Z-UBz1.js +0 -1
  276. package/dist/dashboard/assets/OverviewPage-C5Z-UBz1.js.gz +0 -0
  277. package/dist/dashboard/assets/ProviderDetailPage-CFu1qGcT.js +0 -3
  278. package/dist/dashboard/assets/ProviderDetailPage-CFu1qGcT.js.gz +0 -0
  279. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js +0 -1
  280. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js.gz +0 -0
  281. package/dist/dashboard/assets/ProvidersPage-CnlJZbxF.js +0 -1
  282. package/dist/dashboard/assets/ProvidersPage-CnlJZbxF.js.gz +0 -0
  283. package/dist/dashboard/assets/ProxyPage-B9mBTweh.js +0 -7
  284. package/dist/dashboard/assets/ProxyPage-B9mBTweh.js.gz +0 -0
  285. package/dist/dashboard/assets/QuotaPage-BueSWX5D.js.gz +0 -0
  286. package/dist/dashboard/assets/SettingsPage-B0x00MVY.js +0 -1
  287. package/dist/dashboard/assets/SettingsPage-B0x00MVY.js.gz +0 -0
  288. package/dist/dashboard/assets/SetupPage-DQ9oDRpi.js +0 -1
  289. package/dist/dashboard/assets/SetupPage-DQ9oDRpi.js.gz +0 -0
  290. package/dist/dashboard/assets/SortableList-DrKeMcGN.js.gz +0 -0
  291. package/dist/dashboard/assets/StudioPage-qjuYtccc.js.gz +0 -0
  292. package/dist/dashboard/assets/UsagePage-Be7aNviQ.js +0 -56
  293. package/dist/dashboard/assets/UsagePage-Be7aNviQ.js.gz +0 -0
  294. package/dist/dashboard/assets/api-keys-C23S9sgp.js.gz +0 -0
  295. package/dist/dashboard/assets/app-BUSiYL6F.css +0 -2
  296. package/dist/dashboard/assets/app-BUSiYL6F.css.gz +0 -0
  297. package/dist/dashboard/assets/assert-DU6qrMA_.js.gz +0 -0
  298. package/dist/dashboard/assets/badge-Bkz_-RrM.js.gz +0 -0
  299. package/dist/dashboard/assets/banner-C-7y3VKV.js.gz +0 -0
  300. package/dist/dashboard/assets/card-BOPBuBzD.js.gz +0 -0
  301. package/dist/dashboard/assets/cli-tools-BaFUuFFF.js.gz +0 -0
  302. package/dist/dashboard/assets/clipboard-button-e-Mlk0FH.js.gz +0 -0
  303. package/dist/dashboard/assets/cog-CdWhsajs.js +0 -1
  304. package/dist/dashboard/assets/cog-CdWhsajs.js.gz +0 -0
  305. package/dist/dashboard/assets/dialog-Iec_ywbD.js.gz +0 -0
  306. package/dist/dashboard/assets/drawer-Bs8MIIHc.js.gz +0 -0
  307. package/dist/dashboard/assets/entry-BRszm4_Z.js.gz +0 -0
  308. package/dist/dashboard/assets/entry-DOddwoc0.js.gz +0 -0
  309. package/dist/dashboard/assets/entry-DcobaKFu.js.gz +0 -0
  310. package/dist/dashboard/assets/github-badge-BuDsrsPn.js.gz +0 -0
  311. package/dist/dashboard/assets/index-BeLRhsmt.js.gz +0 -0
  312. package/dist/dashboard/assets/inline-DToMICwl.js.gz +0 -0
  313. package/dist/dashboard/assets/input-WlyHWeG2.js.gz +0 -0
  314. package/dist/dashboard/assets/layout-DaJ5baJr.js.gz +0 -0
  315. package/dist/dashboard/assets/list-row-B3oSK13z.js.gz +0 -0
  316. package/dist/dashboard/assets/live-ta6GMb-8.js.gz +0 -0
  317. package/dist/dashboard/assets/model-bans-BmYTmbAk.js +0 -1
  318. package/dist/dashboard/assets/model-bans-BmYTmbAk.js.gz +0 -0
  319. package/dist/dashboard/assets/mutation-g_fduiNw.js.gz +0 -0
  320. package/dist/dashboard/assets/numbers-Dulqgys5.js.gz +0 -0
  321. package/dist/dashboard/assets/query-keys-UETqfytp.js.gz +0 -0
  322. package/dist/dashboard/assets/routing-BPUo-W8d.js.gz +0 -0
  323. package/dist/dashboard/assets/select-BfZ3SCTM.js.gz +0 -0
  324. package/dist/dashboard/assets/settings--3hxSyry.js +0 -1
  325. package/dist/dashboard/assets/settings--3hxSyry.js.gz +0 -0
  326. package/dist/dashboard/assets/stack-B1w5BM0u.js.gz +0 -0
  327. package/dist/dashboard/assets/state-DhZBfWgx.js.gz +0 -0
  328. package/dist/dashboard/assets/switch-yD7D99Lg.js.gz +0 -0
  329. package/dist/dashboard/assets/useMutation-EDFRkn1i.js.gz +0 -0
  330. package/src/console/admin/model-abuse/contracts.ts +0 -38
  331. package/src/console/admin/model-abuse/routes.ts +0 -97
  332. package/src/security/model-abuse.ts +0 -704
  333. package/src/transport/guards/concurrency-guard.ts +0 -125
  334. /package/dist/dashboard/assets/{app-MdVfwraB.js → app-BaWd0puM.js} +0 -0
  335. /package/dist/dashboard/assets/{app-MdVfwraB.js.gz → app-BaWd0puM.js.gz} +0 -0
@@ -0,0 +1,91 @@
1
+ import type { ApiKeyProviderSpec } from "../../configured-provider";
2
+ import { fetchOpenAICompatibleModels } from "../../discovery/openai-model-discovery";
3
+ import { defineModel, type ModelDefinition } from "../../provider-model-definition";
4
+
5
+ const INCEPTION_PROVIDER_ID = "inception" as const;
6
+
7
+ /**
8
+ * Inception Labs (Mercury) — bearer-authenticated OpenAI-compatible chat.
9
+ *
10
+ * The upstream is a plain `POST /v1/chat/completions` service (SSE streaming,
11
+ * tool calling, structured outputs, `reasoning_effort`). Base URL comes from
12
+ * `BUNDLED_PROVIDER_METADATA`; the chat path is declared below the `/v1`
13
+ * root, exactly like every other version-rooted OpenAI-compatible provider.
14
+ */
15
+ export const INCEPTION_SPEC: ApiKeyProviderSpec = {
16
+ provider_id: INCEPTION_PROVIDER_ID,
17
+ endpoint_paths_by_wire_family: {},
18
+ };
19
+
20
+ /**
21
+ * Offline floor: the Mercury chat model this provider serves, pinned to the
22
+ * free-tier allowance (100M free tokens at signup).
23
+ *
24
+ * The roster intentionally carries only `mercury-3` — the operator's choice.
25
+ * Mercury Voice is enterprise-gated, Mercury Decide is a native decisions
26
+ * endpoint, and Mercury Edit 2 is FIM/edit; none of them is a chat model, and
27
+ * a chat wire would not serve them.
28
+ *
29
+ * `freeTier` is the catalog flag the console groups on; `free: true` zeroes
30
+ * the cost the way every other free-allowance provider models its rows — the
31
+ * allowance does not bill, so the row must not show a price. Limits are
32
+ * mercury-3's own chat-completions numbers: 1M context, 131072 max output,
33
+ * reasoning (instant/low/medium/high), tool calling.
34
+ */
35
+ export const INCEPTION_MODELS: readonly ModelDefinition[] = [
36
+ defineModel({
37
+ id: "mercury-3",
38
+ wireFamily: "chat",
39
+ endpoint: "/chat/completions",
40
+ ctx: 1_000_000,
41
+ out: 131_072,
42
+ reasoning: true,
43
+ toolCall: true,
44
+ free: true,
45
+ freeTier: true,
46
+ }),
47
+ ];
48
+
49
+ /**
50
+ * Live `/v1/models` listing, pinned to the free tier.
51
+ *
52
+ * The listing requires the API key (matches the chat endpoint's bearer), so
53
+ * the credential is forwarded when present; an unauthenticated fetch fails
54
+ * cleanly and the static roster stays authoritative.
55
+ *
56
+ * Every fetched row is stamped `freeTier` and zero-priced, the same rule the
57
+ * static roster declares: this provider is pinned to its free allowance, so a
58
+ * model upstream adds must not land in the billed tail.
59
+ *
60
+ * A fetched id that the static roster already knows keeps the roster row
61
+ * whole, not the listing's fields: upstream publishes `max_output_length` and
62
+ * no `reasoning`/`tool_call` keys, so the shared OpenAI-compatible reader
63
+ * would otherwise overwrite mercury-3's advertised 131072 output and reasoning
64
+ * flag with its 64k/not-reasoning defaults. The roster is the canonical
65
+ * metadata for the models we know; the listing only adds genuinely new ids.
66
+ */
67
+ export async function discoverInceptionFreeModels(options: {
68
+ readonly baseUrl: string;
69
+ readonly credential?: string;
70
+ readonly fetcher?: typeof fetch;
71
+ }): Promise<readonly ModelDefinition[] | null> {
72
+ const listed = await fetchOpenAICompatibleModels({
73
+ baseUrl: options.baseUrl,
74
+ providerId: "inception",
75
+ ...(typeof options.credential === "string" && options.credential.trim().length > 0
76
+ ? { headers: { authorization: `Bearer ${options.credential}` } }
77
+ : {}),
78
+ ...(options.fetcher === undefined ? {} : { fetcher: options.fetcher }),
79
+ });
80
+ if (listed === null) return null;
81
+ const known = new Map(INCEPTION_MODELS.map((model) => [model.modelId, model]));
82
+ return listed.map((model) => {
83
+ const roster = known.get(model.modelId);
84
+ if (roster !== undefined) return roster;
85
+ return {
86
+ ...model,
87
+ freeTier: true,
88
+ cost: { input: 0, output: 0, pricing_model: "pay-per-use" },
89
+ };
90
+ });
91
+ }
@@ -11,7 +11,7 @@ import type { FetchLike, ProviderQuotaResult } from "../quota/quota-contracts";
11
11
  import { probeApiKeyConnectivity } from "../quota/quota-support";
12
12
  import type { CanonicalEvent, CanonicalRequest, ContentPart } from "../../protocol/canonical-model";
13
13
  import { GatewayError } from "../../protocol/gateway-error";
14
- import { applyParamQuirks } from "../../transport/translation/quirks";
14
+ import { applyParamQuirks } from "../../protocol/translation/quirks";
15
15
  import { buildClaudeMessagesRequest, filterClaudeCustomHeaders } from "./shared/claude-messages";
16
16
  import { resolveInboundSessionId } from "../operations/session-resolution";
17
17
  import { isRecord } from "../../protocol/codecs";
@@ -21,7 +21,7 @@
21
21
  import { createHash, randomUUID } from "node:crypto";
22
22
  import type { CanonicalMessage, CanonicalRequest, ContentPart, ToolDefinition } from "../../../protocol/canonical-model";
23
23
  import { resolveImageSource, splitDataUrl } from "../../../protocol/codecs";
24
- import type { ReasoningEffortLevel } from "../../../transport/translation/thinking";
24
+ import type { ReasoningEffortLevel } from "../../../protocol/translation/thinking";
25
25
 
26
26
  /** Longest tool name the upstream accepts, counted in code points. */
27
27
  export const KIRO_TOOL_NAME_MAX_LENGTH = 64;
@@ -4,14 +4,11 @@ import { defineModel } from "../provider-model-definition";
4
4
  const MISTRAL_PROVIDER_ID = "mistral" as const;
5
5
 
6
6
  /**
7
- * Mistral's own current generalist tiers.
7
+ * Mistral's catalog for the generic OpenAI-compatible API-key provider.
8
8
  *
9
- * The provider is registered as a generic OpenAI-compatible API-key provider,
10
- * which carries no catalog of its own: without this list, every model it serves
11
- * stays absent until a discovery run happens to fetch them. These are the two
12
- * `latest` aliases Mistral keeps pointed at its current generalist models —
13
- * `mistral-large-latest` (Large 4) and `mistral-medium-latest` (Medium 3.5),
14
- * per the Mistral model overview.
9
+ * The provider is registered as a generic API-key provider, which carries no
10
+ * catalog of its own: without this list, every model it serves stays absent
11
+ * until a discovery run happens to fetch them.
15
12
  *
16
13
  * Limits and pricing come from the base catalog via `providerId`: `defineModel`
17
14
  * resolves `mistral:<id>` and falls back to the majority row, so no number is
@@ -19,28 +16,110 @@ const MISTRAL_PROVIDER_ID = "mistral" as const;
19
16
  * because the base catalog is keyed by bare id and a bare id maps to many
20
17
  * providers' servings.
21
18
  *
19
+ * Which rows are here: the chat models live on a real Mistral account (the
20
+ * code/codestral family, the ministral small/medium/large sizes, voxtral
21
+ * small, and the small/medium generalist tiers). A live probe against the
22
+ * Mistral API verified each of these responds on `/v1/chat/completions`.
23
+ *
22
24
  * Deliberately not included:
23
25
  *
24
- * - The dated rows (`mistral-large-2411`, `mistral-medium-2508`). Each is on
25
- * Mistral's retired list with a named successor.
26
- * - `mistral-small-latest`. Still live, but the operator asked for the two
27
- * frontier tiers, and listing a model is a routing claim rather than a
28
- * completeness claim.
29
- * - Both Magistral rows. Mistral deprecated Magistral Medium and Small in
30
- * favour of Mistral Medium 3.5 and Mistral Small 4, so listing them
31
- * advertises models the provider is actively retiring.
32
- * - The open-weights rows (`open-mistral-7b`, `open-mixtral-8x7b`), the
33
- * embedding row (`mistral-embed`, not a chat model), and the devstral and
34
- * codestral families — Mistral publishes those as separate product lines.
26
+ * - `mistral-large-latest` / dated large rows — tier-gated (Mistral answers
27
+ * 403 `tier_not_allowed` on many subscription tiers).
28
+ * - The embed/moderation/OCR/transcribe/TTS/realtime rows — they speak a
29
+ * different endpoint, not chat.
30
+ * - The Labs rows (`labs-leanstral-*`) — need an organization admin flag.
31
+ * - The open-weights rows (`open-mistral-7b`, `open-mixtral-8x7b`) and the
32
+ * devstral family — separate product lines.
35
33
  */
36
34
  export const MISTRAL_MODELS: readonly ModelDefinition[] = [
35
+ // Code / coding family
36
+ defineModel({
37
+ id: "codestral-2508",
38
+ providerId: MISTRAL_PROVIDER_ID,
39
+ wireFamily: "chat",
40
+ vision: true,
41
+ toolCall: true,
42
+ }),
43
+ defineModel({
44
+ id: "codestral-latest",
45
+ providerId: MISTRAL_PROVIDER_ID,
46
+ wireFamily: "chat",
47
+ vision: true,
48
+ toolCall: true,
49
+ }),
50
+ defineModel({
51
+ id: "mistral-code-latest",
52
+ providerId: MISTRAL_PROVIDER_ID,
53
+ wireFamily: "chat",
54
+ vision: true,
55
+ toolCall: true,
56
+ }),
57
+ defineModel({
58
+ id: "mistral-code-fim-latest",
59
+ providerId: MISTRAL_PROVIDER_ID,
60
+ wireFamily: "chat",
61
+ vision: true,
62
+ toolCall: true,
63
+ }),
64
+ // Ministral sizes
65
+ defineModel({
66
+ id: "ministral-14b-2512",
67
+ providerId: MISTRAL_PROVIDER_ID,
68
+ wireFamily: "chat",
69
+ vision: true,
70
+ toolCall: true,
71
+ }),
72
+ defineModel({
73
+ id: "ministral-14b-latest",
74
+ providerId: MISTRAL_PROVIDER_ID,
75
+ wireFamily: "chat",
76
+ vision: true,
77
+ toolCall: true,
78
+ }),
37
79
  defineModel({
38
- id: "mistral-large-latest",
80
+ id: "ministral-8b-2512",
39
81
  providerId: MISTRAL_PROVIDER_ID,
40
82
  wireFamily: "chat",
41
83
  vision: true,
42
84
  toolCall: true,
43
85
  }),
86
+ defineModel({
87
+ id: "ministral-8b-latest",
88
+ providerId: MISTRAL_PROVIDER_ID,
89
+ wireFamily: "chat",
90
+ vision: true,
91
+ toolCall: true,
92
+ }),
93
+ defineModel({
94
+ id: "ministral-3b-2512",
95
+ providerId: MISTRAL_PROVIDER_ID,
96
+ wireFamily: "chat",
97
+ vision: true,
98
+ toolCall: true,
99
+ }),
100
+ defineModel({
101
+ id: "ministral-3b-latest",
102
+ providerId: MISTRAL_PROVIDER_ID,
103
+ wireFamily: "chat",
104
+ vision: true,
105
+ toolCall: true,
106
+ }),
107
+ // Voxtral small (chat-capable)
108
+ defineModel({
109
+ id: "voxtral-small-2507",
110
+ providerId: MISTRAL_PROVIDER_ID,
111
+ wireFamily: "chat",
112
+ vision: true,
113
+ toolCall: true,
114
+ }),
115
+ defineModel({
116
+ id: "voxtral-small-latest",
117
+ providerId: MISTRAL_PROVIDER_ID,
118
+ wireFamily: "chat",
119
+ vision: true,
120
+ toolCall: true,
121
+ }),
122
+ // Medium generalist tiers
44
123
  defineModel({
45
124
  id: "mistral-medium-latest",
46
125
  providerId: MISTRAL_PROVIDER_ID,
@@ -49,4 +128,99 @@ export const MISTRAL_MODELS: readonly ModelDefinition[] = [
49
128
  reasoning: true,
50
129
  toolCall: true,
51
130
  }),
131
+ defineModel({
132
+ id: "mistral-medium",
133
+ providerId: MISTRAL_PROVIDER_ID,
134
+ wireFamily: "chat",
135
+ vision: true,
136
+ reasoning: true,
137
+ toolCall: true,
138
+ }),
139
+ defineModel({
140
+ id: "mistral-medium-3-5",
141
+ providerId: MISTRAL_PROVIDER_ID,
142
+ wireFamily: "chat",
143
+ vision: true,
144
+ reasoning: true,
145
+ toolCall: true,
146
+ }),
147
+ defineModel({
148
+ id: "mistral-medium-3.5",
149
+ providerId: MISTRAL_PROVIDER_ID,
150
+ wireFamily: "chat",
151
+ vision: true,
152
+ reasoning: true,
153
+ toolCall: true,
154
+ }),
155
+ defineModel({
156
+ id: "mistral-medium-3",
157
+ providerId: MISTRAL_PROVIDER_ID,
158
+ wireFamily: "chat",
159
+ vision: true,
160
+ reasoning: true,
161
+ toolCall: true,
162
+ }),
163
+ defineModel({
164
+ id: "mistral-medium-2604",
165
+ providerId: MISTRAL_PROVIDER_ID,
166
+ wireFamily: "chat",
167
+ vision: true,
168
+ reasoning: true,
169
+ toolCall: true,
170
+ }),
171
+ // Vibe CLI family
172
+ defineModel({
173
+ id: "mistral-vibe-cli-latest",
174
+ providerId: MISTRAL_PROVIDER_ID,
175
+ wireFamily: "chat",
176
+ vision: true,
177
+ toolCall: true,
178
+ }),
179
+ defineModel({
180
+ id: "mistral-vibe-cli-with-tools",
181
+ providerId: MISTRAL_PROVIDER_ID,
182
+ wireFamily: "chat",
183
+ vision: true,
184
+ toolCall: true,
185
+ }),
186
+ defineModel({
187
+ id: "mistral-vibe-cli-fast",
188
+ providerId: MISTRAL_PROVIDER_ID,
189
+ wireFamily: "chat",
190
+ vision: true,
191
+ toolCall: true,
192
+ }),
193
+ // Magistral / small generalist tiers (chat-capable)
194
+ defineModel({
195
+ id: "magistral-medium-latest",
196
+ providerId: MISTRAL_PROVIDER_ID,
197
+ wireFamily: "chat",
198
+ vision: true,
199
+ reasoning: true,
200
+ toolCall: true,
201
+ }),
202
+ defineModel({
203
+ id: "mistral-small-2603",
204
+ providerId: MISTRAL_PROVIDER_ID,
205
+ wireFamily: "chat",
206
+ vision: true,
207
+ reasoning: true,
208
+ toolCall: true,
209
+ }),
210
+ defineModel({
211
+ id: "mistral-small-latest",
212
+ providerId: MISTRAL_PROVIDER_ID,
213
+ wireFamily: "chat",
214
+ vision: true,
215
+ reasoning: true,
216
+ toolCall: true,
217
+ }),
218
+ defineModel({
219
+ id: "magistral-small-latest",
220
+ providerId: MISTRAL_PROVIDER_ID,
221
+ wireFamily: "chat",
222
+ vision: true,
223
+ reasoning: true,
224
+ toolCall: true,
225
+ }),
52
226
  ];
@@ -1,6 +1,14 @@
1
1
  import { getOpenCodeVersion } from "../../operations/client-versions";
2
2
  import { createHash, randomBytes } from "node:crypto";
3
3
 
4
+ /**
5
+ * The OpenCode fallback client identity, used only while version discovery has
6
+ * not resolved yet. The live feed (`opencode/latest/<version>/cli`) wins once
7
+ * it is available; upstream accepts a range of releases, so the fallback does
8
+ * not need chasing.
9
+ */
10
+ export const OPENCODE_CLIENT_VERSION = "2.1.1";
11
+
4
12
  let lastTimestamp = 0;
5
13
  let sequenceCounter = 0;
6
14
  const SESSION_ID_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -118,11 +126,19 @@ function createTraceHeaders(): Record<string, string> {
118
126
  };
119
127
  }
120
128
 
121
- /** Build the observed OpenCode CLI identity headers for an upstream dispatch. */
129
+ /**
130
+ * Build the observed OpenCode CLI identity headers for an upstream dispatch.
131
+ *
132
+ * The v2 lane splits root and child session ids exactly like the reference
133
+ * gateway: `x-opencode-session` / `x-session-affinity` / `x-session-id` carry
134
+ * the root session, while `x-opencode-session-id` carries the child (the
135
+ * client's own session id when it sent one, else the root).
136
+ */
122
137
  export function buildOpenCodeHeaders(
123
138
  version = getOpenCodeVersion(),
124
139
  affinity?: string,
125
140
  projectId?: string,
141
+ childSessionId?: string,
126
142
  ): Record<string, string> {
127
143
  let sessionId: string;
128
144
  if (isOpenCodeSessionId(affinity)) {
@@ -132,6 +148,7 @@ export function buildOpenCodeHeaders(
132
148
  } else {
133
149
  sessionId = generateOpenCodeSessionId();
134
150
  }
151
+ const childId = isOpenCodeSessionId(childSessionId) ? childSessionId : sessionId;
135
152
  return {
136
153
  // The gate accepts both "cli" and "desktop" (measured 2026-10-17), so this
137
154
  // is not a refusal either way. It is "cli" because that is what the client
@@ -140,7 +157,7 @@ export function buildOpenCodeHeaders(
140
157
  // client identity this adapter does not have, for no measured benefit.
141
158
  "x-opencode-client": "cli",
142
159
  "x-opencode-session": sessionId,
143
- "x-opencode-session-id": sessionId,
160
+ "x-opencode-session-id": childId,
144
161
  "x-session-affinity": sessionId,
145
162
  "x-session-id": sessionId,
146
163
  // No `x-opencode-request`: the current client no longer sends it, and
@@ -0,0 +1,111 @@
1
+ /**
2
+ * The minimal system prompt injected into free-tier OpenCode payloads.
3
+ *
4
+ * The full CLI prompt is unnecessary: live trimming showed the free-tier gate
5
+ * accepts any system content that carries the `<env>` block with a
6
+ * `Working directory:` line — even a ~30-character placeholder passes. The
7
+ * marker line below is kept so `carriesOpenCodePrompt` can detect an already-
8
+ * injected prompt and avoid duplication.
9
+ */
10
+
11
+ /** The marker that identifies a body already carrying the injected prompt. */
12
+ export const OPENCODE_PROMPT_MARKER = "You are an interactive coding agent that helps users";
13
+
14
+ /**
15
+ * Assembles the minimal prompt: the marker line plus the `<env>` block the
16
+ * gate requires. No model identity, no skills, no style rules — the model is
17
+ * a gateway proxy and should not claim an upstream identity.
18
+ */
19
+ export function opencodeSystemPrompt(): string {
20
+ const directory = process.cwd().trim() || "/workspace";
21
+ return `You are an interactive coding agent that helps users with software engineering tasks.\n<env> Working directory: ${directory}</env>`;
22
+ }
23
+
24
+ /** Flattens a system/instruction value into its text fragments. */
25
+ export function textFragments(value: unknown): string[] {
26
+ if (typeof value === "string") {
27
+ return value.trim() === "" ? [] : [value];
28
+ }
29
+ if (Array.isArray(value)) return value.flatMap((item) => textFragments(item));
30
+ if (typeof value === "object" && value !== null) {
31
+ const record = value as Record<string, unknown>;
32
+ if (typeof record["text"] === "string") return textFragments(record["text"]);
33
+ if (record["content"] !== undefined) return textFragments(record["content"]);
34
+ }
35
+ return [];
36
+ }
37
+
38
+ /** Whether any text inside `value` already contains the injected prompt marker. */
39
+ export function carriesOpenCodePrompt(value: unknown): boolean {
40
+ return textFragments(value).some((part) => part.includes(OPENCODE_PROMPT_MARKER));
41
+ }
42
+
43
+ /**
44
+ * Appends the `<env>` block to the first existing system/developer message
45
+ * instead of prepending a new leading system message. The tool's own system
46
+ * content (Claude Code, DSH, …) keeps its place; the gate-required env block
47
+ * is tacked on at the end of it.
48
+ */
49
+ export function injectChatPrompt(payload: Record<string, unknown>, prompt: string): boolean {
50
+ const messages = payload["messages"];
51
+ if (!Array.isArray(messages)) return false;
52
+ const firstSystem = messages.findIndex((raw) => {
53
+ if (typeof raw !== "object" || raw === null) return false;
54
+ const role = (raw as Record<string, unknown>)["role"];
55
+ return role === "system" || role === "developer";
56
+ });
57
+ if (firstSystem === -1) {
58
+ payload["messages"] = [{ role: "system", content: prompt }, ...messages];
59
+ return true;
60
+ }
61
+ const message = messages[firstSystem] as Record<string, unknown>;
62
+ if (carriesOpenCodePrompt(message["content"])) return false;
63
+ const existing = textFragments(message["content"]).join("\n");
64
+ message["content"] = existing === "" ? prompt : `${existing}\n\n${prompt}`;
65
+ return true;
66
+ }
67
+
68
+ /** Appends the prompt to the top-level Anthropic `system` value. */
69
+ export function injectAnthropicPrompt(payload: Record<string, unknown>, prompt: string): boolean {
70
+ const system = payload["system"];
71
+ if (system !== undefined && carriesOpenCodePrompt(system)) return false;
72
+ if (system === undefined) {
73
+ payload["system"] = prompt;
74
+ return true;
75
+ }
76
+ if (typeof system === "string") {
77
+ payload["system"] = system.trim() === "" ? prompt : system + "\n\n" + prompt;
78
+ } else if (Array.isArray(system)) {
79
+ payload["system"] = [...system, { type: "text", text: prompt }];
80
+ } else {
81
+ payload["system"] = prompt;
82
+ }
83
+ return true;
84
+ }
85
+
86
+ /** Appends the prompt to the Responses `instructions` value. */
87
+ export function injectResponsesPrompt(payload: Record<string, unknown>, prompt: string): boolean {
88
+ const instructions = payload["instructions"];
89
+ if (instructions !== undefined && carriesOpenCodePrompt(instructions)) return false;
90
+ if (typeof instructions === "string") {
91
+ payload["instructions"] = instructions.trim() === "" ? prompt : instructions + "\n\n" + prompt;
92
+ } else {
93
+ payload["instructions"] = prompt;
94
+ }
95
+ return true;
96
+ }
97
+
98
+ /**
99
+ * Injects the prompt into a free-tier payload for the given wire family.
100
+ * System One payloads are never touched. Reports whether changed.
101
+ */
102
+ export function injectOpenCodePrompt(
103
+ payload: Record<string, unknown>,
104
+ wireFamily: "chat" | "responses" | "messages" | "systemone",
105
+ ): boolean {
106
+ if (wireFamily === "systemone") return false;
107
+ const prompt = opencodeSystemPrompt();
108
+ if (wireFamily === "chat") return injectChatPrompt(payload, prompt);
109
+ if (wireFamily === "messages") return injectAnthropicPrompt(payload, prompt);
110
+ return injectResponsesPrompt(payload, prompt);
111
+ }