@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
@@ -10,20 +10,27 @@ import {
10
10
  Puri,
11
11
  transactional,
12
12
  } from "sonamu";
13
+ import { z } from "zod";
13
14
 
14
15
  import { SD } from "../../i18n/sd.generated";
15
16
  import { calculateCostUsd } from "../../utils/providers/common/model-cost";
17
+ import {
18
+ isJsonObject,
19
+ isProviderId,
20
+ type JsonValue,
21
+ jsonValueSchema,
22
+ type ProviderId,
23
+ } from "../../utils/providers/common/provider-types";
24
+ import { type RequestLogStepSaveParams } from "../request-log-step/request-log-step.types";
16
25
  import { type RequestLogSubsetKey, type RequestLogSubsetMapping } from "../sonamu.generated";
17
26
  import { requestLogLoaderQueries, requestLogSubsetQueries } from "../sonamu.generated.sso";
27
+ import { renderJsonSchemaZodText, renderParsedJsonSchemaTypeText } from "./json-schema-type-text";
18
28
  import {
19
- renderJsonSchemaZodShapeText,
20
- renderParsedJsonSchemaTypeText,
21
- } from "./json-schema-type-text";
22
- import {
29
+ type HistoryItems,
23
30
  type RequestLogListParams,
24
31
  type RequestLogSaveParams,
25
32
  type InputImages,
26
- type ToolDefinitions,
33
+ ToolDefinitions,
27
34
  type ToolView,
28
35
  } from "./request-log.types";
29
36
  import { formatZodCode } from "./zod-code-format";
@@ -33,11 +40,28 @@ export const MICRO_USD = 1_000_000;
33
40
  const REQUEST_LOG_RUN_LOCK_CLASS_ID = 718;
34
41
  const TOOL_ENUM_VALUE_LIMIT = 6;
35
42
 
36
- function decodeStoredTools(value: unknown): ToolDefinitions | null {
43
+ /**
44
+ * 비용을 알 수 없는 non-token 요청(Grok STT/TTS, ticks 없는 video). provider 비용 없이
45
+ * 토큰 0 으로 성공 저장되므로 SUM 은 건너뛰고 legacy 재계산도 $0 으로 매긴다 — 합계에
46
+ * 빠졌다는 신호를 따로 센다. 실패/중단/진행 중 row 는 과금 대상이 아니라 제외하고,
47
+ * 이미지 row 는 `unknownImageCostCount` 가 이미 센다.
48
+ */
49
+ export const UNKNOWN_MEDIA_COST_PREDICATE =
50
+ "request_logs.status = 'succeeded' AND request_logs.cost_usd IS NULL AND request_logs.cost_source IS NULL" +
51
+ " AND request_logs.is_image_generation = false AND request_logs.input_tokens = 0 AND request_logs.output_tokens = 0";
52
+
53
+ /** Numeric aggregate column that node-postgres may deliver as bigint text. */
54
+ const bigintAggregate = z.coerce.number();
55
+
56
+ function decodeStoredTools(
57
+ value: ToolDefinitions | string | null | undefined,
58
+ ): ToolDefinitions | null {
37
59
  if (!value) return null;
38
- if (typeof value !== "string") return value as ToolDefinitions;
60
+
61
+ if (Array.isArray(value)) return value;
62
+
39
63
  try {
40
- return JSON.parse(value) as ToolDefinitions;
64
+ return ToolDefinitions.safeParse(JSON.parse(value)).data ?? null;
41
65
  } catch {
42
66
  return null;
43
67
  }
@@ -49,6 +73,47 @@ type ToolResultContinuation = {
49
73
  isError?: boolean;
50
74
  };
51
75
 
76
+ type RequestLogRunRow = Partial<RequestLogSaveParams>;
77
+
78
+ export type RequestLogStatus = NonNullable<RequestLogSaveParams["status"]>;
79
+
80
+ /** Step columns the caller supplies; `request_log_id` is bound by `appendStep`. */
81
+ export type RequestLogStepFields = Partial<Omit<RequestLogStepSaveParams, "request_log_id">> &
82
+ Pick<RequestLogStepSaveParams, "step_index" | "type">;
83
+
84
+ export interface FinishRunParams {
85
+ status: RequestLogStatus;
86
+ response?: string;
87
+ token_name?: string;
88
+ input_tokens?: number;
89
+ output_tokens?: number;
90
+ cache_read_tokens?: number;
91
+ cache_creation_tokens?: number;
92
+ cache_creation_5m_tokens?: number | null;
93
+ cache_creation_1h_tokens?: number | null;
94
+ duration_ms?: number;
95
+ requested_model_name?: string | null;
96
+ model_name?: string | null;
97
+ service_tier?: string | null;
98
+ fallback_count?: number | null;
99
+ cost_usd?: number | null;
100
+ cost_source?: string | null;
101
+ history?: HistoryItems;
102
+ error_message?: string;
103
+ tool_call_count?: number;
104
+ image_cost_usd?: number | null;
105
+ image_cost_method?: string | null;
106
+ is_image_generation?: boolean;
107
+ response_json_ok?: boolean | null;
108
+ }
109
+
110
+ type FinishRunUpdate = Partial<FinishRunParams> & { id: number; ttft_ms?: number };
111
+
112
+ /** Copies `key` only when the caller supplied it, so omitted columns stay untouched. */
113
+ function copyDefined<T, K extends keyof T>(target: Partial<T>, source: T, key: K): void {
114
+ if (source[key] !== undefined) target[key] = source[key];
115
+ }
116
+
52
117
  type RequestLogStepAggregate = {
53
118
  input_tokens: number;
54
119
  output_tokens: number;
@@ -75,23 +140,24 @@ const STEP_AGGREGATE_SELECT = {
75
140
  cost_source: "cost_source",
76
141
  } as const;
77
142
 
78
- function aggregateGenerateStepRows(rows: Array<Record<string, unknown>>): RequestLogStepAggregate {
79
- const sum = (field: string): number =>
80
- rows.reduce((total, row) => total + Number(row[field] ?? 0), 0);
81
- const optionalSum = (field: string): number | undefined =>
82
- rows.some((row) => row[field] !== null && row[field] !== undefined) ? sum(field) : undefined;
83
- const collapse = (field: string): string | undefined => {
84
- const values = [
85
- ...new Set(
86
- rows
87
- .map((row) => row[field])
88
- .filter((value): value is string => typeof value === "string" && value.length > 0),
89
- ),
90
- ];
91
- if (values.length === 0) return undefined;
92
- return values.length === 1 ? values[0] : "mixed";
93
- };
94
- return {
143
+ type StepAggregateNumberField = Exclude<keyof typeof STEP_AGGREGATE_SELECT, "cost_source">;
144
+
145
+ type StepAggregateRow = { [K in StepAggregateNumberField]: number | null } & {
146
+ cost_source: string | null;
147
+ };
148
+
149
+ function aggregateGenerateStepRows(rows: StepAggregateRow[]): RequestLogStepAggregate {
150
+ const sum = (field: StepAggregateNumberField): number =>
151
+ rows.reduce((total, row) => total + (row[field] ?? 0), 0);
152
+
153
+ const optionalSum = (field: StepAggregateNumberField): number | undefined =>
154
+ rows.some((row) => row[field] !== null) ? sum(field) : undefined;
155
+
156
+ const costSources = [
157
+ ...new Set(rows.flatMap((row) => (row.cost_source ? [row.cost_source] : []))),
158
+ ];
159
+
160
+ const aggregate: RequestLogStepAggregate = {
95
161
  input_tokens: sum("input_tokens"),
96
162
  output_tokens: sum("output_tokens"),
97
163
  cache_read_tokens: sum("cache_read_tokens"),
@@ -101,8 +167,13 @@ function aggregateGenerateStepRows(rows: Array<Record<string, unknown>>): Reques
101
167
  duration_ms: sum("duration_ms"),
102
168
  fallback_count: sum("fallback_count"),
103
169
  cost_usd: sum("cost_usd"),
104
- cost_source: collapse("cost_source"),
105
170
  };
171
+
172
+ if (costSources.length > 0) {
173
+ aggregate.cost_source = costSources.length === 1 ? costSources[0] : "mixed";
174
+ }
175
+
176
+ return aggregate;
106
177
  }
107
178
 
108
179
  type RequestLogUsageRow = {
@@ -126,11 +197,19 @@ function isAnthropicUsageRow(row: Pick<RequestLogUsageRow, "token_name" | "model
126
197
  );
127
198
  }
128
199
 
200
+ /** Provider of a provider-qualified model id (`openai/`, `anthropic/`, `grok/`); legacy ids are unknown. */
201
+ export function providerOfModelName(modelName: string | null | undefined): ProviderId | "unknown" {
202
+ const slash = modelName?.indexOf("/") ?? -1;
203
+ const prefix = slash > 0 ? modelName?.slice(0, slash) : undefined;
204
+
205
+ return isProviderId(prefix) ? prefix : "unknown";
206
+ }
207
+
129
208
  function canonicalModelName(modelName: string): string {
130
209
  return modelName.includes("/") ? modelName.split("/").pop()! : modelName;
131
210
  }
132
211
 
133
- function normalizedUsageForCost(row: RequestLogUsageRow): {
212
+ interface UsageForCost {
134
213
  model: string | null;
135
214
  inputTokens: number;
136
215
  outputTokens: number;
@@ -138,36 +217,47 @@ function normalizedUsageForCost(row: RequestLogUsageRow): {
138
217
  cacheCreationInputTokens: number;
139
218
  cacheCreationInputTokens5m?: number;
140
219
  cacheCreationInputTokens1h?: number;
141
- } {
220
+ }
221
+
222
+ function normalizedUsageForCost(row: RequestLogUsageRow): UsageForCost {
142
223
  const cacheRead = row.cache_read_tokens;
143
224
  const cacheCreation = row.cache_creation_tokens;
144
225
  const storedInput = row.input_tokens;
226
+
145
227
  const legacyAnthropicSplitInput =
146
228
  isAnthropicUsageRow(row) && storedInput < cacheRead + cacheCreation;
147
- return {
229
+
230
+ const usage: UsageForCost = {
148
231
  model: row.model_name ? canonicalModelName(row.model_name) : null,
149
232
  inputTokens: legacyAnthropicSplitInput ? storedInput + cacheRead + cacheCreation : storedInput,
150
233
  outputTokens: row.output_tokens,
151
234
  cachedInputTokens: cacheRead,
152
235
  cacheCreationInputTokens: cacheCreation,
153
- ...(row.cache_creation_5m_tokens !== null && row.cache_creation_5m_tokens !== undefined
154
- ? { cacheCreationInputTokens5m: row.cache_creation_5m_tokens }
155
- : {}),
156
- ...(row.cache_creation_1h_tokens !== null && row.cache_creation_1h_tokens !== undefined
157
- ? { cacheCreationInputTokens1h: row.cache_creation_1h_tokens }
158
- : {}),
159
236
  };
237
+
238
+ if (row.cache_creation_5m_tokens !== null && row.cache_creation_5m_tokens !== undefined) {
239
+ usage.cacheCreationInputTokens5m = row.cache_creation_5m_tokens;
240
+ }
241
+
242
+ if (row.cache_creation_1h_tokens !== null && row.cache_creation_1h_tokens !== undefined) {
243
+ usage.cacheCreationInputTokens1h = row.cache_creation_1h_tokens;
244
+ }
245
+
246
+ return usage;
160
247
  }
161
248
 
162
249
  function normalizeLegacyAnthropicRow<T extends RequestLogUsageRow>(row: T): T {
163
250
  // 새 row 는 당시의 provider/가격표 비용을 확정 저장한다. 현재 가격표로 덮어쓰지 않는다.
164
251
  if (row.cost_source) return row;
165
252
  const usage = normalizedUsageForCost(row);
253
+
166
254
  if (usage.inputTokens === row.input_tokens) return row;
167
255
  const normalized = { ...row, input_tokens: usage.inputTokens };
256
+
168
257
  if (usage.model) {
169
258
  normalized.cost_usd = Math.round(calculateCostUsd(usage.model, usage) * MICRO_USD);
170
259
  }
260
+
171
261
  return normalized;
172
262
  }
173
263
 
@@ -190,20 +280,25 @@ const ORDERABLE_COLUMNS = {
190
280
  cost_usd: "request_logs.cost_usd",
191
281
  } as const;
192
282
 
283
+ const ORDERABLE_COLUMN_BY_KEY = new Map(Object.entries(ORDERABLE_COLUMNS));
284
+
193
285
  function applyOrderBy(
194
286
  qb: ReturnType<RequestLogModelClass["getSubsetQueries"]>["qb"],
195
287
  orderBy: string,
196
288
  ): void {
197
289
  const separator = orderBy.lastIndexOf("-");
198
- const key = orderBy.slice(0, separator) as keyof typeof ORDERABLE_COLUMNS;
290
+ const key = orderBy.slice(0, separator);
199
291
  const direction = orderBy.slice(separator + 1) === "asc" ? "asc" : "desc";
200
- const column = ORDERABLE_COLUMNS[key];
292
+ const column = ORDERABLE_COLUMN_BY_KEY.get(key);
201
293
 
202
294
  if (!column) {
203
295
  qb.orderBy("request_logs.id", "desc");
296
+
204
297
  return;
205
298
  }
299
+
206
300
  qb.orderBy(column, direction);
301
+
207
302
  // 동점 행의 순서가 페이지마다 흔들리지 않게 고유 컬럼으로 tie-break 한다.
208
303
  if (key !== "id") qb.orderBy("request_logs.id", "desc");
209
304
  }
@@ -232,6 +327,7 @@ class RequestLogModelClass extends BaseModelClass<
232
327
  page: 1,
233
328
  queryMode: "list",
234
329
  });
330
+
235
331
  if (!rows[0]) {
236
332
  throw new NotFoundException(SD("error.entityNotFound")("RequestLog", id));
237
333
  }
@@ -332,9 +428,7 @@ class RequestLogModelClass extends BaseModelClass<
332
428
  const wdb = this.getPuri("w");
333
429
 
334
430
  // register
335
- spa.forEach((sp) => {
336
- wdb.ubRegister("request_logs", sp);
337
- });
431
+ for (const sp of spa) wdb.ubRegister("request_logs", sp);
338
432
 
339
433
  // transaction
340
434
  return wdb.transaction(async (trx) => {
@@ -360,7 +454,8 @@ class RequestLogModelClass extends BaseModelClass<
360
454
  }>
361
455
  > {
362
456
  const rdb = this.getPuri("r");
363
- const rows = (await rdb
457
+
458
+ const rows = await rdb
364
459
  .from("request_logs")
365
460
  .select({
366
461
  requested_model_name: "request_logs.requested_model_name",
@@ -368,36 +463,31 @@ class RequestLogModelClass extends BaseModelClass<
368
463
  input_tokens: "request_logs.input_tokens",
369
464
  cache_read_tokens: "request_logs.cache_read_tokens",
370
465
  })
371
- .where("request_logs.created_at", ">=", since)) as unknown as Array<{
372
- requested_model_name: string | null;
373
- status: string;
374
- input_tokens: number;
375
- cache_read_tokens: number;
376
- }>;
466
+ .where("request_logs.created_at", ">=", since);
377
467
 
378
468
  const byProvider = new Map<
379
469
  string,
380
470
  { requests: number; errors: number; inputTokens: number; cacheReadTokens: number }
381
471
  >();
382
- rows.forEach((row) => {
383
- const model = row.requested_model_name ?? "";
384
- const provider = model.startsWith("openai/")
385
- ? "openai"
386
- : model.startsWith("anthropic/")
387
- ? "anthropic"
388
- : "unknown";
472
+
473
+ for (const row of rows) {
474
+ const provider = providerOfModelName(row.requested_model_name);
475
+
389
476
  const agg = byProvider.get(provider) ?? {
390
477
  requests: 0,
391
478
  errors: 0,
392
479
  inputTokens: 0,
393
480
  cacheReadTokens: 0,
394
481
  };
482
+
395
483
  agg.requests += 1;
484
+
396
485
  if (row.status === "error") agg.errors += 1;
397
486
  agg.inputTokens += row.input_tokens;
398
487
  agg.cacheReadTokens += row.cache_read_tokens;
399
488
  byProvider.set(provider, agg);
400
- });
489
+ }
490
+
401
491
  return [...byProvider.entries()]
402
492
  .map(([provider, agg]) => ({ provider, ...agg }))
403
493
  .toSorted((a, b) => a.provider.localeCompare(b.provider));
@@ -415,27 +505,35 @@ class RequestLogModelClass extends BaseModelClass<
415
505
  zod: string | null;
416
506
  }> {
417
507
  const rdb = this.getPuri("r");
418
- const rows = (await rdb
508
+
509
+ const rows = await rdb
419
510
  .from("request_logs")
420
511
  .select({ json_schema: "request_logs.json_schema" })
421
- .where("request_logs.id", id)) as unknown as Array<{ json_schema: string | null }>;
512
+ .where("request_logs.id", id);
513
+
422
514
  const schema = rows[0]?.json_schema;
515
+
423
516
  if (!schema) return { typescript: null, zod: null };
424
517
 
425
- let parsed: unknown;
518
+ let parsed: JsonValue;
519
+
426
520
  try {
521
+ // JSON.parse without a reviver yields only JSON values.
427
522
  parsed = JSON.parse(schema);
428
523
  } catch {
429
524
  return { typescript: null, zod: null };
430
525
  }
526
+
431
527
  let zod: string | null = null;
432
- try {
433
- zod = formatZodCode(
434
- jsonSchemaToZod(parsed as Parameters<typeof jsonSchemaToZod>[0], { module: "none" }),
435
- );
436
- } catch {
437
- zod = null;
528
+
529
+ if (isJsonObject(parsed) || parsed === true || parsed === false) {
530
+ try {
531
+ zod = formatZodCode(jsonSchemaToZod(parsed, { module: "none" }));
532
+ } catch {
533
+ zod = null;
534
+ }
438
535
  }
536
+
439
537
  return { typescript: renderParsedJsonSchemaTypeText(parsed), zod };
440
538
  }
441
539
 
@@ -450,28 +548,38 @@ class RequestLogModelClass extends BaseModelClass<
450
548
  */
451
549
  @api({ httpMethod: "GET", clients: ["axios", "tanstack-query"] })
452
550
  async toolsView(id: number): Promise<ToolView[]> {
453
- const row = (await this.getPuri("r")
551
+ const row = await this.getPuri("r")
454
552
  .from("request_logs")
455
553
  .select({ tools: "request_logs.tools" })
456
554
  .where("request_logs.id", id)
457
- .first()) as { tools: unknown } | undefined;
555
+ .first();
556
+
458
557
  const tools = decodeStoredTools(row?.tools);
558
+
459
559
  if (!tools) return [];
460
560
 
461
561
  return tools.map((tool) => {
462
- const inputSchema = (tool.inputSchema ?? {}) as {
463
- properties?: Record<string, unknown>;
464
- };
465
- const inputZod = renderJsonSchemaZodShapeText(inputSchema, TOOL_ENUM_VALUE_LIMIT);
466
- const fullInputZod = renderJsonSchemaZodShapeText(inputSchema);
562
+ const inputSchema = jsonValueSchema.safeParse(tool.inputSchema ?? {}).data ?? {};
467
563
 
468
- return {
564
+ const inputZod = renderJsonSchemaZodText(inputSchema, TOOL_ENUM_VALUE_LIMIT);
565
+ const fullInputZod = renderJsonSchemaZodText(inputSchema);
566
+
567
+ const properties =
568
+ isJsonObject(inputSchema) && isJsonObject(inputSchema.properties)
569
+ ? inputSchema.properties
570
+ : {};
571
+
572
+ const view: ToolView = {
469
573
  name: tool.name,
470
- ...(tool.description !== undefined ? { description: tool.description } : {}),
471
- parameterCount: Object.keys(inputSchema.properties ?? {}).length,
574
+ parameterCount: Object.keys(properties).length,
472
575
  inputZod,
473
- ...(inputZod !== fullInputZod ? { fullInputZod } : {}),
474
576
  };
577
+
578
+ if (tool.description !== undefined) view.description = tool.description;
579
+
580
+ if (inputZod !== fullInputZod) view.fullInputZod = fullInputZod;
581
+
582
+ return view;
475
583
  });
476
584
  }
477
585
 
@@ -484,7 +592,7 @@ class RequestLogModelClass extends BaseModelClass<
484
592
  effort?: string | null;
485
593
  service_tier?: string | null;
486
594
  project_name?: string | null;
487
- history?: unknown;
595
+ history?: HistoryItems;
488
596
  input_images?: InputImages;
489
597
  tools?: ToolDefinitions;
490
598
  is_image_generation?: boolean;
@@ -492,7 +600,8 @@ class RequestLogModelClass extends BaseModelClass<
492
600
  json_schema?: string | null;
493
601
  }): Promise<number> {
494
602
  const wdb = this.getPuri("w");
495
- wdb.ubRegister("request_logs", {
603
+
604
+ const row: RequestLogRunRow = {
496
605
  user_prompt: params.user_prompt,
497
606
  system_prompt: params.system_prompt ?? null,
498
607
  // provider 실행 전이므로 serving model은 아직 알 수 없다.
@@ -514,60 +623,44 @@ class RequestLogModelClass extends BaseModelClass<
514
623
  json_schema: params.json_schema ?? null,
515
624
  is_structured:
516
625
  params.is_structured ?? (params.json_schema !== null && params.json_schema !== undefined),
517
- ...(params.history !== undefined ? { history: params.history as { type: string }[] } : {}),
518
- ...(params.input_images ? { input_images: params.input_images } : {}),
519
- ...(params.tools !== undefined ? { tools: params.tools } : {}),
520
- });
626
+ };
627
+
628
+ if (params.history !== undefined) row.history = params.history;
629
+
630
+ if (params.input_images) row.input_images = params.input_images;
631
+
632
+ if (params.tools !== undefined) row.tools = params.tools;
633
+ wdb.ubRegister("request_logs", row);
634
+
521
635
  return wdb.transaction(async (trx) => {
522
636
  const ids = await trx.ubUpsert("request_logs");
637
+
523
638
  return ids[0]!;
524
639
  });
525
640
  }
526
641
 
527
- async appendStep(requestLogId: number, step: Record<string, unknown>): Promise<number> {
642
+ async appendStep(requestLogId: number, step: RequestLogStepFields): Promise<number> {
528
643
  const wdb = this.getPuri("w");
529
644
  wdb.ubRegister("request_log_steps", { request_log_id: requestLogId, ...step });
645
+
530
646
  return wdb.transaction(async (trx) => {
531
647
  const ids = await trx.ubUpsert("request_log_steps");
648
+
532
649
  if (step.type === "tool_call") {
533
650
  await trx.from("request_logs").where("id", requestLogId).increment("tool_call_count", 1);
534
651
  }
652
+
535
653
  return ids[0]!;
536
654
  });
537
655
  }
538
656
 
539
- async finishRun(
540
- requestLogId: number,
541
- params: {
542
- status: string;
543
- response?: string;
544
- token_name?: string;
545
- input_tokens?: number;
546
- output_tokens?: number;
547
- cache_read_tokens?: number;
548
- cache_creation_tokens?: number;
549
- cache_creation_5m_tokens?: number | null;
550
- cache_creation_1h_tokens?: number | null;
551
- duration_ms?: number;
552
- requested_model_name?: string | null;
553
- model_name?: string | null;
554
- service_tier?: string | null;
555
- fallback_count?: number | null;
556
- cost_usd?: number | null;
557
- cost_source?: string | null;
558
- history?: unknown;
559
- error_message?: string;
560
- tool_call_count?: number;
561
- image_cost_usd?: number | null;
562
- image_cost_method?: string | null;
563
- is_image_generation?: boolean;
564
- response_json_ok?: boolean | null;
565
- },
566
- ): Promise<void> {
657
+ async finishRun(requestLogId: number, params: FinishRunParams): Promise<void> {
567
658
  if (params.status === "succeeded" && !params.token_name) {
568
659
  throw new Error("tokenName is required for succeeded runs");
569
660
  }
570
- const update: Record<string, unknown> = { id: requestLogId, status: params.status };
661
+
662
+ const update: FinishRunUpdate = { id: requestLogId, status: params.status };
663
+
571
664
  const fields = [
572
665
  "response",
573
666
  "token_name",
@@ -591,9 +684,9 @@ class RequestLogModelClass extends BaseModelClass<
591
684
  "is_image_generation",
592
685
  "response_json_ok",
593
686
  ] as const;
594
- fields.forEach((key) => {
595
- if (params[key] !== undefined) update[key] = params[key];
596
- });
687
+
688
+ for (const key of fields) copyDefined(update, params, key);
689
+
597
690
  if (params.history !== undefined) update.history = params.history;
598
691
  update.ttft_ms = (await this.firstGenerateStepTtft(requestLogId)) ?? 0;
599
692
 
@@ -609,9 +702,12 @@ class RequestLogModelClass extends BaseModelClass<
609
702
  .select({ model_name: "model_name" })
610
703
  .where("id", requestLogId)
611
704
  .first();
705
+
612
706
  const effectiveModelName = params.model_name ?? row?.model_name;
707
+
613
708
  if (effectiveModelName) {
614
709
  const model = canonicalModelName(effectiveModelName);
710
+
615
711
  const usage = normalizedUsageForCost({
616
712
  token_name: params.token_name,
617
713
  model_name: effectiveModelName,
@@ -622,6 +718,7 @@ class RequestLogModelClass extends BaseModelClass<
622
718
  cache_creation_5m_tokens: params.cache_creation_5m_tokens,
623
719
  cache_creation_1h_tokens: params.cache_creation_1h_tokens,
624
720
  });
721
+
625
722
  update.cost_usd = Math.round(
626
723
  calculateCostUsd(model, {
627
724
  inputTokens: usage.inputTokens,
@@ -653,7 +750,8 @@ class RequestLogModelClass extends BaseModelClass<
653
750
  .orderBy("step_index", "asc")
654
751
  .orderBy("id", "asc")
655
752
  .first();
656
- return row?.ttft_ms === null || row?.ttft_ms === undefined ? null : Number(row.ttft_ms);
753
+
754
+ return row?.ttft_ms ?? null;
657
755
  }
658
756
 
659
757
  async aggregateStepUsage(requestLogId: number): Promise<RequestLogStepAggregate> {
@@ -662,7 +760,8 @@ class RequestLogModelClass extends BaseModelClass<
662
760
  .select(STEP_AGGREGATE_SELECT)
663
761
  .where("request_log_id", requestLogId)
664
762
  .where("type", "generate");
665
- return aggregateGenerateStepRows(rows as Array<Record<string, unknown>>);
763
+
764
+ return aggregateGenerateStepRows(rows);
666
765
  }
667
766
 
668
767
  /**
@@ -678,11 +777,13 @@ class RequestLogModelClass extends BaseModelClass<
678
777
  const threshold = new Date(Date.now() - thresholdMs);
679
778
  const candidateIds = await this.findStaleToolWaitingRunCandidates(threshold, limit);
680
779
  const expiredIds: number[] = [];
780
+
681
781
  for (const requestLogId of candidateIds) {
682
782
  if (await this.tryExpireStaleToolWaitingRun(requestLogId, threshold, errorMessage)) {
683
783
  expiredIds.push(requestLogId);
684
784
  }
685
785
  }
786
+
686
787
  return expiredIds;
687
788
  }
688
789
 
@@ -698,6 +799,7 @@ class RequestLogModelClass extends BaseModelClass<
698
799
  .where("request_log_steps.tool_result", null)
699
800
  .where("request_log_steps.error", null)
700
801
  .limit(limit);
802
+
701
803
  return rows.map(({ id }) => id);
702
804
  }
703
805
 
@@ -708,10 +810,12 @@ class RequestLogModelClass extends BaseModelClass<
708
810
  errorMessage: string,
709
811
  ): Promise<boolean> {
710
812
  const wdb = this.getPuri("w");
711
- const lockResult = (await wdb.knex.raw("SELECT pg_try_advisory_xact_lock(?, ?) AS acquired", [
712
- REQUEST_LOG_RUN_LOCK_CLASS_ID,
713
- requestLogId,
714
- ])) as { rows?: Array<{ acquired?: boolean }> };
813
+
814
+ const lockResult = await wdb.knex.raw<{ rows?: Array<{ acquired?: boolean }> }>(
815
+ "SELECT pg_try_advisory_xact_lock(?, ?) AS acquired",
816
+ [REQUEST_LOG_RUN_LOCK_CLASS_ID, requestLogId],
817
+ );
818
+
715
819
  if (lockResult.rows?.[0]?.acquired !== true) return false;
716
820
 
717
821
  // The follow-up path uses the same writer transaction lock. Recheck after
@@ -725,6 +829,7 @@ class RequestLogModelClass extends BaseModelClass<
725
829
  .where("tool_result", null)
726
830
  .where("error", null)
727
831
  .first();
832
+
728
833
  if (!unresolved) return false;
729
834
 
730
835
  const stepRows = await wdb
@@ -732,7 +837,9 @@ class RequestLogModelClass extends BaseModelClass<
732
837
  .select(STEP_AGGREGATE_SELECT)
733
838
  .where("request_log_id", requestLogId)
734
839
  .where("type", "generate");
735
- const aggregate = aggregateGenerateStepRows(stepRows as Array<Record<string, unknown>>);
840
+
841
+ const aggregate = aggregateGenerateStepRows(stepRows);
842
+
736
843
  const firstTtft = await wdb
737
844
  .from("request_log_steps")
738
845
  .select({ ttft_ms: "ttft_ms" })
@@ -743,32 +850,36 @@ class RequestLogModelClass extends BaseModelClass<
743
850
  .orderBy("id", "asc")
744
851
  .first();
745
852
 
853
+ const expiry: Partial<RequestLogSaveParams> = {
854
+ status: "error",
855
+ error_message: errorMessage,
856
+ input_tokens: aggregate.input_tokens,
857
+ output_tokens: aggregate.output_tokens,
858
+ cache_read_tokens: aggregate.cache_read_tokens,
859
+ cache_creation_tokens: aggregate.cache_creation_tokens,
860
+ };
861
+
862
+ if (aggregate.cache_creation_5m_tokens !== undefined) {
863
+ expiry.cache_creation_5m_tokens = aggregate.cache_creation_5m_tokens;
864
+ }
865
+
866
+ if (aggregate.cache_creation_1h_tokens !== undefined) {
867
+ expiry.cache_creation_1h_tokens = aggregate.cache_creation_1h_tokens;
868
+ }
869
+
870
+ expiry.duration_ms = aggregate.duration_ms;
871
+ expiry.fallback_count = aggregate.fallback_count;
872
+ expiry.cost_usd = aggregate.cost_usd;
873
+
874
+ if (aggregate.cost_source !== undefined) expiry.cost_source = aggregate.cost_source;
875
+ expiry.ttft_ms = firstTtft?.ttft_ms ?? 0;
876
+
746
877
  const updated = await wdb
747
878
  .from("request_logs")
748
879
  .where("id", requestLogId)
749
880
  .where("status", "running")
750
- .update({
751
- status: "error",
752
- error_message: errorMessage,
753
- input_tokens: aggregate.input_tokens,
754
- output_tokens: aggregate.output_tokens,
755
- cache_read_tokens: aggregate.cache_read_tokens,
756
- cache_creation_tokens: aggregate.cache_creation_tokens,
757
- ...(aggregate.cache_creation_5m_tokens !== undefined
758
- ? { cache_creation_5m_tokens: aggregate.cache_creation_5m_tokens }
759
- : {}),
760
- ...(aggregate.cache_creation_1h_tokens !== undefined
761
- ? { cache_creation_1h_tokens: aggregate.cache_creation_1h_tokens }
762
- : {}),
763
- duration_ms: aggregate.duration_ms,
764
- fallback_count: aggregate.fallback_count,
765
- cost_usd: aggregate.cost_usd,
766
- ...(aggregate.cost_source !== undefined ? { cost_source: aggregate.cost_source } : {}),
767
- ttft_ms:
768
- firstTtft?.ttft_ms === null || firstTtft?.ttft_ms === undefined
769
- ? 0
770
- : Number(firstTtft.ttft_ms),
771
- });
881
+ .update(expiry);
882
+
772
883
  return updated > 0;
773
884
  }
774
885
 
@@ -792,7 +903,9 @@ class RequestLogModelClass extends BaseModelClass<
792
903
  .select({ status: "status" })
793
904
  .where("id", requestLogId)
794
905
  .first();
906
+
795
907
  if (!run) throw new Error(`request log run ${requestLogId} not found`);
908
+
796
909
  if (run.status !== "running") {
797
910
  throw new Error(`request log run ${requestLogId} is already ${run.status}`);
798
911
  }
@@ -811,6 +924,7 @@ class RequestLogModelClass extends BaseModelClass<
811
924
  .select({ max_step: Puri.max("step_index") })
812
925
  .where("request_log_id", requestLogId)
813
926
  .first();
927
+
814
928
  return (row?.max_step ?? -1) + 1;
815
929
  }
816
930
 
@@ -829,7 +943,7 @@ class RequestLogModelClass extends BaseModelClass<
829
943
  */
830
944
  async totalCost(
831
945
  rawParams: RequestLogListParams = { num: 0, page: 1 },
832
- ): Promise<{ usd: number; unknownImageCostCount: number }> {
946
+ ): Promise<{ usd: number; unknownImageCostCount: number; unknownCostCount: number }> {
833
947
  const params = {
834
948
  num: 0,
835
949
  page: 1,
@@ -839,10 +953,13 @@ class RequestLogModelClass extends BaseModelClass<
839
953
 
840
954
  const { qb: totalQb } = this.getSubsetQueries("C");
841
955
  this.applyListFilters(totalQb, params);
956
+
842
957
  const sonamuFilter = params.sonamuFilter
843
958
  ? normalizeFilterQuery(params.sonamuFilter)
844
959
  : undefined;
960
+
845
961
  this.applySonamuFilters(totalQb, sonamuFilter);
962
+
846
963
  // subset qb 는 컬럼 목록이 이미 SELECT 에 박혀 있어 집계를 얹으면 GROUP BY 에러가 난다.
847
964
  // executeCountQuery 와 같은 방식으로 select 를 비우고 집계만 남긴다.
848
965
  const stored = await totalQb
@@ -855,12 +972,14 @@ class RequestLogModelClass extends BaseModelClass<
855
972
  unknownImageCostCount: Puri.rawNumber(
856
973
  "COUNT(*) FILTER (WHERE request_logs.is_image_generation = true AND request_logs.image_cost_usd IS NULL)",
857
974
  ),
975
+ unknownCostCount: Puri.rawNumber(`COUNT(*) FILTER (WHERE ${UNKNOWN_MEDIA_COST_PREDICATE})`),
858
976
  })
859
977
  .first();
860
978
 
861
979
  const { qb: legacyQb } = this.getSubsetQueries("C");
862
980
  this.applyListFilters(legacyQb, params);
863
981
  this.applySonamuFilters(legacyQb, sonamuFilter);
982
+
864
983
  const legacyRows = await legacyQb
865
984
  .whereRaw("request_logs.cost_source IS NULL OR request_logs.cost_usd IS NULL")
866
985
  .clear("select")
@@ -876,13 +995,17 @@ class RequestLogModelClass extends BaseModelClass<
876
995
  cost_usd: "request_logs.cost_usd",
877
996
  });
878
997
 
879
- const storedTotal = Number(stored?.total ?? 0) / MICRO_USD;
998
+ // Postgres returns SUM/COUNT as bigint, which node-postgres delivers as text
999
+ // even though `Puri.rawNumber` types it as number.
1000
+ const storedTotal = bigintAggregate.parse(stored?.total ?? 0) / MICRO_USD;
880
1001
 
881
1002
  // legacy row 는 위 SUM 에 저장값으로 이미 포함되어 있다. 재계산값과의 차액만 더한다.
882
1003
  const usd = legacyRows.reduce((sum, row) => {
883
1004
  const alreadySummed = Math.max(row.cost_usd ?? 0, 0) / MICRO_USD;
884
1005
  const usage = normalizedUsageForCost(row);
1006
+
885
1007
  if (!usage.model) return sum;
1008
+
886
1009
  return (
887
1010
  sum +
888
1011
  calculateCostUsd(usage.model, {
@@ -896,7 +1019,12 @@ class RequestLogModelClass extends BaseModelClass<
896
1019
  alreadySummed
897
1020
  );
898
1021
  }, storedTotal);
899
- return { usd, unknownImageCostCount: Number(stored?.unknownImageCostCount ?? 0) };
1022
+
1023
+ return {
1024
+ usd,
1025
+ unknownImageCostCount: bigintAggregate.parse(stored?.unknownImageCostCount ?? 0),
1026
+ unknownCostCount: bigintAggregate.parse(stored?.unknownCostCount ?? 0),
1027
+ };
900
1028
  }
901
1029
 
902
1030
  async distinctProjectNames(): Promise<string[]> {
@@ -908,6 +1036,7 @@ class RequestLogModelClass extends BaseModelClass<
908
1036
  .select({
909
1037
  project_name: "project_name",
910
1038
  });
1039
+
911
1040
  return rows.map((r) => r.project_name!);
912
1041
  }
913
1042
 
@@ -920,6 +1049,7 @@ class RequestLogModelClass extends BaseModelClass<
920
1049
  .select({
921
1050
  model_name: "model_name",
922
1051
  });
1052
+
923
1053
  return rows.map((r) => r.model_name!);
924
1054
  }
925
1055
 
@@ -933,6 +1063,7 @@ class RequestLogModelClass extends BaseModelClass<
933
1063
  .table("request_log_steps")
934
1064
  .whereIn("request_log_steps.request_log_id", ids)
935
1065
  .delete();
1066
+
936
1067
  return trx.table("request_logs").whereIn("request_logs.id", ids).delete();
937
1068
  });
938
1069