@tonyclaw/llm-inspector 1.19.1 → 1.19.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/cli.js +146 -37
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-DtERUdIt.js → CompareDrawer-AMCFfwDw.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-DfxRK7Nt.js → ProxyViewerContainer-Bi1QXDYo.js} +9 -9
- package/.output/public/assets/{ReplayDialog-VMsGnJSI.js → ReplayDialog-C1x2-73A.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-Cx_vluvK.js → RequestAnatomy-CBNqMbxo.js} +1 -1
- package/.output/public/assets/{ResponseView-5F8Ms5z4.js → ResponseView-BsBxYW8b.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-CKDCWfu9.js → StreamingChunkSequence-BjX20-9R.js} +1 -1
- package/.output/public/assets/_sessionId-DE0J5YHU.js +1 -0
- package/.output/public/assets/{index-DeJyypsp.css → index-Bqi9RAGS.css} +1 -1
- package/.output/public/assets/index-DqgTchf4.js +1 -0
- package/.output/public/assets/{json-viewer-CztuZ9cT.js → json-viewer-CyJ5nYhX.js} +1 -1
- package/.output/public/assets/{main-CR9IJlz1.js → main-DpODUL6C.js} +4 -4
- package/.output/server/{_sessionId-DvWQaDEm.mjs → _sessionId-DJ9Eab2q.mjs} +4 -3
- package/.output/server/_ssr/{CompareDrawer-C5FsxSDS.mjs → CompareDrawer-CZjtgISX.mjs} +4 -4
- package/.output/server/_ssr/{ProxyViewerContainer-v0cvR8f5.mjs → ProxyViewerContainer-PjfpTAwC.mjs} +57 -9
- package/.output/server/_ssr/{ReplayDialog-C3KOv9OW.mjs → ReplayDialog-OiEK8Sbt.mjs} +5 -5
- package/.output/server/_ssr/{RequestAnatomy-BYRe33eG.mjs → RequestAnatomy-DN7d-srT.mjs} +4 -3
- package/.output/server/_ssr/{ResponseView-va7yQDeL.mjs → ResponseView-7iJG8mU_.mjs} +5 -5
- package/.output/server/_ssr/{StreamingChunkSequence-BJlI-gWl.mjs → StreamingChunkSequence-DgtV9nLT.mjs} +4 -4
- package/.output/server/_ssr/{index-CS0fA2GT.mjs → index-YZwFhEEr.mjs} +4 -3
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-Dg8rqrxL.mjs → json-viewer-0GHTWO7g.mjs} +4 -4
- package/.output/server/_ssr/{router-D_Boe9Bu.mjs → router-DCW8d1sw.mjs} +131 -106
- package/.output/server/{_tanstack-start-manifest_v-KFXyNRGC.mjs → _tanstack-start-manifest_v-CxTbhyJ_.mjs} +1 -1
- package/.output/server/index.mjs +75 -75
- package/README.md +22 -0
- package/package.json +4 -2
- package/src/assets/favicon.svg +18 -0
- package/src/cli/detect-tools.ts +1 -0
- package/src/cli/templates/skill-onboard.ts +6 -6
- package/src/cli.ts +152 -35
- package/src/components/ProxyViewerContainer.tsx +52 -0
- package/src/components/proxy-viewer/LogEntryHeader.tsx +1 -0
- package/src/proxy/logFinalizer.ts +7 -3
- package/src/proxy/sessionProcess.ts +14 -7
- package/src/proxy/sessionSupervisor.ts +3 -2
- package/src/proxy/socketTracker.ts +19 -7
- package/src/routes/__root.tsx +5 -1
- package/styles/globals.css +14 -7
- package/.output/public/assets/_sessionId-C-aKd1Ky.js +0 -1
- package/.output/public/assets/index-B8ttyigz.js +0 -1
|
@@ -5,9 +5,10 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync, copyFil
|
|
|
5
5
|
import { mkdir, appendFile, readFile, open, readdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
6
6
|
import { Buffer } from "node:buffer";
|
|
7
7
|
import path, { join, isAbsolute, dirname } from "node:path";
|
|
8
|
+
import { execFile, exec, spawn } from "node:child_process";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
8
10
|
import { C as Conf } from "../_libs/conf.mjs";
|
|
9
11
|
import { randomUUID } from "crypto";
|
|
10
|
-
import { exec, fork } from "node:child_process";
|
|
11
12
|
import { promisify } from "node:util";
|
|
12
13
|
import { Worker } from "node:worker_threads";
|
|
13
14
|
import { M as McpServer, W as WebStandardStreamableHTTPServerTransport } from "../_libs/modelcontextprotocol__server.mjs";
|
|
@@ -47,7 +48,8 @@ import "../_libs/debounce-fn.mjs";
|
|
|
47
48
|
import "../_libs/mimic-function.mjs";
|
|
48
49
|
import "../_libs/semver.mjs";
|
|
49
50
|
import "../_libs/uint8array-extras.mjs";
|
|
50
|
-
const
|
|
51
|
+
const faviconSvg = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2064%2064'%20role='img'%20aria-label='LLM%20Inspector'%3e%3crect%20width='64'%20height='64'%20rx='14'%20fill='%23111827'%20/%3e%3cg%20fill='none'%20stroke='%23f59e0b'%20stroke-width='4.2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20fill='%23f59e0b'%20d='M15%2036c0-11%207-18%2017-18s17%207%2017%2018c0%208-7%2013-17%2013s-17-5-17-13z'%20/%3e%3cpath%20d='M16%2031c-6-5-12-3-12%204%200%205%206%206%2011%202'%20/%3e%3cpath%20d='M48%2031c6-5%2012-3%2012%204%200%205-6%206-11%202'%20/%3e%3cpath%20d='M27%2019l-3-7'%20/%3e%3cpath%20d='M37%2019l3-7'%20/%3e%3cpath%20d='M19%2045l-6%209'%20/%3e%3cpath%20d='M27%2048l-3%209'%20/%3e%3cpath%20d='M37%2048l3%209'%20/%3e%3cpath%20d='M45%2045l6%209'%20/%3e%3c/g%3e%3ccircle%20cx='24'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='40'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='25'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3ccircle%20cx='39'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3c/svg%3e";
|
|
52
|
+
const appCss = "/assets/index-Bqi9RAGS.css";
|
|
51
53
|
const Route$l = createRootRoute({
|
|
52
54
|
head: () => ({
|
|
53
55
|
meta: [
|
|
@@ -55,7 +57,10 @@ const Route$l = createRootRoute({
|
|
|
55
57
|
{ name: "viewport", content: "width=device-width, initial-scale=1" },
|
|
56
58
|
{ title: "llm-inspector" }
|
|
57
59
|
],
|
|
58
|
-
links: [
|
|
60
|
+
links: [
|
|
61
|
+
{ rel: "stylesheet", href: appCss },
|
|
62
|
+
{ rel: "icon", type: "image/svg+xml", href: faviconSvg }
|
|
63
|
+
]
|
|
59
64
|
}),
|
|
60
65
|
component: RootComponent
|
|
61
66
|
});
|
|
@@ -71,7 +76,7 @@ function RootDocument({ children }) {
|
|
|
71
76
|
] })
|
|
72
77
|
] });
|
|
73
78
|
}
|
|
74
|
-
const $$splitComponentImporter$1 = () => import("./index-
|
|
79
|
+
const $$splitComponentImporter$1 = () => import("./index-YZwFhEEr.mjs");
|
|
75
80
|
const Route$k = createFileRoute("/")({
|
|
76
81
|
component: lazyRouteComponent($$splitComponentImporter$1, "component")
|
|
77
82
|
});
|
|
@@ -114,7 +119,7 @@ function decodeSessionIdFromPath(encoded) {
|
|
|
114
119
|
function getSessionPath(sessionId) {
|
|
115
120
|
return `/session/${encodeSessionIdForPath(sessionId)}`;
|
|
116
121
|
}
|
|
117
|
-
const $$splitComponentImporter = () => import("../_sessionId-
|
|
122
|
+
const $$splitComponentImporter = () => import("../_sessionId-DJ9Eab2q.mjs");
|
|
118
123
|
const Route$j = createFileRoute("/session/$sessionId")({
|
|
119
124
|
component: lazyRouteComponent($$splitComponentImporter, "component"),
|
|
120
125
|
parseParams: (params) => ({
|
|
@@ -887,13 +892,113 @@ function readChunks(path2) {
|
|
|
887
892
|
return null;
|
|
888
893
|
}
|
|
889
894
|
}
|
|
895
|
+
const IDLE_TIMEOUT_MS = Number(process.env["SESSION_PROCESS_IDLE_MS"]) || 5 * 60 * 1e3;
|
|
896
|
+
const MAX_RESTARTS = 3;
|
|
897
|
+
const _processes = /* @__PURE__ */ new Map();
|
|
898
|
+
function resolveSessionWorkerPath() {
|
|
899
|
+
return fileURLToPath(new URL("./sessionWorkerEntry.ts", import.meta.url));
|
|
900
|
+
}
|
|
901
|
+
function isSessionProcessAvailable() {
|
|
902
|
+
return existsSync(resolveSessionWorkerPath());
|
|
903
|
+
}
|
|
904
|
+
class SessionProcess {
|
|
905
|
+
constructor(sessionId) {
|
|
906
|
+
this.sessionId = sessionId;
|
|
907
|
+
}
|
|
908
|
+
child = null;
|
|
909
|
+
pending = /* @__PURE__ */ new Map();
|
|
910
|
+
nextId = 0;
|
|
911
|
+
idleTimer = null;
|
|
912
|
+
restartCount = 0;
|
|
913
|
+
destroyed = false;
|
|
914
|
+
/** Number of outstanding jobs sent to this process. */
|
|
915
|
+
get pendingCount() {
|
|
916
|
+
return this.pending.size;
|
|
917
|
+
}
|
|
918
|
+
ensureRunning() {
|
|
919
|
+
if (this.child !== null && this.child.connected) return this.child;
|
|
920
|
+
const resolvedPath = resolveSessionWorkerPath();
|
|
921
|
+
this.child = spawn(process.execPath, [...process.execArgv, resolvedPath], {
|
|
922
|
+
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
923
|
+
windowsHide: true
|
|
924
|
+
});
|
|
925
|
+
this.restartCount += 1;
|
|
926
|
+
this.child.on("message", (msg) => {
|
|
927
|
+
const pending = this.pending.get(msg.id);
|
|
928
|
+
if (pending !== void 0) {
|
|
929
|
+
this.pending.delete(msg.id);
|
|
930
|
+
pending.resolve(msg.result);
|
|
931
|
+
}
|
|
932
|
+
this.resetIdleTimer();
|
|
933
|
+
});
|
|
934
|
+
this.child.on("error", (err) => {
|
|
935
|
+
logger.error(`[sessionProcess] Session ${this.sessionId} process error:`, err.message);
|
|
936
|
+
});
|
|
937
|
+
this.child.on("exit", (code, signal) => {
|
|
938
|
+
const wasConnected = this.child !== null;
|
|
939
|
+
this.child = null;
|
|
940
|
+
if (this.destroyed) return;
|
|
941
|
+
for (const [, pending] of this.pending) {
|
|
942
|
+
pending.reject(
|
|
943
|
+
new Error(
|
|
944
|
+
`Session process exited with code ${code ?? signal}, session=${this.sessionId}`
|
|
945
|
+
)
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
this.pending.clear();
|
|
949
|
+
if (wasConnected && this.restartCount <= MAX_RESTARTS) {
|
|
950
|
+
logger.warn(
|
|
951
|
+
`[sessionProcess] Session ${this.sessionId} worker exited (code=${code ?? signal}), restart ${this.restartCount}/${MAX_RESTARTS}`
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
});
|
|
955
|
+
this.resetIdleTimer();
|
|
956
|
+
return this.child;
|
|
957
|
+
}
|
|
958
|
+
enqueue(job) {
|
|
959
|
+
return new Promise((resolve, reject) => {
|
|
960
|
+
const child = this.ensureRunning();
|
|
961
|
+
const id = String(++this.nextId);
|
|
962
|
+
this.pending.set(id, { resolve, reject });
|
|
963
|
+
child.send({ id, job });
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
resetIdleTimer() {
|
|
967
|
+
if (this.idleTimer !== null) clearTimeout(this.idleTimer);
|
|
968
|
+
this.idleTimer = setTimeout(() => {
|
|
969
|
+
if (this.pending.size === 0) {
|
|
970
|
+
this.destroy();
|
|
971
|
+
}
|
|
972
|
+
}, IDLE_TIMEOUT_MS);
|
|
973
|
+
}
|
|
974
|
+
destroy() {
|
|
975
|
+
this.destroyed = true;
|
|
976
|
+
if (this.idleTimer !== null) {
|
|
977
|
+
clearTimeout(this.idleTimer);
|
|
978
|
+
this.idleTimer = null;
|
|
979
|
+
}
|
|
980
|
+
if (this.child !== null) {
|
|
981
|
+
this.child.kill();
|
|
982
|
+
this.child = null;
|
|
983
|
+
}
|
|
984
|
+
_processes.delete(this.sessionId);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
function getSessionProcess(sessionId) {
|
|
988
|
+
const existing = _processes.get(sessionId);
|
|
989
|
+
if (existing !== void 0) return existing;
|
|
990
|
+
const sp = new SessionProcess(sessionId);
|
|
991
|
+
_processes.set(sessionId, sp);
|
|
992
|
+
return sp;
|
|
993
|
+
}
|
|
890
994
|
const PROVIDER_TEST_SESSION_ID = "provider-test";
|
|
891
995
|
function getRuntimeMode() {
|
|
892
996
|
if (process.env["FINALIZER_USE_WORKER"] === "0") return "in-process";
|
|
893
997
|
const mode = process.env["FINALIZER_RUNTIME"];
|
|
998
|
+
if (mode === "process") return "child-process";
|
|
894
999
|
if (mode === "worker") return "worker-thread";
|
|
895
1000
|
if (mode === "inline") return "in-process";
|
|
896
|
-
return "child-process";
|
|
1001
|
+
return isSessionProcessAvailable() ? "child-process" : "in-process";
|
|
897
1002
|
}
|
|
898
1003
|
const sessions = /* @__PURE__ */ new Map();
|
|
899
1004
|
const knownLogSessions = /* @__PURE__ */ new Map();
|
|
@@ -2263,6 +2368,7 @@ function findProviderByModel(model) {
|
|
|
2263
2368
|
return null;
|
|
2264
2369
|
}
|
|
2265
2370
|
const execAsync = promisify(exec);
|
|
2371
|
+
const execFileAsync = promisify(execFile);
|
|
2266
2372
|
const cache = /* @__PURE__ */ new Map();
|
|
2267
2373
|
const CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
2268
2374
|
const MAX_CACHE_SIZE = 200;
|
|
@@ -2305,9 +2411,15 @@ async function lookupClientInfo(port) {
|
|
|
2305
2411
|
` Write-Output "$pid|$cmd"`,
|
|
2306
2412
|
`}`
|
|
2307
2413
|
].join("; ");
|
|
2308
|
-
const { stdout } = await
|
|
2309
|
-
|
|
2310
|
-
|
|
2414
|
+
const { stdout } = await execFileAsync(
|
|
2415
|
+
"powershell.exe",
|
|
2416
|
+
["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", psScript],
|
|
2417
|
+
{
|
|
2418
|
+
windowsHide: true,
|
|
2419
|
+
timeout: 3e3,
|
|
2420
|
+
maxBuffer: 64 * 1024
|
|
2421
|
+
}
|
|
2422
|
+
);
|
|
2311
2423
|
const trimmed = stdout.trim();
|
|
2312
2424
|
if (trimmed === "") {
|
|
2313
2425
|
return { port, pid: null, cwd: null, projectFolder: null };
|
|
@@ -2374,9 +2486,14 @@ async function lookupProcessInfo(pid) {
|
|
|
2374
2486
|
const platform = process.platform;
|
|
2375
2487
|
try {
|
|
2376
2488
|
if (platform === "win32") {
|
|
2377
|
-
const { stdout } = await
|
|
2378
|
-
|
|
2379
|
-
{
|
|
2489
|
+
const { stdout } = await execFileAsync(
|
|
2490
|
+
"wmic.exe",
|
|
2491
|
+
["process", "where", `processid=${pid}`, "get", "commandline", "/value"],
|
|
2492
|
+
{
|
|
2493
|
+
windowsHide: true,
|
|
2494
|
+
timeout: 3e3,
|
|
2495
|
+
maxBuffer: 64 * 1024
|
|
2496
|
+
}
|
|
2380
2497
|
);
|
|
2381
2498
|
const lines = stdout.trim().split("\n").filter(Boolean);
|
|
2382
2499
|
for (const line of lines) {
|
|
@@ -2646,99 +2763,6 @@ function stripOpenAIOrphanToolMessages(rawBody) {
|
|
|
2646
2763
|
parsed.messages = kept;
|
|
2647
2764
|
return { body: JSON.stringify(parsed), removed: indices.length, orphanIds };
|
|
2648
2765
|
}
|
|
2649
|
-
const IDLE_TIMEOUT_MS = Number(process.env["SESSION_PROCESS_IDLE_MS"]) || 5 * 60 * 1e3;
|
|
2650
|
-
const MAX_RESTARTS = 3;
|
|
2651
|
-
const _processes = /* @__PURE__ */ new Map();
|
|
2652
|
-
class SessionProcess {
|
|
2653
|
-
constructor(sessionId) {
|
|
2654
|
-
this.sessionId = sessionId;
|
|
2655
|
-
}
|
|
2656
|
-
child = null;
|
|
2657
|
-
pending = /* @__PURE__ */ new Map();
|
|
2658
|
-
nextId = 0;
|
|
2659
|
-
idleTimer = null;
|
|
2660
|
-
restartCount = 0;
|
|
2661
|
-
destroyed = false;
|
|
2662
|
-
/** Number of outstanding jobs sent to this process. */
|
|
2663
|
-
get pendingCount() {
|
|
2664
|
-
return this.pending.size;
|
|
2665
|
-
}
|
|
2666
|
-
ensureRunning() {
|
|
2667
|
-
if (this.child !== null && this.child.connected) return this.child;
|
|
2668
|
-
const entryPath = new URL("./sessionWorkerEntry.ts", import.meta.url).pathname;
|
|
2669
|
-
const resolvedPath = process.platform === "win32" && entryPath.startsWith("/") ? entryPath.slice(1) : entryPath;
|
|
2670
|
-
this.child = fork(resolvedPath, [], {
|
|
2671
|
-
stdio: ["pipe", "pipe", "pipe", "ipc"]
|
|
2672
|
-
});
|
|
2673
|
-
this.restartCount += 1;
|
|
2674
|
-
this.child.on("message", (msg) => {
|
|
2675
|
-
const pending = this.pending.get(msg.id);
|
|
2676
|
-
if (pending !== void 0) {
|
|
2677
|
-
this.pending.delete(msg.id);
|
|
2678
|
-
pending.resolve(msg.result);
|
|
2679
|
-
}
|
|
2680
|
-
this.resetIdleTimer();
|
|
2681
|
-
});
|
|
2682
|
-
this.child.on("error", (err) => {
|
|
2683
|
-
logger.error(`[sessionProcess] Session ${this.sessionId} process error:`, err.message);
|
|
2684
|
-
});
|
|
2685
|
-
this.child.on("exit", (code, signal) => {
|
|
2686
|
-
const wasConnected = this.child !== null;
|
|
2687
|
-
this.child = null;
|
|
2688
|
-
if (this.destroyed) return;
|
|
2689
|
-
for (const [, pending] of this.pending) {
|
|
2690
|
-
pending.reject(
|
|
2691
|
-
new Error(
|
|
2692
|
-
`Session process exited with code ${code ?? signal}, session=${this.sessionId}`
|
|
2693
|
-
)
|
|
2694
|
-
);
|
|
2695
|
-
}
|
|
2696
|
-
this.pending.clear();
|
|
2697
|
-
if (wasConnected && this.restartCount <= MAX_RESTARTS) {
|
|
2698
|
-
logger.warn(
|
|
2699
|
-
`[sessionProcess] Session ${this.sessionId} worker exited (code=${code ?? signal}), restart ${this.restartCount}/${MAX_RESTARTS}`
|
|
2700
|
-
);
|
|
2701
|
-
}
|
|
2702
|
-
});
|
|
2703
|
-
this.resetIdleTimer();
|
|
2704
|
-
return this.child;
|
|
2705
|
-
}
|
|
2706
|
-
enqueue(job) {
|
|
2707
|
-
return new Promise((resolve, reject) => {
|
|
2708
|
-
const child = this.ensureRunning();
|
|
2709
|
-
const id = String(++this.nextId);
|
|
2710
|
-
this.pending.set(id, { resolve, reject });
|
|
2711
|
-
child.send({ id, job });
|
|
2712
|
-
});
|
|
2713
|
-
}
|
|
2714
|
-
resetIdleTimer() {
|
|
2715
|
-
if (this.idleTimer !== null) clearTimeout(this.idleTimer);
|
|
2716
|
-
this.idleTimer = setTimeout(() => {
|
|
2717
|
-
if (this.pending.size === 0) {
|
|
2718
|
-
this.destroy();
|
|
2719
|
-
}
|
|
2720
|
-
}, IDLE_TIMEOUT_MS);
|
|
2721
|
-
}
|
|
2722
|
-
destroy() {
|
|
2723
|
-
this.destroyed = true;
|
|
2724
|
-
if (this.idleTimer !== null) {
|
|
2725
|
-
clearTimeout(this.idleTimer);
|
|
2726
|
-
this.idleTimer = null;
|
|
2727
|
-
}
|
|
2728
|
-
if (this.child !== null) {
|
|
2729
|
-
this.child.kill();
|
|
2730
|
-
this.child = null;
|
|
2731
|
-
}
|
|
2732
|
-
_processes.delete(this.sessionId);
|
|
2733
|
-
}
|
|
2734
|
-
}
|
|
2735
|
-
function getSessionProcess(sessionId) {
|
|
2736
|
-
const existing = _processes.get(sessionId);
|
|
2737
|
-
if (existing !== void 0) return existing;
|
|
2738
|
-
const sp = new SessionProcess(sessionId);
|
|
2739
|
-
_processes.set(sessionId, sp);
|
|
2740
|
-
return sp;
|
|
2741
|
-
}
|
|
2742
2766
|
function buildFileLogEntry(log, upstreamUrl) {
|
|
2743
2767
|
return {
|
|
2744
2768
|
timestamp: log.timestamp,
|
|
@@ -2873,9 +2897,10 @@ function commitFinalizeLogResult(result) {
|
|
|
2873
2897
|
const RUNTIME = (() => {
|
|
2874
2898
|
if (process.env["FINALIZER_USE_WORKER"] === "0") return "inline";
|
|
2875
2899
|
const mode = process.env["FINALIZER_RUNTIME"];
|
|
2900
|
+
if (mode === "process") return "process";
|
|
2876
2901
|
if (mode === "worker") return "worker";
|
|
2877
2902
|
if (mode === "inline") return "inline";
|
|
2878
|
-
return "process";
|
|
2903
|
+
return isSessionProcessAvailable() ? "process" : "inline";
|
|
2879
2904
|
})();
|
|
2880
2905
|
function executeBuildInSessionProcess(job) {
|
|
2881
2906
|
const sessionId = job.log.sessionId ?? "__unassigned__";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/session/$sessionId"], "preloads": ["/assets/main-
|
|
1
|
+
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/session/$sessionId"], "preloads": ["/assets/main-DpODUL6C.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-DqgTchf4.js", "/assets/ProxyViewerContainer-Bi1QXDYo.js"] }, "/api/config": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.ts", "children": ["/api/config/paths"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/mcp": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/mcp.ts" }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId", "/api/providers/export", "/api/providers/import", "/api/providers/scan"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/session/$sessionId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/session/$sessionId.tsx", "assets": [], "preloads": ["/assets/_sessionId-DE0J5YHU.js", "/assets/ProxyViewerContainer-Bi1QXDYo.js"] }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.import.ts" }, "/api/providers/scan": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.scan.ts" }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts", "children": ["/api/providers/$providerId/test/log"] }, "/api/providers/$providerId/test/log": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.log.ts" } }, "clientEntry": "/assets/main-DpODUL6C.js" });
|
|
2
2
|
export {
|
|
3
3
|
tsrStartManifest
|
|
4
4
|
};
|
package/.output/server/index.mjs
CHANGED
|
@@ -35,110 +35,110 @@ const headers = ((m) => function headersRouteRule(event) {
|
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
37
|
const assets = {
|
|
38
|
-
"/assets/
|
|
39
|
-
"type": "
|
|
40
|
-
"etag": '"
|
|
41
|
-
"mtime": "2026-06-
|
|
42
|
-
"size":
|
|
43
|
-
"path": "../public/assets/
|
|
38
|
+
"/assets/alibaba-TTwafVwX.svg": {
|
|
39
|
+
"type": "image/svg+xml",
|
|
40
|
+
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
41
|
+
"mtime": "2026-06-18T09:12:22.689Z",
|
|
42
|
+
"size": 5915,
|
|
43
|
+
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
44
44
|
},
|
|
45
|
-
"/assets/
|
|
46
|
-
"type": "
|
|
47
|
-
"etag": '"
|
|
48
|
-
"mtime": "2026-06-
|
|
49
|
-
"size":
|
|
50
|
-
"path": "../public/assets/
|
|
45
|
+
"/assets/index-Bqi9RAGS.css": {
|
|
46
|
+
"type": "text/css; charset=utf-8",
|
|
47
|
+
"etag": '"177a9-QMoW/GsYu1jERI0JyFHA9CiB/o0"',
|
|
48
|
+
"mtime": "2026-06-18T09:12:22.692Z",
|
|
49
|
+
"size": 96169,
|
|
50
|
+
"path": "../public/assets/index-Bqi9RAGS.css"
|
|
51
|
+
},
|
|
52
|
+
"/assets/json-viewer-CyJ5nYhX.js": {
|
|
53
|
+
"type": "text/javascript; charset=utf-8",
|
|
54
|
+
"etag": '"1e651-ydiPWeNOTBxab1yp6aZhKmFLc9w"',
|
|
55
|
+
"mtime": "2026-06-18T09:12:22.693Z",
|
|
56
|
+
"size": 124497,
|
|
57
|
+
"path": "../public/assets/json-viewer-CyJ5nYhX.js"
|
|
51
58
|
},
|
|
52
|
-
"/assets/index-
|
|
59
|
+
"/assets/index-DqgTchf4.js": {
|
|
53
60
|
"type": "text/javascript; charset=utf-8",
|
|
54
|
-
"etag": '"74-
|
|
55
|
-
"mtime": "2026-06-
|
|
61
|
+
"etag": '"74-dCXgAHXAyb0J55GEgjrhbbUgzbc"',
|
|
62
|
+
"mtime": "2026-06-18T09:12:22.692Z",
|
|
56
63
|
"size": 116,
|
|
57
|
-
"path": "../public/assets/index-
|
|
64
|
+
"path": "../public/assets/index-DqgTchf4.js"
|
|
58
65
|
},
|
|
59
|
-
"/assets/
|
|
66
|
+
"/assets/CompareDrawer-AMCFfwDw.js": {
|
|
60
67
|
"type": "text/javascript; charset=utf-8",
|
|
61
|
-
"etag": '"
|
|
62
|
-
"mtime": "2026-06-
|
|
63
|
-
"size":
|
|
64
|
-
"path": "../public/assets/
|
|
68
|
+
"etag": '"4a1f-JS26/3WLLROR+e/DYSYJ+f7WiQc"',
|
|
69
|
+
"mtime": "2026-06-18T09:12:22.693Z",
|
|
70
|
+
"size": 18975,
|
|
71
|
+
"path": "../public/assets/CompareDrawer-AMCFfwDw.js"
|
|
65
72
|
},
|
|
66
|
-
"/assets/
|
|
67
|
-
"type": "text/
|
|
68
|
-
"etag": '"
|
|
69
|
-
"mtime": "2026-06-
|
|
70
|
-
"size":
|
|
71
|
-
"path": "../public/assets/
|
|
73
|
+
"/assets/ReplayDialog-C1x2-73A.js": {
|
|
74
|
+
"type": "text/javascript; charset=utf-8",
|
|
75
|
+
"etag": '"11c0-0BdsMUTzMbm8+qZrAg7WR+cZJxI"',
|
|
76
|
+
"mtime": "2026-06-18T09:12:22.692Z",
|
|
77
|
+
"size": 4544,
|
|
78
|
+
"path": "../public/assets/ReplayDialog-C1x2-73A.js"
|
|
72
79
|
},
|
|
73
|
-
"/assets/
|
|
80
|
+
"/assets/StreamingChunkSequence-BjX20-9R.js": {
|
|
74
81
|
"type": "text/javascript; charset=utf-8",
|
|
75
|
-
"etag": '"
|
|
76
|
-
"mtime": "2026-06-
|
|
77
|
-
"size":
|
|
78
|
-
"path": "../public/assets/
|
|
82
|
+
"etag": '"d81-wlp9qhgGUggvmv1Zxwa60zK7kv0"',
|
|
83
|
+
"mtime": "2026-06-18T09:12:22.693Z",
|
|
84
|
+
"size": 3457,
|
|
85
|
+
"path": "../public/assets/StreamingChunkSequence-BjX20-9R.js"
|
|
79
86
|
},
|
|
80
|
-
"/assets/ResponseView-
|
|
87
|
+
"/assets/ResponseView-BsBxYW8b.js": {
|
|
81
88
|
"type": "text/javascript; charset=utf-8",
|
|
82
|
-
"etag": '"6e91-
|
|
83
|
-
"mtime": "2026-06-
|
|
89
|
+
"etag": '"6e91-dcQF6OvaeJlJzeXqydW9EwIelj8"',
|
|
90
|
+
"mtime": "2026-06-18T09:12:22.693Z",
|
|
84
91
|
"size": 28305,
|
|
85
|
-
"path": "../public/assets/ResponseView-
|
|
92
|
+
"path": "../public/assets/ResponseView-BsBxYW8b.js"
|
|
86
93
|
},
|
|
87
|
-
"/assets/
|
|
88
|
-
"type": "
|
|
89
|
-
"etag": '"
|
|
90
|
-
"mtime": "2026-06-
|
|
91
|
-
"size":
|
|
92
|
-
"path": "../public/assets/
|
|
94
|
+
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
95
|
+
"type": "image/jpeg",
|
|
96
|
+
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
97
|
+
"mtime": "2026-06-18T09:12:22.692Z",
|
|
98
|
+
"size": 6918,
|
|
99
|
+
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
93
100
|
},
|
|
94
101
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
95
102
|
"type": "image/svg+xml",
|
|
96
103
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
97
|
-
"mtime": "2026-06-
|
|
104
|
+
"mtime": "2026-06-18T09:12:22.692Z",
|
|
98
105
|
"size": 11256,
|
|
99
106
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
100
107
|
},
|
|
101
|
-
"/assets/
|
|
102
|
-
"type": "text/javascript; charset=utf-8",
|
|
103
|
-
"etag": '"d2-gL7mjPIXj+6BHz4XUVVdKjuvNDk"',
|
|
104
|
-
"mtime": "2026-06-18T01:14:51.128Z",
|
|
105
|
-
"size": 210,
|
|
106
|
-
"path": "../public/assets/_sessionId-C-aKd1Ky.js"
|
|
107
|
-
},
|
|
108
|
-
"/assets/main-CR9IJlz1.js": {
|
|
109
|
-
"type": "text/javascript; charset=utf-8",
|
|
110
|
-
"etag": '"50a37-XeRUA7+G6lgGxJXRg+juq8ZZbMM"',
|
|
111
|
-
"mtime": "2026-06-18T01:14:51.128Z",
|
|
112
|
-
"size": 330295,
|
|
113
|
-
"path": "../public/assets/main-CR9IJlz1.js"
|
|
114
|
-
},
|
|
115
|
-
"/assets/alibaba-TTwafVwX.svg": {
|
|
116
|
-
"type": "image/svg+xml",
|
|
117
|
-
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
118
|
-
"mtime": "2026-06-18T01:14:51.128Z",
|
|
119
|
-
"size": 5915,
|
|
120
|
-
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
121
|
-
},
|
|
122
|
-
"/assets/ProxyViewerContainer-DfxRK7Nt.js": {
|
|
108
|
+
"/assets/main-DpODUL6C.js": {
|
|
123
109
|
"type": "text/javascript; charset=utf-8",
|
|
124
|
-
"etag": '"
|
|
125
|
-
"mtime": "2026-06-
|
|
126
|
-
"size":
|
|
127
|
-
"path": "../public/assets/
|
|
110
|
+
"etag": '"50e93-I+c4WJ0eqNgllRdD+TE3/FNhdZw"',
|
|
111
|
+
"mtime": "2026-06-18T09:12:22.692Z",
|
|
112
|
+
"size": 331411,
|
|
113
|
+
"path": "../public/assets/main-DpODUL6C.js"
|
|
128
114
|
},
|
|
129
115
|
"/assets/qwen-CONDcHqt.png": {
|
|
130
116
|
"type": "image/png",
|
|
131
117
|
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
132
|
-
"mtime": "2026-06-
|
|
118
|
+
"mtime": "2026-06-18T09:12:22.692Z",
|
|
133
119
|
"size": 357059,
|
|
134
120
|
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
135
121
|
},
|
|
136
|
-
"/assets/
|
|
122
|
+
"/assets/RequestAnatomy-CBNqMbxo.js": {
|
|
137
123
|
"type": "text/javascript; charset=utf-8",
|
|
138
|
-
"etag": '"
|
|
139
|
-
"mtime": "2026-06-
|
|
140
|
-
"size":
|
|
141
|
-
"path": "../public/assets/
|
|
124
|
+
"etag": '"142a-OyCo/ZrZQjHOESLPR2QHdrDlSfY"',
|
|
125
|
+
"mtime": "2026-06-18T09:12:22.693Z",
|
|
126
|
+
"size": 5162,
|
|
127
|
+
"path": "../public/assets/RequestAnatomy-CBNqMbxo.js"
|
|
128
|
+
},
|
|
129
|
+
"/assets/ProxyViewerContainer-Bi1QXDYo.js": {
|
|
130
|
+
"type": "text/javascript; charset=utf-8",
|
|
131
|
+
"etag": '"76fed-g89dZRBRI198ItonW8vjcw/8gls"',
|
|
132
|
+
"mtime": "2026-06-18T09:12:22.692Z",
|
|
133
|
+
"size": 487405,
|
|
134
|
+
"path": "../public/assets/ProxyViewerContainer-Bi1QXDYo.js"
|
|
135
|
+
},
|
|
136
|
+
"/assets/_sessionId-DE0J5YHU.js": {
|
|
137
|
+
"type": "text/javascript; charset=utf-8",
|
|
138
|
+
"etag": '"d2-yTX8F3UFbyfcaXlKoGMrmxJtX0U"',
|
|
139
|
+
"mtime": "2026-06-18T09:12:22.692Z",
|
|
140
|
+
"size": 210,
|
|
141
|
+
"path": "../public/assets/_sessionId-DE0J5YHU.js"
|
|
142
142
|
}
|
|
143
143
|
};
|
|
144
144
|
function readAsset(id) {
|
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
- **Web UI**:`http://localhost:25947`
|
|
19
19
|
- **Proxy**:`http://localhost:25947/proxy`
|
|
20
20
|
- **MCP Server**:`http://localhost:25947/api/mcp`
|
|
21
|
+
- **Chrome Companion**:`extensions/chrome`(通过 `chrome://extensions` 以 Load unpacked 方式加载)
|
|
21
22
|
|
|
22
23
|
## 核心能力
|
|
23
24
|
|
|
@@ -53,6 +54,8 @@ llm-inspector
|
|
|
53
54
|
```bash
|
|
54
55
|
llm-inspector --no-open
|
|
55
56
|
llm-inspector --port 3000
|
|
57
|
+
llm-inspector --background
|
|
58
|
+
llm-inspector --force-restart
|
|
56
59
|
llm-inspector --config-dir ./local-config
|
|
57
60
|
llm-inspector --providers '[{"name":"OpenAI","apiKey":"sk-...","models":["gpt-4o-mini"],"openaiBaseUrl":"https://api.openai.com/v1","authHeader":"bearer","createdAt":"2026-01-01T00:00:00.000Z","updatedAt":"2026-01-01T00:00:00.000Z","id":"demo"}]'
|
|
58
61
|
```
|
|
@@ -73,6 +76,23 @@ bun install
|
|
|
73
76
|
bun run dev
|
|
74
77
|
```
|
|
75
78
|
|
|
79
|
+
### Chrome Companion 扩展
|
|
80
|
+
|
|
81
|
+
仓库内提供了一个轻量 Chrome 侧边栏扩展,用来连接本机 llm-inspector、查看运行状态和最近请求,并快速打开 Dashboard 或复制代理命令。
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
extensions/chrome
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
启动方式:
|
|
88
|
+
|
|
89
|
+
1. 先运行 `llm-inspector` 或 `bun run dev`。
|
|
90
|
+
2. 打开 `chrome://extensions`。
|
|
91
|
+
3. 开启 **Developer mode**。
|
|
92
|
+
4. 点击 **Load unpacked**。
|
|
93
|
+
5. 选择 `extensions/chrome` 目录。
|
|
94
|
+
6. 点击扩展图标打开侧边栏。
|
|
95
|
+
|
|
76
96
|
## 配置 Provider
|
|
77
97
|
|
|
78
98
|
打开 Web UI,进入 **Settings** 添加 Provider:
|
|
@@ -315,6 +335,8 @@ ANTHROPIC_BASE_URL=http://localhost:25947/proxy claude
|
|
|
315
335
|
- [架构说明](docs/Architecture.md)
|
|
316
336
|
- [开发指南](docs/Development.md)
|
|
317
337
|
- [MCP Server](docs/MCP-Server.md)
|
|
338
|
+
- [CHANGELOG](CHANGELOG.md) — release notes
|
|
339
|
+
- [CONTRIBUTING](CONTRIBUTING.md) — how to land a change
|
|
318
340
|
|
|
319
341
|
## License
|
|
320
342
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tonyclaw/llm-inspector",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.3",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "LLM API
|
|
5
|
+
"description": "Local LLM API inspector for AI coding tools, with real-time request and response capture.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git"
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
"lint": "eslint .",
|
|
41
41
|
"format": "biome format --write .",
|
|
42
42
|
"format:check": "biome format .",
|
|
43
|
+
"extension:zip": "node scripts/pack-chrome-extension.mjs",
|
|
44
|
+
"extension:release": "node scripts/release-chrome-extension.mjs",
|
|
43
45
|
"knip": "knip",
|
|
44
46
|
"check": "bun format && bun typecheck && bun lint",
|
|
45
47
|
"prepare": "husky",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="LLM Inspector">
|
|
2
|
+
<rect width="64" height="64" rx="14" fill="#111827" />
|
|
3
|
+
<g fill="none" stroke="#f59e0b" stroke-width="4.2" stroke-linecap="round" stroke-linejoin="round">
|
|
4
|
+
<path fill="#f59e0b" d="M15 36c0-11 7-18 17-18s17 7 17 18c0 8-7 13-17 13s-17-5-17-13z" />
|
|
5
|
+
<path d="M16 31c-6-5-12-3-12 4 0 5 6 6 11 2" />
|
|
6
|
+
<path d="M48 31c6-5 12-3 12 4 0 5-6 6-11 2" />
|
|
7
|
+
<path d="M27 19l-3-7" />
|
|
8
|
+
<path d="M37 19l3-7" />
|
|
9
|
+
<path d="M19 45l-6 9" />
|
|
10
|
+
<path d="M27 48l-3 9" />
|
|
11
|
+
<path d="M37 48l3 9" />
|
|
12
|
+
<path d="M45 45l6 9" />
|
|
13
|
+
</g>
|
|
14
|
+
<circle cx="24" cy="11" r="3.2" fill="#f59e0b" />
|
|
15
|
+
<circle cx="40" cy="11" r="3.2" fill="#f59e0b" />
|
|
16
|
+
<circle cx="25" cy="34" r="2.1" fill="#111827" />
|
|
17
|
+
<circle cx="39" cy="34" r="2.1" fill="#111827" />
|
|
18
|
+
</svg>
|
package/src/cli/detect-tools.ts
CHANGED
|
@@ -47,6 +47,7 @@ function which(bin: string): string | null {
|
|
|
47
47
|
const out = execFileSync("where", [bin], {
|
|
48
48
|
encoding: "utf8",
|
|
49
49
|
timeout: 3000,
|
|
50
|
+
windowsHide: true,
|
|
50
51
|
stdio: ["ignore", "pipe", "ignore"],
|
|
51
52
|
});
|
|
52
53
|
const first = out.split(/\r?\n/).find((line) => line.trim().length > 0);
|