@copilotz/admin 0.9.39 → 0.9.40
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/dist/index.cjs +230 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.js +231 -27
- package/dist/index.js.map +1 -1
- package/dist/styles.css +39 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -313,6 +313,14 @@ function createAdminClient(options = {}) {
|
|
|
313
313
|
kind: filters.kind === "all" ? void 0 : filters.kind,
|
|
314
314
|
status: filters.status === "all" ? void 0 : filters.status,
|
|
315
315
|
search: filters.search,
|
|
316
|
+
searchMode: filters.searchMode,
|
|
317
|
+
focusNodeId: filters.focusNodeId,
|
|
318
|
+
includeRelated: filters.includeRelated ? "true" : void 0,
|
|
319
|
+
includeSimilar: filters.includeSimilar ? "true" : void 0,
|
|
320
|
+
similarLimit: filters.similarLimit ? String(filters.similarLimit) : void 0,
|
|
321
|
+
minSimilarity: typeof filters.minSimilarity === "number" ? String(filters.minSimilarity) : void 0,
|
|
322
|
+
relationDepth: filters.relationDepth ? String(filters.relationDepth) : void 0,
|
|
323
|
+
relationTypes: filters.relationTypes?.join(","),
|
|
316
324
|
limit: String(filters.limit ?? 160),
|
|
317
325
|
offset: filters.offset ? String(filters.offset) : void 0
|
|
318
326
|
}),
|
|
@@ -2023,6 +2031,7 @@ var import_react3 = __toESM(require("react"), 1);
|
|
|
2023
2031
|
var import_lucide_react7 = require("lucide-react");
|
|
2024
2032
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2025
2033
|
var BRAIN_LAYERS = ["all", "knowledge", "working"];
|
|
2034
|
+
var BRAIN_SEARCH_MODES = ["hybrid", "semantic", "keyword"];
|
|
2026
2035
|
var BRAIN_STATUSES = ["active", "all", "superseded", "archived"];
|
|
2027
2036
|
var BRAIN_KINDS = [
|
|
2028
2037
|
"all",
|
|
@@ -2060,6 +2069,9 @@ function brainModule() {
|
|
|
2060
2069
|
}
|
|
2061
2070
|
function BrainPage({ context }) {
|
|
2062
2071
|
const [search, setSearch] = import_react3.default.useState("");
|
|
2072
|
+
const [searchMode, setSearchMode] = import_react3.default.useState(
|
|
2073
|
+
"hybrid"
|
|
2074
|
+
);
|
|
2063
2075
|
const [layer, setLayer] = import_react3.default.useState("all");
|
|
2064
2076
|
const [status, setStatus] = import_react3.default.useState(
|
|
2065
2077
|
"active"
|
|
@@ -2072,24 +2084,32 @@ function BrainPage({ context }) {
|
|
|
2072
2084
|
const [selectedNode, setSelectedNode] = import_react3.default.useState(
|
|
2073
2085
|
null
|
|
2074
2086
|
);
|
|
2087
|
+
const [focusNodeId, setFocusNodeId] = import_react3.default.useState(null);
|
|
2075
2088
|
const [loading, setLoading] = import_react3.default.useState(false);
|
|
2076
2089
|
const [error, setError] = import_react3.default.useState(null);
|
|
2077
|
-
const loadBrain = import_react3.default.useCallback(async () => {
|
|
2090
|
+
const loadBrain = import_react3.default.useCallback(async (focusOverride) => {
|
|
2078
2091
|
setLoading(true);
|
|
2079
2092
|
setError(null);
|
|
2093
|
+
const effectiveFocusNodeId = focusOverride === void 0 ? focusNodeId : focusOverride;
|
|
2080
2094
|
try {
|
|
2081
2095
|
const next = await context.client.getBrain({
|
|
2082
2096
|
namespace: context.scope.namespace || void 0,
|
|
2083
2097
|
search: search.trim() || void 0,
|
|
2098
|
+
searchMode,
|
|
2084
2099
|
layer,
|
|
2085
2100
|
status,
|
|
2086
2101
|
kind,
|
|
2087
2102
|
agentId: agentId.trim() || void 0,
|
|
2103
|
+
focusNodeId: effectiveFocusNodeId || void 0,
|
|
2104
|
+
includeRelated: Boolean(effectiveFocusNodeId),
|
|
2105
|
+
includeSimilar: Boolean(effectiveFocusNodeId),
|
|
2106
|
+
similarLimit: 24,
|
|
2107
|
+
minSimilarity: 0.2,
|
|
2088
2108
|
limit: 180
|
|
2089
2109
|
});
|
|
2090
2110
|
setResponse(next);
|
|
2091
2111
|
setSelectedNode(
|
|
2092
|
-
(current) => current && next.nodes.some((node) => node.id === current.id) ? current : next.nodes[0] ?? null
|
|
2112
|
+
(current) => effectiveFocusNodeId ? next.nodes.find((node) => node.id === effectiveFocusNodeId) ?? current : current && next.nodes.some((node) => node.id === current.id) ? next.nodes.find((node) => node.id === current.id) ?? current : next.nodes[0] ?? null
|
|
2093
2113
|
);
|
|
2094
2114
|
} catch (cause) {
|
|
2095
2115
|
setError(cause instanceof Error ? cause.message : "Failed to load brain");
|
|
@@ -2102,17 +2122,30 @@ function BrainPage({ context }) {
|
|
|
2102
2122
|
agentId,
|
|
2103
2123
|
context.client,
|
|
2104
2124
|
context.scope.namespace,
|
|
2125
|
+
focusNodeId,
|
|
2105
2126
|
kind,
|
|
2106
2127
|
layer,
|
|
2107
2128
|
search,
|
|
2129
|
+
searchMode,
|
|
2108
2130
|
status
|
|
2109
2131
|
]);
|
|
2110
2132
|
import_react3.default.useEffect(() => {
|
|
2111
2133
|
void loadBrain();
|
|
2112
|
-
}, [context.refreshKey, context.scope.namespace, loadBrain]);
|
|
2134
|
+
}, [context.refreshKey, context.scope.namespace, focusNodeId, loadBrain]);
|
|
2113
2135
|
const data = response ?? emptyBrainResponse();
|
|
2136
|
+
const matches = data.matches ?? {};
|
|
2137
|
+
const related = data.related ?? [];
|
|
2138
|
+
const similar = data.similar ?? [];
|
|
2114
2139
|
const knowledgeCount = data.stats.byLayer.knowledge ?? 0;
|
|
2115
2140
|
const workingCount = data.stats.byLayer.working ?? 0;
|
|
2141
|
+
const selectNode = import_react3.default.useCallback((node) => {
|
|
2142
|
+
setSelectedNode(node);
|
|
2143
|
+
setFocusNodeId(node.id);
|
|
2144
|
+
}, []);
|
|
2145
|
+
const runSearch = import_react3.default.useCallback(() => {
|
|
2146
|
+
setFocusNodeId(null);
|
|
2147
|
+
void loadBrain(null);
|
|
2148
|
+
}, [loadBrain]);
|
|
2116
2149
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-4", children: [
|
|
2117
2150
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2118
2151
|
PageHeader,
|
|
@@ -2179,7 +2212,7 @@ function BrainPage({ context }) {
|
|
|
2179
2212
|
Button,
|
|
2180
2213
|
{
|
|
2181
2214
|
disabled: loading,
|
|
2182
|
-
onClick:
|
|
2215
|
+
onClick: runSearch,
|
|
2183
2216
|
size: "sm",
|
|
2184
2217
|
type: "button",
|
|
2185
2218
|
children: [
|
|
@@ -2192,6 +2225,19 @@ function BrainPage({ context }) {
|
|
|
2192
2225
|
searchPlaceholder: "Search brain",
|
|
2193
2226
|
searchValue: search,
|
|
2194
2227
|
children: [
|
|
2228
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "inline-flex h-8 overflow-hidden rounded-md border bg-background", children: BRAIN_SEARCH_MODES.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2229
|
+
"button",
|
|
2230
|
+
{
|
|
2231
|
+
className: cn(
|
|
2232
|
+
"px-3 text-xs transition-colors",
|
|
2233
|
+
searchMode === mode ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted"
|
|
2234
|
+
),
|
|
2235
|
+
onClick: () => setSearchMode(mode),
|
|
2236
|
+
type: "button",
|
|
2237
|
+
children: formatLabel(mode)
|
|
2238
|
+
},
|
|
2239
|
+
mode
|
|
2240
|
+
)) }),
|
|
2195
2241
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2196
2242
|
Select,
|
|
2197
2243
|
{
|
|
@@ -2231,7 +2277,7 @@ function BrainPage({ context }) {
|
|
|
2231
2277
|
className: "h-8 w-[190px]",
|
|
2232
2278
|
onChange: (event) => setAgentId(event.target.value),
|
|
2233
2279
|
onKeyDown: (event) => {
|
|
2234
|
-
if (event.key === "Enter")
|
|
2280
|
+
if (event.key === "Enter") runSearch();
|
|
2235
2281
|
},
|
|
2236
2282
|
placeholder: "Agent ID",
|
|
2237
2283
|
value: agentId
|
|
@@ -2240,10 +2286,23 @@ function BrainPage({ context }) {
|
|
|
2240
2286
|
]
|
|
2241
2287
|
}
|
|
2242
2288
|
),
|
|
2289
|
+
data.semantic?.requested && data.semantic.error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: [
|
|
2290
|
+
"Semantic search unavailable: ",
|
|
2291
|
+
data.semantic.error
|
|
2292
|
+
] }) : null,
|
|
2243
2293
|
error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EmptyState, { title: "Unable to load brain", description: error }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2244
2294
|
InspectorPanel,
|
|
2245
2295
|
{
|
|
2246
|
-
side: selectedNode ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2296
|
+
side: selectedNode ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2297
|
+
BrainNodeInspector,
|
|
2298
|
+
{
|
|
2299
|
+
match: matches[selectedNode.id],
|
|
2300
|
+
node: selectedNode,
|
|
2301
|
+
onSelectNode: selectNode,
|
|
2302
|
+
related,
|
|
2303
|
+
similar
|
|
2304
|
+
}
|
|
2305
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2247
2306
|
EmptyState,
|
|
2248
2307
|
{
|
|
2249
2308
|
icon: import_lucide_react7.Brain,
|
|
@@ -2259,7 +2318,8 @@ function BrainPage({ context }) {
|
|
|
2259
2318
|
edges: data.edges,
|
|
2260
2319
|
loading,
|
|
2261
2320
|
nodes: data.nodes,
|
|
2262
|
-
onSelectNode:
|
|
2321
|
+
onSelectNode: selectNode,
|
|
2322
|
+
similar,
|
|
2263
2323
|
selectedNodeId: selectedNode?.id ?? null
|
|
2264
2324
|
}
|
|
2265
2325
|
),
|
|
@@ -2268,7 +2328,7 @@ function BrainPage({ context }) {
|
|
|
2268
2328
|
{
|
|
2269
2329
|
rows: data.nodes,
|
|
2270
2330
|
getRowKey: (row) => row.id,
|
|
2271
|
-
onRowClick:
|
|
2331
|
+
onRowClick: selectNode,
|
|
2272
2332
|
empty: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2273
2333
|
EmptyState,
|
|
2274
2334
|
{
|
|
@@ -2284,7 +2344,8 @@ function BrainPage({ context }) {
|
|
|
2284
2344
|
className: "max-w-[360px]",
|
|
2285
2345
|
render: (row) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "min-w-0", children: [
|
|
2286
2346
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "truncate font-medium", children: row.name }),
|
|
2287
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "truncate text-xs text-muted-foreground", children: row.content || "-" })
|
|
2347
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "truncate text-xs text-muted-foreground", children: row.content || "-" }),
|
|
2348
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MatchBadges, { match: matches[row.id] })
|
|
2288
2349
|
] })
|
|
2289
2350
|
},
|
|
2290
2351
|
{
|
|
@@ -2322,6 +2383,7 @@ function BrainMap({
|
|
|
2322
2383
|
loading,
|
|
2323
2384
|
nodes,
|
|
2324
2385
|
onSelectNode,
|
|
2386
|
+
similar,
|
|
2325
2387
|
selectedNodeId
|
|
2326
2388
|
}) {
|
|
2327
2389
|
const nodeById = import_react3.default.useMemo(
|
|
@@ -2374,12 +2436,15 @@ function BrainMap({
|
|
|
2374
2436
|
const source = nodeById.get(edge.sourceNodeId);
|
|
2375
2437
|
const target = nodeById.get(edge.targetNodeId);
|
|
2376
2438
|
if (!source || !target) return null;
|
|
2439
|
+
const isSelectedEdge = Boolean(
|
|
2440
|
+
selectedNodeId && (edge.sourceNodeId === selectedNodeId || edge.targetNodeId === selectedNodeId)
|
|
2441
|
+
);
|
|
2377
2442
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2378
2443
|
"line",
|
|
2379
2444
|
{
|
|
2380
2445
|
stroke: edge.type === "contradicts" ? "#dc2626" : "#64748b",
|
|
2381
|
-
strokeOpacity: "0.32",
|
|
2382
|
-
strokeWidth: edge.type === "supports" ? 2 : 1.3,
|
|
2446
|
+
strokeOpacity: isSelectedEdge ? "0.75" : "0.32",
|
|
2447
|
+
strokeWidth: isSelectedEdge ? 2.6 : edge.type === "supports" ? 2 : 1.3,
|
|
2383
2448
|
x1: source.x * 1e3,
|
|
2384
2449
|
x2: target.x * 1e3,
|
|
2385
2450
|
y1: source.y * 600,
|
|
@@ -2388,6 +2453,25 @@ function BrainMap({
|
|
|
2388
2453
|
edge.id
|
|
2389
2454
|
);
|
|
2390
2455
|
}),
|
|
2456
|
+
selectedNodeId ? similar.map((item) => {
|
|
2457
|
+
const source = nodeById.get(selectedNodeId);
|
|
2458
|
+
const target = nodeById.get(item.node.id);
|
|
2459
|
+
if (!source || !target) return null;
|
|
2460
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2461
|
+
"line",
|
|
2462
|
+
{
|
|
2463
|
+
stroke: "#0ea5e9",
|
|
2464
|
+
strokeDasharray: "5 6",
|
|
2465
|
+
strokeOpacity: "0.42",
|
|
2466
|
+
strokeWidth: "1.8",
|
|
2467
|
+
x1: source.x * 1e3,
|
|
2468
|
+
x2: target.x * 1e3,
|
|
2469
|
+
y1: source.y * 600,
|
|
2470
|
+
y2: target.y * 600
|
|
2471
|
+
},
|
|
2472
|
+
`similar-${item.node.id}`
|
|
2473
|
+
);
|
|
2474
|
+
}) : null,
|
|
2391
2475
|
nodes.map((node) => {
|
|
2392
2476
|
const isSelected = node.id === selectedNodeId;
|
|
2393
2477
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
@@ -2415,7 +2499,14 @@ function BrainMap({
|
|
|
2415
2499
|
}
|
|
2416
2500
|
) });
|
|
2417
2501
|
}
|
|
2418
|
-
function BrainNodeInspector({
|
|
2502
|
+
function BrainNodeInspector({
|
|
2503
|
+
match,
|
|
2504
|
+
node,
|
|
2505
|
+
onSelectNode,
|
|
2506
|
+
related,
|
|
2507
|
+
similar
|
|
2508
|
+
}) {
|
|
2509
|
+
const [tab, setTab] = import_react3.default.useState("overview");
|
|
2419
2510
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-3", children: [
|
|
2420
2511
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "rounded-lg border bg-background p-4", children: [
|
|
2421
2512
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
@@ -2425,24 +2516,122 @@ function BrainNodeInspector({ node }) {
|
|
|
2425
2516
|
] }),
|
|
2426
2517
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { className: "mt-3 text-base font-semibold", children: node.name }),
|
|
2427
2518
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "mt-2 text-sm leading-6 text-muted-foreground", children: node.content || "-" }),
|
|
2428
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.
|
|
2429
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Agent", value: node.agentId }),
|
|
2430
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Thread", value: node.threadId }),
|
|
2431
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Memory space", value: node.memorySpaceId }),
|
|
2432
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Checkpoint", value: node.checkpointId }),
|
|
2433
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Source field", value: node.sourceField }),
|
|
2434
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2435
|
-
InspectorRow,
|
|
2436
|
-
{
|
|
2437
|
-
label: "Updated",
|
|
2438
|
-
value: formatDateTime(node.updatedAt)
|
|
2439
|
-
}
|
|
2440
|
-
)
|
|
2441
|
-
] })
|
|
2519
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MatchBadges, { match })
|
|
2442
2520
|
] }),
|
|
2443
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2521
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "inline-flex w-full overflow-hidden rounded-md border bg-background", children: ["overview", "related", "similar", "evidence", "json"].map((item) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2522
|
+
"button",
|
|
2523
|
+
{
|
|
2524
|
+
className: cn(
|
|
2525
|
+
"min-w-0 flex-1 px-2 py-2 text-xs transition-colors",
|
|
2526
|
+
tab === item ? "bg-muted font-medium text-foreground" : "text-muted-foreground hover:bg-muted/60"
|
|
2527
|
+
),
|
|
2528
|
+
onClick: () => setTab(item),
|
|
2529
|
+
type: "button",
|
|
2530
|
+
children: formatLabel(item)
|
|
2531
|
+
},
|
|
2532
|
+
item
|
|
2533
|
+
)) }),
|
|
2534
|
+
tab === "overview" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(BrainOverview, { node }) : null,
|
|
2535
|
+
tab === "related" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RelatedPanel, { onSelectNode, related }) : null,
|
|
2536
|
+
tab === "similar" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SimilarPanel, { onSelectNode, similar }) : null,
|
|
2537
|
+
tab === "evidence" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EvidencePanel, { node }) : null,
|
|
2538
|
+
tab === "json" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(JsonPanel, { title: "Node JSON", value: node, minHeight: 300 }) : null
|
|
2444
2539
|
] });
|
|
2445
2540
|
}
|
|
2541
|
+
function BrainOverview({ node }) {
|
|
2542
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "rounded-lg border bg-background p-4", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("dl", { className: "grid gap-2 text-xs", children: [
|
|
2543
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Agent", value: node.agentId }),
|
|
2544
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Thread", value: node.threadId }),
|
|
2545
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Memory space", value: node.memorySpaceId }),
|
|
2546
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Checkpoint", value: node.checkpointId }),
|
|
2547
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Source field", value: node.sourceField }),
|
|
2548
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Confidence", value: formatNullableNumber(node.confidence) }),
|
|
2549
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Updated", value: formatDateTime(node.updatedAt) })
|
|
2550
|
+
] }) });
|
|
2551
|
+
}
|
|
2552
|
+
function RelatedPanel({
|
|
2553
|
+
onSelectNode,
|
|
2554
|
+
related
|
|
2555
|
+
}) {
|
|
2556
|
+
if (related.length === 0) {
|
|
2557
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2558
|
+
EmptyState,
|
|
2559
|
+
{
|
|
2560
|
+
icon: import_lucide_react7.GitBranch,
|
|
2561
|
+
title: "No explicit relations",
|
|
2562
|
+
description: "Relation edges will appear here when this node is connected to other concepts."
|
|
2563
|
+
}
|
|
2564
|
+
);
|
|
2565
|
+
}
|
|
2566
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "space-y-2", children: related.map((item) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2567
|
+
"button",
|
|
2568
|
+
{
|
|
2569
|
+
className: "w-full rounded-lg border bg-background p-3 text-left transition-colors hover:bg-muted/40",
|
|
2570
|
+
onClick: () => onSelectNode(item.node),
|
|
2571
|
+
type: "button",
|
|
2572
|
+
children: [
|
|
2573
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
2574
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Badge, { variant: "outline", children: formatLabel(item.edge.type) }),
|
|
2575
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Badge, { variant: "secondary", children: item.direction === "out" ? "Outgoing" : "Incoming" })
|
|
2576
|
+
] }),
|
|
2577
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-2 text-sm font-medium", children: item.node.name }),
|
|
2578
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "mt-1 line-clamp-3 text-xs leading-5 text-muted-foreground", children: item.node.content || "-" })
|
|
2579
|
+
]
|
|
2580
|
+
},
|
|
2581
|
+
item.edge.id
|
|
2582
|
+
)) });
|
|
2583
|
+
}
|
|
2584
|
+
function SimilarPanel({
|
|
2585
|
+
onSelectNode,
|
|
2586
|
+
similar
|
|
2587
|
+
}) {
|
|
2588
|
+
if (similar.length === 0) {
|
|
2589
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2590
|
+
EmptyState,
|
|
2591
|
+
{
|
|
2592
|
+
icon: import_lucide_react7.Sparkles,
|
|
2593
|
+
title: "No semantic neighbors",
|
|
2594
|
+
description: "Similar nodes appear here when the selected node has an embedding."
|
|
2595
|
+
}
|
|
2596
|
+
);
|
|
2597
|
+
}
|
|
2598
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "space-y-2", children: similar.map((item) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2599
|
+
"button",
|
|
2600
|
+
{
|
|
2601
|
+
className: "w-full rounded-lg border bg-background p-3 text-left transition-colors hover:bg-muted/40",
|
|
2602
|
+
onClick: () => onSelectNode(item.node),
|
|
2603
|
+
type: "button",
|
|
2604
|
+
children: [
|
|
2605
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
2606
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Badge, { variant: "secondary", children: formatSimilarityScore(item.similarity) }),
|
|
2607
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LayerBadge, { layer: item.node.layer }),
|
|
2608
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Badge, { variant: "outline", children: formatLabel(item.node.kind) })
|
|
2609
|
+
] }),
|
|
2610
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-2 text-sm font-medium", children: item.node.name }),
|
|
2611
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "mt-1 line-clamp-3 text-xs leading-5 text-muted-foreground", children: item.node.content || "-" })
|
|
2612
|
+
]
|
|
2613
|
+
},
|
|
2614
|
+
item.node.id
|
|
2615
|
+
)) });
|
|
2616
|
+
}
|
|
2617
|
+
function EvidencePanel({ node }) {
|
|
2618
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "rounded-lg border bg-background p-4", children: [
|
|
2619
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("dl", { className: "grid gap-2 text-xs", children: [
|
|
2620
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Source", value: node.sourceType }),
|
|
2621
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Source ID", value: node.sourceId }),
|
|
2622
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Thread", value: node.threadId }),
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InspectorRow, { label: "Checkpoint", value: node.checkpointId })
|
|
2624
|
+
] }),
|
|
2625
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "mt-4", children: [
|
|
2626
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "text-xs font-medium text-muted-foreground", children: "Source messages" }),
|
|
2627
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-2 flex flex-wrap gap-1", children: node.sourceMessageIds.length ? node.sourceMessageIds.map((id) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Badge, { className: "max-w-full truncate", variant: "outline", children: id }, id)) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground", children: "-" }) })
|
|
2628
|
+
] })
|
|
2629
|
+
] });
|
|
2630
|
+
}
|
|
2631
|
+
function MatchBadges({ match }) {
|
|
2632
|
+
if (!match?.reasons.length) return null;
|
|
2633
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-2 flex flex-wrap gap-1", children: match.reasons.slice(0, 4).map((reason) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Badge, { className: "text-[10px]", variant: "outline", children: reason }, reason)) });
|
|
2634
|
+
}
|
|
2446
2635
|
function InspectorRow({
|
|
2447
2636
|
label,
|
|
2448
2637
|
value
|
|
@@ -2471,6 +2660,12 @@ function formatDateTime(value) {
|
|
|
2471
2660
|
if (Number.isNaN(date.getTime())) return value;
|
|
2472
2661
|
return date.toLocaleString();
|
|
2473
2662
|
}
|
|
2663
|
+
function formatNullableNumber(value) {
|
|
2664
|
+
return typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : "-";
|
|
2665
|
+
}
|
|
2666
|
+
function formatSimilarityScore(value) {
|
|
2667
|
+
return Number.isFinite(value) ? `Similarity ${value.toFixed(2)}` : "-";
|
|
2668
|
+
}
|
|
2474
2669
|
function emptyBrainResponse() {
|
|
2475
2670
|
return {
|
|
2476
2671
|
nodes: [],
|
|
@@ -2482,6 +2677,14 @@ function emptyBrainResponse() {
|
|
|
2482
2677
|
byKind: {},
|
|
2483
2678
|
byStatus: {}
|
|
2484
2679
|
},
|
|
2680
|
+
matches: {},
|
|
2681
|
+
related: [],
|
|
2682
|
+
similar: [],
|
|
2683
|
+
semantic: {
|
|
2684
|
+
requested: false,
|
|
2685
|
+
available: false,
|
|
2686
|
+
error: null
|
|
2687
|
+
},
|
|
2485
2688
|
pageInfo: {
|
|
2486
2689
|
limit: 0,
|
|
2487
2690
|
offset: 0,
|