ltcai 6.4.0 → 6.5.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 +29 -28
- package/docs/CHANGELOG.md +28 -0
- package/frontend/src/api/client.ts +1 -0
- package/frontend/src/features/brain/BrainConversation.tsx +12 -3
- package/frontend/src/features/brain/BrainHome.tsx +21 -1
- package/frontend/src/features/brain/BrainMemoryLayer.tsx +8 -1
- package/frontend/src/features/brain/BrainOverviewPanel.tsx +15 -1
- package/frontend/src/features/brain/brainData.ts +72 -1
- package/frontend/src/features/brain/types.ts +15 -0
- package/frontend/src/i18n.ts +22 -0
- package/frontend/src/styles.css +128 -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/api/memory.py +6 -0
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/services/memory_service.py +66 -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 +5 -5
- package/static/app/assets/index-C1J_1441.js +16 -0
- package/static/app/assets/index-C1J_1441.js.map +1 -0
- package/static/app/assets/{index-Div5vMlq.css → index-CdCVz_i4.css} +1 -1
- package/static/app/index.html +2 -2
- package/static/app/assets/index-t1jx1BR9.js +0 -16
- package/static/app/assets/index-t1jx1BR9.js.map +0 -1
package/README.md
CHANGED
|
@@ -69,42 +69,42 @@ You need Lattice AI when:
|
|
|
69
69
|
Choose the owner of the Brain. The profile is not a SaaS account by default; it
|
|
70
70
|
is the local identity for the knowledge you keep.
|
|
71
71
|
|
|
72
|
-

|
|
73
73
|
|
|
74
74
|
### 2. Environment Analysis
|
|
75
75
|
|
|
76
76
|
See what kind of local AI experience this computer can support before choosing a
|
|
77
77
|
model.
|
|
78
78
|
|
|
79
|
-

|
|
80
80
|
|
|
81
81
|
### 3. Recommended Models
|
|
82
82
|
|
|
83
83
|
Start with a short list: safest recommendation, faster model, stronger model.
|
|
84
84
|
Advanced details stay available without overwhelming first-time users.
|
|
85
85
|
|
|
86
|
-

|
|
87
87
|
|
|
88
88
|
### 4. Install And Load
|
|
89
89
|
|
|
90
90
|
Download and load only after consent. Lattice explains model size, local
|
|
91
91
|
execution, and network use before work starts.
|
|
92
92
|
|
|
93
|
-

|
|
94
94
|
|
|
95
95
|
### 5. Brain Chat
|
|
96
96
|
|
|
97
97
|
Talk normally. Useful decisions and context become memory, then appear later as
|
|
98
98
|
topics, relationships, and graph structure.
|
|
99
99
|
|
|
100
|
-

|
|
101
101
|
|
|
102
102
|
### 6. Review Center
|
|
103
103
|
|
|
104
104
|
Automation results are staged for review before they become durable decisions.
|
|
105
105
|
Snooze, unsnooze, run now, approve, and dismiss actions stay explicit.
|
|
106
106
|
|
|
107
|
-

|
|
108
108
|
|
|
109
109
|
## Brain Depths
|
|
110
110
|
|
|
@@ -120,10 +120,10 @@ The user travels inward from everyday memory to deeper structure:
|
|
|
120
120
|
|
|
121
121
|
Walkthrough:
|
|
122
122
|
|
|
123
|
-

|
|
124
124
|
|
|
125
125
|
Screenshot index and capture notes:
|
|
126
|
-
[output/release/v6.
|
|
126
|
+
[output/release/v6.5.0/SCREENSHOT_INDEX.md](output/release/v6.5.0/SCREENSHOT_INDEX.md)
|
|
127
127
|
|
|
128
128
|
## Install
|
|
129
129
|
|
|
@@ -200,31 +200,31 @@ See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for developer workflow details.
|
|
|
200
200
|
|
|
201
201
|
## Current Release Preparation
|
|
202
202
|
|
|
203
|
-
The current development target is **6.
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
- Memory
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
-
|
|
216
|
-
|
|
203
|
+
The current development target is **6.5.0 Brain Experience Readiness**:
|
|
204
|
+
|
|
205
|
+
- Brain Home now gives normal users a readiness signal that explains whether
|
|
206
|
+
the Brain is waiting for its first memory, turning memories into topics, or
|
|
207
|
+
ready to explore as a connected map. That signal now comes from the backend
|
|
208
|
+
Memory Manager summary instead of a frontend-only estimate.
|
|
209
|
+
- The Living Brain surface now includes a persistent depth progress rail, so
|
|
210
|
+
users can understand and reverse the path from conversation to memory,
|
|
211
|
+
topics, relationships, and the full knowledge graph.
|
|
212
|
+
- Memory-save feedback now explicitly states that saved context is available
|
|
213
|
+
later with source-aware recall, closing the gap between "chat happened" and
|
|
214
|
+
"my Brain became more useful."
|
|
215
|
+
- The release keeps the 6.4.0 quality hardening intact and focuses on
|
|
216
|
+
end-user comprehension rather than adding a new storage or graph schema.
|
|
217
217
|
- The release remains local-first: no automatic web/email/calendar ingestion,
|
|
218
218
|
no package publishing, no production deployment, and no external reranker or
|
|
219
219
|
embedding API use without explicit opt-in.
|
|
220
220
|
|
|
221
|
-
Expected artifacts for 6.
|
|
221
|
+
Expected artifacts for 6.5.0 release must use exact filenames:
|
|
222
222
|
|
|
223
|
-
- `dist/ltcai-6.
|
|
224
|
-
- `dist/ltcai-6.
|
|
225
|
-
- `ltcai-6.
|
|
226
|
-
- `dist/ltcai-6.
|
|
227
|
-
- `src-tauri/target/release/bundle/dmg/Lattice AI_6.
|
|
223
|
+
- `dist/ltcai-6.5.0-py3-none-any.whl`
|
|
224
|
+
- `dist/ltcai-6.5.0.tar.gz`
|
|
225
|
+
- `ltcai-6.5.0.tgz`
|
|
226
|
+
- `dist/ltcai-6.5.0.vsix`
|
|
227
|
+
- `src-tauri/target/release/bundle/dmg/Lattice AI_6.5.0_aarch64.dmg`
|
|
228
228
|
|
|
229
229
|
Do not upload `dist/*`. Package registry publishing remains owner-run.
|
|
230
230
|
|
|
@@ -243,6 +243,7 @@ Do not upload `dist/*`. Package registry publishing remains owner-run.
|
|
|
243
243
|
|
|
244
244
|
| Version | Theme |
|
|
245
245
|
| --- | --- |
|
|
246
|
+
| 6.5.0 | Brain Experience Readiness: Brain readiness signal, depth progress rail, source-aware memory-save feedback, and visual coverage for the first-memory loop |
|
|
246
247
|
| 6.4.0 | Digital Brain Quality Hardening: workspace-scoped graph/search/memory reads and mutations, Brain quality primitives, structured context guardrails, and retrieval benchmark coverage |
|
|
247
248
|
| 6.3.1 | Access Runtime / i18n Follow-up: app-factory access-control extraction, focused access runtime tests, and Capture/Review Center i18n coverage |
|
|
248
249
|
| 6.3.0 | Product Hardening Completion: Brain archive/provenance/ingestion UX polish, Review Center Run Now contract hardening, local model runtime status, app-factory review wiring, shim smoke, i18n guard, and exact release artifacts |
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,34 @@
|
|
|
3
3
|
The top entry is the current release-preparation target. Older entries are
|
|
4
4
|
historical and may describe behavior as it existed at that release.
|
|
5
5
|
|
|
6
|
+
## [6.5.0] - 2026-06-18
|
|
7
|
+
|
|
8
|
+
> Brain Experience Readiness. Uses the 6.4.0 quality baseline to improve what
|
|
9
|
+
> normal users can understand: how alive the Brain is, where they are in the
|
|
10
|
+
> memory-to-graph journey, and what changed after a useful exchange is saved.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Brain Home readiness strip that classifies the current Brain as waiting for
|
|
14
|
+
its first memory, forming topics, or ready for map exploration.
|
|
15
|
+
- Backend-owned Brain readiness summary from `MemoryService`, exposed through
|
|
16
|
+
`/api/memory/manager` and `/api/memory/brain-quality`, so the UI no longer
|
|
17
|
+
has to infer Brain growth from local fragments.
|
|
18
|
+
- Persistent depth progress rail across the Living Brain surface so the
|
|
19
|
+
memory -> topics -> relationships -> graph journey is visible and reversible.
|
|
20
|
+
- Source-aware memory-save detail under chat feedback, making the recall loop
|
|
21
|
+
explicit after a conversation enriches the Brain.
|
|
22
|
+
- Visual regression assertions for Brain readiness, depth progress, and
|
|
23
|
+
source-aware memory-save feedback.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- Brain overview empty states now guide first-memory use without exposing graph
|
|
27
|
+
internals or administrator language.
|
|
28
|
+
- Brain readiness now uses the same memory, graph, relationship, and source
|
|
29
|
+
health signals that the Memory Manager reports, keeping product UX aligned
|
|
30
|
+
with backend Brain state.
|
|
31
|
+
- Package/runtime/static metadata is synchronized to 6.5.0; package publish and
|
|
32
|
+
deployment remain owner-run only.
|
|
33
|
+
|
|
6
34
|
## [6.4.0] - 2026-06-17
|
|
7
35
|
|
|
8
36
|
> Digital Brain Quality Hardening. Tightens workspace-scoped Brain retrieval
|
|
@@ -445,6 +445,7 @@ export const latticeApi = {
|
|
|
445
445
|
},
|
|
446
446
|
browserReadUrl: (url: string) => post("/api/browser/read-url", { url }, {}),
|
|
447
447
|
memoryManager: () => get("/api/memory/manager", { sources: [], tiers: [], usage: {} }),
|
|
448
|
+
memoryBrainQuality: () => get("/api/memory/brain-quality", {}),
|
|
448
449
|
memoryRecall: (query: string, limit = 20) => post("/api/memory/recall", { query, limit }, { matches: [] }),
|
|
449
450
|
memoryCompact: () => post("/api/memory/compact", {}, {}),
|
|
450
451
|
memoryRebuild: () => post("/api/memory/rebuild", { target: "vector" }, {}),
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { ShieldCheck } from "lucide-react";
|
|
2
|
+
import { DatabaseZap, ShieldCheck } from "lucide-react";
|
|
3
3
|
import { LanguageSwitcher } from "@/components/LanguageSwitcher";
|
|
4
4
|
import { t, type Language } from "@/i18n";
|
|
5
|
-
import type { BrainDepth, KnowledgeConcept, MemoryFragment, Message } from "./types";
|
|
5
|
+
import type { BrainDepth, BrainReadiness, KnowledgeConcept, MemoryFragment, Message } from "./types";
|
|
6
6
|
import { BrainCarePanel } from "./BrainCarePanel";
|
|
7
7
|
import { BrainComposer } from "./BrainComposer";
|
|
8
8
|
import { BrainOverviewPanel } from "./BrainOverviewPanel";
|
|
@@ -20,6 +20,7 @@ export function BrainConversation({
|
|
|
20
20
|
streamRef,
|
|
21
21
|
memories,
|
|
22
22
|
concepts,
|
|
23
|
+
readiness,
|
|
23
24
|
onOpenDepth,
|
|
24
25
|
onDraftChange,
|
|
25
26
|
onImageDataChange,
|
|
@@ -37,6 +38,7 @@ export function BrainConversation({
|
|
|
37
38
|
streamRef: React.RefObject<HTMLDivElement | null>;
|
|
38
39
|
memories: MemoryFragment[];
|
|
39
40
|
concepts: KnowledgeConcept[];
|
|
41
|
+
readiness: BrainReadiness;
|
|
40
42
|
onOpenDepth: (depth: BrainDepth) => void;
|
|
41
43
|
onDraftChange: (value: string) => void;
|
|
42
44
|
onImageDataChange: (value: string | null) => void;
|
|
@@ -66,6 +68,7 @@ export function BrainConversation({
|
|
|
66
68
|
<BrainOverviewPanel
|
|
67
69
|
memories={memories}
|
|
68
70
|
concepts={concepts}
|
|
71
|
+
readiness={readiness}
|
|
69
72
|
onOpenDepth={onOpenDepth}
|
|
70
73
|
/>
|
|
71
74
|
{messages.length === 0 ? (
|
|
@@ -79,7 +82,13 @@ export function BrainConversation({
|
|
|
79
82
|
)}
|
|
80
83
|
</div>
|
|
81
84
|
|
|
82
|
-
{memoryFeedback ?
|
|
85
|
+
{memoryFeedback ? (
|
|
86
|
+
<div className="brain-save-feedback" role="status">
|
|
87
|
+
<DatabaseZap className="h-3.5 w-3.5" />
|
|
88
|
+
<span>{memoryFeedback}</span>
|
|
89
|
+
<small>{t(language, "brain.saved.detail")}</small>
|
|
90
|
+
</div>
|
|
91
|
+
) : null}
|
|
83
92
|
|
|
84
93
|
<BrainCarePanel language={language} />
|
|
85
94
|
|
|
@@ -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 { buildMemoryFragments, currentModelName, parseKnowledgeGraph } from "./brainData";
|
|
8
|
+
import { 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
|
|
|
@@ -46,6 +46,10 @@ export function BrainHome({
|
|
|
46
46
|
() => graphModel.nodes.slice(0, 10),
|
|
47
47
|
[graphModel.nodes],
|
|
48
48
|
);
|
|
49
|
+
const brainReadiness = React.useMemo(
|
|
50
|
+
() => buildBrainReadiness(memoriesQ.data?.data, memoryFragments.length, knowledgeConcepts.length),
|
|
51
|
+
[knowledgeConcepts.length, memoriesQ.data, memoryFragments.length],
|
|
52
|
+
);
|
|
49
53
|
const relationshipThreads = React.useMemo(
|
|
50
54
|
() => graphModel.edges.slice(0, 10),
|
|
51
55
|
[graphModel.edges],
|
|
@@ -186,6 +190,21 @@ export function BrainHome({
|
|
|
186
190
|
<button type="button" className={explorationDepth === 5 ? "is-active" : ""} onClick={() => jumpToDepth(5)}>{t(language, "brain.view.graph")}</button>
|
|
187
191
|
</div>
|
|
188
192
|
|
|
193
|
+
<div className="brain-depth-rail" aria-label={t(language, "brain.depthRail.aria")}>
|
|
194
|
+
{DEPTHS.map((depth) => (
|
|
195
|
+
<button
|
|
196
|
+
key={depth.level}
|
|
197
|
+
type="button"
|
|
198
|
+
className={depth.level <= explorationDepth ? "is-revealed" : ""}
|
|
199
|
+
aria-current={depth.level === explorationDepth ? "step" : undefined}
|
|
200
|
+
onClick={() => jumpToDepth(depth.level)}
|
|
201
|
+
>
|
|
202
|
+
<span>{depth.level}</span>
|
|
203
|
+
<strong>{t(language, `brain.depth.${depth.level}`)}</strong>
|
|
204
|
+
</button>
|
|
205
|
+
))}
|
|
206
|
+
</div>
|
|
207
|
+
|
|
189
208
|
<div className="brain-field-layer" aria-hidden={explorationDepth < 2}>
|
|
190
209
|
<DepthEmergence
|
|
191
210
|
depth={explorationDepth}
|
|
@@ -222,6 +241,7 @@ export function BrainHome({
|
|
|
222
241
|
streamRef={streamRef}
|
|
223
242
|
memories={memoryFragments}
|
|
224
243
|
concepts={knowledgeConcepts}
|
|
244
|
+
readiness={brainReadiness}
|
|
225
245
|
onOpenDepth={jumpToDepth}
|
|
226
246
|
onDraftChange={setDraft}
|
|
227
247
|
onImageDataChange={setImageData}
|
|
@@ -14,7 +14,14 @@ export function BrainMemoryLayer({
|
|
|
14
14
|
}) {
|
|
15
15
|
const language = useAppStore((state) => state.language);
|
|
16
16
|
const visible = memories.slice(0, depth >= 3 ? 8 : 6);
|
|
17
|
-
if (!visible.length)
|
|
17
|
+
if (!visible.length) {
|
|
18
|
+
return (
|
|
19
|
+
<div className="memory-fragment is-empty">
|
|
20
|
+
<span>{t(language, "brain.memory.empty.kicker")}</span>
|
|
21
|
+
<strong>{t(language, "brain.memory.empty")}</strong>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
18
25
|
|
|
19
26
|
return (
|
|
20
27
|
<>
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { t } from "@/i18n";
|
|
3
3
|
import { useAppStore } from "@/store/appStore";
|
|
4
|
-
import type { BrainDepth, KnowledgeConcept, MemoryFragment } from "./types";
|
|
4
|
+
import type { BrainDepth, BrainReadiness, KnowledgeConcept, MemoryFragment } from "./types";
|
|
5
5
|
|
|
6
6
|
export function BrainOverviewPanel({
|
|
7
7
|
memories,
|
|
8
8
|
concepts,
|
|
9
|
+
readiness,
|
|
9
10
|
onOpenDepth,
|
|
10
11
|
}: {
|
|
11
12
|
memories: MemoryFragment[];
|
|
12
13
|
concepts: KnowledgeConcept[];
|
|
14
|
+
readiness: BrainReadiness;
|
|
13
15
|
onOpenDepth: (depth: BrainDepth) => void;
|
|
14
16
|
}) {
|
|
15
17
|
const language = useAppStore((state) => state.language);
|
|
@@ -46,6 +48,18 @@ export function BrainOverviewPanel({
|
|
|
46
48
|
onOpen={() => onOpenDepth(3)}
|
|
47
49
|
/>
|
|
48
50
|
</div>
|
|
51
|
+
<div className="brain-readiness-strip" data-state={readiness.state}>
|
|
52
|
+
<div>
|
|
53
|
+
<span>{t(language, "brain.readiness.kicker")}</span>
|
|
54
|
+
<strong>{t(language, readiness.titleKey)}</strong>
|
|
55
|
+
</div>
|
|
56
|
+
<div className="brain-readiness-meter" aria-label={t(language, "brain.readiness.aria")}>
|
|
57
|
+
<i style={{ width: `${readiness.score}%` }} />
|
|
58
|
+
</div>
|
|
59
|
+
<button type="button" onClick={() => onOpenDepth(readiness.depth)}>
|
|
60
|
+
{t(language, readiness.actionKey)}
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
49
63
|
</section>
|
|
50
64
|
);
|
|
51
65
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { asArray } from "@/lib/utils";
|
|
2
|
-
import type { ApiRecord, KnowledgeConcept, KnowledgeGraphModel, MemoryFragment, RelationshipThread } from "./types";
|
|
2
|
+
import type { ApiRecord, BrainDepth, 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[] {
|
|
@@ -60,6 +60,32 @@ export function currentModelName(data: unknown) {
|
|
|
60
60
|
return firstLoaded ? textValue(firstLoaded, ["name", "id", "model_id"], "local mind") : "local mind";
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
export function buildBrainReadiness(memoryData: unknown, fallbackMemoryCount: number, fallbackConceptCount: number): BrainReadiness {
|
|
64
|
+
const memory = isRecord(memoryData) ? memoryData : {};
|
|
65
|
+
const backend = isRecord(memory.brain_readiness) ? memory.brain_readiness : {};
|
|
66
|
+
const backendState = textValue(backend, ["state"]);
|
|
67
|
+
const backendDepth = numberValue(backend, ["depth"]);
|
|
68
|
+
const backendScore = numberValue(backend, ["score"]);
|
|
69
|
+
if ((backendState === "quiet" || backendState === "forming" || backendState === "alive") && isBrainDepth(backendDepth)) {
|
|
70
|
+
const signals = isRecord(backend.signals) ? backend.signals : {};
|
|
71
|
+
return {
|
|
72
|
+
score: clamp(Math.round(backendScore || 0), 0, 100),
|
|
73
|
+
state: backendState,
|
|
74
|
+
depth: backendDepth,
|
|
75
|
+
titleKey: textValue(backend, ["title_key", "titleKey"], `brain.readiness.${backendState}`),
|
|
76
|
+
actionKey: textValue(backend, ["action_key", "actionKey"], readinessActionKey(backendState)),
|
|
77
|
+
source: "memory_service",
|
|
78
|
+
signals: {
|
|
79
|
+
memoryCount: numberValue(signals, ["memory_count", "memoryCount"]),
|
|
80
|
+
conceptCount: numberValue(signals, ["concept_count", "conceptCount"]),
|
|
81
|
+
relationshipCount: numberValue(signals, ["relationship_count", "relationshipCount"]),
|
|
82
|
+
healthySources: numberValue(signals, ["healthy_sources", "healthySources"]),
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return fallbackBrainReadiness(fallbackMemoryCount, fallbackConceptCount);
|
|
87
|
+
}
|
|
88
|
+
|
|
63
89
|
function uniqueById<T extends { id: string }>(items: T[]) {
|
|
64
90
|
const seen = new Set<string>();
|
|
65
91
|
return items.filter((item) => {
|
|
@@ -69,6 +95,51 @@ function uniqueById<T extends { id: string }>(items: T[]) {
|
|
|
69
95
|
});
|
|
70
96
|
}
|
|
71
97
|
|
|
98
|
+
function fallbackBrainReadiness(memoryCount: number, conceptCount: number): BrainReadiness {
|
|
99
|
+
const score = Math.min(100, Math.round(memoryCount * 12 + conceptCount * 10));
|
|
100
|
+
if (memoryCount < 1) {
|
|
101
|
+
return {
|
|
102
|
+
score: Math.max(12, score),
|
|
103
|
+
state: "quiet",
|
|
104
|
+
depth: 2,
|
|
105
|
+
titleKey: "brain.readiness.quiet",
|
|
106
|
+
actionKey: "brain.readiness.start",
|
|
107
|
+
source: "frontend_fallback",
|
|
108
|
+
signals: { memoryCount, conceptCount, relationshipCount: 0, healthySources: 0 },
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (conceptCount < 3) {
|
|
112
|
+
return {
|
|
113
|
+
score: Math.max(38, score),
|
|
114
|
+
state: "forming",
|
|
115
|
+
depth: 3,
|
|
116
|
+
titleKey: "brain.readiness.forming",
|
|
117
|
+
actionKey: "brain.readiness.grow",
|
|
118
|
+
source: "frontend_fallback",
|
|
119
|
+
signals: { memoryCount, conceptCount, relationshipCount: 0, healthySources: 0 },
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
score: Math.max(72, score),
|
|
124
|
+
state: "alive",
|
|
125
|
+
depth: 5,
|
|
126
|
+
titleKey: "brain.readiness.alive",
|
|
127
|
+
actionKey: "brain.readiness.map",
|
|
128
|
+
source: "frontend_fallback",
|
|
129
|
+
signals: { memoryCount, conceptCount, relationshipCount: 0, healthySources: 0 },
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function readinessActionKey(state: "quiet" | "forming" | "alive") {
|
|
134
|
+
if (state === "quiet") return "brain.readiness.start";
|
|
135
|
+
if (state === "forming") return "brain.readiness.grow";
|
|
136
|
+
return "brain.readiness.map";
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function isBrainDepth(value: number): value is BrainDepth {
|
|
140
|
+
return value >= 1 && value <= 5 && Number.isInteger(value);
|
|
141
|
+
}
|
|
142
|
+
|
|
72
143
|
export function isRecord(value: unknown): value is ApiRecord {
|
|
73
144
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
74
145
|
}
|
|
@@ -35,6 +35,21 @@ export type KnowledgeGraphModel = {
|
|
|
35
35
|
edges: RelationshipThread[];
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
+
export type BrainReadiness = {
|
|
39
|
+
score: number;
|
|
40
|
+
state: "quiet" | "forming" | "alive";
|
|
41
|
+
depth: BrainDepth;
|
|
42
|
+
titleKey: string;
|
|
43
|
+
actionKey: string;
|
|
44
|
+
source: "memory_service" | "frontend_fallback";
|
|
45
|
+
signals: {
|
|
46
|
+
memoryCount: number;
|
|
47
|
+
conceptCount: number;
|
|
48
|
+
relationshipCount: number;
|
|
49
|
+
healthySources: number;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
|
|
38
53
|
export const DEPTHS: Array<{ level: BrainDepth; labelKey: string; state: BrainState }> = [
|
|
39
54
|
{ level: 1, labelKey: "brain.depthLabel.1", state: "idle" },
|
|
40
55
|
{ level: 2, labelKey: "brain.depthLabel.2", state: "recalling" },
|
package/frontend/src/i18n.ts
CHANGED
|
@@ -31,6 +31,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
31
31
|
"brain.aria.home": "Lattice Brain",
|
|
32
32
|
"brain.aria.exploration": "Brain 탐색",
|
|
33
33
|
"brain.aria.quickViews": "Brain 빠른 보기",
|
|
34
|
+
"brain.depthRail.aria": "Brain 깊이 진행 상태",
|
|
34
35
|
"brain.aria.conversation": "대화",
|
|
35
36
|
"brain.aria.ownership": "Brain 소유 보장",
|
|
36
37
|
"brain.aria.starterPrompts": "시작 프롬프트",
|
|
@@ -57,6 +58,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
57
58
|
"brain.imageAttached": "이미지 첨부됨",
|
|
58
59
|
"brain.send": "보내기",
|
|
59
60
|
"brain.saved": "기억에 저장됨 · 연결된 주제 {topics}개 · 관련 기억 {memories}개",
|
|
61
|
+
"brain.saved.detail": "출처와 함께 나중에 다시 불러올 수 있습니다.",
|
|
60
62
|
"brain.recalled": "기억을 다시 꺼냈습니다: {title}",
|
|
61
63
|
"brain.overview.kicker": "Brain 한눈에 보기",
|
|
62
64
|
"brain.overview.title": "기억과 주제를 바로 확인하세요.",
|
|
@@ -67,6 +69,15 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
67
69
|
"brain.overview.olderEmpty": "대화가 쌓이면 과거 기억이 보입니다.",
|
|
68
70
|
"brain.overview.topics": "주요 주제",
|
|
69
71
|
"brain.overview.topicsEmpty": "주제가 형성되는 중입니다.",
|
|
72
|
+
"brain.readiness.kicker": "Brain 준비도",
|
|
73
|
+
"brain.readiness.aria": "Brain 준비도 점수",
|
|
74
|
+
"brain.readiness.quiet": "첫 기억을 기다리고 있습니다.",
|
|
75
|
+
"brain.readiness.forming": "기억이 주제로 자라는 중입니다.",
|
|
76
|
+
"brain.readiness.alive": "기억과 관계가 연결되어 있습니다.",
|
|
77
|
+
"brain.readiness.start": "첫 기억 보기",
|
|
78
|
+
"brain.readiness.grow": "주제 키우기",
|
|
79
|
+
"brain.readiness.map": "지도 보기",
|
|
80
|
+
"brain.memory.empty.kicker": "첫 기억",
|
|
70
81
|
"brain.memory.empty": "기억이 조용합니다.",
|
|
71
82
|
"brain.knowledge.empty": "지식이 형성되는 중입니다.",
|
|
72
83
|
"brain.graph.empty": "아직 맞는 지식이 없습니다.",
|
|
@@ -352,6 +363,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
352
363
|
"brain.aria.home": "Lattice Brain",
|
|
353
364
|
"brain.aria.exploration": "Brain exploration",
|
|
354
365
|
"brain.aria.quickViews": "Brain quick views",
|
|
366
|
+
"brain.depthRail.aria": "Brain depth progress",
|
|
355
367
|
"brain.aria.conversation": "Conversation",
|
|
356
368
|
"brain.aria.ownership": "Brain ownership guarantees",
|
|
357
369
|
"brain.aria.starterPrompts": "Starter prompts",
|
|
@@ -378,6 +390,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
378
390
|
"brain.imageAttached": "Image attached",
|
|
379
391
|
"brain.send": "Send",
|
|
380
392
|
"brain.saved": "Saved to memory · {topics} linked topics · {memories} related memories",
|
|
393
|
+
"brain.saved.detail": "Available later with source-aware recall.",
|
|
381
394
|
"brain.recalled": "Recalled this memory: {title}",
|
|
382
395
|
"brain.overview.kicker": "Brain at a glance",
|
|
383
396
|
"brain.overview.title": "See memories and topics immediately.",
|
|
@@ -388,6 +401,15 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
388
401
|
"brain.overview.olderEmpty": "Earlier memories appear as conversations accumulate.",
|
|
389
402
|
"brain.overview.topics": "Main topics",
|
|
390
403
|
"brain.overview.topicsEmpty": "Topics are still forming.",
|
|
404
|
+
"brain.readiness.kicker": "Brain readiness",
|
|
405
|
+
"brain.readiness.aria": "Brain readiness score",
|
|
406
|
+
"brain.readiness.quiet": "Waiting for the first memory.",
|
|
407
|
+
"brain.readiness.forming": "Memories are becoming topics.",
|
|
408
|
+
"brain.readiness.alive": "Memories and relationships are connected.",
|
|
409
|
+
"brain.readiness.start": "View first memory",
|
|
410
|
+
"brain.readiness.grow": "Grow topics",
|
|
411
|
+
"brain.readiness.map": "Open map",
|
|
412
|
+
"brain.memory.empty.kicker": "First memory",
|
|
391
413
|
"brain.memory.empty": "Memory is quiet",
|
|
392
414
|
"brain.knowledge.empty": "Knowledge is forming",
|
|
393
415
|
"brain.graph.empty": "No matching knowledge yet",
|
package/frontend/src/styles.css
CHANGED
|
@@ -1421,7 +1421,65 @@ body {
|
|
|
1421
1421
|
line-height: 1.35;
|
|
1422
1422
|
}
|
|
1423
1423
|
|
|
1424
|
+
.brain-readiness-strip {
|
|
1425
|
+
display: grid;
|
|
1426
|
+
grid-template-columns: minmax(0, 1fr) minmax(5.6rem, 0.6fr) auto;
|
|
1427
|
+
align-items: center;
|
|
1428
|
+
gap: 0.7rem;
|
|
1429
|
+
margin-top: 0.75rem;
|
|
1430
|
+
border: 1px solid hsl(var(--brain-core) / 0.28);
|
|
1431
|
+
border-radius: 8px;
|
|
1432
|
+
background: hsl(var(--brain-core) / 0.06);
|
|
1433
|
+
padding: 0.66rem;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
.brain-readiness-strip span {
|
|
1437
|
+
display: block;
|
|
1438
|
+
color: hsl(var(--fg-muted));
|
|
1439
|
+
font-size: 0.64rem;
|
|
1440
|
+
font-weight: 820;
|
|
1441
|
+
text-transform: uppercase;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
.brain-readiness-strip strong {
|
|
1445
|
+
display: block;
|
|
1446
|
+
margin-top: 0.12rem;
|
|
1447
|
+
font-size: 0.82rem;
|
|
1448
|
+
line-height: 1.2;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
.brain-readiness-strip button {
|
|
1452
|
+
min-height: 2rem;
|
|
1453
|
+
border: 1px solid hsl(var(--brain-core) / 0.34);
|
|
1454
|
+
border-radius: 999px;
|
|
1455
|
+
background: hsl(var(--surface) / 0.78);
|
|
1456
|
+
color: hsl(var(--fg));
|
|
1457
|
+
padding: 0 0.72rem;
|
|
1458
|
+
font-size: 0.76rem;
|
|
1459
|
+
font-weight: 760;
|
|
1460
|
+
white-space: nowrap;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
.brain-readiness-meter {
|
|
1464
|
+
height: 0.42rem;
|
|
1465
|
+
overflow: hidden;
|
|
1466
|
+
border-radius: 999px;
|
|
1467
|
+
background: hsl(var(--bg) / 0.55);
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
.brain-readiness-meter i {
|
|
1471
|
+
display: block;
|
|
1472
|
+
height: 100%;
|
|
1473
|
+
border-radius: inherit;
|
|
1474
|
+
background: linear-gradient(90deg, hsl(var(--memory)), hsl(var(--knowledge)), hsl(var(--brain-core)));
|
|
1475
|
+
transition: width 260ms ease;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1424
1478
|
.brain-save-feedback {
|
|
1479
|
+
display: grid;
|
|
1480
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
1481
|
+
align-items: center;
|
|
1482
|
+
gap: 0.22rem 0.48rem;
|
|
1425
1483
|
border: 1px solid hsl(var(--memory) / 0.38);
|
|
1426
1484
|
border-radius: 8px;
|
|
1427
1485
|
background: hsl(var(--memory) / 0.08);
|
|
@@ -1431,6 +1489,13 @@ body {
|
|
|
1431
1489
|
font-weight: 720;
|
|
1432
1490
|
}
|
|
1433
1491
|
|
|
1492
|
+
.brain-save-feedback small {
|
|
1493
|
+
grid-column: 2;
|
|
1494
|
+
color: hsl(var(--fg-muted));
|
|
1495
|
+
font-size: 0.72rem;
|
|
1496
|
+
font-weight: 560;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1434
1499
|
.brain-message {
|
|
1435
1500
|
max-width: 78%;
|
|
1436
1501
|
margin-bottom: 1.1rem;
|
|
@@ -1911,6 +1976,59 @@ body {
|
|
|
1911
1976
|
outline: none;
|
|
1912
1977
|
}
|
|
1913
1978
|
|
|
1979
|
+
.brain-depth-rail {
|
|
1980
|
+
position: absolute;
|
|
1981
|
+
left: 50%;
|
|
1982
|
+
top: 0.85rem;
|
|
1983
|
+
z-index: 6;
|
|
1984
|
+
display: flex;
|
|
1985
|
+
width: min(92vw, 35rem);
|
|
1986
|
+
transform: translateX(-50%);
|
|
1987
|
+
gap: 0.28rem;
|
|
1988
|
+
border: 1px solid hsl(var(--border) / 0.48);
|
|
1989
|
+
border-radius: 999px;
|
|
1990
|
+
background: hsl(var(--surface-glass));
|
|
1991
|
+
padding: 0.32rem;
|
|
1992
|
+
box-shadow: 0 12px 30px hsl(200 30% 3% / 0.18);
|
|
1993
|
+
backdrop-filter: blur(18px);
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
.brain-depth-rail button {
|
|
1997
|
+
display: inline-grid;
|
|
1998
|
+
min-width: 0;
|
|
1999
|
+
flex: 1 1 0;
|
|
2000
|
+
align-items: center;
|
|
2001
|
+
gap: 0.1rem;
|
|
2002
|
+
border: 0;
|
|
2003
|
+
border-radius: 999px;
|
|
2004
|
+
background: transparent;
|
|
2005
|
+
color: hsl(var(--fg-muted));
|
|
2006
|
+
padding: 0.36rem 0.42rem;
|
|
2007
|
+
text-align: center;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
.brain-depth-rail span {
|
|
2011
|
+
font-size: 0.58rem;
|
|
2012
|
+
font-weight: 840;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
.brain-depth-rail strong {
|
|
2016
|
+
overflow: hidden;
|
|
2017
|
+
text-overflow: ellipsis;
|
|
2018
|
+
white-space: nowrap;
|
|
2019
|
+
font-size: 0.66rem;
|
|
2020
|
+
line-height: 1.05;
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
.brain-depth-rail button.is-revealed {
|
|
2024
|
+
background: hsl(var(--brain-core) / 0.1);
|
|
2025
|
+
color: hsl(var(--fg));
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
.brain-depth-rail button[aria-current="step"] {
|
|
2029
|
+
box-shadow: 0 0 0 1px hsl(var(--brain-core) / 0.38) inset;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
1914
2032
|
.memory-fragment,
|
|
1915
2033
|
.concept-signal,
|
|
1916
2034
|
.graph-node {
|
|
@@ -2833,6 +2951,16 @@ body {
|
|
|
2833
2951
|
.brain-depth-actions button {
|
|
2834
2952
|
flex: 0 0 auto;
|
|
2835
2953
|
}
|
|
2954
|
+
.brain-depth-rail {
|
|
2955
|
+
top: 0.35rem;
|
|
2956
|
+
width: min(100vw - 1rem, 25rem);
|
|
2957
|
+
}
|
|
2958
|
+
.brain-depth-rail strong {
|
|
2959
|
+
display: none;
|
|
2960
|
+
}
|
|
2961
|
+
.brain-readiness-strip {
|
|
2962
|
+
grid-template-columns: 1fr;
|
|
2963
|
+
}
|
|
2836
2964
|
.brain-overview-grid {
|
|
2837
2965
|
grid-template-columns: 1fr;
|
|
2838
2966
|
}
|