@copilotz/admin 0.9.39 → 0.9.41
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 +783 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -1
- package/dist/index.d.ts +52 -1
- package/dist/index.js +779 -104
- package/dist/index.js.map +1 -1
- package/dist/styles.css +81 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -234,6 +234,14 @@ function createAdminClient(options = {}) {
|
|
|
234
234
|
kind: filters.kind === "all" ? void 0 : filters.kind,
|
|
235
235
|
status: filters.status === "all" ? void 0 : filters.status,
|
|
236
236
|
search: filters.search,
|
|
237
|
+
searchMode: filters.searchMode,
|
|
238
|
+
focusNodeId: filters.focusNodeId,
|
|
239
|
+
includeRelated: filters.includeRelated ? "true" : void 0,
|
|
240
|
+
includeSimilar: filters.includeSimilar ? "true" : void 0,
|
|
241
|
+
similarLimit: filters.similarLimit ? String(filters.similarLimit) : void 0,
|
|
242
|
+
minSimilarity: typeof filters.minSimilarity === "number" ? String(filters.minSimilarity) : void 0,
|
|
243
|
+
relationDepth: filters.relationDepth ? String(filters.relationDepth) : void 0,
|
|
244
|
+
relationTypes: filters.relationTypes?.join(","),
|
|
237
245
|
limit: String(filters.limit ?? 160),
|
|
238
246
|
offset: filters.offset ? String(filters.offset) : void 0
|
|
239
247
|
}),
|
|
@@ -1948,18 +1956,165 @@ function AgentDetailPage({ context }) {
|
|
|
1948
1956
|
// src/modules/brain/index.tsx
|
|
1949
1957
|
import React7 from "react";
|
|
1950
1958
|
import {
|
|
1959
|
+
BookOpen,
|
|
1951
1960
|
Brain as Brain2,
|
|
1952
|
-
|
|
1953
|
-
Network,
|
|
1961
|
+
GitBranch,
|
|
1954
1962
|
RefreshCw,
|
|
1955
1963
|
Search as Search2,
|
|
1956
|
-
Sparkles
|
|
1964
|
+
Sparkles,
|
|
1965
|
+
UsersRound
|
|
1957
1966
|
} from "lucide-react";
|
|
1967
|
+
|
|
1968
|
+
// src/modules/brain/view-model.ts
|
|
1969
|
+
var ENTITY_FOCUS_RELATION_TYPES = [
|
|
1970
|
+
"mentions",
|
|
1971
|
+
"related_to",
|
|
1972
|
+
"supports",
|
|
1973
|
+
"depends_on",
|
|
1974
|
+
"contradicts",
|
|
1975
|
+
"supersedes"
|
|
1976
|
+
];
|
|
1977
|
+
var BRAIN_VIEW_LABELS = {
|
|
1978
|
+
entities: "Entities",
|
|
1979
|
+
knowledge: "Knowledge",
|
|
1980
|
+
work: "Work",
|
|
1981
|
+
map: "Map",
|
|
1982
|
+
all: "All nodes"
|
|
1983
|
+
};
|
|
1984
|
+
var BRAIN_RELATION_GROUP_DEFINITIONS = [
|
|
1985
|
+
{
|
|
1986
|
+
id: "decisions",
|
|
1987
|
+
label: "Decisions",
|
|
1988
|
+
description: "Durable choices connected to this entity.",
|
|
1989
|
+
kinds: ["decision"]
|
|
1990
|
+
},
|
|
1991
|
+
{
|
|
1992
|
+
id: "facts",
|
|
1993
|
+
label: "Facts",
|
|
1994
|
+
description: "Known statements and observations.",
|
|
1995
|
+
kinds: ["fact"]
|
|
1996
|
+
},
|
|
1997
|
+
{
|
|
1998
|
+
id: "tasks",
|
|
1999
|
+
label: "Tasks",
|
|
2000
|
+
description: "Actions, next steps, and execution work.",
|
|
2001
|
+
kinds: ["task", "next_action"]
|
|
2002
|
+
},
|
|
2003
|
+
{
|
|
2004
|
+
id: "preferences",
|
|
2005
|
+
label: "Preferences",
|
|
2006
|
+
description: "Remembered user, org, or agent preferences.",
|
|
2007
|
+
kinds: ["preference"]
|
|
2008
|
+
},
|
|
2009
|
+
{
|
|
2010
|
+
id: "constraints",
|
|
2011
|
+
label: "Constraints",
|
|
2012
|
+
description: "Limits, rules, and requirements.",
|
|
2013
|
+
kinds: ["constraint"]
|
|
2014
|
+
},
|
|
2015
|
+
{
|
|
2016
|
+
id: "risks",
|
|
2017
|
+
label: "Risks",
|
|
2018
|
+
description: "Known risks or possible failures.",
|
|
2019
|
+
kinds: ["risk"]
|
|
2020
|
+
},
|
|
2021
|
+
{
|
|
2022
|
+
id: "openQuestions",
|
|
2023
|
+
label: "Open questions",
|
|
2024
|
+
description: "Questions that still need resolution.",
|
|
2025
|
+
kinds: ["open_question"]
|
|
2026
|
+
},
|
|
2027
|
+
{
|
|
2028
|
+
id: "currentState",
|
|
2029
|
+
label: "Current state",
|
|
2030
|
+
description: "Shorter-term context, challenges, and active state.",
|
|
2031
|
+
kinds: ["current_state", "challenge"]
|
|
2032
|
+
},
|
|
2033
|
+
{
|
|
2034
|
+
id: "entities",
|
|
2035
|
+
label: "Other entities",
|
|
2036
|
+
description: "Neighboring people, systems, projects, or concepts.",
|
|
2037
|
+
kinds: ["entity"]
|
|
2038
|
+
},
|
|
2039
|
+
{
|
|
2040
|
+
id: "other",
|
|
2041
|
+
label: "Other",
|
|
2042
|
+
description: "Related nodes that do not fit a standard Brain kind yet.",
|
|
2043
|
+
kinds: []
|
|
2044
|
+
}
|
|
2045
|
+
];
|
|
2046
|
+
var GROUP_BY_KIND = new Map(
|
|
2047
|
+
BRAIN_RELATION_GROUP_DEFINITIONS.flatMap(
|
|
2048
|
+
(group) => group.kinds.map((kind) => [kind, group.id])
|
|
2049
|
+
)
|
|
2050
|
+
);
|
|
2051
|
+
function getBrainViewBaseFilters(view) {
|
|
2052
|
+
if (view === "entities") {
|
|
2053
|
+
return { kind: "entity", layer: "knowledge" };
|
|
2054
|
+
}
|
|
2055
|
+
if (view === "knowledge") {
|
|
2056
|
+
return { kind: "all", layer: "knowledge" };
|
|
2057
|
+
}
|
|
2058
|
+
if (view === "work") {
|
|
2059
|
+
return { kind: "all", layer: "working" };
|
|
2060
|
+
}
|
|
2061
|
+
return { kind: "all", layer: "all" };
|
|
2062
|
+
}
|
|
2063
|
+
function isEntityBrainView(view) {
|
|
2064
|
+
return view === "entities";
|
|
2065
|
+
}
|
|
2066
|
+
function groupBrainRelationsByKind(related) {
|
|
2067
|
+
const groups = BRAIN_RELATION_GROUP_DEFINITIONS.map((definition) => ({
|
|
2068
|
+
id: definition.id,
|
|
2069
|
+
label: definition.label,
|
|
2070
|
+
description: definition.description,
|
|
2071
|
+
items: []
|
|
2072
|
+
}));
|
|
2073
|
+
const byId = new Map(groups.map((group) => [group.id, group]));
|
|
2074
|
+
for (const item of related) {
|
|
2075
|
+
const groupId = GROUP_BY_KIND.get(item.node.kind) ?? "other";
|
|
2076
|
+
byId.get(groupId)?.items.push(item);
|
|
2077
|
+
}
|
|
2078
|
+
return groups.filter((group) => group.items.length > 0);
|
|
2079
|
+
}
|
|
2080
|
+
function getKnowledgeRelationGroups(related) {
|
|
2081
|
+
const knowledgeGroupIds = [
|
|
2082
|
+
"decisions",
|
|
2083
|
+
"facts",
|
|
2084
|
+
"preferences",
|
|
2085
|
+
"constraints"
|
|
2086
|
+
];
|
|
2087
|
+
return groupBrainRelationsByKind(related).filter(
|
|
2088
|
+
(group) => knowledgeGroupIds.includes(group.id)
|
|
2089
|
+
);
|
|
2090
|
+
}
|
|
2091
|
+
function getWorkRelationGroups(related) {
|
|
2092
|
+
const workGroupIds = [
|
|
2093
|
+
"tasks",
|
|
2094
|
+
"risks",
|
|
2095
|
+
"openQuestions",
|
|
2096
|
+
"currentState"
|
|
2097
|
+
];
|
|
2098
|
+
return groupBrainRelationsByKind(related).filter(
|
|
2099
|
+
(group) => workGroupIds.includes(group.id)
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
// src/modules/brain/index.tsx
|
|
1958
2104
|
import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1959
2105
|
var BRAIN_LAYERS = ["all", "knowledge", "working"];
|
|
2106
|
+
var BRAIN_SEARCH_MODES = ["hybrid", "semantic", "keyword"];
|
|
1960
2107
|
var BRAIN_STATUSES = ["active", "all", "superseded", "archived"];
|
|
2108
|
+
var BRAIN_VIEWS = [
|
|
2109
|
+
"entities",
|
|
2110
|
+
"knowledge",
|
|
2111
|
+
"work",
|
|
2112
|
+
"map",
|
|
2113
|
+
"all"
|
|
2114
|
+
];
|
|
1961
2115
|
var BRAIN_KINDS = [
|
|
1962
2116
|
"all",
|
|
2117
|
+
"entity",
|
|
1963
2118
|
"decision",
|
|
1964
2119
|
"fact",
|
|
1965
2120
|
"preference",
|
|
@@ -1993,7 +2148,11 @@ function brainModule() {
|
|
|
1993
2148
|
};
|
|
1994
2149
|
}
|
|
1995
2150
|
function BrainPage({ context }) {
|
|
2151
|
+
const [view, setView] = React7.useState("entities");
|
|
1996
2152
|
const [search, setSearch] = React7.useState("");
|
|
2153
|
+
const [searchMode, setSearchMode] = React7.useState(
|
|
2154
|
+
"hybrid"
|
|
2155
|
+
);
|
|
1997
2156
|
const [layer, setLayer] = React7.useState("all");
|
|
1998
2157
|
const [status, setStatus] = React7.useState(
|
|
1999
2158
|
"active"
|
|
@@ -2006,25 +2165,44 @@ function BrainPage({ context }) {
|
|
|
2006
2165
|
const [selectedNode, setSelectedNode] = React7.useState(
|
|
2007
2166
|
null
|
|
2008
2167
|
);
|
|
2168
|
+
const [focusNodeId, setFocusNodeId] = React7.useState(null);
|
|
2009
2169
|
const [loading, setLoading] = React7.useState(false);
|
|
2010
2170
|
const [error, setError] = React7.useState(null);
|
|
2011
|
-
const loadBrain = React7.useCallback(async () => {
|
|
2171
|
+
const loadBrain = React7.useCallback(async (focusOverride) => {
|
|
2012
2172
|
setLoading(true);
|
|
2013
2173
|
setError(null);
|
|
2174
|
+
const effectiveFocusNodeId = focusOverride === void 0 ? focusNodeId : focusOverride;
|
|
2175
|
+
const viewFilters = getBrainViewBaseFilters(view);
|
|
2176
|
+
const effectiveLayer = view === "map" || view === "all" ? layer : viewFilters.layer;
|
|
2177
|
+
const effectiveKind = view === "entities" ? "entity" : kind;
|
|
2014
2178
|
try {
|
|
2015
2179
|
const next = await context.client.getBrain({
|
|
2016
2180
|
namespace: context.scope.namespace || void 0,
|
|
2017
2181
|
search: search.trim() || void 0,
|
|
2018
|
-
|
|
2182
|
+
searchMode,
|
|
2183
|
+
layer: effectiveLayer,
|
|
2019
2184
|
status,
|
|
2020
|
-
kind,
|
|
2185
|
+
kind: effectiveKind,
|
|
2021
2186
|
agentId: agentId.trim() || void 0,
|
|
2187
|
+
focusNodeId: effectiveFocusNodeId || void 0,
|
|
2188
|
+
includeRelated: Boolean(effectiveFocusNodeId),
|
|
2189
|
+
includeSimilar: Boolean(effectiveFocusNodeId),
|
|
2190
|
+
similarLimit: 24,
|
|
2191
|
+
minSimilarity: 0.2,
|
|
2192
|
+
relationTypes: effectiveFocusNodeId ? [...ENTITY_FOCUS_RELATION_TYPES] : void 0,
|
|
2022
2193
|
limit: 180
|
|
2023
2194
|
});
|
|
2024
2195
|
setResponse(next);
|
|
2025
|
-
setSelectedNode(
|
|
2026
|
-
|
|
2027
|
-
|
|
2196
|
+
setSelectedNode((current) => {
|
|
2197
|
+
const currentInResults = current ? next.nodes.find((node) => node.id === current.id) ?? current : null;
|
|
2198
|
+
if (effectiveFocusNodeId) {
|
|
2199
|
+
return next.nodes.find((node) => node.id === effectiveFocusNodeId) ?? currentInResults;
|
|
2200
|
+
}
|
|
2201
|
+
if (view === "entities") {
|
|
2202
|
+
return current && next.nodes.some((node) => node.id === current.id) ? currentInResults : null;
|
|
2203
|
+
}
|
|
2204
|
+
return current && next.nodes.some((node) => node.id === current.id) ? currentInResults : next.nodes[0] ?? null;
|
|
2205
|
+
});
|
|
2028
2206
|
} catch (cause) {
|
|
2029
2207
|
setError(cause instanceof Error ? cause.message : "Failed to load brain");
|
|
2030
2208
|
setResponse(null);
|
|
@@ -2036,17 +2214,38 @@ function BrainPage({ context }) {
|
|
|
2036
2214
|
agentId,
|
|
2037
2215
|
context.client,
|
|
2038
2216
|
context.scope.namespace,
|
|
2217
|
+
focusNodeId,
|
|
2039
2218
|
kind,
|
|
2040
2219
|
layer,
|
|
2041
2220
|
search,
|
|
2042
|
-
|
|
2221
|
+
searchMode,
|
|
2222
|
+
status,
|
|
2223
|
+
view
|
|
2043
2224
|
]);
|
|
2044
2225
|
React7.useEffect(() => {
|
|
2045
2226
|
void loadBrain();
|
|
2046
|
-
}, [context.refreshKey, context.scope.namespace, loadBrain]);
|
|
2227
|
+
}, [context.refreshKey, context.scope.namespace, focusNodeId, loadBrain]);
|
|
2047
2228
|
const data = response ?? emptyBrainResponse();
|
|
2229
|
+
const matches = data.matches ?? {};
|
|
2230
|
+
const related = data.related ?? [];
|
|
2231
|
+
const similar = data.similar ?? [];
|
|
2232
|
+
const entityCount = data.stats.byKind.entity ?? data.nodes.filter((node) => node.kind === "entity").length;
|
|
2048
2233
|
const knowledgeCount = data.stats.byLayer.knowledge ?? 0;
|
|
2049
2234
|
const workingCount = data.stats.byLayer.working ?? 0;
|
|
2235
|
+
const selectNode = React7.useCallback((node) => {
|
|
2236
|
+
setSelectedNode(node);
|
|
2237
|
+
setFocusNodeId(node.id);
|
|
2238
|
+
}, []);
|
|
2239
|
+
const selectView = React7.useCallback((nextView) => {
|
|
2240
|
+
setView(nextView);
|
|
2241
|
+
setFocusNodeId(null);
|
|
2242
|
+
setSelectedNode(null);
|
|
2243
|
+
}, []);
|
|
2244
|
+
const runSearch = React7.useCallback(() => {
|
|
2245
|
+
setFocusNodeId(null);
|
|
2246
|
+
setSelectedNode(null);
|
|
2247
|
+
void loadBrain(null);
|
|
2248
|
+
}, [loadBrain]);
|
|
2050
2249
|
return /* @__PURE__ */ jsxs13("div", { className: "space-y-4", children: [
|
|
2051
2250
|
/* @__PURE__ */ jsx21(
|
|
2052
2251
|
PageHeader,
|
|
@@ -2080,16 +2279,16 @@ function BrainPage({ context }) {
|
|
|
2080
2279
|
{
|
|
2081
2280
|
items: [
|
|
2082
2281
|
{
|
|
2083
|
-
label: "
|
|
2084
|
-
value:
|
|
2085
|
-
detail: `${data.pageInfo.returned} shown
|
|
2086
|
-
icon:
|
|
2282
|
+
label: "Entities",
|
|
2283
|
+
value: entityCount,
|
|
2284
|
+
detail: view === "entities" ? `${data.pageInfo.returned} shown` : "Stable anchors",
|
|
2285
|
+
icon: UsersRound
|
|
2087
2286
|
},
|
|
2088
2287
|
{
|
|
2089
2288
|
label: "Knowledge",
|
|
2090
2289
|
value: knowledgeCount,
|
|
2091
2290
|
detail: "Durable nodes",
|
|
2092
|
-
icon:
|
|
2291
|
+
icon: BookOpen
|
|
2093
2292
|
},
|
|
2094
2293
|
{
|
|
2095
2294
|
label: "Working",
|
|
@@ -2098,14 +2297,27 @@ function BrainPage({ context }) {
|
|
|
2098
2297
|
icon: Sparkles
|
|
2099
2298
|
},
|
|
2100
2299
|
{
|
|
2101
|
-
label: "
|
|
2102
|
-
value: data.
|
|
2103
|
-
detail: "
|
|
2104
|
-
icon:
|
|
2300
|
+
label: selectedNode ? "Focus links" : "Brain nodes",
|
|
2301
|
+
value: selectedNode ? related.length + similar.length : data.stats.total,
|
|
2302
|
+
detail: selectedNode ? "Related and similar" : `${data.pageInfo.returned} shown`,
|
|
2303
|
+
icon: selectedNode ? GitBranch : Brain2
|
|
2105
2304
|
}
|
|
2106
2305
|
]
|
|
2107
2306
|
}
|
|
2108
2307
|
),
|
|
2308
|
+
/* @__PURE__ */ jsx21("div", { className: "inline-flex max-w-full overflow-hidden rounded-md border bg-background", children: BRAIN_VIEWS.map((item) => /* @__PURE__ */ jsx21(
|
|
2309
|
+
"button",
|
|
2310
|
+
{
|
|
2311
|
+
className: cn(
|
|
2312
|
+
"min-w-0 px-3 py-2 text-xs transition-colors sm:px-4",
|
|
2313
|
+
view === item ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted"
|
|
2314
|
+
),
|
|
2315
|
+
onClick: () => selectView(item),
|
|
2316
|
+
type: "button",
|
|
2317
|
+
children: BRAIN_VIEW_LABELS[item]
|
|
2318
|
+
},
|
|
2319
|
+
item
|
|
2320
|
+
)) }),
|
|
2109
2321
|
/* @__PURE__ */ jsxs13(
|
|
2110
2322
|
FilterBar,
|
|
2111
2323
|
{
|
|
@@ -2113,7 +2325,7 @@ function BrainPage({ context }) {
|
|
|
2113
2325
|
Button,
|
|
2114
2326
|
{
|
|
2115
2327
|
disabled: loading,
|
|
2116
|
-
onClick:
|
|
2328
|
+
onClick: runSearch,
|
|
2117
2329
|
size: "sm",
|
|
2118
2330
|
type: "button",
|
|
2119
2331
|
children: [
|
|
@@ -2123,20 +2335,40 @@ function BrainPage({ context }) {
|
|
|
2123
2335
|
}
|
|
2124
2336
|
),
|
|
2125
2337
|
onSearchChange: setSearch,
|
|
2126
|
-
searchPlaceholder: "Search brain",
|
|
2338
|
+
searchPlaceholder: view === "entities" ? "Search entities" : "Search brain",
|
|
2127
2339
|
searchValue: search,
|
|
2128
2340
|
children: [
|
|
2129
|
-
/* @__PURE__ */
|
|
2341
|
+
/* @__PURE__ */ jsx21("div", { className: "inline-flex h-8 overflow-hidden rounded-md border bg-background", children: BRAIN_SEARCH_MODES.map((mode) => /* @__PURE__ */ jsx21(
|
|
2342
|
+
"button",
|
|
2343
|
+
{
|
|
2344
|
+
className: cn(
|
|
2345
|
+
"px-3 text-xs transition-colors",
|
|
2346
|
+
searchMode === mode ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted"
|
|
2347
|
+
),
|
|
2348
|
+
onClick: () => setSearchMode(mode),
|
|
2349
|
+
type: "button",
|
|
2350
|
+
children: formatLabel(mode)
|
|
2351
|
+
},
|
|
2352
|
+
mode
|
|
2353
|
+
)) }),
|
|
2354
|
+
view === "map" || view === "all" ? /* @__PURE__ */ jsxs13(
|
|
2130
2355
|
Select,
|
|
2131
2356
|
{
|
|
2132
2357
|
value: layer,
|
|
2133
2358
|
onValueChange: (value) => setLayer(value),
|
|
2134
2359
|
children: [
|
|
2135
|
-
/* @__PURE__ */ jsx21(
|
|
2360
|
+
/* @__PURE__ */ jsx21(
|
|
2361
|
+
SelectTrigger,
|
|
2362
|
+
{
|
|
2363
|
+
className: "h-8 w-[140px] text-xs",
|
|
2364
|
+
"aria-label": "Layer",
|
|
2365
|
+
children: /* @__PURE__ */ jsx21(SelectValue, {})
|
|
2366
|
+
}
|
|
2367
|
+
),
|
|
2136
2368
|
/* @__PURE__ */ jsx21(SelectContent, { children: BRAIN_LAYERS.map((option) => /* @__PURE__ */ jsx21(SelectItem, { value: option, children: option === "all" ? "All layers" : formatLabel(option) }, option)) })
|
|
2137
2369
|
]
|
|
2138
2370
|
}
|
|
2139
|
-
),
|
|
2371
|
+
) : null,
|
|
2140
2372
|
/* @__PURE__ */ jsxs13(
|
|
2141
2373
|
Select,
|
|
2142
2374
|
{
|
|
@@ -2148,24 +2380,31 @@ function BrainPage({ context }) {
|
|
|
2148
2380
|
]
|
|
2149
2381
|
}
|
|
2150
2382
|
),
|
|
2151
|
-
/* @__PURE__ */ jsxs13(
|
|
2383
|
+
view !== "entities" ? /* @__PURE__ */ jsxs13(
|
|
2152
2384
|
Select,
|
|
2153
2385
|
{
|
|
2154
2386
|
value: kind,
|
|
2155
2387
|
onValueChange: (value) => setKind(value),
|
|
2156
2388
|
children: [
|
|
2157
|
-
/* @__PURE__ */ jsx21(
|
|
2389
|
+
/* @__PURE__ */ jsx21(
|
|
2390
|
+
SelectTrigger,
|
|
2391
|
+
{
|
|
2392
|
+
className: "h-8 w-[170px] text-xs",
|
|
2393
|
+
"aria-label": "Kind",
|
|
2394
|
+
children: /* @__PURE__ */ jsx21(SelectValue, {})
|
|
2395
|
+
}
|
|
2396
|
+
),
|
|
2158
2397
|
/* @__PURE__ */ jsx21(SelectContent, { children: BRAIN_KINDS.map((option) => /* @__PURE__ */ jsx21(SelectItem, { value: option, children: option === "all" ? "All kinds" : formatLabel(option) }, option)) })
|
|
2159
2398
|
]
|
|
2160
2399
|
}
|
|
2161
|
-
),
|
|
2400
|
+
) : /* @__PURE__ */ jsx21(Badge, { className: "h-8 px-3", variant: "secondary", children: "Entity index" }),
|
|
2162
2401
|
/* @__PURE__ */ jsx21(
|
|
2163
2402
|
Input,
|
|
2164
2403
|
{
|
|
2165
2404
|
className: "h-8 w-[190px]",
|
|
2166
2405
|
onChange: (event) => setAgentId(event.target.value),
|
|
2167
2406
|
onKeyDown: (event) => {
|
|
2168
|
-
if (event.key === "Enter")
|
|
2407
|
+
if (event.key === "Enter") runSearch();
|
|
2169
2408
|
},
|
|
2170
2409
|
placeholder: "Agent ID",
|
|
2171
2410
|
value: agentId
|
|
@@ -2174,10 +2413,23 @@ function BrainPage({ context }) {
|
|
|
2174
2413
|
]
|
|
2175
2414
|
}
|
|
2176
2415
|
),
|
|
2416
|
+
data.semantic?.requested && data.semantic.error ? /* @__PURE__ */ jsxs13("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: [
|
|
2417
|
+
"Semantic search unavailable: ",
|
|
2418
|
+
data.semantic.error
|
|
2419
|
+
] }) : null,
|
|
2177
2420
|
error ? /* @__PURE__ */ jsx21(EmptyState, { title: "Unable to load brain", description: error }) : /* @__PURE__ */ jsx21(
|
|
2178
2421
|
InspectorPanel,
|
|
2179
2422
|
{
|
|
2180
|
-
side: selectedNode ? /* @__PURE__ */ jsx21(
|
|
2423
|
+
side: selectedNode ? /* @__PURE__ */ jsx21(
|
|
2424
|
+
BrainNodeInspector,
|
|
2425
|
+
{
|
|
2426
|
+
match: matches[selectedNode.id],
|
|
2427
|
+
node: selectedNode,
|
|
2428
|
+
onSelectNode: selectNode,
|
|
2429
|
+
related,
|
|
2430
|
+
similar
|
|
2431
|
+
}
|
|
2432
|
+
) : /* @__PURE__ */ jsx21(
|
|
2181
2433
|
EmptyState,
|
|
2182
2434
|
{
|
|
2183
2435
|
icon: Brain2,
|
|
@@ -2185,70 +2437,299 @@ function BrainPage({ context }) {
|
|
|
2185
2437
|
description: "Select a node from the map or table."
|
|
2186
2438
|
}
|
|
2187
2439
|
),
|
|
2188
|
-
children: /* @__PURE__ */
|
|
2440
|
+
children: /* @__PURE__ */ jsx21("div", { className: "space-y-4", children: /* @__PURE__ */ jsx21(
|
|
2441
|
+
BrainPrimaryContent,
|
|
2442
|
+
{
|
|
2443
|
+
data,
|
|
2444
|
+
loading,
|
|
2445
|
+
matches,
|
|
2446
|
+
onSelectNode: selectNode,
|
|
2447
|
+
related,
|
|
2448
|
+
selectedNode,
|
|
2449
|
+
similar,
|
|
2450
|
+
view
|
|
2451
|
+
}
|
|
2452
|
+
) })
|
|
2453
|
+
}
|
|
2454
|
+
)
|
|
2455
|
+
] });
|
|
2456
|
+
}
|
|
2457
|
+
function BrainPrimaryContent({
|
|
2458
|
+
data,
|
|
2459
|
+
loading,
|
|
2460
|
+
matches,
|
|
2461
|
+
onSelectNode,
|
|
2462
|
+
related,
|
|
2463
|
+
selectedNode,
|
|
2464
|
+
similar,
|
|
2465
|
+
view
|
|
2466
|
+
}) {
|
|
2467
|
+
if (view === "entities") {
|
|
2468
|
+
return /* @__PURE__ */ jsxs13("div", { className: "space-y-4", children: [
|
|
2469
|
+
/* @__PURE__ */ jsx21(
|
|
2470
|
+
EntityEgoGraph,
|
|
2471
|
+
{
|
|
2472
|
+
entity: selectedNode?.kind === "entity" ? selectedNode : null,
|
|
2473
|
+
loading,
|
|
2474
|
+
onSelectNode,
|
|
2475
|
+
related,
|
|
2476
|
+
similar
|
|
2477
|
+
}
|
|
2478
|
+
),
|
|
2479
|
+
/* @__PURE__ */ jsx21(
|
|
2480
|
+
BrainNodeTable,
|
|
2481
|
+
{
|
|
2482
|
+
emptyDescription: "Entity nodes will appear here once the Brain has named people, tenants, projects, products, tools, policies, or concepts.",
|
|
2483
|
+
emptyTitle: loading ? "Loading entities" : "No entities yet",
|
|
2484
|
+
loading,
|
|
2485
|
+
matches,
|
|
2486
|
+
nodes: data.nodes,
|
|
2487
|
+
onSelectNode,
|
|
2488
|
+
variant: "entities"
|
|
2489
|
+
}
|
|
2490
|
+
)
|
|
2491
|
+
] });
|
|
2492
|
+
}
|
|
2493
|
+
if (view === "map") {
|
|
2494
|
+
return /* @__PURE__ */ jsxs13("div", { className: "space-y-4", children: [
|
|
2495
|
+
/* @__PURE__ */ jsx21(
|
|
2496
|
+
BrainMap,
|
|
2497
|
+
{
|
|
2498
|
+
clusters: data.clusters,
|
|
2499
|
+
edges: data.edges,
|
|
2500
|
+
loading,
|
|
2501
|
+
nodes: data.nodes,
|
|
2502
|
+
onSelectNode,
|
|
2503
|
+
similar,
|
|
2504
|
+
selectedNodeId: selectedNode?.id ?? null
|
|
2505
|
+
}
|
|
2506
|
+
),
|
|
2507
|
+
/* @__PURE__ */ jsx21(
|
|
2508
|
+
BrainNodeTable,
|
|
2509
|
+
{
|
|
2510
|
+
emptyDescription: "Knowledge and working-state nodes will appear here.",
|
|
2511
|
+
emptyTitle: loading ? "Loading brain" : "No brain nodes",
|
|
2512
|
+
loading,
|
|
2513
|
+
matches,
|
|
2514
|
+
nodes: data.nodes,
|
|
2515
|
+
onSelectNode
|
|
2516
|
+
}
|
|
2517
|
+
)
|
|
2518
|
+
] });
|
|
2519
|
+
}
|
|
2520
|
+
return /* @__PURE__ */ jsx21(
|
|
2521
|
+
BrainNodeTable,
|
|
2522
|
+
{
|
|
2523
|
+
emptyDescription: view === "work" ? "Working-state nodes will appear here when the Brain captures current challenges, tasks, risks, and open questions." : view === "knowledge" ? "Durable facts, decisions, preferences, constraints, and entities will appear here." : "Knowledge and working-state nodes will appear here.",
|
|
2524
|
+
emptyTitle: loading ? `Loading ${BRAIN_VIEW_LABELS[view].toLowerCase()}` : `No ${BRAIN_VIEW_LABELS[view].toLowerCase()}`,
|
|
2525
|
+
loading,
|
|
2526
|
+
matches,
|
|
2527
|
+
nodes: data.nodes,
|
|
2528
|
+
onSelectNode
|
|
2529
|
+
}
|
|
2530
|
+
);
|
|
2531
|
+
}
|
|
2532
|
+
function BrainNodeTable({
|
|
2533
|
+
emptyDescription,
|
|
2534
|
+
emptyTitle,
|
|
2535
|
+
loading,
|
|
2536
|
+
matches,
|
|
2537
|
+
nodes,
|
|
2538
|
+
onSelectNode,
|
|
2539
|
+
variant = "default"
|
|
2540
|
+
}) {
|
|
2541
|
+
return /* @__PURE__ */ jsx21(
|
|
2542
|
+
ResourceTable,
|
|
2543
|
+
{
|
|
2544
|
+
rows: nodes,
|
|
2545
|
+
getRowKey: (row) => row.id,
|
|
2546
|
+
onRowClick: onSelectNode,
|
|
2547
|
+
empty: /* @__PURE__ */ jsx21(
|
|
2548
|
+
EmptyState,
|
|
2549
|
+
{
|
|
2550
|
+
icon: variant === "entities" ? UsersRound : Brain2,
|
|
2551
|
+
title: emptyTitle,
|
|
2552
|
+
description: loading ? "Fetching Brain nodes for the active namespace." : emptyDescription
|
|
2553
|
+
}
|
|
2554
|
+
),
|
|
2555
|
+
columns: [
|
|
2556
|
+
{
|
|
2557
|
+
id: "node",
|
|
2558
|
+
header: variant === "entities" ? "Entity" : "Node",
|
|
2559
|
+
className: "max-w-[420px]",
|
|
2560
|
+
render: (row) => /* @__PURE__ */ jsxs13("div", { className: "min-w-0", children: [
|
|
2561
|
+
/* @__PURE__ */ jsx21("div", { className: "truncate font-medium", children: row.name }),
|
|
2562
|
+
/* @__PURE__ */ jsx21("div", { className: "truncate text-xs text-muted-foreground", children: row.content || "-" }),
|
|
2563
|
+
/* @__PURE__ */ jsx21(MatchBadges, { match: matches[row.id] })
|
|
2564
|
+
] })
|
|
2565
|
+
},
|
|
2566
|
+
...variant === "entities" ? [{
|
|
2567
|
+
id: "updated",
|
|
2568
|
+
header: "Updated",
|
|
2569
|
+
className: "whitespace-nowrap text-xs",
|
|
2570
|
+
render: (row) => formatDateTime(row.updatedAt)
|
|
2571
|
+
}] : [{
|
|
2572
|
+
id: "layer",
|
|
2573
|
+
header: "Layer",
|
|
2574
|
+
render: (row) => /* @__PURE__ */ jsx21(LayerBadge, { layer: row.layer })
|
|
2575
|
+
}, {
|
|
2576
|
+
id: "kind",
|
|
2577
|
+
header: "Kind",
|
|
2578
|
+
render: (row) => formatLabel(row.kind)
|
|
2579
|
+
}],
|
|
2580
|
+
{
|
|
2581
|
+
id: "status",
|
|
2582
|
+
header: "Status",
|
|
2583
|
+
render: (row) => /* @__PURE__ */ jsx21(StatusBadge, { status: row.status })
|
|
2584
|
+
},
|
|
2585
|
+
{
|
|
2586
|
+
id: "agent",
|
|
2587
|
+
header: "Agent",
|
|
2588
|
+
className: "max-w-[160px] truncate font-mono text-xs",
|
|
2589
|
+
render: (row) => row.agentId ?? "-"
|
|
2590
|
+
}
|
|
2591
|
+
]
|
|
2592
|
+
}
|
|
2593
|
+
);
|
|
2594
|
+
}
|
|
2595
|
+
function EntityEgoGraph({
|
|
2596
|
+
entity,
|
|
2597
|
+
loading,
|
|
2598
|
+
onSelectNode,
|
|
2599
|
+
related,
|
|
2600
|
+
similar
|
|
2601
|
+
}) {
|
|
2602
|
+
if (!entity) {
|
|
2603
|
+
return /* @__PURE__ */ jsx21("div", { className: "flex min-h-[300px] items-center justify-center rounded-lg border bg-background", children: /* @__PURE__ */ jsx21(
|
|
2604
|
+
EmptyState,
|
|
2605
|
+
{
|
|
2606
|
+
icon: UsersRound,
|
|
2607
|
+
title: loading ? "Loading entity workspace" : "Select an entity",
|
|
2608
|
+
description: loading ? "Fetching entity nodes for the active namespace." : "Choose an entity to see its explicit relations and semantic neighbors."
|
|
2609
|
+
}
|
|
2610
|
+
) });
|
|
2611
|
+
}
|
|
2612
|
+
const relatedItems = related.slice(0, 18);
|
|
2613
|
+
const similarItems = similar.slice(0, 10);
|
|
2614
|
+
const orbitCount = relatedItems.length + similarItems.length;
|
|
2615
|
+
const center = { x: 500, y: 260 };
|
|
2616
|
+
const radius = orbitCount > 12 ? 190 : 165;
|
|
2617
|
+
const orbitNodes = [
|
|
2618
|
+
...relatedItems.map((item, index) => ({
|
|
2619
|
+
id: item.edge.id,
|
|
2620
|
+
index,
|
|
2621
|
+
node: item.node,
|
|
2622
|
+
tone: "relation",
|
|
2623
|
+
label: formatLabel(item.edge.type)
|
|
2624
|
+
})),
|
|
2625
|
+
...similarItems.map((item, index) => ({
|
|
2626
|
+
id: `similar-${item.node.id}`,
|
|
2627
|
+
index: index + relatedItems.length,
|
|
2628
|
+
node: item.node,
|
|
2629
|
+
tone: "similar",
|
|
2630
|
+
label: formatSimilarityScore(item.similarity)
|
|
2631
|
+
}))
|
|
2632
|
+
].map((item) => {
|
|
2633
|
+
const angle = orbitCount > 0 ? Math.PI * 2 * item.index / orbitCount - Math.PI / 2 : 0;
|
|
2634
|
+
return {
|
|
2635
|
+
...item,
|
|
2636
|
+
x: center.x + Math.cos(angle) * radius,
|
|
2637
|
+
y: center.y + Math.sin(angle) * radius
|
|
2638
|
+
};
|
|
2639
|
+
});
|
|
2640
|
+
return /* @__PURE__ */ jsx21("div", { className: "overflow-hidden rounded-lg border bg-background", children: /* @__PURE__ */ jsxs13("div", { className: "grid gap-0 lg:grid-cols-[minmax(0,1.5fr)_320px]", children: [
|
|
2641
|
+
/* @__PURE__ */ jsxs13(
|
|
2642
|
+
"svg",
|
|
2643
|
+
{
|
|
2644
|
+
className: "block h-[380px] w-full bg-muted/20",
|
|
2645
|
+
role: "img",
|
|
2646
|
+
viewBox: "0 0 1000 520",
|
|
2647
|
+
children: [
|
|
2648
|
+
/* @__PURE__ */ jsx21("rect", { fill: "transparent", height: "520", width: "1000" }),
|
|
2649
|
+
orbitNodes.map((item) => /* @__PURE__ */ jsx21(
|
|
2650
|
+
"line",
|
|
2651
|
+
{
|
|
2652
|
+
stroke: item.tone === "similar" ? "#0ea5e9" : "#64748b",
|
|
2653
|
+
strokeDasharray: item.tone === "similar" ? "6 7" : void 0,
|
|
2654
|
+
strokeOpacity: item.tone === "similar" ? "0.48" : "0.38",
|
|
2655
|
+
strokeWidth: item.tone === "similar" ? "1.8" : "2.2",
|
|
2656
|
+
x1: center.x,
|
|
2657
|
+
x2: item.x,
|
|
2658
|
+
y1: center.y,
|
|
2659
|
+
y2: item.y
|
|
2660
|
+
},
|
|
2661
|
+
`line-${item.id}`
|
|
2662
|
+
)),
|
|
2189
2663
|
/* @__PURE__ */ jsx21(
|
|
2190
|
-
|
|
2664
|
+
"circle",
|
|
2191
2665
|
{
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2666
|
+
cx: center.x,
|
|
2667
|
+
cy: center.y,
|
|
2668
|
+
fill: nodeColor(entity),
|
|
2669
|
+
r: "22",
|
|
2670
|
+
stroke: "#0f172a",
|
|
2671
|
+
strokeWidth: "3",
|
|
2672
|
+
children: /* @__PURE__ */ jsx21("title", { children: entity.name })
|
|
2198
2673
|
}
|
|
2199
2674
|
),
|
|
2200
|
-
/* @__PURE__ */ jsx21(
|
|
2201
|
-
|
|
2675
|
+
orbitNodes.map((item) => /* @__PURE__ */ jsx21(
|
|
2676
|
+
"g",
|
|
2202
2677
|
{
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
EmptyState,
|
|
2208
|
-
{
|
|
2209
|
-
icon: Brain2,
|
|
2210
|
-
title: loading ? "Loading brain" : "No brain nodes",
|
|
2211
|
-
description: loading ? "Fetching brain nodes for the active namespace." : "Knowledge and working-state nodes will appear here."
|
|
2212
|
-
}
|
|
2213
|
-
),
|
|
2214
|
-
columns: [
|
|
2215
|
-
{
|
|
2216
|
-
id: "node",
|
|
2217
|
-
header: "Node",
|
|
2218
|
-
className: "max-w-[360px]",
|
|
2219
|
-
render: (row) => /* @__PURE__ */ jsxs13("div", { className: "min-w-0", children: [
|
|
2220
|
-
/* @__PURE__ */ jsx21("div", { className: "truncate font-medium", children: row.name }),
|
|
2221
|
-
/* @__PURE__ */ jsx21("div", { className: "truncate text-xs text-muted-foreground", children: row.content || "-" })
|
|
2222
|
-
] })
|
|
2223
|
-
},
|
|
2224
|
-
{
|
|
2225
|
-
id: "layer",
|
|
2226
|
-
header: "Layer",
|
|
2227
|
-
render: (row) => /* @__PURE__ */ jsx21(LayerBadge, { layer: row.layer })
|
|
2228
|
-
},
|
|
2229
|
-
{
|
|
2230
|
-
id: "kind",
|
|
2231
|
-
header: "Kind",
|
|
2232
|
-
render: (row) => formatLabel(row.kind)
|
|
2233
|
-
},
|
|
2234
|
-
{
|
|
2235
|
-
id: "status",
|
|
2236
|
-
header: "Status",
|
|
2237
|
-
render: (row) => /* @__PURE__ */ jsx21(StatusBadge, { status: row.status })
|
|
2238
|
-
},
|
|
2678
|
+
className: "cursor-pointer",
|
|
2679
|
+
onClick: () => onSelectNode(item.node),
|
|
2680
|
+
children: /* @__PURE__ */ jsx21(
|
|
2681
|
+
"circle",
|
|
2239
2682
|
{
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2683
|
+
cx: item.x,
|
|
2684
|
+
cy: item.y,
|
|
2685
|
+
fill: nodeColor(item.node),
|
|
2686
|
+
r: item.tone === "similar" ? 9 : 11,
|
|
2687
|
+
stroke: item.tone === "similar" ? "#0ea5e9" : "#ffffff",
|
|
2688
|
+
strokeWidth: "2",
|
|
2689
|
+
children: /* @__PURE__ */ jsx21("title", { children: `${item.node.name} \xB7 ${formatLabel(item.node.kind)} \xB7 ${item.label}` })
|
|
2244
2690
|
}
|
|
2245
|
-
|
|
2246
|
-
}
|
|
2247
|
-
|
|
2248
|
-
|
|
2691
|
+
)
|
|
2692
|
+
},
|
|
2693
|
+
item.id
|
|
2694
|
+
))
|
|
2695
|
+
]
|
|
2249
2696
|
}
|
|
2250
|
-
)
|
|
2251
|
-
|
|
2697
|
+
),
|
|
2698
|
+
/* @__PURE__ */ jsxs13("div", { className: "border-t p-4 lg:border-l lg:border-t-0", children: [
|
|
2699
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
2700
|
+
/* @__PURE__ */ jsx21(LayerBadge, { layer: entity.layer }),
|
|
2701
|
+
/* @__PURE__ */ jsx21(StatusBadge, { status: entity.status }),
|
|
2702
|
+
/* @__PURE__ */ jsx21(Badge, { variant: "outline", children: "Entity" })
|
|
2703
|
+
] }),
|
|
2704
|
+
/* @__PURE__ */ jsx21("h3", { className: "mt-3 truncate text-base font-semibold", children: entity.name }),
|
|
2705
|
+
/* @__PURE__ */ jsx21("p", { className: "mt-2 line-clamp-4 text-sm leading-6 text-muted-foreground", children: entity.content || "-" }),
|
|
2706
|
+
/* @__PURE__ */ jsxs13("div", { className: "mt-4 grid grid-cols-2 gap-2 text-xs", children: [
|
|
2707
|
+
/* @__PURE__ */ jsxs13("div", { className: "rounded-md border bg-muted/20 p-3", children: [
|
|
2708
|
+
/* @__PURE__ */ jsx21("div", { className: "text-muted-foreground", children: "Explicit" }),
|
|
2709
|
+
/* @__PURE__ */ jsx21("div", { className: "mt-1 text-lg font-semibold", children: related.length })
|
|
2710
|
+
] }),
|
|
2711
|
+
/* @__PURE__ */ jsxs13("div", { className: "rounded-md border bg-muted/20 p-3", children: [
|
|
2712
|
+
/* @__PURE__ */ jsx21("div", { className: "text-muted-foreground", children: "Semantic" }),
|
|
2713
|
+
/* @__PURE__ */ jsx21("div", { className: "mt-1 text-lg font-semibold", children: similar.length })
|
|
2714
|
+
] })
|
|
2715
|
+
] }),
|
|
2716
|
+
/* @__PURE__ */ jsxs13("div", { className: "mt-4 space-y-2", children: [
|
|
2717
|
+
/* @__PURE__ */ jsx21("div", { className: "text-xs font-medium text-muted-foreground", children: "Knowledge orbit" }),
|
|
2718
|
+
groupBrainRelationsByKind(related).slice(0, 5).map((group) => /* @__PURE__ */ jsxs13(
|
|
2719
|
+
"div",
|
|
2720
|
+
{
|
|
2721
|
+
className: "flex items-center justify-between gap-3 text-xs",
|
|
2722
|
+
children: [
|
|
2723
|
+
/* @__PURE__ */ jsx21("span", { className: "truncate", children: group.label }),
|
|
2724
|
+
/* @__PURE__ */ jsx21(Badge, { variant: "secondary", children: group.items.length })
|
|
2725
|
+
]
|
|
2726
|
+
},
|
|
2727
|
+
group.id
|
|
2728
|
+
)),
|
|
2729
|
+
related.length === 0 && similar.length === 0 ? /* @__PURE__ */ jsx21("p", { className: "text-xs leading-5 text-muted-foreground", children: "Select an entity with relations or embeddings to see its neighborhood." }) : null
|
|
2730
|
+
] })
|
|
2731
|
+
] })
|
|
2732
|
+
] }) });
|
|
2252
2733
|
}
|
|
2253
2734
|
function BrainMap({
|
|
2254
2735
|
clusters,
|
|
@@ -2256,6 +2737,7 @@ function BrainMap({
|
|
|
2256
2737
|
loading,
|
|
2257
2738
|
nodes,
|
|
2258
2739
|
onSelectNode,
|
|
2740
|
+
similar,
|
|
2259
2741
|
selectedNodeId
|
|
2260
2742
|
}) {
|
|
2261
2743
|
const nodeById = React7.useMemo(
|
|
@@ -2308,12 +2790,15 @@ function BrainMap({
|
|
|
2308
2790
|
const source = nodeById.get(edge.sourceNodeId);
|
|
2309
2791
|
const target = nodeById.get(edge.targetNodeId);
|
|
2310
2792
|
if (!source || !target) return null;
|
|
2793
|
+
const isSelectedEdge = Boolean(
|
|
2794
|
+
selectedNodeId && (edge.sourceNodeId === selectedNodeId || edge.targetNodeId === selectedNodeId)
|
|
2795
|
+
);
|
|
2311
2796
|
return /* @__PURE__ */ jsx21(
|
|
2312
2797
|
"line",
|
|
2313
2798
|
{
|
|
2314
2799
|
stroke: edge.type === "contradicts" ? "#dc2626" : "#64748b",
|
|
2315
|
-
strokeOpacity: "0.32",
|
|
2316
|
-
strokeWidth: edge.type === "supports" ? 2 : 1.3,
|
|
2800
|
+
strokeOpacity: isSelectedEdge ? "0.75" : "0.32",
|
|
2801
|
+
strokeWidth: isSelectedEdge ? 2.6 : edge.type === "supports" ? 2 : 1.3,
|
|
2317
2802
|
x1: source.x * 1e3,
|
|
2318
2803
|
x2: target.x * 1e3,
|
|
2319
2804
|
y1: source.y * 600,
|
|
@@ -2322,6 +2807,25 @@ function BrainMap({
|
|
|
2322
2807
|
edge.id
|
|
2323
2808
|
);
|
|
2324
2809
|
}),
|
|
2810
|
+
selectedNodeId ? similar.map((item) => {
|
|
2811
|
+
const source = nodeById.get(selectedNodeId);
|
|
2812
|
+
const target = nodeById.get(item.node.id);
|
|
2813
|
+
if (!source || !target) return null;
|
|
2814
|
+
return /* @__PURE__ */ jsx21(
|
|
2815
|
+
"line",
|
|
2816
|
+
{
|
|
2817
|
+
stroke: "#0ea5e9",
|
|
2818
|
+
strokeDasharray: "5 6",
|
|
2819
|
+
strokeOpacity: "0.42",
|
|
2820
|
+
strokeWidth: "1.8",
|
|
2821
|
+
x1: source.x * 1e3,
|
|
2822
|
+
x2: target.x * 1e3,
|
|
2823
|
+
y1: source.y * 600,
|
|
2824
|
+
y2: target.y * 600
|
|
2825
|
+
},
|
|
2826
|
+
`similar-${item.node.id}`
|
|
2827
|
+
);
|
|
2828
|
+
}) : null,
|
|
2325
2829
|
nodes.map((node) => {
|
|
2326
2830
|
const isSelected = node.id === selectedNodeId;
|
|
2327
2831
|
return /* @__PURE__ */ jsx21(
|
|
@@ -2349,7 +2853,19 @@ function BrainMap({
|
|
|
2349
2853
|
}
|
|
2350
2854
|
) });
|
|
2351
2855
|
}
|
|
2352
|
-
function BrainNodeInspector({
|
|
2856
|
+
function BrainNodeInspector({
|
|
2857
|
+
match,
|
|
2858
|
+
node,
|
|
2859
|
+
onSelectNode,
|
|
2860
|
+
related,
|
|
2861
|
+
similar
|
|
2862
|
+
}) {
|
|
2863
|
+
const [tab, setTab] = React7.useState("overview");
|
|
2864
|
+
const isEntity = node.kind === "entity";
|
|
2865
|
+
const tabs = isEntity ? ["overview", "knowledge", "work", "relations", "similar", "evidence", "json"] : ["overview", "relations", "similar", "evidence", "json"];
|
|
2866
|
+
React7.useEffect(() => {
|
|
2867
|
+
setTab("overview");
|
|
2868
|
+
}, [node.id]);
|
|
2353
2869
|
return /* @__PURE__ */ jsxs13("div", { className: "space-y-3", children: [
|
|
2354
2870
|
/* @__PURE__ */ jsxs13("div", { className: "rounded-lg border bg-background p-4", children: [
|
|
2355
2871
|
/* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
@@ -2359,24 +2875,161 @@ function BrainNodeInspector({ node }) {
|
|
|
2359
2875
|
] }),
|
|
2360
2876
|
/* @__PURE__ */ jsx21("h3", { className: "mt-3 text-base font-semibold", children: node.name }),
|
|
2361
2877
|
/* @__PURE__ */ jsx21("p", { className: "mt-2 text-sm leading-6 text-muted-foreground", children: node.content || "-" }),
|
|
2362
|
-
/* @__PURE__ */
|
|
2363
|
-
/* @__PURE__ */ jsx21(InspectorRow, { label: "Agent", value: node.agentId }),
|
|
2364
|
-
/* @__PURE__ */ jsx21(InspectorRow, { label: "Thread", value: node.threadId }),
|
|
2365
|
-
/* @__PURE__ */ jsx21(InspectorRow, { label: "Memory space", value: node.memorySpaceId }),
|
|
2366
|
-
/* @__PURE__ */ jsx21(InspectorRow, { label: "Checkpoint", value: node.checkpointId }),
|
|
2367
|
-
/* @__PURE__ */ jsx21(InspectorRow, { label: "Source field", value: node.sourceField }),
|
|
2368
|
-
/* @__PURE__ */ jsx21(
|
|
2369
|
-
InspectorRow,
|
|
2370
|
-
{
|
|
2371
|
-
label: "Updated",
|
|
2372
|
-
value: formatDateTime(node.updatedAt)
|
|
2373
|
-
}
|
|
2374
|
-
)
|
|
2375
|
-
] })
|
|
2878
|
+
/* @__PURE__ */ jsx21(MatchBadges, { match })
|
|
2376
2879
|
] }),
|
|
2377
|
-
/* @__PURE__ */ jsx21(
|
|
2880
|
+
/* @__PURE__ */ jsx21("div", { className: "inline-flex w-full overflow-hidden rounded-md border bg-background", children: tabs.map((item) => /* @__PURE__ */ jsx21(
|
|
2881
|
+
"button",
|
|
2882
|
+
{
|
|
2883
|
+
className: cn(
|
|
2884
|
+
"min-w-0 flex-1 px-2 py-2 text-xs transition-colors",
|
|
2885
|
+
tab === item ? "bg-muted font-medium text-foreground" : "text-muted-foreground hover:bg-muted/60"
|
|
2886
|
+
),
|
|
2887
|
+
onClick: () => setTab(item),
|
|
2888
|
+
type: "button",
|
|
2889
|
+
children: formatLabel(item)
|
|
2890
|
+
},
|
|
2891
|
+
item
|
|
2892
|
+
)) }),
|
|
2893
|
+
tab === "overview" ? /* @__PURE__ */ jsx21(BrainOverview, { node }) : null,
|
|
2894
|
+
tab === "knowledge" ? /* @__PURE__ */ jsx21(
|
|
2895
|
+
RelationGroupsPanel,
|
|
2896
|
+
{
|
|
2897
|
+
emptyDescription: "Durable decisions, facts, preferences, and constraints related to this entity will appear here.",
|
|
2898
|
+
emptyTitle: "No durable knowledge",
|
|
2899
|
+
groups: getKnowledgeRelationGroups(related),
|
|
2900
|
+
onSelectNode
|
|
2901
|
+
}
|
|
2902
|
+
) : null,
|
|
2903
|
+
tab === "work" ? /* @__PURE__ */ jsx21(
|
|
2904
|
+
RelationGroupsPanel,
|
|
2905
|
+
{
|
|
2906
|
+
emptyDescription: "Tasks, risks, open questions, and current-state nodes related to this entity will appear here.",
|
|
2907
|
+
emptyTitle: "No current work",
|
|
2908
|
+
groups: getWorkRelationGroups(related),
|
|
2909
|
+
onSelectNode
|
|
2910
|
+
}
|
|
2911
|
+
) : null,
|
|
2912
|
+
tab === "relations" ? /* @__PURE__ */ jsx21(
|
|
2913
|
+
RelationGroupsPanel,
|
|
2914
|
+
{
|
|
2915
|
+
emptyDescription: "Explicit relation edges will appear here when this node is connected to other concepts.",
|
|
2916
|
+
emptyTitle: "No explicit relations",
|
|
2917
|
+
groups: groupBrainRelationsByKind(related),
|
|
2918
|
+
onSelectNode
|
|
2919
|
+
}
|
|
2920
|
+
) : null,
|
|
2921
|
+
tab === "similar" ? /* @__PURE__ */ jsx21(SimilarPanel, { onSelectNode, similar }) : null,
|
|
2922
|
+
tab === "evidence" ? /* @__PURE__ */ jsx21(EvidencePanel, { node }) : null,
|
|
2923
|
+
tab === "json" ? /* @__PURE__ */ jsx21(JsonPanel, { title: "Node JSON", value: node, minHeight: 300 }) : null
|
|
2378
2924
|
] });
|
|
2379
2925
|
}
|
|
2926
|
+
function BrainOverview({ node }) {
|
|
2927
|
+
return /* @__PURE__ */ jsx21("div", { className: "rounded-lg border bg-background p-4", children: /* @__PURE__ */ jsxs13("dl", { className: "grid gap-2 text-xs", children: [
|
|
2928
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Agent", value: node.agentId }),
|
|
2929
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Thread", value: node.threadId }),
|
|
2930
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Memory space", value: node.memorySpaceId }),
|
|
2931
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Checkpoint", value: node.checkpointId }),
|
|
2932
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Source field", value: node.sourceField }),
|
|
2933
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Confidence", value: formatNullableNumber(node.confidence) }),
|
|
2934
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Updated", value: formatDateTime(node.updatedAt) })
|
|
2935
|
+
] }) });
|
|
2936
|
+
}
|
|
2937
|
+
function RelationGroupsPanel({
|
|
2938
|
+
emptyDescription,
|
|
2939
|
+
emptyTitle,
|
|
2940
|
+
groups,
|
|
2941
|
+
onSelectNode
|
|
2942
|
+
}) {
|
|
2943
|
+
if (groups.length === 0) {
|
|
2944
|
+
return /* @__PURE__ */ jsx21(
|
|
2945
|
+
EmptyState,
|
|
2946
|
+
{
|
|
2947
|
+
icon: GitBranch,
|
|
2948
|
+
title: emptyTitle,
|
|
2949
|
+
description: emptyDescription
|
|
2950
|
+
}
|
|
2951
|
+
);
|
|
2952
|
+
}
|
|
2953
|
+
return /* @__PURE__ */ jsx21("div", { className: "space-y-3", children: groups.map((group) => /* @__PURE__ */ jsxs13("section", { className: "rounded-lg border bg-background", children: [
|
|
2954
|
+
/* @__PURE__ */ jsx21("div", { className: "border-b px-3 py-2", children: /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between gap-3", children: [
|
|
2955
|
+
/* @__PURE__ */ jsxs13("div", { className: "min-w-0", children: [
|
|
2956
|
+
/* @__PURE__ */ jsx21("h4", { className: "truncate text-sm font-medium", children: group.label }),
|
|
2957
|
+
/* @__PURE__ */ jsx21("p", { className: "mt-0.5 line-clamp-2 text-xs text-muted-foreground", children: group.description })
|
|
2958
|
+
] }),
|
|
2959
|
+
/* @__PURE__ */ jsx21(Badge, { variant: "secondary", children: group.items.length })
|
|
2960
|
+
] }) }),
|
|
2961
|
+
/* @__PURE__ */ jsx21("div", { className: "divide-y", children: group.items.map((item) => /* @__PURE__ */ jsxs13(
|
|
2962
|
+
"button",
|
|
2963
|
+
{
|
|
2964
|
+
className: "w-full p-3 text-left transition-colors hover:bg-muted/40",
|
|
2965
|
+
onClick: () => onSelectNode(item.node),
|
|
2966
|
+
type: "button",
|
|
2967
|
+
children: [
|
|
2968
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
2969
|
+
/* @__PURE__ */ jsx21(Badge, { variant: "outline", children: formatLabel(item.edge.type) }),
|
|
2970
|
+
/* @__PURE__ */ jsx21(Badge, { variant: "secondary", children: item.direction === "out" ? "Outgoing" : "Incoming" }),
|
|
2971
|
+
/* @__PURE__ */ jsx21(LayerBadge, { layer: item.node.layer })
|
|
2972
|
+
] }),
|
|
2973
|
+
/* @__PURE__ */ jsx21("div", { className: "mt-2 text-sm font-medium", children: item.node.name }),
|
|
2974
|
+
/* @__PURE__ */ jsx21("p", { className: "mt-1 line-clamp-3 text-xs leading-5 text-muted-foreground", children: item.node.content || "-" })
|
|
2975
|
+
]
|
|
2976
|
+
},
|
|
2977
|
+
item.edge.id
|
|
2978
|
+
)) })
|
|
2979
|
+
] }, group.id)) });
|
|
2980
|
+
}
|
|
2981
|
+
function SimilarPanel({
|
|
2982
|
+
onSelectNode,
|
|
2983
|
+
similar
|
|
2984
|
+
}) {
|
|
2985
|
+
if (similar.length === 0) {
|
|
2986
|
+
return /* @__PURE__ */ jsx21(
|
|
2987
|
+
EmptyState,
|
|
2988
|
+
{
|
|
2989
|
+
icon: Sparkles,
|
|
2990
|
+
title: "No semantic neighbors",
|
|
2991
|
+
description: "Similar nodes appear here when the selected node has an embedding."
|
|
2992
|
+
}
|
|
2993
|
+
);
|
|
2994
|
+
}
|
|
2995
|
+
return /* @__PURE__ */ jsx21("div", { className: "space-y-2", children: similar.map((item) => /* @__PURE__ */ jsxs13(
|
|
2996
|
+
"button",
|
|
2997
|
+
{
|
|
2998
|
+
className: "w-full rounded-lg border bg-background p-3 text-left transition-colors hover:bg-muted/40",
|
|
2999
|
+
onClick: () => onSelectNode(item.node),
|
|
3000
|
+
type: "button",
|
|
3001
|
+
children: [
|
|
3002
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
3003
|
+
/* @__PURE__ */ jsx21(Badge, { variant: "secondary", children: formatSimilarityScore(item.similarity) }),
|
|
3004
|
+
/* @__PURE__ */ jsx21(LayerBadge, { layer: item.node.layer }),
|
|
3005
|
+
/* @__PURE__ */ jsx21(Badge, { variant: "outline", children: formatLabel(item.node.kind) })
|
|
3006
|
+
] }),
|
|
3007
|
+
/* @__PURE__ */ jsx21("div", { className: "mt-2 text-sm font-medium", children: item.node.name }),
|
|
3008
|
+
/* @__PURE__ */ jsx21("p", { className: "mt-1 line-clamp-3 text-xs leading-5 text-muted-foreground", children: item.node.content || "-" })
|
|
3009
|
+
]
|
|
3010
|
+
},
|
|
3011
|
+
item.node.id
|
|
3012
|
+
)) });
|
|
3013
|
+
}
|
|
3014
|
+
function EvidencePanel({ node }) {
|
|
3015
|
+
const sourceMessageIds = Array.isArray(node.sourceMessageIds) ? node.sourceMessageIds : [];
|
|
3016
|
+
return /* @__PURE__ */ jsxs13("div", { className: "rounded-lg border bg-background p-4", children: [
|
|
3017
|
+
/* @__PURE__ */ jsxs13("dl", { className: "grid gap-2 text-xs", children: [
|
|
3018
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Source", value: node.sourceType }),
|
|
3019
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Source ID", value: node.sourceId }),
|
|
3020
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Thread", value: node.threadId }),
|
|
3021
|
+
/* @__PURE__ */ jsx21(InspectorRow, { label: "Checkpoint", value: node.checkpointId })
|
|
3022
|
+
] }),
|
|
3023
|
+
/* @__PURE__ */ jsxs13("div", { className: "mt-4", children: [
|
|
3024
|
+
/* @__PURE__ */ jsx21("div", { className: "text-xs font-medium text-muted-foreground", children: "Source messages" }),
|
|
3025
|
+
/* @__PURE__ */ jsx21("div", { className: "mt-2 flex flex-wrap gap-1", children: sourceMessageIds.length ? sourceMessageIds.map((id) => /* @__PURE__ */ jsx21(Badge, { className: "max-w-full truncate", variant: "outline", children: id }, id)) : /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground", children: "-" }) })
|
|
3026
|
+
] })
|
|
3027
|
+
] });
|
|
3028
|
+
}
|
|
3029
|
+
function MatchBadges({ match }) {
|
|
3030
|
+
if (!match?.reasons.length) return null;
|
|
3031
|
+
return /* @__PURE__ */ jsx21("div", { className: "mt-2 flex flex-wrap gap-1", children: match.reasons.slice(0, 4).map((reason) => /* @__PURE__ */ jsx21(Badge, { className: "text-[10px]", variant: "outline", children: reason }, reason)) });
|
|
3032
|
+
}
|
|
2380
3033
|
function InspectorRow({
|
|
2381
3034
|
label,
|
|
2382
3035
|
value
|
|
@@ -2405,6 +3058,12 @@ function formatDateTime(value) {
|
|
|
2405
3058
|
if (Number.isNaN(date.getTime())) return value;
|
|
2406
3059
|
return date.toLocaleString();
|
|
2407
3060
|
}
|
|
3061
|
+
function formatNullableNumber(value) {
|
|
3062
|
+
return typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : "-";
|
|
3063
|
+
}
|
|
3064
|
+
function formatSimilarityScore(value) {
|
|
3065
|
+
return Number.isFinite(value) ? `Similarity ${value.toFixed(2)}` : "-";
|
|
3066
|
+
}
|
|
2408
3067
|
function emptyBrainResponse() {
|
|
2409
3068
|
return {
|
|
2410
3069
|
nodes: [],
|
|
@@ -2416,6 +3075,14 @@ function emptyBrainResponse() {
|
|
|
2416
3075
|
byKind: {},
|
|
2417
3076
|
byStatus: {}
|
|
2418
3077
|
},
|
|
3078
|
+
matches: {},
|
|
3079
|
+
related: [],
|
|
3080
|
+
similar: [],
|
|
3081
|
+
semantic: {
|
|
3082
|
+
requested: false,
|
|
3083
|
+
available: false,
|
|
3084
|
+
error: null
|
|
3085
|
+
},
|
|
2419
3086
|
pageInfo: {
|
|
2420
3087
|
limit: 0,
|
|
2421
3088
|
offset: 0,
|
|
@@ -4806,8 +5473,11 @@ function useCopilotzAdmin(options = {}) {
|
|
|
4806
5473
|
export {
|
|
4807
5474
|
ADMIN_GROUP_LABELS,
|
|
4808
5475
|
ADMIN_GROUP_ORDER,
|
|
5476
|
+
BRAIN_RELATION_GROUP_DEFINITIONS,
|
|
5477
|
+
BRAIN_VIEW_LABELS,
|
|
4809
5478
|
CopilotzAdmin,
|
|
4810
5479
|
EMPTY_USAGE_TOTALS,
|
|
5480
|
+
ENTITY_FOCUS_RELATION_TYPES,
|
|
4811
5481
|
EmptyState,
|
|
4812
5482
|
FilterBar,
|
|
4813
5483
|
InspectorPanel,
|
|
@@ -4836,11 +5506,16 @@ export {
|
|
|
4836
5506
|
formatNumber,
|
|
4837
5507
|
formatPercent,
|
|
4838
5508
|
formatUsageBucket,
|
|
5509
|
+
getBrainViewBaseFilters,
|
|
5510
|
+
getKnowledgeRelationGroups,
|
|
4839
5511
|
getUsageDimensionLabel,
|
|
4840
5512
|
getUsageGroupLabel,
|
|
4841
5513
|
getUsageMetricLabel,
|
|
4842
5514
|
getUsageRange,
|
|
4843
5515
|
getUsageTotalValue,
|
|
5516
|
+
getWorkRelationGroups,
|
|
5517
|
+
groupBrainRelationsByKind,
|
|
5518
|
+
isEntityBrainView,
|
|
4844
5519
|
mergeAdminConfig,
|
|
4845
5520
|
overviewModule,
|
|
4846
5521
|
participantsModule,
|