@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.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-NEdpe1wl.js → CompareDrawer-DrY-gAzy.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-CiLvRNie.js +115 -0
- package/.output/public/assets/{ReplayDialog-DijzJwaQ.js → ReplayDialog-CFyw6Vu4.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-CYbosGYy.js → RequestAnatomy-DHGJ9py7.js} +1 -1
- package/.output/public/assets/{ResponseView-B3dPM63X.js → ResponseView-CB_3yc08.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-DYDx3xRY.js → StreamingChunkSequence-CqhHwgDn.js} +1 -1
- package/.output/public/assets/_sessionId-CgG9CQ9r.js +1 -0
- package/.output/public/assets/index-CViEXkqa.js +1 -0
- package/.output/public/assets/{main-N-sjHJUM.js → main-CVw7-JyE.js} +2 -2
- package/.output/server/{_sessionId-BR46y_bO.mjs → _sessionId-V33sBWBC.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-DDxpmdPs.mjs → CompareDrawer-C_Fk9joM.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-B1zAefzz.mjs → ProxyViewerContainer-CyFKksQa.mjs} +75 -32
- package/.output/server/_ssr/{ReplayDialog-DleMFvMx.mjs → ReplayDialog-BpQHN7O2.mjs} +3 -3
- package/.output/server/_ssr/{RequestAnatomy-B-P9tC3D.mjs → RequestAnatomy-CuhmKAma.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-DWfGn0i3.mjs → ResponseView-CO6LyBmj.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-C8kFF6xJ.mjs → StreamingChunkSequence-DLeVetNR.mjs} +2 -2
- package/.output/server/_ssr/{index-DzENi2RO.mjs → index-DWUKl9Bf.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-Dy1VEjxy.mjs → router-BrK_DcTS.mjs} +337 -86
- package/.output/server/{_tanstack-start-manifest_v-CyzuAD8A.mjs → _tanstack-start-manifest_v-BjW2XeWE.mjs} +1 -1
- package/.output/server/index.mjs +57 -57
- package/package.json +1 -1
- package/src/components/ProxyViewer.tsx +11 -1
- package/src/components/ProxyViewerContainer.tsx +21 -15
- package/src/lib/export-logs.ts +54 -11
- package/src/lib/providerTestPrompt.ts +4 -4
- 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 +275 -135
- package/src/routes/api/logs.stream.ts +6 -3
- package/src/routes/api/logs.ts +4 -1
- package/.output/public/assets/ProxyViewerContainer-Dwhi4Q1c.js +0 -115
- package/.output/public/assets/_sessionId-b1KDnByv.js +0 -1
- 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-
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
1555
|
-
if (
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
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
|
|
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
|
|
1567
|
-
total
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
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 (
|
|
1851
|
+
if (keptLineCount === 0) {
|
|
1852
|
+
await removeTempFile(tempPath);
|
|
1713
1853
|
await unlink(filePath);
|
|
1714
1854
|
} else {
|
|
1715
|
-
await
|
|
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
|
|
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({
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
|
6822
|
+
return 256;
|
|
6572
6823
|
case "streaming":
|
|
6573
|
-
return
|
|
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-
|
|
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
|
};
|