ltcai 7.5.0 → 7.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 +48 -44
- package/docs/CHANGELOG.md +45 -0
- package/frontend/src/App.tsx +1 -1
- package/frontend/src/api/client.ts +9 -2
- package/frontend/src/components/LivingBrain.tsx +9 -1
- package/frontend/src/components/ProductFlow.tsx +64 -1
- package/frontend/src/components/onboarding/RecommendationScreen.tsx +36 -28
- package/frontend/src/components/onboarding/recommendationModel.ts +1 -1
- package/frontend/src/features/brain/BrainConversation.tsx +123 -2
- package/frontend/src/features/brain/BrainHome.tsx +34 -0
- package/frontend/src/features/review/ReviewInbox.tsx +2 -2
- package/frontend/src/features/review/reviewHelpers.ts +11 -11
- package/frontend/src/i18n.ts +148 -16
- package/frontend/src/pages/Act.tsx +28 -14
- package/frontend/src/routes.ts +6 -6
- package/frontend/src/styles.css +398 -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/local_embeddings.py +4 -3
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/sessions.py +8 -2
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/models/router.py +19 -0
- package/latticeai/services/architecture_readiness.py +119 -0
- package/latticeai/services/model_runtime.py +8 -3
- package/latticeai/services/product_readiness.py +159 -0
- package/package.json +1 -1
- package/scripts/product_readiness.py +37 -0
- package/scripts/pts-claudecode-discord-bridge.mjs +20 -3
- 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 +28 -28
- package/static/app/assets/Act-CX5hL0Z3.js +2 -0
- package/static/app/assets/{Act-Di4tRFWY.js.map → Act-CX5hL0Z3.js.map} +1 -1
- package/static/app/assets/{Brain-BZB3Gy9w.js → Brain-m19en5wz.js} +3 -3
- package/static/app/assets/{Brain-BZB3Gy9w.js.map → Brain-m19en5wz.js.map} +1 -1
- package/static/app/assets/Capture-CdFSrZnA.js +2 -0
- package/static/app/assets/Capture-CdFSrZnA.js.map +1 -0
- package/static/app/assets/Library-CZFVGSmG.js +2 -0
- package/static/app/assets/{Library-DAtDDLdg.js.map → Library-CZFVGSmG.js.map} +1 -1
- package/static/app/assets/System-CMoOoUrZ.js +2 -0
- package/static/app/assets/{System-DEu0xNUc.js.map → System-CMoOoUrZ.js.map} +1 -1
- package/static/app/assets/index-B4_drWel.js +17 -0
- package/static/app/assets/index-B4_drWel.js.map +1 -0
- package/static/app/assets/index-DjpDeE0c.css +2 -0
- package/static/app/assets/{primitives-CdwcE--L.js → primitives-CFhU5Rka.js} +2 -2
- package/static/app/assets/{primitives-CdwcE--L.js.map → primitives-CFhU5Rka.js.map} +1 -1
- package/static/app/assets/textarea-uBpGDOJM.js +2 -0
- package/static/app/assets/{textarea-CqOdBPL1.js.map → textarea-uBpGDOJM.js.map} +1 -1
- package/static/app/index.html +2 -2
- package/static/app/assets/Act-Di4tRFWY.js +0 -2
- package/static/app/assets/Capture-tNyYWxnh.js +0 -2
- package/static/app/assets/Capture-tNyYWxnh.js.map +0 -1
- package/static/app/assets/Library-DAtDDLdg.js +0 -2
- package/static/app/assets/System-DEu0xNUc.js +0 -2
- package/static/app/assets/index-Bi_bpigM.css +0 -2
- package/static/app/assets/index-COuGp7_5.js +0 -17
- package/static/app/assets/index-COuGp7_5.js.map +0 -1
- package/static/app/assets/textarea-CqOdBPL1.js +0 -2
|
@@ -483,6 +483,11 @@ 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>
|
|
486
491
|
<section className="brain-presence" aria-label={t(language, "brain.aria.exploration")}>
|
|
487
492
|
<div className="brain-exploration" data-depth={explorationDepth}>
|
|
488
493
|
<LivingBrain
|
|
@@ -494,6 +499,8 @@ export function BrainHome({
|
|
|
494
499
|
onInteract={deepen}
|
|
495
500
|
/>
|
|
496
501
|
|
|
502
|
+
<BrainDepthRings explorationDepth={explorationDepth} onOpenDepth={jumpToDepth} />
|
|
503
|
+
|
|
497
504
|
<div className="brain-depth-badge" aria-live="polite">
|
|
498
505
|
<span>{t(language, "brain.level")} {explorationDepth}</span>
|
|
499
506
|
<strong>{t(language, `brain.depth.${explorationDepth}`)}</strong>
|
|
@@ -576,6 +583,33 @@ export function BrainHome({
|
|
|
576
583
|
);
|
|
577
584
|
}
|
|
578
585
|
|
|
586
|
+
function BrainDepthRings({
|
|
587
|
+
explorationDepth,
|
|
588
|
+
onOpenDepth,
|
|
589
|
+
}: {
|
|
590
|
+
explorationDepth: BrainDepth;
|
|
591
|
+
onOpenDepth: (depth: BrainDepth) => void;
|
|
592
|
+
}) {
|
|
593
|
+
const language = useAppStore((state) => state.language);
|
|
594
|
+
return (
|
|
595
|
+
<div className="brain-memory-rings" aria-label={t(language, "brain.rings.aria")}>
|
|
596
|
+
{DEPTHS.map((depth, index) => (
|
|
597
|
+
<button
|
|
598
|
+
key={depth.level}
|
|
599
|
+
type="button"
|
|
600
|
+
className={`brain-memory-ring ring-${depth.level} ${depth.level <= explorationDepth ? "is-revealed" : ""}`}
|
|
601
|
+
aria-current={depth.level === explorationDepth ? "step" : undefined}
|
|
602
|
+
onClick={() => onOpenDepth(depth.level)}
|
|
603
|
+
style={{ "--ring-delay": `${index * 70}ms` } as React.CSSProperties}
|
|
604
|
+
>
|
|
605
|
+
<span>{depth.level}</span>
|
|
606
|
+
<strong>{t(language, `brain.rings.${depth.level}`)}</strong>
|
|
607
|
+
</button>
|
|
608
|
+
))}
|
|
609
|
+
</div>
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
|
|
579
613
|
function toMessageProof(proof: BrainProof, query: string, fallbackModelName: string): MessageProof {
|
|
580
614
|
return {
|
|
581
615
|
query,
|
|
@@ -87,12 +87,12 @@ export function ReviewInbox() {
|
|
|
87
87
|
</div>
|
|
88
88
|
<div className="grid gap-2">
|
|
89
89
|
<Tabs
|
|
90
|
-
tabs={reviewStatusFilters}
|
|
90
|
+
tabs={reviewStatusFilters.map((filter) => ({ id: filter.id, label: t(language, filter.labelKey) }))}
|
|
91
91
|
value={statusFilter}
|
|
92
92
|
onChange={(id) => setStatusFilter(id as ReviewStatusFilter)}
|
|
93
93
|
/>
|
|
94
94
|
<Tabs
|
|
95
|
-
tabs={reviewSourceFilters}
|
|
95
|
+
tabs={reviewSourceFilters.map((filter) => ({ id: filter.id, label: t(language, filter.labelKey) }))}
|
|
96
96
|
value={sourceFilter}
|
|
97
97
|
onChange={(id) => setSourceFilter(id as ReviewSourceFilter)}
|
|
98
98
|
/>
|
|
@@ -4,19 +4,19 @@ import type { Badge } from "@/components/ui/badge";
|
|
|
4
4
|
|
|
5
5
|
export type ReviewAction = "approve" | "dismiss" | "snooze" | "unsnooze" | "run_now";
|
|
6
6
|
|
|
7
|
-
export const reviewStatusFilters: Array<{ id: ReviewStatusFilter;
|
|
8
|
-
{ id: "pending",
|
|
9
|
-
{ id: "snoozed",
|
|
10
|
-
{ id: "all",
|
|
11
|
-
{ id: "approved",
|
|
12
|
-
{ id: "dismissed",
|
|
7
|
+
export const reviewStatusFilters: Array<{ id: ReviewStatusFilter; labelKey: string }> = [
|
|
8
|
+
{ id: "pending", labelKey: "review.filter.status.pending" },
|
|
9
|
+
{ id: "snoozed", labelKey: "review.filter.status.snoozed" },
|
|
10
|
+
{ id: "all", labelKey: "review.filter.status.all" },
|
|
11
|
+
{ id: "approved", labelKey: "review.filter.status.approved" },
|
|
12
|
+
{ id: "dismissed", labelKey: "review.filter.status.dismissed" },
|
|
13
13
|
];
|
|
14
14
|
|
|
15
|
-
export const reviewSourceFilters: Array<{ id: ReviewSourceFilter;
|
|
16
|
-
{ id: "all",
|
|
17
|
-
{ id: "workflow_run",
|
|
18
|
-
{ id: "trigger",
|
|
19
|
-
{ id: "kg_change_digest",
|
|
15
|
+
export const reviewSourceFilters: Array<{ id: ReviewSourceFilter; labelKey: string }> = [
|
|
16
|
+
{ id: "all", labelKey: "review.filter.source.all" },
|
|
17
|
+
{ id: "workflow_run", labelKey: "review.filter.source.workflow_run" },
|
|
18
|
+
{ id: "trigger", labelKey: "review.filter.source.trigger" },
|
|
19
|
+
{ id: "kg_change_digest", labelKey: "review.filter.source.kg_change_digest" },
|
|
20
20
|
];
|
|
21
21
|
|
|
22
22
|
export function reviewStatusVariant(status: string): React.ComponentProps<typeof Badge>["variant"] {
|
package/frontend/src/i18n.ts
CHANGED
|
@@ -32,17 +32,48 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
32
32
|
"brain.aria.exploration": "Brain 탐색",
|
|
33
33
|
"brain.aria.quickViews": "Brain 빠른 보기",
|
|
34
34
|
"brain.depthRail.aria": "Brain 깊이 진행 상태",
|
|
35
|
-
"brain.aria.conversation": "대화",
|
|
35
|
+
"brain.aria.conversation": "Brain과의 대화",
|
|
36
36
|
"brain.aria.ownership": "Brain 소유 보장",
|
|
37
37
|
"brain.aria.actions": "Brain 주요 작업",
|
|
38
38
|
"brain.aria.starterPrompts": "시작 프롬프트",
|
|
39
39
|
"brain.aria.overview": "Brain 한눈에 보기",
|
|
40
40
|
"brain.aria.graph": "지식 그래프",
|
|
41
41
|
"brain.title": "Lattice Brain",
|
|
42
|
+
"brain.edition": "정식 제품",
|
|
43
|
+
"brain.edition.tip": "Lattice AI 7.7 — 완성된 정식 출시 디지털 브레인",
|
|
42
44
|
"brain.local": "로컬 우선",
|
|
43
45
|
"brain.portable": "이동 가능",
|
|
44
46
|
"brain.private": "개인 소유",
|
|
45
47
|
"brain.admin": "관리자 콘솔",
|
|
48
|
+
"brain.command.aria": "제품 상태와 다음 행동",
|
|
49
|
+
"brain.command.kicker": "제품 상태판",
|
|
50
|
+
"brain.command.title": "지금 바로 쓸 수 있는 Brain",
|
|
51
|
+
"brain.command.score": "제품 준비도",
|
|
52
|
+
"brain.command.next": "다음 행동",
|
|
53
|
+
"brain.command.next.empty": "첫 자료를 넣고 바로 질문하세요.",
|
|
54
|
+
"brain.command.next.forming": "주제를 열어 기억이 어떻게 묶이는지 확인하세요.",
|
|
55
|
+
"brain.command.next.alive": "근거를 확인하고 필요하면 모델을 바꿔 보세요.",
|
|
56
|
+
"brain.command.metrics": "Brain 제품 지표",
|
|
57
|
+
"brain.command.metric.memories": "기억 {count}개",
|
|
58
|
+
"brain.command.metric.topics": "주제 {count}개",
|
|
59
|
+
"brain.command.metric.sources": "정상 출처 {count}개",
|
|
60
|
+
"brain.command.metric.proof": "근거 {count}개",
|
|
61
|
+
"brain.command.source.empty": "아직 수집 전",
|
|
62
|
+
"brain.command.action.add": "자료 넣기",
|
|
63
|
+
"brain.command.action.find": "주제 확인",
|
|
64
|
+
"brain.command.action.find.detail": "기억이 묶인 구조 보기",
|
|
65
|
+
"brain.command.action.proof": "근거 확인",
|
|
66
|
+
"brain.command.action.own": "소유권 관리",
|
|
67
|
+
"brain.command.action.own.detail": "백업, 복원, 설정",
|
|
68
|
+
"brain.command.signal.local": "로컬 우선",
|
|
69
|
+
"brain.command.signal.private": "명시 동의",
|
|
70
|
+
"brain.command.signal.portable": "백업 가능",
|
|
71
|
+
"shell.route.brain": "Lattice Brain",
|
|
72
|
+
"shell.route.capture": "자료",
|
|
73
|
+
"shell.route.memory": "그래프",
|
|
74
|
+
"shell.route.library": "모델",
|
|
75
|
+
"shell.route.system": "설정",
|
|
76
|
+
"shell.route.act": "실행",
|
|
46
77
|
"shell.workspace.label": "작업공간 및 프로필",
|
|
47
78
|
"shell.workspace.current": "현재 작업공간",
|
|
48
79
|
"shell.workspace.switch": "전환",
|
|
@@ -76,9 +107,9 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
76
107
|
"brain.empty.trail.save": "1. 첫 기억 저장",
|
|
77
108
|
"brain.empty.trail.recall": "2. Brain Home에서 확인",
|
|
78
109
|
"brain.empty.trail.backup": "3. 백업으로 소유",
|
|
79
|
-
"brain.prompt.remember": "이
|
|
80
|
-
"brain.prompt.know": "
|
|
81
|
-
"brain.prompt.plan": "
|
|
110
|
+
"brain.prompt.remember": "이 목표를 Brain이 영원히 기억하게 해줘: ",
|
|
111
|
+
"brain.prompt.know": "이걸 Brain에 넣고 핵심을 뽑아줘: ",
|
|
112
|
+
"brain.prompt.plan": "과거 결정들을 Brain이 구조화해서 나중에 쉽게 찾게 해줘: ",
|
|
82
113
|
"brain.placeholder": "Brain에게 말하기...",
|
|
83
114
|
"brain.upload.cta": "파일/문서 넣기",
|
|
84
115
|
"brain.upload.ctaShort": "문서",
|
|
@@ -140,7 +171,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
140
171
|
"brain.timeline.minutesAgo": "{count}분 전",
|
|
141
172
|
"brain.timeline.empty": "아직 수집 기록이 없습니다. 위에서 무엇이든 넣어보세요.",
|
|
142
173
|
"brain.image": "이미지",
|
|
143
|
-
"brain.unavailable": "지금은
|
|
174
|
+
"brain.unavailable": "지금은 응답할 수 없습니다",
|
|
144
175
|
"brain.imageAttached": "이미지 첨부됨",
|
|
145
176
|
"brain.send": "보내기",
|
|
146
177
|
"brain.saved": "기억에 저장됨 · 연결된 주제 {topics}개 · 관련 기억 {memories}개",
|
|
@@ -175,7 +206,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
175
206
|
"brain.proof.recall": "방금 Brain이 다시 꺼낸 기억",
|
|
176
207
|
"brain.proof.recallEmpty.kicker": "Brain 증거 자리",
|
|
177
208
|
"brain.proof.recallEmpty.title": "첫 대화 후 여기에 다시 꺼낸 기억이 표시됩니다.",
|
|
178
|
-
"brain.proof.recallEmpty.detail": "아직 저장된 기억이
|
|
209
|
+
"brain.proof.recallEmpty.detail": "아직 저장된 기억이 없어, 예시를 꾸며내는 대신 실제 기억이 쌓이기를 기다립니다.",
|
|
179
210
|
"brain.proof.recallPending": "기억은 저장됐고 recall 증거를 준비 중입니다.",
|
|
180
211
|
"brain.proof.recallPending.detail": "인덱싱이 끝나면 이 자리에서 실제 기억을 다시 보여줍니다.",
|
|
181
212
|
"brain.modelDemo.aria": "모델 교체 증거",
|
|
@@ -232,6 +263,12 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
232
263
|
"brain.graph.focus.smooth": "선택한 노드로 부드럽게 포커스 이동하고 이웃을 강조합니다.",
|
|
233
264
|
"brain.graph.focus.recent": "최근 추가됨",
|
|
234
265
|
"brain.graph.focus.clear": "포커스 해제",
|
|
266
|
+
"brain.rings.aria": "Brain 기억 깊이 링",
|
|
267
|
+
"brain.rings.1": "지금",
|
|
268
|
+
"brain.rings.2": "기억",
|
|
269
|
+
"brain.rings.3": "주제",
|
|
270
|
+
"brain.rings.4": "관계",
|
|
271
|
+
"brain.rings.5": "그래프",
|
|
235
272
|
"care.title": "내 Brain 돌보기",
|
|
236
273
|
"care.subtitle": "내 컴퓨터에 두고, 필요하면 옮길 수 있습니다.",
|
|
237
274
|
"care.private": "개인 보관",
|
|
@@ -324,6 +361,26 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
324
361
|
"review.dismiss": "기각",
|
|
325
362
|
"review.feedback.open": "승인 또는 기각 전까지 항목은 열린 상태로 유지됩니다.",
|
|
326
363
|
"review.action.failed": "{action} 실패",
|
|
364
|
+
"review.filter.status.pending": "대기",
|
|
365
|
+
"review.filter.status.snoozed": "일시 중지",
|
|
366
|
+
"review.filter.status.all": "전체",
|
|
367
|
+
"review.filter.status.approved": "승인됨",
|
|
368
|
+
"review.filter.status.dismissed": "기각됨",
|
|
369
|
+
"review.filter.source.all": "전체 출처",
|
|
370
|
+
"review.filter.source.workflow_run": "워크플로",
|
|
371
|
+
"review.filter.source.trigger": "트리거",
|
|
372
|
+
"review.filter.source.kg_change_digest": "KG 요약",
|
|
373
|
+
"act.kicker": "자동화",
|
|
374
|
+
"act.title": "중요한 변경은 검토하면서 일을 진행합니다.",
|
|
375
|
+
"act.copy": "목표를 맡기고, 각 실행 결과를 확인한 뒤 민감한 작업만 명시적으로 승인하세요.",
|
|
376
|
+
"act.tab.goals": "목표",
|
|
377
|
+
"act.tab.runs": "실행",
|
|
378
|
+
"act.tab.review": "검토함",
|
|
379
|
+
"act.tab.recipes": "레시피",
|
|
380
|
+
"act.tab.safeguards": "보호 장치",
|
|
381
|
+
"act.tab.permissions": "권한",
|
|
382
|
+
"act.tab.hooks": "훅",
|
|
383
|
+
"act.tab.tools": "도구",
|
|
327
384
|
"admin.back": "Brain",
|
|
328
385
|
"admin.aria.console": "Lattice 관리자",
|
|
329
386
|
"admin.kicker": "분리된 관리자 작업공간",
|
|
@@ -463,8 +520,17 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
463
520
|
"flow.install.timelineQuick": "잠깐",
|
|
464
521
|
"flow.install.expectedCompletion": "끝나면 바로 Brain이 열립니다.",
|
|
465
522
|
"flow.shell": "내 로컬 AI 브레인 만들기",
|
|
466
|
-
"flow.
|
|
467
|
-
"flow.
|
|
523
|
+
"flow.wake.aria": "Brain 깨우기",
|
|
524
|
+
"flow.wake.title": "당신의 지식이 영원히 살아 숨쉬는 Brain을 지금 시작하세요.",
|
|
525
|
+
"flow.wake.body": "대화할수록 똑똑해지는 당신만의 AI. 모델 바꿔도 기억은 영원히. 로컬, 직관적, 강력. 처음 보는 순간 쓰고 싶어지는 Brain을 시작하세요.",
|
|
526
|
+
"flow.wake.plan.aria": "Brain 시작 단계",
|
|
527
|
+
"flow.wake.step.identity": "주인 확인",
|
|
528
|
+
"flow.wake.step.check": "컴퓨터 확인",
|
|
529
|
+
"flow.wake.step.voice": "목소리 선택",
|
|
530
|
+
"flow.wake.primary": "Brain 지금 깨우기",
|
|
531
|
+
"flow.wake.existing": "기존 Brain 열기",
|
|
532
|
+
"flow.login.title": "이 Brain의 주인은 바로 당신입니다.",
|
|
533
|
+
"flow.login.body": "이 컴퓨터에 사는, 당신만의 영원한 지식 Brain. 3단계로 직관적으로 시작. 모델은 나중에 바꿔도 모든 것이 그대로입니다.",
|
|
468
534
|
"flow.name": "이름",
|
|
469
535
|
"flow.name.placeholder": "나",
|
|
470
536
|
"flow.email": "이메일",
|
|
@@ -485,8 +551,8 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
485
551
|
"flow.promise.ownership.k": "사용자 소유",
|
|
486
552
|
"flow.promise.ownership.v": "백업, 복원, 이동을 직접 결정합니다.",
|
|
487
553
|
"flow.promise.aria": "Lattice AI 제품 약속",
|
|
488
|
-
"flow.analysis.title": "이 컴퓨터에서
|
|
489
|
-
"flow.analysis.body": "
|
|
554
|
+
"flow.analysis.title": "이 컴퓨터에서 가장 자연스럽고 강력한 Brain 경험을 확인합니다.",
|
|
555
|
+
"flow.analysis.body": "스펙이 아니라, 당신의 Mac에서 즉시 직관적으로 쓸 수 있는 로컬 AI 브레인 수준을 보여드립니다. 로컬 상태만 읽고, 클라우드는 선택입니다. 바로 쓰고 싶어지게 준비됐습니다.",
|
|
490
556
|
"flow.analysis.finding": "가장 편한 설정을 찾는 중...",
|
|
491
557
|
"flow.analysis.ready": "추천 모델을 바로 시작할 수 있게 준비했습니다.",
|
|
492
558
|
"flow.analysis.wait": "잠시만 기다리면 자동으로 정리됩니다.",
|
|
@@ -497,18 +563,18 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
497
563
|
"flow.analysis.os.windows": "Windows PC",
|
|
498
564
|
"flow.analysis.os.linux": "Linux 컴퓨터",
|
|
499
565
|
"flow.recommend.title": "추천대로 시작하세요.",
|
|
500
|
-
"flow.recommend.body": "모델은 Brain의
|
|
501
|
-
"flow.recommend.primary": "
|
|
566
|
+
"flow.recommend.body": "모델은 Brain의 목소리일 뿐. 가장 직관적이고 빠른 시작을 위한 추천, 빠른 모델, 강력한 모델을 먼저 보여드립니다. 선택하면 바로 대화가 시작됩니다.",
|
|
567
|
+
"flow.recommend.primary": "추천으로 바로 시작",
|
|
502
568
|
"flow.recommend.unsupported": "이 컴퓨터에서 추가 확인이 필요합니다",
|
|
503
569
|
"flow.recommend.back": "뒤로",
|
|
504
570
|
"flow.recommend.skip": "모델 없이 Brain 열기",
|
|
505
|
-
"flow.recommend.hint": "
|
|
571
|
+
"flow.recommend.hint": "추천을 선택하면 가장 부드럽고 직관적인 경험이 시작됩니다.",
|
|
506
572
|
"flow.recommend.rank.best": "추천",
|
|
507
573
|
"flow.recommend.rank.faster": "빠른 선택",
|
|
508
574
|
"flow.recommend.rank.advanced": "고급 선택",
|
|
509
575
|
"flow.recommend.rank.choice": "선택 {index}",
|
|
510
576
|
"flow.install.title": "모델을 설치하고 시작합니다.",
|
|
511
|
-
"flow.install.body": "이 모델이 Brain의 로컬 목소리가 됩니다.
|
|
577
|
+
"flow.install.body": "이 모델이 당신 Brain의 로컬 목소리가 됩니다. 다운로드는 한 번뿐, 그 후 모든 대화와 기억은 완전 로컬. 직관적이고 강력한 경험을 바로 느껴보세요.",
|
|
512
578
|
"flow.install.wait": "Brain이 사용할 모델을 기다리고 있습니다.",
|
|
513
579
|
"flow.install.prepare": "Brain 준비 중입니다.",
|
|
514
580
|
"flow.install.done": "Brain이 준비되었습니다.",
|
|
@@ -597,10 +663,41 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
597
663
|
"brain.aria.overview": "Brain overview",
|
|
598
664
|
"brain.aria.graph": "Knowledge Graph",
|
|
599
665
|
"brain.title": "Lattice Brain",
|
|
666
|
+
"brain.edition": "Production Ready",
|
|
667
|
+
"brain.edition.tip": "Lattice AI 7.7 — your finished, production-ready Digital Brain",
|
|
600
668
|
"brain.local": "Local-first",
|
|
601
669
|
"brain.portable": "Portable",
|
|
602
670
|
"brain.private": "Private",
|
|
603
671
|
"brain.admin": "Admin Console",
|
|
672
|
+
"brain.command.aria": "Product status and next action",
|
|
673
|
+
"brain.command.kicker": "Product command center",
|
|
674
|
+
"brain.command.title": "A Brain ready to use now",
|
|
675
|
+
"brain.command.score": "Product readiness",
|
|
676
|
+
"brain.command.next": "Next action",
|
|
677
|
+
"brain.command.next.empty": "Add a first source, then ask immediately.",
|
|
678
|
+
"brain.command.next.forming": "Open topics to see how memories are grouping.",
|
|
679
|
+
"brain.command.next.alive": "Verify proof, then switch models when useful.",
|
|
680
|
+
"brain.command.metrics": "Brain product metrics",
|
|
681
|
+
"brain.command.metric.memories": "{count} memories",
|
|
682
|
+
"brain.command.metric.topics": "{count} topics",
|
|
683
|
+
"brain.command.metric.sources": "{count} healthy sources",
|
|
684
|
+
"brain.command.metric.proof": "{count} proof points",
|
|
685
|
+
"brain.command.source.empty": "No ingestion yet",
|
|
686
|
+
"brain.command.action.add": "Add source",
|
|
687
|
+
"brain.command.action.find": "Inspect topics",
|
|
688
|
+
"brain.command.action.find.detail": "See grouped memory structure",
|
|
689
|
+
"brain.command.action.proof": "Verify proof",
|
|
690
|
+
"brain.command.action.own": "Manage ownership",
|
|
691
|
+
"brain.command.action.own.detail": "Backup, restore, settings",
|
|
692
|
+
"brain.command.signal.local": "Local-first",
|
|
693
|
+
"brain.command.signal.private": "Consent gated",
|
|
694
|
+
"brain.command.signal.portable": "Backup ready",
|
|
695
|
+
"shell.route.brain": "Lattice Brain",
|
|
696
|
+
"shell.route.capture": "Files",
|
|
697
|
+
"shell.route.memory": "Graph",
|
|
698
|
+
"shell.route.library": "Models",
|
|
699
|
+
"shell.route.system": "Settings",
|
|
700
|
+
"shell.route.act": "Act",
|
|
604
701
|
"shell.workspace.label": "Workspace and profile",
|
|
605
702
|
"shell.workspace.current": "Current workspace",
|
|
606
703
|
"shell.workspace.switch": "Switch",
|
|
@@ -698,7 +795,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
698
795
|
"brain.timeline.minutesAgo": "{count}m ago",
|
|
699
796
|
"brain.timeline.empty": "No ingestion yet. Add anything above to begin.",
|
|
700
797
|
"brain.image": "Image",
|
|
701
|
-
"brain.unavailable": "
|
|
798
|
+
"brain.unavailable": "Temporarily unavailable",
|
|
702
799
|
"brain.imageAttached": "Image attached",
|
|
703
800
|
"brain.send": "Send",
|
|
704
801
|
"brain.saved": "Saved to memory · {topics} linked topics · {memories} related memories",
|
|
@@ -733,7 +830,7 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
733
830
|
"brain.proof.recall": "Just recalled by Brain",
|
|
734
831
|
"brain.proof.recallEmpty.kicker": "Brain proof slot",
|
|
735
832
|
"brain.proof.recallEmpty.title": "After your first exchange, recalled memory appears here.",
|
|
736
|
-
"brain.proof.recallEmpty.detail": "No saved memory yet
|
|
833
|
+
"brain.proof.recallEmpty.detail": "No saved memory yet — Lattice waits for real memory instead of inventing a placeholder example.",
|
|
737
834
|
"brain.proof.recallPending": "Memory is saved; recall proof is preparing.",
|
|
738
835
|
"brain.proof.recallPending.detail": "When indexing finishes, this slot shows the actual memory Brain can bring back.",
|
|
739
836
|
"brain.modelDemo.aria": "Model switch proof",
|
|
@@ -790,6 +887,12 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
790
887
|
"brain.graph.focus.smooth": "Smoothly focuses the selected node and highlights its neighbors.",
|
|
791
888
|
"brain.graph.focus.recent": "Recently added",
|
|
792
889
|
"brain.graph.focus.clear": "Clear focus",
|
|
890
|
+
"brain.rings.aria": "Brain memory depth rings",
|
|
891
|
+
"brain.rings.1": "Now",
|
|
892
|
+
"brain.rings.2": "Memory",
|
|
893
|
+
"brain.rings.3": "Topics",
|
|
894
|
+
"brain.rings.4": "Relations",
|
|
895
|
+
"brain.rings.5": "Graph",
|
|
793
896
|
"care.title": "Care for my Brain",
|
|
794
897
|
"care.subtitle": "Own it locally. Keep it portable.",
|
|
795
898
|
"care.private": "Private",
|
|
@@ -882,6 +985,26 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
882
985
|
"review.dismiss": "Dismiss",
|
|
883
986
|
"review.feedback.open": "item stays open until you approve or dismiss.",
|
|
884
987
|
"review.action.failed": "{action} failed",
|
|
988
|
+
"review.filter.status.pending": "Pending",
|
|
989
|
+
"review.filter.status.snoozed": "Snoozed",
|
|
990
|
+
"review.filter.status.all": "All",
|
|
991
|
+
"review.filter.status.approved": "Approved",
|
|
992
|
+
"review.filter.status.dismissed": "Dismissed",
|
|
993
|
+
"review.filter.source.all": "All sources",
|
|
994
|
+
"review.filter.source.workflow_run": "Workflow",
|
|
995
|
+
"review.filter.source.trigger": "Trigger",
|
|
996
|
+
"review.filter.source.kg_change_digest": "KG digest",
|
|
997
|
+
"act.kicker": "Automate",
|
|
998
|
+
"act.title": "Make work move, with a hand on the door.",
|
|
999
|
+
"act.copy": "Give Lattice a goal, review each run, and approve sensitive actions before anything important changes.",
|
|
1000
|
+
"act.tab.goals": "Goals",
|
|
1001
|
+
"act.tab.runs": "Runs",
|
|
1002
|
+
"act.tab.review": "Review Center",
|
|
1003
|
+
"act.tab.recipes": "Recipes",
|
|
1004
|
+
"act.tab.safeguards": "Safeguards",
|
|
1005
|
+
"act.tab.permissions": "Permissions",
|
|
1006
|
+
"act.tab.hooks": "Hooks",
|
|
1007
|
+
"act.tab.tools": "Tools",
|
|
885
1008
|
"admin.back": "Brain",
|
|
886
1009
|
"admin.aria.console": "Lattice Admin",
|
|
887
1010
|
"admin.kicker": "Separate admin workspace",
|
|
@@ -1021,6 +1144,15 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
1021
1144
|
"flow.install.timelineQuick": "moment",
|
|
1022
1145
|
"flow.install.expectedCompletion": "When it finishes, your Brain opens right away.",
|
|
1023
1146
|
"flow.shell": "Create your local AI Brain",
|
|
1147
|
+
"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.",
|
|
1150
|
+
"flow.wake.plan.aria": "Brain start steps",
|
|
1151
|
+
"flow.wake.step.identity": "Confirm owner",
|
|
1152
|
+
"flow.wake.step.check": "Check computer",
|
|
1153
|
+
"flow.wake.step.voice": "Choose voice",
|
|
1154
|
+
"flow.wake.primary": "Wake Brain",
|
|
1155
|
+
"flow.wake.existing": "Open existing Brain",
|
|
1024
1156
|
"flow.login.title": "Choose the owner of your AI Brain.",
|
|
1025
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.",
|
|
1026
1158
|
"flow.name": "Name",
|
|
@@ -12,25 +12,27 @@ import { Textarea } from "@/components/ui/textarea";
|
|
|
12
12
|
import { ReviewInbox } from "@/features/review/ReviewInbox";
|
|
13
13
|
import { useAppStore } from "@/store/appStore";
|
|
14
14
|
import { asArray, shortId } from "@/lib/utils";
|
|
15
|
+
import { t } from "@/i18n";
|
|
15
16
|
|
|
16
17
|
type ActTab = "agents" | "runs" | "workflows" | "hooks" | "tools";
|
|
17
18
|
type RunsSubTab = "runs" | "review";
|
|
18
19
|
|
|
19
|
-
const runsSubTabs: Array<{ id: RunsSubTab;
|
|
20
|
-
{ id: "runs",
|
|
21
|
-
{ id: "review",
|
|
20
|
+
const runsSubTabs: Array<{ id: RunsSubTab; labelKey: string }> = [
|
|
21
|
+
{ id: "runs", labelKey: "act.tab.runs" },
|
|
22
|
+
{ id: "review", labelKey: "act.tab.review" },
|
|
22
23
|
];
|
|
23
24
|
|
|
24
|
-
const tabs: Array<{ id: ActTab;
|
|
25
|
-
{ id: "agents",
|
|
26
|
-
{ id: "runs",
|
|
27
|
-
{ id: "workflows",
|
|
28
|
-
{ id: "hooks",
|
|
29
|
-
{ id: "tools",
|
|
25
|
+
const tabs: Array<{ id: ActTab; labelKey: string; advancedLabelKey?: string }> = [
|
|
26
|
+
{ id: "agents", labelKey: "act.tab.goals" },
|
|
27
|
+
{ id: "runs", labelKey: "act.tab.runs" },
|
|
28
|
+
{ id: "workflows", labelKey: "act.tab.recipes" },
|
|
29
|
+
{ id: "hooks", labelKey: "act.tab.safeguards", advancedLabelKey: "act.tab.hooks" },
|
|
30
|
+
{ id: "tools", labelKey: "act.tab.permissions", advancedLabelKey: "act.tab.tools" },
|
|
30
31
|
];
|
|
31
32
|
|
|
32
33
|
export function ActPage({ initialTab }: { initialTab?: string }) {
|
|
33
34
|
const mode = useAppStore((state) => state.mode);
|
|
35
|
+
const language = useAppStore((state) => state.language);
|
|
34
36
|
const [tab, setTab] = React.useState<ActTab>(() => {
|
|
35
37
|
if (initialTab === "review") return "runs";
|
|
36
38
|
return (initialTab as ActTab) || "agents";
|
|
@@ -47,11 +49,18 @@ export function ActPage({ initialTab }: { initialTab?: string }) {
|
|
|
47
49
|
return (
|
|
48
50
|
<div className="space-y-5">
|
|
49
51
|
<header className="page-hero">
|
|
50
|
-
<div className="page-kicker"><Workflow className="h-4 w-4" />
|
|
51
|
-
<h1 className="page-title">
|
|
52
|
-
<p className="page-copy">
|
|
52
|
+
<div className="page-kicker"><Workflow className="h-4 w-4" /> {t(language, "act.kicker")}</div>
|
|
53
|
+
<h1 className="page-title">{t(language, "act.title")}</h1>
|
|
54
|
+
<p className="page-copy">{t(language, "act.copy")}</p>
|
|
53
55
|
</header>
|
|
54
|
-
<Tabs
|
|
56
|
+
<Tabs
|
|
57
|
+
tabs={tabs.map((item) => ({
|
|
58
|
+
id: item.id,
|
|
59
|
+
label: t(language, mode === "basic" || !item.advancedLabelKey ? item.labelKey : item.advancedLabelKey),
|
|
60
|
+
}))}
|
|
61
|
+
value={tab}
|
|
62
|
+
onChange={(id) => setTab(id as ActTab)}
|
|
63
|
+
/>
|
|
55
64
|
{tab === "agents" ? <AgentsPanel /> : null}
|
|
56
65
|
{tab === "runs" ? <RunsPanel subTab={runsSubTab} onSubTabChange={setRunsSubTab} /> : null}
|
|
57
66
|
{tab === "workflows" ? <WorkflowsPanel /> : null}
|
|
@@ -140,9 +149,14 @@ function AgentsPanel() {
|
|
|
140
149
|
}
|
|
141
150
|
|
|
142
151
|
function RunsPanel({ subTab, onSubTabChange }: { subTab: RunsSubTab; onSubTabChange: (tab: RunsSubTab) => void }) {
|
|
152
|
+
const language = useAppStore((state) => state.language);
|
|
143
153
|
return (
|
|
144
154
|
<div className="space-y-4">
|
|
145
|
-
<Tabs
|
|
155
|
+
<Tabs
|
|
156
|
+
tabs={runsSubTabs.map((item) => ({ id: item.id, label: t(language, item.labelKey) }))}
|
|
157
|
+
value={subTab}
|
|
158
|
+
onChange={(id) => onSubTabChange(id as RunsSubTab)}
|
|
159
|
+
/>
|
|
146
160
|
{subTab === "runs" ? <RunsListPanel /> : <ReviewInbox />}
|
|
147
161
|
</div>
|
|
148
162
|
);
|
package/frontend/src/routes.ts
CHANGED
|
@@ -12,12 +12,12 @@ export type PrimaryRoute = "brain" | "memory" | "capture" | "act" | "library" |
|
|
|
12
12
|
export type RouteTarget = { primary: PrimaryRoute; tab?: string };
|
|
13
13
|
|
|
14
14
|
export const productShellRoutes = [
|
|
15
|
-
{ id: "brain", path: "brain",
|
|
16
|
-
{ id: "capture", path: "capture",
|
|
17
|
-
{ id: "memory", path: "knowledge-graph",
|
|
18
|
-
{ id: "library", path: "models",
|
|
19
|
-
{ id: "system", path: "settings",
|
|
20
|
-
{ id: "act", path: "review",
|
|
15
|
+
{ id: "brain", path: "brain", labelKey: "shell.route.brain", icon: Brain, description: "Talk with your living Brain" },
|
|
16
|
+
{ id: "capture", path: "capture", labelKey: "shell.route.capture", icon: FolderInput, description: "Bring in files, folders, and pages" },
|
|
17
|
+
{ id: "memory", path: "knowledge-graph", labelKey: "shell.route.memory", icon: Database, description: "Search and inspect Brain knowledge" },
|
|
18
|
+
{ id: "library", path: "models", labelKey: "shell.route.library", icon: Library, description: "Choose the local model powering your Brain" },
|
|
19
|
+
{ id: "system", path: "settings", labelKey: "shell.route.system", icon: Settings, description: "Keep your Brain safe and portable" },
|
|
20
|
+
{ id: "act", path: "review", labelKey: "shell.route.act", icon: Workflow, description: "Turn goals into supervised runs" },
|
|
21
21
|
] as const;
|
|
22
22
|
|
|
23
23
|
export const directProductRoutes: Record<string, RouteTarget> = {
|