@tonyclaw/llm-inspector 1.16.1 → 1.16.2
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/index-BdXOO2hn.js +107 -0
- package/.output/public/assets/index-DRRCmu5p.css +1 -0
- package/.output/public/assets/{main-BA7dEkGs.js → main-pT0WLAFQ.js} +1 -1
- package/.output/server/_libs/lucide-react.mjs +2 -2
- package/.output/server/_ssr/{index-quoKBRYG.mjs → index-BVUWpOQi.mjs} +2747 -2474
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-DxmdQgBG.mjs → router-DEx3DlVG.mjs} +8 -6
- package/.output/server/{_tanstack-start-manifest_v-CXomfWbm.mjs → _tanstack-start-manifest_v-nEbvsqrj.mjs} +1 -1
- package/.output/server/index.mjs +24 -24
- package/package.json +1 -1
- package/src/components/OnboardingBanner.tsx +67 -0
- package/src/components/ProxyViewer.tsx +24 -34
- package/src/components/ProxyViewerContainer.tsx +2 -0
- package/src/components/providers/SettingsDialog.tsx +15 -25
- package/src/components/proxy-viewer/LogEntry.tsx +4 -34
- package/src/components/proxy-viewer/LogEntryHeader.tsx +12 -29
- package/src/components/proxy-viewer/ThreadConnector.tsx +70 -66
- package/src/components/proxy-viewer/TurnGroup.tsx +237 -36
- package/src/components/ui/json-viewer.tsx +9 -2
- package/src/lib/runtimeConfig.ts +1 -0
- package/src/lib/useOnboarding.ts +74 -0
- package/src/proxy/config.ts +2 -2
- package/src/routes/api/config.ts +1 -0
- package/.output/public/assets/index-BhFaDZUL.js +0 -107
- package/.output/public/assets/index-DPe3eOih.css +0 -1
|
@@ -198,7 +198,7 @@ function getResponse() {
|
|
|
198
198
|
return event.res;
|
|
199
199
|
}
|
|
200
200
|
async function getStartManifest(matchedRoutes) {
|
|
201
|
-
const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-
|
|
201
|
+
const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-nEbvsqrj.mjs");
|
|
202
202
|
const startManifest = tsrStartManifest();
|
|
203
203
|
const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
|
|
204
204
|
rootRoute.assets = rootRoute.assets || [];
|
|
@@ -767,7 +767,7 @@ let entriesPromise;
|
|
|
767
767
|
let baseManifestPromise;
|
|
768
768
|
let cachedFinalManifestPromise;
|
|
769
769
|
async function loadEntries() {
|
|
770
|
-
const routerEntry = await import("./router-
|
|
770
|
+
const routerEntry = await import("./router-DEx3DlVG.mjs").then((n) => n.e);
|
|
771
771
|
const startEntry = await import("./start-HYkvq4Ni.mjs");
|
|
772
772
|
return { startEntry, routerEntry };
|
|
773
773
|
}
|
|
@@ -46,7 +46,7 @@ import "../_libs/debounce-fn.mjs";
|
|
|
46
46
|
import "../_libs/mimic-function.mjs";
|
|
47
47
|
import "../_libs/semver.mjs";
|
|
48
48
|
import "../_libs/uint8array-extras.mjs";
|
|
49
|
-
const appCss = "/assets/index-
|
|
49
|
+
const appCss = "/assets/index-DRRCmu5p.css";
|
|
50
50
|
const Route$k = createRootRoute({
|
|
51
51
|
head: () => ({
|
|
52
52
|
meta: [
|
|
@@ -70,7 +70,7 @@ function RootDocument({ children }) {
|
|
|
70
70
|
] })
|
|
71
71
|
] });
|
|
72
72
|
}
|
|
73
|
-
const $$splitComponentImporter = () => import("./index-
|
|
73
|
+
const $$splitComponentImporter = () => import("./index-BVUWpOQi.mjs");
|
|
74
74
|
const Route$j = createFileRoute("/")({
|
|
75
75
|
component: lazyRouteComponent($$splitComponentImporter, "component")
|
|
76
76
|
});
|
|
@@ -2159,7 +2159,8 @@ async function getClientInfo(request) {
|
|
|
2159
2159
|
return promise;
|
|
2160
2160
|
}
|
|
2161
2161
|
const RuntimeConfigSchema = object({
|
|
2162
|
-
stripClaudeCodeBillingHeader: boolean()
|
|
2162
|
+
stripClaudeCodeBillingHeader: boolean(),
|
|
2163
|
+
hasSeenOnboarding: boolean().default(false)
|
|
2163
2164
|
});
|
|
2164
2165
|
function getConfigFilePath() {
|
|
2165
2166
|
return join(getDataDir(), "config.json");
|
|
@@ -2189,9 +2190,9 @@ function resolveInitialConfig() {
|
|
|
2189
2190
|
}
|
|
2190
2191
|
}
|
|
2191
2192
|
if (process.env["LLM_INSPECTOR_STRIP_CLAUDE_CODE_BILLING_HEADER"] === "1") {
|
|
2192
|
-
return { stripClaudeCodeBillingHeader: true };
|
|
2193
|
+
return { stripClaudeCodeBillingHeader: true, hasSeenOnboarding: false };
|
|
2193
2194
|
}
|
|
2194
|
-
return { stripClaudeCodeBillingHeader: false };
|
|
2195
|
+
return { stripClaudeCodeBillingHeader: false, hasSeenOnboarding: false };
|
|
2195
2196
|
}
|
|
2196
2197
|
function getConfig() {
|
|
2197
2198
|
return currentConfig;
|
|
@@ -3277,7 +3278,8 @@ const Route$c = createFileRoute("/api/health")({
|
|
|
3277
3278
|
}
|
|
3278
3279
|
});
|
|
3279
3280
|
const RuntimeConfigPatchSchema = object({
|
|
3280
|
-
stripClaudeCodeBillingHeader: boolean().optional()
|
|
3281
|
+
stripClaudeCodeBillingHeader: boolean().optional(),
|
|
3282
|
+
hasSeenOnboarding: boolean().optional()
|
|
3281
3283
|
}).strict().refine((v) => Object.keys(v).length > 0, {
|
|
3282
3284
|
message: "At least one field must be provided"
|
|
3283
3285
|
});
|
|
@@ -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/$"], "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/$"], "preloads": ["/assets/main-pT0WLAFQ.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-BdXOO2hn.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" }, "/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-pT0WLAFQ.js" });
|
|
2
2
|
export {
|
|
3
3
|
tsrStartManifest
|
|
4
4
|
};
|
package/.output/server/index.mjs
CHANGED
|
@@ -38,51 +38,51 @@ const assets = {
|
|
|
38
38
|
"/assets/alibaba-TTwafVwX.svg": {
|
|
39
39
|
"type": "image/svg+xml",
|
|
40
40
|
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
41
|
-
"mtime": "2026-06-
|
|
41
|
+
"mtime": "2026-06-13T12:44:57.474Z",
|
|
42
42
|
"size": 5915,
|
|
43
43
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
44
44
|
},
|
|
45
45
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
46
46
|
"type": "image/jpeg",
|
|
47
47
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
48
|
-
"mtime": "2026-06-
|
|
48
|
+
"mtime": "2026-06-13T12:44:57.474Z",
|
|
49
49
|
"size": 6918,
|
|
50
50
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
51
51
|
},
|
|
52
|
-
"/assets/index-
|
|
52
|
+
"/assets/index-DRRCmu5p.css": {
|
|
53
53
|
"type": "text/css; charset=utf-8",
|
|
54
|
-
"etag": '"
|
|
55
|
-
"mtime": "2026-06-
|
|
56
|
-
"size":
|
|
57
|
-
"path": "../public/assets/index-
|
|
54
|
+
"etag": '"15b6a-YPwntwMQpIU2AWIj8lgGWZpCwQw"',
|
|
55
|
+
"mtime": "2026-06-13T12:44:57.477Z",
|
|
56
|
+
"size": 88938,
|
|
57
|
+
"path": "../public/assets/index-DRRCmu5p.css"
|
|
58
58
|
},
|
|
59
|
-
"/assets/
|
|
59
|
+
"/assets/qwen-CONDcHqt.png": {
|
|
60
|
+
"type": "image/png",
|
|
61
|
+
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
62
|
+
"mtime": "2026-06-13T12:44:57.474Z",
|
|
63
|
+
"size": 357059,
|
|
64
|
+
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
65
|
+
},
|
|
66
|
+
"/assets/main-pT0WLAFQ.js": {
|
|
60
67
|
"type": "text/javascript; charset=utf-8",
|
|
61
|
-
"etag": '"50599-
|
|
62
|
-
"mtime": "2026-06-
|
|
68
|
+
"etag": '"50599-82xbDaMtgdQpwvS5w+mS0iJpU3M"',
|
|
69
|
+
"mtime": "2026-06-13T12:44:57.477Z",
|
|
63
70
|
"size": 329113,
|
|
64
|
-
"path": "../public/assets/main-
|
|
71
|
+
"path": "../public/assets/main-pT0WLAFQ.js"
|
|
65
72
|
},
|
|
66
73
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
67
74
|
"type": "image/svg+xml",
|
|
68
75
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
69
|
-
"mtime": "2026-06-
|
|
76
|
+
"mtime": "2026-06-13T12:44:57.475Z",
|
|
70
77
|
"size": 11256,
|
|
71
78
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
72
79
|
},
|
|
73
|
-
"/assets/
|
|
74
|
-
"type": "image/png",
|
|
75
|
-
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
76
|
-
"mtime": "2026-06-13T09:20:36.492Z",
|
|
77
|
-
"size": 357059,
|
|
78
|
-
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
79
|
-
},
|
|
80
|
-
"/assets/index-BhFaDZUL.js": {
|
|
80
|
+
"/assets/index-BdXOO2hn.js": {
|
|
81
81
|
"type": "text/javascript; charset=utf-8",
|
|
82
|
-
"etag": '"
|
|
83
|
-
"mtime": "2026-06-
|
|
84
|
-
"size":
|
|
85
|
-
"path": "../public/assets/index-
|
|
82
|
+
"etag": '"9be56-XbSfCtl5VqxwdRzwEGzflxc3heE"',
|
|
83
|
+
"mtime": "2026-06-13T12:44:57.477Z",
|
|
84
|
+
"size": 638550,
|
|
85
|
+
"path": "../public/assets/index-BdXOO2hn.js"
|
|
86
86
|
}
|
|
87
87
|
};
|
|
88
88
|
function readAsset(id) {
|
package/package.json
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Check, X } from "lucide-react";
|
|
2
|
+
import type { JSX } from "react";
|
|
3
|
+
import { useOnboarding } from "../lib/useOnboarding";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* First-launch onboarding banner. Shows once on a fresh install (or
|
|
7
|
+
* any user who hasn't yet dismissed it), explains the per-tab data
|
|
8
|
+
* shapes the proxy captures, and disappears forever on dismissal.
|
|
9
|
+
*
|
|
10
|
+
* The "seen" state lives in the server's runtime config — see
|
|
11
|
+
* `useOnboarding` — so the dismissal persists across browser sessions
|
|
12
|
+
* and devices for the same install.
|
|
13
|
+
*/
|
|
14
|
+
export function OnboardingBanner(): JSX.Element | null {
|
|
15
|
+
const { hasSeenOnboarding, isLoading, markSeen } = useOnboarding();
|
|
16
|
+
|
|
17
|
+
if (isLoading || hasSeenOnboarding) return null;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
role="note"
|
|
22
|
+
aria-label="Onboarding tip"
|
|
23
|
+
className="mx-4 mt-2 mb-1 flex items-start gap-3 rounded-md border border-amber-500/30 bg-amber-500/5 px-4 py-3 text-sm"
|
|
24
|
+
>
|
|
25
|
+
<div className="flex-1 min-w-0">
|
|
26
|
+
<div className="font-medium text-amber-600 dark:text-amber-400 mb-1">
|
|
27
|
+
Quick tour of the log tabs
|
|
28
|
+
</div>
|
|
29
|
+
<ul className="space-y-0.5 text-muted-foreground text-xs leading-relaxed">
|
|
30
|
+
<li>
|
|
31
|
+
<strong>Request</strong> / <strong>Response</strong> — structured views of what the
|
|
32
|
+
proxy sent and received.
|
|
33
|
+
</li>
|
|
34
|
+
<li>
|
|
35
|
+
<strong>Headers</strong> — request and response headers after proxy processing.
|
|
36
|
+
</li>
|
|
37
|
+
<li>
|
|
38
|
+
<strong>Raw Headers</strong> / <strong>Raw Request</strong> /{" "}
|
|
39
|
+
<strong>Raw Response</strong> — exact bytes from the upstream provider (visible in Full
|
|
40
|
+
mode).
|
|
41
|
+
</li>
|
|
42
|
+
</ul>
|
|
43
|
+
</div>
|
|
44
|
+
<button
|
|
45
|
+
type="button"
|
|
46
|
+
onClick={() => {
|
|
47
|
+
void markSeen();
|
|
48
|
+
}}
|
|
49
|
+
className="inline-flex items-center gap-1.5 text-xs px-2.5 py-1.5 rounded-md border border-amber-500/40 text-amber-700 dark:text-amber-300 hover:bg-amber-500/10 transition-colors shrink-0"
|
|
50
|
+
aria-label="Dismiss onboarding tip"
|
|
51
|
+
>
|
|
52
|
+
<Check className="size-3" />
|
|
53
|
+
Got it
|
|
54
|
+
</button>
|
|
55
|
+
<button
|
|
56
|
+
type="button"
|
|
57
|
+
onClick={() => {
|
|
58
|
+
void markSeen();
|
|
59
|
+
}}
|
|
60
|
+
className="text-muted-foreground hover:text-foreground transition-colors shrink-0 p-1 -m-1"
|
|
61
|
+
aria-label="Dismiss"
|
|
62
|
+
>
|
|
63
|
+
<X className="size-3.5" />
|
|
64
|
+
</button>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type JSX, useCallback, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { Download } from "lucide-react";
|
|
3
3
|
|
|
4
|
-
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "./ui/tooltip";
|
|
5
4
|
import type { CapturedLog } from "../proxy/schemas";
|
|
6
5
|
import { exportLogsAsZip } from "../lib/export-logs";
|
|
7
6
|
import packageJson from "../../package.json";
|
|
@@ -245,39 +244,30 @@ export function ProxyViewer({
|
|
|
245
244
|
))}
|
|
246
245
|
</SelectContent>
|
|
247
246
|
</Select>
|
|
248
|
-
<
|
|
249
|
-
<
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
Full
|
|
273
|
-
</button>
|
|
274
|
-
</div>
|
|
275
|
-
</TooltipTrigger>
|
|
276
|
-
<TooltipContent>
|
|
277
|
-
Simple shows parsed output; Full adds raw headers and tokens
|
|
278
|
-
</TooltipContent>
|
|
279
|
-
</Tooltip>
|
|
280
|
-
</TooltipProvider>
|
|
247
|
+
<div className="flex items-center border border-border rounded-md overflow-hidden">
|
|
248
|
+
<button
|
|
249
|
+
type="button"
|
|
250
|
+
onClick={() => onViewModeChange("simple")}
|
|
251
|
+
className={`px-2 py-1 cursor-pointer transition-colors text-xs ${
|
|
252
|
+
viewMode === "simple"
|
|
253
|
+
? "bg-muted text-foreground"
|
|
254
|
+
: "text-muted-foreground hover:bg-muted/50"
|
|
255
|
+
}`}
|
|
256
|
+
>
|
|
257
|
+
Simple
|
|
258
|
+
</button>
|
|
259
|
+
<button
|
|
260
|
+
type="button"
|
|
261
|
+
onClick={() => onViewModeChange("full")}
|
|
262
|
+
className={`px-2 py-1 cursor-pointer transition-colors text-xs ${
|
|
263
|
+
viewMode === "full"
|
|
264
|
+
? "bg-muted text-foreground"
|
|
265
|
+
: "text-muted-foreground hover:bg-muted/50"
|
|
266
|
+
}`}
|
|
267
|
+
>
|
|
268
|
+
Full
|
|
269
|
+
</button>
|
|
270
|
+
</div>
|
|
281
271
|
<div className="flex-1" />
|
|
282
272
|
<span className="text-muted-foreground text-xs font-mono">
|
|
283
273
|
{logs.length} request{logs.length !== 1 ? "s" : ""}
|
|
@@ -2,6 +2,7 @@ import { useState, useEffect, useCallback, useRef, useMemo, type JSX } from "rea
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { CapturedLogSchema, type CapturedLog } from "../proxy/schemas";
|
|
4
4
|
import { useStripConfig } from "../lib/useStripConfig";
|
|
5
|
+
import { OnboardingBanner } from "./OnboardingBanner";
|
|
5
6
|
import { ProxyViewer } from "./ProxyViewer";
|
|
6
7
|
|
|
7
8
|
type SSEUpdate =
|
|
@@ -279,6 +280,7 @@ export function ProxyViewerContainer(): JSX.Element {
|
|
|
279
280
|
{error}
|
|
280
281
|
</div>
|
|
281
282
|
)}
|
|
283
|
+
<OnboardingBanner />
|
|
282
284
|
<ProxyViewer
|
|
283
285
|
logs={logs}
|
|
284
286
|
sessions={sessions}
|
|
@@ -3,7 +3,6 @@ import { Settings } from "lucide-react";
|
|
|
3
3
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "../ui/dialog";
|
|
4
4
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from "../ui/tabs";
|
|
5
5
|
import { Button } from "../ui/button";
|
|
6
|
-
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../ui/tooltip";
|
|
7
6
|
import { ProvidersPanel } from "./ProvidersPanel";
|
|
8
7
|
import { useProviders } from "../../lib/useProviders";
|
|
9
8
|
import { useStripConfig } from "../../lib/useStripConfig";
|
|
@@ -130,30 +129,21 @@ function ProxySettingsTab(): JSX.Element {
|
|
|
130
129
|
</p>
|
|
131
130
|
</div>
|
|
132
131
|
|
|
133
|
-
<
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
{isLoading ? "Loading…" : strip ? "Stripping enabled" : "Stripping disabled"}
|
|
149
|
-
</span>
|
|
150
|
-
</label>
|
|
151
|
-
</TooltipTrigger>
|
|
152
|
-
<TooltipContent>
|
|
153
|
-
Strip Claude Code billing header to improve cache hit rates
|
|
154
|
-
</TooltipContent>
|
|
155
|
-
</Tooltip>
|
|
156
|
-
</TooltipProvider>
|
|
132
|
+
<label className="flex items-center gap-3">
|
|
133
|
+
<input
|
|
134
|
+
type="checkbox"
|
|
135
|
+
role="switch"
|
|
136
|
+
checked={strip}
|
|
137
|
+
disabled={isLoading || pending}
|
|
138
|
+
onChange={(e) => {
|
|
139
|
+
void handleToggle(e.currentTarget.checked);
|
|
140
|
+
}}
|
|
141
|
+
className="size-4 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50"
|
|
142
|
+
/>
|
|
143
|
+
<span className="text-sm">
|
|
144
|
+
{isLoading ? "Loading…" : strip ? "Stripping enabled" : "Stripping disabled"}
|
|
145
|
+
</span>
|
|
146
|
+
</label>
|
|
157
147
|
|
|
158
148
|
{error !== null && <p className="text-xs text-destructive">Failed to save: {error}</p>}
|
|
159
149
|
</div>
|
|
@@ -248,43 +248,13 @@ export const LogEntry = memo(function ({
|
|
|
248
248
|
<div onClick={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()}>
|
|
249
249
|
<Tabs value={activeTab} onValueChange={setActiveTab}>
|
|
250
250
|
<TabsList className="mx-4 mt-2">
|
|
251
|
-
{viewMode === "full" &&
|
|
252
|
-
|
|
253
|
-
<TooltipTrigger asChild>
|
|
254
|
-
<TabsTrigger value="raw-headers">Raw Headers</TabsTrigger>
|
|
255
|
-
</TooltipTrigger>
|
|
256
|
-
<TooltipContent>
|
|
257
|
-
HTTP headers received from the upstream provider
|
|
258
|
-
</TooltipContent>
|
|
259
|
-
</Tooltip>
|
|
260
|
-
)}
|
|
261
|
-
{viewMode === "full" && (
|
|
262
|
-
<Tooltip>
|
|
263
|
-
<TooltipTrigger asChild>
|
|
264
|
-
<TabsTrigger value="headers">Headers</TabsTrigger>
|
|
265
|
-
</TooltipTrigger>
|
|
266
|
-
<TooltipContent>Request and response headers sent and received</TooltipContent>
|
|
267
|
-
</Tooltip>
|
|
268
|
-
)}
|
|
251
|
+
{viewMode === "full" && <TabsTrigger value="raw-headers">Raw Headers</TabsTrigger>}
|
|
252
|
+
{viewMode === "full" && <TabsTrigger value="headers">Headers</TabsTrigger>}
|
|
269
253
|
{shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && (
|
|
270
|
-
<
|
|
271
|
-
<TooltipTrigger asChild>
|
|
272
|
-
<TabsTrigger value="raw-request">Raw Request</TabsTrigger>
|
|
273
|
-
</TooltipTrigger>
|
|
274
|
-
<TooltipContent>
|
|
275
|
-
Exact HTTP request sent to the upstream provider
|
|
276
|
-
</TooltipContent>
|
|
277
|
-
</Tooltip>
|
|
254
|
+
<TabsTrigger value="raw-request">Raw Request</TabsTrigger>
|
|
278
255
|
)}
|
|
279
256
|
<TabsTrigger value="request">Request</TabsTrigger>
|
|
280
|
-
{viewMode === "full" &&
|
|
281
|
-
<Tooltip>
|
|
282
|
-
<TooltipTrigger asChild>
|
|
283
|
-
<TabsTrigger value="raw">Raw Response</TabsTrigger>
|
|
284
|
-
</TooltipTrigger>
|
|
285
|
-
<TooltipContent>Exact HTTP response from the upstream provider</TooltipContent>
|
|
286
|
-
</Tooltip>
|
|
287
|
-
)}
|
|
257
|
+
{viewMode === "full" && <TabsTrigger value="raw">Raw Response</TabsTrigger>}
|
|
288
258
|
<TabsTrigger value="parsed">Response</TabsTrigger>
|
|
289
259
|
</TabsList>
|
|
290
260
|
|
|
@@ -210,43 +210,26 @@ export const LogEntryHeader = memo(function ({
|
|
|
210
210
|
|
|
211
211
|
{/* Message count */}
|
|
212
212
|
{messageCount !== null && (
|
|
213
|
-
<
|
|
214
|
-
<
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
<span className="font-mono tabular-nums">{messageCount}</span>
|
|
218
|
-
</span>
|
|
219
|
-
</TooltipTrigger>
|
|
220
|
-
<TooltipContent>Number of messages in the conversation</TooltipContent>
|
|
221
|
-
</Tooltip>
|
|
213
|
+
<span className="flex items-center gap-1 text-muted-foreground text-xs shrink-0">
|
|
214
|
+
<MessageSquare className="size-3" />
|
|
215
|
+
<span className="font-mono tabular-nums">{messageCount}</span>
|
|
216
|
+
</span>
|
|
222
217
|
)}
|
|
223
218
|
|
|
224
219
|
{/* Tool count */}
|
|
225
220
|
{toolCount !== null && (
|
|
226
|
-
<
|
|
227
|
-
<
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
<span className="font-mono tabular-nums">{toolCount}</span>
|
|
231
|
-
</span>
|
|
232
|
-
</TooltipTrigger>
|
|
233
|
-
<TooltipContent>Number of tools defined in the request</TooltipContent>
|
|
234
|
-
</Tooltip>
|
|
221
|
+
<span className="flex items-center gap-1 text-muted-foreground text-xs shrink-0">
|
|
222
|
+
<Wrench className="size-3" />
|
|
223
|
+
<span className="font-mono tabular-nums">{toolCount}</span>
|
|
224
|
+
</span>
|
|
235
225
|
)}
|
|
236
226
|
|
|
237
227
|
{/* Response tool calls — tool names the model requested to invoke */}
|
|
238
228
|
{responseToolNames !== null && responseToolNames.length > 0 && (
|
|
239
|
-
<
|
|
240
|
-
<
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
<span className="font-mono tabular-nums truncate max-w-[160px]">
|
|
244
|
-
{toolNamesJoined}
|
|
245
|
-
</span>
|
|
246
|
-
</span>
|
|
247
|
-
</TooltipTrigger>
|
|
248
|
-
<TooltipContent>Tools called by model: {toolNamesJoined}</TooltipContent>
|
|
249
|
-
</Tooltip>
|
|
229
|
+
<span className="flex items-center gap-1 text-amber-400/80 text-xs shrink-0">
|
|
230
|
+
<Wrench className="size-3" />
|
|
231
|
+
<span className="font-mono tabular-nums truncate max-w-[160px]">{toolNamesJoined}</span>
|
|
232
|
+
</span>
|
|
250
233
|
)}
|
|
251
234
|
|
|
252
235
|
{/* Origin */}
|