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,10 +1,23 @@
|
|
|
1
|
-
"""Phases 1-4: platform, configuration, identity, brain.
|
|
1
|
+
"""Phases 1-4 of the AI-Worker build: platform, configuration, identity, brain.
|
|
2
2
|
|
|
3
3
|
The first half of the build order — everything that must exist before a
|
|
4
|
-
FastAPI application object is worth creating.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
FastAPI application object is worth creating.
|
|
5
|
+
|
|
6
|
+
v11.6.0 (WP-P1) cut these four phases down to what a **pure compute worker**
|
|
7
|
+
needs. The product application built users, sessions, SSO, VPC config, the MCP
|
|
8
|
+
install state, the audit log, the knowledge-graph store, the conversation
|
|
9
|
+
store, the workspace OS and a dozen platform services here; ``lattice-host``
|
|
10
|
+
owns every one of those now, and Python owns no durable state at all. What
|
|
11
|
+
survives is the smallest set that still lets this process infer, embed, parse,
|
|
12
|
+
render and transcribe:
|
|
13
|
+
|
|
14
|
+
* the MLX device (phase 1),
|
|
15
|
+
* configuration and the data directory the model cache lives under (phase 2),
|
|
16
|
+
* the **seam gate** — ``require_user``, the rate limiter, the loopback posture
|
|
17
|
+
(phase 3). It is a check, not a store: durable sessions and users are
|
|
18
|
+
``lattice-auth``'s,
|
|
19
|
+
* the resolved embedder and the multi-modal ports (phase 4), which is all the
|
|
20
|
+
compute seams need.
|
|
8
21
|
|
|
9
22
|
Every heavy import lives *inside* a phase, never at module scope
|
|
10
23
|
(``tests/unit/test_runtime_context.py`` enforces that for each submodule).
|
|
@@ -13,7 +26,7 @@ Every heavy import lives *inside* a phase, never at module scope
|
|
|
13
26
|
from __future__ import annotations
|
|
14
27
|
|
|
15
28
|
import logging
|
|
16
|
-
from typing import Any, Dict,
|
|
29
|
+
from typing import Any, Dict, Optional
|
|
17
30
|
|
|
18
31
|
from latticeai.core.quiet import quiet
|
|
19
32
|
from latticeai.runtime.runtime_context import RuntimeContext
|
|
@@ -43,8 +56,7 @@ def phase_config(ctx: RuntimeContext) -> None:
|
|
|
43
56
|
"""Parse configuration once and lay out the data directory."""
|
|
44
57
|
ctx.enter("config")
|
|
45
58
|
|
|
46
|
-
from latticeai
|
|
47
|
-
from latticeai.core.workspace_os import WORKSPACE_OS_VERSION
|
|
59
|
+
from latticeai import __version__ as app_version
|
|
48
60
|
from latticeai.runtime.config_runtime import build_config_runtime
|
|
49
61
|
from latticeai.runtime.security_runtime import build_security_runtime
|
|
50
62
|
|
|
@@ -62,7 +74,6 @@ def phase_config(ctx: RuntimeContext) -> None:
|
|
|
62
74
|
"IS_PUBLIC_MODE",
|
|
63
75
|
"DEFAULT_HOST",
|
|
64
76
|
"DEFAULT_PORT",
|
|
65
|
-
"ENABLE_TELEGRAM",
|
|
66
77
|
"ENABLE_GRAPH",
|
|
67
78
|
"AUTOLOAD_MODELS",
|
|
68
79
|
"MODEL_IDLE_UNLOAD_SECONDS",
|
|
@@ -78,29 +89,15 @@ def phase_config(ctx: RuntimeContext) -> None:
|
|
|
78
89
|
"LOCAL_MODEL",
|
|
79
90
|
"LOCAL_DRAFT_MODEL",
|
|
80
91
|
)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
# Forwarded headers (X-Forwarded-For / CF-Connecting-IP) are honoured
|
|
86
|
-
# for IP rate limiting only when the direct peer is a trusted proxy.
|
|
87
|
-
_host_is_loopback=lambda host: _host_is_loopback_impl(host),
|
|
88
|
-
)
|
|
92
|
+
# The version the worker reports on ``/health``. It used to be read off the
|
|
93
|
+
# Workspace OS store's schema constant; that store is native platform state
|
|
94
|
+
# now, and the package version was always the same number.
|
|
95
|
+
ctx.set(APP_VERSION=app_version)
|
|
89
96
|
|
|
90
97
|
security_runtime = build_security_runtime(ctx.CONFIG)
|
|
91
98
|
ctx.set(security_runtime=security_runtime)
|
|
92
|
-
ctx.adopt(
|
|
93
|
-
|
|
94
|
-
"SSO_DISCOVERY_URL",
|
|
95
|
-
"SSO_CLIENT_ID",
|
|
96
|
-
"SSO_CLIENT_SECRET",
|
|
97
|
-
"SSO_REDIRECT_URI",
|
|
98
|
-
"SSO_PROVIDER_NAME",
|
|
99
|
-
"INVITE_CODE",
|
|
100
|
-
"INVITE_COOKIE_SECRET",
|
|
101
|
-
"INVITE_GATE_ENABLED",
|
|
102
|
-
"SECURE_COOKIES",
|
|
103
|
-
)
|
|
99
|
+
ctx.adopt(security_runtime, "RATE_LIMIT_ENABLED")
|
|
100
|
+
ctx.set(_RATE_LIMIT_ENABLED=ctx.RATE_LIMIT_ENABLED)
|
|
104
101
|
|
|
105
102
|
from pathlib import Path
|
|
106
103
|
|
|
@@ -117,148 +114,47 @@ def phase_config(ctx: RuntimeContext) -> None:
|
|
|
117
114
|
DATA_DIR=data_dir,
|
|
118
115
|
STATIC_DIR=ctx.CONFIG.static_dir,
|
|
119
116
|
USERS_FILE=data_dir / "users.json",
|
|
120
|
-
HISTORY_FILE=data_dir / "chat_history.json",
|
|
121
|
-
VPC_FILE=data_dir / "vpc_config.json",
|
|
122
|
-
AUDIT_FILE=data_dir / "audit_log.json",
|
|
123
|
-
SSO_FILE=data_dir / "sso_config.json",
|
|
124
117
|
)
|
|
125
118
|
|
|
126
119
|
|
|
127
|
-
# ── phase 3:
|
|
120
|
+
# ── phase 3: the seam gate ───────────────────────────────────────────────────
|
|
128
121
|
def phase_identity(ctx: RuntimeContext) -> None:
|
|
129
|
-
"""
|
|
122
|
+
"""Who is calling, and may they call this often.
|
|
123
|
+
|
|
124
|
+
Not an identity *store*: the worker reads ``users.json`` to answer "what
|
|
125
|
+
role does this session's email have" and holds session tokens in memory for
|
|
126
|
+
the life of the process. Registration, password hashing, invitations, SSO
|
|
127
|
+
and the audit log went to ``lattice-auth`` and ``lattice-platform`` with
|
|
128
|
+
every route that used them.
|
|
129
|
+
"""
|
|
130
130
|
ctx.enter("identity")
|
|
131
131
|
|
|
132
132
|
from fastapi import HTTPException, Request
|
|
133
133
|
|
|
134
|
-
from latticeai.core.
|
|
135
|
-
from latticeai.core.
|
|
136
|
-
check_ip_rate_limit as _check_ip_rate_limit,
|
|
137
|
-
)
|
|
138
|
-
from latticeai.core.security import (
|
|
139
|
-
client_ip as _client_ip_impl,
|
|
140
|
-
)
|
|
141
|
-
from latticeai.core.security import (
|
|
142
|
-
enforce_rate_limit as _enforce_rate_limit,
|
|
143
|
-
)
|
|
144
|
-
from latticeai.core.security import hash_password, verify_password
|
|
145
|
-
from latticeai.core.security import (
|
|
146
|
-
redact_secret_text as _redact_secret_text,
|
|
147
|
-
)
|
|
148
|
-
from latticeai.core.users import (
|
|
149
|
-
ensure_user_identity,
|
|
150
|
-
load_users_file,
|
|
151
|
-
migrate_knowledge_graph_identity,
|
|
152
|
-
save_users_file,
|
|
153
|
-
)
|
|
134
|
+
from latticeai.core.security import enforce_rate_limit as _enforce_rate_limit
|
|
135
|
+
from latticeai.core.users import load_users_file
|
|
154
136
|
from latticeai.core.users import user_id_for_email as _user_id_for_email
|
|
155
137
|
from latticeai.runtime.access_runtime import build_access_runtime
|
|
156
|
-
from latticeai.runtime.audit_runtime import build_audit_runtime
|
|
157
138
|
from latticeai.runtime.bootstrap import build_session_runtime
|
|
158
|
-
from latticeai.runtime.network_config_runtime import build_vpc_runtime
|
|
159
|
-
from latticeai.runtime.sso_config_runtime import build_sso_config_runtime
|
|
160
|
-
from latticeai.runtime.user_key_runtime import build_user_key_runtime
|
|
161
|
-
|
|
162
|
-
# MCP install state (extracted to mcp_registry during the server decomp).
|
|
163
|
-
mcp_state = create_mcp_install_state(ctx.DATA_DIR)
|
|
164
|
-
ctx.adopt(
|
|
165
|
-
mcp_state,
|
|
166
|
-
"load_mcp_installs",
|
|
167
|
-
"mcp_public_item",
|
|
168
|
-
"recommend_mcps",
|
|
169
|
-
"install_mcp",
|
|
170
|
-
)
|
|
171
139
|
|
|
172
140
|
def load_users() -> Dict[str, Any]:
|
|
173
|
-
|
|
174
|
-
email_to_id = {
|
|
175
|
-
email: str(user["id"])
|
|
176
|
-
for email, user in users.items()
|
|
177
|
-
if isinstance(user, dict) and user.get("id")
|
|
178
|
-
}
|
|
179
|
-
try:
|
|
180
|
-
migrate_knowledge_graph_identity(
|
|
181
|
-
ctx.DATA_DIR / "knowledge_graph.sqlite", email_to_id
|
|
182
|
-
)
|
|
183
|
-
except Exception as exc:
|
|
184
|
-
logging.warning("knowledge graph identity migration skipped: %s", exc)
|
|
185
|
-
try:
|
|
186
|
-
# WORKSPACE_OS is built in the `brain` phase; resolving it here (at
|
|
187
|
-
# call time) is why this stays a closure over ctx.
|
|
188
|
-
ctx.WORKSPACE_OS.migrate_workspace_identities(email_to_id)
|
|
189
|
-
except Exception as exc:
|
|
190
|
-
logging.warning("workspace identity migration skipped: %s", exc)
|
|
191
|
-
return users
|
|
192
|
-
|
|
193
|
-
def save_users(users: Dict[str, Any]) -> None:
|
|
194
|
-
save_users_file(ctx.USERS_FILE, users)
|
|
141
|
+
return load_users_file(ctx.USERS_FILE)
|
|
195
142
|
|
|
196
143
|
def user_id_for_email(email: Optional[str]) -> Optional[str]:
|
|
197
144
|
return _user_id_for_email(load_users(), email)
|
|
198
145
|
|
|
199
|
-
def verify_and_migrate_password(
|
|
200
|
-
email: str, plain: str, stored: str, users: Dict
|
|
201
|
-
) -> bool:
|
|
202
|
-
"""평문 비밀번호를 투명하게 해시로 마이그레이션. 마이그레이션 발생 시 audit log 남김."""
|
|
203
|
-
if ":" in stored and len(stored) > 64:
|
|
204
|
-
return verify_password(plain, stored)
|
|
205
|
-
if plain == stored:
|
|
206
|
-
users[email]["password"] = hash_password(plain)
|
|
207
|
-
save_users(users)
|
|
208
|
-
try:
|
|
209
|
-
ctx.append_audit_event(
|
|
210
|
-
"password_migrated_from_plaintext", user_email=email
|
|
211
|
-
)
|
|
212
|
-
except Exception as exc:
|
|
213
|
-
logging.warning("audit log failed on password migration: %s", exc)
|
|
214
|
-
logging.info("Migrated plaintext password to scrypt hash for %s", email)
|
|
215
|
-
return True
|
|
216
|
-
return False
|
|
217
|
-
|
|
218
|
-
def redact_secret_text(text: str) -> str:
|
|
219
|
-
return _redact_secret_text(text)
|
|
220
|
-
|
|
221
|
-
def _check_rate_limit(
|
|
222
|
-
ip: str, action: str, max_calls: int, window_secs: float
|
|
223
|
-
) -> None:
|
|
224
|
-
_check_ip_rate_limit(ip, action, max_calls=max_calls, window_secs=window_secs)
|
|
225
|
-
|
|
226
|
-
def _client_ip(request: Request) -> str:
|
|
227
|
-
return _client_ip_impl(request)
|
|
228
|
-
|
|
229
146
|
def enforce_rate_limit(email: str, bucket_key: str) -> None:
|
|
230
147
|
_enforce_rate_limit(email, bucket_key, enabled=ctx._RATE_LIMIT_ENABLED)
|
|
231
148
|
|
|
232
149
|
ctx.set(
|
|
233
150
|
load_users=load_users,
|
|
234
|
-
save_users=save_users,
|
|
235
151
|
user_id_for_email=user_id_for_email,
|
|
236
|
-
verify_and_migrate_password=verify_and_migrate_password,
|
|
237
|
-
redact_secret_text=redact_secret_text,
|
|
238
|
-
_check_rate_limit=_check_rate_limit,
|
|
239
|
-
_client_ip=_client_ip,
|
|
240
152
|
enforce_rate_limit=enforce_rate_limit,
|
|
241
153
|
)
|
|
242
154
|
|
|
243
155
|
# Session token lifecycle; user_id_for_email is the injected subject resolver.
|
|
244
156
|
session_runtime = build_session_runtime(user_id_resolver=user_id_for_email)
|
|
245
|
-
ctx.adopt(
|
|
246
|
-
session_runtime,
|
|
247
|
-
"_SESSION_TTL",
|
|
248
|
-
"_session_store",
|
|
249
|
-
"create_session",
|
|
250
|
-
"get_session_email",
|
|
251
|
-
"invalidate_session",
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
# Audit is built after redaction is available, because every event is
|
|
255
|
-
# redacted before it is written.
|
|
256
|
-
audit_runtime = build_audit_runtime(
|
|
257
|
-
audit_file=ctx.AUDIT_FILE,
|
|
258
|
-
logging=logging,
|
|
259
|
-
redact_fn=redact_secret_text,
|
|
260
|
-
)
|
|
261
|
-
ctx.adopt(audit_runtime, "get_audit_log", "append_audit_event")
|
|
157
|
+
ctx.adopt(session_runtime, "_session_store", "get_session_email")
|
|
262
158
|
|
|
263
159
|
access_runtime = build_access_runtime(
|
|
264
160
|
config=ctx.CONFIG,
|
|
@@ -276,81 +172,34 @@ def phase_identity(ctx: RuntimeContext) -> None:
|
|
|
276
172
|
"get_current_user",
|
|
277
173
|
"require_user",
|
|
278
174
|
"require_admin",
|
|
279
|
-
"public_user",
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
user_key_runtime = build_user_key_runtime(
|
|
283
|
-
load_users=load_users,
|
|
284
|
-
save_users=save_users,
|
|
285
|
-
ensure_user_identity=ensure_user_identity,
|
|
286
|
-
keyring=ctx.keyring,
|
|
287
|
-
allow_plaintext_api_keys=ctx.ALLOW_PLAINTEXT_API_KEYS,
|
|
288
|
-
logging=logging,
|
|
289
|
-
http_exception=HTTPException,
|
|
290
175
|
)
|
|
291
|
-
ctx.adopt(
|
|
292
|
-
user_key_runtime, "get_history_user", "get_user_api_key", "set_user_api_key"
|
|
293
|
-
)
|
|
294
|
-
|
|
295
|
-
# SSO config + OIDC discovery share one closure, so saving the config
|
|
296
|
-
# actually invalidates the discovery cache.
|
|
297
|
-
sso_runtime = build_sso_config_runtime(
|
|
298
|
-
sso_file=ctx.SSO_FILE,
|
|
299
|
-
discovery_url=ctx.SSO_DISCOVERY_URL,
|
|
300
|
-
client_id=ctx.SSO_CLIENT_ID,
|
|
301
|
-
client_secret=ctx.SSO_CLIENT_SECRET,
|
|
302
|
-
redirect_uri=ctx.SSO_REDIRECT_URI,
|
|
303
|
-
provider_name=ctx.SSO_PROVIDER_NAME,
|
|
304
|
-
logging=logging,
|
|
305
|
-
)
|
|
306
|
-
ctx.adopt(
|
|
307
|
-
sso_runtime,
|
|
308
|
-
"_sso_env_defaults",
|
|
309
|
-
"get_sso_settings",
|
|
310
|
-
"public_sso_config",
|
|
311
|
-
"save_sso_config",
|
|
312
|
-
"_get_sso_discovery",
|
|
313
|
-
"_sso_states",
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
vpc_runtime = build_vpc_runtime(vpc_file=ctx.VPC_FILE, logging=logging)
|
|
317
|
-
ctx.adopt(vpc_runtime, "load_vpc_config", "save_vpc_config")
|
|
318
176
|
|
|
319
177
|
|
|
320
|
-
# ── phase 4:
|
|
178
|
+
# ── phase 4: the compute ports ───────────────────────────────────────────────
|
|
321
179
|
def phase_brain(ctx: RuntimeContext) -> None:
|
|
322
|
-
"""
|
|
180
|
+
"""The embedder and the multi-modal ports — the worker's whole Brain half.
|
|
181
|
+
|
|
182
|
+
``phase_brain`` used to open ``knowledge_graph.sqlite``, build the
|
|
183
|
+
conversation store, the workspace OS, the plugin registry, the memory
|
|
184
|
+
service and the ingest write door. Rust owns every one of those writes
|
|
185
|
+
(§Wave 2.5), so what is left is the two *ports* the compute seams need:
|
|
186
|
+
something that turns text into a vector, and something that can look at a
|
|
187
|
+
picture or listen to a recording. Both degrade to an honest absence rather
|
|
188
|
+
than failing construction.
|
|
189
|
+
"""
|
|
323
190
|
ctx.enter("brain")
|
|
324
191
|
|
|
325
|
-
import
|
|
326
|
-
|
|
327
|
-
from fastapi import HTTPException
|
|
328
|
-
|
|
329
|
-
from lattice_brain.graph.schema import set_embed_dim
|
|
330
|
-
from lattice_brain.ingestion import IngestionItem
|
|
331
|
-
from lattice_brain.storage import storage_from_env
|
|
332
|
-
from latticeai.core.audit import (
|
|
333
|
-
build_admin_audit_report as _build_admin_audit_report,
|
|
334
|
-
)
|
|
335
|
-
from latticeai.core.audit import (
|
|
336
|
-
build_sensitivity_report as _build_sensitivity_report,
|
|
337
|
-
)
|
|
338
|
-
from latticeai.core.audit import (
|
|
339
|
-
classify_sensitive_message as _classify_sensitive_message,
|
|
340
|
-
)
|
|
192
|
+
from lattice_brain.ingestion import IngestionPipeline
|
|
341
193
|
from latticeai.core.embedding_providers import (
|
|
342
194
|
resolve_embedder,
|
|
343
195
|
resolve_embedding_profile,
|
|
344
196
|
)
|
|
345
|
-
from latticeai.
|
|
346
|
-
|
|
197
|
+
from latticeai.runtime.brain_runtime import build_embedder_runtime
|
|
198
|
+
from latticeai.services.multimodal_ports import (
|
|
199
|
+
build_multimodal_ports,
|
|
200
|
+
multimodal_enabled,
|
|
347
201
|
)
|
|
348
|
-
from latticeai.
|
|
349
|
-
from latticeai.runtime.brain_runtime import build_brain_runtime
|
|
350
|
-
from latticeai.runtime.history_runtime import build_history_query_runtime
|
|
351
|
-
from latticeai.runtime.history_writer import HistoryWriterDeps, write_chat_turn
|
|
352
|
-
from latticeai.runtime.hooks_runtime import build_hooks_runtime
|
|
353
|
-
from latticeai.runtime.persistence_runtime import build_persistence_runtime
|
|
202
|
+
from latticeai.services.voice_capture import VoiceCaptureService
|
|
354
203
|
|
|
355
204
|
# Resolve the configured embedding provider once. Degrades to the offline
|
|
356
205
|
# hash fallback when unavailable, recording requested-vs-active provider.
|
|
@@ -360,196 +209,37 @@ def phase_brain(ctx: RuntimeContext) -> None:
|
|
|
360
209
|
logging.warning("Embedding profile ignored: %s", exc)
|
|
361
210
|
embedding_profile = {}
|
|
362
211
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
provider = str(embedding_profile.get("provider") or provider)
|
|
368
|
-
|
|
369
|
-
embedder = resolve_embedder(
|
|
370
|
-
provider,
|
|
371
|
-
model=model,
|
|
372
|
-
base_url=ctx.CONFIG.embedding_base_url,
|
|
373
|
-
api_key=ctx.CONFIG.embedding_api_key,
|
|
374
|
-
dim=dim,
|
|
375
|
-
timeout=ctx.CONFIG.embedding_timeout,
|
|
376
|
-
extra={"target": ctx.CONFIG.embedding_custom_target},
|
|
377
|
-
probe=provider not in {"", "hash", "local", "fallback"},
|
|
212
|
+
embedder = build_embedder_runtime(
|
|
213
|
+
config=ctx.CONFIG,
|
|
214
|
+
profile=embedding_profile,
|
|
215
|
+
resolve_embedder=resolve_embedder,
|
|
378
216
|
)
|
|
379
|
-
set_embed_dim(int(getattr(embedder, "dim", None) or dim or 384))
|
|
380
217
|
if embedder.fell_back:
|
|
381
218
|
logging.warning(
|
|
382
219
|
"Embedding provider %s unavailable: %s", embedder.requested, embedder.detail
|
|
383
220
|
)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
)
|
|
401
|
-
|
|
402
|
-
# CONVERSATIONS is the v4 durable episodic store: unbounded history in the
|
|
403
|
-
# same SQLite file as the graph, so backup/restore covers it for free.
|
|
404
|
-
ctx.adopt(brain_runtime, "KNOWLEDGE_GRAPH", "CONVERSATIONS")
|
|
405
|
-
|
|
406
|
-
def save_to_history(
|
|
407
|
-
role: str,
|
|
408
|
-
message: str,
|
|
409
|
-
user_email: Optional[str] = None,
|
|
410
|
-
user_nickname: Optional[str] = None,
|
|
411
|
-
source: Optional[str] = None,
|
|
412
|
-
conversation_id: Optional[str] = None,
|
|
413
|
-
workspace_id: Optional[str] = None,
|
|
414
|
-
) -> None:
|
|
415
|
-
"""Persist one chat turn. Logic lives in runtime/history_writer.py.
|
|
416
|
-
|
|
417
|
-
The dependency bundle is built per call because INGESTION_PIPELINE is
|
|
418
|
-
published later in this same phase; resolving through ctx keeps the
|
|
419
|
-
ordering contract in one place instead of reordering the phase.
|
|
420
|
-
"""
|
|
421
|
-
write_chat_turn(
|
|
422
|
-
role,
|
|
423
|
-
message,
|
|
424
|
-
user_email=user_email,
|
|
425
|
-
user_nickname=user_nickname,
|
|
426
|
-
source=source,
|
|
427
|
-
conversation_id=conversation_id,
|
|
428
|
-
workspace_id=workspace_id,
|
|
429
|
-
deps=HistoryWriterDeps(
|
|
430
|
-
conversations=ctx.CONVERSATIONS,
|
|
431
|
-
append_audit_event=ctx.append_audit_event,
|
|
432
|
-
classify_sensitive_message=ctx.classify_sensitive_message,
|
|
433
|
-
redact_secret_text=ctx.redact_secret_text,
|
|
434
|
-
normalize_branding=normalize_branding,
|
|
435
|
-
ingestion_pipeline=ctx.INGESTION_PIPELINE,
|
|
436
|
-
ingestion_item_factory=IngestionItem,
|
|
437
|
-
enable_graph=ctx.ENABLE_GRAPH,
|
|
438
|
-
knowledge_graph=ctx.KNOWLEDGE_GRAPH,
|
|
439
|
-
),
|
|
440
|
-
)
|
|
441
|
-
|
|
442
|
-
def classify_sensitive_message(item: Dict, index: int) -> Dict:
|
|
443
|
-
return _classify_sensitive_message(item, index)
|
|
444
|
-
|
|
445
|
-
def build_sensitivity_report(history: List[Dict]) -> Dict:
|
|
446
|
-
return _build_sensitivity_report(history)
|
|
447
|
-
|
|
448
|
-
def build_admin_audit_report(
|
|
449
|
-
users: Dict, audit_events: Optional[List[Dict]] = None
|
|
450
|
-
) -> Dict:
|
|
451
|
-
graph_stats = None
|
|
452
|
-
try:
|
|
453
|
-
if ctx.ENABLE_GRAPH and ctx.KNOWLEDGE_GRAPH:
|
|
454
|
-
graph_stats = ctx.KNOWLEDGE_GRAPH.stats()
|
|
455
|
-
except Exception:
|
|
456
|
-
quiet()
|
|
457
|
-
return _build_admin_audit_report(
|
|
458
|
-
ctx.AUDIT_FILE,
|
|
459
|
-
users,
|
|
460
|
-
get_user_role=ctx.get_user_role,
|
|
461
|
-
graph_stats=graph_stats,
|
|
462
|
-
audit_events=audit_events,
|
|
463
|
-
)
|
|
464
|
-
|
|
465
|
-
def _bytes_match_extension(data: bytes, ext: str) -> bool:
|
|
466
|
-
return _bytes_match_extension_impl(data, ext)
|
|
467
|
-
|
|
468
|
-
def _require_graph() -> None:
|
|
469
|
-
if not ctx.ENABLE_GRAPH or ctx.KNOWLEDGE_GRAPH is None:
|
|
470
|
-
raise HTTPException(
|
|
471
|
-
status_code=404,
|
|
472
|
-
detail=(
|
|
473
|
-
"지식 그래프가 비활성화되어 있습니다. "
|
|
474
|
-
"LATTICEAI_ENABLE_GRAPH=true 설정 후 다시 시도해 주세요."
|
|
475
|
-
),
|
|
476
|
-
)
|
|
477
|
-
|
|
478
|
-
def _workspace_graph() -> Any:
|
|
479
|
-
return (
|
|
480
|
-
ctx.KNOWLEDGE_GRAPH
|
|
481
|
-
if (ctx.ENABLE_GRAPH and ctx.KNOWLEDGE_GRAPH)
|
|
482
|
-
else None
|
|
483
|
-
)
|
|
484
|
-
|
|
221
|
+
ctx.set(EMBEDDING_PROFILE=embedding_profile, EMBEDDER=embedder)
|
|
222
|
+
|
|
223
|
+
# Multi-modal capture (v11.1.0): off unless the user turned it on, and even
|
|
224
|
+
# then only as capable as the models actually present. With nothing
|
|
225
|
+
# configured this resolves to an empty bundle without importing or loading
|
|
226
|
+
# anything.
|
|
227
|
+
#
|
|
228
|
+
# The transcriber is resolved through the voice service so a voice memo and
|
|
229
|
+
# a scanned ``.m4a`` are transcribed by the same thing — or, far more often,
|
|
230
|
+
# by the same nothing.
|
|
231
|
+
voice_capture = VoiceCaptureService(transcriber=None)
|
|
232
|
+
multimodal_ports = build_multimodal_ports(
|
|
233
|
+
transcriber=voice_capture.multimodal_ports().transcriber
|
|
234
|
+
)
|
|
235
|
+
# The capability probe behind ``GET /api/ingestion/multimodal``. It answers
|
|
236
|
+
# what this machine *could* do with a picture, a recording or a video; the
|
|
237
|
+
# ingest door itself is native (§W3b), which is why nothing is passed here
|
|
238
|
+
# for it to write through.
|
|
485
239
|
ctx.set(
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
_bytes_match_extension=_bytes_match_extension,
|
|
491
|
-
_require_graph=_require_graph,
|
|
492
|
-
_workspace_graph=_workspace_graph,
|
|
493
|
-
)
|
|
494
|
-
|
|
495
|
-
# The hooks registry is built ahead of the watcher so folder-watch
|
|
496
|
-
# reindexes can fire the pre_index/post_index lifecycle hooks.
|
|
497
|
-
hooks_runtime = build_hooks_runtime(
|
|
498
|
-
data_dir=ctx.DATA_DIR,
|
|
499
|
-
enable_graph=ctx.ENABLE_GRAPH,
|
|
500
|
-
knowledge_graph_getter=lambda: ctx.KNOWLEDGE_GRAPH,
|
|
501
|
-
)
|
|
502
|
-
ctx.adopt(hooks_runtime, "HOOKS_REGISTRY", "LOCAL_KG_WATCHER")
|
|
503
|
-
|
|
504
|
-
persistence_runtime = build_persistence_runtime(
|
|
505
|
-
data_dir=ctx.DATA_DIR,
|
|
506
|
-
base_dir=ctx.BASE_DIR,
|
|
507
|
-
enable_graph=ctx.ENABLE_GRAPH,
|
|
508
|
-
knowledge_graph=ctx.KNOWLEDGE_GRAPH,
|
|
509
|
-
hooks_registry=ctx.HOOKS_REGISTRY,
|
|
510
|
-
history_file=ctx.HISTORY_FILE,
|
|
511
|
-
conversations=ctx.CONVERSATIONS,
|
|
512
|
-
user_id_for_email=ctx.user_id_for_email,
|
|
513
|
-
audit=lambda action, detail, user: ctx.append_audit_event(
|
|
514
|
-
action, user_email=user, **detail
|
|
240
|
+
VOICE_CAPTURE=voice_capture,
|
|
241
|
+
MULTIMODAL_PORTS=multimodal_ports,
|
|
242
|
+
INGESTION_PIPELINE=IngestionPipeline(
|
|
243
|
+
allow_multimodal=multimodal_enabled(), multimodal=multimodal_ports
|
|
515
244
|
),
|
|
516
245
|
)
|
|
517
|
-
ctx.adopt(
|
|
518
|
-
persistence_runtime,
|
|
519
|
-
"REALTIME_BUS",
|
|
520
|
-
"WORKSPACE_OS",
|
|
521
|
-
"WORKSPACE_SERVICE",
|
|
522
|
-
"INVITATION_STORE",
|
|
523
|
-
"PLUGIN_REGISTRY",
|
|
524
|
-
"TEMPLATE_CATALOG",
|
|
525
|
-
"AGENT_REGISTRY",
|
|
526
|
-
"MEMORY_SERVICE",
|
|
527
|
-
"BRAIN_INTELLIGENCE",
|
|
528
|
-
"AUTOMATION_INTELLIGENCE",
|
|
529
|
-
"INGESTION_PIPELINE",
|
|
530
|
-
"MULTIMODAL_PORTS",
|
|
531
|
-
"DEVICE_IDENTITY",
|
|
532
|
-
"KG_PORTABILITY",
|
|
533
|
-
"FUNNEL_METRICS",
|
|
534
|
-
)
|
|
535
|
-
|
|
536
|
-
# History reads/clears. The write path (save_to_history above) stays a
|
|
537
|
-
# closure because it is bound to redaction/audit/ingestion.
|
|
538
|
-
history_query_runtime = build_history_query_runtime(
|
|
539
|
-
conversations=ctx.CONVERSATIONS,
|
|
540
|
-
workspace_service=ctx.WORKSPACE_SERVICE,
|
|
541
|
-
require_auth=ctx.REQUIRE_AUTH,
|
|
542
|
-
logging=logging,
|
|
543
|
-
)
|
|
544
|
-
ctx.adopt(
|
|
545
|
-
history_query_runtime,
|
|
546
|
-
"_history_allowed_workspaces_for",
|
|
547
|
-
"_history_include_legacy_global",
|
|
548
|
-
"get_history",
|
|
549
|
-
"conversation_title",
|
|
550
|
-
"group_history_conversations",
|
|
551
|
-
"get_conversation_messages",
|
|
552
|
-
"clear_history",
|
|
553
|
-
"clear_conversation",
|
|
554
|
-
)
|
|
555
|
-
|