ltcai 7.9.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 (107) hide show
  1. package/README.md +35 -49
  2. package/docs/CHANGELOG.md +35 -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/graph/projection.py +19 -5
  7. package/lattice_brain/graph/provenance.py +26 -4
  8. package/lattice_brain/graph/write_master.py +30 -3
  9. package/lattice_brain/runtime/multi_agent.py +1 -1
  10. package/latticeai/__init__.py +1 -1
  11. package/latticeai/app_factory.py +13 -134
  12. package/latticeai/core/local_embeddings.py +8 -0
  13. package/latticeai/core/marketplace.py +1 -1
  14. package/latticeai/core/mcp_registry.py +140 -1
  15. package/latticeai/core/tool_registry.py +7 -0
  16. package/latticeai/core/workspace_os.py +1 -1
  17. package/latticeai/services/architecture_readiness.py +50 -6
  18. package/latticeai/services/model_runtime.py +36 -2
  19. package/latticeai/services/product_readiness.py +19 -17
  20. package/package.json +2 -2
  21. package/scripts/build_frontend_assets.mjs +11 -2
  22. package/src-tauri/Cargo.lock +1 -1
  23. package/src-tauri/Cargo.toml +1 -1
  24. package/src-tauri/tauri.conf.json +1 -1
  25. package/static/app/asset-manifest.json +11 -102
  26. package/static/app/assets/Act-BOO66G-c.js +1 -0
  27. package/static/app/assets/Brain-C6lEYiD7.js +321 -0
  28. package/static/app/assets/{Capture-B9Tlhzqr.js → Capture-TATXBRDw.js} +1 -2
  29. package/static/app/assets/Library-DK4FIp8a.js +1 -0
  30. package/static/app/assets/System-Bgs6Ql7x.js +1 -0
  31. package/static/app/assets/core-CwxXejkd.js +1 -2
  32. package/static/app/assets/index-Bvv79nre.js +16 -0
  33. package/static/app/assets/index-Dslqglia.css +2 -0
  34. package/static/app/assets/primitives-B70WOra0.js +1 -0
  35. package/static/app/assets/{textarea-BZk6ybp5.js → textarea-Czrd9gwM.js} +1 -2
  36. package/static/app/index.html +3 -10
  37. package/static/app/theme-boot.js +8 -0
  38. package/static/sw.js +1 -1
  39. package/frontend/index.html +0 -24
  40. package/frontend/openapi.json +0 -15425
  41. package/frontend/src/App.tsx +0 -243
  42. package/frontend/src/api/client.ts +0 -580
  43. package/frontend/src/api/openapi.ts +0 -17892
  44. package/frontend/src/components/AdminAccessGate.tsx +0 -70
  45. package/frontend/src/components/FeedbackState.tsx +0 -45
  46. package/frontend/src/components/LanguageSwitcher.tsx +0 -23
  47. package/frontend/src/components/LivingBrain.tsx +0 -220
  48. package/frontend/src/components/ProductFlow.tsx +0 -171
  49. package/frontend/src/components/WorkspaceProfileSwitcher.tsx +0 -176
  50. package/frontend/src/components/onboarding/AnalysisScreen.tsx +0 -135
  51. package/frontend/src/components/onboarding/DownloadConsentPanel.tsx +0 -29
  52. package/frontend/src/components/onboarding/InstallScreen.tsx +0 -263
  53. package/frontend/src/components/onboarding/LanguageChooser.tsx +0 -23
  54. package/frontend/src/components/onboarding/LoginScreen.tsx +0 -131
  55. package/frontend/src/components/onboarding/ProductFlowScreens.tsx +0 -13
  56. package/frontend/src/components/onboarding/RecommendationScreen.tsx +0 -116
  57. package/frontend/src/components/onboarding/recommendationModel.ts +0 -189
  58. package/frontend/src/components/primitives.tsx +0 -392
  59. package/frontend/src/components/ui/badge.tsx +0 -27
  60. package/frontend/src/components/ui/button.tsx +0 -37
  61. package/frontend/src/components/ui/card.tsx +0 -22
  62. package/frontend/src/components/ui/input.tsx +0 -16
  63. package/frontend/src/components/ui/textarea.tsx +0 -16
  64. package/frontend/src/features/admin/AdminConsole.tsx +0 -334
  65. package/frontend/src/features/brain/BrainCarePanel.tsx +0 -254
  66. package/frontend/src/features/brain/BrainComposer.tsx +0 -85
  67. package/frontend/src/features/brain/BrainConversation.tsx +0 -688
  68. package/frontend/src/features/brain/BrainGraphLayer.tsx +0 -365
  69. package/frontend/src/features/brain/BrainHome.tsx +0 -624
  70. package/frontend/src/features/brain/BrainMemoryLayer.tsx +0 -45
  71. package/frontend/src/features/brain/BrainOverviewPanel.tsx +0 -149
  72. package/frontend/src/features/brain/BrainRelationshipLayer.tsx +0 -43
  73. package/frontend/src/features/brain/DepthEmergence.tsx +0 -53
  74. package/frontend/src/features/brain/brainData.ts +0 -246
  75. package/frontend/src/features/brain/graphLayout.ts +0 -37
  76. package/frontend/src/features/brain/types.ts +0 -150
  77. package/frontend/src/features/review/ReviewCard.tsx +0 -100
  78. package/frontend/src/features/review/ReviewInbox.tsx +0 -127
  79. package/frontend/src/features/review/reviewHelpers.ts +0 -69
  80. package/frontend/src/i18n.ts +0 -1303
  81. package/frontend/src/lib/utils.ts +0 -33
  82. package/frontend/src/main.tsx +0 -23
  83. package/frontend/src/pages/Act.tsx +0 -458
  84. package/frontend/src/pages/Ask.tsx +0 -14
  85. package/frontend/src/pages/Brain.tsx +0 -914
  86. package/frontend/src/pages/Capture.tsx +0 -258
  87. package/frontend/src/pages/Library.tsx +0 -486
  88. package/frontend/src/pages/System.tsx +0 -621
  89. package/frontend/src/routes.ts +0 -92
  90. package/frontend/src/store/appStore.ts +0 -94
  91. package/frontend/src/styles.css +0 -6579
  92. package/static/app/assets/Act-DOvf59ru.js +0 -2
  93. package/static/app/assets/Act-DOvf59ru.js.map +0 -1
  94. package/static/app/assets/Brain-C7_0mEiI.js +0 -322
  95. package/static/app/assets/Brain-C7_0mEiI.js.map +0 -1
  96. package/static/app/assets/Capture-B9Tlhzqr.js.map +0 -1
  97. package/static/app/assets/Library-BJPEEm5O.js +0 -2
  98. package/static/app/assets/Library-BJPEEm5O.js.map +0 -1
  99. package/static/app/assets/System-D6t9jo9V.js +0 -2
  100. package/static/app/assets/System-D6t9jo9V.js.map +0 -1
  101. package/static/app/assets/core-CwxXejkd.js.map +0 -1
  102. package/static/app/assets/index-C7g26IF6.css +0 -2
  103. package/static/app/assets/index-DbcEYJQ2.js +0 -17
  104. package/static/app/assets/index-DbcEYJQ2.js.map +0 -1
  105. package/static/app/assets/primitives-CD38lt4n.js +0 -2
  106. package/static/app/assets/primitives-CD38lt4n.js.map +0 -1
  107. 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
- }