@cartanova/qgrid-cli 2.10.10 → 2.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) 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 +21 -19
  10. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +40 -33
  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 -70
  24. package/bundle/dist/application/request-log/request-log.types.js +1 -1
  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 +32 -16
  33. package/bundle/dist/application/sonamu.generated.sso.js +1 -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 +1 -1
  39. package/bundle/dist/migrations/20260807133553_manual__backfill_request_log_cost.js +8 -6
  40. package/bundle/dist/server-bootstrap.js +4 -2
  41. package/bundle/dist/server-error-handler.js +1 -1
  42. package/bundle/dist/sonamu.config.js +37 -8
  43. package/bundle/dist/startup-migrations.js +17 -7
  44. package/bundle/dist/testing/global.js +1 -1
  45. package/bundle/dist/testing/schema-bench.js +0 -0
  46. package/bundle/dist/testing/test-database-name.js +1 -1
  47. package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +1 -1
  48. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +11 -5
  49. package/bundle/dist/utils/providers/anthropic/anthropic-quota.js +4 -4
  50. package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
  51. package/bundle/dist/utils/providers/anthropic/claude-session.js +20 -19
  52. package/bundle/dist/utils/providers/anthropic/fence-strip.js +1 -1
  53. package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +49 -23
  54. package/bundle/dist/utils/providers/common/credentials.js +5 -1
  55. package/bundle/dist/utils/providers/common/effort.js +3 -3
  56. package/bundle/dist/utils/providers/common/model-cost.js +69 -14
  57. package/bundle/dist/utils/providers/common/provider-types.js +29 -1
  58. package/bundle/dist/utils/providers/common/schema-validation.js +78 -40
  59. package/bundle/dist/utils/providers/common/smooth-weighted-round-robin.js +1 -1
  60. package/bundle/dist/utils/providers/common/strictifier.js +62 -43
  61. package/bundle/dist/utils/providers/common/thinking.js +3 -2
  62. package/bundle/dist/utils/providers/common/ttft.js +1 -1
  63. package/bundle/dist/utils/providers/grok/grok-backend-protocol.js +427 -0
  64. package/bundle/dist/utils/providers/grok/grok-constants.js +55 -0
  65. package/bundle/dist/utils/providers/grok/grok-direct-client.js +196 -0
  66. package/bundle/dist/utils/providers/grok/grok-dispatcher.js +1313 -0
  67. package/bundle/dist/utils/providers/grok/grok-headers.js +118 -0
  68. package/bundle/dist/utils/providers/grok/grok-media-client.js +420 -0
  69. package/bundle/dist/utils/providers/grok/grok-models.js +114 -0
  70. package/bundle/dist/utils/providers/grok/grok-oauth.js +455 -0
  71. package/bundle/dist/utils/providers/grok/grok-quota.js +119 -0
  72. package/bundle/dist/utils/providers/grok/grok-refresh.js +192 -0
  73. package/bundle/dist/utils/providers/grok/grok-types.js +186 -0
  74. package/bundle/dist/utils/providers/grok/grok-voice-client.js +199 -0
  75. package/bundle/dist/utils/providers/grok/index.js +11 -0
  76. package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +111 -83
  77. package/bundle/dist/utils/providers/openai/openai-callback-relay.js +3 -2
  78. package/bundle/dist/utils/providers/openai/openai-constants.js +1 -1
  79. package/bundle/dist/utils/providers/openai/openai-direct-client.js +23 -7
  80. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +143 -106
  81. package/bundle/dist/utils/providers/openai/openai-image-generation.js +48 -33
  82. package/bundle/dist/utils/providers/openai/openai-oauth.js +28 -13
  83. package/bundle/dist/utils/providers/openai/openai-quota.js +38 -27
  84. package/bundle/dist/utils/providers/openai/openai-refresh.js +17 -9
  85. package/bundle/dist/utils/providers/openai/openai-sse.js +1 -1
  86. package/bundle/dist/utils/providers/openai/openai-transport-config.js +1 -1
  87. package/bundle/dist/utils/quiet-hours.js +1 -1
  88. package/bundle/dist/utils/slack-notify.js +14 -8
  89. package/bundle/dist/utils/subset-loaders.js +4 -5
  90. package/bundle/src/application/monit/log-buffer.ts +23 -9
  91. package/bundle/src/application/monit/monit.frame.ts +22 -5
  92. package/bundle/src/application/monit/monit.types.ts +6 -0
  93. package/bundle/src/application/qgrid/conv-routing.test.ts +76 -4
  94. package/bundle/src/application/qgrid/conv-routing.ts +35 -9
  95. package/bundle/src/application/qgrid/expired-token-reminder.ts +9 -1
  96. package/bundle/src/application/qgrid/oauth.ts +51 -15
  97. package/bundle/src/application/qgrid/qgrid-image-generation.ts +9 -0
  98. package/bundle/src/application/qgrid/qgrid-response-format.ts +50 -25
  99. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +19 -0
  100. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +84 -40
  101. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +97 -0
  102. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +274 -126
  103. package/bundle/src/application/qgrid/qgrid.frame.test.ts +1013 -3
  104. package/bundle/src/application/qgrid/qgrid.frame.ts +1415 -60
  105. package/bundle/src/application/qgrid/qgrid.types.ts +335 -0
  106. package/bundle/src/application/qgrid/schema-prompt.ts +105 -41
  107. package/bundle/src/application/qgrid/slack-user-map.ts +5 -0
  108. package/bundle/src/application/qgrid/token-death.ts +4 -0
  109. package/bundle/src/application/qgrid/token-subscriber.test.ts +21 -19
  110. package/bundle/src/application/qgrid/token-subscriber.ts +186 -53
  111. package/bundle/src/application/qgrid/token-trigger-setup.ts +2 -0
  112. package/bundle/src/application/qgrid/token-window-keepalive.ts +49 -6
  113. package/bundle/src/application/qgrid/tool-emulation-schema.ts +33 -29
  114. package/bundle/src/application/qgrid/tool-emulation.ts +52 -27
  115. package/bundle/src/application/request-log/json-schema-type-text.test.ts +5 -5
  116. package/bundle/src/application/request-log/json-schema-type-text.ts +81 -26
  117. package/bundle/src/application/request-log/request-log.model.test.ts +111 -4
  118. package/bundle/src/application/request-log/request-log.model.ts +277 -146
  119. package/bundle/src/application/request-log/request-log.types.ts +6 -0
  120. package/bundle/src/application/request-log/zod-code-format.ts +11 -0
  121. package/bundle/src/application/request-log-step/request-log-step.model.ts +1 -0
  122. package/bundle/src/application/request-log-step/request-log-step.types.ts +2 -0
  123. package/bundle/src/application/setting/setting.constant.ts +9 -0
  124. package/bundle/src/application/setting/setting.model.ts +12 -2
  125. package/bundle/src/application/setting/setting.store.ts +5 -1
  126. package/bundle/src/application/setting/setting.types.ts +8 -0
  127. package/bundle/src/application/sonamu.generated.http +133 -0
  128. package/bundle/src/application/sonamu.generated.sso.ts +2 -0
  129. package/bundle/src/application/sonamu.generated.ts +15 -0
  130. package/bundle/src/application/token/token.identity.test.ts +20 -0
  131. package/bundle/src/application/token/token.model.ts +66 -7
  132. package/bundle/src/application/token/token.types.ts +24 -1
  133. package/bundle/src/i18n/en.ts +19 -0
  134. package/bundle/src/i18n/ko.ts +21 -0
  135. package/bundle/src/i18n/sd.generated.ts +23 -2
  136. package/bundle/src/migrations/20260807133553_manual__backfill_request_log_cost.ts +16 -8
  137. package/bundle/src/server-bootstrap.ts +4 -2
  138. package/bundle/src/server-error-handler.ts +1 -0
  139. package/bundle/src/sonamu.config.ts +69 -7
  140. package/bundle/src/startup-migrations.ts +27 -9
  141. package/bundle/src/testing/global.ts +20 -0
  142. package/bundle/src/testing/schema-bench.ts +105 -30
  143. package/bundle/src/testing/test-database-name.ts +2 -0
  144. package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +8 -0
  145. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +41 -6
  146. package/bundle/src/utils/providers/anthropic/anthropic-quota.ts +7 -3
  147. package/bundle/src/utils/providers/anthropic/anthropic-thinking.ts +6 -0
  148. package/bundle/src/utils/providers/anthropic/claude-session.ts +58 -24
  149. package/bundle/src/utils/providers/anthropic/fence-strip.ts +11 -0
  150. package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +110 -45
  151. package/bundle/src/utils/providers/common/credentials.ts +8 -0
  152. package/bundle/src/utils/providers/common/effort.ts +9 -2
  153. package/bundle/src/utils/providers/common/model-cost.test.ts +48 -1
  154. package/bundle/src/utils/providers/common/model-cost.ts +259 -158
  155. package/bundle/src/utils/providers/common/provider-dispatcher.ts +98 -2
  156. package/bundle/src/utils/providers/common/provider-types.ts +46 -3
  157. package/bundle/src/utils/providers/common/schema-validation.test.ts +5 -1
  158. package/bundle/src/utils/providers/common/schema-validation.ts +124 -56
  159. package/bundle/src/utils/providers/common/smooth-weighted-round-robin.ts +4 -0
  160. package/bundle/src/utils/providers/common/strictifier.ts +185 -59
  161. package/bundle/src/utils/providers/common/thinking.ts +2 -2
  162. package/bundle/src/utils/providers/common/ttft.ts +4 -2
  163. package/bundle/src/utils/providers/grok/__fixtures__/golden-responses-1.0.60.json +164 -0
  164. package/bundle/src/utils/providers/grok/grok-backend-protocol.test.ts +325 -0
  165. package/bundle/src/utils/providers/grok/grok-backend-protocol.ts +721 -0
  166. package/bundle/src/utils/providers/grok/grok-constants.ts +105 -0
  167. package/bundle/src/utils/providers/grok/grok-direct-client.test.ts +179 -0
  168. package/bundle/src/utils/providers/grok/grok-direct-client.ts +313 -0
  169. package/bundle/src/utils/providers/grok/grok-dispatcher.test.ts +1395 -0
  170. package/bundle/src/utils/providers/grok/grok-dispatcher.ts +2105 -0
  171. package/bundle/src/utils/providers/grok/grok-headers.test.ts +149 -0
  172. package/bundle/src/utils/providers/grok/grok-headers.ts +199 -0
  173. package/bundle/src/utils/providers/grok/grok-media-client.test.ts +446 -0
  174. package/bundle/src/utils/providers/grok/grok-media-client.ts +703 -0
  175. package/bundle/src/utils/providers/grok/grok-models.test.ts +96 -0
  176. package/bundle/src/utils/providers/grok/grok-models.ts +161 -0
  177. package/bundle/src/utils/providers/grok/grok-oauth.test.ts +406 -0
  178. package/bundle/src/utils/providers/grok/grok-oauth.ts +771 -0
  179. package/bundle/src/utils/providers/grok/grok-quota.test.ts +142 -0
  180. package/bundle/src/utils/providers/grok/grok-quota.ts +198 -0
  181. package/bundle/src/utils/providers/grok/grok-refresh.test.ts +239 -0
  182. package/bundle/src/utils/providers/grok/grok-refresh.ts +325 -0
  183. package/bundle/src/utils/providers/grok/grok-types.test.ts +252 -0
  184. package/bundle/src/utils/providers/grok/grok-types.ts +374 -0
  185. package/bundle/src/utils/providers/grok/grok-voice-client.test.ts +321 -0
  186. package/bundle/src/utils/providers/grok/grok-voice-client.ts +284 -0
  187. package/bundle/src/utils/providers/grok/index.ts +20 -0
  188. package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +221 -137
  189. package/bundle/src/utils/providers/openai/openai-callback-relay.ts +12 -1
  190. package/bundle/src/utils/providers/openai/openai-constants.ts +2 -0
  191. package/bundle/src/utils/providers/openai/openai-direct-client.ts +111 -21
  192. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +322 -169
  193. package/bundle/src/utils/providers/openai/openai-image-generation.ts +116 -36
  194. package/bundle/src/utils/providers/openai/openai-oauth.ts +48 -20
  195. package/bundle/src/utils/providers/openai/openai-quota.ts +77 -46
  196. package/bundle/src/utils/providers/openai/openai-refresh.ts +42 -18
  197. package/bundle/src/utils/providers/openai/openai-sse.ts +27 -3
  198. package/bundle/src/utils/providers/openai/openai-transport-config.ts +2 -0
  199. package/bundle/src/utils/quiet-hours.ts +12 -1
  200. package/bundle/src/utils/slack-notify.ts +44 -13
  201. package/bundle/src/utils/subset-loaders.ts +7 -7
  202. package/bundle/web-dist/client/assets/clsx-5XM_pHvN.js +1 -0
  203. package/bundle/web-dist/client/assets/index-Be2qCZmI.css +1 -0
  204. package/bundle/web-dist/client/assets/index-C96h3feE.js +32 -0
  205. package/bundle/web-dist/client/assets/logs-DBM6U0QD.js +1 -0
  206. package/bundle/web-dist/client/assets/monit-BBjXa7vB.js +1 -0
  207. package/bundle/web-dist/client/assets/routes-Crz_PQzi.js +5 -0
  208. package/bundle/web-dist/client/assets/{services.generated-NP-ValHd.js → services.generated-B5lc3aIC.js} +5 -5
  209. package/bundle/web-dist/client/assets/settings-Cdwm3OBB.js +1 -0
  210. package/bundle/web-dist/client/assets/show-DBUhALT1.js +2 -0
  211. package/bundle/web-dist/client/assets/tokens-CVQAVJTo.js +1 -0
  212. package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
  213. package/bundle/web-dist/client/assets/use-oauth-login-flow-BfxYI4Oh.js +1 -0
  214. package/bundle/web-dist/client/assets/use-update-token-mutation-qKBC2sn7.js +1 -0
  215. package/bundle/web-dist/client/assets/{vendor-tanstack-DJRQAbrY.js → vendor-tanstack-DRPs09ai.js} +1 -1
  216. package/bundle/web-dist/client/index.html +5 -5
  217. package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
  218. package/bundle/web-dist/server/assets/{lazyRouteComponent-CgBdabgd.js → lazyRouteComponent-AKiHfZWp.js} +129 -2
  219. package/bundle/web-dist/server/assets/{logs-BMyR98rU.js → logs-B7QmGJq3.js} +18 -14
  220. package/bundle/web-dist/server/assets/{monit-ZPt66W5M.js → monit-DFt7x3bh.js} +13 -12
  221. package/bundle/web-dist/server/assets/{plus-BZ9I0VgC.js → plus-DaYQRpBt.js} +1 -1
  222. package/bundle/web-dist/server/assets/{react-dom-Ds75e4Jl.js → react-dom-Cv23mm1K.js} +2 -129
  223. package/bundle/web-dist/server/assets/{refresh-cw-CztCFis-.js → refresh-cw-BpXNsAy-.js} +1 -1
  224. package/bundle/web-dist/server/assets/{request-model-DjGldb-h.js → request-model-eHE6YbaF.js} +1 -1
  225. package/bundle/web-dist/server/assets/{routes-Ct-k7nBA.js → routes-_Y-PJfgO.js} +110 -39
  226. package/bundle/web-dist/server/assets/{services.generated-BA4AcAf5.js → services.generated-CMJ8AHbO.js} +582 -172
  227. package/bundle/web-dist/server/assets/{settings-CBUZ47Xx.js → settings-JwJKxn2e.js} +14 -14
  228. package/bundle/web-dist/server/assets/{show-LSFIzvO2.js → show-BEv6z1v_.js} +90 -60
  229. package/bundle/web-dist/server/assets/{tokens-DxrBW512.js → tokens-CNT4mI-f.js} +162 -50
  230. package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
  231. package/bundle/web-dist/server/assets/use-oauth-login-flow-jkAkT3X6.js +2345 -0
  232. package/bundle/web-dist/server/assets/{use-update-token-mutation-pkArIzCP.js → use-update-token-mutation-Sm6kh02m.js} +1 -1
  233. package/bundle/web-dist/server/entry-server.generated.js +1644 -21655
  234. package/dist/cli.js +9 -9
  235. package/package.json +4 -11
  236. package/postinstall.mjs +12 -0
  237. package/skills/qgrid/SKILL.md +1 -0
  238. package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
  239. package/skills/qgrid/references/decision-rationale.md +23 -0
  240. package/skills/qgrid/references/grok-runtime.md +89 -0
  241. package/skills/qgrid/references/provider-runtime-differences.md +30 -29
  242. package/skills/qgrid/references/repo-map.md +10 -0
  243. package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
  244. package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
  245. package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
  246. package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
  247. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
  248. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
  249. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
  250. package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
  251. package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
  252. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
  253. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
  254. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
  255. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
  256. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
  257. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
  258. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
  259. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
  260. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
  261. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
  262. package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
  263. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
  264. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
  265. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
  266. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
  267. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
  268. package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
  269. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
  270. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
  271. package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
  272. package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
  273. 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
  274. 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
  275. 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
  276. 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
  277. 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
  278. 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
  279. 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
  280. 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
  281. 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
  282. 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
  283. package/bundle/dist/testing/setup-mocks.js +0 -16
  284. package/bundle/src/testing/setup-mocks.ts +0 -44
  285. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
  286. package/bundle/web-dist/client/assets/index-DZwzUfI-.js +0 -106
  287. package/bundle/web-dist/client/assets/logs-Cog79DU5.js +0 -1
  288. package/bundle/web-dist/client/assets/monit-2auznBys.js +0 -1
  289. package/bundle/web-dist/client/assets/routes-B0lTeLK-.js +0 -5
  290. package/bundle/web-dist/client/assets/settings-D8ZxZGSJ.js +0 -1
  291. package/bundle/web-dist/client/assets/show-CFSERlnM.js +0 -2
  292. package/bundle/web-dist/client/assets/tokens-CZXUyI7O.js +0 -1
  293. package/bundle/web-dist/client/assets/use-oauth-login-flow-hboOs3wG.js +0 -1
  294. package/bundle/web-dist/client/assets/use-update-token-mutation-BQHS0byG.js +0 -1
  295. package/bundle/web-dist/server/assets/use-oauth-login-flow-Gn8flMK5.js +0 -178
  296. package/dist/cli.d.ts +0 -10
  297. /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
  298. /package/bundle/web-dist/client/assets/{plus-B62CuqT8.js → plus-BsQdY7PS.js} +0 -0
  299. /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
  300. /package/bundle/web-dist/client/assets/{refresh-cw-NNcU0Cmq.js → refresh-cw-D9IUmT23.js} +0 -0
  301. /package/bundle/web-dist/client/assets/{request-model-CojtinqK.js → request-model-Bpp_rkK8.js} +0 -0
  302. /package/bundle/web-dist/server/assets/{cost-eEHeTRT5.js → cost-BC9yzyA9.js} +0 -0
@@ -1,14 +1,21 @@
1
+ import { createHash } from "node:crypto";
2
+
1
3
  /**
2
4
  * conv-routing — 대화 연속성(cache affinity) 좌표 검증/구성.
3
5
  *
4
6
  * 모든 turn은 현재 input과 전체 history를 전달한다.
5
- * OpenAI의 epoch=-1 좌표는 system/model hash와 opaque affinity를 검증한 뒤
7
+ * Direct provider(OpenAI, Grok)의 epoch=-1 좌표는 system/model hash와 opaque affinity를 검증한 뒤
6
8
  * token 선택과 prompt-cache 힌트로만 사용한다.
7
9
  */
8
- import { createHash } from "node:crypto";
10
+ import { z } from "zod";
9
11
 
10
12
  import { type ReuseThreadCoord } from "../../utils/providers/common/provider-dispatcher";
11
- import { type JsonValue, type UserInput } from "../../utils/providers/common/provider-types";
13
+ import {
14
+ jsonValueSchema,
15
+ type JsonValue,
16
+ type ProviderId,
17
+ type UserInput,
18
+ } from "../../utils/providers/common/provider-types";
12
19
  import { type QgridThreadCoord, type QueryInput, type QgridToolResultInput } from "./qgrid.types";
13
20
 
14
21
  export function systemHash(system?: string, modelNamespace?: string): string {
@@ -23,8 +30,10 @@ function toolResultsToText(toolResults: QgridToolResultInput[]): string {
23
30
  const lines = toolResults.map((tr) => {
24
31
  const name = tr.toolName ? ` (${tr.toolName})` : "";
25
32
  const errMark = tr.isError ? " [error]" : "";
33
+
26
34
  return `Tool result for call ${tr.toolCallId}${name}${errMark}: ${tr.output}`;
27
35
  });
36
+
28
37
  return `${lines.join("\n")}\n\nNow continue answering the user's request using these results.`;
29
38
  }
30
39
 
@@ -40,22 +49,31 @@ export interface ConvDecision {
40
49
  preferredTokenId?: number;
41
50
  }
42
51
 
52
+ // HTTPS direct transport 로 prompt_cache_key affinity 를 쓰는 provider.
53
+ export type DirectProviderId = Extract<ProviderId, "openai" | "grok">;
54
+
43
55
  export interface ConvRoutingOptions {
44
- directOpenAI?: boolean;
56
+ directProvider?: DirectProviderId;
57
+ // 보통 `<provider>/<model>`. 같은 system 이라도 provider/model 이 다르면 좌표를 공유하지 않는다.
45
58
  modelNamespace?: string;
46
59
  }
47
60
 
48
- // 입력과 전체 history를 구성하고, 검증된 OpenAI cache affinity만 부가한다.
61
+ // 입력과 전체 history를 구성하고, 검증된 direct-provider cache affinity만 부가한다.
49
62
  export function decideConvRouting(
50
63
  input: QueryInput,
51
64
  options: ConvRoutingOptions = {},
52
65
  ): ConvDecision {
66
+ const directProvider = options.directProvider;
67
+
53
68
  const sysHash = systemHash(
54
69
  input.system,
55
- options.directOpenAI ? (options.modelNamespace ?? input.model ?? "openai") : undefined,
70
+ directProvider === undefined
71
+ ? undefined
72
+ : (options.modelNamespace ?? input.model ?? directProvider),
56
73
  );
74
+
57
75
  const history: Array<JsonValue> | undefined = input.history
58
- ? (JSON.parse(input.history) as Array<JsonValue>)
76
+ ? z.array(jsonValueSchema).parse(JSON.parse(input.history))
59
77
  : undefined;
60
78
 
61
79
  const coord = input.runContext?.threadCoord;
@@ -63,14 +81,15 @@ export function decideConvRouting(
63
81
  // 재사용 자격: 좌표 존재 + system 동일. sessionKey 격리 + systemHash 로 대화 동일성이
64
82
  // 보장되고, 공통 prefix 는 백엔드가 prompt_cache_key 고정으로 알아서 캐시한다.
65
83
  const directCoordEligible =
66
- options.directOpenAI === true &&
84
+ directProvider !== undefined &&
67
85
  coord?.epoch === -1 &&
68
86
  coord.systemHash === sysHash &&
69
87
  input.cacheAffinityKey !== undefined &&
70
88
  coord.threadId === input.cacheAffinityKey;
89
+
71
90
  // affinity 를 요청하지 않은 one-shot 요청에 임의 키를 붙이면 transport 가 그 소켓을
72
91
  // affinity 소켓으로 오인해 재사용되지 않을 연결을 계속 붙들어 둔다 → 키를 비워 둔다.
73
- const cacheKey = options.directOpenAI ? input.cacheAffinityKey : undefined;
92
+ const cacheKey = directProvider === undefined ? undefined : input.cacheAffinityKey;
74
93
 
75
94
  return {
76
95
  // tool follow-up도 실행 user 줄에 결과를 사용해 계속 답하라는 안내를 담는다.
@@ -87,19 +106,25 @@ function buildDeltaInput(input: QueryInput): Array<UserInput> {
87
106
  if (input.toolResults && input.toolResults.length > 0) {
88
107
  return [{ type: "text", text: toolResultsToText(input.toolResults), text_elements: [] }];
89
108
  }
109
+
90
110
  if (input.input && input.input.length > 0) {
91
111
  const hasText = input.input.some((part) => part.type === "text");
112
+
92
113
  const parts: Array<UserInput> = input.input.map((part) => {
93
114
  if (part.type === "text") {
94
115
  return { type: "text", text: part.text, text_elements: part.text_elements };
95
116
  }
117
+
96
118
  return { type: "image", url: part.url };
97
119
  });
120
+
98
121
  if (!hasText && input.prompt.length > 0) {
99
122
  return [{ type: "text", text: input.prompt, text_elements: [] }, ...parts];
100
123
  }
124
+
101
125
  return parts;
102
126
  }
127
+
103
128
  return [{ type: "text", text: input.prompt, text_elements: [] }];
104
129
  }
105
130
 
@@ -117,6 +142,7 @@ export function issueConvContext(
117
142
  systemHash: decision.systemHash,
118
143
  };
119
144
  }
145
+
120
146
  return {
121
147
  workerId: threadCoord.workerId,
122
148
  threadId: threadCoord.threadId,
@@ -45,12 +45,16 @@ export function buildReminderContext(
45
45
  userMap: Map<string, string>,
46
46
  ): string {
47
47
  const showLabel = tokens.length > 1;
48
+
48
49
  const lines = tokens.map((token) => {
49
50
  const mention = mentionFor(token.name, userMap);
50
51
  const label = token.name ?? "unnamed";
52
+
51
53
  if (!showLabel) return mention;
54
+
52
55
  return mention ? `${mention} ${label}` : label;
53
56
  });
57
+
54
58
  return [...lines, "재로그인이 필요합니다"].filter(Boolean).join("\n");
55
59
  }
56
60
 
@@ -59,6 +63,7 @@ async function sendReminder(
59
63
  mode: "scheduled" | "manual",
60
64
  ): Promise<number> {
61
65
  const expired = await deps.findReauthRequired();
66
+
62
67
  if (expired.length === 0) return 0;
63
68
 
64
69
  const userMap = deps.getSlackUserMap();
@@ -72,6 +77,7 @@ async function sendReminder(
72
77
  urgent: mode === "manual",
73
78
  throwOnFailure: mode === "manual",
74
79
  });
80
+
75
81
  return expired.length;
76
82
  }
77
83
 
@@ -95,12 +101,14 @@ function scheduleExpiredTokenReminder(runNow: boolean, deps: ExpiredTokenReminde
95
101
  // 주기 값과 별개인 스위치다. 꺼도 주기는 남아 있어 다시 켤 때 고르던 값이 그대로다.
96
102
  if (deps.readSetting("slack.remindersEnabled", "SLACK_REMINDERS_ENABLED") === "false") {
97
103
  logger.info("expired token reminder disabled");
104
+
98
105
  return;
99
106
  }
100
107
 
101
108
  const minutes = Number(
102
109
  deps.readSetting("slack.expiryReminderMinutes", "SLACK_EXPIRY_REMINDER_INTERVAL_MINUTES") ?? 0,
103
110
  );
111
+
104
112
  if (!Number.isFinite(minutes) || minutes <= 0) return;
105
113
 
106
114
  logger.info(
@@ -109,7 +117,7 @@ function scheduleExpiredTokenReminder(runNow: boolean, deps: ExpiredTokenReminde
109
117
 
110
118
  const run = () =>
111
119
  sendReminder(deps, "scheduled").catch((e) =>
112
- logger.warn(`reminder failed: ${(e as Error).message}`),
120
+ logger.warn(`reminder failed: ${e instanceof Error ? e.message : String(e)}`),
113
121
  );
114
122
 
115
123
  if (runNow) void run();
@@ -4,6 +4,7 @@
4
4
  import { createHash, randomBytes } from "node:crypto";
5
5
 
6
6
  import { getLogger } from "@logtape/logtape";
7
+ import { z } from "zod";
7
8
 
8
9
  export type AnthropicUsageRaw = {
9
10
  error?: string;
@@ -11,6 +12,35 @@ export type AnthropicUsageRaw = {
11
12
  seven_day?: { utilization: number | null; resets_at: string | null } | null;
12
13
  seven_day_overage_included?: { utilization: number | null; resets_at: string | null } | null;
13
14
  };
15
+
16
+ const usageWindowSchema = z
17
+ .object({ utilization: z.number().nullable(), resets_at: z.string().nullable() })
18
+ .nullable()
19
+ .optional();
20
+
21
+ const anthropicUsageRawSchema: z.ZodType<AnthropicUsageRaw> = z.looseObject({
22
+ error: z.string().optional(),
23
+ five_hour: usageWindowSchema,
24
+ seven_day: usageWindowSchema,
25
+ seven_day_overage_included: usageWindowSchema,
26
+ });
27
+
28
+ const tokenExchangeResponseSchema = z.object({
29
+ access_token: z.string(),
30
+ refresh_token: z.string(),
31
+ expires_in: z.number(),
32
+ scope: z.string(),
33
+ account: z.object({ uuid: z.string(), email_address: z.string() }).optional(),
34
+ });
35
+
36
+ // A refresh response may omit refresh_token; the caller then keeps the current one.
37
+ const tokenRefreshResponseSchema = z.object({
38
+ access_token: z.string(),
39
+ refresh_token: z.string().optional(),
40
+ expires_in: z.number(),
41
+ scope: z.string(),
42
+ });
43
+
14
44
  export type AnthropicUsageWithMeta = {
15
45
  data: AnthropicUsageRaw;
16
46
  cachedAt: number;
@@ -21,6 +51,7 @@ const logger = getLogger(["qgrid", "oauth"]);
21
51
  const CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
22
52
  const AUTHORIZE_URL = "https://claude.com/cai/oauth/authorize";
23
53
  const TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
54
+
24
55
  // client 허용 목록에 있는 콘솔 콜백. 인증 후 콘솔 페이지가 `code#state`를 표시하고
25
56
  // 사용자가 붙여넣는 코드 플로우(Claude Code CLI와 동일)에 사용한다.
26
57
  export const CONSOLE_CALLBACK_URL = "https://console.anthropic.com/oauth/code/callback";
@@ -48,10 +79,17 @@ function base64URLEncode(buffer: Buffer): string {
48
79
  return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
49
80
  }
50
81
 
51
- export function generatePKCE(): { codeVerifier: string; codeChallenge: string; state: string } {
82
+ export interface PKCEChallenge {
83
+ codeVerifier: string;
84
+ codeChallenge: string;
85
+ state: string;
86
+ }
87
+
88
+ export function generatePKCE(): PKCEChallenge {
52
89
  const codeVerifier = base64URLEncode(randomBytes(32));
53
90
  const codeChallenge = base64URLEncode(createHash("sha256").update(codeVerifier).digest());
54
91
  const state = base64URLEncode(randomBytes(32));
92
+
55
93
  return { codeVerifier, codeChallenge, state };
56
94
  }
57
95
 
@@ -65,6 +103,7 @@ export function buildAuthUrl(codeChallenge: string, state: string, redirectUri:
65
103
  url.searchParams.append("code_challenge", codeChallenge);
66
104
  url.searchParams.append("code_challenge_method", "S256");
67
105
  url.searchParams.append("state", state);
106
+
68
107
  return url.toString();
69
108
  }
70
109
 
@@ -95,18 +134,13 @@ export async function exchangeCodeForTokens(
95
134
  state,
96
135
  }),
97
136
  });
137
+
98
138
  if (!res.ok) {
99
139
  const text = await res.text();
100
140
  throw new Error(`Token exchange failed (${res.status}): ${text}`);
101
141
  }
102
142
 
103
- const data = (await res.json()) as {
104
- access_token: string;
105
- refresh_token: string;
106
- expires_in: number;
107
- scope: string;
108
- account?: { uuid: string; email_address: string };
109
- };
143
+ const data = tokenExchangeResponseSchema.parse(await res.json());
110
144
 
111
145
  return {
112
146
  accessToken: data.access_token,
@@ -148,16 +182,13 @@ export async function refreshAccessToken(refreshToken: string): Promise<OAuthTok
148
182
  scope: REFRESH_SCOPES.join(" "),
149
183
  }),
150
184
  });
185
+
151
186
  if (!res.ok) {
152
187
  const text = await res.text();
153
188
  throw new RefreshFailedError(res.status, text);
154
189
  }
155
- const data = (await res.json()) as {
156
- access_token: string;
157
- refresh_token: string;
158
- expires_in: number;
159
- scope: string;
160
- };
190
+
191
+ const data = tokenRefreshResponseSchema.parse(await res.json());
161
192
 
162
193
  return {
163
194
  accessToken: data.access_token,
@@ -181,6 +212,7 @@ export async function fetchUsage(accessToken: string): Promise<AnthropicUsageRaw
181
212
  export async function fetchUsageWithMeta(accessToken: string): Promise<AnthropicUsageWithMeta> {
182
213
  const cacheKey = accessToken.slice(-10);
183
214
  const cached = usageCache[cacheKey];
215
+
184
216
  if (cached && Date.now() - cached.cachedAt < USAGE_API_CACHE_TTL) {
185
217
  return cached;
186
218
  }
@@ -193,11 +225,13 @@ export async function fetchUsageWithMeta(accessToken: string): Promise<Anthropic
193
225
  },
194
226
  signal: AbortSignal.timeout(5000),
195
227
  });
228
+
196
229
  if (!res.ok) {
197
230
  const text = await res.text();
198
231
 
199
232
  // 파싱 시도해서 에러 메시지 추출
200
233
  let errorMessage = `Error ${res.status}`;
234
+
201
235
  try {
202
236
  const parsed = JSON.parse(text);
203
237
  errorMessage = parsed.error?.message ?? errorMessage;
@@ -214,12 +248,14 @@ export async function fetchUsageWithMeta(accessToken: string): Promise<Anthropic
214
248
  const errorResult = { error: errorMessage };
215
249
  const entry = { data: errorResult, cachedAt: Date.now() };
216
250
  usageCache[cacheKey] = entry;
251
+
217
252
  return entry;
218
253
  }
219
254
 
220
- const data = (await res.json()) as AnthropicUsageRaw;
255
+ const data = anthropicUsageRawSchema.parse(await res.json());
221
256
  // cache invalidate
222
257
  const entry = { data, cachedAt: Date.now() };
223
258
  usageCache[cacheKey] = entry;
259
+
224
260
  return entry;
225
261
  }
@@ -42,6 +42,7 @@ export function resolveImageGenerationOptions(
42
42
  options: ImageGenerationOptions | undefined,
43
43
  ): ResolvedImageGenerationOptions {
44
44
  const size = options?.size;
45
+
45
46
  return {
46
47
  quality: options?.quality ?? DEFAULT_IMAGE_GENERATION_QUALITY,
47
48
  // Unknown/custom sizes use the default price, without changing output hints.
@@ -61,7 +62,9 @@ export function imageGenerationCostMethod(
61
62
  ) {
62
63
  return "estimated:gpt-image-2:reported-usage:public-prices:conservative";
63
64
  }
65
+
64
66
  const resolved = resolveImageGenerationOptions(options);
67
+
65
68
  return `assumed:${CODEX_IMAGE_GENERATION_MODEL}:${resolved.quality}:${resolved.size}:png`;
66
69
  }
67
70
 
@@ -71,8 +74,10 @@ export function estimateImageGenerationCostMicroUsd(
71
74
  ): number | null {
72
75
  const images = result.content.filter((item) => item.type === "image");
73
76
  const imageCount = images.length;
77
+
74
78
  if (imageCount === 0) return null;
75
79
  const usage = images.find((image) => image.generation?.usage)?.generation?.usage;
80
+
76
81
  if (usage) {
77
82
  // Response-level image usage is carried by its first image only.
78
83
  // Do not multiply it by output count or price it as the requested text driver.
@@ -82,15 +87,19 @@ export function estimateImageGenerationCostMicroUsd(
82
87
  // Use a consistent reported split; unknown input is conservatively priced as
83
88
  // images. Cache discounts and private subscription billing remain unknown.
84
89
  const details = usage.input_tokens_details;
90
+
85
91
  const textTokens =
86
92
  details && details.text_tokens + details.image_tokens <= usage.input_tokens
87
93
  ? details.text_tokens
88
94
  : 0;
95
+
89
96
  return Math.round(
90
97
  textTokens * 5 + (usage.input_tokens - textTokens) * 8 + usage.output_tokens * 30,
91
98
  );
92
99
  }
100
+
93
101
  const resolved = resolveImageGenerationOptions(options);
94
102
  const unitCost = IMAGE_OUTPUT_COST_MICRO_USD[resolved.quality][resolved.size];
103
+
95
104
  return imageCount * unitCost;
96
105
  }
@@ -1,3 +1,4 @@
1
+ import { type JsonValue } from "../../utils/providers/common/provider-types";
1
2
  import {
2
3
  CODEX_IMAGE_GENERATION_MODEL,
3
4
  resolveImageGenerationOptions,
@@ -26,7 +27,9 @@ export function formatResponseForLog(result: QueryOutput): string {
26
27
  return result.content
27
28
  .flatMap((item) => {
28
29
  if (item.type === "text") return [item.text];
30
+
29
31
  if (item.type === "image") return [formatImagePartForLog(item)];
32
+
30
33
  return [];
31
34
  })
32
35
  .filter((part) => part.length > 0)
@@ -39,6 +42,7 @@ export function getImageParts(result: QueryOutput): Extract<QgridContent, { type
39
42
 
40
43
  export function formatImagePartForLog(image: Extract<QgridContent, { type: "image" }>): string {
41
44
  const alt = escapeHtmlAttribute(image.revisedPrompt ?? "generated image");
45
+
42
46
  return `<img src="data:${image.mediaType ?? "image/png"};base64,${image.data}" alt="${alt}" />`;
43
47
  }
44
48
 
@@ -47,29 +51,38 @@ export function imageGenerationToolArgs(
47
51
  options: { includeInputImages?: boolean; generation?: ImageGenerationMetadata } = {},
48
52
  ): string {
49
53
  const resolved = resolveImageGenerationOptions(args.imageGenerationOptions);
54
+
50
55
  const inputImages =
51
56
  options.includeInputImages === false ? [] : extractInputImagesForToolArgs(args);
52
- return JSON.stringify({
53
- prompt: args.prompt,
54
- ...(inputImages.length > 0 ? { inputImages } : {}),
55
- driverModel: args.model ?? null,
56
- tool: {
57
- ...CODEX_IMAGE_GENERATION_TOOL_CONFIG,
58
- ...(args.imageGenerationOptions?.outputFormat
59
- ? { outputFormat: args.imageGenerationOptions.outputFormat }
60
- : {}),
61
- },
62
- ...(args.imageGenerationOptions ? { requestedOptions: args.imageGenerationOptions } : {}),
63
- ...(options.generation
64
- ? { observedGeneration: options.generation }
65
- : {
66
- pricingAssumption: {
67
- model: CODEX_IMAGE_GENERATION_MODEL,
68
- quality: resolved.quality,
69
- size: resolved.size,
70
- },
71
- }),
72
- });
57
+
58
+ // Keys are assigned in their serialized order; request logs store this JSON text.
59
+ const toolArgs: Record<string, JsonValue> = {};
60
+ toolArgs.prompt = args.prompt;
61
+
62
+ if (inputImages.length > 0) toolArgs.inputImages = inputImages;
63
+ toolArgs.driverModel = args.model ?? null;
64
+ const tool: Record<string, JsonValue> = {};
65
+ Object.assign(tool, CODEX_IMAGE_GENERATION_TOOL_CONFIG);
66
+
67
+ if (args.imageGenerationOptions?.outputFormat) {
68
+ tool.outputFormat = args.imageGenerationOptions.outputFormat;
69
+ }
70
+
71
+ toolArgs.tool = tool;
72
+
73
+ if (args.imageGenerationOptions) toolArgs.requestedOptions = args.imageGenerationOptions;
74
+
75
+ if (options.generation) {
76
+ toolArgs.observedGeneration = options.generation;
77
+ } else {
78
+ toolArgs.pricingAssumption = {
79
+ model: CODEX_IMAGE_GENERATION_MODEL,
80
+ quality: resolved.quality,
81
+ size: resolved.size,
82
+ };
83
+ }
84
+
85
+ return JSON.stringify(toolArgs);
73
86
  }
74
87
 
75
88
  export function buildImageGenerationToolSteps(
@@ -101,16 +114,21 @@ export function buildImageGenerationToolSteps(
101
114
  }));
102
115
  }
103
116
 
104
- export function extractInputImagesForToolArgs(args: QueryInput): Array<{
117
+ type LoggedInputImage = {
105
118
  mediaType?: string;
106
119
  data?: string;
107
120
  url?: string;
108
121
  byteSize?: number;
109
- }> {
122
+ };
123
+
124
+ export function extractInputImagesForToolArgs(args: QueryInput): LoggedInputImage[] {
110
125
  const images = args.input?.filter((item) => item.type === "image") ?? [];
126
+
111
127
  return images.map((image) => {
112
128
  const dataUrl = parseDataUrl(image.url);
129
+
113
130
  if (!dataUrl) return { url: image.url };
131
+
114
132
  if (dataUrl.isBase64 && dataUrl.mediaType.toLowerCase().startsWith("image/")) {
115
133
  return {
116
134
  mediaType: dataUrl.mediaType,
@@ -118,11 +136,15 @@ export function extractInputImagesForToolArgs(args: QueryInput): Array<{
118
136
  byteSize: base64ByteSize(dataUrl.data),
119
137
  };
120
138
  }
121
- return {
139
+
140
+ const logged: LoggedInputImage = {
122
141
  mediaType: dataUrl.mediaType,
123
142
  url: `[data-url ${image.url.length} chars]`,
124
- ...(dataUrl.isBase64 ? { byteSize: base64ByteSize(dataUrl.data) } : {}),
125
143
  };
144
+
145
+ if (dataUrl.isBase64) logged.byteSize = base64ByteSize(dataUrl.data);
146
+
147
+ return logged;
126
148
  });
127
149
  }
128
150
 
@@ -130,13 +152,16 @@ function parseDataUrl(
130
152
  value: string,
131
153
  ): { mediaType: string; data: string; isBase64: boolean } | null {
132
154
  const match = /^data:([^;,]+)((?:;[^,]*)*),(.*)$/is.exec(value);
155
+
133
156
  if (!match) return null;
134
157
  const params = match[2]!.toLowerCase().split(";").filter(Boolean);
158
+
135
159
  return { mediaType: match[1]!, data: match[3]!, isBase64: params.includes("base64") };
136
160
  }
137
161
 
138
162
  function base64ByteSize(value: string): number {
139
163
  const normalized = /\s/.test(value) ? value.replace(/\s/g, "") : value;
140
164
  const padding = normalized.endsWith("==") ? 2 : normalized.endsWith("=") ? 1 : 0;
165
+
141
166
  return Math.max(Math.floor((normalized.length * 3) / 4) - padding, 0);
142
167
  }
@@ -112,6 +112,25 @@ describe("qgrid run lifecycle start", () => {
112
112
  });
113
113
  });
114
114
 
115
+ it.each([undefined, "Caller system"])(
116
+ "logs the Anthropic schema instructions with system=%s",
117
+ async (system) => {
118
+ const jsonSchema = '{"type":"object","properties":{"answer":{"type":"string"}}}';
119
+ await beforeQuery({
120
+ prompt: "hi",
121
+ model: "anthropic/claude-opus-5-5",
122
+ system,
123
+ jsonSchema,
124
+ });
125
+
126
+ const saved = createRunMock.mock.calls[0]![0];
127
+ expect(saved.system_prompt).toContain("## Output Format");
128
+ expect(saved.system_prompt).toContain(`<output-json-schema>\n${jsonSchema}\n</output-json-schema>`);
129
+ if (system) expect(saved.system_prompt).toMatch(/^Caller system\n\n/);
130
+ expect(saved.json_schema).toBe(jsonSchema);
131
+ },
132
+ );
133
+
115
134
  it.each([
116
135
  ["openai/gpt-6-sol", "fast", "fast"],
117
136
  ["openai/gpt-6-sol", "flex", "flex"],