ltcai 3.5.0 → 4.0.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 (181) hide show
  1. package/README.md +73 -35
  2. package/docs/CARRYOVER_AUDIT_v3.6.0.md +61 -0
  3. package/docs/CHANGELOG.md +32 -0
  4. package/docs/HANDOVER_v3.6.0.md +46 -0
  5. package/docs/RUNTIME_HOOK_COVERAGE_v3.6.0.md +49 -0
  6. package/docs/V4_BRAIN_ARCHITECTURE.md +322 -0
  7. package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +509 -0
  8. package/docs/V4_IMPLEMENTATION_PLAN.md +470 -0
  9. package/docs/architecture.md +13 -12
  10. package/docs/kg-schema.md +102 -53
  11. package/docs/privacy.md +18 -2
  12. package/docs/security-model.md +17 -0
  13. package/kg_schema.py +139 -10
  14. package/knowledge_graph.py +874 -26
  15. package/knowledge_graph_api.py +11 -127
  16. package/latticeai/__init__.py +1 -1
  17. package/latticeai/api/admin.py +1 -1
  18. package/latticeai/api/agents.py +7 -1
  19. package/latticeai/api/auth.py +27 -4
  20. package/latticeai/api/browser.py +217 -0
  21. package/latticeai/api/chat.py +112 -76
  22. package/latticeai/api/health.py +1 -1
  23. package/latticeai/api/hooks.py +1 -1
  24. package/latticeai/api/knowledge_graph.py +146 -0
  25. package/latticeai/api/local_files.py +1 -1
  26. package/latticeai/api/mcp.py +23 -11
  27. package/latticeai/api/memory.py +1 -1
  28. package/latticeai/api/models.py +1 -1
  29. package/latticeai/api/network.py +81 -0
  30. package/latticeai/api/portability.py +93 -0
  31. package/latticeai/api/realtime.py +1 -1
  32. package/latticeai/api/search.py +26 -2
  33. package/latticeai/api/security_dashboard.py +2 -3
  34. package/latticeai/api/setup.py +2 -2
  35. package/latticeai/api/static_routes.py +2 -4
  36. package/latticeai/api/tools.py +3 -0
  37. package/latticeai/api/workflow_designer.py +46 -0
  38. package/latticeai/api/workspace.py +71 -49
  39. package/latticeai/app_factory.py +1710 -0
  40. package/latticeai/brain/__init__.py +18 -0
  41. package/latticeai/brain/context.py +213 -0
  42. package/latticeai/brain/conversations.py +236 -0
  43. package/latticeai/brain/identity.py +175 -0
  44. package/latticeai/brain/memory.py +102 -0
  45. package/latticeai/brain/network.py +205 -0
  46. package/latticeai/core/agent.py +31 -7
  47. package/latticeai/core/audit.py +0 -7
  48. package/latticeai/core/config.py +1 -1
  49. package/latticeai/core/context_builder.py +1 -2
  50. package/latticeai/core/enterprise.py +1 -1
  51. package/latticeai/core/graph_curator.py +2 -2
  52. package/latticeai/core/marketplace.py +1 -1
  53. package/latticeai/core/mcp_registry.py +791 -0
  54. package/latticeai/core/model_compat.py +1 -1
  55. package/latticeai/core/model_resolution.py +0 -1
  56. package/latticeai/core/multi_agent.py +238 -4
  57. package/latticeai/core/security.py +1 -1
  58. package/latticeai/core/sessions.py +37 -7
  59. package/latticeai/core/workflow_engine.py +114 -2
  60. package/latticeai/core/workspace_os.py +58 -10
  61. package/latticeai/models/__init__.py +7 -0
  62. package/latticeai/models/router.py +779 -0
  63. package/latticeai/server_app.py +29 -1504
  64. package/latticeai/services/agent_runtime.py +1 -0
  65. package/latticeai/services/app_context.py +75 -14
  66. package/latticeai/services/ingestion.py +318 -0
  67. package/latticeai/services/kg_portability.py +207 -0
  68. package/latticeai/services/memory_service.py +39 -11
  69. package/latticeai/services/model_runtime.py +2 -5
  70. package/latticeai/services/platform_runtime.py +100 -23
  71. package/latticeai/services/search_service.py +17 -8
  72. package/latticeai/services/tool_dispatch.py +12 -2
  73. package/latticeai/services/triggers.py +241 -0
  74. package/latticeai/services/upload_service.py +37 -12
  75. package/latticeai/services/workspace_service.py +31 -0
  76. package/llm_router.py +29 -772
  77. package/ltcai_cli.py +1 -2
  78. package/mcp_registry.py +25 -788
  79. package/p_reinforce.py +124 -14
  80. package/package.json +11 -8
  81. package/scripts/build_vsix.mjs +72 -0
  82. package/scripts/bump_version.py +99 -0
  83. package/scripts/generate_diagrams.py +0 -1
  84. package/scripts/lint_v3.mjs +82 -18
  85. package/scripts/validate_release_artifacts.py +0 -1
  86. package/scripts/wheel_smoke.py +142 -0
  87. package/server.py +11 -7
  88. package/setup_wizard.py +1142 -0
  89. package/static/account.html +2 -4
  90. package/static/admin.html +3 -5
  91. package/static/chat.html +3 -6
  92. package/static/graph.html +2 -4
  93. package/static/sw.js +81 -52
  94. package/static/v3/asset-manifest.json +20 -19
  95. package/static/v3/css/{lattice.base.e4cdd05d.css → lattice.base.49deefb5.css} +1 -1
  96. package/static/v3/css/lattice.base.css +1 -1
  97. package/static/v3/css/{lattice.components.9b49d614.css → lattice.components.cde18231.css} +1 -1
  98. package/static/v3/css/lattice.components.css +1 -1
  99. package/static/v3/css/{lattice.shell.8fcc9d33.css → lattice.shell.29d36d85.css} +1 -1
  100. package/static/v3/css/lattice.shell.css +1 -1
  101. package/static/v3/css/{lattice.tokens.e7018963.css → lattice.tokens.304cbc40.css} +3 -0
  102. package/static/v3/css/lattice.tokens.css +3 -0
  103. package/static/v3/css/{lattice.views.22f69117.css → lattice.views.0a18b6c5.css} +2 -2
  104. package/static/v3/css/lattice.views.css +2 -2
  105. package/static/v3/index.html +3 -4
  106. package/static/v3/js/{app.d086489d.js → app.356e6452.js} +1 -1
  107. package/static/v3/js/core/{api.12b568ad.js → api.7a308b89.js} +39 -1
  108. package/static/v3/js/core/api.js +38 -0
  109. package/static/v3/js/core/{routes.d214b399.js → routes.7222343d.js} +22 -22
  110. package/static/v3/js/core/routes.js +22 -22
  111. package/static/v3/js/core/{shell.d05266f5.js → shell.a1657f20.js} +4 -4
  112. package/static/v3/js/core/shell.js +1 -1
  113. package/static/v3/js/core/{store.34ebd5e6.js → store.204a08b2.js} +1 -1
  114. package/static/v3/js/core/store.js +1 -1
  115. package/static/v3/js/views/graph-canvas.17c15d65.js +509 -0
  116. package/static/v3/js/views/graph-canvas.js +509 -0
  117. package/static/v3/js/views/{hybrid-search.b22b97e0.js → hybrid-search.2fb63ed9.js} +1 -2
  118. package/static/v3/js/views/hybrid-search.js +1 -2
  119. package/static/v3/js/views/knowledge-graph.5e40cbeb.js +509 -0
  120. package/static/v3/js/views/knowledge-graph.js +326 -54
  121. package/static/vendor/chart.umd.min.js +20 -0
  122. package/static/vendor/fonts/inter-latin-300-normal.woff2 +0 -0
  123. package/static/vendor/fonts/inter-latin-400-normal.woff2 +0 -0
  124. package/static/vendor/fonts/inter-latin-500-normal.woff2 +0 -0
  125. package/static/vendor/fonts/inter-latin-600-normal.woff2 +0 -0
  126. package/static/vendor/fonts/inter-latin-700-normal.woff2 +0 -0
  127. package/static/vendor/fonts/inter-latin-800-normal.woff2 +0 -0
  128. package/static/vendor/fonts/inter.css +44 -0
  129. package/static/vendor/icons/tabler-icons.min.css +4 -0
  130. package/static/vendor/icons/tabler-icons.woff2 +0 -0
  131. package/static/vendor/marked.min.js +69 -0
  132. package/static/workspace.html +2 -2
  133. package/telegram_bot.py +1 -2
  134. package/tools/commands.py +4 -2
  135. package/tools/computer.py +1 -1
  136. package/tools/documents.py +1 -3
  137. package/tools/filesystem.py +0 -4
  138. package/tools/knowledge.py +1 -3
  139. package/tools/network.py +1 -3
  140. package/codex_telegram_bot.py +0 -195
  141. package/docs/assets/v3.4.0/agent-run.png +0 -0
  142. package/docs/assets/v3.4.0/agents.png +0 -0
  143. package/docs/assets/v3.4.0/before/chat-before.png +0 -0
  144. package/docs/assets/v3.4.0/before/files-before.png +0 -0
  145. package/docs/assets/v3.4.0/chat.png +0 -0
  146. package/docs/assets/v3.4.0/connect-folder.png +0 -0
  147. package/docs/assets/v3.4.0/files.png +0 -0
  148. package/docs/assets/v3.4.0/home.png +0 -0
  149. package/docs/assets/v3.4.0/hooks-dispatch.png +0 -0
  150. package/docs/assets/v3.4.0/knowledge-graph.png +0 -0
  151. package/docs/assets/v3.4.0/local-agent.png +0 -0
  152. package/docs/assets/v3.4.0/memory.png +0 -0
  153. package/docs/assets/v3.4.0/settings.png +0 -0
  154. package/docs/assets/v3.4.0/vision-input.png +0 -0
  155. package/docs/assets/v3.4.0/workflows.png +0 -0
  156. package/docs/assets/v3.4.1/e2e_runtime_log.txt +0 -42
  157. package/docs/assets/v3.4.1/hooks-dispatch.png +0 -0
  158. package/docs/assets/v3.4.1/local-agent.png +0 -0
  159. package/docs/images/admin-dashboard.png +0 -0
  160. package/docs/images/architecture.png +0 -0
  161. package/docs/images/enterprise.png +0 -0
  162. package/docs/images/graph.png +0 -0
  163. package/docs/images/hero.gif +0 -0
  164. package/docs/images/knowledge-graph.png +0 -0
  165. package/docs/images/lattice-ai-demo.gif +0 -0
  166. package/docs/images/lattice-ai-hero.png +0 -0
  167. package/docs/images/logo.svg +0 -33
  168. package/docs/images/mobile-responsive.png +0 -0
  169. package/docs/images/model-recommendation.png +0 -0
  170. package/docs/images/onboarding.png +0 -0
  171. package/docs/images/organization.png +0 -0
  172. package/docs/images/pipeline.png +0 -0
  173. package/docs/images/screenshot-admin.png +0 -0
  174. package/docs/images/screenshot-chat.png +0 -0
  175. package/docs/images/screenshot-graph.png +0 -0
  176. package/docs/images/skills.png +0 -0
  177. package/docs/images/workspace-dark.png +0 -0
  178. package/docs/images/workspace-light.png +0 -0
  179. package/docs/images/workspace.png +0 -0
  180. package/requirements.txt +0 -16
  181. package/static/v3/js/views/knowledge-graph.a14ea7e7.js +0 -237
@@ -10,10 +10,8 @@
10
10
  <meta name="apple-mobile-web-app-capable" content="yes">
11
11
  <link rel="apple-touch-icon" href="/icons/apple-touch-icon.png">
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png">
13
- <link rel="preconnect" href="https://fonts.googleapis.com">
14
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
15
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap">
16
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
13
+ <link rel="stylesheet" href="/static/vendor/fonts/inter.css">
14
+ <link rel="stylesheet" href="/static/vendor/icons/tabler-icons.min.css">
17
15
  <link rel="stylesheet" href="/static/css/tokens.css">
18
16
  <link rel="stylesheet" href="/static/css/reference/base.css">
19
17
  <link rel="stylesheet" href="/static/css/reference/account.css">
package/static/admin.html CHANGED
@@ -11,10 +11,8 @@
11
11
  <meta name="apple-mobile-web-app-capable" content="yes">
12
12
  <link rel="apple-touch-icon" href="/icons/apple-touch-icon.png">
13
13
  <link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png">
14
- <link rel="preconnect" href="https://fonts.googleapis.com">
15
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
16
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap">
17
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
14
+ <link rel="stylesheet" href="/static/vendor/fonts/inter.css">
15
+ <link rel="stylesheet" href="/static/vendor/icons/tabler-icons.min.css">
18
16
  <link rel="stylesheet" href="/static/css/tokens.css">
19
17
  <link rel="stylesheet" href="/static/css/reference/base.css">
20
18
  <link rel="stylesheet" href="/static/css/reference/account.css">
@@ -22,7 +20,7 @@
22
20
  <link rel="stylesheet" href="/static/css/reference/graph.css">
23
21
  <link rel="stylesheet" href="/static/css/reference/chat.css">
24
22
  <link rel="stylesheet" href="/static/css/responsive.css">
25
- <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
23
+ <script src="/static/vendor/chart.umd.min.js"></script>
26
24
  </head>
27
25
 
28
26
  <body class="lattice-ref-admin">
package/static/chat.html CHANGED
@@ -16,12 +16,9 @@
16
16
  <meta name="apple-mobile-web-app-title" content="LatticeAI">
17
17
  <link rel="apple-touch-icon" href="/icons/apple-touch-icon.png">
18
18
  <link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png">
19
-
20
- <link rel="preconnect" href="https://fonts.googleapis.com">
21
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
22
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap">
23
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
24
- <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
19
+ <link rel="stylesheet" href="/static/vendor/fonts/inter.css">
20
+ <link rel="stylesheet" href="/static/vendor/icons/tabler-icons.min.css">
21
+ <script src="/static/vendor/marked.min.js"></script>
25
22
 
26
23
  <!-- ── Setup Wizard Styles ──────────────────────────────────────────── -->
27
24
  <link rel="stylesheet" href="/static/css/tokens.css">
package/static/graph.html CHANGED
@@ -5,10 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content">
6
6
  <title>Lattice AI - 지식 그래프</title>
7
7
  <script src="/static/scripts/ux.js"></script>
8
- <link rel="preconnect" href="https://fonts.googleapis.com">
9
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap">
11
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
8
+ <link rel="stylesheet" href="/static/vendor/fonts/inter.css">
9
+ <link rel="stylesheet" href="/static/vendor/icons/tabler-icons.min.css">
12
10
  <link rel="stylesheet" href="/static/css/tokens.css">
13
11
  <link rel="stylesheet" href="/static/css/reference/base.css">
14
12
  <link rel="stylesheet" href="/static/css/reference/account.css">
package/static/sw.js CHANGED
@@ -1,71 +1,100 @@
1
- // Lattice AI Service Worker — enables PWA install on Android/iOS
2
- // Strategy: network-first for API, cache-first for static assets.
3
- const CACHE = "ltcai-v310";
4
- const STATIC = [
5
- "/",
1
+ // Lattice Service Worker — PWA install + offline shell for the /app SPA.
2
+ // Strategy: precache the v3 bundle from its asset manifest (hashed files),
3
+ // cache-first for static assets, network-only for everything dynamic.
4
+ const CACHE = "lattice-v4";
5
+ const MANIFEST_URL = "/static/v3/asset-manifest.json";
6
+
7
+ // Non-manifest assets the shell needs offline.
8
+ const SHELL = [
6
9
  "/app",
7
- "/workspace",
8
- "/static/v3/asset-manifest.json",
9
- "/static/css/tokens.css",
10
- "/static/css/reference/base.css",
11
- "/static/css/reference/chat.css",
12
- "/static/css/responsive.css",
13
- "/static/workspace.css",
14
- "/static/scripts/chat.js",
15
- "/static/scripts/admin.js",
16
- "/static/scripts/graph.js",
17
- "/static/scripts/workspace.js",
18
- "/static/scripts/account.js",
10
+ MANIFEST_URL,
19
11
  "/manifest.json",
20
12
  "/icons/icon-192.png",
21
13
  "/icons/icon-512.png",
22
14
  "/icons/apple-touch-icon.png",
15
+ "/static/vendor/fonts/inter.css",
16
+ "/static/vendor/fonts/inter-latin-400-normal.woff2",
17
+ "/static/vendor/fonts/inter-latin-500-normal.woff2",
18
+ "/static/vendor/fonts/inter-latin-600-normal.woff2",
19
+ "/static/vendor/fonts/inter-latin-700-normal.woff2",
20
+ "/static/vendor/fonts/inter-latin-800-normal.woff2",
21
+ "/static/vendor/icons/tabler-icons.min.css",
22
+ "/static/vendor/icons/tabler-icons.woff2",
23
23
  ];
24
24
 
25
- self.addEventListener("install", e => {
26
- e.waitUntil(
27
- caches.open(CACHE).then(c => c.addAll(STATIC)).then(() => self.skipWaiting())
28
- );
25
+ async function precache() {
26
+ const cache = await caches.open(CACHE);
27
+ let manifestPaths = [];
28
+ try {
29
+ const res = await fetch(MANIFEST_URL, { cache: "no-cache" });
30
+ const manifest = await res.json();
31
+ const entry = manifest.entrypoints || {};
32
+ manifestPaths = [entry.app, ...(entry.styles || []), ...Object.values(manifest.assets || {})]
33
+ .filter(Boolean);
34
+ } catch (err) {
35
+ // Offline install: shell precache below still applies.
36
+ }
37
+ const unique = [...new Set([...SHELL, ...manifestPaths])];
38
+ await Promise.all(unique.map(async (path) => {
39
+ try {
40
+ const res = await fetch(path, { cache: "no-cache" });
41
+ if (res.ok) await cache.put(path, res);
42
+ } catch (err) {
43
+ // Missing one asset must not abort install; it just isn't offline-ready.
44
+ }
45
+ }));
46
+ }
47
+
48
+ self.addEventListener("install", (e) => {
49
+ e.waitUntil(precache().then(() => self.skipWaiting()));
29
50
  });
30
51
 
31
- self.addEventListener("activate", e => {
52
+ self.addEventListener("activate", (e) => {
32
53
  e.waitUntil(
33
- caches.keys().then(keys =>
34
- Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k)))
35
- ).then(() => clients.claim())
54
+ caches.keys()
55
+ .then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))))
56
+ .then(() => clients.claim())
36
57
  );
37
58
  });
38
59
 
39
- self.addEventListener("fetch", e => {
60
+ self.addEventListener("fetch", (e) => {
40
61
  const url = new URL(e.request.url);
62
+ if (e.request.method !== "GET" || url.origin !== self.location.origin) return;
41
63
 
42
- // API calls → always network (never cache)
43
- if (url.pathname.startsWith("/chat") ||
44
- url.pathname.startsWith("/agent") ||
45
- url.pathname.startsWith("/models") ||
46
- url.pathname.startsWith("/admin/") ||
47
- url.pathname.startsWith("/auth/") ||
48
- url.pathname.startsWith("/account/") ||
49
- url.pathname.startsWith("/vpc/") ||
50
- url.pathname.startsWith("/health") ||
51
- url.pathname.startsWith("/runtime_features") ||
52
- url.pathname.startsWith("/local") ||
53
- url.pathname.startsWith("/tools") ||
54
- url.pathname.startsWith("/knowledge") ||
55
- url.pathname.startsWith("/workspace/") ||
56
- url.pathname.startsWith("/history")) {
57
- e.respondWith(fetch(e.request));
64
+ const isStatic =
65
+ url.pathname.startsWith("/static/") ||
66
+ url.pathname.startsWith("/icons/") ||
67
+ url.pathname === "/manifest.json";
68
+
69
+ if (isStatic) {
70
+ // Hashed filenames make cache-first safe; unhashed files revalidate.
71
+ e.respondWith(
72
+ caches.match(e.request).then((hit) =>
73
+ hit ||
74
+ fetch(e.request).then((res) => {
75
+ const clone = res.clone();
76
+ if (res.ok) caches.open(CACHE).then((c) => c.put(e.request, clone));
77
+ return res;
78
+ })
79
+ )
80
+ );
58
81
  return;
59
82
  }
60
83
 
61
- // Static HTML network-first, fall back to cache
62
- e.respondWith(
63
- fetch(e.request)
64
- .then(res => {
65
- const clone = res.clone();
66
- caches.open(CACHE).then(c => c.put(e.request, clone));
67
- return res;
68
- })
69
- .catch(() => caches.match(e.request))
70
- );
84
+ if (url.pathname === "/app" || url.pathname.startsWith("/app/")) {
85
+ // SPA shell: network-first so updates land, cache fallback for offline.
86
+ e.respondWith(
87
+ fetch(e.request)
88
+ .then((res) => {
89
+ const clone = res.clone();
90
+ if (res.ok) caches.open(CACHE).then((c) => c.put("/app", clone));
91
+ return res;
92
+ })
93
+ .catch(() => caches.match("/app"))
94
+ );
95
+ return;
96
+ }
97
+
98
+ // Everything else (APIs, auth, realtime) is dynamic: network only —
99
+ // serving stale API responses would fabricate state.
71
100
  });
@@ -1,32 +1,32 @@
1
1
  {
2
- "version": "3.5.0",
2
+ "version": "4.0.0",
3
3
  "generated_at": "deterministic",
4
4
  "entrypoints": {
5
- "app": "/static/v3/js/app.d086489d.js",
5
+ "app": "/static/v3/js/app.356e6452.js",
6
6
  "styles": [
7
7
  "/static/css/tokens.3ba22e37.css",
8
- "/static/v3/css/lattice.tokens.e7018963.css",
9
- "/static/v3/css/lattice.base.e4cdd05d.css",
10
- "/static/v3/css/lattice.components.9b49d614.css",
11
- "/static/v3/css/lattice.shell.8fcc9d33.css",
12
- "/static/v3/css/lattice.views.22f69117.css"
8
+ "/static/v3/css/lattice.tokens.304cbc40.css",
9
+ "/static/v3/css/lattice.base.49deefb5.css",
10
+ "/static/v3/css/lattice.components.cde18231.css",
11
+ "/static/v3/css/lattice.shell.29d36d85.css",
12
+ "/static/v3/css/lattice.views.0a18b6c5.css"
13
13
  ]
14
14
  },
15
15
  "assets": {
16
16
  "static/css/tokens.css": "/static/css/tokens.3ba22e37.css",
17
- "static/v3/css/lattice.tokens.css": "/static/v3/css/lattice.tokens.e7018963.css",
18
- "static/v3/css/lattice.base.css": "/static/v3/css/lattice.base.e4cdd05d.css",
19
- "static/v3/css/lattice.components.css": "/static/v3/css/lattice.components.9b49d614.css",
20
- "static/v3/css/lattice.shell.css": "/static/v3/css/lattice.shell.8fcc9d33.css",
21
- "static/v3/css/lattice.views.css": "/static/v3/css/lattice.views.22f69117.css",
22
- "static/v3/js/app.js": "/static/v3/js/app.d086489d.js",
23
- "static/v3/js/core/api.js": "/static/v3/js/core/api.12b568ad.js",
17
+ "static/v3/css/lattice.tokens.css": "/static/v3/css/lattice.tokens.304cbc40.css",
18
+ "static/v3/css/lattice.base.css": "/static/v3/css/lattice.base.49deefb5.css",
19
+ "static/v3/css/lattice.components.css": "/static/v3/css/lattice.components.cde18231.css",
20
+ "static/v3/css/lattice.shell.css": "/static/v3/css/lattice.shell.29d36d85.css",
21
+ "static/v3/css/lattice.views.css": "/static/v3/css/lattice.views.0a18b6c5.css",
22
+ "static/v3/js/app.js": "/static/v3/js/app.356e6452.js",
23
+ "static/v3/js/core/api.js": "/static/v3/js/core/api.7a308b89.js",
24
24
  "static/v3/js/core/components.js": "/static/v3/js/core/components.f25b3b93.js",
25
25
  "static/v3/js/core/dom.js": "/static/v3/js/core/dom.a2773eb0.js",
26
26
  "static/v3/js/core/router.js": "/static/v3/js/core/router.584570f2.js",
27
- "static/v3/js/core/routes.js": "/static/v3/js/core/routes.d214b399.js",
28
- "static/v3/js/core/shell.js": "/static/v3/js/core/shell.d05266f5.js",
29
- "static/v3/js/core/store.js": "/static/v3/js/core/store.34ebd5e6.js",
27
+ "static/v3/js/core/routes.js": "/static/v3/js/core/routes.7222343d.js",
28
+ "static/v3/js/core/shell.js": "/static/v3/js/core/shell.a1657f20.js",
29
+ "static/v3/js/core/store.js": "/static/v3/js/core/store.204a08b2.js",
30
30
  "static/v3/js/views/admin-audit.js": "/static/v3/js/views/admin-audit.660a1fb1.js",
31
31
  "static/v3/js/views/admin-permissions.js": "/static/v3/js/views/admin-permissions.a7ae5f09.js",
32
32
  "static/v3/js/views/admin-policies.js": "/static/v3/js/views/admin-policies.3658fd86.js",
@@ -36,10 +36,11 @@
36
36
  "static/v3/js/views/agents.js": "/static/v3/js/views/agents.014d0b74.js",
37
37
  "static/v3/js/views/chat.js": "/static/v3/js/views/chat.e6dd7dd0.js",
38
38
  "static/v3/js/views/files.js": "/static/v3/js/views/files.adad14c1.js",
39
+ "static/v3/js/views/graph-canvas.js": "/static/v3/js/views/graph-canvas.17c15d65.js",
39
40
  "static/v3/js/views/home.js": "/static/v3/js/views/home.24f8b8ae.js",
40
41
  "static/v3/js/views/hooks.js": "/static/v3/js/views/hooks.37895880.js",
41
- "static/v3/js/views/hybrid-search.js": "/static/v3/js/views/hybrid-search.b22b97e0.js",
42
- "static/v3/js/views/knowledge-graph.js": "/static/v3/js/views/knowledge-graph.a14ea7e7.js",
42
+ "static/v3/js/views/hybrid-search.js": "/static/v3/js/views/hybrid-search.2fb63ed9.js",
43
+ "static/v3/js/views/knowledge-graph.js": "/static/v3/js/views/knowledge-graph.5e40cbeb.js",
43
44
  "static/v3/js/views/marketplace.js": "/static/v3/js/views/marketplace.ab0583d4.js",
44
45
  "static/v3/js/views/mcp.js": "/static/v3/js/views/mcp.99b5c6a7.js",
45
46
  "static/v3/js/views/memory.js": "/static/v3/js/views/memory.4ebdf474.js",
@@ -111,7 +111,7 @@ code, pre, kbd, samp { font-family: var(--lt3-font-mono); }
111
111
  z-index: var(--lt3-z-toast);
112
112
  padding: var(--lt3-space-2) var(--lt3-space-4);
113
113
  background: var(--accent);
114
- color: #fff;
114
+ color: var(--lt3-on-accent);
115
115
  border-radius: var(--lt3-radius-sm);
116
116
  transform: translateY(-200%);
117
117
  transition: transform var(--lt3-dur-2) var(--lt3-ease);
@@ -111,7 +111,7 @@ code, pre, kbd, samp { font-family: var(--lt3-font-mono); }
111
111
  z-index: var(--lt3-z-toast);
112
112
  padding: var(--lt3-space-2) var(--lt3-space-4);
113
113
  background: var(--accent);
114
- color: #fff;
114
+ color: var(--lt3-on-accent);
115
115
  border-radius: var(--lt3-radius-sm);
116
116
  transform: translateY(-200%);
117
117
  transition: transform var(--lt3-dur-2) var(--lt3-ease);
@@ -87,7 +87,7 @@
87
87
  .lt3-btn[disabled] { opacity: 0.5; pointer-events: none; }
88
88
  .lt3-btn .ti { font-size: 1.05rem; }
89
89
 
90
- .lt3-btn--primary { background: var(--accent); color: #fff; box-shadow: var(--lt3-elev-1); }
90
+ .lt3-btn--primary { background: var(--accent); color: var(--lt3-on-accent); box-shadow: var(--lt3-elev-1); }
91
91
  .lt3-btn--primary:hover { background: var(--accent-deep); }
92
92
  .lt3-btn--ghost { background: var(--surface-2); border-color: var(--border); color: var(--text); }
93
93
  .lt3-btn--ghost:hover { border-color: var(--border-strong); background: var(--surface-3); }
@@ -87,7 +87,7 @@
87
87
  .lt3-btn[disabled] { opacity: 0.5; pointer-events: none; }
88
88
  .lt3-btn .ti { font-size: 1.05rem; }
89
89
 
90
- .lt3-btn--primary { background: var(--accent); color: #fff; box-shadow: var(--lt3-elev-1); }
90
+ .lt3-btn--primary { background: var(--accent); color: var(--lt3-on-accent); box-shadow: var(--lt3-elev-1); }
91
91
  .lt3-btn--primary:hover { background: var(--accent-deep); }
92
92
  .lt3-btn--ghost { background: var(--surface-2); border-color: var(--border); color: var(--text); }
93
93
  .lt3-btn--ghost:hover { border-color: var(--border-strong); background: var(--surface-3); }
@@ -36,7 +36,7 @@
36
36
  width: 34px; height: 34px; flex: none;
37
37
  border-radius: var(--lt3-radius-md);
38
38
  background: var(--text);
39
- color: #fff;
39
+ color: var(--lt3-on-accent);
40
40
  box-shadow: var(--lt3-elev-1);
41
41
  }
42
42
  .lt3-rail__logo svg { width: 22px; height: 22px; }
@@ -36,7 +36,7 @@
36
36
  width: 34px; height: 34px; flex: none;
37
37
  border-radius: var(--lt3-radius-md);
38
38
  background: var(--text);
39
- color: #fff;
39
+ color: var(--lt3-on-accent);
40
40
  box-shadow: var(--lt3-elev-1);
41
41
  }
42
42
  .lt3-rail__logo svg { width: 22px; height: 22px; }
@@ -98,6 +98,9 @@
98
98
  --lt3-pillar-graph: var(--accent); /* blue — relational structure */
99
99
  --lt3-pillar-vector: var(--accent-2); /* teal — embeddings field */
100
100
  --lt3-pillar-hybrid: var(--accent-pink); /* magenta — fusion of both */
101
+
102
+ /* Text rendered on saturated accent fills (both themes keep accents dark-safe). */
103
+ --lt3-on-accent: #ffffff;
101
104
  --lt3-pillar-graph-soft: color-mix(in srgb, var(--lt3-pillar-graph) 14%, transparent);
102
105
  --lt3-pillar-vector-soft: color-mix(in srgb, var(--lt3-pillar-vector) 16%, transparent);
103
106
  --lt3-pillar-hybrid-soft: color-mix(in srgb, var(--lt3-pillar-hybrid) 16%, transparent);
@@ -98,6 +98,9 @@
98
98
  --lt3-pillar-graph: var(--accent); /* blue — relational structure */
99
99
  --lt3-pillar-vector: var(--accent-2); /* teal — embeddings field */
100
100
  --lt3-pillar-hybrid: var(--accent-pink); /* magenta — fusion of both */
101
+
102
+ /* Text rendered on saturated accent fills (both themes keep accents dark-safe). */
103
+ --lt3-on-accent: #ffffff;
101
104
  --lt3-pillar-graph-soft: color-mix(in srgb, var(--lt3-pillar-graph) 14%, transparent);
102
105
  --lt3-pillar-vector-soft: color-mix(in srgb, var(--lt3-pillar-vector) 16%, transparent);
103
106
  --lt3-pillar-hybrid-soft: color-mix(in srgb, var(--lt3-pillar-hybrid) 16%, transparent);
@@ -222,12 +222,12 @@
222
222
  .lt3-msg--user { align-self: flex-end; flex-direction: row-reverse; max-width: 90%; }
223
223
  .lt3-msg--ai { align-self: flex-start; max-width: 100%; }
224
224
  .lt3-msg__avatar { width: 32px; height: 32px; flex: none; border-radius: var(--lt3-radius-sm); display: grid; place-items: center; }
225
- .lt3-msg--ai .lt3-msg__avatar { background: linear-gradient(135deg, var(--lt3-pillar-graph), var(--lt3-pillar-vector)); color: #fff; }
225
+ .lt3-msg--ai .lt3-msg__avatar { background: linear-gradient(135deg, var(--lt3-pillar-graph), var(--lt3-pillar-vector)); color: var(--lt3-on-accent); }
226
226
  .lt3-msg--user .lt3-msg__avatar { background: var(--surface-3); color: var(--muted); }
227
227
  .lt3-msg__body { min-width: 0; display: flex; flex-direction: column; gap: var(--lt3-space-2); }
228
228
  .lt3-msg__bubble { padding: var(--lt3-space-3) var(--lt3-space-4); border-radius: var(--lt3-radius-md); font-size: var(--lt3-text-md); line-height: var(--lt3-leading-normal); white-space: pre-wrap; overflow-wrap: anywhere; }
229
229
  .lt3-msg--ai .lt3-msg__bubble { background: var(--surface); border: 1px solid var(--border); }
230
- .lt3-msg--user .lt3-msg__bubble { background: var(--accent); color: #fff; }
230
+ .lt3-msg--user .lt3-msg__bubble { background: var(--accent); color: var(--lt3-on-accent); }
231
231
  .lt3-msg__cites { display: flex; flex-wrap: wrap; gap: var(--lt3-space-2); }
232
232
  .lt3-typing { display: inline-flex; gap: 4px; align-items: center; padding: var(--lt3-space-1) 0; }
233
233
  .lt3-typing i { width: 6px; height: 6px; border-radius: 99px; background: var(--faint); animation: lt3-bounce 1s var(--lt3-ease) infinite; }
@@ -222,12 +222,12 @@
222
222
  .lt3-msg--user { align-self: flex-end; flex-direction: row-reverse; max-width: 90%; }
223
223
  .lt3-msg--ai { align-self: flex-start; max-width: 100%; }
224
224
  .lt3-msg__avatar { width: 32px; height: 32px; flex: none; border-radius: var(--lt3-radius-sm); display: grid; place-items: center; }
225
- .lt3-msg--ai .lt3-msg__avatar { background: linear-gradient(135deg, var(--lt3-pillar-graph), var(--lt3-pillar-vector)); color: #fff; }
225
+ .lt3-msg--ai .lt3-msg__avatar { background: linear-gradient(135deg, var(--lt3-pillar-graph), var(--lt3-pillar-vector)); color: var(--lt3-on-accent); }
226
226
  .lt3-msg--user .lt3-msg__avatar { background: var(--surface-3); color: var(--muted); }
227
227
  .lt3-msg__body { min-width: 0; display: flex; flex-direction: column; gap: var(--lt3-space-2); }
228
228
  .lt3-msg__bubble { padding: var(--lt3-space-3) var(--lt3-space-4); border-radius: var(--lt3-radius-md); font-size: var(--lt3-text-md); line-height: var(--lt3-leading-normal); white-space: pre-wrap; overflow-wrap: anywhere; }
229
229
  .lt3-msg--ai .lt3-msg__bubble { background: var(--surface); border: 1px solid var(--border); }
230
- .lt3-msg--user .lt3-msg__bubble { background: var(--accent); color: #fff; }
230
+ .lt3-msg--user .lt3-msg__bubble { background: var(--accent); color: var(--lt3-on-accent); }
231
231
  .lt3-msg__cites { display: flex; flex-wrap: wrap; gap: var(--lt3-space-2); }
232
232
  .lt3-typing { display: inline-flex; gap: 4px; align-items: center; padding: var(--lt3-space-1) 0; }
233
233
  .lt3-typing i { width: 6px; height: 6px; border-radius: 99px; background: var(--faint); animation: lt3-bounce 1s var(--lt3-ease) infinite; }
@@ -18,10 +18,9 @@
18
18
 
19
19
  <link rel="manifest" href="/manifest.json">
20
20
  <link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png">
21
- <link rel="preconnect" href="https://fonts.googleapis.com">
22
- <link rel="preconnect" href="https://cdn.jsdelivr.net">
23
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap">
24
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
21
+ <!-- Fonts and icons are vendored locally: no CDN calls from shipped pages. -->
22
+ <link rel="stylesheet" href="/static/vendor/fonts/inter.css">
23
+ <link rel="stylesheet" href="/static/vendor/icons/tabler-icons.min.css">
25
24
 
26
25
  <script>
27
26
  window.__LT_ASSET_SOURCES__ = {
@@ -3,7 +3,7 @@
3
3
  * Boots the shell. Views are lazy-loaded by the router (see core/routes.js).
4
4
  * ========================================================================== */
5
5
 
6
- import { boot } from "./core/shell.d05266f5.js";
6
+ import { boot } from "./core/shell.a1657f20.js";
7
7
 
8
8
  const root = document.getElementById("app");
9
9
  if (root) boot(root);
@@ -11,7 +11,7 @@
11
11
  * "unavailable" → endpoint missing/down; no fake payload
12
12
  * ========================================================================== */
13
13
 
14
- import { store } from "./store.34ebd5e6.js";
14
+ import { store } from "./store.204a08b2.js";
15
15
 
16
16
  const TIMEOUT_MS = 8000;
17
17
  const EMPTY_INDEX_STATUS = { generated_at: null, pipelines: {}, sources: [] };
@@ -507,6 +507,44 @@ export const api = {
507
507
  // Hooks dispatch (real backend: POST /api/hooks/run + GET /api/hooks/runs)
508
508
  hookRun(body) { return raw("/api/hooks/run", { method: "POST", body }); },
509
509
  hookRuns(limit = 50, kind) { return withFallback(`/api/hooks/runs?limit=${encodeURIComponent(limit)}${kind ? "&kind=" + encodeURIComponent(kind) : ""}`, {}, { runs: [], total: 0 }); },
510
+
511
+ /* ── v3.6 Knowledge Graph First: ingestion provenance + portability ─────
512
+ * The graph is the durable asset; these surface its health, where every node
513
+ * came from, and local export/import/backup. All fallback-safe; never fake. */
514
+
515
+ /** GET /api/knowledge-graph/portability — schema versions + stats + provenance counts. */
516
+ async kgPortability() {
517
+ const res = await raw("/api/knowledge-graph/portability");
518
+ if (res.ok && res.data && res.data.available) {
519
+ return { ok: true, status: res.status, data: res.data, source: "live" };
520
+ }
521
+ return {
522
+ ok: false, status: res.status, source: "unavailable",
523
+ data: { available: false, graph_schema_version: null, embed_dim: null,
524
+ stats: { nodes: {}, edges: {} },
525
+ provenance: { total: 0, by_source_type: {}, embedded: 0, duplicates: 0, last_ingested_at: null } },
526
+ };
527
+ },
528
+
529
+ /** GET /api/knowledge-graph/provenance — recent ingestions (newest first). */
530
+ kgProvenance(limit = 50, sourceType) {
531
+ const qs = `?limit=${encodeURIComponent(limit)}${sourceType ? "&source_type=" + encodeURIComponent(sourceType) : ""}`;
532
+ return withFallback(`/api/knowledge-graph/provenance${qs}`, {}, { items: [], count: 0 });
533
+ },
534
+
535
+ /** POST /api/knowledge-graph/export — logical JSON export of the whole graph. */
536
+ graphExport() { return raw("/api/knowledge-graph/export", { method: "POST", body: {} }); },
537
+
538
+ /** POST /api/knowledge-graph/import — import an export artifact (merge|replace). */
539
+ graphImport(artifact, mode = "merge", dryRun = false) {
540
+ return raw("/api/knowledge-graph/import", { method: "POST", body: { artifact, mode, dry_run: dryRun } });
541
+ },
542
+
543
+ /** POST /api/knowledge-graph/backup — binary backup (sqlite + blobs) to a local zip. */
544
+ graphBackup() { return raw("/api/knowledge-graph/backup", { method: "POST", body: {} }); },
545
+
546
+ /** POST /api/browser/read-url — fetch a public URL locally into the graph. */
547
+ browserReadUrl(url) { return raw("/api/browser/read-url", { method: "POST", body: { url } }); },
510
548
  };
511
549
 
512
550
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -507,6 +507,44 @@ export const api = {
507
507
  // Hooks dispatch (real backend: POST /api/hooks/run + GET /api/hooks/runs)
508
508
  hookRun(body) { return raw("/api/hooks/run", { method: "POST", body }); },
509
509
  hookRuns(limit = 50, kind) { return withFallback(`/api/hooks/runs?limit=${encodeURIComponent(limit)}${kind ? "&kind=" + encodeURIComponent(kind) : ""}`, {}, { runs: [], total: 0 }); },
510
+
511
+ /* ── v3.6 Knowledge Graph First: ingestion provenance + portability ─────
512
+ * The graph is the durable asset; these surface its health, where every node
513
+ * came from, and local export/import/backup. All fallback-safe; never fake. */
514
+
515
+ /** GET /api/knowledge-graph/portability — schema versions + stats + provenance counts. */
516
+ async kgPortability() {
517
+ const res = await raw("/api/knowledge-graph/portability");
518
+ if (res.ok && res.data && res.data.available) {
519
+ return { ok: true, status: res.status, data: res.data, source: "live" };
520
+ }
521
+ return {
522
+ ok: false, status: res.status, source: "unavailable",
523
+ data: { available: false, graph_schema_version: null, embed_dim: null,
524
+ stats: { nodes: {}, edges: {} },
525
+ provenance: { total: 0, by_source_type: {}, embedded: 0, duplicates: 0, last_ingested_at: null } },
526
+ };
527
+ },
528
+
529
+ /** GET /api/knowledge-graph/provenance — recent ingestions (newest first). */
530
+ kgProvenance(limit = 50, sourceType) {
531
+ const qs = `?limit=${encodeURIComponent(limit)}${sourceType ? "&source_type=" + encodeURIComponent(sourceType) : ""}`;
532
+ return withFallback(`/api/knowledge-graph/provenance${qs}`, {}, { items: [], count: 0 });
533
+ },
534
+
535
+ /** POST /api/knowledge-graph/export — logical JSON export of the whole graph. */
536
+ graphExport() { return raw("/api/knowledge-graph/export", { method: "POST", body: {} }); },
537
+
538
+ /** POST /api/knowledge-graph/import — import an export artifact (merge|replace). */
539
+ graphImport(artifact, mode = "merge", dryRun = false) {
540
+ return raw("/api/knowledge-graph/import", { method: "POST", body: { artifact, mode, dry_run: dryRun } });
541
+ },
542
+
543
+ /** POST /api/knowledge-graph/backup — binary backup (sqlite + blobs) to a local zip. */
544
+ graphBackup() { return raw("/api/knowledge-graph/backup", { method: "POST", body: {} }); },
545
+
546
+ /** POST /api/browser/read-url — fetch a public URL locally into the graph. */
547
+ browserReadUrl(url) { return raw("/api/browser/read-url", { method: "POST", body: { url } }); },
510
548
  };
511
549
 
512
550
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));