@cartanova/qgrid-cli 2.10.9 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/bundle/dist/_virtual/_rolldown/runtime.js +1 -10
  2. package/bundle/dist/application/monit/log-buffer.js +12 -6
  3. package/bundle/dist/application/monit/monit.frame.js +11 -3
  4. package/bundle/dist/application/monit/monit.types.js +1 -1
  5. package/bundle/dist/application/qgrid/conv-routing.js +9 -6
  6. package/bundle/dist/application/qgrid/expired-token-reminder.js +2 -2
  7. package/bundle/dist/application/qgrid/oauth.js +31 -4
  8. package/bundle/dist/application/qgrid/qgrid-image-generation.js +1 -1
  9. package/bundle/dist/application/qgrid/qgrid-response-format.js +22 -20
  10. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +43 -34
  11. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +128 -93
  12. package/bundle/dist/application/qgrid/qgrid.frame.js +930 -49
  13. package/bundle/dist/application/qgrid/qgrid.types.js +212 -5
  14. package/bundle/dist/application/qgrid/schema-prompt.js +75 -48
  15. package/bundle/dist/application/qgrid/slack-user-map.js +1 -1
  16. package/bundle/dist/application/qgrid/token-death.js +1 -1
  17. package/bundle/dist/application/qgrid/token-subscriber.js +83 -30
  18. package/bundle/dist/application/qgrid/token-trigger-setup.js +1 -1
  19. package/bundle/dist/application/qgrid/token-window-keepalive.js +8 -6
  20. package/bundle/dist/application/qgrid/tool-emulation-schema.js +13 -13
  21. package/bundle/dist/application/qgrid/tool-emulation.js +19 -15
  22. package/bundle/dist/application/request-log/json-schema-type-text.js +29 -12
  23. package/bundle/dist/application/request-log/request-log.model.js +83 -69
  24. package/bundle/dist/application/request-log/request-log.types.js +8 -2
  25. package/bundle/dist/application/request-log/zod-code-format.js +1 -1
  26. package/bundle/dist/application/request-log-step/request-log-step.model.js +1 -1
  27. package/bundle/dist/application/request-log-step/request-log-step.types.js +1 -1
  28. package/bundle/dist/application/setting/setting.constant.js +1 -1
  29. package/bundle/dist/application/setting/setting.model.js +2 -2
  30. package/bundle/dist/application/setting/setting.store.js +2 -2
  31. package/bundle/dist/application/setting/setting.types.js +1 -1
  32. package/bundle/dist/application/sonamu.generated.js +40 -16
  33. package/bundle/dist/application/sonamu.generated.sso.js +2 -1
  34. package/bundle/dist/application/token/token.model.js +26 -9
  35. package/bundle/dist/application/token/token.types.js +20 -3
  36. package/bundle/dist/i18n/en.js +15 -1
  37. package/bundle/dist/i18n/ko.js +15 -1
  38. package/bundle/dist/i18n/sd.generated.js +2 -1
  39. package/bundle/dist/migrations/20260807133553_manual__backfill_request_log_cost.js +8 -6
  40. package/bundle/dist/migrations/20261018215031_alter_request_logs_add1_alter1.js +15 -0
  41. package/bundle/dist/server-bootstrap.js +4 -2
  42. package/bundle/dist/server-error-handler.js +1 -1
  43. package/bundle/dist/sonamu.config.js +37 -8
  44. package/bundle/dist/startup-migrations.js +17 -7
  45. package/bundle/dist/testing/global.js +1 -1
  46. package/bundle/dist/testing/schema-bench.js +0 -0
  47. package/bundle/dist/testing/test-database-name.js +1 -1
  48. package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +1 -1
  49. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +11 -5
  50. package/bundle/dist/utils/providers/anthropic/anthropic-quota.js +4 -4
  51. package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
  52. package/bundle/dist/utils/providers/anthropic/claude-session.js +20 -19
  53. package/bundle/dist/utils/providers/anthropic/fence-strip.js +1 -1
  54. package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +49 -23
  55. package/bundle/dist/utils/providers/common/credentials.js +5 -1
  56. package/bundle/dist/utils/providers/common/effort.js +3 -3
  57. package/bundle/dist/utils/providers/common/model-cost.js +69 -14
  58. package/bundle/dist/utils/providers/common/provider-types.js +29 -1
  59. package/bundle/dist/utils/providers/common/schema-validation.js +78 -40
  60. package/bundle/dist/utils/providers/common/smooth-weighted-round-robin.js +1 -1
  61. package/bundle/dist/utils/providers/common/strictifier.js +62 -43
  62. package/bundle/dist/utils/providers/common/thinking.js +3 -2
  63. package/bundle/dist/utils/providers/common/ttft.js +1 -1
  64. package/bundle/dist/utils/providers/grok/grok-backend-protocol.js +427 -0
  65. package/bundle/dist/utils/providers/grok/grok-constants.js +55 -0
  66. package/bundle/dist/utils/providers/grok/grok-direct-client.js +196 -0
  67. package/bundle/dist/utils/providers/grok/grok-dispatcher.js +1313 -0
  68. package/bundle/dist/utils/providers/grok/grok-headers.js +118 -0
  69. package/bundle/dist/utils/providers/grok/grok-media-client.js +420 -0
  70. package/bundle/dist/utils/providers/grok/grok-models.js +114 -0
  71. package/bundle/dist/utils/providers/grok/grok-oauth.js +455 -0
  72. package/bundle/dist/utils/providers/grok/grok-quota.js +119 -0
  73. package/bundle/dist/utils/providers/grok/grok-refresh.js +192 -0
  74. package/bundle/dist/utils/providers/grok/grok-types.js +186 -0
  75. package/bundle/dist/utils/providers/grok/grok-voice-client.js +199 -0
  76. package/bundle/dist/utils/providers/grok/index.js +11 -0
  77. package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +111 -83
  78. package/bundle/dist/utils/providers/openai/openai-callback-relay.js +3 -2
  79. package/bundle/dist/utils/providers/openai/openai-constants.js +1 -1
  80. package/bundle/dist/utils/providers/openai/openai-direct-client.js +23 -7
  81. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +143 -106
  82. package/bundle/dist/utils/providers/openai/openai-image-generation.js +48 -33
  83. package/bundle/dist/utils/providers/openai/openai-oauth.js +28 -13
  84. package/bundle/dist/utils/providers/openai/openai-quota.js +38 -27
  85. package/bundle/dist/utils/providers/openai/openai-refresh.js +17 -9
  86. package/bundle/dist/utils/providers/openai/openai-sse.js +1 -1
  87. package/bundle/dist/utils/providers/openai/openai-transport-config.js +1 -1
  88. package/bundle/dist/utils/quiet-hours.js +1 -1
  89. package/bundle/dist/utils/slack-notify.js +14 -8
  90. package/bundle/dist/utils/subset-loaders.js +4 -5
  91. package/bundle/src/application/monit/log-buffer.ts +23 -9
  92. package/bundle/src/application/monit/monit.frame.ts +22 -5
  93. package/bundle/src/application/monit/monit.types.ts +6 -0
  94. package/bundle/src/application/qgrid/conv-routing.test.ts +76 -4
  95. package/bundle/src/application/qgrid/conv-routing.ts +35 -9
  96. package/bundle/src/application/qgrid/expired-token-reminder.ts +9 -1
  97. package/bundle/src/application/qgrid/oauth.ts +51 -15
  98. package/bundle/src/application/qgrid/qgrid-image-generation.ts +9 -0
  99. package/bundle/src/application/qgrid/qgrid-response-format.ts +50 -25
  100. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +33 -0
  101. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +87 -40
  102. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +97 -0
  103. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +274 -126
  104. package/bundle/src/application/qgrid/qgrid.frame.test.ts +1013 -3
  105. package/bundle/src/application/qgrid/qgrid.frame.ts +1415 -60
  106. package/bundle/src/application/qgrid/qgrid.types.ts +335 -0
  107. package/bundle/src/application/qgrid/schema-prompt.ts +105 -41
  108. package/bundle/src/application/qgrid/slack-user-map.ts +5 -0
  109. package/bundle/src/application/qgrid/token-death.ts +4 -0
  110. package/bundle/src/application/qgrid/token-subscriber.test.ts +21 -19
  111. package/bundle/src/application/qgrid/token-subscriber.ts +186 -53
  112. package/bundle/src/application/qgrid/token-trigger-setup.ts +2 -0
  113. package/bundle/src/application/qgrid/token-window-keepalive.ts +49 -6
  114. package/bundle/src/application/qgrid/tool-emulation-schema.ts +33 -29
  115. package/bundle/src/application/qgrid/tool-emulation.ts +52 -27
  116. package/bundle/src/application/request-log/json-schema-type-text.test.ts +5 -5
  117. package/bundle/src/application/request-log/json-schema-type-text.ts +81 -26
  118. package/bundle/src/application/request-log/request-log.entity.json +8 -0
  119. package/bundle/src/application/request-log/request-log.model.test.ts +111 -4
  120. package/bundle/src/application/request-log/request-log.model.ts +279 -145
  121. package/bundle/src/application/request-log/request-log.types.ts +17 -0
  122. package/bundle/src/application/request-log/zod-code-format.ts +11 -0
  123. package/bundle/src/application/request-log-step/request-log-step.model.ts +1 -0
  124. package/bundle/src/application/request-log-step/request-log-step.types.ts +2 -0
  125. package/bundle/src/application/setting/setting.constant.ts +9 -0
  126. package/bundle/src/application/setting/setting.model.ts +12 -2
  127. package/bundle/src/application/setting/setting.store.ts +5 -1
  128. package/bundle/src/application/setting/setting.types.ts +8 -0
  129. package/bundle/src/application/sonamu.generated.http +135 -0
  130. package/bundle/src/application/sonamu.generated.sso.ts +3 -0
  131. package/bundle/src/application/sonamu.generated.ts +29 -0
  132. package/bundle/src/application/token/token.identity.test.ts +20 -0
  133. package/bundle/src/application/token/token.model.ts +66 -7
  134. package/bundle/src/application/token/token.types.ts +24 -1
  135. package/bundle/src/i18n/en.ts +19 -0
  136. package/bundle/src/i18n/ko.ts +21 -0
  137. package/bundle/src/i18n/sd.generated.ts +24 -2
  138. package/bundle/src/migrations/20260807133553_manual__backfill_request_log_cost.ts +16 -8
  139. package/bundle/src/migrations/20261018215031_alter_request_logs_add1_alter1.ts +15 -0
  140. package/bundle/src/server-bootstrap.ts +4 -2
  141. package/bundle/src/server-error-handler.ts +1 -0
  142. package/bundle/src/sonamu.config.ts +69 -7
  143. package/bundle/src/startup-migrations.ts +27 -9
  144. package/bundle/src/testing/global.ts +20 -0
  145. package/bundle/src/testing/schema-bench.ts +105 -30
  146. package/bundle/src/testing/test-database-name.ts +2 -0
  147. package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +8 -0
  148. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +41 -6
  149. package/bundle/src/utils/providers/anthropic/anthropic-quota.ts +7 -3
  150. package/bundle/src/utils/providers/anthropic/anthropic-thinking.ts +6 -0
  151. package/bundle/src/utils/providers/anthropic/claude-session.ts +58 -24
  152. package/bundle/src/utils/providers/anthropic/fence-strip.ts +11 -0
  153. package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +110 -45
  154. package/bundle/src/utils/providers/common/credentials.ts +8 -0
  155. package/bundle/src/utils/providers/common/effort.ts +9 -2
  156. package/bundle/src/utils/providers/common/model-cost.test.ts +48 -1
  157. package/bundle/src/utils/providers/common/model-cost.ts +259 -158
  158. package/bundle/src/utils/providers/common/provider-dispatcher.ts +98 -2
  159. package/bundle/src/utils/providers/common/provider-types.ts +46 -3
  160. package/bundle/src/utils/providers/common/schema-validation.test.ts +5 -1
  161. package/bundle/src/utils/providers/common/schema-validation.ts +124 -56
  162. package/bundle/src/utils/providers/common/smooth-weighted-round-robin.ts +4 -0
  163. package/bundle/src/utils/providers/common/strictifier.ts +185 -59
  164. package/bundle/src/utils/providers/common/thinking.ts +2 -2
  165. package/bundle/src/utils/providers/common/ttft.ts +4 -2
  166. package/bundle/src/utils/providers/grok/__fixtures__/golden-responses-1.0.60.json +164 -0
  167. package/bundle/src/utils/providers/grok/grok-backend-protocol.test.ts +325 -0
  168. package/bundle/src/utils/providers/grok/grok-backend-protocol.ts +721 -0
  169. package/bundle/src/utils/providers/grok/grok-constants.ts +105 -0
  170. package/bundle/src/utils/providers/grok/grok-direct-client.test.ts +179 -0
  171. package/bundle/src/utils/providers/grok/grok-direct-client.ts +313 -0
  172. package/bundle/src/utils/providers/grok/grok-dispatcher.test.ts +1395 -0
  173. package/bundle/src/utils/providers/grok/grok-dispatcher.ts +2105 -0
  174. package/bundle/src/utils/providers/grok/grok-headers.test.ts +149 -0
  175. package/bundle/src/utils/providers/grok/grok-headers.ts +199 -0
  176. package/bundle/src/utils/providers/grok/grok-media-client.test.ts +446 -0
  177. package/bundle/src/utils/providers/grok/grok-media-client.ts +703 -0
  178. package/bundle/src/utils/providers/grok/grok-models.test.ts +96 -0
  179. package/bundle/src/utils/providers/grok/grok-models.ts +161 -0
  180. package/bundle/src/utils/providers/grok/grok-oauth.test.ts +406 -0
  181. package/bundle/src/utils/providers/grok/grok-oauth.ts +771 -0
  182. package/bundle/src/utils/providers/grok/grok-quota.test.ts +142 -0
  183. package/bundle/src/utils/providers/grok/grok-quota.ts +198 -0
  184. package/bundle/src/utils/providers/grok/grok-refresh.test.ts +239 -0
  185. package/bundle/src/utils/providers/grok/grok-refresh.ts +325 -0
  186. package/bundle/src/utils/providers/grok/grok-types.test.ts +252 -0
  187. package/bundle/src/utils/providers/grok/grok-types.ts +374 -0
  188. package/bundle/src/utils/providers/grok/grok-voice-client.test.ts +321 -0
  189. package/bundle/src/utils/providers/grok/grok-voice-client.ts +284 -0
  190. package/bundle/src/utils/providers/grok/index.ts +20 -0
  191. package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +221 -137
  192. package/bundle/src/utils/providers/openai/openai-callback-relay.ts +12 -1
  193. package/bundle/src/utils/providers/openai/openai-constants.ts +2 -0
  194. package/bundle/src/utils/providers/openai/openai-direct-client.ts +111 -21
  195. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +322 -169
  196. package/bundle/src/utils/providers/openai/openai-image-generation.ts +116 -36
  197. package/bundle/src/utils/providers/openai/openai-oauth.ts +48 -20
  198. package/bundle/src/utils/providers/openai/openai-quota.ts +77 -46
  199. package/bundle/src/utils/providers/openai/openai-refresh.ts +42 -18
  200. package/bundle/src/utils/providers/openai/openai-sse.ts +27 -3
  201. package/bundle/src/utils/providers/openai/openai-transport-config.ts +2 -0
  202. package/bundle/src/utils/quiet-hours.ts +12 -1
  203. package/bundle/src/utils/slack-notify.ts +44 -13
  204. package/bundle/src/utils/subset-loaders.ts +7 -7
  205. package/bundle/web-dist/client/assets/clsx-5XM_pHvN.js +1 -0
  206. package/bundle/web-dist/client/assets/index-BA7uQ-6c.js +31 -0
  207. package/bundle/web-dist/client/assets/index-Be2qCZmI.css +1 -0
  208. package/bundle/web-dist/client/assets/logs-C47OJGEI.js +1 -0
  209. package/bundle/web-dist/client/assets/monit-BS9no0dU.js +4 -0
  210. package/bundle/web-dist/client/assets/plus-sdACTfH0.js +1 -0
  211. package/bundle/web-dist/client/assets/refresh-cw-CY8o_1cT.js +1 -0
  212. package/bundle/web-dist/client/assets/request-model-BRtFuZvj.js +1 -0
  213. package/bundle/web-dist/client/assets/routes-kqgkUxE8.js +5 -0
  214. package/bundle/web-dist/client/assets/{services.generated-BsieU37H.js → services.generated-CefiDXEv.js} +5 -5
  215. package/bundle/web-dist/client/assets/settings-DNDvFGSw.js +1 -0
  216. package/bundle/web-dist/client/assets/show-u8Np69q3.js +2 -0
  217. package/bundle/web-dist/client/assets/tokens-QvP410NW.js +1 -0
  218. package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
  219. package/bundle/web-dist/client/assets/use-oauth-login-flow-Bzdh28Ws.js +1 -0
  220. package/bundle/web-dist/client/assets/use-update-token-mutation-CfJKaxmR.js +1 -0
  221. package/bundle/web-dist/client/assets/vendor-react-CUFFrVN9.js +244 -0
  222. package/bundle/web-dist/client/assets/vendor-tanstack-Bf_jag9G.js +1 -0
  223. package/bundle/web-dist/client/index.html +6 -6
  224. package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
  225. package/bundle/web-dist/server/assets/{lazyRouteComponent-Dtd0NR4r.js → lazyRouteComponent-D8iTIHyn.js} +129 -2
  226. package/bundle/web-dist/server/assets/logs-B3OTd9hy.js +825 -0
  227. package/bundle/web-dist/server/assets/{monit-DvzribSE.js → monit-B2hqorPe.js} +385 -126
  228. package/bundle/web-dist/server/assets/plus-DwG7h9kq.js +28 -0
  229. package/bundle/web-dist/server/assets/{react-dom-B4a6-uuR.js → react-dom-BIYQzBqG.js} +2 -129
  230. package/bundle/web-dist/server/assets/refresh-cw-mMBkwOq0.js +44 -0
  231. package/bundle/web-dist/server/assets/{request-model-CbqfnQOJ.js → request-model-I6OdODSH.js} +15 -6
  232. package/bundle/web-dist/server/assets/{routes-BAPWTizT.js → routes-B95YlUv2.js} +760 -213
  233. package/bundle/web-dist/server/assets/{services.generated-CEbGjsI0.js → services.generated-DQATJ6qf.js} +12821 -12194
  234. package/bundle/web-dist/server/assets/settings-C3gbGk0m.js +830 -0
  235. package/bundle/web-dist/server/assets/{show-CxVZTAdv.js → show-Bxaj3rhH.js} +1355 -419
  236. package/bundle/web-dist/server/assets/tokens-CZjH3cB7.js +1038 -0
  237. package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
  238. package/bundle/web-dist/server/assets/use-oauth-login-flow-CKDHgc3U.js +2379 -0
  239. package/bundle/web-dist/server/assets/{use-update-token-mutation-CfYmk_4_.js → use-update-token-mutation-BEbgOzaa.js} +1 -1
  240. package/bundle/web-dist/server/entry-server.generated.js +4303 -22810
  241. package/dist/cli.js +9 -9
  242. package/package.json +4 -11
  243. package/postinstall.mjs +12 -0
  244. package/skills/qgrid/SKILL.md +1 -0
  245. package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
  246. package/skills/qgrid/references/decision-rationale.md +24 -1
  247. package/skills/qgrid/references/grok-runtime.md +89 -0
  248. package/skills/qgrid/references/provider-runtime-differences.md +30 -29
  249. package/skills/qgrid/references/repo-map.md +10 -0
  250. package/skills/qgrid/references/request-log-run-lifecycle.md +1 -1
  251. package/skills/qgrid/references/sonamu-api-web-flow.md +1 -1
  252. package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
  253. package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
  254. package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
  255. package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
  256. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
  257. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
  258. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
  259. package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
  260. package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
  261. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
  262. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
  263. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
  264. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
  265. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
  266. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
  267. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
  268. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
  269. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
  270. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
  271. package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
  272. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
  273. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
  274. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
  275. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
  276. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
  277. package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
  278. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
  279. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
  280. package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
  281. package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
  282. package/bundle/dist/node_modules/.pnpm/vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.4_5b35fc1fb85d2af4d105e0d74f940f50/node_modules/vite/dist/node/module-runner.js +0 -1265
  283. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js +0 -9
  284. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/benchmark.CX_oY03V.js +0 -41
  285. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js +0 -19
  286. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.Chj8NDwU.js +0 -202
  287. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.DdgEv5B1.js +0 -46
  288. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/rpc.MzXet3jl.js +0 -119
  289. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/test.DNmyFkvJ.js +0 -3044
  290. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.js +0 -59
  291. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/index.js +0 -28
  292. package/bundle/dist/testing/setup-mocks.js +0 -16
  293. package/bundle/src/testing/setup-mocks.ts +0 -44
  294. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
  295. package/bundle/web-dist/client/assets/index-CrXKu_J8.js +0 -106
  296. package/bundle/web-dist/client/assets/logs-B2SmWJXA.js +0 -1
  297. package/bundle/web-dist/client/assets/monit-D-JwXXoA.js +0 -1
  298. package/bundle/web-dist/client/assets/plus-B62CuqT8.js +0 -1
  299. package/bundle/web-dist/client/assets/refresh-cw-NNcU0Cmq.js +0 -1
  300. package/bundle/web-dist/client/assets/request-model-CojtinqK.js +0 -1
  301. package/bundle/web-dist/client/assets/routes-C5r4gTvY.js +0 -5
  302. package/bundle/web-dist/client/assets/settings-D3tDSAck.js +0 -1
  303. package/bundle/web-dist/client/assets/show-Cah_kUKC.js +0 -2
  304. package/bundle/web-dist/client/assets/tokens-DU2Iyxxd.js +0 -1
  305. package/bundle/web-dist/client/assets/use-oauth-login-flow-D0UaR9_e.js +0 -1
  306. package/bundle/web-dist/client/assets/use-update-token-mutation-DAq0F8p-.js +0 -1
  307. package/bundle/web-dist/client/assets/vendor-react-DH4kUfK2.js +0 -9
  308. package/bundle/web-dist/client/assets/vendor-tanstack-DJRQAbrY.js +0 -1
  309. package/bundle/web-dist/server/assets/logs-l91avYif.js +0 -509
  310. package/bundle/web-dist/server/assets/plus-KZrECewT.js +0 -19
  311. package/bundle/web-dist/server/assets/refresh-cw-BND93JrF.js +0 -23
  312. package/bundle/web-dist/server/assets/settings-BZR5HSAL.js +0 -461
  313. package/bundle/web-dist/server/assets/tokens-D1hb4eKk.js +0 -448
  314. package/bundle/web-dist/server/assets/use-oauth-login-flow-Cvdy0zF8.js +0 -178
  315. package/dist/cli.d.ts +0 -10
  316. /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
  317. /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
  318. /package/bundle/web-dist/server/assets/{cost-eEHeTRT5.js → cost-BC9yzyA9.js} +0 -0
package/dist/cli.js CHANGED
@@ -39,7 +39,7 @@ function runSelfUpdate(params, dependencies) {
39
39
  try {
40
40
  latest = latestVersion(packageName);
41
41
  } catch (cause) {
42
- warn(`Warning: failed to check for qgrid-cli updates: ${cause.message}`);
42
+ warn(`Warning: failed to check for qgrid-cli updates: ${cause instanceof Error ? cause.message : String(cause)}`);
43
43
  warn(`Continuing with qgrid-cli ${currentVersion}.`);
44
44
  return { kind: "continue" };
45
45
  }
@@ -60,7 +60,8 @@ function runSelfUpdate(params, dependencies) {
60
60
  return { kind: "continue" };
61
61
  }
62
62
  } catch (cause) {
63
- warn(`Warning: failed to update qgrid-cli to ${latest}: ${cause.message}`);
63
+ const message = cause instanceof Error ? cause.message : String(cause);
64
+ warn(`Warning: failed to update qgrid-cli to ${latest}: ${message}`);
64
65
  warn(`Continuing with qgrid-cli ${currentVersion}; fix the global ${packageManager} install.`);
65
66
  return { kind: "continue" };
66
67
  }
@@ -213,13 +214,12 @@ function ensureLatestRuntimeCliDependencies() {
213
214
  installedOutput = commandVersion(dep.command);
214
215
  }
215
216
  } catch (e) {
216
- console.warn(`Warning: failed to update ${dep.label}: ${e.message}`);
217
+ console.warn(`Warning: failed to update ${dep.label}: ${e instanceof Error ? e.message : String(e)}`);
217
218
  }
218
219
  if (!installedOutput) warnMissingRuntimeCliDependency(dep);
219
220
  }
220
221
  }
221
- function normalizePort(port) {
222
- const value = String(port);
222
+ function normalizePort(value) {
223
223
  const numeric = Number(value);
224
224
  if (!/^\d+$/.test(value) || numeric < 1 || numeric > 65535) {
225
225
  console.error(`Invalid port: ${value}`);
@@ -303,10 +303,10 @@ program.name("qgrid").version(pkg.version).description("Qgrid — LLM subscripti
303
303
  await client.connect();
304
304
  await client.end();
305
305
  } catch (e) {
306
- const err = e;
306
+ const message = e instanceof Error ? e.message : String(e);
307
307
  console.error(`Error: Cannot connect to PostgreSQL at ${dbHost}:${dbPort}/${dbName}`);
308
- console.error(`error: ${err.message}`);
309
- if (err.message.includes("timeout expired")) console.error(`cannot connect to the database server. Please check if the database is running and accessible.`);
308
+ console.error(`error: ${message}`);
309
+ if (message.includes("timeout expired")) console.error(`cannot connect to the database server. Please check if the database is running and accessible.`);
310
310
  console.error(`\nProvide DB connection via --db flag or QGRID_DB_* env vars:`);
311
311
  console.error(` qgrid --db postgres://user:password@host:port/dbname`);
312
312
  process.exit(1);
@@ -314,7 +314,7 @@ program.name("qgrid").version(pkg.version).description("Qgrid — LLM subscripti
314
314
  try {
315
315
  await import(serverEntry);
316
316
  } catch (e) {
317
- console.error("Failed to start server:", e.stack ?? e.message);
317
+ console.error("Failed to start server:", e instanceof Error ? e.stack ?? e.message : e);
318
318
  process.exit(1);
319
319
  }
320
320
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cartanova/qgrid-cli",
3
- "version": "2.10.9",
3
+ "version": "2.11.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cartanova-ai/qgrid"
@@ -20,20 +20,15 @@
20
20
  "@ai-sdk/anthropic": "^3.0.0",
21
21
  "@ai-sdk/provider": "^3.0.0",
22
22
  "@ai-sdk/provider-utils": "^4.0.0",
23
- "@anthropic-ai/sdk": "^0.81.0",
24
23
  "@better-auth/core": "~1.6.0",
25
24
  "@better-auth/passkey": "~1.6.0",
26
25
  "@better-auth/sso": "~1.6.0",
27
26
  "@logtape/logtape": "2.0.0",
28
27
  "@logtape/pretty": "2.0.0",
29
- "@logtape/redaction": "2.0.0",
30
- "@oxc-project/runtime": "^0.79.0",
28
+ "@oxc-project/runtime": "^0.79.1",
31
29
  "ai": "^6.0.1",
32
- "bcrypt": "^6.0.0",
33
30
  "better-auth": "~1.6.0",
34
- "chalk": "^4.1.2",
35
31
  "commander": "^13.0.0",
36
- "date-fns": "^4.1.0",
37
32
  "dotenv": "^16",
38
33
  "fastify": "^4",
39
34
  "ioredis": "^5.8.2",
@@ -41,16 +36,14 @@
41
36
  "knex": "^3.2.9",
42
37
  "pg": "^8.16.3",
43
38
  "pngjs": "^7.0.0",
44
- "radashi": "^12.2.0",
45
- "sonamu": "0.10.3",
46
- "typescript": "6.0.3",
39
+ "sonamu": "0.11.16",
40
+ "typescript": "7.1.0-dev.20260831.1",
47
41
  "ws": "8.20.0",
48
42
  "zod": "^4.3.6"
49
43
  },
50
44
  "devDependencies": {
51
45
  "@types/node": "25.0.7",
52
46
  "@types/pg": "^8.20.0",
53
- "@types/ws": "8.18.1",
54
47
  "semver": "^7.7.4",
55
48
  "tsdown": "^0.22.3",
56
49
  "yaml": "^2.8.2"
package/postinstall.mjs CHANGED
@@ -28,6 +28,7 @@ function findProjectRoot(startDir) {
28
28
  }
29
29
 
30
30
  const parent = path.dirname(current);
31
+
31
32
  if (parent === current) return packageJsonRoot ?? path.resolve(startDir);
32
33
  current = parent;
33
34
  }
@@ -35,15 +36,19 @@ function findProjectRoot(startDir) {
35
36
 
36
37
  function defaultProjectRoot() {
37
38
  if (process.env.QGRID_SKILLS_CWD) return findProjectRoot(process.env.QGRID_SKILLS_CWD);
39
+
38
40
  if (process.env.INIT_CWD) return findProjectRoot(process.env.INIT_CWD);
39
41
 
40
42
  const cwd = process.cwd();
43
+
41
44
  if (cwd.includes(`${path.sep}node_modules${path.sep}`)) return null;
45
+
42
46
  return findProjectRoot(cwd);
43
47
  }
44
48
 
45
49
  function isInside(parentDir, childDir) {
46
50
  const relative = path.relative(path.resolve(parentDir), path.resolve(childDir));
51
+
47
52
  return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
48
53
  }
49
54
 
@@ -55,9 +60,11 @@ function defaultTargets() {
55
60
  const codexHome = process.env.CODEX_HOME
56
61
  ? path.resolve(process.env.CODEX_HOME)
57
62
  : path.join(os.homedir(), ".codex");
63
+
58
64
  const claudeHome = process.env.CLAUDE_HOME
59
65
  ? path.resolve(process.env.CLAUDE_HOME)
60
66
  : path.join(os.homedir(), ".claude");
67
+
61
68
  return [
62
69
  { label: "Codex", target: path.join(codexHome, "skills", "qgrid"), useSymlink: false },
63
70
  { label: "Claude Code", target: path.join(claudeHome, "skills", "qgrid"), useSymlink: false },
@@ -65,10 +72,13 @@ function defaultTargets() {
65
72
  }
66
73
 
67
74
  const projectRoot = defaultProjectRoot();
75
+
68
76
  if (!projectRoot) return null;
69
77
  const isInstalledPackage = packageDir.split(path.sep).includes("node_modules");
78
+
70
79
  if (!isInstalledPackage && isInside(projectRoot, sourceSkillsDir)) {
71
80
  console.log("qgrid skill sync skipped: running inside qgrid repository.");
81
+
72
82
  return [];
73
83
  }
74
84
 
@@ -89,6 +99,7 @@ function defaultTargets() {
89
99
  async function syncSkill({ label, target, useSymlink }) {
90
100
  if (!existsSync(path.join(sourceSkillsDir, "SKILL.md"))) {
91
101
  console.log("qgrid skill source not found in qgrid CLI package.");
102
+
92
103
  return;
93
104
  }
94
105
 
@@ -99,6 +110,7 @@ async function syncSkill({ label, target, useSymlink }) {
99
110
  try {
100
111
  await symlink(sourceSkillsDir, target, "dir");
101
112
  console.log(`qgrid skill linked for ${label}: ${target}`);
113
+
102
114
  return;
103
115
  } catch (error) {
104
116
  console.log(
@@ -21,6 +21,7 @@ Before changing code, identify the affected path:
21
21
  - OpenAI direct transport, permits, routing, cache affinity, OAuth, or quota behavior: read `references/openai-codex-runtime.md`.
22
22
  - Adding an OpenAI model, its pricing, or reasoning levels: follow the model-addition checklist in `references/openai-codex-runtime.md`.
23
23
  - Anthropic models or Claude Code spawn/stream-json behavior: read `references/anthropic-claude-code-runtime.md`.
24
+ - Grok fingerprinting, OAuth, quota routing, media, voice, or retry behavior: read `references/grok-runtime.md`.
24
25
  - Token registration, OAuth, token sync, active/inactive behavior, quota thresholds, or weighted token routing: read `references/token-auth-quota-lifecycle.md`.
25
26
  - Provider comparisons, routing, or cross-provider bugs: read `references/provider-runtime-differences.md`.
26
27
  - Tool calling, AI SDK multi-step loops, or tool-call request logs: read `references/tool-calling-and-multiturn.md`.
@@ -66,6 +66,8 @@ When helping a user set up qgrid locally, check for `QGRID_PROJECT_NAME` or conf
66
66
  |---|---:|---|
67
67
  | `QGRID_OPENAI_TRANSPORT` | `websocket` | OpenAI transport selector (`https` or `websocket`). Invalid values fail at dispatcher configuration time. This is the only OpenAI runtime knob; there is no concurrency cap. |
68
68
  | `QGRID_OPENAI_AUTOSCALE` / `QGRID_OPENAI_MIN_WORKERS_PER_TOKEN` / `QGRID_OPENAI_MAX_WORKERS_PER_TOKEN` / `QGRID_OPENAI_PERMITS_PER_TOKEN` | ignored | Removed. OpenAI requests run uncapped like Anthropic (stateless per-request execution); setting these has no effect. |
69
+ | `QGRID_GROK_MAX_INFLIGHT_PER_TOKEN` | unset (uncapped) | Optional positive-integer per-account Grok cap. Accounts at the cap are excluded from selection rather than queued. Invalid values are ignored with a warning (`packages/api/src/utils/providers/grok/grok-dispatcher.ts`). |
70
+ | `QGRID_GROK_LIVE_TOKEN_ID` | unset | Reserved token-row selector for opt-in Grok live tests. Keep it unset in CI and ordinary server runs. The live-test gate is specified in `docs/plans/2026-10-16-grok-provider-integration-plan.md` §7; no current server runtime behavior reads it. |
69
71
  | `QGRID_TOKEN_WINDOW_KEEPALIVE_ENABLED` | off | Marks this instance as the Anthropic 5-hour window keepalive runner (2.8.0, `ea7feb3`). Only the literal `true` enables it; set it on exactly one instance per shared DB so developer instances do not fire duplicates. Two more gates apply: the global setting `qgrid.tokenWindowKeepaliveEnabled` (`false` turns everything off; changing it reschedules immediately) and the per-token `tokens.keepalive_enabled` flag (default `false`, dashboard settings-panel toggle). In 2.7.6 this env was a default-on global switch with no per-token opt-in. |
70
72
  | `MAX_STRUCTURED_OUTPUT_RETRIES` | `1` for structured Anthropic streaming calls | Claude Code structured-output retry count for streaming only, clamped to at least 1 by qgrid. Non-streaming `generate` leaves the variable unset and uses Claude Code's default retry budget. |
71
73
 
@@ -81,7 +83,8 @@ When helping a user set up qgrid locally, check for `QGRID_PROJECT_NAME` or conf
81
83
  1. Ensures PostgreSQL `tokens_changed` triggers.
82
84
  2. Starts `TokenSubscriber` for LISTEN/NOTIFY plus periodic reconcile.
83
85
  3. Starts `OpenAIDispatcher` and `AnthropicDispatcher`.
84
- 4. Logs server URL and provider readiness counts.
86
+ 4. Constructs `GrokRefreshCoordinator`, `GrokMediaClient`, and `GrokVoiceClient`, injects them into `GrokDispatcher`, starts it, then reconciles Grok tokens (`packages/api/src/sonamu.config.ts`).
87
+ 5. Logs server URL and provider readiness counts.
85
88
 
86
89
  On shutdown, it stops provider dispatchers and the token subscriber.
87
90
 
@@ -10,6 +10,7 @@ Do not copy these notes blindly into implementation. Use them to find the releva
10
10
  - Tool calling and request-log lifecycle
11
11
  - OpenAI/Codex runtime
12
12
  - Anthropic/Claude Code runtime
13
+ - Grok (xAI subscription) runtime
13
14
  - Token sync and quota thresholds
14
15
  - Weighted token routing
15
16
  - Request logs, metrics, and dashboard
@@ -133,6 +134,28 @@ Key decisions:
133
134
  - `--setting-sources project` is required for shared-service isolation. User/local Claude settings can load hooks or memory and leak context across requests.
134
135
  - Claude Code OAuth prompt cache sharing across tokens in the same workspace is an observed cost behavior, not a product contract. Monitor it; do not promise it.
135
136
 
137
+ ## Grok (xAI Subscription) Runtime
138
+
139
+ Sources:
140
+
141
+ - `docs/plans/2026-10-16-grok-provider-integration-plan.md`
142
+ - `docs/diagnosis/2026-10-16-grok-live-probe.md`
143
+ - `packages/api/src/utils/providers/grok/*`
144
+ - `packages/api/src/application/qgrid/qgrid.dispatcher.ts`
145
+
146
+ Key decisions:
147
+
148
+ - **D1 — accepted terms risk:** The user accepted the risk of using an xAI subscription token from a non-official client and authorized the bounded live probe. This is recorded acceptance, not a claim that xAI permits every deployment.
149
+ - **D2 — reproduce grok-build:** Qgrid sends the full installed grok-build fingerprint. `GROK_BUILD_VERSION` is a source pin, not an environment override; changing it requires a new installed-binary capture, golden fixture, build id, and fingerprint test.
150
+ - **D3 — subscription OAuth only:** Grok tokens must be `at+jwt` OAuth credentials issued by `auth.x.ai`. Raw xAI API keys are outside qgrid's subscription-pooling purpose.
151
+ - **D4 — URL video delivery:** Return the upstream `api.x.ai` video URL in the AI SDK URL result. Qgrid does not download, proxy, or persist video bytes.
152
+ - **D5 — no new workspace package:** Grok runtime code lives under `packages/api/src/utils/providers/grok/`; SDK adapters stay in `packages/ai-sdk/src/`.
153
+ - **D6 — exclude on-demand billing:** An account with `/settings.on_demand_enabled = true` is ineligible. There is no per-token override because the exclusion closes accidental paid usage.
154
+ - **D7 — shared weighted routing:** Grok uses the common `SmoothWeightedRoundRobin` with `tokens.weight`, after quota, on-demand, cooldown, entitlement, and optional in-flight gates.
155
+ - **D8 — preserve tool emulation:** Grok remains on qgrid's shared strict action-envelope tool contract. The provider can emit native function calls, but qgrid callers continue to receive the same emulated AI SDK multi-step lifecycle as the other routes.
156
+
157
+ Current implementation evidence is in `grok-constants.ts`, `grok-dispatcher.ts`, `grok-oauth.ts`, `grok-media-client.ts`, `packages/api/src/application/qgrid/qgrid.frame.ts`, and `qgrid.dispatcher.ts`. See `references/grok-runtime.md` for operational details and unverified gaps.
158
+
136
159
  ## Token Sync And Quota Thresholds
137
160
 
138
161
  Sources:
@@ -237,7 +260,7 @@ Key decisions:
237
260
  - qgrid performs preflight capability/model gates. Raw `imageGeneration: true` requires an image; `"auto"` allows normal text replies but still rejects attempted image generation without a completed image. Public `generateImage` requires one direct Images output per provider call; AI SDK batches requests for `n` outputs.
238
261
  - Raw returned images are inline base64 content parts. The image SDK maps them to AI SDK `image`/`images` and takes references through standard `prompt: { text, images }`, with JSON data URL size guarding and HTTPS reference URL support. The language SDK forwards user-message images to `openai/` models as image input (image→text) and drops other image parts with an AI SDK `unsupported` warning.
239
262
  - Raw/server `imageGenerationOptions` supports quality, size, and background. The public image SDK uses flat `QgridImageProviderOptions` and standard top-level `size`. The subscription backend can ignore size and quality hints. Put desired ratios in the prompt, report observed output settings, and never silently resize. Reported image usage is priced at public token rates; without it, use the requested quality/size table with a default-size price for auto/custom hints. Preserve observed settings separately from pricing assumptions. No background-removal fallback is allowed.
240
- - qgrid does not manage generated or reference images as durable assets through a `generated_images` table or object-storage layer. Current request logs can still contain inline image data URLs for inspection and synthetic `image_generation` tool-call steps; reference input images live in the first synthetic step's `tool_args.inputImages`.
263
+ - qgrid does not manage generated or reference images as durable assets through a `generated_images` table or object-storage layer. Current request logs can still contain inline image data URLs for inspection and synthetic `image_generation` tool-call steps; current-turn input images (image→text and image references) live in `request_logs.input_images`; older image-generation logs keep them only in the first synthetic step's `tool_args.inputImages`.
241
264
  - Image cost is stored separately in `request_logs.image_cost_usd`; `request_logs.cost_usd` remains the Codex driver model token cost. Image costs use reported image usage at public token rates, or per-image quality/size estimates when usage is absent. Auto/custom sizes fall back to the 1536x1024 price; omitted quality uses medium. Rows and totals display combined costs as dollar amounts without Cost labels, without Known/Estimated labels or pricing disclaimers. Existing stored null costs are not backfilled; `totalCost.unknownImageCostCount` remains for API compatibility.
242
265
  - Inspect current plans, tests, and implementation before changing behavior; the Codex tool surface can change underneath qgrid.
243
266
 
@@ -0,0 +1,89 @@
1
+ # Grok Direct Runtime
2
+
3
+ Use this reference before changing Grok chat transport, fingerprinting, OAuth, quota routing, media, voice, cost accounting, or retry behavior.
4
+
5
+ ## Source files
6
+
7
+ - Fingerprint constants and headers: `packages/api/src/utils/providers/grok/grok-constants.ts`, `grok-headers.ts`.
8
+ - Chat protocol, transport, models, and dispatch: `grok-backend-protocol.ts`, `grok-direct-client.ts`, `grok-models.ts`, `grok-dispatcher.ts`.
9
+ - OAuth, refresh, billing, and settings: `grok-oauth.ts`, `grok-refresh.ts`, `grok-quota.ts`.
10
+ - Image/video and voice clients: `grok-media-client.ts`, `grok-voice-client.ts`.
11
+ - API limits and endpoints: `packages/api/src/application/qgrid/qgrid.types.ts`, `qgrid.frame.ts`.
12
+ - Probe evidence and design decisions: `docs/diagnosis/2026-10-16-grok-live-probe.md`, `docs/plans/2026-10-16-grok-provider-integration-plan.md`.
13
+
14
+ ## Hosts and fingerprint
15
+
16
+ Grok uses the same xAI subscription OAuth bearer on two hosts, but the header families are not interchangeable (`grok-constants.ts`, `grok-headers.ts`):
17
+
18
+ | Host | Operations | Identity headers |
19
+ | --- | --- | --- |
20
+ | `https://cli-chat-proxy.grok.com/v1` | `/responses`, `/settings`, `/models`, `/billing`, `/user` | `grok-shell/1.0.60 (<os>; <arch>)`, client version and identifier, client mode, and the proxy auth headers. `/responses` also sends the captured `x-grok-*` conversation headers, trace context, loop guards, and zstd encoding. |
21
+ | `https://api.x.ai/v1` | image generation/editing, video start/status, STT, TTS | Media uses `xai-grok-build/1.0.60`; voice uses the shell user agent. Both send the client version and identifier, but never the proxy auth trio. |
22
+
23
+ D2 requires the installed grok-build fingerprint. `GROK_BUILD_VERSION` is pinned to `1.0.60` and `GROK_BUILD_COMMIT` to build `01a8e1c591c0`; the golden request came from the installed binary, not the older public source (`grok-constants.ts`, `grok-headers.test.ts`, `docs/diagnosis/2026-10-16-grok-live-probe.md`).
24
+
25
+ Handle the pin like OpenAI's `CODEX_CLI_VERSION`: keep it as a source constant with no runtime override. To bump it:
26
+
27
+ 1. Edit `GROK_BUILD_VERSION` in `grok-constants.ts`.
28
+ 2. Run the newly installed grok-build binary through an intercepting proxy and re-capture the redacted golden request fixture.
29
+ 3. Update `GROK_BUILD_COMMIT` with that binary's build id.
30
+ 4. Run `grok-headers.test.ts` and the golden fingerprint test before release.
31
+
32
+ The proxy treats the client version as a floor. The 2026-10-16 probe saw `/settings.min_client_version = 1.0.13`; a lower client received HTTP 426. The dispatcher trips a chat-only fast gate for 10 minutes and reports the bump routine (`docs/diagnosis/2026-10-16-grok-live-probe.md`, `grok-dispatcher.ts`).
33
+
34
+ ## OAuth, credentials, and refresh
35
+
36
+ Grok login uses OIDC discovery under `https://auth.x.ai`, public client id `b1a00492-073a-47ea-816f-4c329264a828`, S256 PKCE, `referrer=grok-build`, and these frozen scopes: `openid profile email offline_access grok-cli:access api:access conversations:read conversations:write workspaces:read workspaces:write` (`grok-constants.ts`, `grok-oauth.ts`).
37
+
38
+ Browser login uses a random `127.0.0.1` callback and accepts either the full callback URL or a pasted bare code. Qgrid exposes this as code-paste completion because it does not serve the random callback. Device login uses `/oauth2/device/code`, polls `/oauth2/token` at the returned interval, and adds five seconds after `slow_down` (`grok-oauth.ts`, `packages/api/src/application/qgrid/qgrid.frame.ts`).
39
+
40
+ Stored credentials contain OAuth access/refresh tokens, RFC 3339 expiry, issuer, client id, scopes, `userId`, stable session/agent ids, and an optional tier. Registration accepts only an `at+jwt` issued by `auth.x.ai`; the post-login `/user` lookup resolves the account (`grok-types.ts`, `grok-oauth.ts`). `userId` is the token identity key, so signing in again replaces the prior row for the same account while preserving token settings (`packages/api/src/application/token/token.model.ts`).
41
+
42
+ Refresh starts 300 seconds plus stable 0–60 second per-account jitter before expiry, coalesces concurrent refreshes, persists before publishing credentials, and retains the old refresh token when xAI does not rotate it. Only `invalid_grant` and `invalid_client` require a new login; network errors, 429, 5xx, and unknown OAuth errors remain transient. An upstream 401 permits one forced refresh and one same-token retry (`grok-refresh.ts`, `grok-dispatcher.ts`).
43
+
44
+ ## Quota, billing, and token selection
45
+
46
+ `/billing?format=credits` is camelCase: qgrid reads `config.creditUsagePercent`, `config.currentPeriod`, and `config.prepaidBalance.val`. The observed period was seven days anchored at subscription start. Results are cached for 60 seconds; lookup failure fails open (`grok-quota.ts`, `grok-dispatcher.ts`, `docs/diagnosis/2026-10-16-grok-live-probe.md`).
47
+
48
+ D6 excludes accounts when `/settings.on_demand_enabled` is `true`; `null`, `false`, or absence allows routing. Billing does not carry this field. D7 selects eligible accounts through the shared `SmoothWeightedRoundRobin`, using `tokens.weight`; a valid cache-affinity token remains preferred. `QGRID_GROK_MAX_INFLIGHT_PER_TOKEN` optionally excludes accounts at the cap, while omission leaves Grok uncapped (`grok-quota.ts`, `grok-dispatcher.ts`, `packages/api/src/utils/providers/common/smooth-weighted-round-robin.ts`).
49
+
50
+ ## Failure and failover rules
51
+
52
+ The dispatcher implements the plan §5.4 state machine (`grok-backend-protocol.ts`, `grok-direct-client.ts`, `grok-dispatcher.ts`, `grok-media-client.ts`):
53
+
54
+ | Condition | State and retry behavior |
55
+ | --- | --- |
56
+ | 429 with `Retry-After` | Set a request-class cooldown, capped at 120 seconds; fail over within the hop budget. If every candidate is cooling down, wait once for at most 30 seconds, then return a rate-limit error. |
57
+ | 429 exhaustion | Block the request class until the billing period ends, or one hour when the end is unavailable; invalidate billing and fail over. |
58
+ | 403 | Chat fails permanently without refresh or failover. Public API sets a one-hour entitlement block for that request class and may fail over once. |
59
+ | HTTP 426 | Trip the chat-only version gate. Media and voice remain available. |
60
+ | 401 | Refresh once and retry the same account; a second 401 marks it for re-authentication and may fail over. |
61
+ | `x-should-retry: false` | Return the error without retry or failover. |
62
+ | Chat 5xx/connect/idle failure | Fail over only before any event was forwarded and before upstream execution was observed. |
63
+ | Media/voice transport failure | Fail over only for a classified pre-send connection failure. Never replay a sent POST or a timeout that may have executed upstream. |
64
+
65
+ ## Chat, tools, usage, and cost
66
+
67
+ Chat sends complete Responses-format history over HTTPS/SSE. It preserves image data/HTTPS inputs, strict structured output, prompt-cache affinity, reasoning effort, and the fixed include/store fields captured from grok-build. A stream succeeds only after `response.completed` (`grok-backend-protocol.ts`, `grok-direct-client.ts`, `grok-dispatcher.ts`, `docs/diagnosis/2026-10-16-grok-live-probe.md`).
68
+
69
+ D8 keeps qgrid's shared structured-output tool emulation: caller tools become the strict action envelope, the AI SDK executes returned tool calls, and a follow-up turn replays results. Do not replace this with Grok-native function execution without reopening the cross-provider contract (`packages/api/src/application/qgrid/qgrid.dispatcher.ts`, `tool-emulation.ts`, `tool-emulation-schema.ts`).
70
+
71
+ Provider `cost_in_usd_ticks` is authoritative, including zero; one tick is `1e-10` USD. If ticks are absent, qgrid uses catalog-seeded language/image prices and marks `costSource: "pricing_table"`; reported ticks use `costSource: "provider"` (`grok-dispatcher.ts`, `packages/api/src/utils/providers/common/model-cost.ts`, `docs/diagnosis/2026-10-16-grok-live-probe.md`).
72
+
73
+ ## Media and voice
74
+
75
+ Qgrid exposes image generation/editing, asynchronous video start/status, transcription, and speech through `api.x.ai`. Reference images select `/images/edits`; video uses `/videos/generations` and `/videos/{request_id}`; voice uses multipart `/stt` and JSON `/tts` (`grok-media-client.ts`, `grok-voice-client.ts`, `packages/api/src/application/qgrid/qgrid.frame.ts`).
76
+
77
+ Inline audio, each inline image, and the aggregate inline images in one request are capped at 7 MiB decoded. The server maps Fastify's oversized-body error to HTTP 413 (`packages/api/src/application/qgrid/qgrid.types.ts`, `qgrid.frame.ts`).
78
+
79
+ Video starts return a random 128-bit in-memory job handle. Handles expire after 24 hours, polling stays pinned to the starting token, and `projectName` must match the owner supplied at start. D4 returns the upstream `api.x.ai` video URL unchanged; qgrid does not fetch, proxy, or store the bytes (`qgrid.frame.ts`, `grok-media-client.ts`, `packages/ai-sdk/README.md`).
80
+
81
+ **ZDR and video.** xAI refuses `POST /v1/videos/generations` for Zero Data Retention accounts with HTTP 400 `invalid_request`: "Zero Data Retention teams must provide output.upload_url for video generation." The dispatcher therefore keeps a per-token `zdr` state and excludes `zdr === true` tokens from video only; chat, image, STT, and TTS still route. The primary signal is `codingDataRetentionOptOut` on `GET /user?include=subscription`, re-read on the 60 s prefetch with settings; `x-zero-data-retention: true` on a chat-proxy response confirms it, but its absence never clears it. Unknown state, or a failed `/user` read with no prior value, routes (fail open). If a video start still gets the ZDR 400, the token is marked ZDR, video is entitlement-blocked for an hour, and the start fails over under the media rules. With no eligible video token the caller gets `GrokZdrVideoUnavailableError` (HTTP 503) naming the tokens; usage exposes `zdrVideoExcluded`. Both signals were inferred from one account (plan §11). grok-build's remedy, a user-owned S3 presigned `output.upload_url`, is not implemented (`grok-dispatcher.ts`, `grok-quota.ts`).
82
+
83
+ ## Known gaps and residual risks
84
+
85
+ - **Verified 2026-10-16:** video generation succeeded through the SDK once the account's data-retention opt-out was off (8 s H.264 mp4 on vidgen.x.ai, $0.64; plan section 11). ZDR accounts are refused upstream and are excluded from the video class (see ZDR and video).
86
+ - Node/undici adds headers such as `accept-language` and `sec-fetch-mode` that the captured reqwest client did not send. Transport fingerprinting remains residual risk 10; D1/D2 do not authorize anti-detection work (`docs/plans/2026-10-16-grok-provider-integration-plan.md`, risk 10).
87
+ - **Unverified:** The capture pins chat header order. Media header order has not been verified through an installed-binary capture (`grok-headers.ts`, `docs/diagnosis/2026-10-16-grok-live-probe.md`).
88
+ - **Observed 2026-10-16, not represented in the catalog fixture:** `grok-composer` ids silently remapped to `grok-4.5-build`. Treat the returned serving model as authoritative; the captured catalog itself lists only the four documented model ids (`docs/diagnosis/2026-10-16-grok-live-probe.md`, `grok-models.ts`).
89
+ - `QGRID_GROK_LIVE_TOKEN_ID` is reserved by the plan for opt-in live tests and must stay unset in ordinary/CI runs; no current server runtime behavior depends on it (`docs/plans/2026-10-16-grok-provider-integration-plan.md`, §7).
@@ -1,31 +1,31 @@
1
1
  # Provider Runtime Differences
2
2
 
3
- Use this reference when comparing OpenAI and Anthropic behavior, debugging provider-specific bugs, or reviewing cross-provider changes.
4
-
5
- | Topic | OpenAI via Codex | Anthropic via Claude Code |
6
- |---|---|---|
7
- | Process lifetime | No child process; direct HTTPS/SSE request | Fresh `claude` process per request |
8
- | Worker pool | None; in-memory token pool only | None; in-memory token pool only |
9
- | Worker id | Legacy coordinate field carries token id | `tokenId` |
10
- | Epoch | Legacy compatibility value; not a process generation | Always `0` |
11
- | Request concurrency | Uncapped; stateless HTTPS/WS request per call | Uncapped; fresh process per request |
12
- | Token selection | Smooth weighted RR over quota-eligible tokens; valid affinity may prefer its token | Smooth weighted RR over quota-eligible tokens per request |
13
- | Model routing | `openai/*`; qgrid strips provider prefix before provider call | `anthropic/*`; provider canonicalizes model and strips prefix/`[1m]` |
14
- | Prefix-less models | Fallback not implemented | Fallback not implemented |
15
- | Effort vocabulary | Codex catalog levels `low`..`ultra` (Astra, GPT-6 Sol, GPT-5.6 Sol/Terra through `ultra`; GPT-6/5.6 Luna through `max`); public-API `none`/`minimal` absent | Claude Code `--effort` levels `low`..`max`; per-model caps handled by Claude Code |
16
- | Unsupported effort | Server drops it silently before the request (`resolveOpenAIEffort`), backend default applies | Server drops it silently (`resolveAnthropicEffort`), qgrid default `low` applies |
17
- | Thread/session | No provider thread retained | Fresh Claude `--session-id` per request |
18
- | `sessionKey` | AI SDK derives and replays opaque `prompt_cache_key` affinity | AI SDK intentionally disables storage/replay |
19
- | Multi-turn | Full Responses-format history is sent on every request | Fresh spawn receives flattened full history through stream-json |
20
- | Cache key | Opaque model-scoped affinity key plus stable serialized prefix | Anthropic prefix cache via Claude Code; fresh spawn still can cache stable prefixes |
21
- | Built-in tools | Direct Responses request includes only requested qgrid tools/options | Claude tools disabled via `--tools ""` on every call |
22
- | AI SDK tools | Emulated via qgrid structured output schema, then mapped to AI SDK `tool-call` content | Emulated via envelope contract rendered as prompt text (SON-532); reply parsed by `parseEnvelope`; not native Claude Code tools |
23
- | Structured output | Strict JSON schema is sent in the direct Responses request; schema changes can affect prefix cache | Schema delivered as prompt text appended to the system prompt (no `--json-schema`, no strictify); server strips fences; validation is the consumer's |
24
- | Usage accounting | Responses usage reports input including cached input | Native Anthropic categories are mutually exclusive; qgrid sums them into total input |
25
- | Cost source | qgrid model price fallback | Prefer Claude Code `total_cost_usd`, else qgrid price fallback |
26
- | Settings isolation | Per-token credentials in memory | Shared project cwd plus per-token `CLAUDE_CONFIG_DIR` |
27
- | Streaming close | `AbortSignal` cancels queue wait, retry delay, or `fetch` | Abort kills the fresh child process |
28
- | Image generation | Implemented as an opt-in direct Responses `image_generation` tool path; non-stream only | Explicitly unsupported |
3
+ Use this reference when comparing OpenAI, Anthropic, and Grok behavior, debugging provider-specific bugs, or reviewing cross-provider changes. Sources: `packages/api/src/utils/providers/{openai,anthropic,grok}/*`, `packages/api/src/application/qgrid/qgrid.dispatcher.ts`, and `references/grok-runtime.md`.
4
+
5
+ | Topic | OpenAI via Codex | Anthropic via Claude Code | Grok via grok-build fingerprint |
6
+ |---|---|---|---|
7
+ | Process lifetime | No child process; direct HTTPS/SSE or WebSocket request | Fresh `claude` process per request | No child process; direct HTTPS/SSE request |
8
+ | Worker pool | None; in-memory token pool only | None; in-memory token pool only | None; in-memory token/account pool only |
9
+ | Worker id | Legacy coordinate field carries token id | `tokenId` | Legacy coordinate field carries token id |
10
+ | Epoch | Legacy compatibility value; not a process generation | Always `0` | `-1`; not a process generation |
11
+ | Request concurrency | Uncapped; stateless request per call | Uncapped; fresh process per request | Uncapped by default; optional `QGRID_GROK_MAX_INFLIGHT_PER_TOKEN` excludes accounts at the cap |
12
+ | Token selection | Smooth weighted RR over quota-eligible tokens; valid affinity may prefer its token | Smooth weighted RR over quota-eligible tokens per request | Smooth weighted RR after quota, on-demand, cooldown, entitlement, and capacity gates; valid affinity may prefer its token |
13
+ | Model routing | `openai/*`; qgrid strips provider prefix before provider call | `anthropic/*`; provider canonicalizes model and strips prefix/`[1m]` | `grok/*`; qgrid strips the provider prefix and validates against the seeded/live catalog |
14
+ | Prefix-less models | Fallback not implemented | Fallback not implemented | Fallback not implemented |
15
+ | Effort vocabulary | Codex catalog levels `low`..`ultra` | Claude Code `--effort` levels `low`..`max` | Catalog levels `low`, `medium`, `high`, `xhigh`; thinking-off is unverified and rejected |
16
+ | Unsupported effort | Server drops it before the request; backend default applies | Server drops it; qgrid default `low` applies | Server drops it; catalog default applies |
17
+ | Thread/session | No provider thread retained | Fresh Claude `--session-id` per request | No provider thread retained; stable account session/agent ids are fingerprint headers |
18
+ | `sessionKey` | AI SDK derives and replays opaque `prompt_cache_key` affinity | AI SDK intentionally disables storage/replay | AI SDK derives and replays account-affine `prompt_cache_key` coordinates |
19
+ | Multi-turn | Full Responses-format history is sent on every request | Fresh spawn receives flattened full history through stream-json | Full Responses-format history is sent on every request |
20
+ | Cache key | Opaque model-scoped affinity key plus stable serialized prefix | Anthropic prefix cache via Claude Code | Opaque model-scoped affinity key, also used to derive Grok conversation ids |
21
+ | Built-in tools | Direct request includes only requested qgrid tools/options | Claude tools disabled via `--tools ""` | Captured proxy supports `web_search`/`x_search`, but qgrid's public tool path remains the shared emulation contract |
22
+ | AI SDK tools | Emulated via qgrid structured output schema | Emulated via prompt envelope; not native Claude Code tools | Emulated via the strict qgrid action envelope (D8), not provider-executed function tools |
23
+ | Structured output | Strict JSON schema is sent in the direct Responses request | Schema is prompt text; consumer validation owns correctness | Strict JSON schema is sent in the direct Responses request |
24
+ | Usage accounting | Input includes cached input | Native categories are summed into total input | Responses reports cached/reasoning/context tokens and `cost_in_usd_ticks` |
25
+ | Cost source | qgrid model price fallback | Prefer Claude Code `total_cost_usd`, else qgrid fallback | Provider ticks are authoritative; catalog-seeded fallback when ticks are absent |
26
+ | Settings isolation | Per-token credentials in memory | Shared project cwd plus per-token `CLAUDE_CONFIG_DIR` | Per-token OAuth credentials and stable ids in memory |
27
+ | Streaming close | `AbortSignal` cancels selection or active transport | Abort kills the fresh child process | `AbortSignal` cancels selection or active SSE; success requires `response.completed` |
28
+ | Media/voice | OpenAI image routes only | Explicitly unsupported | Image generation/editing, async video URL jobs, STT, and TTS on `api.x.ai` |
29
29
 
30
30
  ## Routing contract
31
31
 
@@ -33,13 +33,14 @@ Provider routing happens in `packages/api/src/application/qgrid/qgrid.dispatcher
33
33
 
34
34
  - `openai/<model>` routes to `OpenAIDispatcher`.
35
35
  - `anthropic/<model>` routes to `AnthropicDispatcher`.
36
+ - `grok/<model>` routes to `GrokDispatcher`.
36
37
  - models without provider prefix produce "Direct LLM API fallback not implemented".
37
38
 
38
39
  Do not silently route prefix-less Claude model names such as `claude-sonnet-4-6` to Anthropic. Tests intentionally guard against this.
39
40
 
40
41
  ## Shared contracts
41
42
 
42
- Both providers return `GenerateResult` with:
43
+ All three providers return `GenerateResult` with:
43
44
 
44
45
  - `text`
45
46
  - `tokenName`
@@ -52,6 +53,6 @@ Both providers return `GenerateResult` with:
52
53
 
53
54
  `qgrid.dispatcher.ts` maps this into `QueryOutput`, applies tool-call emulation, calculates fallback cost, and keeps the legacy `QgridThreadCoord` response shape for opaque OpenAI cache affinity.
54
55
 
55
- Both providers receive strictified output schemas from `buildStrictOutputSchema`.
56
+ OpenAI and Grok receive strictified output schemas from `buildStrictOutputSchema`; Anthropic receives the original schema as prompt text.
56
57
 
57
- Tool calling uses this shared strict-schema path. It is not native provider tool calling on either route.
58
+ Tool calling uses qgrid's shared action-envelope path. It is not native provider tool execution on any public route (`packages/api/src/application/qgrid/qgrid.dispatcher.ts`, `tool-emulation.ts`).
@@ -25,6 +25,7 @@ Use this map to orient qgrid work quickly.
25
25
  - Token trigger setup: `packages/api/src/application/qgrid/token-trigger-setup.ts`.
26
26
  - OpenAI direct backend transport, OAuth, quota, and dispatcher: `packages/api/src/utils/providers/openai/*`.
27
27
  - Anthropic Claude Code runtime: `packages/api/src/utils/providers/anthropic/*`.
28
+ - Grok chat fingerprint/transport, OAuth/refresh, quota/models, dispatcher, media, and voice: `packages/api/src/utils/providers/grok/{grok-constants.ts,grok-headers.ts,grok-backend-protocol.ts,grok-direct-client.ts,grok-oauth.ts,grok-refresh.ts,grok-quota.ts,grok-models.ts,grok-dispatcher.ts,grok-media-client.ts,grok-voice-client.ts,grok-types.ts}`. See `packages/cli/skills/qgrid/references/grok-runtime.md`.
28
29
  - Cost/usage accounting: `packages/api/src/utils/providers/common/model-cost.ts`.
29
30
  - Weighted token selection: `packages/api/src/utils/providers/common/smooth-weighted-round-robin.ts`.
30
31
  - Boot order and startup migrations: `packages/api/src/server-bootstrap.ts`, `packages/api/src/startup-migrations.ts`.
@@ -38,3 +39,12 @@ Use this map to orient qgrid work quickly.
38
39
  - Generated API files: `packages/api/src/application/sonamu.generated*`, `packages/web/src/services` when present, generated route/client files.
39
40
  - Dashboard components: `packages/web/src/components/qgrid/*`.
40
41
  - Dashboard routes: `packages/web/src/routes/*`.
42
+
43
+ ## Grok SDK and API surfaces
44
+
45
+ - Public AI SDK language/options integration: `packages/ai-sdk/src/index.ts`, `index.types.ts`, `grok-options.ts`.
46
+ - Grok image/video/transcription/speech adapters: `packages/ai-sdk/src/image-model.ts`, `video-model.ts`, `transcription-model.ts`, `speech-model.ts`.
47
+ - Grok OAuth, media, voice, limits, and video job handles: `packages/api/src/application/qgrid/qgrid.frame.ts`, `qgrid.types.ts`.
48
+ - Grok dispatcher construction and lifecycle: `packages/api/src/sonamu.config.ts`.
49
+
50
+ These paths are documented by `packages/ai-sdk/README.md` and `packages/cli/skills/qgrid/references/grok-runtime.md`.
@@ -98,7 +98,7 @@ For `imageGeneration: "auto"`, set `is_image_generation` only when returned cont
98
98
 
99
99
  If the auto image stage fails or is cancelled after the chat driver has completed, preserve the completed driver result as internal failure metadata. The frame converts it with the same usage/pricing mapper used on success; terminal logging writes one generate step before aggregating the run and retains the actual/requested model and token. The parent remains `error` or `aborted` with the original error message. Do not write a completed image step, invent an image cost, expose failure metadata in the HTTP error, or record this step again on success. A driver that never completed and a direct image-only call have no completed chat usage to retain. `logger: false` still creates no logs. Log-writing failures must not replace the original generation failure.
100
100
 
101
- Reference images for image generation are not stored in `request_logs.user_prompt`; that field remains the text prompt. For inspection in the detail view, qgrid stores reference image metadata/base64 in the synthetic `image_generation` step's `tool_args.inputImages`. If Codex returns multiple image outputs, store `inputImages` only on the first synthetic image tool step so multi-output logs do not duplicate the same input payload on every output.
101
+ Input images are not stored in `request_logs.user_prompt`; that field remains the text prompt. `beforeQuery` stores the current turn's `args.input` images on the run as `request_logs.input_images` (`{ mediaType, data, byteSize }` or `{ url }`), for text and image runs alike. Earlier-turn images in `history` stay in `request_logs.history`. For inspection in the detail view, qgrid stores reference image metadata/base64 in the synthetic `image_generation` step's `tool_args.inputImages`. If Codex returns multiple image outputs, store `inputImages` only on the first synthetic image tool step so multi-output logs do not duplicate the same input payload on every output.
102
102
 
103
103
  ## Structured output fields
104
104
 
@@ -78,7 +78,7 @@ Chat model presets: the model `<select>` lists the served subset of `QgridSuppor
78
78
 
79
79
  The monit tab's vitals strip shows per-provider in-flight counts, an in-flight sparkline, token chips with quota gauges (fed by the dispatcher's 60-second rate-limits cache; `resetsAt` arrives as ms epoch), and a 1-hour per-provider request/error/cache-hit stats line polled separately every 30 seconds.
80
80
 
81
- Reference input images for image generation render in the detail view under the user prompt from the first synthetic `image_generation` step's `tool_args.inputImages`. Keep the prompt itself text-only, redact large base64 in request JSON views, and avoid rendering duplicate input previews for multi-output image turns.
81
+ Current-turn input images render in the detail view under the user prompt from `request_logs.input_images` (subset `A` only, not the list subset). Logs created before that column fall back to the first synthetic `image_generation` step's `tool_args.inputImages`. Keep the prompt itself text-only, redact large base64 in request JSON views, and avoid rendering duplicate input previews for multi-output image turns.
82
82
 
83
83
  ## Verification
84
84
 
@@ -9,6 +9,7 @@ Use this reference before changing token storage, OAuth flows, token activation,
9
9
  - Token APIs
10
10
  - Anthropic OAuth flow
11
11
  - OpenAI OAuth and refresh flow
12
+ - Grok OAuth, refresh, and quota flow
12
13
  - Token sync and reconcile
13
14
  - Provider runtime consequences
14
15
  - Quota threshold semantics
@@ -24,7 +25,8 @@ Use this reference before changing token storage, OAuth flows, token activation,
24
25
  - Token subscriber: `packages/api/src/application/qgrid/token-subscriber.ts`.
25
26
  - OpenAI direct OAuth/refresh/quota: `packages/api/src/utils/providers/openai/openai-oauth.ts`, `openai-refresh.ts`, `openai-quota.ts`.
26
27
  - Anthropic quota: `packages/api/src/utils/providers/anthropic/anthropic-quota.ts`.
27
- - Provider token event handlers: `openai-dispatcher.ts`, `anthropic-dispatcher.ts`.
28
+ - Grok OAuth/refresh/quota: `packages/api/src/utils/providers/grok/grok-oauth.ts`, `grok-refresh.ts`, `grok-quota.ts`.
29
+ - Provider token event handlers: `openai-dispatcher.ts`, `anthropic-dispatcher.ts`, `grok-dispatcher.ts`.
28
30
 
29
31
  ## Token Table Contract
30
32
 
@@ -71,10 +73,29 @@ Anthropic credentials:
71
73
  }
72
74
  ```
73
75
 
74
- Duplicate account replacement is account-identifier based:
76
+ Grok credentials (`packages/api/src/utils/providers/grok/grok-types.ts`):
77
+
78
+ ```ts
79
+ {
80
+ authMode: "oauth";
81
+ accessToken: string;
82
+ refreshToken: string;
83
+ expiresAt: string;
84
+ issuer: "https://auth.x.ai";
85
+ clientId: string;
86
+ scopes: string[];
87
+ userId: string;
88
+ sessionId: string;
89
+ agentId: string;
90
+ subscriptionTier?: string;
91
+ }
92
+ ```
93
+
94
+ Duplicate account replacement is account-identifier based (`packages/api/src/application/token/token.model.ts`):
75
95
 
76
96
  - OpenAI: `credentials.accountId`.
77
97
  - Anthropic: `credentials.accountUuid`.
98
+ - Grok: `credentials.userId`.
78
99
 
79
100
  ## Token APIs
80
101
 
@@ -152,6 +173,26 @@ Usage/quota:
152
173
  - Threshold uses primary `usedPercent`.
153
174
  - Usage lookup failure is fail-open for routing.
154
175
 
176
+ ## Grok OAuth, Refresh, And Quota Flow
177
+
178
+ Grok supports two OAuth entry paths (`grok-oauth.ts`, `packages/api/src/application/qgrid/qgrid.frame.ts`):
179
+
180
+ 1. Browser PKCE uses xAI OIDC discovery, a random `127.0.0.1` callback, the grok-build client id/scopes/referrer, and code-paste completion from either a full callback URL or bare code.
181
+ 2. Device code starts at `auth.x.ai/oauth2/device/code` and polls the token endpoint at the returned interval; `slow_down` adds five seconds.
182
+
183
+ The resulting access token must be an `at+jwt` issued by `auth.x.ai`. Qgrid confirms identity through `/user?include=subscription` and stores `userId` as the account identity key (`grok-oauth.ts`, `grok-types.ts`, `token.model.ts`).
184
+
185
+ Refresh starts 300 seconds plus stable 0–60 second jitter before expiry, is single-flight per token, keeps the previous refresh token when xAI does not rotate it, and persists rotated credentials before exposing them. `invalid_grant` and `invalid_client` require re-login; other failures remain transient. A generation 401 permits one forced refresh and same-token retry (`grok-refresh.ts`, `grok-dispatcher.ts`).
186
+
187
+ Quota and spending controls use two proxy reads (`grok-quota.ts`, `grok-dispatcher.ts`):
188
+
189
+ | Read | Routing fields | Cache/failure policy |
190
+ |---|---|---|
191
+ | `/billing?format=credits` | camelCase `config.creditUsagePercent`, weekly `currentPeriod`, prepaid balance | 60-second cache; lookup failure fails open |
192
+ | `/settings` | `on_demand_enabled`, minimum client version, feature/tier flags | 60-second cache; `true` excludes the account under D6; lookup failure fails open |
193
+
194
+ The observed weekly billing window begins at subscription start, not a calendar boundary (`docs/diagnosis/2026-10-16-grok-live-probe.md`). Quota exhaustion blocks only the affected request class until period end (one-hour fallback); a fresh below-threshold billing read clears blocks (`grok-dispatcher.ts`).
195
+
155
196
  ## Token Sync And Reconcile
156
197
 
157
198
  On server start, qgrid creates PostgreSQL triggers for `tokens_changed`.
@@ -176,7 +217,8 @@ On DELETE or missing row:
176
217
 
177
218
  - remove from `QgridDispatcher.tokens`;
178
219
  - call OpenAI `onTokenRemoved`;
179
- - call Anthropic `onTokenRemoved`.
220
+ - call Anthropic `onTokenRemoved`;
221
+ - call Grok `onTokenRemoved`.
180
222
 
181
223
  OpenAI row changes:
182
224
 
@@ -192,6 +234,12 @@ Anthropic row changes:
192
234
  - inactive row: remove from pool.
193
235
  - reconcile uses active Anthropic rows to replace the in-memory pool.
194
236
 
237
+ Grok row changes (`packages/api/src/application/qgrid/token-subscriber.ts`, `grok-dispatcher.ts`):
238
+
239
+ - active INSERT/UPDATE: validate credentials and upsert account metadata plus selector weight.
240
+ - inactive or deleted row: remove it from the in-memory pool and weighted selector.
241
+ - reconcile uses active Grok rows to replace the in-memory pool.
242
+
195
243
  ## Provider Runtime Consequences
196
244
 
197
245
  OpenAI token changes create, update, deactivate, or remove in-memory credential metadata.
@@ -202,6 +250,8 @@ OpenAI token changes create, update, deactivate, or remove in-memory credential
202
250
 
203
251
  Anthropic token changes only affect the in-memory token pool because every request fresh-spawns Claude Code.
204
252
 
253
+ Grok token changes update the in-memory OAuth credentials, quota/settings cache generation, and weighted selector. Grok has no child process; media and chat reserve the selected account for the request (`grok-dispatcher.ts`).
254
+
205
255
  ## Auth-Dead Detection And Token Registration
206
256
 
207
257
  When a refresh fails in a way that only re-login can fix, qgrid removes the token from routing instead of letting every subsequent request 401.
@@ -232,6 +282,9 @@ When a refresh fails in a way that only re-login can fix, qgrid removes the toke
232
282
  `recovered` once a later quota check falls below the threshold. Metadata generations prevent an
233
283
  in-flight lookup from restoring a block after a threshold or lifecycle change. The state is not
234
284
  persisted across server restarts.
285
+ - Grok also keeps threshold and exhaustion blocks in memory. Its exhaustion block is request-class
286
+ scoped, and `/settings.on_demand_enabled = true` independently excludes the entire account
287
+ (`packages/api/src/utils/providers/grok/grok-dispatcher.ts`).
235
288
  - If all ready/eligible tokens are over threshold, qgrid throws `QuotaThresholdExceededError`.
236
289
  - Log messages use `quota_threshold gate` with reasons such as `over_threshold`, `lookup_fail_open`, and `all_exceeded`.
237
290