@cartanova/qgrid-cli 2.10.1 → 2.10.3

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 (97) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +1 -1
  3. package/bundle/dist/application/monit/log-buffer.js +7 -11
  4. package/bundle/dist/application/monit/monit.frame.js +6 -11
  5. package/bundle/dist/application/qgrid/oauth.js +2 -2
  6. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +2 -2
  7. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +12 -36
  8. package/bundle/dist/application/qgrid/qgrid.frame.js +2 -2
  9. package/bundle/dist/application/qgrid/qgrid.types.js +2 -1
  10. package/bundle/dist/application/qgrid/token-subscriber.js +4 -7
  11. package/bundle/dist/application/qgrid/token-window-keepalive.js +3 -2
  12. package/bundle/dist/application/qgrid/tool-emulation-schema.js +4 -4
  13. package/bundle/dist/application/qgrid/tool-emulation.js +14 -2
  14. package/bundle/dist/application/request-log/request-log.model.js +7 -5
  15. package/bundle/dist/application/setting/setting.model.js +1 -1
  16. package/bundle/dist/sonamu.config.js +6 -6
  17. package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +1 -1
  18. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +53 -84
  19. package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +55 -0
  20. package/bundle/dist/utils/providers/anthropic/claude-session.js +11 -13
  21. package/bundle/dist/utils/providers/common/effort.js +1 -1
  22. package/bundle/dist/utils/providers/common/smooth-weighted-round-robin.js +3 -3
  23. package/bundle/dist/utils/providers/common/thinking.js +12 -0
  24. package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +3 -2
  25. package/bundle/dist/utils/providers/openai/openai-direct-client.js +6 -16
  26. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +89 -78
  27. package/bundle/src/application/monit/log-buffer.test.ts +3 -4
  28. package/bundle/src/application/monit/log-buffer.ts +13 -27
  29. package/bundle/src/application/monit/monit.frame.test.ts +7 -8
  30. package/bundle/src/application/monit/monit.frame.ts +9 -14
  31. package/bundle/src/application/qgrid/oauth.ts +1 -1
  32. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +7 -0
  33. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +1 -1
  34. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +62 -1
  35. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +25 -71
  36. package/bundle/src/application/qgrid/qgrid.frame.ts +4 -8
  37. package/bundle/src/application/qgrid/qgrid.types.ts +2 -0
  38. package/bundle/src/application/qgrid/token-subscriber.test.ts +8 -18
  39. package/bundle/src/application/qgrid/token-subscriber.ts +10 -20
  40. package/bundle/src/application/qgrid/token-window-keepalive.test.ts +2 -2
  41. package/bundle/src/application/qgrid/token-window-keepalive.ts +2 -1
  42. package/bundle/src/application/qgrid/tool-emulation-schema.test.ts +6 -3
  43. package/bundle/src/application/qgrid/tool-emulation-schema.ts +3 -3
  44. package/bundle/src/application/qgrid/tool-emulation.test.ts +8 -1
  45. package/bundle/src/application/qgrid/tool-emulation.ts +29 -0
  46. package/bundle/src/application/request-log/request-log.model.ts +5 -5
  47. package/bundle/src/application/setting/setting.model.ts +1 -1
  48. package/bundle/src/sonamu.config.ts +5 -5
  49. package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +3 -6
  50. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.test.ts +26 -0
  51. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +70 -148
  52. package/bundle/src/utils/providers/anthropic/anthropic-thinking.test.ts +36 -0
  53. package/bundle/src/utils/providers/anthropic/anthropic-thinking.ts +84 -0
  54. package/bundle/src/utils/providers/anthropic/claude-session.test.ts +74 -13
  55. package/bundle/src/utils/providers/anthropic/claude-session.ts +11 -20
  56. package/bundle/src/utils/providers/common/effort.ts +1 -1
  57. package/bundle/src/utils/providers/common/provider-dispatcher.ts +4 -0
  58. package/bundle/src/utils/providers/common/smooth-weighted-round-robin.ts +4 -4
  59. package/bundle/src/utils/providers/common/thinking.ts +10 -0
  60. package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +7 -3
  61. package/bundle/src/utils/providers/openai/openai-direct-client.test.ts +3 -3
  62. package/bundle/src/utils/providers/openai/openai-direct-client.ts +20 -33
  63. package/bundle/src/utils/providers/openai/openai-dispatcher.test.ts +97 -6
  64. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +113 -77
  65. package/bundle/web-dist/client/assets/{index-Cq4_ExLO.js → index-BIC1sQxw.js} +3 -3
  66. package/bundle/web-dist/client/assets/logs-zvdujZWn.js +1 -0
  67. package/bundle/web-dist/client/assets/monit-CraVV3MQ.js +1 -0
  68. package/bundle/web-dist/client/assets/refresh-cw-NNcU0Cmq.js +1 -0
  69. package/bundle/web-dist/client/assets/{routes-CXotE1OF.js → routes-B3ZBoJ60.js} +1 -1
  70. package/bundle/web-dist/client/assets/{settings-CfJDz4AC.js → settings-DwbzT5jo.js} +1 -1
  71. package/bundle/web-dist/client/assets/{show-gBpWK4z2.js → show-ItTExdAh.js} +1 -1
  72. package/bundle/web-dist/client/assets/{tokens-CbFJjIyC.js → tokens-BynKx8Vn.js} +1 -1
  73. package/bundle/web-dist/client/assets/{use-oauth-login-flow-jJo7GV3r.js → use-oauth-login-flow-8xw6on5P.js} +1 -1
  74. package/bundle/web-dist/client/index.html +1 -1
  75. package/bundle/web-dist/server/assets/{logs-DMlOXcDS.js → logs-BSk9lOHe.js} +13 -3
  76. package/bundle/web-dist/server/assets/{monit-Dg1wZCdx.js → monit-D9W4ioUi.js} +2 -21
  77. package/bundle/web-dist/server/assets/refresh-cw-B8U9BL9-.js +23 -0
  78. package/bundle/web-dist/server/assets/{settings-BaIBt_Vs.js → settings-BFVuldch.js} +1 -1
  79. package/bundle/web-dist/server/assets/{show-CDxGr4rS.js → show-Cswh_tqs.js} +1 -1
  80. package/bundle/web-dist/server/assets/{tokens-DJlfeGcx.js → tokens-DiTUwUwr.js} +1 -1
  81. package/bundle/web-dist/server/entry-server.generated.js +6 -7
  82. package/package.json +1 -1
  83. package/skills/qgrid/SKILL.md +1 -0
  84. package/skills/qgrid/references/ai-sdk-provider-contract.md +2 -1
  85. package/skills/qgrid/references/anthropic-claude-code-runtime.md +7 -4
  86. package/skills/qgrid/references/decision-rationale.md +9 -0
  87. package/skills/qgrid/references/openai-codex-runtime.md +6 -0
  88. package/skills/qgrid/references/sonamu-api-web-flow.md +3 -1
  89. package/skills/qgrid/references/token-auth-quota-lifecycle.md +2 -0
  90. package/skills/qgrid/references/tool-calling-and-multiturn.md +18 -1
  91. package/skills/qgrid/references/verification-and-debugging.md +1 -1
  92. package/bundle/web-dist/client/assets/logs-kg1KOMBk.js +0 -1
  93. package/bundle/web-dist/client/assets/monit-DmtHTmSM.js +0 -1
  94. /package/bundle/web-dist/client/assets/{plus-CknMNCP5.js → plus-B62CuqT8.js} +0 -0
  95. /package/bundle/web-dist/client/assets/{request-model-eygfdRv7.js → request-model-D4CZPmnG.js} +0 -0
  96. /package/bundle/web-dist/server/assets/{plus-DVobMrag.js → plus-CmvbWuDf.js} +0 -0
  97. /package/bundle/web-dist/server/assets/{request-model-DXclJfdP.js → request-model-CnCeaNLE.js} +0 -0
@@ -5,7 +5,7 @@
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-Cq4_ExLO.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-BIC1sQxw.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">
@@ -2,7 +2,8 @@ import { A as require_jsx_runtime, S as string, j as require_react, n as QgridSe
2
2
  import { a as Link, o as useNavigate } from "./lazyRouteComponent-Bj1cPq6x.js";
3
3
  import { i as RequestLogOrderBy, n as Route, r as RequestLogBaseListParams } from "../entry-server.generated.js";
4
4
  import { n as formatMicroUsd, r as formatUsd, t as cacheHitRate } from "./cost-CSH_t17I.js";
5
- import { t as requestModelDisplay } from "./request-model-DXclJfdP.js";
5
+ import { t as lucideRefreshCw } from "./refresh-cw-B8U9BL9-.js";
6
+ import { t as requestModelDisplay } from "./request-model-CnCeaNLE.js";
6
7
  require_react();
7
8
  var import_jsx_runtime = require_jsx_runtime();
8
9
  var lucideChevronLeft = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
@@ -195,13 +196,13 @@ function RequestLogTable({ search, onSearchChange }) {
195
196
  const separator = sort.lastIndexOf("-");
196
197
  const sortColumn = sort.slice(0, separator);
197
198
  const sortDirection = sort.slice(separator + 1) === "asc" ? "asc" : "desc";
198
- const { data, isLoading, isError } = RequestLogService.useRequestLogs("P", {
199
+ const { data, isLoading, isError, refresh, isRefreshing } = RequestLogService.useRequestLogs("P", {
199
200
  num: PAGE_SIZE,
200
201
  page,
201
202
  orderBy: sort,
202
203
  ...listFilters
203
204
  });
204
- const { data: costData, isError: isCostError } = QgridService.useTotalCost({
205
+ const { data: costData, isError: isCostError, refresh: refreshCost } = QgridService.useTotalCost({
205
206
  num: 0,
206
207
  page: 1,
207
208
  ...listFilters
@@ -266,6 +267,15 @@ function RequestLogTable({ search, onSearchChange }) {
266
267
  children: name
267
268
  }, name))]
268
269
  }),
270
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
271
+ type: "button",
272
+ onClick: () => void Promise.all([refresh(), refreshCost()]),
273
+ disabled: isRefreshing,
274
+ "aria-label": "Reload",
275
+ title: "Reload",
276
+ className: "p-1 rounded text-sand-400 hover:text-sand-600 disabled:opacity-30 transition-colors",
277
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(lucideRefreshCw, { className: isRefreshing ? "size-3.5 animate-spin" : "size-3.5" })
278
+ }),
269
279
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex-1" }),
270
280
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
271
281
  className: "text-[11px] text-sand-400",
@@ -2,6 +2,7 @@ import { A as require_jsx_runtime, D as useQuery, Z as __toESM, j as require_rea
2
2
  import { t as require_react_dom } from "./react-dom-BjR1Iaz8.js";
3
3
  import { a as Route, s as clsx } from "../entry-server.generated.js";
4
4
  import { t as cacheHitRate } from "./cost-CSH_t17I.js";
5
+ import { t as lucideRefreshCw } from "./refresh-cw-B8U9BL9-.js";
5
6
  //#region ../../node_modules/.pnpm/@tanstack+virtual-core@3.17.4/node_modules/@tanstack/virtual-core/dist/esm/lazy-measurements.js
6
7
  var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
7
8
  var import_react_dom = /* @__PURE__ */ __toESM(require_react_dom(), 1);
@@ -1180,28 +1181,8 @@ function useVirtualizer(options) {
1180
1181
  });
1181
1182
  }
1182
1183
  //#endregion
1183
- //#region ~icons/lucide/refresh-cw.jsx
1184
- var import_jsx_runtime = require_jsx_runtime();
1185
- var lucideRefreshCw = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
1186
- viewBox: "0 0 24 24",
1187
- width: "1.2em",
1188
- height: "1.2em",
1189
- ...props,
1190
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", {
1191
- fill: "none",
1192
- stroke: "currentColor",
1193
- strokeLinecap: "round",
1194
- strokeLinejoin: "round",
1195
- strokeWidth: 2,
1196
- children: [
1197
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 12a9 9 0 0 1 9-9a9.75 9.75 0 0 1 6.74 2.74L21 8" }),
1198
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 3v5h-5m5 4a9 9 0 0 1-9 9a9.75 9.75 0 0 1-6.74-2.74L3 16" }),
1199
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 16H3v5" })
1200
- ]
1201
- })
1202
- });
1203
- //#endregion
1204
1184
  //#region src/components/qgrid/MonitConsole.tsx
1185
+ var import_jsx_runtime = require_jsx_runtime();
1205
1186
  var POLL_INTERVAL_MS = 1e3;
1206
1187
  var STALE_AFTER_MS = 5e3;
1207
1188
  var MIRROR_CAP = 4e3;
@@ -0,0 +1,23 @@
1
+ import { A as require_jsx_runtime, j as require_react } from "./services.generated-BM4X3Ecj.js";
2
+ require_react();
3
+ var import_jsx_runtime = require_jsx_runtime();
4
+ var lucideRefreshCw = (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.jsxs)("g", {
10
+ fill: "none",
11
+ stroke: "currentColor",
12
+ strokeLinecap: "round",
13
+ strokeLinejoin: "round",
14
+ strokeWidth: 2,
15
+ children: [
16
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 12a9 9 0 0 1 9-9a9.75 9.75 0 0 1 6.74 2.74L21 8" }),
17
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 3v5h-5m5 4a9 9 0 0 1-9 9a9.75 9.75 0 0 1-6.74-2.74L3 16" }),
18
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 16H3v5" })
19
+ ]
20
+ })
21
+ });
22
+ //#endregion
23
+ export { lucideRefreshCw as t };
@@ -1,7 +1,7 @@
1
1
  import { A as require_jsx_runtime, D as useQuery, T as isAxiosError, Z as __toESM, a as SettingService, j as require_react, k as useQueryClient, l as isSonamuError, n as QgridService, o as TokenService } from "./services.generated-BM4X3Ecj.js";
2
2
  import { l as lucideRotateCcw } from "../entry-server.generated.js";
3
3
  import { t as useUpdateTokenMutation } from "./use-update-token-mutation-DqGMopII.js";
4
- import { t as lucidePlus } from "./plus-DVobMrag.js";
4
+ import { t as lucidePlus } from "./plus-CmvbWuDf.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();
@@ -2,7 +2,7 @@ import { A as require_jsx_runtime, D as useQuery, J as __commonJSMin, Z as __toE
2
2
  import { a as Link } from "./lazyRouteComponent-Bj1cPq6x.js";
3
3
  import { c as lucideX, d as Markdown, t as Route, u as remarkGfm } from "../entry-server.generated.js";
4
4
  import { n as formatMicroUsd, t as cacheHitRate } from "./cost-CSH_t17I.js";
5
- import { t as requestModelDisplay } from "./request-model-DXclJfdP.js";
5
+ import { t as requestModelDisplay } from "./request-model-CnCeaNLE.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() {
@@ -2,7 +2,7 @@ import { A as require_jsx_runtime, Z as __toESM, j as require_react, k as useQue
2
2
  import { f as lucideKeyRound, o as Q } from "../entry-server.generated.js";
3
3
  import { t as useUpdateTokenMutation } from "./use-update-token-mutation-DqGMopII.js";
4
4
  import { n as OAuthCodeEntry, t as useOAuthLoginFlow } from "./use-oauth-login-flow-DYKnG4A2.js";
5
- import { t as lucidePlus } from "./plus-DVobMrag.js";
5
+ import { t as lucidePlus } from "./plus-CmvbWuDf.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();
@@ -46275,7 +46275,6 @@ var MODEL_PRESET_GROUPS = [{
46275
46275
  "anthropic/claude-opus-4-6",
46276
46276
  "anthropic/claude-opus-4-5",
46277
46277
  "anthropic/claude-sonnet-4-6",
46278
- "anthropic/claude-sonnet-4-5",
46279
46278
  "anthropic/claude-haiku-4-5"
46280
46279
  ]
46281
46280
  }];
@@ -46875,7 +46874,7 @@ function ChatWidget() {
46875
46874
  }
46876
46875
  //#endregion
46877
46876
  //#region src/components/Sidebar.tsx
46878
- var qgridVersion = "2.10.1";
46877
+ var qgridVersion = "2.10.3";
46879
46878
  function Sidebar({ className }) {
46880
46879
  const pathname = useRouterState({ select: (s) => s.location.pathname });
46881
46880
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
@@ -68753,15 +68752,15 @@ function RootComponent() {
68753
68752
  }
68754
68753
  //#endregion
68755
68754
  //#region src/routes/tokens.tsx
68756
- var $$splitComponentImporter$5 = () => import("./assets/tokens-DJlfeGcx.js");
68755
+ var $$splitComponentImporter$5 = () => import("./assets/tokens-DiTUwUwr.js");
68757
68756
  var Route$5 = createFileRoute("/tokens")({ component: lazyRouteComponent($$splitComponentImporter$5, "component") });
68758
68757
  //#endregion
68759
68758
  //#region src/routes/settings.tsx
68760
- var $$splitComponentImporter$4 = () => import("./assets/settings-BaIBt_Vs.js");
68759
+ var $$splitComponentImporter$4 = () => import("./assets/settings-BFVuldch.js");
68761
68760
  var Route$4 = createFileRoute("/settings")({ component: lazyRouteComponent($$splitComponentImporter$4, "component") });
68762
68761
  //#endregion
68763
68762
  //#region src/routes/monit.tsx
68764
- var $$splitComponentImporter$3 = () => import("./assets/monit-Dg1wZCdx.js");
68763
+ var $$splitComponentImporter$3 = () => import("./assets/monit-D9W4ioUi.js");
68765
68764
  var monitSearchSchema = object({ level: _enum([
68766
68765
  "all",
68767
68766
  "warn",
@@ -69138,7 +69137,7 @@ object({
69138
69137
  _enum(["A"]);
69139
69138
  //#endregion
69140
69139
  //#region src/routes/logs.tsx
69141
- var $$splitComponentImporter$2 = () => import("./assets/logs-DMlOXcDS.js");
69140
+ var $$splitComponentImporter$2 = () => import("./assets/logs-BSk9lOHe.js");
69142
69141
  var logsSearchSchema = object({
69143
69142
  token: string$2().optional(),
69144
69143
  project: string$2().optional(),
@@ -69156,7 +69155,7 @@ var $$splitComponentImporter$1 = () => import("./assets/routes-C7lB2Q85.js");
69156
69155
  var Route$1 = createFileRoute("/")({ component: lazyRouteComponent($$splitComponentImporter$1, "component") });
69157
69156
  //#endregion
69158
69157
  //#region src/routes/requests/show.tsx
69159
- var $$splitComponentImporter = () => import("./assets/show-CDxGr4rS.js");
69158
+ var $$splitComponentImporter = () => import("./assets/show-Cswh_tqs.js");
69160
69159
  var showSearchSchema = object({ id: number$1() });
69161
69160
  var Route = createFileRoute("/requests/show")({
69162
69161
  validateSearch: showSearchSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cartanova/qgrid-cli",
3
- "version": "2.10.1",
3
+ "version": "2.10.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cartanova-ai/qgrid"
@@ -45,6 +45,7 @@ Request logging is enabled by default. Use `providerOptions.qgrid.logger: false`
45
45
  ## Non-Negotiable Boundaries
46
46
 
47
47
  - Use `packages/ai-sdk` as the active public SDK surface.
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.
48
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.
49
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.
50
51
  - Route provider models by prefix: `openai/*` goes to the OpenAI Codex runtime, `anthropic/*` goes to the Anthropic Claude Code runtime. Prefix-less model fallback is not implemented.
@@ -63,7 +63,8 @@ Do not write `providerOptions: { ... } satisfies QgridProviderOptions`: the expo
63
63
  rejected by the SDK before transport; omission keeps weighted round-robin routing.
64
64
  - `logger`: request-log switch. Omitted or `true` is the default and enables qgrid logging; `false` guarantees that generation creates zero qgrid request-log rows.
65
65
  - `sessionKey`: source for model-scoped opaque OpenAI prompt-cache affinity. Disabled for Anthropic models.
66
- - `effort`: provider-specific vocabulary. OpenAI (ChatGPT-subscription Codex route): `low | medium | high | xhigh | max | ultra`, where GPT-6 Astra, GPT-6 Sol, GPT-5.6 Sol, and Terra support `ultra`, and GPT-6 Luna and GPT-5.6 Luna support through `max`; the public OpenAI API's `none`/`minimal` do not exist on this route. Anthropic (Claude Code `--effort`): `low | medium | high | xhigh | max`. The server resolves the value per provider and model (`providers/common/effort.ts`): anything outside the provider set, or above the Codex model's supported maximum, is silently dropped and treated as unspecified — Anthropic falls back to qgrid's default `low`, OpenAI omits `reasoning` so the backend default applies. No error, no metadata; a debug log line only. Use `QgridOpenAIProviderOptions` / `QgridAnthropicProviderOptions` for provider-typed `satisfies`; `QgridProviderOptions` is their union.
66
+ - `thinking`: optional boolean for both providers. Omission preserves existing model behavior. True enables thinking with the normal request effort → config `defaultEffort` → default resolution; it does not guarantee thinking tokens on every response. False ignores both efforts, including in request logging, and rejects unsupported or unverified model/runtime combinations. Generate, stream, tool continuation, and structured output carry the same boolean. Update SDK and server together: older servers can ignore the field. No `defaultThinking` or public `effort: "none"` is exposed. Haiku/Sonnet 5.5 off requires Claude Code >=2.1.295; Sonnet uses `between_tools` and may retain thinking blocks between tools.
67
+ - `effort`: provider-specific vocabulary. OpenAI (ChatGPT-subscription Codex route): `low | medium | high | xhigh | max | ultra`, where GPT-6 Astra, GPT-6 Sol, GPT-5.6 Sol, and Terra support `ultra`, and GPT-6 Luna and GPT-5.6 Luna support through `max`; `none`/`minimal` are not public effort values; use `thinking: false` for verified off-capable models. Anthropic (Claude Code `--effort`): `low | medium | high | xhigh | max`. The server resolves the value per provider and model (`providers/common/effort.ts`): anything outside the provider set, or above the Codex model's supported maximum, is silently dropped and treated as unspecified. With thinking omitted, Anthropic falls back to qgrid's default `low`; OpenAI omits `reasoning.effort` so the backend default applies. With `thinking: true`, OpenAI explicitly falls back to `low` for absent or unsupported effort, including raw API requests. With `thinking: false`, both providers ignore caller/default effort and apply their off policy instead. Invalid effort itself produces no error or metadata, only a debug log; unsupported thinking-off requests still fail explicitly. Use `QgridOpenAIProviderOptions` / `QgridAnthropicProviderOptions` for provider-typed `satisfies`; `QgridProviderOptions` is their union.
67
68
  - `verbosity`: OpenAI/Codex route only.
68
69
  - `reasoningSummary`: OpenAI/Codex route only.
69
70
  - `serviceTier`: OpenAI/Codex route only.
@@ -77,7 +77,7 @@ claude -p
77
77
  --model <canonical-model-or-1m-suffix>
78
78
  --system-prompt <text> # small system prompt
79
79
  --system-prompt-file <path> # large system prompt
80
- --thinking disabled # omitted for Fable 5/5.1, Opus 5, Opus 5.5, Sonnet 5.5 and Haiku 5.5
80
+ --thinking <disabled|adaptive> # resolved from thinking and the existing model default
81
81
  --effort <effort-or-low>
82
82
  --disable-slash-commands
83
83
  --session-id <uuid>
@@ -97,7 +97,11 @@ Important details:
97
97
  - Large system prompts over 64 KiB are written to a temporary file to avoid argv `E2BIG` — this
98
98
  same branch absorbs large injected schema contracts, so the old 64 KiB schema argv limit no
99
99
  longer applies (only the global 512 KiB caller-schema complexity limit remains).
100
- - `--thinking disabled`, `MAX_THINKING_TOKENS=0`, and adaptive thinking env suppression keep thinking off for existing models. Fable 5, Fable 5.1, Opus 5.5, Sonnet 5.5 and Haiku 5.5 require always-on adaptive thinking (Fable: CLI catalog `rejects_disabled_thinking`; Opus 5.5: official spec, thinking cannot be turned off; Sonnet 5.5: API `{type: "disabled"}` returns 400 and the CLI catalog marks `rejects_disabled_thinking`; Haiku 5.5 (released 2026-10-07): the API accepts disabled thinking only at `high` effort or below and returns 400 at `xhigh`/`max`, and the Claude Code 2.1.293 catalog marks `rejects_disabled_thinking`). Opus 5 defaults to adaptive thinking and rejects disabled thinking at `xhigh`/`max` effort. qgrid omits all three suppressors for these models (`usesAdaptiveThinking`) and uses `effort` to control depth.
100
+ - One policy resolves the CLI thinking flag and effort before spawning. Omission preserves the existing model policy: Fable 5/5.1, Opus 5/5.5, Sonnet 5.5 and Haiku 5.5 keep adaptive defaults; other models use `--thinking disabled`. Explicit `true` uses `--thinking adaptive` and the normal effort resolution. Explicit `false` uses `--thinking disabled --effort low` only on supported models, ignoring caller/default effort. `CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING` and `MAX_THINKING_TOKENS` are no longer sent. Do not reintroduce overlapping suppressors or inherit `CLAUDE_CODE_EFFORT_LEVEL`.
101
+ - The 2026-10-10 off policy includes Haiku 4.5/5.5, Sonnet 4.5/4.6/5/5.5, and Opus 4.5/4.6/4.7/4.8/5. Fable 5/5.1 and Opus 5.5 reject disabled thinking at the backend. Off requests for unverified models fail before spawning instead of changing models or silently enabling thinking.
102
+ - Haiku 5.5 and Sonnet 5.5 require Claude Code 2.1.295 or newer for explicit false. Cache the result of `claude --version`; unknown or older versions return an input error. The policy computes `CLAUDE_CODE_EXTRA_BODY` containing only `thinking: {type: "disabled"}` for Haiku or `thinking: {type: "between_tools"}` for Sonnet, alongside `--thinking disabled --effort low`. Native delivery was verified on 2.1.295; invalid-type and Sonnet-disabled negative controls confirmed that the CLI applied the body field. `between_tools` disables pre-answer thinking but may emit thinking blocks between tools. Never inherit this env variable or expose arbitrary body overrides to callers.
103
+ - Legacy environment suppression versus CLI-only disabled was compared on Sonnet 4.6 and Opus 4.8: both completed with zero thinking tokens in the short-text baseline. The comparison supports removing the duplicate suppressors without changing the omitted-option policy.
104
+
101
105
 
102
106
  ## Spawn env
103
107
 
@@ -109,14 +113,13 @@ Included env:
109
113
  - `TMPDIR`
110
114
  - `CLAUDE_CODE_OAUTH_TOKEN`
111
115
  - `CLAUDE_CONFIG_DIR`
116
+ - `CLAUDE_CODE_EXTRA_BODY` only when computed by the thinking policy for explicit Haiku/Sonnet 5.5 off; never inherited
112
117
  - `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1`
113
- - `CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1` except for Fable 5/5.1 and Opus 5
114
118
  - `CLAUDE_CODE_DISABLE_CLAUDE_MDS=1`
115
119
  - `CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1`
116
120
  - `CLAUDE_CODE_DISABLE_BUNDLED_SKILLS=1`
117
121
  - `CLAUDE_CODE_DISABLE_WORKFLOWS=1`
118
122
  - `CLAUDE_CODE_ATTRIBUTION_HEADER=0`
119
- - `MAX_THINKING_TOKENS=0` except for Fable 5/5.1 and Opus 5
120
123
  - `CLAUDE_CODE_DISABLE_1M_CONTEXT=1` when model does not support qgrid's 1M path
121
124
  - `MAX_STRUCTURED_OUTPUT_RETRIES` for streaming structured output only (not non-streaming `generate`)
122
125
 
@@ -37,6 +37,15 @@ Key decisions:
37
37
  - The SDK should stay a thin adapter. Server APIs own request-log lifecycle, provider dispatch, structured-output emulation, and provider runtime details.
38
38
  - Request logging defaults to enabled. `providerOptions.qgrid.logger: false` is the single per-generation opt-out for both native qgrid logs and `createQgridLogger` telemetry logs; it must not alter generation or tool behavior.
39
39
 
40
+ ## Thinking Control
41
+
42
+ Source: `docs/plans/2026-10-10-001-feat-thinking-control-plan.md`.
43
+
44
+ - Use the independent `providerOptions.qgrid.thinking?: boolean` switch. False makes effort irrelevant; do not reject the combination or expose a cross-provider `effort: "none"` value.
45
+ - Preserve omitted-option behavior. Reject unsupported and runtime-unverified off requests before token acquisition/spawn, without fallback. Backend capability and Claude Code delivery are separate evidence.
46
+ - Use one Anthropic CLI thinking policy instead of overlapping environment suppressors. Preserve the OAuth env allowlist, token-specific config, empty settings, isolated cwd, memory/CLAUDE.md/skills/workflow disabling, tools, attribution, and 1M policy. These isolation controls prevent previously observed cross-request context injection and account metadata leakage.
47
+ - Haiku/Sonnet 5.5 use a narrowly computed native `CLAUDE_CODE_EXTRA_BODY` thinking field, guarded by Claude Code >=2.1.295. Do not inherit that variable, expose arbitrary body overrides, add a transport, or add a relay. Sonnet's `between_tools` exception remains visible: it turns off pre-answer thinking but can retain thinking blocks between tools.
48
+
40
49
  ## Tool Calling And Request-Log Lifecycle
41
50
 
42
51
  Sources:
@@ -12,6 +12,12 @@ Use this reference before changing OpenAI transport, concurrency, routing, promp
12
12
  - Direct quota lookup: `openai-quota.ts`.
13
13
  - Provider integration and history: `packages/api/src/application/qgrid/qgrid.dispatcher.ts`, `conv-routing.ts`.
14
14
 
15
+ ## Thinking control
16
+
17
+ `providerOptions.qgrid.thinking` reaches the Responses builder as a boolean. False overrides request/default effort and sends `reasoning: { effort: "none" }` without a reasoning summary. True uses a valid resolved effort, or explicitly sends `low` when effort is absent or unsupported, so a raw API request cannot fall back to a non-thinking backend default. Omission preserves the existing behavior: valid effort is forwarded; absent or unsupported effort leaves the backend default in effect. True and omission retain the requested reasoning summary policy. `none` belongs only to the internal wire type, not the public effort enum.
18
+
19
+ The 2026-10-10 subscription probe accepted off for `gpt-6-sol`, `gpt-6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, and `gpt-5.5`. `gpt-6-astra` and `gpt-6.1-sol` explicitly rejected it. Other model IDs are unverified for off and are rejected locally only when false is requested. Model-access failures are not evidence of mandatory thinking. Validate terminal success and response settings, not HTTP 200 alone: errors can arrive within SSE. The same policy applies to text-model requests driving image generation, not to the image model itself.
20
+
15
21
  ## Adding an OpenAI model
16
22
 
17
23
  Use this checklist whenever a model is added. A public API release does not by itself prove
@@ -60,6 +60,8 @@ Image-generation request logs add `is_image_generation`, `image_cost_usd`, and `
60
60
 
61
61
  In 2.9.8, list and detail model labels show requested model to image model for generated-image results, using an image serving model or the model recorded in `image_cost_method`. The cost fallback is an estimate, not an upstream version guarantee. Preserve the actual driver in stored `model_name` for hosted/auto turns. Do not hardcode a display version or render an image-generation/assumption badge. Auto text-only replies are not marked `is_image_generation`.
62
62
 
63
+ The list header ends its filter row with a reload button (2.10.2+) that calls the generated hooks' `refresh()` for the list and the total-cost query with the current filters; it does not refetch the token/project/model filter options, and TanStack Query's `isRefreshing` disables it while a reload is in flight.
64
+
63
65
  Structured output visibility: the list has an `Fmt` column (`json` badge from `is_structured` vs `text`) and a `broken` badge driven by `response_json_ok = false`; there is no broken-JSON list filter. At review time, all 114,647 succeeded structured rows had `response_json_ok = true` and zero false rows existed; the unindexed zero-result lookup scanned 1,286,016 rows and took about 3 seconds. Before reinstating the filter, validate the failure-signal semantics and index the predicate. The detail page shows a dark Response Type panel (zod expression by default, `type` declaration via toggle) rendered server-side from the stored `json_schema`. Plain-text rows render no panel. Rows written by pre-2.7.2 servers show `text`.
64
66
 
65
67
  Tool contract visibility: the detail page renders a Tools panel between Response Type and Steps for requests whose `tools` is non-empty. It starts collapsed and its header shows the tool count plus a responsive, truncated name list built from the detail subset — collapsed views issue no extra query. Expanding fires `toolsView` once and caches it for that request id, since a stored tool contract never changes. Each card shows the name, the full description, the parameter count, and a compact display-only zod shape; enum values past the sixth collapse to `/* +N */`, with the full shape reachable through hover and keyboard focus. All JSON Schema conversion happens server-side — the web renders completed strings and holds no schema logic.
@@ -72,7 +74,7 @@ Clicking an attached or generated image opens a preview with extension, decoded
72
74
 
73
75
  Token credential previews must tolerate missing `accessToken` rather than reading `.length` unconditionally. Legacy system-keychain credentials display `System Keychain`; this display compatibility does not enable an Antigravity runtime.
74
76
 
75
- Chat model presets: the model `<select>` lists the served subset of `QgridSupportedModel` grouped by provider (`MODEL_PRESET_GROUPS` in `ChatWidget.tsx`), newest first, and defaults to `anthropic/claude-fable-5-1`. Ids that the ChatGPT-subscription Codex route no longer serves (`gpt-5.4` and `gpt-5.4-mini` retired 2026-08-31 with `gpt-5.6-terra` / `gpt-5.6-luna` as replacements; `gpt-5.2` and `gpt-5.3-codex` removed earlier), `gpt-5.3-codex-spark` (rejected on the ChatGPT-account Codex route and absent from its catalog as of 2026-09-29), `gpt-5.5` (retires from the Codex/ChatGPT route on 2026-10-14; replacements `gpt-6.1-sol` / `gpt-6-luna`), the retired `claude-opus-4` / `claude-sonnet-4` (2026-06-15) and `claude-opus-4-1` (2026-08-05; Claude Code silently serves `claude-opus-5-5` instead), and the catalog-less `claude-sonnet-4-7` stay in the SDK type and price table (legacy request-log cost) but are excluded here. web does not depend on ai-sdk, so a new model must be added in both places. `openai/gpt-6-astra`, `openai/gpt-6.1-sol`, `openai/gpt-6-sol`, and `openai/gpt-6-luna` are included in the OpenAI group and `anthropic/claude-opus-5-5`, `anthropic/claude-sonnet-5-5`, and `anthropic/claude-haiku-5-5` in the Anthropic group; adding them does not change the default model.
77
+ Chat model presets: the model `<select>` lists the served subset of `QgridSupportedModel` grouped by provider (`MODEL_PRESET_GROUPS` in `ChatWidget.tsx`), newest first, and defaults to `anthropic/claude-fable-5-1`. Ids that the ChatGPT-subscription Codex route no longer serves (`gpt-5.4` and `gpt-5.4-mini` retired 2026-08-31 with `gpt-5.6-terra` / `gpt-5.6-luna` as replacements; `gpt-5.2` and `gpt-5.3-codex` removed earlier), `gpt-5.3-codex-spark` (rejected on the ChatGPT-account Codex route and absent from its catalog as of 2026-09-29), `gpt-5.5` (retires from the Codex/ChatGPT route on 2026-10-14; replacements `gpt-6.1-sol` / `gpt-6-luna`), the retired `claude-opus-4` / `claude-sonnet-4` (2026-06-15) and `claude-opus-4-1` (2026-08-05; Claude Code silently serves `claude-opus-5-5` instead), `claude-sonnet-4-5` (deprecated 2026-09-30, retirement 2026-11-30, replacement `claude-sonnet-5-5`), and the catalog-less `claude-sonnet-4-7` stay in the SDK type and price table (legacy request-log cost) but are excluded here. web does not depend on ai-sdk, so a new model must be added in both places. `openai/gpt-6-astra`, `openai/gpt-6.1-sol`, `openai/gpt-6-sol`, and `openai/gpt-6-luna` are included in the OpenAI group and `anthropic/claude-opus-5-5`, `anthropic/claude-sonnet-5-5`, and `anthropic/claude-haiku-5-5` in the Anthropic group; adding them does not change the default model.
76
78
 
77
79
  The monit tab's vitals strip shows per-provider in-flight counts, an in-flight sparkline, token chips with quota gauges (fed by the dispatcher's 60-second rate-limits cache; `resetsAt` arrives as ms epoch), and a 1-hour per-provider request/error/cache-hit stats line polled separately every 30 seconds.
78
80
 
@@ -253,6 +253,8 @@ Anthropic's 5-hour usage window anchors on the first request, so an unused token
253
253
 
254
254
  Keepalive breaks that coupling by burning the window clock during idle time. Every keepalive-enabled active Anthropic token gets one cheap request as soon as its window expires, so windows always run and a workday lands mid-window rather than on a boundary. Across an eight-hour day this raises the number of windows the day can touch from a fixed 2 to an expected 2.6.
255
255
 
256
+ The keepalive request uses `anthropic/claude-haiku-5-5`, `thinking: false`, `effort: "low"`, and the prompt `Reply OK.`. Thinking is disabled because this request only opens the usage window; the false policy overrides the supplied effort and uses the provider's low-effort off path. Haiku 5.5 off requires Claude Code >=2.1.295. The model constant lives in `token-window-keepalive.ts`; changing it does not change the scheduler or opt-in gates below.
257
+
256
258
  - Since 2.8.0 (`ea7feb3`) keepalive is opt-in at two levels. The runner instance must have env `QGRID_TOKEN_WINDOW_KEEPALIVE_ENABLED=true` (default off; set it on one instance per shared DB), and a token is a target only when `tokens.keepalive_enabled` is `true` (default `false`, toggled in the dashboard settings panel). The global setting `qgrid.tokenWindowKeepaliveEnabled` is a kill switch (`false` disables everything), not a substitute for either gate. In 2.7.6 every instance fired for every active token.
257
259
  - Operational trap: the 2.8.0 migration adds `keepalive_enabled` as default `false` without backfilling existing tokens. After upgrading, both the runner env and the per-token toggles must be set, or keepalive silently schedules zero tokens. This happened on dev0 after the 2026-08-31 self-update; a lingering 2.7.6 instance masked it until 2026-09-01. Diagnose with `GET /api/setting/listSettings` (`keepaliveRunnerEnabled`), `GET /api/token/findMany?subset=A` (`keepalive_enabled`), and the latest request log under project `qgrid-token-window-keepalive`.
258
260
  - The next fire is scheduled from the token's real `resetsAt` rather than a fixed five-hour timer, so a provider-side change to the window length is followed automatically.
@@ -24,6 +24,16 @@ qgrid supports the AI SDK `tools` interface, but it does not use native provider
24
24
  - qgrid maps that structured object back into AI SDK `tool-call` content.
25
25
  - The AI SDK executes the actual tool functions and calls qgrid again with tool results.
26
26
 
27
+ OpenAI can emit separate commentary and final-answer message items in one response.
28
+ Plain commentary is an intermediate update, not an emulation payload: do not join
29
+ it to the final JSON. Known final-answer message deltas still stream incrementally.
30
+ For tool emulation, a complete message that passes the strict envelope and tool-name
31
+ validation with `action: tool_call` is the client handoff boundary. Stop aggregating
32
+ and streaming later text from that response: it cannot incorporate a tool result
33
+ that the client has not produced yet. Drain the upstream response to preserve usage,
34
+ errors, and cancellation. Never split concatenated JSON inside a single message or
35
+ recover malformed envelopes. Ordinary text requests keep their existing aggregation.
36
+
27
37
  `generateText` and `streamText` default to `stepCountIs(1)`. When an executable
28
38
  tool can run before the final answer, callers must set a bounded `stopWhen`
29
39
  (for example `stepCountIs(3)`) or the AI SDK stops after the first tool-call
@@ -99,9 +109,16 @@ The schema explicitly tells the model:
99
109
 
100
110
  - use `tool_call` when client-side tool execution is needed;
101
111
  - use `answer` only for a final answer;
102
- - do not invoke listed tools as native Claude Code tools;
112
+ - return the tool request as the JSON response body, then end the turn and wait for client results;
113
+ - do not invent tool results or emit an answer before the required results arrive;
103
114
  - put tool arguments in `args` as a JSON string.
104
115
 
116
+ Do not instruct OpenAI to use a `StructuredOutput` or Claude Code tool: neither is
117
+ provided on this route. The legacy schema descriptions contained that stale
118
+ instruction; schema descriptions now explain the actual client handoff protocol.
119
+ The discriminated union, required fields, argument encoding and user-schema refs
120
+ are unchanged. Prompt wording improves guidance but does not guarantee model compliance.
121
+
105
122
  Delivery differs by provider (SON-532). OpenAI: `qgrid.dispatcher.ts` strictifies the composed
106
123
  envelope through `buildStrictOutputSchema` and passes it as the response format — constrained
107
124
  decoding enforces it. Anthropic: no schema is passed to CC at all; `schema-prompt.ts` renders the
@@ -149,7 +149,7 @@ Generated SSE handlers missing a newly added event field:
149
149
  `NO_OPENAI_WORKERS`:
150
150
 
151
151
  - The request path returns this only when there is no active OpenAI token candidate; there is no queue and no busy state.
152
- - Check active OpenAI tokens and credential state (`OpenAIDispatcher.tokenCount`).
152
+ - Check active OpenAI tokens and credential state (`OpenAIDispatcher.countActiveTokens()`).
153
153
  - If tokens were recently changed, inspect `TokenSubscriber` status and reconcile behavior.
154
154
 
155
155
  `NO_ACTIVE_WORKERS`:
@@ -1 +0,0 @@
1
- import"./rolldown-runtime-Dw2cE7zH.js";import{l as e,u as t}from"./vendor-tanstack-DJRQAbrY.js";import{i as n,r}from"./vendor-react-DH4kUfK2.js";import{C as i,S as a,n as o,o as s,r as c}from"./services.generated-Cbvg2sGQ.js";import{i as l,n as u,r as d}from"./index-Cq4_ExLO.js";import{n as f,r as p,t as m}from"./cost-CpjVoAqp.js";import{t as h}from"./request-model-eygfdRv7.js";n();var g=r(),_=e=>(0,g.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,g.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,d:`m15 18l-6-6l6-6`})}),v=e=>(0,g.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,g.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,d:`m9 18l6-6l-6-6`})}),y=50,b=`__unassigned__`;function x(e){let t=new Date(e);return`${String(t.getMonth()+1).padStart(2,`0`)}-${String(t.getDate()).padStart(2,`0`)} ${String(t.getHours()).padStart(2,`0`)}:${String(t.getMinutes()).padStart(2,`0`)}`}function S(e){return e.toLocaleString()}function C(e){let t=Math.round(e/1e3),n=Math.floor(t/60),r=t%60;return n>0?`${n}m ${r}s`:`${r}s`}function w({status:e,requestedModel:t,servedModel:n,imageCostMethod:r,fallbackCount:i}){if(e===`running`)return(0,g.jsx)(`span`,{className:`text-[9px] px-1.5 py-0.5 rounded-full bg-blue-100 text-blue-600 font-medium whitespace-nowrap`,children:`실행 중`});let a=h({status:e,requestedModel:t,servedModel:n,imageCostMethod:r}),o=t!==null&&n===null;return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`text-xs text-sand-500`,children:a.label}),o&&(0,g.jsx)(`span`,{className:`ml-1 text-[9px] text-sand-400`,children:`요청`}),(i??0)>0&&(0,g.jsxs)(`span`,{className:`ml-1 text-[9px] text-caution-500`,children:[`×`,i]})]})}function T(e){return e<=0?`—`:e>=1e3?`${(e/1e3).toFixed(1)}s`:`${e}ms`}var E=[{label:`ID`,align:`left`,width:`w-12`,sortKey:`id`},{label:`Date`,align:`left`,width:`w-20`,sortKey:`created_at`},{label:`Project`,align:`left`,width:`w-20`},{label:`Token`,align:`left`,width:`w-24`},{label:`Model`,align:`left`,width:`w-20`},{label:`Fmt`,align:`left`,width:`w-12`},{label:`TTFT`,align:`right`,width:`w-16`,sortKey:`ttft_ms`},{label:`Duration`,align:`right`,width:`w-20`,sortKey:`duration_ms`},{label:`In`,align:`right`,width:`w-16`,sortKey:`input_tokens`},{label:`Out`,align:`right`,width:`w-20`,sortKey:`output_tokens`},{label:`C.Read`,align:`right`,width:`w-20`,sortKey:`cache_read_tokens`},{label:`C.Write`,align:`right`,width:`w-20`,sortKey:`cache_creation_tokens`},{label:`Hit`,align:`right`,width:`w-14`},{label:`Tools`,align:`right`,width:`w-14`},{label:`Cost`,align:`right`,width:`w-20`,sortKey:`cost_usd`}];function D({search:n,onSearchChange:r}){let i=t(),a=n.page??1,u=n.token??``,d=n.project??``,h=n.model??``,{data:D}=s.useTokens(`A`),O=(D?.rows??[]).map(e=>e.name).filter(Boolean),{data:k}=o.useProjectNames(),A=k?.names??[],{data:j}=o.useModelNames(),M=j?.names??[],N=d===b?{project_name_is_null:!0}:d?{project_name:d}:{},P={...u?{token_name:u}:{},...N,...h?{model_name:h}:{}},F=n.sort??`id-desc`,I=F.lastIndexOf(`-`),L=F.slice(0,I),R=F.slice(I+1)===`asc`?`asc`:`desc`,{data:z,isLoading:B,isError:V}=c.useRequestLogs(`P`,{num:y,page:a,orderBy:F,...P}),{data:H,isError:U}=o.useTotalCost({num:0,page:1,...P}),W=z?.rows??[],G=z?.total??0,K=Math.ceil(G/y),q=e=>{r({...n,...e,page:1})};return(0,g.jsxs)(`div`,{className:`panel overflow-hidden`,children:[(0,g.jsxs)(`div`,{className:`panel-header flex items-center gap-2 px-3 py-2.5 flex-wrap sm:gap-3 sm:px-5`,children:[(0,g.jsxs)(`select`,{value:u,onChange:e=>q({token:e.target.value||void 0}),disabled:O.length===0,className:`border border-sand-200/80 rounded-lg px-2.5 py-1.5 text-[11px] text-sand-700 bg-sand-50/50 focus:outline-none focus:border-sienna-300 disabled:text-sand-300 disabled:cursor-not-allowed`,children:[(0,g.jsx)(`option`,{value:``,children:O.length>0?`All Tokens`:`Tokens —`}),O.map(e=>(0,g.jsx)(`option`,{value:e,children:e},e))]}),(0,g.jsxs)(`select`,{value:d,onChange:e=>q({project:e.target.value||void 0}),className:`border border-sand-200/80 rounded-lg px-2.5 py-1.5 text-[11px] text-sand-700 bg-sand-50/50 focus:outline-none focus:border-sienna-300`,children:[(0,g.jsx)(`option`,{value:``,children:`All Projects`}),(0,g.jsx)(`option`,{value:b,children:`(unassigned)`}),A.map(e=>(0,g.jsx)(`option`,{value:e,children:e},e))]}),(0,g.jsxs)(`select`,{value:h,onChange:e=>q({model:e.target.value||void 0}),disabled:M.length===0,className:`border border-sand-200/80 rounded-lg px-2.5 py-1.5 text-[11px] text-sand-700 bg-sand-50/50 focus:outline-none focus:border-sienna-300 disabled:text-sand-300 disabled:cursor-not-allowed`,children:[(0,g.jsx)(`option`,{value:``,children:M.length>0?`All Models`:`Models —`}),M.map(e=>(0,g.jsx)(`option`,{value:e,children:e},e))]}),(0,g.jsx)(`div`,{className:`flex-1`}),(0,g.jsxs)(`span`,{className:`text-[11px] text-sand-400`,children:[V||!z?`—`:G,` results`]}),U?(0,g.jsx)(`span`,{role:`alert`,className:`text-[11px] text-danger-500`,children:`Failed to load total cost.`}):(0,g.jsx)(`span`,{className:`text-[11px] tabular-nums font-medium text-sienna-600`,children:H?p(H.usd):`—`})]}),V?(0,g.jsx)(`div`,{role:`alert`,className:`text-danger-500 text-center py-12 text-sm`,children:`Failed to load request logs.`}):B?(0,g.jsx)(`div`,{className:`space-y-2`,children:Array.from({length:5}).map((e,t)=>(0,g.jsx)(`div`,{className:`h-8 bg-sand-100 rounded animate-pulse`},`skel-${t}`))}):W.length===0?(0,g.jsx)(`div`,{className:`text-sand-400 text-center py-12 text-sm`,children:`No requests yet.`}):(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`div`,{className:`overflow-x-auto px-3 py-3 sm:px-5`,children:(0,g.jsxs)(`table`,{className:`w-full min-w-[900px] text-[13px]`,children:[(0,g.jsx)(`thead`,{children:(0,g.jsxs)(`tr`,{className:`border-b border-sand-100/60`,children:[E.map(e=>{let t=e.label===`Duration`?`pl-5 pr-3`:e.width?`px-4`:`px-3`,n=e.sortKey===L;return(0,g.jsx)(`th`,{className:`${e.align===`right`?`text-right`:`text-left`} ${e.width??``} ${e.width?`whitespace-nowrap`:``} ${t} py-1.5 text-[10px] uppercase font-medium ${n?`text-sienna-600`:`text-sand-400`}`,children:e.sortKey?(0,g.jsxs)(`button`,{type:`button`,onClick:()=>q({sort:l.parse(`${e.sortKey}-${n&&R===`desc`?`asc`:`desc`}`)}),className:`inline-flex items-center gap-0.5 text-[10px] uppercase font-medium hover:text-sienna-500 transition-colors duration-150 ${e.align===`right`?`justify-end w-full`:``}`,children:[e.label,(0,g.jsx)(`span`,{className:n?``:`text-sand-300`,children:n?R===`desc`?`↓`:`↑`:`↕`})]}):e.label},e.label)}),(0,g.jsx)(`th`,{className:`w-8`})]})}),(0,g.jsx)(`tbody`,{className:`divide-y divide-sand-100/60`,children:W.map(t=>(0,g.jsxs)(`tr`,{className:`transition-colors duration-150 hover:bg-sand-100/60 cursor-pointer`,onClick:e=>{if(e.metaKey||e.ctrlKey){window.open(`/requests/show?id=${t.id}`,`_blank`);return}i({to:`/requests/show`,search:{id:t.id}})},children:[(0,g.jsx)(`td`,{className:`px-4 py-1.5 whitespace-nowrap`,children:(0,g.jsx)(e,{to:`/requests/show`,search:{id:t.id},onClick:e=>e.stopPropagation(),className:`text-xs text-sand-500 tabular-nums hover:text-sienna-500`,children:t.id})}),(0,g.jsx)(`td`,{className:`px-4 py-1.5 whitespace-nowrap`,children:(0,g.jsx)(`span`,{className:`text-xs text-sand-400 tabular-nums`,children:x(t.created_at)})}),(0,g.jsx)(`td`,{className:`px-4 py-1.5 whitespace-nowrap`,children:(0,g.jsx)(`span`,{className:`text-xs text-sand-600`,children:t.project_name??`—`})}),(0,g.jsx)(`td`,{className:`px-4 py-1.5 whitespace-nowrap`,children:(0,g.jsx)(`span`,{className:`text-xs text-sand-500`,children:t.token_name})}),(0,g.jsxs)(`td`,{className:`px-4 py-1.5 whitespace-nowrap`,children:[(0,g.jsx)(w,{status:t.status,requestedModel:t.requested_model_name,servedModel:t.model_name,imageCostMethod:t.image_cost_method,fallbackCount:t.fallback_count}),t.response_json_ok===!1&&(0,g.jsx)(`span`,{title:`structured 요청의 응답이 JSON 파싱에 실패했습니다`,className:`ml-1.5 rounded-full bg-caution-400/15 px-1.5 py-0.5 text-[9px] font-semibold text-caution-500`,children:`broken`})]}),(0,g.jsx)(`td`,{className:`px-4 py-1.5 whitespace-nowrap`,children:t.is_structured?(0,g.jsx)(`span`,{className:`rounded bg-sienna-100 px-1.5 py-0.5 font-mono text-[10px] text-sienna-700`,children:`json`}):(0,g.jsx)(`span`,{className:`font-mono text-[10px] text-sand-400`,children:`text`})}),(0,g.jsx)(`td`,{className:`px-4 py-1.5 text-right tabular-nums text-sand-500 whitespace-nowrap`,children:T(t.ttft_ms)}),(0,g.jsx)(`td`,{className:`pl-5 pr-3 py-1.5 text-right tabular-nums text-sand-500 whitespace-nowrap`,children:C(t.duration_ms)}),(0,g.jsx)(`td`,{className:`px-3 py-1.5 text-right tabular-nums text-sand-700`,children:S(t.input_tokens)}),(0,g.jsx)(`td`,{className:`px-3 py-1.5 text-right tabular-nums text-sand-700`,children:S(t.output_tokens)}),(0,g.jsx)(`td`,{className:`px-3 py-1.5 text-right tabular-nums text-sand-700`,children:S(t.cache_read_tokens)}),(0,g.jsx)(`td`,{className:`px-3 py-1.5 text-right tabular-nums text-sand-700`,children:S(t.cache_creation_tokens)}),(0,g.jsx)(`td`,{className:`px-3 py-1.5 text-right tabular-nums text-sand-700`,children:m(t)}),(0,g.jsx)(`td`,{className:`px-3 py-1.5 text-right tabular-nums text-sand-500`,children:t.tool_call_count>0?t.tool_call_count:`—`}),(0,g.jsx)(`td`,{className:`px-3 py-1.5 text-right tabular-nums text-sand-700`,children:t.image_cost_usd===null?t.cost_usd===null?`—`:f(t.cost_usd):f((t.cost_usd??0)+t.image_cost_usd)}),(0,g.jsx)(`td`,{className:`px-2 py-1.5`,children:(0,g.jsx)(v,{className:`size-4 text-sand-400`})})]},t.id))})]})}),K>1&&(0,g.jsxs)(`div`,{className:`flex items-center justify-center gap-3 px-5 py-2.5 border-t border-sand-100/60`,children:[(0,g.jsx)(`button`,{type:`button`,className:`p-1 rounded text-sand-400 hover:text-sand-600 disabled:opacity-30 transition-colors`,disabled:a===1,onClick:()=>r({...n,page:a-1}),children:(0,g.jsx)(_,{className:`size-4`})}),(0,g.jsxs)(`span`,{className:`text-[11px] text-sand-400 tabular-nums`,children:[a,` / `,K]}),(0,g.jsx)(`button`,{type:`button`,className:`p-1 rounded text-sand-400 hover:text-sand-600 disabled:opacity-30 transition-colors`,disabled:a===K,onClick:()=>r({...n,page:a+1}),children:(0,g.jsx)(v,{className:`size-4`})})]})]})]})}a({token:i().optional(),project:i().optional(),model:i().optional(),sort:l.optional(),page:d.shape.page.default(1)});function O(){let e=u.useSearch(),t=u.useNavigate();return(0,g.jsx)(`div`,{className:`max-w-[100rem] mx-auto`,children:(0,g.jsx)(D,{search:e,onSearchChange:e=>t({search:e})})})}export{O as component};
@@ -1 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{_ as t}from"./vendor-tanstack-DJRQAbrY.js";import{i as n,n as r,r as i}from"./vendor-react-DH4kUfK2.js";import{S as a,h as o,t as s}from"./services.generated-Cbvg2sGQ.js";import{a as c,s as l}from"./index-Cq4_ExLO.js";import{t as u}from"./cost-CpjVoAqp.js";var d=e(n(),1),f=e(r(),1);function p(e,t,n){let r=Array(e);return new Proxy(r,{get(r,i,a){if(typeof i==`string`){let a=i.charCodeAt(0);if(a>=48&&a<=57){let a=+i;if(Number.isInteger(a)&&a>=0&&a<e){let e=r[a];if(!e){let i=t[a*2];e=r[a]={index:a,key:n(a),start:i,size:t[a*2+1],end:i+t[a*2+1],lane:0}}return e}}if(i===`length`)return e}return Reflect.get(r,i,a)}})}function m(e,t,n){let r=n.initialDeps??[],i,a=!0;function o(){let o=e();return o.length!==r.length||o.some((e,t)=>r[t]!==e)?(r=o,i=t(...o),n?.onChange&&!(a&&n.skipInitialOnChange)&&n.onChange(i),a=!1,i):i}return o.updateDeps=e=>{r=e},o}function h(e,t){if(e===void 0)throw Error(`Unexpected undefined${t?`: ${t}`:``}`);return e}var g=(e,t)=>Math.abs(e-t)<1.01,_=(e,t,n)=>{let r;return function(...i){e.clearTimeout(r),r=e.setTimeout(()=>t.apply(this,i),n)}},v,y=()=>{if(v!==void 0)return v;if(typeof navigator>`u`)return v=!1;if(/iP(hone|od|ad)/.test(navigator.userAgent))return v=!0;let e=navigator.maxTouchPoints;return v=navigator.platform===`MacIntel`&&e!==void 0&&e>0},b=e=>{let{offsetWidth:t,offsetHeight:n}=e;return{width:t,height:n}},x=e=>e,S=e=>{let t=Math.max(e.startIndex-e.overscan,0),n=Math.min(e.endIndex+e.overscan,e.count-1)-t+1,r=Array(n);for(let e=0;e<n;e++)r[e]=t+e;return r},C=(e,t)=>{let n=e.scrollElement;if(!n)return;let r=e.targetWindow;if(!r)return;let i=e=>{let{width:n,height:r}=e;t({width:Math.round(n),height:Math.round(r)})};if(i(b(n)),!r.ResizeObserver)return()=>{};let a=new r.ResizeObserver(t=>{let r=()=>{let e=t[0];if(e?.borderBoxSize){let t=e.borderBoxSize[0];if(t){i({width:t.inlineSize,height:t.blockSize});return}}i(b(n))};e.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(r):r()});return a.observe(n,{box:`border-box`}),()=>{a.unobserve(n)}},w={passive:!0},T=typeof window>`u`?!0:`onscrollend`in window,E=(e,t,n)=>{let r=e.scrollElement;if(!r)return;let i=e.targetWindow;if(!i)return;let a=e.options.useScrollendEvent&&T,o=0,s=a?null:_(i,()=>t(o,!1),e.options.isScrollingResetDelay),c=e=>()=>{o=n(r),s?.(),t(o,e)},l=c(!0),u=c(!1);return r.addEventListener(`scroll`,l,w),a&&r.addEventListener(`scrollend`,u,w),()=>{r.removeEventListener(`scroll`,l),a&&r.removeEventListener(`scrollend`,u)}},D=(e,t)=>E(e,t,t=>{let{horizontal:n,isRtl:r}=e.options;return n?t.scrollLeft*(r&&-1||1):t.scrollTop}),O=(e,t,n)=>{if(n.options.useCachedMeasurements){let t=n.indexFromElement(e),r=n.options.getItemKey(t);return n.itemSizeCache.get(r)??n.options.estimateSize(t)}if(t?.borderBoxSize){let e=t.borderBoxSize[0];if(e)return Math.round(e[n.options.horizontal?`inlineSize`:`blockSize`])}if(!t){let t=n.indexFromElement(e),r=n.options.getItemKey(t),i=n.itemSizeCache.get(r);if(i!==void 0)return i}return e[n.options.horizontal?`offsetWidth`:`offsetHeight`]},k=(e,{adjustments:t=0,behavior:n},r)=>{var i,a;(a=(i=r.scrollElement)?.scrollTo)==null||a.call(i,{[r.options.horizontal?`left`:`top`]:e+t,behavior:n})},A=class{constructor(e){this.unsubs=[],this.scrollElement=null,this.targetWindow=null,this.isScrolling=!1,this.scrollState=null,this.measurementsCache=[],this._flatMeasurements=null,this.itemSizeCache=new Map,this.itemSizeCacheVersion=0,this.laneAssignments=new Map,this.pendingMin=null,this.prevLanes=void 0,this.lanesChangedFlag=!1,this.lanesSettling=!1,this.pendingScrollAnchor=null,this.scrollRect=null,this.scrollOffset=null,this.scrollDirection=null,this.scrollAdjustments=0,this._iosDeferredAdjustment=0,this._iosTouching=!1,this._iosJustTouchEnded=!1,this._iosTouchEndTimerId=null,this._intendedScrollOffset=null,this.elementsCache=new Map,this.now=()=>{var e;return((e=this.targetWindow?.performance)?.now)?.call(e)??Date.now()},this.observer=(()=>{let e=null,t=()=>e||(!this.targetWindow||!this.targetWindow.ResizeObserver?null:e=new this.targetWindow.ResizeObserver(e=>{e.forEach(e=>{let t=()=>{let t=e.target,n=this.indexFromElement(t);if(!t.isConnected){this.observer.unobserve(t);for(let[e,n]of this.elementsCache)if(n===t){this.elementsCache.delete(e);break}return}this.shouldMeasureDuringScroll(n)&&this.resizeItem(n,this.options.measureElement(t,e,this))};this.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(t):t()})}));return{disconnect:()=>{var n;(n=t())==null||n.disconnect(),e=null},observe:e=>t()?.observe(e,{box:`border-box`}),unobserve:e=>t()?.unobserve(e)}})(),this.range=null,this.setOptions=e=>{let t={debug:!1,initialOffset:0,overscan:1,paddingStart:0,paddingEnd:0,scrollPaddingStart:0,scrollPaddingEnd:0,horizontal:!1,getItemKey:x,rangeExtractor:S,onChange:()=>{},measureElement:O,initialRect:{width:0,height:0},scrollMargin:0,gap:0,indexAttribute:`data-index`,initialMeasurementsCache:[],lanes:1,anchorTo:`start`,followOnAppend:!1,scrollEndThreshold:1,isScrollingResetDelay:150,enabled:!0,isRtl:!1,useScrollendEvent:!1,useAnimationFrameWithResizeObserver:!1,laneAssignmentMode:`estimate`,useCachedMeasurements:!1};for(let n in e){let r=e[n];r!==void 0&&(t[n]=r)}let n=this.options,r=null,i=null,a=!1;if(n!==void 0&&n.enabled&&t.enabled&&t.anchorTo===`end`&&this.scrollElement!==null){let e=n.count,o=t.count,s=this.getMeasurements(),c=e>0?s[0]?.key??n.getItemKey(0):null,l=e>0?s[e-1]?.key??n.getItemKey(e-1):null;if(o!==e||e>0&&o>0&&(t.getItemKey(0)!==c||t.getItemKey(o-1)!==l)){a=!0;let c=e>0?this.getVirtualItemForOffset(this.getScrollOffset())??s[0]:null;c&&(r=[c.key,this.getScrollOffset()-c.start]);let u=t.followOnAppend===!0?`auto`:t.followOnAppend||null;u&&o>e&&this.isAtEnd(n.scrollEndThreshold)&&(e===0||t.getItemKey(o-1)!==l)&&(i=u)}}this.options=t,a&&(this.pendingMin=0,this.itemSizeCacheVersion++);let o=!1,s=0;if(r&&this.scrollOffset!==null){let[e,t]=r,n=this.getMeasurements(),{count:i,getItemKey:a}=this.options,c=0;for(;c<i&&a(c)!==e;)c++;if(c<i){let e=n[c];if(e){let n=e.start+t;n!==this.scrollOffset&&(s=n-this.scrollOffset,this.scrollOffset=n,o=!0)}}}(o||i)&&(this.pendingScrollAnchor=[o?r[0]:null,o?r[1]:0,i,s])},this.notify=e=>{var t,n;(n=(t=this.options).onChange)==null||n.call(t,this,e)},this.maybeNotify=m(()=>(this.calculateRange(),[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]),e=>{this.notify(e)},{key:!1,debug:()=>this.options.debug,initialDeps:[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]}),this.cleanup=()=>{this.unsubs.filter(Boolean).forEach(e=>e()),this.unsubs=[],this.observer.disconnect(),this.rafId!=null&&this.targetWindow&&(this.targetWindow.cancelAnimationFrame(this.rafId),this.rafId=null),this.scrollState=null,this._iosDeferredAdjustment=0,this._iosTouching=!1,this._iosJustTouchEnded=!1,this.scrollElement=null,this.targetWindow=null},this._didMount=()=>()=>{this.cleanup()},this._willUpdate=()=>{let e=this.options.enabled?this.options.getScrollElement():null;if(this.scrollElement!==e){if(this.cleanup(),!e){this.maybeNotify();return}if(this.scrollElement=e,this.scrollElement&&`ownerDocument`in this.scrollElement?this.targetWindow=this.scrollElement.ownerDocument.defaultView:this.targetWindow=this.scrollElement?.window??null,this.elementsCache.forEach(e=>{this.observer.observe(e)}),this.unsubs.push(this.options.observeElementRect(this,e=>{this.scrollRect=e,this.maybeNotify()})),this.unsubs.push(this.options.observeElementOffset(this,(e,t)=>{if(t&&this._intendedScrollOffset===null&&e===this.scrollOffset)return;this._intendedScrollOffset!==null&&Math.abs(e-this._intendedScrollOffset)<1.5&&(e=this._intendedScrollOffset),this._intendedScrollOffset=null,this.scrollAdjustments=0;let n=this.getScrollOffset();this.scrollDirection=t?n===e?this.scrollDirection:n<e?`forward`:`backward`:null,this.scrollOffset=e,this.isScrolling=t,this._flushIosDeferredIfReady(),this.scrollState&&this.scheduleScrollReconcile(),this.maybeNotify()})),`addEventListener`in this.scrollElement){let e=this.scrollElement,t=()=>{this._iosTouching=!0,this._iosJustTouchEnded=!1,this._iosTouchEndTimerId!==null&&this.targetWindow!=null&&(this.targetWindow.clearTimeout(this._iosTouchEndTimerId),this._iosTouchEndTimerId=null)},n=()=>{this._iosTouching=!1,!(!y()||this.targetWindow==null)&&(this._iosJustTouchEnded=!0,this._iosTouchEndTimerId=this.targetWindow.setTimeout(()=>{this._iosJustTouchEnded=!1,this._iosTouchEndTimerId=null,this._flushIosDeferredIfReady()},150))};e.addEventListener(`touchstart`,t,w),e.addEventListener(`touchend`,n,w),this.unsubs.push(()=>{e.removeEventListener(`touchstart`,t),e.removeEventListener(`touchend`,n),this._iosTouchEndTimerId!==null&&this.targetWindow!=null&&(this.targetWindow.clearTimeout(this._iosTouchEndTimerId),this._iosTouchEndTimerId=null)})}this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0})}let t=this.pendingScrollAnchor;if(this.pendingScrollAnchor=null,t&&this.scrollElement&&this.options.enabled){let[e,n,r,i]=t;e!==null&&!r&&(y()&&(this.isScrolling||this._iosTouching||this._iosJustTouchEnded)?i!==0&&(this._iosDeferredAdjustment+=i):this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0})),r&&this.scrollToEnd({behavior:r})}},this._flushIosDeferredIfReady=()=>{if(this._iosDeferredAdjustment===0||this.isScrolling||this._iosTouching||this._iosJustTouchEnded)return;let e=this.getScrollOffset(),t=this.getMaxScrollOffset();if(e<0||e>t)return;let n=this._iosDeferredAdjustment;this._iosDeferredAdjustment=0,this._scrollToOffset(e,{adjustments:this.scrollAdjustments+=n,behavior:void 0})},this.rafId=null,this.getSize=()=>this.options.enabled?(this.scrollRect=this.scrollRect??this.options.initialRect,this.scrollRect[this.options.horizontal?`width`:`height`]):(this.scrollRect=null,0),this.getScrollOffset=()=>this.options.enabled?(this.scrollOffset=this.scrollOffset??(typeof this.options.initialOffset==`function`?this.options.initialOffset():this.options.initialOffset),this.scrollOffset):(this.scrollOffset=null,0),this.getMeasurementOptions=m(()=>[this.options.count,this.options.paddingStart,this.options.scrollMargin,this.options.getItemKey,this.options.enabled,this.options.lanes,this.options.laneAssignmentMode,this.options.gap],(e,t,n,r,i,a,o,s)=>(this.prevLanes!==void 0&&this.prevLanes!==a&&(this.lanesChangedFlag=!0),this.prevLanes=a,this.pendingMin=null,{count:e,paddingStart:t,scrollMargin:n,getItemKey:r,enabled:i,lanes:a,laneAssignmentMode:o,gap:s}),{key:!1}),this.getMeasurements=m(()=>[this.getMeasurementOptions(),this.itemSizeCacheVersion],({count:e,paddingStart:t,scrollMargin:n,getItemKey:r,enabled:i,lanes:a,laneAssignmentMode:o,gap:s},c)=>{let l=this.itemSizeCache;if(!i)return this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),[];if(this.laneAssignments.size>e)for(let t of this.laneAssignments.keys())t>=e&&this.laneAssignments.delete(t);this.lanesChangedFlag&&(this.lanesChangedFlag=!1,this.lanesSettling=!0,this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),this.pendingMin=null),this.measurementsCache.length===0&&!this.lanesSettling&&(this.measurementsCache=this.options.initialMeasurementsCache,this.measurementsCache.forEach(e=>{this.itemSizeCache.set(e.key,e.size)}));let u=this.lanesSettling?0:this.pendingMin??0;if(this.pendingMin=null,this.lanesSettling&&this.measurementsCache.length===e&&(this.lanesSettling=!1),a===1){let i=e*2,a=this._flatMeasurements;if(!a||a.length<i){let e=new Float64Array(i);a&&u>0&&e.set(a.subarray(0,u*2)),a=e,this._flatMeasurements=a}let o;if(u===0)o=t+n;else{let e=u-1;o=a[e*2]+a[e*2+1]+s}for(let t=u;t<e;t++){let e=r(t),n=l.get(e),i=typeof n==`number`?n:this.options.estimateSize(t);a[t*2]=o,a[t*2+1]=i,o+=i+s}let c=p(e,a,r);return this.measurementsCache=c,c}let d=this.measurementsCache.slice(0,u),f=Array(a).fill(void 0),m=new Float64Array(a),h=0;for(let e=0;e<u;e++){let t=d[e];t&&(f[t.lane]===void 0&&h++,f[t.lane]=e,m[t.lane]=t.end)}for(let i=u;i<e;i++){let e=r(i),c=this.laneAssignments.get(i),u,p,g=o===`estimate`||l.has(e);if(c!==void 0&&this.options.lanes>1){u=c;let e=f[u],r=e===void 0?void 0:d[e];p=r?r.end+s:t+n}else if(h===a){let e=0,t=m[0],n=f[0];for(let r=1;r<a;r++){let i=m[r];(i<t||i===t&&f[r]<n)&&(e=r,t=i,n=f[r])}u=e,p=t+s,g&&this.laneAssignments.set(i,u)}else u=i%this.options.lanes,p=t+n,g&&this.laneAssignments.set(i,u);let _=l.get(e),v=typeof _==`number`?_:this.options.estimateSize(i),y=p+v;d[i]={index:i,start:p,size:v,end:y,key:e,lane:u},f[u]===void 0&&h++,f[u]=i,m[u]=y}return this.measurementsCache=d,d},{key:!1,debug:()=>this.options.debug}),this.calculateRange=m(()=>[this.getMeasurements(),this.getSize(),this.getScrollOffset(),this.options.lanes],(e,t,n,r)=>e.length===0||t===0?(this.range=null,null):(this.range=N(e,t,n,r,r===1&&this._flatMeasurements!=null?this._flatMeasurements:null),this.range),{key:!1,debug:()=>this.options.debug}),this.getVirtualIndexes=m(()=>{let e=null,t=null,n=this.calculateRange();return n&&(e=n.startIndex,t=n.endIndex),this.maybeNotify.updateDeps([this.isScrolling,e,t]),[this.options.rangeExtractor,this.options.overscan,this.options.count,e,t]},(e,t,n,r,i)=>r===null||i===null?[]:e({startIndex:r,endIndex:i,overscan:t,count:n}),{key:!1,debug:()=>this.options.debug}),this.indexFromElement=e=>{let t=this.options.indexAttribute,n=e.getAttribute(t);return n?parseInt(n,10):(console.warn(`Missing attribute name '${t}={index}' on measured element.`),-1)},this.shouldMeasureDuringScroll=e=>{if(!this.scrollState||this.scrollState.behavior!==`smooth`)return!0;let t=this.scrollState.index??this.getVirtualItemForOffset(this.scrollState.lastTargetOffset)?.index;if(t!==void 0&&this.range){let n=Math.max(this.options.overscan,Math.ceil((this.range.endIndex-this.range.startIndex)/2)),r=Math.max(0,t-n),i=Math.min(this.options.count-1,t+n);return e>=r&&e<=i}return!0},this.measureElement=e=>{if(!e){this.elementsCache.forEach((e,t)=>{e.isConnected||(this.observer.unobserve(e),this.elementsCache.delete(t))});return}let t=this.indexFromElement(e),n=this.options.getItemKey(t),r=this.elementsCache.get(n);r!==e&&(r&&this.observer.unobserve(r),this.observer.observe(e),this.elementsCache.set(n,e)),(!this.isScrolling||this.scrollState)&&this.shouldMeasureDuringScroll(t)&&this.resizeItem(t,this.options.measureElement(e,void 0,this))},this.resizeItem=(e,t)=>{if(e<0||e>=this.options.count)return;let n,r,i,a=this._flatMeasurements;if(this.options.lanes===1&&a!==null)i=this.options.getItemKey(e),r=a[e*2],n=a[e*2+1];else{let t=this.measurementsCache[e];if(!t)return;i=t.key,r=t.start,n=t.size}let o=t-(this.itemSizeCache.get(i)??n);if(o!==0){let a=this.options.anchorTo===`end`&&this.scrollState?.behavior!==`smooth`&&this.getVirtualDistanceFromEnd()<=this.options.scrollEndThreshold,s=a?this.getTotalSize():0,c=this.scrollState?.behavior!==`smooth`&&(this.shouldAdjustScrollPositionOnItemSizeChange===void 0?r<this.getScrollOffset()+this.scrollAdjustments&&(!this.itemSizeCache.has(i)||this.scrollDirection!==`backward`):this.shouldAdjustScrollPositionOnItemSizeChange(this.measurementsCache[e]??{index:e,key:i,start:r,size:n,end:r+n,lane:0},o,this));(this.pendingMin===null||e<this.pendingMin)&&(this.pendingMin=e),this.itemSizeCache.set(i,t),this.itemSizeCacheVersion++,a?this.applyScrollAdjustment(this.getTotalSize()-s):c&&this.applyScrollAdjustment(o),this.notify(!1)}},this.getVirtualItems=m(()=>[this.getVirtualIndexes(),this.getMeasurements()],(e,t)=>{let n=[];for(let r=0,i=e.length;r<i;r++){let i=t[e[r]];n.push(i)}return n},{key:!1,debug:()=>this.options.debug}),this.getVirtualItemForOffset=e=>{let t=this.getMeasurements();if(t.length===0)return;let n=this._flatMeasurements,r=this.options.lanes===1&&n!=null;return h(t[j(0,t.length-1,r?e=>n[e*2]:e=>h(t[e]).start,e)])},this.getMaxScrollOffset=()=>{if(!this.scrollElement)return 0;if(`scrollHeight`in this.scrollElement)return this.options.horizontal?this.scrollElement.scrollWidth-this.scrollElement.clientWidth:this.scrollElement.scrollHeight-this.scrollElement.clientHeight;{let e=this.scrollElement.document.documentElement;return this.options.horizontal?e.scrollWidth-this.scrollElement.innerWidth:e.scrollHeight-this.scrollElement.innerHeight}},this.getVirtualDistanceFromEnd=()=>Math.max(this.getTotalSize()-this.getSize()-this.getScrollOffset(),0),this.getDistanceFromEnd=()=>Math.max(this.getMaxScrollOffset()-this.getScrollOffset(),0),this.isAtEnd=(e=this.options.scrollEndThreshold)=>this.getDistanceFromEnd()<=e,this.getOffsetForAlignment=(e,t,n=0)=>{if(!this.scrollElement)return 0;let r=this.getSize(),i=this.getScrollOffset();t===`auto`&&(t=e>=i+r?`end`:`start`),t===`center`?e+=(n-r)/2:t===`end`&&(e-=r);let a=this.getMaxScrollOffset();return Math.max(Math.min(a,e),0)},this.getOffsetForIndex=(e,t=`auto`)=>{e=Math.max(0,Math.min(e,this.options.count-1));let n=this.getSize(),r=this.getScrollOffset(),i=this.measurementsCache[e];if(!i)return;if(t===`auto`)if(i.end>=r+n-this.options.scrollPaddingEnd)t=`end`;else if(i.start<=r+this.options.scrollPaddingStart)t=`start`;else return[r,t];if(t===`end`&&e===this.options.count-1)return[this.getMaxScrollOffset(),t];let a=t===`end`?i.end+this.options.scrollPaddingEnd:i.start-this.options.scrollPaddingStart;return[this.getOffsetForAlignment(a,t,i.size),t]},this.scrollToOffset=(e,{align:t=`start`,behavior:n=`auto`}={})=>{let r=this.getOffsetForAlignment(e,t);this.scrollState={index:null,align:t,behavior:n,startedAt:this.now(),lastTargetOffset:r,stableFrames:0},this._scrollToOffset(r,{adjustments:void 0,behavior:n}),this.scheduleScrollReconcile()},this.scrollToIndex=(e,{align:t=`auto`,behavior:n=`auto`}={})=>{e=Math.max(0,Math.min(e,this.options.count-1));let r=this.getOffsetForIndex(e,t);if(!r)return;let[i,a]=r,o=this.now();this.scrollState={index:e,align:a,behavior:n,startedAt:o,lastTargetOffset:i,stableFrames:0},this._scrollToOffset(i,{adjustments:void 0,behavior:n}),this.scheduleScrollReconcile()},this.scrollBy=(e,{behavior:t=`auto`}={})=>{let n=this.getScrollOffset()+e;this.scrollState={index:null,align:`start`,behavior:t,startedAt:this.now(),lastTargetOffset:n,stableFrames:0},this._scrollToOffset(n,{adjustments:void 0,behavior:t}),this.scheduleScrollReconcile()},this.scrollToEnd=({behavior:e=`auto`}={})=>{if(this.options.count>0){this.scrollToIndex(this.options.count-1,{align:`end`,behavior:e});return}this.scrollToOffset(Math.max(this.getTotalSize()-this.getSize(),0),{behavior:e})},this.getTotalSize=()=>{let e=this.getMeasurements(),t;if(e.length===0)t=this.options.paddingStart;else if(this.options.lanes===1){let n=e.length-1,r=this._flatMeasurements;t=r==null?e[n]?.end??0:r[n*2]+r[n*2+1]}else{let n=Array(this.options.lanes).fill(null),r=e.length-1;for(;r>=0&&n.some(e=>e===null);){let t=e[r];n[t.lane]===null&&(n[t.lane]=t.end),r--}t=Math.max(...n.filter(e=>e!==null))}return Math.max(t-this.options.scrollMargin+this.options.paddingEnd,0)},this.takeSnapshot=()=>{let e=[];if(this.itemSizeCache.size===0)return e;let t=this.getMeasurements();for(let n of t)n&&this.itemSizeCache.has(n.key)&&e.push({index:n.index,key:n.key,start:n.start,size:n.size,end:n.end,lane:n.lane});return e},this._scrollToOffset=(e,{adjustments:t,behavior:n})=>{this._intendedScrollOffset=e+(t??0),this.options.scrollToFn(e,{behavior:n,adjustments:t},this)},this.measure=()=>{this.pendingMin=null,this.itemSizeCache.clear(),this.laneAssignments.clear(),this.itemSizeCacheVersion++,this.notify(!1)},this.setOptions(e)}applyScrollAdjustment(e,t){e!==0&&(y()&&(this.isScrolling||this._iosTouching||this._iosJustTouchEnded)?this._iosDeferredAdjustment+=e:(this._scrollToOffset(this.getScrollOffset(),{adjustments:this.scrollAdjustments+=e,behavior:t}),this.scrollOffset!==null&&(this.scrollOffset+=this.scrollAdjustments,this.scrollAdjustments=0)))}scheduleScrollReconcile(){if(!this.targetWindow){this.scrollState=null;return}this.rafId??=this.targetWindow.requestAnimationFrame(()=>{this.rafId=null,this.reconcileScroll()})}reconcileScroll(){if(!this.scrollState||!this.scrollElement)return;if(this.now()-this.scrollState.startedAt>5e3){this.scrollState=null;return}let e=this.scrollState.index==null?void 0:this.getOffsetForIndex(this.scrollState.index,this.scrollState.align),t=e?e[0]:this.scrollState.lastTargetOffset,n=t!==this.scrollState.lastTargetOffset;if(!n&&g(t,this.getScrollOffset())){if(this.scrollState.stableFrames++,this.scrollState.stableFrames>=1){this.getScrollOffset()!==t&&this._scrollToOffset(t,{adjustments:void 0,behavior:`auto`}),this.scrollState=null;return}}else if(this.scrollState.stableFrames=0,n){let e=this.getSize()||600,n=Math.abs(t-this.getScrollOffset()),r=this.scrollState.behavior===`smooth`&&n>e;this.scrollState.lastTargetOffset=t,r||(this.scrollState.behavior=`auto`),this._scrollToOffset(t,{adjustments:void 0,behavior:r?`smooth`:`auto`})}this.scheduleScrollReconcile()}},j=(e,t,n,r)=>{for(;e<=t;){let i=(e+t)/2|0,a=n(i);if(a<r)e=i+1;else if(a>r)t=i-1;else return i}return e>0?e-1:0};function M(e,t,n){let r=0;for(;r<=t;){let i=(r+t)/2|0,a=e[i*2];if(a<n)r=i+1;else if(a>n)t=i-1;else return i}return r>0?r-1:0}function N(e,t,n,r,i){let a=e.length-1;if(e.length<=r)return{startIndex:0,endIndex:a};if(r===1&&i!==null){let e=M(i,a,n),r=e,o=n+t;for(;r<a&&i[r*2]+i[r*2+1]<o;)r++;return{startIndex:e,endIndex:r}}let o=j(0,a,t=>e[t].start,n),s=o;if(r===1)for(;s<a&&e[s].end<n+t;)s++;else if(r>1){let i=Array(r).fill(0);for(;s<a&&i.some(e=>e<n+t);){let t=e[s];i[t.lane]=t.end,s++}let c=Array(r).fill(n+t);for(;o>=0&&c.some(e=>e>=n);){let t=e[o];c[t.lane]=t.start,o--}o=Math.max(0,o-o%r),s=Math.min(a,s+(r-1-s%r))}return{startIndex:o,endIndex:s}}var P=typeof document<`u`?d.useLayoutEffect:d.useEffect;function F({useFlushSync:e=!0,directDomUpdates:t=!1,directDomUpdatesMode:n=`transform`,...r}){let i=d.useReducer(e=>e+1,0)[1],a=d.useRef({enabled:t,mode:n,container:null,lastSize:null,lastPositions:new WeakMap,prevRange:null});a.current.enabled=t,a.current.mode=n;let o=e=>{let t=a.current;if(!t.enabled||!t.container)return;let n=e.getTotalSize();if(n!==t.lastSize){t.lastSize=n;let r=e.options.horizontal?`width`:`height`;t.container.style[r]=`${n}px`}let r=!!e.options.horizontal,i=t.mode===`transform`,o=r?`left`:`top`,s=e.options.scrollMargin,c=e.getVirtualItems();for(let n of c){let a=n.start-s,c=e.elementsCache.get(n.key);c&&t.lastPositions.get(c)!==a&&(t.lastPositions.set(c,a),i?c.style.transform=r?`translate3d(${a}px, 0, 0)`:`translate3d(0, ${a}px, 0)`:c.style[o]=`${a}px`)}},s={...r,onChange:(t,n)=>{var s;let c=a.current,l=!0;if(c.enabled){o(t);let e=t.range,n=c.prevRange;l=!n||n.isScrolling!==t.isScrolling||n.startIndex!==e?.startIndex||n.endIndex!==e?.endIndex,l&&(c.prevRange=e?{startIndex:e.startIndex,endIndex:e.endIndex,isScrolling:t.isScrolling}:null)}l&&(e&&n?(0,f.flushSync)(i):i()),(s=r.onChange)==null||s.call(r,t,n)}},[c]=d.useState(()=>{let e=new A(s);return Object.assign(e,{containerRef:t=>{let n=a.current;if(n.container=t,n.lastSize=null,t&&n.enabled){let r=e.getTotalSize();n.lastSize=r;let i=e.options.horizontal?`width`:`height`;t.style[i]=`${r}px`}}})});return c.setOptions(s),P(()=>c._didMount(),[]),P(()=>c._willUpdate()),P(()=>{o(c)}),c}function I(e){return F({observeElementRect:C,observeElementOffset:D,scrollToFn:k,...e})}var L=i(),R=e=>(0,L.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,L.jsxs)(`g`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,children:[(0,L.jsx)(`path`,{d:`M3 12a9 9 0 0 1 9-9a9.75 9.75 0 0 1 6.74 2.74L21 8`}),(0,L.jsx)(`path`,{d:`M21 3v5h-5m5 4a9 9 0 0 1-9 9a9.75 9.75 0 0 1-6.74-2.74L3 16`}),(0,L.jsx)(`path`,{d:`M8 16H3v5`})]})}),z=1e3,B=5e3,V=4e3,H={trace:0,debug:1,info:2,warning:3,error:4,fatal:5},U={trace:`TRC`,debug:`DBG`,info:`INF`,warning:`WRN`,error:`ERR`,fatal:`FTL`},W=new Intl.DateTimeFormat(`en-GB`,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1});function G(e){return W.format(new Date(e))}function K(e){return e.join(`·`)}var q=120;function J(e,t){e.push(t),e.length>q&&e.shift()}var Y=56,X=14;function Z({values:e}){if(e.length<2)return null;let t=Y,n=X,r=Math.max(...e,1),i=t/(q-1),a=t-(e.length-1)*i,o=e.map((e,t)=>{let o=a+t*i,s=n-1-e/r*(n-2);return`${o.toFixed(1)},${s.toFixed(1)}`}).join(` `);return(0,L.jsx)(`svg`,{width:t,height:n,viewBox:`0 0 ${t} ${n}`,className:`shrink-0`,"aria-hidden":`true`,children:(0,L.jsx)(`polyline`,{points:o,fill:`none`,stroke:`currentColor`,strokeWidth:`1.5`,strokeLinejoin:`round`,strokeLinecap:`round`,className:`text-sand-300`})})}function Q({usedPercent:e,threshold:t,blocked:n}){if(e===null)return null;let r=Math.max(0,Math.min(e,100)),i=n||t!==null&&e>=t;return(0,L.jsxs)(`span`,{className:`inline-flex items-center gap-1`,children:[(0,L.jsxs)(`span`,{className:`relative inline-block h-[4px] w-9 overflow-hidden rounded-full bg-sand-100`,children:[(0,L.jsx)(`span`,{className:l(`absolute inset-y-0 left-0 rounded-full`,i?`bg-caution-500`:`bg-sand-400`),style:{width:`${r}%`}}),t!==null&&(0,L.jsx)(`span`,{className:`absolute inset-y-0 w-px bg-sand-500`,style:{left:`${Math.min(t,100)}%`}})]}),(0,L.jsxs)(`span`,{className:l(`font-mono text-[10px] tabular-nums`,i?`font-semibold text-caution-500`:`text-sand-500`),children:[Math.round(e),`%`]})]})}function $({search:e,onSearchChange:n}){let[r,i]=(0,d.useState)([]),a=(0,d.useRef)(void 0),o=(0,d.useRef)(void 0),c=(0,d.useRef)(0),[f,p]=(0,d.useState)(()=>Date.now()),m=t({queryKey:[`Monit`,`monitLogs`],queryFn:()=>s.monitLogs(a.current),refetchInterval:z,retry:!1}),h=t({...s.monitInfoQueryOptions(),staleTime:1/0}).data,g=m.data?.vitals,_=t({...s.monitStatsQueryOptions(),refetchInterval:3e4,retry:!1}).data,v=(0,d.useRef)([]);(0,d.useEffect)(()=>{g&&J(v.current,g.openaiInFlight)},[g]),(0,d.useEffect)(()=>{let e=m.data;e&&y(e)},[m.data]);function y(e){let t=()=>++c.current;i(n=>{let r=n,i=[];o.current!==void 0&&e.processStartedAt!==o.current?(r=[],i.push({kind:`restart`,key:t(),processStartedAt:e.processStartedAt})):e.dropped>0&&i.push({kind:`dropped`,key:t(),count:e.dropped}),o.current=e.processStartedAt,a.current=e.nextCursor;let s=r.findLast(e=>e.kind===`log`)?.entry.seq;for(let n of e.entries)s!==void 0&&n.seq<=s||i.push({kind:`log`,key:t(),entry:n});if(i.length===0)return n;let c=[...r,...i];return c.length>V?c.slice(-V):c})}(0,d.useEffect)(()=>{let e=window.setInterval(()=>p(Date.now()),2e3);return()=>window.clearInterval(e)},[]);let b=r.length>0&&(m.isRefetchError||m.dataUpdatedAt>0&&f-m.dataUpdatedAt>B),x=(0,d.useMemo)(()=>r.filter(t=>{if(t.kind!==`log`)return!0;switch(e.level){case`warn`:return(H[t.entry.level]??2)>=3;case`error`:return(H[t.entry.level]??2)>=4;default:return!0}}),[r,e.level]),S=(0,d.useRef)(null),C=I({count:x.length,getScrollElement:()=>S.current,estimateSize:()=>20,getItemKey:e=>x[e].key,anchorTo:`end`,followOnAppend:!0,scrollEndThreshold:80,overscan:12}),w=C.isAtEnd(),T=m.dataUpdatedAt>0,E=!T&&m.isError;return(0,L.jsxs)(`section`,{className:`panel overflow-hidden`,children:[(0,L.jsxs)(`header`,{className:`panel-header flex min-h-11 flex-wrap items-center gap-x-3 gap-y-2 px-4 py-2 sm:px-5`,children:[(0,L.jsx)(`h2`,{className:`text-[13px] font-semibold tracking-[-0.01em] text-sand-800`,children:`Server logs`}),(0,L.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 text-[11px] font-medium text-sand-700`,children:[(0,L.jsx)(`span`,{className:l(`size-1.5 rounded-full`,b||E?`bg-danger-400`:`bg-sienna-500 motion-safe:animate-pulse`)}),E?`Disconnected`:b?`Stale`:T?`Live`:`…`]}),o.current!==void 0&&(0,L.jsxs)(`span`,{className:`text-[11px] text-sand-500`,children:[`ephemeral · resets on restart · since `,G(o.current)]}),(0,L.jsx)(`div`,{className:`ml-auto flex flex-wrap items-center gap-2`,children:(0,L.jsx)(`div`,{className:`segmented-control inline-flex`,role:`tablist`,"aria-label":`Log filter`,children:[{value:`all`,label:`All`},{value:`warn`,label:`Warn+`},{value:`error`,label:`Err+`}].map(t=>(0,L.jsx)(`button`,{type:`button`,"data-active":e.level===t.value,onClick:()=>n({...e,level:t.value}),className:`rounded-[6px] px-2.5 py-1 text-[11px] font-medium text-sand-500 transition-colors hover:text-sand-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sienna-300 data-[active=true]:text-sand-900`,children:t.label},t.value))})})]}),h&&(0,L.jsxs)(`div`,{className:`flex flex-wrap items-center gap-x-5 gap-y-1 border-b border-sand-100 bg-sand-50/60 px-4 py-2 text-[11px] text-sand-600 sm:px-5`,children:[(0,L.jsxs)(`span`,{children:[`server `,(0,L.jsx)(`span`,{className:`font-mono text-sand-800`,children:h.serverUrl})]}),(0,L.jsxs)(`span`,{children:[`db`,` `,(0,L.jsxs)(`span`,{className:`font-mono text-sand-800`,children:[h.dbHost,`/`,h.dbName]})]}),(0,L.jsxs)(`span`,{children:[`openai transport`,` `,(0,L.jsx)(`span`,{className:`font-mono text-sand-800`,children:h.openai.transport})]}),g&&(0,L.jsxs)(L.Fragment,{children:[(0,L.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[`openai in-flight`,` `,(0,L.jsx)(`span`,{className:`font-mono text-sand-800`,children:g.openaiInFlight}),(0,L.jsx)(Z,{values:v.current})]}),g.anthropicTokenCount>0&&(0,L.jsxs)(`span`,{children:[`anthropic running`,` `,(0,L.jsx)(`span`,{className:`font-mono text-sand-800`,children:g.anthropicInFlight})]})]}),_?.providers.map(e=>(0,L.jsxs)(`span`,{className:`text-sand-500`,children:[`1h `,e.provider,` `,(0,L.jsx)(`span`,{className:`font-mono text-sand-700`,children:e.requests}),` req`,e.errors>0&&(0,L.jsxs)(L.Fragment,{children:[` · `,(0,L.jsx)(`span`,{className:`font-mono font-semibold text-caution-500`,children:e.errors}),` err`]}),` · hit `,(0,L.jsx)(`span`,{className:`font-mono text-sand-700`,children:u({input_tokens:e.inputTokens,cache_read_tokens:e.cacheReadTokens})})]},e.provider))]}),g&&(g.openaiQuotaByToken.length>0||g.anthropicTokenNames.length>0)&&(0,L.jsxs)(`div`,{className:`space-y-1.5 border-b border-sand-100 px-4 py-2.5 sm:px-5`,children:[g.openaiQuotaByToken.length>0&&(0,L.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,L.jsx)(`span`,{className:`w-[4.5rem] shrink-0 text-[10px] font-medium uppercase tracking-[0.08em] text-sand-400`,children:`openai`}),g.openaiQuotaByToken.map(e=>{let t=e.usedPercent===null?`quota not sampled yet`:`quota ${Math.round(e.usedPercent)}%${e.threshold===null?``:` / threshold ${e.threshold}%`}${e.resetsAt?` · resets ${G(e.resetsAt)}`:``}`;return(0,L.jsxs)(`span`,{title:`${e.name} · ${t}`,className:`inline-flex items-center gap-1.5 rounded-md border border-sand-200 bg-white px-2 py-1`,children:[(0,L.jsx)(`span`,{className:`font-mono text-[11px] text-sand-600`,children:e.name.split(`/`).pop()}),(0,L.jsx)(Q,{usedPercent:e.usedPercent,threshold:e.threshold,blocked:e.blocked}),e.blocked&&(0,L.jsx)(`span`,{className:`rounded-full bg-caution-500/10 px-1.5 py-0.5 text-[9px] font-semibold text-caution-500`,children:`quota`})]},e.name)})]}),g.anthropicTokenNames.length>0&&(0,L.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,L.jsx)(`span`,{className:`w-[4.5rem] shrink-0 text-[10px] font-medium uppercase tracking-[0.08em] text-sand-400`,children:`anthropic`}),g.anthropicTokenNames.map(e=>(0,L.jsx)(`span`,{title:e,className:`inline-flex items-baseline rounded-md border border-sand-200 bg-white px-2 py-1 font-mono text-[11px] text-sand-600`,children:e.split(`/`).pop()},e))]})]}),(0,L.jsxs)(`div`,{className:`relative`,children:[(0,L.jsx)(`div`,{ref:S,role:`log`,"aria-label":`Server process logs`,tabIndex:0,className:`main-scroll h-[calc(100vh-232px)] min-h-[320px] overflow-y-auto bg-sand-900 px-4 py-3 font-mono text-[12px] leading-[1.6] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-sienna-400`,children:E?(0,L.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center gap-3 text-sand-400`,children:[(0,L.jsxs)(`p`,{className:`text-[12px]`,children:[`Could not reach the qgrid server — is it running?`,m.error instanceof Error&&(0,L.jsx)(`span`,{className:`block text-center text-[11px] text-sand-500`,children:m.error.message})]}),(0,L.jsxs)(`button`,{type:`button`,onClick:()=>void m.refetch(),className:`inline-flex items-center gap-1.5 rounded-md border border-sand-600 px-2.5 py-1.5 text-[11px] font-medium text-sand-300 transition-colors hover:bg-sand-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sienna-400`,children:[(0,L.jsx)(R,{className:`size-3`}),`Retry now`]})]}):T?x.length===0?(0,L.jsx)(`div`,{className:`flex h-full items-center justify-center text-[12px] text-sand-500`,children:r.length===0?`No log lines yet — waiting for activity since ${o.current===void 0?`startup`:G(o.current)}.`:`No lines match the current filters.`}):(0,L.jsx)(`div`,{className:`relative w-full`,style:{height:`${C.getTotalSize()}px`},children:C.getVirtualItems().map(e=>{let t=x[e.index];return(0,L.jsx)(`div`,{ref:C.measureElement,"data-index":e.index,className:`absolute left-0 top-0 w-full`,style:{transform:`translateY(${e.start}px)`},children:(0,L.jsx)(ee,{item:t})},e.key)})}):(0,L.jsx)(`div`,{className:`flex h-full items-center justify-center text-[12px] text-sand-500`,children:`Connecting to server logs…`})}),T&&!E&&!w&&(0,L.jsx)(`button`,{type:`button`,onClick:()=>C.scrollToEnd(),className:`absolute bottom-4 right-5 inline-flex items-center gap-1.5 rounded-full border border-sand-600 bg-sand-800/90 px-3 py-1.5 text-[11px] font-medium text-sand-200 shadow-lg backdrop-blur transition-colors hover:bg-sand-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sienna-400`,children:`↓ Jump to live`})]})]})}function ee({item:e}){if(e.kind===`restart`)return(0,L.jsxs)(`div`,{className:`py-1 text-center text-[11px] text-caution-400`,children:[`── process restarted · `,G(e.processStartedAt),` ──`]});if(e.kind===`dropped`)return(0,L.jsxs)(`div`,{className:`py-1 text-center text-[11px] italic text-sand-500`,children:[`── `,e.count,` lines dropped (buffer overflow) ──`]});let{entry:t}=e;return(0,L.jsxs)(`div`,{className:`whitespace-pre-wrap break-words text-sand-200`,children:[(0,L.jsx)(`span`,{className:`text-sand-500`,children:G(t.timestamp)}),` `,(0,L.jsx)(`span`,{className:l(`font-semibold`,t.level===`fatal`||t.level===`error`?`text-danger-400`:t.level===`warning`?`text-caution-400`:`text-sand-400`),children:U[t.level]??t.level.slice(0,3).toUpperCase()}),` `,(0,L.jsx)(`span`,{className:`text-sienna-300`,children:K(t.category)}),` `,(0,L.jsx)(`span`,{children:t.text})]})}a({level:o([`all`,`warn`,`error`]).optional().default(`all`).catch(()=>`all`)});function te(){let e=c.useSearch(),t=c.useNavigate();return(0,L.jsx)(`div`,{className:`max-w-[100rem] mx-auto`,children:(0,L.jsx)($,{search:e,onSearchChange:e=>t({search:e,replace:!0})})})}export{te as component};