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
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""The worker profile: which routes an AI-Worker process serves, and only those.
|
|
2
|
+
|
|
3
|
+
v11.6.0 turns ``lattice-host`` into the product server (plan §설계 결정 1): 439
|
|
4
|
+
of the 464 Python routes become native axum handlers, and the proxy fall-through
|
|
5
|
+
is inverted into an allowlist that passes **only** the worker's own surface. The
|
|
6
|
+
allowlist and this module's :data:`WORKER_ROUTES` are the same contract read from
|
|
7
|
+
opposite ends, so it is written down once, here, as data.
|
|
8
|
+
|
|
9
|
+
Two honest boundaries, because a reader will otherwise assume more:
|
|
10
|
+
|
|
11
|
+
* **This profile shrinks the HTTP surface, not the construction.** WP-P1
|
|
12
|
+
deleted the keep-set's complement, so the six phases the worker runs now
|
|
13
|
+
build only what it serves and the filter below removes nothing — it has
|
|
14
|
+
become the assertion that nothing crept back. It stays because the allowlist
|
|
15
|
+
and the route table must keep being one fact read from two ends.
|
|
16
|
+
|
|
17
|
+
* **The filter fails loudly.** A route named here that construction did not
|
|
18
|
+
produce raises at boot instead of yielding a worker that is quietly missing
|
|
19
|
+
its embedding surface. That is the failure mode a later WP will actually hit.
|
|
20
|
+
|
|
21
|
+
The browser middleware (CORS, the CSRF origin guard) and the ``/static`` +
|
|
22
|
+
``/icons`` mounts stay on the application object — they are attached by
|
|
23
|
+
``phase_web`` — but the UI routes they serve are gone from the worker, which is
|
|
24
|
+
correct: the worker is a loopback process the host starts for itself, and every
|
|
25
|
+
seam on it is still behind ``require_user`` plus the seam switch.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from typing import Any, List, Set, Tuple
|
|
31
|
+
|
|
32
|
+
#: ``(method, path)`` for each product route v11.6.0 leaves in Python —
|
|
33
|
+
#: docs/v11.6.0_ONE_DOOR_PLAN.md §최종 Python 워커 표면, cross-checked against
|
|
34
|
+
#: the KEEP_WORKER table of the route scout, then narrowed by §W3b (ingest,
|
|
35
|
+
#: drain/rebuild, voice capture and the four document creators went native) and
|
|
36
|
+
#: widened by §4a (the model pull came back). Paths are FastAPI's, converters
|
|
37
|
+
#: included, so this compares to ``APIRoute.path`` without normalisation.
|
|
38
|
+
#:
|
|
39
|
+
#: This tuple, through :func:`worker_route_keys`, is the **one** source of the
|
|
40
|
+
#: gateway's proxy allowlist. ``rust/fixtures/worker_allowlist.json`` is its
|
|
41
|
+
#: committed projection, regenerated by
|
|
42
|
+
#: ``scripts/gen_worker_allowlist_fixture.py`` and pinned by
|
|
43
|
+
#: ``tests/unit/test_worker_allowlist.py`` — so a route added or removed here
|
|
44
|
+
#: without regenerating fails CI instead of silently opening or closing a door
|
|
45
|
+
#: in the Rust front door.
|
|
46
|
+
WORKER_ROUTES: Tuple[Tuple[str, str], ...] = (
|
|
47
|
+
# AI-Worker seam (v11.5.1; /agent/change-proposal retired by WP-P1 —
|
|
48
|
+
# proposal state is native platform state and a stateless worker has no
|
|
49
|
+
# verdict to give)
|
|
50
|
+
("POST", "/agent/llm"),
|
|
51
|
+
("POST", "/agent/tool"),
|
|
52
|
+
# supervisor liveness + access posture
|
|
53
|
+
("GET", "/health"),
|
|
54
|
+
# embedding production (drain/rebuild are native — W3b)
|
|
55
|
+
("GET", "/api/embeddings/status"),
|
|
56
|
+
("GET", "/api/embeddings/providers"),
|
|
57
|
+
# MLX model + engine lifecycle (in-process only)
|
|
58
|
+
("GET", "/models"),
|
|
59
|
+
("POST", "/models/load"),
|
|
60
|
+
("POST", "/models/switch/{model_id:path}"),
|
|
61
|
+
("DELETE", "/models/unload/{model_id:path}"),
|
|
62
|
+
("DELETE", "/models/unload-all"),
|
|
63
|
+
("POST", "/engines/prepare-model"),
|
|
64
|
+
("POST", "/engines/prepare-model/stream"),
|
|
65
|
+
# The download itself is huggingface_hub / ollama running in *this*
|
|
66
|
+
# interpreter, which is the same reason the six lines above stay: model
|
|
67
|
+
# management is the worker's box. The gateway proxies it rather than
|
|
68
|
+
# shipping a native consent check in front of a 501 (v11.6.0 gateway
|
|
69
|
+
# integration §4a).
|
|
70
|
+
("POST", "/engines/pull-model"),
|
|
71
|
+
# document parser (create_* + upload are native — W3b)
|
|
72
|
+
("POST", "/tools/read_document"),
|
|
73
|
+
("GET", "/tools/pdf_pages"),
|
|
74
|
+
("GET", "/api/ingestion/multimodal"),
|
|
75
|
+
# local ASR status (POST /api/capture/voice is native — W3b)
|
|
76
|
+
("GET", "/api/capture/voice/status"),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
#: Retired by W3b — ingest is native. Kept as an empty tuple so imports
|
|
80
|
+
#: (`GRAPH_WRITER_ROUTES`) and `worker_route_keys()` stay stable.
|
|
81
|
+
GRAPH_WRITER_ROUTES: Tuple[Tuple[str, str], ...] = ()
|
|
82
|
+
|
|
83
|
+
#: The seams v11.6.0 adds (WP-I6 + WP-R4's streaming completion). Mounted here
|
|
84
|
+
#: and nowhere else. ``/worker/chat/record-turn`` was the third: WP-W3a moved
|
|
85
|
+
#: the redact → audit → store → ingest chain into ``lattice-chat`` and proved
|
|
86
|
+
#: the seam is requested zero times, and WP-P1 deleted the handler with the
|
|
87
|
+
#: conversation store it wrote through.
|
|
88
|
+
WORKER_SEAM_ROUTES: Tuple[Tuple[str, str], ...] = (
|
|
89
|
+
("GET", "/worker/sysinfo"),
|
|
90
|
+
("POST", "/worker/llm/stream"),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
#: The pure-compute seams of Wave 2.5 §W2 (``latticeai/api/worker_compute.py``).
|
|
94
|
+
#: Kept apart from :data:`WORKER_SEAM_ROUTES` because they age in the opposite
|
|
95
|
+
#: direction: the state seams above are retired once §W3 lands the native write
|
|
96
|
+
#: engine, while these nine are what the worker is *for* once Rust owns every
|
|
97
|
+
#: write. Mounted here and nowhere else.
|
|
98
|
+
WORKER_COMPUTE_ROUTES: Tuple[Tuple[str, str], ...] = (
|
|
99
|
+
("POST", "/worker/embed"),
|
|
100
|
+
("POST", "/worker/parse"),
|
|
101
|
+
("POST", "/worker/render/docx"),
|
|
102
|
+
("POST", "/worker/render/xlsx"),
|
|
103
|
+
("POST", "/worker/render/pptx"),
|
|
104
|
+
("POST", "/worker/render/pdf"),
|
|
105
|
+
("POST", "/worker/asr"),
|
|
106
|
+
("POST", "/worker/multimodal/describe"),
|
|
107
|
+
("POST", "/worker/extract"),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def worker_route_keys() -> Set[Tuple[str, str]]:
|
|
112
|
+
"""Every ``(method, path)`` a worker process may answer."""
|
|
113
|
+
return (
|
|
114
|
+
set(WORKER_ROUTES)
|
|
115
|
+
| set(GRAPH_WRITER_ROUTES)
|
|
116
|
+
| set(WORKER_SEAM_ROUTES)
|
|
117
|
+
| set(WORKER_COMPUTE_ROUTES)
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _route_keys(route: Any) -> Set[Tuple[str, str]]:
|
|
123
|
+
"""``{(method, path)}`` for one API route — every method it answers.
|
|
124
|
+
|
|
125
|
+
A route is kept only when *all* of its methods are on the allowlist, so a
|
|
126
|
+
path that also serves an un-allowlisted verb cannot slip through on the
|
|
127
|
+
strength of the one verb the worker wanted.
|
|
128
|
+
"""
|
|
129
|
+
return {(str(method), str(route.path)) for method in route.methods}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def phase_worker_routes(ctx: Any) -> None:
|
|
133
|
+
"""Mount the v11.6.0 seams, then reduce the app to the worker surface.
|
|
134
|
+
|
|
135
|
+
Runs *after* the ordinary build phases: it needs the model router and the
|
|
136
|
+
resolved embedder. It publishes nothing onto the context — the profile is a
|
|
137
|
+
decision about the application object, not more assembly state.
|
|
138
|
+
"""
|
|
139
|
+
from latticeai.api.worker_compute import create_worker_compute_router
|
|
140
|
+
from latticeai.api.worker_seams import create_worker_seams_router
|
|
141
|
+
|
|
142
|
+
app = ctx.app
|
|
143
|
+
app.include_router(
|
|
144
|
+
create_worker_seams_router(
|
|
145
|
+
require_user=ctx.require_user,
|
|
146
|
+
enforce_rate_limit=ctx.enforce_rate_limit,
|
|
147
|
+
model_router=getattr(ctx, "model_router", None),
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
# The compute seams take the *resolved* embedder and the same injected
|
|
151
|
+
# multimodal ports the ingestion path holds, so a vector or a caption
|
|
152
|
+
# produced through HTTP is the one this process would have produced
|
|
153
|
+
# in-process. ``getattr`` because a worker built without a Brain still boots
|
|
154
|
+
# — each seam reports the absence rather than failing construction.
|
|
155
|
+
ports = getattr(ctx, "MULTIMODAL_PORTS", None)
|
|
156
|
+
app.include_router(
|
|
157
|
+
create_worker_compute_router(
|
|
158
|
+
embedder=getattr(ctx, "EMBEDDER", None),
|
|
159
|
+
transcriber=getattr(ports, "transcriber", None),
|
|
160
|
+
multimodal_ports=ports,
|
|
161
|
+
require_user=ctx.require_user,
|
|
162
|
+
enforce_rate_limit=ctx.enforce_rate_limit,
|
|
163
|
+
)
|
|
164
|
+
)
|
|
165
|
+
apply_worker_route_filter(app)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _included_router(route: Any) -> Any:
|
|
169
|
+
"""The router behind an ``include_router`` entry, or ``None``.
|
|
170
|
+
|
|
171
|
+
FastAPI ≥ 0.140 stopped flattening ``include_router`` into the application's
|
|
172
|
+
own route list and appends a ``_IncludedRouter`` wrapper instead. A filter
|
|
173
|
+
that only understood the flat shape saw *zero* API routes on the newer
|
|
174
|
+
release and raised "the build produced no route for …" for the entire
|
|
175
|
+
surface — a boot failure that depends on which FastAPI a fresh resolve
|
|
176
|
+
picked, which is the worst kind. Read through the wrapper by duck-typing
|
|
177
|
+
(``original_router``) rather than importing a private class, so neither
|
|
178
|
+
release is the one this file is written against.
|
|
179
|
+
"""
|
|
180
|
+
inner = getattr(route, "original_router", None)
|
|
181
|
+
return inner if inner is not None and hasattr(inner, "routes") else None
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def apply_worker_route_filter(app: Any) -> None:
|
|
185
|
+
"""Keep the worker's routes and FastAPI's own doc routes; drop the rest.
|
|
186
|
+
|
|
187
|
+
``/openapi.json`` survives because the worker-only schema is one half of
|
|
188
|
+
the v11.6.0 OpenAPI composer (plan §설계 결정 4); the ``/static`` and
|
|
189
|
+
``/icons`` mounts do not, because a worker serves no UI.
|
|
190
|
+
|
|
191
|
+
Since WP-P1 this removes nothing — construction produces exactly the worker
|
|
192
|
+
surface — so what it really is now is the assertion that nothing crept back
|
|
193
|
+
in, and that every route the allowlist promises was actually built.
|
|
194
|
+
"""
|
|
195
|
+
from fastapi.routing import APIRoute
|
|
196
|
+
from starlette.routing import Mount
|
|
197
|
+
|
|
198
|
+
wanted = worker_route_keys()
|
|
199
|
+
present: Set[Tuple[str, str]] = set()
|
|
200
|
+
|
|
201
|
+
def _prune(routes: List[Any]) -> List[Any]:
|
|
202
|
+
kept: List[Any] = []
|
|
203
|
+
for route in list(routes):
|
|
204
|
+
included = _included_router(route)
|
|
205
|
+
if included is not None:
|
|
206
|
+
included.routes = _prune(included.routes)
|
|
207
|
+
if included.routes:
|
|
208
|
+
kept.append(route)
|
|
209
|
+
continue
|
|
210
|
+
if isinstance(route, APIRoute):
|
|
211
|
+
keys = _route_keys(route)
|
|
212
|
+
if keys <= wanted:
|
|
213
|
+
present.update(keys)
|
|
214
|
+
kept.append(route)
|
|
215
|
+
continue
|
|
216
|
+
if isinstance(route, Mount):
|
|
217
|
+
# ``/static`` and ``/icons``: a worker serves no UI.
|
|
218
|
+
continue
|
|
219
|
+
# FastAPI's own ``/openapi.json``, ``/docs``, ``/redoc``.
|
|
220
|
+
kept.append(route)
|
|
221
|
+
return kept
|
|
222
|
+
|
|
223
|
+
kept = _prune(app.router.routes)
|
|
224
|
+
missing = sorted(wanted - present)
|
|
225
|
+
if missing:
|
|
226
|
+
raise RuntimeError(
|
|
227
|
+
"worker profile: the build produced no route for "
|
|
228
|
+
+ ", ".join(f"{method} {path}" for method, path in missing)
|
|
229
|
+
)
|
|
230
|
+
app.router.routes = kept
|
|
231
|
+
# The schema was never generated at this point, but a caller that asked for
|
|
232
|
+
# it before pruning would otherwise be served the product route table.
|
|
233
|
+
app.openapi_schema = None
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
__all__ = [
|
|
237
|
+
"GRAPH_WRITER_ROUTES",
|
|
238
|
+
"WORKER_COMPUTE_ROUTES",
|
|
239
|
+
"WORKER_ROUTES",
|
|
240
|
+
"WORKER_SEAM_ROUTES",
|
|
241
|
+
"apply_worker_route_filter",
|
|
242
|
+
"phase_worker_routes",
|
|
243
|
+
"worker_route_keys",
|
|
244
|
+
]
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
"""FastAPI lifespan assembly for
|
|
1
|
+
"""FastAPI lifespan assembly for worker startup and shutdown tasks.
|
|
2
|
+
|
|
3
|
+
Two background tasks, both about the one thing this process holds that a
|
|
4
|
+
restart would lose: the loaded model. The telegram bridge and the local
|
|
5
|
+
knowledge watcher used to start here too — both are product surfaces
|
|
6
|
+
``lattice-host`` owns now, and neither had anything to do with inference.
|
|
7
|
+
"""
|
|
2
8
|
|
|
3
9
|
from __future__ import annotations
|
|
4
10
|
|
|
@@ -11,7 +17,6 @@ from latticeai.core.quiet import quiet
|
|
|
11
17
|
def build_lifespan_runtime(
|
|
12
18
|
*,
|
|
13
19
|
app_mode: str,
|
|
14
|
-
enable_telegram: bool,
|
|
15
20
|
autoload_models: bool,
|
|
16
21
|
is_public_mode: bool,
|
|
17
22
|
public_model: str,
|
|
@@ -20,7 +25,6 @@ def build_lifespan_runtime(
|
|
|
20
25
|
local_draft_model: str,
|
|
21
26
|
model_idle_unload_seconds: int,
|
|
22
27
|
model_router: Any,
|
|
23
|
-
local_kg_watcher: Any,
|
|
24
28
|
local_server_processes: Dict[str, Any],
|
|
25
29
|
logger: Any,
|
|
26
30
|
) -> Dict[str, Any]:
|
|
@@ -103,26 +107,13 @@ def build_lifespan_runtime(
|
|
|
103
107
|
async def lifespan(_app):
|
|
104
108
|
try:
|
|
105
109
|
print(f"🧭 Lattice AI mode: {app_mode}")
|
|
106
|
-
if enable_telegram:
|
|
107
|
-
from latticeai.integrations.telegram_bot import run_bot
|
|
108
|
-
|
|
109
|
-
spawn(run_bot(), name="telegram_bot")
|
|
110
|
-
print("🚀 Telegram Bot Bridge activated!")
|
|
111
|
-
else:
|
|
112
|
-
print("⏭️ Telegram Bot Bridge disabled for this mode.")
|
|
113
110
|
spawn(unload_idle_models_loop(), name="unload_idle_models")
|
|
114
111
|
spawn(autoload_default_model(), name="autoload_default_model")
|
|
115
|
-
if local_kg_watcher:
|
|
116
|
-
restored = local_kg_watcher.restore_enabled_sources()
|
|
117
|
-
if restored.get("restored"):
|
|
118
|
-
print(f"🕸️ Local knowledge watchers restored: {restored['restored']}")
|
|
119
112
|
except Exception as e: # pragma: no cover - startup diagnostics
|
|
120
113
|
print(f"⚠️ Startup sequence failed: {e}")
|
|
121
114
|
try:
|
|
122
115
|
yield
|
|
123
116
|
finally:
|
|
124
|
-
if local_kg_watcher:
|
|
125
|
-
local_kg_watcher.stop_all()
|
|
126
117
|
model_router.unload_all()
|
|
127
118
|
for proc in local_server_processes.values():
|
|
128
119
|
try:
|
|
@@ -22,18 +22,4 @@ def build_model_service(
|
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
*,
|
|
27
|
-
identity: Any,
|
|
28
|
-
portability: Any,
|
|
29
|
-
data_dir: Any,
|
|
30
|
-
) -> Any:
|
|
31
|
-
"""Construct peer sync/network service for brain portability routes."""
|
|
32
|
-
|
|
33
|
-
from lattice_brain.graph.network import BrainNetwork
|
|
34
|
-
|
|
35
|
-
return BrainNetwork(
|
|
36
|
-
identity=identity,
|
|
37
|
-
portability=portability,
|
|
38
|
-
data_dir=data_dir,
|
|
39
|
-
)
|
|
25
|
+
__all__ = ["build_model_service"]
|
|
@@ -44,7 +44,6 @@ class RuntimeContext:
|
|
|
44
44
|
IS_PUBLIC_MODE: bool
|
|
45
45
|
DEFAULT_HOST: str
|
|
46
46
|
DEFAULT_PORT: int
|
|
47
|
-
ENABLE_TELEGRAM: bool
|
|
48
47
|
ENABLE_GRAPH: bool
|
|
49
48
|
AUTOLOAD_MODELS: bool
|
|
50
49
|
MODEL_IDLE_UNLOAD_SECONDS: Any
|
|
@@ -59,166 +58,50 @@ class RuntimeContext:
|
|
|
59
58
|
PUBLIC_MODEL: str
|
|
60
59
|
LOCAL_MODEL: Any
|
|
61
60
|
LOCAL_DRAFT_MODEL: Any
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
SSO_CLIENT_ID: Any
|
|
65
|
-
SSO_CLIENT_SECRET: Any
|
|
66
|
-
SSO_REDIRECT_URI: Any
|
|
67
|
-
SSO_PROVIDER_NAME: Any
|
|
68
|
-
INVITE_CODE: Any
|
|
69
|
-
INVITE_COOKIE_SECRET: Any
|
|
70
|
-
INVITE_GATE_ENABLED: bool
|
|
71
|
-
SECURE_COOKIES: bool
|
|
61
|
+
RATE_LIMIT_ENABLED: bool
|
|
62
|
+
_RATE_LIMIT_ENABLED: bool
|
|
72
63
|
BASE_DIR: Any
|
|
73
64
|
DATA_DIR: Any
|
|
74
65
|
STATIC_DIR: Any
|
|
75
66
|
USERS_FILE: Any
|
|
76
|
-
HISTORY_FILE: Any
|
|
77
|
-
VPC_FILE: Any
|
|
78
|
-
AUDIT_FILE: Any
|
|
79
|
-
SSO_FILE: Any
|
|
80
67
|
keyring: Any
|
|
81
68
|
|
|
82
|
-
# ── phase 3:
|
|
83
|
-
load_mcp_installs: Any
|
|
84
|
-
mcp_public_item: Any
|
|
85
|
-
recommend_mcps: Any
|
|
86
|
-
install_mcp: Any
|
|
87
|
-
_SESSION_TTL: Any
|
|
69
|
+
# ── phase 3: the seam gate ───────────────────────────────────────────
|
|
88
70
|
_session_store: Any
|
|
89
|
-
create_session: Any
|
|
90
71
|
get_session_email: Any
|
|
91
|
-
invalidate_session: Any
|
|
92
72
|
load_users: Any
|
|
93
|
-
save_users: Any
|
|
94
73
|
user_id_for_email: Any
|
|
95
|
-
verify_and_migrate_password: Any
|
|
96
|
-
redact_secret_text: Any
|
|
97
|
-
get_audit_log: Any
|
|
98
|
-
append_audit_event: Any
|
|
99
|
-
classify_sensitive_message: Any
|
|
100
|
-
build_sensitivity_report: Any
|
|
101
|
-
build_admin_audit_report: Any
|
|
102
74
|
get_user_role: Any
|
|
103
75
|
_extract_bearer_token: Any
|
|
104
76
|
get_current_user: Any
|
|
105
77
|
require_user: Any
|
|
106
78
|
require_admin: Any
|
|
107
|
-
public_user: Any
|
|
108
|
-
_RATE_LIMIT_ENABLED: bool
|
|
109
79
|
enforce_rate_limit: Any
|
|
110
|
-
_check_rate_limit: Any
|
|
111
|
-
_client_ip: Any
|
|
112
|
-
_bytes_match_extension: Any
|
|
113
|
-
_host_is_loopback: Any
|
|
114
|
-
get_history_user: Any
|
|
115
|
-
get_user_api_key: Any
|
|
116
|
-
set_user_api_key: Any
|
|
117
|
-
get_sso_settings: Any
|
|
118
|
-
public_sso_config: Any
|
|
119
|
-
save_sso_config: Any
|
|
120
|
-
_get_sso_discovery: Any
|
|
121
|
-
_sso_states: Any
|
|
122
|
-
_sso_env_defaults: Any
|
|
123
|
-
load_vpc_config: Any
|
|
124
|
-
save_vpc_config: Any
|
|
125
80
|
|
|
126
|
-
# ── phase 4:
|
|
81
|
+
# ── phase 4: the compute ports ───────────────────────────────────────
|
|
127
82
|
EMBEDDING_PROFILE: Any
|
|
128
83
|
EMBEDDER: Any
|
|
129
|
-
|
|
130
|
-
brain_runtime: Any
|
|
131
|
-
KNOWLEDGE_GRAPH: Any
|
|
132
|
-
CONVERSATIONS: Any
|
|
133
|
-
save_to_history: Any
|
|
134
|
-
HOOKS_REGISTRY: Any
|
|
135
|
-
LOCAL_KG_WATCHER: Any
|
|
136
|
-
REALTIME_BUS: Any
|
|
137
|
-
WORKSPACE_OS: Any
|
|
138
|
-
WORKSPACE_SERVICE: Any
|
|
139
|
-
INVITATION_STORE: Any
|
|
140
|
-
PLUGIN_REGISTRY: Any
|
|
141
|
-
TEMPLATE_CATALOG: Any
|
|
142
|
-
AGENT_REGISTRY: Any
|
|
143
|
-
MEMORY_SERVICE: Any
|
|
144
|
-
BRAIN_INTELLIGENCE: Any
|
|
145
|
-
AUTOMATION_INTELLIGENCE: Any
|
|
146
|
-
INGESTION_PIPELINE: Any
|
|
84
|
+
VOICE_CAPTURE: Any
|
|
147
85
|
MULTIMODAL_PORTS: Any
|
|
148
|
-
|
|
149
|
-
KG_PORTABILITY: Any
|
|
150
|
-
FUNNEL_METRICS: Any
|
|
151
|
-
get_history: Any
|
|
152
|
-
conversation_title: Any
|
|
153
|
-
group_history_conversations: Any
|
|
154
|
-
get_conversation_messages: Any
|
|
155
|
-
clear_history: Any
|
|
156
|
-
clear_conversation: Any
|
|
157
|
-
_history_allowed_workspaces_for: Any
|
|
158
|
-
_history_include_legacy_global: Any
|
|
159
|
-
_require_graph: Any
|
|
160
|
-
_workspace_graph: Any
|
|
86
|
+
INGESTION_PIPELINE: Any
|
|
161
87
|
|
|
162
|
-
# ── phase 5: domain
|
|
88
|
+
# ── phase 5: domain singletons ───────────────────────────────────────
|
|
163
89
|
model_router: Any
|
|
164
|
-
gardener: Any
|
|
165
|
-
CHAT_SERVICE: Any
|
|
166
|
-
SEARCH_SERVICE: Any
|
|
167
|
-
BRAIN_MEMORY: Any
|
|
168
|
-
CONTEXT_ASSEMBLER: Any
|
|
169
|
-
ARTIFACT_LEDGER: Any
|
|
170
|
-
_scoped_hybrid_search: Any
|
|
171
|
-
CHAT_AGENT_RUNTIME: Any
|
|
172
|
-
on_chat_message: Any
|
|
173
|
-
_recent_chat_context: Any
|
|
174
|
-
_workspace_settings_payload: Any
|
|
175
|
-
_workspace_models_payload: Any
|
|
176
|
-
_embedding_info: Any
|
|
177
|
-
_allowed_workspaces_for: Any
|
|
178
|
-
app_context: Any
|
|
179
90
|
|
|
180
|
-
# ── phase 6: web
|
|
91
|
+
# ── phase 6: the web shell ───────────────────────────────────────────
|
|
181
92
|
_spawn: Any
|
|
182
93
|
lifespan: Any
|
|
183
94
|
app: Any
|
|
95
|
+
CORS_ALLOWED_ORIGINS: Any
|
|
96
|
+
CSRF_ALLOWED_ORIGINS: Any
|
|
184
97
|
model_runtime_service: Any
|
|
185
|
-
STATIC_ROUTES: Any
|
|
186
|
-
ui_file_response: Any
|
|
187
|
-
local_sysinfo: Any
|
|
188
|
-
invite_authorized: Any
|
|
189
|
-
auth_router: Any
|
|
190
|
-
admin_router: Any
|
|
191
|
-
invitations_router: Any
|
|
192
|
-
security_router: Any
|
|
193
|
-
_graph_stats_safe: Any
|
|
194
|
-
_product_hardening_status: Any
|
|
195
|
-
_security_audit_events_safe: Any
|
|
196
|
-
_security_list_uploaded_files: Any
|
|
197
|
-
|
|
198
|
-
# ── phase 7: platform features ───────────────────────────────────────
|
|
199
|
-
_llm_generate_sync: Any
|
|
200
|
-
PLATFORM: Any
|
|
201
|
-
_automation_runtime: Any
|
|
202
|
-
REVIEW_QUEUE: Any
|
|
203
|
-
TRIGGER_SERVICE: Any
|
|
204
|
-
AGENT_RUNTIME: Any
|
|
205
|
-
RUN_EXECUTOR: Any
|
|
206
|
-
COMMAND_CENTER: Any
|
|
207
|
-
CHRONICLE: Any
|
|
208
|
-
CHANGE_PROPOSALS: Any
|
|
209
|
-
EVIDENCE_ACTIONS_SERVICE: Any
|
|
210
|
-
VOICE_CAPTURE: Any
|
|
211
|
-
PROJECT_SESSIONS: Any
|
|
212
98
|
|
|
213
|
-
# ── phase
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
# ── legacy compatibility surface (phase 9 reads these) ───────────────
|
|
217
|
-
legacy: Dict[str, Any]
|
|
99
|
+
# ── phase 7: the compute routers ─────────────────────────────────────
|
|
100
|
+
model_service: Any
|
|
101
|
+
_embedding_info: Any
|
|
218
102
|
|
|
219
103
|
def __init__(self, config: Any = None) -> None:
|
|
220
104
|
self.config_arg = config
|
|
221
|
-
self.legacy = {}
|
|
222
105
|
self._produced: Dict[str, str] = {}
|
|
223
106
|
self._phase: str = "<none>"
|
|
224
107
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
"""Security runtime
|
|
1
|
+
"""Security-derived runtime settings for the AI-Worker build.
|
|
2
|
+
|
|
3
|
+
Everything this module used to resolve — SSO endpoints, the invitation gate's
|
|
4
|
+
per-install secrets, the Secure-cookie decision — belonged to the login surface
|
|
5
|
+
``lattice-auth`` owns now. One setting outlives it: whether the per-user rate
|
|
6
|
+
limiter is armed, which the worker still enforces on every seam call.
|
|
7
|
+
"""
|
|
2
8
|
|
|
3
9
|
from __future__ import annotations
|
|
4
10
|
|
|
5
|
-
import json
|
|
6
|
-
import logging
|
|
7
|
-
import secrets
|
|
8
11
|
from dataclasses import dataclass
|
|
9
|
-
from
|
|
10
|
-
from typing import TYPE_CHECKING, Dict
|
|
12
|
+
from typing import TYPE_CHECKING
|
|
11
13
|
|
|
12
14
|
from latticeai.runtime.stages import RuntimeStage
|
|
13
15
|
|
|
@@ -15,110 +17,15 @@ if TYPE_CHECKING:
|
|
|
15
17
|
from latticeai.core.config import Config
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
_SECURITY_SECRETS_FILE = "security_secrets.json"
|
|
19
|
-
|
|
20
|
-
|
|
21
20
|
@dataclass(frozen=True)
|
|
22
21
|
class SecurityRuntime(RuntimeStage):
|
|
23
|
-
SSO_DISCOVERY_URL: str
|
|
24
|
-
SSO_CLIENT_ID: str
|
|
25
|
-
SSO_CLIENT_SECRET: str
|
|
26
|
-
SSO_REDIRECT_URI: str
|
|
27
|
-
SSO_PROVIDER_NAME: str
|
|
28
22
|
RATE_LIMIT_ENABLED: bool
|
|
29
|
-
OPEN_REGISTRATION: bool
|
|
30
|
-
INVITE_CODE: str
|
|
31
|
-
INVITE_COOKIE_SECRET: str
|
|
32
|
-
INVITE_GATE_ENABLED: bool
|
|
33
|
-
SECURE_COOKIES: bool
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def _stored_security_secrets(data_dir: Path) -> Dict[str, str]:
|
|
37
|
-
path = data_dir / _SECURITY_SECRETS_FILE
|
|
38
|
-
if not path.exists():
|
|
39
|
-
return {}
|
|
40
|
-
try:
|
|
41
|
-
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
42
|
-
except Exception as exc:
|
|
43
|
-
# A corrupt secret store invalidates old invite cookies, but must never
|
|
44
|
-
# make startup fall back to a shared or predictable signing key.
|
|
45
|
-
logging.warning("invite-gate secret store is unreadable; rotating secrets: %s", exc)
|
|
46
|
-
return {}
|
|
47
|
-
if not isinstance(payload, dict):
|
|
48
|
-
return {}
|
|
49
|
-
return {
|
|
50
|
-
key: str(value)
|
|
51
|
-
for key, value in payload.items()
|
|
52
|
-
if key in {"invite_code", "invite_cookie_secret"} and value
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def _resolve_invite_gate_secrets(config: "Config") -> tuple[str, str]:
|
|
57
|
-
"""Resolve stable, per-install invitation secrets.
|
|
58
|
-
|
|
59
|
-
No file is created while the invitation gate is disabled. Once enabled,
|
|
60
|
-
missing values are generated with the OS CSPRNG and persisted atomically
|
|
61
|
-
with mode 0600 so restarts do not invalidate links or signed cookies.
|
|
62
|
-
Explicit environment values remain authoritative and are not copied to the
|
|
63
|
-
local secret file unnecessarily.
|
|
64
|
-
"""
|
|
65
|
-
|
|
66
|
-
if not config.invite_gate_enabled:
|
|
67
|
-
return config.invite_code, config.invite_cookie_secret
|
|
68
|
-
|
|
69
|
-
from latticeai.core.io_utils import atomic_write_json
|
|
70
|
-
|
|
71
|
-
data_dir = Path(config.data_dir)
|
|
72
|
-
stored = _stored_security_secrets(data_dir)
|
|
73
|
-
invite_code = config.invite_code or stored.get("invite_code") or secrets.token_urlsafe(24)
|
|
74
|
-
cookie_secret = (
|
|
75
|
-
config.invite_cookie_secret
|
|
76
|
-
or stored.get("invite_cookie_secret")
|
|
77
|
-
or secrets.token_urlsafe(48)
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
persisted = dict(stored)
|
|
81
|
-
if not config.invite_code:
|
|
82
|
-
persisted["invite_code"] = invite_code
|
|
83
|
-
if not config.invite_cookie_secret:
|
|
84
|
-
persisted["invite_cookie_secret"] = cookie_secret
|
|
85
|
-
if persisted != stored:
|
|
86
|
-
atomic_write_json(data_dir / _SECURITY_SECRETS_FILE, persisted)
|
|
87
|
-
return invite_code, cookie_secret
|
|
88
23
|
|
|
89
24
|
|
|
90
25
|
def build_security_runtime(config: "Config") -> SecurityRuntime:
|
|
91
|
-
"""Build
|
|
92
|
-
|
|
93
|
-
from latticeai.core.security import configure_trusted_proxies
|
|
26
|
+
"""Build the security-derived runtime settings from the central config."""
|
|
94
27
|
|
|
95
|
-
|
|
96
|
-
invite_code, invite_cookie_secret = _resolve_invite_gate_secrets(config)
|
|
97
|
-
secure_cookies = bool(config.is_public or config.network_exposed)
|
|
98
|
-
if secure_cookies:
|
|
99
|
-
logging.warning(
|
|
100
|
-
"Public/non-loopback mode: authentication and Secure cookies are forced; "
|
|
101
|
-
"serve Lattice AI through HTTPS/TLS or browser sessions will be rejected."
|
|
102
|
-
)
|
|
103
|
-
if config.invite_gate_enabled and not config.invite_code:
|
|
104
|
-
logging.warning(
|
|
105
|
-
"No LATTICEAI_INVITE_CODE was configured; generated a private per-install "
|
|
106
|
-
"invite code in %s.",
|
|
107
|
-
Path(config.data_dir) / _SECURITY_SECRETS_FILE,
|
|
108
|
-
)
|
|
109
|
-
return SecurityRuntime(
|
|
110
|
-
SSO_DISCOVERY_URL=config.sso_discovery_url,
|
|
111
|
-
SSO_CLIENT_ID=config.sso_client_id,
|
|
112
|
-
SSO_CLIENT_SECRET=config.sso_client_secret,
|
|
113
|
-
SSO_REDIRECT_URI=config.sso_redirect_uri,
|
|
114
|
-
SSO_PROVIDER_NAME=config.sso_provider_name,
|
|
115
|
-
RATE_LIMIT_ENABLED=config.rate_limit_enabled,
|
|
116
|
-
OPEN_REGISTRATION=config.open_registration,
|
|
117
|
-
INVITE_CODE=invite_code,
|
|
118
|
-
INVITE_COOKIE_SECRET=invite_cookie_secret,
|
|
119
|
-
INVITE_GATE_ENABLED=config.invite_gate_enabled,
|
|
120
|
-
SECURE_COOKIES=secure_cookies,
|
|
121
|
-
)
|
|
28
|
+
return SecurityRuntime(RATE_LIMIT_ENABLED=config.rate_limit_enabled)
|
|
122
29
|
|
|
123
30
|
|
|
124
31
|
__all__ = ["SecurityRuntime", "build_security_runtime"]
|