@tonyclaw/agent-inspector 2.0.35 → 2.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-Cin0_f71.js → CompareDrawer-nEHCEVP4.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-BVlcRirf.js → ProxyViewerContainer-BstBIX2B.js} +35 -35
- package/.output/public/assets/{ReplayDialog-C6nOMhjx.js → ReplayDialog-CUnBdt1Q.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-DenWbdqV.js → RequestAnatomy-BU9VT2Sw.js} +1 -1
- package/.output/public/assets/{ResponseView-BsalZiZ5.js → ResponseView-amxuKPKY.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-Cla2X13P.js → StreamingChunkSequence-DpscrQM2.js} +1 -1
- package/.output/public/assets/_sessionId-7c9bsOFT.js +1 -0
- package/.output/public/assets/index-B7a5OmIO.js +1 -0
- package/.output/public/assets/{main-eD8hEOHT.js → main-D56QvEyw.js} +4 -4
- package/.output/server/_libs/lucide-react.mjs +114 -94
- package/.output/server/{_sessionId-URSu2XsA.mjs → _sessionId-ChwEDyI4.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-BbBPKdVc.mjs → CompareDrawer-Ce2590rK.mjs} +3 -3
- package/.output/server/_ssr/{ProxyViewerContainer-DtQxtOpi.mjs → ProxyViewerContainer-D6xM8A0S.mjs} +797 -781
- package/.output/server/_ssr/{ReplayDialog-BU20cMGd.mjs → ReplayDialog-CB4KOlLe.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-a5ySAAG1.mjs → RequestAnatomy-CsWV3W03.mjs} +3 -3
- package/.output/server/_ssr/{ResponseView-CA_QM1fM.mjs → ResponseView-BuCCV3LU.mjs} +3 -3
- package/.output/server/_ssr/{StreamingChunkSequence-DJjITqM7.mjs → StreamingChunkSequence-C5dE7V1d.mjs} +2 -2
- package/.output/server/_ssr/{index-DIFzLUAV.mjs → index-BeIi0CPv.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-aVeuM_1d.mjs → router-Ca2MCyUX.mjs} +91 -71
- package/.output/server/{_tanstack-start-manifest_v-BNlafGbl.mjs → _tanstack-start-manifest_v-CBAJfSAX.mjs} +1 -1
- package/.output/server/index.mjs +55 -55
- package/package.json +1 -1
- package/src/components/ProxyViewer.tsx +42 -8
- package/src/components/proxy-viewer/ConversationHeader.tsx +10 -6
- package/src/proxy/formats/registry.ts +7 -1
- package/src/proxy/store.ts +14 -11
- package/src/router.tsx +17 -0
- package/.output/public/assets/_sessionId-DkhHqlzB.js +0 -1
- package/.output/public/assets/index-AiQY20d7.js +0 -1
package/.output/server/_ssr/{ProxyViewerContainer-DtQxtOpi.mjs → ProxyViewerContainer-D6xM8A0S.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
|
|
2
|
-
import { C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, v as packageJson, h as GroupEvidenceExportResultSchema, i as DeleteInspectorGroupResponseSchema, d as RuntimeConfigSchema, P as ProviderConfigSchema, r as requestFormatForPath, l as createPendingProviderTestResults, n as ProviderTestResultsSchema, o as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, q as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, m as maskApiKey, j as providerHasContextMetadata, k as findProviderModelMetadata, g as getSessionPath, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, t as resolveProviderContextWindow, K as KnowledgeCandidateSchema, f as stripClaudeCodeBillingHeader, u as isPlainRecord, G as GroupEvidenceReadResponseSchema, I as InspectorGroupsListResponseSchema } from "./router-
|
|
2
|
+
import { C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, v as packageJson, h as GroupEvidenceExportResultSchema, i as DeleteInspectorGroupResponseSchema, d as RuntimeConfigSchema, P as ProviderConfigSchema, r as requestFormatForPath, l as createPendingProviderTestResults, n as ProviderTestResultsSchema, o as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, q as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, m as maskApiKey, j as providerHasContextMetadata, k as findProviderModelMetadata, g as getSessionPath, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, t as resolveProviderContextWindow, K as KnowledgeCandidateSchema, f as stripClaudeCodeBillingHeader, u as isPlainRecord, G as GroupEvidenceReadResponseSchema, I as InspectorGroupsListResponseSchema } from "./router-Ca2MCyUX.mjs";
|
|
3
3
|
import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
|
|
4
4
|
import { J as JSZip } from "../_libs/jszip.mjs";
|
|
5
5
|
import { c as clsx } from "../_libs/clsx.mjs";
|
|
@@ -9,7 +9,7 @@ import { R as Root, T as Trigger$2, C as Content, a as Close, b as Title, P as P
|
|
|
9
9
|
import { d as diffJson, a as diffLines } from "../_libs/diff.mjs";
|
|
10
10
|
import { u as useWindowVirtualizer, a as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
|
|
11
11
|
import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Content2, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
|
|
12
|
-
import { C as Check, X, P as Plus, D as Download, L as Layers, a as LoaderCircle, R as RefreshCw, S as Settings, A as ArrowLeft, b as Copy, c as ChevronDown,
|
|
12
|
+
import { C as Check, X, P as Plus, D as Download, F as FileBraces, T as Trash2, L as Layers, a as LoaderCircle, R as RefreshCw, S as Settings, A as ArrowLeft, b as Copy, c as ChevronDown, U as Upload, d as Scan, e as CircleAlert, f as Terminal, g as ChevronUp, E as EyeOff, h as Eye, i as ExternalLink, j as RotateCw, k as Clock, l as ChevronRight, m as Pencil, n as ArrowUpRight, o as ArrowDownRight, p as User, M as MessageSquare, Z as Zap, W as Wrench, q as TriangleAlert, B as Brain, r as Minus, s as CircleCheckBig, t as CircleX, u as ShieldCheck, v as Save, w as FileSearch, x as CircleCheck, y as CloudUpload, O as OctagonAlert, z as Radio, G as Gauge, H as Globe, I as FileTerminal, J as ChevronsUp, K as ChevronsDown, N as FileDiff, Q as History, V as RotateCcw, Y as Search, _ as GitCompareArrows, $ as CircleQuestionMark, a0 as Server, a1 as Lock, a2 as Wifi, a3 as WifiOff, a4 as ArrowUp, a5 as ArrowDown, a6 as Ellipsis, a7 as CodeXml, a8 as Blocks, a9 as MousePointerClick, aa as FileText, ab as Rows3, ac as Columns2 } from "../_libs/lucide-react.mjs";
|
|
13
13
|
import { M as Markdown } from "../_libs/react-markdown.mjs";
|
|
14
14
|
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";
|
|
15
15
|
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";
|
|
@@ -700,264 +700,573 @@ function ConfirmDialog({
|
|
|
700
700
|
] })
|
|
701
701
|
] }) });
|
|
702
702
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
703
|
+
function forEachCodePoint(text, visit) {
|
|
704
|
+
for (const ch of Array.from(text)) {
|
|
705
|
+
visit(ch);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
const CJK_REGEX = /[\u3000-\u9FFF\uAC00-\uD7FF\uF900-\uFAFF\uFF00-\uFFEF\u{1F300}-\u{1FAFF}]/u;
|
|
709
|
+
function estimateTokens(text) {
|
|
710
|
+
if (text.length === 0) return 0;
|
|
711
|
+
let cjk = 0;
|
|
712
|
+
let other = 0;
|
|
713
|
+
forEachCodePoint(text, (ch) => {
|
|
714
|
+
if (CJK_REGEX.test(ch)) {
|
|
715
|
+
cjk += 1;
|
|
716
|
+
} else {
|
|
717
|
+
other += 1;
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
return Math.ceil(cjk * 1) + Math.ceil(other / 4);
|
|
721
|
+
}
|
|
722
|
+
function countCharacters(text) {
|
|
723
|
+
if (text.length === 0) return 0;
|
|
724
|
+
let n = 0;
|
|
725
|
+
forEachCodePoint(text, () => {
|
|
726
|
+
n += 1;
|
|
727
|
+
});
|
|
728
|
+
return n;
|
|
729
|
+
}
|
|
730
|
+
function emptyRequestAnalysis(rawBody) {
|
|
731
|
+
return {
|
|
732
|
+
parsed: null,
|
|
733
|
+
comparisonValue: rawBody,
|
|
734
|
+
messageCount: null,
|
|
735
|
+
toolCount: null
|
|
729
736
|
};
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
);
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
children: conversationId.startsWith("PID:") || conversationId.includes("|") ? conversationId : conversationId.length > 24 ? conversationId.slice(0, 12) + "..." + conversationId.slice(-12) : conversationId
|
|
767
|
-
}
|
|
768
|
-
),
|
|
769
|
-
userAgent !== null && userAgent !== void 0 && userAgent !== "" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
770
|
-
"span",
|
|
771
|
-
{
|
|
772
|
-
className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0",
|
|
773
|
-
title: userAgent,
|
|
774
|
-
children: [
|
|
775
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(User, { className: "size-3" }),
|
|
776
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[120px]", children: userAgent })
|
|
777
|
-
]
|
|
778
|
-
}
|
|
779
|
-
),
|
|
780
|
-
!hideApiFormat && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
781
|
-
Badge,
|
|
782
|
-
{
|
|
783
|
-
variant: "outline",
|
|
784
|
-
className: cn(
|
|
785
|
-
"text-[10px] px-1.5 py-0 h-5 font-mono shrink-0",
|
|
786
|
-
apiFormat === "openai" && "border-blue-500/40 text-blue-400",
|
|
787
|
-
apiFormat === "anthropic" && "border-orange-500/40 text-orange-400",
|
|
788
|
-
apiFormat === "unknown" && "border-muted text-muted-foreground"
|
|
789
|
-
),
|
|
790
|
-
children: API_FORMAT_LABELS[apiFormat]
|
|
791
|
-
}
|
|
792
|
-
),
|
|
793
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
794
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
|
|
795
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatTimestampRange(startTime, endTime, timeDisplayFormat) })
|
|
796
|
-
] }),
|
|
797
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
798
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3" }),
|
|
799
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
800
|
-
totalCalls,
|
|
801
|
-
" call",
|
|
802
|
-
totalCalls !== 1 ? "s" : ""
|
|
803
|
-
] })
|
|
804
|
-
] }),
|
|
805
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
|
|
806
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
|
|
807
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
808
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-400", children: formatTokens(totalInputTokens) }),
|
|
809
|
-
" / ",
|
|
810
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-amber-400", children: formatTokens(totalOutputTokens) })
|
|
811
|
-
] })
|
|
812
|
-
] }),
|
|
813
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
|
|
814
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
815
|
-
"button",
|
|
816
|
-
{
|
|
817
|
-
type: "button",
|
|
818
|
-
onClick: handleOpenInNewTab,
|
|
819
|
-
onKeyDown: (e) => {
|
|
820
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
821
|
-
handleOpenInNewTab(e);
|
|
822
|
-
}
|
|
823
|
-
},
|
|
824
|
-
"aria-label": `Open session ${conversationId} in a new tab`,
|
|
825
|
-
title: "Open this session in a new tab",
|
|
826
|
-
className: "text-muted-foreground hover:text-foreground transition-colors shrink-0 inline-flex items-center justify-center size-8 rounded hover:bg-muted cursor-pointer",
|
|
827
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-3.5" })
|
|
828
|
-
}
|
|
829
|
-
),
|
|
830
|
-
onClear !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
831
|
-
"button",
|
|
832
|
-
{
|
|
833
|
-
type: "button",
|
|
834
|
-
onClick: handleClearClick,
|
|
835
|
-
"aria-label": `Clear group (${totalCalls} request${totalCalls !== 1 ? "s" : ""})`,
|
|
836
|
-
title: "Clear this group",
|
|
837
|
-
className: "text-muted-foreground hover:text-foreground transition-colors shrink-0 inline-flex items-center justify-center size-8 rounded hover:bg-muted cursor-pointer",
|
|
838
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" })
|
|
839
|
-
}
|
|
840
|
-
),
|
|
841
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
842
|
-
ConfirmDialog,
|
|
843
|
-
{
|
|
844
|
-
open: confirmOpen,
|
|
845
|
-
onOpenChange: setConfirmOpen,
|
|
846
|
-
title: "Clear this group?",
|
|
847
|
-
description: `This will remove ${totalCalls} request${totalCalls !== 1 ? "s" : ""} from this conversation. This action cannot be undone.`,
|
|
848
|
-
confirmLabel: "Clear",
|
|
849
|
-
variant: "destructive",
|
|
850
|
-
onConfirm: () => {
|
|
851
|
-
onClear?.();
|
|
737
|
+
}
|
|
738
|
+
const EMPTY_RESPONSE_ANALYSIS = {
|
|
739
|
+
parsed: null,
|
|
740
|
+
toolNames: null
|
|
741
|
+
};
|
|
742
|
+
function contentToText$1(content) {
|
|
743
|
+
if (typeof content === "string") return content;
|
|
744
|
+
if (!Array.isArray(content)) return "";
|
|
745
|
+
const parts = [];
|
|
746
|
+
for (const block of content) {
|
|
747
|
+
if (block === null || typeof block !== "object") continue;
|
|
748
|
+
const b = block;
|
|
749
|
+
const type = b.type;
|
|
750
|
+
switch (type) {
|
|
751
|
+
case "text":
|
|
752
|
+
if (typeof b.text === "string") parts.push(b.text);
|
|
753
|
+
break;
|
|
754
|
+
case "thinking":
|
|
755
|
+
case "think":
|
|
756
|
+
if (typeof b.thinking === "string") parts.push(b.thinking);
|
|
757
|
+
break;
|
|
758
|
+
case "tool_use": {
|
|
759
|
+
const name = typeof b.name === "string" ? b.name : "";
|
|
760
|
+
const input = b.input !== void 0 ? JSON.stringify(b.input) : "";
|
|
761
|
+
parts.push(`${name} ${input}`.trim());
|
|
762
|
+
break;
|
|
763
|
+
}
|
|
764
|
+
case "tool_result": {
|
|
765
|
+
const inner = b.content;
|
|
766
|
+
if (typeof inner === "string") {
|
|
767
|
+
parts.push(inner);
|
|
768
|
+
} else if (Array.isArray(inner)) {
|
|
769
|
+
for (const item of inner) {
|
|
770
|
+
if (item !== null && typeof item === "object") {
|
|
771
|
+
const t = item.text;
|
|
772
|
+
if (typeof t === "string") parts.push(t);
|
|
852
773
|
}
|
|
853
774
|
}
|
|
854
|
-
|
|
855
|
-
|
|
775
|
+
}
|
|
776
|
+
break;
|
|
777
|
+
}
|
|
778
|
+
case "image":
|
|
779
|
+
parts.push("[image]");
|
|
780
|
+
break;
|
|
856
781
|
}
|
|
857
|
-
|
|
782
|
+
}
|
|
783
|
+
return parts.join("\n");
|
|
858
784
|
}
|
|
859
|
-
function
|
|
860
|
-
|
|
861
|
-
if (
|
|
862
|
-
|
|
785
|
+
function systemToText(system) {
|
|
786
|
+
if (typeof system === "string") return system;
|
|
787
|
+
if (!Array.isArray(system)) return "";
|
|
788
|
+
const parts = [];
|
|
789
|
+
for (const block of system) {
|
|
790
|
+
if (block !== null && typeof block === "object") {
|
|
791
|
+
const t = block.text;
|
|
792
|
+
const type = block.type;
|
|
793
|
+
if (type === "text" && typeof t === "string") parts.push(t);
|
|
794
|
+
}
|
|
863
795
|
}
|
|
864
|
-
return
|
|
796
|
+
return parts.join("\n");
|
|
865
797
|
}
|
|
866
|
-
function
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
for (const
|
|
870
|
-
if (
|
|
871
|
-
|
|
872
|
-
if (
|
|
798
|
+
function toolsToText$1(tools) {
|
|
799
|
+
if (!Array.isArray(tools)) return "";
|
|
800
|
+
const parts = [];
|
|
801
|
+
for (const tool of tools) {
|
|
802
|
+
if (tool === null || typeof tool !== "object") continue;
|
|
803
|
+
const t = tool;
|
|
804
|
+
if (typeof t.name === "string") parts.push(t.name);
|
|
805
|
+
if (typeof t.description === "string") parts.push(t.description);
|
|
806
|
+
if (t.input_schema !== void 0) parts.push(JSON.stringify(t.input_schema));
|
|
873
807
|
}
|
|
874
|
-
return
|
|
808
|
+
return parts.join("\n");
|
|
875
809
|
}
|
|
876
|
-
function
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
810
|
+
function segment$1(role, label, text, path) {
|
|
811
|
+
return {
|
|
812
|
+
role,
|
|
813
|
+
label,
|
|
814
|
+
text,
|
|
815
|
+
size: estimateTokens(text),
|
|
816
|
+
characters: countCharacters(text),
|
|
817
|
+
path
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
const anthropicLogFormatAdapter = {
|
|
821
|
+
format: "anthropic",
|
|
822
|
+
analyzeRequest(rawBody) {
|
|
823
|
+
if (rawBody === null) return emptyRequestAnalysis(rawBody);
|
|
824
|
+
try {
|
|
825
|
+
const result = AnthropicRequestSchema.safeParse(JSON.parse(rawBody));
|
|
826
|
+
if (!result.success) return emptyRequestAnalysis(rawBody);
|
|
827
|
+
return {
|
|
828
|
+
parsed: result.data,
|
|
829
|
+
comparisonValue: result.data,
|
|
830
|
+
messageCount: result.data.messages.length,
|
|
831
|
+
toolCount: result.data.tools !== void 0 && result.data.tools.length > 0 ? result.data.tools.length : null
|
|
832
|
+
};
|
|
833
|
+
} catch {
|
|
834
|
+
return emptyRequestAnalysis(rawBody);
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
analyzeResponse(responseText) {
|
|
838
|
+
if (responseText === null) return EMPTY_RESPONSE_ANALYSIS;
|
|
839
|
+
try {
|
|
840
|
+
let json = JSON.parse(responseText);
|
|
841
|
+
if (typeof json === "string") json = JSON.parse(json);
|
|
842
|
+
const result = AnthropicResponseSchema$1.safeParse(json);
|
|
843
|
+
if (!result.success) return EMPTY_RESPONSE_ANALYSIS;
|
|
844
|
+
const toolNames = result.data.content.filter((block) => block.type === "tool_use").map((block) => block.name);
|
|
845
|
+
return {
|
|
846
|
+
parsed: result.data,
|
|
847
|
+
toolNames: toolNames.length > 0 ? toolNames : null
|
|
848
|
+
};
|
|
849
|
+
} catch {
|
|
850
|
+
return EMPTY_RESPONSE_ANALYSIS;
|
|
851
|
+
}
|
|
852
|
+
},
|
|
853
|
+
anatomySegments(parsed) {
|
|
854
|
+
if (parsed === null || typeof parsed !== "object") return null;
|
|
855
|
+
const body = parsed;
|
|
856
|
+
const segments = [];
|
|
857
|
+
if (body.system !== void 0) {
|
|
858
|
+
const text = systemToText(body.system);
|
|
859
|
+
if (text.length > 0) {
|
|
860
|
+
segments.push(segment$1("system", "system", text, "/system"));
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
if (Array.isArray(body.messages)) {
|
|
864
|
+
body.messages.forEach((message, index) => {
|
|
865
|
+
if (message === null || typeof message !== "object") return;
|
|
866
|
+
const m = message;
|
|
867
|
+
const role = m.role === "user" || m.role === "assistant" ? m.role : "user";
|
|
868
|
+
const text = contentToText$1(m.content);
|
|
869
|
+
segments.push(segment$1(role, `[${index}] ${role}`, text, `/messages/${index}`));
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
if (Array.isArray(body.tools) && body.tools.length > 0) {
|
|
873
|
+
const text = toolsToText$1(body.tools);
|
|
874
|
+
segments.push(segment$1("tools", "tools", text, "/tools"));
|
|
875
|
+
}
|
|
876
|
+
return segments.length > 0 ? segments : null;
|
|
880
877
|
}
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
if (
|
|
884
|
-
|
|
885
|
-
const
|
|
886
|
-
|
|
878
|
+
};
|
|
879
|
+
function contentToText(content) {
|
|
880
|
+
if (typeof content === "string") return content;
|
|
881
|
+
if (!Array.isArray(content)) return "";
|
|
882
|
+
const parts = [];
|
|
883
|
+
for (const block of content) {
|
|
884
|
+
if (block === null || typeof block !== "object") continue;
|
|
885
|
+
const b = block;
|
|
886
|
+
const type = b.type;
|
|
887
|
+
if (type === "text" && typeof b.text === "string") {
|
|
888
|
+
parts.push(b.text);
|
|
889
|
+
} else if (type === "image_url") {
|
|
890
|
+
parts.push("[image]");
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
return parts.join("\n");
|
|
887
894
|
}
|
|
888
|
-
function
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
895
|
+
function messageToText(message) {
|
|
896
|
+
const parts = [];
|
|
897
|
+
const text = contentToText(message.content);
|
|
898
|
+
if (text.length > 0) parts.push(text);
|
|
899
|
+
const reasoning = typeof message.reasoning_content === "string" ? message.reasoning_content : typeof message.thinking === "string" ? message.thinking : typeof message.think === "string" ? message.think : "";
|
|
900
|
+
if (reasoning.length > 0) parts.push(reasoning);
|
|
901
|
+
const toolCalls = message.tool_calls;
|
|
902
|
+
if (Array.isArray(toolCalls)) {
|
|
903
|
+
for (const call of toolCalls) {
|
|
904
|
+
if (call === null || typeof call !== "object") continue;
|
|
905
|
+
const fn = call.function;
|
|
906
|
+
if (fn === void 0) continue;
|
|
907
|
+
const name = typeof fn.name === "string" ? fn.name : "";
|
|
908
|
+
const args = typeof fn.arguments === "string" ? fn.arguments : "";
|
|
909
|
+
parts.push(`${name} ${args}`.trim());
|
|
897
910
|
}
|
|
898
911
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
912
|
+
return parts.join("\n");
|
|
913
|
+
}
|
|
914
|
+
function toolsToText(tools) {
|
|
915
|
+
if (!Array.isArray(tools)) return "";
|
|
916
|
+
const parts = [];
|
|
917
|
+
for (const tool of tools) {
|
|
918
|
+
if (tool === null || typeof tool !== "object") continue;
|
|
919
|
+
const t = tool;
|
|
920
|
+
const fn = t.function;
|
|
921
|
+
if (fn === void 0) continue;
|
|
922
|
+
if (typeof fn.name === "string") parts.push(fn.name);
|
|
923
|
+
if (typeof fn.description === "string") parts.push(fn.description);
|
|
924
|
+
if (fn.parameters !== void 0) parts.push(JSON.stringify(fn.parameters));
|
|
907
925
|
}
|
|
908
|
-
|
|
909
|
-
return result;
|
|
926
|
+
return parts.join("\n");
|
|
910
927
|
}
|
|
911
|
-
function
|
|
912
|
-
return
|
|
928
|
+
function segment(role, label, text, path) {
|
|
929
|
+
return {
|
|
930
|
+
role,
|
|
931
|
+
label,
|
|
932
|
+
text,
|
|
933
|
+
size: estimateTokens(text),
|
|
934
|
+
characters: countCharacters(text),
|
|
935
|
+
path
|
|
936
|
+
};
|
|
913
937
|
}
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
938
|
+
const openAILogFormatAdapter = {
|
|
939
|
+
format: "openai",
|
|
940
|
+
analyzeRequest(rawBody) {
|
|
941
|
+
if (rawBody === null) return emptyRequestAnalysis(rawBody);
|
|
942
|
+
try {
|
|
943
|
+
const result = OpenAIRequestSchema.safeParse(JSON.parse(rawBody));
|
|
944
|
+
if (!result.success) return emptyRequestAnalysis(rawBody);
|
|
945
|
+
return {
|
|
946
|
+
parsed: result.data,
|
|
947
|
+
comparisonValue: result.data,
|
|
948
|
+
messageCount: result.data.messages.length,
|
|
949
|
+
toolCount: result.data.tools !== void 0 && result.data.tools.length > 0 ? result.data.tools.length : null
|
|
950
|
+
};
|
|
951
|
+
} catch {
|
|
952
|
+
return emptyRequestAnalysis(rawBody);
|
|
920
953
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
954
|
+
},
|
|
955
|
+
analyzeResponse(responseText) {
|
|
956
|
+
if (responseText === null) return EMPTY_RESPONSE_ANALYSIS;
|
|
957
|
+
const parsed = parseOpenAIResponse(responseText);
|
|
958
|
+
if (parsed === null) return EMPTY_RESPONSE_ANALYSIS;
|
|
959
|
+
const toolNames = parsed.choices[0]?.message?.tool_calls?.map((toolCall) => toolCall.function?.name ?? "").filter((name) => name !== "") ?? [];
|
|
960
|
+
return {
|
|
961
|
+
parsed,
|
|
962
|
+
toolNames: toolNames.length > 0 ? toolNames : null
|
|
963
|
+
};
|
|
964
|
+
},
|
|
965
|
+
anatomySegments(parsed) {
|
|
966
|
+
if (parsed === null || typeof parsed !== "object") return null;
|
|
967
|
+
const body = parsed;
|
|
968
|
+
const segments = [];
|
|
969
|
+
if (Array.isArray(body.messages)) {
|
|
970
|
+
body.messages.forEach((message, index) => {
|
|
971
|
+
if (message === null || typeof message !== "object") return;
|
|
972
|
+
const m = message;
|
|
973
|
+
const role = m.role === "user" || m.role === "assistant" || m.role === "system" || m.role === "tool" ? m.role : "user";
|
|
974
|
+
const text = messageToText(m);
|
|
975
|
+
segments.push(segment(role, `[${index}] ${role}`, text, `/messages/${index}`));
|
|
976
|
+
});
|
|
927
977
|
}
|
|
928
|
-
if (Array.isArray(
|
|
929
|
-
|
|
978
|
+
if (Array.isArray(body.tools) && body.tools.length > 0) {
|
|
979
|
+
const text = toolsToText(body.tools);
|
|
980
|
+
segments.push(segment("tools", "tools", text, "/tools"));
|
|
930
981
|
}
|
|
931
|
-
return null;
|
|
932
|
-
}
|
|
982
|
+
return segments.length > 0 ? segments : null;
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
const unknownLogFormatAdapter = {
|
|
986
|
+
format: "unknown",
|
|
987
|
+
analyzeRequest(rawBody) {
|
|
988
|
+
return emptyRequestAnalysis(rawBody);
|
|
989
|
+
},
|
|
990
|
+
analyzeResponse() {
|
|
991
|
+
return EMPTY_RESPONSE_ANALYSIS;
|
|
992
|
+
},
|
|
993
|
+
anatomySegments() {
|
|
933
994
|
return null;
|
|
934
995
|
}
|
|
996
|
+
};
|
|
997
|
+
const ADAPTERS = {
|
|
998
|
+
anthropic: anthropicLogFormatAdapter,
|
|
999
|
+
openai: openAILogFormatAdapter,
|
|
1000
|
+
unknown: unknownLogFormatAdapter
|
|
1001
|
+
};
|
|
1002
|
+
function getLogFormatAdapter(format) {
|
|
1003
|
+
return ADAPTERS[format];
|
|
935
1004
|
}
|
|
936
|
-
function
|
|
937
|
-
|
|
1005
|
+
function resolveLogFormat(log) {
|
|
1006
|
+
const pathFormat = requestFormatForPath(log.path);
|
|
1007
|
+
return pathFormat === "unknown" ? log.apiFormat : pathFormat;
|
|
938
1008
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1009
|
+
const API_FORMAT_LABELS = {
|
|
1010
|
+
anthropic: "Anthropic",
|
|
1011
|
+
openai: "OpenAI",
|
|
1012
|
+
unknown: "Unknown"
|
|
1013
|
+
};
|
|
1014
|
+
function ConversationHeader({
|
|
1015
|
+
conversationId,
|
|
1016
|
+
startTime,
|
|
1017
|
+
endTime,
|
|
1018
|
+
totalCalls,
|
|
1019
|
+
totalInputTokens,
|
|
1020
|
+
totalOutputTokens,
|
|
1021
|
+
apiFormat,
|
|
1022
|
+
expanded,
|
|
1023
|
+
onToggle,
|
|
1024
|
+
hideApiFormat = false,
|
|
1025
|
+
isLoading = false,
|
|
1026
|
+
userAgent,
|
|
1027
|
+
timeDisplayFormat,
|
|
1028
|
+
onClear
|
|
1029
|
+
}) {
|
|
1030
|
+
const [confirmOpen, setConfirmOpen] = reactExports.useState(false);
|
|
1031
|
+
const handleClearClick = (e) => {
|
|
1032
|
+
e.stopPropagation();
|
|
1033
|
+
if (onClear === void 0) return;
|
|
1034
|
+
setConfirmOpen(true);
|
|
1035
|
+
};
|
|
1036
|
+
const handleOpenInNewTab = reactExports.useCallback(
|
|
1037
|
+
(e) => {
|
|
1038
|
+
e.stopPropagation();
|
|
1039
|
+
window.open(getSessionPath(conversationId), "_blank", "noopener,noreferrer");
|
|
1040
|
+
},
|
|
1041
|
+
[conversationId]
|
|
1042
|
+
);
|
|
1043
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1044
|
+
"div",
|
|
1045
|
+
{
|
|
1046
|
+
role: "button",
|
|
1047
|
+
tabIndex: 0,
|
|
1048
|
+
"data-nav-id": `conv-${conversationId}`,
|
|
1049
|
+
"data-nav-action": expanded ? "collapse" : "expand",
|
|
1050
|
+
className: cn(
|
|
1051
|
+
"flex items-center gap-3 px-3 py-2 cursor-pointer transition-colors",
|
|
1052
|
+
"hover:bg-muted/50",
|
|
1053
|
+
"select-none",
|
|
1054
|
+
"border border-border rounded-lg mb-2 bg-background sticky top-0 z-10",
|
|
1055
|
+
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none"
|
|
1056
|
+
),
|
|
1057
|
+
onClick: onToggle,
|
|
1058
|
+
onKeyDown: (e) => {
|
|
1059
|
+
if (e.target !== e.currentTarget) return;
|
|
1060
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1061
|
+
e.preventDefault();
|
|
1062
|
+
onToggle();
|
|
1063
|
+
}
|
|
1064
|
+
},
|
|
1065
|
+
children: [
|
|
1066
|
+
expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 text-muted-foreground shrink-0" }) : isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin text-muted-foreground shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 text-muted-foreground shrink-0" }),
|
|
1067
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1068
|
+
"span",
|
|
1069
|
+
{
|
|
1070
|
+
className: "text-purple-400/90 font-mono text-xs font-semibold shrink-0",
|
|
1071
|
+
title: conversationId,
|
|
1072
|
+
children: conversationId.startsWith("PID:") || conversationId.includes("|") ? conversationId : conversationId.length > 24 ? conversationId.slice(0, 12) + "..." + conversationId.slice(-12) : conversationId
|
|
1073
|
+
}
|
|
1074
|
+
),
|
|
1075
|
+
userAgent !== null && userAgent !== void 0 && userAgent !== "" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1076
|
+
"span",
|
|
1077
|
+
{
|
|
1078
|
+
className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0",
|
|
1079
|
+
title: userAgent,
|
|
1080
|
+
children: [
|
|
1081
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(User, { className: "size-3" }),
|
|
1082
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[120px]", children: userAgent })
|
|
1083
|
+
]
|
|
1084
|
+
}
|
|
1085
|
+
),
|
|
1086
|
+
!hideApiFormat && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1087
|
+
Badge,
|
|
1088
|
+
{
|
|
1089
|
+
variant: "outline",
|
|
1090
|
+
className: cn(
|
|
1091
|
+
"text-[10px] px-1.5 py-0 h-5 font-mono shrink-0",
|
|
1092
|
+
apiFormat === "openai" && "border-blue-500/40 text-blue-400",
|
|
1093
|
+
apiFormat === "anthropic" && "border-orange-500/40 text-orange-400",
|
|
1094
|
+
apiFormat === "unknown" && "border-muted text-muted-foreground"
|
|
1095
|
+
),
|
|
1096
|
+
children: API_FORMAT_LABELS[apiFormat]
|
|
1097
|
+
}
|
|
1098
|
+
),
|
|
1099
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
1100
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
|
|
1101
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatTimestampRange(startTime, endTime, timeDisplayFormat) })
|
|
1102
|
+
] }),
|
|
1103
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
1104
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3" }),
|
|
1105
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
1106
|
+
totalCalls,
|
|
1107
|
+
" call",
|
|
1108
|
+
totalCalls !== 1 ? "s" : ""
|
|
1109
|
+
] })
|
|
1110
|
+
] }),
|
|
1111
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
|
|
1112
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
|
|
1113
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
1114
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-400", children: formatTokens(totalInputTokens) }),
|
|
1115
|
+
" / ",
|
|
1116
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-amber-400", children: formatTokens(totalOutputTokens) })
|
|
1117
|
+
] })
|
|
1118
|
+
] }),
|
|
1119
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
|
|
1120
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1121
|
+
"button",
|
|
1122
|
+
{
|
|
1123
|
+
type: "button",
|
|
1124
|
+
onClick: handleOpenInNewTab,
|
|
1125
|
+
onKeyDown: (e) => {
|
|
1126
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1127
|
+
handleOpenInNewTab(e);
|
|
1128
|
+
}
|
|
1129
|
+
},
|
|
1130
|
+
"aria-label": `Open session ${conversationId} in a new tab`,
|
|
1131
|
+
title: "Open this session in a new tab",
|
|
1132
|
+
className: "text-muted-foreground hover:text-foreground transition-colors shrink-0 inline-flex items-center justify-center size-8 rounded hover:bg-muted cursor-pointer",
|
|
1133
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-3.5" })
|
|
1134
|
+
}
|
|
1135
|
+
),
|
|
1136
|
+
onClear !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1137
|
+
"button",
|
|
1138
|
+
{
|
|
1139
|
+
type: "button",
|
|
1140
|
+
onClick: handleClearClick,
|
|
1141
|
+
"aria-label": `Clear group (${totalCalls} request${totalCalls !== 1 ? "s" : ""})`,
|
|
1142
|
+
title: "Clear this group",
|
|
1143
|
+
className: "text-muted-foreground hover:text-foreground transition-colors shrink-0 inline-flex items-center justify-center size-8 rounded hover:bg-muted cursor-pointer",
|
|
1144
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" })
|
|
1145
|
+
}
|
|
1146
|
+
),
|
|
1147
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1148
|
+
ConfirmDialog,
|
|
1149
|
+
{
|
|
1150
|
+
open: confirmOpen,
|
|
1151
|
+
onOpenChange: setConfirmOpen,
|
|
1152
|
+
title: "Clear this group?",
|
|
1153
|
+
description: `This will remove ${totalCalls} request${totalCalls !== 1 ? "s" : ""} from this conversation. This action cannot be undone.`,
|
|
1154
|
+
confirmLabel: "Clear",
|
|
1155
|
+
variant: "destructive",
|
|
1156
|
+
onConfirm: () => {
|
|
1157
|
+
onClear?.();
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
)
|
|
1161
|
+
]
|
|
1162
|
+
}
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
function getGroupApiFormat(logs) {
|
|
1166
|
+
for (const log of logs) {
|
|
1167
|
+
const apiFormat = resolveLogFormat(log);
|
|
1168
|
+
if (apiFormat !== "unknown") {
|
|
1169
|
+
return apiFormat;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
return "unknown";
|
|
1173
|
+
}
|
|
1174
|
+
function hasMixedApiFormat(logs) {
|
|
1175
|
+
let hasAnthropic = false;
|
|
1176
|
+
let hasOpenai = false;
|
|
1177
|
+
for (const log of logs) {
|
|
1178
|
+
const apiFormat = resolveLogFormat(log);
|
|
1179
|
+
if (apiFormat === "anthropic") hasAnthropic = true;
|
|
1180
|
+
else if (apiFormat === "openai") hasOpenai = true;
|
|
1181
|
+
if (hasAnthropic && hasOpenai) return true;
|
|
1182
|
+
}
|
|
1183
|
+
return false;
|
|
1184
|
+
}
|
|
1185
|
+
function getConversationId(log) {
|
|
1186
|
+
if (log.isTest === true) return "provider-test";
|
|
1187
|
+
if (log.sessionId !== null && log.sessionId !== "" && log.sessionId !== void 0) {
|
|
1188
|
+
return log.sessionId;
|
|
1189
|
+
}
|
|
1190
|
+
const hasPid = log.clientPid !== null && log.clientPid !== void 0;
|
|
1191
|
+
const hasFolder = log.clientProjectFolder !== null && log.clientProjectFolder !== void 0;
|
|
1192
|
+
if (!hasPid && !hasFolder) return "default";
|
|
1193
|
+
const pid = hasPid ? `PID:${log.clientPid}` : "unknown";
|
|
1194
|
+
const folder = hasFolder ? log.clientProjectFolder : "no-folder";
|
|
1195
|
+
return `${pid}|${folder}`;
|
|
1196
|
+
}
|
|
1197
|
+
function groupLogsByConversation(logs) {
|
|
1198
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1199
|
+
for (const log of logs) {
|
|
1200
|
+
const convId = getConversationId(log);
|
|
1201
|
+
const existing = groups.get(convId);
|
|
1202
|
+
if (existing !== void 0) {
|
|
1203
|
+
existing.push(log);
|
|
1204
|
+
} else {
|
|
1205
|
+
groups.set(convId, [log]);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
const result = [];
|
|
1209
|
+
for (const [conversationId, groupLogs] of groups) {
|
|
1210
|
+
const sorted = [...groupLogs].sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
1211
|
+
result.push({
|
|
1212
|
+
id: conversationId,
|
|
1213
|
+
conversationId,
|
|
1214
|
+
logs: sorted
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
result.sort((a, b) => (a.logs[0]?.timestamp ?? "").localeCompare(b.logs[0]?.timestamp ?? ""));
|
|
1218
|
+
return result;
|
|
1219
|
+
}
|
|
1220
|
+
function isRecord(value) {
|
|
1221
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1222
|
+
}
|
|
1223
|
+
function extractStopReason(log) {
|
|
1224
|
+
if (log.responseText === null) return null;
|
|
1225
|
+
try {
|
|
1226
|
+
let json = JSON.parse(log.responseText);
|
|
1227
|
+
if (typeof json === "string") {
|
|
1228
|
+
json = JSON.parse(json);
|
|
1229
|
+
}
|
|
1230
|
+
if (!isRecord(json)) return null;
|
|
1231
|
+
if (typeof json.stop_reason === "string") {
|
|
1232
|
+
if (json.stop_reason === "end_turn" || json.stop_reason === "tool_use") {
|
|
1233
|
+
return json.stop_reason;
|
|
1234
|
+
}
|
|
1235
|
+
return null;
|
|
1236
|
+
}
|
|
1237
|
+
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") {
|
|
1238
|
+
return "stop";
|
|
1239
|
+
}
|
|
1240
|
+
return null;
|
|
1241
|
+
} catch {
|
|
1242
|
+
return null;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
function isTurnBoundary(stopReason) {
|
|
1246
|
+
return stopReason === "end_turn" || stopReason === "stop";
|
|
1247
|
+
}
|
|
1248
|
+
function SvgShell({
|
|
1249
|
+
className,
|
|
1250
|
+
style,
|
|
1251
|
+
d,
|
|
1252
|
+
eyeStalks,
|
|
1253
|
+
eyes,
|
|
1254
|
+
legs,
|
|
1255
|
+
extras
|
|
1256
|
+
}) {
|
|
1257
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1258
|
+
"svg",
|
|
1259
|
+
{
|
|
1260
|
+
viewBox: "0 0 24 24",
|
|
1261
|
+
fill: "none",
|
|
1262
|
+
stroke: "currentColor",
|
|
1263
|
+
strokeWidth: "1.5",
|
|
1264
|
+
strokeLinecap: "round",
|
|
1265
|
+
strokeLinejoin: "round",
|
|
1266
|
+
"aria-hidden": "true",
|
|
1267
|
+
style,
|
|
1268
|
+
className: cn("inline-block size-5", className),
|
|
1269
|
+
children: [
|
|
961
1270
|
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d }),
|
|
962
1271
|
eyeStalks,
|
|
963
1272
|
eyes,
|
|
@@ -1572,19 +1881,19 @@ function useCopyFeedback(text) {
|
|
|
1572
1881
|
return { copied, copy };
|
|
1573
1882
|
}
|
|
1574
1883
|
const LazyCompareDrawer = reactExports.lazy(
|
|
1575
|
-
() => import("./CompareDrawer-
|
|
1884
|
+
() => import("./CompareDrawer-Ce2590rK.mjs").then((m) => ({ default: m.CompareDrawer }))
|
|
1576
1885
|
);
|
|
1577
1886
|
const LazyReplayDialog = reactExports.lazy(
|
|
1578
|
-
() => import("./ReplayDialog-
|
|
1887
|
+
() => import("./ReplayDialog-CB4KOlLe.mjs").then((m) => ({ default: m.ReplayDialog }))
|
|
1579
1888
|
);
|
|
1580
1889
|
const LazyRequestAnatomy = reactExports.lazy(
|
|
1581
|
-
() => import("./RequestAnatomy-
|
|
1890
|
+
() => import("./RequestAnatomy-CsWV3W03.mjs").then((m) => ({ default: m.RequestAnatomy }))
|
|
1582
1891
|
);
|
|
1583
1892
|
const LazyResponseView = reactExports.lazy(
|
|
1584
|
-
() => import("./ResponseView-
|
|
1893
|
+
() => import("./ResponseView-BuCCV3LU.mjs").then((m) => ({ default: m.ResponseView }))
|
|
1585
1894
|
);
|
|
1586
1895
|
const LazyStreamingChunkSequence = reactExports.lazy(
|
|
1587
|
-
() => import("./StreamingChunkSequence-
|
|
1896
|
+
() => import("./StreamingChunkSequence-C5dE7V1d.mjs").then((m) => ({
|
|
1588
1897
|
default: m.StreamingChunkSequence
|
|
1589
1898
|
}))
|
|
1590
1899
|
);
|
|
@@ -2688,542 +2997,236 @@ function ScrollBar({
|
|
|
2688
2997
|
"flex touch-none p-px transition-colors select-none",
|
|
2689
2998
|
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
|
|
2690
2999
|
orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
|
|
2691
|
-
className
|
|
2692
|
-
),
|
|
2693
|
-
...props,
|
|
2694
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2695
|
-
ScrollAreaThumb,
|
|
2696
|
-
{
|
|
2697
|
-
"data-slot": "scroll-area-thumb",
|
|
2698
|
-
className: "bg-border relative flex-1 rounded-full"
|
|
2699
|
-
}
|
|
2700
|
-
)
|
|
2701
|
-
}
|
|
2702
|
-
);
|
|
2703
|
-
}
|
|
2704
|
-
const CATEGORY_LABELS = {
|
|
2705
|
-
file: "file",
|
|
2706
|
-
shell: "shell",
|
|
2707
|
-
browser: "browser",
|
|
2708
|
-
web: "web",
|
|
2709
|
-
mcp: "MCP",
|
|
2710
|
-
code: "code",
|
|
2711
|
-
other: "other"
|
|
2712
|
-
};
|
|
2713
|
-
const CATEGORY_CLASSES = {
|
|
2714
|
-
file: "border-blue-400/20 bg-blue-400/5 text-blue-300",
|
|
2715
|
-
shell: "border-teal-400/20 bg-teal-400/5 text-teal-300",
|
|
2716
|
-
browser: "border-cyan-400/20 bg-cyan-400/5 text-cyan-300",
|
|
2717
|
-
web: "border-sky-400/20 bg-sky-400/5 text-sky-300",
|
|
2718
|
-
mcp: "border-violet-400/20 bg-violet-400/5 text-violet-300",
|
|
2719
|
-
code: "border-emerald-400/20 bg-emerald-400/5 text-emerald-300",
|
|
2720
|
-
other: "border-muted-foreground/20 bg-muted/30 text-muted-foreground"
|
|
2721
|
-
};
|
|
2722
|
-
function CategoryIcon({ category }) {
|
|
2723
|
-
switch (category) {
|
|
2724
|
-
case "file":
|
|
2725
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { className: "size-3.5" });
|
|
2726
|
-
case "shell":
|
|
2727
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { className: "size-3.5" });
|
|
2728
|
-
case "browser":
|
|
2729
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(MousePointerClick, { className: "size-3.5" });
|
|
2730
|
-
case "web":
|
|
2731
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Globe, { className: "size-3.5" });
|
|
2732
|
-
case "mcp":
|
|
2733
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Blocks, { className: "size-3.5" });
|
|
2734
|
-
case "code":
|
|
2735
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(CodeXml, { className: "size-3.5" });
|
|
2736
|
-
case "other":
|
|
2737
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Ellipsis, { className: "size-3.5" });
|
|
2738
|
-
}
|
|
2739
|
-
}
|
|
2740
|
-
function RequiredParameters({ names }) {
|
|
2741
|
-
if (names.length === 0) return null;
|
|
2742
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-1", children: [
|
|
2743
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: "required" }),
|
|
2744
|
-
names.slice(0, 4).map((name) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2745
|
-
Badge,
|
|
2746
|
-
{
|
|
2747
|
-
variant: "outline",
|
|
2748
|
-
className: "h-5 max-w-36 truncate rounded-md px-1.5 py-0 font-mono text-[10px]",
|
|
2749
|
-
children: name
|
|
2750
|
-
},
|
|
2751
|
-
name
|
|
2752
|
-
)),
|
|
2753
|
-
names.length > 4 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[10px] text-muted-foreground", children: [
|
|
2754
|
-
"+",
|
|
2755
|
-
names.length - 4
|
|
2756
|
-
] })
|
|
2757
|
-
] });
|
|
2758
|
-
}
|
|
2759
|
-
function ToolRow({ tool, called }) {
|
|
2760
|
-
const [open, setOpen] = reactExports.useState(false);
|
|
2761
|
-
const nameCopy = useCopyFeedback(tool.name);
|
|
2762
|
-
const hasDetails = tool.description !== null || tool.requiredParameters.length > 0 || tool.schema !== null;
|
|
2763
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Collapsible, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-md border border-border/60 bg-background/40", children: [
|
|
2764
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2 px-2.5 py-2", children: [
|
|
2765
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2766
|
-
"button",
|
|
2767
|
-
{
|
|
2768
|
-
type: "button",
|
|
2769
|
-
className: "flex min-w-0 flex-1 items-center gap-2 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2770
|
-
onClick: () => setOpen((value) => !value),
|
|
2771
|
-
"aria-expanded": open,
|
|
2772
|
-
disabled: !hasDetails,
|
|
2773
|
-
children: [
|
|
2774
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(CategoryIcon, { category: tool.category }),
|
|
2775
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 truncate font-mono text-xs font-semibold text-foreground/90", children: tool.name }),
|
|
2776
|
-
called && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2777
|
-
Badge,
|
|
2778
|
-
{
|
|
2779
|
-
variant: "outline",
|
|
2780
|
-
className: "h-5 rounded-md border-emerald-400/20 bg-emerald-400/5 px-1.5 py-0 text-[10px] text-emerald-300",
|
|
2781
|
-
children: "called"
|
|
2782
|
-
}
|
|
2783
|
-
),
|
|
2784
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[10px] text-muted-foreground", children: [
|
|
2785
|
-
tool.parameterCount,
|
|
2786
|
-
" params"
|
|
2787
|
-
] }),
|
|
2788
|
-
tool.descriptionPreview !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "hidden min-w-0 truncate text-xs text-muted-foreground md:inline", children: tool.descriptionPreview }),
|
|
2789
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1" }),
|
|
2790
|
-
hasDetails && (open ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3.5 shrink-0 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3.5 shrink-0 text-muted-foreground" }))
|
|
2791
|
-
]
|
|
2792
|
-
}
|
|
2793
|
-
),
|
|
2794
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2795
|
-
"button",
|
|
2796
|
-
{
|
|
2797
|
-
type: "button",
|
|
2798
|
-
className: "inline-flex size-7 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2799
|
-
onClick: nameCopy.copy,
|
|
2800
|
-
"aria-label": nameCopy.copied ? "Copied tool name" : "Copy tool name",
|
|
2801
|
-
children: nameCopy.copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-emerald-400" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
|
|
2802
|
-
}
|
|
2803
|
-
)
|
|
2804
|
-
] }),
|
|
2805
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2 border-t border-border/60 px-2.5 py-2", children: [
|
|
2806
|
-
tool.description !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: tool.description }),
|
|
2807
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(RequiredParameters, { names: tool.requiredParameters }),
|
|
2808
|
-
tool.schema !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "max-h-64 rounded-md border border-border/60 bg-muted/20 p-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewer, { data: safeJsonValue(tool.schema), defaultExpandDepth: 0 }) })
|
|
2809
|
-
] }) })
|
|
2810
|
-
] }) });
|
|
2811
|
-
}
|
|
2812
|
-
function matchesQuery(tool, query) {
|
|
2813
|
-
if (query.length === 0) return true;
|
|
2814
|
-
const haystack = `${tool.name} ${tool.description ?? ""} ${CATEGORY_LABELS[tool.category]}`.toLowerCase().trim();
|
|
2815
|
-
return haystack.includes(query);
|
|
2816
|
-
}
|
|
2817
|
-
const RequestTools = reactExports.memo(function RequestTools2({
|
|
2818
|
-
summary,
|
|
2819
|
-
calledToolNames
|
|
2820
|
-
}) {
|
|
2821
|
-
const [expanded, setExpanded] = reactExports.useState(false);
|
|
2822
|
-
const [query, setQuery] = reactExports.useState("");
|
|
2823
|
-
const calledNames = reactExports.useMemo(() => new Set(calledToolNames), [calledToolNames]);
|
|
2824
|
-
const normalizedQuery = query.trim().toLowerCase();
|
|
2825
|
-
const visibleTools = reactExports.useMemo(
|
|
2826
|
-
() => summary === null ? [] : summary.tools.filter((tool) => matchesQuery(tool, normalizedQuery)),
|
|
2827
|
-
[normalizedQuery, summary]
|
|
2828
|
-
);
|
|
2829
|
-
if (summary === null) return null;
|
|
2830
|
-
const previewTools = summary.tools.slice(0, 6);
|
|
2831
|
-
const hiddenPreviewCount = summary.tools.length - previewTools.length;
|
|
2832
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "mb-3 rounded-lg border border-border/70 bg-muted/20", children: [
|
|
2833
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2 px-3 py-2", children: [
|
|
2834
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
2835
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-4 shrink-0 text-sky-300/80" }),
|
|
2836
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
|
|
2837
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-1.5", children: [
|
|
2838
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-semibold text-foreground", children: "Request Tools" }),
|
|
2839
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "h-5 rounded-md px-1.5 py-0 font-mono text-[10px]", children: summary.tools.length }),
|
|
2840
|
-
summary.toolChoiceLabel !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2841
|
-
Badge,
|
|
2842
|
-
{
|
|
2843
|
-
variant: "outline",
|
|
2844
|
-
className: "h-5 rounded-md px-1.5 py-0 font-mono text-[10px] text-muted-foreground",
|
|
2845
|
-
children: [
|
|
2846
|
-
"tool_choice: ",
|
|
2847
|
-
summary.toolChoiceLabel
|
|
2848
|
-
]
|
|
2849
|
-
}
|
|
2850
|
-
)
|
|
2851
|
-
] }),
|
|
2852
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 flex min-w-0 flex-wrap gap-1", children: summary.categories.map((category) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2853
|
-
Badge,
|
|
2854
|
-
{
|
|
2855
|
-
variant: "outline",
|
|
2856
|
-
className: cn(
|
|
2857
|
-
"h-5 rounded-md px-1.5 py-0 font-mono text-[10px]",
|
|
2858
|
-
CATEGORY_CLASSES[category.category]
|
|
2859
|
-
),
|
|
2860
|
-
children: [
|
|
2861
|
-
category.count,
|
|
2862
|
-
" ",
|
|
2863
|
-
CATEGORY_LABELS[category.category]
|
|
2864
|
-
]
|
|
2865
|
-
},
|
|
2866
|
-
category.category
|
|
2867
|
-
)) })
|
|
2868
|
-
] })
|
|
2869
|
-
] }),
|
|
2870
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2871
|
-
Button,
|
|
2872
|
-
{
|
|
2873
|
-
type: "button",
|
|
2874
|
-
variant: "ghost",
|
|
2875
|
-
size: "sm",
|
|
2876
|
-
className: "h-7 px-2",
|
|
2877
|
-
onClick: () => setExpanded((value) => !value),
|
|
2878
|
-
"aria-expanded": expanded,
|
|
2879
|
-
children: [
|
|
2880
|
-
expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3.5" }),
|
|
2881
|
-
expanded ? "Hide" : "Show"
|
|
2882
|
-
]
|
|
2883
|
-
}
|
|
2884
|
-
)
|
|
2885
|
-
] }),
|
|
2886
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap gap-1.5 border-t border-border/60 px-3 py-2", children: [
|
|
2887
|
-
previewTools.map((tool) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2888
|
-
Badge,
|
|
2889
|
-
{
|
|
2890
|
-
variant: "outline",
|
|
2891
|
-
className: cn(
|
|
2892
|
-
"h-5 max-w-44 truncate rounded-md px-1.5 py-0 font-mono text-[10px]",
|
|
2893
|
-
calledNames.has(tool.name) && "border-emerald-400/20 text-emerald-300"
|
|
2894
|
-
),
|
|
2895
|
-
children: tool.name
|
|
2896
|
-
},
|
|
2897
|
-
tool.name
|
|
2898
|
-
)),
|
|
2899
|
-
hiddenPreviewCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[10px] leading-5 text-muted-foreground", children: [
|
|
2900
|
-
"+",
|
|
2901
|
-
hiddenPreviewCount
|
|
2902
|
-
] })
|
|
2903
|
-
] }),
|
|
2904
|
-
expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2 border-t border-border/60 px-3 py-3", children: [
|
|
2905
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex h-8 items-center gap-2 rounded-md border border-border/70 bg-background/50 px-2 text-xs", children: [
|
|
2906
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Search, { className: "size-3.5 shrink-0 text-muted-foreground" }),
|
|
2907
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2908
|
-
"input",
|
|
2909
|
-
{
|
|
2910
|
-
value: query,
|
|
2911
|
-
onChange: (event) => setQuery(event.target.value),
|
|
2912
|
-
placeholder: "Filter tools",
|
|
2913
|
-
className: "min-w-0 flex-1 bg-transparent font-mono text-xs outline-none placeholder:text-muted-foreground/70"
|
|
2914
|
-
}
|
|
2915
|
-
)
|
|
2916
|
-
] }),
|
|
2917
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-1.5", children: visibleTools.length > 0 ? visibleTools.map((tool) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToolRow, { tool, called: calledNames.has(tool.name) }, tool.name)) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "py-2 text-xs text-muted-foreground", children: "No matching tools" }) })
|
|
2918
|
-
] })
|
|
2919
|
-
] });
|
|
2920
|
-
});
|
|
2921
|
-
function forEachCodePoint(text, visit) {
|
|
2922
|
-
for (const ch of Array.from(text)) {
|
|
2923
|
-
visit(ch);
|
|
2924
|
-
}
|
|
2925
|
-
}
|
|
2926
|
-
const CJK_REGEX = /[\u3000-\u9FFF\uAC00-\uD7FF\uF900-\uFAFF\uFF00-\uFFEF\u{1F300}-\u{1FAFF}]/u;
|
|
2927
|
-
function estimateTokens(text) {
|
|
2928
|
-
if (text.length === 0) return 0;
|
|
2929
|
-
let cjk = 0;
|
|
2930
|
-
let other = 0;
|
|
2931
|
-
forEachCodePoint(text, (ch) => {
|
|
2932
|
-
if (CJK_REGEX.test(ch)) {
|
|
2933
|
-
cjk += 1;
|
|
2934
|
-
} else {
|
|
2935
|
-
other += 1;
|
|
2936
|
-
}
|
|
2937
|
-
});
|
|
2938
|
-
return Math.ceil(cjk * 1) + Math.ceil(other / 4);
|
|
2939
|
-
}
|
|
2940
|
-
function countCharacters(text) {
|
|
2941
|
-
if (text.length === 0) return 0;
|
|
2942
|
-
let n = 0;
|
|
2943
|
-
forEachCodePoint(text, () => {
|
|
2944
|
-
n += 1;
|
|
2945
|
-
});
|
|
2946
|
-
return n;
|
|
2947
|
-
}
|
|
2948
|
-
function emptyRequestAnalysis(rawBody) {
|
|
2949
|
-
return {
|
|
2950
|
-
parsed: null,
|
|
2951
|
-
comparisonValue: rawBody,
|
|
2952
|
-
messageCount: null,
|
|
2953
|
-
toolCount: null
|
|
2954
|
-
};
|
|
2955
|
-
}
|
|
2956
|
-
const EMPTY_RESPONSE_ANALYSIS = {
|
|
2957
|
-
parsed: null,
|
|
2958
|
-
toolNames: null
|
|
2959
|
-
};
|
|
2960
|
-
function contentToText$1(content) {
|
|
2961
|
-
if (typeof content === "string") return content;
|
|
2962
|
-
if (!Array.isArray(content)) return "";
|
|
2963
|
-
const parts = [];
|
|
2964
|
-
for (const block of content) {
|
|
2965
|
-
if (block === null || typeof block !== "object") continue;
|
|
2966
|
-
const b = block;
|
|
2967
|
-
const type = b.type;
|
|
2968
|
-
switch (type) {
|
|
2969
|
-
case "text":
|
|
2970
|
-
if (typeof b.text === "string") parts.push(b.text);
|
|
2971
|
-
break;
|
|
2972
|
-
case "thinking":
|
|
2973
|
-
case "think":
|
|
2974
|
-
if (typeof b.thinking === "string") parts.push(b.thinking);
|
|
2975
|
-
break;
|
|
2976
|
-
case "tool_use": {
|
|
2977
|
-
const name = typeof b.name === "string" ? b.name : "";
|
|
2978
|
-
const input = b.input !== void 0 ? JSON.stringify(b.input) : "";
|
|
2979
|
-
parts.push(`${name} ${input}`.trim());
|
|
2980
|
-
break;
|
|
2981
|
-
}
|
|
2982
|
-
case "tool_result": {
|
|
2983
|
-
const inner = b.content;
|
|
2984
|
-
if (typeof inner === "string") {
|
|
2985
|
-
parts.push(inner);
|
|
2986
|
-
} else if (Array.isArray(inner)) {
|
|
2987
|
-
for (const item of inner) {
|
|
2988
|
-
if (item !== null && typeof item === "object") {
|
|
2989
|
-
const t = item.text;
|
|
2990
|
-
if (typeof t === "string") parts.push(t);
|
|
2991
|
-
}
|
|
2992
|
-
}
|
|
2993
|
-
}
|
|
2994
|
-
break;
|
|
2995
|
-
}
|
|
2996
|
-
case "image":
|
|
2997
|
-
parts.push("[image]");
|
|
2998
|
-
break;
|
|
2999
|
-
}
|
|
3000
|
-
}
|
|
3001
|
-
return parts.join("\n");
|
|
3002
|
-
}
|
|
3003
|
-
function systemToText(system) {
|
|
3004
|
-
if (typeof system === "string") return system;
|
|
3005
|
-
if (!Array.isArray(system)) return "";
|
|
3006
|
-
const parts = [];
|
|
3007
|
-
for (const block of system) {
|
|
3008
|
-
if (block !== null && typeof block === "object") {
|
|
3009
|
-
const t = block.text;
|
|
3010
|
-
const type = block.type;
|
|
3011
|
-
if (type === "text" && typeof t === "string") parts.push(t);
|
|
3012
|
-
}
|
|
3013
|
-
}
|
|
3014
|
-
return parts.join("\n");
|
|
3015
|
-
}
|
|
3016
|
-
function toolsToText$1(tools) {
|
|
3017
|
-
if (!Array.isArray(tools)) return "";
|
|
3018
|
-
const parts = [];
|
|
3019
|
-
for (const tool of tools) {
|
|
3020
|
-
if (tool === null || typeof tool !== "object") continue;
|
|
3021
|
-
const t = tool;
|
|
3022
|
-
if (typeof t.name === "string") parts.push(t.name);
|
|
3023
|
-
if (typeof t.description === "string") parts.push(t.description);
|
|
3024
|
-
if (t.input_schema !== void 0) parts.push(JSON.stringify(t.input_schema));
|
|
3025
|
-
}
|
|
3026
|
-
return parts.join("\n");
|
|
3027
|
-
}
|
|
3028
|
-
function segment$1(role, label, text, path) {
|
|
3029
|
-
return {
|
|
3030
|
-
role,
|
|
3031
|
-
label,
|
|
3032
|
-
text,
|
|
3033
|
-
size: estimateTokens(text),
|
|
3034
|
-
characters: countCharacters(text),
|
|
3035
|
-
path
|
|
3036
|
-
};
|
|
3037
|
-
}
|
|
3038
|
-
const anthropicLogFormatAdapter = {
|
|
3039
|
-
format: "anthropic",
|
|
3040
|
-
analyzeRequest(rawBody) {
|
|
3041
|
-
if (rawBody === null) return emptyRequestAnalysis(rawBody);
|
|
3042
|
-
try {
|
|
3043
|
-
const result = AnthropicRequestSchema.safeParse(JSON.parse(rawBody));
|
|
3044
|
-
if (!result.success) return emptyRequestAnalysis(rawBody);
|
|
3045
|
-
return {
|
|
3046
|
-
parsed: result.data,
|
|
3047
|
-
comparisonValue: result.data,
|
|
3048
|
-
messageCount: result.data.messages.length,
|
|
3049
|
-
toolCount: result.data.tools !== void 0 && result.data.tools.length > 0 ? result.data.tools.length : null
|
|
3050
|
-
};
|
|
3051
|
-
} catch {
|
|
3052
|
-
return emptyRequestAnalysis(rawBody);
|
|
3053
|
-
}
|
|
3054
|
-
},
|
|
3055
|
-
analyzeResponse(responseText) {
|
|
3056
|
-
if (responseText === null) return EMPTY_RESPONSE_ANALYSIS;
|
|
3057
|
-
try {
|
|
3058
|
-
let json = JSON.parse(responseText);
|
|
3059
|
-
if (typeof json === "string") json = JSON.parse(json);
|
|
3060
|
-
const result = AnthropicResponseSchema$1.safeParse(json);
|
|
3061
|
-
if (!result.success) return EMPTY_RESPONSE_ANALYSIS;
|
|
3062
|
-
const toolNames = result.data.content.filter((block) => block.type === "tool_use").map((block) => block.name);
|
|
3063
|
-
return {
|
|
3064
|
-
parsed: result.data,
|
|
3065
|
-
toolNames: toolNames.length > 0 ? toolNames : null
|
|
3066
|
-
};
|
|
3067
|
-
} catch {
|
|
3068
|
-
return EMPTY_RESPONSE_ANALYSIS;
|
|
3069
|
-
}
|
|
3070
|
-
},
|
|
3071
|
-
anatomySegments(parsed) {
|
|
3072
|
-
if (parsed === null || typeof parsed !== "object") return null;
|
|
3073
|
-
const body = parsed;
|
|
3074
|
-
const segments = [];
|
|
3075
|
-
if (body.system !== void 0) {
|
|
3076
|
-
const text = systemToText(body.system);
|
|
3077
|
-
if (text.length > 0) {
|
|
3078
|
-
segments.push(segment$1("system", "system", text, "/system"));
|
|
3079
|
-
}
|
|
3080
|
-
}
|
|
3081
|
-
if (Array.isArray(body.messages)) {
|
|
3082
|
-
body.messages.forEach((message, index) => {
|
|
3083
|
-
if (message === null || typeof message !== "object") return;
|
|
3084
|
-
const m = message;
|
|
3085
|
-
const role = m.role === "user" || m.role === "assistant" ? m.role : "user";
|
|
3086
|
-
const text = contentToText$1(m.content);
|
|
3087
|
-
segments.push(segment$1(role, `[${index}] ${role}`, text, `/messages/${index}`));
|
|
3088
|
-
});
|
|
3089
|
-
}
|
|
3090
|
-
if (Array.isArray(body.tools) && body.tools.length > 0) {
|
|
3091
|
-
const text = toolsToText$1(body.tools);
|
|
3092
|
-
segments.push(segment$1("tools", "tools", text, "/tools"));
|
|
3093
|
-
}
|
|
3094
|
-
return segments.length > 0 ? segments : null;
|
|
3095
|
-
}
|
|
3096
|
-
};
|
|
3097
|
-
function contentToText(content) {
|
|
3098
|
-
if (typeof content === "string") return content;
|
|
3099
|
-
if (!Array.isArray(content)) return "";
|
|
3100
|
-
const parts = [];
|
|
3101
|
-
for (const block of content) {
|
|
3102
|
-
if (block === null || typeof block !== "object") continue;
|
|
3103
|
-
const b = block;
|
|
3104
|
-
const type = b.type;
|
|
3105
|
-
if (type === "text" && typeof b.text === "string") {
|
|
3106
|
-
parts.push(b.text);
|
|
3107
|
-
} else if (type === "image_url") {
|
|
3108
|
-
parts.push("[image]");
|
|
3109
|
-
}
|
|
3110
|
-
}
|
|
3111
|
-
return parts.join("\n");
|
|
3112
|
-
}
|
|
3113
|
-
function messageToText(message) {
|
|
3114
|
-
const parts = [];
|
|
3115
|
-
const text = contentToText(message.content);
|
|
3116
|
-
if (text.length > 0) parts.push(text);
|
|
3117
|
-
const reasoning = typeof message.reasoning_content === "string" ? message.reasoning_content : typeof message.thinking === "string" ? message.thinking : typeof message.think === "string" ? message.think : "";
|
|
3118
|
-
if (reasoning.length > 0) parts.push(reasoning);
|
|
3119
|
-
const toolCalls = message.tool_calls;
|
|
3120
|
-
if (Array.isArray(toolCalls)) {
|
|
3121
|
-
for (const call of toolCalls) {
|
|
3122
|
-
if (call === null || typeof call !== "object") continue;
|
|
3123
|
-
const fn = call.function;
|
|
3124
|
-
if (fn === void 0) continue;
|
|
3125
|
-
const name = typeof fn.name === "string" ? fn.name : "";
|
|
3126
|
-
const args = typeof fn.arguments === "string" ? fn.arguments : "";
|
|
3127
|
-
parts.push(`${name} ${args}`.trim());
|
|
3128
|
-
}
|
|
3129
|
-
}
|
|
3130
|
-
return parts.join("\n");
|
|
3131
|
-
}
|
|
3132
|
-
function toolsToText(tools) {
|
|
3133
|
-
if (!Array.isArray(tools)) return "";
|
|
3134
|
-
const parts = [];
|
|
3135
|
-
for (const tool of tools) {
|
|
3136
|
-
if (tool === null || typeof tool !== "object") continue;
|
|
3137
|
-
const t = tool;
|
|
3138
|
-
const fn = t.function;
|
|
3139
|
-
if (fn === void 0) continue;
|
|
3140
|
-
if (typeof fn.name === "string") parts.push(fn.name);
|
|
3141
|
-
if (typeof fn.description === "string") parts.push(fn.description);
|
|
3142
|
-
if (fn.parameters !== void 0) parts.push(JSON.stringify(fn.parameters));
|
|
3143
|
-
}
|
|
3144
|
-
return parts.join("\n");
|
|
3145
|
-
}
|
|
3146
|
-
function segment(role, label, text, path) {
|
|
3147
|
-
return {
|
|
3148
|
-
role,
|
|
3149
|
-
label,
|
|
3150
|
-
text,
|
|
3151
|
-
size: estimateTokens(text),
|
|
3152
|
-
characters: countCharacters(text),
|
|
3153
|
-
path
|
|
3154
|
-
};
|
|
3155
|
-
}
|
|
3156
|
-
const openAILogFormatAdapter = {
|
|
3157
|
-
format: "openai",
|
|
3158
|
-
analyzeRequest(rawBody) {
|
|
3159
|
-
if (rawBody === null) return emptyRequestAnalysis(rawBody);
|
|
3160
|
-
try {
|
|
3161
|
-
const result = OpenAIRequestSchema.safeParse(JSON.parse(rawBody));
|
|
3162
|
-
if (!result.success) return emptyRequestAnalysis(rawBody);
|
|
3163
|
-
return {
|
|
3164
|
-
parsed: result.data,
|
|
3165
|
-
comparisonValue: result.data,
|
|
3166
|
-
messageCount: result.data.messages.length,
|
|
3167
|
-
toolCount: result.data.tools !== void 0 && result.data.tools.length > 0 ? result.data.tools.length : null
|
|
3168
|
-
};
|
|
3169
|
-
} catch {
|
|
3170
|
-
return emptyRequestAnalysis(rawBody);
|
|
3171
|
-
}
|
|
3172
|
-
},
|
|
3173
|
-
analyzeResponse(responseText) {
|
|
3174
|
-
if (responseText === null) return EMPTY_RESPONSE_ANALYSIS;
|
|
3175
|
-
const parsed = parseOpenAIResponse(responseText);
|
|
3176
|
-
if (parsed === null) return EMPTY_RESPONSE_ANALYSIS;
|
|
3177
|
-
const toolNames = parsed.choices[0]?.message?.tool_calls?.map((toolCall) => toolCall.function?.name ?? "").filter((name) => name !== "") ?? [];
|
|
3178
|
-
return {
|
|
3179
|
-
parsed,
|
|
3180
|
-
toolNames: toolNames.length > 0 ? toolNames : null
|
|
3181
|
-
};
|
|
3182
|
-
},
|
|
3183
|
-
anatomySegments(parsed) {
|
|
3184
|
-
if (parsed === null || typeof parsed !== "object") return null;
|
|
3185
|
-
const body = parsed;
|
|
3186
|
-
const segments = [];
|
|
3187
|
-
if (Array.isArray(body.messages)) {
|
|
3188
|
-
body.messages.forEach((message, index) => {
|
|
3189
|
-
if (message === null || typeof message !== "object") return;
|
|
3190
|
-
const m = message;
|
|
3191
|
-
const role = m.role === "user" || m.role === "assistant" || m.role === "system" || m.role === "tool" ? m.role : "user";
|
|
3192
|
-
const text = messageToText(m);
|
|
3193
|
-
segments.push(segment(role, `[${index}] ${role}`, text, `/messages/${index}`));
|
|
3194
|
-
});
|
|
3195
|
-
}
|
|
3196
|
-
if (Array.isArray(body.tools) && body.tools.length > 0) {
|
|
3197
|
-
const text = toolsToText(body.tools);
|
|
3198
|
-
segments.push(segment("tools", "tools", text, "/tools"));
|
|
3000
|
+
className
|
|
3001
|
+
),
|
|
3002
|
+
...props,
|
|
3003
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3004
|
+
ScrollAreaThumb,
|
|
3005
|
+
{
|
|
3006
|
+
"data-slot": "scroll-area-thumb",
|
|
3007
|
+
className: "bg-border relative flex-1 rounded-full"
|
|
3008
|
+
}
|
|
3009
|
+
)
|
|
3199
3010
|
}
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
},
|
|
3211
|
-
anatomySegments() {
|
|
3212
|
-
return null;
|
|
3213
|
-
}
|
|
3011
|
+
);
|
|
3012
|
+
}
|
|
3013
|
+
const CATEGORY_LABELS = {
|
|
3014
|
+
file: "file",
|
|
3015
|
+
shell: "shell",
|
|
3016
|
+
browser: "browser",
|
|
3017
|
+
web: "web",
|
|
3018
|
+
mcp: "MCP",
|
|
3019
|
+
code: "code",
|
|
3020
|
+
other: "other"
|
|
3214
3021
|
};
|
|
3215
|
-
const
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3022
|
+
const CATEGORY_CLASSES = {
|
|
3023
|
+
file: "border-blue-400/20 bg-blue-400/5 text-blue-300",
|
|
3024
|
+
shell: "border-teal-400/20 bg-teal-400/5 text-teal-300",
|
|
3025
|
+
browser: "border-cyan-400/20 bg-cyan-400/5 text-cyan-300",
|
|
3026
|
+
web: "border-sky-400/20 bg-sky-400/5 text-sky-300",
|
|
3027
|
+
mcp: "border-violet-400/20 bg-violet-400/5 text-violet-300",
|
|
3028
|
+
code: "border-emerald-400/20 bg-emerald-400/5 text-emerald-300",
|
|
3029
|
+
other: "border-muted-foreground/20 bg-muted/30 text-muted-foreground"
|
|
3219
3030
|
};
|
|
3220
|
-
function
|
|
3221
|
-
|
|
3031
|
+
function CategoryIcon({ category }) {
|
|
3032
|
+
switch (category) {
|
|
3033
|
+
case "file":
|
|
3034
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { className: "size-3.5" });
|
|
3035
|
+
case "shell":
|
|
3036
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { className: "size-3.5" });
|
|
3037
|
+
case "browser":
|
|
3038
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(MousePointerClick, { className: "size-3.5" });
|
|
3039
|
+
case "web":
|
|
3040
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Globe, { className: "size-3.5" });
|
|
3041
|
+
case "mcp":
|
|
3042
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Blocks, { className: "size-3.5" });
|
|
3043
|
+
case "code":
|
|
3044
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(CodeXml, { className: "size-3.5" });
|
|
3045
|
+
case "other":
|
|
3046
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Ellipsis, { className: "size-3.5" });
|
|
3047
|
+
}
|
|
3222
3048
|
}
|
|
3223
|
-
function
|
|
3224
|
-
|
|
3225
|
-
return
|
|
3049
|
+
function RequiredParameters({ names }) {
|
|
3050
|
+
if (names.length === 0) return null;
|
|
3051
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-1", children: [
|
|
3052
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: "required" }),
|
|
3053
|
+
names.slice(0, 4).map((name) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3054
|
+
Badge,
|
|
3055
|
+
{
|
|
3056
|
+
variant: "outline",
|
|
3057
|
+
className: "h-5 max-w-36 truncate rounded-md px-1.5 py-0 font-mono text-[10px]",
|
|
3058
|
+
children: name
|
|
3059
|
+
},
|
|
3060
|
+
name
|
|
3061
|
+
)),
|
|
3062
|
+
names.length > 4 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[10px] text-muted-foreground", children: [
|
|
3063
|
+
"+",
|
|
3064
|
+
names.length - 4
|
|
3065
|
+
] })
|
|
3066
|
+
] });
|
|
3067
|
+
}
|
|
3068
|
+
function ToolRow({ tool, called }) {
|
|
3069
|
+
const [open, setOpen] = reactExports.useState(false);
|
|
3070
|
+
const nameCopy = useCopyFeedback(tool.name);
|
|
3071
|
+
const hasDetails = tool.description !== null || tool.requiredParameters.length > 0 || tool.schema !== null;
|
|
3072
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Collapsible, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-md border border-border/60 bg-background/40", children: [
|
|
3073
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2 px-2.5 py-2", children: [
|
|
3074
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3075
|
+
"button",
|
|
3076
|
+
{
|
|
3077
|
+
type: "button",
|
|
3078
|
+
className: "flex min-w-0 flex-1 items-center gap-2 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
3079
|
+
onClick: () => setOpen((value) => !value),
|
|
3080
|
+
"aria-expanded": open,
|
|
3081
|
+
disabled: !hasDetails,
|
|
3082
|
+
children: [
|
|
3083
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CategoryIcon, { category: tool.category }),
|
|
3084
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 truncate font-mono text-xs font-semibold text-foreground/90", children: tool.name }),
|
|
3085
|
+
called && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3086
|
+
Badge,
|
|
3087
|
+
{
|
|
3088
|
+
variant: "outline",
|
|
3089
|
+
className: "h-5 rounded-md border-emerald-400/20 bg-emerald-400/5 px-1.5 py-0 text-[10px] text-emerald-300",
|
|
3090
|
+
children: "called"
|
|
3091
|
+
}
|
|
3092
|
+
),
|
|
3093
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[10px] text-muted-foreground", children: [
|
|
3094
|
+
tool.parameterCount,
|
|
3095
|
+
" params"
|
|
3096
|
+
] }),
|
|
3097
|
+
tool.descriptionPreview !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "hidden min-w-0 truncate text-xs text-muted-foreground md:inline", children: tool.descriptionPreview }),
|
|
3098
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1" }),
|
|
3099
|
+
hasDetails && (open ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3.5 shrink-0 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3.5 shrink-0 text-muted-foreground" }))
|
|
3100
|
+
]
|
|
3101
|
+
}
|
|
3102
|
+
),
|
|
3103
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3104
|
+
"button",
|
|
3105
|
+
{
|
|
3106
|
+
type: "button",
|
|
3107
|
+
className: "inline-flex size-7 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
3108
|
+
onClick: nameCopy.copy,
|
|
3109
|
+
"aria-label": nameCopy.copied ? "Copied tool name" : "Copy tool name",
|
|
3110
|
+
children: nameCopy.copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-emerald-400" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
|
|
3111
|
+
}
|
|
3112
|
+
)
|
|
3113
|
+
] }),
|
|
3114
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2 border-t border-border/60 px-2.5 py-2", children: [
|
|
3115
|
+
tool.description !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: tool.description }),
|
|
3116
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(RequiredParameters, { names: tool.requiredParameters }),
|
|
3117
|
+
tool.schema !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "max-h-64 rounded-md border border-border/60 bg-muted/20 p-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(JsonViewer, { data: safeJsonValue(tool.schema), defaultExpandDepth: 0 }) })
|
|
3118
|
+
] }) })
|
|
3119
|
+
] }) });
|
|
3120
|
+
}
|
|
3121
|
+
function matchesQuery(tool, query) {
|
|
3122
|
+
if (query.length === 0) return true;
|
|
3123
|
+
const haystack = `${tool.name} ${tool.description ?? ""} ${CATEGORY_LABELS[tool.category]}`.toLowerCase().trim();
|
|
3124
|
+
return haystack.includes(query);
|
|
3226
3125
|
}
|
|
3126
|
+
const RequestTools = reactExports.memo(function RequestTools2({
|
|
3127
|
+
summary,
|
|
3128
|
+
calledToolNames
|
|
3129
|
+
}) {
|
|
3130
|
+
const [expanded, setExpanded] = reactExports.useState(false);
|
|
3131
|
+
const [query, setQuery] = reactExports.useState("");
|
|
3132
|
+
const calledNames = reactExports.useMemo(() => new Set(calledToolNames), [calledToolNames]);
|
|
3133
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
3134
|
+
const visibleTools = reactExports.useMemo(
|
|
3135
|
+
() => summary === null ? [] : summary.tools.filter((tool) => matchesQuery(tool, normalizedQuery)),
|
|
3136
|
+
[normalizedQuery, summary]
|
|
3137
|
+
);
|
|
3138
|
+
if (summary === null) return null;
|
|
3139
|
+
const previewTools = summary.tools.slice(0, 6);
|
|
3140
|
+
const hiddenPreviewCount = summary.tools.length - previewTools.length;
|
|
3141
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "mb-3 rounded-lg border border-border/70 bg-muted/20", children: [
|
|
3142
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2 px-3 py-2", children: [
|
|
3143
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
3144
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-4 shrink-0 text-sky-300/80" }),
|
|
3145
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
|
|
3146
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-1.5", children: [
|
|
3147
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-semibold text-foreground", children: "Request Tools" }),
|
|
3148
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "h-5 rounded-md px-1.5 py-0 font-mono text-[10px]", children: summary.tools.length }),
|
|
3149
|
+
summary.toolChoiceLabel !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3150
|
+
Badge,
|
|
3151
|
+
{
|
|
3152
|
+
variant: "outline",
|
|
3153
|
+
className: "h-5 rounded-md px-1.5 py-0 font-mono text-[10px] text-muted-foreground",
|
|
3154
|
+
children: [
|
|
3155
|
+
"tool_choice: ",
|
|
3156
|
+
summary.toolChoiceLabel
|
|
3157
|
+
]
|
|
3158
|
+
}
|
|
3159
|
+
)
|
|
3160
|
+
] }),
|
|
3161
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 flex min-w-0 flex-wrap gap-1", children: summary.categories.map((category) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3162
|
+
Badge,
|
|
3163
|
+
{
|
|
3164
|
+
variant: "outline",
|
|
3165
|
+
className: cn(
|
|
3166
|
+
"h-5 rounded-md px-1.5 py-0 font-mono text-[10px]",
|
|
3167
|
+
CATEGORY_CLASSES[category.category]
|
|
3168
|
+
),
|
|
3169
|
+
children: [
|
|
3170
|
+
category.count,
|
|
3171
|
+
" ",
|
|
3172
|
+
CATEGORY_LABELS[category.category]
|
|
3173
|
+
]
|
|
3174
|
+
},
|
|
3175
|
+
category.category
|
|
3176
|
+
)) })
|
|
3177
|
+
] })
|
|
3178
|
+
] }),
|
|
3179
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3180
|
+
Button,
|
|
3181
|
+
{
|
|
3182
|
+
type: "button",
|
|
3183
|
+
variant: "ghost",
|
|
3184
|
+
size: "sm",
|
|
3185
|
+
className: "h-7 px-2",
|
|
3186
|
+
onClick: () => setExpanded((value) => !value),
|
|
3187
|
+
"aria-expanded": expanded,
|
|
3188
|
+
children: [
|
|
3189
|
+
expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3.5" }),
|
|
3190
|
+
expanded ? "Hide" : "Show"
|
|
3191
|
+
]
|
|
3192
|
+
}
|
|
3193
|
+
)
|
|
3194
|
+
] }),
|
|
3195
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap gap-1.5 border-t border-border/60 px-3 py-2", children: [
|
|
3196
|
+
previewTools.map((tool) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3197
|
+
Badge,
|
|
3198
|
+
{
|
|
3199
|
+
variant: "outline",
|
|
3200
|
+
className: cn(
|
|
3201
|
+
"h-5 max-w-44 truncate rounded-md px-1.5 py-0 font-mono text-[10px]",
|
|
3202
|
+
calledNames.has(tool.name) && "border-emerald-400/20 text-emerald-300"
|
|
3203
|
+
),
|
|
3204
|
+
children: tool.name
|
|
3205
|
+
},
|
|
3206
|
+
tool.name
|
|
3207
|
+
)),
|
|
3208
|
+
hiddenPreviewCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[10px] leading-5 text-muted-foreground", children: [
|
|
3209
|
+
"+",
|
|
3210
|
+
hiddenPreviewCount
|
|
3211
|
+
] })
|
|
3212
|
+
] }),
|
|
3213
|
+
expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2 border-t border-border/60 px-3 py-3", children: [
|
|
3214
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex h-8 items-center gap-2 rounded-md border border-border/70 bg-background/50 px-2 text-xs", children: [
|
|
3215
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Search, { className: "size-3.5 shrink-0 text-muted-foreground" }),
|
|
3216
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3217
|
+
"input",
|
|
3218
|
+
{
|
|
3219
|
+
value: query,
|
|
3220
|
+
onChange: (event) => setQuery(event.target.value),
|
|
3221
|
+
placeholder: "Filter tools",
|
|
3222
|
+
className: "min-w-0 flex-1 bg-transparent font-mono text-xs outline-none placeholder:text-muted-foreground/70"
|
|
3223
|
+
}
|
|
3224
|
+
)
|
|
3225
|
+
] }),
|
|
3226
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-1.5", children: visibleTools.length > 0 ? visibleTools.map((tool) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToolRow, { tool, called: calledNames.has(tool.name) }, tool.name)) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "py-2 text-xs text-muted-foreground", children: "No matching tools" }) })
|
|
3227
|
+
] })
|
|
3228
|
+
] });
|
|
3229
|
+
});
|
|
3227
3230
|
const LOG_FOCUS_REQUEST_EVENT = "agent-inspector:focus-log";
|
|
3228
3231
|
function dispatchLogFocusRequest(request) {
|
|
3229
3232
|
window.dispatchEvent(new CustomEvent(LOG_FOCUS_REQUEST_EVENT, { detail: request }));
|
|
@@ -9948,6 +9951,13 @@ function truncateSessionId(id) {
|
|
|
9948
9951
|
function shouldShowRawExport(captureMode) {
|
|
9949
9952
|
return captureMode === "full";
|
|
9950
9953
|
}
|
|
9954
|
+
function getExportActionVisibility(captureMode, logCount) {
|
|
9955
|
+
const hasLogs = logCount > 0;
|
|
9956
|
+
return {
|
|
9957
|
+
redacted: hasLogs,
|
|
9958
|
+
raw: hasLogs && shouldShowRawExport(captureMode)
|
|
9959
|
+
};
|
|
9960
|
+
}
|
|
9951
9961
|
function computeTokenSummary(logs) {
|
|
9952
9962
|
let totalIn = 0;
|
|
9953
9963
|
let totalOut = 0;
|
|
@@ -10517,7 +10527,7 @@ function ProxyViewer({
|
|
|
10517
10527
|
);
|
|
10518
10528
|
const cacheTrends = reactExports.useMemo(() => computeCacheTrends(groups), [groups]);
|
|
10519
10529
|
const comparisonPredecessors = reactExports.useMemo(() => buildValidPredecessors(groups), [groups]);
|
|
10520
|
-
const
|
|
10530
|
+
const exportActionVisibility = getExportActionVisibility(captureMode, logs.length);
|
|
10521
10531
|
const handleCompareWithPrevious = reactExports.useCallback(
|
|
10522
10532
|
(log) => {
|
|
10523
10533
|
const predecessor = comparisonPredecessors.get(log.id);
|
|
@@ -10641,7 +10651,7 @@ function ProxyViewer({
|
|
|
10641
10651
|
logs.length !== 1 ? "s" : "",
|
|
10642
10652
|
totalIn > 0 || totalOut > 0 ? ` - ${formatTokens(totalIn)} in / ${formatTokens(totalOut)} out` : ""
|
|
10643
10653
|
] }),
|
|
10644
|
-
|
|
10654
|
+
exportActionVisibility.redacted && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10645
10655
|
"button",
|
|
10646
10656
|
{
|
|
10647
10657
|
type: "button",
|
|
@@ -10657,7 +10667,7 @@ function ProxyViewer({
|
|
|
10657
10667
|
] })
|
|
10658
10668
|
}
|
|
10659
10669
|
),
|
|
10660
|
-
|
|
10670
|
+
exportActionVisibility.raw && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10661
10671
|
"button",
|
|
10662
10672
|
{
|
|
10663
10673
|
type: "button",
|
|
@@ -10665,19 +10675,25 @@ function ProxyViewer({
|
|
|
10665
10675
|
void handleExport("raw");
|
|
10666
10676
|
},
|
|
10667
10677
|
disabled: exporting !== null,
|
|
10668
|
-
className: "h-8 px-2 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed rounded-md hover:bg-muted",
|
|
10678
|
+
className: "h-8 px-2.5 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center gap-1.5 rounded-md hover:bg-muted",
|
|
10669
10679
|
title: "Export raw logs without redaction",
|
|
10670
|
-
children: exporting === "raw" ? "Exporting..." :
|
|
10680
|
+
children: exporting === "raw" ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Exporting..." }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
10681
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FileBraces, { className: "size-3.5" }),
|
|
10682
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Raw" })
|
|
10683
|
+
] })
|
|
10671
10684
|
}
|
|
10672
10685
|
),
|
|
10673
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
10686
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
10674
10687
|
"button",
|
|
10675
10688
|
{
|
|
10676
10689
|
type: "button",
|
|
10677
10690
|
onClick: onClearAll,
|
|
10678
|
-
className: "h-8 px-3 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer rounded-md hover:bg-muted",
|
|
10691
|
+
className: "h-8 px-3 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer inline-flex items-center gap-1.5 rounded-md hover:bg-muted",
|
|
10679
10692
|
title: "Clear all logs",
|
|
10680
|
-
children:
|
|
10693
|
+
children: [
|
|
10694
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" }),
|
|
10695
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Clear" })
|
|
10696
|
+
]
|
|
10681
10697
|
}
|
|
10682
10698
|
)
|
|
10683
10699
|
] }),
|