@tonyclaw/agent-inspector 2.1.3 → 2.1.5
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-SAn2KFl2.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-DaiTFf7n.js +117 -0
- package/.output/public/assets/{ReplayDialog-_kCy9L9E.js → ReplayDialog-CCwz0YUV.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-DWp5pWsv.js → RequestAnatomy-DXcC4ydl.js} +1 -1
- package/.output/public/assets/{ResponseView-Ci92o6mt.js → ResponseView-Bh9t9aZF.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-C-1ZQl_b.js → StreamingChunkSequence-B69M2rr-.js} +1 -1
- package/.output/public/assets/_sessionId-6fF5JpyQ.js +1 -0
- package/.output/public/assets/index-Bcq8bZoK.css +1 -0
- package/.output/public/assets/index-DBSbw8Gd.js +1 -0
- package/.output/public/assets/{main-RgLvmIQk.js → main-DZVKUeg6.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-COVUf_EG.mjs} +3 -3
- package/.output/server/_ssr/{CompareDrawer-D44_F13_.mjs → CompareDrawer-DqQHO4tk.mjs} +3 -3
- package/.output/server/_ssr/{ProxyViewerContainer-Cx4p_awW.mjs → ProxyViewerContainer-BEeF4V-C.mjs} +1006 -75
- package/.output/server/_ssr/{ReplayDialog-wScCF3Oc.mjs → ReplayDialog-DUZbsd5x.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-Cf7R7PXS.mjs → RequestAnatomy-DKuIxoBj.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-7pVIZLL-.mjs → ResponseView-BB9CYmTJ.mjs} +3 -3
- package/.output/server/_ssr/{StreamingChunkSequence-Bs57_GbC.mjs → StreamingChunkSequence-CkY3uTjF.mjs} +3 -3
- package/.output/server/_ssr/{index-6eY__la9.mjs → index-CHTchkrO.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-DRZPhZB6.mjs → router-C8DJ5pQZ.mjs} +1972 -221
- package/.output/server/_tanstack-start-manifest_v-Z1ffcxDr.mjs +4 -0
- package/.output/server/index.mjs +68 -68
- 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/groups/GroupsDialog.tsx +41 -13
- 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/groupContract.ts +1 -0
- 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/src/services/groups.ts +1 -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-CHTchkrO.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-COVUf_EG.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 });
|
|
@@ -6571,6 +7158,7 @@ const InspectorGroupEvidenceSummarySchema = object({
|
|
|
6571
7158
|
const GroupEvidenceReadResponseSchema = object({
|
|
6572
7159
|
group: InspectorGroupSchema,
|
|
6573
7160
|
evidence: InspectorGroupEvidenceSchema,
|
|
7161
|
+
members: array(InspectorGroupExportMemberSchema).nullable(),
|
|
6574
7162
|
markdown: string(),
|
|
6575
7163
|
summary: InspectorGroupEvidenceSummarySchema.nullable(),
|
|
6576
7164
|
report: EvidenceReportSchema.nullable()
|
|
@@ -7246,19 +7834,19 @@ async function readJsonBody$6(request) {
|
|
|
7246
7834
|
return { ok: false };
|
|
7247
7835
|
}
|
|
7248
7836
|
}
|
|
7249
|
-
function parsePositiveInt$
|
|
7837
|
+
function parsePositiveInt$3(value, fallback) {
|
|
7250
7838
|
if (value === null) return fallback;
|
|
7251
7839
|
const parsed = Number(value);
|
|
7252
7840
|
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
7253
7841
|
return parsed;
|
|
7254
7842
|
}
|
|
7255
|
-
const Route$
|
|
7843
|
+
const Route$y = createFileRoute("/api/runs")({
|
|
7256
7844
|
server: {
|
|
7257
7845
|
handlers: {
|
|
7258
7846
|
GET: ({ request }) => {
|
|
7259
7847
|
const url = new URL(request.url);
|
|
7260
7848
|
if (url.searchParams.get("failures") === "1") {
|
|
7261
|
-
const limit = parsePositiveInt$
|
|
7849
|
+
const limit = parsePositiveInt$3(
|
|
7262
7850
|
url.searchParams.get("limit"),
|
|
7263
7851
|
RECENT_FAILURES_DEFAULT_LIMIT
|
|
7264
7852
|
);
|
|
@@ -7297,7 +7885,7 @@ const ProviderInputSchema = object({
|
|
|
7297
7885
|
modelMetadata: array(ProviderModelMetadataSchema).optional(),
|
|
7298
7886
|
source: _enum(["company", "personal"]).optional()
|
|
7299
7887
|
});
|
|
7300
|
-
const Route$
|
|
7888
|
+
const Route$x = createFileRoute("/api/providers")({
|
|
7301
7889
|
server: {
|
|
7302
7890
|
handlers: {
|
|
7303
7891
|
GET: ({ request }) => {
|
|
@@ -7331,14 +7919,14 @@ const Route$t = createFileRoute("/api/providers")({
|
|
|
7331
7919
|
}
|
|
7332
7920
|
}
|
|
7333
7921
|
});
|
|
7334
|
-
const Route$
|
|
7922
|
+
const Route$w = createFileRoute("/api/models")({
|
|
7335
7923
|
server: {
|
|
7336
7924
|
handlers: {
|
|
7337
7925
|
GET: () => Response.json(getModels())
|
|
7338
7926
|
}
|
|
7339
7927
|
}
|
|
7340
7928
|
});
|
|
7341
|
-
const version = "2.1.
|
|
7929
|
+
const version = "2.1.5";
|
|
7342
7930
|
const packageJson = {
|
|
7343
7931
|
version
|
|
7344
7932
|
};
|
|
@@ -7483,7 +8071,7 @@ function isCompletedMember(member) {
|
|
|
7483
8071
|
const status = memberEffectiveStatus(member);
|
|
7484
8072
|
return status === "completed";
|
|
7485
8073
|
}
|
|
7486
|
-
function isFailedMember(member) {
|
|
8074
|
+
function isFailedMember$1(member) {
|
|
7487
8075
|
const status = memberEffectiveStatus(member);
|
|
7488
8076
|
return status === "failed" || status === "cancelled";
|
|
7489
8077
|
}
|
|
@@ -7527,7 +8115,7 @@ function buildSummary(members) {
|
|
|
7527
8115
|
members.flatMap((member) => [member.member.provider, ...member.session?.providers ?? []])
|
|
7528
8116
|
),
|
|
7529
8117
|
completedMembers: members.filter(isCompletedMember).length,
|
|
7530
|
-
failedMembers: members.filter(isFailedMember).length,
|
|
8118
|
+
failedMembers: members.filter(isFailedMember$1).length,
|
|
7531
8119
|
runningMembers: members.filter(isRunningMember).length
|
|
7532
8120
|
};
|
|
7533
8121
|
}
|
|
@@ -7764,6 +8352,7 @@ function readInspectorGroupEvidence(groupId) {
|
|
|
7764
8352
|
return serviceOk({
|
|
7765
8353
|
group,
|
|
7766
8354
|
evidence: group.evidence,
|
|
8355
|
+
members: document?.members ?? null,
|
|
7767
8356
|
markdown,
|
|
7768
8357
|
summary: document?.summary ?? null,
|
|
7769
8358
|
report: document?.jenkinsReport ?? null
|
|
@@ -9839,7 +10428,7 @@ const PROMPT_NAMES = [
|
|
|
9839
10428
|
"inspector_generate_group_report",
|
|
9840
10429
|
"inspector_extract_repro_steps"
|
|
9841
10430
|
];
|
|
9842
|
-
const Route$
|
|
10431
|
+
const Route$v = createFileRoute("/api/mcp")({
|
|
9843
10432
|
server: {
|
|
9844
10433
|
handlers: {
|
|
9845
10434
|
// The SDK may issue either POST, GET, or DELETE. TanStack Start only
|
|
@@ -9855,15 +10444,15 @@ const LOG_SEARCH_DEFAULT_LIMIT = 10;
|
|
|
9855
10444
|
const LOG_SEARCH_MAX_LIMIT = 50;
|
|
9856
10445
|
const LOG_SEARCH_DEFAULT_SCAN_LIMIT = 200;
|
|
9857
10446
|
const LOG_SEARCH_MAX_SCAN_LIMIT = 1e3;
|
|
9858
|
-
function clampPositiveInt(value, fallback, max) {
|
|
10447
|
+
function clampPositiveInt$1(value, fallback, max) {
|
|
9859
10448
|
if (!Number.isInteger(value) || value < 1) return fallback;
|
|
9860
10449
|
return Math.min(value, max);
|
|
9861
10450
|
}
|
|
9862
10451
|
function clampLogSearchLimit(value) {
|
|
9863
|
-
return clampPositiveInt(value, LOG_SEARCH_DEFAULT_LIMIT, LOG_SEARCH_MAX_LIMIT);
|
|
10452
|
+
return clampPositiveInt$1(value, LOG_SEARCH_DEFAULT_LIMIT, LOG_SEARCH_MAX_LIMIT);
|
|
9864
10453
|
}
|
|
9865
10454
|
function clampLogSearchScanLimit(value) {
|
|
9866
|
-
return clampPositiveInt(value, LOG_SEARCH_DEFAULT_SCAN_LIMIT, LOG_SEARCH_MAX_SCAN_LIMIT);
|
|
10455
|
+
return clampPositiveInt$1(value, LOG_SEARCH_DEFAULT_SCAN_LIMIT, LOG_SEARCH_MAX_SCAN_LIMIT);
|
|
9867
10456
|
}
|
|
9868
10457
|
function queryTerms(query) {
|
|
9869
10458
|
return query.trim().toLowerCase().split(/\s+/).filter((term) => term.length > 0);
|
|
@@ -9944,7 +10533,7 @@ function parseNonNegativeInt(value, fallback) {
|
|
|
9944
10533
|
if (!Number.isInteger(parsed) || parsed < 0) return fallback;
|
|
9945
10534
|
return parsed;
|
|
9946
10535
|
}
|
|
9947
|
-
function parsePositiveInt(value, fallback) {
|
|
10536
|
+
function parsePositiveInt$2(value, fallback) {
|
|
9948
10537
|
if (value === null) return fallback;
|
|
9949
10538
|
const parsed = Number(value);
|
|
9950
10539
|
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
@@ -9956,7 +10545,7 @@ function parseOptionalPositiveInt(value) {
|
|
|
9956
10545
|
if (!Number.isInteger(parsed) || parsed < 1) return { ok: false };
|
|
9957
10546
|
return { ok: true, value: parsed };
|
|
9958
10547
|
}
|
|
9959
|
-
const Route$
|
|
10548
|
+
const Route$u = createFileRoute("/api/logs")({
|
|
9960
10549
|
server: {
|
|
9961
10550
|
handlers: {
|
|
9962
10551
|
GET: async ({ request }) => {
|
|
@@ -9978,8 +10567,8 @@ const Route$q = createFileRoute("/api/logs")({
|
|
|
9978
10567
|
const query = url.searchParams.get("q") ?? url.searchParams.get("search");
|
|
9979
10568
|
const offset = parseNonNegativeInt(url.searchParams.get("offset"), 0);
|
|
9980
10569
|
if (query !== null) {
|
|
9981
|
-
const limit2 = parsePositiveInt(url.searchParams.get("limit"), LOG_SEARCH_DEFAULT_LIMIT);
|
|
9982
|
-
const scanLimit = parsePositiveInt(
|
|
10570
|
+
const limit2 = parsePositiveInt$2(url.searchParams.get("limit"), LOG_SEARCH_DEFAULT_LIMIT);
|
|
10571
|
+
const scanLimit = parsePositiveInt$2(
|
|
9983
10572
|
url.searchParams.get("scanLimit"),
|
|
9984
10573
|
LOG_SEARCH_DEFAULT_SCAN_LIMIT
|
|
9985
10574
|
);
|
|
@@ -9987,7 +10576,7 @@ const Route$q = createFileRoute("/api/logs")({
|
|
|
9987
10576
|
await searchLogsPage({ query, sessionId, model, offset, limit: limit2, scanLimit })
|
|
9988
10577
|
);
|
|
9989
10578
|
}
|
|
9990
|
-
const limit = parsePositiveInt(url.searchParams.get("limit"), 50);
|
|
10579
|
+
const limit = parsePositiveInt$2(url.searchParams.get("limit"), 50);
|
|
9991
10580
|
const includeBodies = url.searchParams.get("compact") !== "1";
|
|
9992
10581
|
if (url.searchParams.get("cursor") === "1" || url.searchParams.get("cursor") === "true") {
|
|
9993
10582
|
const beforeLogId = parseOptionalPositiveInt(url.searchParams.get("beforeLogId"));
|
|
@@ -10057,7 +10646,7 @@ const Route$q = createFileRoute("/api/logs")({
|
|
|
10057
10646
|
}
|
|
10058
10647
|
});
|
|
10059
10648
|
logger.debug("Health endpoint loaded");
|
|
10060
|
-
const Route$
|
|
10649
|
+
const Route$t = createFileRoute("/api/health")({
|
|
10061
10650
|
server: {
|
|
10062
10651
|
handlers: {
|
|
10063
10652
|
GET: () => {
|
|
@@ -10075,7 +10664,7 @@ async function readJsonBody$5(request) {
|
|
|
10075
10664
|
return { ok: false };
|
|
10076
10665
|
}
|
|
10077
10666
|
}
|
|
10078
|
-
const Route$
|
|
10667
|
+
const Route$s = createFileRoute("/api/groups")({
|
|
10079
10668
|
server: {
|
|
10080
10669
|
handlers: {
|
|
10081
10670
|
GET: () => Response.json(listInspectorGroups()),
|
|
@@ -10105,7 +10694,7 @@ const RuntimeConfigPatchSchema = object({
|
|
|
10105
10694
|
}).strict().refine((v) => Object.keys(v).length > 0, {
|
|
10106
10695
|
message: "At least one field must be provided"
|
|
10107
10696
|
});
|
|
10108
|
-
const Route$
|
|
10697
|
+
const Route$r = createFileRoute("/api/config")({
|
|
10109
10698
|
server: {
|
|
10110
10699
|
handlers: {
|
|
10111
10700
|
GET: () => {
|
|
@@ -10134,107 +10723,703 @@ const Route$n = createFileRoute("/api/config")({
|
|
|
10134
10723
|
}
|
|
10135
10724
|
}
|
|
10136
10725
|
});
|
|
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
|
-
}
|
|
10726
|
+
const AlertSeveritySchema = _enum(["critical", "warning", "notice"]);
|
|
10727
|
+
const AlertStatusSchema = _enum(["open"]);
|
|
10728
|
+
const AlertSourceSchema = _enum(["proxy", "tool-schema", "run", "group"]);
|
|
10729
|
+
const AlertCategorySchema = _enum([
|
|
10730
|
+
"request-failure",
|
|
10731
|
+
"request-timeout",
|
|
10732
|
+
"slow-response",
|
|
10733
|
+
"tool-schema",
|
|
10734
|
+
"run-failure",
|
|
10735
|
+
"group-failure",
|
|
10736
|
+
"group-incomplete"
|
|
10737
|
+
]);
|
|
10738
|
+
const AlertEvidenceKindSchema = _enum(["log", "session", "run", "group"]);
|
|
10739
|
+
const AlertApiFormatSchema = _enum(["anthropic", "openai", "unknown"]);
|
|
10740
|
+
const AlertEvidenceLinkSchema = object({
|
|
10741
|
+
kind: AlertEvidenceKindSchema,
|
|
10742
|
+
id: string(),
|
|
10743
|
+
label: string(),
|
|
10744
|
+
href: string().nullable()
|
|
10176
10745
|
});
|
|
10177
|
-
const
|
|
10178
|
-
|
|
10179
|
-
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
|
|
10187
|
-
|
|
10746
|
+
const AlertSchema = object({
|
|
10747
|
+
id: string(),
|
|
10748
|
+
fingerprint: string(),
|
|
10749
|
+
severity: AlertSeveritySchema,
|
|
10750
|
+
category: AlertCategorySchema,
|
|
10751
|
+
source: AlertSourceSchema,
|
|
10752
|
+
status: AlertStatusSchema,
|
|
10753
|
+
title: string(),
|
|
10754
|
+
message: string(),
|
|
10755
|
+
count: number().int().positive(),
|
|
10756
|
+
firstSeenAt: string(),
|
|
10757
|
+
lastSeenAt: string(),
|
|
10758
|
+
logIds: array(number().int().positive()),
|
|
10759
|
+
sessionIds: array(string()),
|
|
10760
|
+
runIds: array(string()),
|
|
10761
|
+
groupIds: array(string()),
|
|
10762
|
+
provider: string().nullable(),
|
|
10763
|
+
model: string().nullable(),
|
|
10764
|
+
apiFormat: AlertApiFormatSchema.nullable(),
|
|
10765
|
+
evidence: array(AlertEvidenceLinkSchema),
|
|
10766
|
+
metadata: record(string(), JsonValueSchema)
|
|
10767
|
+
});
|
|
10768
|
+
const AlertCategoryCountSchema = object({
|
|
10769
|
+
category: AlertCategorySchema,
|
|
10770
|
+
count: number().int().nonnegative()
|
|
10771
|
+
});
|
|
10772
|
+
const AlertSummarySchema = object({
|
|
10773
|
+
total: number().int().nonnegative(),
|
|
10774
|
+
open: number().int().nonnegative(),
|
|
10775
|
+
critical: number().int().nonnegative(),
|
|
10776
|
+
warning: number().int().nonnegative(),
|
|
10777
|
+
notice: number().int().nonnegative(),
|
|
10778
|
+
byCategory: array(AlertCategoryCountSchema)
|
|
10779
|
+
});
|
|
10780
|
+
const AlertListResponseSchema = object({
|
|
10781
|
+
alerts: array(AlertSchema),
|
|
10782
|
+
total: number().int().nonnegative(),
|
|
10783
|
+
limit: number().int().positive(),
|
|
10784
|
+
summary: AlertSummarySchema
|
|
10785
|
+
});
|
|
10786
|
+
const DEFAULT_ALERT_LIMIT = 50;
|
|
10787
|
+
const MAX_ALERT_LIMIT = 200;
|
|
10788
|
+
const DEFAULT_ALERT_SCAN_LIMIT = 500;
|
|
10789
|
+
const MAX_ALERT_SCAN_LIMIT = 2e3;
|
|
10790
|
+
function clampPositiveInt(value, fallback, max) {
|
|
10791
|
+
if (value === void 0) return fallback;
|
|
10792
|
+
if (!Number.isInteger(value) || value < 1) return fallback;
|
|
10793
|
+
return Math.min(value, max);
|
|
10794
|
+
}
|
|
10795
|
+
function clampAlertLimit(value) {
|
|
10796
|
+
return clampPositiveInt(value, DEFAULT_ALERT_LIMIT, MAX_ALERT_LIMIT);
|
|
10797
|
+
}
|
|
10798
|
+
function clampAlertScanLimit(value) {
|
|
10799
|
+
return clampPositiveInt(value, DEFAULT_ALERT_SCAN_LIMIT, MAX_ALERT_SCAN_LIMIT);
|
|
10800
|
+
}
|
|
10801
|
+
function alertIdFor(value) {
|
|
10802
|
+
const digest = createHash("sha1").update(value).digest("hex").slice(0, 16);
|
|
10803
|
+
return `alert_${digest}`;
|
|
10804
|
+
}
|
|
10805
|
+
function sanitizeFingerprintPart(value) {
|
|
10806
|
+
if (value === null) return "-";
|
|
10807
|
+
return String(value).trim().toLowerCase().replace(/\s+/g, " ").slice(0, 240);
|
|
10808
|
+
}
|
|
10809
|
+
function fingerprint(parts) {
|
|
10810
|
+
return parts.map(sanitizeFingerprintPart).join("|");
|
|
10811
|
+
}
|
|
10812
|
+
function uniqueStrings$1(values) {
|
|
10813
|
+
return [...new Set(values)].sort();
|
|
10814
|
+
}
|
|
10815
|
+
function uniqueNumbers(values) {
|
|
10816
|
+
return [...new Set(values)].sort((left, right) => left - right);
|
|
10817
|
+
}
|
|
10818
|
+
function logEvidence(logId) {
|
|
10819
|
+
const id = String(logId);
|
|
10820
|
+
return { kind: "log", id, label: `Log #${id}`, href: `#log-${id}` };
|
|
10821
|
+
}
|
|
10822
|
+
function sessionEvidence(sessionId) {
|
|
10823
|
+
return {
|
|
10824
|
+
kind: "session",
|
|
10825
|
+
id: sessionId,
|
|
10826
|
+
label: `Session ${sessionId}`,
|
|
10827
|
+
href: getSessionPath(sessionId)
|
|
10828
|
+
};
|
|
10829
|
+
}
|
|
10830
|
+
function runEvidence(runId) {
|
|
10831
|
+
return { kind: "run", id: runId, label: `Run ${runId}`, href: null };
|
|
10832
|
+
}
|
|
10833
|
+
function groupEvidence(groupId) {
|
|
10834
|
+
return { kind: "group", id: groupId, label: `Group ${groupId}`, href: null };
|
|
10835
|
+
}
|
|
10836
|
+
function baseEvidence(logId, sessionId, runId, groupId) {
|
|
10837
|
+
const links = [];
|
|
10838
|
+
if (logId !== null) links.push(logEvidence(logId));
|
|
10839
|
+
if (sessionId !== null) links.push(sessionEvidence(sessionId));
|
|
10840
|
+
if (runId !== null) links.push(runEvidence(runId));
|
|
10841
|
+
if (groupId !== null) links.push(groupEvidence(groupId));
|
|
10842
|
+
return links;
|
|
10843
|
+
}
|
|
10844
|
+
function hasEquivalentEvidence(links, candidate) {
|
|
10845
|
+
return links.some((link) => link.kind === candidate.kind && link.id === candidate.id);
|
|
10846
|
+
}
|
|
10847
|
+
function mergeEvidence(left, right) {
|
|
10848
|
+
const merged = [...left];
|
|
10849
|
+
for (const link of right) {
|
|
10850
|
+
if (!hasEquivalentEvidence(merged, link)) merged.push(link);
|
|
10188
10851
|
}
|
|
10852
|
+
return merged;
|
|
10189
10853
|
}
|
|
10190
|
-
function
|
|
10191
|
-
|
|
10192
|
-
const val = envObj[key];
|
|
10193
|
-
return typeof val === "string" ? val.trim() : void 0;
|
|
10854
|
+
function firstString(left, right) {
|
|
10855
|
+
return left ?? right;
|
|
10194
10856
|
}
|
|
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
|
-
|
|
10857
|
+
function mergeAlert(existing, observation) {
|
|
10858
|
+
const logIds = observation.logId === null ? existing.logIds : [...existing.logIds, observation.logId];
|
|
10859
|
+
const sessionIds = observation.sessionId === null ? existing.sessionIds : [...existing.sessionIds, observation.sessionId];
|
|
10860
|
+
const runIds = observation.runId === null ? existing.runIds : [...existing.runIds, observation.runId];
|
|
10861
|
+
const groupIds = observation.groupId === null ? existing.groupIds : [...existing.groupIds, observation.groupId];
|
|
10862
|
+
return {
|
|
10863
|
+
...existing,
|
|
10864
|
+
count: existing.count + 1,
|
|
10865
|
+
firstSeenAt: observation.observedAt < existing.firstSeenAt ? observation.observedAt : existing.firstSeenAt,
|
|
10866
|
+
lastSeenAt: observation.observedAt > existing.lastSeenAt ? observation.observedAt : existing.lastSeenAt,
|
|
10867
|
+
logIds: uniqueNumbers(logIds),
|
|
10868
|
+
sessionIds: uniqueStrings$1(sessionIds),
|
|
10869
|
+
runIds: uniqueStrings$1(runIds),
|
|
10870
|
+
groupIds: uniqueStrings$1(groupIds),
|
|
10871
|
+
provider: firstString(existing.provider, observation.provider),
|
|
10872
|
+
model: firstString(existing.model, observation.model),
|
|
10873
|
+
apiFormat: existing.apiFormat ?? observation.apiFormat,
|
|
10874
|
+
evidence: mergeEvidence(existing.evidence, observation.evidence),
|
|
10875
|
+
metadata: { ...existing.metadata, ...observation.metadata }
|
|
10876
|
+
};
|
|
10877
|
+
}
|
|
10878
|
+
function observationToAlert(observation) {
|
|
10879
|
+
return {
|
|
10880
|
+
id: alertIdFor(observation.fingerprint),
|
|
10881
|
+
fingerprint: observation.fingerprint,
|
|
10882
|
+
severity: observation.severity,
|
|
10883
|
+
category: observation.category,
|
|
10884
|
+
source: observation.source,
|
|
10885
|
+
status: "open",
|
|
10886
|
+
title: observation.title,
|
|
10887
|
+
message: observation.message,
|
|
10888
|
+
count: 1,
|
|
10889
|
+
firstSeenAt: observation.observedAt,
|
|
10890
|
+
lastSeenAt: observation.observedAt,
|
|
10891
|
+
logIds: observation.logId === null ? [] : [observation.logId],
|
|
10892
|
+
sessionIds: observation.sessionId === null ? [] : [observation.sessionId],
|
|
10893
|
+
runIds: observation.runId === null ? [] : [observation.runId],
|
|
10894
|
+
groupIds: observation.groupId === null ? [] : [observation.groupId],
|
|
10895
|
+
provider: observation.provider,
|
|
10896
|
+
model: observation.model,
|
|
10897
|
+
apiFormat: observation.apiFormat,
|
|
10898
|
+
evidence: observation.evidence,
|
|
10899
|
+
metadata: observation.metadata
|
|
10900
|
+
};
|
|
10901
|
+
}
|
|
10902
|
+
function addObservation(map, observation) {
|
|
10903
|
+
const existing = map.get(observation.fingerprint);
|
|
10904
|
+
if (existing === void 0) {
|
|
10905
|
+
map.set(observation.fingerprint, observationToAlert(observation));
|
|
10906
|
+
return;
|
|
10231
10907
|
}
|
|
10908
|
+
map.set(observation.fingerprint, mergeAlert(existing, observation));
|
|
10232
10909
|
}
|
|
10233
|
-
function
|
|
10234
|
-
|
|
10235
|
-
|
|
10236
|
-
|
|
10237
|
-
|
|
10910
|
+
function lowerText(value) {
|
|
10911
|
+
if (value === null || value === void 0) return "";
|
|
10912
|
+
return value.toLowerCase();
|
|
10913
|
+
}
|
|
10914
|
+
function isTimeoutStatus(status) {
|
|
10915
|
+
return status === 408 || status === 504;
|
|
10916
|
+
}
|
|
10917
|
+
function isTimeoutLog(log) {
|
|
10918
|
+
const text = `${lowerText(log.error)} ${lowerText(log.responseText)}`;
|
|
10919
|
+
return isTimeoutStatus(log.responseStatus) || text.includes("timeout") || text.includes("timed out") || text.includes("abort");
|
|
10920
|
+
}
|
|
10921
|
+
function hasFailureStatus(status) {
|
|
10922
|
+
return status !== null && status >= 400;
|
|
10923
|
+
}
|
|
10924
|
+
function isFailedLog(log) {
|
|
10925
|
+
return log.error !== null && log.error !== void 0 && log.error.length > 0 ? true : hasFailureStatus(log.responseStatus);
|
|
10926
|
+
}
|
|
10927
|
+
function statusLabel(status) {
|
|
10928
|
+
return status === null ? "no status" : `HTTP ${String(status)}`;
|
|
10929
|
+
}
|
|
10930
|
+
function errorDetail(log) {
|
|
10931
|
+
if (log.error !== null && log.error !== void 0 && log.error.length > 0) return log.error;
|
|
10932
|
+
return statusLabel(log.responseStatus);
|
|
10933
|
+
}
|
|
10934
|
+
function requestFailureTitle(log, timeout) {
|
|
10935
|
+
if (log.isTest === true && timeout) return "Provider test timed out";
|
|
10936
|
+
if (log.isTest === true) return "Provider test failed";
|
|
10937
|
+
return timeout ? "Request timed out" : "Request failed";
|
|
10938
|
+
}
|
|
10939
|
+
function requestFailureCategory(timeout) {
|
|
10940
|
+
return timeout ? "request-timeout" : "request-failure";
|
|
10941
|
+
}
|
|
10942
|
+
function logProvider(log) {
|
|
10943
|
+
return log.providerName ?? null;
|
|
10944
|
+
}
|
|
10945
|
+
function requestFailureObservation(log) {
|
|
10946
|
+
if (!isFailedLog(log)) return null;
|
|
10947
|
+
const timeout = isTimeoutLog(log);
|
|
10948
|
+
const category = requestFailureCategory(timeout);
|
|
10949
|
+
const message = `${errorDetail(log)} while calling ${log.path}.`;
|
|
10950
|
+
return {
|
|
10951
|
+
fingerprint: fingerprint([
|
|
10952
|
+
"proxy",
|
|
10953
|
+
category,
|
|
10954
|
+
logProvider(log),
|
|
10955
|
+
log.model,
|
|
10956
|
+
log.responseStatus,
|
|
10957
|
+
errorDetail(log)
|
|
10958
|
+
]),
|
|
10959
|
+
severity: "critical",
|
|
10960
|
+
category,
|
|
10961
|
+
source: "proxy",
|
|
10962
|
+
title: requestFailureTitle(log, timeout),
|
|
10963
|
+
message,
|
|
10964
|
+
observedAt: log.timestamp,
|
|
10965
|
+
logId: log.id,
|
|
10966
|
+
sessionId: log.sessionId,
|
|
10967
|
+
runId: null,
|
|
10968
|
+
groupId: null,
|
|
10969
|
+
provider: logProvider(log),
|
|
10970
|
+
model: log.model,
|
|
10971
|
+
apiFormat: log.apiFormat,
|
|
10972
|
+
evidence: baseEvidence(log.id, log.sessionId, null, null),
|
|
10973
|
+
metadata: {
|
|
10974
|
+
path: log.path,
|
|
10975
|
+
status: log.responseStatus,
|
|
10976
|
+
error: log.error ?? null,
|
|
10977
|
+
isTest: log.isTest,
|
|
10978
|
+
streaming: log.streaming
|
|
10979
|
+
}
|
|
10980
|
+
};
|
|
10981
|
+
}
|
|
10982
|
+
function slowResponseObservation(log, slowResponseThresholdSeconds) {
|
|
10983
|
+
if (slowResponseThresholdSeconds <= 0) return null;
|
|
10984
|
+
if (isFailedLog(log)) return null;
|
|
10985
|
+
if (log.elapsedMs === null) return null;
|
|
10986
|
+
const thresholdMs = slowResponseThresholdSeconds * 1e3;
|
|
10987
|
+
if (log.elapsedMs < thresholdMs) return null;
|
|
10988
|
+
const elapsedSeconds = (log.elapsedMs / 1e3).toFixed(1);
|
|
10989
|
+
return {
|
|
10990
|
+
fingerprint: fingerprint(["proxy", "slow-response", logProvider(log), log.model, log.path]),
|
|
10991
|
+
severity: "warning",
|
|
10992
|
+
category: "slow-response",
|
|
10993
|
+
source: "proxy",
|
|
10994
|
+
title: "Slow model response",
|
|
10995
|
+
message: `Response took ${elapsedSeconds}s, above the ${String(
|
|
10996
|
+
slowResponseThresholdSeconds
|
|
10997
|
+
)}s threshold.`,
|
|
10998
|
+
observedAt: log.timestamp,
|
|
10999
|
+
logId: log.id,
|
|
11000
|
+
sessionId: log.sessionId,
|
|
11001
|
+
runId: null,
|
|
11002
|
+
groupId: null,
|
|
11003
|
+
provider: logProvider(log),
|
|
11004
|
+
model: log.model,
|
|
11005
|
+
apiFormat: log.apiFormat,
|
|
11006
|
+
evidence: baseEvidence(log.id, log.sessionId, null, null),
|
|
11007
|
+
metadata: {
|
|
11008
|
+
path: log.path,
|
|
11009
|
+
elapsedMs: log.elapsedMs,
|
|
11010
|
+
thresholdMs,
|
|
11011
|
+
streaming: log.streaming,
|
|
11012
|
+
firstChunkMs: log.firstChunkMs ?? null,
|
|
11013
|
+
totalStreamMs: log.totalStreamMs ?? null
|
|
11014
|
+
}
|
|
11015
|
+
};
|
|
11016
|
+
}
|
|
11017
|
+
function warningObservation(log, warning) {
|
|
11018
|
+
return {
|
|
11019
|
+
fingerprint: fingerprint(["tool-schema", logProvider(log), log.model, warning]),
|
|
11020
|
+
severity: "warning",
|
|
11021
|
+
category: "tool-schema",
|
|
11022
|
+
source: "tool-schema",
|
|
11023
|
+
title: "Tool calling argument warning",
|
|
11024
|
+
message: warning,
|
|
11025
|
+
observedAt: log.timestamp,
|
|
11026
|
+
logId: log.id,
|
|
11027
|
+
sessionId: log.sessionId,
|
|
11028
|
+
runId: null,
|
|
11029
|
+
groupId: null,
|
|
11030
|
+
provider: logProvider(log),
|
|
11031
|
+
model: log.model,
|
|
11032
|
+
apiFormat: log.apiFormat,
|
|
11033
|
+
evidence: baseEvidence(log.id, log.sessionId, null, null),
|
|
11034
|
+
metadata: {
|
|
11035
|
+
path: log.path,
|
|
11036
|
+
warning
|
|
11037
|
+
}
|
|
11038
|
+
};
|
|
11039
|
+
}
|
|
11040
|
+
function addLogObservations(map, logs, slowResponseThresholdSeconds) {
|
|
11041
|
+
for (const log of logs) {
|
|
11042
|
+
const failure = requestFailureObservation(log);
|
|
11043
|
+
if (failure !== null) addObservation(map, failure);
|
|
11044
|
+
const slow = slowResponseObservation(log, slowResponseThresholdSeconds);
|
|
11045
|
+
if (slow !== null) addObservation(map, slow);
|
|
11046
|
+
for (const warning of log.warnings ?? []) {
|
|
11047
|
+
addObservation(map, warningObservation(log, warning));
|
|
11048
|
+
}
|
|
11049
|
+
}
|
|
11050
|
+
}
|
|
11051
|
+
function alertSeverityFromFailure(failure) {
|
|
11052
|
+
switch (failure.classification.severity) {
|
|
11053
|
+
case "high":
|
|
11054
|
+
return "critical";
|
|
11055
|
+
case "medium":
|
|
11056
|
+
case "low":
|
|
11057
|
+
return "warning";
|
|
11058
|
+
case "none":
|
|
11059
|
+
return "notice";
|
|
11060
|
+
}
|
|
11061
|
+
}
|
|
11062
|
+
function providerFromRun(failure) {
|
|
11063
|
+
const provider = failure.run.metadata["provider"] ?? failure.run.metadata["providerName"];
|
|
11064
|
+
return typeof provider === "string" && provider.length > 0 ? provider : null;
|
|
11065
|
+
}
|
|
11066
|
+
function modelFromRun(failure) {
|
|
11067
|
+
const model = failure.run.metadata["model"] ?? failure.run.metadata["modelName"];
|
|
11068
|
+
return typeof model === "string" && model.length > 0 ? model : null;
|
|
11069
|
+
}
|
|
11070
|
+
function runFailureObservation(failure) {
|
|
11071
|
+
const groupId = failure.run.groupId;
|
|
11072
|
+
const logEvidenceLinks = failure.classification.evidenceLogIds.map(logEvidence);
|
|
11073
|
+
const links = mergeEvidence(
|
|
11074
|
+
baseEvidence(null, failure.sessionId, failure.run.id, groupId),
|
|
11075
|
+
logEvidenceLinks
|
|
11076
|
+
);
|
|
11077
|
+
return {
|
|
11078
|
+
fingerprint: fingerprint(["run", failure.run.id, failure.classification.category]),
|
|
11079
|
+
severity: alertSeverityFromFailure(failure),
|
|
11080
|
+
category: "run-failure",
|
|
11081
|
+
source: "run",
|
|
11082
|
+
title: `Run ${failure.run.status}`,
|
|
11083
|
+
message: failure.classification.summary,
|
|
11084
|
+
observedAt: failure.updatedAt,
|
|
11085
|
+
logId: failure.classification.evidenceLogIds[0] ?? null,
|
|
11086
|
+
sessionId: failure.sessionId,
|
|
11087
|
+
runId: failure.run.id,
|
|
11088
|
+
groupId,
|
|
11089
|
+
provider: providerFromRun(failure),
|
|
11090
|
+
model: modelFromRun(failure),
|
|
11091
|
+
apiFormat: null,
|
|
11092
|
+
evidence: links,
|
|
11093
|
+
metadata: {
|
|
11094
|
+
runStatus: failure.run.status,
|
|
11095
|
+
failureCategory: failure.classification.category,
|
|
11096
|
+
evidenceMarkdownPath: failure.evidenceMarkdownPath
|
|
11097
|
+
}
|
|
11098
|
+
};
|
|
11099
|
+
}
|
|
11100
|
+
function addRunFailureObservations(map, recentFailures) {
|
|
11101
|
+
for (const failure of recentFailures) {
|
|
11102
|
+
addObservation(map, runFailureObservation(failure));
|
|
11103
|
+
}
|
|
11104
|
+
}
|
|
11105
|
+
function memberProvider(member) {
|
|
11106
|
+
return member.provider !== null && member.provider.length > 0 ? member.provider : null;
|
|
11107
|
+
}
|
|
11108
|
+
function memberModel(member) {
|
|
11109
|
+
return member.model !== null && member.model.length > 0 ? member.model : null;
|
|
11110
|
+
}
|
|
11111
|
+
function isFailedMember(member) {
|
|
11112
|
+
return member.status === "failed" || member.status === "cancelled";
|
|
11113
|
+
}
|
|
11114
|
+
function groupFailureObservation(group) {
|
|
11115
|
+
if (group.status !== "failed" && group.status !== "cancelled") return null;
|
|
11116
|
+
return {
|
|
11117
|
+
fingerprint: fingerprint(["group", group.id, group.status]),
|
|
11118
|
+
severity: "critical",
|
|
11119
|
+
category: "group-failure",
|
|
11120
|
+
source: "group",
|
|
11121
|
+
title: `Group ${group.status}`,
|
|
11122
|
+
message: `${group.title} is marked ${group.status}.`,
|
|
11123
|
+
observedAt: group.updatedAt,
|
|
11124
|
+
logId: null,
|
|
11125
|
+
sessionId: null,
|
|
11126
|
+
runId: null,
|
|
11127
|
+
groupId: group.id,
|
|
11128
|
+
provider: null,
|
|
11129
|
+
model: null,
|
|
11130
|
+
apiFormat: null,
|
|
11131
|
+
evidence: baseEvidence(null, null, null, group.id),
|
|
11132
|
+
metadata: {
|
|
11133
|
+
groupStatus: group.status,
|
|
11134
|
+
memberCount: group.members.length
|
|
11135
|
+
}
|
|
11136
|
+
};
|
|
11137
|
+
}
|
|
11138
|
+
function groupMemberFailureObservation(group, member) {
|
|
11139
|
+
return {
|
|
11140
|
+
fingerprint: fingerprint(["group-member", group.id, member.id, member.status]),
|
|
11141
|
+
severity: "critical",
|
|
11142
|
+
category: "group-failure",
|
|
11143
|
+
source: "group",
|
|
11144
|
+
title: "Group member failed",
|
|
11145
|
+
message: `${member.label ?? member.sessionId} is marked ${member.status ?? "unknown"}.`,
|
|
11146
|
+
observedAt: member.updatedAt,
|
|
11147
|
+
logId: null,
|
|
11148
|
+
sessionId: member.sessionId,
|
|
11149
|
+
runId: member.runId,
|
|
11150
|
+
groupId: group.id,
|
|
11151
|
+
provider: memberProvider(member),
|
|
11152
|
+
model: memberModel(member),
|
|
11153
|
+
apiFormat: null,
|
|
11154
|
+
evidence: baseEvidence(null, member.sessionId, member.runId, group.id),
|
|
11155
|
+
metadata: {
|
|
11156
|
+
groupTitle: group.title,
|
|
11157
|
+
memberId: member.id,
|
|
11158
|
+
memberStatus: member.status
|
|
11159
|
+
}
|
|
11160
|
+
};
|
|
11161
|
+
}
|
|
11162
|
+
function groupIncompleteObservation(group, missingStatusCount) {
|
|
11163
|
+
return {
|
|
11164
|
+
fingerprint: fingerprint(["group-incomplete", group.id, missingStatusCount]),
|
|
11165
|
+
severity: "notice",
|
|
11166
|
+
category: "group-incomplete",
|
|
11167
|
+
source: "group",
|
|
11168
|
+
title: "Group has unclassified members",
|
|
11169
|
+
message: `${group.title} has ${String(missingStatusCount)} member(s) without a final status.`,
|
|
11170
|
+
observedAt: group.updatedAt,
|
|
11171
|
+
logId: null,
|
|
11172
|
+
sessionId: null,
|
|
11173
|
+
runId: null,
|
|
11174
|
+
groupId: group.id,
|
|
11175
|
+
provider: null,
|
|
11176
|
+
model: null,
|
|
11177
|
+
apiFormat: null,
|
|
11178
|
+
evidence: baseEvidence(null, null, null, group.id),
|
|
11179
|
+
metadata: {
|
|
11180
|
+
groupTitle: group.title,
|
|
11181
|
+
missingStatusCount
|
|
11182
|
+
}
|
|
11183
|
+
};
|
|
11184
|
+
}
|
|
11185
|
+
function addGroupObservations(map, groups) {
|
|
11186
|
+
for (const group of groups) {
|
|
11187
|
+
const groupFailure = groupFailureObservation(group);
|
|
11188
|
+
if (groupFailure !== null) addObservation(map, groupFailure);
|
|
11189
|
+
let missingStatusCount = 0;
|
|
11190
|
+
for (const member of group.members) {
|
|
11191
|
+
if (isFailedMember(member)) {
|
|
11192
|
+
addObservation(map, groupMemberFailureObservation(group, member));
|
|
11193
|
+
}
|
|
11194
|
+
if (member.status === null) missingStatusCount += 1;
|
|
11195
|
+
}
|
|
11196
|
+
if (missingStatusCount > 0) {
|
|
11197
|
+
addObservation(map, groupIncompleteObservation(group, missingStatusCount));
|
|
11198
|
+
}
|
|
11199
|
+
}
|
|
11200
|
+
}
|
|
11201
|
+
function alertMatchesFilters(alert, filters) {
|
|
11202
|
+
if (filters.severity !== void 0 && alert.severity !== filters.severity) return false;
|
|
11203
|
+
if (filters.category !== void 0 && alert.category !== filters.category) return false;
|
|
11204
|
+
if (filters.source !== void 0 && alert.source !== filters.source) return false;
|
|
11205
|
+
return true;
|
|
11206
|
+
}
|
|
11207
|
+
function sortAlerts(alerts) {
|
|
11208
|
+
return [...alerts].sort((left, right) => {
|
|
11209
|
+
const timeCompare = right.lastSeenAt.localeCompare(left.lastSeenAt);
|
|
11210
|
+
if (timeCompare !== 0) return timeCompare;
|
|
11211
|
+
return left.id.localeCompare(right.id);
|
|
11212
|
+
});
|
|
11213
|
+
}
|
|
11214
|
+
function buildAlertSummary(alerts) {
|
|
11215
|
+
let critical = 0;
|
|
11216
|
+
let warning = 0;
|
|
11217
|
+
let notice = 0;
|
|
11218
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
11219
|
+
for (const alert of alerts) {
|
|
11220
|
+
switch (alert.severity) {
|
|
11221
|
+
case "critical":
|
|
11222
|
+
critical += 1;
|
|
11223
|
+
break;
|
|
11224
|
+
case "warning":
|
|
11225
|
+
warning += 1;
|
|
11226
|
+
break;
|
|
11227
|
+
case "notice":
|
|
11228
|
+
notice += 1;
|
|
11229
|
+
break;
|
|
11230
|
+
}
|
|
11231
|
+
byCategory.set(alert.category, (byCategory.get(alert.category) ?? 0) + 1);
|
|
11232
|
+
}
|
|
11233
|
+
return {
|
|
11234
|
+
total: alerts.length,
|
|
11235
|
+
open: alerts.length,
|
|
11236
|
+
critical,
|
|
11237
|
+
warning,
|
|
11238
|
+
notice,
|
|
11239
|
+
byCategory: [...byCategory.entries()].map(([category, count]) => ({ category, count })).sort(
|
|
11240
|
+
(left, right) => right.count - left.count || left.category.localeCompare(right.category)
|
|
11241
|
+
)
|
|
11242
|
+
};
|
|
11243
|
+
}
|
|
11244
|
+
function collectAlertsFromEvidence(input) {
|
|
11245
|
+
const map = /* @__PURE__ */ new Map();
|
|
11246
|
+
addLogObservations(map, input.logs, input.slowResponseThresholdSeconds);
|
|
11247
|
+
addRunFailureObservations(map, input.recentFailures);
|
|
11248
|
+
addGroupObservations(map, input.groups);
|
|
11249
|
+
return sortAlerts([...map.values()]);
|
|
11250
|
+
}
|
|
11251
|
+
function filterAlerts(alerts, filters) {
|
|
11252
|
+
return alerts.filter((alert) => alertMatchesFilters(alert, filters));
|
|
11253
|
+
}
|
|
11254
|
+
async function listAlerts(options = {}) {
|
|
11255
|
+
const limit = clampAlertLimit(options.limit);
|
|
11256
|
+
const scanLimit = clampAlertScanLimit(options.scanLimit);
|
|
11257
|
+
const logPage = await listLogsCursorPage({
|
|
11258
|
+
limit: scanLimit,
|
|
11259
|
+
includeBodies: false,
|
|
11260
|
+
anchor: "newest"
|
|
11261
|
+
});
|
|
11262
|
+
const config = getConfig();
|
|
11263
|
+
const alerts = collectAlertsFromEvidence({
|
|
11264
|
+
logs: logPage.logs,
|
|
11265
|
+
recentFailures: listRecentFailures(scanLimit).failures,
|
|
11266
|
+
groups: listGroups(),
|
|
11267
|
+
slowResponseThresholdSeconds: config.slowResponseThresholdSeconds
|
|
11268
|
+
});
|
|
11269
|
+
const filtered = filterAlerts(alerts, options);
|
|
11270
|
+
return {
|
|
11271
|
+
alerts: filtered.slice(0, limit),
|
|
11272
|
+
total: filtered.length,
|
|
11273
|
+
limit,
|
|
11274
|
+
summary: buildAlertSummary(filtered)
|
|
11275
|
+
};
|
|
11276
|
+
}
|
|
11277
|
+
async function getAlertSummary(options = {}) {
|
|
11278
|
+
const response = await listAlerts({
|
|
11279
|
+
limit: MAX_ALERT_LIMIT,
|
|
11280
|
+
scanLimit: options.scanLimit
|
|
11281
|
+
});
|
|
11282
|
+
return response.summary;
|
|
11283
|
+
}
|
|
11284
|
+
function listInspectorAlerts(options) {
|
|
11285
|
+
return listAlerts(options);
|
|
11286
|
+
}
|
|
11287
|
+
function getInspectorAlertSummary(options) {
|
|
11288
|
+
return getAlertSummary(options);
|
|
11289
|
+
}
|
|
11290
|
+
function parsePositiveInt$1(value) {
|
|
11291
|
+
if (value === null) return void 0;
|
|
11292
|
+
const parsed = Number(value);
|
|
11293
|
+
if (!Number.isInteger(parsed) || parsed < 1) return void 0;
|
|
11294
|
+
return parsed;
|
|
11295
|
+
}
|
|
11296
|
+
function parseFilters(url) {
|
|
11297
|
+
const severityResult = AlertSeveritySchema.safeParse(url.searchParams.get("severity"));
|
|
11298
|
+
const categoryResult = AlertCategorySchema.safeParse(url.searchParams.get("category"));
|
|
11299
|
+
const sourceResult = AlertSourceSchema.safeParse(url.searchParams.get("source"));
|
|
11300
|
+
return {
|
|
11301
|
+
severity: severityResult.success ? severityResult.data : void 0,
|
|
11302
|
+
category: categoryResult.success ? categoryResult.data : void 0,
|
|
11303
|
+
source: sourceResult.success ? sourceResult.data : void 0
|
|
11304
|
+
};
|
|
11305
|
+
}
|
|
11306
|
+
const Route$q = createFileRoute("/api/alerts")({
|
|
11307
|
+
server: {
|
|
11308
|
+
handlers: {
|
|
11309
|
+
GET: async ({ request }) => {
|
|
11310
|
+
const url = new URL(request.url);
|
|
11311
|
+
return Response.json(
|
|
11312
|
+
await listInspectorAlerts({
|
|
11313
|
+
...parseFilters(url),
|
|
11314
|
+
limit: parsePositiveInt$1(url.searchParams.get("limit")),
|
|
11315
|
+
scanLimit: parsePositiveInt$1(url.searchParams.get("scanLimit"))
|
|
11316
|
+
})
|
|
11317
|
+
);
|
|
11318
|
+
}
|
|
11319
|
+
}
|
|
11320
|
+
}
|
|
11321
|
+
});
|
|
11322
|
+
async function readJsonBody$4(request) {
|
|
11323
|
+
try {
|
|
11324
|
+
const raw = await request.text();
|
|
11325
|
+
if (raw.trim().length === 0) return { ok: true, value: {} };
|
|
11326
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
11327
|
+
} catch {
|
|
11328
|
+
return { ok: false };
|
|
11329
|
+
}
|
|
11330
|
+
}
|
|
11331
|
+
const Route$p = createFileRoute("/api/runs/$runId")({
|
|
11332
|
+
server: {
|
|
11333
|
+
handlers: {
|
|
11334
|
+
GET: ({ params }) => {
|
|
11335
|
+
const run = getInspectorRun(params.runId);
|
|
11336
|
+
if (!run.ok) {
|
|
11337
|
+
return Response.json({ error: run.message }, { status: run.status });
|
|
11338
|
+
}
|
|
11339
|
+
return Response.json(run.value);
|
|
11340
|
+
},
|
|
11341
|
+
PATCH: async ({ params, request }) => {
|
|
11342
|
+
const body = await readJsonBody$4(request);
|
|
11343
|
+
if (!body.ok) {
|
|
11344
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
11345
|
+
}
|
|
11346
|
+
const parsed = UpdateInspectorRunInputSchema.safeParse(body.value);
|
|
11347
|
+
if (!parsed.success) {
|
|
11348
|
+
return Response.json(
|
|
11349
|
+
{ error: "Invalid request body", details: parsed.error.format() },
|
|
11350
|
+
{ status: 400 }
|
|
11351
|
+
);
|
|
11352
|
+
}
|
|
11353
|
+
const updated = updateInspectorRun(params.runId, parsed.data);
|
|
11354
|
+
if (!updated.ok) {
|
|
11355
|
+
return Response.json({ error: updated.message }, { status: updated.status });
|
|
11356
|
+
}
|
|
11357
|
+
return Response.json(updated.value);
|
|
11358
|
+
}
|
|
11359
|
+
}
|
|
11360
|
+
}
|
|
11361
|
+
});
|
|
11362
|
+
const ZHIPU_OPENAI_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
|
|
11363
|
+
const ZHIPU_CODING_OPENAI_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4";
|
|
11364
|
+
const ZHIPU_CODING_ANTHROPIC_BASE_URL = "https://open.bigmodel.cn/api/anthropic";
|
|
11365
|
+
function readJsonSafe(filePath) {
|
|
11366
|
+
try {
|
|
11367
|
+
if (!existsSync(filePath)) return null;
|
|
11368
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
11369
|
+
const parsed = JSON.parse(raw);
|
|
11370
|
+
return isPlainRecord(parsed) ? parsed : null;
|
|
11371
|
+
} catch {
|
|
11372
|
+
return null;
|
|
11373
|
+
}
|
|
11374
|
+
}
|
|
11375
|
+
function getEnvValue(envObj, key) {
|
|
11376
|
+
if (!isPlainRecord(envObj)) return void 0;
|
|
11377
|
+
const val = envObj[key];
|
|
11378
|
+
return typeof val === "string" ? val.trim() : void 0;
|
|
11379
|
+
}
|
|
11380
|
+
const KNOWN_PROVIDER_NAMES = {
|
|
11381
|
+
deepseek: "DeepSeek",
|
|
11382
|
+
minimaxi: "MiniMax",
|
|
11383
|
+
openai: "OpenAI",
|
|
11384
|
+
anthropic: "Anthropic",
|
|
11385
|
+
openrouter: "OpenRouter",
|
|
11386
|
+
groq: "Groq",
|
|
11387
|
+
together: "Together",
|
|
11388
|
+
fireworks: "Fireworks",
|
|
11389
|
+
bedrock: "Bedrock",
|
|
11390
|
+
vertexai: "Vertex AI",
|
|
11391
|
+
azure: "Azure",
|
|
11392
|
+
moonshot: "Moonshot",
|
|
11393
|
+
zhipu: "ZhipuAI",
|
|
11394
|
+
zhipuai: "ZhipuAI",
|
|
11395
|
+
bigmodel: "ZhipuAI",
|
|
11396
|
+
zai: "Z.AI",
|
|
11397
|
+
qwen: "Qwen",
|
|
11398
|
+
baichuan: "Baichuan",
|
|
11399
|
+
iflytek: "iFlytek",
|
|
11400
|
+
doubao: "Doubao",
|
|
11401
|
+
lingyiwanwu: "LingyiWanwu",
|
|
11402
|
+
stepfun: "StepFun"
|
|
11403
|
+
};
|
|
11404
|
+
function deriveNameFromUrl(url) {
|
|
11405
|
+
try {
|
|
11406
|
+
const hostname = new URL(url).hostname;
|
|
11407
|
+
const parts = hostname.split(".");
|
|
11408
|
+
const domain = parts.length >= 2 ? parts[parts.length - 2] ?? hostname : hostname;
|
|
11409
|
+
const domainLower = domain.toLowerCase();
|
|
11410
|
+
if (KNOWN_PROVIDER_NAMES[domainLower] !== void 0) {
|
|
11411
|
+
return KNOWN_PROVIDER_NAMES[domainLower];
|
|
11412
|
+
}
|
|
11413
|
+
return domain.charAt(0).toUpperCase() + domain.slice(1);
|
|
11414
|
+
} catch {
|
|
11415
|
+
return "Imported Provider";
|
|
11416
|
+
}
|
|
11417
|
+
}
|
|
11418
|
+
function detectClaudeCodeProviders() {
|
|
11419
|
+
const home = homedir();
|
|
11420
|
+
const results = [];
|
|
11421
|
+
const globalConfig = readJsonSafe(join(home, ".claude", "settings.json"));
|
|
11422
|
+
const localConfig = readJsonSafe(join(home, ".claude", "settings.local.json"));
|
|
10238
11423
|
const mergedEnv = {};
|
|
10239
11424
|
if (isPlainRecord(globalConfig)) {
|
|
10240
11425
|
const env = globalConfig["env"];
|
|
@@ -10600,7 +11785,7 @@ function scanExternalProviders() {
|
|
|
10600
11785
|
}
|
|
10601
11786
|
return { providers: filteredProviders, warnings };
|
|
10602
11787
|
}
|
|
10603
|
-
const Route$
|
|
11788
|
+
const Route$o = createFileRoute("/api/providers/scan")({
|
|
10604
11789
|
server: {
|
|
10605
11790
|
handlers: {
|
|
10606
11791
|
GET: () => {
|
|
@@ -10621,7 +11806,7 @@ const Route$l = createFileRoute("/api/providers/scan")({
|
|
|
10621
11806
|
}
|
|
10622
11807
|
});
|
|
10623
11808
|
union([string(), object({ providers: unknown() })]);
|
|
10624
|
-
const Route$
|
|
11809
|
+
const Route$n = createFileRoute("/api/providers/import")({
|
|
10625
11810
|
server: {
|
|
10626
11811
|
handlers: {
|
|
10627
11812
|
POST: async ({ request }) => {
|
|
@@ -10654,7 +11839,7 @@ const Route$k = createFileRoute("/api/providers/import")({
|
|
|
10654
11839
|
}
|
|
10655
11840
|
}
|
|
10656
11841
|
});
|
|
10657
|
-
const Route$
|
|
11842
|
+
const Route$m = createFileRoute("/api/providers/export")({
|
|
10658
11843
|
server: {
|
|
10659
11844
|
handlers: {
|
|
10660
11845
|
GET: ({ request }) => {
|
|
@@ -10687,7 +11872,7 @@ const ProviderUpdateSchema = object({
|
|
|
10687
11872
|
modelMetadata: array(ProviderModelMetadataSchema).optional(),
|
|
10688
11873
|
source: _enum(["company", "personal"]).optional()
|
|
10689
11874
|
});
|
|
10690
|
-
const Route$
|
|
11875
|
+
const Route$l = createFileRoute("/api/providers/$providerId")({
|
|
10691
11876
|
server: {
|
|
10692
11877
|
handlers: {
|
|
10693
11878
|
GET: ({ params, request }) => {
|
|
@@ -10722,7 +11907,7 @@ const Route$i = createFileRoute("/api/providers/$providerId")({
|
|
|
10722
11907
|
}
|
|
10723
11908
|
});
|
|
10724
11909
|
const INITIAL_STREAM_LOG_LIMIT = 100;
|
|
10725
|
-
const Route$
|
|
11910
|
+
const Route$k = createFileRoute("/api/logs/stream")({
|
|
10726
11911
|
server: {
|
|
10727
11912
|
handlers: {
|
|
10728
11913
|
GET: ({ request }) => {
|
|
@@ -10795,7 +11980,411 @@ const Route$h = createFileRoute("/api/logs/stream")({
|
|
|
10795
11980
|
}
|
|
10796
11981
|
}
|
|
10797
11982
|
});
|
|
10798
|
-
const
|
|
11983
|
+
const ManifestSchema = object({
|
|
11984
|
+
version: string().optional(),
|
|
11985
|
+
exportedAt: string().optional(),
|
|
11986
|
+
mode: string().optional(),
|
|
11987
|
+
redacted: boolean().optional(),
|
|
11988
|
+
logIds: array(number().int().positive()).optional()
|
|
11989
|
+
}).passthrough();
|
|
11990
|
+
const LogsArraySchema = array(CapturedLogSchema);
|
|
11991
|
+
const LogsEnvelopeSchema = object({ logs: array(CapturedLogSchema) }).passthrough();
|
|
11992
|
+
const StreamingChunksImportSchema = object({
|
|
11993
|
+
chunks: array(StreamingChunkSchema$1),
|
|
11994
|
+
truncated: boolean().optional().default(false)
|
|
11995
|
+
});
|
|
11996
|
+
const SEMVER_MAJOR_PATTERN = /^([0-9]+)\.[0-9]+\.[0-9]+(?:[-+].*)?$/;
|
|
11997
|
+
function readRecordProperty(value, name) {
|
|
11998
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
11999
|
+
const desc = Object.getOwnPropertyDescriptor(value, name);
|
|
12000
|
+
return desc === void 0 ? void 0 : desc.value;
|
|
12001
|
+
}
|
|
12002
|
+
function parseJson(text) {
|
|
12003
|
+
if (text === null) return null;
|
|
12004
|
+
try {
|
|
12005
|
+
const parsed = JSON.parse(text);
|
|
12006
|
+
return parsed;
|
|
12007
|
+
} catch {
|
|
12008
|
+
return null;
|
|
12009
|
+
}
|
|
12010
|
+
}
|
|
12011
|
+
function parseJsonLogs(text) {
|
|
12012
|
+
const parsed = parseJson(text);
|
|
12013
|
+
const direct = LogsArraySchema.safeParse(parsed);
|
|
12014
|
+
if (direct.success) return direct.data;
|
|
12015
|
+
const envelope = LogsEnvelopeSchema.safeParse(parsed);
|
|
12016
|
+
if (envelope.success) return envelope.data.logs;
|
|
12017
|
+
return null;
|
|
12018
|
+
}
|
|
12019
|
+
function parseJsonlLogs(text) {
|
|
12020
|
+
const logs = [];
|
|
12021
|
+
let skipped = 0;
|
|
12022
|
+
for (const line of text.split(/\r?\n/)) {
|
|
12023
|
+
if (line.trim() === "") continue;
|
|
12024
|
+
const parsed = CapturedLogSchema.safeParse(parseJson(line));
|
|
12025
|
+
if (parsed.success) {
|
|
12026
|
+
logs.push(parsed.data);
|
|
12027
|
+
} else {
|
|
12028
|
+
skipped += 1;
|
|
12029
|
+
}
|
|
12030
|
+
}
|
|
12031
|
+
return { logs, skipped };
|
|
12032
|
+
}
|
|
12033
|
+
function readStringProperty(value, name) {
|
|
12034
|
+
const property = readRecordProperty(value, name);
|
|
12035
|
+
return typeof property === "string" ? property : null;
|
|
12036
|
+
}
|
|
12037
|
+
function hasProperty(value, name) {
|
|
12038
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
12039
|
+
return Object.getOwnPropertyDescriptor(value, name) !== void 0;
|
|
12040
|
+
}
|
|
12041
|
+
function modelFromRequestText(requestText) {
|
|
12042
|
+
return readStringProperty(parseJson(requestText), "model");
|
|
12043
|
+
}
|
|
12044
|
+
function inferApiFormatFromBody(path2, model, requestText) {
|
|
12045
|
+
const pathFormat = apiFormatForPath(path2);
|
|
12046
|
+
if (pathFormat !== "unknown") return pathFormat;
|
|
12047
|
+
const normalizedModel = model?.toLowerCase() ?? "";
|
|
12048
|
+
if (normalizedModel.startsWith("claude-")) return "anthropic";
|
|
12049
|
+
if (normalizedModel.startsWith("gpt-") || normalizedModel.startsWith("o1-") || normalizedModel.startsWith("o3-") || normalizedModel.startsWith("o4-") || normalizedModel.startsWith("deepseek-") || normalizedModel.startsWith("glm-") || normalizedModel.startsWith("qwen")) {
|
|
12050
|
+
return "openai";
|
|
12051
|
+
}
|
|
12052
|
+
const parsedRequest = parseJson(requestText);
|
|
12053
|
+
if (hasProperty(parsedRequest, "system") || hasProperty(parsedRequest, "max_tokens")) {
|
|
12054
|
+
return "anthropic";
|
|
12055
|
+
}
|
|
12056
|
+
return "openai";
|
|
12057
|
+
}
|
|
12058
|
+
function defaultPathForApiFormat(apiFormat) {
|
|
12059
|
+
switch (apiFormat) {
|
|
12060
|
+
case "anthropic":
|
|
12061
|
+
return "/v1/messages";
|
|
12062
|
+
case "openai":
|
|
12063
|
+
return "/v1/chat/completions";
|
|
12064
|
+
case "unknown":
|
|
12065
|
+
return "/v1/chat/completions";
|
|
12066
|
+
}
|
|
12067
|
+
}
|
|
12068
|
+
function normalizeTimestamp(value, fallback) {
|
|
12069
|
+
return Number.isNaN(new Date(value).getTime()) ? fallback : value;
|
|
12070
|
+
}
|
|
12071
|
+
function responseStatusFromText(responseText) {
|
|
12072
|
+
if (responseText === null) return null;
|
|
12073
|
+
const parsed = parseJson(responseText);
|
|
12074
|
+
return hasProperty(parsed, "error") ? 500 : 200;
|
|
12075
|
+
}
|
|
12076
|
+
function mergeWarnings(existing, generated) {
|
|
12077
|
+
const values = [];
|
|
12078
|
+
for (const warning of existing ?? []) {
|
|
12079
|
+
if (!values.includes(warning)) values.push(warning);
|
|
12080
|
+
}
|
|
12081
|
+
for (const warning of generated) {
|
|
12082
|
+
if (!values.includes(warning)) values.push(warning);
|
|
12083
|
+
}
|
|
12084
|
+
return values.length === 0 ? void 0 : values;
|
|
12085
|
+
}
|
|
12086
|
+
function withToolWarnings(log) {
|
|
12087
|
+
const warnings = analyzeToolSchemaWarnings({
|
|
12088
|
+
rawRequestBody: log.rawRequestBody,
|
|
12089
|
+
responseText: log.responseText,
|
|
12090
|
+
apiFormat: log.apiFormat
|
|
12091
|
+
});
|
|
12092
|
+
return {
|
|
12093
|
+
...log,
|
|
12094
|
+
warnings: mergeWarnings(log.warnings, warnings)
|
|
12095
|
+
};
|
|
12096
|
+
}
|
|
12097
|
+
function streamingChunksFromText(text) {
|
|
12098
|
+
const parsed = StreamingChunksImportSchema.safeParse(parseJson(text));
|
|
12099
|
+
return parsed.success ? parsed.data : void 0;
|
|
12100
|
+
}
|
|
12101
|
+
function draftFromCapturedLog(log, requestText, responseText, streamingChunks) {
|
|
12102
|
+
const rawRequestBody = requestText ?? log.rawRequestBody;
|
|
12103
|
+
const response = responseText ?? log.responseText;
|
|
12104
|
+
const model = log.model ?? modelFromRequestText(rawRequestBody);
|
|
12105
|
+
const apiFormat = log.apiFormat === "unknown" ? inferApiFormatFromBody(log.path, model, rawRequestBody) : log.apiFormat;
|
|
12106
|
+
const path2 = log.path.trim() === "" ? defaultPathForApiFormat(apiFormat) : log.path;
|
|
12107
|
+
return withToolWarnings({
|
|
12108
|
+
timestamp: normalizeTimestamp(log.timestamp, (/* @__PURE__ */ new Date()).toISOString()),
|
|
12109
|
+
method: log.method.trim() === "" ? "POST" : log.method,
|
|
12110
|
+
path: path2,
|
|
12111
|
+
model,
|
|
12112
|
+
sessionId: null,
|
|
12113
|
+
rawRequestBody,
|
|
12114
|
+
responseStatus: log.responseStatus ?? responseStatusFromText(response),
|
|
12115
|
+
responseText: response,
|
|
12116
|
+
inputTokens: log.inputTokens,
|
|
12117
|
+
outputTokens: log.outputTokens,
|
|
12118
|
+
cacheCreationInputTokens: log.cacheCreationInputTokens,
|
|
12119
|
+
cacheReadInputTokens: log.cacheReadInputTokens,
|
|
12120
|
+
elapsedMs: log.elapsedMs,
|
|
12121
|
+
firstChunkMs: log.firstChunkMs ?? null,
|
|
12122
|
+
totalStreamMs: log.totalStreamMs ?? null,
|
|
12123
|
+
tokensPerSecond: log.tokensPerSecond ?? null,
|
|
12124
|
+
streaming: log.streaming || streamingChunks !== void 0,
|
|
12125
|
+
userAgent: log.userAgent,
|
|
12126
|
+
origin: log.origin,
|
|
12127
|
+
rawHeaders: log.rawHeaders,
|
|
12128
|
+
headers: log.headers,
|
|
12129
|
+
apiFormat,
|
|
12130
|
+
isTest: false,
|
|
12131
|
+
replayOfLogId: null,
|
|
12132
|
+
providerName: log.providerName ?? null,
|
|
12133
|
+
clientPort: log.clientPort ?? null,
|
|
12134
|
+
clientPid: log.clientPid ?? null,
|
|
12135
|
+
clientCwd: log.clientCwd ?? null,
|
|
12136
|
+
clientProjectFolder: log.clientProjectFolder ?? null,
|
|
12137
|
+
streamingChunks,
|
|
12138
|
+
streamingChunksPath: null,
|
|
12139
|
+
rawRequestBodyBytes: log.rawRequestBodyBytes,
|
|
12140
|
+
responseTextBytes: log.responseTextBytes,
|
|
12141
|
+
bodyContentMode: "full",
|
|
12142
|
+
warnings: log.warnings,
|
|
12143
|
+
error: log.error ?? null
|
|
12144
|
+
});
|
|
12145
|
+
}
|
|
12146
|
+
function legacyDraftFromParts(input) {
|
|
12147
|
+
const model = modelFromRequestText(input.requestText);
|
|
12148
|
+
const apiFormat = inferApiFormatFromBody("", model, input.requestText);
|
|
12149
|
+
return withToolWarnings({
|
|
12150
|
+
timestamp: input.exportedAt,
|
|
12151
|
+
method: "POST",
|
|
12152
|
+
path: defaultPathForApiFormat(apiFormat),
|
|
12153
|
+
model,
|
|
12154
|
+
sessionId: null,
|
|
12155
|
+
rawRequestBody: input.requestText,
|
|
12156
|
+
responseStatus: responseStatusFromText(input.responseText),
|
|
12157
|
+
responseText: input.responseText,
|
|
12158
|
+
inputTokens: null,
|
|
12159
|
+
outputTokens: null,
|
|
12160
|
+
cacheCreationInputTokens: null,
|
|
12161
|
+
cacheReadInputTokens: null,
|
|
12162
|
+
elapsedMs: null,
|
|
12163
|
+
firstChunkMs: null,
|
|
12164
|
+
totalStreamMs: null,
|
|
12165
|
+
tokensPerSecond: null,
|
|
12166
|
+
streaming: input.streamingChunks !== void 0,
|
|
12167
|
+
userAgent: "agent-inspector-import",
|
|
12168
|
+
origin: null,
|
|
12169
|
+
apiFormat,
|
|
12170
|
+
isTest: false,
|
|
12171
|
+
replayOfLogId: null,
|
|
12172
|
+
providerName: null,
|
|
12173
|
+
clientPort: null,
|
|
12174
|
+
clientPid: null,
|
|
12175
|
+
clientCwd: null,
|
|
12176
|
+
clientProjectFolder: null,
|
|
12177
|
+
streamingChunks: input.streamingChunks,
|
|
12178
|
+
streamingChunksPath: null,
|
|
12179
|
+
bodyContentMode: "full",
|
|
12180
|
+
error: null
|
|
12181
|
+
});
|
|
12182
|
+
}
|
|
12183
|
+
async function readZipText(zip, path2) {
|
|
12184
|
+
const file = zip.file(path2);
|
|
12185
|
+
return file === null ? null : await file.async("text");
|
|
12186
|
+
}
|
|
12187
|
+
async function readManifest(zip) {
|
|
12188
|
+
const text = await readZipText(zip, "manifest.json");
|
|
12189
|
+
const parsed = ManifestSchema.safeParse(parseJson(text));
|
|
12190
|
+
return parsed.success ? parsed.data : null;
|
|
12191
|
+
}
|
|
12192
|
+
function versionMajor(version2) {
|
|
12193
|
+
const match = SEMVER_MAJOR_PATTERN.exec(version2);
|
|
12194
|
+
if (match === null) return null;
|
|
12195
|
+
const major = match[1];
|
|
12196
|
+
return major === void 0 ? null : Number.parseInt(major, 10);
|
|
12197
|
+
}
|
|
12198
|
+
function validateManifestVersion(manifest) {
|
|
12199
|
+
const exportedVersion = manifest?.version;
|
|
12200
|
+
if (exportedVersion === void 0) {
|
|
12201
|
+
return {
|
|
12202
|
+
ok: true,
|
|
12203
|
+
warning: "Imported legacy export without version metadata. Compatibility could not be verified."
|
|
12204
|
+
};
|
|
12205
|
+
}
|
|
12206
|
+
const exportedMajor = versionMajor(exportedVersion);
|
|
12207
|
+
if (exportedMajor === null) {
|
|
12208
|
+
return {
|
|
12209
|
+
ok: false,
|
|
12210
|
+
message: `Unsupported export version "${exportedVersion}".`
|
|
12211
|
+
};
|
|
12212
|
+
}
|
|
12213
|
+
const currentMajor = versionMajor(packageJson.version);
|
|
12214
|
+
if (currentMajor === null) {
|
|
12215
|
+
return {
|
|
12216
|
+
ok: true,
|
|
12217
|
+
warning: `Current Agent Inspector version "${packageJson.version}" could not be verified against export version "${exportedVersion}".`
|
|
12218
|
+
};
|
|
12219
|
+
}
|
|
12220
|
+
if (exportedMajor !== currentMajor) {
|
|
12221
|
+
return {
|
|
12222
|
+
ok: false,
|
|
12223
|
+
message: `Export version mismatch: archive was created by Agent Inspector v${exportedVersion}, current version is v${packageJson.version}. Import with a matching major version.`
|
|
12224
|
+
};
|
|
12225
|
+
}
|
|
12226
|
+
if (exportedVersion !== packageJson.version) {
|
|
12227
|
+
return {
|
|
12228
|
+
ok: true,
|
|
12229
|
+
warning: `Imported export from Agent Inspector v${exportedVersion}; current version is v${packageJson.version}.`
|
|
12230
|
+
};
|
|
12231
|
+
}
|
|
12232
|
+
return { ok: true, warning: null };
|
|
12233
|
+
}
|
|
12234
|
+
async function parseZipLogImport(data) {
|
|
12235
|
+
const warnings = [];
|
|
12236
|
+
const zip = await JSZip.loadAsync(data);
|
|
12237
|
+
const manifest = await readManifest(zip);
|
|
12238
|
+
const versionCheck = validateManifestVersion(manifest);
|
|
12239
|
+
if (!versionCheck.ok) {
|
|
12240
|
+
return {
|
|
12241
|
+
ok: false,
|
|
12242
|
+
message: versionCheck.message,
|
|
12243
|
+
warnings
|
|
12244
|
+
};
|
|
12245
|
+
}
|
|
12246
|
+
if (versionCheck.warning !== null) {
|
|
12247
|
+
warnings.push(versionCheck.warning);
|
|
12248
|
+
}
|
|
12249
|
+
const exportedAt = normalizeTimestamp(manifest?.exportedAt ?? "", (/* @__PURE__ */ new Date()).toISOString());
|
|
12250
|
+
if (manifest?.redacted === true) {
|
|
12251
|
+
warnings.push("Imported redacted export. Secrets and some replay details may be unavailable.");
|
|
12252
|
+
}
|
|
12253
|
+
const metadataText2 = await readZipText(zip, "logs.json");
|
|
12254
|
+
const metadataLogs = metadataText2 === null ? null : parseJsonLogs(metadataText2);
|
|
12255
|
+
const logs = [];
|
|
12256
|
+
let skipped = 0;
|
|
12257
|
+
if (metadataLogs !== null) {
|
|
12258
|
+
for (const log of metadataLogs) {
|
|
12259
|
+
const requestText = await readZipText(zip, `#${String(log.id)}.Request.json`);
|
|
12260
|
+
const responseText = await readZipText(zip, `#${String(log.id)}.Response.json`);
|
|
12261
|
+
const streamingText = await readZipText(zip, `#${String(log.id)}.SSE.Response.json`);
|
|
12262
|
+
logs.push(
|
|
12263
|
+
draftFromCapturedLog(
|
|
12264
|
+
log,
|
|
12265
|
+
requestText,
|
|
12266
|
+
responseText,
|
|
12267
|
+
streamingChunksFromText(streamingText)
|
|
12268
|
+
)
|
|
12269
|
+
);
|
|
12270
|
+
}
|
|
12271
|
+
return { ok: true, logs, skipped, warnings };
|
|
12272
|
+
}
|
|
12273
|
+
for (const originalId of manifest?.logIds ?? []) {
|
|
12274
|
+
const requestText = await readZipText(zip, `#${String(originalId)}.Request.json`);
|
|
12275
|
+
const responseText = await readZipText(zip, `#${String(originalId)}.Response.json`);
|
|
12276
|
+
const streamingText = await readZipText(zip, `#${String(originalId)}.SSE.Response.json`);
|
|
12277
|
+
if (requestText === null && responseText === null && streamingText === null) {
|
|
12278
|
+
skipped += 1;
|
|
12279
|
+
continue;
|
|
12280
|
+
}
|
|
12281
|
+
logs.push(
|
|
12282
|
+
legacyDraftFromParts({
|
|
12283
|
+
exportedAt,
|
|
12284
|
+
requestText,
|
|
12285
|
+
responseText,
|
|
12286
|
+
streamingChunks: streamingChunksFromText(streamingText)
|
|
12287
|
+
})
|
|
12288
|
+
);
|
|
12289
|
+
}
|
|
12290
|
+
if (logs.length === 0) {
|
|
12291
|
+
return {
|
|
12292
|
+
ok: false,
|
|
12293
|
+
message: "No importable logs were found in the archive.",
|
|
12294
|
+
warnings
|
|
12295
|
+
};
|
|
12296
|
+
}
|
|
12297
|
+
return { ok: true, logs, skipped, warnings };
|
|
12298
|
+
}
|
|
12299
|
+
function looksLikeZip(data, fileName) {
|
|
12300
|
+
if (fileName.toLowerCase().endsWith(".zip")) return true;
|
|
12301
|
+
return data[0] === 80 && data[1] === 75;
|
|
12302
|
+
}
|
|
12303
|
+
function parseTextLogImport(text) {
|
|
12304
|
+
const jsonLogs = parseJsonLogs(text);
|
|
12305
|
+
if (jsonLogs !== null) {
|
|
12306
|
+
return {
|
|
12307
|
+
ok: true,
|
|
12308
|
+
logs: jsonLogs.map((log) => draftFromCapturedLog(log, null, null, void 0)),
|
|
12309
|
+
skipped: 0,
|
|
12310
|
+
warnings: []
|
|
12311
|
+
};
|
|
12312
|
+
}
|
|
12313
|
+
const jsonl = parseJsonlLogs(text);
|
|
12314
|
+
if (jsonl.logs.length > 0) {
|
|
12315
|
+
return {
|
|
12316
|
+
ok: true,
|
|
12317
|
+
logs: jsonl.logs.map((log) => draftFromCapturedLog(log, null, null, void 0)),
|
|
12318
|
+
skipped: jsonl.skipped,
|
|
12319
|
+
warnings: []
|
|
12320
|
+
};
|
|
12321
|
+
}
|
|
12322
|
+
return {
|
|
12323
|
+
ok: false,
|
|
12324
|
+
message: "Unsupported import file. Use an Agent Inspector export ZIP, logs.json, or JSONL file.",
|
|
12325
|
+
warnings: []
|
|
12326
|
+
};
|
|
12327
|
+
}
|
|
12328
|
+
async function parseImportedLogFile(input) {
|
|
12329
|
+
try {
|
|
12330
|
+
if (looksLikeZip(input.data, input.fileName)) {
|
|
12331
|
+
return await parseZipLogImport(input.data);
|
|
12332
|
+
}
|
|
12333
|
+
return parseTextLogImport(new TextDecoder("utf-8").decode(input.data));
|
|
12334
|
+
} catch (err) {
|
|
12335
|
+
return {
|
|
12336
|
+
ok: false,
|
|
12337
|
+
message: err instanceof Error ? err.message : "Failed to parse import file.",
|
|
12338
|
+
warnings: []
|
|
12339
|
+
};
|
|
12340
|
+
}
|
|
12341
|
+
}
|
|
12342
|
+
function sessionNameFromImportFileName(fileName) {
|
|
12343
|
+
const normalized = fileName.replaceAll("\\", "/");
|
|
12344
|
+
const base = basename(normalized).replace(/\.(zip|json|jsonl)$/i, "").trim();
|
|
12345
|
+
return base === "" ? `import-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}` : base;
|
|
12346
|
+
}
|
|
12347
|
+
function isUploadedFile(value) {
|
|
12348
|
+
return value instanceof File;
|
|
12349
|
+
}
|
|
12350
|
+
const Route$j = createFileRoute("/api/logs/import")({
|
|
12351
|
+
server: {
|
|
12352
|
+
handlers: {
|
|
12353
|
+
POST: async ({ request }) => {
|
|
12354
|
+
let formData;
|
|
12355
|
+
try {
|
|
12356
|
+
formData = await request.formData();
|
|
12357
|
+
} catch {
|
|
12358
|
+
return Response.json({ error: "Expected multipart form data" }, { status: 400 });
|
|
12359
|
+
}
|
|
12360
|
+
const upload = formData.get("file");
|
|
12361
|
+
if (!isUploadedFile(upload)) {
|
|
12362
|
+
return Response.json({ error: "Missing import file" }, { status: 400 });
|
|
12363
|
+
}
|
|
12364
|
+
const sessionId = sessionNameFromImportFileName(upload.name);
|
|
12365
|
+
const parsed = await parseImportedLogFile({
|
|
12366
|
+
fileName: upload.name,
|
|
12367
|
+
data: Buffer.from(await upload.arrayBuffer())
|
|
12368
|
+
});
|
|
12369
|
+
if (!parsed.ok) {
|
|
12370
|
+
return Response.json(
|
|
12371
|
+
{ error: parsed.message, warnings: parsed.warnings },
|
|
12372
|
+
{ status: 400 }
|
|
12373
|
+
);
|
|
12374
|
+
}
|
|
12375
|
+
const imported = await importCapturedLogs(parsed.logs, sessionId);
|
|
12376
|
+
return Response.json({
|
|
12377
|
+
sessionId,
|
|
12378
|
+
imported: imported.length,
|
|
12379
|
+
skipped: parsed.skipped,
|
|
12380
|
+
warnings: parsed.warnings,
|
|
12381
|
+
logs: imported.map((log) => compactLogForList(log))
|
|
12382
|
+
});
|
|
12383
|
+
}
|
|
12384
|
+
}
|
|
12385
|
+
}
|
|
12386
|
+
});
|
|
12387
|
+
const Route$i = createFileRoute("/api/logs/$id")({
|
|
10799
12388
|
server: {
|
|
10800
12389
|
handlers: {
|
|
10801
12390
|
GET: async ({ params }) => {
|
|
@@ -11332,7 +12921,7 @@ const SearchBodySchema = object({
|
|
|
11332
12921
|
query: string().min(1),
|
|
11333
12922
|
project: string().optional()
|
|
11334
12923
|
});
|
|
11335
|
-
const Route$
|
|
12924
|
+
const Route$h = createFileRoute("/api/knowledge/search")({
|
|
11336
12925
|
server: {
|
|
11337
12926
|
handlers: {
|
|
11338
12927
|
GET: async ({ request }) => {
|
|
@@ -11354,7 +12943,7 @@ const Route$f = createFileRoute("/api/knowledge/search")({
|
|
|
11354
12943
|
}
|
|
11355
12944
|
}
|
|
11356
12945
|
});
|
|
11357
|
-
const Route$
|
|
12946
|
+
const Route$g = createFileRoute("/api/knowledge/project-context")({
|
|
11358
12947
|
server: {
|
|
11359
12948
|
handlers: {
|
|
11360
12949
|
GET: async ({ request }) => {
|
|
@@ -11436,7 +13025,7 @@ function updateCandidateDraft(id, updates) {
|
|
|
11436
13025
|
candidates.set(id, updated);
|
|
11437
13026
|
return updated;
|
|
11438
13027
|
}
|
|
11439
|
-
const Route$
|
|
13028
|
+
const Route$f = createFileRoute("/api/knowledge/candidates")({
|
|
11440
13029
|
server: {
|
|
11441
13030
|
handlers: {
|
|
11442
13031
|
GET: () => Response.json({ candidates: listCandidates() })
|
|
@@ -11471,7 +13060,7 @@ function readDeleteEvidenceFlag(request) {
|
|
|
11471
13060
|
return { ok: false };
|
|
11472
13061
|
}
|
|
11473
13062
|
}
|
|
11474
|
-
const Route$
|
|
13063
|
+
const Route$e = createFileRoute("/api/groups/$groupId")({
|
|
11475
13064
|
server: {
|
|
11476
13065
|
handlers: {
|
|
11477
13066
|
GET: ({ params }) => {
|
|
@@ -11518,7 +13107,7 @@ const Route$c = createFileRoute("/api/groups/$groupId")({
|
|
|
11518
13107
|
}
|
|
11519
13108
|
}
|
|
11520
13109
|
});
|
|
11521
|
-
const Route$
|
|
13110
|
+
const Route$d = createFileRoute("/api/config/paths")({
|
|
11522
13111
|
server: {
|
|
11523
13112
|
handlers: {
|
|
11524
13113
|
GET: () => {
|
|
@@ -11529,6 +13118,26 @@ const Route$b = createFileRoute("/api/config/paths")({
|
|
|
11529
13118
|
}
|
|
11530
13119
|
}
|
|
11531
13120
|
});
|
|
13121
|
+
function parsePositiveInt(value) {
|
|
13122
|
+
if (value === null) return void 0;
|
|
13123
|
+
const parsed = Number(value);
|
|
13124
|
+
if (!Number.isInteger(parsed) || parsed < 1) return void 0;
|
|
13125
|
+
return parsed;
|
|
13126
|
+
}
|
|
13127
|
+
const Route$c = createFileRoute("/api/alerts/summary")({
|
|
13128
|
+
server: {
|
|
13129
|
+
handlers: {
|
|
13130
|
+
GET: async ({ request }) => {
|
|
13131
|
+
const url = new URL(request.url);
|
|
13132
|
+
return Response.json(
|
|
13133
|
+
await getInspectorAlertSummary({
|
|
13134
|
+
scanLimit: parsePositiveInt(url.searchParams.get("scanLimit"))
|
|
13135
|
+
})
|
|
13136
|
+
);
|
|
13137
|
+
}
|
|
13138
|
+
}
|
|
13139
|
+
}
|
|
13140
|
+
});
|
|
11532
13141
|
async function readJsonBody$2(request) {
|
|
11533
13142
|
try {
|
|
11534
13143
|
const raw = await request.text();
|
|
@@ -11538,7 +13147,7 @@ async function readJsonBody$2(request) {
|
|
|
11538
13147
|
return { ok: false };
|
|
11539
13148
|
}
|
|
11540
13149
|
}
|
|
11541
|
-
const Route$
|
|
13150
|
+
const Route$b = createFileRoute("/api/runs/$runId/evidence")({
|
|
11542
13151
|
server: {
|
|
11543
13152
|
handlers: {
|
|
11544
13153
|
GET: ({ params }) => {
|
|
@@ -12189,7 +13798,7 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
12189
13798
|
clearTimeout(timeoutId);
|
|
12190
13799
|
}
|
|
12191
13800
|
}
|
|
12192
|
-
const Route$
|
|
13801
|
+
const Route$a = createFileRoute("/api/providers/$providerId/test")({
|
|
12193
13802
|
server: {
|
|
12194
13803
|
handlers: {
|
|
12195
13804
|
POST: async ({ params }) => {
|
|
@@ -12283,7 +13892,7 @@ async function readRegistryJson(response) {
|
|
|
12283
13892
|
return null;
|
|
12284
13893
|
}
|
|
12285
13894
|
}
|
|
12286
|
-
const Route$
|
|
13895
|
+
const Route$9 = createFileRoute("/api/providers/$providerId/model-metadata")({
|
|
12287
13896
|
server: {
|
|
12288
13897
|
handlers: {
|
|
12289
13898
|
POST: async ({ params, request }) => {
|
|
@@ -12373,7 +13982,7 @@ const Route$8 = createFileRoute("/api/providers/$providerId/model-metadata")({
|
|
|
12373
13982
|
const ReplayRequestSchema = object({
|
|
12374
13983
|
modifiedBody: string()
|
|
12375
13984
|
});
|
|
12376
|
-
const Route$
|
|
13985
|
+
const Route$8 = createFileRoute("/api/logs/$id/replay")({
|
|
12377
13986
|
server: {
|
|
12378
13987
|
handlers: {
|
|
12379
13988
|
POST: async ({ params, request }) => {
|
|
@@ -12574,7 +14183,7 @@ const Route$7 = createFileRoute("/api/logs/$id/replay")({
|
|
|
12574
14183
|
}
|
|
12575
14184
|
}
|
|
12576
14185
|
});
|
|
12577
|
-
const Route$
|
|
14186
|
+
const Route$7 = createFileRoute("/api/logs/$id/chunks")({
|
|
12578
14187
|
server: {
|
|
12579
14188
|
handlers: {
|
|
12580
14189
|
GET: async ({ params }) => {
|
|
@@ -12600,6 +14209,116 @@ const Route$6 = createFileRoute("/api/logs/$id/chunks")({
|
|
|
12600
14209
|
}
|
|
12601
14210
|
}
|
|
12602
14211
|
});
|
|
14212
|
+
const DEFAULT_LOG_BODY_CHUNK_BYTES = 256 * 1024;
|
|
14213
|
+
const MAX_LOG_BODY_CHUNK_BYTES = 1024 * 1024;
|
|
14214
|
+
function normalizeLogBodyChunkOffset(offset) {
|
|
14215
|
+
if (!Number.isInteger(offset) || offset < 0) return 0;
|
|
14216
|
+
return offset;
|
|
14217
|
+
}
|
|
14218
|
+
function normalizeLogBodyChunkLimit(limit) {
|
|
14219
|
+
if (!Number.isInteger(limit) || limit < 1) return DEFAULT_LOG_BODY_CHUNK_BYTES;
|
|
14220
|
+
return Math.min(limit, MAX_LOG_BODY_CHUNK_BYTES);
|
|
14221
|
+
}
|
|
14222
|
+
function bodyTextForPart(log, part) {
|
|
14223
|
+
switch (part) {
|
|
14224
|
+
case "request":
|
|
14225
|
+
return log.rawRequestBody;
|
|
14226
|
+
case "response":
|
|
14227
|
+
return log.responseText;
|
|
14228
|
+
}
|
|
14229
|
+
}
|
|
14230
|
+
function isUtf8ContinuationByte(byte) {
|
|
14231
|
+
return byte !== void 0 && (byte & 192) === 128;
|
|
14232
|
+
}
|
|
14233
|
+
function expandToUtf8Boundary(buffer, end) {
|
|
14234
|
+
if (end >= buffer.byteLength) return buffer.byteLength;
|
|
14235
|
+
let safeEnd = end;
|
|
14236
|
+
while (safeEnd < buffer.byteLength && isUtf8ContinuationByte(buffer[safeEnd])) {
|
|
14237
|
+
safeEnd++;
|
|
14238
|
+
}
|
|
14239
|
+
return safeEnd;
|
|
14240
|
+
}
|
|
14241
|
+
function createLogBodyChunk({
|
|
14242
|
+
log,
|
|
14243
|
+
part,
|
|
14244
|
+
offset,
|
|
14245
|
+
limit
|
|
14246
|
+
}) {
|
|
14247
|
+
const text = bodyTextForPart(log, part);
|
|
14248
|
+
const normalizedLimit = normalizeLogBodyChunkLimit(limit);
|
|
14249
|
+
if (text === null || text === "") {
|
|
14250
|
+
return {
|
|
14251
|
+
logId: log.id,
|
|
14252
|
+
part,
|
|
14253
|
+
text: "",
|
|
14254
|
+
offset: 0,
|
|
14255
|
+
limit: normalizedLimit,
|
|
14256
|
+
totalBytes: 0,
|
|
14257
|
+
textBytes: 0,
|
|
14258
|
+
nextOffset: null,
|
|
14259
|
+
hasMore: false,
|
|
14260
|
+
contentMode: "empty"
|
|
14261
|
+
};
|
|
14262
|
+
}
|
|
14263
|
+
const bodyBytes = Buffer.from(text, "utf8");
|
|
14264
|
+
const totalBytes = bodyBytes.byteLength;
|
|
14265
|
+
const normalizedOffset = Math.min(normalizeLogBodyChunkOffset(offset), totalBytes);
|
|
14266
|
+
const end = expandToUtf8Boundary(
|
|
14267
|
+
bodyBytes,
|
|
14268
|
+
Math.min(normalizedOffset + normalizedLimit, totalBytes)
|
|
14269
|
+
);
|
|
14270
|
+
const chunkText = bodyBytes.toString("utf8", normalizedOffset, end);
|
|
14271
|
+
const textBytes = end - normalizedOffset;
|
|
14272
|
+
const hasMore = end < totalBytes;
|
|
14273
|
+
const contentMode = hasMore || normalizedOffset > 0 ? "partial" : "full";
|
|
14274
|
+
return {
|
|
14275
|
+
logId: log.id,
|
|
14276
|
+
part,
|
|
14277
|
+
text: chunkText,
|
|
14278
|
+
offset: normalizedOffset,
|
|
14279
|
+
limit: normalizedLimit,
|
|
14280
|
+
totalBytes,
|
|
14281
|
+
textBytes,
|
|
14282
|
+
nextOffset: hasMore ? end : null,
|
|
14283
|
+
hasMore,
|
|
14284
|
+
contentMode
|
|
14285
|
+
};
|
|
14286
|
+
}
|
|
14287
|
+
function parseIntegerParam(value, fallback) {
|
|
14288
|
+
if (value === null) return fallback;
|
|
14289
|
+
const parsed = Number(value);
|
|
14290
|
+
if (!Number.isInteger(parsed)) return fallback;
|
|
14291
|
+
return parsed;
|
|
14292
|
+
}
|
|
14293
|
+
const Route$6 = createFileRoute("/api/logs/$id/body")({
|
|
14294
|
+
server: {
|
|
14295
|
+
handlers: {
|
|
14296
|
+
GET: async ({ params, request }) => {
|
|
14297
|
+
const id = Number(params.id);
|
|
14298
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
14299
|
+
return Response.json({ error: "Invalid log ID" }, { status: 400 });
|
|
14300
|
+
}
|
|
14301
|
+
const url = new URL(request.url);
|
|
14302
|
+
const partResult = LogBodyPartSchema.safeParse(url.searchParams.get("part"));
|
|
14303
|
+
if (!partResult.success) {
|
|
14304
|
+
return Response.json({ error: "Invalid body part" }, { status: 400 });
|
|
14305
|
+
}
|
|
14306
|
+
const log = await getLogById(id);
|
|
14307
|
+
if (log === null) {
|
|
14308
|
+
return Response.json({ error: "Log not found" }, { status: 404 });
|
|
14309
|
+
}
|
|
14310
|
+
return Response.json(
|
|
14311
|
+
createLogBodyChunk({
|
|
14312
|
+
log,
|
|
14313
|
+
part: partResult.data,
|
|
14314
|
+
offset: parseIntegerParam(url.searchParams.get("offset"), 0),
|
|
14315
|
+
limit: parseIntegerParam(url.searchParams.get("limit"), 0)
|
|
14316
|
+
})
|
|
14317
|
+
);
|
|
14318
|
+
}
|
|
14319
|
+
}
|
|
14320
|
+
}
|
|
14321
|
+
});
|
|
12603
14322
|
const CandidateUpdateSchema = object({
|
|
12604
14323
|
type: KnowledgeCandidateTypeSchema.optional(),
|
|
12605
14324
|
title: string().trim().min(1).max(160).optional(),
|
|
@@ -13144,151 +14863,171 @@ const Route = createFileRoute("/api/knowledge/candidates/$candidateId/promote")(
|
|
|
13144
14863
|
}
|
|
13145
14864
|
}
|
|
13146
14865
|
});
|
|
13147
|
-
const IndexRoute = Route$
|
|
14866
|
+
const IndexRoute = Route$C.update({
|
|
13148
14867
|
id: "/",
|
|
13149
14868
|
path: "/",
|
|
13150
|
-
getParentRoute: () => Route$
|
|
14869
|
+
getParentRoute: () => Route$D
|
|
13151
14870
|
});
|
|
13152
|
-
const SessionSessionIdRoute = Route$
|
|
14871
|
+
const SessionSessionIdRoute = Route$B.update({
|
|
13153
14872
|
id: "/session/$sessionId",
|
|
13154
14873
|
path: "/session/$sessionId",
|
|
13155
|
-
getParentRoute: () => Route$
|
|
14874
|
+
getParentRoute: () => Route$D
|
|
13156
14875
|
});
|
|
13157
|
-
const ProxySplatRoute = Route$
|
|
14876
|
+
const ProxySplatRoute = Route$A.update({
|
|
13158
14877
|
id: "/proxy/$",
|
|
13159
14878
|
path: "/proxy/$",
|
|
13160
|
-
getParentRoute: () => Route$
|
|
14879
|
+
getParentRoute: () => Route$D
|
|
13161
14880
|
});
|
|
13162
|
-
const ApiSessionsRoute = Route$
|
|
14881
|
+
const ApiSessionsRoute = Route$z.update({
|
|
13163
14882
|
id: "/api/sessions",
|
|
13164
14883
|
path: "/api/sessions",
|
|
13165
|
-
getParentRoute: () => Route$
|
|
14884
|
+
getParentRoute: () => Route$D
|
|
13166
14885
|
});
|
|
13167
|
-
const ApiRunsRoute = Route$
|
|
14886
|
+
const ApiRunsRoute = Route$y.update({
|
|
13168
14887
|
id: "/api/runs",
|
|
13169
14888
|
path: "/api/runs",
|
|
13170
|
-
getParentRoute: () => Route$
|
|
14889
|
+
getParentRoute: () => Route$D
|
|
13171
14890
|
});
|
|
13172
|
-
const ApiProvidersRoute = Route$
|
|
14891
|
+
const ApiProvidersRoute = Route$x.update({
|
|
13173
14892
|
id: "/api/providers",
|
|
13174
14893
|
path: "/api/providers",
|
|
13175
|
-
getParentRoute: () => Route$
|
|
14894
|
+
getParentRoute: () => Route$D
|
|
13176
14895
|
});
|
|
13177
|
-
const ApiModelsRoute = Route$
|
|
14896
|
+
const ApiModelsRoute = Route$w.update({
|
|
13178
14897
|
id: "/api/models",
|
|
13179
14898
|
path: "/api/models",
|
|
13180
|
-
getParentRoute: () => Route$
|
|
14899
|
+
getParentRoute: () => Route$D
|
|
13181
14900
|
});
|
|
13182
|
-
const ApiMcpRoute = Route$
|
|
14901
|
+
const ApiMcpRoute = Route$v.update({
|
|
13183
14902
|
id: "/api/mcp",
|
|
13184
14903
|
path: "/api/mcp",
|
|
13185
|
-
getParentRoute: () => Route$
|
|
14904
|
+
getParentRoute: () => Route$D
|
|
13186
14905
|
});
|
|
13187
|
-
const ApiLogsRoute = Route$
|
|
14906
|
+
const ApiLogsRoute = Route$u.update({
|
|
13188
14907
|
id: "/api/logs",
|
|
13189
14908
|
path: "/api/logs",
|
|
13190
|
-
getParentRoute: () => Route$
|
|
14909
|
+
getParentRoute: () => Route$D
|
|
13191
14910
|
});
|
|
13192
|
-
const ApiHealthRoute = Route$
|
|
14911
|
+
const ApiHealthRoute = Route$t.update({
|
|
13193
14912
|
id: "/api/health",
|
|
13194
14913
|
path: "/api/health",
|
|
13195
|
-
getParentRoute: () => Route$
|
|
14914
|
+
getParentRoute: () => Route$D
|
|
13196
14915
|
});
|
|
13197
|
-
const ApiGroupsRoute = Route$
|
|
14916
|
+
const ApiGroupsRoute = Route$s.update({
|
|
13198
14917
|
id: "/api/groups",
|
|
13199
14918
|
path: "/api/groups",
|
|
13200
|
-
getParentRoute: () => Route$
|
|
14919
|
+
getParentRoute: () => Route$D
|
|
13201
14920
|
});
|
|
13202
|
-
const ApiConfigRoute = Route$
|
|
14921
|
+
const ApiConfigRoute = Route$r.update({
|
|
13203
14922
|
id: "/api/config",
|
|
13204
14923
|
path: "/api/config",
|
|
13205
|
-
getParentRoute: () => Route$
|
|
14924
|
+
getParentRoute: () => Route$D
|
|
13206
14925
|
});
|
|
13207
|
-
const
|
|
14926
|
+
const ApiAlertsRoute = Route$q.update({
|
|
14927
|
+
id: "/api/alerts",
|
|
14928
|
+
path: "/api/alerts",
|
|
14929
|
+
getParentRoute: () => Route$D
|
|
14930
|
+
});
|
|
14931
|
+
const ApiRunsRunIdRoute = Route$p.update({
|
|
13208
14932
|
id: "/$runId",
|
|
13209
14933
|
path: "/$runId",
|
|
13210
14934
|
getParentRoute: () => ApiRunsRoute
|
|
13211
14935
|
});
|
|
13212
|
-
const ApiProvidersScanRoute = Route$
|
|
14936
|
+
const ApiProvidersScanRoute = Route$o.update({
|
|
13213
14937
|
id: "/scan",
|
|
13214
14938
|
path: "/scan",
|
|
13215
14939
|
getParentRoute: () => ApiProvidersRoute
|
|
13216
14940
|
});
|
|
13217
|
-
const ApiProvidersImportRoute = Route$
|
|
14941
|
+
const ApiProvidersImportRoute = Route$n.update({
|
|
13218
14942
|
id: "/import",
|
|
13219
14943
|
path: "/import",
|
|
13220
14944
|
getParentRoute: () => ApiProvidersRoute
|
|
13221
14945
|
});
|
|
13222
|
-
const ApiProvidersExportRoute = Route$
|
|
14946
|
+
const ApiProvidersExportRoute = Route$m.update({
|
|
13223
14947
|
id: "/export",
|
|
13224
14948
|
path: "/export",
|
|
13225
14949
|
getParentRoute: () => ApiProvidersRoute
|
|
13226
14950
|
});
|
|
13227
|
-
const ApiProvidersProviderIdRoute = Route$
|
|
14951
|
+
const ApiProvidersProviderIdRoute = Route$l.update({
|
|
13228
14952
|
id: "/$providerId",
|
|
13229
14953
|
path: "/$providerId",
|
|
13230
14954
|
getParentRoute: () => ApiProvidersRoute
|
|
13231
14955
|
});
|
|
13232
|
-
const ApiLogsStreamRoute = Route$
|
|
14956
|
+
const ApiLogsStreamRoute = Route$k.update({
|
|
13233
14957
|
id: "/stream",
|
|
13234
14958
|
path: "/stream",
|
|
13235
14959
|
getParentRoute: () => ApiLogsRoute
|
|
13236
14960
|
});
|
|
13237
|
-
const
|
|
14961
|
+
const ApiLogsImportRoute = Route$j.update({
|
|
14962
|
+
id: "/import",
|
|
14963
|
+
path: "/import",
|
|
14964
|
+
getParentRoute: () => ApiLogsRoute
|
|
14965
|
+
});
|
|
14966
|
+
const ApiLogsIdRoute = Route$i.update({
|
|
13238
14967
|
id: "/$id",
|
|
13239
14968
|
path: "/$id",
|
|
13240
14969
|
getParentRoute: () => ApiLogsRoute
|
|
13241
14970
|
});
|
|
13242
|
-
const ApiKnowledgeSearchRoute = Route$
|
|
14971
|
+
const ApiKnowledgeSearchRoute = Route$h.update({
|
|
13243
14972
|
id: "/api/knowledge/search",
|
|
13244
14973
|
path: "/api/knowledge/search",
|
|
13245
|
-
getParentRoute: () => Route$
|
|
14974
|
+
getParentRoute: () => Route$D
|
|
13246
14975
|
});
|
|
13247
|
-
const ApiKnowledgeProjectContextRoute = Route$
|
|
14976
|
+
const ApiKnowledgeProjectContextRoute = Route$g.update({
|
|
13248
14977
|
id: "/api/knowledge/project-context",
|
|
13249
14978
|
path: "/api/knowledge/project-context",
|
|
13250
|
-
getParentRoute: () => Route$
|
|
14979
|
+
getParentRoute: () => Route$D
|
|
13251
14980
|
});
|
|
13252
|
-
const ApiKnowledgeCandidatesRoute = Route$
|
|
14981
|
+
const ApiKnowledgeCandidatesRoute = Route$f.update({
|
|
13253
14982
|
id: "/api/knowledge/candidates",
|
|
13254
14983
|
path: "/api/knowledge/candidates",
|
|
13255
|
-
getParentRoute: () => Route$
|
|
14984
|
+
getParentRoute: () => Route$D
|
|
13256
14985
|
});
|
|
13257
|
-
const ApiGroupsGroupIdRoute = Route$
|
|
14986
|
+
const ApiGroupsGroupIdRoute = Route$e.update({
|
|
13258
14987
|
id: "/$groupId",
|
|
13259
14988
|
path: "/$groupId",
|
|
13260
14989
|
getParentRoute: () => ApiGroupsRoute
|
|
13261
14990
|
});
|
|
13262
|
-
const ApiConfigPathsRoute = Route$
|
|
14991
|
+
const ApiConfigPathsRoute = Route$d.update({
|
|
13263
14992
|
id: "/paths",
|
|
13264
14993
|
path: "/paths",
|
|
13265
14994
|
getParentRoute: () => ApiConfigRoute
|
|
13266
14995
|
});
|
|
13267
|
-
const
|
|
14996
|
+
const ApiAlertsSummaryRoute = Route$c.update({
|
|
14997
|
+
id: "/summary",
|
|
14998
|
+
path: "/summary",
|
|
14999
|
+
getParentRoute: () => ApiAlertsRoute
|
|
15000
|
+
});
|
|
15001
|
+
const ApiRunsRunIdEvidenceRoute = Route$b.update({
|
|
13268
15002
|
id: "/evidence",
|
|
13269
15003
|
path: "/evidence",
|
|
13270
15004
|
getParentRoute: () => ApiRunsRunIdRoute
|
|
13271
15005
|
});
|
|
13272
|
-
const ApiProvidersProviderIdTestRoute = Route$
|
|
15006
|
+
const ApiProvidersProviderIdTestRoute = Route$a.update({
|
|
13273
15007
|
id: "/test",
|
|
13274
15008
|
path: "/test",
|
|
13275
15009
|
getParentRoute: () => ApiProvidersProviderIdRoute
|
|
13276
15010
|
});
|
|
13277
|
-
const ApiProvidersProviderIdModelMetadataRoute = Route$
|
|
15011
|
+
const ApiProvidersProviderIdModelMetadataRoute = Route$9.update({
|
|
13278
15012
|
id: "/model-metadata",
|
|
13279
15013
|
path: "/model-metadata",
|
|
13280
15014
|
getParentRoute: () => ApiProvidersProviderIdRoute
|
|
13281
15015
|
});
|
|
13282
|
-
const ApiLogsIdReplayRoute = Route$
|
|
15016
|
+
const ApiLogsIdReplayRoute = Route$8.update({
|
|
13283
15017
|
id: "/replay",
|
|
13284
15018
|
path: "/replay",
|
|
13285
15019
|
getParentRoute: () => ApiLogsIdRoute
|
|
13286
15020
|
});
|
|
13287
|
-
const ApiLogsIdChunksRoute = Route$
|
|
15021
|
+
const ApiLogsIdChunksRoute = Route$7.update({
|
|
13288
15022
|
id: "/chunks",
|
|
13289
15023
|
path: "/chunks",
|
|
13290
15024
|
getParentRoute: () => ApiLogsIdRoute
|
|
13291
15025
|
});
|
|
15026
|
+
const ApiLogsIdBodyRoute = Route$6.update({
|
|
15027
|
+
id: "/body",
|
|
15028
|
+
path: "/body",
|
|
15029
|
+
getParentRoute: () => ApiLogsIdRoute
|
|
15030
|
+
});
|
|
13292
15031
|
const ApiKnowledgeCandidatesCandidateIdRoute = Route$5.update({
|
|
13293
15032
|
id: "/$candidateId",
|
|
13294
15033
|
path: "/$candidateId",
|
|
@@ -13312,13 +15051,19 @@ const ApiProvidersProviderIdTestLogRoute = Route$2.update({
|
|
|
13312
15051
|
const ApiKnowledgeSessionsSessionIdCandidatesRoute = Route$1.update({
|
|
13313
15052
|
id: "/api/knowledge/sessions/$sessionId/candidates",
|
|
13314
15053
|
path: "/api/knowledge/sessions/$sessionId/candidates",
|
|
13315
|
-
getParentRoute: () => Route$
|
|
15054
|
+
getParentRoute: () => Route$D
|
|
13316
15055
|
});
|
|
13317
15056
|
const ApiKnowledgeCandidatesCandidateIdPromoteRoute = Route.update({
|
|
13318
15057
|
id: "/promote",
|
|
13319
15058
|
path: "/promote",
|
|
13320
15059
|
getParentRoute: () => ApiKnowledgeCandidatesCandidateIdRoute
|
|
13321
15060
|
});
|
|
15061
|
+
const ApiAlertsRouteChildren = {
|
|
15062
|
+
ApiAlertsSummaryRoute
|
|
15063
|
+
};
|
|
15064
|
+
const ApiAlertsRouteWithChildren = ApiAlertsRoute._addFileChildren(
|
|
15065
|
+
ApiAlertsRouteChildren
|
|
15066
|
+
);
|
|
13322
15067
|
const ApiConfigRouteChildren = {
|
|
13323
15068
|
ApiConfigPathsRoute
|
|
13324
15069
|
};
|
|
@@ -13337,6 +15082,7 @@ const ApiGroupsRouteWithChildren = ApiGroupsRoute._addFileChildren(
|
|
|
13337
15082
|
ApiGroupsRouteChildren
|
|
13338
15083
|
);
|
|
13339
15084
|
const ApiLogsIdRouteChildren = {
|
|
15085
|
+
ApiLogsIdBodyRoute,
|
|
13340
15086
|
ApiLogsIdChunksRoute,
|
|
13341
15087
|
ApiLogsIdReplayRoute
|
|
13342
15088
|
};
|
|
@@ -13345,6 +15091,7 @@ const ApiLogsIdRouteWithChildren = ApiLogsIdRoute._addFileChildren(
|
|
|
13345
15091
|
);
|
|
13346
15092
|
const ApiLogsRouteChildren = {
|
|
13347
15093
|
ApiLogsIdRoute: ApiLogsIdRouteWithChildren,
|
|
15094
|
+
ApiLogsImportRoute,
|
|
13348
15095
|
ApiLogsStreamRoute
|
|
13349
15096
|
};
|
|
13350
15097
|
const ApiLogsRouteWithChildren = ApiLogsRoute._addFileChildren(ApiLogsRouteChildren);
|
|
@@ -13394,6 +15141,7 @@ const ApiKnowledgeCandidatesRouteWithChildren = ApiKnowledgeCandidatesRoute._add
|
|
|
13394
15141
|
);
|
|
13395
15142
|
const rootRouteChildren = {
|
|
13396
15143
|
IndexRoute,
|
|
15144
|
+
ApiAlertsRoute: ApiAlertsRouteWithChildren,
|
|
13397
15145
|
ApiConfigRoute: ApiConfigRouteWithChildren,
|
|
13398
15146
|
ApiGroupsRoute: ApiGroupsRouteWithChildren,
|
|
13399
15147
|
ApiHealthRoute,
|
|
@@ -13410,7 +15158,7 @@ const rootRouteChildren = {
|
|
|
13410
15158
|
ApiKnowledgeSearchRoute,
|
|
13411
15159
|
ApiKnowledgeSessionsSessionIdCandidatesRoute
|
|
13412
15160
|
};
|
|
13413
|
-
const routeTree = Route$
|
|
15161
|
+
const routeTree = Route$D._addFileChildren(rootRouteChildren)._addFileTypes();
|
|
13414
15162
|
function getRouter() {
|
|
13415
15163
|
const router2 = createRouter({
|
|
13416
15164
|
routeTree,
|
|
@@ -13442,32 +15190,35 @@ export {
|
|
|
13442
15190
|
GroupEvidenceReadResponseSchema as G,
|
|
13443
15191
|
InspectorGroupsListResponseSchema as I,
|
|
13444
15192
|
KnowledgeCandidateSchema as K,
|
|
15193
|
+
LogBodyChunkSchema as L,
|
|
13445
15194
|
MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as M,
|
|
13446
15195
|
OpenAIRequestSchema as O,
|
|
13447
15196
|
ProviderConfigSchema as P,
|
|
13448
|
-
Route$
|
|
15197
|
+
Route$B as R,
|
|
13449
15198
|
TimeDisplayFormatSchema as T,
|
|
13450
15199
|
DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS as a,
|
|
13451
15200
|
DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS as b,
|
|
13452
15201
|
DEFAULT_TIME_DISPLAY_FORMAT as c,
|
|
13453
15202
|
RuntimeConfigSchema as d,
|
|
13454
15203
|
AnthropicRequestSchema as e,
|
|
13455
|
-
|
|
13456
|
-
|
|
13457
|
-
|
|
13458
|
-
|
|
13459
|
-
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
|
|
15204
|
+
parseOpenAIResponse as f,
|
|
15205
|
+
apiFormatForPath as g,
|
|
15206
|
+
getSessionPath as h,
|
|
15207
|
+
stripClaudeCodeBillingHeader as i,
|
|
15208
|
+
AlertSummarySchema as j,
|
|
15209
|
+
AlertListResponseSchema as k,
|
|
15210
|
+
GroupEvidenceExportResultSchema as l,
|
|
15211
|
+
DeleteInspectorGroupResponseSchema as m,
|
|
15212
|
+
providerHasContextMetadata as n,
|
|
15213
|
+
findProviderModelMetadata as o,
|
|
15214
|
+
packageJson as p,
|
|
15215
|
+
maskApiKey as q,
|
|
15216
|
+
createPendingProviderTestResults as r,
|
|
13468
15217
|
safeGetOwnProperty as s,
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
15218
|
+
ProviderTestResultsSchema as t,
|
|
15219
|
+
createFailedProviderTestResults as u,
|
|
15220
|
+
MAX_PROVIDER_TEST_TIMEOUT_SECONDS as v,
|
|
15221
|
+
resolveProviderContextWindow as w,
|
|
15222
|
+
isPlainRecord as x,
|
|
15223
|
+
router as y
|
|
13473
15224
|
};
|