ltcai 11.5.2 → 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 (439) hide show
  1. package/README.md +91 -148
  2. package/bin/ltcai.js +234 -24
  3. package/docs/CHANGELOG.md +75 -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/MULTI_AGENT_RUNTIME.md +12 -5
  8. package/docs/ONBOARDING.md +1 -1
  9. package/docs/OPERATIONS.md +6 -3
  10. package/docs/REALTIME_COLLABORATION.md +1 -1
  11. package/docs/TRUST_MODEL.md +1 -1
  12. package/docs/WHY_LATTICE.md +1 -1
  13. package/docs/WORKFLOW_DESIGNER.md +3 -2
  14. package/docs/kg-schema.md +1 -1
  15. package/docs/v11.6.0_ONE_DOOR_PLAN.md +170 -0
  16. package/lattice_brain/__init__.py +42 -79
  17. package/lattice_brain/graph/__init__.py +9 -24
  18. package/lattice_brain/graph/_kg_common/__init__.py +13 -24
  19. package/lattice_brain/ingestion/__init__.py +19 -58
  20. package/lattice_brain/ingestion/pipeline.py +20 -398
  21. package/lattice_brain/multimodal/__init__.py +7 -18
  22. package/lattice_brain/multimodal/images.py +6 -264
  23. package/lattice_brain/multimodal/video.py +8 -247
  24. package/lattice_brain/runtime/__init__.py +8 -79
  25. package/lattice_brain/runtime/hooks.py +22 -584
  26. package/latticeai/__init__.py +1 -1
  27. package/latticeai/api/agent_worker_seam.py +7 -80
  28. package/latticeai/api/health.py +6 -20
  29. package/latticeai/api/local_files.py +16 -613
  30. package/latticeai/api/models.py +12 -87
  31. package/latticeai/api/search.py +17 -255
  32. package/latticeai/api/tools.py +69 -750
  33. package/latticeai/api/voice_capture.py +8 -70
  34. package/latticeai/api/worker_compute.py +842 -0
  35. package/latticeai/api/worker_seams.py +216 -0
  36. package/latticeai/app_factory.py +23 -232
  37. package/latticeai/cli/entrypoint.py +36 -249
  38. package/latticeai/core/agent_permission.py +16 -91
  39. package/latticeai/core/messages.py +89 -531
  40. package/latticeai/runtime/access_runtime.py +0 -14
  41. package/latticeai/runtime/bootstrap.py +10 -21
  42. package/latticeai/runtime/brain_runtime.py +35 -43
  43. package/latticeai/runtime/build_phases/__init__.py +21 -37
  44. package/latticeai/runtime/build_phases/features.py +99 -389
  45. package/latticeai/runtime/build_phases/foundation.py +82 -392
  46. package/latticeai/runtime/build_phases/web.py +91 -408
  47. package/latticeai/runtime/build_phases/worker_profile.py +244 -0
  48. package/latticeai/runtime/lifespan_runtime.py +7 -16
  49. package/latticeai/runtime/platform_services_runtime.py +1 -15
  50. package/latticeai/runtime/runtime_context.py +13 -130
  51. package/latticeai/runtime/security_runtime.py +10 -103
  52. package/latticeai/services/architecture_readiness.py +82 -43
  53. package/latticeai/services/model_runtime/__init__.py +2 -11
  54. package/latticeai/services/model_runtime/service.py +4 -28
  55. package/latticeai/services/p_reinforce.py +10 -261
  56. package/latticeai/services/product_readiness.py +31 -38
  57. package/latticeai/services/search_service.py +37 -795
  58. package/latticeai/services/tool_dispatch.py +30 -386
  59. package/latticeai/services/voice_capture.py +13 -107
  60. package/latticeai/tools/__init__.py +22 -49
  61. package/latticeai/tools/commands.py +0 -163
  62. package/latticeai/tools/computer.py +0 -39
  63. package/latticeai/tools/documents.py +1 -134
  64. package/latticeai/tools/filesystem.py +1 -247
  65. package/latticeai/tools/knowledge.py +1 -52
  66. package/latticeai/tools/local_files.py +0 -20
  67. package/latticeai/worker_app.py +75 -0
  68. package/package.json +2 -3
  69. package/requirements.txt +0 -5
  70. package/scripts/agent_eval.py +16 -28
  71. package/scripts/brain_quality_eval.py +20 -183
  72. package/scripts/bump_version.py +5 -5
  73. package/scripts/check_current_release_docs.mjs +7 -4
  74. package/scripts/check_openapi_drift.mjs +10 -0
  75. package/scripts/check_server_i18n.mjs +2 -18
  76. package/scripts/compose_openapi.py +377 -0
  77. package/scripts/export_openapi.py +32 -4
  78. package/scripts/gen_messages_catalog_fixture.py +302 -0
  79. package/scripts/gen_openapi_fragments.py +365 -0
  80. package/scripts/gen_redact_fixture.py +196 -0
  81. package/scripts/gen_worker_allowlist_fixture.py +115 -0
  82. package/scripts/generate_agent_parity_fixtures.py +33 -14
  83. package/scripts/openapi_route_families.json +2161 -0
  84. package/scripts/release_screen_claims.json +21 -0
  85. package/scripts/run_integration_tests.mjs +134 -29
  86. package/scripts/run_sidecar_e2e.mjs +104 -11
  87. package/scripts/wheel_smoke.py +32 -22
  88. package/src-tauri/Cargo.lock +375 -9
  89. package/src-tauri/Cargo.toml +1 -1
  90. package/src-tauri/src/backend.rs +151 -45
  91. package/src-tauri/src/main.rs +18 -18
  92. package/src-tauri/src/topology.rs +58 -88
  93. package/src-tauri/tauri.conf.json +1 -2
  94. package/static/app/asset-manifest.json +41 -41
  95. package/static/app/assets/{Act-DcQizkl1.js → Act-CToZnOHz.js} +1 -1
  96. package/static/app/assets/{AdminConsole-cf4npybT.js → AdminConsole-D5kbrBu8.js} +1 -1
  97. package/static/app/assets/{Brain-3VCSHFcn.js → Brain-C6zCdv4S.js} +1 -1
  98. package/static/app/assets/{BrainHome-Qm8eaztx.js → BrainHome-D4n3EDUt.js} +1 -1
  99. package/static/app/assets/{BrainSignals-DS9BtKOW.js → BrainSignals-CzeZ-vQ9.js} +1 -1
  100. package/static/app/assets/{Capture-DiQ219jW.js → Capture-DPcyTczq.js} +1 -1
  101. package/static/app/assets/{Chronicle-BGvuAchH.js → Chronicle-D3Nx-oWS.js} +1 -1
  102. package/static/app/assets/{CommandPalette-Bqhm0Urn.js → CommandPalette-DPPvpp28.js} +1 -1
  103. package/static/app/assets/{Library-BV6NnF0a.js → Library-Co2qTu3I.js} +1 -1
  104. package/static/app/assets/{LivingBrain-GzenJchP.js → LivingBrain-Bsmzwy8_.js} +1 -1
  105. package/static/app/assets/{ProductFlow-DEP6-vML.js → ProductFlow-CBLdmesT.js} +1 -1
  106. package/static/app/assets/{ReviewCard-CNZ7XjWG.js → ReviewCard-CfR6DLs7.js} +1 -1
  107. package/static/app/assets/{System-CieofHQa.js → System-Ce-P2YL6.js} +1 -1
  108. package/static/app/assets/arrow-left-DD5jFGHV.js +1 -0
  109. package/static/app/assets/{bot-B_K1Tdmw.js → bot-C5-XIww2.js} +1 -1
  110. package/static/app/assets/{brain-DWyaV1L1.js → brain-CFRJUvdX.js} +1 -1
  111. package/static/app/assets/{button-aTn4s84A.js → button-DI1KcQP-.js} +1 -1
  112. package/static/app/assets/circle-check-CY20XMCh.js +1 -0
  113. package/static/app/assets/{circle-pause-xKgeGXkT.js → circle-pause-C8HHyood.js} +1 -1
  114. package/static/app/assets/{circle-play-DkT6tYPX.js → circle-play-Cufc235E.js} +1 -1
  115. package/static/app/assets/{cpu-85xYObUC.js → cpu-DW2_JVsv.js} +1 -1
  116. package/static/app/assets/{download-B5Fm7YXo.js → download-gbdKTBb8.js} +1 -1
  117. package/static/app/assets/{folder-open-kk2Xa52u.js → folder-open-C9ydyX33.js} +1 -1
  118. package/static/app/assets/{hard-drive-DkA3zBW_.js → hard-drive-BxNMzBM3.js} +1 -1
  119. package/static/app/assets/index-BovSWRmQ.css +2 -0
  120. package/static/app/assets/{index-BMPdTmlY.js → index-q9XyDY7A.js} +3 -3
  121. package/static/app/assets/{input-B0nRf2jO.js → input-GLD94Y_K.js} +1 -1
  122. package/static/app/assets/{link-2-Dwb4gnTc.js → link-2-B4Y0gz1S.js} +1 -1
  123. package/static/app/assets/{permissionCopy-CQDUBrOZ.js → permissionCopy-CxrV0fvU.js} +1 -1
  124. package/static/app/assets/{primitives-SNp0LRJz.js → primitives-2ANdAsu2.js} +1 -1
  125. package/static/app/assets/search-DTxtjQ07.js +1 -0
  126. package/static/app/assets/{share-2-BsrxFglO.js → share-2-DxArfiuI.js} +1 -1
  127. package/static/app/assets/{shield-alert-5BStfp2_.js → shield-alert-CgftuFFs.js} +1 -1
  128. package/static/app/assets/{textarea-Cg8IUA-k.js → textarea-BHVBAoCr.js} +1 -1
  129. package/static/app/assets/{useFocusTrap-CYKvE46M.js → useFocusTrap-Dzq2j_OG.js} +1 -1
  130. package/static/app/assets/{useMutation-CSn9t1op.js → useMutation-BcqfMLNq.js} +1 -1
  131. package/static/app/assets/{useQuery-CY2OI2uy.js → useQuery-DBzLKCOv.js} +1 -1
  132. package/static/app/assets/{utils-Ddol2RWD.js → utils-B-Aah1bO.js} +1 -1
  133. package/static/app/assets/{workspace-BqDwOz_p.js → workspace-B6fFhoko.js} +1 -1
  134. package/static/app/index.html +4 -4
  135. package/static/sw.js +1 -1
  136. package/lattice_brain/archive.py +0 -522
  137. package/lattice_brain/context.py +0 -325
  138. package/lattice_brain/conversations.py +0 -382
  139. package/lattice_brain/core.py +0 -82
  140. package/lattice_brain/graph/_kg_contract.py +0 -249
  141. package/lattice_brain/graph/curator.py +0 -676
  142. package/lattice_brain/graph/discovery.py +0 -595
  143. package/lattice_brain/graph/discovery_index/__init__.py +0 -35
  144. package/lattice_brain/graph/discovery_index/cleanup.py +0 -182
  145. package/lattice_brain/graph/discovery_index/extract.py +0 -137
  146. package/lattice_brain/graph/discovery_index/scan.py +0 -411
  147. package/lattice_brain/graph/discovery_index/upsert.py +0 -495
  148. package/lattice_brain/graph/documents.py +0 -380
  149. package/lattice_brain/graph/fusion.py +0 -395
  150. package/lattice_brain/graph/identity.py +0 -175
  151. package/lattice_brain/graph/image_vectors.py +0 -230
  152. package/lattice_brain/graph/ingest.py +0 -829
  153. package/lattice_brain/graph/network.py +0 -205
  154. package/lattice_brain/graph/proactive.py +0 -724
  155. package/lattice_brain/graph/projection/__init__.py +0 -42
  156. package/lattice_brain/graph/projection/curation.py +0 -500
  157. package/lattice_brain/graph/projection/v2_schema.py +0 -518
  158. package/lattice_brain/graph/provenance.py +0 -524
  159. package/lattice_brain/graph/rerank.py +0 -163
  160. package/lattice_brain/graph/retrieval/__init__.py +0 -54
  161. package/lattice_brain/graph/retrieval/context.py +0 -197
  162. package/lattice_brain/graph/retrieval/graph_view.py +0 -319
  163. package/lattice_brain/graph/retrieval/hybrid.py +0 -488
  164. package/lattice_brain/graph/retrieval/maintenance.py +0 -121
  165. package/lattice_brain/graph/retrieval/signals.py +0 -95
  166. package/lattice_brain/graph/retrieval_docgen.py +0 -253
  167. package/lattice_brain/graph/retrieval_policy.py +0 -180
  168. package/lattice_brain/graph/retrieval_reads.py +0 -769
  169. package/lattice_brain/graph/retrieval_vector/__init__.py +0 -42
  170. package/lattice_brain/graph/retrieval_vector/fingerprint.py +0 -97
  171. package/lattice_brain/graph/retrieval_vector/indexing.py +0 -347
  172. package/lattice_brain/graph/retrieval_vector/search.py +0 -560
  173. package/lattice_brain/graph/retrieval_vector/status.py +0 -374
  174. package/lattice_brain/graph/schema.py +0 -792
  175. package/lattice_brain/graph/store.py +0 -268
  176. package/lattice_brain/graph/vector_index/__init__.py +0 -85
  177. package/lattice_brain/graph/vector_index/base.py +0 -167
  178. package/lattice_brain/graph/vector_index/brute_force.py +0 -110
  179. package/lattice_brain/graph/vector_index/hnsw.py +0 -290
  180. package/lattice_brain/graph/vector_index/jobs.py +0 -287
  181. package/lattice_brain/graph/vector_index/quantized.py +0 -148
  182. package/lattice_brain/graph/vector_index/selector.py +0 -161
  183. package/lattice_brain/graph/write_master.py +0 -308
  184. package/lattice_brain/ingestion/_contract.py +0 -90
  185. package/lattice_brain/ingestion/folder_scan.py +0 -57
  186. package/lattice_brain/ingestion/folders.py +0 -258
  187. package/lattice_brain/ingestion/jobs_api.py +0 -107
  188. package/lattice_brain/ingestion/routing.py +0 -295
  189. package/lattice_brain/ingestion_jobs.py +0 -380
  190. package/lattice_brain/memory.py +0 -75
  191. package/lattice_brain/portability/__init__.py +0 -90
  192. package/lattice_brain/portability/_contract.py +0 -42
  193. package/lattice_brain/portability/backups.py +0 -338
  194. package/lattice_brain/portability/bundles.py +0 -136
  195. package/lattice_brain/portability/constants.py +0 -93
  196. package/lattice_brain/portability/fsops.py +0 -138
  197. package/lattice_brain/portability/service.py +0 -41
  198. package/lattice_brain/portability/sharing.py +0 -710
  199. package/lattice_brain/quality.py +0 -543
  200. package/lattice_brain/retrieval_benchmark_fixtures.py +0 -92
  201. package/lattice_brain/runtime/agent_runtime.py +0 -859
  202. package/lattice_brain/runtime/contracts.py +0 -460
  203. package/lattice_brain/runtime/multi_agent.py +0 -942
  204. package/lattice_brain/runtime/statuses.py +0 -10
  205. package/lattice_brain/sealed_box.py +0 -240
  206. package/lattice_brain/self_model.py +0 -675
  207. package/lattice_brain/sensitivity.py +0 -94
  208. package/lattice_brain/storage/__init__.py +0 -22
  209. package/lattice_brain/storage/base.py +0 -100
  210. package/lattice_brain/storage/docker.py +0 -105
  211. package/lattice_brain/storage/factory.py +0 -31
  212. package/lattice_brain/storage/migration.py +0 -191
  213. package/lattice_brain/storage/postgres.py +0 -123
  214. package/lattice_brain/storage/sqlite.py +0 -143
  215. package/lattice_brain/synthesis.py +0 -824
  216. package/lattice_brain/workflow.py +0 -497
  217. package/latticeai/api/admin.py +0 -471
  218. package/latticeai/api/agent_registry.py +0 -105
  219. package/latticeai/api/agents.py +0 -228
  220. package/latticeai/api/auth.py +0 -383
  221. package/latticeai/api/automation_intelligence.py +0 -401
  222. package/latticeai/api/brain_intelligence.py +0 -199
  223. package/latticeai/api/browser.py +0 -493
  224. package/latticeai/api/change_proposals.py +0 -89
  225. package/latticeai/api/chat.py +0 -572
  226. package/latticeai/api/chat_agent_http.py +0 -892
  227. package/latticeai/api/chat_contracts.py +0 -73
  228. package/latticeai/api/chat_documents.py +0 -276
  229. package/latticeai/api/chat_helpers.py +0 -460
  230. package/latticeai/api/chat_history.py +0 -101
  231. package/latticeai/api/chat_hybrid.py +0 -113
  232. package/latticeai/api/chat_intents.py +0 -646
  233. package/latticeai/api/chat_stream.py +0 -216
  234. package/latticeai/api/chronicle.py +0 -63
  235. package/latticeai/api/command_center.py +0 -51
  236. package/latticeai/api/computer_use.py +0 -474
  237. package/latticeai/api/evidence_actions.py +0 -48
  238. package/latticeai/api/features.py +0 -70
  239. package/latticeai/api/funnel_metrics.py +0 -31
  240. package/latticeai/api/garden.py +0 -34
  241. package/latticeai/api/hooks.py +0 -165
  242. package/latticeai/api/index_jobs.py +0 -145
  243. package/latticeai/api/invitations.py +0 -100
  244. package/latticeai/api/knowledge_graph.py +0 -536
  245. package/latticeai/api/marketplace.py +0 -105
  246. package/latticeai/api/mcp.py +0 -482
  247. package/latticeai/api/memory.py +0 -270
  248. package/latticeai/api/network.py +0 -81
  249. package/latticeai/api/network_boundary.py +0 -225
  250. package/latticeai/api/permission_mode.py +0 -61
  251. package/latticeai/api/permissions.py +0 -436
  252. package/latticeai/api/plugins.py +0 -126
  253. package/latticeai/api/portability.py +0 -391
  254. package/latticeai/api/project_sessions.py +0 -114
  255. package/latticeai/api/realtime.py +0 -118
  256. package/latticeai/api/review_queue.py +0 -364
  257. package/latticeai/api/security_dashboard.py +0 -604
  258. package/latticeai/api/setup.py +0 -319
  259. package/latticeai/api/static_routes.py +0 -354
  260. package/latticeai/api/ui_redirects.py +0 -26
  261. package/latticeai/api/workflow_designer.py +0 -394
  262. package/latticeai/api/workspace.py +0 -856
  263. package/latticeai/api/workspace_scope.py +0 -125
  264. package/latticeai/core/agent/__init__.py +0 -93
  265. package/latticeai/core/agent/_contract.py +0 -79
  266. package/latticeai/core/agent/context.py +0 -57
  267. package/latticeai/core/agent/deps.py +0 -125
  268. package/latticeai/core/agent/execution.py +0 -622
  269. package/latticeai/core/agent/planning.py +0 -145
  270. package/latticeai/core/agent/recovery.py +0 -157
  271. package/latticeai/core/agent/runtime.py +0 -210
  272. package/latticeai/core/agent/verification.py +0 -231
  273. package/latticeai/core/agent_eval.py +0 -739
  274. package/latticeai/core/agent_helpers.py +0 -493
  275. package/latticeai/core/agent_profiles.py +0 -110
  276. package/latticeai/core/agent_prompts.py +0 -171
  277. package/latticeai/core/agent_registry.py +0 -232
  278. package/latticeai/core/agent_state.py +0 -41
  279. package/latticeai/core/agent_trace.py +0 -104
  280. package/latticeai/core/artifact_ledger.py +0 -109
  281. package/latticeai/core/audit.py +0 -260
  282. package/latticeai/core/builtin_hooks.py +0 -105
  283. package/latticeai/core/context_builder.py +0 -394
  284. package/latticeai/core/document_generator.py +0 -103
  285. package/latticeai/core/enterprise.py +0 -154
  286. package/latticeai/core/enterprise_admin.py +0 -158
  287. package/latticeai/core/file_generation/__init__.py +0 -115
  288. package/latticeai/core/file_generation/bundles.py +0 -76
  289. package/latticeai/core/file_generation/extraction.py +0 -154
  290. package/latticeai/core/file_generation/inference.py +0 -235
  291. package/latticeai/core/file_generation/orchestration.py +0 -152
  292. package/latticeai/core/file_generation/prompting.py +0 -117
  293. package/latticeai/core/file_generation/repair.py +0 -114
  294. package/latticeai/core/file_generation/sanitize.py +0 -61
  295. package/latticeai/core/file_generation/validation.py +0 -201
  296. package/latticeai/core/invitations.py +0 -132
  297. package/latticeai/core/legacy_compatibility.py +0 -243
  298. package/latticeai/core/logging_safety.py +0 -46
  299. package/latticeai/core/marketplace.py +0 -293
  300. package/latticeai/core/mcp_catalog.py +0 -452
  301. package/latticeai/core/mcp_registry.py +0 -506
  302. package/latticeai/core/network_boundary.py +0 -168
  303. package/latticeai/core/oidc.py +0 -208
  304. package/latticeai/core/plugins.py +0 -432
  305. package/latticeai/core/product_hardening.py +0 -218
  306. package/latticeai/core/project_sessions.py +0 -337
  307. package/latticeai/core/realtime.py +0 -238
  308. package/latticeai/core/run_explain.py +0 -426
  309. package/latticeai/core/run_store.py +0 -252
  310. package/latticeai/core/timezones.py +0 -80
  311. package/latticeai/core/workspace_computer_memory.py +0 -84
  312. package/latticeai/core/workspace_graph_trace.py +0 -155
  313. package/latticeai/core/workspace_indexing.py +0 -102
  314. package/latticeai/core/workspace_memory.py +0 -77
  315. package/latticeai/core/workspace_onboarding.py +0 -104
  316. package/latticeai/core/workspace_os.py +0 -978
  317. package/latticeai/core/workspace_os_constants.py +0 -126
  318. package/latticeai/core/workspace_os_state.py +0 -180
  319. package/latticeai/core/workspace_os_utils.py +0 -103
  320. package/latticeai/core/workspace_permissions.py +0 -101
  321. package/latticeai/core/workspace_plugins.py +0 -97
  322. package/latticeai/core/workspace_relationships.py +0 -99
  323. package/latticeai/core/workspace_reorganization.py +0 -335
  324. package/latticeai/core/workspace_review_items.py +0 -112
  325. package/latticeai/core/workspace_runs.py +0 -726
  326. package/latticeai/core/workspace_skills.py +0 -109
  327. package/latticeai/core/workspace_snapshots.py +0 -198
  328. package/latticeai/core/workspace_timeline.py +0 -110
  329. package/latticeai/integrations/__init__.py +0 -0
  330. package/latticeai/integrations/telegram_bot/__init__.py +0 -123
  331. package/latticeai/integrations/telegram_bot/__main__.py +0 -17
  332. package/latticeai/integrations/telegram_bot/config.py +0 -86
  333. package/latticeai/integrations/telegram_bot/dispatch.py +0 -311
  334. package/latticeai/integrations/telegram_bot/flows.py +0 -478
  335. package/latticeai/integrations/telegram_bot/helpers.py +0 -322
  336. package/latticeai/integrations/telegram_bot/screens.py +0 -394
  337. package/latticeai/runtime/audit_runtime.py +0 -76
  338. package/latticeai/runtime/automation_runtime.py +0 -81
  339. package/latticeai/runtime/chat_wiring.py +0 -141
  340. package/latticeai/runtime/context_runtime.py +0 -66
  341. package/latticeai/runtime/feature_toggle_wiring.py +0 -157
  342. package/latticeai/runtime/history_runtime.py +0 -163
  343. package/latticeai/runtime/history_writer.py +0 -138
  344. package/latticeai/runtime/hooks_runtime.py +0 -77
  345. package/latticeai/runtime/model_wiring.py +0 -68
  346. package/latticeai/runtime/namespace_runtime.py +0 -163
  347. package/latticeai/runtime/network_boundary_wiring.py +0 -117
  348. package/latticeai/runtime/network_config_runtime.py +0 -56
  349. package/latticeai/runtime/permission_mode_wiring.py +0 -112
  350. package/latticeai/runtime/persistence_runtime.py +0 -159
  351. package/latticeai/runtime/platform_runtime_wiring.py +0 -89
  352. package/latticeai/runtime/review_wiring.py +0 -42
  353. package/latticeai/runtime/router_registration.py +0 -693
  354. package/latticeai/runtime/service_singletons.py +0 -55
  355. package/latticeai/runtime/sso_config_runtime.py +0 -128
  356. package/latticeai/runtime/user_key_runtime.py +0 -106
  357. package/latticeai/runtime/web_runtime.py +0 -92
  358. package/latticeai/server_app.py +0 -51
  359. package/latticeai/services/app_context.py +0 -130
  360. package/latticeai/services/automation_execution.py +0 -266
  361. package/latticeai/services/automation_intelligence.py +0 -614
  362. package/latticeai/services/brain_automation.py +0 -191
  363. package/latticeai/services/brain_intelligence/__init__.py +0 -58
  364. package/latticeai/services/brain_intelligence/_contract.py +0 -71
  365. package/latticeai/services/brain_intelligence/consistency.py +0 -193
  366. package/latticeai/services/brain_intelligence/constants.py +0 -47
  367. package/latticeai/services/brain_intelligence/digest.py +0 -258
  368. package/latticeai/services/brain_intelligence/health.py +0 -331
  369. package/latticeai/services/brain_intelligence/proposals.py +0 -259
  370. package/latticeai/services/brain_intelligence/sampling.py +0 -84
  371. package/latticeai/services/brain_intelligence/service.py +0 -48
  372. package/latticeai/services/change_proposals.py +0 -471
  373. package/latticeai/services/chat_service.py +0 -243
  374. package/latticeai/services/chronicle.py +0 -555
  375. package/latticeai/services/cloud_egress_audit.py +0 -85
  376. package/latticeai/services/cloud_extraction.py +0 -129
  377. package/latticeai/services/cloud_streaming.py +0 -268
  378. package/latticeai/services/cloud_token_guard.py +0 -84
  379. package/latticeai/services/command_center.py +0 -548
  380. package/latticeai/services/evidence_actions.py +0 -258
  381. package/latticeai/services/feature_toggles.py +0 -502
  382. package/latticeai/services/folder_watch.py +0 -520
  383. package/latticeai/services/funnel_metrics.py +0 -307
  384. package/latticeai/services/hybrid_chat.py +0 -316
  385. package/latticeai/services/hybrid_context.py +0 -228
  386. package/latticeai/services/hybrid_policy.py +0 -129
  387. package/latticeai/services/interop_bridges.py +0 -978
  388. package/latticeai/services/local_knowledge.py +0 -465
  389. package/latticeai/services/memory_service/__init__.py +0 -52
  390. package/latticeai/services/memory_service/_contract.py +0 -100
  391. package/latticeai/services/memory_service/brief.py +0 -431
  392. package/latticeai/services/memory_service/constants.py +0 -57
  393. package/latticeai/services/memory_service/maintenance.py +0 -138
  394. package/latticeai/services/memory_service/manager.py +0 -186
  395. package/latticeai/services/memory_service/proof.py +0 -136
  396. package/latticeai/services/memory_service/recall.py +0 -225
  397. package/latticeai/services/memory_service/service.py +0 -48
  398. package/latticeai/services/memory_service/stores.py +0 -110
  399. package/latticeai/services/mode_store.py +0 -132
  400. package/latticeai/services/model_recommendation.py +0 -224
  401. package/latticeai/services/model_runtime/cloud.py +0 -87
  402. package/latticeai/services/network_boundary_service.py +0 -117
  403. package/latticeai/services/obsidian_bridge.py +0 -609
  404. package/latticeai/services/openai_compatible_adapter.py +0 -101
  405. package/latticeai/services/permission_mode_service.py +0 -122
  406. package/latticeai/services/platform_runtime.py +0 -366
  407. package/latticeai/services/review_queue.py +0 -380
  408. package/latticeai/services/router_context.py +0 -59
  409. package/latticeai/services/run_executor.py +0 -387
  410. package/latticeai/services/self_model_service.py +0 -171
  411. package/latticeai/services/setup_detection.py +0 -147
  412. package/latticeai/services/triggers.py +0 -378
  413. package/latticeai/services/upload_service.py +0 -172
  414. package/latticeai/services/workspace_service.py +0 -165
  415. package/latticeai/setup/__init__.py +0 -25
  416. package/latticeai/setup/auto_setup.py +0 -846
  417. package/latticeai/setup/demo_corpus.py +0 -98
  418. package/latticeai/setup/wizard/__init__.py +0 -126
  419. package/latticeai/setup/wizard/catalog.py +0 -175
  420. package/latticeai/setup/wizard/detect.py +0 -302
  421. package/latticeai/setup/wizard/install.py +0 -348
  422. package/latticeai/setup/wizard/paths.py +0 -165
  423. package/latticeai/setup/wizard/plans.py +0 -74
  424. package/latticeai/setup/wizard/recommend.py +0 -320
  425. package/scripts/bench_agent_smoke.py +0 -409
  426. package/scripts/bench_models.py +0 -540
  427. package/scripts/bench_vector_index.py +0 -295
  428. package/scripts/funnel_soft_gate.py +0 -192
  429. package/scripts/generate_agent_loop_fixtures.py +0 -994
  430. package/scripts/generate_rust_parity_fixtures.py +0 -908
  431. package/scripts/migrate_brain_storage.py +0 -57
  432. package/scripts/parity_fixture_corpus_context.py +0 -162
  433. package/scripts/parity_fixture_corpus_docgen.py +0 -341
  434. package/scripts/profile_kg.py +0 -355
  435. package/server.py +0 -30
  436. package/static/app/assets/arrow-left-kfsrk0mv.js +0 -1
  437. package/static/app/assets/circle-check-qqLug9nU.js +0 -1
  438. package/static/app/assets/index-DxmOfNRi.css +0 -2
  439. package/static/app/assets/search-BcHqkjoy.js +0 -1
@@ -1,792 +0,0 @@
1
- """
2
- Lattice AI — Knowledge Graph v2 schema (PPT spec aligned)
3
- =========================================================
4
-
5
- 명세: ``lattice_ai_full_spec.pptx`` 슬라이드 20~22 (Node / Edge / Data Model)
6
-
7
- 목적
8
- ----
9
- 기존 ``knowledge_graph.py`` 의 자유 문자열 노드/엣지 타입을 **명시 enum + SQLite v2
10
- 스키마** 로 정식화한다. 이 모듈은 **스키마/초기화/프로젝션 지원** 역할만 담당한다:
11
- ``NodeType``/``EdgeType`` taxonomy + legacy 정규화 매핑, ``nodes_v2``/``edges_v2``
12
- DDL(``SCHEMA_SQL``), 그리고 ``KGStoreV2``(스키마 init·heal·stats).
13
-
14
- 실제 데이터 read/write 는 ``knowledge_graph.py`` 의 ``KnowledgeGraphStore`` 가
15
- legacy 테이블에 대한 dual-write 프로젝션(raw SQL) + ``kgv2_*`` 재구성 뷰로 수행한다.
16
- (과거의 native ``Node``/``Edge`` 모델과 ``KGStoreV2.upsert_*``/``get_node``/
17
- ``search_*`` API 는 production 에서 쓰이지 않아 제거되었다.)
18
-
19
- 설계 원칙
20
- ---------
21
- 1. **기존 코드를 깨지 않는다**: 새 테이블 이름은 ``nodes_v2`` / ``edges_v2``
22
- 로 분리. 기존 ``nodes`` / ``edges`` 와 공존한다. legacy → v2 reprojection 은
23
- ``knowledge_graph.py`` 의 버전 게이트 백필 한 곳에서만 수행한다.
24
- 2. **정규화 + 무손실**: legacy 자유 문자열 타입은 ``NodeType``/``EdgeType``
25
- superset 으로 정규화해 ``type`` 칼럼에 저장하고, 원본 문자열은 ``legacy_type``
26
- 칼럼에 그대로 보존한다. summary 와 metadata 는 ``attrs._kg`` 패스스루 blob 이
27
- 아니라 전용 ``summary`` 칼럼 / ``attrs``·``metadata`` 칼럼에 1급으로 저장한다.
28
- 3. **표준 라이브러리만 사용**: 외부 의존성 없이 ``sqlite3`` 만으로 동작한다.
29
- 4. **정규화 매핑은 명시적**: 한글 동사/legacy 라벨 → 영문 enum 표가 코드 안에
30
- 들어 있어서 어떤 옛 라벨이 어디로 매핑되는지 한눈에 보인다.
31
-
32
- 사용 예
33
- -------
34
- ```python
35
- from lattice_brain.graph.schema import KGStoreV2
36
-
37
- store = KGStoreV2("/Users/me/.ltcai/kg_v2.db")
38
- store.init_schema() # nodes_v2 / edges_v2 생성 + 컬럼 drift self-heal
39
- print(store.stats()) # {"nodes": ..., "by_node_type": {...}, ...}
40
- ```
41
- """
42
-
43
- from __future__ import annotations
44
-
45
- import json
46
- import logging
47
- import os
48
- import sqlite3
49
- from contextlib import contextmanager
50
- from enum import Enum
51
- from pathlib import Path
52
- from typing import Any, Dict, Optional
53
-
54
- from ..quiet import quiet
55
- from ..utils import now_iso as _stamp_now
56
-
57
- # ── Schema version ──────────────────────────────────────────────────────────
58
- KG_SCHEMA_V2_VERSION = 2
59
- EMBED_DIM = int(os.getenv("LATTICEAI_EMBED_DIM", "1024"))
60
-
61
-
62
- def set_embed_dim(dim: int) -> None:
63
- """Optional way for upper layers to override without direct module import at top level in lattice_brain."""
64
- global EMBED_DIM
65
- EMBED_DIM = int(dim) # lattice_brain isolation: no direct latticeai import; callers can pre-set env if using central Config
66
-
67
-
68
- # ── Node / Edge taxonomy (PPT 슬라이드 20·21) ──────────────────────────────
69
- class NodeType(str, Enum):
70
- """워크스페이스의 모든 ‘명사’.
71
-
72
- PPT 슬라이드 20 카탈로그(상단 그룹)에 더해, ``knowledge_graph.py`` 가 실제로
73
- 써오던 legacy 자유 문자열 타입을 **무손실 superset**(하단 그룹)으로 1급 enum 화
74
- 한다. 덕분에 ``from_legacy`` 정규화가 의미를 잃지 않고(예: ``Computer`` →
75
- ``COMPUTER``), 알 수 없는/동적(이벤트) 타입만 ``CONCEPT`` 로 폴백한다.
76
- 원본 문자열은 ``nodes_v2.legacy_type`` 에 그대로 보존되므로 정규화는 항상 무손실.
77
- """
78
-
79
- # PPT 슬라이드 20 정식 카탈로그
80
- CONVERSATION = "CONVERSATION" # 대화 세션 전체
81
- MESSAGE = "MESSAGE" # 단일 발화
82
- FILE = "FILE" # 업로드/연결된 파일
83
- DOCUMENT = "DOCUMENT" # 생성/관리되는 문서 (보고서, 계획서 등)
84
- CHUNK = "CHUNK" # 파일의 분할 청크
85
- CODE_SYMBOL = "CODE_SYMBOL" # 함수·클래스·모듈
86
- CONCEPT = "CONCEPT" # 추출된 개념 / 태그
87
- PERSON = "PERSON" # 사용자·협업자
88
- MODEL = "MODEL" # 로컬/원격 LLM
89
- TOOL = "TOOL" # MCP 서버·외부 도구
90
- PROJECT = "PROJECT" # 주제별 작업 공간
91
- # legacy superset — knowledge_graph.py 가 실제로 생성하던 노드 타입들
92
- COMPUTER = "COMPUTER" # 내 컴퓨터 (로컬 스캔 루트)
93
- DRIVE = "DRIVE" # 드라이브 / 볼륨
94
- FOLDER = "FOLDER" # 폴더
95
- CODE_FILE = "CODE_FILE" # 코드 파일 (.py/.ts 등)
96
- SPREADSHEET = "SPREADSHEET" # 엑셀 / CSV
97
- SLIDE_DECK = "SLIDE_DECK" # 프레젠테이션
98
- IMAGE = "IMAGE" # 이미지 파일
99
- IMAGE_TEXT = "IMAGE_TEXT" # OCR 텍스트
100
- SLIDE = "SLIDE" # 슬라이드 (덱의 한 장)
101
- PAGE = "PAGE" # 페이지 (문서의 한 면)
102
- SHEET = "SHEET" # 시트 (스프레드시트의 한 탭)
103
- SECTION = "SECTION" # 문서 섹션
104
- CHAT = "CHAT" # 대화 세션(채팅 UI)
105
- AI_RESPONSE = "AI_RESPONSE" # 어시스턴트 발화
106
- TOPIC = "TOPIC" # 주제 / 토픽
107
- FEATURE = "FEATURE" # 소프트웨어 기능
108
- TASK = "TASK" # 할 일
109
- DECISION = "DECISION" # 결정 사항
110
- ERROR = "ERROR" # 오류 / 버그
111
- EVENT = "EVENT" # 분석/시스템 이벤트(동적 타입 폴백)
112
- # v3.6.0 Knowledge Graph First — 모든 데이터 소스가 그래프로 수렴하기 위한
113
- # 1급 엔티티. 추가형(additive)·확장 가능(extensible): 새 도메인 엔티티는
114
- # 여기에 enum 멤버를 추가하고 _LEGACY_NODE_MAP 에 별칭만 등록하면 된다.
115
- SOURCE = "SOURCE" # 수집 출처(파일/URL/브라우저 탭/git 등)의 출처 노드
116
- REPOSITORY = "REPOSITORY" # git 저장소
117
- MEETING = "MEETING" # 회의 / 미팅
118
- ORGANIZATION = "ORGANIZATION" # 조직 / 회사 / 팀
119
- WORKFLOW = "WORKFLOW" # 워크플로우 정의/실행
120
- AGENT = "AGENT" # 에이전트(역할/실행 주체)
121
- # v11.1.0 Personal Ontology (Track 4) — the Self-Model subgraph. These are
122
- # not "another kind of document": they are what the Brain has been told
123
- # about *its owner*, so they are read, edited and deleted as a unit
124
- # (``lattice_brain.self_model``). DECISION already exists above and is
125
- # reused rather than duplicated — a decision is a decision whether it came
126
- # from a meeting note or from "결정: 로컬 모델을 기본값으로 쓴다".
127
- SELF = "SELF" # 사용자 자신(Self-Model 루트)
128
- PREFERENCE = "PREFERENCE" # 선호 (좋아함/싫어함/선호 방식)
129
- HABIT = "HABIT" # 습관 (반복되는 행동)
130
- RELATIONSHIP = "RELATIONSHIP" # 관계 (동료/친구/멘토 등)
131
- # v11.1.0 Multi-modal (Track 3) — a recording is its own noun. It used to
132
- # enter through the text door as a DOCUMENT because "a transcript *is*
133
- # text"; that is true of the transcript and false of the recording, which
134
- # exists whether or not anyone could hear it. IMAGE has been first-class
135
- # since 3.6.0 for the same reason, and AUDIO now sits beside it.
136
- AUDIO = "AUDIO" # 녹음 / 음성 메모
137
- # v11.2.0 — a video is its own noun for the same reason a recording is:
138
- # keyframes and subtitles are *derived* from it (IMAGE children, text
139
- # chunks), and calling the thing they came from a DOCUMENT would make the
140
- # source of a memory indistinguishable from one of its pieces.
141
- VIDEO = "VIDEO" # 영상 / 화면 녹화
142
-
143
- @classmethod
144
- def from_legacy(cls, label: str) -> "NodeType":
145
- """legacy ``knowledge_graph.py`` 의 자유 문자열을 정식 enum 으로 정규화.
146
-
147
- 매핑이 없는(동적 이벤트 등) 타입은 ``CONCEPT`` 로 폴백하지만, 호출부는
148
- 원본 문자열을 ``legacy_type`` 칼럼에 별도 보존하므로 정보 손실은 없다.
149
- """
150
- m = (label or "").strip()
151
- # Canonical values round-trip exactly (v4 native writes use them);
152
- # without this, CODE_FILE/AI_RESPONSE etc. would degrade to CONCEPT.
153
- try:
154
- return cls(m.upper())
155
- except ValueError:
156
- quiet()
157
- return _LEGACY_NODE_MAP.get(m.lower(), cls.CONCEPT)
158
-
159
-
160
- class EdgeType(str, Enum):
161
- """노드 사이의 ‘방향성 있고 타입이 명시된’ 관계. PPT 슬라이드 21."""
162
-
163
- CONTAINS = "CONTAINS" # FILE → CHUNK
164
- MENTIONS = "MENTIONS" # MESSAGE → CONCEPT
165
- REFERENCES = "REFERENCES" # FILE → FILE / URL
166
- REPLIES_TO = "REPLIES_TO" # MESSAGE → MESSAGE
167
- AUTHORED_BY = "AUTHORED_BY" # FILE → PERSON
168
- USES = "USES" # PROJECT → TOOL / MODEL
169
- DERIVED_FROM = "DERIVED_FROM" # CHUNK → CHUNK (요약 등)
170
- SIMILAR_TO = "SIMILAR_TO" # ANY ↔ ANY (의미 유사도)
171
- DEPENDS_ON = "DEPENDS_ON" # CODE_SYMBOL → CODE_SYMBOL
172
- TAGGED_AS = "TAGGED_AS" # ANY → CONCEPT
173
- VERSION_OF = "VERSION_OF" # FILE → FILE (히스토리)
174
- GRANTS_ACCESS = "GRANTS_ACCESS" # PERSON → RESOURCE
175
- USED_IN = "USED_IN" # CONCEPT → DOCUMENT (문서에 활용됨)
176
- INSPIRED_BY = "INSPIRED_BY" # DOCUMENT → DOCUMENT (영감/참조 관계)
177
- CONTRADICTS = "CONTRADICTS" # DOCUMENT ↔ DOCUMENT (상충 관계)
178
- EVOLVES_FROM = "EVOLVES_FROM" # DOCUMENT → DOCUMENT (발전/개정 관계)
179
- # legacy superset — knowledge_graph.py 가 실제로 생성하던 엣지 타입들
180
- UPLOADED_BY = "UPLOADED_BY" # PERSON → FILE (업로드함)
181
- WROTE = "WROTE" # PERSON → CONVERSATION (작성함)
182
- HAS_EVENT = "HAS_EVENT" # CONVERSATION → EVENT (has_event)
183
- TRIGGERED = "TRIGGERED" # PERSON → EVENT (triggered)
184
- HAS_SLIDE = "HAS_SLIDE" # SLIDE_DECK → SLIDE (has_slide)
185
- HAS_PAGE = "HAS_PAGE" # DOCUMENT → PAGE (has_page)
186
- HAS_SHEET = "HAS_SHEET" # SPREADSHEET → SHEET (has_sheet)
187
- HAS_CHUNK = "HAS_CHUNK" # FILE → CHUNK (has_chunk)
188
- CONTAINS_IMAGE = "CONTAINS_IMAGE" # FILE → IMAGE (contains_image)
189
- CONTAINS_SIGNAL = "CONTAINS_SIGNAL" # NODE → CONCEPT (contains_signal)
190
- DISCUSSES = "DISCUSSES" # SLIDE/PAGE → TOPIC (discusses)
191
- IMPLIES = "IMPLIES" # NODE → NODE (implies)
192
- RELATED_TO = "RELATED_TO" # ANY ↔ ANY (related_to)
193
- # v3.6.0 Knowledge Graph First — 출처/소유/구성/결정 관계를 1급 엣지로 승격.
194
- # 추가형: 새 관계는 enum 멤버 추가 + _LEGACY_EDGE_MAP 별칭 등록만으로 확장된다.
195
- INDEXED_FROM = "INDEXED_FROM" # NODE → SOURCE (어떤 출처에서 색인됐는가)
196
- MODIFIED_BY = "MODIFIED_BY" # NODE → PERSON (마지막 수정자)
197
- BELONGS_TO_PROJECT = "BELONGS_TO_PROJECT" # NODE → PROJECT
198
- PART_OF = "PART_OF" # NODE → NODE (구성요소 관계)
199
- DISCUSSED_IN = "DISCUSSED_IN" # CONCEPT/DECISION → MEETING/CHAT
200
- DECIDED_BY = "DECIDED_BY" # DECISION → PERSON
201
- GENERATED_BY = "GENERATED_BY" # NODE → AGENT/MODEL/WORKFLOW
202
- USED_BY_AGENT = "USED_BY_AGENT" # NODE → AGENT (에이전트가 사용함)
203
-
204
- @classmethod
205
- def from_legacy(cls, label: str) -> "EdgeType":
206
- """legacy 자유 문자열/한글 동사를 정식 enum 으로 정규화.
207
-
208
- 매핑이 없는 동적 타입은 ``MENTIONS`` 로 폴백하지만, 호출부는 원본 문자열을
209
- ``edges_v2.legacy_type`` 에 보존하므로 정보 손실은 없다.
210
- """
211
- m = (label or "").strip()
212
- # Canonical values round-trip exactly (v4 native writes use them).
213
- try:
214
- return cls(m.upper())
215
- except ValueError:
216
- quiet()
217
- return _LEGACY_EDGE_MAP.get(m.lower(), cls.MENTIONS)
218
-
219
-
220
- # legacy(자유 문자열 / 한글 동사) → enum 매핑 표.
221
- # superset 정규화: 알려진 legacy 타입은 1:1 의미 보존 매핑, 미지/동적 타입만 폴백.
222
- _LEGACY_NODE_MAP: Dict[str, NodeType] = {
223
- "conversation": NodeType.CONVERSATION,
224
- "chat": NodeType.CHAT,
225
- "message": NodeType.MESSAGE,
226
- "airesponse": NodeType.AI_RESPONSE,
227
- "file": NodeType.FILE,
228
- "codefile": NodeType.CODE_FILE,
229
- "spreadsheet": NodeType.SPREADSHEET,
230
- "slidedeck": NodeType.SLIDE_DECK,
231
- "image": NodeType.IMAGE,
232
- "imagetext": NodeType.IMAGE_TEXT,
233
- "computer": NodeType.COMPUTER,
234
- "drive": NodeType.DRIVE,
235
- "folder": NodeType.FOLDER,
236
- "page": NodeType.PAGE,
237
- "sheet": NodeType.SHEET,
238
- "slide": NodeType.SLIDE,
239
- "section": NodeType.SECTION,
240
- "chunk": NodeType.CHUNK,
241
- "code": NodeType.CODE_SYMBOL,
242
- "concept": NodeType.CONCEPT,
243
- "topic": NodeType.TOPIC,
244
- "feature": NodeType.FEATURE,
245
- "task": NodeType.TASK,
246
- "decision": NodeType.DECISION,
247
- "error": NodeType.ERROR,
248
- "event": NodeType.EVENT,
249
- "tag": NodeType.CONCEPT,
250
- "person": NodeType.PERSON,
251
- "user": NodeType.PERSON,
252
- "model": NodeType.MODEL,
253
- "tool": NodeType.TOOL,
254
- "mcp": NodeType.TOOL,
255
- "project": NodeType.PROJECT,
256
- "workspace": NodeType.PROJECT,
257
- "document": NodeType.DOCUMENT,
258
- "report": NodeType.DOCUMENT,
259
- "plan": NodeType.DOCUMENT,
260
- "proposal": NodeType.DOCUMENT,
261
- "보고서": NodeType.DOCUMENT,
262
- "계획서": NodeType.DOCUMENT,
263
- "기획서": NodeType.DOCUMENT,
264
- # v3.6.0 Knowledge Graph First 엔티티
265
- "source": NodeType.SOURCE,
266
- "ingestionsource": NodeType.SOURCE,
267
- "repository": NodeType.REPOSITORY,
268
- "repo": NodeType.REPOSITORY,
269
- "gitrepo": NodeType.REPOSITORY,
270
- "meeting": NodeType.MEETING,
271
- "organization": NodeType.ORGANIZATION,
272
- "org": NodeType.ORGANIZATION,
273
- "company": NodeType.ORGANIZATION,
274
- "team": NodeType.ORGANIZATION,
275
- "workflow": NodeType.WORKFLOW,
276
- "agent": NodeType.AGENT,
277
- # v11.1.0 Personal Ontology — the Self-Model vocabulary, including the
278
- # Korean labels a person actually types.
279
- "self": NodeType.SELF,
280
- "selfmodel": NodeType.SELF,
281
- "me": NodeType.SELF,
282
- "나": NodeType.SELF,
283
- "preference": NodeType.PREFERENCE,
284
- "선호": NodeType.PREFERENCE,
285
- "habit": NodeType.HABIT,
286
- "습관": NodeType.HABIT,
287
- "relationship": NodeType.RELATIONSHIP,
288
- "관계": NodeType.RELATIONSHIP,
289
- "결정": NodeType.DECISION,
290
- # v11.1.0 Multi-modal — recordings as a first-class noun.
291
- "audio": NodeType.AUDIO,
292
- "오디오": NodeType.AUDIO,
293
- # v11.2.0 — videos likewise.
294
- "video": NodeType.VIDEO,
295
- "영상": NodeType.VIDEO,
296
- "동영상": NodeType.VIDEO,
297
- }
298
-
299
- _LEGACY_EDGE_MAP: Dict[str, EdgeType] = {
300
- # 한글 동사 (knowledge_graph.py 의 EDGE_VERB)
301
- "언급함": EdgeType.MENTIONS,
302
- "포함함": EdgeType.CONTAINS,
303
- "해결함": EdgeType.REFERENCES,
304
- "의존함": EdgeType.DEPENDS_ON,
305
- "설명함": EdgeType.MENTIONS,
306
- "비교함": EdgeType.SIMILAR_TO,
307
- "사용함": EdgeType.USES,
308
- "연결함": EdgeType.REFERENCES,
309
- "확장함": EdgeType.DERIVED_FROM,
310
- "생성함": EdgeType.AUTHORED_BY,
311
- "작성함": EdgeType.WROTE,
312
- "업로드함": EdgeType.UPLOADED_BY,
313
- "대체함": EdgeType.VERSION_OF,
314
- "지원함": EdgeType.USES,
315
- "발생함": EdgeType.REFERENCES,
316
- "관련됨": EdgeType.MENTIONS,
317
- # 영문 별칭
318
- "mentions": EdgeType.MENTIONS,
319
- "contains": EdgeType.CONTAINS,
320
- "references": EdgeType.REFERENCES,
321
- "replies_to": EdgeType.REPLIES_TO,
322
- "authored_by": EdgeType.AUTHORED_BY,
323
- "uses": EdgeType.USES,
324
- "derived_from": EdgeType.DERIVED_FROM,
325
- "similar_to": EdgeType.SIMILAR_TO,
326
- "depends_on": EdgeType.DEPENDS_ON,
327
- "tagged_as": EdgeType.TAGGED_AS,
328
- "version_of": EdgeType.VERSION_OF,
329
- "grants_access": EdgeType.GRANTS_ACCESS,
330
- "used_in": EdgeType.USED_IN,
331
- "inspired_by": EdgeType.INSPIRED_BY,
332
- "contradicts": EdgeType.CONTRADICTS,
333
- "evolves_from": EdgeType.EVOLVES_FROM,
334
- # legacy superset 별칭 (knowledge_graph.py 가 실제로 쓰던 엣지 타입)
335
- "uploaded_by": EdgeType.UPLOADED_BY,
336
- "wrote": EdgeType.WROTE,
337
- "has_event": EdgeType.HAS_EVENT,
338
- "triggered": EdgeType.TRIGGERED,
339
- "has_slide": EdgeType.HAS_SLIDE,
340
- "has_page": EdgeType.HAS_PAGE,
341
- "has_sheet": EdgeType.HAS_SHEET,
342
- "has_chunk": EdgeType.HAS_CHUNK,
343
- "contains_image": EdgeType.CONTAINS_IMAGE,
344
- "contains_signal": EdgeType.CONTAINS_SIGNAL,
345
- "discusses": EdgeType.DISCUSSES,
346
- "implies": EdgeType.IMPLIES,
347
- "related_to": EdgeType.RELATED_TO,
348
- "활용됨": EdgeType.USED_IN,
349
- "영감받음": EdgeType.INSPIRED_BY,
350
- "상충함": EdgeType.CONTRADICTS,
351
- "발전함": EdgeType.EVOLVES_FROM,
352
- # v3.6.0 Knowledge Graph First 관계
353
- "indexed_from": EdgeType.INDEXED_FROM,
354
- "modified_by": EdgeType.MODIFIED_BY,
355
- "belongs_to_project": EdgeType.BELONGS_TO_PROJECT,
356
- "belongs_to": EdgeType.BELONGS_TO_PROJECT,
357
- "part_of": EdgeType.PART_OF,
358
- "discussed_in": EdgeType.DISCUSSED_IN,
359
- "decided_by": EdgeType.DECIDED_BY,
360
- "generated_by": EdgeType.GENERATED_BY,
361
- "used_by_agent": EdgeType.USED_BY_AGENT,
362
- "색인됨": EdgeType.INDEXED_FROM,
363
- "수정함": EdgeType.MODIFIED_BY,
364
- "결정함": EdgeType.DECIDED_BY,
365
- "구성요소": EdgeType.PART_OF,
366
- }
367
-
368
- # ── SQLite v2 store ─────────────────────────────────────────────────────────
369
- SCHEMA_SQL = """
370
- CREATE TABLE IF NOT EXISTS kg_meta (
371
- key TEXT PRIMARY KEY,
372
- value TEXT NOT NULL
373
- );
374
-
375
- CREATE TABLE IF NOT EXISTS nodes_v2 (
376
- id TEXT PRIMARY KEY,
377
- type TEXT NOT NULL,
378
- legacy_type TEXT,
379
- label TEXT NOT NULL,
380
- summary TEXT,
381
- attrs TEXT NOT NULL DEFAULT '{}',
382
- embedding BLOB,
383
- owner_id TEXT,
384
- -- NULL workspace_id = legacy-global (pre-scoping rows, readable machine-wide).
385
- workspace_id TEXT,
386
- -- 'legacy' marks rows that predate scoping — the 'private' default must not
387
- -- silently privatize previously machine-shared data (design-review ruling).
388
- visibility TEXT NOT NULL DEFAULT 'private',
389
- -- Revision chain: a node replaced by a newer one points at its successor.
390
- superseded_by TEXT,
391
- -- Bitemporal validity (v11.1.0). NULL is the convention, not '':
392
- -- valid_from IS NULL → the row has been valid since created_at
393
- -- valid_to IS NULL → the row is still valid now
394
- -- An empty string would read as "valid since the beginning of time" in a
395
- -- string comparison, which is why the columns are nullable with no default.
396
- valid_from TEXT,
397
- valid_to TEXT,
398
- created_at TEXT NOT NULL,
399
- updated_at TEXT NOT NULL,
400
- style TEXT,
401
- tone TEXT,
402
- importance_score REAL NOT NULL DEFAULT 0.0,
403
- last_used TEXT
404
- );
405
-
406
- CREATE TABLE IF NOT EXISTS edges_v2 (
407
- id TEXT PRIMARY KEY,
408
- source TEXT NOT NULL,
409
- target TEXT NOT NULL,
410
- type TEXT NOT NULL,
411
- legacy_type TEXT NOT NULL DEFAULT '',
412
- weight REAL NOT NULL DEFAULT 1.0,
413
- confidence REAL NOT NULL DEFAULT 1.0,
414
- evidence TEXT NOT NULL DEFAULT '[]',
415
- metadata TEXT NOT NULL DEFAULT '{}',
416
- created_by TEXT NOT NULL DEFAULT 'user',
417
- created_at TEXT NOT NULL,
418
- -- Bitemporal validity + revision chain (v11.1.0), same NULL convention as
419
- -- nodes_v2: NULL valid_from falls back to created_at, NULL valid_to means
420
- -- "still holds". Relationships go stale exactly like facts do.
421
- valid_from TEXT,
422
- valid_to TEXT,
423
- superseded_by TEXT,
424
- -- Edge identity (v4): the normalized type AND the raw legacy type.
425
- -- Migrated rows keep their legacy_type discriminator, so two distinct
426
- -- legacy strings between one pair (e.g. "mentions" / "관련됨") stay
427
- -- distinct even though both normalize to MENTIONS. Native canonical
428
- -- writes carry legacy_type='' so their identity is effectively
429
- -- (source, target, type) — two canonical types between the same pair
430
- -- (e.g. MENTIONS + CONTAINS) never collide. The pre-v4
431
- -- UNIQUE(source, target, legacy_type) would have silently merged them.
432
- UNIQUE(source, target, type, legacy_type),
433
- FOREIGN KEY(source) REFERENCES nodes_v2(id) ON DELETE CASCADE,
434
- FOREIGN KEY(target) REFERENCES nodes_v2(id) ON DELETE CASCADE
435
- );
436
-
437
- -- Temporal dimension (v4): every repeated observation of a relationship is
438
- -- recorded — edges_v2's UNIQUE identity + weight=max would otherwise erase
439
- -- when something was learned, how often, and whether it still holds.
440
- CREATE TABLE IF NOT EXISTS edge_occurrences (
441
- id INTEGER PRIMARY KEY AUTOINCREMENT,
442
- edge_id TEXT NOT NULL,
443
- observed_at TEXT NOT NULL,
444
- weight REAL NOT NULL DEFAULT 1.0,
445
- source TEXT,
446
- FOREIGN KEY(edge_id) REFERENCES edges_v2(id) ON DELETE CASCADE
447
- );
448
- CREATE INDEX IF NOT EXISTS idx_edge_occurrences_edge ON edge_occurrences(edge_id);
449
- CREATE INDEX IF NOT EXISTS idx_edge_occurrences_time ON edge_occurrences(observed_at);
450
-
451
- CREATE INDEX IF NOT EXISTS idx_nodes_v2_type ON nodes_v2(type);
452
- CREATE INDEX IF NOT EXISTS idx_nodes_v2_legacy ON nodes_v2(legacy_type);
453
- CREATE INDEX IF NOT EXISTS idx_nodes_v2_owner ON nodes_v2(owner_id);
454
- CREATE INDEX IF NOT EXISTS idx_edges_v2_source ON edges_v2(source);
455
- CREATE INDEX IF NOT EXISTS idx_edges_v2_target ON edges_v2(target);
456
- CREATE INDEX IF NOT EXISTS idx_edges_v2_type ON edges_v2(type);
457
- CREATE INDEX IF NOT EXISTS idx_edges_v2_legacy ON edges_v2(legacy_type);
458
- """
459
-
460
-
461
- # ── Temporal read convention (v11.1.0) ──────────────────────────────────────
462
- # One predicate, shared by every ``as_of`` read so the fallback rule cannot
463
- # drift between call sites:
464
- # * ``valid_from IS NULL`` → the row has been valid since ``created_at``
465
- # (plan §10 mitigation: existing Brains keep working with no backfill)
466
- # * ``valid_to IS NULL`` → the row is still valid
467
- # The window is half-open ``[valid_from, valid_to)``: the instant a fact is
468
- # superseded belongs to its successor, so an ``as_of`` at exactly that instant
469
- # returns exactly one of the two.
470
- TEMPORAL_PREDICATE_SQL = (
471
- "COALESCE(valid_from, created_at) <= ? AND (valid_to IS NULL OR valid_to > ?)"
472
- )
473
-
474
-
475
- def _exec_script(conn: sqlite3.Connection, script: str) -> None:
476
- """Run a multi-statement SQL script on ``conn`` statement-by-statement.
477
-
478
- Unlike ``sqlite3.Connection.executescript``, this does NOT issue an implicit
479
- COMMIT before running, so the statements join the caller's open transaction.
480
- Safe for our schema/view DDL (no ``;`` inside string literals).
481
- """
482
- for stmt in script.split(";"):
483
- s = stmt.strip()
484
- if s:
485
- conn.execute(s)
486
-
487
-
488
- class KGStoreV2:
489
- """가벼운 SQLite 기반 v2 스토어 — **스키마/초기화 지원 전용**.
490
-
491
- ``init_schema`` 으로 ``nodes_v2``/``edges_v2`` 를 생성·heal 하고 ``stats`` 로
492
- 집계를 노출한다. 데이터 read/write 는 ``knowledge_graph.KnowledgeGraphStore``
493
- 프로젝션이 담당하므로 native upsert/get/search API 는 두지 않는다.
494
- """
495
-
496
- def __init__(self, db_path: "str | Path"):
497
- # Callers pass a Path (the store keeps db_path as a Path); sqlite3
498
- # accepts either, so the annotation now matches what is actually
499
- # handed in instead of forcing every call site to str() it.
500
- self.db_path = str(db_path)
501
-
502
- @contextmanager
503
- def _conn(self):
504
- conn = sqlite3.connect(self.db_path)
505
- conn.row_factory = sqlite3.Row
506
- conn.execute("PRAGMA foreign_keys = ON")
507
- try:
508
- yield conn
509
- conn.commit()
510
- finally:
511
- conn.close()
512
-
513
- # Columns the current code writes; used to detect schema-evolution drift in
514
- # v2 tables that an older ``CREATE TABLE IF NOT EXISTS`` left behind.
515
- _V2_EXPECTED_COLUMNS = {
516
- "edges_v2": {
517
- "id",
518
- "source",
519
- "target",
520
- "type",
521
- "legacy_type",
522
- "weight",
523
- "confidence",
524
- "evidence",
525
- "metadata",
526
- "created_by",
527
- "created_at",
528
- "valid_from",
529
- "valid_to",
530
- "superseded_by",
531
- },
532
- "nodes_v2": {
533
- "id",
534
- "type",
535
- "legacy_type",
536
- "label",
537
- "summary",
538
- "attrs",
539
- "embedding",
540
- "owner_id",
541
- "workspace_id",
542
- "visibility",
543
- "superseded_by",
544
- "valid_from",
545
- "valid_to",
546
- "created_at",
547
- "updated_at",
548
- "style",
549
- "tone",
550
- "importance_score",
551
- "last_used",
552
- },
553
- }
554
-
555
- # Columns added after a table's first release that can be healed in place
556
- # with ALTER TABLE ADD COLUMN (nullable / defaulted only).
557
- _V2_ADDABLE_COLUMNS = {
558
- "nodes_v2": {
559
- "workspace_id": "TEXT",
560
- "superseded_by": "TEXT",
561
- "valid_from": "TEXT",
562
- "valid_to": "TEXT",
563
- },
564
- "edges_v2": {
565
- "valid_from": "TEXT",
566
- "valid_to": "TEXT",
567
- "superseded_by": "TEXT",
568
- },
569
- }
570
-
571
- def _drop_stale_empty_v2_tables(self, conn: sqlite3.Connection) -> None:
572
- """Drop v2 tables that predate a schema change — but only when empty.
573
-
574
- ``CREATE TABLE IF NOT EXISTS`` never upgrades an existing table, so a
575
- v2 table created by an older version keeps its old columns and breaks
576
- inserts. Recreating is safe precisely because these tables have never
577
- held data (the v2 read-path isn't wired yet); we refuse to drop any
578
- table that contains rows.
579
- """
580
- # edges_v2 first (it has FKs into nodes_v2)
581
- for table in ("edges_v2", "nodes_v2"):
582
- exists = conn.execute(
583
- "SELECT 1 FROM sqlite_master WHERE type='table' AND name=?", (table,)
584
- ).fetchone()
585
- if not exists:
586
- continue
587
- cols = {
588
- r[1] for r in conn.execute(f"PRAGMA table_info({table})").fetchall()
589
- }
590
- missing = self._V2_EXPECTED_COLUMNS[table] - cols
591
- if not missing:
592
- continue
593
- # Additive columns heal in place without touching data.
594
- addable = self._V2_ADDABLE_COLUMNS.get(table, {})
595
- for col in sorted(missing & set(addable)):
596
- conn.execute(f"ALTER TABLE {table} ADD COLUMN {col} {addable[col]}")
597
- missing -= set(addable)
598
- if not missing:
599
- continue
600
- count = conn.execute(f"SELECT COUNT(*) FROM {table}").fetchone()[0]
601
- if count == 0:
602
- conn.execute(f"DROP TABLE {table}")
603
- else:
604
- logging.warning(
605
- "kg_schema: %s is missing columns %s but holds %d rows — "
606
- "leaving it untouched (manual migration required).",
607
- table,
608
- sorted(missing),
609
- count,
610
- )
611
-
612
- def init_schema(self, conn: Optional[sqlite3.Connection] = None) -> None:
613
- """Create the v2 schema and record metadata.
614
-
615
- Pass ``conn`` to run inside the caller's open transaction (used by the
616
- atomic knowledge_graph migration); otherwise a private connection is
617
- opened and committed. Uses ``_exec_script`` rather than
618
- ``executescript`` so it never force-commits the caller's transaction.
619
- """
620
- if conn is not None:
621
- self._init_schema_on(conn)
622
- return
623
- with self._conn() as own:
624
- self._init_schema_on(own)
625
-
626
- def _rebuild_edges_identity(self, conn: sqlite3.Connection) -> None:
627
- """Migrate edges_v2 from the pre-v4 UNIQUE(source, target, legacy_type)
628
- identity to UNIQUE(source, target, type, legacy_type).
629
-
630
- SQLite cannot alter constraints, so this is a create→copy→swap inside
631
- the caller's transaction. Data-preserving: every existing row keeps its
632
- legacy_type discriminator. Re-entrant: keyed on the actual constraint
633
- in sqlite_master, not a one-time stamp.
634
- """
635
- row = conn.execute(
636
- "SELECT sql FROM sqlite_master WHERE type='table' AND name='edges_v2'"
637
- ).fetchone()
638
- if not row or "UNIQUE(source, target, type, legacy_type)" in (row["sql"] or ""):
639
- return
640
- conn.execute("ALTER TABLE edges_v2 RENAME TO edges_v2_old")
641
- # Recreate from the canonical DDL (edges_v2 portion of SCHEMA_SQL).
642
- start = SCHEMA_SQL.index("CREATE TABLE IF NOT EXISTS edges_v2")
643
- end = SCHEMA_SQL.index(");", start) + 2
644
- conn.execute(SCHEMA_SQL[start:end].rstrip(";"))
645
- conn.execute(
646
- """
647
- INSERT INTO edges_v2 (id, source, target, type, legacy_type, weight,
648
- confidence, evidence, metadata, created_by, created_at)
649
- SELECT id, source, target, type, legacy_type, weight,
650
- confidence, evidence, metadata, created_by, created_at
651
- FROM edges_v2_old
652
- """
653
- )
654
- conn.execute("DROP TABLE edges_v2_old")
655
- logging.info(
656
- "kg_schema: rebuilt edges_v2 with (source, target, type, legacy_type) identity"
657
- )
658
-
659
- def _init_schema_on(self, conn: sqlite3.Connection) -> None:
660
- self._drop_stale_empty_v2_tables(conn)
661
- self._rebuild_edges_identity(conn)
662
- _exec_script(conn, SCHEMA_SQL)
663
- conn.execute(
664
- "INSERT OR REPLACE INTO kg_meta(key, value) VALUES (?, ?)",
665
- ("schema_version", str(KG_SCHEMA_V2_VERSION)),
666
- )
667
- conn.execute(
668
- "INSERT OR REPLACE INTO kg_meta(key, value) VALUES (?, ?)",
669
- ("embed_dim", str(EMBED_DIM)),
670
- )
671
-
672
- # ── Temporal stamping (v11.1.0) ──────────────────────────
673
- #
674
- # These are *primitives*, not a policy: the only caller in the product is
675
- # the review-approval path in :mod:`lattice_brain.synthesis`. Background
676
- # jobs and agents never call them directly — they raise a proposal and the
677
- # user approves it. See ``ARCHITECTURE.md`` → "Temporal knowledge".
678
- def stamp_node_validity(
679
- self,
680
- node_id: str,
681
- *,
682
- valid_from: Optional[str] = None,
683
- valid_to: Optional[str] = None,
684
- superseded_by: Optional[str] = None,
685
- ) -> bool:
686
- """Stamp a node's validity window. ``True`` when a row was updated.
687
-
688
- Only the arguments actually supplied are written; ``None`` leaves the
689
- stored value alone (it never clears a column back to NULL, so a second
690
- resolution cannot silently un-supersede an earlier one).
691
- """
692
- return self._stamp_row(
693
- "nodes_v2",
694
- node_id,
695
- {
696
- "valid_from": valid_from,
697
- "valid_to": valid_to,
698
- "superseded_by": superseded_by,
699
- },
700
- )
701
-
702
- def touch_node(self, node_id: str, *, at: Optional[str] = None) -> bool:
703
- """Record one access: bump ``importance_score`` and set ``last_used``.
704
-
705
- Read-path bookkeeping for the importance/decay report. Returns whether
706
- a row existed; callers treat a ``False``/failure as harmless.
707
- """
708
- with self._conn() as conn:
709
- cursor = conn.execute(
710
- "UPDATE nodes_v2 SET importance_score = importance_score + 1.0, "
711
- "last_used = ? WHERE id = ?",
712
- (at or _stamp_now(), str(node_id)),
713
- )
714
- return int(cursor.rowcount or 0) > 0
715
-
716
- def _stamp_row(
717
- self, table: str, row_id: str, updates: Dict[str, Optional[str]]
718
- ) -> bool:
719
- fields = {key: value for key, value in updates.items() if value is not None}
720
- if not fields:
721
- return False
722
- assignments = ", ".join(f"{key}=?" for key in fields)
723
- with self._conn() as conn:
724
- cursor = conn.execute(
725
- f"UPDATE {table} SET {assignments} WHERE id=?",
726
- (*fields.values(), str(row_id)),
727
- )
728
- return int(cursor.rowcount or 0) > 0
729
-
730
- # ── Maintenance ──────────────────────────────────────────
731
- def stats(self) -> Dict[str, Any]:
732
- with self._conn() as conn:
733
- n_nodes = conn.execute("SELECT COUNT(*) FROM nodes_v2").fetchone()[0]
734
- n_edges = conn.execute("SELECT COUNT(*) FROM edges_v2").fetchone()[0]
735
- per_type = {
736
- r["type"]: r["c"]
737
- for r in conn.execute(
738
- "SELECT type, COUNT(*) AS c FROM nodes_v2 GROUP BY type"
739
- ).fetchall()
740
- }
741
- per_edge = {
742
- r["type"]: r["c"]
743
- for r in conn.execute(
744
- "SELECT type, COUNT(*) AS c FROM edges_v2 GROUP BY type"
745
- ).fetchall()
746
- }
747
- return {
748
- "schema_version": KG_SCHEMA_V2_VERSION,
749
- "embed_dim": EMBED_DIM,
750
- "nodes": n_nodes,
751
- "edges": n_edges,
752
- "by_node_type": per_type,
753
- "by_edge_type": per_edge,
754
- }
755
-
756
-
757
- # NOTE: legacy → v2 reprojection lives in ``knowledge_graph.py``
758
- # (``KnowledgeGraphStore._backfill_v2_if_needed`` / ``_v2_project_node``/_edge),
759
- # which is the single live, version-gated migration path. The old standalone
760
- # ``migrate_legacy_to_v2()`` helper + CLI ``migrate`` subcommand were removed as
761
- # dead code (no callers); the normalized projection now writes the first-class
762
- # ``legacy_type``/``summary``/``metadata`` columns directly.
763
-
764
-
765
- # ── CLI ────────────────────────────────────────────────────────────────────
766
- def _cli() -> int:
767
- import argparse
768
-
769
- p = argparse.ArgumentParser(
770
- prog="kg_schema", description="Lattice AI KG v2 utilities"
771
- )
772
- sub = p.add_subparsers(dest="cmd", required=True)
773
-
774
- sub_init = sub.add_parser("init", help="initialize v2 schema in a DB")
775
- sub_init.add_argument("db", help="path to sqlite db")
776
-
777
- sub_stats = sub.add_parser("stats", help="print store statistics")
778
- sub_stats.add_argument("db", help="path to sqlite db")
779
-
780
- args = p.parse_args()
781
- if args.cmd == "init":
782
- KGStoreV2(args.db).init_schema()
783
- print(f"initialized v2 schema in {args.db}")
784
- return 0
785
- if args.cmd == "stats":
786
- print(json.dumps(KGStoreV2(args.db).stats(), indent=2, ensure_ascii=False))
787
- return 0
788
- return 2
789
-
790
-
791
- if __name__ == "__main__":
792
- raise SystemExit(_cli())