ltcai 11.5.2 → 11.7.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 (443) hide show
  1. package/README.md +93 -148
  2. package/bin/ltcai.js +234 -24
  3. package/docs/CHANGELOG.md +119 -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 +54 -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-BPcVAbOL.js} +1 -1
  96. package/static/app/assets/AdminConsole-Bw1ATQL0.js +1 -0
  97. package/static/app/assets/{Brain-3VCSHFcn.js → Brain-CT92Kos0.js} +2 -2
  98. package/static/app/assets/{BrainHome-Qm8eaztx.js → BrainHome-CFBkt1K_.js} +1 -1
  99. package/static/app/assets/{BrainSignals-DS9BtKOW.js → BrainSignals-ReLWF2H8.js} +1 -1
  100. package/static/app/assets/Capture-BsTokYkk.js +1 -0
  101. package/static/app/assets/{Chronicle-BGvuAchH.js → Chronicle-B6f0T9id.js} +1 -1
  102. package/static/app/assets/{CommandPalette-Bqhm0Urn.js → CommandPalette-CuvjTv1u.js} +1 -1
  103. package/static/app/assets/{Library-BV6NnF0a.js → Library-BGJbG9Hd.js} +1 -1
  104. package/static/app/assets/{LivingBrain-GzenJchP.js → LivingBrain-DGYK_Jsa.js} +1 -1
  105. package/static/app/assets/{ProductFlow-DEP6-vML.js → ProductFlow-DXBC6brE.js} +1 -1
  106. package/static/app/assets/{ReviewCard-CNZ7XjWG.js → ReviewCard-HXRle3qq.js} +2 -2
  107. package/static/app/assets/System-CMHSO9qM.js +1 -0
  108. package/static/app/assets/arrow-left-BfmkskWx.js +1 -0
  109. package/static/app/assets/{bot-B_K1Tdmw.js → bot-Cn8bWRuq.js} +1 -1
  110. package/static/app/assets/{brain-DWyaV1L1.js → brain-CQJberbE.js} +1 -1
  111. package/static/app/assets/{button-aTn4s84A.js → button-Ct9f2_oT.js} +1 -1
  112. package/static/app/assets/circle-check-DruOxB-4.js +1 -0
  113. package/static/app/assets/{circle-pause-xKgeGXkT.js → circle-pause-CmzC_apg.js} +1 -1
  114. package/static/app/assets/{circle-play-DkT6tYPX.js → circle-play-D8mW2aQ7.js} +1 -1
  115. package/static/app/assets/{cpu-85xYObUC.js → cpu-DZcdd0PZ.js} +1 -1
  116. package/static/app/assets/{download-B5Fm7YXo.js → download-bv1KEPGQ.js} +1 -1
  117. package/static/app/assets/{folder-open-kk2Xa52u.js → folder-open-d-Pip5gr.js} +1 -1
  118. package/static/app/assets/{hard-drive-DkA3zBW_.js → hard-drive-D20iavUb.js} +1 -1
  119. package/static/app/assets/index-D9x-kSNy.css +2 -0
  120. package/static/app/assets/{index-BMPdTmlY.js → index-Do83hDzJ.js} +3 -3
  121. package/static/app/assets/{input-B0nRf2jO.js → input-BLXVNmj1.js} +1 -1
  122. package/static/app/assets/{link-2-Dwb4gnTc.js → link-2-BPJOFlAy.js} +1 -1
  123. package/static/app/assets/{permissionCopy-CQDUBrOZ.js → permissionCopy-ChdJd493.js} +1 -1
  124. package/static/app/assets/primitives-Cv5tbZBY.js +1 -0
  125. package/static/app/assets/search-CT9aho2j.js +1 -0
  126. package/static/app/assets/{share-2-BsrxFglO.js → share-2-YNX_NtMU.js} +1 -1
  127. package/static/app/assets/{shield-alert-5BStfp2_.js → shield-alert-DuQ3zrVL.js} +1 -1
  128. package/static/app/assets/{textarea-Cg8IUA-k.js → textarea-DqwLnli4.js} +1 -1
  129. package/static/app/assets/{useFocusTrap-CYKvE46M.js → useFocusTrap-ZVI98jaW.js} +1 -1
  130. package/static/app/assets/{useMutation-CSn9t1op.js → useMutation-CVC4qv_D.js} +1 -1
  131. package/static/app/assets/{useQuery-CY2OI2uy.js → useQuery-C7BeG4HU.js} +1 -1
  132. package/static/app/assets/{utils-Ddol2RWD.js → utils-CiFtIdZq.js} +1 -1
  133. package/static/app/assets/{workspace-BqDwOz_p.js → workspace-DQz9vIId.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/AdminConsole-cf4npybT.js +0 -1
  437. package/static/app/assets/Capture-DiQ219jW.js +0 -1
  438. package/static/app/assets/System-CieofHQa.js +0 -1
  439. package/static/app/assets/arrow-left-kfsrk0mv.js +0 -1
  440. package/static/app/assets/circle-check-qqLug9nU.js +0 -1
  441. package/static/app/assets/index-DxmOfNRi.css +0 -2
  442. package/static/app/assets/primitives-SNp0LRJz.js +0 -1
  443. package/static/app/assets/search-BcHqkjoy.js +0 -1
@@ -1,105 +1,58 @@
1
- """The single normalized entrypoint every source is fed through.
1
+ """What this machine will do with a picture, a recording, or a video.
2
2
 
3
3
  Source → normalize → content hash → (file | text) ingest → provenance
4
4
 
5
- :meth:`IngestionPipeline.ingest` owns normalization, the gate reads, idempotency
6
- reporting, provenance capture, the advisory quality annotation, and routing
7
- every ingest through the shared ``dispatch_tool`` lifecycle so ``pre_tool`` /
8
- ``post_tool`` hooks fire on data ingestion exactly as they do on tool calls.
9
- The per-source doors live in ``routing.py``, the folder walk in ``folders.py``
10
- and background scheduling in ``jobs_api.py``; this module is what they compose
11
- into, and it owns the constructor state all three read.
5
+ That was this module: :meth:`IngestionPipeline.ingest` owned normalization, the
6
+ gate reads, idempotency reporting, provenance capture, the advisory quality
7
+ annotation, and routing every ingest through the shared ``dispatch_tool``
8
+ lifecycle. The per-source doors lived in ``routing.py``, the folder walk in
9
+ ``folders.py`` and background scheduling in ``jobs_api.py``.
10
+
11
+ v11.6.0 §Wave 2.5 made Rust the single writer of the Brain, so the whole write
12
+ side moved to ``lattice-core``'s graph write engine and ``lattice-jobs``. What
13
+ a stateless worker still owns is the *capability question* behind
14
+ ``GET /api/ingestion/multimodal``: which gates are on, which model-backed ports
15
+ actually resolved, and — if a video would be refused — which of the three
16
+ reasons applies. The answer is derived from this process's environment and its
17
+ injected ports, which is why it is still answered here and not natively.
12
18
  """
13
19
 
14
20
  from __future__ import annotations
15
21
 
16
- from typing import Any, Dict, List, Optional, Tuple
22
+ from typing import Any, Dict, Optional
17
23
 
18
- from ..graph.vector_index import DEFAULT_TICK_LIMIT as VECTOR_TICK_LIMIT
19
- from ..ingestion_jobs import BackgroundIngestionQueue
20
24
  from ..multimodal import (
21
25
  DEFAULT_KEYFRAMES,
22
- MODALITY_AUDIO,
23
- MODALITY_IMAGE,
24
- MODALITY_VIDEO,
25
26
  VIDEO_UNAVAILABLE_DETAIL,
26
27
  MultimodalPorts,
27
28
  ffmpeg_available,
28
29
  )
29
- from ..quiet import quiet
30
- from ..runtime.hooks import dispatch_tool
31
- from ..utils import utc_now_iso
32
30
  from .constants import (
33
31
  ALLOW_MULTIMODAL_ENV,
34
32
  ALLOW_VIDEO_ENV,
35
- AUTO_VECTOR_INDEX_GATE,
36
- CHAT_SOURCE_TYPES,
37
- DEFAULT_MAX_TEXT_BYTES,
38
- FILE_SOURCE_TYPES,
39
- MEMORY_SOURCE_TYPES,
40
33
  MULTIMODAL_GATE,
41
34
  VIDEO_GATE,
42
35
  )
43
- from .folders import IngestionFolderMixin
44
- from .jobs_api import IngestionJobsMixin
45
- from .models import IngestionItem, IngestionResult
46
- from .quality import QUALITY_LOW_WARNING, assess_extraction_quality
47
- from .routing import IngestionRoutingMixin
48
36
 
49
37
 
50
- class IngestionPipeline(
51
- IngestionRoutingMixin, IngestionFolderMixin, IngestionJobsMixin
52
- ):
53
- """Single normalized entrypoint that feeds every source into the graph."""
38
+ class IngestionPipeline:
39
+ """The multi-modal capability probe. Writes nothing, holds no store."""
54
40
 
55
41
  def __init__(
56
42
  self,
57
- knowledge_graph: Any,
58
43
  *,
59
- hooks: Any = None,
60
- enable_graph: bool = True,
61
- audit: Optional[Any] = None,
62
- max_text_bytes: int = DEFAULT_MAX_TEXT_BYTES,
63
- pipeline_name: str = "unified-ingestion",
64
- bg_queue: Optional[BackgroundIngestionQueue] = None,
65
- auto_vector_index: bool = True,
66
44
  allow_multimodal: bool = False,
67
45
  multimodal: Optional[MultimodalPorts] = None,
68
46
  ) -> None:
69
- self._kg = knowledge_graph
70
- self._hooks = hooks
71
- self._enable = bool(enable_graph)
72
- self._audit = audit
73
- self._max_text_bytes = int(max_text_bytes)
74
- self._pipeline_name = pipeline_name
75
- # Background job state lives in the graph database by default, so a
76
- # restart resumes from the last completed item instead of replaying the
77
- # whole corpus. A store without a usable ``db_path`` (mocks, disabled
78
- # graph) degrades to the historical in-memory queue, which reports
79
- # itself as non-durable through ``BackgroundIngestionQueue.describe()``.
80
- self._bg_queue = bg_queue or BackgroundIngestionQueue(
81
- db_path=getattr(knowledge_graph, "db_path", None)
82
- )
83
- # Incremental vector sync after each successful non-duplicate ingest.
84
- # Constructor opt-out AND gate opt-out (LATTICEAI_AUTO_VECTOR_INDEX=0,
85
- # or the settings toggle bound to it) both disable it; a vector failure
86
- # never fails the ingest. The gate half is asked per ingest rather than
87
- # frozen here, so turning it off takes effect on the next item.
88
- self._auto_vector_index_opt_in = bool(auto_vector_index)
89
47
  # Multi-modal routing. Off unless the caller asks for it *or* the gate
90
48
  # says yes — the env behind that gate is the escape hatch for an
91
49
  # install with no code path to the constructor (CLI, background
92
- # worker), and the gate is now asked per call so a runtime toggle can
93
- # reach it. A constructor ``True`` is still a permanent yes.
50
+ # worker), and the gate is asked per call so a runtime toggle can reach
51
+ # it. A constructor ``True`` is still a permanent yes.
94
52
  self._multimodal_opt_in = bool(allow_multimodal)
95
53
  self._multimodal = multimodal or MultimodalPorts()
96
54
  self._keyframes = DEFAULT_KEYFRAMES
97
55
 
98
- @property
99
- def _auto_vector_index(self) -> bool:
100
- """Whether a landed ingest also syncs its vector, asked *now*."""
101
- return self._auto_vector_index_opt_in and AUTO_VECTOR_INDEX_GATE.enabled()
102
-
103
56
  @property
104
57
  def _allow_multimodal(self) -> bool:
105
58
  """Whether pictures and recordings route by modality, asked *now*."""
@@ -114,9 +67,6 @@ class IngestionPipeline(
114
67
  """An injected keyframe port counts as a decoder; otherwise, ffmpeg."""
115
68
  return self._multimodal.keyframe_extractor is not None or ffmpeg_available()
116
69
 
117
- def available(self) -> bool:
118
- return self._enable and self._kg is not None
119
-
120
70
  def multimodal_status(self) -> Dict[str, Any]:
121
71
  """What this pipeline will do with a picture or a recording, honestly.
122
72
 
@@ -154,333 +104,5 @@ class IngestionPipeline(
154
104
  )
155
105
  return VIDEO_UNAVAILABLE_DETAIL
156
106
 
157
- # ── public API ───────────────────────────────────────────────────────────
158
- def ingest(self, item: IngestionItem, *, user_email: Optional[str] = None) -> IngestionResult:
159
- """Normalize, hash, route through dispatch_tool, and record provenance."""
160
- source_type = str(item.source_type or "text").strip().lower()
161
- if not self.available():
162
- return IngestionResult(
163
- status="unavailable", source_type=source_type,
164
- indexing_status="skipped",
165
- detail="Knowledge Graph is disabled (LATTICEAI_ENABLE_GRAPH).",
166
- )
167
-
168
- # Modality routing is a no-op while the flag is off: ``modality`` stays
169
- # "text" and every branch below behaves exactly as it did before.
170
- modality = self._modality_for(item, source_type)
171
- if modality == MODALITY_VIDEO and not self._allow_video:
172
- # Recognized and refused, with the reason that actually applies
173
- # right now — a missing decoder is not the same answer as a
174
- # switched-off feature, and the caller can act on the difference.
175
- return IngestionResult(
176
- status="unavailable", source_type=source_type,
177
- indexing_status="skipped", detail=self._video_refusal(),
178
- )
179
-
180
- captured_at = item.captured_at or utc_now_iso()
181
- owner = item.owner or user_email
182
- tool_name = f"kg_ingest.{source_type}"
183
- # Only the keys are read by the hook payload, so this dict is safe/cheap.
184
- args = {
185
- "source_type": source_type,
186
- "source_uri": item.source_uri,
187
- "owner": owner,
188
- "workspace_id": item.workspace_id,
189
- }
190
-
191
- def _run() -> Dict[str, Any]:
192
- if source_type in CHAT_SOURCE_TYPES:
193
- return self._ingest_chat(item, source_type=source_type, owner=owner)
194
- if source_type in MEMORY_SOURCE_TYPES:
195
- return self._ingest_memory_record(item, source_type=source_type, owner=owner)
196
- if modality == MODALITY_IMAGE:
197
- return self._ingest_image(item, source_type=source_type, owner=owner, captured_at=captured_at)
198
- if modality == MODALITY_AUDIO:
199
- return self._ingest_audio(item, source_type=source_type, owner=owner, captured_at=captured_at)
200
- if modality == MODALITY_VIDEO:
201
- return self._ingest_video(item, source_type=source_type, owner=owner, captured_at=captured_at)
202
- if source_type in FILE_SOURCE_TYPES or (item.path and not item.text):
203
- return self._ingest_file(item, source_type=source_type, owner=owner, captured_at=captured_at)
204
- return self._ingest_text(item, source_type=source_type, owner=owner, captured_at=captured_at)
205
-
206
- # v9.8.0 observation-only quality gate: computed *before* the write so
207
- # the search never matches the node we are about to create. It is
208
- # recorded on the result and never skips an ingest (behavior unchanged).
209
- quality_text = self._extractable_text(item)
210
- quality_gate = self._observe_quality_gate(
211
- item, source_type=source_type, text=quality_text,
212
- )
213
-
214
- try:
215
- raw = dispatch_tool(
216
- self._hooks, tool_name, args, _run,
217
- user_email=user_email, workspace_id=item.workspace_id, source="ingestion",
218
- )
219
- except PermissionError as exc:
220
- return IngestionResult(
221
- status="blocked", source_type=source_type,
222
- indexing_status="skipped", detail=str(exc),
223
- )
224
- except FileNotFoundError as exc:
225
- return IngestionResult(
226
- status="failed", source_type=source_type,
227
- indexing_status="failed", detail=str(exc),
228
- )
229
- except Exception as exc: # noqa: BLE001 — surface as a failed result, never crash the caller
230
- return IngestionResult(
231
- status="failed", source_type=source_type,
232
- indexing_status="failed", detail=str(exc),
233
- )
234
-
235
- node_id = raw.get("node_id")
236
- content_hash = raw.get("content_hash") or raw.get("sha256")
237
- chunk_ids = list(raw.get("chunk_ids") or [])
238
- title = raw.get("title") or item.title
239
-
240
- # Incremental vector-index sync (opt-in via auto_vector_index +
241
- # LATTICEAI_AUTO_VECTOR_INDEX). Exception-safe by contract: the graph
242
- # write above already landed, so a vector failure only downgrades
243
- # indexing_status to "pending" — index_status()/rebuild_vector_index()
244
- # discover the same node as backlog and pick it up later.
245
- indexing_status = "indexed"
246
- vector_detail: Optional[str] = None
247
- if node_id and self._auto_vector_index and not bool(raw.get("duplicate")):
248
- indexing_status, vector_detail = self._sync_vector_index(node_id)
249
- embedded = bool(self._kg.node_is_embedded(node_id)) if node_id else False
250
-
251
- # Provenance capture must never turn an already-persisted ingest into a
252
- # caller-visible failure: the graph write above succeeded, so a broken
253
- # provenance table degrades the result instead of raising.
254
- provenance_detail: Optional[str] = None
255
- try:
256
- prov = self._kg.record_provenance(
257
- node_id=node_id,
258
- source_type=source_type,
259
- pipeline=self._pipeline_name,
260
- source_uri=item.source_uri,
261
- content_hash=content_hash,
262
- title=title,
263
- owner=owner,
264
- workspace_id=item.workspace_id,
265
- captured_at=captured_at,
266
- modified_at=item.modified_at,
267
- embedded=embedded,
268
- linked=bool(raw.get("source_node_id")),
269
- duplicate=bool(raw.get("duplicate")),
270
- agent_used=item.agent_used,
271
- chunk_count=len(chunk_ids),
272
- permissions=item.permissions,
273
- metadata=item.metadata,
274
- )
275
- except Exception as exc: # noqa: BLE001 — the ingest itself already landed
276
- prov = {}
277
- provenance_detail = f"provenance capture failed: {exc}"
278
- if self._audit is not None:
279
- try:
280
- self._audit(
281
- "kg_ingest",
282
- {
283
- "source_type": source_type, "node_id": node_id,
284
- "content_hash": content_hash, "duplicate": bool(raw.get("duplicate")),
285
- },
286
- user_email,
287
- )
288
- except Exception: # noqa: BLE001 — audit must never break ingestion
289
- quiet()
290
-
291
- # A modality-aware door scores its own extraction (a picture's quality
292
- # is "how much of it can be retrieved", not "does the text read well"),
293
- # so its verdict wins. Text/file doors never set the key and keep the
294
- # historical scoring untouched.
295
- extraction_quality = raw.get("extraction_quality") or self._assess_item_quality(
296
- item, source_type=source_type, text=quality_text, chunk_ids=chunk_ids,
297
- )
298
- warnings: List[str] = []
299
- if extraction_quality is not None and extraction_quality.get("level") == "low":
300
- warnings.append(QUALITY_LOW_WARNING)
301
-
302
- details = [d for d in (provenance_detail, vector_detail) if d]
303
- return IngestionResult(
304
- status="ok",
305
- source_type=source_type,
306
- node_id=node_id,
307
- source_node_id=raw.get("source_node_id"),
308
- content_hash=content_hash,
309
- title=title,
310
- chunk_ids=chunk_ids,
311
- chunk_count=len(chunk_ids),
312
- duplicate=bool(raw.get("duplicate")),
313
- embedded=embedded,
314
- indexing_status=indexing_status,
315
- provenance_id=prov.get("id"),
316
- detail="; ".join(details) if details else None,
317
- extraction_quality=extraction_quality,
318
- warnings=warnings,
319
- quality_gate=quality_gate,
320
- )
321
-
322
- # ── extraction quality (v9.8.0 A1 — advisory, never gates) ───────────────
323
- @staticmethod
324
- def _extractable_text(item: IngestionItem) -> Optional[str]:
325
- """Best available extracted text for quality scoring/gating."""
326
- if item.text is not None:
327
- return item.text
328
- extracted = (item.metadata or {}).get("extracted")
329
- if isinstance(extracted, dict):
330
- content = extracted.get("content") or extracted.get("text")
331
- if content is not None:
332
- return str(content)
333
- return None
334
-
335
- @staticmethod
336
- def _upstream_confidence(item: IngestionItem) -> Optional[Any]:
337
- """Upstream extractor confidence, if the capture surface supplied one."""
338
- meta = item.metadata or {}
339
- extracted = meta.get("extracted")
340
- if isinstance(extracted, dict) and extracted.get("confidence") is not None:
341
- return extracted.get("confidence")
342
- if meta.get("extraction_confidence") is not None:
343
- return meta.get("extraction_confidence")
344
- return None
345
107
 
346
- def _assess_item_quality(
347
- self,
348
- item: IngestionItem,
349
- *,
350
- source_type: str,
351
- text: Optional[str],
352
- chunk_ids: List[str],
353
- ) -> Optional[Dict[str, Any]]:
354
- """Quality annotation for document-like sources (not chat/memory)."""
355
- if source_type in CHAT_SOURCE_TYPES or source_type in MEMORY_SOURCE_TYPES:
356
- return None
357
- confidence = self._upstream_confidence(item)
358
- if text is not None or confidence is not None:
359
- return assess_extraction_quality(
360
- text, source_type=source_type, upstream_confidence=confidence,
361
- )
362
- # File door without inline extraction (e.g. PDF): the pipeline never saw
363
- # the text, so score honestly from the chunk output instead of guessing.
364
- if chunk_ids:
365
- return {
366
- "score": 0.5,
367
- "level": "medium",
368
- "reasons": ["content_extracted_upstream_not_scored"],
369
- }
370
- return {"score": 0.0, "level": "low", "reasons": ["no_extracted_text"]}
371
-
372
- def _observe_quality_gate(
373
- self,
374
- item: IngestionItem,
375
- *,
376
- source_type: str,
377
- text: Optional[str],
378
- ) -> Optional[Dict[str, Any]]:
379
- """Observation-mode ``gate_ingest_candidate`` wiring.
380
-
381
- Records what the proactive gate *would* decide (ingest /
382
- skip_duplicate / review) without ever acting on it. Any failure —
383
- import, search, gate — yields ``None``; the ingest proceeds untouched.
384
- """
385
- if source_type in CHAT_SOURCE_TYPES or source_type in MEMORY_SOURCE_TYPES:
386
- return None
387
- body = str(text or "").strip()
388
- if not body:
389
- return None
390
- try:
391
- from ..graph.proactive import gate_ingest_candidate
392
- except Exception: # noqa: BLE001 — optional observation, never required
393
- return None
394
-
395
- def _search(query: str) -> Any:
396
- snippet = str(query or "")[:400]
397
- try:
398
- if item.workspace_id:
399
- return self._kg.search(
400
- snippet, 20, allowed_workspaces={item.workspace_id},
401
- )
402
- return self._kg.search(snippet, 20)
403
- except TypeError:
404
- # Older store without workspace-scoped search.
405
- return self._kg.search(snippet, 20)
406
-
407
- try:
408
- gate = gate_ingest_candidate(body, _search)
409
- except Exception: # noqa: BLE001 — observation must never fail the ingest
410
- return None
411
- parts = [str(gate.get("reason") or "")]
412
- if gate.get("similarity") is not None:
413
- parts.append(f"similarity={gate.get('similarity')}")
414
- if gate.get("match_id"):
415
- parts.append(f"match={gate.get('match_id')}")
416
- return {
417
- "action": str(gate.get("action") or "review"),
418
- "detail": "; ".join(p for p in parts if p),
419
- }
420
-
421
- def _queue_pending_embed(self, node_id: str, detail: str) -> bool:
422
- """Hand a node the inline sync could not embed to the background queue.
423
-
424
- Before v11.1.0 ``indexing_status="pending"`` was the end of the story:
425
- honest, but nobody was coming back for it, so the node stayed
426
- unsearchable until a human ran a rebuild. The durable queue is who
427
- comes back. A store without one (older stores, mocks) just keeps the
428
- old behaviour — the node is still visible as ``index_status`` backlog.
429
- """
430
- queue = getattr(self._kg, "vector_queue", None)
431
- if queue is None:
432
- return False
433
- try:
434
- return bool(queue.schedule(node_id, detail=detail))
435
- except Exception: # noqa: BLE001 — queueing must never fail an ingest
436
- quiet()
437
- return False
438
-
439
- def _sync_vector_index(self, node_id: str) -> Tuple[str, Optional[str]]:
440
- """Best-effort incremental vector sync → (indexing_status, detail).
441
-
442
- Any failure — missing method on older stores, embedding provider down,
443
- storage error — yields ``("pending", detail)`` so a later
444
- ``rebuild_vector_index`` run picks the node up from the backlog, and
445
- the node is queued for background embedding so that pickup happens on
446
- its own.
447
- """
448
- sync = getattr(self._kg, "index_node_incremental", None)
449
- if not callable(sync):
450
- # Older store without the incremental path: the write-side already
451
- # embeds inline, so nothing extra to do.
452
- return "indexed", None
453
- try:
454
- outcome = sync(node_id) or {}
455
- except Exception as exc: # noqa: BLE001 — vector sync must never fail the ingest
456
- return "pending", self._pending_detail(node_id, f"vector index sync failed: {exc}")
457
- if str(outcome.get("status") or "") == "failed":
458
- reason = outcome.get("detail") or "unknown error"
459
- return "pending", self._pending_detail(
460
- node_id, f"vector index sync failed: {reason}"
461
- )
462
- return "indexed", None
463
-
464
- def _pending_detail(self, node_id: str, reason: str) -> str:
465
- """``reason``, plus whether a background retry was actually scheduled."""
466
- if self._queue_pending_embed(node_id, reason):
467
- return f"{reason}; queued for background embedding"
468
- return reason
469
-
470
- def drain_vector_queue(self, limit: int = VECTOR_TICK_LIMIT) -> Dict[str, Any]:
471
- """Run one background-embedding tick over the store's pending backlog.
472
-
473
- Deliberately caller-driven (a scheduler, a CLI, a test) rather than a
474
- thread this pipeline owns: the queue is durable, so "who runs it" is a
475
- deployment decision, not a property of having ingested something.
476
- """
477
- queue = getattr(self._kg, "vector_queue", None)
478
- if queue is None:
479
- return {
480
- "claimed": 0,
481
- "indexed": 0,
482
- "retried": 0,
483
- "failed": 0,
484
- "detail": "this store has no background vector queue",
485
- }
486
- return dict(queue.tick(limit))
108
+ __all__ = ["IngestionPipeline"]
@@ -34,6 +34,12 @@ Brain Core owns none of those models. Every heavy dependency arrives as an
34
34
  injected callable (:class:`MultimodalPorts`), which is also why this module
35
35
  imports nothing from ``latticeai``.
36
36
 
37
+ v11.6.0 removed the *writing* half — ``write_image_memory``,
38
+ ``write_video_memory``, the keyframe writer and the node-id helpers. Extraction
39
+ returns facts; ``lattice-core``'s graph write engine turns them into nodes. What
40
+ is left here is exactly what ``POST /worker/multimodal/describe`` and
41
+ ``POST /worker/asr`` answer with.
42
+
37
43
  Split into cohesive submodules in v11.3.0 (no behaviour change): ``common``
38
44
  (taxonomy + shared helpers), ``ports`` (injected capabilities + the ffmpeg
39
45
  fallback), ``images``, ``audio``, ``video``. This module re-exports every name
@@ -74,16 +80,8 @@ from .common import (
74
80
  from .common import _sha256_file as _sha256_file
75
81
  from .common import _sha256_text as _sha256_text
76
82
  from .common import _split_index_text as _split_index_text
77
- from .images import (
78
- ImageFacts,
79
- extract_image_facts,
80
- image_node_id,
81
- image_quality_score,
82
- write_image_memory,
83
- )
83
+ from .images import ImageFacts, extract_image_facts, image_quality_score
84
84
  from .images import _apply_vision_embedding as _apply_vision_embedding
85
- from .images import _attach_concepts as _attach_concepts
86
- from .images import _attach_source as _attach_source
87
85
  from .images import _open_image as _open_image
88
86
  from .images import _run_ocr as _run_ocr
89
87
  from .images import _safe_caption as _safe_caption
@@ -112,12 +110,8 @@ from .video import (
112
110
  find_subtitle,
113
111
  parse_subtitles,
114
112
  read_video_facts,
115
- video_frame_dir,
116
- video_node_id,
117
113
  video_quality_score,
118
- write_video_memory,
119
114
  )
120
- from .video import _write_keyframes as _write_keyframes
121
115
 
122
116
  __all__ = [
123
117
  "AUDIO_EXTENSIONS",
@@ -151,14 +145,9 @@ __all__ = [
151
145
  "extract_keyframes",
152
146
  "ffmpeg_available",
153
147
  "find_subtitle",
154
- "image_node_id",
155
148
  "image_quality_score",
156
149
  "parse_subtitles",
157
150
  "read_video_facts",
158
151
  "transcribe_audio",
159
- "video_frame_dir",
160
- "video_node_id",
161
152
  "video_quality_score",
162
- "write_image_memory",
163
- "write_video_memory",
164
153
  ]