ltcai 8.0.0 → 8.2.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 (183) hide show
  1. package/README.md +33 -72
  2. package/docs/CHANGELOG.md +52 -874
  3. package/docs/DEVELOPMENT.md +26 -3
  4. package/docs/LEGACY_COMPATIBILITY.md +3 -1
  5. package/docs/TRUST_MODEL.md +26 -26
  6. package/docs/WHY_LATTICE.md +28 -25
  7. package/docs/kg-schema.md +6 -4
  8. package/lattice_brain/__init__.py +1 -1
  9. package/lattice_brain/embeddings.py +9 -1
  10. package/lattice_brain/graph/schema.py +6 -0
  11. package/lattice_brain/runtime/multi_agent.py +1 -1
  12. package/latticeai/__init__.py +1 -1
  13. package/latticeai/api/computer_use.py +2 -0
  14. package/latticeai/api/memory.py +13 -0
  15. package/latticeai/app_factory.py +43 -162
  16. package/latticeai/brain/__init__.py +1 -1
  17. package/latticeai/core/config.py +10 -0
  18. package/latticeai/core/local_embeddings.py +8 -0
  19. package/latticeai/core/marketplace.py +1 -1
  20. package/latticeai/core/mcp_registry.py +140 -1
  21. package/latticeai/core/tool_registry.py +10 -0
  22. package/latticeai/core/workspace_graph_trace.py +132 -0
  23. package/latticeai/core/workspace_memory.py +75 -0
  24. package/latticeai/core/workspace_os.py +135 -1283
  25. package/latticeai/core/workspace_os_utils.py +132 -0
  26. package/latticeai/core/workspace_permissions.py +99 -0
  27. package/latticeai/core/workspace_plugins.py +97 -0
  28. package/latticeai/core/workspace_runs.py +612 -0
  29. package/latticeai/core/workspace_skills.py +114 -0
  30. package/latticeai/core/workspace_snapshots.py +195 -0
  31. package/latticeai/core/workspace_timeline.py +107 -0
  32. package/latticeai/runtime/audit_runtime.py +64 -0
  33. package/latticeai/runtime/config_runtime.py +4 -0
  34. package/latticeai/runtime/sso_runtime.py +52 -0
  35. package/latticeai/services/architecture_readiness.py +6 -5
  36. package/latticeai/services/memory_service.py +215 -7
  37. package/latticeai/services/model_capability_registry.py +68 -0
  38. package/latticeai/services/model_engines.py +603 -0
  39. package/latticeai/services/model_loading.py +482 -0
  40. package/latticeai/services/model_recommendation.py +5 -0
  41. package/latticeai/services/model_runtime.py +146 -837
  42. package/latticeai/services/product_readiness.py +19 -18
  43. package/package.json +2 -2
  44. package/scripts/build_frontend_assets.mjs +11 -2
  45. package/src-tauri/Cargo.lock +1 -1
  46. package/src-tauri/Cargo.toml +1 -1
  47. package/src-tauri/tauri.conf.json +1 -1
  48. package/static/app/asset-manifest.json +11 -102
  49. package/static/app/assets/Act-D9jIknFd.js +1 -0
  50. package/static/app/assets/Brain-CFOtWbPN.js +321 -0
  51. package/static/app/assets/{Capture-B9Tlhzqr.js → Capture-Q4WYzwr5.js} +1 -2
  52. package/static/app/assets/Library-C5Q2yWee.js +1 -0
  53. package/static/app/assets/System-BLbjdr1_.js +1 -0
  54. package/static/app/assets/core-CwxXejkd.js +1 -2
  55. package/static/app/assets/index-BqammyNu.js +16 -0
  56. package/static/app/assets/index-ty1iGgZu.css +2 -0
  57. package/static/app/assets/primitives-Br8uSfZ4.js +1 -0
  58. package/static/app/assets/{textarea-BZk6ybp5.js → textarea-BnhNs1_X.js} +1 -2
  59. package/static/app/index.html +3 -10
  60. package/static/app/theme-boot.js +8 -0
  61. package/static/sw.js +1 -1
  62. package/tools/__init__.py +2 -1
  63. package/tools/computer.py +21 -0
  64. package/docs/CARRYOVER_AUDIT_v3.6.0.md +0 -61
  65. package/docs/HANDOVER_v3.6.0.md +0 -46
  66. package/docs/RUNTIME_HOOK_COVERAGE_v3.5.0.md +0 -56
  67. package/docs/RUNTIME_HOOK_COVERAGE_v3.6.0.md +0 -49
  68. package/docs/V2_ARCHITECTURE.md +0 -561
  69. package/docs/V3_2_AUDIT.md +0 -82
  70. package/docs/V3_BACKEND_ARCHITECTURE.md +0 -138
  71. package/docs/V3_FRONTEND.md +0 -140
  72. package/docs/V4_1_FRONTEND_ARCHITECTURE_REVIEW.md +0 -65
  73. package/docs/V4_1_FRONTEND_MIGRATION_REPORT.md +0 -70
  74. package/docs/V4_1_VALIDATION_REPORT.md +0 -47
  75. package/docs/V4_2_BRAIN_CORE_ARCHITECTURE.md +0 -97
  76. package/docs/V4_2_STORAGE_MIGRATION_REPORT.md +0 -91
  77. package/docs/V4_2_VALIDATION_REPORT.md +0 -89
  78. package/docs/V4_3_2_DEADCODE_AUDIT_REPORT.md +0 -174
  79. package/docs/V4_3_2_DOCUMENTATION_CLEANUP_REPORT.md +0 -81
  80. package/docs/V4_3_2_GITHUB_VERCEL_CHECK_REPORT.md +0 -75
  81. package/docs/V4_3_2_GRAPH_UX_REPORT.md +0 -48
  82. package/docs/V4_3_2_INDEPENDENT_AUDIT_PACKAGE.md +0 -209
  83. package/docs/V4_3_2_PRODUCT_POLISH_REPORT.md +0 -57
  84. package/docs/V4_3_2_SELF_AUDIT_REPORT.md +0 -63
  85. package/docs/V4_3_2_VALIDATION_REPORT.md +0 -97
  86. package/docs/V4_3_3_VALIDATION_REPORT.md +0 -46
  87. package/docs/V4_3_PORTABILITY_ARCHITECTURE.md +0 -69
  88. package/docs/V4_3_PRIVACY_AUDIT.md +0 -60
  89. package/docs/V4_3_PRODUCT_HARDENING_REPORT.md +0 -53
  90. package/docs/V4_3_VALIDATION_REPORT.md +0 -58
  91. package/docs/V4_4_0_EXTRACTION_REPORT.md +0 -239
  92. package/docs/V4_5_0_GEMMA_RUNTIME_COMPATIBILITY_REPORT.md +0 -49
  93. package/docs/V4_5_0_GRAPH_UX_REPORT.md +0 -34
  94. package/docs/V4_5_0_MODEL_RUNTIME_UX_REPORT.md +0 -40
  95. package/docs/V4_5_0_ONBOARDING_REPORT.md +0 -31
  96. package/docs/V4_5_0_PRODUCT_EXPERIENCE_RECOVERY_REPORT.md +0 -49
  97. package/docs/V4_5_0_VALIDATION_REPORT.md +0 -60
  98. package/docs/V4_5_1_GRAPH_EXPERIENCE_REPORT.md +0 -33
  99. package/docs/V4_5_1_MODEL_EXPERIENCE_REPORT.md +0 -37
  100. package/docs/V4_5_1_NAVIGATION_REPORT.md +0 -37
  101. package/docs/V4_5_1_ONBOARDING_REPORT.md +0 -29
  102. package/docs/V4_5_1_PRODUCT_REIMAGINING_REPORT.md +0 -61
  103. package/docs/V4_5_1_RC_ARTIFACTS.md +0 -44
  104. package/docs/V4_5_1_UX_REPORT.md +0 -45
  105. package/docs/V4_5_1_VALIDATION_REPORT.md +0 -55
  106. package/docs/V4_5_1_VISUAL_DESIGN_REPORT.md +0 -30
  107. package/docs/V4_6_0_LIVING_BRAIN_EXPERIENCE_REPORT.md +0 -72
  108. package/docs/V4_6_1_RELEASE_REFRESH_REPORT.md +0 -42
  109. package/docs/V4_7_0_ADMIN_SEPARATION_REPORT.md +0 -42
  110. package/docs/V4_7_1_ADMIN_OPERATIONS_REPORT.md +0 -49
  111. package/docs/V4_7_2_INTUITIVE_BRAIN_UX_REPORT.md +0 -62
  112. package/docs/V4_BRAIN_ARCHITECTURE.md +0 -322
  113. package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +0 -555
  114. package/docs/V4_IMPLEMENTATION_PLAN.md +0 -470
  115. package/frontend/index.html +0 -24
  116. package/frontend/openapi.json +0 -15425
  117. package/frontend/src/App.tsx +0 -243
  118. package/frontend/src/api/client.ts +0 -580
  119. package/frontend/src/api/openapi.ts +0 -17892
  120. package/frontend/src/components/AdminAccessGate.tsx +0 -70
  121. package/frontend/src/components/FeedbackState.tsx +0 -45
  122. package/frontend/src/components/LanguageSwitcher.tsx +0 -23
  123. package/frontend/src/components/LivingBrain.tsx +0 -220
  124. package/frontend/src/components/ProductFlow.tsx +0 -171
  125. package/frontend/src/components/WorkspaceProfileSwitcher.tsx +0 -176
  126. package/frontend/src/components/onboarding/AnalysisScreen.tsx +0 -135
  127. package/frontend/src/components/onboarding/DownloadConsentPanel.tsx +0 -29
  128. package/frontend/src/components/onboarding/InstallScreen.tsx +0 -263
  129. package/frontend/src/components/onboarding/LanguageChooser.tsx +0 -23
  130. package/frontend/src/components/onboarding/LoginScreen.tsx +0 -131
  131. package/frontend/src/components/onboarding/ProductFlowScreens.tsx +0 -13
  132. package/frontend/src/components/onboarding/RecommendationScreen.tsx +0 -116
  133. package/frontend/src/components/onboarding/recommendationModel.ts +0 -189
  134. package/frontend/src/components/primitives.tsx +0 -392
  135. package/frontend/src/components/ui/badge.tsx +0 -27
  136. package/frontend/src/components/ui/button.tsx +0 -37
  137. package/frontend/src/components/ui/card.tsx +0 -22
  138. package/frontend/src/components/ui/input.tsx +0 -16
  139. package/frontend/src/components/ui/textarea.tsx +0 -16
  140. package/frontend/src/features/admin/AdminConsole.tsx +0 -334
  141. package/frontend/src/features/brain/BrainCarePanel.tsx +0 -254
  142. package/frontend/src/features/brain/BrainComposer.tsx +0 -85
  143. package/frontend/src/features/brain/BrainConversation.tsx +0 -688
  144. package/frontend/src/features/brain/BrainGraphLayer.tsx +0 -365
  145. package/frontend/src/features/brain/BrainHome.tsx +0 -624
  146. package/frontend/src/features/brain/BrainMemoryLayer.tsx +0 -45
  147. package/frontend/src/features/brain/BrainOverviewPanel.tsx +0 -149
  148. package/frontend/src/features/brain/BrainRelationshipLayer.tsx +0 -43
  149. package/frontend/src/features/brain/DepthEmergence.tsx +0 -53
  150. package/frontend/src/features/brain/brainData.ts +0 -246
  151. package/frontend/src/features/brain/graphLayout.ts +0 -37
  152. package/frontend/src/features/brain/types.ts +0 -150
  153. package/frontend/src/features/review/ReviewCard.tsx +0 -100
  154. package/frontend/src/features/review/ReviewInbox.tsx +0 -127
  155. package/frontend/src/features/review/reviewHelpers.ts +0 -69
  156. package/frontend/src/i18n.ts +0 -1303
  157. package/frontend/src/lib/utils.ts +0 -33
  158. package/frontend/src/main.tsx +0 -23
  159. package/frontend/src/pages/Act.tsx +0 -458
  160. package/frontend/src/pages/Ask.tsx +0 -14
  161. package/frontend/src/pages/Brain.tsx +0 -914
  162. package/frontend/src/pages/Capture.tsx +0 -258
  163. package/frontend/src/pages/Library.tsx +0 -486
  164. package/frontend/src/pages/System.tsx +0 -621
  165. package/frontend/src/routes.ts +0 -92
  166. package/frontend/src/store/appStore.ts +0 -94
  167. package/frontend/src/styles.css +0 -6579
  168. package/static/app/assets/Act-DOvf59ru.js +0 -2
  169. package/static/app/assets/Act-DOvf59ru.js.map +0 -1
  170. package/static/app/assets/Brain-C7_0mEiI.js +0 -322
  171. package/static/app/assets/Brain-C7_0mEiI.js.map +0 -1
  172. package/static/app/assets/Capture-B9Tlhzqr.js.map +0 -1
  173. package/static/app/assets/Library-BJPEEm5O.js +0 -2
  174. package/static/app/assets/Library-BJPEEm5O.js.map +0 -1
  175. package/static/app/assets/System-D6t9jo9V.js +0 -2
  176. package/static/app/assets/System-D6t9jo9V.js.map +0 -1
  177. package/static/app/assets/core-CwxXejkd.js.map +0 -1
  178. package/static/app/assets/index-C7g26IF6.css +0 -2
  179. package/static/app/assets/index-DbcEYJQ2.js +0 -17
  180. package/static/app/assets/index-DbcEYJQ2.js.map +0 -1
  181. package/static/app/assets/primitives-CD38lt4n.js +0 -2
  182. package/static/app/assets/primitives-CD38lt4n.js.map +0 -1
  183. package/static/app/assets/textarea-BZk6ybp5.js.map +0 -1
@@ -1,8 +1,11 @@
1
1
  # Lattice AI Development
2
2
 
3
+ Current release: **8.2.0 - Brain Brief**.
4
+
3
5
  This document is for contributors working on the local-first Digital Brain
4
6
  codebase. Product positioning and quick start stay in `README.md`; release
5
- history stays in `docs/CHANGELOG.md` and `RELEASE.md`.
7
+ history is intentionally limited to 7.0.0-8.2.0 in `docs/CHANGELOG.md` and
8
+ `RELEASE.md`.
6
9
 
7
10
  ## Product Contract
8
11
 
@@ -77,9 +80,21 @@ Runtime assembly seams live under `latticeai.runtime`:
77
80
  - `config_runtime.py` derives app config values from `Config`;
78
81
  - `security_runtime.py` applies trusted proxy/security-derived settings;
79
82
  - `brain_runtime.py` constructs Brain Core and conversation primitives.
83
+ - model/runtime, ToolRegistry/MCP, router, static asset, and lifespan seams
84
+ should continue moving out of monolithic app-factory helpers.
85
+
86
+ Future extraction should continue with AgentRuntime, ToolRegistry, config,
87
+ server decomposition, and Knowledge Graph stabilization in that order when
88
+ architectural debt is present.
89
+
90
+ ## Runtime Hook Coverage
80
91
 
81
- Future extraction should continue with router assembly, model runtime assembly,
82
- platform/hooks assembly, static asset serving, and lifespan/startup/shutdown.
92
+ Knowledge Graph ingestion paths must continue to pass through the shared
93
+ pre-tool/post-tool lifecycle:
94
+
95
+ - browser `read-url` ingestion dispatches `tool.kg_ingest.*` events;
96
+ - browser `ingest-current-tab` ingestion dispatches the same lifecycle;
97
+ - `IngestionPipeline` remains the common ingestion boundary behind those routes.
83
98
 
84
99
  ## Documentation Sync
85
100
 
@@ -96,3 +111,11 @@ For user-facing, API, runtime, release, or packaging changes, check:
96
111
 
97
112
  Release/publish examples must use exact target-version filenames. Do not
98
113
  document wildcard artifact upload commands.
114
+
115
+ For 8.2.0 release work, exact artifacts are:
116
+
117
+ - `dist/ltcai-8.2.0-py3-none-any.whl`
118
+ - `dist/ltcai-8.2.0.tar.gz`
119
+ - `ltcai-8.2.0.tgz`
120
+ - `dist/ltcai-8.2.0.vsix`
121
+ - `src-tauri/target/release/bundle/dmg/Lattice AI_8.2.0_aarch64.dmg`
@@ -1,10 +1,12 @@
1
1
  # Legacy Compatibility Map
2
2
 
3
+ Current release: **8.2.0 - Brain Brief**.
4
+
3
5
  Lattice AI is moving toward a smaller, modular architecture centered on
4
6
  `lattice_brain`, `latticeai.services`, `latticeai.api`, and `latticeai.runtime`.
5
7
  Some root-level modules remain packaged for compatibility with older imports,
6
8
  CLI entrypoints, or extension workflows. Their presence does not define the
7
- current architecture.
9
+ current 8.2.0 architecture.
8
10
 
9
11
  ## Current Policy
10
12
 
@@ -1,7 +1,9 @@
1
1
  # Lattice AI Trust Model
2
2
 
3
- Lattice AI's trust model is local-first, opt-in for external communication, and
4
- honest when something is unavailable.
3
+ Current release: **8.2.0 - Brain Brief**.
4
+
5
+ Lattice AI is local-first, explicit about external communication, and honest
6
+ when a capability is unavailable.
5
7
 
6
8
  ## Local By Default
7
9
 
@@ -9,58 +11,56 @@ By default, Lattice AI binds the API to `127.0.0.1`, stores Brain data under the
9
11
  local data directory, and does not send prompts, documents, graph content, or
10
12
  archives to Lattice-owned servers.
11
13
 
12
- Local data includes:
14
+ Local data can include:
13
15
 
14
- - local profile and sessions;
15
- - conversations and memory records;
16
- - Knowledge Graph nodes, edges, provenance, and search indexes;
17
- - uploaded document blobs;
16
+ - profile and session metadata;
17
+ - conversations, memories, decisions, and workflow history;
18
+ - Knowledge Graph nodes, edges, provenance, and indexes;
19
+ - uploaded document blobs and extracted text;
18
20
  - audit and admin operation logs;
19
21
  - backups and encrypted `.latticebrain` archives.
20
22
 
21
23
  ## Explicit External Paths
22
24
 
23
- Some features can contact third parties, but they require explicit user/admin
24
- action or configuration:
25
+ External communication requires configuration plus a user/admin action:
25
26
 
26
- - model downloads from model registries;
27
- - cloud model API calls after keys are configured and a cloud model is chosen;
27
+ - cloud model calls after keys are configured and a cloud model is selected;
28
+ - model downloads from registries after install consent;
28
29
  - Telegram bridge after the integration is enabled;
29
- - Brain Network peer actions after pairing/initiating network flows;
30
+ - Brain Network peer actions after pairing;
30
31
  - Docker/Postgres setup after opt-in scale configuration;
31
- - update checks only when update checking is enabled;
32
- - remote marketplace/registry refreshes only through explicit user actions.
32
+ - update checks only when enabled;
33
+ - marketplace or remote registry refreshes only when invoked.
33
34
 
34
35
  Token presence alone must not start external communication.
35
36
 
36
37
  ## Consent And Honesty Gates
37
38
 
38
- Lattice AI should fail closed or report unavailable state for:
39
+ Lattice AI should fail closed or show an unavailable state for:
39
40
 
40
41
  - no model loaded;
41
- - local model not installed;
42
- - installed model not loaded;
42
+ - local model not installed or not loaded;
43
43
  - missing cloud key;
44
44
  - deterministic/model-free preview;
45
45
  - dry-run versus real execution;
46
46
  - no graph/context evidence available;
47
47
  - unavailable external integration;
48
48
  - wrong archive passphrase;
49
- - archive path traversal or tampering.
49
+ - archive tampering, unsupported archive versions, or path traversal.
50
50
 
51
- ## Admin Boundary
51
+ ## Product Boundary
52
52
 
53
- The normal user product is Brain Chat, memory, topics, relationships, graph
54
- exploration, model state, and Brain ownership. Admin Console is for users,
53
+ Normal Brain use is conversation, memory, topics, relationships, model state,
54
+ source capture, and Knowledge Graph exploration. Admin Console is for users,
55
55
  roles, audit logs, security events, retention, and operations. Admin visibility
56
56
  does not mean secrets should appear in clear text.
57
57
 
58
- ## Known Limitations
58
+ ## Known Limits
59
59
 
60
- - Local files are only as protected as the user's machine, account, backups, and
61
- disk encryption.
62
- - Cloud model prompts follow the selected provider's policy.
60
+ - Local files are only as protected as the user's machine, OS account, backups,
61
+ and disk encryption.
62
+ - Cloud model prompts follow the selected provider's policy once the user
63
+ explicitly chooses that provider.
63
64
  - A local admin can inspect local files and process memory outside Lattice AI.
64
65
  - Marketplace and model registries are third-party services when explicitly
65
66
  contacted.
66
-
@@ -1,51 +1,54 @@
1
1
  # Why Lattice AI Exists
2
2
 
3
- **Lattice AI is a local-first Digital Brain that keeps your knowledge durable across any AI model.**
3
+ Current release: **8.2.0 - Brain Brief**.
4
+
5
+ **Lattice AI is a local-first Digital Brain that keeps your knowledge durable
6
+ across any AI model.**
4
7
 
5
8
  **모델은 바꿔도, 내 지식은 남는 로컬 AI 브레인.**
6
9
 
7
- AI models change quickly. A model you use today may be replaced next month, and
8
- the conversation history, project context, decisions, and sources you built
9
- around it can become scattered across tools. Lattice AI exists so the durable
10
- asset is not the model. The durable asset is your Brain.
10
+ AI models change quickly. A model you use today may be replaced tomorrow, and a
11
+ cloud chat history can become scattered across tools. Lattice AI exists so the
12
+ durable asset is not the model. The durable asset is your Brain.
11
13
 
12
14
  ## The Problem
13
15
 
14
- Most AI products begin with a model and treat your context as temporary prompt
15
- material. That works for short questions, but it fails for long-running work:
16
+ Most AI products start with a model and treat your context as temporary prompt
17
+ material. That breaks down for real work:
16
18
 
17
19
  - project decisions disappear into old chats;
18
- - documents and notes are disconnected from conversations;
20
+ - documents and notes stay disconnected from conversations;
19
21
  - switching models often means losing useful context;
20
- - graph or database tools expose implementation details before user value;
21
- - cloud-only products make it hard to inspect, back up, or move your knowledge.
22
+ - graph tools expose implementation detail before user value;
23
+ - cloud-only products make your knowledge hard to inspect, back up, or move.
22
24
 
23
25
  ## The Lattice Answer
24
26
 
25
- Lattice AI is a local-first private AI memory layer. It keeps conversations,
26
- documents, decisions, relationships, and project history in a Brain that belongs
27
- to the user. Models can be local, cloud, current, or future. The Brain remains.
27
+ Lattice AI keeps conversations, documents, memories, decisions, relationships,
28
+ and source provenance in a private local Brain. Models can be local, cloud,
29
+ current, or future. The Brain remains.
30
+
31
+ The graph matters, but it is not the product identity. The product identity is a
32
+ local-first Digital Brain: a place where the user can talk, add sources, watch
33
+ memory grow, and inspect the Knowledge Graph when they need proof.
28
34
 
29
- The graph is real, but it is not the product identity. Product category is
30
- local-first Digital Brain; core capability is a private AI memory layer; UX
31
- metaphor is the Living Brain. Users start with Brain
32
- Chat, memory, topics, relationships, ownership, backup, and graph exploration.
33
- Advanced admin logs, roles, hooks, workflows, Telegram, Brain Network, Docker,
34
- Postgres, and plugin details stay outside the normal user flow.
35
+ In 8.2.0 the first screen is intentionally not a dashboard. The living Brain,
36
+ conversation composer, and evidence-backed Brain Brief appear together so the
37
+ user immediately knows what matters and what to do next.
35
38
 
36
39
  ## Practical Reasons To Use It
37
40
 
38
- - Ask what the team decided last week and see the source.
39
- - Drop in documents and build a searchable personal memory.
40
- - Prepare for a meeting from past notes, project decisions, and files.
41
- - Preserve context when moving from one model to another.
42
- - Export or back up the Brain as an encrypted `.latticebrain` archive.
41
+ - Ask what the team decided and see the source.
42
+ - Add documents and build a searchable private memory.
43
+ - Prepare from old notes, project decisions, and files.
44
+ - Preserve context when moving between models.
45
+ - Export or restore the Brain as an encrypted `.latticebrain` archive.
43
46
  - Use Korean or English without changing the underlying Brain.
44
47
  - Avoid fake answers when no model or evidence is available.
45
48
 
46
49
  ## What Lattice AI Is Not
47
50
 
48
- - Not a hosted SaaS by default.
51
+ - Not hosted SaaS by default.
49
52
  - Not just a model launcher.
50
53
  - Not just a graph viewer.
51
54
  - Not a generic dashboard.
package/docs/kg-schema.md CHANGED
@@ -1,4 +1,6 @@
1
- # Knowledge Graph — v2 스키마
1
+ # Knowledge Graph Schema
2
+
3
+ Current release: **8.2.0 - Brain Brief**.
2
4
 
3
5
  명세 출처: `lattice_ai_full_spec.pptx` 슬라이드 20·21·22
4
6
  구현: `kg_schema.py`
@@ -80,15 +82,15 @@ Edge {
80
82
 
81
83
  **엔드포인트 룰은 권고 사항이다 (스키마 문서 기준).** 코드에는 엔드포인트 페어
82
84
  검증기가 존재하지 않는다 — `validate_endpoints` 는 구현된 적이 없으며, 쓰기
83
- 경로는 타입 페어를 거부하지 않는다. v4 쓰기 정규화는 *타입 어휘* 를
85
+ 경로는 타입 페어를 거부하지 않는다. 현재 쓰기 정규화는 *타입 어휘* 를
84
86
  강제한다: `_upsert_edge` 가 모든 엣지 타입을 canonical `EdgeType` 값으로
85
87
  정규화하므로 자유 문자열 타입은 더 이상 생성되지 않는다.
86
88
 
87
89
  ---
88
90
 
89
- ## v3.6.0 Knowledge Graph First 엔티티/관계
91
+ ## Current Knowledge Graph First 엔티티/관계
90
92
 
91
- v3.6.0 은 "모든 데이터 소스가 Knowledge Graph 로 수렴한다"는 원칙을 1급 스키마로
93
+ 8.2.0 은 "모든 데이터 소스가 Knowledge Graph 로 수렴한다"는 원칙을 1급 스키마로
92
94
  승격한다. 아래 타입은 **추가형(additive)**이다 — 기존 enum/legacy 매핑을 깨지 않고
93
95
  `from_legacy` 가 무손실로 정규화하며, 알 수 없는 타입은 여전히 `CONCEPT`/`MENTIONS` 로
94
96
  폴백한다. 스키마는 **확장 가능**하게 유지한다: 새 도메인 엔티티는 enum 멤버 1개 +
@@ -26,7 +26,7 @@ from .storage import (
26
26
  storage_from_env,
27
27
  )
28
28
 
29
- __version__ = "8.0.0"
29
+ __version__ = "8.2.0"
30
30
 
31
31
  __all__ = [
32
32
  "AgentRuntime",
@@ -15,6 +15,10 @@ DEFAULT_EMBEDDING_DIM = int(os.getenv("LATTICEAI_VECTOR_DIM", "384"))
15
15
  EMBEDDING_MODEL_ID = f"lattice-local-hash-v1:{DEFAULT_EMBEDDING_DIM}"
16
16
 
17
17
 
18
+ def embedding_model_id(dim: int) -> str:
19
+ return f"lattice-local-hash-v1:{int(dim)}"
20
+
21
+
18
22
  def _tokenize(text: str) -> List[str]:
19
23
  raw = str(text or "").lower()
20
24
  tokens = re.findall(r"[a-z0-9][a-z0-9_.:/+-]{1,}|[가-힣]{2,}", raw)
@@ -49,6 +53,10 @@ class LocalEmbeddingModel:
49
53
  dim: int = DEFAULT_EMBEDDING_DIM
50
54
  model_id: str = EMBEDDING_MODEL_ID
51
55
 
56
+ def __post_init__(self) -> None:
57
+ if self.model_id == EMBEDDING_MODEL_ID and self.dim != DEFAULT_EMBEDDING_DIM:
58
+ object.__setattr__(self, "model_id", embedding_model_id(self.dim))
59
+
52
60
  def embed(self, text: str) -> List[float]:
53
61
  vector = [0.0] * self.dim
54
62
  features = _tokenize(text)
@@ -79,4 +87,4 @@ class LocalEmbeddingModel:
79
87
  return list(struct.unpack(f"<{count}f", payload[: count * 4]))
80
88
 
81
89
 
82
- __all__ = ["DEFAULT_EMBEDDING_DIM", "EMBEDDING_MODEL_ID", "LocalEmbeddingModel"]
90
+ __all__ = ["DEFAULT_EMBEDDING_DIM", "EMBEDDING_MODEL_ID", "LocalEmbeddingModel", "embedding_model_id"]
@@ -56,6 +56,12 @@ KG_SCHEMA_V2_VERSION = 2
56
56
  EMBED_DIM = int(os.getenv("LATTICEAI_EMBED_DIM", "1024"))
57
57
 
58
58
 
59
+ def set_embed_dim(dim: int) -> None:
60
+ """Optional way for upper layers to override without direct module import at top level in lattice_brain."""
61
+ global EMBED_DIM
62
+ EMBED_DIM = int(dim) # lattice_brain isolation: no direct latticeai import; callers can pre-set env if using central Config
63
+
64
+
59
65
  # ── Node / Edge taxonomy (PPT 슬라이드 20·21) ──────────────────────────────
60
66
  class NodeType(str, Enum):
61
67
  """워크스페이스의 모든 ‘명사’.
@@ -21,7 +21,7 @@ from typing import Any, Callable, Dict, List, Optional
21
21
  from .contracts import multi_agent_contract
22
22
 
23
23
 
24
- MULTI_AGENT_VERSION = "8.0.0"
24
+ MULTI_AGENT_VERSION = "8.2.0"
25
25
 
26
26
  AGENT_ROLES = ("researcher", "planner", "executor", "reviewer", "release")
27
27
  CORE_PIPELINE = ("planner", "executor", "reviewer")
@@ -1,3 +1,3 @@
1
1
  """Lattice AI - modular server package."""
2
2
 
3
- __version__ = "8.0.0"
3
+ __version__ = "8.2.0"
@@ -42,12 +42,14 @@ Available actions:
42
42
  - computer_scroll: {"action":"computer_scroll","args":{"x":500,"y":300,"direction":"down","clicks":3}}
43
43
  - computer_move: {"action":"computer_move","args":{"x":500,"y":300}}
44
44
  - computer_drag: {"action":"computer_drag","args":{"x1":100,"y1":100,"x2":500,"y2":500}}
45
+ - vision_analyze: {"action":"vision_analyze","args":{"image_b64": "...", "prompt": "What do you see on screen?"}} — use after screenshot to let VLM describe/answer about the image (only when multimodal model loaded)
45
46
  - final: {"action":"final","message":"Korean summary of what was accomplished"}
46
47
 
47
48
  Rules:
48
49
  - Respond with exactly ONE JSON object. No markdown, no extra text.
49
50
  - Do not take screenshots for simple app launch, URL opening, keyboard shortcuts, or non-visual tasks.
50
51
  - Take a screenshot before coordinate-based clicks/drags or when the task explicitly asks you to inspect the screen.
52
+ - After screenshot, prefer vision_analyze (with good prompt) over raw b64 in next step when you need to understand what is on screen (especially with multimodal/VLM loaded).
51
53
  - After coordinate-based clicking or typing into an unknown focused field, take a screenshot only if verification is necessary.
52
54
  - Use coordinates relative to the screen (0,0 is top-left).
53
55
  - If a UI element is not visible, scroll or search for it first.
@@ -58,6 +58,19 @@ def create_memory_router(
58
58
  scope = gate_read(request)
59
59
  return service.brain_quality_summary(user_email=user, workspace_id=scope)
60
60
 
61
+ @router.get("/api/memory/brain-brief")
62
+ async def brain_brief(request: Request, q: str = "", limit: int = 3):
63
+ user = require_user(request)
64
+ scope = gate_read(request)
65
+ active_model = active_model_getter() if active_model_getter else ""
66
+ return service.brain_brief(
67
+ user_email=user,
68
+ workspace_id=scope,
69
+ active_model=active_model,
70
+ recall_query=q,
71
+ limit=limit,
72
+ )
73
+
61
74
  @router.get("/api/memory/brain-proof")
62
75
  async def brain_proof(request: Request, q: str = "", limit: int = 3):
63
76
  user = require_user(request)
@@ -44,6 +44,8 @@ from latticeai.runtime.platform_services_runtime import (
44
44
  from latticeai.runtime.platform_runtime_wiring import build_platform_automation_runtime
45
45
  from latticeai.runtime.persistence_runtime import build_persistence_runtime
46
46
  from latticeai.runtime.review_wiring import build_review_run_now_runner
47
+ from latticeai.runtime.sso_runtime import build_sso_runtime
48
+ from latticeai.runtime.audit_runtime import build_audit_runtime
47
49
  from latticeai.runtime.router_registration import (
48
50
  build_auth_admin_security_router_bundle,
49
51
  build_static_routes_bundle,
@@ -77,8 +79,6 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
77
79
  import re
78
80
  import secrets
79
81
  import threading
80
- import subprocess
81
- import sys
82
82
  import time
83
83
  from pathlib import Path
84
84
 
@@ -95,6 +95,7 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
95
95
 
96
96
  from latticeai.models.router import LLMRouter, normalize_branding
97
97
  from lattice_brain._kg_common import set_llm_router
98
+ from lattice_brain.graph.schema import set_embed_dim
98
99
  from latticeai.core.security import (
99
100
  hash_password,
100
101
  verify_password,
@@ -107,7 +108,6 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
107
108
  )
108
109
  from latticeai.core.audit import (
109
110
  get_audit_log as _get_audit_log,
110
- append_audit_event as _append_audit_event,
111
111
  classify_sensitive_message as _classify_sensitive_message,
112
112
  build_sensitivity_report as _build_sensitivity_report,
113
113
  build_admin_audit_report as _build_admin_audit_report,
@@ -195,8 +195,10 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
195
195
  )
196
196
  from latticeai.core.tool_registry import TOOL_CATALOG_BRIEF as _TOOL_CATALOG_BRIEF # noqa: F401
197
197
  from latticeai.core.mcp_registry import (
198
- _get_combined_registry,
199
- _fetch_skills_marketplace, install_skill, SKILLS_DIR,
198
+ _fetch_skills_marketplace,
199
+ install_skill,
200
+ SKILLS_DIR,
201
+ create_mcp_install_state,
200
202
  )
201
203
  from latticeai.services.p_reinforce import PReinforceGardener
202
204
  from setup_wizard import get_recommendations, scan_environment
@@ -249,29 +251,12 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
249
251
  SSO_CLIENT_SECRET = _security_runtime["SSO_CLIENT_SECRET"]
250
252
  SSO_REDIRECT_URI = _security_runtime["SSO_REDIRECT_URI"]
251
253
  SSO_PROVIDER_NAME = _security_runtime["SSO_PROVIDER_NAME"]
252
- _sso_discovery_cache: Optional[Dict] = None
253
- _sso_discovery_cache_url: str = ""
254
- _sso_states: Dict[str, float] = {} # state → timestamp (CSRF protection)
255
254
 
256
- async def _get_sso_discovery() -> Optional[Dict]:
257
- nonlocal _sso_discovery_cache, _sso_discovery_cache_url
258
- settings = get_sso_settings()
259
- discovery_url = settings.get("discovery_url", "")
260
- if _sso_discovery_cache and _sso_discovery_cache_url == discovery_url:
261
- return _sso_discovery_cache
262
- if not discovery_url:
263
- return None
264
- try:
265
- import httpx as _httpx
266
- async with _httpx.AsyncClient() as c:
267
- r = await c.get(discovery_url, timeout=10)
268
- r.raise_for_status()
269
- _sso_discovery_cache = r.json()
270
- _sso_discovery_cache_url = discovery_url
271
- except Exception as e:
272
- logging.warning("SSO discovery failed: %s", e)
273
- return None
274
- return _sso_discovery_cache
255
+ # SSO cache + discovery built after get_sso_settings is defined (see below)
256
+ _sso_discovery_cache = None
257
+ _sso_discovery_cache_url = ""
258
+ _sso_states: Dict[str, float] = {}
259
+ _get_sso_discovery = None # filled after def below
275
260
 
276
261
  # ── Password hashing — used directly from latticeai.core.security ──────────────
277
262
  # (hash_password / verify_password are imported above; no local wrapper needed)
@@ -322,6 +307,15 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
322
307
  MCP_FILE = DATA_DIR / "mcp_installs.json"
323
308
  AUDIT_FILE = DATA_DIR / "audit_log.json"
324
309
  SSO_FILE = DATA_DIR / "sso_config.json"
310
+
311
+ # MCP state extracted to mcp_registry.create_mcp_install_state (server decomp)
312
+ _mcp_state = create_mcp_install_state(DATA_DIR)
313
+ load_mcp_installs = _mcp_state["load_mcp_installs"]
314
+ save_mcp_installs = _mcp_state["save_mcp_installs"]
315
+ mcp_public_item = _mcp_state["mcp_public_item"]
316
+ recommend_mcps = _mcp_state["recommend_mcps"]
317
+ install_mcp = _mcp_state["install_mcp"]
318
+
325
319
  # Resolve the configured embedding provider once at startup. Degrades to the
326
320
  # offline hash fallback when the requested provider is unavailable, while
327
321
  # recording the requested-vs-active provider for the Embeddings status surface.
@@ -346,6 +340,7 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
346
340
  extra={"target": CONFIG.embedding_custom_target},
347
341
  probe=_embedding_provider not in {"", "hash", "local", "fallback"},
348
342
  )
343
+ set_embed_dim(int(getattr(EMBEDDER, "dim", None) or _embedding_dim or 384))
349
344
  if EMBEDDER.fell_back:
350
345
  logging.warning("Embedding provider %s unavailable: %s", EMBEDDER.requested, EMBEDDER.detail)
351
346
  STORAGE_ENGINE = storage_from_env(os.environ, data_dir=DATA_DIR) if ENABLE_GRAPH else None
@@ -470,6 +465,17 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
470
465
  def get_sso_settings() -> Dict[str, object]:
471
466
  return load_sso_config()
472
467
 
468
+ # Build SSO runtime (cache + helper) now that get_sso_settings exists in scope.
469
+ if _get_sso_discovery is None:
470
+ _sso = build_sso_runtime(
471
+ get_sso_settings=get_sso_settings,
472
+ logging=logging,
473
+ )
474
+ _sso_discovery_cache = _sso["_sso_discovery_cache"]
475
+ _sso_discovery_cache_url = _sso["_sso_discovery_cache_url"]
476
+ _sso_states = _sso["_sso_states"]
477
+ _get_sso_discovery = _sso["_get_sso_discovery"]
478
+
473
479
  def public_sso_config(config: Optional[Dict[str, object]] = None) -> Dict[str, object]:
474
480
  cfg = config or get_sso_settings()
475
481
  return {
@@ -546,144 +552,10 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
546
552
  with open(VPC_FILE, "w", encoding="utf-8") as f:
547
553
  json.dump(config, f, ensure_ascii=False, indent=2)
548
554
 
549
- def load_mcp_installs() -> Dict:
550
- if not os.path.exists(MCP_FILE):
551
- return {"installed": {}, "updated_at": None}
552
- try:
553
- with open(MCP_FILE, "r", encoding="utf-8") as f:
554
- data = json.load(f)
555
- if "installed" not in data:
556
- data["installed"] = {}
557
- return data
558
- except Exception as e:
559
- logging.warning("load_mcp_installs failed: %s", e)
560
- return {"installed": {}, "updated_at": None}
561
-
562
- def save_mcp_installs(data: Dict):
563
- data["updated_at"] = datetime.now().isoformat()
564
- with open(MCP_FILE, "w", encoding="utf-8") as f:
565
- json.dump(data, f, ensure_ascii=False, indent=2)
566
-
567
- def mcp_public_item(item: Dict, installed_state: Dict) -> Dict:
568
- state = installed_state.get(item["id"]) or {}
569
- installed = item["install_mode"] in {"builtin", "bundled"} or bool(state.get("installed"))
570
- connector_pending = item["install_mode"] == "connector" and not state.get("authenticated")
571
- authenticated = item["install_mode"] != "connector" or bool(state.get("authenticated"))
572
- return {
573
- "id": item["id"],
574
- "name": item["name"],
575
- "category": item.get("category", ""),
576
- "install_mode": item["install_mode"],
577
- "description": item.get("description", ""),
578
- "capabilities": item.get("capabilities", []),
579
- "connector_url": item.get("connector_url"),
580
- "external_url": item.get("external_url"),
581
- "package": item.get("package"),
582
- "homepage": item.get("homepage"),
583
- "source": item.get("source", "local"),
584
- "installed": installed,
585
- "status": state.get("status") or ("active" if installed and not connector_pending else "needs_auth" if connector_pending else "available"),
586
- "authenticated": authenticated,
587
- "updated_at": state.get("updated_at"),
588
- }
589
-
590
- async def recommend_mcps(query: str, limit: int = 5) -> List[Dict]:
591
- text = (query or "").lower()
592
- installed = load_mcp_installs().get("installed", {})
593
- registry = await _get_combined_registry()
594
- scored = []
595
- for item in registry:
596
- score = 0
597
- hits = []
598
- for keyword in item.get("keywords", []):
599
- if keyword.lower() in text:
600
- score += 3 if len(keyword) > 2 else 1
601
- hits.append(keyword)
602
- # description 키워드 매칭 (remote 항목 보완)
603
- if not hits and text:
604
- desc_words = item.get("description", "").lower().split()
605
- for word in text.split():
606
- if len(word) > 2 and word in desc_words:
607
- score += 1
608
- hits.append(word)
609
- if item["id"] == "filesystem" and any(word in text for word in ["만들", "구현", "build", "deploy", "코드", "앱"]):
610
- score += 2
611
- if score:
612
- public = mcp_public_item(item, installed)
613
- public["score"] = score
614
- public["matched_keywords"] = hits[:6]
615
- scored.append(public)
616
- if not scored:
617
- fallback_ids = ["filesystem", "browser", "documents"]
618
- scored = [
619
- {**mcp_public_item(item, installed), "score": 1, "matched_keywords": []}
620
- for item in registry
621
- if item["id"] in fallback_ids
622
- ]
623
- return sorted(scored, key=lambda item: item["score"], reverse=True)[: max(1, min(limit, 24))]
624
-
625
- async def install_mcp(mcp_id: str) -> Dict:
626
- registry = await _get_combined_registry()
627
- item = next((entry for entry in registry if entry["id"] == mcp_id), None)
628
- if not item:
629
- raise HTTPException(status_code=404, detail="MCP를 찾을 수 없습니다.")
630
- data = load_mcp_installs()
631
- state = data.setdefault("installed", {})
632
- status = "active"
633
- message = "MCP가 활성화되었습니다."
634
- if item["install_mode"] == "connector":
635
- status = "needs_auth"
636
- message = "커넥터 인증이 필요합니다. Codex 앱의 connector 설정에서 계정을 연결하면 바로 사용할 수 있습니다."
637
- elif item["install_mode"] == "pip":
638
- packages = item.get("pip_packages") or []
639
- for pkg in packages:
640
- completed = subprocess.run(
641
- [sys.executable, "-m", "pip", "install", "--upgrade", pkg],
642
- capture_output=True, text=True, timeout=900, check=False,
643
- )
644
- if completed.returncode != 0:
645
- raise HTTPException(status_code=500, detail=completed.stderr[-2000:] or f"{pkg} 설치 실패")
646
- message = f"필수 패키지 설치 완료: {', '.join(packages)}"
647
- elif item["install_mode"] == "pypi":
648
- pkg = item.get("package", "")
649
- version = item.get("package_version")
650
- pkg_str = f"{pkg}=={version}" if version else pkg
651
- completed = subprocess.run(
652
- [sys.executable, "-m", "pip", "install", pkg_str],
653
- capture_output=True, text=True, timeout=300, check=False,
654
- )
655
- if completed.returncode != 0:
656
- raise HTTPException(status_code=500, detail=completed.stderr[-2000:] or f"{pkg} 설치 실패")
657
- message = f"pip 패키지 설치 완료: {pkg_str}"
658
- elif item["install_mode"] == "npm":
659
- pkg = item.get("package", "")
660
- version = item.get("package_version")
661
- pkg_str = f"{pkg}@{version}" if version else pkg
662
- completed = subprocess.run(
663
- ["npm", "install", "-g", pkg_str],
664
- capture_output=True, text=True, timeout=300, check=False,
665
- )
666
- if completed.returncode != 0:
667
- raise HTTPException(status_code=500, detail=completed.stderr[-2000:] or f"{pkg} 설치 실패")
668
- message = f"npm 패키지 설치 완료: {pkg_str}"
669
- state[mcp_id] = {
670
- "installed": True,
671
- "status": status,
672
- "authenticated": item["install_mode"] != "connector",
673
- "updated_at": datetime.now().isoformat(),
674
- }
675
- save_mcp_installs(data)
676
- public = mcp_public_item(item, state)
677
- public["message"] = message
678
- return public
679
555
 
680
556
  _history_lock = threading.Lock()
681
557
 
682
- def get_audit_log() -> List[Dict]:
683
- return _get_audit_log(AUDIT_FILE)
684
-
685
- def append_audit_event(event_type: str, **payload) -> None:
686
- _append_audit_event(AUDIT_FILE, event_type, **payload)
558
+ # audit build moved after redact_secret_text is defined (see below)
687
559
 
688
560
  def save_to_history(
689
561
  role: str,
@@ -755,6 +627,15 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
755
627
  def redact_secret_text(text: str) -> str:
756
628
  return _redact_secret_text(text)
757
629
 
630
+ # Build audit now that redact is available
631
+ _audit_rt = build_audit_runtime(
632
+ audit_file=AUDIT_FILE,
633
+ logging=logging,
634
+ redact_fn=redact_secret_text,
635
+ )
636
+ get_audit_log = _audit_rt["get_audit_log"]
637
+ append_audit_event = _audit_rt["append_audit_event"]
638
+
758
639
  def get_history():
759
640
  try:
760
641
  return CONVERSATIONS.history()