@cartanova/qgrid-cli 2.10.5 → 2.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/bundle/dist/application/monit/monit.frame.js +1 -1
  2. package/bundle/dist/application/qgrid/expired-token-reminder.js +1 -1
  3. package/bundle/dist/application/qgrid/oauth.js +1 -1
  4. package/bundle/dist/application/qgrid/qgrid-image-generation.js +7 -11
  5. package/bundle/dist/application/qgrid/qgrid-response-format.js +4 -4
  6. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +26 -7
  7. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +12 -7
  8. package/bundle/dist/application/qgrid/qgrid.frame.js +24 -10
  9. package/bundle/dist/application/qgrid/token-death.js +1 -1
  10. package/bundle/dist/application/qgrid/token-window-keepalive.js +1 -1
  11. package/bundle/dist/application/qgrid/tool-emulation.js +1 -1
  12. package/bundle/dist/application/request-log/request-log.model.js +5 -3
  13. package/bundle/dist/application/sonamu.generated.js +4 -1
  14. package/bundle/dist/application/sonamu.generated.sso.js +3 -1
  15. package/bundle/dist/i18n/sd.generated.js +4 -3
  16. package/bundle/dist/migrations/20261016155350_alter_request_logs_add1_alter1.js +15 -0
  17. package/bundle/dist/sonamu.config.js +2 -2
  18. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +1 -1
  19. package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
  20. package/bundle/dist/utils/providers/common/model-cost.js +14 -3
  21. package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +13 -2
  22. package/bundle/dist/utils/providers/openai/openai-direct-client.js +5 -4
  23. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +111 -57
  24. package/bundle/dist/utils/providers/openai/openai-image-generation.js +25 -17
  25. package/bundle/dist/utils/providers/openai/openai-refresh.js +1 -1
  26. package/bundle/src/application/qgrid/qgrid-image-generation.test.ts +19 -8
  27. package/bundle/src/application/qgrid/qgrid-image-generation.ts +17 -24
  28. package/bundle/src/application/qgrid/qgrid-response-format.test.ts +4 -2
  29. package/bundle/src/application/qgrid/qgrid-response-format.ts +7 -10
  30. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +105 -9
  31. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +47 -5
  32. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +160 -2
  33. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +40 -18
  34. package/bundle/src/application/qgrid/qgrid.frame.test.ts +74 -0
  35. package/bundle/src/application/qgrid/qgrid.frame.ts +39 -4
  36. package/bundle/src/application/request-log/request-log.entity.json +11 -2
  37. package/bundle/src/application/request-log/request-log.model.ts +4 -0
  38. package/bundle/src/application/sonamu.generated.http +2 -2
  39. package/bundle/src/application/sonamu.generated.sso.ts +2 -0
  40. package/bundle/src/application/sonamu.generated.ts +4 -0
  41. package/bundle/src/i18n/sd.generated.ts +3 -2
  42. package/bundle/src/migrations/20261016155350_alter_request_logs_add1_alter1.ts +15 -0
  43. package/bundle/src/utils/providers/common/model-cost.test.ts +28 -0
  44. package/bundle/src/utils/providers/common/model-cost.ts +19 -2
  45. package/bundle/src/utils/providers/openai/openai-backend-protocol.test.ts +23 -1
  46. package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +24 -2
  47. package/bundle/src/utils/providers/openai/openai-direct-client.test.ts +15 -0
  48. package/bundle/src/utils/providers/openai/openai-direct-client.ts +14 -4
  49. package/bundle/src/utils/providers/openai/openai-dispatcher.test.ts +223 -32
  50. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +174 -72
  51. package/bundle/src/utils/providers/openai/openai-image-generation.test.ts +89 -0
  52. package/bundle/src/utils/providers/openai/openai-image-generation.ts +26 -15
  53. package/bundle/web-dist/client/assets/cost-DH2jZbrw.js +1 -0
  54. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +1 -0
  55. package/bundle/web-dist/client/assets/{index-Dxw7DiXF.js → index-CwqqPF4F.js} +4 -4
  56. package/bundle/web-dist/client/assets/logs-CZgl1RSu.js +1 -0
  57. package/bundle/web-dist/client/assets/{monit-E8eGW1Sj.js → monit-TarvUWiE.js} +1 -1
  58. package/bundle/web-dist/client/assets/request-model-CojtinqK.js +1 -0
  59. package/bundle/web-dist/client/assets/{routes-7spLfIGZ.js → routes-BXR6OLah.js} +2 -2
  60. package/bundle/web-dist/client/assets/{services.generated-jnPHYMER.js → services.generated-BsieU37H.js} +1 -1
  61. package/bundle/web-dist/client/assets/{settings-BdosZFNC.js → settings-B1y5MNSU.js} +1 -1
  62. package/bundle/web-dist/client/assets/show-CG-BAdhS.js +2 -0
  63. package/bundle/web-dist/client/assets/{tokens-CBdHb2_U.js → tokens-D9tAWBEW.js} +1 -1
  64. package/bundle/web-dist/client/assets/{use-oauth-login-flow-Cyn3YPqW.js → use-oauth-login-flow-DxdOhz4a.js} +1 -1
  65. package/bundle/web-dist/client/assets/{use-update-token-mutation-DQCwCYfR.js → use-update-token-mutation-DAq0F8p-.js} +1 -1
  66. package/bundle/web-dist/client/index.html +3 -3
  67. package/bundle/web-dist/server/assets/{cost-59jBdx-I.js → cost-eEHeTRT5.js} +4 -5
  68. package/bundle/web-dist/server/assets/{lazyRouteComponent-CUR-kWzI.js → lazyRouteComponent-Dtd0NR4r.js} +2 -2
  69. package/bundle/web-dist/server/assets/{logs-CaaWO9-Z.js → logs-l91avYif.js} +33 -21
  70. package/bundle/web-dist/server/assets/{monit-CBil92fJ.js → monit-DvzribSE.js} +4 -4
  71. package/bundle/web-dist/server/assets/{plus-Bvdj8Pwx.js → plus-KZrECewT.js} +1 -1
  72. package/bundle/web-dist/server/assets/{react-dom-CyuShs9K.js → react-dom-B4a6-uuR.js} +1 -1
  73. package/bundle/web-dist/server/assets/{refresh-cw-3QAiSWBd.js → refresh-cw-BND93JrF.js} +1 -1
  74. package/bundle/web-dist/server/assets/{request-model-CnCeaNLE.js → request-model-CbqfnQOJ.js} +19 -1
  75. package/bundle/web-dist/server/assets/{routes-DtVf9yqo.js → routes-BAPWTizT.js} +6 -7
  76. package/bundle/web-dist/server/assets/{services.generated-FPwsG9p3.js → services.generated-CEbGjsI0.js} +3 -2
  77. package/bundle/web-dist/server/assets/{settings-DeHNwoMv.js → settings-BZR5HSAL.js} +3 -3
  78. package/bundle/web-dist/server/assets/{show-8NNdRxhM.js → show-CxVZTAdv.js} +17 -21
  79. package/bundle/web-dist/server/assets/{tokens-odgS2-9q.js → tokens-D1hb4eKk.js} +4 -4
  80. package/bundle/web-dist/server/assets/{use-oauth-login-flow-DTQKdYBO.js → use-oauth-login-flow-Cvdy0zF8.js} +1 -1
  81. package/bundle/web-dist/server/assets/{use-update-token-mutation-xvXbPrCI.js → use-update-token-mutation-CfYmk_4_.js} +1 -1
  82. package/bundle/web-dist/server/entry-server.generated.js +13 -10
  83. package/package.json +1 -1
  84. package/skills/qgrid/SKILL.md +9 -8
  85. package/skills/qgrid/references/ai-sdk-provider-contract.md +27 -17
  86. package/skills/qgrid/references/decision-rationale.md +8 -8
  87. package/skills/qgrid/references/openai-codex-runtime.md +19 -11
  88. package/skills/qgrid/references/prompt-cache-and-usage.md +3 -0
  89. package/skills/qgrid/references/request-log-run-lifecycle.md +14 -2
  90. package/skills/qgrid/references/sonamu-api-web-flow.md +2 -2
  91. package/skills/qgrid/references/verification-and-debugging.md +23 -9
  92. package/bundle/web-dist/client/assets/cost-CY2BJEPC.js +0 -1
  93. package/bundle/web-dist/client/assets/index-CvG4UB9v.css +0 -1
  94. package/bundle/web-dist/client/assets/logs-3n_U4qnI.js +0 -1
  95. package/bundle/web-dist/client/assets/request-model-D4CZPmnG.js +0 -1
  96. package/bundle/web-dist/client/assets/show-b2PFNI3D.js +0 -2
@@ -1 +1 @@
1
- import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{y as t}from"./vendor-tanstack-DJRQAbrY.js";import{i as n,r}from"./vendor-react-DH4kUfK2.js";import{n as i,o as a}from"./services.generated-jnPHYMER.js";import{o}from"./index-Dxw7DiXF.js";var s=e(n(),1),c=r();function l({provider:e,isPending:t,isError:n,onSubmit:r,onRestart:i}){let[a,l]=(0,s.useState)(``),u=e===`openai`;return(0,c.jsxs)(`div`,{className:`space-y-2`,children:[(0,c.jsx)(`p`,{className:`text-[12px] text-sand-600 leading-relaxed`,children:u?`새 탭에서 OpenAI 로그인을 완료한 뒤 연결 실패 화면이 나타나면, 주소창의 전체 URL을 아래에 붙여넣으세요.`:`새 탭에서 Claude 로그인을 완료하면 코드가 표시됩니다. 코드 전체를 아래에 붙여넣으세요.`}),(0,c.jsx)(o,{value:a,onChange:e=>l(e.target.value),placeholder:u?`http://localhost:1455/auth/callback?code=...&state=...`:`code#state`,className:`w-full border border-sand-200 rounded-md px-3 py-2 text-sm font-mono text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`}),n&&(0,c.jsx)(`p`,{className:`text-[11px] text-red-500`,children:`인증 결과 확인에 실패했습니다 — 전체 값을 다시 붙여넣거나 로그인을 다시 시작하세요.`}),(0,c.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md bg-sand-900 text-white hover:bg-sand-800 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!a.trim()||t,onClick:()=>r(a),children:t?(0,c.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,c.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin`}),`Verifying...`]}):`Complete login`}),(0,c.jsx)(`button`,{type:`button`,className:`w-full py-1.5 text-[12px] text-sand-500 hover:text-sand-700 transition-colors duration-150`,onClick:()=>{l(``),i()},children:`처음부터 다시 시작`})]})}var u=3e3,d=3e5;async function f(e,t){let{rows:n}=await a.getTokens(`A`,{num:0,queryMode:`list`});return new Set(n.filter(n=>n.provider===e&&n.name===t).map(e=>e.id))}function p(){let[e,n]=(0,s.useState)(null),[r,a]=(0,s.useState)(null),o=t(),c=i.useOauthStartMutation(),l=i.useOauthStartOpenAIMutation(),p=i.useOauthCompleteMutation(),m=(0,s.useRef)({}),h=(0,s.useRef)(0),g=()=>{h.current+=1,m.current.interval!==void 0&&clearInterval(m.current.interval),m.current.timeout!==void 0&&clearTimeout(m.current.timeout),m.current={}};(0,s.useEffect)(()=>g,[]);let _=()=>Promise.all([o.invalidateQueries({queryKey:[`Token`]}),o.invalidateQueries({queryKey:[`Qgrid`]})]);return{loadingProvider:e,codeEntryProvider:r,start:async(e,t)=>{let r=t.trim();if(!r)return;g();let i=h.current,o=window.open(`about:blank`,`_blank`);n(e);try{if(e===`openai`){let t=await f(e,r);if(i!==h.current){o?.close();return}let{authUrl:s,mode:c}=await l.mutateAsync({name:r});if(i!==h.current){o?.close();return}if(o?o.location.href=s:window.open(s,`_blank`),c===`code`){a(e),n(null);return}m.current.interval=window.setInterval(()=>{f(e,r).then(e=>{i===h.current&&[...e].some(e=>!t.has(e))&&(g(),n(null),_())}).catch(()=>{})},u),m.current.timeout=window.setTimeout(()=>{i===h.current&&(g(),n(null))},d);return}let{authUrl:t,mode:s}=await c.mutateAsync({name:r});if(i!==h.current){o?.close();return}s===`code`?(o?o.location.href=t:window.open(t,`_blank`),a(e),n(null)):(o?.close(),window.location.href=t)}catch(e){if(o?.close(),i!==h.current)return;console.error(`OAuth start failed:`,e),n(null)}},submitCode:async e=>{let t=e.trim();if(!t)return!1;try{await p.mutateAsync({pastedCode:t})}catch(e){return console.error(`OAuth complete failed:`,e),!1}return await _(),!0},reset:()=>{g(),n(null),a(null),p.reset()},completeMutation:p}}export{l as n,p as t};
1
+ import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{y as t}from"./vendor-tanstack-DJRQAbrY.js";import{i as n,r}from"./vendor-react-DH4kUfK2.js";import{n as i,o as a}from"./services.generated-BsieU37H.js";import{o}from"./index-CwqqPF4F.js";var s=e(n(),1),c=r();function l({provider:e,isPending:t,isError:n,onSubmit:r,onRestart:i}){let[a,l]=(0,s.useState)(``),u=e===`openai`;return(0,c.jsxs)(`div`,{className:`space-y-2`,children:[(0,c.jsx)(`p`,{className:`text-[12px] text-sand-600 leading-relaxed`,children:u?`새 탭에서 OpenAI 로그인을 완료한 뒤 연결 실패 화면이 나타나면, 주소창의 전체 URL을 아래에 붙여넣으세요.`:`새 탭에서 Claude 로그인을 완료하면 코드가 표시됩니다. 코드 전체를 아래에 붙여넣으세요.`}),(0,c.jsx)(o,{value:a,onChange:e=>l(e.target.value),placeholder:u?`http://localhost:1455/auth/callback?code=...&state=...`:`code#state`,className:`w-full border border-sand-200 rounded-md px-3 py-2 text-sm font-mono text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`}),n&&(0,c.jsx)(`p`,{className:`text-[11px] text-red-500`,children:`인증 결과 확인에 실패했습니다 — 전체 값을 다시 붙여넣거나 로그인을 다시 시작하세요.`}),(0,c.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md bg-sand-900 text-white hover:bg-sand-800 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!a.trim()||t,onClick:()=>r(a),children:t?(0,c.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,c.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin`}),`Verifying...`]}):`Complete login`}),(0,c.jsx)(`button`,{type:`button`,className:`w-full py-1.5 text-[12px] text-sand-500 hover:text-sand-700 transition-colors duration-150`,onClick:()=>{l(``),i()},children:`처음부터 다시 시작`})]})}var u=3e3,d=3e5;async function f(e,t){let{rows:n}=await a.getTokens(`A`,{num:0,queryMode:`list`});return new Set(n.filter(n=>n.provider===e&&n.name===t).map(e=>e.id))}function p(){let[e,n]=(0,s.useState)(null),[r,a]=(0,s.useState)(null),o=t(),c=i.useOauthStartMutation(),l=i.useOauthStartOpenAIMutation(),p=i.useOauthCompleteMutation(),m=(0,s.useRef)({}),h=(0,s.useRef)(0),g=()=>{h.current+=1,m.current.interval!==void 0&&clearInterval(m.current.interval),m.current.timeout!==void 0&&clearTimeout(m.current.timeout),m.current={}};(0,s.useEffect)(()=>g,[]);let _=()=>Promise.all([o.invalidateQueries({queryKey:[`Token`]}),o.invalidateQueries({queryKey:[`Qgrid`]})]);return{loadingProvider:e,codeEntryProvider:r,start:async(e,t)=>{let r=t.trim();if(!r)return;g();let i=h.current,o=window.open(`about:blank`,`_blank`);n(e);try{if(e===`openai`){let t=await f(e,r);if(i!==h.current){o?.close();return}let{authUrl:s,mode:c}=await l.mutateAsync({name:r});if(i!==h.current){o?.close();return}if(o?o.location.href=s:window.open(s,`_blank`),c===`code`){a(e),n(null);return}m.current.interval=window.setInterval(()=>{f(e,r).then(e=>{i===h.current&&[...e].some(e=>!t.has(e))&&(g(),n(null),_())}).catch(()=>{})},u),m.current.timeout=window.setTimeout(()=>{i===h.current&&(g(),n(null))},d);return}let{authUrl:t,mode:s}=await c.mutateAsync({name:r});if(i!==h.current){o?.close();return}s===`code`?(o?o.location.href=t:window.open(t,`_blank`),a(e),n(null)):(o?.close(),window.location.href=t)}catch(e){if(o?.close(),i!==h.current)return;console.error(`OAuth start failed:`,e),n(null)}},submitCode:async e=>{let t=e.trim();if(!t)return!1;try{await p.mutateAsync({pastedCode:t})}catch(e){return console.error(`OAuth complete failed:`,e),!1}return await _(),!0},reset:()=>{g(),n(null),a(null),p.reset()},completeMutation:p}}export{l as n,p as t};
@@ -1 +1 @@
1
- import{m as e}from"./vendor-tanstack-DJRQAbrY.js";import{n as t}from"./services.generated-jnPHYMER.js";function n(){return e({mutationFn:({id:e,name:n,quotaThreshold:r,weight:i,keepaliveEnabled:a})=>t.updateToken(e,n,r,i,a)})}export{n as t};
1
+ import{m as e}from"./vendor-tanstack-DJRQAbrY.js";import{n as t}from"./services.generated-BsieU37H.js";function n(){return e({mutationFn:({id:e,name:n,quotaThreshold:r,weight:i,keepaliveEnabled:a})=>t.updateToken(e,n,r,i,a)})}export{n as t};
@@ -5,13 +5,13 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/sonamu.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Qgrid</title>
8
- <script type="module" crossorigin src="/assets/index-Dxw7DiXF.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-CwqqPF4F.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-Dw2cE7zH.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-ca-nBW7U.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-DH4kUfK2.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/vendor-tanstack-DJRQAbrY.js">
13
- <link rel="modulepreload" crossorigin href="/assets/services.generated-jnPHYMER.js">
14
- <link rel="stylesheet" crossorigin href="/assets/index-CvG4UB9v.css">
13
+ <link rel="modulepreload" crossorigin href="/assets/services.generated-BsieU37H.js">
14
+ <link rel="stylesheet" crossorigin href="/assets/index-Bw2s88Ot.css">
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
@@ -4,16 +4,15 @@ var COST_DECIMALS = 4;
4
4
  function microUsdToUsd(microUsd) {
5
5
  return microUsd / MICRO_USD;
6
6
  }
7
- function formatUsd(usd, partial = false) {
8
- return `${partial ? "Known " : ""}$${usd.toFixed(COST_DECIMALS)}`;
7
+ function formatUsd(usd) {
8
+ return `$${usd.toFixed(COST_DECIMALS)}`;
9
9
  }
10
10
  function formatMicroUsd(microUsd) {
11
11
  return formatUsd(microUsdToUsd(microUsd));
12
12
  }
13
13
  function formatRequestCost(row) {
14
- const partial = row.is_image_generation && row.image_cost_usd === null;
15
- if (row.cost_usd === null && row.image_cost_usd === null) return partial ? "Unknown" : "—";
16
- return formatUsd(microUsdToUsd((row.cost_usd ?? 0) + (row.image_cost_usd ?? 0)), partial);
14
+ if (row.cost_usd === null && row.image_cost_usd === null) return "—";
15
+ return formatUsd(microUsdToUsd((row.cost_usd ?? 0) + (row.image_cost_usd ?? 0)));
17
16
  }
18
17
  /**
19
18
  * prompt cache 적중률. input_tokens 는 cache_read 를 포함한 전체 입력 토큰(OpenAI/codex 표준,
@@ -1,5 +1,5 @@
1
- import { A as require_react, X as __toESM, k as require_jsx_runtime, q as __commonJSMin } from "./services.generated-FPwsG9p3.js";
2
- import { n as require_shim, t as require_react_dom } from "./react-dom-CyuShs9K.js";
1
+ import { A as require_react, X as __toESM, k as require_jsx_runtime, q as __commonJSMin } from "./services.generated-CEbGjsI0.js";
2
+ import { n as require_shim, t as require_react_dom } from "./react-dom-B4a6-uuR.js";
3
3
  //#region ../../node_modules/.pnpm/@tanstack+router-core@1.143.6/node_modules/@tanstack/router-core/dist/esm/utils.js
4
4
  function last(arr) {
5
5
  return arr[arr.length - 1];
@@ -1,9 +1,9 @@
1
- import { A as require_react, S as string, k as require_jsx_runtime, n as QgridService, o as TokenService, r as RequestLogService, x as object } from "./services.generated-FPwsG9p3.js";
2
- import { a as Link, o as useNavigate } from "./lazyRouteComponent-CUR-kWzI.js";
1
+ import { A as require_react, S as string, k as require_jsx_runtime, n as QgridService, o as TokenService, r as RequestLogService, x as object } from "./services.generated-CEbGjsI0.js";
2
+ import { a as Link, o as useNavigate } from "./lazyRouteComponent-Dtd0NR4r.js";
3
3
  import { i as RequestLogOrderBy, n as Route, r as RequestLogBaseListParams } from "../entry-server.generated.js";
4
- import { i as formatUsd, r as formatRequestCost, t as cacheHitRate } from "./cost-59jBdx-I.js";
5
- import { t as lucideRefreshCw } from "./refresh-cw-3QAiSWBd.js";
6
- import { t as requestModelDisplay } from "./request-model-CnCeaNLE.js";
4
+ import { i as formatUsd, r as formatRequestCost, t as cacheHitRate } from "./cost-eEHeTRT5.js";
5
+ import { t as lucideRefreshCw } from "./refresh-cw-BND93JrF.js";
6
+ import { n as lucideZap, t as requestModelDisplay } from "./request-model-CbqfnQOJ.js";
7
7
  require_react();
8
8
  var import_jsx_runtime = require_jsx_runtime();
9
9
  var lucideChevronLeft = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
@@ -164,7 +164,7 @@ var COLUMNS = [
164
164
  width: "w-14"
165
165
  },
166
166
  {
167
- label: "Cost",
167
+ label: "$",
168
168
  align: "right",
169
169
  width: "w-20",
170
170
  sortKey: "cost_usd"
@@ -287,8 +287,7 @@ function RequestLogTable({ search, onSearchChange }) {
287
287
  children: "Failed to load total cost."
288
288
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
289
289
  className: "text-[11px] tabular-nums font-medium text-sienna-600",
290
- title: costData && costData.unknownImageCostCount > 0 ? `${costData.unknownImageCostCount} image requests have unknown image costs. Only known costs are included.` : void 0,
291
- children: costData ? formatUsd(costData.usd, costData.unknownImageCostCount > 0) : "—"
290
+ children: costData ? formatUsd(costData.usd) : "—"
292
291
  })
293
292
  ]
294
293
  }), isError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
@@ -371,21 +370,35 @@ function RequestLogTable({ search, onSearchChange }) {
371
370
  }),
372
371
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", {
373
372
  className: "px-4 py-1.5 whitespace-nowrap",
374
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RequestModel, {
375
- status: row.status,
376
- requestedModel: row.requested_model_name,
377
- servedModel: row.model_name,
378
- imageCostMethod: row.image_cost_method,
379
- fallbackCount: row.fallback_count
380
- }), row.response_json_ok === false && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
381
- title: "structured 요청의 응답이 JSON 파싱에 실패했습니다",
382
- className: "ml-1.5 rounded-full bg-caution-400/15 px-1.5 py-0.5 text-[9px] font-semibold text-caution-500",
383
- children: "broken"
384
- })]
373
+ children: [
374
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RequestModel, {
375
+ status: row.status,
376
+ requestedModel: row.requested_model_name,
377
+ servedModel: row.model_name,
378
+ imageCostMethod: row.image_cost_method,
379
+ fallbackCount: row.fallback_count
380
+ }),
381
+ row.service_tier === "fast" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
382
+ title: "Fast 모드",
383
+ className: "ml-1 inline-flex align-middle",
384
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(lucideZap, {
385
+ "aria-label": "Fast 모드",
386
+ className: "size-3 text-[#1877F2] [&_path]:fill-current"
387
+ })
388
+ }),
389
+ row.response_json_ok === false && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
390
+ title: "structured 요청의 응답이 JSON 파싱에 실패했습니다",
391
+ className: "ml-1.5 rounded-full bg-caution-400/15 px-1.5 py-0.5 text-[9px] font-semibold text-caution-500",
392
+ children: "broken"
393
+ })
394
+ ]
385
395
  }),
386
396
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
387
397
  className: "px-4 py-1.5 whitespace-nowrap",
388
- children: row.is_structured ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
398
+ children: row.is_image_generation ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
399
+ className: "rounded bg-sage-100 px-1.5 py-0.5 font-mono text-[10px] text-sage-700",
400
+ children: "img"
401
+ }) : row.is_structured ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
389
402
  className: "rounded bg-sienna-100 px-1.5 py-0.5 font-mono text-[10px] text-sienna-700",
390
403
  children: "json"
391
404
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
@@ -427,7 +440,6 @@ function RequestLogTable({ search, onSearchChange }) {
427
440
  }),
428
441
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
429
442
  className: "px-3 py-1.5 text-right tabular-nums text-sand-700 whitespace-nowrap",
430
- title: row.is_image_generation && row.image_cost_usd === null ? "Image cost is unknown. Only known costs are shown." : void 0,
431
443
  children: formatRequestCost(row)
432
444
  }),
433
445
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
@@ -1,8 +1,8 @@
1
- import { A as require_react, E as useQuery, X as __toESM, k as require_jsx_runtime, m as _enum, t as MonitService, x as object } from "./services.generated-FPwsG9p3.js";
2
- import { t as require_react_dom } from "./react-dom-CyuShs9K.js";
1
+ import { A as require_react, E as useQuery, X as __toESM, k as require_jsx_runtime, m as _enum, t as MonitService, x as object } from "./services.generated-CEbGjsI0.js";
2
+ import { t as require_react_dom } from "./react-dom-B4a6-uuR.js";
3
3
  import { a as Route, s as clsx } from "../entry-server.generated.js";
4
- import { t as cacheHitRate } from "./cost-59jBdx-I.js";
5
- import { t as lucideRefreshCw } from "./refresh-cw-3QAiSWBd.js";
4
+ import { t as cacheHitRate } from "./cost-eEHeTRT5.js";
5
+ import { t as lucideRefreshCw } from "./refresh-cw-BND93JrF.js";
6
6
  //#region ../../node_modules/.pnpm/@tanstack+virtual-core@3.17.4/node_modules/@tanstack/virtual-core/dist/esm/lazy-measurements.js
7
7
  var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
8
8
  var import_react_dom = /* @__PURE__ */ __toESM(require_react_dom(), 1);
@@ -1,4 +1,4 @@
1
- import { A as require_react, k as require_jsx_runtime } from "./services.generated-FPwsG9p3.js";
1
+ import { A as require_react, k as require_jsx_runtime } from "./services.generated-CEbGjsI0.js";
2
2
  require_react();
3
3
  var import_jsx_runtime = require_jsx_runtime();
4
4
  var lucidePlus = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
@@ -1,4 +1,4 @@
1
- import { A as require_react, q as __commonJSMin } from "./services.generated-FPwsG9p3.js";
1
+ import { A as require_react, q as __commonJSMin } from "./services.generated-CEbGjsI0.js";
2
2
  //#region ../../node_modules/.pnpm/use-sync-external-store@1.6.0_react@19.2.4/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js
3
3
  /**
4
4
  * @license React
@@ -1,4 +1,4 @@
1
- import { A as require_react, k as require_jsx_runtime } from "./services.generated-FPwsG9p3.js";
1
+ import { A as require_react, k as require_jsx_runtime } from "./services.generated-CEbGjsI0.js";
2
2
  require_react();
3
3
  var import_jsx_runtime = require_jsx_runtime();
4
4
  var lucideRefreshCw = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
@@ -1,3 +1,21 @@
1
+ import { A as require_react, k as require_jsx_runtime } from "./services.generated-CEbGjsI0.js";
2
+ require_react();
3
+ var import_jsx_runtime = require_jsx_runtime();
4
+ var lucideZap = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
5
+ viewBox: "0 0 24 24",
6
+ width: "1.2em",
7
+ height: "1.2em",
8
+ ...props,
9
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
10
+ fill: "none",
11
+ stroke: "currentColor",
12
+ strokeLinecap: "round",
13
+ strokeLinejoin: "round",
14
+ strokeWidth: 2,
15
+ d: "M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"
16
+ })
17
+ });
18
+ //#endregion
1
19
  //#region src/lib/request-model.ts
2
20
  function requestModelDisplay({ status, requestedModel, servedModel, imageCostMethod }) {
3
21
  if (status === "running") return { label: "실행 중" };
@@ -10,4 +28,4 @@ function requestModelDisplay({ status, requestedModel, servedModel, imageCostMet
10
28
  return { label: requestedModel && servedModel && requestedModel !== servedModel ? `${requestedModel} → ${servedModel}` : servedModel ?? requestedModel ?? "—" };
11
29
  }
12
30
  //#endregion
13
- export { requestModelDisplay as t };
31
+ export { lucideZap as n, requestModelDisplay as t };
@@ -1,9 +1,9 @@
1
- import { A as require_react, O as useQueryClient, X as __toESM, k as require_jsx_runtime, n as QgridService, o as TokenService } from "./services.generated-FPwsG9p3.js";
2
- import { t as require_react_dom } from "./react-dom-CyuShs9K.js";
1
+ import { A as require_react, O as useQueryClient, X as __toESM, k as require_jsx_runtime, n as QgridService, o as TokenService } from "./services.generated-CEbGjsI0.js";
2
+ import { t as require_react_dom } from "./react-dom-B4a6-uuR.js";
3
3
  import { o as Q } from "../entry-server.generated.js";
4
- import { i as formatUsd } from "./cost-59jBdx-I.js";
5
- import { t as useUpdateTokenMutation } from "./use-update-token-mutation-xvXbPrCI.js";
6
- import { n as OAuthCodeEntry, t as useOAuthLoginFlow } from "./use-oauth-login-flow-DTQKdYBO.js";
4
+ import { i as formatUsd } from "./cost-eEHeTRT5.js";
5
+ import { t as useUpdateTokenMutation } from "./use-update-token-mutation-CfYmk_4_.js";
6
+ import { n as OAuthCodeEntry, t as useOAuthLoginFlow } from "./use-oauth-login-flow-Cvdy0zF8.js";
7
7
  //#region ../../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@19.2.4/node_modules/@dnd-kit/utilities/dist/utilities.esm.js
8
8
  var import_react_dom = /* @__PURE__ */ __toESM(require_react_dom());
9
9
  var import_react = /* @__PURE__ */ __toESM(require_react());
@@ -2792,8 +2792,7 @@ function SortableTokenCard({ token }) {
2792
2792
  })]
2793
2793
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2794
2794
  className: `text-[11px] tabular-nums font-medium shrink-0 ${theme.cost}`,
2795
- title: costData && costData.unknownImageCostCount > 0 ? `이미지 비용을 알 수 없는 요청 ${costData.unknownImageCostCount}건이 있습니다. 확인된 비용만 포함합니다.` : "이 토큰의 누적 비용",
2796
- children: formatUsd(costData?.usd ?? 0, (costData?.unknownImageCostCount ?? 0) > 0)
2795
+ children: formatUsd(costData?.usd ?? 0)
2797
2796
  })]
2798
2797
  }),
2799
2798
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -22565,8 +22565,9 @@ var entityLabels = {
22565
22565
  "entity.RequestLog.ttft_ms": "first gen TTFT(ms)",
22566
22566
  "entity.RequestLog.cost_usd": "API 비용",
22567
22567
  "entity.RequestLog.cost_source": "비용 출처(provider/pricing_table/mixed)",
22568
- "entity.RequestLog.image_cost_usd": "이미지 생성 추정 비용",
22569
- "entity.RequestLog.image_cost_method": "이미지 비용 추정 방식",
22568
+ "entity.RequestLog.image_cost_usd": "이미지 생성 비용",
22569
+ "entity.RequestLog.image_cost_method": "이미지 비용 계산 방식",
22570
+ "entity.RequestLog.service_tier": "Requested OpenAI service tier",
22570
22571
  "entity.RequestLog.effort": "effort level",
22571
22572
  "entity.RequestLog.history": "inject_items 히스토리",
22572
22573
  "entity.RequestLog.tools": "요청에 장착된 tool 정의 목록",
@@ -1,7 +1,7 @@
1
- import { A as require_react, O as useQueryClient, X as __toESM, a as SettingService, k as require_jsx_runtime, o as TokenService } from "./services.generated-FPwsG9p3.js";
1
+ import { A as require_react, O as useQueryClient, X as __toESM, a as SettingService, k as require_jsx_runtime, o as TokenService } from "./services.generated-CEbGjsI0.js";
2
2
  import { l as lucideRotateCcw } from "../entry-server.generated.js";
3
- import { t as useUpdateTokenMutation } from "./use-update-token-mutation-xvXbPrCI.js";
4
- import { t as lucidePlus } from "./plus-Bvdj8Pwx.js";
3
+ import { t as useUpdateTokenMutation } from "./use-update-token-mutation-CfYmk_4_.js";
4
+ import { t as lucidePlus } from "./plus-KZrECewT.js";
5
5
  //#region ~icons/lucide/eye.jsx
6
6
  var import_react = /* @__PURE__ */ __toESM(require_react());
7
7
  var import_jsx_runtime = require_jsx_runtime();
@@ -1,8 +1,8 @@
1
- import { A as require_react, E as useQuery, X as __toESM, i as RequestLogStepService, k as require_jsx_runtime, l as isSonamuError, q as __commonJSMin, r as RequestLogService } from "./services.generated-FPwsG9p3.js";
2
- import { a as Link } from "./lazyRouteComponent-CUR-kWzI.js";
1
+ import { A as require_react, E as useQuery, X as __toESM, i as RequestLogStepService, k as require_jsx_runtime, l as isSonamuError, q as __commonJSMin, r as RequestLogService } from "./services.generated-CEbGjsI0.js";
2
+ import { a as Link } from "./lazyRouteComponent-Dtd0NR4r.js";
3
3
  import { c as lucideX, d as Markdown, t as Route, u as remarkGfm } from "../entry-server.generated.js";
4
- import { n as formatMicroUsd, t as cacheHitRate } from "./cost-59jBdx-I.js";
5
- import { t as requestModelDisplay } from "./request-model-CnCeaNLE.js";
4
+ import { n as formatMicroUsd, t as cacheHitRate } from "./cost-eEHeTRT5.js";
5
+ import { n as lucideZap, t as requestModelDisplay } from "./request-model-CbqfnQOJ.js";
6
6
  //#region ../../node_modules/.pnpm/@babel+runtime@7.29.2/node_modules/@babel/runtime/helpers/extends.js
7
7
  var require_extends = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8
8
  function _extends() {
@@ -2146,6 +2146,14 @@ function HeaderBar({ data }) {
2146
2146
  className: "text-[10px] text-sand-400",
2147
2147
  children: "요청"
2148
2148
  }),
2149
+ data.service_tier === "fast" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2150
+ title: "Fast 모드",
2151
+ className: "inline-flex shrink-0",
2152
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(lucideZap, {
2153
+ "aria-label": "Fast 모드",
2154
+ className: "size-3.5 text-[#1877F2] [&_path]:fill-current"
2155
+ })
2156
+ }),
2149
2157
  !isRunning && (data.fallback_count ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2150
2158
  className: "text-[10px] px-1.5 py-0.5 rounded-full bg-caution-400/15 text-caution-500 font-medium uppercase",
2151
2159
  children: ["fallback ×", data.fallback_count]
@@ -2194,15 +2202,11 @@ function MetricsPanel({ data, toolCallCount }) {
2194
2202
  value: formatTokensPerSec(data.output_tokens, data.duration_ms, data.ttft_ms, tokensPerSecEnabled)
2195
2203
  }),
2196
2204
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Metric, {
2197
- label: "Driver Cost",
2205
+ label: "Driver",
2198
2206
  value: data.cost_usd !== null ? formatMicroUsd(data.cost_usd) : "—"
2199
2207
  }),
2200
2208
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Metric, {
2201
- label: "Cost Source",
2202
- value: data.cost_source ?? "legacy"
2203
- }),
2204
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Metric, {
2205
- label: "Image Cost",
2209
+ label: "Image",
2206
2210
  value: data.image_cost_usd !== null ? formatMicroUsd(data.image_cost_usd) : "—"
2207
2211
  }),
2208
2212
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Metric, {
@@ -2277,8 +2281,8 @@ function formatTokensPerSec(outputTokens, durationMs, ttftMs, enabled) {
2277
2281
  }
2278
2282
  function CompactMetric({ label, value }) {
2279
2283
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2280
- className: "min-w-0",
2281
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2284
+ className: "min-w-0 self-end",
2285
+ children: [label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2282
2286
  className: "text-[10px] uppercase tracking-wider text-sand-400 font-medium truncate",
2283
2287
  children: label
2284
2288
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
@@ -2534,14 +2538,7 @@ function StepTreeItem({ entry, tokensPerSecEnabled }) {
2534
2538
  label: "Cache 5m / 1h",
2535
2539
  value: `${generate.cacheCreation5mTokens === null ? "—" : formatNum(generate.cacheCreation5mTokens)} / ${generate.cacheCreation1hTokens === null ? "—" : formatNum(generate.cacheCreation1hTokens)}`
2536
2540
  }),
2537
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CompactMetric, {
2538
- label: "Cost",
2539
- value: generate.costUsd === null ? "—" : formatMicroUsd(generate.costUsd)
2540
- }),
2541
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CompactMetric, {
2542
- label: "Cost Source",
2543
- value: generate.costSource ?? "legacy"
2544
- }),
2541
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CompactMetric, { value: generate.costUsd === null ? "—" : formatMicroUsd(generate.costUsd) }),
2545
2542
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CompactMetric, {
2546
2543
  label: "Reasoning",
2547
2544
  value: generate.reasoningTokens !== null && generate.reasoningTokens !== void 0 ? formatNum(generate.reasoningTokens) : "—"
@@ -2598,7 +2595,6 @@ function buildStepTree(steps) {
2598
2595
  cacheCreation5mTokens: step.cache_creation_5m_tokens,
2599
2596
  cacheCreation1hTokens: step.cache_creation_1h_tokens,
2600
2597
  costUsd: step.cost_usd,
2601
- costSource: step.cost_source,
2602
2598
  durationMs: step.duration_ms,
2603
2599
  ttftMs: step.ttft_ms,
2604
2600
  finishReason: step.finish_reason,
@@ -1,8 +1,8 @@
1
- import { A as require_react, O as useQueryClient, X as __toESM, k as require_jsx_runtime, n as QgridService, o as TokenService } from "./services.generated-FPwsG9p3.js";
1
+ import { A as require_react, O as useQueryClient, X as __toESM, k as require_jsx_runtime, n as QgridService, o as TokenService } from "./services.generated-CEbGjsI0.js";
2
2
  import { f as lucideKeyRound, o as Q } from "../entry-server.generated.js";
3
- import { t as useUpdateTokenMutation } from "./use-update-token-mutation-xvXbPrCI.js";
4
- import { n as OAuthCodeEntry, t as useOAuthLoginFlow } from "./use-oauth-login-flow-DTQKdYBO.js";
5
- import { t as lucidePlus } from "./plus-Bvdj8Pwx.js";
3
+ import { t as useUpdateTokenMutation } from "./use-update-token-mutation-CfYmk_4_.js";
4
+ import { n as OAuthCodeEntry, t as useOAuthLoginFlow } from "./use-oauth-login-flow-Cvdy0zF8.js";
5
+ import { t as lucidePlus } from "./plus-KZrECewT.js";
6
6
  //#region src/components/qgrid/AddTokenModal.tsx
7
7
  var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
8
8
  var import_jsx_runtime = require_jsx_runtime();
@@ -1,4 +1,4 @@
1
- import { A as require_react, O as useQueryClient, X as __toESM, k as require_jsx_runtime, n as QgridService, o as TokenService } from "./services.generated-FPwsG9p3.js";
1
+ import { A as require_react, O as useQueryClient, X as __toESM, k as require_jsx_runtime, n as QgridService, o as TokenService } from "./services.generated-CEbGjsI0.js";
2
2
  import { o as Q } from "../entry-server.generated.js";
3
3
  //#region src/components/qgrid/OAuthCodeEntry.tsx
4
4
  var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
@@ -1,4 +1,4 @@
1
- import { T as useMutation, n as QgridService } from "./services.generated-FPwsG9p3.js";
1
+ import { T as useMutation, n as QgridService } from "./services.generated-CEbGjsI0.js";
2
2
  //#region src/services/token/use-update-token-mutation.ts
3
3
  function useUpdateTokenMutation() {
4
4
  return useMutation({ mutationFn: ({ id, name, quotaThreshold, weight, keepaliveEnabled }) => QgridService.updateToken(id, name, quotaThreshold, weight, keepaliveEnabled) });
@@ -1,6 +1,6 @@
1
- import { A as require_react, B as matchQuery, C as union, D as QueryClientProvider, F as notifyManager, G as focusManager, H as partialMatchKey, I as functionalUpdate, J as __exportAll, K as Subscribable, L as hashKey, M as infiniteQueryBehavior, N as Query, P as onlineManager, R as hashQueryKeyByOptions, S as string$2, U as resolveStaleTime, V as noop$1, W as skipToken, X as __toESM, Y as __require, _ as custom, b as number$1, c as fetch$1, d as SD, f as SUPPORTED_LOCALES, g as boolean$1, h as array, j as Mutation, k as require_jsx_runtime, m as _enum, n as QgridService, o as TokenService, p as setLocale, q as __commonJSMin, s as SonamuQueryMode, u as zArrayable, v as date, w as unknown, x as object, y as int, z as matchMutation } from "./assets/services.generated-FPwsG9p3.js";
2
- import { A as decodePath, C as findRouteMatch, D as createLRUCache, E as processRouteTree, F as last, I as replaceEqualDeep, M as findLast, N as functionalUpdate$1, O as invariant, P as isPromise, S as findFlatMatch, T as processRouteMasks, _ as interpolatePath, a as Link$1, b as trimPath, c as usePrevious$1, d as useRouter, f as getRouterContext, g as cleanPath, h as isNotFound, i as createRootRouteWithContext, j as deepEqual$2, k as createControlledPromise, l as matchContext, m as rootRouteId, n as createFileRoute, p as warning, r as createLazyFileRoute, s as useLayoutEffect$3, t as lazyRouteComponent, u as useRouterState, v as joinPaths, w as findSingleMatch, x as trimPathRight, y as resolvePath } from "./assets/lazyRouteComponent-CUR-kWzI.js";
3
- import { n as require_shim, t as require_react_dom } from "./assets/react-dom-CyuShs9K.js";
1
+ import { A as require_react, B as matchQuery, C as union, D as QueryClientProvider, F as notifyManager, G as focusManager, H as partialMatchKey, I as functionalUpdate, J as __exportAll, K as Subscribable, L as hashKey, M as infiniteQueryBehavior, N as Query, P as onlineManager, R as hashQueryKeyByOptions, S as string$2, U as resolveStaleTime, V as noop$1, W as skipToken, X as __toESM, Y as __require, _ as custom, b as number$1, c as fetch$1, d as SD, f as SUPPORTED_LOCALES, g as boolean$1, h as array, j as Mutation, k as require_jsx_runtime, m as _enum, n as QgridService, o as TokenService, p as setLocale, q as __commonJSMin, s as SonamuQueryMode, u as zArrayable, v as date, w as unknown, x as object, y as int, z as matchMutation } from "./assets/services.generated-CEbGjsI0.js";
2
+ import { A as decodePath, C as findRouteMatch, D as createLRUCache, E as processRouteTree, F as last, I as replaceEqualDeep, M as findLast, N as functionalUpdate$1, O as invariant, P as isPromise, S as findFlatMatch, T as processRouteMasks, _ as interpolatePath, a as Link$1, b as trimPath, c as usePrevious$1, d as useRouter, f as getRouterContext, g as cleanPath, h as isNotFound, i as createRootRouteWithContext, j as deepEqual$2, k as createControlledPromise, l as matchContext, m as rootRouteId, n as createFileRoute, p as warning, r as createLazyFileRoute, s as useLayoutEffect$3, t as lazyRouteComponent, u as useRouterState, v as joinPaths, w as findSingleMatch, x as trimPathRight, y as resolvePath } from "./assets/lazyRouteComponent-Dtd0NR4r.js";
3
+ import { n as require_shim, t as require_react_dom } from "./assets/react-dom-B4a6-uuR.js";
4
4
  import minpath from "node:path";
5
5
  import minproc from "node:process";
6
6
  import { fileURLToPath as urlToPath } from "node:url";
@@ -46874,7 +46874,7 @@ function ChatWidget() {
46874
46874
  }
46875
46875
  //#endregion
46876
46876
  //#region src/components/Sidebar.tsx
46877
- var qgridVersion = "2.10.5";
46877
+ var qgridVersion = "2.10.7";
46878
46878
  function Sidebar({ className }) {
46879
46879
  const pathname = useRouterState({ select: (s) => s.location.pathname });
46880
46880
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
@@ -68752,15 +68752,15 @@ function RootComponent() {
68752
68752
  }
68753
68753
  //#endregion
68754
68754
  //#region src/routes/tokens.tsx
68755
- var $$splitComponentImporter$5 = () => import("./assets/tokens-odgS2-9q.js");
68755
+ var $$splitComponentImporter$5 = () => import("./assets/tokens-D1hb4eKk.js");
68756
68756
  var Route$5 = createFileRoute("/tokens")({ component: lazyRouteComponent($$splitComponentImporter$5, "component") });
68757
68757
  //#endregion
68758
68758
  //#region src/routes/settings.tsx
68759
- var $$splitComponentImporter$4 = () => import("./assets/settings-DeHNwoMv.js");
68759
+ var $$splitComponentImporter$4 = () => import("./assets/settings-BZR5HSAL.js");
68760
68760
  var Route$4 = createFileRoute("/settings")({ component: lazyRouteComponent($$splitComponentImporter$4, "component") });
68761
68761
  //#endregion
68762
68762
  //#region src/routes/monit.tsx
68763
- var $$splitComponentImporter$3 = () => import("./assets/monit-CBil92fJ.js");
68763
+ var $$splitComponentImporter$3 = () => import("./assets/monit-DvzribSE.js");
68764
68764
  var monitSearchSchema = object({ level: _enum([
68765
68765
  "all",
68766
68766
  "warn",
@@ -68865,6 +68865,7 @@ object({
68865
68865
  cost_source: string$2().max(20).nullable(),
68866
68866
  image_cost_usd: int().nullable(),
68867
68867
  image_cost_method: string$2().max(100).nullable(),
68868
+ service_tier: string$2().max(20).nullable(),
68868
68869
  effort: string$2().max(10).nullable(),
68869
68870
  history: HistoryItems.nullable(),
68870
68871
  tools: ToolDefinitions.nullable(),
@@ -68995,6 +68996,7 @@ object({
68995
68996
  image_cost_usd: int().nullable(),
68996
68997
  image_cost_method: string$2().max(100).nullable(),
68997
68998
  effort: string$2().max(10).nullable(),
68999
+ service_tier: string$2().max(20).nullable(),
68998
69000
  history: HistoryItems.nullable(),
68999
69001
  tools: ToolDefinitions.nullable(),
69000
69002
  status: RequestLogStatus,
@@ -69025,6 +69027,7 @@ object({
69025
69027
  image_cost_usd: int().nullable(),
69026
69028
  image_cost_method: string$2().max(100).nullable(),
69027
69029
  effort: string$2().max(10).nullable(),
69030
+ service_tier: string$2().max(20).nullable(),
69028
69031
  status: RequestLogStatus,
69029
69032
  response_json_ok: boolean$1().nullable(),
69030
69033
  tool_call_count: int(),
@@ -69137,7 +69140,7 @@ object({
69137
69140
  _enum(["A"]);
69138
69141
  //#endregion
69139
69142
  //#region src/routes/logs.tsx
69140
- var $$splitComponentImporter$2 = () => import("./assets/logs-CaaWO9-Z.js");
69143
+ var $$splitComponentImporter$2 = () => import("./assets/logs-l91avYif.js");
69141
69144
  var logsSearchSchema = object({
69142
69145
  token: string$2().optional(),
69143
69146
  project: string$2().optional(),
@@ -69151,11 +69154,11 @@ var Route$2 = createFileRoute("/logs")({
69151
69154
  });
69152
69155
  //#endregion
69153
69156
  //#region src/routes/index.tsx
69154
- var $$splitComponentImporter$1 = () => import("./assets/routes-DtVf9yqo.js");
69157
+ var $$splitComponentImporter$1 = () => import("./assets/routes-BAPWTizT.js");
69155
69158
  var Route$1 = createFileRoute("/")({ component: lazyRouteComponent($$splitComponentImporter$1, "component") });
69156
69159
  //#endregion
69157
69160
  //#region src/routes/requests/show.tsx
69158
- var $$splitComponentImporter = () => import("./assets/show-8NNdRxhM.js");
69161
+ var $$splitComponentImporter = () => import("./assets/show-CxVZTAdv.js");
69159
69162
  var showSearchSchema = object({ id: number$1() });
69160
69163
  var Route = createFileRoute("/requests/show")({
69161
69164
  validateSearch: showSearchSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cartanova/qgrid-cli",
3
- "version": "2.10.5",
3
+ "version": "2.10.7",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cartanova-ai/qgrid"
@@ -38,13 +38,13 @@ When helping a user set up local `@cartanova/qgrid-ai-sdk`, `createQgridLogger`,
38
38
 
39
39
  Prefer `QGRID_PROJECT_NAME` as the project-wide default. Use config `projectName` only for a deliberate per-call/per-provider override. Do not add `projectName` or `project_name` under `providerOptions.qgrid`; current code does not read it there.
40
40
 
41
- When writing AI SDK examples or setup code, import the public `QgridProviderOptions` type and apply `satisfies QgridProviderOptions` to the value under `providerOptions.qgrid`. AI SDK types the outer `providerOptions` as a generic JSON record, so it cannot infer qgrid's option names and values by itself. `QgridProviderOptions` is the inner qgrid namespace type, not the outer record type.
41
+ When writing AI SDK examples or setup code, use `satisfies QgridProviderOptions` for language-model options or `satisfies QgridImageProviderOptions` for image-model options under `providerOptions.qgrid`. AI SDK types the outer `providerOptions` as a generic JSON record, so it cannot infer qgrid's option names and values by itself. These types describe the inner qgrid namespace, not the outer record.
42
42
 
43
43
  Request logging is enabled by default. Use `providerOptions.qgrid.logger: false` only for a call that must create zero qgrid request-log rows. The same option suppresses both qgrid's server-native logging and `createQgridLogger` telemetry logging for that generation; it does not disable generation, AI SDK tool execution, multi-step continuation, or OpenAI cache affinity. The old `logMode` input has been removed and must not appear in setup code or raw qgrid payloads.
44
44
 
45
45
  ## Non-Negotiable Boundaries
46
46
 
47
- - Use `packages/ai-sdk` as the active public SDK surface.
47
+ - Use `packages/ai-sdk` as the active public SDK surface. `qgrid()` implements `LanguageModelV3` for text, tools, and structured output; it has no public image-generation options and does not support general vision. `qgrid.image("openai/gpt-image-2")` implements `ImageModelV3` for standard AI SDK `generateImage`, directly calling subscription Images for generation or reference editing without a chat driver. Dashboard chat registers its image tool internally; do not add a public SDK tool factory. See `references/ai-sdk-provider-contract.md` for image options, usage, and metadata.
48
48
  - Expose thinking only as `providerOptions.qgrid.thinking?: boolean`: omission preserves the model policy, false overrides effort, and unsupported/unverified off requests fail explicitly. See the SDK and provider runtime references for the dated support snapshot. Keep Anthropic thinking controls separate from mandatory configuration and memory isolation. Haiku/Sonnet 5.5 off uses a computed thinking-only native body override with Claude Code >=2.1.295; never inherit or expose arbitrary extra body.
49
49
  - The old v1 SDK package (`packages/sdk`, `@cartanova/qgrid-sdk`) has been removed from the repository. It survives only as a deprecated npm artifact (1.9.0); do not resurrect it or write new code against it.
50
50
  - Let the server infer single-turn versus tool-run request-log lifecycle. Do not recreate caller-selected logging modes in the SDK or API examples.
@@ -54,11 +54,11 @@ Request logging is enabled by default. Use `providerOptions.qgrid.logger: false`
54
54
  - Prefer `getPuri()` for Sonamu model queries. Treat `getDB()` as a legacy escape hatch only when Puri cannot express the required query. Inside `@transactional` methods, all participating queries must use `getPuri()`; `getDB()` does not reuse Sonamu's ambient transaction connection.
55
55
  - Never hand-author migration files for Sonamu-managed schema. In the qgrid source repository, change the entity definition, inspect `sonamu migrate status`, and create migration files with `mise exec -- pnpm --dir packages/api sonamu migrate generate`. Inspect the generated files before applying them. If Sonamu cannot express a required schema change, stop and ask rather than silently replacing its workflow with a custom migration.
56
56
  - Keep OpenAI Codex built-in tools, apps, plugins, skills, web search, shell, and environment instruction blocks disabled unless the user explicitly asks for agentic Codex behavior.
57
- - Treat OpenAI image generation as opt-in outside dashboard chat. In 2.9.8, OpenAI `qgrid_chat` opts into raw API `imageGeneration: "auto"` on every turn; the public AI SDK option remains boolean. Ordinary images use the hosted Responses image tool; a server-executed transparent-image function calls Codex standalone Images directly with subscription credentials. Do not reintroduce a client decision tool followed by another GPT generation request. Hosted image costs are unknown (`null`); standalone usage and known-size legacy responses use public-price estimates. Mark totals as known subtotals when they omit unknown image costs.
57
+ - Treat OpenAI image generation as opt-in outside dashboard chat. OpenAI `qgrid_chat` opts into raw API `imageGeneration: "auto"` on every turn. Auto mode registers only the server-executed `generate_image` function and calls Codex standalone Images for ordinary or transparent output. The raw explicit chat-model `imageGeneration: true` hosted route remains supported separately. The public SDK uses only `qgrid.image()` / `generateImage` for images, calling standalone Images for every background. Do not expose the raw `imageGeneration` or `imageGenerationOptions` fields as language-model options or retain deprecated shims. Do not reintroduce a client decision tool followed by another GPT generation request. Image costs use reported image usage at public token rates when available; otherwise estimate per image from the requested quality/size table. Auto or unsupported sizes use the 1536x1024 price; omitted quality uses medium. Display combined driver and image costs as dollar amounts without Cost labels. Do not show Known/Estimated labels, pricing disclaimers, or cost-source metadata in the dashboard.
58
58
 
59
59
  ## Request log IDs (2.10.0+)
60
60
 
61
- - Successful raw query responses and stream `done` events expose optional top-level `requestLogId`. The AI SDK exposes it as `providerMetadata.qgrid.requestLogId`; await stream metadata after consuming the stream.
61
+ - Successful raw query responses and stream `done` events expose optional top-level `requestLogId`. AI SDK text calls expose it as `providerMetadata.qgrid.requestLogId`; await stream metadata after consuming the stream. `generateImage` exposes each call's ID under `providerMetadata.qgrid.images[]` alongside generation metadata.
62
62
  - The ID identifies the parent request log and stays the same across tool-run steps. It is omitted with `logger: false`. Keep `runContext.requestLogId` for tool continuation only; do not replay the top-level ID as continuation state.
63
63
  - Update both server and AI SDK to 2.10.0 or later to consume the metadata. Older servers may omit the ID. This contract does not add IDs to delta or error events or change `createQgridLogger` for external providers.
64
64
 
@@ -66,17 +66,18 @@ Request logging is enabled by default. Use `providerOptions.qgrid.logger: false`
66
66
 
67
67
  - Raw `imageGeneration: "auto"` permits text-only replies; explicit `true` still requires an image. Both use non-stream requests. Auto mode rejects caller tools and output schemas.
68
68
  - Dashboard chat sends complete text and image history, including prior generated images as user visual references. Do not assume provider conversation state retains image bytes or send assistant `input_image` blocks.
69
- - The model chooses ordinary `image_generation` or `generate_transparent_image`; the server runs the latter directly with the selected token and cancellation signal. Preserve driver usage separately from image usage.
69
+ - Register only `generate_image` for auto mode, with server-validated arguments `prompt: string`, `transparent_background: boolean`, and `num_last_images_to_include: integer` from 0 to 5. Use `strict: false` on the wire, matching Codex; Astra subscription requests fail with `strict: true`. Keep complete server-side validation. The driver sees the complete conversation and writes a self-contained image prompt. Zero references means fresh generation; a positive count selects the last N conversation images in chronological order for editing. Do not forward all historical images automatically.
70
+ - Run the function directly against subscription Images with the selected token and cancellation signal, without a second text-driver request. Preserve driver usage separately from image usage. Do not register the native hosted `image_generation` tool in auto mode.
70
71
  - Request-log model labels show requested model to image model using serving/image-cost metadata. Do not hardcode `gpt-image-2.5` or restore image-generation/assumption badges. In auto mode, mark image generation only when an image was produced.
71
72
  - Read `references/decision-rationale.md` and `references/openai-codex-runtime.md` before changing this routing or its cache boundary.
72
73
 
73
74
  ## Image output formats (2.9.6+)
74
75
 
75
- - Use `imageGenerationOptions.outputFormat: "png" | "jpeg" | "webp"` on the hosted Responses image path. Omission retains PNG.
76
+ - Raw explicit chat-model hosted Responses requests support `imageGenerationOptions.outputFormat: "png" | "jpeg" | "webp"`. Omission retains PNG. Auto chat and public `generateImage` use standalone Images and support PNG only; reject other formats before generation. Public image options use flat `QgridImageProviderOptions`.
76
77
  - Preserve the actual returned MIME type in qgrid content, AI SDK files, and request-log image URLs; do not relabel bytes as the requested format.
77
- - Transparent generation keeps the standalone Codex Images route and accepts PNG only. Reject transparent JPEG/WebP requests before generation.
78
+ - Transparent generation uses the standalone Codex Images route and accepts PNG only. Reject transparent JPEG/WebP requests before generation. Do not convert output or fall back to another route.
78
79
  - Keep the AI SDK standard `GeneratedFile.mediaType: string` contract. Do not add a qgrid-specific image wrapper or conditional return type.
79
- - A 2026-09-29 live probe returned PNG for a prompt-only WebP request and WebP when `outputFormat: "webp"` was supplied. Model prose is not format evidence; inspect file bytes. Chat does not infer output format from prose, and no post-generation conversion is performed.
80
+ - A 2026-09-29 hosted-route probe returned PNG for a prompt-only WebP request and WebP when `outputFormat: "webp"` was supplied. Model prose is not format evidence; inspect file bytes. Chat does not infer output format from prose, and no post-generation conversion is performed.
80
81
 
81
82
  ## Verification
82
83