@tonyclaw/agent-inspector 3.0.7 → 3.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/cli.js +245 -171
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-C0Kbsm-Q.js → CompareDrawer-CJKL4LMm.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-DBUy29O-.js +106 -0
- package/.output/public/assets/ReplayDialog-BYanl-a_.js +1 -0
- package/.output/public/assets/{RequestAnatomy-fa0JXy5p.js → RequestAnatomy-DvPz1jqE.js} +1 -1
- package/.output/public/assets/ResponseView-sZnxp9GN.js +3 -0
- package/.output/public/assets/StreamingChunkSequence-G-tiYiBd.js +1 -0
- package/.output/public/assets/{_sessionId-D5fYH2C0.js → _sessionId-_hDcsmXq.js} +1 -1
- package/.output/public/assets/agent-inspector-58K1_MsC.ico +0 -0
- package/.output/public/assets/index-DAPAWsAd.js +1 -0
- package/.output/public/assets/index-DspnLqUW.css +1 -0
- package/.output/public/assets/{index-BEsqvywM.js → index-SuOSQb2_.js} +1 -1
- package/.output/public/assets/{json-viewer-B0QRbMSf.js → json-viewer-yQdhgjaw.js} +1 -1
- package/.output/public/assets/{main-CuKZD7n0.js → main-CgjcDxjR.js} +2 -2
- package/.output/server/_libs/radix-ui__react-dialog.mjs +2 -2
- package/.output/server/{_sessionId-DdBTK3qm.mjs → _sessionId-BGISf2En.mjs} +3 -3
- package/.output/server/_ssr/{CompareDrawer-m82cVZ73.mjs → CompareDrawer-s-UF9gW3.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-7geuf78f.mjs → ProxyViewerContainer-C0Sbz9ED.mjs} +1033 -530
- package/.output/server/_ssr/{ReplayDialog-B8RlWLLH.mjs → ReplayDialog-DvS8gvJr.mjs} +58 -23
- package/.output/server/_ssr/{RequestAnatomy-BE7pmwpv.mjs → RequestAnatomy-BwhWglJL.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-D-sDsdQr.mjs → ResponseView-wBVreqQf.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-DU_hThJr.mjs → StreamingChunkSequence-Dr6eg-MJ.mjs} +30 -20
- package/.output/server/_ssr/{index-D0sV8UbE.mjs → index-B98Wia1X.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-CaDh1zrw.mjs → json-viewer-D7L8y0FH.mjs} +2 -2
- package/.output/server/_ssr/{router-Zh2iZ_u0.mjs → router-g9mo0nWT.mjs} +459 -196
- package/.output/server/_tanstack-start-manifest_v-CbGc-o50.mjs +4 -0
- package/.output/server/index.mjs +76 -69
- package/package.json +1 -1
- package/src/assets/IDE/opencode.svg +1 -1
- package/src/assets/IDE/xiaomimimo.svg +1 -1
- package/src/cli/detect-tools.ts +2 -27
- package/src/cli/templates/codex-skill-onboard.ts +1 -1
- package/src/cli/templates/skill-onboard.ts +2 -3
- package/src/cli.ts +9 -86
- package/src/components/ProxyViewer.tsx +249 -37
- package/src/components/ProxyViewerContainer.tsx +167 -22
- package/src/components/clients/ClientLogo.tsx +38 -3
- package/src/components/ecosystem/AgentLabDialog.tsx +204 -3
- package/src/components/groups/GroupsDialog.tsx +28 -40
- package/src/components/providers/ImportWizardDialog.tsx +51 -101
- package/src/components/providers/ProvidersPanel.tsx +82 -68
- package/src/components/providers/SettingsDialog.tsx +11 -12
- package/src/components/proxy-viewer/AgentTraceSummary.tsx +15 -23
- package/src/components/proxy-viewer/ReplayDialog.tsx +65 -22
- package/src/components/proxy-viewer/StreamingChunkSequence.tsx +33 -20
- package/src/components/proxy-viewer/TurnGroup.tsx +0 -16
- package/src/components/proxy-viewer/log-formats/anthropic.ts +5 -5
- package/src/components/proxy-viewer/log-formats/openai.ts +7 -10
- package/src/components/proxy-viewer/requestTools.ts +5 -2
- package/src/lib/apiClient.ts +43 -10
- package/src/lib/ecosystemContract.ts +32 -0
- package/src/lib/export-logs.ts +37 -3
- package/src/proxy/ecosystemRegistry.ts +244 -0
- package/src/proxy/ecosystemTasks.ts +153 -0
- package/src/proxy/platformCommands.ts +212 -0
- package/src/proxy/socketTracker.ts +84 -143
- package/src/routes/api/ecosystem.packages.$packageId.help.ts +16 -0
- package/src/routes/api/ecosystem.packages.$packageId.install.ts +16 -0
- package/src/routes/api/ecosystem.packages.$packageId.runner-presets.ts +19 -0
- package/src/routes/api/ecosystem.packages.$packageId.upgrade.ts +16 -0
- package/src/routes/api/ecosystem.packages.ts +1 -248
- package/src/routes/api/ecosystem.tasks.$taskId.ts +16 -0
- package/src/routes/api/ecosystem.tasks.ts +12 -0
- package/src/routes/api/providers.$providerId.test.log.ts +28 -24
- package/.output/public/assets/ProxyViewerContainer-p-rpYyiF.js +0 -106
- package/.output/public/assets/ReplayDialog-CM3dhP8v.js +0 -1
- package/.output/public/assets/ResponseView-Bq6sC7Ay.js +0 -3
- package/.output/public/assets/StreamingChunkSequence-CGOun3Df.js +0 -1
- package/.output/public/assets/index-C29Olfzt.js +0 -1
- package/.output/public/assets/index-DgANE0r3.css +0 -1
- package/.output/server/_tanstack-start-manifest_v-LCE-2AaF.mjs +0 -4
package/.output/server/_ssr/{ProxyViewerContainer-7geuf78f.mjs → ProxyViewerContainer-C0Sbz9ED.mjs}
RENAMED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
|
|
2
|
-
import {
|
|
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, d as RuntimeConfigSchema, p as packageJson, P as ProviderConfigSchema, i as apiFormatForPath, n as DeleteInspectorGroupsResponseSchema, o as GroupEvidenceExportResultSchema, q as DeleteInspectorGroupResponseSchema, l as AlertSummarySchema, m as AlertListResponseSchema, I as InspectorGroupsListResponseSchema, G as GroupEvidenceReadResponseSchema, z as createPendingProviderTestResults, B as ProviderTestResultsSchema, E as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, F as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, t as maskApiKey, u as PATH_V1_MESSAGES, v as PATH_V1_CHAT_COMPLETIONS, w as PATH_V1_RESPONSES, r as providerHasContextMetadata, f as parseOpenAIResponse, g as parseOpenAIResponsesResponse, O as OpenAIRequestSchema, h as OpenAIResponsesRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, H as resolveProviderContextWindow, j as getSessionPath, x as findProviderModelMetadata, y as previewUpstreamUrl, K as KnowledgeCandidateSchema, J as isPlainRecord, k as stripClaudeCodeBillingHeader, L as LogBodyChunkSchema } from "./router-g9mo0nWT.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";
|
|
6
6
|
import { t as twMerge } from "../_libs/tailwind-merge.mjs";
|
|
7
|
-
import { R as Root,
|
|
7
|
+
import { R as Root, C as Content, a as Close, T as Title, D as Description, P as Portal$1, O as Overlay, b as Trigger$1 } from "../_libs/radix-ui__react-dialog.mjs";
|
|
8
8
|
import { c as cva } from "../_libs/class-variance-authority.mjs";
|
|
9
9
|
import { u as useWindowVirtualizer, a as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
|
|
10
10
|
import { d as diffJson, a as diffLines } from "../_libs/diff.mjs";
|
|
11
11
|
import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Content2, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
|
|
12
12
|
import { T as TriangleAlert, C as CircleCheck, X, I as Info, a as ChevronDown, b as Check, R as RefreshCw, c as Trash2, S as Search, U as Upload, D as Download, F as FileBraces, P as Plus, A as ArrowLeft, d as ChevronUp, e as Copy, f as ChevronsLeft, g as ChevronLeft, h as ChevronRight, i as ChevronsRight, j as Clapperboard, k as Flag, l as Siren, m as Timer, G as Gauge, L as LoaderCircle, n as Layers, o as FlaskConical, p as Sparkles, q as Activity, B as Beaker, N as Network, r as Terminal, s as Settings, M as Monitor, t as Rocket, u as PackageCheck, v as Scan, w as CircleAlert, x as ArrowUpRight, y as ArrowDownRight, z as Cpu, E as FolderOpen, H as Bell, J as Clock3, K as ShieldAlert, O as EyeOff, Q as Eye, V as ExternalLink, W as Clock, Y as RotateCw, Z as Pencil, _ as MessageSquare, $ as Zap, a0 as Wrench, a1 as Brain, a2 as Minus, a3 as CircleCheckBig, a4 as CircleQuestionMark, a5 as Server, a6 as Lock, a7 as Wifi, a8 as WifiOff, a9 as CircleX, aa as ShieldCheck, ab as Save, ac as FileSearch, ad as CloudUpload, ae as OctagonAlert, af as Radio, ag as Globe, ah as FileTerminal, ai as ChevronsUp, aj as ChevronsDown, ak as FileDiff, al as History, am as RotateCcw, an as GitCompareArrows, ao as ArrowUp, ap as ArrowDown, aq as Ellipsis, ar as CodeXml, as as Blocks, at as MousePointerClick, au as FileText, av as Rows3, aw as Columns2 } from "../_libs/lucide-react.mjs";
|
|
13
|
-
import { u as union, d as object, a as array, l as literal,
|
|
13
|
+
import { u as union, d as object, a as array, l as literal, n as number, c as boolean, b as string, _ as _enum } from "../_libs/zod.mjs";
|
|
14
14
|
import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
|
|
15
15
|
import { R as Root2$1, L as List, T as Trigger$2, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
|
|
16
|
-
import { P as Provider, R as Root3, T as Trigger$3, a as Portal$
|
|
16
|
+
import { P as Provider, R as Root3, T as Trigger$3, a as Portal$2, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
|
|
17
17
|
import { R as Root$1, C as CollapsibleContent$1, a as CollapsibleTrigger$1 } from "../_libs/radix-ui__react-collapsible.mjs";
|
|
18
18
|
import { R as Root$2, V as Viewport$1, C as Corner, S as ScrollAreaScrollbar, a as ScrollAreaThumb } from "../_libs/radix-ui__react-scroll-area.mjs";
|
|
19
19
|
const ApiErrorSchema = object({
|
|
@@ -50,19 +50,41 @@ class ApiTimeoutError extends Error {
|
|
|
50
50
|
this.name = "ApiTimeoutError";
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
async function
|
|
53
|
+
async function fetchWithTimeout(input, timeoutMs, init) {
|
|
54
54
|
const controller = new AbortController();
|
|
55
|
-
|
|
55
|
+
let timedOut = false;
|
|
56
|
+
const timeout = setTimeout(() => {
|
|
57
|
+
timedOut = true;
|
|
58
|
+
controller.abort();
|
|
59
|
+
}, timeoutMs);
|
|
60
|
+
const callerSignal = init?.signal ?? void 0;
|
|
61
|
+
const abortFromCaller = () => controller.abort();
|
|
62
|
+
if (callerSignal !== void 0) {
|
|
63
|
+
if (callerSignal.aborted) {
|
|
64
|
+
controller.abort();
|
|
65
|
+
} else {
|
|
66
|
+
callerSignal.addEventListener("abort", abortFromCaller, { once: true });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
56
69
|
try {
|
|
57
|
-
return await
|
|
70
|
+
return await fetch(input, { ...init, signal: controller.signal });
|
|
58
71
|
} catch (error) {
|
|
59
|
-
if (error instanceof DOMException && error.name === "AbortError") {
|
|
72
|
+
if (timedOut && error instanceof DOMException && error.name === "AbortError") {
|
|
60
73
|
throw new ApiTimeoutError(timeoutMs);
|
|
61
74
|
}
|
|
62
75
|
throw error;
|
|
63
76
|
} finally {
|
|
64
77
|
clearTimeout(timeout);
|
|
78
|
+
callerSignal?.removeEventListener("abort", abortFromCaller);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async function fetchJsonWithTimeout(input, schema, timeoutMs, init, errorFallback) {
|
|
82
|
+
const response = await fetchWithTimeout(input, timeoutMs, init);
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
const fallback = errorFallback?.(response) ?? `Request failed with status ${response.status}`;
|
|
85
|
+
throw new Error(await readApiError(response, fallback));
|
|
65
86
|
}
|
|
87
|
+
return parseJsonResponse$1(response, schema);
|
|
66
88
|
}
|
|
67
89
|
const ImportLogsResponseSchema = object({
|
|
68
90
|
sessionId: string(),
|
|
@@ -321,6 +343,7 @@ const SECRET_TEXT_PATTERNS = [
|
|
|
321
343
|
const MAX_EXPORT_LOGS = 200;
|
|
322
344
|
const MAX_EXPORT_TEXT_CHARS = 25e6;
|
|
323
345
|
const MAX_STREAMING_CHUNK_EXPORTS = 50;
|
|
346
|
+
const STREAMING_CHUNK_EXPORT_TIMEOUT_MS = 1e4;
|
|
324
347
|
function formatApproxSize(chars) {
|
|
325
348
|
if (chars < 1024) return `${chars} chars`;
|
|
326
349
|
if (chars < 1024 * 1024) return `${Math.ceil(chars / 1024)} KB`;
|
|
@@ -346,9 +369,19 @@ function exportLimitMessage(logs) {
|
|
|
346
369
|
}
|
|
347
370
|
return null;
|
|
348
371
|
}
|
|
349
|
-
|
|
372
|
+
function exportCanceled(signal) {
|
|
373
|
+
if (signal?.aborted === true) {
|
|
374
|
+
return { ok: false, message: "Export canceled.", canceled: true };
|
|
375
|
+
}
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
async function fetchStreamingChunks(logId, signal) {
|
|
350
379
|
try {
|
|
351
|
-
const response = await
|
|
380
|
+
const response = await fetchWithTimeout(
|
|
381
|
+
`/api/logs/${logId}/chunks`,
|
|
382
|
+
STREAMING_CHUNK_EXPORT_TIMEOUT_MS,
|
|
383
|
+
{ signal }
|
|
384
|
+
);
|
|
352
385
|
if (!response.ok) return null;
|
|
353
386
|
const data = await response.json();
|
|
354
387
|
return JSON.stringify(data, null, 2);
|
|
@@ -409,7 +442,9 @@ function buildExportManifest(logs, mode, streamingLogs, exportedAt = (/* @__PURE
|
|
|
409
442
|
streamingChunkLogIds: streamingLogs.map((log) => log.id)
|
|
410
443
|
};
|
|
411
444
|
}
|
|
412
|
-
async function exportLogsAsZip(logs, mode = "redacted") {
|
|
445
|
+
async function exportLogsAsZip(logs, mode = "redacted", options = {}) {
|
|
446
|
+
const initialCancel = exportCanceled(options.signal);
|
|
447
|
+
if (initialCancel !== null) return initialCancel;
|
|
413
448
|
const limitMessage = exportLimitMessage(logs);
|
|
414
449
|
if (limitMessage !== null) return { ok: false, message: limitMessage };
|
|
415
450
|
const zip = new JSZip();
|
|
@@ -428,6 +463,8 @@ async function exportLogsAsZip(logs, mode = "redacted") {
|
|
|
428
463
|
)
|
|
429
464
|
);
|
|
430
465
|
for (const log of logs) {
|
|
466
|
+
const canceled2 = exportCanceled(options.signal);
|
|
467
|
+
if (canceled2 !== null) return canceled2;
|
|
431
468
|
if (log.rawRequestBody !== null) {
|
|
432
469
|
zip.file(`#${log.id}.Request.json`, exportText(log.rawRequestBody, mode));
|
|
433
470
|
}
|
|
@@ -436,12 +473,16 @@ async function exportLogsAsZip(logs, mode = "redacted") {
|
|
|
436
473
|
}
|
|
437
474
|
}
|
|
438
475
|
for (const log of streamingLogs) {
|
|
439
|
-
const
|
|
476
|
+
const canceled2 = exportCanceled(options.signal);
|
|
477
|
+
if (canceled2 !== null) return canceled2;
|
|
478
|
+
const chunks = await fetchStreamingChunks(log.id, options.signal);
|
|
440
479
|
if (chunks !== null) {
|
|
441
480
|
zip.file(`#${log.id}.SSE.Response.json`, exportText(chunks, mode));
|
|
442
481
|
}
|
|
443
482
|
}
|
|
444
483
|
const blob = await zip.generateAsync({ type: "blob" });
|
|
484
|
+
const canceled = exportCanceled(options.signal);
|
|
485
|
+
if (canceled !== null) return canceled;
|
|
445
486
|
const url = URL.createObjectURL(blob);
|
|
446
487
|
const anchor = document.createElement("a");
|
|
447
488
|
anchor.href = url;
|
|
@@ -697,7 +738,7 @@ function DialogTrigger({
|
|
|
697
738
|
function DialogPortal({
|
|
698
739
|
...props
|
|
699
740
|
}) {
|
|
700
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$
|
|
741
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$1, { "data-slot": "dialog-portal", ...props });
|
|
701
742
|
}
|
|
702
743
|
function DialogOverlay({
|
|
703
744
|
className,
|
|
@@ -849,9 +890,11 @@ function ConfirmDialog({
|
|
|
849
890
|
}
|
|
850
891
|
const ClaudeCodeLogoSvg = "data:image/svg+xml,%3csvg%20height='1em'%20style='flex:none;line-height:1'%20viewBox='0%200%2024%2024'%20width='1em'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eClaude%20Code%3c/title%3e%3cpath%20clip-rule='evenodd'%20d='M20.998%2010.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6%2010.949h1.488V8.102H6v2.847zm10.51%200H18V8.102h-1.49v2.847z'%20fill='%23D97757'%20fill-rule='evenodd'%3e%3c/path%3e%3c/svg%3e";
|
|
851
892
|
const CodexLogoSvg = "data:image/svg+xml,%3csvg%20height='1em'%20style='flex:none;line-height:1'%20viewBox='0%200%2024%2024'%20width='1em'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eCodex%3c/title%3e%3cpath%20d='M19.503%200H4.496A4.496%204.496%200%20000%204.496v15.007A4.496%204.496%200%20004.496%2024h15.007A4.496%204.496%200%200024%2019.503V4.496A4.496%204.496%200%200019.503%200z'%20fill='%23fff'%3e%3c/path%3e%3cpath%20d='M9.064%203.344a4.578%204.578%200%20012.285-.312c1%20.115%201.891.54%202.673%201.275.01.01.024.017.037.021a.09.09%200%2000.043%200%204.55%204.55%200%20013.046.275l.047.022.116.057a4.581%204.581%200%20012.188%202.399c.209.51.313%201.041.315%201.595a4.24%204.24%200%2001-.134%201.223.123.123%200%2000.03.115c.594.607.988%201.33%201.183%202.17.289%201.425-.007%202.71-.887%203.854l-.136.166a4.548%204.548%200%2001-2.201%201.388.123.123%200%2000-.081.076c-.191.551-.383%201.023-.74%201.494-.9%201.187-2.222%201.846-3.711%201.838-1.187-.006-2.239-.44-3.157-1.302a.107.107%200%2000-.105-.024c-.388.125-.78.143-1.204.138a4.441%204.441%200%2001-1.945-.466%204.544%204.544%200%2001-1.61-1.335c-.152-.202-.303-.392-.414-.617a5.81%205.81%200%2001-.37-.961%204.582%204.582%200%2001-.014-2.298.124.124%200%2000.006-.056.085.085%200%2000-.027-.048%204.467%204.467%200%2001-1.034-1.651%203.896%203.896%200%2001-.251-1.192%205.189%205.189%200%2001.141-1.6c.337-1.112.982-1.985%201.933-2.618.212-.141.413-.251.601-.33.215-.089.43-.164.646-.227a.098.098%200%2000.065-.066%204.51%204.51%200%2001.829-1.615%204.535%204.535%200%20011.837-1.388zm3.482%2010.565a.637.637%200%20000%201.272h3.636a.637.637%200%20100-1.272h-3.636zM8.462%209.23a.637.637%200%2000-1.106.631l1.272%202.224-1.266%202.136a.636.636%200%20101.095.649l1.454-2.455a.636.636%200%2000.005-.64L8.462%209.23z'%20fill='url(%23lobe-icons-codex-_R_0_)'%3e%3c/path%3e%3cdefs%3e%3clinearGradient%20gradientUnits='userSpaceOnUse'%20id='lobe-icons-codex-_R_0_'%20x1='12'%20x2='12'%20y1='3'%20y2='21'%3e%3cstop%20stop-color='%23B1A7FF'%3e%3c/stop%3e%3cstop%20offset='.5'%20stop-color='%237A9DFF'%3e%3c/stop%3e%3cstop%20offset='1'%20stop-color='%233941FF'%3e%3c/stop%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e";
|
|
852
|
-
const OpenCodeLogoSvg = "data:image/svg+xml,%3csvg%20fill='
|
|
853
|
-
const MiMoCodeLogoSvg = "data:image/svg+xml,%3csvg%20fill='
|
|
893
|
+
const OpenCodeLogoSvg = "data:image/svg+xml,%3csvg%20fill='%237dd3fc'%20fill-rule='evenodd'%20height='1em'%20style='flex:none;line-height:1'%20viewBox='0%200%2024%2024'%20width='1em'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eOpenCode%3c/title%3e%3cpath%20d='M16%206H8v12h8V6zm4%2016H4V2h16v20z'%3e%3c/path%3e%3c/svg%3e";
|
|
894
|
+
const MiMoCodeLogoSvg = "data:image/svg+xml,%3csvg%20fill='%23ff6900'%20fill-rule='evenodd'%20height='1em'%20style='flex:none;line-height:1'%20viewBox='0%200%2024%2024'%20width='1em'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eMiMo%20Code%3c/title%3e%3cpath%20d='M.958%2015.936a.459.459%200%2001.459.44v2.729a.46.46%200%2001-.918%200v-2.729a.459.459%200%2001.459-.44zm4.814-2.035a.46.46%200%2001.553.45v4.754a.458.458%200%2011-.918%200V15.48L3.74%2017.202a.462.462%200%2001-.655.016.462.462%200%2001-.065-.082L.628%2014.67a.459.459%200%2001.658-.637l2.124%202.187%202.127-2.188a.46.46%200%2001.235-.13zm2.068.004a.46.46%200%2001.458.445v4.755a.46.46%200%2001-.458.458.459.459%200%2001-.458-.458V14.35a.459.459%200%2001.458-.445zm1.973%202.014a.46.46%200%2001.46.457v2.729a.46.46%200%2001-.784.324.46.46%200%2001-.134-.324v-2.729a.46.46%200%2001.458-.458zm.002-2.045a.458.458%200%2001.328.157l2.127%202.19%202.125-2.19a.459.459%200%2001.784.318v4.756a.46.46%200%2001-.455.458.46.46%200%2001-.458-.458V15.48l-1.667%201.723a.46.46%200%2001-.65.008l-.005-.005c0-.002-.002-.002-.004-.003l-2.455-2.534a.46.46%200%2001-.008-.667.461.461%200%2001.338-.128zm6.797%201.206a.46.46%200%2001.53.651A1.966%201.966%200%200019.81%2018.4a.462.462%200%2001.623.18.46.46%200%2001-.181.624%202.863%202.863%200%2001-1.38.353l-.142-.004a2.88%202.88%200%2001-2.393-4.263.461.461%200%2001.274-.21zm.864-.931a2.884%202.884%200%20013.915%203.914.46.46%200%2001-.402.24l-.057-.004a.458.458%200%2001-.164-.055.46.46%200%2001-.182-.622%201.967%201.967%200%2000-2.669-2.67.459.459%200%2011-.441-.803zM9.59%206.368c1.481%200%201.696%201.202%201.696%201.654v2.648h-.917v-.432c-.26.346-.792.535-1.36.535-.133%200-1.289-.03-1.384-1.136-.082-.932.675-1.61%202.053-1.61h.691c0-.563-.367-.886-.983-.886-.44.013-.864.174-1.2.458l-.36-.664c.484-.379%201.012-.567%201.764-.567zm4.427.1c1.263%200%202.082.97%202.083%202.15%200%201.181-.824%202.154-2.083%202.154-1.26%200-2.084-.972-2.084-2.152%200-1.18.82-2.153%202.084-2.153zm6.801.015c.68%200%201.202.465%201.197%201.548v2.642H21.1V8.29c0-.312-.002-.98-.63-.98s-.628.667-.628.838v2.524h-.89V8.148c0-.17-.001-.838-.63-.838-.628%200-.628.668-.628.98v2.383h-.917v-4.03h.917V7a1.22%201.22%200%2001.947-.516c.398%200%20.76.193.982.686a1.321%201.321%200%20011.195-.686zm-18.093.872l1.457-1.772H5.32L3.311%208.07l2.14%202.602H4.24L2.725%208.796%201.21%2010.672H0L2.138%208.07.13%205.583h1.138l1.458%201.772zm4.149%203.317h-.916V6.644h.916v4.028zm16.99%200h-.916V6.644h.916v4.028zM9.925%208.71c-1.055%200-1.359.412-1.326.742.032.329.324.537.757.537a1.013%201.013%200%20001.014-.968l.002-.31h-.447zM14.018%207.3c-.663%200-1.184.487-1.184%201.32%200%20.832.52%201.32%201.184%201.32.662%200%201.182-.49%201.182-1.32%200-.832-.52-1.32-1.182-1.32zM6.417%205.001a.568.568%200%2001.587.582.588.588%200%2001-1.175%200A.57.57%200%20016.417%205zm16.991%200a.57.57%200%2001.592.582.588.588%200%2001-1.174%200%20.57.57%200%2001.357-.542.572.572%200%2001.225-.04z'%3e%3c/path%3e%3c/svg%3e";
|
|
895
|
+
const AgentInspectorLogo = "/assets/agent-inspector-58K1_MsC.ico";
|
|
854
896
|
const CLIENT_LABELS = {
|
|
897
|
+
"agent-inspector": "Inspector",
|
|
855
898
|
codex: "Codex",
|
|
856
899
|
opencode: "OpenCode",
|
|
857
900
|
"mimo-code": "MiMo Code",
|
|
@@ -872,6 +915,9 @@ function detectClientApp(input) {
|
|
|
872
915
|
normalize(input.conversationId),
|
|
873
916
|
normalize(input.clientProjectFolder)
|
|
874
917
|
].join(" ");
|
|
918
|
+
if (matchesAny(haystack, ["agent-inspector", "agent inspector", "provider-test"])) {
|
|
919
|
+
return "agent-inspector";
|
|
920
|
+
}
|
|
875
921
|
if (matchesAny(haystack, ["mimocode", "mimo-code", "mimo code"])) return "mimo-code";
|
|
876
922
|
if (matchesAny(haystack, ["opencode", "open-code", "open code"])) return "opencode";
|
|
877
923
|
if (matchesAny(haystack, ["claude-code", "claude code", "claudecode"])) return "claude-code";
|
|
@@ -882,6 +928,7 @@ function detectClientApp(input) {
|
|
|
882
928
|
}
|
|
883
929
|
function clientAppLabel(client) {
|
|
884
930
|
switch (client) {
|
|
931
|
+
case "agent-inspector":
|
|
885
932
|
case "codex":
|
|
886
933
|
case "opencode":
|
|
887
934
|
case "mimo-code":
|
|
@@ -892,11 +939,26 @@ function clientAppLabel(client) {
|
|
|
892
939
|
}
|
|
893
940
|
}
|
|
894
941
|
const CLIENT_LOGOS = {
|
|
942
|
+
"agent-inspector": AgentInspectorLogo,
|
|
895
943
|
codex: CodexLogoSvg,
|
|
896
944
|
opencode: OpenCodeLogoSvg,
|
|
897
945
|
"mimo-code": MiMoCodeLogoSvg,
|
|
898
946
|
"claude-code": ClaudeCodeLogoSvg
|
|
899
947
|
};
|
|
948
|
+
const CLIENT_LOGO_FRAMES = {
|
|
949
|
+
"agent-inspector": "border-orange-200/25 bg-orange-300/[0.12]",
|
|
950
|
+
codex: "border-cyan-200/20 bg-cyan-300/[0.08]",
|
|
951
|
+
opencode: "border-sky-200/25 bg-sky-300/[0.12]",
|
|
952
|
+
"mimo-code": "border-orange-200/25 bg-orange-400/[0.12]",
|
|
953
|
+
"claude-code": "border-amber-100/20 bg-amber-300/[0.09]"
|
|
954
|
+
};
|
|
955
|
+
const CLIENT_LOGO_IMAGES = {
|
|
956
|
+
"agent-inspector": "p-0.5 drop-shadow-[0_0_8px_rgba(251,146,60,0.35)]",
|
|
957
|
+
codex: "p-0.5",
|
|
958
|
+
opencode: "p-1 drop-shadow-[0_0_8px_rgba(125,211,252,0.35)]",
|
|
959
|
+
"mimo-code": "p-0.5 drop-shadow-[0_0_8px_rgba(255,105,0,0.35)]",
|
|
960
|
+
"claude-code": "p-0.5"
|
|
961
|
+
};
|
|
900
962
|
function ClientLogo({
|
|
901
963
|
client,
|
|
902
964
|
className
|
|
@@ -909,12 +971,21 @@ function ClientLogo({
|
|
|
909
971
|
"span",
|
|
910
972
|
{
|
|
911
973
|
className: cn(
|
|
912
|
-
"
|
|
974
|
+
"inline-flex size-6 shrink-0 items-center justify-center rounded-md border p-0 shadow-sm",
|
|
975
|
+
CLIENT_LOGO_FRAMES[client],
|
|
913
976
|
className
|
|
914
977
|
),
|
|
915
978
|
"aria-label": label,
|
|
916
979
|
title: label,
|
|
917
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
980
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
981
|
+
"img",
|
|
982
|
+
{
|
|
983
|
+
src: logoSrc,
|
|
984
|
+
alt: "",
|
|
985
|
+
className: cn("size-full object-contain", CLIENT_LOGO_IMAGES[client]),
|
|
986
|
+
"aria-hidden": "true"
|
|
987
|
+
}
|
|
988
|
+
)
|
|
918
989
|
}
|
|
919
990
|
);
|
|
920
991
|
}
|
|
@@ -1027,7 +1098,7 @@ function TooltipContent({
|
|
|
1027
1098
|
children,
|
|
1028
1099
|
...props
|
|
1029
1100
|
}) {
|
|
1030
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$
|
|
1101
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$2, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1031
1102
|
Content2$1,
|
|
1032
1103
|
{
|
|
1033
1104
|
"data-slot": "tooltip-content",
|
|
@@ -1102,6 +1173,171 @@ function countCharacters(text) {
|
|
|
1102
1173
|
});
|
|
1103
1174
|
return n;
|
|
1104
1175
|
}
|
|
1176
|
+
const CATEGORY_ORDER = [
|
|
1177
|
+
"file",
|
|
1178
|
+
"shell",
|
|
1179
|
+
"browser",
|
|
1180
|
+
"web",
|
|
1181
|
+
"mcp",
|
|
1182
|
+
"code",
|
|
1183
|
+
"other"
|
|
1184
|
+
];
|
|
1185
|
+
function firstTextSlice(value) {
|
|
1186
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
1187
|
+
if (normalized.length <= 120) return normalized;
|
|
1188
|
+
return `${normalized.slice(0, 119)}...`;
|
|
1189
|
+
}
|
|
1190
|
+
function previewDescription(description) {
|
|
1191
|
+
if (description === null) return null;
|
|
1192
|
+
const normalized = description.replace(/\s+/g, " ").trim();
|
|
1193
|
+
if (normalized.length === 0) return null;
|
|
1194
|
+
const sentenceEnd = normalized.search(/[.!?。!?]/);
|
|
1195
|
+
if (sentenceEnd >= 24) return firstTextSlice(normalized.slice(0, sentenceEnd + 1));
|
|
1196
|
+
return firstTextSlice(normalized);
|
|
1197
|
+
}
|
|
1198
|
+
function lowerHaystack(name, description) {
|
|
1199
|
+
return `${name} ${description ?? ""}`.toLowerCase();
|
|
1200
|
+
}
|
|
1201
|
+
function includesAny(value, needles) {
|
|
1202
|
+
return needles.some((needle) => value.includes(needle));
|
|
1203
|
+
}
|
|
1204
|
+
function categorizeTool(name, description) {
|
|
1205
|
+
const haystack = lowerHaystack(name, description);
|
|
1206
|
+
if (name.startsWith("mcp__") || name.startsWith("inspector_") || includesAny(haystack, [" mcp", "model context protocol"])) {
|
|
1207
|
+
return "mcp";
|
|
1208
|
+
}
|
|
1209
|
+
if (includesAny(haystack, ["bash", "shell", "terminal", "command", "powershell", "exec", "process"])) {
|
|
1210
|
+
return "shell";
|
|
1211
|
+
}
|
|
1212
|
+
if (includesAny(haystack, [
|
|
1213
|
+
"browser",
|
|
1214
|
+
"playwright",
|
|
1215
|
+
"screenshot",
|
|
1216
|
+
"click",
|
|
1217
|
+
"navigate",
|
|
1218
|
+
"page",
|
|
1219
|
+
"tab"
|
|
1220
|
+
])) {
|
|
1221
|
+
return "browser";
|
|
1222
|
+
}
|
|
1223
|
+
if (includesAny(haystack, [
|
|
1224
|
+
"read",
|
|
1225
|
+
"write",
|
|
1226
|
+
"edit",
|
|
1227
|
+
"file",
|
|
1228
|
+
"glob",
|
|
1229
|
+
"grep",
|
|
1230
|
+
"patch",
|
|
1231
|
+
"filesystem",
|
|
1232
|
+
"directory"
|
|
1233
|
+
])) {
|
|
1234
|
+
return "file";
|
|
1235
|
+
}
|
|
1236
|
+
if (includesAny(haystack, ["web", "search", "http", "url", "fetch"])) {
|
|
1237
|
+
return "web";
|
|
1238
|
+
}
|
|
1239
|
+
if (includesAny(haystack, ["code", "typescript", "javascript", "python", "repl"])) {
|
|
1240
|
+
return "code";
|
|
1241
|
+
}
|
|
1242
|
+
return "other";
|
|
1243
|
+
}
|
|
1244
|
+
function parameterNames(schema) {
|
|
1245
|
+
const properties = safeGetOwnProperty(schema, "properties");
|
|
1246
|
+
if (properties === null || typeof properties !== "object" || Array.isArray(properties)) {
|
|
1247
|
+
return [];
|
|
1248
|
+
}
|
|
1249
|
+
return Object.keys(properties).sort((a, b) => a.localeCompare(b));
|
|
1250
|
+
}
|
|
1251
|
+
function requiredParameterNames(schema) {
|
|
1252
|
+
const required = safeGetOwnProperty(schema, "required");
|
|
1253
|
+
if (!Array.isArray(required)) return [];
|
|
1254
|
+
const names = [];
|
|
1255
|
+
for (const item of required) {
|
|
1256
|
+
if (typeof item === "string" && item.length > 0) names.push(item);
|
|
1257
|
+
}
|
|
1258
|
+
return names.sort((a, b) => a.localeCompare(b));
|
|
1259
|
+
}
|
|
1260
|
+
function parseAnthropicTool(tool) {
|
|
1261
|
+
const name = safeGetOwnProperty(tool, "name");
|
|
1262
|
+
if (typeof name !== "string" || name.length === 0) return null;
|
|
1263
|
+
const description = safeGetOwnProperty(tool, "description");
|
|
1264
|
+
const schema = safeGetOwnProperty(tool, "input_schema") ?? null;
|
|
1265
|
+
const normalizedDescription = typeof description === "string" ? description : null;
|
|
1266
|
+
return {
|
|
1267
|
+
name,
|
|
1268
|
+
description: normalizedDescription,
|
|
1269
|
+
descriptionPreview: previewDescription(normalizedDescription),
|
|
1270
|
+
category: categorizeTool(name, normalizedDescription),
|
|
1271
|
+
parameterCount: parameterNames(schema).length,
|
|
1272
|
+
requiredParameters: requiredParameterNames(schema),
|
|
1273
|
+
schema
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
function parseOpenAITool(tool) {
|
|
1277
|
+
const fn = safeGetOwnProperty(tool, "function");
|
|
1278
|
+
const toolType = safeGetOwnProperty(tool, "type");
|
|
1279
|
+
if (fn === void 0 && typeof toolType !== "string") return null;
|
|
1280
|
+
const name = safeGetOwnProperty(fn, "name") ?? safeGetOwnProperty(tool, "name") ?? (typeof toolType === "string" ? toolType : void 0);
|
|
1281
|
+
if (typeof name !== "string" || name.length === 0) return null;
|
|
1282
|
+
const description = safeGetOwnProperty(fn, "description") ?? safeGetOwnProperty(tool, "description");
|
|
1283
|
+
const schema = safeGetOwnProperty(fn, "parameters") ?? safeGetOwnProperty(tool, "parameters") ?? null;
|
|
1284
|
+
const normalizedDescription = typeof description === "string" ? description : null;
|
|
1285
|
+
return {
|
|
1286
|
+
name,
|
|
1287
|
+
description: normalizedDescription,
|
|
1288
|
+
descriptionPreview: previewDescription(normalizedDescription),
|
|
1289
|
+
category: categorizeTool(name, normalizedDescription),
|
|
1290
|
+
parameterCount: parameterNames(schema).length,
|
|
1291
|
+
requiredParameters: requiredParameterNames(schema),
|
|
1292
|
+
schema
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
function parseTool(tool) {
|
|
1296
|
+
const openAITool = parseOpenAITool(tool);
|
|
1297
|
+
if (openAITool !== null) return openAITool;
|
|
1298
|
+
return parseAnthropicTool(tool);
|
|
1299
|
+
}
|
|
1300
|
+
function formatToolChoice(choice) {
|
|
1301
|
+
if (choice === void 0 || choice === null) return null;
|
|
1302
|
+
if (typeof choice === "string") return choice;
|
|
1303
|
+
const type = safeGetOwnProperty(choice, "type");
|
|
1304
|
+
const name = safeGetOwnProperty(choice, "name");
|
|
1305
|
+
const fnName = safeGetOwnProperty(safeGetOwnProperty(choice, "function"), "name");
|
|
1306
|
+
if (typeof type === "string" && typeof fnName === "string" && fnName.length > 0) {
|
|
1307
|
+
return `${type}: ${fnName}`;
|
|
1308
|
+
}
|
|
1309
|
+
if (typeof type === "string" && typeof name === "string" && name.length > 0) {
|
|
1310
|
+
return `${type}: ${name}`;
|
|
1311
|
+
}
|
|
1312
|
+
if (typeof type === "string") return type;
|
|
1313
|
+
const encoded = JSON.stringify(choice);
|
|
1314
|
+
return encoded === void 0 ? null : firstTextSlice(encoded);
|
|
1315
|
+
}
|
|
1316
|
+
function summarizeCategories(tools) {
|
|
1317
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1318
|
+
for (const tool of tools) {
|
|
1319
|
+
counts.set(tool.category, (counts.get(tool.category) ?? 0) + 1);
|
|
1320
|
+
}
|
|
1321
|
+
return CATEGORY_ORDER.flatMap((category) => {
|
|
1322
|
+
const count = counts.get(category) ?? 0;
|
|
1323
|
+
return count > 0 ? [{ category, count }] : [];
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
function parseRequestTools(parsed) {
|
|
1327
|
+
const rawTools = safeGetOwnProperty(parsed, "tools");
|
|
1328
|
+
if (!Array.isArray(rawTools) || rawTools.length === 0) return null;
|
|
1329
|
+
const tools = [];
|
|
1330
|
+
for (const rawTool of rawTools) {
|
|
1331
|
+
const tool = parseTool(rawTool);
|
|
1332
|
+
if (tool !== null) tools.push(tool);
|
|
1333
|
+
}
|
|
1334
|
+
if (tools.length === 0) return null;
|
|
1335
|
+
return {
|
|
1336
|
+
tools,
|
|
1337
|
+
toolChoiceLabel: formatToolChoice(safeGetOwnProperty(parsed, "tool_choice")),
|
|
1338
|
+
categories: summarizeCategories(tools)
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1105
1341
|
function emptyRequestAnalysis(rawBody) {
|
|
1106
1342
|
return {
|
|
1107
1343
|
parsed: null,
|
|
@@ -1197,13 +1433,15 @@ const anthropicLogFormatAdapter = {
|
|
|
1197
1433
|
analyzeRequest(rawBody) {
|
|
1198
1434
|
if (rawBody === null) return emptyRequestAnalysis(rawBody);
|
|
1199
1435
|
try {
|
|
1200
|
-
const
|
|
1436
|
+
const parsedBody = JSON.parse(rawBody);
|
|
1437
|
+
const toolCount = parseRequestTools(parsedBody)?.tools.length ?? null;
|
|
1438
|
+
const result = AnthropicRequestSchema.safeParse(parsedBody);
|
|
1201
1439
|
if (!result.success) return emptyRequestAnalysis(rawBody);
|
|
1202
1440
|
return {
|
|
1203
1441
|
parsed: result.data,
|
|
1204
1442
|
comparisonValue: result.data,
|
|
1205
1443
|
messageCount: result.data.messages.length,
|
|
1206
|
-
toolCount
|
|
1444
|
+
toolCount
|
|
1207
1445
|
};
|
|
1208
1446
|
} catch {
|
|
1209
1447
|
return emptyRequestAnalysis(rawBody);
|
|
@@ -1354,22 +1592,24 @@ const openAILogFormatAdapter = {
|
|
|
1354
1592
|
analyzeRequest(rawBody) {
|
|
1355
1593
|
if (rawBody === null) return emptyRequestAnalysis(rawBody);
|
|
1356
1594
|
try {
|
|
1357
|
-
const
|
|
1595
|
+
const parsedBody = JSON.parse(rawBody);
|
|
1596
|
+
const toolCount = parseRequestTools(parsedBody)?.tools.length ?? null;
|
|
1597
|
+
const result = OpenAIRequestSchema.safeParse(parsedBody);
|
|
1358
1598
|
if (!result.success) {
|
|
1359
|
-
const responsesResult = OpenAIResponsesRequestSchema.safeParse(
|
|
1599
|
+
const responsesResult = OpenAIResponsesRequestSchema.safeParse(parsedBody);
|
|
1360
1600
|
if (!responsesResult.success) return emptyRequestAnalysis(rawBody);
|
|
1361
1601
|
return {
|
|
1362
1602
|
parsed: responsesResult.data,
|
|
1363
1603
|
comparisonValue: responsesResult.data,
|
|
1364
1604
|
messageCount: countResponsesInput(responsesResult.data.input),
|
|
1365
|
-
toolCount
|
|
1605
|
+
toolCount
|
|
1366
1606
|
};
|
|
1367
1607
|
}
|
|
1368
1608
|
return {
|
|
1369
1609
|
parsed: result.data,
|
|
1370
1610
|
comparisonValue: result.data,
|
|
1371
1611
|
messageCount: result.data.messages.length,
|
|
1372
|
-
toolCount
|
|
1612
|
+
toolCount
|
|
1373
1613
|
};
|
|
1374
1614
|
} catch {
|
|
1375
1615
|
return emptyRequestAnalysis(rawBody);
|
|
@@ -2306,27 +2546,27 @@ function useCopyFeedback(text) {
|
|
|
2306
2546
|
return { copied, copy };
|
|
2307
2547
|
}
|
|
2308
2548
|
const LazyCompareDrawer = reactExports.lazy(
|
|
2309
|
-
() => import("./CompareDrawer-
|
|
2549
|
+
() => import("./CompareDrawer-s-UF9gW3.mjs").then((m) => ({ default: m.CompareDrawer }))
|
|
2310
2550
|
);
|
|
2311
2551
|
const LazyReplayDialog = reactExports.lazy(
|
|
2312
|
-
() => import("./ReplayDialog-
|
|
2552
|
+
() => import("./ReplayDialog-DvS8gvJr.mjs").then((m) => ({ default: m.ReplayDialog }))
|
|
2313
2553
|
);
|
|
2314
2554
|
const LazyRequestAnatomy = reactExports.lazy(
|
|
2315
|
-
() => import("./RequestAnatomy-
|
|
2555
|
+
() => import("./RequestAnatomy-BwhWglJL.mjs").then((m) => ({ default: m.RequestAnatomy }))
|
|
2316
2556
|
);
|
|
2317
2557
|
const LazyResponseView = reactExports.lazy(
|
|
2318
|
-
() => import("./ResponseView-
|
|
2558
|
+
() => import("./ResponseView-wBVreqQf.mjs").then((m) => ({ default: m.ResponseView }))
|
|
2319
2559
|
);
|
|
2320
2560
|
const LazyStreamingChunkSequence = reactExports.lazy(
|
|
2321
|
-
() => import("./StreamingChunkSequence-
|
|
2561
|
+
() => import("./StreamingChunkSequence-Dr6eg-MJ.mjs").then((m) => ({
|
|
2322
2562
|
default: m.StreamingChunkSequence
|
|
2323
2563
|
}))
|
|
2324
2564
|
);
|
|
2325
2565
|
const LazyJsonViewer = reactExports.lazy(
|
|
2326
|
-
() => import("./json-viewer-
|
|
2566
|
+
() => import("./json-viewer-D7L8y0FH.mjs").then((m) => ({ default: m.JsonViewer }))
|
|
2327
2567
|
);
|
|
2328
2568
|
const LazyJsonViewerFromString = reactExports.lazy(
|
|
2329
|
-
() => import("./json-viewer-
|
|
2569
|
+
() => import("./json-viewer-D7L8y0FH.mjs").then((m) => ({ default: m.JsonViewerFromString }))
|
|
2330
2570
|
);
|
|
2331
2571
|
const HIGHLIGHT_DURATION_MS = 1200;
|
|
2332
2572
|
const MAX_HIGHLIGHT_ATTEMPTS = 12;
|
|
@@ -3473,171 +3713,6 @@ function shouldShowHeadersDiffButton(viewMode, hasRawHeaders) {
|
|
|
3473
3713
|
function shouldShowRequestDiffButton(apiFormat, viewMode, strip, hasRawRequest) {
|
|
3474
3714
|
return apiFormat === "anthropic" && viewMode === "full" && strip && hasRawRequest;
|
|
3475
3715
|
}
|
|
3476
|
-
const CATEGORY_ORDER = [
|
|
3477
|
-
"file",
|
|
3478
|
-
"shell",
|
|
3479
|
-
"browser",
|
|
3480
|
-
"web",
|
|
3481
|
-
"mcp",
|
|
3482
|
-
"code",
|
|
3483
|
-
"other"
|
|
3484
|
-
];
|
|
3485
|
-
function firstTextSlice(value) {
|
|
3486
|
-
const normalized = value.replace(/\s+/g, " ").trim();
|
|
3487
|
-
if (normalized.length <= 120) return normalized;
|
|
3488
|
-
return `${normalized.slice(0, 119)}...`;
|
|
3489
|
-
}
|
|
3490
|
-
function previewDescription(description) {
|
|
3491
|
-
if (description === null) return null;
|
|
3492
|
-
const normalized = description.replace(/\s+/g, " ").trim();
|
|
3493
|
-
if (normalized.length === 0) return null;
|
|
3494
|
-
const sentenceEnd = normalized.search(/[.!?。!?]/);
|
|
3495
|
-
if (sentenceEnd >= 24) return firstTextSlice(normalized.slice(0, sentenceEnd + 1));
|
|
3496
|
-
return firstTextSlice(normalized);
|
|
3497
|
-
}
|
|
3498
|
-
function lowerHaystack(name, description) {
|
|
3499
|
-
return `${name} ${description ?? ""}`.toLowerCase();
|
|
3500
|
-
}
|
|
3501
|
-
function includesAny(value, needles) {
|
|
3502
|
-
return needles.some((needle) => value.includes(needle));
|
|
3503
|
-
}
|
|
3504
|
-
function categorizeTool(name, description) {
|
|
3505
|
-
const haystack = lowerHaystack(name, description);
|
|
3506
|
-
if (name.startsWith("mcp__") || name.startsWith("inspector_") || includesAny(haystack, [" mcp", "model context protocol"])) {
|
|
3507
|
-
return "mcp";
|
|
3508
|
-
}
|
|
3509
|
-
if (includesAny(haystack, ["bash", "shell", "terminal", "command", "powershell", "exec", "process"])) {
|
|
3510
|
-
return "shell";
|
|
3511
|
-
}
|
|
3512
|
-
if (includesAny(haystack, [
|
|
3513
|
-
"browser",
|
|
3514
|
-
"playwright",
|
|
3515
|
-
"screenshot",
|
|
3516
|
-
"click",
|
|
3517
|
-
"navigate",
|
|
3518
|
-
"page",
|
|
3519
|
-
"tab"
|
|
3520
|
-
])) {
|
|
3521
|
-
return "browser";
|
|
3522
|
-
}
|
|
3523
|
-
if (includesAny(haystack, [
|
|
3524
|
-
"read",
|
|
3525
|
-
"write",
|
|
3526
|
-
"edit",
|
|
3527
|
-
"file",
|
|
3528
|
-
"glob",
|
|
3529
|
-
"grep",
|
|
3530
|
-
"patch",
|
|
3531
|
-
"filesystem",
|
|
3532
|
-
"directory"
|
|
3533
|
-
])) {
|
|
3534
|
-
return "file";
|
|
3535
|
-
}
|
|
3536
|
-
if (includesAny(haystack, ["web", "search", "http", "url", "fetch"])) {
|
|
3537
|
-
return "web";
|
|
3538
|
-
}
|
|
3539
|
-
if (includesAny(haystack, ["code", "typescript", "javascript", "python", "repl"])) {
|
|
3540
|
-
return "code";
|
|
3541
|
-
}
|
|
3542
|
-
return "other";
|
|
3543
|
-
}
|
|
3544
|
-
function parameterNames(schema) {
|
|
3545
|
-
const properties = safeGetOwnProperty(schema, "properties");
|
|
3546
|
-
if (properties === null || typeof properties !== "object" || Array.isArray(properties)) {
|
|
3547
|
-
return [];
|
|
3548
|
-
}
|
|
3549
|
-
return Object.keys(properties).sort((a, b) => a.localeCompare(b));
|
|
3550
|
-
}
|
|
3551
|
-
function requiredParameterNames(schema) {
|
|
3552
|
-
const required = safeGetOwnProperty(schema, "required");
|
|
3553
|
-
if (!Array.isArray(required)) return [];
|
|
3554
|
-
const names = [];
|
|
3555
|
-
for (const item of required) {
|
|
3556
|
-
if (typeof item === "string" && item.length > 0) names.push(item);
|
|
3557
|
-
}
|
|
3558
|
-
return names.sort((a, b) => a.localeCompare(b));
|
|
3559
|
-
}
|
|
3560
|
-
function parseAnthropicTool(tool) {
|
|
3561
|
-
const name = safeGetOwnProperty(tool, "name");
|
|
3562
|
-
if (typeof name !== "string" || name.length === 0) return null;
|
|
3563
|
-
const description = safeGetOwnProperty(tool, "description");
|
|
3564
|
-
const schema = safeGetOwnProperty(tool, "input_schema") ?? null;
|
|
3565
|
-
const normalizedDescription = typeof description === "string" ? description : null;
|
|
3566
|
-
return {
|
|
3567
|
-
name,
|
|
3568
|
-
description: normalizedDescription,
|
|
3569
|
-
descriptionPreview: previewDescription(normalizedDescription),
|
|
3570
|
-
category: categorizeTool(name, normalizedDescription),
|
|
3571
|
-
parameterCount: parameterNames(schema).length,
|
|
3572
|
-
requiredParameters: requiredParameterNames(schema),
|
|
3573
|
-
schema
|
|
3574
|
-
};
|
|
3575
|
-
}
|
|
3576
|
-
function parseOpenAITool(tool) {
|
|
3577
|
-
const fn = safeGetOwnProperty(tool, "function");
|
|
3578
|
-
const toolType = safeGetOwnProperty(tool, "type");
|
|
3579
|
-
if (fn === void 0 && toolType !== "function") return null;
|
|
3580
|
-
const name = safeGetOwnProperty(fn, "name") ?? safeGetOwnProperty(tool, "name");
|
|
3581
|
-
if (typeof name !== "string" || name.length === 0) return null;
|
|
3582
|
-
const description = safeGetOwnProperty(fn, "description") ?? safeGetOwnProperty(tool, "description");
|
|
3583
|
-
const schema = safeGetOwnProperty(fn, "parameters") ?? safeGetOwnProperty(tool, "parameters") ?? null;
|
|
3584
|
-
const normalizedDescription = typeof description === "string" ? description : null;
|
|
3585
|
-
return {
|
|
3586
|
-
name,
|
|
3587
|
-
description: normalizedDescription,
|
|
3588
|
-
descriptionPreview: previewDescription(normalizedDescription),
|
|
3589
|
-
category: categorizeTool(name, normalizedDescription),
|
|
3590
|
-
parameterCount: parameterNames(schema).length,
|
|
3591
|
-
requiredParameters: requiredParameterNames(schema),
|
|
3592
|
-
schema
|
|
3593
|
-
};
|
|
3594
|
-
}
|
|
3595
|
-
function parseTool(tool) {
|
|
3596
|
-
const openAITool = parseOpenAITool(tool);
|
|
3597
|
-
if (openAITool !== null) return openAITool;
|
|
3598
|
-
return parseAnthropicTool(tool);
|
|
3599
|
-
}
|
|
3600
|
-
function formatToolChoice(choice) {
|
|
3601
|
-
if (choice === void 0 || choice === null) return null;
|
|
3602
|
-
if (typeof choice === "string") return choice;
|
|
3603
|
-
const type = safeGetOwnProperty(choice, "type");
|
|
3604
|
-
const name = safeGetOwnProperty(choice, "name");
|
|
3605
|
-
const fnName = safeGetOwnProperty(safeGetOwnProperty(choice, "function"), "name");
|
|
3606
|
-
if (typeof type === "string" && typeof fnName === "string" && fnName.length > 0) {
|
|
3607
|
-
return `${type}: ${fnName}`;
|
|
3608
|
-
}
|
|
3609
|
-
if (typeof type === "string" && typeof name === "string" && name.length > 0) {
|
|
3610
|
-
return `${type}: ${name}`;
|
|
3611
|
-
}
|
|
3612
|
-
if (typeof type === "string") return type;
|
|
3613
|
-
const encoded = JSON.stringify(choice);
|
|
3614
|
-
return encoded === void 0 ? null : firstTextSlice(encoded);
|
|
3615
|
-
}
|
|
3616
|
-
function summarizeCategories(tools) {
|
|
3617
|
-
const counts = /* @__PURE__ */ new Map();
|
|
3618
|
-
for (const tool of tools) {
|
|
3619
|
-
counts.set(tool.category, (counts.get(tool.category) ?? 0) + 1);
|
|
3620
|
-
}
|
|
3621
|
-
return CATEGORY_ORDER.flatMap((category) => {
|
|
3622
|
-
const count = counts.get(category) ?? 0;
|
|
3623
|
-
return count > 0 ? [{ category, count }] : [];
|
|
3624
|
-
});
|
|
3625
|
-
}
|
|
3626
|
-
function parseRequestTools(parsed) {
|
|
3627
|
-
const rawTools = safeGetOwnProperty(parsed, "tools");
|
|
3628
|
-
if (!Array.isArray(rawTools) || rawTools.length === 0) return null;
|
|
3629
|
-
const tools = [];
|
|
3630
|
-
for (const rawTool of rawTools) {
|
|
3631
|
-
const tool = parseTool(rawTool);
|
|
3632
|
-
if (tool !== null) tools.push(tool);
|
|
3633
|
-
}
|
|
3634
|
-
if (tools.length === 0) return null;
|
|
3635
|
-
return {
|
|
3636
|
-
tools,
|
|
3637
|
-
toolChoiceLabel: formatToolChoice(safeGetOwnProperty(parsed, "tool_choice")),
|
|
3638
|
-
categories: summarizeCategories(tools)
|
|
3639
|
-
};
|
|
3640
|
-
}
|
|
3641
3716
|
function TabFallback() {
|
|
3642
3717
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-1", "aria-hidden": "true" });
|
|
3643
3718
|
}
|
|
@@ -5005,7 +5080,6 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
5005
5080
|
}
|
|
5006
5081
|
},
|
|
5007
5082
|
children: [
|
|
5008
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0 flex items-start pt-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground/50 font-mono tabular-nums leading-none select-none", children: turnIndex + 1 }) }),
|
|
5009
5083
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-6 shrink-0 flex flex-col items-center pt-1.5 pb-1.5", children: [
|
|
5010
5084
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center h-[calc(0.75rem-8px)]" }),
|
|
5011
5085
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -5112,7 +5186,6 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
5112
5186
|
const { log, stopReason: reason } = entry;
|
|
5113
5187
|
const isTurnStart = visibleIdx === 0;
|
|
5114
5188
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-stretch", children: [
|
|
5115
|
-
isTurnStart ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0 flex items-start pt-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground/50 font-mono tabular-nums leading-none select-none", children: turnIndex + 1 }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0" }),
|
|
5116
5189
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5117
5190
|
ThreadConnector,
|
|
5118
5191
|
{
|
|
@@ -5260,6 +5333,9 @@ const CandidatePromotionFailureResponseSchema = object({
|
|
|
5260
5333
|
const CandidateUpdateResponseSchema = object({
|
|
5261
5334
|
candidate: KnowledgeCandidateSchema
|
|
5262
5335
|
});
|
|
5336
|
+
const CANDIDATE_GENERATE_TIMEOUT_MS = 3e4;
|
|
5337
|
+
const CANDIDATE_PROMOTE_TIMEOUT_MS = 15e3;
|
|
5338
|
+
const CANDIDATE_UPDATE_TIMEOUT_MS = 15e3;
|
|
5263
5339
|
const CANDIDATE_STATUS_CLASSES = {
|
|
5264
5340
|
draft: "border-amber-500/30 bg-amber-500/10 text-amber-500",
|
|
5265
5341
|
promoted: "border-emerald-500/30 bg-emerald-500/10 text-emerald-500",
|
|
@@ -5765,19 +5841,13 @@ function AgentTraceSummary({
|
|
|
5765
5841
|
setCandidateState({ status: "loading", error: null });
|
|
5766
5842
|
void (async () => {
|
|
5767
5843
|
try {
|
|
5768
|
-
const
|
|
5844
|
+
const parsed = await fetchJsonWithTimeout(
|
|
5769
5845
|
`/api/knowledge/sessions/${encodeURIComponent(scopeId)}/candidates`,
|
|
5770
|
-
|
|
5846
|
+
CandidateResponseSchema,
|
|
5847
|
+
CANDIDATE_GENERATE_TIMEOUT_MS,
|
|
5848
|
+
{ method: "POST" },
|
|
5849
|
+
(response) => `Candidate generation failed with ${String(response.status)}`
|
|
5771
5850
|
);
|
|
5772
|
-
if (!response.ok) {
|
|
5773
|
-
const message = await readApiError(
|
|
5774
|
-
response,
|
|
5775
|
-
`Candidate generation failed with ${String(response.status)}`
|
|
5776
|
-
);
|
|
5777
|
-
setCandidateState({ status: "failed", error: message });
|
|
5778
|
-
return;
|
|
5779
|
-
}
|
|
5780
|
-
const parsed = await parseJsonResponse$1(response, CandidateResponseSchema);
|
|
5781
5851
|
setCandidates(parsed.candidates);
|
|
5782
5852
|
setCandidatesExpanded(parsed.candidates.length > 0);
|
|
5783
5853
|
setCandidateState(
|
|
@@ -5800,8 +5870,9 @@ function AgentTraceSummary({
|
|
|
5800
5870
|
});
|
|
5801
5871
|
void (async () => {
|
|
5802
5872
|
try {
|
|
5803
|
-
const response = await
|
|
5873
|
+
const response = await fetchWithTimeout(
|
|
5804
5874
|
`/api/knowledge/candidates/${encodeURIComponent(candidateId)}/promote`,
|
|
5875
|
+
CANDIDATE_PROMOTE_TIMEOUT_MS,
|
|
5805
5876
|
{ method: "POST" }
|
|
5806
5877
|
);
|
|
5807
5878
|
const raw = await response.json().catch(() => null);
|
|
@@ -5850,23 +5921,17 @@ function AgentTraceSummary({
|
|
|
5850
5921
|
return next;
|
|
5851
5922
|
});
|
|
5852
5923
|
try {
|
|
5853
|
-
const
|
|
5924
|
+
const parsed = await fetchJsonWithTimeout(
|
|
5854
5925
|
`/api/knowledge/candidates/${encodeURIComponent(candidateId)}`,
|
|
5926
|
+
CandidateUpdateResponseSchema,
|
|
5927
|
+
CANDIDATE_UPDATE_TIMEOUT_MS,
|
|
5855
5928
|
{
|
|
5856
5929
|
method: "PATCH",
|
|
5857
5930
|
headers: { "Content-Type": "application/json" },
|
|
5858
5931
|
body: JSON.stringify(update)
|
|
5859
|
-
}
|
|
5932
|
+
},
|
|
5933
|
+
(response) => `Candidate update failed with ${String(response.status)}`
|
|
5860
5934
|
);
|
|
5861
|
-
if (!response.ok) {
|
|
5862
|
-
const message = await readApiError(
|
|
5863
|
-
response,
|
|
5864
|
-
`Candidate update failed with ${String(response.status)}`
|
|
5865
|
-
);
|
|
5866
|
-
setCandidateState({ status: "failed", error: message });
|
|
5867
|
-
return false;
|
|
5868
|
-
}
|
|
5869
|
-
const parsed = await parseJsonResponse$1(response, CandidateUpdateResponseSchema);
|
|
5870
5935
|
setCandidates(
|
|
5871
5936
|
(current) => current.map(
|
|
5872
5937
|
(candidate) => candidate.id === parsed.candidate.id ? parsed.candidate : candidate
|
|
@@ -6942,6 +7007,7 @@ function TransientToast({
|
|
|
6942
7007
|
}
|
|
6943
7008
|
);
|
|
6944
7009
|
}
|
|
7010
|
+
const GROUP_OPERATION_TIMEOUT_MS = 2e4;
|
|
6945
7011
|
function groupDeletePath(groupId, deleteEvidence) {
|
|
6946
7012
|
const path = `/api/groups/${encodeURIComponent(groupId)}`;
|
|
6947
7013
|
return deleteEvidence ? `${path}?deleteEvidence=1` : path;
|
|
@@ -7162,18 +7228,13 @@ function GroupsDialog() {
|
|
|
7162
7228
|
setDeleteError(null);
|
|
7163
7229
|
setExportError(null);
|
|
7164
7230
|
try {
|
|
7165
|
-
const
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
tone: "error"
|
|
7173
|
-
});
|
|
7174
|
-
return;
|
|
7175
|
-
}
|
|
7176
|
-
const parsed = await parseJsonResponse$1(response, DeleteInspectorGroupsResponseSchema);
|
|
7231
|
+
const parsed = await fetchJsonWithTimeout(
|
|
7232
|
+
groupsClearPath(false),
|
|
7233
|
+
DeleteInspectorGroupsResponseSchema,
|
|
7234
|
+
GROUP_OPERATION_TIMEOUT_MS,
|
|
7235
|
+
{ method: "DELETE" },
|
|
7236
|
+
(response) => `Clear failed with status ${String(response.status)}`
|
|
7237
|
+
);
|
|
7177
7238
|
setExportResult(null);
|
|
7178
7239
|
setSelectedGroupId(null);
|
|
7179
7240
|
await mutate();
|
|
@@ -7196,18 +7257,17 @@ function GroupsDialog() {
|
|
|
7196
7257
|
setExportingGroupId(group.id);
|
|
7197
7258
|
setExportError(null);
|
|
7198
7259
|
try {
|
|
7199
|
-
const
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
const parsed = await parseJsonResponse$1(response, GroupEvidenceExportResultSchema);
|
|
7260
|
+
const parsed = await fetchJsonWithTimeout(
|
|
7261
|
+
`/api/groups/${encodeURIComponent(group.id)}/evidence`,
|
|
7262
|
+
GroupEvidenceExportResultSchema,
|
|
7263
|
+
GROUP_OPERATION_TIMEOUT_MS,
|
|
7264
|
+
{
|
|
7265
|
+
method: "POST",
|
|
7266
|
+
headers: { "content-type": "application/json" },
|
|
7267
|
+
body: JSON.stringify({ latestLogLimit: 10 })
|
|
7268
|
+
},
|
|
7269
|
+
(response) => `Export failed with status ${String(response.status)}`
|
|
7270
|
+
);
|
|
7211
7271
|
setExportResult(parsed);
|
|
7212
7272
|
await mutate();
|
|
7213
7273
|
await mutateEvidence();
|
|
@@ -7242,16 +7302,13 @@ function GroupsDialog() {
|
|
|
7242
7302
|
setDeletingGroupId(group.id);
|
|
7243
7303
|
setDeleteError(null);
|
|
7244
7304
|
try {
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
return;
|
|
7253
|
-
}
|
|
7254
|
-
await parseJsonResponse$1(response, DeleteInspectorGroupResponseSchema);
|
|
7305
|
+
await fetchJsonWithTimeout(
|
|
7306
|
+
groupDeletePath(group.id, deleteEvidence),
|
|
7307
|
+
DeleteInspectorGroupResponseSchema,
|
|
7308
|
+
GROUP_OPERATION_TIMEOUT_MS,
|
|
7309
|
+
{ method: "DELETE" },
|
|
7310
|
+
(response) => `Delete failed with status ${String(response.status)}`
|
|
7311
|
+
);
|
|
7255
7312
|
setExportResult(
|
|
7256
7313
|
(current) => current !== null && current.group.id === group.id ? null : current
|
|
7257
7314
|
);
|
|
@@ -7934,70 +7991,6 @@ function MemberMetadata({ entries }) {
|
|
|
7934
7991
|
}) })
|
|
7935
7992
|
] });
|
|
7936
7993
|
}
|
|
7937
|
-
function ClaudeCodeIcon() {
|
|
7938
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
7939
|
-
"svg",
|
|
7940
|
-
{
|
|
7941
|
-
fill: "currentColor",
|
|
7942
|
-
fillRule: "evenodd",
|
|
7943
|
-
viewBox: "0 0 24 24",
|
|
7944
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
7945
|
-
className: "size-6 shrink-0",
|
|
7946
|
-
children: [
|
|
7947
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("title", { children: "Claude Code" }),
|
|
7948
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
7949
|
-
"path",
|
|
7950
|
-
{
|
|
7951
|
-
clipRule: "evenodd",
|
|
7952
|
-
d: "M20.998 10.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6 10.949h1.488V8.102H6v2.847zm10.51 0H18V8.102h-1.49v2.847z"
|
|
7953
|
-
}
|
|
7954
|
-
)
|
|
7955
|
-
]
|
|
7956
|
-
}
|
|
7957
|
-
);
|
|
7958
|
-
}
|
|
7959
|
-
function OpenCodeIcon() {
|
|
7960
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
7961
|
-
"svg",
|
|
7962
|
-
{
|
|
7963
|
-
fill: "currentColor",
|
|
7964
|
-
fillRule: "evenodd",
|
|
7965
|
-
viewBox: "0 0 24 24",
|
|
7966
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
7967
|
-
className: "size-6 shrink-0",
|
|
7968
|
-
children: [
|
|
7969
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("title", { children: "OpenCode" }),
|
|
7970
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M16 6H8v12h8V6zm4 16H4V2h16v20z" })
|
|
7971
|
-
]
|
|
7972
|
-
}
|
|
7973
|
-
);
|
|
7974
|
-
}
|
|
7975
|
-
function MiMoCodeIcon() {
|
|
7976
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
7977
|
-
"svg",
|
|
7978
|
-
{
|
|
7979
|
-
fill: "currentColor",
|
|
7980
|
-
viewBox: "0 0 24 24",
|
|
7981
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
7982
|
-
className: "size-6 shrink-0",
|
|
7983
|
-
children: [
|
|
7984
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("title", { children: "MiMo Code" }),
|
|
7985
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
7986
|
-
"text",
|
|
7987
|
-
{
|
|
7988
|
-
x: "12",
|
|
7989
|
-
y: "18",
|
|
7990
|
-
textAnchor: "middle",
|
|
7991
|
-
fontSize: "16",
|
|
7992
|
-
fontWeight: "800",
|
|
7993
|
-
fontFamily: "system-ui, sans-serif",
|
|
7994
|
-
children: "M"
|
|
7995
|
-
}
|
|
7996
|
-
)
|
|
7997
|
-
]
|
|
7998
|
-
}
|
|
7999
|
-
);
|
|
8000
|
-
}
|
|
8001
7994
|
const ExternalProviderSchema = object({
|
|
8002
7995
|
name: string(),
|
|
8003
7996
|
apiKey: string(),
|
|
@@ -8019,11 +8012,7 @@ const ImportResponseSchema$1 = object({
|
|
|
8019
8012
|
message: string().optional(),
|
|
8020
8013
|
errors: array(string()).optional()
|
|
8021
8014
|
});
|
|
8022
|
-
const
|
|
8023
|
-
"claude-code": ClaudeCodeIcon,
|
|
8024
|
-
opencode: OpenCodeIcon,
|
|
8025
|
-
"mimo-code": MiMoCodeIcon
|
|
8026
|
-
};
|
|
8015
|
+
const PROVIDER_IMPORT_TIMEOUT_MS$1 = 2e4;
|
|
8027
8016
|
function ImportWizardDialog({
|
|
8028
8017
|
open,
|
|
8029
8018
|
onOpenChange,
|
|
@@ -8037,7 +8026,11 @@ function ImportWizardDialog({
|
|
|
8037
8026
|
const [importing, setImporting] = reactExports.useState(false);
|
|
8038
8027
|
const [importResult, setImportResult] = reactExports.useState(null);
|
|
8039
8028
|
const [importError, setImportError] = reactExports.useState(null);
|
|
8029
|
+
const scanRequestIdRef = reactExports.useRef(0);
|
|
8030
|
+
const importRequestIdRef = reactExports.useRef(0);
|
|
8040
8031
|
const scan = reactExports.useCallback(() => {
|
|
8032
|
+
const requestId = scanRequestIdRef.current + 1;
|
|
8033
|
+
scanRequestIdRef.current = requestId;
|
|
8041
8034
|
setScanning(true);
|
|
8042
8035
|
setScanError(null);
|
|
8043
8036
|
setWarnings([]);
|
|
@@ -8045,29 +8038,26 @@ function ImportWizardDialog({
|
|
|
8045
8038
|
setSelected(/* @__PURE__ */ new Set());
|
|
8046
8039
|
setImportResult(null);
|
|
8047
8040
|
setImportError(null);
|
|
8048
|
-
|
|
8049
|
-
|
|
8050
|
-
|
|
8051
|
-
|
|
8052
|
-
|
|
8053
|
-
}
|
|
8054
|
-
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
setWarnings(parsed.data.warnings ?? []);
|
|
8062
|
-
const indices = /* @__PURE__ */ new Set();
|
|
8063
|
-
parsed.data.providers.forEach((p, i) => {
|
|
8064
|
-
if (!p.alreadyExists) indices.add(i);
|
|
8065
|
-
});
|
|
8066
|
-
setSelected(indices);
|
|
8041
|
+
void fetchJsonWithTimeout(
|
|
8042
|
+
"/api/providers/scan",
|
|
8043
|
+
ScanResponseSchema,
|
|
8044
|
+
PROVIDER_IMPORT_TIMEOUT_MS$1,
|
|
8045
|
+
void 0,
|
|
8046
|
+
(response) => `Scan failed (${String(response.status)})`
|
|
8047
|
+
).then((data) => {
|
|
8048
|
+
if (scanRequestIdRef.current !== requestId) return;
|
|
8049
|
+
setProviders(data.providers);
|
|
8050
|
+
setWarnings(data.warnings ?? []);
|
|
8051
|
+
const indices = /* @__PURE__ */ new Set();
|
|
8052
|
+
data.providers.forEach((provider, index) => {
|
|
8053
|
+
if (!provider.alreadyExists) indices.add(index);
|
|
8067
8054
|
});
|
|
8055
|
+
setSelected(indices);
|
|
8068
8056
|
}).catch((err) => {
|
|
8057
|
+
if (scanRequestIdRef.current !== requestId) return;
|
|
8069
8058
|
setScanError(err instanceof Error ? err.message : String(err));
|
|
8070
8059
|
}).finally(() => {
|
|
8060
|
+
if (scanRequestIdRef.current !== requestId) return;
|
|
8071
8061
|
setScanning(false);
|
|
8072
8062
|
});
|
|
8073
8063
|
}, []);
|
|
@@ -8076,6 +8066,13 @@ function ImportWizardDialog({
|
|
|
8076
8066
|
scan();
|
|
8077
8067
|
}
|
|
8078
8068
|
}, [open, scan]);
|
|
8069
|
+
reactExports.useEffect(() => {
|
|
8070
|
+
if (open) return;
|
|
8071
|
+
scanRequestIdRef.current += 1;
|
|
8072
|
+
importRequestIdRef.current += 1;
|
|
8073
|
+
setScanning(false);
|
|
8074
|
+
setImporting(false);
|
|
8075
|
+
}, [open]);
|
|
8079
8076
|
const toggleProvider = reactExports.useCallback((index) => {
|
|
8080
8077
|
setSelected((prev) => {
|
|
8081
8078
|
const next = new Set(prev);
|
|
@@ -8090,6 +8087,8 @@ function ImportWizardDialog({
|
|
|
8090
8087
|
const importSelected = reactExports.useCallback(() => {
|
|
8091
8088
|
const toImport = providers.filter((_, i) => selected.has(i));
|
|
8092
8089
|
if (toImport.length === 0) return;
|
|
8090
|
+
const requestId = importRequestIdRef.current + 1;
|
|
8091
|
+
importRequestIdRef.current = requestId;
|
|
8093
8092
|
setImporting(true);
|
|
8094
8093
|
setImportError(null);
|
|
8095
8094
|
setImportResult(null);
|
|
@@ -8106,17 +8105,18 @@ function ImportWizardDialog({
|
|
|
8106
8105
|
createdAt: now,
|
|
8107
8106
|
updatedAt: now
|
|
8108
8107
|
}));
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
}
|
|
8119
|
-
|
|
8108
|
+
void fetchJsonWithTimeout(
|
|
8109
|
+
"/api/providers/import",
|
|
8110
|
+
ImportResponseSchema$1,
|
|
8111
|
+
PROVIDER_IMPORT_TIMEOUT_MS$1,
|
|
8112
|
+
{
|
|
8113
|
+
method: "POST",
|
|
8114
|
+
headers: { "Content-Type": "application/json" },
|
|
8115
|
+
body: JSON.stringify({ providers: providersPayload })
|
|
8116
|
+
},
|
|
8117
|
+
(response) => `Import failed (${String(response.status)})`
|
|
8118
|
+
).then((result) => {
|
|
8119
|
+
if (importRequestIdRef.current !== requestId) return;
|
|
8120
8120
|
setProviders(
|
|
8121
8121
|
(prev) => prev.map((p, i) => selected.has(i) ? { ...p, alreadyExists: true } : p)
|
|
8122
8122
|
);
|
|
@@ -8128,8 +8128,10 @@ function ImportWizardDialog({
|
|
|
8128
8128
|
}
|
|
8129
8129
|
onImportComplete();
|
|
8130
8130
|
}).catch((err) => {
|
|
8131
|
+
if (importRequestIdRef.current !== requestId) return;
|
|
8131
8132
|
setImportError(err instanceof Error ? err.message : String(err));
|
|
8132
8133
|
}).finally(() => {
|
|
8134
|
+
if (importRequestIdRef.current !== requestId) return;
|
|
8133
8135
|
setImporting(false);
|
|
8134
8136
|
});
|
|
8135
8137
|
}, [providers, selected, onImportComplete]);
|
|
@@ -8170,11 +8172,7 @@ function ImportWizardDialog({
|
|
|
8170
8172
|
),
|
|
8171
8173
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
8172
8174
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
8173
|
-
(
|
|
8174
|
-
const LogoComponent = sourceLogoMap[p.sourceTool];
|
|
8175
|
-
if (LogoComponent === void 0) return null;
|
|
8176
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(LogoComponent, {});
|
|
8177
|
-
})(),
|
|
8175
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ClientLogo, { client: p.sourceTool, className: "size-7 rounded-[8px]" }),
|
|
8178
8176
|
p.alreadyExists && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground", children: "Already added" })
|
|
8179
8177
|
] }),
|
|
8180
8178
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 text-xs leading-snug text-muted-foreground", children: [
|
|
@@ -9848,6 +9846,13 @@ const ModelMetadataRefreshResponseSchema = object({
|
|
|
9848
9846
|
sourceUrl: string()
|
|
9849
9847
|
});
|
|
9850
9848
|
const NETWORK_ERROR_MESSAGE = "Network error: could not reach the server. Is the proxy running?";
|
|
9849
|
+
const CONFIG_PATH_FETCH_TIMEOUT_MS = 5e3;
|
|
9850
|
+
const PROVIDER_TEST_LOG_TIMEOUT_MS = 5e3;
|
|
9851
|
+
const PROVIDER_WRITE_TIMEOUT_MS = 15e3;
|
|
9852
|
+
const PROVIDER_DELETE_TIMEOUT_MS = 1e4;
|
|
9853
|
+
const PROVIDER_EXPORT_TIMEOUT_MS = 2e4;
|
|
9854
|
+
const PROVIDER_IMPORT_TIMEOUT_MS = 2e4;
|
|
9855
|
+
const PROVIDER_METADATA_TIMEOUT_MS = 3e4;
|
|
9851
9856
|
function createProviderPayload(data) {
|
|
9852
9857
|
return {
|
|
9853
9858
|
name: data.name,
|
|
@@ -9871,7 +9876,7 @@ async function persistProviderTestLog(providerId, results) {
|
|
|
9871
9876
|
return;
|
|
9872
9877
|
}
|
|
9873
9878
|
try {
|
|
9874
|
-
await
|
|
9879
|
+
await fetchWithTimeout(`/api/providers/${providerId}/test/log`, PROVIDER_TEST_LOG_TIMEOUT_MS, {
|
|
9875
9880
|
method: "POST",
|
|
9876
9881
|
headers: { "Content-Type": "application/json" },
|
|
9877
9882
|
body: JSON.stringify(results)
|
|
@@ -9939,11 +9944,12 @@ function ProvidersPanel({
|
|
|
9939
9944
|
reactExports.useEffect(() => {
|
|
9940
9945
|
void (async () => {
|
|
9941
9946
|
try {
|
|
9942
|
-
const
|
|
9943
|
-
|
|
9944
|
-
|
|
9945
|
-
|
|
9946
|
-
|
|
9947
|
+
const data = await fetchJsonWithTimeout(
|
|
9948
|
+
"/api/config/paths",
|
|
9949
|
+
ConfigPathsResponseSchema,
|
|
9950
|
+
CONFIG_PATH_FETCH_TIMEOUT_MS
|
|
9951
|
+
);
|
|
9952
|
+
setConfigPath(data.providerConfig);
|
|
9947
9953
|
} catch {
|
|
9948
9954
|
}
|
|
9949
9955
|
})();
|
|
@@ -10017,29 +10023,30 @@ function ProvidersPanel({
|
|
|
10017
10023
|
}
|
|
10018
10024
|
}, 1e3);
|
|
10019
10025
|
try {
|
|
10020
|
-
const
|
|
10021
|
-
|
|
10022
|
-
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
|
|
10026
|
-
|
|
10027
|
-
|
|
10028
|
-
|
|
10026
|
+
const results = await fetchJsonWithTimeout(
|
|
10027
|
+
`/api/providers/${providerId}/test`,
|
|
10028
|
+
ProviderTestResultsSchema,
|
|
10029
|
+
timeoutSeconds * 1e3 + 1e3,
|
|
10030
|
+
{
|
|
10031
|
+
method: "POST",
|
|
10032
|
+
signal: controller.signal
|
|
10033
|
+
},
|
|
10034
|
+
(response) => `HTTP ${response.status}: ${response.statusText}`
|
|
10035
|
+
);
|
|
10036
|
+
updateTestResults(providerId, results);
|
|
10037
|
+
await persistProviderTestLog(providerId, results);
|
|
10038
|
+
} catch (err) {
|
|
10039
|
+
const isAbort = err instanceof Error && err.name === "AbortError";
|
|
10040
|
+
const isTimeout = err instanceof ApiTimeoutError;
|
|
10041
|
+
if (isAbort || isTimeout) {
|
|
10029
10042
|
updateTestResults(
|
|
10030
10043
|
providerId,
|
|
10031
|
-
createFailedProviderTestResults(
|
|
10032
|
-
`HTTP ${res.status}: ${res.statusText}`,
|
|
10033
|
-
"server_error"
|
|
10034
|
-
)
|
|
10044
|
+
createFailedProviderTestResults("Request timed out", "timeout")
|
|
10035
10045
|
);
|
|
10036
|
-
}
|
|
10037
|
-
} catch (err) {
|
|
10038
|
-
const isAbort = err instanceof Error && err.name === "AbortError";
|
|
10039
|
-
if (isAbort) {
|
|
10046
|
+
} else if (err instanceof Error) {
|
|
10040
10047
|
updateTestResults(
|
|
10041
10048
|
providerId,
|
|
10042
|
-
createFailedProviderTestResults(
|
|
10049
|
+
createFailedProviderTestResults(err.message, "server_error")
|
|
10043
10050
|
);
|
|
10044
10051
|
}
|
|
10045
10052
|
} finally {
|
|
@@ -10065,18 +10072,17 @@ function ProvidersPanel({
|
|
|
10065
10072
|
});
|
|
10066
10073
|
try {
|
|
10067
10074
|
const payload = url !== void 0 && url.trim() !== "" ? { url } : {};
|
|
10068
|
-
const
|
|
10069
|
-
|
|
10070
|
-
|
|
10071
|
-
|
|
10072
|
-
|
|
10073
|
-
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
}
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
const data = await parseJsonResponse$1(res, ModelMetadataRefreshResponseSchema);
|
|
10075
|
+
const data = await fetchJsonWithTimeout(
|
|
10076
|
+
`/api/providers/${providerId}/model-metadata`,
|
|
10077
|
+
ModelMetadataRefreshResponseSchema,
|
|
10078
|
+
PROVIDER_METADATA_TIMEOUT_MS,
|
|
10079
|
+
{
|
|
10080
|
+
method: "POST",
|
|
10081
|
+
headers: { "Content-Type": "application/json" },
|
|
10082
|
+
body: JSON.stringify(payload)
|
|
10083
|
+
},
|
|
10084
|
+
() => "Failed to refresh model metadata"
|
|
10085
|
+
);
|
|
10080
10086
|
if (data.imported === 0 && showError) {
|
|
10081
10087
|
setError("No matching model metadata found for this provider.");
|
|
10082
10088
|
} else {
|
|
@@ -10085,9 +10091,9 @@ function ProvidersPanel({
|
|
|
10085
10091
|
triggerHighlight(data.provider.id);
|
|
10086
10092
|
refreshProviders();
|
|
10087
10093
|
return data.imported > 0;
|
|
10088
|
-
} catch {
|
|
10094
|
+
} catch (err) {
|
|
10089
10095
|
if (showError) {
|
|
10090
|
-
setError(NETWORK_ERROR_MESSAGE);
|
|
10096
|
+
setError(err instanceof Error ? err.message : NETWORK_ERROR_MESSAGE);
|
|
10091
10097
|
}
|
|
10092
10098
|
return false;
|
|
10093
10099
|
} finally {
|
|
@@ -10103,16 +10109,17 @@ function ProvidersPanel({
|
|
|
10103
10109
|
function handleAddProvider(data) {
|
|
10104
10110
|
void (async () => {
|
|
10105
10111
|
try {
|
|
10106
|
-
const
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10114
|
-
|
|
10115
|
-
|
|
10112
|
+
const newProvider = await fetchJsonWithTimeout(
|
|
10113
|
+
"/api/providers",
|
|
10114
|
+
ProviderConfigSchema,
|
|
10115
|
+
PROVIDER_WRITE_TIMEOUT_MS,
|
|
10116
|
+
{
|
|
10117
|
+
method: "POST",
|
|
10118
|
+
headers: { "Content-Type": "application/json" },
|
|
10119
|
+
body: JSON.stringify(createProviderPayload(data))
|
|
10120
|
+
},
|
|
10121
|
+
() => "Failed to add provider"
|
|
10122
|
+
);
|
|
10116
10123
|
setShowForm(false);
|
|
10117
10124
|
triggerHighlight(newProvider.id);
|
|
10118
10125
|
if (data.modelMetadataUrl !== void 0 && data.modelMetadataUrl.trim() !== "") {
|
|
@@ -10120,8 +10127,8 @@ function ProvidersPanel({
|
|
|
10120
10127
|
}
|
|
10121
10128
|
refreshProviders();
|
|
10122
10129
|
await runTest(newProvider.id);
|
|
10123
|
-
} catch {
|
|
10124
|
-
setError(NETWORK_ERROR_MESSAGE);
|
|
10130
|
+
} catch (err) {
|
|
10131
|
+
setError(err instanceof Error ? err.message : NETWORK_ERROR_MESSAGE);
|
|
10125
10132
|
}
|
|
10126
10133
|
})();
|
|
10127
10134
|
}
|
|
@@ -10129,16 +10136,17 @@ function ProvidersPanel({
|
|
|
10129
10136
|
if (!editingProvider) return;
|
|
10130
10137
|
void (async () => {
|
|
10131
10138
|
try {
|
|
10132
|
-
const
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10139
|
+
const updated = await fetchJsonWithTimeout(
|
|
10140
|
+
`/api/providers/${editingProvider.id}`,
|
|
10141
|
+
ProviderConfigSchema,
|
|
10142
|
+
PROVIDER_WRITE_TIMEOUT_MS,
|
|
10143
|
+
{
|
|
10144
|
+
method: "PUT",
|
|
10145
|
+
headers: { "Content-Type": "application/json" },
|
|
10146
|
+
body: JSON.stringify(createProviderPayload(data))
|
|
10147
|
+
},
|
|
10148
|
+
() => "Failed to update provider"
|
|
10149
|
+
);
|
|
10142
10150
|
setEditingProvider(void 0);
|
|
10143
10151
|
triggerHighlight(updated.id);
|
|
10144
10152
|
if (data.modelMetadataUrl !== void 0 && data.modelMetadataUrl.trim() !== "") {
|
|
@@ -10149,8 +10157,8 @@ function ProvidersPanel({
|
|
|
10149
10157
|
if (criticalFieldsChanged) {
|
|
10150
10158
|
await runTest(updated.id);
|
|
10151
10159
|
}
|
|
10152
|
-
} catch {
|
|
10153
|
-
setError(NETWORK_ERROR_MESSAGE);
|
|
10160
|
+
} catch (err) {
|
|
10161
|
+
setError(err instanceof Error ? err.message : NETWORK_ERROR_MESSAGE);
|
|
10154
10162
|
}
|
|
10155
10163
|
})();
|
|
10156
10164
|
}
|
|
@@ -10164,7 +10172,7 @@ function ProvidersPanel({
|
|
|
10164
10172
|
void (async () => {
|
|
10165
10173
|
let res;
|
|
10166
10174
|
try {
|
|
10167
|
-
res = await
|
|
10175
|
+
res = await fetchWithTimeout(`/api/providers/${providerId}`, PROVIDER_DELETE_TIMEOUT_MS, {
|
|
10168
10176
|
method: "DELETE"
|
|
10169
10177
|
});
|
|
10170
10178
|
} catch {
|
|
@@ -10183,7 +10191,7 @@ function ProvidersPanel({
|
|
|
10183
10191
|
const url = `/api/providers/export${""}`;
|
|
10184
10192
|
void (async () => {
|
|
10185
10193
|
try {
|
|
10186
|
-
const res = await
|
|
10194
|
+
const res = await fetchWithTimeout(url, PROVIDER_EXPORT_TIMEOUT_MS);
|
|
10187
10195
|
if (!res.ok) {
|
|
10188
10196
|
setError("Failed to export providers");
|
|
10189
10197
|
return;
|
|
@@ -10211,7 +10219,7 @@ function ProvidersPanel({
|
|
|
10211
10219
|
void (async () => {
|
|
10212
10220
|
try {
|
|
10213
10221
|
const text = await file.text();
|
|
10214
|
-
const res = await
|
|
10222
|
+
const res = await fetchWithTimeout("/api/providers/import", PROVIDER_IMPORT_TIMEOUT_MS, {
|
|
10215
10223
|
method: "POST",
|
|
10216
10224
|
headers: { "Content-Type": "application/json" },
|
|
10217
10225
|
body: JSON.stringify(text)
|
|
@@ -10511,6 +10519,7 @@ const LogStorageStatsSchema = object({
|
|
|
10511
10519
|
sessionArchiveFileCount: number(),
|
|
10512
10520
|
sessionArchiveBytes: number()
|
|
10513
10521
|
});
|
|
10522
|
+
const STORAGE_STATS_FETCH_TIMEOUT_MS = 1e4;
|
|
10514
10523
|
function formatBytes(bytes) {
|
|
10515
10524
|
if (bytes < 1024) return `${bytes} B`;
|
|
10516
10525
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
@@ -10526,18 +10535,14 @@ function StorageSettingsTab() {
|
|
|
10526
10535
|
setLoading(true);
|
|
10527
10536
|
setError(null);
|
|
10528
10537
|
try {
|
|
10529
|
-
const
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
setError("Storage stats response was not valid.");
|
|
10538
|
-
return;
|
|
10539
|
-
}
|
|
10540
|
-
setStats(parsed.data);
|
|
10538
|
+
const data = await fetchJsonWithTimeout(
|
|
10539
|
+
"/api/logs?stats=1",
|
|
10540
|
+
LogStorageStatsSchema,
|
|
10541
|
+
STORAGE_STATS_FETCH_TIMEOUT_MS,
|
|
10542
|
+
void 0,
|
|
10543
|
+
(response) => `Failed to load storage stats: HTTP ${String(response.status)}`
|
|
10544
|
+
);
|
|
10545
|
+
setStats(data);
|
|
10541
10546
|
} catch (err) {
|
|
10542
10547
|
setError(err instanceof Error ? err.message : String(err));
|
|
10543
10548
|
} finally {
|
|
@@ -11153,6 +11158,28 @@ const EcosystemPackagesResponseSchema = object({
|
|
|
11153
11158
|
packages: array(EcosystemPackageSchema),
|
|
11154
11159
|
runnerPresets: array(EcosystemRunnerPresetSchema)
|
|
11155
11160
|
});
|
|
11161
|
+
const EcosystemTaskActionSchema = _enum(["install", "upgrade", "help", "runner-presets"]);
|
|
11162
|
+
const EcosystemTaskStatusSchema = _enum(["queued", "running", "succeeded", "failed"]);
|
|
11163
|
+
const EcosystemTaskSchema = object({
|
|
11164
|
+
id: string(),
|
|
11165
|
+
packageId: string(),
|
|
11166
|
+
npmName: string(),
|
|
11167
|
+
action: EcosystemTaskActionSchema,
|
|
11168
|
+
status: EcosystemTaskStatusSchema,
|
|
11169
|
+
command: string(),
|
|
11170
|
+
output: string(),
|
|
11171
|
+
createdAt: string(),
|
|
11172
|
+
startedAt: string().nullable(),
|
|
11173
|
+
finishedAt: string().nullable(),
|
|
11174
|
+
exitCode: number().nullable(),
|
|
11175
|
+
error: string().nullable()
|
|
11176
|
+
});
|
|
11177
|
+
const EcosystemTaskResponseSchema = object({
|
|
11178
|
+
task: EcosystemTaskSchema
|
|
11179
|
+
});
|
|
11180
|
+
object({
|
|
11181
|
+
tasks: array(EcosystemTaskSchema)
|
|
11182
|
+
});
|
|
11156
11183
|
const WORKFLOWS = [
|
|
11157
11184
|
{
|
|
11158
11185
|
id: "observe",
|
|
@@ -11195,6 +11222,23 @@ async function fetchEcosystemPackages(url) {
|
|
|
11195
11222
|
(response) => `Failed to load ecosystem packages: ${String(response.status)}`
|
|
11196
11223
|
);
|
|
11197
11224
|
}
|
|
11225
|
+
async function fetchEcosystemTask(url) {
|
|
11226
|
+
return fetchJson(
|
|
11227
|
+
url,
|
|
11228
|
+
EcosystemTaskResponseSchema,
|
|
11229
|
+
void 0,
|
|
11230
|
+
(response) => `Failed to load ecosystem task: ${String(response.status)}`
|
|
11231
|
+
);
|
|
11232
|
+
}
|
|
11233
|
+
async function startEcosystemTask(packageId, action) {
|
|
11234
|
+
const response = await fetchJson(
|
|
11235
|
+
`/api/ecosystem/packages/${encodeURIComponent(packageId)}/${action}`,
|
|
11236
|
+
EcosystemTaskResponseSchema,
|
|
11237
|
+
{ method: "POST" },
|
|
11238
|
+
(result) => `Failed to start ecosystem task: ${String(result.status)}`
|
|
11239
|
+
);
|
|
11240
|
+
return response.task;
|
|
11241
|
+
}
|
|
11198
11242
|
function stateLabel(state) {
|
|
11199
11243
|
switch (state) {
|
|
11200
11244
|
case "installed":
|
|
@@ -11232,7 +11276,49 @@ function versionLabel(pkg) {
|
|
|
11232
11276
|
if (pkg.latestVersion !== null) return `latest v${pkg.latestVersion}`;
|
|
11233
11277
|
return "not published";
|
|
11234
11278
|
}
|
|
11235
|
-
function
|
|
11279
|
+
function taskActionLabel(action) {
|
|
11280
|
+
switch (action) {
|
|
11281
|
+
case "install":
|
|
11282
|
+
return "Install";
|
|
11283
|
+
case "upgrade":
|
|
11284
|
+
return "Upgrade";
|
|
11285
|
+
case "help":
|
|
11286
|
+
return "Help";
|
|
11287
|
+
case "runner-presets":
|
|
11288
|
+
return "Presets";
|
|
11289
|
+
}
|
|
11290
|
+
}
|
|
11291
|
+
function taskStatusLabel(task) {
|
|
11292
|
+
switch (task.status) {
|
|
11293
|
+
case "queued":
|
|
11294
|
+
return "Queued";
|
|
11295
|
+
case "running":
|
|
11296
|
+
return `${taskActionLabel(task.action)} running`;
|
|
11297
|
+
case "succeeded":
|
|
11298
|
+
return `${taskActionLabel(task.action)} complete`;
|
|
11299
|
+
case "failed":
|
|
11300
|
+
return `${taskActionLabel(task.action)} failed`;
|
|
11301
|
+
}
|
|
11302
|
+
}
|
|
11303
|
+
function packagePrimaryAction(pkg) {
|
|
11304
|
+
switch (pkg.state) {
|
|
11305
|
+
case "available":
|
|
11306
|
+
return "install";
|
|
11307
|
+
case "update-available":
|
|
11308
|
+
return "upgrade";
|
|
11309
|
+
case "installed":
|
|
11310
|
+
case "planned":
|
|
11311
|
+
case "unknown":
|
|
11312
|
+
return null;
|
|
11313
|
+
}
|
|
11314
|
+
}
|
|
11315
|
+
function PackageStatusCard({
|
|
11316
|
+
pkg,
|
|
11317
|
+
activeTask,
|
|
11318
|
+
onStartTask
|
|
11319
|
+
}) {
|
|
11320
|
+
const primaryAction = packagePrimaryAction(pkg);
|
|
11321
|
+
const packageTaskRunning = activeTask !== null && activeTask.packageId === pkg.id && activeTask.status === "running";
|
|
11236
11322
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg bg-white/[0.025] p-3 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]", children: [
|
|
11237
11323
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
|
|
11238
11324
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
|
|
@@ -11249,9 +11335,81 @@ function PackageStatusCard({ pkg }) {
|
|
|
11249
11335
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "rounded bg-white/[0.035] px-2 py-1 font-mono text-white/50", children: versionLabel(pkg) }),
|
|
11250
11336
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "rounded bg-white/[0.035] px-2 py-1 text-white/45", children: pkg.capability }),
|
|
11251
11337
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "rounded bg-white/[0.035] px-2 py-1 font-mono text-white/35", children: pkg.installCommand })
|
|
11338
|
+
] }),
|
|
11339
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
|
|
11340
|
+
primaryAction !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
11341
|
+
Button,
|
|
11342
|
+
{
|
|
11343
|
+
type: "button",
|
|
11344
|
+
size: "sm",
|
|
11345
|
+
variant: "secondary",
|
|
11346
|
+
disabled: packageTaskRunning,
|
|
11347
|
+
onClick: () => onStartTask(pkg.id, primaryAction),
|
|
11348
|
+
children: [
|
|
11349
|
+
packageTaskRunning ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "size-3.5" }),
|
|
11350
|
+
taskActionLabel(primaryAction)
|
|
11351
|
+
]
|
|
11352
|
+
}
|
|
11353
|
+
),
|
|
11354
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
11355
|
+
Button,
|
|
11356
|
+
{
|
|
11357
|
+
type: "button",
|
|
11358
|
+
size: "sm",
|
|
11359
|
+
variant: "outline",
|
|
11360
|
+
disabled: packageTaskRunning || pkg.state === "planned",
|
|
11361
|
+
onClick: () => onStartTask(pkg.id, "help"),
|
|
11362
|
+
children: [
|
|
11363
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { className: "size-3.5" }),
|
|
11364
|
+
"Help"
|
|
11365
|
+
]
|
|
11366
|
+
}
|
|
11367
|
+
),
|
|
11368
|
+
pkg.id === "eval-harness" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
11369
|
+
Button,
|
|
11370
|
+
{
|
|
11371
|
+
type: "button",
|
|
11372
|
+
size: "sm",
|
|
11373
|
+
variant: "ghost",
|
|
11374
|
+
disabled: packageTaskRunning || pkg.state === "planned",
|
|
11375
|
+
onClick: () => onStartTask(pkg.id, "runner-presets"),
|
|
11376
|
+
children: [
|
|
11377
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Beaker, { className: "size-3.5" }),
|
|
11378
|
+
"Presets"
|
|
11379
|
+
]
|
|
11380
|
+
}
|
|
11381
|
+
)
|
|
11252
11382
|
] })
|
|
11253
11383
|
] });
|
|
11254
11384
|
}
|
|
11385
|
+
function TaskConsole({ task }) {
|
|
11386
|
+
if (task === null) return null;
|
|
11387
|
+
const isRunning = task.status === "queued" || task.status === "running";
|
|
11388
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "mt-3 rounded-lg bg-white/[0.025] p-3 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]", children: [
|
|
11389
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
|
|
11390
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
11391
|
+
isRunning ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin text-cyan-200/75" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { className: "size-4 text-white/55" }),
|
|
11392
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
|
|
11393
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-semibold", children: taskStatusLabel(task) }),
|
|
11394
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "break-all font-mono text-[11px] text-white/35", children: task.command })
|
|
11395
|
+
] })
|
|
11396
|
+
] }),
|
|
11397
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
11398
|
+
Badge,
|
|
11399
|
+
{
|
|
11400
|
+
variant: "outline",
|
|
11401
|
+
className: cn(
|
|
11402
|
+
"shrink-0",
|
|
11403
|
+
task.status === "failed" ? "border-red-400/20 bg-red-400/8 text-red-100" : "border-cyan-300/20 bg-cyan-300/8 text-cyan-100"
|
|
11404
|
+
),
|
|
11405
|
+
children: task.status
|
|
11406
|
+
}
|
|
11407
|
+
)
|
|
11408
|
+
] }),
|
|
11409
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "mt-3 max-h-56 overflow-auto whitespace-pre-wrap rounded-md bg-black/30 p-3 font-mono text-[11px] leading-5 text-white/60 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]", children: task.output.trim().length > 0 ? task.output : "Waiting for npm output..." }),
|
|
11410
|
+
task.error !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 text-xs text-red-100", children: task.error })
|
|
11411
|
+
] });
|
|
11412
|
+
}
|
|
11255
11413
|
function WorkflowTile({ workflow }) {
|
|
11256
11414
|
const Icon2 = workflow.icon;
|
|
11257
11415
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg bg-white/[0.025] p-3 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]", children: [
|
|
@@ -11307,10 +11465,23 @@ function AgentLabDialog({ currentSessionId, logCount }) {
|
|
|
11307
11465
|
const [open, setOpen] = reactExports.useState(false);
|
|
11308
11466
|
const [copied, setCopied] = reactExports.useState(false);
|
|
11309
11467
|
const [copiedPresets, setCopiedPresets] = reactExports.useState(false);
|
|
11468
|
+
const [activeTaskId, setActiveTaskId] = reactExports.useState(null);
|
|
11469
|
+
const [taskError, setTaskError] = reactExports.useState(null);
|
|
11310
11470
|
const response = useSWR("/api/ecosystem/packages", fetchEcosystemPackages, {
|
|
11311
11471
|
revalidateOnFocus: false,
|
|
11312
11472
|
revalidateIfStale: false
|
|
11313
11473
|
});
|
|
11474
|
+
const activeTaskResponse = useSWR(
|
|
11475
|
+
activeTaskId === null ? null : `/api/ecosystem/tasks/${activeTaskId}`,
|
|
11476
|
+
fetchEcosystemTask,
|
|
11477
|
+
{
|
|
11478
|
+
refreshInterval: (taskResponse) => {
|
|
11479
|
+
const task = taskResponse?.task;
|
|
11480
|
+
return task !== void 0 && (task.status === "queued" || task.status === "running") ? 900 : 0;
|
|
11481
|
+
},
|
|
11482
|
+
revalidateOnFocus: false
|
|
11483
|
+
}
|
|
11484
|
+
);
|
|
11314
11485
|
const packages = response.data?.packages ?? [];
|
|
11315
11486
|
const runnerPresets = response.data?.runnerPresets ?? [];
|
|
11316
11487
|
const installedCount = reactExports.useMemo(
|
|
@@ -11331,6 +11502,21 @@ function AgentLabDialog({ currentSessionId, logCount }) {
|
|
|
11331
11502
|
window.setTimeout(() => setCopiedPresets(false), 1200);
|
|
11332
11503
|
});
|
|
11333
11504
|
};
|
|
11505
|
+
const activeTask = activeTaskResponse.data?.task ?? null;
|
|
11506
|
+
reactExports.useEffect(() => {
|
|
11507
|
+
if (activeTask === null) return;
|
|
11508
|
+
if (activeTask.status !== "succeeded") return;
|
|
11509
|
+
void response.mutate();
|
|
11510
|
+
}, [activeTask, response]);
|
|
11511
|
+
const handleStartTask = (packageId, action) => {
|
|
11512
|
+
setTaskError(null);
|
|
11513
|
+
void startEcosystemTask(packageId, action).then((task) => {
|
|
11514
|
+
setActiveTaskId(task.id);
|
|
11515
|
+
void activeTaskResponse.mutate({ task }, { revalidate: true });
|
|
11516
|
+
}).catch((error) => {
|
|
11517
|
+
setTaskError(error instanceof Error ? error.message : "Failed to start ecosystem task");
|
|
11518
|
+
});
|
|
11519
|
+
};
|
|
11334
11520
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Dialog, { open, onOpenChange: setOpen, children: [
|
|
11335
11521
|
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
11336
11522
|
Button,
|
|
@@ -11418,7 +11604,15 @@ function AgentLabDialog({ currentSessionId, logCount }) {
|
|
|
11418
11604
|
] }),
|
|
11419
11605
|
response.error !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-lg bg-red-500/8 p-3 text-xs text-red-100 shadow-[inset_0_0_0_1px_rgba(248,113,113,0.16)]", children: "Package status is temporarily unavailable." }),
|
|
11420
11606
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-3 md:grid-cols-3", children: [
|
|
11421
|
-
packages.map((pkg) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
11607
|
+
packages.map((pkg) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
11608
|
+
PackageStatusCard,
|
|
11609
|
+
{
|
|
11610
|
+
pkg,
|
|
11611
|
+
activeTask,
|
|
11612
|
+
onStartTask: handleStartTask
|
|
11613
|
+
},
|
|
11614
|
+
pkg.id
|
|
11615
|
+
)),
|
|
11422
11616
|
response.isLoading && packages.length === 0 && [0, 1, 2].map((index) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
11423
11617
|
"div",
|
|
11424
11618
|
{
|
|
@@ -11427,7 +11621,9 @@ function AgentLabDialog({ currentSessionId, logCount }) {
|
|
|
11427
11621
|
index
|
|
11428
11622
|
))
|
|
11429
11623
|
] })
|
|
11430
|
-
] })
|
|
11624
|
+
] }),
|
|
11625
|
+
taskError !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-3 rounded-lg bg-red-500/8 p-3 text-xs text-red-100 shadow-[inset_0_0_0_1px_rgba(248,113,113,0.16)]", children: taskError }),
|
|
11626
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TaskConsole, { task: activeTask })
|
|
11431
11627
|
] })
|
|
11432
11628
|
] })
|
|
11433
11629
|
] });
|
|
@@ -13592,6 +13788,36 @@ function LogPaginationButton({
|
|
|
13592
13788
|
}
|
|
13593
13789
|
);
|
|
13594
13790
|
}
|
|
13791
|
+
function formatDurationSeconds(ms) {
|
|
13792
|
+
return `${Math.max(0, Math.ceil(ms / 1e3)).toString()}s`;
|
|
13793
|
+
}
|
|
13794
|
+
function SessionLoadProgressBar({ progress }) {
|
|
13795
|
+
const elapsedRatio = Math.min(1, progress.elapsedMs / progress.timeoutMs);
|
|
13796
|
+
const percent = Math.max(4, Math.round(elapsedRatio * 100));
|
|
13797
|
+
const remainingMs = Math.max(0, progress.timeoutMs - progress.elapsedMs);
|
|
13798
|
+
const nearTimeout = elapsedRatio >= 0.75;
|
|
13799
|
+
const details = [
|
|
13800
|
+
progress.loadedLogs > 0 ? `${progress.loadedLogs.toString()} logs` : null,
|
|
13801
|
+
progress.loadedPages > 0 ? `${progress.loadedPages.toString()} page${progress.loadedPages === 1 ? "" : "s"}` : null,
|
|
13802
|
+
`${formatDurationSeconds(remainingMs)} before timeout`
|
|
13803
|
+
].filter((item) => item !== null);
|
|
13804
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 space-y-1 px-1 pb-1", children: [
|
|
13805
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center justify-between gap-3 font-mono text-[10px] text-muted-foreground", children: [
|
|
13806
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 truncate", children: progress.label }),
|
|
13807
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn("shrink-0 tabular-nums", nearTimeout && "text-amber-300"), children: details.join(" / ") })
|
|
13808
|
+
] }),
|
|
13809
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-1.5 overflow-hidden rounded-full bg-white/[0.06]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13810
|
+
"div",
|
|
13811
|
+
{
|
|
13812
|
+
className: cn(
|
|
13813
|
+
"h-full rounded-full transition-all duration-300",
|
|
13814
|
+
nearTimeout ? "bg-amber-300/80" : "bg-cyan-300/70"
|
|
13815
|
+
),
|
|
13816
|
+
style: { width: `${percent.toString()}%` }
|
|
13817
|
+
}
|
|
13818
|
+
) })
|
|
13819
|
+
] });
|
|
13820
|
+
}
|
|
13595
13821
|
function LogPaginationBar({
|
|
13596
13822
|
logs,
|
|
13597
13823
|
pagination,
|
|
@@ -13609,7 +13835,8 @@ function LogPaginationBar({
|
|
|
13609
13835
|
children: [
|
|
13610
13836
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full min-w-0 px-1 font-mono text-[11px] text-muted-foreground sm:flex-1", children: [
|
|
13611
13837
|
formatPaginationStatus({ logs, pagination }),
|
|
13612
|
-
pagination.isLoading && logs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-2", children: "Loading..." })
|
|
13838
|
+
pagination.isLoading && logs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-2", children: "Loading..." }),
|
|
13839
|
+
pagination.loadProgress !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(SessionLoadProgressBar, { progress: pagination.loadProgress })
|
|
13613
13840
|
] }),
|
|
13614
13841
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex w-full items-center gap-1 overflow-x-auto sm:w-auto", children: [
|
|
13615
13842
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -13747,16 +13974,6 @@ function CopyableCommand({ command }) {
|
|
|
13747
13974
|
)
|
|
13748
13975
|
] });
|
|
13749
13976
|
}
|
|
13750
|
-
function McpReadyBadge() {
|
|
13751
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
13752
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "bg-cyan-300/[0.055] shadow-[inset_0_1px_0_rgba(255,255,255,0.05)] inline-flex h-7 items-center gap-2 rounded-md px-2.5 font-mono text-[11px] font-medium text-cyan-200", children: [
|
|
13753
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "size-1.5 rounded-full bg-cyan-200 shadow-[0_0_8px_rgba(125,211,252,0.75)]" }),
|
|
13754
|
-
"MCP Ready",
|
|
13755
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "hidden text-cyan-200/70 sm:inline", children: "/api/mcp" })
|
|
13756
|
-
] }) }),
|
|
13757
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { sideOffset: 8, className: "max-w-[320px] text-left leading-relaxed", children: "Coding agents can inspect logs, replay requests, test providers, and debug sessions through MCP at /api/mcp." })
|
|
13758
|
-
] }) });
|
|
13759
|
-
}
|
|
13760
13977
|
function SidebarPanel({
|
|
13761
13978
|
label,
|
|
13762
13979
|
children,
|
|
@@ -13801,7 +14018,7 @@ function CrabFamily({
|
|
|
13801
14018
|
entrancePhase
|
|
13802
14019
|
}) {
|
|
13803
14020
|
if (compact) {
|
|
13804
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-
|
|
14021
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-14 text-amber-500" });
|
|
13805
14022
|
}
|
|
13806
14023
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex shrink-0 items-end gap-1 group cursor-default", "aria-hidden": "true", children: [
|
|
13807
14024
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-10 text-amber-500 transition-all duration-300 group-hover:scale-125 group-hover:-translate-y-1.5" }),
|
|
@@ -13829,30 +14046,27 @@ function BrandHeader({
|
|
|
13829
14046
|
logCount
|
|
13830
14047
|
}) {
|
|
13831
14048
|
if (compact) {
|
|
13832
|
-
return /* @__PURE__ */ jsxRuntimeExports.
|
|
13833
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex
|
|
13834
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
13835
|
-
|
|
13836
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-fit", children: [
|
|
13837
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
|
|
13844
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "hidden text-[11px] font-semibold text-muted-foreground sm:block", children: "Local First. Evidence First." })
|
|
13845
|
-
] })
|
|
13846
|
-
] }),
|
|
13847
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
13848
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(AlertsDialog, {}),
|
|
13849
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(GroupsDialog, {}),
|
|
13850
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(AgentLabDialog, { currentSessionId, logCount }),
|
|
13851
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {})
|
|
14049
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("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", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
|
|
14050
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-fit items-start gap-3", children: [
|
|
14051
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CrabFamily, { compact: true, entrancePhase: crabEntrancePhase }),
|
|
14052
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-fit", children: [
|
|
14053
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-fit flex-wrap items-baseline gap-x-2 gap-y-0.5", children: [
|
|
14054
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "whitespace-nowrap text-base font-bold", children: "Agent Inspector" }),
|
|
14055
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "hidden shrink-0 font-mono text-[11px] font-semibold text-muted-foreground sm:inline", children: [
|
|
14056
|
+
"v",
|
|
14057
|
+
packageJson.version
|
|
14058
|
+
] })
|
|
14059
|
+
] }),
|
|
14060
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "hidden text-[11px] font-semibold text-muted-foreground sm:block", children: "Local First. Evidence First." })
|
|
13852
14061
|
] })
|
|
13853
14062
|
] }),
|
|
13854
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
13855
|
-
|
|
14063
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
14064
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(AlertsDialog, {}),
|
|
14065
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(GroupsDialog, {}),
|
|
14066
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(AgentLabDialog, { currentSessionId, logCount }),
|
|
14067
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {})
|
|
14068
|
+
] })
|
|
14069
|
+
] }) });
|
|
13856
14070
|
}
|
|
13857
14071
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-x-4 gap-y-3 pb-6", children: [
|
|
13858
14072
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-w-10 flex-1", "aria-hidden": "true" }),
|
|
@@ -13869,8 +14083,7 @@ function BrandHeader({
|
|
|
13869
14083
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "size-4 shrink-0 text-muted-foreground/70", "aria-hidden": "true" }),
|
|
13870
14084
|
/* @__PURE__ */ jsxRuntimeExports.jsx(McpLogo, { className: "size-10 shrink-0" })
|
|
13871
14085
|
] }),
|
|
13872
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "max-w-full text-sm font-semibold text-muted-foreground", children: "Local First. Evidence First." })
|
|
13873
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(McpReadyBadge, {})
|
|
14086
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "max-w-full text-sm font-semibold text-muted-foreground", children: "Local First. Evidence First." })
|
|
13874
14087
|
] }),
|
|
13875
14088
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 justify-end gap-1", children: [
|
|
13876
14089
|
/* @__PURE__ */ jsxRuntimeExports.jsx(AlertsDialog, {}),
|
|
@@ -14177,6 +14390,7 @@ function ProxyViewer({
|
|
|
14177
14390
|
onSessionChange,
|
|
14178
14391
|
onModelChange,
|
|
14179
14392
|
onClearAll,
|
|
14393
|
+
onDeleteCurrentView,
|
|
14180
14394
|
onReloadSession,
|
|
14181
14395
|
onClearGroup,
|
|
14182
14396
|
onNotify,
|
|
@@ -14188,6 +14402,7 @@ function ProxyViewer({
|
|
|
14188
14402
|
timeDisplayFormat,
|
|
14189
14403
|
isLoading = false,
|
|
14190
14404
|
pagination,
|
|
14405
|
+
sessionLoadProgress,
|
|
14191
14406
|
sessionMemberships = [],
|
|
14192
14407
|
hideSessionFilter = false,
|
|
14193
14408
|
pinnedSessionId
|
|
@@ -14199,6 +14414,9 @@ function ProxyViewer({
|
|
|
14199
14414
|
const [importing, setImporting] = reactExports.useState(false);
|
|
14200
14415
|
const [importStatus, setImportStatus] = reactExports.useState(null);
|
|
14201
14416
|
const [importError, setImportError] = reactExports.useState(null);
|
|
14417
|
+
const [deleteDialogOpen, setDeleteDialogOpen] = reactExports.useState(false);
|
|
14418
|
+
const [deleteStoredData, setDeleteStoredData] = reactExports.useState(false);
|
|
14419
|
+
const [deletingCurrentView, setDeletingCurrentView] = reactExports.useState(false);
|
|
14202
14420
|
const [comparePair, setComparePair] = reactExports.useState(null);
|
|
14203
14421
|
const [crabEntrancePhase, setCrabEntrancePhase] = reactExports.useState(
|
|
14204
14422
|
"hidden"
|
|
@@ -14206,7 +14424,24 @@ function ProxyViewer({
|
|
|
14206
14424
|
const logListRef = reactExports.useRef(null);
|
|
14207
14425
|
const logListWrapperRef = reactExports.useRef(null);
|
|
14208
14426
|
const importInputRef = reactExports.useRef(null);
|
|
14427
|
+
const exportAbortRef = reactExports.useRef(null);
|
|
14428
|
+
const exportRequestIdRef = reactExports.useRef(0);
|
|
14209
14429
|
useKeyboardNavigation(logListRef, logListWrapperRef, { pageWide: true });
|
|
14430
|
+
const cancelTransientTasks = reactExports.useCallback(() => {
|
|
14431
|
+
exportRequestIdRef.current += 1;
|
|
14432
|
+
exportAbortRef.current?.abort();
|
|
14433
|
+
exportAbortRef.current = null;
|
|
14434
|
+
setExporting(null);
|
|
14435
|
+
setExportError(null);
|
|
14436
|
+
}, []);
|
|
14437
|
+
reactExports.useEffect(
|
|
14438
|
+
() => () => {
|
|
14439
|
+
exportRequestIdRef.current += 1;
|
|
14440
|
+
exportAbortRef.current?.abort();
|
|
14441
|
+
exportAbortRef.current = null;
|
|
14442
|
+
},
|
|
14443
|
+
[]
|
|
14444
|
+
);
|
|
14210
14445
|
reactExports.useEffect(() => {
|
|
14211
14446
|
const perCrabDuration = 400;
|
|
14212
14447
|
const startDelay = 50;
|
|
@@ -14228,11 +14463,18 @@ function ProxyViewer({
|
|
|
14228
14463
|
}, [logs.length, pinnedSessionId]);
|
|
14229
14464
|
const handleExport = reactExports.useCallback(
|
|
14230
14465
|
async (mode) => {
|
|
14466
|
+
exportAbortRef.current?.abort();
|
|
14467
|
+
const controller = new AbortController();
|
|
14468
|
+
exportAbortRef.current = controller;
|
|
14469
|
+
const requestId = exportRequestIdRef.current + 1;
|
|
14470
|
+
exportRequestIdRef.current = requestId;
|
|
14231
14471
|
setExporting(mode);
|
|
14232
14472
|
setExportError(null);
|
|
14233
14473
|
try {
|
|
14234
|
-
const result = await exportLogsAsZip(logs, mode);
|
|
14474
|
+
const result = await exportLogsAsZip(logs, mode, { signal: controller.signal });
|
|
14475
|
+
if (exportRequestIdRef.current !== requestId) return;
|
|
14235
14476
|
if (!result.ok) {
|
|
14477
|
+
if (result.canceled === true) return;
|
|
14236
14478
|
if (onNotify !== void 0) {
|
|
14237
14479
|
onNotify({ message: result.message, tone: "error" });
|
|
14238
14480
|
} else {
|
|
@@ -14240,7 +14482,10 @@ function ProxyViewer({
|
|
|
14240
14482
|
}
|
|
14241
14483
|
}
|
|
14242
14484
|
} finally {
|
|
14243
|
-
|
|
14485
|
+
if (exportRequestIdRef.current === requestId) {
|
|
14486
|
+
exportAbortRef.current = null;
|
|
14487
|
+
setExporting(null);
|
|
14488
|
+
}
|
|
14244
14489
|
}
|
|
14245
14490
|
},
|
|
14246
14491
|
[logs, onNotify]
|
|
@@ -14278,8 +14523,52 @@ function ProxyViewer({
|
|
|
14278
14523
|
[onImportLogs, onNotify]
|
|
14279
14524
|
);
|
|
14280
14525
|
reactExports.useEffect(() => {
|
|
14526
|
+
cancelTransientTasks();
|
|
14527
|
+
setComparePair(null);
|
|
14528
|
+
}, [cancelTransientTasks, selectedSession, selectedModel]);
|
|
14529
|
+
const handleClearCurrentView = reactExports.useCallback(() => {
|
|
14530
|
+
cancelTransientTasks();
|
|
14531
|
+
setImportStatus(null);
|
|
14532
|
+
setImportError(null);
|
|
14533
|
+
setComparePair(null);
|
|
14534
|
+
onClearAll();
|
|
14535
|
+
}, [cancelTransientTasks, onClearAll]);
|
|
14536
|
+
const handleRequestDeleteCurrentView = reactExports.useCallback(() => {
|
|
14537
|
+
setDeleteStoredData(false);
|
|
14538
|
+
setDeleteDialogOpen(true);
|
|
14539
|
+
}, []);
|
|
14540
|
+
const handleConfirmDeleteCurrentView = reactExports.useCallback(() => {
|
|
14541
|
+
cancelTransientTasks();
|
|
14542
|
+
setImportStatus(null);
|
|
14543
|
+
setImportError(null);
|
|
14544
|
+
setComparePair(null);
|
|
14545
|
+
if (!deleteStoredData || onDeleteCurrentView === void 0) {
|
|
14546
|
+
setDeleteDialogOpen(false);
|
|
14547
|
+
onClearAll();
|
|
14548
|
+
return;
|
|
14549
|
+
}
|
|
14550
|
+
setDeletingCurrentView(true);
|
|
14551
|
+
void onDeleteCurrentView(logs.map((log) => log.id)).then(() => {
|
|
14552
|
+
setDeleteDialogOpen(false);
|
|
14553
|
+
}).catch((err) => {
|
|
14554
|
+
const message = err instanceof Error ? err.message : "Failed to delete stored logs";
|
|
14555
|
+
if (onNotify !== void 0) {
|
|
14556
|
+
onNotify({ message, tone: "error" });
|
|
14557
|
+
} else {
|
|
14558
|
+
setImportError(message);
|
|
14559
|
+
}
|
|
14560
|
+
}).finally(() => {
|
|
14561
|
+
setDeletingCurrentView(false);
|
|
14562
|
+
});
|
|
14563
|
+
}, [cancelTransientTasks, deleteStoredData, logs, onClearAll, onDeleteCurrentView, onNotify]);
|
|
14564
|
+
const handleReloadCurrentSession = reactExports.useCallback(() => {
|
|
14565
|
+
if (onReloadSession === void 0) return;
|
|
14566
|
+
cancelTransientTasks();
|
|
14567
|
+
setImportStatus(null);
|
|
14568
|
+
setImportError(null);
|
|
14281
14569
|
setComparePair(null);
|
|
14282
|
-
|
|
14570
|
+
onReloadSession();
|
|
14571
|
+
}, [cancelTransientTasks, onReloadSession]);
|
|
14283
14572
|
const closeCompare = reactExports.useCallback(() => {
|
|
14284
14573
|
setComparePair(null);
|
|
14285
14574
|
}, []);
|
|
@@ -14376,7 +14665,7 @@ function ProxyViewer({
|
|
|
14376
14665
|
"button",
|
|
14377
14666
|
{
|
|
14378
14667
|
type: "button",
|
|
14379
|
-
onClick:
|
|
14668
|
+
onClick: handleReloadCurrentSession,
|
|
14380
14669
|
disabled: isLoading,
|
|
14381
14670
|
className: "bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 min-w-0 items-center justify-center gap-1.5 rounded-md px-2 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",
|
|
14382
14671
|
title: "Load stored logs for this session",
|
|
@@ -14390,20 +14679,35 @@ function ProxyViewer({
|
|
|
14390
14679
|
"button",
|
|
14391
14680
|
{
|
|
14392
14681
|
type: "button",
|
|
14393
|
-
onClick:
|
|
14682
|
+
onClick: handleClearCurrentView,
|
|
14394
14683
|
disabled: !canClearCurrentView,
|
|
14395
14684
|
className: cn(
|
|
14396
14685
|
"bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 min-w-0 items-center justify-center gap-1.5 rounded-md px-2 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",
|
|
14397
|
-
onReloadSession === void 0 && "col-span-2"
|
|
14686
|
+
onReloadSession === void 0 && onDeleteCurrentView === void 0 && "col-span-2"
|
|
14398
14687
|
),
|
|
14399
14688
|
title: "Clear the current view. Stored logs remain reloadable.",
|
|
14400
14689
|
children: [
|
|
14401
14690
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" }),
|
|
14402
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Clear
|
|
14691
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Clear" })
|
|
14692
|
+
]
|
|
14693
|
+
}
|
|
14694
|
+
),
|
|
14695
|
+
onDeleteCurrentView !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14696
|
+
"button",
|
|
14697
|
+
{
|
|
14698
|
+
type: "button",
|
|
14699
|
+
onClick: handleRequestDeleteCurrentView,
|
|
14700
|
+
disabled: !canClearCurrentView || deletingCurrentView,
|
|
14701
|
+
className: "bg-red-500/[0.07] hover:bg-red-500/[0.12] inline-flex h-8 min-w-0 items-center justify-center gap-1.5 rounded-md px-2 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",
|
|
14702
|
+
title: "Choose whether to delete stored data for the current view.",
|
|
14703
|
+
children: [
|
|
14704
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" }),
|
|
14705
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Delete" })
|
|
14403
14706
|
]
|
|
14404
14707
|
}
|
|
14405
14708
|
)
|
|
14406
|
-
] })
|
|
14709
|
+
] }),
|
|
14710
|
+
sessionLoadProgress !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 rounded-md bg-black/20 px-2 py-2 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SessionLoadProgressBar, { progress: sessionLoadProgress }) })
|
|
14407
14711
|
] }),
|
|
14408
14712
|
/* @__PURE__ */ jsxRuntimeExports.jsx(SidebarPanel, { label: "Workspace", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-black/20 rounded-md px-3 py-2 shadow-[inset_0_1px_0_rgba(255,255,255,0.035)]", children: [
|
|
14409
14713
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -14547,7 +14851,7 @@ function ProxyViewer({
|
|
|
14547
14851
|
"button",
|
|
14548
14852
|
{
|
|
14549
14853
|
type: "button",
|
|
14550
|
-
onClick:
|
|
14854
|
+
onClick: handleReloadCurrentSession,
|
|
14551
14855
|
disabled: isLoading,
|
|
14552
14856
|
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",
|
|
14553
14857
|
title: "Reload this session from stored logs",
|
|
@@ -14561,17 +14865,32 @@ function ProxyViewer({
|
|
|
14561
14865
|
"button",
|
|
14562
14866
|
{
|
|
14563
14867
|
type: "button",
|
|
14564
|
-
onClick:
|
|
14868
|
+
onClick: handleClearCurrentView,
|
|
14565
14869
|
disabled: !canClearCurrentView,
|
|
14566
14870
|
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",
|
|
14567
14871
|
title: "Clear the current view. Stored logs remain reloadable.",
|
|
14568
14872
|
children: [
|
|
14569
14873
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" }),
|
|
14570
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Clear
|
|
14874
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Clear" })
|
|
14875
|
+
]
|
|
14876
|
+
}
|
|
14877
|
+
),
|
|
14878
|
+
onDeleteCurrentView !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14879
|
+
"button",
|
|
14880
|
+
{
|
|
14881
|
+
type: "button",
|
|
14882
|
+
onClick: handleRequestDeleteCurrentView,
|
|
14883
|
+
disabled: !canClearCurrentView || deletingCurrentView,
|
|
14884
|
+
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",
|
|
14885
|
+
title: "Choose whether to delete stored data for the current view.",
|
|
14886
|
+
children: [
|
|
14887
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" }),
|
|
14888
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Delete" })
|
|
14571
14889
|
]
|
|
14572
14890
|
}
|
|
14573
14891
|
)
|
|
14574
14892
|
] }),
|
|
14893
|
+
pagination === void 0 && sessionLoadProgress !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 rounded-md bg-black/20 px-2 py-2 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SessionLoadProgressBar, { progress: sessionLoadProgress }) }),
|
|
14575
14894
|
/* @__PURE__ */ jsxRuntimeExports.jsx(LogPaginationBar, { logs, pagination, embedded: true }),
|
|
14576
14895
|
onNotify === void 0 && exportError !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: exportError }),
|
|
14577
14896
|
onNotify === void 0 && importError !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: importError }),
|
|
@@ -14582,6 +14901,7 @@ function ProxyViewer({
|
|
|
14582
14901
|
logs.length === 0 ? selectedSession !== "__all__" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "py-16 text-center text-muted-foreground", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("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", children: [
|
|
14583
14902
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium", children: isLoading ? "Loading session data..." : "No logs loaded for this session" }),
|
|
14584
14903
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "inline-block max-w-full rounded bg-muted px-3 py-1 font-mono text-xs break-all", children: truncateSessionId(selectedSession) }),
|
|
14904
|
+
sessionLoadProgress !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto max-w-md rounded-md bg-black/20 px-2 py-2 text-left shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SessionLoadProgressBar, { progress: sessionLoadProgress }) }),
|
|
14585
14905
|
sessionMemberships.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-left", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SessionMembershipPanel, { memberships: sessionMemberships }) }),
|
|
14586
14906
|
!isLoading && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-3 text-xs", children: [
|
|
14587
14907
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Stored logs may still be available." }),
|
|
@@ -14590,7 +14910,7 @@ function ProxyViewer({
|
|
|
14590
14910
|
"button",
|
|
14591
14911
|
{
|
|
14592
14912
|
type: "button",
|
|
14593
|
-
onClick:
|
|
14913
|
+
onClick: handleReloadCurrentSession,
|
|
14594
14914
|
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",
|
|
14595
14915
|
children: [
|
|
14596
14916
|
/* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "size-3.5" }),
|
|
@@ -14653,6 +14973,59 @@ function ProxyViewer({
|
|
|
14653
14973
|
] })
|
|
14654
14974
|
] })
|
|
14655
14975
|
] }),
|
|
14976
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open: deleteDialogOpen, onOpenChange: setDeleteDialogOpen, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { className: "border-red-500/20 bg-zinc-950 text-zinc-100 sm:max-w-md", children: [
|
|
14977
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(DialogHeader, { children: [
|
|
14978
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogTitle, { children: "Delete current logs?" }),
|
|
14979
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogDescription, { children: "Choose whether this only clears the UI or also deletes the stored log data for the current view." })
|
|
14980
|
+
] }),
|
|
14981
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-start gap-3 rounded-md bg-red-500/[0.08] px-3 py-3 text-sm text-red-100 shadow-[inset_0_0_0_1px_rgba(248,113,113,0.16)]", children: [
|
|
14982
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14983
|
+
"input",
|
|
14984
|
+
{
|
|
14985
|
+
type: "checkbox",
|
|
14986
|
+
className: "mt-0.5 size-4 shrink-0",
|
|
14987
|
+
checked: deleteStoredData,
|
|
14988
|
+
disabled: deletingCurrentView,
|
|
14989
|
+
onChange: (event) => setDeleteStoredData(event.currentTarget.checked)
|
|
14990
|
+
}
|
|
14991
|
+
),
|
|
14992
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "min-w-0", children: [
|
|
14993
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block font-medium", children: "Also delete stored data" }),
|
|
14994
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "mt-1 block text-xs text-red-200/80", children: [
|
|
14995
|
+
"Removes persisted log rows, streaming chunks, and session archive entries for these",
|
|
14996
|
+
" ",
|
|
14997
|
+
logs.length.toString(),
|
|
14998
|
+
" visible request",
|
|
14999
|
+
logs.length === 1 ? "" : "s",
|
|
15000
|
+
"."
|
|
15001
|
+
] })
|
|
15002
|
+
] })
|
|
15003
|
+
] }),
|
|
15004
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
15005
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
15006
|
+
Button,
|
|
15007
|
+
{
|
|
15008
|
+
type: "button",
|
|
15009
|
+
variant: "outline",
|
|
15010
|
+
size: "sm",
|
|
15011
|
+
disabled: deletingCurrentView,
|
|
15012
|
+
onClick: () => setDeleteDialogOpen(false),
|
|
15013
|
+
children: "Cancel"
|
|
15014
|
+
}
|
|
15015
|
+
),
|
|
15016
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
15017
|
+
Button,
|
|
15018
|
+
{
|
|
15019
|
+
type: "button",
|
|
15020
|
+
variant: deleteStoredData ? "destructive" : "secondary",
|
|
15021
|
+
size: "sm",
|
|
15022
|
+
disabled: deletingCurrentView,
|
|
15023
|
+
onClick: handleConfirmDeleteCurrentView,
|
|
15024
|
+
children: deletingCurrentView ? "Deleting..." : deleteStoredData ? "Delete data" : "Clear only"
|
|
15025
|
+
}
|
|
15026
|
+
)
|
|
15027
|
+
] })
|
|
15028
|
+
] }) }),
|
|
14656
15029
|
comparePair !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14657
15030
|
LazyCompareDrawer,
|
|
14658
15031
|
{
|
|
@@ -14685,6 +15058,13 @@ const LogCursorPageSchema = object({
|
|
|
14685
15058
|
newestLogId: number().int().positive().nullable()
|
|
14686
15059
|
});
|
|
14687
15060
|
const SessionsResponseSchema = array(string());
|
|
15061
|
+
const DeleteLogsResponseSchema = object({
|
|
15062
|
+
success: boolean(),
|
|
15063
|
+
cleared: number().int().nonnegative(),
|
|
15064
|
+
logFilesRewritten: number().int().nonnegative().optional(),
|
|
15065
|
+
chunkFilesDeleted: number().int().nonnegative(),
|
|
15066
|
+
sessionArchiveLogsDeleted: number().int().nonnegative().optional()
|
|
15067
|
+
});
|
|
14688
15068
|
function buildSessionMembershipEvidence(groups, sessionId) {
|
|
14689
15069
|
const memberships = [];
|
|
14690
15070
|
for (const group of groups) {
|
|
@@ -14732,6 +15112,8 @@ const HASH_HIGHLIGHT_MS = 1800;
|
|
|
14732
15112
|
const SESSION_PAGE_LIMIT = 100;
|
|
14733
15113
|
const SESSION_RELOAD_PAGE_LIMIT = 500;
|
|
14734
15114
|
const MAX_SESSION_RELOAD_PAGES = 200;
|
|
15115
|
+
const SESSION_LOGS_FETCH_TIMEOUT_MS = 2e4;
|
|
15116
|
+
const SESSION_MEMBERSHIP_FETCH_TIMEOUT_MS = 1e4;
|
|
14735
15117
|
function buildLogsStreamUrl(sessionId) {
|
|
14736
15118
|
const params = new URLSearchParams();
|
|
14737
15119
|
if (sessionId !== void 0) {
|
|
@@ -14769,6 +15151,13 @@ function buildLogIndex(logs) {
|
|
|
14769
15151
|
}
|
|
14770
15152
|
return idx;
|
|
14771
15153
|
}
|
|
15154
|
+
function fetchSessionLogsPage(sessionId, request, limit = SESSION_PAGE_LIMIT) {
|
|
15155
|
+
return fetchJsonWithTimeout(
|
|
15156
|
+
buildSessionLogsPageUrl(sessionId, request, limit),
|
|
15157
|
+
LogCursorPageSchema,
|
|
15158
|
+
SESSION_LOGS_FETCH_TIMEOUT_MS
|
|
15159
|
+
);
|
|
15160
|
+
}
|
|
14772
15161
|
function mergeLogsById(previousLogs, incomingLogs) {
|
|
14773
15162
|
if (incomingLogs.length === 0) return [...previousLogs];
|
|
14774
15163
|
const byId = /* @__PURE__ */ new Map();
|
|
@@ -14801,12 +15190,17 @@ function ProxyViewerContainer({
|
|
|
14801
15190
|
const [streamInitialized, setStreamInitialized] = reactExports.useState(initialSessionId === void 0);
|
|
14802
15191
|
const [logPage, setLogPage] = reactExports.useState(null);
|
|
14803
15192
|
const [sessionPageLoading, setSessionPageLoading] = reactExports.useState(initialSessionId !== void 0);
|
|
15193
|
+
const [sessionLoadProgress, setSessionLoadProgress] = reactExports.useState(
|
|
15194
|
+
void 0
|
|
15195
|
+
);
|
|
14804
15196
|
const [sessionMemberships, setSessionMemberships] = reactExports.useState([]);
|
|
14805
15197
|
const [, startLogTransition] = reactExports.useTransition();
|
|
14806
15198
|
const eventSourceRef = reactExports.useRef(null);
|
|
14807
15199
|
const reconnectTimeoutRef = reactExports.useRef(null);
|
|
14808
15200
|
const handledHashRef = reactExports.useRef(null);
|
|
14809
15201
|
const sessionPageRequestIdRef = reactExports.useRef(0);
|
|
15202
|
+
const sessionLoadStartedAtRef = reactExports.useRef(null);
|
|
15203
|
+
const sessionLoadTimerRef = reactExports.useRef(null);
|
|
14810
15204
|
const logIndexRef = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
14811
15205
|
const pendingUpdatesRef = reactExports.useRef([]);
|
|
14812
15206
|
const flushTimerRef = reactExports.useRef(null);
|
|
@@ -14816,6 +15210,50 @@ function ProxyViewerContainer({
|
|
|
14816
15210
|
},
|
|
14817
15211
|
[showToast]
|
|
14818
15212
|
);
|
|
15213
|
+
const stopSessionLoadProgress = reactExports.useCallback(() => {
|
|
15214
|
+
if (sessionLoadTimerRef.current !== null) {
|
|
15215
|
+
clearInterval(sessionLoadTimerRef.current);
|
|
15216
|
+
sessionLoadTimerRef.current = null;
|
|
15217
|
+
}
|
|
15218
|
+
sessionLoadStartedAtRef.current = null;
|
|
15219
|
+
setSessionLoadProgress(void 0);
|
|
15220
|
+
}, []);
|
|
15221
|
+
const startSessionLoadProgress = reactExports.useCallback(
|
|
15222
|
+
(label, requestId, loadedLogs = 0, loadedPages = 0) => {
|
|
15223
|
+
if (sessionLoadTimerRef.current !== null) {
|
|
15224
|
+
clearInterval(sessionLoadTimerRef.current);
|
|
15225
|
+
}
|
|
15226
|
+
const startedAt = Date.now();
|
|
15227
|
+
sessionLoadStartedAtRef.current = startedAt;
|
|
15228
|
+
const update = () => {
|
|
15229
|
+
if (sessionPageRequestIdRef.current !== requestId) return;
|
|
15230
|
+
setSessionLoadProgress({
|
|
15231
|
+
label,
|
|
15232
|
+
elapsedMs: Date.now() - startedAt,
|
|
15233
|
+
timeoutMs: SESSION_LOGS_FETCH_TIMEOUT_MS,
|
|
15234
|
+
loadedLogs,
|
|
15235
|
+
loadedPages
|
|
15236
|
+
});
|
|
15237
|
+
};
|
|
15238
|
+
update();
|
|
15239
|
+
sessionLoadTimerRef.current = setInterval(update, 250);
|
|
15240
|
+
},
|
|
15241
|
+
[]
|
|
15242
|
+
);
|
|
15243
|
+
const updateSessionLoadProgress = reactExports.useCallback(
|
|
15244
|
+
(label, requestId, loadedLogs, loadedPages) => {
|
|
15245
|
+
const startedAt = sessionLoadStartedAtRef.current;
|
|
15246
|
+
if (startedAt === null || sessionPageRequestIdRef.current !== requestId) return;
|
|
15247
|
+
setSessionLoadProgress({
|
|
15248
|
+
label,
|
|
15249
|
+
elapsedMs: Date.now() - startedAt,
|
|
15250
|
+
timeoutMs: SESSION_LOGS_FETCH_TIMEOUT_MS,
|
|
15251
|
+
loadedLogs,
|
|
15252
|
+
loadedPages
|
|
15253
|
+
});
|
|
15254
|
+
},
|
|
15255
|
+
[]
|
|
15256
|
+
);
|
|
14819
15257
|
const logs = reactExports.useMemo(
|
|
14820
15258
|
() => filterLogs(allLogs, selectedSession, selectedModel),
|
|
14821
15259
|
[allLogs, selectedSession, selectedModel]
|
|
@@ -14911,8 +15349,9 @@ function ProxyViewerContainer({
|
|
|
14911
15349
|
const requestId = sessionPageRequestIdRef.current + 1;
|
|
14912
15350
|
sessionPageRequestIdRef.current = requestId;
|
|
14913
15351
|
setSessionPageLoading(true);
|
|
15352
|
+
startSessionLoadProgress("Loading session logs", requestId);
|
|
14914
15353
|
dismissToast();
|
|
14915
|
-
void
|
|
15354
|
+
void fetchSessionLogsPage(initialSessionId, request).then((page) => {
|
|
14916
15355
|
if (sessionPageRequestIdRef.current !== requestId) return;
|
|
14917
15356
|
const nextLogs = page.logs;
|
|
14918
15357
|
logIndexRef.current = buildLogIndex(nextLogs);
|
|
@@ -14920,42 +15359,56 @@ function ProxyViewerContainer({
|
|
|
14920
15359
|
setLogPage(page);
|
|
14921
15360
|
setSelectedSession(initialSessionId);
|
|
14922
15361
|
setSessionPageLoading(false);
|
|
15362
|
+
stopSessionLoadProgress();
|
|
14923
15363
|
dismissToast();
|
|
14924
15364
|
}).catch((err) => {
|
|
14925
15365
|
if (sessionPageRequestIdRef.current !== requestId) return;
|
|
14926
15366
|
setAllLogs([]);
|
|
14927
15367
|
setLogPage(null);
|
|
14928
15368
|
setSessionPageLoading(false);
|
|
15369
|
+
stopSessionLoadProgress();
|
|
14929
15370
|
showErrorToast(err instanceof Error ? err.message : "Failed to load session logs");
|
|
14930
15371
|
});
|
|
14931
15372
|
},
|
|
14932
|
-
[
|
|
15373
|
+
[
|
|
15374
|
+
dismissToast,
|
|
15375
|
+
initialSessionId,
|
|
15376
|
+
showErrorToast,
|
|
15377
|
+
startSessionLoadProgress,
|
|
15378
|
+
stopSessionLoadProgress
|
|
15379
|
+
]
|
|
14933
15380
|
);
|
|
14934
15381
|
const reloadSessionLogs = reactExports.useCallback(
|
|
14935
15382
|
(sessionId) => {
|
|
14936
15383
|
const requestId = sessionPageRequestIdRef.current + 1;
|
|
14937
15384
|
sessionPageRequestIdRef.current = requestId;
|
|
14938
15385
|
setSessionPageLoading(true);
|
|
15386
|
+
startSessionLoadProgress("Reloading full session", requestId);
|
|
14939
15387
|
dismissToast();
|
|
14940
15388
|
void (async () => {
|
|
14941
15389
|
const collected = [];
|
|
14942
|
-
let page = await
|
|
14943
|
-
|
|
14944
|
-
|
|
15390
|
+
let page = await fetchSessionLogsPage(
|
|
15391
|
+
sessionId,
|
|
15392
|
+
{ kind: "oldest" },
|
|
15393
|
+
SESSION_RELOAD_PAGE_LIMIT
|
|
14945
15394
|
);
|
|
14946
15395
|
collected.push(...page.logs);
|
|
15396
|
+
updateSessionLoadProgress("Reloading full session", requestId, collected.length, 1);
|
|
14947
15397
|
let loadedPages = 1;
|
|
14948
15398
|
while (page.hasNewer && page.newestLogId !== null && loadedPages < MAX_SESSION_RELOAD_PAGES) {
|
|
14949
|
-
page = await
|
|
14950
|
-
|
|
14951
|
-
|
|
14952
|
-
|
|
14953
|
-
SESSION_RELOAD_PAGE_LIMIT
|
|
14954
|
-
),
|
|
14955
|
-
LogCursorPageSchema
|
|
15399
|
+
page = await fetchSessionLogsPage(
|
|
15400
|
+
sessionId,
|
|
15401
|
+
{ kind: "newer", afterLogId: page.newestLogId },
|
|
15402
|
+
SESSION_RELOAD_PAGE_LIMIT
|
|
14956
15403
|
);
|
|
14957
15404
|
collected.push(...page.logs);
|
|
14958
15405
|
loadedPages += 1;
|
|
15406
|
+
updateSessionLoadProgress(
|
|
15407
|
+
"Reloading full session",
|
|
15408
|
+
requestId,
|
|
15409
|
+
collected.length,
|
|
15410
|
+
loadedPages
|
|
15411
|
+
);
|
|
14959
15412
|
}
|
|
14960
15413
|
if (sessionPageRequestIdRef.current !== requestId) return;
|
|
14961
15414
|
setAllLogs((prev) => {
|
|
@@ -14965,6 +15418,7 @@ function ProxyViewerContainer({
|
|
|
14965
15418
|
});
|
|
14966
15419
|
setKnownSessions((prev) => mergeSessionIds(prev, [sessionId]));
|
|
14967
15420
|
setSessionPageLoading(false);
|
|
15421
|
+
stopSessionLoadProgress();
|
|
14968
15422
|
if (page.hasNewer) {
|
|
14969
15423
|
showToast({
|
|
14970
15424
|
message: `Loaded ${String(collected.length)} logs for this session. More history is available.`,
|
|
@@ -14976,10 +15430,18 @@ function ProxyViewerContainer({
|
|
|
14976
15430
|
})().catch((err) => {
|
|
14977
15431
|
if (sessionPageRequestIdRef.current !== requestId) return;
|
|
14978
15432
|
setSessionPageLoading(false);
|
|
15433
|
+
stopSessionLoadProgress();
|
|
14979
15434
|
showErrorToast(err instanceof Error ? err.message : "Failed to reload session logs");
|
|
14980
15435
|
});
|
|
14981
15436
|
},
|
|
14982
|
-
[
|
|
15437
|
+
[
|
|
15438
|
+
dismissToast,
|
|
15439
|
+
showErrorToast,
|
|
15440
|
+
showToast,
|
|
15441
|
+
startSessionLoadProgress,
|
|
15442
|
+
stopSessionLoadProgress,
|
|
15443
|
+
updateSessionLoadProgress
|
|
15444
|
+
]
|
|
14983
15445
|
);
|
|
14984
15446
|
reactExports.useEffect(() => {
|
|
14985
15447
|
if (initialSessionId === void 0) {
|
|
@@ -14987,12 +15449,11 @@ function ProxyViewerContainer({
|
|
|
14987
15449
|
return;
|
|
14988
15450
|
}
|
|
14989
15451
|
let cancelled = false;
|
|
14990
|
-
void
|
|
14991
|
-
|
|
14992
|
-
|
|
14993
|
-
|
|
14994
|
-
|
|
14995
|
-
}).then((groups) => {
|
|
15452
|
+
void fetchJsonWithTimeout(
|
|
15453
|
+
"/api/groups",
|
|
15454
|
+
InspectorGroupsListResponseSchema,
|
|
15455
|
+
SESSION_MEMBERSHIP_FETCH_TIMEOUT_MS
|
|
15456
|
+
).then((response) => response.groups).then((groups) => {
|
|
14996
15457
|
if (cancelled || groups === null) return;
|
|
14997
15458
|
setSessionMemberships(buildSessionMembershipEvidence(groups, initialSessionId));
|
|
14998
15459
|
}).catch(() => {
|
|
@@ -15005,6 +15466,11 @@ function ProxyViewerContainer({
|
|
|
15005
15466
|
reactExports.useEffect(() => {
|
|
15006
15467
|
refreshSessions();
|
|
15007
15468
|
}, [refreshSessions]);
|
|
15469
|
+
reactExports.useEffect(() => {
|
|
15470
|
+
return () => {
|
|
15471
|
+
stopSessionLoadProgress();
|
|
15472
|
+
};
|
|
15473
|
+
}, [stopSessionLoadProgress]);
|
|
15008
15474
|
reactExports.useEffect(() => {
|
|
15009
15475
|
if (initialSessionId === void 0) return;
|
|
15010
15476
|
loadSessionPage({ kind: "newest" });
|
|
@@ -15082,6 +15548,8 @@ function ProxyViewerContainer({
|
|
|
15082
15548
|
}, [logs.length]);
|
|
15083
15549
|
const handleClearAll = reactExports.useCallback(() => {
|
|
15084
15550
|
const clearedSessions = extractSessions(allLogs);
|
|
15551
|
+
stopSessionLoadProgress();
|
|
15552
|
+
setSessionPageLoading(false);
|
|
15085
15553
|
logIndexRef.current.clear();
|
|
15086
15554
|
setAllLogs([]);
|
|
15087
15555
|
setLogPage(null);
|
|
@@ -15090,7 +15558,7 @@ function ProxyViewerContainer({
|
|
|
15090
15558
|
message: "Cleared the current view. Stored logs are still reloadable.",
|
|
15091
15559
|
tone: "success"
|
|
15092
15560
|
});
|
|
15093
|
-
}, [allLogs, showToast]);
|
|
15561
|
+
}, [allLogs, showToast, stopSessionLoadProgress]);
|
|
15094
15562
|
const handleClearGroup = reactExports.useCallback(
|
|
15095
15563
|
(ids) => {
|
|
15096
15564
|
if (ids.length === 0) return;
|
|
@@ -15106,6 +15574,35 @@ function ProxyViewerContainer({
|
|
|
15106
15574
|
},
|
|
15107
15575
|
[showToast]
|
|
15108
15576
|
);
|
|
15577
|
+
const handleDeleteCurrentView = reactExports.useCallback(
|
|
15578
|
+
async (ids) => {
|
|
15579
|
+
if (ids.length === 0) return;
|
|
15580
|
+
const idSet = new Set(ids);
|
|
15581
|
+
const removed = allLogs.filter((log) => idSet.has(log.id));
|
|
15582
|
+
const result = await fetchJson("/api/logs", DeleteLogsResponseSchema, {
|
|
15583
|
+
method: "DELETE",
|
|
15584
|
+
headers: { "content-type": "application/json" },
|
|
15585
|
+
body: JSON.stringify({ ids })
|
|
15586
|
+
});
|
|
15587
|
+
setAllLogs((prev) => {
|
|
15588
|
+
const remaining = prev.filter((log) => !idSet.has(log.id));
|
|
15589
|
+
logIndexRef.current = buildLogIndex(remaining);
|
|
15590
|
+
return remaining;
|
|
15591
|
+
});
|
|
15592
|
+
setLogPage(
|
|
15593
|
+
(prev) => prev === null ? null : {
|
|
15594
|
+
...prev,
|
|
15595
|
+
logs: prev.logs.filter((log) => !idSet.has(log.id))
|
|
15596
|
+
}
|
|
15597
|
+
);
|
|
15598
|
+
setKnownSessions((prev) => mergeSessionIds(prev, extractSessions(removed)));
|
|
15599
|
+
showToast({
|
|
15600
|
+
message: `Deleted ${result.cleared.toString()} stored log${result.cleared === 1 ? "" : "s"} from the current view.`,
|
|
15601
|
+
tone: "success"
|
|
15602
|
+
});
|
|
15603
|
+
},
|
|
15604
|
+
[allLogs, showToast]
|
|
15605
|
+
);
|
|
15109
15606
|
const handleReloadSession = reactExports.useCallback(() => {
|
|
15110
15607
|
if (initialSessionId !== void 0) {
|
|
15111
15608
|
loadSessionPage({ kind: "newest" });
|
|
@@ -15166,6 +15663,7 @@ function ProxyViewerContainer({
|
|
|
15166
15663
|
if (initialSessionId === void 0) return void 0;
|
|
15167
15664
|
return {
|
|
15168
15665
|
isLoading: sessionPageLoading,
|
|
15666
|
+
loadProgress: sessionLoadProgress,
|
|
15169
15667
|
total: logPage?.total ?? null,
|
|
15170
15668
|
pageSize: logPage?.limit ?? SESSION_PAGE_LIMIT,
|
|
15171
15669
|
hasOlder: logPage?.hasOlder ?? false,
|
|
@@ -15184,6 +15682,7 @@ function ProxyViewerContainer({
|
|
|
15184
15682
|
loadOlderPage,
|
|
15185
15683
|
loadOldestPage,
|
|
15186
15684
|
logPage,
|
|
15685
|
+
sessionLoadProgress,
|
|
15187
15686
|
sessionPageLoading
|
|
15188
15687
|
]);
|
|
15189
15688
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
@@ -15200,12 +15699,14 @@ function ProxyViewerContainer({
|
|
|
15200
15699
|
onSessionChange: setSelectedSession,
|
|
15201
15700
|
onModelChange: setSelectedModel,
|
|
15202
15701
|
onClearAll: handleClearAll,
|
|
15702
|
+
onDeleteCurrentView: handleDeleteCurrentView,
|
|
15203
15703
|
onReloadSession: initialSessionId !== void 0 || selectedSession !== "__all__" ? handleReloadSession : void 0,
|
|
15204
15704
|
onClearGroup: handleClearGroup,
|
|
15205
15705
|
onNotify: showToast,
|
|
15206
15706
|
onImportLogs: initialSessionId === void 0 ? handleImportLogs : void 0,
|
|
15207
15707
|
isLoading: initialSessionId === void 0 ? !streamInitialized || sessionPageLoading : sessionPageLoading,
|
|
15208
15708
|
pagination,
|
|
15709
|
+
sessionLoadProgress,
|
|
15209
15710
|
sessionMemberships,
|
|
15210
15711
|
viewMode,
|
|
15211
15712
|
captureMode,
|
|
@@ -15219,13 +15720,15 @@ function ProxyViewerContainer({
|
|
|
15219
15720
|
] });
|
|
15220
15721
|
}
|
|
15221
15722
|
export {
|
|
15222
|
-
|
|
15723
|
+
ApiTimeoutError as A,
|
|
15223
15724
|
Badge as B,
|
|
15224
15725
|
CONTEXT_USAGE_THRESHOLDS as C,
|
|
15225
15726
|
Dialog as D,
|
|
15226
|
-
|
|
15227
|
-
|
|
15228
|
-
|
|
15727
|
+
CollapsibleContent as E,
|
|
15728
|
+
ScrollArea as F,
|
|
15729
|
+
LazyJsonViewer as G,
|
|
15730
|
+
safeJsonValue as H,
|
|
15731
|
+
parseJsonText as I,
|
|
15229
15732
|
LazyJsonViewerFromString as L,
|
|
15230
15733
|
ProxyViewerContainer as P,
|
|
15231
15734
|
ROLE_COLOR_CLASSES as R,
|
|
@@ -15234,27 +15737,27 @@ export {
|
|
|
15234
15737
|
getConversationId as a,
|
|
15235
15738
|
copyTextToClipboard as b,
|
|
15236
15739
|
cn as c,
|
|
15237
|
-
|
|
15238
|
-
|
|
15740
|
+
fetchJsonWithTimeout as d,
|
|
15741
|
+
DialogContent as e,
|
|
15239
15742
|
formatTokens as f,
|
|
15240
15743
|
getLogFormatAdapter as g,
|
|
15241
|
-
|
|
15242
|
-
|
|
15243
|
-
|
|
15244
|
-
|
|
15245
|
-
|
|
15246
|
-
|
|
15247
|
-
|
|
15248
|
-
|
|
15249
|
-
|
|
15250
|
-
|
|
15744
|
+
DialogHeader as h,
|
|
15745
|
+
DialogTitle as i,
|
|
15746
|
+
TabsList as j,
|
|
15747
|
+
TabsTrigger as k,
|
|
15748
|
+
TabsContent as l,
|
|
15749
|
+
Button as m,
|
|
15750
|
+
TooltipProvider as n,
|
|
15751
|
+
Tooltip as o,
|
|
15752
|
+
TooltipTrigger as p,
|
|
15753
|
+
TooltipContent as q,
|
|
15251
15754
|
resolveLogFormat as r,
|
|
15252
|
-
|
|
15253
|
-
|
|
15755
|
+
dispatchLogFocusRequest as s,
|
|
15756
|
+
analyzeContextIntelligence as t,
|
|
15254
15757
|
useProviders as u,
|
|
15255
|
-
|
|
15256
|
-
|
|
15257
|
-
|
|
15258
|
-
|
|
15259
|
-
|
|
15758
|
+
ANATOMY_ROLE_LABELS as v,
|
|
15759
|
+
formatContextWindowTokens as w,
|
|
15760
|
+
getStatusCategory as x,
|
|
15761
|
+
Collapsible as y,
|
|
15762
|
+
CollapsibleTrigger as z
|
|
15260
15763
|
};
|