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
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
[](https://github.com/TaeSooPark-PTS/LatticeAI/actions/workflows/ci.yml)
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
|
|
14
|
-

|
|
15
15
|
|
|
16
16
|
Chat, files, folders, notes, and web pages all flow into one durable knowledge
|
|
17
17
|
graph on your computer. Any model — local MLX or cloud — can speak with that
|
|
@@ -24,10 +24,10 @@ memory. Nothing leaves your machine without explicit consent.
|
|
|
24
24
|
|
|
25
25
|
| | |
|
|
26
26
|
| --- | --- |
|
|
27
|
-
| **See your Brain's story in time** — a growth curve, an activity heatmap, and each day's story, rewindable to any past moment  | **Chat with a Brain that remembers** — every conversation grows durable, source-linked memory  |
|
|
28
|
+
| **See how knowledge connects** — a real relationship graph, not a file list  | **Capture anything** — files, whole folders, notes, screenshots, web pages  |
|
|
29
|
+
| **Automate with review** — agent changes become proposals you approve first  | **Pick a model in one click** — recommended local models for your hardware  |
|
|
30
|
+
| **Watch a file become memory** — three named steps, not a pipeline diagram  | **Say how much it may do alone** — one dial in plain words; dangerous actions stay blocked either way  |
|
|
31
31
|
|
|
32
32
|
## Why Lattice AI
|
|
33
33
|
|
|
@@ -58,103 +58,81 @@ First-run flow — wake the Brain, pick the owner, load a recommended model:
|
|
|
58
58
|
|
|
59
59
|
| | | |
|
|
60
60
|
| --- | --- | --- |
|
|
61
|
-
|  |  |  |
|
|
62
62
|
|
|
63
63
|
Screenshot index and capture notes:
|
|
64
|
-
[output/release/v11.
|
|
64
|
+
[output/release/v11.7.0/SCREENSHOT_INDEX.md](output/release/v11.7.0/SCREENSHOT_INDEX.md)
|
|
65
65
|
|
|
66
66
|
## Current Release
|
|
67
67
|
|
|
68
|
-
The current release is **11.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
(`
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
- **
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
`agent_profiles` helper goldens, 97 rows. The corpus stands at **251
|
|
123
|
-
golden files**.
|
|
124
|
-
- **The boundaries, stated plainly.** The native lanes are an
|
|
125
|
-
open-posture, single-local-owner surface (a closed or unknown posture
|
|
126
|
-
answers 401). The recent-chat context seam is still owned by the ad-hoc
|
|
127
|
-
prepends in `/chat` rather than the assembler — wiring it changes the
|
|
128
|
-
shape of a live prompt, which is a minor-release item, not something to
|
|
129
|
-
ship quietly here. `workspace_scope_from_request` itself remains
|
|
130
|
-
lenient for its two remaining callers. And the proxy hop deliberately
|
|
131
|
-
carries no request timeout: a blanket timeout would kill long-lived SSE.
|
|
132
|
-
|
|
133
|
-
The floor holds: **7,022 Python tests (11 skipped) at 100.00% statement
|
|
134
|
-
and branch coverage — 40,307 statements, 10,970 branches, `fail_under=100`
|
|
135
|
-
with the pragma budget untouched — 1,761 frontend tests across 101 files
|
|
136
|
-
at 100% on all four metrics, and 760 Rust workspace tests**, with the
|
|
137
|
-
OpenAPI schema regenerated at 421 paths and the whole suite re-verified in
|
|
138
|
-
a fresh-resolve Python 3.11 environment.
|
|
139
|
-
|
|
140
|
-
Release notes: [RELEASE.md](RELEASE.md) · Full history: [docs/CHANGELOG.md](docs/CHANGELOG.md)
|
|
141
|
-
|
|
142
|
-
Expected artifacts for 11.5.2 release must use exact filenames:
|
|
143
|
-
|
|
144
|
-
- `dist/ltcai-11.5.2-py3-none-any.whl`
|
|
145
|
-
- `dist/ltcai-11.5.2.tar.gz`
|
|
146
|
-
- `ltcai-11.5.2.tgz`
|
|
147
|
-
- `dist/ltcai-11.5.2.vsix`
|
|
148
|
-
- `src-tauri/target/release/bundle/dmg/Lattice AI_11.5.2_aarch64.dmg`
|
|
68
|
+
The current release is **11.7.0 — Clean Sweep**:
|
|
69
|
+
|
|
70
|
+
11.6.0 left a disclosed backlog and a visual language that still used
|
|
71
|
+
glass. This release closes that backlog, fixes regressions One Door did
|
|
72
|
+
not know it had shipped, and restyles every captured surface on an
|
|
73
|
+
elevation ladder — ink night, paper day, no glass. The door is unchanged:
|
|
74
|
+
`lattice-host` still serves **420 operations across 41 route families**,
|
|
75
|
+
and the Python package is still a **28-route AI worker** (LLM, embed,
|
|
76
|
+
extract, parse, four renderers, ASR, multimodal, catalog, `sysinfo`,
|
|
77
|
+
`/health`). The allowlist still includes `/worker/parse` and
|
|
78
|
+
`/worker/render/*`; nothing product-shaped moved back into Python.
|
|
79
|
+
|
|
80
|
+
- **The three oracle bugs 11.6.0 ported as-is are fixed.** Command-search
|
|
81
|
+
knowledge now reads `matches` and returns nodes. Review snooze accepts
|
|
82
|
+
offset-aware datetimes (unparseable `until` → 422). Double-reject is
|
|
83
|
+
409, byte-identical to its dismiss sibling. Fixture bodies that pinned
|
|
84
|
+
the old faults were updated and marked as divergences from the oracle.
|
|
85
|
+
- **The §5.3 holes are closed.** Binary uploads go through `/worker/parse`.
|
|
86
|
+
Per-chunk supplied vectors land at the four ingest doors. User hooks
|
|
87
|
+
fire on native tools (`HooksStore` → `HookSink`) and write the same run
|
|
88
|
+
log the HTTP route writes. `sanitize_write_content` runs on the loop
|
|
89
|
+
path and on `POST /tools/write_file`. Every mutating review route records
|
|
90
|
+
`review_item_created` / `review_item_updated`. `workspace_os.json` has
|
|
91
|
+
one writer (`WorkspaceOsStore` + registry + ports).
|
|
92
|
+
- **Regressions One Door did not know it had.** Self-Model writes were
|
|
93
|
+
100% dead (five routes posted into the retired `/worker/graph/mutate`;
|
|
94
|
+
`resolve_contradiction` claimed "applied" while writing nothing) —
|
|
95
|
+
restored natively, nine recorded bodies byte-identical. The security
|
|
96
|
+
xlsx export 502'd because it posted to a product route; it now uses
|
|
97
|
+
`/worker/render/xlsx`. Chat `ingest_generated` was a schema 400 even
|
|
98
|
+
against a live 11.5.2 worker. Vault-watch had fixtures and no poller —
|
|
99
|
+
it is a real native ingest loop now. A decoy-proven static gate keeps
|
|
100
|
+
this class from shipping again.
|
|
101
|
+
- **Time bombs defused.** Chronicle `@today`, briefing freshness, and the
|
|
102
|
+
insights/garden/proactive/health/quality cutoffs now take a frozen
|
|
103
|
+
clock. Falsifier tests fail on the next run if a fuse is re-armed.
|
|
104
|
+
- **The UI is one language.** Token-native elevation and gradients replace
|
|
105
|
+
backdrop-filter. Cytoscape reads theme tokens (comma-form `hsl()`).
|
|
106
|
+
Layout and a11y contracts stay; the first-paint bundle is still ~103 KiB
|
|
107
|
+
gzip.
|
|
108
|
+
|
|
109
|
+
What this release still carries openly — `open_keys` pending-only, no
|
|
110
|
+
extraction refiner, `delete_node` leaving `PART_OF`, review events silent
|
|
111
|
+
without an owner, text-only KG-api ingest, two store cycles per review
|
|
112
|
+
mutation, raw-English snooze 422 — is listed in
|
|
113
|
+
[RELEASE_NOTES_v11.7.0.md](RELEASE_NOTES_v11.7.0.md).
|
|
114
|
+
|
|
115
|
+
Expected artifacts for 11.7.0 release must use exact filenames:
|
|
116
|
+
|
|
117
|
+
- `dist/ltcai-11.7.0-py3-none-any.whl`
|
|
118
|
+
- `dist/ltcai-11.7.0.tar.gz`
|
|
119
|
+
- `ltcai-11.7.0.tgz`
|
|
120
|
+
- `dist/ltcai-11.7.0.vsix`
|
|
121
|
+
- `src-tauri/target/release/bundle/dmg/Lattice AI_11.7.0_aarch64.dmg`
|
|
149
122
|
|
|
150
123
|
Do not use wildcard artifact uploads. Package registry publishing remains owner-run.
|
|
151
124
|
|
|
125
|
+
Release notes: [RELEASE.md](RELEASE.md) · Full history: [docs/CHANGELOG.md](docs/CHANGELOG.md)
|
|
126
|
+
|
|
152
127
|
## Architecture At A Glance
|
|
153
128
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
129
|
+
One Rust server on localhost is the source of truth: `lattice-host` answers
|
|
130
|
+
every product route, owns every write to the Brain, and supervises a Python
|
|
131
|
+
**AI worker** it reaches over loopback for the things a model does — inference,
|
|
132
|
+
embedding, extraction, parsing, rendering, speech-to-text. The React/Vite
|
|
133
|
+
frontend and the Tauri desktop shell sit on top of that one door. Local-first
|
|
134
|
+
by default — cloud model calls, downloads, Brain Network, and update checks are
|
|
135
|
+
opt-in.
|
|
158
136
|
|
|
159
137
|
See [ARCHITECTURE.md](ARCHITECTURE.md) for details and
|
|
160
138
|
[docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for the developer workflow
|
|
@@ -164,22 +142,38 @@ See [ARCHITECTURE.md](ARCHITECTURE.md) for details and
|
|
|
164
142
|
## Known Limitations
|
|
165
143
|
|
|
166
144
|
- External package registries are owner-published and can lag behind GitHub.
|
|
167
|
-
-
|
|
168
|
-
|
|
169
|
-
- Docker, model downloads, cloud model calls,
|
|
170
|
-
|
|
145
|
+
- SQLite is the live local Brain store. The optional PostgreSQL/pgvector
|
|
146
|
+
migration tooling is not part of the 11.6.0 worker.
|
|
147
|
+
- Docker, model downloads, cloud model calls, Brain Network, and update checks
|
|
148
|
+
require explicit user action.
|
|
149
|
+
- **The Telegram bridge was removed in 11.6.0** — it lived in the platform code
|
|
150
|
+
that became the AI worker. **SSO/OIDC login and callback flows were removed
|
|
151
|
+
with it**; the configuration surface remains and password login is native.
|
|
171
152
|
- Conversation does not fabricate answers when no model is loaded. Agent and
|
|
172
153
|
workflow simulation without a loaded LLM is deterministic and LLM-free (it
|
|
173
154
|
does not call a model) — labeled as such, never presented as autonomous
|
|
174
155
|
model success.
|
|
175
|
-
-
|
|
176
|
-
|
|
177
|
-
|
|
156
|
+
- `POST /worker/render/pdf` ships working out of the box: `reportlab` is a
|
|
157
|
+
required dependency as of 11.6.0 (it used to be an undeclared lazy import
|
|
158
|
+
that raised a 500; `ltcai[pdf]` remains as an empty alias for older
|
|
159
|
+
install instructions).
|
|
160
|
+
- Pointer-control tools still execute in the worker. Remaining honest gaps
|
|
161
|
+
(`open_keys` pending-only, no Self-Model refiner, `PART_OF` left on
|
|
162
|
+
delete, review events silent without an owner, KG-api ingest text-only,
|
|
163
|
+
two store cycles per review mutation) are listed with their reasons in
|
|
164
|
+
[RELEASE_NOTES_v11.7.0.md](RELEASE_NOTES_v11.7.0.md).
|
|
178
165
|
|
|
179
166
|
## Release History
|
|
180
167
|
|
|
168
|
+
Public history starts at 11.0.0. 11.6.0 rebuilt the product server in Rust and
|
|
169
|
+
reduced the Python package to an AI worker, so a 10.x or 9.x install is a
|
|
170
|
+
different program; `SECURITY.md` supports only 11.x, and this table states the
|
|
171
|
+
same boundary. Earlier notes stay in the tree as `RELEASE_NOTES_v*.md` files.
|
|
172
|
+
|
|
181
173
|
| Version | Theme |
|
|
182
174
|
| --- | --- |
|
|
175
|
+
| 11.7.0 | Clean Sweep |
|
|
176
|
+
| 11.6.0 | One Door |
|
|
183
177
|
| 11.5.2 | Tight Ship |
|
|
184
178
|
| 11.5.1 | Rust Full Loop |
|
|
185
179
|
| 11.5.0 | Rust Complete |
|
|
@@ -189,54 +183,5 @@ See [ARCHITECTURE.md](ARCHITECTURE.md) for details and
|
|
|
189
183
|
| 11.1.0 | Product Intelligence |
|
|
190
184
|
| 11.0.1 | Both Branches |
|
|
191
185
|
| 11.0.0 | Full Measure |
|
|
192
|
-
| 10.10.0 | Quiet Station |
|
|
193
|
-
| 10.9.0 | Never Blocks |
|
|
194
|
-
| 10.8.0 | Within Reach |
|
|
195
|
-
| 10.7.0 | Plain Surface |
|
|
196
|
-
| 10.6.4 | Loud Limits |
|
|
197
|
-
| 10.6.3 | Loud Limits |
|
|
198
|
-
| 10.6.2 | Ask First |
|
|
199
|
-
| 10.6.1 | First Things |
|
|
200
|
-
| 10.6.0 | Promoted Panels |
|
|
201
|
-
| 10.5.0 | Everyday Words |
|
|
202
|
-
| 10.4.0 | Named Ground |
|
|
203
|
-
| 10.3.0 | Measured Ground |
|
|
204
|
-
| 10.2.0 | Load-Bearing Fixes |
|
|
205
|
-
| 10.1.1 | Reachable Boundary |
|
|
206
|
-
| 10.1.0 | Hybrid Brain |
|
|
207
|
-
| 10.0.1 | One Source of Truth |
|
|
208
|
-
| 10.0.0 | Plain Language |
|
|
209
|
-
| 9.9.9 | Lean Shell |
|
|
210
|
-
| 9.9.8 | Autonomy Dial |
|
|
211
|
-
| 9.9.7 | No Gaps Left |
|
|
212
|
-
| 9.9.6 | Same Brain Everywhere |
|
|
213
|
-
| 9.9.5 | Closed Gaps |
|
|
214
|
-
| 9.9.4 | Durable Loops |
|
|
215
|
-
| 9.9.3 | Closed Loops |
|
|
216
|
-
| 9.9.2 | Artifact Trust |
|
|
217
|
-
| 9.9.1 | Clean Foundations |
|
|
218
|
-
| 9.9.0 | Fail-Closed Trust |
|
|
219
|
-
| 9.8.0 | Honest Knowledge Pipeline |
|
|
220
|
-
| 9.7.0 | Proactive Hybrid Brain |
|
|
221
|
-
| 9.6.0 | Trusted Agent Loop |
|
|
222
|
-
| 9.5.0 | Command Center |
|
|
223
|
-
| 9.4.0 | Question-Driven Everyday Automation |
|
|
224
|
-
| 9.3.0 | Proactive Brain Intelligence |
|
|
225
|
-
| 9.2.0 | Model-Agnostic File Generation |
|
|
226
|
-
| 9.1.0 | Code Review Completion & Fail-Closed Runtime |
|
|
227
|
-
| 9.0.0 | Code Review Closure & Runtime Cleanup |
|
|
228
186
|
|
|
229
187
|
Per-release details: [RELEASE_NOTES.md](RELEASE_NOTES.md)
|
|
230
|
-
|
|
231
|
-
## Documentation
|
|
232
|
-
|
|
233
|
-
- [docs/WHY_LATTICE.md](docs/WHY_LATTICE.md) — product philosophy
|
|
234
|
-
- [docs/TRUST_MODEL.md](docs/TRUST_MODEL.md) — local-first trust model
|
|
235
|
-
- [PRIVACY.md](PRIVACY.md) — privacy and external communication policy
|
|
236
|
-
- [FEATURE_STATUS.md](FEATURE_STATUS.md) — feature status and limitations
|
|
237
|
-
- [SECURITY.md](SECURITY.md) — security posture
|
|
238
|
-
- [RELEASE.md](RELEASE.md) — release guide and notes
|
|
239
|
-
|
|
240
|
-
## License
|
|
241
|
-
|
|
242
|
-
MIT. See [LICENSE](LICENSE).
|
package/bin/ltcai.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { spawn } = require("node:child_process");
|
|
4
|
-
const { spawnSync } = require("node:child_process");
|
|
3
|
+
const { spawn, spawnSync } = require("node:child_process");
|
|
5
4
|
const fs = require("node:fs");
|
|
6
5
|
const os = require("node:os");
|
|
7
6
|
const path = require("node:path");
|
|
@@ -11,6 +10,34 @@ const managedVenv = process.env.LTCAI_NPM_VENV || path.join(os.homedir(), ".ltca
|
|
|
11
10
|
const managedPython = process.platform === "win32"
|
|
12
11
|
? path.join(managedVenv, "Scripts", "python.exe")
|
|
13
12
|
: path.join(managedVenv, "bin", "python");
|
|
13
|
+
const hostName = process.platform === "win32" ? "lattice-host.exe" : "lattice-host";
|
|
14
|
+
const WORKER_MODULE = "latticeai.worker_app";
|
|
15
|
+
// Mirrors rust/lattice-host/src/supervisor/command.rs::WORKER_FACTORY — the
|
|
16
|
+
// supervisor appends `--host`/`--port` itself, so this is the whole of what a
|
|
17
|
+
// launcher can name.
|
|
18
|
+
const WORKER_FACTORY = `-m uvicorn ${WORKER_MODULE}:create_worker_app --factory`;
|
|
19
|
+
|
|
20
|
+
const USAGE = `\
|
|
21
|
+
ltcai — Lattice AI front door (lattice-host)
|
|
22
|
+
|
|
23
|
+
USAGE:
|
|
24
|
+
ltcai [OPTIONS]
|
|
25
|
+
ltcai doctor
|
|
26
|
+
|
|
27
|
+
OPTIONS:
|
|
28
|
+
--host <HOST> Bind hint (sets LATTICEAI_HOST). lattice-host listens on 127.0.0.1
|
|
29
|
+
--port <PORT> Gateway port (default: LATTICEAI_PORT, then 4825)
|
|
30
|
+
--worker-port <PORT> Pin the worker port instead of scanning
|
|
31
|
+
--no-spawn Do not start a worker; front an existing one
|
|
32
|
+
--no-jobs Mount /host/jobs but never run the timer
|
|
33
|
+
-h, --help Print this help
|
|
34
|
+
-V, --version Print the version
|
|
35
|
+
|
|
36
|
+
lattice-host is the only front door. It supervises the Python AI worker
|
|
37
|
+
(\`python ${WORKER_FACTORY}\`, with the port it chose).
|
|
38
|
+
LATTICEAI_* environment variables are passed through. Pin the host binary with
|
|
39
|
+
LATTICEAI_HOST_BIN or LTCAI_HOST, and the worker interpreter with LTCAI_PYTHON.
|
|
40
|
+
`;
|
|
14
41
|
|
|
15
42
|
function loadDotEnv(file) {
|
|
16
43
|
if (!fs.existsSync(file)) return;
|
|
@@ -61,7 +88,7 @@ function ensureManagedPython() {
|
|
|
61
88
|
if (!canImport(managedPython, "fastapi")) {
|
|
62
89
|
const requirements = path.join(root, "requirements.txt");
|
|
63
90
|
if (!fs.existsSync(requirements)) {
|
|
64
|
-
console.error(`[LTCAI] Missing ${requirements}. The npm package is incomplete and cannot start the Python
|
|
91
|
+
console.error(`[LTCAI] Missing ${requirements}. The npm package is incomplete and cannot start the Python worker.`);
|
|
65
92
|
process.exit(1);
|
|
66
93
|
}
|
|
67
94
|
console.log("[LTCAI] Installing Python dependencies. This can take a few minutes on first run.");
|
|
@@ -72,34 +99,217 @@ function ensureManagedPython() {
|
|
|
72
99
|
return managedPython;
|
|
73
100
|
}
|
|
74
101
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
102
|
+
function pythonCandidates(includeManaged) {
|
|
103
|
+
return [
|
|
104
|
+
process.env.LTCAI_PYTHON,
|
|
105
|
+
includeManaged ? ensureManagedPython() : managedPython,
|
|
106
|
+
path.join(root, ".venv", "bin", "python"),
|
|
107
|
+
path.join(root, "venv", "bin", "python"),
|
|
108
|
+
process.platform === "win32" ? path.join(root, ".venv", "Scripts", "python.exe") : null,
|
|
109
|
+
process.env.PYTHON,
|
|
110
|
+
"python3",
|
|
111
|
+
"python",
|
|
112
|
+
].filter(Boolean);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function resolveWorkerPython(bootstrap) {
|
|
116
|
+
for (const python of pythonCandidates(bootstrap)) {
|
|
117
|
+
if (canImport(python, WORKER_MODULE)) return python;
|
|
118
|
+
}
|
|
119
|
+
return pythonCandidates(bootstrap)[0] || "python3";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function whichHost() {
|
|
123
|
+
const tool = process.platform === "win32" ? "where" : "which";
|
|
124
|
+
const result = spawnSync(tool, ["lattice-host"], { encoding: "utf8" });
|
|
125
|
+
if (result.status !== 0) return null;
|
|
126
|
+
const found = String(result.stdout || "").split(/\r?\n/).map((line) => line.trim()).find(Boolean);
|
|
127
|
+
return found && fs.existsSync(found) ? found : null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function existingHostBinary() {
|
|
131
|
+
const pinned = process.env.LATTICEAI_HOST_BIN || process.env.LTCAI_HOST;
|
|
132
|
+
if (pinned && fs.existsSync(pinned)) return pinned;
|
|
133
|
+
const candidates = [
|
|
134
|
+
path.join(root, "rust", "target", "release", hostName),
|
|
135
|
+
path.join(root, "rust", "target", "debug", hostName),
|
|
136
|
+
path.join(root, "src-tauri", "target", "release", hostName),
|
|
137
|
+
path.join(root, "src-tauri", "target", "debug", hostName),
|
|
138
|
+
];
|
|
139
|
+
for (const candidate of candidates) {
|
|
140
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
141
|
+
}
|
|
142
|
+
return whichHost();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function ensureHostBinary() {
|
|
146
|
+
const existing = existingHostBinary();
|
|
147
|
+
if (existing) return existing;
|
|
148
|
+
if (process.env.LTCAI_SKIP_HOST_BUILD === "1") {
|
|
149
|
+
console.error("[LTCAI] lattice-host binary not found and LTCAI_SKIP_HOST_BUILD=1.");
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
const manifest = path.join(root, "rust", "Cargo.toml");
|
|
153
|
+
if (!fs.existsSync(manifest)) {
|
|
154
|
+
console.error("[LTCAI] lattice-host binary not found and rust/ workspace is missing.");
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
console.log("[LTCAI] Building lattice-host (cargo build -p lattice-host)...");
|
|
158
|
+
if (!runSync("cargo", ["build", "-p", "lattice-host"], { cwd: path.join(root, "rust") })) {
|
|
159
|
+
console.error("[LTCAI] cargo build -p lattice-host failed.");
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
const built = path.join(root, "rust", "target", "debug", hostName);
|
|
163
|
+
if (!fs.existsSync(built)) {
|
|
164
|
+
console.error(`[LTCAI] build succeeded but ${built} is missing.`);
|
|
90
165
|
process.exit(1);
|
|
91
166
|
}
|
|
167
|
+
return built;
|
|
168
|
+
}
|
|
92
169
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
170
|
+
function parseArgs(argv) {
|
|
171
|
+
const parsed = {
|
|
172
|
+
help: false,
|
|
173
|
+
version: false,
|
|
174
|
+
doctor: false,
|
|
175
|
+
host: null,
|
|
176
|
+
port: null,
|
|
177
|
+
hostArgs: [],
|
|
178
|
+
};
|
|
179
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
180
|
+
const arg = argv[i];
|
|
181
|
+
if (arg === "doctor") {
|
|
182
|
+
parsed.doctor = true;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (arg === "-h" || arg === "--help") {
|
|
186
|
+
parsed.help = true;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (arg === "-V" || arg === "--version") {
|
|
190
|
+
parsed.version = true;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (arg === "--host" || arg.startsWith("--host=")) {
|
|
194
|
+
parsed.host = arg === "--host" ? argv[++i] : arg.slice("--host=".length);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (arg === "--port" || arg.startsWith("--port=")) {
|
|
198
|
+
parsed.port = arg === "--port" ? argv[++i] : arg.slice("--port=".length);
|
|
199
|
+
if (parsed.port) parsed.hostArgs.push("--port", parsed.port);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (arg === "--reload" || arg === "--tunnel") {
|
|
203
|
+
console.error(`[LTCAI] ${arg} is not supported on the lattice-host front door.`);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
parsed.hostArgs.push(arg);
|
|
207
|
+
}
|
|
208
|
+
return parsed;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* The interpreter, as an absolute path.
|
|
213
|
+
*
|
|
214
|
+
* `lattice-host` spawns the worker with `PATH` prefixed by
|
|
215
|
+
* `/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`
|
|
216
|
+
* (supervisor/worker_env.rs — GUI processes inherit a minimal PATH), so a bare
|
|
217
|
+
* `python3` is looked up against a different PATH than the one this launcher
|
|
218
|
+
* validated it on and can land on an interpreter with none of the deps.
|
|
219
|
+
* `sys.executable` is what keeps it the same interpreter on both sides.
|
|
220
|
+
*/
|
|
221
|
+
function absoluteInterpreter(python) {
|
|
222
|
+
const probe = spawnSync(python, ["-c", "import sys; print(sys.executable)"], { encoding: "utf8" });
|
|
223
|
+
const resolved = probe.status === 0 ? String(probe.stdout || "").trim() : "";
|
|
224
|
+
return resolved && fs.existsSync(resolved) ? resolved : python;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Tell the supervisor *which interpreter*, and let it build the command.
|
|
229
|
+
*
|
|
230
|
+
* This used to pin `LATTICEAI_DESKTOP_BACKEND_CMD = "<python> -m
|
|
231
|
+
* latticeai.worker_app"`, and that command serves nothing: `worker_app` exports
|
|
232
|
+
* `main()` but has no `if __name__ == "__main__"` guard, so the module form
|
|
233
|
+
* imports and exits 0 without binding a port — the supervisor restarts it,
|
|
234
|
+
* forever, and the front door answers 502 on every proxied route.
|
|
235
|
+
*
|
|
236
|
+
* The fix is not to pin the uvicorn string instead. `LATTICEAI_DESKTOP_BACKEND_CMD`
|
|
237
|
+
* is the supervisor's rule 1, whose args are passed **verbatim**; `--host` and
|
|
238
|
+
* `--port` are appended only by the module rules (`command.rs::module_args`),
|
|
239
|
+
* and the worker port is chosen at runtime by a free-port scan. A statically
|
|
240
|
+
* pinned `-m uvicorn … --factory` would therefore bind uvicorn's default 8000
|
|
241
|
+
* while the supervisor health-probes the port it actually picked.
|
|
242
|
+
*
|
|
243
|
+
* So pin the input the launcher genuinely knows — the interpreter — and let
|
|
244
|
+
* rule 2 produce its own canonical command (`command.rs::WORKER_FACTORY`):
|
|
245
|
+
* `<python> -m uvicorn latticeai.worker_app:create_worker_app --factory --host
|
|
246
|
+
* 127.0.0.1 --port <chosen>`. An explicit `LATTICEAI_DESKTOP_BACKEND_CMD` from
|
|
247
|
+
* the caller still wins, untouched.
|
|
248
|
+
*/
|
|
249
|
+
function pinWorkerInterpreter() {
|
|
250
|
+
if (process.env.LATTICEAI_DESKTOP_BACKEND_CMD) return;
|
|
251
|
+
process.env.LTCAI_PYTHON = absoluteInterpreter(resolveWorkerPython(true));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function doctor() {
|
|
255
|
+
let ok = true;
|
|
256
|
+
const host = existingHostBinary();
|
|
257
|
+
if (host) {
|
|
258
|
+
console.log(`[OK] lattice-host: ${host}`);
|
|
259
|
+
} else {
|
|
260
|
+
console.log("[MISS] lattice-host: not built (run without doctor to cargo-build it)");
|
|
261
|
+
ok = false;
|
|
262
|
+
}
|
|
263
|
+
const python = absoluteInterpreter(resolveWorkerPython(false));
|
|
264
|
+
if (canImport(python, WORKER_MODULE)) {
|
|
265
|
+
console.log(`[OK] worker: ${python} ${WORKER_FACTORY}`);
|
|
266
|
+
} else {
|
|
267
|
+
console.log(`[MISS] worker: cannot import ${WORKER_MODULE} (${python})`);
|
|
268
|
+
ok = false;
|
|
269
|
+
}
|
|
270
|
+
process.exit(ok ? 0 : 1);
|
|
271
|
+
}
|
|
97
272
|
|
|
98
|
-
|
|
273
|
+
function launchHost(bin, args) {
|
|
274
|
+
const child = spawn(bin, args, { cwd: root, stdio: "inherit" });
|
|
275
|
+
child.on("error", (err) => {
|
|
276
|
+
console.error(`[LTCAI] failed to launch lattice-host (${bin}): ${err.message}`);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
});
|
|
99
279
|
child.on("exit", (code, signal) => {
|
|
100
280
|
if (signal) process.kill(process.pid, signal);
|
|
101
281
|
process.exit(code ?? 0);
|
|
102
282
|
});
|
|
103
283
|
}
|
|
104
284
|
|
|
105
|
-
|
|
285
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
286
|
+
|
|
287
|
+
if (parsed.help) {
|
|
288
|
+
process.stdout.write(USAGE);
|
|
289
|
+
const host = existingHostBinary();
|
|
290
|
+
if (host) {
|
|
291
|
+
process.stdout.write("\n");
|
|
292
|
+
spawnSync(host, ["--help"], { stdio: "inherit" });
|
|
293
|
+
}
|
|
294
|
+
process.exit(0);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (parsed.version) {
|
|
298
|
+
const host = existingHostBinary();
|
|
299
|
+
if (host) {
|
|
300
|
+
spawnSync(host, ["--version"], { stdio: "inherit" });
|
|
301
|
+
} else {
|
|
302
|
+
console.log("ltcai (lattice-host front door)");
|
|
303
|
+
}
|
|
304
|
+
process.exit(0);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (parsed.doctor) {
|
|
308
|
+
doctor();
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (parsed.host) process.env.LATTICEAI_HOST = parsed.host;
|
|
312
|
+
if (parsed.port) process.env.LATTICEAI_PORT = parsed.port;
|
|
313
|
+
|
|
314
|
+
pinWorkerInterpreter();
|
|
315
|
+
launchHost(ensureHostBinary(), parsed.hostArgs);
|