ltcai 11.5.2 → 11.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -148
- package/bin/ltcai.js +234 -24
- package/docs/CHANGELOG.md +119 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +8 -6
- package/docs/ENTERPRISE.md +2 -1
- package/docs/MULTI_AGENT_RUNTIME.md +12 -5
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +6 -3
- package/docs/REALTIME_COLLABORATION.md +1 -1
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/WORKFLOW_DESIGNER.md +3 -2
- package/docs/kg-schema.md +1 -1
- package/docs/v11.6.0_ONE_DOOR_PLAN.md +170 -0
- package/lattice_brain/__init__.py +42 -79
- package/lattice_brain/graph/__init__.py +9 -24
- package/lattice_brain/graph/_kg_common/__init__.py +13 -24
- package/lattice_brain/ingestion/__init__.py +19 -58
- package/lattice_brain/ingestion/pipeline.py +20 -398
- package/lattice_brain/multimodal/__init__.py +7 -18
- package/lattice_brain/multimodal/images.py +6 -264
- package/lattice_brain/multimodal/video.py +8 -247
- package/lattice_brain/runtime/__init__.py +8 -79
- package/lattice_brain/runtime/hooks.py +22 -584
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/agent_worker_seam.py +7 -80
- package/latticeai/api/health.py +6 -20
- package/latticeai/api/local_files.py +16 -613
- package/latticeai/api/models.py +12 -87
- package/latticeai/api/search.py +17 -255
- package/latticeai/api/tools.py +69 -750
- package/latticeai/api/voice_capture.py +8 -70
- package/latticeai/api/worker_compute.py +842 -0
- package/latticeai/api/worker_seams.py +216 -0
- package/latticeai/app_factory.py +23 -232
- package/latticeai/cli/entrypoint.py +36 -249
- package/latticeai/core/agent_permission.py +16 -91
- package/latticeai/core/messages.py +89 -531
- package/latticeai/runtime/access_runtime.py +0 -14
- package/latticeai/runtime/bootstrap.py +10 -21
- package/latticeai/runtime/brain_runtime.py +35 -43
- package/latticeai/runtime/build_phases/__init__.py +21 -37
- package/latticeai/runtime/build_phases/features.py +99 -389
- package/latticeai/runtime/build_phases/foundation.py +82 -392
- package/latticeai/runtime/build_phases/web.py +91 -408
- package/latticeai/runtime/build_phases/worker_profile.py +244 -0
- package/latticeai/runtime/lifespan_runtime.py +7 -16
- package/latticeai/runtime/platform_services_runtime.py +1 -15
- package/latticeai/runtime/runtime_context.py +13 -130
- package/latticeai/runtime/security_runtime.py +10 -103
- package/latticeai/services/architecture_readiness.py +82 -43
- package/latticeai/services/model_runtime/__init__.py +2 -11
- package/latticeai/services/model_runtime/service.py +4 -28
- package/latticeai/services/p_reinforce.py +10 -261
- package/latticeai/services/product_readiness.py +31 -38
- package/latticeai/services/search_service.py +37 -795
- package/latticeai/services/tool_dispatch.py +30 -386
- package/latticeai/services/voice_capture.py +13 -107
- package/latticeai/tools/__init__.py +22 -49
- package/latticeai/tools/commands.py +0 -163
- package/latticeai/tools/computer.py +0 -39
- package/latticeai/tools/documents.py +1 -134
- package/latticeai/tools/filesystem.py +1 -247
- package/latticeai/tools/knowledge.py +1 -52
- package/latticeai/tools/local_files.py +0 -20
- package/latticeai/worker_app.py +75 -0
- package/package.json +2 -3
- package/requirements.txt +0 -5
- package/scripts/agent_eval.py +16 -28
- package/scripts/brain_quality_eval.py +20 -183
- package/scripts/bump_version.py +5 -5
- package/scripts/check_current_release_docs.mjs +7 -4
- package/scripts/check_openapi_drift.mjs +10 -0
- package/scripts/check_server_i18n.mjs +2 -18
- package/scripts/compose_openapi.py +377 -0
- package/scripts/export_openapi.py +32 -4
- package/scripts/gen_messages_catalog_fixture.py +302 -0
- package/scripts/gen_openapi_fragments.py +365 -0
- package/scripts/gen_redact_fixture.py +196 -0
- package/scripts/gen_worker_allowlist_fixture.py +115 -0
- package/scripts/generate_agent_parity_fixtures.py +33 -14
- package/scripts/openapi_route_families.json +2161 -0
- package/scripts/release_screen_claims.json +54 -0
- package/scripts/run_integration_tests.mjs +134 -29
- package/scripts/run_sidecar_e2e.mjs +104 -11
- package/scripts/wheel_smoke.py +32 -22
- package/src-tauri/Cargo.lock +375 -9
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/src/backend.rs +151 -45
- package/src-tauri/src/main.rs +18 -18
- package/src-tauri/src/topology.rs +58 -88
- package/src-tauri/tauri.conf.json +1 -2
- package/static/app/asset-manifest.json +41 -41
- package/static/app/assets/{Act-DcQizkl1.js → Act-BPcVAbOL.js} +1 -1
- package/static/app/assets/AdminConsole-Bw1ATQL0.js +1 -0
- package/static/app/assets/{Brain-3VCSHFcn.js → Brain-CT92Kos0.js} +2 -2
- package/static/app/assets/{BrainHome-Qm8eaztx.js → BrainHome-CFBkt1K_.js} +1 -1
- package/static/app/assets/{BrainSignals-DS9BtKOW.js → BrainSignals-ReLWF2H8.js} +1 -1
- package/static/app/assets/Capture-BsTokYkk.js +1 -0
- package/static/app/assets/{Chronicle-BGvuAchH.js → Chronicle-B6f0T9id.js} +1 -1
- package/static/app/assets/{CommandPalette-Bqhm0Urn.js → CommandPalette-CuvjTv1u.js} +1 -1
- package/static/app/assets/{Library-BV6NnF0a.js → Library-BGJbG9Hd.js} +1 -1
- package/static/app/assets/{LivingBrain-GzenJchP.js → LivingBrain-DGYK_Jsa.js} +1 -1
- package/static/app/assets/{ProductFlow-DEP6-vML.js → ProductFlow-DXBC6brE.js} +1 -1
- package/static/app/assets/{ReviewCard-CNZ7XjWG.js → ReviewCard-HXRle3qq.js} +2 -2
- package/static/app/assets/System-CMHSO9qM.js +1 -0
- package/static/app/assets/arrow-left-BfmkskWx.js +1 -0
- package/static/app/assets/{bot-B_K1Tdmw.js → bot-Cn8bWRuq.js} +1 -1
- package/static/app/assets/{brain-DWyaV1L1.js → brain-CQJberbE.js} +1 -1
- package/static/app/assets/{button-aTn4s84A.js → button-Ct9f2_oT.js} +1 -1
- package/static/app/assets/circle-check-DruOxB-4.js +1 -0
- package/static/app/assets/{circle-pause-xKgeGXkT.js → circle-pause-CmzC_apg.js} +1 -1
- package/static/app/assets/{circle-play-DkT6tYPX.js → circle-play-D8mW2aQ7.js} +1 -1
- package/static/app/assets/{cpu-85xYObUC.js → cpu-DZcdd0PZ.js} +1 -1
- package/static/app/assets/{download-B5Fm7YXo.js → download-bv1KEPGQ.js} +1 -1
- package/static/app/assets/{folder-open-kk2Xa52u.js → folder-open-d-Pip5gr.js} +1 -1
- package/static/app/assets/{hard-drive-DkA3zBW_.js → hard-drive-D20iavUb.js} +1 -1
- package/static/app/assets/index-D9x-kSNy.css +2 -0
- package/static/app/assets/{index-BMPdTmlY.js → index-Do83hDzJ.js} +3 -3
- package/static/app/assets/{input-B0nRf2jO.js → input-BLXVNmj1.js} +1 -1
- package/static/app/assets/{link-2-Dwb4gnTc.js → link-2-BPJOFlAy.js} +1 -1
- package/static/app/assets/{permissionCopy-CQDUBrOZ.js → permissionCopy-ChdJd493.js} +1 -1
- package/static/app/assets/primitives-Cv5tbZBY.js +1 -0
- package/static/app/assets/search-CT9aho2j.js +1 -0
- package/static/app/assets/{share-2-BsrxFglO.js → share-2-YNX_NtMU.js} +1 -1
- package/static/app/assets/{shield-alert-5BStfp2_.js → shield-alert-DuQ3zrVL.js} +1 -1
- package/static/app/assets/{textarea-Cg8IUA-k.js → textarea-DqwLnli4.js} +1 -1
- package/static/app/assets/{useFocusTrap-CYKvE46M.js → useFocusTrap-ZVI98jaW.js} +1 -1
- package/static/app/assets/{useMutation-CSn9t1op.js → useMutation-CVC4qv_D.js} +1 -1
- package/static/app/assets/{useQuery-CY2OI2uy.js → useQuery-C7BeG4HU.js} +1 -1
- package/static/app/assets/{utils-Ddol2RWD.js → utils-CiFtIdZq.js} +1 -1
- package/static/app/assets/{workspace-BqDwOz_p.js → workspace-DQz9vIId.js} +1 -1
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/lattice_brain/archive.py +0 -522
- package/lattice_brain/context.py +0 -325
- package/lattice_brain/conversations.py +0 -382
- package/lattice_brain/core.py +0 -82
- package/lattice_brain/graph/_kg_contract.py +0 -249
- package/lattice_brain/graph/curator.py +0 -676
- package/lattice_brain/graph/discovery.py +0 -595
- package/lattice_brain/graph/discovery_index/__init__.py +0 -35
- package/lattice_brain/graph/discovery_index/cleanup.py +0 -182
- package/lattice_brain/graph/discovery_index/extract.py +0 -137
- package/lattice_brain/graph/discovery_index/scan.py +0 -411
- package/lattice_brain/graph/discovery_index/upsert.py +0 -495
- package/lattice_brain/graph/documents.py +0 -380
- package/lattice_brain/graph/fusion.py +0 -395
- package/lattice_brain/graph/identity.py +0 -175
- package/lattice_brain/graph/image_vectors.py +0 -230
- package/lattice_brain/graph/ingest.py +0 -829
- package/lattice_brain/graph/network.py +0 -205
- package/lattice_brain/graph/proactive.py +0 -724
- package/lattice_brain/graph/projection/__init__.py +0 -42
- package/lattice_brain/graph/projection/curation.py +0 -500
- package/lattice_brain/graph/projection/v2_schema.py +0 -518
- package/lattice_brain/graph/provenance.py +0 -524
- package/lattice_brain/graph/rerank.py +0 -163
- package/lattice_brain/graph/retrieval/__init__.py +0 -54
- package/lattice_brain/graph/retrieval/context.py +0 -197
- package/lattice_brain/graph/retrieval/graph_view.py +0 -319
- package/lattice_brain/graph/retrieval/hybrid.py +0 -488
- package/lattice_brain/graph/retrieval/maintenance.py +0 -121
- package/lattice_brain/graph/retrieval/signals.py +0 -95
- package/lattice_brain/graph/retrieval_docgen.py +0 -253
- package/lattice_brain/graph/retrieval_policy.py +0 -180
- package/lattice_brain/graph/retrieval_reads.py +0 -769
- package/lattice_brain/graph/retrieval_vector/__init__.py +0 -42
- package/lattice_brain/graph/retrieval_vector/fingerprint.py +0 -97
- package/lattice_brain/graph/retrieval_vector/indexing.py +0 -347
- package/lattice_brain/graph/retrieval_vector/search.py +0 -560
- package/lattice_brain/graph/retrieval_vector/status.py +0 -374
- package/lattice_brain/graph/schema.py +0 -792
- package/lattice_brain/graph/store.py +0 -268
- package/lattice_brain/graph/vector_index/__init__.py +0 -85
- package/lattice_brain/graph/vector_index/base.py +0 -167
- package/lattice_brain/graph/vector_index/brute_force.py +0 -110
- package/lattice_brain/graph/vector_index/hnsw.py +0 -290
- package/lattice_brain/graph/vector_index/jobs.py +0 -287
- package/lattice_brain/graph/vector_index/quantized.py +0 -148
- package/lattice_brain/graph/vector_index/selector.py +0 -161
- package/lattice_brain/graph/write_master.py +0 -308
- package/lattice_brain/ingestion/_contract.py +0 -90
- package/lattice_brain/ingestion/folder_scan.py +0 -57
- package/lattice_brain/ingestion/folders.py +0 -258
- package/lattice_brain/ingestion/jobs_api.py +0 -107
- package/lattice_brain/ingestion/routing.py +0 -295
- package/lattice_brain/ingestion_jobs.py +0 -380
- package/lattice_brain/memory.py +0 -75
- package/lattice_brain/portability/__init__.py +0 -90
- package/lattice_brain/portability/_contract.py +0 -42
- package/lattice_brain/portability/backups.py +0 -338
- package/lattice_brain/portability/bundles.py +0 -136
- package/lattice_brain/portability/constants.py +0 -93
- package/lattice_brain/portability/fsops.py +0 -138
- package/lattice_brain/portability/service.py +0 -41
- package/lattice_brain/portability/sharing.py +0 -710
- package/lattice_brain/quality.py +0 -543
- package/lattice_brain/retrieval_benchmark_fixtures.py +0 -92
- package/lattice_brain/runtime/agent_runtime.py +0 -859
- package/lattice_brain/runtime/contracts.py +0 -460
- package/lattice_brain/runtime/multi_agent.py +0 -942
- package/lattice_brain/runtime/statuses.py +0 -10
- package/lattice_brain/sealed_box.py +0 -240
- package/lattice_brain/self_model.py +0 -675
- package/lattice_brain/sensitivity.py +0 -94
- package/lattice_brain/storage/__init__.py +0 -22
- package/lattice_brain/storage/base.py +0 -100
- package/lattice_brain/storage/docker.py +0 -105
- package/lattice_brain/storage/factory.py +0 -31
- package/lattice_brain/storage/migration.py +0 -191
- package/lattice_brain/storage/postgres.py +0 -123
- package/lattice_brain/storage/sqlite.py +0 -143
- package/lattice_brain/synthesis.py +0 -824
- package/lattice_brain/workflow.py +0 -497
- package/latticeai/api/admin.py +0 -471
- package/latticeai/api/agent_registry.py +0 -105
- package/latticeai/api/agents.py +0 -228
- package/latticeai/api/auth.py +0 -383
- package/latticeai/api/automation_intelligence.py +0 -401
- package/latticeai/api/brain_intelligence.py +0 -199
- package/latticeai/api/browser.py +0 -493
- package/latticeai/api/change_proposals.py +0 -89
- package/latticeai/api/chat.py +0 -572
- package/latticeai/api/chat_agent_http.py +0 -892
- package/latticeai/api/chat_contracts.py +0 -73
- package/latticeai/api/chat_documents.py +0 -276
- package/latticeai/api/chat_helpers.py +0 -460
- package/latticeai/api/chat_history.py +0 -101
- package/latticeai/api/chat_hybrid.py +0 -113
- package/latticeai/api/chat_intents.py +0 -646
- package/latticeai/api/chat_stream.py +0 -216
- package/latticeai/api/chronicle.py +0 -63
- package/latticeai/api/command_center.py +0 -51
- package/latticeai/api/computer_use.py +0 -474
- package/latticeai/api/evidence_actions.py +0 -48
- package/latticeai/api/features.py +0 -70
- package/latticeai/api/funnel_metrics.py +0 -31
- package/latticeai/api/garden.py +0 -34
- package/latticeai/api/hooks.py +0 -165
- package/latticeai/api/index_jobs.py +0 -145
- package/latticeai/api/invitations.py +0 -100
- package/latticeai/api/knowledge_graph.py +0 -536
- package/latticeai/api/marketplace.py +0 -105
- package/latticeai/api/mcp.py +0 -482
- package/latticeai/api/memory.py +0 -270
- package/latticeai/api/network.py +0 -81
- package/latticeai/api/network_boundary.py +0 -225
- package/latticeai/api/permission_mode.py +0 -61
- package/latticeai/api/permissions.py +0 -436
- package/latticeai/api/plugins.py +0 -126
- package/latticeai/api/portability.py +0 -391
- package/latticeai/api/project_sessions.py +0 -114
- package/latticeai/api/realtime.py +0 -118
- package/latticeai/api/review_queue.py +0 -364
- package/latticeai/api/security_dashboard.py +0 -604
- package/latticeai/api/setup.py +0 -319
- package/latticeai/api/static_routes.py +0 -354
- package/latticeai/api/ui_redirects.py +0 -26
- package/latticeai/api/workflow_designer.py +0 -394
- package/latticeai/api/workspace.py +0 -856
- package/latticeai/api/workspace_scope.py +0 -125
- package/latticeai/core/agent/__init__.py +0 -93
- package/latticeai/core/agent/_contract.py +0 -79
- package/latticeai/core/agent/context.py +0 -57
- package/latticeai/core/agent/deps.py +0 -125
- package/latticeai/core/agent/execution.py +0 -622
- package/latticeai/core/agent/planning.py +0 -145
- package/latticeai/core/agent/recovery.py +0 -157
- package/latticeai/core/agent/runtime.py +0 -210
- package/latticeai/core/agent/verification.py +0 -231
- package/latticeai/core/agent_eval.py +0 -739
- package/latticeai/core/agent_helpers.py +0 -493
- package/latticeai/core/agent_profiles.py +0 -110
- package/latticeai/core/agent_prompts.py +0 -171
- package/latticeai/core/agent_registry.py +0 -232
- package/latticeai/core/agent_state.py +0 -41
- package/latticeai/core/agent_trace.py +0 -104
- package/latticeai/core/artifact_ledger.py +0 -109
- package/latticeai/core/audit.py +0 -260
- package/latticeai/core/builtin_hooks.py +0 -105
- package/latticeai/core/context_builder.py +0 -394
- package/latticeai/core/document_generator.py +0 -103
- package/latticeai/core/enterprise.py +0 -154
- package/latticeai/core/enterprise_admin.py +0 -158
- package/latticeai/core/file_generation/__init__.py +0 -115
- package/latticeai/core/file_generation/bundles.py +0 -76
- package/latticeai/core/file_generation/extraction.py +0 -154
- package/latticeai/core/file_generation/inference.py +0 -235
- package/latticeai/core/file_generation/orchestration.py +0 -152
- package/latticeai/core/file_generation/prompting.py +0 -117
- package/latticeai/core/file_generation/repair.py +0 -114
- package/latticeai/core/file_generation/sanitize.py +0 -61
- package/latticeai/core/file_generation/validation.py +0 -201
- package/latticeai/core/invitations.py +0 -132
- package/latticeai/core/legacy_compatibility.py +0 -243
- package/latticeai/core/logging_safety.py +0 -46
- package/latticeai/core/marketplace.py +0 -293
- package/latticeai/core/mcp_catalog.py +0 -452
- package/latticeai/core/mcp_registry.py +0 -506
- package/latticeai/core/network_boundary.py +0 -168
- package/latticeai/core/oidc.py +0 -208
- package/latticeai/core/plugins.py +0 -432
- package/latticeai/core/product_hardening.py +0 -218
- package/latticeai/core/project_sessions.py +0 -337
- package/latticeai/core/realtime.py +0 -238
- package/latticeai/core/run_explain.py +0 -426
- package/latticeai/core/run_store.py +0 -252
- package/latticeai/core/timezones.py +0 -80
- package/latticeai/core/workspace_computer_memory.py +0 -84
- package/latticeai/core/workspace_graph_trace.py +0 -155
- package/latticeai/core/workspace_indexing.py +0 -102
- package/latticeai/core/workspace_memory.py +0 -77
- package/latticeai/core/workspace_onboarding.py +0 -104
- package/latticeai/core/workspace_os.py +0 -978
- package/latticeai/core/workspace_os_constants.py +0 -126
- package/latticeai/core/workspace_os_state.py +0 -180
- package/latticeai/core/workspace_os_utils.py +0 -103
- package/latticeai/core/workspace_permissions.py +0 -101
- package/latticeai/core/workspace_plugins.py +0 -97
- package/latticeai/core/workspace_relationships.py +0 -99
- package/latticeai/core/workspace_reorganization.py +0 -335
- package/latticeai/core/workspace_review_items.py +0 -112
- package/latticeai/core/workspace_runs.py +0 -726
- package/latticeai/core/workspace_skills.py +0 -109
- package/latticeai/core/workspace_snapshots.py +0 -198
- package/latticeai/core/workspace_timeline.py +0 -110
- package/latticeai/integrations/__init__.py +0 -0
- package/latticeai/integrations/telegram_bot/__init__.py +0 -123
- package/latticeai/integrations/telegram_bot/__main__.py +0 -17
- package/latticeai/integrations/telegram_bot/config.py +0 -86
- package/latticeai/integrations/telegram_bot/dispatch.py +0 -311
- package/latticeai/integrations/telegram_bot/flows.py +0 -478
- package/latticeai/integrations/telegram_bot/helpers.py +0 -322
- package/latticeai/integrations/telegram_bot/screens.py +0 -394
- package/latticeai/runtime/audit_runtime.py +0 -76
- package/latticeai/runtime/automation_runtime.py +0 -81
- package/latticeai/runtime/chat_wiring.py +0 -141
- package/latticeai/runtime/context_runtime.py +0 -66
- package/latticeai/runtime/feature_toggle_wiring.py +0 -157
- package/latticeai/runtime/history_runtime.py +0 -163
- package/latticeai/runtime/history_writer.py +0 -138
- package/latticeai/runtime/hooks_runtime.py +0 -77
- package/latticeai/runtime/model_wiring.py +0 -68
- package/latticeai/runtime/namespace_runtime.py +0 -163
- package/latticeai/runtime/network_boundary_wiring.py +0 -117
- package/latticeai/runtime/network_config_runtime.py +0 -56
- package/latticeai/runtime/permission_mode_wiring.py +0 -112
- package/latticeai/runtime/persistence_runtime.py +0 -159
- package/latticeai/runtime/platform_runtime_wiring.py +0 -89
- package/latticeai/runtime/review_wiring.py +0 -42
- package/latticeai/runtime/router_registration.py +0 -693
- package/latticeai/runtime/service_singletons.py +0 -55
- package/latticeai/runtime/sso_config_runtime.py +0 -128
- package/latticeai/runtime/user_key_runtime.py +0 -106
- package/latticeai/runtime/web_runtime.py +0 -92
- package/latticeai/server_app.py +0 -51
- package/latticeai/services/app_context.py +0 -130
- package/latticeai/services/automation_execution.py +0 -266
- package/latticeai/services/automation_intelligence.py +0 -614
- package/latticeai/services/brain_automation.py +0 -191
- package/latticeai/services/brain_intelligence/__init__.py +0 -58
- package/latticeai/services/brain_intelligence/_contract.py +0 -71
- package/latticeai/services/brain_intelligence/consistency.py +0 -193
- package/latticeai/services/brain_intelligence/constants.py +0 -47
- package/latticeai/services/brain_intelligence/digest.py +0 -258
- package/latticeai/services/brain_intelligence/health.py +0 -331
- package/latticeai/services/brain_intelligence/proposals.py +0 -259
- package/latticeai/services/brain_intelligence/sampling.py +0 -84
- package/latticeai/services/brain_intelligence/service.py +0 -48
- package/latticeai/services/change_proposals.py +0 -471
- package/latticeai/services/chat_service.py +0 -243
- package/latticeai/services/chronicle.py +0 -555
- package/latticeai/services/cloud_egress_audit.py +0 -85
- package/latticeai/services/cloud_extraction.py +0 -129
- package/latticeai/services/cloud_streaming.py +0 -268
- package/latticeai/services/cloud_token_guard.py +0 -84
- package/latticeai/services/command_center.py +0 -548
- package/latticeai/services/evidence_actions.py +0 -258
- package/latticeai/services/feature_toggles.py +0 -502
- package/latticeai/services/folder_watch.py +0 -520
- package/latticeai/services/funnel_metrics.py +0 -307
- package/latticeai/services/hybrid_chat.py +0 -316
- package/latticeai/services/hybrid_context.py +0 -228
- package/latticeai/services/hybrid_policy.py +0 -129
- package/latticeai/services/interop_bridges.py +0 -978
- package/latticeai/services/local_knowledge.py +0 -465
- package/latticeai/services/memory_service/__init__.py +0 -52
- package/latticeai/services/memory_service/_contract.py +0 -100
- package/latticeai/services/memory_service/brief.py +0 -431
- package/latticeai/services/memory_service/constants.py +0 -57
- package/latticeai/services/memory_service/maintenance.py +0 -138
- package/latticeai/services/memory_service/manager.py +0 -186
- package/latticeai/services/memory_service/proof.py +0 -136
- package/latticeai/services/memory_service/recall.py +0 -225
- package/latticeai/services/memory_service/service.py +0 -48
- package/latticeai/services/memory_service/stores.py +0 -110
- package/latticeai/services/mode_store.py +0 -132
- package/latticeai/services/model_recommendation.py +0 -224
- package/latticeai/services/model_runtime/cloud.py +0 -87
- package/latticeai/services/network_boundary_service.py +0 -117
- package/latticeai/services/obsidian_bridge.py +0 -609
- package/latticeai/services/openai_compatible_adapter.py +0 -101
- package/latticeai/services/permission_mode_service.py +0 -122
- package/latticeai/services/platform_runtime.py +0 -366
- package/latticeai/services/review_queue.py +0 -380
- package/latticeai/services/router_context.py +0 -59
- package/latticeai/services/run_executor.py +0 -387
- package/latticeai/services/self_model_service.py +0 -171
- package/latticeai/services/setup_detection.py +0 -147
- package/latticeai/services/triggers.py +0 -378
- package/latticeai/services/upload_service.py +0 -172
- package/latticeai/services/workspace_service.py +0 -165
- package/latticeai/setup/__init__.py +0 -25
- package/latticeai/setup/auto_setup.py +0 -846
- package/latticeai/setup/demo_corpus.py +0 -98
- package/latticeai/setup/wizard/__init__.py +0 -126
- package/latticeai/setup/wizard/catalog.py +0 -175
- package/latticeai/setup/wizard/detect.py +0 -302
- package/latticeai/setup/wizard/install.py +0 -348
- package/latticeai/setup/wizard/paths.py +0 -165
- package/latticeai/setup/wizard/plans.py +0 -74
- package/latticeai/setup/wizard/recommend.py +0 -320
- package/scripts/bench_agent_smoke.py +0 -409
- package/scripts/bench_models.py +0 -540
- package/scripts/bench_vector_index.py +0 -295
- package/scripts/funnel_soft_gate.py +0 -192
- package/scripts/generate_agent_loop_fixtures.py +0 -994
- package/scripts/generate_rust_parity_fixtures.py +0 -908
- package/scripts/migrate_brain_storage.py +0 -57
- package/scripts/parity_fixture_corpus_context.py +0 -162
- package/scripts/parity_fixture_corpus_docgen.py +0 -341
- package/scripts/profile_kg.py +0 -355
- package/server.py +0 -30
- package/static/app/assets/AdminConsole-cf4npybT.js +0 -1
- package/static/app/assets/Capture-DiQ219jW.js +0 -1
- package/static/app/assets/System-CieofHQa.js +0 -1
- package/static/app/assets/arrow-left-kfsrk0mv.js +0 -1
- package/static/app/assets/circle-check-qqLug9nU.js +0 -1
- package/static/app/assets/index-DxmOfNRi.css +0 -2
- package/static/app/assets/primitives-SNp0LRJz.js +0 -1
- package/static/app/assets/search-BcHqkjoy.js +0 -1
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
"""PATH discovery, binary lookup, and the ``.env`` handoff for the wizard.
|
|
2
|
-
|
|
3
|
-
The base layer of the setup wizard: it knows where installers put things on
|
|
4
|
-
each platform, how to get those directories onto ``PATH`` for the running
|
|
5
|
-
process, and how to persist that repair into the project ``.env``. Nothing
|
|
6
|
-
here imports another wizard submodule, which is also what lets
|
|
7
|
-
``tests/unit/test_cov_wp04_wizard_detect.py`` re-execute this file under a
|
|
8
|
-
throwaway name to reach the Windows-only import-time branch.
|
|
9
|
-
|
|
10
|
-
``COMMON_PATH_DIRS`` is module-level state that the import-time Windows block
|
|
11
|
-
extends and tests replace, so it lives here and only here — the modules that
|
|
12
|
-
repair PATH call :func:`repair_path_for` rather than copying the list.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
import os
|
|
18
|
-
import platform
|
|
19
|
-
import shutil
|
|
20
|
-
from pathlib import Path
|
|
21
|
-
from typing import Any, Dict, List
|
|
22
|
-
|
|
23
|
-
from latticeai.core.module_probe import module_available as _module_available
|
|
24
|
-
|
|
25
|
-
OFFICIAL_DOWNLOADS: Dict[str, str] = {
|
|
26
|
-
"homebrew": "https://brew.sh",
|
|
27
|
-
"python": "https://www.python.org/downloads/",
|
|
28
|
-
"node": "https://nodejs.org/en/download",
|
|
29
|
-
"git": "https://git-scm.com/downloads",
|
|
30
|
-
"ollama": "https://ollama.com/download",
|
|
31
|
-
"lmstudio": "https://lmstudio.ai/download",
|
|
32
|
-
"cuda": "https://developer.nvidia.com/cuda-downloads",
|
|
33
|
-
"mlx": "https://ml-explore.github.io/mlx/build/html/install.html",
|
|
34
|
-
"cloudflared": "https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/",
|
|
35
|
-
"tesseract": "https://tesseract-ocr.github.io/tessdoc/Installation.html",
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
COMMON_PATH_DIRS = [
|
|
39
|
-
"/opt/homebrew/bin",
|
|
40
|
-
"/usr/local/bin",
|
|
41
|
-
"/usr/bin",
|
|
42
|
-
"/bin",
|
|
43
|
-
str(Path.home() / ".local" / "bin"),
|
|
44
|
-
str(Path.home() / ".cargo" / "bin"),
|
|
45
|
-
str(Path.home() / ".latticeai" / "bin"),
|
|
46
|
-
]
|
|
47
|
-
|
|
48
|
-
if platform.system() == "Windows":
|
|
49
|
-
_local_appdata = os.environ.get("LOCALAPPDATA", "")
|
|
50
|
-
_program_files = os.environ.get("ProgramFiles", r"C:\Program Files")
|
|
51
|
-
_program_files_x86 = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")
|
|
52
|
-
COMMON_PATH_DIRS.extend([
|
|
53
|
-
str(Path(_local_appdata) / "Programs" / "Ollama") if _local_appdata else "",
|
|
54
|
-
str(Path(_program_files) / "Ollama"),
|
|
55
|
-
str(Path(_program_files) / "LM Studio"),
|
|
56
|
-
str(Path(_program_files) / "NVIDIA Corporation" / "NVSMI"),
|
|
57
|
-
str(Path(_program_files_x86) / "NVIDIA Corporation" / "NVSMI"),
|
|
58
|
-
])
|
|
59
|
-
COMMON_PATH_DIRS = [p for p in COMMON_PATH_DIRS if p]
|
|
60
|
-
|
|
61
|
-
WINDOWS_BINARY_CANDIDATES: Dict[str, List[str]] = {
|
|
62
|
-
"ollama": [
|
|
63
|
-
str(Path(os.environ.get("LOCALAPPDATA", "")) / "Programs" / "Ollama" / "ollama.exe"),
|
|
64
|
-
str(Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "Ollama" / "ollama.exe"),
|
|
65
|
-
],
|
|
66
|
-
"lms": [
|
|
67
|
-
str(Path(os.environ.get("LOCALAPPDATA", "")) / "Programs" / "LM Studio" / "resources" / "app" / ".webpack" / "lms.exe"),
|
|
68
|
-
str(Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "LM Studio" / "resources" / "app" / ".webpack" / "lms.exe"),
|
|
69
|
-
],
|
|
70
|
-
"nvidia-smi": [
|
|
71
|
-
str(Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA Corporation" / "NVSMI" / "nvidia-smi.exe"),
|
|
72
|
-
str(Path(os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")) / "NVIDIA Corporation" / "NVSMI" / "nvidia-smi.exe"),
|
|
73
|
-
],
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
PACKAGE_MODULES: Dict[str, str] = {
|
|
77
|
-
"mlx-vlm": "mlx_vlm",
|
|
78
|
-
"huggingface_hub[cli]": "huggingface_hub",
|
|
79
|
-
"openai-whisper": "whisper",
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def _project_env_file() -> Path:
|
|
84
|
-
return Path(__file__).resolve().parents[2] / ".env"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def _update_env_file(env_file: Path, key: str, value: str) -> None:
|
|
88
|
-
lines: List[str] = []
|
|
89
|
-
found = False
|
|
90
|
-
if env_file.exists():
|
|
91
|
-
lines = env_file.read_text(encoding="utf-8").splitlines()
|
|
92
|
-
updated: List[str] = []
|
|
93
|
-
for line in lines:
|
|
94
|
-
if line.startswith(f"{key}="):
|
|
95
|
-
updated.append(f"{key}={value}")
|
|
96
|
-
found = True
|
|
97
|
-
else:
|
|
98
|
-
updated.append(line)
|
|
99
|
-
if not found:
|
|
100
|
-
updated.append(f"{key}={value}")
|
|
101
|
-
env_file.write_text("\n".join(updated) + "\n", encoding="utf-8")
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def _merge_path_dirs(dirs: List[str]) -> List[str]:
|
|
105
|
-
current = os.environ.get("PATH", "")
|
|
106
|
-
parts = [p for p in current.split(os.pathsep) if p]
|
|
107
|
-
for item in dirs:
|
|
108
|
-
expanded = str(Path(item).expanduser())
|
|
109
|
-
if Path(expanded).exists() and expanded not in parts:
|
|
110
|
-
parts.insert(0, expanded)
|
|
111
|
-
os.environ["PATH"] = os.pathsep.join(parts)
|
|
112
|
-
return parts
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def _persist_extra_path(dirs: List[str]) -> None:
|
|
116
|
-
existing = [
|
|
117
|
-
p for p in os.environ.get("LATTICEAI_EXTRA_PATH", "").split(os.pathsep)
|
|
118
|
-
if p
|
|
119
|
-
]
|
|
120
|
-
merged = existing[:]
|
|
121
|
-
for item in dirs:
|
|
122
|
-
expanded = str(Path(item).expanduser())
|
|
123
|
-
if Path(expanded).exists() and expanded not in merged:
|
|
124
|
-
merged.append(expanded)
|
|
125
|
-
if merged:
|
|
126
|
-
os.environ["LATTICEAI_EXTRA_PATH"] = os.pathsep.join(merged)
|
|
127
|
-
_update_env_file(_project_env_file(), "LATTICEAI_EXTRA_PATH", os.environ["LATTICEAI_EXTRA_PATH"])
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def repair_path_for(binary: str | None = None) -> List[str]:
|
|
131
|
-
before = _which_any(binary) if binary else None
|
|
132
|
-
paths = _merge_path_dirs(COMMON_PATH_DIRS)
|
|
133
|
-
if binary and not before and _which_any(binary):
|
|
134
|
-
_persist_extra_path(COMMON_PATH_DIRS)
|
|
135
|
-
return paths
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
def _which_any(binary: str) -> str | None:
|
|
139
|
-
path = shutil.which(binary)
|
|
140
|
-
if path:
|
|
141
|
-
return path
|
|
142
|
-
if platform.system() == "Windows":
|
|
143
|
-
for candidate in WINDOWS_BINARY_CANDIDATES.get(binary, []):
|
|
144
|
-
if candidate and Path(candidate).exists():
|
|
145
|
-
return candidate
|
|
146
|
-
return None
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
def _which_detail(binary: str) -> Dict[str, Any]:
|
|
150
|
-
path = _which_any(binary)
|
|
151
|
-
return {"installed": path is not None, "path": path}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
def _package_module(package: str) -> str:
|
|
155
|
-
return PACKAGE_MODULES.get(package, package.replace("-", "_").split("[", 1)[0])
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def _component_detail(name: str, binary: str | None = None, module: str | None = None) -> Dict[str, Any]:
|
|
159
|
-
detail: Dict[str, Any] = {"official_url": OFFICIAL_DOWNLOADS.get(name)}
|
|
160
|
-
if binary:
|
|
161
|
-
detail.update(_which_detail(binary))
|
|
162
|
-
if module:
|
|
163
|
-
detail["module_available"] = _module_available(module)
|
|
164
|
-
detail["installed"] = bool(detail.get("installed") or detail["module_available"])
|
|
165
|
-
return detail
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"""SSE framing and the confirmation-token plans for wizard install actions.
|
|
2
|
-
|
|
3
|
-
Every install action the wizard offers is turned into an explicit command plan
|
|
4
|
-
before it is shown, so the token the browser sends back can be compared against
|
|
5
|
-
the exact commands that would run. An action with nothing to execute has no
|
|
6
|
-
plan and therefore nothing to confirm.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
import sys
|
|
12
|
-
from typing import Any, Dict, List
|
|
13
|
-
|
|
14
|
-
from latticeai.core.sse import sse_frame
|
|
15
|
-
from latticeai.services.process_audit import command_plan_for_commands
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def _sse(data: Dict) -> str:
|
|
19
|
-
return sse_frame(None, data)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def _action_commands(action: Dict[str, Any]) -> List[List[str]]:
|
|
23
|
-
atype = action.get("type")
|
|
24
|
-
if atype == "pip":
|
|
25
|
-
return [[sys.executable, "-m", "pip", "install", "--upgrade", str(pkg)] for pkg in action.get("packages", [])]
|
|
26
|
-
if atype == "brew":
|
|
27
|
-
package = str(action.get("package") or "")
|
|
28
|
-
return [["brew", "install", package]] if package else []
|
|
29
|
-
return []
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _action_command_plan(action: Dict[str, Any], *, name: str) -> Dict[str, Any] | None:
|
|
33
|
-
commands = _action_commands(action)
|
|
34
|
-
if not commands:
|
|
35
|
-
return None
|
|
36
|
-
return command_plan_for_commands(
|
|
37
|
-
commands,
|
|
38
|
-
name=name,
|
|
39
|
-
purpose="setup_wizard_install",
|
|
40
|
-
metadata={"action_type": action.get("type")},
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def _attach_action_plan(action: Dict[str, Any] | None, *, name: str) -> Dict[str, Any] | None:
|
|
45
|
-
if not isinstance(action, dict):
|
|
46
|
-
return action
|
|
47
|
-
plan = _action_command_plan(action, name=name)
|
|
48
|
-
if not plan:
|
|
49
|
-
return action
|
|
50
|
-
hydrated = dict(action)
|
|
51
|
-
hydrated["command_plan"] = plan
|
|
52
|
-
hydrated["confirmation_token"] = plan["confirmation_token"]
|
|
53
|
-
return hydrated
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def _hydrate_install_actions(groups: Dict[str, Any]) -> Dict[str, Any]:
|
|
57
|
-
for group_name in ("components", "engines", "models", "mcps"):
|
|
58
|
-
items = groups.get(group_name)
|
|
59
|
-
if not isinstance(items, list):
|
|
60
|
-
continue
|
|
61
|
-
for item in items:
|
|
62
|
-
if isinstance(item, dict):
|
|
63
|
-
item["action"] = _attach_action_plan(
|
|
64
|
-
item.get("action"),
|
|
65
|
-
name=str(item.get("id") or item.get("name") or group_name),
|
|
66
|
-
)
|
|
67
|
-
return groups
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def _verify_action_confirmation(action: Dict[str, Any], token: str | None, *, name: str) -> bool:
|
|
71
|
-
plan = _action_command_plan(action, name=name)
|
|
72
|
-
if not plan:
|
|
73
|
-
return True
|
|
74
|
-
return str(token or "").strip() == plan["confirmation_token"]
|
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
"""The wizard's recommendation: environment scan in, tailored checklist out.
|
|
2
|
-
|
|
3
|
-
Pure function over the :func:`~latticeai.setup.wizard.detect.scan_environment`
|
|
4
|
-
payload — no probing, no installing. It picks the preferred engine, filters the
|
|
5
|
-
catalogue to what fits, and returns the component / engine / model / MCP groups
|
|
6
|
-
the setup screen renders, each already carrying a confirmation-token plan.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
import sys
|
|
12
|
-
from typing import Any, Dict, List
|
|
13
|
-
|
|
14
|
-
from latticeai.setup.wizard.catalog import (
|
|
15
|
-
_CROSS_PLATFORM_MODEL_CATALOG,
|
|
16
|
-
_MODEL_CATALOG,
|
|
17
|
-
_best_model_for_engine,
|
|
18
|
-
_filter_lower_family_versions,
|
|
19
|
-
)
|
|
20
|
-
from latticeai.setup.wizard.paths import OFFICIAL_DOWNLOADS
|
|
21
|
-
from latticeai.setup.wizard.plans import _hydrate_install_actions
|
|
22
|
-
|
|
23
|
-
# ── Recommendation Logic ──────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
def get_recommendations(env: Dict[str, Any]) -> Dict[str, Any]:
|
|
26
|
-
ram = env["ram_gb"]
|
|
27
|
-
chip = env["chip"]
|
|
28
|
-
mlx = env["mlx"]
|
|
29
|
-
tools = env["tools"]
|
|
30
|
-
api_keys = env["api_keys"]
|
|
31
|
-
disk_free = env["disk_free_gb"]
|
|
32
|
-
is_apple = chip["is_apple_silicon"]
|
|
33
|
-
gpu = env.get("gpu", {})
|
|
34
|
-
cuda = env.get("cuda", {})
|
|
35
|
-
wsl = env.get("wsl", {})
|
|
36
|
-
cpu = env.get("cpu", {})
|
|
37
|
-
os_name = env.get("os", "")
|
|
38
|
-
|
|
39
|
-
max_model_gb = ram * 0.72 # ~28% headroom for OS + apps
|
|
40
|
-
|
|
41
|
-
if is_apple:
|
|
42
|
-
preferred_engine = "local_mlx"
|
|
43
|
-
elif gpu.get("vendor") == "nvidia" and cuda.get("available") and (os_name == "Linux" or wsl.get("is_wsl")):
|
|
44
|
-
preferred_engine = "vllm"
|
|
45
|
-
elif tools.get("lms"):
|
|
46
|
-
preferred_engine = "lmstudio"
|
|
47
|
-
elif tools.get("ollama"):
|
|
48
|
-
preferred_engine = "ollama"
|
|
49
|
-
else:
|
|
50
|
-
preferred_engine = "llamacpp"
|
|
51
|
-
|
|
52
|
-
apple_catalog = _filter_lower_family_versions(_MODEL_CATALOG)
|
|
53
|
-
engine_catalog = (
|
|
54
|
-
[]
|
|
55
|
-
if is_apple
|
|
56
|
-
else _filter_lower_family_versions(_CROSS_PLATFORM_MODEL_CATALOG[preferred_engine])
|
|
57
|
-
)
|
|
58
|
-
best_id = _best_model_for_engine(
|
|
59
|
-
"local_mlx" if is_apple else preferred_engine,
|
|
60
|
-
ram,
|
|
61
|
-
apple_catalog if is_apple else engine_catalog,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
# ── Engines ──────────────────────────────────────────────────────────────
|
|
65
|
-
engines: List[Dict] = []
|
|
66
|
-
|
|
67
|
-
if is_apple:
|
|
68
|
-
if mlx["available"] and mlx["mlx_vlm"]:
|
|
69
|
-
engines.append({
|
|
70
|
-
"id": "engine_mlx", "name": "MLX",
|
|
71
|
-
"subtitle": f"{chip['name']} GPU 가속 · MLX-VLM 멀티모달 실행",
|
|
72
|
-
"status": "installed", "priority": "recommended",
|
|
73
|
-
"checked": True, "action": None, "badge": "설치됨",
|
|
74
|
-
})
|
|
75
|
-
else:
|
|
76
|
-
engines.append({
|
|
77
|
-
"id": "engine_mlx", "name": "MLX",
|
|
78
|
-
"subtitle": f"{chip['name']} 전용 MLX-VLM 멀티모달 실행",
|
|
79
|
-
"status": "available", "priority": "recommended",
|
|
80
|
-
"checked": True,
|
|
81
|
-
"action": {"type": "pip", "packages": ["mlx-vlm"], "verify_modules": ["mlx", "mlx_vlm"]},
|
|
82
|
-
"badge": "설치 필요",
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
if tools.get("ollama"):
|
|
86
|
-
engines.append({
|
|
87
|
-
"id": "engine_ollama", "name": "Ollama",
|
|
88
|
-
"subtitle": "범용 로컬 LLM 서버 · 크로스 플랫폼",
|
|
89
|
-
"status": "installed", "priority": "recommended" if preferred_engine == "ollama" else "optional",
|
|
90
|
-
"checked": preferred_engine == "ollama", "action": None, "badge": "설치됨",
|
|
91
|
-
})
|
|
92
|
-
else:
|
|
93
|
-
hint = "brew install 가능" if (tools.get("brew") or env["os"] == "Darwin") else "수동 설치 필요"
|
|
94
|
-
engines.append({
|
|
95
|
-
"id": "engine_ollama", "name": "Ollama",
|
|
96
|
-
"subtitle": "범용 로컬 LLM 서버 · 크로스 플랫폼",
|
|
97
|
-
"status": "available", "priority": "recommended" if preferred_engine == "ollama" else "optional",
|
|
98
|
-
"checked": preferred_engine == "ollama",
|
|
99
|
-
"action": (
|
|
100
|
-
{"type": "brew", "package": "ollama", "binary": "ollama", "official_url": OFFICIAL_DOWNLOADS["ollama"]}
|
|
101
|
-
if tools.get("brew")
|
|
102
|
-
else {"type": "url", "url": OFFICIAL_DOWNLOADS["ollama"], "binary": "ollama"}
|
|
103
|
-
),
|
|
104
|
-
"badge": hint,
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
if not is_apple:
|
|
108
|
-
lmstudio_installed = bool(tools.get("lms"))
|
|
109
|
-
engines.append({
|
|
110
|
-
"id": "engine_lmstudio", "name": "LM Studio",
|
|
111
|
-
"subtitle": "Windows/macOS/Linux 데스크톱 GPU 서버 · 모델 다운로드 UI 포함",
|
|
112
|
-
"status": "installed" if lmstudio_installed else "available",
|
|
113
|
-
"priority": "recommended" if preferred_engine == "lmstudio" else "optional",
|
|
114
|
-
"checked": preferred_engine == "lmstudio",
|
|
115
|
-
"action": None if lmstudio_installed else {"type": "url", "url": OFFICIAL_DOWNLOADS["lmstudio"], "binary": "lms"},
|
|
116
|
-
"badge": "설치됨" if lmstudio_installed else "설치 필요",
|
|
117
|
-
})
|
|
118
|
-
if gpu.get("vendor") == "nvidia":
|
|
119
|
-
engines.append({
|
|
120
|
-
"id": "engine_cuda", "name": "CUDA",
|
|
121
|
-
"subtitle": f"NVIDIA {gpu.get('name') or 'GPU'} · VRAM {gpu.get('vram_gb') or 0} GB",
|
|
122
|
-
"status": "installed" if cuda.get("available") else "available",
|
|
123
|
-
"priority": "recommended",
|
|
124
|
-
"checked": False,
|
|
125
|
-
"action": None if cuda.get("available") else {"type": "url", "url": OFFICIAL_DOWNLOADS["cuda"], "binary": "nvcc"},
|
|
126
|
-
"badge": cuda.get("version") or ("감지됨" if cuda.get("available") else "설치 필요"),
|
|
127
|
-
})
|
|
128
|
-
engines.append({
|
|
129
|
-
"id": "engine_vllm", "name": "vLLM",
|
|
130
|
-
"subtitle": "NVIDIA 서버형 추론 · Windows는 WSL/Linux 권장",
|
|
131
|
-
"status": "available",
|
|
132
|
-
"priority": "recommended" if preferred_engine == "vllm" else "optional",
|
|
133
|
-
"checked": preferred_engine == "vllm",
|
|
134
|
-
"action": {"type": "pip", "packages": ["vllm", "huggingface_hub[cli]"], "verify_modules": ["vllm", "huggingface_hub"]},
|
|
135
|
-
"badge": "WSL/Linux 권장" if os_name == "Windows" and not wsl.get("is_wsl") else "설치 가능",
|
|
136
|
-
})
|
|
137
|
-
elif gpu.get("vendor") in {"amd", "intel"}:
|
|
138
|
-
engines.append({
|
|
139
|
-
"id": "engine_vulkan_directml", "name": "Vulkan/DirectML",
|
|
140
|
-
"subtitle": f"{gpu.get('vendor', '').upper()} GPU 감지 · LM Studio 또는 llama.cpp 백엔드 권장",
|
|
141
|
-
"status": "available",
|
|
142
|
-
"priority": "recommended" if preferred_engine in {"lmstudio", "llamacpp"} else "optional",
|
|
143
|
-
"checked": False,
|
|
144
|
-
"action": None,
|
|
145
|
-
"badge": gpu.get("backend") or "GPU",
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
components: List[Dict] = []
|
|
149
|
-
component_specs = [
|
|
150
|
-
("homebrew", "Homebrew", "macOS 패키지 관리자 · 자동 설치 기반", "brew", None, "recommended"),
|
|
151
|
-
("git", "Git", "저장소 · 확장 · MCP 도구 연동에 필요", "git", "git", "recommended"),
|
|
152
|
-
("node", "Node.js", "npm 패키지와 VS Code 확장 개발에 필요", "node", "node", "optional"),
|
|
153
|
-
("tesseract", "Tesseract OCR", "이미지/PDF OCR 기능에 필요", "tesseract", "tesseract", "optional"),
|
|
154
|
-
]
|
|
155
|
-
for cid, name, subtitle, binary, brew_pkg, priority in component_specs:
|
|
156
|
-
installed = bool(tools.get(binary))
|
|
157
|
-
if cid == "homebrew" and env["os"] != "Darwin":
|
|
158
|
-
continue
|
|
159
|
-
if installed:
|
|
160
|
-
components.append({
|
|
161
|
-
"id": f"component_{cid}", "name": name,
|
|
162
|
-
"subtitle": subtitle, "status": "installed",
|
|
163
|
-
"priority": priority, "checked": False, "action": None,
|
|
164
|
-
"badge": "설치됨",
|
|
165
|
-
})
|
|
166
|
-
continue
|
|
167
|
-
if cid == "homebrew":
|
|
168
|
-
action = {"type": "url", "url": OFFICIAL_DOWNLOADS["homebrew"], "binary": "brew"}
|
|
169
|
-
elif tools.get("brew") and brew_pkg:
|
|
170
|
-
action = {
|
|
171
|
-
"type": "brew",
|
|
172
|
-
"package": brew_pkg,
|
|
173
|
-
"binary": binary or "",
|
|
174
|
-
"official_url": OFFICIAL_DOWNLOADS.get(cid, ""),
|
|
175
|
-
}
|
|
176
|
-
else:
|
|
177
|
-
action = {
|
|
178
|
-
"type": "url",
|
|
179
|
-
"url": OFFICIAL_DOWNLOADS.get(cid, ""),
|
|
180
|
-
"binary": binary or "",
|
|
181
|
-
}
|
|
182
|
-
components.append({
|
|
183
|
-
"id": f"component_{cid}", "name": name,
|
|
184
|
-
"subtitle": subtitle, "status": "available",
|
|
185
|
-
"priority": priority, "checked": priority == "recommended",
|
|
186
|
-
"action": action, "badge": "설치 필요",
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
python_ok = sys.version_info >= (3, 11)
|
|
190
|
-
if not python_ok:
|
|
191
|
-
components.insert(0, {
|
|
192
|
-
"id": "component_python", "name": "Python 3.11+",
|
|
193
|
-
"subtitle": "Lattice AI 서버 실행에 필요한 Python 런타임",
|
|
194
|
-
"status": "available", "priority": "recommended", "checked": True,
|
|
195
|
-
"action": {"type": "url", "url": OFFICIAL_DOWNLOADS["python"], "binary": "python3"},
|
|
196
|
-
"badge": "업데이트 필요",
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
for provider, has_key in api_keys.items():
|
|
200
|
-
if has_key:
|
|
201
|
-
engines.append({
|
|
202
|
-
"id": f"engine_{provider}", "name": provider.title(),
|
|
203
|
-
"subtitle": f"{provider.upper()}_API_KEY 감지됨 · 클라우드 API",
|
|
204
|
-
"status": "ready", "priority": "optional",
|
|
205
|
-
"checked": False, "action": None, "badge": "준비됨",
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
# ── Models ───────────────────────────────────────────────────────────────
|
|
209
|
-
models: List[Dict] = []
|
|
210
|
-
|
|
211
|
-
if is_apple:
|
|
212
|
-
for mid, mname, size_gb, tag, desc, min_ram in apple_catalog:
|
|
213
|
-
fits = ram >= min_ram and size_gb <= max_model_gb and disk_free >= size_gb + 2
|
|
214
|
-
is_best = mid == best_id
|
|
215
|
-
models.append({
|
|
216
|
-
"id": f"model_{mid.replace('/', '__').replace('-', '_')}",
|
|
217
|
-
"model_id": mid,
|
|
218
|
-
"name": mname,
|
|
219
|
-
"subtitle": desc,
|
|
220
|
-
"size_gb": size_gb,
|
|
221
|
-
"tag": tag,
|
|
222
|
-
"fits": fits,
|
|
223
|
-
"priority": "recommended" if is_best else "optional",
|
|
224
|
-
"checked": is_best and fits,
|
|
225
|
-
"disabled": not fits,
|
|
226
|
-
"badge": f"{size_gb} GB",
|
|
227
|
-
"action": {"type": "load_model", "model_id": mid} if fits else None,
|
|
228
|
-
})
|
|
229
|
-
else:
|
|
230
|
-
vram_gb = float(gpu.get("vram_gb") or 0)
|
|
231
|
-
gpu_budget_gb = vram_gb * 1.15 if gpu.get("vendor") in {"nvidia", "amd", "intel"} and vram_gb else max_model_gb
|
|
232
|
-
model_budget_gb = min(max_model_gb, gpu_budget_gb)
|
|
233
|
-
for mid, mname, size_gb, tag, desc, min_ram in engine_catalog:
|
|
234
|
-
fits = ram >= min_ram and size_gb <= model_budget_gb and disk_free >= size_gb + 2
|
|
235
|
-
is_best = mid == best_id
|
|
236
|
-
models.append({
|
|
237
|
-
"id": f"model_{mid.replace('/', '__').replace(':', '__').replace('-', '_')}",
|
|
238
|
-
"model_id": mid,
|
|
239
|
-
"name": mname,
|
|
240
|
-
"subtitle": desc,
|
|
241
|
-
"size_gb": size_gb,
|
|
242
|
-
"tag": tag,
|
|
243
|
-
"fits": fits,
|
|
244
|
-
"priority": "recommended" if is_best else "optional",
|
|
245
|
-
"checked": is_best and fits,
|
|
246
|
-
"disabled": not fits,
|
|
247
|
-
"badge": f"{size_gb} GB · {preferred_engine}",
|
|
248
|
-
"action": {"type": "load_model", "model_id": mid} if fits else None,
|
|
249
|
-
})
|
|
250
|
-
if models and not any(item.get("checked") for item in models):
|
|
251
|
-
for item in models:
|
|
252
|
-
if not item.get("disabled"):
|
|
253
|
-
item["priority"] = "recommended"
|
|
254
|
-
item["checked"] = True
|
|
255
|
-
break
|
|
256
|
-
|
|
257
|
-
# ── MCPs ─────────────────────────────────────────────────────────────────
|
|
258
|
-
mcps: List[Dict] = [
|
|
259
|
-
{
|
|
260
|
-
"id": "mcp_files", "name": "Workspace Files",
|
|
261
|
-
"subtitle": "파일 읽기/쓰기 · 코드 생성 · 미리보기",
|
|
262
|
-
"status": "active", "priority": "recommended",
|
|
263
|
-
"checked": True, "action": None,
|
|
264
|
-
"badge": "기본 탑재", "needs_auth": False,
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
"id": "mcp_presentations", "name": "Presentations",
|
|
268
|
-
"subtitle": "PPTX · 슬라이드 자동 생성",
|
|
269
|
-
"status": "active", "priority": "optional",
|
|
270
|
-
"checked": False, "action": None,
|
|
271
|
-
"badge": "기본 탑재", "needs_auth": False,
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
"id": "mcp_github", "name": "GitHub",
|
|
275
|
-
"subtitle": "저장소 · PR · 이슈 · CI 연동",
|
|
276
|
-
"status": "available", "priority": "optional",
|
|
277
|
-
"checked": False,
|
|
278
|
-
"action": {"type": "auth", "url": "https://github.com/apps", "mcp_id": "github"},
|
|
279
|
-
"badge": "인증 필요", "needs_auth": True,
|
|
280
|
-
},
|
|
281
|
-
{
|
|
282
|
-
"id": "mcp_googledrive", "name": "Google Drive",
|
|
283
|
-
"subtitle": "Docs · Sheets · Drive 파일 연동",
|
|
284
|
-
"status": "available", "priority": "optional",
|
|
285
|
-
"checked": False,
|
|
286
|
-
"action": {"type": "auth", "url": "https://chatgpt.com/connectors", "mcp_id": "google-drive"},
|
|
287
|
-
"badge": "인증 필요", "needs_auth": True,
|
|
288
|
-
},
|
|
289
|
-
{
|
|
290
|
-
"id": "mcp_slack", "name": "Slack",
|
|
291
|
-
"subtitle": "팀 채널 공유 · 알림 워크플로",
|
|
292
|
-
"status": "available", "priority": "optional",
|
|
293
|
-
"checked": False,
|
|
294
|
-
"action": {"type": "auth", "url": "https://chatgpt.com/connectors", "mcp_id": "slack"},
|
|
295
|
-
"badge": "인증 필요", "needs_auth": True,
|
|
296
|
-
},
|
|
297
|
-
]
|
|
298
|
-
|
|
299
|
-
return _hydrate_install_actions({
|
|
300
|
-
"components": components,
|
|
301
|
-
"engines": engines,
|
|
302
|
-
"models": models,
|
|
303
|
-
"mcps": mcps,
|
|
304
|
-
"summary": {
|
|
305
|
-
"chip": chip["name"],
|
|
306
|
-
"cpu_cores": cpu.get("logical_cores"),
|
|
307
|
-
"cpu_instructions": cpu.get("instructions", []),
|
|
308
|
-
"gpu": gpu.get("name") or gpu.get("vendor"),
|
|
309
|
-
"gpu_vendor": gpu.get("vendor"),
|
|
310
|
-
"vram_gb": gpu.get("vram_gb"),
|
|
311
|
-
"cuda": cuda.get("available"),
|
|
312
|
-
"cuda_version": cuda.get("version"),
|
|
313
|
-
"wsl": wsl,
|
|
314
|
-
"preferred_engine": preferred_engine,
|
|
315
|
-
"ram_gb": ram,
|
|
316
|
-
"disk_free_gb": disk_free,
|
|
317
|
-
"is_apple_silicon": is_apple,
|
|
318
|
-
"max_model_gb": round(max_model_gb, 1),
|
|
319
|
-
},
|
|
320
|
-
})
|