@tonyclaw/agent-inspector 2.0.23 → 2.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-DnYQtd8R.js → CompareDrawer-DVNvS0GQ.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-By3XtQhZ.js +115 -0
- package/.output/public/assets/{ReplayDialog-B-3V95xT.js → ReplayDialog-Cw6bN-NR.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-CT8hLGLa.js → RequestAnatomy-DnIsirBE.js} +1 -1
- package/.output/public/assets/{ResponseView-DK3CYom0.js → ResponseView-ygsUs7FU.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-D3jJutjp.js → StreamingChunkSequence-DMUn8qXi.js} +1 -1
- package/.output/public/assets/_sessionId-DoqvnFx7.js +1 -0
- package/.output/public/assets/index-B0YcFeL-.js +1 -0
- package/.output/public/assets/index-DsiKfWCp.css +1 -0
- package/.output/public/assets/{main-hF_572U6.js → main-kBQ49n13.js} +2 -2
- package/.output/server/{_sessionId-BqhNE2M8.mjs → _sessionId-CYKaI68v.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-C4LQW4S1.mjs → CompareDrawer-CHk4p41X.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-BKInvawk.mjs → ProxyViewerContainer-Co9ENCKV.mjs} +276 -47
- package/.output/server/_ssr/{ReplayDialog-C3ZiRihL.mjs → ReplayDialog-BRs3fk8H.mjs} +3 -3
- package/.output/server/_ssr/{RequestAnatomy-DlVAPIQZ.mjs → RequestAnatomy-Cb68EeZz.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-nMS0rkxu.mjs → ResponseView-DGdbfEjs.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-PDWqrNiO.mjs → StreamingChunkSequence-DptYgirK.mjs} +2 -2
- package/.output/server/_ssr/{index-Cd1zD-lo.mjs → index-Ef5mCuww.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-R9gm7_sh.mjs → router-Cvv7SJnd.mjs} +192 -15
- package/.output/server/{_tanstack-start-manifest_v-BnLVH_EX.mjs → _tanstack-start-manifest_v-DQoXxIFQ.mjs} +1 -1
- package/.output/server/index.mjs +56 -56
- package/package.json +1 -1
- package/src/components/ProxyViewer.tsx +11 -1
- package/src/components/ProxyViewerContainer.tsx +21 -15
- package/src/components/providers/ProviderForm.tsx +176 -16
- package/src/lib/export-logs.ts +54 -11
- package/src/lib/providerTestPrompt.ts +4 -4
- package/src/lib/utils.ts +46 -0
- package/src/mcp/toolHandlers.ts +58 -8
- package/src/proxy/logFinalizer.ts +79 -1
- package/src/proxy/logIndex.ts +6 -1
- package/src/proxy/schemas.ts +3 -0
- package/src/proxy/store.ts +79 -2
- package/src/routes/api/logs.stream.ts +5 -2
- package/src/routes/api/logs.ts +4 -1
- package/.output/public/assets/ProxyViewerContainer-BTYGkg36.js +0 -115
- package/.output/public/assets/_sessionId-DpdfAzbo.js +0 -1
- package/.output/public/assets/index-780zTVwp.css +0 -1
- package/.output/public/assets/index-BpJNbm9G.js +0 -1
|
@@ -50,7 +50,7 @@ import "../_libs/mimic-function.mjs";
|
|
|
50
50
|
import "../_libs/semver.mjs";
|
|
51
51
|
import "../_libs/uint8array-extras.mjs";
|
|
52
52
|
const faviconSvg = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2064%2064'%20role='img'%20aria-label='Agent%20Inspector'%3e%3crect%20width='64'%20height='64'%20rx='14'%20fill='%23111827'%20/%3e%3cg%20fill='none'%20stroke='%23f59e0b'%20stroke-width='4.2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20fill='%23f59e0b'%20d='M15%2036c0-11%207-18%2017-18s17%207%2017%2018c0%208-7%2013-17%2013s-17-5-17-13z'%20/%3e%3cpath%20d='M16%2031c-6-5-12-3-12%204%200%205%206%206%2011%202'%20/%3e%3cpath%20d='M48%2031c6-5%2012-3%2012%204%200%205-6%206-11%202'%20/%3e%3cpath%20d='M27%2019l-3-7'%20/%3e%3cpath%20d='M37%2019l3-7'%20/%3e%3cpath%20d='M19%2045l-6%209'%20/%3e%3cpath%20d='M27%2048l-3%209'%20/%3e%3cpath%20d='M37%2048l3%209'%20/%3e%3cpath%20d='M45%2045l6%209'%20/%3e%3c/g%3e%3cpath%20d='M14%2047l9-8%208%209c-5%203.5-12%203-17-1z'%20fill='%232f6b3f'%20opacity='.95'%20/%3e%3cpath%20d='M18%2046l5-5%205%206c-3%201.6-7%201.4-10-1z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M23%2041v10'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='1.6'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='31'%20cy='48'%20r='1.8'%20fill='%23c2412d'%20/%3e%3cpath%20d='M24%2044l13-11%2014%2013c-8%205.8-18%205.3-27-2z'%20fill='%232f6b3f'%20opacity='.97'%20/%3e%3cpath%20d='M30%2043l7-7%209%209c-5%202.7-11%202.5-16-2z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M37%2036v14'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='2'%20stroke-linecap='round'%20/%3e%3cpath%20d='M30%2043c5-2%2011-1.5%2016%202'%20fill='none'%20stroke='%239fca78'%20stroke-width='1.8'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='51'%20cy='46'%20r='2'%20fill='%23c2412d'%20/%3e%3cpath%20d='M40%2050l8-8%207%208c-4.2%203.2-10%203-15%200z'%20fill='%232f6b3f'%20opacity='.95'%20/%3e%3cpath%20d='M43%2049l5-5%204.5%205.5c-3%201.5-6%201.2-9.5-.5z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M48%2044v9'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='1.5'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='55'%20cy='50'%20r='1.7'%20fill='%23c2412d'%20/%3e%3ccircle%20cx='24'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='40'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='25'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3ccircle%20cx='39'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3c/svg%3e";
|
|
53
|
-
const appCss = "/assets/index-
|
|
53
|
+
const appCss = "/assets/index-DsiKfWCp.css";
|
|
54
54
|
const Route$s = createRootRoute({
|
|
55
55
|
head: () => ({
|
|
56
56
|
meta: [
|
|
@@ -93,7 +93,7 @@ function RootDocument({ children }) {
|
|
|
93
93
|
] })
|
|
94
94
|
] });
|
|
95
95
|
}
|
|
96
|
-
const $$splitComponentImporter$1 = () => import("./index-
|
|
96
|
+
const $$splitComponentImporter$1 = () => import("./index-Ef5mCuww.mjs");
|
|
97
97
|
const Route$r = createFileRoute("/")({
|
|
98
98
|
component: lazyRouteComponent($$splitComponentImporter$1, "component")
|
|
99
99
|
});
|
|
@@ -136,7 +136,7 @@ function decodeSessionIdFromPath(encoded) {
|
|
|
136
136
|
function getSessionPath(sessionId) {
|
|
137
137
|
return `/session/${encodeSessionIdForPath(sessionId)}`;
|
|
138
138
|
}
|
|
139
|
-
const $$splitComponentImporter = () => import("../_sessionId-
|
|
139
|
+
const $$splitComponentImporter = () => import("../_sessionId-CYKaI68v.mjs");
|
|
140
140
|
const Route$q = createFileRoute("/session/$sessionId")({
|
|
141
141
|
component: lazyRouteComponent($$splitComponentImporter, "component"),
|
|
142
142
|
parseParams: (params) => ({
|
|
@@ -729,6 +729,9 @@ const CapturedLogSchema = object({
|
|
|
729
729
|
clientProjectFolder: string().nullable().optional(),
|
|
730
730
|
streamingChunks: StreamingChunksArraySchema.optional(),
|
|
731
731
|
streamingChunksPath: string().nullable().optional(),
|
|
732
|
+
rawRequestBodyBytes: number().int().nonnegative().nullable().optional(),
|
|
733
|
+
responseTextBytes: number().int().nonnegative().nullable().optional(),
|
|
734
|
+
bodyContentMode: _enum(["full", "compact", "truncated"]).optional(),
|
|
732
735
|
/** Error message from streaming response (e.g., SSE error event) */
|
|
733
736
|
error: string().nullable().optional()
|
|
734
737
|
});
|
|
@@ -927,6 +930,10 @@ async function findInIndex(id) {
|
|
|
927
930
|
const index = await loadIndex();
|
|
928
931
|
return index.entries[id] ?? null;
|
|
929
932
|
}
|
|
933
|
+
async function listIndexEntries() {
|
|
934
|
+
const index = await loadIndex();
|
|
935
|
+
return Object.values(index.entries).sort((left, right) => left.id - right.id);
|
|
936
|
+
}
|
|
930
937
|
async function indexFile(filePath, file) {
|
|
931
938
|
const entries = {};
|
|
932
939
|
let maxId = 0;
|
|
@@ -1341,6 +1348,26 @@ function addToCache(log) {
|
|
|
1341
1348
|
function removeFromCache(id) {
|
|
1342
1349
|
memoryCache.delete(id);
|
|
1343
1350
|
}
|
|
1351
|
+
function textByteLength$1(value) {
|
|
1352
|
+
if (value === null) return null;
|
|
1353
|
+
return Buffer.byteLength(value, "utf8");
|
|
1354
|
+
}
|
|
1355
|
+
function compactLogForList(log) {
|
|
1356
|
+
return {
|
|
1357
|
+
...log,
|
|
1358
|
+
rawRequestBody: null,
|
|
1359
|
+
responseText: null,
|
|
1360
|
+
rawHeaders: void 0,
|
|
1361
|
+
headers: void 0,
|
|
1362
|
+
streamingChunks: void 0,
|
|
1363
|
+
rawRequestBodyBytes: textByteLength$1(log.rawRequestBody),
|
|
1364
|
+
responseTextBytes: textByteLength$1(log.responseText),
|
|
1365
|
+
bodyContentMode: "compact"
|
|
1366
|
+
};
|
|
1367
|
+
}
|
|
1368
|
+
function prepareLogForList(log, includeBodies) {
|
|
1369
|
+
return includeBodies ? log : compactLogForList(log);
|
|
1370
|
+
}
|
|
1344
1371
|
async function addTestLogEntry(entry) {
|
|
1345
1372
|
const id = await getNextLogId();
|
|
1346
1373
|
let streamingChunksPath = null;
|
|
@@ -1542,11 +1569,50 @@ async function visitPersistedLogFile(filePath, visitor) {
|
|
|
1542
1569
|
logger.error("[store] Failed to read persisted log file:", filePath, String(err));
|
|
1543
1570
|
}
|
|
1544
1571
|
}
|
|
1572
|
+
function canUseIndexedListPage(options) {
|
|
1573
|
+
return options.sessionId === void 0 && options.model === void 0;
|
|
1574
|
+
}
|
|
1575
|
+
function hasUsableIndexOffset(entry) {
|
|
1576
|
+
return entry.byteOffset >= 0 && entry.byteLength > 0;
|
|
1577
|
+
}
|
|
1578
|
+
async function listLogsPageFromIndex(options, allowRebuild) {
|
|
1579
|
+
if (!canUseIndexedListPage(options)) return null;
|
|
1580
|
+
let entries = await listIndexEntries();
|
|
1581
|
+
if (entries.length === 0 && allowRebuild) {
|
|
1582
|
+
await rebuildIndex();
|
|
1583
|
+
entries = await listIndexEntries();
|
|
1584
|
+
}
|
|
1585
|
+
const pageStart = options.offset;
|
|
1586
|
+
const pageEnd = options.offset + options.limit;
|
|
1587
|
+
const pageEntries = entries.slice(pageStart, pageEnd);
|
|
1588
|
+
const hasIncompleteOffset = pageEntries.some((entry) => !hasUsableIndexOffset(entry));
|
|
1589
|
+
if (hasIncompleteOffset) {
|
|
1590
|
+
if (!allowRebuild) return null;
|
|
1591
|
+
await rebuildIndex();
|
|
1592
|
+
return await listLogsPageFromIndex(options, false);
|
|
1593
|
+
}
|
|
1594
|
+
const logs = [];
|
|
1595
|
+
const includeBodies = options.includeBodies !== false;
|
|
1596
|
+
for (const entry of pageEntries) {
|
|
1597
|
+
const log = await getLogById(entry.id);
|
|
1598
|
+
if (log === null) return null;
|
|
1599
|
+
logs.push(prepareLogForList(log, includeBodies));
|
|
1600
|
+
}
|
|
1601
|
+
return {
|
|
1602
|
+
logs,
|
|
1603
|
+
total: entries.length,
|
|
1604
|
+
offset: options.offset,
|
|
1605
|
+
limit: options.limit
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1545
1608
|
async function listLogsPage(options) {
|
|
1609
|
+
const indexedPage = await listLogsPageFromIndex(options, true);
|
|
1610
|
+
if (indexedPage !== null) return indexedPage;
|
|
1546
1611
|
const seenIds = /* @__PURE__ */ new Set();
|
|
1547
1612
|
const pageById = /* @__PURE__ */ new Map();
|
|
1548
1613
|
const pageStart = options.offset;
|
|
1549
1614
|
const pageEnd = options.offset + options.limit;
|
|
1615
|
+
const includeBodies = options.includeBodies !== false;
|
|
1550
1616
|
let total = 0;
|
|
1551
1617
|
const visitLog = (log) => {
|
|
1552
1618
|
if (!matchesLogFilters(log, options.sessionId, options.model)) return;
|
|
@@ -1555,12 +1621,12 @@ async function listLogsPage(options) {
|
|
|
1555
1621
|
const position = total;
|
|
1556
1622
|
total += 1;
|
|
1557
1623
|
if (position >= pageStart && position < pageEnd) {
|
|
1558
|
-
pageById.set(log.id, log);
|
|
1624
|
+
pageById.set(log.id, prepareLogForList(log, includeBodies));
|
|
1559
1625
|
}
|
|
1560
1626
|
return;
|
|
1561
1627
|
}
|
|
1562
1628
|
if (pageById.has(log.id)) {
|
|
1563
|
-
pageById.set(log.id, log);
|
|
1629
|
+
pageById.set(log.id, prepareLogForList(log, includeBodies));
|
|
1564
1630
|
}
|
|
1565
1631
|
};
|
|
1566
1632
|
await visitPersistedLogs((log) => {
|
|
@@ -3851,6 +3917,14 @@ function stripOpenAIOrphanToolMessages(rawBody) {
|
|
|
3851
3917
|
parsed.messages = kept;
|
|
3852
3918
|
return { body: JSON.stringify(parsed), removed: indices.length, orphanIds };
|
|
3853
3919
|
}
|
|
3920
|
+
const DEFAULT_MAX_FINALIZE_STREAM_BYTES = 20 * 1024 * 1024;
|
|
3921
|
+
function resolveMaxFinalizeStreamBytes() {
|
|
3922
|
+
const raw = process.env["AGENT_INSPECTOR_MAX_FINALIZE_STREAM_BYTES"];
|
|
3923
|
+
if (raw === void 0 || raw === "") return DEFAULT_MAX_FINALIZE_STREAM_BYTES;
|
|
3924
|
+
const parsed = Number(raw);
|
|
3925
|
+
if (!Number.isFinite(parsed) || parsed < 1) return DEFAULT_MAX_FINALIZE_STREAM_BYTES;
|
|
3926
|
+
return Math.floor(parsed);
|
|
3927
|
+
}
|
|
3854
3928
|
function buildFileLogEntry(log, upstreamUrl) {
|
|
3855
3929
|
return {
|
|
3856
3930
|
timestamp: log.timestamp,
|
|
@@ -3933,6 +4007,37 @@ function cleanupPathForRawStream(rawStream) {
|
|
|
3933
4007
|
return rawStream.path;
|
|
3934
4008
|
}
|
|
3935
4009
|
}
|
|
4010
|
+
function rawStreamByteLength(rawStream) {
|
|
4011
|
+
if (typeof rawStream === "string") {
|
|
4012
|
+
return Buffer.byteLength(rawStream, "utf8");
|
|
4013
|
+
}
|
|
4014
|
+
switch (rawStream.type) {
|
|
4015
|
+
case "memory":
|
|
4016
|
+
return Buffer.byteLength(rawStream.rawStream, "utf8");
|
|
4017
|
+
case "file":
|
|
4018
|
+
try {
|
|
4019
|
+
return statSync(rawStream.path).size;
|
|
4020
|
+
} catch {
|
|
4021
|
+
return null;
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
4025
|
+
function getOversizedRawStream(rawStream) {
|
|
4026
|
+
const limit = resolveMaxFinalizeStreamBytes();
|
|
4027
|
+
const byteLength = rawStreamByteLength(rawStream);
|
|
4028
|
+
if (byteLength === null || byteLength <= limit) return null;
|
|
4029
|
+
return { byteLength, limit };
|
|
4030
|
+
}
|
|
4031
|
+
function formatBytes(bytes) {
|
|
4032
|
+
if (bytes < 1024) return `${bytes} bytes`;
|
|
4033
|
+
if (bytes < 1024 * 1024) return `${Math.ceil(bytes / 1024)} KB`;
|
|
4034
|
+
return `${Math.ceil(bytes / (1024 * 1024))} MB`;
|
|
4035
|
+
}
|
|
4036
|
+
function oversizedRawStreamText(oversized) {
|
|
4037
|
+
return `Streaming response omitted because the captured raw stream is ${formatBytes(
|
|
4038
|
+
oversized.byteLength
|
|
4039
|
+
)}, exceeding the finalize limit of ${formatBytes(oversized.limit)}. Increase AGENT_INSPECTOR_MAX_FINALIZE_STREAM_BYTES if this response must be parsed.`;
|
|
4040
|
+
}
|
|
3936
4041
|
function readRawStream(rawStream) {
|
|
3937
4042
|
if (typeof rawStream === "string") {
|
|
3938
4043
|
return { rawStreamText: rawStream, cleanupRawStreamPath: null };
|
|
@@ -3959,6 +4064,18 @@ function finalizeStreaming(job, log) {
|
|
|
3959
4064
|
cleanupPathForRawStream(job.rawStream)
|
|
3960
4065
|
);
|
|
3961
4066
|
}
|
|
4067
|
+
const oversized = getOversizedRawStream(job.rawStream);
|
|
4068
|
+
if (oversized !== null) {
|
|
4069
|
+
log.elapsedMs = job.elapsedMs;
|
|
4070
|
+
log.responseStatus = job.responseStatus;
|
|
4071
|
+
log.responseText = oversizedRawStreamText(oversized);
|
|
4072
|
+
return {
|
|
4073
|
+
log,
|
|
4074
|
+
upstreamUrl: job.upstreamUrl,
|
|
4075
|
+
error: null,
|
|
4076
|
+
cleanupRawStreamPath: cleanupPathForRawStream(job.rawStream)
|
|
4077
|
+
};
|
|
4078
|
+
}
|
|
3962
4079
|
let rawStreamText = "";
|
|
3963
4080
|
let cleanupRawStreamPath = null;
|
|
3964
4081
|
try {
|
|
@@ -4003,6 +4120,16 @@ function finalizeStreamAbort(job, log) {
|
|
|
4003
4120
|
try {
|
|
4004
4121
|
log.elapsedMs = job.elapsedMs;
|
|
4005
4122
|
if (job.hasChunks && formatHandler !== null) {
|
|
4123
|
+
const oversized = getOversizedRawStream(job.rawStream);
|
|
4124
|
+
if (oversized !== null) {
|
|
4125
|
+
log.responseText = `Client aborted. ${oversizedRawStreamText(oversized)}`;
|
|
4126
|
+
return {
|
|
4127
|
+
log,
|
|
4128
|
+
upstreamUrl: job.upstreamUrl,
|
|
4129
|
+
error: "Client aborted",
|
|
4130
|
+
cleanupRawStreamPath: cleanupPathForRawStream(job.rawStream)
|
|
4131
|
+
};
|
|
4132
|
+
}
|
|
4006
4133
|
const raw = readRawStream(job.rawStream);
|
|
4007
4134
|
rawStreamText = raw.rawStreamText;
|
|
4008
4135
|
cleanupRawStreamPath = raw.cleanupRawStreamPath;
|
|
@@ -4756,6 +4883,7 @@ const LogsListResponseSchema = object({
|
|
|
4756
4883
|
});
|
|
4757
4884
|
const PAGINATION_DEFAULTS = { offset: 0, limit: 3 };
|
|
4758
4885
|
const LIMIT_HARD_CAP = 5;
|
|
4886
|
+
const LOG_DETAIL_TEXT_LIMIT = 2e5;
|
|
4759
4887
|
function clampLimit(input) {
|
|
4760
4888
|
if (input === void 0) return PAGINATION_DEFAULTS.limit;
|
|
4761
4889
|
if (!Number.isFinite(input) || input < 1) return 1;
|
|
@@ -4767,8 +4895,46 @@ function textJson(data) {
|
|
|
4767
4895
|
function toolError(message) {
|
|
4768
4896
|
return { content: [{ type: "text", text: message }], isError: true };
|
|
4769
4897
|
}
|
|
4898
|
+
function textByteLength(value) {
|
|
4899
|
+
if (value === null) return null;
|
|
4900
|
+
return Buffer.byteLength(value, "utf8");
|
|
4901
|
+
}
|
|
4902
|
+
function hasBodyText(value, byteLength) {
|
|
4903
|
+
if (value !== null && value.length > 0) return true;
|
|
4904
|
+
return byteLength !== void 0 && byteLength !== null && byteLength > 0;
|
|
4905
|
+
}
|
|
4906
|
+
function truncateToolText(value) {
|
|
4907
|
+
if (value === null) return { value: null, byteLength: null, truncated: false };
|
|
4908
|
+
const byteLength = textByteLength(value);
|
|
4909
|
+
if (value.length <= LOG_DETAIL_TEXT_LIMIT) {
|
|
4910
|
+
return { value, byteLength, truncated: false };
|
|
4911
|
+
}
|
|
4912
|
+
const suffix = `
|
|
4913
|
+
[truncated by agent-inspector MCP: original ${byteLength ?? 0} bytes]`;
|
|
4914
|
+
return {
|
|
4915
|
+
value: `${value.slice(0, LOG_DETAIL_TEXT_LIMIT)}${suffix}`,
|
|
4916
|
+
byteLength,
|
|
4917
|
+
truncated: true
|
|
4918
|
+
};
|
|
4919
|
+
}
|
|
4920
|
+
function buildBoundedLogDetail(log) {
|
|
4921
|
+
const { streamingChunks: _chunks, rawRequestBody, responseText, ...rest } = log;
|
|
4922
|
+
const boundedRequest = truncateToolText(rawRequestBody);
|
|
4923
|
+
const boundedResponse = truncateToolText(responseText);
|
|
4924
|
+
return {
|
|
4925
|
+
...rest,
|
|
4926
|
+
rawRequestBody: boundedRequest.value,
|
|
4927
|
+
responseText: boundedResponse.value,
|
|
4928
|
+
rawRequestBodyBytes: boundedRequest.byteLength,
|
|
4929
|
+
responseTextBytes: boundedResponse.byteLength,
|
|
4930
|
+
rawRequestBodyTruncated: boundedRequest.truncated,
|
|
4931
|
+
responseTextTruncated: boundedResponse.truncated
|
|
4932
|
+
};
|
|
4933
|
+
}
|
|
4770
4934
|
function buildLogSummary(log) {
|
|
4771
4935
|
const hasError = log.error !== null && log.error !== void 0 && log.error.length > 0 || log.responseStatus !== null && log.responseStatus !== void 0 && log.responseStatus >= 400;
|
|
4936
|
+
const rawRequestBodyBytes = log.rawRequestBodyBytes ?? textByteLength(log.rawRequestBody);
|
|
4937
|
+
const responseTextBytes = log.responseTextBytes ?? textByteLength(log.responseText);
|
|
4772
4938
|
return {
|
|
4773
4939
|
id: log.id,
|
|
4774
4940
|
timestamp: log.timestamp,
|
|
@@ -4792,13 +4958,19 @@ function buildLogSummary(log) {
|
|
|
4792
4958
|
lastUserMessagePreview: extractLastUserMessagePreview(log),
|
|
4793
4959
|
responsePreview: extractResponsePreview(log),
|
|
4794
4960
|
hasChunks: log.streamingChunks !== void 0 && log.streamingChunks !== null || log.streamingChunksPath !== null && log.streamingChunksPath !== void 0,
|
|
4795
|
-
hasRawRequestBody: log.rawRequestBody
|
|
4961
|
+
hasRawRequestBody: hasBodyText(log.rawRequestBody, rawRequestBodyBytes),
|
|
4962
|
+
rawRequestBodyBytes,
|
|
4963
|
+
responseTextBytes
|
|
4796
4964
|
};
|
|
4797
4965
|
}
|
|
4798
4966
|
async function listLogsImpl(callApi2, args) {
|
|
4799
4967
|
const offset = args.offset ?? PAGINATION_DEFAULTS.offset;
|
|
4800
4968
|
const limit = clampLimit(args.limit);
|
|
4801
|
-
const params = new URLSearchParams({
|
|
4969
|
+
const params = new URLSearchParams({
|
|
4970
|
+
offset: String(offset),
|
|
4971
|
+
limit: String(limit),
|
|
4972
|
+
compact: "1"
|
|
4973
|
+
});
|
|
4802
4974
|
if (args.sessionId !== void 0 && args.sessionId.length > 0) {
|
|
4803
4975
|
params.set("sessionId", args.sessionId);
|
|
4804
4976
|
}
|
|
@@ -4821,8 +4993,7 @@ async function getLogImpl(callApi2, id) {
|
|
|
4821
4993
|
if (!parsed.success) {
|
|
4822
4994
|
return toolError(`GET /api/logs/${id} returned an unparseable CapturedLog`);
|
|
4823
4995
|
}
|
|
4824
|
-
|
|
4825
|
-
return textJson(rest);
|
|
4996
|
+
return textJson(buildBoundedLogDetail(parsed.data));
|
|
4826
4997
|
}
|
|
4827
4998
|
async function getLogChunksImpl(callApi2, id) {
|
|
4828
4999
|
const res = await callApi2(`/api/logs/${id}/chunks`);
|
|
@@ -5259,7 +5430,10 @@ const Route$k = createFileRoute("/api/logs")({
|
|
|
5259
5430
|
const model = url.searchParams.get("model") ?? void 0;
|
|
5260
5431
|
const offset = parseNonNegativeInt(url.searchParams.get("offset"), 0);
|
|
5261
5432
|
const limit = parsePositiveInt(url.searchParams.get("limit"), 50);
|
|
5262
|
-
|
|
5433
|
+
const includeBodies = url.searchParams.get("compact") !== "1";
|
|
5434
|
+
return Response.json(
|
|
5435
|
+
await listLogsPage({ sessionId, model, offset, limit, includeBodies })
|
|
5436
|
+
);
|
|
5263
5437
|
},
|
|
5264
5438
|
DELETE: async ({ request }) => {
|
|
5265
5439
|
let body = void 0;
|
|
@@ -5902,6 +6076,7 @@ const Route$d = createFileRoute("/api/logs/stream")({
|
|
|
5902
6076
|
const url = new URL(request.url);
|
|
5903
6077
|
const sessionId = url.searchParams.get("sessionId") ?? void 0;
|
|
5904
6078
|
const model = url.searchParams.get("model") ?? void 0;
|
|
6079
|
+
const includeBodies = url.searchParams.get("compact") !== "1";
|
|
5905
6080
|
let controllerRef = null;
|
|
5906
6081
|
let cleanedUp = false;
|
|
5907
6082
|
const unsubscribe = onLogUpdate((log) => {
|
|
@@ -5909,7 +6084,8 @@ const Route$d = createFileRoute("/api/logs/stream")({
|
|
|
5909
6084
|
if (sessionId !== void 0 && getLogSessionId(log) !== sessionId) return;
|
|
5910
6085
|
if (model !== void 0 && log.model !== model) return;
|
|
5911
6086
|
try {
|
|
5912
|
-
const
|
|
6087
|
+
const payloadLog = includeBodies ? log : compactLogForList(log);
|
|
6088
|
+
const data = `data: ${JSON.stringify({ type: "update", log: payloadLog })}
|
|
5913
6089
|
|
|
5914
6090
|
`;
|
|
5915
6091
|
controllerRef.enqueue(new TextEncoder().encode(data));
|
|
@@ -5942,7 +6118,8 @@ const Route$d = createFileRoute("/api/logs/stream")({
|
|
|
5942
6118
|
sessionId,
|
|
5943
6119
|
model,
|
|
5944
6120
|
offset: 0,
|
|
5945
|
-
limit: INITIAL_STREAM_LOG_LIMIT
|
|
6121
|
+
limit: INITIAL_STREAM_LOG_LIMIT,
|
|
6122
|
+
includeBodies
|
|
5946
6123
|
});
|
|
5947
6124
|
const logs = result.logs;
|
|
5948
6125
|
const initData = `data: ${JSON.stringify({ type: "init", logs })}
|
|
@@ -6642,9 +6819,9 @@ function modeInstruction(mode) {
|
|
|
6642
6819
|
function maxTokensForMode(mode) {
|
|
6643
6820
|
switch (mode) {
|
|
6644
6821
|
case "non-streaming":
|
|
6645
|
-
return
|
|
6822
|
+
return 256;
|
|
6646
6823
|
case "streaming":
|
|
6647
|
-
return
|
|
6824
|
+
return 256;
|
|
6648
6825
|
}
|
|
6649
6826
|
}
|
|
6650
6827
|
function buildProviderTestUserPrompt(mode) {
|
|
@@ -6675,7 +6852,7 @@ function buildProviderTestRequestBody(model, mode) {
|
|
|
6675
6852
|
};
|
|
6676
6853
|
switch (mode) {
|
|
6677
6854
|
case "non-streaming":
|
|
6678
|
-
return base;
|
|
6855
|
+
return { ...base, stream: false };
|
|
6679
6856
|
case "streaming":
|
|
6680
6857
|
return { ...base, stream: true };
|
|
6681
6858
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/session/$sessionId", "/api/knowledge/candidates", "/api/knowledge/project-context", "/api/knowledge/search", "/api/knowledge/sessions/$sessionId/candidates"], "preloads": ["/assets/main-
|
|
1
|
+
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/session/$sessionId", "/api/knowledge/candidates", "/api/knowledge/project-context", "/api/knowledge/search", "/api/knowledge/sessions/$sessionId/candidates"], "preloads": ["/assets/main-kBQ49n13.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-B0YcFeL-.js", "/assets/ProxyViewerContainer-By3XtQhZ.js"] }, "/api/config": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/config.ts", "children": ["/api/config/paths"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/mcp": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/mcp.ts" }, "/api/models": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId", "/api/providers/export", "/api/providers/import", "/api/providers/scan"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/proxy/$.ts" }, "/session/$sessionId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/session/$sessionId.tsx", "assets": [], "preloads": ["/assets/_sessionId-DoqvnFx7.js", "/assets/ProxyViewerContainer-By3XtQhZ.js"] }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/config.paths.ts" }, "/api/knowledge/candidates": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.ts", "children": ["/api/knowledge/candidates/$candidateId"] }, "/api/knowledge/project-context": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.project-context.ts" }, "/api/knowledge/search": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.search.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/model-metadata", "/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.import.ts" }, "/api/providers/scan": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.scan.ts" }, "/api/knowledge/candidates/$candidateId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.$candidateId.ts", "children": ["/api/knowledge/candidates/$candidateId/promote"] }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/model-metadata": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.model-metadata.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.test.ts", "children": ["/api/providers/$providerId/test/log"] }, "/api/knowledge/candidates/$candidateId/promote": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.$candidateId.promote.ts" }, "/api/knowledge/sessions/$sessionId/candidates": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.sessions.$sessionId.candidates.ts" }, "/api/providers/$providerId/test/log": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.test.log.ts" } }, "clientEntry": "/assets/main-kBQ49n13.js" });
|
|
2
2
|
export {
|
|
3
3
|
tsrStartManifest
|
|
4
4
|
};
|
package/.output/server/index.mjs
CHANGED
|
@@ -38,100 +38,100 @@ const assets = {
|
|
|
38
38
|
"/assets/alibaba-TTwafVwX.svg": {
|
|
39
39
|
"type": "image/svg+xml",
|
|
40
40
|
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
41
|
-
"mtime": "2026-06-
|
|
41
|
+
"mtime": "2026-06-29T13:24:14.325Z",
|
|
42
42
|
"size": 5915,
|
|
43
43
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
44
44
|
},
|
|
45
|
-
"/assets/CompareDrawer-
|
|
45
|
+
"/assets/CompareDrawer-DVNvS0GQ.js": {
|
|
46
46
|
"type": "text/javascript; charset=utf-8",
|
|
47
|
-
"etag": '"49fe-
|
|
48
|
-
"mtime": "2026-06-
|
|
47
|
+
"etag": '"49fe-2PP252UHJD4ZMXt5VpoaibQADuU"',
|
|
48
|
+
"mtime": "2026-06-29T13:24:14.326Z",
|
|
49
49
|
"size": 18942,
|
|
50
|
-
"path": "../public/assets/CompareDrawer-
|
|
50
|
+
"path": "../public/assets/CompareDrawer-DVNvS0GQ.js"
|
|
51
51
|
},
|
|
52
|
-
"/assets/index-
|
|
52
|
+
"/assets/index-B0YcFeL-.js": {
|
|
53
53
|
"type": "text/javascript; charset=utf-8",
|
|
54
|
-
"etag": '"74-
|
|
55
|
-
"mtime": "2026-06-
|
|
54
|
+
"etag": '"74-ohkGewLZlIYioQpffENsT1gm8EE"',
|
|
55
|
+
"mtime": "2026-06-29T13:24:14.325Z",
|
|
56
56
|
"size": 116,
|
|
57
|
-
"path": "../public/assets/index-
|
|
58
|
-
},
|
|
59
|
-
"/assets/index-780zTVwp.css": {
|
|
60
|
-
"type": "text/css; charset=utf-8",
|
|
61
|
-
"etag": '"1a380-Lz+Shs13XyKSlh9PTaGE50w/BpU"',
|
|
62
|
-
"mtime": "2026-06-29T10:57:03.958Z",
|
|
63
|
-
"size": 107392,
|
|
64
|
-
"path": "../public/assets/index-780zTVwp.css"
|
|
57
|
+
"path": "../public/assets/index-B0YcFeL-.js"
|
|
65
58
|
},
|
|
66
59
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
67
60
|
"type": "image/jpeg",
|
|
68
61
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
69
|
-
"mtime": "2026-06-
|
|
62
|
+
"mtime": "2026-06-29T13:24:14.325Z",
|
|
70
63
|
"size": 6918,
|
|
71
64
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
72
65
|
},
|
|
73
|
-
"/assets/
|
|
74
|
-
"type": "text/
|
|
75
|
-
"etag": '"
|
|
76
|
-
"mtime": "2026-06-
|
|
77
|
-
"size":
|
|
78
|
-
"path": "../public/assets/
|
|
66
|
+
"/assets/index-DsiKfWCp.css": {
|
|
67
|
+
"type": "text/css; charset=utf-8",
|
|
68
|
+
"etag": '"1a3d5-pnLJEAiyUUKlRw5OUnvwf1dCQeI"',
|
|
69
|
+
"mtime": "2026-06-29T13:24:14.325Z",
|
|
70
|
+
"size": 107477,
|
|
71
|
+
"path": "../public/assets/index-DsiKfWCp.css"
|
|
79
72
|
},
|
|
80
|
-
"/assets/main-
|
|
73
|
+
"/assets/main-kBQ49n13.js": {
|
|
81
74
|
"type": "text/javascript; charset=utf-8",
|
|
82
|
-
"etag": '"51726
|
|
83
|
-
"mtime": "2026-06-
|
|
75
|
+
"etag": '"51726-+FidFdV98/WDrHsP2x5s4MGlsZI"',
|
|
76
|
+
"mtime": "2026-06-29T13:24:14.325Z",
|
|
84
77
|
"size": 333606,
|
|
85
|
-
"path": "../public/assets/main-
|
|
78
|
+
"path": "../public/assets/main-kBQ49n13.js"
|
|
86
79
|
},
|
|
87
|
-
"/assets/ResponseView-
|
|
80
|
+
"/assets/ResponseView-ygsUs7FU.js": {
|
|
88
81
|
"type": "text/javascript; charset=utf-8",
|
|
89
|
-
"etag": '"30d0-
|
|
90
|
-
"mtime": "2026-06-
|
|
82
|
+
"etag": '"30d0-VoRHAUzRfGHjVqxMmhp9+gxQNvg"',
|
|
83
|
+
"mtime": "2026-06-29T13:24:14.326Z",
|
|
91
84
|
"size": 12496,
|
|
92
|
-
"path": "../public/assets/ResponseView-
|
|
85
|
+
"path": "../public/assets/ResponseView-ygsUs7FU.js"
|
|
93
86
|
},
|
|
94
|
-
"/assets/
|
|
87
|
+
"/assets/ReplayDialog-Cw6bN-NR.js": {
|
|
95
88
|
"type": "text/javascript; charset=utf-8",
|
|
96
|
-
"etag": '"
|
|
97
|
-
"mtime": "2026-06-
|
|
98
|
-
"size":
|
|
99
|
-
"path": "../public/assets/
|
|
89
|
+
"etag": '"318c-Ec8xMdTaVtWn+gQco0A8wJxm/Zw"',
|
|
90
|
+
"mtime": "2026-06-29T13:24:14.325Z",
|
|
91
|
+
"size": 12684,
|
|
92
|
+
"path": "../public/assets/ReplayDialog-Cw6bN-NR.js"
|
|
100
93
|
},
|
|
101
|
-
"/assets/StreamingChunkSequence-
|
|
94
|
+
"/assets/StreamingChunkSequence-DMUn8qXi.js": {
|
|
102
95
|
"type": "text/javascript; charset=utf-8",
|
|
103
|
-
"etag": '"d57-
|
|
104
|
-
"mtime": "2026-06-
|
|
96
|
+
"etag": '"d57-sKePDdoc8LggANuuW66cotctSKo"',
|
|
97
|
+
"mtime": "2026-06-29T13:24:14.326Z",
|
|
105
98
|
"size": 3415,
|
|
106
|
-
"path": "../public/assets/StreamingChunkSequence-
|
|
99
|
+
"path": "../public/assets/StreamingChunkSequence-DMUn8qXi.js"
|
|
107
100
|
},
|
|
108
|
-
"/assets/_sessionId-
|
|
101
|
+
"/assets/_sessionId-DoqvnFx7.js": {
|
|
109
102
|
"type": "text/javascript; charset=utf-8",
|
|
110
|
-
"etag": '"d2-
|
|
111
|
-
"mtime": "2026-06-
|
|
103
|
+
"etag": '"d2-eM4ckKV5XpF8O96oypRgw/AMrPQ"',
|
|
104
|
+
"mtime": "2026-06-29T13:24:14.325Z",
|
|
112
105
|
"size": 210,
|
|
113
|
-
"path": "../public/assets/_sessionId-
|
|
106
|
+
"path": "../public/assets/_sessionId-DoqvnFx7.js"
|
|
114
107
|
},
|
|
115
|
-
"/assets/
|
|
116
|
-
"type": "
|
|
117
|
-
"etag": '"
|
|
118
|
-
"mtime": "2026-06-
|
|
119
|
-
"size":
|
|
120
|
-
"path": "../public/assets/
|
|
108
|
+
"/assets/RequestAnatomy-DnIsirBE.js": {
|
|
109
|
+
"type": "text/javascript; charset=utf-8",
|
|
110
|
+
"etag": '"4485-FLpxtJEMMSiId/JKv/qeTF/xc4E"',
|
|
111
|
+
"mtime": "2026-06-29T13:24:14.326Z",
|
|
112
|
+
"size": 17541,
|
|
113
|
+
"path": "../public/assets/RequestAnatomy-DnIsirBE.js"
|
|
121
114
|
},
|
|
122
115
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
123
116
|
"type": "image/svg+xml",
|
|
124
117
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
125
|
-
"mtime": "2026-06-
|
|
118
|
+
"mtime": "2026-06-29T13:24:14.325Z",
|
|
126
119
|
"size": 11256,
|
|
127
120
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
128
121
|
},
|
|
129
|
-
"/assets/
|
|
122
|
+
"/assets/qwen-CONDcHqt.png": {
|
|
123
|
+
"type": "image/png",
|
|
124
|
+
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
125
|
+
"mtime": "2026-06-29T13:24:14.325Z",
|
|
126
|
+
"size": 357059,
|
|
127
|
+
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
128
|
+
},
|
|
129
|
+
"/assets/ProxyViewerContainer-By3XtQhZ.js": {
|
|
130
130
|
"type": "text/javascript; charset=utf-8",
|
|
131
|
-
"etag": '"
|
|
132
|
-
"mtime": "2026-06-
|
|
133
|
-
"size":
|
|
134
|
-
"path": "../public/assets/ProxyViewerContainer-
|
|
131
|
+
"etag": '"af111-Qj0fjruqs4EheKPZxm5LynPyIwI"',
|
|
132
|
+
"mtime": "2026-06-29T13:24:14.326Z",
|
|
133
|
+
"size": 717073,
|
|
134
|
+
"path": "../public/assets/ProxyViewerContainer-By3XtQhZ.js"
|
|
135
135
|
}
|
|
136
136
|
};
|
|
137
137
|
function readAsset(id) {
|
package/package.json
CHANGED
|
@@ -637,6 +637,7 @@ export function ProxyViewer({
|
|
|
637
637
|
const { totalIn, totalOut } = useMemo(() => computeTokenSummary(logs), [logs]);
|
|
638
638
|
const { providers } = useProviders();
|
|
639
639
|
const [exporting, setExporting] = useState<ExportMode | null>(null);
|
|
640
|
+
const [exportError, setExportError] = useState<string | null>(null);
|
|
640
641
|
const [comparePair, setComparePair] = useState<[CapturedLog, CapturedLog] | null>(null);
|
|
641
642
|
const [crabEntrancePhase, setCrabEntrancePhase] = useState<"hidden" | "playing" | "done">(
|
|
642
643
|
"hidden",
|
|
@@ -669,8 +670,12 @@ export function ProxyViewer({
|
|
|
669
670
|
const handleExport = useCallback(
|
|
670
671
|
async (mode: ExportMode) => {
|
|
671
672
|
setExporting(mode);
|
|
673
|
+
setExportError(null);
|
|
672
674
|
try {
|
|
673
|
-
await exportLogsAsZip(logs, mode);
|
|
675
|
+
const result = await exportLogsAsZip(logs, mode);
|
|
676
|
+
if (!result.ok) {
|
|
677
|
+
setExportError(result.message);
|
|
678
|
+
}
|
|
674
679
|
} finally {
|
|
675
680
|
setExporting(null);
|
|
676
681
|
}
|
|
@@ -908,6 +913,11 @@ export function ProxyViewer({
|
|
|
908
913
|
Clear
|
|
909
914
|
</button>
|
|
910
915
|
</div>
|
|
916
|
+
{exportError !== null && (
|
|
917
|
+
<div className="mb-4 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive">
|
|
918
|
+
{exportError}
|
|
919
|
+
</div>
|
|
920
|
+
)}
|
|
911
921
|
</div>
|
|
912
922
|
|
|
913
923
|
{/* Log list */}
|