@tonyclaw/agent-inspector 2.1.3 → 2.1.4
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-BLYcm6Dg.js → CompareDrawer-BihEPd3v.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-DYqXb6WW.js +117 -0
- package/.output/public/assets/{ReplayDialog-_kCy9L9E.js → ReplayDialog-DnX-6kY8.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-DWp5pWsv.js → RequestAnatomy-CIkHAxZO.js} +1 -1
- package/.output/public/assets/{ResponseView-Ci92o6mt.js → ResponseView-BFc8jjZM.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-C-1ZQl_b.js → StreamingChunkSequence-p8qkpF6K.js} +1 -1
- package/.output/public/assets/_sessionId-Csx4T_y6.js +1 -0
- package/.output/public/assets/index-Bcq8bZoK.css +1 -0
- package/.output/public/assets/index-KMuh-31x.js +1 -0
- package/.output/public/assets/{main-RgLvmIQk.js → main-xlSdu7_I.js} +2 -2
- package/.output/server/_libs/lucide-react.mjs +204 -173
- package/.output/server/_libs/radix-ui__react-dialog.mjs +2 -0
- package/.output/server/{_sessionId-DnOYbKO7.mjs → _sessionId-CwVQgxoK.mjs} +3 -3
- package/.output/server/_ssr/{CompareDrawer-D44_F13_.mjs → CompareDrawer-Br9Ec0ah.mjs} +3 -3
- package/.output/server/_ssr/{ProxyViewerContainer-Cx4p_awW.mjs → ProxyViewerContainer-Oe5Tr3C2.mjs} +982 -70
- package/.output/server/_ssr/{ReplayDialog-wScCF3Oc.mjs → ReplayDialog-C1_QsoA-.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-Cf7R7PXS.mjs → RequestAnatomy-cn08QSoz.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-7pVIZLL-.mjs → ResponseView-CIqUCCTG.mjs} +3 -3
- package/.output/server/_ssr/{StreamingChunkSequence-Bs57_GbC.mjs → StreamingChunkSequence-0MhVWD2F.mjs} +3 -3
- package/.output/server/_ssr/{index-6eY__la9.mjs → index-jpnI5ghp.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-DRZPhZB6.mjs → router-SSOn7c09.mjs} +1970 -221
- package/.output/server/_tanstack-start-manifest_v-BCgy_9er.mjs +4 -0
- package/.output/server/index.mjs +64 -64
- package/package.json +2 -1
- package/src/components/ProxyViewer.tsx +87 -1
- package/src/components/ProxyViewerContainer.tsx +26 -0
- package/src/components/alerts/AlertsDialog.tsx +610 -0
- package/src/components/proxy-viewer/LogEntry.tsx +324 -51
- package/src/components/ui/dialog.tsx +1 -0
- package/src/contracts/index.ts +15 -2
- package/src/contracts/log.ts +18 -0
- package/src/lib/alertContract.ts +79 -0
- package/src/lib/apiClient.ts +39 -0
- package/src/lib/export-logs.ts +47 -9
- package/src/lib/logImportContract.ts +12 -0
- package/src/lib/useAlerts.ts +82 -0
- package/src/lib/useGroupEvidence.ts +6 -2
- package/src/lib/useGroups.ts +6 -2
- package/src/proxy/alerts.ts +664 -0
- package/src/proxy/logBodyChunks.ts +91 -0
- package/src/proxy/logImporter.ts +491 -0
- package/src/proxy/logIndex.ts +63 -2
- package/src/proxy/sqliteLogIndex.ts +612 -0
- package/src/proxy/store.ts +32 -7
- package/src/routes/api/alerts.summary.ts +24 -0
- package/src/routes/api/alerts.ts +52 -0
- package/src/routes/api/logs.$id.body.ts +44 -0
- package/src/routes/api/logs.import.ts +50 -0
- package/src/services/alerts.ts +12 -0
- package/.output/public/assets/ProxyViewerContainer-Ba5wFn00.js +0 -117
- package/.output/public/assets/_sessionId-DKzAmSNP.js +0 -1
- package/.output/public/assets/index-B-MZ9lQM.css +0 -1
- package/.output/public/assets/index-ZZHwgkWJ.js +0 -1
- package/.output/server/_tanstack-start-manifest_v-DfAVFkZ5.mjs +0 -4
|
@@ -5,14 +5,14 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync, copyFil
|
|
|
5
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
|
-
import path, { join, isAbsolute, dirname, resolve, relative } from "node:path";
|
|
8
|
+
import path, { basename, join, isAbsolute, dirname, resolve, relative } from "node:path";
|
|
9
9
|
import { execFile, exec, spawn } from "node:child_process";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { C as Conf } from "../_libs/conf.mjs";
|
|
12
12
|
import { randomUUID } from "crypto";
|
|
13
13
|
import { promisify } from "node:util";
|
|
14
14
|
import { Worker } from "node:worker_threads";
|
|
15
|
-
import { randomUUID as randomUUID$1 } from "node:crypto";
|
|
15
|
+
import { randomUUID as randomUUID$1, createHash } from "node:crypto";
|
|
16
16
|
import { M as McpServer, W as WebStandardStreamableHTTPServerTransport, R as ResourceTemplate } from "../_libs/modelcontextprotocol__server.mjs";
|
|
17
17
|
import { J as JSZip } from "../_libs/jszip.mjs";
|
|
18
18
|
import { homedir } from "node:os";
|
|
@@ -65,8 +65,8 @@ import "../_libs/immediate.mjs";
|
|
|
65
65
|
import "../_libs/setimmediate.mjs";
|
|
66
66
|
import "../_libs/pako.mjs";
|
|
67
67
|
const faviconSvg = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20role='img'%20aria-label='Agent%20Inspector'%3e%3cg%20fill='none'%20stroke='%23f59e0b'%20stroke-width='1.5'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M5%2013%20C5%209%208%207%2012%207%20C16%207%2019%209%2019%2013%20C19%2016%2016%2018%2012%2018%20C8%2018%205%2016%205%2013%20Z'%20/%3e%3cpath%20d='M5%2011%20C3.5%209.5%201.5%2010%202%2012.5%20C2.5%2014%204%2013.5%205%2012.5'%20/%3e%3cpath%20d='M19%2011%20C20.5%209.5%2022.5%2010%2022%2012.5%20C21.5%2014%2020%2013.5%2019%2012.5'%20/%3e%3cline%20x1='10'%20y1='7'%20x2='9.5'%20y2='5'%20/%3e%3cline%20x1='14'%20y1='7'%20x2='14.5'%20y2='5'%20/%3e%3cline%20x1='6.5'%20y1='16'%20x2='4.5'%20y2='19.5'%20/%3e%3cline%20x1='9'%20y1='17.5'%20x2='8'%20y2='20.5'%20/%3e%3cline%20x1='15'%20y1='17.5'%20x2='16'%20y2='20.5'%20/%3e%3cline%20x1='17.5'%20y1='16'%20x2='19.5'%20y2='19.5'%20/%3e%3c/g%3e%3ccircle%20cx='9.5'%20cy='4.5'%20r='0.9'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='14.5'%20cy='4.5'%20r='0.9'%20fill='%23f59e0b'%20/%3e%3c/svg%3e";
|
|
68
|
-
const appCss = "/assets/index-
|
|
69
|
-
const Route$
|
|
68
|
+
const appCss = "/assets/index-Bcq8bZoK.css";
|
|
69
|
+
const Route$D = createRootRoute({
|
|
70
70
|
head: () => ({
|
|
71
71
|
meta: [
|
|
72
72
|
{ charSet: "utf-8" },
|
|
@@ -108,8 +108,8 @@ function RootDocument({ children }) {
|
|
|
108
108
|
] })
|
|
109
109
|
] });
|
|
110
110
|
}
|
|
111
|
-
const $$splitComponentImporter$1 = () => import("./index-
|
|
112
|
-
const Route$
|
|
111
|
+
const $$splitComponentImporter$1 = () => import("./index-jpnI5ghp.mjs");
|
|
112
|
+
const Route$C = createFileRoute("/")({
|
|
113
113
|
component: lazyRouteComponent($$splitComponentImporter$1, "component")
|
|
114
114
|
});
|
|
115
115
|
const B64URL_RE = /^[A-Za-z0-9_-]+$/;
|
|
@@ -151,8 +151,8 @@ function decodeSessionIdFromPath(encoded) {
|
|
|
151
151
|
function getSessionPath(sessionId) {
|
|
152
152
|
return `/session/${encodeSessionIdForPath(sessionId)}`;
|
|
153
153
|
}
|
|
154
|
-
const $$splitComponentImporter = () => import("../_sessionId-
|
|
155
|
-
const Route$
|
|
154
|
+
const $$splitComponentImporter = () => import("../_sessionId-CwVQgxoK.mjs");
|
|
155
|
+
const Route$B = createFileRoute("/session/$sessionId")({
|
|
156
156
|
component: lazyRouteComponent($$splitComponentImporter, "component"),
|
|
157
157
|
parseParams: (params) => ({
|
|
158
158
|
sessionId: decodeSessionIdFromPath(params.sessionId)
|
|
@@ -385,6 +385,19 @@ const StreamingChunksArraySchema = object({
|
|
|
385
385
|
chunks: array(StreamingChunkSchema$1),
|
|
386
386
|
truncated: boolean().optional().default(false)
|
|
387
387
|
});
|
|
388
|
+
const LogBodyPartSchema = _enum(["request", "response"]);
|
|
389
|
+
const LogBodyChunkSchema = object({
|
|
390
|
+
logId: number().int().positive(),
|
|
391
|
+
part: LogBodyPartSchema,
|
|
392
|
+
text: string(),
|
|
393
|
+
offset: number().int().nonnegative(),
|
|
394
|
+
limit: number().int().positive(),
|
|
395
|
+
totalBytes: number().int().nonnegative(),
|
|
396
|
+
textBytes: number().int().nonnegative(),
|
|
397
|
+
nextOffset: number().int().nonnegative().nullable(),
|
|
398
|
+
hasMore: boolean(),
|
|
399
|
+
contentMode: _enum(["empty", "partial", "full"])
|
|
400
|
+
});
|
|
388
401
|
const CapturedLogSchema = object({
|
|
389
402
|
id: number(),
|
|
390
403
|
timestamp: string(),
|
|
@@ -851,12 +864,530 @@ function readChunks(path2) {
|
|
|
851
864
|
return null;
|
|
852
865
|
}
|
|
853
866
|
}
|
|
867
|
+
const SQLITE_INDEX_FILE = "inspector.sqlite";
|
|
868
|
+
const SQLITE_PACKAGE_NAME = "better-sqlite3";
|
|
869
|
+
const BUN_SQLITE_MODULE_NAME = "bun:sqlite";
|
|
870
|
+
const CREATE_SCHEMA_SQL = `
|
|
871
|
+
CREATE TABLE IF NOT EXISTS log_index (
|
|
872
|
+
id INTEGER PRIMARY KEY,
|
|
873
|
+
file TEXT NOT NULL,
|
|
874
|
+
byte_offset INTEGER NOT NULL,
|
|
875
|
+
byte_length INTEGER NOT NULL,
|
|
876
|
+
session_id TEXT,
|
|
877
|
+
model TEXT,
|
|
878
|
+
timestamp TEXT NOT NULL,
|
|
879
|
+
method TEXT NOT NULL,
|
|
880
|
+
path TEXT NOT NULL,
|
|
881
|
+
response_status INTEGER,
|
|
882
|
+
input_tokens INTEGER,
|
|
883
|
+
output_tokens INTEGER,
|
|
884
|
+
cache_creation_input_tokens INTEGER,
|
|
885
|
+
cache_read_input_tokens INTEGER,
|
|
886
|
+
elapsed_ms INTEGER,
|
|
887
|
+
first_chunk_ms INTEGER,
|
|
888
|
+
total_stream_ms INTEGER,
|
|
889
|
+
tokens_per_second REAL,
|
|
890
|
+
streaming INTEGER NOT NULL,
|
|
891
|
+
user_agent TEXT,
|
|
892
|
+
origin TEXT,
|
|
893
|
+
api_format TEXT NOT NULL,
|
|
894
|
+
is_test INTEGER NOT NULL,
|
|
895
|
+
replay_of_log_id INTEGER,
|
|
896
|
+
provider_name TEXT,
|
|
897
|
+
client_port INTEGER,
|
|
898
|
+
client_pid INTEGER,
|
|
899
|
+
client_cwd TEXT,
|
|
900
|
+
client_project_folder TEXT,
|
|
901
|
+
streaming_chunks_path TEXT,
|
|
902
|
+
raw_request_body_bytes INTEGER,
|
|
903
|
+
response_text_bytes INTEGER,
|
|
904
|
+
warnings_json TEXT,
|
|
905
|
+
error TEXT
|
|
906
|
+
);
|
|
907
|
+
CREATE INDEX IF NOT EXISTS idx_log_index_session_id_id ON log_index(session_id, id);
|
|
908
|
+
CREATE INDEX IF NOT EXISTS idx_log_index_model_id ON log_index(model, id);
|
|
909
|
+
CREATE INDEX IF NOT EXISTS idx_log_index_timestamp ON log_index(timestamp);
|
|
910
|
+
`;
|
|
911
|
+
const UPSERT_SQL = `
|
|
912
|
+
INSERT INTO log_index (
|
|
913
|
+
id,
|
|
914
|
+
file,
|
|
915
|
+
byte_offset,
|
|
916
|
+
byte_length,
|
|
917
|
+
session_id,
|
|
918
|
+
model,
|
|
919
|
+
timestamp,
|
|
920
|
+
method,
|
|
921
|
+
path,
|
|
922
|
+
response_status,
|
|
923
|
+
input_tokens,
|
|
924
|
+
output_tokens,
|
|
925
|
+
cache_creation_input_tokens,
|
|
926
|
+
cache_read_input_tokens,
|
|
927
|
+
elapsed_ms,
|
|
928
|
+
first_chunk_ms,
|
|
929
|
+
total_stream_ms,
|
|
930
|
+
tokens_per_second,
|
|
931
|
+
streaming,
|
|
932
|
+
user_agent,
|
|
933
|
+
origin,
|
|
934
|
+
api_format,
|
|
935
|
+
is_test,
|
|
936
|
+
replay_of_log_id,
|
|
937
|
+
provider_name,
|
|
938
|
+
client_port,
|
|
939
|
+
client_pid,
|
|
940
|
+
client_cwd,
|
|
941
|
+
client_project_folder,
|
|
942
|
+
streaming_chunks_path,
|
|
943
|
+
raw_request_body_bytes,
|
|
944
|
+
response_text_bytes,
|
|
945
|
+
warnings_json,
|
|
946
|
+
error
|
|
947
|
+
) VALUES (
|
|
948
|
+
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
949
|
+
)
|
|
950
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
951
|
+
file = excluded.file,
|
|
952
|
+
byte_offset = excluded.byte_offset,
|
|
953
|
+
byte_length = excluded.byte_length,
|
|
954
|
+
session_id = excluded.session_id,
|
|
955
|
+
model = excluded.model,
|
|
956
|
+
timestamp = excluded.timestamp,
|
|
957
|
+
method = excluded.method,
|
|
958
|
+
path = excluded.path,
|
|
959
|
+
response_status = excluded.response_status,
|
|
960
|
+
input_tokens = excluded.input_tokens,
|
|
961
|
+
output_tokens = excluded.output_tokens,
|
|
962
|
+
cache_creation_input_tokens = excluded.cache_creation_input_tokens,
|
|
963
|
+
cache_read_input_tokens = excluded.cache_read_input_tokens,
|
|
964
|
+
elapsed_ms = excluded.elapsed_ms,
|
|
965
|
+
first_chunk_ms = excluded.first_chunk_ms,
|
|
966
|
+
total_stream_ms = excluded.total_stream_ms,
|
|
967
|
+
tokens_per_second = excluded.tokens_per_second,
|
|
968
|
+
streaming = excluded.streaming,
|
|
969
|
+
user_agent = excluded.user_agent,
|
|
970
|
+
origin = excluded.origin,
|
|
971
|
+
api_format = excluded.api_format,
|
|
972
|
+
is_test = excluded.is_test,
|
|
973
|
+
replay_of_log_id = excluded.replay_of_log_id,
|
|
974
|
+
provider_name = excluded.provider_name,
|
|
975
|
+
client_port = excluded.client_port,
|
|
976
|
+
client_pid = excluded.client_pid,
|
|
977
|
+
client_cwd = excluded.client_cwd,
|
|
978
|
+
client_project_folder = excluded.client_project_folder,
|
|
979
|
+
streaming_chunks_path = excluded.streaming_chunks_path,
|
|
980
|
+
raw_request_body_bytes = excluded.raw_request_body_bytes,
|
|
981
|
+
response_text_bytes = excluded.response_text_bytes,
|
|
982
|
+
warnings_json = excluded.warnings_json,
|
|
983
|
+
error = excluded.error
|
|
984
|
+
`;
|
|
985
|
+
let sqliteStatePromise = null;
|
|
986
|
+
let sqliteStatePath = null;
|
|
987
|
+
let activeDb = null;
|
|
988
|
+
let didLogUnavailable = false;
|
|
989
|
+
function isSqliteLogIndexEnabled() {
|
|
990
|
+
const configured = process.env["AGENT_INSPECTOR_SQLITE_INDEX"];
|
|
991
|
+
if (configured === "1") return true;
|
|
992
|
+
if (configured === "0") return false;
|
|
993
|
+
return process.env["NODE_ENV"] !== "test";
|
|
994
|
+
}
|
|
995
|
+
function getSqlitePath() {
|
|
996
|
+
return join(resolveLogDir(), SQLITE_INDEX_FILE);
|
|
997
|
+
}
|
|
998
|
+
function objectFromUnknown(value) {
|
|
999
|
+
if (value === null) return null;
|
|
1000
|
+
if (typeof value === "object" || typeof value === "function") return value;
|
|
1001
|
+
return null;
|
|
1002
|
+
}
|
|
1003
|
+
function readProperty$1(value, name) {
|
|
1004
|
+
let current = objectFromUnknown(value);
|
|
1005
|
+
while (current !== null) {
|
|
1006
|
+
const desc = Object.getOwnPropertyDescriptor(current, name);
|
|
1007
|
+
if (desc !== void 0) {
|
|
1008
|
+
const propertyValue = Reflect.get(current, name);
|
|
1009
|
+
return propertyValue;
|
|
1010
|
+
}
|
|
1011
|
+
const nextPrototype = Object.getPrototypeOf(current);
|
|
1012
|
+
current = objectFromUnknown(nextPrototype);
|
|
1013
|
+
}
|
|
1014
|
+
return void 0;
|
|
1015
|
+
}
|
|
1016
|
+
function readFunction(value, name) {
|
|
1017
|
+
const property = readProperty$1(value, name);
|
|
1018
|
+
return typeof property === "function" ? property : null;
|
|
1019
|
+
}
|
|
1020
|
+
function callMethod(target, methodName, args) {
|
|
1021
|
+
const method = readFunction(target, methodName);
|
|
1022
|
+
if (method === null) return void 0;
|
|
1023
|
+
try {
|
|
1024
|
+
return Reflect.apply(method, target, [...args]);
|
|
1025
|
+
} catch (err) {
|
|
1026
|
+
logger.warn("[sqliteLogIndex] SQLite method failed:", methodName, String(err));
|
|
1027
|
+
return void 0;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
function prepareStatement(db, sql) {
|
|
1031
|
+
return callMethod(db, "prepare", [sql]);
|
|
1032
|
+
}
|
|
1033
|
+
function runPrepared(db, sql, params = []) {
|
|
1034
|
+
const statement = prepareStatement(db, sql);
|
|
1035
|
+
if (statement === void 0) return false;
|
|
1036
|
+
const result = callMethod(statement, "run", params);
|
|
1037
|
+
callMethod(statement, "finalize", []);
|
|
1038
|
+
return result !== void 0;
|
|
1039
|
+
}
|
|
1040
|
+
function getPrepared(db, sql, params = []) {
|
|
1041
|
+
const statement = prepareStatement(db, sql);
|
|
1042
|
+
if (statement === void 0) return void 0;
|
|
1043
|
+
const result = callMethod(statement, "get", params);
|
|
1044
|
+
callMethod(statement, "finalize", []);
|
|
1045
|
+
return result;
|
|
1046
|
+
}
|
|
1047
|
+
function allPrepared(db, sql, params = []) {
|
|
1048
|
+
const statement = prepareStatement(db, sql);
|
|
1049
|
+
if (statement === void 0) return null;
|
|
1050
|
+
const result = callMethod(statement, "all", params);
|
|
1051
|
+
callMethod(statement, "finalize", []);
|
|
1052
|
+
return Array.isArray(result) ? result : null;
|
|
1053
|
+
}
|
|
1054
|
+
function execSql(db, sql) {
|
|
1055
|
+
const result = callMethod(db, "exec", [sql]);
|
|
1056
|
+
return result !== void 0;
|
|
1057
|
+
}
|
|
1058
|
+
function sqliteConstructorFromModule(moduleValue, exportName) {
|
|
1059
|
+
const exportedValue = readProperty$1(moduleValue, exportName);
|
|
1060
|
+
if (typeof exportedValue === "function") {
|
|
1061
|
+
return (path2) => Reflect.construct(exportedValue, [path2]);
|
|
1062
|
+
}
|
|
1063
|
+
return null;
|
|
1064
|
+
}
|
|
1065
|
+
async function loadSqliteModuleConstructor(moduleName, exportName) {
|
|
1066
|
+
try {
|
|
1067
|
+
const importedModule = await import(
|
|
1068
|
+
/* @vite-ignore */
|
|
1069
|
+
moduleName
|
|
1070
|
+
);
|
|
1071
|
+
const exportedConstructor = sqliteConstructorFromModule(importedModule, exportName);
|
|
1072
|
+
if (exportedConstructor !== null) return { constructor: exportedConstructor, reason: null };
|
|
1073
|
+
if (exportName === "default" && typeof importedModule === "function") {
|
|
1074
|
+
return {
|
|
1075
|
+
constructor: (path2) => Reflect.construct(importedModule, [path2]),
|
|
1076
|
+
reason: null
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
return { constructor: null, reason: `${moduleName} did not expose ${exportName}` };
|
|
1080
|
+
} catch (err) {
|
|
1081
|
+
return { constructor: null, reason: String(err) };
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
async function loadSqliteConstructor() {
|
|
1085
|
+
const bunRuntimeDesc = Object.getOwnPropertyDescriptor(process.versions, "bun");
|
|
1086
|
+
if (bunRuntimeDesc !== void 0) {
|
|
1087
|
+
const bunSqlite2 = await loadSqliteModuleConstructor(BUN_SQLITE_MODULE_NAME, "Database");
|
|
1088
|
+
if (bunSqlite2.constructor !== null) return bunSqlite2;
|
|
1089
|
+
const betterSqlite2 = await loadSqliteModuleConstructor(SQLITE_PACKAGE_NAME, "default");
|
|
1090
|
+
if (betterSqlite2.constructor !== null) return betterSqlite2;
|
|
1091
|
+
const reason2 = [bunSqlite2.reason, betterSqlite2.reason].filter((item) => item !== null).join("; ");
|
|
1092
|
+
if (!didLogUnavailable) {
|
|
1093
|
+
didLogUnavailable = true;
|
|
1094
|
+
logger.warn("[sqliteLogIndex] Optional SQLite index unavailable:", reason2);
|
|
1095
|
+
}
|
|
1096
|
+
return { constructor: null, reason: reason2 };
|
|
1097
|
+
}
|
|
1098
|
+
const betterSqlite = await loadSqliteModuleConstructor(SQLITE_PACKAGE_NAME, "default");
|
|
1099
|
+
if (betterSqlite.constructor !== null) return betterSqlite;
|
|
1100
|
+
const bunSqlite = await loadSqliteModuleConstructor(BUN_SQLITE_MODULE_NAME, "Database");
|
|
1101
|
+
if (bunSqlite.constructor !== null) return bunSqlite;
|
|
1102
|
+
const reason = [betterSqlite.reason, bunSqlite.reason].filter((item) => item !== null).join("; ");
|
|
1103
|
+
if (!didLogUnavailable) {
|
|
1104
|
+
didLogUnavailable = true;
|
|
1105
|
+
logger.warn("[sqliteLogIndex] Optional SQLite index unavailable:", reason);
|
|
1106
|
+
}
|
|
1107
|
+
return { constructor: null, reason };
|
|
1108
|
+
}
|
|
1109
|
+
async function initializeSqliteState() {
|
|
1110
|
+
const path2 = getSqlitePath();
|
|
1111
|
+
if (!isSqliteLogIndexEnabled()) {
|
|
1112
|
+
return { status: "unavailable", path: path2, reason: "SQLite log index is disabled" };
|
|
1113
|
+
}
|
|
1114
|
+
const sqliteConstructor = await loadSqliteConstructor();
|
|
1115
|
+
if (sqliteConstructor.constructor === null) {
|
|
1116
|
+
return {
|
|
1117
|
+
status: "unavailable",
|
|
1118
|
+
path: path2,
|
|
1119
|
+
reason: sqliteConstructor.reason ?? "SQLite runtime is not available"
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
try {
|
|
1123
|
+
await mkdir(dirname(path2), { recursive: true });
|
|
1124
|
+
const db = sqliteConstructor.constructor(path2);
|
|
1125
|
+
execSql(db, "PRAGMA journal_mode = WAL");
|
|
1126
|
+
execSql(db, "PRAGMA synchronous = NORMAL");
|
|
1127
|
+
if (!execSql(db, CREATE_SCHEMA_SQL)) {
|
|
1128
|
+
return { status: "unavailable", path: path2, reason: "SQLite schema initialization failed" };
|
|
1129
|
+
}
|
|
1130
|
+
activeDb = db;
|
|
1131
|
+
return { status: "ready", db, path: path2 };
|
|
1132
|
+
} catch (err) {
|
|
1133
|
+
logger.warn("[sqliteLogIndex] Failed to initialize SQLite index:", String(err));
|
|
1134
|
+
return { status: "unavailable", path: path2, reason: String(err) };
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
async function getSqliteState() {
|
|
1138
|
+
const path2 = getSqlitePath();
|
|
1139
|
+
if (sqliteStatePromise !== null && sqliteStatePath !== path2) {
|
|
1140
|
+
closeSqliteLogIndex();
|
|
1141
|
+
}
|
|
1142
|
+
if (sqliteStatePromise === null) {
|
|
1143
|
+
sqliteStatePath = path2;
|
|
1144
|
+
sqliteStatePromise = initializeSqliteState();
|
|
1145
|
+
}
|
|
1146
|
+
return await sqliteStatePromise;
|
|
1147
|
+
}
|
|
1148
|
+
function closeSqliteLogIndex() {
|
|
1149
|
+
if (activeDb !== null) {
|
|
1150
|
+
callMethod(activeDb, "close", []);
|
|
1151
|
+
}
|
|
1152
|
+
activeDb = null;
|
|
1153
|
+
sqliteStatePromise = null;
|
|
1154
|
+
sqliteStatePath = null;
|
|
1155
|
+
}
|
|
1156
|
+
function warningJson(warnings) {
|
|
1157
|
+
return warnings === void 0 ? null : JSON.stringify(warnings);
|
|
1158
|
+
}
|
|
1159
|
+
function boolToInt(value) {
|
|
1160
|
+
return value ? 1 : 0;
|
|
1161
|
+
}
|
|
1162
|
+
function entryParams(entry) {
|
|
1163
|
+
const summary = entry.summary;
|
|
1164
|
+
return [
|
|
1165
|
+
entry.id,
|
|
1166
|
+
entry.file,
|
|
1167
|
+
entry.byteOffset,
|
|
1168
|
+
entry.byteLength,
|
|
1169
|
+
entry.sessionId ?? summary?.sessionId ?? null,
|
|
1170
|
+
entry.model ?? summary?.model ?? null,
|
|
1171
|
+
summary?.timestamp ?? "",
|
|
1172
|
+
summary?.method ?? "",
|
|
1173
|
+
summary?.path ?? "",
|
|
1174
|
+
summary?.responseStatus ?? null,
|
|
1175
|
+
summary?.inputTokens ?? null,
|
|
1176
|
+
summary?.outputTokens ?? null,
|
|
1177
|
+
summary?.cacheCreationInputTokens ?? null,
|
|
1178
|
+
summary?.cacheReadInputTokens ?? null,
|
|
1179
|
+
summary?.elapsedMs ?? null,
|
|
1180
|
+
summary?.firstChunkMs ?? null,
|
|
1181
|
+
summary?.totalStreamMs ?? null,
|
|
1182
|
+
summary?.tokensPerSecond ?? null,
|
|
1183
|
+
boolToInt(summary?.streaming ?? false),
|
|
1184
|
+
summary?.userAgent ?? null,
|
|
1185
|
+
summary?.origin ?? null,
|
|
1186
|
+
summary?.apiFormat ?? "unknown",
|
|
1187
|
+
boolToInt(summary?.isTest ?? false),
|
|
1188
|
+
summary?.replayOfLogId ?? null,
|
|
1189
|
+
summary?.providerName ?? null,
|
|
1190
|
+
summary?.clientPort ?? null,
|
|
1191
|
+
summary?.clientPid ?? null,
|
|
1192
|
+
summary?.clientCwd ?? null,
|
|
1193
|
+
summary?.clientProjectFolder ?? null,
|
|
1194
|
+
summary?.streamingChunksPath ?? null,
|
|
1195
|
+
summary?.rawRequestBodyBytes ?? null,
|
|
1196
|
+
summary?.responseTextBytes ?? null,
|
|
1197
|
+
warningJson(summary?.warnings),
|
|
1198
|
+
summary?.error ?? null
|
|
1199
|
+
];
|
|
1200
|
+
}
|
|
1201
|
+
function readNumber(row, name) {
|
|
1202
|
+
const value = readProperty$1(row, name);
|
|
1203
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1204
|
+
}
|
|
1205
|
+
function readString$1(row, name) {
|
|
1206
|
+
const value = readProperty$1(row, name);
|
|
1207
|
+
return typeof value === "string" ? value : null;
|
|
1208
|
+
}
|
|
1209
|
+
function readBoolean(row, name) {
|
|
1210
|
+
return readNumber(row, name) === 1;
|
|
1211
|
+
}
|
|
1212
|
+
function readApiFormat(row) {
|
|
1213
|
+
const value = readString$1(row, "api_format");
|
|
1214
|
+
switch (value) {
|
|
1215
|
+
case "anthropic":
|
|
1216
|
+
return "anthropic";
|
|
1217
|
+
case "openai":
|
|
1218
|
+
return "openai";
|
|
1219
|
+
case "unknown":
|
|
1220
|
+
case null:
|
|
1221
|
+
return "unknown";
|
|
1222
|
+
default:
|
|
1223
|
+
return "unknown";
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
function readWarnings(row) {
|
|
1227
|
+
const value = readString$1(row, "warnings_json");
|
|
1228
|
+
if (value === null) return void 0;
|
|
1229
|
+
try {
|
|
1230
|
+
const parsed = JSON.parse(value);
|
|
1231
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
1232
|
+
const warnings = [];
|
|
1233
|
+
for (const item of parsed) {
|
|
1234
|
+
if (typeof item !== "string") return void 0;
|
|
1235
|
+
warnings.push(item);
|
|
1236
|
+
}
|
|
1237
|
+
return warnings;
|
|
1238
|
+
} catch {
|
|
1239
|
+
return void 0;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
function readRequiredNumber(row, name) {
|
|
1243
|
+
const value = readNumber(row, name);
|
|
1244
|
+
return value === null || !Number.isInteger(value) ? null : value;
|
|
1245
|
+
}
|
|
1246
|
+
function summaryFromRow(row, id) {
|
|
1247
|
+
return {
|
|
1248
|
+
id,
|
|
1249
|
+
timestamp: readString$1(row, "timestamp") ?? "",
|
|
1250
|
+
method: readString$1(row, "method") ?? "",
|
|
1251
|
+
path: readString$1(row, "path") ?? "",
|
|
1252
|
+
model: readString$1(row, "model"),
|
|
1253
|
+
sessionId: readString$1(row, "session_id"),
|
|
1254
|
+
responseStatus: readNumber(row, "response_status"),
|
|
1255
|
+
inputTokens: readNumber(row, "input_tokens"),
|
|
1256
|
+
outputTokens: readNumber(row, "output_tokens"),
|
|
1257
|
+
cacheCreationInputTokens: readNumber(row, "cache_creation_input_tokens"),
|
|
1258
|
+
cacheReadInputTokens: readNumber(row, "cache_read_input_tokens"),
|
|
1259
|
+
elapsedMs: readNumber(row, "elapsed_ms"),
|
|
1260
|
+
firstChunkMs: readNumber(row, "first_chunk_ms"),
|
|
1261
|
+
totalStreamMs: readNumber(row, "total_stream_ms"),
|
|
1262
|
+
tokensPerSecond: readNumber(row, "tokens_per_second"),
|
|
1263
|
+
streaming: readBoolean(row, "streaming"),
|
|
1264
|
+
userAgent: readString$1(row, "user_agent"),
|
|
1265
|
+
origin: readString$1(row, "origin"),
|
|
1266
|
+
apiFormat: readApiFormat(row),
|
|
1267
|
+
isTest: readBoolean(row, "is_test"),
|
|
1268
|
+
replayOfLogId: readNumber(row, "replay_of_log_id"),
|
|
1269
|
+
providerName: readString$1(row, "provider_name"),
|
|
1270
|
+
clientPort: readNumber(row, "client_port"),
|
|
1271
|
+
clientPid: readNumber(row, "client_pid"),
|
|
1272
|
+
clientCwd: readString$1(row, "client_cwd"),
|
|
1273
|
+
clientProjectFolder: readString$1(row, "client_project_folder"),
|
|
1274
|
+
streamingChunksPath: readString$1(row, "streaming_chunks_path"),
|
|
1275
|
+
rawRequestBodyBytes: readNumber(row, "raw_request_body_bytes"),
|
|
1276
|
+
responseTextBytes: readNumber(row, "response_text_bytes"),
|
|
1277
|
+
warnings: readWarnings(row),
|
|
1278
|
+
error: readString$1(row, "error")
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
function entryFromRow(row) {
|
|
1282
|
+
const id = readRequiredNumber(row, "id");
|
|
1283
|
+
const file = readString$1(row, "file");
|
|
1284
|
+
const byteOffset = readRequiredNumber(row, "byte_offset");
|
|
1285
|
+
const byteLength = readRequiredNumber(row, "byte_length");
|
|
1286
|
+
if (id === null || file === null || byteOffset === null || byteLength === null) return null;
|
|
1287
|
+
return {
|
|
1288
|
+
id,
|
|
1289
|
+
file,
|
|
1290
|
+
byteOffset,
|
|
1291
|
+
byteLength,
|
|
1292
|
+
sessionId: readString$1(row, "session_id"),
|
|
1293
|
+
model: readString$1(row, "model"),
|
|
1294
|
+
summary: summaryFromRow(row, id)
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
async function getSqliteLogIndexMaxId() {
|
|
1298
|
+
const state = await getSqliteState();
|
|
1299
|
+
if (state.status !== "ready") return null;
|
|
1300
|
+
const row = getPrepared(state.db, "SELECT MAX(id) AS max_id FROM log_index");
|
|
1301
|
+
return readNumber(row, "max_id") ?? 0;
|
|
1302
|
+
}
|
|
1303
|
+
async function upsertSqliteLogIndexEntry(entry) {
|
|
1304
|
+
if (entry.summary === void 0) return false;
|
|
1305
|
+
const state = await getSqliteState();
|
|
1306
|
+
if (state.status !== "ready") return false;
|
|
1307
|
+
return runPrepared(state.db, UPSERT_SQL, entryParams(entry));
|
|
1308
|
+
}
|
|
1309
|
+
async function syncSqliteLogIndexEntries(entries) {
|
|
1310
|
+
const state = await getSqliteState();
|
|
1311
|
+
if (state.status !== "ready") return false;
|
|
1312
|
+
if (entries.length === 0) return true;
|
|
1313
|
+
if (!execSql(state.db, "BEGIN IMMEDIATE")) return false;
|
|
1314
|
+
try {
|
|
1315
|
+
for (const entry of entries) {
|
|
1316
|
+
if (entry.summary === void 0) continue;
|
|
1317
|
+
if (!runPrepared(state.db, UPSERT_SQL, entryParams(entry))) {
|
|
1318
|
+
execSql(state.db, "ROLLBACK");
|
|
1319
|
+
return false;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
return execSql(state.db, "COMMIT");
|
|
1323
|
+
} catch (err) {
|
|
1324
|
+
execSql(state.db, "ROLLBACK");
|
|
1325
|
+
logger.warn("[sqliteLogIndex] Failed to sync SQLite index:", String(err));
|
|
1326
|
+
return false;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
async function findSqliteLogIndexEntry(id) {
|
|
1330
|
+
const state = await getSqliteState();
|
|
1331
|
+
if (state.status !== "ready") return null;
|
|
1332
|
+
const row = getPrepared(state.db, "SELECT * FROM log_index WHERE id = ?", [id]);
|
|
1333
|
+
return entryFromRow(row);
|
|
1334
|
+
}
|
|
1335
|
+
async function listSqliteLogIndexEntries({
|
|
1336
|
+
sessionId,
|
|
1337
|
+
model
|
|
1338
|
+
} = {}) {
|
|
1339
|
+
const state = await getSqliteState();
|
|
1340
|
+
if (state.status !== "ready") return null;
|
|
1341
|
+
const clauses = [];
|
|
1342
|
+
const params = [];
|
|
1343
|
+
if (sessionId !== void 0) {
|
|
1344
|
+
clauses.push("session_id = ?");
|
|
1345
|
+
params.push(sessionId);
|
|
1346
|
+
}
|
|
1347
|
+
if (model !== void 0) {
|
|
1348
|
+
clauses.push("model = ?");
|
|
1349
|
+
params.push(model);
|
|
1350
|
+
}
|
|
1351
|
+
const where = clauses.length === 0 ? "" : ` WHERE ${clauses.join(" AND ")}`;
|
|
1352
|
+
const rows = allPrepared(state.db, `SELECT * FROM log_index${where} ORDER BY id ASC`, params);
|
|
1353
|
+
if (rows === null) return null;
|
|
1354
|
+
const entries = [];
|
|
1355
|
+
for (const row of rows) {
|
|
1356
|
+
const entry = entryFromRow(row);
|
|
1357
|
+
if (entry !== null) entries.push(entry);
|
|
1358
|
+
}
|
|
1359
|
+
return entries;
|
|
1360
|
+
}
|
|
1361
|
+
async function replaceSqliteLogIndexEntries(entries) {
|
|
1362
|
+
const state = await getSqliteState();
|
|
1363
|
+
if (state.status !== "ready") return false;
|
|
1364
|
+
if (!execSql(state.db, "BEGIN IMMEDIATE")) return false;
|
|
1365
|
+
try {
|
|
1366
|
+
if (!runPrepared(state.db, "DELETE FROM log_index")) {
|
|
1367
|
+
execSql(state.db, "ROLLBACK");
|
|
1368
|
+
return false;
|
|
1369
|
+
}
|
|
1370
|
+
for (const entry of entries) {
|
|
1371
|
+
if (entry.summary === void 0) continue;
|
|
1372
|
+
if (!runPrepared(state.db, UPSERT_SQL, entryParams(entry))) {
|
|
1373
|
+
execSql(state.db, "ROLLBACK");
|
|
1374
|
+
return false;
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
return execSql(state.db, "COMMIT");
|
|
1378
|
+
} catch (err) {
|
|
1379
|
+
execSql(state.db, "ROLLBACK");
|
|
1380
|
+
logger.warn("[sqliteLogIndex] Failed to replace SQLite index:", String(err));
|
|
1381
|
+
return false;
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
854
1384
|
const INDEX_VERSION = 1;
|
|
855
1385
|
const INDEX_FILE = "logs.idx";
|
|
856
1386
|
function getIndexPath() {
|
|
857
1387
|
return join(resolveLogDir(), INDEX_FILE);
|
|
858
1388
|
}
|
|
859
1389
|
let cachedIndex = null;
|
|
1390
|
+
let sqliteBackfillScheduledMaxId = 0;
|
|
860
1391
|
function textByteLength$2(value) {
|
|
861
1392
|
return value === null ? null : Buffer.byteLength(value, "utf8");
|
|
862
1393
|
}
|
|
@@ -950,10 +1481,12 @@ async function saveIndex(index) {
|
|
|
950
1481
|
}
|
|
951
1482
|
async function addToIndex(id, file, byteOffset, byteLength, metadata) {
|
|
952
1483
|
const index = await loadIndex();
|
|
953
|
-
|
|
1484
|
+
const entry = metadata === void 0 ? { id, file, byteOffset, byteLength } : { id, file, byteOffset, byteLength, ...metadata };
|
|
1485
|
+
index.entries[id] = entry;
|
|
954
1486
|
if (id > index.maxId) {
|
|
955
1487
|
index.maxId = id;
|
|
956
1488
|
}
|
|
1489
|
+
void upsertSqliteLogIndexEntry(entry);
|
|
957
1490
|
scheduleIndexFlush();
|
|
958
1491
|
}
|
|
959
1492
|
let indexFlushScheduled = false;
|
|
@@ -981,13 +1514,50 @@ async function flushIndex() {
|
|
|
981
1514
|
await saveIndex(index);
|
|
982
1515
|
}
|
|
983
1516
|
async function findInIndex(id) {
|
|
1517
|
+
const sqliteEntry = await findSqliteLogIndexEntry(id);
|
|
1518
|
+
if (sqliteEntry !== null) return sqliteEntry;
|
|
984
1519
|
const index = await loadIndex();
|
|
985
1520
|
return index.entries[id] ?? null;
|
|
986
1521
|
}
|
|
987
1522
|
async function listIndexEntries() {
|
|
988
1523
|
const index = await loadIndex();
|
|
1524
|
+
const sqliteMaxId = await getSqliteLogIndexMaxId();
|
|
1525
|
+
if (sqliteMaxId !== null && sqliteMaxId >= index.maxId) {
|
|
1526
|
+
const sqliteEntries = await listSqliteLogIndexEntries();
|
|
1527
|
+
if (sqliteEntries !== null) return sqliteEntries;
|
|
1528
|
+
}
|
|
1529
|
+
maybeBackfillSqliteIndex(index, sqliteMaxId);
|
|
989
1530
|
return Object.values(index.entries).sort((left, right) => left.id - right.id);
|
|
990
1531
|
}
|
|
1532
|
+
async function listFilteredIndexEntries({
|
|
1533
|
+
sessionId,
|
|
1534
|
+
model
|
|
1535
|
+
}) {
|
|
1536
|
+
const index = await loadIndex();
|
|
1537
|
+
const sqliteMaxId = await getSqliteLogIndexMaxId();
|
|
1538
|
+
if (sqliteMaxId !== null && sqliteMaxId >= index.maxId) {
|
|
1539
|
+
const sqliteEntries = await listSqliteLogIndexEntries({ sessionId, model });
|
|
1540
|
+
if (sqliteEntries !== null) return sqliteEntries;
|
|
1541
|
+
}
|
|
1542
|
+
maybeBackfillSqliteIndex(index, sqliteMaxId);
|
|
1543
|
+
return Object.values(index.entries).sort((left, right) => left.id - right.id).filter((entry) => {
|
|
1544
|
+
if (sessionId !== void 0 && entry.sessionId !== sessionId) return false;
|
|
1545
|
+
if (model !== void 0 && entry.model !== model) return false;
|
|
1546
|
+
return true;
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
function maybeBackfillSqliteIndex(index, sqliteMaxId) {
|
|
1550
|
+
if (sqliteMaxId === null) return;
|
|
1551
|
+
if (index.maxId <= sqliteMaxId) return;
|
|
1552
|
+
if (index.maxId <= sqliteBackfillScheduledMaxId) return;
|
|
1553
|
+
sqliteBackfillScheduledMaxId = index.maxId;
|
|
1554
|
+
const entries = Object.values(index.entries);
|
|
1555
|
+
void syncSqliteLogIndexEntries(entries).then((ok) => {
|
|
1556
|
+
if (!ok && sqliteMaxId < sqliteBackfillScheduledMaxId) {
|
|
1557
|
+
sqliteBackfillScheduledMaxId = sqliteMaxId;
|
|
1558
|
+
}
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
991
1561
|
function readStringOrNullField(entry, field) {
|
|
992
1562
|
const desc = Object.getOwnPropertyDescriptor(entry, field);
|
|
993
1563
|
if (desc === void 0) return null;
|
|
@@ -1113,6 +1683,7 @@ async function rebuildIndex() {
|
|
|
1113
1683
|
if (!existsSync(logDir)) {
|
|
1114
1684
|
cachedIndex = newIndex;
|
|
1115
1685
|
await saveIndex(newIndex);
|
|
1686
|
+
await replaceSqliteLogIndexEntries([]);
|
|
1116
1687
|
return newIndex;
|
|
1117
1688
|
}
|
|
1118
1689
|
const files = (await readdir(logDir)).filter((f) => f.endsWith(".jsonl")).sort();
|
|
@@ -1127,6 +1698,7 @@ async function rebuildIndex() {
|
|
|
1127
1698
|
}
|
|
1128
1699
|
cachedIndex = newIndex;
|
|
1129
1700
|
await saveIndex(newIndex);
|
|
1701
|
+
await replaceSqliteLogIndexEntries(Object.values(newIndex.entries));
|
|
1130
1702
|
return newIndex;
|
|
1131
1703
|
}
|
|
1132
1704
|
let idGenerationPromise = null;
|
|
@@ -1155,7 +1727,8 @@ async function getNextLogId() {
|
|
|
1155
1727
|
await acquireLock();
|
|
1156
1728
|
try {
|
|
1157
1729
|
const index = await loadIndex();
|
|
1158
|
-
const
|
|
1730
|
+
const sqliteMaxId = await getSqliteLogIndexMaxId();
|
|
1731
|
+
const nextId = Math.max(index.maxId, sqliteMaxId ?? 0) + 1;
|
|
1159
1732
|
index.maxId = nextId;
|
|
1160
1733
|
cachedIndex = index;
|
|
1161
1734
|
return nextId;
|
|
@@ -1624,7 +2197,7 @@ function rememberLogSession(log) {
|
|
|
1624
2197
|
knownLogSessions.set(log.id, sessionId);
|
|
1625
2198
|
return true;
|
|
1626
2199
|
}
|
|
1627
|
-
function isFailedLog(log) {
|
|
2200
|
+
function isFailedLog$1(log) {
|
|
1628
2201
|
const hasError = log.error !== null && log.error !== void 0 && log.error.length > 0;
|
|
1629
2202
|
const hasErrorStatus = log.responseStatus !== null && log.responseStatus >= 400;
|
|
1630
2203
|
return hasError || hasErrorStatus;
|
|
@@ -1648,7 +2221,7 @@ function markSessionFinished(log, sourceOverride) {
|
|
|
1648
2221
|
completedLogIds.add(log.id);
|
|
1649
2222
|
session.completedRequests += 1;
|
|
1650
2223
|
}
|
|
1651
|
-
if (isFailedLog(log) && failedLogIds.has(log.id) === false) {
|
|
2224
|
+
if (isFailedLog$1(log) && failedLogIds.has(log.id) === false) {
|
|
1652
2225
|
failedLogIds.add(log.id);
|
|
1653
2226
|
session.failedRequests += 1;
|
|
1654
2227
|
}
|
|
@@ -1798,8 +2371,8 @@ function compactLogForList(log) {
|
|
|
1798
2371
|
rawHeaders: void 0,
|
|
1799
2372
|
headers: void 0,
|
|
1800
2373
|
streamingChunks: void 0,
|
|
1801
|
-
rawRequestBodyBytes: textByteLength$1(log.rawRequestBody),
|
|
1802
|
-
responseTextBytes: textByteLength$1(log.responseText),
|
|
2374
|
+
rawRequestBodyBytes: log.rawRequestBodyBytes ?? textByteLength$1(log.rawRequestBody),
|
|
2375
|
+
responseTextBytes: log.responseTextBytes ?? textByteLength$1(log.responseText),
|
|
1803
2376
|
bodyContentMode: "compact"
|
|
1804
2377
|
};
|
|
1805
2378
|
}
|
|
@@ -1874,6 +2447,19 @@ async function addTestLogEntry(entry) {
|
|
|
1874
2447
|
emitLogUpdate(log);
|
|
1875
2448
|
return log;
|
|
1876
2449
|
}
|
|
2450
|
+
async function importCapturedLogs(entries, sessionId) {
|
|
2451
|
+
const imported = [];
|
|
2452
|
+
for (const entry of entries) {
|
|
2453
|
+
const log = await addTestLogEntry({
|
|
2454
|
+
...entry,
|
|
2455
|
+
sessionId,
|
|
2456
|
+
isTest: false,
|
|
2457
|
+
replayOfLogId: null
|
|
2458
|
+
});
|
|
2459
|
+
imported.push(log);
|
|
2460
|
+
}
|
|
2461
|
+
return imported;
|
|
2462
|
+
}
|
|
1877
2463
|
async function createLog(method, path2, requestBody, headers, clientInfo, rawHeaders, upstreamHeaders, apiFormat = "unknown", model = null, sessionId = null, preAcquiredId) {
|
|
1878
2464
|
const userAgent = headers.get("user-agent");
|
|
1879
2465
|
const origin = headers.get("origin");
|
|
@@ -2164,10 +2750,10 @@ function matchesLogIndexEntryFilters(entry, sessionId, model) {
|
|
|
2164
2750
|
return true;
|
|
2165
2751
|
}
|
|
2166
2752
|
async function buildLogCursorPageIndexFromLogIndex(options, allowRebuild) {
|
|
2167
|
-
let entries = await
|
|
2753
|
+
let entries = await listFilteredIndexEntries(options);
|
|
2168
2754
|
if (entries.length === 0 && allowRebuild) {
|
|
2169
2755
|
await rebuildIndex();
|
|
2170
|
-
entries = await
|
|
2756
|
+
entries = await listFilteredIndexEntries(options);
|
|
2171
2757
|
}
|
|
2172
2758
|
if (entries.some((entry) => !hasLogIndexFilterMetadata(entry))) {
|
|
2173
2759
|
if (!allowRebuild) return null;
|
|
@@ -2325,7 +2911,7 @@ async function collectSessionLogSummaries(sessionId, includeHistory) {
|
|
|
2325
2911
|
return [...summariesById.values()];
|
|
2326
2912
|
}
|
|
2327
2913
|
async function collectIndexedSessionLogSummaries(sessionId) {
|
|
2328
|
-
let entries = await
|
|
2914
|
+
let entries = await listFilteredIndexEntries({ sessionId });
|
|
2329
2915
|
if (entries.length === 0) return [];
|
|
2330
2916
|
const needsMetadataRebuild = entries.some((entry) => !hasLogIndexFilterMetadata(entry));
|
|
2331
2917
|
const needsSummaryRebuild = entries.some((entry) => {
|
|
@@ -2334,7 +2920,7 @@ async function collectIndexedSessionLogSummaries(sessionId) {
|
|
|
2334
2920
|
});
|
|
2335
2921
|
if (needsMetadataRebuild || needsSummaryRebuild) {
|
|
2336
2922
|
await rebuildIndex();
|
|
2337
|
-
entries = await
|
|
2923
|
+
entries = await listFilteredIndexEntries({ sessionId });
|
|
2338
2924
|
}
|
|
2339
2925
|
const summaries = [];
|
|
2340
2926
|
for (const entry of entries) {
|
|
@@ -2430,6 +3016,7 @@ function clearAllLogs() {
|
|
|
2430
3016
|
memoryCache.clear();
|
|
2431
3017
|
clearLogCursorPageIndexes();
|
|
2432
3018
|
clearSessionRegistry();
|
|
3019
|
+
closeSqliteLogIndex();
|
|
2433
3020
|
return { cleared: count };
|
|
2434
3021
|
}
|
|
2435
3022
|
async function deleteMatchingFiles(dir, shouldDelete) {
|
|
@@ -2460,7 +3047,7 @@ async function clearPersistedLogStorage() {
|
|
|
2460
3047
|
const [logFilesDeleted, chunkFilesDeleted] = await Promise.all([
|
|
2461
3048
|
deleteMatchingFiles(
|
|
2462
3049
|
resolveLogDir(),
|
|
2463
|
-
(fileName) => fileName.endsWith(".jsonl") || fileName === "logs.idx"
|
|
3050
|
+
(fileName) => fileName.endsWith(".jsonl") || fileName === "logs.idx" || fileName === "inspector.sqlite" || fileName.startsWith("inspector.sqlite-")
|
|
2464
3051
|
),
|
|
2465
3052
|
deleteMatchingFiles(
|
|
2466
3053
|
getChunksDir(),
|
|
@@ -4604,7 +5191,7 @@ function firstChunkMsFromChunks(chunks) {
|
|
|
4604
5191
|
if (!Number.isFinite(first.timestamp) || first.timestamp < 0) return null;
|
|
4605
5192
|
return Math.floor(first.timestamp);
|
|
4606
5193
|
}
|
|
4607
|
-
function parseJson(raw) {
|
|
5194
|
+
function parseJson$1(raw) {
|
|
4608
5195
|
if (raw === null) return { ok: false };
|
|
4609
5196
|
try {
|
|
4610
5197
|
return { ok: true, value: JSON.parse(raw) };
|
|
@@ -4963,8 +5550,8 @@ function uniqueWarnings(warnings) {
|
|
|
4963
5550
|
return unique2;
|
|
4964
5551
|
}
|
|
4965
5552
|
function analyzeToolSchemaWarnings(input) {
|
|
4966
|
-
const request = parseJson(input.rawRequestBody);
|
|
4967
|
-
const response = parseJson(input.responseText);
|
|
5553
|
+
const request = parseJson$1(input.rawRequestBody);
|
|
5554
|
+
const response = parseJson$1(input.responseText);
|
|
4968
5555
|
if (!request.ok || !response.ok) return [];
|
|
4969
5556
|
const toolSchemas = extractToolSchemas(request.value, input.apiFormat);
|
|
4970
5557
|
const toolCalls = extractToolCalls(response.value, input.apiFormat);
|
|
@@ -5794,7 +6381,7 @@ async function handleProxy(req) {
|
|
|
5794
6381
|
}
|
|
5795
6382
|
return handleStreamingResponse(upstreamRes, req, startTime, upstreamUrl, log, captureFullDetails);
|
|
5796
6383
|
}
|
|
5797
|
-
const Route$
|
|
6384
|
+
const Route$A = createFileRoute("/proxy/$")({
|
|
5798
6385
|
server: {
|
|
5799
6386
|
handlers: {
|
|
5800
6387
|
GET: ({ request }) => handleProxy(request),
|
|
@@ -5806,7 +6393,7 @@ const Route$w = createFileRoute("/proxy/$")({
|
|
|
5806
6393
|
}
|
|
5807
6394
|
}
|
|
5808
6395
|
});
|
|
5809
|
-
function parsePositiveInt$
|
|
6396
|
+
function parsePositiveInt$4(value) {
|
|
5810
6397
|
if (value === null) return void 0;
|
|
5811
6398
|
const parsed = Number(value);
|
|
5812
6399
|
if (!Number.isInteger(parsed) || parsed < 1) return void 0;
|
|
@@ -5815,7 +6402,7 @@ function parsePositiveInt$2(value) {
|
|
|
5815
6402
|
function parseBooleanFlag(value) {
|
|
5816
6403
|
return value === "1" || value === "true";
|
|
5817
6404
|
}
|
|
5818
|
-
const Route$
|
|
6405
|
+
const Route$z = createFileRoute("/api/sessions")({
|
|
5819
6406
|
server: {
|
|
5820
6407
|
handlers: {
|
|
5821
6408
|
GET: async ({ request }) => {
|
|
@@ -5828,7 +6415,7 @@ const Route$v = createFileRoute("/api/sessions")({
|
|
|
5828
6415
|
const info = await getSessionInfo(sessionId, {
|
|
5829
6416
|
baseUrl: url.origin,
|
|
5830
6417
|
includeHistory: parseBooleanFlag(url.searchParams.get("includeHistory")),
|
|
5831
|
-
latestLogLimit: parsePositiveInt$
|
|
6418
|
+
latestLogLimit: parsePositiveInt$4(url.searchParams.get("limit"))
|
|
5832
6419
|
});
|
|
5833
6420
|
if (info === null) {
|
|
5834
6421
|
return Response.json({ error: "Session not found" }, { status: 404 });
|
|
@@ -7246,19 +7833,19 @@ async function readJsonBody$6(request) {
|
|
|
7246
7833
|
return { ok: false };
|
|
7247
7834
|
}
|
|
7248
7835
|
}
|
|
7249
|
-
function parsePositiveInt$
|
|
7836
|
+
function parsePositiveInt$3(value, fallback) {
|
|
7250
7837
|
if (value === null) return fallback;
|
|
7251
7838
|
const parsed = Number(value);
|
|
7252
7839
|
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
7253
7840
|
return parsed;
|
|
7254
7841
|
}
|
|
7255
|
-
const Route$
|
|
7842
|
+
const Route$y = createFileRoute("/api/runs")({
|
|
7256
7843
|
server: {
|
|
7257
7844
|
handlers: {
|
|
7258
7845
|
GET: ({ request }) => {
|
|
7259
7846
|
const url = new URL(request.url);
|
|
7260
7847
|
if (url.searchParams.get("failures") === "1") {
|
|
7261
|
-
const limit = parsePositiveInt$
|
|
7848
|
+
const limit = parsePositiveInt$3(
|
|
7262
7849
|
url.searchParams.get("limit"),
|
|
7263
7850
|
RECENT_FAILURES_DEFAULT_LIMIT
|
|
7264
7851
|
);
|
|
@@ -7297,7 +7884,7 @@ const ProviderInputSchema = object({
|
|
|
7297
7884
|
modelMetadata: array(ProviderModelMetadataSchema).optional(),
|
|
7298
7885
|
source: _enum(["company", "personal"]).optional()
|
|
7299
7886
|
});
|
|
7300
|
-
const Route$
|
|
7887
|
+
const Route$x = createFileRoute("/api/providers")({
|
|
7301
7888
|
server: {
|
|
7302
7889
|
handlers: {
|
|
7303
7890
|
GET: ({ request }) => {
|
|
@@ -7331,14 +7918,14 @@ const Route$t = createFileRoute("/api/providers")({
|
|
|
7331
7918
|
}
|
|
7332
7919
|
}
|
|
7333
7920
|
});
|
|
7334
|
-
const Route$
|
|
7921
|
+
const Route$w = createFileRoute("/api/models")({
|
|
7335
7922
|
server: {
|
|
7336
7923
|
handlers: {
|
|
7337
7924
|
GET: () => Response.json(getModels())
|
|
7338
7925
|
}
|
|
7339
7926
|
}
|
|
7340
7927
|
});
|
|
7341
|
-
const version = "2.1.
|
|
7928
|
+
const version = "2.1.4";
|
|
7342
7929
|
const packageJson = {
|
|
7343
7930
|
version
|
|
7344
7931
|
};
|
|
@@ -7483,7 +8070,7 @@ function isCompletedMember(member) {
|
|
|
7483
8070
|
const status = memberEffectiveStatus(member);
|
|
7484
8071
|
return status === "completed";
|
|
7485
8072
|
}
|
|
7486
|
-
function isFailedMember(member) {
|
|
8073
|
+
function isFailedMember$1(member) {
|
|
7487
8074
|
const status = memberEffectiveStatus(member);
|
|
7488
8075
|
return status === "failed" || status === "cancelled";
|
|
7489
8076
|
}
|
|
@@ -7527,7 +8114,7 @@ function buildSummary(members) {
|
|
|
7527
8114
|
members.flatMap((member) => [member.member.provider, ...member.session?.providers ?? []])
|
|
7528
8115
|
),
|
|
7529
8116
|
completedMembers: members.filter(isCompletedMember).length,
|
|
7530
|
-
failedMembers: members.filter(isFailedMember).length,
|
|
8117
|
+
failedMembers: members.filter(isFailedMember$1).length,
|
|
7531
8118
|
runningMembers: members.filter(isRunningMember).length
|
|
7532
8119
|
};
|
|
7533
8120
|
}
|
|
@@ -9839,7 +10426,7 @@ const PROMPT_NAMES = [
|
|
|
9839
10426
|
"inspector_generate_group_report",
|
|
9840
10427
|
"inspector_extract_repro_steps"
|
|
9841
10428
|
];
|
|
9842
|
-
const Route$
|
|
10429
|
+
const Route$v = createFileRoute("/api/mcp")({
|
|
9843
10430
|
server: {
|
|
9844
10431
|
handlers: {
|
|
9845
10432
|
// The SDK may issue either POST, GET, or DELETE. TanStack Start only
|
|
@@ -9855,15 +10442,15 @@ const LOG_SEARCH_DEFAULT_LIMIT = 10;
|
|
|
9855
10442
|
const LOG_SEARCH_MAX_LIMIT = 50;
|
|
9856
10443
|
const LOG_SEARCH_DEFAULT_SCAN_LIMIT = 200;
|
|
9857
10444
|
const LOG_SEARCH_MAX_SCAN_LIMIT = 1e3;
|
|
9858
|
-
function clampPositiveInt(value, fallback, max) {
|
|
10445
|
+
function clampPositiveInt$1(value, fallback, max) {
|
|
9859
10446
|
if (!Number.isInteger(value) || value < 1) return fallback;
|
|
9860
10447
|
return Math.min(value, max);
|
|
9861
10448
|
}
|
|
9862
10449
|
function clampLogSearchLimit(value) {
|
|
9863
|
-
return clampPositiveInt(value, LOG_SEARCH_DEFAULT_LIMIT, LOG_SEARCH_MAX_LIMIT);
|
|
10450
|
+
return clampPositiveInt$1(value, LOG_SEARCH_DEFAULT_LIMIT, LOG_SEARCH_MAX_LIMIT);
|
|
9864
10451
|
}
|
|
9865
10452
|
function clampLogSearchScanLimit(value) {
|
|
9866
|
-
return clampPositiveInt(value, LOG_SEARCH_DEFAULT_SCAN_LIMIT, LOG_SEARCH_MAX_SCAN_LIMIT);
|
|
10453
|
+
return clampPositiveInt$1(value, LOG_SEARCH_DEFAULT_SCAN_LIMIT, LOG_SEARCH_MAX_SCAN_LIMIT);
|
|
9867
10454
|
}
|
|
9868
10455
|
function queryTerms(query) {
|
|
9869
10456
|
return query.trim().toLowerCase().split(/\s+/).filter((term) => term.length > 0);
|
|
@@ -9944,7 +10531,7 @@ function parseNonNegativeInt(value, fallback) {
|
|
|
9944
10531
|
if (!Number.isInteger(parsed) || parsed < 0) return fallback;
|
|
9945
10532
|
return parsed;
|
|
9946
10533
|
}
|
|
9947
|
-
function parsePositiveInt(value, fallback) {
|
|
10534
|
+
function parsePositiveInt$2(value, fallback) {
|
|
9948
10535
|
if (value === null) return fallback;
|
|
9949
10536
|
const parsed = Number(value);
|
|
9950
10537
|
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
@@ -9956,7 +10543,7 @@ function parseOptionalPositiveInt(value) {
|
|
|
9956
10543
|
if (!Number.isInteger(parsed) || parsed < 1) return { ok: false };
|
|
9957
10544
|
return { ok: true, value: parsed };
|
|
9958
10545
|
}
|
|
9959
|
-
const Route$
|
|
10546
|
+
const Route$u = createFileRoute("/api/logs")({
|
|
9960
10547
|
server: {
|
|
9961
10548
|
handlers: {
|
|
9962
10549
|
GET: async ({ request }) => {
|
|
@@ -9978,8 +10565,8 @@ const Route$q = createFileRoute("/api/logs")({
|
|
|
9978
10565
|
const query = url.searchParams.get("q") ?? url.searchParams.get("search");
|
|
9979
10566
|
const offset = parseNonNegativeInt(url.searchParams.get("offset"), 0);
|
|
9980
10567
|
if (query !== null) {
|
|
9981
|
-
const limit2 = parsePositiveInt(url.searchParams.get("limit"), LOG_SEARCH_DEFAULT_LIMIT);
|
|
9982
|
-
const scanLimit = parsePositiveInt(
|
|
10568
|
+
const limit2 = parsePositiveInt$2(url.searchParams.get("limit"), LOG_SEARCH_DEFAULT_LIMIT);
|
|
10569
|
+
const scanLimit = parsePositiveInt$2(
|
|
9983
10570
|
url.searchParams.get("scanLimit"),
|
|
9984
10571
|
LOG_SEARCH_DEFAULT_SCAN_LIMIT
|
|
9985
10572
|
);
|
|
@@ -9987,7 +10574,7 @@ const Route$q = createFileRoute("/api/logs")({
|
|
|
9987
10574
|
await searchLogsPage({ query, sessionId, model, offset, limit: limit2, scanLimit })
|
|
9988
10575
|
);
|
|
9989
10576
|
}
|
|
9990
|
-
const limit = parsePositiveInt(url.searchParams.get("limit"), 50);
|
|
10577
|
+
const limit = parsePositiveInt$2(url.searchParams.get("limit"), 50);
|
|
9991
10578
|
const includeBodies = url.searchParams.get("compact") !== "1";
|
|
9992
10579
|
if (url.searchParams.get("cursor") === "1" || url.searchParams.get("cursor") === "true") {
|
|
9993
10580
|
const beforeLogId = parseOptionalPositiveInt(url.searchParams.get("beforeLogId"));
|
|
@@ -10057,7 +10644,7 @@ const Route$q = createFileRoute("/api/logs")({
|
|
|
10057
10644
|
}
|
|
10058
10645
|
});
|
|
10059
10646
|
logger.debug("Health endpoint loaded");
|
|
10060
|
-
const Route$
|
|
10647
|
+
const Route$t = createFileRoute("/api/health")({
|
|
10061
10648
|
server: {
|
|
10062
10649
|
handlers: {
|
|
10063
10650
|
GET: () => {
|
|
@@ -10075,7 +10662,7 @@ async function readJsonBody$5(request) {
|
|
|
10075
10662
|
return { ok: false };
|
|
10076
10663
|
}
|
|
10077
10664
|
}
|
|
10078
|
-
const Route$
|
|
10665
|
+
const Route$s = createFileRoute("/api/groups")({
|
|
10079
10666
|
server: {
|
|
10080
10667
|
handlers: {
|
|
10081
10668
|
GET: () => Response.json(listInspectorGroups()),
|
|
@@ -10105,7 +10692,7 @@ const RuntimeConfigPatchSchema = object({
|
|
|
10105
10692
|
}).strict().refine((v) => Object.keys(v).length > 0, {
|
|
10106
10693
|
message: "At least one field must be provided"
|
|
10107
10694
|
});
|
|
10108
|
-
const Route$
|
|
10695
|
+
const Route$r = createFileRoute("/api/config")({
|
|
10109
10696
|
server: {
|
|
10110
10697
|
handlers: {
|
|
10111
10698
|
GET: () => {
|
|
@@ -10134,107 +10721,703 @@ const Route$n = createFileRoute("/api/config")({
|
|
|
10134
10721
|
}
|
|
10135
10722
|
}
|
|
10136
10723
|
});
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
PATCH: async ({ params, request }) => {
|
|
10157
|
-
const body = await readJsonBody$4(request);
|
|
10158
|
-
if (!body.ok) {
|
|
10159
|
-
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
10160
|
-
}
|
|
10161
|
-
const parsed = UpdateInspectorRunInputSchema.safeParse(body.value);
|
|
10162
|
-
if (!parsed.success) {
|
|
10163
|
-
return Response.json(
|
|
10164
|
-
{ error: "Invalid request body", details: parsed.error.format() },
|
|
10165
|
-
{ status: 400 }
|
|
10166
|
-
);
|
|
10167
|
-
}
|
|
10168
|
-
const updated = updateInspectorRun(params.runId, parsed.data);
|
|
10169
|
-
if (!updated.ok) {
|
|
10170
|
-
return Response.json({ error: updated.message }, { status: updated.status });
|
|
10171
|
-
}
|
|
10172
|
-
return Response.json(updated.value);
|
|
10173
|
-
}
|
|
10174
|
-
}
|
|
10175
|
-
}
|
|
10724
|
+
const AlertSeveritySchema = _enum(["critical", "warning", "notice"]);
|
|
10725
|
+
const AlertStatusSchema = _enum(["open"]);
|
|
10726
|
+
const AlertSourceSchema = _enum(["proxy", "tool-schema", "run", "group"]);
|
|
10727
|
+
const AlertCategorySchema = _enum([
|
|
10728
|
+
"request-failure",
|
|
10729
|
+
"request-timeout",
|
|
10730
|
+
"slow-response",
|
|
10731
|
+
"tool-schema",
|
|
10732
|
+
"run-failure",
|
|
10733
|
+
"group-failure",
|
|
10734
|
+
"group-incomplete"
|
|
10735
|
+
]);
|
|
10736
|
+
const AlertEvidenceKindSchema = _enum(["log", "session", "run", "group"]);
|
|
10737
|
+
const AlertApiFormatSchema = _enum(["anthropic", "openai", "unknown"]);
|
|
10738
|
+
const AlertEvidenceLinkSchema = object({
|
|
10739
|
+
kind: AlertEvidenceKindSchema,
|
|
10740
|
+
id: string(),
|
|
10741
|
+
label: string(),
|
|
10742
|
+
href: string().nullable()
|
|
10176
10743
|
});
|
|
10177
|
-
const
|
|
10178
|
-
|
|
10179
|
-
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
|
|
10187
|
-
|
|
10744
|
+
const AlertSchema = object({
|
|
10745
|
+
id: string(),
|
|
10746
|
+
fingerprint: string(),
|
|
10747
|
+
severity: AlertSeveritySchema,
|
|
10748
|
+
category: AlertCategorySchema,
|
|
10749
|
+
source: AlertSourceSchema,
|
|
10750
|
+
status: AlertStatusSchema,
|
|
10751
|
+
title: string(),
|
|
10752
|
+
message: string(),
|
|
10753
|
+
count: number().int().positive(),
|
|
10754
|
+
firstSeenAt: string(),
|
|
10755
|
+
lastSeenAt: string(),
|
|
10756
|
+
logIds: array(number().int().positive()),
|
|
10757
|
+
sessionIds: array(string()),
|
|
10758
|
+
runIds: array(string()),
|
|
10759
|
+
groupIds: array(string()),
|
|
10760
|
+
provider: string().nullable(),
|
|
10761
|
+
model: string().nullable(),
|
|
10762
|
+
apiFormat: AlertApiFormatSchema.nullable(),
|
|
10763
|
+
evidence: array(AlertEvidenceLinkSchema),
|
|
10764
|
+
metadata: record(string(), JsonValueSchema)
|
|
10765
|
+
});
|
|
10766
|
+
const AlertCategoryCountSchema = object({
|
|
10767
|
+
category: AlertCategorySchema,
|
|
10768
|
+
count: number().int().nonnegative()
|
|
10769
|
+
});
|
|
10770
|
+
const AlertSummarySchema = object({
|
|
10771
|
+
total: number().int().nonnegative(),
|
|
10772
|
+
open: number().int().nonnegative(),
|
|
10773
|
+
critical: number().int().nonnegative(),
|
|
10774
|
+
warning: number().int().nonnegative(),
|
|
10775
|
+
notice: number().int().nonnegative(),
|
|
10776
|
+
byCategory: array(AlertCategoryCountSchema)
|
|
10777
|
+
});
|
|
10778
|
+
const AlertListResponseSchema = object({
|
|
10779
|
+
alerts: array(AlertSchema),
|
|
10780
|
+
total: number().int().nonnegative(),
|
|
10781
|
+
limit: number().int().positive(),
|
|
10782
|
+
summary: AlertSummarySchema
|
|
10783
|
+
});
|
|
10784
|
+
const DEFAULT_ALERT_LIMIT = 50;
|
|
10785
|
+
const MAX_ALERT_LIMIT = 200;
|
|
10786
|
+
const DEFAULT_ALERT_SCAN_LIMIT = 500;
|
|
10787
|
+
const MAX_ALERT_SCAN_LIMIT = 2e3;
|
|
10788
|
+
function clampPositiveInt(value, fallback, max) {
|
|
10789
|
+
if (value === void 0) return fallback;
|
|
10790
|
+
if (!Number.isInteger(value) || value < 1) return fallback;
|
|
10791
|
+
return Math.min(value, max);
|
|
10792
|
+
}
|
|
10793
|
+
function clampAlertLimit(value) {
|
|
10794
|
+
return clampPositiveInt(value, DEFAULT_ALERT_LIMIT, MAX_ALERT_LIMIT);
|
|
10795
|
+
}
|
|
10796
|
+
function clampAlertScanLimit(value) {
|
|
10797
|
+
return clampPositiveInt(value, DEFAULT_ALERT_SCAN_LIMIT, MAX_ALERT_SCAN_LIMIT);
|
|
10798
|
+
}
|
|
10799
|
+
function alertIdFor(value) {
|
|
10800
|
+
const digest = createHash("sha1").update(value).digest("hex").slice(0, 16);
|
|
10801
|
+
return `alert_${digest}`;
|
|
10802
|
+
}
|
|
10803
|
+
function sanitizeFingerprintPart(value) {
|
|
10804
|
+
if (value === null) return "-";
|
|
10805
|
+
return String(value).trim().toLowerCase().replace(/\s+/g, " ").slice(0, 240);
|
|
10806
|
+
}
|
|
10807
|
+
function fingerprint(parts) {
|
|
10808
|
+
return parts.map(sanitizeFingerprintPart).join("|");
|
|
10809
|
+
}
|
|
10810
|
+
function uniqueStrings$1(values) {
|
|
10811
|
+
return [...new Set(values)].sort();
|
|
10812
|
+
}
|
|
10813
|
+
function uniqueNumbers(values) {
|
|
10814
|
+
return [...new Set(values)].sort((left, right) => left - right);
|
|
10815
|
+
}
|
|
10816
|
+
function logEvidence(logId) {
|
|
10817
|
+
const id = String(logId);
|
|
10818
|
+
return { kind: "log", id, label: `Log #${id}`, href: `#log-${id}` };
|
|
10819
|
+
}
|
|
10820
|
+
function sessionEvidence(sessionId) {
|
|
10821
|
+
return {
|
|
10822
|
+
kind: "session",
|
|
10823
|
+
id: sessionId,
|
|
10824
|
+
label: `Session ${sessionId}`,
|
|
10825
|
+
href: getSessionPath(sessionId)
|
|
10826
|
+
};
|
|
10827
|
+
}
|
|
10828
|
+
function runEvidence(runId) {
|
|
10829
|
+
return { kind: "run", id: runId, label: `Run ${runId}`, href: null };
|
|
10830
|
+
}
|
|
10831
|
+
function groupEvidence(groupId) {
|
|
10832
|
+
return { kind: "group", id: groupId, label: `Group ${groupId}`, href: null };
|
|
10833
|
+
}
|
|
10834
|
+
function baseEvidence(logId, sessionId, runId, groupId) {
|
|
10835
|
+
const links = [];
|
|
10836
|
+
if (logId !== null) links.push(logEvidence(logId));
|
|
10837
|
+
if (sessionId !== null) links.push(sessionEvidence(sessionId));
|
|
10838
|
+
if (runId !== null) links.push(runEvidence(runId));
|
|
10839
|
+
if (groupId !== null) links.push(groupEvidence(groupId));
|
|
10840
|
+
return links;
|
|
10841
|
+
}
|
|
10842
|
+
function hasEquivalentEvidence(links, candidate) {
|
|
10843
|
+
return links.some((link) => link.kind === candidate.kind && link.id === candidate.id);
|
|
10844
|
+
}
|
|
10845
|
+
function mergeEvidence(left, right) {
|
|
10846
|
+
const merged = [...left];
|
|
10847
|
+
for (const link of right) {
|
|
10848
|
+
if (!hasEquivalentEvidence(merged, link)) merged.push(link);
|
|
10188
10849
|
}
|
|
10850
|
+
return merged;
|
|
10189
10851
|
}
|
|
10190
|
-
function
|
|
10191
|
-
|
|
10192
|
-
const val = envObj[key];
|
|
10193
|
-
return typeof val === "string" ? val.trim() : void 0;
|
|
10852
|
+
function firstString(left, right) {
|
|
10853
|
+
return left ?? right;
|
|
10194
10854
|
}
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10202
|
-
|
|
10203
|
-
|
|
10204
|
-
|
|
10205
|
-
|
|
10206
|
-
|
|
10207
|
-
|
|
10208
|
-
|
|
10209
|
-
|
|
10210
|
-
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10855
|
+
function mergeAlert(existing, observation) {
|
|
10856
|
+
const logIds = observation.logId === null ? existing.logIds : [...existing.logIds, observation.logId];
|
|
10857
|
+
const sessionIds = observation.sessionId === null ? existing.sessionIds : [...existing.sessionIds, observation.sessionId];
|
|
10858
|
+
const runIds = observation.runId === null ? existing.runIds : [...existing.runIds, observation.runId];
|
|
10859
|
+
const groupIds = observation.groupId === null ? existing.groupIds : [...existing.groupIds, observation.groupId];
|
|
10860
|
+
return {
|
|
10861
|
+
...existing,
|
|
10862
|
+
count: existing.count + 1,
|
|
10863
|
+
firstSeenAt: observation.observedAt < existing.firstSeenAt ? observation.observedAt : existing.firstSeenAt,
|
|
10864
|
+
lastSeenAt: observation.observedAt > existing.lastSeenAt ? observation.observedAt : existing.lastSeenAt,
|
|
10865
|
+
logIds: uniqueNumbers(logIds),
|
|
10866
|
+
sessionIds: uniqueStrings$1(sessionIds),
|
|
10867
|
+
runIds: uniqueStrings$1(runIds),
|
|
10868
|
+
groupIds: uniqueStrings$1(groupIds),
|
|
10869
|
+
provider: firstString(existing.provider, observation.provider),
|
|
10870
|
+
model: firstString(existing.model, observation.model),
|
|
10871
|
+
apiFormat: existing.apiFormat ?? observation.apiFormat,
|
|
10872
|
+
evidence: mergeEvidence(existing.evidence, observation.evidence),
|
|
10873
|
+
metadata: { ...existing.metadata, ...observation.metadata }
|
|
10874
|
+
};
|
|
10875
|
+
}
|
|
10876
|
+
function observationToAlert(observation) {
|
|
10877
|
+
return {
|
|
10878
|
+
id: alertIdFor(observation.fingerprint),
|
|
10879
|
+
fingerprint: observation.fingerprint,
|
|
10880
|
+
severity: observation.severity,
|
|
10881
|
+
category: observation.category,
|
|
10882
|
+
source: observation.source,
|
|
10883
|
+
status: "open",
|
|
10884
|
+
title: observation.title,
|
|
10885
|
+
message: observation.message,
|
|
10886
|
+
count: 1,
|
|
10887
|
+
firstSeenAt: observation.observedAt,
|
|
10888
|
+
lastSeenAt: observation.observedAt,
|
|
10889
|
+
logIds: observation.logId === null ? [] : [observation.logId],
|
|
10890
|
+
sessionIds: observation.sessionId === null ? [] : [observation.sessionId],
|
|
10891
|
+
runIds: observation.runId === null ? [] : [observation.runId],
|
|
10892
|
+
groupIds: observation.groupId === null ? [] : [observation.groupId],
|
|
10893
|
+
provider: observation.provider,
|
|
10894
|
+
model: observation.model,
|
|
10895
|
+
apiFormat: observation.apiFormat,
|
|
10896
|
+
evidence: observation.evidence,
|
|
10897
|
+
metadata: observation.metadata
|
|
10898
|
+
};
|
|
10899
|
+
}
|
|
10900
|
+
function addObservation(map, observation) {
|
|
10901
|
+
const existing = map.get(observation.fingerprint);
|
|
10902
|
+
if (existing === void 0) {
|
|
10903
|
+
map.set(observation.fingerprint, observationToAlert(observation));
|
|
10904
|
+
return;
|
|
10231
10905
|
}
|
|
10906
|
+
map.set(observation.fingerprint, mergeAlert(existing, observation));
|
|
10232
10907
|
}
|
|
10233
|
-
function
|
|
10234
|
-
|
|
10235
|
-
|
|
10236
|
-
|
|
10237
|
-
|
|
10908
|
+
function lowerText(value) {
|
|
10909
|
+
if (value === null || value === void 0) return "";
|
|
10910
|
+
return value.toLowerCase();
|
|
10911
|
+
}
|
|
10912
|
+
function isTimeoutStatus(status) {
|
|
10913
|
+
return status === 408 || status === 504;
|
|
10914
|
+
}
|
|
10915
|
+
function isTimeoutLog(log) {
|
|
10916
|
+
const text = `${lowerText(log.error)} ${lowerText(log.responseText)}`;
|
|
10917
|
+
return isTimeoutStatus(log.responseStatus) || text.includes("timeout") || text.includes("timed out") || text.includes("abort");
|
|
10918
|
+
}
|
|
10919
|
+
function hasFailureStatus(status) {
|
|
10920
|
+
return status !== null && status >= 400;
|
|
10921
|
+
}
|
|
10922
|
+
function isFailedLog(log) {
|
|
10923
|
+
return log.error !== null && log.error !== void 0 && log.error.length > 0 ? true : hasFailureStatus(log.responseStatus);
|
|
10924
|
+
}
|
|
10925
|
+
function statusLabel(status) {
|
|
10926
|
+
return status === null ? "no status" : `HTTP ${String(status)}`;
|
|
10927
|
+
}
|
|
10928
|
+
function errorDetail(log) {
|
|
10929
|
+
if (log.error !== null && log.error !== void 0 && log.error.length > 0) return log.error;
|
|
10930
|
+
return statusLabel(log.responseStatus);
|
|
10931
|
+
}
|
|
10932
|
+
function requestFailureTitle(log, timeout) {
|
|
10933
|
+
if (log.isTest === true && timeout) return "Provider test timed out";
|
|
10934
|
+
if (log.isTest === true) return "Provider test failed";
|
|
10935
|
+
return timeout ? "Request timed out" : "Request failed";
|
|
10936
|
+
}
|
|
10937
|
+
function requestFailureCategory(timeout) {
|
|
10938
|
+
return timeout ? "request-timeout" : "request-failure";
|
|
10939
|
+
}
|
|
10940
|
+
function logProvider(log) {
|
|
10941
|
+
return log.providerName ?? null;
|
|
10942
|
+
}
|
|
10943
|
+
function requestFailureObservation(log) {
|
|
10944
|
+
if (!isFailedLog(log)) return null;
|
|
10945
|
+
const timeout = isTimeoutLog(log);
|
|
10946
|
+
const category = requestFailureCategory(timeout);
|
|
10947
|
+
const message = `${errorDetail(log)} while calling ${log.path}.`;
|
|
10948
|
+
return {
|
|
10949
|
+
fingerprint: fingerprint([
|
|
10950
|
+
"proxy",
|
|
10951
|
+
category,
|
|
10952
|
+
logProvider(log),
|
|
10953
|
+
log.model,
|
|
10954
|
+
log.responseStatus,
|
|
10955
|
+
errorDetail(log)
|
|
10956
|
+
]),
|
|
10957
|
+
severity: "critical",
|
|
10958
|
+
category,
|
|
10959
|
+
source: "proxy",
|
|
10960
|
+
title: requestFailureTitle(log, timeout),
|
|
10961
|
+
message,
|
|
10962
|
+
observedAt: log.timestamp,
|
|
10963
|
+
logId: log.id,
|
|
10964
|
+
sessionId: log.sessionId,
|
|
10965
|
+
runId: null,
|
|
10966
|
+
groupId: null,
|
|
10967
|
+
provider: logProvider(log),
|
|
10968
|
+
model: log.model,
|
|
10969
|
+
apiFormat: log.apiFormat,
|
|
10970
|
+
evidence: baseEvidence(log.id, log.sessionId, null, null),
|
|
10971
|
+
metadata: {
|
|
10972
|
+
path: log.path,
|
|
10973
|
+
status: log.responseStatus,
|
|
10974
|
+
error: log.error ?? null,
|
|
10975
|
+
isTest: log.isTest,
|
|
10976
|
+
streaming: log.streaming
|
|
10977
|
+
}
|
|
10978
|
+
};
|
|
10979
|
+
}
|
|
10980
|
+
function slowResponseObservation(log, slowResponseThresholdSeconds) {
|
|
10981
|
+
if (slowResponseThresholdSeconds <= 0) return null;
|
|
10982
|
+
if (isFailedLog(log)) return null;
|
|
10983
|
+
if (log.elapsedMs === null) return null;
|
|
10984
|
+
const thresholdMs = slowResponseThresholdSeconds * 1e3;
|
|
10985
|
+
if (log.elapsedMs < thresholdMs) return null;
|
|
10986
|
+
const elapsedSeconds = (log.elapsedMs / 1e3).toFixed(1);
|
|
10987
|
+
return {
|
|
10988
|
+
fingerprint: fingerprint(["proxy", "slow-response", logProvider(log), log.model, log.path]),
|
|
10989
|
+
severity: "warning",
|
|
10990
|
+
category: "slow-response",
|
|
10991
|
+
source: "proxy",
|
|
10992
|
+
title: "Slow model response",
|
|
10993
|
+
message: `Response took ${elapsedSeconds}s, above the ${String(
|
|
10994
|
+
slowResponseThresholdSeconds
|
|
10995
|
+
)}s threshold.`,
|
|
10996
|
+
observedAt: log.timestamp,
|
|
10997
|
+
logId: log.id,
|
|
10998
|
+
sessionId: log.sessionId,
|
|
10999
|
+
runId: null,
|
|
11000
|
+
groupId: null,
|
|
11001
|
+
provider: logProvider(log),
|
|
11002
|
+
model: log.model,
|
|
11003
|
+
apiFormat: log.apiFormat,
|
|
11004
|
+
evidence: baseEvidence(log.id, log.sessionId, null, null),
|
|
11005
|
+
metadata: {
|
|
11006
|
+
path: log.path,
|
|
11007
|
+
elapsedMs: log.elapsedMs,
|
|
11008
|
+
thresholdMs,
|
|
11009
|
+
streaming: log.streaming,
|
|
11010
|
+
firstChunkMs: log.firstChunkMs ?? null,
|
|
11011
|
+
totalStreamMs: log.totalStreamMs ?? null
|
|
11012
|
+
}
|
|
11013
|
+
};
|
|
11014
|
+
}
|
|
11015
|
+
function warningObservation(log, warning) {
|
|
11016
|
+
return {
|
|
11017
|
+
fingerprint: fingerprint(["tool-schema", logProvider(log), log.model, warning]),
|
|
11018
|
+
severity: "warning",
|
|
11019
|
+
category: "tool-schema",
|
|
11020
|
+
source: "tool-schema",
|
|
11021
|
+
title: "Tool calling argument warning",
|
|
11022
|
+
message: warning,
|
|
11023
|
+
observedAt: log.timestamp,
|
|
11024
|
+
logId: log.id,
|
|
11025
|
+
sessionId: log.sessionId,
|
|
11026
|
+
runId: null,
|
|
11027
|
+
groupId: null,
|
|
11028
|
+
provider: logProvider(log),
|
|
11029
|
+
model: log.model,
|
|
11030
|
+
apiFormat: log.apiFormat,
|
|
11031
|
+
evidence: baseEvidence(log.id, log.sessionId, null, null),
|
|
11032
|
+
metadata: {
|
|
11033
|
+
path: log.path,
|
|
11034
|
+
warning
|
|
11035
|
+
}
|
|
11036
|
+
};
|
|
11037
|
+
}
|
|
11038
|
+
function addLogObservations(map, logs, slowResponseThresholdSeconds) {
|
|
11039
|
+
for (const log of logs) {
|
|
11040
|
+
const failure = requestFailureObservation(log);
|
|
11041
|
+
if (failure !== null) addObservation(map, failure);
|
|
11042
|
+
const slow = slowResponseObservation(log, slowResponseThresholdSeconds);
|
|
11043
|
+
if (slow !== null) addObservation(map, slow);
|
|
11044
|
+
for (const warning of log.warnings ?? []) {
|
|
11045
|
+
addObservation(map, warningObservation(log, warning));
|
|
11046
|
+
}
|
|
11047
|
+
}
|
|
11048
|
+
}
|
|
11049
|
+
function alertSeverityFromFailure(failure) {
|
|
11050
|
+
switch (failure.classification.severity) {
|
|
11051
|
+
case "high":
|
|
11052
|
+
return "critical";
|
|
11053
|
+
case "medium":
|
|
11054
|
+
case "low":
|
|
11055
|
+
return "warning";
|
|
11056
|
+
case "none":
|
|
11057
|
+
return "notice";
|
|
11058
|
+
}
|
|
11059
|
+
}
|
|
11060
|
+
function providerFromRun(failure) {
|
|
11061
|
+
const provider = failure.run.metadata["provider"] ?? failure.run.metadata["providerName"];
|
|
11062
|
+
return typeof provider === "string" && provider.length > 0 ? provider : null;
|
|
11063
|
+
}
|
|
11064
|
+
function modelFromRun(failure) {
|
|
11065
|
+
const model = failure.run.metadata["model"] ?? failure.run.metadata["modelName"];
|
|
11066
|
+
return typeof model === "string" && model.length > 0 ? model : null;
|
|
11067
|
+
}
|
|
11068
|
+
function runFailureObservation(failure) {
|
|
11069
|
+
const groupId = failure.run.groupId;
|
|
11070
|
+
const logEvidenceLinks = failure.classification.evidenceLogIds.map(logEvidence);
|
|
11071
|
+
const links = mergeEvidence(
|
|
11072
|
+
baseEvidence(null, failure.sessionId, failure.run.id, groupId),
|
|
11073
|
+
logEvidenceLinks
|
|
11074
|
+
);
|
|
11075
|
+
return {
|
|
11076
|
+
fingerprint: fingerprint(["run", failure.run.id, failure.classification.category]),
|
|
11077
|
+
severity: alertSeverityFromFailure(failure),
|
|
11078
|
+
category: "run-failure",
|
|
11079
|
+
source: "run",
|
|
11080
|
+
title: `Run ${failure.run.status}`,
|
|
11081
|
+
message: failure.classification.summary,
|
|
11082
|
+
observedAt: failure.updatedAt,
|
|
11083
|
+
logId: failure.classification.evidenceLogIds[0] ?? null,
|
|
11084
|
+
sessionId: failure.sessionId,
|
|
11085
|
+
runId: failure.run.id,
|
|
11086
|
+
groupId,
|
|
11087
|
+
provider: providerFromRun(failure),
|
|
11088
|
+
model: modelFromRun(failure),
|
|
11089
|
+
apiFormat: null,
|
|
11090
|
+
evidence: links,
|
|
11091
|
+
metadata: {
|
|
11092
|
+
runStatus: failure.run.status,
|
|
11093
|
+
failureCategory: failure.classification.category,
|
|
11094
|
+
evidenceMarkdownPath: failure.evidenceMarkdownPath
|
|
11095
|
+
}
|
|
11096
|
+
};
|
|
11097
|
+
}
|
|
11098
|
+
function addRunFailureObservations(map, recentFailures) {
|
|
11099
|
+
for (const failure of recentFailures) {
|
|
11100
|
+
addObservation(map, runFailureObservation(failure));
|
|
11101
|
+
}
|
|
11102
|
+
}
|
|
11103
|
+
function memberProvider(member) {
|
|
11104
|
+
return member.provider !== null && member.provider.length > 0 ? member.provider : null;
|
|
11105
|
+
}
|
|
11106
|
+
function memberModel(member) {
|
|
11107
|
+
return member.model !== null && member.model.length > 0 ? member.model : null;
|
|
11108
|
+
}
|
|
11109
|
+
function isFailedMember(member) {
|
|
11110
|
+
return member.status === "failed" || member.status === "cancelled";
|
|
11111
|
+
}
|
|
11112
|
+
function groupFailureObservation(group) {
|
|
11113
|
+
if (group.status !== "failed" && group.status !== "cancelled") return null;
|
|
11114
|
+
return {
|
|
11115
|
+
fingerprint: fingerprint(["group", group.id, group.status]),
|
|
11116
|
+
severity: "critical",
|
|
11117
|
+
category: "group-failure",
|
|
11118
|
+
source: "group",
|
|
11119
|
+
title: `Group ${group.status}`,
|
|
11120
|
+
message: `${group.title} is marked ${group.status}.`,
|
|
11121
|
+
observedAt: group.updatedAt,
|
|
11122
|
+
logId: null,
|
|
11123
|
+
sessionId: null,
|
|
11124
|
+
runId: null,
|
|
11125
|
+
groupId: group.id,
|
|
11126
|
+
provider: null,
|
|
11127
|
+
model: null,
|
|
11128
|
+
apiFormat: null,
|
|
11129
|
+
evidence: baseEvidence(null, null, null, group.id),
|
|
11130
|
+
metadata: {
|
|
11131
|
+
groupStatus: group.status,
|
|
11132
|
+
memberCount: group.members.length
|
|
11133
|
+
}
|
|
11134
|
+
};
|
|
11135
|
+
}
|
|
11136
|
+
function groupMemberFailureObservation(group, member) {
|
|
11137
|
+
return {
|
|
11138
|
+
fingerprint: fingerprint(["group-member", group.id, member.id, member.status]),
|
|
11139
|
+
severity: "critical",
|
|
11140
|
+
category: "group-failure",
|
|
11141
|
+
source: "group",
|
|
11142
|
+
title: "Group member failed",
|
|
11143
|
+
message: `${member.label ?? member.sessionId} is marked ${member.status ?? "unknown"}.`,
|
|
11144
|
+
observedAt: member.updatedAt,
|
|
11145
|
+
logId: null,
|
|
11146
|
+
sessionId: member.sessionId,
|
|
11147
|
+
runId: member.runId,
|
|
11148
|
+
groupId: group.id,
|
|
11149
|
+
provider: memberProvider(member),
|
|
11150
|
+
model: memberModel(member),
|
|
11151
|
+
apiFormat: null,
|
|
11152
|
+
evidence: baseEvidence(null, member.sessionId, member.runId, group.id),
|
|
11153
|
+
metadata: {
|
|
11154
|
+
groupTitle: group.title,
|
|
11155
|
+
memberId: member.id,
|
|
11156
|
+
memberStatus: member.status
|
|
11157
|
+
}
|
|
11158
|
+
};
|
|
11159
|
+
}
|
|
11160
|
+
function groupIncompleteObservation(group, missingStatusCount) {
|
|
11161
|
+
return {
|
|
11162
|
+
fingerprint: fingerprint(["group-incomplete", group.id, missingStatusCount]),
|
|
11163
|
+
severity: "notice",
|
|
11164
|
+
category: "group-incomplete",
|
|
11165
|
+
source: "group",
|
|
11166
|
+
title: "Group has unclassified members",
|
|
11167
|
+
message: `${group.title} has ${String(missingStatusCount)} member(s) without a final status.`,
|
|
11168
|
+
observedAt: group.updatedAt,
|
|
11169
|
+
logId: null,
|
|
11170
|
+
sessionId: null,
|
|
11171
|
+
runId: null,
|
|
11172
|
+
groupId: group.id,
|
|
11173
|
+
provider: null,
|
|
11174
|
+
model: null,
|
|
11175
|
+
apiFormat: null,
|
|
11176
|
+
evidence: baseEvidence(null, null, null, group.id),
|
|
11177
|
+
metadata: {
|
|
11178
|
+
groupTitle: group.title,
|
|
11179
|
+
missingStatusCount
|
|
11180
|
+
}
|
|
11181
|
+
};
|
|
11182
|
+
}
|
|
11183
|
+
function addGroupObservations(map, groups) {
|
|
11184
|
+
for (const group of groups) {
|
|
11185
|
+
const groupFailure = groupFailureObservation(group);
|
|
11186
|
+
if (groupFailure !== null) addObservation(map, groupFailure);
|
|
11187
|
+
let missingStatusCount = 0;
|
|
11188
|
+
for (const member of group.members) {
|
|
11189
|
+
if (isFailedMember(member)) {
|
|
11190
|
+
addObservation(map, groupMemberFailureObservation(group, member));
|
|
11191
|
+
}
|
|
11192
|
+
if (member.status === null) missingStatusCount += 1;
|
|
11193
|
+
}
|
|
11194
|
+
if (missingStatusCount > 0) {
|
|
11195
|
+
addObservation(map, groupIncompleteObservation(group, missingStatusCount));
|
|
11196
|
+
}
|
|
11197
|
+
}
|
|
11198
|
+
}
|
|
11199
|
+
function alertMatchesFilters(alert, filters) {
|
|
11200
|
+
if (filters.severity !== void 0 && alert.severity !== filters.severity) return false;
|
|
11201
|
+
if (filters.category !== void 0 && alert.category !== filters.category) return false;
|
|
11202
|
+
if (filters.source !== void 0 && alert.source !== filters.source) return false;
|
|
11203
|
+
return true;
|
|
11204
|
+
}
|
|
11205
|
+
function sortAlerts(alerts) {
|
|
11206
|
+
return [...alerts].sort((left, right) => {
|
|
11207
|
+
const timeCompare = right.lastSeenAt.localeCompare(left.lastSeenAt);
|
|
11208
|
+
if (timeCompare !== 0) return timeCompare;
|
|
11209
|
+
return left.id.localeCompare(right.id);
|
|
11210
|
+
});
|
|
11211
|
+
}
|
|
11212
|
+
function buildAlertSummary(alerts) {
|
|
11213
|
+
let critical = 0;
|
|
11214
|
+
let warning = 0;
|
|
11215
|
+
let notice = 0;
|
|
11216
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
11217
|
+
for (const alert of alerts) {
|
|
11218
|
+
switch (alert.severity) {
|
|
11219
|
+
case "critical":
|
|
11220
|
+
critical += 1;
|
|
11221
|
+
break;
|
|
11222
|
+
case "warning":
|
|
11223
|
+
warning += 1;
|
|
11224
|
+
break;
|
|
11225
|
+
case "notice":
|
|
11226
|
+
notice += 1;
|
|
11227
|
+
break;
|
|
11228
|
+
}
|
|
11229
|
+
byCategory.set(alert.category, (byCategory.get(alert.category) ?? 0) + 1);
|
|
11230
|
+
}
|
|
11231
|
+
return {
|
|
11232
|
+
total: alerts.length,
|
|
11233
|
+
open: alerts.length,
|
|
11234
|
+
critical,
|
|
11235
|
+
warning,
|
|
11236
|
+
notice,
|
|
11237
|
+
byCategory: [...byCategory.entries()].map(([category, count]) => ({ category, count })).sort(
|
|
11238
|
+
(left, right) => right.count - left.count || left.category.localeCompare(right.category)
|
|
11239
|
+
)
|
|
11240
|
+
};
|
|
11241
|
+
}
|
|
11242
|
+
function collectAlertsFromEvidence(input) {
|
|
11243
|
+
const map = /* @__PURE__ */ new Map();
|
|
11244
|
+
addLogObservations(map, input.logs, input.slowResponseThresholdSeconds);
|
|
11245
|
+
addRunFailureObservations(map, input.recentFailures);
|
|
11246
|
+
addGroupObservations(map, input.groups);
|
|
11247
|
+
return sortAlerts([...map.values()]);
|
|
11248
|
+
}
|
|
11249
|
+
function filterAlerts(alerts, filters) {
|
|
11250
|
+
return alerts.filter((alert) => alertMatchesFilters(alert, filters));
|
|
11251
|
+
}
|
|
11252
|
+
async function listAlerts(options = {}) {
|
|
11253
|
+
const limit = clampAlertLimit(options.limit);
|
|
11254
|
+
const scanLimit = clampAlertScanLimit(options.scanLimit);
|
|
11255
|
+
const logPage = await listLogsCursorPage({
|
|
11256
|
+
limit: scanLimit,
|
|
11257
|
+
includeBodies: false,
|
|
11258
|
+
anchor: "newest"
|
|
11259
|
+
});
|
|
11260
|
+
const config = getConfig();
|
|
11261
|
+
const alerts = collectAlertsFromEvidence({
|
|
11262
|
+
logs: logPage.logs,
|
|
11263
|
+
recentFailures: listRecentFailures(scanLimit).failures,
|
|
11264
|
+
groups: listGroups(),
|
|
11265
|
+
slowResponseThresholdSeconds: config.slowResponseThresholdSeconds
|
|
11266
|
+
});
|
|
11267
|
+
const filtered = filterAlerts(alerts, options);
|
|
11268
|
+
return {
|
|
11269
|
+
alerts: filtered.slice(0, limit),
|
|
11270
|
+
total: filtered.length,
|
|
11271
|
+
limit,
|
|
11272
|
+
summary: buildAlertSummary(filtered)
|
|
11273
|
+
};
|
|
11274
|
+
}
|
|
11275
|
+
async function getAlertSummary(options = {}) {
|
|
11276
|
+
const response = await listAlerts({
|
|
11277
|
+
limit: MAX_ALERT_LIMIT,
|
|
11278
|
+
scanLimit: options.scanLimit
|
|
11279
|
+
});
|
|
11280
|
+
return response.summary;
|
|
11281
|
+
}
|
|
11282
|
+
function listInspectorAlerts(options) {
|
|
11283
|
+
return listAlerts(options);
|
|
11284
|
+
}
|
|
11285
|
+
function getInspectorAlertSummary(options) {
|
|
11286
|
+
return getAlertSummary(options);
|
|
11287
|
+
}
|
|
11288
|
+
function parsePositiveInt$1(value) {
|
|
11289
|
+
if (value === null) return void 0;
|
|
11290
|
+
const parsed = Number(value);
|
|
11291
|
+
if (!Number.isInteger(parsed) || parsed < 1) return void 0;
|
|
11292
|
+
return parsed;
|
|
11293
|
+
}
|
|
11294
|
+
function parseFilters(url) {
|
|
11295
|
+
const severityResult = AlertSeveritySchema.safeParse(url.searchParams.get("severity"));
|
|
11296
|
+
const categoryResult = AlertCategorySchema.safeParse(url.searchParams.get("category"));
|
|
11297
|
+
const sourceResult = AlertSourceSchema.safeParse(url.searchParams.get("source"));
|
|
11298
|
+
return {
|
|
11299
|
+
severity: severityResult.success ? severityResult.data : void 0,
|
|
11300
|
+
category: categoryResult.success ? categoryResult.data : void 0,
|
|
11301
|
+
source: sourceResult.success ? sourceResult.data : void 0
|
|
11302
|
+
};
|
|
11303
|
+
}
|
|
11304
|
+
const Route$q = createFileRoute("/api/alerts")({
|
|
11305
|
+
server: {
|
|
11306
|
+
handlers: {
|
|
11307
|
+
GET: async ({ request }) => {
|
|
11308
|
+
const url = new URL(request.url);
|
|
11309
|
+
return Response.json(
|
|
11310
|
+
await listInspectorAlerts({
|
|
11311
|
+
...parseFilters(url),
|
|
11312
|
+
limit: parsePositiveInt$1(url.searchParams.get("limit")),
|
|
11313
|
+
scanLimit: parsePositiveInt$1(url.searchParams.get("scanLimit"))
|
|
11314
|
+
})
|
|
11315
|
+
);
|
|
11316
|
+
}
|
|
11317
|
+
}
|
|
11318
|
+
}
|
|
11319
|
+
});
|
|
11320
|
+
async function readJsonBody$4(request) {
|
|
11321
|
+
try {
|
|
11322
|
+
const raw = await request.text();
|
|
11323
|
+
if (raw.trim().length === 0) return { ok: true, value: {} };
|
|
11324
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
11325
|
+
} catch {
|
|
11326
|
+
return { ok: false };
|
|
11327
|
+
}
|
|
11328
|
+
}
|
|
11329
|
+
const Route$p = createFileRoute("/api/runs/$runId")({
|
|
11330
|
+
server: {
|
|
11331
|
+
handlers: {
|
|
11332
|
+
GET: ({ params }) => {
|
|
11333
|
+
const run = getInspectorRun(params.runId);
|
|
11334
|
+
if (!run.ok) {
|
|
11335
|
+
return Response.json({ error: run.message }, { status: run.status });
|
|
11336
|
+
}
|
|
11337
|
+
return Response.json(run.value);
|
|
11338
|
+
},
|
|
11339
|
+
PATCH: async ({ params, request }) => {
|
|
11340
|
+
const body = await readJsonBody$4(request);
|
|
11341
|
+
if (!body.ok) {
|
|
11342
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
11343
|
+
}
|
|
11344
|
+
const parsed = UpdateInspectorRunInputSchema.safeParse(body.value);
|
|
11345
|
+
if (!parsed.success) {
|
|
11346
|
+
return Response.json(
|
|
11347
|
+
{ error: "Invalid request body", details: parsed.error.format() },
|
|
11348
|
+
{ status: 400 }
|
|
11349
|
+
);
|
|
11350
|
+
}
|
|
11351
|
+
const updated = updateInspectorRun(params.runId, parsed.data);
|
|
11352
|
+
if (!updated.ok) {
|
|
11353
|
+
return Response.json({ error: updated.message }, { status: updated.status });
|
|
11354
|
+
}
|
|
11355
|
+
return Response.json(updated.value);
|
|
11356
|
+
}
|
|
11357
|
+
}
|
|
11358
|
+
}
|
|
11359
|
+
});
|
|
11360
|
+
const ZHIPU_OPENAI_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
|
|
11361
|
+
const ZHIPU_CODING_OPENAI_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4";
|
|
11362
|
+
const ZHIPU_CODING_ANTHROPIC_BASE_URL = "https://open.bigmodel.cn/api/anthropic";
|
|
11363
|
+
function readJsonSafe(filePath) {
|
|
11364
|
+
try {
|
|
11365
|
+
if (!existsSync(filePath)) return null;
|
|
11366
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
11367
|
+
const parsed = JSON.parse(raw);
|
|
11368
|
+
return isPlainRecord(parsed) ? parsed : null;
|
|
11369
|
+
} catch {
|
|
11370
|
+
return null;
|
|
11371
|
+
}
|
|
11372
|
+
}
|
|
11373
|
+
function getEnvValue(envObj, key) {
|
|
11374
|
+
if (!isPlainRecord(envObj)) return void 0;
|
|
11375
|
+
const val = envObj[key];
|
|
11376
|
+
return typeof val === "string" ? val.trim() : void 0;
|
|
11377
|
+
}
|
|
11378
|
+
const KNOWN_PROVIDER_NAMES = {
|
|
11379
|
+
deepseek: "DeepSeek",
|
|
11380
|
+
minimaxi: "MiniMax",
|
|
11381
|
+
openai: "OpenAI",
|
|
11382
|
+
anthropic: "Anthropic",
|
|
11383
|
+
openrouter: "OpenRouter",
|
|
11384
|
+
groq: "Groq",
|
|
11385
|
+
together: "Together",
|
|
11386
|
+
fireworks: "Fireworks",
|
|
11387
|
+
bedrock: "Bedrock",
|
|
11388
|
+
vertexai: "Vertex AI",
|
|
11389
|
+
azure: "Azure",
|
|
11390
|
+
moonshot: "Moonshot",
|
|
11391
|
+
zhipu: "ZhipuAI",
|
|
11392
|
+
zhipuai: "ZhipuAI",
|
|
11393
|
+
bigmodel: "ZhipuAI",
|
|
11394
|
+
zai: "Z.AI",
|
|
11395
|
+
qwen: "Qwen",
|
|
11396
|
+
baichuan: "Baichuan",
|
|
11397
|
+
iflytek: "iFlytek",
|
|
11398
|
+
doubao: "Doubao",
|
|
11399
|
+
lingyiwanwu: "LingyiWanwu",
|
|
11400
|
+
stepfun: "StepFun"
|
|
11401
|
+
};
|
|
11402
|
+
function deriveNameFromUrl(url) {
|
|
11403
|
+
try {
|
|
11404
|
+
const hostname = new URL(url).hostname;
|
|
11405
|
+
const parts = hostname.split(".");
|
|
11406
|
+
const domain = parts.length >= 2 ? parts[parts.length - 2] ?? hostname : hostname;
|
|
11407
|
+
const domainLower = domain.toLowerCase();
|
|
11408
|
+
if (KNOWN_PROVIDER_NAMES[domainLower] !== void 0) {
|
|
11409
|
+
return KNOWN_PROVIDER_NAMES[domainLower];
|
|
11410
|
+
}
|
|
11411
|
+
return domain.charAt(0).toUpperCase() + domain.slice(1);
|
|
11412
|
+
} catch {
|
|
11413
|
+
return "Imported Provider";
|
|
11414
|
+
}
|
|
11415
|
+
}
|
|
11416
|
+
function detectClaudeCodeProviders() {
|
|
11417
|
+
const home = homedir();
|
|
11418
|
+
const results = [];
|
|
11419
|
+
const globalConfig = readJsonSafe(join(home, ".claude", "settings.json"));
|
|
11420
|
+
const localConfig = readJsonSafe(join(home, ".claude", "settings.local.json"));
|
|
10238
11421
|
const mergedEnv = {};
|
|
10239
11422
|
if (isPlainRecord(globalConfig)) {
|
|
10240
11423
|
const env = globalConfig["env"];
|
|
@@ -10600,7 +11783,7 @@ function scanExternalProviders() {
|
|
|
10600
11783
|
}
|
|
10601
11784
|
return { providers: filteredProviders, warnings };
|
|
10602
11785
|
}
|
|
10603
|
-
const Route$
|
|
11786
|
+
const Route$o = createFileRoute("/api/providers/scan")({
|
|
10604
11787
|
server: {
|
|
10605
11788
|
handlers: {
|
|
10606
11789
|
GET: () => {
|
|
@@ -10621,7 +11804,7 @@ const Route$l = createFileRoute("/api/providers/scan")({
|
|
|
10621
11804
|
}
|
|
10622
11805
|
});
|
|
10623
11806
|
union([string(), object({ providers: unknown() })]);
|
|
10624
|
-
const Route$
|
|
11807
|
+
const Route$n = createFileRoute("/api/providers/import")({
|
|
10625
11808
|
server: {
|
|
10626
11809
|
handlers: {
|
|
10627
11810
|
POST: async ({ request }) => {
|
|
@@ -10654,7 +11837,7 @@ const Route$k = createFileRoute("/api/providers/import")({
|
|
|
10654
11837
|
}
|
|
10655
11838
|
}
|
|
10656
11839
|
});
|
|
10657
|
-
const Route$
|
|
11840
|
+
const Route$m = createFileRoute("/api/providers/export")({
|
|
10658
11841
|
server: {
|
|
10659
11842
|
handlers: {
|
|
10660
11843
|
GET: ({ request }) => {
|
|
@@ -10687,7 +11870,7 @@ const ProviderUpdateSchema = object({
|
|
|
10687
11870
|
modelMetadata: array(ProviderModelMetadataSchema).optional(),
|
|
10688
11871
|
source: _enum(["company", "personal"]).optional()
|
|
10689
11872
|
});
|
|
10690
|
-
const Route$
|
|
11873
|
+
const Route$l = createFileRoute("/api/providers/$providerId")({
|
|
10691
11874
|
server: {
|
|
10692
11875
|
handlers: {
|
|
10693
11876
|
GET: ({ params, request }) => {
|
|
@@ -10722,7 +11905,7 @@ const Route$i = createFileRoute("/api/providers/$providerId")({
|
|
|
10722
11905
|
}
|
|
10723
11906
|
});
|
|
10724
11907
|
const INITIAL_STREAM_LOG_LIMIT = 100;
|
|
10725
|
-
const Route$
|
|
11908
|
+
const Route$k = createFileRoute("/api/logs/stream")({
|
|
10726
11909
|
server: {
|
|
10727
11910
|
handlers: {
|
|
10728
11911
|
GET: ({ request }) => {
|
|
@@ -10795,7 +11978,411 @@ const Route$h = createFileRoute("/api/logs/stream")({
|
|
|
10795
11978
|
}
|
|
10796
11979
|
}
|
|
10797
11980
|
});
|
|
10798
|
-
const
|
|
11981
|
+
const ManifestSchema = object({
|
|
11982
|
+
version: string().optional(),
|
|
11983
|
+
exportedAt: string().optional(),
|
|
11984
|
+
mode: string().optional(),
|
|
11985
|
+
redacted: boolean().optional(),
|
|
11986
|
+
logIds: array(number().int().positive()).optional()
|
|
11987
|
+
}).passthrough();
|
|
11988
|
+
const LogsArraySchema = array(CapturedLogSchema);
|
|
11989
|
+
const LogsEnvelopeSchema = object({ logs: array(CapturedLogSchema) }).passthrough();
|
|
11990
|
+
const StreamingChunksImportSchema = object({
|
|
11991
|
+
chunks: array(StreamingChunkSchema$1),
|
|
11992
|
+
truncated: boolean().optional().default(false)
|
|
11993
|
+
});
|
|
11994
|
+
const SEMVER_MAJOR_PATTERN = /^([0-9]+)\.[0-9]+\.[0-9]+(?:[-+].*)?$/;
|
|
11995
|
+
function readRecordProperty(value, name) {
|
|
11996
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
11997
|
+
const desc = Object.getOwnPropertyDescriptor(value, name);
|
|
11998
|
+
return desc === void 0 ? void 0 : desc.value;
|
|
11999
|
+
}
|
|
12000
|
+
function parseJson(text) {
|
|
12001
|
+
if (text === null) return null;
|
|
12002
|
+
try {
|
|
12003
|
+
const parsed = JSON.parse(text);
|
|
12004
|
+
return parsed;
|
|
12005
|
+
} catch {
|
|
12006
|
+
return null;
|
|
12007
|
+
}
|
|
12008
|
+
}
|
|
12009
|
+
function parseJsonLogs(text) {
|
|
12010
|
+
const parsed = parseJson(text);
|
|
12011
|
+
const direct = LogsArraySchema.safeParse(parsed);
|
|
12012
|
+
if (direct.success) return direct.data;
|
|
12013
|
+
const envelope = LogsEnvelopeSchema.safeParse(parsed);
|
|
12014
|
+
if (envelope.success) return envelope.data.logs;
|
|
12015
|
+
return null;
|
|
12016
|
+
}
|
|
12017
|
+
function parseJsonlLogs(text) {
|
|
12018
|
+
const logs = [];
|
|
12019
|
+
let skipped = 0;
|
|
12020
|
+
for (const line of text.split(/\r?\n/)) {
|
|
12021
|
+
if (line.trim() === "") continue;
|
|
12022
|
+
const parsed = CapturedLogSchema.safeParse(parseJson(line));
|
|
12023
|
+
if (parsed.success) {
|
|
12024
|
+
logs.push(parsed.data);
|
|
12025
|
+
} else {
|
|
12026
|
+
skipped += 1;
|
|
12027
|
+
}
|
|
12028
|
+
}
|
|
12029
|
+
return { logs, skipped };
|
|
12030
|
+
}
|
|
12031
|
+
function readStringProperty(value, name) {
|
|
12032
|
+
const property = readRecordProperty(value, name);
|
|
12033
|
+
return typeof property === "string" ? property : null;
|
|
12034
|
+
}
|
|
12035
|
+
function hasProperty(value, name) {
|
|
12036
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
12037
|
+
return Object.getOwnPropertyDescriptor(value, name) !== void 0;
|
|
12038
|
+
}
|
|
12039
|
+
function modelFromRequestText(requestText) {
|
|
12040
|
+
return readStringProperty(parseJson(requestText), "model");
|
|
12041
|
+
}
|
|
12042
|
+
function inferApiFormatFromBody(path2, model, requestText) {
|
|
12043
|
+
const pathFormat = apiFormatForPath(path2);
|
|
12044
|
+
if (pathFormat !== "unknown") return pathFormat;
|
|
12045
|
+
const normalizedModel = model?.toLowerCase() ?? "";
|
|
12046
|
+
if (normalizedModel.startsWith("claude-")) return "anthropic";
|
|
12047
|
+
if (normalizedModel.startsWith("gpt-") || normalizedModel.startsWith("o1-") || normalizedModel.startsWith("o3-") || normalizedModel.startsWith("o4-") || normalizedModel.startsWith("deepseek-") || normalizedModel.startsWith("glm-") || normalizedModel.startsWith("qwen")) {
|
|
12048
|
+
return "openai";
|
|
12049
|
+
}
|
|
12050
|
+
const parsedRequest = parseJson(requestText);
|
|
12051
|
+
if (hasProperty(parsedRequest, "system") || hasProperty(parsedRequest, "max_tokens")) {
|
|
12052
|
+
return "anthropic";
|
|
12053
|
+
}
|
|
12054
|
+
return "openai";
|
|
12055
|
+
}
|
|
12056
|
+
function defaultPathForApiFormat(apiFormat) {
|
|
12057
|
+
switch (apiFormat) {
|
|
12058
|
+
case "anthropic":
|
|
12059
|
+
return "/v1/messages";
|
|
12060
|
+
case "openai":
|
|
12061
|
+
return "/v1/chat/completions";
|
|
12062
|
+
case "unknown":
|
|
12063
|
+
return "/v1/chat/completions";
|
|
12064
|
+
}
|
|
12065
|
+
}
|
|
12066
|
+
function normalizeTimestamp(value, fallback) {
|
|
12067
|
+
return Number.isNaN(new Date(value).getTime()) ? fallback : value;
|
|
12068
|
+
}
|
|
12069
|
+
function responseStatusFromText(responseText) {
|
|
12070
|
+
if (responseText === null) return null;
|
|
12071
|
+
const parsed = parseJson(responseText);
|
|
12072
|
+
return hasProperty(parsed, "error") ? 500 : 200;
|
|
12073
|
+
}
|
|
12074
|
+
function mergeWarnings(existing, generated) {
|
|
12075
|
+
const values = [];
|
|
12076
|
+
for (const warning of existing ?? []) {
|
|
12077
|
+
if (!values.includes(warning)) values.push(warning);
|
|
12078
|
+
}
|
|
12079
|
+
for (const warning of generated) {
|
|
12080
|
+
if (!values.includes(warning)) values.push(warning);
|
|
12081
|
+
}
|
|
12082
|
+
return values.length === 0 ? void 0 : values;
|
|
12083
|
+
}
|
|
12084
|
+
function withToolWarnings(log) {
|
|
12085
|
+
const warnings = analyzeToolSchemaWarnings({
|
|
12086
|
+
rawRequestBody: log.rawRequestBody,
|
|
12087
|
+
responseText: log.responseText,
|
|
12088
|
+
apiFormat: log.apiFormat
|
|
12089
|
+
});
|
|
12090
|
+
return {
|
|
12091
|
+
...log,
|
|
12092
|
+
warnings: mergeWarnings(log.warnings, warnings)
|
|
12093
|
+
};
|
|
12094
|
+
}
|
|
12095
|
+
function streamingChunksFromText(text) {
|
|
12096
|
+
const parsed = StreamingChunksImportSchema.safeParse(parseJson(text));
|
|
12097
|
+
return parsed.success ? parsed.data : void 0;
|
|
12098
|
+
}
|
|
12099
|
+
function draftFromCapturedLog(log, requestText, responseText, streamingChunks) {
|
|
12100
|
+
const rawRequestBody = requestText ?? log.rawRequestBody;
|
|
12101
|
+
const response = responseText ?? log.responseText;
|
|
12102
|
+
const model = log.model ?? modelFromRequestText(rawRequestBody);
|
|
12103
|
+
const apiFormat = log.apiFormat === "unknown" ? inferApiFormatFromBody(log.path, model, rawRequestBody) : log.apiFormat;
|
|
12104
|
+
const path2 = log.path.trim() === "" ? defaultPathForApiFormat(apiFormat) : log.path;
|
|
12105
|
+
return withToolWarnings({
|
|
12106
|
+
timestamp: normalizeTimestamp(log.timestamp, (/* @__PURE__ */ new Date()).toISOString()),
|
|
12107
|
+
method: log.method.trim() === "" ? "POST" : log.method,
|
|
12108
|
+
path: path2,
|
|
12109
|
+
model,
|
|
12110
|
+
sessionId: null,
|
|
12111
|
+
rawRequestBody,
|
|
12112
|
+
responseStatus: log.responseStatus ?? responseStatusFromText(response),
|
|
12113
|
+
responseText: response,
|
|
12114
|
+
inputTokens: log.inputTokens,
|
|
12115
|
+
outputTokens: log.outputTokens,
|
|
12116
|
+
cacheCreationInputTokens: log.cacheCreationInputTokens,
|
|
12117
|
+
cacheReadInputTokens: log.cacheReadInputTokens,
|
|
12118
|
+
elapsedMs: log.elapsedMs,
|
|
12119
|
+
firstChunkMs: log.firstChunkMs ?? null,
|
|
12120
|
+
totalStreamMs: log.totalStreamMs ?? null,
|
|
12121
|
+
tokensPerSecond: log.tokensPerSecond ?? null,
|
|
12122
|
+
streaming: log.streaming || streamingChunks !== void 0,
|
|
12123
|
+
userAgent: log.userAgent,
|
|
12124
|
+
origin: log.origin,
|
|
12125
|
+
rawHeaders: log.rawHeaders,
|
|
12126
|
+
headers: log.headers,
|
|
12127
|
+
apiFormat,
|
|
12128
|
+
isTest: false,
|
|
12129
|
+
replayOfLogId: null,
|
|
12130
|
+
providerName: log.providerName ?? null,
|
|
12131
|
+
clientPort: log.clientPort ?? null,
|
|
12132
|
+
clientPid: log.clientPid ?? null,
|
|
12133
|
+
clientCwd: log.clientCwd ?? null,
|
|
12134
|
+
clientProjectFolder: log.clientProjectFolder ?? null,
|
|
12135
|
+
streamingChunks,
|
|
12136
|
+
streamingChunksPath: null,
|
|
12137
|
+
rawRequestBodyBytes: log.rawRequestBodyBytes,
|
|
12138
|
+
responseTextBytes: log.responseTextBytes,
|
|
12139
|
+
bodyContentMode: "full",
|
|
12140
|
+
warnings: log.warnings,
|
|
12141
|
+
error: log.error ?? null
|
|
12142
|
+
});
|
|
12143
|
+
}
|
|
12144
|
+
function legacyDraftFromParts(input) {
|
|
12145
|
+
const model = modelFromRequestText(input.requestText);
|
|
12146
|
+
const apiFormat = inferApiFormatFromBody("", model, input.requestText);
|
|
12147
|
+
return withToolWarnings({
|
|
12148
|
+
timestamp: input.exportedAt,
|
|
12149
|
+
method: "POST",
|
|
12150
|
+
path: defaultPathForApiFormat(apiFormat),
|
|
12151
|
+
model,
|
|
12152
|
+
sessionId: null,
|
|
12153
|
+
rawRequestBody: input.requestText,
|
|
12154
|
+
responseStatus: responseStatusFromText(input.responseText),
|
|
12155
|
+
responseText: input.responseText,
|
|
12156
|
+
inputTokens: null,
|
|
12157
|
+
outputTokens: null,
|
|
12158
|
+
cacheCreationInputTokens: null,
|
|
12159
|
+
cacheReadInputTokens: null,
|
|
12160
|
+
elapsedMs: null,
|
|
12161
|
+
firstChunkMs: null,
|
|
12162
|
+
totalStreamMs: null,
|
|
12163
|
+
tokensPerSecond: null,
|
|
12164
|
+
streaming: input.streamingChunks !== void 0,
|
|
12165
|
+
userAgent: "agent-inspector-import",
|
|
12166
|
+
origin: null,
|
|
12167
|
+
apiFormat,
|
|
12168
|
+
isTest: false,
|
|
12169
|
+
replayOfLogId: null,
|
|
12170
|
+
providerName: null,
|
|
12171
|
+
clientPort: null,
|
|
12172
|
+
clientPid: null,
|
|
12173
|
+
clientCwd: null,
|
|
12174
|
+
clientProjectFolder: null,
|
|
12175
|
+
streamingChunks: input.streamingChunks,
|
|
12176
|
+
streamingChunksPath: null,
|
|
12177
|
+
bodyContentMode: "full",
|
|
12178
|
+
error: null
|
|
12179
|
+
});
|
|
12180
|
+
}
|
|
12181
|
+
async function readZipText(zip, path2) {
|
|
12182
|
+
const file = zip.file(path2);
|
|
12183
|
+
return file === null ? null : await file.async("text");
|
|
12184
|
+
}
|
|
12185
|
+
async function readManifest(zip) {
|
|
12186
|
+
const text = await readZipText(zip, "manifest.json");
|
|
12187
|
+
const parsed = ManifestSchema.safeParse(parseJson(text));
|
|
12188
|
+
return parsed.success ? parsed.data : null;
|
|
12189
|
+
}
|
|
12190
|
+
function versionMajor(version2) {
|
|
12191
|
+
const match = SEMVER_MAJOR_PATTERN.exec(version2);
|
|
12192
|
+
if (match === null) return null;
|
|
12193
|
+
const major = match[1];
|
|
12194
|
+
return major === void 0 ? null : Number.parseInt(major, 10);
|
|
12195
|
+
}
|
|
12196
|
+
function validateManifestVersion(manifest) {
|
|
12197
|
+
const exportedVersion = manifest?.version;
|
|
12198
|
+
if (exportedVersion === void 0) {
|
|
12199
|
+
return {
|
|
12200
|
+
ok: true,
|
|
12201
|
+
warning: "Imported legacy export without version metadata. Compatibility could not be verified."
|
|
12202
|
+
};
|
|
12203
|
+
}
|
|
12204
|
+
const exportedMajor = versionMajor(exportedVersion);
|
|
12205
|
+
if (exportedMajor === null) {
|
|
12206
|
+
return {
|
|
12207
|
+
ok: false,
|
|
12208
|
+
message: `Unsupported export version "${exportedVersion}".`
|
|
12209
|
+
};
|
|
12210
|
+
}
|
|
12211
|
+
const currentMajor = versionMajor(packageJson.version);
|
|
12212
|
+
if (currentMajor === null) {
|
|
12213
|
+
return {
|
|
12214
|
+
ok: true,
|
|
12215
|
+
warning: `Current Agent Inspector version "${packageJson.version}" could not be verified against export version "${exportedVersion}".`
|
|
12216
|
+
};
|
|
12217
|
+
}
|
|
12218
|
+
if (exportedMajor !== currentMajor) {
|
|
12219
|
+
return {
|
|
12220
|
+
ok: false,
|
|
12221
|
+
message: `Export version mismatch: archive was created by Agent Inspector v${exportedVersion}, current version is v${packageJson.version}. Import with a matching major version.`
|
|
12222
|
+
};
|
|
12223
|
+
}
|
|
12224
|
+
if (exportedVersion !== packageJson.version) {
|
|
12225
|
+
return {
|
|
12226
|
+
ok: true,
|
|
12227
|
+
warning: `Imported export from Agent Inspector v${exportedVersion}; current version is v${packageJson.version}.`
|
|
12228
|
+
};
|
|
12229
|
+
}
|
|
12230
|
+
return { ok: true, warning: null };
|
|
12231
|
+
}
|
|
12232
|
+
async function parseZipLogImport(data) {
|
|
12233
|
+
const warnings = [];
|
|
12234
|
+
const zip = await JSZip.loadAsync(data);
|
|
12235
|
+
const manifest = await readManifest(zip);
|
|
12236
|
+
const versionCheck = validateManifestVersion(manifest);
|
|
12237
|
+
if (!versionCheck.ok) {
|
|
12238
|
+
return {
|
|
12239
|
+
ok: false,
|
|
12240
|
+
message: versionCheck.message,
|
|
12241
|
+
warnings
|
|
12242
|
+
};
|
|
12243
|
+
}
|
|
12244
|
+
if (versionCheck.warning !== null) {
|
|
12245
|
+
warnings.push(versionCheck.warning);
|
|
12246
|
+
}
|
|
12247
|
+
const exportedAt = normalizeTimestamp(manifest?.exportedAt ?? "", (/* @__PURE__ */ new Date()).toISOString());
|
|
12248
|
+
if (manifest?.redacted === true) {
|
|
12249
|
+
warnings.push("Imported redacted export. Secrets and some replay details may be unavailable.");
|
|
12250
|
+
}
|
|
12251
|
+
const metadataText2 = await readZipText(zip, "logs.json");
|
|
12252
|
+
const metadataLogs = metadataText2 === null ? null : parseJsonLogs(metadataText2);
|
|
12253
|
+
const logs = [];
|
|
12254
|
+
let skipped = 0;
|
|
12255
|
+
if (metadataLogs !== null) {
|
|
12256
|
+
for (const log of metadataLogs) {
|
|
12257
|
+
const requestText = await readZipText(zip, `#${String(log.id)}.Request.json`);
|
|
12258
|
+
const responseText = await readZipText(zip, `#${String(log.id)}.Response.json`);
|
|
12259
|
+
const streamingText = await readZipText(zip, `#${String(log.id)}.SSE.Response.json`);
|
|
12260
|
+
logs.push(
|
|
12261
|
+
draftFromCapturedLog(
|
|
12262
|
+
log,
|
|
12263
|
+
requestText,
|
|
12264
|
+
responseText,
|
|
12265
|
+
streamingChunksFromText(streamingText)
|
|
12266
|
+
)
|
|
12267
|
+
);
|
|
12268
|
+
}
|
|
12269
|
+
return { ok: true, logs, skipped, warnings };
|
|
12270
|
+
}
|
|
12271
|
+
for (const originalId of manifest?.logIds ?? []) {
|
|
12272
|
+
const requestText = await readZipText(zip, `#${String(originalId)}.Request.json`);
|
|
12273
|
+
const responseText = await readZipText(zip, `#${String(originalId)}.Response.json`);
|
|
12274
|
+
const streamingText = await readZipText(zip, `#${String(originalId)}.SSE.Response.json`);
|
|
12275
|
+
if (requestText === null && responseText === null && streamingText === null) {
|
|
12276
|
+
skipped += 1;
|
|
12277
|
+
continue;
|
|
12278
|
+
}
|
|
12279
|
+
logs.push(
|
|
12280
|
+
legacyDraftFromParts({
|
|
12281
|
+
exportedAt,
|
|
12282
|
+
requestText,
|
|
12283
|
+
responseText,
|
|
12284
|
+
streamingChunks: streamingChunksFromText(streamingText)
|
|
12285
|
+
})
|
|
12286
|
+
);
|
|
12287
|
+
}
|
|
12288
|
+
if (logs.length === 0) {
|
|
12289
|
+
return {
|
|
12290
|
+
ok: false,
|
|
12291
|
+
message: "No importable logs were found in the archive.",
|
|
12292
|
+
warnings
|
|
12293
|
+
};
|
|
12294
|
+
}
|
|
12295
|
+
return { ok: true, logs, skipped, warnings };
|
|
12296
|
+
}
|
|
12297
|
+
function looksLikeZip(data, fileName) {
|
|
12298
|
+
if (fileName.toLowerCase().endsWith(".zip")) return true;
|
|
12299
|
+
return data[0] === 80 && data[1] === 75;
|
|
12300
|
+
}
|
|
12301
|
+
function parseTextLogImport(text) {
|
|
12302
|
+
const jsonLogs = parseJsonLogs(text);
|
|
12303
|
+
if (jsonLogs !== null) {
|
|
12304
|
+
return {
|
|
12305
|
+
ok: true,
|
|
12306
|
+
logs: jsonLogs.map((log) => draftFromCapturedLog(log, null, null, void 0)),
|
|
12307
|
+
skipped: 0,
|
|
12308
|
+
warnings: []
|
|
12309
|
+
};
|
|
12310
|
+
}
|
|
12311
|
+
const jsonl = parseJsonlLogs(text);
|
|
12312
|
+
if (jsonl.logs.length > 0) {
|
|
12313
|
+
return {
|
|
12314
|
+
ok: true,
|
|
12315
|
+
logs: jsonl.logs.map((log) => draftFromCapturedLog(log, null, null, void 0)),
|
|
12316
|
+
skipped: jsonl.skipped,
|
|
12317
|
+
warnings: []
|
|
12318
|
+
};
|
|
12319
|
+
}
|
|
12320
|
+
return {
|
|
12321
|
+
ok: false,
|
|
12322
|
+
message: "Unsupported import file. Use an Agent Inspector export ZIP, logs.json, or JSONL file.",
|
|
12323
|
+
warnings: []
|
|
12324
|
+
};
|
|
12325
|
+
}
|
|
12326
|
+
async function parseImportedLogFile(input) {
|
|
12327
|
+
try {
|
|
12328
|
+
if (looksLikeZip(input.data, input.fileName)) {
|
|
12329
|
+
return await parseZipLogImport(input.data);
|
|
12330
|
+
}
|
|
12331
|
+
return parseTextLogImport(new TextDecoder("utf-8").decode(input.data));
|
|
12332
|
+
} catch (err) {
|
|
12333
|
+
return {
|
|
12334
|
+
ok: false,
|
|
12335
|
+
message: err instanceof Error ? err.message : "Failed to parse import file.",
|
|
12336
|
+
warnings: []
|
|
12337
|
+
};
|
|
12338
|
+
}
|
|
12339
|
+
}
|
|
12340
|
+
function sessionNameFromImportFileName(fileName) {
|
|
12341
|
+
const normalized = fileName.replaceAll("\\", "/");
|
|
12342
|
+
const base = basename(normalized).replace(/\.(zip|json|jsonl)$/i, "").trim();
|
|
12343
|
+
return base === "" ? `import-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}` : base;
|
|
12344
|
+
}
|
|
12345
|
+
function isUploadedFile(value) {
|
|
12346
|
+
return value instanceof File;
|
|
12347
|
+
}
|
|
12348
|
+
const Route$j = createFileRoute("/api/logs/import")({
|
|
12349
|
+
server: {
|
|
12350
|
+
handlers: {
|
|
12351
|
+
POST: async ({ request }) => {
|
|
12352
|
+
let formData;
|
|
12353
|
+
try {
|
|
12354
|
+
formData = await request.formData();
|
|
12355
|
+
} catch {
|
|
12356
|
+
return Response.json({ error: "Expected multipart form data" }, { status: 400 });
|
|
12357
|
+
}
|
|
12358
|
+
const upload = formData.get("file");
|
|
12359
|
+
if (!isUploadedFile(upload)) {
|
|
12360
|
+
return Response.json({ error: "Missing import file" }, { status: 400 });
|
|
12361
|
+
}
|
|
12362
|
+
const sessionId = sessionNameFromImportFileName(upload.name);
|
|
12363
|
+
const parsed = await parseImportedLogFile({
|
|
12364
|
+
fileName: upload.name,
|
|
12365
|
+
data: Buffer.from(await upload.arrayBuffer())
|
|
12366
|
+
});
|
|
12367
|
+
if (!parsed.ok) {
|
|
12368
|
+
return Response.json(
|
|
12369
|
+
{ error: parsed.message, warnings: parsed.warnings },
|
|
12370
|
+
{ status: 400 }
|
|
12371
|
+
);
|
|
12372
|
+
}
|
|
12373
|
+
const imported = await importCapturedLogs(parsed.logs, sessionId);
|
|
12374
|
+
return Response.json({
|
|
12375
|
+
sessionId,
|
|
12376
|
+
imported: imported.length,
|
|
12377
|
+
skipped: parsed.skipped,
|
|
12378
|
+
warnings: parsed.warnings,
|
|
12379
|
+
logs: imported.map((log) => compactLogForList(log))
|
|
12380
|
+
});
|
|
12381
|
+
}
|
|
12382
|
+
}
|
|
12383
|
+
}
|
|
12384
|
+
});
|
|
12385
|
+
const Route$i = createFileRoute("/api/logs/$id")({
|
|
10799
12386
|
server: {
|
|
10800
12387
|
handlers: {
|
|
10801
12388
|
GET: async ({ params }) => {
|
|
@@ -11332,7 +12919,7 @@ const SearchBodySchema = object({
|
|
|
11332
12919
|
query: string().min(1),
|
|
11333
12920
|
project: string().optional()
|
|
11334
12921
|
});
|
|
11335
|
-
const Route$
|
|
12922
|
+
const Route$h = createFileRoute("/api/knowledge/search")({
|
|
11336
12923
|
server: {
|
|
11337
12924
|
handlers: {
|
|
11338
12925
|
GET: async ({ request }) => {
|
|
@@ -11354,7 +12941,7 @@ const Route$f = createFileRoute("/api/knowledge/search")({
|
|
|
11354
12941
|
}
|
|
11355
12942
|
}
|
|
11356
12943
|
});
|
|
11357
|
-
const Route$
|
|
12944
|
+
const Route$g = createFileRoute("/api/knowledge/project-context")({
|
|
11358
12945
|
server: {
|
|
11359
12946
|
handlers: {
|
|
11360
12947
|
GET: async ({ request }) => {
|
|
@@ -11436,7 +13023,7 @@ function updateCandidateDraft(id, updates) {
|
|
|
11436
13023
|
candidates.set(id, updated);
|
|
11437
13024
|
return updated;
|
|
11438
13025
|
}
|
|
11439
|
-
const Route$
|
|
13026
|
+
const Route$f = createFileRoute("/api/knowledge/candidates")({
|
|
11440
13027
|
server: {
|
|
11441
13028
|
handlers: {
|
|
11442
13029
|
GET: () => Response.json({ candidates: listCandidates() })
|
|
@@ -11471,7 +13058,7 @@ function readDeleteEvidenceFlag(request) {
|
|
|
11471
13058
|
return { ok: false };
|
|
11472
13059
|
}
|
|
11473
13060
|
}
|
|
11474
|
-
const Route$
|
|
13061
|
+
const Route$e = createFileRoute("/api/groups/$groupId")({
|
|
11475
13062
|
server: {
|
|
11476
13063
|
handlers: {
|
|
11477
13064
|
GET: ({ params }) => {
|
|
@@ -11518,7 +13105,7 @@ const Route$c = createFileRoute("/api/groups/$groupId")({
|
|
|
11518
13105
|
}
|
|
11519
13106
|
}
|
|
11520
13107
|
});
|
|
11521
|
-
const Route$
|
|
13108
|
+
const Route$d = createFileRoute("/api/config/paths")({
|
|
11522
13109
|
server: {
|
|
11523
13110
|
handlers: {
|
|
11524
13111
|
GET: () => {
|
|
@@ -11529,6 +13116,26 @@ const Route$b = createFileRoute("/api/config/paths")({
|
|
|
11529
13116
|
}
|
|
11530
13117
|
}
|
|
11531
13118
|
});
|
|
13119
|
+
function parsePositiveInt(value) {
|
|
13120
|
+
if (value === null) return void 0;
|
|
13121
|
+
const parsed = Number(value);
|
|
13122
|
+
if (!Number.isInteger(parsed) || parsed < 1) return void 0;
|
|
13123
|
+
return parsed;
|
|
13124
|
+
}
|
|
13125
|
+
const Route$c = createFileRoute("/api/alerts/summary")({
|
|
13126
|
+
server: {
|
|
13127
|
+
handlers: {
|
|
13128
|
+
GET: async ({ request }) => {
|
|
13129
|
+
const url = new URL(request.url);
|
|
13130
|
+
return Response.json(
|
|
13131
|
+
await getInspectorAlertSummary({
|
|
13132
|
+
scanLimit: parsePositiveInt(url.searchParams.get("scanLimit"))
|
|
13133
|
+
})
|
|
13134
|
+
);
|
|
13135
|
+
}
|
|
13136
|
+
}
|
|
13137
|
+
}
|
|
13138
|
+
});
|
|
11532
13139
|
async function readJsonBody$2(request) {
|
|
11533
13140
|
try {
|
|
11534
13141
|
const raw = await request.text();
|
|
@@ -11538,7 +13145,7 @@ async function readJsonBody$2(request) {
|
|
|
11538
13145
|
return { ok: false };
|
|
11539
13146
|
}
|
|
11540
13147
|
}
|
|
11541
|
-
const Route$
|
|
13148
|
+
const Route$b = createFileRoute("/api/runs/$runId/evidence")({
|
|
11542
13149
|
server: {
|
|
11543
13150
|
handlers: {
|
|
11544
13151
|
GET: ({ params }) => {
|
|
@@ -12189,7 +13796,7 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
12189
13796
|
clearTimeout(timeoutId);
|
|
12190
13797
|
}
|
|
12191
13798
|
}
|
|
12192
|
-
const Route$
|
|
13799
|
+
const Route$a = createFileRoute("/api/providers/$providerId/test")({
|
|
12193
13800
|
server: {
|
|
12194
13801
|
handlers: {
|
|
12195
13802
|
POST: async ({ params }) => {
|
|
@@ -12283,7 +13890,7 @@ async function readRegistryJson(response) {
|
|
|
12283
13890
|
return null;
|
|
12284
13891
|
}
|
|
12285
13892
|
}
|
|
12286
|
-
const Route$
|
|
13893
|
+
const Route$9 = createFileRoute("/api/providers/$providerId/model-metadata")({
|
|
12287
13894
|
server: {
|
|
12288
13895
|
handlers: {
|
|
12289
13896
|
POST: async ({ params, request }) => {
|
|
@@ -12373,7 +13980,7 @@ const Route$8 = createFileRoute("/api/providers/$providerId/model-metadata")({
|
|
|
12373
13980
|
const ReplayRequestSchema = object({
|
|
12374
13981
|
modifiedBody: string()
|
|
12375
13982
|
});
|
|
12376
|
-
const Route$
|
|
13983
|
+
const Route$8 = createFileRoute("/api/logs/$id/replay")({
|
|
12377
13984
|
server: {
|
|
12378
13985
|
handlers: {
|
|
12379
13986
|
POST: async ({ params, request }) => {
|
|
@@ -12574,7 +14181,7 @@ const Route$7 = createFileRoute("/api/logs/$id/replay")({
|
|
|
12574
14181
|
}
|
|
12575
14182
|
}
|
|
12576
14183
|
});
|
|
12577
|
-
const Route$
|
|
14184
|
+
const Route$7 = createFileRoute("/api/logs/$id/chunks")({
|
|
12578
14185
|
server: {
|
|
12579
14186
|
handlers: {
|
|
12580
14187
|
GET: async ({ params }) => {
|
|
@@ -12600,6 +14207,116 @@ const Route$6 = createFileRoute("/api/logs/$id/chunks")({
|
|
|
12600
14207
|
}
|
|
12601
14208
|
}
|
|
12602
14209
|
});
|
|
14210
|
+
const DEFAULT_LOG_BODY_CHUNK_BYTES = 256 * 1024;
|
|
14211
|
+
const MAX_LOG_BODY_CHUNK_BYTES = 1024 * 1024;
|
|
14212
|
+
function normalizeLogBodyChunkOffset(offset) {
|
|
14213
|
+
if (!Number.isInteger(offset) || offset < 0) return 0;
|
|
14214
|
+
return offset;
|
|
14215
|
+
}
|
|
14216
|
+
function normalizeLogBodyChunkLimit(limit) {
|
|
14217
|
+
if (!Number.isInteger(limit) || limit < 1) return DEFAULT_LOG_BODY_CHUNK_BYTES;
|
|
14218
|
+
return Math.min(limit, MAX_LOG_BODY_CHUNK_BYTES);
|
|
14219
|
+
}
|
|
14220
|
+
function bodyTextForPart(log, part) {
|
|
14221
|
+
switch (part) {
|
|
14222
|
+
case "request":
|
|
14223
|
+
return log.rawRequestBody;
|
|
14224
|
+
case "response":
|
|
14225
|
+
return log.responseText;
|
|
14226
|
+
}
|
|
14227
|
+
}
|
|
14228
|
+
function isUtf8ContinuationByte(byte) {
|
|
14229
|
+
return byte !== void 0 && (byte & 192) === 128;
|
|
14230
|
+
}
|
|
14231
|
+
function expandToUtf8Boundary(buffer, end) {
|
|
14232
|
+
if (end >= buffer.byteLength) return buffer.byteLength;
|
|
14233
|
+
let safeEnd = end;
|
|
14234
|
+
while (safeEnd < buffer.byteLength && isUtf8ContinuationByte(buffer[safeEnd])) {
|
|
14235
|
+
safeEnd++;
|
|
14236
|
+
}
|
|
14237
|
+
return safeEnd;
|
|
14238
|
+
}
|
|
14239
|
+
function createLogBodyChunk({
|
|
14240
|
+
log,
|
|
14241
|
+
part,
|
|
14242
|
+
offset,
|
|
14243
|
+
limit
|
|
14244
|
+
}) {
|
|
14245
|
+
const text = bodyTextForPart(log, part);
|
|
14246
|
+
const normalizedLimit = normalizeLogBodyChunkLimit(limit);
|
|
14247
|
+
if (text === null || text === "") {
|
|
14248
|
+
return {
|
|
14249
|
+
logId: log.id,
|
|
14250
|
+
part,
|
|
14251
|
+
text: "",
|
|
14252
|
+
offset: 0,
|
|
14253
|
+
limit: normalizedLimit,
|
|
14254
|
+
totalBytes: 0,
|
|
14255
|
+
textBytes: 0,
|
|
14256
|
+
nextOffset: null,
|
|
14257
|
+
hasMore: false,
|
|
14258
|
+
contentMode: "empty"
|
|
14259
|
+
};
|
|
14260
|
+
}
|
|
14261
|
+
const bodyBytes = Buffer.from(text, "utf8");
|
|
14262
|
+
const totalBytes = bodyBytes.byteLength;
|
|
14263
|
+
const normalizedOffset = Math.min(normalizeLogBodyChunkOffset(offset), totalBytes);
|
|
14264
|
+
const end = expandToUtf8Boundary(
|
|
14265
|
+
bodyBytes,
|
|
14266
|
+
Math.min(normalizedOffset + normalizedLimit, totalBytes)
|
|
14267
|
+
);
|
|
14268
|
+
const chunkText = bodyBytes.toString("utf8", normalizedOffset, end);
|
|
14269
|
+
const textBytes = end - normalizedOffset;
|
|
14270
|
+
const hasMore = end < totalBytes;
|
|
14271
|
+
const contentMode = hasMore || normalizedOffset > 0 ? "partial" : "full";
|
|
14272
|
+
return {
|
|
14273
|
+
logId: log.id,
|
|
14274
|
+
part,
|
|
14275
|
+
text: chunkText,
|
|
14276
|
+
offset: normalizedOffset,
|
|
14277
|
+
limit: normalizedLimit,
|
|
14278
|
+
totalBytes,
|
|
14279
|
+
textBytes,
|
|
14280
|
+
nextOffset: hasMore ? end : null,
|
|
14281
|
+
hasMore,
|
|
14282
|
+
contentMode
|
|
14283
|
+
};
|
|
14284
|
+
}
|
|
14285
|
+
function parseIntegerParam(value, fallback) {
|
|
14286
|
+
if (value === null) return fallback;
|
|
14287
|
+
const parsed = Number(value);
|
|
14288
|
+
if (!Number.isInteger(parsed)) return fallback;
|
|
14289
|
+
return parsed;
|
|
14290
|
+
}
|
|
14291
|
+
const Route$6 = createFileRoute("/api/logs/$id/body")({
|
|
14292
|
+
server: {
|
|
14293
|
+
handlers: {
|
|
14294
|
+
GET: async ({ params, request }) => {
|
|
14295
|
+
const id = Number(params.id);
|
|
14296
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
14297
|
+
return Response.json({ error: "Invalid log ID" }, { status: 400 });
|
|
14298
|
+
}
|
|
14299
|
+
const url = new URL(request.url);
|
|
14300
|
+
const partResult = LogBodyPartSchema.safeParse(url.searchParams.get("part"));
|
|
14301
|
+
if (!partResult.success) {
|
|
14302
|
+
return Response.json({ error: "Invalid body part" }, { status: 400 });
|
|
14303
|
+
}
|
|
14304
|
+
const log = await getLogById(id);
|
|
14305
|
+
if (log === null) {
|
|
14306
|
+
return Response.json({ error: "Log not found" }, { status: 404 });
|
|
14307
|
+
}
|
|
14308
|
+
return Response.json(
|
|
14309
|
+
createLogBodyChunk({
|
|
14310
|
+
log,
|
|
14311
|
+
part: partResult.data,
|
|
14312
|
+
offset: parseIntegerParam(url.searchParams.get("offset"), 0),
|
|
14313
|
+
limit: parseIntegerParam(url.searchParams.get("limit"), 0)
|
|
14314
|
+
})
|
|
14315
|
+
);
|
|
14316
|
+
}
|
|
14317
|
+
}
|
|
14318
|
+
}
|
|
14319
|
+
});
|
|
12603
14320
|
const CandidateUpdateSchema = object({
|
|
12604
14321
|
type: KnowledgeCandidateTypeSchema.optional(),
|
|
12605
14322
|
title: string().trim().min(1).max(160).optional(),
|
|
@@ -13144,151 +14861,171 @@ const Route = createFileRoute("/api/knowledge/candidates/$candidateId/promote")(
|
|
|
13144
14861
|
}
|
|
13145
14862
|
}
|
|
13146
14863
|
});
|
|
13147
|
-
const IndexRoute = Route$
|
|
14864
|
+
const IndexRoute = Route$C.update({
|
|
13148
14865
|
id: "/",
|
|
13149
14866
|
path: "/",
|
|
13150
|
-
getParentRoute: () => Route$
|
|
14867
|
+
getParentRoute: () => Route$D
|
|
13151
14868
|
});
|
|
13152
|
-
const SessionSessionIdRoute = Route$
|
|
14869
|
+
const SessionSessionIdRoute = Route$B.update({
|
|
13153
14870
|
id: "/session/$sessionId",
|
|
13154
14871
|
path: "/session/$sessionId",
|
|
13155
|
-
getParentRoute: () => Route$
|
|
14872
|
+
getParentRoute: () => Route$D
|
|
13156
14873
|
});
|
|
13157
|
-
const ProxySplatRoute = Route$
|
|
14874
|
+
const ProxySplatRoute = Route$A.update({
|
|
13158
14875
|
id: "/proxy/$",
|
|
13159
14876
|
path: "/proxy/$",
|
|
13160
|
-
getParentRoute: () => Route$
|
|
14877
|
+
getParentRoute: () => Route$D
|
|
13161
14878
|
});
|
|
13162
|
-
const ApiSessionsRoute = Route$
|
|
14879
|
+
const ApiSessionsRoute = Route$z.update({
|
|
13163
14880
|
id: "/api/sessions",
|
|
13164
14881
|
path: "/api/sessions",
|
|
13165
|
-
getParentRoute: () => Route$
|
|
14882
|
+
getParentRoute: () => Route$D
|
|
13166
14883
|
});
|
|
13167
|
-
const ApiRunsRoute = Route$
|
|
14884
|
+
const ApiRunsRoute = Route$y.update({
|
|
13168
14885
|
id: "/api/runs",
|
|
13169
14886
|
path: "/api/runs",
|
|
13170
|
-
getParentRoute: () => Route$
|
|
14887
|
+
getParentRoute: () => Route$D
|
|
13171
14888
|
});
|
|
13172
|
-
const ApiProvidersRoute = Route$
|
|
14889
|
+
const ApiProvidersRoute = Route$x.update({
|
|
13173
14890
|
id: "/api/providers",
|
|
13174
14891
|
path: "/api/providers",
|
|
13175
|
-
getParentRoute: () => Route$
|
|
14892
|
+
getParentRoute: () => Route$D
|
|
13176
14893
|
});
|
|
13177
|
-
const ApiModelsRoute = Route$
|
|
14894
|
+
const ApiModelsRoute = Route$w.update({
|
|
13178
14895
|
id: "/api/models",
|
|
13179
14896
|
path: "/api/models",
|
|
13180
|
-
getParentRoute: () => Route$
|
|
14897
|
+
getParentRoute: () => Route$D
|
|
13181
14898
|
});
|
|
13182
|
-
const ApiMcpRoute = Route$
|
|
14899
|
+
const ApiMcpRoute = Route$v.update({
|
|
13183
14900
|
id: "/api/mcp",
|
|
13184
14901
|
path: "/api/mcp",
|
|
13185
|
-
getParentRoute: () => Route$
|
|
14902
|
+
getParentRoute: () => Route$D
|
|
13186
14903
|
});
|
|
13187
|
-
const ApiLogsRoute = Route$
|
|
14904
|
+
const ApiLogsRoute = Route$u.update({
|
|
13188
14905
|
id: "/api/logs",
|
|
13189
14906
|
path: "/api/logs",
|
|
13190
|
-
getParentRoute: () => Route$
|
|
14907
|
+
getParentRoute: () => Route$D
|
|
13191
14908
|
});
|
|
13192
|
-
const ApiHealthRoute = Route$
|
|
14909
|
+
const ApiHealthRoute = Route$t.update({
|
|
13193
14910
|
id: "/api/health",
|
|
13194
14911
|
path: "/api/health",
|
|
13195
|
-
getParentRoute: () => Route$
|
|
14912
|
+
getParentRoute: () => Route$D
|
|
13196
14913
|
});
|
|
13197
|
-
const ApiGroupsRoute = Route$
|
|
14914
|
+
const ApiGroupsRoute = Route$s.update({
|
|
13198
14915
|
id: "/api/groups",
|
|
13199
14916
|
path: "/api/groups",
|
|
13200
|
-
getParentRoute: () => Route$
|
|
14917
|
+
getParentRoute: () => Route$D
|
|
13201
14918
|
});
|
|
13202
|
-
const ApiConfigRoute = Route$
|
|
14919
|
+
const ApiConfigRoute = Route$r.update({
|
|
13203
14920
|
id: "/api/config",
|
|
13204
14921
|
path: "/api/config",
|
|
13205
|
-
getParentRoute: () => Route$
|
|
14922
|
+
getParentRoute: () => Route$D
|
|
13206
14923
|
});
|
|
13207
|
-
const
|
|
14924
|
+
const ApiAlertsRoute = Route$q.update({
|
|
14925
|
+
id: "/api/alerts",
|
|
14926
|
+
path: "/api/alerts",
|
|
14927
|
+
getParentRoute: () => Route$D
|
|
14928
|
+
});
|
|
14929
|
+
const ApiRunsRunIdRoute = Route$p.update({
|
|
13208
14930
|
id: "/$runId",
|
|
13209
14931
|
path: "/$runId",
|
|
13210
14932
|
getParentRoute: () => ApiRunsRoute
|
|
13211
14933
|
});
|
|
13212
|
-
const ApiProvidersScanRoute = Route$
|
|
14934
|
+
const ApiProvidersScanRoute = Route$o.update({
|
|
13213
14935
|
id: "/scan",
|
|
13214
14936
|
path: "/scan",
|
|
13215
14937
|
getParentRoute: () => ApiProvidersRoute
|
|
13216
14938
|
});
|
|
13217
|
-
const ApiProvidersImportRoute = Route$
|
|
14939
|
+
const ApiProvidersImportRoute = Route$n.update({
|
|
13218
14940
|
id: "/import",
|
|
13219
14941
|
path: "/import",
|
|
13220
14942
|
getParentRoute: () => ApiProvidersRoute
|
|
13221
14943
|
});
|
|
13222
|
-
const ApiProvidersExportRoute = Route$
|
|
14944
|
+
const ApiProvidersExportRoute = Route$m.update({
|
|
13223
14945
|
id: "/export",
|
|
13224
14946
|
path: "/export",
|
|
13225
14947
|
getParentRoute: () => ApiProvidersRoute
|
|
13226
14948
|
});
|
|
13227
|
-
const ApiProvidersProviderIdRoute = Route$
|
|
14949
|
+
const ApiProvidersProviderIdRoute = Route$l.update({
|
|
13228
14950
|
id: "/$providerId",
|
|
13229
14951
|
path: "/$providerId",
|
|
13230
14952
|
getParentRoute: () => ApiProvidersRoute
|
|
13231
14953
|
});
|
|
13232
|
-
const ApiLogsStreamRoute = Route$
|
|
14954
|
+
const ApiLogsStreamRoute = Route$k.update({
|
|
13233
14955
|
id: "/stream",
|
|
13234
14956
|
path: "/stream",
|
|
13235
14957
|
getParentRoute: () => ApiLogsRoute
|
|
13236
14958
|
});
|
|
13237
|
-
const
|
|
14959
|
+
const ApiLogsImportRoute = Route$j.update({
|
|
14960
|
+
id: "/import",
|
|
14961
|
+
path: "/import",
|
|
14962
|
+
getParentRoute: () => ApiLogsRoute
|
|
14963
|
+
});
|
|
14964
|
+
const ApiLogsIdRoute = Route$i.update({
|
|
13238
14965
|
id: "/$id",
|
|
13239
14966
|
path: "/$id",
|
|
13240
14967
|
getParentRoute: () => ApiLogsRoute
|
|
13241
14968
|
});
|
|
13242
|
-
const ApiKnowledgeSearchRoute = Route$
|
|
14969
|
+
const ApiKnowledgeSearchRoute = Route$h.update({
|
|
13243
14970
|
id: "/api/knowledge/search",
|
|
13244
14971
|
path: "/api/knowledge/search",
|
|
13245
|
-
getParentRoute: () => Route$
|
|
14972
|
+
getParentRoute: () => Route$D
|
|
13246
14973
|
});
|
|
13247
|
-
const ApiKnowledgeProjectContextRoute = Route$
|
|
14974
|
+
const ApiKnowledgeProjectContextRoute = Route$g.update({
|
|
13248
14975
|
id: "/api/knowledge/project-context",
|
|
13249
14976
|
path: "/api/knowledge/project-context",
|
|
13250
|
-
getParentRoute: () => Route$
|
|
14977
|
+
getParentRoute: () => Route$D
|
|
13251
14978
|
});
|
|
13252
|
-
const ApiKnowledgeCandidatesRoute = Route$
|
|
14979
|
+
const ApiKnowledgeCandidatesRoute = Route$f.update({
|
|
13253
14980
|
id: "/api/knowledge/candidates",
|
|
13254
14981
|
path: "/api/knowledge/candidates",
|
|
13255
|
-
getParentRoute: () => Route$
|
|
14982
|
+
getParentRoute: () => Route$D
|
|
13256
14983
|
});
|
|
13257
|
-
const ApiGroupsGroupIdRoute = Route$
|
|
14984
|
+
const ApiGroupsGroupIdRoute = Route$e.update({
|
|
13258
14985
|
id: "/$groupId",
|
|
13259
14986
|
path: "/$groupId",
|
|
13260
14987
|
getParentRoute: () => ApiGroupsRoute
|
|
13261
14988
|
});
|
|
13262
|
-
const ApiConfigPathsRoute = Route$
|
|
14989
|
+
const ApiConfigPathsRoute = Route$d.update({
|
|
13263
14990
|
id: "/paths",
|
|
13264
14991
|
path: "/paths",
|
|
13265
14992
|
getParentRoute: () => ApiConfigRoute
|
|
13266
14993
|
});
|
|
13267
|
-
const
|
|
14994
|
+
const ApiAlertsSummaryRoute = Route$c.update({
|
|
14995
|
+
id: "/summary",
|
|
14996
|
+
path: "/summary",
|
|
14997
|
+
getParentRoute: () => ApiAlertsRoute
|
|
14998
|
+
});
|
|
14999
|
+
const ApiRunsRunIdEvidenceRoute = Route$b.update({
|
|
13268
15000
|
id: "/evidence",
|
|
13269
15001
|
path: "/evidence",
|
|
13270
15002
|
getParentRoute: () => ApiRunsRunIdRoute
|
|
13271
15003
|
});
|
|
13272
|
-
const ApiProvidersProviderIdTestRoute = Route$
|
|
15004
|
+
const ApiProvidersProviderIdTestRoute = Route$a.update({
|
|
13273
15005
|
id: "/test",
|
|
13274
15006
|
path: "/test",
|
|
13275
15007
|
getParentRoute: () => ApiProvidersProviderIdRoute
|
|
13276
15008
|
});
|
|
13277
|
-
const ApiProvidersProviderIdModelMetadataRoute = Route$
|
|
15009
|
+
const ApiProvidersProviderIdModelMetadataRoute = Route$9.update({
|
|
13278
15010
|
id: "/model-metadata",
|
|
13279
15011
|
path: "/model-metadata",
|
|
13280
15012
|
getParentRoute: () => ApiProvidersProviderIdRoute
|
|
13281
15013
|
});
|
|
13282
|
-
const ApiLogsIdReplayRoute = Route$
|
|
15014
|
+
const ApiLogsIdReplayRoute = Route$8.update({
|
|
13283
15015
|
id: "/replay",
|
|
13284
15016
|
path: "/replay",
|
|
13285
15017
|
getParentRoute: () => ApiLogsIdRoute
|
|
13286
15018
|
});
|
|
13287
|
-
const ApiLogsIdChunksRoute = Route$
|
|
15019
|
+
const ApiLogsIdChunksRoute = Route$7.update({
|
|
13288
15020
|
id: "/chunks",
|
|
13289
15021
|
path: "/chunks",
|
|
13290
15022
|
getParentRoute: () => ApiLogsIdRoute
|
|
13291
15023
|
});
|
|
15024
|
+
const ApiLogsIdBodyRoute = Route$6.update({
|
|
15025
|
+
id: "/body",
|
|
15026
|
+
path: "/body",
|
|
15027
|
+
getParentRoute: () => ApiLogsIdRoute
|
|
15028
|
+
});
|
|
13292
15029
|
const ApiKnowledgeCandidatesCandidateIdRoute = Route$5.update({
|
|
13293
15030
|
id: "/$candidateId",
|
|
13294
15031
|
path: "/$candidateId",
|
|
@@ -13312,13 +15049,19 @@ const ApiProvidersProviderIdTestLogRoute = Route$2.update({
|
|
|
13312
15049
|
const ApiKnowledgeSessionsSessionIdCandidatesRoute = Route$1.update({
|
|
13313
15050
|
id: "/api/knowledge/sessions/$sessionId/candidates",
|
|
13314
15051
|
path: "/api/knowledge/sessions/$sessionId/candidates",
|
|
13315
|
-
getParentRoute: () => Route$
|
|
15052
|
+
getParentRoute: () => Route$D
|
|
13316
15053
|
});
|
|
13317
15054
|
const ApiKnowledgeCandidatesCandidateIdPromoteRoute = Route.update({
|
|
13318
15055
|
id: "/promote",
|
|
13319
15056
|
path: "/promote",
|
|
13320
15057
|
getParentRoute: () => ApiKnowledgeCandidatesCandidateIdRoute
|
|
13321
15058
|
});
|
|
15059
|
+
const ApiAlertsRouteChildren = {
|
|
15060
|
+
ApiAlertsSummaryRoute
|
|
15061
|
+
};
|
|
15062
|
+
const ApiAlertsRouteWithChildren = ApiAlertsRoute._addFileChildren(
|
|
15063
|
+
ApiAlertsRouteChildren
|
|
15064
|
+
);
|
|
13322
15065
|
const ApiConfigRouteChildren = {
|
|
13323
15066
|
ApiConfigPathsRoute
|
|
13324
15067
|
};
|
|
@@ -13337,6 +15080,7 @@ const ApiGroupsRouteWithChildren = ApiGroupsRoute._addFileChildren(
|
|
|
13337
15080
|
ApiGroupsRouteChildren
|
|
13338
15081
|
);
|
|
13339
15082
|
const ApiLogsIdRouteChildren = {
|
|
15083
|
+
ApiLogsIdBodyRoute,
|
|
13340
15084
|
ApiLogsIdChunksRoute,
|
|
13341
15085
|
ApiLogsIdReplayRoute
|
|
13342
15086
|
};
|
|
@@ -13345,6 +15089,7 @@ const ApiLogsIdRouteWithChildren = ApiLogsIdRoute._addFileChildren(
|
|
|
13345
15089
|
);
|
|
13346
15090
|
const ApiLogsRouteChildren = {
|
|
13347
15091
|
ApiLogsIdRoute: ApiLogsIdRouteWithChildren,
|
|
15092
|
+
ApiLogsImportRoute,
|
|
13348
15093
|
ApiLogsStreamRoute
|
|
13349
15094
|
};
|
|
13350
15095
|
const ApiLogsRouteWithChildren = ApiLogsRoute._addFileChildren(ApiLogsRouteChildren);
|
|
@@ -13394,6 +15139,7 @@ const ApiKnowledgeCandidatesRouteWithChildren = ApiKnowledgeCandidatesRoute._add
|
|
|
13394
15139
|
);
|
|
13395
15140
|
const rootRouteChildren = {
|
|
13396
15141
|
IndexRoute,
|
|
15142
|
+
ApiAlertsRoute: ApiAlertsRouteWithChildren,
|
|
13397
15143
|
ApiConfigRoute: ApiConfigRouteWithChildren,
|
|
13398
15144
|
ApiGroupsRoute: ApiGroupsRouteWithChildren,
|
|
13399
15145
|
ApiHealthRoute,
|
|
@@ -13410,7 +15156,7 @@ const rootRouteChildren = {
|
|
|
13410
15156
|
ApiKnowledgeSearchRoute,
|
|
13411
15157
|
ApiKnowledgeSessionsSessionIdCandidatesRoute
|
|
13412
15158
|
};
|
|
13413
|
-
const routeTree = Route$
|
|
15159
|
+
const routeTree = Route$D._addFileChildren(rootRouteChildren)._addFileTypes();
|
|
13414
15160
|
function getRouter() {
|
|
13415
15161
|
const router2 = createRouter({
|
|
13416
15162
|
routeTree,
|
|
@@ -13442,32 +15188,35 @@ export {
|
|
|
13442
15188
|
GroupEvidenceReadResponseSchema as G,
|
|
13443
15189
|
InspectorGroupsListResponseSchema as I,
|
|
13444
15190
|
KnowledgeCandidateSchema as K,
|
|
15191
|
+
LogBodyChunkSchema as L,
|
|
13445
15192
|
MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as M,
|
|
13446
15193
|
OpenAIRequestSchema as O,
|
|
13447
15194
|
ProviderConfigSchema as P,
|
|
13448
|
-
Route$
|
|
15195
|
+
Route$B as R,
|
|
13449
15196
|
TimeDisplayFormatSchema as T,
|
|
13450
15197
|
DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS as a,
|
|
13451
15198
|
DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS as b,
|
|
13452
15199
|
DEFAULT_TIME_DISPLAY_FORMAT as c,
|
|
13453
15200
|
RuntimeConfigSchema as d,
|
|
13454
15201
|
AnthropicRequestSchema as e,
|
|
13455
|
-
|
|
13456
|
-
|
|
13457
|
-
|
|
13458
|
-
|
|
13459
|
-
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
|
|
15202
|
+
parseOpenAIResponse as f,
|
|
15203
|
+
apiFormatForPath as g,
|
|
15204
|
+
getSessionPath as h,
|
|
15205
|
+
stripClaudeCodeBillingHeader as i,
|
|
15206
|
+
AlertSummarySchema as j,
|
|
15207
|
+
AlertListResponseSchema as k,
|
|
15208
|
+
GroupEvidenceExportResultSchema as l,
|
|
15209
|
+
DeleteInspectorGroupResponseSchema as m,
|
|
15210
|
+
providerHasContextMetadata as n,
|
|
15211
|
+
findProviderModelMetadata as o,
|
|
15212
|
+
packageJson as p,
|
|
15213
|
+
maskApiKey as q,
|
|
15214
|
+
createPendingProviderTestResults as r,
|
|
13468
15215
|
safeGetOwnProperty as s,
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
15216
|
+
ProviderTestResultsSchema as t,
|
|
15217
|
+
createFailedProviderTestResults as u,
|
|
15218
|
+
MAX_PROVIDER_TEST_TIMEOUT_SECONDS as v,
|
|
15219
|
+
resolveProviderContextWindow as w,
|
|
15220
|
+
isPlainRecord as x,
|
|
15221
|
+
router as y
|
|
13473
15222
|
};
|