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.
- package/README.md +93 -148
- package/bin/ltcai.js +234 -24
- package/docs/CHANGELOG.md +119 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +8 -6
- package/docs/ENTERPRISE.md +2 -1
- package/docs/MULTI_AGENT_RUNTIME.md +12 -5
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +6 -3
- package/docs/REALTIME_COLLABORATION.md +1 -1
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/WORKFLOW_DESIGNER.md +3 -2
- package/docs/kg-schema.md +1 -1
- package/docs/v11.6.0_ONE_DOOR_PLAN.md +170 -0
- package/lattice_brain/__init__.py +42 -79
- package/lattice_brain/graph/__init__.py +9 -24
- package/lattice_brain/graph/_kg_common/__init__.py +13 -24
- package/lattice_brain/ingestion/__init__.py +19 -58
- package/lattice_brain/ingestion/pipeline.py +20 -398
- package/lattice_brain/multimodal/__init__.py +7 -18
- package/lattice_brain/multimodal/images.py +6 -264
- package/lattice_brain/multimodal/video.py +8 -247
- package/lattice_brain/runtime/__init__.py +8 -79
- package/lattice_brain/runtime/hooks.py +22 -584
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/agent_worker_seam.py +7 -80
- package/latticeai/api/health.py +6 -20
- package/latticeai/api/local_files.py +16 -613
- package/latticeai/api/models.py +12 -87
- package/latticeai/api/search.py +17 -255
- package/latticeai/api/tools.py +69 -750
- package/latticeai/api/voice_capture.py +8 -70
- package/latticeai/api/worker_compute.py +842 -0
- package/latticeai/api/worker_seams.py +216 -0
- package/latticeai/app_factory.py +23 -232
- package/latticeai/cli/entrypoint.py +36 -249
- package/latticeai/core/agent_permission.py +16 -91
- package/latticeai/core/messages.py +89 -531
- package/latticeai/runtime/access_runtime.py +0 -14
- package/latticeai/runtime/bootstrap.py +10 -21
- package/latticeai/runtime/brain_runtime.py +35 -43
- package/latticeai/runtime/build_phases/__init__.py +21 -37
- package/latticeai/runtime/build_phases/features.py +99 -389
- package/latticeai/runtime/build_phases/foundation.py +82 -392
- package/latticeai/runtime/build_phases/web.py +91 -408
- package/latticeai/runtime/build_phases/worker_profile.py +244 -0
- package/latticeai/runtime/lifespan_runtime.py +7 -16
- package/latticeai/runtime/platform_services_runtime.py +1 -15
- package/latticeai/runtime/runtime_context.py +13 -130
- package/latticeai/runtime/security_runtime.py +10 -103
- package/latticeai/services/architecture_readiness.py +82 -43
- package/latticeai/services/model_runtime/__init__.py +2 -11
- package/latticeai/services/model_runtime/service.py +4 -28
- package/latticeai/services/p_reinforce.py +10 -261
- package/latticeai/services/product_readiness.py +31 -38
- package/latticeai/services/search_service.py +37 -795
- package/latticeai/services/tool_dispatch.py +30 -386
- package/latticeai/services/voice_capture.py +13 -107
- package/latticeai/tools/__init__.py +22 -49
- package/latticeai/tools/commands.py +0 -163
- package/latticeai/tools/computer.py +0 -39
- package/latticeai/tools/documents.py +1 -134
- package/latticeai/tools/filesystem.py +1 -247
- package/latticeai/tools/knowledge.py +1 -52
- package/latticeai/tools/local_files.py +0 -20
- package/latticeai/worker_app.py +75 -0
- package/package.json +2 -3
- package/requirements.txt +0 -5
- package/scripts/agent_eval.py +16 -28
- package/scripts/brain_quality_eval.py +20 -183
- package/scripts/bump_version.py +5 -5
- package/scripts/check_current_release_docs.mjs +7 -4
- package/scripts/check_openapi_drift.mjs +10 -0
- package/scripts/check_server_i18n.mjs +2 -18
- package/scripts/compose_openapi.py +377 -0
- package/scripts/export_openapi.py +32 -4
- package/scripts/gen_messages_catalog_fixture.py +302 -0
- package/scripts/gen_openapi_fragments.py +365 -0
- package/scripts/gen_redact_fixture.py +196 -0
- package/scripts/gen_worker_allowlist_fixture.py +115 -0
- package/scripts/generate_agent_parity_fixtures.py +33 -14
- package/scripts/openapi_route_families.json +2161 -0
- package/scripts/release_screen_claims.json +54 -0
- package/scripts/run_integration_tests.mjs +134 -29
- package/scripts/run_sidecar_e2e.mjs +104 -11
- package/scripts/wheel_smoke.py +32 -22
- package/src-tauri/Cargo.lock +375 -9
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/src/backend.rs +151 -45
- package/src-tauri/src/main.rs +18 -18
- package/src-tauri/src/topology.rs +58 -88
- package/src-tauri/tauri.conf.json +1 -2
- package/static/app/asset-manifest.json +41 -41
- package/static/app/assets/{Act-DcQizkl1.js → Act-BPcVAbOL.js} +1 -1
- package/static/app/assets/AdminConsole-Bw1ATQL0.js +1 -0
- package/static/app/assets/{Brain-3VCSHFcn.js → Brain-CT92Kos0.js} +2 -2
- package/static/app/assets/{BrainHome-Qm8eaztx.js → BrainHome-CFBkt1K_.js} +1 -1
- package/static/app/assets/{BrainSignals-DS9BtKOW.js → BrainSignals-ReLWF2H8.js} +1 -1
- package/static/app/assets/Capture-BsTokYkk.js +1 -0
- package/static/app/assets/{Chronicle-BGvuAchH.js → Chronicle-B6f0T9id.js} +1 -1
- package/static/app/assets/{CommandPalette-Bqhm0Urn.js → CommandPalette-CuvjTv1u.js} +1 -1
- package/static/app/assets/{Library-BV6NnF0a.js → Library-BGJbG9Hd.js} +1 -1
- package/static/app/assets/{LivingBrain-GzenJchP.js → LivingBrain-DGYK_Jsa.js} +1 -1
- package/static/app/assets/{ProductFlow-DEP6-vML.js → ProductFlow-DXBC6brE.js} +1 -1
- package/static/app/assets/{ReviewCard-CNZ7XjWG.js → ReviewCard-HXRle3qq.js} +2 -2
- package/static/app/assets/System-CMHSO9qM.js +1 -0
- package/static/app/assets/arrow-left-BfmkskWx.js +1 -0
- package/static/app/assets/{bot-B_K1Tdmw.js → bot-Cn8bWRuq.js} +1 -1
- package/static/app/assets/{brain-DWyaV1L1.js → brain-CQJberbE.js} +1 -1
- package/static/app/assets/{button-aTn4s84A.js → button-Ct9f2_oT.js} +1 -1
- package/static/app/assets/circle-check-DruOxB-4.js +1 -0
- package/static/app/assets/{circle-pause-xKgeGXkT.js → circle-pause-CmzC_apg.js} +1 -1
- package/static/app/assets/{circle-play-DkT6tYPX.js → circle-play-D8mW2aQ7.js} +1 -1
- package/static/app/assets/{cpu-85xYObUC.js → cpu-DZcdd0PZ.js} +1 -1
- package/static/app/assets/{download-B5Fm7YXo.js → download-bv1KEPGQ.js} +1 -1
- package/static/app/assets/{folder-open-kk2Xa52u.js → folder-open-d-Pip5gr.js} +1 -1
- package/static/app/assets/{hard-drive-DkA3zBW_.js → hard-drive-D20iavUb.js} +1 -1
- package/static/app/assets/index-D9x-kSNy.css +2 -0
- package/static/app/assets/{index-BMPdTmlY.js → index-Do83hDzJ.js} +3 -3
- package/static/app/assets/{input-B0nRf2jO.js → input-BLXVNmj1.js} +1 -1
- package/static/app/assets/{link-2-Dwb4gnTc.js → link-2-BPJOFlAy.js} +1 -1
- package/static/app/assets/{permissionCopy-CQDUBrOZ.js → permissionCopy-ChdJd493.js} +1 -1
- package/static/app/assets/primitives-Cv5tbZBY.js +1 -0
- package/static/app/assets/search-CT9aho2j.js +1 -0
- package/static/app/assets/{share-2-BsrxFglO.js → share-2-YNX_NtMU.js} +1 -1
- package/static/app/assets/{shield-alert-5BStfp2_.js → shield-alert-DuQ3zrVL.js} +1 -1
- package/static/app/assets/{textarea-Cg8IUA-k.js → textarea-DqwLnli4.js} +1 -1
- package/static/app/assets/{useFocusTrap-CYKvE46M.js → useFocusTrap-ZVI98jaW.js} +1 -1
- package/static/app/assets/{useMutation-CSn9t1op.js → useMutation-CVC4qv_D.js} +1 -1
- package/static/app/assets/{useQuery-CY2OI2uy.js → useQuery-C7BeG4HU.js} +1 -1
- package/static/app/assets/{utils-Ddol2RWD.js → utils-CiFtIdZq.js} +1 -1
- package/static/app/assets/{workspace-BqDwOz_p.js → workspace-DQz9vIId.js} +1 -1
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/lattice_brain/archive.py +0 -522
- package/lattice_brain/context.py +0 -325
- package/lattice_brain/conversations.py +0 -382
- package/lattice_brain/core.py +0 -82
- package/lattice_brain/graph/_kg_contract.py +0 -249
- package/lattice_brain/graph/curator.py +0 -676
- package/lattice_brain/graph/discovery.py +0 -595
- package/lattice_brain/graph/discovery_index/__init__.py +0 -35
- package/lattice_brain/graph/discovery_index/cleanup.py +0 -182
- package/lattice_brain/graph/discovery_index/extract.py +0 -137
- package/lattice_brain/graph/discovery_index/scan.py +0 -411
- package/lattice_brain/graph/discovery_index/upsert.py +0 -495
- package/lattice_brain/graph/documents.py +0 -380
- package/lattice_brain/graph/fusion.py +0 -395
- package/lattice_brain/graph/identity.py +0 -175
- package/lattice_brain/graph/image_vectors.py +0 -230
- package/lattice_brain/graph/ingest.py +0 -829
- package/lattice_brain/graph/network.py +0 -205
- package/lattice_brain/graph/proactive.py +0 -724
- package/lattice_brain/graph/projection/__init__.py +0 -42
- package/lattice_brain/graph/projection/curation.py +0 -500
- package/lattice_brain/graph/projection/v2_schema.py +0 -518
- package/lattice_brain/graph/provenance.py +0 -524
- package/lattice_brain/graph/rerank.py +0 -163
- package/lattice_brain/graph/retrieval/__init__.py +0 -54
- package/lattice_brain/graph/retrieval/context.py +0 -197
- package/lattice_brain/graph/retrieval/graph_view.py +0 -319
- package/lattice_brain/graph/retrieval/hybrid.py +0 -488
- package/lattice_brain/graph/retrieval/maintenance.py +0 -121
- package/lattice_brain/graph/retrieval/signals.py +0 -95
- package/lattice_brain/graph/retrieval_docgen.py +0 -253
- package/lattice_brain/graph/retrieval_policy.py +0 -180
- package/lattice_brain/graph/retrieval_reads.py +0 -769
- package/lattice_brain/graph/retrieval_vector/__init__.py +0 -42
- package/lattice_brain/graph/retrieval_vector/fingerprint.py +0 -97
- package/lattice_brain/graph/retrieval_vector/indexing.py +0 -347
- package/lattice_brain/graph/retrieval_vector/search.py +0 -560
- package/lattice_brain/graph/retrieval_vector/status.py +0 -374
- package/lattice_brain/graph/schema.py +0 -792
- package/lattice_brain/graph/store.py +0 -268
- package/lattice_brain/graph/vector_index/__init__.py +0 -85
- package/lattice_brain/graph/vector_index/base.py +0 -167
- package/lattice_brain/graph/vector_index/brute_force.py +0 -110
- package/lattice_brain/graph/vector_index/hnsw.py +0 -290
- package/lattice_brain/graph/vector_index/jobs.py +0 -287
- package/lattice_brain/graph/vector_index/quantized.py +0 -148
- package/lattice_brain/graph/vector_index/selector.py +0 -161
- package/lattice_brain/graph/write_master.py +0 -308
- package/lattice_brain/ingestion/_contract.py +0 -90
- package/lattice_brain/ingestion/folder_scan.py +0 -57
- package/lattice_brain/ingestion/folders.py +0 -258
- package/lattice_brain/ingestion/jobs_api.py +0 -107
- package/lattice_brain/ingestion/routing.py +0 -295
- package/lattice_brain/ingestion_jobs.py +0 -380
- package/lattice_brain/memory.py +0 -75
- package/lattice_brain/portability/__init__.py +0 -90
- package/lattice_brain/portability/_contract.py +0 -42
- package/lattice_brain/portability/backups.py +0 -338
- package/lattice_brain/portability/bundles.py +0 -136
- package/lattice_brain/portability/constants.py +0 -93
- package/lattice_brain/portability/fsops.py +0 -138
- package/lattice_brain/portability/service.py +0 -41
- package/lattice_brain/portability/sharing.py +0 -710
- package/lattice_brain/quality.py +0 -543
- package/lattice_brain/retrieval_benchmark_fixtures.py +0 -92
- package/lattice_brain/runtime/agent_runtime.py +0 -859
- package/lattice_brain/runtime/contracts.py +0 -460
- package/lattice_brain/runtime/multi_agent.py +0 -942
- package/lattice_brain/runtime/statuses.py +0 -10
- package/lattice_brain/sealed_box.py +0 -240
- package/lattice_brain/self_model.py +0 -675
- package/lattice_brain/sensitivity.py +0 -94
- package/lattice_brain/storage/__init__.py +0 -22
- package/lattice_brain/storage/base.py +0 -100
- package/lattice_brain/storage/docker.py +0 -105
- package/lattice_brain/storage/factory.py +0 -31
- package/lattice_brain/storage/migration.py +0 -191
- package/lattice_brain/storage/postgres.py +0 -123
- package/lattice_brain/storage/sqlite.py +0 -143
- package/lattice_brain/synthesis.py +0 -824
- package/lattice_brain/workflow.py +0 -497
- package/latticeai/api/admin.py +0 -471
- package/latticeai/api/agent_registry.py +0 -105
- package/latticeai/api/agents.py +0 -228
- package/latticeai/api/auth.py +0 -383
- package/latticeai/api/automation_intelligence.py +0 -401
- package/latticeai/api/brain_intelligence.py +0 -199
- package/latticeai/api/browser.py +0 -493
- package/latticeai/api/change_proposals.py +0 -89
- package/latticeai/api/chat.py +0 -572
- package/latticeai/api/chat_agent_http.py +0 -892
- package/latticeai/api/chat_contracts.py +0 -73
- package/latticeai/api/chat_documents.py +0 -276
- package/latticeai/api/chat_helpers.py +0 -460
- package/latticeai/api/chat_history.py +0 -101
- package/latticeai/api/chat_hybrid.py +0 -113
- package/latticeai/api/chat_intents.py +0 -646
- package/latticeai/api/chat_stream.py +0 -216
- package/latticeai/api/chronicle.py +0 -63
- package/latticeai/api/command_center.py +0 -51
- package/latticeai/api/computer_use.py +0 -474
- package/latticeai/api/evidence_actions.py +0 -48
- package/latticeai/api/features.py +0 -70
- package/latticeai/api/funnel_metrics.py +0 -31
- package/latticeai/api/garden.py +0 -34
- package/latticeai/api/hooks.py +0 -165
- package/latticeai/api/index_jobs.py +0 -145
- package/latticeai/api/invitations.py +0 -100
- package/latticeai/api/knowledge_graph.py +0 -536
- package/latticeai/api/marketplace.py +0 -105
- package/latticeai/api/mcp.py +0 -482
- package/latticeai/api/memory.py +0 -270
- package/latticeai/api/network.py +0 -81
- package/latticeai/api/network_boundary.py +0 -225
- package/latticeai/api/permission_mode.py +0 -61
- package/latticeai/api/permissions.py +0 -436
- package/latticeai/api/plugins.py +0 -126
- package/latticeai/api/portability.py +0 -391
- package/latticeai/api/project_sessions.py +0 -114
- package/latticeai/api/realtime.py +0 -118
- package/latticeai/api/review_queue.py +0 -364
- package/latticeai/api/security_dashboard.py +0 -604
- package/latticeai/api/setup.py +0 -319
- package/latticeai/api/static_routes.py +0 -354
- package/latticeai/api/ui_redirects.py +0 -26
- package/latticeai/api/workflow_designer.py +0 -394
- package/latticeai/api/workspace.py +0 -856
- package/latticeai/api/workspace_scope.py +0 -125
- package/latticeai/core/agent/__init__.py +0 -93
- package/latticeai/core/agent/_contract.py +0 -79
- package/latticeai/core/agent/context.py +0 -57
- package/latticeai/core/agent/deps.py +0 -125
- package/latticeai/core/agent/execution.py +0 -622
- package/latticeai/core/agent/planning.py +0 -145
- package/latticeai/core/agent/recovery.py +0 -157
- package/latticeai/core/agent/runtime.py +0 -210
- package/latticeai/core/agent/verification.py +0 -231
- package/latticeai/core/agent_eval.py +0 -739
- package/latticeai/core/agent_helpers.py +0 -493
- package/latticeai/core/agent_profiles.py +0 -110
- package/latticeai/core/agent_prompts.py +0 -171
- package/latticeai/core/agent_registry.py +0 -232
- package/latticeai/core/agent_state.py +0 -41
- package/latticeai/core/agent_trace.py +0 -104
- package/latticeai/core/artifact_ledger.py +0 -109
- package/latticeai/core/audit.py +0 -260
- package/latticeai/core/builtin_hooks.py +0 -105
- package/latticeai/core/context_builder.py +0 -394
- package/latticeai/core/document_generator.py +0 -103
- package/latticeai/core/enterprise.py +0 -154
- package/latticeai/core/enterprise_admin.py +0 -158
- package/latticeai/core/file_generation/__init__.py +0 -115
- package/latticeai/core/file_generation/bundles.py +0 -76
- package/latticeai/core/file_generation/extraction.py +0 -154
- package/latticeai/core/file_generation/inference.py +0 -235
- package/latticeai/core/file_generation/orchestration.py +0 -152
- package/latticeai/core/file_generation/prompting.py +0 -117
- package/latticeai/core/file_generation/repair.py +0 -114
- package/latticeai/core/file_generation/sanitize.py +0 -61
- package/latticeai/core/file_generation/validation.py +0 -201
- package/latticeai/core/invitations.py +0 -132
- package/latticeai/core/legacy_compatibility.py +0 -243
- package/latticeai/core/logging_safety.py +0 -46
- package/latticeai/core/marketplace.py +0 -293
- package/latticeai/core/mcp_catalog.py +0 -452
- package/latticeai/core/mcp_registry.py +0 -506
- package/latticeai/core/network_boundary.py +0 -168
- package/latticeai/core/oidc.py +0 -208
- package/latticeai/core/plugins.py +0 -432
- package/latticeai/core/product_hardening.py +0 -218
- package/latticeai/core/project_sessions.py +0 -337
- package/latticeai/core/realtime.py +0 -238
- package/latticeai/core/run_explain.py +0 -426
- package/latticeai/core/run_store.py +0 -252
- package/latticeai/core/timezones.py +0 -80
- package/latticeai/core/workspace_computer_memory.py +0 -84
- package/latticeai/core/workspace_graph_trace.py +0 -155
- package/latticeai/core/workspace_indexing.py +0 -102
- package/latticeai/core/workspace_memory.py +0 -77
- package/latticeai/core/workspace_onboarding.py +0 -104
- package/latticeai/core/workspace_os.py +0 -978
- package/latticeai/core/workspace_os_constants.py +0 -126
- package/latticeai/core/workspace_os_state.py +0 -180
- package/latticeai/core/workspace_os_utils.py +0 -103
- package/latticeai/core/workspace_permissions.py +0 -101
- package/latticeai/core/workspace_plugins.py +0 -97
- package/latticeai/core/workspace_relationships.py +0 -99
- package/latticeai/core/workspace_reorganization.py +0 -335
- package/latticeai/core/workspace_review_items.py +0 -112
- package/latticeai/core/workspace_runs.py +0 -726
- package/latticeai/core/workspace_skills.py +0 -109
- package/latticeai/core/workspace_snapshots.py +0 -198
- package/latticeai/core/workspace_timeline.py +0 -110
- package/latticeai/integrations/__init__.py +0 -0
- package/latticeai/integrations/telegram_bot/__init__.py +0 -123
- package/latticeai/integrations/telegram_bot/__main__.py +0 -17
- package/latticeai/integrations/telegram_bot/config.py +0 -86
- package/latticeai/integrations/telegram_bot/dispatch.py +0 -311
- package/latticeai/integrations/telegram_bot/flows.py +0 -478
- package/latticeai/integrations/telegram_bot/helpers.py +0 -322
- package/latticeai/integrations/telegram_bot/screens.py +0 -394
- package/latticeai/runtime/audit_runtime.py +0 -76
- package/latticeai/runtime/automation_runtime.py +0 -81
- package/latticeai/runtime/chat_wiring.py +0 -141
- package/latticeai/runtime/context_runtime.py +0 -66
- package/latticeai/runtime/feature_toggle_wiring.py +0 -157
- package/latticeai/runtime/history_runtime.py +0 -163
- package/latticeai/runtime/history_writer.py +0 -138
- package/latticeai/runtime/hooks_runtime.py +0 -77
- package/latticeai/runtime/model_wiring.py +0 -68
- package/latticeai/runtime/namespace_runtime.py +0 -163
- package/latticeai/runtime/network_boundary_wiring.py +0 -117
- package/latticeai/runtime/network_config_runtime.py +0 -56
- package/latticeai/runtime/permission_mode_wiring.py +0 -112
- package/latticeai/runtime/persistence_runtime.py +0 -159
- package/latticeai/runtime/platform_runtime_wiring.py +0 -89
- package/latticeai/runtime/review_wiring.py +0 -42
- package/latticeai/runtime/router_registration.py +0 -693
- package/latticeai/runtime/service_singletons.py +0 -55
- package/latticeai/runtime/sso_config_runtime.py +0 -128
- package/latticeai/runtime/user_key_runtime.py +0 -106
- package/latticeai/runtime/web_runtime.py +0 -92
- package/latticeai/server_app.py +0 -51
- package/latticeai/services/app_context.py +0 -130
- package/latticeai/services/automation_execution.py +0 -266
- package/latticeai/services/automation_intelligence.py +0 -614
- package/latticeai/services/brain_automation.py +0 -191
- package/latticeai/services/brain_intelligence/__init__.py +0 -58
- package/latticeai/services/brain_intelligence/_contract.py +0 -71
- package/latticeai/services/brain_intelligence/consistency.py +0 -193
- package/latticeai/services/brain_intelligence/constants.py +0 -47
- package/latticeai/services/brain_intelligence/digest.py +0 -258
- package/latticeai/services/brain_intelligence/health.py +0 -331
- package/latticeai/services/brain_intelligence/proposals.py +0 -259
- package/latticeai/services/brain_intelligence/sampling.py +0 -84
- package/latticeai/services/brain_intelligence/service.py +0 -48
- package/latticeai/services/change_proposals.py +0 -471
- package/latticeai/services/chat_service.py +0 -243
- package/latticeai/services/chronicle.py +0 -555
- package/latticeai/services/cloud_egress_audit.py +0 -85
- package/latticeai/services/cloud_extraction.py +0 -129
- package/latticeai/services/cloud_streaming.py +0 -268
- package/latticeai/services/cloud_token_guard.py +0 -84
- package/latticeai/services/command_center.py +0 -548
- package/latticeai/services/evidence_actions.py +0 -258
- package/latticeai/services/feature_toggles.py +0 -502
- package/latticeai/services/folder_watch.py +0 -520
- package/latticeai/services/funnel_metrics.py +0 -307
- package/latticeai/services/hybrid_chat.py +0 -316
- package/latticeai/services/hybrid_context.py +0 -228
- package/latticeai/services/hybrid_policy.py +0 -129
- package/latticeai/services/interop_bridges.py +0 -978
- package/latticeai/services/local_knowledge.py +0 -465
- package/latticeai/services/memory_service/__init__.py +0 -52
- package/latticeai/services/memory_service/_contract.py +0 -100
- package/latticeai/services/memory_service/brief.py +0 -431
- package/latticeai/services/memory_service/constants.py +0 -57
- package/latticeai/services/memory_service/maintenance.py +0 -138
- package/latticeai/services/memory_service/manager.py +0 -186
- package/latticeai/services/memory_service/proof.py +0 -136
- package/latticeai/services/memory_service/recall.py +0 -225
- package/latticeai/services/memory_service/service.py +0 -48
- package/latticeai/services/memory_service/stores.py +0 -110
- package/latticeai/services/mode_store.py +0 -132
- package/latticeai/services/model_recommendation.py +0 -224
- package/latticeai/services/model_runtime/cloud.py +0 -87
- package/latticeai/services/network_boundary_service.py +0 -117
- package/latticeai/services/obsidian_bridge.py +0 -609
- package/latticeai/services/openai_compatible_adapter.py +0 -101
- package/latticeai/services/permission_mode_service.py +0 -122
- package/latticeai/services/platform_runtime.py +0 -366
- package/latticeai/services/review_queue.py +0 -380
- package/latticeai/services/router_context.py +0 -59
- package/latticeai/services/run_executor.py +0 -387
- package/latticeai/services/self_model_service.py +0 -171
- package/latticeai/services/setup_detection.py +0 -147
- package/latticeai/services/triggers.py +0 -378
- package/latticeai/services/upload_service.py +0 -172
- package/latticeai/services/workspace_service.py +0 -165
- package/latticeai/setup/__init__.py +0 -25
- package/latticeai/setup/auto_setup.py +0 -846
- package/latticeai/setup/demo_corpus.py +0 -98
- package/latticeai/setup/wizard/__init__.py +0 -126
- package/latticeai/setup/wizard/catalog.py +0 -175
- package/latticeai/setup/wizard/detect.py +0 -302
- package/latticeai/setup/wizard/install.py +0 -348
- package/latticeai/setup/wizard/paths.py +0 -165
- package/latticeai/setup/wizard/plans.py +0 -74
- package/latticeai/setup/wizard/recommend.py +0 -320
- package/scripts/bench_agent_smoke.py +0 -409
- package/scripts/bench_models.py +0 -540
- package/scripts/bench_vector_index.py +0 -295
- package/scripts/funnel_soft_gate.py +0 -192
- package/scripts/generate_agent_loop_fixtures.py +0 -994
- package/scripts/generate_rust_parity_fixtures.py +0 -908
- package/scripts/migrate_brain_storage.py +0 -57
- package/scripts/parity_fixture_corpus_context.py +0 -162
- package/scripts/parity_fixture_corpus_docgen.py +0 -341
- package/scripts/profile_kg.py +0 -355
- package/server.py +0 -30
- package/static/app/assets/AdminConsole-cf4npybT.js +0 -1
- package/static/app/assets/Capture-DiQ219jW.js +0 -1
- package/static/app/assets/System-CieofHQa.js +0 -1
- package/static/app/assets/arrow-left-kfsrk0mv.js +0 -1
- package/static/app/assets/circle-check-qqLug9nU.js +0 -1
- package/static/app/assets/index-DxmOfNRi.css +0 -2
- package/static/app/assets/primitives-SNp0LRJz.js +0 -1
- package/static/app/assets/search-BcHqkjoy.js +0 -1
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"""The derived vector index: build it, report on it, search it.
|
|
2
|
-
|
|
3
|
-
v11.3.0 turned this module into a package. ``KnowledgeGraphVectorMixin`` is
|
|
4
|
-
now composed from four cohesive sub-mixins — embedder fingerprint, index
|
|
5
|
-
build, index status, and search — each moved here verbatim. Every name this
|
|
6
|
-
module exported before still resolves from
|
|
7
|
-
``lattice_brain.graph.retrieval_vector``.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from __future__ import annotations
|
|
11
|
-
|
|
12
|
-
# ruff: noqa: F403,F405
|
|
13
|
-
from .._kg_common import * # noqa: F403,F401
|
|
14
|
-
from .fingerprint import _VectorFingerprintMixin
|
|
15
|
-
from .indexing import _VectorIndexingMixin
|
|
16
|
-
from .search import ( # noqa: F401
|
|
17
|
-
DEFAULT_VECTOR_MAX_CANDIDATES,
|
|
18
|
-
VECTOR_MAX_CANDIDATES_CEILING,
|
|
19
|
-
VECTOR_MAX_CANDIDATES_ENV,
|
|
20
|
-
VECTOR_SCAN_BATCH,
|
|
21
|
-
_configured_vector_max_candidates,
|
|
22
|
-
_VectorSearchMixin,
|
|
23
|
-
)
|
|
24
|
-
from .status import _VectorStatusMixin
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# Base order is most-composed-first (status → indexing → fingerprint, then
|
|
28
|
-
# search): each half names the ones it calls as its typing-only base, and C3
|
|
29
|
-
# needs a subclass ahead of the class it extends. The method sets are disjoint,
|
|
30
|
-
# so at runtime the order changes nothing.
|
|
31
|
-
class KnowledgeGraphVectorMixin(
|
|
32
|
-
_VectorStatusMixin,
|
|
33
|
-
_VectorIndexingMixin,
|
|
34
|
-
_VectorFingerprintMixin,
|
|
35
|
-
_VectorSearchMixin,
|
|
36
|
-
):
|
|
37
|
-
"""Vector-embedding index build/status/search, split out of retrieval.
|
|
38
|
-
|
|
39
|
-
Composed into KnowledgeGraphStore alongside KnowledgeGraphRetrievalMixin;
|
|
40
|
-
both mixins share the same instance, so vector methods still reach sibling
|
|
41
|
-
retrieval/write helpers (e.g. self._vector_text_for_node) through the MRO.
|
|
42
|
-
"""
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
"""Which embedder actually built the index, recorded in ``graph_meta``.
|
|
2
|
-
|
|
3
|
-
``vector_search`` filters on the current model/dim, so swapping the embedder
|
|
4
|
-
silently yields zero vector rows; the fingerprint turns that into the honest
|
|
5
|
-
``stale_embedder`` signal. Moved verbatim out of ``retrieval_vector.py``.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
from typing import TYPE_CHECKING
|
|
11
|
-
|
|
12
|
-
# ruff: noqa: F403,F405
|
|
13
|
-
from .._kg_common import * # noqa: F403,F401
|
|
14
|
-
|
|
15
|
-
# The cross-mixin surface (`_connect`, `_upsert_node`, …) is declared in
|
|
16
|
-
# `_kg_contract.KnowledgeGraphCore`. It is a typing-only base: at runtime this
|
|
17
|
-
# is `object`, so the MRO of `KnowledgeGraphStore` is unchanged.
|
|
18
|
-
if TYPE_CHECKING:
|
|
19
|
-
from .._kg_contract import KnowledgeGraphCore as _Core
|
|
20
|
-
else:
|
|
21
|
-
_Core = object
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class _VectorFingerprintMixin(_Core):
|
|
25
|
-
"""Embedder-fingerprint read/write. Composed into the public mixin."""
|
|
26
|
-
|
|
27
|
-
# ── embedder fingerprint (review Wave 2.2 — stale_embedder) ──────────────
|
|
28
|
-
# vector_search filters on the CURRENT model/dim, so swapping the embedder
|
|
29
|
-
# silently yields zero vector rows. The fingerprint persisted in graph_meta
|
|
30
|
-
# records which embedder actually built the index; a mismatch is surfaced
|
|
31
|
-
# as the honest ``stale_embedder`` signal instead of a silent degradation.
|
|
32
|
-
|
|
33
|
-
_EMBEDDER_FINGERPRINT_KEY = "embedder_fingerprint"
|
|
34
|
-
|
|
35
|
-
def _embedder_fingerprint_record(
|
|
36
|
-
self, conn: sqlite3.Connection
|
|
37
|
-
) -> Optional[Dict[str, Any]]:
|
|
38
|
-
"""Read the recorded embedder fingerprint from graph_meta (or None)."""
|
|
39
|
-
row = conn.execute(
|
|
40
|
-
"SELECT value FROM graph_meta WHERE key=?",
|
|
41
|
-
(self._EMBEDDER_FINGERPRINT_KEY,),
|
|
42
|
-
).fetchone()
|
|
43
|
-
if not row:
|
|
44
|
-
return None
|
|
45
|
-
payload = _safe_loads(row["value"])
|
|
46
|
-
if not isinstance(payload, dict) or not payload.get("model_id"):
|
|
47
|
-
return None
|
|
48
|
-
try:
|
|
49
|
-
dim = int(payload.get("dim") or 0)
|
|
50
|
-
except (TypeError, ValueError):
|
|
51
|
-
dim = 0
|
|
52
|
-
return {"model_id": str(payload["model_id"]), "dim": dim}
|
|
53
|
-
|
|
54
|
-
def _write_embedder_fingerprint(self, conn: sqlite3.Connection) -> Dict[str, Any]:
|
|
55
|
-
"""Persist the CURRENT embedder identity (same transaction as caller)."""
|
|
56
|
-
fingerprint = {
|
|
57
|
-
"model_id": self._embedding_model.model_id,
|
|
58
|
-
"dim": int(self._embedding_model.dim),
|
|
59
|
-
}
|
|
60
|
-
conn.execute(
|
|
61
|
-
"INSERT OR REPLACE INTO graph_meta(key, value) VALUES (?, ?)",
|
|
62
|
-
(self._EMBEDDER_FINGERPRINT_KEY, _json(fingerprint)),
|
|
63
|
-
)
|
|
64
|
-
return fingerprint
|
|
65
|
-
|
|
66
|
-
def record_embedder_fingerprint(self) -> Dict[str, Any]:
|
|
67
|
-
"""Record the current embedder (model_id + dim) as the index builder."""
|
|
68
|
-
with self._connect() as conn:
|
|
69
|
-
return self._write_embedder_fingerprint(conn)
|
|
70
|
-
|
|
71
|
-
def embedder_fingerprint_status(self) -> Dict[str, Any]:
|
|
72
|
-
"""Compare the current embedder against the recorded index fingerprint.
|
|
73
|
-
|
|
74
|
-
Returns ``{"current": {model_id, dim}, "recorded": {...} | None,
|
|
75
|
-
"stale_embedder": bool}``. ``stale_embedder`` is True only when a
|
|
76
|
-
fingerprint was recorded AND it differs from the current embedder —
|
|
77
|
-
an unrecorded index (legacy DBs, nothing indexed yet) is honestly
|
|
78
|
-
"unknown", never reported stale. Never raises.
|
|
79
|
-
"""
|
|
80
|
-
current = {
|
|
81
|
-
"model_id": self._embedding_model.model_id,
|
|
82
|
-
"dim": int(self._embedding_model.dim),
|
|
83
|
-
}
|
|
84
|
-
recorded: Optional[Dict[str, Any]] = None
|
|
85
|
-
try:
|
|
86
|
-
with self._connect() as conn:
|
|
87
|
-
recorded = self._embedder_fingerprint_record(conn)
|
|
88
|
-
except Exception: # noqa: BLE001 — status must degrade, never raise
|
|
89
|
-
recorded = None
|
|
90
|
-
stale = bool(
|
|
91
|
-
recorded is not None
|
|
92
|
-
and (
|
|
93
|
-
recorded.get("model_id") != current["model_id"]
|
|
94
|
-
or recorded.get("dim") != current["dim"]
|
|
95
|
-
)
|
|
96
|
-
)
|
|
97
|
-
return {"current": current, "recorded": recorded, "stale_embedder": stale}
|
|
@@ -1,347 +0,0 @@
|
|
|
1
|
-
"""Building the vector index: incremental upserts and full rebuilds.
|
|
2
|
-
|
|
3
|
-
Moved verbatim out of ``retrieval_vector.py`` (v11.3.0 decomposition).
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
|
|
8
|
-
from typing import TYPE_CHECKING
|
|
9
|
-
|
|
10
|
-
# ruff: noqa: F403,F405
|
|
11
|
-
from .._kg_common import * # noqa: F403,F401
|
|
12
|
-
|
|
13
|
-
# Typing-only base (runtime value is `object`, so the store's MRO is
|
|
14
|
-
# unchanged). Every build path records which embedder produced the rows, so
|
|
15
|
-
# this half calls the fingerprint half through `self`; naming it as the base
|
|
16
|
-
# states that assumption and carries the store contract
|
|
17
|
-
# (`_connect`, `_upsert_node`, …) along with it.
|
|
18
|
-
if TYPE_CHECKING:
|
|
19
|
-
from .fingerprint import _VectorFingerprintMixin as _Core
|
|
20
|
-
else:
|
|
21
|
-
_Core = object
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class _VectorIndexingMixin(_Core):
|
|
25
|
-
"""Vector index build/refresh. Composed into the public mixin."""
|
|
26
|
-
|
|
27
|
-
def _vector_text_hashes(self, conn: sqlite3.Connection) -> Dict[str, str]:
|
|
28
|
-
"""``item_id -> text_hash`` for rows already embedded by *this* embedder.
|
|
29
|
-
|
|
30
|
-
The incremental rebuild's job is mostly deciding what it does *not*
|
|
31
|
-
have to do, and it used to ask that question with one ``SELECT`` per
|
|
32
|
-
candidate item — a round trip per node and per chunk on every run,
|
|
33
|
-
almost all of which answer "unchanged". One query returning two short
|
|
34
|
-
columns replaces all of them.
|
|
35
|
-
|
|
36
|
-
Rows written by a different embedder are left out, so they compare as
|
|
37
|
-
missing and get re-embedded, which is what an embedder swap requires.
|
|
38
|
-
"""
|
|
39
|
-
return {
|
|
40
|
-
row["item_id"]: row["text_hash"]
|
|
41
|
-
for row in conn.execute(
|
|
42
|
-
"""
|
|
43
|
-
SELECT item_id, text_hash
|
|
44
|
-
FROM vector_embeddings
|
|
45
|
-
WHERE embedding_model=? AND embedding_dim=?
|
|
46
|
-
""",
|
|
47
|
-
(self._embedding_model.model_id, self._embedding_model.dim),
|
|
48
|
-
).fetchall()
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
def _iter_vector_source_items(
|
|
52
|
-
self,
|
|
53
|
-
conn: sqlite3.Connection,
|
|
54
|
-
*,
|
|
55
|
-
include_nodes: bool = True,
|
|
56
|
-
include_chunks: bool = True,
|
|
57
|
-
) -> Iterator[Dict[str, Any]]:
|
|
58
|
-
"""Stream the graph's embeddable text, one item at a time.
|
|
59
|
-
|
|
60
|
-
Yields rather than returns a list. Every caller consumes this exactly
|
|
61
|
-
once in a ``for``, and building the list first meant a rebuild held
|
|
62
|
-
the full text of every node and chunk in memory simultaneously — the
|
|
63
|
-
one shape guaranteed to fail on precisely the large graph that most
|
|
64
|
-
needs the index.
|
|
65
|
-
"""
|
|
66
|
-
if include_nodes:
|
|
67
|
-
for row in conn.execute(
|
|
68
|
-
"""
|
|
69
|
-
SELECT id, type, title, summary, metadata_json
|
|
70
|
-
FROM nodes
|
|
71
|
-
WHERE type <> 'Chunk'
|
|
72
|
-
ORDER BY updated_at DESC, id ASC
|
|
73
|
-
"""
|
|
74
|
-
).fetchall():
|
|
75
|
-
metadata = _safe_loads(row["metadata_json"])
|
|
76
|
-
text = self._vector_text_for_node(
|
|
77
|
-
title=row["title"],
|
|
78
|
-
summary=row["summary"] or "",
|
|
79
|
-
metadata=metadata,
|
|
80
|
-
)
|
|
81
|
-
if text:
|
|
82
|
-
yield {
|
|
83
|
-
"item_id": row["id"],
|
|
84
|
-
"item_type": "node",
|
|
85
|
-
"source_node": row["id"],
|
|
86
|
-
"text": text,
|
|
87
|
-
"metadata": {"node_type": row["type"], **metadata},
|
|
88
|
-
}
|
|
89
|
-
if include_chunks:
|
|
90
|
-
for row in conn.execute(
|
|
91
|
-
"""
|
|
92
|
-
SELECT c.id, c.source_node AS parent_source_node, c.text, c.metadata_json
|
|
93
|
-
FROM chunks c
|
|
94
|
-
JOIN nodes n ON n.id=c.id
|
|
95
|
-
ORDER BY c.created_at DESC, c.id ASC
|
|
96
|
-
"""
|
|
97
|
-
).fetchall():
|
|
98
|
-
metadata = _safe_loads(row["metadata_json"])
|
|
99
|
-
text = _clean_text(row["text"] or "")
|
|
100
|
-
if text:
|
|
101
|
-
yield {
|
|
102
|
-
"item_id": row["id"],
|
|
103
|
-
"item_type": "chunk",
|
|
104
|
-
"source_node": row["id"],
|
|
105
|
-
"text": text,
|
|
106
|
-
"metadata": {
|
|
107
|
-
**metadata,
|
|
108
|
-
"parent_source_node": row["parent_source_node"],
|
|
109
|
-
},
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
def index_node_incremental(self, node_id: str) -> Dict[str, Any]:
|
|
113
|
-
"""Embed/index only ``node_id`` and its chunks (incremental sync).
|
|
114
|
-
|
|
115
|
-
The item construction mirrors :meth:`_iter_vector_source_items` exactly
|
|
116
|
-
(same ids, same ``source_node``/``parent_source_node`` semantics), so
|
|
117
|
-
anything this method indexes is indistinguishable from a full
|
|
118
|
-
:meth:`rebuild_vector_index` pass — and anything it *fails* to index
|
|
119
|
-
stays visible as ``missing``/``stale`` backlog in :meth:`index_status`,
|
|
120
|
-
where a later rebuild picks it up.
|
|
121
|
-
|
|
122
|
-
Never raises: embedding-provider or storage failures are reported as
|
|
123
|
-
``{"status": "failed", ...}`` so ingestion callers can degrade instead
|
|
124
|
-
of losing an already-persisted write.
|
|
125
|
-
"""
|
|
126
|
-
node_id = str(node_id or "").strip()
|
|
127
|
-
started = time.perf_counter()
|
|
128
|
-
summary: Dict[str, Any] = {
|
|
129
|
-
"node_id": node_id,
|
|
130
|
-
"items_total": 0,
|
|
131
|
-
"items_indexed": 0,
|
|
132
|
-
"items_skipped": 0,
|
|
133
|
-
}
|
|
134
|
-
if not node_id:
|
|
135
|
-
return {**summary, "status": "skipped", "detail": "node_id required"}
|
|
136
|
-
try:
|
|
137
|
-
with self._connect() as conn:
|
|
138
|
-
row = conn.execute(
|
|
139
|
-
"SELECT id, type, title, summary, metadata_json FROM nodes WHERE id=?",
|
|
140
|
-
(node_id,),
|
|
141
|
-
).fetchone()
|
|
142
|
-
if row is None:
|
|
143
|
-
return {**summary, "status": "skipped", "detail": "node not found"}
|
|
144
|
-
items: List[Dict[str, Any]] = []
|
|
145
|
-
if row["type"] != "Chunk":
|
|
146
|
-
metadata = _safe_loads(row["metadata_json"])
|
|
147
|
-
text = self._vector_text_for_node(
|
|
148
|
-
title=row["title"],
|
|
149
|
-
summary=row["summary"] or "",
|
|
150
|
-
metadata=metadata,
|
|
151
|
-
)
|
|
152
|
-
if text:
|
|
153
|
-
items.append(
|
|
154
|
-
{
|
|
155
|
-
"item_id": row["id"],
|
|
156
|
-
"item_type": "node",
|
|
157
|
-
"source_node": row["id"],
|
|
158
|
-
"text": text,
|
|
159
|
-
"metadata": {"node_type": row["type"], **metadata},
|
|
160
|
-
}
|
|
161
|
-
)
|
|
162
|
-
for chunk_row in conn.execute(
|
|
163
|
-
"""
|
|
164
|
-
SELECT c.id, c.source_node AS parent_source_node, c.text, c.metadata_json
|
|
165
|
-
FROM chunks c
|
|
166
|
-
JOIN nodes n ON n.id=c.id
|
|
167
|
-
WHERE c.source_node=?
|
|
168
|
-
ORDER BY c.created_at ASC, c.id ASC
|
|
169
|
-
""",
|
|
170
|
-
(node_id,),
|
|
171
|
-
).fetchall():
|
|
172
|
-
metadata = _safe_loads(chunk_row["metadata_json"])
|
|
173
|
-
text = _clean_text(chunk_row["text"] or "")
|
|
174
|
-
if text:
|
|
175
|
-
items.append(
|
|
176
|
-
{
|
|
177
|
-
"item_id": chunk_row["id"],
|
|
178
|
-
"item_type": "chunk",
|
|
179
|
-
"source_node": chunk_row["id"],
|
|
180
|
-
"text": text,
|
|
181
|
-
"metadata": {
|
|
182
|
-
**metadata,
|
|
183
|
-
"parent_source_node": chunk_row["parent_source_node"],
|
|
184
|
-
},
|
|
185
|
-
}
|
|
186
|
-
)
|
|
187
|
-
indexed = skipped = 0
|
|
188
|
-
for item in items:
|
|
189
|
-
if self._upsert_vector_item(conn, **item):
|
|
190
|
-
indexed += 1
|
|
191
|
-
else:
|
|
192
|
-
skipped += 1
|
|
193
|
-
if indexed and self._embedder_fingerprint_record(conn) is None:
|
|
194
|
-
# First successful vector write establishes the fingerprint;
|
|
195
|
-
# later incremental writes never overwrite it (only a full
|
|
196
|
-
# rebuild may flip it after an embedder swap).
|
|
197
|
-
self._write_embedder_fingerprint(conn)
|
|
198
|
-
summary.update(
|
|
199
|
-
{
|
|
200
|
-
"items_total": len(items),
|
|
201
|
-
"items_indexed": indexed,
|
|
202
|
-
"items_skipped": skipped,
|
|
203
|
-
}
|
|
204
|
-
)
|
|
205
|
-
return {
|
|
206
|
-
**summary,
|
|
207
|
-
"status": "indexed" if indexed else "noop",
|
|
208
|
-
"duration_ms": round((time.perf_counter() - started) * 1000, 2),
|
|
209
|
-
"embedding_model": self._embedding_model.model_id,
|
|
210
|
-
}
|
|
211
|
-
except Exception as exc: # noqa: BLE001 — incremental sync must never raise
|
|
212
|
-
return {
|
|
213
|
-
**summary,
|
|
214
|
-
"status": "failed",
|
|
215
|
-
"detail": str(exc),
|
|
216
|
-
"duration_ms": round((time.perf_counter() - started) * 1000, 2),
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
def rebuild_vector_index(
|
|
220
|
-
self,
|
|
221
|
-
*,
|
|
222
|
-
full: bool = False,
|
|
223
|
-
include_nodes: bool = True,
|
|
224
|
-
include_chunks: bool = True,
|
|
225
|
-
) -> Dict[str, Any]:
|
|
226
|
-
"""Rebuild the derived vector index without mutating graph content."""
|
|
227
|
-
op_id = f"vector-op:{_sha256_text(f'{time.time()}:{os.getpid()}')[:24]}"
|
|
228
|
-
requested_at = _now()
|
|
229
|
-
started = time.perf_counter()
|
|
230
|
-
try:
|
|
231
|
-
with self._connect() as conn:
|
|
232
|
-
conn.execute(
|
|
233
|
-
"""
|
|
234
|
-
INSERT INTO vector_index_operations(
|
|
235
|
-
id, operation, status, requested_at, started_at, metadata_json
|
|
236
|
-
)
|
|
237
|
-
VALUES (?, ?, 'running', ?, ?, ?)
|
|
238
|
-
""",
|
|
239
|
-
(
|
|
240
|
-
op_id,
|
|
241
|
-
"rebuild_full" if full else "rebuild_incremental",
|
|
242
|
-
requested_at,
|
|
243
|
-
requested_at,
|
|
244
|
-
_json(
|
|
245
|
-
{
|
|
246
|
-
"include_nodes": include_nodes,
|
|
247
|
-
"include_chunks": include_chunks,
|
|
248
|
-
}
|
|
249
|
-
),
|
|
250
|
-
),
|
|
251
|
-
)
|
|
252
|
-
if full:
|
|
253
|
-
filters = []
|
|
254
|
-
if include_nodes:
|
|
255
|
-
filters.append("'node'")
|
|
256
|
-
if include_chunks:
|
|
257
|
-
filters.append("'chunk'")
|
|
258
|
-
if filters:
|
|
259
|
-
conn.execute(
|
|
260
|
-
f"DELETE FROM vector_embeddings WHERE item_type IN ({','.join(filters)})"
|
|
261
|
-
)
|
|
262
|
-
# After a full wipe nothing is current by definition, so the
|
|
263
|
-
# prefetch would only be a wasted scan of a table we just
|
|
264
|
-
# emptied. Incremental is where it pays: it turns "one SELECT
|
|
265
|
-
# per item, nearly all of which say unchanged" into one query.
|
|
266
|
-
known = {} if full else self._vector_text_hashes(conn)
|
|
267
|
-
total = indexed = skipped = 0
|
|
268
|
-
for item in self._iter_vector_source_items(
|
|
269
|
-
conn,
|
|
270
|
-
include_nodes=include_nodes,
|
|
271
|
-
include_chunks=include_chunks,
|
|
272
|
-
):
|
|
273
|
-
total += 1
|
|
274
|
-
if known.get(item["item_id"]) == _sha256_text(_clean_text(item["text"])):
|
|
275
|
-
skipped += 1
|
|
276
|
-
continue
|
|
277
|
-
if self._upsert_vector_item(conn, **item):
|
|
278
|
-
indexed += 1
|
|
279
|
-
else:
|
|
280
|
-
skipped += 1
|
|
281
|
-
duration_ms = round((time.perf_counter() - started) * 1000, 2)
|
|
282
|
-
conn.execute(
|
|
283
|
-
"""
|
|
284
|
-
UPDATE vector_index_operations
|
|
285
|
-
SET status='completed', completed_at=?, items_total=?,
|
|
286
|
-
items_indexed=?, items_skipped=?, metadata_json=?
|
|
287
|
-
WHERE id=?
|
|
288
|
-
""",
|
|
289
|
-
(
|
|
290
|
-
_now(),
|
|
291
|
-
total,
|
|
292
|
-
indexed,
|
|
293
|
-
skipped,
|
|
294
|
-
_json(
|
|
295
|
-
{
|
|
296
|
-
"include_nodes": include_nodes,
|
|
297
|
-
"include_chunks": include_chunks,
|
|
298
|
-
"duration_ms": duration_ms,
|
|
299
|
-
"embedding_model": self._embedding_model.model_id,
|
|
300
|
-
"embedding_dim": self._embedding_model.dim,
|
|
301
|
-
}
|
|
302
|
-
),
|
|
303
|
-
op_id,
|
|
304
|
-
),
|
|
305
|
-
)
|
|
306
|
-
# A successful rebuild (re)establishes which embedder built
|
|
307
|
-
# the index — this is the only path that may flip a recorded
|
|
308
|
-
# fingerprint after an embedder swap.
|
|
309
|
-
self._write_embedder_fingerprint(conn)
|
|
310
|
-
return {
|
|
311
|
-
"status": "completed",
|
|
312
|
-
"operation_id": op_id,
|
|
313
|
-
"full": bool(full),
|
|
314
|
-
"items_total": total,
|
|
315
|
-
"items_indexed": indexed,
|
|
316
|
-
"items_skipped": skipped,
|
|
317
|
-
"duration_ms": duration_ms,
|
|
318
|
-
"embedding_model": self._embedding_model.model_id,
|
|
319
|
-
"embedding_dim": self._embedding_model.dim,
|
|
320
|
-
}
|
|
321
|
-
except Exception as exc:
|
|
322
|
-
duration_ms = round((time.perf_counter() - started) * 1000, 2)
|
|
323
|
-
with self._connect() as conn:
|
|
324
|
-
conn.execute(
|
|
325
|
-
"""
|
|
326
|
-
INSERT INTO vector_index_operations(
|
|
327
|
-
id, operation, status, requested_at, started_at, completed_at,
|
|
328
|
-
error_message, metadata_json
|
|
329
|
-
)
|
|
330
|
-
VALUES (?, ?, 'failed', ?, ?, ?, ?, ?)
|
|
331
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
332
|
-
status='failed',
|
|
333
|
-
completed_at=excluded.completed_at,
|
|
334
|
-
error_message=excluded.error_message,
|
|
335
|
-
metadata_json=excluded.metadata_json
|
|
336
|
-
""",
|
|
337
|
-
(
|
|
338
|
-
op_id,
|
|
339
|
-
"rebuild_full" if full else "rebuild_incremental",
|
|
340
|
-
requested_at,
|
|
341
|
-
requested_at,
|
|
342
|
-
_now(),
|
|
343
|
-
str(exc),
|
|
344
|
-
_json({"duration_ms": duration_ms}),
|
|
345
|
-
),
|
|
346
|
-
)
|
|
347
|
-
raise
|