@tonyclaw/llm-inspector 1.15.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/cli.js +1 -0
- package/.output/nitro.json +1 -1
- package/.output/public/assets/index-BmkN9DxE.js +107 -0
- package/.output/public/assets/index-DPe3eOih.css +1 -0
- package/.output/public/assets/{main-BLYgekFx.js → main-BjnjXVBU.js} +1 -1
- package/.output/server/_libs/diff.mjs +2 -2
- package/.output/server/_ssr/{index-P66uoVEU.mjs → index-BIOEVAzU.mjs} +783 -588
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-DpLCKk51.mjs → router-THS9ptvu.mjs} +439 -177
- package/.output/server/{_tanstack-start-manifest_v-C9Wq6YdJ.mjs → _tanstack-start-manifest_v-BYhN7q_z.mjs} +1 -1
- package/.output/server/index.mjs +31 -31
- package/README.md +200 -113
- package/package.json +1 -1
- package/src/cli.ts +1 -0
- package/src/components/ProxyViewer.tsx +77 -85
- package/src/components/ProxyViewerContainer.tsx +148 -76
- package/src/components/providers/ImportWizardDialog.tsx +27 -3
- package/src/components/proxy-viewer/CompareDrawer.tsx +17 -4
- package/src/components/proxy-viewer/ConversationGroup.tsx +15 -47
- package/src/components/proxy-viewer/ConversationHeader.tsx +58 -5
- package/src/components/proxy-viewer/LogEntry.tsx +297 -329
- package/src/components/proxy-viewer/LogEntryHeader.tsx +126 -137
- package/src/components/proxy-viewer/ResponseView.tsx +14 -34
- package/src/components/proxy-viewer/StreamingChunkSequence.tsx +3 -3
- package/src/components/proxy-viewer/TurnGroup.tsx +25 -21
- package/src/components/proxy-viewer/diff/DiffView.tsx +5 -3
- package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +13 -9
- package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +3 -3
- package/src/components/proxy-viewer/formats/index.tsx +19 -10
- package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +7 -3
- package/src/components/proxy-viewer/log-formats/anthropic.ts +48 -0
- package/src/components/proxy-viewer/log-formats/index.ts +23 -0
- package/src/components/proxy-viewer/log-formats/openai.ts +40 -0
- package/src/components/proxy-viewer/log-formats/types.ts +33 -0
- package/src/components/proxy-viewer/log-formats/unknown.ts +14 -0
- package/src/components/proxy-viewer/viewerState.ts +58 -0
- package/src/components/ui/json-viewer.tsx +3 -3
- package/src/lib/objectUtils.ts +22 -0
- package/src/proxy/claudeCodeStrip.ts +5 -8
- package/src/proxy/formats/index.ts +1 -1
- package/src/proxy/formats/registry.ts +9 -0
- package/src/proxy/handler.ts +2 -8
- package/src/proxy/logIndex.ts +58 -43
- package/src/proxy/logger.ts +51 -27
- package/src/proxy/openaiOrphanToolStrip.ts +11 -17
- package/src/proxy/providerImporters.ts +245 -19
- package/src/proxy/providers.ts +20 -7
- package/src/proxy/schemas.ts +5 -9
- package/src/proxy/socketTracker.ts +109 -78
- package/src/proxy/store.ts +68 -83
- package/src/routes/api/logs.ts +31 -2
- package/styles/globals.css +22 -0
- package/.output/public/assets/index-CMuJQyt1.js +0 -105
- package/.output/public/assets/index-DciyfYBk.css +0 -1
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
|
|
2
|
-
import { C as CapturedLogSchema,
|
|
2
|
+
import { C as CapturedLogSchema, R as RuntimeConfigSchema, r as requestFormatForPath, c as createPendingProviderTestResults, P as ProviderTestResultsSchema, b as createFailedProviderTestResults, d as ProviderConfigSchema, s as stripClaudeCodeBillingHeader, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, a as AnthropicRequestSchema } from "./router-THS9ptvu.mjs";
|
|
3
3
|
import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
|
|
4
|
-
import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
|
|
5
4
|
import { c as clsx } from "../_libs/clsx.mjs";
|
|
6
5
|
import { t as twMerge } from "../_libs/tailwind-merge.mjs";
|
|
7
6
|
import { J as JSZip } from "../_libs/jszip.mjs";
|
|
8
7
|
import { c as cva } from "../_libs/class-variance-authority.mjs";
|
|
9
|
-
import { d as diffLines, a as diffJson } from "../_libs/diff.mjs";
|
|
10
8
|
import { R as Root, T as Trigger$2, C as Content, a as Close, b as Title, P as Portal$2, O as Overlay } from "../_libs/radix-ui__react-dialog.mjs";
|
|
9
|
+
import { d as diffJson, a as diffLines } from "../_libs/diff.mjs";
|
|
10
|
+
import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
|
|
11
11
|
import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Content2, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
|
|
12
12
|
import "../_libs/modelcontextprotocol__server.mjs";
|
|
13
|
-
import { D as Download, S as Settings, C as ChevronDown, a as Check, X, U as Upload, b as Scan, P as Plus, c as Copy, d as CircleAlert, e as ChevronUp, L as LoaderCircle, f as ChevronRight, g as User, h as Clock, M as MessageSquare, Z as Zap, R as Rows3, i as Columns2, j as Minus, k as Pencil, E as Equal, l as EyeOff, m as Eye, n as ExternalLink, o as RotateCw,
|
|
13
|
+
import { D as Download, S as Settings, C as ChevronDown, a as Check, X, U as Upload, b as Scan, P as Plus, c as Copy, d as CircleAlert, e as ChevronUp, L as LoaderCircle, f as ChevronRight, g as User, h as Clock, M as MessageSquare, Z as Zap, T as Trash2, R as Rows3, i as Columns2, j as Minus, k as Pencil, E as Equal, l as EyeOff, m as Eye, n as ExternalLink, o as RotateCw, G as GitCompareArrows, p as RotateCcw, q as CircleCheckBig, W as Wrench, r as Globe, F as FileTerminal, s as Radio, t as CircleQuestionMark, u as Server, v as Gauge, w as Lock, x as Wifi, y as WifiOff, A as ArrowUp, z as ArrowDown, B as TriangleAlert, H as CircleStop, I as ChevronsUp, J as ChevronsDown, K as Brain, N as Terminal } from "../_libs/lucide-react.mjs";
|
|
14
14
|
import { M as Markdown } from "../_libs/react-markdown.mjs";
|
|
15
|
-
import {
|
|
15
|
+
import { u as union, d as object, a as array, l as literal, b as string, n as number, c as boolean, _ as _enum } from "../_libs/zod.mjs";
|
|
16
16
|
import { P as Provider, R as Root3, T as Trigger$1, a as Portal$1, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
|
|
17
17
|
import { R as Root2$1, L as List, T as Trigger$3, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
|
|
18
18
|
import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
|
|
@@ -36,8 +36,9 @@ import "stream";
|
|
|
36
36
|
import "crypto";
|
|
37
37
|
import "../_libs/isbot.mjs";
|
|
38
38
|
import "node:fs";
|
|
39
|
-
import "node:path";
|
|
40
39
|
import "node:fs/promises";
|
|
40
|
+
import "node:buffer";
|
|
41
|
+
import "node:path";
|
|
41
42
|
import "../_libs/conf.mjs";
|
|
42
43
|
import "node:util";
|
|
43
44
|
import "node:process";
|
|
@@ -62,7 +63,6 @@ import "../_libs/uint8array-extras.mjs";
|
|
|
62
63
|
import "node:child_process";
|
|
63
64
|
import "../_libs/use-sync-external-store.mjs";
|
|
64
65
|
import "../_libs/dequal.mjs";
|
|
65
|
-
import "../_libs/tanstack__virtual-core.mjs";
|
|
66
66
|
import "../_libs/readable-stream.mjs";
|
|
67
67
|
import "events";
|
|
68
68
|
import "node:string_decoder";
|
|
@@ -99,6 +99,7 @@ import "../_libs/get-nonce.mjs";
|
|
|
99
99
|
import "../_libs/use-sidecar.mjs";
|
|
100
100
|
import "../_libs/use-callback-ref.mjs";
|
|
101
101
|
import "../_libs/aria-hidden.mjs";
|
|
102
|
+
import "../_libs/tanstack__virtual-core.mjs";
|
|
102
103
|
import "../_libs/radix-ui__number.mjs";
|
|
103
104
|
import "../_libs/radix-ui__react-collection.mjs";
|
|
104
105
|
import "../_libs/radix-ui__react-direction.mjs";
|
|
@@ -333,38 +334,10 @@ async function exportLogsAsZip(logs) {
|
|
|
333
334
|
document.body.removeChild(anchor);
|
|
334
335
|
URL.revokeObjectURL(url);
|
|
335
336
|
}
|
|
336
|
-
const version = "1.
|
|
337
|
+
const version = "1.16.0";
|
|
337
338
|
const packageJson = {
|
|
338
339
|
version
|
|
339
340
|
};
|
|
340
|
-
function isRecord(value) {
|
|
341
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
342
|
-
}
|
|
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 (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 (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
|
-
}
|
|
364
|
-
}
|
|
365
|
-
function isTurnBoundary(stopReason) {
|
|
366
|
-
return stopReason === "end_turn" || stopReason === "stop";
|
|
367
|
-
}
|
|
368
341
|
const badgeVariants = cva(
|
|
369
342
|
"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",
|
|
370
343
|
{
|
|
@@ -400,6 +373,156 @@ function Badge({
|
|
|
400
373
|
}
|
|
401
374
|
);
|
|
402
375
|
}
|
|
376
|
+
function Dialog({
|
|
377
|
+
...props
|
|
378
|
+
}) {
|
|
379
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Root, { "data-slot": "dialog", ...props });
|
|
380
|
+
}
|
|
381
|
+
function DialogTrigger({
|
|
382
|
+
...props
|
|
383
|
+
}) {
|
|
384
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger$2, { "data-slot": "dialog-trigger", ...props });
|
|
385
|
+
}
|
|
386
|
+
function DialogPortal({
|
|
387
|
+
...props
|
|
388
|
+
}) {
|
|
389
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$2, { "data-slot": "dialog-portal", ...props });
|
|
390
|
+
}
|
|
391
|
+
function DialogOverlay({
|
|
392
|
+
className,
|
|
393
|
+
...props
|
|
394
|
+
}) {
|
|
395
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
396
|
+
Overlay,
|
|
397
|
+
{
|
|
398
|
+
"data-slot": "dialog-overlay",
|
|
399
|
+
className: cn(
|
|
400
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
401
|
+
className
|
|
402
|
+
),
|
|
403
|
+
...props
|
|
404
|
+
}
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
function DialogContent({
|
|
408
|
+
className,
|
|
409
|
+
children,
|
|
410
|
+
...props
|
|
411
|
+
}) {
|
|
412
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogPortal, { children: [
|
|
413
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogOverlay, {}),
|
|
414
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
415
|
+
Content,
|
|
416
|
+
{
|
|
417
|
+
"data-slot": "dialog-content",
|
|
418
|
+
className: cn(
|
|
419
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg",
|
|
420
|
+
className
|
|
421
|
+
),
|
|
422
|
+
...props,
|
|
423
|
+
children: [
|
|
424
|
+
children,
|
|
425
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
|
|
426
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "size-4" }),
|
|
427
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Close" })
|
|
428
|
+
] })
|
|
429
|
+
]
|
|
430
|
+
}
|
|
431
|
+
)
|
|
432
|
+
] });
|
|
433
|
+
}
|
|
434
|
+
function DialogHeader({ className, ...props }) {
|
|
435
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
436
|
+
"div",
|
|
437
|
+
{
|
|
438
|
+
"data-slot": "dialog-header",
|
|
439
|
+
className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className),
|
|
440
|
+
...props
|
|
441
|
+
}
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
function DialogTitle({
|
|
445
|
+
className,
|
|
446
|
+
...props
|
|
447
|
+
}) {
|
|
448
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
449
|
+
Title,
|
|
450
|
+
{
|
|
451
|
+
"data-slot": "dialog-title",
|
|
452
|
+
className: cn("text-lg font-semibold leading-none tracking-tight", className),
|
|
453
|
+
...props
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
const buttonVariants = cva(
|
|
458
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
459
|
+
{
|
|
460
|
+
variants: {
|
|
461
|
+
variant: {
|
|
462
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
463
|
+
destructive: "bg-destructive text-white hover:bg-destructive/90",
|
|
464
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
465
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
466
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
467
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
468
|
+
},
|
|
469
|
+
size: {
|
|
470
|
+
default: "h-9 px-4 py-2",
|
|
471
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
472
|
+
lg: "h-10 rounded-md px-8",
|
|
473
|
+
icon: "size-9"
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
defaultVariants: {
|
|
477
|
+
variant: "default",
|
|
478
|
+
size: "default"
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
);
|
|
482
|
+
function Button({
|
|
483
|
+
className,
|
|
484
|
+
variant,
|
|
485
|
+
size,
|
|
486
|
+
...props
|
|
487
|
+
}) {
|
|
488
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
489
|
+
"button",
|
|
490
|
+
{
|
|
491
|
+
"data-slot": "button",
|
|
492
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
493
|
+
...props
|
|
494
|
+
}
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
function ConfirmDialog({
|
|
498
|
+
open,
|
|
499
|
+
onOpenChange,
|
|
500
|
+
title,
|
|
501
|
+
description,
|
|
502
|
+
confirmLabel = "Confirm",
|
|
503
|
+
variant = "default",
|
|
504
|
+
onConfirm
|
|
505
|
+
}) {
|
|
506
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { children: [
|
|
507
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(DialogTitle, { children: title }) }),
|
|
508
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground", children: description }),
|
|
509
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [
|
|
510
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outline", size: "sm", onClick: () => onOpenChange(false), children: "Cancel" }),
|
|
511
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
512
|
+
Button,
|
|
513
|
+
{
|
|
514
|
+
variant,
|
|
515
|
+
size: "sm",
|
|
516
|
+
onClick: () => {
|
|
517
|
+
onConfirm();
|
|
518
|
+
onOpenChange(false);
|
|
519
|
+
},
|
|
520
|
+
children: confirmLabel
|
|
521
|
+
}
|
|
522
|
+
)
|
|
523
|
+
] })
|
|
524
|
+
] }) });
|
|
525
|
+
}
|
|
403
526
|
const API_FORMAT_LABELS = {
|
|
404
527
|
anthropic: "Anthropic",
|
|
405
528
|
openai: "OpenAI",
|
|
@@ -421,8 +544,15 @@ function ConversationHeader({
|
|
|
421
544
|
onToggle,
|
|
422
545
|
hideApiFormat = false,
|
|
423
546
|
isLoading = false,
|
|
424
|
-
userAgent
|
|
547
|
+
userAgent,
|
|
548
|
+
onClear
|
|
425
549
|
}) {
|
|
550
|
+
const [confirmOpen, setConfirmOpen] = reactExports.useState(false);
|
|
551
|
+
const handleClearClick = (e) => {
|
|
552
|
+
e.stopPropagation();
|
|
553
|
+
if (onClear === void 0) return;
|
|
554
|
+
setConfirmOpen(true);
|
|
555
|
+
};
|
|
426
556
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
427
557
|
"div",
|
|
428
558
|
{
|
|
@@ -432,10 +562,11 @@ function ConversationHeader({
|
|
|
432
562
|
"flex items-center gap-3 px-3 py-2 cursor-pointer transition-colors",
|
|
433
563
|
"hover:bg-muted/50",
|
|
434
564
|
"select-none",
|
|
435
|
-
"border border-border rounded-lg mb-2 bg-
|
|
565
|
+
"border border-border rounded-lg mb-2 bg-background sticky top-0 z-10"
|
|
436
566
|
),
|
|
437
567
|
onClick: onToggle,
|
|
438
568
|
onKeyDown: (e) => {
|
|
569
|
+
if (e.target !== e.currentTarget) return;
|
|
439
570
|
if (e.key === "Enter" || e.key === " ") {
|
|
440
571
|
e.preventDefault();
|
|
441
572
|
onToggle();
|
|
@@ -499,7 +630,32 @@ function ConversationHeader({
|
|
|
499
630
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-amber-400", children: formatTokens(totalOutputTokens) })
|
|
500
631
|
] })
|
|
501
632
|
] }),
|
|
502
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" })
|
|
633
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
|
|
634
|
+
onClear !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
635
|
+
"button",
|
|
636
|
+
{
|
|
637
|
+
type: "button",
|
|
638
|
+
onClick: handleClearClick,
|
|
639
|
+
"aria-label": `Clear group (${totalCalls} request${totalCalls !== 1 ? "s" : ""})`,
|
|
640
|
+
title: "Clear this group",
|
|
641
|
+
className: "text-muted-foreground hover:text-foreground transition-colors shrink-0 inline-flex items-center justify-center size-6 rounded hover:bg-muted cursor-pointer",
|
|
642
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" })
|
|
643
|
+
}
|
|
644
|
+
),
|
|
645
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
646
|
+
ConfirmDialog,
|
|
647
|
+
{
|
|
648
|
+
open: confirmOpen,
|
|
649
|
+
onOpenChange: setConfirmOpen,
|
|
650
|
+
title: "Clear this group?",
|
|
651
|
+
description: `This will remove ${totalCalls} request${totalCalls !== 1 ? "s" : ""} from this conversation. This action cannot be undone.`,
|
|
652
|
+
confirmLabel: "Clear",
|
|
653
|
+
variant: "destructive",
|
|
654
|
+
onConfirm: () => {
|
|
655
|
+
onClear?.();
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
)
|
|
503
659
|
]
|
|
504
660
|
}
|
|
505
661
|
);
|
|
@@ -522,11 +678,15 @@ function hasMixedApiFormat(logs) {
|
|
|
522
678
|
return false;
|
|
523
679
|
}
|
|
524
680
|
function getConversationId(log) {
|
|
525
|
-
if (log.
|
|
681
|
+
if (log.isTest === true) return "provider-test";
|
|
682
|
+
if (log.sessionId !== null && log.sessionId !== "" && log.sessionId !== void 0) {
|
|
526
683
|
return log.sessionId;
|
|
527
684
|
}
|
|
528
|
-
const
|
|
529
|
-
const
|
|
685
|
+
const hasPid = log.clientPid !== null && log.clientPid !== void 0;
|
|
686
|
+
const hasFolder = log.clientProjectFolder !== null && log.clientProjectFolder !== void 0;
|
|
687
|
+
if (!hasPid && !hasFolder) return "default";
|
|
688
|
+
const pid = hasPid ? `PID:${log.clientPid}` : "unknown";
|
|
689
|
+
const folder = hasFolder ? log.clientProjectFolder : "no-folder";
|
|
530
690
|
return `${pid}|${folder}`;
|
|
531
691
|
}
|
|
532
692
|
function groupLogsByConversation(logs) {
|
|
@@ -552,45 +712,33 @@ function groupLogsByConversation(logs) {
|
|
|
552
712
|
result.sort((a, b) => (a.logs[0]?.timestamp ?? "").localeCompare(b.logs[0]?.timestamp ?? ""));
|
|
553
713
|
return result;
|
|
554
714
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
sm: "h-8 rounded-md px-3 text-xs",
|
|
570
|
-
lg: "h-10 rounded-md px-8",
|
|
571
|
-
icon: "size-9"
|
|
715
|
+
function isRecord$1(value) {
|
|
716
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
717
|
+
}
|
|
718
|
+
function extractStopReason(log) {
|
|
719
|
+
if (log.responseText === null) return null;
|
|
720
|
+
try {
|
|
721
|
+
let json = JSON.parse(log.responseText);
|
|
722
|
+
if (typeof json === "string") {
|
|
723
|
+
json = JSON.parse(json);
|
|
724
|
+
}
|
|
725
|
+
if (!isRecord$1(json)) return null;
|
|
726
|
+
if (typeof json.stop_reason === "string") {
|
|
727
|
+
if (json.stop_reason === "end_turn" || json.stop_reason === "tool_use") {
|
|
728
|
+
return json.stop_reason;
|
|
572
729
|
}
|
|
573
|
-
|
|
574
|
-
defaultVariants: {
|
|
575
|
-
variant: "default",
|
|
576
|
-
size: "default"
|
|
730
|
+
return null;
|
|
577
731
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
function Button({
|
|
581
|
-
className,
|
|
582
|
-
variant,
|
|
583
|
-
size,
|
|
584
|
-
...props
|
|
585
|
-
}) {
|
|
586
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
587
|
-
"button",
|
|
588
|
-
{
|
|
589
|
-
"data-slot": "button",
|
|
590
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
591
|
-
...props
|
|
732
|
+
if (Array.isArray(json.choices) && json.choices.length > 0 && isRecord$1(json.choices[0]) && typeof json.choices[0].finish_reason === "string" && json.choices[0].finish_reason === "stop") {
|
|
733
|
+
return "stop";
|
|
592
734
|
}
|
|
593
|
-
|
|
735
|
+
return null;
|
|
736
|
+
} catch {
|
|
737
|
+
return null;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
function isTurnBoundary(stopReason) {
|
|
741
|
+
return stopReason === "end_turn" || stopReason === "stop";
|
|
594
742
|
}
|
|
595
743
|
function classifyValue(value) {
|
|
596
744
|
if (value === null) return "null";
|
|
@@ -779,7 +927,7 @@ function ExpandCollapseButton({
|
|
|
779
927
|
}
|
|
780
928
|
);
|
|
781
929
|
}
|
|
782
|
-
|
|
930
|
+
const JsonNode = reactExports.memo(function JsonNode2({
|
|
783
931
|
name,
|
|
784
932
|
value,
|
|
785
933
|
level,
|
|
@@ -853,7 +1001,7 @@ function JsonNode({
|
|
|
853
1001
|
),
|
|
854
1002
|
expandable && expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "pl-4", children: [
|
|
855
1003
|
getEntries(value).map(([key, childValue]) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
856
|
-
|
|
1004
|
+
JsonNode2,
|
|
857
1005
|
{
|
|
858
1006
|
name: key,
|
|
859
1007
|
value: childValue,
|
|
@@ -866,7 +1014,7 @@ function JsonNode({
|
|
|
866
1014
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground py-0.5 px-1", children: closeBracket })
|
|
867
1015
|
] }, childResetKey)
|
|
868
1016
|
] });
|
|
869
|
-
}
|
|
1017
|
+
});
|
|
870
1018
|
function JsonViewer({
|
|
871
1019
|
data,
|
|
872
1020
|
defaultExpandDepth = 2,
|
|
@@ -1112,7 +1260,7 @@ function kindClass(kind) {
|
|
|
1112
1260
|
}
|
|
1113
1261
|
return "text-foreground/80";
|
|
1114
1262
|
}
|
|
1115
|
-
function
|
|
1263
|
+
const DiffViewInner = function DiffView2({ result, emptyLabel }) {
|
|
1116
1264
|
const [mode, setMode] = reactExports.useState("unified");
|
|
1117
1265
|
const scrollRef = reactExports.useRef(null);
|
|
1118
1266
|
const virtualizer = useVirtualizer({
|
|
@@ -1189,7 +1337,7 @@ function DiffView({ result, emptyLabel }) {
|
|
|
1189
1337
|
}
|
|
1190
1338
|
)
|
|
1191
1339
|
] });
|
|
1192
|
-
}
|
|
1340
|
+
};
|
|
1193
1341
|
function UnifiedRows({
|
|
1194
1342
|
virtualizer,
|
|
1195
1343
|
lines
|
|
@@ -1347,6 +1495,7 @@ function SplitRows({ lines }) {
|
|
|
1347
1495
|
idx
|
|
1348
1496
|
)) });
|
|
1349
1497
|
}
|
|
1498
|
+
const DiffView = reactExports.memo(DiffViewInner);
|
|
1350
1499
|
const AnthropicLogoSvg = "data:image/svg+xml,%3csvg%20height='2500'%20viewBox='0%206.603%201192.672%201193.397'%20width='2500'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='m233.96%20800.215%20234.684-131.678%203.947-11.436-3.947-6.363h-11.436l-39.221-2.416-134.094-3.624-116.296-4.832-112.67-6.04-28.35-6.04-26.577-35.035%202.738-17.477%2023.84-16.027%2034.147%202.98%2075.463%205.155%20113.235%207.812%2082.147%204.832%20121.692%2012.644h19.329l2.738-7.812-6.604-4.832-5.154-4.832-117.182-79.41-126.845-83.92-66.443-48.321-35.92-24.484-18.12-22.953-7.813-50.093%2032.618-35.92%2043.812%202.98%2011.195%202.98%2044.375%2034.147%2094.792%2073.37%20123.786%2091.167%2018.12%2015.06%207.249-5.154.886-3.624-8.135-13.61-67.329-121.692-71.838-123.785-31.974-51.302-8.456-30.765c-2.98-12.645-5.154-23.275-5.154-36.242l37.127-50.416%2020.537-6.604%2049.53%206.604%2020.86%2018.121%2030.765%2070.39%2049.852%20110.818%2077.315%20150.684%2022.631%2044.698%2012.08%2041.396%204.51%2012.645h7.813v-7.248l6.362-84.886%2011.759-104.215%2011.436-134.094%203.946-37.772%2018.685-45.262%2037.127-24.482%2028.994%2013.852%2023.839%2034.148-3.303%2022.067-14.174%2092.134-27.785%20144.323-18.121%2096.644h10.55l12.08-12.08%2048.887-64.913%2082.147-102.685%2036.242-40.752%2042.282-45.02%2027.14-21.423h51.303l37.772%2056.135-16.913%2057.986-52.832%2067.007-43.812%2056.779-62.82%2084.563-39.22%2067.651%203.623%205.396%209.343-.886%20141.906-30.201%2076.671-13.852%2091.49-15.705%2041.396%2019.329%204.51%2019.65-16.269%2040.189-97.852%2024.16-114.764%2022.954-170.9%2040.43-2.093%201.53%202.416%202.98%2076.993%207.248%2032.94%201.771h80.617l150.12%2011.195%2039.222%2025.933%2023.517%2031.732-3.946%2024.16-60.403%2030.766-81.503-19.33-190.228-45.26-65.235-16.27h-9.02v5.397l54.362%2053.154%2099.624%2089.96%20124.752%20115.973%206.362%2028.671-16.027%2022.63-16.912-2.415-109.611-82.47-42.282-37.127-95.758-80.618h-6.363v8.456l22.067%2032.296%20116.537%20175.167%206.04%2053.719-8.456%2017.476-30.201%2010.55-33.181-6.04-68.215-95.758-70.39-107.84-56.778-96.644-6.926%203.947-33.503%20360.886-15.705%2018.443-36.243%2013.852-30.201-22.953-16.027-37.127%2016.027-73.37%2019.329-95.758%2015.704-76.107%2014.175-94.55%208.456-31.41-.563-2.094-6.927.886-71.275%2097.852-108.402%20146.497-85.772%2091.812-20.537%208.134-35.597-18.443%203.301-32.94%2019.893-29.315%20118.712-151.007%2071.597-93.583%2046.228-54.04-.322-7.813h-2.738l-315.302%20204.725-56.135%207.248-24.16-22.63%202.98-37.128%2011.435-12.08%2094.792-65.236-.322.323z'%20fill='%23d97757'/%3e%3c/svg%3e";
|
|
1351
1500
|
const OpenAILogoSvg = "data:image/svg+xml,%3csvg%20height='2500'%20viewBox='-1%20-.1%20949.1%20959.8'%20width='2474'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='m925.8%20456.3c10.4%2023.2%2017%2048%2019.7%2073.3%202.6%2025.3%201.3%2050.9-4.1%2075.8-5.3%2024.9-14.5%2048.8-27.3%2070.8-8.4%2014.7-18.3%2028.5-29.7%2041.2-11.3%2012.6-23.9%2024-37.6%2034-13.8%2010-28.5%2018.4-44.1%2025.3-15.5%206.8-31.7%2012-48.3%2015.4-7.8%2024.2-19.4%2047.1-34.4%2067.7-14.9%2020.6-33%2038.7-53.6%2053.6-20.6%2015-43.4%2026.6-67.6%2034.4-24.2%207.9-49.5%2011.8-75%2011.8-16.9.1-33.9-1.7-50.5-5.1-16.5-3.5-32.7-8.8-48.2-15.7s-30.2-15.5-43.9-25.5c-13.6-10-26.2-21.5-37.4-34.2-25%205.4-50.6%206.7-75.9%204.1-25.3-2.7-50.1-9.3-73.4-19.7-23.2-10.3-44.7-24.3-63.6-41.4s-35-37.1-47.7-59.1c-8.5-14.7-15.5-30.2-20.8-46.3s-8.8-32.7-10.6-49.6c-1.8-16.8-1.7-33.8.1-50.7%201.8-16.8%205.5-33.4%2010.8-49.5-17-18.9-31-40.4-41.4-63.6-10.3-23.3-17-48-19.6-73.3-2.7-25.3-1.3-50.9%204-75.8s14.5-48.8%2027.3-70.8c8.4-14.7%2018.3-28.6%2029.6-41.2s24-24%2037.7-34%2028.5-18.5%2044-25.3c15.6-6.9%2031.8-12%2048.4-15.4%207.8-24.3%2019.4-47.1%2034.3-67.7%2015-20.6%2033.1-38.7%2053.7-53.7%2020.6-14.9%2043.4-26.5%2067.6-34.4%2024.2-7.8%2049.5-11.8%2075-11.7%2016.9-.1%2033.9%201.6%2050.5%205.1s32.8%208.7%2048.3%2015.6c15.5%207%2030.2%2015.5%2043.9%2025.5%2013.7%2010.1%2026.3%2021.5%2037.5%2034.2%2024.9-5.3%2050.5-6.6%2075.8-4s50%209.3%2073.3%2019.6c23.2%2010.4%2044.7%2024.3%2063.6%2041.4%2018.9%2017%2035%2036.9%2047.7%2059%208.5%2014.6%2015.5%2030.1%2020.8%2046.3%205.3%2016.1%208.9%2032.7%2010.6%2049.6%201.8%2016.9%201.8%2033.9-.1%2050.8-1.8%2016.9-5.5%2033.5-10.8%2049.6%2017.1%2018.9%2031%2040.3%2041.4%2063.6zm-333.2%20426.9c21.8-9%2041.6-22.3%2058.3-39s30-36.5%2039-58.4c9-21.8%2013.7-45.2%2013.7-68.8v-223q-.1-.3-.2-.7-.1-.3-.3-.6-.2-.3-.5-.5-.3-.3-.6-.4l-80.7-46.6v269.4c0%202.7-.4%205.5-1.1%208.1-.7%202.7-1.7%205.2-3.1%207.6s-3%204.6-5%206.5a32.1%2032.1%200%200%201%20-6.5%205l-191.1%20110.3c-1.6%201-4.3%202.4-5.7%203.2%207.9%206.7%2016.5%2012.6%2025.5%2017.8%209.1%205.2%2018.5%209.6%2028.3%2013.2%209.8%203.5%2019.9%206.2%2030.1%208%2010.3%201.8%2020.7%202.7%2031.1%202.7%2023.6%200%2047-4.7%2068.8-13.8zm-455.1-151.4c11.9%2020.5%2027.6%2038.3%2046.3%2052.7%2018.8%2014.4%2040.1%2024.9%2062.9%2031s46.6%207.7%2070%204.6%2045.9-10.7%2066.4-22.5l193.2-111.5.5-.5q.2-.2.3-.6.2-.3.3-.6v-94l-233.2%20134.9c-2.4%201.4-4.9%202.4-7.5%203.2-2.7.7-5.4%201-8.2%201-2.7%200-5.4-.3-8.1-1-2.6-.8-5.2-1.8-7.6-3.2l-191.1-110.4c-1.7-1-4.2-2.5-5.6-3.4-1.8%2010.3-2.7%2020.7-2.7%2031.1s1%2020.8%202.8%2031.1c1.8%2010.2%204.6%2020.3%208.1%2030.1%203.6%209.8%208%2019.2%2013.2%2028.2zm-50.2-417c-11.8%2020.5-19.4%2043.1-22.5%2066.5s-1.5%2047.1%204.6%2070c6.1%2022.8%2016.6%2044.1%2031%2062.9%2014.4%2018.7%2032.3%2034.4%2052.7%2046.2l193.1%20111.6q.3.1.7.2h.7q.4%200%20.7-.2.3-.1.6-.3l81-46.8-233.2-134.6c-2.3-1.4-4.5-3.1-6.5-5a32.1%2032.1%200%200%201%20-5-6.5c-1.3-2.4-2.4-4.9-3.1-7.6-.7-2.6-1.1-5.3-1-8.1v-227.1c-9.8%203.6-19.3%208-28.3%2013.2-9%205.3-17.5%2011.3-25.5%2018-7.9%206.7-15.3%2014.1-22%2022.1-6.7%207.9-12.6%2016.5-17.8%2025.5zm663.3%20154.4c2.4%201.4%204.6%203%206.6%205%201.9%201.9%203.6%204.1%205%206.5%201.3%202.4%202.4%205%203.1%207.6.6%202.7%201%205.4.9%208.2v227.1c32.1-11.8%2060.1-32.5%2080.8-59.7%2020.8-27.2%2033.3-59.7%2036.2-93.7s-3.9-68.2-19.7-98.5-39.9-55.5-69.5-72.5l-193.1-111.6q-.3-.1-.7-.2h-.7q-.3.1-.7.2-.3.1-.6.3l-80.6%2046.6%20233.2%20134.7zm80.5-121h-.1v.1zm-.1-.1c5.8-33.6%201.9-68.2-11.3-99.7-13.1-31.5-35-58.6-63-78.2-28-19.5-61-30.7-95.1-32.2-34.2-1.4-68%206.9-97.6%2023.9l-193.1%20111.5q-.3.2-.5.5l-.4.6q-.1.3-.2.7-.1.3-.1.7v93.2l233.2-134.7c2.4-1.4%205-2.4%207.6-3.2%202.7-.7%205.4-1%208.1-1%202.8%200%205.5.3%208.2%201%202.6.8%205.1%201.8%207.5%203.2l191.1%20110.4c1.7%201%204.2%202.4%205.6%203.3zm-505.3-103.2c0-2.7.4-5.4%201.1-8.1.7-2.6%201.7-5.2%203.1-7.6%201.4-2.3%203-4.5%205-6.5%201.9-1.9%204.1-3.6%206.5-4.9l191.1-110.3c1.8-1.1%204.3-2.5%205.7-3.2-26.2-21.9-58.2-35.9-92.1-40.2-33.9-4.4-68.3%201-99.2%2015.5-31%2014.5-57.2%2037.6-75.5%2066.4-18.3%2028.9-28%2062.3-28%2096.5v223q.1.4.2.7.1.3.3.6.2.3.5.6.2.2.6.4l80.7%2046.6zm43.8%20294.7%20103.9%2060%20103.9-60v-119.9l-103.8-60-103.9%2060z'/%3e%3c/svg%3e";
|
|
1352
1501
|
const DeepSeekLogoSvg = "data:image/svg+xml,%3csvg%20fill='none'%20height='1320'%20viewBox='3.771%206.973%2023.993%2017.652'%20width='2500'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='m27.501%208.469c-.252-.123-.36.111-.508.23-.05.04-.093.09-.135.135-.368.395-.797.652-1.358.621-.821-.045-1.521.213-2.14.842-.132-.776-.57-1.238-1.235-1.535-.349-.155-.701-.309-.944-.645-.171-.238-.217-.504-.303-.765-.054-.159-.108-.32-.29-.348-.197-.031-.274.135-.352.273-.31.567-.43%201.192-.419%201.825.028%201.421.628%202.554%201.82%203.36.136.093.17.186.128.321-.081.278-.178.547-.264.824-.054.178-.135.217-.324.14a5.448%205.448%200%200%201%20-1.719-1.169c-.848-.82-1.614-1.726-2.57-2.435-.225-.166-.449-.32-.681-.467-.976-.95.128-1.729.383-1.82.267-.096.093-.428-.77-.424s-1.653.293-2.659.677a2.782%202.782%200%200%201%20-.46.135%209.554%209.554%200%200%200%20-2.853-.1c-1.866.21-3.356%201.092-4.452%202.6-1.315%201.81-1.625%203.87-1.246%206.018.399%202.261%201.552%204.136%203.326%205.601%201.837%201.518%203.955%202.262%206.37%202.12%201.466-.085%203.1-.282%204.942-1.842.465.23.952.322%201.762.392.623.059%201.223-.031%201.687-.127.728-.154.677-.828.414-.953-2.132-.994-1.665-.59-2.09-.916%201.084-1.285%202.717-2.619%203.356-6.94.05-.343.007-.558%200-.837-.004-.168.034-.235.228-.254a4.084%204.084%200%200%200%201.529-.47c1.382-.757%201.938-1.997%202.07-3.485.02-.227-.004-.463-.243-.582zm-12.041%2013.391c-2.067-1.627-3.07-2.162-3.483-2.138-.387.021-.318.465-.233.754.089.285.205.482.368.732.113.166.19.414-.112.598-.666.414-1.823-.139-1.878-.166-1.347-.793-2.473-1.842-3.267-3.276-.765-1.38-1.21-2.861-1.284-4.441-.02-.383.093-.518.472-.586a4.692%204.692%200%200%201%201.514-.04c2.109.31%203.905%201.255%205.41%202.749.86.853%201.51%201.871%202.18%202.865.711%201.057%201.478%202.063%202.454%202.887.343.289.619.51.881.672-.792.088-2.117.107-3.022-.61zm.99-6.38a.304.304%200%201%201%20.609%200c0%20.17-.136.304-.306.304a.3.3%200%200%201%20-.303-.305zm3.077%201.581c-.197.08-.394.15-.584.159a1.246%201.246%200%200%201%20-.79-.252c-.27-.227-.463-.354-.546-.752a1.752%201.752%200%200%201%20.016-.582c.07-.324-.008-.531-.235-.72-.187-.155-.422-.196-.682-.196a.551.551%200%200%201%20-.252-.078c-.108-.055-.197-.19-.112-.356.027-.053.159-.183.19-.207.352-.201.758-.135%201.134.016.349.142.611.404.99.773.388.448.457.573.678.906.174.264.333.534.441.842.066.192-.02.35-.248.448z'%20fill='%234d6bfe'/%3e%3c/svg%3e";
|
|
@@ -1461,13 +1610,14 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1461
1610
|
}) {
|
|
1462
1611
|
const statusCategory = getStatusCategory(log.responseStatus);
|
|
1463
1612
|
const hasTokens = log.inputTokens !== null || log.outputTokens !== null;
|
|
1464
|
-
|
|
1613
|
+
const toolNamesJoined = reactExports.useMemo(() => responseToolNames?.join(", ") ?? null, [responseToolNames]);
|
|
1614
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1465
1615
|
"div",
|
|
1466
1616
|
{
|
|
1467
1617
|
role: "button",
|
|
1468
1618
|
tabIndex: 0,
|
|
1469
1619
|
className: cn(
|
|
1470
|
-
"flex items-center gap-2
|
|
1620
|
+
"flex items-center gap-2 px-3 py-1 cursor-pointer transition-colors",
|
|
1471
1621
|
"hover:bg-muted/50",
|
|
1472
1622
|
"select-none"
|
|
1473
1623
|
),
|
|
@@ -1483,15 +1633,15 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1483
1633
|
"#",
|
|
1484
1634
|
log.id
|
|
1485
1635
|
] }),
|
|
1486
|
-
log.model !== null && /* @__PURE__ */ jsxRuntimeExports.
|
|
1636
|
+
log.model !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1487
1637
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderLogo, { provider: detectProvider(log.model), className: "size-4" }) }) }),
|
|
1488
1638
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: log.model })
|
|
1489
|
-
] })
|
|
1639
|
+
] }),
|
|
1490
1640
|
statusCategory !== "success" && /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: statusCategory === "server_error" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1491
1641
|
Badge,
|
|
1492
1642
|
{
|
|
1493
1643
|
variant: "destructive",
|
|
1494
|
-
className: "text-[10px] px-1.5 py-0 h-
|
|
1644
|
+
className: "text-[10px] px-1.5 py-0 h-4 font-mono tabular-nums",
|
|
1495
1645
|
children: log.responseStatus
|
|
1496
1646
|
}
|
|
1497
1647
|
) : statusCategory === "pending" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -1499,7 +1649,7 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1499
1649
|
{
|
|
1500
1650
|
variant: "outline",
|
|
1501
1651
|
className: cn(
|
|
1502
|
-
"text-[10px] px-1.5 py-0 h-
|
|
1652
|
+
"text-[10px] px-1.5 py-0 h-4 font-mono tabular-nums",
|
|
1503
1653
|
STATUS_BADGE_CLASSES[statusCategory]
|
|
1504
1654
|
),
|
|
1505
1655
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3 animate-spin" })
|
|
@@ -1509,7 +1659,7 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1509
1659
|
{
|
|
1510
1660
|
variant: "outline",
|
|
1511
1661
|
className: cn(
|
|
1512
|
-
"text-[10px] px-1.5 py-0 h-
|
|
1662
|
+
"text-[10px] px-1.5 py-0 h-4 font-mono tabular-nums",
|
|
1513
1663
|
STATUS_BADGE_CLASSES[statusCategory]
|
|
1514
1664
|
),
|
|
1515
1665
|
children: log.responseStatus
|
|
@@ -1522,10 +1672,16 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1522
1672
|
hasTokens && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
|
|
1523
1673
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
|
|
1524
1674
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
1525
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1526
|
-
"
|
|
1527
|
-
|
|
1528
|
-
|
|
1675
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1676
|
+
"span",
|
|
1677
|
+
{
|
|
1678
|
+
className: log.inputTokens !== null ? "text-blue-400" : "text-muted-foreground",
|
|
1679
|
+
children: [
|
|
1680
|
+
"IN ",
|
|
1681
|
+
log.inputTokens !== null ? formatTokens(log.inputTokens) : "—"
|
|
1682
|
+
]
|
|
1683
|
+
}
|
|
1684
|
+
),
|
|
1529
1685
|
" / ",
|
|
1530
1686
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1531
1687
|
"span",
|
|
@@ -1539,7 +1695,7 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1539
1695
|
)
|
|
1540
1696
|
] })
|
|
1541
1697
|
] }),
|
|
1542
|
-
log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.
|
|
1698
|
+
log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1543
1699
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
|
|
1544
1700
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.creation ?? null }),
|
|
1545
1701
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-emerald-400", children: [
|
|
@@ -1548,8 +1704,8 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1548
1704
|
] })
|
|
1549
1705
|
] }) }),
|
|
1550
1706
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens cached for reuse, reducing future API cost" })
|
|
1551
|
-
] })
|
|
1552
|
-
log.cacheReadInputTokens !== null && log.cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.
|
|
1707
|
+
] }),
|
|
1708
|
+
log.cacheReadInputTokens !== null && log.cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1553
1709
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
|
|
1554
1710
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.read ?? null }),
|
|
1555
1711
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
|
|
@@ -1558,31 +1714,31 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1558
1714
|
] })
|
|
1559
1715
|
] }) }),
|
|
1560
1716
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens served from cache, reducing API cost" })
|
|
1561
|
-
] })
|
|
1562
|
-
messageCount !== null && /* @__PURE__ */ jsxRuntimeExports.
|
|
1717
|
+
] }),
|
|
1718
|
+
messageCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1563
1719
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
1564
1720
|
/* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3" }),
|
|
1565
1721
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: messageCount })
|
|
1566
1722
|
] }) }),
|
|
1567
1723
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Number of messages in the conversation" })
|
|
1568
|
-
] })
|
|
1569
|
-
toolCount !== null && /* @__PURE__ */ jsxRuntimeExports.
|
|
1724
|
+
] }),
|
|
1725
|
+
toolCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1570
1726
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
1571
1727
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3" }),
|
|
1572
1728
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: toolCount })
|
|
1573
1729
|
] }) }),
|
|
1574
1730
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Number of tools defined in the request" })
|
|
1575
|
-
] })
|
|
1576
|
-
responseToolNames !== null && responseToolNames.length > 0 && /* @__PURE__ */ jsxRuntimeExports.
|
|
1731
|
+
] }),
|
|
1732
|
+
responseToolNames !== null && responseToolNames.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1577
1733
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-amber-400/80 text-xs shrink-0", children: [
|
|
1578
1734
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3" }),
|
|
1579
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[160px]", children:
|
|
1735
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[160px]", children: toolNamesJoined })
|
|
1580
1736
|
] }) }),
|
|
1581
1737
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(TooltipContent, { children: [
|
|
1582
1738
|
"Tools called by model: ",
|
|
1583
|
-
|
|
1739
|
+
toolNamesJoined
|
|
1584
1740
|
] })
|
|
1585
|
-
] })
|
|
1741
|
+
] }),
|
|
1586
1742
|
log.origin !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1587
1743
|
"span",
|
|
1588
1744
|
{
|
|
@@ -1594,7 +1750,7 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1594
1750
|
]
|
|
1595
1751
|
}
|
|
1596
1752
|
),
|
|
1597
|
-
(log.clientPid !== null || log.clientProjectFolder !== null) && /* @__PURE__ */ jsxRuntimeExports.
|
|
1753
|
+
(log.clientPid !== null || log.clientProjectFolder !== null) && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1598
1754
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "hidden xl:flex items-center gap-1 text-purple-400/80 text-xs shrink-0", children: [
|
|
1599
1755
|
/* @__PURE__ */ jsxRuntimeExports.jsx(FileTerminal, { className: "size-3" }),
|
|
1600
1756
|
log.clientProjectFolder !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: log.clientProjectFolder }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
@@ -1603,98 +1759,17 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1603
1759
|
] })
|
|
1604
1760
|
] }) }),
|
|
1605
1761
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: log.clientCwd !== null ? `PID: ${log.clientPid ?? "?"} CWD: ${log.clientCwd}` : `Process ID: ${log.clientPid ?? "?"}` })
|
|
1606
|
-
] })
|
|
1607
|
-
log.streaming && /* @__PURE__ */ jsxRuntimeExports.
|
|
1762
|
+
] }),
|
|
1763
|
+
log.streaming && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1608
1764
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Radio, { className: "size-3 text-muted-foreground/60 shrink-0" }) }),
|
|
1609
1765
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Request used SSE streaming" })
|
|
1610
|
-
] })
|
|
1766
|
+
] }),
|
|
1611
1767
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
|
|
1612
1768
|
expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 text-muted-foreground shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 text-muted-foreground shrink-0" })
|
|
1613
1769
|
]
|
|
1614
1770
|
}
|
|
1615
|
-
);
|
|
1771
|
+
) });
|
|
1616
1772
|
});
|
|
1617
|
-
function Dialog({
|
|
1618
|
-
...props
|
|
1619
|
-
}) {
|
|
1620
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Root, { "data-slot": "dialog", ...props });
|
|
1621
|
-
}
|
|
1622
|
-
function DialogTrigger({
|
|
1623
|
-
...props
|
|
1624
|
-
}) {
|
|
1625
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger$2, { "data-slot": "dialog-trigger", ...props });
|
|
1626
|
-
}
|
|
1627
|
-
function DialogPortal({
|
|
1628
|
-
...props
|
|
1629
|
-
}) {
|
|
1630
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$2, { "data-slot": "dialog-portal", ...props });
|
|
1631
|
-
}
|
|
1632
|
-
function DialogOverlay({
|
|
1633
|
-
className,
|
|
1634
|
-
...props
|
|
1635
|
-
}) {
|
|
1636
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1637
|
-
Overlay,
|
|
1638
|
-
{
|
|
1639
|
-
"data-slot": "dialog-overlay",
|
|
1640
|
-
className: cn(
|
|
1641
|
-
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
1642
|
-
className
|
|
1643
|
-
),
|
|
1644
|
-
...props
|
|
1645
|
-
}
|
|
1646
|
-
);
|
|
1647
|
-
}
|
|
1648
|
-
function DialogContent({
|
|
1649
|
-
className,
|
|
1650
|
-
children,
|
|
1651
|
-
...props
|
|
1652
|
-
}) {
|
|
1653
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogPortal, { children: [
|
|
1654
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogOverlay, {}),
|
|
1655
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1656
|
-
Content,
|
|
1657
|
-
{
|
|
1658
|
-
"data-slot": "dialog-content",
|
|
1659
|
-
className: cn(
|
|
1660
|
-
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg",
|
|
1661
|
-
className
|
|
1662
|
-
),
|
|
1663
|
-
...props,
|
|
1664
|
-
children: [
|
|
1665
|
-
children,
|
|
1666
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
|
|
1667
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "size-4" }),
|
|
1668
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Close" })
|
|
1669
|
-
] })
|
|
1670
|
-
]
|
|
1671
|
-
}
|
|
1672
|
-
)
|
|
1673
|
-
] });
|
|
1674
|
-
}
|
|
1675
|
-
function DialogHeader({ className, ...props }) {
|
|
1676
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1677
|
-
"div",
|
|
1678
|
-
{
|
|
1679
|
-
"data-slot": "dialog-header",
|
|
1680
|
-
className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className),
|
|
1681
|
-
...props
|
|
1682
|
-
}
|
|
1683
|
-
);
|
|
1684
|
-
}
|
|
1685
|
-
function DialogTitle({
|
|
1686
|
-
className,
|
|
1687
|
-
...props
|
|
1688
|
-
}) {
|
|
1689
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1690
|
-
Title,
|
|
1691
|
-
{
|
|
1692
|
-
"data-slot": "dialog-title",
|
|
1693
|
-
className: cn("text-lg font-semibold leading-none tracking-tight", className),
|
|
1694
|
-
...props
|
|
1695
|
-
}
|
|
1696
|
-
);
|
|
1697
|
-
}
|
|
1698
1773
|
function Separator({
|
|
1699
1774
|
className,
|
|
1700
1775
|
orientation = "horizontal",
|
|
@@ -1807,7 +1882,7 @@ function extractThinkingFromContent(text) {
|
|
|
1807
1882
|
const remainingText = text.replace(THINKING_TAG_REGEX, "").trim();
|
|
1808
1883
|
return { thinking, remainingText };
|
|
1809
1884
|
}
|
|
1810
|
-
|
|
1885
|
+
const TextBlock = reactExports.memo(function TextBlock2({ text }) {
|
|
1811
1886
|
if (text.includes("<system-reminder>")) {
|
|
1812
1887
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(SystemReminderBlock, { text });
|
|
1813
1888
|
}
|
|
@@ -1817,8 +1892,10 @@ function TextBlock({ text }) {
|
|
|
1817
1892
|
remainingText.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "prose prose-sm dark:prose-invert max-w-none [&_pre]:bg-muted [&_pre]:text-foreground [&_code]:text-[0.8em] [&_p]:my-1 [&_ul]:my-1 [&_ol]:my-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { children: remainingText }) }),
|
|
1818
1893
|
thinking === null && remainingText.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "Empty text block" })
|
|
1819
1894
|
] });
|
|
1820
|
-
}
|
|
1821
|
-
|
|
1895
|
+
});
|
|
1896
|
+
const ThinkingBlock = reactExports.memo(function ThinkingBlock2({
|
|
1897
|
+
thinking
|
|
1898
|
+
}) {
|
|
1822
1899
|
const [open, setOpen] = reactExports.useState(false);
|
|
1823
1900
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(Collapsible, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-l-2 border-purple-500/40 my-1", children: [
|
|
1824
1901
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(CollapsibleTrigger, { className: "flex items-center gap-1.5 px-3 py-1 w-full text-left cursor-pointer hover:bg-purple-500/5 transition-colors rounded-r-sm group", children: [
|
|
@@ -1840,8 +1917,8 @@ function ThinkingBlock({ thinking }) {
|
|
|
1840
1917
|
] }),
|
|
1841
1918
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "max-h-[60vh]", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono leading-relaxed", children: thinking }) }) }) })
|
|
1842
1919
|
] }) });
|
|
1843
|
-
}
|
|
1844
|
-
|
|
1920
|
+
});
|
|
1921
|
+
const ToolUseBlock = reactExports.memo(function ToolUseBlock2({
|
|
1845
1922
|
name,
|
|
1846
1923
|
input
|
|
1847
1924
|
}) {
|
|
@@ -1855,8 +1932,8 @@ function ToolUseBlock({
|
|
|
1855
1932
|
] }),
|
|
1856
1933
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "max-h-[60vh]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewer, { data: safeJsonValue(input), defaultExpandDepth: 2 }) }) }) })
|
|
1857
1934
|
] }) });
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1935
|
+
});
|
|
1936
|
+
const ResponseContentBlockRenderer = reactExports.memo(function ResponseContentBlockRenderer2({
|
|
1860
1937
|
block
|
|
1861
1938
|
}) {
|
|
1862
1939
|
switch (block.type) {
|
|
@@ -1870,8 +1947,8 @@ function ResponseContentBlockRenderer({
|
|
|
1870
1947
|
default:
|
|
1871
1948
|
return assertNever();
|
|
1872
1949
|
}
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1950
|
+
});
|
|
1951
|
+
const StructuredResponseViewAnthropic = reactExports.memo(function StructuredResponseViewAnthropic2({
|
|
1875
1952
|
response
|
|
1876
1953
|
}) {
|
|
1877
1954
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
|
|
@@ -1913,7 +1990,7 @@ function StructuredResponseViewAnthropic({
|
|
|
1913
1990
|
response.content.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "Empty response content" })
|
|
1914
1991
|
] })
|
|
1915
1992
|
] });
|
|
1916
|
-
}
|
|
1993
|
+
});
|
|
1917
1994
|
function parseToolArguments(raw) {
|
|
1918
1995
|
if (raw === void 0 || raw === "") return {};
|
|
1919
1996
|
try {
|
|
@@ -1941,7 +2018,9 @@ function OpenAIToolCallBlock({ call }) {
|
|
|
1941
2018
|
) : /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewer, { data: safeJsonValue(parsed), defaultExpandDepth: 2 }) }) }) })
|
|
1942
2019
|
] }) });
|
|
1943
2020
|
}
|
|
1944
|
-
|
|
2021
|
+
const OpenAIResponseView = reactExports.memo(function OpenAIResponseView2({
|
|
2022
|
+
response
|
|
2023
|
+
}) {
|
|
1945
2024
|
const choice = response.choices[0];
|
|
1946
2025
|
const message = choice?.message;
|
|
1947
2026
|
const toolCalls = message?.tool_calls ?? [];
|
|
@@ -1999,17 +2078,119 @@ function OpenAIResponseView({ response }) {
|
|
|
1999
2078
|
(message?.content === null || message?.content === void 0 || message.content.length === 0) && (message?.reasoning_content === null || message?.reasoning_content === void 0 || message.reasoning_content.length === 0) && (message?.function_call === null || message?.function_call === void 0) && toolCalls.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "Empty response content" })
|
|
2000
2079
|
] })
|
|
2001
2080
|
] });
|
|
2081
|
+
});
|
|
2082
|
+
function isRecord(value) {
|
|
2083
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2002
2084
|
}
|
|
2003
|
-
function isOpenAIResponse(
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2085
|
+
function isOpenAIResponse(response) {
|
|
2086
|
+
return isRecord(response) && response.object === "chat.completion";
|
|
2087
|
+
}
|
|
2088
|
+
function isAnthropicResponse(response) {
|
|
2089
|
+
return isRecord(response) && response.type === "message" && Array.isArray(response.content);
|
|
2007
2090
|
}
|
|
2008
2091
|
function formatViewFor(apiFormat, response) {
|
|
2009
|
-
if (isOpenAIResponse(response)) {
|
|
2092
|
+
if (apiFormat === "openai" && isOpenAIResponse(response)) {
|
|
2010
2093
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(OpenAIResponseView, { response });
|
|
2011
2094
|
}
|
|
2012
|
-
|
|
2095
|
+
if (apiFormat === "anthropic" && isAnthropicResponse(response)) {
|
|
2096
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(StructuredResponseViewAnthropic, { response });
|
|
2097
|
+
}
|
|
2098
|
+
return null;
|
|
2099
|
+
}
|
|
2100
|
+
function emptyRequestAnalysis(rawBody) {
|
|
2101
|
+
return {
|
|
2102
|
+
parsed: null,
|
|
2103
|
+
comparisonValue: rawBody,
|
|
2104
|
+
messageCount: null,
|
|
2105
|
+
toolCount: null
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
const EMPTY_RESPONSE_ANALYSIS = {
|
|
2109
|
+
parsed: null,
|
|
2110
|
+
toolNames: null
|
|
2111
|
+
};
|
|
2112
|
+
const anthropicLogFormatAdapter = {
|
|
2113
|
+
format: "anthropic",
|
|
2114
|
+
analyzeRequest(rawBody) {
|
|
2115
|
+
if (rawBody === null) return emptyRequestAnalysis(rawBody);
|
|
2116
|
+
try {
|
|
2117
|
+
const result = AnthropicRequestSchema.safeParse(JSON.parse(rawBody));
|
|
2118
|
+
if (!result.success) return emptyRequestAnalysis(rawBody);
|
|
2119
|
+
return {
|
|
2120
|
+
parsed: result.data,
|
|
2121
|
+
comparisonValue: result.data,
|
|
2122
|
+
messageCount: result.data.messages.length,
|
|
2123
|
+
toolCount: result.data.tools !== void 0 && result.data.tools.length > 0 ? result.data.tools.length : null
|
|
2124
|
+
};
|
|
2125
|
+
} catch {
|
|
2126
|
+
return emptyRequestAnalysis(rawBody);
|
|
2127
|
+
}
|
|
2128
|
+
},
|
|
2129
|
+
analyzeResponse(responseText) {
|
|
2130
|
+
if (responseText === null) return EMPTY_RESPONSE_ANALYSIS;
|
|
2131
|
+
try {
|
|
2132
|
+
let json = JSON.parse(responseText);
|
|
2133
|
+
if (typeof json === "string") json = JSON.parse(json);
|
|
2134
|
+
const result = AnthropicResponseSchema$1.safeParse(json);
|
|
2135
|
+
if (!result.success) return EMPTY_RESPONSE_ANALYSIS;
|
|
2136
|
+
const toolNames = result.data.content.filter((block) => block.type === "tool_use").map((block) => block.name);
|
|
2137
|
+
return {
|
|
2138
|
+
parsed: result.data,
|
|
2139
|
+
toolNames: toolNames.length > 0 ? toolNames : null
|
|
2140
|
+
};
|
|
2141
|
+
} catch {
|
|
2142
|
+
return EMPTY_RESPONSE_ANALYSIS;
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
};
|
|
2146
|
+
const openAILogFormatAdapter = {
|
|
2147
|
+
format: "openai",
|
|
2148
|
+
analyzeRequest(rawBody) {
|
|
2149
|
+
if (rawBody === null) return emptyRequestAnalysis(rawBody);
|
|
2150
|
+
try {
|
|
2151
|
+
const result = OpenAIRequestSchema.safeParse(JSON.parse(rawBody));
|
|
2152
|
+
if (!result.success) return emptyRequestAnalysis(rawBody);
|
|
2153
|
+
return {
|
|
2154
|
+
parsed: result.data,
|
|
2155
|
+
comparisonValue: result.data,
|
|
2156
|
+
messageCount: result.data.messages.length,
|
|
2157
|
+
toolCount: result.data.tools !== void 0 && result.data.tools.length > 0 ? result.data.tools.length : null
|
|
2158
|
+
};
|
|
2159
|
+
} catch {
|
|
2160
|
+
return emptyRequestAnalysis(rawBody);
|
|
2161
|
+
}
|
|
2162
|
+
},
|
|
2163
|
+
analyzeResponse(responseText) {
|
|
2164
|
+
if (responseText === null) return EMPTY_RESPONSE_ANALYSIS;
|
|
2165
|
+
const parsed = parseOpenAIResponse(responseText);
|
|
2166
|
+
if (parsed === null) return EMPTY_RESPONSE_ANALYSIS;
|
|
2167
|
+
const toolNames = parsed.choices[0]?.message?.tool_calls?.map((toolCall) => toolCall.function?.name ?? "").filter((name) => name !== "") ?? [];
|
|
2168
|
+
return {
|
|
2169
|
+
parsed,
|
|
2170
|
+
toolNames: toolNames.length > 0 ? toolNames : null
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
};
|
|
2174
|
+
const unknownLogFormatAdapter = {
|
|
2175
|
+
format: "unknown",
|
|
2176
|
+
analyzeRequest(rawBody) {
|
|
2177
|
+
return emptyRequestAnalysis(rawBody);
|
|
2178
|
+
},
|
|
2179
|
+
analyzeResponse() {
|
|
2180
|
+
return EMPTY_RESPONSE_ANALYSIS;
|
|
2181
|
+
}
|
|
2182
|
+
};
|
|
2183
|
+
const ADAPTERS = {
|
|
2184
|
+
anthropic: anthropicLogFormatAdapter,
|
|
2185
|
+
openai: openAILogFormatAdapter,
|
|
2186
|
+
unknown: unknownLogFormatAdapter
|
|
2187
|
+
};
|
|
2188
|
+
function getLogFormatAdapter(format) {
|
|
2189
|
+
return ADAPTERS[format];
|
|
2190
|
+
}
|
|
2191
|
+
function resolveLogFormat(log) {
|
|
2192
|
+
const pathFormat = requestFormatForPath(log.path);
|
|
2193
|
+
return pathFormat === "unknown" ? log.apiFormat : pathFormat;
|
|
2013
2194
|
}
|
|
2014
2195
|
function getStatusClasses(category) {
|
|
2015
2196
|
switch (category) {
|
|
@@ -2023,23 +2204,6 @@ function getStatusClasses(category) {
|
|
|
2023
2204
|
return "text-muted-foreground";
|
|
2024
2205
|
}
|
|
2025
2206
|
}
|
|
2026
|
-
function parseResponse(text, apiFormat) {
|
|
2027
|
-
try {
|
|
2028
|
-
let json = JSON.parse(text);
|
|
2029
|
-
if (typeof json === "string") {
|
|
2030
|
-
json = JSON.parse(json);
|
|
2031
|
-
}
|
|
2032
|
-
if (apiFormat === "openai") {
|
|
2033
|
-
const result2 = parseOpenAIResponse(text);
|
|
2034
|
-
if (result2) return result2;
|
|
2035
|
-
}
|
|
2036
|
-
const result = InspectorResponseSchema.safeParse(json);
|
|
2037
|
-
if (result.success) return result.data;
|
|
2038
|
-
return null;
|
|
2039
|
-
} catch {
|
|
2040
|
-
return null;
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
2207
|
function StatusIndicator({ status }) {
|
|
2044
2208
|
const category = getStatusCategory(status);
|
|
2045
2209
|
const classes = getStatusClasses(category);
|
|
@@ -2057,7 +2221,7 @@ function ErrorResponseView({ text }) {
|
|
|
2057
2221
|
function MarkdownFallbackView({ text }) {
|
|
2058
2222
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "prose prose-sm dark:prose-invert max-w-none [&_pre]:bg-muted [&_pre]:text-foreground [&_code]:text-[0.8em] [&_p]:my-1 [&_ul]:my-1 [&_ol]:my-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { children: text }) });
|
|
2059
2223
|
}
|
|
2060
|
-
|
|
2224
|
+
const ResponseView = reactExports.memo(function ResponseView2({
|
|
2061
2225
|
responseText,
|
|
2062
2226
|
responseStatus,
|
|
2063
2227
|
streaming,
|
|
@@ -2068,6 +2232,11 @@ function ResponseView({
|
|
|
2068
2232
|
apiFormat,
|
|
2069
2233
|
error
|
|
2070
2234
|
}) {
|
|
2235
|
+
const resolvedFormat = apiFormat ?? "unknown";
|
|
2236
|
+
const parsed = reactExports.useMemo(
|
|
2237
|
+
() => getLogFormatAdapter(resolvedFormat).analyzeResponse(responseText).parsed,
|
|
2238
|
+
[resolvedFormat, responseText]
|
|
2239
|
+
);
|
|
2071
2240
|
if (responseText === null && error === void 0) {
|
|
2072
2241
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 py-3", children: [
|
|
2073
2242
|
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusIndicator, { status: responseStatus }),
|
|
@@ -2095,11 +2264,10 @@ function ResponseView({
|
|
|
2095
2264
|
responseText !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorResponseView, { text: responseText }) })
|
|
2096
2265
|
] });
|
|
2097
2266
|
}
|
|
2098
|
-
const parsed = responseText !== null ? parseResponse(responseText, apiFormat) : null;
|
|
2099
2267
|
if (parsed !== null) {
|
|
2100
2268
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
2101
2269
|
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusIndicator, { status: responseStatus }),
|
|
2102
|
-
formatViewFor(
|
|
2270
|
+
formatViewFor(resolvedFormat, parsed)
|
|
2103
2271
|
] });
|
|
2104
2272
|
}
|
|
2105
2273
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
@@ -2126,7 +2294,7 @@ function ResponseView({
|
|
|
2126
2294
|
] }),
|
|
2127
2295
|
/* @__PURE__ */ jsxRuntimeExports.jsx(MarkdownFallbackView, { text: responseText ?? "" })
|
|
2128
2296
|
] });
|
|
2129
|
-
}
|
|
2297
|
+
});
|
|
2130
2298
|
const ReplayResultSchema = object({
|
|
2131
2299
|
success: boolean(),
|
|
2132
2300
|
error: string().optional(),
|
|
@@ -2276,7 +2444,7 @@ function ReplayDialog({ log, open, onOpenChange }) {
|
|
|
2276
2444
|
] })
|
|
2277
2445
|
] }) });
|
|
2278
2446
|
}
|
|
2279
|
-
|
|
2447
|
+
const StreamingChunkSequence = reactExports.memo(function StreamingChunkSequence2({
|
|
2280
2448
|
logId,
|
|
2281
2449
|
truncated
|
|
2282
2450
|
}) {
|
|
@@ -2408,7 +2576,7 @@ function StreamingChunkSequence({
|
|
|
2408
2576
|
] }) }),
|
|
2409
2577
|
containerExpanded === true ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-border bg-muted/20 overflow-auto max-h-64", children: renderBody() }) : null
|
|
2410
2578
|
] });
|
|
2411
|
-
}
|
|
2579
|
+
});
|
|
2412
2580
|
function shouldShowRawRequestTab(apiFormat, viewMode, strip) {
|
|
2413
2581
|
return apiFormat === "anthropic" && viewMode === "full" && strip;
|
|
2414
2582
|
}
|
|
@@ -2445,7 +2613,7 @@ function DiffToggleButton({
|
|
|
2445
2613
|
active,
|
|
2446
2614
|
onClick
|
|
2447
2615
|
}) {
|
|
2448
|
-
return /* @__PURE__ */ jsxRuntimeExports.
|
|
2616
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2449
2617
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2450
2618
|
"button",
|
|
2451
2619
|
{
|
|
@@ -2463,7 +2631,49 @@ function DiffToggleButton({
|
|
|
2463
2631
|
}
|
|
2464
2632
|
) }),
|
|
2465
2633
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: active ? "Hide diff view" : "Compare proxy output against the original raw version" })
|
|
2466
|
-
] })
|
|
2634
|
+
] });
|
|
2635
|
+
}
|
|
2636
|
+
const RequestDiffContent = reactExports.memo(function({
|
|
2637
|
+
rawBody,
|
|
2638
|
+
displayedBody,
|
|
2639
|
+
emptyLabel
|
|
2640
|
+
}) {
|
|
2641
|
+
const result = reactExports.useMemo(
|
|
2642
|
+
() => computeRequestDiff(rawBody, displayedBody),
|
|
2643
|
+
[rawBody, displayedBody]
|
|
2644
|
+
);
|
|
2645
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(DiffView, { result, emptyLabel });
|
|
2646
|
+
});
|
|
2647
|
+
const HeadersDiffContent = reactExports.memo(function({
|
|
2648
|
+
rawHeaders,
|
|
2649
|
+
headers,
|
|
2650
|
+
emptyLabel
|
|
2651
|
+
}) {
|
|
2652
|
+
const result = reactExports.useMemo(() => computeHeadersDiff(rawHeaders, headers), [rawHeaders, headers]);
|
|
2653
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(DiffView, { result, emptyLabel });
|
|
2654
|
+
});
|
|
2655
|
+
function useCopyFeedback(text) {
|
|
2656
|
+
const [copied, setCopied] = reactExports.useState(false);
|
|
2657
|
+
const timerRef = reactExports.useRef(null);
|
|
2658
|
+
reactExports.useEffect(
|
|
2659
|
+
() => () => {
|
|
2660
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
2661
|
+
},
|
|
2662
|
+
[]
|
|
2663
|
+
);
|
|
2664
|
+
const copy = reactExports.useCallback(
|
|
2665
|
+
(event) => {
|
|
2666
|
+
event.stopPropagation();
|
|
2667
|
+
if (text === null) return;
|
|
2668
|
+
void window.navigator.clipboard.writeText(text).then(() => {
|
|
2669
|
+
setCopied(true);
|
|
2670
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
2671
|
+
timerRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
2672
|
+
});
|
|
2673
|
+
},
|
|
2674
|
+
[text]
|
|
2675
|
+
);
|
|
2676
|
+
return { copied, copy };
|
|
2467
2677
|
}
|
|
2468
2678
|
const LogEntry = reactExports.memo(function({
|
|
2469
2679
|
log,
|
|
@@ -2473,156 +2683,81 @@ const LogEntry = reactExports.memo(function({
|
|
|
2473
2683
|
onCompareWithPrevious
|
|
2474
2684
|
}) {
|
|
2475
2685
|
const [expanded, setExpanded] = reactExports.useState(false);
|
|
2476
|
-
const [requestCopied, setRequestCopied] = reactExports.useState(false);
|
|
2477
|
-
const [rawRequestCopied, setRawRequestCopied] = reactExports.useState(false);
|
|
2478
|
-
const [responseCopied, setResponseCopied] = reactExports.useState(false);
|
|
2479
2686
|
const [replayOpen, setReplayOpen] = reactExports.useState(false);
|
|
2480
2687
|
const [headersDiff, setHeadersDiff] = reactExports.useState(false);
|
|
2481
2688
|
const [requestDiff, setRequestDiff] = reactExports.useState(false);
|
|
2482
|
-
const
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
}
|
|
2494
|
-
return null;
|
|
2495
|
-
}, [log.rawRequestBody, log.apiFormat]);
|
|
2496
|
-
const toolCount = reactExports.useMemo(() => {
|
|
2497
|
-
if (log.rawRequestBody === null) return null;
|
|
2498
|
-
if (log.apiFormat === "anthropic") {
|
|
2499
|
-
const parsed = parseRequest(log.rawRequestBody);
|
|
2500
|
-
if (parsed !== null && parsed.tools !== void 0 && parsed.tools.length > 0) {
|
|
2501
|
-
return parsed.tools.length;
|
|
2502
|
-
}
|
|
2503
|
-
} else if (log.apiFormat === "openai") {
|
|
2504
|
-
try {
|
|
2505
|
-
const result = OpenAIRequestSchema.safeParse(JSON.parse(log.rawRequestBody));
|
|
2506
|
-
if (result.success && result.data.tools !== void 0 && result.data.tools.length > 0) {
|
|
2507
|
-
return result.data.tools.length;
|
|
2508
|
-
}
|
|
2509
|
-
} catch {
|
|
2510
|
-
}
|
|
2511
|
-
}
|
|
2512
|
-
return null;
|
|
2513
|
-
}, [log.rawRequestBody, log.apiFormat]);
|
|
2514
|
-
const responseToolNames = reactExports.useMemo(() => {
|
|
2515
|
-
if (log.responseText === null) return null;
|
|
2516
|
-
if (log.apiFormat === "openai") {
|
|
2517
|
-
const parsed = parseOpenAIResponse(log.responseText);
|
|
2518
|
-
if (parsed !== null) {
|
|
2519
|
-
const toolCalls = parsed.choices[0]?.message?.tool_calls;
|
|
2520
|
-
if (toolCalls !== void 0 && toolCalls !== null && toolCalls.length > 0) {
|
|
2521
|
-
return toolCalls.map((tc) => tc.function?.name ?? "?").filter((n) => n !== "");
|
|
2522
|
-
}
|
|
2523
|
-
}
|
|
2524
|
-
} else if (log.apiFormat === "anthropic") {
|
|
2525
|
-
try {
|
|
2526
|
-
const result = InspectorResponseSchema.safeParse(JSON.parse(log.responseText));
|
|
2527
|
-
if (result.success) {
|
|
2528
|
-
const names = result.data.content.filter((c) => c.type === "tool_use").map((c) => c.name);
|
|
2529
|
-
if (names.length > 0) return names;
|
|
2530
|
-
}
|
|
2531
|
-
} catch {
|
|
2532
|
-
}
|
|
2533
|
-
}
|
|
2534
|
-
return null;
|
|
2535
|
-
}, [log.responseText, log.apiFormat]);
|
|
2689
|
+
const [activeTab, setActiveTab] = reactExports.useState("request");
|
|
2690
|
+
const resolvedFormat = resolveLogFormat(log);
|
|
2691
|
+
const adapter = getLogFormatAdapter(resolvedFormat);
|
|
2692
|
+
const requestAnalysis = reactExports.useMemo(
|
|
2693
|
+
() => adapter.analyzeRequest(log.rawRequestBody),
|
|
2694
|
+
[adapter, log.rawRequestBody]
|
|
2695
|
+
);
|
|
2696
|
+
const responseAnalysis = reactExports.useMemo(
|
|
2697
|
+
() => adapter.analyzeResponse(log.responseText),
|
|
2698
|
+
[adapter, log.responseText]
|
|
2699
|
+
);
|
|
2536
2700
|
const strippedRequestBody = reactExports.useMemo(() => {
|
|
2537
|
-
if (!strip ||
|
|
2701
|
+
if (!strip || resolvedFormat !== "anthropic" || log.rawRequestBody === null) {
|
|
2538
2702
|
return null;
|
|
2539
2703
|
}
|
|
2540
2704
|
return stripClaudeCodeBillingHeader(log.rawRequestBody).body;
|
|
2541
|
-
}, [log.rawRequestBody,
|
|
2705
|
+
}, [log.rawRequestBody, resolvedFormat, strip]);
|
|
2542
2706
|
const displayedRequestBody = strippedRequestBody ?? log.rawRequestBody;
|
|
2543
|
-
const
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
() => computeRequestDiff(log.rawRequestBody, displayedRequestBody),
|
|
2549
|
-
[log.rawRequestBody, displayedRequestBody]
|
|
2550
|
-
);
|
|
2551
|
-
function handleCopyRequest(e) {
|
|
2552
|
-
e.stopPropagation();
|
|
2553
|
-
if (displayedRequestBody === null) return;
|
|
2554
|
-
void window.navigator.clipboard.writeText(displayedRequestBody).then(() => {
|
|
2555
|
-
setRequestCopied(true);
|
|
2556
|
-
setTimeout(() => setRequestCopied(false), 2e3);
|
|
2557
|
-
});
|
|
2558
|
-
}
|
|
2559
|
-
function handleCopyRawRequest(e) {
|
|
2560
|
-
e.stopPropagation();
|
|
2561
|
-
if (log.rawRequestBody === null) return;
|
|
2562
|
-
void window.navigator.clipboard.writeText(log.rawRequestBody).then(() => {
|
|
2563
|
-
setRawRequestCopied(true);
|
|
2564
|
-
setTimeout(() => setRawRequestCopied(false), 2e3);
|
|
2565
|
-
});
|
|
2566
|
-
}
|
|
2567
|
-
function handleCopyResponse(e) {
|
|
2568
|
-
e.stopPropagation();
|
|
2569
|
-
if (log.responseText === null) return;
|
|
2570
|
-
void window.navigator.clipboard.writeText(log.responseText).then(() => {
|
|
2571
|
-
setResponseCopied(true);
|
|
2572
|
-
setTimeout(() => setResponseCopied(false), 2e3);
|
|
2573
|
-
});
|
|
2574
|
-
}
|
|
2575
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
2576
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-border rounded-lg mb-3 overflow-hidden", children: [
|
|
2707
|
+
const requestCopy = useCopyFeedback(displayedRequestBody);
|
|
2708
|
+
const rawRequestCopy = useCopyFeedback(log.rawRequestBody);
|
|
2709
|
+
const responseCopy = useCopyFeedback(log.responseText);
|
|
2710
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(TooltipProvider, { children: [
|
|
2711
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-border rounded-lg mb-1 overflow-hidden", children: [
|
|
2577
2712
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2578
2713
|
LogEntryHeader,
|
|
2579
2714
|
{
|
|
2580
2715
|
log,
|
|
2581
|
-
messageCount,
|
|
2582
|
-
toolCount,
|
|
2716
|
+
messageCount: requestAnalysis.messageCount,
|
|
2717
|
+
toolCount: requestAnalysis.toolCount,
|
|
2583
2718
|
expanded,
|
|
2584
2719
|
onToggle: () => setExpanded(!expanded),
|
|
2585
|
-
responseToolNames,
|
|
2720
|
+
responseToolNames: responseAnalysis.toolNames,
|
|
2586
2721
|
cacheTrend
|
|
2587
2722
|
}
|
|
2588
2723
|
),
|
|
2589
|
-
expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, {
|
|
2724
|
+
expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { value: activeTab, onValueChange: setActiveTab, children: [
|
|
2590
2725
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, { className: "mx-4 mt-2", children: [
|
|
2591
|
-
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.
|
|
2726
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2592
2727
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw-headers", children: "Raw Headers" }) }),
|
|
2593
2728
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "HTTP headers received from the upstream provider" })
|
|
2594
|
-
] })
|
|
2595
|
-
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.
|
|
2729
|
+
] }),
|
|
2730
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2596
2731
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "headers", children: "Headers" }) }),
|
|
2597
2732
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Request and response headers sent and received" })
|
|
2598
|
-
] })
|
|
2599
|
-
shouldShowRawRequestTab(
|
|
2733
|
+
] }),
|
|
2734
|
+
shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2600
2735
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw-request", children: "Raw Request" }) }),
|
|
2601
2736
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Exact HTTP request sent to the upstream provider" })
|
|
2602
|
-
] })
|
|
2737
|
+
] }),
|
|
2603
2738
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "request", children: "Request" }),
|
|
2604
|
-
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.
|
|
2739
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2605
2740
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw", children: "Raw Response" }) }),
|
|
2606
2741
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Exact HTTP response from the upstream provider" })
|
|
2607
|
-
] })
|
|
2742
|
+
] }),
|
|
2608
2743
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" })
|
|
2609
2744
|
] }),
|
|
2610
|
-
shouldShowRawRequestTab(
|
|
2745
|
+
shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: activeTab === "raw-request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
|
|
2611
2746
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end mb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2612
2747
|
CopyButton,
|
|
2613
2748
|
{
|
|
2614
2749
|
text: log.rawRequestBody,
|
|
2615
2750
|
label: "Copy Raw Request",
|
|
2616
|
-
copied:
|
|
2617
|
-
onCopy:
|
|
2751
|
+
copied: rawRequestCopy.copied,
|
|
2752
|
+
onCopy: rawRequestCopy.copy
|
|
2618
2753
|
}
|
|
2619
2754
|
) }),
|
|
2620
2755
|
log.rawRequestBody !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: log.rawRequestBody, defaultExpandDepth: 1 }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" })
|
|
2621
2756
|
] }) }),
|
|
2622
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
|
|
2757
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: activeTab === "request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
|
|
2623
2758
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 mb-2", children: [
|
|
2624
2759
|
shouldShowRequestDiffButton(
|
|
2625
|
-
|
|
2760
|
+
resolvedFormat,
|
|
2626
2761
|
viewMode,
|
|
2627
2762
|
strip,
|
|
2628
2763
|
log.rawRequestBody !== null
|
|
@@ -2636,7 +2771,7 @@ const LogEntry = reactExports.memo(function({
|
|
|
2636
2771
|
}
|
|
2637
2772
|
}
|
|
2638
2773
|
),
|
|
2639
|
-
onCompareWithPrevious !== void 0 && /* @__PURE__ */ jsxRuntimeExports.
|
|
2774
|
+
onCompareWithPrevious !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2640
2775
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2641
2776
|
Button,
|
|
2642
2777
|
{
|
|
@@ -2645,7 +2780,7 @@ const LogEntry = reactExports.memo(function({
|
|
|
2645
2780
|
className: "h-7 text-xs",
|
|
2646
2781
|
onClick: (e) => {
|
|
2647
2782
|
e.stopPropagation();
|
|
2648
|
-
onCompareWithPrevious();
|
|
2783
|
+
onCompareWithPrevious(log);
|
|
2649
2784
|
},
|
|
2650
2785
|
children: [
|
|
2651
2786
|
/* @__PURE__ */ jsxRuntimeExports.jsx(GitCompareArrows, { className: "size-3 mr-1" }),
|
|
@@ -2654,8 +2789,8 @@ const LogEntry = reactExports.memo(function({
|
|
|
2654
2789
|
}
|
|
2655
2790
|
) }),
|
|
2656
2791
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Compare this request with the immediately preceding one" })
|
|
2657
|
-
] })
|
|
2658
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
2792
|
+
] }),
|
|
2793
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2659
2794
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2660
2795
|
Button,
|
|
2661
2796
|
{
|
|
@@ -2673,26 +2808,27 @@ const LogEntry = reactExports.memo(function({
|
|
|
2673
2808
|
}
|
|
2674
2809
|
) }),
|
|
2675
2810
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Re-send this request to the provider" })
|
|
2676
|
-
] })
|
|
2811
|
+
] }),
|
|
2677
2812
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2678
2813
|
CopyButton,
|
|
2679
2814
|
{
|
|
2680
2815
|
text: displayedRequestBody,
|
|
2681
2816
|
label: "Copy Request",
|
|
2682
|
-
copied:
|
|
2683
|
-
onCopy:
|
|
2817
|
+
copied: requestCopy.copied,
|
|
2818
|
+
onCopy: requestCopy.copy
|
|
2684
2819
|
}
|
|
2685
2820
|
)
|
|
2686
2821
|
] }),
|
|
2687
2822
|
requestDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2688
|
-
|
|
2823
|
+
RequestDiffContent,
|
|
2689
2824
|
{
|
|
2690
|
-
|
|
2825
|
+
rawBody: log.rawRequestBody,
|
|
2826
|
+
displayedBody: displayedRequestBody,
|
|
2691
2827
|
emptyLabel: "No transformation applied — raw and sent request bodies are identical."
|
|
2692
2828
|
}
|
|
2693
2829
|
) : displayedRequestBody !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewerFromString, { text: displayedRequestBody, defaultExpandDepth: 1 }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" })
|
|
2694
2830
|
] }) }),
|
|
2695
|
-
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "headers", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
|
|
2831
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "headers", children: activeTab === "headers" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
|
|
2696
2832
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end gap-2 mb-2", children: shouldShowHeadersDiffButton(
|
|
2697
2833
|
viewMode,
|
|
2698
2834
|
log.rawHeaders !== void 0 && Object.keys(log.rawHeaders).length > 0
|
|
@@ -2707,9 +2843,10 @@ const LogEntry = reactExports.memo(function({
|
|
|
2707
2843
|
}
|
|
2708
2844
|
) }),
|
|
2709
2845
|
headersDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2710
|
-
|
|
2846
|
+
HeadersDiffContent,
|
|
2711
2847
|
{
|
|
2712
|
-
|
|
2848
|
+
rawHeaders: log.rawHeaders,
|
|
2849
|
+
headers: log.headers,
|
|
2713
2850
|
emptyLabel: "No transformation applied — raw and processed headers are identical."
|
|
2714
2851
|
}
|
|
2715
2852
|
) : 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: [
|
|
@@ -2720,14 +2857,14 @@ const LogEntry = reactExports.memo(function({
|
|
|
2720
2857
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
|
|
2721
2858
|
] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No headers captured" })
|
|
2722
2859
|
] }) }),
|
|
2723
|
-
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-headers", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: log.rawHeaders && Object.keys(log.rawHeaders).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.rawHeaders).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
2860
|
+
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-headers", children: activeTab === "raw-headers" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: log.rawHeaders && Object.keys(log.rawHeaders).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.rawHeaders).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
2724
2861
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-600 dark:text-blue-400 font-semibold shrink-0", children: [
|
|
2725
2862
|
key,
|
|
2726
2863
|
":"
|
|
2727
2864
|
] }),
|
|
2728
2865
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
|
|
2729
2866
|
] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No raw headers captured" }) }) }),
|
|
2730
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3 space-y-3", children: [
|
|
2867
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: activeTab === "raw" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3 space-y-3", children: [
|
|
2731
2868
|
log.error !== void 0 && log.error !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded border border-destructive/50 bg-destructive/10 p-3 text-xs", children: [
|
|
2732
2869
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold text-destructive mb-1", children: "SSE Error" }),
|
|
2733
2870
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground font-mono", children: log.error })
|
|
@@ -2737,8 +2874,8 @@ const LogEntry = reactExports.memo(function({
|
|
|
2737
2874
|
{
|
|
2738
2875
|
text: log.responseText,
|
|
2739
2876
|
label: "Copy Response",
|
|
2740
|
-
copied:
|
|
2741
|
-
onCopy:
|
|
2877
|
+
copied: responseCopy.copied,
|
|
2878
|
+
onCopy: responseCopy.copy
|
|
2742
2879
|
}
|
|
2743
2880
|
) }),
|
|
2744
2881
|
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" }),
|
|
@@ -2750,7 +2887,7 @@ const LogEntry = reactExports.memo(function({
|
|
|
2750
2887
|
}
|
|
2751
2888
|
)
|
|
2752
2889
|
] }) }),
|
|
2753
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2890
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: activeTab === "parsed" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2754
2891
|
ResponseView,
|
|
2755
2892
|
{
|
|
2756
2893
|
responseText: log.responseText,
|
|
@@ -2760,7 +2897,7 @@ const LogEntry = reactExports.memo(function({
|
|
|
2760
2897
|
outputTokens: log.outputTokens,
|
|
2761
2898
|
cacheCreationInputTokens: log.cacheCreationInputTokens,
|
|
2762
2899
|
cacheReadInputTokens: log.cacheReadInputTokens,
|
|
2763
|
-
apiFormat:
|
|
2900
|
+
apiFormat: resolvedFormat,
|
|
2764
2901
|
error: log.error
|
|
2765
2902
|
}
|
|
2766
2903
|
) }) })
|
|
@@ -3173,37 +3310,37 @@ function ThreadConnector({
|
|
|
3173
3310
|
) })
|
|
3174
3311
|
] });
|
|
3175
3312
|
}
|
|
3176
|
-
|
|
3177
|
-
|
|
3313
|
+
const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
3314
|
+
entries,
|
|
3178
3315
|
viewMode,
|
|
3179
3316
|
strip,
|
|
3180
3317
|
cacheTrends,
|
|
3181
3318
|
onCompareWithPrevious,
|
|
3319
|
+
comparisonPredecessors,
|
|
3182
3320
|
turnIndex = 0
|
|
3183
3321
|
}) {
|
|
3184
|
-
const
|
|
3185
|
-
const
|
|
3186
|
-
const lastStop = stopReasons[lastIdx] ?? null;
|
|
3322
|
+
const lastIdx = entries.length - 1;
|
|
3323
|
+
const lastStop = entries[lastIdx]?.stopReason ?? null;
|
|
3187
3324
|
const isComplete = lastStop !== null ? isTurnBoundary(lastStop) : false;
|
|
3188
|
-
const isPending =
|
|
3325
|
+
const isPending = entries[lastIdx]?.log.responseStatus === null;
|
|
3189
3326
|
const collapsible = isComplete && !isPending;
|
|
3190
3327
|
const [collapsed, setCollapsed] = reactExports.useState(false);
|
|
3191
3328
|
const toggleCollapse = reactExports.useCallback(() => {
|
|
3192
3329
|
if (collapsible) setCollapsed((prev) => !prev);
|
|
3193
3330
|
}, [collapsible]);
|
|
3194
|
-
const
|
|
3195
|
-
if (!collapsed) return
|
|
3196
|
-
const last =
|
|
3331
|
+
const visibleEntries = reactExports.useMemo(() => {
|
|
3332
|
+
if (!collapsed) return entries;
|
|
3333
|
+
const last = entries[lastIdx];
|
|
3197
3334
|
return last !== void 0 ? [last] : [];
|
|
3198
|
-
}, [
|
|
3335
|
+
}, [entries, collapsed, lastIdx]);
|
|
3199
3336
|
const bgClass = turnIndex % 2 === 0 ? "bg-muted/10" : "bg-muted/25";
|
|
3200
3337
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3201
3338
|
"div",
|
|
3202
3339
|
{
|
|
3203
3340
|
className: cn("border rounded-lg", isPending ? "border-amber-500/10" : "border-transparent"),
|
|
3204
|
-
children:
|
|
3341
|
+
children: visibleEntries.map((entry, visibleIdx) => {
|
|
3205
3342
|
const originalIdx = collapsed ? lastIdx : visibleIdx;
|
|
3206
|
-
const reason =
|
|
3343
|
+
const { log, stopReason: reason } = entry;
|
|
3207
3344
|
const isBoundary = reason === "end_turn" || reason === "stop";
|
|
3208
3345
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-stretch", children: [
|
|
3209
3346
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -3214,25 +3351,59 @@ function TurnGroup({
|
|
|
3214
3351
|
isFirst: originalIdx === 0,
|
|
3215
3352
|
isTurnStart: originalIdx === 0,
|
|
3216
3353
|
crabIndex: log.id % 12,
|
|
3217
|
-
collapsible: collapsible && isBoundary &&
|
|
3354
|
+
collapsible: collapsible && isBoundary && entries.length > 1,
|
|
3218
3355
|
collapsed,
|
|
3219
3356
|
onToggle: toggleCollapse
|
|
3220
3357
|
}
|
|
3221
3358
|
),
|
|
3222
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("flex-1 min-w-0 mb-
|
|
3359
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("flex-1 min-w-0 mb-0.5 rounded-lg", bgClass), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3223
3360
|
LogEntry,
|
|
3224
3361
|
{
|
|
3225
3362
|
log,
|
|
3226
3363
|
viewMode,
|
|
3227
3364
|
strip,
|
|
3228
3365
|
cacheTrend: cacheTrends?.get(log.id) ?? null,
|
|
3229
|
-
onCompareWithPrevious: ()
|
|
3366
|
+
onCompareWithPrevious: comparisonPredecessors.has(log.id) ? onCompareWithPrevious : void 0
|
|
3230
3367
|
}
|
|
3231
3368
|
) })
|
|
3232
3369
|
] }, log.id);
|
|
3233
3370
|
})
|
|
3234
3371
|
}
|
|
3235
3372
|
);
|
|
3373
|
+
});
|
|
3374
|
+
function shouldRenderConversationContent(standalone, expanded) {
|
|
3375
|
+
return standalone || expanded;
|
|
3376
|
+
}
|
|
3377
|
+
function buildTurnGroups(logs) {
|
|
3378
|
+
const groups = [];
|
|
3379
|
+
let entries = [];
|
|
3380
|
+
let turnIndex = 0;
|
|
3381
|
+
for (const log of logs) {
|
|
3382
|
+
entries.push({ log, stopReason: extractStopReason(log) });
|
|
3383
|
+
const current = entries[entries.length - 1];
|
|
3384
|
+
if (current !== void 0 && isTurnBoundary(current.stopReason)) {
|
|
3385
|
+
groups.push({ entries, turnIndex });
|
|
3386
|
+
entries = [];
|
|
3387
|
+
turnIndex += 1;
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
if (entries.length > 0) groups.push({ entries, turnIndex });
|
|
3391
|
+
return groups;
|
|
3392
|
+
}
|
|
3393
|
+
function buildValidPredecessors(groups) {
|
|
3394
|
+
const predecessors = /* @__PURE__ */ new Map();
|
|
3395
|
+
for (const group of groups) {
|
|
3396
|
+
for (let index = 1; index < group.logs.length; index += 1) {
|
|
3397
|
+
const current = group.logs[index];
|
|
3398
|
+
const previous = group.logs[index - 1];
|
|
3399
|
+
if (current === void 0 || previous === void 0) continue;
|
|
3400
|
+
const currentFormat = resolveLogFormat(current);
|
|
3401
|
+
const previousFormat = resolveLogFormat(previous);
|
|
3402
|
+
if (currentFormat === "unknown" || currentFormat !== previousFormat) continue;
|
|
3403
|
+
predecessors.set(current.id, previous);
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
return predecessors;
|
|
3236
3407
|
}
|
|
3237
3408
|
function computeStats(logs) {
|
|
3238
3409
|
let totalInput = 0;
|
|
@@ -3249,51 +3420,19 @@ const ConversationGroup = reactExports.memo(function({
|
|
|
3249
3420
|
strip,
|
|
3250
3421
|
cacheTrends,
|
|
3251
3422
|
onCompareWithPrevious,
|
|
3423
|
+
comparisonPredecessors,
|
|
3424
|
+
onClearGroup,
|
|
3252
3425
|
standalone = false
|
|
3253
3426
|
}) {
|
|
3254
|
-
const [expanded, setExpanded] = reactExports.useState(
|
|
3255
|
-
const stats = computeStats(group.logs);
|
|
3427
|
+
const [expanded, setExpanded] = reactExports.useState(false);
|
|
3428
|
+
const stats = reactExports.useMemo(() => computeStats(group.logs), [group.logs]);
|
|
3256
3429
|
const startTime = group.logs[0]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3257
3430
|
const endTime = group.logs[group.logs.length - 1]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3258
3431
|
const mixed = hasMixedApiFormat(group.logs);
|
|
3259
3432
|
const isLoading = group.logs.some((log) => log.responseStatus === null);
|
|
3260
|
-
const
|
|
3261
|
-
const turnIndices = reactExports.useMemo(() => {
|
|
3262
|
-
const indices = [];
|
|
3263
|
-
let turn = 0;
|
|
3264
|
-
for (let i = 0; i < stopReasons.length; i++) {
|
|
3265
|
-
if (i > 0 && (stopReasons[i - 1] === "end_turn" || stopReasons[i - 1] === "stop")) {
|
|
3266
|
-
turn++;
|
|
3267
|
-
}
|
|
3268
|
-
indices.push(turn);
|
|
3269
|
-
}
|
|
3270
|
-
return indices;
|
|
3271
|
-
}, [stopReasons]);
|
|
3272
|
-
const turnGroups = reactExports.useMemo(() => {
|
|
3273
|
-
const groups = [];
|
|
3274
|
-
let currentGroup = [];
|
|
3275
|
-
let currentTurn = 0;
|
|
3276
|
-
for (let i = 0; i < group.logs.length; i++) {
|
|
3277
|
-
const turnIdx = turnIndices[i] ?? 0;
|
|
3278
|
-
const log = group.logs[i];
|
|
3279
|
-
if (!log) continue;
|
|
3280
|
-
if (turnIdx !== currentTurn) {
|
|
3281
|
-
if (currentGroup.length > 0) {
|
|
3282
|
-
groups.push({ logs: currentGroup, turnIndex: currentTurn });
|
|
3283
|
-
}
|
|
3284
|
-
currentGroup = [log];
|
|
3285
|
-
currentTurn = turnIdx;
|
|
3286
|
-
} else {
|
|
3287
|
-
currentGroup.push(log);
|
|
3288
|
-
}
|
|
3289
|
-
}
|
|
3290
|
-
if (currentGroup.length > 0) {
|
|
3291
|
-
groups.push({ logs: currentGroup, turnIndex: currentTurn });
|
|
3292
|
-
}
|
|
3293
|
-
return groups;
|
|
3294
|
-
}, [group.logs, turnIndices]);
|
|
3433
|
+
const turnGroups = reactExports.useMemo(() => buildTurnGroups(group.logs), [group.logs]);
|
|
3295
3434
|
const displayId = group.conversationId.startsWith("PID:") || group.conversationId.includes("|") ? group.conversationId : group.conversationId.length > 24 ? group.conversationId.slice(0, 12) + "…" + group.conversationId.slice(-12) : group.conversationId;
|
|
3296
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-
|
|
3435
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-2", children: [
|
|
3297
3436
|
!standalone && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3298
3437
|
ConversationHeader,
|
|
3299
3438
|
{
|
|
@@ -3308,17 +3447,19 @@ const ConversationGroup = reactExports.memo(function({
|
|
|
3308
3447
|
onToggle: () => setExpanded(!expanded),
|
|
3309
3448
|
hideApiFormat: mixed,
|
|
3310
3449
|
isLoading,
|
|
3311
|
-
userAgent: group.logs[0]?.userAgent ?? null
|
|
3450
|
+
userAgent: group.logs[0]?.userAgent ?? null,
|
|
3451
|
+
onClear: () => onClearGroup(group.logs.map((l) => l.id))
|
|
3312
3452
|
}
|
|
3313
3453
|
),
|
|
3314
|
-
expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: turnGroups.map((tg) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3454
|
+
shouldRenderConversationContent(standalone, expanded) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "max-h-[70vh] overflow-y-auto", children: turnGroups.map((tg) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3315
3455
|
TurnGroup,
|
|
3316
3456
|
{
|
|
3317
|
-
|
|
3457
|
+
entries: tg.entries,
|
|
3318
3458
|
viewMode,
|
|
3319
3459
|
strip,
|
|
3320
3460
|
cacheTrends,
|
|
3321
3461
|
onCompareWithPrevious,
|
|
3462
|
+
comparisonPredecessors,
|
|
3322
3463
|
turnIndex: tg.turnIndex
|
|
3323
3464
|
},
|
|
3324
3465
|
tg.turnIndex
|
|
@@ -3509,6 +3650,32 @@ function OpenCodeIcon() {
|
|
|
3509
3650
|
}
|
|
3510
3651
|
);
|
|
3511
3652
|
}
|
|
3653
|
+
function MiMoCodeIcon() {
|
|
3654
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3655
|
+
"svg",
|
|
3656
|
+
{
|
|
3657
|
+
fill: "currentColor",
|
|
3658
|
+
viewBox: "0 0 24 24",
|
|
3659
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3660
|
+
className: "size-6 shrink-0",
|
|
3661
|
+
children: [
|
|
3662
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("title", { children: "MiMo Code" }),
|
|
3663
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3664
|
+
"text",
|
|
3665
|
+
{
|
|
3666
|
+
x: "12",
|
|
3667
|
+
y: "18",
|
|
3668
|
+
textAnchor: "middle",
|
|
3669
|
+
fontSize: "16",
|
|
3670
|
+
fontWeight: "800",
|
|
3671
|
+
fontFamily: "system-ui, sans-serif",
|
|
3672
|
+
children: "M"
|
|
3673
|
+
}
|
|
3674
|
+
)
|
|
3675
|
+
]
|
|
3676
|
+
}
|
|
3677
|
+
);
|
|
3678
|
+
}
|
|
3512
3679
|
const ExternalProviderSchema = object({
|
|
3513
3680
|
name: string(),
|
|
3514
3681
|
apiKey: string(),
|
|
@@ -3516,7 +3683,7 @@ const ExternalProviderSchema = object({
|
|
|
3516
3683
|
anthropicBaseUrl: string(),
|
|
3517
3684
|
openaiBaseUrl: string(),
|
|
3518
3685
|
models: array(string()),
|
|
3519
|
-
sourceTool: _enum(["claude-code", "opencode"]),
|
|
3686
|
+
sourceTool: _enum(["claude-code", "opencode", "mimo-code"]),
|
|
3520
3687
|
alreadyExists: boolean()
|
|
3521
3688
|
});
|
|
3522
3689
|
const ScanResponseSchema = object({
|
|
@@ -3531,7 +3698,8 @@ const ImportResponseSchema$1 = object({
|
|
|
3531
3698
|
});
|
|
3532
3699
|
const sourceLogoMap = {
|
|
3533
3700
|
"claude-code": ClaudeCodeIcon,
|
|
3534
|
-
opencode: OpenCodeIcon
|
|
3701
|
+
opencode: OpenCodeIcon,
|
|
3702
|
+
"mimo-code": MiMoCodeIcon
|
|
3535
3703
|
};
|
|
3536
3704
|
function ImportWizardDialog({
|
|
3537
3705
|
open,
|
|
@@ -3645,7 +3813,7 @@ function ImportWizardDialog({
|
|
|
3645
3813
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { className: "max-w-xl max-h-[80vh] overflow-hidden flex flex-col", children: [
|
|
3646
3814
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(DialogHeader, { children: [
|
|
3647
3815
|
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogTitle, { children: "Import from External Tools" }),
|
|
3648
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Detect provider configurations from Claude Code and
|
|
3816
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Detect provider configurations from Claude Code, OpenCode, and MiMo Code." })
|
|
3649
3817
|
] }),
|
|
3650
3818
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto space-y-3", children: [
|
|
3651
3819
|
scanning && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center py-8 gap-2 text-muted-foreground", children: [
|
|
@@ -3659,7 +3827,7 @@ function ImportWizardDialog({
|
|
|
3659
3827
|
!scanning && scanError === null && providers.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-sm text-muted-foreground py-8 text-center", children: [
|
|
3660
3828
|
"No external provider configurations found.",
|
|
3661
3829
|
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
3662
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Supported tools: Claude Code (~/.claude/settings.json), OpenCode (~/.config/opencode/opencode.json)" })
|
|
3830
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Supported tools: Claude Code (~/.claude/settings.json), OpenCode (~/.config/opencode/opencode.json), MiMo Code (~/.config/mimocode/mimocode.jsonc)" })
|
|
3663
3831
|
] }),
|
|
3664
3832
|
!scanning && providers.map((p, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3665
3833
|
"label",
|
|
@@ -3723,35 +3891,6 @@ function ImportWizardDialog({
|
|
|
3723
3891
|
] })
|
|
3724
3892
|
] }) });
|
|
3725
3893
|
}
|
|
3726
|
-
function ConfirmDialog({
|
|
3727
|
-
open,
|
|
3728
|
-
onOpenChange,
|
|
3729
|
-
title,
|
|
3730
|
-
description,
|
|
3731
|
-
confirmLabel = "Confirm",
|
|
3732
|
-
variant = "default",
|
|
3733
|
-
onConfirm
|
|
3734
|
-
}) {
|
|
3735
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { children: [
|
|
3736
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(DialogTitle, { children: title }) }),
|
|
3737
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground", children: description }),
|
|
3738
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [
|
|
3739
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outline", size: "sm", onClick: () => onOpenChange(false), children: "Cancel" }),
|
|
3740
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3741
|
-
Button,
|
|
3742
|
-
{
|
|
3743
|
-
variant,
|
|
3744
|
-
size: "sm",
|
|
3745
|
-
onClick: () => {
|
|
3746
|
-
onConfirm();
|
|
3747
|
-
onOpenChange(false);
|
|
3748
|
-
},
|
|
3749
|
-
children: confirmLabel
|
|
3750
|
-
}
|
|
3751
|
-
)
|
|
3752
|
-
] })
|
|
3753
|
-
] }) });
|
|
3754
|
-
}
|
|
3755
3894
|
function maskApiKey(apiKey) {
|
|
3756
3895
|
if (apiKey.length <= 8) return "••••••••";
|
|
3757
3896
|
return apiKey.slice(0, 4) + "••••••••" + apiKey.slice(-4);
|
|
@@ -5776,10 +5915,23 @@ function SideSummary({ log, side }) {
|
|
|
5776
5915
|
}
|
|
5777
5916
|
function CompareDrawer({ left, right, onClose }) {
|
|
5778
5917
|
const ops = reactExports.useMemo(() => {
|
|
5779
|
-
const
|
|
5780
|
-
|
|
5918
|
+
const leftRequest = getLogFormatAdapter(resolveLogFormat(left)).analyzeRequest(
|
|
5919
|
+
left.rawRequestBody
|
|
5920
|
+
);
|
|
5921
|
+
const rightRequest = getLogFormatAdapter(resolveLogFormat(right)).analyzeRequest(
|
|
5922
|
+
right.rawRequestBody
|
|
5923
|
+
);
|
|
5924
|
+
const l = normalizeRequest(leftRequest.comparisonValue);
|
|
5925
|
+
const r = normalizeRequest(rightRequest.comparisonValue);
|
|
5781
5926
|
return diffTrees(l, r);
|
|
5782
|
-
}, [
|
|
5927
|
+
}, [
|
|
5928
|
+
left.apiFormat,
|
|
5929
|
+
left.path,
|
|
5930
|
+
left.rawRequestBody,
|
|
5931
|
+
right.apiFormat,
|
|
5932
|
+
right.path,
|
|
5933
|
+
right.rawRequestBody
|
|
5934
|
+
]);
|
|
5783
5935
|
const grouped = reactExports.useMemo(() => groupContiguousEquals(ops), [ops]);
|
|
5784
5936
|
const counts = reactExports.useMemo(() => {
|
|
5785
5937
|
let added = 0;
|
|
@@ -6116,13 +6268,28 @@ function ProxyViewer({
|
|
|
6116
6268
|
onSessionChange,
|
|
6117
6269
|
onModelChange,
|
|
6118
6270
|
onClearAll,
|
|
6271
|
+
onClearGroup,
|
|
6119
6272
|
viewMode,
|
|
6120
6273
|
onViewModeChange,
|
|
6121
6274
|
strip
|
|
6122
6275
|
}) {
|
|
6123
|
-
const { totalIn, totalOut } = computeTokenSummary(logs);
|
|
6276
|
+
const { totalIn, totalOut } = reactExports.useMemo(() => computeTokenSummary(logs), [logs]);
|
|
6124
6277
|
const [exporting, setExporting] = reactExports.useState(false);
|
|
6125
6278
|
const [comparePair, setComparePair] = reactExports.useState(null);
|
|
6279
|
+
const [crabEntrancePhase, setCrabEntrancePhase] = reactExports.useState(
|
|
6280
|
+
"hidden"
|
|
6281
|
+
);
|
|
6282
|
+
reactExports.useEffect(() => {
|
|
6283
|
+
const perCrabDuration = 400;
|
|
6284
|
+
const startDelay = 50;
|
|
6285
|
+
const playingDone = startDelay + crabVariants.length * perCrabDuration;
|
|
6286
|
+
const t1 = setTimeout(() => setCrabEntrancePhase("playing"), startDelay);
|
|
6287
|
+
const t2 = setTimeout(() => setCrabEntrancePhase("done"), playingDone);
|
|
6288
|
+
return () => {
|
|
6289
|
+
clearTimeout(t1);
|
|
6290
|
+
clearTimeout(t2);
|
|
6291
|
+
};
|
|
6292
|
+
}, []);
|
|
6126
6293
|
const handleExport = reactExports.useCallback(async () => {
|
|
6127
6294
|
setExporting(true);
|
|
6128
6295
|
try {
|
|
@@ -6131,58 +6298,55 @@ function ProxyViewer({
|
|
|
6131
6298
|
setExporting(false);
|
|
6132
6299
|
}
|
|
6133
6300
|
}, [logs]);
|
|
6134
|
-
const parentRef = reactExports.useRef(null);
|
|
6135
6301
|
reactExports.useEffect(() => {
|
|
6136
6302
|
setComparePair(null);
|
|
6137
6303
|
}, [selectedSession, selectedModel]);
|
|
6138
6304
|
const closeCompare = reactExports.useCallback(() => {
|
|
6139
6305
|
setComparePair(null);
|
|
6140
6306
|
}, []);
|
|
6307
|
+
const groups = reactExports.useMemo(() => groupLogsByConversation(logs), [logs]);
|
|
6308
|
+
const cacheTrends = reactExports.useMemo(() => computeCacheTrends(groups), [groups]);
|
|
6309
|
+
const comparisonPredecessors = reactExports.useMemo(() => buildValidPredecessors(groups), [groups]);
|
|
6141
6310
|
const handleCompareWithPrevious = reactExports.useCallback(
|
|
6142
6311
|
(log) => {
|
|
6143
|
-
const
|
|
6144
|
-
if (
|
|
6145
|
-
const predecessor = logs[idx - 1];
|
|
6146
|
-
if (predecessor === void 0) return;
|
|
6147
|
-
setComparePair([predecessor, log]);
|
|
6312
|
+
const predecessor = comparisonPredecessors.get(log.id);
|
|
6313
|
+
if (predecessor !== void 0) setComparePair([predecessor, log]);
|
|
6148
6314
|
},
|
|
6149
|
-
[
|
|
6315
|
+
[comparisonPredecessors]
|
|
6150
6316
|
);
|
|
6151
|
-
const groups = reactExports.useMemo(() => groupLogsByConversation(logs), [logs]);
|
|
6152
|
-
const cacheTrends = reactExports.useMemo(() => computeCacheTrends(groups), [groups]);
|
|
6153
|
-
const rowVirtualizer = useVirtualizer({
|
|
6154
|
-
count: groups.length,
|
|
6155
|
-
getScrollElement: () => parentRef.current,
|
|
6156
|
-
estimateSize: () => 150,
|
|
6157
|
-
measureElement: typeof window !== "undefined" ? (element) => element.getBoundingClientRect().height : void 0,
|
|
6158
|
-
overscan: 5
|
|
6159
|
-
});
|
|
6160
6317
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-[1200px] mx-auto flex flex-col h-screen", style: { maxHeight: "100vh" }, children: [
|
|
6161
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end px-6 pt-6 pb-
|
|
6318
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end px-6 pt-6 pb-8 relative", children: [
|
|
6162
6319
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-lg font-bold flex items-end gap-2 absolute left-1/2 -translate-x-1/2 whitespace-nowrap", children: [
|
|
6163
6320
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-end gap-1 group cursor-default", "aria-hidden": "true", children: [
|
|
6164
6321
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-10 text-amber-500 transition-all duration-300 group-hover:scale-125 group-hover:-translate-y-1.5" }),
|
|
6165
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex items-end gap-0.5", children: crabVariants.map((Crab, i) =>
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6322
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex items-end gap-0.5", children: crabVariants.map((Crab, i) => {
|
|
6323
|
+
const color = [
|
|
6324
|
+
"text-amber-500",
|
|
6325
|
+
"text-rose-500",
|
|
6326
|
+
"text-sky-500",
|
|
6327
|
+
"text-emerald-500",
|
|
6328
|
+
"text-violet-500",
|
|
6329
|
+
"text-orange-500",
|
|
6330
|
+
"text-cyan-500",
|
|
6331
|
+
"text-pink-500",
|
|
6332
|
+
"text-lime-500",
|
|
6333
|
+
"text-blue-500",
|
|
6334
|
+
"text-yellow-500",
|
|
6335
|
+
"text-fuchsia-500"
|
|
6336
|
+
][i];
|
|
6337
|
+
const entranceClass = crabEntrancePhase === "hidden" ? "opacity-0 scale-0" : crabEntrancePhase === "playing" ? "animate-crab-piano-pop" : "";
|
|
6338
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6339
|
+
Crab,
|
|
6340
|
+
{
|
|
6341
|
+
className: `size-5 ${color} transition-all duration-300 ease-out group-hover:scale-125 group-hover:-translate-y-1 ${entranceClass}`,
|
|
6342
|
+
style: {
|
|
6343
|
+
transitionDelay: `${i * 50}ms`,
|
|
6344
|
+
...crabEntrancePhase === "playing" ? { animationDelay: `${i * 400}ms` } : {}
|
|
6345
|
+
}
|
|
6346
|
+
},
|
|
6347
|
+
i
|
|
6348
|
+
);
|
|
6349
|
+
}) })
|
|
6186
6350
|
] }),
|
|
6187
6351
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-baseline gap-2", children: [
|
|
6188
6352
|
"LLM Inspector",
|
|
@@ -6267,59 +6431,26 @@ function ProxyViewer({
|
|
|
6267
6431
|
)
|
|
6268
6432
|
] }),
|
|
6269
6433
|
/* @__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: [
|
|
6270
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-12 text-muted-foreground/20 mx-auto" }),
|
|
6271
6434
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm", children: "No requests captured yet." }),
|
|
6272
6435
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs", children: "Route AI coding tools through the proxy:" }),
|
|
6273
6436
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CopyableCommand, { command: "LLM_BASE_URL=http://localhost:25947/proxy <your-tool>" })
|
|
6274
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", {
|
|
6275
|
-
|
|
6437
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-y-auto h-full flex flex-col gap-2", children: groups.map((group) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6438
|
+
ConversationGroup,
|
|
6276
6439
|
{
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
"data-index": virtualRow.index,
|
|
6289
|
-
ref: rowVirtualizer.measureElement,
|
|
6290
|
-
style: {
|
|
6291
|
-
position: "absolute",
|
|
6292
|
-
top: 0,
|
|
6293
|
-
left: 0,
|
|
6294
|
-
width: "100%",
|
|
6295
|
-
transform: `translateY(${virtualRow.start}px)`
|
|
6296
|
-
},
|
|
6297
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6298
|
-
ConversationGroup,
|
|
6299
|
-
{
|
|
6300
|
-
group,
|
|
6301
|
-
viewMode,
|
|
6302
|
-
strip,
|
|
6303
|
-
cacheTrends,
|
|
6304
|
-
onCompareWithPrevious: handleCompareWithPrevious,
|
|
6305
|
-
standalone: groups.length === 1
|
|
6306
|
-
}
|
|
6307
|
-
)
|
|
6308
|
-
},
|
|
6309
|
-
group.id
|
|
6310
|
-
);
|
|
6311
|
-
})
|
|
6312
|
-
}
|
|
6313
|
-
) }) }),
|
|
6440
|
+
group,
|
|
6441
|
+
viewMode,
|
|
6442
|
+
strip,
|
|
6443
|
+
cacheTrends,
|
|
6444
|
+
onCompareWithPrevious: handleCompareWithPrevious,
|
|
6445
|
+
comparisonPredecessors,
|
|
6446
|
+
onClearGroup,
|
|
6447
|
+
standalone: groups.length === 1
|
|
6448
|
+
},
|
|
6449
|
+
group.id
|
|
6450
|
+
)) }) }),
|
|
6314
6451
|
comparePair !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(CompareDrawer, { left: comparePair[0], right: comparePair[1], onClose: closeCompare })
|
|
6315
6452
|
] });
|
|
6316
6453
|
}
|
|
6317
|
-
object({
|
|
6318
|
-
logs: array(CapturedLogSchema),
|
|
6319
|
-
total: number(),
|
|
6320
|
-
offset: number(),
|
|
6321
|
-
limit: number()
|
|
6322
|
-
});
|
|
6323
6454
|
const SSEUpdateSchema = union([
|
|
6324
6455
|
object({
|
|
6325
6456
|
type: literal("init"),
|
|
@@ -6344,8 +6475,17 @@ function extractModels(logs) {
|
|
|
6344
6475
|
}
|
|
6345
6476
|
return [...set];
|
|
6346
6477
|
}
|
|
6478
|
+
function filterLogs(logs, selectedSession, selectedModel) {
|
|
6479
|
+
if (selectedSession === "__all__" && selectedModel === "__all__") return logs;
|
|
6480
|
+
return logs.filter((l) => {
|
|
6481
|
+
if (selectedSession !== "__all__" && l.sessionId !== selectedSession) return false;
|
|
6482
|
+
if (selectedModel !== "__all__" && l.model !== selectedModel) return false;
|
|
6483
|
+
return true;
|
|
6484
|
+
});
|
|
6485
|
+
}
|
|
6486
|
+
const DEBOUNCE_MS = 50;
|
|
6347
6487
|
function ProxyViewerContainer() {
|
|
6348
|
-
const [
|
|
6488
|
+
const [allLogs, setAllLogs] = reactExports.useState([]);
|
|
6349
6489
|
const [sessions, setSessions] = reactExports.useState([]);
|
|
6350
6490
|
const [models, setModels] = reactExports.useState([]);
|
|
6351
6491
|
const [selectedSession, setSelectedSession] = reactExports.useState("__all__");
|
|
@@ -6354,31 +6494,58 @@ function ProxyViewerContainer() {
|
|
|
6354
6494
|
const [error, setError] = reactExports.useState(null);
|
|
6355
6495
|
const eventSourceRef = reactExports.useRef(null);
|
|
6356
6496
|
const reconnectTimeoutRef = reactExports.useRef(null);
|
|
6357
|
-
const
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6497
|
+
const logIndexRef = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
6498
|
+
const logsRef = reactExports.useRef([]);
|
|
6499
|
+
const pendingUpdatesRef = reactExports.useRef([]);
|
|
6500
|
+
const flushTimerRef = reactExports.useRef(null);
|
|
6501
|
+
const logs = reactExports.useMemo(
|
|
6502
|
+
() => filterLogs(allLogs, selectedSession, selectedModel),
|
|
6503
|
+
[allLogs, selectedSession, selectedModel]
|
|
6504
|
+
);
|
|
6505
|
+
const flushUpdates = reactExports.useCallback(() => {
|
|
6506
|
+
flushTimerRef.current = null;
|
|
6507
|
+
const updates = pendingUpdatesRef.current;
|
|
6508
|
+
pendingUpdatesRef.current = [];
|
|
6509
|
+
if (updates.length === 0) return;
|
|
6510
|
+
setAllLogs((prev) => {
|
|
6511
|
+
let next = prev;
|
|
6512
|
+
let sessionsChanged = false;
|
|
6513
|
+
let modelsChanged = false;
|
|
6514
|
+
for (const log of updates) {
|
|
6515
|
+
const idx = logIndexRef.current.get(log.id);
|
|
6516
|
+
if (idx !== void 0) {
|
|
6517
|
+
next = [...next.slice(0, idx), log, ...next.slice(idx + 1)];
|
|
6518
|
+
} else {
|
|
6519
|
+
logIndexRef.current.set(log.id, next.length);
|
|
6520
|
+
next = [...next, log];
|
|
6521
|
+
}
|
|
6522
|
+
if (log.sessionId !== null && log.sessionId !== "" && !sessions.includes(log.sessionId)) {
|
|
6523
|
+
sessionsChanged = true;
|
|
6524
|
+
}
|
|
6525
|
+
if (log.model !== null && log.model !== "" && !models.includes(log.model)) {
|
|
6526
|
+
modelsChanged = true;
|
|
6527
|
+
}
|
|
6370
6528
|
}
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6529
|
+
logsRef.current = next;
|
|
6530
|
+
if (sessionsChanged) setSessions((s) => extractSessions(next));
|
|
6531
|
+
if (modelsChanged) setModels((m) => extractModels(next));
|
|
6532
|
+
return next;
|
|
6533
|
+
});
|
|
6534
|
+
}, [sessions, models]);
|
|
6535
|
+
const scheduleUpdate = reactExports.useCallback(
|
|
6536
|
+
(log) => {
|
|
6537
|
+
pendingUpdatesRef.current.push(log);
|
|
6538
|
+
if (flushTimerRef.current === null) {
|
|
6539
|
+
flushTimerRef.current = setTimeout(flushUpdates, DEBOUNCE_MS);
|
|
6540
|
+
}
|
|
6541
|
+
},
|
|
6542
|
+
[flushUpdates]
|
|
6543
|
+
);
|
|
6374
6544
|
const connectSSE = reactExports.useCallback(() => {
|
|
6375
6545
|
if (eventSourceRef.current) {
|
|
6376
6546
|
eventSourceRef.current.close();
|
|
6377
6547
|
}
|
|
6378
|
-
const
|
|
6379
|
-
if (selectedSession !== "__all__") params.set("sessionId", selectedSession);
|
|
6380
|
-
if (selectedModel !== "__all__") params.set("model", selectedModel);
|
|
6381
|
-
const es = new EventSource(`/api/logs/stream?${params}`);
|
|
6548
|
+
const es = new EventSource("/api/logs/stream");
|
|
6382
6549
|
eventSourceRef.current = es;
|
|
6383
6550
|
es.onmessage = (event) => {
|
|
6384
6551
|
try {
|
|
@@ -6391,35 +6558,24 @@ function ProxyViewerContainer() {
|
|
|
6391
6558
|
}
|
|
6392
6559
|
const update = updateResult.data;
|
|
6393
6560
|
if (update.type === "init") {
|
|
6394
|
-
|
|
6561
|
+
if (flushTimerRef.current !== null) {
|
|
6562
|
+
clearTimeout(flushTimerRef.current);
|
|
6563
|
+
flushTimerRef.current = null;
|
|
6564
|
+
}
|
|
6565
|
+
pendingUpdatesRef.current = [];
|
|
6566
|
+
const idx = /* @__PURE__ */ new Map();
|
|
6567
|
+
for (let i = 0; i < update.logs.length; i++) {
|
|
6568
|
+
const log = update.logs[i];
|
|
6569
|
+
if (log !== void 0) idx.set(log.id, i);
|
|
6570
|
+
}
|
|
6571
|
+
logIndexRef.current = idx;
|
|
6572
|
+
logsRef.current = update.logs;
|
|
6573
|
+
setAllLogs(update.logs);
|
|
6395
6574
|
setSessions(extractSessions(update.logs));
|
|
6396
6575
|
setModels(extractModels(update.logs));
|
|
6397
6576
|
setError(null);
|
|
6398
6577
|
} else if (update.type === "update") {
|
|
6399
|
-
|
|
6400
|
-
const sessionMatch = selectedSession === "__all__" || update.log.sessionId === selectedSession;
|
|
6401
|
-
const modelMatch = selectedModel === "__all__" || update.log.model === selectedModel;
|
|
6402
|
-
if (!sessionMatch || !modelMatch) return prev;
|
|
6403
|
-
const existsIndex = prev.findIndex((l) => l.id === update.log.id);
|
|
6404
|
-
if (existsIndex >= 0) {
|
|
6405
|
-
return prev.map((l) => l.id === update.log.id ? update.log : l);
|
|
6406
|
-
}
|
|
6407
|
-
return [...prev, update.log];
|
|
6408
|
-
});
|
|
6409
|
-
setSessions((prev) => {
|
|
6410
|
-
const sessionId = update.log.sessionId;
|
|
6411
|
-
if (sessionId !== null && sessionId !== void 0 && sessionId !== "") {
|
|
6412
|
-
return prev.includes(sessionId) ? prev : [...prev, sessionId];
|
|
6413
|
-
}
|
|
6414
|
-
return prev;
|
|
6415
|
-
});
|
|
6416
|
-
setModels((prev) => {
|
|
6417
|
-
const model = update.log.model;
|
|
6418
|
-
if (model !== null && model !== void 0 && model !== "") {
|
|
6419
|
-
return prev.includes(model) ? prev : [...prev, model];
|
|
6420
|
-
}
|
|
6421
|
-
return prev;
|
|
6422
|
-
});
|
|
6578
|
+
scheduleUpdate(update.log);
|
|
6423
6579
|
}
|
|
6424
6580
|
} catch {
|
|
6425
6581
|
setError("Failed to parse SSE data");
|
|
@@ -6433,8 +6589,7 @@ function ProxyViewerContainer() {
|
|
|
6433
6589
|
}
|
|
6434
6590
|
reconnectTimeoutRef.current = setTimeout(connectSSE, 3e3);
|
|
6435
6591
|
};
|
|
6436
|
-
|
|
6437
|
-
}, [selectedSession, selectedModel, fetchSessionsAndModels]);
|
|
6592
|
+
}, [scheduleUpdate]);
|
|
6438
6593
|
reactExports.useEffect(() => {
|
|
6439
6594
|
connectSSE();
|
|
6440
6595
|
return () => {
|
|
@@ -6446,6 +6601,10 @@ function ProxyViewerContainer() {
|
|
|
6446
6601
|
clearTimeout(reconnectTimeoutRef.current);
|
|
6447
6602
|
reconnectTimeoutRef.current = null;
|
|
6448
6603
|
}
|
|
6604
|
+
if (flushTimerRef.current !== null) {
|
|
6605
|
+
clearTimeout(flushTimerRef.current);
|
|
6606
|
+
flushTimerRef.current = null;
|
|
6607
|
+
}
|
|
6449
6608
|
};
|
|
6450
6609
|
}, [connectSSE]);
|
|
6451
6610
|
const handleClearAll = reactExports.useCallback(() => {
|
|
@@ -6456,7 +6615,9 @@ function ProxyViewerContainer() {
|
|
|
6456
6615
|
setError("Failed to clear logs");
|
|
6457
6616
|
return;
|
|
6458
6617
|
}
|
|
6459
|
-
|
|
6618
|
+
logIndexRef.current.clear();
|
|
6619
|
+
logsRef.current = [];
|
|
6620
|
+
setAllLogs([]);
|
|
6460
6621
|
setSessions([]);
|
|
6461
6622
|
setModels([]);
|
|
6462
6623
|
setError(null);
|
|
@@ -6465,6 +6626,39 @@ function ProxyViewerContainer() {
|
|
|
6465
6626
|
}
|
|
6466
6627
|
})();
|
|
6467
6628
|
}, []);
|
|
6629
|
+
const handleClearGroup = reactExports.useCallback((ids) => {
|
|
6630
|
+
if (ids.length === 0) return;
|
|
6631
|
+
void (async () => {
|
|
6632
|
+
try {
|
|
6633
|
+
const res = await fetch("/api/logs", {
|
|
6634
|
+
method: "DELETE",
|
|
6635
|
+
headers: { "Content-Type": "application/json" },
|
|
6636
|
+
body: JSON.stringify({ ids })
|
|
6637
|
+
});
|
|
6638
|
+
if (!res.ok) {
|
|
6639
|
+
setError("Failed to clear group");
|
|
6640
|
+
return;
|
|
6641
|
+
}
|
|
6642
|
+
const idSet = new Set(ids);
|
|
6643
|
+
setAllLogs((prev) => {
|
|
6644
|
+
const remaining = prev.filter((l) => !idSet.has(l.id));
|
|
6645
|
+
const idx = /* @__PURE__ */ new Map();
|
|
6646
|
+
for (let i = 0; i < remaining.length; i++) {
|
|
6647
|
+
const log = remaining[i];
|
|
6648
|
+
if (log !== void 0) idx.set(log.id, i);
|
|
6649
|
+
}
|
|
6650
|
+
logIndexRef.current = idx;
|
|
6651
|
+
logsRef.current = remaining;
|
|
6652
|
+
setSessions(extractSessions(remaining));
|
|
6653
|
+
setModels(extractModels(remaining));
|
|
6654
|
+
return remaining;
|
|
6655
|
+
});
|
|
6656
|
+
setError(null);
|
|
6657
|
+
} catch (err) {
|
|
6658
|
+
setError(err instanceof Error ? err.message : "Unknown error clearing group");
|
|
6659
|
+
}
|
|
6660
|
+
})();
|
|
6661
|
+
}, []);
|
|
6468
6662
|
const { strip } = useStripConfig();
|
|
6469
6663
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
6470
6664
|
error !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed top-4 right-4 bg-destructive text-destructive-foreground px-4 py-2 rounded-md text-sm z-50", children: error }),
|
|
@@ -6479,6 +6673,7 @@ function ProxyViewerContainer() {
|
|
|
6479
6673
|
onSessionChange: setSelectedSession,
|
|
6480
6674
|
onModelChange: setSelectedModel,
|
|
6481
6675
|
onClearAll: handleClearAll,
|
|
6676
|
+
onClearGroup: handleClearGroup,
|
|
6482
6677
|
viewMode,
|
|
6483
6678
|
onViewModeChange: setViewMode,
|
|
6484
6679
|
strip
|