ltcai 7.7.0 → 7.9.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.
Files changed (61) hide show
  1. package/README.md +38 -26
  2. package/docs/CHANGELOG.md +37 -0
  3. package/docs/DEVELOPMENT.md +1 -2
  4. package/docs/MULTI_AGENT_RUNTIME.md +6 -5
  5. package/docs/V2_ARCHITECTURE.md +3 -2
  6. package/frontend/src/App.tsx +3 -1
  7. package/frontend/src/components/ProductFlow.tsx +19 -23
  8. package/frontend/src/components/onboarding/RecommendationScreen.tsx +11 -12
  9. package/frontend/src/features/brain/BrainConversation.tsx +107 -108
  10. package/frontend/src/features/brain/BrainHome.tsx +32 -33
  11. package/frontend/src/i18n.ts +53 -19
  12. package/frontend/src/pages/Ask.tsx +11 -2
  13. package/frontend/src/pages/Brain.tsx +12 -2
  14. package/frontend/src/styles.css +390 -65
  15. package/lattice_brain/__init__.py +1 -1
  16. package/lattice_brain/runtime/__init__.py +8 -2
  17. package/lattice_brain/runtime/agent_runtime.py +17 -1
  18. package/lattice_brain/runtime/contracts.py +64 -1
  19. package/lattice_brain/runtime/multi_agent.py +1 -1
  20. package/latticeai/__init__.py +1 -1
  21. package/latticeai/core/agent.py +39 -12
  22. package/latticeai/core/marketplace.py +1 -1
  23. package/latticeai/core/workspace_os.py +1 -1
  24. package/latticeai/services/architecture_readiness.py +1 -1
  25. package/latticeai/services/product_readiness.py +22 -15
  26. package/latticeai/services/tool_dispatch.py +15 -3
  27. package/package.json +1 -1
  28. package/scripts/product_readiness.py +1 -1
  29. package/src-tauri/Cargo.lock +1 -1
  30. package/src-tauri/Cargo.toml +1 -1
  31. package/src-tauri/tauri.conf.json +1 -1
  32. package/static/app/asset-manifest.json +28 -28
  33. package/static/app/assets/Act-DOvf59ru.js +2 -0
  34. package/static/app/assets/{Act-CX5hL0Z3.js.map → Act-DOvf59ru.js.map} +1 -1
  35. package/static/app/assets/Brain-C7_0mEiI.js +322 -0
  36. package/static/app/assets/Brain-C7_0mEiI.js.map +1 -0
  37. package/static/app/assets/Capture-B9Tlhzqr.js +2 -0
  38. package/static/app/assets/{Capture-CdFSrZnA.js.map → Capture-B9Tlhzqr.js.map} +1 -1
  39. package/static/app/assets/{Library-CZFVGSmG.js → Library-BJPEEm5O.js} +2 -2
  40. package/static/app/assets/{Library-CZFVGSmG.js.map → Library-BJPEEm5O.js.map} +1 -1
  41. package/static/app/assets/System-D6t9jo9V.js +2 -0
  42. package/static/app/assets/{System-CMoOoUrZ.js.map → System-D6t9jo9V.js.map} +1 -1
  43. package/static/app/assets/index-C7g26IF6.css +2 -0
  44. package/static/app/assets/index-DbcEYJQ2.js +17 -0
  45. package/static/app/assets/{index-B4_drWel.js.map → index-DbcEYJQ2.js.map} +1 -1
  46. package/static/app/assets/primitives-CD38lt4n.js +2 -0
  47. package/static/app/assets/{primitives-CFhU5Rka.js.map → primitives-CD38lt4n.js.map} +1 -1
  48. package/static/app/assets/textarea-BZk6ybp5.js +2 -0
  49. package/static/app/assets/{textarea-uBpGDOJM.js.map → textarea-BZk6ybp5.js.map} +1 -1
  50. package/static/app/index.html +2 -2
  51. package/frontend/src/components/BrainConversation.tsx +0 -533
  52. package/frontend/src/components/FirstRunGuide.tsx +0 -99
  53. package/static/app/assets/Act-CX5hL0Z3.js +0 -2
  54. package/static/app/assets/Brain-m19en5wz.js +0 -322
  55. package/static/app/assets/Brain-m19en5wz.js.map +0 -1
  56. package/static/app/assets/Capture-CdFSrZnA.js +0 -2
  57. package/static/app/assets/System-CMoOoUrZ.js +0 -2
  58. package/static/app/assets/index-B4_drWel.js +0 -17
  59. package/static/app/assets/index-DjpDeE0c.css +0 -2
  60. package/static/app/assets/primitives-CFhU5Rka.js +0 -2
  61. package/static/app/assets/textarea-uBpGDOJM.js +0 -2
@@ -12,7 +12,6 @@ import {
12
12
  Loader2,
13
13
  Repeat2,
14
14
  Search,
15
- Settings,
16
15
  ShieldCheck,
17
16
  Sparkles,
18
17
  } from "lucide-react";
@@ -44,7 +43,6 @@ import { BrainOverviewPanel } from "./BrainOverviewPanel";
44
43
 
45
44
  export function BrainConversation({
46
45
  language,
47
- explorationDepth,
48
46
  modelName,
49
47
  messages,
50
48
  starterPrompts,
@@ -100,129 +98,130 @@ export function BrainConversation({
100
98
  return (
101
99
  <section className="brain-conversation" aria-label={t(language, "brain.aria.conversation")}>
102
100
  <div className="brain-conversation-header">
103
- <div>
101
+ <div className="brain-conversation-title">
104
102
  <h1>
105
103
  {t(language, "brain.title")}
106
104
  <span className="brain-edition-badge" title={t(language, "brain.edition.tip")}>
107
105
  {t(language, "brain.edition")}
108
106
  </span>
109
107
  </h1>
110
- <span>{t(language, `brain.depth.${explorationDepth}`)}</span>
111
- </div>
112
- <LanguageSwitcher compact />
113
- <div className="brain-ownership-strip" aria-label={t(language, "brain.aria.ownership")}>
114
- <span>{t(language, "brain.local")}</span>
115
- <span>{t(language, "brain.portable")}</span>
116
- <span>{t(language, "brain.private")}</span>
108
+ <span>{t(language, "brain.chatHome.headerLine")}</span>
117
109
  </div>
118
- <div className="brain-flow-actions" aria-label={t(language, "brain.aria.actions")}>
119
- <button type="button" onClick={() => navigateHash("/capture")}>
120
- <FileUp className="h-3.5 w-3.5" />
121
- {t(language, "brain.action.add")}
122
- </button>
123
- <button type="button" onClick={() => navigateHash("/knowledge-graph")}>
124
- <Search className="h-3.5 w-3.5" />
125
- {t(language, "brain.action.find")}
126
- </button>
127
- <button type="button" onClick={() => navigateHash("/models")}>
128
- <Cpu className="h-3.5 w-3.5" />
129
- {t(language, "brain.action.model")}
130
- </button>
131
- <button type="button" onClick={() => navigateHash("/settings")}>
132
- <Settings className="h-3.5 w-3.5" />
133
- {t(language, "brain.action.settings")}
110
+ <div className="brain-header-tools">
111
+ <LanguageSwitcher compact />
112
+ <div className="brain-model-pill">{modelName}</div>
113
+ <button className="brain-admin-link" type="button" onClick={() => navigateHash("/admin")}>
114
+ <ShieldCheck className="h-3.5 w-3.5" />
115
+ {t(language, "brain.admin")}
134
116
  </button>
135
117
  </div>
136
- <div className="brain-model-pill">{modelName}</div>
137
- <button className="brain-admin-link" type="button" onClick={() => navigateHash("/admin")}>
138
- <ShieldCheck className="h-3.5 w-3.5" />
139
- {t(language, "brain.admin")}
140
- </button>
141
118
  </div>
142
119
 
143
- <div ref={streamRef} className="brain-stream">
144
- <ProductCommandCenter
145
- language={language}
146
- readiness={readiness}
147
- proof={proof}
148
- modelName={modelName}
149
- memories={memories}
150
- concepts={concepts}
151
- emergenceEvents={emergenceEvents}
152
- onOpenDepth={onOpenDepth}
153
- onVerifyModelContinuity={onVerifyModelContinuity}
154
- />
155
- <BrainIngestionPanel
156
- language={language}
157
- uploadingDocument={uploadingDocument}
158
- ingestionStates={ingestionStates}
159
- onUploadDocument={onUploadDocument}
160
- onConnectFolder={onConnectFolder}
161
- onIngestNote={onIngestNote}
162
- onIngestWeb={onIngestWeb}
163
- />
164
- <IngestionTimelineSection language={language} emergenceEvents={emergenceEvents} />
165
- <BrainOverviewPanel
166
- memories={memories}
167
- concepts={concepts}
168
- readiness={readiness}
169
- proof={proof}
170
- onOpenDepth={onOpenDepth}
171
- />
172
- <ModelContinuityDemo
173
- language={language}
174
- proof={proof}
175
- modelName={modelName}
176
- onVerify={onVerifyModelContinuity}
177
- />
178
- {messages.length === 0 ? (
179
- <BrainEmptyState
120
+ <div className="brain-chat-home-layout">
121
+ <section className="brain-chat-home-card" aria-label={t(language, "brain.chatHome.aria")}>
122
+ <div className="brain-chat-home-head">
123
+ <div>
124
+ <span>{t(language, "brain.chatHome.kicker")}</span>
125
+ <h2>{t(language, "brain.chatHome.title")}</h2>
126
+ <p>{t(language, "brain.chatHome.body")}</p>
127
+ </div>
128
+ <div className="brain-chat-home-proof" aria-label={t(language, "brain.aria.ownership")}>
129
+ <span><CheckCircle2 className="h-3.5 w-3.5" />{t(language, "brain.local")}</span>
130
+ <span><CheckCircle2 className="h-3.5 w-3.5" />{t(language, "brain.private")}</span>
131
+ <span><CheckCircle2 className="h-3.5 w-3.5" />{t(language, "brain.portable")}</span>
132
+ </div>
133
+ </div>
134
+
135
+ <div ref={streamRef} className="brain-stream">
136
+ {messages.length === 0 ? (
137
+ <BrainEmptyState
138
+ language={language}
139
+ starterPrompts={starterPrompts}
140
+ uploadingDocument={uploadingDocument}
141
+ onDraftChange={onDraftChange}
142
+ onUploadDocument={onUploadDocument}
143
+ />
144
+ ) : (
145
+ messages.map((message, index) => {
146
+ const messageId = `brain-msg-${index}`;
147
+ const proof = message.role === "assistant" ? message.proof : undefined;
148
+ return (
149
+ <div key={`${message.role}-${index}`} className={`brain-message ${message.role}`}>
150
+ <div className="brain-message-bubble">
151
+ {message.content}
152
+ {proof && proof.citations.length ? (
153
+ <InlineCitationMarkers language={language} proof={proof} messageId={messageId} />
154
+ ) : null}
155
+ </div>
156
+ {proof ? <AnswerProofCard language={language} proof={proof} messageId={messageId} /> : null}
157
+ </div>
158
+ );
159
+ })
160
+ )}
161
+ </div>
162
+
163
+ {memoryFeedback ? (
164
+ <div className="brain-save-feedback" role="status">
165
+ <DatabaseZap className="h-3.5 w-3.5" />
166
+ <span>{memoryFeedback}</span>
167
+ <small>{t(language, "brain.saved.detail")}</small>
168
+ </div>
169
+ ) : null}
170
+
171
+ <BrainComposer
180
172
  language={language}
181
- starterPrompts={starterPrompts}
173
+ draft={draft}
174
+ streaming={streaming}
175
+ imageData={imageData}
182
176
  uploadingDocument={uploadingDocument}
183
177
  onDraftChange={onDraftChange}
178
+ onImageDataChange={onImageDataChange}
184
179
  onUploadDocument={onUploadDocument}
180
+ onSend={onSend}
185
181
  />
186
- ) : (
187
- messages.map((message, index) => {
188
- const messageId = `brain-msg-${index}`;
189
- const proof = message.role === "assistant" ? message.proof : undefined;
190
- return (
191
- <div key={`${message.role}-${index}`} className={`brain-message ${message.role}`}>
192
- <div className="brain-message-bubble">
193
- {message.content}
194
- {proof && proof.citations.length ? (
195
- <InlineCitationMarkers language={language} proof={proof} messageId={messageId} />
196
- ) : null}
197
- </div>
198
- {proof ? <AnswerProofCard language={language} proof={proof} messageId={messageId} /> : null}
199
- </div>
200
- );
201
- })
202
- )}
203
- </div>
204
182
 
205
- {memoryFeedback ? (
206
- <div className="brain-save-feedback" role="status">
207
- <DatabaseZap className="h-3.5 w-3.5" />
208
- <span>{memoryFeedback}</span>
209
- <small>{t(language, "brain.saved.detail")}</small>
210
- </div>
211
- ) : null}
212
-
213
- <BrainCarePanel language={language} />
214
-
215
- <BrainComposer
216
- language={language}
217
- draft={draft}
218
- streaming={streaming}
219
- imageData={imageData}
220
- uploadingDocument={uploadingDocument}
221
- onDraftChange={onDraftChange}
222
- onImageDataChange={onImageDataChange}
223
- onUploadDocument={onUploadDocument}
224
- onSend={onSend}
225
- />
183
+ <details className="brain-utility-drawer">
184
+ <summary>{t(language, "brain.chatHome.utility")}</summary>
185
+ <div className="brain-utility-grid">
186
+ <BrainIngestionPanel
187
+ language={language}
188
+ uploadingDocument={uploadingDocument}
189
+ ingestionStates={ingestionStates}
190
+ onUploadDocument={onUploadDocument}
191
+ onConnectFolder={onConnectFolder}
192
+ onIngestNote={onIngestNote}
193
+ onIngestWeb={onIngestWeb}
194
+ />
195
+ <ProductCommandCenter
196
+ language={language}
197
+ readiness={readiness}
198
+ proof={proof}
199
+ modelName={modelName}
200
+ memories={memories}
201
+ concepts={concepts}
202
+ emergenceEvents={emergenceEvents}
203
+ onOpenDepth={onOpenDepth}
204
+ onVerifyModelContinuity={onVerifyModelContinuity}
205
+ />
206
+ <IngestionTimelineSection language={language} emergenceEvents={emergenceEvents} />
207
+ <ModelContinuityDemo
208
+ language={language}
209
+ proof={proof}
210
+ modelName={modelName}
211
+ onVerify={onVerifyModelContinuity}
212
+ />
213
+ <BrainOverviewPanel
214
+ memories={memories}
215
+ concepts={concepts}
216
+ readiness={readiness}
217
+ proof={proof}
218
+ onOpenDepth={onOpenDepth}
219
+ />
220
+ <BrainCarePanel language={language} />
221
+ </div>
222
+ </details>
223
+ </section>
224
+ </div>
226
225
  </section>
227
226
  );
228
227
  }
@@ -483,11 +483,6 @@ export function BrainHome({
483
483
 
484
484
  return (
485
485
  <main className="brain-home" aria-label={t(language, "brain.aria.home")}>
486
- {/* 강력하고 직관적인 첫인상 - BrainHome */}
487
- <div style={{textAlign: "center", marginBottom: "0.4rem", opacity: 0.9}}>
488
- <div style={{fontSize: "0.78rem", letterSpacing: "1.5px", textTransform: "uppercase", color: "hsl(var(--brain-core))"}}>LATTICE AI — YOUR LIVING BRAIN</div>
489
- <div style={{fontSize: "1.05rem", fontWeight: 600, marginTop: "0.15rem"}}>대화할수록 더 똑똑해지는, 당신만의 영원한 지식</div>
490
- </div>
491
486
  <section className="brain-presence" aria-label={t(language, "brain.aria.exploration")}>
492
487
  <div className="brain-exploration" data-depth={explorationDepth}>
493
488
  <LivingBrain
@@ -499,34 +494,38 @@ export function BrainHome({
499
494
  onInteract={deepen}
500
495
  />
501
496
 
502
- <BrainDepthRings explorationDepth={explorationDepth} onOpenDepth={jumpToDepth} />
503
-
504
- <div className="brain-depth-badge" aria-live="polite">
505
- <span>{t(language, "brain.level")} {explorationDepth}</span>
506
- <strong>{t(language, `brain.depth.${explorationDepth}`)}</strong>
507
- </div>
508
-
509
- <div className="brain-depth-actions" aria-label={t(language, "brain.aria.quickViews")}>
510
- <button type="button" className={explorationDepth === 2 ? "is-active" : ""} onClick={() => jumpToDepth(2)}>{t(language, "brain.view.memories")}</button>
511
- <button type="button" className={explorationDepth === 3 ? "is-active" : ""} onClick={() => jumpToDepth(3)}>{t(language, "brain.view.topics")}</button>
512
- <button type="button" className={explorationDepth === 4 ? "is-active" : ""} onClick={() => jumpToDepth(4)}>{t(language, "brain.view.relationships")}</button>
513
- <button type="button" className={explorationDepth === 5 ? "is-active" : ""} onClick={() => jumpToDepth(5)}>{t(language, "brain.view.graph")}</button>
514
- </div>
515
-
516
- <div className="brain-depth-rail" aria-label={t(language, "brain.depthRail.aria")}>
517
- {DEPTHS.map((depth) => (
518
- <button
519
- key={depth.level}
520
- type="button"
521
- className={depth.level <= explorationDepth ? "is-revealed" : ""}
522
- aria-current={depth.level === explorationDepth ? "step" : undefined}
523
- onClick={() => jumpToDepth(depth.level)}
524
- >
525
- <span>{depth.level}</span>
526
- <strong>{t(language, `brain.depth.${depth.level}`)}</strong>
527
- </button>
528
- ))}
529
- </div>
497
+ {explorationDepth > 1 ? (
498
+ <>
499
+ <BrainDepthRings explorationDepth={explorationDepth} onOpenDepth={jumpToDepth} />
500
+
501
+ <div className="brain-depth-badge" aria-live="polite">
502
+ <span>{t(language, "brain.level")} {explorationDepth}</span>
503
+ <strong>{t(language, `brain.depth.${explorationDepth}`)}</strong>
504
+ </div>
505
+
506
+ <div className="brain-depth-actions" aria-label={t(language, "brain.aria.quickViews")}>
507
+ <button type="button" className={explorationDepth === 2 ? "is-active" : ""} onClick={() => jumpToDepth(2)}>{t(language, "brain.view.memories")}</button>
508
+ <button type="button" className={explorationDepth === 3 ? "is-active" : ""} onClick={() => jumpToDepth(3)}>{t(language, "brain.view.topics")}</button>
509
+ <button type="button" className={explorationDepth === 4 ? "is-active" : ""} onClick={() => jumpToDepth(4)}>{t(language, "brain.view.relationships")}</button>
510
+ <button type="button" className={explorationDepth === 5 ? "is-active" : ""} onClick={() => jumpToDepth(5)}>{t(language, "brain.view.graph")}</button>
511
+ </div>
512
+
513
+ <div className="brain-depth-rail" aria-label={t(language, "brain.depthRail.aria")}>
514
+ {DEPTHS.map((depth) => (
515
+ <button
516
+ key={depth.level}
517
+ type="button"
518
+ className={depth.level <= explorationDepth ? "is-revealed" : ""}
519
+ aria-current={depth.level === explorationDepth ? "step" : undefined}
520
+ onClick={() => jumpToDepth(depth.level)}
521
+ >
522
+ <span>{depth.level}</span>
523
+ <strong>{t(language, `brain.depth.${depth.level}`)}</strong>
524
+ </button>
525
+ ))}
526
+ </div>
527
+ </>
528
+ ) : null}
530
529
 
531
530
  <div className="brain-field-layer" aria-hidden={explorationDepth < 2}>
532
531
  <DepthEmergence
@@ -40,7 +40,7 @@ export const COPY: Record<Language, TextMap> = {
40
40
  "brain.aria.graph": "지식 그래프",
41
41
  "brain.title": "Lattice Brain",
42
42
  "brain.edition": "정식 제품",
43
- "brain.edition.tip": "Lattice AI 7.7완성된 정식 출시 디지털 브레인",
43
+ "brain.edition.tip": "Lattice AI 7.8한눈에 바로 쓰는 디지털 브레인",
44
44
  "brain.local": "로컬 우선",
45
45
  "brain.portable": "이동 가능",
46
46
  "brain.private": "개인 소유",
@@ -68,6 +68,13 @@ export const COPY: Record<Language, TextMap> = {
68
68
  "brain.command.signal.local": "로컬 우선",
69
69
  "brain.command.signal.private": "명시 동의",
70
70
  "brain.command.signal.portable": "백업 가능",
71
+ "brain.chatHome.aria": "Brain Chat Home",
72
+ "brain.chatHome.contextAria": "Brain 상태와 자료 패널",
73
+ "brain.chatHome.headerLine": "대화, 자료, 기억 상태를 한 화면에서 바로 조작합니다.",
74
+ "brain.chatHome.kicker": "Brain Chat Home",
75
+ "brain.chatHome.title": "먼저 질문하고, 필요하면 자료를 넣으세요.",
76
+ "brain.chatHome.body": "입력창과 시작 프롬프트를 첫 화면에 고정하고, 준비도와 수집 상태는 옆에서 조용히 따라오게 했습니다.",
77
+ "brain.chatHome.utility": "자료 넣기와 Brain 상태",
71
78
  "shell.route.brain": "Lattice Brain",
72
79
  "shell.route.capture": "자료",
73
80
  "shell.route.memory": "그래프",
@@ -107,6 +114,8 @@ export const COPY: Record<Language, TextMap> = {
107
114
  "brain.empty.trail.save": "1. 첫 기억 저장",
108
115
  "brain.empty.trail.recall": "2. Brain Home에서 확인",
109
116
  "brain.empty.trail.backup": "3. 백업으로 소유",
117
+ "brain.home.kicker": "Lattice AI — Living Brain",
118
+ "brain.home.line": "대화할수록 선명해지는, 내 로컬 지식의 중심",
110
119
  "brain.prompt.remember": "이 목표를 Brain이 영원히 기억하게 해줘: ",
111
120
  "brain.prompt.know": "이걸 Brain에 넣고 핵심을 뽑아줘: ",
112
121
  "brain.prompt.plan": "과거 결정들을 Brain이 구조화해서 나중에 쉽게 찾게 해줘: ",
@@ -521,16 +530,24 @@ export const COPY: Record<Language, TextMap> = {
521
530
  "flow.install.expectedCompletion": "끝나면 바로 Brain이 열립니다.",
522
531
  "flow.shell": "내 로컬 AI 브레인 만들기",
523
532
  "flow.wake.aria": "Brain 깨우기",
524
- "flow.wake.title": "당신의 지식이 영원히 살아 숨쉬는 Brain을 지금 시작하세요.",
525
- "flow.wake.body": "대화할수록 똑똑해지는 당신만의 AI. 모델 바꿔도 기억은 영원히. 로컬, 직관적, 강력. 처음 보는 순간 쓰고 싶어지는 Brain 시작하세요.",
533
+ "flow.wake.title": " 지식이 살아나는 Brain을 시작하세요.",
534
+ "flow.wake.body": "Lattice AI는 컴퓨터 안에서 대화, 문서, 결정이 오래 남는 작업 기억이 되게 합니다. 모델은 바꿔도 Brain 계속 내 것입니다.",
535
+ "flow.wake.value.aria": "Brain 시작 가치",
536
+ "flow.wake.value.local.k": "완전 로컬",
537
+ "flow.wake.value.local.v": "지식과 대화는 이 컴퓨터에서 먼저 정리됩니다.",
538
+ "flow.wake.value.instant.k": "바로 이해",
539
+ "flow.wake.value.instant.v": "복잡한 설정 대신 3단계로 첫 대화를 엽니다.",
540
+ "flow.wake.value.brain.k": "지속되는 Brain",
541
+ "flow.wake.value.brain.v": "모델을 바꿔도 내 기억과 그래프는 이어집니다.",
526
542
  "flow.wake.plan.aria": "Brain 시작 단계",
527
543
  "flow.wake.step.identity": "주인 확인",
528
544
  "flow.wake.step.check": "컴퓨터 확인",
529
545
  "flow.wake.step.voice": "목소리 선택",
530
546
  "flow.wake.primary": "Brain 지금 깨우기",
531
547
  "flow.wake.existing": "기존 Brain 열기",
532
- "flow.login.title": " Brain의 주인은 바로 당신입니다.",
533
- "flow.login.body": "이 컴퓨터에 사는, 당신만의 영원한 지식 Brain. 3단계로 직관적으로 시작. 모델은 나중에 바꿔도 모든 것이 그대로입니다.",
548
+ "flow.wake.startNote": "평균 2분 안에 대화 시작 · 로컬 우선 · 사용자가 제어",
549
+ "flow.login.title": "이 Brain 주인을 정합니다.",
550
+ "flow.login.body": "프로필은 로컬 Brain의 소유권을 묶는 기준입니다. 기존 Brain이 있으면 새로 만들기 전에 먼저 안전하게 확인합니다.",
534
551
  "flow.name": "이름",
535
552
  "flow.name.placeholder": "나",
536
553
  "flow.email": "이메일",
@@ -551,8 +568,8 @@ export const COPY: Record<Language, TextMap> = {
551
568
  "flow.promise.ownership.k": "사용자 소유",
552
569
  "flow.promise.ownership.v": "백업, 복원, 이동을 직접 결정합니다.",
553
570
  "flow.promise.aria": "Lattice AI 제품 약속",
554
- "flow.analysis.title": "이 컴퓨터에서 가장 자연스럽고 강력한 Brain 경험을 확인합니다.",
555
- "flow.analysis.body": "스펙이 아니라, 당신의 Mac에서 즉시 직관적으로 쓸 수 있는 로컬 AI 브레인 수준을 보여드립니다. 로컬 상태만 읽고, 클라우드는 선택입니다. 바로 쓰고 싶어지게 준비됐습니다.",
571
+ "flow.analysis.title": "이 컴퓨터에 맞는 Brain 경험을 확인합니다.",
572
+ "flow.analysis.body": "스펙 점수가 아니라, Mac에서 어떤 로컬 AI 브레인 경험이 편한지 보여드립니다. 확인은 로컬 상태를 읽는 것이고, 클라우드 모델은 선택 사항입니다.",
556
573
  "flow.analysis.finding": "가장 편한 설정을 찾는 중...",
557
574
  "flow.analysis.ready": "추천 모델을 바로 시작할 수 있게 준비했습니다.",
558
575
  "flow.analysis.wait": "잠시만 기다리면 자동으로 정리됩니다.",
@@ -563,18 +580,18 @@ export const COPY: Record<Language, TextMap> = {
563
580
  "flow.analysis.os.windows": "Windows PC",
564
581
  "flow.analysis.os.linux": "Linux 컴퓨터",
565
582
  "flow.recommend.title": "추천대로 시작하세요.",
566
- "flow.recommend.body": "모델은 Brain의 목소리일 뿐. 가장 직관적이고 빠른 시작을 위한 추천, 빠른 모델, 강력한 모델을 먼저 보여드립니다. 선택하면 바로 대화가 시작됩니다.",
583
+ "flow.recommend.body": "모델은 Brain의 현재 목소리입니다. 추천, 빠른 선택, 강한 선택만 먼저 보여드려 바로 결정할 수 있게 합니다.",
567
584
  "flow.recommend.primary": "추천으로 바로 시작",
568
585
  "flow.recommend.unsupported": "이 컴퓨터에서 추가 확인이 필요합니다",
569
586
  "flow.recommend.back": "뒤로",
570
587
  "flow.recommend.skip": "모델 없이 Brain 열기",
571
- "flow.recommend.hint": "추천을 선택하면 가장 부드럽고 직관적인 경험이 시작됩니다.",
588
+ "flow.recommend.hint": " 모르겠다면 추천대로 시작하면 됩니다.",
572
589
  "flow.recommend.rank.best": "추천",
573
590
  "flow.recommend.rank.faster": "빠른 선택",
574
591
  "flow.recommend.rank.advanced": "고급 선택",
575
592
  "flow.recommend.rank.choice": "선택 {index}",
576
593
  "flow.install.title": "모델을 설치하고 시작합니다.",
577
- "flow.install.body": "이 모델이 당신 Brain의 로컬 목소리가 됩니다. 다운로드는 번뿐, 모든 대화와 기억은 완전 로컬. 직관적이고 강력한 경험을 바로 느껴보세요.",
594
+ "flow.install.body": "이 모델이 Brain의 로컬 목소리가 됩니다. 다운로드는 사용자가 시작할 때만 진행되고, 실행과 기억은 컴퓨터에서 유지됩니다.",
578
595
  "flow.install.wait": "Brain이 사용할 모델을 기다리고 있습니다.",
579
596
  "flow.install.prepare": "Brain 준비 중입니다.",
580
597
  "flow.install.done": "Brain이 준비되었습니다.",
@@ -664,7 +681,7 @@ export const COPY: Record<Language, TextMap> = {
664
681
  "brain.aria.graph": "Knowledge Graph",
665
682
  "brain.title": "Lattice Brain",
666
683
  "brain.edition": "Production Ready",
667
- "brain.edition.tip": "Lattice AI 7.7your finished, production-ready Digital Brain",
684
+ "brain.edition.tip": "Lattice AI 7.8a Digital Brain you can understand and use at a glance",
668
685
  "brain.local": "Local-first",
669
686
  "brain.portable": "Portable",
670
687
  "brain.private": "Private",
@@ -692,6 +709,13 @@ export const COPY: Record<Language, TextMap> = {
692
709
  "brain.command.signal.local": "Local-first",
693
710
  "brain.command.signal.private": "Consent gated",
694
711
  "brain.command.signal.portable": "Backup ready",
712
+ "brain.chatHome.aria": "Brain Chat Home",
713
+ "brain.chatHome.contextAria": "Brain status and source panel",
714
+ "brain.chatHome.headerLine": "Chat, sources, and memory status are usable from one screen.",
715
+ "brain.chatHome.kicker": "Brain Chat Home",
716
+ "brain.chatHome.title": "Ask first, add sources when you need them.",
717
+ "brain.chatHome.body": "The input and starter prompts stay in the first viewport while readiness and ingestion status follow quietly beside them.",
718
+ "brain.chatHome.utility": "Sources and Brain status",
695
719
  "shell.route.brain": "Lattice Brain",
696
720
  "shell.route.capture": "Files",
697
721
  "shell.route.memory": "Graph",
@@ -731,6 +755,8 @@ export const COPY: Record<Language, TextMap> = {
731
755
  "brain.empty.trail.save": "1. Save first memory",
732
756
  "brain.empty.trail.recall": "2. See it in Brain Home",
733
757
  "brain.empty.trail.backup": "3. Own it with backup",
758
+ "brain.home.kicker": "Lattice AI — Living Brain",
759
+ "brain.home.line": "The center of your local knowledge, clearer with every conversation",
734
760
  "brain.prompt.remember": "Remember this project goal: ",
735
761
  "brain.prompt.know": "Put this document into my Brain and summarize it: ",
736
762
  "brain.prompt.plan": "Organize past decisions so I can find them later: ",
@@ -1145,16 +1171,24 @@ export const COPY: Record<Language, TextMap> = {
1145
1171
  "flow.install.expectedCompletion": "When it finishes, your Brain opens right away.",
1146
1172
  "flow.shell": "Create your local AI Brain",
1147
1173
  "flow.wake.aria": "Wake your Brain",
1148
- "flow.wake.title": "Wake your Brain.",
1149
- "flow.wake.body": "This Brain lives on this computer. You can change the model like a voice while your memories and knowledge graph remain yours.",
1174
+ "flow.wake.title": "Start the Brain where your knowledge comes alive.",
1175
+ "flow.wake.body": "Lattice AI turns your conversations, documents, and decisions into durable working memory on this computer. Models can change while your Brain remains yours.",
1176
+ "flow.wake.value.aria": "Brain startup value",
1177
+ "flow.wake.value.local.k": "Fully local",
1178
+ "flow.wake.value.local.v": "Knowledge and conversations are organized on this computer first.",
1179
+ "flow.wake.value.instant.k": "Clear start",
1180
+ "flow.wake.value.instant.v": "Open the first conversation in three guided steps.",
1181
+ "flow.wake.value.brain.k": "Durable Brain",
1182
+ "flow.wake.value.brain.v": "Your memories and graph continue even when models change.",
1150
1183
  "flow.wake.plan.aria": "Brain start steps",
1151
1184
  "flow.wake.step.identity": "Confirm owner",
1152
1185
  "flow.wake.step.check": "Check computer",
1153
1186
  "flow.wake.step.voice": "Choose voice",
1154
1187
  "flow.wake.primary": "Wake Brain",
1155
1188
  "flow.wake.existing": "Open existing Brain",
1156
- "flow.login.title": "Choose the owner of your AI Brain.",
1157
- "flow.login.body": "Lattice AI is a local-first Digital Brain that keeps your knowledge on this computer. Models can change; external transfer starts only when you choose it.",
1189
+ "flow.wake.startNote": "First conversation in about 2 minutes · local-first · user controlled",
1190
+ "flow.login.title": "Choose the owner of this Brain.",
1191
+ "flow.login.body": "Your profile anchors ownership of the local Brain. If a Brain already exists here, Lattice checks safely before creating anything new.",
1158
1192
  "flow.name": "Name",
1159
1193
  "flow.name.placeholder": "You",
1160
1194
  "flow.email": "Email",
@@ -1175,8 +1209,8 @@ export const COPY: Record<Language, TextMap> = {
1175
1209
  "flow.promise.ownership.k": "User owned",
1176
1210
  "flow.promise.ownership.v": "You decide when to back up, restore, or move it.",
1177
1211
  "flow.promise.aria": "Lattice AI product promise",
1178
- "flow.analysis.title": "Checking what this computer can do.",
1179
- "flow.analysis.body": "This is not a spec test. Lattice reads local capability and explains what AI Brain experience this Mac can support. Cloud models remain optional.",
1212
+ "flow.analysis.title": "Checking the Brain experience for this computer.",
1213
+ "flow.analysis.body": "This is not a spec score. Lattice reads local capability and explains which local AI Brain experience will feel comfortable on this Mac. Cloud models remain optional.",
1180
1214
  "flow.analysis.finding": "Finding the easiest setup...",
1181
1215
  "flow.analysis.ready": "Your recommended model is ready to start.",
1182
1216
  "flow.analysis.wait": "This will be summarized automatically in a moment.",
@@ -1187,7 +1221,7 @@ export const COPY: Record<Language, TextMap> = {
1187
1221
  "flow.analysis.os.windows": "Windows PC",
1188
1222
  "flow.analysis.os.linux": "Linux computer",
1189
1223
  "flow.recommend.title": "Start with the recommendation.",
1190
- "flow.recommend.body": "The model is your Brain's current voice. You see the safest recommendation, a faster model, and a stronger model first.",
1224
+ "flow.recommend.body": "The model is your Brain's current voice. Lattice shows the recommendation, a faster choice, and a stronger choice first so you can decide quickly.",
1191
1225
  "flow.recommend.primary": "Start with recommendation",
1192
1226
  "flow.recommend.unsupported": "This computer needs one more check",
1193
1227
  "flow.recommend.back": "Back",
@@ -1198,7 +1232,7 @@ export const COPY: Record<Language, TextMap> = {
1198
1232
  "flow.recommend.rank.advanced": "Advanced",
1199
1233
  "flow.recommend.rank.choice": "Choice {index}",
1200
1234
  "flow.install.title": "Install the model and start.",
1201
- "flow.install.body": "This model becomes your Brain's local voice. Internet is needed only for download; execution and memory stay on this computer.",
1235
+ "flow.install.body": "This model becomes your Brain's local voice. Download starts only when you choose it; execution and memory stay on this computer.",
1202
1236
  "flow.install.wait": "Waiting for the model your Brain will use.",
1203
1237
  "flow.install.prepare": "Preparing your Brain.",
1204
1238
  "flow.install.done": "Your Brain is ready.",
@@ -1,5 +1,14 @@
1
- import { BrainConversation } from "@/components/BrainConversation";
1
+ import * as React from "react";
2
+ import { type BrainState } from "@/components/LivingBrain";
3
+ import { BrainHome } from "@/features/brain/BrainHome";
2
4
 
3
5
  export function AskPage() {
4
- return <BrainConversation />;
6
+ const [brainPresence, setBrainPresence] = React.useState<{ state: BrainState; intensity: number }>({
7
+ state: "idle",
8
+ intensity: 0.58,
9
+ });
10
+ const setBrain = React.useCallback((state: BrainState, intensity = 0.58) => {
11
+ setBrainPresence({ state, intensity });
12
+ }, []);
13
+ return <BrainHome brainState={brainPresence.state} intensity={brainPresence.intensity} onBrainChange={setBrain} />;
5
14
  }
@@ -3,13 +3,14 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3
3
  import cytoscape, { Core, ElementDefinition } from "cytoscape";
4
4
  import { BrainCircuit, DatabaseBackup, Filter, Focus, Layers3, LocateFixed, Search, Sparkles } from "lucide-react";
5
5
  import { latticeApi } from "@/api/client";
6
- import { BrainConversation } from "@/components/BrainConversation";
6
+ import { type BrainState } from "@/components/LivingBrain";
7
7
  import { ActionButton, DataPanel, EmptyState, EntityList, KeyValueList, LoadingPanel, OperationResult, StatGrid, StructuredView, Tabs } from "@/components/primitives";
8
8
  import { Badge } from "@/components/ui/badge";
9
9
  import { Button } from "@/components/ui/button";
10
10
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
11
11
  import { Input } from "@/components/ui/input";
12
12
  import { Textarea } from "@/components/ui/textarea";
13
+ import { BrainHome } from "@/features/brain/BrainHome";
13
14
  import { useAppStore } from "@/store/appStore";
14
15
  import { asArray, fmtNumber, pct, shortId, titleize } from "@/lib/utils";
15
16
 
@@ -416,9 +417,16 @@ export function BrainPage({ initialTab }: { initialTab?: string }) {
416
417
  const mode = useAppStore((state) => state.mode);
417
418
  const normalizedInitialTab = normalizeBrainTab(initialTab);
418
419
  const [tab, setTab] = React.useState<BrainTab>(normalizedInitialTab);
420
+ const [brainPresence, setBrainPresence] = React.useState<{ state: BrainState; intensity: number }>({
421
+ state: "idle",
422
+ intensity: 0.58,
423
+ });
419
424
  React.useEffect(() => {
420
425
  setTab(normalizeBrainTab(initialTab));
421
426
  }, [initialTab]);
427
+ const setBrain = React.useCallback((state: BrainState, intensity = 0.58) => {
428
+ setBrainPresence({ state, intensity });
429
+ }, []);
422
430
  const graph = useQuery({ queryKey: ["graph"], queryFn: latticeApi.graph });
423
431
  const stats = useQuery({ queryKey: ["graphStats"], queryFn: latticeApi.graphStats });
424
432
  const index = useQuery({ queryKey: ["index"], queryFn: latticeApi.indexStatus });
@@ -442,7 +450,9 @@ export function BrainPage({ initialTab }: { initialTab?: string }) {
442
450
  )}
443
451
  <Tabs tabs={tabs} value={tab} onChange={(id) => setTab(id as BrainTab)} />
444
452
 
445
- {tab === "conversation" ? <BrainConversation /> : null}
453
+ {tab === "conversation" ? (
454
+ <BrainHome brainState={brainPresence.state} intensity={brainPresence.intensity} onBrainChange={setBrain} />
455
+ ) : null}
446
456
  {tab === "memory" ? <MemoryPanel /> : null}
447
457
  {tab === "knowledge" ? <HybridSearch /> : null}
448
458
  {tab === "relationships" ? (