ltcai 8.9.0 → 9.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 (208) hide show
  1. package/README.md +81 -58
  2. package/auto_setup.py +7 -904
  3. package/desktop/electron/README.md +9 -0
  4. package/desktop/electron/main.cjs +5 -3
  5. package/docs/CHANGELOG.md +221 -238
  6. package/docs/COMMUNITY_AND_PLUGINS.md +3 -2
  7. package/docs/DEVELOPMENT.md +53 -14
  8. package/docs/LEGACY_COMPATIBILITY.md +4 -4
  9. package/docs/ONBOARDING.md +10 -2
  10. package/docs/OPERATIONS.md +8 -4
  11. package/docs/PRODUCT_DIRECTION_REVIEW.md +4 -0
  12. package/docs/ROADMAP_RECOMMENDATIONS.md +61 -36
  13. package/docs/TRUST_MODEL.md +5 -2
  14. package/docs/WHY_LATTICE.md +15 -10
  15. package/docs/WORKFLOW_DESIGNER.md +22 -0
  16. package/docs/kg-schema.md +13 -2
  17. package/docs/mcp-tools.md +17 -6
  18. package/docs/privacy.md +19 -3
  19. package/docs/public-deploy.md +32 -3
  20. package/docs/security-model.md +46 -11
  21. package/lattice_brain/__init__.py +1 -1
  22. package/lattice_brain/archive.py +4 -14
  23. package/lattice_brain/context.py +66 -9
  24. package/lattice_brain/embeddings.py +38 -2
  25. package/lattice_brain/graph/_kg_common.py +27 -462
  26. package/lattice_brain/graph/_kg_constants.py +243 -0
  27. package/lattice_brain/graph/_kg_fsutil.py +293 -0
  28. package/lattice_brain/graph/discovery.py +0 -948
  29. package/lattice_brain/graph/discovery_index.py +1126 -0
  30. package/lattice_brain/graph/documents.py +44 -9
  31. package/lattice_brain/graph/ingest.py +47 -20
  32. package/lattice_brain/graph/provenance.py +13 -6
  33. package/lattice_brain/graph/retrieval.py +141 -610
  34. package/lattice_brain/graph/retrieval_docgen.py +243 -0
  35. package/lattice_brain/graph/retrieval_vector.py +460 -0
  36. package/lattice_brain/graph/store.py +6 -0
  37. package/lattice_brain/ingestion.py +69 -4
  38. package/lattice_brain/portability.py +29 -23
  39. package/lattice_brain/quality.py +98 -4
  40. package/lattice_brain/runtime/agent_runtime.py +169 -7
  41. package/lattice_brain/runtime/hooks.py +30 -13
  42. package/lattice_brain/runtime/multi_agent.py +27 -8
  43. package/lattice_brain/runtime/statuses.py +10 -0
  44. package/lattice_brain/utils.py +46 -0
  45. package/lattice_brain/workflow.py +1 -5
  46. package/latticeai/__init__.py +1 -1
  47. package/latticeai/api/admin.py +1 -1
  48. package/latticeai/api/agent_registry.py +10 -8
  49. package/latticeai/api/agents.py +22 -3
  50. package/latticeai/api/auth.py +78 -16
  51. package/latticeai/api/browser.py +303 -34
  52. package/latticeai/api/chat.py +355 -952
  53. package/latticeai/api/chat_agent_http.py +356 -0
  54. package/latticeai/api/chat_contracts.py +54 -0
  55. package/latticeai/api/chat_documents.py +256 -0
  56. package/latticeai/api/chat_helpers.py +250 -0
  57. package/latticeai/api/chat_history.py +99 -0
  58. package/latticeai/api/chat_intents.py +302 -0
  59. package/latticeai/api/chat_stream.py +115 -0
  60. package/latticeai/api/computer_use.py +211 -40
  61. package/latticeai/api/health.py +9 -3
  62. package/latticeai/api/hooks.py +17 -6
  63. package/latticeai/api/knowledge_graph.py +78 -14
  64. package/latticeai/api/local_files.py +7 -2
  65. package/latticeai/api/marketplace.py +11 -0
  66. package/latticeai/api/mcp.py +102 -23
  67. package/latticeai/api/models.py +72 -33
  68. package/latticeai/api/network.py +5 -5
  69. package/latticeai/api/permissions.py +70 -29
  70. package/latticeai/api/plugins.py +21 -7
  71. package/latticeai/api/portability.py +5 -5
  72. package/latticeai/api/realtime.py +33 -5
  73. package/latticeai/api/setup.py +2 -2
  74. package/latticeai/api/static_routes.py +123 -24
  75. package/latticeai/api/tools.py +97 -14
  76. package/latticeai/api/workflow_designer.py +37 -0
  77. package/latticeai/api/workspace.py +2 -1
  78. package/latticeai/app_factory.py +185 -405
  79. package/latticeai/core/agent.py +19 -9
  80. package/latticeai/core/agent_registry.py +1 -5
  81. package/latticeai/core/config.py +23 -3
  82. package/latticeai/core/context_builder.py +21 -3
  83. package/latticeai/core/invitations.py +1 -4
  84. package/latticeai/core/io_utils.py +45 -0
  85. package/latticeai/core/legacy_compatibility.py +24 -3
  86. package/latticeai/core/local_embeddings.py +2 -4
  87. package/latticeai/core/marketplace.py +33 -2
  88. package/latticeai/core/mcp_catalog.py +450 -0
  89. package/latticeai/core/mcp_registry.py +2 -441
  90. package/latticeai/core/plugins.py +15 -0
  91. package/latticeai/core/policy.py +1 -1
  92. package/latticeai/core/realtime.py +38 -15
  93. package/latticeai/core/sessions.py +7 -2
  94. package/latticeai/core/timeutil.py +10 -0
  95. package/latticeai/core/tool_registry.py +90 -18
  96. package/latticeai/core/users.py +5 -14
  97. package/latticeai/core/workspace_graph_trace.py +31 -5
  98. package/latticeai/core/workspace_memory.py +3 -1
  99. package/latticeai/core/workspace_os.py +18 -7
  100. package/latticeai/core/workspace_os_utils.py +2 -21
  101. package/latticeai/core/workspace_permissions.py +2 -1
  102. package/latticeai/core/workspace_plugins.py +1 -1
  103. package/latticeai/core/workspace_runs.py +14 -5
  104. package/latticeai/core/workspace_skills.py +1 -1
  105. package/latticeai/core/workspace_snapshots.py +2 -1
  106. package/latticeai/core/workspace_timeline.py +2 -1
  107. package/latticeai/integrations/telegram_bot.py +96 -40
  108. package/latticeai/models/model_providers.py +111 -0
  109. package/latticeai/models/router.py +189 -173
  110. package/latticeai/runtime/access_runtime.py +62 -4
  111. package/latticeai/runtime/audit_runtime.py +27 -16
  112. package/latticeai/runtime/automation_runtime.py +22 -7
  113. package/latticeai/runtime/brain_runtime.py +19 -7
  114. package/latticeai/runtime/chat_wiring.py +2 -0
  115. package/latticeai/runtime/config_runtime.py +58 -26
  116. package/latticeai/runtime/context_runtime.py +16 -4
  117. package/latticeai/runtime/history_runtime.py +163 -0
  118. package/latticeai/runtime/hooks_runtime.py +1 -1
  119. package/latticeai/runtime/model_wiring.py +33 -5
  120. package/latticeai/runtime/namespace_runtime.py +163 -0
  121. package/latticeai/runtime/network_config_runtime.py +56 -0
  122. package/latticeai/runtime/platform_runtime_wiring.py +4 -3
  123. package/latticeai/runtime/review_wiring.py +1 -1
  124. package/latticeai/runtime/router_registration.py +34 -1
  125. package/latticeai/runtime/security_runtime.py +110 -13
  126. package/latticeai/runtime/sso_config_runtime.py +128 -0
  127. package/latticeai/runtime/stages.py +27 -0
  128. package/latticeai/runtime/user_key_runtime.py +106 -0
  129. package/latticeai/server_app.py +5 -1
  130. package/latticeai/services/architecture_readiness.py +74 -5
  131. package/latticeai/services/brain_automation.py +3 -26
  132. package/latticeai/services/chat_service.py +205 -15
  133. package/latticeai/services/local_knowledge.py +423 -0
  134. package/latticeai/services/memory_service.py +268 -21
  135. package/latticeai/services/model_engines.py +48 -33
  136. package/latticeai/services/model_errors.py +17 -0
  137. package/latticeai/services/model_loading.py +28 -25
  138. package/latticeai/services/model_runtime.py +228 -162
  139. package/latticeai/services/p_reinforce.py +22 -3
  140. package/latticeai/services/platform_runtime.py +92 -24
  141. package/latticeai/services/product_readiness.py +19 -17
  142. package/latticeai/services/review_queue.py +76 -11
  143. package/latticeai/services/router_context.py +1 -0
  144. package/latticeai/services/run_executor.py +25 -9
  145. package/latticeai/services/search_service.py +203 -28
  146. package/latticeai/services/setup_detection.py +80 -0
  147. package/latticeai/services/tool_dispatch.py +28 -5
  148. package/latticeai/services/triggers.py +53 -4
  149. package/latticeai/services/upload_service.py +13 -2
  150. package/latticeai/setup/__init__.py +25 -0
  151. package/latticeai/setup/auto_setup.py +857 -0
  152. package/latticeai/setup/wizard.py +1264 -0
  153. package/latticeai/tools/__init__.py +278 -0
  154. package/{tools → latticeai/tools}/commands.py +67 -7
  155. package/{tools → latticeai/tools}/computer.py +1 -1
  156. package/{tools → latticeai/tools}/documents.py +1 -1
  157. package/{tools → latticeai/tools}/filesystem.py +3 -3
  158. package/latticeai/tools/knowledge.py +178 -0
  159. package/{tools → latticeai/tools}/local_files.py +7 -1
  160. package/{tools → latticeai/tools}/network.py +0 -1
  161. package/local_knowledge_api.py +4 -342
  162. package/package.json +22 -2
  163. package/scripts/brain_quality_eval.py +3 -1
  164. package/scripts/bump_version.py +3 -0
  165. package/scripts/capture_release_evidence.mjs +180 -0
  166. package/scripts/check_current_release_docs.mjs +142 -0
  167. package/scripts/check_i18n_literals.mjs +107 -31
  168. package/scripts/check_openapi_drift.mjs +56 -0
  169. package/scripts/export_openapi.py +67 -7
  170. package/scripts/i18n_literal_allowlist.json +22 -24
  171. package/scripts/run_integration_tests.mjs +72 -10
  172. package/scripts/validate_release_artifacts.py +49 -7
  173. package/scripts/wheel_smoke.py +5 -0
  174. package/setup_wizard.py +3 -1304
  175. package/src-tauri/Cargo.lock +1 -1
  176. package/src-tauri/Cargo.toml +1 -1
  177. package/src-tauri/tauri.conf.json +1 -1
  178. package/static/app/asset-manifest.json +11 -11
  179. package/static/app/assets/Act-Bzz0bUyW.js +1 -0
  180. package/static/app/assets/Brain-Dj2J20YA.js +321 -0
  181. package/static/app/assets/Capture-CqlEl1Ga.js +1 -0
  182. package/static/app/assets/Library-B03FP1Yx.js +1 -0
  183. package/static/app/assets/System-80lHW0Ux.js +1 -0
  184. package/static/app/assets/index-BiMofBTM.js +17 -0
  185. package/static/app/assets/index-Bmx9rzTc.css +2 -0
  186. package/static/app/assets/primitives-Q1A96_7v.js +1 -0
  187. package/static/app/assets/textarea-D13RtnTo.js +1 -0
  188. package/static/app/index.html +2 -2
  189. package/static/css/tokens.css +4 -2
  190. package/static/sw.js +1 -1
  191. package/tools/__init__.py +21 -269
  192. package/docs/CODE_REVIEW_2026-07-06.md +0 -764
  193. package/latticeai/runtime/app_context_runtime.py +0 -13
  194. package/latticeai/runtime/sso_runtime.py +0 -52
  195. package/latticeai/runtime/tail_wiring.py +0 -21
  196. package/scripts/com.pts.claudecode.discord.plist +0 -31
  197. package/scripts/pts-claudecode-discord-bridge.mjs +0 -207
  198. package/scripts/start-pts-claudecode-discord.sh +0 -51
  199. package/static/app/assets/Act-fZokUnC0.js +0 -1
  200. package/static/app/assets/Brain-DtyuWubr.js +0 -321
  201. package/static/app/assets/Capture-D5KV3Cu7.js +0 -1
  202. package/static/app/assets/Library-C9kyFkSt.js +0 -1
  203. package/static/app/assets/System-VbChmX7r.js +0 -1
  204. package/static/app/assets/index-DCh5AoXt.css +0 -2
  205. package/static/app/assets/index-DPdcPoF0.js +0 -17
  206. package/static/app/assets/primitives-DFeanEV6.js +0 -1
  207. package/static/app/assets/textarea-CD8UNKIy.js +0 -1
  208. package/tools/knowledge.py +0 -95
@@ -0,0 +1,243 @@
1
+ from __future__ import annotations
2
+
3
+ # ruff: noqa: F403,F405
4
+
5
+ from ._kg_common import * # noqa: F403,F401
6
+
7
+
8
+ class KnowledgeGraphDocGenMixin:
9
+ """Multi-hop retrieval specialised for document generation, split out
10
+ of retrieval. Composed into KnowledgeGraphStore alongside the other
11
+ retrieval mixins; shared instance means sibling helpers resolve via MRO.
12
+ """
13
+
14
+ def search_for_document_generation(
15
+ self,
16
+ query: str,
17
+ limit: int = 10,
18
+ *,
19
+ allowed_workspaces=None,
20
+ include_legacy_global: bool = False,
21
+ ) -> List[Dict[str, Any]]:
22
+ """Hybrid retrieval optimized for document generation.
23
+
24
+ Scoring: 0.5*text_relevance + 0.3*graph_relationship + 0.2*recency
25
+ Returns nodes with rich context for document generation prompts.
26
+ """
27
+ query = str(query or "").strip()
28
+ if not query:
29
+ return []
30
+ limit = max(1, min(int(limit or 10), 50))
31
+ terms = _topic_candidates(query, limit=12)
32
+ now = datetime.now()
33
+ nt, et = self._read_tables()
34
+
35
+ with self._connect() as conn:
36
+ candidate_rows = []
37
+ seen_ids = set()
38
+
39
+ if query:
40
+ q = f"%{query}%"
41
+ rows = conn.execute(
42
+ f"""
43
+ SELECT id, type, title, summary, metadata_json, updated_at
44
+ FROM {nt}
45
+ WHERE (title LIKE ? OR summary LIKE ? OR metadata_json LIKE ?)
46
+ AND type IN ('Document', 'File', 'CodeFile', 'SlideDeck',
47
+ 'Spreadsheet', 'Image', 'ImageText', 'Chat',
48
+ 'Decision', 'Task', 'Concept', 'Feature',
49
+ 'Page', 'Slide')
50
+ ORDER BY updated_at DESC, id ASC
51
+ LIMIT ?
52
+ """,
53
+ (q, q, q, limit * 5),
54
+ ).fetchall()
55
+ for row in rows:
56
+ if row["id"] not in seen_ids:
57
+ seen_ids.add(row["id"])
58
+ candidate_rows.append(row)
59
+
60
+ for term in terms:
61
+ t = f"%{term}%"
62
+ rows = conn.execute(
63
+ f"""
64
+ SELECT id, type, title, summary, metadata_json, updated_at
65
+ FROM {nt}
66
+ WHERE (title LIKE ? OR summary LIKE ? OR metadata_json LIKE ?)
67
+ AND type IN ('Document', 'File', 'CodeFile', 'SlideDeck',
68
+ 'Spreadsheet', 'Image', 'ImageText', 'Chat',
69
+ 'Decision', 'Task', 'Concept', 'Feature',
70
+ 'Page', 'Slide')
71
+ ORDER BY updated_at DESC, id ASC
72
+ LIMIT ?
73
+ """,
74
+ (t, t, t, limit * 3),
75
+ ).fetchall()
76
+ for row in rows:
77
+ if row["id"] not in seen_ids:
78
+ seen_ids.add(row["id"])
79
+ candidate_rows.append(row)
80
+
81
+ scored_results = []
82
+ for row in candidate_rows:
83
+ haystack = (
84
+ f"{row['title']} {row['summary']} {row['metadata_json']}".lower()
85
+ )
86
+
87
+ text_hits = sum(1 for term in terms if term.lower() in haystack)
88
+ text_score = min(1.0, text_hits / max(len(terms), 1))
89
+
90
+ edge_count = conn.execute(
91
+ f"SELECT COUNT(*) AS c FROM {et} WHERE from_node=? OR to_node=?",
92
+ (row["id"], row["id"]),
93
+ ).fetchone()["c"]
94
+ graph_score = min(1.0, math.log1p(edge_count) / 4.0)
95
+
96
+ recency = _recency_score(
97
+ row["updated_at"], now=now, half_life_days=14.0
98
+ )
99
+
100
+ doc_type_boost = (
101
+ 1.2
102
+ if row["type"]
103
+ in (
104
+ "Document",
105
+ "File",
106
+ "SlideDeck",
107
+ "Decision",
108
+ )
109
+ else 1.0
110
+ )
111
+
112
+ hybrid_score = (
113
+ 0.5 * text_score + 0.3 * graph_score + 0.2 * recency
114
+ ) * doc_type_boost
115
+
116
+ meta = _safe_loads(row["metadata_json"])
117
+ neighbor_concepts = []
118
+ neighbor_rows = conn.execute(
119
+ f"""
120
+ SELECT n.id, n.title, n.type FROM {et} e
121
+ JOIN {nt} n ON n.id = CASE WHEN e.from_node = ? THEN e.to_node ELSE e.from_node END
122
+ WHERE (e.from_node = ? OR e.to_node = ?)
123
+ AND n.type IN ('Concept', 'Feature', 'Decision', 'Task')
124
+ LIMIT 8
125
+ """,
126
+ (row["id"], row["id"], row["id"]),
127
+ ).fetchall()
128
+ for nr in neighbor_rows:
129
+ neighbor_concepts.append({"id": nr["id"], "title": nr["title"], "type": nr["type"]})
130
+
131
+ scored_results.append(
132
+ {
133
+ "id": row["id"],
134
+ "type": row["type"],
135
+ "title": row["title"],
136
+ "summary": row["summary"],
137
+ "metadata": meta,
138
+ "updated_at": row["updated_at"],
139
+ "hybrid_score": round(hybrid_score, 4),
140
+ "scores": {
141
+ "text": round(text_score, 4),
142
+ "graph": round(graph_score, 4),
143
+ "recency": round(recency, 4),
144
+ },
145
+ "related_concepts": neighbor_concepts,
146
+ }
147
+ )
148
+
149
+ if allowed_workspaces is not None:
150
+ scored_results = self.filter_scoped_nodes(
151
+ scored_results,
152
+ allowed_workspaces,
153
+ include_legacy_global=include_legacy_global,
154
+ )
155
+ for item in scored_results:
156
+ item["related_concepts"] = self.filter_scoped_nodes(
157
+ item.get("related_concepts", []),
158
+ allowed_workspaces,
159
+ include_legacy_global=include_legacy_global,
160
+ )
161
+ scored_results.sort(key=lambda x: x["hybrid_score"], reverse=True)
162
+ return scored_results[:limit]
163
+
164
+ def multi_hop_context(
165
+ self,
166
+ node_ids: List[str],
167
+ max_hops: int = 2,
168
+ *,
169
+ allowed_workspaces=None,
170
+ include_legacy_global: bool = False,
171
+ ) -> Dict[str, Any]:
172
+ """Multi-hop graph traversal from seed nodes for richer context."""
173
+ visited_nodes = set()
174
+ visited_edges = set()
175
+ all_nodes = []
176
+ all_edges = []
177
+ frontier = set(node_ids)
178
+ nt, et = self._read_tables()
179
+
180
+ with self._connect() as conn:
181
+ for hop in range(max_hops):
182
+ if not frontier:
183
+ break
184
+ next_frontier = set()
185
+ for nid in frontier:
186
+ if nid in visited_nodes:
187
+ continue
188
+ visited_nodes.add(nid)
189
+ row = conn.execute(
190
+ f"SELECT id, type, title, summary, metadata_json, updated_at FROM {nt} WHERE id=?",
191
+ (nid,),
192
+ ).fetchone()
193
+ if row:
194
+ all_nodes.append(
195
+ {
196
+ "id": row["id"],
197
+ "type": row["type"],
198
+ "title": row["title"],
199
+ "summary": row["summary"],
200
+ "metadata": _safe_loads(row["metadata_json"]),
201
+ "hop": hop,
202
+ }
203
+ )
204
+ edge_rows = conn.execute(
205
+ f"""
206
+ SELECT id, from_node, to_node, type, weight
207
+ FROM {et} WHERE from_node=? OR to_node=?
208
+ ORDER BY id ASC
209
+ """,
210
+ (nid, nid),
211
+ ).fetchall()
212
+ for er in edge_rows:
213
+ if er["id"] not in visited_edges:
214
+ visited_edges.add(er["id"])
215
+ all_edges.append(
216
+ {
217
+ "from": er["from_node"],
218
+ "to": er["to_node"],
219
+ "type": er["type"],
220
+ "weight": er["weight"],
221
+ }
222
+ )
223
+ other = (
224
+ er["to_node"]
225
+ if er["from_node"] == nid
226
+ else er["from_node"]
227
+ )
228
+ if other not in visited_nodes:
229
+ next_frontier.add(other)
230
+ frontier = next_frontier
231
+
232
+ if allowed_workspaces is not None:
233
+ all_nodes = self.filter_scoped_nodes(
234
+ all_nodes,
235
+ allowed_workspaces,
236
+ include_legacy_global=include_legacy_global,
237
+ )
238
+ visible_ids = {node.get("id") for node in all_nodes}
239
+ all_edges = [
240
+ edge for edge in all_edges
241
+ if edge.get("from") in visible_ids and edge.get("to") in visible_ids
242
+ ]
243
+ return {"nodes": all_nodes, "edges": all_edges}