@tonyclaw/agent-inspector 2.0.4 → 2.0.6
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-BCH_fsLm.js → CompareDrawer-DDmqSAfl.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-Cxpdziwd.js +101 -0
- package/.output/public/assets/ReplayDialog-Bt5DGzlh.js +1 -0
- package/.output/public/assets/RequestAnatomy-BxX3_N9S.js +1 -0
- package/.output/public/assets/ResponseView-Bl_5S9gZ.js +1 -0
- package/.output/public/assets/StreamingChunkSequence-RJMwNf6F.js +1 -0
- package/.output/public/assets/_sessionId-b4isaoDp.js +1 -0
- package/.output/public/assets/index-BZ4x5UI6.js +1 -0
- package/.output/public/assets/{index-CobXD0yH.css → index-C624DUk9.css} +1 -1
- package/.output/public/assets/{json-viewer-BrzjD7qI.js → json-viewer-CRL_gWEZ.js} +1 -1
- package/.output/public/assets/{main-mgxeUdZQ.js → main-CKnTJ4-O.js} +6 -6
- package/.output/server/_libs/lucide-react.mjs +181 -114
- package/.output/server/{_sessionId-C4xsxIWm.mjs → _sessionId-B-x9fRY3.mjs} +3 -3
- package/.output/server/_ssr/{CompareDrawer-DuWEpqQ7.mjs → CompareDrawer-BQVNsAY2.mjs} +6 -6
- package/.output/server/_ssr/{ProxyViewerContainer-Cckz5qKu.mjs → ProxyViewerContainer-CYm2Dw19.mjs} +766 -122
- package/.output/server/_ssr/{ReplayDialog-BDRcr8E5.mjs → ReplayDialog-CaMQBc79.mjs} +240 -14
- package/.output/server/_ssr/{RequestAnatomy-BoO2_Ij0.mjs → RequestAnatomy--P5arRH2.mjs} +236 -66
- package/.output/server/_ssr/{ResponseView-DZiPBxvO.mjs → ResponseView-RtFwNvgD.mjs} +8 -8
- package/.output/server/_ssr/{StreamingChunkSequence-D-be7KEL.mjs → StreamingChunkSequence-B5HPkzab.mjs} +3 -3
- package/.output/server/_ssr/{index-5RImHKfu.mjs → index-CZIKZU43.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-aJhb93ZK.mjs → json-viewer-d4obyRaA.mjs} +3 -3
- package/.output/server/_ssr/{router-Dgkv5nKP.mjs → router-DGPt3MUc.mjs} +145 -71
- package/.output/server/_tanstack-start-manifest_v-BzH4pNaI.mjs +4 -0
- package/.output/server/index.mjs +64 -64
- package/package.json +1 -1
- package/src/components/OnboardingBanner.tsx +11 -19
- package/src/components/ProxyViewer.tsx +1 -1
- package/src/components/providers/ProviderCard.tsx +6 -20
- package/src/components/providers/SettingsDialog.tsx +95 -2
- package/src/components/proxy-viewer/AgentTraceSummary.tsx +639 -38
- package/src/components/proxy-viewer/CompareDrawer.tsx +4 -2
- package/src/components/proxy-viewer/LogEntry.tsx +4 -4
- package/src/components/proxy-viewer/LogEntryHeader.tsx +15 -25
- package/src/components/proxy-viewer/ReplayDialog.tsx +190 -8
- package/src/components/proxy-viewer/ResponseView.tsx +2 -2
- package/src/components/proxy-viewer/ToolTraceEvents.tsx +37 -16
- package/src/components/proxy-viewer/TurnGroup.tsx +14 -2
- package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +196 -45
- package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +92 -67
- package/src/components/proxy-viewer/anatomy/types.ts +15 -13
- package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +2 -2
- package/src/components/proxy-viewer/log-formats/anthropic.ts +1 -1
- package/src/components/proxy-viewer/log-formats/openai.ts +1 -1
- package/src/components/proxy-viewer/log-formats/types.ts +1 -1
- package/src/components/proxy-viewer/replayComparison.ts +131 -0
- package/src/components/proxy-viewer/useKeyboardNavigation.ts +64 -22
- package/src/components/proxy-viewer/viewerState.ts +14 -2
- package/src/components/ui/json-viewer.tsx +1 -1
- package/src/knowledge/candidateStore.ts +32 -1
- package/src/routes/api/knowledge.candidates.$candidateId.ts +50 -0
- package/src/routes/api/knowledge.sessions.$sessionId.candidates.ts +12 -2
- package/.output/public/assets/ProxyViewerContainer-D85_UANk.js +0 -101
- package/.output/public/assets/ReplayDialog-DTeaHHit.js +0 -1
- package/.output/public/assets/RequestAnatomy-DZ8grAih.js +0 -1
- package/.output/public/assets/ResponseView-Cldm6RCi.js +0 -1
- package/.output/public/assets/StreamingChunkSequence-3x4p-yT7.js +0 -1
- package/.output/public/assets/_sessionId-YqWFBu6d.js +0 -1
- package/.output/public/assets/index-BIw2H6jO.js +0 -1
- package/.output/server/_tanstack-start-manifest_v-B8rrWXjr.mjs +0 -4
package/.output/server/_ssr/{ProxyViewerContainer-Cckz5qKu.mjs → ProxyViewerContainer-CYm2Dw19.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
|
|
2
|
-
import { C as CapturedLogSchema, D as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, a as DEFAULT_TIME_DISPLAY_FORMAT, b as RuntimeConfigSchema, r as requestFormatForPath, e as createPendingProviderTestResults, P as ProviderTestResultsSchema, f as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, T as TimeDisplayFormatSchema, g as getSessionPath, h as ProviderConfigSchema, K as KnowledgeCandidateSchema, s as stripClaudeCodeBillingHeader, d as safeGetOwnProperty, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, c as AnthropicRequestSchema } from "./router-
|
|
2
|
+
import { C as CapturedLogSchema, D as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, a as DEFAULT_TIME_DISPLAY_FORMAT, b as RuntimeConfigSchema, r as requestFormatForPath, e as createPendingProviderTestResults, P as ProviderTestResultsSchema, f as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, T as TimeDisplayFormatSchema, g as getSessionPath, h as ProviderConfigSchema, K as KnowledgeCandidateSchema, s as stripClaudeCodeBillingHeader, d as safeGetOwnProperty, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, c as AnthropicRequestSchema } from "./router-DGPt3MUc.mjs";
|
|
3
3
|
import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
|
|
4
4
|
import { J as JSZip } from "../_libs/jszip.mjs";
|
|
5
5
|
import { c as clsx } from "../_libs/clsx.mjs";
|
|
@@ -9,7 +9,7 @@ import { R as Root, T as Trigger$2, C as Content, a as Close, b as Title, P as P
|
|
|
9
9
|
import { d as diffJson, a as diffLines } from "../_libs/diff.mjs";
|
|
10
10
|
import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
|
|
11
11
|
import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Content2, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
|
|
12
|
-
import { C as Check, X, P as Plus, D as Download, S as Settings, A as ArrowLeft, a as Copy, b as ChevronDown, U as Upload, c as Scan, d as CircleAlert, e as ChevronUp, L as LoaderCircle, f as ChevronRight, g as User, h as Clock, M as MessageSquare, Z as Zap, E as ExternalLink,
|
|
12
|
+
import { C as Check, X, P as Plus, D as Download, S as Settings, A as ArrowLeft, a as Copy, b as ChevronDown, U as Upload, c as Scan, d as CircleAlert, T as Terminal, e as ChevronUp, L as LoaderCircle, f as ChevronRight, g as User, h as Clock, M as MessageSquare, Z as Zap, E as ExternalLink, i as Trash2, W as Wrench, j as TriangleAlert, B as Brain, k as EyeOff, l as Eye, R as RotateCw, m as Pencil, n as Minus, o as CircleCheckBig, p as CircleX, q as ShieldCheck, r as RefreshCw, s as Save, F as FileSearch, t as CircleCheck, u as CloudUpload, O as OctagonAlert, G as Globe, v as FileTerminal, w as Radio, x as ChevronsUp, y as ChevronsDown, z as FileDiff, H as History, I as RotateCcw, J as GitCompareArrows, K as CircleQuestionMark, N as Server, Q as Gauge, V as Lock, Y as Wifi, _ as WifiOff, $ as ArrowUp, a0 as ArrowDown, a1 as Rows3, a2 as Columns2 } from "../_libs/lucide-react.mjs";
|
|
13
13
|
import { u as union, d as object, a as array, l as literal, b as string, n as number, c as boolean, _ as _enum } from "../_libs/zod.mjs";
|
|
14
14
|
import { P as Provider, R as Root3, T as Trigger$1, a as Portal$1, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
|
|
15
15
|
import { R as Root2$1, L as List, T as Trigger$3, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
|
|
@@ -179,27 +179,20 @@ function OnboardingBanner() {
|
|
|
179
179
|
"aria-label": "Onboarding tip",
|
|
180
180
|
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",
|
|
181
181
|
children: [
|
|
182
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "
|
|
183
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium text-amber-600 dark:text-amber-400
|
|
184
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "space-y-0.5 text-
|
|
182
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
183
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-1 font-medium text-amber-600 dark:text-amber-400", children: "Agent Inspector is ready" }),
|
|
184
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "space-y-0.5 text-xs leading-relaxed text-muted-foreground", children: [
|
|
185
185
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
|
|
186
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "
|
|
187
|
-
"
|
|
188
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Response" }),
|
|
189
|
-
" — structured views of what the proxy sent and received."
|
|
186
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Trace" }),
|
|
187
|
+
": requests, responses, streaming chunks, tools, and timing."
|
|
190
188
|
] }),
|
|
191
189
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
|
|
192
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "
|
|
193
|
-
"
|
|
190
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Replay" }),
|
|
191
|
+
": resend captured requests and compare provider behavior."
|
|
194
192
|
] }),
|
|
195
193
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
|
|
196
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "
|
|
197
|
-
"
|
|
198
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Raw Request" }),
|
|
199
|
-
" /",
|
|
200
|
-
" ",
|
|
201
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Raw Response" }),
|
|
202
|
-
" — exact bytes from the upstream provider (visible in Full mode)."
|
|
194
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Memory" }),
|
|
195
|
+
": create reviewable candidates before promotion to OpenClaw."
|
|
203
196
|
] })
|
|
204
197
|
] })
|
|
205
198
|
] }),
|
|
@@ -210,7 +203,7 @@ function OnboardingBanner() {
|
|
|
210
203
|
onClick: () => {
|
|
211
204
|
void markSeen();
|
|
212
205
|
},
|
|
213
|
-
className: "inline-flex items-center gap-1.5
|
|
206
|
+
className: "inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md border border-amber-500/40 px-3 text-xs text-amber-700 transition-colors hover:bg-amber-500/10 dark:text-amber-300",
|
|
214
207
|
"aria-label": "Dismiss onboarding tip",
|
|
215
208
|
children: [
|
|
216
209
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5" }),
|
|
@@ -225,7 +218,7 @@ function OnboardingBanner() {
|
|
|
225
218
|
onClick: () => {
|
|
226
219
|
void markSeen();
|
|
227
220
|
},
|
|
228
|
-
className: "
|
|
221
|
+
className: "-m-1 shrink-0 p-1 text-muted-foreground transition-colors hover:text-foreground",
|
|
229
222
|
"aria-label": "Dismiss",
|
|
230
223
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "size-3.5" })
|
|
231
224
|
}
|
|
@@ -302,7 +295,7 @@ function getStatusCategory(status) {
|
|
|
302
295
|
if (status >= 500) return "server_error";
|
|
303
296
|
return "pending";
|
|
304
297
|
}
|
|
305
|
-
const version = "2.0.
|
|
298
|
+
const version = "2.0.6";
|
|
306
299
|
const packageJson = {
|
|
307
300
|
version
|
|
308
301
|
};
|
|
@@ -1363,27 +1356,27 @@ function useCopyFeedback(text) {
|
|
|
1363
1356
|
return { copied, copy };
|
|
1364
1357
|
}
|
|
1365
1358
|
const LazyCompareDrawer = reactExports.lazy(
|
|
1366
|
-
() => import("./CompareDrawer-
|
|
1359
|
+
() => import("./CompareDrawer-BQVNsAY2.mjs").then((m) => ({ default: m.CompareDrawer }))
|
|
1367
1360
|
);
|
|
1368
1361
|
const LazyReplayDialog = reactExports.lazy(
|
|
1369
|
-
() => import("./ReplayDialog-
|
|
1362
|
+
() => import("./ReplayDialog-CaMQBc79.mjs").then((m) => ({ default: m.ReplayDialog }))
|
|
1370
1363
|
);
|
|
1371
1364
|
const LazyRequestAnatomy = reactExports.lazy(
|
|
1372
|
-
() => import("./RequestAnatomy
|
|
1365
|
+
() => import("./RequestAnatomy--P5arRH2.mjs").then((m) => ({ default: m.RequestAnatomy }))
|
|
1373
1366
|
);
|
|
1374
1367
|
const LazyResponseView = reactExports.lazy(
|
|
1375
|
-
() => import("./ResponseView-
|
|
1368
|
+
() => import("./ResponseView-RtFwNvgD.mjs").then((m) => ({ default: m.ResponseView }))
|
|
1376
1369
|
);
|
|
1377
1370
|
const LazyStreamingChunkSequence = reactExports.lazy(
|
|
1378
|
-
() => import("./StreamingChunkSequence-
|
|
1371
|
+
() => import("./StreamingChunkSequence-B5HPkzab.mjs").then((m) => ({
|
|
1379
1372
|
default: m.StreamingChunkSequence
|
|
1380
1373
|
}))
|
|
1381
1374
|
);
|
|
1382
1375
|
const LazyJsonViewer = reactExports.lazy(
|
|
1383
|
-
() => import("./json-viewer-
|
|
1376
|
+
() => import("./json-viewer-d4obyRaA.mjs").then((m) => ({ default: m.JsonViewer }))
|
|
1384
1377
|
);
|
|
1385
1378
|
const LazyJsonViewerFromString = reactExports.lazy(
|
|
1386
|
-
() => import("./json-viewer-
|
|
1379
|
+
() => import("./json-viewer-d4obyRaA.mjs").then((m) => ({ default: m.JsonViewerFromString }))
|
|
1387
1380
|
);
|
|
1388
1381
|
const HIGHLIGHT_DURATION_MS = 1200;
|
|
1389
1382
|
const MAX_HIGHLIGHT_ATTEMPTS = 12;
|
|
@@ -1903,25 +1896,19 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1903
1896
|
)
|
|
1904
1897
|
] })
|
|
1905
1898
|
] }),
|
|
1906
|
-
log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1907
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
] })
|
|
1913
|
-
] }) }),
|
|
1914
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens cached for reuse, reducing future API cost" })
|
|
1899
|
+
log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
|
|
1900
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.creation ?? null }),
|
|
1901
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-emerald-400", children: [
|
|
1902
|
+
"KV Cache +",
|
|
1903
|
+
formatTokens(log.cacheCreationInputTokens)
|
|
1904
|
+
] })
|
|
1915
1905
|
] }),
|
|
1916
|
-
log.cacheReadInputTokens !== null && log.cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1917
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
] })
|
|
1923
|
-
] }) }),
|
|
1924
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens served from cache, reducing API cost" })
|
|
1906
|
+
log.cacheReadInputTokens !== null && log.cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
|
|
1907
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.read ?? null }),
|
|
1908
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
|
|
1909
|
+
"KV Cache ~",
|
|
1910
|
+
formatTokens(log.cacheReadInputTokens)
|
|
1911
|
+
] })
|
|
1925
1912
|
] }),
|
|
1926
1913
|
messageCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
|
|
1927
1914
|
/* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3" }),
|
|
@@ -2583,7 +2570,7 @@ const LogEntry = reactExports.memo(function({
|
|
|
2583
2570
|
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "headers", children: "Headers" }),
|
|
2584
2571
|
shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw-request", children: "Raw Request" }),
|
|
2585
2572
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "request", children: "Request" }),
|
|
2586
|
-
anatomySegments !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "anatomy", children: "
|
|
2573
|
+
anatomySegments !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "anatomy", children: "Context" }),
|
|
2587
2574
|
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw", children: "Raw Response" }),
|
|
2588
2575
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" })
|
|
2589
2576
|
] }),
|
|
@@ -2600,7 +2587,7 @@ const LogEntry = reactExports.memo(function({
|
|
|
2600
2587
|
{
|
|
2601
2588
|
rawBody: log.rawRequestBody,
|
|
2602
2589
|
displayedBody: displayedRequestBody,
|
|
2603
|
-
emptyLabel: "No transformation applied
|
|
2590
|
+
emptyLabel: "No transformation applied; raw and sent request bodies are identical."
|
|
2604
2591
|
}
|
|
2605
2592
|
) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: requestJsonRef, children: displayedRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : requestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2606
2593
|
LazyJsonViewer,
|
|
@@ -2640,7 +2627,7 @@ const LogEntry = reactExports.memo(function({
|
|
|
2640
2627
|
{
|
|
2641
2628
|
rawHeaders: log.rawHeaders,
|
|
2642
2629
|
headers: log.headers,
|
|
2643
|
-
emptyLabel: "No transformation applied
|
|
2630
|
+
emptyLabel: "No transformation applied; raw and processed headers are identical."
|
|
2644
2631
|
}
|
|
2645
2632
|
) : log.headers && Object.keys(log.headers).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.headers).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
2646
2633
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-600 dark:text-blue-400 font-semibold shrink-0", children: [
|
|
@@ -2776,23 +2763,39 @@ function ThreadConnector({
|
|
|
2776
2763
|
) })
|
|
2777
2764
|
] });
|
|
2778
2765
|
}
|
|
2779
|
-
function
|
|
2780
|
-
|
|
2781
|
-
|
|
2766
|
+
function ToolTraceEventRow({ event }) {
|
|
2767
|
+
const argumentCopy = useCopyFeedback(event.argumentsText);
|
|
2768
|
+
const canCopyArguments = event.argumentsText !== null;
|
|
2769
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2782
2770
|
"div",
|
|
2783
2771
|
{
|
|
2784
|
-
className: "flex min-w-0 items-center gap-2 rounded-md border border-border/70 bg-muted/20 px-2.5 py-1.5 text-xs",
|
|
2772
|
+
className: "group/tool-trace flex min-w-0 items-center gap-2 rounded-md border border-border/70 bg-muted/20 px-2.5 py-1.5 text-xs",
|
|
2785
2773
|
children: [
|
|
2786
2774
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3.5 shrink-0 text-sky-400/70" }),
|
|
2787
2775
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono font-semibold text-foreground/80", children: event.name }),
|
|
2788
2776
|
event.argumentsPreview !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
2789
2777
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3 shrink-0 text-muted-foreground/60" }),
|
|
2790
2778
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 truncate font-mono text-muted-foreground", children: event.argumentsPreview })
|
|
2791
|
-
] })
|
|
2779
|
+
] }),
|
|
2780
|
+
canCopyArguments && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2781
|
+
"button",
|
|
2782
|
+
{
|
|
2783
|
+
type: "button",
|
|
2784
|
+
className: "ml-auto inline-flex size-6 shrink-0 items-center justify-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-background/80 hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring group-hover/tool-trace:opacity-100 group-focus-within/tool-trace:opacity-100",
|
|
2785
|
+
onClick: argumentCopy.copy,
|
|
2786
|
+
"aria-label": argumentCopy.copied ? "Copied tool arguments" : "Copy tool arguments",
|
|
2787
|
+
title: argumentCopy.copied ? "Copied tool arguments" : "Copy tool arguments",
|
|
2788
|
+
children: argumentCopy.copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
|
|
2789
|
+
}
|
|
2790
|
+
)
|
|
2792
2791
|
]
|
|
2793
2792
|
},
|
|
2794
2793
|
event.id
|
|
2795
|
-
)
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2796
|
+
function ToolTraceEvents({ events }) {
|
|
2797
|
+
if (events.length === 0) return null;
|
|
2798
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-3 mb-2 grid gap-1.5", children: events.map((event) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToolTraceEventRow, { event }, event.id)) });
|
|
2796
2799
|
}
|
|
2797
2800
|
const PREVIEW_LIMIT = 180;
|
|
2798
2801
|
function shouldRenderConversationContent(standalone, expanded) {
|
|
@@ -2852,6 +2855,12 @@ function previewValue(value) {
|
|
|
2852
2855
|
if (normalized.length === 0) return null;
|
|
2853
2856
|
return normalized.length > PREVIEW_LIMIT ? `${normalized.slice(0, PREVIEW_LIMIT - 1)}...` : normalized;
|
|
2854
2857
|
}
|
|
2858
|
+
function copyValue(value) {
|
|
2859
|
+
if (value === void 0 || value === null) return null;
|
|
2860
|
+
if (typeof value === "string") return value.length > 0 ? value : null;
|
|
2861
|
+
const raw = JSON.stringify(value, null, 2);
|
|
2862
|
+
return raw === void 0 || raw.length === 0 ? null : raw;
|
|
2863
|
+
}
|
|
2855
2864
|
function extractAnthropicToolTraceEvents(log) {
|
|
2856
2865
|
const parsed = parseJsonResponse(log.responseText);
|
|
2857
2866
|
const content = safeGetOwnProperty(parsed, "content");
|
|
@@ -2862,13 +2871,15 @@ function extractAnthropicToolTraceEvents(log) {
|
|
|
2862
2871
|
if (type !== "tool_use") continue;
|
|
2863
2872
|
const name = safeGetOwnProperty(block, "name");
|
|
2864
2873
|
if (typeof name !== "string" || name.length === 0) continue;
|
|
2874
|
+
const input = safeGetOwnProperty(block, "input");
|
|
2865
2875
|
events.push({
|
|
2866
2876
|
id: `${String(log.id)}-anthropic-tool-${String(events.length)}`,
|
|
2867
2877
|
logId: log.id,
|
|
2868
2878
|
index: events.length,
|
|
2869
2879
|
provider: "anthropic",
|
|
2870
2880
|
name,
|
|
2871
|
-
|
|
2881
|
+
argumentsText: copyValue(input),
|
|
2882
|
+
argumentsPreview: previewValue(input)
|
|
2872
2883
|
});
|
|
2873
2884
|
}
|
|
2874
2885
|
return events;
|
|
@@ -2886,13 +2897,15 @@ function extractOpenAIToolTraceEvents(log) {
|
|
|
2886
2897
|
const fn = safeGetOwnProperty(call, "function");
|
|
2887
2898
|
const name = safeGetOwnProperty(fn, "name");
|
|
2888
2899
|
if (typeof name !== "string" || name.length === 0) continue;
|
|
2900
|
+
const args = safeGetOwnProperty(fn, "arguments");
|
|
2889
2901
|
events.push({
|
|
2890
2902
|
id: `${String(log.id)}-openai-tool-${String(events.length)}`,
|
|
2891
2903
|
logId: log.id,
|
|
2892
2904
|
index: events.length,
|
|
2893
2905
|
provider: "openai",
|
|
2894
2906
|
name,
|
|
2895
|
-
|
|
2907
|
+
argumentsText: copyValue(args),
|
|
2908
|
+
argumentsPreview: previewValue(args)
|
|
2896
2909
|
});
|
|
2897
2910
|
}
|
|
2898
2911
|
}
|
|
@@ -3055,17 +3068,27 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
3055
3068
|
window.cancelAnimationFrame(raf);
|
|
3056
3069
|
};
|
|
3057
3070
|
}, []);
|
|
3071
|
+
const firstLogId = entries[0]?.log.id ?? turnIndex;
|
|
3072
|
+
const turnLabel = `Turn ${String(turnIndex + 1)}`;
|
|
3058
3073
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3059
3074
|
"div",
|
|
3060
3075
|
{
|
|
3061
3076
|
ref: containerRef,
|
|
3062
|
-
|
|
3077
|
+
tabIndex: collapsed ? void 0 : 0,
|
|
3078
|
+
role: collapsed ? void 0 : "group",
|
|
3079
|
+
"aria-label": collapsed ? void 0 : turnLabel,
|
|
3080
|
+
"data-nav-id": collapsed ? void 0 : `turn-${String(firstLogId)}`,
|
|
3081
|
+
className: cn(
|
|
3082
|
+
"border rounded-lg",
|
|
3083
|
+
isPending ? "border-amber-500/10" : "border-transparent",
|
|
3084
|
+
!collapsed && "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none"
|
|
3085
|
+
),
|
|
3063
3086
|
children: collapsed ? (
|
|
3064
3087
|
/* ---- Collapsed: dual-crab (+ summary card for multi-log turns) ---- */
|
|
3065
3088
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3066
3089
|
"div",
|
|
3067
3090
|
{
|
|
3068
|
-
"data-nav-id": `turn-collapsed-${
|
|
3091
|
+
"data-nav-id": `turn-collapsed-${String(firstLogId)}`,
|
|
3069
3092
|
"data-nav-action": "expand",
|
|
3070
3093
|
role: "button",
|
|
3071
3094
|
tabIndex: 0,
|
|
@@ -3244,6 +3267,21 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
3244
3267
|
const CandidateResponseSchema = object({
|
|
3245
3268
|
candidates: array(KnowledgeCandidateSchema)
|
|
3246
3269
|
});
|
|
3270
|
+
const CandidatePromotionResponseSchema = object({
|
|
3271
|
+
candidate: KnowledgeCandidateSchema
|
|
3272
|
+
});
|
|
3273
|
+
const CandidatePromotionFailureResponseSchema = object({
|
|
3274
|
+
error: string().optional(),
|
|
3275
|
+
candidate: KnowledgeCandidateSchema.optional()
|
|
3276
|
+
});
|
|
3277
|
+
const CandidateUpdateResponseSchema = object({
|
|
3278
|
+
candidate: KnowledgeCandidateSchema
|
|
3279
|
+
});
|
|
3280
|
+
const CANDIDATE_STATUS_CLASSES = {
|
|
3281
|
+
draft: "border-amber-500/30 bg-amber-500/10 text-amber-500",
|
|
3282
|
+
promoted: "border-emerald-500/30 bg-emerald-500/10 text-emerald-500",
|
|
3283
|
+
failed: "border-destructive/30 bg-destructive/10 text-destructive"
|
|
3284
|
+
};
|
|
3247
3285
|
function formatElapsed(ms) {
|
|
3248
3286
|
if (ms === null) return "-";
|
|
3249
3287
|
if (ms < 1e3) return `${String(ms)}ms`;
|
|
@@ -3267,36 +3305,420 @@ function jumpToLog(logId) {
|
|
|
3267
3305
|
target.scrollIntoView({ block: "center", behavior: "smooth" });
|
|
3268
3306
|
target.focus({ preventScroll: true });
|
|
3269
3307
|
}
|
|
3270
|
-
function
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3308
|
+
function firstFailureLog(logs) {
|
|
3309
|
+
for (const log of logs) {
|
|
3310
|
+
if (log.responseStatus !== null && log.responseStatus >= 400) return log;
|
|
3311
|
+
}
|
|
3312
|
+
return null;
|
|
3313
|
+
}
|
|
3314
|
+
function slowestLog(logs) {
|
|
3315
|
+
let current = null;
|
|
3316
|
+
let currentElapsed = -1;
|
|
3317
|
+
for (const log of logs) {
|
|
3318
|
+
if (log.elapsedMs === null) continue;
|
|
3319
|
+
if (log.elapsedMs > currentElapsed) {
|
|
3320
|
+
current = log;
|
|
3321
|
+
currentElapsed = log.elapsedMs;
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
return current;
|
|
3325
|
+
}
|
|
3326
|
+
function firstToolLog(logs) {
|
|
3327
|
+
for (const log of logs) {
|
|
3328
|
+
if (extractToolTraceEvents(log).length > 0) return log;
|
|
3329
|
+
}
|
|
3330
|
+
return null;
|
|
3331
|
+
}
|
|
3332
|
+
function buildTraceInsights(input) {
|
|
3333
|
+
const insights = [
|
|
3334
|
+
{
|
|
3335
|
+
kind: "session",
|
|
3336
|
+
title: `${String(input.summary.llmCallCount)} LLM call${input.summary.llmCallCount === 1 ? "" : "s"}`,
|
|
3337
|
+
detail: `Scope ${input.scopeId}`,
|
|
3338
|
+
logId: input.logs[0]?.id ?? null
|
|
3339
|
+
}
|
|
3340
|
+
];
|
|
3341
|
+
const toolLog = firstToolLog(input.logs);
|
|
3342
|
+
if (input.summary.toolCallCount > 0 && toolLog !== null) {
|
|
3343
|
+
insights.push({
|
|
3344
|
+
kind: "tool",
|
|
3345
|
+
title: `${String(input.summary.toolCallCount)} tool call${input.summary.toolCallCount === 1 ? "" : "s"}`,
|
|
3346
|
+
detail: `First tool evidence at #${String(toolLog.id)}`,
|
|
3347
|
+
logId: toolLog.id
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3350
|
+
const failure = firstFailureLog(input.logs);
|
|
3351
|
+
if (failure !== null) {
|
|
3352
|
+
insights.push({
|
|
3353
|
+
kind: "failure",
|
|
3354
|
+
title: `Failure #${String(failure.responseStatus)}`,
|
|
3355
|
+
detail: `First failed request is #${String(failure.id)}`,
|
|
3356
|
+
logId: failure.id
|
|
3357
|
+
});
|
|
3358
|
+
}
|
|
3359
|
+
const slowest = slowestLog(input.logs);
|
|
3360
|
+
if (slowest !== null && input.summary.maxElapsedMs !== null) {
|
|
3361
|
+
insights.push({
|
|
3362
|
+
kind: "slow",
|
|
3363
|
+
title: `Slowest ${formatElapsed(input.summary.maxElapsedMs)}`,
|
|
3364
|
+
detail: `Max latency observed at #${String(slowest.id)}`,
|
|
3365
|
+
logId: slowest.id
|
|
3366
|
+
});
|
|
3367
|
+
}
|
|
3368
|
+
if (input.candidates.length > 0) {
|
|
3369
|
+
const draftCount = input.candidates.filter((candidate) => candidate.status === "draft").length;
|
|
3370
|
+
const promotedCount = input.candidates.filter(
|
|
3371
|
+
(candidate) => candidate.status === "promoted"
|
|
3372
|
+
).length;
|
|
3373
|
+
insights.push({
|
|
3374
|
+
kind: "candidate",
|
|
3375
|
+
title: `${String(input.candidates.length)} memory candidate${input.candidates.length === 1 ? "" : "s"}`,
|
|
3376
|
+
detail: `${String(draftCount)} draft / ${String(promotedCount)} promoted`,
|
|
3377
|
+
logId: input.candidates[0]?.logIds[0] ?? null
|
|
3378
|
+
});
|
|
3379
|
+
}
|
|
3380
|
+
return insights;
|
|
3381
|
+
}
|
|
3382
|
+
function insightIcon(kind) {
|
|
3383
|
+
switch (kind) {
|
|
3384
|
+
case "session":
|
|
3385
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3.5 text-blue-400" });
|
|
3386
|
+
case "tool":
|
|
3387
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3.5 text-sky-400/70" });
|
|
3388
|
+
case "slow":
|
|
3389
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3.5 text-amber-400" });
|
|
3390
|
+
case "failure":
|
|
3391
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "size-3.5 text-destructive" });
|
|
3392
|
+
case "candidate":
|
|
3393
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Brain, { className: "size-3.5 text-emerald-400" });
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
function TraceInsights({ insights }) {
|
|
3397
|
+
if (insights.length === 0) return null;
|
|
3398
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 grid gap-1.5 border-t border-border/70 pt-2 md:grid-cols-2 xl:grid-cols-3", children: insights.map((insight) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3399
|
+
"button",
|
|
3274
3400
|
{
|
|
3275
|
-
|
|
3401
|
+
type: "button",
|
|
3402
|
+
className: cn(
|
|
3403
|
+
"flex min-w-0 items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs",
|
|
3404
|
+
"text-muted-foreground transition-colors hover:bg-muted/40 hover:text-foreground",
|
|
3405
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
3406
|
+
),
|
|
3407
|
+
onClick: () => {
|
|
3408
|
+
if (insight.logId !== null) jumpToLog(insight.logId);
|
|
3409
|
+
},
|
|
3410
|
+
disabled: insight.logId === null,
|
|
3276
3411
|
children: [
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "
|
|
3280
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "
|
|
3412
|
+
insightIcon(insight.kind),
|
|
3413
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "min-w-0", children: [
|
|
3414
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block truncate font-medium text-foreground/90", children: insight.title }),
|
|
3415
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block truncate font-mono text-[10px]", children: insight.detail })
|
|
3416
|
+
] })
|
|
3417
|
+
]
|
|
3418
|
+
},
|
|
3419
|
+
`${insight.kind}-${insight.title}`
|
|
3420
|
+
)) });
|
|
3421
|
+
}
|
|
3422
|
+
function candidateStatusLabel(status) {
|
|
3423
|
+
switch (status) {
|
|
3424
|
+
case "draft":
|
|
3425
|
+
return "Draft";
|
|
3426
|
+
case "promoted":
|
|
3427
|
+
return "Promoted";
|
|
3428
|
+
case "failed":
|
|
3429
|
+
return "Failed";
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
function candidatePromoteLabel(candidate, promoting) {
|
|
3433
|
+
if (promoting) return "Promoting";
|
|
3434
|
+
switch (candidate.status) {
|
|
3435
|
+
case "draft":
|
|
3436
|
+
return "Promote";
|
|
3437
|
+
case "failed":
|
|
3438
|
+
return "Retry";
|
|
3439
|
+
case "promoted":
|
|
3440
|
+
return "Promoted";
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
function redactionLabel(candidate) {
|
|
3444
|
+
if (!candidate.redaction.redacted) return "No sensitive pattern matched";
|
|
3445
|
+
return `Redacted ${candidate.redaction.patterns.join(", ")}`;
|
|
3446
|
+
}
|
|
3447
|
+
function previewText(value, maxLength) {
|
|
3448
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
3449
|
+
if (normalized.length <= maxLength) return normalized;
|
|
3450
|
+
return `${normalized.slice(0, maxLength - 3)}...`;
|
|
3451
|
+
}
|
|
3452
|
+
function logRangeLabel(logIds) {
|
|
3453
|
+
const first = logIds[0];
|
|
3454
|
+
const last = logIds[logIds.length - 1];
|
|
3455
|
+
if (first === void 0) return "No evidence logs";
|
|
3456
|
+
if (last === void 0 || first === last) return `#${String(first)}`;
|
|
3457
|
+
return `#${String(first)}-#${String(last)}`;
|
|
3458
|
+
}
|
|
3459
|
+
function tagsToText(tags) {
|
|
3460
|
+
return tags.join(", ");
|
|
3461
|
+
}
|
|
3462
|
+
function textToTags(value) {
|
|
3463
|
+
return value.split(",").map((tag) => tag.trim()).filter((tag) => tag.length > 0);
|
|
3464
|
+
}
|
|
3465
|
+
function CandidateItem({
|
|
3466
|
+
candidate,
|
|
3467
|
+
isPromoting,
|
|
3468
|
+
isUpdating,
|
|
3469
|
+
onPromoteCandidate,
|
|
3470
|
+
onUpdateCandidate
|
|
3471
|
+
}) {
|
|
3472
|
+
const [editing, setEditing] = reactExports.useState(false);
|
|
3473
|
+
const [draftType, setDraftType] = reactExports.useState(candidate.type);
|
|
3474
|
+
const [draftTitle, setDraftTitle] = reactExports.useState(candidate.title);
|
|
3475
|
+
const [draftContent, setDraftContent] = reactExports.useState(candidate.content);
|
|
3476
|
+
const [draftTags, setDraftTags] = reactExports.useState(tagsToText(candidate.tags));
|
|
3477
|
+
const [localError, setLocalError] = reactExports.useState(null);
|
|
3478
|
+
const canPromote = candidate.status !== "promoted";
|
|
3479
|
+
const canEdit = candidate.status !== "promoted";
|
|
3480
|
+
const resetDraft = reactExports.useCallback(() => {
|
|
3481
|
+
setDraftType(candidate.type);
|
|
3482
|
+
setDraftTitle(candidate.title);
|
|
3483
|
+
setDraftContent(candidate.content);
|
|
3484
|
+
setDraftTags(tagsToText(candidate.tags));
|
|
3485
|
+
setLocalError(null);
|
|
3486
|
+
}, [candidate.content, candidate.tags, candidate.title, candidate.type]);
|
|
3487
|
+
const saveDraft = reactExports.useCallback(async () => {
|
|
3488
|
+
const title = draftTitle.trim();
|
|
3489
|
+
const content = draftContent.trim();
|
|
3490
|
+
const tags = textToTags(draftTags);
|
|
3491
|
+
if (title.length === 0) {
|
|
3492
|
+
setLocalError("Title is required.");
|
|
3493
|
+
return;
|
|
3494
|
+
}
|
|
3495
|
+
if (content.length === 0) {
|
|
3496
|
+
setLocalError("Content is required.");
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3499
|
+
if (tags.length === 0) {
|
|
3500
|
+
setLocalError("At least one tag is required.");
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
setLocalError(null);
|
|
3504
|
+
const saved = await onUpdateCandidate(candidate.id, {
|
|
3505
|
+
type: draftType,
|
|
3506
|
+
title,
|
|
3507
|
+
content,
|
|
3508
|
+
tags
|
|
3509
|
+
});
|
|
3510
|
+
if (saved) setEditing(false);
|
|
3511
|
+
}, [candidate.id, draftContent, draftTags, draftTitle, draftType, onUpdateCandidate]);
|
|
3512
|
+
if (editing) {
|
|
3513
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-border/80 bg-background/60 px-2.5 py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-2", children: [
|
|
3514
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
3515
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3516
|
+
"select",
|
|
3517
|
+
{
|
|
3518
|
+
value: draftType,
|
|
3519
|
+
disabled: isUpdating,
|
|
3520
|
+
onChange: (event) => {
|
|
3521
|
+
const parsed = KnowledgeCandidateSchema.shape.type.safeParse(
|
|
3522
|
+
event.currentTarget.value
|
|
3523
|
+
);
|
|
3524
|
+
if (parsed.success) setDraftType(parsed.data);
|
|
3525
|
+
},
|
|
3526
|
+
className: "h-7 rounded-md border border-input bg-background px-2 text-xs",
|
|
3527
|
+
"aria-label": "Candidate type",
|
|
3528
|
+
children: [
|
|
3529
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "episode", children: "episode" }),
|
|
3530
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "procedure", children: "procedure" }),
|
|
3531
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "preference", children: "preference" }),
|
|
3532
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "project-fact", children: "project-fact" })
|
|
3533
|
+
]
|
|
3534
|
+
}
|
|
3535
|
+
),
|
|
3536
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3537
|
+
"input",
|
|
3538
|
+
{
|
|
3539
|
+
value: draftTitle,
|
|
3540
|
+
disabled: isUpdating,
|
|
3541
|
+
onChange: (event) => setDraftTitle(event.currentTarget.value),
|
|
3542
|
+
className: "h-7 min-w-[220px] flex-1 rounded-md border border-input bg-background px-2 text-xs",
|
|
3543
|
+
"aria-label": "Candidate title"
|
|
3544
|
+
}
|
|
3545
|
+
)
|
|
3546
|
+
] }),
|
|
3547
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3548
|
+
"textarea",
|
|
3549
|
+
{
|
|
3550
|
+
value: draftContent,
|
|
3551
|
+
disabled: isUpdating,
|
|
3552
|
+
onChange: (event) => setDraftContent(event.currentTarget.value),
|
|
3553
|
+
className: "min-h-28 rounded-md border border-input bg-background px-2 py-1.5 font-mono text-[11px] leading-relaxed",
|
|
3554
|
+
"aria-label": "Candidate content"
|
|
3555
|
+
}
|
|
3556
|
+
),
|
|
3557
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3558
|
+
"input",
|
|
3559
|
+
{
|
|
3560
|
+
value: draftTags,
|
|
3561
|
+
disabled: isUpdating,
|
|
3562
|
+
onChange: (event) => setDraftTags(event.currentTarget.value),
|
|
3563
|
+
className: "h-7 rounded-md border border-input bg-background px-2 text-xs",
|
|
3564
|
+
"aria-label": "Candidate tags"
|
|
3565
|
+
}
|
|
3566
|
+
),
|
|
3567
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
3568
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1 text-[10px] text-muted-foreground", children: [
|
|
3569
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ShieldCheck, { className: "size-3" }),
|
|
3570
|
+
"Saving reruns Inspector redaction before promotion."
|
|
3281
3571
|
] }),
|
|
3282
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("
|
|
3283
|
-
|
|
3572
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1" }),
|
|
3573
|
+
localError !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-destructive", children: localError }),
|
|
3574
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3575
|
+
Button,
|
|
3284
3576
|
{
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3577
|
+
type: "button",
|
|
3578
|
+
variant: "ghost",
|
|
3579
|
+
size: "sm",
|
|
3580
|
+
className: "h-7 gap-1.5 px-2 text-xs",
|
|
3581
|
+
disabled: isUpdating,
|
|
3582
|
+
onClick: () => {
|
|
3583
|
+
resetDraft();
|
|
3584
|
+
setEditing(false);
|
|
3289
3585
|
},
|
|
3290
|
-
className: "rounded border border-blue-400/25 px-1.5 py-0.5 font-mono text-[10px] text-blue-400 underline-offset-2 transition-colors hover:bg-blue-400/10 hover:text-blue-300 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
3291
|
-
"aria-label": `Jump to evidence log ${String(logId)}`,
|
|
3292
3586
|
children: [
|
|
3293
|
-
"
|
|
3294
|
-
|
|
3587
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "size-3.5" }),
|
|
3588
|
+
"Cancel"
|
|
3295
3589
|
]
|
|
3590
|
+
}
|
|
3591
|
+
),
|
|
3592
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3593
|
+
Button,
|
|
3594
|
+
{
|
|
3595
|
+
type: "button",
|
|
3596
|
+
variant: "outline",
|
|
3597
|
+
size: "sm",
|
|
3598
|
+
className: "h-7 gap-1.5 px-2 text-xs",
|
|
3599
|
+
disabled: isUpdating,
|
|
3600
|
+
onClick: () => {
|
|
3601
|
+
void saveDraft();
|
|
3602
|
+
},
|
|
3603
|
+
children: [
|
|
3604
|
+
isUpdating ? /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { className: "size-3.5" }),
|
|
3605
|
+
"Save"
|
|
3606
|
+
]
|
|
3607
|
+
}
|
|
3608
|
+
)
|
|
3609
|
+
] })
|
|
3610
|
+
] }) });
|
|
3611
|
+
}
|
|
3612
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-md border border-border/80 bg-background/60 px-2.5 py-2", children: [
|
|
3613
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
3614
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "h-5 px-1.5 text-[10px] font-mono", children: candidate.type }),
|
|
3615
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1 truncate text-xs font-medium", title: candidate.title, children: candidate.title }),
|
|
3616
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3617
|
+
Badge,
|
|
3618
|
+
{
|
|
3619
|
+
variant: "outline",
|
|
3620
|
+
className: cn(
|
|
3621
|
+
"h-5 shrink-0 px-1.5 text-[10px] font-mono",
|
|
3622
|
+
CANDIDATE_STATUS_CLASSES[candidate.status]
|
|
3623
|
+
),
|
|
3624
|
+
children: candidateStatusLabel(candidate.status)
|
|
3625
|
+
}
|
|
3626
|
+
)
|
|
3627
|
+
] }),
|
|
3628
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3629
|
+
"p",
|
|
3630
|
+
{
|
|
3631
|
+
className: "mt-1 text-[11px] leading-relaxed text-muted-foreground",
|
|
3632
|
+
title: candidate.content,
|
|
3633
|
+
children: previewText(candidate.content, 360)
|
|
3634
|
+
}
|
|
3635
|
+
),
|
|
3636
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-[10px] text-muted-foreground", children: [
|
|
3637
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1", children: [
|
|
3638
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FileSearch, { className: "size-3" }),
|
|
3639
|
+
logRangeLabel(candidate.logIds)
|
|
3640
|
+
] }),
|
|
3641
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1", children: [
|
|
3642
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ShieldCheck, { className: "size-3" }),
|
|
3643
|
+
redactionLabel(candidate)
|
|
3644
|
+
] }),
|
|
3645
|
+
candidate.status === "promoted" && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1 text-emerald-500", children: [
|
|
3646
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "size-3" }),
|
|
3647
|
+
candidate.openClawMemoryId ?? "OpenClaw"
|
|
3648
|
+
] }),
|
|
3649
|
+
candidate.status === "failed" && candidate.error !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1 text-destructive", children: [
|
|
3650
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "size-3" }),
|
|
3651
|
+
candidate.error
|
|
3652
|
+
] })
|
|
3653
|
+
] }),
|
|
3654
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-1.5", children: [
|
|
3655
|
+
candidate.logIds.map((logId) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3656
|
+
"a",
|
|
3657
|
+
{
|
|
3658
|
+
href: `#${getLogAnchor(logId)}`,
|
|
3659
|
+
onClick: (event) => {
|
|
3660
|
+
event.preventDefault();
|
|
3661
|
+
jumpToLog(logId);
|
|
3296
3662
|
},
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3663
|
+
className: "rounded border border-blue-400/25 px-1.5 py-0.5 font-mono text-[10px] text-blue-400 underline-offset-2 transition-colors hover:bg-blue-400/10 hover:text-blue-300 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
3664
|
+
"aria-label": `Jump to evidence log ${String(logId)}`,
|
|
3665
|
+
children: [
|
|
3666
|
+
"#",
|
|
3667
|
+
logId
|
|
3668
|
+
]
|
|
3669
|
+
},
|
|
3670
|
+
logId
|
|
3671
|
+
)),
|
|
3672
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1" }),
|
|
3673
|
+
canEdit && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3674
|
+
Button,
|
|
3675
|
+
{
|
|
3676
|
+
type: "button",
|
|
3677
|
+
variant: "ghost",
|
|
3678
|
+
size: "sm",
|
|
3679
|
+
className: "h-6 gap-1.5 px-2 text-[10px]",
|
|
3680
|
+
disabled: isUpdating || isPromoting,
|
|
3681
|
+
onClick: () => setEditing(true),
|
|
3682
|
+
children: [
|
|
3683
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Pencil, { className: "size-3" }),
|
|
3684
|
+
"Review"
|
|
3685
|
+
]
|
|
3686
|
+
}
|
|
3687
|
+
),
|
|
3688
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3689
|
+
Button,
|
|
3690
|
+
{
|
|
3691
|
+
type: "button",
|
|
3692
|
+
variant: canPromote ? "outline" : "ghost",
|
|
3693
|
+
size: "sm",
|
|
3694
|
+
className: "h-6 gap-1.5 px-2 text-[10px]",
|
|
3695
|
+
onClick: () => onPromoteCandidate(candidate.id),
|
|
3696
|
+
disabled: !canPromote || isPromoting || isUpdating,
|
|
3697
|
+
children: [
|
|
3698
|
+
isPromoting ? /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "size-3 animate-spin" }) : canPromote ? /* @__PURE__ */ jsxRuntimeExports.jsx(CloudUpload, { className: "size-3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "size-3" }),
|
|
3699
|
+
candidatePromoteLabel(candidate, isPromoting)
|
|
3700
|
+
]
|
|
3701
|
+
}
|
|
3702
|
+
)
|
|
3703
|
+
] })
|
|
3704
|
+
] });
|
|
3705
|
+
}
|
|
3706
|
+
function CandidateList({
|
|
3707
|
+
candidates,
|
|
3708
|
+
promotingCandidateIds,
|
|
3709
|
+
updatingCandidateIds,
|
|
3710
|
+
onPromoteCandidate,
|
|
3711
|
+
onUpdateCandidate
|
|
3712
|
+
}) {
|
|
3713
|
+
if (candidates.length === 0) return null;
|
|
3714
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 grid gap-1.5", children: candidates.map((candidate) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3715
|
+
CandidateItem,
|
|
3716
|
+
{
|
|
3717
|
+
candidate,
|
|
3718
|
+
isPromoting: promotingCandidateIds.has(candidate.id),
|
|
3719
|
+
isUpdating: updatingCandidateIds.has(candidate.id),
|
|
3720
|
+
onPromoteCandidate,
|
|
3721
|
+
onUpdateCandidate
|
|
3300
3722
|
},
|
|
3301
3723
|
candidate.id
|
|
3302
3724
|
)) });
|
|
@@ -3314,11 +3736,21 @@ function AgentTraceSummary({
|
|
|
3314
3736
|
status: "idle",
|
|
3315
3737
|
error: null
|
|
3316
3738
|
});
|
|
3739
|
+
const [promotingCandidateIds, setPromotingCandidateIds] = reactExports.useState(
|
|
3740
|
+
() => /* @__PURE__ */ new Set()
|
|
3741
|
+
);
|
|
3742
|
+
const [updatingCandidateIds, setUpdatingCandidateIds] = reactExports.useState(
|
|
3743
|
+
() => /* @__PURE__ */ new Set()
|
|
3744
|
+
);
|
|
3317
3745
|
const hasCandidates = candidates.length > 0;
|
|
3318
3746
|
const summary = reactExports.useMemo(
|
|
3319
3747
|
() => buildTraceSummary(logs, slowResponseThresholdSeconds, candidates.length),
|
|
3320
3748
|
[candidates.length, logs, slowResponseThresholdSeconds]
|
|
3321
3749
|
);
|
|
3750
|
+
const traceInsights = reactExports.useMemo(
|
|
3751
|
+
() => buildTraceInsights({ logs, scopeId, summary, candidates }),
|
|
3752
|
+
[candidates, logs, scopeId, summary]
|
|
3753
|
+
);
|
|
3322
3754
|
const showElapsedSummary = showRollupMetrics || summary.maxElapsedMs !== null;
|
|
3323
3755
|
const timeRange = reactExports.useMemo(
|
|
3324
3756
|
() => formatTimeRange$1(summary.startedAt, summary.endedAt, timeDisplayFormat),
|
|
@@ -3344,7 +3776,9 @@ function AgentTraceSummary({
|
|
|
3344
3776
|
const parsed = await parseJsonResponse$1(response, CandidateResponseSchema);
|
|
3345
3777
|
setCandidates(parsed.candidates);
|
|
3346
3778
|
setCandidatesExpanded(parsed.candidates.length > 0);
|
|
3347
|
-
setCandidateState(
|
|
3779
|
+
setCandidateState(
|
|
3780
|
+
parsed.candidates.length > 0 ? { status: "ready", error: null } : { status: "failed", error: "No candidate was generated for this trace scope." }
|
|
3781
|
+
);
|
|
3348
3782
|
} catch (error) {
|
|
3349
3783
|
setCandidateState({
|
|
3350
3784
|
status: "failed",
|
|
@@ -3353,6 +3787,105 @@ function AgentTraceSummary({
|
|
|
3353
3787
|
}
|
|
3354
3788
|
})();
|
|
3355
3789
|
}, [candidateState.status, logs.length, scopeId]);
|
|
3790
|
+
const promoteCandidate = reactExports.useCallback((candidateId) => {
|
|
3791
|
+
setPromotingCandidateIds((current) => {
|
|
3792
|
+
if (current.has(candidateId)) return current;
|
|
3793
|
+
const next = new Set(current);
|
|
3794
|
+
next.add(candidateId);
|
|
3795
|
+
return next;
|
|
3796
|
+
});
|
|
3797
|
+
void (async () => {
|
|
3798
|
+
try {
|
|
3799
|
+
const response = await fetch(
|
|
3800
|
+
`/api/knowledge/candidates/${encodeURIComponent(candidateId)}/promote`,
|
|
3801
|
+
{ method: "POST" }
|
|
3802
|
+
);
|
|
3803
|
+
const raw = await response.json().catch(() => null);
|
|
3804
|
+
const parsed = CandidatePromotionResponseSchema.safeParse(raw);
|
|
3805
|
+
if (response.ok && parsed.success) {
|
|
3806
|
+
setCandidates(
|
|
3807
|
+
(current) => current.map(
|
|
3808
|
+
(candidate) => candidate.id === parsed.data.candidate.id ? parsed.data.candidate : candidate
|
|
3809
|
+
)
|
|
3810
|
+
);
|
|
3811
|
+
setCandidateState({ status: "ready", error: null });
|
|
3812
|
+
return;
|
|
3813
|
+
}
|
|
3814
|
+
const failure = CandidatePromotionFailureResponseSchema.safeParse(raw);
|
|
3815
|
+
if (failure.success && failure.data.candidate !== void 0) {
|
|
3816
|
+
setCandidates(
|
|
3817
|
+
(current) => current.map(
|
|
3818
|
+
(candidate) => candidate.id === failure.data.candidate?.id ? failure.data.candidate : candidate
|
|
3819
|
+
)
|
|
3820
|
+
);
|
|
3821
|
+
}
|
|
3822
|
+
setCandidateState({
|
|
3823
|
+
status: "failed",
|
|
3824
|
+
error: failure.success ? failure.data.error ?? "Candidate promotion failed" : `Candidate promotion failed with ${String(response.status)}`
|
|
3825
|
+
});
|
|
3826
|
+
} catch (error) {
|
|
3827
|
+
setCandidateState({
|
|
3828
|
+
status: "failed",
|
|
3829
|
+
error: error instanceof Error ? error.message : "Candidate promotion failed"
|
|
3830
|
+
});
|
|
3831
|
+
} finally {
|
|
3832
|
+
setPromotingCandidateIds((current) => {
|
|
3833
|
+
const next = new Set(current);
|
|
3834
|
+
next.delete(candidateId);
|
|
3835
|
+
return next;
|
|
3836
|
+
});
|
|
3837
|
+
}
|
|
3838
|
+
})();
|
|
3839
|
+
}, []);
|
|
3840
|
+
const updateCandidate = reactExports.useCallback(
|
|
3841
|
+
async (candidateId, update) => {
|
|
3842
|
+
setUpdatingCandidateIds((current) => {
|
|
3843
|
+
if (current.has(candidateId)) return current;
|
|
3844
|
+
const next = new Set(current);
|
|
3845
|
+
next.add(candidateId);
|
|
3846
|
+
return next;
|
|
3847
|
+
});
|
|
3848
|
+
try {
|
|
3849
|
+
const response = await fetch(
|
|
3850
|
+
`/api/knowledge/candidates/${encodeURIComponent(candidateId)}`,
|
|
3851
|
+
{
|
|
3852
|
+
method: "PATCH",
|
|
3853
|
+
headers: { "Content-Type": "application/json" },
|
|
3854
|
+
body: JSON.stringify(update)
|
|
3855
|
+
}
|
|
3856
|
+
);
|
|
3857
|
+
if (!response.ok) {
|
|
3858
|
+
const message = await readApiError(
|
|
3859
|
+
response,
|
|
3860
|
+
`Candidate update failed with ${String(response.status)}`
|
|
3861
|
+
);
|
|
3862
|
+
setCandidateState({ status: "failed", error: message });
|
|
3863
|
+
return false;
|
|
3864
|
+
}
|
|
3865
|
+
const parsed = await parseJsonResponse$1(response, CandidateUpdateResponseSchema);
|
|
3866
|
+
setCandidates(
|
|
3867
|
+
(current) => current.map(
|
|
3868
|
+
(candidate) => candidate.id === parsed.candidate.id ? parsed.candidate : candidate
|
|
3869
|
+
)
|
|
3870
|
+
);
|
|
3871
|
+
setCandidateState({ status: "ready", error: null });
|
|
3872
|
+
return true;
|
|
3873
|
+
} catch (error) {
|
|
3874
|
+
setCandidateState({
|
|
3875
|
+
status: "failed",
|
|
3876
|
+
error: error instanceof Error ? error.message : "Candidate update failed"
|
|
3877
|
+
});
|
|
3878
|
+
return false;
|
|
3879
|
+
} finally {
|
|
3880
|
+
setUpdatingCandidateIds((current) => {
|
|
3881
|
+
const next = new Set(current);
|
|
3882
|
+
next.delete(candidateId);
|
|
3883
|
+
return next;
|
|
3884
|
+
});
|
|
3885
|
+
}
|
|
3886
|
+
},
|
|
3887
|
+
[]
|
|
3888
|
+
);
|
|
3356
3889
|
if (logs.length === 0) return null;
|
|
3357
3890
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "mb-2 rounded-lg border border-border bg-muted/10 px-3 py-2", children: [
|
|
3358
3891
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 text-xs", children: [
|
|
@@ -3377,7 +3910,7 @@ function AgentTraceSummary({
|
|
|
3377
3910
|
(summary.totalCacheCreationInputTokens > 0 || summary.totalCacheReadInputTokens > 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5 text-muted-foreground", children: [
|
|
3378
3911
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3.5 text-purple-400" }),
|
|
3379
3912
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono", children: [
|
|
3380
|
-
"+",
|
|
3913
|
+
"KV Cache +",
|
|
3381
3914
|
formatTokens(summary.totalCacheCreationInputTokens),
|
|
3382
3915
|
" / ~",
|
|
3383
3916
|
formatTokens(summary.totalCacheReadInputTokens)
|
|
@@ -3436,7 +3969,17 @@ function AgentTraceSummary({
|
|
|
3436
3969
|
)
|
|
3437
3970
|
] }),
|
|
3438
3971
|
candidateState.status === "failed" && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-2 text-xs text-destructive", children: candidateState.error }),
|
|
3439
|
-
|
|
3972
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TraceInsights, { insights: traceInsights }),
|
|
3973
|
+
candidatesExpanded && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3974
|
+
CandidateList,
|
|
3975
|
+
{
|
|
3976
|
+
candidates,
|
|
3977
|
+
promotingCandidateIds,
|
|
3978
|
+
updatingCandidateIds,
|
|
3979
|
+
onPromoteCandidate: promoteCandidate,
|
|
3980
|
+
onUpdateCandidate: updateCandidate
|
|
3981
|
+
}
|
|
3982
|
+
)
|
|
3440
3983
|
] });
|
|
3441
3984
|
}
|
|
3442
3985
|
function computeStats(logs) {
|
|
@@ -4088,26 +4631,18 @@ function TestStatus({ result }) {
|
|
|
4088
4631
|
}
|
|
4089
4632
|
if (result.cacheCreationInputTokens !== void 0 && result.cacheCreationInputTokens > 0) {
|
|
4090
4633
|
tokenParts.push(
|
|
4091
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
" cache"
|
|
4096
|
-
] }) }),
|
|
4097
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens cached for reuse, reducing future API cost" })
|
|
4098
|
-
] }) }, "cache-create")
|
|
4634
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-emerald-400", children: [
|
|
4635
|
+
"KV Cache +",
|
|
4636
|
+
result.cacheCreationInputTokens
|
|
4637
|
+
] }, "cache-create")
|
|
4099
4638
|
);
|
|
4100
4639
|
}
|
|
4101
4640
|
if (result.cacheReadInputTokens !== void 0 && result.cacheReadInputTokens > 0) {
|
|
4102
4641
|
tokenParts.push(
|
|
4103
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
" cached"
|
|
4108
|
-
] }) }),
|
|
4109
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Tokens served from cache, reducing API cost" })
|
|
4110
|
-
] }) }, "cache-read")
|
|
4642
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
|
|
4643
|
+
"KV Cache ~",
|
|
4644
|
+
result.cacheReadInputTokens
|
|
4645
|
+
] }, "cache-read")
|
|
4111
4646
|
);
|
|
4112
4647
|
}
|
|
4113
4648
|
const displayTokens = [];
|
|
@@ -5344,7 +5879,8 @@ function SettingsDialog() {
|
|
|
5344
5879
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { value: activeTab, onValueChange: setActiveTab, className: "flex-1 overflow-hidden", children: [
|
|
5345
5880
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, { children: [
|
|
5346
5881
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "providers", children: "Providers" }),
|
|
5347
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "proxy", children: "Proxy" })
|
|
5882
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "proxy", children: "Proxy" }),
|
|
5883
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "onboarding", children: "Onboarding" })
|
|
5348
5884
|
] }),
|
|
5349
5885
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-4 overflow-y-auto flex-1 pr-3", children: [
|
|
5350
5886
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "providers", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -5363,12 +5899,89 @@ function SettingsDialog() {
|
|
|
5363
5899
|
onTestingTimeLeftChange: handleTestingTimeLeftChange
|
|
5364
5900
|
}
|
|
5365
5901
|
) }),
|
|
5366
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "proxy", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProxySettingsTab, {}) })
|
|
5902
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "proxy", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProxySettingsTab, {}) }),
|
|
5903
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "onboarding", children: /* @__PURE__ */ jsxRuntimeExports.jsx(OnboardingSettingsTab, {}) })
|
|
5367
5904
|
] })
|
|
5368
5905
|
] })
|
|
5369
5906
|
] })
|
|
5370
5907
|
] });
|
|
5371
5908
|
}
|
|
5909
|
+
function CopyableSetupValue({
|
|
5910
|
+
id,
|
|
5911
|
+
label,
|
|
5912
|
+
value,
|
|
5913
|
+
copiedId,
|
|
5914
|
+
onCopy
|
|
5915
|
+
}) {
|
|
5916
|
+
const copied = copiedId === id;
|
|
5917
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-3 py-2", children: [
|
|
5918
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: label }),
|
|
5919
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
5920
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "min-w-0 flex-1 truncate font-mono text-xs text-foreground", children: value }),
|
|
5921
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5922
|
+
Button,
|
|
5923
|
+
{
|
|
5924
|
+
type: "button",
|
|
5925
|
+
variant: "ghost",
|
|
5926
|
+
size: "icon",
|
|
5927
|
+
className: "size-7 shrink-0",
|
|
5928
|
+
onClick: () => onCopy(id, value),
|
|
5929
|
+
"aria-label": copied ? `Copied ${label}` : `Copy ${label}`,
|
|
5930
|
+
children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-emerald-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
|
|
5931
|
+
}
|
|
5932
|
+
)
|
|
5933
|
+
] })
|
|
5934
|
+
] });
|
|
5935
|
+
}
|
|
5936
|
+
function OnboardingSettingsTab() {
|
|
5937
|
+
const [copiedId, setCopiedId] = reactExports.useState(null);
|
|
5938
|
+
const origin = reactExports.useMemo(() => {
|
|
5939
|
+
if (typeof window === "undefined") return "http://localhost:25947";
|
|
5940
|
+
return window.location.origin;
|
|
5941
|
+
}, []);
|
|
5942
|
+
const values = reactExports.useMemo(
|
|
5943
|
+
() => [
|
|
5944
|
+
{ id: "skill", label: "Codex skill", value: "agent-inspector onboard --force" },
|
|
5945
|
+
{ id: "mcp", label: "MCP URL", value: `${origin}/api/mcp` },
|
|
5946
|
+
{ id: "proxy", label: "Proxy URL", value: `${origin}/proxy` },
|
|
5947
|
+
{ id: "anthropic", label: "Anthropic base", value: `ANTHROPIC_BASE_URL=${origin}/proxy` }
|
|
5948
|
+
],
|
|
5949
|
+
[origin]
|
|
5950
|
+
);
|
|
5951
|
+
const handleCopy = reactExports.useCallback((id, value) => {
|
|
5952
|
+
void window.navigator.clipboard.writeText(value).then(() => {
|
|
5953
|
+
setCopiedId(id);
|
|
5954
|
+
setTimeout(() => setCopiedId(null), 1600);
|
|
5955
|
+
});
|
|
5956
|
+
}, []);
|
|
5957
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
|
|
5958
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
5959
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { className: "size-4 text-muted-foreground" }),
|
|
5960
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-semibold", children: "Agent onboarding" })
|
|
5961
|
+
] }),
|
|
5962
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-2", children: values.map((item) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5963
|
+
CopyableSetupValue,
|
|
5964
|
+
{
|
|
5965
|
+
id: item.id,
|
|
5966
|
+
label: item.label,
|
|
5967
|
+
value: item.value,
|
|
5968
|
+
copiedId,
|
|
5969
|
+
onCopy: handleCopy
|
|
5970
|
+
},
|
|
5971
|
+
item.id
|
|
5972
|
+
)) }),
|
|
5973
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-2 rounded-md border border-border bg-background px-3 py-2 text-xs text-muted-foreground", children: [
|
|
5974
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
5975
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-emerald-500" }),
|
|
5976
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Provider test creates a traceable memory probe session." })
|
|
5977
|
+
] }),
|
|
5978
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
5979
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-emerald-500" }),
|
|
5980
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Captured sessions can produce reviewable memory candidates." })
|
|
5981
|
+
] })
|
|
5982
|
+
] })
|
|
5983
|
+
] });
|
|
5984
|
+
}
|
|
5372
5985
|
function ProxySettingsTab() {
|
|
5373
5986
|
const {
|
|
5374
5987
|
strip,
|
|
@@ -5566,20 +6179,40 @@ function safeItemAt(items, index) {
|
|
|
5566
6179
|
}
|
|
5567
6180
|
function isEditableTarget(target) {
|
|
5568
6181
|
const tag = target.tagName;
|
|
5569
|
-
if (tag === "INPUT" || tag === "TEXTAREA") return true;
|
|
6182
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
5570
6183
|
if (target.isContentEditable) return true;
|
|
5571
6184
|
return false;
|
|
5572
6185
|
}
|
|
5573
|
-
function
|
|
6186
|
+
function isInteractiveTarget(target) {
|
|
6187
|
+
const tag = target.tagName;
|
|
6188
|
+
if (tag === "BUTTON" || tag === "A") return true;
|
|
6189
|
+
if (isEditableTarget(target)) return true;
|
|
6190
|
+
return target.closest("[role='button'],[role='menuitem'],[role='option']") !== null;
|
|
6191
|
+
}
|
|
6192
|
+
function isInOpenOverlay(target) {
|
|
6193
|
+
if (target.closest("[role='dialog'],[role='menu'],[role='listbox']") !== null) return true;
|
|
6194
|
+
return document.querySelector("[role='dialog'],[role='menu'],[role='listbox']") !== null;
|
|
6195
|
+
}
|
|
6196
|
+
function hasActiveTextSelection() {
|
|
6197
|
+
const selection = window.getSelection();
|
|
6198
|
+
if (selection === null) return false;
|
|
6199
|
+
return selection.type === "Range" && selection.toString().length > 0;
|
|
6200
|
+
}
|
|
6201
|
+
function isLetterNavigationKey(event, key) {
|
|
6202
|
+
return event.key === key && event.shiftKey;
|
|
6203
|
+
}
|
|
6204
|
+
function useKeyboardNavigation(containerRef, wrapperRef, options = {}) {
|
|
5574
6205
|
const rootRef = wrapperRef ?? containerRef;
|
|
6206
|
+
const pageWide = options.pageWide === true;
|
|
5575
6207
|
const handleFocusContainer = reactExports.useCallback(
|
|
5576
6208
|
(e) => {
|
|
5577
6209
|
const container = containerRef.current;
|
|
6210
|
+
const root = rootRef.current;
|
|
5578
6211
|
if (!container) return;
|
|
6212
|
+
if (!root) return;
|
|
5579
6213
|
const target = e.target;
|
|
5580
6214
|
if (!isFocusTarget(target)) return;
|
|
5581
|
-
if (target !==
|
|
5582
|
-
if (!container.contains(target)) return;
|
|
6215
|
+
if (target !== root) return;
|
|
5583
6216
|
const items = findNavItems(container);
|
|
5584
6217
|
const first = safeItemAt(items, 0);
|
|
5585
6218
|
if (first !== null) focusAndScroll(first);
|
|
@@ -5587,14 +6220,22 @@ function useKeyboardNavigation(containerRef, wrapperRef) {
|
|
|
5587
6220
|
[containerRef, rootRef]
|
|
5588
6221
|
);
|
|
5589
6222
|
reactExports.useEffect(() => {
|
|
5590
|
-
const root = rootRef.current;
|
|
5591
|
-
const container = containerRef.current;
|
|
5592
|
-
if (!root || !container) return;
|
|
5593
6223
|
const handleKeyDown = (e) => {
|
|
6224
|
+
if (e.altKey || e.ctrlKey || e.metaKey) return;
|
|
6225
|
+
const container = containerRef.current;
|
|
6226
|
+
if (!container) return;
|
|
5594
6227
|
const target = e.target;
|
|
5595
6228
|
if (!isFocusTarget(target)) return;
|
|
5596
|
-
if (!container.contains(target)) return;
|
|
5597
6229
|
if (isEditableTarget(target)) return;
|
|
6230
|
+
if (hasActiveTextSelection()) return;
|
|
6231
|
+
const isInsideContainer = container.contains(target);
|
|
6232
|
+
if (isInsideContainer && isInteractiveTarget(target) && !target.hasAttribute(NAV_ATTR)) {
|
|
6233
|
+
return;
|
|
6234
|
+
}
|
|
6235
|
+
if (!isInsideContainer) {
|
|
6236
|
+
if (!pageWide) return;
|
|
6237
|
+
if (isInteractiveTarget(target) || isInOpenOverlay(target)) return;
|
|
6238
|
+
}
|
|
5598
6239
|
const items = findNavItems(container);
|
|
5599
6240
|
if (items.length === 0) return;
|
|
5600
6241
|
const current = findClosestNavItem(target, container);
|
|
@@ -5603,7 +6244,8 @@ function useKeyboardNavigation(containerRef, wrapperRef) {
|
|
|
5603
6244
|
switch (e.key) {
|
|
5604
6245
|
case "ArrowUp":
|
|
5605
6246
|
case "W": {
|
|
5606
|
-
if (e.key === "
|
|
6247
|
+
if (e.shiftKey && e.key === "ArrowUp") break;
|
|
6248
|
+
if (e.key === "W" && !isLetterNavigationKey(e, "W")) break;
|
|
5607
6249
|
e.preventDefault();
|
|
5608
6250
|
const prevIdx = currentIdx > 0 ? currentIdx - 1 : currentIdx === -1 ? items.length - 1 : -1;
|
|
5609
6251
|
if (prevIdx !== -1) {
|
|
@@ -5615,7 +6257,8 @@ function useKeyboardNavigation(containerRef, wrapperRef) {
|
|
|
5615
6257
|
}
|
|
5616
6258
|
case "ArrowDown":
|
|
5617
6259
|
case "S": {
|
|
5618
|
-
if (e.key === "
|
|
6260
|
+
if (e.shiftKey && e.key === "ArrowDown") break;
|
|
6261
|
+
if (e.key === "S" && !isLetterNavigationKey(e, "S")) break;
|
|
5619
6262
|
e.preventDefault();
|
|
5620
6263
|
const nextIdx = currentIdx < items.length - 1 ? currentIdx + 1 : currentIdx === -1 ? 0 : -1;
|
|
5621
6264
|
if (nextIdx !== -1) {
|
|
@@ -5627,7 +6270,8 @@ function useKeyboardNavigation(containerRef, wrapperRef) {
|
|
|
5627
6270
|
}
|
|
5628
6271
|
case "ArrowLeft":
|
|
5629
6272
|
case "A": {
|
|
5630
|
-
if (e.key === "
|
|
6273
|
+
if (e.shiftKey && e.key === "ArrowLeft") break;
|
|
6274
|
+
if (e.key === "A" && !isLetterNavigationKey(e, "A")) break;
|
|
5631
6275
|
if (current === null) break;
|
|
5632
6276
|
e.preventDefault();
|
|
5633
6277
|
const action = getAction(current);
|
|
@@ -5642,7 +6286,8 @@ function useKeyboardNavigation(containerRef, wrapperRef) {
|
|
|
5642
6286
|
}
|
|
5643
6287
|
case "ArrowRight":
|
|
5644
6288
|
case "D": {
|
|
5645
|
-
if (e.key === "
|
|
6289
|
+
if (e.shiftKey && e.key === "ArrowRight") break;
|
|
6290
|
+
if (e.key === "D" && !isLetterNavigationKey(e, "D")) break;
|
|
5646
6291
|
if (current === null) break;
|
|
5647
6292
|
e.preventDefault();
|
|
5648
6293
|
const action = getAction(current);
|
|
@@ -5670,13 +6315,11 @@ function useKeyboardNavigation(containerRef, wrapperRef) {
|
|
|
5670
6315
|
};
|
|
5671
6316
|
document.addEventListener("keydown", handleKeyDown, { capture: true });
|
|
5672
6317
|
return () => document.removeEventListener("keydown", handleKeyDown, { capture: true });
|
|
5673
|
-
}, [containerRef, rootRef]);
|
|
6318
|
+
}, [containerRef, pageWide, rootRef]);
|
|
5674
6319
|
reactExports.useEffect(() => {
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
return () => root.removeEventListener("focus", handleFocusContainer);
|
|
5679
|
-
}, [handleFocusContainer, rootRef]);
|
|
6320
|
+
document.addEventListener("focusin", handleFocusContainer);
|
|
6321
|
+
return () => document.removeEventListener("focusin", handleFocusContainer);
|
|
6322
|
+
}, [handleFocusContainer]);
|
|
5680
6323
|
}
|
|
5681
6324
|
function truncateSessionId(id) {
|
|
5682
6325
|
if (id.length <= 30) return id;
|
|
@@ -5862,7 +6505,7 @@ function ProxyViewer({
|
|
|
5862
6505
|
);
|
|
5863
6506
|
const logListRef = reactExports.useRef(null);
|
|
5864
6507
|
const logListWrapperRef = reactExports.useRef(null);
|
|
5865
|
-
useKeyboardNavigation(logListRef, logListWrapperRef);
|
|
6508
|
+
useKeyboardNavigation(logListRef, logListWrapperRef, { pageWide: true });
|
|
5866
6509
|
reactExports.useEffect(() => {
|
|
5867
6510
|
const perCrabDuration = 400;
|
|
5868
6511
|
const startDelay = 50;
|
|
@@ -6392,5 +7035,6 @@ export {
|
|
|
6392
7035
|
getStatusCategory as p,
|
|
6393
7036
|
parseJsonText as q,
|
|
6394
7037
|
resolveLogFormat as r,
|
|
6395
|
-
safeJsonValue as s
|
|
7038
|
+
safeJsonValue as s,
|
|
7039
|
+
useProviders as u
|
|
6396
7040
|
};
|