@tonyclaw/agent-inspector 2.0.21 → 2.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/cli.js +10 -0
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-ztKMd-FE.js → CompareDrawer-DnYQtd8R.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-BTYGkg36.js +115 -0
- package/.output/public/assets/{ReplayDialog-RNhfLSsW.js → ReplayDialog-B-3V95xT.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-fsUI5HhH.js → RequestAnatomy-CT8hLGLa.js} +1 -1
- package/.output/public/assets/{ResponseView-B3YTDBBX.js → ResponseView-DK3CYom0.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-CbGqQ0mO.js → StreamingChunkSequence-D3jJutjp.js} +1 -1
- package/.output/public/assets/_sessionId-DpdfAzbo.js +1 -0
- package/.output/public/assets/index-780zTVwp.css +1 -0
- package/.output/public/assets/index-BpJNbm9G.js +1 -0
- package/.output/public/assets/{main-lTQKpxiU.js → main-hF_572U6.js} +2 -2
- package/.output/server/_libs/lucide-react.mjs +27 -27
- package/.output/server/{_sessionId-DsF6LFJG.mjs → _sessionId-BqhNE2M8.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-DgdZcMpg.mjs → CompareDrawer-C4LQW4S1.mjs} +3 -3
- package/.output/server/_ssr/{ProxyViewerContainer-DaFW1IVu.mjs → ProxyViewerContainer-BKInvawk.mjs} +214 -41
- package/.output/server/_ssr/{ReplayDialog-BOaTX1ir.mjs → ReplayDialog-C3ZiRihL.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-C-2_dejd.mjs → RequestAnatomy-DlVAPIQZ.mjs} +3 -3
- package/.output/server/_ssr/{ResponseView-BtRVhgzy.mjs → ResponseView-nMS0rkxu.mjs} +3 -3
- package/.output/server/_ssr/{StreamingChunkSequence-DZaerowX.mjs → StreamingChunkSequence-PDWqrNiO.mjs} +3 -3
- package/.output/server/_ssr/{index-B3_fgwFy.mjs → index-Cd1zD-lo.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-CDOnHAWy.mjs → router-R9gm7_sh.mjs} +394 -151
- package/.output/server/{_tanstack-start-manifest_v-Brrx1NEa.mjs → _tanstack-start-manifest_v-BnLVH_EX.mjs} +1 -1
- package/.output/server/index.mjs +60 -60
- package/package.json +1 -1
- package/src/cli/templates/codex-skill-onboard.ts +5 -0
- package/src/cli/templates/skill-onboard.ts +5 -0
- package/src/components/OnboardingBanner.tsx +4 -0
- package/src/components/ProxyViewer.tsx +5 -0
- package/src/components/providers/ProviderCard.tsx +178 -38
- package/src/components/providers/ProvidersPanel.tsx +21 -3
- package/src/components/providers/SettingsDialog.tsx +76 -2
- package/src/lib/providerTestContract.ts +13 -0
- package/src/lib/runtimeConfig.ts +8 -0
- package/src/lib/useOnboarding.ts +3 -0
- package/src/lib/useStripConfig.ts +22 -0
- package/src/proxy/config.ts +4 -0
- package/src/proxy/store.ts +198 -135
- package/src/routes/api/config.ts +7 -0
- package/src/routes/api/logs.stream.ts +1 -1
- package/src/routes/api/providers.$providerId.test.log.ts +28 -12
- package/.output/public/assets/ProxyViewerContainer-BT8Ilsbs.js +0 -114
- package/.output/public/assets/_sessionId-C9cpyfLX.js +0 -1
- package/.output/public/assets/index-0mTTpvA2.js +0 -1
- package/.output/public/assets/index-DynnYt7S.css +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";
|
|
@@ -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-780zTVwp.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-Cd1zD-lo.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-BqhNE2M8.mjs");
|
|
140
140
|
const Route$q = createFileRoute("/session/$sessionId")({
|
|
141
141
|
component: lazyRouteComponent($$splitComponentImporter, "component"),
|
|
142
142
|
parseParams: (params) => ({
|
|
@@ -1458,30 +1458,7 @@ async function getLogById(id) {
|
|
|
1458
1458
|
}
|
|
1459
1459
|
return null;
|
|
1460
1460
|
}
|
|
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
|
-
}
|
|
1461
|
+
const lastMatch = await scanLogFileForId(filePath, id);
|
|
1485
1462
|
if (lastMatch !== null) {
|
|
1486
1463
|
addToCache(lastMatch);
|
|
1487
1464
|
observeSessionLog(lastMatch);
|
|
@@ -1492,6 +1469,33 @@ async function getLogById(id) {
|
|
|
1492
1469
|
}
|
|
1493
1470
|
return null;
|
|
1494
1471
|
}
|
|
1472
|
+
async function scanLogFileForId(filePath, id) {
|
|
1473
|
+
let lastMatch = null;
|
|
1474
|
+
const fileStream = createInterface({
|
|
1475
|
+
input: createReadStream(filePath),
|
|
1476
|
+
crlfDelay: Infinity
|
|
1477
|
+
});
|
|
1478
|
+
for await (const line of fileStream) {
|
|
1479
|
+
if (line.trim() === "") continue;
|
|
1480
|
+
try {
|
|
1481
|
+
const parsed = JSON.parse(line);
|
|
1482
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
1483
|
+
const desc = Object.getOwnPropertyDescriptor(parsed, "id");
|
|
1484
|
+
if (desc !== void 0 && typeof desc.value === "number" && desc.value === id) {
|
|
1485
|
+
const result = CapturedLogSchema.safeParse(parsed);
|
|
1486
|
+
if (result.success) {
|
|
1487
|
+
lastMatch = normalizeLogSession(result.data);
|
|
1488
|
+
if (result.data.responseStatus !== null) {
|
|
1489
|
+
return lastMatch;
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
} catch {
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
return lastMatch;
|
|
1498
|
+
}
|
|
1495
1499
|
function getFilteredLogs(sessionId, model) {
|
|
1496
1500
|
return [...memoryCache.values()].filter((l) => {
|
|
1497
1501
|
return matchesLogFilters(l, sessionId, model);
|
|
@@ -1502,31 +1506,20 @@ function matchesLogFilters(log, sessionId, model) {
|
|
|
1502
1506
|
if (model !== void 0 && log.model !== model) return false;
|
|
1503
1507
|
return true;
|
|
1504
1508
|
}
|
|
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();
|
|
1509
|
+
async function visitPersistedLogs(visitor) {
|
|
1513
1510
|
const logDir = resolveLogDir();
|
|
1514
|
-
if (!existsSync(logDir)) return
|
|
1511
|
+
if (!existsSync(logDir)) return;
|
|
1515
1512
|
try {
|
|
1516
1513
|
const entries = await readdir(logDir);
|
|
1517
1514
|
const files = entries.filter((file) => file.endsWith(".jsonl")).sort();
|
|
1518
1515
|
for (const file of files) {
|
|
1519
|
-
await
|
|
1516
|
+
await visitPersistedLogFile(join(logDir, file), visitor);
|
|
1520
1517
|
}
|
|
1521
1518
|
} catch (err) {
|
|
1522
1519
|
logger.error("[store] Failed to list persisted logs:", String(err));
|
|
1523
1520
|
}
|
|
1524
|
-
for (const log of memoryCache.values()) {
|
|
1525
|
-
byId.set(log.id, log);
|
|
1526
|
-
}
|
|
1527
|
-
return byId;
|
|
1528
1521
|
}
|
|
1529
|
-
async function
|
|
1522
|
+
async function visitPersistedLogFile(filePath, visitor) {
|
|
1530
1523
|
if (!existsSync(filePath)) return;
|
|
1531
1524
|
try {
|
|
1532
1525
|
const fileStream = createInterface({
|
|
@@ -1540,8 +1533,7 @@ async function readPersistedLogFile(filePath, byId) {
|
|
|
1540
1533
|
const result = CapturedLogSchema.safeParse(parsed);
|
|
1541
1534
|
if (result.success) {
|
|
1542
1535
|
const log = normalizeLogSession(result.data);
|
|
1543
|
-
|
|
1544
|
-
observeSessionLog(log);
|
|
1536
|
+
visitor(log);
|
|
1545
1537
|
}
|
|
1546
1538
|
} catch {
|
|
1547
1539
|
}
|
|
@@ -1551,20 +1543,37 @@ async function readPersistedLogFile(filePath, byId) {
|
|
|
1551
1543
|
}
|
|
1552
1544
|
}
|
|
1553
1545
|
async function listLogsPage(options) {
|
|
1554
|
-
const
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1546
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1547
|
+
const pageById = /* @__PURE__ */ new Map();
|
|
1548
|
+
const pageStart = options.offset;
|
|
1549
|
+
const pageEnd = options.offset + options.limit;
|
|
1550
|
+
let total = 0;
|
|
1551
|
+
const visitLog = (log) => {
|
|
1552
|
+
if (!matchesLogFilters(log, options.sessionId, options.model)) return;
|
|
1553
|
+
if (!seenIds.has(log.id)) {
|
|
1554
|
+
seenIds.add(log.id);
|
|
1555
|
+
const position = total;
|
|
1556
|
+
total += 1;
|
|
1557
|
+
if (position >= pageStart && position < pageEnd) {
|
|
1558
|
+
pageById.set(log.id, log);
|
|
1559
|
+
}
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
if (pageById.has(log.id)) {
|
|
1563
|
+
pageById.set(log.id, log);
|
|
1564
|
+
}
|
|
1565
|
+
};
|
|
1566
|
+
await visitPersistedLogs((log) => {
|
|
1567
|
+
observeSessionLog(log);
|
|
1568
|
+
visitLog(log);
|
|
1569
|
+
});
|
|
1570
|
+
for (const log of memoryCache.values()) {
|
|
1571
|
+
visitLog(log);
|
|
1562
1572
|
}
|
|
1563
|
-
const
|
|
1564
|
-
const persistedLogs = [...persistedById.values()].filter((log) => matchesLogFilters(log, options.sessionId, options.model)).sort((left, right) => left.id - right.id);
|
|
1573
|
+
const logs = [...pageById.values()].sort((left, right) => left.id - right.id);
|
|
1565
1574
|
return {
|
|
1566
|
-
logs
|
|
1567
|
-
total
|
|
1575
|
+
logs,
|
|
1576
|
+
total,
|
|
1568
1577
|
offset: options.offset,
|
|
1569
1578
|
limit: options.limit
|
|
1570
1579
|
};
|
|
@@ -1687,35 +1696,100 @@ function readLogIdFromLine(line) {
|
|
|
1687
1696
|
return null;
|
|
1688
1697
|
}
|
|
1689
1698
|
}
|
|
1699
|
+
function tempRewritePath(filePath) {
|
|
1700
|
+
return `${filePath}.rewrite-${String(process.pid)}-${String(Date.now())}.tmp`;
|
|
1701
|
+
}
|
|
1702
|
+
async function removeTempFile(filePath) {
|
|
1703
|
+
try {
|
|
1704
|
+
await unlink(filePath);
|
|
1705
|
+
} catch {
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
function waitForWriterDrain(writer) {
|
|
1709
|
+
return new Promise((resolve) => {
|
|
1710
|
+
const cleanup = () => {
|
|
1711
|
+
writer.off("drain", onDrain);
|
|
1712
|
+
writer.off("error", onError);
|
|
1713
|
+
};
|
|
1714
|
+
const onDrain = () => {
|
|
1715
|
+
cleanup();
|
|
1716
|
+
resolve(true);
|
|
1717
|
+
};
|
|
1718
|
+
const onError = () => {
|
|
1719
|
+
cleanup();
|
|
1720
|
+
resolve(false);
|
|
1721
|
+
};
|
|
1722
|
+
writer.once("drain", onDrain);
|
|
1723
|
+
writer.once("error", onError);
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
async function writeKeptLogLine(writer, line) {
|
|
1727
|
+
if (writer.write(`${line}
|
|
1728
|
+
`, "utf-8")) return true;
|
|
1729
|
+
return await waitForWriterDrain(writer);
|
|
1730
|
+
}
|
|
1731
|
+
function finishWriter(writer) {
|
|
1732
|
+
return new Promise((resolve) => {
|
|
1733
|
+
const cleanup = () => {
|
|
1734
|
+
writer.off("finish", onFinish);
|
|
1735
|
+
writer.off("error", onError);
|
|
1736
|
+
};
|
|
1737
|
+
const onFinish = () => {
|
|
1738
|
+
cleanup();
|
|
1739
|
+
resolve(true);
|
|
1740
|
+
};
|
|
1741
|
+
const onError = () => {
|
|
1742
|
+
cleanup();
|
|
1743
|
+
resolve(false);
|
|
1744
|
+
};
|
|
1745
|
+
writer.once("finish", onFinish);
|
|
1746
|
+
writer.once("error", onError);
|
|
1747
|
+
writer.end();
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1690
1750
|
async function rewriteLogFileWithoutIds(filePath, ids) {
|
|
1691
|
-
|
|
1751
|
+
const tempPath = tempRewritePath(filePath);
|
|
1752
|
+
const writer = createWriteStream(tempPath, { encoding: "utf-8" });
|
|
1753
|
+
const removedIds = /* @__PURE__ */ new Set();
|
|
1754
|
+
let keptLineCount = 0;
|
|
1755
|
+
let writeOk = true;
|
|
1692
1756
|
try {
|
|
1693
|
-
|
|
1757
|
+
const fileStream = createInterface({
|
|
1758
|
+
input: createReadStream(filePath),
|
|
1759
|
+
crlfDelay: Infinity
|
|
1760
|
+
});
|
|
1761
|
+
for await (const line of fileStream) {
|
|
1762
|
+
if (line === "") continue;
|
|
1763
|
+
const id = readLogIdFromLine(line);
|
|
1764
|
+
if (id !== null && ids.has(id)) {
|
|
1765
|
+
removedIds.add(id);
|
|
1766
|
+
} else {
|
|
1767
|
+
keptLineCount += 1;
|
|
1768
|
+
writeOk = await writeKeptLogLine(writer, line);
|
|
1769
|
+
if (!writeOk) break;
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1694
1772
|
} catch (err) {
|
|
1695
|
-
logger.warn("[store] Failed to
|
|
1773
|
+
logger.warn("[store] Failed to stream log file for deletion:", filePath, String(err));
|
|
1774
|
+
writeOk = false;
|
|
1775
|
+
}
|
|
1776
|
+
if (!await finishWriter(writer) || !writeOk) {
|
|
1777
|
+
await removeTempFile(tempPath);
|
|
1696
1778
|
return { rewritten: false, removedIds: /* @__PURE__ */ new Set() };
|
|
1697
1779
|
}
|
|
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
|
-
}
|
|
1780
|
+
if (removedIds.size === 0) {
|
|
1781
|
+
await removeTempFile(tempPath);
|
|
1782
|
+
return { rewritten: false, removedIds };
|
|
1709
1783
|
}
|
|
1710
|
-
if (removedIds.size === 0) return { rewritten: false, removedIds };
|
|
1711
1784
|
try {
|
|
1712
|
-
if (
|
|
1785
|
+
if (keptLineCount === 0) {
|
|
1786
|
+
await removeTempFile(tempPath);
|
|
1713
1787
|
await unlink(filePath);
|
|
1714
1788
|
} else {
|
|
1715
|
-
await
|
|
1716
|
-
`, "utf-8");
|
|
1789
|
+
await rename(tempPath, filePath);
|
|
1717
1790
|
}
|
|
1718
1791
|
} catch (err) {
|
|
1792
|
+
await removeTempFile(tempPath);
|
|
1719
1793
|
logger.warn("[store] Failed to rewrite log file after deletion:", filePath, String(err));
|
|
1720
1794
|
return { rewritten: false, removedIds: /* @__PURE__ */ new Set() };
|
|
1721
1795
|
}
|
|
@@ -3527,6 +3601,8 @@ async function getClientInfo(request) {
|
|
|
3527
3601
|
}
|
|
3528
3602
|
const DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS = 10;
|
|
3529
3603
|
const MAX_SLOW_RESPONSE_THRESHOLD_SECONDS = 600;
|
|
3604
|
+
const DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS = 60;
|
|
3605
|
+
const MAX_PROVIDER_TEST_TIMEOUT_SECONDS = 600;
|
|
3530
3606
|
const DEFAULT_TIME_DISPLAY_FORMAT = "time";
|
|
3531
3607
|
const DEFAULT_CAPTURE_MODE = "simple";
|
|
3532
3608
|
const TimeDisplayFormatSchema = _enum(["time", "full"]);
|
|
@@ -3535,6 +3611,7 @@ const RuntimeConfigSchema = object({
|
|
|
3535
3611
|
stripClaudeCodeBillingHeader: boolean(),
|
|
3536
3612
|
hasSeenOnboarding: boolean().default(false),
|
|
3537
3613
|
slowResponseThresholdSeconds: number().int().min(0).max(MAX_SLOW_RESPONSE_THRESHOLD_SECONDS).default(DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS),
|
|
3614
|
+
providerTestTimeoutSeconds: number().int().min(1).max(MAX_PROVIDER_TEST_TIMEOUT_SECONDS).default(DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS),
|
|
3538
3615
|
timeDisplayFormat: TimeDisplayFormatSchema.default(DEFAULT_TIME_DISPLAY_FORMAT),
|
|
3539
3616
|
captureMode: CaptureModeSchema.default(DEFAULT_CAPTURE_MODE)
|
|
3540
3617
|
});
|
|
@@ -3579,6 +3656,7 @@ function resolveInitialConfig() {
|
|
|
3579
3656
|
stripClaudeCodeBillingHeader: true,
|
|
3580
3657
|
hasSeenOnboarding: false,
|
|
3581
3658
|
slowResponseThresholdSeconds: DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS,
|
|
3659
|
+
providerTestTimeoutSeconds: DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS,
|
|
3582
3660
|
timeDisplayFormat: DEFAULT_TIME_DISPLAY_FORMAT,
|
|
3583
3661
|
captureMode
|
|
3584
3662
|
};
|
|
@@ -3587,6 +3665,7 @@ function resolveInitialConfig() {
|
|
|
3587
3665
|
stripClaudeCodeBillingHeader: false,
|
|
3588
3666
|
hasSeenOnboarding: false,
|
|
3589
3667
|
slowResponseThresholdSeconds: DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS,
|
|
3668
|
+
providerTestTimeoutSeconds: DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS,
|
|
3590
3669
|
timeDisplayFormat: DEFAULT_TIME_DISPLAY_FORMAT,
|
|
3591
3670
|
captureMode
|
|
3592
3671
|
};
|
|
@@ -3640,6 +3719,7 @@ function toPersistedConfig(value) {
|
|
|
3640
3719
|
stripClaudeCodeBillingHeader: value.stripClaudeCodeBillingHeader,
|
|
3641
3720
|
hasSeenOnboarding: value.hasSeenOnboarding,
|
|
3642
3721
|
slowResponseThresholdSeconds: value.slowResponseThresholdSeconds,
|
|
3722
|
+
providerTestTimeoutSeconds: value.providerTestTimeoutSeconds,
|
|
3643
3723
|
timeDisplayFormat: value.timeDisplayFormat
|
|
3644
3724
|
};
|
|
3645
3725
|
}
|
|
@@ -5233,6 +5313,7 @@ const RuntimeConfigPatchSchema = object({
|
|
|
5233
5313
|
stripClaudeCodeBillingHeader: boolean().optional(),
|
|
5234
5314
|
hasSeenOnboarding: boolean().optional(),
|
|
5235
5315
|
slowResponseThresholdSeconds: number().int().min(0).max(MAX_SLOW_RESPONSE_THRESHOLD_SECONDS).optional(),
|
|
5316
|
+
providerTestTimeoutSeconds: number().int().min(1).max(MAX_PROVIDER_TEST_TIMEOUT_SECONDS).optional(),
|
|
5236
5317
|
timeDisplayFormat: TimeDisplayFormatSchema.optional()
|
|
5237
5318
|
}).strict().refine((v) => Object.keys(v).length > 0, {
|
|
5238
5319
|
message: "At least one field must be provided"
|
|
@@ -5813,7 +5894,7 @@ const Route$e = createFileRoute("/api/providers/$providerId")({
|
|
|
5813
5894
|
}
|
|
5814
5895
|
}
|
|
5815
5896
|
});
|
|
5816
|
-
const INITIAL_STREAM_LOG_LIMIT =
|
|
5897
|
+
const INITIAL_STREAM_LOG_LIMIT = 100;
|
|
5817
5898
|
const Route$d = createFileRoute("/api/logs/stream")({
|
|
5818
5899
|
server: {
|
|
5819
5900
|
handlers: {
|
|
@@ -6599,10 +6680,11 @@ function buildProviderTestRequestBody(model, mode) {
|
|
|
6599
6680
|
return { ...base, stream: true };
|
|
6600
6681
|
}
|
|
6601
6682
|
}
|
|
6683
|
+
const CONTAINER_NETWORK_HINT = "If the tool, Agent Inspector, or provider runs in another container or host, replace localhost with an address reachable from the caller and verify the network/firewall path.";
|
|
6602
6684
|
const ERROR_HINTS = {
|
|
6603
|
-
timeout:
|
|
6604
|
-
network_unreachable:
|
|
6605
|
-
connection_refused:
|
|
6685
|
+
timeout: `The request took too long. Check your network connection or try again. ${CONTAINER_NETWORK_HINT}`,
|
|
6686
|
+
network_unreachable: `Cannot reach the server. Verify the base URL and check your firewall settings. ${CONTAINER_NETWORK_HINT}`,
|
|
6687
|
+
connection_refused: `Connection was refused. Make sure the provider server is running and the URL is correct. ${CONTAINER_NETWORK_HINT}`,
|
|
6606
6688
|
auth_failed: "Authentication failed. Check your API key is correct and has not expired.",
|
|
6607
6689
|
rate_limited: "Too many requests. Wait a moment and try again, or check your API quota.",
|
|
6608
6690
|
server_error: "The provider server encountered an error. Check their status page and try again later.",
|
|
@@ -6610,6 +6692,17 @@ const ERROR_HINTS = {
|
|
|
6610
6692
|
unknown: "An unexpected error occurred. Check the details and try again."
|
|
6611
6693
|
};
|
|
6612
6694
|
const MAX_ERROR_DETAILS_LENGTH = 200;
|
|
6695
|
+
const MAX_DEBUG_TEXT_LENGTH = 2e4;
|
|
6696
|
+
const REDACTED_HEADER_VALUE = "[redacted]";
|
|
6697
|
+
const SENSITIVE_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
6698
|
+
"authorization",
|
|
6699
|
+
"x-api-key",
|
|
6700
|
+
"api-key",
|
|
6701
|
+
"x-goog-api-key",
|
|
6702
|
+
"anthropic-api-key",
|
|
6703
|
+
"openai-api-key",
|
|
6704
|
+
"proxy-authorization"
|
|
6705
|
+
]);
|
|
6613
6706
|
function classifyError(error, responseStatus) {
|
|
6614
6707
|
const errorStr = String(error);
|
|
6615
6708
|
const errorLower = errorStr.toLowerCase();
|
|
@@ -6649,6 +6742,9 @@ function classifyError(error, responseStatus) {
|
|
|
6649
6742
|
if (errorLower.includes("bad gateway") || errorLower.includes("gateway timeout")) {
|
|
6650
6743
|
return { type: "server_error", details: extractErrorDetails(errorStr) };
|
|
6651
6744
|
}
|
|
6745
|
+
if (errorLower.includes("invalid response") || errorLower.includes("unexpected token") || errorLower.includes("failed to parse") || errorLower.includes("schema") || errorLower.includes("zod")) {
|
|
6746
|
+
return { type: "invalid_response", details: extractErrorDetails(errorStr) };
|
|
6747
|
+
}
|
|
6652
6748
|
if (responseStatus !== void 0) {
|
|
6653
6749
|
if (responseStatus === 401 || responseStatus === 403) {
|
|
6654
6750
|
return { type: "auth_failed", details: `Authentication failed (HTTP ${responseStatus})` };
|
|
@@ -6689,9 +6785,64 @@ function truncateErrorDetails(details) {
|
|
|
6689
6785
|
}
|
|
6690
6786
|
return details.slice(0, MAX_ERROR_DETAILS_LENGTH) + "...";
|
|
6691
6787
|
}
|
|
6692
|
-
function
|
|
6788
|
+
function truncateDebugText(text) {
|
|
6789
|
+
if (text.length <= MAX_DEBUG_TEXT_LENGTH) {
|
|
6790
|
+
return text;
|
|
6791
|
+
}
|
|
6792
|
+
return `${text.slice(0, MAX_DEBUG_TEXT_LENGTH)}
|
|
6793
|
+
... truncated`;
|
|
6794
|
+
}
|
|
6795
|
+
function headersToRecord(headers) {
|
|
6796
|
+
const result = {};
|
|
6797
|
+
headers.forEach((value, key) => {
|
|
6798
|
+
result[key] = value;
|
|
6799
|
+
});
|
|
6800
|
+
return result;
|
|
6801
|
+
}
|
|
6802
|
+
function redactHeaderValue(name, value) {
|
|
6803
|
+
const lowerName = name.toLowerCase();
|
|
6804
|
+
if (!SENSITIVE_HEADER_NAMES.has(lowerName)) {
|
|
6805
|
+
return value;
|
|
6806
|
+
}
|
|
6807
|
+
if (lowerName === "authorization" && value.startsWith("Bearer ")) {
|
|
6808
|
+
return `Bearer ${REDACTED_HEADER_VALUE}`;
|
|
6809
|
+
}
|
|
6810
|
+
return REDACTED_HEADER_VALUE;
|
|
6811
|
+
}
|
|
6812
|
+
function redactHeaders(headers) {
|
|
6813
|
+
const result = {};
|
|
6814
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
6815
|
+
result[name] = redactHeaderValue(name, value);
|
|
6816
|
+
}
|
|
6817
|
+
return result;
|
|
6818
|
+
}
|
|
6819
|
+
function createTestDebug(input) {
|
|
6820
|
+
const debug = {
|
|
6821
|
+
requestUrl: input.requestUrl,
|
|
6822
|
+
requestMethod: "POST",
|
|
6823
|
+
requestHeaders: redactHeaders(input.requestHeaders),
|
|
6824
|
+
requestBody: truncateDebugText(input.requestBody)
|
|
6825
|
+
};
|
|
6826
|
+
if (input.response !== void 0) {
|
|
6827
|
+
debug.responseStatus = input.response.status;
|
|
6828
|
+
debug.responseStatusText = input.response.statusText;
|
|
6829
|
+
debug.responseHeaders = headersToRecord(input.response.headers);
|
|
6830
|
+
}
|
|
6831
|
+
if (input.responseBody !== void 0) {
|
|
6832
|
+
debug.responseBody = truncateDebugText(input.responseBody);
|
|
6833
|
+
}
|
|
6834
|
+
return debug;
|
|
6835
|
+
}
|
|
6836
|
+
async function readResponseText(response) {
|
|
6837
|
+
try {
|
|
6838
|
+
return await response.text();
|
|
6839
|
+
} catch (err) {
|
|
6840
|
+
return `Failed to read response body: ${String(err)}`;
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6843
|
+
function createErrorResult(error, latencyMs, streaming, responseStatus, debug) {
|
|
6693
6844
|
const { type, details } = classifyError(error, responseStatus);
|
|
6694
|
-
|
|
6845
|
+
const result = {
|
|
6695
6846
|
success: false,
|
|
6696
6847
|
error: {
|
|
6697
6848
|
message: getErrorMessage(type),
|
|
@@ -6702,6 +6853,13 @@ function createErrorResult(error, latencyMs, streaming, responseStatus) {
|
|
|
6702
6853
|
latencyMs,
|
|
6703
6854
|
streaming
|
|
6704
6855
|
};
|
|
6856
|
+
if (debug !== void 0) {
|
|
6857
|
+
result.debug = debug;
|
|
6858
|
+
if (debug.requestHeaders !== void 0) {
|
|
6859
|
+
result.requestHeaders = debug.requestHeaders;
|
|
6860
|
+
}
|
|
6861
|
+
}
|
|
6862
|
+
return result;
|
|
6705
6863
|
}
|
|
6706
6864
|
function getErrorMessage(type) {
|
|
6707
6865
|
const messages = {
|
|
@@ -6751,7 +6909,9 @@ const OpenAIResponseSchema = object({
|
|
|
6751
6909
|
})
|
|
6752
6910
|
)
|
|
6753
6911
|
});
|
|
6754
|
-
|
|
6912
|
+
function getProviderTestTimeoutMs() {
|
|
6913
|
+
return getConfig().providerTestTimeoutSeconds * 1e3;
|
|
6914
|
+
}
|
|
6755
6915
|
function buildTestRequestHeaders(provider) {
|
|
6756
6916
|
const headers = new Headers();
|
|
6757
6917
|
headers.set("Content-Type", "application/json");
|
|
@@ -6766,27 +6926,36 @@ async function testEndpoint(baseUrl, provider, path2, model, isOpenAI) {
|
|
|
6766
6926
|
const startTime = Date.now();
|
|
6767
6927
|
const body = JSON.stringify(buildProviderTestRequestBody(model, "non-streaming"));
|
|
6768
6928
|
const requestHeaders = buildTestRequestHeaders(provider);
|
|
6929
|
+
let requestUrl = baseUrl;
|
|
6769
6930
|
const controller = new AbortController();
|
|
6770
|
-
const timeoutId = setTimeout(() => controller.abort(),
|
|
6931
|
+
const timeoutId = setTimeout(() => controller.abort(), getProviderTestTimeoutMs());
|
|
6771
6932
|
try {
|
|
6772
|
-
|
|
6773
|
-
const response = await fetch(
|
|
6933
|
+
requestUrl = buildUpstreamUrl(baseUrl, path2);
|
|
6934
|
+
const response = await fetch(requestUrl, {
|
|
6774
6935
|
method: "POST",
|
|
6775
6936
|
headers: requestHeaders,
|
|
6776
6937
|
body,
|
|
6777
6938
|
signal: controller.signal
|
|
6778
6939
|
});
|
|
6779
|
-
clearTimeout(timeoutId);
|
|
6780
6940
|
const latencyMs = Date.now() - startTime;
|
|
6781
6941
|
if (!response.ok) {
|
|
6942
|
+
const responseText2 = await readResponseText(response);
|
|
6782
6943
|
return createErrorResult(
|
|
6783
6944
|
`HTTP ${response.status}: ${response.statusText}`,
|
|
6784
6945
|
latencyMs,
|
|
6785
6946
|
false,
|
|
6786
|
-
response.status
|
|
6947
|
+
response.status,
|
|
6948
|
+
createTestDebug({
|
|
6949
|
+
requestUrl,
|
|
6950
|
+
requestHeaders,
|
|
6951
|
+
requestBody: body,
|
|
6952
|
+
response,
|
|
6953
|
+
responseBody: responseText2
|
|
6954
|
+
})
|
|
6787
6955
|
);
|
|
6788
6956
|
}
|
|
6789
6957
|
const responseText = await response.text();
|
|
6958
|
+
const safeRequestHeaders = redactHeaders(requestHeaders);
|
|
6790
6959
|
try {
|
|
6791
6960
|
if (isOpenAI) {
|
|
6792
6961
|
const json = OpenAIResponseSchema.parse(JSON.parse(responseText));
|
|
@@ -6802,7 +6971,7 @@ async function testEndpoint(baseUrl, provider, path2, model, isOpenAI) {
|
|
|
6802
6971
|
latencyMs,
|
|
6803
6972
|
content: content !== null && content !== "" ? [{ type: "text", text: content }] : void 0,
|
|
6804
6973
|
rawResponse: responseText,
|
|
6805
|
-
requestHeaders
|
|
6974
|
+
requestHeaders: safeRequestHeaders
|
|
6806
6975
|
};
|
|
6807
6976
|
} else {
|
|
6808
6977
|
const json = AnthropicResponseSchema.parse(JSON.parse(responseText));
|
|
@@ -6829,61 +6998,78 @@ async function testEndpoint(baseUrl, provider, path2, model, isOpenAI) {
|
|
|
6829
6998
|
latencyMs,
|
|
6830
6999
|
content: content.length > 0 ? content : void 0,
|
|
6831
7000
|
rawResponse: responseText,
|
|
6832
|
-
requestHeaders
|
|
7001
|
+
requestHeaders: safeRequestHeaders
|
|
6833
7002
|
};
|
|
6834
7003
|
}
|
|
6835
7004
|
} catch (parseErr) {
|
|
6836
|
-
return
|
|
6837
|
-
|
|
6838
|
-
model,
|
|
7005
|
+
return createErrorResult(
|
|
7006
|
+
`Invalid response: ${String(parseErr)}`,
|
|
6839
7007
|
latencyMs,
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
7008
|
+
false,
|
|
7009
|
+
response.status,
|
|
7010
|
+
createTestDebug({
|
|
7011
|
+
requestUrl,
|
|
7012
|
+
requestHeaders,
|
|
7013
|
+
requestBody: body,
|
|
7014
|
+
response,
|
|
7015
|
+
responseBody: responseText
|
|
7016
|
+
})
|
|
7017
|
+
);
|
|
6844
7018
|
}
|
|
6845
7019
|
} catch (err) {
|
|
7020
|
+
return createErrorResult(
|
|
7021
|
+
err,
|
|
7022
|
+
Date.now() - startTime,
|
|
7023
|
+
false,
|
|
7024
|
+
void 0,
|
|
7025
|
+
createTestDebug({ requestUrl, requestHeaders, requestBody: body })
|
|
7026
|
+
);
|
|
7027
|
+
} finally {
|
|
6846
7028
|
clearTimeout(timeoutId);
|
|
6847
|
-
return createErrorResult(err, Date.now() - startTime, false);
|
|
6848
7029
|
}
|
|
6849
7030
|
}
|
|
6850
7031
|
async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI) {
|
|
6851
7032
|
const startTime = Date.now();
|
|
6852
7033
|
const body = JSON.stringify(buildProviderTestRequestBody(model, "streaming"));
|
|
6853
7034
|
const requestHeaders = buildTestRequestHeaders(provider);
|
|
7035
|
+
let requestUrl = baseUrl;
|
|
6854
7036
|
const controller = new AbortController();
|
|
6855
|
-
const timeoutId = setTimeout(() => controller.abort(),
|
|
7037
|
+
const timeoutId = setTimeout(() => controller.abort(), getProviderTestTimeoutMs());
|
|
6856
7038
|
try {
|
|
6857
|
-
|
|
6858
|
-
const response = await fetch(
|
|
7039
|
+
requestUrl = buildUpstreamUrl(baseUrl, path2);
|
|
7040
|
+
const response = await fetch(requestUrl, {
|
|
6859
7041
|
method: "POST",
|
|
6860
7042
|
headers: requestHeaders,
|
|
6861
7043
|
body,
|
|
6862
7044
|
signal: controller.signal
|
|
6863
7045
|
});
|
|
6864
|
-
clearTimeout(timeoutId);
|
|
6865
7046
|
const latencyMs = Date.now() - startTime;
|
|
6866
7047
|
if (!response.ok) {
|
|
7048
|
+
const responseText = await readResponseText(response);
|
|
6867
7049
|
return createErrorResult(
|
|
6868
7050
|
`HTTP ${response.status}: ${response.statusText}`,
|
|
6869
7051
|
latencyMs,
|
|
6870
7052
|
true,
|
|
6871
|
-
response.status
|
|
7053
|
+
response.status,
|
|
7054
|
+
createTestDebug({
|
|
7055
|
+
requestUrl,
|
|
7056
|
+
requestHeaders,
|
|
7057
|
+
requestBody: body,
|
|
7058
|
+
response,
|
|
7059
|
+
responseBody: responseText
|
|
7060
|
+
})
|
|
6872
7061
|
);
|
|
6873
7062
|
}
|
|
6874
7063
|
const chunks = [];
|
|
6875
7064
|
const reader = response.body?.getReader();
|
|
6876
7065
|
if (!reader) {
|
|
6877
|
-
return
|
|
6878
|
-
|
|
6879
|
-
error: {
|
|
6880
|
-
message: "No response body",
|
|
6881
|
-
type: "invalid_response",
|
|
6882
|
-
hint: ERROR_HINTS.invalid_response
|
|
6883
|
-
},
|
|
7066
|
+
return createErrorResult(
|
|
7067
|
+
"Invalid response: no response body",
|
|
6884
7068
|
latencyMs,
|
|
6885
|
-
|
|
6886
|
-
|
|
7069
|
+
true,
|
|
7070
|
+
response.status,
|
|
7071
|
+
createTestDebug({ requestUrl, requestHeaders, requestBody: body, response })
|
|
7072
|
+
);
|
|
6887
7073
|
}
|
|
6888
7074
|
const decoder = new TextDecoder();
|
|
6889
7075
|
const MAX_CHUNKS_SIZE = 10 * 1024 * 1024;
|
|
@@ -6896,7 +7082,15 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
6896
7082
|
return createErrorResult(
|
|
6897
7083
|
"Response too large (exceeded 10MB limit)",
|
|
6898
7084
|
Date.now() - startTime,
|
|
6899
|
-
true
|
|
7085
|
+
true,
|
|
7086
|
+
response.status,
|
|
7087
|
+
createTestDebug({
|
|
7088
|
+
requestUrl,
|
|
7089
|
+
requestHeaders,
|
|
7090
|
+
requestBody: body,
|
|
7091
|
+
response,
|
|
7092
|
+
responseBody: chunks.join("")
|
|
7093
|
+
})
|
|
6900
7094
|
);
|
|
6901
7095
|
}
|
|
6902
7096
|
const decoded = decoder.decode(value, { stream: true });
|
|
@@ -6908,9 +7102,23 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
6908
7102
|
chunks.push(finalChunk);
|
|
6909
7103
|
}
|
|
6910
7104
|
} catch (readErr) {
|
|
6911
|
-
|
|
7105
|
+
const error = readErr instanceof Error && readErr.name === "AbortError" ? readErr : `Stream read error: ${String(readErr)}`;
|
|
7106
|
+
return createErrorResult(
|
|
7107
|
+
error,
|
|
7108
|
+
latencyMs,
|
|
7109
|
+
true,
|
|
7110
|
+
response.status,
|
|
7111
|
+
createTestDebug({
|
|
7112
|
+
requestUrl,
|
|
7113
|
+
requestHeaders,
|
|
7114
|
+
requestBody: body,
|
|
7115
|
+
response,
|
|
7116
|
+
responseBody: chunks.join("")
|
|
7117
|
+
})
|
|
7118
|
+
);
|
|
6912
7119
|
}
|
|
6913
7120
|
const fullResponse = chunks.join("");
|
|
7121
|
+
const safeRequestHeaders = redactHeaders(requestHeaders);
|
|
6914
7122
|
const mockLog = {
|
|
6915
7123
|
id: 0,
|
|
6916
7124
|
timestamp: "",
|
|
@@ -6982,23 +7190,33 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
6982
7190
|
rawResponse: reconstructedJson,
|
|
6983
7191
|
streaming: true,
|
|
6984
7192
|
streamingChunks,
|
|
6985
|
-
requestHeaders
|
|
7193
|
+
requestHeaders: safeRequestHeaders
|
|
6986
7194
|
};
|
|
6987
7195
|
} catch {
|
|
6988
|
-
return
|
|
6989
|
-
|
|
6990
|
-
model,
|
|
7196
|
+
return createErrorResult(
|
|
7197
|
+
"Invalid response: could not parse reconstructed stream response",
|
|
6991
7198
|
latencyMs,
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
7199
|
+
true,
|
|
7200
|
+
response.status,
|
|
7201
|
+
createTestDebug({
|
|
7202
|
+
requestUrl,
|
|
7203
|
+
requestHeaders,
|
|
7204
|
+
requestBody: body,
|
|
7205
|
+
response,
|
|
7206
|
+
responseBody: fullResponse
|
|
7207
|
+
})
|
|
7208
|
+
);
|
|
6998
7209
|
}
|
|
6999
7210
|
} catch (err) {
|
|
7211
|
+
return createErrorResult(
|
|
7212
|
+
err,
|
|
7213
|
+
Date.now() - startTime,
|
|
7214
|
+
true,
|
|
7215
|
+
void 0,
|
|
7216
|
+
createTestDebug({ requestUrl, requestHeaders, requestBody: body })
|
|
7217
|
+
);
|
|
7218
|
+
} finally {
|
|
7000
7219
|
clearTimeout(timeoutId);
|
|
7001
|
-
return createErrorResult(err, Date.now() - startTime, true);
|
|
7002
7220
|
}
|
|
7003
7221
|
}
|
|
7004
7222
|
const Route$7 = createFileRoute("/api/providers/$providerId/test")({
|
|
@@ -7451,6 +7669,16 @@ const ProviderTestContentSchema = object({
|
|
|
7451
7669
|
text: string().optional(),
|
|
7452
7670
|
thinking: string().optional()
|
|
7453
7671
|
});
|
|
7672
|
+
const ProviderTestDebugSchema = object({
|
|
7673
|
+
requestUrl: string().optional(),
|
|
7674
|
+
requestMethod: string().optional(),
|
|
7675
|
+
requestHeaders: record(string(), string()).optional(),
|
|
7676
|
+
requestBody: string().optional(),
|
|
7677
|
+
responseStatus: number().optional(),
|
|
7678
|
+
responseStatusText: string().optional(),
|
|
7679
|
+
responseHeaders: record(string(), string()).optional(),
|
|
7680
|
+
responseBody: string().optional()
|
|
7681
|
+
});
|
|
7454
7682
|
const ProviderTestResultSchema = object({
|
|
7455
7683
|
success: boolean(),
|
|
7456
7684
|
error: ProviderTestErrorSchema.optional(),
|
|
@@ -7467,7 +7695,8 @@ const ProviderTestResultSchema = object({
|
|
|
7467
7695
|
chunks: array(StreamingChunkSchema$1),
|
|
7468
7696
|
truncated: boolean().default(false)
|
|
7469
7697
|
}).optional(),
|
|
7470
|
-
requestHeaders: record(string(), string()).optional()
|
|
7698
|
+
requestHeaders: record(string(), string()).optional(),
|
|
7699
|
+
debug: ProviderTestDebugSchema.optional()
|
|
7471
7700
|
});
|
|
7472
7701
|
const ProviderTestStateSchema = union([
|
|
7473
7702
|
ProviderTestResultSchema,
|
|
@@ -7516,6 +7745,18 @@ function createFailedProviderTestResults(message, type) {
|
|
|
7516
7745
|
function hasSuccessField(result) {
|
|
7517
7746
|
return Object.prototype.hasOwnProperty.call(result, "success");
|
|
7518
7747
|
}
|
|
7748
|
+
function getResultResponseStatus(result) {
|
|
7749
|
+
if (result.debug?.responseStatus !== void 0) {
|
|
7750
|
+
return result.debug.responseStatus;
|
|
7751
|
+
}
|
|
7752
|
+
return result.success ? 200 : 500;
|
|
7753
|
+
}
|
|
7754
|
+
function getResultResponseText(result) {
|
|
7755
|
+
return result.rawResponse ?? result.debug?.responseBody ?? JSON.stringify(result);
|
|
7756
|
+
}
|
|
7757
|
+
function getResultHeaders(result) {
|
|
7758
|
+
return result.requestHeaders ?? result.debug?.requestHeaders ?? {};
|
|
7759
|
+
}
|
|
7519
7760
|
async function logModelResults(displayName, providerName, anthropicUrl, openaiUrl, modelResults, captureFullDetails) {
|
|
7520
7761
|
const usageModel = getModelUsageName(displayName, providerName);
|
|
7521
7762
|
if (anthropicUrl !== void 0) {
|
|
@@ -7532,8 +7773,8 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
7532
7773
|
model: nonStreamingResult.model ?? displayName,
|
|
7533
7774
|
sessionId: null,
|
|
7534
7775
|
rawRequestBody: requestBody,
|
|
7535
|
-
responseStatus: nonStreamingResult
|
|
7536
|
-
responseText:
|
|
7776
|
+
responseStatus: getResultResponseStatus(nonStreamingResult),
|
|
7777
|
+
responseText: getResultResponseText(nonStreamingResult),
|
|
7537
7778
|
inputTokens: nonStreamingResult.inputTokens ?? null,
|
|
7538
7779
|
outputTokens: nonStreamingResult.outputTokens ?? null,
|
|
7539
7780
|
cacheCreationInputTokens: nonStreamingResult.cacheCreationInputTokens ?? null,
|
|
@@ -7545,7 +7786,7 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
7545
7786
|
apiFormat: "anthropic",
|
|
7546
7787
|
isTest: true,
|
|
7547
7788
|
providerName,
|
|
7548
|
-
headers: captureFullDetails ? nonStreamingResult
|
|
7789
|
+
headers: captureFullDetails ? getResultHeaders(nonStreamingResult) : void 0
|
|
7549
7790
|
});
|
|
7550
7791
|
const streamingRequestBody = JSON.stringify(
|
|
7551
7792
|
buildProviderTestRequestBody(usageModel, "streaming")
|
|
@@ -7557,8 +7798,8 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
7557
7798
|
model: streamingResult.model ?? displayName,
|
|
7558
7799
|
sessionId: null,
|
|
7559
7800
|
rawRequestBody: streamingRequestBody,
|
|
7560
|
-
responseStatus: streamingResult
|
|
7561
|
-
responseText:
|
|
7801
|
+
responseStatus: getResultResponseStatus(streamingResult),
|
|
7802
|
+
responseText: getResultResponseText(streamingResult),
|
|
7562
7803
|
inputTokens: streamingResult.inputTokens ?? null,
|
|
7563
7804
|
outputTokens: streamingResult.outputTokens ?? null,
|
|
7564
7805
|
cacheCreationInputTokens: streamingResult.cacheCreationInputTokens ?? null,
|
|
@@ -7571,7 +7812,7 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
7571
7812
|
apiFormat: "anthropic",
|
|
7572
7813
|
isTest: true,
|
|
7573
7814
|
providerName,
|
|
7574
|
-
headers: captureFullDetails ? streamingResult
|
|
7815
|
+
headers: captureFullDetails ? getResultHeaders(streamingResult) : void 0
|
|
7575
7816
|
});
|
|
7576
7817
|
}
|
|
7577
7818
|
}
|
|
@@ -7589,8 +7830,8 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
7589
7830
|
model: nonStreamingResult.model ?? displayName,
|
|
7590
7831
|
sessionId: null,
|
|
7591
7832
|
rawRequestBody: requestBody,
|
|
7592
|
-
responseStatus: nonStreamingResult
|
|
7593
|
-
responseText:
|
|
7833
|
+
responseStatus: getResultResponseStatus(nonStreamingResult),
|
|
7834
|
+
responseText: getResultResponseText(nonStreamingResult),
|
|
7594
7835
|
inputTokens: nonStreamingResult.inputTokens ?? null,
|
|
7595
7836
|
outputTokens: nonStreamingResult.outputTokens ?? null,
|
|
7596
7837
|
cacheCreationInputTokens: null,
|
|
@@ -7602,7 +7843,7 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
7602
7843
|
apiFormat: "openai",
|
|
7603
7844
|
isTest: true,
|
|
7604
7845
|
providerName,
|
|
7605
|
-
headers: captureFullDetails ? nonStreamingResult
|
|
7846
|
+
headers: captureFullDetails ? getResultHeaders(nonStreamingResult) : void 0
|
|
7606
7847
|
});
|
|
7607
7848
|
const streamingRequestBody = JSON.stringify(
|
|
7608
7849
|
buildProviderTestRequestBody(usageModel, "streaming")
|
|
@@ -7614,8 +7855,8 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
7614
7855
|
model: streamingResult.model ?? displayName,
|
|
7615
7856
|
sessionId: null,
|
|
7616
7857
|
rawRequestBody: streamingRequestBody,
|
|
7617
|
-
responseStatus: streamingResult
|
|
7618
|
-
responseText:
|
|
7858
|
+
responseStatus: getResultResponseStatus(streamingResult),
|
|
7859
|
+
responseText: getResultResponseText(streamingResult),
|
|
7619
7860
|
inputTokens: streamingResult.inputTokens ?? null,
|
|
7620
7861
|
outputTokens: streamingResult.outputTokens ?? null,
|
|
7621
7862
|
cacheCreationInputTokens: null,
|
|
@@ -7628,7 +7869,7 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
7628
7869
|
apiFormat: "openai",
|
|
7629
7870
|
isTest: true,
|
|
7630
7871
|
providerName,
|
|
7631
|
-
headers: captureFullDetails ? streamingResult
|
|
7872
|
+
headers: captureFullDetails ? getResultHeaders(streamingResult) : void 0
|
|
7632
7873
|
});
|
|
7633
7874
|
}
|
|
7634
7875
|
}
|
|
@@ -8033,21 +8274,23 @@ export {
|
|
|
8033
8274
|
Route$q as R,
|
|
8034
8275
|
TimeDisplayFormatSchema as T,
|
|
8035
8276
|
DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS as a,
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8277
|
+
DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS as b,
|
|
8278
|
+
DEFAULT_TIME_DISPLAY_FORMAT as c,
|
|
8279
|
+
RuntimeConfigSchema as d,
|
|
8280
|
+
AnthropicRequestSchema as e,
|
|
8281
|
+
stripClaudeCodeBillingHeader as f,
|
|
8041
8282
|
getSessionPath as g,
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
|
|
8283
|
+
providerHasContextMetadata as h,
|
|
8284
|
+
findProviderModelMetadata as i,
|
|
8285
|
+
createPendingProviderTestResults as j,
|
|
8286
|
+
ProviderTestResultsSchema as k,
|
|
8287
|
+
createFailedProviderTestResults as l,
|
|
8047
8288
|
maskApiKey as m,
|
|
8048
|
-
|
|
8049
|
-
|
|
8289
|
+
MAX_PROVIDER_TEST_TIMEOUT_SECONDS as n,
|
|
8290
|
+
resolveProviderContextWindow as o,
|
|
8050
8291
|
parseOpenAIResponse as p,
|
|
8292
|
+
isPlainRecord as q,
|
|
8051
8293
|
requestFormatForPath as r,
|
|
8052
|
-
safeGetOwnProperty as s
|
|
8294
|
+
safeGetOwnProperty as s,
|
|
8295
|
+
router as t
|
|
8053
8296
|
};
|