ltcai 11.1.0 → 11.4.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 +47 -54
- package/docs/CHANGELOG.md +94 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/FEATURE_AUDIT_v11.2.0.md +393 -0
- package/docs/LAYOUT_REBUILD_SPEC.md +9 -1
- package/docs/MULTI_AGENT_RUNTIME.md +1 -1
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +6 -2
- package/docs/PERMISSION_MODE.md +1 -1
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/architecture.md +6 -2
- package/docs/kg-schema.md +2 -2
- package/docs/v11.3.0_PLAN.md +202 -0
- package/docs/v11.4.0_RUST_FOUNDATION_PLAN.md +176 -0
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/gates.py +125 -0
- package/lattice_brain/graph/_kg_common/__init__.py +287 -0
- package/lattice_brain/graph/_kg_common/extraction.py +516 -0
- package/lattice_brain/graph/_kg_common/relations.py +161 -0
- package/lattice_brain/graph/_kg_common/text.py +479 -0
- package/lattice_brain/graph/discovery_index/__init__.py +35 -0
- package/lattice_brain/graph/discovery_index/cleanup.py +182 -0
- package/lattice_brain/graph/discovery_index/extract.py +137 -0
- package/lattice_brain/graph/discovery_index/scan.py +411 -0
- package/lattice_brain/graph/discovery_index/upsert.py +495 -0
- package/lattice_brain/graph/fusion.py +35 -4
- package/lattice_brain/graph/projection/__init__.py +42 -0
- package/lattice_brain/graph/projection/curation.py +500 -0
- package/lattice_brain/graph/{projection.py → projection/v2_schema.py} +81 -485
- package/lattice_brain/graph/retrieval/__init__.py +54 -0
- package/lattice_brain/graph/retrieval/context.py +197 -0
- package/lattice_brain/graph/retrieval/graph_view.py +319 -0
- package/lattice_brain/graph/retrieval/hybrid.py +488 -0
- package/lattice_brain/graph/retrieval/maintenance.py +121 -0
- package/lattice_brain/graph/retrieval/signals.py +95 -0
- package/lattice_brain/graph/retrieval_vector/__init__.py +42 -0
- package/lattice_brain/graph/retrieval_vector/fingerprint.py +97 -0
- package/lattice_brain/graph/retrieval_vector/indexing.py +347 -0
- package/lattice_brain/graph/retrieval_vector/search.py +560 -0
- package/lattice_brain/graph/retrieval_vector/status.py +374 -0
- package/lattice_brain/graph/schema.py +9 -0
- package/lattice_brain/graph/store.py +9 -0
- package/lattice_brain/graph/vector_index/selector.py +32 -2
- package/lattice_brain/ingestion/__init__.py +130 -0
- package/lattice_brain/ingestion/_contract.py +90 -0
- package/lattice_brain/ingestion/constants.py +127 -0
- package/lattice_brain/ingestion/folder_scan.py +57 -0
- package/lattice_brain/ingestion/folders.py +258 -0
- package/lattice_brain/ingestion/hashing.py +26 -0
- package/lattice_brain/ingestion/jobs_api.py +107 -0
- package/lattice_brain/ingestion/models.py +80 -0
- package/lattice_brain/ingestion/pipeline.py +486 -0
- package/lattice_brain/ingestion/quality.py +209 -0
- package/lattice_brain/ingestion/routing.py +295 -0
- package/lattice_brain/multimodal/__init__.py +164 -0
- package/lattice_brain/multimodal/audio.py +77 -0
- package/lattice_brain/multimodal/common.py +118 -0
- package/lattice_brain/{multimodal.py → multimodal/images.py} +22 -262
- package/lattice_brain/multimodal/ports.py +169 -0
- package/lattice_brain/multimodal/video.py +410 -0
- package/lattice_brain/portability/__init__.py +90 -0
- package/lattice_brain/portability/_contract.py +42 -0
- package/lattice_brain/portability/backups.py +338 -0
- package/lattice_brain/portability/bundles.py +136 -0
- package/lattice_brain/portability/constants.py +93 -0
- package/lattice_brain/portability/fsops.py +138 -0
- package/lattice_brain/portability/service.py +41 -0
- package/lattice_brain/portability/sharing.py +714 -0
- package/lattice_brain/runtime/__init__.py +1 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/lattice_brain/sealed_box.py +244 -0
- package/lattice_brain/synthesis.py +24 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/brain_intelligence.py +4 -0
- package/latticeai/api/chat.py +11 -0
- package/latticeai/api/chat_helpers.py +16 -3
- package/latticeai/api/chat_hybrid.py +32 -1
- package/latticeai/api/chronicle.py +63 -0
- package/latticeai/api/features.py +70 -0
- package/latticeai/api/local_files.py +102 -0
- package/latticeai/api/portability.py +39 -4
- package/latticeai/api/review_queue.py +126 -0
- package/latticeai/api/search.py +16 -2
- package/latticeai/core/agent/__init__.py +93 -0
- package/latticeai/core/agent/_contract.py +79 -0
- package/latticeai/core/agent/context.py +57 -0
- package/latticeai/core/agent/deps.py +125 -0
- package/latticeai/core/agent/execution.py +622 -0
- package/latticeai/core/agent/planning.py +145 -0
- package/latticeai/core/agent/recovery.py +157 -0
- package/latticeai/core/agent/runtime.py +210 -0
- package/latticeai/core/agent/verification.py +231 -0
- package/latticeai/core/config.py +4 -1
- package/latticeai/core/context_builder.py +6 -3
- package/latticeai/core/embedding_providers/__init__.py +151 -0
- package/latticeai/core/embedding_providers/base.py +199 -0
- package/latticeai/core/embedding_providers/captions.py +162 -0
- package/latticeai/core/embedding_providers/profiles.py +126 -0
- package/latticeai/core/embedding_providers/text.py +350 -0
- package/latticeai/core/embedding_providers/vision.py +352 -0
- package/latticeai/core/file_generation/__init__.py +115 -0
- package/latticeai/core/file_generation/bundles.py +76 -0
- package/latticeai/core/file_generation/extraction.py +154 -0
- package/latticeai/core/file_generation/inference.py +235 -0
- package/latticeai/core/file_generation/orchestration.py +152 -0
- package/latticeai/core/file_generation/prompting.py +117 -0
- package/latticeai/core/file_generation/repair.py +114 -0
- package/latticeai/core/file_generation/sanitize.py +61 -0
- package/latticeai/core/file_generation/validation.py +201 -0
- package/latticeai/core/legacy_compatibility.py +1 -1
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/messages.py +152 -0
- package/latticeai/core/model_compat.py +73 -2
- package/latticeai/core/workspace_os_constants.py +1 -1
- package/latticeai/integrations/telegram_bot/__init__.py +123 -0
- package/latticeai/integrations/telegram_bot/__main__.py +17 -0
- package/latticeai/integrations/telegram_bot/config.py +86 -0
- package/latticeai/integrations/telegram_bot/dispatch.py +311 -0
- package/latticeai/integrations/telegram_bot/flows.py +478 -0
- package/latticeai/integrations/telegram_bot/helpers.py +322 -0
- package/latticeai/integrations/telegram_bot/screens.py +394 -0
- package/latticeai/models/model_providers.py +12 -4
- package/latticeai/models/router/__init__.py +88 -0
- package/latticeai/models/router/_contract.py +66 -0
- package/latticeai/models/router/branding.py +56 -0
- package/latticeai/models/router/catalog.py +69 -0
- package/latticeai/models/router/documents.py +199 -0
- package/latticeai/models/router/errors.py +37 -0
- package/latticeai/models/router/generation.py +258 -0
- package/latticeai/models/router/loading.py +291 -0
- package/latticeai/models/router/local_models.py +85 -0
- package/latticeai/models/router/registry.py +147 -0
- package/latticeai/runtime/build_phases/__init__.py +82 -0
- package/latticeai/runtime/build_phases/features.py +407 -0
- package/latticeai/runtime/build_phases/foundation.py +555 -0
- package/latticeai/runtime/build_phases/web.py +492 -0
- package/latticeai/runtime/chat_wiring.py +4 -0
- package/latticeai/runtime/feature_toggle_wiring.py +163 -0
- package/latticeai/runtime/router_registration.py +11 -0
- package/latticeai/runtime/runtime_context.py +1 -0
- package/latticeai/services/app_context.py +8 -0
- package/latticeai/services/architecture_readiness.py +48 -19
- package/latticeai/services/automation_intelligence.py +22 -2
- package/latticeai/services/brain_intelligence/__init__.py +58 -0
- package/latticeai/services/brain_intelligence/_contract.py +71 -0
- package/latticeai/services/brain_intelligence/consistency.py +193 -0
- package/latticeai/services/brain_intelligence/constants.py +47 -0
- package/latticeai/services/brain_intelligence/digest.py +258 -0
- package/latticeai/services/brain_intelligence/health.py +331 -0
- package/latticeai/services/brain_intelligence/proposals.py +264 -0
- package/latticeai/services/brain_intelligence/sampling.py +84 -0
- package/latticeai/services/brain_intelligence/service.py +48 -0
- package/latticeai/services/chronicle.py +557 -0
- package/latticeai/services/command_center.py +10 -4
- package/latticeai/services/feature_toggles.py +502 -0
- package/latticeai/services/folder_watch.py +122 -1
- package/latticeai/services/hybrid_chat.py +56 -5
- package/latticeai/services/interop_bridges.py +978 -0
- package/latticeai/services/memory_service/__init__.py +52 -0
- package/latticeai/services/memory_service/_contract.py +100 -0
- package/latticeai/services/memory_service/brief.py +431 -0
- package/latticeai/services/memory_service/constants.py +57 -0
- package/latticeai/services/memory_service/maintenance.py +138 -0
- package/latticeai/services/memory_service/manager.py +186 -0
- package/latticeai/services/memory_service/proof.py +136 -0
- package/latticeai/services/memory_service/recall.py +225 -0
- package/latticeai/services/memory_service/service.py +48 -0
- package/latticeai/services/memory_service/stores.py +110 -0
- package/latticeai/services/model_capability_registry.py +434 -261
- package/latticeai/services/model_catalog.py +95 -61
- package/latticeai/services/model_recommendation.py +18 -11
- package/latticeai/services/model_runtime/__init__.py +322 -0
- package/latticeai/services/model_runtime/cloud.py +87 -0
- package/latticeai/services/model_runtime/download.py +282 -0
- package/latticeai/services/model_runtime/engines.py +341 -0
- package/latticeai/services/model_runtime/loading.py +178 -0
- package/latticeai/services/model_runtime/service.py +129 -0
- package/latticeai/services/model_runtime/state.py +131 -0
- package/latticeai/services/model_runtime/status.py +255 -0
- package/latticeai/services/multimodal_ports.py +26 -1
- package/latticeai/services/obsidian_bridge.py +16 -25
- package/latticeai/services/product_readiness.py +15 -7
- package/latticeai/services/search_service.py +149 -2
- package/latticeai/services/tool_dispatch.py +4 -0
- package/latticeai/setup/auto_setup.py +27 -30
- package/latticeai/setup/wizard/__init__.py +126 -0
- package/latticeai/setup/wizard/catalog.py +172 -0
- package/latticeai/setup/wizard/detect.py +323 -0
- package/latticeai/setup/wizard/install.py +348 -0
- package/latticeai/setup/wizard/paths.py +168 -0
- package/latticeai/setup/wizard/plans.py +74 -0
- package/latticeai/setup/wizard/recommend.py +320 -0
- package/package.json +6 -2
- package/scripts/bump_version.py +14 -0
- package/scripts/capture_release_evidence.mjs +33 -21
- package/scripts/check_current_release_docs.mjs +1 -1
- package/scripts/check_i18n_namespace_coverage.mjs +41 -4
- package/scripts/check_max_file_lines.mjs +102 -0
- package/scripts/check_release_evidence_bound.mjs +30 -15
- package/scripts/check_screenshot_pixel_delta.py +34 -4
- package/scripts/check_server_i18n.mjs +2 -0
- package/scripts/generate_rust_parity_fixtures.py +562 -0
- package/scripts/lib/mock_server_fingerprint.mjs +94 -0
- package/scripts/release_screen_claims.json +44 -2
- package/scripts/verify_hf_model_registry.py +253 -218
- package/src-tauri/Cargo.lock +361 -3
- package/src-tauri/Cargo.toml +6 -1
- package/src-tauri/src/backend.rs +349 -0
- package/src-tauri/src/folder.rs +33 -0
- package/src-tauri/src/main.rs +97 -399
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +41 -37
- package/static/app/assets/Act-yYpYnn0v.js +1 -0
- package/static/app/assets/AdminConsole-DL3Cr5pL.js +1 -0
- package/static/app/assets/{Brain-CzCsI1mi.js → Brain-C1HBN0Wf.js} +2 -2
- package/static/app/assets/BrainHome-DoXRhUUC.js +2 -0
- package/static/app/assets/BrainSignals-6yR6ir5t.js +1 -0
- package/static/app/assets/Capture-CFIRsFNE.js +1 -0
- package/static/app/assets/Chronicle-BZbEgiwN.js +1 -0
- package/static/app/assets/CommandPalette-D2pMxC2I.js +1 -0
- package/static/app/assets/Library-DwO3yZST.js +1 -0
- package/static/app/assets/{LivingBrain-BXMWIK_2.js → LivingBrain-Jn1GK0-S.js} +1 -1
- package/static/app/assets/ProductFlow-B-w1R4Oo.js +1 -0
- package/static/app/assets/ReviewCard-6B27X8Vg.js +3 -0
- package/static/app/assets/System-DW8F-2xL.js +1 -0
- package/static/app/assets/arrow-left-DXvKg9U6.js +1 -0
- package/static/app/assets/{bot-4BvN07ux.js → bot-IM_E_Y12.js} +1 -1
- package/static/app/assets/brain-Ci1CkWjM.js +1 -0
- package/static/app/assets/{button-CDjtnAoU.js → button-COwyqfHM.js} +1 -1
- package/static/app/assets/circle-check-DfInj-qD.js +1 -0
- package/static/app/assets/{circle-pause-D_RMn7tp.js → circle-pause-DEM4A1Y5.js} +1 -1
- package/static/app/assets/{circle-play-B5OpB8ae.js → circle-play-C9djDuLd.js} +1 -1
- package/static/app/assets/{cpu-BIlWInHf.js → cpu-DFdo1gw-.js} +1 -1
- package/static/app/assets/{download-BtjXfL3z.js → download-SnJL6oqk.js} +1 -1
- package/static/app/assets/{folder-open-DefMpxI2.js → folder-open-CqZeDkjE.js} +1 -1
- package/static/app/assets/{hard-drive-BQ8NZVkw.js → hard-drive-j1jJXYYf.js} +1 -1
- package/static/app/assets/{index-vtEfYvQY.css → index-BLPb5lmE.css} +1 -1
- package/static/app/assets/index-_u5iUHDr.js +10 -0
- package/static/app/assets/input-B0lPdRQZ.js +1 -0
- package/static/app/assets/link-2-CoFbooHS.js +1 -0
- package/static/app/assets/{permissionCopy-BqZ5tsgL.js → permissionCopy-BsyLxtao.js} +1 -1
- package/static/app/assets/primitives-DEbN-d6p.js +1 -0
- package/static/app/assets/search-BybIWPNd.js +1 -0
- package/static/app/assets/{share-2-D5zg_0fY.js → share-2-CVtZ_ewX.js} +1 -1
- package/static/app/assets/{shield-alert-B5pZzkUb.js → shield-alert-CBi2GNWM.js} +1 -1
- package/static/app/assets/{textarea-nEVIweKY.js → textarea-DNMpB5ih.js} +1 -1
- package/static/app/assets/{useFocusTrap-Cm99AHlz.js → useFocusTrap-C83t3GXF.js} +1 -1
- package/static/app/assets/useMutation-DtbJDoyz.js +1 -0
- package/static/app/assets/{useQuery-Dm__N6bL.js → useQuery-Dcp1OChy.js} +1 -1
- package/static/app/assets/utils-BlZr7Pd4.js +4 -0
- package/static/app/assets/workspace-jJY4RuAV.js +1 -0
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/lattice_brain/graph/_kg_common.py +0 -1331
- package/lattice_brain/graph/discovery_index.py +0 -1141
- package/lattice_brain/graph/retrieval.py +0 -1120
- package/lattice_brain/graph/retrieval_vector.py +0 -1293
- package/lattice_brain/ingestion.py +0 -1377
- package/lattice_brain/portability.py +0 -1210
- package/latticeai/core/agent.py +0 -1412
- package/latticeai/core/embedding_providers.py +0 -1196
- package/latticeai/core/file_generation.py +0 -1047
- package/latticeai/integrations/telegram_bot.py +0 -1390
- package/latticeai/models/router.py +0 -1007
- package/latticeai/runtime/build_phases.py +0 -1422
- package/latticeai/services/brain_intelligence.py +0 -967
- package/latticeai/services/memory_service.py +0 -1177
- package/latticeai/services/model_runtime.py +0 -1281
- package/latticeai/setup/wizard.py +0 -1277
- package/static/app/assets/Act-D0HWqtn0.js +0 -1
- package/static/app/assets/AdminConsole-D-QDW-A4.js +0 -1
- package/static/app/assets/BrainHome-Btns-_TA.js +0 -2
- package/static/app/assets/BrainSignals-2dHQNkns.js +0 -1
- package/static/app/assets/Capture-CT8v1StE.js +0 -1
- package/static/app/assets/CommandPalette-DoLXC2KH.js +0 -1
- package/static/app/assets/Library-DDoxFE5c.js +0 -1
- package/static/app/assets/ProductFlow-DOYf7JIs.js +0 -1
- package/static/app/assets/ReviewCard-COQsqidK.js +0 -3
- package/static/app/assets/System-BRllvYXd.js +0 -1
- package/static/app/assets/arrow-left-DnyMzss-.js +0 -1
- package/static/app/assets/brain-uMb_5hnO.js +0 -1
- package/static/app/assets/index-0AvoEBzJ.js +0 -10
- package/static/app/assets/input-B_5ZJ9oy.js +0 -1
- package/static/app/assets/primitives-CVwew78r.js +0 -1
- package/static/app/assets/search-DkhnOKZt.js +0 -1
- package/static/app/assets/utils-DcDMoZIe.js +0 -4
- package/static/app/assets/workspace-LtRRSKTf.js +0 -1
|
@@ -14,7 +14,7 @@ every capability is honestly ``None``.
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
16
|
import os
|
|
17
|
-
from typing import Any, Callable, Dict, Optional
|
|
17
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
18
18
|
|
|
19
19
|
from lattice_brain.ingestion import ALLOW_MULTIMODAL_ENV
|
|
20
20
|
from lattice_brain.multimodal import MODALITY_IMAGE, MultimodalPorts
|
|
@@ -65,11 +65,35 @@ def build_multimodal_ports(
|
|
|
65
65
|
captioner=vision_caption_port(captioner),
|
|
66
66
|
vision_embedder=resolved.as_port(),
|
|
67
67
|
transcriber=transcriber,
|
|
68
|
+
text_to_image_embedder=text_to_image_port(provider),
|
|
68
69
|
vision_model_id=provider.model_id if provider is not None else "",
|
|
69
70
|
vision_space=resolved.space,
|
|
70
71
|
)
|
|
71
72
|
|
|
72
73
|
|
|
74
|
+
def text_to_image_port(
|
|
75
|
+
provider: Any,
|
|
76
|
+
) -> Optional[Callable[[str], List[float]]]:
|
|
77
|
+
"""A *query-text* → image-space vector port, only from a shared-space model.
|
|
78
|
+
|
|
79
|
+
This is what lets a typed question reach a picture through the image index
|
|
80
|
+
instead of only through its OCR text. It exists as its own port precisely
|
|
81
|
+
because most vision models cannot do it: a CLIP image vector and a BGE text
|
|
82
|
+
vector are not comparable, and `VisionEmbeddingProvider.embed_batch` refuses
|
|
83
|
+
outright unless the model declares a shared space. An image-space model
|
|
84
|
+
therefore yields ``None`` here — the honest answer, and the one the search
|
|
85
|
+
surface reports rather than silently ranking on a meaningless number.
|
|
86
|
+
"""
|
|
87
|
+
if provider is None or not getattr(provider, "shares_text_space", False):
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
def _embed(query: str) -> List[float]:
|
|
91
|
+
vectors = provider.embed_batch([str(query or "")])
|
|
92
|
+
return [float(value) for value in (vectors[0] if vectors else [])]
|
|
93
|
+
|
|
94
|
+
return _embed
|
|
95
|
+
|
|
96
|
+
|
|
73
97
|
def describe_multimodal(ports: MultimodalPorts) -> Dict[str, Any]:
|
|
74
98
|
"""Operator-facing status: enabled, plus what is actually wired."""
|
|
75
99
|
return {"enabled": multimodal_enabled(), **ports.describe()}
|
|
@@ -84,4 +108,5 @@ __all__ = [
|
|
|
84
108
|
"build_multimodal_ports",
|
|
85
109
|
"describe_multimodal",
|
|
86
110
|
"multimodal_enabled",
|
|
111
|
+
"text_to_image_port",
|
|
87
112
|
]
|
|
@@ -35,7 +35,6 @@ be a lie in the summary.
|
|
|
35
35
|
|
|
36
36
|
from __future__ import annotations
|
|
37
37
|
|
|
38
|
-
import json
|
|
39
38
|
import os
|
|
40
39
|
import re
|
|
41
40
|
from dataclasses import dataclass, field
|
|
@@ -48,6 +47,7 @@ from urllib.parse import unquote
|
|
|
48
47
|
# store-extracted topic the same node instead of two nodes with one label.
|
|
49
48
|
from lattice_brain.graph.ingest import _scoped_slug_id
|
|
50
49
|
from lattice_brain.ingestion import IngestionItem
|
|
50
|
+
from latticeai.services.interop_bridges import edge_row, topic_row
|
|
51
51
|
|
|
52
52
|
SOURCE_TYPE = "obsidian"
|
|
53
53
|
NOTE_EXTENSIONS = frozenset({".md", ".markdown"})
|
|
@@ -567,15 +567,9 @@ class ObsidianVaultBridge:
|
|
|
567
567
|
"index": outcome.get("index"),
|
|
568
568
|
}
|
|
569
569
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
"from_node": from_id,
|
|
574
|
-
"to_node": to_id,
|
|
575
|
-
"type": relation,
|
|
576
|
-
"weight": 1.0,
|
|
577
|
-
"metadata_json": json.dumps(metadata, ensure_ascii=False),
|
|
578
|
-
}
|
|
570
|
+
# Row shapes are shared with every other bridge (v11.2.0): two copies of
|
|
571
|
+
# "what an edge row looks like" is two places to forget an encoding.
|
|
572
|
+
_edge_row = staticmethod(edge_row)
|
|
579
573
|
|
|
580
574
|
@staticmethod
|
|
581
575
|
def _topic_row(
|
|
@@ -586,21 +580,18 @@ class ObsidianVaultBridge:
|
|
|
586
580
|
owner: Optional[str],
|
|
587
581
|
workspace_id: Optional[str],
|
|
588
582
|
) -> Dict[str, Any]:
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
"
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
"metadata_json": json.dumps(metadata, ensure_ascii=False),
|
|
602
|
-
"raw_json": "{}",
|
|
603
|
-
}
|
|
583
|
+
return topic_row(
|
|
584
|
+
topic_id,
|
|
585
|
+
tag,
|
|
586
|
+
summary=f"Obsidian tag #{tag}",
|
|
587
|
+
metadata={
|
|
588
|
+
"topic": tag,
|
|
589
|
+
"source": SOURCE_TYPE,
|
|
590
|
+
"vault": vault,
|
|
591
|
+
"owner": owner,
|
|
592
|
+
"workspace_id": workspace_id,
|
|
593
|
+
},
|
|
594
|
+
)
|
|
604
595
|
|
|
605
596
|
|
|
606
597
|
__all__ = [
|
|
@@ -18,7 +18,7 @@ from typing import Any, Dict, List
|
|
|
18
18
|
|
|
19
19
|
from latticeai.services.architecture_readiness import architecture_readiness
|
|
20
20
|
|
|
21
|
-
PRODUCT_VERSION_TARGET = "11.
|
|
21
|
+
PRODUCT_VERSION_TARGET = "11.4.0"
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
@dataclass(frozen=True)
|
|
@@ -44,7 +44,10 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
44
44
|
"frontend/src/features/brain/BrainHome.tsx",
|
|
45
45
|
"frontend/src/App.tsx::brain-mobile-nav",
|
|
46
46
|
"latticeai/setup/auto_setup.py",
|
|
47
|
-
|
|
47
|
+
# v11.3.0: the wizard is a package (paths / detect / plans /
|
|
48
|
+
# catalog / recommend / install); the recommender is the piece
|
|
49
|
+
# first-run actually shows.
|
|
50
|
+
"latticeai/setup/wizard/recommend.py",
|
|
48
51
|
],
|
|
49
52
|
),
|
|
50
53
|
ProductGate(
|
|
@@ -64,8 +67,11 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
64
67
|
"latticeai/api/chat_intents.py::direct_write_file",
|
|
65
68
|
# v9.9.2 ArtifactWritePipeline: every write path shares the same
|
|
66
69
|
# extract → validate → repair guarantee, proven by the FG harness.
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
# v11.3.0: both modules became packages — the write-side door is
|
|
71
|
+
# its own submodule, and the agent's use of it lives in the
|
|
72
|
+
# EXECUTE phase.
|
|
73
|
+
"latticeai/core/file_generation/sanitize.py::sanitize_write_content",
|
|
74
|
+
"latticeai/core/agent/execution.py::content_sanitize",
|
|
69
75
|
"tests/unit/test_artifact_write_scenarios.py::test_fg06_agent_dispatch_strips_fences_from_write_file_content",
|
|
70
76
|
"tests/unit/test_chat_telegram_decoupling.py::test_chat_file_creation_intent_writes_real_file",
|
|
71
77
|
],
|
|
@@ -110,12 +116,14 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
110
116
|
f"docs/CHANGELOG.md::## [{PRODUCT_VERSION_TARGET}]",
|
|
111
117
|
"FEATURE_STATUS.md",
|
|
112
118
|
f"RELEASE_NOTES_v{PRODUCT_VERSION_TARGET}.md",
|
|
113
|
-
|
|
119
|
+
# v11.3.0: the single-agent loop is a package; the composed
|
|
120
|
+
# class and its boundary contract live in the runtime half.
|
|
121
|
+
"latticeai/core/agent/runtime.py::SingleAgentRuntime",
|
|
114
122
|
"lattice_brain/runtime/agent_runtime.py::class AgentRuntime",
|
|
115
123
|
"lattice_brain/runtime/contracts.py::runtime-boundary/v1",
|
|
116
124
|
"lattice_brain/runtime/contracts.py::RuntimeBoundaryProtocol",
|
|
117
125
|
"lattice_brain/runtime/agent_runtime.py::def boundary",
|
|
118
|
-
"latticeai/core/agent.py::def boundary",
|
|
126
|
+
"latticeai/core/agent/runtime.py::def boundary",
|
|
119
127
|
"latticeai/services/architecture_readiness.py::lattice-architecture-contract/v1",
|
|
120
128
|
"latticeai/services/tool_dispatch.py::rollback_file",
|
|
121
129
|
],
|
|
@@ -148,7 +156,7 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
148
156
|
"scripts/brain_quality_eval.py",
|
|
149
157
|
"scripts/product_readiness.py",
|
|
150
158
|
"tests/unit/test_product_readiness.py",
|
|
151
|
-
"tests/visual/v3.spec.js::Brain Chat Home",
|
|
159
|
+
"tests/visual/v3.surfaces.spec.js::Brain Chat Home",
|
|
152
160
|
".github/workflows/ci.yml::scripts/product_readiness.py",
|
|
153
161
|
".github/workflows/release.yml::npm run lint",
|
|
154
162
|
],
|
|
@@ -8,9 +8,11 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
from dataclasses import dataclass
|
|
10
10
|
from datetime import datetime
|
|
11
|
-
from typing import Any, Dict, List, Mapping, Optional
|
|
11
|
+
from typing import Any, Dict, List, Mapping, Optional, Tuple
|
|
12
12
|
|
|
13
|
+
from lattice_brain.gates import FeatureGate
|
|
13
14
|
from lattice_brain.graph._kg_fsutil import _parse_iso, _recency_score
|
|
15
|
+
from lattice_brain.graph.image_vectors import DEFAULT_IMAGE_FUSION_WEIGHT
|
|
14
16
|
from lattice_brain.graph.retrieval_policy import resolve_policy
|
|
15
17
|
|
|
16
18
|
DEFAULT_HYBRID_WEIGHTS = {
|
|
@@ -19,6 +21,33 @@ DEFAULT_HYBRID_WEIGHTS = {
|
|
|
19
21
|
"graph": 0.25,
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
# ── text query → image space (v11.2.0) ───────────────────────────────────────
|
|
25
|
+
# 11.1.0 shipped image late fusion as API-only, because the two vector spaces
|
|
26
|
+
# are not comparable and nothing produced a query vector for the image index.
|
|
27
|
+
# A *shared-space* vision model can produce one, and this is the switch that
|
|
28
|
+
# lets the search API do it automatically. Off by default and resolved when
|
|
29
|
+
# asked, so a settings toggle can move it without a restart; with it off the
|
|
30
|
+
# hybrid response is byte-identical to 11.1.0's.
|
|
31
|
+
TEXT_IMAGE_FUSION_ENV = "LATTICEAI_TEXT_IMAGE_FUSION"
|
|
32
|
+
IMAGE_QUERY_FUSION_GATE = FeatureGate(
|
|
33
|
+
TEXT_IMAGE_FUSION_ENV,
|
|
34
|
+
default=False,
|
|
35
|
+
name="text_image_fusion",
|
|
36
|
+
detail=(
|
|
37
|
+
"Typed questions can also be scored against the image index when a "
|
|
38
|
+
"shared-space vision model is configured."
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
IMAGE_FUSION_UNAVAILABLE = (
|
|
42
|
+
"no shared-space vision model is configured, so a typed question cannot be "
|
|
43
|
+
"scored against image vectors; pictures are still found through their OCR "
|
|
44
|
+
"text and captions"
|
|
45
|
+
)
|
|
46
|
+
IMAGE_FUSION_DISABLED = (
|
|
47
|
+
"automatic image fusion is off for this install "
|
|
48
|
+
f"({TEXT_IMAGE_FUSION_ENV}); the caller may still supply an image vector"
|
|
49
|
+
)
|
|
50
|
+
|
|
22
51
|
|
|
23
52
|
def _clean(text: Any, limit: int = 1000) -> str:
|
|
24
53
|
return " ".join(str(text or "").split())[:limit]
|
|
@@ -31,6 +60,115 @@ def _result_key(result: Mapping[str, Any]) -> str:
|
|
|
31
60
|
@dataclass
|
|
32
61
|
class SearchService:
|
|
33
62
|
graph_store: Any
|
|
63
|
+
#: ``(query_text) -> image-space vector``. Defaults to the port the store
|
|
64
|
+
#: already carries (``multimodal_ports.text_to_image_embedder``), so no new
|
|
65
|
+
#: wiring is needed; the field exists so a test — or an install with its
|
|
66
|
+
#: own encoder — can supply one directly.
|
|
67
|
+
image_query_embedder: Any = None
|
|
68
|
+
|
|
69
|
+
# ── image-space query channel (v11.2.0) ──────────────────────────────
|
|
70
|
+
def image_query_status(self) -> Dict[str, Any]:
|
|
71
|
+
"""Whether a typed question can reach the image index here, and why not."""
|
|
72
|
+
port, detail = self._image_query_port()
|
|
73
|
+
return {
|
|
74
|
+
"available": port is not None,
|
|
75
|
+
"gate": IMAGE_QUERY_FUSION_GATE.describe(),
|
|
76
|
+
"detail": detail,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
def _image_query_port(self) -> Tuple[Any, Optional[str]]:
|
|
80
|
+
"""The text→image port and, when there is none, the honest reason."""
|
|
81
|
+
if self.image_query_embedder is not None:
|
|
82
|
+
return self.image_query_embedder, None
|
|
83
|
+
ports = getattr(self.graph_store, "multimodal_ports", None)
|
|
84
|
+
port = getattr(ports, "text_to_image_embedder", None)
|
|
85
|
+
return (port, None) if port is not None else (None, IMAGE_FUSION_UNAVAILABLE)
|
|
86
|
+
|
|
87
|
+
def _image_query_vector(self, query: str) -> Tuple[Optional[List[float]], Optional[str]]:
|
|
88
|
+
port, detail = self._image_query_port()
|
|
89
|
+
if port is None:
|
|
90
|
+
return None, detail
|
|
91
|
+
try:
|
|
92
|
+
vector = [float(value) for value in (port(query) or [])]
|
|
93
|
+
except Exception as exc: # noqa: BLE001 — a broken encoder never fails a search
|
|
94
|
+
return None, f"the vision model could not embed the query: {exc}"
|
|
95
|
+
if not vector:
|
|
96
|
+
return None, "the vision model returned an empty query vector"
|
|
97
|
+
return vector, None
|
|
98
|
+
|
|
99
|
+
def _image_channel(
|
|
100
|
+
self, query: str, matches: List[Dict[str, Any]], *, requested: bool, limit: int
|
|
101
|
+
) -> Optional[Dict[str, Any]]:
|
|
102
|
+
"""Late-fuse the image index into an already-ranked match list.
|
|
103
|
+
|
|
104
|
+
Returns ``None`` when the caller did not ask, which is what keeps the
|
|
105
|
+
response byte-identical for everyone who did not opt in. When it *was*
|
|
106
|
+
asked for and could not run, it returns the reason rather than silently
|
|
107
|
+
producing the same answer as before.
|
|
108
|
+
"""
|
|
109
|
+
if not requested:
|
|
110
|
+
return None
|
|
111
|
+
report: Dict[str, Any] = {
|
|
112
|
+
"requested": True,
|
|
113
|
+
"applied": False,
|
|
114
|
+
"weight": DEFAULT_IMAGE_FUSION_WEIGHT,
|
|
115
|
+
"candidates": 0,
|
|
116
|
+
"fused": 0,
|
|
117
|
+
"detail": None,
|
|
118
|
+
}
|
|
119
|
+
if not IMAGE_QUERY_FUSION_GATE.enabled():
|
|
120
|
+
report["detail"] = IMAGE_FUSION_DISABLED
|
|
121
|
+
return {"image_fusion": report}
|
|
122
|
+
vector, detail = self._image_query_vector(query)
|
|
123
|
+
if vector is None:
|
|
124
|
+
report["detail"] = detail
|
|
125
|
+
return {"image_fusion": report}
|
|
126
|
+
from lattice_brain.graph.image_vectors import image_similarity_search
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
found = image_similarity_search(
|
|
130
|
+
self.graph_store, vector, top_k=max(1, int(limit) * 2)
|
|
131
|
+
)
|
|
132
|
+
except Exception as exc: # noqa: BLE001 — the text answer must survive
|
|
133
|
+
report["detail"] = f"image index unavailable: {exc}"
|
|
134
|
+
return {"image_fusion": report}
|
|
135
|
+
report["candidates"] = int(found.get("candidates") or 0)
|
|
136
|
+
scores = {
|
|
137
|
+
str(match["node_id"]): float(match["score"])
|
|
138
|
+
for match in found.get("matches") or []
|
|
139
|
+
}
|
|
140
|
+
report["fused"] = self._blend_image_scores(matches, scores)
|
|
141
|
+
report["applied"] = True
|
|
142
|
+
report["detail"] = found.get("detail")
|
|
143
|
+
return {"image_fusion": report}
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def _blend_image_scores(
|
|
147
|
+
matches: List[Dict[str, Any]],
|
|
148
|
+
scores: Dict[str, float],
|
|
149
|
+
*,
|
|
150
|
+
weight: float = DEFAULT_IMAGE_FUSION_WEIGHT,
|
|
151
|
+
) -> int:
|
|
152
|
+
"""The graph layer's blend, over this layer's ``source_scores`` shape.
|
|
153
|
+
|
|
154
|
+
Late fusion by construction: the two rankings were produced
|
|
155
|
+
independently and only the final numbers meet, so neither space is ever
|
|
156
|
+
asked to interpret the other's.
|
|
157
|
+
"""
|
|
158
|
+
touched = 0
|
|
159
|
+
for match in matches:
|
|
160
|
+
raw = scores.get(_result_key(match))
|
|
161
|
+
if raw is None:
|
|
162
|
+
continue
|
|
163
|
+
touched += 1
|
|
164
|
+
match.setdefault("source_scores", {})["image"] = round(raw, 6)
|
|
165
|
+
blended = (1.0 - weight) * float(match.get("score") or 0.0) + weight * raw
|
|
166
|
+
match["score"] = round(blended, 6)
|
|
167
|
+
if touched:
|
|
168
|
+
matches.sort(key=lambda item: float(item.get("score") or 0.0), reverse=True)
|
|
169
|
+
for rank, match in enumerate(matches, start=1):
|
|
170
|
+
match["rank"] = rank
|
|
171
|
+
return touched
|
|
34
172
|
|
|
35
173
|
def _require_graph(self) -> Any:
|
|
36
174
|
if self.graph_store is None:
|
|
@@ -410,6 +548,7 @@ class SearchService:
|
|
|
410
548
|
weights: Optional[Mapping[str, float]] = None,
|
|
411
549
|
allowed_workspaces=None,
|
|
412
550
|
include_legacy_global: bool = False,
|
|
551
|
+
image_fusion: bool = False,
|
|
413
552
|
) -> Dict[str, Any]:
|
|
414
553
|
# Single retrieval policy (review Wave 0.2): when the caller does not
|
|
415
554
|
# pin explicit weights, resolve the query class + per-class channel
|
|
@@ -513,7 +652,10 @@ class SearchService:
|
|
|
513
652
|
}
|
|
514
653
|
if query_class is not None:
|
|
515
654
|
match["fusion"]["query_class"] = query_class
|
|
516
|
-
|
|
655
|
+
multimodal = self._image_channel(
|
|
656
|
+
query, matches, requested=image_fusion, limit=limit,
|
|
657
|
+
)
|
|
658
|
+
report: Dict[str, Any] = {
|
|
517
659
|
"query": query,
|
|
518
660
|
"mode": "hybrid",
|
|
519
661
|
"query_class": query_class,
|
|
@@ -529,6 +671,11 @@ class SearchService:
|
|
|
529
671
|
},
|
|
530
672
|
"matches": matches,
|
|
531
673
|
}
|
|
674
|
+
# Additive key only when the caller asked, so an untouched response is
|
|
675
|
+
# the one 11.1.0 returned.
|
|
676
|
+
if multimodal is not None:
|
|
677
|
+
report["multimodal"] = multimodal
|
|
678
|
+
return report
|
|
532
679
|
|
|
533
680
|
def graph(
|
|
534
681
|
self,
|
|
@@ -486,6 +486,7 @@ def build_agent_runtime(
|
|
|
486
486
|
brain_memory: Any = None,
|
|
487
487
|
dispatch_service: ToolDispatchService = DEFAULT_TOOL_DISPATCH_SERVICE,
|
|
488
488
|
permission_mode: Any = None,
|
|
489
|
+
self_model_summary: Any = None,
|
|
489
490
|
) -> SingleAgentRuntime:
|
|
490
491
|
ensure_agent_root()
|
|
491
492
|
mode = permission_mode if permission_mode is not None else dispatch_service.permission_mode
|
|
@@ -513,6 +514,9 @@ def build_agent_runtime(
|
|
|
513
514
|
hooks=hooks,
|
|
514
515
|
brain_memory=brain_memory,
|
|
515
516
|
permission_mode=mode,
|
|
517
|
+
# v11.2.0: what the Brain knows about its owner reaches the agent loop.
|
|
518
|
+
# ``None`` keeps the pre-11.2.0 prompt bytes exactly.
|
|
519
|
+
self_model_summary=self_model_summary,
|
|
516
520
|
)
|
|
517
521
|
return SingleAgentRuntime(deps)
|
|
518
522
|
|
|
@@ -399,36 +399,36 @@ class Recommendation:
|
|
|
399
399
|
return asdict(self)
|
|
400
400
|
|
|
401
401
|
|
|
402
|
-
# 모델
|
|
402
|
+
# 모델 카탈로그 — RAM/VRAM 내림차순. 첫 번째로 조건을 만족하는 항목이 선택된다.
|
|
403
|
+
# 모든 repo id 는 2026-08-10 Hugging Face API 로 확인했다(존재·비gated·정확한 대소문자).
|
|
404
|
+
# OS 오버헤드(~4-6 GB) + KV 캐시 여유를 감안한 보수적 RAM 임계값.
|
|
403
405
|
_MODEL_CATALOG: List[Dict[str, Any]] = [
|
|
404
|
-
# (
|
|
405
|
-
# OS 오버헤드(~4-6 GB) + KV 캐시 여유를 감안한 보수적 RAM 임계값
|
|
406
|
+
# 대형 (48GB+): 최상위 dense / Gemma 4 최대 모델
|
|
406
407
|
{"ram": 64 * 1024, "vram": 32 * 1024,
|
|
407
408
|
"id": "mlx-community/gemma-4-31b-it-4bit", "q": "4bit", "multimodal": True},
|
|
408
|
-
{"ram": 64 * 1024, "vram": 32 * 1024,
|
|
409
|
-
"id": "Qwen/Qwen3-VL-30B-A3B-Instruct", "q": "q4_K_M", "multimodal": True},
|
|
410
409
|
{"ram": 48 * 1024, "vram": 24 * 1024,
|
|
411
|
-
"id": "mlx-community/
|
|
410
|
+
"id": "mlx-community/Qwen3.6-27B-4bit", "q": "4bit", "multimodal": True},
|
|
411
|
+
# MoE (32GB+)
|
|
412
|
+
{"ram": 40 * 1024, "vram": 24 * 1024,
|
|
413
|
+
"id": "mlx-community/Qwen3.6-35B-A3B-4bit", "q": "4bit", "multimodal": True},
|
|
412
414
|
{"ram": 32 * 1024, "vram": 16 * 1024,
|
|
413
415
|
"id": "mlx-community/gemma-4-26b-a4b-it-4bit", "q": "4bit", "multimodal": True},
|
|
414
|
-
|
|
415
|
-
"id": "Qwen/Qwen3-VL-30B-A3B-Instruct", "q": "q4_K_M", "multimodal": True},
|
|
416
|
-
{"ram": 24 * 1024, "vram": 12 * 1024,
|
|
417
|
-
"id": "mlx-community/Llama-4-Scout-17B-16E-Instruct-4bit", "q": "4bit", "multimodal": True},
|
|
418
|
-
{"ram": 16 * 1024, "vram": 8 * 1024,
|
|
419
|
-
"id": "mlx-community/gemma-4-12b-it-4bit", "q": "4bit", "multimodal": True},
|
|
420
|
-
{"ram": 32 * 1024, "vram": 16 * 1024,
|
|
421
|
-
"id": "Qwen/Qwen3-VL-8B-Instruct", "q": "q5_K_M", "multimodal": True},
|
|
416
|
+
# 범용 (24GB)
|
|
422
417
|
{"ram": 24 * 1024, "vram": 12 * 1024,
|
|
423
|
-
"id": "
|
|
418
|
+
"id": "mlx-community/gpt-oss-20b-MXFP4-Q8", "q": "MXFP4-Q8", "multimodal": False},
|
|
419
|
+
# 중형 (16GB)
|
|
424
420
|
{"ram": 16 * 1024, "vram": 8 * 1024,
|
|
425
|
-
"id": "
|
|
421
|
+
"id": "mlx-community/gemma-4-12B-it-4bit", "q": "4bit", "multimodal": True},
|
|
426
422
|
{"ram": 12 * 1024, "vram": 6 * 1024,
|
|
427
|
-
"id": "
|
|
423
|
+
"id": "mlx-community/Qwen3.5-9B-MLX-4bit", "q": "4bit", "multimodal": True},
|
|
424
|
+
# 경량 (10GB) / 초경량 (8GB 이하)
|
|
425
|
+
{"ram": 10 * 1024, "vram": 6 * 1024,
|
|
426
|
+
"id": "mlx-community/gemma-4-e4b-it-4bit", "q": "4bit", "multimodal": True},
|
|
428
427
|
{"ram": 8 * 1024, "vram": 4 * 1024,
|
|
429
|
-
"id": "
|
|
428
|
+
"id": "mlx-community/gemma-4-e2b-it-4bit", "q": "4bit", "multimodal": True},
|
|
429
|
+
# 최소 사양: 사진은 못 읽지만 한국어로 대답은 한다.
|
|
430
430
|
{"ram": 4 * 1024, "vram": 0,
|
|
431
|
-
"id": "
|
|
431
|
+
"id": "mlx-community/LFM2.5-2.6B-4bit", "q": "4bit", "multimodal": False},
|
|
432
432
|
]
|
|
433
433
|
|
|
434
434
|
|
|
@@ -622,17 +622,14 @@ def plan(profile: SystemProfile, rec: Recommendation) -> InstallPlan:
|
|
|
622
622
|
# 모델 가중치 풀
|
|
623
623
|
model_command = ["huggingface-cli", "download", rec.model_id, "--quiet"]
|
|
624
624
|
if rec.runtime == "ollama":
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
model_command = ["ollama", "pull", "qwen3-vl:8b"]
|
|
634
|
-
elif "qwen3-vl-4b" in lower:
|
|
635
|
-
model_command = ["ollama", "pull", "qwen3-vl:4b"]
|
|
625
|
+
# Local import: this module keeps a stdlib-only import graph so it can be
|
|
626
|
+
# run before the app is wired. The alias table is the single source of
|
|
627
|
+
# truth for per-engine repo ids — the old hardcoded if/elif chain here
|
|
628
|
+
# drifted from it and still named Llama 4 Scout and Qwen3-VL.
|
|
629
|
+
from latticeai.services.model_catalog import MODEL_ENGINE_ALIASES
|
|
630
|
+
ollama_target = (MODEL_ENGINE_ALIASES.get(rec.model_id.lower()) or {}).get("ollama")
|
|
631
|
+
if ollama_target:
|
|
632
|
+
model_command = ["ollama", "pull", ollama_target]
|
|
636
633
|
elif rec.runtime == "lmstudio":
|
|
637
634
|
model_command = ["lms", "get", rec.model_id]
|
|
638
635
|
steps.append(InstallStep(
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Smart Setup Wizard — Environment Scanner, Recommender & Auto-Installer
|
|
3
|
+
Detects hardware, tools, and API keys; returns tailored recommendations;
|
|
4
|
+
streams SSE installation progress.
|
|
5
|
+
|
|
6
|
+
Formerly the root ``setup.py``; renamed in v4 so it no longer collides with
|
|
7
|
+
the setuptools build entrypoint and actually ships in the wheel
|
|
8
|
+
(``pyproject.toml`` py-modules). Packaging is owned entirely by
|
|
9
|
+
``pyproject.toml`` — there is deliberately no root ``setup.py``.
|
|
10
|
+
|
|
11
|
+
Split into cohesive submodules in v11.3.0 (no behaviour change): ``paths``
|
|
12
|
+
(PATH repair + binary lookup + the module-level ``COMMON_PATH_DIRS``),
|
|
13
|
+
``detect`` (hardware/OS/tool probes and ``scan_environment``), ``plans``
|
|
14
|
+
(SSE framing + confirmation-token command plans), ``catalog`` (model tables),
|
|
15
|
+
``recommend`` (``get_recommendations``) and ``install`` (verify/repair and the
|
|
16
|
+
SSE ``install_stream``). This module re-exports every name the single file
|
|
17
|
+
exposed, so ``latticeai.setup.wizard.X`` keeps working.
|
|
18
|
+
|
|
19
|
+
Stubbing note: rebinding one of these names *here* changes only this module's
|
|
20
|
+
name. The submodule that calls it holds its own reference, so a test standing
|
|
21
|
+
in for a helper patches the submodule that uses it.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
# The single file had no ``__all__``, so its public surface was "every module
|
|
27
|
+
# global" — including the names it imported for its own use. Every re-export
|
|
28
|
+
# below therefore uses the redundant-alias form: it reproduces exactly that
|
|
29
|
+
# surface, and it marks each name as deliberate rather than a leftover import.
|
|
30
|
+
from latticeai.core.quiet import quiet as quiet
|
|
31
|
+
from latticeai.services.process_audit import (
|
|
32
|
+
CommandConfirmationError as CommandConfirmationError,
|
|
33
|
+
)
|
|
34
|
+
from latticeai.services.process_audit import (
|
|
35
|
+
append_process_audit_event as append_process_audit_event,
|
|
36
|
+
)
|
|
37
|
+
from latticeai.services.process_audit import command_plan as command_plan
|
|
38
|
+
from latticeai.services.process_audit import (
|
|
39
|
+
command_plan_for_commands as command_plan_for_commands,
|
|
40
|
+
)
|
|
41
|
+
from latticeai.services.process_audit import (
|
|
42
|
+
require_command_confirmation as require_command_confirmation,
|
|
43
|
+
)
|
|
44
|
+
from latticeai.services.setup_detection import detect_cuda as detect_cuda
|
|
45
|
+
from latticeai.services.setup_detection import detect_tools as detect_tools
|
|
46
|
+
from latticeai.services.setup_detection import (
|
|
47
|
+
detect_wsl_from_text as detect_wsl_from_text,
|
|
48
|
+
)
|
|
49
|
+
from latticeai.setup.wizard.catalog import (
|
|
50
|
+
_BEST_MODEL_TIERS as _BEST_MODEL_TIERS,
|
|
51
|
+
)
|
|
52
|
+
from latticeai.setup.wizard.catalog import (
|
|
53
|
+
_CROSS_PLATFORM_MODEL_CATALOG as _CROSS_PLATFORM_MODEL_CATALOG,
|
|
54
|
+
)
|
|
55
|
+
from latticeai.setup.wizard.catalog import (
|
|
56
|
+
_MODEL_CATALOG as _MODEL_CATALOG,
|
|
57
|
+
)
|
|
58
|
+
from latticeai.setup.wizard.catalog import (
|
|
59
|
+
_VERSIONED_MODEL_PATTERNS as _VERSIONED_MODEL_PATTERNS,
|
|
60
|
+
)
|
|
61
|
+
from latticeai.setup.wizard.catalog import (
|
|
62
|
+
_best_model_for_engine as _best_model_for_engine,
|
|
63
|
+
)
|
|
64
|
+
from latticeai.setup.wizard.catalog import (
|
|
65
|
+
_catalog_row_family_version as _catalog_row_family_version,
|
|
66
|
+
)
|
|
67
|
+
from latticeai.setup.wizard.catalog import (
|
|
68
|
+
_filter_lower_family_versions as _filter_lower_family_versions,
|
|
69
|
+
)
|
|
70
|
+
from latticeai.setup.wizard.catalog import (
|
|
71
|
+
_version_tuple as _version_tuple,
|
|
72
|
+
)
|
|
73
|
+
from latticeai.setup.wizard.detect import _cmd as _cmd
|
|
74
|
+
from latticeai.setup.wizard.detect import _detect_api_keys as _detect_api_keys
|
|
75
|
+
from latticeai.setup.wizard.detect import _detect_chip as _detect_chip
|
|
76
|
+
from latticeai.setup.wizard.detect import _detect_cpu as _detect_cpu
|
|
77
|
+
from latticeai.setup.wizard.detect import _detect_cuda as _detect_cuda
|
|
78
|
+
from latticeai.setup.wizard.detect import (
|
|
79
|
+
_detect_disk_free_gb as _detect_disk_free_gb,
|
|
80
|
+
)
|
|
81
|
+
from latticeai.setup.wizard.detect import _detect_gpu as _detect_gpu
|
|
82
|
+
from latticeai.setup.wizard.detect import _detect_mlx as _detect_mlx
|
|
83
|
+
from latticeai.setup.wizard.detect import _detect_ram_gb as _detect_ram_gb
|
|
84
|
+
from latticeai.setup.wizard.detect import _detect_tools as _detect_tools
|
|
85
|
+
from latticeai.setup.wizard.detect import _detect_wsl as _detect_wsl
|
|
86
|
+
from latticeai.setup.wizard.detect import (
|
|
87
|
+
_parse_windows_video_controllers as _parse_windows_video_controllers,
|
|
88
|
+
)
|
|
89
|
+
from latticeai.setup.wizard.detect import scan_environment as scan_environment
|
|
90
|
+
from latticeai.setup.wizard.install import _brew_install as _brew_install
|
|
91
|
+
from latticeai.setup.wizard.install import _pip_install as _pip_install
|
|
92
|
+
from latticeai.setup.wizard.install import _repair_action as _repair_action
|
|
93
|
+
from latticeai.setup.wizard.install import _verify_action as _verify_action
|
|
94
|
+
from latticeai.setup.wizard.install import _verify_binary as _verify_binary
|
|
95
|
+
from latticeai.setup.wizard.install import _wait_for_binary as _wait_for_binary
|
|
96
|
+
from latticeai.setup.wizard.install import install_stream as install_stream
|
|
97
|
+
from latticeai.setup.wizard.install import open_url as open_url
|
|
98
|
+
from latticeai.setup.wizard.paths import COMMON_PATH_DIRS as COMMON_PATH_DIRS
|
|
99
|
+
from latticeai.setup.wizard.paths import OFFICIAL_DOWNLOADS as OFFICIAL_DOWNLOADS
|
|
100
|
+
from latticeai.setup.wizard.paths import PACKAGE_MODULES as PACKAGE_MODULES
|
|
101
|
+
from latticeai.setup.wizard.paths import (
|
|
102
|
+
WINDOWS_BINARY_CANDIDATES as WINDOWS_BINARY_CANDIDATES,
|
|
103
|
+
)
|
|
104
|
+
from latticeai.setup.wizard.paths import _component_detail as _component_detail
|
|
105
|
+
from latticeai.setup.wizard.paths import _merge_path_dirs as _merge_path_dirs
|
|
106
|
+
from latticeai.setup.wizard.paths import _module_available as _module_available
|
|
107
|
+
from latticeai.setup.wizard.paths import _package_module as _package_module
|
|
108
|
+
from latticeai.setup.wizard.paths import _persist_extra_path as _persist_extra_path
|
|
109
|
+
from latticeai.setup.wizard.paths import _project_env_file as _project_env_file
|
|
110
|
+
from latticeai.setup.wizard.paths import _update_env_file as _update_env_file
|
|
111
|
+
from latticeai.setup.wizard.paths import _which_any as _which_any
|
|
112
|
+
from latticeai.setup.wizard.paths import _which_detail as _which_detail
|
|
113
|
+
from latticeai.setup.wizard.paths import repair_path_for as repair_path_for
|
|
114
|
+
from latticeai.setup.wizard.plans import _action_command_plan as _action_command_plan
|
|
115
|
+
from latticeai.setup.wizard.plans import _action_commands as _action_commands
|
|
116
|
+
from latticeai.setup.wizard.plans import _attach_action_plan as _attach_action_plan
|
|
117
|
+
from latticeai.setup.wizard.plans import (
|
|
118
|
+
_hydrate_install_actions as _hydrate_install_actions,
|
|
119
|
+
)
|
|
120
|
+
from latticeai.setup.wizard.plans import _sse as _sse
|
|
121
|
+
from latticeai.setup.wizard.plans import (
|
|
122
|
+
_verify_action_confirmation as _verify_action_confirmation,
|
|
123
|
+
)
|
|
124
|
+
from latticeai.setup.wizard.recommend import (
|
|
125
|
+
get_recommendations as get_recommendations,
|
|
126
|
+
)
|