@tonyclaw/llm-inspector 1.16.4 → 1.16.5
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.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/CompareDrawer-C1w4KUGZ.js +1 -0
- package/.output/public/assets/ReplayDialog-DR2Sgq_g.js +1 -0
- package/.output/public/assets/RequestAnatomy-DAre35kj.js +1 -0
- package/.output/public/assets/ResponseView-ackes7_g.js +1 -0
- package/.output/public/assets/StreamingChunkSequence-GrXwIGKA.js +1 -0
- package/.output/public/assets/index-BGzHFOEX.css +1 -0
- package/.output/public/assets/index-DX88k9br.js +101 -0
- package/.output/public/assets/json-viewer-C_QUhGeu.js +14 -0
- package/.output/public/assets/{main-DbWwVQFh.js → main-CDMdNDY_.js} +1 -1
- package/.output/server/_libs/lucide-react.mjs +104 -84
- package/.output/server/_ssr/CompareDrawer-ftkJxyk6.mjs +1040 -0
- package/.output/server/_ssr/ReplayDialog-DcmE3lj5.mjs +321 -0
- package/.output/server/_ssr/RequestAnatomy-rK_LNMdG.mjs +351 -0
- package/.output/server/_ssr/ResponseView-CbQ4n-aJ.mjs +601 -0
- package/.output/server/_ssr/StreamingChunkSequence-84FZkIzv.mjs +301 -0
- package/.output/server/_ssr/{index-C-z-fZtq.mjs → index-CDjLoMsk.mjs} +1026 -2455
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/json-viewer-B-qpM5xC.mjs +510 -0
- package/.output/server/_ssr/{router-CNM9Kbi0.mjs → router-BrdjOUEW.mjs} +24 -14
- package/.output/server/{_tanstack-start-manifest_v-BWfLeIsC.mjs → _tanstack-start-manifest_v-DmOZEcJ3.mjs} +1 -1
- package/.output/server/index.mjs +68 -26
- package/package.json +1 -1
- package/src/components/OnboardingBanner.tsx +2 -2
- package/src/components/ProxyViewer.tsx +38 -26
- package/src/components/ProxyViewerContainer.tsx +3 -24
- package/src/components/proxy-viewer/ConversationGroup.tsx +1 -1
- package/src/components/proxy-viewer/ConversationHeader.tsx +4 -1
- package/src/components/proxy-viewer/LogEntry.tsx +213 -181
- package/src/components/proxy-viewer/LogEntryHeader.tsx +134 -36
- package/src/components/proxy-viewer/ThreadConnector.tsx +17 -2
- package/src/components/proxy-viewer/TurnGroup.tsx +94 -71
- package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +98 -0
- package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +196 -0
- package/src/components/proxy-viewer/anatomy/tokenEstimate.ts +53 -0
- package/src/components/proxy-viewer/anatomy/types.ts +39 -0
- package/src/components/proxy-viewer/anatomy/useAnatomyJump.ts +114 -0
- package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +3 -23
- package/src/components/proxy-viewer/formats/anthropic/thinkingExtract.ts +21 -0
- package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +5 -3
- package/src/components/proxy-viewer/lazy.ts +37 -0
- package/src/components/proxy-viewer/log-formats/anthropic.ts +146 -0
- package/src/components/proxy-viewer/log-formats/openai.ts +127 -0
- package/src/components/proxy-viewer/log-formats/types.ts +7 -0
- package/src/components/proxy-viewer/log-formats/unknown.ts +4 -0
- package/src/components/proxy-viewer/logEntryVisibility.ts +39 -0
- package/src/components/proxy-viewer/useKeyboardNavigation.ts +190 -0
- package/src/components/proxy-viewer/viewerState.ts +8 -0
- package/src/components/ui/crab-variants.tsx +11 -0
- package/src/components/ui/json-expansion-button.tsx +56 -0
- package/src/components/ui/json-viewer-bulk.ts +97 -0
- package/src/components/ui/json-viewer.tsx +58 -183
- package/src/lib/utils.ts +2 -3
- package/src/routes/api/logs.stream.ts +26 -16
- package/.output/public/assets/index-DRRCmu5p.css +0 -1
- package/.output/public/assets/index-X7CHS7fS.js +0 -107
|
@@ -1,5 +1,5 @@
|
|
|
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-
|
|
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-BrdjOUEW.mjs";
|
|
3
3
|
import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
|
|
4
4
|
import { J as JSZip } from "../_libs/jszip.mjs";
|
|
5
5
|
import { c as clsx } from "../_libs/clsx.mjs";
|
|
@@ -9,16 +9,11 @@ import { R as Root, T as Trigger$1, C as Content, a as Close, b as Title, P as P
|
|
|
9
9
|
import { d as diffJson, a as diffLines } from "../_libs/diff.mjs";
|
|
10
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
|
-
import "../_libs/
|
|
13
|
-
import { C as Check, X, D as Download, S as Settings, a as ChevronDown, 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 ChevronsUp, u as ChevronsDown, v as CircleQuestionMark, w as Server, x as Gauge, y as Lock, z as Wifi, A as WifiOff, B as ArrowUp, H as ArrowDown, I as TriangleAlert, J as CircleStop, K as Brain, N as Terminal } from "../_libs/lucide-react.mjs";
|
|
14
|
-
import { M as Markdown } from "../_libs/react-markdown.mjs";
|
|
12
|
+
import { C as Check, X, D as Download, S as Settings, a as ChevronDown, 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, E as EyeOff, i as Eye, j as ExternalLink, R as RotateCw, k as Pencil, G as GitCompareArrows, l as Minus, m as CircleCheckBig, O as OctagonAlert, n as TriangleAlert, W as Wrench, o as Globe, F as FileTerminal, p as Radio, q as ChevronsUp, r as ChevronsDown, s as RotateCcw, 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 Rows3, H as Columns2 } from "../_libs/lucide-react.mjs";
|
|
15
13
|
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
14
|
import { R as Root2$1, L as List, T as Trigger$2, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
|
|
17
15
|
import { P as Provider, R as Root3, T as Trigger$3, a as Portal$2, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
|
|
18
16
|
import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
|
|
19
|
-
import { R as Root$1 } from "../_libs/radix-ui__react-separator.mjs";
|
|
20
|
-
import { R as Root$2, C as CollapsibleTrigger$1, a as CollapsibleContent$1 } from "../_libs/radix-ui__react-collapsible.mjs";
|
|
21
|
-
import { R as Root$3, V as Viewport$1, C as Corner, S as ScrollAreaScrollbar, a as ScrollAreaThumb } from "../_libs/radix-ui__react-scroll-area.mjs";
|
|
22
17
|
import "../_libs/tanstack__react-router.mjs";
|
|
23
18
|
import "../_libs/tiny-warning.mjs";
|
|
24
19
|
import "../_libs/tanstack__router-core.mjs";
|
|
@@ -61,6 +56,7 @@ import "../_libs/mimic-function.mjs";
|
|
|
61
56
|
import "../_libs/semver.mjs";
|
|
62
57
|
import "../_libs/uint8array-extras.mjs";
|
|
63
58
|
import "node:child_process";
|
|
59
|
+
import "../_libs/modelcontextprotocol__server.mjs";
|
|
64
60
|
import "../_libs/use-sync-external-store.mjs";
|
|
65
61
|
import "../_libs/dequal.mjs";
|
|
66
62
|
import "../_libs/readable-stream.mjs";
|
|
@@ -112,57 +108,6 @@ import "../_libs/radix-ui__react-arrow.mjs";
|
|
|
112
108
|
import "../_libs/radix-ui__react-use-size.mjs";
|
|
113
109
|
import "../_libs/radix-ui__react-use-previous.mjs";
|
|
114
110
|
import "../_libs/@radix-ui/react-visually-hidden+[...].mjs";
|
|
115
|
-
import "../_libs/devlop.mjs";
|
|
116
|
-
import "../_libs/unified.mjs";
|
|
117
|
-
import "../_libs/bail.mjs";
|
|
118
|
-
import "../_libs/extend.mjs";
|
|
119
|
-
import "../_libs/is-plain-obj.mjs";
|
|
120
|
-
import "../_libs/trough.mjs";
|
|
121
|
-
import "../_libs/vfile.mjs";
|
|
122
|
-
import "../_libs/vfile-message.mjs";
|
|
123
|
-
import "../_libs/unist-util-stringify-position.mjs";
|
|
124
|
-
import "node:url";
|
|
125
|
-
import "../_libs/remark-parse.mjs";
|
|
126
|
-
import "../_libs/mdast-util-from-markdown.mjs";
|
|
127
|
-
import "../_libs/micromark-util-decode-numeric-character-reference+[...].mjs";
|
|
128
|
-
import "../_libs/micromark-util-decode-string.mjs";
|
|
129
|
-
import "../_libs/decode-named-character-reference+[...].mjs";
|
|
130
|
-
import "../_libs/character-entities.mjs";
|
|
131
|
-
import "../_libs/micromark-util-normalize-identifier+[...].mjs";
|
|
132
|
-
import "../_libs/micromark.mjs";
|
|
133
|
-
import "../_libs/micromark-util-combine-extensions+[...].mjs";
|
|
134
|
-
import "../_libs/micromark-util-chunked.mjs";
|
|
135
|
-
import "../_libs/micromark-factory-space.mjs";
|
|
136
|
-
import "../_libs/micromark-util-character.mjs";
|
|
137
|
-
import "../_libs/micromark-core-commonmark.mjs";
|
|
138
|
-
import "../_libs/micromark-util-classify-character+[...].mjs";
|
|
139
|
-
import "../_libs/micromark-util-resolve-all.mjs";
|
|
140
|
-
import "../_libs/micromark-util-subtokenize.mjs";
|
|
141
|
-
import "../_libs/micromark-factory-destination.mjs";
|
|
142
|
-
import "../_libs/micromark-factory-label.mjs";
|
|
143
|
-
import "../_libs/micromark-factory-title.mjs";
|
|
144
|
-
import "../_libs/micromark-factory-whitespace.mjs";
|
|
145
|
-
import "../_libs/micromark-util-html-tag-name.mjs";
|
|
146
|
-
import "../_libs/mdast-util-to-string.mjs";
|
|
147
|
-
import "../_libs/remark-rehype.mjs";
|
|
148
|
-
import "../_libs/mdast-util-to-hast.mjs";
|
|
149
|
-
import "../_libs/ungap__structured-clone.mjs";
|
|
150
|
-
import "../_libs/micromark-util-sanitize-uri.mjs";
|
|
151
|
-
import "../_libs/unist-util-position.mjs";
|
|
152
|
-
import "../_libs/trim-lines.mjs";
|
|
153
|
-
import "../_libs/unist-util-visit.mjs";
|
|
154
|
-
import "../_libs/unist-util-visit-parents.mjs";
|
|
155
|
-
import "../_libs/unist-util-is.mjs";
|
|
156
|
-
import "../_libs/hast-util-to-jsx-runtime.mjs";
|
|
157
|
-
import "../_libs/comma-separated-tokens.mjs";
|
|
158
|
-
import "../_libs/property-information.mjs";
|
|
159
|
-
import "../_libs/space-separated-tokens.mjs";
|
|
160
|
-
import "../_libs/style-to-js.mjs";
|
|
161
|
-
import "../_libs/style-to-object.mjs";
|
|
162
|
-
import "../_libs/inline-style-parser.mjs";
|
|
163
|
-
import "../_libs/hast-util-whitespace.mjs";
|
|
164
|
-
import "../_libs/estree-util-is-identifier-name.mjs";
|
|
165
|
-
import "../_libs/html-url-attributes.mjs";
|
|
166
111
|
import "../_libs/radix-ui__react-roving-focus.mjs";
|
|
167
112
|
const ApiErrorSchema = object({
|
|
168
113
|
error: string()
|
|
@@ -327,10 +272,10 @@ function OnboardingBanner() {
|
|
|
327
272
|
onClick: () => {
|
|
328
273
|
void markSeen();
|
|
329
274
|
},
|
|
330
|
-
className: "inline-flex items-center gap-1.5 text-xs
|
|
275
|
+
className: "inline-flex items-center gap-1.5 text-xs h-8 px-3 rounded-md border border-amber-500/40 text-amber-700 dark:text-amber-300 hover:bg-amber-500/10 transition-colors shrink-0",
|
|
331
276
|
"aria-label": "Dismiss onboarding tip",
|
|
332
277
|
children: [
|
|
333
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3" }),
|
|
278
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5" }),
|
|
334
279
|
"Got it"
|
|
335
280
|
]
|
|
336
281
|
}
|
|
@@ -390,7 +335,7 @@ async function exportLogsAsZip(logs) {
|
|
|
390
335
|
document.body.removeChild(anchor);
|
|
391
336
|
URL.revokeObjectURL(url);
|
|
392
337
|
}
|
|
393
|
-
const version = "1.16.
|
|
338
|
+
const version = "1.16.5";
|
|
394
339
|
const packageJson = {
|
|
395
340
|
version
|
|
396
341
|
};
|
|
@@ -398,9 +343,8 @@ function cn(...inputs) {
|
|
|
398
343
|
return twMerge(clsx(inputs));
|
|
399
344
|
}
|
|
400
345
|
function formatTokens(count) {
|
|
401
|
-
if (count >=
|
|
402
|
-
|
|
403
|
-
return count.toString();
|
|
346
|
+
if (count >= 1e6) return (count / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
|
|
347
|
+
return (count / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
|
|
404
348
|
}
|
|
405
349
|
function getStatusCategory(status) {
|
|
406
350
|
if (status === null) return "pending";
|
|
@@ -629,11 +573,14 @@ function ConversationHeader({
|
|
|
629
573
|
{
|
|
630
574
|
role: "button",
|
|
631
575
|
tabIndex: 0,
|
|
576
|
+
"data-nav-id": `conv-${conversationId}`,
|
|
577
|
+
"data-nav-action": expanded ? "collapse" : "expand",
|
|
632
578
|
className: cn(
|
|
633
579
|
"flex items-center gap-3 px-3 py-2 cursor-pointer transition-colors",
|
|
634
580
|
"hover:bg-muted/50",
|
|
635
581
|
"select-none",
|
|
636
|
-
"border border-border rounded-lg mb-2 bg-background sticky top-0 z-10"
|
|
582
|
+
"border border-border rounded-lg mb-2 bg-background sticky top-0 z-10",
|
|
583
|
+
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none"
|
|
637
584
|
),
|
|
638
585
|
onClick: onToggle,
|
|
639
586
|
onKeyDown: (e) => {
|
|
@@ -709,7 +656,7 @@ function ConversationHeader({
|
|
|
709
656
|
onClick: handleClearClick,
|
|
710
657
|
"aria-label": `Clear group (${totalCalls} request${totalCalls !== 1 ? "s" : ""})`,
|
|
711
658
|
title: "Clear this group",
|
|
712
|
-
className: "text-muted-foreground hover:text-foreground transition-colors shrink-0 inline-flex items-center justify-center size-
|
|
659
|
+
className: "text-muted-foreground hover:text-foreground transition-colors shrink-0 inline-flex items-center justify-center size-8 rounded hover:bg-muted cursor-pointer",
|
|
713
660
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" })
|
|
714
661
|
}
|
|
715
662
|
),
|
|
@@ -783,7 +730,7 @@ function groupLogsByConversation(logs) {
|
|
|
783
730
|
result.sort((a, b) => (a.logs[0]?.timestamp ?? "").localeCompare(b.logs[0]?.timestamp ?? ""));
|
|
784
731
|
return result;
|
|
785
732
|
}
|
|
786
|
-
function isRecord
|
|
733
|
+
function isRecord(value) {
|
|
787
734
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
788
735
|
}
|
|
789
736
|
function extractStopReason(log) {
|
|
@@ -793,14 +740,14 @@ function extractStopReason(log) {
|
|
|
793
740
|
if (typeof json === "string") {
|
|
794
741
|
json = JSON.parse(json);
|
|
795
742
|
}
|
|
796
|
-
if (!isRecord
|
|
743
|
+
if (!isRecord(json)) return null;
|
|
797
744
|
if (typeof json.stop_reason === "string") {
|
|
798
745
|
if (json.stop_reason === "end_turn" || json.stop_reason === "tool_use") {
|
|
799
746
|
return json.stop_reason;
|
|
800
747
|
}
|
|
801
748
|
return null;
|
|
802
749
|
}
|
|
803
|
-
if (Array.isArray(json.choices) && json.choices.length > 0 && isRecord
|
|
750
|
+
if (Array.isArray(json.choices) && json.choices.length > 0 && isRecord(json.choices[0]) && typeof json.choices[0].finish_reason === "string" && json.choices[0].finish_reason === "stop") {
|
|
804
751
|
return "stop";
|
|
805
752
|
}
|
|
806
753
|
return null;
|
|
@@ -1151,8 +1098,17 @@ const crabVariants = [
|
|
|
1151
1098
|
Crab11,
|
|
1152
1099
|
Crab12
|
|
1153
1100
|
];
|
|
1154
|
-
function getCrabVariant(
|
|
1155
|
-
return crabVariants[Math.abs(
|
|
1101
|
+
function getCrabVariant(index2) {
|
|
1102
|
+
return crabVariants[Math.abs(index2) % crabVariants.length] ?? Crab1;
|
|
1103
|
+
}
|
|
1104
|
+
function getInteriorCrabVariantIndex(seed) {
|
|
1105
|
+
const interiorCount = crabVariants.length - 2;
|
|
1106
|
+
if (interiorCount <= 0) return 0;
|
|
1107
|
+
const normalizedSeed = Number.isFinite(seed) ? Math.trunc(seed) : 0;
|
|
1108
|
+
return 1 + (normalizedSeed % interiorCount + interiorCount) % interiorCount;
|
|
1109
|
+
}
|
|
1110
|
+
function getInteriorCrabVariant(seed) {
|
|
1111
|
+
return getCrabVariant(getInteriorCrabVariantIndex(seed));
|
|
1156
1112
|
}
|
|
1157
1113
|
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";
|
|
1158
1114
|
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";
|
|
@@ -1276,85 +1232,6 @@ function TooltipContent({
|
|
|
1276
1232
|
}
|
|
1277
1233
|
) });
|
|
1278
1234
|
}
|
|
1279
|
-
function classifyValue(value) {
|
|
1280
|
-
if (value === null) return "null";
|
|
1281
|
-
if (Array.isArray(value)) return "array";
|
|
1282
|
-
switch (typeof value) {
|
|
1283
|
-
case "string":
|
|
1284
|
-
return "string";
|
|
1285
|
-
case "number":
|
|
1286
|
-
return "number";
|
|
1287
|
-
case "boolean":
|
|
1288
|
-
return "boolean";
|
|
1289
|
-
case "object":
|
|
1290
|
-
return "object";
|
|
1291
|
-
case "bigint":
|
|
1292
|
-
case "symbol":
|
|
1293
|
-
case "undefined":
|
|
1294
|
-
case "function":
|
|
1295
|
-
return "object";
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
function isExpandable(value) {
|
|
1299
|
-
return value !== null && (Array.isArray(value) || typeof value === "object");
|
|
1300
|
-
}
|
|
1301
|
-
function getEntries(value) {
|
|
1302
|
-
if (Array.isArray(value)) {
|
|
1303
|
-
return value.map((item, index) => [String(index), item]);
|
|
1304
|
-
}
|
|
1305
|
-
if (typeof value === "object" && value !== null) {
|
|
1306
|
-
return Object.entries(value);
|
|
1307
|
-
}
|
|
1308
|
-
return [];
|
|
1309
|
-
}
|
|
1310
|
-
const JSON_FULL_EXPANSION_NODE_LIMIT = 1e3;
|
|
1311
|
-
const JSON_LARGE_EXPANSION_DEPTH = 2;
|
|
1312
|
-
function countJsonNodes(value, limit = Number.POSITIVE_INFINITY) {
|
|
1313
|
-
let count = 0;
|
|
1314
|
-
const pending = [value];
|
|
1315
|
-
while (pending.length > 0) {
|
|
1316
|
-
const current = pending.pop();
|
|
1317
|
-
if (current === void 0) continue;
|
|
1318
|
-
count += 1;
|
|
1319
|
-
if (count > limit) return count;
|
|
1320
|
-
if (!isExpandable(current)) continue;
|
|
1321
|
-
for (const [, child] of getEntries(current)) {
|
|
1322
|
-
pending.push(child);
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
return count;
|
|
1326
|
-
}
|
|
1327
|
-
function getJsonExpansionPolicy(value) {
|
|
1328
|
-
const countedNodes = countJsonNodes(value, JSON_FULL_EXPANSION_NODE_LIMIT);
|
|
1329
|
-
const limited = countedNodes > JSON_FULL_EXPANSION_NODE_LIMIT;
|
|
1330
|
-
return {
|
|
1331
|
-
depth: limited ? JSON_LARGE_EXPANSION_DEPTH : Number.POSITIVE_INFINITY,
|
|
1332
|
-
limited,
|
|
1333
|
-
countedNodes
|
|
1334
|
-
};
|
|
1335
|
-
}
|
|
1336
|
-
function useJsonBulkExpansion(text) {
|
|
1337
|
-
const parsed = reactExports.useMemo(() => text === null ? null : parseJsonText(text), [text]);
|
|
1338
|
-
const parsedData = parsed?.kind === "json" ? parsed.data : null;
|
|
1339
|
-
const policy = reactExports.useMemo(
|
|
1340
|
-
() => parsedData === null ? null : getJsonExpansionPolicy(parsedData),
|
|
1341
|
-
[parsedData]
|
|
1342
|
-
);
|
|
1343
|
-
const [isExpanded, setIsExpanded] = reactExports.useState(false);
|
|
1344
|
-
const [bulkDepth, setBulkDepth] = reactExports.useState(0);
|
|
1345
|
-
const [bulkRevision, setBulkRevision] = reactExports.useState(0);
|
|
1346
|
-
const [isPending, startTransition] = reactExports.useTransition();
|
|
1347
|
-
const toggle = reactExports.useCallback(() => {
|
|
1348
|
-
const nextExpanded = !isExpanded;
|
|
1349
|
-
const targetDepth = nextExpanded && policy !== null ? policy.depth : 0;
|
|
1350
|
-
startTransition(() => {
|
|
1351
|
-
setIsExpanded(nextExpanded);
|
|
1352
|
-
setBulkDepth(targetDepth);
|
|
1353
|
-
setBulkRevision((current) => current + 1);
|
|
1354
|
-
});
|
|
1355
|
-
}, [isExpanded, policy]);
|
|
1356
|
-
return { parsedData, policy, isExpanded, toggle, isPending, bulkDepth, bulkRevision };
|
|
1357
|
-
}
|
|
1358
1235
|
function JsonExpansionButton({
|
|
1359
1236
|
policy,
|
|
1360
1237
|
isExpanded,
|
|
@@ -1362,15 +1239,15 @@ function JsonExpansionButton({
|
|
|
1362
1239
|
onToggle
|
|
1363
1240
|
}) {
|
|
1364
1241
|
if (policy === null) return null;
|
|
1365
|
-
const label = isPending ? "Updating..." : isExpanded ? "Collapse all" :
|
|
1366
|
-
const tooltip =
|
|
1367
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1242
|
+
const label = isPending ? "Updating..." : isExpanded ? "Collapse all" : "Expand all";
|
|
1243
|
+
const tooltip = isExpanded ? "Collapse all JSON nodes" : "Expand all JSON nodes";
|
|
1244
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1368
1245
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1369
1246
|
Button,
|
|
1370
1247
|
{
|
|
1371
1248
|
variant: "outline",
|
|
1372
1249
|
size: "sm",
|
|
1373
|
-
className: "h-
|
|
1250
|
+
className: "h-8 text-xs",
|
|
1374
1251
|
onClick: (e) => {
|
|
1375
1252
|
e.stopPropagation();
|
|
1376
1253
|
onToggle();
|
|
@@ -1378,283 +1255,17 @@ function JsonExpansionButton({
|
|
|
1378
1255
|
disabled: isPending,
|
|
1379
1256
|
"aria-pressed": isExpanded,
|
|
1380
1257
|
children: [
|
|
1381
|
-
isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsUp, { className: "size-3 mr-1" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsDown, { className: "size-3 mr-1" }),
|
|
1258
|
+
isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsUp, { className: "size-3.5 mr-1" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsDown, { className: "size-3.5 mr-1" }),
|
|
1382
1259
|
label
|
|
1383
1260
|
]
|
|
1384
1261
|
}
|
|
1385
1262
|
) }),
|
|
1386
1263
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: tooltip })
|
|
1387
|
-
] });
|
|
1388
|
-
}
|
|
1389
|
-
const STRING_TRUNCATE_LIMIT = 120;
|
|
1390
|
-
function StringValue({ text }) {
|
|
1391
|
-
const [expanded, setExpanded] = reactExports.useState(false);
|
|
1392
|
-
const isLong = text.length > STRING_TRUNCATE_LIMIT;
|
|
1393
|
-
if (!isLong) {
|
|
1394
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-emerald-400 break-all", children: [
|
|
1395
|
-
'"',
|
|
1396
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "prose prose-sm dark:prose-invert inline max-w-none [&_p]:inline [&_p]:my-0 [&_code]:text-emerald-300 [&_a]:text-emerald-300", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { children: text }) }),
|
|
1397
|
-
'"'
|
|
1398
|
-
] });
|
|
1399
|
-
}
|
|
1400
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-emerald-400 break-all", children: [
|
|
1401
|
-
'"',
|
|
1402
|
-
expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1403
|
-
"span",
|
|
1404
|
-
{
|
|
1405
|
-
className: "cursor-pointer prose prose-sm dark:prose-invert inline max-w-none [&_p]:inline [&_p]:my-0 [&_code]:text-emerald-300 [&_a]:text-emerald-300",
|
|
1406
|
-
onClick: (e) => {
|
|
1407
|
-
e.stopPropagation();
|
|
1408
|
-
setExpanded(false);
|
|
1409
|
-
},
|
|
1410
|
-
onKeyDown: (e) => {
|
|
1411
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
1412
|
-
e.stopPropagation();
|
|
1413
|
-
setExpanded(false);
|
|
1414
|
-
}
|
|
1415
|
-
},
|
|
1416
|
-
role: "button",
|
|
1417
|
-
tabIndex: 0,
|
|
1418
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { children: text })
|
|
1419
|
-
}
|
|
1420
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { delayDuration: 300, children: [
|
|
1421
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1422
|
-
TooltipTrigger,
|
|
1423
|
-
{
|
|
1424
|
-
onClick: (e) => {
|
|
1425
|
-
e.stopPropagation();
|
|
1426
|
-
setExpanded(true);
|
|
1427
|
-
},
|
|
1428
|
-
className: "text-left cursor-pointer",
|
|
1429
|
-
children: [
|
|
1430
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: text.slice(0, STRING_TRUNCATE_LIMIT) }),
|
|
1431
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-emerald-400/50", children: "…" })
|
|
1432
|
-
]
|
|
1433
|
-
}
|
|
1434
|
-
),
|
|
1435
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1436
|
-
TooltipContent,
|
|
1437
|
-
{
|
|
1438
|
-
side: "bottom",
|
|
1439
|
-
className: "max-w-md text-xs p-2 break-words whitespace-pre-wrap",
|
|
1440
|
-
children: [
|
|
1441
|
-
text.slice(0, 500),
|
|
1442
|
-
text.length > 500 ? "…" : ""
|
|
1443
|
-
]
|
|
1444
|
-
}
|
|
1445
|
-
)
|
|
1446
|
-
] }),
|
|
1447
|
-
'"'
|
|
1448
|
-
] });
|
|
1449
|
-
}
|
|
1450
|
-
function PrimitiveValue({ value }) {
|
|
1451
|
-
if (value === null) {
|
|
1452
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-rose-400 italic", children: "null" });
|
|
1453
|
-
}
|
|
1454
|
-
switch (typeof value) {
|
|
1455
|
-
case "string":
|
|
1456
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(StringValue, { text: value });
|
|
1457
|
-
case "number":
|
|
1458
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-amber-400", children: value });
|
|
1459
|
-
case "boolean":
|
|
1460
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-400", children: value ? "true" : "false" });
|
|
1461
|
-
case "object":
|
|
1462
|
-
case "bigint":
|
|
1463
|
-
case "symbol":
|
|
1464
|
-
case "undefined":
|
|
1465
|
-
case "function":
|
|
1466
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground", children: JSON.stringify(value) });
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
function CopyValueButton({ value }) {
|
|
1470
|
-
const [copied, setCopied] = reactExports.useState(false);
|
|
1471
|
-
function handleCopy(e) {
|
|
1472
|
-
e.stopPropagation();
|
|
1473
|
-
void window.navigator.clipboard.writeText(JSON.stringify(value, null, 2)).then(() => {
|
|
1474
|
-
setCopied(true);
|
|
1475
|
-
setTimeout(() => {
|
|
1476
|
-
setCopied(false);
|
|
1477
|
-
}, 2e3);
|
|
1478
|
-
});
|
|
1479
|
-
}
|
|
1480
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1481
|
-
"button",
|
|
1482
|
-
{
|
|
1483
|
-
type: "button",
|
|
1484
|
-
onClick: handleCopy,
|
|
1485
|
-
className: "inline-flex items-center gap-1 text-[10px] text-muted-foreground hover:text-foreground transition-colors",
|
|
1486
|
-
title: "Copy JSON",
|
|
1487
|
-
children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3 text-green-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3" })
|
|
1488
|
-
}
|
|
1489
|
-
);
|
|
1490
|
-
}
|
|
1491
|
-
function CopyButton$1({ value }) {
|
|
1492
|
-
const [copied, setCopied] = reactExports.useState(false);
|
|
1493
|
-
function handleCopy(e) {
|
|
1494
|
-
e.stopPropagation();
|
|
1495
|
-
void window.navigator.clipboard.writeText(JSON.stringify(value, null, 2)).then(() => {
|
|
1496
|
-
setCopied(true);
|
|
1497
|
-
setTimeout(() => {
|
|
1498
|
-
setCopied(false);
|
|
1499
|
-
}, 2e3);
|
|
1500
|
-
});
|
|
1501
|
-
}
|
|
1502
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1503
|
-
"button",
|
|
1504
|
-
{
|
|
1505
|
-
type: "button",
|
|
1506
|
-
onClick: handleCopy,
|
|
1507
|
-
className: "opacity-0 group-hover/row:opacity-100 hover:bg-muted p-0.5 rounded transition-opacity shrink-0",
|
|
1508
|
-
title: "Copy to clipboard",
|
|
1509
|
-
children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3 text-green-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3 text-muted-foreground" })
|
|
1510
|
-
}
|
|
1511
|
-
);
|
|
1512
|
-
}
|
|
1513
|
-
function ExpandCollapseButton({
|
|
1514
|
-
onClick
|
|
1515
|
-
}) {
|
|
1516
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1517
|
-
"button",
|
|
1518
|
-
{
|
|
1519
|
-
type: "button",
|
|
1520
|
-
onClick,
|
|
1521
|
-
className: "opacity-0 group-hover/row:opacity-100 hover:bg-muted p-0.5 rounded transition-opacity shrink-0",
|
|
1522
|
-
title: "Expand all descendants",
|
|
1523
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsDown, { className: "size-3.5 text-muted-foreground" })
|
|
1524
|
-
}
|
|
1525
|
-
);
|
|
1526
|
-
}
|
|
1527
|
-
const JsonNode = reactExports.memo(function JsonNode2({
|
|
1528
|
-
name,
|
|
1529
|
-
value,
|
|
1530
|
-
level,
|
|
1531
|
-
defaultExpandDepth,
|
|
1532
|
-
isArrayItem
|
|
1533
|
-
}) {
|
|
1534
|
-
const [expanded, setExpanded] = reactExports.useState(level < defaultExpandDepth);
|
|
1535
|
-
const [childResetKey, setChildResetKey] = reactExports.useState(0);
|
|
1536
|
-
const [childDepthOverride, setChildDepthOverride] = reactExports.useState(null);
|
|
1537
|
-
const expandable = isExpandable(value);
|
|
1538
|
-
const fullyExpanded = childDepthOverride === Number.POSITIVE_INFINITY;
|
|
1539
|
-
const entries = reactExports.useMemo(() => getEntries(value), [value]);
|
|
1540
|
-
const hasExpandableChild = reactExports.useMemo(
|
|
1541
|
-
() => entries.some(([, child]) => isExpandable(child)),
|
|
1542
|
-
[entries]
|
|
1543
|
-
);
|
|
1544
|
-
const dataType = classifyValue(value);
|
|
1545
|
-
const openBracket = dataType === "array" ? "[" : "{";
|
|
1546
|
-
const closeBracket = dataType === "array" ? "]" : "}";
|
|
1547
|
-
function expandAllDeep() {
|
|
1548
|
-
setExpanded(true);
|
|
1549
|
-
setChildDepthOverride(Number.POSITIVE_INFINITY);
|
|
1550
|
-
setChildResetKey((k) => k + 1);
|
|
1551
|
-
}
|
|
1552
|
-
function collapseToDefault() {
|
|
1553
|
-
setExpanded(false);
|
|
1554
|
-
setChildDepthOverride(0);
|
|
1555
|
-
setChildResetKey((k) => k + 1);
|
|
1556
|
-
}
|
|
1557
|
-
function handleRowToggle() {
|
|
1558
|
-
if (fullyExpanded) {
|
|
1559
|
-
collapseToDefault();
|
|
1560
|
-
} else {
|
|
1561
|
-
setExpanded(!expanded);
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
function handleExpandAll(e) {
|
|
1565
|
-
e.stopPropagation();
|
|
1566
|
-
expandAllDeep();
|
|
1567
|
-
}
|
|
1568
|
-
const effectiveChildDepth = childDepthOverride ?? defaultExpandDepth;
|
|
1569
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn(level > 0 && "border-l border-border/50 ml-2"), children: [
|
|
1570
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1571
|
-
"div",
|
|
1572
|
-
{
|
|
1573
|
-
className: cn(
|
|
1574
|
-
"flex items-start gap-1 py-0.5 px-1 -ml-1 rounded-sm group/row",
|
|
1575
|
-
expandable && "cursor-pointer hover:bg-muted/50"
|
|
1576
|
-
),
|
|
1577
|
-
onClick: expandable ? handleRowToggle : void 0,
|
|
1578
|
-
onKeyDown: expandable ? (e) => {
|
|
1579
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
1580
|
-
e.preventDefault();
|
|
1581
|
-
handleRowToggle();
|
|
1582
|
-
}
|
|
1583
|
-
} : void 0,
|
|
1584
|
-
onDoubleClick: expandable && hasExpandableChild ? () => expandAllDeep() : void 0,
|
|
1585
|
-
role: expandable ? "button" : void 0,
|
|
1586
|
-
tabIndex: expandable ? 0 : void 0,
|
|
1587
|
-
children: [
|
|
1588
|
-
expandable ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-4 h-5 flex items-center justify-center shrink-0", children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3 text-muted-foreground" }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-4 shrink-0" }),
|
|
1589
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn("shrink-0", isArrayItem ? "text-muted-foreground" : "text-cyan-400"), children: isArrayItem ? name : `"${name}"` }),
|
|
1590
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground shrink-0", children: expandable ? "" : ":" }),
|
|
1591
|
-
expandable ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground", children: [
|
|
1592
|
-
openBracket,
|
|
1593
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground/60 text-xs", children: [
|
|
1594
|
-
" ",
|
|
1595
|
-
entries.length,
|
|
1596
|
-
" ",
|
|
1597
|
-
entries.length === 1 ? "item" : "items",
|
|
1598
|
-
" ",
|
|
1599
|
-
closeBracket
|
|
1600
|
-
] })
|
|
1601
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(PrimitiveValue, { value }) }),
|
|
1602
|
-
expandable && hasExpandableChild && !fullyExpanded && /* @__PURE__ */ jsxRuntimeExports.jsx(ExpandCollapseButton, { onClick: handleExpandAll }),
|
|
1603
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(CopyButton$1, { value })
|
|
1604
|
-
]
|
|
1605
|
-
}
|
|
1606
|
-
),
|
|
1607
|
-
expandable && expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "pl-4", children: [
|
|
1608
|
-
entries.map(([key, childValue]) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1609
|
-
JsonNode2,
|
|
1610
|
-
{
|
|
1611
|
-
name: key,
|
|
1612
|
-
value: childValue,
|
|
1613
|
-
level: level + 1,
|
|
1614
|
-
defaultExpandDepth: effectiveChildDepth,
|
|
1615
|
-
isArrayItem: dataType === "array"
|
|
1616
|
-
},
|
|
1617
|
-
key
|
|
1618
|
-
)),
|
|
1619
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground py-0.5 px-1", children: closeBracket })
|
|
1620
|
-
] }, childResetKey)
|
|
1621
|
-
] });
|
|
1622
|
-
});
|
|
1623
|
-
function JsonViewer({
|
|
1624
|
-
data,
|
|
1625
|
-
defaultExpandDepth = 0,
|
|
1626
|
-
className,
|
|
1627
|
-
showCopy = false,
|
|
1628
|
-
bulkDepth: controlledBulkDepth,
|
|
1629
|
-
bulkRevision: controlledBulkRevision
|
|
1630
|
-
}) {
|
|
1631
|
-
const expandable = isExpandable(data);
|
|
1632
|
-
const entries = reactExports.useMemo(() => getEntries(data), [data]);
|
|
1633
|
-
const bulkDepth = controlledBulkDepth ?? defaultExpandDepth;
|
|
1634
|
-
const bulkRevision = controlledBulkRevision ?? 0;
|
|
1635
|
-
if (!expandable) {
|
|
1636
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("font-mono text-xs leading-relaxed", className), children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
1637
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(PrimitiveValue, { value: data }),
|
|
1638
|
-
showCopy && /* @__PURE__ */ jsxRuntimeExports.jsx(CopyValueButton, { value: data })
|
|
1639
|
-
] }) }) });
|
|
1640
|
-
}
|
|
1641
|
-
const dataType = classifyValue(data);
|
|
1642
|
-
const isArray = dataType === "array";
|
|
1643
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn("font-mono text-xs leading-relaxed", className), children: [
|
|
1644
|
-
showCopy && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-2 flex items-center justify-end gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyValueButton, { value: data }) }),
|
|
1645
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: entries.map(([key, childValue]) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1646
|
-
JsonNode,
|
|
1647
|
-
{
|
|
1648
|
-
name: key,
|
|
1649
|
-
value: childValue,
|
|
1650
|
-
level: 0,
|
|
1651
|
-
defaultExpandDepth: bulkDepth,
|
|
1652
|
-
isArrayItem: isArray
|
|
1653
|
-
},
|
|
1654
|
-
key
|
|
1655
|
-
)) }, bulkRevision)
|
|
1656
1264
|
] }) });
|
|
1657
1265
|
}
|
|
1266
|
+
function getJsonExpansionPolicy(_value) {
|
|
1267
|
+
return { depth: Number.POSITIVE_INFINITY };
|
|
1268
|
+
}
|
|
1658
1269
|
function parseJsonText(text) {
|
|
1659
1270
|
try {
|
|
1660
1271
|
const parsed = JSON.parse(text);
|
|
@@ -1663,24 +1274,28 @@ function parseJsonText(text) {
|
|
|
1663
1274
|
return { kind: "text" };
|
|
1664
1275
|
}
|
|
1665
1276
|
}
|
|
1666
|
-
|
|
1667
|
-
text,
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
)
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1277
|
+
function useJsonBulkExpansion(text) {
|
|
1278
|
+
const parsed = reactExports.useMemo(() => text === null ? null : parseJsonText(text), [text]);
|
|
1279
|
+
const parsedData = parsed?.kind === "json" ? parsed.data : null;
|
|
1280
|
+
const policy = reactExports.useMemo(
|
|
1281
|
+
() => parsedData === null ? null : getJsonExpansionPolicy(),
|
|
1282
|
+
[parsedData]
|
|
1283
|
+
);
|
|
1284
|
+
const [isExpanded, setIsExpanded] = reactExports.useState(false);
|
|
1285
|
+
const [bulkDepth, setBulkDepth] = reactExports.useState(0);
|
|
1286
|
+
const [bulkRevision, setBulkRevision] = reactExports.useState(0);
|
|
1287
|
+
const [isPending, startTransition] = reactExports.useTransition();
|
|
1288
|
+
const toggle = reactExports.useCallback(() => {
|
|
1289
|
+
const nextExpanded = !isExpanded;
|
|
1290
|
+
const targetDepth = nextExpanded && policy !== null ? policy.depth : 0;
|
|
1291
|
+
startTransition(() => {
|
|
1292
|
+
setIsExpanded(nextExpanded);
|
|
1293
|
+
setBulkDepth(targetDepth);
|
|
1294
|
+
setBulkRevision((current) => current + 1);
|
|
1295
|
+
});
|
|
1296
|
+
}, [isExpanded, policy]);
|
|
1297
|
+
return { parsedData, policy, isExpanded, toggle, isPending, bulkDepth, bulkRevision };
|
|
1298
|
+
}
|
|
1684
1299
|
function safeJsonValue(value) {
|
|
1685
1300
|
if (value === null || value === void 0) return null;
|
|
1686
1301
|
switch (typeof value) {
|
|
@@ -1786,6 +1401,88 @@ function TabsContent({
|
|
|
1786
1401
|
}
|
|
1787
1402
|
);
|
|
1788
1403
|
}
|
|
1404
|
+
const LazyCompareDrawer = reactExports.lazy(
|
|
1405
|
+
() => import("./CompareDrawer-ftkJxyk6.mjs").then((m) => ({ default: m.CompareDrawer }))
|
|
1406
|
+
);
|
|
1407
|
+
const LazyReplayDialog = reactExports.lazy(
|
|
1408
|
+
() => import("./ReplayDialog-DcmE3lj5.mjs").then((m) => ({ default: m.ReplayDialog }))
|
|
1409
|
+
);
|
|
1410
|
+
const LazyRequestAnatomy = reactExports.lazy(
|
|
1411
|
+
() => import("./RequestAnatomy-rK_LNMdG.mjs").then((m) => ({ default: m.RequestAnatomy }))
|
|
1412
|
+
);
|
|
1413
|
+
const LazyResponseView = reactExports.lazy(
|
|
1414
|
+
() => import("./ResponseView-CbQ4n-aJ.mjs").then((m) => ({ default: m.ResponseView }))
|
|
1415
|
+
);
|
|
1416
|
+
const LazyStreamingChunkSequence = reactExports.lazy(
|
|
1417
|
+
() => import("./StreamingChunkSequence-84FZkIzv.mjs").then((m) => ({
|
|
1418
|
+
default: m.StreamingChunkSequence
|
|
1419
|
+
}))
|
|
1420
|
+
);
|
|
1421
|
+
const LazyJsonViewer = reactExports.lazy(
|
|
1422
|
+
() => import("./json-viewer-B-qpM5xC.mjs").then((m) => ({ default: m.JsonViewer }))
|
|
1423
|
+
);
|
|
1424
|
+
const LazyJsonViewerFromString = reactExports.lazy(
|
|
1425
|
+
() => import("./json-viewer-B-qpM5xC.mjs").then((m) => ({ default: m.JsonViewerFromString }))
|
|
1426
|
+
);
|
|
1427
|
+
const HIGHLIGHT_DURATION_MS = 1200;
|
|
1428
|
+
const MAX_HIGHLIGHT_ATTEMPTS = 12;
|
|
1429
|
+
function useAnatomyJump(options) {
|
|
1430
|
+
const { containerRef, setExpandToPath, ensureTabActive, highlightMs } = options;
|
|
1431
|
+
const highlightTimer = reactExports.useRef(null);
|
|
1432
|
+
return reactExports.useCallback(
|
|
1433
|
+
(segment2) => {
|
|
1434
|
+
ensureTabActive?.();
|
|
1435
|
+
setExpandToPath(segment2.path);
|
|
1436
|
+
const applyHighlight = (target) => {
|
|
1437
|
+
target.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
1438
|
+
target.classList.add(
|
|
1439
|
+
"ring-2",
|
|
1440
|
+
"ring-primary/60",
|
|
1441
|
+
"ring-offset-1",
|
|
1442
|
+
"ring-offset-background",
|
|
1443
|
+
"rounded-sm",
|
|
1444
|
+
"transition-shadow"
|
|
1445
|
+
);
|
|
1446
|
+
if (highlightTimer.current !== null) clearTimeout(highlightTimer.current);
|
|
1447
|
+
highlightTimer.current = setTimeout(() => {
|
|
1448
|
+
target.classList.remove(
|
|
1449
|
+
"ring-2",
|
|
1450
|
+
"ring-primary/60",
|
|
1451
|
+
"ring-offset-1",
|
|
1452
|
+
"ring-offset-background",
|
|
1453
|
+
"rounded-sm",
|
|
1454
|
+
"transition-shadow"
|
|
1455
|
+
);
|
|
1456
|
+
setExpandToPath(null);
|
|
1457
|
+
}, highlightMs ?? HIGHLIGHT_DURATION_MS);
|
|
1458
|
+
};
|
|
1459
|
+
const escape = (value) => {
|
|
1460
|
+
if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
|
|
1461
|
+
return CSS.escape(value);
|
|
1462
|
+
}
|
|
1463
|
+
return value.replace(/(["'\\[\](){}])/g, "\\$1");
|
|
1464
|
+
};
|
|
1465
|
+
const selector = `[data-anatomy-path="${escape(segment2.path)}"]`;
|
|
1466
|
+
const tryFindTarget = (attemptsLeft) => {
|
|
1467
|
+
const container = containerRef.current;
|
|
1468
|
+
if (container !== null) {
|
|
1469
|
+
const target = container.querySelector(selector);
|
|
1470
|
+
if (target !== null) {
|
|
1471
|
+
applyHighlight(target);
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
if (attemptsLeft > 0) {
|
|
1476
|
+
window.requestAnimationFrame(() => tryFindTarget(attemptsLeft - 1));
|
|
1477
|
+
} else {
|
|
1478
|
+
setExpandToPath(null);
|
|
1479
|
+
}
|
|
1480
|
+
};
|
|
1481
|
+
window.requestAnimationFrame(() => tryFindTarget(MAX_HIGHLIGHT_ATTEMPTS));
|
|
1482
|
+
},
|
|
1483
|
+
[containerRef, ensureTabActive, highlightMs, setExpandToPath]
|
|
1484
|
+
);
|
|
1485
|
+
}
|
|
1789
1486
|
function normalizeHeaders(headers) {
|
|
1790
1487
|
if (headers === void 0) return [];
|
|
1791
1488
|
return Object.entries(headers).map((entry) => [entry[0].toLowerCase(), entry[1]]).sort(([a], [b]) => a.localeCompare(b));
|
|
@@ -2113,16 +1810,16 @@ function SplitRows({ lines }) {
|
|
|
2113
1810
|
)) });
|
|
2114
1811
|
}
|
|
2115
1812
|
const DiffView = reactExports.memo(DiffViewInner);
|
|
2116
|
-
function formatElapsed$1(ms) {
|
|
2117
|
-
if (ms < 1e3) return `${ms}ms`;
|
|
2118
|
-
return `${(ms / 1e3).toFixed(1)}s`;
|
|
2119
|
-
}
|
|
2120
1813
|
const STATUS_BADGE_CLASSES = {
|
|
2121
1814
|
success: "bg-emerald-500/15 text-emerald-400 border-emerald-500/25",
|
|
2122
1815
|
client_error: "bg-amber-500/15 text-amber-400 border-amber-500/25",
|
|
2123
|
-
server_error: "",
|
|
1816
|
+
server_error: "bg-rose-500/15 text-rose-400 border-rose-500/25",
|
|
2124
1817
|
pending: "bg-muted text-muted-foreground border-border"
|
|
2125
1818
|
};
|
|
1819
|
+
function formatElapsed$1(ms) {
|
|
1820
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
1821
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
1822
|
+
}
|
|
2126
1823
|
function CacheTrendIndicator({ trend }) {
|
|
2127
1824
|
if (trend === null) return null;
|
|
2128
1825
|
const isUp = trend.direction === "up";
|
|
@@ -2143,7 +1840,12 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
2143
1840
|
expanded,
|
|
2144
1841
|
onToggle,
|
|
2145
1842
|
responseToolNames = null,
|
|
2146
|
-
cacheTrend = null
|
|
1843
|
+
cacheTrend = null,
|
|
1844
|
+
onReplay,
|
|
1845
|
+
onCopyRequest,
|
|
1846
|
+
requestCopied = false,
|
|
1847
|
+
onToggleRequestExpansion,
|
|
1848
|
+
requestExpansionState = null
|
|
2147
1849
|
}) {
|
|
2148
1850
|
const statusCategory = getStatusCategory(log.responseStatus);
|
|
2149
1851
|
const hasTokens = log.inputTokens !== null || log.outputTokens !== null;
|
|
@@ -2153,10 +1855,13 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
2153
1855
|
{
|
|
2154
1856
|
role: "button",
|
|
2155
1857
|
tabIndex: 0,
|
|
1858
|
+
"data-nav-id": `log-${log.id}`,
|
|
1859
|
+
"data-nav-action": expanded ? "collapse" : "expand",
|
|
2156
1860
|
className: cn(
|
|
2157
1861
|
"flex items-center gap-2 px-3 py-1 cursor-pointer transition-colors",
|
|
2158
1862
|
"hover:bg-muted/50",
|
|
2159
|
-
"select-none"
|
|
1863
|
+
"select-none",
|
|
1864
|
+
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none"
|
|
2160
1865
|
),
|
|
2161
1866
|
onClick: onToggle,
|
|
2162
1867
|
onKeyDown: (e) => {
|
|
@@ -2174,34 +1879,20 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
2174
1879
|
/* @__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" }) }) }),
|
|
2175
1880
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: log.model })
|
|
2176
1881
|
] }),
|
|
2177
|
-
statusCategory !== "success" && /* @__PURE__ */ jsxRuntimeExports.
|
|
2178
|
-
Badge,
|
|
2179
|
-
{
|
|
2180
|
-
variant: "destructive",
|
|
2181
|
-
className: "text-[10px] px-1.5 py-0 h-4 font-mono tabular-nums",
|
|
2182
|
-
children: log.responseStatus
|
|
2183
|
-
}
|
|
2184
|
-
) : statusCategory === "pending" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1882
|
+
statusCategory !== "success" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2185
1883
|
Badge,
|
|
2186
1884
|
{
|
|
2187
1885
|
variant: "outline",
|
|
2188
1886
|
className: cn(
|
|
2189
|
-
"text-[10px] px-1.5 py-0 h-
|
|
1887
|
+
"text-[10px] px-1.5 py-0 h-5 font-mono tabular-nums gap-1",
|
|
2190
1888
|
STATUS_BADGE_CLASSES[statusCategory]
|
|
2191
1889
|
),
|
|
2192
|
-
children:
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
{
|
|
2197
|
-
variant: "outline",
|
|
2198
|
-
className: cn(
|
|
2199
|
-
"text-[10px] px-1.5 py-0 h-4 font-mono tabular-nums",
|
|
2200
|
-
STATUS_BADGE_CLASSES[statusCategory]
|
|
2201
|
-
),
|
|
2202
|
-
children: log.responseStatus
|
|
1890
|
+
children: [
|
|
1891
|
+
statusCategory === "server_error" ? /* @__PURE__ */ jsxRuntimeExports.jsx(OctagonAlert, { className: "size-3", "aria-label": "Server error" }) : statusCategory === "client_error" ? /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Client error" }) : statusCategory === "pending" ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3 animate-spin", "aria-label": "Pending" }) : null,
|
|
1892
|
+
log.responseStatus
|
|
1893
|
+
]
|
|
2203
1894
|
}
|
|
2204
|
-
)
|
|
1895
|
+
),
|
|
2205
1896
|
log.elapsedMs !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
2206
1897
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
|
|
2207
1898
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed$1(log.elapsedMs) })
|
|
@@ -2290,337 +1981,91 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
2290
1981
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Request used SSE streaming" })
|
|
2291
1982
|
] }),
|
|
2292
1983
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
|
|
1984
|
+
expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1985
|
+
"span",
|
|
1986
|
+
{
|
|
1987
|
+
className: "flex items-center gap-1.5 shrink-0",
|
|
1988
|
+
onClick: (e) => e.stopPropagation(),
|
|
1989
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
1990
|
+
children: [
|
|
1991
|
+
requestExpansionState !== null && onToggleRequestExpansion !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1992
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1993
|
+
Button,
|
|
1994
|
+
{
|
|
1995
|
+
variant: "outline",
|
|
1996
|
+
size: "icon",
|
|
1997
|
+
className: "size-8",
|
|
1998
|
+
onClick: onToggleRequestExpansion,
|
|
1999
|
+
disabled: requestExpansionState.isPending,
|
|
2000
|
+
"aria-pressed": requestExpansionState.isExpanded,
|
|
2001
|
+
"aria-label": requestExpansionState.isExpanded ? "Collapse all JSON" : "Expand all JSON",
|
|
2002
|
+
children: requestExpansionState.isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsUp, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsDown, { className: "size-3.5" })
|
|
2003
|
+
}
|
|
2004
|
+
) }),
|
|
2005
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: requestExpansionState.isExpanded ? "Collapse all JSON nodes" : "Expand all JSON nodes" })
|
|
2006
|
+
] }),
|
|
2007
|
+
onCopyRequest !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2008
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2009
|
+
Button,
|
|
2010
|
+
{
|
|
2011
|
+
variant: "outline",
|
|
2012
|
+
size: "icon",
|
|
2013
|
+
className: "size-8",
|
|
2014
|
+
onClick: onCopyRequest,
|
|
2015
|
+
"aria-label": "Copy request body",
|
|
2016
|
+
children: requestCopied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-emerald-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
|
|
2017
|
+
}
|
|
2018
|
+
) }),
|
|
2019
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: requestCopied ? "Copied to clipboard" : "Copy request body" })
|
|
2020
|
+
] }),
|
|
2021
|
+
onReplay !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2022
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2023
|
+
Button,
|
|
2024
|
+
{
|
|
2025
|
+
variant: "outline",
|
|
2026
|
+
size: "icon",
|
|
2027
|
+
className: "size-8",
|
|
2028
|
+
onClick: onReplay,
|
|
2029
|
+
"aria-label": "Replay request",
|
|
2030
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { className: "size-3.5" })
|
|
2031
|
+
}
|
|
2032
|
+
) }),
|
|
2033
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Re-send this request to the provider" })
|
|
2034
|
+
] })
|
|
2035
|
+
]
|
|
2036
|
+
}
|
|
2037
|
+
),
|
|
2293
2038
|
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" })
|
|
2294
2039
|
]
|
|
2295
2040
|
}
|
|
2296
2041
|
) });
|
|
2297
2042
|
});
|
|
2298
|
-
function
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
decorative = true,
|
|
2302
|
-
...props
|
|
2303
|
-
}) {
|
|
2304
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2305
|
-
Root$1,
|
|
2306
|
-
{
|
|
2307
|
-
"data-slot": "separator",
|
|
2308
|
-
decorative,
|
|
2309
|
-
orientation,
|
|
2310
|
-
className: cn(
|
|
2311
|
-
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
|
2312
|
-
className
|
|
2313
|
-
),
|
|
2314
|
-
...props
|
|
2315
|
-
}
|
|
2316
|
-
);
|
|
2317
|
-
}
|
|
2318
|
-
function Collapsible({
|
|
2319
|
-
...props
|
|
2320
|
-
}) {
|
|
2321
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Root$2, { "data-slot": "collapsible", ...props });
|
|
2322
|
-
}
|
|
2323
|
-
function CollapsibleTrigger({
|
|
2324
|
-
...props
|
|
2325
|
-
}) {
|
|
2326
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleTrigger$1, { "data-slot": "collapsible-trigger", ...props });
|
|
2327
|
-
}
|
|
2328
|
-
function CollapsibleContent({
|
|
2329
|
-
...props
|
|
2330
|
-
}) {
|
|
2331
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleContent$1, { "data-slot": "collapsible-content", ...props });
|
|
2332
|
-
}
|
|
2333
|
-
function ScrollArea({
|
|
2334
|
-
className,
|
|
2335
|
-
children,
|
|
2336
|
-
...props
|
|
2337
|
-
}) {
|
|
2338
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2339
|
-
Root$3,
|
|
2340
|
-
{
|
|
2341
|
-
"data-slot": "scroll-area",
|
|
2342
|
-
className: cn("relative", className),
|
|
2343
|
-
...props,
|
|
2344
|
-
children: [
|
|
2345
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2346
|
-
Viewport$1,
|
|
2347
|
-
{
|
|
2348
|
-
"data-slot": "scroll-area-viewport",
|
|
2349
|
-
className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
|
|
2350
|
-
children
|
|
2351
|
-
}
|
|
2352
|
-
),
|
|
2353
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(ScrollBar, {}),
|
|
2354
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Corner, {})
|
|
2355
|
-
]
|
|
2356
|
-
}
|
|
2357
|
-
);
|
|
2358
|
-
}
|
|
2359
|
-
function ScrollBar({
|
|
2360
|
-
className,
|
|
2361
|
-
orientation = "vertical",
|
|
2362
|
-
...props
|
|
2363
|
-
}) {
|
|
2364
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2365
|
-
ScrollAreaScrollbar,
|
|
2366
|
-
{
|
|
2367
|
-
"data-slot": "scroll-area-scrollbar",
|
|
2368
|
-
orientation,
|
|
2369
|
-
className: cn(
|
|
2370
|
-
"flex touch-none p-px transition-colors select-none",
|
|
2371
|
-
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
|
|
2372
|
-
orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
|
|
2373
|
-
className
|
|
2374
|
-
),
|
|
2375
|
-
...props,
|
|
2376
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2377
|
-
ScrollAreaThumb,
|
|
2378
|
-
{
|
|
2379
|
-
"data-slot": "scroll-area-thumb",
|
|
2380
|
-
className: "bg-border relative flex-1 rounded-full"
|
|
2381
|
-
}
|
|
2382
|
-
)
|
|
2383
|
-
}
|
|
2384
|
-
);
|
|
2385
|
-
}
|
|
2386
|
-
function assertNever(_value) {
|
|
2387
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, {});
|
|
2388
|
-
}
|
|
2389
|
-
function SystemReminderBlock({ text }) {
|
|
2390
|
-
const [open, setOpen] = reactExports.useState(false);
|
|
2391
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Collapsible, { open, onOpenChange: setOpen, children: [
|
|
2392
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(CollapsibleTrigger, { className: "flex items-center gap-1.5 py-0.5 cursor-pointer hover:opacity-80 transition-opacity group", children: [
|
|
2393
|
-
open ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3 text-muted-foreground" }),
|
|
2394
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground text-xs italic select-none opacity-60", children: "[system-reminder]" })
|
|
2395
|
-
] }),
|
|
2396
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4 pt-1", children: /* @__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 }) }) }) })
|
|
2397
|
-
] });
|
|
2398
|
-
}
|
|
2399
|
-
const THINKING_TAG_REGEX = /<think>([\s\S]*?)<\/think>/gi;
|
|
2400
|
-
const THINKING_TAG_REGEX_SINGLE = /<think>([\s\S]*?)<\/think>/i;
|
|
2401
|
-
function extractThinkingFromContent(text) {
|
|
2402
|
-
const match = THINKING_TAG_REGEX_SINGLE.exec(text);
|
|
2403
|
-
if (!match || match[1] === void 0) {
|
|
2404
|
-
return { thinking: null, remainingText: text };
|
|
2405
|
-
}
|
|
2406
|
-
const thinking = match[1].trim();
|
|
2407
|
-
const remainingText = text.replace(THINKING_TAG_REGEX, "").trim();
|
|
2408
|
-
return { thinking, remainingText };
|
|
2409
|
-
}
|
|
2410
|
-
const TextBlock = reactExports.memo(function TextBlock2({ text }) {
|
|
2411
|
-
if (text.includes("<system-reminder>")) {
|
|
2412
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(SystemReminderBlock, { text });
|
|
2413
|
-
}
|
|
2414
|
-
const { thinking, remainingText } = extractThinkingFromContent(text);
|
|
2415
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
2416
|
-
thinking !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(ThinkingBlock, { thinking }),
|
|
2417
|
-
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 }) }),
|
|
2418
|
-
thinking === null && remainingText.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "Empty text block" })
|
|
2419
|
-
] });
|
|
2420
|
-
});
|
|
2421
|
-
const ThinkingBlock = reactExports.memo(function ThinkingBlock2({
|
|
2422
|
-
thinking
|
|
2423
|
-
}) {
|
|
2424
|
-
const [open, setOpen] = reactExports.useState(false);
|
|
2425
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Collapsible, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-l-2 border-purple-500/40 my-1", children: [
|
|
2426
|
-
/* @__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: [
|
|
2427
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Brain, { className: "size-3.5 text-purple-400 shrink-0" }),
|
|
2428
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium text-purple-400", children: "Thinking" }),
|
|
2429
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2430
|
-
Badge,
|
|
2431
|
-
{
|
|
2432
|
-
variant: "ghost",
|
|
2433
|
-
className: "text-[10px] text-muted-foreground px-1.5 py-0 h-4 font-mono",
|
|
2434
|
-
children: [
|
|
2435
|
-
thinking.length.toLocaleString(),
|
|
2436
|
-
" chars"
|
|
2437
|
-
]
|
|
2438
|
-
}
|
|
2439
|
-
),
|
|
2440
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1" }),
|
|
2441
|
-
open ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3 text-muted-foreground" })
|
|
2442
|
-
] }),
|
|
2443
|
-
/* @__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 }) }) }) })
|
|
2444
|
-
] }) });
|
|
2445
|
-
});
|
|
2446
|
-
const ToolUseBlock = reactExports.memo(function ToolUseBlock2({
|
|
2447
|
-
name,
|
|
2448
|
-
input
|
|
2449
|
-
}) {
|
|
2450
|
-
const [open, setOpen] = reactExports.useState(false);
|
|
2451
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Collapsible, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-l-2 border-blue-500/40 my-1", children: [
|
|
2452
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(CollapsibleTrigger, { className: "flex items-center gap-1.5 px-3 py-1 w-full text-left cursor-pointer hover:bg-blue-500/5 transition-colors rounded-r-sm group", children: [
|
|
2453
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { className: "size-3.5 text-blue-400 shrink-0" }),
|
|
2454
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "text-[10px] font-mono px-1.5 py-0 h-4", children: name }),
|
|
2455
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1" }),
|
|
2456
|
-
open ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3 text-muted-foreground" })
|
|
2457
|
-
] }),
|
|
2458
|
-
/* @__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: 0 }) }) }) })
|
|
2459
|
-
] }) });
|
|
2460
|
-
});
|
|
2461
|
-
const ResponseContentBlockRenderer = reactExports.memo(function ResponseContentBlockRenderer2({
|
|
2462
|
-
block
|
|
2463
|
-
}) {
|
|
2464
|
-
switch (block.type) {
|
|
2465
|
-
case "text":
|
|
2466
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(TextBlock, { text: block.text });
|
|
2467
|
-
case "thinking":
|
|
2468
|
-
case "think":
|
|
2469
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(ThinkingBlock, { thinking: block.thinking });
|
|
2470
|
-
case "tool_use":
|
|
2471
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(ToolUseBlock, { name: block.name, input: block.input });
|
|
2472
|
-
default:
|
|
2473
|
-
return assertNever();
|
|
2474
|
-
}
|
|
2475
|
-
});
|
|
2476
|
-
const StructuredResponseViewAnthropic = reactExports.memo(function StructuredResponseViewAnthropic2({
|
|
2477
|
-
response
|
|
2478
|
-
}) {
|
|
2479
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
|
|
2480
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
2481
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "secondary", className: "text-[10px] px-1.5 py-0 h-5 font-mono", children: response.model }),
|
|
2482
|
-
response.stop_reason !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2483
|
-
Badge,
|
|
2484
|
-
{
|
|
2485
|
-
variant: "outline",
|
|
2486
|
-
className: "text-[10px] px-1.5 py-0 h-5 font-mono flex items-center gap-1",
|
|
2487
|
-
children: [
|
|
2488
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleStop, { className: "size-2.5" }),
|
|
2489
|
-
response.stop_reason
|
|
2490
|
-
]
|
|
2491
|
-
}
|
|
2492
|
-
),
|
|
2493
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs", children: [
|
|
2494
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3" }),
|
|
2495
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
2496
|
-
formatTokens(response.usage.input_tokens ?? 0),
|
|
2497
|
-
" in /",
|
|
2498
|
-
" ",
|
|
2499
|
-
formatTokens(response.usage.output_tokens ?? 0),
|
|
2500
|
-
" out"
|
|
2501
|
-
] }),
|
|
2502
|
-
response.usage.cache_creation_input_tokens !== void 0 && response.usage.cache_creation_input_tokens !== null && response.usage.cache_creation_input_tokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-emerald-400", children: [
|
|
2503
|
-
"Cache +",
|
|
2504
|
-
formatTokens(response.usage.cache_creation_input_tokens)
|
|
2505
|
-
] }),
|
|
2506
|
-
response.usage.cache_read_input_tokens !== void 0 && response.usage.cache_read_input_tokens !== null && response.usage.cache_read_input_tokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
|
|
2507
|
-
"Cache ~",
|
|
2508
|
-
formatTokens(response.usage.cache_read_input_tokens)
|
|
2509
|
-
] })
|
|
2510
|
-
] })
|
|
2511
|
-
] }),
|
|
2512
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Separator, { className: "opacity-50" }),
|
|
2513
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
2514
|
-
response.content.map((block, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(ResponseContentBlockRenderer, { block }, i)),
|
|
2515
|
-
response.content.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "Empty response content" })
|
|
2516
|
-
] })
|
|
2517
|
-
] });
|
|
2518
|
-
});
|
|
2519
|
-
function parseToolArguments(raw) {
|
|
2520
|
-
if (raw === void 0 || raw === "") return {};
|
|
2521
|
-
try {
|
|
2522
|
-
return JSON.parse(raw);
|
|
2523
|
-
} catch {
|
|
2524
|
-
return null;
|
|
2043
|
+
function forEachCodePoint(text, visit) {
|
|
2044
|
+
for (const ch of Array.from(text)) {
|
|
2045
|
+
visit(ch);
|
|
2525
2046
|
}
|
|
2526
2047
|
}
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
// JSON.parse failed — show the raw string so the user can
|
|
2541
|
-
// still see what the model tried to call.
|
|
2542
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words text-rose-300/90", children: call.function.arguments })
|
|
2543
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewer, { data: safeJsonValue(parsed), defaultExpandDepth: 0 }) }) }) })
|
|
2544
|
-
] }) });
|
|
2545
|
-
}
|
|
2546
|
-
const OpenAIResponseView = reactExports.memo(function OpenAIResponseView2({
|
|
2547
|
-
response
|
|
2548
|
-
}) {
|
|
2549
|
-
const choice = response.choices[0];
|
|
2550
|
-
const message = choice?.message;
|
|
2551
|
-
const toolCalls = message?.tool_calls ?? [];
|
|
2552
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
|
|
2553
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
2554
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "secondary", className: "text-[10px] px-1.5 py-0 h-5 font-mono", children: response.model }),
|
|
2555
|
-
choice?.finish_reason !== null && choice?.finish_reason !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2556
|
-
Badge,
|
|
2557
|
-
{
|
|
2558
|
-
variant: "outline",
|
|
2559
|
-
className: "text-[10px] px-1.5 py-0 h-5 font-mono flex items-center gap-1",
|
|
2560
|
-
children: [
|
|
2561
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleStop, { className: "size-2.5" }),
|
|
2562
|
-
choice.finish_reason
|
|
2563
|
-
]
|
|
2564
|
-
}
|
|
2565
|
-
),
|
|
2566
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs", children: [
|
|
2567
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3" }),
|
|
2568
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
2569
|
-
formatTokens(response.usage.prompt_tokens ?? 0),
|
|
2570
|
-
" in /",
|
|
2571
|
-
" ",
|
|
2572
|
-
formatTokens(response.usage.completion_tokens ?? 0),
|
|
2573
|
-
" out"
|
|
2574
|
-
] })
|
|
2575
|
-
] })
|
|
2576
|
-
] }),
|
|
2577
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Separator, { className: "opacity-50" }),
|
|
2578
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
2579
|
-
message?.reasoning_content !== null && message?.reasoning_content !== void 0 && message.reasoning_content.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(ThinkingBlock, { thinking: message.reasoning_content }),
|
|
2580
|
-
message?.content !== null && message?.content !== void 0 && message.content.length > 0 && (() => {
|
|
2581
|
-
const hasReasoningField = message.reasoning_content !== null && message.reasoning_content !== void 0 && message.reasoning_content.length > 0;
|
|
2582
|
-
const { thinking, remainingText } = extractThinkingFromContent(message.content);
|
|
2583
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
2584
|
-
thinking !== null && !hasReasoningField && /* @__PURE__ */ jsxRuntimeExports.jsx(ThinkingBlock, { thinking }),
|
|
2585
|
-
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 }) })
|
|
2586
|
-
] });
|
|
2587
|
-
})(),
|
|
2588
|
-
toolCalls.map((call, i) => (
|
|
2589
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: tool_calls is the positionally stable list from the response
|
|
2590
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(OpenAIToolCallBlock, { call }, call.id ?? `tc-${i}`)
|
|
2591
|
-
)),
|
|
2592
|
-
message?.function_call !== null && message?.function_call !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-blue-500/30 rounded-md p-3 bg-blue-500/5", children: [
|
|
2593
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-blue-400 font-mono mb-1", children: "function_call" }),
|
|
2594
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-mono text-xs", children: [
|
|
2595
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-300", children: message.function_call.name }),
|
|
2596
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground", children: [
|
|
2597
|
-
"(",
|
|
2598
|
-
message.function_call.arguments,
|
|
2599
|
-
")"
|
|
2600
|
-
] })
|
|
2601
|
-
] })
|
|
2602
|
-
] }),
|
|
2603
|
-
(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" })
|
|
2604
|
-
] })
|
|
2605
|
-
] });
|
|
2606
|
-
});
|
|
2607
|
-
function isRecord(value) {
|
|
2608
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2609
|
-
}
|
|
2610
|
-
function isOpenAIResponse(response) {
|
|
2611
|
-
return isRecord(response) && response.object === "chat.completion";
|
|
2612
|
-
}
|
|
2613
|
-
function isAnthropicResponse(response) {
|
|
2614
|
-
return isRecord(response) && response.type === "message" && Array.isArray(response.content);
|
|
2048
|
+
const CJK_REGEX = /[\u3000-\u9FFF\uAC00-\uD7FF\uF900-\uFAFF\uFF00-\uFFEF\u{1F300}-\u{1FAFF}]/u;
|
|
2049
|
+
function estimateTokens(text) {
|
|
2050
|
+
if (text.length === 0) return 0;
|
|
2051
|
+
let cjk = 0;
|
|
2052
|
+
let other = 0;
|
|
2053
|
+
forEachCodePoint(text, (ch) => {
|
|
2054
|
+
if (CJK_REGEX.test(ch)) {
|
|
2055
|
+
cjk += 1;
|
|
2056
|
+
} else {
|
|
2057
|
+
other += 1;
|
|
2058
|
+
}
|
|
2059
|
+
});
|
|
2060
|
+
return Math.ceil(cjk * 1) + Math.ceil(other / 4);
|
|
2615
2061
|
}
|
|
2616
|
-
function
|
|
2617
|
-
if (
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
return null;
|
|
2062
|
+
function countCharacters(text) {
|
|
2063
|
+
if (text.length === 0) return 0;
|
|
2064
|
+
let n = 0;
|
|
2065
|
+
forEachCodePoint(text, () => {
|
|
2066
|
+
n += 1;
|
|
2067
|
+
});
|
|
2068
|
+
return n;
|
|
2624
2069
|
}
|
|
2625
2070
|
function emptyRequestAnalysis(rawBody) {
|
|
2626
2071
|
return {
|
|
@@ -2634,6 +2079,84 @@ const EMPTY_RESPONSE_ANALYSIS = {
|
|
|
2634
2079
|
parsed: null,
|
|
2635
2080
|
toolNames: null
|
|
2636
2081
|
};
|
|
2082
|
+
function contentToText$1(content) {
|
|
2083
|
+
if (typeof content === "string") return content;
|
|
2084
|
+
if (!Array.isArray(content)) return "";
|
|
2085
|
+
const parts = [];
|
|
2086
|
+
for (const block of content) {
|
|
2087
|
+
if (block === null || typeof block !== "object") continue;
|
|
2088
|
+
const b = block;
|
|
2089
|
+
const type = b.type;
|
|
2090
|
+
switch (type) {
|
|
2091
|
+
case "text":
|
|
2092
|
+
if (typeof b.text === "string") parts.push(b.text);
|
|
2093
|
+
break;
|
|
2094
|
+
case "thinking":
|
|
2095
|
+
case "think":
|
|
2096
|
+
if (typeof b.thinking === "string") parts.push(b.thinking);
|
|
2097
|
+
break;
|
|
2098
|
+
case "tool_use": {
|
|
2099
|
+
const name = typeof b.name === "string" ? b.name : "";
|
|
2100
|
+
const input = b.input !== void 0 ? JSON.stringify(b.input) : "";
|
|
2101
|
+
parts.push(`${name} ${input}`.trim());
|
|
2102
|
+
break;
|
|
2103
|
+
}
|
|
2104
|
+
case "tool_result": {
|
|
2105
|
+
const inner = b.content;
|
|
2106
|
+
if (typeof inner === "string") {
|
|
2107
|
+
parts.push(inner);
|
|
2108
|
+
} else if (Array.isArray(inner)) {
|
|
2109
|
+
for (const item of inner) {
|
|
2110
|
+
if (item !== null && typeof item === "object") {
|
|
2111
|
+
const t = item.text;
|
|
2112
|
+
if (typeof t === "string") parts.push(t);
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
break;
|
|
2117
|
+
}
|
|
2118
|
+
case "image":
|
|
2119
|
+
parts.push("[image]");
|
|
2120
|
+
break;
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
return parts.join("\n");
|
|
2124
|
+
}
|
|
2125
|
+
function systemToText(system) {
|
|
2126
|
+
if (typeof system === "string") return system;
|
|
2127
|
+
if (!Array.isArray(system)) return "";
|
|
2128
|
+
const parts = [];
|
|
2129
|
+
for (const block of system) {
|
|
2130
|
+
if (block !== null && typeof block === "object") {
|
|
2131
|
+
const t = block.text;
|
|
2132
|
+
const type = block.type;
|
|
2133
|
+
if (type === "text" && typeof t === "string") parts.push(t);
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
return parts.join("\n");
|
|
2137
|
+
}
|
|
2138
|
+
function toolsToText$1(tools) {
|
|
2139
|
+
if (!Array.isArray(tools)) return "";
|
|
2140
|
+
const parts = [];
|
|
2141
|
+
for (const tool of tools) {
|
|
2142
|
+
if (tool === null || typeof tool !== "object") continue;
|
|
2143
|
+
const t = tool;
|
|
2144
|
+
if (typeof t.name === "string") parts.push(t.name);
|
|
2145
|
+
if (typeof t.description === "string") parts.push(t.description);
|
|
2146
|
+
if (t.input_schema !== void 0) parts.push(JSON.stringify(t.input_schema));
|
|
2147
|
+
}
|
|
2148
|
+
return parts.join("\n");
|
|
2149
|
+
}
|
|
2150
|
+
function segment$1(role, label, text, path) {
|
|
2151
|
+
return {
|
|
2152
|
+
role,
|
|
2153
|
+
label,
|
|
2154
|
+
text,
|
|
2155
|
+
size: estimateTokens(text),
|
|
2156
|
+
characters: countCharacters(text),
|
|
2157
|
+
path
|
|
2158
|
+
};
|
|
2159
|
+
}
|
|
2637
2160
|
const anthropicLogFormatAdapter = {
|
|
2638
2161
|
format: "anthropic",
|
|
2639
2162
|
analyzeRequest(rawBody) {
|
|
@@ -2666,8 +2189,92 @@ const anthropicLogFormatAdapter = {
|
|
|
2666
2189
|
} catch {
|
|
2667
2190
|
return EMPTY_RESPONSE_ANALYSIS;
|
|
2668
2191
|
}
|
|
2192
|
+
},
|
|
2193
|
+
anatomySegments(parsed) {
|
|
2194
|
+
if (parsed === null || typeof parsed !== "object") return null;
|
|
2195
|
+
const body = parsed;
|
|
2196
|
+
const segments = [];
|
|
2197
|
+
if (body.system !== void 0) {
|
|
2198
|
+
const text = systemToText(body.system);
|
|
2199
|
+
if (text.length > 0) {
|
|
2200
|
+
segments.push(segment$1("system", "system", text, "/system"));
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
if (Array.isArray(body.messages)) {
|
|
2204
|
+
body.messages.forEach((message, index2) => {
|
|
2205
|
+
if (message === null || typeof message !== "object") return;
|
|
2206
|
+
const m = message;
|
|
2207
|
+
const role = m.role === "user" || m.role === "assistant" ? m.role : "user";
|
|
2208
|
+
const text = contentToText$1(m.content);
|
|
2209
|
+
segments.push(segment$1(role, `[${index2}] ${role}`, text, `/messages/${index2}`));
|
|
2210
|
+
});
|
|
2211
|
+
}
|
|
2212
|
+
if (Array.isArray(body.tools) && body.tools.length > 0) {
|
|
2213
|
+
const text = toolsToText$1(body.tools);
|
|
2214
|
+
segments.push(segment$1("tools", "tools", text, "/tools"));
|
|
2215
|
+
}
|
|
2216
|
+
return segments.length > 0 ? segments : null;
|
|
2669
2217
|
}
|
|
2670
2218
|
};
|
|
2219
|
+
function contentToText(content) {
|
|
2220
|
+
if (typeof content === "string") return content;
|
|
2221
|
+
if (!Array.isArray(content)) return "";
|
|
2222
|
+
const parts = [];
|
|
2223
|
+
for (const block of content) {
|
|
2224
|
+
if (block === null || typeof block !== "object") continue;
|
|
2225
|
+
const b = block;
|
|
2226
|
+
const type = b.type;
|
|
2227
|
+
if (type === "text" && typeof b.text === "string") {
|
|
2228
|
+
parts.push(b.text);
|
|
2229
|
+
} else if (type === "image_url") {
|
|
2230
|
+
parts.push("[image]");
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
return parts.join("\n");
|
|
2234
|
+
}
|
|
2235
|
+
function messageToText(message) {
|
|
2236
|
+
const parts = [];
|
|
2237
|
+
const text = contentToText(message.content);
|
|
2238
|
+
if (text.length > 0) parts.push(text);
|
|
2239
|
+
const reasoning = typeof message.reasoning_content === "string" ? message.reasoning_content : typeof message.thinking === "string" ? message.thinking : typeof message.think === "string" ? message.think : "";
|
|
2240
|
+
if (reasoning.length > 0) parts.push(reasoning);
|
|
2241
|
+
const toolCalls = message.tool_calls;
|
|
2242
|
+
if (Array.isArray(toolCalls)) {
|
|
2243
|
+
for (const call of toolCalls) {
|
|
2244
|
+
if (call === null || typeof call !== "object") continue;
|
|
2245
|
+
const fn = call.function;
|
|
2246
|
+
if (fn === void 0) continue;
|
|
2247
|
+
const name = typeof fn.name === "string" ? fn.name : "";
|
|
2248
|
+
const args = typeof fn.arguments === "string" ? fn.arguments : "";
|
|
2249
|
+
parts.push(`${name} ${args}`.trim());
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
return parts.join("\n");
|
|
2253
|
+
}
|
|
2254
|
+
function toolsToText(tools) {
|
|
2255
|
+
if (!Array.isArray(tools)) return "";
|
|
2256
|
+
const parts = [];
|
|
2257
|
+
for (const tool of tools) {
|
|
2258
|
+
if (tool === null || typeof tool !== "object") continue;
|
|
2259
|
+
const t = tool;
|
|
2260
|
+
const fn = t.function;
|
|
2261
|
+
if (fn === void 0) continue;
|
|
2262
|
+
if (typeof fn.name === "string") parts.push(fn.name);
|
|
2263
|
+
if (typeof fn.description === "string") parts.push(fn.description);
|
|
2264
|
+
if (fn.parameters !== void 0) parts.push(JSON.stringify(fn.parameters));
|
|
2265
|
+
}
|
|
2266
|
+
return parts.join("\n");
|
|
2267
|
+
}
|
|
2268
|
+
function segment(role, label, text, path) {
|
|
2269
|
+
return {
|
|
2270
|
+
role,
|
|
2271
|
+
label,
|
|
2272
|
+
text,
|
|
2273
|
+
size: estimateTokens(text),
|
|
2274
|
+
characters: countCharacters(text),
|
|
2275
|
+
path
|
|
2276
|
+
};
|
|
2277
|
+
}
|
|
2671
2278
|
const openAILogFormatAdapter = {
|
|
2672
2279
|
format: "openai",
|
|
2673
2280
|
analyzeRequest(rawBody) {
|
|
@@ -2694,6 +2301,25 @@ const openAILogFormatAdapter = {
|
|
|
2694
2301
|
parsed,
|
|
2695
2302
|
toolNames: toolNames.length > 0 ? toolNames : null
|
|
2696
2303
|
};
|
|
2304
|
+
},
|
|
2305
|
+
anatomySegments(parsed) {
|
|
2306
|
+
if (parsed === null || typeof parsed !== "object") return null;
|
|
2307
|
+
const body = parsed;
|
|
2308
|
+
const segments = [];
|
|
2309
|
+
if (Array.isArray(body.messages)) {
|
|
2310
|
+
body.messages.forEach((message, index2) => {
|
|
2311
|
+
if (message === null || typeof message !== "object") return;
|
|
2312
|
+
const m = message;
|
|
2313
|
+
const role = m.role === "user" || m.role === "assistant" || m.role === "system" || m.role === "tool" ? m.role : "user";
|
|
2314
|
+
const text = messageToText(m);
|
|
2315
|
+
segments.push(segment(role, `[${index2}] ${role}`, text, `/messages/${index2}`));
|
|
2316
|
+
});
|
|
2317
|
+
}
|
|
2318
|
+
if (Array.isArray(body.tools) && body.tools.length > 0) {
|
|
2319
|
+
const text = toolsToText(body.tools);
|
|
2320
|
+
segments.push(segment("tools", "tools", text, "/tools"));
|
|
2321
|
+
}
|
|
2322
|
+
return segments.length > 0 ? segments : null;
|
|
2697
2323
|
}
|
|
2698
2324
|
};
|
|
2699
2325
|
const unknownLogFormatAdapter = {
|
|
@@ -2703,6 +2329,9 @@ const unknownLogFormatAdapter = {
|
|
|
2703
2329
|
},
|
|
2704
2330
|
analyzeResponse() {
|
|
2705
2331
|
return EMPTY_RESPONSE_ANALYSIS;
|
|
2332
|
+
},
|
|
2333
|
+
anatomySegments() {
|
|
2334
|
+
return null;
|
|
2706
2335
|
}
|
|
2707
2336
|
};
|
|
2708
2337
|
const ADAPTERS = {
|
|
@@ -2717,465 +2346,83 @@ function resolveLogFormat(log) {
|
|
|
2717
2346
|
const pathFormat = requestFormatForPath(log.path);
|
|
2718
2347
|
return pathFormat === "unknown" ? log.apiFormat : pathFormat;
|
|
2719
2348
|
}
|
|
2720
|
-
function
|
|
2721
|
-
|
|
2722
|
-
case "success":
|
|
2723
|
-
return "text-emerald-400";
|
|
2724
|
-
case "client_error":
|
|
2725
|
-
return "text-amber-400";
|
|
2726
|
-
case "server_error":
|
|
2727
|
-
return "text-red-400";
|
|
2728
|
-
case "pending":
|
|
2729
|
-
return "text-muted-foreground";
|
|
2730
|
-
}
|
|
2349
|
+
function shouldShowRawRequestTab(apiFormat, viewMode, strip) {
|
|
2350
|
+
return apiFormat === "anthropic" && viewMode === "full" && strip;
|
|
2731
2351
|
}
|
|
2732
|
-
function
|
|
2733
|
-
|
|
2734
|
-
const classes = getStatusClasses(category);
|
|
2735
|
-
if (status === null) {
|
|
2736
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-muted-foreground italic", children: "pending" });
|
|
2737
|
-
}
|
|
2738
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn("flex items-center gap-1 text-xs font-mono font-semibold", classes), children: [
|
|
2739
|
-
category === "server_error" && /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3" }),
|
|
2740
|
-
status
|
|
2741
|
-
] });
|
|
2352
|
+
function shouldShowHeadersDiffButton(viewMode, hasRawHeaders) {
|
|
2353
|
+
return viewMode === "full" && hasRawHeaders;
|
|
2742
2354
|
}
|
|
2743
|
-
function
|
|
2744
|
-
return
|
|
2355
|
+
function shouldShowRequestDiffButton(apiFormat, viewMode, strip, hasRawRequest) {
|
|
2356
|
+
return apiFormat === "anthropic" && viewMode === "full" && strip && hasRawRequest;
|
|
2745
2357
|
}
|
|
2746
|
-
function
|
|
2747
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "
|
|
2358
|
+
function TabFallback() {
|
|
2359
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-1", "aria-hidden": "true" });
|
|
2748
2360
|
}
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
outputTokens,
|
|
2755
|
-
cacheCreationInputTokens,
|
|
2756
|
-
cacheReadInputTokens,
|
|
2757
|
-
apiFormat,
|
|
2758
|
-
error
|
|
2361
|
+
function CopyButton({
|
|
2362
|
+
text,
|
|
2363
|
+
label,
|
|
2364
|
+
copied,
|
|
2365
|
+
onCopy
|
|
2759
2366
|
}) {
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
(
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2800
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusIndicator, { status: responseStatus }),
|
|
2801
|
-
streaming && (inputTokens !== null || outputTokens !== null) && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs", children: [
|
|
2802
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3" }),
|
|
2803
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
2804
|
-
inputTokens !== null ? formatTokens(inputTokens) : "—",
|
|
2805
|
-
" in /",
|
|
2806
|
-
" ",
|
|
2807
|
-
outputTokens !== null ? formatTokens(outputTokens) : "—",
|
|
2808
|
-
" out"
|
|
2809
|
-
] }),
|
|
2810
|
-
cacheCreationInputTokens !== null && cacheCreationInputTokens !== void 0 && cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-emerald-400", children: [
|
|
2811
|
-
"Cache +",
|
|
2812
|
-
formatTokens(cacheCreationInputTokens)
|
|
2813
|
-
] }),
|
|
2814
|
-
cacheReadInputTokens !== null && cacheReadInputTokens !== void 0 && cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
|
|
2815
|
-
"Cache ~",
|
|
2816
|
-
formatTokens(cacheReadInputTokens)
|
|
2817
|
-
] })
|
|
2818
|
-
] })
|
|
2819
|
-
] }),
|
|
2820
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(MarkdownFallbackView, { text: responseText ?? "" })
|
|
2367
|
+
if (text === null) return null;
|
|
2368
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2369
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2370
|
+
Button,
|
|
2371
|
+
{
|
|
2372
|
+
variant: "outline",
|
|
2373
|
+
size: "sm",
|
|
2374
|
+
className: "h-8 text-xs",
|
|
2375
|
+
onClick: onCopy,
|
|
2376
|
+
"aria-label": label,
|
|
2377
|
+
children: [
|
|
2378
|
+
copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 mr-1 text-emerald-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5 mr-1" }),
|
|
2379
|
+
copied ? "Copied!" : label
|
|
2380
|
+
]
|
|
2381
|
+
}
|
|
2382
|
+
) }),
|
|
2383
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: copied ? "Copied to clipboard" : label })
|
|
2384
|
+
] });
|
|
2385
|
+
}
|
|
2386
|
+
function DiffToggleButton({
|
|
2387
|
+
active,
|
|
2388
|
+
onClick
|
|
2389
|
+
}) {
|
|
2390
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2391
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2392
|
+
Button,
|
|
2393
|
+
{
|
|
2394
|
+
variant: active ? "default" : "outline",
|
|
2395
|
+
size: "sm",
|
|
2396
|
+
className: "h-8 text-xs",
|
|
2397
|
+
onClick,
|
|
2398
|
+
"aria-pressed": active,
|
|
2399
|
+
children: [
|
|
2400
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(GitCompareArrows, { className: "size-3.5 mr-1" }),
|
|
2401
|
+
active ? "Showing diff" : "Diff with Raw"
|
|
2402
|
+
]
|
|
2403
|
+
}
|
|
2404
|
+
) }),
|
|
2405
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: active ? "Hide diff view" : "Compare proxy output against the original raw version" })
|
|
2821
2406
|
] });
|
|
2407
|
+
}
|
|
2408
|
+
const RequestDiffContent = reactExports.memo(function({
|
|
2409
|
+
rawBody,
|
|
2410
|
+
displayedBody,
|
|
2411
|
+
emptyLabel
|
|
2412
|
+
}) {
|
|
2413
|
+
const result = reactExports.useMemo(
|
|
2414
|
+
() => computeRequestDiff(rawBody, displayedBody),
|
|
2415
|
+
[rawBody, displayedBody]
|
|
2416
|
+
);
|
|
2417
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(DiffView, { result, emptyLabel });
|
|
2822
2418
|
});
|
|
2823
|
-
const
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
elapsedMs: number().optional(),
|
|
2831
|
-
streaming: boolean().optional()
|
|
2832
|
-
});
|
|
2833
|
-
function ReplayDialog({ log, open, onOpenChange }) {
|
|
2834
|
-
const [modifiedBody, setModifiedBody] = reactExports.useState(() => {
|
|
2835
|
-
return log.rawRequestBody ?? "{}";
|
|
2836
|
-
});
|
|
2837
|
-
const [replayResult, setReplayResult] = reactExports.useState(null);
|
|
2838
|
-
const [loading, setLoading] = reactExports.useState(false);
|
|
2839
|
-
const [error, setError] = reactExports.useState(null);
|
|
2840
|
-
async function handleReplay() {
|
|
2841
|
-
setLoading(true);
|
|
2842
|
-
setError(null);
|
|
2843
|
-
setReplayResult(null);
|
|
2844
|
-
try {
|
|
2845
|
-
const res = await fetch(`/api/logs/${log.id}/replay`, {
|
|
2846
|
-
method: "POST",
|
|
2847
|
-
headers: { "Content-Type": "application/json" },
|
|
2848
|
-
body: JSON.stringify({ modifiedBody })
|
|
2849
|
-
});
|
|
2850
|
-
const json = await res.json();
|
|
2851
|
-
const parsed = ReplayResultSchema.safeParse(json);
|
|
2852
|
-
if (!parsed.success) {
|
|
2853
|
-
setError("Invalid response from server");
|
|
2854
|
-
setLoading(false);
|
|
2855
|
-
return;
|
|
2856
|
-
}
|
|
2857
|
-
const data = parsed.data;
|
|
2858
|
-
setReplayResult(data);
|
|
2859
|
-
if (!data.success) {
|
|
2860
|
-
setError(data.error ?? "Replay failed");
|
|
2861
|
-
}
|
|
2862
|
-
} catch (err) {
|
|
2863
|
-
setError(err instanceof Error ? err.message : "Network error");
|
|
2864
|
-
} finally {
|
|
2865
|
-
setLoading(false);
|
|
2866
|
-
}
|
|
2867
|
-
}
|
|
2868
|
-
function handleClose() {
|
|
2869
|
-
setReplayResult(null);
|
|
2870
|
-
setError(null);
|
|
2871
|
-
onOpenChange(false);
|
|
2872
|
-
}
|
|
2873
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { className: "max-w-4xl max-h-[85vh] overflow-auto", children: [
|
|
2874
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
|
|
2875
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { className: "size-4" }),
|
|
2876
|
-
"Replay Request #",
|
|
2877
|
-
log.id
|
|
2878
|
-
] }) }),
|
|
2879
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { defaultValue: "modified", children: [
|
|
2880
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, { children: [
|
|
2881
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "modified", children: "Modified Request" }),
|
|
2882
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "original", children: "Original Response" }),
|
|
2883
|
-
replayResult && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "replay", children: "Replay Response" })
|
|
2884
|
-
] }),
|
|
2885
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(TabsContent, { value: "modified", className: "space-y-4", children: [
|
|
2886
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
2887
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-sm font-medium mb-2 block", children: "Request Body (JSON)" }),
|
|
2888
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2889
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2890
|
-
"textarea",
|
|
2891
|
-
{
|
|
2892
|
-
className: "w-full h-64 p-3 font-mono text-xs bg-muted rounded-md border border-input resize-none focus:outline-none focus:ring-2 focus:ring-ring",
|
|
2893
|
-
value: modifiedBody,
|
|
2894
|
-
onChange: (e) => setModifiedBody(e.target.value),
|
|
2895
|
-
spellCheck: false
|
|
2896
|
-
}
|
|
2897
|
-
) }),
|
|
2898
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Edit the request body before re-sending to the provider" })
|
|
2899
|
-
] }) })
|
|
2900
|
-
] }),
|
|
2901
|
-
error !== null && error !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-destructive bg-destructive/10 px-3 py-2 rounded-md", children: error }),
|
|
2902
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2903
|
-
Button,
|
|
2904
|
-
{
|
|
2905
|
-
onClick: () => {
|
|
2906
|
-
void handleReplay();
|
|
2907
|
-
},
|
|
2908
|
-
disabled: loading,
|
|
2909
|
-
children: loading ? "Replaying..." : "Replay"
|
|
2910
|
-
}
|
|
2911
|
-
) }),
|
|
2912
|
-
replayResult && replayResult.success && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { defaultValue: "parsed", children: [
|
|
2913
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, { children: [
|
|
2914
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" }),
|
|
2915
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw", children: "Raw Response" })
|
|
2916
|
-
] }),
|
|
2917
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2918
|
-
ResponseView,
|
|
2919
|
-
{
|
|
2920
|
-
responseText: replayResult.responseText ?? null,
|
|
2921
|
-
responseStatus: replayResult.responseStatus ?? null,
|
|
2922
|
-
streaming: replayResult.streaming ?? false,
|
|
2923
|
-
inputTokens: replayResult.inputTokens ?? null,
|
|
2924
|
-
outputTokens: replayResult.outputTokens ?? null,
|
|
2925
|
-
apiFormat: log.apiFormat
|
|
2926
|
-
}
|
|
2927
|
-
) }),
|
|
2928
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap bg-muted p-3 rounded-md max-h-96 overflow-auto", children: replayResult.responseText ?? "No response" }) })
|
|
2929
|
-
] })
|
|
2930
|
-
] }),
|
|
2931
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "original", children: log.responseText !== null ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { defaultValue: "parsed", children: [
|
|
2932
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, { children: [
|
|
2933
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" }),
|
|
2934
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw", children: "Raw Response" })
|
|
2935
|
-
] }),
|
|
2936
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2937
|
-
ResponseView,
|
|
2938
|
-
{
|
|
2939
|
-
responseText: log.responseText,
|
|
2940
|
-
responseStatus: log.responseStatus,
|
|
2941
|
-
streaming: log.streaming,
|
|
2942
|
-
inputTokens: log.inputTokens,
|
|
2943
|
-
outputTokens: log.outputTokens,
|
|
2944
|
-
cacheCreationInputTokens: log.cacheCreationInputTokens,
|
|
2945
|
-
cacheReadInputTokens: log.cacheReadInputTokens,
|
|
2946
|
-
apiFormat: log.apiFormat
|
|
2947
|
-
}
|
|
2948
|
-
) }),
|
|
2949
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap bg-muted p-3 rounded-md max-h-96 overflow-auto", children: log.responseText }) })
|
|
2950
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground italic", children: "No original response" }) }),
|
|
2951
|
-
replayResult && replayResult.success && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "replay", children: replayResult.responseText !== null ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { defaultValue: "parsed", children: [
|
|
2952
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, { children: [
|
|
2953
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" }),
|
|
2954
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw", children: "Raw Response" })
|
|
2955
|
-
] }),
|
|
2956
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2957
|
-
ResponseView,
|
|
2958
|
-
{
|
|
2959
|
-
responseText: replayResult.responseText ?? null,
|
|
2960
|
-
responseStatus: replayResult.responseStatus ?? null,
|
|
2961
|
-
streaming: replayResult.streaming ?? false,
|
|
2962
|
-
inputTokens: replayResult.inputTokens ?? null,
|
|
2963
|
-
outputTokens: replayResult.outputTokens ?? null,
|
|
2964
|
-
apiFormat: log.apiFormat
|
|
2965
|
-
}
|
|
2966
|
-
) }),
|
|
2967
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap bg-muted p-3 rounded-md max-h-96 overflow-auto", children: replayResult.responseText }) })
|
|
2968
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground italic", children: "No replay response" }) })
|
|
2969
|
-
] })
|
|
2970
|
-
] }) });
|
|
2971
|
-
}
|
|
2972
|
-
const StreamingChunkSequence = reactExports.memo(function StreamingChunkSequence2({
|
|
2973
|
-
logId,
|
|
2974
|
-
truncated
|
|
2975
|
-
}) {
|
|
2976
|
-
const [containerExpanded, setContainerExpanded] = reactExports.useState(false);
|
|
2977
|
-
const [chunkState, setChunkState] = reactExports.useState({ status: "idle" });
|
|
2978
|
-
const [expandedIndices, setExpandedIndices] = reactExports.useState(/* @__PURE__ */ new Set());
|
|
2979
|
-
reactExports.useEffect(() => {
|
|
2980
|
-
if (!containerExpanded || chunkState.status !== "idle") return;
|
|
2981
|
-
let cancelled = false;
|
|
2982
|
-
setChunkState({ status: "loading" });
|
|
2983
|
-
fetch(`/api/logs/${logId}/chunks`).then((res) => {
|
|
2984
|
-
if (!res.ok) {
|
|
2985
|
-
return Promise.reject(new Error("Chunks not found"));
|
|
2986
|
-
}
|
|
2987
|
-
return res.json();
|
|
2988
|
-
}).then((data) => {
|
|
2989
|
-
if (!cancelled) {
|
|
2990
|
-
setChunkState({ status: "success", chunks: data.chunks });
|
|
2991
|
-
}
|
|
2992
|
-
}).catch(() => {
|
|
2993
|
-
if (!cancelled) {
|
|
2994
|
-
setChunkState({ status: "error", message: "Chunk data unavailable" });
|
|
2995
|
-
}
|
|
2996
|
-
});
|
|
2997
|
-
return () => {
|
|
2998
|
-
cancelled = true;
|
|
2999
|
-
};
|
|
3000
|
-
}, [containerExpanded, logId]);
|
|
3001
|
-
const groups = reactExports.useMemo(() => {
|
|
3002
|
-
if (chunkState.status !== "success") return [];
|
|
3003
|
-
const map = /* @__PURE__ */ new Map();
|
|
3004
|
-
for (const chunk of chunkState.chunks) {
|
|
3005
|
-
const existing = map.get(chunk.index);
|
|
3006
|
-
if (existing) {
|
|
3007
|
-
existing.push(chunk);
|
|
3008
|
-
} else {
|
|
3009
|
-
map.set(chunk.index, [chunk]);
|
|
3010
|
-
}
|
|
3011
|
-
}
|
|
3012
|
-
return Array.from(map.entries()).map(([index, chunks]) => ({ index, chunks })).sort((a, b) => a.index - b.index);
|
|
3013
|
-
}, [chunkState]);
|
|
3014
|
-
const toggleIndex = (index) => {
|
|
3015
|
-
setExpandedIndices((prev) => {
|
|
3016
|
-
const next = new Set(prev);
|
|
3017
|
-
if (next.has(index)) {
|
|
3018
|
-
next.delete(index);
|
|
3019
|
-
} else {
|
|
3020
|
-
next.add(index);
|
|
3021
|
-
}
|
|
3022
|
-
return next;
|
|
3023
|
-
});
|
|
3024
|
-
};
|
|
3025
|
-
function renderBody() {
|
|
3026
|
-
if (chunkState.status === "idle" || chunkState.status === "loading") {
|
|
3027
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 py-2 text-xs text-muted-foreground", children: [
|
|
3028
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3 animate-spin" }),
|
|
3029
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Loading chunks..." })
|
|
3030
|
-
] });
|
|
3031
|
-
}
|
|
3032
|
-
if (chunkState.status === "error") {
|
|
3033
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "py-2 text-xs text-muted-foreground italic", children: chunkState.message });
|
|
3034
|
-
}
|
|
3035
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-2 space-y-1", children: [
|
|
3036
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] text-muted-foreground font-mono mb-2", children: [
|
|
3037
|
-
groups.length,
|
|
3038
|
-
" index group",
|
|
3039
|
-
groups.length !== 1 ? "s" : "",
|
|
3040
|
-
" available"
|
|
3041
|
-
] }),
|
|
3042
|
-
groups.map((group) => {
|
|
3043
|
-
const isExpanded = expandedIndices.has(group.index);
|
|
3044
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded border border-border bg-background", children: [
|
|
3045
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3046
|
-
"button",
|
|
3047
|
-
{
|
|
3048
|
-
type: "button",
|
|
3049
|
-
className: "flex items-center gap-2 w-full px-2 py-1.5 text-left hover:bg-muted/50 transition-colors cursor-pointer",
|
|
3050
|
-
onClick: () => toggleIndex(group.index),
|
|
3051
|
-
children: [
|
|
3052
|
-
isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3 text-muted-foreground" }),
|
|
3053
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-muted-foreground font-mono", children: [
|
|
3054
|
-
"[",
|
|
3055
|
-
group.index,
|
|
3056
|
-
"] ",
|
|
3057
|
-
group.chunks[0]?.type ?? ""
|
|
3058
|
-
] }),
|
|
3059
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-muted-foreground font-mono", children: [
|
|
3060
|
-
group.chunks.length,
|
|
3061
|
-
" chunk",
|
|
3062
|
-
group.chunks.length !== 1 ? "s" : ""
|
|
3063
|
-
] })
|
|
3064
|
-
]
|
|
3065
|
-
}
|
|
3066
|
-
),
|
|
3067
|
-
isExpanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2 pb-2 space-y-1", children: group.chunks.map((chunk) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded border border-border bg-muted/20 p-2", children: [
|
|
3068
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
3069
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-muted-foreground font-mono", children: [
|
|
3070
|
-
"+",
|
|
3071
|
-
chunk.timestamp,
|
|
3072
|
-
"ms"
|
|
3073
|
-
] }),
|
|
3074
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground font-mono", children: chunk.type })
|
|
3075
|
-
] }),
|
|
3076
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewer, { data: chunk, defaultExpandDepth: 0, showCopy: true })
|
|
3077
|
-
] }, chunk.index)) })
|
|
3078
|
-
] }, group.index);
|
|
3079
|
-
})
|
|
3080
|
-
] });
|
|
3081
|
-
}
|
|
3082
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
|
|
3083
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
3084
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3085
|
-
"button",
|
|
3086
|
-
{
|
|
3087
|
-
type: "button",
|
|
3088
|
-
className: "flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer",
|
|
3089
|
-
onClick: () => setContainerExpanded((v) => !v),
|
|
3090
|
-
children: [
|
|
3091
|
-
containerExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3" }),
|
|
3092
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Raw SSE Events" }),
|
|
3093
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(Badge, { variant: "outline", className: "text-[9px] px-1 py-0 h-4 font-mono ml-1", children: [
|
|
3094
|
-
logId,
|
|
3095
|
-
truncated === true ? "+" : ""
|
|
3096
|
-
] })
|
|
3097
|
-
]
|
|
3098
|
-
}
|
|
3099
|
-
) }),
|
|
3100
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Server-Sent Events streaming chunks from the provider" })
|
|
3101
|
-
] }) }),
|
|
3102
|
-
containerExpanded === true ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-border bg-muted/20 overflow-auto max-h-64", children: renderBody() }) : null
|
|
3103
|
-
] });
|
|
3104
|
-
});
|
|
3105
|
-
function shouldShowRawRequestTab(apiFormat, viewMode, strip) {
|
|
3106
|
-
return apiFormat === "anthropic" && viewMode === "full" && strip;
|
|
3107
|
-
}
|
|
3108
|
-
function shouldShowHeadersDiffButton(viewMode, hasRawHeaders) {
|
|
3109
|
-
return viewMode === "full" && hasRawHeaders;
|
|
3110
|
-
}
|
|
3111
|
-
function shouldShowRequestDiffButton(apiFormat, viewMode, strip, hasRawRequest) {
|
|
3112
|
-
return apiFormat === "anthropic" && viewMode === "full" && strip && hasRawRequest;
|
|
3113
|
-
}
|
|
3114
|
-
function CopyButton({
|
|
3115
|
-
text,
|
|
3116
|
-
label,
|
|
3117
|
-
copied,
|
|
3118
|
-
onCopy
|
|
3119
|
-
}) {
|
|
3120
|
-
if (text === null) return null;
|
|
3121
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3122
|
-
"button",
|
|
3123
|
-
{
|
|
3124
|
-
type: "button",
|
|
3125
|
-
onClick: onCopy,
|
|
3126
|
-
className: "flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors px-2 py-1 rounded hover:bg-muted",
|
|
3127
|
-
children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
3128
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3 text-green-500" }),
|
|
3129
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-green-500", children: "Copied!" })
|
|
3130
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
3131
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3" }),
|
|
3132
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: label })
|
|
3133
|
-
] })
|
|
3134
|
-
}
|
|
3135
|
-
);
|
|
3136
|
-
}
|
|
3137
|
-
function DiffToggleButton({
|
|
3138
|
-
active,
|
|
3139
|
-
onClick
|
|
3140
|
-
}) {
|
|
3141
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
3142
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3143
|
-
"button",
|
|
3144
|
-
{
|
|
3145
|
-
type: "button",
|
|
3146
|
-
onClick,
|
|
3147
|
-
"aria-pressed": active,
|
|
3148
|
-
className: cn(
|
|
3149
|
-
"flex items-center gap-1.5 text-xs px-2 py-1 rounded transition-colors",
|
|
3150
|
-
active ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground hover:bg-muted"
|
|
3151
|
-
),
|
|
3152
|
-
children: [
|
|
3153
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(GitCompareArrows, { className: "size-3" }),
|
|
3154
|
-
active ? "Showing diff" : "Diff with Raw"
|
|
3155
|
-
]
|
|
3156
|
-
}
|
|
3157
|
-
) }),
|
|
3158
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: active ? "Hide diff view" : "Compare proxy output against the original raw version" })
|
|
3159
|
-
] });
|
|
3160
|
-
}
|
|
3161
|
-
const RequestDiffContent = reactExports.memo(function({
|
|
3162
|
-
rawBody,
|
|
3163
|
-
displayedBody,
|
|
3164
|
-
emptyLabel
|
|
3165
|
-
}) {
|
|
3166
|
-
const result = reactExports.useMemo(
|
|
3167
|
-
() => computeRequestDiff(rawBody, displayedBody),
|
|
3168
|
-
[rawBody, displayedBody]
|
|
3169
|
-
);
|
|
3170
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(DiffView, { result, emptyLabel });
|
|
3171
|
-
});
|
|
3172
|
-
const HeadersDiffContent = reactExports.memo(function({
|
|
3173
|
-
rawHeaders,
|
|
3174
|
-
headers,
|
|
3175
|
-
emptyLabel
|
|
3176
|
-
}) {
|
|
3177
|
-
const result = reactExports.useMemo(() => computeHeadersDiff(rawHeaders, headers), [rawHeaders, headers]);
|
|
3178
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(DiffView, { result, emptyLabel });
|
|
2419
|
+
const HeadersDiffContent = reactExports.memo(function({
|
|
2420
|
+
rawHeaders,
|
|
2421
|
+
headers,
|
|
2422
|
+
emptyLabel
|
|
2423
|
+
}) {
|
|
2424
|
+
const result = reactExports.useMemo(() => computeHeadersDiff(rawHeaders, headers), [rawHeaders, headers]);
|
|
2425
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(DiffView, { result, emptyLabel });
|
|
3179
2426
|
});
|
|
3180
2427
|
function useCopyFeedback(text) {
|
|
3181
2428
|
const [copied, setCopied] = reactExports.useState(false);
|
|
@@ -3212,6 +2459,8 @@ const LogEntry = reactExports.memo(function({
|
|
|
3212
2459
|
const [headersDiff, setHeadersDiff] = reactExports.useState(false);
|
|
3213
2460
|
const [requestDiff, setRequestDiff] = reactExports.useState(false);
|
|
3214
2461
|
const [activeTab, setActiveTab] = reactExports.useState("request");
|
|
2462
|
+
const [expandToPath, setExpandToPath] = reactExports.useState(null);
|
|
2463
|
+
const requestJsonRef = reactExports.useRef(null);
|
|
3215
2464
|
const resolvedFormat = resolveLogFormat(log);
|
|
3216
2465
|
const adapter = getLogFormatAdapter(resolvedFormat);
|
|
3217
2466
|
const requestAnalysis = reactExports.useMemo(
|
|
@@ -3234,6 +2483,21 @@ const LogEntry = reactExports.memo(function({
|
|
|
3234
2483
|
const responseCopy = useCopyFeedback(log.responseText);
|
|
3235
2484
|
const requestExpansion = useJsonBulkExpansion(displayedRequestBody);
|
|
3236
2485
|
const rawRequestExpansion = useJsonBulkExpansion(log.rawRequestBody);
|
|
2486
|
+
const anatomySegments = reactExports.useMemo(
|
|
2487
|
+
() => requestExpansion.parsedData !== null ? adapter.anatomySegments(requestExpansion.parsedData) : null,
|
|
2488
|
+
[adapter, requestExpansion.parsedData]
|
|
2489
|
+
);
|
|
2490
|
+
const anatomyPaths = reactExports.useMemo(() => {
|
|
2491
|
+
if (anatomySegments === null) return void 0;
|
|
2492
|
+
return new Set(anatomySegments.map((s) => s.path));
|
|
2493
|
+
}, [anatomySegments]);
|
|
2494
|
+
const jumpToAnatomySegment = useAnatomyJump({
|
|
2495
|
+
containerRef: requestJsonRef,
|
|
2496
|
+
setExpandToPath,
|
|
2497
|
+
ensureTabActive: () => {
|
|
2498
|
+
if (activeTab !== "request") setActiveTab("request");
|
|
2499
|
+
}
|
|
2500
|
+
});
|
|
3237
2501
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(TooltipProvider, { children: [
|
|
3238
2502
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-border rounded-lg mb-1 overflow-hidden", children: [
|
|
3239
2503
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -3245,7 +2509,19 @@ const LogEntry = reactExports.memo(function({
|
|
|
3245
2509
|
expanded,
|
|
3246
2510
|
onToggle: () => setExpanded(!expanded),
|
|
3247
2511
|
responseToolNames: responseAnalysis.toolNames,
|
|
3248
|
-
cacheTrend
|
|
2512
|
+
cacheTrend,
|
|
2513
|
+
onReplay: onCompareWithPrevious === void 0 ? void 0 : () => {
|
|
2514
|
+
setReplayOpen(true);
|
|
2515
|
+
},
|
|
2516
|
+
onCopyRequest: displayedRequestBody === null ? void 0 : (e) => {
|
|
2517
|
+
requestCopy.copy(e);
|
|
2518
|
+
},
|
|
2519
|
+
requestCopied: requestCopy.copied,
|
|
2520
|
+
onToggleRequestExpansion: requestExpansion.toggle,
|
|
2521
|
+
requestExpansionState: requestExpansion.policy === null ? null : {
|
|
2522
|
+
isExpanded: requestExpansion.isExpanded,
|
|
2523
|
+
isPending: requestExpansion.isPending
|
|
2524
|
+
}
|
|
3249
2525
|
}
|
|
3250
2526
|
),
|
|
3251
2527
|
expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { value: activeTab, onValueChange: setActiveTab, children: [
|
|
@@ -3254,10 +2530,11 @@ const LogEntry = reactExports.memo(function({
|
|
|
3254
2530
|
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "headers", children: "Headers" }),
|
|
3255
2531
|
shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw-request", children: "Raw Request" }),
|
|
3256
2532
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "request", children: "Request" }),
|
|
2533
|
+
anatomySegments !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "anatomy", children: "Anatomy" }),
|
|
3257
2534
|
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw", children: "Raw Response" }),
|
|
3258
2535
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" })
|
|
3259
2536
|
] }),
|
|
3260
|
-
shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: activeTab === "raw-request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4
|
|
2537
|
+
shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: activeTab === "raw-request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pt-1 pb-3", children: [
|
|
3261
2538
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 mb-2", children: [
|
|
3262
2539
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3263
2540
|
JsonExpansionButton,
|
|
@@ -3278,17 +2555,22 @@ const LogEntry = reactExports.memo(function({
|
|
|
3278
2555
|
}
|
|
3279
2556
|
)
|
|
3280
2557
|
] }),
|
|
3281
|
-
log.rawRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : rawRequestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3282
|
-
|
|
2558
|
+
log.rawRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : rawRequestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2559
|
+
LazyJsonViewer,
|
|
3283
2560
|
{
|
|
3284
2561
|
data: rawRequestExpansion.parsedData,
|
|
3285
2562
|
bulkDepth: rawRequestExpansion.bulkDepth,
|
|
3286
2563
|
bulkRevision: rawRequestExpansion.bulkRevision
|
|
3287
2564
|
}
|
|
3288
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words", children: log.rawRequestBody })
|
|
2565
|
+
) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words", children: log.rawRequestBody })
|
|
3289
2566
|
] }) }),
|
|
3290
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: activeTab === "request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4
|
|
3291
|
-
|
|
2567
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: activeTab === "request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pt-1 pb-3", children: [
|
|
2568
|
+
(shouldShowRequestDiffButton(
|
|
2569
|
+
resolvedFormat,
|
|
2570
|
+
viewMode,
|
|
2571
|
+
strip,
|
|
2572
|
+
log.rawRequestBody !== null
|
|
2573
|
+
) || onCompareWithPrevious !== void 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 mb-2", children: [
|
|
3292
2574
|
shouldShowRequestDiffButton(
|
|
3293
2575
|
resolvedFormat,
|
|
3294
2576
|
viewMode,
|
|
@@ -3310,7 +2592,7 @@ const LogEntry = reactExports.memo(function({
|
|
|
3310
2592
|
{
|
|
3311
2593
|
variant: "outline",
|
|
3312
2594
|
size: "sm",
|
|
3313
|
-
className: "h-
|
|
2595
|
+
className: "h-8 text-xs",
|
|
3314
2596
|
onClick: (e) => {
|
|
3315
2597
|
e.stopPropagation();
|
|
3316
2598
|
onCompareWithPrevious(log);
|
|
@@ -3322,44 +2604,7 @@ const LogEntry = reactExports.memo(function({
|
|
|
3322
2604
|
}
|
|
3323
2605
|
) }),
|
|
3324
2606
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Compare this request with the immediately preceding one" })
|
|
3325
|
-
] })
|
|
3326
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
3327
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3328
|
-
Button,
|
|
3329
|
-
{
|
|
3330
|
-
variant: "outline",
|
|
3331
|
-
size: "sm",
|
|
3332
|
-
className: "h-7 text-xs",
|
|
3333
|
-
onClick: (e) => {
|
|
3334
|
-
e.stopPropagation();
|
|
3335
|
-
setReplayOpen(true);
|
|
3336
|
-
},
|
|
3337
|
-
children: [
|
|
3338
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { className: "size-3 mr-1" }),
|
|
3339
|
-
"Replay"
|
|
3340
|
-
]
|
|
3341
|
-
}
|
|
3342
|
-
) }),
|
|
3343
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Re-send this request to the provider" })
|
|
3344
|
-
] }),
|
|
3345
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3346
|
-
JsonExpansionButton,
|
|
3347
|
-
{
|
|
3348
|
-
policy: requestExpansion.policy,
|
|
3349
|
-
isExpanded: requestExpansion.isExpanded,
|
|
3350
|
-
isPending: requestExpansion.isPending,
|
|
3351
|
-
onToggle: requestExpansion.toggle
|
|
3352
|
-
}
|
|
3353
|
-
),
|
|
3354
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3355
|
-
CopyButton,
|
|
3356
|
-
{
|
|
3357
|
-
text: displayedRequestBody,
|
|
3358
|
-
label: "Copy",
|
|
3359
|
-
copied: requestCopy.copied,
|
|
3360
|
-
onCopy: requestCopy.copy
|
|
3361
|
-
}
|
|
3362
|
-
)
|
|
2607
|
+
] })
|
|
3363
2608
|
] }),
|
|
3364
2609
|
requestDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3365
2610
|
RequestDiffContent,
|
|
@@ -3368,16 +2613,27 @@ const LogEntry = reactExports.memo(function({
|
|
|
3368
2613
|
displayedBody: displayedRequestBody,
|
|
3369
2614
|
emptyLabel: "No transformation applied — raw and sent request bodies are identical."
|
|
3370
2615
|
}
|
|
3371
|
-
) : displayedRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : requestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3372
|
-
|
|
2616
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: requestJsonRef, children: displayedRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : requestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2617
|
+
LazyJsonViewer,
|
|
3373
2618
|
{
|
|
3374
2619
|
data: requestExpansion.parsedData,
|
|
3375
2620
|
bulkDepth: requestExpansion.bulkDepth,
|
|
3376
|
-
bulkRevision: requestExpansion.bulkRevision
|
|
2621
|
+
bulkRevision: requestExpansion.bulkRevision,
|
|
2622
|
+
anatomyPaths,
|
|
2623
|
+
expandToPath
|
|
3377
2624
|
}
|
|
3378
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words", children: displayedRequestBody })
|
|
2625
|
+
) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words", children: displayedRequestBody }) })
|
|
3379
2626
|
] }) }),
|
|
3380
|
-
|
|
2627
|
+
anatomySegments !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "anatomy", children: activeTab === "anatomy" && /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2628
|
+
LazyRequestAnatomy,
|
|
2629
|
+
{
|
|
2630
|
+
parsed: null,
|
|
2631
|
+
inputTokens: log.inputTokens ?? null,
|
|
2632
|
+
segments: anatomySegments,
|
|
2633
|
+
onSegmentActivate: jumpToAnatomySegment
|
|
2634
|
+
}
|
|
2635
|
+
) }) }),
|
|
2636
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "headers", children: activeTab === "headers" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pt-1 pb-3", children: [
|
|
3381
2637
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end gap-2 mb-2", children: shouldShowHeadersDiffButton(
|
|
3382
2638
|
viewMode,
|
|
3383
2639
|
log.rawHeaders !== void 0 && Object.keys(log.rawHeaders).length > 0
|
|
@@ -3406,14 +2662,14 @@ const LogEntry = reactExports.memo(function({
|
|
|
3406
2662
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
|
|
3407
2663
|
] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No headers captured" })
|
|
3408
2664
|
] }) }),
|
|
3409
|
-
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-headers", children: activeTab === "raw-headers" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4
|
|
2665
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-headers", children: activeTab === "raw-headers" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 pt-1 pb-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: [
|
|
3410
2666
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-600 dark:text-blue-400 font-semibold shrink-0", children: [
|
|
3411
2667
|
key,
|
|
3412
2668
|
":"
|
|
3413
2669
|
] }),
|
|
3414
2670
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
|
|
3415
2671
|
] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No raw headers captured" }) }) }),
|
|
3416
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: activeTab === "raw" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4
|
|
2672
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: activeTab === "raw" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pt-1 pb-3 space-y-3", children: [
|
|
3417
2673
|
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: [
|
|
3418
2674
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold text-destructive mb-1", children: "SSE Error" }),
|
|
3419
2675
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground font-mono", children: log.error })
|
|
@@ -3427,17 +2683,17 @@ const LogEntry = reactExports.memo(function({
|
|
|
3427
2683
|
onCopy: responseCopy.copy
|
|
3428
2684
|
}
|
|
3429
2685
|
) }),
|
|
3430
|
-
log.responseText !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3431
|
-
log.streaming === true && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3432
|
-
|
|
2686
|
+
log.responseText !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(LazyJsonViewerFromString, { text: log.responseText, defaultExpandDepth: 0 }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No response" }),
|
|
2687
|
+
log.streaming === true && /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2688
|
+
LazyStreamingChunkSequence,
|
|
3433
2689
|
{
|
|
3434
2690
|
logId: log.id,
|
|
3435
2691
|
truncated: log.streamingChunksPath !== null
|
|
3436
2692
|
}
|
|
3437
|
-
)
|
|
2693
|
+
) })
|
|
3438
2694
|
] }) }),
|
|
3439
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: activeTab === "parsed" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4
|
|
3440
|
-
|
|
2695
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: activeTab === "parsed" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 pt-1 pb-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2696
|
+
LazyResponseView,
|
|
3441
2697
|
{
|
|
3442
2698
|
responseText: log.responseText,
|
|
3443
2699
|
responseStatus: log.responseStatus,
|
|
@@ -3449,10 +2705,10 @@ const LogEntry = reactExports.memo(function({
|
|
|
3449
2705
|
apiFormat: resolvedFormat,
|
|
3450
2706
|
error: log.error
|
|
3451
2707
|
}
|
|
3452
|
-
) }) })
|
|
2708
|
+
) }) }) })
|
|
3453
2709
|
] }) })
|
|
3454
2710
|
] }),
|
|
3455
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2711
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntimeExports.jsx(LazyReplayDialog, { log, open: replayOpen, onOpenChange: setReplayOpen }) })
|
|
3456
2712
|
] });
|
|
3457
2713
|
});
|
|
3458
2714
|
function ThreadConnector({
|
|
@@ -3460,13 +2716,16 @@ function ThreadConnector({
|
|
|
3460
2716
|
isPending,
|
|
3461
2717
|
isFirst,
|
|
3462
2718
|
isTurnStart,
|
|
2719
|
+
isOnlyEntry = false,
|
|
3463
2720
|
crabIndex = 0,
|
|
3464
2721
|
collapsible = false,
|
|
3465
2722
|
onToggle
|
|
3466
2723
|
}) {
|
|
3467
2724
|
const isBoundary = stopReason === "end_turn" || stopReason === "stop";
|
|
2725
|
+
const isFusedBoundary = isOnlyEntry && isTurnStart && isBoundary;
|
|
3468
2726
|
const isRunning = isPending && !isBoundary;
|
|
3469
2727
|
const Crab = reactExports.useMemo(() => getCrabVariant(crabIndex), [crabIndex]);
|
|
2728
|
+
const FusedCrab = reactExports.useMemo(() => getInteriorCrabVariant(crabIndex), [crabIndex]);
|
|
3470
2729
|
const interactiveProps = collapsible && onToggle ? {
|
|
3471
2730
|
role: "button",
|
|
3472
2731
|
tabIndex: 0,
|
|
@@ -3484,7 +2743,16 @@ function ThreadConnector({
|
|
|
3484
2743
|
} : {};
|
|
3485
2744
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center w-6 shrink-0 pt-0.5 pb-0.5", children: [
|
|
3486
2745
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center h-[calc(0.75rem-8px)]", children: !isFirst && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-0.5 bg-muted-foreground/30 h-full" }) }),
|
|
3487
|
-
|
|
2746
|
+
isFusedBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { title: "Start and end of turn", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2747
|
+
FusedCrab,
|
|
2748
|
+
{
|
|
2749
|
+
className: cn(
|
|
2750
|
+
"size-3.5 text-[#80FF00]",
|
|
2751
|
+
"animate-crab-settle",
|
|
2752
|
+
"drop-shadow-[0_0_4px_rgba(128,255,0,0.5)]"
|
|
2753
|
+
)
|
|
2754
|
+
}
|
|
2755
|
+
) }) : isBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3488
2756
|
"span",
|
|
3489
2757
|
{
|
|
3490
2758
|
title: stopReason === "end_turn" ? "End of Turn (Anthropic)" : "End of Turn (OpenAI)",
|
|
@@ -3521,6 +2789,43 @@ function ThreadConnector({
|
|
|
3521
2789
|
) })
|
|
3522
2790
|
] });
|
|
3523
2791
|
}
|
|
2792
|
+
function shouldRenderConversationContent(standalone, expanded) {
|
|
2793
|
+
return standalone || expanded;
|
|
2794
|
+
}
|
|
2795
|
+
function isTurnCollapsible(entryCount, isComplete, isPending) {
|
|
2796
|
+
return entryCount > 1 && isComplete && !isPending;
|
|
2797
|
+
}
|
|
2798
|
+
function buildTurnGroups(logs) {
|
|
2799
|
+
const groups = [];
|
|
2800
|
+
let entries = [];
|
|
2801
|
+
let turnIndex = 0;
|
|
2802
|
+
for (const log of logs) {
|
|
2803
|
+
entries.push({ log, stopReason: extractStopReason(log) });
|
|
2804
|
+
const current = entries[entries.length - 1];
|
|
2805
|
+
if (current !== void 0 && isTurnBoundary(current.stopReason)) {
|
|
2806
|
+
groups.push({ entries, turnIndex });
|
|
2807
|
+
entries = [];
|
|
2808
|
+
turnIndex += 1;
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
if (entries.length > 0) groups.push({ entries, turnIndex });
|
|
2812
|
+
return groups;
|
|
2813
|
+
}
|
|
2814
|
+
function buildValidPredecessors(groups) {
|
|
2815
|
+
const predecessors = /* @__PURE__ */ new Map();
|
|
2816
|
+
for (const group of groups) {
|
|
2817
|
+
for (let index2 = 1; index2 < group.logs.length; index2 += 1) {
|
|
2818
|
+
const current = group.logs[index2];
|
|
2819
|
+
const previous = group.logs[index2 - 1];
|
|
2820
|
+
if (current === void 0 || previous === void 0) continue;
|
|
2821
|
+
const currentFormat = resolveLogFormat(current);
|
|
2822
|
+
const previousFormat = resolveLogFormat(previous);
|
|
2823
|
+
if (currentFormat === "unknown" || currentFormat !== previousFormat) continue;
|
|
2824
|
+
predecessors.set(current.id, previous);
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
return predecessors;
|
|
2828
|
+
}
|
|
3524
2829
|
function formatElapsed(ms) {
|
|
3525
2830
|
if (ms < 1e3) return `${ms}ms`;
|
|
3526
2831
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
@@ -3538,15 +2843,18 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
3538
2843
|
const lastStop = entries[lastIdx]?.stopReason ?? null;
|
|
3539
2844
|
const isComplete = lastStop !== null ? isTurnBoundary(lastStop) : false;
|
|
3540
2845
|
const isPending = entries[lastIdx]?.log.responseStatus === null;
|
|
3541
|
-
const
|
|
2846
|
+
const isSingleLog = entries.length === 1;
|
|
2847
|
+
const collapsible = isTurnCollapsible(entries.length, isComplete, isPending);
|
|
3542
2848
|
const [collapsed, setCollapsed] = reactExports.useState(false);
|
|
3543
|
-
const prevCompleteRef = reactExports.useRef(
|
|
2849
|
+
const prevCompleteRef = reactExports.useRef(false);
|
|
3544
2850
|
reactExports.useEffect(() => {
|
|
3545
|
-
if (
|
|
2851
|
+
if (!collapsible) {
|
|
2852
|
+
setCollapsed(false);
|
|
2853
|
+
} else if (isComplete && !prevCompleteRef.current) {
|
|
3546
2854
|
setCollapsed(true);
|
|
3547
2855
|
}
|
|
3548
2856
|
prevCompleteRef.current = isComplete;
|
|
3549
|
-
}, [isComplete]);
|
|
2857
|
+
}, [collapsible, isComplete]);
|
|
3550
2858
|
const toggleCollapse = reactExports.useCallback(() => {
|
|
3551
2859
|
if (collapsible) setCollapsed((prev) => !prev);
|
|
3552
2860
|
}, [collapsible]);
|
|
@@ -3611,129 +2919,137 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
3611
2919
|
ref: containerRef,
|
|
3612
2920
|
className: cn("border rounded-lg", isPending ? "border-amber-500/10" : "border-transparent"),
|
|
3613
2921
|
children: collapsed ? (
|
|
3614
|
-
/* ---- Collapsed: dual-crab + summary ---- */
|
|
3615
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
StartCrab,
|
|
2922
|
+
/* ---- Collapsed: dual-crab (+ summary card for multi-log turns) ---- */
|
|
2923
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2924
|
+
"div",
|
|
2925
|
+
{
|
|
2926
|
+
"data-nav-id": `turn-collapsed-${entries[0]?.log.id ?? turnIndex}`,
|
|
2927
|
+
"data-nav-action": "expand",
|
|
2928
|
+
role: "button",
|
|
2929
|
+
tabIndex: 0,
|
|
2930
|
+
className: "flex items-stretch cursor-pointer focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none rounded-lg",
|
|
2931
|
+
onClick: toggleCollapse,
|
|
2932
|
+
onKeyDown: (e) => {
|
|
2933
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2934
|
+
e.preventDefault();
|
|
2935
|
+
toggleCollapse();
|
|
2936
|
+
}
|
|
2937
|
+
},
|
|
2938
|
+
children: [
|
|
2939
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0 flex items-start pt-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground/50 font-mono tabular-nums leading-none select-none", children: turnIndex + 1 }) }),
|
|
2940
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-6 shrink-0 flex flex-col items-center pt-0.5 pb-0.5", children: [
|
|
2941
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center h-[calc(0.75rem-8px)]" }),
|
|
2942
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2943
|
+
"span",
|
|
3637
2944
|
{
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
2945
|
+
role: "button",
|
|
2946
|
+
tabIndex: 0,
|
|
2947
|
+
title: "Start of turn — click to expand",
|
|
2948
|
+
className: "cursor-pointer",
|
|
2949
|
+
onClick: (e) => {
|
|
2950
|
+
e.stopPropagation();
|
|
2951
|
+
toggleCollapse();
|
|
2952
|
+
},
|
|
2953
|
+
onKeyDown: (e) => {
|
|
2954
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2955
|
+
e.preventDefault();
|
|
2956
|
+
toggleCollapse();
|
|
2957
|
+
}
|
|
2958
|
+
},
|
|
2959
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2960
|
+
StartCrab,
|
|
2961
|
+
{
|
|
2962
|
+
className: cn(
|
|
2963
|
+
"size-3.5 text-emerald-400",
|
|
2964
|
+
"animate-crab-appear drop-shadow-[0_0_4px_rgba(52,211,153,0.5)]"
|
|
2965
|
+
)
|
|
2966
|
+
}
|
|
3642
2967
|
)
|
|
3643
2968
|
}
|
|
3644
|
-
)
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3649
|
-
"span",
|
|
3650
|
-
{
|
|
3651
|
-
role: "button",
|
|
3652
|
-
tabIndex: 0,
|
|
3653
|
-
title: "End of Turn — click to expand",
|
|
3654
|
-
className: "cursor-pointer",
|
|
3655
|
-
onClick: (e) => {
|
|
3656
|
-
e.stopPropagation();
|
|
3657
|
-
toggleCollapse();
|
|
3658
|
-
},
|
|
3659
|
-
onKeyDown: (e) => {
|
|
3660
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
3661
|
-
e.preventDefault();
|
|
3662
|
-
toggleCollapse();
|
|
3663
|
-
}
|
|
3664
|
-
},
|
|
3665
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3666
|
-
EndCrab,
|
|
2969
|
+
),
|
|
2970
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex justify-center min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-0.5 bg-muted-foreground/30 h-full" }) }),
|
|
2971
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2972
|
+
"span",
|
|
3667
2973
|
{
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
2974
|
+
role: "button",
|
|
2975
|
+
tabIndex: 0,
|
|
2976
|
+
title: "End of Turn — click to expand",
|
|
2977
|
+
className: "cursor-pointer",
|
|
2978
|
+
onClick: (e) => {
|
|
2979
|
+
e.stopPropagation();
|
|
2980
|
+
toggleCollapse();
|
|
2981
|
+
},
|
|
2982
|
+
onKeyDown: (e) => {
|
|
2983
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2984
|
+
e.preventDefault();
|
|
2985
|
+
toggleCollapse();
|
|
2986
|
+
}
|
|
2987
|
+
},
|
|
2988
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2989
|
+
EndCrab,
|
|
2990
|
+
{
|
|
2991
|
+
className: cn(
|
|
2992
|
+
"size-3.5 text-amber-400",
|
|
2993
|
+
"animate-crab-settle drop-shadow-[0_0_4px_rgba(251,191,36,0.5)]"
|
|
2994
|
+
)
|
|
2995
|
+
}
|
|
3672
2996
|
)
|
|
3673
2997
|
}
|
|
3674
2998
|
)
|
|
3675
|
-
}
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
3690
|
-
e.preventDefault();
|
|
3691
|
-
toggleCollapse();
|
|
3692
|
-
}
|
|
3693
|
-
},
|
|
3694
|
-
children: [
|
|
3695
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-400/80 font-mono font-semibold tabular-nums shrink-0", children: [
|
|
3696
|
-
"#",
|
|
3697
|
-
entries[0]?.log.id ?? "?",
|
|
3698
|
-
" ~ #",
|
|
3699
|
-
entries[lastIdx]?.log.id ?? "?"
|
|
3700
|
-
] }),
|
|
3701
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground shrink-0", children: [
|
|
3702
|
-
entries.length,
|
|
3703
|
-
" request",
|
|
3704
|
-
entries.length > 1 ? "s" : ""
|
|
3705
|
-
] }),
|
|
3706
|
-
uniqueProviders.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex items-center gap-0.5 shrink-0", children: uniqueProviders.map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderLogo, { provider: p, className: "size-4" }, p)) }),
|
|
3707
|
-
aggregate.hasElapsed && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground shrink-0", children: [
|
|
3708
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
|
|
3709
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed(aggregate.totalElapsed) })
|
|
3710
|
-
] }),
|
|
3711
|
-
aggregate.hasTokens && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 shrink-0", children: [
|
|
3712
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
|
|
3713
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
3714
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-400", children: [
|
|
3715
|
-
"IN ",
|
|
3716
|
-
formatTokens(aggregate.totalInput)
|
|
2999
|
+
] }),
|
|
3000
|
+
entries.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3001
|
+
"div",
|
|
3002
|
+
{
|
|
3003
|
+
className: cn(
|
|
3004
|
+
"flex-1 min-w-0 mb-0.5 rounded-lg border border-border py-1 px-3 flex items-center gap-3 text-xs",
|
|
3005
|
+
bgClass
|
|
3006
|
+
),
|
|
3007
|
+
children: [
|
|
3008
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-400/80 font-mono font-semibold tabular-nums shrink-0", children: [
|
|
3009
|
+
"#",
|
|
3010
|
+
entries[0]?.log.id ?? "?",
|
|
3011
|
+
" ~ #",
|
|
3012
|
+
entries[lastIdx]?.log.id ?? "?"
|
|
3717
3013
|
] }),
|
|
3718
|
-
"
|
|
3719
|
-
|
|
3720
|
-
"
|
|
3721
|
-
|
|
3722
|
-
] })
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3014
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground shrink-0", children: [
|
|
3015
|
+
entries.length,
|
|
3016
|
+
" request",
|
|
3017
|
+
entries.length > 1 ? "s" : ""
|
|
3018
|
+
] }),
|
|
3019
|
+
uniqueProviders.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex items-center gap-0.5 shrink-0", children: uniqueProviders.map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderLogo, { provider: p, className: "size-4" }, p)) }),
|
|
3020
|
+
aggregate.hasElapsed && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground shrink-0", children: [
|
|
3021
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
|
|
3022
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed(aggregate.totalElapsed) })
|
|
3023
|
+
] }),
|
|
3024
|
+
aggregate.hasTokens && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 shrink-0", children: [
|
|
3025
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
|
|
3026
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
3027
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-400", children: [
|
|
3028
|
+
"IN ",
|
|
3029
|
+
formatTokens(aggregate.totalInput)
|
|
3030
|
+
] }),
|
|
3031
|
+
" / ",
|
|
3032
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-amber-400", children: [
|
|
3033
|
+
"OUT ",
|
|
3034
|
+
formatTokens(aggregate.totalOutput)
|
|
3035
|
+
] })
|
|
3036
|
+
] })
|
|
3037
|
+
] }),
|
|
3038
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
|
|
3039
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 text-muted-foreground shrink-0" })
|
|
3040
|
+
]
|
|
3041
|
+
}
|
|
3042
|
+
)
|
|
3043
|
+
]
|
|
3044
|
+
}
|
|
3045
|
+
)
|
|
3731
3046
|
) : (
|
|
3732
3047
|
/* ---- Expanded: full entries ---- */
|
|
3733
3048
|
entries.map((entry, visibleIdx) => {
|
|
3734
3049
|
const { log, stopReason: reason } = entry;
|
|
3735
3050
|
const isTurnStart = visibleIdx === 0;
|
|
3736
3051
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-stretch", children: [
|
|
3052
|
+
isTurnStart ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0 flex items-start pt-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground/50 font-mono tabular-nums leading-none select-none", children: turnIndex + 1 }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0" }),
|
|
3737
3053
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3738
3054
|
ThreadConnector,
|
|
3739
3055
|
{
|
|
@@ -3741,8 +3057,9 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
3741
3057
|
isPending: log.responseStatus === null,
|
|
3742
3058
|
isFirst: visibleIdx === 0,
|
|
3743
3059
|
isTurnStart,
|
|
3060
|
+
isOnlyEntry: isSingleLog,
|
|
3744
3061
|
crabIndex: log.id % 12,
|
|
3745
|
-
collapsible: collapsible &&
|
|
3062
|
+
collapsible: collapsible && isTurnStart,
|
|
3746
3063
|
onToggle: toggleCollapse
|
|
3747
3064
|
}
|
|
3748
3065
|
),
|
|
@@ -3762,40 +3079,6 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
3762
3079
|
}
|
|
3763
3080
|
);
|
|
3764
3081
|
});
|
|
3765
|
-
function shouldRenderConversationContent(standalone, expanded) {
|
|
3766
|
-
return standalone || expanded;
|
|
3767
|
-
}
|
|
3768
|
-
function buildTurnGroups(logs) {
|
|
3769
|
-
const groups = [];
|
|
3770
|
-
let entries = [];
|
|
3771
|
-
let turnIndex = 0;
|
|
3772
|
-
for (const log of logs) {
|
|
3773
|
-
entries.push({ log, stopReason: extractStopReason(log) });
|
|
3774
|
-
const current = entries[entries.length - 1];
|
|
3775
|
-
if (current !== void 0 && isTurnBoundary(current.stopReason)) {
|
|
3776
|
-
groups.push({ entries, turnIndex });
|
|
3777
|
-
entries = [];
|
|
3778
|
-
turnIndex += 1;
|
|
3779
|
-
}
|
|
3780
|
-
}
|
|
3781
|
-
if (entries.length > 0) groups.push({ entries, turnIndex });
|
|
3782
|
-
return groups;
|
|
3783
|
-
}
|
|
3784
|
-
function buildValidPredecessors(groups) {
|
|
3785
|
-
const predecessors = /* @__PURE__ */ new Map();
|
|
3786
|
-
for (const group of groups) {
|
|
3787
|
-
for (let index = 1; index < group.logs.length; index += 1) {
|
|
3788
|
-
const current = group.logs[index];
|
|
3789
|
-
const previous = group.logs[index - 1];
|
|
3790
|
-
if (current === void 0 || previous === void 0) continue;
|
|
3791
|
-
const currentFormat = resolveLogFormat(current);
|
|
3792
|
-
const previousFormat = resolveLogFormat(previous);
|
|
3793
|
-
if (currentFormat === "unknown" || currentFormat !== previousFormat) continue;
|
|
3794
|
-
predecessors.set(current.id, previous);
|
|
3795
|
-
}
|
|
3796
|
-
}
|
|
3797
|
-
return predecessors;
|
|
3798
|
-
}
|
|
3799
3082
|
function computeStats(logs) {
|
|
3800
3083
|
let totalInput = 0;
|
|
3801
3084
|
let totalOutput = 0;
|
|
@@ -3842,7 +3125,7 @@ const ConversationGroup = reactExports.memo(function({
|
|
|
3842
3125
|
onClear: () => onClearGroup(group.logs.map((l) => l.id))
|
|
3843
3126
|
}
|
|
3844
3127
|
),
|
|
3845
|
-
shouldRenderConversationContent(standalone, expanded) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", {
|
|
3128
|
+
shouldRenderConversationContent(standalone, expanded) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: turnGroups.map((tg) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3846
3129
|
TurnGroup,
|
|
3847
3130
|
{
|
|
3848
3131
|
entries: tg.entries,
|
|
@@ -4144,13 +3427,13 @@ function ImportWizardDialog({
|
|
|
4144
3427
|
scan();
|
|
4145
3428
|
}
|
|
4146
3429
|
}, [open, scan]);
|
|
4147
|
-
const toggleProvider = reactExports.useCallback((
|
|
3430
|
+
const toggleProvider = reactExports.useCallback((index2) => {
|
|
4148
3431
|
setSelected((prev) => {
|
|
4149
3432
|
const next = new Set(prev);
|
|
4150
|
-
if (next.has(
|
|
4151
|
-
next.delete(
|
|
3433
|
+
if (next.has(index2)) {
|
|
3434
|
+
next.delete(index2);
|
|
4152
3435
|
} else {
|
|
4153
|
-
next.add(
|
|
3436
|
+
next.add(index2);
|
|
4154
3437
|
}
|
|
4155
3438
|
return next;
|
|
4156
3439
|
});
|
|
@@ -4675,10 +3958,10 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
4675
3958
|
const modelRowRefs = reactExports.useRef([]);
|
|
4676
3959
|
reactExports.useEffect(() => {
|
|
4677
3960
|
if (openModelDropdown === null) return;
|
|
4678
|
-
const
|
|
3961
|
+
const index2 = openModelDropdown;
|
|
4679
3962
|
function handleClick(e) {
|
|
4680
3963
|
if (!(e.target instanceof Node)) return;
|
|
4681
|
-
const ref = modelRowRefs.current[
|
|
3964
|
+
const ref = modelRowRefs.current[index2];
|
|
4682
3965
|
if (ref !== null && ref !== void 0 && !ref.contains(e.target)) {
|
|
4683
3966
|
setOpenModelDropdown(null);
|
|
4684
3967
|
}
|
|
@@ -5620,968 +4903,240 @@ function SettingsDialog() {
|
|
|
5620
4903
|
isLoading,
|
|
5621
4904
|
externalTestResults: testResults,
|
|
5622
4905
|
externalTestingProviders: testingProviders,
|
|
5623
|
-
externalTestingTimeLeft: testingTimeLeft,
|
|
5624
|
-
onProvidersMutate: () => {
|
|
5625
|
-
return mutate();
|
|
5626
|
-
},
|
|
5627
|
-
onTestResultsChange: handleTestResultsChange,
|
|
5628
|
-
onTestingProvidersChange: handleTestingProvidersChange,
|
|
5629
|
-
onTestingTimeLeftChange: handleTestingTimeLeftChange
|
|
5630
|
-
}
|
|
5631
|
-
) }),
|
|
5632
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "proxy", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProxySettingsTab, {}) })
|
|
5633
|
-
] })
|
|
5634
|
-
] })
|
|
5635
|
-
] })
|
|
5636
|
-
] });
|
|
5637
|
-
}
|
|
5638
|
-
function ProxySettingsTab() {
|
|
5639
|
-
const { strip, isLoading, setStrip } = useStripConfig();
|
|
5640
|
-
const [error, setError] = reactExports.useState(null);
|
|
5641
|
-
const [pending, setPending] = reactExports.useState(false);
|
|
5642
|
-
const handleToggle = reactExports.useCallback(
|
|
5643
|
-
async (next) => {
|
|
5644
|
-
setError(null);
|
|
5645
|
-
setPending(true);
|
|
5646
|
-
try {
|
|
5647
|
-
await setStrip(next);
|
|
5648
|
-
} catch (err) {
|
|
5649
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
5650
|
-
} finally {
|
|
5651
|
-
setPending(false);
|
|
5652
|
-
}
|
|
5653
|
-
},
|
|
5654
|
-
[setStrip]
|
|
5655
|
-
);
|
|
5656
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
|
|
5657
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
|
|
5658
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-semibold", children: "Claude Code billing header" }),
|
|
5659
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
5660
|
-
"When enabled, the proxy strips the synthetic ",
|
|
5661
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "x-anthropic-billing-header" }),
|
|
5662
|
-
" text block that Claude Code prepends to the system prompt before forwarding to upstream. Improves prefix-cache hit rates against third-party upstreams. The default at startup is controlled by the ",
|
|
5663
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "LLM_INSPECTOR_STRIP_CLAUDE_CODE_BILLING_HEADER" }),
|
|
5664
|
-
" environment variable; your choice is persisted to ",
|
|
5665
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "config.json" }),
|
|
5666
|
-
" and overrides the env var for subsequent requests."
|
|
5667
|
-
] })
|
|
5668
|
-
] }),
|
|
5669
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-3", children: [
|
|
5670
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5671
|
-
"input",
|
|
5672
|
-
{
|
|
5673
|
-
type: "checkbox",
|
|
5674
|
-
role: "switch",
|
|
5675
|
-
checked: strip,
|
|
5676
|
-
disabled: isLoading || pending,
|
|
5677
|
-
onChange: (e) => {
|
|
5678
|
-
void handleToggle(e.currentTarget.checked);
|
|
5679
|
-
},
|
|
5680
|
-
className: "size-4 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50"
|
|
5681
|
-
}
|
|
5682
|
-
),
|
|
5683
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: isLoading ? "Loading…" : strip ? "Stripping enabled" : "Stripping disabled" })
|
|
5684
|
-
] }),
|
|
5685
|
-
error !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-destructive", children: [
|
|
5686
|
-
"Failed to save: ",
|
|
5687
|
-
error
|
|
5688
|
-
] })
|
|
5689
|
-
] });
|
|
5690
|
-
}
|
|
5691
|
-
function computeCacheTrends(groups) {
|
|
5692
|
-
const result = /* @__PURE__ */ new Map();
|
|
5693
|
-
for (const group of groups) {
|
|
5694
|
-
const logs = group.logs;
|
|
5695
|
-
for (let i = 1; i < logs.length; i++) {
|
|
5696
|
-
const prev = logs[i - 1];
|
|
5697
|
-
const curr = logs[i];
|
|
5698
|
-
if (prev === void 0 || curr === void 0) continue;
|
|
5699
|
-
result.set(curr.id, {
|
|
5700
|
-
creation: compareField(prev.cacheCreationInputTokens, curr.cacheCreationInputTokens),
|
|
5701
|
-
read: compareField(prev.cacheReadInputTokens, curr.cacheReadInputTokens)
|
|
5702
|
-
});
|
|
5703
|
-
}
|
|
5704
|
-
}
|
|
5705
|
-
return result;
|
|
5706
|
-
}
|
|
5707
|
-
function compareField(previous, current) {
|
|
5708
|
-
if (current === null) return null;
|
|
5709
|
-
if (previous === null) return null;
|
|
5710
|
-
if (current > previous) return { direction: "up", delta: current - previous };
|
|
5711
|
-
if (current < previous) return { direction: "down", delta: previous - current };
|
|
5712
|
-
return null;
|
|
5713
|
-
}
|
|
5714
|
-
const ROOT_PATH = "";
|
|
5715
|
-
function formatPath(segments) {
|
|
5716
|
-
if (segments.length === 0) return ROOT_PATH;
|
|
5717
|
-
let out = "";
|
|
5718
|
-
for (let i = 0; i < segments.length; i++) {
|
|
5719
|
-
const seg = segments[i];
|
|
5720
|
-
if (seg === void 0) continue;
|
|
5721
|
-
if (typeof seg === "number") {
|
|
5722
|
-
out += `[${seg}]`;
|
|
5723
|
-
} else if (i === 0) {
|
|
5724
|
-
out += seg;
|
|
5725
|
-
} else {
|
|
5726
|
-
out += `.${seg}`;
|
|
5727
|
-
}
|
|
5728
|
-
}
|
|
5729
|
-
return out;
|
|
5730
|
-
}
|
|
5731
|
-
function isPlainObject(value) {
|
|
5732
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5733
|
-
}
|
|
5734
|
-
function normalizeRequest(raw) {
|
|
5735
|
-
if (typeof raw === "string") {
|
|
5736
|
-
try {
|
|
5737
|
-
return toNode(JSON.parse(raw));
|
|
5738
|
-
} catch {
|
|
5739
|
-
return { kind: "primitive", value: raw };
|
|
5740
|
-
}
|
|
5741
|
-
}
|
|
5742
|
-
return toNode(raw);
|
|
5743
|
-
}
|
|
5744
|
-
function toNode(value) {
|
|
5745
|
-
if (value === null) return { kind: "primitive", value: null };
|
|
5746
|
-
if (typeof value === "string") return { kind: "primitive", value };
|
|
5747
|
-
if (typeof value === "number") return { kind: "primitive", value };
|
|
5748
|
-
if (typeof value === "boolean") return { kind: "primitive", value };
|
|
5749
|
-
if (Array.isArray(value)) {
|
|
5750
|
-
return { kind: "array", value: value.map((v) => toNode(v)) };
|
|
5751
|
-
}
|
|
5752
|
-
if (isPlainObject(value)) {
|
|
5753
|
-
const out = {};
|
|
5754
|
-
for (const k of Object.keys(value).sort()) {
|
|
5755
|
-
out[k] = toNode(value[k]);
|
|
5756
|
-
}
|
|
5757
|
-
return { kind: "object", value: out };
|
|
5758
|
-
}
|
|
5759
|
-
return { kind: "primitive", value: null };
|
|
5760
|
-
}
|
|
5761
|
-
function diffTrees(left, right) {
|
|
5762
|
-
const ops = [];
|
|
5763
|
-
walk([], left, right, ops);
|
|
5764
|
-
return ops;
|
|
5765
|
-
}
|
|
5766
|
-
function walk(segments, left, right, out) {
|
|
5767
|
-
const path = formatPath(segments);
|
|
5768
|
-
if (nodeEqual(left, right)) {
|
|
5769
|
-
out.push({ kind: "equal", path, value: left });
|
|
5770
|
-
return;
|
|
5771
|
-
}
|
|
5772
|
-
if (left.kind !== right.kind) {
|
|
5773
|
-
out.push({ kind: "changed", path, left, right });
|
|
5774
|
-
return;
|
|
5775
|
-
}
|
|
5776
|
-
if (left.kind === "primitive" && right.kind === "primitive") {
|
|
5777
|
-
out.push({ kind: "changed", path, left, right });
|
|
5778
|
-
return;
|
|
5779
|
-
}
|
|
5780
|
-
if (left.kind === "object" && right.kind === "object") {
|
|
5781
|
-
const leftKeys = Object.keys(left.value);
|
|
5782
|
-
const rightKeys = Object.keys(right.value);
|
|
5783
|
-
const rightKeySet = new Set(rightKeys);
|
|
5784
|
-
for (const k of leftKeys) {
|
|
5785
|
-
const lChild = left.value[k];
|
|
5786
|
-
if (lChild === void 0) continue;
|
|
5787
|
-
if (!rightKeySet.has(k)) {
|
|
5788
|
-
out.push({
|
|
5789
|
-
kind: "removed",
|
|
5790
|
-
path: formatPath([...segments, k]),
|
|
5791
|
-
value: lChild
|
|
5792
|
-
});
|
|
5793
|
-
} else {
|
|
5794
|
-
const rChild = right.value[k];
|
|
5795
|
-
if (rChild === void 0) continue;
|
|
5796
|
-
walk([...segments, k], lChild, rChild, out);
|
|
5797
|
-
}
|
|
5798
|
-
}
|
|
5799
|
-
for (const k of rightKeys) {
|
|
5800
|
-
if (leftKeys.includes(k)) continue;
|
|
5801
|
-
const rChild = right.value[k];
|
|
5802
|
-
if (rChild === void 0) continue;
|
|
5803
|
-
out.push({
|
|
5804
|
-
kind: "added",
|
|
5805
|
-
path: formatPath([...segments, k]),
|
|
5806
|
-
value: rChild
|
|
5807
|
-
});
|
|
5808
|
-
}
|
|
5809
|
-
return;
|
|
5810
|
-
}
|
|
5811
|
-
if (left.kind === "array" && right.kind === "array") {
|
|
5812
|
-
const minLen = Math.min(left.value.length, right.value.length);
|
|
5813
|
-
for (let i = 0; i < minLen; i++) {
|
|
5814
|
-
const lChild = left.value[i];
|
|
5815
|
-
const rChild = right.value[i];
|
|
5816
|
-
if (lChild === void 0 || rChild === void 0) continue;
|
|
5817
|
-
walk([...segments, i], lChild, rChild, out);
|
|
5818
|
-
}
|
|
5819
|
-
for (let i = minLen; i < right.value.length; i++) {
|
|
5820
|
-
const rChild = right.value[i];
|
|
5821
|
-
if (rChild === void 0) continue;
|
|
5822
|
-
out.push({
|
|
5823
|
-
kind: "added",
|
|
5824
|
-
path: formatPath([...segments, i]),
|
|
5825
|
-
value: rChild
|
|
5826
|
-
});
|
|
5827
|
-
}
|
|
5828
|
-
for (let i = minLen; i < left.value.length; i++) {
|
|
5829
|
-
const lChild = left.value[i];
|
|
5830
|
-
if (lChild === void 0) continue;
|
|
5831
|
-
out.push({
|
|
5832
|
-
kind: "removed",
|
|
5833
|
-
path: formatPath([...segments, i]),
|
|
5834
|
-
value: lChild
|
|
5835
|
-
});
|
|
5836
|
-
}
|
|
5837
|
-
}
|
|
5838
|
-
}
|
|
5839
|
-
function nodeEqual(a, b) {
|
|
5840
|
-
if (a.kind !== b.kind) return false;
|
|
5841
|
-
if (a.kind === "primitive" && b.kind === "primitive") {
|
|
5842
|
-
return a.value === b.value;
|
|
5843
|
-
}
|
|
5844
|
-
if (a.kind === "array" && b.kind === "array") {
|
|
5845
|
-
if (a.value.length !== b.value.length) return false;
|
|
5846
|
-
for (let i = 0; i < a.value.length; i++) {
|
|
5847
|
-
const ai = a.value[i];
|
|
5848
|
-
const bi = b.value[i];
|
|
5849
|
-
if (ai === void 0 || bi === void 0) return false;
|
|
5850
|
-
if (!nodeEqual(ai, bi)) return false;
|
|
5851
|
-
}
|
|
5852
|
-
return true;
|
|
5853
|
-
}
|
|
5854
|
-
if (a.kind === "object" && b.kind === "object") {
|
|
5855
|
-
const aKeys = Object.keys(a.value);
|
|
5856
|
-
const bKeys = Object.keys(b.value);
|
|
5857
|
-
if (aKeys.length !== bKeys.length) return false;
|
|
5858
|
-
for (const k of aKeys) {
|
|
5859
|
-
const av = a.value[k];
|
|
5860
|
-
const bv = b.value[k];
|
|
5861
|
-
if (av === void 0 || bv === void 0) return false;
|
|
5862
|
-
if (!nodeEqual(av, bv)) return false;
|
|
5863
|
-
}
|
|
5864
|
-
return true;
|
|
5865
|
-
}
|
|
5866
|
-
return false;
|
|
5867
|
-
}
|
|
5868
|
-
function previewNode(node, maxLen = 80) {
|
|
5869
|
-
let s;
|
|
5870
|
-
switch (node.kind) {
|
|
5871
|
-
case "primitive":
|
|
5872
|
-
s = node.value === null ? "null" : JSON.stringify(node.value);
|
|
5873
|
-
break;
|
|
5874
|
-
case "array":
|
|
5875
|
-
s = `[… ${node.value.length} items]`;
|
|
5876
|
-
break;
|
|
5877
|
-
case "object":
|
|
5878
|
-
s = `{… ${Object.keys(node.value).length} keys}`;
|
|
5879
|
-
break;
|
|
5880
|
-
}
|
|
5881
|
-
if (s.length > maxLen) s = `${s.slice(0, maxLen - 1)}…`;
|
|
5882
|
-
return s;
|
|
5883
|
-
}
|
|
5884
|
-
function nodeToJsonString(node, indent = 2) {
|
|
5885
|
-
return JSON.stringify(nodeToJsonValue(node), null, indent);
|
|
5886
|
-
}
|
|
5887
|
-
function nodeToJsonValue(node) {
|
|
5888
|
-
switch (node.kind) {
|
|
5889
|
-
case "primitive":
|
|
5890
|
-
return node.value;
|
|
5891
|
-
case "array":
|
|
5892
|
-
return node.value.map(nodeToJsonValue);
|
|
5893
|
-
case "object": {
|
|
5894
|
-
const out = {};
|
|
5895
|
-
for (const [k, v] of Object.entries(node.value)) {
|
|
5896
|
-
out[k] = nodeToJsonValue(v);
|
|
5897
|
-
}
|
|
5898
|
-
return out;
|
|
5899
|
-
}
|
|
5900
|
-
}
|
|
5901
|
-
}
|
|
5902
|
-
function parentPath(path) {
|
|
5903
|
-
if (path === "") return "";
|
|
5904
|
-
for (let i = path.length - 1; i >= 0; i--) {
|
|
5905
|
-
const ch = path[i];
|
|
5906
|
-
if (ch === "." || ch === "[") {
|
|
5907
|
-
return path.substring(0, i);
|
|
5908
|
-
}
|
|
5909
|
-
}
|
|
5910
|
-
return "";
|
|
5911
|
-
}
|
|
5912
|
-
function isDeepEqual(op) {
|
|
5913
|
-
return op.kind === "equal" && (op.value.kind === "object" || op.value.kind === "array");
|
|
5914
|
-
}
|
|
5915
|
-
function groupContiguousEquals(ops) {
|
|
5916
|
-
const out = [];
|
|
5917
|
-
let i = 0;
|
|
5918
|
-
while (i < ops.length) {
|
|
5919
|
-
const op = ops[i];
|
|
5920
|
-
if (op !== void 0 && isDeepEqual(op)) {
|
|
5921
|
-
const startParent = parentPath(op.path);
|
|
5922
|
-
let j = i + 1;
|
|
5923
|
-
while (j < ops.length) {
|
|
5924
|
-
const next = ops[j];
|
|
5925
|
-
if (next === void 0) break;
|
|
5926
|
-
if (!isDeepEqual(next)) break;
|
|
5927
|
-
if (parentPath(next.path) !== startParent) break;
|
|
5928
|
-
j++;
|
|
5929
|
-
}
|
|
5930
|
-
if (j - i > 1) {
|
|
5931
|
-
const equalOps = [];
|
|
5932
|
-
for (let k = i; k < j; k++) {
|
|
5933
|
-
const eop = ops[k];
|
|
5934
|
-
if (eop !== void 0 && eop.kind === "equal") {
|
|
5935
|
-
equalOps.push(eop);
|
|
5936
|
-
}
|
|
5937
|
-
}
|
|
5938
|
-
out.push({ kind: "equal-run", ops: equalOps });
|
|
5939
|
-
i = j;
|
|
5940
|
-
continue;
|
|
5941
|
-
}
|
|
5942
|
-
}
|
|
5943
|
-
if (op !== void 0) {
|
|
5944
|
-
out.push({ kind: "single", op });
|
|
5945
|
-
}
|
|
5946
|
-
i++;
|
|
5947
|
-
}
|
|
5948
|
-
return out;
|
|
5949
|
-
}
|
|
5950
|
-
const KIND_VISUAL = {
|
|
5951
|
-
added: {
|
|
5952
|
-
icon: Plus,
|
|
5953
|
-
accent: "text-emerald-600 dark:text-emerald-400",
|
|
5954
|
-
bg: "bg-emerald-500/5 hover:bg-emerald-500/10",
|
|
5955
|
-
border: "border-l-emerald-500",
|
|
5956
|
-
label: "ADDED"
|
|
5957
|
-
},
|
|
5958
|
-
removed: {
|
|
5959
|
-
icon: Minus,
|
|
5960
|
-
accent: "text-rose-600 dark:text-rose-400",
|
|
5961
|
-
bg: "bg-rose-500/5 hover:bg-rose-500/10",
|
|
5962
|
-
border: "border-l-rose-500",
|
|
5963
|
-
label: "REMOVED"
|
|
5964
|
-
},
|
|
5965
|
-
changed: {
|
|
5966
|
-
icon: Pencil,
|
|
5967
|
-
accent: "text-amber-600 dark:text-amber-400",
|
|
5968
|
-
bg: "bg-amber-500/5 hover:bg-amber-500/10",
|
|
5969
|
-
border: "border-l-amber-500",
|
|
5970
|
-
label: "CHANGED"
|
|
5971
|
-
},
|
|
5972
|
-
equal: {
|
|
5973
|
-
icon: Equal,
|
|
5974
|
-
accent: "text-muted-foreground/70",
|
|
5975
|
-
bg: "bg-muted/20 hover:bg-muted/30",
|
|
5976
|
-
border: "border-l-muted-foreground/20",
|
|
5977
|
-
label: "EQUAL"
|
|
5978
|
-
}
|
|
5979
|
-
};
|
|
5980
|
-
function EqualRunRow({
|
|
5981
|
-
ops,
|
|
5982
|
-
expanded,
|
|
5983
|
-
onToggle
|
|
5984
|
-
}) {
|
|
5985
|
-
const first = ops[0];
|
|
5986
|
-
const last = ops[ops.length - 1];
|
|
5987
|
-
if (first === void 0 || last === void 0) {
|
|
5988
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground/40 text-xs", children: "—" });
|
|
5989
|
-
}
|
|
5990
|
-
const firstPath = first.path;
|
|
5991
|
-
const lastPath = last.path;
|
|
5992
|
-
const label = ops.length === 1 ? firstPath : `${firstPath} … ${lastPath}`;
|
|
5993
|
-
const summary = first.value.kind === "array" ? `${ops.length} equal arrays` : first.value.kind === "object" ? `${ops.length} equal objects` : "equal";
|
|
5994
|
-
const v = KIND_VISUAL.equal;
|
|
5995
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn("border-l-4 rounded-sm", v.border, v.bg), children: [
|
|
5996
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
5997
|
-
"button",
|
|
5998
|
-
{
|
|
5999
|
-
type: "button",
|
|
6000
|
-
onClick: onToggle,
|
|
6001
|
-
className: "w-full text-left flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground cursor-pointer",
|
|
6002
|
-
children: [
|
|
6003
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6004
|
-
ChevronRight,
|
|
6005
|
-
{
|
|
6006
|
-
className: cn("size-3 transition-transform shrink-0", expanded && "rotate-90")
|
|
6007
|
-
}
|
|
6008
|
-
),
|
|
6009
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(v.icon, { className: cn("size-3 shrink-0", v.accent) }),
|
|
6010
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono truncate flex-1", title: `${firstPath} … ${lastPath}`, children: label }),
|
|
6011
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn("text-[10px] uppercase tracking-wider shrink-0", v.accent), children: v.label }),
|
|
6012
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground/60 shrink-0", children: [
|
|
6013
|
-
"(",
|
|
6014
|
-
summary,
|
|
6015
|
-
")"
|
|
6016
|
-
] })
|
|
6017
|
-
]
|
|
6018
|
-
}
|
|
6019
|
-
),
|
|
6020
|
-
expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ml-5 mt-1 mb-2 space-y-2 pr-2", children: ops.map((op) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-border/50 rounded p-2 bg-muted/20", children: [
|
|
6021
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-mono text-xs text-muted-foreground mb-1", children: op.path }),
|
|
6022
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: nodeToJsonString(op.value), defaultExpandDepth: 0 })
|
|
6023
|
-
] }, op.path)) })
|
|
6024
|
-
] });
|
|
6025
|
-
}
|
|
6026
|
-
function UnifiedOpRow({
|
|
6027
|
-
op,
|
|
6028
|
-
idx,
|
|
6029
|
-
copiedPath,
|
|
6030
|
-
onCopyPath,
|
|
6031
|
-
expanded,
|
|
6032
|
-
onToggle
|
|
6033
|
-
}) {
|
|
6034
|
-
const v = KIND_VISUAL[op.kind];
|
|
6035
|
-
const Icon2 = v.icon;
|
|
6036
|
-
const isExpandable2 = op.kind === "added" || op.kind === "removed" ? op.value.kind === "object" || op.value.kind === "array" : op.kind === "changed" ? op.left.kind === "object" || op.left.kind === "array" || op.right.kind === "object" || op.right.kind === "array" : false;
|
|
6037
|
-
const preview = op.kind === "changed" ? [
|
|
6038
|
-
{
|
|
6039
|
-
text: previewNode(op.left, 400),
|
|
6040
|
-
tone: "text-rose-700 dark:text-rose-300 line-through"
|
|
6041
|
-
},
|
|
6042
|
-
{ text: previewNode(op.right, 400), tone: "text-emerald-700 dark:text-emerald-300" }
|
|
6043
|
-
] : op.kind === "removed" ? [
|
|
6044
|
-
{
|
|
6045
|
-
text: previewNode(op.value, 400),
|
|
6046
|
-
tone: "text-rose-700 dark:text-rose-300 line-through"
|
|
6047
|
-
}
|
|
6048
|
-
] : op.kind === "added" ? [{ text: previewNode(op.value, 400), tone: "text-emerald-700 dark:text-emerald-300" }] : [{ text: previewNode(op.value, 400), tone: "text-muted-foreground" }];
|
|
6049
|
-
const justCopied = copiedPath === op.path && op.path !== "";
|
|
6050
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
6051
|
-
"div",
|
|
6052
|
-
{
|
|
6053
|
-
"data-diff-idx": idx,
|
|
6054
|
-
"data-diff-kind": op.kind,
|
|
6055
|
-
className: cn("border-l-4 rounded-sm px-3 py-2 my-0.5 transition-colors", v.border, v.bg),
|
|
6056
|
-
children: [
|
|
6057
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
6058
|
-
"button",
|
|
6059
|
-
{
|
|
6060
|
-
type: "button",
|
|
6061
|
-
onClick: onToggle,
|
|
6062
|
-
disabled: !isExpandable2,
|
|
6063
|
-
className: cn(
|
|
6064
|
-
"w-full flex items-center gap-2 text-xs text-left rounded-sm",
|
|
6065
|
-
isExpandable2 ? "cursor-pointer" : "cursor-default"
|
|
6066
|
-
),
|
|
6067
|
-
"aria-expanded": isExpandable2 ? expanded : void 0,
|
|
6068
|
-
"aria-label": isExpandable2 ? expanded ? `Collapse ${op.path || "root"}` : `Expand ${op.path || "root"}` : void 0,
|
|
6069
|
-
children: [
|
|
6070
|
-
isExpandable2 ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6071
|
-
ChevronRight,
|
|
6072
|
-
{
|
|
6073
|
-
className: cn(
|
|
6074
|
-
"size-3 shrink-0 transition-transform",
|
|
6075
|
-
v.accent,
|
|
6076
|
-
expanded && "rotate-90"
|
|
6077
|
-
)
|
|
6078
|
-
}
|
|
6079
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "size-3 shrink-0", "aria-hidden": "true" }),
|
|
6080
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { className: cn("size-3.5 shrink-0", v.accent), strokeWidth: 2.5 }),
|
|
6081
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono truncate flex-1 min-w-0", title: op.path || "(root)", children: op.path === "" ? "(root)" : op.path }),
|
|
6082
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6083
|
-
"span",
|
|
6084
|
-
{
|
|
6085
|
-
className: cn(
|
|
6086
|
-
"text-[9px] font-bold uppercase tracking-wider shrink-0 px-1.5 py-0.5 rounded",
|
|
6087
|
-
v.accent,
|
|
6088
|
-
op.kind === "equal" ? "bg-muted/40" : "bg-background/60"
|
|
6089
|
-
),
|
|
6090
|
-
children: v.label
|
|
6091
|
-
}
|
|
6092
|
-
),
|
|
6093
|
-
op.path !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6094
|
-
"span",
|
|
6095
|
-
{
|
|
6096
|
-
role: "button",
|
|
6097
|
-
tabIndex: 0,
|
|
6098
|
-
onClick: (e) => {
|
|
6099
|
-
e.stopPropagation();
|
|
6100
|
-
onCopyPath(op.path);
|
|
6101
|
-
},
|
|
6102
|
-
onKeyDown: (e) => {
|
|
6103
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
6104
|
-
e.stopPropagation();
|
|
6105
|
-
e.preventDefault();
|
|
6106
|
-
onCopyPath(op.path);
|
|
6107
|
-
}
|
|
6108
|
-
},
|
|
6109
|
-
className: cn(
|
|
6110
|
-
"shrink-0 p-1 rounded transition-colors cursor-pointer inline-flex items-center justify-center",
|
|
6111
|
-
justCopied ? "text-emerald-500" : "text-muted-foreground/50 hover:text-foreground hover:bg-muted"
|
|
6112
|
-
),
|
|
6113
|
-
"aria-label": justCopied ? "Copied" : "Copy",
|
|
6114
|
-
title: justCopied ? "Copied!" : "Copy",
|
|
6115
|
-
children: justCopied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3" })
|
|
6116
|
-
}
|
|
6117
|
-
)
|
|
6118
|
-
]
|
|
6119
|
-
}
|
|
6120
|
-
),
|
|
6121
|
-
preview.map((p, i) => (
|
|
6122
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: preview list is rebuilt on every render and is positional
|
|
6123
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("font-mono text-xs mt-1 break-all pl-5", p.tone), children: p.text }, i)
|
|
6124
|
-
)),
|
|
6125
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6126
|
-
"div",
|
|
6127
|
-
{
|
|
6128
|
-
className: "overflow-hidden transition-all duration-200",
|
|
6129
|
-
style: { maxHeight: expanded && isExpandable2 ? "2000px" : "0" },
|
|
6130
|
-
"aria-hidden": !expanded,
|
|
6131
|
-
children: expanded && isExpandable2 && op.kind !== "equal" ? /* @__PURE__ */ jsxRuntimeExports.jsx(ExpandedSubtree, { op }) : null
|
|
6132
|
-
}
|
|
6133
|
-
)
|
|
6134
|
-
]
|
|
6135
|
-
}
|
|
6136
|
-
);
|
|
6137
|
-
}
|
|
6138
|
-
function ExpandedSubtree({ op }) {
|
|
6139
|
-
if (op.kind === "added" || op.kind === "removed") {
|
|
6140
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-5 mt-2 border border-border/50 rounded p-2 bg-muted/20", children: /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: nodeToJsonString(op.value), defaultExpandDepth: 0 }) });
|
|
6141
|
-
}
|
|
6142
|
-
const leftIsStructured = op.left.kind === "object" || op.left.kind === "array";
|
|
6143
|
-
const rightIsStructured = op.right.kind === "object" || op.right.kind === "array";
|
|
6144
|
-
if (!leftIsStructured && !rightIsStructured) {
|
|
6145
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-5 mt-2 text-xs text-muted-foreground/70 italic", children: "Primitive values are shown inline above." });
|
|
6146
|
-
}
|
|
6147
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "pl-5 mt-2 grid grid-cols-1 md:grid-cols-2 gap-2", children: [
|
|
6148
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-rose-500/30 rounded p-2 bg-rose-500/5", children: [
|
|
6149
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] uppercase tracking-wider text-rose-500 mb-1", children: "Old" }),
|
|
6150
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: nodeToJsonString(op.left), defaultExpandDepth: 0 })
|
|
6151
|
-
] }),
|
|
6152
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-emerald-500/30 rounded p-2 bg-emerald-500/5", children: [
|
|
6153
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] uppercase tracking-wider text-emerald-500 mb-1", children: "New" }),
|
|
6154
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: nodeToJsonString(op.right), defaultExpandDepth: 0 })
|
|
6155
|
-
] })
|
|
6156
|
-
] });
|
|
6157
|
-
}
|
|
6158
|
-
function SummaryChips({
|
|
6159
|
-
counts,
|
|
6160
|
-
onJumpTo
|
|
6161
|
-
}) {
|
|
6162
|
-
const total = counts.added + counts.removed + counts.changed;
|
|
6163
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-2 border-b border-border bg-muted/20 flex items-center gap-2 text-xs flex-wrap", children: [
|
|
6164
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground font-medium", children: [
|
|
6165
|
-
total,
|
|
6166
|
-
" ",
|
|
6167
|
-
total === 1 ? "change" : "changes"
|
|
6168
|
-
] }),
|
|
6169
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
6170
|
-
"button",
|
|
6171
|
-
{
|
|
6172
|
-
type: "button",
|
|
6173
|
-
onClick: () => onJumpTo("removed"),
|
|
6174
|
-
disabled: counts.removed === 0,
|
|
6175
|
-
className: cn(
|
|
6176
|
-
"inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",
|
|
6177
|
-
counts.removed > 0 ? "border-rose-500/40 text-rose-600 dark:text-rose-400 bg-rose-500/10 hover:bg-rose-500/20" : "border-border text-muted-foreground/40 cursor-not-allowed"
|
|
6178
|
-
),
|
|
6179
|
-
title: counts.removed > 0 ? "Jump to first removed" : "No removals",
|
|
6180
|
-
children: [
|
|
6181
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Minus, { className: "size-3" }),
|
|
6182
|
-
counts.removed,
|
|
6183
|
-
" removed"
|
|
6184
|
-
]
|
|
6185
|
-
}
|
|
6186
|
-
),
|
|
6187
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
6188
|
-
"button",
|
|
6189
|
-
{
|
|
6190
|
-
type: "button",
|
|
6191
|
-
onClick: () => onJumpTo("added"),
|
|
6192
|
-
disabled: counts.added === 0,
|
|
6193
|
-
className: cn(
|
|
6194
|
-
"inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",
|
|
6195
|
-
counts.added > 0 ? "border-emerald-500/40 text-emerald-600 dark:text-emerald-400 bg-emerald-500/10 hover:bg-emerald-500/20" : "border-border text-muted-foreground/40 cursor-not-allowed"
|
|
6196
|
-
),
|
|
6197
|
-
title: counts.added > 0 ? "Jump to first added" : "No additions",
|
|
6198
|
-
children: [
|
|
6199
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "size-3" }),
|
|
6200
|
-
counts.added,
|
|
6201
|
-
" added"
|
|
6202
|
-
]
|
|
6203
|
-
}
|
|
6204
|
-
),
|
|
6205
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
6206
|
-
"button",
|
|
6207
|
-
{
|
|
6208
|
-
type: "button",
|
|
6209
|
-
onClick: () => onJumpTo("changed"),
|
|
6210
|
-
disabled: counts.changed === 0,
|
|
6211
|
-
className: cn(
|
|
6212
|
-
"inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",
|
|
6213
|
-
counts.changed > 0 ? "border-amber-500/40 text-amber-600 dark:text-amber-400 bg-amber-500/10 hover:bg-amber-500/20" : "border-border text-muted-foreground/40 cursor-not-allowed"
|
|
6214
|
-
),
|
|
6215
|
-
title: counts.changed > 0 ? "Jump to first changed" : "No changes",
|
|
6216
|
-
children: [
|
|
6217
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Pencil, { className: "size-3" }),
|
|
6218
|
-
counts.changed,
|
|
6219
|
-
" changed"
|
|
6220
|
-
]
|
|
6221
|
-
}
|
|
6222
|
-
)
|
|
4906
|
+
externalTestingTimeLeft: testingTimeLeft,
|
|
4907
|
+
onProvidersMutate: () => {
|
|
4908
|
+
return mutate();
|
|
4909
|
+
},
|
|
4910
|
+
onTestResultsChange: handleTestResultsChange,
|
|
4911
|
+
onTestingProvidersChange: handleTestingProvidersChange,
|
|
4912
|
+
onTestingTimeLeftChange: handleTestingTimeLeftChange
|
|
4913
|
+
}
|
|
4914
|
+
) }),
|
|
4915
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "proxy", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProxySettingsTab, {}) })
|
|
4916
|
+
] })
|
|
4917
|
+
] })
|
|
4918
|
+
] })
|
|
6223
4919
|
] });
|
|
6224
4920
|
}
|
|
6225
|
-
function
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
),
|
|
6240
|
-
title: "Unified view (single column, emphasized diffs)",
|
|
6241
|
-
children: [
|
|
6242
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Rows3, { className: "size-3" }),
|
|
6243
|
-
"Unified"
|
|
6244
|
-
]
|
|
6245
|
-
}
|
|
6246
|
-
),
|
|
6247
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
6248
|
-
"button",
|
|
6249
|
-
{
|
|
6250
|
-
type: "button",
|
|
6251
|
-
onClick: () => onChange("split"),
|
|
6252
|
-
"aria-pressed": mode === "split",
|
|
6253
|
-
className: cn(
|
|
6254
|
-
"flex items-center gap-1 px-2 py-1 text-xs transition-colors border-l border-border cursor-pointer",
|
|
6255
|
-
mode === "split" ? "bg-muted text-foreground" : "hover:bg-muted/50 text-muted-foreground"
|
|
6256
|
-
),
|
|
6257
|
-
title: "Split view (path | left | right)",
|
|
6258
|
-
children: [
|
|
6259
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Columns2, { className: "size-3" }),
|
|
6260
|
-
"Split"
|
|
6261
|
-
]
|
|
4921
|
+
function ProxySettingsTab() {
|
|
4922
|
+
const { strip, isLoading, setStrip } = useStripConfig();
|
|
4923
|
+
const [error, setError] = reactExports.useState(null);
|
|
4924
|
+
const [pending, setPending] = reactExports.useState(false);
|
|
4925
|
+
const handleToggle = reactExports.useCallback(
|
|
4926
|
+
async (next) => {
|
|
4927
|
+
setError(null);
|
|
4928
|
+
setPending(true);
|
|
4929
|
+
try {
|
|
4930
|
+
await setStrip(next);
|
|
4931
|
+
} catch (err) {
|
|
4932
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4933
|
+
} finally {
|
|
4934
|
+
setPending(false);
|
|
6262
4935
|
}
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
4936
|
+
},
|
|
4937
|
+
[setStrip]
|
|
4938
|
+
);
|
|
4939
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
|
|
4940
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
|
|
4941
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-semibold", children: "Claude Code billing header" }),
|
|
4942
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
4943
|
+
"When enabled, the proxy strips the synthetic ",
|
|
4944
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "x-anthropic-billing-header" }),
|
|
4945
|
+
" text block that Claude Code prepends to the system prompt before forwarding to upstream. Improves prefix-cache hit rates against third-party upstreams. The default at startup is controlled by the ",
|
|
4946
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "LLM_INSPECTOR_STRIP_CLAUDE_CODE_BILLING_HEADER" }),
|
|
4947
|
+
" environment variable; your choice is persisted to ",
|
|
4948
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "config.json" }),
|
|
4949
|
+
" and overrides the env var for subsequent requests."
|
|
4950
|
+
] })
|
|
4951
|
+
] }),
|
|
4952
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-3", children: [
|
|
6270
4953
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6271
|
-
|
|
4954
|
+
"input",
|
|
6272
4955
|
{
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
)
|
|
6278
|
-
|
|
4956
|
+
type: "checkbox",
|
|
4957
|
+
role: "switch",
|
|
4958
|
+
checked: strip,
|
|
4959
|
+
disabled: isLoading || pending,
|
|
4960
|
+
onChange: (e) => {
|
|
4961
|
+
void handleToggle(e.currentTarget.checked);
|
|
4962
|
+
},
|
|
4963
|
+
className: "size-4 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50"
|
|
6279
4964
|
}
|
|
6280
4965
|
),
|
|
6281
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
6282
|
-
"#",
|
|
6283
|
-
log.id
|
|
6284
|
-
] }),
|
|
6285
|
-
log.model !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-muted-foreground truncate", children: log.model })
|
|
6286
|
-
] }),
|
|
6287
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 text-muted-foreground font-mono", children: [
|
|
6288
|
-
log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-emerald-400", children: [
|
|
6289
|
-
"Cache +",
|
|
6290
|
-
formatTokens(log.cacheCreationInputTokens)
|
|
6291
|
-
] }),
|
|
6292
|
-
log.cacheReadInputTokens !== null && log.cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-purple-400", children: [
|
|
6293
|
-
"Cache ~",
|
|
6294
|
-
formatTokens(log.cacheReadInputTokens)
|
|
6295
|
-
] }),
|
|
6296
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", title: log.timestamp, children: log.timestamp })
|
|
4966
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: isLoading ? "Loading…" : strip ? "Stripping enabled" : "Stripping disabled" })
|
|
6297
4967
|
] }),
|
|
6298
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("
|
|
6299
|
-
"
|
|
6300
|
-
|
|
4968
|
+
error !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-destructive", children: [
|
|
4969
|
+
"Failed to save: ",
|
|
4970
|
+
error
|
|
6301
4971
|
] })
|
|
6302
4972
|
] });
|
|
6303
4973
|
}
|
|
6304
|
-
function
|
|
6305
|
-
const
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
)
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
left.apiFormat,
|
|
6317
|
-
left.path,
|
|
6318
|
-
left.rawRequestBody,
|
|
6319
|
-
right.apiFormat,
|
|
6320
|
-
right.path,
|
|
6321
|
-
right.rawRequestBody
|
|
6322
|
-
]);
|
|
6323
|
-
const grouped = reactExports.useMemo(() => groupContiguousEquals(ops), [ops]);
|
|
6324
|
-
const counts = reactExports.useMemo(() => {
|
|
6325
|
-
let added = 0;
|
|
6326
|
-
let removed = 0;
|
|
6327
|
-
let changed = 0;
|
|
6328
|
-
for (const g of grouped) {
|
|
6329
|
-
if (g.kind !== "single") continue;
|
|
6330
|
-
switch (g.op.kind) {
|
|
6331
|
-
case "added":
|
|
6332
|
-
added++;
|
|
6333
|
-
break;
|
|
6334
|
-
case "removed":
|
|
6335
|
-
removed++;
|
|
6336
|
-
break;
|
|
6337
|
-
case "changed":
|
|
6338
|
-
changed++;
|
|
6339
|
-
break;
|
|
6340
|
-
}
|
|
6341
|
-
}
|
|
6342
|
-
return { added, removed, changed };
|
|
6343
|
-
}, [grouped]);
|
|
6344
|
-
const [expandedRuns, setExpandedRuns] = reactExports.useState(/* @__PURE__ */ new Set());
|
|
6345
|
-
const toggleRun = (idx) => {
|
|
6346
|
-
setExpandedRuns((prev) => {
|
|
6347
|
-
const next = new Set(prev);
|
|
6348
|
-
if (next.has(idx)) next.delete(idx);
|
|
6349
|
-
else next.add(idx);
|
|
6350
|
-
return next;
|
|
6351
|
-
});
|
|
6352
|
-
};
|
|
6353
|
-
const [expandedRows, setExpandedRows] = reactExports.useState(/* @__PURE__ */ new Set());
|
|
6354
|
-
const toggleRow = (idx) => {
|
|
6355
|
-
setExpandedRows((prev) => {
|
|
6356
|
-
const next = new Set(prev);
|
|
6357
|
-
if (next.has(idx)) next.delete(idx);
|
|
6358
|
-
else next.add(idx);
|
|
6359
|
-
return next;
|
|
6360
|
-
});
|
|
6361
|
-
};
|
|
6362
|
-
reactExports.useEffect(() => {
|
|
6363
|
-
setExpandedRows(/* @__PURE__ */ new Set());
|
|
6364
|
-
}, [left.id, right.id]);
|
|
6365
|
-
const [mode, setMode] = reactExports.useState("unified");
|
|
6366
|
-
const bodyRef = reactExports.useRef(null);
|
|
6367
|
-
const [copiedPath, setCopiedPath] = reactExports.useState(null);
|
|
6368
|
-
const copyResetTimer = reactExports.useRef(null);
|
|
6369
|
-
const onCopyPath = (path) => {
|
|
6370
|
-
void window.navigator.clipboard.writeText(path).then(() => {
|
|
6371
|
-
setCopiedPath(path);
|
|
6372
|
-
if (copyResetTimer.current !== null) clearTimeout(copyResetTimer.current);
|
|
6373
|
-
copyResetTimer.current = setTimeout(() => setCopiedPath(null), 1500);
|
|
6374
|
-
});
|
|
6375
|
-
};
|
|
6376
|
-
reactExports.useEffect(() => {
|
|
6377
|
-
return () => {
|
|
6378
|
-
if (copyResetTimer.current !== null) clearTimeout(copyResetTimer.current);
|
|
6379
|
-
};
|
|
6380
|
-
}, []);
|
|
6381
|
-
const jumpToKind = (kind) => {
|
|
6382
|
-
const idx = grouped.findIndex((g) => g.kind === "single" && g.op.kind === kind);
|
|
6383
|
-
if (idx === -1) return;
|
|
6384
|
-
const root = bodyRef.current;
|
|
6385
|
-
if (root === null) return;
|
|
6386
|
-
const el = root.querySelector(`[data-diff-idx="${idx}"]`);
|
|
6387
|
-
if (el !== null) {
|
|
6388
|
-
el.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
4974
|
+
function computeCacheTrends(groups) {
|
|
4975
|
+
const result = /* @__PURE__ */ new Map();
|
|
4976
|
+
for (const group of groups) {
|
|
4977
|
+
const logs = group.logs;
|
|
4978
|
+
for (let i = 1; i < logs.length; i++) {
|
|
4979
|
+
const prev = logs[i - 1];
|
|
4980
|
+
const curr = logs[i];
|
|
4981
|
+
if (prev === void 0 || curr === void 0) continue;
|
|
4982
|
+
result.set(curr.id, {
|
|
4983
|
+
creation: compareField(prev.cacheCreationInputTokens, curr.cacheCreationInputTokens),
|
|
4984
|
+
read: compareField(prev.cacheReadInputTokens, curr.cacheReadInputTokens)
|
|
4985
|
+
});
|
|
6389
4986
|
}
|
|
6390
|
-
}
|
|
4987
|
+
}
|
|
4988
|
+
return result;
|
|
4989
|
+
}
|
|
4990
|
+
function compareField(previous, current) {
|
|
4991
|
+
if (current === null) return null;
|
|
4992
|
+
if (previous === null) return null;
|
|
4993
|
+
if (current > previous) return { direction: "up", delta: current - previous };
|
|
4994
|
+
if (current < previous) return { direction: "down", delta: previous - current };
|
|
4995
|
+
return null;
|
|
4996
|
+
}
|
|
4997
|
+
const NAV_ATTR = "data-nav-id";
|
|
4998
|
+
const NAV_ACTION_ATTR = "data-nav-action";
|
|
4999
|
+
function findNavItems(container) {
|
|
5000
|
+
return Array.from(container.querySelectorAll(`[${NAV_ATTR}]`));
|
|
5001
|
+
}
|
|
5002
|
+
function isFocusTarget(node) {
|
|
5003
|
+
return node instanceof HTMLElement;
|
|
5004
|
+
}
|
|
5005
|
+
function findClosestNavItem(target, container) {
|
|
5006
|
+
let el = target;
|
|
5007
|
+
while (el !== null && el !== container) {
|
|
5008
|
+
if (el.hasAttribute(NAV_ATTR)) return el;
|
|
5009
|
+
el = el.parentElement;
|
|
5010
|
+
}
|
|
5011
|
+
if (target.hasAttribute(NAV_ATTR)) return target;
|
|
5012
|
+
return null;
|
|
5013
|
+
}
|
|
5014
|
+
function getAction(el) {
|
|
5015
|
+
const val = el.getAttribute(NAV_ACTION_ATTR);
|
|
5016
|
+
if (val === "toggle" || val === "expand" || val === "collapse") return val;
|
|
5017
|
+
return null;
|
|
5018
|
+
}
|
|
5019
|
+
function focusAndScroll(el) {
|
|
5020
|
+
el.focus({ preventScroll: true });
|
|
5021
|
+
el.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
5022
|
+
}
|
|
5023
|
+
function safeItemAt(items, index2) {
|
|
5024
|
+
const el = items[index2];
|
|
5025
|
+
return el ?? null;
|
|
5026
|
+
}
|
|
5027
|
+
function isEditableTarget(target) {
|
|
5028
|
+
const tag = target.tagName;
|
|
5029
|
+
if (tag === "INPUT" || tag === "TEXTAREA") return true;
|
|
5030
|
+
if (target.isContentEditable) return true;
|
|
5031
|
+
return false;
|
|
5032
|
+
}
|
|
5033
|
+
function useKeyboardNavigation(containerRef, wrapperRef) {
|
|
5034
|
+
const rootRef = wrapperRef ?? containerRef;
|
|
5035
|
+
const handleFocusContainer = reactExports.useCallback(
|
|
5036
|
+
(e) => {
|
|
5037
|
+
const container = containerRef.current;
|
|
5038
|
+
if (!container) return;
|
|
5039
|
+
const target = e.target;
|
|
5040
|
+
if (!isFocusTarget(target)) return;
|
|
5041
|
+
if (target !== rootRef.current) return;
|
|
5042
|
+
if (!container.contains(target)) return;
|
|
5043
|
+
const items = findNavItems(container);
|
|
5044
|
+
const first = safeItemAt(items, 0);
|
|
5045
|
+
if (first !== null) focusAndScroll(first);
|
|
5046
|
+
},
|
|
5047
|
+
[containerRef, rootRef]
|
|
5048
|
+
);
|
|
6391
5049
|
reactExports.useEffect(() => {
|
|
6392
|
-
const
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
"button",
|
|
6415
|
-
{
|
|
6416
|
-
type: "button",
|
|
6417
|
-
onClick: onClose,
|
|
6418
|
-
"aria-label": "Close compare drawer",
|
|
6419
|
-
className: "absolute inset-0 bg-black/40 cursor-default",
|
|
6420
|
-
tabIndex: -1
|
|
5050
|
+
const root = rootRef.current;
|
|
5051
|
+
const container = containerRef.current;
|
|
5052
|
+
if (!root || !container) return;
|
|
5053
|
+
const handleKeyDown = (e) => {
|
|
5054
|
+
const target = e.target;
|
|
5055
|
+
if (!isFocusTarget(target)) return;
|
|
5056
|
+
if (!container.contains(target)) return;
|
|
5057
|
+
if (isEditableTarget(target)) return;
|
|
5058
|
+
const items = findNavItems(container);
|
|
5059
|
+
if (items.length === 0) return;
|
|
5060
|
+
const current = findClosestNavItem(target, container);
|
|
5061
|
+
const currentIdx = current !== null ? items.indexOf(current) : -1;
|
|
5062
|
+
let handled = false;
|
|
5063
|
+
switch (e.key) {
|
|
5064
|
+
case "ArrowUp":
|
|
5065
|
+
case "W": {
|
|
5066
|
+
if (e.key === "W" && !e.shiftKey) break;
|
|
5067
|
+
e.preventDefault();
|
|
5068
|
+
const prevIdx = currentIdx > 0 ? currentIdx - 1 : currentIdx === -1 ? items.length - 1 : -1;
|
|
5069
|
+
if (prevIdx !== -1) {
|
|
5070
|
+
const prev = safeItemAt(items, prevIdx);
|
|
5071
|
+
if (prev !== null) focusAndScroll(prev);
|
|
6421
5072
|
}
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-4 px-4 py-3 border-b border-border", children: [
|
|
6434
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex gap-4 min-w-0", children: [
|
|
6435
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SideSummary, { log: left, side: "left" }),
|
|
6436
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SideSummary, { log: right, side: "right" })
|
|
6437
|
-
] }),
|
|
6438
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
6439
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(ModeToggle, { mode, onChange: setMode }),
|
|
6440
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6441
|
-
"button",
|
|
6442
|
-
{
|
|
6443
|
-
type: "button",
|
|
6444
|
-
onClick: onClose,
|
|
6445
|
-
"aria-label": "Close",
|
|
6446
|
-
className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted cursor-pointer",
|
|
6447
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "size-4" })
|
|
6448
|
-
}
|
|
6449
|
-
)
|
|
6450
|
-
] })
|
|
6451
|
-
] }),
|
|
6452
|
-
!sameSession && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-1.5 text-xs text-amber-400 bg-amber-500/10 border-b border-border", children: "Heads up: the two selected logs are from different sessions." }),
|
|
6453
|
-
allEqual ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 overflow-y-auto flex items-center justify-center text-muted-foreground text-sm", children: "The two Request payloads are identical." }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
6454
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SummaryChips, { counts, onJumpTo: jumpToKind }),
|
|
6455
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: bodyRef, className: "flex-1 min-h-0 overflow-y-auto", children: mode === "unified" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 py-2 space-y-0.5", children: grouped.map((g, i) => {
|
|
6456
|
-
if (g.kind === "equal-run") {
|
|
6457
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6458
|
-
EqualRunRow,
|
|
6459
|
-
{
|
|
6460
|
-
ops: g.ops,
|
|
6461
|
-
expanded: expandedRuns.has(i),
|
|
6462
|
-
onToggle: () => toggleRun(i)
|
|
6463
|
-
},
|
|
6464
|
-
`r${i}`
|
|
6465
|
-
);
|
|
6466
|
-
}
|
|
6467
|
-
const op = g.op;
|
|
6468
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6469
|
-
UnifiedOpRow,
|
|
6470
|
-
{
|
|
6471
|
-
op,
|
|
6472
|
-
idx: i,
|
|
6473
|
-
copiedPath,
|
|
6474
|
-
onCopyPath,
|
|
6475
|
-
expanded: expandedRows.has(i),
|
|
6476
|
-
onToggle: () => toggleRow(i)
|
|
6477
|
-
},
|
|
6478
|
-
`o${i}`
|
|
6479
|
-
);
|
|
6480
|
-
}) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(SplitBody, { grouped, left, right }) })
|
|
6481
|
-
] })
|
|
6482
|
-
]
|
|
5073
|
+
handled = true;
|
|
5074
|
+
break;
|
|
5075
|
+
}
|
|
5076
|
+
case "ArrowDown":
|
|
5077
|
+
case "S": {
|
|
5078
|
+
if (e.key === "S" && !e.shiftKey) break;
|
|
5079
|
+
e.preventDefault();
|
|
5080
|
+
const nextIdx = currentIdx < items.length - 1 ? currentIdx + 1 : currentIdx === -1 ? 0 : -1;
|
|
5081
|
+
if (nextIdx !== -1) {
|
|
5082
|
+
const next = safeItemAt(items, nextIdx);
|
|
5083
|
+
if (next !== null) focusAndScroll(next);
|
|
6483
5084
|
}
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
"
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
"div",
|
|
6526
|
-
{
|
|
6527
|
-
className: "col-span-3 grid grid-cols-[200px_1fr_1fr] gap-x-2 px-2 py-0.5 text-muted-foreground",
|
|
6528
|
-
children: [
|
|
6529
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-xs truncate", title: op.path, children: op.path }),
|
|
6530
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-xs break-all opacity-60", children: previewNode(op.value, 200) }),
|
|
6531
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-xs break-all opacity-60", children: previewNode(op.value, 200) })
|
|
6532
|
-
]
|
|
6533
|
-
},
|
|
6534
|
-
i
|
|
6535
|
-
);
|
|
6536
|
-
}
|
|
6537
|
-
if (op.kind === "added") {
|
|
6538
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
6539
|
-
"div",
|
|
6540
|
-
{
|
|
6541
|
-
className: "col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-emerald-400/70 bg-emerald-500/5",
|
|
6542
|
-
children: [
|
|
6543
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-mono text-xs text-muted-foreground mb-0.5", children: op.path }),
|
|
6544
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-mono break-all text-emerald-300/90", children: [
|
|
6545
|
-
"+ ",
|
|
6546
|
-
previewNode(op.value, 400)
|
|
6547
|
-
] })
|
|
6548
|
-
]
|
|
6549
|
-
},
|
|
6550
|
-
i
|
|
6551
|
-
);
|
|
5085
|
+
handled = true;
|
|
5086
|
+
break;
|
|
5087
|
+
}
|
|
5088
|
+
case "ArrowLeft":
|
|
5089
|
+
case "A": {
|
|
5090
|
+
if (e.key === "A" && !e.shiftKey) break;
|
|
5091
|
+
if (current === null) break;
|
|
5092
|
+
e.preventDefault();
|
|
5093
|
+
const action = getAction(current);
|
|
5094
|
+
if (action === "collapse") {
|
|
5095
|
+
current.click();
|
|
5096
|
+
} else if (currentIdx > 0) {
|
|
5097
|
+
const prev = safeItemAt(items, currentIdx - 1);
|
|
5098
|
+
if (prev !== null) focusAndScroll(prev);
|
|
5099
|
+
}
|
|
5100
|
+
handled = true;
|
|
5101
|
+
break;
|
|
5102
|
+
}
|
|
5103
|
+
case "ArrowRight":
|
|
5104
|
+
case "D": {
|
|
5105
|
+
if (e.key === "D" && !e.shiftKey) break;
|
|
5106
|
+
if (current === null) break;
|
|
5107
|
+
e.preventDefault();
|
|
5108
|
+
const action = getAction(current);
|
|
5109
|
+
if (action === "expand") {
|
|
5110
|
+
current.click();
|
|
5111
|
+
} else if (currentIdx < items.length - 1) {
|
|
5112
|
+
const next = safeItemAt(items, currentIdx + 1);
|
|
5113
|
+
if (next !== null) focusAndScroll(next);
|
|
5114
|
+
}
|
|
5115
|
+
handled = true;
|
|
5116
|
+
break;
|
|
5117
|
+
}
|
|
5118
|
+
case " ": {
|
|
5119
|
+
if (current === null) break;
|
|
5120
|
+
e.preventDefault();
|
|
5121
|
+
const action = getAction(current);
|
|
5122
|
+
if (action !== null) current.click();
|
|
5123
|
+
handled = true;
|
|
5124
|
+
break;
|
|
5125
|
+
}
|
|
6552
5126
|
}
|
|
6553
|
-
if (
|
|
6554
|
-
|
|
6555
|
-
"div",
|
|
6556
|
-
{
|
|
6557
|
-
className: "col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-rose-400/70 bg-rose-500/5",
|
|
6558
|
-
children: [
|
|
6559
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-mono text-xs text-muted-foreground mb-0.5", children: op.path }),
|
|
6560
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-mono break-all text-rose-300/90 line-through", children: [
|
|
6561
|
-
"− ",
|
|
6562
|
-
previewNode(op.value, 400)
|
|
6563
|
-
] })
|
|
6564
|
-
]
|
|
6565
|
-
},
|
|
6566
|
-
i
|
|
6567
|
-
);
|
|
5127
|
+
if (handled) {
|
|
5128
|
+
e.stopPropagation();
|
|
6568
5129
|
}
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
]
|
|
6580
|
-
},
|
|
6581
|
-
i
|
|
6582
|
-
);
|
|
6583
|
-
})
|
|
6584
|
-
] });
|
|
5130
|
+
};
|
|
5131
|
+
document.addEventListener("keydown", handleKeyDown, { capture: true });
|
|
5132
|
+
return () => document.removeEventListener("keydown", handleKeyDown, { capture: true });
|
|
5133
|
+
}, [containerRef, rootRef]);
|
|
5134
|
+
reactExports.useEffect(() => {
|
|
5135
|
+
const root = rootRef.current;
|
|
5136
|
+
if (!root) return;
|
|
5137
|
+
root.addEventListener("focus", handleFocusContainer);
|
|
5138
|
+
return () => root.removeEventListener("focus", handleFocusContainer);
|
|
5139
|
+
}, [handleFocusContainer, rootRef]);
|
|
6585
5140
|
}
|
|
6586
5141
|
function truncateSessionId(id) {
|
|
6587
5142
|
if (id.length <= 30) return id;
|
|
@@ -6667,6 +5222,9 @@ function ProxyViewer({
|
|
|
6667
5222
|
const [crabEntrancePhase, setCrabEntrancePhase] = reactExports.useState(
|
|
6668
5223
|
"hidden"
|
|
6669
5224
|
);
|
|
5225
|
+
const logListRef = reactExports.useRef(null);
|
|
5226
|
+
const logListWrapperRef = reactExports.useRef(null);
|
|
5227
|
+
useKeyboardNavigation(logListRef, logListWrapperRef);
|
|
6670
5228
|
reactExports.useEffect(() => {
|
|
6671
5229
|
const perCrabDuration = 400;
|
|
6672
5230
|
const startDelay = 50;
|
|
@@ -6702,8 +5260,8 @@ function ProxyViewer({
|
|
|
6702
5260
|
},
|
|
6703
5261
|
[comparisonPredecessors]
|
|
6704
5262
|
);
|
|
6705
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-[
|
|
6706
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end
|
|
5263
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-[1400px] xl:max-w-[1600px] 2xl:max-w-[1800px] mx-auto px-6 pb-6", children: [
|
|
5264
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end pt-6 pb-8 relative", children: [
|
|
6707
5265
|
/* @__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: [
|
|
6708
5266
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-end gap-1 group cursor-default", "aria-hidden": "true", children: [
|
|
6709
5267
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-10 text-amber-500 transition-all duration-300 group-hover:scale-125 group-hover:-translate-y-1.5" }),
|
|
@@ -6746,7 +5304,7 @@ function ProxyViewer({
|
|
|
6746
5304
|
] }),
|
|
6747
5305
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ml-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {}) })
|
|
6748
5306
|
] }),
|
|
6749
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3
|
|
5307
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
6750
5308
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: selectedSession, onValueChange: onSessionChange, children: [
|
|
6751
5309
|
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "flex-1 max-w-[350px] text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "All sessions" }) }),
|
|
6752
5310
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
|
|
@@ -6767,7 +5325,7 @@ function ProxyViewer({
|
|
|
6767
5325
|
{
|
|
6768
5326
|
type: "button",
|
|
6769
5327
|
onClick: () => onViewModeChange("simple"),
|
|
6770
|
-
className: `
|
|
5328
|
+
className: `h-8 px-3 cursor-pointer transition-colors text-xs ${viewMode === "simple" ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
|
|
6771
5329
|
children: "Simple"
|
|
6772
5330
|
}
|
|
6773
5331
|
),
|
|
@@ -6776,7 +5334,7 @@ function ProxyViewer({
|
|
|
6776
5334
|
{
|
|
6777
5335
|
type: "button",
|
|
6778
5336
|
onClick: () => onViewModeChange("full"),
|
|
6779
|
-
className: `
|
|
5337
|
+
className: `h-8 px-3 cursor-pointer transition-colors text-xs ${viewMode === "full" ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
|
|
6780
5338
|
children: "Full"
|
|
6781
5339
|
}
|
|
6782
5340
|
)
|
|
@@ -6796,10 +5354,10 @@ function ProxyViewer({
|
|
|
6796
5354
|
void handleExport();
|
|
6797
5355
|
},
|
|
6798
5356
|
disabled: exporting,
|
|
6799
|
-
className: "text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center gap-1",
|
|
5357
|
+
className: "h-8 px-3 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center gap-1.5 rounded-md hover:bg-muted",
|
|
6800
5358
|
title: "Export all logs as JSON ZIP",
|
|
6801
5359
|
children: exporting ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Exporting..." }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
6802
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "size-3" }),
|
|
5360
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "size-3.5" }),
|
|
6803
5361
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Export" })
|
|
6804
5362
|
] })
|
|
6805
5363
|
}
|
|
@@ -6809,31 +5367,39 @@ function ProxyViewer({
|
|
|
6809
5367
|
{
|
|
6810
5368
|
type: "button",
|
|
6811
5369
|
onClick: onClearAll,
|
|
6812
|
-
className: "text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer",
|
|
5370
|
+
className: "h-8 px-3 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer rounded-md hover:bg-muted",
|
|
6813
5371
|
title: "Clear all logs",
|
|
6814
5372
|
children: "Clear"
|
|
6815
5373
|
}
|
|
6816
5374
|
)
|
|
6817
5375
|
] }),
|
|
6818
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", {
|
|
5376
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: logs.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-muted-foreground py-16 space-y-4", children: [
|
|
6819
5377
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm", children: "No requests captured yet." }),
|
|
6820
5378
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs", children: "Route AI coding tools through the proxy:" }),
|
|
6821
5379
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CopyableCommand, { command: "LLM_BASE_URL=http://localhost:25947/proxy <your-tool>" })
|
|
6822
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6823
|
-
|
|
5380
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5381
|
+
"div",
|
|
6824
5382
|
{
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
5383
|
+
ref: logListWrapperRef,
|
|
5384
|
+
tabIndex: 0,
|
|
5385
|
+
className: "flex flex-col gap-2 focus:outline-none",
|
|
5386
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: logListRef, children: groups.map((group) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5387
|
+
ConversationGroup,
|
|
5388
|
+
{
|
|
5389
|
+
group,
|
|
5390
|
+
viewMode,
|
|
5391
|
+
strip,
|
|
5392
|
+
cacheTrends,
|
|
5393
|
+
onCompareWithPrevious: handleCompareWithPrevious,
|
|
5394
|
+
comparisonPredecessors,
|
|
5395
|
+
onClearGroup,
|
|
5396
|
+
standalone: groups.length === 1
|
|
5397
|
+
},
|
|
5398
|
+
group.id
|
|
5399
|
+
)) })
|
|
5400
|
+
}
|
|
5401
|
+
) }),
|
|
5402
|
+
comparePair !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntimeExports.jsx(LazyCompareDrawer, { left: comparePair[0], right: comparePair[1], onClose: closeCompare }) })
|
|
6837
5403
|
] });
|
|
6838
5404
|
}
|
|
6839
5405
|
const SSEUpdateSchema = union([
|
|
@@ -6871,8 +5437,6 @@ function filterLogs(logs, selectedSession, selectedModel) {
|
|
|
6871
5437
|
const DEBOUNCE_MS = 50;
|
|
6872
5438
|
function ProxyViewerContainer() {
|
|
6873
5439
|
const [allLogs, setAllLogs] = reactExports.useState([]);
|
|
6874
|
-
const [sessions, setSessions] = reactExports.useState([]);
|
|
6875
|
-
const [models, setModels] = reactExports.useState([]);
|
|
6876
5440
|
const [selectedSession, setSelectedSession] = reactExports.useState("__all__");
|
|
6877
5441
|
const [selectedModel, setSelectedModel] = reactExports.useState("__all__");
|
|
6878
5442
|
const [viewMode, setViewMode] = reactExports.useState("simple");
|
|
@@ -6880,13 +5444,14 @@ function ProxyViewerContainer() {
|
|
|
6880
5444
|
const eventSourceRef = reactExports.useRef(null);
|
|
6881
5445
|
const reconnectTimeoutRef = reactExports.useRef(null);
|
|
6882
5446
|
const logIndexRef = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
6883
|
-
const logsRef = reactExports.useRef([]);
|
|
6884
5447
|
const pendingUpdatesRef = reactExports.useRef([]);
|
|
6885
5448
|
const flushTimerRef = reactExports.useRef(null);
|
|
6886
5449
|
const logs = reactExports.useMemo(
|
|
6887
5450
|
() => filterLogs(allLogs, selectedSession, selectedModel),
|
|
6888
5451
|
[allLogs, selectedSession, selectedModel]
|
|
6889
5452
|
);
|
|
5453
|
+
const sessions = reactExports.useMemo(() => extractSessions(allLogs), [allLogs]);
|
|
5454
|
+
const models = reactExports.useMemo(() => extractModels(allLogs), [allLogs]);
|
|
6890
5455
|
const flushUpdates = reactExports.useCallback(() => {
|
|
6891
5456
|
flushTimerRef.current = null;
|
|
6892
5457
|
const updates = pendingUpdatesRef.current;
|
|
@@ -6894,8 +5459,6 @@ function ProxyViewerContainer() {
|
|
|
6894
5459
|
if (updates.length === 0) return;
|
|
6895
5460
|
setAllLogs((prev) => {
|
|
6896
5461
|
let next = prev;
|
|
6897
|
-
let sessionsChanged = false;
|
|
6898
|
-
let modelsChanged = false;
|
|
6899
5462
|
for (const log of updates) {
|
|
6900
5463
|
const idx = logIndexRef.current.get(log.id);
|
|
6901
5464
|
if (idx !== void 0) {
|
|
@@ -6904,19 +5467,10 @@ function ProxyViewerContainer() {
|
|
|
6904
5467
|
logIndexRef.current.set(log.id, next.length);
|
|
6905
5468
|
next = [...next, log];
|
|
6906
5469
|
}
|
|
6907
|
-
if (log.sessionId !== null && log.sessionId !== "" && !sessions.includes(log.sessionId)) {
|
|
6908
|
-
sessionsChanged = true;
|
|
6909
|
-
}
|
|
6910
|
-
if (log.model !== null && log.model !== "" && !models.includes(log.model)) {
|
|
6911
|
-
modelsChanged = true;
|
|
6912
|
-
}
|
|
6913
5470
|
}
|
|
6914
|
-
logsRef.current = next;
|
|
6915
|
-
if (sessionsChanged) setSessions((s) => extractSessions(next));
|
|
6916
|
-
if (modelsChanged) setModels((m) => extractModels(next));
|
|
6917
5471
|
return next;
|
|
6918
5472
|
});
|
|
6919
|
-
}, [
|
|
5473
|
+
}, []);
|
|
6920
5474
|
const scheduleUpdate = reactExports.useCallback(
|
|
6921
5475
|
(log) => {
|
|
6922
5476
|
pendingUpdatesRef.current.push(log);
|
|
@@ -6954,10 +5508,7 @@ function ProxyViewerContainer() {
|
|
|
6954
5508
|
if (log !== void 0) idx.set(log.id, i);
|
|
6955
5509
|
}
|
|
6956
5510
|
logIndexRef.current = idx;
|
|
6957
|
-
logsRef.current = update.logs;
|
|
6958
5511
|
setAllLogs(update.logs);
|
|
6959
|
-
setSessions(extractSessions(update.logs));
|
|
6960
|
-
setModels(extractModels(update.logs));
|
|
6961
5512
|
setError(null);
|
|
6962
5513
|
} else if (update.type === "update") {
|
|
6963
5514
|
scheduleUpdate(update.log);
|
|
@@ -7001,10 +5552,7 @@ function ProxyViewerContainer() {
|
|
|
7001
5552
|
return;
|
|
7002
5553
|
}
|
|
7003
5554
|
logIndexRef.current.clear();
|
|
7004
|
-
logsRef.current = [];
|
|
7005
5555
|
setAllLogs([]);
|
|
7006
|
-
setSessions([]);
|
|
7007
|
-
setModels([]);
|
|
7008
5556
|
setError(null);
|
|
7009
5557
|
} catch (err) {
|
|
7010
5558
|
setError(err instanceof Error ? err.message : "Unknown error clearing logs");
|
|
@@ -7033,9 +5581,6 @@ function ProxyViewerContainer() {
|
|
|
7033
5581
|
if (log !== void 0) idx.set(log.id, i);
|
|
7034
5582
|
}
|
|
7035
5583
|
logIndexRef.current = idx;
|
|
7036
|
-
logsRef.current = remaining;
|
|
7037
|
-
setSessions(extractSessions(remaining));
|
|
7038
|
-
setModels(extractModels(remaining));
|
|
7039
5584
|
return remaining;
|
|
7040
5585
|
});
|
|
7041
5586
|
setError(null);
|
|
@@ -7068,6 +5613,32 @@ function ProxyViewerContainer() {
|
|
|
7068
5613
|
] });
|
|
7069
5614
|
}
|
|
7070
5615
|
const SplitComponent = ProxyViewerContainer;
|
|
5616
|
+
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
5617
|
+
__proto__: null,
|
|
5618
|
+
component: SplitComponent
|
|
5619
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
7071
5620
|
export {
|
|
7072
|
-
|
|
5621
|
+
Badge as B,
|
|
5622
|
+
Dialog as D,
|
|
5623
|
+
Tabs as T,
|
|
5624
|
+
getConversationId as a,
|
|
5625
|
+
DialogContent as b,
|
|
5626
|
+
cn as c,
|
|
5627
|
+
DialogHeader as d,
|
|
5628
|
+
DialogTitle as e,
|
|
5629
|
+
formatTokens as f,
|
|
5630
|
+
getLogFormatAdapter as g,
|
|
5631
|
+
TabsList as h,
|
|
5632
|
+
TabsTrigger as i,
|
|
5633
|
+
TabsContent as j,
|
|
5634
|
+
TooltipProvider as k,
|
|
5635
|
+
Tooltip as l,
|
|
5636
|
+
TooltipTrigger as m,
|
|
5637
|
+
TooltipContent as n,
|
|
5638
|
+
Button as o,
|
|
5639
|
+
getStatusCategory as p,
|
|
5640
|
+
parseJsonText as q,
|
|
5641
|
+
resolveLogFormat as r,
|
|
5642
|
+
safeJsonValue as s,
|
|
5643
|
+
index as t
|
|
7073
5644
|
};
|