ltcai 6.6.0 → 7.0.0
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/README.md +32 -36
- package/docs/CHANGELOG.md +50 -2
- package/frontend/src/App.tsx +78 -3
- package/frontend/src/api/client.ts +5 -0
- package/frontend/src/features/brain/BrainConversation.tsx +182 -2
- package/frontend/src/features/brain/BrainHome.tsx +108 -1
- package/frontend/src/features/brain/types.ts +13 -0
- package/frontend/src/i18n.ts +80 -0
- package/frontend/src/routes.ts +31 -17
- package/frontend/src/styles.css +295 -0
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/package.json +1 -1
- package/scripts/brain_quality_eval.py +118 -0
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +84 -6
- package/static/app/assets/Act-DhLaHnrT.js +2 -0
- package/static/app/assets/Act-DhLaHnrT.js.map +1 -0
- package/static/app/assets/Brain-DS7NULyY.js +322 -0
- package/static/app/assets/Brain-DS7NULyY.js.map +1 -0
- package/static/app/assets/Capture-CAKouj52.js +2 -0
- package/static/app/assets/Capture-CAKouj52.js.map +1 -0
- package/static/app/assets/Library-B_hW4AwR.js +2 -0
- package/static/app/assets/Library-B_hW4AwR.js.map +1 -0
- package/static/app/assets/System-9OAoXWPz.js +2 -0
- package/static/app/assets/System-9OAoXWPz.js.map +1 -0
- package/static/app/assets/index-C-7aHabu.js +17 -0
- package/static/app/assets/index-C-7aHabu.js.map +1 -0
- package/static/app/assets/index-DKFpn5Kn.css +2 -0
- package/static/app/assets/primitives-DcO2H3yh.js +2 -0
- package/static/app/assets/primitives-DcO2H3yh.js.map +1 -0
- package/static/app/assets/textarea-DR2Tyy_6.js +2 -0
- package/static/app/assets/textarea-DR2Tyy_6.js.map +1 -0
- package/static/app/index.html +2 -2
- package/static/app/assets/index-C8toxDpv.css +0 -2
- package/static/app/assets/index-CbvcAQ6B.js +0 -16
- package/static/app/assets/index-CbvcAQ6B.js.map +0 -1
|
@@ -7,7 +7,7 @@ import { t } from "@/i18n";
|
|
|
7
7
|
import { BrainConversation } from "./BrainConversation";
|
|
8
8
|
import { buildBrainProof, buildBrainReadiness, buildMemoryFragments, currentModelName, parseKnowledgeGraph } from "./brainData";
|
|
9
9
|
import { DepthEmergence } from "./DepthEmergence";
|
|
10
|
-
import { DEPTHS, type BrainDepth, type MemoryFragment, type Message } from "./types";
|
|
10
|
+
import { DEPTHS, type BrainDepth, type BrainProof, type MemoryFragment, type Message, type MessageProof } from "./types";
|
|
11
11
|
|
|
12
12
|
export function BrainHome({
|
|
13
13
|
brainState,
|
|
@@ -134,6 +134,7 @@ export function BrainHome({
|
|
|
134
134
|
} else {
|
|
135
135
|
setMemoryFeedback(t(language, "brain.saved", { topics: knowledgeConcepts.length, memories: memoryFragments.length }));
|
|
136
136
|
setLastRecallQuery(text);
|
|
137
|
+
void attachAnswerProof(text);
|
|
137
138
|
}
|
|
138
139
|
} finally {
|
|
139
140
|
setStreaming(false);
|
|
@@ -144,6 +145,22 @@ export function BrainHome({
|
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
|
|
148
|
+
async function attachAnswerProof(query: string) {
|
|
149
|
+
const proofResult = await latticeApi.memoryBrainProof(query, 4);
|
|
150
|
+
const proof = buildBrainProof(proofResult.data, modelName);
|
|
151
|
+
const messageProof = toMessageProof(proof, query, modelName);
|
|
152
|
+
setMessages((items) => {
|
|
153
|
+
const next = [...items];
|
|
154
|
+
for (let index = next.length - 1; index >= 0; index -= 1) {
|
|
155
|
+
if (next[index].role === "assistant") {
|
|
156
|
+
next[index] = { ...next[index], proof: messageProof };
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return next;
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
147
164
|
async function uploadDocument(file: File) {
|
|
148
165
|
if (uploadingDocument) return;
|
|
149
166
|
|
|
@@ -169,6 +186,78 @@ export function BrainHome({
|
|
|
169
186
|
}
|
|
170
187
|
}
|
|
171
188
|
|
|
189
|
+
async function connectFolder(path: string) {
|
|
190
|
+
const target = path.trim();
|
|
191
|
+
if (!target) return;
|
|
192
|
+
setMemoryFeedback(t(language, "brain.ingest.folder.pending", { path: target }));
|
|
193
|
+
onBrainChange("recalling", 0.84);
|
|
194
|
+
const result = await latticeApi.connectFolder(target);
|
|
195
|
+
if (result.error || !result.ok) {
|
|
196
|
+
setMemoryFeedback(t(language, "brain.ingest.folder.failed", { reason: result.error || "unavailable" }));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
setMemoryFeedback(t(language, "brain.ingest.folder.saved", { path: target }));
|
|
200
|
+
setLastRecallQuery(target);
|
|
201
|
+
triggerBrainRecall();
|
|
202
|
+
void refreshBrainProof(target);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function ingestNote(note: string) {
|
|
206
|
+
const content = note.trim();
|
|
207
|
+
if (!content) return;
|
|
208
|
+
setMemoryFeedback(t(language, "brain.ingest.note.pending"));
|
|
209
|
+
onBrainChange("recalling", 0.84);
|
|
210
|
+
const result = await latticeApi.ingestNote(content, content.slice(0, 80));
|
|
211
|
+
if (result.error || !result.ok) {
|
|
212
|
+
setMemoryFeedback(t(language, "brain.ingest.note.failed", { reason: result.error || "unavailable" }));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
setMemoryFeedback(t(language, "brain.ingest.note.saved"));
|
|
216
|
+
setLastRecallQuery(content.slice(0, 120));
|
|
217
|
+
triggerBrainRecall();
|
|
218
|
+
void refreshBrainProof(content.slice(0, 120));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function ingestWeb(url: string) {
|
|
222
|
+
const target = url.trim();
|
|
223
|
+
if (!target) return;
|
|
224
|
+
setMemoryFeedback(t(language, "brain.ingest.web.pending", { url: target }));
|
|
225
|
+
onBrainChange("recalling", 0.84);
|
|
226
|
+
const result = await latticeApi.browserReadUrl(target);
|
|
227
|
+
if (result.error || !result.ok) {
|
|
228
|
+
setMemoryFeedback(t(language, "brain.ingest.web.failed", { reason: result.error || "unavailable" }));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
setMemoryFeedback(t(language, "brain.ingest.web.saved", { url: target }));
|
|
232
|
+
setLastRecallQuery(target);
|
|
233
|
+
triggerBrainRecall();
|
|
234
|
+
void refreshBrainProof(target);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function refreshBrainProof(query = lastRecallQuery) {
|
|
238
|
+
await Promise.all([
|
|
239
|
+
qc.invalidateQueries({ queryKey: ["memoryManager"] }),
|
|
240
|
+
qc.invalidateQueries({ queryKey: ["graph"] }),
|
|
241
|
+
qc.invalidateQueries({ queryKey: ["memoryBrainProof"] }),
|
|
242
|
+
]);
|
|
243
|
+
if (query.trim()) {
|
|
244
|
+
await attachAnswerProof(query);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function verifyModelContinuity() {
|
|
249
|
+
const lastUserMessage = [...messages].reverse().find((message: Message) => message.role === "user");
|
|
250
|
+
const query = lastRecallQuery || lastUserMessage?.content || "";
|
|
251
|
+
if (!query.trim()) {
|
|
252
|
+
setMemoryFeedback(t(language, "brain.modelDemo.needQuestion"));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
setMemoryFeedback(t(language, "brain.modelDemo.checking", { model: modelName }));
|
|
256
|
+
await attachAnswerProof(query);
|
|
257
|
+
setLastRecallQuery(query);
|
|
258
|
+
setMemoryFeedback(t(language, "brain.modelDemo.done", { model: modelName }));
|
|
259
|
+
}
|
|
260
|
+
|
|
172
261
|
function deepen() {
|
|
173
262
|
setExplorationDepth((depth) => {
|
|
174
263
|
const next = Math.min(5, depth + 1) as BrainDepth;
|
|
@@ -285,8 +374,26 @@ export function BrainHome({
|
|
|
285
374
|
onDraftChange={setDraft}
|
|
286
375
|
onImageDataChange={setImageData}
|
|
287
376
|
onUploadDocument={(file) => void uploadDocument(file)}
|
|
377
|
+
onConnectFolder={(path) => void connectFolder(path)}
|
|
378
|
+
onIngestNote={(note) => void ingestNote(note)}
|
|
379
|
+
onIngestWeb={(url) => void ingestWeb(url)}
|
|
380
|
+
onVerifyModelContinuity={() => void verifyModelContinuity()}
|
|
288
381
|
onSend={() => void send()}
|
|
289
382
|
/>
|
|
290
383
|
</main>
|
|
291
384
|
);
|
|
292
385
|
}
|
|
386
|
+
|
|
387
|
+
function toMessageProof(proof: BrainProof, query: string, fallbackModelName: string): MessageProof {
|
|
388
|
+
return {
|
|
389
|
+
query,
|
|
390
|
+
model: proof.modelContinuity.activeModel || fallbackModelName,
|
|
391
|
+
provenAcrossModels: proof.modelContinuity.proven && proof.claims.keepsContextAcrossModels,
|
|
392
|
+
citations: proof.recall.items.slice(0, 4).map((item) => ({
|
|
393
|
+
id: item.id,
|
|
394
|
+
source: item.source,
|
|
395
|
+
title: item.title,
|
|
396
|
+
snippet: item.snippet,
|
|
397
|
+
})),
|
|
398
|
+
};
|
|
399
|
+
}
|
|
@@ -6,6 +6,19 @@ export type BrainDepth = 1 | 2 | 3 | 4 | 5;
|
|
|
6
6
|
export type Message = {
|
|
7
7
|
role: "user" | "assistant";
|
|
8
8
|
content: string;
|
|
9
|
+
proof?: MessageProof;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type MessageProof = {
|
|
13
|
+
query: string;
|
|
14
|
+
model: string;
|
|
15
|
+
provenAcrossModels: boolean;
|
|
16
|
+
citations: Array<{
|
|
17
|
+
id: string;
|
|
18
|
+
source: string;
|
|
19
|
+
title: string;
|
|
20
|
+
snippet: string;
|
|
21
|
+
}>;
|
|
9
22
|
};
|
|
10
23
|
|
|
11
24
|
export type MemoryFragment = {
|
package/frontend/src/i18n.ts
CHANGED
|
@@ -34,6 +34,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
34
34
|
"brain.depthRail.aria": "Brain 깊이 진행 상태",
|
|
35
35
|
"brain.aria.conversation": "대화",
|
|
36
36
|
"brain.aria.ownership": "Brain 소유 보장",
|
|
37
|
+
"brain.aria.actions": "Brain 주요 작업",
|
|
37
38
|
"brain.aria.starterPrompts": "시작 프롬프트",
|
|
38
39
|
"brain.aria.overview": "Brain 한눈에 보기",
|
|
39
40
|
"brain.aria.graph": "지식 그래프",
|
|
@@ -42,6 +43,10 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
42
43
|
"brain.portable": "이동 가능",
|
|
43
44
|
"brain.private": "개인 소유",
|
|
44
45
|
"brain.admin": "관리자 콘솔",
|
|
46
|
+
"brain.action.add": "넣기",
|
|
47
|
+
"brain.action.find": "찾기",
|
|
48
|
+
"brain.action.model": "모델",
|
|
49
|
+
"brain.action.settings": "설정",
|
|
45
50
|
"brain.empty.kicker": "내 오래가는 기억",
|
|
46
51
|
"brain.empty.title": "잊으면 안 되는 맥락부터 말해 주세요.",
|
|
47
52
|
"brain.empty.body": "문서, 대화, 프로젝트, 결정이 이 컴퓨터의 Brain에 쌓이고 나중에 주제와 관계로 다시 보입니다.",
|
|
@@ -60,6 +65,26 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
60
65
|
"brain.upload.pending": "{name}을 Brain에 넣는 중입니다.",
|
|
61
66
|
"brain.upload.saved": "{name}이 Brain에 저장됐습니다.",
|
|
62
67
|
"brain.upload.failed": "문서를 넣지 못했습니다: {reason}",
|
|
68
|
+
"brain.ingest.aria": "Brain에 넣기",
|
|
69
|
+
"brain.ingest.kicker": "5분 안에 Brain 만들기",
|
|
70
|
+
"brain.ingest.title": "파일, 폴더, 노트, 웹을 바로 넣으세요.",
|
|
71
|
+
"brain.ingest.file": "파일 넣기",
|
|
72
|
+
"brain.ingest.file.detail": "PDF, 문서, 표, 메모",
|
|
73
|
+
"brain.ingest.folder": "폴더 넣기",
|
|
74
|
+
"brain.ingest.folder.placeholder": "로컬 폴더 경로",
|
|
75
|
+
"brain.ingest.note": "노트 넣기",
|
|
76
|
+
"brain.ingest.note.placeholder": "결정이나 맥락을 붙여넣기",
|
|
77
|
+
"brain.ingest.web": "웹 넣기",
|
|
78
|
+
"brain.ingest.web.placeholder": "https://...",
|
|
79
|
+
"brain.ingest.folder.pending": "{path} 폴더를 Brain에 연결 중입니다.",
|
|
80
|
+
"brain.ingest.folder.saved": "{path} 폴더가 Brain에 연결됐습니다.",
|
|
81
|
+
"brain.ingest.folder.failed": "폴더를 넣지 못했습니다: {reason}",
|
|
82
|
+
"brain.ingest.note.pending": "노트를 Brain에 저장 중입니다.",
|
|
83
|
+
"brain.ingest.note.saved": "노트가 Brain에 저장됐습니다.",
|
|
84
|
+
"brain.ingest.note.failed": "노트를 넣지 못했습니다: {reason}",
|
|
85
|
+
"brain.ingest.web.pending": "{url}을 읽어 Brain에 넣는 중입니다.",
|
|
86
|
+
"brain.ingest.web.saved": "{url}이 Brain에 저장됐습니다.",
|
|
87
|
+
"brain.ingest.web.failed": "웹 페이지를 넣지 못했습니다: {reason}",
|
|
63
88
|
"brain.image": "이미지",
|
|
64
89
|
"brain.unavailable": "지금은 답할 수 없음",
|
|
65
90
|
"brain.imageAttached": "이미지 첨부됨",
|
|
@@ -99,6 +124,21 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
99
124
|
"brain.proof.recallEmpty.detail": "아직 저장된 기억이 없어서 가짜 예시는 보여주지 않습니다.",
|
|
100
125
|
"brain.proof.recallPending": "기억은 저장됐고 recall 증거를 준비 중입니다.",
|
|
101
126
|
"brain.proof.recallPending.detail": "인덱싱이 끝나면 이 자리에서 실제 기억을 다시 보여줍니다.",
|
|
127
|
+
"brain.modelDemo.aria": "모델 교체 증거",
|
|
128
|
+
"brain.modelDemo.kicker": "모델 독립 Brain",
|
|
129
|
+
"brain.modelDemo.proven": "현재 기억은 모델 밖에 남아 있습니다.",
|
|
130
|
+
"brain.modelDemo.pending": "첫 기억이 저장되면 모델 교체 증거가 생깁니다.",
|
|
131
|
+
"brain.modelDemo.detail": "현재 모델: {model}. 같은 질문으로 Brain 증거를 다시 확인할 수 있습니다.",
|
|
132
|
+
"brain.modelDemo.verify": "같은 증거 확인",
|
|
133
|
+
"brain.modelDemo.change": "모델 바꾸기",
|
|
134
|
+
"brain.modelDemo.needQuestion": "먼저 질문하거나 기억을 넣으면 같은 증거를 다시 확인할 수 있습니다.",
|
|
135
|
+
"brain.modelDemo.checking": "{model}에서 같은 Brain 증거를 다시 확인 중입니다.",
|
|
136
|
+
"brain.modelDemo.done": "{model}에서도 같은 Brain 증거를 확인했습니다.",
|
|
137
|
+
"brain.answerProof.aria": "답변 출처와 Memory proof",
|
|
138
|
+
"brain.answerProof.title": "Memory proof + source citation",
|
|
139
|
+
"brain.answerProof.modelProven": "{model} 밖에 남은 Brain 증거",
|
|
140
|
+
"brain.answerProof.modelPending": "{model} 응답 · 증거 저장 대기",
|
|
141
|
+
"brain.answerProof.empty": "아직 연결된 출처가 없습니다. 기억이 인덱싱되면 여기에 표시됩니다.",
|
|
102
142
|
"brain.memory.empty.kicker": "첫 기억",
|
|
103
143
|
"brain.memory.empty": "기억이 조용합니다.",
|
|
104
144
|
"brain.knowledge.empty": "지식이 형성되는 중입니다.",
|
|
@@ -388,6 +428,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
388
428
|
"brain.depthRail.aria": "Brain depth progress",
|
|
389
429
|
"brain.aria.conversation": "Conversation",
|
|
390
430
|
"brain.aria.ownership": "Brain ownership guarantees",
|
|
431
|
+
"brain.aria.actions": "Brain primary actions",
|
|
391
432
|
"brain.aria.starterPrompts": "Starter prompts",
|
|
392
433
|
"brain.aria.overview": "Brain overview",
|
|
393
434
|
"brain.aria.graph": "Knowledge Graph",
|
|
@@ -396,6 +437,10 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
396
437
|
"brain.portable": "Portable",
|
|
397
438
|
"brain.private": "Private",
|
|
398
439
|
"brain.admin": "Admin Console",
|
|
440
|
+
"brain.action.add": "Add",
|
|
441
|
+
"brain.action.find": "Find",
|
|
442
|
+
"brain.action.model": "Model",
|
|
443
|
+
"brain.action.settings": "Settings",
|
|
399
444
|
"brain.empty.kicker": "Durable memory",
|
|
400
445
|
"brain.empty.title": "Start with context that should not be forgotten.",
|
|
401
446
|
"brain.empty.body": "Documents, conversations, projects, and decisions accumulate in the Brain on this computer, then reappear as topics and relationships.",
|
|
@@ -414,6 +459,26 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
414
459
|
"brain.upload.pending": "Adding {name} to Brain.",
|
|
415
460
|
"brain.upload.saved": "{name} was saved to Brain.",
|
|
416
461
|
"brain.upload.failed": "Could not add the document: {reason}",
|
|
462
|
+
"brain.ingest.aria": "Add to Brain",
|
|
463
|
+
"brain.ingest.kicker": "Build a Brain in 5 minutes",
|
|
464
|
+
"brain.ingest.title": "Add files, folders, notes, and web pages immediately.",
|
|
465
|
+
"brain.ingest.file": "Add file",
|
|
466
|
+
"brain.ingest.file.detail": "PDFs, docs, tables, notes",
|
|
467
|
+
"brain.ingest.folder": "Add folder",
|
|
468
|
+
"brain.ingest.folder.placeholder": "Local folder path",
|
|
469
|
+
"brain.ingest.note": "Add note",
|
|
470
|
+
"brain.ingest.note.placeholder": "Paste a decision or context",
|
|
471
|
+
"brain.ingest.web": "Add web",
|
|
472
|
+
"brain.ingest.web.placeholder": "https://...",
|
|
473
|
+
"brain.ingest.folder.pending": "Connecting {path} to Brain.",
|
|
474
|
+
"brain.ingest.folder.saved": "{path} is connected to Brain.",
|
|
475
|
+
"brain.ingest.folder.failed": "Could not add the folder: {reason}",
|
|
476
|
+
"brain.ingest.note.pending": "Saving note to Brain.",
|
|
477
|
+
"brain.ingest.note.saved": "Note was saved to Brain.",
|
|
478
|
+
"brain.ingest.note.failed": "Could not add the note: {reason}",
|
|
479
|
+
"brain.ingest.web.pending": "Reading {url} into Brain.",
|
|
480
|
+
"brain.ingest.web.saved": "{url} was saved to Brain.",
|
|
481
|
+
"brain.ingest.web.failed": "Could not add the web page: {reason}",
|
|
417
482
|
"brain.image": "Image",
|
|
418
483
|
"brain.unavailable": "Unavailable",
|
|
419
484
|
"brain.imageAttached": "Image attached",
|
|
@@ -453,6 +518,21 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
453
518
|
"brain.proof.recallEmpty.detail": "No saved memory yet, so Lattice does not show a fake example.",
|
|
454
519
|
"brain.proof.recallPending": "Memory is saved; recall proof is preparing.",
|
|
455
520
|
"brain.proof.recallPending.detail": "When indexing finishes, this slot shows the actual memory Brain can bring back.",
|
|
521
|
+
"brain.modelDemo.aria": "Model switch proof",
|
|
522
|
+
"brain.modelDemo.kicker": "Model-independent Brain",
|
|
523
|
+
"brain.modelDemo.proven": "This memory lives outside the model.",
|
|
524
|
+
"brain.modelDemo.pending": "After the first memory is saved, model-switch proof appears.",
|
|
525
|
+
"brain.modelDemo.detail": "Current model: {model}. Recheck the same question against Brain evidence.",
|
|
526
|
+
"brain.modelDemo.verify": "Recheck same evidence",
|
|
527
|
+
"brain.modelDemo.change": "Switch model",
|
|
528
|
+
"brain.modelDemo.needQuestion": "Ask a question or add memory first, then recheck the same evidence.",
|
|
529
|
+
"brain.modelDemo.checking": "Rechecking the same Brain evidence with {model}.",
|
|
530
|
+
"brain.modelDemo.done": "The same Brain evidence is visible with {model}.",
|
|
531
|
+
"brain.answerProof.aria": "Answer sources and memory proof",
|
|
532
|
+
"brain.answerProof.title": "Memory proof + source citation",
|
|
533
|
+
"brain.answerProof.modelProven": "Brain evidence outside {model}",
|
|
534
|
+
"brain.answerProof.modelPending": "{model} response · evidence pending",
|
|
535
|
+
"brain.answerProof.empty": "No linked source yet. Indexed memory appears here.",
|
|
456
536
|
"brain.memory.empty.kicker": "First memory",
|
|
457
537
|
"brain.memory.empty": "Memory is quiet",
|
|
458
538
|
"brain.knowledge.empty": "Knowledge is forming",
|
package/frontend/src/routes.ts
CHANGED
|
@@ -9,19 +9,29 @@ import {
|
|
|
9
9
|
|
|
10
10
|
export type PrimaryRoute = "brain" | "memory" | "capture" | "act" | "library" | "system";
|
|
11
11
|
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
{ id: "
|
|
16
|
-
{ id: "
|
|
17
|
-
{ id: "
|
|
18
|
-
{ id: "
|
|
12
|
+
export type RouteTarget = { primary: PrimaryRoute; tab?: string };
|
|
13
|
+
|
|
14
|
+
export const productShellRoutes = [
|
|
15
|
+
{ id: "brain", path: "brain", label: "Lattice Brain", icon: Brain, description: "Talk with your living Brain" },
|
|
16
|
+
{ id: "capture", path: "capture", label: "Files", icon: FolderInput, description: "Bring in files, folders, and pages" },
|
|
17
|
+
{ id: "memory", path: "knowledge-graph", label: "Graph", icon: Database, description: "Search and inspect Brain knowledge" },
|
|
18
|
+
{ id: "library", path: "models", label: "Models", icon: Library, description: "Choose the local model powering your Brain" },
|
|
19
|
+
{ id: "system", path: "settings", label: "Settings", icon: Settings, description: "Keep your Brain safe and portable" },
|
|
20
|
+
{ id: "act", path: "review", label: "Act", icon: Workflow, description: "Turn goals into supervised runs" },
|
|
19
21
|
] as const;
|
|
20
22
|
|
|
21
|
-
export const
|
|
23
|
+
export const directProductRoutes: Record<string, RouteTarget> = {
|
|
24
|
+
brain: { primary: "brain", tab: "conversation" },
|
|
25
|
+
capture: { primary: "capture", tab: "files" },
|
|
26
|
+
"knowledge-graph": { primary: "brain", tab: "graph" },
|
|
27
|
+
models: { primary: "library", tab: "models" },
|
|
28
|
+
settings: { primary: "system", tab: "settings" },
|
|
29
|
+
review: { primary: "act", tab: "review" },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const compatibilityRouteAliases: Record<string, RouteTarget> = {
|
|
22
33
|
home: { primary: "brain", tab: "conversation" },
|
|
23
34
|
onboarding: { primary: "system", tab: "account" },
|
|
24
|
-
"knowledge-graph": { primary: "brain", tab: "graph" },
|
|
25
35
|
"hybrid-search": { primary: "brain", tab: "knowledge" },
|
|
26
36
|
memory: { primary: "memory", tab: "memory" },
|
|
27
37
|
ask: { primary: "brain", tab: "conversation" },
|
|
@@ -31,13 +41,11 @@ export const routeAliases: Record<string, { primary: PrimaryRoute; tab?: string
|
|
|
31
41
|
"my-computer": { primary: "capture", tab: "local" },
|
|
32
42
|
agents: { primary: "act", tab: "agents" },
|
|
33
43
|
runs: { primary: "act", tab: "runs" },
|
|
34
|
-
review: { primary: "act", tab: "review" },
|
|
35
44
|
"review-center": { primary: "act", tab: "review" },
|
|
36
45
|
workflows: { primary: "act", tab: "workflows" },
|
|
37
46
|
planning: { primary: "act", tab: "agents" },
|
|
38
47
|
hooks: { primary: "act", tab: "hooks" },
|
|
39
48
|
tools: { primary: "act", tab: "tools" },
|
|
40
|
-
models: { primary: "library", tab: "models" },
|
|
41
49
|
skills: { primary: "library", tab: "skills" },
|
|
42
50
|
mcp: { primary: "library", tab: "mcp" },
|
|
43
51
|
marketplace: { primary: "library", tab: "marketplace" },
|
|
@@ -55,21 +63,27 @@ export const routeAliases: Record<string, { primary: PrimaryRoute; tab?: string
|
|
|
55
63
|
"admin/private-vpc": { primary: "system", tab: "admin" },
|
|
56
64
|
};
|
|
57
65
|
|
|
66
|
+
export const primaryRoutes = productShellRoutes;
|
|
67
|
+
export const routeAliases = compatibilityRouteAliases;
|
|
68
|
+
|
|
58
69
|
export const commandRoutes = [
|
|
59
|
-
{ key: "brain", label: "Brain", icon: Brain },
|
|
60
|
-
{ key: "memory", label: "Memory", icon: Database },
|
|
70
|
+
{ key: "brain", label: "Lattice Brain", icon: Brain },
|
|
61
71
|
{ key: "files", label: "Files", icon: FolderInput },
|
|
62
|
-
{ key: "
|
|
72
|
+
{ key: "knowledge-graph", label: "Graph", icon: Database },
|
|
63
73
|
{ key: "models", label: "Models", icon: Library },
|
|
64
74
|
{ key: "settings", label: "Settings", icon: Settings },
|
|
75
|
+
{ key: "review", label: "Act", icon: Workflow },
|
|
65
76
|
];
|
|
66
77
|
|
|
67
78
|
export function parseHash() {
|
|
68
79
|
const raw = window.location.hash.replace(/^#\/?/, "").replace(/^\/+/, "");
|
|
69
80
|
const path = raw || "brain";
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
81
|
+
const normalized = path.split("?")[0];
|
|
82
|
+
const direct = directProductRoutes[normalized];
|
|
83
|
+
if (direct) return { ...direct, path };
|
|
84
|
+
const primary = productShellRoutes.find((route) => route.id === normalized);
|
|
85
|
+
if (primary) return { primary: primary.id as PrimaryRoute, tab: undefined, path };
|
|
86
|
+
const aliased = compatibilityRouteAliases[normalized];
|
|
73
87
|
return { primary: aliased?.primary || "brain", tab: aliased?.tab, path };
|
|
74
88
|
}
|
|
75
89
|
|