@tonyclaw/agent-inspector 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/cli.js +344 -53
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-sVLGhCO3.js → CompareDrawer-D5A4bTfV.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-Da0jpBkp.js +101 -0
- package/.output/public/assets/{ReplayDialog-DxbFUqNW.js → ReplayDialog-CxUk_TF0.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-CSmGQa_g.js → RequestAnatomy-DIlzjgjJ.js} +1 -1
- package/.output/public/assets/ResponseView-DQCuKJ1G.js +1 -0
- package/.output/public/assets/{StreamingChunkSequence-BzqpY0TN.js → StreamingChunkSequence-DHk4SGGL.js} +1 -1
- package/.output/public/assets/_sessionId-dY1TTl7N.js +1 -0
- package/.output/public/assets/index-D7wwbwly.css +1 -0
- package/.output/public/assets/index-FqQZbfl2.js +1 -0
- package/.output/public/assets/{json-viewer-CKNMihlh.js → json-viewer-BbU0n8eM.js} +1 -1
- package/.output/public/assets/{main-yWf8dv9w.js → main-CZT_F-gu.js} +2 -2
- package/.output/server/_libs/lucide-react.mjs +8 -8
- package/.output/server/{_sessionId-DfHd0gd8.mjs → _sessionId-B-s9P7fJ.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-DGYAUWgF.mjs → CompareDrawer-C08L3UOO.mjs} +4 -4
- package/.output/server/_ssr/{ProxyViewerContainer-fawglkTo.mjs → ProxyViewerContainer-CMWl3Ijy.mjs} +414 -70
- package/.output/server/_ssr/{ReplayDialog-B4vlKa2W.mjs → ReplayDialog-CPDo9_G5.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-BNQvEIZK.mjs → RequestAnatomy-D9wt_K1E.mjs} +3 -3
- package/.output/server/_ssr/{ResponseView-X6X6G16_.mjs → ResponseView-DXaL7nY3.mjs} +4 -4
- package/.output/server/_ssr/{StreamingChunkSequence-BPVN3MnF.mjs → StreamingChunkSequence-B_hudZyb.mjs} +3 -3
- package/.output/server/_ssr/{index-CXmpc2X5.mjs → index-CuE_BN86.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-3XC3eq4R.mjs → json-viewer-Ci6kkjde.mjs} +2 -2
- package/.output/server/_ssr/{router-C0B2qvIM.mjs → router-BemxgIg7.mjs} +402 -131
- package/.output/server/{_tanstack-start-manifest_v-7tfsmd2I.mjs → _tanstack-start-manifest_v--L1_b4sd.mjs} +1 -1
- package/.output/server/index.mjs +62 -62
- package/README.md +50 -7
- package/package.json +3 -2
- package/scripts/setup-codex-skill.mjs +38 -0
- package/scripts/setup-windows-runtime.mjs +4 -3
- package/src/cli/onboard.ts +175 -68
- package/src/cli/templates/codex-skill-onboard.ts +210 -0
- package/src/components/providers/ProviderCard.tsx +2 -27
- package/src/components/providers/ProvidersPanel.tsx +16 -0
- package/src/components/proxy-viewer/AgentTraceSummary.tsx +218 -0
- package/src/components/proxy-viewer/ConversationGroup.tsx +6 -0
- package/src/components/proxy-viewer/ToolTraceEvents.tsx +33 -0
- package/src/components/proxy-viewer/TurnGroup.tsx +11 -1
- package/src/components/proxy-viewer/viewerState.ts +177 -0
- package/src/knowledge/openclawClient.ts +34 -5
- package/src/knowledge/openclawGatewayClient.ts +237 -0
- package/src/knowledge/openclawMarkdown.ts +146 -0
- package/src/lib/providerTestPrompt.ts +78 -0
- package/src/proxy/chunkStorage.ts +3 -4
- package/src/proxy/logger.ts +8 -15
- package/src/proxy/store.ts +8 -16
- package/src/routes/api/providers.$providerId.test.log.ts +7 -99
- package/.output/public/assets/ProxyViewerContainer-p9QvzZ6U.js +0 -101
- package/.output/public/assets/ResponseView-B5f89c8Z.js +0 -1
- package/.output/public/assets/_sessionId-BF7ftHV3.js +0 -1
- package/.output/public/assets/index-BU0PpLby.js +0 -1
- package/.output/public/assets/index-CpWG2hFn.css +0 -1
package/.output/server/_ssr/{ProxyViewerContainer-fawglkTo.mjs → ProxyViewerContainer-CMWl3Ijy.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 RuntimeConfigSchema, r as requestFormatForPath,
|
|
2
|
+
import { C as CapturedLogSchema, D as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, a as RuntimeConfigSchema, r as requestFormatForPath, d as createPendingProviderTestResults, P as ProviderTestResultsSchema, e as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, g as getSessionPath, f as ProviderConfigSchema, K as KnowledgeCandidateSchema, s as stripClaudeCodeBillingHeader, c as safeGetOwnProperty, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, b as AnthropicRequestSchema } from "./router-BemxgIg7.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, T as Trash2, i as TriangleAlert, j as EyeOff, k as Eye, R as RotateCw, l as Pencil, m as Minus, n as CircleCheckBig, O as OctagonAlert,
|
|
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, T as Trash2, W as Wrench, i as TriangleAlert, B as Brain, j as EyeOff, k as Eye, R as RotateCw, l as Pencil, m as Minus, n as CircleCheckBig, O as OctagonAlert, G as Globe, F as FileTerminal, o as Radio, p as ChevronsUp, q as ChevronsDown, r as FileDiff, H as History, s as RotateCcw, t as GitCompareArrows, u as CircleQuestionMark, v as Server, w as Gauge, x as Lock, y as Wifi, z as WifiOff, I as ArrowUp, J as ArrowDown, K as Rows3, N 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";
|
|
@@ -17,7 +17,7 @@ import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
|
|
|
17
17
|
const ApiErrorSchema = object({
|
|
18
18
|
error: string()
|
|
19
19
|
});
|
|
20
|
-
async function parseJsonResponse(response, schema) {
|
|
20
|
+
async function parseJsonResponse$1(response, schema) {
|
|
21
21
|
const data = await response.json();
|
|
22
22
|
return schema.parse(data);
|
|
23
23
|
}
|
|
@@ -36,7 +36,7 @@ async function fetchJson(input, schema, init, errorFallback) {
|
|
|
36
36
|
const fallback = errorFallback?.(response) ?? `Request failed with status ${response.status}`;
|
|
37
37
|
throw new Error(await readApiError(response, fallback));
|
|
38
38
|
}
|
|
39
|
-
return parseJsonResponse(response, schema);
|
|
39
|
+
return parseJsonResponse$1(response, schema);
|
|
40
40
|
}
|
|
41
41
|
const STRIP_CONFIG_SWR_KEY = "/api/config";
|
|
42
42
|
async function fetcher$2(url) {
|
|
@@ -275,7 +275,7 @@ function getStatusCategory(status) {
|
|
|
275
275
|
if (status >= 500) return "server_error";
|
|
276
276
|
return "pending";
|
|
277
277
|
}
|
|
278
|
-
const version = "2.0.
|
|
278
|
+
const version = "2.0.3";
|
|
279
279
|
const packageJson = {
|
|
280
280
|
version
|
|
281
281
|
};
|
|
@@ -1343,27 +1343,27 @@ function useCopyFeedback(text) {
|
|
|
1343
1343
|
return { copied, copy };
|
|
1344
1344
|
}
|
|
1345
1345
|
const LazyCompareDrawer = reactExports.lazy(
|
|
1346
|
-
() => import("./CompareDrawer-
|
|
1346
|
+
() => import("./CompareDrawer-C08L3UOO.mjs").then((m) => ({ default: m.CompareDrawer }))
|
|
1347
1347
|
);
|
|
1348
1348
|
const LazyReplayDialog = reactExports.lazy(
|
|
1349
|
-
() => import("./ReplayDialog-
|
|
1349
|
+
() => import("./ReplayDialog-CPDo9_G5.mjs").then((m) => ({ default: m.ReplayDialog }))
|
|
1350
1350
|
);
|
|
1351
1351
|
const LazyRequestAnatomy = reactExports.lazy(
|
|
1352
|
-
() => import("./RequestAnatomy-
|
|
1352
|
+
() => import("./RequestAnatomy-D9wt_K1E.mjs").then((m) => ({ default: m.RequestAnatomy }))
|
|
1353
1353
|
);
|
|
1354
1354
|
const LazyResponseView = reactExports.lazy(
|
|
1355
|
-
() => import("./ResponseView-
|
|
1355
|
+
() => import("./ResponseView-DXaL7nY3.mjs").then((m) => ({ default: m.ResponseView }))
|
|
1356
1356
|
);
|
|
1357
1357
|
const LazyStreamingChunkSequence = reactExports.lazy(
|
|
1358
|
-
() => import("./StreamingChunkSequence-
|
|
1358
|
+
() => import("./StreamingChunkSequence-B_hudZyb.mjs").then((m) => ({
|
|
1359
1359
|
default: m.StreamingChunkSequence
|
|
1360
1360
|
}))
|
|
1361
1361
|
);
|
|
1362
1362
|
const LazyJsonViewer = reactExports.lazy(
|
|
1363
|
-
() => import("./json-viewer-
|
|
1363
|
+
() => import("./json-viewer-Ci6kkjde.mjs").then((m) => ({ default: m.JsonViewer }))
|
|
1364
1364
|
);
|
|
1365
1365
|
const LazyJsonViewerFromString = reactExports.lazy(
|
|
1366
|
-
() => import("./json-viewer-
|
|
1366
|
+
() => import("./json-viewer-Ci6kkjde.mjs").then((m) => ({ default: m.JsonViewerFromString }))
|
|
1367
1367
|
);
|
|
1368
1368
|
const HIGHLIGHT_DURATION_MS = 1200;
|
|
1369
1369
|
const MAX_HIGHLIGHT_ATTEMPTS = 12;
|
|
@@ -1757,7 +1757,7 @@ const STATUS_BADGE_CLASSES = {
|
|
|
1757
1757
|
server_error: "bg-rose-500/15 text-rose-400 border-rose-500/25",
|
|
1758
1758
|
pending: "bg-muted text-muted-foreground border-border"
|
|
1759
1759
|
};
|
|
1760
|
-
function formatElapsed$
|
|
1760
|
+
function formatElapsed$2(ms) {
|
|
1761
1761
|
if (ms < 1e3) return `${ms}ms`;
|
|
1762
1762
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
1763
1763
|
}
|
|
@@ -1849,12 +1849,12 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1849
1849
|
),
|
|
1850
1850
|
children: [
|
|
1851
1851
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
|
|
1852
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed$
|
|
1852
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed$2(log.elapsedMs) }),
|
|
1853
1853
|
isSlowResponse && /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Slow response" })
|
|
1854
1854
|
]
|
|
1855
1855
|
}
|
|
1856
1856
|
) }),
|
|
1857
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: isSlowResponse ? `Slow response: ${formatElapsed$
|
|
1857
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: isSlowResponse ? `Slow response: ${formatElapsed$2(log.elapsedMs)} exceeds ${formatElapsed$2(
|
|
1858
1858
|
slowResponseThresholdSeconds * 1e3
|
|
1859
1859
|
)}` : "Elapsed response time" })
|
|
1860
1860
|
] }),
|
|
@@ -2764,6 +2764,29 @@ function ThreadConnector({
|
|
|
2764
2764
|
) })
|
|
2765
2765
|
] });
|
|
2766
2766
|
}
|
|
2767
|
+
function ToolTraceEvents({ events }) {
|
|
2768
|
+
if (events.length === 0) return null;
|
|
2769
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-3 mb-2 grid gap-1.5", children: events.map((event) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2770
|
+
"div",
|
|
2771
|
+
{
|
|
2772
|
+
className: "flex min-w-0 items-center gap-2 rounded-md border border-amber-500/20 bg-amber-500/5 px-2.5 py-1.5 text-xs",
|
|
2773
|
+
children: [
|
|
2774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3.5 shrink-0 text-amber-400" }),
|
|
2775
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono font-semibold text-amber-300", children: event.name }),
|
|
2776
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-muted-foreground", children: [
|
|
2777
|
+
"#",
|
|
2778
|
+
event.logId
|
|
2779
|
+
] }),
|
|
2780
|
+
event.argumentsPreview !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
2781
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3 shrink-0 text-muted-foreground/60" }),
|
|
2782
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 truncate font-mono text-muted-foreground", children: event.argumentsPreview })
|
|
2783
|
+
] })
|
|
2784
|
+
]
|
|
2785
|
+
},
|
|
2786
|
+
event.id
|
|
2787
|
+
)) });
|
|
2788
|
+
}
|
|
2789
|
+
const PREVIEW_LIMIT = 180;
|
|
2767
2790
|
function shouldRenderConversationContent(standalone, expanded) {
|
|
2768
2791
|
return standalone || expanded;
|
|
2769
2792
|
}
|
|
@@ -2801,7 +2824,135 @@ function buildValidPredecessors(groups) {
|
|
|
2801
2824
|
}
|
|
2802
2825
|
return predecessors;
|
|
2803
2826
|
}
|
|
2804
|
-
function
|
|
2827
|
+
function parseJsonResponse(responseText) {
|
|
2828
|
+
if (responseText === null) return null;
|
|
2829
|
+
try {
|
|
2830
|
+
const parsed = JSON.parse(responseText);
|
|
2831
|
+
if (typeof parsed === "string") {
|
|
2832
|
+
return JSON.parse(parsed);
|
|
2833
|
+
}
|
|
2834
|
+
return parsed;
|
|
2835
|
+
} catch {
|
|
2836
|
+
return null;
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
function previewValue(value) {
|
|
2840
|
+
if (value === void 0 || value === null) return null;
|
|
2841
|
+
const raw = typeof value === "string" ? value : JSON.stringify(value);
|
|
2842
|
+
if (raw === void 0) return null;
|
|
2843
|
+
const normalized = raw.replace(/\s+/g, " ").trim();
|
|
2844
|
+
if (normalized.length === 0) return null;
|
|
2845
|
+
return normalized.length > PREVIEW_LIMIT ? `${normalized.slice(0, PREVIEW_LIMIT - 1)}...` : normalized;
|
|
2846
|
+
}
|
|
2847
|
+
function extractAnthropicToolTraceEvents(log) {
|
|
2848
|
+
const parsed = parseJsonResponse(log.responseText);
|
|
2849
|
+
const content = safeGetOwnProperty(parsed, "content");
|
|
2850
|
+
if (!Array.isArray(content)) return [];
|
|
2851
|
+
const events = [];
|
|
2852
|
+
for (const block of content) {
|
|
2853
|
+
const type = safeGetOwnProperty(block, "type");
|
|
2854
|
+
if (type !== "tool_use") continue;
|
|
2855
|
+
const name = safeGetOwnProperty(block, "name");
|
|
2856
|
+
if (typeof name !== "string" || name.length === 0) continue;
|
|
2857
|
+
events.push({
|
|
2858
|
+
id: `${String(log.id)}-anthropic-tool-${String(events.length)}`,
|
|
2859
|
+
logId: log.id,
|
|
2860
|
+
index: events.length,
|
|
2861
|
+
provider: "anthropic",
|
|
2862
|
+
name,
|
|
2863
|
+
argumentsPreview: previewValue(safeGetOwnProperty(block, "input"))
|
|
2864
|
+
});
|
|
2865
|
+
}
|
|
2866
|
+
return events;
|
|
2867
|
+
}
|
|
2868
|
+
function extractOpenAIToolTraceEvents(log) {
|
|
2869
|
+
const parsed = parseJsonResponse(log.responseText);
|
|
2870
|
+
const choices = safeGetOwnProperty(parsed, "choices");
|
|
2871
|
+
if (!Array.isArray(choices)) return [];
|
|
2872
|
+
const events = [];
|
|
2873
|
+
for (const choice of choices) {
|
|
2874
|
+
const message = safeGetOwnProperty(choice, "message");
|
|
2875
|
+
const toolCalls = safeGetOwnProperty(message, "tool_calls");
|
|
2876
|
+
if (!Array.isArray(toolCalls)) continue;
|
|
2877
|
+
for (const call of toolCalls) {
|
|
2878
|
+
const fn = safeGetOwnProperty(call, "function");
|
|
2879
|
+
const name = safeGetOwnProperty(fn, "name");
|
|
2880
|
+
if (typeof name !== "string" || name.length === 0) continue;
|
|
2881
|
+
events.push({
|
|
2882
|
+
id: `${String(log.id)}-openai-tool-${String(events.length)}`,
|
|
2883
|
+
logId: log.id,
|
|
2884
|
+
index: events.length,
|
|
2885
|
+
provider: "openai",
|
|
2886
|
+
name,
|
|
2887
|
+
argumentsPreview: previewValue(safeGetOwnProperty(fn, "arguments"))
|
|
2888
|
+
});
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
return events;
|
|
2892
|
+
}
|
|
2893
|
+
function extractToolTraceEvents(log) {
|
|
2894
|
+
const format = resolveLogFormat(log);
|
|
2895
|
+
switch (format) {
|
|
2896
|
+
case "anthropic":
|
|
2897
|
+
return extractAnthropicToolTraceEvents(log);
|
|
2898
|
+
case "openai":
|
|
2899
|
+
return extractOpenAIToolTraceEvents(log);
|
|
2900
|
+
case "unknown":
|
|
2901
|
+
return [];
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
function buildTraceSummary(logs, slowResponseThresholdSeconds, knowledgeCandidateCount = 0) {
|
|
2905
|
+
let failedCallCount = 0;
|
|
2906
|
+
let pendingCallCount = 0;
|
|
2907
|
+
let slowCallCount = 0;
|
|
2908
|
+
let totalInputTokens = 0;
|
|
2909
|
+
let totalOutputTokens = 0;
|
|
2910
|
+
let totalCacheCreationInputTokens = 0;
|
|
2911
|
+
let totalCacheReadInputTokens = 0;
|
|
2912
|
+
let totalElapsedMs = 0;
|
|
2913
|
+
let maxElapsedMs = null;
|
|
2914
|
+
let toolCallCount = 0;
|
|
2915
|
+
for (const log of logs) {
|
|
2916
|
+
if (log.responseStatus === null) {
|
|
2917
|
+
pendingCallCount += 1;
|
|
2918
|
+
} else if (log.responseStatus >= 400) {
|
|
2919
|
+
failedCallCount += 1;
|
|
2920
|
+
}
|
|
2921
|
+
if (log.elapsedMs !== null && slowResponseThresholdSeconds > 0 && log.elapsedMs > slowResponseThresholdSeconds * 1e3) {
|
|
2922
|
+
slowCallCount += 1;
|
|
2923
|
+
}
|
|
2924
|
+
if (log.inputTokens !== null) totalInputTokens += log.inputTokens;
|
|
2925
|
+
if (log.outputTokens !== null) totalOutputTokens += log.outputTokens;
|
|
2926
|
+
if (log.cacheCreationInputTokens !== null) {
|
|
2927
|
+
totalCacheCreationInputTokens += log.cacheCreationInputTokens;
|
|
2928
|
+
}
|
|
2929
|
+
if (log.cacheReadInputTokens !== null) {
|
|
2930
|
+
totalCacheReadInputTokens += log.cacheReadInputTokens;
|
|
2931
|
+
}
|
|
2932
|
+
if (log.elapsedMs !== null) {
|
|
2933
|
+
totalElapsedMs += log.elapsedMs;
|
|
2934
|
+
maxElapsedMs = maxElapsedMs === null ? log.elapsedMs : Math.max(maxElapsedMs, log.elapsedMs);
|
|
2935
|
+
}
|
|
2936
|
+
toolCallCount += extractToolTraceEvents(log).length;
|
|
2937
|
+
}
|
|
2938
|
+
return {
|
|
2939
|
+
llmCallCount: logs.length,
|
|
2940
|
+
toolCallCount,
|
|
2941
|
+
failedCallCount,
|
|
2942
|
+
pendingCallCount,
|
|
2943
|
+
slowCallCount,
|
|
2944
|
+
totalInputTokens,
|
|
2945
|
+
totalOutputTokens,
|
|
2946
|
+
totalCacheCreationInputTokens,
|
|
2947
|
+
totalCacheReadInputTokens,
|
|
2948
|
+
totalElapsedMs,
|
|
2949
|
+
maxElapsedMs,
|
|
2950
|
+
startedAt: logs[0]?.timestamp ?? null,
|
|
2951
|
+
endedAt: logs[logs.length - 1]?.timestamp ?? null,
|
|
2952
|
+
knowledgeCandidateCount
|
|
2953
|
+
};
|
|
2954
|
+
}
|
|
2955
|
+
function formatElapsed$1(ms) {
|
|
2805
2956
|
if (ms < 1e3) return `${ms}ms`;
|
|
2806
2957
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
2807
2958
|
}
|
|
@@ -2871,6 +3022,14 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
2871
3022
|
const EndCrab = reactExports.useMemo(() => getCrabVariant(entries[lastIdx]?.log.id ?? 0), [entries, lastIdx]);
|
|
2872
3023
|
const bgClass = turnIndex % 2 === 0 ? "bg-muted/10" : "bg-muted/25";
|
|
2873
3024
|
const aggregateIsSlow = aggregate.maxElapsed !== null && slowResponseThresholdSeconds > 0 && aggregate.maxElapsed > slowResponseThresholdSeconds * 1e3;
|
|
3025
|
+
const toolEventsByLogId = reactExports.useMemo(() => {
|
|
3026
|
+
const events = /* @__PURE__ */ new Map();
|
|
3027
|
+
for (const entry of entries) {
|
|
3028
|
+
const extracted = extractToolTraceEvents(entry.log);
|
|
3029
|
+
if (extracted.length > 0) events.set(entry.log.id, extracted);
|
|
3030
|
+
}
|
|
3031
|
+
return events;
|
|
3032
|
+
}, [entries]);
|
|
2874
3033
|
const [layoutVersion, setLayoutVersion] = reactExports.useState(0);
|
|
2875
3034
|
const containerRef = reactExports.useRef(null);
|
|
2876
3035
|
reactExports.useEffect(() => {
|
|
@@ -3001,14 +3160,14 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
3001
3160
|
),
|
|
3002
3161
|
children: [
|
|
3003
3162
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
|
|
3004
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed(aggregate.maxElapsed) }),
|
|
3163
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed$1(aggregate.maxElapsed) }),
|
|
3005
3164
|
aggregateIsSlow && /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Slow response" })
|
|
3006
3165
|
]
|
|
3007
3166
|
}
|
|
3008
3167
|
) }),
|
|
3009
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: aggregateIsSlow ? `Slow response: ${formatElapsed(
|
|
3168
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: aggregateIsSlow ? `Slow response: ${formatElapsed$1(
|
|
3010
3169
|
aggregate.maxElapsed
|
|
3011
|
-
)} exceeds ${formatElapsed(slowResponseThresholdSeconds * 1e3)}` : "Slowest request in this turn" })
|
|
3170
|
+
)} exceeds ${formatElapsed$1(slowResponseThresholdSeconds * 1e3)}` : "Slowest request in this turn" })
|
|
3012
3171
|
] }) }),
|
|
3013
3172
|
aggregate.hasTokens && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 shrink-0", children: [
|
|
3014
3173
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
|
|
@@ -3052,23 +3211,204 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
|
|
|
3052
3211
|
onToggle: toggleCollapse
|
|
3053
3212
|
}
|
|
3054
3213
|
),
|
|
3055
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3214
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn("flex-1 min-w-0 mb-0.5 rounded-lg", bgClass), children: [
|
|
3215
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3216
|
+
LogEntry,
|
|
3217
|
+
{
|
|
3218
|
+
log,
|
|
3219
|
+
viewMode,
|
|
3220
|
+
strip,
|
|
3221
|
+
slowResponseThresholdSeconds,
|
|
3222
|
+
cacheTrend: cacheTrends?.get(log.id) ?? null,
|
|
3223
|
+
onCompareWithPrevious: comparisonPredecessors.has(log.id) ? onCompareWithPrevious : void 0
|
|
3224
|
+
}
|
|
3225
|
+
),
|
|
3226
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ToolTraceEvents, { events: toolEventsByLogId.get(log.id) ?? [] })
|
|
3227
|
+
] })
|
|
3066
3228
|
] }, log.id);
|
|
3067
3229
|
})
|
|
3068
3230
|
)
|
|
3069
3231
|
}
|
|
3070
3232
|
);
|
|
3071
3233
|
});
|
|
3234
|
+
const CandidateResponseSchema = object({
|
|
3235
|
+
candidates: array(KnowledgeCandidateSchema)
|
|
3236
|
+
});
|
|
3237
|
+
function formatElapsed(ms) {
|
|
3238
|
+
if (ms === null) return "-";
|
|
3239
|
+
if (ms < 1e3) return `${String(ms)}ms`;
|
|
3240
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
3241
|
+
}
|
|
3242
|
+
function formatTimeRange$1(startedAt, endedAt) {
|
|
3243
|
+
if (startedAt === null || endedAt === null) return null;
|
|
3244
|
+
const format = (iso) => new Date(iso).toLocaleTimeString([], {
|
|
3245
|
+
hour: "2-digit",
|
|
3246
|
+
minute: "2-digit",
|
|
3247
|
+
second: "2-digit"
|
|
3248
|
+
});
|
|
3249
|
+
return `${format(startedAt)} - ${format(endedAt)}`;
|
|
3250
|
+
}
|
|
3251
|
+
function scrollToLog(logId) {
|
|
3252
|
+
const target = document.getElementById(`log-${String(logId)}`);
|
|
3253
|
+
if (!(target instanceof HTMLElement)) return;
|
|
3254
|
+
target.scrollIntoView({ block: "center", behavior: "smooth" });
|
|
3255
|
+
target.focus({ preventScroll: true });
|
|
3256
|
+
if (target.getAttribute("data-nav-action") === "expand") {
|
|
3257
|
+
target.click();
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
function CandidateList({ candidates }) {
|
|
3261
|
+
if (candidates.length === 0) return null;
|
|
3262
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 grid gap-1.5", children: candidates.map((candidate) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3263
|
+
"div",
|
|
3264
|
+
{
|
|
3265
|
+
className: "rounded-md border border-border/80 bg-background/60 px-2.5 py-2",
|
|
3266
|
+
children: [
|
|
3267
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
3268
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "h-5 px-1.5 text-[10px] font-mono", children: candidate.type }),
|
|
3269
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1 truncate text-xs font-medium", title: candidate.title, children: candidate.title }),
|
|
3270
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 font-mono text-[10px] text-muted-foreground", children: candidate.status })
|
|
3271
|
+
] }),
|
|
3272
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 flex flex-wrap items-center gap-1.5", children: candidate.logIds.map((logId) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3273
|
+
"button",
|
|
3274
|
+
{
|
|
3275
|
+
type: "button",
|
|
3276
|
+
onClick: () => scrollToLog(logId),
|
|
3277
|
+
className: "rounded border border-border px-1.5 py-0.5 font-mono text-[10px] text-blue-400 transition-colors hover:bg-muted hover:text-blue-300",
|
|
3278
|
+
children: [
|
|
3279
|
+
"#",
|
|
3280
|
+
logId
|
|
3281
|
+
]
|
|
3282
|
+
},
|
|
3283
|
+
logId
|
|
3284
|
+
)) })
|
|
3285
|
+
]
|
|
3286
|
+
},
|
|
3287
|
+
candidate.id
|
|
3288
|
+
)) });
|
|
3289
|
+
}
|
|
3290
|
+
function AgentTraceSummary({
|
|
3291
|
+
logs,
|
|
3292
|
+
scopeId,
|
|
3293
|
+
slowResponseThresholdSeconds
|
|
3294
|
+
}) {
|
|
3295
|
+
const [candidates, setCandidates] = reactExports.useState([]);
|
|
3296
|
+
const [candidateState, setCandidateState] = reactExports.useState({
|
|
3297
|
+
status: "idle",
|
|
3298
|
+
error: null
|
|
3299
|
+
});
|
|
3300
|
+
const summary = reactExports.useMemo(
|
|
3301
|
+
() => buildTraceSummary(logs, slowResponseThresholdSeconds, candidates.length),
|
|
3302
|
+
[candidates.length, logs, slowResponseThresholdSeconds]
|
|
3303
|
+
);
|
|
3304
|
+
const timeRange = reactExports.useMemo(
|
|
3305
|
+
() => formatTimeRange$1(summary.startedAt, summary.endedAt),
|
|
3306
|
+
[summary.endedAt, summary.startedAt]
|
|
3307
|
+
);
|
|
3308
|
+
const createCandidates = reactExports.useCallback(() => {
|
|
3309
|
+
if (logs.length === 0 || candidateState.status === "loading") return;
|
|
3310
|
+
setCandidateState({ status: "loading", error: null });
|
|
3311
|
+
void (async () => {
|
|
3312
|
+
try {
|
|
3313
|
+
const response = await fetch(
|
|
3314
|
+
`/api/knowledge/sessions/${encodeURIComponent(scopeId)}/candidates`,
|
|
3315
|
+
{ method: "POST" }
|
|
3316
|
+
);
|
|
3317
|
+
if (!response.ok) {
|
|
3318
|
+
const message = await readApiError(
|
|
3319
|
+
response,
|
|
3320
|
+
`Candidate generation failed with ${String(response.status)}`
|
|
3321
|
+
);
|
|
3322
|
+
setCandidateState({ status: "failed", error: message });
|
|
3323
|
+
return;
|
|
3324
|
+
}
|
|
3325
|
+
const parsed = await parseJsonResponse$1(response, CandidateResponseSchema);
|
|
3326
|
+
setCandidates(parsed.candidates);
|
|
3327
|
+
setCandidateState({ status: "ready", error: null });
|
|
3328
|
+
} catch (error) {
|
|
3329
|
+
setCandidateState({
|
|
3330
|
+
status: "failed",
|
|
3331
|
+
error: error instanceof Error ? error.message : "Candidate response was invalid"
|
|
3332
|
+
});
|
|
3333
|
+
}
|
|
3334
|
+
})();
|
|
3335
|
+
}, [candidateState.status, logs.length, scopeId]);
|
|
3336
|
+
if (logs.length === 0) return null;
|
|
3337
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "mb-2 rounded-lg border border-border bg-muted/10 px-3 py-2", children: [
|
|
3338
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 text-xs", children: [
|
|
3339
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5 font-semibold text-foreground", children: [
|
|
3340
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3.5 text-blue-400" }),
|
|
3341
|
+
summary.llmCallCount,
|
|
3342
|
+
" LLM"
|
|
3343
|
+
] }),
|
|
3344
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5 text-muted-foreground", children: [
|
|
3345
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3.5 text-amber-400" }),
|
|
3346
|
+
summary.toolCallCount,
|
|
3347
|
+
" tools"
|
|
3348
|
+
] }),
|
|
3349
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5 text-muted-foreground", children: [
|
|
3350
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3.5 text-emerald-400" }),
|
|
3351
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono", children: [
|
|
3352
|
+
formatTokens(summary.totalInputTokens),
|
|
3353
|
+
" / ",
|
|
3354
|
+
formatTokens(summary.totalOutputTokens)
|
|
3355
|
+
] })
|
|
3356
|
+
] }),
|
|
3357
|
+
(summary.totalCacheCreationInputTokens > 0 || summary.totalCacheReadInputTokens > 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5 text-muted-foreground", children: [
|
|
3358
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3.5 text-purple-400" }),
|
|
3359
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono", children: [
|
|
3360
|
+
"+",
|
|
3361
|
+
formatTokens(summary.totalCacheCreationInputTokens),
|
|
3362
|
+
" / ~",
|
|
3363
|
+
formatTokens(summary.totalCacheReadInputTokens)
|
|
3364
|
+
] })
|
|
3365
|
+
] }),
|
|
3366
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5 text-muted-foreground", children: [
|
|
3367
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3.5" }),
|
|
3368
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: formatElapsed(summary.totalElapsedMs) }),
|
|
3369
|
+
summary.maxElapsedMs !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-muted-foreground/70", children: [
|
|
3370
|
+
"max ",
|
|
3371
|
+
formatElapsed(summary.maxElapsedMs)
|
|
3372
|
+
] })
|
|
3373
|
+
] }),
|
|
3374
|
+
timeRange !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-muted-foreground/70", children: timeRange }),
|
|
3375
|
+
(summary.failedCallCount > 0 || summary.pendingCallCount > 0 || summary.slowCallCount > 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5 text-amber-400", children: [
|
|
3376
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3.5" }),
|
|
3377
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono", children: [
|
|
3378
|
+
summary.failedCallCount,
|
|
3379
|
+
" fail / ",
|
|
3380
|
+
summary.pendingCallCount,
|
|
3381
|
+
" pending /",
|
|
3382
|
+
" ",
|
|
3383
|
+
summary.slowCallCount,
|
|
3384
|
+
" slow"
|
|
3385
|
+
] })
|
|
3386
|
+
] }),
|
|
3387
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1" }),
|
|
3388
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Badge, { variant: "outline", className: "h-6 px-2 text-[10px] font-mono", children: [
|
|
3389
|
+
summary.knowledgeCandidateCount,
|
|
3390
|
+
" memory"
|
|
3391
|
+
] }),
|
|
3392
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3393
|
+
Button,
|
|
3394
|
+
{
|
|
3395
|
+
type: "button",
|
|
3396
|
+
variant: "outline",
|
|
3397
|
+
size: "sm",
|
|
3398
|
+
className: "h-7 gap-1.5 px-2 text-xs",
|
|
3399
|
+
onClick: createCandidates,
|
|
3400
|
+
disabled: candidateState.status === "loading",
|
|
3401
|
+
children: [
|
|
3402
|
+
candidateState.status === "loading" ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Brain, { className: "size-3.5" }),
|
|
3403
|
+
"Candidate"
|
|
3404
|
+
]
|
|
3405
|
+
}
|
|
3406
|
+
)
|
|
3407
|
+
] }),
|
|
3408
|
+
candidateState.status === "failed" && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-2 text-xs text-destructive", children: candidateState.error }),
|
|
3409
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CandidateList, { candidates })
|
|
3410
|
+
] });
|
|
3411
|
+
}
|
|
3072
3412
|
function computeStats(logs) {
|
|
3073
3413
|
let totalInput = 0;
|
|
3074
3414
|
let totalOutput = 0;
|
|
@@ -3115,20 +3455,30 @@ const ConversationGroup = reactExports.memo(function({
|
|
|
3115
3455
|
onClear: () => onClearGroup(group.logs.map((l) => l.id))
|
|
3116
3456
|
}
|
|
3117
3457
|
),
|
|
3118
|
-
shouldRenderConversationContent(standalone, expanded) && /* @__PURE__ */ jsxRuntimeExports.
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3458
|
+
shouldRenderConversationContent(standalone, expanded) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
3459
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3460
|
+
AgentTraceSummary,
|
|
3461
|
+
{
|
|
3462
|
+
logs: group.logs,
|
|
3463
|
+
scopeId: group.conversationId,
|
|
3464
|
+
slowResponseThresholdSeconds
|
|
3465
|
+
}
|
|
3466
|
+
),
|
|
3467
|
+
turnGroups.map((tg) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3468
|
+
TurnGroup,
|
|
3469
|
+
{
|
|
3470
|
+
entries: tg.entries,
|
|
3471
|
+
viewMode,
|
|
3472
|
+
strip,
|
|
3473
|
+
slowResponseThresholdSeconds,
|
|
3474
|
+
cacheTrends,
|
|
3475
|
+
onCompareWithPrevious,
|
|
3476
|
+
comparisonPredecessors,
|
|
3477
|
+
turnIndex: tg.turnIndex
|
|
3478
|
+
},
|
|
3479
|
+
tg.turnIndex
|
|
3480
|
+
))
|
|
3481
|
+
] })
|
|
3132
3482
|
] });
|
|
3133
3483
|
});
|
|
3134
3484
|
function CrabLogo({ className }) {
|
|
@@ -3798,26 +4148,6 @@ function ProviderCard({
|
|
|
3798
4148
|
const [showApiKey, setShowApiKey] = reactExports.useState(false);
|
|
3799
4149
|
const [copied, setCopied] = reactExports.useState(false);
|
|
3800
4150
|
const [showModelResults, setShowModelResults] = reactExports.useState(false);
|
|
3801
|
-
const hasLoggedRef = reactExports.useRef(null);
|
|
3802
|
-
const lastTestedAtRef = reactExports.useRef(void 0);
|
|
3803
|
-
if (testResults?.testedAt !== void 0 && testResults.testedAt !== lastTestedAtRef.current) {
|
|
3804
|
-
lastTestedAtRef.current = testResults.testedAt;
|
|
3805
|
-
hasLoggedRef.current = null;
|
|
3806
|
-
}
|
|
3807
|
-
const handleToggleModelResults = reactExports.useCallback(() => {
|
|
3808
|
-
setShowModelResults((v) => {
|
|
3809
|
-
const next = !v;
|
|
3810
|
-
if (next && hasLoggedRef.current === null && testResults?.models !== void 0) {
|
|
3811
|
-
hasLoggedRef.current = testResults.testedAt ?? "";
|
|
3812
|
-
void fetch(`/api/providers/${provider.id}/test/log`, {
|
|
3813
|
-
method: "POST",
|
|
3814
|
-
headers: { "Content-Type": "application/json" },
|
|
3815
|
-
body: JSON.stringify(testResults)
|
|
3816
|
-
});
|
|
3817
|
-
}
|
|
3818
|
-
return next;
|
|
3819
|
-
});
|
|
3820
|
-
}, [provider.id, testResults]);
|
|
3821
4151
|
function handleCopy() {
|
|
3822
4152
|
navigator.clipboard.writeText(provider.apiKey).catch(() => {
|
|
3823
4153
|
});
|
|
@@ -3911,7 +4241,7 @@ function ProviderCard({
|
|
|
3911
4241
|
"button",
|
|
3912
4242
|
{
|
|
3913
4243
|
type: "button",
|
|
3914
|
-
onClick:
|
|
4244
|
+
onClick: () => setShowModelResults((value) => !value),
|
|
3915
4245
|
className: "text-xs text-muted-foreground hover:text-foreground transition-colors flex items-center gap-1",
|
|
3916
4246
|
children: [
|
|
3917
4247
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: showModelResults ? "▾" : "▸" }),
|
|
@@ -4429,6 +4759,19 @@ function createProviderPayload(data) {
|
|
|
4429
4759
|
source: data.source
|
|
4430
4760
|
};
|
|
4431
4761
|
}
|
|
4762
|
+
async function persistProviderTestLog(providerId, results) {
|
|
4763
|
+
if (results.models === void 0) {
|
|
4764
|
+
return;
|
|
4765
|
+
}
|
|
4766
|
+
try {
|
|
4767
|
+
await fetch(`/api/providers/${providerId}/test/log`, {
|
|
4768
|
+
method: "POST",
|
|
4769
|
+
headers: { "Content-Type": "application/json" },
|
|
4770
|
+
body: JSON.stringify(results)
|
|
4771
|
+
});
|
|
4772
|
+
} catch {
|
|
4773
|
+
}
|
|
4774
|
+
}
|
|
4432
4775
|
function ProvidersPanel({
|
|
4433
4776
|
externalProviders,
|
|
4434
4777
|
isLoading = false,
|
|
@@ -4487,7 +4830,7 @@ function ProvidersPanel({
|
|
|
4487
4830
|
try {
|
|
4488
4831
|
const res = await fetch("/api/config/paths");
|
|
4489
4832
|
if (res.ok) {
|
|
4490
|
-
const data = await parseJsonResponse(res, ConfigPathsResponseSchema);
|
|
4833
|
+
const data = await parseJsonResponse$1(res, ConfigPathsResponseSchema);
|
|
4491
4834
|
setConfigPath(data.providerConfig);
|
|
4492
4835
|
}
|
|
4493
4836
|
} catch {
|
|
@@ -4566,8 +4909,9 @@ function ProvidersPanel({
|
|
|
4566
4909
|
signal: controller.signal
|
|
4567
4910
|
});
|
|
4568
4911
|
if (res.ok) {
|
|
4569
|
-
const results = await parseJsonResponse(res, ProviderTestResultsSchema);
|
|
4912
|
+
const results = await parseJsonResponse$1(res, ProviderTestResultsSchema);
|
|
4570
4913
|
updateTestResults(providerId, results);
|
|
4914
|
+
await persistProviderTestLog(providerId, results);
|
|
4571
4915
|
} else {
|
|
4572
4916
|
updateTestResults(
|
|
4573
4917
|
providerId,
|
|
@@ -4605,7 +4949,7 @@ function ProvidersPanel({
|
|
|
4605
4949
|
setError(await readApiError(res, "Failed to add provider"));
|
|
4606
4950
|
return;
|
|
4607
4951
|
}
|
|
4608
|
-
const newProvider = await parseJsonResponse(res, ProviderConfigSchema);
|
|
4952
|
+
const newProvider = await parseJsonResponse$1(res, ProviderConfigSchema);
|
|
4609
4953
|
setShowForm(false);
|
|
4610
4954
|
triggerHighlight(newProvider.id);
|
|
4611
4955
|
refreshProviders();
|
|
@@ -4628,7 +4972,7 @@ function ProvidersPanel({
|
|
|
4628
4972
|
setError(await readApiError(res, "Failed to update provider"));
|
|
4629
4973
|
return;
|
|
4630
4974
|
}
|
|
4631
|
-
const updated = await parseJsonResponse(res, ProviderConfigSchema);
|
|
4975
|
+
const updated = await parseJsonResponse$1(res, ProviderConfigSchema);
|
|
4632
4976
|
setEditingProvider(void 0);
|
|
4633
4977
|
triggerHighlight(updated.id);
|
|
4634
4978
|
refreshProviders();
|
|
@@ -4703,7 +5047,7 @@ function ProvidersPanel({
|
|
|
4703
5047
|
headers: { "Content-Type": "application/json" },
|
|
4704
5048
|
body: JSON.stringify(text)
|
|
4705
5049
|
});
|
|
4706
|
-
const data = await parseJsonResponse(res, ImportResponseSchema);
|
|
5050
|
+
const data = await parseJsonResponse$1(res, ImportResponseSchema);
|
|
4707
5051
|
if (res.ok && data.imported !== void 0 && data.imported > 0) {
|
|
4708
5052
|
refreshProviders();
|
|
4709
5053
|
setError(null);
|