@tonyclaw/agent-inspector 2.0.22 → 2.0.24

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.
Files changed (37) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-NEdpe1wl.js → CompareDrawer-DrY-gAzy.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-CiLvRNie.js +115 -0
  4. package/.output/public/assets/{ReplayDialog-DijzJwaQ.js → ReplayDialog-CFyw6Vu4.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-CYbosGYy.js → RequestAnatomy-DHGJ9py7.js} +1 -1
  6. package/.output/public/assets/{ResponseView-B3dPM63X.js → ResponseView-CB_3yc08.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-DYDx3xRY.js → StreamingChunkSequence-CqhHwgDn.js} +1 -1
  8. package/.output/public/assets/_sessionId-CgG9CQ9r.js +1 -0
  9. package/.output/public/assets/index-CViEXkqa.js +1 -0
  10. package/.output/public/assets/{main-N-sjHJUM.js → main-CVw7-JyE.js} +2 -2
  11. package/.output/server/{_sessionId-BR46y_bO.mjs → _sessionId-V33sBWBC.mjs} +2 -2
  12. package/.output/server/_ssr/{CompareDrawer-DDxpmdPs.mjs → CompareDrawer-C_Fk9joM.mjs} +2 -2
  13. package/.output/server/_ssr/{ProxyViewerContainer-B1zAefzz.mjs → ProxyViewerContainer-CyFKksQa.mjs} +75 -32
  14. package/.output/server/_ssr/{ReplayDialog-DleMFvMx.mjs → ReplayDialog-BpQHN7O2.mjs} +3 -3
  15. package/.output/server/_ssr/{RequestAnatomy-B-P9tC3D.mjs → RequestAnatomy-CuhmKAma.mjs} +2 -2
  16. package/.output/server/_ssr/{ResponseView-DWfGn0i3.mjs → ResponseView-CO6LyBmj.mjs} +2 -2
  17. package/.output/server/_ssr/{StreamingChunkSequence-C8kFF6xJ.mjs → StreamingChunkSequence-DLeVetNR.mjs} +2 -2
  18. package/.output/server/_ssr/{index-DzENi2RO.mjs → index-DWUKl9Bf.mjs} +2 -2
  19. package/.output/server/_ssr/index.mjs +2 -2
  20. package/.output/server/_ssr/{router-Dy1VEjxy.mjs → router-BrK_DcTS.mjs} +337 -86
  21. package/.output/server/{_tanstack-start-manifest_v-CyzuAD8A.mjs → _tanstack-start-manifest_v-BjW2XeWE.mjs} +1 -1
  22. package/.output/server/index.mjs +57 -57
  23. package/package.json +1 -1
  24. package/src/components/ProxyViewer.tsx +11 -1
  25. package/src/components/ProxyViewerContainer.tsx +21 -15
  26. package/src/lib/export-logs.ts +54 -11
  27. package/src/lib/providerTestPrompt.ts +4 -4
  28. package/src/mcp/toolHandlers.ts +58 -8
  29. package/src/proxy/logFinalizer.ts +79 -1
  30. package/src/proxy/logIndex.ts +6 -1
  31. package/src/proxy/schemas.ts +3 -0
  32. package/src/proxy/store.ts +275 -135
  33. package/src/routes/api/logs.stream.ts +6 -3
  34. package/src/routes/api/logs.ts +4 -1
  35. package/.output/public/assets/ProxyViewerContainer-Dwhi4Q1c.js +0 -115
  36. package/.output/public/assets/_sessionId-b1KDnByv.js +0 -1
  37. package/.output/public/assets/index-CUyRKgII.js +0 -1
@@ -1,8 +1,8 @@
1
1
  import { c as createRouter, a as createRootRoute, b as createFileRoute, l as lazyRouteComponent, O as Outlet, H as HeadContent, S as Scripts } from "../_libs/tanstack__react-router.mjs";
2
2
  import { j as jsxRuntimeExports } from "../_libs/react.mjs";
3
3
  import { S as SWRConfig } from "../_libs/swr.mjs";
4
- import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync, copyFileSync, unlinkSync, readdirSync, statSync, createReadStream, cpSync, rmSync } from "node:fs";
5
- import fs, { mkdir, appendFile, readFile, writeFile, readdir, open, stat, unlink } from "node:fs/promises";
4
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync, copyFileSync, unlinkSync, readdirSync, statSync, createReadStream, cpSync, rmSync, createWriteStream } from "node:fs";
5
+ import fs, { mkdir, appendFile, readFile, writeFile, readdir, open, stat, unlink, rename } from "node:fs/promises";
6
6
  import { createInterface } from "node:readline";
7
7
  import { Buffer } from "node:buffer";
8
8
  import path, { join, isAbsolute, dirname } from "node:path";
@@ -93,7 +93,7 @@ function RootDocument({ children }) {
93
93
  ] })
94
94
  ] });
95
95
  }
96
- const $$splitComponentImporter$1 = () => import("./index-DzENi2RO.mjs");
96
+ const $$splitComponentImporter$1 = () => import("./index-DWUKl9Bf.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-BR46y_bO.mjs");
139
+ const $$splitComponentImporter = () => import("../_sessionId-V33sBWBC.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;
@@ -1458,30 +1485,7 @@ async function getLogById(id) {
1458
1485
  }
1459
1486
  return null;
1460
1487
  }
1461
- const content = readFileSync(filePath, "utf-8");
1462
- const lines = content.split("\n");
1463
- let lastMatch = null;
1464
- for (const line of lines) {
1465
- if (line.trim() === "") continue;
1466
- try {
1467
- const parsed = JSON.parse(line);
1468
- if (typeof parsed === "object" && parsed !== null) {
1469
- const desc = Object.getOwnPropertyDescriptor(parsed, "id");
1470
- if (desc !== void 0 && typeof desc.value === "number" && desc.value === id) {
1471
- const result = CapturedLogSchema.safeParse(parsed);
1472
- if (result.success) {
1473
- lastMatch = normalizeLogSession(result.data);
1474
- if (result.data.responseStatus !== null) {
1475
- addToCache(lastMatch);
1476
- observeSessionLog(lastMatch);
1477
- return lastMatch;
1478
- }
1479
- }
1480
- }
1481
- }
1482
- } catch {
1483
- }
1484
- }
1488
+ const lastMatch = await scanLogFileForId(filePath, id);
1485
1489
  if (lastMatch !== null) {
1486
1490
  addToCache(lastMatch);
1487
1491
  observeSessionLog(lastMatch);
@@ -1492,6 +1496,33 @@ async function getLogById(id) {
1492
1496
  }
1493
1497
  return null;
1494
1498
  }
1499
+ async function scanLogFileForId(filePath, id) {
1500
+ let lastMatch = null;
1501
+ const fileStream = createInterface({
1502
+ input: createReadStream(filePath),
1503
+ crlfDelay: Infinity
1504
+ });
1505
+ for await (const line of fileStream) {
1506
+ if (line.trim() === "") continue;
1507
+ try {
1508
+ const parsed = JSON.parse(line);
1509
+ if (typeof parsed === "object" && parsed !== null) {
1510
+ const desc = Object.getOwnPropertyDescriptor(parsed, "id");
1511
+ if (desc !== void 0 && typeof desc.value === "number" && desc.value === id) {
1512
+ const result = CapturedLogSchema.safeParse(parsed);
1513
+ if (result.success) {
1514
+ lastMatch = normalizeLogSession(result.data);
1515
+ if (result.data.responseStatus !== null) {
1516
+ return lastMatch;
1517
+ }
1518
+ }
1519
+ }
1520
+ }
1521
+ } catch {
1522
+ }
1523
+ }
1524
+ return lastMatch;
1525
+ }
1495
1526
  function getFilteredLogs(sessionId, model) {
1496
1527
  return [...memoryCache.values()].filter((l) => {
1497
1528
  return matchesLogFilters(l, sessionId, model);
@@ -1502,31 +1533,20 @@ function matchesLogFilters(log, sessionId, model) {
1502
1533
  if (model !== void 0 && log.model !== model) return false;
1503
1534
  return true;
1504
1535
  }
1505
- function requestedWindowFitsMemory(filteredMemoryCount, offset, limit) {
1506
- return offset + limit <= filteredMemoryCount;
1507
- }
1508
- function paginateLogs(logs, offset, limit) {
1509
- return logs.slice(offset, offset + limit);
1510
- }
1511
- async function readPersistedLogsById() {
1512
- const byId = /* @__PURE__ */ new Map();
1536
+ async function visitPersistedLogs(visitor) {
1513
1537
  const logDir = resolveLogDir();
1514
- if (!existsSync(logDir)) return byId;
1538
+ if (!existsSync(logDir)) return;
1515
1539
  try {
1516
1540
  const entries = await readdir(logDir);
1517
1541
  const files = entries.filter((file) => file.endsWith(".jsonl")).sort();
1518
1542
  for (const file of files) {
1519
- await readPersistedLogFile(join(logDir, file), byId);
1543
+ await visitPersistedLogFile(join(logDir, file), visitor);
1520
1544
  }
1521
1545
  } catch (err) {
1522
1546
  logger.error("[store] Failed to list persisted logs:", String(err));
1523
1547
  }
1524
- for (const log of memoryCache.values()) {
1525
- byId.set(log.id, log);
1526
- }
1527
- return byId;
1528
1548
  }
1529
- async function readPersistedLogFile(filePath, byId) {
1549
+ async function visitPersistedLogFile(filePath, visitor) {
1530
1550
  if (!existsSync(filePath)) return;
1531
1551
  try {
1532
1552
  const fileStream = createInterface({
@@ -1540,8 +1560,7 @@ async function readPersistedLogFile(filePath, byId) {
1540
1560
  const result = CapturedLogSchema.safeParse(parsed);
1541
1561
  if (result.success) {
1542
1562
  const log = normalizeLogSession(result.data);
1543
- byId.set(log.id, log);
1544
- observeSessionLog(log);
1563
+ visitor(log);
1545
1564
  }
1546
1565
  } catch {
1547
1566
  }
@@ -1550,21 +1569,77 @@ async function readPersistedLogFile(filePath, byId) {
1550
1569
  logger.error("[store] Failed to read persisted log file:", filePath, String(err));
1551
1570
  }
1552
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
+ }
1553
1608
  async function listLogsPage(options) {
1554
- const memoryLogs = getFilteredLogs(options.sessionId, options.model);
1555
- if (requestedWindowFitsMemory(memoryLogs.length, options.offset, options.limit)) {
1556
- return {
1557
- logs: paginateLogs(memoryLogs, options.offset, options.limit),
1558
- total: memoryLogs.length,
1559
- offset: options.offset,
1560
- limit: options.limit
1561
- };
1609
+ const indexedPage = await listLogsPageFromIndex(options, true);
1610
+ if (indexedPage !== null) return indexedPage;
1611
+ const seenIds = /* @__PURE__ */ new Set();
1612
+ const pageById = /* @__PURE__ */ new Map();
1613
+ const pageStart = options.offset;
1614
+ const pageEnd = options.offset + options.limit;
1615
+ const includeBodies = options.includeBodies !== false;
1616
+ let total = 0;
1617
+ const visitLog = (log) => {
1618
+ if (!matchesLogFilters(log, options.sessionId, options.model)) return;
1619
+ if (!seenIds.has(log.id)) {
1620
+ seenIds.add(log.id);
1621
+ const position = total;
1622
+ total += 1;
1623
+ if (position >= pageStart && position < pageEnd) {
1624
+ pageById.set(log.id, prepareLogForList(log, includeBodies));
1625
+ }
1626
+ return;
1627
+ }
1628
+ if (pageById.has(log.id)) {
1629
+ pageById.set(log.id, prepareLogForList(log, includeBodies));
1630
+ }
1631
+ };
1632
+ await visitPersistedLogs((log) => {
1633
+ observeSessionLog(log);
1634
+ visitLog(log);
1635
+ });
1636
+ for (const log of memoryCache.values()) {
1637
+ visitLog(log);
1562
1638
  }
1563
- const persistedById = await readPersistedLogsById();
1564
- const persistedLogs = [...persistedById.values()].filter((log) => matchesLogFilters(log, options.sessionId, options.model)).sort((left, right) => left.id - right.id);
1639
+ const logs = [...pageById.values()].sort((left, right) => left.id - right.id);
1565
1640
  return {
1566
- logs: paginateLogs(persistedLogs, options.offset, options.limit),
1567
- total: persistedLogs.length,
1641
+ logs,
1642
+ total,
1568
1643
  offset: options.offset,
1569
1644
  limit: options.limit
1570
1645
  };
@@ -1687,35 +1762,100 @@ function readLogIdFromLine(line) {
1687
1762
  return null;
1688
1763
  }
1689
1764
  }
1765
+ function tempRewritePath(filePath) {
1766
+ return `${filePath}.rewrite-${String(process.pid)}-${String(Date.now())}.tmp`;
1767
+ }
1768
+ async function removeTempFile(filePath) {
1769
+ try {
1770
+ await unlink(filePath);
1771
+ } catch {
1772
+ }
1773
+ }
1774
+ function waitForWriterDrain(writer) {
1775
+ return new Promise((resolve) => {
1776
+ const cleanup = () => {
1777
+ writer.off("drain", onDrain);
1778
+ writer.off("error", onError);
1779
+ };
1780
+ const onDrain = () => {
1781
+ cleanup();
1782
+ resolve(true);
1783
+ };
1784
+ const onError = () => {
1785
+ cleanup();
1786
+ resolve(false);
1787
+ };
1788
+ writer.once("drain", onDrain);
1789
+ writer.once("error", onError);
1790
+ });
1791
+ }
1792
+ async function writeKeptLogLine(writer, line) {
1793
+ if (writer.write(`${line}
1794
+ `, "utf-8")) return true;
1795
+ return await waitForWriterDrain(writer);
1796
+ }
1797
+ function finishWriter(writer) {
1798
+ return new Promise((resolve) => {
1799
+ const cleanup = () => {
1800
+ writer.off("finish", onFinish);
1801
+ writer.off("error", onError);
1802
+ };
1803
+ const onFinish = () => {
1804
+ cleanup();
1805
+ resolve(true);
1806
+ };
1807
+ const onError = () => {
1808
+ cleanup();
1809
+ resolve(false);
1810
+ };
1811
+ writer.once("finish", onFinish);
1812
+ writer.once("error", onError);
1813
+ writer.end();
1814
+ });
1815
+ }
1690
1816
  async function rewriteLogFileWithoutIds(filePath, ids) {
1691
- let content;
1817
+ const tempPath = tempRewritePath(filePath);
1818
+ const writer = createWriteStream(tempPath, { encoding: "utf-8" });
1819
+ const removedIds = /* @__PURE__ */ new Set();
1820
+ let keptLineCount = 0;
1821
+ let writeOk = true;
1692
1822
  try {
1693
- content = await readFile(filePath, "utf-8");
1823
+ const fileStream = createInterface({
1824
+ input: createReadStream(filePath),
1825
+ crlfDelay: Infinity
1826
+ });
1827
+ for await (const line of fileStream) {
1828
+ if (line === "") continue;
1829
+ const id = readLogIdFromLine(line);
1830
+ if (id !== null && ids.has(id)) {
1831
+ removedIds.add(id);
1832
+ } else {
1833
+ keptLineCount += 1;
1834
+ writeOk = await writeKeptLogLine(writer, line);
1835
+ if (!writeOk) break;
1836
+ }
1837
+ }
1694
1838
  } catch (err) {
1695
- logger.warn("[store] Failed to read log file for deletion:", filePath, String(err));
1839
+ logger.warn("[store] Failed to stream log file for deletion:", filePath, String(err));
1840
+ writeOk = false;
1841
+ }
1842
+ if (!await finishWriter(writer) || !writeOk) {
1843
+ await removeTempFile(tempPath);
1696
1844
  return { rewritten: false, removedIds: /* @__PURE__ */ new Set() };
1697
1845
  }
1698
- const lines = content.split("\n");
1699
- const keptLines = [];
1700
- const removedIds = /* @__PURE__ */ new Set();
1701
- for (const line of lines) {
1702
- if (line === "") continue;
1703
- const id = readLogIdFromLine(line);
1704
- if (id !== null && ids.has(id)) {
1705
- removedIds.add(id);
1706
- } else {
1707
- keptLines.push(line);
1708
- }
1846
+ if (removedIds.size === 0) {
1847
+ await removeTempFile(tempPath);
1848
+ return { rewritten: false, removedIds };
1709
1849
  }
1710
- if (removedIds.size === 0) return { rewritten: false, removedIds };
1711
1850
  try {
1712
- if (keptLines.length === 0) {
1851
+ if (keptLineCount === 0) {
1852
+ await removeTempFile(tempPath);
1713
1853
  await unlink(filePath);
1714
1854
  } else {
1715
- await writeFile(filePath, `${keptLines.join("\n")}
1716
- `, "utf-8");
1855
+ await rename(tempPath, filePath);
1717
1856
  }
1718
1857
  } catch (err) {
1858
+ await removeTempFile(tempPath);
1719
1859
  logger.warn("[store] Failed to rewrite log file after deletion:", filePath, String(err));
1720
1860
  return { rewritten: false, removedIds: /* @__PURE__ */ new Set() };
1721
1861
  }
@@ -3777,6 +3917,14 @@ function stripOpenAIOrphanToolMessages(rawBody) {
3777
3917
  parsed.messages = kept;
3778
3918
  return { body: JSON.stringify(parsed), removed: indices.length, orphanIds };
3779
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
+ }
3780
3928
  function buildFileLogEntry(log, upstreamUrl) {
3781
3929
  return {
3782
3930
  timestamp: log.timestamp,
@@ -3859,6 +4007,37 @@ function cleanupPathForRawStream(rawStream) {
3859
4007
  return rawStream.path;
3860
4008
  }
3861
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
+ }
3862
4041
  function readRawStream(rawStream) {
3863
4042
  if (typeof rawStream === "string") {
3864
4043
  return { rawStreamText: rawStream, cleanupRawStreamPath: null };
@@ -3885,6 +4064,18 @@ function finalizeStreaming(job, log) {
3885
4064
  cleanupPathForRawStream(job.rawStream)
3886
4065
  );
3887
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
+ }
3888
4079
  let rawStreamText = "";
3889
4080
  let cleanupRawStreamPath = null;
3890
4081
  try {
@@ -3929,6 +4120,16 @@ function finalizeStreamAbort(job, log) {
3929
4120
  try {
3930
4121
  log.elapsedMs = job.elapsedMs;
3931
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
+ }
3932
4133
  const raw = readRawStream(job.rawStream);
3933
4134
  rawStreamText = raw.rawStreamText;
3934
4135
  cleanupRawStreamPath = raw.cleanupRawStreamPath;
@@ -4682,6 +4883,7 @@ const LogsListResponseSchema = object({
4682
4883
  });
4683
4884
  const PAGINATION_DEFAULTS = { offset: 0, limit: 3 };
4684
4885
  const LIMIT_HARD_CAP = 5;
4886
+ const LOG_DETAIL_TEXT_LIMIT = 2e5;
4685
4887
  function clampLimit(input) {
4686
4888
  if (input === void 0) return PAGINATION_DEFAULTS.limit;
4687
4889
  if (!Number.isFinite(input) || input < 1) return 1;
@@ -4693,8 +4895,46 @@ function textJson(data) {
4693
4895
  function toolError(message) {
4694
4896
  return { content: [{ type: "text", text: message }], isError: true };
4695
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
+ }
4696
4934
  function buildLogSummary(log) {
4697
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);
4698
4938
  return {
4699
4939
  id: log.id,
4700
4940
  timestamp: log.timestamp,
@@ -4718,13 +4958,19 @@ function buildLogSummary(log) {
4718
4958
  lastUserMessagePreview: extractLastUserMessagePreview(log),
4719
4959
  responsePreview: extractResponsePreview(log),
4720
4960
  hasChunks: log.streamingChunks !== void 0 && log.streamingChunks !== null || log.streamingChunksPath !== null && log.streamingChunksPath !== void 0,
4721
- hasRawRequestBody: log.rawRequestBody !== null && log.rawRequestBody !== void 0
4961
+ hasRawRequestBody: hasBodyText(log.rawRequestBody, rawRequestBodyBytes),
4962
+ rawRequestBodyBytes,
4963
+ responseTextBytes
4722
4964
  };
4723
4965
  }
4724
4966
  async function listLogsImpl(callApi2, args) {
4725
4967
  const offset = args.offset ?? PAGINATION_DEFAULTS.offset;
4726
4968
  const limit = clampLimit(args.limit);
4727
- const params = new URLSearchParams({ offset: String(offset), limit: String(limit) });
4969
+ const params = new URLSearchParams({
4970
+ offset: String(offset),
4971
+ limit: String(limit),
4972
+ compact: "1"
4973
+ });
4728
4974
  if (args.sessionId !== void 0 && args.sessionId.length > 0) {
4729
4975
  params.set("sessionId", args.sessionId);
4730
4976
  }
@@ -4747,8 +4993,7 @@ async function getLogImpl(callApi2, id) {
4747
4993
  if (!parsed.success) {
4748
4994
  return toolError(`GET /api/logs/${id} returned an unparseable CapturedLog`);
4749
4995
  }
4750
- const { streamingChunks: _chunks, ...rest } = parsed.data;
4751
- return textJson(rest);
4996
+ return textJson(buildBoundedLogDetail(parsed.data));
4752
4997
  }
4753
4998
  async function getLogChunksImpl(callApi2, id) {
4754
4999
  const res = await callApi2(`/api/logs/${id}/chunks`);
@@ -5185,7 +5430,10 @@ const Route$k = createFileRoute("/api/logs")({
5185
5430
  const model = url.searchParams.get("model") ?? void 0;
5186
5431
  const offset = parseNonNegativeInt(url.searchParams.get("offset"), 0);
5187
5432
  const limit = parsePositiveInt(url.searchParams.get("limit"), 50);
5188
- return Response.json(await listLogsPage({ sessionId, model, offset, limit }));
5433
+ const includeBodies = url.searchParams.get("compact") !== "1";
5434
+ return Response.json(
5435
+ await listLogsPage({ sessionId, model, offset, limit, includeBodies })
5436
+ );
5189
5437
  },
5190
5438
  DELETE: async ({ request }) => {
5191
5439
  let body = void 0;
@@ -5820,7 +6068,7 @@ const Route$e = createFileRoute("/api/providers/$providerId")({
5820
6068
  }
5821
6069
  }
5822
6070
  });
5823
- const INITIAL_STREAM_LOG_LIMIT = 500;
6071
+ const INITIAL_STREAM_LOG_LIMIT = 100;
5824
6072
  const Route$d = createFileRoute("/api/logs/stream")({
5825
6073
  server: {
5826
6074
  handlers: {
@@ -5828,6 +6076,7 @@ const Route$d = createFileRoute("/api/logs/stream")({
5828
6076
  const url = new URL(request.url);
5829
6077
  const sessionId = url.searchParams.get("sessionId") ?? void 0;
5830
6078
  const model = url.searchParams.get("model") ?? void 0;
6079
+ const includeBodies = url.searchParams.get("compact") !== "1";
5831
6080
  let controllerRef = null;
5832
6081
  let cleanedUp = false;
5833
6082
  const unsubscribe = onLogUpdate((log) => {
@@ -5835,7 +6084,8 @@ const Route$d = createFileRoute("/api/logs/stream")({
5835
6084
  if (sessionId !== void 0 && getLogSessionId(log) !== sessionId) return;
5836
6085
  if (model !== void 0 && log.model !== model) return;
5837
6086
  try {
5838
- const data = `data: ${JSON.stringify({ type: "update", log })}
6087
+ const payloadLog = includeBodies ? log : compactLogForList(log);
6088
+ const data = `data: ${JSON.stringify({ type: "update", log: payloadLog })}
5839
6089
 
5840
6090
  `;
5841
6091
  controllerRef.enqueue(new TextEncoder().encode(data));
@@ -5868,7 +6118,8 @@ const Route$d = createFileRoute("/api/logs/stream")({
5868
6118
  sessionId,
5869
6119
  model,
5870
6120
  offset: 0,
5871
- limit: INITIAL_STREAM_LOG_LIMIT
6121
+ limit: INITIAL_STREAM_LOG_LIMIT,
6122
+ includeBodies
5872
6123
  });
5873
6124
  const logs = result.logs;
5874
6125
  const initData = `data: ${JSON.stringify({ type: "init", logs })}
@@ -6568,9 +6819,9 @@ function modeInstruction(mode) {
6568
6819
  function maxTokensForMode(mode) {
6569
6820
  switch (mode) {
6570
6821
  case "non-streaming":
6571
- return 1024;
6822
+ return 256;
6572
6823
  case "streaming":
6573
- return 384;
6824
+ return 256;
6574
6825
  }
6575
6826
  }
6576
6827
  function buildProviderTestUserPrompt(mode) {
@@ -6601,7 +6852,7 @@ function buildProviderTestRequestBody(model, mode) {
6601
6852
  };
6602
6853
  switch (mode) {
6603
6854
  case "non-streaming":
6604
- return base;
6855
+ return { ...base, stream: false };
6605
6856
  case "streaming":
6606
6857
  return { ...base, stream: true };
6607
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-N-sjHJUM.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-CUyRKgII.js", "/assets/ProxyViewerContainer-Dwhi4Q1c.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-b1KDnByv.js", "/assets/ProxyViewerContainer-Dwhi4Q1c.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-N-sjHJUM.js" });
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-CVw7-JyE.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-CViEXkqa.js", "/assets/ProxyViewerContainer-CiLvRNie.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-CgG9CQ9r.js", "/assets/ProxyViewerContainer-CiLvRNie.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-CVw7-JyE.js" });
2
2
  export {
3
3
  tsrStartManifest
4
4
  };