cartethyia 2.7.5 → 2.7.7

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 (300) hide show
  1. package/.env.example +8 -3
  2. package/README.md +26 -2
  3. package/dist/dashboard/assets/BannedPage-B05aF8Dg.js +1 -0
  4. package/dist/dashboard/assets/BannedPage-B05aF8Dg.js.gz +0 -0
  5. package/dist/dashboard/assets/CliToolDetailPage-CLUhmjUy.js +3 -0
  6. package/dist/dashboard/assets/CliToolDetailPage-CLUhmjUy.js.gz +0 -0
  7. package/dist/dashboard/assets/CliToolsPage-CQmrqqrk.js +1 -0
  8. package/dist/dashboard/assets/CliToolsPage-CQmrqqrk.js.gz +0 -0
  9. package/dist/dashboard/assets/CombosPage-CHG_1Wr3.js +1 -0
  10. package/dist/dashboard/assets/CombosPage-CHG_1Wr3.js.gz +0 -0
  11. package/dist/dashboard/assets/{ConsoleLogPage-D5rol2j2.js → ConsoleLogPage-DPgbklad.js} +1 -1
  12. package/dist/dashboard/assets/ConsoleLogPage-DPgbklad.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-BKj_r0rp.js → CustomizationPage-pnfAqr_-.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-pnfAqr_-.js.gz +0 -0
  15. package/dist/dashboard/assets/HealthEventsModal-DGJuU2A6.js +1 -0
  16. package/dist/dashboard/assets/HealthEventsModal-DGJuU2A6.js.gz +0 -0
  17. package/dist/dashboard/assets/{InjectSystemPromptPanel-B5nZvmf0.js → InjectSystemPromptPanel-C-e2AMz6.js} +245 -2
  18. package/dist/dashboard/assets/InjectSystemPromptPanel-C-e2AMz6.js.gz +0 -0
  19. package/dist/dashboard/assets/LoginPage-J8wPbmfT.js +1 -0
  20. package/dist/dashboard/assets/LoginPage-J8wPbmfT.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-DnQPSIA8.js → ModelPicker-C6WlpU5E.js} +1 -1
  22. package/dist/dashboard/assets/ModelPicker-C6WlpU5E.js.gz +0 -0
  23. package/dist/dashboard/assets/OverviewPage-BSQnF2Lp.js +1 -0
  24. package/dist/dashboard/assets/OverviewPage-BSQnF2Lp.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-DK_e0FJz.js +7 -0
  26. package/dist/dashboard/assets/ProviderDetailPage-DK_e0FJz.js.gz +0 -0
  27. package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +1 -0
  28. package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
  29. package/dist/dashboard/assets/ProvidersPage-D_a3r6Gc.js +1 -0
  30. package/dist/dashboard/assets/ProvidersPage-D_a3r6Gc.js.gz +0 -0
  31. package/dist/dashboard/assets/{ProxyPage-5SnUSy3j.js → ProxyPage-BBTRBAQ3.js} +1 -1
  32. package/dist/dashboard/assets/ProxyPage-BBTRBAQ3.js.gz +0 -0
  33. package/dist/dashboard/assets/QuotaPage-B2WqMSG1.js +1 -0
  34. package/dist/dashboard/assets/QuotaPage-B2WqMSG1.js.gz +0 -0
  35. package/dist/dashboard/assets/{SettingsPage-BJtRZ4qD.js → SettingsPage-D7xp5Ij_.js} +1 -1
  36. package/dist/dashboard/assets/SettingsPage-D7xp5Ij_.js.gz +0 -0
  37. package/dist/dashboard/assets/SetupPage-LND6_Ss7.js +1 -0
  38. package/dist/dashboard/assets/SetupPage-LND6_Ss7.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-BfAb5-o_.js → StudioPage-BzNnm6Bi.js} +4 -4
  40. package/dist/dashboard/assets/StudioPage-BzNnm6Bi.js.gz +0 -0
  41. package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js +1 -0
  42. package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js.gz +0 -0
  43. package/dist/dashboard/assets/{UsagePage-BNzeZ2Vk.js → UsagePage-C1TbL24N.js} +13 -13
  44. package/dist/dashboard/assets/UsagePage-C1TbL24N.js.gz +0 -0
  45. package/dist/dashboard/assets/api-keys-KvX83mRe.js +1 -0
  46. package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
  47. package/dist/dashboard/assets/app-DRnQLhsc.js +9 -0
  48. package/dist/dashboard/assets/app-DRnQLhsc.js.gz +0 -0
  49. package/dist/dashboard/assets/app-mweRcsKp.css +2 -0
  50. package/dist/dashboard/assets/app-mweRcsKp.css.gz +0 -0
  51. package/dist/dashboard/assets/{assert-C0K-c4eo.js → assert-CidQVoNo.js} +1 -1
  52. package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
  53. package/dist/dashboard/assets/{badge-DfbhQU4k.js → badge-BaX2GTrn.js} +1 -1
  54. package/dist/dashboard/assets/badge-BaX2GTrn.js.gz +0 -0
  55. package/dist/dashboard/assets/{banner-BllT4LcF.js → banner-DFH4Bkte.js} +1 -1
  56. package/dist/dashboard/assets/banner-DFH4Bkte.js.gz +0 -0
  57. package/dist/dashboard/assets/{card-CtkX66Wd.js → card-CxDw0lK6.js} +1 -1
  58. package/dist/dashboard/assets/card-CxDw0lK6.js.gz +0 -0
  59. package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js +1 -0
  60. package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js.gz +0 -0
  61. package/dist/dashboard/assets/{cli-tools-CQXVMn4P.js → cli-tools-Bwv5-zGZ.js} +1 -1
  62. package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
  63. package/dist/dashboard/assets/{clipboard-button-BQqBQd2n.js → clipboard-button-DfS1ntiq.js} +1 -1
  64. package/dist/dashboard/assets/clipboard-button-DfS1ntiq.js.gz +0 -0
  65. package/dist/dashboard/assets/dialog-BK-NRr5u.js +1 -0
  66. package/dist/dashboard/assets/dialog-BK-NRr5u.js.gz +0 -0
  67. package/dist/dashboard/assets/{drawer-BrTEZ8zu.js → drawer-QqPul6sC.js} +1 -1
  68. package/dist/dashboard/assets/drawer-QqPul6sC.js.gz +0 -0
  69. package/dist/dashboard/assets/entry-BMlYJVFj.js +1 -0
  70. package/dist/dashboard/assets/entry-BMlYJVFj.js.gz +0 -0
  71. package/dist/dashboard/assets/entry-Dmx7gBiN.js +1 -0
  72. package/dist/dashboard/assets/entry-Dmx7gBiN.js.gz +0 -0
  73. package/dist/dashboard/assets/entry-vqGb8yVz.js +4 -0
  74. package/dist/dashboard/assets/entry-vqGb8yVz.js.gz +0 -0
  75. package/dist/dashboard/assets/formatters-DP-5E01-.js +1 -0
  76. package/dist/dashboard/assets/formatters-DP-5E01-.js.gz +0 -0
  77. package/dist/dashboard/assets/house-h9AZlJuT.js +1 -0
  78. package/dist/dashboard/assets/house-h9AZlJuT.js.gz +0 -0
  79. package/dist/dashboard/assets/{index-FQlj0HUT.js → index-D36vCZht.js} +2 -2
  80. package/dist/dashboard/assets/index-D36vCZht.js.gz +0 -0
  81. package/dist/dashboard/assets/{inline-C4gU5iOL.js → inline-CHJQwxLa.js} +1 -1
  82. package/dist/dashboard/assets/inline-CHJQwxLa.js.gz +0 -0
  83. package/dist/dashboard/assets/{input-BHHX_Tmm.js → input-BlmlizVV.js} +1 -1
  84. package/dist/dashboard/assets/input-BlmlizVV.js.gz +0 -0
  85. package/dist/dashboard/assets/{layout-CajrYUnD.js → layout-Bz93I-yE.js} +1 -1
  86. package/dist/dashboard/assets/layout-Bz93I-yE.js.gz +0 -0
  87. package/dist/dashboard/assets/{list-row-Bx2I7XUe.js → list-row-Ml16KCfu.js} +1 -1
  88. package/dist/dashboard/assets/list-row-Ml16KCfu.js.gz +0 -0
  89. package/dist/dashboard/assets/{live-DNNqRbj2.js → live-7_QpnYGu.js} +1 -1
  90. package/dist/dashboard/assets/live-7_QpnYGu.js.gz +0 -0
  91. package/dist/dashboard/assets/{mutation-Rr0TIvcj.js → mutation-GU7XdEjz.js} +1 -1
  92. package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
  93. package/dist/dashboard/assets/{network-C5UBACrJ.js → network-CuMDaTzT.js} +1 -1
  94. package/dist/dashboard/assets/network-CuMDaTzT.js.gz +0 -0
  95. package/dist/dashboard/assets/numbers-CoqpaDMx.js +2 -0
  96. package/dist/dashboard/assets/numbers-CoqpaDMx.js.gz +0 -0
  97. package/dist/dashboard/assets/{pagination-Xsi9Qx04.js → pagination-B5aOoweZ.js} +1 -1
  98. package/dist/dashboard/assets/pagination-B5aOoweZ.js.gz +0 -0
  99. package/dist/dashboard/assets/providers/zai.webp +0 -0
  100. package/dist/dashboard/assets/providers/zcode.webp +0 -0
  101. package/dist/dashboard/assets/{query-keys-BloKtaXJ.js → query-keys-YSoQOUh6.js} +1 -1
  102. package/dist/dashboard/assets/{query-keys-BloKtaXJ.js.gz → query-keys-YSoQOUh6.js.gz} +0 -0
  103. package/dist/dashboard/assets/quota-DJ1QlAOq.js +1 -0
  104. package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
  105. package/dist/dashboard/assets/{routing-in0f_IfK.js → routing-fnCsxgNO.js} +1 -1
  106. package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
  107. package/dist/dashboard/assets/{select-BLULNqTp.js → select-C9Ssle9b.js} +2 -2
  108. package/dist/dashboard/assets/select-C9Ssle9b.js.gz +0 -0
  109. package/dist/dashboard/assets/{settings-CcGczj6I.js → settings-BxslsErn.js} +1 -1
  110. package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
  111. package/dist/dashboard/assets/{stack-D2lIR0tg.js → stack-j7cXjgYX.js} +1 -1
  112. package/dist/dashboard/assets/stack-j7cXjgYX.js.gz +0 -0
  113. package/dist/dashboard/assets/{state-DTARjfiW.js → state-DHmEnLa2.js} +1 -1
  114. package/dist/dashboard/assets/state-DHmEnLa2.js.gz +0 -0
  115. package/dist/dashboard/assets/{switch-c0oPSnqW.js → switch-DmZcyTIC.js} +1 -1
  116. package/dist/dashboard/assets/switch-DmZcyTIC.js.gz +0 -0
  117. package/dist/dashboard/assets/{useMutation-m8WGNPrz.js → useMutation-CbCP4w1o.js} +1 -1
  118. package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
  119. package/dist/dashboard/index.html +2 -2
  120. package/dist/dashboard/index.html.gz +0 -0
  121. package/dist/dashboard/precompressed-assets.json +57 -57
  122. package/migrations/full-postgres/0042_add_telemetry_degenerate_stop.sql +14 -0
  123. package/migrations/full-postgres/0043_add_provider_custom_user_agent.sql +14 -0
  124. package/migrations/lite-sqlite3/0042_add_telemetry_degenerate_stop.sql +12 -0
  125. package/migrations/lite-sqlite3/0043_add_provider_custom_user_agent.sql +10 -0
  126. package/package.json +3 -1
  127. package/src/boot/dependencies.ts +10 -2
  128. package/src/config/providers.ts +13 -7
  129. package/src/config/security.ts +1 -1
  130. package/src/config/spec.ts +31 -17
  131. package/src/config/usage.ts +27 -0
  132. package/src/console/api-keys/routes.ts +19 -23
  133. package/src/console/cli-tools/cartethyia-websearch-plugin.ts +186 -0
  134. package/src/console/cli-tools/contracts.ts +39 -295
  135. package/src/console/cli-tools/fs-ops.ts +29 -0
  136. package/src/console/cli-tools/injectors/claude.ts +3 -3
  137. package/src/console/cli-tools/injectors/codex.ts +6 -6
  138. package/src/console/cli-tools/injectors/driver.ts +8 -105
  139. package/src/console/cli-tools/injectors/kilo.ts +146 -21
  140. package/src/console/cli-tools/injectors/opencode.ts +68 -17
  141. package/src/console/cli-tools/routes.ts +6 -0
  142. package/src/console/cli-tools/service.ts +7 -6
  143. package/src/console/observability/contracts.ts +6 -0
  144. package/src/console/observability/store.ts +3 -0
  145. package/src/console/providers/catalog/contracts.ts +4 -0
  146. package/src/console/providers/catalog/routes.ts +1 -0
  147. package/src/console/providers/detail/routes.ts +8 -0
  148. package/src/console/providers/detail/store.ts +4 -0
  149. package/src/console/quota/account-quota-tenant.ts +74 -0
  150. package/src/console/share/share-stats.ts +7 -9
  151. package/src/observability/event-log.ts +7 -0
  152. package/src/observability/event-query.ts +2 -0
  153. package/src/observability/telemetry-buffer.ts +9 -1
  154. package/src/persistence/boot.ts +13 -4
  155. package/src/persistence/schema.ts +15 -1
  156. package/src/persistence/stores/api-key-store.ts +19 -1
  157. package/src/protocol/canonical-model.ts +7 -0
  158. package/src/protocol/dsml.ts +5 -76
  159. package/src/protocol/request/gemini.ts +20 -1
  160. package/src/protocol/tool-identity.ts +15 -1
  161. package/src/providers/adapters/compatible-adapter.ts +29 -1
  162. package/src/providers/default-registry.ts +20 -4
  163. package/src/providers/discovery/discovery-types.ts +18 -0
  164. package/src/providers/discovery/probe-phases.ts +45 -0
  165. package/src/providers/discovery/probing-service.ts +41 -6
  166. package/src/providers/integrations/antigravity/antigravity-protocol.ts +108 -16
  167. package/src/providers/integrations/antigravity/antigravity-quota.ts +18 -6
  168. package/src/providers/integrations/antigravity/antigravity.ts +44 -11
  169. package/src/providers/integrations/codex/codex.ts +28 -1
  170. package/src/providers/integrations/cursor/cursor.ts +2 -3
  171. package/src/providers/integrations/github/github-discovery.ts +15 -2
  172. package/src/providers/integrations/github/github-oauth.ts +178 -9
  173. package/src/providers/integrations/github/github.ts +95 -14
  174. package/src/providers/integrations/kiro/kiro.ts +1 -2
  175. package/src/providers/integrations/qoder/chat-proto.ts +328 -0
  176. package/src/providers/integrations/qoder/claim-qoder-credits.ts +258 -0
  177. package/src/providers/integrations/qoder/qoder-adapter.ts +275 -0
  178. package/src/providers/integrations/qoder/qoder-auth.ts +201 -0
  179. package/src/providers/integrations/qoder/qoder-body.ts +78 -0
  180. package/src/providers/integrations/qoder/qoder-catalog.ts +14 -4
  181. package/src/providers/integrations/qoder/qoder-chat.ts +514 -0
  182. package/src/providers/integrations/qoder/qoder-cosy.ts +162 -0
  183. package/src/providers/integrations/qoder/qoder-grpc.ts +667 -0
  184. package/src/providers/integrations/qoder/qoder-ide.ts +584 -0
  185. package/src/providers/integrations/qoder/qoder-oauth.ts +4 -4
  186. package/src/providers/integrations/qoder/qoder-quota.ts +1 -1
  187. package/src/providers/integrations/qoder/qoder-realm.ts +40 -4
  188. package/src/providers/integrations/qoder/qoder-types.ts +51 -0
  189. package/src/providers/integrations/qoder/qoder-umid.ts +123 -8
  190. package/src/providers/integrations/qoder/qoder.ts +147 -1830
  191. package/src/providers/integrations/trae/trae.ts +2 -2
  192. package/src/providers/operations/account-error-classification.ts +67 -17
  193. package/src/providers/operations/byok-wire-profile.ts +19 -15
  194. package/src/providers/provider-contracts.ts +7 -0
  195. package/src/providers/provider-usage.ts +24 -55
  196. package/src/security/abuse.ts +5 -5
  197. package/src/security/admission/service.ts +11 -4
  198. package/src/security/api-key-auth.ts +5 -3
  199. package/src/transport/dispatch/attempt-finalize.ts +69 -21
  200. package/src/transport/dispatch/attempt-loop.ts +22 -0
  201. package/src/transport/dispatch/upstream.ts +4 -2
  202. package/src/transport/failure-policy.ts +15 -1
  203. package/src/transport/guards/error-lifecycle.ts +4 -0
  204. package/src/transport/request/state.ts +6 -0
  205. package/src/transport/routing/route-catalog.ts +8 -0
  206. package/src/transport/routing/route-model.ts +4 -0
  207. package/src/transport/routing/router.ts +8 -110
  208. package/src/transport/surface/reasoning-summary.ts +9 -14
  209. package/src/transport/vision-handoff.ts +83 -28
  210. package/dist/dashboard/assets/BannedPage-Cj15GsMp.js +0 -1
  211. package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
  212. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +0 -1
  213. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
  214. package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js +0 -1
  215. package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
  216. package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js +0 -1
  217. package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
  218. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +0 -1
  219. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
  220. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
  221. package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
  222. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
  223. package/dist/dashboard/assets/LoginPage-DkXb6dx-.js +0 -1
  224. package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
  225. package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
  226. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +0 -1
  227. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
  228. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +0 -5
  229. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
  230. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +0 -1
  231. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
  232. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +0 -1
  233. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
  234. package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
  235. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +0 -1
  236. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
  237. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
  238. package/dist/dashboard/assets/SetupPage-WTa0sktC.js +0 -1
  239. package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
  240. package/dist/dashboard/assets/StudioPage-BfAb5-o_.js.gz +0 -0
  241. package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js +0 -1
  242. package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js.gz +0 -0
  243. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js.gz +0 -0
  244. package/dist/dashboard/assets/api-keys-l29JROPv.js +0 -1
  245. package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
  246. package/dist/dashboard/assets/app--PJWq8_C.css +0 -2
  247. package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
  248. package/dist/dashboard/assets/app-Bgd3zANQ.js +0 -9
  249. package/dist/dashboard/assets/app-Bgd3zANQ.js.gz +0 -0
  250. package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
  251. package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
  252. package/dist/dashboard/assets/banner-BllT4LcF.js.gz +0 -0
  253. package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
  254. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
  255. package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
  256. package/dist/dashboard/assets/dialog-BEK7KP0H.js +0 -1
  257. package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
  258. package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
  259. package/dist/dashboard/assets/entry-CHWxbS56.js +0 -1
  260. package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
  261. package/dist/dashboard/assets/entry-EBHJ3DrE.js +0 -1
  262. package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
  263. package/dist/dashboard/assets/entry-LCS85hiq.js +0 -4
  264. package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
  265. package/dist/dashboard/assets/formatters-BAACA727.js +0 -1
  266. package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
  267. package/dist/dashboard/assets/github-badge-YSCE4UC2.js +0 -1
  268. package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
  269. package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
  270. package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
  271. package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
  272. package/dist/dashboard/assets/layout-CajrYUnD.js.gz +0 -0
  273. package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
  274. package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
  275. package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
  276. package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
  277. package/dist/dashboard/assets/numbers-CUWAZK4J.js +0 -2
  278. package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
  279. package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
  280. package/dist/dashboard/assets/providers/zai-coding-plan.svg +0 -6
  281. package/dist/dashboard/assets/providers/zai-coding-plan.svg.gz +0 -0
  282. package/dist/dashboard/assets/quota-DvQbD_sr.js +0 -1
  283. package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
  284. package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
  285. package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
  286. package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
  287. package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
  288. package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
  289. package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
  290. package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
  291. package/src/console/cli-tools/injectors/cline.ts +0 -110
  292. package/src/console/cli-tools/injectors/copilot.ts +0 -108
  293. package/src/console/cli-tools/injectors/cowork.ts +0 -64
  294. package/src/console/cli-tools/injectors/deepseek-tui.ts +0 -85
  295. package/src/console/cli-tools/injectors/droid.ts +0 -96
  296. package/src/console/cli-tools/injectors/grok-build.ts +0 -70
  297. package/src/console/cli-tools/injectors/hermes.ts +0 -101
  298. package/src/console/cli-tools/injectors/jcode.ts +0 -115
  299. package/src/console/cli-tools/injectors/openclaw.ts +0 -161
  300. package/src/providers/integrations/qoder/qoder-text-tools.ts +0 -277
@@ -33,7 +33,8 @@ import {
33
33
  GITHUB_AUTO_MODELS,
34
34
  recordGithubModelRoutes,
35
35
  } from "./github";
36
- import { GITHUB_REQUEST_HEADERS, parseGithubCredential } from "./github-oauth";
36
+ import { GITHUB_REQUEST_HEADERS, githubCopilotClientIds, parseGithubCredential } from "./github-oauth";
37
+ import { createHash } from "node:crypto";
37
38
 
38
39
  /** A context window above this is unsatisfiable headroom, not a real limit. */
39
40
  const MAX_CONTEXT = 1_000_000_000;
@@ -170,8 +171,20 @@ export async function discoverGithubModels(
170
171
  const signal =
171
172
  input.signal === undefined ? timeoutSignal : AbortSignal.any([input.signal, timeoutSignal]);
172
173
  try {
174
+ // The reference client stamps its Copilot identity on `/models` too
175
+ // (`_mixinHeaders` covers the Models request type): session + machine ids.
176
+ // Machine id is per-account — see `githubCopilotClientIds`.
177
+ const accountKey = createHash("sha256").update(`${apiHost}:${access}`).digest("hex");
178
+ const { sessionId, machineId } = await githubCopilotClientIds(accountKey);
173
179
  const response = await fetcher(`https://${apiHost}/models`, {
174
- headers: { accept: "application/json", authorization: `Bearer ${access}`, ...GITHUB_REQUEST_HEADERS },
180
+ headers: {
181
+ accept: "application/json",
182
+ authorization: `Bearer ${access}`,
183
+ ...GITHUB_REQUEST_HEADERS,
184
+ "VScode-SessionId": sessionId,
185
+ "VScode-MachineId": machineId,
186
+ "editor-device-id": machineId,
187
+ },
175
188
  signal,
176
189
  });
177
190
  if (!response.ok) return null;
@@ -29,13 +29,31 @@ import type { OAuthTokenRefreshResult } from "../../authentication/oauth-refresh
29
29
  import { OAuthDeviceFlow } from "../../authentication/oauth-device-flow";
30
30
  import type { FetchLike } from "../../authentication/oauth-client";
31
31
  import { resolveGithubEnterpriseDomain } from "../../../config/providers";
32
+ import { randomUUID, createHash } from "node:crypto";
33
+ import { getOrCreateInstallId } from "../shared/install-id";
32
34
 
33
35
 
34
36
  /** Public GitHub OAuth app id the Copilot clients use; not a secret. */
35
37
  export const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98" as const;
38
+ /** The OpenCode desktop client's own GitHub OAuth app id (used by its Copilot integration). */
39
+ export const GITHUB_OPENCODE_CLIENT_ID = "Ov23li8tweQw6odWQebz" as const;
36
40
  export const GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token" as const;
37
41
  /** Default API host when a token carries no `proxy-ep` claim. */
38
42
  export const GITHUB_DEFAULT_API_HOST = "api.individual.githubcopilot.com" as const;
43
+ /**
44
+ * The Copilot API host OpenCode's integration uses. The reference plugin always
45
+ * dials `api.githubcopilot.com` for GitHub.com (never the per-claim
46
+ * `api.individual.*` host the VS Code minted tokens carry), so an OpenCode
47
+ * login pins this host rather than falling back to the VS Code default.
48
+ */
49
+ export const GITHUB_OPENCODE_API_HOST = "api.githubcopilot.com" as const;
50
+ /**
51
+ * How long an OpenCode login's credential is treated as valid before the
52
+ * refresh sweep revisits it. The raw GitHub OAuth token has no Copilot token
53
+ * expiry (there is no minted token), so this is a far-future safeguard, not a
54
+ * real lifetime: a re-login or upstream expiry is what actually rotates it.
55
+ */
56
+ const GITHUB_OPENCODE_TOKEN_LIFETIME_MS = 365 * 24 * 60 * 60 * 1000;
39
57
 
40
58
  /**
41
59
  * Headers every Copilot inference and policy request must carry.
@@ -55,6 +73,52 @@ export const GITHUB_REQUEST_HEADERS: Readonly<Record<string, string>> = Object.f
55
73
  "x-github-api-version": "2026-08-01",
56
74
  });
57
75
 
76
+ /**
77
+ * Stable per-process Copilot session id.
78
+ *
79
+ * The reference extension (`_mixinHeaders`) stamps `VScode-SessionId` with the
80
+ * VS Code window session and `VScode-MachineId` with the machine id. There is
81
+ * no VS Code window here, so the closest 1:1 shapes are: a session id minted
82
+ * once per gateway process (a new window = a new process in the reference), and
83
+ * a stable per-installation identity for the machine id.
84
+ */
85
+ export const GITHUB_COPILOT_SESSION_ID = randomUUID();
86
+
87
+ /**
88
+ * Resolves the Copilot client identity headers shared by chat/auto/discovery.
89
+ *
90
+ * The machine id is derived deterministically from the persisted install id and
91
+ * an account fingerprint when one is provided. The reference extension uses one
92
+ * machine id per VS Code installation for every account, but this gateway pools
93
+ * many accounts on one host — sharing one id across all of them makes every
94
+ * account look like a single device (an easy clustering/abuse signal). A
95
+ * per-account machine id keeps each account looking like its own device while
96
+ * staying stable across restarts for the same account. Without an account key
97
+ * (e.g. credential could not be parsed) the raw install id is used.
98
+ */
99
+ export async function githubCopilotClientIds(
100
+ accountKey?: string,
101
+ ): Promise<{
102
+ readonly sessionId: string;
103
+ readonly machineId: string;
104
+ }> {
105
+ const installId = await getOrCreateInstallId("github");
106
+ const machineId =
107
+ accountKey === undefined || accountKey.length === 0
108
+ ? installId
109
+ : deterministicMachineId(installId, accountKey);
110
+ return {
111
+ sessionId: GITHUB_COPILOT_SESSION_ID,
112
+ machineId,
113
+ };
114
+ }
115
+
116
+ /** Stable UUID-shaped machine id derived from the install id and an account key. */
117
+ export function deterministicMachineId(installId: string, accountKey: string): string {
118
+ const digest = createHash("sha256").update(`${installId}:${accountKey}`).digest("hex");
119
+ return `${digest.slice(0, 8)}-${digest.slice(8, 12)}-${digest.slice(12, 16)}-${digest.slice(16, 20)}-${digest.slice(20, 32)}`;
120
+ }
121
+
58
122
  const DEVICE_INTERVAL_SECONDS = 5;
59
123
  const DEVICE_EXPIRY_SECONDS = 900;
60
124
  /** Copilot tokens are short-lived; a missing `expires_at` falls back to 25 minutes. */
@@ -196,17 +260,80 @@ async function fetchGitHubLogin(
196
260
  }
197
261
  }
198
262
 
263
+ interface CopilotUserProfile {
264
+ readonly chat_enabled?: boolean;
265
+ readonly can_signup_for_limited?: boolean;
266
+ }
267
+
268
+ /**
269
+ * Reads the Copilot entitlement profile for a freshly approved GitHub token.
270
+ *
271
+ * OAuth itself succeeds for any GitHub account; entitlement is the only signal
272
+ * that the account can chat. Mirrors the reference OpenCode provider: an
273
+ * explicit `chat_enabled: false` is a denial (the account is not signed up or
274
+ * has no seat), and a failed/malformed lookup must not turn a GitHub hiccup
275
+ * into a denial — only an explicit answer blocks login.
276
+ */
277
+ async function fetchGitHubCopilotEntitlement(
278
+ githubAccessToken: string,
279
+ domain: string,
280
+ fetchFn: FetchLike,
281
+ signal: AbortSignal,
282
+ ): Promise<{ denied: string } | { denied?: undefined }> {
283
+ try {
284
+ const endpoint =
285
+ domain === "github.com"
286
+ ? "https://api.github.com/copilot_internal/user"
287
+ : `https://api.${domain}/copilot_internal/user`;
288
+ const response = await fetchFn(endpoint, {
289
+ headers: {
290
+ accept: "application/json",
291
+ authorization: `Bearer ${githubAccessToken}`,
292
+ "user-agent": GITHUB_REQUEST_HEADERS["user-agent"]!,
293
+ "x-github-api-version": "2025-04-01",
294
+ },
295
+ signal,
296
+ });
297
+ if (!response.ok) return { denied: undefined };
298
+ const profile = record(await response.json()) as CopilotUserProfile | undefined;
299
+ if (profile?.chat_enabled === false) {
300
+ if (profile.can_signup_for_limited) {
301
+ return {
302
+ denied:
303
+ "This GitHub account is not signed up for GitHub Copilot. Sign up for Copilot Free at https://github.com/features/copilot/plans and connect again.",
304
+ };
305
+ }
306
+ return {
307
+ denied:
308
+ "This GitHub account does not have GitHub Copilot access. It needs an active Copilot subscription or a seat assigned by an organization.",
309
+ };
310
+ }
311
+ return { denied: undefined };
312
+ } catch {
313
+ // Entitlement is a gate, not a reliability dependency: a network glitch
314
+ // here must not lock out an account that did approve the login.
315
+ return { denied: undefined };
316
+ }
317
+ }
318
+
199
319
  export class GithubOAuthClient extends OAuthDeviceFlow {
200
320
  override readonly supportsDeviceCode = true;
201
321
  override readonly supportsBrowserCode = false;
202
322
 
203
323
  protected override readonly providerLabel = "GitHub Copilot";
204
- protected override readonly clientId = GITHUB_CLIENT_ID;
205
324
  protected override readonly tokenUrl = GITHUB_ACCESS_TOKEN_URL;
206
325
  protected override readonly scopes = "read:user";
207
326
 
208
- constructor(fetchFn: FetchLike = globalThis.fetch) {
327
+ /** Which GitHub OAuth app this flow presents. Defaults to the Copilot Chat
328
+ * extension's app; OpenCode's own app differs (`GITHUB_OPENCODE_CLIENT_ID`). */
329
+ protected override readonly clientId: string;
330
+
331
+ constructor(
332
+ fetchFn: FetchLike = globalThis.fetch,
333
+ clientId: string = GITHUB_CLIENT_ID,
334
+ ) {
209
335
  super(fetchFn);
336
+ this.clientId = clientId;
210
337
  }
211
338
 
212
339
  override async startDeviceAuth(_context?: OAuthDeviceFlowContext): Promise<OAuthDeviceStartResult> {
@@ -218,7 +345,7 @@ export class GithubOAuthClient extends OAuthDeviceFlow {
218
345
  "content-type": "application/x-www-form-urlencoded",
219
346
  "user-agent": GITHUB_REQUEST_HEADERS["user-agent"]!,
220
347
  },
221
- body: new URLSearchParams({ client_id: GITHUB_CLIENT_ID, scope: "read:user" }),
348
+ body: new URLSearchParams({ client_id: this.clientId, scope: "read:user" }),
222
349
  });
223
350
  const body = record(await readJsonResponse(response, "GitHub device authorization"));
224
351
  const deviceCode = nonEmptyTrimmedString(body?.device_code);
@@ -272,7 +399,7 @@ export class GithubOAuthClient extends OAuthDeviceFlow {
272
399
  "user-agent": GITHUB_REQUEST_HEADERS["user-agent"]!,
273
400
  },
274
401
  body: new URLSearchParams({
275
- client_id: GITHUB_CLIENT_ID,
402
+ client_id: this.clientId,
276
403
  device_code: deviceAuthId,
277
404
  grant_type: "urn:ietf:params:oauth:grant-type:device_code",
278
405
  }),
@@ -315,21 +442,48 @@ export class GithubOAuthClient extends OAuthDeviceFlow {
315
442
  : `GitHub device polling failed (${response.status})`;
316
443
  return { status: "failed", reason };
317
444
  }
318
- let minted;
445
+ let minted: Awaited<ReturnType<typeof mintGithubToken>> | undefined;
319
446
  try {
320
- minted = await mintGithubToken(githubToken, domain, this.fetchFn);
447
+ // OAuth succeeds for any GitHub account; the entitlement profile is the
448
+ // only signal that the account can actually chat. An explicit denial is
449
+ // surfaced as a failed verdict before any token is minted or stored,
450
+ // mirroring the reference OpenCode provider.
451
+ const entitlement = await fetchGitHubCopilotEntitlement(
452
+ githubToken,
453
+ domain,
454
+ this.fetchFn,
455
+ AbortSignal.timeout(10_000),
456
+ );
457
+ if (entitlement.denied !== undefined) {
458
+ return { status: "failed", reason: entitlement.denied };
459
+ }
460
+ // OpenCode's OAuth app is the client the `opencode-copilot` wire mode
461
+ // presents upstream, and that mode uses the raw GitHub token directly —
462
+ // no minted Copilot token. The VS Code mint endpoint
463
+ // (`/copilot_internal/v2/token`) rejects non-VS-Code client ids with 403
464
+ // (GitHub's anti-scraping gate), so an OpenCode login must not mint.
465
+ if (this.clientId !== GITHUB_OPENCODE_CLIENT_ID) {
466
+ minted = await mintGithubToken(githubToken, domain, this.fetchFn);
467
+ }
321
468
  } catch (error) {
322
469
  // The mint runs after approval: surface its reason as a failed verdict,
323
470
  // not an exception that escapes the dashboard's poll request.
324
471
  return { status: "failed", reason: error instanceof Error ? error.message : "GitHub Copilot token mint failed" };
325
472
  }
326
473
  const label = await fetchGitHubLogin(githubToken, domain, this.fetchFn, AbortSignal.timeout(10_000));
474
+ const access = minted === undefined ? githubToken : minted.access;
475
+ const apiHost = minted === undefined ? GITHUB_OPENCODE_API_HOST : minted.apiHost;
476
+ const expiresAt =
477
+ minted === undefined
478
+ ? new Date(Date.now() + GITHUB_OPENCODE_TOKEN_LIFETIME_MS)
479
+ : minted.expiresAt;
327
480
  const result: OAuthExchangeResult = {
328
- access: encodeGithubCredential(minted.access, minted.apiHost, githubToken),
481
+ access: encodeGithubCredential(access, apiHost, githubToken),
329
482
  // The GitHub token is the refresh value: it is what re-mints the Copilot
330
- // token, which expires on its own much shorter clock.
483
+ // token (VS Code app) or is the raw credential itself (OpenCode app),
484
+ // depending on which app the flow presented.
331
485
  refresh: githubToken,
332
- expiresAt: minted.expiresAt,
486
+ expiresAt,
333
487
  ...(label === undefined ? {} : { accountLabel: label }),
334
488
  };
335
489
  return { status: "complete", result };
@@ -337,6 +491,21 @@ export class GithubOAuthClient extends OAuthDeviceFlow {
337
491
 
338
492
 
339
493
  override async refresh(refreshToken: string, signal?: AbortSignal): Promise<OAuthTokenRefreshResult> {
494
+ // OpenCode's app uses the raw GitHub token directly — there is no minted
495
+ // Copilot token to re-mint, and the VS Code mint endpoint rejects the
496
+ // OpenCode client id. Refresh is then a no-op that keeps the credential
497
+ // valid on its far-future lifetime.
498
+ if (this.clientId === GITHUB_OPENCODE_CLIENT_ID) {
499
+ return {
500
+ access: encodeGithubCredential(
501
+ refreshToken,
502
+ GITHUB_OPENCODE_API_HOST,
503
+ refreshToken,
504
+ ),
505
+ refresh: refreshToken,
506
+ expiresAt: new Date(Date.now() + GITHUB_OPENCODE_TOKEN_LIFETIME_MS),
507
+ };
508
+ }
340
509
  const minted = await mintGithubToken(
341
510
  refreshToken,
342
511
  copilotGitHubDomain(),
@@ -23,14 +23,16 @@ import { allParts, type CanonicalEvent, type CanonicalRequest, type ContentPart
23
23
  import { OpenAICompatibleAdapter, withBearerAuthentication } from "../../adapters/compatible-adapter";
24
24
  import { postUpstreamJson } from "../../../protocol/upstream/post-json";
25
25
  import { providerBaseUrl } from "../../provider-metadata";
26
- import { getOrCreateInstallId } from "../shared/install-id";
27
26
  import { resolveRedisClient } from "../../../persistence/redis";
28
27
  import { applyParamQuirks } from "../../../protocol/translation/quirks";
29
28
  import { resolveInboundSessionId } from "../../operations/session-resolution";
30
29
  import {
31
30
  GITHUB_REQUEST_HEADERS,
31
+ githubCopilotClientIds,
32
32
  parseGithubCredential,
33
+ type GithubCredential,
33
34
  } from "./github-oauth";
35
+ import { resolveGithubCopilotMode } from "../../../config/providers";
34
36
 
35
37
  export const GITHUB_PROVIDER_ID = "github" as const;
36
38
 
@@ -502,6 +504,36 @@ class GithubAdapter extends OpenAICompatibleAdapter {
502
504
  );
503
505
  }
504
506
 
507
+ /**
508
+ * Minimal OpenCode-style Copilot headers using the long-lived GitHub OAuth
509
+ * token directly (no minted Copilot token, no VS Code identity). This is
510
+ * the shape the official OpenCode plugin sends; proven live (2026-11-03):
511
+ *
512
+ * - POST /auto with these headers + the raw GitHub token -> 200, returns the
513
+ * session token and selects gpt-6-luna;
514
+ * - POST /responses with `Copilot-Session-Token` + GitHub token -> 200 stream.
515
+ */
516
+ async #opencodeStyleHeaders(
517
+ context: ProviderDispatchContext,
518
+ request: CanonicalRequest,
519
+ credential: GithubCredential,
520
+ ): Promise<Record<string, string>> {
521
+ const headers: Record<string, string> = {
522
+ "content-type": "application/json",
523
+ "user-agent": "opencode/0.1.0",
524
+ "openai-intent": "conversation-edits",
525
+ "x-github-api-version": "2026-08-01",
526
+ "x-interaction-type": "conversation-agent",
527
+ "x-interaction-id": randomUUID(),
528
+ "x-initiator": isAgentInitiated(request) ? "agent" : "user",
529
+ "x-request-id": context.request_id ?? randomUUID(),
530
+ };
531
+ if (credential.github !== undefined && credential.github.length > 0) {
532
+ headers.authorization = `Bearer ${credential.github}`;
533
+ }
534
+ return headers;
535
+ }
536
+
505
537
  async #selectAutoModel(
506
538
  prompt: string,
507
539
  tier: "efficiency" | "balance" | "intelligence",
@@ -510,13 +542,24 @@ class GithubAdapter extends OpenAICompatibleAdapter {
510
542
  candidate: ProviderDispatchTarget,
511
543
  context: ProviderDispatchContext,
512
544
  ): Promise<GithubAutoDecision> {
513
- const headers = await this.prepareHeaders(context, request, candidate);
514
545
  const credential = context.credential.secret === undefined
515
546
  ? undefined
516
547
  : parseGithubCredential(new TextDecoder().decode(context.credential.secret));
517
548
  if (credential === undefined) {
518
549
  throw new GatewayError("authentication_failed", 401, "GitHub Copilot credential is missing (request {requestId}). Wrong key, right door — check the credential 🔑");
519
550
  }
551
+ // `opencode-copilot` mode (default): raw GitHub token + minimal headers,
552
+ // proven the most stable (single token, no mint expiry). The reference
553
+ // mode (`vscode-client-real`) uses the minted Copilot token + full VS Code
554
+ // headers — but a stale/expired minted token fails with 403 and the
555
+ // reference headers on /auto can answer 400 "invalid apiVersion" unless the
556
+ // minted token is fresh, so the default stays opencode.
557
+ const headers =
558
+ resolveGithubCopilotMode() === "opencode-copilot" &&
559
+ credential.github !== undefined &&
560
+ credential.github.length > 0
561
+ ? await this.#opencodeStyleHeaders(context, request, credential)
562
+ : await this.prepareHeaders(context, request, candidate);
520
563
  const payload: Record<string, unknown> = { prompt, tier };
521
564
  if (hasImage) payload.has_image = true;
522
565
  const outboundFetch = context.outbound_fetch ?? this.#fetch ?? globalThis.fetch;
@@ -648,20 +691,64 @@ class GithubAdapter extends OpenAICompatibleAdapter {
648
691
  // it and wins — the route-level User-Agent is for generic OpenAI-compatible
649
692
  // hosts and would be rejected here.
650
693
  Object.assign(headers, GITHUB_REQUEST_HEADERS);
694
+ const secret = context.credential.secret;
695
+ let parsedCredential: ReturnType<typeof parseGithubCredential> | undefined;
696
+ if (secret !== undefined && secret.length > 0) {
697
+ try {
698
+ parsedCredential = parseGithubCredential(new TextDecoder().decode(secret));
699
+ } catch {
700
+ // Unparseable credential; fall back to the reference identity below.
701
+ }
702
+ }
651
703
  const autoSessionToken = this.#autoSessionTokens.get(request);
652
- if (autoSessionToken !== undefined) {
704
+ // Auto-selected requests stream behind the session token. In the default
705
+ // `opencode-copilot` mode (raw GitHub token + minimal headers, proven 200
706
+ // on /auto and /responses), the whole request uses the OpenCode shape. The
707
+ // reference mode (`vscode-client-real`) keeps the reference identity and
708
+ // the minted Copilot token.
709
+ if (autoSessionToken !== undefined && parsedCredential?.github !== undefined) {
710
+ if (resolveGithubCopilotMode() === "opencode-copilot") {
711
+ const opencode = await this.#opencodeStyleHeaders(context, request, parsedCredential);
712
+ for (const key of Object.keys(headers)) delete headers[key];
713
+ Object.assign(headers, opencode);
714
+ headers["Copilot-Session-Token"] = autoSessionToken;
715
+ return headers;
716
+ }
717
+ headers["Copilot-Session-Token"] = autoSessionToken;
718
+ } else if (autoSessionToken !== undefined) {
653
719
  headers["Copilot-Session-Token"] = autoSessionToken;
654
720
  }
655
721
  const requestId = context.request_id ?? randomUUID();
722
+ // Reference (`_mixinHeaders` + request path): the interaction id is a
723
+ // separate value from the request id (`X-Request-Id`), and the Copilot
724
+ // client identity is stamped as `VScode-SessionId`/`VScode-MachineId`.
725
+ // The library version header carries the fetcher library id (`node-http`
726
+ // etc.), not the extension version — we previously sent the extension
727
+ // version there, which the upstream reads as a different client fingerprint.
728
+ const interactionId = randomUUID();
729
+ // Machine id is per-account (stable derive from install id + account
730
+ // fingerprint), so a pooled gateway does not make every account look like
731
+ // one device.
732
+ const accountKey =
733
+ parsedCredential === undefined
734
+ ? undefined
735
+ : createHash("sha256")
736
+ .update(`${parsedCredential.apiHost}:${parsedCredential.access}`)
737
+ .digest("hex");
738
+ const { sessionId, machineId } = await githubCopilotClientIds(accountKey);
656
739
  Object.assign(headers, {
657
- "editor-device-id": await getOrCreateInstallId("github"),
740
+ "editor-device-id": machineId,
741
+ "VScode-MachineId": machineId,
742
+ "VScode-SessionId": sessionId,
658
743
  "openai-intent": "conversation-agent",
744
+ // Reference stamps `Openai-Organization` on HTTP chat requests.
745
+ ...(candidate?.wire_family === "chat" ? { "Openai-Organization": "github-copilot" } : {}),
659
746
  "x-agent-task-id": requestId,
660
- "x-interaction-id": requestId,
747
+ "x-interaction-id": interactionId,
661
748
  "x-initiator": isAgentInitiated(request) ? "agent" : "user",
662
749
  "x-interaction-type": "conversation-agent",
663
750
  "x-request-id": requestId,
664
- "x-vscode-user-agent-library-version": "vscode-chat/0.72.0",
751
+ "x-vscode-user-agent-library-version": "node-http",
665
752
  });
666
753
  // The copy Claude family is served on the native Anthropic Messages wire,
667
754
  // which gates feature betas behind `anthropic-beta` (mirroring the
@@ -676,14 +763,8 @@ class GithubAdapter extends OpenAICompatibleAdapter {
676
763
  } else {
677
764
  delete headers["copilot-vision-request"];
678
765
  }
679
- const secret = context.credential.secret;
680
- if (secret === undefined || secret.length === 0) return headers;
681
- try {
682
- const { access } = parseGithubCredential(new TextDecoder().decode(secret));
683
- headers.authorization = `Bearer ${access}`;
684
- } catch {
685
- // Left as the factory sent it: the request fails closed at the upstream
686
- // auth boundary, and the parse error belongs to the credential boundary.
766
+ if (parsedCredential !== undefined) {
767
+ headers.authorization = `Bearer ${parsedCredential.access}`;
687
768
  }
688
769
  return headers;
689
770
  }
@@ -52,7 +52,6 @@ import {
52
52
  } from "./kiro-request";
53
53
  import { machineIdForAuthState } from "./kiro-machine-id";
54
54
  import { estimateKiroSessionCache } from "./kiro-cache";
55
- import { applyCacheMode } from "../../provider-usage";
56
55
  import { resolveKiroProfileArn } from "./kiro-profile";
57
56
  import {
58
57
  AWS_REGION_PATTERN,
@@ -284,7 +283,7 @@ function kiroUsage(
284
283
  // The runtime never reports cache hits; close the gap with our own history.
285
284
  // A genuine ( >0) report conserves the complete record. Then the operator's
286
285
  // cache mode decides whether a hit makes the whole input count as cached.
287
- return applyCacheMode(estimateKiroSessionCache(record, sessionId, messages));
286
+ return estimateKiroSessionCache(record, sessionId, messages);
288
287
  }
289
288
 
290
289
  /**