ltcai 11.5.1 → 11.6.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 (473) hide show
  1. package/README.md +92 -117
  2. package/bin/ltcai.js +234 -24
  3. package/docs/CHANGELOG.md +129 -0
  4. package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
  5. package/docs/DEVELOPMENT.md +8 -6
  6. package/docs/ENTERPRISE.md +2 -1
  7. package/docs/HYBRID_CLOUD_KG_STREAMING.md +8 -4
  8. package/docs/MULTI_AGENT_RUNTIME.md +12 -5
  9. package/docs/ONBOARDING.md +1 -1
  10. package/docs/OPERATIONS.md +6 -3
  11. package/docs/REALTIME_COLLABORATION.md +1 -1
  12. package/docs/TRUST_MODEL.md +1 -1
  13. package/docs/WHY_LATTICE.md +1 -1
  14. package/docs/WORKFLOW_DESIGNER.md +3 -2
  15. package/docs/architecture.md +4 -4
  16. package/docs/kg-schema.md +1 -1
  17. package/docs/v11.5.2_TIGHT_SHIP_PLAN.md +144 -0
  18. package/docs/v11.6.0_ONE_DOOR_PLAN.md +170 -0
  19. package/lattice_brain/__init__.py +42 -79
  20. package/lattice_brain/graph/__init__.py +9 -24
  21. package/lattice_brain/graph/_kg_common/__init__.py +13 -24
  22. package/lattice_brain/ingestion/__init__.py +19 -58
  23. package/lattice_brain/ingestion/pipeline.py +20 -398
  24. package/lattice_brain/multimodal/__init__.py +7 -18
  25. package/lattice_brain/multimodal/images.py +6 -264
  26. package/lattice_brain/multimodal/video.py +8 -247
  27. package/lattice_brain/runtime/__init__.py +8 -79
  28. package/lattice_brain/runtime/hooks.py +22 -597
  29. package/latticeai/__init__.py +1 -1
  30. package/latticeai/api/agent_worker_seam.py +7 -80
  31. package/latticeai/api/health.py +26 -20
  32. package/latticeai/api/local_files.py +25 -608
  33. package/latticeai/api/models.py +12 -87
  34. package/latticeai/api/search.py +17 -231
  35. package/latticeai/api/tools.py +69 -750
  36. package/latticeai/api/voice_capture.py +8 -70
  37. package/latticeai/api/worker_compute.py +842 -0
  38. package/latticeai/api/worker_seams.py +216 -0
  39. package/latticeai/app_factory.py +23 -232
  40. package/latticeai/cli/entrypoint.py +36 -249
  41. package/latticeai/cli/runtime.py +7 -3
  42. package/latticeai/core/agent_permission.py +16 -91
  43. package/latticeai/core/config.py +47 -3
  44. package/latticeai/core/csrf.py +28 -2
  45. package/latticeai/core/embedding_providers/__init__.py +3 -5
  46. package/latticeai/core/embedding_providers/base.py +1 -1
  47. package/latticeai/core/embedding_providers/text.py +1 -1
  48. package/latticeai/core/http_origin.py +146 -0
  49. package/latticeai/core/io_utils.py +2 -11
  50. package/latticeai/core/messages.py +94 -531
  51. package/latticeai/core/model_compat.py +2 -8
  52. package/latticeai/core/module_probe.py +37 -0
  53. package/latticeai/core/security.py +13 -0
  54. package/latticeai/core/sessions.py +3 -2
  55. package/latticeai/core/sse.py +25 -0
  56. package/latticeai/core/users.py +0 -9
  57. package/latticeai/models/router/documents.py +0 -35
  58. package/latticeai/models/router/registry.py +0 -4
  59. package/latticeai/runtime/access_runtime.py +16 -18
  60. package/latticeai/runtime/bootstrap.py +10 -21
  61. package/latticeai/runtime/brain_runtime.py +35 -43
  62. package/latticeai/runtime/build_phases/__init__.py +21 -37
  63. package/latticeai/runtime/build_phases/features.py +101 -389
  64. package/latticeai/runtime/build_phases/foundation.py +82 -392
  65. package/latticeai/runtime/build_phases/web.py +91 -406
  66. package/latticeai/runtime/build_phases/worker_profile.py +244 -0
  67. package/latticeai/runtime/lifespan_runtime.py +7 -16
  68. package/latticeai/runtime/platform_services_runtime.py +1 -15
  69. package/latticeai/runtime/runtime_context.py +14 -143
  70. package/latticeai/runtime/security_runtime.py +10 -103
  71. package/latticeai/services/architecture_readiness.py +82 -43
  72. package/latticeai/services/model_capability_registry.py +0 -15
  73. package/latticeai/services/model_catalog.py +0 -7
  74. package/latticeai/services/model_loading.py +3 -2
  75. package/latticeai/services/model_runtime/__init__.py +2 -68
  76. package/latticeai/services/model_runtime/engines.py +27 -128
  77. package/latticeai/services/model_runtime/loading.py +2 -2
  78. package/latticeai/services/model_runtime/service.py +4 -28
  79. package/latticeai/services/p_reinforce.py +10 -261
  80. package/latticeai/services/product_readiness.py +31 -38
  81. package/latticeai/services/search_service.py +37 -795
  82. package/latticeai/services/tool_dispatch.py +30 -390
  83. package/latticeai/services/voice_capture.py +13 -107
  84. package/latticeai/tools/__init__.py +22 -49
  85. package/latticeai/tools/commands.py +0 -163
  86. package/latticeai/tools/computer.py +0 -39
  87. package/latticeai/tools/documents.py +1 -134
  88. package/latticeai/tools/filesystem.py +1 -247
  89. package/latticeai/tools/knowledge.py +1 -52
  90. package/latticeai/tools/local_files.py +0 -20
  91. package/latticeai/worker_app.py +75 -0
  92. package/package.json +3 -6
  93. package/requirements.txt +0 -5
  94. package/scripts/agent_eval.py +16 -28
  95. package/scripts/brain_quality_eval.py +20 -183
  96. package/scripts/bump_version.py +19 -6
  97. package/scripts/check_current_release_docs.mjs +7 -4
  98. package/scripts/check_legacy_debt.mjs +1 -1
  99. package/scripts/check_openapi_drift.mjs +10 -0
  100. package/scripts/check_server_i18n.mjs +2 -18
  101. package/scripts/compose_openapi.py +377 -0
  102. package/scripts/export_openapi.py +32 -4
  103. package/scripts/gen_messages_catalog_fixture.py +302 -0
  104. package/scripts/gen_openapi_fragments.py +365 -0
  105. package/scripts/gen_redact_fixture.py +196 -0
  106. package/scripts/gen_worker_allowlist_fixture.py +115 -0
  107. package/scripts/generate_agent_parity_fixtures.py +33 -14
  108. package/scripts/openapi_route_families.json +2161 -0
  109. package/scripts/release_screen_claims.json +31 -0
  110. package/scripts/run_integration_tests.mjs +134 -29
  111. package/scripts/run_sidecar_e2e.mjs +104 -11
  112. package/scripts/wheel_smoke.py +32 -22
  113. package/src-tauri/Cargo.lock +375 -9
  114. package/src-tauri/Cargo.toml +1 -1
  115. package/src-tauri/src/backend.rs +223 -43
  116. package/src-tauri/src/main.rs +27 -17
  117. package/src-tauri/src/topology.rs +58 -88
  118. package/src-tauri/tauri.conf.json +2 -3
  119. package/static/app/asset-manifest.json +41 -41
  120. package/static/app/assets/{Act-Drs_jd-O.js → Act-CToZnOHz.js} +1 -1
  121. package/static/app/assets/{AdminConsole-BqNx5oF6.js → AdminConsole-D5kbrBu8.js} +1 -1
  122. package/static/app/assets/{Brain-C7bdNmz-.js → Brain-C6zCdv4S.js} +1 -1
  123. package/static/app/assets/{BrainHome-DcTnINcI.js → BrainHome-D4n3EDUt.js} +1 -1
  124. package/static/app/assets/{BrainSignals-Df1MRIPD.js → BrainSignals-CzeZ-vQ9.js} +1 -1
  125. package/static/app/assets/{Capture-Dgsxvnbx.js → Capture-DPcyTczq.js} +1 -1
  126. package/static/app/assets/{Chronicle-BrkTxJK1.js → Chronicle-D3Nx-oWS.js} +1 -1
  127. package/static/app/assets/{CommandPalette-DDziw7Oj.js → CommandPalette-DPPvpp28.js} +1 -1
  128. package/static/app/assets/{Library-CYxeuraA.js → Library-Co2qTu3I.js} +1 -1
  129. package/static/app/assets/{LivingBrain-CNp6mvCm.js → LivingBrain-Bsmzwy8_.js} +1 -1
  130. package/static/app/assets/{ProductFlow-BVsowu3Z.js → ProductFlow-CBLdmesT.js} +1 -1
  131. package/static/app/assets/{ReviewCard-D1LbOfJS.js → ReviewCard-CfR6DLs7.js} +1 -1
  132. package/static/app/assets/{System-DcRAq7wj.js → System-Ce-P2YL6.js} +1 -1
  133. package/static/app/assets/arrow-left-DD5jFGHV.js +1 -0
  134. package/static/app/assets/{bot-BK2xQ9mN.js → bot-C5-XIww2.js} +1 -1
  135. package/static/app/assets/{brain-BZNztFBb.js → brain-CFRJUvdX.js} +1 -1
  136. package/static/app/assets/{button-CjueubVZ.js → button-DI1KcQP-.js} +1 -1
  137. package/static/app/assets/circle-check-CY20XMCh.js +1 -0
  138. package/static/app/assets/{circle-pause-HRjSmpyY.js → circle-pause-C8HHyood.js} +1 -1
  139. package/static/app/assets/{circle-play-CMcKDVwu.js → circle-play-Cufc235E.js} +1 -1
  140. package/static/app/assets/{cpu-B_MyTfYr.js → cpu-DW2_JVsv.js} +1 -1
  141. package/static/app/assets/{download-CTy0EByV.js → download-gbdKTBb8.js} +1 -1
  142. package/static/app/assets/{folder-open-DF6bLhTg.js → folder-open-C9ydyX33.js} +1 -1
  143. package/static/app/assets/{hard-drive-CpWHG77C.js → hard-drive-BxNMzBM3.js} +1 -1
  144. package/static/app/assets/index-BovSWRmQ.css +2 -0
  145. package/static/app/assets/{index-Dd6abJHX.js → index-q9XyDY7A.js} +3 -3
  146. package/static/app/assets/{input-bVgIRN3s.js → input-GLD94Y_K.js} +1 -1
  147. package/static/app/assets/{link-2-bg6CG5Vk.js → link-2-B4Y0gz1S.js} +1 -1
  148. package/static/app/assets/{permissionCopy-DFTf1HDZ.js → permissionCopy-CxrV0fvU.js} +1 -1
  149. package/static/app/assets/{primitives-D7D-sQ3T.js → primitives-2ANdAsu2.js} +1 -1
  150. package/static/app/assets/search-DTxtjQ07.js +1 -0
  151. package/static/app/assets/{share-2-BLzo7U4L.js → share-2-DxArfiuI.js} +1 -1
  152. package/static/app/assets/{shield-alert-BmngqnsJ.js → shield-alert-CgftuFFs.js} +1 -1
  153. package/static/app/assets/{textarea-DOSlAQQ3.js → textarea-BHVBAoCr.js} +1 -1
  154. package/static/app/assets/{useFocusTrap-pZhgeee4.js → useFocusTrap-Dzq2j_OG.js} +1 -1
  155. package/static/app/assets/{useMutation-BMDwNk4I.js → useMutation-BcqfMLNq.js} +1 -1
  156. package/static/app/assets/{useQuery-CSjKttRo.js → useQuery-DBzLKCOv.js} +1 -1
  157. package/static/app/assets/{utils-D3u_yv7B.js → utils-B-Aah1bO.js} +1 -1
  158. package/static/app/assets/{workspace-H3bMjYXC.js → workspace-B6fFhoko.js} +1 -1
  159. package/static/app/index.html +4 -4
  160. package/static/sw.js +1 -1
  161. package/desktop/electron/README.md +0 -9
  162. package/desktop/electron/main.cjs +0 -58
  163. package/desktop/electron/preload.cjs +0 -5
  164. package/lattice_brain/archive.py +0 -522
  165. package/lattice_brain/context.py +0 -325
  166. package/lattice_brain/conversations.py +0 -382
  167. package/lattice_brain/core.py +0 -82
  168. package/lattice_brain/graph/_kg_contract.py +0 -249
  169. package/lattice_brain/graph/curator.py +0 -676
  170. package/lattice_brain/graph/discovery.py +0 -595
  171. package/lattice_brain/graph/discovery_index/__init__.py +0 -35
  172. package/lattice_brain/graph/discovery_index/cleanup.py +0 -182
  173. package/lattice_brain/graph/discovery_index/extract.py +0 -137
  174. package/lattice_brain/graph/discovery_index/scan.py +0 -411
  175. package/lattice_brain/graph/discovery_index/upsert.py +0 -495
  176. package/lattice_brain/graph/documents.py +0 -380
  177. package/lattice_brain/graph/fusion.py +0 -395
  178. package/lattice_brain/graph/identity.py +0 -175
  179. package/lattice_brain/graph/image_vectors.py +0 -230
  180. package/lattice_brain/graph/ingest.py +0 -829
  181. package/lattice_brain/graph/network.py +0 -205
  182. package/lattice_brain/graph/proactive.py +0 -724
  183. package/lattice_brain/graph/projection/__init__.py +0 -42
  184. package/lattice_brain/graph/projection/curation.py +0 -500
  185. package/lattice_brain/graph/projection/v2_schema.py +0 -546
  186. package/lattice_brain/graph/provenance.py +0 -524
  187. package/lattice_brain/graph/rerank.py +0 -163
  188. package/lattice_brain/graph/retrieval/__init__.py +0 -54
  189. package/lattice_brain/graph/retrieval/context.py +0 -197
  190. package/lattice_brain/graph/retrieval/graph_view.py +0 -319
  191. package/lattice_brain/graph/retrieval/hybrid.py +0 -488
  192. package/lattice_brain/graph/retrieval/maintenance.py +0 -121
  193. package/lattice_brain/graph/retrieval/signals.py +0 -95
  194. package/lattice_brain/graph/retrieval_docgen.py +0 -253
  195. package/lattice_brain/graph/retrieval_policy.py +0 -180
  196. package/lattice_brain/graph/retrieval_reads.py +0 -769
  197. package/lattice_brain/graph/retrieval_vector/__init__.py +0 -42
  198. package/lattice_brain/graph/retrieval_vector/fingerprint.py +0 -97
  199. package/lattice_brain/graph/retrieval_vector/indexing.py +0 -347
  200. package/lattice_brain/graph/retrieval_vector/search.py +0 -560
  201. package/lattice_brain/graph/retrieval_vector/status.py +0 -374
  202. package/lattice_brain/graph/schema.py +0 -792
  203. package/lattice_brain/graph/store.py +0 -268
  204. package/lattice_brain/graph/vector_index/__init__.py +0 -85
  205. package/lattice_brain/graph/vector_index/base.py +0 -170
  206. package/lattice_brain/graph/vector_index/brute_force.py +0 -114
  207. package/lattice_brain/graph/vector_index/hnsw.py +0 -293
  208. package/lattice_brain/graph/vector_index/jobs.py +0 -287
  209. package/lattice_brain/graph/vector_index/quantized.py +0 -151
  210. package/lattice_brain/graph/vector_index/selector.py +0 -161
  211. package/lattice_brain/graph/write_master.py +0 -308
  212. package/lattice_brain/ingestion/_contract.py +0 -90
  213. package/lattice_brain/ingestion/folder_scan.py +0 -57
  214. package/lattice_brain/ingestion/folders.py +0 -258
  215. package/lattice_brain/ingestion/jobs_api.py +0 -107
  216. package/lattice_brain/ingestion/routing.py +0 -295
  217. package/lattice_brain/ingestion_jobs.py +0 -383
  218. package/lattice_brain/memory.py +0 -102
  219. package/lattice_brain/portability/__init__.py +0 -90
  220. package/lattice_brain/portability/_contract.py +0 -42
  221. package/lattice_brain/portability/backups.py +0 -338
  222. package/lattice_brain/portability/bundles.py +0 -136
  223. package/lattice_brain/portability/constants.py +0 -93
  224. package/lattice_brain/portability/fsops.py +0 -138
  225. package/lattice_brain/portability/service.py +0 -41
  226. package/lattice_brain/portability/sharing.py +0 -714
  227. package/lattice_brain/quality.py +0 -592
  228. package/lattice_brain/retrieval_benchmark_fixtures.py +0 -92
  229. package/lattice_brain/runtime/agent_runtime.py +0 -859
  230. package/lattice_brain/runtime/contracts.py +0 -460
  231. package/lattice_brain/runtime/multi_agent.py +0 -942
  232. package/lattice_brain/runtime/statuses.py +0 -10
  233. package/lattice_brain/sealed_box.py +0 -244
  234. package/lattice_brain/self_model.py +0 -675
  235. package/lattice_brain/sensitivity.py +0 -94
  236. package/lattice_brain/storage/__init__.py +0 -22
  237. package/lattice_brain/storage/base.py +0 -100
  238. package/lattice_brain/storage/docker.py +0 -105
  239. package/lattice_brain/storage/factory.py +0 -31
  240. package/lattice_brain/storage/migration.py +0 -191
  241. package/lattice_brain/storage/postgres.py +0 -123
  242. package/lattice_brain/storage/sqlite.py +0 -143
  243. package/lattice_brain/synthesis.py +0 -824
  244. package/lattice_brain/workflow.py +0 -497
  245. package/latticeai/api/admin.py +0 -471
  246. package/latticeai/api/agent_registry.py +0 -105
  247. package/latticeai/api/agents.py +0 -228
  248. package/latticeai/api/auth.py +0 -360
  249. package/latticeai/api/automation_intelligence.py +0 -401
  250. package/latticeai/api/brain_intelligence.py +0 -199
  251. package/latticeai/api/browser.py +0 -493
  252. package/latticeai/api/change_proposals.py +0 -89
  253. package/latticeai/api/chat.py +0 -572
  254. package/latticeai/api/chat_agent_http.py +0 -901
  255. package/latticeai/api/chat_contracts.py +0 -73
  256. package/latticeai/api/chat_documents.py +0 -276
  257. package/latticeai/api/chat_helpers.py +0 -463
  258. package/latticeai/api/chat_history.py +0 -101
  259. package/latticeai/api/chat_hybrid.py +0 -113
  260. package/latticeai/api/chat_intents.py +0 -646
  261. package/latticeai/api/chat_stream.py +0 -216
  262. package/latticeai/api/chronicle.py +0 -63
  263. package/latticeai/api/command_center.py +0 -51
  264. package/latticeai/api/computer_use.py +0 -485
  265. package/latticeai/api/evidence_actions.py +0 -48
  266. package/latticeai/api/features.py +0 -70
  267. package/latticeai/api/funnel_metrics.py +0 -31
  268. package/latticeai/api/garden.py +0 -34
  269. package/latticeai/api/hooks.py +0 -165
  270. package/latticeai/api/index_jobs.py +0 -145
  271. package/latticeai/api/invitations.py +0 -100
  272. package/latticeai/api/knowledge_graph.py +0 -536
  273. package/latticeai/api/marketplace.py +0 -105
  274. package/latticeai/api/mcp.py +0 -482
  275. package/latticeai/api/memory.py +0 -270
  276. package/latticeai/api/network.py +0 -81
  277. package/latticeai/api/network_boundary.py +0 -225
  278. package/latticeai/api/permission_mode.py +0 -61
  279. package/latticeai/api/permissions.py +0 -410
  280. package/latticeai/api/plugins.py +0 -126
  281. package/latticeai/api/portability.py +0 -391
  282. package/latticeai/api/project_sessions.py +0 -114
  283. package/latticeai/api/realtime.py +0 -118
  284. package/latticeai/api/review_queue.py +0 -364
  285. package/latticeai/api/security_dashboard.py +0 -604
  286. package/latticeai/api/setup.py +0 -319
  287. package/latticeai/api/static_routes.py +0 -351
  288. package/latticeai/api/ui_redirects.py +0 -26
  289. package/latticeai/api/workflow_designer.py +0 -394
  290. package/latticeai/api/workspace.py +0 -856
  291. package/latticeai/api/workspace_scope.py +0 -125
  292. package/latticeai/core/agent/__init__.py +0 -93
  293. package/latticeai/core/agent/_contract.py +0 -79
  294. package/latticeai/core/agent/context.py +0 -57
  295. package/latticeai/core/agent/deps.py +0 -125
  296. package/latticeai/core/agent/execution.py +0 -622
  297. package/latticeai/core/agent/planning.py +0 -145
  298. package/latticeai/core/agent/recovery.py +0 -157
  299. package/latticeai/core/agent/runtime.py +0 -210
  300. package/latticeai/core/agent/verification.py +0 -231
  301. package/latticeai/core/agent_eval.py +0 -739
  302. package/latticeai/core/agent_helpers.py +0 -493
  303. package/latticeai/core/agent_profiles.py +0 -110
  304. package/latticeai/core/agent_prompts.py +0 -171
  305. package/latticeai/core/agent_registry.py +0 -232
  306. package/latticeai/core/agent_state.py +0 -41
  307. package/latticeai/core/agent_trace.py +0 -104
  308. package/latticeai/core/artifact_ledger.py +0 -109
  309. package/latticeai/core/audit.py +0 -260
  310. package/latticeai/core/builtin_hooks.py +0 -105
  311. package/latticeai/core/context_builder.py +0 -394
  312. package/latticeai/core/document_generator.py +0 -103
  313. package/latticeai/core/enterprise.py +0 -157
  314. package/latticeai/core/enterprise_admin.py +0 -158
  315. package/latticeai/core/file_generation/__init__.py +0 -115
  316. package/latticeai/core/file_generation/bundles.py +0 -76
  317. package/latticeai/core/file_generation/extraction.py +0 -154
  318. package/latticeai/core/file_generation/inference.py +0 -235
  319. package/latticeai/core/file_generation/orchestration.py +0 -152
  320. package/latticeai/core/file_generation/prompting.py +0 -117
  321. package/latticeai/core/file_generation/repair.py +0 -114
  322. package/latticeai/core/file_generation/sanitize.py +0 -61
  323. package/latticeai/core/file_generation/validation.py +0 -201
  324. package/latticeai/core/graph_curator.py +0 -11
  325. package/latticeai/core/hooks.py +0 -11
  326. package/latticeai/core/invitations.py +0 -131
  327. package/latticeai/core/legacy_compatibility.py +0 -243
  328. package/latticeai/core/local_embeddings.py +0 -104
  329. package/latticeai/core/logging_safety.py +0 -46
  330. package/latticeai/core/marketplace.py +0 -293
  331. package/latticeai/core/mcp_catalog.py +0 -452
  332. package/latticeai/core/mcp_registry.py +0 -506
  333. package/latticeai/core/multi_agent.py +0 -11
  334. package/latticeai/core/network_boundary.py +0 -168
  335. package/latticeai/core/oidc.py +0 -208
  336. package/latticeai/core/plugins.py +0 -432
  337. package/latticeai/core/product_hardening.py +0 -218
  338. package/latticeai/core/project_sessions.py +0 -337
  339. package/latticeai/core/realtime.py +0 -238
  340. package/latticeai/core/run_explain.py +0 -423
  341. package/latticeai/core/run_store.py +0 -252
  342. package/latticeai/core/timezones.py +0 -80
  343. package/latticeai/core/workflow_engine.py +0 -11
  344. package/latticeai/core/workspace_computer_memory.py +0 -84
  345. package/latticeai/core/workspace_graph_trace.py +0 -161
  346. package/latticeai/core/workspace_indexing.py +0 -102
  347. package/latticeai/core/workspace_memory.py +0 -77
  348. package/latticeai/core/workspace_onboarding.py +0 -104
  349. package/latticeai/core/workspace_os.py +0 -988
  350. package/latticeai/core/workspace_os_constants.py +0 -126
  351. package/latticeai/core/workspace_os_state.py +0 -180
  352. package/latticeai/core/workspace_os_utils.py +0 -69
  353. package/latticeai/core/workspace_permissions.py +0 -101
  354. package/latticeai/core/workspace_plugins.py +0 -97
  355. package/latticeai/core/workspace_relationships.py +0 -99
  356. package/latticeai/core/workspace_reorganization.py +0 -335
  357. package/latticeai/core/workspace_review_items.py +0 -118
  358. package/latticeai/core/workspace_runs.py +0 -732
  359. package/latticeai/core/workspace_skills.py +0 -114
  360. package/latticeai/core/workspace_snapshots.py +0 -198
  361. package/latticeai/core/workspace_timeline.py +0 -110
  362. package/latticeai/integrations/__init__.py +0 -0
  363. package/latticeai/integrations/telegram_bot/__init__.py +0 -123
  364. package/latticeai/integrations/telegram_bot/__main__.py +0 -17
  365. package/latticeai/integrations/telegram_bot/config.py +0 -86
  366. package/latticeai/integrations/telegram_bot/dispatch.py +0 -311
  367. package/latticeai/integrations/telegram_bot/flows.py +0 -478
  368. package/latticeai/integrations/telegram_bot/helpers.py +0 -322
  369. package/latticeai/integrations/telegram_bot/screens.py +0 -394
  370. package/latticeai/runtime/audit_runtime.py +0 -76
  371. package/latticeai/runtime/automation_runtime.py +0 -81
  372. package/latticeai/runtime/chat_wiring.py +0 -141
  373. package/latticeai/runtime/context_runtime.py +0 -66
  374. package/latticeai/runtime/feature_toggle_wiring.py +0 -163
  375. package/latticeai/runtime/history_runtime.py +0 -163
  376. package/latticeai/runtime/history_writer.py +0 -138
  377. package/latticeai/runtime/hooks_runtime.py +0 -77
  378. package/latticeai/runtime/model_wiring.py +0 -68
  379. package/latticeai/runtime/namespace_runtime.py +0 -163
  380. package/latticeai/runtime/network_boundary_wiring.py +0 -128
  381. package/latticeai/runtime/network_config_runtime.py +0 -56
  382. package/latticeai/runtime/permission_mode_wiring.py +0 -119
  383. package/latticeai/runtime/persistence_runtime.py +0 -159
  384. package/latticeai/runtime/platform_runtime_wiring.py +0 -89
  385. package/latticeai/runtime/review_wiring.py +0 -42
  386. package/latticeai/runtime/router_registration.py +0 -689
  387. package/latticeai/runtime/sso_config_runtime.py +0 -128
  388. package/latticeai/runtime/user_key_runtime.py +0 -106
  389. package/latticeai/runtime/web_runtime.py +0 -92
  390. package/latticeai/server_app.py +0 -51
  391. package/latticeai/services/app_context.py +0 -130
  392. package/latticeai/services/automation_execution.py +0 -266
  393. package/latticeai/services/automation_intelligence.py +0 -614
  394. package/latticeai/services/brain_automation.py +0 -191
  395. package/latticeai/services/brain_intelligence/__init__.py +0 -58
  396. package/latticeai/services/brain_intelligence/_contract.py +0 -71
  397. package/latticeai/services/brain_intelligence/consistency.py +0 -193
  398. package/latticeai/services/brain_intelligence/constants.py +0 -47
  399. package/latticeai/services/brain_intelligence/digest.py +0 -258
  400. package/latticeai/services/brain_intelligence/health.py +0 -331
  401. package/latticeai/services/brain_intelligence/proposals.py +0 -264
  402. package/latticeai/services/brain_intelligence/sampling.py +0 -84
  403. package/latticeai/services/brain_intelligence/service.py +0 -48
  404. package/latticeai/services/change_proposals.py +0 -505
  405. package/latticeai/services/chat_service.py +0 -243
  406. package/latticeai/services/chronicle.py +0 -557
  407. package/latticeai/services/cloud_egress_audit.py +0 -85
  408. package/latticeai/services/cloud_extraction.py +0 -129
  409. package/latticeai/services/cloud_streaming.py +0 -268
  410. package/latticeai/services/cloud_token_guard.py +0 -84
  411. package/latticeai/services/command_center.py +0 -548
  412. package/latticeai/services/evidence_actions.py +0 -255
  413. package/latticeai/services/feature_toggles.py +0 -502
  414. package/latticeai/services/folder_watch.py +0 -520
  415. package/latticeai/services/funnel_metrics.py +0 -307
  416. package/latticeai/services/hybrid_chat.py +0 -316
  417. package/latticeai/services/hybrid_context.py +0 -228
  418. package/latticeai/services/hybrid_policy.py +0 -178
  419. package/latticeai/services/ingestion.py +0 -11
  420. package/latticeai/services/interop_bridges.py +0 -978
  421. package/latticeai/services/kg_portability.py +0 -11
  422. package/latticeai/services/local_knowledge.py +0 -465
  423. package/latticeai/services/memory_service/__init__.py +0 -52
  424. package/latticeai/services/memory_service/_contract.py +0 -100
  425. package/latticeai/services/memory_service/brief.py +0 -431
  426. package/latticeai/services/memory_service/constants.py +0 -57
  427. package/latticeai/services/memory_service/maintenance.py +0 -138
  428. package/latticeai/services/memory_service/manager.py +0 -186
  429. package/latticeai/services/memory_service/proof.py +0 -136
  430. package/latticeai/services/memory_service/recall.py +0 -225
  431. package/latticeai/services/memory_service/service.py +0 -48
  432. package/latticeai/services/memory_service/stores.py +0 -110
  433. package/latticeai/services/model_recommendation.py +0 -224
  434. package/latticeai/services/model_runtime/cloud.py +0 -87
  435. package/latticeai/services/multimodal_streaming.py +0 -129
  436. package/latticeai/services/network_boundary_service.py +0 -154
  437. package/latticeai/services/obsidian_bridge.py +0 -609
  438. package/latticeai/services/openai_compatible_adapter.py +0 -101
  439. package/latticeai/services/permission_mode_service.py +0 -170
  440. package/latticeai/services/platform_runtime.py +0 -366
  441. package/latticeai/services/review_queue.py +0 -380
  442. package/latticeai/services/router_context.py +0 -59
  443. package/latticeai/services/run_executor.py +0 -387
  444. package/latticeai/services/self_model_service.py +0 -171
  445. package/latticeai/services/setup_detection.py +0 -81
  446. package/latticeai/services/triggers.py +0 -378
  447. package/latticeai/services/upload_service.py +0 -185
  448. package/latticeai/services/workspace_service.py +0 -171
  449. package/latticeai/setup/__init__.py +0 -25
  450. package/latticeai/setup/auto_setup.py +0 -857
  451. package/latticeai/setup/demo_corpus.py +0 -98
  452. package/latticeai/setup/wizard/__init__.py +0 -126
  453. package/latticeai/setup/wizard/catalog.py +0 -172
  454. package/latticeai/setup/wizard/detect.py +0 -323
  455. package/latticeai/setup/wizard/install.py +0 -348
  456. package/latticeai/setup/wizard/paths.py +0 -168
  457. package/latticeai/setup/wizard/plans.py +0 -74
  458. package/latticeai/setup/wizard/recommend.py +0 -320
  459. package/scripts/bench_agent_smoke.py +0 -409
  460. package/scripts/bench_models.py +0 -540
  461. package/scripts/bench_vector_index.py +0 -295
  462. package/scripts/funnel_soft_gate.py +0 -192
  463. package/scripts/generate_agent_loop_fixtures.py +0 -907
  464. package/scripts/generate_rust_parity_fixtures.py +0 -1000
  465. package/scripts/measure_brain_home_fill.mjs +0 -141
  466. package/scripts/migrate_brain_storage.py +0 -57
  467. package/scripts/parity_fixture_corpus_docgen.py +0 -341
  468. package/scripts/profile_kg.py +0 -355
  469. package/server.py +0 -30
  470. package/static/app/assets/arrow-left-BHYmOTWU.js +0 -1
  471. package/static/app/assets/circle-check-CLeWJr67.js +0 -1
  472. package/static/app/assets/index-DxmOfNRi.css +0 -2
  473. package/static/app/assets/search-BgSVX6NG.js +0 -1
@@ -1,11 +0,0 @@
1
- """Compatibility shim: physically moved to ``lattice_brain.portability``.
2
-
3
- Aliases itself to the physical module so identity, module-level state, and
4
- monkeypatching keep working through the old import path.
5
- """
6
-
7
- import sys
8
-
9
- import lattice_brain.portability as _impl
10
-
11
- sys.modules[__name__] = _impl
@@ -1,465 +0,0 @@
1
- """Local folder knowledge-source API and optional filesystem watcher."""
2
-
3
- import logging
4
- import threading
5
- from pathlib import Path
6
- from typing import Any, Callable, Dict, Optional
7
-
8
- from fastapi import APIRouter, HTTPException, Request
9
- from pydantic import BaseModel, Field
10
-
11
-
12
- class LocalTreeRequest(BaseModel):
13
- path: str
14
- max_items: int = 200
15
- approved: bool = False
16
- approval_token: Optional[str] = None
17
-
18
-
19
- class LocalKnowledgeAuditRequest(BaseModel):
20
- path: str
21
- include_ocr: bool = False
22
- max_files: int = 50_000
23
- approved: bool = False
24
- approval_token: Optional[str] = None
25
-
26
-
27
- class LocalKnowledgeIndexRequest(BaseModel):
28
- path: str
29
- include_ocr: bool = False
30
- watch_enabled: bool = False
31
- max_files: int = 5_000
32
- consent: Dict[str, Any] = Field(default_factory=dict)
33
- approved: bool = False
34
- approval_token: Optional[str] = None
35
-
36
-
37
- class LocalKnowledgeWatchRequest(BaseModel):
38
- source_id: str
39
-
40
-
41
- class _LocalWatchHandler:
42
- def __init__(self, schedule_change: Callable[[], None]):
43
- self._schedule_change = schedule_change
44
-
45
- def on_any_event(self, event): # pragma: no cover - exercised by OS watcher
46
- if getattr(event, "is_directory", False):
47
- return
48
- self._schedule_change()
49
-
50
-
51
- class LocalKnowledgeWatcher:
52
- """Debounced watchdog wrapper for approved local knowledge sources."""
53
-
54
- def __init__(self, get_graph: Callable[[], Any], *, debounce_seconds: float = 5.0, hooks: Any = None):
55
- self._get_graph = get_graph
56
- self._debounce_seconds = debounce_seconds
57
- self._hooks = hooks
58
- self._lock = threading.Lock()
59
- self._watched: Dict[str, Dict[str, Any]] = {}
60
- # watchdog is optional; these stay None when it is not installed.
61
- self._observer_cls: Optional[Any] = None
62
- self._event_handler_base: Optional[Any] = None
63
- self._import_error = ""
64
- try:
65
- from watchdog.events import FileSystemEventHandler
66
- from watchdog.observers import Observer
67
-
68
- self._observer_cls = Observer
69
- self._event_handler_base = FileSystemEventHandler
70
- except Exception as exc: # pragma: no cover - depends on optional dependency
71
- self._import_error = str(exc)
72
-
73
- @property
74
- def available(self) -> bool:
75
- return self._observer_cls is not None and self._event_handler_base is not None
76
-
77
- def status(self) -> Dict[str, Any]:
78
- with self._lock:
79
- active = {
80
- source_id: {
81
- "root_path": item["source"].get("root_path"),
82
- "last_event_at": item.get("last_event_at"),
83
- "last_indexed_at": item.get("last_indexed_at"),
84
- "last_error": item.get("last_error"),
85
- }
86
- for source_id, item in self._watched.items()
87
- }
88
- return {
89
- "available": self.available,
90
- "error": "" if self.available else self._import_error or "watchdog is not installed",
91
- "debounce_seconds": self._debounce_seconds,
92
- "active": active,
93
- }
94
-
95
- def restore_enabled_sources(self) -> Dict[str, Any]:
96
- graph = self._get_graph()
97
- if graph is None:
98
- return {"restored": 0, "available": self.available}
99
- restored = 0
100
- try:
101
- for source in graph.local_sources().get("sources", []):
102
- if source.get("watch_enabled"):
103
- consent = source.get("consent") or {}
104
- restored_source = {
105
- **source,
106
- # Older sources had no explicit scope. Their local
107
- # knowledge belongs to the personal Brain, never every
108
- # workspace.
109
- "workspace_id": source.get("workspace_id") or consent.get("workspace_id") or "personal",
110
- }
111
- result = self.start_source(restored_source)
112
- if result.get("watching"):
113
- restored += 1
114
- except Exception as exc:
115
- logging.warning("local knowledge watcher restore failed: %s", exc)
116
- return {"restored": restored, "available": self.available}
117
-
118
- def start_source(self, source: Dict[str, Any]) -> Dict[str, Any]:
119
- source_id = str(source.get("id") or "")
120
- root_path = str(source.get("root_path") or "")
121
- if not source_id or not root_path:
122
- return {"watching": False, "error": "source_id and root_path are required"}
123
- if not self.available:
124
- return {"watching": False, "source_id": source_id, "error": self._import_error or "watchdog is not installed"}
125
- root = Path(root_path).expanduser().resolve()
126
- if not root.exists() or not root.is_dir():
127
- return {"watching": False, "source_id": source_id, "error": "source folder is not available"}
128
-
129
- self.stop_source(source_id)
130
-
131
- handler_base = self._event_handler_base
132
- observer_cls = self._observer_cls
133
- if handler_base is None or observer_cls is None:
134
- return {
135
- "watching": False,
136
- "source_id": source_id,
137
- "error": self._import_error or "watchdog is not installed",
138
- }
139
-
140
- class Handler(_LocalWatchHandler, handler_base): # type: ignore[misc, valid-type]
141
- def __init__(handler_self):
142
- handler_base.__init__(handler_self) # type: ignore[misc]
143
- _LocalWatchHandler.__init__(handler_self, lambda: self._schedule(source_id))
144
-
145
- observer = observer_cls()
146
- try:
147
- observer.schedule(Handler(), str(root), recursive=True)
148
- observer.start()
149
- except Exception as exc:
150
- logging.warning("local knowledge watcher start failed for %s: %s", root, exc)
151
- return {"watching": False, "source_id": source_id, "error": str(exc)}
152
-
153
- with self._lock:
154
- self._watched[source_id] = {
155
- "observer": observer,
156
- "timer": None,
157
- "source": dict(source),
158
- "last_event_at": None,
159
- "last_indexed_at": None,
160
- "last_error": None,
161
- }
162
- return {"watching": True, "source_id": source_id, "root_path": str(root)}
163
-
164
- def stop_source(self, source_id: str) -> Dict[str, Any]:
165
- with self._lock:
166
- item = self._watched.pop(source_id, None)
167
- if not item:
168
- return {"stopped": False, "source_id": source_id}
169
- timer = item.get("timer")
170
- if timer:
171
- timer.cancel()
172
- observer = item.get("observer")
173
- try:
174
- if observer is None:
175
- raise RuntimeError("watch entry has no observer")
176
- observer.stop()
177
- observer.join(timeout=3)
178
- except Exception as exc:
179
- logging.warning("local knowledge watcher stop failed for %s: %s", source_id, exc)
180
- return {"stopped": True, "source_id": source_id}
181
-
182
- def stop_all(self) -> None:
183
- for source_id in list(self.status().get("active", {}).keys()):
184
- self.stop_source(source_id)
185
-
186
- def _schedule(self, source_id: str) -> None:
187
- with self._lock:
188
- item = self._watched.get(source_id)
189
- if not item:
190
- return
191
- timer = item.get("timer")
192
- if timer:
193
- timer.cancel()
194
- item["last_event_at"] = _now_seconds()
195
- timer = threading.Timer(self._debounce_seconds, self._run_index, args=(source_id,))
196
- timer.daemon = True
197
- item["timer"] = timer
198
- timer.start()
199
-
200
- def _run_index(self, source_id: str) -> None:
201
- with self._lock:
202
- item = self._watched.get(source_id)
203
- if not item:
204
- return
205
- source = dict(item["source"])
206
- item["timer"] = None
207
- graph = self._get_graph()
208
- if graph is None:
209
- return
210
- consent = source.get("consent") or {}
211
- root = source.get("root_path")
212
- if self._hooks is not None:
213
- self._hooks.fire_hook("pre_index", "folder.reindex",
214
- payload={"source_id": source_id, "root_path": root, "trigger": "watch"})
215
- try:
216
- result = graph.index_local_folder(
217
- Path(source["root_path"]),
218
- include_ocr=bool(source.get("include_ocr")),
219
- watch_enabled=True,
220
- user_email=consent.get("approved_by"),
221
- workspace_id=source.get("workspace_id") or consent.get("workspace_id") or "personal",
222
- consent=consent,
223
- source_id_override=source_id,
224
- )
225
- with self._lock:
226
- if source_id in self._watched:
227
- self._watched[source_id]["last_indexed_at"] = _now_seconds()
228
- self._watched[source_id]["last_error"] = None
229
- if self._hooks is not None:
230
- self._hooks.fire_hook("post_index", "folder.reindex",
231
- payload={"source_id": source_id, "root_path": root, "trigger": "watch", "status": "ok"})
232
- counts = (result.get("counts") or {}) if isinstance(result, dict) else {}
233
- if int(counts.get("indexed") or 0) + int(counts.get("deleted") or 0) > 0:
234
- self._hooks.fire_hook(
235
- "post_tool",
236
- "tool.kg_ingest.local_folder",
237
- payload={
238
- "tool": "kg_ingest.local_folder",
239
- "status": "ok",
240
- "source": "ingestion",
241
- "source_type": "local_folder",
242
- "source_id": source_id,
243
- },
244
- user_email=consent.get("approved_by"),
245
- workspace_id=source.get("workspace_id"),
246
- )
247
- except Exception as exc:
248
- logging.warning("local knowledge watcher reindex failed for %s: %s", source_id, exc)
249
- with self._lock:
250
- if source_id in self._watched:
251
- self._watched[source_id]["last_error"] = str(exc)
252
- if self._hooks is not None:
253
- self._hooks.fire_hook("post_index", "folder.reindex",
254
- payload={"source_id": source_id, "root_path": root, "trigger": "watch", "status": "error", "error": str(exc)})
255
-
256
-
257
- def _now_seconds() -> float:
258
- import time
259
-
260
- return time.time()
261
-
262
-
263
- def create_local_knowledge_router(
264
- *,
265
- get_graph: Callable[[], Any],
266
- require_graph: Callable[[], None],
267
- require_user: Callable[[Request], str],
268
- require_local_user: Callable[[Request], str],
269
- local_permission_response: Callable[..., dict],
270
- require_local_approval: Callable[..., None],
271
- watcher: Optional[LocalKnowledgeWatcher] = None,
272
- hooks: Any = None,
273
- workspace_service: Any = None,
274
- ) -> APIRouter:
275
- router = APIRouter()
276
-
277
- def graph():
278
- require_graph()
279
- return get_graph()
280
-
281
- def write_workspace(request: Request, user: str) -> Optional[str]:
282
- requested = request.headers.get("X-Workspace-Id")
283
- requested = requested.strip() if requested and requested.strip() else None
284
- if workspace_service is None:
285
- return requested
286
- try:
287
- return workspace_service.resolve_write_scope(requested, user or None)
288
- except PermissionError as exc:
289
- raise HTTPException(status_code=403, detail=str(exc)) from exc
290
-
291
- @router.get("/knowledge-graph/local/roots")
292
- async def knowledge_graph_local_roots(request: Request):
293
- require_user(request)
294
- return graph().discover_local_roots()
295
-
296
- @router.get("/knowledge-graph/local/sources")
297
- async def knowledge_graph_local_sources(request: Request):
298
- require_user(request)
299
- payload = graph().local_sources()
300
- watch_status: Dict[str, Any] = (
301
- watcher.status() if watcher else {"available": False, "active": {}}
302
- )
303
- active: Dict[str, Any] = dict(watch_status.get("active") or {})
304
- for source in payload.get("sources", []):
305
- source["watch_active"] = source.get("id") in active
306
- source["watch_status"] = active.get(source.get("id"))
307
- payload["watch"] = watch_status
308
- return payload
309
-
310
- @router.get("/knowledge-graph/local/health")
311
- async def knowledge_graph_local_health(request: Request, error_samples: int = 3):
312
- """Per-folder memory state (v9.9.7): indexing coverage, failures with
313
- their stored reasons, and watch state.
314
-
315
- Vector freshness rides along as an explicitly **global** figure — the
316
- vector index is not per-folder, and claiming otherwise would invent a
317
- number.
318
- """
319
- require_user(request)
320
- kg = graph()
321
- payload = kg.local_source_health(error_samples=error_samples)
322
- watch_status: Dict[str, Any] = (
323
- watcher.status() if watcher else {"available": False, "active": {}}
324
- )
325
- active = dict(watch_status.get("active") or {})
326
- for folder in payload.get("folders", []):
327
- folder["watch_active"] = folder.get("id") in active
328
- payload["watch"] = watch_status
329
- try:
330
- payload["vector_freshness_global"] = kg.vector_freshness()
331
- except Exception as exc: # noqa: BLE001 — one missing signal, not a 500
332
- payload["vector_freshness_global"] = {
333
- "status": "unavailable", "detail": str(exc),
334
- "pending_items": 0, "total_items": 0,
335
- }
336
- return payload
337
-
338
- @router.get("/knowledge-graph/local/watch/status")
339
- async def knowledge_graph_local_watch_status(request: Request):
340
- require_user(request)
341
- graph()
342
- return watcher.status() if watcher else {"available": False, "active": {}, "error": "watcher unavailable"}
343
-
344
- @router.post("/knowledge-graph/local/watch/stop")
345
- async def knowledge_graph_local_watch_stop(req: LocalKnowledgeWatchRequest, request: Request):
346
- require_user(request)
347
- kg = graph()
348
- try:
349
- kg.set_local_source_watch(req.source_id, False)
350
- except ValueError as exc:
351
- raise HTTPException(status_code=404, detail=str(exc)) from exc
352
- result = watcher.stop_source(req.source_id) if watcher else {"stopped": False, "source_id": req.source_id}
353
- return {"status": "ok", "watch": result}
354
-
355
- @router.post("/knowledge-graph/local/tree")
356
- async def knowledge_graph_local_tree(req: LocalTreeRequest, request: Request):
357
- current_user = require_local_user(request)
358
- kg = graph()
359
- if not req.approved:
360
- return local_permission_response(req.path, "list", current_user)
361
- require_local_approval(token=req.approval_token, path=req.path, action="list", user_email=current_user)
362
- try:
363
- return kg.preview_local_tree(Path(req.path), max_items=req.max_items)
364
- except ValueError as exc:
365
- raise HTTPException(status_code=400, detail=str(exc)) from exc
366
-
367
- @router.post("/knowledge-graph/local/audit")
368
- async def knowledge_graph_local_audit(req: LocalKnowledgeAuditRequest, request: Request):
369
- current_user = require_local_user(request)
370
- kg = graph()
371
- if not req.approved:
372
- return local_permission_response(req.path, "list", current_user)
373
- require_local_approval(token=req.approval_token, path=req.path, action="list", user_email=current_user)
374
- try:
375
- return kg.audit_local_folder(Path(req.path), include_ocr=req.include_ocr, max_files=req.max_files)
376
- except ValueError as exc:
377
- raise HTTPException(status_code=400, detail=str(exc)) from exc
378
-
379
- @router.post("/knowledge-graph/local/index")
380
- async def knowledge_graph_local_index(req: LocalKnowledgeIndexRequest, request: Request):
381
- current_user = require_local_user(request)
382
- workspace_id = write_workspace(request, current_user)
383
- kg = graph()
384
- if not req.approved:
385
- return local_permission_response(req.path, "read", current_user)
386
- require_local_approval(token=req.approval_token, path=req.path, action="read", user_email=current_user)
387
- consent = {
388
- **(req.consent or {}),
389
- "approved_by": current_user,
390
- "workspace_id": workspace_id or "personal",
391
- }
392
- source_id_override = None
393
- try:
394
- target_root = Path(req.path).expanduser().resolve()
395
- target_scope = workspace_id or "personal"
396
- for source in kg.local_sources().get("sources", []):
397
- source_consent = source.get("consent") or {}
398
- source_scope = source_consent.get("workspace_id") or "personal"
399
- source_root_value = str(source.get("root_path") or "").strip()
400
- if not source_root_value:
401
- continue
402
- source_root = Path(source_root_value).expanduser().resolve()
403
- if source_scope == target_scope and source_root == target_root:
404
- source_id_override = source.get("id")
405
- break
406
- except Exception:
407
- # Source reuse is a compatibility optimization; indexing still has
408
- # a deterministic workspace-scoped ID when discovery is unavailable.
409
- source_id_override = None
410
- if hooks is not None:
411
- hooks.fire_hook("pre_index", "folder.index",
412
- payload={"root_path": req.path, "trigger": "connect", "watch": req.watch_enabled},
413
- user_email=current_user, workspace_id=workspace_id)
414
- try:
415
- result = kg.index_local_folder(
416
- Path(req.path),
417
- include_ocr=req.include_ocr,
418
- watch_enabled=req.watch_enabled,
419
- user_email=current_user,
420
- workspace_id=workspace_id or "personal",
421
- consent=consent,
422
- max_files=req.max_files,
423
- source_id_override=source_id_override,
424
- )
425
- except ValueError as exc:
426
- if hooks is not None:
427
- hooks.fire_hook("post_index", "folder.index",
428
- payload={"root_path": req.path, "trigger": "connect", "status": "error", "error": str(exc)},
429
- user_email=current_user, workspace_id=workspace_id)
430
- raise HTTPException(status_code=400, detail=str(exc)) from exc
431
- if hooks is not None:
432
- _idx = (result.get("index") or {}) if isinstance(result, dict) else {}
433
- hooks.fire_hook("post_index", "folder.index",
434
- payload={"root_path": req.path, "trigger": "connect", "status": "ok",
435
- "indexed": _idx.get("indexed") or (result or {}).get("indexed")},
436
- user_email=current_user, workspace_id=workspace_id)
437
- counts = (result.get("counts") or {}) if isinstance(result, dict) else {}
438
- if int(counts.get("indexed") or 0) + int(counts.get("deleted") or 0) > 0:
439
- hooks.fire_hook(
440
- "post_tool",
441
- "tool.kg_ingest.local_folder",
442
- payload={
443
- "tool": "kg_ingest.local_folder",
444
- "status": "ok",
445
- "source": "ingestion",
446
- "source_type": "local_folder",
447
- "source_id": (result.get("source") or {}).get("id") if isinstance(result, dict) else None,
448
- },
449
- user_email=current_user,
450
- workspace_id=workspace_id,
451
- )
452
-
453
- if watcher:
454
- if req.watch_enabled:
455
- source_payload = {
456
- **result.get("source", {}),
457
- "workspace_id": workspace_id or "personal",
458
- "consent": consent,
459
- }
460
- result["watch"] = watcher.start_source(source_payload)
461
- else:
462
- result["watch"] = watcher.stop_source(result.get("source", {}).get("id", ""))
463
- return result
464
-
465
- return router
@@ -1,52 +0,0 @@
1
- """Long-Term Memory platform + Memory Manager (v3.2.0).
2
-
3
- Parts 7, 8 and 13. Lattice AI already persists memory in several real stores;
4
- before this service they were unrelated. ``MemoryService`` unifies them behind
5
- one façade and adds a Memory Manager that reports usage / sources / health /
6
- size / type and supports recall / inspect / prune / compact / rebuild / clear.
7
-
8
- Memory tiers and their real backing store (nothing is fabricated — a tier with
9
- no backing reports ``unavailable``):
10
-
11
- * **workspace** — personal workspace memories (``WorkspaceOS`` memories)
12
- * **project** — memories scoped to a non-personal (organization) workspace
13
- * **agent** — agent memory snapshots captured during runs
14
- * **conversation** — chat history conversations
15
- * **graph** — Knowledge Graph nodes (entities + relations)
16
- * **vector** — local embedding vector index
17
-
18
- The service never invents counts or health: every number is read from the
19
- underlying store, and missing stores surface as ``unavailable``.
20
-
21
- Split into cohesive submodules in v11.3.0 (no behaviour change): ``constants``
22
- (tier vocabulary + the visual passthrough), ``stores`` (reads over the real
23
- backends), ``manager`` (the cross-tier report), ``brief`` and ``proof`` (the
24
- home screen's briefing and its evidence), ``recall`` (unified retrieval and
25
- per-tier inspection), ``maintenance`` (the mutating half), and ``service`` (the
26
- composed class). This module re-exports every name the single file exposed, so
27
- ``latticeai.services.memory_service.X`` keeps working.
28
- """
29
-
30
- from __future__ import annotations
31
-
32
- # The single file had no ``__all__``, so its public surface was "every module
33
- # global" — including the names it imported for its own use. The redundant-alias
34
- # form reproduces exactly that surface and marks each name as a deliberate
35
- # re-export rather than a leftover import.
36
- #
37
- # Stubbing note: rebinding one of these *here* changes only this module's name.
38
- # The submodule that calls it holds its own reference, so a test standing in for
39
- # ``LOGGER`` or ``_now`` patches the submodule that uses it.
40
- # noqa on the next line, not a redundant alias: the single file exposed this
41
- # name *renamed* (``memory_service._now``), and reproducing that surface exactly
42
- # is the point — importing it as ``now_iso`` would add a name the module never had.
43
- from latticeai.core.timeutil import now_iso as _now # noqa: F401
44
- from latticeai.core.workspace_os_utils import _file_size as _file_size
45
-
46
- from .constants import LOGGER as LOGGER
47
- from .constants import MAX_RECALL_THUMBNAIL_CHARS as MAX_RECALL_THUMBNAIL_CHARS
48
- from .constants import TIERS as TIERS
49
- from .constants import WORKSPACE_KINDS as WORKSPACE_KINDS
50
- from .constants import MemoryServiceError as MemoryServiceError
51
- from .constants import _visual_fields as _visual_fields
52
- from .service import MemoryService as MemoryService
@@ -1,100 +0,0 @@
1
- """The seam the memory mixins share.
2
-
3
- ``MemoryService`` is assembled from the store-read, manager, brief, proof,
4
- recall and maintenance mixins. Every one of them reads constructor state it
5
- does not own, and most of them call methods another mixin implements. That
6
- contract existed as an unwritten convention inside one class; this module
7
- writes it down.
8
-
9
- Typing-only, exactly like :mod:`lattice_brain.portability._contract`: the
10
- declarations below are never executed as behaviour — each body is a bare
11
- ``raise NotImplementedError`` that the composed class always overrides — so the
12
- MRO and every method resolution stay what the single-file class had. Adding a
13
- cross-mixin call without declaring it here is a type error.
14
- """
15
-
16
- from __future__ import annotations
17
-
18
- from pathlib import Path
19
- from typing import Any, Dict, List, Optional
20
-
21
-
22
- class MemoryCore:
23
- """What any memory mixin may assume about ``self``.
24
-
25
- Members are declared, not implemented: the implementation lives in
26
- ``service.py`` (constructor state) or in whichever mixin owns the method.
27
- """
28
-
29
- # ── State owned by MemoryService.__init__ ────────────────────────────────
30
- _store: Any
31
- _kg: Any
32
- _enable_graph: bool
33
- _data_dir: Path
34
- _history_file: Path
35
- _conversation_store: Any
36
-
37
- # ── stores.py: the reads every other surface is built on ─────────────────
38
- def _workspace_memories(
39
- self, *, user_email: Optional[str], workspace_id: Optional[str]
40
- ) -> List[Dict[str, Any]]:
41
- raise NotImplementedError
42
-
43
- def _all_memories(self) -> List[Dict[str, Any]]:
44
- raise NotImplementedError
45
-
46
- def _snapshots(self, *, workspace_id: Optional[str]) -> List[Dict[str, Any]]:
47
- raise NotImplementedError
48
-
49
- def _conversations(self) -> List[Dict[str, Any]]:
50
- raise NotImplementedError
51
-
52
- def _scoped_conversations(
53
- self, *, user_email: Optional[str], workspace_id: Optional[str]
54
- ) -> List[Dict[str, Any]]:
55
- raise NotImplementedError
56
-
57
- def _kg_stats(self) -> Optional[Dict[str, Any]]:
58
- raise NotImplementedError
59
-
60
- def _kg_index(self) -> Optional[Dict[str, Any]]:
61
- raise NotImplementedError
62
-
63
- # ── manager.py: the cross-tier report the brief and the proof rest on ────
64
- def manager(
65
- self, *, user_email: Optional[str] = None, workspace_id: Optional[str] = None
66
- ) -> Dict[str, Any]:
67
- raise NotImplementedError
68
-
69
- # ── proof.py / recall.py: what the brief composes ────────────────────────
70
- def brain_proof(
71
- self,
72
- *,
73
- user_email: Optional[str] = None,
74
- workspace_id: Optional[str] = None,
75
- active_model: Optional[str] = None,
76
- recall_query: str = "",
77
- limit: int = 3,
78
- ) -> Dict[str, Any]:
79
- raise NotImplementedError
80
-
81
- def recall(
82
- self,
83
- query: str,
84
- *,
85
- user_email: Optional[str] = None,
86
- workspace_id: Optional[str] = None,
87
- limit: int = 20,
88
- ) -> Dict[str, Any]:
89
- raise NotImplementedError
90
-
91
- # ── maintenance.py: clear() delegates every scope to prune() ─────────────
92
- def prune(
93
- self,
94
- *,
95
- ids: Optional[List[str]] = None,
96
- kind: Optional[str] = None,
97
- user_email: Optional[str] = None,
98
- workspace_id: Optional[str] = None,
99
- ) -> Dict[str, Any]:
100
- raise NotImplementedError