ltcai 6.5.0 → 6.7.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 +35 -35
- package/docs/CHANGELOG.md +59 -2
- package/frontend/openapi.json +65 -1
- package/frontend/src/App.tsx +78 -3
- package/frontend/src/api/client.ts +1 -0
- package/frontend/src/api/openapi.ts +86 -0
- package/frontend/src/features/brain/BrainComposer.tsx +20 -1
- package/frontend/src/features/brain/BrainConversation.tsx +57 -4
- package/frontend/src/features/brain/BrainHome.tsx +41 -1
- package/frontend/src/features/brain/BrainOverviewPanel.tsx +62 -1
- package/frontend/src/features/brain/brainData.ts +54 -1
- package/frontend/src/features/brain/types.ts +37 -0
- package/frontend/src/i18n.ts +54 -0
- package/frontend/src/routes.ts +31 -17
- package/frontend/src/styles.css +216 -0
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/graph/ingest.py +41 -6
- package/lattice_brain/ingestion.py +1 -0
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/knowledge_graph.py +11 -0
- package/latticeai/api/memory.py +14 -0
- package/latticeai/app_factory.py +2 -0
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/runtime/chat_wiring.py +2 -0
- package/latticeai/runtime/router_registration.py +3 -0
- package/latticeai/services/memory_service.py +122 -2
- package/latticeai/services/router_context.py +1 -0
- package/latticeai/services/upload_service.py +12 -0
- package/package.json +1 -1
- 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-DGN37eR4.js +2 -0
- package/static/app/assets/Act-DGN37eR4.js.map +1 -0
- package/static/app/assets/Brain-HDcIwPHW.js +322 -0
- package/static/app/assets/Brain-HDcIwPHW.js.map +1 -0
- package/static/app/assets/Capture--eZfb_Ex.js +2 -0
- package/static/app/assets/Capture--eZfb_Ex.js.map +1 -0
- package/static/app/assets/Library-BbagRFyd.js +2 -0
- package/static/app/assets/Library-BbagRFyd.js.map +1 -0
- package/static/app/assets/System-C6pd3Mp_.js +2 -0
- package/static/app/assets/System-C6pd3Mp_.js.map +1 -0
- package/static/app/assets/index-C950aES_.js +17 -0
- package/static/app/assets/index-C950aES_.js.map +1 -0
- package/static/app/assets/index-ztppMg0c.css +2 -0
- package/static/app/assets/primitives-Bcm5lZRu.js +2 -0
- package/static/app/assets/primitives-Bcm5lZRu.js.map +1 -0
- package/static/app/assets/textarea-C2PLu6_O.js +2 -0
- package/static/app/assets/textarea-C2PLu6_O.js.map +1 -0
- package/static/app/index.html +2 -2
- package/static/app/assets/index-C1J_1441.js +0 -16
- package/static/app/assets/index-C1J_1441.js.map +0 -1
- package/static/app/assets/index-CdCVz_i4.css +0 -2
|
@@ -5,7 +5,7 @@ import { type BrainState, LivingBrain, triggerBrainRecall } from "@/components/L
|
|
|
5
5
|
import { useAppStore } from "@/store/appStore";
|
|
6
6
|
import { t } from "@/i18n";
|
|
7
7
|
import { BrainConversation } from "./BrainConversation";
|
|
8
|
-
import { buildBrainReadiness, buildMemoryFragments, currentModelName, parseKnowledgeGraph } from "./brainData";
|
|
8
|
+
import { buildBrainProof, buildBrainReadiness, buildMemoryFragments, currentModelName, parseKnowledgeGraph } from "./brainData";
|
|
9
9
|
import { DepthEmergence } from "./DepthEmergence";
|
|
10
10
|
import { DEPTHS, type BrainDepth, type MemoryFragment, type Message } from "./types";
|
|
11
11
|
|
|
@@ -29,6 +29,8 @@ export function BrainHome({
|
|
|
29
29
|
const [graphSearch, setGraphSearch] = React.useState("");
|
|
30
30
|
const [selectedGraphId, setSelectedGraphId] = React.useState<string | null>(null);
|
|
31
31
|
const [memoryFeedback, setMemoryFeedback] = React.useState<string | null>(null);
|
|
32
|
+
const [uploadingDocument, setUploadingDocument] = React.useState(false);
|
|
33
|
+
const [lastRecallQuery, setLastRecallQuery] = React.useState("");
|
|
32
34
|
const streamRef = React.useRef<HTMLDivElement>(null);
|
|
33
35
|
const recallTimerRef = React.useRef<number | null>(null);
|
|
34
36
|
|
|
@@ -36,6 +38,10 @@ export function BrainHome({
|
|
|
36
38
|
const historyQ = useQuery({ queryKey: ["chatHistory"], queryFn: latticeApi.chatHistory });
|
|
37
39
|
const graphQ = useQuery({ queryKey: ["graph"], queryFn: latticeApi.graph });
|
|
38
40
|
const modelsQ = useQuery({ queryKey: ["models"], queryFn: latticeApi.models });
|
|
41
|
+
const brainProofQ = useQuery({
|
|
42
|
+
queryKey: ["memoryBrainProof", lastRecallQuery],
|
|
43
|
+
queryFn: () => latticeApi.memoryBrainProof(lastRecallQuery, 3),
|
|
44
|
+
});
|
|
39
45
|
|
|
40
46
|
const memoryFragments = React.useMemo(
|
|
41
47
|
() => buildMemoryFragments(memoriesQ.data?.data, historyQ.data?.data),
|
|
@@ -55,6 +61,10 @@ export function BrainHome({
|
|
|
55
61
|
[graphModel.edges],
|
|
56
62
|
);
|
|
57
63
|
const modelName = React.useMemo(() => currentModelName(modelsQ.data?.data), [modelsQ.data]);
|
|
64
|
+
const brainProof = React.useMemo(
|
|
65
|
+
() => buildBrainProof(brainProofQ.data?.data, modelName),
|
|
66
|
+
[brainProofQ.data, modelName],
|
|
67
|
+
);
|
|
58
68
|
const currentDepth = DEPTHS[explorationDepth - 1];
|
|
59
69
|
const starterPrompts = React.useMemo(
|
|
60
70
|
() => [
|
|
@@ -123,12 +133,39 @@ export function BrainHome({
|
|
|
123
133
|
});
|
|
124
134
|
} else {
|
|
125
135
|
setMemoryFeedback(t(language, "brain.saved", { topics: knowledgeConcepts.length, memories: memoryFragments.length }));
|
|
136
|
+
setLastRecallQuery(text);
|
|
126
137
|
}
|
|
127
138
|
} finally {
|
|
128
139
|
setStreaming(false);
|
|
129
140
|
void qc.invalidateQueries({ queryKey: ["chatHistory"] });
|
|
130
141
|
void qc.invalidateQueries({ queryKey: ["memoryManager"] });
|
|
131
142
|
void qc.invalidateQueries({ queryKey: ["graph"] });
|
|
143
|
+
void qc.invalidateQueries({ queryKey: ["memoryBrainProof"] });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function uploadDocument(file: File) {
|
|
148
|
+
if (uploadingDocument) return;
|
|
149
|
+
|
|
150
|
+
setUploadingDocument(true);
|
|
151
|
+
setMemoryFeedback(t(language, "brain.upload.pending", { name: file.name }));
|
|
152
|
+
onBrainChange("recalling", 0.86);
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const result = await latticeApi.uploadDocument(file);
|
|
156
|
+
if (result.error) {
|
|
157
|
+
setMemoryFeedback(t(language, "brain.upload.failed", { reason: result.error }));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
setMemoryFeedback(t(language, "brain.upload.saved", { name: file.name }));
|
|
162
|
+
setLastRecallQuery(file.name);
|
|
163
|
+
triggerBrainRecall();
|
|
164
|
+
void qc.invalidateQueries({ queryKey: ["memoryManager"] });
|
|
165
|
+
void qc.invalidateQueries({ queryKey: ["graph"] });
|
|
166
|
+
void qc.invalidateQueries({ queryKey: ["memoryBrainProof"] });
|
|
167
|
+
} finally {
|
|
168
|
+
setUploadingDocument(false);
|
|
132
169
|
}
|
|
133
170
|
}
|
|
134
171
|
|
|
@@ -242,9 +279,12 @@ export function BrainHome({
|
|
|
242
279
|
memories={memoryFragments}
|
|
243
280
|
concepts={knowledgeConcepts}
|
|
244
281
|
readiness={brainReadiness}
|
|
282
|
+
proof={brainProof}
|
|
283
|
+
uploadingDocument={uploadingDocument}
|
|
245
284
|
onOpenDepth={jumpToDepth}
|
|
246
285
|
onDraftChange={setDraft}
|
|
247
286
|
onImageDataChange={setImageData}
|
|
287
|
+
onUploadDocument={(file) => void uploadDocument(file)}
|
|
248
288
|
onSend={() => void send()}
|
|
249
289
|
/>
|
|
250
290
|
</main>
|
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { BrainCircuit, DatabaseZap, Repeat2 } from "lucide-react";
|
|
2
3
|
import { t } from "@/i18n";
|
|
3
4
|
import { useAppStore } from "@/store/appStore";
|
|
4
|
-
import type { BrainDepth, BrainReadiness, KnowledgeConcept, MemoryFragment } from "./types";
|
|
5
|
+
import type { BrainDepth, BrainProof, BrainReadiness, KnowledgeConcept, MemoryFragment } from "./types";
|
|
5
6
|
|
|
6
7
|
export function BrainOverviewPanel({
|
|
7
8
|
memories,
|
|
8
9
|
concepts,
|
|
9
10
|
readiness,
|
|
11
|
+
proof,
|
|
10
12
|
onOpenDepth,
|
|
11
13
|
}: {
|
|
12
14
|
memories: MemoryFragment[];
|
|
13
15
|
concepts: KnowledgeConcept[];
|
|
14
16
|
readiness: BrainReadiness;
|
|
17
|
+
proof: BrainProof;
|
|
15
18
|
onOpenDepth: (depth: BrainDepth) => void;
|
|
16
19
|
}) {
|
|
17
20
|
const language = useAppStore((state) => state.language);
|
|
18
21
|
const recent = memories.slice(0, 3);
|
|
19
22
|
const older = memories.slice(3, 6);
|
|
20
23
|
const topics = concepts.slice(0, 4);
|
|
24
|
+
const hasDurableProof = proof.proofs.hasDurableEvidence || proof.modelContinuity.proven;
|
|
25
|
+
const hasRecallProof = proof.recall.items.length > 0;
|
|
26
|
+
const modelProofValue = proof.modelContinuity.proven && proof.claims.keepsContextAcrossModels
|
|
27
|
+
? proof.modelContinuity.activeModel || t(language, "brain.proof.noModel")
|
|
28
|
+
: t(language, "brain.proof.modelPending");
|
|
21
29
|
|
|
22
30
|
return (
|
|
23
31
|
<section className="brain-overview-panel" aria-label={t(language, "brain.aria.overview")}>
|
|
@@ -60,10 +68,63 @@ export function BrainOverviewPanel({
|
|
|
60
68
|
{t(language, readiness.actionKey)}
|
|
61
69
|
</button>
|
|
62
70
|
</div>
|
|
71
|
+
<div className="brain-proof-strip" aria-label={t(language, "brain.proof.aria")}>
|
|
72
|
+
<BrainProofPoint
|
|
73
|
+
icon={<DatabaseZap className="h-4 w-4" />}
|
|
74
|
+
label={t(language, "brain.proof.context")}
|
|
75
|
+
value={hasDurableProof
|
|
76
|
+
? t(language, "brain.proof.contextValue", { count: proof.proofs.durableItems })
|
|
77
|
+
: t(language, "brain.proof.contextEmpty")}
|
|
78
|
+
/>
|
|
79
|
+
<BrainProofPoint
|
|
80
|
+
icon={<Repeat2 className="h-4 w-4" />}
|
|
81
|
+
label={t(language, "brain.proof.model")}
|
|
82
|
+
value={modelProofValue}
|
|
83
|
+
/>
|
|
84
|
+
<BrainProofPoint
|
|
85
|
+
icon={<BrainCircuit className="h-4 w-4" />}
|
|
86
|
+
label={t(language, "brain.proof.store")}
|
|
87
|
+
value={t(language, "brain.proof.storeValue", {
|
|
88
|
+
topics: proof.proofs.graphConcepts,
|
|
89
|
+
vectors: proof.proofs.vectorItems,
|
|
90
|
+
})}
|
|
91
|
+
/>
|
|
92
|
+
</div>
|
|
93
|
+
{hasRecallProof ? (
|
|
94
|
+
<button type="button" className="brain-recall-proof" onClick={() => onOpenDepth(2)}>
|
|
95
|
+
<span>{t(language, "brain.proof.recall")}</span>
|
|
96
|
+
<strong>{proof.recall.items[0].title}</strong>
|
|
97
|
+
<small>{proof.recall.items[0].snippet || proof.recall.query}</small>
|
|
98
|
+
</button>
|
|
99
|
+
) : (
|
|
100
|
+
<div className="brain-recall-proof is-empty" role="status">
|
|
101
|
+
<span>{t(language, "brain.proof.recallEmpty.kicker")}</span>
|
|
102
|
+
<strong>{t(language, hasDurableProof ? "brain.proof.recallPending" : "brain.proof.recallEmpty.title")}</strong>
|
|
103
|
+
<small>{t(language, hasDurableProof ? "brain.proof.recallPending.detail" : "brain.proof.recallEmpty.detail")}</small>
|
|
104
|
+
</div>
|
|
105
|
+
)}
|
|
63
106
|
</section>
|
|
64
107
|
);
|
|
65
108
|
}
|
|
66
109
|
|
|
110
|
+
function BrainProofPoint({
|
|
111
|
+
icon,
|
|
112
|
+
label,
|
|
113
|
+
value,
|
|
114
|
+
}: {
|
|
115
|
+
icon: React.ReactNode;
|
|
116
|
+
label: string;
|
|
117
|
+
value: string;
|
|
118
|
+
}) {
|
|
119
|
+
return (
|
|
120
|
+
<div className="brain-proof-point">
|
|
121
|
+
{icon}
|
|
122
|
+
<span>{label}</span>
|
|
123
|
+
<strong>{value}</strong>
|
|
124
|
+
</div>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
67
128
|
function BrainOverviewColumn({
|
|
68
129
|
title,
|
|
69
130
|
empty,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { asArray } from "@/lib/utils";
|
|
2
|
-
import type { ApiRecord, BrainDepth, BrainReadiness, KnowledgeConcept, KnowledgeGraphModel, MemoryFragment, RelationshipThread } from "./types";
|
|
2
|
+
import type { ApiRecord, BrainDepth, BrainProof, BrainReadiness, KnowledgeConcept, KnowledgeGraphModel, MemoryFragment, RelationshipThread } from "./types";
|
|
3
3
|
import { clamp } from "./graphLayout";
|
|
4
4
|
|
|
5
5
|
export function buildMemoryFragments(memoryData: unknown, historyData: unknown): MemoryFragment[] {
|
|
@@ -86,6 +86,51 @@ export function buildBrainReadiness(memoryData: unknown, fallbackMemoryCount: nu
|
|
|
86
86
|
return fallbackBrainReadiness(fallbackMemoryCount, fallbackConceptCount);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
export function buildBrainProof(data: unknown, fallbackModelName = ""): BrainProof {
|
|
90
|
+
const proof = isRecord(data) ? data : {};
|
|
91
|
+
const modelContinuity = isRecord(proof.model_continuity) ? proof.model_continuity : {};
|
|
92
|
+
const proofs = isRecord(proof.proofs) ? proof.proofs : {};
|
|
93
|
+
const recall = isRecord(proof.recall) ? proof.recall : {};
|
|
94
|
+
const claims = isRecord(proof.claims) ? proof.claims : {};
|
|
95
|
+
const durableItems = numberValue(proofs, ["durable_items", "durableItems"]);
|
|
96
|
+
return {
|
|
97
|
+
status: textValue(proof, ["status"], "quiet"),
|
|
98
|
+
modelContinuity: {
|
|
99
|
+
activeModel: textValue(modelContinuity, ["active_model", "activeModel"], fallbackModelName),
|
|
100
|
+
brainOwner: textValue(modelContinuity, ["brain_owner", "brainOwner"], "lattice_brain"),
|
|
101
|
+
capability: booleanValue(modelContinuity, ["capability"], true),
|
|
102
|
+
survivesModelSwitch: booleanValue(modelContinuity, ["survives_model_switch", "survivesModelSwitch"], false),
|
|
103
|
+
proven: booleanValue(modelContinuity, ["proven"], false),
|
|
104
|
+
contextStore: textValue(modelContinuity, ["context_store", "contextStore"], "workspace + conversation + graph + vector"),
|
|
105
|
+
},
|
|
106
|
+
proofs: {
|
|
107
|
+
durableItems,
|
|
108
|
+
hasDurableEvidence: booleanValue(proofs, ["has_durable_evidence", "hasDurableEvidence"], durableItems > 0),
|
|
109
|
+
workspaceMemories: numberValue(proofs, ["workspace_memories", "workspaceMemories"]),
|
|
110
|
+
conversations: numberValue(proofs, ["conversations"]),
|
|
111
|
+
graphConcepts: numberValue(proofs, ["graph_concepts", "graphConcepts"]),
|
|
112
|
+
vectorItems: numberValue(proofs, ["vector_items", "vectorItems"]),
|
|
113
|
+
healthySources: numberValue(proofs, ["healthy_sources", "healthySources"]),
|
|
114
|
+
},
|
|
115
|
+
recall: {
|
|
116
|
+
query: textValue(recall, ["query"]),
|
|
117
|
+
count: numberValue(recall, ["count"]),
|
|
118
|
+
items: asArray<ApiRecord>(recall.items).map((item, index) => ({
|
|
119
|
+
id: textValue(item, ["id"], `recall-${index}`),
|
|
120
|
+
source: titleValue(item, ["source"], "Memory"),
|
|
121
|
+
title: textValue(item, ["title"], "Memory"),
|
|
122
|
+
snippet: textValue(item, ["snippet"]),
|
|
123
|
+
score: numberValue(item, ["score"]),
|
|
124
|
+
})),
|
|
125
|
+
},
|
|
126
|
+
claims: {
|
|
127
|
+
canRecallUserContext: booleanValue(claims, ["can_recall_user_context", "canRecallUserContext"], false),
|
|
128
|
+
keepsContextAcrossModels: booleanValue(claims, ["keeps_context_across_models", "keepsContextAcrossModels"], false),
|
|
129
|
+
isKnowledgeStore: booleanValue(claims, ["is_knowledge_store", "isKnowledgeStore"], false),
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
89
134
|
function uniqueById<T extends { id: string }>(items: T[]) {
|
|
90
135
|
const seen = new Set<string>();
|
|
91
136
|
return items.filter((item) => {
|
|
@@ -167,3 +212,11 @@ function numberValue(record: ApiRecord, keys: string[]) {
|
|
|
167
212
|
}
|
|
168
213
|
return 0;
|
|
169
214
|
}
|
|
215
|
+
|
|
216
|
+
function booleanValue(record: ApiRecord, keys: string[], fallback: boolean) {
|
|
217
|
+
for (const key of keys) {
|
|
218
|
+
const value = record[key];
|
|
219
|
+
if (typeof value === "boolean") return value;
|
|
220
|
+
}
|
|
221
|
+
return fallback;
|
|
222
|
+
}
|
|
@@ -50,6 +50,43 @@ export type BrainReadiness = {
|
|
|
50
50
|
};
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
+
export type BrainProof = {
|
|
54
|
+
status: "quiet" | "forming" | "alive" | string;
|
|
55
|
+
modelContinuity: {
|
|
56
|
+
activeModel: string;
|
|
57
|
+
brainOwner: string;
|
|
58
|
+
capability: boolean;
|
|
59
|
+
survivesModelSwitch: boolean;
|
|
60
|
+
proven: boolean;
|
|
61
|
+
contextStore: string;
|
|
62
|
+
};
|
|
63
|
+
proofs: {
|
|
64
|
+
durableItems: number;
|
|
65
|
+
hasDurableEvidence: boolean;
|
|
66
|
+
workspaceMemories: number;
|
|
67
|
+
conversations: number;
|
|
68
|
+
graphConcepts: number;
|
|
69
|
+
vectorItems: number;
|
|
70
|
+
healthySources: number;
|
|
71
|
+
};
|
|
72
|
+
recall: {
|
|
73
|
+
query: string;
|
|
74
|
+
count: number;
|
|
75
|
+
items: Array<{
|
|
76
|
+
id: string;
|
|
77
|
+
source: string;
|
|
78
|
+
title: string;
|
|
79
|
+
snippet: string;
|
|
80
|
+
score: number;
|
|
81
|
+
}>;
|
|
82
|
+
};
|
|
83
|
+
claims: {
|
|
84
|
+
canRecallUserContext: boolean;
|
|
85
|
+
keepsContextAcrossModels: boolean;
|
|
86
|
+
isKnowledgeStore: boolean;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
|
|
53
90
|
export const DEPTHS: Array<{ level: BrainDepth; labelKey: string; state: BrainState }> = [
|
|
54
91
|
{ level: 1, labelKey: "brain.depthLabel.1", state: "idle" },
|
|
55
92
|
{ level: 2, labelKey: "brain.depthLabel.2", state: "recalling" },
|
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에 쌓이고 나중에 주제와 관계로 다시 보입니다.",
|
|
@@ -53,6 +58,13 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
53
58
|
"brain.prompt.know": "이 문서를 내 Brain에 넣고 요약해줘: ",
|
|
54
59
|
"brain.prompt.plan": "지난 결정들을 나중에 찾을 수 있게 정리해줘: ",
|
|
55
60
|
"brain.placeholder": "Brain에게 말하기...",
|
|
61
|
+
"brain.upload.cta": "파일/문서 넣기",
|
|
62
|
+
"brain.upload.ctaShort": "문서",
|
|
63
|
+
"brain.upload.uploading": "넣는 중",
|
|
64
|
+
"brain.upload.hint": "업로드하면 실제 기억과 그래프로 다시 보입니다.",
|
|
65
|
+
"brain.upload.pending": "{name}을 Brain에 넣는 중입니다.",
|
|
66
|
+
"brain.upload.saved": "{name}이 Brain에 저장됐습니다.",
|
|
67
|
+
"brain.upload.failed": "문서를 넣지 못했습니다: {reason}",
|
|
56
68
|
"brain.image": "이미지",
|
|
57
69
|
"brain.unavailable": "지금은 답할 수 없음",
|
|
58
70
|
"brain.imageAttached": "이미지 첨부됨",
|
|
@@ -77,6 +89,21 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
77
89
|
"brain.readiness.start": "첫 기억 보기",
|
|
78
90
|
"brain.readiness.grow": "주제 키우기",
|
|
79
91
|
"brain.readiness.map": "지도 보기",
|
|
92
|
+
"brain.proof.aria": "Brain 증거",
|
|
93
|
+
"brain.proof.context": "다시 불러올 맥락",
|
|
94
|
+
"brain.proof.contextValue": "{count}개 저장됨",
|
|
95
|
+
"brain.proof.contextEmpty": "첫 기억 대기",
|
|
96
|
+
"brain.proof.model": "모델 교체 후에도 유지",
|
|
97
|
+
"brain.proof.noModel": "모델 미로드",
|
|
98
|
+
"brain.proof.modelPending": "저장 후 증명됨",
|
|
99
|
+
"brain.proof.store": "지식 저장소",
|
|
100
|
+
"brain.proof.storeValue": "주제 {topics}개 · 벡터 {vectors}개",
|
|
101
|
+
"brain.proof.recall": "방금 Brain이 다시 꺼낸 기억",
|
|
102
|
+
"brain.proof.recallEmpty.kicker": "Brain 증거 자리",
|
|
103
|
+
"brain.proof.recallEmpty.title": "첫 대화 후 여기에 다시 꺼낸 기억이 표시됩니다.",
|
|
104
|
+
"brain.proof.recallEmpty.detail": "아직 저장된 기억이 없어서 가짜 예시는 보여주지 않습니다.",
|
|
105
|
+
"brain.proof.recallPending": "기억은 저장됐고 recall 증거를 준비 중입니다.",
|
|
106
|
+
"brain.proof.recallPending.detail": "인덱싱이 끝나면 이 자리에서 실제 기억을 다시 보여줍니다.",
|
|
80
107
|
"brain.memory.empty.kicker": "첫 기억",
|
|
81
108
|
"brain.memory.empty": "기억이 조용합니다.",
|
|
82
109
|
"brain.knowledge.empty": "지식이 형성되는 중입니다.",
|
|
@@ -366,6 +393,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
366
393
|
"brain.depthRail.aria": "Brain depth progress",
|
|
367
394
|
"brain.aria.conversation": "Conversation",
|
|
368
395
|
"brain.aria.ownership": "Brain ownership guarantees",
|
|
396
|
+
"brain.aria.actions": "Brain primary actions",
|
|
369
397
|
"brain.aria.starterPrompts": "Starter prompts",
|
|
370
398
|
"brain.aria.overview": "Brain overview",
|
|
371
399
|
"brain.aria.graph": "Knowledge Graph",
|
|
@@ -374,6 +402,10 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
374
402
|
"brain.portable": "Portable",
|
|
375
403
|
"brain.private": "Private",
|
|
376
404
|
"brain.admin": "Admin Console",
|
|
405
|
+
"brain.action.add": "Add",
|
|
406
|
+
"brain.action.find": "Find",
|
|
407
|
+
"brain.action.model": "Model",
|
|
408
|
+
"brain.action.settings": "Settings",
|
|
377
409
|
"brain.empty.kicker": "Durable memory",
|
|
378
410
|
"brain.empty.title": "Start with context that should not be forgotten.",
|
|
379
411
|
"brain.empty.body": "Documents, conversations, projects, and decisions accumulate in the Brain on this computer, then reappear as topics and relationships.",
|
|
@@ -385,6 +417,13 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
385
417
|
"brain.prompt.know": "Put this document into my Brain and summarize it: ",
|
|
386
418
|
"brain.prompt.plan": "Organize past decisions so I can find them later: ",
|
|
387
419
|
"brain.placeholder": "Talk to your Brain...",
|
|
420
|
+
"brain.upload.cta": "Add file or document",
|
|
421
|
+
"brain.upload.ctaShort": "Document",
|
|
422
|
+
"brain.upload.uploading": "Adding...",
|
|
423
|
+
"brain.upload.hint": "After upload, it reappears as real memory and graph context.",
|
|
424
|
+
"brain.upload.pending": "Adding {name} to Brain.",
|
|
425
|
+
"brain.upload.saved": "{name} was saved to Brain.",
|
|
426
|
+
"brain.upload.failed": "Could not add the document: {reason}",
|
|
388
427
|
"brain.image": "Image",
|
|
389
428
|
"brain.unavailable": "Unavailable",
|
|
390
429
|
"brain.imageAttached": "Image attached",
|
|
@@ -409,6 +448,21 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
409
448
|
"brain.readiness.start": "View first memory",
|
|
410
449
|
"brain.readiness.grow": "Grow topics",
|
|
411
450
|
"brain.readiness.map": "Open map",
|
|
451
|
+
"brain.proof.aria": "Brain proof",
|
|
452
|
+
"brain.proof.context": "Recallable context",
|
|
453
|
+
"brain.proof.contextValue": "{count} saved",
|
|
454
|
+
"brain.proof.contextEmpty": "Waiting for first memory",
|
|
455
|
+
"brain.proof.model": "Survives model switches",
|
|
456
|
+
"brain.proof.noModel": "No model loaded",
|
|
457
|
+
"brain.proof.modelPending": "Proven after saving",
|
|
458
|
+
"brain.proof.store": "Knowledge store",
|
|
459
|
+
"brain.proof.storeValue": "{topics} topics · {vectors} vectors",
|
|
460
|
+
"brain.proof.recall": "Just recalled by Brain",
|
|
461
|
+
"brain.proof.recallEmpty.kicker": "Brain proof slot",
|
|
462
|
+
"brain.proof.recallEmpty.title": "After your first exchange, recalled memory appears here.",
|
|
463
|
+
"brain.proof.recallEmpty.detail": "No saved memory yet, so Lattice does not show a fake example.",
|
|
464
|
+
"brain.proof.recallPending": "Memory is saved; recall proof is preparing.",
|
|
465
|
+
"brain.proof.recallPending.detail": "When indexing finishes, this slot shows the actual memory Brain can bring back.",
|
|
412
466
|
"brain.memory.empty.kicker": "First memory",
|
|
413
467
|
"brain.memory.empty": "Memory is quiet",
|
|
414
468
|
"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
|
|