@tonyclaw/llm-inspector 1.15.1 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.output/cli.js +1 -0
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/index-BmkN9DxE.js +107 -0
  4. package/.output/public/assets/index-DPe3eOih.css +1 -0
  5. package/.output/public/assets/{main-C2-qvdhC.js → main-BjnjXVBU.js} +1 -1
  6. package/.output/server/_ssr/{index-C001qcnM.mjs → index-BIOEVAzU.mjs} +216 -180
  7. package/.output/server/_ssr/index.mjs +2 -2
  8. package/.output/server/_ssr/{router-D7aEu4dR.mjs → router-THS9ptvu.mjs} +392 -170
  9. package/.output/server/{_tanstack-start-manifest_v-BXMwlSXD.mjs → _tanstack-start-manifest_v-BYhN7q_z.mjs} +1 -1
  10. package/.output/server/index.mjs +27 -27
  11. package/package.json +1 -1
  12. package/src/cli.ts +1 -0
  13. package/src/components/ProxyViewer.tsx +16 -54
  14. package/src/components/ProxyViewerContainer.tsx +121 -77
  15. package/src/components/providers/ImportWizardDialog.tsx +27 -3
  16. package/src/components/proxy-viewer/ConversationGroup.tsx +3 -3
  17. package/src/components/proxy-viewer/ConversationHeader.tsx +1 -1
  18. package/src/components/proxy-viewer/LogEntry.tsx +184 -171
  19. package/src/components/proxy-viewer/LogEntryHeader.tsx +126 -137
  20. package/src/components/proxy-viewer/ResponseView.tsx +3 -2
  21. package/src/components/proxy-viewer/StreamingChunkSequence.tsx +3 -3
  22. package/src/components/proxy-viewer/TurnGroup.tsx +4 -4
  23. package/src/components/proxy-viewer/diff/DiffView.tsx +5 -3
  24. package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +13 -9
  25. package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +3 -3
  26. package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +7 -3
  27. package/src/components/ui/json-viewer.tsx +3 -3
  28. package/src/lib/objectUtils.ts +22 -0
  29. package/src/proxy/claudeCodeStrip.ts +5 -8
  30. package/src/proxy/logIndex.ts +58 -43
  31. package/src/proxy/logger.ts +51 -27
  32. package/src/proxy/openaiOrphanToolStrip.ts +11 -17
  33. package/src/proxy/providerImporters.ts +245 -19
  34. package/src/proxy/providers.ts +20 -7
  35. package/src/proxy/schemas.ts +5 -9
  36. package/src/proxy/socketTracker.ts +109 -78
  37. package/src/proxy/store.ts +52 -83
  38. package/.output/public/assets/index-BIUbzgJN.css +0 -1
  39. package/.output/public/assets/index-TwYgzIL4.js +0 -107
@@ -1,18 +1,18 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
2
- import { C as CapturedLogSchema, R as RuntimeConfigSchema, r as requestFormatForPath, c as createPendingProviderTestResults, P as ProviderTestResultsSchema, b as createFailedProviderTestResults, d as ProviderConfigSchema, s as stripClaudeCodeBillingHeader, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, a as AnthropicRequestSchema } from "./router-D7aEu4dR.mjs";
2
+ import { C as CapturedLogSchema, R as RuntimeConfigSchema, r as requestFormatForPath, c as createPendingProviderTestResults, P as ProviderTestResultsSchema, b as createFailedProviderTestResults, d as ProviderConfigSchema, s as stripClaudeCodeBillingHeader, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, a as AnthropicRequestSchema } from "./router-THS9ptvu.mjs";
3
3
  import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
4
- import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
5
4
  import { c as clsx } from "../_libs/clsx.mjs";
6
5
  import { t as twMerge } from "../_libs/tailwind-merge.mjs";
7
6
  import { J as JSZip } from "../_libs/jszip.mjs";
8
7
  import { c as cva } from "../_libs/class-variance-authority.mjs";
9
8
  import { R as Root, T as Trigger$2, C as Content, a as Close, b as Title, P as Portal$2, O as Overlay } from "../_libs/radix-ui__react-dialog.mjs";
10
9
  import { d as diffJson, a as diffLines } from "../_libs/diff.mjs";
10
+ import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
11
11
  import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Content2, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
12
12
  import "../_libs/modelcontextprotocol__server.mjs";
13
13
  import { D as Download, S as Settings, C as ChevronDown, a as Check, X, U as Upload, b as Scan, P as Plus, c as Copy, d as CircleAlert, e as ChevronUp, L as LoaderCircle, f as ChevronRight, g as User, h as Clock, M as MessageSquare, Z as Zap, T as Trash2, R as Rows3, i as Columns2, j as Minus, k as Pencil, E as Equal, l as EyeOff, m as Eye, n as ExternalLink, o as RotateCw, G as GitCompareArrows, p as RotateCcw, q as CircleCheckBig, W as Wrench, r as Globe, F as FileTerminal, s as Radio, t as CircleQuestionMark, u as Server, v as Gauge, w as Lock, x as Wifi, y as WifiOff, A as ArrowUp, z as ArrowDown, B as TriangleAlert, H as CircleStop, I as ChevronsUp, J as ChevronsDown, K as Brain, N as Terminal } from "../_libs/lucide-react.mjs";
14
14
  import { M as Markdown } from "../_libs/react-markdown.mjs";
15
- import { a as array, b as string, u as union, d as object, l as literal, n as number, c as boolean, _ as _enum } from "../_libs/zod.mjs";
15
+ import { u as union, d as object, a as array, l as literal, b as string, n as number, c as boolean, _ as _enum } from "../_libs/zod.mjs";
16
16
  import { P as Provider, R as Root3, T as Trigger$1, a as Portal$1, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
17
17
  import { R as Root2$1, L as List, T as Trigger$3, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
18
18
  import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
@@ -36,8 +36,9 @@ import "stream";
36
36
  import "crypto";
37
37
  import "../_libs/isbot.mjs";
38
38
  import "node:fs";
39
- import "node:path";
40
39
  import "node:fs/promises";
40
+ import "node:buffer";
41
+ import "node:path";
41
42
  import "../_libs/conf.mjs";
42
43
  import "node:util";
43
44
  import "node:process";
@@ -62,7 +63,6 @@ import "../_libs/uint8array-extras.mjs";
62
63
  import "node:child_process";
63
64
  import "../_libs/use-sync-external-store.mjs";
64
65
  import "../_libs/dequal.mjs";
65
- import "../_libs/tanstack__virtual-core.mjs";
66
66
  import "../_libs/readable-stream.mjs";
67
67
  import "events";
68
68
  import "node:string_decoder";
@@ -99,6 +99,7 @@ import "../_libs/get-nonce.mjs";
99
99
  import "../_libs/use-sidecar.mjs";
100
100
  import "../_libs/use-callback-ref.mjs";
101
101
  import "../_libs/aria-hidden.mjs";
102
+ import "../_libs/tanstack__virtual-core.mjs";
102
103
  import "../_libs/radix-ui__number.mjs";
103
104
  import "../_libs/radix-ui__react-collection.mjs";
104
105
  import "../_libs/radix-ui__react-direction.mjs";
@@ -333,7 +334,7 @@ async function exportLogsAsZip(logs) {
333
334
  document.body.removeChild(anchor);
334
335
  URL.revokeObjectURL(url);
335
336
  }
336
- const version = "1.15.1";
337
+ const version = "1.16.0";
337
338
  const packageJson = {
338
339
  version
339
340
  };
@@ -561,7 +562,7 @@ function ConversationHeader({
561
562
  "flex items-center gap-3 px-3 py-2 cursor-pointer transition-colors",
562
563
  "hover:bg-muted/50",
563
564
  "select-none",
564
- "border border-border rounded-lg mb-2 bg-muted/30"
565
+ "border border-border rounded-lg mb-2 bg-background sticky top-0 z-10"
565
566
  ),
566
567
  onClick: onToggle,
567
568
  onKeyDown: (e) => {
@@ -926,7 +927,7 @@ function ExpandCollapseButton({
926
927
  }
927
928
  );
928
929
  }
929
- function JsonNode({
930
+ const JsonNode = reactExports.memo(function JsonNode2({
930
931
  name,
931
932
  value,
932
933
  level,
@@ -1000,7 +1001,7 @@ function JsonNode({
1000
1001
  ),
1001
1002
  expandable && expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "pl-4", children: [
1002
1003
  getEntries(value).map(([key, childValue]) => /* @__PURE__ */ jsxRuntimeExports.jsx(
1003
- JsonNode,
1004
+ JsonNode2,
1004
1005
  {
1005
1006
  name: key,
1006
1007
  value: childValue,
@@ -1013,7 +1014,7 @@ function JsonNode({
1013
1014
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground py-0.5 px-1", children: closeBracket })
1014
1015
  ] }, childResetKey)
1015
1016
  ] });
1016
- }
1017
+ });
1017
1018
  function JsonViewer({
1018
1019
  data,
1019
1020
  defaultExpandDepth = 2,
@@ -1259,7 +1260,7 @@ function kindClass(kind) {
1259
1260
  }
1260
1261
  return "text-foreground/80";
1261
1262
  }
1262
- function DiffView({ result, emptyLabel }) {
1263
+ const DiffViewInner = function DiffView2({ result, emptyLabel }) {
1263
1264
  const [mode, setMode] = reactExports.useState("unified");
1264
1265
  const scrollRef = reactExports.useRef(null);
1265
1266
  const virtualizer = useVirtualizer({
@@ -1336,7 +1337,7 @@ function DiffView({ result, emptyLabel }) {
1336
1337
  }
1337
1338
  )
1338
1339
  ] });
1339
- }
1340
+ };
1340
1341
  function UnifiedRows({
1341
1342
  virtualizer,
1342
1343
  lines
@@ -1494,6 +1495,7 @@ function SplitRows({ lines }) {
1494
1495
  idx
1495
1496
  )) });
1496
1497
  }
1498
+ const DiffView = reactExports.memo(DiffViewInner);
1497
1499
  const AnthropicLogoSvg = "data:image/svg+xml,%3csvg%20height='2500'%20viewBox='0%206.603%201192.672%201193.397'%20width='2500'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='m233.96%20800.215%20234.684-131.678%203.947-11.436-3.947-6.363h-11.436l-39.221-2.416-134.094-3.624-116.296-4.832-112.67-6.04-28.35-6.04-26.577-35.035%202.738-17.477%2023.84-16.027%2034.147%202.98%2075.463%205.155%20113.235%207.812%2082.147%204.832%20121.692%2012.644h19.329l2.738-7.812-6.604-4.832-5.154-4.832-117.182-79.41-126.845-83.92-66.443-48.321-35.92-24.484-18.12-22.953-7.813-50.093%2032.618-35.92%2043.812%202.98%2011.195%202.98%2044.375%2034.147%2094.792%2073.37%20123.786%2091.167%2018.12%2015.06%207.249-5.154.886-3.624-8.135-13.61-67.329-121.692-71.838-123.785-31.974-51.302-8.456-30.765c-2.98-12.645-5.154-23.275-5.154-36.242l37.127-50.416%2020.537-6.604%2049.53%206.604%2020.86%2018.121%2030.765%2070.39%2049.852%20110.818%2077.315%20150.684%2022.631%2044.698%2012.08%2041.396%204.51%2012.645h7.813v-7.248l6.362-84.886%2011.759-104.215%2011.436-134.094%203.946-37.772%2018.685-45.262%2037.127-24.482%2028.994%2013.852%2023.839%2034.148-3.303%2022.067-14.174%2092.134-27.785%20144.323-18.121%2096.644h10.55l12.08-12.08%2048.887-64.913%2082.147-102.685%2036.242-40.752%2042.282-45.02%2027.14-21.423h51.303l37.772%2056.135-16.913%2057.986-52.832%2067.007-43.812%2056.779-62.82%2084.563-39.22%2067.651%203.623%205.396%209.343-.886%20141.906-30.201%2076.671-13.852%2091.49-15.705%2041.396%2019.329%204.51%2019.65-16.269%2040.189-97.852%2024.16-114.764%2022.954-170.9%2040.43-2.093%201.53%202.416%202.98%2076.993%207.248%2032.94%201.771h80.617l150.12%2011.195%2039.222%2025.933%2023.517%2031.732-3.946%2024.16-60.403%2030.766-81.503-19.33-190.228-45.26-65.235-16.27h-9.02v5.397l54.362%2053.154%2099.624%2089.96%20124.752%20115.973%206.362%2028.671-16.027%2022.63-16.912-2.415-109.611-82.47-42.282-37.127-95.758-80.618h-6.363v8.456l22.067%2032.296%20116.537%20175.167%206.04%2053.719-8.456%2017.476-30.201%2010.55-33.181-6.04-68.215-95.758-70.39-107.84-56.778-96.644-6.926%203.947-33.503%20360.886-15.705%2018.443-36.243%2013.852-30.201-22.953-16.027-37.127%2016.027-73.37%2019.329-95.758%2015.704-76.107%2014.175-94.55%208.456-31.41-.563-2.094-6.927.886-71.275%2097.852-108.402%20146.497-85.772%2091.812-20.537%208.134-35.597-18.443%203.301-32.94%2019.893-29.315%20118.712-151.007%2071.597-93.583%2046.228-54.04-.322-7.813h-2.738l-315.302%20204.725-56.135%207.248-24.16-22.63%202.98-37.128%2011.435-12.08%2094.792-65.236-.322.323z'%20fill='%23d97757'/%3e%3c/svg%3e";
1498
1500
  const OpenAILogoSvg = "data:image/svg+xml,%3csvg%20height='2500'%20viewBox='-1%20-.1%20949.1%20959.8'%20width='2474'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='m925.8%20456.3c10.4%2023.2%2017%2048%2019.7%2073.3%202.6%2025.3%201.3%2050.9-4.1%2075.8-5.3%2024.9-14.5%2048.8-27.3%2070.8-8.4%2014.7-18.3%2028.5-29.7%2041.2-11.3%2012.6-23.9%2024-37.6%2034-13.8%2010-28.5%2018.4-44.1%2025.3-15.5%206.8-31.7%2012-48.3%2015.4-7.8%2024.2-19.4%2047.1-34.4%2067.7-14.9%2020.6-33%2038.7-53.6%2053.6-20.6%2015-43.4%2026.6-67.6%2034.4-24.2%207.9-49.5%2011.8-75%2011.8-16.9.1-33.9-1.7-50.5-5.1-16.5-3.5-32.7-8.8-48.2-15.7s-30.2-15.5-43.9-25.5c-13.6-10-26.2-21.5-37.4-34.2-25%205.4-50.6%206.7-75.9%204.1-25.3-2.7-50.1-9.3-73.4-19.7-23.2-10.3-44.7-24.3-63.6-41.4s-35-37.1-47.7-59.1c-8.5-14.7-15.5-30.2-20.8-46.3s-8.8-32.7-10.6-49.6c-1.8-16.8-1.7-33.8.1-50.7%201.8-16.8%205.5-33.4%2010.8-49.5-17-18.9-31-40.4-41.4-63.6-10.3-23.3-17-48-19.6-73.3-2.7-25.3-1.3-50.9%204-75.8s14.5-48.8%2027.3-70.8c8.4-14.7%2018.3-28.6%2029.6-41.2s24-24%2037.7-34%2028.5-18.5%2044-25.3c15.6-6.9%2031.8-12%2048.4-15.4%207.8-24.3%2019.4-47.1%2034.3-67.7%2015-20.6%2033.1-38.7%2053.7-53.7%2020.6-14.9%2043.4-26.5%2067.6-34.4%2024.2-7.8%2049.5-11.8%2075-11.7%2016.9-.1%2033.9%201.6%2050.5%205.1s32.8%208.7%2048.3%2015.6c15.5%207%2030.2%2015.5%2043.9%2025.5%2013.7%2010.1%2026.3%2021.5%2037.5%2034.2%2024.9-5.3%2050.5-6.6%2075.8-4s50%209.3%2073.3%2019.6c23.2%2010.4%2044.7%2024.3%2063.6%2041.4%2018.9%2017%2035%2036.9%2047.7%2059%208.5%2014.6%2015.5%2030.1%2020.8%2046.3%205.3%2016.1%208.9%2032.7%2010.6%2049.6%201.8%2016.9%201.8%2033.9-.1%2050.8-1.8%2016.9-5.5%2033.5-10.8%2049.6%2017.1%2018.9%2031%2040.3%2041.4%2063.6zm-333.2%20426.9c21.8-9%2041.6-22.3%2058.3-39s30-36.5%2039-58.4c9-21.8%2013.7-45.2%2013.7-68.8v-223q-.1-.3-.2-.7-.1-.3-.3-.6-.2-.3-.5-.5-.3-.3-.6-.4l-80.7-46.6v269.4c0%202.7-.4%205.5-1.1%208.1-.7%202.7-1.7%205.2-3.1%207.6s-3%204.6-5%206.5a32.1%2032.1%200%200%201%20-6.5%205l-191.1%20110.3c-1.6%201-4.3%202.4-5.7%203.2%207.9%206.7%2016.5%2012.6%2025.5%2017.8%209.1%205.2%2018.5%209.6%2028.3%2013.2%209.8%203.5%2019.9%206.2%2030.1%208%2010.3%201.8%2020.7%202.7%2031.1%202.7%2023.6%200%2047-4.7%2068.8-13.8zm-455.1-151.4c11.9%2020.5%2027.6%2038.3%2046.3%2052.7%2018.8%2014.4%2040.1%2024.9%2062.9%2031s46.6%207.7%2070%204.6%2045.9-10.7%2066.4-22.5l193.2-111.5.5-.5q.2-.2.3-.6.2-.3.3-.6v-94l-233.2%20134.9c-2.4%201.4-4.9%202.4-7.5%203.2-2.7.7-5.4%201-8.2%201-2.7%200-5.4-.3-8.1-1-2.6-.8-5.2-1.8-7.6-3.2l-191.1-110.4c-1.7-1-4.2-2.5-5.6-3.4-1.8%2010.3-2.7%2020.7-2.7%2031.1s1%2020.8%202.8%2031.1c1.8%2010.2%204.6%2020.3%208.1%2030.1%203.6%209.8%208%2019.2%2013.2%2028.2zm-50.2-417c-11.8%2020.5-19.4%2043.1-22.5%2066.5s-1.5%2047.1%204.6%2070c6.1%2022.8%2016.6%2044.1%2031%2062.9%2014.4%2018.7%2032.3%2034.4%2052.7%2046.2l193.1%20111.6q.3.1.7.2h.7q.4%200%20.7-.2.3-.1.6-.3l81-46.8-233.2-134.6c-2.3-1.4-4.5-3.1-6.5-5a32.1%2032.1%200%200%201%20-5-6.5c-1.3-2.4-2.4-4.9-3.1-7.6-.7-2.6-1.1-5.3-1-8.1v-227.1c-9.8%203.6-19.3%208-28.3%2013.2-9%205.3-17.5%2011.3-25.5%2018-7.9%206.7-15.3%2014.1-22%2022.1-6.7%207.9-12.6%2016.5-17.8%2025.5zm663.3%20154.4c2.4%201.4%204.6%203%206.6%205%201.9%201.9%203.6%204.1%205%206.5%201.3%202.4%202.4%205%203.1%207.6.6%202.7%201%205.4.9%208.2v227.1c32.1-11.8%2060.1-32.5%2080.8-59.7%2020.8-27.2%2033.3-59.7%2036.2-93.7s-3.9-68.2-19.7-98.5-39.9-55.5-69.5-72.5l-193.1-111.6q-.3-.1-.7-.2h-.7q-.3.1-.7.2-.3.1-.6.3l-80.6%2046.6%20233.2%20134.7zm80.5-121h-.1v.1zm-.1-.1c5.8-33.6%201.9-68.2-11.3-99.7-13.1-31.5-35-58.6-63-78.2-28-19.5-61-30.7-95.1-32.2-34.2-1.4-68%206.9-97.6%2023.9l-193.1%20111.5q-.3.2-.5.5l-.4.6q-.1.3-.2.7-.1.3-.1.7v93.2l233.2-134.7c2.4-1.4%205-2.4%207.6-3.2%202.7-.7%205.4-1%208.1-1%202.8%200%205.5.3%208.2%201%202.6.8%205.1%201.8%207.5%203.2l191.1%20110.4c1.7%201%204.2%202.4%205.6%203.3zm-505.3-103.2c0-2.7.4-5.4%201.1-8.1.7-2.6%201.7-5.2%203.1-7.6%201.4-2.3%203-4.5%205-6.5%201.9-1.9%204.1-3.6%206.5-4.9l191.1-110.3c1.8-1.1%204.3-2.5%205.7-3.2-26.2-21.9-58.2-35.9-92.1-40.2-33.9-4.4-68.3%201-99.2%2015.5-31%2014.5-57.2%2037.6-75.5%2066.4-18.3%2028.9-28%2062.3-28%2096.5v223q.1.4.2.7.1.3.3.6.2.3.5.6.2.2.6.4l80.7%2046.6zm43.8%20294.7%20103.9%2060%20103.9-60v-119.9l-103.8-60-103.9%2060z'/%3e%3c/svg%3e";
1499
1501
  const DeepSeekLogoSvg = "data:image/svg+xml,%3csvg%20fill='none'%20height='1320'%20viewBox='3.771%206.973%2023.993%2017.652'%20width='2500'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='m27.501%208.469c-.252-.123-.36.111-.508.23-.05.04-.093.09-.135.135-.368.395-.797.652-1.358.621-.821-.045-1.521.213-2.14.842-.132-.776-.57-1.238-1.235-1.535-.349-.155-.701-.309-.944-.645-.171-.238-.217-.504-.303-.765-.054-.159-.108-.32-.29-.348-.197-.031-.274.135-.352.273-.31.567-.43%201.192-.419%201.825.028%201.421.628%202.554%201.82%203.36.136.093.17.186.128.321-.081.278-.178.547-.264.824-.054.178-.135.217-.324.14a5.448%205.448%200%200%201%20-1.719-1.169c-.848-.82-1.614-1.726-2.57-2.435-.225-.166-.449-.32-.681-.467-.976-.95.128-1.729.383-1.82.267-.096.093-.428-.77-.424s-1.653.293-2.659.677a2.782%202.782%200%200%201%20-.46.135%209.554%209.554%200%200%200%20-2.853-.1c-1.866.21-3.356%201.092-4.452%202.6-1.315%201.81-1.625%203.87-1.246%206.018.399%202.261%201.552%204.136%203.326%205.601%201.837%201.518%203.955%202.262%206.37%202.12%201.466-.085%203.1-.282%204.942-1.842.465.23.952.322%201.762.392.623.059%201.223-.031%201.687-.127.728-.154.677-.828.414-.953-2.132-.994-1.665-.59-2.09-.916%201.084-1.285%202.717-2.619%203.356-6.94.05-.343.007-.558%200-.837-.004-.168.034-.235.228-.254a4.084%204.084%200%200%200%201.529-.47c1.382-.757%201.938-1.997%202.07-3.485.02-.227-.004-.463-.243-.582zm-12.041%2013.391c-2.067-1.627-3.07-2.162-3.483-2.138-.387.021-.318.465-.233.754.089.285.205.482.368.732.113.166.19.414-.112.598-.666.414-1.823-.139-1.878-.166-1.347-.793-2.473-1.842-3.267-3.276-.765-1.38-1.21-2.861-1.284-4.441-.02-.383.093-.518.472-.586a4.692%204.692%200%200%201%201.514-.04c2.109.31%203.905%201.255%205.41%202.749.86.853%201.51%201.871%202.18%202.865.711%201.057%201.478%202.063%202.454%202.887.343.289.619.51.881.672-.792.088-2.117.107-3.022-.61zm.99-6.38a.304.304%200%201%201%20.609%200c0%20.17-.136.304-.306.304a.3.3%200%200%201%20-.303-.305zm3.077%201.581c-.197.08-.394.15-.584.159a1.246%201.246%200%200%201%20-.79-.252c-.27-.227-.463-.354-.546-.752a1.752%201.752%200%200%201%20.016-.582c.07-.324-.008-.531-.235-.72-.187-.155-.422-.196-.682-.196a.551.551%200%200%201%20-.252-.078c-.108-.055-.197-.19-.112-.356.027-.053.159-.183.19-.207.352-.201.758-.135%201.134.016.349.142.611.404.99.773.388.448.457.573.678.906.174.264.333.534.441.842.066.192-.02.35-.248.448z'%20fill='%234d6bfe'/%3e%3c/svg%3e";
@@ -1608,13 +1610,14 @@ const LogEntryHeader = reactExports.memo(function({
1608
1610
  }) {
1609
1611
  const statusCategory = getStatusCategory(log.responseStatus);
1610
1612
  const hasTokens = log.inputTokens !== null || log.outputTokens !== null;
1611
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1613
+ const toolNamesJoined = reactExports.useMemo(() => responseToolNames?.join(", ") ?? null, [responseToolNames]);
1614
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
1612
1615
  "div",
1613
1616
  {
1614
1617
  role: "button",
1615
1618
  tabIndex: 0,
1616
1619
  className: cn(
1617
- "flex items-center gap-2.5 px-3 py-2 cursor-pointer transition-colors",
1620
+ "flex items-center gap-2 px-3 py-1 cursor-pointer transition-colors",
1618
1621
  "hover:bg-muted/50",
1619
1622
  "select-none"
1620
1623
  ),
@@ -1630,15 +1633,15 @@ const LogEntryHeader = reactExports.memo(function({
1630
1633
  "#",
1631
1634
  log.id
1632
1635
  ] }),
1633
- log.model !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1636
+ log.model !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1634
1637
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderLogo, { provider: detectProvider(log.model), className: "size-4" }) }) }),
1635
1638
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: log.model })
1636
- ] }) }),
1639
+ ] }),
1637
1640
  statusCategory !== "success" && /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: statusCategory === "server_error" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1638
1641
  Badge,
1639
1642
  {
1640
1643
  variant: "destructive",
1641
- className: "text-[10px] px-1.5 py-0 h-5 font-mono tabular-nums",
1644
+ className: "text-[10px] px-1.5 py-0 h-4 font-mono tabular-nums",
1642
1645
  children: log.responseStatus
1643
1646
  }
1644
1647
  ) : statusCategory === "pending" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -1646,7 +1649,7 @@ const LogEntryHeader = reactExports.memo(function({
1646
1649
  {
1647
1650
  variant: "outline",
1648
1651
  className: cn(
1649
- "text-[10px] px-1.5 py-0 h-5 font-mono tabular-nums",
1652
+ "text-[10px] px-1.5 py-0 h-4 font-mono tabular-nums",
1650
1653
  STATUS_BADGE_CLASSES[statusCategory]
1651
1654
  ),
1652
1655
  children: /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3 animate-spin" })
@@ -1656,7 +1659,7 @@ const LogEntryHeader = reactExports.memo(function({
1656
1659
  {
1657
1660
  variant: "outline",
1658
1661
  className: cn(
1659
- "text-[10px] px-1.5 py-0 h-5 font-mono tabular-nums",
1662
+ "text-[10px] px-1.5 py-0 h-4 font-mono tabular-nums",
1660
1663
  STATUS_BADGE_CLASSES[statusCategory]
1661
1664
  ),
1662
1665
  children: log.responseStatus
@@ -1669,10 +1672,16 @@ const LogEntryHeader = reactExports.memo(function({
1669
1672
  hasTokens && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
1670
1673
  /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
1671
1674
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
1672
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: log.inputTokens !== null ? "text-blue-400" : "text-muted-foreground", children: [
1673
- "IN ",
1674
- log.inputTokens !== null ? formatTokens(log.inputTokens) : "—"
1675
- ] }),
1675
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1676
+ "span",
1677
+ {
1678
+ className: log.inputTokens !== null ? "text-blue-400" : "text-muted-foreground",
1679
+ children: [
1680
+ "IN ",
1681
+ log.inputTokens !== null ? formatTokens(log.inputTokens) : "—"
1682
+ ]
1683
+ }
1684
+ ),
1676
1685
  " / ",
1677
1686
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
1678
1687
  "span",
@@ -1686,7 +1695,7 @@ const LogEntryHeader = reactExports.memo(function({
1686
1695
  )
1687
1696
  ] })
1688
1697
  ] }),
1689
- log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1698
+ log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1690
1699
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
1691
1700
  /* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.creation ?? null }),
1692
1701
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-emerald-400", children: [
@@ -1695,8 +1704,8 @@ const LogEntryHeader = reactExports.memo(function({
1695
1704
  ] })
1696
1705
  ] }) }),
1697
1706
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens cached for reuse, reducing future API cost" })
1698
- ] }) }),
1699
- log.cacheReadInputTokens !== null && log.cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1707
+ ] }),
1708
+ log.cacheReadInputTokens !== null && log.cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1700
1709
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
1701
1710
  /* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.read ?? null }),
1702
1711
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
@@ -1705,31 +1714,31 @@ const LogEntryHeader = reactExports.memo(function({
1705
1714
  ] })
1706
1715
  ] }) }),
1707
1716
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens served from cache, reducing API cost" })
1708
- ] }) }),
1709
- messageCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1717
+ ] }),
1718
+ messageCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1710
1719
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
1711
1720
  /* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3" }),
1712
1721
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: messageCount })
1713
1722
  ] }) }),
1714
1723
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Number of messages in the conversation" })
1715
- ] }) }),
1716
- toolCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1724
+ ] }),
1725
+ toolCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1717
1726
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
1718
1727
  /* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3" }),
1719
1728
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: toolCount })
1720
1729
  ] }) }),
1721
1730
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Number of tools defined in the request" })
1722
- ] }) }),
1723
- responseToolNames !== null && responseToolNames.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1731
+ ] }),
1732
+ responseToolNames !== null && responseToolNames.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1724
1733
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-amber-400/80 text-xs shrink-0", children: [
1725
1734
  /* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3" }),
1726
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[160px]", children: responseToolNames.join(", ") })
1735
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[160px]", children: toolNamesJoined })
1727
1736
  ] }) }),
1728
1737
  /* @__PURE__ */ jsxRuntimeExports.jsxs(TooltipContent, { children: [
1729
1738
  "Tools called by model: ",
1730
- responseToolNames.join(", ")
1739
+ toolNamesJoined
1731
1740
  ] })
1732
- ] }) }),
1741
+ ] }),
1733
1742
  log.origin !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(
1734
1743
  "span",
1735
1744
  {
@@ -1741,7 +1750,7 @@ const LogEntryHeader = reactExports.memo(function({
1741
1750
  ]
1742
1751
  }
1743
1752
  ),
1744
- (log.clientPid !== null || log.clientProjectFolder !== null) && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1753
+ (log.clientPid !== null || log.clientProjectFolder !== null) && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1745
1754
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "hidden xl:flex items-center gap-1 text-purple-400/80 text-xs shrink-0", children: [
1746
1755
  /* @__PURE__ */ jsxRuntimeExports.jsx(FileTerminal, { className: "size-3" }),
1747
1756
  log.clientProjectFolder !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: log.clientProjectFolder }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
@@ -1750,16 +1759,16 @@ const LogEntryHeader = reactExports.memo(function({
1750
1759
  ] })
1751
1760
  ] }) }),
1752
1761
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: log.clientCwd !== null ? `PID: ${log.clientPid ?? "?"} CWD: ${log.clientCwd}` : `Process ID: ${log.clientPid ?? "?"}` })
1753
- ] }) }),
1754
- log.streaming && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1762
+ ] }),
1763
+ log.streaming && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1755
1764
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Radio, { className: "size-3 text-muted-foreground/60 shrink-0" }) }),
1756
1765
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Request used SSE streaming" })
1757
- ] }) }),
1766
+ ] }),
1758
1767
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
1759
1768
  expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 text-muted-foreground shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 text-muted-foreground shrink-0" })
1760
1769
  ]
1761
1770
  }
1762
- );
1771
+ ) });
1763
1772
  });
1764
1773
  function Separator({
1765
1774
  className,
@@ -1873,7 +1882,7 @@ function extractThinkingFromContent(text) {
1873
1882
  const remainingText = text.replace(THINKING_TAG_REGEX, "").trim();
1874
1883
  return { thinking, remainingText };
1875
1884
  }
1876
- function TextBlock({ text }) {
1885
+ const TextBlock = reactExports.memo(function TextBlock2({ text }) {
1877
1886
  if (text.includes("<system-reminder>")) {
1878
1887
  return /* @__PURE__ */ jsxRuntimeExports.jsx(SystemReminderBlock, { text });
1879
1888
  }
@@ -1883,8 +1892,10 @@ function TextBlock({ text }) {
1883
1892
  remainingText.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "prose prose-sm dark:prose-invert max-w-none [&_pre]:bg-muted [&_pre]:text-foreground [&_code]:text-[0.8em] [&_p]:my-1 [&_ul]:my-1 [&_ol]:my-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { children: remainingText }) }),
1884
1893
  thinking === null && remainingText.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "Empty text block" })
1885
1894
  ] });
1886
- }
1887
- function ThinkingBlock({ thinking }) {
1895
+ });
1896
+ const ThinkingBlock = reactExports.memo(function ThinkingBlock2({
1897
+ thinking
1898
+ }) {
1888
1899
  const [open, setOpen] = reactExports.useState(false);
1889
1900
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Collapsible, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-l-2 border-purple-500/40 my-1", children: [
1890
1901
  /* @__PURE__ */ jsxRuntimeExports.jsxs(CollapsibleTrigger, { className: "flex items-center gap-1.5 px-3 py-1 w-full text-left cursor-pointer hover:bg-purple-500/5 transition-colors rounded-r-sm group", children: [
@@ -1906,8 +1917,8 @@ function ThinkingBlock({ thinking }) {
1906
1917
  ] }),
1907
1918
  /* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "max-h-[60vh]", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono leading-relaxed", children: thinking }) }) }) })
1908
1919
  ] }) });
1909
- }
1910
- function ToolUseBlock({
1920
+ });
1921
+ const ToolUseBlock = reactExports.memo(function ToolUseBlock2({
1911
1922
  name,
1912
1923
  input
1913
1924
  }) {
@@ -1921,8 +1932,8 @@ function ToolUseBlock({
1921
1932
  ] }),
1922
1933
  /* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "max-h-[60vh]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewer, { data: safeJsonValue(input), defaultExpandDepth: 2 }) }) }) })
1923
1934
  ] }) });
1924
- }
1925
- function ResponseContentBlockRenderer({
1935
+ });
1936
+ const ResponseContentBlockRenderer = reactExports.memo(function ResponseContentBlockRenderer2({
1926
1937
  block
1927
1938
  }) {
1928
1939
  switch (block.type) {
@@ -1936,8 +1947,8 @@ function ResponseContentBlockRenderer({
1936
1947
  default:
1937
1948
  return assertNever();
1938
1949
  }
1939
- }
1940
- function StructuredResponseViewAnthropic({
1950
+ });
1951
+ const StructuredResponseViewAnthropic = reactExports.memo(function StructuredResponseViewAnthropic2({
1941
1952
  response
1942
1953
  }) {
1943
1954
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
@@ -1979,7 +1990,7 @@ function StructuredResponseViewAnthropic({
1979
1990
  response.content.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "Empty response content" })
1980
1991
  ] })
1981
1992
  ] });
1982
- }
1993
+ });
1983
1994
  function parseToolArguments(raw) {
1984
1995
  if (raw === void 0 || raw === "") return {};
1985
1996
  try {
@@ -2007,7 +2018,9 @@ function OpenAIToolCallBlock({ call }) {
2007
2018
  ) : /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewer, { data: safeJsonValue(parsed), defaultExpandDepth: 2 }) }) }) })
2008
2019
  ] }) });
2009
2020
  }
2010
- function OpenAIResponseView({ response }) {
2021
+ const OpenAIResponseView = reactExports.memo(function OpenAIResponseView2({
2022
+ response
2023
+ }) {
2011
2024
  const choice = response.choices[0];
2012
2025
  const message = choice?.message;
2013
2026
  const toolCalls = message?.tool_calls ?? [];
@@ -2065,7 +2078,7 @@ function OpenAIResponseView({ response }) {
2065
2078
  (message?.content === null || message?.content === void 0 || message.content.length === 0) && (message?.reasoning_content === null || message?.reasoning_content === void 0 || message.reasoning_content.length === 0) && (message?.function_call === null || message?.function_call === void 0) && toolCalls.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "Empty response content" })
2066
2079
  ] })
2067
2080
  ] });
2068
- }
2081
+ });
2069
2082
  function isRecord(value) {
2070
2083
  return typeof value === "object" && value !== null && !Array.isArray(value);
2071
2084
  }
@@ -2208,7 +2221,7 @@ function ErrorResponseView({ text }) {
2208
2221
  function MarkdownFallbackView({ text }) {
2209
2222
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "prose prose-sm dark:prose-invert max-w-none [&_pre]:bg-muted [&_pre]:text-foreground [&_code]:text-[0.8em] [&_p]:my-1 [&_ul]:my-1 [&_ol]:my-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { children: text }) });
2210
2223
  }
2211
- function ResponseView({
2224
+ const ResponseView = reactExports.memo(function ResponseView2({
2212
2225
  responseText,
2213
2226
  responseStatus,
2214
2227
  streaming,
@@ -2281,7 +2294,7 @@ function ResponseView({
2281
2294
  ] }),
2282
2295
  /* @__PURE__ */ jsxRuntimeExports.jsx(MarkdownFallbackView, { text: responseText ?? "" })
2283
2296
  ] });
2284
- }
2297
+ });
2285
2298
  const ReplayResultSchema = object({
2286
2299
  success: boolean(),
2287
2300
  error: string().optional(),
@@ -2431,7 +2444,7 @@ function ReplayDialog({ log, open, onOpenChange }) {
2431
2444
  ] })
2432
2445
  ] }) });
2433
2446
  }
2434
- function StreamingChunkSequence({
2447
+ const StreamingChunkSequence = reactExports.memo(function StreamingChunkSequence2({
2435
2448
  logId,
2436
2449
  truncated
2437
2450
  }) {
@@ -2563,7 +2576,7 @@ function StreamingChunkSequence({
2563
2576
  ] }) }),
2564
2577
  containerExpanded === true ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-border bg-muted/20 overflow-auto max-h-64", children: renderBody() }) : null
2565
2578
  ] });
2566
- }
2579
+ });
2567
2580
  function shouldShowRawRequestTab(apiFormat, viewMode, strip) {
2568
2581
  return apiFormat === "anthropic" && viewMode === "full" && strip;
2569
2582
  }
@@ -2673,6 +2686,7 @@ const LogEntry = reactExports.memo(function({
2673
2686
  const [replayOpen, setReplayOpen] = reactExports.useState(false);
2674
2687
  const [headersDiff, setHeadersDiff] = reactExports.useState(false);
2675
2688
  const [requestDiff, setRequestDiff] = reactExports.useState(false);
2689
+ const [activeTab, setActiveTab] = reactExports.useState("request");
2676
2690
  const resolvedFormat = resolveLogFormat(log);
2677
2691
  const adapter = getLogFormatAdapter(resolvedFormat);
2678
2692
  const requestAnalysis = reactExports.useMemo(
@@ -2694,7 +2708,7 @@ const LogEntry = reactExports.memo(function({
2694
2708
  const rawRequestCopy = useCopyFeedback(log.rawRequestBody);
2695
2709
  const responseCopy = useCopyFeedback(log.responseText);
2696
2710
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(TooltipProvider, { children: [
2697
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-border rounded-lg mb-1.5 overflow-hidden", children: [
2711
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-border rounded-lg mb-1 overflow-hidden", children: [
2698
2712
  /* @__PURE__ */ jsxRuntimeExports.jsx(
2699
2713
  LogEntryHeader,
2700
2714
  {
@@ -2707,7 +2721,7 @@ const LogEntry = reactExports.memo(function({
2707
2721
  cacheTrend
2708
2722
  }
2709
2723
  ),
2710
- expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { defaultValue: "request", children: [
2724
+ expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { value: activeTab, onValueChange: setActiveTab, children: [
2711
2725
  /* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, { className: "mx-4 mt-2", children: [
2712
2726
  viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2713
2727
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw-headers", children: "Raw Headers" }) }),
@@ -2728,7 +2742,7 @@ const LogEntry = reactExports.memo(function({
2728
2742
  ] }),
2729
2743
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" })
2730
2744
  ] }),
2731
- shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
2745
+ shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: activeTab === "raw-request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
2732
2746
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end mb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2733
2747
  CopyButton,
2734
2748
  {
@@ -2740,7 +2754,7 @@ const LogEntry = reactExports.memo(function({
2740
2754
  ) }),
2741
2755
  log.rawRequestBody !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: log.rawRequestBody, defaultExpandDepth: 1 }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" })
2742
2756
  ] }) }),
2743
- /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
2757
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: activeTab === "request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
2744
2758
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 mb-2", children: [
2745
2759
  shouldShowRequestDiffButton(
2746
2760
  resolvedFormat,
@@ -2814,7 +2828,7 @@ const LogEntry = reactExports.memo(function({
2814
2828
  }
2815
2829
  ) : displayedRequestBody !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: displayedRequestBody, defaultExpandDepth: 1 }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" })
2816
2830
  ] }) }),
2817
- viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "headers", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
2831
+ viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "headers", children: activeTab === "headers" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
2818
2832
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end gap-2 mb-2", children: shouldShowHeadersDiffButton(
2819
2833
  viewMode,
2820
2834
  log.rawHeaders !== void 0 && Object.keys(log.rawHeaders).length > 0
@@ -2843,14 +2857,14 @@ const LogEntry = reactExports.memo(function({
2843
2857
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
2844
2858
  ] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No headers captured" })
2845
2859
  ] }) }),
2846
- viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-headers", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: log.rawHeaders && Object.keys(log.rawHeaders).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.rawHeaders).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
2860
+ viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-headers", children: activeTab === "raw-headers" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: log.rawHeaders && Object.keys(log.rawHeaders).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.rawHeaders).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
2847
2861
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-600 dark:text-blue-400 font-semibold shrink-0", children: [
2848
2862
  key,
2849
2863
  ":"
2850
2864
  ] }),
2851
2865
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
2852
2866
  ] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No raw headers captured" }) }) }),
2853
- /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3 space-y-3", children: [
2867
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: activeTab === "raw" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3 space-y-3", children: [
2854
2868
  log.error !== void 0 && log.error !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded border border-destructive/50 bg-destructive/10 p-3 text-xs", children: [
2855
2869
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold text-destructive mb-1", children: "SSE Error" }),
2856
2870
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground font-mono", children: log.error })
@@ -2873,7 +2887,7 @@ const LogEntry = reactExports.memo(function({
2873
2887
  }
2874
2888
  )
2875
2889
  ] }) }),
2876
- /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2890
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: activeTab === "parsed" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2877
2891
  ResponseView,
2878
2892
  {
2879
2893
  responseText: log.responseText,
@@ -3296,7 +3310,7 @@ function ThreadConnector({
3296
3310
  ) })
3297
3311
  ] });
3298
3312
  }
3299
- function TurnGroup({
3313
+ const TurnGroup = reactExports.memo(function TurnGroup2({
3300
3314
  entries,
3301
3315
  viewMode,
3302
3316
  strip,
@@ -3342,7 +3356,7 @@ function TurnGroup({
3342
3356
  onToggle: toggleCollapse
3343
3357
  }
3344
3358
  ),
3345
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("flex-1 min-w-0 mb-1 rounded-lg", bgClass), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3359
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("flex-1 min-w-0 mb-0.5 rounded-lg", bgClass), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3346
3360
  LogEntry,
3347
3361
  {
3348
3362
  log,
@@ -3356,7 +3370,7 @@ function TurnGroup({
3356
3370
  })
3357
3371
  }
3358
3372
  );
3359
- }
3373
+ });
3360
3374
  function shouldRenderConversationContent(standalone, expanded) {
3361
3375
  return standalone || expanded;
3362
3376
  }
@@ -3411,14 +3425,14 @@ const ConversationGroup = reactExports.memo(function({
3411
3425
  standalone = false
3412
3426
  }) {
3413
3427
  const [expanded, setExpanded] = reactExports.useState(false);
3414
- const stats = computeStats(group.logs);
3428
+ const stats = reactExports.useMemo(() => computeStats(group.logs), [group.logs]);
3415
3429
  const startTime = group.logs[0]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
3416
3430
  const endTime = group.logs[group.logs.length - 1]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
3417
3431
  const mixed = hasMixedApiFormat(group.logs);
3418
3432
  const isLoading = group.logs.some((log) => log.responseStatus === null);
3419
3433
  const turnGroups = reactExports.useMemo(() => buildTurnGroups(group.logs), [group.logs]);
3420
3434
  const displayId = group.conversationId.startsWith("PID:") || group.conversationId.includes("|") ? group.conversationId : group.conversationId.length > 24 ? group.conversationId.slice(0, 12) + "…" + group.conversationId.slice(-12) : group.conversationId;
3421
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4", children: [
3435
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-2", children: [
3422
3436
  !standalone && /* @__PURE__ */ jsxRuntimeExports.jsx(
3423
3437
  ConversationHeader,
3424
3438
  {
@@ -3437,7 +3451,7 @@ const ConversationGroup = reactExports.memo(function({
3437
3451
  onClear: () => onClearGroup(group.logs.map((l) => l.id))
3438
3452
  }
3439
3453
  ),
3440
- shouldRenderConversationContent(standalone, expanded) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: turnGroups.map((tg) => /* @__PURE__ */ jsxRuntimeExports.jsx(
3454
+ shouldRenderConversationContent(standalone, expanded) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "max-h-[70vh] overflow-y-auto", children: turnGroups.map((tg) => /* @__PURE__ */ jsxRuntimeExports.jsx(
3441
3455
  TurnGroup,
3442
3456
  {
3443
3457
  entries: tg.entries,
@@ -3636,6 +3650,32 @@ function OpenCodeIcon() {
3636
3650
  }
3637
3651
  );
3638
3652
  }
3653
+ function MiMoCodeIcon() {
3654
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
3655
+ "svg",
3656
+ {
3657
+ fill: "currentColor",
3658
+ viewBox: "0 0 24 24",
3659
+ xmlns: "http://www.w3.org/2000/svg",
3660
+ className: "size-6 shrink-0",
3661
+ children: [
3662
+ /* @__PURE__ */ jsxRuntimeExports.jsx("title", { children: "MiMo Code" }),
3663
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3664
+ "text",
3665
+ {
3666
+ x: "12",
3667
+ y: "18",
3668
+ textAnchor: "middle",
3669
+ fontSize: "16",
3670
+ fontWeight: "800",
3671
+ fontFamily: "system-ui, sans-serif",
3672
+ children: "M"
3673
+ }
3674
+ )
3675
+ ]
3676
+ }
3677
+ );
3678
+ }
3639
3679
  const ExternalProviderSchema = object({
3640
3680
  name: string(),
3641
3681
  apiKey: string(),
@@ -3643,7 +3683,7 @@ const ExternalProviderSchema = object({
3643
3683
  anthropicBaseUrl: string(),
3644
3684
  openaiBaseUrl: string(),
3645
3685
  models: array(string()),
3646
- sourceTool: _enum(["claude-code", "opencode"]),
3686
+ sourceTool: _enum(["claude-code", "opencode", "mimo-code"]),
3647
3687
  alreadyExists: boolean()
3648
3688
  });
3649
3689
  const ScanResponseSchema = object({
@@ -3658,7 +3698,8 @@ const ImportResponseSchema$1 = object({
3658
3698
  });
3659
3699
  const sourceLogoMap = {
3660
3700
  "claude-code": ClaudeCodeIcon,
3661
- opencode: OpenCodeIcon
3701
+ opencode: OpenCodeIcon,
3702
+ "mimo-code": MiMoCodeIcon
3662
3703
  };
3663
3704
  function ImportWizardDialog({
3664
3705
  open,
@@ -3772,7 +3813,7 @@ function ImportWizardDialog({
3772
3813
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { className: "max-w-xl max-h-[80vh] overflow-hidden flex flex-col", children: [
3773
3814
  /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogHeader, { children: [
3774
3815
  /* @__PURE__ */ jsxRuntimeExports.jsx(DialogTitle, { children: "Import from External Tools" }),
3775
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Detect provider configurations from Claude Code and OpenCode." })
3816
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Detect provider configurations from Claude Code, OpenCode, and MiMo Code." })
3776
3817
  ] }),
3777
3818
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto space-y-3", children: [
3778
3819
  scanning && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center py-8 gap-2 text-muted-foreground", children: [
@@ -3786,7 +3827,7 @@ function ImportWizardDialog({
3786
3827
  !scanning && scanError === null && providers.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-sm text-muted-foreground py-8 text-center", children: [
3787
3828
  "No external provider configurations found.",
3788
3829
  /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
3789
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Supported tools: Claude Code (~/.claude/settings.json), OpenCode (~/.config/opencode/opencode.json)" })
3830
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Supported tools: Claude Code (~/.claude/settings.json), OpenCode (~/.config/opencode/opencode.json), MiMo Code (~/.config/mimocode/mimocode.jsonc)" })
3790
3831
  ] }),
3791
3832
  !scanning && providers.map((p, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
3792
3833
  "label",
@@ -6232,7 +6273,7 @@ function ProxyViewer({
6232
6273
  onViewModeChange,
6233
6274
  strip
6234
6275
  }) {
6235
- const { totalIn, totalOut } = computeTokenSummary(logs);
6276
+ const { totalIn, totalOut } = reactExports.useMemo(() => computeTokenSummary(logs), [logs]);
6236
6277
  const [exporting, setExporting] = reactExports.useState(false);
6237
6278
  const [comparePair, setComparePair] = reactExports.useState(null);
6238
6279
  const [crabEntrancePhase, setCrabEntrancePhase] = reactExports.useState(
@@ -6257,7 +6298,6 @@ function ProxyViewer({
6257
6298
  setExporting(false);
6258
6299
  }
6259
6300
  }, [logs]);
6260
- const parentRef = reactExports.useRef(null);
6261
6301
  reactExports.useEffect(() => {
6262
6302
  setComparePair(null);
6263
6303
  }, [selectedSession, selectedModel]);
@@ -6274,13 +6314,6 @@ function ProxyViewer({
6274
6314
  },
6275
6315
  [comparisonPredecessors]
6276
6316
  );
6277
- const rowVirtualizer = useVirtualizer({
6278
- count: groups.length,
6279
- getScrollElement: () => parentRef.current,
6280
- estimateSize: () => 150,
6281
- measureElement: typeof window !== "undefined" ? (element) => element.getBoundingClientRect().height : void 0,
6282
- overscan: 5
6283
- });
6284
6317
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-[1200px] mx-auto flex flex-col h-screen", style: { maxHeight: "100vh" }, children: [
6285
6318
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end px-6 pt-6 pb-8 relative", children: [
6286
6319
  /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-lg font-bold flex items-end gap-2 absolute left-1/2 -translate-x-1/2 whitespace-nowrap", children: [
@@ -6401,57 +6434,23 @@ function ProxyViewer({
6401
6434
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm", children: "No requests captured yet." }),
6402
6435
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs", children: "Route AI coding tools through the proxy:" }),
6403
6436
  /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableCommand, { command: "LLM_BASE_URL=http://localhost:25947/proxy <your-tool>" })
6404
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: parentRef, className: "overflow-y-auto h-full", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
6405
- "div",
6437
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-y-auto h-full flex flex-col gap-2", children: groups.map((group) => /* @__PURE__ */ jsxRuntimeExports.jsx(
6438
+ ConversationGroup,
6406
6439
  {
6407
- style: {
6408
- height: `${rowVirtualizer.getTotalSize()}px`,
6409
- width: "100%",
6410
- position: "relative"
6411
- },
6412
- children: rowVirtualizer.getVirtualItems().map((virtualRow) => {
6413
- const group = groups[virtualRow.index];
6414
- if (group === void 0) return null;
6415
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
6416
- "div",
6417
- {
6418
- "data-index": virtualRow.index,
6419
- ref: rowVirtualizer.measureElement,
6420
- style: {
6421
- position: "absolute",
6422
- top: 0,
6423
- left: 0,
6424
- width: "100%",
6425
- transform: `translateY(${virtualRow.start}px)`
6426
- },
6427
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
6428
- ConversationGroup,
6429
- {
6430
- group,
6431
- viewMode,
6432
- strip,
6433
- cacheTrends,
6434
- onCompareWithPrevious: handleCompareWithPrevious,
6435
- comparisonPredecessors,
6436
- onClearGroup,
6437
- standalone: groups.length === 1
6438
- }
6439
- )
6440
- },
6441
- group.id
6442
- );
6443
- })
6444
- }
6445
- ) }) }),
6440
+ group,
6441
+ viewMode,
6442
+ strip,
6443
+ cacheTrends,
6444
+ onCompareWithPrevious: handleCompareWithPrevious,
6445
+ comparisonPredecessors,
6446
+ onClearGroup,
6447
+ standalone: groups.length === 1
6448
+ },
6449
+ group.id
6450
+ )) }) }),
6446
6451
  comparePair !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(CompareDrawer, { left: comparePair[0], right: comparePair[1], onClose: closeCompare })
6447
6452
  ] });
6448
6453
  }
6449
- object({
6450
- logs: array(CapturedLogSchema),
6451
- total: number(),
6452
- offset: number(),
6453
- limit: number()
6454
- });
6455
6454
  const SSEUpdateSchema = union([
6456
6455
  object({
6457
6456
  type: literal("init"),
@@ -6476,8 +6475,17 @@ function extractModels(logs) {
6476
6475
  }
6477
6476
  return [...set];
6478
6477
  }
6478
+ function filterLogs(logs, selectedSession, selectedModel) {
6479
+ if (selectedSession === "__all__" && selectedModel === "__all__") return logs;
6480
+ return logs.filter((l) => {
6481
+ if (selectedSession !== "__all__" && l.sessionId !== selectedSession) return false;
6482
+ if (selectedModel !== "__all__" && l.model !== selectedModel) return false;
6483
+ return true;
6484
+ });
6485
+ }
6486
+ const DEBOUNCE_MS = 50;
6479
6487
  function ProxyViewerContainer() {
6480
- const [logs, setLogs] = reactExports.useState([]);
6488
+ const [allLogs, setAllLogs] = reactExports.useState([]);
6481
6489
  const [sessions, setSessions] = reactExports.useState([]);
6482
6490
  const [models, setModels] = reactExports.useState([]);
6483
6491
  const [selectedSession, setSelectedSession] = reactExports.useState("__all__");
@@ -6486,31 +6494,58 @@ function ProxyViewerContainer() {
6486
6494
  const [error, setError] = reactExports.useState(null);
6487
6495
  const eventSourceRef = reactExports.useRef(null);
6488
6496
  const reconnectTimeoutRef = reactExports.useRef(null);
6489
- const fetchSessionsAndModels = reactExports.useCallback(async () => {
6490
- try {
6491
- const [sessionsRes, modelsRes] = await Promise.all([
6492
- fetch("/api/sessions"),
6493
- fetch("/api/models")
6494
- ]);
6495
- if (sessionsRes.ok && modelsRes.ok) {
6496
- const sessionsJson = await sessionsRes.json();
6497
- const modelsJson = await modelsRes.json();
6498
- const sessionsResult = array(string()).safeParse(sessionsJson);
6499
- const modelsResult = array(string()).safeParse(modelsJson);
6500
- if (sessionsResult.success) setSessions(sessionsResult.data);
6501
- if (modelsResult.success) setModels(modelsResult.data);
6497
+ const logIndexRef = reactExports.useRef(/* @__PURE__ */ new Map());
6498
+ const logsRef = reactExports.useRef([]);
6499
+ const pendingUpdatesRef = reactExports.useRef([]);
6500
+ const flushTimerRef = reactExports.useRef(null);
6501
+ const logs = reactExports.useMemo(
6502
+ () => filterLogs(allLogs, selectedSession, selectedModel),
6503
+ [allLogs, selectedSession, selectedModel]
6504
+ );
6505
+ const flushUpdates = reactExports.useCallback(() => {
6506
+ flushTimerRef.current = null;
6507
+ const updates = pendingUpdatesRef.current;
6508
+ pendingUpdatesRef.current = [];
6509
+ if (updates.length === 0) return;
6510
+ setAllLogs((prev) => {
6511
+ let next = prev;
6512
+ let sessionsChanged = false;
6513
+ let modelsChanged = false;
6514
+ for (const log of updates) {
6515
+ const idx = logIndexRef.current.get(log.id);
6516
+ if (idx !== void 0) {
6517
+ next = [...next.slice(0, idx), log, ...next.slice(idx + 1)];
6518
+ } else {
6519
+ logIndexRef.current.set(log.id, next.length);
6520
+ next = [...next, log];
6521
+ }
6522
+ if (log.sessionId !== null && log.sessionId !== "" && !sessions.includes(log.sessionId)) {
6523
+ sessionsChanged = true;
6524
+ }
6525
+ if (log.model !== null && log.model !== "" && !models.includes(log.model)) {
6526
+ modelsChanged = true;
6527
+ }
6502
6528
  }
6503
- } catch {
6504
- }
6505
- }, []);
6529
+ logsRef.current = next;
6530
+ if (sessionsChanged) setSessions((s) => extractSessions(next));
6531
+ if (modelsChanged) setModels((m) => extractModels(next));
6532
+ return next;
6533
+ });
6534
+ }, [sessions, models]);
6535
+ const scheduleUpdate = reactExports.useCallback(
6536
+ (log) => {
6537
+ pendingUpdatesRef.current.push(log);
6538
+ if (flushTimerRef.current === null) {
6539
+ flushTimerRef.current = setTimeout(flushUpdates, DEBOUNCE_MS);
6540
+ }
6541
+ },
6542
+ [flushUpdates]
6543
+ );
6506
6544
  const connectSSE = reactExports.useCallback(() => {
6507
6545
  if (eventSourceRef.current) {
6508
6546
  eventSourceRef.current.close();
6509
6547
  }
6510
- const params = new URLSearchParams();
6511
- if (selectedSession !== "__all__") params.set("sessionId", selectedSession);
6512
- if (selectedModel !== "__all__") params.set("model", selectedModel);
6513
- const es = new EventSource(`/api/logs/stream?${params}`);
6548
+ const es = new EventSource("/api/logs/stream");
6514
6549
  eventSourceRef.current = es;
6515
6550
  es.onmessage = (event) => {
6516
6551
  try {
@@ -6523,35 +6558,24 @@ function ProxyViewerContainer() {
6523
6558
  }
6524
6559
  const update = updateResult.data;
6525
6560
  if (update.type === "init") {
6526
- setLogs(update.logs);
6561
+ if (flushTimerRef.current !== null) {
6562
+ clearTimeout(flushTimerRef.current);
6563
+ flushTimerRef.current = null;
6564
+ }
6565
+ pendingUpdatesRef.current = [];
6566
+ const idx = /* @__PURE__ */ new Map();
6567
+ for (let i = 0; i < update.logs.length; i++) {
6568
+ const log = update.logs[i];
6569
+ if (log !== void 0) idx.set(log.id, i);
6570
+ }
6571
+ logIndexRef.current = idx;
6572
+ logsRef.current = update.logs;
6573
+ setAllLogs(update.logs);
6527
6574
  setSessions(extractSessions(update.logs));
6528
6575
  setModels(extractModels(update.logs));
6529
6576
  setError(null);
6530
6577
  } else if (update.type === "update") {
6531
- setLogs((prev) => {
6532
- const sessionMatch = selectedSession === "__all__" || update.log.sessionId === selectedSession;
6533
- const modelMatch = selectedModel === "__all__" || update.log.model === selectedModel;
6534
- if (!sessionMatch || !modelMatch) return prev;
6535
- const existsIndex = prev.findIndex((l) => l.id === update.log.id);
6536
- if (existsIndex >= 0) {
6537
- return prev.map((l) => l.id === update.log.id ? update.log : l);
6538
- }
6539
- return [...prev, update.log];
6540
- });
6541
- setSessions((prev) => {
6542
- const sessionId = update.log.sessionId;
6543
- if (sessionId !== null && sessionId !== void 0 && sessionId !== "") {
6544
- return prev.includes(sessionId) ? prev : [...prev, sessionId];
6545
- }
6546
- return prev;
6547
- });
6548
- setModels((prev) => {
6549
- const model = update.log.model;
6550
- if (model !== null && model !== void 0 && model !== "") {
6551
- return prev.includes(model) ? prev : [...prev, model];
6552
- }
6553
- return prev;
6554
- });
6578
+ scheduleUpdate(update.log);
6555
6579
  }
6556
6580
  } catch {
6557
6581
  setError("Failed to parse SSE data");
@@ -6565,8 +6589,7 @@ function ProxyViewerContainer() {
6565
6589
  }
6566
6590
  reconnectTimeoutRef.current = setTimeout(connectSSE, 3e3);
6567
6591
  };
6568
- void fetchSessionsAndModels();
6569
- }, [selectedSession, selectedModel, fetchSessionsAndModels]);
6592
+ }, [scheduleUpdate]);
6570
6593
  reactExports.useEffect(() => {
6571
6594
  connectSSE();
6572
6595
  return () => {
@@ -6578,6 +6601,10 @@ function ProxyViewerContainer() {
6578
6601
  clearTimeout(reconnectTimeoutRef.current);
6579
6602
  reconnectTimeoutRef.current = null;
6580
6603
  }
6604
+ if (flushTimerRef.current !== null) {
6605
+ clearTimeout(flushTimerRef.current);
6606
+ flushTimerRef.current = null;
6607
+ }
6581
6608
  };
6582
6609
  }, [connectSSE]);
6583
6610
  const handleClearAll = reactExports.useCallback(() => {
@@ -6588,7 +6615,9 @@ function ProxyViewerContainer() {
6588
6615
  setError("Failed to clear logs");
6589
6616
  return;
6590
6617
  }
6591
- setLogs([]);
6618
+ logIndexRef.current.clear();
6619
+ logsRef.current = [];
6620
+ setAllLogs([]);
6592
6621
  setSessions([]);
6593
6622
  setModels([]);
6594
6623
  setError(null);
@@ -6611,8 +6640,15 @@ function ProxyViewerContainer() {
6611
6640
  return;
6612
6641
  }
6613
6642
  const idSet = new Set(ids);
6614
- setLogs((prev) => {
6643
+ setAllLogs((prev) => {
6615
6644
  const remaining = prev.filter((l) => !idSet.has(l.id));
6645
+ const idx = /* @__PURE__ */ new Map();
6646
+ for (let i = 0; i < remaining.length; i++) {
6647
+ const log = remaining[i];
6648
+ if (log !== void 0) idx.set(log.id, i);
6649
+ }
6650
+ logIndexRef.current = idx;
6651
+ logsRef.current = remaining;
6616
6652
  setSessions(extractSessions(remaining));
6617
6653
  setModels(extractModels(remaining));
6618
6654
  return remaining;