@tonyclaw/agent-inspector 3.0.29 → 3.0.31
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 +791 -191
- package/.output/nitro.json +1 -1
- package/.output/public/assets/CompareDrawer-DB2KggLE.js +1 -0
- package/.output/public/assets/InspectorPet-CfwDw6kD.js +4108 -0
- package/.output/public/assets/ProxyViewerContainer-PcrO96_F.js +126 -0
- package/.output/public/assets/{ReplayDialog-CctnITbt.js → ReplayDialog-3Pl7EKjp.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-BrN0RBbL.js → RequestAnatomy-BcPjcHLX.js} +1 -1
- package/.output/public/assets/ResponseView-DOx51wV3.js +2 -0
- package/.output/public/assets/StreamingChunkSequence-LkYJWM1A.js +1 -0
- package/.output/public/assets/_sessionId-BSg32vC6.js +1 -0
- package/.output/public/assets/{_sessionId-DKM91udC.js → _sessionId-C0CA68QV.js} +1 -1
- package/.output/public/assets/{index-Bq-nqolG.js → index-BpBUqdAB.js} +1 -1
- package/.output/public/assets/index-D93dCgAQ.js +1 -0
- package/.output/public/assets/{index-DPiESBo2.js → index-FV5sxqx3.js} +6 -6
- package/.output/public/assets/index-VUsF4nhf.js +76 -0
- package/.output/public/assets/index-hyQHZeQI.css +1 -0
- package/.output/public/assets/{json-viewer-CfaDJwx8.js → json-viewer-WctIbAh_.js} +1 -1
- package/.output/public/assets/jszip.min-DnSIoTix.js +2 -0
- package/.output/public/assets/qwen-mMn3f5ul.webp +0 -0
- package/.output/server/_libs/jszip.mjs +35 -9
- package/.output/server/_libs/lucide-react.mjs +80 -80
- package/.output/server/_libs/radix-ui__react-dialog.mjs +3 -3
- package/.output/server/_libs/tanstack__react-router.mjs +1 -1
- package/.output/server/{_sessionId-CwGXPD4C.mjs → _sessionId-BHBK3VbF.mjs} +15 -15
- package/.output/server/_sessionId-CyuJ6Kfl.mjs +81 -0
- package/.output/server/_ssr/{CompareDrawer-R_P1-VNr.mjs → CompareDrawer-27amlv_a.mjs} +138 -103
- package/.output/server/_ssr/InspectorPet-CQnGXfLs.mjs +925 -0
- package/.output/server/_ssr/{ProxyViewerContainer-DUgxRNbj.mjs → ProxyViewerContainer-DlAl0uF-.mjs} +1569 -1646
- package/.output/server/_ssr/{ReplayDialog-De9wKKzS.mjs → ReplayDialog-5m2jtlLa.mjs} +18 -18
- package/.output/server/_ssr/{RequestAnatomy-Db4MxUYo.mjs → RequestAnatomy--1WtQNY9.mjs} +58 -58
- package/.output/server/_ssr/{ResponseView-8rDXOiNB.mjs → ResponseView-CgbqS8sr.mjs} +60 -71
- package/.output/server/_ssr/{StreamingChunkSequence-N9teZHkA.mjs → StreamingChunkSequence-BwpnopWx.mjs} +16 -16
- package/.output/server/_ssr/{index-D4DvByuW.mjs → index-CNVi1TzT.mjs} +15 -15
- package/.output/server/_ssr/index-DMCjH_4V.mjs +81 -0
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-BjoHRbjS.mjs → json-viewer-DNGN2uoe.mjs} +58 -58
- package/.output/server/_ssr/{router-BYlePDj8.mjs → router-CgsqLnk5.mjs} +16007 -12632
- package/.output/server/_tanstack-start-manifest_v-BH5f_kWV.mjs +4 -0
- package/.output/server/index.mjs +99 -71
- package/.output/workers/logFinalizer.worker.js +16908 -0
- package/.output/workers/sessionWorkerEntry.js +16904 -0
- package/README.md +21 -5
- package/package.json +6 -2
- package/src/assets/logos/qwen.webp +0 -0
- package/src/cli.ts +85 -10
- package/src/components/OnboardingBanner.tsx +41 -21
- package/src/components/ProxyViewer.tsx +198 -269
- package/src/components/ProxyViewerContainer.tsx +128 -17
- package/src/components/ecosystem/AgentLabDialog.tsx +166 -19
- package/src/components/errors/SafeErrorBoundary.tsx +201 -0
- package/src/components/pi-agent/PiAgentPanel.tsx +209 -35
- package/src/components/pi-agent/piAgentChatLogic.ts +263 -0
- package/src/components/providers/ImportWizardDialog.tsx +18 -42
- package/src/components/providers/ProviderLogo.tsx +1 -1
- package/src/components/providers/ProvidersPanel.tsx +8 -5
- package/src/components/providers/SettingsDialog.tsx +34 -11
- package/src/components/proxy-viewer/ApplicationBar.tsx +63 -0
- package/src/components/proxy-viewer/CompareDrawer.tsx +92 -49
- package/src/components/proxy-viewer/LiveConnectionStatus.tsx +186 -0
- package/src/components/proxy-viewer/LogEntry.tsx +283 -275
- package/src/components/proxy-viewer/RawExportWarning.tsx +77 -0
- package/src/components/proxy-viewer/SessionLoadProgressBar.tsx +61 -0
- package/src/components/proxy-viewer/ThreadConnector.tsx +16 -1
- package/src/components/proxy-viewer/TurnGroup.tsx +13 -2
- package/src/components/proxy-viewer/accessibility.ts +8 -0
- package/src/components/proxy-viewer/lazy.ts +4 -0
- package/src/components/proxy-viewer/liveConnectionState.ts +158 -0
- package/src/components/proxy-viewer/proxyViewerLogic.ts +10 -0
- package/src/components/proxy-viewer/viewerState.ts +2 -6
- package/src/components/ui/select.tsx +1 -1
- package/src/components/ui/tabs.tsx +3 -3
- package/src/components/ui/transient-toast.tsx +7 -6
- package/src/lib/apiClient.ts +17 -2
- package/src/lib/ecosystemContract.ts +34 -0
- package/src/lib/export-logs.ts +1 -1
- package/src/lib/piAgentContract.ts +80 -0
- package/src/lib/providerContract.ts +70 -4
- package/src/lib/providerImportContract.ts +27 -0
- package/src/lib/providerModelMetadata.ts +16 -7
- package/src/lib/resourceLimits.ts +152 -0
- package/src/lib/safeDiagnostic.ts +38 -0
- package/src/lib/useProviders.ts +4 -4
- package/src/mcp/server.ts +39 -6
- package/src/mcp/toolHandlers.ts +131 -4
- package/src/proxy/chunkStorage.ts +20 -6
- package/src/proxy/config.ts +20 -6
- package/src/proxy/dataDir.ts +3 -0
- package/src/proxy/ecosystemExecutionConfirmation.ts +114 -0
- package/src/proxy/ecosystemExecutionRoute.ts +116 -0
- package/src/proxy/ecosystemTasks.ts +48 -0
- package/src/proxy/evidenceExporter.ts +23 -9
- package/src/proxy/groupEvidenceExporter.ts +26 -5
- package/src/proxy/groupStore.ts +13 -3
- package/src/proxy/handler.ts +103 -20
- package/src/proxy/identityProxy.ts +333 -14
- package/src/proxy/logFinalizer.ts +73 -6
- package/src/proxy/logImportUpload.ts +128 -0
- package/src/proxy/logImporter.ts +321 -70
- package/src/proxy/logIndex.ts +16 -6
- package/src/proxy/logger.ts +294 -41
- package/src/proxy/privateDataPath.ts +183 -0
- package/src/proxy/providerScanStore.ts +87 -0
- package/src/proxy/providerSecretStore.ts +58 -19
- package/src/proxy/providers.ts +175 -58
- package/src/proxy/rawStreamCapture.ts +66 -5
- package/src/proxy/runStore.ts +13 -3
- package/src/proxy/runtimeAdmission.ts +52 -0
- package/src/proxy/runtimeHealth.ts +206 -0
- package/src/proxy/runtimeShutdown.ts +75 -0
- package/src/proxy/sessionArchive.ts +15 -2
- package/src/proxy/sessionProcess.ts +19 -0
- package/src/proxy/sessionRuntime.ts +7 -0
- package/src/proxy/shutdownCoordinator.ts +90 -0
- package/src/proxy/sqliteLogIndex.ts +18 -2
- package/src/proxy/store.ts +18 -2
- package/src/routes/__root.tsx +18 -1
- package/src/routes/api/alerts.summary.ts +12 -8
- package/src/routes/api/alerts.ts +27 -9
- package/src/routes/api/ecosystem.packages.$packageId.help.ts +3 -8
- package/src/routes/api/ecosystem.packages.$packageId.install.ts +3 -8
- package/src/routes/api/ecosystem.packages.$packageId.runner-presets.ts +3 -11
- package/src/routes/api/ecosystem.packages.$packageId.upgrade.ts +3 -8
- package/src/routes/api/ecosystem.recipes.$recipeId.run.ts +3 -8
- package/src/routes/api/health.ts +9 -2
- package/src/routes/api/knowledge.project-context.ts +11 -0
- package/src/routes/api/knowledge.search.ts +33 -2
- package/src/routes/api/logs.$id.body.ts +16 -2
- package/src/routes/api/logs.import.ts +7 -18
- package/src/routes/api/logs.stream.ts +147 -69
- package/src/routes/api/logs.ts +55 -14
- package/src/routes/api/providers.$providerId.model-metadata.ts +22 -4
- package/src/routes/api/providers.$providerId.ts +37 -6
- package/src/routes/api/providers.export.ts +34 -16
- package/src/routes/api/providers.import.ts +42 -8
- package/src/routes/api/providers.scan.ts +13 -8
- package/src/routes/api/providers.ts +36 -5
- package/src/routes/api/runs.ts +12 -12
- package/src/routes/api/sessions.ts +15 -8
- package/src/routes/index.tsx +6 -0
- package/src/routes/livez.ts +13 -0
- package/src/routes/readyz.ts +18 -0
- package/src/routes/session/$sessionId.tsx +6 -0
- package/src/services/piAgent.ts +131 -102
- package/src/services/piAgentRetrieval.ts +1180 -0
- package/styles/globals.css +19 -3
- package/.output/public/assets/CompareDrawer-Cb5ccPeX.js +0 -1
- package/.output/public/assets/ProxyViewerContainer-COBe5GTT.js +0 -4234
- package/.output/public/assets/ResponseView-Cqq87lX_.js +0 -3
- package/.output/public/assets/StreamingChunkSequence-CnTa9mCr.js +0 -1
- package/.output/public/assets/index-DTLNVcgc.js +0 -76
- package/.output/public/assets/index-DliqmwUw.css +0 -1
- package/.output/public/assets/qwen-CONDcHqt.png +0 -0
- package/.output/server/_tanstack-start-manifest_v-DMCA8KK3.mjs +0 -4
- package/src/assets/logos/mcp.png +0 -0
- package/src/assets/logos/qwen.png +0 -0
- package/src/components/ui/mcp-logo.tsx +0 -20
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
Flag,
|
|
31
31
|
PanelRightClose,
|
|
32
32
|
PanelRightOpen,
|
|
33
|
-
Plus,
|
|
34
33
|
RefreshCw,
|
|
35
34
|
Search,
|
|
36
35
|
Siren,
|
|
@@ -54,10 +53,12 @@ import { useThemeMode } from "../lib/useThemeMode";
|
|
|
54
53
|
import { formatUiScale, normalizeUiScalePreference, type UiScalePreference } from "../lib/uiScale";
|
|
55
54
|
import { useUiScale } from "../lib/useUiScale";
|
|
56
55
|
import { useProviders } from "../lib/useProviders";
|
|
57
|
-
import packageJson from "../../package.json";
|
|
58
56
|
import { groupLogsByConversation, type ConversationGroupData } from "./proxy-viewer";
|
|
59
57
|
import {
|
|
60
58
|
buildSessionSlateStats,
|
|
59
|
+
COPYABLE_COMMAND_CONTAINER_CLASS_NAME,
|
|
60
|
+
COPYABLE_COMMAND_TEXT_CLASS_NAME,
|
|
61
|
+
exportRequiresConfirmation,
|
|
61
62
|
formatPaginationStatus,
|
|
62
63
|
getExportActionVisibility,
|
|
63
64
|
resolveSessionContextScope,
|
|
@@ -68,8 +69,6 @@ import {
|
|
|
68
69
|
} from "./proxy-viewer/proxyViewerLogic";
|
|
69
70
|
|
|
70
71
|
import { CrabLogo } from "./ui/crab-logo";
|
|
71
|
-
import { crabVariants } from "./ui/crab-variants";
|
|
72
|
-
import { McpLogo } from "./ui/mcp-logo";
|
|
73
72
|
import { Button } from "./ui/button";
|
|
74
73
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "./ui/dialog";
|
|
75
74
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
|
|
@@ -79,12 +78,25 @@ import { AlertsDialog } from "./alerts/AlertsDialog";
|
|
|
79
78
|
import { GroupsDialog } from "./groups/GroupsDialog";
|
|
80
79
|
import { SettingsDialog } from "./providers/SettingsDialog";
|
|
81
80
|
import { AgentLabDialog } from "./ecosystem/AgentLabDialog";
|
|
82
|
-
import { InspectorPet } from "./inspector-pet/InspectorPet";
|
|
83
81
|
import { PiAgentPanel } from "./pi-agent/PiAgentPanel";
|
|
82
|
+
import { LazyFeatureBoundary } from "./errors/SafeErrorBoundary";
|
|
84
83
|
import { computeCacheTrends } from "./proxy-viewer/cacheTrend";
|
|
85
|
-
import { LazyCompareDrawer } from "./proxy-viewer/lazy";
|
|
84
|
+
import { LazyCompareDrawer, LazyInspectorPet } from "./proxy-viewer/lazy";
|
|
86
85
|
import { dispatchLogFocusRequest } from "./proxy-viewer/logFocus";
|
|
86
|
+
import { ApplicationBar } from "./proxy-viewer/ApplicationBar";
|
|
87
|
+
import {
|
|
88
|
+
SessionLoadProgressBar,
|
|
89
|
+
type SessionLoadProgress,
|
|
90
|
+
} from "./proxy-viewer/SessionLoadProgressBar";
|
|
91
|
+
import { browserPrefersReducedMotion, preferredScrollBehavior } from "./proxy-viewer/accessibility";
|
|
92
|
+
import { LiveConnectionStatus } from "./proxy-viewer/LiveConnectionStatus";
|
|
93
|
+
import {
|
|
94
|
+
getLiveEmptyStateCopy,
|
|
95
|
+
resolveLiveEmptyState,
|
|
96
|
+
type LiveConnectionState,
|
|
97
|
+
} from "./proxy-viewer/liveConnectionState";
|
|
87
98
|
import { ConversationGroupList } from "./proxy-viewer/ConversationGroupList";
|
|
99
|
+
import { RAW_EXPORT_DIALOG_CLASS_NAME, RawExportWarning } from "./proxy-viewer/RawExportWarning";
|
|
88
100
|
import { buildValidPredecessors } from "./proxy-viewer/viewerState";
|
|
89
101
|
import { useKeyboardNavigation } from "./proxy-viewer/useKeyboardNavigation";
|
|
90
102
|
import { SegmentBar } from "./proxy-viewer/anatomy/SegmentBar";
|
|
@@ -158,14 +170,6 @@ export type LogPaginationControls = {
|
|
|
158
170
|
onNewest: () => void;
|
|
159
171
|
};
|
|
160
172
|
|
|
161
|
-
export type SessionLoadProgress = {
|
|
162
|
-
label: string;
|
|
163
|
-
elapsedMs: number;
|
|
164
|
-
timeoutMs: number;
|
|
165
|
-
loadedLogs: number;
|
|
166
|
-
loadedPages: number;
|
|
167
|
-
};
|
|
168
|
-
|
|
169
173
|
function getFirstUserAgent(logs: CapturedLog[]): string | null {
|
|
170
174
|
for (const log of logs) {
|
|
171
175
|
if (log.userAgent !== null && log.userAgent !== undefined && log.userAgent !== "") {
|
|
@@ -574,7 +578,7 @@ function LogPaginationButton({
|
|
|
574
578
|
type="button"
|
|
575
579
|
onClick={onClick}
|
|
576
580
|
disabled={disabled}
|
|
577
|
-
className="border border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs text-muted-foreground transition-colors hover:text-foreground disabled:cursor-not-allowed disabled:opacity-45"
|
|
581
|
+
className="border border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-45"
|
|
578
582
|
title={title}
|
|
579
583
|
>
|
|
580
584
|
{icon}
|
|
@@ -583,44 +587,6 @@ function LogPaginationButton({
|
|
|
583
587
|
);
|
|
584
588
|
}
|
|
585
589
|
|
|
586
|
-
function formatDurationSeconds(ms: number): string {
|
|
587
|
-
return `${Math.max(0, Math.ceil(ms / 1000)).toString()}s`;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
function SessionLoadProgressBar({ progress }: { progress: SessionLoadProgress }): JSX.Element {
|
|
591
|
-
const elapsedRatio = Math.min(1, progress.elapsedMs / progress.timeoutMs);
|
|
592
|
-
const percent = Math.max(4, Math.round(elapsedRatio * 100));
|
|
593
|
-
const remainingMs = Math.max(0, progress.timeoutMs - progress.elapsedMs);
|
|
594
|
-
const nearTimeout = elapsedRatio >= 0.75;
|
|
595
|
-
const details = [
|
|
596
|
-
progress.loadedLogs > 0 ? `${progress.loadedLogs.toString()} logs` : null,
|
|
597
|
-
progress.loadedPages > 0
|
|
598
|
-
? `${progress.loadedPages.toString()} page${progress.loadedPages === 1 ? "" : "s"}`
|
|
599
|
-
: null,
|
|
600
|
-
`${formatDurationSeconds(remainingMs)} before timeout`,
|
|
601
|
-
].filter((item): item is string => item !== null);
|
|
602
|
-
|
|
603
|
-
return (
|
|
604
|
-
<div className="min-w-0 space-y-1 px-1 pb-1">
|
|
605
|
-
<div className="flex min-w-0 items-center justify-between gap-3 font-mono text-[10px] text-muted-foreground">
|
|
606
|
-
<span className="min-w-0 truncate">{progress.label}</span>
|
|
607
|
-
<span className={cn("shrink-0 tabular-nums", nearTimeout && "text-amber-300")}>
|
|
608
|
-
{details.join(" / ")}
|
|
609
|
-
</span>
|
|
610
|
-
</div>
|
|
611
|
-
<div className="h-1.5 overflow-hidden rounded-full bg-white/[0.06]">
|
|
612
|
-
<div
|
|
613
|
-
className={cn(
|
|
614
|
-
"h-full rounded-full transition-all duration-300",
|
|
615
|
-
nearTimeout ? "bg-amber-300/80" : "bg-cyan-300/70",
|
|
616
|
-
)}
|
|
617
|
-
style={{ width: `${percent.toString()}%` }}
|
|
618
|
-
/>
|
|
619
|
-
</div>
|
|
620
|
-
</div>
|
|
621
|
-
);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
590
|
function LogPaginationBar({
|
|
625
591
|
logs,
|
|
626
592
|
pagination,
|
|
@@ -634,7 +600,8 @@ function LogPaginationBar({
|
|
|
634
600
|
const disabled = pagination.isLoading;
|
|
635
601
|
|
|
636
602
|
return (
|
|
637
|
-
<
|
|
603
|
+
<nav
|
|
604
|
+
aria-label="Session log pagination"
|
|
638
605
|
className={cn(
|
|
639
606
|
"flex min-h-9 flex-col gap-2 px-1 py-1 sm:flex-row sm:items-center",
|
|
640
607
|
embedded
|
|
@@ -643,8 +610,10 @@ function LogPaginationBar({
|
|
|
643
610
|
)}
|
|
644
611
|
>
|
|
645
612
|
<div className="w-full min-w-0 px-1 font-mono text-[11px] text-muted-foreground sm:flex-1">
|
|
646
|
-
|
|
647
|
-
|
|
613
|
+
<div role="status" aria-live="polite" aria-atomic="true">
|
|
614
|
+
{formatPaginationStatus({ logs, pagination })}
|
|
615
|
+
{pagination.isLoading && logs.length > 0 && <span className="ml-2">Loading...</span>}
|
|
616
|
+
</div>
|
|
648
617
|
{pagination.loadProgress !== undefined && (
|
|
649
618
|
<SessionLoadProgressBar progress={pagination.loadProgress} />
|
|
650
619
|
)}
|
|
@@ -679,7 +648,7 @@ function LogPaginationBar({
|
|
|
679
648
|
onClick={pagination.onNewest}
|
|
680
649
|
/>
|
|
681
650
|
</div>
|
|
682
|
-
</
|
|
651
|
+
</nav>
|
|
683
652
|
);
|
|
684
653
|
}
|
|
685
654
|
|
|
@@ -739,7 +708,10 @@ function highlightLogTarget(target: HTMLElement): void {
|
|
|
739
708
|
function focusLogTarget(logId: number): boolean {
|
|
740
709
|
const target = document.getElementById(`log-${String(logId)}`);
|
|
741
710
|
if (!(target instanceof HTMLElement)) return false;
|
|
742
|
-
target.scrollIntoView({
|
|
711
|
+
target.scrollIntoView({
|
|
712
|
+
block: "center",
|
|
713
|
+
behavior: preferredScrollBehavior(browserPrefersReducedMotion()),
|
|
714
|
+
});
|
|
743
715
|
target.focus({ preventScroll: true });
|
|
744
716
|
highlightLogTarget(target);
|
|
745
717
|
return true;
|
|
@@ -774,12 +746,12 @@ function CopyableCommand({ command }: { command: string }): JSX.Element {
|
|
|
774
746
|
}, [command]);
|
|
775
747
|
|
|
776
748
|
return (
|
|
777
|
-
<div
|
|
778
|
-
<pre className=
|
|
749
|
+
<div data-command-example="true" className={COPYABLE_COMMAND_CONTAINER_CLASS_NAME}>
|
|
750
|
+
<pre className={COPYABLE_COMMAND_TEXT_CLASS_NAME}>{command}</pre>
|
|
779
751
|
<button
|
|
780
752
|
type="button"
|
|
781
753
|
onClick={handleCopy}
|
|
782
|
-
className="shrink-0 cursor-pointer text-muted-foreground transition-colors hover:text-foreground"
|
|
754
|
+
className="shrink-0 cursor-pointer rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none"
|
|
783
755
|
aria-label="Copy command"
|
|
784
756
|
>
|
|
785
757
|
{copied ? <Check className="size-4" /> : <Copy className="size-4" />}
|
|
@@ -827,60 +799,6 @@ function SidebarMetric({ label, value }: { label: string; value: string | number
|
|
|
827
799
|
);
|
|
828
800
|
}
|
|
829
801
|
|
|
830
|
-
const CRAB_VARIANT_COLORS = [
|
|
831
|
-
"text-amber-500",
|
|
832
|
-
"text-rose-500",
|
|
833
|
-
"text-sky-500",
|
|
834
|
-
"text-emerald-500",
|
|
835
|
-
"text-violet-500",
|
|
836
|
-
"text-orange-500",
|
|
837
|
-
"text-cyan-500",
|
|
838
|
-
"text-pink-500",
|
|
839
|
-
"text-lime-500",
|
|
840
|
-
"text-blue-500",
|
|
841
|
-
"text-yellow-500",
|
|
842
|
-
"text-fuchsia-500",
|
|
843
|
-
] as const;
|
|
844
|
-
|
|
845
|
-
function CrabFamily({
|
|
846
|
-
compact,
|
|
847
|
-
entrancePhase,
|
|
848
|
-
}: {
|
|
849
|
-
compact: boolean;
|
|
850
|
-
entrancePhase: "hidden" | "playing" | "done";
|
|
851
|
-
}): JSX.Element {
|
|
852
|
-
if (compact) {
|
|
853
|
-
return <CrabLogo className="size-14 text-amber-500" />;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
return (
|
|
857
|
-
<span className="flex shrink-0 items-end gap-1 group cursor-default" aria-hidden="true">
|
|
858
|
-
<CrabLogo className="size-10 text-amber-500 transition-all duration-300 group-hover:scale-125 group-hover:-translate-y-1.5" />
|
|
859
|
-
<span className="hidden items-end gap-0.5 sm:flex">
|
|
860
|
-
{crabVariants.map((Crab, i) => {
|
|
861
|
-
const color = CRAB_VARIANT_COLORS[i] ?? "text-amber-500";
|
|
862
|
-
const entranceClass =
|
|
863
|
-
entrancePhase === "hidden"
|
|
864
|
-
? "opacity-0 scale-0"
|
|
865
|
-
: entrancePhase === "playing"
|
|
866
|
-
? "animate-crab-piano-pop"
|
|
867
|
-
: "";
|
|
868
|
-
return (
|
|
869
|
-
<Crab
|
|
870
|
-
key={i}
|
|
871
|
-
className={`size-5 ${color} transition-all duration-300 ease-out group-hover:scale-125 group-hover:-translate-y-1 ${entranceClass}`}
|
|
872
|
-
style={{
|
|
873
|
-
transitionDelay: `${i * 50}ms`,
|
|
874
|
-
...(entrancePhase === "playing" ? { animationDelay: `${i * 400}ms` } : {}),
|
|
875
|
-
}}
|
|
876
|
-
/>
|
|
877
|
-
);
|
|
878
|
-
})}
|
|
879
|
-
</span>
|
|
880
|
-
</span>
|
|
881
|
-
);
|
|
882
|
-
}
|
|
883
|
-
|
|
884
802
|
function ThemeModeToggle(): JSX.Element {
|
|
885
803
|
const { themeMode, setThemeMode } = useThemeMode();
|
|
886
804
|
|
|
@@ -894,7 +812,7 @@ function ThemeModeToggle(): JSX.Element {
|
|
|
894
812
|
type="button"
|
|
895
813
|
onClick={() => setThemeMode("light")}
|
|
896
814
|
className={cn(
|
|
897
|
-
"inline-flex size-7 items-center justify-center rounded-[6px] text-muted-foreground transition-colors hover:text-foreground",
|
|
815
|
+
"inline-flex size-7 items-center justify-center rounded-[6px] text-muted-foreground transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none",
|
|
898
816
|
themeMode === "light" && "bg-background text-foreground shadow-sm",
|
|
899
817
|
)}
|
|
900
818
|
aria-label="Use light mode"
|
|
@@ -907,7 +825,7 @@ function ThemeModeToggle(): JSX.Element {
|
|
|
907
825
|
type="button"
|
|
908
826
|
onClick={() => setThemeMode("eye-care")}
|
|
909
827
|
className={cn(
|
|
910
|
-
"inline-flex size-7 items-center justify-center rounded-[6px] text-muted-foreground transition-colors hover:text-foreground",
|
|
828
|
+
"inline-flex size-7 items-center justify-center rounded-[6px] text-muted-foreground transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none",
|
|
911
829
|
themeMode === "eye-care" && "bg-background text-foreground shadow-sm",
|
|
912
830
|
)}
|
|
913
831
|
aria-label="Use eye care mode"
|
|
@@ -920,7 +838,7 @@ function ThemeModeToggle(): JSX.Element {
|
|
|
920
838
|
type="button"
|
|
921
839
|
onClick={() => setThemeMode("dark")}
|
|
922
840
|
className={cn(
|
|
923
|
-
"inline-flex size-7 items-center justify-center rounded-[6px] text-muted-foreground transition-colors hover:text-foreground",
|
|
841
|
+
"inline-flex size-7 items-center justify-center rounded-[6px] text-muted-foreground transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none",
|
|
924
842
|
themeMode === "dark" && "bg-background text-foreground shadow-sm",
|
|
925
843
|
)}
|
|
926
844
|
aria-label="Use dark mode"
|
|
@@ -994,93 +912,6 @@ function UiScaleControl({
|
|
|
994
912
|
);
|
|
995
913
|
}
|
|
996
914
|
|
|
997
|
-
function BrandHeader({
|
|
998
|
-
compact,
|
|
999
|
-
crabEntrancePhase,
|
|
1000
|
-
currentSessionId,
|
|
1001
|
-
logCount,
|
|
1002
|
-
uiScalePreference,
|
|
1003
|
-
resolvedUiScale,
|
|
1004
|
-
onUiScaleChange,
|
|
1005
|
-
}: {
|
|
1006
|
-
compact: boolean;
|
|
1007
|
-
crabEntrancePhase: "hidden" | "playing" | "done";
|
|
1008
|
-
currentSessionId: string | null;
|
|
1009
|
-
logCount: number;
|
|
1010
|
-
uiScalePreference: UiScalePreference;
|
|
1011
|
-
resolvedUiScale: number;
|
|
1012
|
-
onUiScaleChange: (preference: UiScalePreference) => void;
|
|
1013
|
-
}): JSX.Element {
|
|
1014
|
-
if (compact) {
|
|
1015
|
-
return (
|
|
1016
|
-
<div className="bg-white/[0.035] shadow-[inset_0_1px_0_rgba(255,255,255,0.045),0_16px_44px_rgba(0,0,0,0.18)] rounded-[8px] p-3">
|
|
1017
|
-
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
1018
|
-
<div className="flex min-w-fit items-start gap-3">
|
|
1019
|
-
<CrabFamily compact={true} entrancePhase={crabEntrancePhase} />
|
|
1020
|
-
<div className="min-w-fit">
|
|
1021
|
-
<div className="flex min-w-fit flex-wrap items-baseline gap-x-2 gap-y-0.5">
|
|
1022
|
-
<span className="whitespace-nowrap text-base font-bold">Agent Inspector</span>
|
|
1023
|
-
<span className="hidden shrink-0 font-mono text-[11px] font-semibold text-muted-foreground sm:inline">
|
|
1024
|
-
v{packageJson.version}
|
|
1025
|
-
</span>
|
|
1026
|
-
</div>
|
|
1027
|
-
<div className="hidden text-[11px] font-semibold text-muted-foreground sm:block">
|
|
1028
|
-
Local First. Evidence First.
|
|
1029
|
-
</div>
|
|
1030
|
-
</div>
|
|
1031
|
-
</div>
|
|
1032
|
-
<div className="flex shrink-0 items-center gap-1">
|
|
1033
|
-
<ThemeModeToggle />
|
|
1034
|
-
<UiScaleControl
|
|
1035
|
-
preference={uiScalePreference}
|
|
1036
|
-
resolvedScale={resolvedUiScale}
|
|
1037
|
-
onChange={onUiScaleChange}
|
|
1038
|
-
/>
|
|
1039
|
-
<AlertsDialog />
|
|
1040
|
-
<GroupsDialog />
|
|
1041
|
-
<AgentLabDialog currentSessionId={currentSessionId} logCount={logCount} />
|
|
1042
|
-
<SettingsDialog />
|
|
1043
|
-
</div>
|
|
1044
|
-
</div>
|
|
1045
|
-
</div>
|
|
1046
|
-
);
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
return (
|
|
1050
|
-
<div className="flex flex-wrap items-start justify-between gap-x-4 gap-y-3 pb-6">
|
|
1051
|
-
<div className="min-w-10 flex-1" aria-hidden="true" />
|
|
1052
|
-
<h1 className="flex min-w-fit flex-col items-center gap-2 text-center">
|
|
1053
|
-
<span className="flex max-w-full flex-wrap items-end justify-center gap-x-2 gap-y-1">
|
|
1054
|
-
<CrabFamily compact={false} entrancePhase={crabEntrancePhase} />
|
|
1055
|
-
<span className="flex min-w-fit flex-wrap items-baseline justify-center gap-x-2 gap-y-0.5 pl-1">
|
|
1056
|
-
<span className="whitespace-nowrap text-lg font-bold">Agent Inspector</span>
|
|
1057
|
-
<span className="shrink-0 font-mono text-xs font-semibold text-muted-foreground">
|
|
1058
|
-
v{packageJson.version}
|
|
1059
|
-
</span>
|
|
1060
|
-
</span>
|
|
1061
|
-
<Plus className="size-4 shrink-0 text-muted-foreground/70" aria-hidden="true" />
|
|
1062
|
-
<McpLogo className="size-10 shrink-0" />
|
|
1063
|
-
</span>
|
|
1064
|
-
<span className="max-w-full text-sm font-semibold text-muted-foreground">
|
|
1065
|
-
Local First. Evidence First.
|
|
1066
|
-
</span>
|
|
1067
|
-
</h1>
|
|
1068
|
-
<div className="flex flex-1 justify-end gap-1">
|
|
1069
|
-
<ThemeModeToggle />
|
|
1070
|
-
<UiScaleControl
|
|
1071
|
-
preference={uiScalePreference}
|
|
1072
|
-
resolvedScale={resolvedUiScale}
|
|
1073
|
-
onChange={onUiScaleChange}
|
|
1074
|
-
/>
|
|
1075
|
-
<AlertsDialog />
|
|
1076
|
-
<GroupsDialog />
|
|
1077
|
-
<AgentLabDialog currentSessionId={currentSessionId} logCount={logCount} />
|
|
1078
|
-
<SettingsDialog />
|
|
1079
|
-
</div>
|
|
1080
|
-
</div>
|
|
1081
|
-
);
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
915
|
const DETAILS_PANEL_COLLAPSED_STORAGE_KEY = "agent-inspector.detailsPanelCollapsed";
|
|
1085
916
|
const INSPECTOR_PET_VISIBLE_STORAGE_KEY = "agent-inspector.pet.visible";
|
|
1086
917
|
|
|
@@ -1435,10 +1266,18 @@ export type ProxyViewerProps = {
|
|
|
1435
1266
|
timeDisplayFormat: TimeDisplayFormat;
|
|
1436
1267
|
/** True while a pinned session page is waiting for its initial log scan. */
|
|
1437
1268
|
isLoading?: boolean;
|
|
1269
|
+
/** Current truth for the all-sessions live stream. Omitted on stored session pages. */
|
|
1270
|
+
liveConnection?: LiveConnectionState;
|
|
1271
|
+
/** Retry the live stream immediately without discarding displayed logs. */
|
|
1272
|
+
onRetryLiveConnection?: () => void;
|
|
1273
|
+
/** Stop automatic live-stream retries while keeping displayed logs available. */
|
|
1274
|
+
onStopLiveConnection?: () => void;
|
|
1438
1275
|
/** Cursor controls for history pages. Undefined keeps the live stream UI compact. */
|
|
1439
1276
|
pagination?: LogPaginationControls;
|
|
1440
1277
|
/** Active session log loading progress, shown near load/reload controls. */
|
|
1441
1278
|
sessionLoadProgress?: SessionLoadProgress;
|
|
1279
|
+
/** Recoverable session history load failure; existing logs remain visible. */
|
|
1280
|
+
sessionLoadError?: string;
|
|
1442
1281
|
/** Group/run member metadata attached to the pinned session id. */
|
|
1443
1282
|
sessionMemberships?: SessionMembershipEvidence[];
|
|
1444
1283
|
/** Hide the session filter dropdown. Used on `/session/$id` routes where
|
|
@@ -1469,8 +1308,12 @@ export function ProxyViewer({
|
|
|
1469
1308
|
slowResponseThresholdSeconds,
|
|
1470
1309
|
timeDisplayFormat,
|
|
1471
1310
|
isLoading = false,
|
|
1311
|
+
liveConnection,
|
|
1312
|
+
onRetryLiveConnection,
|
|
1313
|
+
onStopLiveConnection,
|
|
1472
1314
|
pagination,
|
|
1473
1315
|
sessionLoadProgress,
|
|
1316
|
+
sessionLoadError,
|
|
1474
1317
|
sessionMemberships = [],
|
|
1475
1318
|
hideSessionFilter = false,
|
|
1476
1319
|
pinnedSessionId,
|
|
@@ -1480,6 +1323,7 @@ export function ProxyViewer({
|
|
|
1480
1323
|
const { uiScalePreference, resolvedUiScale, setUiScalePreference } = useUiScale();
|
|
1481
1324
|
const [exporting, setExporting] = useState<ExportMode | null>(null);
|
|
1482
1325
|
const [exportError, setExportError] = useState<string | null>(null);
|
|
1326
|
+
const [rawExportDialogOpen, setRawExportDialogOpen] = useState(false);
|
|
1483
1327
|
const [importing, setImporting] = useState(false);
|
|
1484
1328
|
const [importStatus, setImportStatus] = useState<string | null>(null);
|
|
1485
1329
|
const [importError, setImportError] = useState<string | null>(null);
|
|
@@ -1490,9 +1334,6 @@ export function ProxyViewer({
|
|
|
1490
1334
|
const [petVisible, setPetVisible] = useState(true);
|
|
1491
1335
|
const [petVisibilityStorageLoaded, setPetVisibilityStorageLoaded] = useState(false);
|
|
1492
1336
|
const [comparePair, setComparePair] = useState<[CapturedLog, CapturedLog] | null>(null);
|
|
1493
|
-
const [crabEntrancePhase, setCrabEntrancePhase] = useState<"hidden" | "playing" | "done">(
|
|
1494
|
-
"hidden",
|
|
1495
|
-
);
|
|
1496
1337
|
const logListRef = useRef<HTMLDivElement>(null);
|
|
1497
1338
|
const logListWrapperRef = useRef<HTMLDivElement>(null);
|
|
1498
1339
|
const importInputRef = useRef<HTMLInputElement>(null);
|
|
@@ -1517,18 +1358,6 @@ export function ProxyViewer({
|
|
|
1517
1358
|
[],
|
|
1518
1359
|
);
|
|
1519
1360
|
|
|
1520
|
-
useEffect(() => {
|
|
1521
|
-
const perCrabDuration = 400;
|
|
1522
|
-
const startDelay = 50;
|
|
1523
|
-
const playingDone = startDelay + crabVariants.length * perCrabDuration;
|
|
1524
|
-
const t1 = setTimeout(() => setCrabEntrancePhase("playing"), startDelay);
|
|
1525
|
-
const t2 = setTimeout(() => setCrabEntrancePhase("done"), playingDone);
|
|
1526
|
-
return () => {
|
|
1527
|
-
clearTimeout(t1);
|
|
1528
|
-
clearTimeout(t2);
|
|
1529
|
-
};
|
|
1530
|
-
}, []);
|
|
1531
|
-
|
|
1532
1361
|
useEffect(() => {
|
|
1533
1362
|
setDetailsPanelCollapsed(readStoredDetailsPanelCollapsed());
|
|
1534
1363
|
setDetailsPanelStorageLoaded(true);
|
|
@@ -1594,6 +1423,24 @@ export function ProxyViewer({
|
|
|
1594
1423
|
},
|
|
1595
1424
|
[logs, onNotify],
|
|
1596
1425
|
);
|
|
1426
|
+
const handleExportRequest = useCallback(
|
|
1427
|
+
(mode: ExportMode) => {
|
|
1428
|
+
if (exportRequiresConfirmation(mode)) {
|
|
1429
|
+
setRawExportDialogOpen(true);
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
void handleExport(mode);
|
|
1433
|
+
},
|
|
1434
|
+
[handleExport],
|
|
1435
|
+
);
|
|
1436
|
+
const handleExportRedactedInstead = useCallback(() => {
|
|
1437
|
+
setRawExportDialogOpen(false);
|
|
1438
|
+
void handleExport("redacted");
|
|
1439
|
+
}, [handleExport]);
|
|
1440
|
+
const handleConfirmRawExport = useCallback(() => {
|
|
1441
|
+
setRawExportDialogOpen(false);
|
|
1442
|
+
void handleExport("raw");
|
|
1443
|
+
}, [handleExport]);
|
|
1597
1444
|
const handleImportClick = useCallback(() => {
|
|
1598
1445
|
importInputRef.current?.click();
|
|
1599
1446
|
}, []);
|
|
@@ -1736,6 +1583,8 @@ export function ProxyViewer({
|
|
|
1736
1583
|
: selectedSession === "__all__"
|
|
1737
1584
|
? "All sessions"
|
|
1738
1585
|
: truncateSessionId(selectedSession);
|
|
1586
|
+
const liveEmptyState = resolveLiveEmptyState(liveConnection);
|
|
1587
|
+
const liveEmptyStateCopy = getLiveEmptyStateCopy(liveEmptyState);
|
|
1739
1588
|
const slateStats = useMemo(
|
|
1740
1589
|
() =>
|
|
1741
1590
|
buildSessionSlateStats({
|
|
@@ -1776,12 +1625,17 @@ export function ProxyViewer({
|
|
|
1776
1625
|
: selectedSession;
|
|
1777
1626
|
|
|
1778
1627
|
return (
|
|
1779
|
-
<div className="bg-background min-h-screen w-full text-foreground lg:h-screen lg:flex lg:flex-col lg:overflow-hidden">
|
|
1628
|
+
<div className="bg-background min-h-screen w-full overflow-x-clip text-foreground lg:h-screen lg:flex lg:flex-col lg:overflow-hidden">
|
|
1629
|
+
<ApplicationBar
|
|
1630
|
+
liveConnection={liveConnection}
|
|
1631
|
+
alertsAction={<AlertsDialog />}
|
|
1632
|
+
settingsAction={<SettingsDialog />}
|
|
1633
|
+
/>
|
|
1780
1634
|
<button
|
|
1781
1635
|
type="button"
|
|
1782
1636
|
onClick={toggleDetailsPanelCollapsed}
|
|
1783
1637
|
className={cn(
|
|
1784
|
-
"group fixed top-1/2 right-3 z-40 inline-flex h-14 w-7 -translate-y-1/2 items-center justify-center rounded-l-md border border-white/[0.08] bg-background/90 text-muted-foreground shadow-[0_12px_34px_rgba(0,0,0,0.26),inset_0_1px_0_rgba(255,255,255,0.06)] backdrop-blur transition-[right,background-color,color,border-color] duration-200 hover:border-white/[0.16] hover:bg-white/[0.07] hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none",
|
|
1638
|
+
"group fixed top-1/2 right-3 z-40 inline-flex h-14 w-7 -translate-y-1/2 items-center justify-center rounded-l-md border border-white/[0.08] bg-background/90 text-muted-foreground shadow-[0_12px_34px_rgba(0,0,0,0.26),inset_0_1px_0_rgba(255,255,255,0.06)] backdrop-blur transition-[right,background-color,color,border-color] duration-200 motion-reduce:transition-none hover:border-white/[0.16] hover:bg-white/[0.07] hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none",
|
|
1785
1639
|
detailsPanelCollapsed
|
|
1786
1640
|
? "right-3"
|
|
1787
1641
|
: "lg:right-[calc(21.25rem-0.875rem)] xl:right-[calc(22.5rem-0.875rem)]",
|
|
@@ -1796,7 +1650,13 @@ export function ProxyViewer({
|
|
|
1796
1650
|
<PanelRightClose className="size-3.5" />
|
|
1797
1651
|
)}
|
|
1798
1652
|
</button>
|
|
1799
|
-
{petVisibilityStorageLoaded && petVisible &&
|
|
1653
|
+
{petVisibilityStorageLoaded && petVisible && (
|
|
1654
|
+
<LazyFeatureBoundary feature="Inspector Pet">
|
|
1655
|
+
<Suspense fallback={null}>
|
|
1656
|
+
<LazyInspectorPet logs={logs} />
|
|
1657
|
+
</Suspense>
|
|
1658
|
+
</LazyFeatureBoundary>
|
|
1659
|
+
)}
|
|
1800
1660
|
<div
|
|
1801
1661
|
className={cn(
|
|
1802
1662
|
"grid w-full min-w-0 grid-cols-1 lg:min-h-0 lg:flex-1 lg:overflow-hidden",
|
|
@@ -1808,15 +1668,18 @@ export function ProxyViewer({
|
|
|
1808
1668
|
{!detailsPanelCollapsed && (
|
|
1809
1669
|
<aside className="bg-background/95 order-1 border-b border-white/[0.045] lg:order-2 lg:h-full lg:overflow-y-auto lg:border-b-0 lg:border-l lg:border-white/[0.055] inspector-scrollbar">
|
|
1810
1670
|
<div className="space-y-4 p-4">
|
|
1811
|
-
<
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1671
|
+
<SidebarPanel label="Tools">
|
|
1672
|
+
<div className="flex flex-wrap items-center gap-1.5">
|
|
1673
|
+
<ThemeModeToggle />
|
|
1674
|
+
<UiScaleControl
|
|
1675
|
+
preference={uiScalePreference}
|
|
1676
|
+
resolvedScale={resolvedUiScale}
|
|
1677
|
+
onChange={setUiScalePreference}
|
|
1678
|
+
/>
|
|
1679
|
+
<GroupsDialog />
|
|
1680
|
+
<AgentLabDialog currentSessionId={labSessionId} logCount={logs.length} />
|
|
1681
|
+
</div>
|
|
1682
|
+
</SidebarPanel>
|
|
1820
1683
|
|
|
1821
1684
|
<SidebarPanel label="Session">
|
|
1822
1685
|
<div className="grid grid-cols-2 gap-2">
|
|
@@ -1891,7 +1754,7 @@ export function ProxyViewer({
|
|
|
1891
1754
|
<button
|
|
1892
1755
|
type="button"
|
|
1893
1756
|
onClick={() => onSessionChange("__all__")}
|
|
1894
|
-
className="absolute right-1.5 top-1/2 inline-flex size-6 -translate-y-1/2 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-white/[0.06] hover:text-foreground"
|
|
1757
|
+
className="absolute right-1.5 top-1/2 inline-flex size-6 -translate-y-1/2 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-white/[0.06] hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none"
|
|
1895
1758
|
aria-label="Clear session filter"
|
|
1896
1759
|
title="Clear session filter"
|
|
1897
1760
|
>
|
|
@@ -1900,7 +1763,10 @@ export function ProxyViewer({
|
|
|
1900
1763
|
)}
|
|
1901
1764
|
</div>
|
|
1902
1765
|
<Select value={sessionSelectValue} onValueChange={handleSessionSelectChange}>
|
|
1903
|
-
<SelectTrigger
|
|
1766
|
+
<SelectTrigger
|
|
1767
|
+
aria-label="Select a session"
|
|
1768
|
+
className="bg-black/25 hover:bg-white/[0.045] h-9 w-full border-0 text-xs text-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)]"
|
|
1769
|
+
>
|
|
1904
1770
|
<SelectValue placeholder="All sessions" />
|
|
1905
1771
|
</SelectTrigger>
|
|
1906
1772
|
<SelectContent>
|
|
@@ -1920,7 +1786,10 @@ export function ProxyViewer({
|
|
|
1920
1786
|
</>
|
|
1921
1787
|
)}
|
|
1922
1788
|
<Select value={selectedModel} onValueChange={onModelChange}>
|
|
1923
|
-
<SelectTrigger
|
|
1789
|
+
<SelectTrigger
|
|
1790
|
+
aria-label="Select a model"
|
|
1791
|
+
className="bg-black/25 hover:bg-white/[0.045] h-9 w-full border-0 text-xs text-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)]"
|
|
1792
|
+
>
|
|
1924
1793
|
<SelectValue placeholder="All models" />
|
|
1925
1794
|
</SelectTrigger>
|
|
1926
1795
|
<SelectContent>
|
|
@@ -1961,7 +1830,7 @@ export function ProxyViewer({
|
|
|
1961
1830
|
type="button"
|
|
1962
1831
|
onClick={handleImportClick}
|
|
1963
1832
|
disabled={importing}
|
|
1964
|
-
className="bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
|
1833
|
+
className="bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
1965
1834
|
title="Import Agent Inspector export"
|
|
1966
1835
|
>
|
|
1967
1836
|
{importing ? (
|
|
@@ -1979,10 +1848,10 @@ export function ProxyViewer({
|
|
|
1979
1848
|
<button
|
|
1980
1849
|
type="button"
|
|
1981
1850
|
onClick={() => {
|
|
1982
|
-
|
|
1851
|
+
handleExportRequest("redacted");
|
|
1983
1852
|
}}
|
|
1984
1853
|
disabled={exporting !== null}
|
|
1985
|
-
className="bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
|
1854
|
+
className="bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
1986
1855
|
title="Export redacted logs as JSON ZIP"
|
|
1987
1856
|
>
|
|
1988
1857
|
{exporting === "redacted" ? (
|
|
@@ -1999,10 +1868,10 @@ export function ProxyViewer({
|
|
|
1999
1868
|
<button
|
|
2000
1869
|
type="button"
|
|
2001
1870
|
onClick={() => {
|
|
2002
|
-
|
|
1871
|
+
handleExportRequest("raw");
|
|
2003
1872
|
}}
|
|
2004
1873
|
disabled={exporting !== null}
|
|
2005
|
-
className="bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
|
1874
|
+
className="bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
2006
1875
|
title="Export raw logs without redaction"
|
|
2007
1876
|
>
|
|
2008
1877
|
{exporting === "raw" ? (
|
|
@@ -2020,10 +1889,15 @@ export function ProxyViewer({
|
|
|
2020
1889
|
type="button"
|
|
2021
1890
|
onClick={handleReloadCurrentSession}
|
|
2022
1891
|
disabled={isLoading}
|
|
2023
|
-
className="bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
|
1892
|
+
className="bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
2024
1893
|
title="Reload this session from stored logs"
|
|
2025
1894
|
>
|
|
2026
|
-
<RefreshCw
|
|
1895
|
+
<RefreshCw
|
|
1896
|
+
className={cn(
|
|
1897
|
+
"size-3.5",
|
|
1898
|
+
isLoading && "animate-spin motion-reduce:animate-none",
|
|
1899
|
+
)}
|
|
1900
|
+
/>
|
|
2027
1901
|
<span>{reloadSessionLabel}</span>
|
|
2028
1902
|
</button>
|
|
2029
1903
|
)}
|
|
@@ -2031,7 +1905,7 @@ export function ProxyViewer({
|
|
|
2031
1905
|
type="button"
|
|
2032
1906
|
onClick={handleClearCurrentView}
|
|
2033
1907
|
disabled={!canClearCurrentView}
|
|
2034
|
-
className="bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
|
1908
|
+
className="bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
2035
1909
|
title="Clear the current view. Stored logs remain reloadable."
|
|
2036
1910
|
>
|
|
2037
1911
|
<Trash2 className="size-3.5" />
|
|
@@ -2042,7 +1916,7 @@ export function ProxyViewer({
|
|
|
2042
1916
|
type="button"
|
|
2043
1917
|
onClick={handleRequestDeleteCurrentView}
|
|
2044
1918
|
disabled={!canDeleteCurrentView || deletingCurrentView}
|
|
2045
|
-
className="bg-red-500/[0.07] hover:bg-red-500/[0.12] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-red-200 shadow-[inset_0_0_0_1px_rgba(248,113,113,0.14)] transition-colors hover:text-red-100 disabled:cursor-not-allowed disabled:opacity-50"
|
|
1919
|
+
className="bg-red-500/[0.07] hover:bg-red-500/[0.12] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-red-200 shadow-[inset_0_0_0_1px_rgba(248,113,113,0.14)] transition-colors hover:text-red-100 focus-visible:ring-1 focus-visible:ring-red-300 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
2046
1920
|
title="Delete persisted history for the selected session."
|
|
2047
1921
|
>
|
|
2048
1922
|
<Trash2 className="size-3.5" />
|
|
@@ -2055,6 +1929,26 @@ export function ProxyViewer({
|
|
|
2055
1929
|
<SessionLoadProgressBar progress={sessionLoadProgress} />
|
|
2056
1930
|
</div>
|
|
2057
1931
|
)}
|
|
1932
|
+
{sessionLoadError !== undefined && (
|
|
1933
|
+
<div
|
|
1934
|
+
role="alert"
|
|
1935
|
+
className="mt-2 flex flex-wrap items-center gap-2 rounded-md border border-red-400/25 bg-red-500/10 px-3 py-2 text-xs text-red-100"
|
|
1936
|
+
>
|
|
1937
|
+
<span className="min-w-0 flex-1">
|
|
1938
|
+
Session logs could not be loaded. {sessionLoadError} Existing logs remain visible.
|
|
1939
|
+
</span>
|
|
1940
|
+
{onReloadSession !== undefined && (
|
|
1941
|
+
<button
|
|
1942
|
+
type="button"
|
|
1943
|
+
onClick={handleReloadCurrentSession}
|
|
1944
|
+
className="inline-flex h-7 items-center gap-1 rounded-md bg-black/15 px-2 font-medium transition-colors hover:bg-black/25 focus-visible:ring-1 focus-visible:ring-current focus-visible:outline-none"
|
|
1945
|
+
>
|
|
1946
|
+
<RefreshCw className="size-3" />
|
|
1947
|
+
Retry
|
|
1948
|
+
</button>
|
|
1949
|
+
)}
|
|
1950
|
+
</div>
|
|
1951
|
+
)}
|
|
2058
1952
|
<LogPaginationBar logs={logs} pagination={pagination} embedded={true} />
|
|
2059
1953
|
{onNotify === undefined && exportError !== null && (
|
|
2060
1954
|
<div className="mt-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive">
|
|
@@ -2071,6 +1965,17 @@ export function ProxyViewer({
|
|
|
2071
1965
|
{importStatus}
|
|
2072
1966
|
</div>
|
|
2073
1967
|
)}
|
|
1968
|
+
{liveConnection !== undefined &&
|
|
1969
|
+
liveConnection.status !== "live" &&
|
|
1970
|
+
onRetryLiveConnection !== undefined &&
|
|
1971
|
+
onStopLiveConnection !== undefined && (
|
|
1972
|
+
<LiveConnectionStatus
|
|
1973
|
+
state={liveConnection}
|
|
1974
|
+
hasLogs={logs.length > 0}
|
|
1975
|
+
onRetry={onRetryLiveConnection}
|
|
1976
|
+
onStop={onStopLiveConnection}
|
|
1977
|
+
/>
|
|
1978
|
+
)}
|
|
2074
1979
|
</div>
|
|
2075
1980
|
|
|
2076
1981
|
<div className="px-4 py-4 lg:px-5">
|
|
@@ -2080,7 +1985,11 @@ export function ProxyViewer({
|
|
|
2080
1985
|
<div className="py-16 text-center text-muted-foreground">
|
|
2081
1986
|
<div className="bg-white/[0.035] shadow-[inset_0_1px_0_rgba(255,255,255,0.045),0_18px_52px_rgba(0,0,0,0.18)] mx-auto max-w-xl space-y-4 rounded-[8px] px-4 py-8">
|
|
2082
1987
|
<p className="text-sm font-medium">
|
|
2083
|
-
{isLoading
|
|
1988
|
+
{isLoading
|
|
1989
|
+
? "Loading session data..."
|
|
1990
|
+
: sessionLoadError === undefined
|
|
1991
|
+
? "No logs loaded for this session"
|
|
1992
|
+
: "Session logs could not be loaded"}
|
|
2084
1993
|
</p>
|
|
2085
1994
|
<p className="inline-block max-w-full rounded bg-muted px-3 py-1 font-mono text-xs break-all">
|
|
2086
1995
|
{truncateSessionId(selectedSession)}
|
|
@@ -2103,7 +2012,7 @@ export function ProxyViewer({
|
|
|
2103
2012
|
<button
|
|
2104
2013
|
type="button"
|
|
2105
2014
|
onClick={handleReloadCurrentSession}
|
|
2106
|
-
className="bg-white/[0.045] hover:bg-white/[0.075] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground"
|
|
2015
|
+
className="bg-white/[0.045] hover:bg-white/[0.075] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none"
|
|
2107
2016
|
>
|
|
2108
2017
|
<RefreshCw className="size-3.5" />
|
|
2109
2018
|
<span>Load session</span>
|
|
@@ -2112,7 +2021,7 @@ export function ProxyViewer({
|
|
|
2112
2021
|
{hideSessionFilter ? (
|
|
2113
2022
|
<a
|
|
2114
2023
|
href="/"
|
|
2115
|
-
className="inline-flex h-8 items-center rounded-md px-3 text-xs text-muted-foreground underline transition-colors hover:text-foreground"
|
|
2024
|
+
className="inline-flex h-8 items-center rounded-md px-3 text-xs text-muted-foreground underline transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none"
|
|
2116
2025
|
>
|
|
2117
2026
|
Back to all sessions
|
|
2118
2027
|
</a>
|
|
@@ -2120,7 +2029,7 @@ export function ProxyViewer({
|
|
|
2120
2029
|
<button
|
|
2121
2030
|
type="button"
|
|
2122
2031
|
onClick={() => onSessionChange("__all__")}
|
|
2123
|
-
className="inline-flex h-8 items-center rounded-md px-3 text-xs text-muted-foreground underline transition-colors hover:text-foreground"
|
|
2032
|
+
className="inline-flex h-8 items-center rounded-md px-3 text-xs text-muted-foreground underline transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none"
|
|
2124
2033
|
>
|
|
2125
2034
|
Show all sessions
|
|
2126
2035
|
</button>
|
|
@@ -2133,21 +2042,28 @@ export function ProxyViewer({
|
|
|
2133
2042
|
) : (
|
|
2134
2043
|
<div className="py-16 text-center text-muted-foreground">
|
|
2135
2044
|
<div className="bg-white/[0.035] shadow-[inset_0_1px_0_rgba(255,255,255,0.045),0_18px_52px_rgba(0,0,0,0.18)] mx-auto max-w-2xl space-y-4 rounded-[8px] px-4 py-8">
|
|
2136
|
-
<p className="text-sm">
|
|
2137
|
-
|
|
2045
|
+
<p className="text-sm font-medium">{liveEmptyStateCopy.title}</p>
|
|
2046
|
+
<p className="mx-auto max-w-xl text-xs leading-relaxed text-muted-foreground">
|
|
2047
|
+
{liveEmptyStateCopy.description}
|
|
2048
|
+
</p>
|
|
2049
|
+
{liveEmptyState === "empty" && sessions.length > 0 && (
|
|
2138
2050
|
<p className="mx-auto max-w-xl text-xs leading-relaxed text-muted-foreground">
|
|
2139
2051
|
Pick a session from the filter panel to load stored logs on demand.
|
|
2140
2052
|
</p>
|
|
2141
2053
|
)}
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2054
|
+
{liveEmptyStateCopy.showConnectionCommands && (
|
|
2055
|
+
<>
|
|
2056
|
+
<div className="flex flex-col items-center gap-2">
|
|
2057
|
+
<CopyableCommand command="ANTHROPIC_BASE_URL=http://localhost:9527/proxy <your-tool>" />
|
|
2058
|
+
<CopyableCommand command="OPENAI_BASE_URL=http://localhost:9527/proxy <your-tool>" />
|
|
2059
|
+
</div>
|
|
2060
|
+
<p className="mx-auto max-w-xl text-xs leading-relaxed text-muted-foreground">
|
|
2061
|
+
Container note: if your AI tool runs in a different container or host than
|
|
2062
|
+
Agent Inspector, replace localhost with an address reachable from that
|
|
2063
|
+
tool and verify the network/firewall path.
|
|
2064
|
+
</p>
|
|
2065
|
+
</>
|
|
2066
|
+
)}
|
|
2151
2067
|
</div>
|
|
2152
2068
|
</div>
|
|
2153
2069
|
)
|
|
@@ -2155,7 +2071,8 @@ export function ProxyViewer({
|
|
|
2155
2071
|
<div
|
|
2156
2072
|
ref={logListWrapperRef}
|
|
2157
2073
|
tabIndex={0}
|
|
2158
|
-
|
|
2074
|
+
aria-label="Captured logs"
|
|
2075
|
+
className="flex flex-col gap-2 rounded-md focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none"
|
|
2159
2076
|
>
|
|
2160
2077
|
<div ref={logListRef}>
|
|
2161
2078
|
<ConversationGroupList
|
|
@@ -2180,6 +2097,16 @@ export function ProxyViewer({
|
|
|
2180
2097
|
</main>
|
|
2181
2098
|
</div>
|
|
2182
2099
|
|
|
2100
|
+
<Dialog open={rawExportDialogOpen} onOpenChange={setRawExportDialogOpen}>
|
|
2101
|
+
<DialogContent className={RAW_EXPORT_DIALOG_CLASS_NAME}>
|
|
2102
|
+
<RawExportWarning
|
|
2103
|
+
onCancel={() => setRawExportDialogOpen(false)}
|
|
2104
|
+
onExportRedacted={handleExportRedactedInstead}
|
|
2105
|
+
onConfirmRaw={handleConfirmRawExport}
|
|
2106
|
+
/>
|
|
2107
|
+
</DialogContent>
|
|
2108
|
+
</Dialog>
|
|
2109
|
+
|
|
2183
2110
|
<Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
|
|
2184
2111
|
<DialogContent className="border-red-500/20 bg-zinc-950 text-zinc-100 sm:max-w-md">
|
|
2185
2112
|
<DialogHeader>
|
|
@@ -2217,15 +2144,17 @@ export function ProxyViewer({
|
|
|
2217
2144
|
|
|
2218
2145
|
{/* Compare drawer: sibling of the log list, not a route change. */}
|
|
2219
2146
|
{comparePair !== null && (
|
|
2220
|
-
<
|
|
2221
|
-
<
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2147
|
+
<LazyFeatureBoundary feature="Compare">
|
|
2148
|
+
<Suspense fallback={null}>
|
|
2149
|
+
<LazyCompareDrawer
|
|
2150
|
+
left={comparePair[0]}
|
|
2151
|
+
right={comparePair[1]}
|
|
2152
|
+
leftDisplayNumber={displayNumberForLog(comparePair[0], displayNumberByLogId)}
|
|
2153
|
+
rightDisplayNumber={displayNumberForLog(comparePair[1], displayNumberByLogId)}
|
|
2154
|
+
onClose={closeCompare}
|
|
2155
|
+
/>
|
|
2156
|
+
</Suspense>
|
|
2157
|
+
</LazyFeatureBoundary>
|
|
2229
2158
|
)}
|
|
2230
2159
|
</div>
|
|
2231
2160
|
);
|