ltcai 7.6.0 → 7.8.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 +39 -34
- package/docs/CHANGELOG.md +39 -0
- package/frontend/src/App.tsx +4 -2
- package/frontend/src/api/client.ts +9 -2
- package/frontend/src/components/LivingBrain.tsx +9 -1
- package/frontend/src/components/ProductFlow.tsx +27 -3
- package/frontend/src/components/onboarding/RecommendationScreen.tsx +33 -26
- package/frontend/src/features/brain/BrainConversation.tsx +214 -94
- package/frontend/src/features/brain/BrainHome.tsx +32 -28
- package/frontend/src/features/review/ReviewInbox.tsx +2 -2
- package/frontend/src/features/review/reviewHelpers.ts +11 -11
- package/frontend/src/i18n.ts +162 -26
- package/frontend/src/pages/Act.tsx +28 -14
- package/frontend/src/pages/Ask.tsx +11 -2
- package/frontend/src/pages/Brain.tsx +12 -2
- package/frontend/src/routes.ts +6 -6
- package/frontend/src/styles.css +592 -25
- 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/latticeai/services/architecture_readiness.py +25 -7
- package/latticeai/services/product_readiness.py +159 -0
- package/package.json +1 -1
- package/scripts/product_readiness.py +37 -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 +28 -28
- package/static/app/assets/{Act-CSeeIWB4.js → Act-DOvf59ru.js} +2 -2
- package/static/app/assets/{Act-CSeeIWB4.js.map → Act-DOvf59ru.js.map} +1 -1
- package/static/app/assets/Brain-C7_0mEiI.js +322 -0
- package/static/app/assets/Brain-C7_0mEiI.js.map +1 -0
- package/static/app/assets/Capture-B9Tlhzqr.js +2 -0
- package/static/app/assets/Capture-B9Tlhzqr.js.map +1 -0
- package/static/app/assets/Library-BJPEEm5O.js +2 -0
- package/static/app/assets/{Library-C4zmA8O2.js.map → Library-BJPEEm5O.js.map} +1 -1
- package/static/app/assets/System-D6t9jo9V.js +2 -0
- package/static/app/assets/{System-Da-Kxwiz.js.map → System-D6t9jo9V.js.map} +1 -1
- package/static/app/assets/index-C7g26IF6.css +2 -0
- package/static/app/assets/index-DbcEYJQ2.js +17 -0
- package/static/app/assets/index-DbcEYJQ2.js.map +1 -0
- package/static/app/assets/primitives-CD38lt4n.js +2 -0
- package/static/app/assets/{primitives-CSsF_Ymb.js.map → primitives-CD38lt4n.js.map} +1 -1
- package/static/app/assets/textarea-BZk6ybp5.js +2 -0
- package/static/app/assets/{textarea-CJMFSyfQ.js.map → textarea-BZk6ybp5.js.map} +1 -1
- package/static/app/index.html +2 -2
- package/frontend/src/components/BrainConversation.tsx +0 -533
- package/frontend/src/components/FirstRunGuide.tsx +0 -99
- package/static/app/assets/Brain-D_Ne4YoR.js +0 -322
- package/static/app/assets/Brain-D_Ne4YoR.js.map +0 -1
- package/static/app/assets/Capture-YFRAO4bJ.js +0 -2
- package/static/app/assets/Capture-YFRAO4bJ.js.map +0 -1
- package/static/app/assets/Library-C4zmA8O2.js +0 -2
- package/static/app/assets/System-Da-Kxwiz.js +0 -2
- package/static/app/assets/index-BwmCpRoW.css +0 -2
- package/static/app/assets/index-D1hsexMt.js +0 -17
- package/static/app/assets/index-D1hsexMt.js.map +0 -1
- package/static/app/assets/primitives-CSsF_Ymb.js +0 -2
- package/static/app/assets/textarea-CJMFSyfQ.js +0 -2
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
BrainCircuit,
|
|
4
|
+
CheckCircle2,
|
|
5
|
+
Cpu,
|
|
6
|
+
DatabaseZap,
|
|
7
|
+
FileText,
|
|
8
|
+
FileUp,
|
|
9
|
+
FolderPlus,
|
|
10
|
+
Globe2,
|
|
11
|
+
HardDrive,
|
|
12
|
+
Loader2,
|
|
13
|
+
Repeat2,
|
|
14
|
+
Search,
|
|
15
|
+
ShieldCheck,
|
|
16
|
+
Sparkles,
|
|
17
|
+
} from "lucide-react";
|
|
3
18
|
|
|
4
19
|
const INGESTION_TYPE_LABEL_KEY: Record<IngestionSourceType, string> = {
|
|
5
20
|
file: "brain.ingest.type.file",
|
|
@@ -28,7 +43,6 @@ import { BrainOverviewPanel } from "./BrainOverviewPanel";
|
|
|
28
43
|
|
|
29
44
|
export function BrainConversation({
|
|
30
45
|
language,
|
|
31
|
-
explorationDepth,
|
|
32
46
|
modelName,
|
|
33
47
|
messages,
|
|
34
48
|
starterPrompts,
|
|
@@ -84,113 +98,219 @@ export function BrainConversation({
|
|
|
84
98
|
return (
|
|
85
99
|
<section className="brain-conversation" aria-label={t(language, "brain.aria.conversation")}>
|
|
86
100
|
<div className="brain-conversation-header">
|
|
87
|
-
<div>
|
|
88
|
-
<h1>
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
<span>{t(language, "brain.
|
|
95
|
-
<span>{t(language, "brain.private")}</span>
|
|
101
|
+
<div className="brain-conversation-title">
|
|
102
|
+
<h1>
|
|
103
|
+
{t(language, "brain.title")}
|
|
104
|
+
<span className="brain-edition-badge" title={t(language, "brain.edition.tip")}>
|
|
105
|
+
{t(language, "brain.edition")}
|
|
106
|
+
</span>
|
|
107
|
+
</h1>
|
|
108
|
+
<span>{t(language, "brain.chatHome.headerLine")}</span>
|
|
96
109
|
</div>
|
|
97
|
-
<div className="brain-
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
<Search className="h-3.5 w-3.5" />
|
|
104
|
-
{t(language, "brain.action.find")}
|
|
105
|
-
</button>
|
|
106
|
-
<button type="button" onClick={() => navigateHash("/models")}>
|
|
107
|
-
<Cpu className="h-3.5 w-3.5" />
|
|
108
|
-
{t(language, "brain.action.model")}
|
|
109
|
-
</button>
|
|
110
|
-
<button type="button" onClick={() => navigateHash("/settings")}>
|
|
111
|
-
<Settings className="h-3.5 w-3.5" />
|
|
112
|
-
{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")}
|
|
113
116
|
</button>
|
|
114
117
|
</div>
|
|
115
|
-
<div className="brain-model-pill">{modelName}</div>
|
|
116
|
-
<button className="brain-admin-link" type="button" onClick={() => navigateHash("/admin")}>
|
|
117
|
-
<ShieldCheck className="h-3.5 w-3.5" />
|
|
118
|
-
{t(language, "brain.admin")}
|
|
119
|
-
</button>
|
|
120
118
|
</div>
|
|
121
119
|
|
|
122
|
-
<div
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
148
172
|
language={language}
|
|
149
|
-
|
|
173
|
+
draft={draft}
|
|
174
|
+
streaming={streaming}
|
|
175
|
+
imageData={imageData}
|
|
150
176
|
uploadingDocument={uploadingDocument}
|
|
151
177
|
onDraftChange={onDraftChange}
|
|
178
|
+
onImageDataChange={onImageDataChange}
|
|
152
179
|
onUploadDocument={onUploadDocument}
|
|
180
|
+
onSend={onSend}
|
|
153
181
|
/>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
182
|
+
|
|
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>
|
|
171
224
|
</div>
|
|
225
|
+
</section>
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function ProductCommandCenter({
|
|
230
|
+
language,
|
|
231
|
+
readiness,
|
|
232
|
+
proof,
|
|
233
|
+
modelName,
|
|
234
|
+
memories,
|
|
235
|
+
concepts,
|
|
236
|
+
emergenceEvents,
|
|
237
|
+
onOpenDepth,
|
|
238
|
+
onVerifyModelContinuity,
|
|
239
|
+
}: {
|
|
240
|
+
language: Language;
|
|
241
|
+
readiness: BrainReadiness;
|
|
242
|
+
proof: BrainProof;
|
|
243
|
+
modelName: string;
|
|
244
|
+
memories: MemoryFragment[];
|
|
245
|
+
concepts: KnowledgeConcept[];
|
|
246
|
+
emergenceEvents: EmergenceEvent[];
|
|
247
|
+
onOpenDepth: (depth: BrainDepth) => void;
|
|
248
|
+
onVerifyModelContinuity: () => void;
|
|
249
|
+
}) {
|
|
250
|
+
const score = Math.max(0, Math.min(100, readiness.score));
|
|
251
|
+
const nextKey =
|
|
252
|
+
readiness.state === "alive"
|
|
253
|
+
? "brain.command.next.alive"
|
|
254
|
+
: readiness.state === "forming"
|
|
255
|
+
? "brain.command.next.forming"
|
|
256
|
+
: "brain.command.next.empty";
|
|
257
|
+
const recallable = (proof.recall && proof.recall.items) ? proof.recall.items.length : (proof.proofs ? (proof.proofs.durableItems || 1) : 1);
|
|
258
|
+
const latestSource = emergenceEvents[0]?.label ?? t(language, "brain.command.source.empty");
|
|
172
259
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<
|
|
260
|
+
return (
|
|
261
|
+
<section className="brain-command-center" aria-label={t(language, "brain.command.aria")}>
|
|
262
|
+
<div className="brain-command-head">
|
|
263
|
+
<div>
|
|
264
|
+
<span>{t(language, "brain.command.kicker")}</span>
|
|
265
|
+
<strong>{t(language, "brain.command.title")}</strong>
|
|
178
266
|
</div>
|
|
179
|
-
|
|
267
|
+
<div className="brain-command-score" role="meter" aria-valuemin={0} aria-valuemax={100} aria-valuenow={score}>
|
|
268
|
+
<span>{t(language, "brain.command.score")}</span>
|
|
269
|
+
<strong>{score}%</strong>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
180
272
|
|
|
181
|
-
<
|
|
273
|
+
<div className="brain-command-next">
|
|
274
|
+
<BrainCircuit className="h-4 w-4" />
|
|
275
|
+
<span>{t(language, "brain.command.next")}</span>
|
|
276
|
+
<strong>{t(language, nextKey)}</strong>
|
|
277
|
+
</div>
|
|
182
278
|
|
|
183
|
-
<
|
|
184
|
-
language
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
279
|
+
<div className="brain-command-metrics" aria-label={t(language, "brain.command.metrics")}>
|
|
280
|
+
<span>{t(language, "brain.command.metric.memories", { count: memories.length })}</span>
|
|
281
|
+
<span>{t(language, "brain.command.metric.topics", { count: concepts.length })}</span>
|
|
282
|
+
<span>{t(language, "brain.command.metric.sources", { count: readiness.signals.healthySources })}</span>
|
|
283
|
+
<span>{t(language, "brain.command.metric.proof", { count: recallable })}</span>
|
|
284
|
+
</div>
|
|
285
|
+
|
|
286
|
+
<div className="brain-command-actions">
|
|
287
|
+
<button type="button" aria-label={t(language, "brain.command.action.add")} onClick={() => navigateHash("/capture")}>
|
|
288
|
+
<FileUp className="h-4 w-4" />
|
|
289
|
+
<span>{t(language, "brain.command.action.add")}</span>
|
|
290
|
+
<small>{latestSource}</small>
|
|
291
|
+
</button>
|
|
292
|
+
<button type="button" aria-label={t(language, "brain.command.action.find")} onClick={() => onOpenDepth(3)}>
|
|
293
|
+
<Search className="h-4 w-4" />
|
|
294
|
+
<span>{t(language, "brain.command.action.find")}</span>
|
|
295
|
+
<small>{t(language, "brain.command.action.find.detail")}</small>
|
|
296
|
+
</button>
|
|
297
|
+
<button type="button" aria-label={t(language, "brain.command.action.proof")} onClick={onVerifyModelContinuity}>
|
|
298
|
+
<Repeat2 className="h-4 w-4" />
|
|
299
|
+
<span>{t(language, "brain.command.action.proof")}</span>
|
|
300
|
+
<small>{proof.modelContinuity.proven ? proof.modelContinuity.activeModel || modelName : modelName}</small>
|
|
301
|
+
</button>
|
|
302
|
+
<button type="button" aria-label={t(language, "brain.command.action.own")} onClick={() => navigateHash("/settings")}>
|
|
303
|
+
<HardDrive className="h-4 w-4" />
|
|
304
|
+
<span>{t(language, "brain.command.action.own")}</span>
|
|
305
|
+
<small>{t(language, "brain.command.action.own.detail")}</small>
|
|
306
|
+
</button>
|
|
307
|
+
</div>
|
|
308
|
+
|
|
309
|
+
<div className="brain-command-signals">
|
|
310
|
+
<span><CheckCircle2 className="h-3.5 w-3.5" />{t(language, "brain.command.signal.local")}</span>
|
|
311
|
+
<span><CheckCircle2 className="h-3.5 w-3.5" />{t(language, "brain.command.signal.private")}</span>
|
|
312
|
+
<span><CheckCircle2 className="h-3.5 w-3.5" />{t(language, "brain.command.signal.portable")}</span>
|
|
313
|
+
</div>
|
|
194
314
|
</section>
|
|
195
315
|
);
|
|
196
316
|
}
|
|
@@ -494,34 +494,38 @@ export function BrainHome({
|
|
|
494
494
|
onInteract={deepen}
|
|
495
495
|
/>
|
|
496
496
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
<
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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}
|
|
525
529
|
|
|
526
530
|
<div className="brain-field-layer" aria-hidden={explorationDepth < 2}>
|
|
527
531
|
<DepthEmergence
|
|
@@ -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"] {
|