ltcai 11.5.2 → 11.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -148
- package/bin/ltcai.js +234 -24
- package/docs/CHANGELOG.md +75 -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 +21 -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-CToZnOHz.js} +1 -1
- package/static/app/assets/{AdminConsole-cf4npybT.js → AdminConsole-D5kbrBu8.js} +1 -1
- package/static/app/assets/{Brain-3VCSHFcn.js → Brain-C6zCdv4S.js} +1 -1
- package/static/app/assets/{BrainHome-Qm8eaztx.js → BrainHome-D4n3EDUt.js} +1 -1
- package/static/app/assets/{BrainSignals-DS9BtKOW.js → BrainSignals-CzeZ-vQ9.js} +1 -1
- package/static/app/assets/{Capture-DiQ219jW.js → Capture-DPcyTczq.js} +1 -1
- package/static/app/assets/{Chronicle-BGvuAchH.js → Chronicle-D3Nx-oWS.js} +1 -1
- package/static/app/assets/{CommandPalette-Bqhm0Urn.js → CommandPalette-DPPvpp28.js} +1 -1
- package/static/app/assets/{Library-BV6NnF0a.js → Library-Co2qTu3I.js} +1 -1
- package/static/app/assets/{LivingBrain-GzenJchP.js → LivingBrain-Bsmzwy8_.js} +1 -1
- package/static/app/assets/{ProductFlow-DEP6-vML.js → ProductFlow-CBLdmesT.js} +1 -1
- package/static/app/assets/{ReviewCard-CNZ7XjWG.js → ReviewCard-CfR6DLs7.js} +1 -1
- package/static/app/assets/{System-CieofHQa.js → System-Ce-P2YL6.js} +1 -1
- package/static/app/assets/arrow-left-DD5jFGHV.js +1 -0
- package/static/app/assets/{bot-B_K1Tdmw.js → bot-C5-XIww2.js} +1 -1
- package/static/app/assets/{brain-DWyaV1L1.js → brain-CFRJUvdX.js} +1 -1
- package/static/app/assets/{button-aTn4s84A.js → button-DI1KcQP-.js} +1 -1
- package/static/app/assets/circle-check-CY20XMCh.js +1 -0
- package/static/app/assets/{circle-pause-xKgeGXkT.js → circle-pause-C8HHyood.js} +1 -1
- package/static/app/assets/{circle-play-DkT6tYPX.js → circle-play-Cufc235E.js} +1 -1
- package/static/app/assets/{cpu-85xYObUC.js → cpu-DW2_JVsv.js} +1 -1
- package/static/app/assets/{download-B5Fm7YXo.js → download-gbdKTBb8.js} +1 -1
- package/static/app/assets/{folder-open-kk2Xa52u.js → folder-open-C9ydyX33.js} +1 -1
- package/static/app/assets/{hard-drive-DkA3zBW_.js → hard-drive-BxNMzBM3.js} +1 -1
- package/static/app/assets/index-BovSWRmQ.css +2 -0
- package/static/app/assets/{index-BMPdTmlY.js → index-q9XyDY7A.js} +3 -3
- package/static/app/assets/{input-B0nRf2jO.js → input-GLD94Y_K.js} +1 -1
- package/static/app/assets/{link-2-Dwb4gnTc.js → link-2-B4Y0gz1S.js} +1 -1
- package/static/app/assets/{permissionCopy-CQDUBrOZ.js → permissionCopy-CxrV0fvU.js} +1 -1
- package/static/app/assets/{primitives-SNp0LRJz.js → primitives-2ANdAsu2.js} +1 -1
- package/static/app/assets/search-DTxtjQ07.js +1 -0
- package/static/app/assets/{share-2-BsrxFglO.js → share-2-DxArfiuI.js} +1 -1
- package/static/app/assets/{shield-alert-5BStfp2_.js → shield-alert-CgftuFFs.js} +1 -1
- package/static/app/assets/{textarea-Cg8IUA-k.js → textarea-BHVBAoCr.js} +1 -1
- package/static/app/assets/{useFocusTrap-CYKvE46M.js → useFocusTrap-Dzq2j_OG.js} +1 -1
- package/static/app/assets/{useMutation-CSn9t1op.js → useMutation-BcqfMLNq.js} +1 -1
- package/static/app/assets/{useQuery-CY2OI2uy.js → useQuery-DBzLKCOv.js} +1 -1
- package/static/app/assets/{utils-Ddol2RWD.js → utils-B-Aah1bO.js} +1 -1
- package/static/app/assets/{workspace-BqDwOz_p.js → workspace-B6fFhoko.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/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/search-BcHqkjoy.js +0 -1
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
"""The rebinding half of the process-wide service singletons.
|
|
2
|
-
|
|
3
|
-
Four wiring modules create one service each — the permission dial, the network
|
|
4
|
-
boundary, the hybrid policy, the feature switchboard — and all four had the
|
|
5
|
-
same problem and the same four-line answer to it: a lazy first caller (a tool
|
|
6
|
-
dispatch, a feature gate) can ask for the service *before* routers know the
|
|
7
|
-
configured data dir or the audit sink, and if the later explicit call were
|
|
8
|
-
allowed to be a no-op the service would stay pinned to the fallback path with
|
|
9
|
-
its audit events going nowhere.
|
|
10
|
-
|
|
11
|
-
So explicit arguments rebind rather than being dropped. That rule was written
|
|
12
|
-
out four times; it lives here once, because "the second caller silently loses"
|
|
13
|
-
is precisely the kind of divergence that produces a second, invisible copy of
|
|
14
|
-
the user's data and no failing test.
|
|
15
|
-
|
|
16
|
-
The singleton *slot* deliberately stays a module global in each wiring module:
|
|
17
|
-
the modules are the unit of process state, and the suite resets them by
|
|
18
|
-
assigning ``_SHARED = None``.
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
from __future__ import annotations
|
|
22
|
-
|
|
23
|
-
from pathlib import Path
|
|
24
|
-
from typing import Any, Callable, Optional, TypeVar
|
|
25
|
-
|
|
26
|
-
from latticeai.core.config import default_data_dir
|
|
27
|
-
|
|
28
|
-
ServiceT = TypeVar("ServiceT")
|
|
29
|
-
|
|
30
|
-
__all__ = ["singleton_data_dir", "rebind_singleton"]
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def singleton_data_dir(data_dir: Optional[Path]) -> Path:
|
|
34
|
-
"""Where a *first* lazy caller should put the store."""
|
|
35
|
-
return Path(data_dir) if data_dir is not None else default_data_dir()
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def rebind_singleton(
|
|
39
|
-
service: ServiceT,
|
|
40
|
-
*,
|
|
41
|
-
data_dir: Optional[Path] = None,
|
|
42
|
-
audit: Optional[Callable[..., None]] = None,
|
|
43
|
-
) -> ServiceT:
|
|
44
|
-
"""Apply explicit arguments to an already-created singleton, then return it.
|
|
45
|
-
|
|
46
|
-
``None`` means "the caller did not say", never "unset it" — a router that
|
|
47
|
-
mounts without an audit sink must not silence a sink an earlier caller
|
|
48
|
-
already supplied.
|
|
49
|
-
"""
|
|
50
|
-
rebindable: Any = service
|
|
51
|
-
if data_dir is not None:
|
|
52
|
-
rebindable.rebind_data_dir(Path(data_dir))
|
|
53
|
-
if audit is not None:
|
|
54
|
-
rebindable.rebind_audit(audit)
|
|
55
|
-
return service
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
"""SSO / OIDC config + discovery seam extracted from the app factory.
|
|
2
|
-
|
|
3
|
-
Owns the whole SSO surface that used to be inline in ``app_factory._build``:
|
|
4
|
-
the env-default resolution, the ``sso_config.json`` load/save, the public
|
|
5
|
-
(secret-stripped) view, and the OIDC discovery document cache.
|
|
6
|
-
|
|
7
|
-
Unlike the previous split (config inline in the factory + a separate discovery
|
|
8
|
-
cache in ``sso_runtime``), the discovery cache now lives in the *same* closure
|
|
9
|
-
as ``save_sso_config``, so saving a new SSO config actually invalidates the
|
|
10
|
-
cached discovery document. The old inline ``save_sso_config`` reassigned a
|
|
11
|
-
factory-local cache variable that ``_get_sso_discovery`` never read, so the
|
|
12
|
-
invalidation was a silent no-op — this consolidation fixes that.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
import json
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
from typing import Any, Dict, Optional
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def build_sso_config_runtime(
|
|
23
|
-
*,
|
|
24
|
-
sso_file: Path,
|
|
25
|
-
discovery_url: str,
|
|
26
|
-
client_id: str,
|
|
27
|
-
client_secret: str,
|
|
28
|
-
redirect_uri: str,
|
|
29
|
-
provider_name: str,
|
|
30
|
-
logging: Any,
|
|
31
|
-
) -> Dict[str, Any]:
|
|
32
|
-
"""Return the SSO config helpers + discovery accessor as a name → value dict."""
|
|
33
|
-
|
|
34
|
-
# Single shared discovery cache: save_sso_config and _get_sso_discovery both
|
|
35
|
-
# close over it, so a config change is observed on the next discovery fetch.
|
|
36
|
-
_discovery_cache: Dict[str, Any] = {"data": None, "url": ""}
|
|
37
|
-
_sso_states: Dict[str, float] = {}
|
|
38
|
-
|
|
39
|
-
def _sso_env_defaults() -> Dict[str, object]:
|
|
40
|
-
return {
|
|
41
|
-
"enabled": bool(discovery_url and client_id and client_secret),
|
|
42
|
-
"provider_name": provider_name,
|
|
43
|
-
"discovery_url": discovery_url,
|
|
44
|
-
"client_id": client_id,
|
|
45
|
-
"client_secret": client_secret,
|
|
46
|
-
"redirect_uri": redirect_uri,
|
|
47
|
-
"scopes": "openid email profile",
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
def load_sso_config() -> Dict[str, object]:
|
|
51
|
-
config = _sso_env_defaults()
|
|
52
|
-
if sso_file.exists():
|
|
53
|
-
try:
|
|
54
|
-
data = json.loads(sso_file.read_text(encoding="utf-8"))
|
|
55
|
-
if isinstance(data, dict):
|
|
56
|
-
config.update({k: v for k, v in data.items() if v is not None})
|
|
57
|
-
except Exception as e:
|
|
58
|
-
logging.warning("load_sso_config failed (using env/defaults): %s", e)
|
|
59
|
-
config["provider_name"] = str(config.get("provider_name") or "SSO")
|
|
60
|
-
config["discovery_url"] = str(config.get("discovery_url") or "")
|
|
61
|
-
config["client_id"] = str(config.get("client_id") or "")
|
|
62
|
-
config["client_secret"] = str(config.get("client_secret") or "")
|
|
63
|
-
config["redirect_uri"] = str(config.get("redirect_uri") or redirect_uri)
|
|
64
|
-
config["scopes"] = str(config.get("scopes") or "openid email profile")
|
|
65
|
-
config["enabled"] = bool(config.get("enabled")) and bool(
|
|
66
|
-
config["discovery_url"] and config["client_id"] and config["client_secret"]
|
|
67
|
-
)
|
|
68
|
-
return config
|
|
69
|
-
|
|
70
|
-
def get_sso_settings() -> Dict[str, object]:
|
|
71
|
-
return load_sso_config()
|
|
72
|
-
|
|
73
|
-
def public_sso_config(config: Optional[Dict[str, object]] = None) -> Dict[str, object]:
|
|
74
|
-
cfg = config or get_sso_settings()
|
|
75
|
-
return {
|
|
76
|
-
"enabled": bool(cfg.get("enabled")),
|
|
77
|
-
"provider_name": cfg.get("provider_name") or "",
|
|
78
|
-
"discovery_url": cfg.get("discovery_url") or "",
|
|
79
|
-
"client_id": cfg.get("client_id") or "",
|
|
80
|
-
"redirect_uri": cfg.get("redirect_uri") or redirect_uri,
|
|
81
|
-
"scopes": cfg.get("scopes") or "openid email profile",
|
|
82
|
-
"secret_configured": bool(cfg.get("client_secret")),
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
def save_sso_config(update: Dict[str, object]) -> Dict[str, object]:
|
|
86
|
-
current = load_sso_config()
|
|
87
|
-
if update.get("client_secret") == "":
|
|
88
|
-
update.pop("client_secret", None)
|
|
89
|
-
current.update({k: v for k, v in update.items() if v is not None})
|
|
90
|
-
current["enabled"] = bool(current.get("enabled")) and bool(
|
|
91
|
-
current.get("discovery_url") and current.get("client_id") and current.get("client_secret")
|
|
92
|
-
)
|
|
93
|
-
sso_file.write_text(json.dumps(current, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
94
|
-
_discovery_cache["data"] = None
|
|
95
|
-
_discovery_cache["url"] = ""
|
|
96
|
-
return current
|
|
97
|
-
|
|
98
|
-
async def _get_sso_discovery() -> Optional[Dict]:
|
|
99
|
-
settings = get_sso_settings()
|
|
100
|
-
url = str(settings.get("discovery_url", "") or "")
|
|
101
|
-
if _discovery_cache["data"] and _discovery_cache["url"] == url:
|
|
102
|
-
return _discovery_cache["data"]
|
|
103
|
-
if not url:
|
|
104
|
-
return None
|
|
105
|
-
try:
|
|
106
|
-
import httpx as _httpx
|
|
107
|
-
async with _httpx.AsyncClient() as c:
|
|
108
|
-
r = await c.get(url, timeout=10)
|
|
109
|
-
r.raise_for_status()
|
|
110
|
-
_discovery_cache["data"] = r.json()
|
|
111
|
-
_discovery_cache["url"] = url
|
|
112
|
-
except Exception as e:
|
|
113
|
-
logging.warning("SSO discovery failed: %s", e)
|
|
114
|
-
return None
|
|
115
|
-
return _discovery_cache["data"]
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
"_sso_env_defaults": _sso_env_defaults,
|
|
119
|
-
"load_sso_config": load_sso_config,
|
|
120
|
-
"get_sso_settings": get_sso_settings,
|
|
121
|
-
"public_sso_config": public_sso_config,
|
|
122
|
-
"save_sso_config": save_sso_config,
|
|
123
|
-
"_get_sso_discovery": _get_sso_discovery,
|
|
124
|
-
"_sso_states": _sso_states,
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
__all__ = ["build_sso_config_runtime"]
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
"""User profile + provider API-key helpers extracted from the app factory.
|
|
2
|
-
|
|
3
|
-
The helpers close over the user store, keyring adapter, identity migration, and
|
|
4
|
-
plaintext-key policy. Returning callables preserves the legacy ``server_app``
|
|
5
|
-
namespace while keeping ``app_factory._build`` focused on wiring.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
from typing import Any, Dict, Optional
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def build_user_key_runtime(
|
|
14
|
-
*,
|
|
15
|
-
load_users: Any,
|
|
16
|
-
save_users: Any,
|
|
17
|
-
ensure_user_identity: Any,
|
|
18
|
-
keyring: Any,
|
|
19
|
-
allow_plaintext_api_keys: bool,
|
|
20
|
-
logging: Any,
|
|
21
|
-
http_exception: Any,
|
|
22
|
-
) -> Dict[str, Any]:
|
|
23
|
-
"""Return history-user and provider API-key helpers."""
|
|
24
|
-
|
|
25
|
-
def get_history_user(email: Optional[str], nickname: Optional[str] = None) -> Dict:
|
|
26
|
-
if not email:
|
|
27
|
-
return {"user_email": None, "user_nickname": nickname or None}
|
|
28
|
-
users = load_users()
|
|
29
|
-
user = users.get(email, {})
|
|
30
|
-
return {
|
|
31
|
-
"user_email": email,
|
|
32
|
-
"user_nickname": nickname or user.get("nickname") or user.get("name") or email,
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
def get_user_api_key(email: Optional[str], provider: str) -> Optional[str]:
|
|
36
|
-
if not email:
|
|
37
|
-
return None
|
|
38
|
-
keyring_key = f"{email}:{provider}"
|
|
39
|
-
if keyring is not None:
|
|
40
|
-
try:
|
|
41
|
-
key = keyring.get_password("LatticeAI", keyring_key)
|
|
42
|
-
if key:
|
|
43
|
-
return key.strip()
|
|
44
|
-
except Exception as exc:
|
|
45
|
-
logging.warning("keyring read failed for %s: %s", provider, exc)
|
|
46
|
-
users = load_users()
|
|
47
|
-
user = users.get(email) or {}
|
|
48
|
-
api_keys = user.get("api_keys") or {}
|
|
49
|
-
key = api_keys.get(provider)
|
|
50
|
-
if isinstance(key, str) and key.strip() and allow_plaintext_api_keys:
|
|
51
|
-
return key.strip()
|
|
52
|
-
return None
|
|
53
|
-
|
|
54
|
-
def set_user_api_key(email: str, provider: str, key: str) -> None:
|
|
55
|
-
keyring_key = f"{email}:{provider}"
|
|
56
|
-
if keyring is not None:
|
|
57
|
-
try:
|
|
58
|
-
keyring.set_password("LatticeAI", keyring_key, key)
|
|
59
|
-
users = load_users()
|
|
60
|
-
user = users.get(email)
|
|
61
|
-
if user and "api_keys" in user:
|
|
62
|
-
user["api_keys"].pop(provider, None)
|
|
63
|
-
if not user["api_keys"]:
|
|
64
|
-
user.pop("api_keys", None)
|
|
65
|
-
save_users(users)
|
|
66
|
-
return
|
|
67
|
-
except Exception as exc:
|
|
68
|
-
logging.warning("keyring write failed for %s: %s", provider, exc)
|
|
69
|
-
if not allow_plaintext_api_keys:
|
|
70
|
-
raise http_exception(
|
|
71
|
-
status_code=500,
|
|
72
|
-
detail="OS keyring에 API 키를 저장하지 못했습니다. keyring 설정을 확인하거나 LATTICEAI_ALLOW_PLAINTEXT_API_KEYS=true를 명시적으로 설정하세요.",
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
if not allow_plaintext_api_keys:
|
|
76
|
-
raise http_exception(
|
|
77
|
-
status_code=500,
|
|
78
|
-
detail="keyring 패키지를 사용할 수 없어 API 키를 안전하게 저장할 수 없습니다.",
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
users = load_users()
|
|
82
|
-
user = users.get(email)
|
|
83
|
-
if not user:
|
|
84
|
-
user = {
|
|
85
|
-
"password_hash": "",
|
|
86
|
-
"salt": "",
|
|
87
|
-
"name": email,
|
|
88
|
-
"nickname": email,
|
|
89
|
-
"role": "user",
|
|
90
|
-
"disabled": False,
|
|
91
|
-
}
|
|
92
|
-
ensure_user_identity(email, user)
|
|
93
|
-
api_keys = user.get("api_keys") or {}
|
|
94
|
-
api_keys[provider] = key
|
|
95
|
-
user["api_keys"] = api_keys
|
|
96
|
-
users[email] = user
|
|
97
|
-
save_users(users)
|
|
98
|
-
|
|
99
|
-
return {
|
|
100
|
-
"get_history_user": get_history_user,
|
|
101
|
-
"get_user_api_key": get_user_api_key,
|
|
102
|
-
"set_user_api_key": set_user_api_key,
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
__all__ = ["build_user_key_runtime"]
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
"""FastAPI shell assembly for the application factory.
|
|
2
|
-
|
|
3
|
-
This seam owns only the outer web shell: app construction, the request-side
|
|
4
|
-
middleware (CSRF origin guard, CORS), and static asset mounts. Router
|
|
5
|
-
registration stays in ``app_factory`` until the route snapshot/reorder step is
|
|
6
|
-
reviewed.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
from typing import Any, Dict, Iterable, List
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def build_web_runtime(
|
|
16
|
-
*,
|
|
17
|
-
app_mode: str,
|
|
18
|
-
app_version: str,
|
|
19
|
-
lifespan: Any,
|
|
20
|
-
default_host: str,
|
|
21
|
-
default_port: int,
|
|
22
|
-
cors_extra_origins: Iterable[str],
|
|
23
|
-
cors_allow_network: bool,
|
|
24
|
-
static_dir: Path,
|
|
25
|
-
csrf_trusted_origins: Iterable[str] = (),
|
|
26
|
-
) -> Dict[str, Any]:
|
|
27
|
-
"""Create the FastAPI shell and mount static assets in legacy order."""
|
|
28
|
-
|
|
29
|
-
from fastapi import FastAPI
|
|
30
|
-
from fastapi.middleware.cors import CORSMiddleware
|
|
31
|
-
from fastapi.staticfiles import StaticFiles
|
|
32
|
-
|
|
33
|
-
from latticeai.core.csrf import CSRFOriginGuardMiddleware, CSRFOriginPolicy
|
|
34
|
-
from latticeai.core.security import host_is_loopback
|
|
35
|
-
|
|
36
|
-
app = FastAPI(
|
|
37
|
-
title=f"Lattice AI Server ({app_mode})",
|
|
38
|
-
version=app_version,
|
|
39
|
-
lifespan=lifespan,
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
cors_allowed_origins = [
|
|
43
|
-
f"http://localhost:{default_port}",
|
|
44
|
-
f"http://127.0.0.1:{default_port}",
|
|
45
|
-
*cors_extra_origins,
|
|
46
|
-
]
|
|
47
|
-
if cors_allow_network:
|
|
48
|
-
cors_allowed_origins = cors_allowed_origins + [
|
|
49
|
-
f"http://{default_host}:{default_port}",
|
|
50
|
-
f"https://{default_host}:{default_port}",
|
|
51
|
-
]
|
|
52
|
-
|
|
53
|
-
# An origin that CORS already lets send *credentialed* cross-origin
|
|
54
|
-
# requests is, by that decision, trusted with the session cookie; listing
|
|
55
|
-
# it again here would be a second place to forget. The explicit
|
|
56
|
-
# LATTICEAI_CSRF_TRUSTED_ORIGINS entries are for the reverse-proxy case,
|
|
57
|
-
# where the public hostname is not the bind address.
|
|
58
|
-
csrf_allowed_origins: List[str] = [
|
|
59
|
-
*cors_allowed_origins,
|
|
60
|
-
*csrf_trusted_origins,
|
|
61
|
-
]
|
|
62
|
-
csrf_policy = CSRFOriginPolicy(
|
|
63
|
-
trusted_origins=csrf_allowed_origins,
|
|
64
|
-
server_host=default_host,
|
|
65
|
-
server_port=default_port,
|
|
66
|
-
bind_is_loopback=host_is_loopback(default_host),
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
# Registration order is stack order in reverse: the LAST middleware added
|
|
70
|
-
# is the OUTERMOST. CORS must stay outside the guard so a rejected request
|
|
71
|
-
# still comes back with the CORS headers the browser needs to surface the
|
|
72
|
-
# 403 instead of an opaque network error.
|
|
73
|
-
app.add_middleware(CSRFOriginGuardMiddleware, policy=csrf_policy)
|
|
74
|
-
app.add_middleware(
|
|
75
|
-
CORSMiddleware,
|
|
76
|
-
allow_origins=cors_allowed_origins,
|
|
77
|
-
allow_methods=["*"],
|
|
78
|
-
allow_headers=["*"],
|
|
79
|
-
allow_credentials=True,
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
static_dir.mkdir(parents=True, exist_ok=True)
|
|
83
|
-
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
|
|
84
|
-
icons_dir = static_dir / "icons"
|
|
85
|
-
if icons_dir.exists():
|
|
86
|
-
app.mount("/icons", StaticFiles(directory=str(icons_dir)), name="icons")
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
"app": app,
|
|
90
|
-
"CORS_ALLOWED_ORIGINS": cors_allowed_origins,
|
|
91
|
-
"CSRF_ALLOWED_ORIGINS": csrf_allowed_origins,
|
|
92
|
-
}
|
package/latticeai/server_app.py
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"""Lazy compatibility facade over :mod:`latticeai.app_factory`.
|
|
2
|
-
|
|
3
|
-
The application used to be assembled here at import time (MLX/GPU init,
|
|
4
|
-
~15 singletons, file creation under the data dir). All of that now lives in
|
|
5
|
-
``latticeai.app_factory.create_app``. This module keeps every historical
|
|
6
|
-
module-level name (``app``, ``KNOWLEDGE_GRAPH``, ``load_users``,
|
|
7
|
-
``save_to_history``, …) importable for tests and legacy callers via module
|
|
8
|
-
``__getattr__`` — construction happens on *first attribute access*, never on
|
|
9
|
-
import. Importing ``latticeai.server_app`` has no side effects.
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
from __future__ import annotations
|
|
13
|
-
|
|
14
|
-
from typing import Any, List
|
|
15
|
-
|
|
16
|
-
from latticeai.runtime.namespace_runtime import SERVER_APP_EXPORTS
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def _runtime():
|
|
20
|
-
from latticeai.app_factory import get_shared_runtime
|
|
21
|
-
|
|
22
|
-
return get_shared_runtime()
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def __getattr__(name: str) -> Any:
|
|
26
|
-
if name.startswith("__") and name.endswith("__"):
|
|
27
|
-
# Never let dunder probes (importlib, inspect, pickling) trigger the
|
|
28
|
-
# full application construction.
|
|
29
|
-
raise AttributeError(name)
|
|
30
|
-
if name not in SERVER_APP_EXPORTS:
|
|
31
|
-
raise AttributeError(f"module 'latticeai.server_app' has no attribute '{name}'")
|
|
32
|
-
try:
|
|
33
|
-
return getattr(_runtime(), name)
|
|
34
|
-
except AttributeError as exc:
|
|
35
|
-
raise AttributeError(
|
|
36
|
-
f"module 'latticeai.server_app' has no attribute '{name}'"
|
|
37
|
-
) from exc
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def __dir__() -> List[str]:
|
|
41
|
-
return sorted(set(globals()) | set(SERVER_APP_EXPORTS))
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def main() -> None:
|
|
45
|
-
from latticeai.app_factory import main as _main
|
|
46
|
-
|
|
47
|
-
_main()
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if __name__ == "__main__":
|
|
51
|
-
main()
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
"""Application dependency context for router assembly.
|
|
2
|
-
|
|
3
|
-
``latticeai.app_factory.create_app`` builds one ``AppContext`` per app and
|
|
4
|
-
hands it to router factories, replacing the historical 25-30-kwarg closure
|
|
5
|
-
wiring. Every field defaults to ``None``-ish so tests can construct a context
|
|
6
|
-
carrying only the dependencies a router actually touches.
|
|
7
|
-
|
|
8
|
-
Fields are grouped by the consumer that motivated them; routers must treat the
|
|
9
|
-
context as read-only.
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
from __future__ import annotations
|
|
13
|
-
|
|
14
|
-
from dataclasses import dataclass
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
from typing import Any, Callable, Optional
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@dataclass(frozen=True)
|
|
20
|
-
class AppContext:
|
|
21
|
-
# ── core configuration / paths ────────────────────────────────────────
|
|
22
|
-
config: Any = None
|
|
23
|
-
data_dir: Optional[Path] = None
|
|
24
|
-
static_dir: Optional[Path] = None
|
|
25
|
-
base_dir: Optional[Path] = None
|
|
26
|
-
skills_dir: Optional[Path] = None
|
|
27
|
-
|
|
28
|
-
# ── singletons ────────────────────────────────────────────────────────
|
|
29
|
-
model_router: Any = None
|
|
30
|
-
workspace_store: Any = None
|
|
31
|
-
workspace_service: Any = None
|
|
32
|
-
knowledge_graph: Any = None
|
|
33
|
-
local_kg_watcher: Any = None
|
|
34
|
-
chat_service: Any = None
|
|
35
|
-
context_assembler: Any = None
|
|
36
|
-
# Re-search loop (v9.9.6): conversation-scoped ledger of just-written
|
|
37
|
-
# artifacts, so a follow-up turn sees them before indexing catches up.
|
|
38
|
-
artifact_ledger: Any = None
|
|
39
|
-
brain_memory: Any = None
|
|
40
|
-
# Unified ingestion gateway (lattice_brain.ingestion.IngestionPipeline);
|
|
41
|
-
# None when the knowledge graph is disabled.
|
|
42
|
-
ingestion_pipeline: Any = None
|
|
43
|
-
chat_agent_runtime: Any = None
|
|
44
|
-
gardener: Any = None
|
|
45
|
-
hooks: Any = None
|
|
46
|
-
realtime_bus: Any = None
|
|
47
|
-
capability_registry: Any = None
|
|
48
|
-
# UX funnel metrics (latticeai.services.funnel_metrics); None in tests
|
|
49
|
-
# that don't observe the funnel — every increment site is nil-safe.
|
|
50
|
-
funnel_metrics: Any = None
|
|
51
|
-
|
|
52
|
-
# ── auth / session callables ──────────────────────────────────────────
|
|
53
|
-
require_user: Optional[Callable[..., str]] = None
|
|
54
|
-
require_admin: Optional[Callable[..., tuple]] = None
|
|
55
|
-
get_current_user: Optional[Callable[..., Optional[str]]] = None
|
|
56
|
-
load_users: Optional[Callable[[], dict]] = None
|
|
57
|
-
get_user_role: Optional[Callable[..., str]] = None
|
|
58
|
-
enforce_rate_limit: Optional[Callable[..., None]] = None
|
|
59
|
-
allowed_workspaces_for: Optional[Callable[..., Any]] = None
|
|
60
|
-
|
|
61
|
-
# ── audit / history callables ─────────────────────────────────────────
|
|
62
|
-
append_audit_event: Optional[Callable[..., None]] = None
|
|
63
|
-
get_audit_log: Optional[Callable[[], list]] = None
|
|
64
|
-
get_history: Optional[Callable[[], list]] = None
|
|
65
|
-
get_history_user: Optional[Callable[..., dict]] = None
|
|
66
|
-
save_to_history: Optional[Callable[..., None]] = None
|
|
67
|
-
clear_history: Optional[Callable[..., dict]] = None
|
|
68
|
-
clear_conversation: Optional[Callable[..., dict]] = None
|
|
69
|
-
group_history_conversations: Optional[Callable[..., list]] = None
|
|
70
|
-
get_conversation_messages: Optional[Callable[..., list]] = None
|
|
71
|
-
conversation_title: Optional[Callable[..., str]] = None
|
|
72
|
-
|
|
73
|
-
# ── knowledge graph access ────────────────────────────────────────────
|
|
74
|
-
enable_graph: bool = False
|
|
75
|
-
require_graph: Optional[Callable[[], None]] = None
|
|
76
|
-
workspace_graph: Optional[Callable[[], Any]] = None
|
|
77
|
-
graph_stats: Optional[Callable[[], dict]] = None
|
|
78
|
-
|
|
79
|
-
# ── review center ─────────────────────────────────────────────────────
|
|
80
|
-
# ``ReviewQueueService``, reached through a provider like
|
|
81
|
-
# ``workspace_graph`` above: the queue is built in a later runtime phase
|
|
82
|
-
# than this context, so a value captured here would be ``None`` forever.
|
|
83
|
-
# Call it per request; ``None`` means no Review Center is wired (tests,
|
|
84
|
-
# headless helpers) and the callers stage nothing rather than writing.
|
|
85
|
-
review_queue: Optional[Callable[[], Any]] = None
|
|
86
|
-
|
|
87
|
-
# ── workspace payload providers / skills ──────────────────────────────
|
|
88
|
-
workspace_models: Optional[Callable[[], dict]] = None
|
|
89
|
-
workspace_settings: Optional[Callable[[], dict]] = None
|
|
90
|
-
scan_environment: Optional[Callable[[], Any]] = None
|
|
91
|
-
local_sysinfo: Optional[Callable[..., Any]] = None
|
|
92
|
-
get_recommendations: Optional[Callable[..., Any]] = None
|
|
93
|
-
fetch_skills_marketplace: Optional[Callable[..., Any]] = None
|
|
94
|
-
install_skill: Optional[Callable[..., Any]] = None
|
|
95
|
-
remove_skill_directory: Optional[Callable[..., dict]] = None
|
|
96
|
-
redact_secret_text: Optional[Callable[[str], str]] = None
|
|
97
|
-
ui_file_response: Optional[Callable[..., Any]] = None
|
|
98
|
-
|
|
99
|
-
# ── models ────────────────────────────────────────────────────────────
|
|
100
|
-
public_model: str = ""
|
|
101
|
-
local_model: str = ""
|
|
102
|
-
|
|
103
|
-
# ── integrations ──────────────────────────────────────────────────────
|
|
104
|
-
# Fired as on_chat_message(role, text, source) after a chat exchange is
|
|
105
|
-
# persisted; ``None`` means no external chat mirror is registered. The
|
|
106
|
-
# telegram bridge subscribes here only when ENABLE_TELEGRAM is truthy.
|
|
107
|
-
on_chat_message: Optional[Callable[..., None]] = None
|
|
108
|
-
|
|
109
|
-
def require(self, field: str) -> Any:
|
|
110
|
-
"""Return a dependency this router cannot operate without.
|
|
111
|
-
|
|
112
|
-
Every field defaults to ``None`` so a test can build a context holding
|
|
113
|
-
only what it exercises. A router that binds an absent dependency used
|
|
114
|
-
to discover it as ``TypeError: 'NoneType' object is not callable``
|
|
115
|
-
inside a request handler, far from the wiring mistake. Binding through
|
|
116
|
-
``require`` moves that to router construction with the field named.
|
|
117
|
-
|
|
118
|
-
It is also what makes the binding statically honest: the declared type
|
|
119
|
-
is ``Optional[...]``, so a type checker reports every call site as
|
|
120
|
-
``"None" not callable`` — 105 of them in the workspace router alone.
|
|
121
|
-
``require`` states the precondition once instead.
|
|
122
|
-
"""
|
|
123
|
-
if field not in self.__dataclass_fields__:
|
|
124
|
-
raise AttributeError(f"AppContext has no field {field!r}")
|
|
125
|
-
value = getattr(self, field)
|
|
126
|
-
if value is None:
|
|
127
|
-
raise RuntimeError(
|
|
128
|
-
f"AppContext.{field} is required by this router but was not provided"
|
|
129
|
-
)
|
|
130
|
-
return value
|