@tonyclaw/llm-inspector 1.14.7 → 1.14.9
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/index-Dv-dj1xH.js +105 -0
- package/.output/public/assets/index-bqeypwJB.css +1 -0
- package/.output/public/assets/{main-BV7uNIIz.js → main-C8OUJKbz.js} +1 -1
- package/.output/server/_libs/lucide-react.mjs +87 -79
- package/.output/server/_libs/radix-ui__react-id.mjs +1 -1
- package/.output/server/_ssr/{index-BvHLASu8.mjs → index-_9xcAkkw.mjs} +861 -608
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-lUOA8pi6.mjs → router-CmanwZJc.mjs} +45 -14
- package/.output/server/{_tanstack-start-manifest_v-XNH7fVPN.mjs → _tanstack-start-manifest_v-BVIiyDeJ.mjs} +1 -1
- package/.output/server/index.mjs +23 -23
- package/package.json +1 -1
- package/src/components/ProxyViewer.tsx +137 -146
- package/src/components/providers/ProviderCard.tsx +79 -26
- package/src/components/providers/ProviderForm.tsx +37 -22
- package/src/components/providers/ProvidersPanel.tsx +79 -47
- package/src/components/providers/SettingsDialog.tsx +25 -15
- package/src/components/proxy-viewer/ConversationGroup.tsx +74 -11
- package/src/components/proxy-viewer/ConversationHeader.tsx +63 -2
- package/src/components/proxy-viewer/LogEntry.tsx +184 -54
- package/src/components/proxy-viewer/LogEntryHeader.tsx +148 -143
- package/src/components/proxy-viewer/ReplayDialog.tsx +16 -6
- package/src/components/proxy-viewer/StreamingChunkSequence.tsx +24 -16
- package/src/components/proxy-viewer/ThreadConnector.tsx +93 -0
- package/src/components/proxy-viewer/index.ts +2 -1
- package/src/lib/stopReason.ts +57 -0
- package/src/proxy/formats/anthropic/handler.ts +2 -5
- package/src/proxy/formats/openai/handler.ts +33 -7
- package/src/proxy/formats/openai/schemas.ts +1 -0
- package/src/proxy/formats/openai/stream.ts +24 -0
- package/src/proxy/handler.ts +8 -2
- package/src/proxy/schemas.ts +6 -3
- package/.output/public/assets/index-Cmi8TfeU.js +0 -105
- package/.output/public/assets/index-DXUNTCVh.css +0 -1
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
|
|
2
|
-
import { C as CapturedLogSchema, a as parseRequest, s as stripClaudeCodeBillingHeader, R as RuntimeConfigSchema, c as createPendingProviderTestResults, P as ProviderTestResultsSchema, b as createFailedProviderTestResults, d as ProviderConfigSchema
|
|
2
|
+
import { C as CapturedLogSchema, a as parseRequest, O as OpenAIRequestSchema, p as parseOpenAIResponse, I as InspectorResponseSchema, s as stripClaudeCodeBillingHeader, R as RuntimeConfigSchema, c as createPendingProviderTestResults, P as ProviderTestResultsSchema, b as createFailedProviderTestResults, d as ProviderConfigSchema } from "./router-CmanwZJc.mjs";
|
|
3
3
|
import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
|
|
4
4
|
import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
|
|
5
|
-
import { J as JSZip } from "../_libs/jszip.mjs";
|
|
6
5
|
import { c as clsx } from "../_libs/clsx.mjs";
|
|
7
6
|
import { t as twMerge } from "../_libs/tailwind-merge.mjs";
|
|
7
|
+
import { J as JSZip } from "../_libs/jszip.mjs";
|
|
8
8
|
import { c as cva } from "../_libs/class-variance-authority.mjs";
|
|
9
9
|
import { d as diffLines, a as diffJson } from "../_libs/diff.mjs";
|
|
10
|
-
import { R as Root, T as Trigger$
|
|
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";
|
|
10
|
+
import { R as Root, T as Trigger$2, C as Content, a as Close, b as Title, P as Portal$2, O as Overlay } from "../_libs/radix-ui__react-dialog.mjs";
|
|
11
|
+
import { R as Root2, T as Trigger$1, I as Icon, V as Value, P as Portal$1, C as Content2$1, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
|
|
12
12
|
import "../_libs/modelcontextprotocol__server.mjs";
|
|
13
|
-
import { D as Download, L as LayoutGrid, a as List, G as
|
|
13
|
+
import { D as Download, L as LayoutGrid, a as List, G as GitBranch, S as Settings, C as ChevronDown, b as Check, c as GitCompareArrows, R as RotateCcw, X, U as Upload, d as Scan, P as Plus, e as Copy, f as CircleAlert, g as ChevronUp, h as LoaderCircle, i as ChevronRight, j as User, k as Clock, M as MessageSquare, Z as Zap, W as Wrench, l as Globe, F as FileTerminal, m as Radio, n as Rows3, o as Columns2, p as Minus, q as Pencil, E as Equal, r as EyeOff, s as Eye, t as ExternalLink, u as RotateCw, T as Trash2, A as ArrowUp, v as ArrowDown, w as TriangleAlert, x as CircleCheckBig, y as CircleStop, z as CircleQuestionMark, B as Server, H as Gauge, I as Lock, J as Wifi, K as WifiOff, N as ChevronsUp, O as ChevronsDown, Q as Brain, V as Terminal } from "../_libs/lucide-react.mjs";
|
|
14
14
|
import { M as Markdown } from "../_libs/react-markdown.mjs";
|
|
15
15
|
import { a as array, b as string, u as union, d as object, l as literal, n as number, c as boolean, _ as _enum } from "../_libs/zod.mjs";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
16
|
+
import { P as Provider, R as Root3, T as Trigger, a as Portal, C as Content2, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
|
|
17
|
+
import { R as Root2$1, L as List$1, T as Trigger$3, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
|
|
18
18
|
import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
|
|
19
19
|
import { R as Root$1 } from "../_libs/radix-ui__react-separator.mjs";
|
|
20
20
|
import { R as Root$2, C as CollapsibleTrigger$1, a as CollapsibleContent$1 } from "../_libs/radix-ui__react-collapsible.mjs";
|
|
@@ -237,6 +237,63 @@ function useStripConfig() {
|
|
|
237
237
|
setStrip
|
|
238
238
|
};
|
|
239
239
|
}
|
|
240
|
+
function cn(...inputs) {
|
|
241
|
+
return twMerge(clsx(inputs));
|
|
242
|
+
}
|
|
243
|
+
function formatTokens(count) {
|
|
244
|
+
if (count >= 1048576) return (count / 1048576).toFixed(1).replace(/\.0$/, "") + "M";
|
|
245
|
+
if (count >= 1024) return (count / 1024).toFixed(1).replace(/\.0$/, "") + "K";
|
|
246
|
+
return count.toString();
|
|
247
|
+
}
|
|
248
|
+
function getStatusCategory(status) {
|
|
249
|
+
if (status === null) return "pending";
|
|
250
|
+
if (status >= 200 && status < 300) return "success";
|
|
251
|
+
if (status >= 400 && status < 500) return "client_error";
|
|
252
|
+
if (status >= 500) return "server_error";
|
|
253
|
+
return "pending";
|
|
254
|
+
}
|
|
255
|
+
function TooltipProvider({
|
|
256
|
+
delayDuration = 0,
|
|
257
|
+
...props
|
|
258
|
+
}) {
|
|
259
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
260
|
+
Provider,
|
|
261
|
+
{
|
|
262
|
+
"data-slot": "tooltip-provider",
|
|
263
|
+
delayDuration,
|
|
264
|
+
...props
|
|
265
|
+
}
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
function Tooltip({ ...props }) {
|
|
269
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Root3, { "data-slot": "tooltip", ...props });
|
|
270
|
+
}
|
|
271
|
+
function TooltipTrigger({ ...props }) {
|
|
272
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
273
|
+
}
|
|
274
|
+
function TooltipContent({
|
|
275
|
+
className,
|
|
276
|
+
sideOffset = 0,
|
|
277
|
+
children,
|
|
278
|
+
...props
|
|
279
|
+
}) {
|
|
280
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
281
|
+
Content2,
|
|
282
|
+
{
|
|
283
|
+
"data-slot": "tooltip-content",
|
|
284
|
+
sideOffset,
|
|
285
|
+
className: cn(
|
|
286
|
+
"bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
287
|
+
className
|
|
288
|
+
),
|
|
289
|
+
...props,
|
|
290
|
+
children: [
|
|
291
|
+
children,
|
|
292
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Arrow2, { className: "bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
|
|
293
|
+
]
|
|
294
|
+
}
|
|
295
|
+
) });
|
|
296
|
+
}
|
|
240
297
|
async function fetchStreamingChunks(logId) {
|
|
241
298
|
try {
|
|
242
299
|
const response = await fetch(`/api/logs/${logId}/chunks`);
|
|
@@ -276,24 +333,34 @@ async function exportLogsAsZip(logs) {
|
|
|
276
333
|
document.body.removeChild(anchor);
|
|
277
334
|
URL.revokeObjectURL(url);
|
|
278
335
|
}
|
|
279
|
-
const version = "1.14.
|
|
336
|
+
const version = "1.14.9";
|
|
280
337
|
const packageJson = {
|
|
281
338
|
version
|
|
282
339
|
};
|
|
283
|
-
function
|
|
284
|
-
return
|
|
285
|
-
}
|
|
286
|
-
function formatTokens(count) {
|
|
287
|
-
if (count >= 1048576) return (count / 1048576).toFixed(1).replace(/\.0$/, "") + "M";
|
|
288
|
-
if (count >= 1024) return (count / 1024).toFixed(1).replace(/\.0$/, "") + "K";
|
|
289
|
-
return count.toString();
|
|
340
|
+
function isRecord(value) {
|
|
341
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
290
342
|
}
|
|
291
|
-
function
|
|
292
|
-
if (
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
343
|
+
function extractStopReason(log) {
|
|
344
|
+
if (log.responseText === null) return null;
|
|
345
|
+
try {
|
|
346
|
+
let json = JSON.parse(log.responseText);
|
|
347
|
+
if (typeof json === "string") {
|
|
348
|
+
json = JSON.parse(json);
|
|
349
|
+
}
|
|
350
|
+
if (!isRecord(json)) return null;
|
|
351
|
+
if (log.apiFormat === "anthropic" && typeof json.stop_reason === "string") {
|
|
352
|
+
if (json.stop_reason === "end_turn" || json.stop_reason === "tool_use") {
|
|
353
|
+
return json.stop_reason;
|
|
354
|
+
}
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
if (log.apiFormat === "openai" && 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") {
|
|
358
|
+
return "stop";
|
|
359
|
+
}
|
|
360
|
+
return null;
|
|
361
|
+
} catch {
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
297
364
|
}
|
|
298
365
|
const badgeVariants = cva(
|
|
299
366
|
"inline-flex items-center justify-center rounded-full border border-transparent px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
|
@@ -349,7 +416,11 @@ function ConversationHeader({
|
|
|
349
416
|
apiFormat,
|
|
350
417
|
expanded,
|
|
351
418
|
onToggle,
|
|
352
|
-
hideApiFormat = false
|
|
419
|
+
hideApiFormat = false,
|
|
420
|
+
isLoading = false,
|
|
421
|
+
viewMode,
|
|
422
|
+
onToggleViewMode,
|
|
423
|
+
userAgent
|
|
353
424
|
}) {
|
|
354
425
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
355
426
|
"div",
|
|
@@ -370,7 +441,23 @@ function ConversationHeader({
|
|
|
370
441
|
}
|
|
371
442
|
},
|
|
372
443
|
children: [
|
|
373
|
-
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" }),
|
|
444
|
+
expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 text-muted-foreground shrink-0" }) : isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin text-muted-foreground shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 text-muted-foreground shrink-0" }),
|
|
445
|
+
expanded && onToggleViewMode !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
446
|
+
"button",
|
|
447
|
+
{
|
|
448
|
+
type: "button",
|
|
449
|
+
onClick: (e) => {
|
|
450
|
+
e.stopPropagation();
|
|
451
|
+
onToggleViewMode();
|
|
452
|
+
},
|
|
453
|
+
className: cn(
|
|
454
|
+
"px-1.5 py-0.5 rounded text-[10px] font-mono transition-colors shrink-0 cursor-pointer",
|
|
455
|
+
viewMode === "thread" ? "bg-amber-500/15 text-amber-400 border border-amber-500/30" : "bg-muted text-muted-foreground border border-border hover:text-foreground"
|
|
456
|
+
),
|
|
457
|
+
title: viewMode === "thread" ? "Thread view — click for flat view" : "Flat view — click for thread view",
|
|
458
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { className: "size-3" })
|
|
459
|
+
}
|
|
460
|
+
),
|
|
374
461
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
375
462
|
"span",
|
|
376
463
|
{
|
|
@@ -379,6 +466,17 @@ function ConversationHeader({
|
|
|
379
466
|
children: conversationId.length > 24 ? conversationId.slice(0, 12) + "…" + conversationId.slice(-12) : conversationId
|
|
380
467
|
}
|
|
381
468
|
),
|
|
469
|
+
userAgent !== null && userAgent !== void 0 && userAgent !== "" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
470
|
+
"span",
|
|
471
|
+
{
|
|
472
|
+
className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0",
|
|
473
|
+
title: userAgent,
|
|
474
|
+
children: [
|
|
475
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(User, { className: "size-3" }),
|
|
476
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[120px]", children: userAgent })
|
|
477
|
+
]
|
|
478
|
+
}
|
|
479
|
+
),
|
|
382
480
|
!hideApiFormat && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
383
481
|
Badge,
|
|
384
482
|
{
|
|
@@ -509,48 +607,6 @@ function Button({
|
|
|
509
607
|
}
|
|
510
608
|
);
|
|
511
609
|
}
|
|
512
|
-
function TooltipProvider({
|
|
513
|
-
delayDuration = 0,
|
|
514
|
-
...props
|
|
515
|
-
}) {
|
|
516
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
517
|
-
Provider,
|
|
518
|
-
{
|
|
519
|
-
"data-slot": "tooltip-provider",
|
|
520
|
-
delayDuration,
|
|
521
|
-
...props
|
|
522
|
-
}
|
|
523
|
-
);
|
|
524
|
-
}
|
|
525
|
-
function Tooltip({ ...props }) {
|
|
526
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Root3, { "data-slot": "tooltip", ...props });
|
|
527
|
-
}
|
|
528
|
-
function TooltipTrigger({ ...props }) {
|
|
529
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger$3, { "data-slot": "tooltip-trigger", ...props });
|
|
530
|
-
}
|
|
531
|
-
function TooltipContent({
|
|
532
|
-
className,
|
|
533
|
-
sideOffset = 0,
|
|
534
|
-
children,
|
|
535
|
-
...props
|
|
536
|
-
}) {
|
|
537
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$2, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
538
|
-
Content2$1,
|
|
539
|
-
{
|
|
540
|
-
"data-slot": "tooltip-content",
|
|
541
|
-
sideOffset,
|
|
542
|
-
className: cn(
|
|
543
|
-
"bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
544
|
-
className
|
|
545
|
-
),
|
|
546
|
-
...props,
|
|
547
|
-
children: [
|
|
548
|
-
children,
|
|
549
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Arrow2, { className: "bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
|
|
550
|
-
]
|
|
551
|
-
}
|
|
552
|
-
) });
|
|
553
|
-
}
|
|
554
610
|
function classifyValue(value) {
|
|
555
611
|
if (value === null) return "null";
|
|
556
612
|
if (Array.isArray(value)) return "array";
|
|
@@ -953,7 +1009,7 @@ function TabsTrigger({
|
|
|
953
1009
|
...props
|
|
954
1010
|
}) {
|
|
955
1011
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
956
|
-
Trigger$
|
|
1012
|
+
Trigger$3,
|
|
957
1013
|
{
|
|
958
1014
|
"data-slot": "tabs-trigger",
|
|
959
1015
|
className: cn(
|
|
@@ -1411,18 +1467,15 @@ function CacheTrendIndicator({ trend }) {
|
|
|
1411
1467
|
}
|
|
1412
1468
|
const LogEntryHeader = reactExports.memo(function({
|
|
1413
1469
|
log,
|
|
1414
|
-
|
|
1470
|
+
messageCount = null,
|
|
1471
|
+
toolCount = null,
|
|
1415
1472
|
expanded,
|
|
1416
1473
|
onToggle,
|
|
1417
|
-
|
|
1418
|
-
cacheTrend = null
|
|
1419
|
-
isSelected = false,
|
|
1420
|
-
onToggleSelect
|
|
1474
|
+
responseToolNames = null,
|
|
1475
|
+
cacheTrend = null
|
|
1421
1476
|
}) {
|
|
1422
1477
|
const statusCategory = getStatusCategory(log.responseStatus);
|
|
1423
1478
|
const hasTokens = log.inputTokens !== null || log.outputTokens !== null;
|
|
1424
|
-
const messageCount = parsedRequest !== null ? parsedRequest.messages.length : null;
|
|
1425
|
-
const toolCount = parsedRequest !== null && parsedRequest.tools !== void 0 && parsedRequest.tools.length > 0 ? parsedRequest.tools.length : null;
|
|
1426
1479
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1427
1480
|
"div",
|
|
1428
1481
|
{
|
|
@@ -1441,45 +1494,22 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1441
1494
|
}
|
|
1442
1495
|
},
|
|
1443
1496
|
children: [
|
|
1444
|
-
onToggleSelect !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1445
|
-
"button",
|
|
1446
|
-
{
|
|
1447
|
-
type: "button",
|
|
1448
|
-
onClick: (e) => {
|
|
1449
|
-
e.stopPropagation();
|
|
1450
|
-
onToggleSelect(log.id);
|
|
1451
|
-
},
|
|
1452
|
-
"aria-label": isSelected ? "Deselect for comparison" : "Select for comparison",
|
|
1453
|
-
"aria-pressed": isSelected,
|
|
1454
|
-
className: cn(
|
|
1455
|
-
"shrink-0 size-4 rounded-sm border flex items-center justify-center transition-colors cursor-pointer",
|
|
1456
|
-
isSelected ? "bg-amber-400 border-amber-400 text-amber-950" : "border-muted-foreground/40 hover:border-amber-400 hover:bg-amber-400/10"
|
|
1457
|
-
),
|
|
1458
|
-
children: isSelected && /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3", strokeWidth: 3 })
|
|
1459
|
-
}
|
|
1460
|
-
),
|
|
1461
1497
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-400/80 font-mono text-xs font-semibold tabular-nums shrink-0", children: [
|
|
1462
1498
|
"#",
|
|
1463
1499
|
log.id
|
|
1464
1500
|
] }),
|
|
1465
|
-
log.model !== null && /* @__PURE__ */ jsxRuntimeExports.
|
|
1466
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(ProviderLogo, { provider: detectProvider(log.model), className: "size-4
|
|
1467
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1468
|
-
] }),
|
|
1469
|
-
|
|
1501
|
+
log.model !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1502
|
+
/* @__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" }) }) }),
|
|
1503
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: log.model })
|
|
1504
|
+
] }) }),
|
|
1505
|
+
statusCategory !== "success" && /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: statusCategory === "server_error" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1470
1506
|
Badge,
|
|
1471
1507
|
{
|
|
1472
|
-
variant: "
|
|
1473
|
-
className:
|
|
1474
|
-
|
|
1475
|
-
log.apiFormat === "openai" && "border-blue-500/40 text-blue-400",
|
|
1476
|
-
log.apiFormat === "anthropic" && "border-orange-500/40 text-orange-400",
|
|
1477
|
-
log.apiFormat === "unknown" && "border-muted text-muted-foreground"
|
|
1478
|
-
),
|
|
1479
|
-
children: log.apiFormat === "anthropic" ? "Anthropic" : log.apiFormat === "openai" ? "OpenAI" : "Unknown"
|
|
1508
|
+
variant: "destructive",
|
|
1509
|
+
className: "text-[10px] px-1.5 py-0 h-5 font-mono tabular-nums",
|
|
1510
|
+
children: log.responseStatus
|
|
1480
1511
|
}
|
|
1481
|
-
)
|
|
1482
|
-
statusCategory === "server_error" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "destructive", className: "text-[10px] px-1.5 py-0 h-5 font-mono tabular-nums", children: log.responseStatus }) : statusCategory === "pending" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1512
|
+
) : statusCategory === "pending" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1483
1513
|
Badge,
|
|
1484
1514
|
{
|
|
1485
1515
|
variant: "outline",
|
|
@@ -1499,7 +1529,7 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1499
1529
|
),
|
|
1500
1530
|
children: log.responseStatus
|
|
1501
1531
|
}
|
|
1502
|
-
),
|
|
1532
|
+
) }),
|
|
1503
1533
|
log.elapsedMs !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
1504
1534
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
|
|
1505
1535
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed(log.elapsedMs) })
|
|
@@ -1524,28 +1554,50 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1524
1554
|
)
|
|
1525
1555
|
] })
|
|
1526
1556
|
] }),
|
|
1527
|
-
log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.
|
|
1528
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1529
|
-
|
|
1530
|
-
"
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1557
|
+
log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1558
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
|
|
1559
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.creation ?? null }),
|
|
1560
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-emerald-400", children: [
|
|
1561
|
+
"Cache +",
|
|
1562
|
+
formatTokens(log.cacheCreationInputTokens)
|
|
1563
|
+
] })
|
|
1564
|
+
] }) }),
|
|
1565
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens cached for reuse, reducing future API cost" })
|
|
1566
|
+
] }) }),
|
|
1567
|
+
log.cacheReadInputTokens !== null && log.cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1568
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
|
|
1569
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.read ?? null }),
|
|
1570
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
|
|
1571
|
+
"Cache ~",
|
|
1572
|
+
formatTokens(log.cacheReadInputTokens)
|
|
1573
|
+
] })
|
|
1574
|
+
] }) }),
|
|
1575
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens served from cache, reducing API cost" })
|
|
1576
|
+
] }) }),
|
|
1577
|
+
messageCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1578
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
1579
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3" }),
|
|
1580
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: messageCount })
|
|
1581
|
+
] }) }),
|
|
1582
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Number of messages in the conversation" })
|
|
1583
|
+
] }) }),
|
|
1584
|
+
toolCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1585
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
1586
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3" }),
|
|
1587
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: toolCount })
|
|
1588
|
+
] }) }),
|
|
1589
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Number of tools defined in the request" })
|
|
1590
|
+
] }) }),
|
|
1591
|
+
responseToolNames !== null && responseToolNames.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1592
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-amber-400/80 text-xs shrink-0", children: [
|
|
1593
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3" }),
|
|
1594
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[160px]", children: responseToolNames.join(", ") })
|
|
1595
|
+
] }) }),
|
|
1596
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(TooltipContent, { children: [
|
|
1597
|
+
"Tools called by model: ",
|
|
1598
|
+
responseToolNames.join(", ")
|
|
1539
1599
|
] })
|
|
1540
|
-
] }),
|
|
1541
|
-
messageCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
1542
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3" }),
|
|
1543
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: messageCount })
|
|
1544
|
-
] }),
|
|
1545
|
-
toolCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
1546
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3" }),
|
|
1547
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: toolCount })
|
|
1548
|
-
] }),
|
|
1600
|
+
] }) }),
|
|
1549
1601
|
log.origin !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1550
1602
|
"span",
|
|
1551
1603
|
{
|
|
@@ -1557,32 +1609,20 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1557
1609
|
]
|
|
1558
1610
|
}
|
|
1559
1611
|
),
|
|
1560
|
-
log.
|
|
1561
|
-
"span",
|
|
1562
|
-
|
|
1563
|
-
className: "
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
"
|
|
1573
|
-
|
|
1574
|
-
className: "flex items-center gap-1 text-purple-400/80 text-xs shrink-0",
|
|
1575
|
-
title: log.clientCwd !== null ? `PID: ${log.clientPid ?? "?"} | CWD: ${log.clientCwd}` : `PID: ${log.clientPid ?? "?"}`,
|
|
1576
|
-
children: [
|
|
1577
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FileTerminal, { className: "size-3" }),
|
|
1578
|
-
log.clientProjectFolder !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: log.clientProjectFolder }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
1579
|
-
"PID ",
|
|
1580
|
-
log.clientPid
|
|
1581
|
-
] })
|
|
1582
|
-
]
|
|
1583
|
-
}
|
|
1584
|
-
),
|
|
1585
|
-
log.streaming && /* @__PURE__ */ jsxRuntimeExports.jsx(Radio, { className: "size-3 text-muted-foreground/60 shrink-0" }),
|
|
1612
|
+
(log.clientPid !== null || log.clientProjectFolder !== null) && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1613
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-purple-400/80 text-xs shrink-0", children: [
|
|
1614
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FileTerminal, { className: "size-3" }),
|
|
1615
|
+
log.clientProjectFolder !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: log.clientProjectFolder }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
1616
|
+
"PID ",
|
|
1617
|
+
log.clientPid
|
|
1618
|
+
] })
|
|
1619
|
+
] }) }),
|
|
1620
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: log.clientCwd !== null ? `PID: ${log.clientPid ?? "?"} CWD: ${log.clientCwd}` : `Process ID: ${log.clientPid ?? "?"}` })
|
|
1621
|
+
] }) }),
|
|
1622
|
+
log.streaming && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1623
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Radio, { className: "size-3 text-muted-foreground/60 shrink-0" }) }),
|
|
1624
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Request used SSE streaming" })
|
|
1625
|
+
] }) }),
|
|
1586
1626
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
|
|
1587
1627
|
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" })
|
|
1588
1628
|
]
|
|
@@ -1597,12 +1637,12 @@ function Dialog({
|
|
|
1597
1637
|
function DialogTrigger({
|
|
1598
1638
|
...props
|
|
1599
1639
|
}) {
|
|
1600
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger$
|
|
1640
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger$2, { "data-slot": "dialog-trigger", ...props });
|
|
1601
1641
|
}
|
|
1602
1642
|
function DialogPortal({
|
|
1603
1643
|
...props
|
|
1604
1644
|
}) {
|
|
1605
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$
|
|
1645
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$2, { "data-slot": "dialog-portal", ...props });
|
|
1606
1646
|
}
|
|
1607
1647
|
function DialogOverlay({
|
|
1608
1648
|
className,
|
|
@@ -2167,15 +2207,18 @@ function ReplayDialog({ log, open, onOpenChange }) {
|
|
|
2167
2207
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(TabsContent, { value: "modified", className: "space-y-4", children: [
|
|
2168
2208
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
2169
2209
|
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-sm font-medium mb-2 block", children: "Request Body (JSON)" }),
|
|
2170
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2210
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2211
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2212
|
+
"textarea",
|
|
2213
|
+
{
|
|
2214
|
+
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",
|
|
2215
|
+
value: modifiedBody,
|
|
2216
|
+
onChange: (e) => setModifiedBody(e.target.value),
|
|
2217
|
+
spellCheck: false
|
|
2218
|
+
}
|
|
2219
|
+
) }),
|
|
2220
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Edit the request body before re-sending to the provider" })
|
|
2221
|
+
] }) })
|
|
2179
2222
|
] }),
|
|
2180
2223
|
error !== null && error !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-destructive bg-destructive/10 px-3 py-2 rounded-md", children: error }),
|
|
2181
2224
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -2359,22 +2402,25 @@ function StreamingChunkSequence({
|
|
|
2359
2402
|
] });
|
|
2360
2403
|
}
|
|
2361
2404
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
|
|
2362
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2405
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2406
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2407
|
+
"button",
|
|
2408
|
+
{
|
|
2409
|
+
type: "button",
|
|
2410
|
+
className: "flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer",
|
|
2411
|
+
onClick: () => setContainerExpanded((v) => !v),
|
|
2412
|
+
children: [
|
|
2413
|
+
containerExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3" }),
|
|
2414
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Raw SSE Events" }),
|
|
2415
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Badge, { variant: "outline", className: "text-[9px] px-1 py-0 h-4 font-mono ml-1", children: [
|
|
2416
|
+
logId,
|
|
2417
|
+
truncated === true ? "+" : ""
|
|
2418
|
+
] })
|
|
2419
|
+
]
|
|
2420
|
+
}
|
|
2421
|
+
) }),
|
|
2422
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Server-Sent Events streaming chunks from the provider" })
|
|
2423
|
+
] }) }),
|
|
2378
2424
|
containerExpanded === true ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-border bg-muted/20 overflow-auto max-h-64", children: renderBody() }) : null
|
|
2379
2425
|
] });
|
|
2380
2426
|
}
|
|
@@ -2414,32 +2460,32 @@ function DiffToggleButton({
|
|
|
2414
2460
|
active,
|
|
2415
2461
|
onClick
|
|
2416
2462
|
}) {
|
|
2417
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2463
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2464
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2465
|
+
"button",
|
|
2466
|
+
{
|
|
2467
|
+
type: "button",
|
|
2468
|
+
onClick,
|
|
2469
|
+
"aria-pressed": active,
|
|
2470
|
+
className: cn(
|
|
2471
|
+
"flex items-center gap-1.5 text-xs px-2 py-1 rounded transition-colors",
|
|
2472
|
+
active ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground hover:bg-muted"
|
|
2473
|
+
),
|
|
2474
|
+
children: [
|
|
2475
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(GitCompareArrows, { className: "size-3" }),
|
|
2476
|
+
active ? "Showing diff" : "Diff with Raw"
|
|
2477
|
+
]
|
|
2478
|
+
}
|
|
2479
|
+
) }),
|
|
2480
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: active ? "Hide diff view" : "Compare proxy output against the original raw version" })
|
|
2481
|
+
] }) });
|
|
2434
2482
|
}
|
|
2435
2483
|
const LogEntry = reactExports.memo(function({
|
|
2436
2484
|
log,
|
|
2437
2485
|
viewMode = "simple",
|
|
2438
|
-
suppressApiFormatBadge = false,
|
|
2439
2486
|
strip,
|
|
2440
2487
|
cacheTrend = null,
|
|
2441
|
-
|
|
2442
|
-
onToggleSelect
|
|
2488
|
+
onCompareWithPrevious
|
|
2443
2489
|
}) {
|
|
2444
2490
|
const [expanded, setExpanded] = reactExports.useState(false);
|
|
2445
2491
|
const [requestCopied, setRequestCopied] = reactExports.useState(false);
|
|
@@ -2448,7 +2494,60 @@ const LogEntry = reactExports.memo(function({
|
|
|
2448
2494
|
const [replayOpen, setReplayOpen] = reactExports.useState(false);
|
|
2449
2495
|
const [headersDiff, setHeadersDiff] = reactExports.useState(false);
|
|
2450
2496
|
const [requestDiff, setRequestDiff] = reactExports.useState(false);
|
|
2451
|
-
const
|
|
2497
|
+
const messageCount = reactExports.useMemo(() => {
|
|
2498
|
+
if (log.rawRequestBody === null) return null;
|
|
2499
|
+
if (log.apiFormat === "anthropic") {
|
|
2500
|
+
const parsed = parseRequest(log.rawRequestBody);
|
|
2501
|
+
if (parsed !== null) return parsed.messages.length;
|
|
2502
|
+
} else if (log.apiFormat === "openai") {
|
|
2503
|
+
try {
|
|
2504
|
+
const result = OpenAIRequestSchema.safeParse(JSON.parse(log.rawRequestBody));
|
|
2505
|
+
if (result.success) return result.data.messages.length;
|
|
2506
|
+
} catch {
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
return null;
|
|
2510
|
+
}, [log.rawRequestBody, log.apiFormat]);
|
|
2511
|
+
const toolCount = reactExports.useMemo(() => {
|
|
2512
|
+
if (log.rawRequestBody === null) return null;
|
|
2513
|
+
if (log.apiFormat === "anthropic") {
|
|
2514
|
+
const parsed = parseRequest(log.rawRequestBody);
|
|
2515
|
+
if (parsed !== null && parsed.tools !== void 0 && parsed.tools.length > 0) {
|
|
2516
|
+
return parsed.tools.length;
|
|
2517
|
+
}
|
|
2518
|
+
} else if (log.apiFormat === "openai") {
|
|
2519
|
+
try {
|
|
2520
|
+
const result = OpenAIRequestSchema.safeParse(JSON.parse(log.rawRequestBody));
|
|
2521
|
+
if (result.success && result.data.tools !== void 0 && result.data.tools.length > 0) {
|
|
2522
|
+
return result.data.tools.length;
|
|
2523
|
+
}
|
|
2524
|
+
} catch {
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
return null;
|
|
2528
|
+
}, [log.rawRequestBody, log.apiFormat]);
|
|
2529
|
+
const responseToolNames = reactExports.useMemo(() => {
|
|
2530
|
+
if (log.responseText === null) return null;
|
|
2531
|
+
if (log.apiFormat === "openai") {
|
|
2532
|
+
const parsed = parseOpenAIResponse(log.responseText);
|
|
2533
|
+
if (parsed !== null) {
|
|
2534
|
+
const toolCalls = parsed.choices[0]?.message?.tool_calls;
|
|
2535
|
+
if (toolCalls !== void 0 && toolCalls !== null && toolCalls.length > 0) {
|
|
2536
|
+
return toolCalls.map((tc) => tc.function?.name ?? "?").filter((n) => n !== "");
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
} else if (log.apiFormat === "anthropic") {
|
|
2540
|
+
try {
|
|
2541
|
+
const result = InspectorResponseSchema.safeParse(JSON.parse(log.responseText));
|
|
2542
|
+
if (result.success) {
|
|
2543
|
+
const names = result.data.content.filter((c) => c.type === "tool_use").map((c) => c.name);
|
|
2544
|
+
if (names.length > 0) return names;
|
|
2545
|
+
}
|
|
2546
|
+
} catch {
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
return null;
|
|
2550
|
+
}, [log.responseText, log.apiFormat]);
|
|
2452
2551
|
const strippedRequestBody = reactExports.useMemo(() => {
|
|
2453
2552
|
if (!strip || log.apiFormat !== "anthropic" || log.rawRequestBody === null) {
|
|
2454
2553
|
return null;
|
|
@@ -2489,178 +2588,258 @@ const LogEntry = reactExports.memo(function({
|
|
|
2489
2588
|
});
|
|
2490
2589
|
}
|
|
2491
2590
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
2492
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2591
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-border rounded-lg mb-3 overflow-hidden", children: [
|
|
2592
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2593
|
+
LogEntryHeader,
|
|
2594
|
+
{
|
|
2595
|
+
log,
|
|
2596
|
+
messageCount,
|
|
2597
|
+
toolCount,
|
|
2598
|
+
expanded,
|
|
2599
|
+
onToggle: () => setExpanded(!expanded),
|
|
2600
|
+
responseToolNames,
|
|
2601
|
+
cacheTrend
|
|
2602
|
+
}
|
|
2603
|
+
),
|
|
2604
|
+
expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { defaultValue: "request", children: [
|
|
2605
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, { className: "mx-4 mt-2", children: [
|
|
2606
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2607
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw-headers", children: "Raw Headers" }) }),
|
|
2608
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "HTTP headers received from the upstream provider" })
|
|
2609
|
+
] }) }),
|
|
2610
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2611
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "headers", children: "Headers" }) }),
|
|
2612
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Request and response headers sent and received" })
|
|
2613
|
+
] }) }),
|
|
2614
|
+
shouldShowRawRequestTab(log.apiFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2615
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw-request", children: "Raw Request" }) }),
|
|
2616
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Exact HTTP request sent to the upstream provider" })
|
|
2617
|
+
] }) }),
|
|
2618
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "request", children: "Request" }),
|
|
2619
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2620
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw", children: "Raw Response" }) }),
|
|
2621
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Exact HTTP response from the upstream provider" })
|
|
2622
|
+
] }) }),
|
|
2623
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" })
|
|
2624
|
+
] }),
|
|
2625
|
+
shouldShowRawRequestTab(log.apiFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
|
|
2626
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end mb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2627
|
+
CopyButton,
|
|
2502
2628
|
{
|
|
2503
|
-
log,
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
suppressApiFormatBadge,
|
|
2508
|
-
cacheTrend,
|
|
2509
|
-
isSelected,
|
|
2510
|
-
onToggleSelect
|
|
2629
|
+
text: log.rawRequestBody,
|
|
2630
|
+
label: "Copy Raw Request",
|
|
2631
|
+
copied: rawRequestCopied,
|
|
2632
|
+
onCopy: handleCopyRawRequest
|
|
2511
2633
|
}
|
|
2512
|
-
),
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
viewMode
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
onCopy: handleCopyRawRequest
|
|
2530
|
-
}
|
|
2531
|
-
) }),
|
|
2532
|
-
log.rawRequestBody !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: log.rawRequestBody, defaultExpandDepth: 1 }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" })
|
|
2533
|
-
] }) }),
|
|
2534
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
|
|
2535
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 mb-2", children: [
|
|
2536
|
-
shouldShowRequestDiffButton(
|
|
2537
|
-
log.apiFormat,
|
|
2538
|
-
viewMode,
|
|
2539
|
-
strip,
|
|
2540
|
-
log.rawRequestBody !== null
|
|
2541
|
-
) && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2542
|
-
DiffToggleButton,
|
|
2543
|
-
{
|
|
2544
|
-
active: requestDiff,
|
|
2545
|
-
onClick: (e) => {
|
|
2546
|
-
e.stopPropagation();
|
|
2547
|
-
setRequestDiff(!requestDiff);
|
|
2548
|
-
}
|
|
2549
|
-
}
|
|
2550
|
-
),
|
|
2551
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2552
|
-
Button,
|
|
2553
|
-
{
|
|
2554
|
-
variant: "outline",
|
|
2555
|
-
size: "sm",
|
|
2556
|
-
className: "h-7 text-xs",
|
|
2557
|
-
onClick: (e) => {
|
|
2558
|
-
e.stopPropagation();
|
|
2559
|
-
setReplayOpen(true);
|
|
2560
|
-
},
|
|
2561
|
-
children: [
|
|
2562
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { className: "size-3 mr-1" }),
|
|
2563
|
-
"Replay"
|
|
2564
|
-
]
|
|
2565
|
-
}
|
|
2566
|
-
),
|
|
2567
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2568
|
-
CopyButton,
|
|
2569
|
-
{
|
|
2570
|
-
text: displayedRequestBody,
|
|
2571
|
-
label: "Copy Request",
|
|
2572
|
-
copied: requestCopied,
|
|
2573
|
-
onCopy: handleCopyRequest
|
|
2574
|
-
}
|
|
2575
|
-
)
|
|
2576
|
-
] }),
|
|
2577
|
-
requestDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2578
|
-
DiffView,
|
|
2579
|
-
{
|
|
2580
|
-
result: requestDiffResult,
|
|
2581
|
-
emptyLabel: "No transformation applied — raw and sent request bodies are identical."
|
|
2634
|
+
) }),
|
|
2635
|
+
log.rawRequestBody !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: log.rawRequestBody, defaultExpandDepth: 1 }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" })
|
|
2636
|
+
] }) }),
|
|
2637
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
|
|
2638
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 mb-2", children: [
|
|
2639
|
+
shouldShowRequestDiffButton(
|
|
2640
|
+
log.apiFormat,
|
|
2641
|
+
viewMode,
|
|
2642
|
+
strip,
|
|
2643
|
+
log.rawRequestBody !== null
|
|
2644
|
+
) && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2645
|
+
DiffToggleButton,
|
|
2646
|
+
{
|
|
2647
|
+
active: requestDiff,
|
|
2648
|
+
onClick: (e) => {
|
|
2649
|
+
e.stopPropagation();
|
|
2650
|
+
setRequestDiff(!requestDiff);
|
|
2582
2651
|
}
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2587
|
-
|
|
2588
|
-
log.rawHeaders !== void 0 && Object.keys(log.rawHeaders).length > 0
|
|
2589
|
-
) && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2590
|
-
DiffToggleButton,
|
|
2652
|
+
}
|
|
2653
|
+
),
|
|
2654
|
+
onCompareWithPrevious !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2655
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2656
|
+
Button,
|
|
2591
2657
|
{
|
|
2592
|
-
|
|
2658
|
+
variant: "outline",
|
|
2659
|
+
size: "sm",
|
|
2660
|
+
className: "h-7 text-xs",
|
|
2593
2661
|
onClick: (e) => {
|
|
2594
2662
|
e.stopPropagation();
|
|
2595
|
-
|
|
2596
|
-
}
|
|
2663
|
+
onCompareWithPrevious();
|
|
2664
|
+
},
|
|
2665
|
+
children: [
|
|
2666
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(GitCompareArrows, { className: "size-3 mr-1" }),
|
|
2667
|
+
"Diff with Previous"
|
|
2668
|
+
]
|
|
2597
2669
|
}
|
|
2598
2670
|
) }),
|
|
2599
|
-
|
|
2600
|
-
DiffView,
|
|
2601
|
-
{
|
|
2602
|
-
result: headersDiffResult,
|
|
2603
|
-
emptyLabel: "No transformation applied — raw and processed headers are identical."
|
|
2604
|
-
}
|
|
2605
|
-
) : log.headers && Object.keys(log.headers).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.headers).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
2606
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-600 dark:text-blue-400 font-semibold shrink-0", children: [
|
|
2607
|
-
key,
|
|
2608
|
-
":"
|
|
2609
|
-
] }),
|
|
2610
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
|
|
2611
|
-
] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No headers captured" })
|
|
2671
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Compare this request with the immediately preceding one" })
|
|
2612
2672
|
] }) }),
|
|
2613
|
-
|
|
2614
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
2615
|
-
|
|
2616
|
-
":"
|
|
2617
|
-
] }),
|
|
2618
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
|
|
2619
|
-
] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No raw headers captured" }) }) }),
|
|
2620
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3 space-y-3", children: [
|
|
2621
|
-
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: [
|
|
2622
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold text-destructive mb-1", children: "SSE Error" }),
|
|
2623
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground font-mono", children: log.error })
|
|
2624
|
-
] }),
|
|
2625
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2626
|
-
CopyButton,
|
|
2673
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2674
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2675
|
+
Button,
|
|
2627
2676
|
{
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2677
|
+
variant: "outline",
|
|
2678
|
+
size: "sm",
|
|
2679
|
+
className: "h-7 text-xs",
|
|
2680
|
+
onClick: (e) => {
|
|
2681
|
+
e.stopPropagation();
|
|
2682
|
+
setReplayOpen(true);
|
|
2683
|
+
},
|
|
2684
|
+
children: [
|
|
2685
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { className: "size-3 mr-1" }),
|
|
2686
|
+
"Replay"
|
|
2687
|
+
]
|
|
2632
2688
|
}
|
|
2633
2689
|
) }),
|
|
2634
|
-
|
|
2635
|
-
log.streaming === true && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2636
|
-
StreamingChunkSequence,
|
|
2637
|
-
{
|
|
2638
|
-
logId: log.id,
|
|
2639
|
-
truncated: log.streamingChunksPath !== null
|
|
2640
|
-
}
|
|
2641
|
-
)
|
|
2690
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Re-send this request to the provider" })
|
|
2642
2691
|
] }) }),
|
|
2643
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2644
|
-
|
|
2692
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2693
|
+
CopyButton,
|
|
2645
2694
|
{
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
outputTokens: log.outputTokens,
|
|
2651
|
-
cacheCreationInputTokens: log.cacheCreationInputTokens,
|
|
2652
|
-
cacheReadInputTokens: log.cacheReadInputTokens,
|
|
2653
|
-
apiFormat: log.apiFormat,
|
|
2654
|
-
error: log.error
|
|
2695
|
+
text: displayedRequestBody,
|
|
2696
|
+
label: "Copy Request",
|
|
2697
|
+
copied: requestCopied,
|
|
2698
|
+
onCopy: handleCopyRequest
|
|
2655
2699
|
}
|
|
2656
|
-
)
|
|
2657
|
-
] })
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2700
|
+
)
|
|
2701
|
+
] }),
|
|
2702
|
+
requestDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2703
|
+
DiffView,
|
|
2704
|
+
{
|
|
2705
|
+
result: requestDiffResult,
|
|
2706
|
+
emptyLabel: "No transformation applied — raw and sent request bodies are identical."
|
|
2707
|
+
}
|
|
2708
|
+
) : displayedRequestBody !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: displayedRequestBody, defaultExpandDepth: 1 }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" })
|
|
2709
|
+
] }) }),
|
|
2710
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "headers", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
|
|
2711
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end gap-2 mb-2", children: shouldShowHeadersDiffButton(
|
|
2712
|
+
viewMode,
|
|
2713
|
+
log.rawHeaders !== void 0 && Object.keys(log.rawHeaders).length > 0
|
|
2714
|
+
) && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2715
|
+
DiffToggleButton,
|
|
2716
|
+
{
|
|
2717
|
+
active: headersDiff,
|
|
2718
|
+
onClick: (e) => {
|
|
2719
|
+
e.stopPropagation();
|
|
2720
|
+
setHeadersDiff(!headersDiff);
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
) }),
|
|
2724
|
+
headersDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2725
|
+
DiffView,
|
|
2726
|
+
{
|
|
2727
|
+
result: headersDiffResult,
|
|
2728
|
+
emptyLabel: "No transformation applied — raw and processed headers are identical."
|
|
2729
|
+
}
|
|
2730
|
+
) : log.headers && Object.keys(log.headers).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.headers).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
2731
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-600 dark:text-blue-400 font-semibold shrink-0", children: [
|
|
2732
|
+
key,
|
|
2733
|
+
":"
|
|
2734
|
+
] }),
|
|
2735
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
|
|
2736
|
+
] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No headers captured" })
|
|
2737
|
+
] }) }),
|
|
2738
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-headers", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: log.rawHeaders && Object.keys(log.rawHeaders).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.rawHeaders).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
2739
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-600 dark:text-blue-400 font-semibold shrink-0", children: [
|
|
2740
|
+
key,
|
|
2741
|
+
":"
|
|
2742
|
+
] }),
|
|
2743
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
|
|
2744
|
+
] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No raw headers captured" }) }) }),
|
|
2745
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3 space-y-3", children: [
|
|
2746
|
+
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: [
|
|
2747
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold text-destructive mb-1", children: "SSE Error" }),
|
|
2748
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground font-mono", children: log.error })
|
|
2749
|
+
] }),
|
|
2750
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2751
|
+
CopyButton,
|
|
2752
|
+
{
|
|
2753
|
+
text: log.responseText,
|
|
2754
|
+
label: "Copy Response",
|
|
2755
|
+
copied: responseCopied,
|
|
2756
|
+
onCopy: handleCopyResponse
|
|
2757
|
+
}
|
|
2758
|
+
) }),
|
|
2759
|
+
log.responseText !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: log.responseText, defaultExpandDepth: 1 }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No response" }),
|
|
2760
|
+
log.streaming === true && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2761
|
+
StreamingChunkSequence,
|
|
2762
|
+
{
|
|
2763
|
+
logId: log.id,
|
|
2764
|
+
truncated: log.streamingChunksPath !== null
|
|
2765
|
+
}
|
|
2766
|
+
)
|
|
2767
|
+
] }) }),
|
|
2768
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2769
|
+
ResponseView,
|
|
2770
|
+
{
|
|
2771
|
+
responseText: log.responseText,
|
|
2772
|
+
responseStatus: log.responseStatus,
|
|
2773
|
+
streaming: log.streaming,
|
|
2774
|
+
inputTokens: log.inputTokens,
|
|
2775
|
+
outputTokens: log.outputTokens,
|
|
2776
|
+
cacheCreationInputTokens: log.cacheCreationInputTokens,
|
|
2777
|
+
cacheReadInputTokens: log.cacheReadInputTokens,
|
|
2778
|
+
apiFormat: log.apiFormat,
|
|
2779
|
+
error: log.error
|
|
2780
|
+
}
|
|
2781
|
+
) }) })
|
|
2782
|
+
] }) })
|
|
2783
|
+
] }),
|
|
2661
2784
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ReplayDialog, { log, open: replayOpen, onOpenChange: setReplayOpen })
|
|
2662
2785
|
] });
|
|
2663
2786
|
});
|
|
2787
|
+
function ThreadConnector({
|
|
2788
|
+
stopReason,
|
|
2789
|
+
isPending,
|
|
2790
|
+
isFirst,
|
|
2791
|
+
isLast: _isLast,
|
|
2792
|
+
isTurnStart
|
|
2793
|
+
}) {
|
|
2794
|
+
const isBoundary = stopReason === "end_turn" || stopReason === "stop";
|
|
2795
|
+
const isToolUse = stopReason === "tool_use";
|
|
2796
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center w-6 shrink-0", children: [
|
|
2797
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center h-4", children: !isFirst && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-0.5 bg-muted-foreground/30" }) }),
|
|
2798
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-0.5", children: isBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2799
|
+
"div",
|
|
2800
|
+
{
|
|
2801
|
+
className: cn(
|
|
2802
|
+
"size-2.5 rounded-full border-2",
|
|
2803
|
+
"bg-background border-amber-400",
|
|
2804
|
+
"shadow-[0_0_6px_rgba(251,191,36,0.4)]"
|
|
2805
|
+
),
|
|
2806
|
+
title: stopReason === "end_turn" ? "End of Turn (Anthropic)" : "End of Turn (OpenAI)"
|
|
2807
|
+
}
|
|
2808
|
+
) : isToolUse ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2809
|
+
"div",
|
|
2810
|
+
{
|
|
2811
|
+
className: cn(
|
|
2812
|
+
"size-2 rounded-full",
|
|
2813
|
+
isTurnStart ? "bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.5)]" : "bg-muted-foreground/25"
|
|
2814
|
+
),
|
|
2815
|
+
title: isTurnStart ? "Tool Use — start of turn" : "Tool Use — turn continues"
|
|
2816
|
+
}
|
|
2817
|
+
) : isPending ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2818
|
+
"div",
|
|
2819
|
+
{
|
|
2820
|
+
className: "size-2.5 rounded-full border-2 border-dashed border-muted-foreground/30 animate-pulse",
|
|
2821
|
+
title: "Response pending"
|
|
2822
|
+
}
|
|
2823
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2824
|
+
"div",
|
|
2825
|
+
{
|
|
2826
|
+
className: cn(
|
|
2827
|
+
"size-1.5 rounded-full",
|
|
2828
|
+
isTurnStart ? "bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.5)]" : "bg-muted-foreground/30"
|
|
2829
|
+
)
|
|
2830
|
+
}
|
|
2831
|
+
) }),
|
|
2832
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex justify-center min-h-1", children: isBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-0.5 bg-muted-foreground/10 h-4" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2833
|
+
"div",
|
|
2834
|
+
{
|
|
2835
|
+
className: cn(
|
|
2836
|
+
"w-0.5 h-full",
|
|
2837
|
+
isPending ? "border-dashed bg-transparent border-l-2 border-muted-foreground/20" : "bg-muted-foreground/30"
|
|
2838
|
+
)
|
|
2839
|
+
}
|
|
2840
|
+
) })
|
|
2841
|
+
] });
|
|
2842
|
+
}
|
|
2664
2843
|
function computeStats(logs) {
|
|
2665
2844
|
let totalInput = 0;
|
|
2666
2845
|
let totalOutput = 0;
|
|
@@ -2675,14 +2854,31 @@ const ConversationGroup = reactExports.memo(function({
|
|
|
2675
2854
|
viewMode = "simple",
|
|
2676
2855
|
strip,
|
|
2677
2856
|
cacheTrends,
|
|
2678
|
-
|
|
2679
|
-
|
|
2857
|
+
onCompareWithPrevious,
|
|
2858
|
+
defaultGroupViewMode = "thread"
|
|
2680
2859
|
}) {
|
|
2681
2860
|
const [expanded, setExpanded] = reactExports.useState(false);
|
|
2861
|
+
const [groupViewMode, setGroupViewMode] = reactExports.useState(defaultGroupViewMode);
|
|
2862
|
+
reactExports.useEffect(() => {
|
|
2863
|
+
setGroupViewMode(defaultGroupViewMode);
|
|
2864
|
+
}, [defaultGroupViewMode]);
|
|
2682
2865
|
const stats = computeStats(group.logs);
|
|
2683
2866
|
const startTime = group.logs[0]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
2684
2867
|
const endTime = group.logs[group.logs.length - 1]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
2685
2868
|
const mixed = hasMixedApiFormat(group.logs);
|
|
2869
|
+
const isLoading = group.logs.some((log) => log.responseStatus === null);
|
|
2870
|
+
const stopReasons = reactExports.useMemo(() => group.logs.map((log) => extractStopReason(log)), [group.logs]);
|
|
2871
|
+
const turnIndices = reactExports.useMemo(() => {
|
|
2872
|
+
const indices = [];
|
|
2873
|
+
let turn = 0;
|
|
2874
|
+
for (let i = 0; i < stopReasons.length; i++) {
|
|
2875
|
+
if (i > 0 && (stopReasons[i - 1] === "end_turn" || stopReasons[i - 1] === "stop")) {
|
|
2876
|
+
turn++;
|
|
2877
|
+
}
|
|
2878
|
+
indices.push(turn);
|
|
2879
|
+
}
|
|
2880
|
+
return indices;
|
|
2881
|
+
}, [stopReasons]);
|
|
2686
2882
|
const displayId = group.conversationId.startsWith("PID:") || group.conversationId.includes("|") ? group.conversationId : group.conversationId.length > 24 ? group.conversationId.slice(0, 12) + "…" + group.conversationId.slice(-12) : group.conversationId;
|
|
2687
2883
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4", children: [
|
|
2688
2884
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -2697,22 +2893,58 @@ const ConversationGroup = reactExports.memo(function({
|
|
|
2697
2893
|
apiFormat: getGroupApiFormat(group.logs),
|
|
2698
2894
|
expanded,
|
|
2699
2895
|
onToggle: () => setExpanded(!expanded),
|
|
2700
|
-
hideApiFormat: mixed
|
|
2896
|
+
hideApiFormat: mixed,
|
|
2897
|
+
isLoading,
|
|
2898
|
+
userAgent: group.logs[0]?.userAgent ?? null,
|
|
2899
|
+
viewMode: groupViewMode,
|
|
2900
|
+
onToggleViewMode: () => setGroupViewMode((prev) => prev === "thread" ? "flat" : "thread")
|
|
2701
2901
|
}
|
|
2702
2902
|
),
|
|
2703
|
-
expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4 border-l-2 border-muted ml-3", children: group.logs.map((log) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2903
|
+
expanded && groupViewMode === "flat" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4 border-l-2 border-muted ml-3", children: group.logs.map((log) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2704
2904
|
LogEntry,
|
|
2705
2905
|
{
|
|
2706
2906
|
log,
|
|
2707
2907
|
viewMode,
|
|
2708
|
-
suppressApiFormatBadge: !mixed,
|
|
2709
2908
|
strip,
|
|
2710
2909
|
cacheTrend: cacheTrends?.get(log.id) ?? null,
|
|
2711
|
-
|
|
2712
|
-
onToggleSelect
|
|
2910
|
+
onCompareWithPrevious: () => onCompareWithPrevious(log)
|
|
2713
2911
|
},
|
|
2714
2912
|
log.id
|
|
2715
|
-
)) })
|
|
2913
|
+
)) }),
|
|
2914
|
+
expanded && groupViewMode === "thread" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ml-3", children: group.logs.map((log, idx) => {
|
|
2915
|
+
const isTurnStart = idx === 0 || stopReasons[idx - 1] === "end_turn" || stopReasons[idx - 1] === "stop";
|
|
2916
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-stretch", children: [
|
|
2917
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2918
|
+
ThreadConnector,
|
|
2919
|
+
{
|
|
2920
|
+
stopReason: stopReasons[idx] ?? null,
|
|
2921
|
+
isPending: log.responseStatus === null,
|
|
2922
|
+
isFirst: idx === 0,
|
|
2923
|
+
isLast: idx === group.logs.length - 1,
|
|
2924
|
+
isTurnStart
|
|
2925
|
+
}
|
|
2926
|
+
),
|
|
2927
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2928
|
+
"div",
|
|
2929
|
+
{
|
|
2930
|
+
className: cn(
|
|
2931
|
+
"flex-1 min-w-0 mb-2 rounded-lg",
|
|
2932
|
+
(turnIndices[idx] ?? 0) % 2 === 0 ? "bg-muted/10" : "bg-muted/25"
|
|
2933
|
+
),
|
|
2934
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2935
|
+
LogEntry,
|
|
2936
|
+
{
|
|
2937
|
+
log,
|
|
2938
|
+
viewMode,
|
|
2939
|
+
strip,
|
|
2940
|
+
cacheTrend: cacheTrends?.get(log.id) ?? null,
|
|
2941
|
+
onCompareWithPrevious: () => onCompareWithPrevious(log)
|
|
2942
|
+
}
|
|
2943
|
+
)
|
|
2944
|
+
}
|
|
2945
|
+
)
|
|
2946
|
+
] }, log.id);
|
|
2947
|
+
}) })
|
|
2716
2948
|
] });
|
|
2717
2949
|
});
|
|
2718
2950
|
function CrabLogo({ className }) {
|
|
@@ -2760,7 +2992,7 @@ function SelectTrigger({
|
|
|
2760
2992
|
...props
|
|
2761
2993
|
}) {
|
|
2762
2994
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2763
|
-
Trigger,
|
|
2995
|
+
Trigger$1,
|
|
2764
2996
|
{
|
|
2765
2997
|
"data-slot": "select-trigger",
|
|
2766
2998
|
"data-size": size,
|
|
@@ -2783,8 +3015,8 @@ function SelectContent({
|
|
|
2783
3015
|
align = "center",
|
|
2784
3016
|
...props
|
|
2785
3017
|
}) {
|
|
2786
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2787
|
-
Content2,
|
|
3018
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3019
|
+
Content2$1,
|
|
2788
3020
|
{
|
|
2789
3021
|
"data-slot": "select-content",
|
|
2790
3022
|
className: cn(
|
|
@@ -3208,20 +3440,26 @@ function TestStatus({ result }) {
|
|
|
3208
3440
|
}
|
|
3209
3441
|
if (result.cacheCreationInputTokens !== void 0 && result.cacheCreationInputTokens > 0) {
|
|
3210
3442
|
tokenParts.push(
|
|
3211
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
3212
|
-
"
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3443
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
3444
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-emerald-400", children: [
|
|
3445
|
+
"+",
|
|
3446
|
+
result.cacheCreationInputTokens,
|
|
3447
|
+
" cache"
|
|
3448
|
+
] }) }),
|
|
3449
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens cached for reuse, reducing future API cost" })
|
|
3450
|
+
] }) }, "cache-create")
|
|
3216
3451
|
);
|
|
3217
3452
|
}
|
|
3218
3453
|
if (result.cacheReadInputTokens !== void 0 && result.cacheReadInputTokens > 0) {
|
|
3219
3454
|
tokenParts.push(
|
|
3220
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
3221
|
-
"
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3455
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
3456
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
|
|
3457
|
+
"~",
|
|
3458
|
+
result.cacheReadInputTokens,
|
|
3459
|
+
" cached"
|
|
3460
|
+
] }) }),
|
|
3461
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens served from cache, reducing API cost" })
|
|
3462
|
+
] }) }, "cache-read")
|
|
3225
3463
|
);
|
|
3226
3464
|
}
|
|
3227
3465
|
const displayTokens = [];
|
|
@@ -3229,15 +3467,18 @@ function TestStatus({ result }) {
|
|
|
3229
3467
|
if (i > 0) displayTokens.push(", ");
|
|
3230
3468
|
displayTokens.push(tokenParts[i]);
|
|
3231
3469
|
}
|
|
3232
|
-
return /* @__PURE__ */ jsxRuntimeExports.
|
|
3233
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3470
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
3471
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-xs text-green-600 shrink-0", children: [
|
|
3472
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { className: "size-3" }),
|
|
3473
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Connected" }),
|
|
3474
|
+
tokenParts.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground", children: [
|
|
3475
|
+
"(",
|
|
3476
|
+
displayTokens,
|
|
3477
|
+
")"
|
|
3478
|
+
] })
|
|
3479
|
+
] }) }),
|
|
3480
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Connection test passed" })
|
|
3481
|
+
] }) });
|
|
3241
3482
|
}
|
|
3242
3483
|
const error = result.error;
|
|
3243
3484
|
const errorMessage = error?.message ?? "Connection failed";
|
|
@@ -3247,17 +3488,22 @@ function TestStatus({ result }) {
|
|
|
3247
3488
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1 shrink-0", children: [
|
|
3248
3489
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-xs text-red-600 max-w-[200px]", children: [
|
|
3249
3490
|
getErrorIcon(errorType),
|
|
3250
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3251
|
-
|
|
3252
|
-
"
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3491
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
3492
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: errorMessage }) }),
|
|
3493
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Connection test failed" })
|
|
3494
|
+
] }) }),
|
|
3495
|
+
errorDetails !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
3496
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3497
|
+
"button",
|
|
3498
|
+
{
|
|
3499
|
+
type: "button",
|
|
3500
|
+
onClick: () => setShowDetails(!showDetails),
|
|
3501
|
+
className: "shrink-0 text-muted-foreground hover:text-foreground transition-colors",
|
|
3502
|
+
children: showDetails ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { className: "size-3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { className: "size-3" })
|
|
3503
|
+
}
|
|
3504
|
+
) }),
|
|
3505
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: showDetails ? "Hide error details" : "Show detailed error information" })
|
|
3506
|
+
] }) })
|
|
3261
3507
|
] }),
|
|
3262
3508
|
showDetails && errorDetails !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground bg-muted/50 rounded p-2 max-w-[300px]", children: [
|
|
3263
3509
|
errorHint !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-1", children: errorHint }),
|
|
@@ -3328,8 +3574,14 @@ function ProviderCard({
|
|
|
3328
3574
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
3329
3575
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
3330
3576
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium truncate", children: provider.name }),
|
|
3331
|
-
provider.source === "company" && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3332
|
-
|
|
3577
|
+
provider.source === "company" && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
3578
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs px-1.5 py-0.5 rounded bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400 shrink-0", children: "公司" }) }),
|
|
3579
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Company-provided API key" })
|
|
3580
|
+
] }) }),
|
|
3581
|
+
provider.source === "personal" && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
3582
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs px-1.5 py-0.5 rounded bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400 shrink-0", children: "个人" }) }),
|
|
3583
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Your personal API key" })
|
|
3584
|
+
] }) })
|
|
3333
3585
|
] }),
|
|
3334
3586
|
docsUrl !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3335
3587
|
"a",
|
|
@@ -3808,24 +4060,30 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
3808
4060
|
] }),
|
|
3809
4061
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
3810
4062
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1 border-b border-border", children: [
|
|
3811
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
"
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
4063
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
4064
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4065
|
+
"button",
|
|
4066
|
+
{
|
|
4067
|
+
type: "button",
|
|
4068
|
+
onClick: () => setActiveTab("anthropic"),
|
|
4069
|
+
className: `px-3 py-2 text-sm font-medium border-b-2 transition-colors ${activeTab === "anthropic" ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"}`,
|
|
4070
|
+
children: "Anthropic Format"
|
|
4071
|
+
}
|
|
4072
|
+
) }),
|
|
4073
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Anthropic Messages API protocol" })
|
|
4074
|
+
] }) }),
|
|
4075
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
4076
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4077
|
+
"button",
|
|
4078
|
+
{
|
|
4079
|
+
type: "button",
|
|
4080
|
+
onClick: () => setActiveTab("openai"),
|
|
4081
|
+
className: `px-3 py-2 text-sm font-medium border-b-2 transition-colors ${activeTab === "openai" ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"}`,
|
|
4082
|
+
children: "OpenAI Format"
|
|
4083
|
+
}
|
|
4084
|
+
) }),
|
|
4085
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "OpenAI Chat Completions API protocol" })
|
|
4086
|
+
] }) })
|
|
3829
4087
|
] }),
|
|
3830
4088
|
errors.format !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.format })
|
|
3831
4089
|
] }),
|
|
@@ -4222,32 +4480,38 @@ function ProvidersPanel({
|
|
|
4222
4480
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between sticky top-0 z-10 bg-background pb-2", children: [
|
|
4223
4481
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-medium", children: "Providers" }),
|
|
4224
4482
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4225
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4483
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
4484
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
4485
|
+
Button,
|
|
4486
|
+
{
|
|
4487
|
+
variant: "outline",
|
|
4488
|
+
size: "sm",
|
|
4489
|
+
onClick: () => handleExport(),
|
|
4490
|
+
className: "gap-1 hover:bg-muted",
|
|
4491
|
+
children: [
|
|
4492
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "size-3" }),
|
|
4493
|
+
"Export"
|
|
4494
|
+
]
|
|
4495
|
+
}
|
|
4496
|
+
) }),
|
|
4497
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Download providers as JSON for backup or sharing" })
|
|
4498
|
+
] }) }),
|
|
4499
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
4500
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
4501
|
+
Button,
|
|
4502
|
+
{
|
|
4503
|
+
variant: "outline",
|
|
4504
|
+
size: "sm",
|
|
4505
|
+
onClick: handleImportClick,
|
|
4506
|
+
className: "gap-1 hover:bg-muted",
|
|
4507
|
+
children: [
|
|
4508
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { className: "size-3" }),
|
|
4509
|
+
"Import"
|
|
4510
|
+
]
|
|
4511
|
+
}
|
|
4512
|
+
) }),
|
|
4513
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Import providers from an exported JSON file" })
|
|
4514
|
+
] }) }),
|
|
4251
4515
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4252
4516
|
"input",
|
|
4253
4517
|
{
|
|
@@ -4283,21 +4547,23 @@ function ProvidersPanel({
|
|
|
4283
4547
|
configPath !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground bg-muted/30 rounded-md px-3 py-2", children: [
|
|
4284
4548
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0", children: "Config:" }),
|
|
4285
4549
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono truncate", title: configPath, children: configPath }),
|
|
4286
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4550
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
4551
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4552
|
+
"button",
|
|
4553
|
+
{
|
|
4554
|
+
type: "button",
|
|
4555
|
+
onClick: () => {
|
|
4556
|
+
void window.navigator.clipboard.writeText(configPath).then(() => {
|
|
4557
|
+
setConfigPathCopied(true);
|
|
4558
|
+
setTimeout(() => setConfigPathCopied(false), 2e3);
|
|
4559
|
+
});
|
|
4560
|
+
},
|
|
4561
|
+
className: "shrink-0 ml-auto text-muted-foreground hover:text-foreground transition-colors",
|
|
4562
|
+
children: configPathCopied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3 text-green-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3" })
|
|
4563
|
+
}
|
|
4564
|
+
) }),
|
|
4565
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Copy config file path to clipboard" })
|
|
4566
|
+
] }) })
|
|
4301
4567
|
] }),
|
|
4302
4568
|
error !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-sm text-destructive bg-destructive/10 rounded-md px-3 py-2", children: [
|
|
4303
4569
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "size-4 shrink-0" }),
|
|
@@ -4310,16 +4576,18 @@ function ProvidersPanel({
|
|
|
4310
4576
|
"Add Your First Provider"
|
|
4311
4577
|
] })
|
|
4312
4578
|
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
|
|
4313
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex gap-1 border-b border-border", children: ["all", "personal", "company"].map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4579
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex gap-1 border-b border-border", children: ["all", "personal", "company"].map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
4580
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4581
|
+
"button",
|
|
4582
|
+
{
|
|
4583
|
+
type: "button",
|
|
4584
|
+
onClick: () => setSourceFilter(tab),
|
|
4585
|
+
className: `px-3 py-2 text-sm font-medium border-b-2 transition-colors ${sourceFilter === tab ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"}`,
|
|
4586
|
+
children: tab === "all" ? "All" : tab === "personal" ? "Personal" : "Company"
|
|
4587
|
+
}
|
|
4588
|
+
) }),
|
|
4589
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: tab === "all" ? "Show all providers" : tab === "personal" ? "Providers you configured yourself" : "Providers set by your organization" })
|
|
4590
|
+
] }) }, tab)) }),
|
|
4323
4591
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: listScrollRef, className: "space-y-3", children: filteredProviders.map((provider) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4324
4592
|
ProviderCard,
|
|
4325
4593
|
{
|
|
@@ -4490,22 +4758,25 @@ function ProxySettingsTab() {
|
|
|
4490
4758
|
" and overrides the env var for subsequent requests."
|
|
4491
4759
|
] })
|
|
4492
4760
|
] }),
|
|
4493
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
4494
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4761
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
4762
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-3", children: [
|
|
4763
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4764
|
+
"input",
|
|
4765
|
+
{
|
|
4766
|
+
type: "checkbox",
|
|
4767
|
+
role: "switch",
|
|
4768
|
+
checked: strip,
|
|
4769
|
+
disabled: isLoading || pending,
|
|
4770
|
+
onChange: (e) => {
|
|
4771
|
+
void handleToggle(e.currentTarget.checked);
|
|
4772
|
+
},
|
|
4773
|
+
className: "size-4 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50"
|
|
4774
|
+
}
|
|
4775
|
+
),
|
|
4776
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: isLoading ? "Loading…" : strip ? "Stripping enabled" : "Stripping disabled" })
|
|
4777
|
+
] }) }),
|
|
4778
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Strip Claude Code billing header to improve cache hit rates" })
|
|
4779
|
+
] }) }),
|
|
4509
4780
|
error !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-destructive", children: [
|
|
4510
4781
|
"Failed to save: ",
|
|
4511
4782
|
error
|
|
@@ -5473,9 +5744,8 @@ function ProxyViewer({
|
|
|
5473
5744
|
}) {
|
|
5474
5745
|
const { totalIn, totalOut } = computeTokenSummary(logs);
|
|
5475
5746
|
const [groupedView, setGroupedView] = reactExports.useState(true);
|
|
5747
|
+
const [groupViewMode, setGroupViewMode] = reactExports.useState("thread");
|
|
5476
5748
|
const [exporting, setExporting] = reactExports.useState(false);
|
|
5477
|
-
const [selectedLogIds, setSelectedLogIds] = reactExports.useState([]);
|
|
5478
|
-
const [compareOpen, setCompareOpen] = reactExports.useState(false);
|
|
5479
5749
|
const [comparePair, setComparePair] = reactExports.useState(null);
|
|
5480
5750
|
const handleExport = reactExports.useCallback(async () => {
|
|
5481
5751
|
setExporting(true);
|
|
@@ -5486,76 +5756,37 @@ function ProxyViewer({
|
|
|
5486
5756
|
}
|
|
5487
5757
|
}, [logs]);
|
|
5488
5758
|
const parentRef = reactExports.useRef(null);
|
|
5489
|
-
const handleToggleSelect = reactExports.useCallback((logId) => {
|
|
5490
|
-
setSelectedLogIds((prev) => {
|
|
5491
|
-
if (prev.includes(logId)) {
|
|
5492
|
-
return prev.filter((id) => id !== logId);
|
|
5493
|
-
}
|
|
5494
|
-
if (prev.length < 2) {
|
|
5495
|
-
return [...prev, logId];
|
|
5496
|
-
}
|
|
5497
|
-
const newer = prev[1];
|
|
5498
|
-
if (newer === void 0) return prev;
|
|
5499
|
-
return [newer, logId];
|
|
5500
|
-
});
|
|
5501
|
-
}, []);
|
|
5502
5759
|
reactExports.useEffect(() => {
|
|
5503
|
-
|
|
5504
|
-
setCompareOpen(false);
|
|
5760
|
+
setComparePair(null);
|
|
5505
5761
|
}, [selectedSession, selectedModel]);
|
|
5506
|
-
const selectedSet = reactExports.useMemo(() => new Set(selectedLogIds), [selectedLogIds]);
|
|
5507
|
-
const openCompare = reactExports.useCallback(() => {
|
|
5508
|
-
if (selectedLogIds.length !== 2) return;
|
|
5509
|
-
const [idA, idB] = selectedLogIds;
|
|
5510
|
-
if (idA === void 0 || idB === void 0) return;
|
|
5511
|
-
const logA = logs.find((l) => l.id === idA);
|
|
5512
|
-
const logB = logs.find((l) => l.id === idB);
|
|
5513
|
-
if (logA === void 0 || logB === void 0) return;
|
|
5514
|
-
setComparePair([logA, logB]);
|
|
5515
|
-
setCompareOpen(true);
|
|
5516
|
-
}, [selectedLogIds, logs]);
|
|
5517
5762
|
const closeCompare = reactExports.useCallback(() => {
|
|
5518
|
-
|
|
5519
|
-
}, []);
|
|
5520
|
-
const clearSelection = reactExports.useCallback(() => {
|
|
5521
|
-
setSelectedLogIds([]);
|
|
5763
|
+
setComparePair(null);
|
|
5522
5764
|
}, []);
|
|
5523
|
-
const
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
const a = Date.parse(logA.timestamp);
|
|
5534
|
-
const b = Date.parse(logB.timestamp);
|
|
5535
|
-
if (!Number.isNaN(a) && !Number.isNaN(b)) {
|
|
5536
|
-
const ms = Math.abs(b - a);
|
|
5537
|
-
elapsed = formatElapsed2(ms);
|
|
5538
|
-
}
|
|
5539
|
-
}
|
|
5540
|
-
return {
|
|
5541
|
-
logA,
|
|
5542
|
-
logB,
|
|
5543
|
-
sameSession,
|
|
5544
|
-
elapsed
|
|
5545
|
-
};
|
|
5546
|
-
}, [selectedLogIds, logs]);
|
|
5547
|
-
function formatElapsed2(ms) {
|
|
5548
|
-
if (ms < 1e3) return `${ms}ms`;
|
|
5549
|
-
const sec = Math.floor(ms / 1e3);
|
|
5550
|
-
if (sec < 60) return `${sec}s`;
|
|
5551
|
-
const min = Math.floor(sec / 60);
|
|
5552
|
-
if (min < 60) return `${min}m`;
|
|
5553
|
-
const hr = Math.floor(min / 60);
|
|
5554
|
-
return `${hr}h${min % 60}m`;
|
|
5555
|
-
}
|
|
5765
|
+
const handleCompareWithPrevious = reactExports.useCallback(
|
|
5766
|
+
(log) => {
|
|
5767
|
+
const idx = logs.indexOf(log);
|
|
5768
|
+
if (idx <= 0) return;
|
|
5769
|
+
const predecessor = logs[idx - 1];
|
|
5770
|
+
if (predecessor === void 0) return;
|
|
5771
|
+
setComparePair([predecessor, log]);
|
|
5772
|
+
},
|
|
5773
|
+
[logs]
|
|
5774
|
+
);
|
|
5556
5775
|
const groups = reactExports.useMemo(() => groupLogsByConversation(logs), [logs]);
|
|
5557
5776
|
const cacheTrends = reactExports.useMemo(() => computeCacheTrends(groups), [groups]);
|
|
5558
|
-
const
|
|
5777
|
+
const stopReasons = reactExports.useMemo(() => logs.map((log) => extractStopReason(log)), [logs]);
|
|
5778
|
+
const turnIndices = reactExports.useMemo(() => {
|
|
5779
|
+
const indices = [];
|
|
5780
|
+
let turn = 0;
|
|
5781
|
+
for (let i = 0; i < stopReasons.length; i++) {
|
|
5782
|
+
if (i > 0 && (stopReasons[i - 1] === "end_turn" || stopReasons[i - 1] === "stop")) {
|
|
5783
|
+
turn++;
|
|
5784
|
+
}
|
|
5785
|
+
indices.push(turn);
|
|
5786
|
+
}
|
|
5787
|
+
return indices;
|
|
5788
|
+
}, [stopReasons]);
|
|
5789
|
+
const renderGroups = logs.length > 0 && groupedView && groups.length > 1;
|
|
5559
5790
|
const rowVirtualizer = useVirtualizer({
|
|
5560
5791
|
count: renderGroups ? groups.length : logs.length,
|
|
5561
5792
|
getScrollElement: () => parentRef.current,
|
|
@@ -5575,26 +5806,29 @@ function ProxyViewer({
|
|
|
5575
5806
|
] })
|
|
5576
5807
|
] })
|
|
5577
5808
|
] }),
|
|
5578
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
5579
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5809
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
5810
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center border border-border rounded-md overflow-hidden", children: [
|
|
5811
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5812
|
+
"button",
|
|
5813
|
+
{
|
|
5814
|
+
type: "button",
|
|
5815
|
+
onClick: () => onViewModeChange("simple"),
|
|
5816
|
+
className: `px-2 py-1 cursor-pointer transition-colors text-xs ${viewMode === "simple" ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
|
|
5817
|
+
children: "Simple"
|
|
5818
|
+
}
|
|
5819
|
+
),
|
|
5820
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5821
|
+
"button",
|
|
5822
|
+
{
|
|
5823
|
+
type: "button",
|
|
5824
|
+
onClick: () => onViewModeChange("full"),
|
|
5825
|
+
className: `px-2 py-1 cursor-pointer transition-colors text-xs ${viewMode === "full" ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
|
|
5826
|
+
children: "Full"
|
|
5827
|
+
}
|
|
5828
|
+
)
|
|
5829
|
+
] }) }),
|
|
5830
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Simple shows parsed output; Full adds raw headers and tokens" })
|
|
5831
|
+
] }) }),
|
|
5598
5832
|
/* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {}),
|
|
5599
5833
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground text-xs font-mono", children: [
|
|
5600
5834
|
logs.length,
|
|
@@ -5665,6 +5899,28 @@ function ProxyViewer({
|
|
|
5665
5899
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(List, { className: "size-4" })
|
|
5666
5900
|
}
|
|
5667
5901
|
)
|
|
5902
|
+
] }),
|
|
5903
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center border border-border rounded-md overflow-hidden", children: [
|
|
5904
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5905
|
+
"button",
|
|
5906
|
+
{
|
|
5907
|
+
type: "button",
|
|
5908
|
+
onClick: () => setGroupViewMode("thread"),
|
|
5909
|
+
className: `px-2 py-1.5 cursor-pointer transition-colors ${groupViewMode === "thread" ? "bg-amber-500/15 text-amber-400 border-r border-amber-500/30" : "text-muted-foreground hover:bg-muted/50"}`,
|
|
5910
|
+
title: "Thread view (connected timeline)",
|
|
5911
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { className: "size-4" })
|
|
5912
|
+
}
|
|
5913
|
+
),
|
|
5914
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5915
|
+
"button",
|
|
5916
|
+
{
|
|
5917
|
+
type: "button",
|
|
5918
|
+
onClick: () => setGroupViewMode("flat"),
|
|
5919
|
+
className: `px-2 py-1.5 cursor-pointer transition-colors ${groupViewMode === "flat" ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
|
|
5920
|
+
title: "Flat view (card list)",
|
|
5921
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(List, { className: "size-4" })
|
|
5922
|
+
}
|
|
5923
|
+
)
|
|
5668
5924
|
] })
|
|
5669
5925
|
] }),
|
|
5670
5926
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 px-6 pb-6", children: logs.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-muted-foreground py-16 space-y-4", children: [
|
|
@@ -5702,8 +5958,8 @@ function ProxyViewer({
|
|
|
5702
5958
|
viewMode,
|
|
5703
5959
|
strip,
|
|
5704
5960
|
cacheTrends,
|
|
5705
|
-
|
|
5706
|
-
|
|
5961
|
+
onCompareWithPrevious: handleCompareWithPrevious,
|
|
5962
|
+
defaultGroupViewMode: groupViewMode
|
|
5707
5963
|
}
|
|
5708
5964
|
)
|
|
5709
5965
|
},
|
|
@@ -5712,6 +5968,7 @@ function ProxyViewer({
|
|
|
5712
5968
|
} else {
|
|
5713
5969
|
const log = logs[virtualRow.index];
|
|
5714
5970
|
if (log === void 0) return null;
|
|
5971
|
+
const idx = virtualRow.index;
|
|
5715
5972
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5716
5973
|
"div",
|
|
5717
5974
|
{
|
|
@@ -5724,15 +5981,44 @@ function ProxyViewer({
|
|
|
5724
5981
|
width: "100%",
|
|
5725
5982
|
transform: `translateY(${virtualRow.start}px)`
|
|
5726
5983
|
},
|
|
5727
|
-
children: /* @__PURE__ */ jsxRuntimeExports.
|
|
5984
|
+
children: groupViewMode === "thread" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-stretch ml-3", children: [
|
|
5985
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5986
|
+
ThreadConnector,
|
|
5987
|
+
{
|
|
5988
|
+
stopReason: stopReasons[idx] ?? null,
|
|
5989
|
+
isPending: log.responseStatus === null,
|
|
5990
|
+
isFirst: idx === 0,
|
|
5991
|
+
isLast: idx === logs.length - 1,
|
|
5992
|
+
isTurnStart: idx === 0 || stopReasons[idx - 1] === "end_turn" || stopReasons[idx - 1] === "stop"
|
|
5993
|
+
}
|
|
5994
|
+
),
|
|
5995
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5996
|
+
"div",
|
|
5997
|
+
{
|
|
5998
|
+
className: cn(
|
|
5999
|
+
"flex-1 min-w-0 mb-2 rounded-lg",
|
|
6000
|
+
(turnIndices[idx] ?? 0) % 2 === 0 ? "bg-muted/10" : "bg-muted/25"
|
|
6001
|
+
),
|
|
6002
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6003
|
+
LogEntry,
|
|
6004
|
+
{
|
|
6005
|
+
log,
|
|
6006
|
+
viewMode,
|
|
6007
|
+
strip,
|
|
6008
|
+
cacheTrend: cacheTrends.get(log.id) ?? null,
|
|
6009
|
+
onCompareWithPrevious: () => handleCompareWithPrevious(log)
|
|
6010
|
+
}
|
|
6011
|
+
)
|
|
6012
|
+
}
|
|
6013
|
+
)
|
|
6014
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5728
6015
|
LogEntry,
|
|
5729
6016
|
{
|
|
5730
6017
|
log,
|
|
5731
6018
|
viewMode,
|
|
5732
6019
|
strip,
|
|
5733
6020
|
cacheTrend: cacheTrends.get(log.id) ?? null,
|
|
5734
|
-
|
|
5735
|
-
onToggleSelect: handleToggleSelect
|
|
6021
|
+
onCompareWithPrevious: () => handleCompareWithPrevious(log)
|
|
5736
6022
|
}
|
|
5737
6023
|
)
|
|
5738
6024
|
},
|
|
@@ -5742,40 +6028,7 @@ function ProxyViewer({
|
|
|
5742
6028
|
})
|
|
5743
6029
|
}
|
|
5744
6030
|
) }) }),
|
|
5745
|
-
|
|
5746
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(GitCompareArrows, { className: "size-4 text-amber-400 shrink-0" }),
|
|
5747
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground font-mono", children: [
|
|
5748
|
-
"#",
|
|
5749
|
-
selectedSummary.logA.id,
|
|
5750
|
-
" ↔ #",
|
|
5751
|
-
selectedSummary.logB.id,
|
|
5752
|
-
" · ",
|
|
5753
|
-
selectedSummary.sameSession ? "same session" : "different sessions",
|
|
5754
|
-
selectedSummary.elapsed !== "" && ` · ${selectedSummary.elapsed} apart`
|
|
5755
|
-
] }),
|
|
5756
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
5757
|
-
"button",
|
|
5758
|
-
{
|
|
5759
|
-
type: "button",
|
|
5760
|
-
onClick: clearSelection,
|
|
5761
|
-
className: "text-muted-foreground hover:text-foreground transition-colors cursor-pointer inline-flex items-center gap-1",
|
|
5762
|
-
children: [
|
|
5763
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "size-3" }),
|
|
5764
|
-
"Clear"
|
|
5765
|
-
]
|
|
5766
|
-
}
|
|
5767
|
-
),
|
|
5768
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5769
|
-
"button",
|
|
5770
|
-
{
|
|
5771
|
-
type: "button",
|
|
5772
|
-
onClick: openCompare,
|
|
5773
|
-
className: "bg-amber-400 text-amber-950 hover:bg-amber-300 transition-colors px-3 py-1 rounded font-medium cursor-pointer",
|
|
5774
|
-
children: "Compare 2 logs"
|
|
5775
|
-
}
|
|
5776
|
-
)
|
|
5777
|
-
] }),
|
|
5778
|
-
compareOpen && comparePair !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(CompareDrawer, { left: comparePair[0], right: comparePair[1], onClose: closeCompare })
|
|
6031
|
+
comparePair !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(CompareDrawer, { left: comparePair[0], right: comparePair[1], onClose: closeCompare })
|
|
5779
6032
|
] });
|
|
5780
6033
|
}
|
|
5781
6034
|
object({
|