ltcai 8.0.0 → 8.1.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 (103) hide show
  1. package/README.md +32 -50
  2. package/docs/CHANGELOG.md +14 -0
  3. package/docs/V3_FRONTEND.md +11 -5
  4. package/lattice_brain/__init__.py +1 -1
  5. package/lattice_brain/embeddings.py +9 -1
  6. package/lattice_brain/runtime/multi_agent.py +1 -1
  7. package/latticeai/__init__.py +1 -1
  8. package/latticeai/app_factory.py +13 -134
  9. package/latticeai/core/local_embeddings.py +8 -0
  10. package/latticeai/core/marketplace.py +1 -1
  11. package/latticeai/core/mcp_registry.py +140 -1
  12. package/latticeai/core/workspace_os.py +1 -1
  13. package/latticeai/services/architecture_readiness.py +6 -5
  14. package/latticeai/services/model_runtime.py +36 -2
  15. package/latticeai/services/product_readiness.py +18 -18
  16. package/package.json +2 -2
  17. package/scripts/build_frontend_assets.mjs +11 -2
  18. package/src-tauri/Cargo.lock +1 -1
  19. package/src-tauri/Cargo.toml +1 -1
  20. package/src-tauri/tauri.conf.json +1 -1
  21. package/static/app/asset-manifest.json +11 -102
  22. package/static/app/assets/Act-BOO66G-c.js +1 -0
  23. package/static/app/assets/Brain-C6lEYiD7.js +321 -0
  24. package/static/app/assets/{Capture-B9Tlhzqr.js → Capture-TATXBRDw.js} +1 -2
  25. package/static/app/assets/Library-DK4FIp8a.js +1 -0
  26. package/static/app/assets/System-Bgs6Ql7x.js +1 -0
  27. package/static/app/assets/core-CwxXejkd.js +1 -2
  28. package/static/app/assets/index-Bvv79nre.js +16 -0
  29. package/static/app/assets/index-Dslqglia.css +2 -0
  30. package/static/app/assets/primitives-B70WOra0.js +1 -0
  31. package/static/app/assets/{textarea-BZk6ybp5.js → textarea-Czrd9gwM.js} +1 -2
  32. package/static/app/index.html +3 -10
  33. package/static/app/theme-boot.js +8 -0
  34. package/static/sw.js +1 -1
  35. package/frontend/index.html +0 -24
  36. package/frontend/openapi.json +0 -15425
  37. package/frontend/src/App.tsx +0 -243
  38. package/frontend/src/api/client.ts +0 -580
  39. package/frontend/src/api/openapi.ts +0 -17892
  40. package/frontend/src/components/AdminAccessGate.tsx +0 -70
  41. package/frontend/src/components/FeedbackState.tsx +0 -45
  42. package/frontend/src/components/LanguageSwitcher.tsx +0 -23
  43. package/frontend/src/components/LivingBrain.tsx +0 -220
  44. package/frontend/src/components/ProductFlow.tsx +0 -171
  45. package/frontend/src/components/WorkspaceProfileSwitcher.tsx +0 -176
  46. package/frontend/src/components/onboarding/AnalysisScreen.tsx +0 -135
  47. package/frontend/src/components/onboarding/DownloadConsentPanel.tsx +0 -29
  48. package/frontend/src/components/onboarding/InstallScreen.tsx +0 -263
  49. package/frontend/src/components/onboarding/LanguageChooser.tsx +0 -23
  50. package/frontend/src/components/onboarding/LoginScreen.tsx +0 -131
  51. package/frontend/src/components/onboarding/ProductFlowScreens.tsx +0 -13
  52. package/frontend/src/components/onboarding/RecommendationScreen.tsx +0 -116
  53. package/frontend/src/components/onboarding/recommendationModel.ts +0 -189
  54. package/frontend/src/components/primitives.tsx +0 -392
  55. package/frontend/src/components/ui/badge.tsx +0 -27
  56. package/frontend/src/components/ui/button.tsx +0 -37
  57. package/frontend/src/components/ui/card.tsx +0 -22
  58. package/frontend/src/components/ui/input.tsx +0 -16
  59. package/frontend/src/components/ui/textarea.tsx +0 -16
  60. package/frontend/src/features/admin/AdminConsole.tsx +0 -334
  61. package/frontend/src/features/brain/BrainCarePanel.tsx +0 -254
  62. package/frontend/src/features/brain/BrainComposer.tsx +0 -85
  63. package/frontend/src/features/brain/BrainConversation.tsx +0 -688
  64. package/frontend/src/features/brain/BrainGraphLayer.tsx +0 -365
  65. package/frontend/src/features/brain/BrainHome.tsx +0 -624
  66. package/frontend/src/features/brain/BrainMemoryLayer.tsx +0 -45
  67. package/frontend/src/features/brain/BrainOverviewPanel.tsx +0 -149
  68. package/frontend/src/features/brain/BrainRelationshipLayer.tsx +0 -43
  69. package/frontend/src/features/brain/DepthEmergence.tsx +0 -53
  70. package/frontend/src/features/brain/brainData.ts +0 -246
  71. package/frontend/src/features/brain/graphLayout.ts +0 -37
  72. package/frontend/src/features/brain/types.ts +0 -150
  73. package/frontend/src/features/review/ReviewCard.tsx +0 -100
  74. package/frontend/src/features/review/ReviewInbox.tsx +0 -127
  75. package/frontend/src/features/review/reviewHelpers.ts +0 -69
  76. package/frontend/src/i18n.ts +0 -1303
  77. package/frontend/src/lib/utils.ts +0 -33
  78. package/frontend/src/main.tsx +0 -23
  79. package/frontend/src/pages/Act.tsx +0 -458
  80. package/frontend/src/pages/Ask.tsx +0 -14
  81. package/frontend/src/pages/Brain.tsx +0 -914
  82. package/frontend/src/pages/Capture.tsx +0 -258
  83. package/frontend/src/pages/Library.tsx +0 -486
  84. package/frontend/src/pages/System.tsx +0 -621
  85. package/frontend/src/routes.ts +0 -92
  86. package/frontend/src/store/appStore.ts +0 -94
  87. package/frontend/src/styles.css +0 -6579
  88. package/static/app/assets/Act-DOvf59ru.js +0 -2
  89. package/static/app/assets/Act-DOvf59ru.js.map +0 -1
  90. package/static/app/assets/Brain-C7_0mEiI.js +0 -322
  91. package/static/app/assets/Brain-C7_0mEiI.js.map +0 -1
  92. package/static/app/assets/Capture-B9Tlhzqr.js.map +0 -1
  93. package/static/app/assets/Library-BJPEEm5O.js +0 -2
  94. package/static/app/assets/Library-BJPEEm5O.js.map +0 -1
  95. package/static/app/assets/System-D6t9jo9V.js +0 -2
  96. package/static/app/assets/System-D6t9jo9V.js.map +0 -1
  97. package/static/app/assets/core-CwxXejkd.js.map +0 -1
  98. package/static/app/assets/index-C7g26IF6.css +0 -2
  99. package/static/app/assets/index-DbcEYJQ2.js +0 -17
  100. package/static/app/assets/index-DbcEYJQ2.js.map +0 -1
  101. package/static/app/assets/primitives-CD38lt4n.js +0 -2
  102. package/static/app/assets/primitives-CD38lt4n.js.map +0 -1
  103. package/static/app/assets/textarea-BZk6ybp5.js.map +0 -1
@@ -1,258 +0,0 @@
1
- import * as React from "react";
2
- import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3
- import { AlertCircle, CheckCircle2, FolderPlus, Globe2, HardDrive, Loader2, RotateCcw, Upload } from "lucide-react";
4
- import { latticeApi } from "@/api/client";
5
- import { ActionButton, DataPanel, EntityList, OperationResult, StructuredView, Tabs } from "@/components/primitives";
6
- import { Button } from "@/components/ui/button";
7
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
8
- import { Input } from "@/components/ui/input";
9
- import { t, type Language } from "@/i18n";
10
- import { asArray } from "@/lib/utils";
11
- import { useAppStore } from "@/store/appStore";
12
-
13
- type CaptureTab = "files" | "local" | "browser" | "pipeline";
14
-
15
- export function CapturePage({ initialTab }: { initialTab?: string }) {
16
- const language = useAppStore((state) => state.language);
17
- const [tab, setTab] = React.useState<CaptureTab>((initialTab as CaptureTab) || "files");
18
- const tabs: Array<{ id: CaptureTab; label: string }> = [
19
- { id: "files", label: t(language, "capture.tab.files") },
20
- { id: "local", label: t(language, "capture.tab.local") },
21
- { id: "browser", label: t(language, "capture.tab.browser") },
22
- { id: "pipeline", label: t(language, "capture.tab.pipeline") },
23
- ];
24
- React.useEffect(() => {
25
- if (initialTab === "pipeline" || initialTab === "local" || initialTab === "files") setTab(initialTab);
26
- }, [initialTab]);
27
- return (
28
- <div className="space-y-5">
29
- <header className="page-hero">
30
- <div className="page-kicker"><Upload className="h-4 w-4" /> {t(language, "capture.kicker")}</div>
31
- <h1 className="page-title">{t(language, "capture.title")}</h1>
32
- <p className="page-copy">{t(language, "capture.body")}</p>
33
- </header>
34
- <Tabs tabs={tabs} value={tab} onChange={(id) => setTab(id as CaptureTab)} />
35
- {tab === "files" ? <FilesPanel /> : null}
36
- {tab === "local" ? <LocalPanel /> : null}
37
- {tab === "browser" ? <BrowserPanel /> : null}
38
- {tab === "pipeline" ? <PipelinePanel /> : null}
39
- </div>
40
- );
41
- }
42
-
43
- function FilesPanel() {
44
- const language = useAppStore((state) => state.language);
45
- const qc = useQueryClient();
46
- const docs = useQuery({ queryKey: ["documents"], queryFn: () => latticeApi.documents(200) });
47
- const [queue, setQueue] = React.useState<UploadQueueItem[]>([]);
48
- const upload = useMutation({
49
- mutationFn: (files: File[]) => uploadFiles(files, setQueue),
50
- onSuccess: () => {
51
- void qc.invalidateQueries({ queryKey: ["documents"] });
52
- void qc.invalidateQueries({ queryKey: ["graphStats"] });
53
- void qc.invalidateQueries({ queryKey: ["memoryManager"] });
54
- },
55
- });
56
- const beginUpload = React.useCallback((files: FileList | File[]) => {
57
- const nextFiles = Array.from(files);
58
- if (!nextFiles.length) return;
59
- upload.mutate(nextFiles);
60
- }, [upload]);
61
- return (
62
- <div className="grid gap-4 xl:grid-cols-[0.75fr_1.25fr]">
63
- <Card>
64
- <CardHeader>
65
- <CardTitle className="flex items-center gap-2"><Upload className="h-4 w-4" /> {t(language, "capture.files.title")}</CardTitle>
66
- <CardDescription>{t(language, "capture.files.description")}</CardDescription>
67
- </CardHeader>
68
- <CardContent>
69
- <label
70
- className="flex min-h-56 cursor-pointer flex-col items-center justify-center gap-3 rounded-lg border border-dashed border-border bg-muted/30 p-6 text-center transition hover:bg-muted/50"
71
- onDragOver={(event) => event.preventDefault()}
72
- onDrop={(event) => {
73
- event.preventDefault();
74
- beginUpload(event.dataTransfer.files);
75
- }}
76
- >
77
- <Upload className="h-7 w-7 text-primary" />
78
- <span className="text-lg font-semibold">{t(language, "capture.files.drop")}</span>
79
- <span className="max-w-sm text-sm leading-6 text-muted-foreground">{t(language, "capture.files.dropDetail")}</span>
80
- <input type="file" multiple className="sr-only" onChange={(e) => e.target.files && beginUpload(e.target.files)} />
81
- </label>
82
- <DocumentUploadQueue queue={queue} onRetry={(file) => beginUpload([file])} />
83
- </CardContent>
84
- </Card>
85
- <DataPanel title={t(language, "capture.files.uploaded")} result={docs.data}>
86
- {(data) => (
87
- <div className="space-y-3">
88
- <EntityList items={(data as Record<string, unknown>).documents || data} titleKey="filename" metaKey="ingest_state" limit={12} />
89
- <div className="rounded-md border border-border bg-background/55 p-3 text-sm text-muted-foreground">
90
- {t(language, "capture.files.completed")}
91
- </div>
92
- </div>
93
- )}
94
- </DataPanel>
95
- </div>
96
- );
97
- }
98
-
99
- type UploadQueueItem = {
100
- id: string;
101
- file: File;
102
- name: string;
103
- size: number;
104
- status: "queued" | "uploading" | "done" | "failed";
105
- result?: Awaited<ReturnType<typeof latticeApi.uploadDocument>>;
106
- };
107
-
108
- async function uploadFiles(files: File[], setQueue: React.Dispatch<React.SetStateAction<UploadQueueItem[]>>) {
109
- const rows = files.map((file) => ({
110
- id: `${file.name}-${file.size}-${file.lastModified}-${Date.now()}`,
111
- file,
112
- name: file.name,
113
- size: file.size,
114
- status: "queued" as const,
115
- }));
116
- setQueue((items) => [...rows, ...items].slice(0, 12));
117
- const results = [];
118
- for (const row of rows) {
119
- setQueue((items) => items.map((item) => item.id === row.id ? { ...item, status: "uploading" } : item));
120
- const result = await latticeApi.uploadDocument(row.file);
121
- results.push(result);
122
- setQueue((items) => items.map((item) => item.id === row.id ? { ...item, status: result.ok ? "done" : "failed", result } : item));
123
- }
124
- return results;
125
- }
126
-
127
- function DocumentUploadQueue({ queue, onRetry }: { queue: UploadQueueItem[]; onRetry: (file: File) => void }) {
128
- const language = useAppStore((state) => state.language);
129
- if (!queue.length) return null;
130
- return (
131
- <div className="mt-4 space-y-2">
132
- {queue.map((item) => {
133
- const detail = uploadResultDetail(item, language);
134
- return (
135
- <div key={item.id} className="rounded-md border border-border bg-background/55 p-3 text-sm">
136
- <div className="flex flex-wrap items-start justify-between gap-3">
137
- <div>
138
- <div className="flex items-center gap-2 font-medium">
139
- {item.status === "done" ? <CheckCircle2 className="h-4 w-4 text-emerald-400" /> : item.status === "failed" ? <AlertCircle className="h-4 w-4 text-amber-400" /> : <Loader2 className="h-4 w-4 animate-spin text-primary" />}
140
- {item.name}
141
- </div>
142
- <div className="mt-1 text-xs text-muted-foreground">
143
- {Math.max(1, Math.round(item.size / 1024))} KB · {detail}
144
- </div>
145
- </div>
146
- {item.status === "failed" ? (
147
- <Button size="sm" variant="outline" onClick={() => onRetry(item.file)}>
148
- <RotateCcw className="h-3.5 w-3.5" /> {t(language, "capture.retry")}
149
- </Button>
150
- ) : null}
151
- </div>
152
- {item.result ? <OperationResult result={item.result} successLabel={t(language, "capture.files.success")} /> : null}
153
- </div>
154
- );
155
- })}
156
- </div>
157
- );
158
- }
159
-
160
- function uploadResultDetail(item: UploadQueueItem, language: Language) {
161
- if (item.status === "queued") return t(language, "capture.files.queued");
162
- if (item.status === "uploading") return t(language, "capture.files.uploading");
163
- if (!item.result?.ok) return item.result?.error || t(language, "capture.files.failed");
164
- const data = item.result.data || {};
165
- const node = String(data.node_id || data.graph_node || data.provenance_id || "");
166
- return node ? t(language, "capture.files.capturedWithNode", { node }) : t(language, "capture.files.captured");
167
- }
168
-
169
- function LocalPanel() {
170
- const language = useAppStore((state) => state.language);
171
- const qc = useQueryClient();
172
- const [path, setPath] = React.useState("");
173
- const local = useQuery({ queryKey: ["localSources"], queryFn: latticeApi.localSources });
174
- const agent = useQuery({ queryKey: ["localAgent"], queryFn: latticeApi.localAgent });
175
- const connect = useMutation({
176
- mutationFn: () => latticeApi.connectFolder(path),
177
- onSuccess: () => qc.invalidateQueries({ queryKey: ["localSources"] }),
178
- });
179
- return (
180
- <div className="grid gap-4 xl:grid-cols-[0.9fr_1.1fr]">
181
- <Card>
182
- <CardHeader>
183
- <CardTitle className="flex items-center gap-2"><FolderPlus className="h-4 w-4" /> {t(language, "capture.local.title")}</CardTitle>
184
- <CardDescription>{t(language, "capture.local.description")}</CardDescription>
185
- </CardHeader>
186
- <CardContent className="space-y-3">
187
- <Input value={path} onChange={(e) => setPath(e.target.value)} placeholder={t(language, "capture.local.placeholder")} />
188
- <Button disabled={!path.trim() || connect.isPending} onClick={() => connect.mutate()}>{t(language, "capture.local.connect")}</Button>
189
- {connect.data ? <OperationResult result={connect.data} successLabel={t(language, "capture.local.success")} /> : null}
190
- </CardContent>
191
- </Card>
192
- <DataPanel title={t(language, "capture.local.sources")} result={local.data}>
193
- {(data) => (
194
- <div className="space-y-3">
195
- <EntityList items={(data as Record<string, unknown>).sources} titleKey="path" metaKey="status" />
196
- {asArray<Record<string, unknown>>((data as Record<string, unknown>).sources).map((source) => (
197
- <ActionButton
198
- key={String(source.id || source.source_id || source.path)}
199
- label={`Stop ${String(source.path || source.id || "source")}`}
200
- action={() => latticeApi.localWatchStop(String(source.id || source.source_id))}
201
- invalidate={["localSources"]}
202
- />
203
- ))}
204
- </div>
205
- )}
206
- </DataPanel>
207
- <DataPanel title={t(language, "capture.local.access")} result={agent.data} className="xl:col-span-2">
208
- {(data) => <StructuredView value={data} />}
209
- </DataPanel>
210
- </div>
211
- );
212
- }
213
-
214
- function BrowserPanel() {
215
- const language = useAppStore((state) => state.language);
216
- const [url, setUrl] = React.useState("");
217
- const read = useMutation({ mutationFn: () => latticeApi.browserReadUrl(url) });
218
- return (
219
- <Card>
220
- <CardHeader>
221
- <CardTitle className="flex items-center gap-2"><Globe2 className="h-4 w-4" /> {t(language, "capture.browser.title")}</CardTitle>
222
- <CardDescription>{t(language, "capture.browser.description")}</CardDescription>
223
- </CardHeader>
224
- <CardContent className="space-y-3">
225
- <div className="flex flex-col gap-2 sm:flex-row">
226
- <Input value={url} onChange={(e) => setUrl(e.target.value)} placeholder={t(language, "capture.browser.placeholder")} />
227
- <Button disabled={!url.trim() || read.isPending} onClick={() => read.mutate()}>{t(language, "capture.browser.capture")}</Button>
228
- </div>
229
- {read.data ? <OperationResult result={read.data} successLabel={t(language, "capture.browser.success")} /> : null}
230
- </CardContent>
231
- </Card>
232
- );
233
- }
234
-
235
- function PipelinePanel() {
236
- const language = useAppStore((state) => state.language);
237
- const index = useQuery({ queryKey: ["index"], queryFn: latticeApi.indexStatus });
238
- const stats = useQuery({ queryKey: ["graphStats"], queryFn: latticeApi.graphStats });
239
- return (
240
- <div className="grid gap-4 xl:grid-cols-2">
241
- <DataPanel title={t(language, "capture.pipeline.status")} result={index.data}>
242
- {(data) => <StructuredView value={data} />}
243
- </DataPanel>
244
- <DataPanel title={t(language, "capture.pipeline.growth")} result={stats.data}>
245
- {(data) => <StructuredView value={data} />}
246
- </DataPanel>
247
- <Card className="xl:col-span-2">
248
- <CardHeader>
249
- <CardTitle className="flex items-center gap-2"><HardDrive className="h-4 w-4" /> {t(language, "capture.pipeline.refresh")}</CardTitle>
250
- <CardDescription>{t(language, "capture.pipeline.description")}</CardDescription>
251
- </CardHeader>
252
- <CardContent>
253
- <ActionButton label={t(language, "capture.pipeline.rebuild")} action={() => latticeApi.rebuildIndex()} invalidate={["index"]} />
254
- </CardContent>
255
- </Card>
256
- </div>
257
- );
258
- }