@tonyclaw/agent-inspector 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-Bp7_x-5N.js → CompareDrawer-BCH_fsLm.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-D85_UANk.js +101 -0
- package/.output/public/assets/{ReplayDialog-DFHCd0yx.js → ReplayDialog-DTeaHHit.js} +1 -1
- package/.output/public/assets/RequestAnatomy-DZ8grAih.js +1 -0
- package/.output/public/assets/ResponseView-Cldm6RCi.js +1 -0
- package/.output/public/assets/{StreamingChunkSequence-Bjs4Lqwn.js → StreamingChunkSequence-3x4p-yT7.js} +1 -1
- package/.output/public/assets/_sessionId-YqWFBu6d.js +1 -0
- package/.output/public/assets/index-BIw2H6jO.js +1 -0
- package/.output/public/assets/index-CobXD0yH.css +1 -0
- package/.output/public/assets/{json-viewer-6uV_YXws.js → json-viewer-BrzjD7qI.js} +1 -1
- package/.output/public/assets/{main-FSGUGtEL.js → main-mgxeUdZQ.js} +2 -2
- package/.output/server/_libs/lucide-react.mjs +8 -8
- package/.output/server/{_sessionId-_bf9vUww.mjs → _sessionId-C4xsxIWm.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-DIth2DQM.mjs → CompareDrawer-DuWEpqQ7.mjs} +4 -4
- package/.output/server/_ssr/{ProxyViewerContainer-249bTH-T.mjs → ProxyViewerContainer-Cckz5qKu.mjs} +519 -89
- package/.output/server/_ssr/{ReplayDialog-C1aGx0y1.mjs → ReplayDialog-BDRcr8E5.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-D2bCiEJn.mjs → RequestAnatomy-BoO2_Ij0.mjs} +5 -5
- package/.output/server/_ssr/{ResponseView-DP6k4Xs_.mjs → ResponseView-DZiPBxvO.mjs} +21 -17
- package/.output/server/_ssr/{StreamingChunkSequence-HyXZV-b5.mjs → StreamingChunkSequence-D-be7KEL.mjs} +3 -3
- package/.output/server/_ssr/{index-Bt47f9pn.mjs → index-5RImHKfu.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-Co-YRwUP.mjs → json-viewer-aJhb93ZK.mjs} +2 -2
- package/.output/server/_ssr/{router-to_OJirX.mjs → router-Dgkv5nKP.mjs} +38 -99
- package/.output/server/{_tanstack-start-manifest_v-Bd-2YRWo.mjs → _tanstack-start-manifest_v-B8rrWXjr.mjs} +1 -1
- package/.output/server/index.mjs +63 -63
- package/README.md +5 -2
- package/package.json +1 -1
- package/src/components/ProxyViewer.tsx +25 -15
- package/src/components/ProxyViewerContainer.tsx +2 -1
- package/src/components/providers/SettingsDialog.tsx +45 -1
- package/src/components/proxy-viewer/AgentTraceSummary.tsx +276 -0
- package/src/components/proxy-viewer/AnswerMarkdown.tsx +16 -0
- package/src/components/proxy-viewer/ConversationGroup.tsx +18 -0
- package/src/components/proxy-viewer/ConversationHeader.tsx +6 -6
- package/src/components/proxy-viewer/LogEntry.tsx +5 -5
- package/src/components/proxy-viewer/LogEntryHeader.tsx +9 -14
- package/src/components/proxy-viewer/ResponseView.tsx +2 -6
- package/src/components/proxy-viewer/ToolTraceEvents.tsx +32 -0
- package/src/components/proxy-viewer/TurnGroup.tsx +15 -1
- package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +2 -2
- package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +6 -12
- package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +10 -14
- package/src/components/proxy-viewer/viewerState.ts +177 -0
- package/src/lib/runtimeConfig.ts +6 -0
- package/src/lib/timeDisplay.ts +22 -0
- package/src/lib/useOnboarding.ts +2 -0
- package/src/lib/useStripConfig.ts +16 -0
- package/src/proxy/chunkStorage.ts +3 -4
- package/src/proxy/config.ts +3 -0
- package/src/proxy/logger.ts +8 -15
- package/src/proxy/store.ts +8 -16
- package/src/routes/api/config.ts +5 -1
- package/src/routes/api/providers.$providerId.test.log.ts +0 -79
- package/.output/public/assets/ProxyViewerContainer-USuxPy-K.js +0 -101
- package/.output/public/assets/RequestAnatomy-ehyrskxt.js +0 -1
- package/.output/public/assets/ResponseView-BNGyc8e_.js +0 -1
- package/.output/public/assets/_sessionId-D_SeK_qp.js +0 -1
- package/.output/public/assets/index-BGGOWR7A.js +0 -1
- package/.output/public/assets/index-CIL46Z2y.css +0 -1
package/.output/server/index.mjs
CHANGED
|
@@ -38,107 +38,107 @@ 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-20T09:50:40.188Z",
|
|
42
42
|
"size": 5915,
|
|
43
43
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
44
44
|
},
|
|
45
|
-
"/assets/
|
|
45
|
+
"/assets/index-BIw2H6jO.js": {
|
|
46
46
|
"type": "text/javascript; charset=utf-8",
|
|
47
|
-
"etag": '"
|
|
48
|
-
"mtime": "2026-06-
|
|
49
|
-
"size":
|
|
50
|
-
"path": "../public/assets/
|
|
47
|
+
"etag": '"74-4Z3U3XPh22QGtEz8rgtC6KUxxBk"',
|
|
48
|
+
"mtime": "2026-06-20T09:50:40.189Z",
|
|
49
|
+
"size": 116,
|
|
50
|
+
"path": "../public/assets/index-BIw2H6jO.js"
|
|
51
|
+
},
|
|
52
|
+
"/assets/index-CobXD0yH.css": {
|
|
53
|
+
"type": "text/css; charset=utf-8",
|
|
54
|
+
"etag": '"17587-wM3UwOtYjpQy81oA4sjkIdizScg"',
|
|
55
|
+
"mtime": "2026-06-20T09:50:40.188Z",
|
|
56
|
+
"size": 95623,
|
|
57
|
+
"path": "../public/assets/index-CobXD0yH.css"
|
|
51
58
|
},
|
|
52
59
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
53
60
|
"type": "image/jpeg",
|
|
54
61
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
55
|
-
"mtime": "2026-06-
|
|
62
|
+
"mtime": "2026-06-20T09:50:40.188Z",
|
|
56
63
|
"size": 6918,
|
|
57
64
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
58
65
|
},
|
|
59
|
-
"/assets/json-viewer-
|
|
66
|
+
"/assets/json-viewer-BrzjD7qI.js": {
|
|
60
67
|
"type": "text/javascript; charset=utf-8",
|
|
61
|
-
"etag": '"
|
|
62
|
-
"mtime": "2026-06-
|
|
63
|
-
"size":
|
|
64
|
-
"path": "../public/assets/json-viewer-
|
|
68
|
+
"etag": '"1e652-kToNy9EOWKlmvVVK2ggoK6Yj4is"',
|
|
69
|
+
"mtime": "2026-06-20T09:50:40.189Z",
|
|
70
|
+
"size": 124498,
|
|
71
|
+
"path": "../public/assets/json-viewer-BrzjD7qI.js"
|
|
65
72
|
},
|
|
66
|
-
"/assets/
|
|
67
|
-
"type": "text/
|
|
68
|
-
"etag": '"
|
|
69
|
-
"mtime": "2026-06-
|
|
70
|
-
"size":
|
|
71
|
-
"path": "../public/assets/
|
|
73
|
+
"/assets/main-mgxeUdZQ.js": {
|
|
74
|
+
"type": "text/javascript; charset=utf-8",
|
|
75
|
+
"etag": '"5138c-8pFfB8xlDwdi154QNl3icGhbrO0"',
|
|
76
|
+
"mtime": "2026-06-20T09:50:40.189Z",
|
|
77
|
+
"size": 332684,
|
|
78
|
+
"path": "../public/assets/main-mgxeUdZQ.js"
|
|
72
79
|
},
|
|
73
|
-
"/assets/
|
|
80
|
+
"/assets/RequestAnatomy-DZ8grAih.js": {
|
|
74
81
|
"type": "text/javascript; charset=utf-8",
|
|
75
|
-
"etag": '"
|
|
76
|
-
"mtime": "2026-06-
|
|
77
|
-
"size":
|
|
78
|
-
"path": "../public/assets/
|
|
82
|
+
"etag": '"1426-KgPrtOak3tXSA1eBiDgPYDF0NzY"',
|
|
83
|
+
"mtime": "2026-06-20T09:50:40.189Z",
|
|
84
|
+
"size": 5158,
|
|
85
|
+
"path": "../public/assets/RequestAnatomy-DZ8grAih.js"
|
|
79
86
|
},
|
|
80
|
-
"/assets/
|
|
87
|
+
"/assets/ReplayDialog-DTeaHHit.js": {
|
|
81
88
|
"type": "text/javascript; charset=utf-8",
|
|
82
|
-
"etag": '"
|
|
83
|
-
"mtime": "2026-06-
|
|
84
|
-
"size":
|
|
85
|
-
"path": "../public/assets/
|
|
89
|
+
"etag": '"11c0-vzfqRFtK58XnhNRimd5URd22Gcs"',
|
|
90
|
+
"mtime": "2026-06-20T09:50:40.189Z",
|
|
91
|
+
"size": 4544,
|
|
92
|
+
"path": "../public/assets/ReplayDialog-DTeaHHit.js"
|
|
86
93
|
},
|
|
87
|
-
"/assets/
|
|
94
|
+
"/assets/ResponseView-Cldm6RCi.js": {
|
|
88
95
|
"type": "text/javascript; charset=utf-8",
|
|
89
|
-
"etag": '"
|
|
90
|
-
"mtime": "2026-06-
|
|
91
|
-
"size":
|
|
92
|
-
"path": "../public/assets/
|
|
96
|
+
"etag": '"6b01-Qix5qsvqjrCTAlqfCJ+Pp8h1e9I"',
|
|
97
|
+
"mtime": "2026-06-20T09:50:40.189Z",
|
|
98
|
+
"size": 27393,
|
|
99
|
+
"path": "../public/assets/ResponseView-Cldm6RCi.js"
|
|
100
|
+
},
|
|
101
|
+
"/assets/StreamingChunkSequence-3x4p-yT7.js": {
|
|
102
|
+
"type": "text/javascript; charset=utf-8",
|
|
103
|
+
"etag": '"d81-mHjIspQgaAOB4LmN6Cfnz+NcWOM"',
|
|
104
|
+
"mtime": "2026-06-20T09:50:40.189Z",
|
|
105
|
+
"size": 3457,
|
|
106
|
+
"path": "../public/assets/StreamingChunkSequence-3x4p-yT7.js"
|
|
93
107
|
},
|
|
94
108
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
95
109
|
"type": "image/svg+xml",
|
|
96
110
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
97
|
-
"mtime": "2026-06-
|
|
111
|
+
"mtime": "2026-06-20T09:50:40.188Z",
|
|
98
112
|
"size": 11256,
|
|
99
113
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
100
114
|
},
|
|
101
|
-
"/assets/
|
|
102
|
-
"type": "text/javascript; charset=utf-8",
|
|
103
|
-
"etag": '"5138c-aZy2XlKYAw/+FTrgYI1Iz4MHtww"',
|
|
104
|
-
"mtime": "2026-06-20T06:54:35.500Z",
|
|
105
|
-
"size": 332684,
|
|
106
|
-
"path": "../public/assets/main-FSGUGtEL.js"
|
|
107
|
-
},
|
|
108
|
-
"/assets/ProxyViewerContainer-USuxPy-K.js": {
|
|
115
|
+
"/assets/CompareDrawer-BCH_fsLm.js": {
|
|
109
116
|
"type": "text/javascript; charset=utf-8",
|
|
110
|
-
"etag": '"
|
|
111
|
-
"mtime": "2026-06-
|
|
112
|
-
"size":
|
|
113
|
-
"path": "../public/assets/
|
|
117
|
+
"etag": '"4a1f-Y215Tlm1TY2GPfXfX4DX86bgJPU"',
|
|
118
|
+
"mtime": "2026-06-20T09:50:40.189Z",
|
|
119
|
+
"size": 18975,
|
|
120
|
+
"path": "../public/assets/CompareDrawer-BCH_fsLm.js"
|
|
114
121
|
},
|
|
115
|
-
"/assets/_sessionId-
|
|
122
|
+
"/assets/_sessionId-YqWFBu6d.js": {
|
|
116
123
|
"type": "text/javascript; charset=utf-8",
|
|
117
|
-
"etag": '"d2-
|
|
118
|
-
"mtime": "2026-06-
|
|
124
|
+
"etag": '"d2-hOIbwqwgtPs0H/vPSZ1gDPz5pFU"',
|
|
125
|
+
"mtime": "2026-06-20T09:50:40.189Z",
|
|
119
126
|
"size": 210,
|
|
120
|
-
"path": "../public/assets/_sessionId-
|
|
121
|
-
},
|
|
122
|
-
"/assets/ResponseView-BNGyc8e_.js": {
|
|
123
|
-
"type": "text/javascript; charset=utf-8",
|
|
124
|
-
"etag": '"6e91-De46gQnfLBYdkbMBsXcKinAu7mE"',
|
|
125
|
-
"mtime": "2026-06-20T06:54:35.501Z",
|
|
126
|
-
"size": 28305,
|
|
127
|
-
"path": "../public/assets/ResponseView-BNGyc8e_.js"
|
|
127
|
+
"path": "../public/assets/_sessionId-YqWFBu6d.js"
|
|
128
128
|
},
|
|
129
129
|
"/assets/qwen-CONDcHqt.png": {
|
|
130
130
|
"type": "image/png",
|
|
131
131
|
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
132
|
-
"mtime": "2026-06-
|
|
132
|
+
"mtime": "2026-06-20T09:50:40.188Z",
|
|
133
133
|
"size": 357059,
|
|
134
134
|
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
135
135
|
},
|
|
136
|
-
"/assets/
|
|
136
|
+
"/assets/ProxyViewerContainer-D85_UANk.js": {
|
|
137
137
|
"type": "text/javascript; charset=utf-8",
|
|
138
|
-
"etag": '"
|
|
139
|
-
"mtime": "2026-06-
|
|
140
|
-
"size":
|
|
141
|
-
"path": "../public/assets/
|
|
138
|
+
"etag": '"79ec4-8t+BfQ9tY8ia35/KlmoU69wDlc8"',
|
|
139
|
+
"mtime": "2026-06-20T09:50:40.189Z",
|
|
140
|
+
"size": 499396,
|
|
141
|
+
"path": "../public/assets/ProxyViewerContainer-D85_UANk.js"
|
|
142
142
|
}
|
|
143
143
|
};
|
|
144
144
|
function readAsset(id) {
|
package/README.md
CHANGED
|
@@ -28,7 +28,8 @@ therefore appears in Task Manager as **Agent Inspector <version>** with the
|
|
|
28
28
|
project icon. The executable also carries standard `FileVersion` and
|
|
29
29
|
`ProductVersion` metadata for the installed package version. If npm lifecycle
|
|
30
30
|
scripts are disabled, Agent Inspector falls back to `node.exe` and keeps
|
|
31
|
-
working normally.
|
|
31
|
+
working normally. Set `AGENT_INSPECTOR_SKIP_WINDOWS_RUNTIME=1` to skip the
|
|
32
|
+
Windows runtime metadata step explicitly.
|
|
32
33
|
|
|
33
34
|
For Linux containers, the Windows runtime setup is a no-op. To keep images lean,
|
|
34
35
|
install with optional dependencies omitted:
|
|
@@ -51,7 +52,9 @@ The onboarding command installs guided setup skills for local agents:
|
|
|
51
52
|
|
|
52
53
|
During npm global install, Agent Inspector also makes a best-effort Codex skill install when
|
|
53
54
|
`~/.codex` already exists. Set `AGENT_INSPECTOR_SKIP_CODEX_SKILL=1` to skip that postinstall step,
|
|
54
|
-
|
|
55
|
+
set `AGENT_INSPECTOR_INSTALL_CODEX_SKILL=1` to attempt it even before `~/.codex` exists, or run
|
|
56
|
+
`agent-inspector onboard --codex-only --force` later to refresh it. For a full refresh of all
|
|
57
|
+
generated onboarding files, run `agent-inspector onboard --force`.
|
|
55
58
|
|
|
56
59
|
For local development from source:
|
|
57
60
|
|
package/package.json
CHANGED
|
@@ -3,6 +3,8 @@ import { ArrowLeft, Check, Copy, Download, Plus } from "lucide-react";
|
|
|
3
3
|
|
|
4
4
|
import type { CapturedLog } from "../proxy/schemas";
|
|
5
5
|
import { exportLogsAsZip } from "../lib/export-logs";
|
|
6
|
+
import type { TimeDisplayFormat } from "../lib/runtimeConfig";
|
|
7
|
+
import { formatTimestampRange } from "../lib/timeDisplay";
|
|
6
8
|
import { formatTokens } from "../lib/utils";
|
|
7
9
|
import packageJson from "../../package.json";
|
|
8
10
|
import { ConversationGroup, groupLogsByConversation } from "./proxy-viewer";
|
|
@@ -33,17 +35,11 @@ function computeTokenSummary(logs: CapturedLog[]): { totalIn: number; totalOut:
|
|
|
33
35
|
return { totalIn, totalOut };
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
function formatTimeRange(logs: CapturedLog[]): string | null {
|
|
38
|
+
function formatTimeRange(logs: CapturedLog[], timeDisplayFormat: TimeDisplayFormat): string | null {
|
|
37
39
|
const first = logs[0];
|
|
38
40
|
const last = logs[logs.length - 1];
|
|
39
41
|
if (first === undefined || last === undefined) return null;
|
|
40
|
-
|
|
41
|
-
new Date(iso).toLocaleTimeString([], {
|
|
42
|
-
hour: "2-digit",
|
|
43
|
-
minute: "2-digit",
|
|
44
|
-
second: "2-digit",
|
|
45
|
-
});
|
|
46
|
-
return `${format(first.timestamp)} - ${format(last.timestamp)}`;
|
|
42
|
+
return formatTimestampRange(first.timestamp, last.timestamp, timeDisplayFormat);
|
|
47
43
|
}
|
|
48
44
|
|
|
49
45
|
function getFirstUserAgent(logs: CapturedLog[]): string | null {
|
|
@@ -132,14 +128,19 @@ function SessionContextBar({
|
|
|
132
128
|
logs,
|
|
133
129
|
totalIn,
|
|
134
130
|
totalOut,
|
|
131
|
+
timeDisplayFormat,
|
|
135
132
|
}: {
|
|
136
133
|
sessionId: string;
|
|
137
134
|
logs: CapturedLog[];
|
|
138
135
|
totalIn: number;
|
|
139
136
|
totalOut: number;
|
|
137
|
+
timeDisplayFormat: TimeDisplayFormat;
|
|
140
138
|
}): JSX.Element {
|
|
141
139
|
const [copied, setCopied] = useState(false);
|
|
142
|
-
const timeRange = useMemo(
|
|
140
|
+
const timeRange = useMemo(
|
|
141
|
+
() => formatTimeRange(logs, timeDisplayFormat),
|
|
142
|
+
[logs, timeDisplayFormat],
|
|
143
|
+
);
|
|
143
144
|
const userAgent = useMemo(() => getFirstUserAgent(logs), [logs]);
|
|
144
145
|
|
|
145
146
|
const handleCopyLink = useCallback(() => {
|
|
@@ -216,6 +217,8 @@ export type ProxyViewerProps = {
|
|
|
216
217
|
strip: boolean;
|
|
217
218
|
/** Slow-response threshold in seconds. `0` disables the warning indicator. */
|
|
218
219
|
slowResponseThresholdSeconds: number;
|
|
220
|
+
/** Controls whether timestamps render as compact local time or full ISO strings. */
|
|
221
|
+
timeDisplayFormat: TimeDisplayFormat;
|
|
219
222
|
/** Hide the session filter dropdown. Used on `/session/$id` routes where
|
|
220
223
|
* the session is already pinned by the URL and the dropdown would just
|
|
221
224
|
* fight the URL state. */
|
|
@@ -238,6 +241,7 @@ export function ProxyViewer({
|
|
|
238
241
|
onViewModeChange,
|
|
239
242
|
strip,
|
|
240
243
|
slowResponseThresholdSeconds,
|
|
244
|
+
timeDisplayFormat,
|
|
241
245
|
hideSessionFilter = false,
|
|
242
246
|
pinnedSessionId,
|
|
243
247
|
}: ProxyViewerProps): JSX.Element {
|
|
@@ -291,6 +295,7 @@ export function ProxyViewer({
|
|
|
291
295
|
}, []);
|
|
292
296
|
|
|
293
297
|
const groups = useMemo(() => groupLogsByConversation(logs), [logs]);
|
|
298
|
+
const hasPinnedSessionContext = pinnedSessionId !== undefined;
|
|
294
299
|
const cacheTrends = useMemo(() => computeCacheTrends(groups), [groups]);
|
|
295
300
|
const comparisonPredecessors = useMemo(() => buildValidPredecessors(groups), [groups]);
|
|
296
301
|
const handleCompareWithPrevious = useCallback(
|
|
@@ -380,6 +385,7 @@ export function ProxyViewer({
|
|
|
380
385
|
logs={logs}
|
|
381
386
|
totalIn={totalIn}
|
|
382
387
|
totalOut={totalOut}
|
|
388
|
+
timeDisplayFormat={timeDisplayFormat}
|
|
383
389
|
/>
|
|
384
390
|
)}
|
|
385
391
|
|
|
@@ -438,12 +444,14 @@ export function ProxyViewer({
|
|
|
438
444
|
</button>
|
|
439
445
|
</div>
|
|
440
446
|
<div className="flex-1" />
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
+
{!hasPinnedSessionContext && (
|
|
448
|
+
<span className="text-muted-foreground text-xs font-mono">
|
|
449
|
+
{logs.length} request{logs.length !== 1 ? "s" : ""}
|
|
450
|
+
{totalIn > 0 || totalOut > 0
|
|
451
|
+
? ` · ${formatTokens(totalIn)} in / ${formatTokens(totalOut)} out`
|
|
452
|
+
: ""}
|
|
453
|
+
</span>
|
|
454
|
+
)}
|
|
447
455
|
{logs.length > 0 && (
|
|
448
456
|
<button
|
|
449
457
|
type="button"
|
|
@@ -527,6 +535,8 @@ export function ProxyViewer({
|
|
|
527
535
|
comparisonPredecessors={comparisonPredecessors}
|
|
528
536
|
onClearGroup={onClearGroup}
|
|
529
537
|
standalone={groups.length === 1}
|
|
538
|
+
hasPinnedSessionContext={hasPinnedSessionContext}
|
|
539
|
+
timeDisplayFormat={timeDisplayFormat}
|
|
530
540
|
/>
|
|
531
541
|
))}
|
|
532
542
|
</div>
|
|
@@ -330,7 +330,7 @@ export function ProxyViewerContainer({
|
|
|
330
330
|
|
|
331
331
|
// Read the strip config once at the container so the virtualized list does
|
|
332
332
|
// not need N independent SWR subscriptions per row.
|
|
333
|
-
const { strip, slowResponseThresholdSeconds } = useStripConfig();
|
|
333
|
+
const { strip, slowResponseThresholdSeconds, timeDisplayFormat } = useStripConfig();
|
|
334
334
|
|
|
335
335
|
return (
|
|
336
336
|
<>
|
|
@@ -354,6 +354,7 @@ export function ProxyViewerContainer({
|
|
|
354
354
|
onViewModeChange={setViewMode}
|
|
355
355
|
strip={strip}
|
|
356
356
|
slowResponseThresholdSeconds={slowResponseThresholdSeconds}
|
|
357
|
+
timeDisplayFormat={timeDisplayFormat}
|
|
357
358
|
// Session filter is the URL's job when `initialSessionId` was given.
|
|
358
359
|
hideSessionFilter={initialSessionId !== undefined}
|
|
359
360
|
pinnedSessionId={initialSessionId}
|
|
@@ -6,7 +6,11 @@ import { Button } from "../ui/button";
|
|
|
6
6
|
import { ProvidersPanel } from "./ProvidersPanel";
|
|
7
7
|
import { useProviders } from "../../lib/useProviders";
|
|
8
8
|
import { useStripConfig } from "../../lib/useStripConfig";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
MAX_SLOW_RESPONSE_THRESHOLD_SECONDS,
|
|
11
|
+
TimeDisplayFormatSchema,
|
|
12
|
+
type TimeDisplayFormat,
|
|
13
|
+
} from "../../lib/runtimeConfig";
|
|
10
14
|
|
|
11
15
|
export function SettingsDialog(): JSX.Element {
|
|
12
16
|
const [open, setOpen] = useState(false);
|
|
@@ -100,9 +104,11 @@ function ProxySettingsTab(): JSX.Element {
|
|
|
100
104
|
const {
|
|
101
105
|
strip,
|
|
102
106
|
slowResponseThresholdSeconds,
|
|
107
|
+
timeDisplayFormat,
|
|
103
108
|
isLoading,
|
|
104
109
|
setStrip,
|
|
105
110
|
setSlowResponseThresholdSeconds,
|
|
111
|
+
setTimeDisplayFormat,
|
|
106
112
|
} = useStripConfig();
|
|
107
113
|
const [error, setError] = useState<string | null>(null);
|
|
108
114
|
const [pending, setPending] = useState(false);
|
|
@@ -137,6 +143,21 @@ function ProxySettingsTab(): JSX.Element {
|
|
|
137
143
|
[setSlowResponseThresholdSeconds],
|
|
138
144
|
);
|
|
139
145
|
|
|
146
|
+
const handleTimeDisplayFormatChange = useCallback(
|
|
147
|
+
async (next: TimeDisplayFormat) => {
|
|
148
|
+
setError(null);
|
|
149
|
+
setPending(true);
|
|
150
|
+
try {
|
|
151
|
+
await setTimeDisplayFormat(next);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
154
|
+
} finally {
|
|
155
|
+
setPending(false);
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
[setTimeDisplayFormat],
|
|
159
|
+
);
|
|
160
|
+
|
|
140
161
|
return (
|
|
141
162
|
<div className="space-y-4">
|
|
142
163
|
<div className="space-y-1">
|
|
@@ -196,6 +217,29 @@ function ProxySettingsTab(): JSX.Element {
|
|
|
196
217
|
</div>
|
|
197
218
|
</div>
|
|
198
219
|
|
|
220
|
+
<div className="space-y-1">
|
|
221
|
+
<label htmlFor="time-display-format" className="text-sm font-semibold">
|
|
222
|
+
Time display
|
|
223
|
+
</label>
|
|
224
|
+
<p className="text-xs text-muted-foreground">
|
|
225
|
+
Controls timestamps in session summaries, conversation headers, and log rows.
|
|
226
|
+
</p>
|
|
227
|
+
<select
|
|
228
|
+
id="time-display-format"
|
|
229
|
+
value={timeDisplayFormat}
|
|
230
|
+
disabled={isLoading || pending}
|
|
231
|
+
onChange={(event) => {
|
|
232
|
+
const parsed = TimeDisplayFormatSchema.safeParse(event.currentTarget.value);
|
|
233
|
+
if (!parsed.success) return;
|
|
234
|
+
void handleTimeDisplayFormatChange(parsed.data);
|
|
235
|
+
}}
|
|
236
|
+
className="h-8 rounded-md border border-input bg-background px-2 text-sm disabled:cursor-not-allowed disabled:opacity-50"
|
|
237
|
+
>
|
|
238
|
+
<option value="time">Time only</option>
|
|
239
|
+
<option value="full">Full ISO</option>
|
|
240
|
+
</select>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
199
243
|
{error !== null && <p className="text-xs text-destructive">Failed to save: {error}</p>}
|
|
200
244
|
</div>
|
|
201
245
|
);
|