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
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/
|
|
126
|
+
[output/release/v7.0.0/SCREENSHOT_INDEX.md](output/release/v7.0.0/SCREENSHOT_INDEX.md)
|
|
127
127
|
|
|
128
128
|
## Install
|
|
129
129
|
|
|
@@ -198,34 +198,28 @@ npm run docs:check-links
|
|
|
198
198
|
|
|
199
199
|
See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for developer workflow details.
|
|
200
200
|
|
|
201
|
-
## Current Release
|
|
202
|
-
|
|
203
|
-
The current
|
|
204
|
-
|
|
205
|
-
- Brain Home
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
- `dist/ltcai-6.6.0-py3-none-any.whl`
|
|
225
|
-
- `dist/ltcai-6.6.0.tar.gz`
|
|
226
|
-
- `ltcai-6.6.0.tgz`
|
|
227
|
-
- `dist/ltcai-6.6.0.vsix`
|
|
228
|
-
- `src-tauri/target/release/bundle/dmg/Lattice AI_6.6.0_aarch64.dmg`
|
|
201
|
+
## Current Release
|
|
202
|
+
|
|
203
|
+
The current release is **7.0.0 Brain Productization Loop**:
|
|
204
|
+
|
|
205
|
+
- Brain Home starts with ingestion: files, folders, notes, and web pages can be
|
|
206
|
+
added directly from the first screen.
|
|
207
|
+
- Every Brain answer can show memory proof and source citations instead of
|
|
208
|
+
asking users to trust an ungrounded chat bubble.
|
|
209
|
+
- The model-continuity demo lets users recheck the same Brain evidence after
|
|
210
|
+
changing models.
|
|
211
|
+
- The first-run loop is optimized for five minutes: add source, ask, see proof,
|
|
212
|
+
then switch or deepen.
|
|
213
|
+
- CI now includes a deterministic recall/KG quality eval so the Brain proof
|
|
214
|
+
promise is guarded before release.
|
|
215
|
+
|
|
216
|
+
Expected artifacts for 7.0.0 release must use exact filenames:
|
|
217
|
+
|
|
218
|
+
- `dist/ltcai-7.0.0-py3-none-any.whl`
|
|
219
|
+
- `dist/ltcai-7.0.0.tar.gz`
|
|
220
|
+
- `ltcai-7.0.0.tgz`
|
|
221
|
+
- `dist/ltcai-7.0.0.vsix`
|
|
222
|
+
- `src-tauri/target/release/bundle/dmg/Lattice AI_7.0.0_aarch64.dmg`
|
|
229
223
|
|
|
230
224
|
Do not upload `dist/*`. Package registry publishing remains owner-run.
|
|
231
225
|
|
|
@@ -244,6 +238,8 @@ Do not upload `dist/*`. Package registry publishing remains owner-run.
|
|
|
244
238
|
|
|
245
239
|
| Version | Theme |
|
|
246
240
|
| --- | --- |
|
|
241
|
+
| 7.0.0 | Brain Productization Loop: first-screen ingestion for files/folders/notes/web, answer-level memory proof and source citations, model-continuity demo flow, five-minute first-run loop, and recall/KG quality eval in CI |
|
|
242
|
+
| 6.7.0 | Brain IA Cleanup: reachable rich pages, separated product routes vs compatibility aliases, shared Brain shell navigation, and lazy-loaded rich pages |
|
|
247
243
|
| 6.6.0 | Brain Proof Runtime: backend-owned Brain proof API, model-continuity wiring, first-screen proof that saved context can be recalled across model changes, and direct Brain Home document upload |
|
|
248
244
|
| 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 |
|
|
249
245
|
| 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 |
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,54 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
The top entry is the current
|
|
4
|
-
historical and may describe behavior as it
|
|
3
|
+
The top entry is either the current unreleased main-branch work or the current
|
|
4
|
+
release line. Older entries are historical and may describe behavior as it
|
|
5
|
+
existed at that release.
|
|
6
|
+
|
|
7
|
+
## [7.0.0] - 2026-06-18
|
|
8
|
+
|
|
9
|
+
> Brain Productization Loop. Turns the Brain proof work into a first-five-minute
|
|
10
|
+
> product flow: add sources, ask a question, see proof/citations, and verify the
|
|
11
|
+
> same Brain evidence after switching models.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- Brain Home ingestion panel for files, local folder paths, notes, and web URLs,
|
|
15
|
+
all backed by existing workspace-scoped ingestion routes.
|
|
16
|
+
- Answer-level Memory proof and source citation cards rendered under assistant
|
|
17
|
+
responses after Brain proof refreshes for the user's query.
|
|
18
|
+
- Model-continuity demo strip that lets the user recheck the same Brain
|
|
19
|
+
evidence and jump to model switching from the Brain flow.
|
|
20
|
+
- Deterministic `scripts/brain_quality_eval.py` recall/KG quality gate, wired
|
|
21
|
+
into CI after the unit suite.
|
|
22
|
+
- Visual mock coverage for Brain proof, document upload, note ingest, folder
|
|
23
|
+
indexing, and web URL ingestion endpoints.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- Brain Home is now ingestion-first instead of chat-first: first screen action
|
|
27
|
+
labels are files/folders/notes/web, with deeper graph/model/settings still
|
|
28
|
+
reachable from the shell.
|
|
29
|
+
- Package/runtime/static metadata is synchronized to 7.0.0; package publish and
|
|
30
|
+
deployment remain owner-run only.
|
|
31
|
+
|
|
32
|
+
## [6.7.0] - 2026-06-18
|
|
33
|
+
|
|
34
|
+
> Brain IA Cleanup. Makes rich product pages reachable from Brain Home,
|
|
35
|
+
> separates visible product IA from legacy compatibility aliases, and
|
|
36
|
+
> code-splits heavy pages out of the first Brain bundle.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
- Brain Home now exposes direct action routes for adding documents, searching
|
|
40
|
+
the knowledge graph, changing models, and opening settings, so the rich
|
|
41
|
+
Capture, Brain explorer, Library, and System pages are reachable from the
|
|
42
|
+
first Brain flow.
|
|
43
|
+
- The post-onboarding app shell now mounts Capture, Brain explorer/graph,
|
|
44
|
+
Library, System, and Act pages inside a shared Brain shell navigation instead
|
|
45
|
+
of leaving those rich pages as compatibility-only routes.
|
|
46
|
+
- `routes.ts` now keeps product shell routes and compatibility aliases in
|
|
47
|
+
separate maps while preserving old hash/entry URLs.
|
|
48
|
+
- Rich pages now load through `React.lazy`, splitting Brain explorer, Capture,
|
|
49
|
+
Library, System, and Act chunks away from the initial Brain Home bundle.
|
|
50
|
+
- Package/runtime/static metadata is synchronized to 6.7.0; package publish and
|
|
51
|
+
deployment remain owner-run only.
|
|
5
52
|
|
|
6
53
|
## [6.6.0] - 2026-06-18
|
|
7
54
|
|
|
@@ -19,6 +66,7 @@ historical and may describe behavior as it existed at that release.
|
|
|
19
66
|
bring back after a useful exchange.
|
|
20
67
|
- Brain Home document upload CTA in the empty state and composer, giving the
|
|
21
68
|
first session a direct way to grow the Brain with files.
|
|
69
|
+
- Refreshed README-linked release evidence under `output/release/v6.6.0/`.
|
|
22
70
|
- Unit coverage for model-independent Brain proof recall behavior.
|
|
23
71
|
- Honest empty-state Brain proof: model-independent capability remains visible,
|
|
24
72
|
but continuity is only marked proven after durable evidence exists.
|
package/frontend/src/App.tsx
CHANGED
|
@@ -2,11 +2,16 @@ import * as React from "react";
|
|
|
2
2
|
import { type BrainState } from "@/components/LivingBrain";
|
|
3
3
|
import { ProductFlow, readProductFlowComplete } from "@/components/ProductFlow";
|
|
4
4
|
import { useAppStore } from "@/store/appStore";
|
|
5
|
-
import { parseHash } from "@/routes";
|
|
6
|
-
import { ActPage } from "@/pages/Act";
|
|
5
|
+
import { parseHash, productShellRoutes } from "@/routes";
|
|
7
6
|
import { BrainHome } from "@/features/brain/BrainHome";
|
|
8
7
|
import { AdminConsole } from "@/features/admin/AdminConsole";
|
|
9
8
|
|
|
9
|
+
const ActPage = React.lazy(() => import("@/pages/Act").then((module) => ({ default: module.ActPage })));
|
|
10
|
+
const BrainPage = React.lazy(() => import("@/pages/Brain").then((module) => ({ default: module.BrainPage })));
|
|
11
|
+
const CapturePage = React.lazy(() => import("@/pages/Capture").then((module) => ({ default: module.CapturePage })));
|
|
12
|
+
const LibraryPage = React.lazy(() => import("@/pages/Library").then((module) => ({ default: module.LibraryPage })));
|
|
13
|
+
const SystemPage = React.lazy(() => import("@/pages/System").then((module) => ({ default: module.SystemPage })));
|
|
14
|
+
|
|
10
15
|
export default function App() {
|
|
11
16
|
const theme = useAppStore((state) => state.theme);
|
|
12
17
|
const language = useAppStore((state) => state.language);
|
|
@@ -41,7 +46,41 @@ export default function App() {
|
|
|
41
46
|
{rawRoute.startsWith("/admin") ? (
|
|
42
47
|
<AdminConsole onBack={() => navigateHash("/brain")} />
|
|
43
48
|
) : parsed.primary === "act" ? (
|
|
44
|
-
<
|
|
49
|
+
<BrainShell active={parsed.primary}>
|
|
50
|
+
<React.Suspense fallback={<PageLoader />}>
|
|
51
|
+
<ActPage initialTab={parsed.tab} />
|
|
52
|
+
</React.Suspense>
|
|
53
|
+
</BrainShell>
|
|
54
|
+
) : parsed.primary === "capture" ? (
|
|
55
|
+
<BrainShell active={parsed.primary}>
|
|
56
|
+
<React.Suspense fallback={<PageLoader />}>
|
|
57
|
+
<CapturePage initialTab={parsed.tab} />
|
|
58
|
+
</React.Suspense>
|
|
59
|
+
</BrainShell>
|
|
60
|
+
) : parsed.primary === "library" ? (
|
|
61
|
+
<BrainShell active={parsed.primary}>
|
|
62
|
+
<React.Suspense fallback={<PageLoader />}>
|
|
63
|
+
<LibraryPage initialTab={parsed.tab} />
|
|
64
|
+
</React.Suspense>
|
|
65
|
+
</BrainShell>
|
|
66
|
+
) : parsed.primary === "system" ? (
|
|
67
|
+
<BrainShell active={parsed.primary}>
|
|
68
|
+
<React.Suspense fallback={<PageLoader />}>
|
|
69
|
+
<SystemPage initialTab={parsed.tab} />
|
|
70
|
+
</React.Suspense>
|
|
71
|
+
</BrainShell>
|
|
72
|
+
) : parsed.primary === "memory" ? (
|
|
73
|
+
<BrainShell active="memory">
|
|
74
|
+
<React.Suspense fallback={<PageLoader />}>
|
|
75
|
+
<BrainPage initialTab="memory" />
|
|
76
|
+
</React.Suspense>
|
|
77
|
+
</BrainShell>
|
|
78
|
+
) : parsed.primary === "brain" && parsed.tab && parsed.tab !== "conversation" ? (
|
|
79
|
+
<BrainShell active="brain">
|
|
80
|
+
<React.Suspense fallback={<PageLoader />}>
|
|
81
|
+
<BrainPage initialTab={parsed.tab} />
|
|
82
|
+
</React.Suspense>
|
|
83
|
+
</BrainShell>
|
|
45
84
|
) : (
|
|
46
85
|
<BrainHome brainState={brainState} intensity={intensity} onBrainChange={setBrain} />
|
|
47
86
|
)}
|
|
@@ -49,6 +88,42 @@ export default function App() {
|
|
|
49
88
|
);
|
|
50
89
|
}
|
|
51
90
|
|
|
91
|
+
function BrainShell({
|
|
92
|
+
active,
|
|
93
|
+
children,
|
|
94
|
+
}: {
|
|
95
|
+
active: string;
|
|
96
|
+
children: React.ReactNode;
|
|
97
|
+
}) {
|
|
98
|
+
return (
|
|
99
|
+
<main className="brain-shell-page" aria-label="Lattice workspace">
|
|
100
|
+
<nav className="brain-shell-nav" aria-label="Brain workspace navigation">
|
|
101
|
+
{productShellRoutes.map((item) => (
|
|
102
|
+
<button
|
|
103
|
+
key={item.id}
|
|
104
|
+
type="button"
|
|
105
|
+
className={item.id === active ? "is-active" : ""}
|
|
106
|
+
onClick={() => navigateHash(`/${item.path}`)}
|
|
107
|
+
>
|
|
108
|
+
{item.label}
|
|
109
|
+
</button>
|
|
110
|
+
))}
|
|
111
|
+
</nav>
|
|
112
|
+
<section className="brain-shell-content">
|
|
113
|
+
{children}
|
|
114
|
+
</section>
|
|
115
|
+
</main>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function PageLoader() {
|
|
120
|
+
return (
|
|
121
|
+
<div className="brain-shell-loader" role="status">
|
|
122
|
+
Loading Brain workspace...
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
52
127
|
function useHashRoute() {
|
|
53
128
|
const read = React.useCallback(() => {
|
|
54
129
|
const hash = window.location.hash.replace(/^#/, "");
|
|
@@ -444,6 +444,11 @@ export const latticeApi = {
|
|
|
444
444
|
return res;
|
|
445
445
|
},
|
|
446
446
|
browserReadUrl: (url: string) => post("/api/browser/read-url", { url }, {}),
|
|
447
|
+
ingestNote: (content: string, title = "Brain note") => post(
|
|
448
|
+
"/knowledge-graph/ingest",
|
|
449
|
+
{ type: "note", content, title, source: "brain_home" },
|
|
450
|
+
{},
|
|
451
|
+
),
|
|
447
452
|
memoryManager: () => get("/api/memory/manager", { sources: [], tiers: [], usage: {} }),
|
|
448
453
|
memoryBrainQuality: () => get("/api/memory/brain-quality", {}),
|
|
449
454
|
memoryBrainProof: (query = "", limit = 3) => get("/api/memory/brain-proof", { proofs: {}, recall: { items: [] }, model_continuity: {}, claims: {} }, { q: query, limit }),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { DatabaseZap, ShieldCheck } from "lucide-react";
|
|
2
|
+
import { Cpu, DatabaseZap, FileText, FileUp, FolderPlus, Globe2, Repeat2, Search, Settings, ShieldCheck } from "lucide-react";
|
|
3
3
|
import { LanguageSwitcher } from "@/components/LanguageSwitcher";
|
|
4
4
|
import { t, type Language } from "@/i18n";
|
|
5
5
|
import type { BrainDepth, BrainProof, BrainReadiness, KnowledgeConcept, MemoryFragment, Message } from "./types";
|
|
@@ -27,6 +27,10 @@ export function BrainConversation({
|
|
|
27
27
|
onDraftChange,
|
|
28
28
|
onImageDataChange,
|
|
29
29
|
onUploadDocument,
|
|
30
|
+
onConnectFolder,
|
|
31
|
+
onIngestNote,
|
|
32
|
+
onIngestWeb,
|
|
33
|
+
onVerifyModelContinuity,
|
|
30
34
|
onSend,
|
|
31
35
|
}: {
|
|
32
36
|
language: Language;
|
|
@@ -48,6 +52,10 @@ export function BrainConversation({
|
|
|
48
52
|
onDraftChange: (value: string) => void;
|
|
49
53
|
onImageDataChange: (value: string | null) => void;
|
|
50
54
|
onUploadDocument: (file: File) => void;
|
|
55
|
+
onConnectFolder: (path: string) => void;
|
|
56
|
+
onIngestNote: (note: string) => void;
|
|
57
|
+
onIngestWeb: (url: string) => void;
|
|
58
|
+
onVerifyModelContinuity: () => void;
|
|
51
59
|
onSend: () => void;
|
|
52
60
|
}) {
|
|
53
61
|
return (
|
|
@@ -63,7 +71,25 @@ export function BrainConversation({
|
|
|
63
71
|
<span>{t(language, "brain.portable")}</span>
|
|
64
72
|
<span>{t(language, "brain.private")}</span>
|
|
65
73
|
</div>
|
|
66
|
-
<div
|
|
74
|
+
<div className="brain-flow-actions" aria-label={t(language, "brain.aria.actions")}>
|
|
75
|
+
<button type="button" onClick={() => navigateHash("/capture")}>
|
|
76
|
+
<FileUp className="h-3.5 w-3.5" />
|
|
77
|
+
{t(language, "brain.action.add")}
|
|
78
|
+
</button>
|
|
79
|
+
<button type="button" onClick={() => navigateHash("/knowledge-graph")}>
|
|
80
|
+
<Search className="h-3.5 w-3.5" />
|
|
81
|
+
{t(language, "brain.action.find")}
|
|
82
|
+
</button>
|
|
83
|
+
<button type="button" onClick={() => navigateHash("/models")}>
|
|
84
|
+
<Cpu className="h-3.5 w-3.5" />
|
|
85
|
+
{t(language, "brain.action.model")}
|
|
86
|
+
</button>
|
|
87
|
+
<button type="button" onClick={() => navigateHash("/settings")}>
|
|
88
|
+
<Settings className="h-3.5 w-3.5" />
|
|
89
|
+
{t(language, "brain.action.settings")}
|
|
90
|
+
</button>
|
|
91
|
+
</div>
|
|
92
|
+
<div className="brain-model-pill">{modelName}</div>
|
|
67
93
|
<button className="brain-admin-link" type="button" onClick={() => navigateHash("/admin")}>
|
|
68
94
|
<ShieldCheck className="h-3.5 w-3.5" />
|
|
69
95
|
{t(language, "brain.admin")}
|
|
@@ -71,6 +97,14 @@ export function BrainConversation({
|
|
|
71
97
|
</div>
|
|
72
98
|
|
|
73
99
|
<div ref={streamRef} className="brain-stream">
|
|
100
|
+
<BrainIngestionPanel
|
|
101
|
+
language={language}
|
|
102
|
+
uploadingDocument={uploadingDocument}
|
|
103
|
+
onUploadDocument={onUploadDocument}
|
|
104
|
+
onConnectFolder={onConnectFolder}
|
|
105
|
+
onIngestNote={onIngestNote}
|
|
106
|
+
onIngestWeb={onIngestWeb}
|
|
107
|
+
/>
|
|
74
108
|
<BrainOverviewPanel
|
|
75
109
|
memories={memories}
|
|
76
110
|
concepts={concepts}
|
|
@@ -78,6 +112,12 @@ export function BrainConversation({
|
|
|
78
112
|
proof={proof}
|
|
79
113
|
onOpenDepth={onOpenDepth}
|
|
80
114
|
/>
|
|
115
|
+
<ModelContinuityDemo
|
|
116
|
+
language={language}
|
|
117
|
+
proof={proof}
|
|
118
|
+
modelName={modelName}
|
|
119
|
+
onVerify={onVerifyModelContinuity}
|
|
120
|
+
/>
|
|
81
121
|
{messages.length === 0 ? (
|
|
82
122
|
<BrainEmptyState
|
|
83
123
|
language={language}
|
|
@@ -90,6 +130,9 @@ export function BrainConversation({
|
|
|
90
130
|
messages.map((message, index) => (
|
|
91
131
|
<div key={`${message.role}-${index}`} className={`brain-message ${message.role}`}>
|
|
92
132
|
<div className="brain-message-bubble">{message.content}</div>
|
|
133
|
+
{message.role === "assistant" && message.proof ? (
|
|
134
|
+
<AnswerProofCard language={language} proof={message.proof} />
|
|
135
|
+
) : null}
|
|
93
136
|
</div>
|
|
94
137
|
))
|
|
95
138
|
)}
|
|
@@ -120,6 +163,143 @@ export function BrainConversation({
|
|
|
120
163
|
);
|
|
121
164
|
}
|
|
122
165
|
|
|
166
|
+
function BrainIngestionPanel({
|
|
167
|
+
language,
|
|
168
|
+
uploadingDocument,
|
|
169
|
+
onUploadDocument,
|
|
170
|
+
onConnectFolder,
|
|
171
|
+
onIngestNote,
|
|
172
|
+
onIngestWeb,
|
|
173
|
+
}: {
|
|
174
|
+
language: Language;
|
|
175
|
+
uploadingDocument: boolean;
|
|
176
|
+
onUploadDocument: (file: File) => void;
|
|
177
|
+
onConnectFolder: (path: string) => void;
|
|
178
|
+
onIngestNote: (note: string) => void;
|
|
179
|
+
onIngestWeb: (url: string) => void;
|
|
180
|
+
}) {
|
|
181
|
+
const [folderPath, setFolderPath] = React.useState("");
|
|
182
|
+
const [note, setNote] = React.useState("");
|
|
183
|
+
const [url, setUrl] = React.useState("");
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<section className="brain-ingestion-panel" aria-label={t(language, "brain.ingest.aria")}>
|
|
187
|
+
<div className="brain-ingestion-head">
|
|
188
|
+
<span>{t(language, "brain.ingest.kicker")}</span>
|
|
189
|
+
<strong>{t(language, "brain.ingest.title")}</strong>
|
|
190
|
+
</div>
|
|
191
|
+
<div className="brain-ingestion-grid">
|
|
192
|
+
<label className={`brain-ingest-tile is-primary ${uploadingDocument ? "is-disabled" : ""}`}>
|
|
193
|
+
<FileUp className="h-4 w-4" />
|
|
194
|
+
<span>{uploadingDocument ? t(language, "brain.upload.uploading") : t(language, "brain.ingest.file")}</span>
|
|
195
|
+
<small>{t(language, "brain.ingest.file.detail")}</small>
|
|
196
|
+
<input
|
|
197
|
+
type="file"
|
|
198
|
+
accept=".pdf,.docx,.xlsx,.pptx,.txt,.md,.csv,application/pdf,text/plain,text/markdown,text/csv"
|
|
199
|
+
className="sr-only"
|
|
200
|
+
disabled={uploadingDocument}
|
|
201
|
+
onChange={(event) => {
|
|
202
|
+
const file = event.target.files?.[0];
|
|
203
|
+
event.currentTarget.value = "";
|
|
204
|
+
if (file) onUploadDocument(file);
|
|
205
|
+
}}
|
|
206
|
+
/>
|
|
207
|
+
</label>
|
|
208
|
+
<form
|
|
209
|
+
className="brain-ingest-tile"
|
|
210
|
+
onSubmit={(event) => {
|
|
211
|
+
event.preventDefault();
|
|
212
|
+
onConnectFolder(folderPath);
|
|
213
|
+
setFolderPath("");
|
|
214
|
+
}}
|
|
215
|
+
>
|
|
216
|
+
<FolderPlus className="h-4 w-4" />
|
|
217
|
+
<span>{t(language, "brain.ingest.folder")}</span>
|
|
218
|
+
<input value={folderPath} onChange={(event) => setFolderPath(event.target.value)} placeholder={t(language, "brain.ingest.folder.placeholder")} />
|
|
219
|
+
</form>
|
|
220
|
+
<form
|
|
221
|
+
className="brain-ingest-tile"
|
|
222
|
+
onSubmit={(event) => {
|
|
223
|
+
event.preventDefault();
|
|
224
|
+
onIngestNote(note);
|
|
225
|
+
setNote("");
|
|
226
|
+
}}
|
|
227
|
+
>
|
|
228
|
+
<FileText className="h-4 w-4" />
|
|
229
|
+
<span>{t(language, "brain.ingest.note")}</span>
|
|
230
|
+
<input value={note} onChange={(event) => setNote(event.target.value)} placeholder={t(language, "brain.ingest.note.placeholder")} />
|
|
231
|
+
</form>
|
|
232
|
+
<form
|
|
233
|
+
className="brain-ingest-tile"
|
|
234
|
+
onSubmit={(event) => {
|
|
235
|
+
event.preventDefault();
|
|
236
|
+
onIngestWeb(url);
|
|
237
|
+
setUrl("");
|
|
238
|
+
}}
|
|
239
|
+
>
|
|
240
|
+
<Globe2 className="h-4 w-4" />
|
|
241
|
+
<span>{t(language, "brain.ingest.web")}</span>
|
|
242
|
+
<input value={url} onChange={(event) => setUrl(event.target.value)} placeholder={t(language, "brain.ingest.web.placeholder")} />
|
|
243
|
+
</form>
|
|
244
|
+
</div>
|
|
245
|
+
</section>
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function ModelContinuityDemo({
|
|
250
|
+
language,
|
|
251
|
+
proof,
|
|
252
|
+
modelName,
|
|
253
|
+
onVerify,
|
|
254
|
+
}: {
|
|
255
|
+
language: Language;
|
|
256
|
+
proof: BrainProof;
|
|
257
|
+
modelName: string;
|
|
258
|
+
onVerify: () => void;
|
|
259
|
+
}) {
|
|
260
|
+
return (
|
|
261
|
+
<section className="brain-model-demo" aria-label={t(language, "brain.modelDemo.aria")}>
|
|
262
|
+
<div>
|
|
263
|
+
<span>{t(language, "brain.modelDemo.kicker")}</span>
|
|
264
|
+
<strong>{proof.modelContinuity.proven ? t(language, "brain.modelDemo.proven") : t(language, "brain.modelDemo.pending")}</strong>
|
|
265
|
+
<small>{t(language, "brain.modelDemo.detail", { model: proof.modelContinuity.activeModel || modelName })}</small>
|
|
266
|
+
</div>
|
|
267
|
+
<button type="button" onClick={onVerify}>
|
|
268
|
+
<Repeat2 className="h-3.5 w-3.5" />
|
|
269
|
+
{t(language, "brain.modelDemo.verify")}
|
|
270
|
+
</button>
|
|
271
|
+
<button type="button" onClick={() => navigateHash("/models")}>
|
|
272
|
+
<Cpu className="h-3.5 w-3.5" />
|
|
273
|
+
{t(language, "brain.modelDemo.change")}
|
|
274
|
+
</button>
|
|
275
|
+
</section>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function AnswerProofCard({ language, proof }: { language: Language; proof: NonNullable<Message["proof"]> }) {
|
|
280
|
+
return (
|
|
281
|
+
<div className="brain-answer-proof" aria-label={t(language, "brain.answerProof.aria")}>
|
|
282
|
+
<div className="brain-answer-proof-head">
|
|
283
|
+
<span>{t(language, "brain.answerProof.title")}</span>
|
|
284
|
+
<strong>{proof.provenAcrossModels ? t(language, "brain.answerProof.modelProven", { model: proof.model }) : t(language, "brain.answerProof.modelPending", { model: proof.model })}</strong>
|
|
285
|
+
</div>
|
|
286
|
+
{proof.citations.length ? (
|
|
287
|
+
<ol>
|
|
288
|
+
{proof.citations.map((citation) => (
|
|
289
|
+
<li key={citation.id}>
|
|
290
|
+
<span>{citation.source}</span>
|
|
291
|
+
<strong>{citation.title}</strong>
|
|
292
|
+
<small>{citation.snippet || proof.query}</small>
|
|
293
|
+
</li>
|
|
294
|
+
))}
|
|
295
|
+
</ol>
|
|
296
|
+
) : (
|
|
297
|
+
<small>{t(language, "brain.answerProof.empty")}</small>
|
|
298
|
+
)}
|
|
299
|
+
</div>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
123
303
|
function BrainEmptyState({
|
|
124
304
|
language,
|
|
125
305
|
starterPrompts,
|