ltcai 8.2.0 → 8.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 +27 -19
- package/docs/CHANGELOG.md +59 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +43 -0
- package/docs/DEVELOPMENT.md +8 -8
- package/docs/LEGACY_COMPATIBILITY.md +22 -2
- package/docs/ONBOARDING.md +38 -0
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +5 -4
- package/docs/kg-schema.md +3 -3
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/graph/ingest.py +40 -8
- package/lattice_brain/runtime/agent_runtime.py +22 -37
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/lattice_brain/workflow.py +26 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/chat.py +230 -51
- package/latticeai/api/knowledge_graph.py +33 -0
- package/latticeai/api/local_files.py +2 -0
- package/latticeai/api/tools.py +1 -0
- package/latticeai/api/workflow_designer.py +5 -4
- package/latticeai/core/legacy_compatibility.py +174 -0
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/services/architecture_readiness.py +37 -3
- package/latticeai/services/model_catalog.py +6 -0
- package/latticeai/services/model_engines.py +12 -21
- package/latticeai/services/model_runtime.py +17 -23
- package/latticeai/services/product_readiness.py +45 -14
- package/llm_router.py +7 -28
- package/mcp_registry.py +7 -24
- package/package.json +1 -1
- package/scripts/pts-claudecode-discord-bridge.mjs +2 -1
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +10 -10
- package/static/app/assets/{Act-D9jIknFd.js → Act-D5mo4tE4.js} +1 -1
- package/static/app/assets/{Brain-CFOtWbPN.js → Brain-BVWyQw8A.js} +1 -1
- package/static/app/assets/{Capture-Q4WYzwr5.js → Capture-C1R6GT0t.js} +1 -1
- package/static/app/assets/{Library-C5Q2yWee.js → Library-C2wIxpTs.js} +1 -1
- package/static/app/assets/{System-BLbjdr1_.js → System-DE5GRyQR.js} +1 -1
- package/static/app/assets/{index-BqammyNu.js → index-CoiuIFFP.js} +3 -3
- package/static/app/assets/{primitives-Br8uSfZ4.js → primitives-BdsUNXa6.js} +1 -1
- package/static/app/assets/{textarea-BnhNs1_X.js → textarea-e7qaj6Hm.js} +1 -1
- package/static/app/index.html +1 -1
- package/static/sw.js +1 -1
|
@@ -46,6 +46,7 @@ def create_local_files_router(
|
|
|
46
46
|
require_graph,
|
|
47
47
|
static_dir: Path,
|
|
48
48
|
local_kg_watcher,
|
|
49
|
+
ingestion_pipeline=None,
|
|
49
50
|
hooks=None,
|
|
50
51
|
data_dir: Optional[Path] = None,
|
|
51
52
|
allowed_workspaces_for=None,
|
|
@@ -212,6 +213,7 @@ def create_local_files_router(
|
|
|
212
213
|
require_user=require_user,
|
|
213
214
|
static_dir=static_dir,
|
|
214
215
|
allowed_workspaces_for=allowed_workspaces_for,
|
|
216
|
+
ingestion_pipeline=ingestion_pipeline,
|
|
215
217
|
)
|
|
216
218
|
)
|
|
217
219
|
|
package/latticeai/api/tools.py
CHANGED
|
@@ -488,6 +488,7 @@ def create_tools_router(
|
|
|
488
488
|
require_graph=_require_graph,
|
|
489
489
|
static_dir=STATIC_DIR,
|
|
490
490
|
local_kg_watcher=LOCAL_KG_WATCHER,
|
|
491
|
+
ingestion_pipeline=ingestion_pipeline,
|
|
491
492
|
hooks=HOOKS,
|
|
492
493
|
data_dir=DATA_DIR,
|
|
493
494
|
allowed_workspaces_for=allowed_workspaces_for,
|
|
@@ -73,10 +73,11 @@ def create_workflow_designer_router(
|
|
|
73
73
|
) -> APIRouter:
|
|
74
74
|
from lattice_brain.workflow import (
|
|
75
75
|
WorkflowEngine,
|
|
76
|
+
WorkflowError,
|
|
76
77
|
validate_definition,
|
|
77
78
|
export_workflow,
|
|
78
79
|
import_workflow,
|
|
79
|
-
|
|
80
|
+
legacy_steps_from_nodes,
|
|
80
81
|
)
|
|
81
82
|
|
|
82
83
|
router = APIRouter()
|
|
@@ -101,7 +102,7 @@ def create_workflow_designer_router(
|
|
|
101
102
|
raise HTTPException(status_code=400, detail={"validation_errors": errors})
|
|
102
103
|
workflow = store.create_workflow(
|
|
103
104
|
name=req.name,
|
|
104
|
-
steps=
|
|
105
|
+
steps=legacy_steps_from_nodes(req.nodes),
|
|
105
106
|
nodes=req.nodes,
|
|
106
107
|
metadata=req.metadata,
|
|
107
108
|
user_email=current_user or None,
|
|
@@ -293,7 +294,7 @@ def create_workflow_designer_router(
|
|
|
293
294
|
raise HTTPException(status_code=400, detail={"validation_errors": errors})
|
|
294
295
|
workflow = store.create_workflow(
|
|
295
296
|
name=definition["name"],
|
|
296
|
-
steps=
|
|
297
|
+
steps=legacy_steps_from_nodes(definition["nodes"]),
|
|
297
298
|
nodes=definition["nodes"],
|
|
298
299
|
metadata=definition["metadata"],
|
|
299
300
|
user_email=current_user or None,
|
|
@@ -343,7 +344,7 @@ def create_workflow_designer_router(
|
|
|
343
344
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
344
345
|
workflow = store.create_workflow(
|
|
345
346
|
name=definition["name"],
|
|
346
|
-
steps=
|
|
347
|
+
steps=legacy_steps_from_nodes(definition["nodes"]),
|
|
347
348
|
nodes=definition["nodes"],
|
|
348
349
|
metadata=definition.get("metadata") or {},
|
|
349
350
|
user_email=current_user or None,
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""Managed legacy compatibility surface for legacy import shims.
|
|
2
|
+
|
|
3
|
+
Compatibility modules are intentionally still present for old scripts, VS Code
|
|
4
|
+
extension paths, historical integrations, and pre-graph-package imports. 8.4.0
|
|
5
|
+
stops treating them as vague technical debt: every tracked shim has an owner,
|
|
6
|
+
migration target, removal phase, and replacement import that can be surfaced in
|
|
7
|
+
docs and tests.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, List
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
LEGACY_COMPATIBILITY_VERSION = "8.4.0"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class LegacyShim:
|
|
22
|
+
path: str
|
|
23
|
+
owner: str
|
|
24
|
+
replacement: str
|
|
25
|
+
reason: str
|
|
26
|
+
removal_phase: str
|
|
27
|
+
layer: str = "root"
|
|
28
|
+
status: str = "managed"
|
|
29
|
+
|
|
30
|
+
def as_dict(self) -> Dict[str, str]:
|
|
31
|
+
return {
|
|
32
|
+
"path": self.path,
|
|
33
|
+
"owner": self.owner,
|
|
34
|
+
"replacement": self.replacement,
|
|
35
|
+
"reason": self.reason,
|
|
36
|
+
"removal_phase": self.removal_phase,
|
|
37
|
+
"layer": self.layer,
|
|
38
|
+
"status": self.status,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
LEGACY_SHIMS: List[LegacyShim] = [
|
|
43
|
+
LegacyShim(
|
|
44
|
+
path="knowledge_graph.py",
|
|
45
|
+
owner="lattice_brain.graph",
|
|
46
|
+
replacement="from lattice_brain.store import KnowledgeGraphStore",
|
|
47
|
+
reason="Historical scripts imported the graph store from the repo root.",
|
|
48
|
+
removal_phase="major-release-after-8.x",
|
|
49
|
+
),
|
|
50
|
+
LegacyShim(
|
|
51
|
+
path="knowledge_graph_api.py",
|
|
52
|
+
owner="latticeai.api.knowledge_graph",
|
|
53
|
+
replacement="from latticeai.api.knowledge_graph import create_knowledge_graph_router",
|
|
54
|
+
reason="Older API composition roots imported the knowledge graph router from the repo root.",
|
|
55
|
+
removal_phase="major-release-after-8.x",
|
|
56
|
+
),
|
|
57
|
+
LegacyShim(
|
|
58
|
+
path="kg_schema.py",
|
|
59
|
+
owner="lattice_brain.graph.schema",
|
|
60
|
+
replacement="from lattice_brain.schema import ...",
|
|
61
|
+
reason="Historical graph schema tests and tools referenced root schema symbols.",
|
|
62
|
+
removal_phase="major-release-after-8.x",
|
|
63
|
+
),
|
|
64
|
+
LegacyShim(
|
|
65
|
+
path="ltcai_cli.py",
|
|
66
|
+
owner="latticeai.cli.entrypoint",
|
|
67
|
+
replacement="from latticeai.cli.entrypoint import main",
|
|
68
|
+
reason="Console entry points and older package installs imported the CLI root module.",
|
|
69
|
+
removal_phase="major-release-after-8.x",
|
|
70
|
+
),
|
|
71
|
+
LegacyShim(
|
|
72
|
+
path="telegram_bot.py",
|
|
73
|
+
owner="latticeai.integrations.telegram_bot",
|
|
74
|
+
replacement="from latticeai.integrations.telegram_bot import run_bot",
|
|
75
|
+
reason="Existing Telegram automation setups still import the legacy root module.",
|
|
76
|
+
removal_phase="major-release-after-8.x",
|
|
77
|
+
),
|
|
78
|
+
LegacyShim(
|
|
79
|
+
path="p_reinforce.py",
|
|
80
|
+
owner="latticeai.services.p_reinforce",
|
|
81
|
+
replacement="from latticeai.services.p_reinforce import PReinforceGardener",
|
|
82
|
+
reason="Old gardener scripts referenced the root reinforcement helper.",
|
|
83
|
+
removal_phase="major-release-after-8.x",
|
|
84
|
+
),
|
|
85
|
+
LegacyShim(
|
|
86
|
+
path="server.py",
|
|
87
|
+
owner="latticeai.server_app",
|
|
88
|
+
replacement="from latticeai.server_app import app, main",
|
|
89
|
+
reason="Deployment docs and local launch scripts historically targeted server.py.",
|
|
90
|
+
removal_phase="major-release-after-8.x",
|
|
91
|
+
),
|
|
92
|
+
LegacyShim(
|
|
93
|
+
path="local_knowledge_api.py",
|
|
94
|
+
owner="latticeai.api.local_files",
|
|
95
|
+
replacement="from latticeai.api.local_files import create_local_files_router",
|
|
96
|
+
reason="Local folder ingestion integrations used the root local knowledge API.",
|
|
97
|
+
removal_phase="requires-api-route-migration",
|
|
98
|
+
),
|
|
99
|
+
LegacyShim(
|
|
100
|
+
path="lattice_brain/store.py",
|
|
101
|
+
owner="lattice_brain.graph.store",
|
|
102
|
+
replacement="from lattice_brain.graph.store import KnowledgeGraphStore",
|
|
103
|
+
reason="Pre-graph-package imports used the flat Brain store module.",
|
|
104
|
+
removal_phase="major-release-after-8.x",
|
|
105
|
+
layer="brain-flat",
|
|
106
|
+
),
|
|
107
|
+
LegacyShim(
|
|
108
|
+
path="lattice_brain/ingest.py",
|
|
109
|
+
owner="lattice_brain.graph.ingest",
|
|
110
|
+
replacement="from lattice_brain.graph.ingest import KnowledgeGraphIngestMixin",
|
|
111
|
+
reason="Pre-graph-package imports used the flat Brain ingest module.",
|
|
112
|
+
removal_phase="major-release-after-8.x",
|
|
113
|
+
layer="brain-flat",
|
|
114
|
+
),
|
|
115
|
+
LegacyShim(
|
|
116
|
+
path="lattice_brain/retrieval.py",
|
|
117
|
+
owner="lattice_brain.graph.retrieval",
|
|
118
|
+
replacement="from lattice_brain.graph.retrieval import KnowledgeGraphRetrievalMixin",
|
|
119
|
+
reason="Pre-graph-package imports used the flat Brain retrieval module.",
|
|
120
|
+
removal_phase="major-release-after-8.x",
|
|
121
|
+
layer="brain-flat",
|
|
122
|
+
),
|
|
123
|
+
LegacyShim(
|
|
124
|
+
path="latticeai/brain/store.py",
|
|
125
|
+
owner="lattice_brain.graph.store",
|
|
126
|
+
replacement="from lattice_brain.graph.store import KnowledgeGraphStore",
|
|
127
|
+
reason="The deprecated latticeai.brain namespace remains for package users.",
|
|
128
|
+
removal_phase="major-release-after-8.x",
|
|
129
|
+
layer="deprecated-namespace",
|
|
130
|
+
),
|
|
131
|
+
LegacyShim(
|
|
132
|
+
path="latticeai/brain/ingest.py",
|
|
133
|
+
owner="lattice_brain.graph.ingest",
|
|
134
|
+
replacement="from lattice_brain.graph.ingest import KnowledgeGraphIngestMixin",
|
|
135
|
+
reason="The deprecated latticeai.brain namespace remains for package users.",
|
|
136
|
+
removal_phase="major-release-after-8.x",
|
|
137
|
+
layer="deprecated-namespace",
|
|
138
|
+
),
|
|
139
|
+
LegacyShim(
|
|
140
|
+
path="latticeai/services/agent_runtime.py",
|
|
141
|
+
owner="lattice_brain.runtime.agent_runtime",
|
|
142
|
+
replacement="from lattice_brain.runtime.agent_runtime import AgentRuntime",
|
|
143
|
+
reason="Service-layer imports existed before AgentRuntime moved into Brain runtime.",
|
|
144
|
+
removal_phase="major-release-after-8.x",
|
|
145
|
+
layer="service-alias",
|
|
146
|
+
),
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def legacy_shim_report(root: Path | None = None) -> Dict[str, Any]:
|
|
151
|
+
if root is None:
|
|
152
|
+
root = Path(__file__).resolve().parents[2]
|
|
153
|
+
entries = [shim.as_dict() for shim in LEGACY_SHIMS]
|
|
154
|
+
missing = [shim.path for shim in LEGACY_SHIMS if not (root / shim.path).exists()]
|
|
155
|
+
phases = sorted({shim.removal_phase for shim in LEGACY_SHIMS})
|
|
156
|
+
layers = sorted({shim.layer for shim in LEGACY_SHIMS})
|
|
157
|
+
return {
|
|
158
|
+
"schema_version": "legacy-compatibility/v1",
|
|
159
|
+
"version_target": LEGACY_COMPATIBILITY_VERSION,
|
|
160
|
+
"status": "managed" if not missing else "incomplete",
|
|
161
|
+
"remaining_count": len(LEGACY_SHIMS),
|
|
162
|
+
"missing": missing,
|
|
163
|
+
"removal_phases": phases,
|
|
164
|
+
"layers": layers,
|
|
165
|
+
"shims": entries,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
__all__ = [
|
|
170
|
+
"LEGACY_COMPATIBILITY_VERSION",
|
|
171
|
+
"LEGACY_SHIMS",
|
|
172
|
+
"LegacyShim",
|
|
173
|
+
"legacy_shim_report",
|
|
174
|
+
]
|
|
@@ -49,7 +49,7 @@ __all__ = [
|
|
|
49
49
|
"remove_skill_directory",
|
|
50
50
|
]
|
|
51
51
|
|
|
52
|
-
WORKSPACE_OS_VERSION = "8.
|
|
52
|
+
WORKSPACE_OS_VERSION = "8.4.0"
|
|
53
53
|
|
|
54
54
|
# Workspace types separate single-user Personal workspaces from shared
|
|
55
55
|
# Organization workspaces. Both keep the same local-first JSON store; the type
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Machine-checkable architecture readiness gates for release work.
|
|
2
2
|
|
|
3
|
-
8.
|
|
4
|
-
contract while
|
|
3
|
+
8.4.0 keeps the major architecture priorities under an explicit release
|
|
4
|
+
contract while product maturity work reduces visible beta seams. AgentRuntime, ToolRegistry,
|
|
5
5
|
central Config, decomposed server runtime, and Knowledge Graph stabilization
|
|
6
6
|
must remain discoverable, ordered, and backed by tests before the release can be
|
|
7
7
|
called complete.
|
|
@@ -14,8 +14,10 @@ from dataclasses import dataclass
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
from typing import Any, Dict, List
|
|
16
16
|
|
|
17
|
+
from latticeai.core.legacy_compatibility import legacy_shim_report
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
|
|
20
|
+
ARCHITECTURE_VERSION_TARGET = "8.4.0"
|
|
19
21
|
|
|
20
22
|
PREFERRED_REFACTORING_ORDER = [
|
|
21
23
|
"agent-runtime",
|
|
@@ -55,6 +57,7 @@ def _symbol_exists(dotted: str) -> bool:
|
|
|
55
57
|
def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
56
58
|
if root is None:
|
|
57
59
|
root = Path(__file__).resolve().parents[2]
|
|
60
|
+
shim_report = legacy_shim_report(root)
|
|
58
61
|
|
|
59
62
|
gates = [
|
|
60
63
|
ArchitectureGate(
|
|
@@ -117,6 +120,35 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
117
120
|
"tests/visual/v3.spec.js first-run and Brain depth coverage",
|
|
118
121
|
],
|
|
119
122
|
),
|
|
123
|
+
ArchitectureGate(
|
|
124
|
+
id="legacy-compatibility",
|
|
125
|
+
title="Legacy shim sunset plan",
|
|
126
|
+
status="complete" if shim_report["status"] == "managed" else "incomplete",
|
|
127
|
+
evidence=[
|
|
128
|
+
"latticeai.core.legacy_compatibility.legacy_shim_report",
|
|
129
|
+
"docs/LEGACY_COMPATIBILITY.md",
|
|
130
|
+
"tests/unit/test_legacy_root_shims.py",
|
|
131
|
+
],
|
|
132
|
+
),
|
|
133
|
+
ArchitectureGate(
|
|
134
|
+
id="orchestration-maturity",
|
|
135
|
+
title="AgentRuntime and workflow orchestration maturity",
|
|
136
|
+
status="complete" if all(
|
|
137
|
+
_symbol_exists(s)
|
|
138
|
+
for s in [
|
|
139
|
+
"lattice_brain.runtime.multi_agent.MultiAgentOrchestrator",
|
|
140
|
+
"lattice_brain.workflow.WorkflowEngine",
|
|
141
|
+
"latticeai.services.run_executor.RunExecutor",
|
|
142
|
+
]
|
|
143
|
+
) else "incomplete",
|
|
144
|
+
evidence=[
|
|
145
|
+
"lattice_brain.runtime.multi_agent.MultiAgentOrchestrator",
|
|
146
|
+
"lattice_brain.workflow.WorkflowEngine",
|
|
147
|
+
"latticeai.services.run_executor.RunExecutor",
|
|
148
|
+
"tests/unit/test_agent_platform_maturity.py",
|
|
149
|
+
"tests/unit/test_t7_async_run_executor.py",
|
|
150
|
+
],
|
|
151
|
+
),
|
|
120
152
|
]
|
|
121
153
|
|
|
122
154
|
api_router_count = len(list((root / "latticeai" / "api").glob("*.py")))
|
|
@@ -159,5 +191,7 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
159
191
|
"api_router_modules": api_router_count,
|
|
160
192
|
"runtime_modules": runtime_module_count,
|
|
161
193
|
"architecture_gates": len(gates),
|
|
194
|
+
"legacy_shims_remaining": shim_report["remaining_count"],
|
|
162
195
|
},
|
|
196
|
+
"legacy_compatibility": shim_report,
|
|
163
197
|
}
|
|
@@ -102,6 +102,12 @@ MODEL_ENGINE_ALIASES = {
|
|
|
102
102
|
"lmstudio": "ggml-org/gemma-4-12B-it-GGUF",
|
|
103
103
|
"llamacpp": "ggml-org/gemma-4-12B-it-GGUF",
|
|
104
104
|
},
|
|
105
|
+
"gemma-4-26b-it-4bit": {
|
|
106
|
+
"local_mlx": "mlx-community/gemma-4-26b-a4b-it-4bit",
|
|
107
|
+
},
|
|
108
|
+
"mlx-community/gemma-4-26b-a4b-it-4bit": {
|
|
109
|
+
"local_mlx": "mlx-community/gemma-4-26b-a4b-it-4bit",
|
|
110
|
+
},
|
|
105
111
|
"gemma-4-31b-it-4bit": {
|
|
106
112
|
"local_mlx": "mlx-community/gemma-4-31b-it-4bit",
|
|
107
113
|
"ollama": "hf.co/ggml-org/gemma-4-31B-it-GGUF:Q4_K_M",
|
|
@@ -24,6 +24,14 @@ from typing import Any, Dict, List, Optional
|
|
|
24
24
|
from fastapi import HTTPException
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
def _progress_payload(*args, **kwargs) -> Dict[str, object]:
|
|
28
|
+
try:
|
|
29
|
+
from latticeai.services.model_runtime import model_download_progress_payload
|
|
30
|
+
except Exception:
|
|
31
|
+
return {}
|
|
32
|
+
return model_download_progress_payload(*args, **kwargs)
|
|
33
|
+
|
|
34
|
+
|
|
27
35
|
LOCAL_SERVER_PROCESSES: Dict[str, subprocess.Popen] = {}
|
|
28
36
|
VLLM_METAL_ENV = Path.home() / ".venv-vllm-metal"
|
|
29
37
|
VLLM_METAL_BIN = VLLM_METAL_ENV / "bin" / "vllm"
|
|
@@ -335,12 +343,7 @@ def pull_ollama_model_with_progress(model_name: str, progress_emit=None) -> Dict
|
|
|
335
343
|
if not ollama:
|
|
336
344
|
raise HTTPException(status_code=400, detail="Ollama가 설치되지 않았습니다.")
|
|
337
345
|
if progress_emit:
|
|
338
|
-
|
|
339
|
-
try:
|
|
340
|
-
from latticeai.services.model_runtime import model_download_progress_payload as _prog
|
|
341
|
-
except Exception:
|
|
342
|
-
_prog = lambda *a, **k: {}
|
|
343
|
-
progress_emit(_prog(
|
|
346
|
+
progress_emit(_progress_payload(
|
|
344
347
|
"download",
|
|
345
348
|
"Ollama 모델 다운로드를 시작합니다.",
|
|
346
349
|
percent=0,
|
|
@@ -368,11 +371,7 @@ def pull_ollama_model_with_progress(model_name: str, progress_emit=None) -> Dict
|
|
|
368
371
|
if match:
|
|
369
372
|
last_percent = min(100.0, float(match.group(1)))
|
|
370
373
|
if progress_emit:
|
|
371
|
-
|
|
372
|
-
from latticeai.services.model_runtime import model_download_progress_payload as _prog2
|
|
373
|
-
except Exception:
|
|
374
|
-
_prog2 = lambda *a, **k: {}
|
|
375
|
-
progress_emit(_prog2(
|
|
374
|
+
progress_emit(_progress_payload(
|
|
376
375
|
"download",
|
|
377
376
|
"Ollama 모델 다운로드 중입니다.",
|
|
378
377
|
percent=last_percent,
|
|
@@ -381,11 +380,7 @@ def pull_ollama_model_with_progress(model_name: str, progress_emit=None) -> Dict
|
|
|
381
380
|
indeterminate=False,
|
|
382
381
|
))
|
|
383
382
|
elif progress_emit:
|
|
384
|
-
|
|
385
|
-
from latticeai.services.model_runtime import model_download_progress_payload as _prog3
|
|
386
|
-
except Exception:
|
|
387
|
-
_prog3 = lambda *a, **k: {}
|
|
388
|
-
progress_emit(_prog3(
|
|
383
|
+
progress_emit(_progress_payload(
|
|
389
384
|
"download",
|
|
390
385
|
"Ollama 모델 다운로드 중입니다.",
|
|
391
386
|
percent=last_percent,
|
|
@@ -403,11 +398,7 @@ def pull_ollama_model_with_progress(model_name: str, progress_emit=None) -> Dict
|
|
|
403
398
|
raise HTTPException(status_code=500, detail=tail[-2000:] or "Ollama 모델 다운로드 실패")
|
|
404
399
|
|
|
405
400
|
if progress_emit:
|
|
406
|
-
|
|
407
|
-
from latticeai.services.model_runtime import model_download_progress_payload as _prog4
|
|
408
|
-
except Exception:
|
|
409
|
-
_prog4 = lambda *a, **k: {}
|
|
410
|
-
progress_emit(_prog4(
|
|
401
|
+
progress_emit(_progress_payload(
|
|
411
402
|
"download",
|
|
412
403
|
"Ollama 모델 다운로드가 완료되었습니다.",
|
|
413
404
|
percent=100,
|
|
@@ -12,12 +12,7 @@ import importlib.util
|
|
|
12
12
|
import json
|
|
13
13
|
import logging
|
|
14
14
|
import os
|
|
15
|
-
import platform
|
|
16
|
-
import queue
|
|
17
15
|
import shutil
|
|
18
|
-
import subprocess
|
|
19
|
-
import sys
|
|
20
|
-
import threading
|
|
21
16
|
import time
|
|
22
17
|
import urllib.error
|
|
23
18
|
import urllib.request
|
|
@@ -26,14 +21,6 @@ from typing import AsyncIterator, Dict, List, Optional
|
|
|
26
21
|
|
|
27
22
|
from fastapi import HTTPException, Request
|
|
28
23
|
|
|
29
|
-
def _missing_current_user(_request: Request) -> Optional[str]:
|
|
30
|
-
return None
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def _missing_user_api_key(_email: Optional[str], _provider: str) -> Optional[str]:
|
|
34
|
-
return None
|
|
35
|
-
|
|
36
|
-
|
|
37
24
|
from latticeai.models.router import (
|
|
38
25
|
AsyncOpenAI,
|
|
39
26
|
HF_MODELS_ROOT,
|
|
@@ -43,11 +30,12 @@ from latticeai.models.router import (
|
|
|
43
30
|
hf_model_dir,
|
|
44
31
|
parse_model_ref,
|
|
45
32
|
)
|
|
33
|
+
from latticeai.core.model_resolution import ModelResolution as _ModelResolution
|
|
46
34
|
from latticeai.core.model_compat import (
|
|
47
35
|
friendly_model_runtime_error as _friendly_model_runtime_error,
|
|
48
36
|
model_runtime_compatibility as _model_runtime_compatibility,
|
|
37
|
+
SMOKE_PROMPT as _SMOKE_PROMPT,
|
|
49
38
|
)
|
|
50
|
-
from latticeai.core.model_resolution import ModelResolution as _ModelResolution
|
|
51
39
|
from .model_engines import (
|
|
52
40
|
ensure_lmstudio_server as _ensure_lmstudio_server,
|
|
53
41
|
ensure_ollama_server as _ensure_ollama_server,
|
|
@@ -67,15 +55,21 @@ from .model_engines import (
|
|
|
67
55
|
LOCAL_SERVER_PROCESSES as _LOCAL_SERVER_PROCESSES,
|
|
68
56
|
)
|
|
69
57
|
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
58
|
+
# ``model_loading._get_model_runtime_deps`` imports these private names from
|
|
59
|
+
# this module to preserve the historical model_runtime wiring surface.
|
|
60
|
+
_MODEL_LOADING_COMPAT_EXPORTS = (
|
|
61
|
+
_friendly_model_runtime_error,
|
|
62
|
+
_model_runtime_compatibility,
|
|
63
|
+
_SMOKE_PROMPT,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _missing_current_user(_request: Request) -> Optional[str]:
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _missing_user_api_key(_email: Optional[str], _provider: str) -> Optional[str]:
|
|
72
|
+
return None
|
|
79
73
|
|
|
80
74
|
# Server decomp: proper ModelRuntimeState class for globals/wiring
|
|
81
75
|
class ModelRuntimeState:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"""Machine-checkable *product* readiness gates for the 8.
|
|
1
|
+
"""Machine-checkable *product* readiness gates for the 8.4 line.
|
|
2
2
|
|
|
3
3
|
Where ``architecture_readiness`` proves the internal structure is sound, this
|
|
4
|
-
module answers the product question the 8.
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
module answers the product question the 8.4 release exists to settle: *does the
|
|
5
|
+
app now feel like a finished product rather than only a strong framework?*
|
|
6
|
+
It does so honestly: every gate is backed by
|
|
7
7
|
evidence that is probed on disk, so a gate only reports ``complete`` when its
|
|
8
8
|
evidence actually resolves. The same report can be printed by
|
|
9
9
|
``scripts/product_readiness.py`` and re-run after every change, which is the
|
|
@@ -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 = "8.
|
|
21
|
+
PRODUCT_VERSION_TARGET = "8.4.0"
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
@dataclass(frozen=True)
|
|
@@ -35,6 +35,7 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
35
35
|
id="first-run",
|
|
36
36
|
title="First five minutes lands without a manual",
|
|
37
37
|
evidence=[
|
|
38
|
+
"docs/ONBOARDING.md::five-minute",
|
|
38
39
|
"frontend/src/components/ProductFlow.tsx::WakeBrainScreen",
|
|
39
40
|
"frontend/src/features/brain/BrainConversation.tsx::ProductCommandCenter",
|
|
40
41
|
"frontend/src/features/brain/BrainConversation.tsx::BrainBriefPanel",
|
|
@@ -51,6 +52,15 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
51
52
|
"scripts/brain_quality_eval.py",
|
|
52
53
|
],
|
|
53
54
|
),
|
|
55
|
+
ProductGate(
|
|
56
|
+
id="action-aware-chat",
|
|
57
|
+
title="File action requests create artifacts instead of code-only answers",
|
|
58
|
+
evidence=[
|
|
59
|
+
"latticeai/api/chat.py::is_file_action_request",
|
|
60
|
+
"latticeai/api/chat.py::direct_write_file",
|
|
61
|
+
"tests/unit/test_chat_telegram_decoupling.py::test_chat_file_creation_intent_writes_real_file",
|
|
62
|
+
],
|
|
63
|
+
),
|
|
54
64
|
ProductGate(
|
|
55
65
|
id="local-first-trust",
|
|
56
66
|
title="Local-first privacy is stated and bounded",
|
|
@@ -66,10 +76,10 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
66
76
|
evidence=[
|
|
67
77
|
"package.json::release:artifacts",
|
|
68
78
|
"package.json::release:validate",
|
|
69
|
-
"README.md::dist/ltcai-8.
|
|
70
|
-
"README.md::dist/ltcai-8.
|
|
71
|
-
"README.md::dist/ltcai-8.
|
|
72
|
-
"README.md::ltcai-8.
|
|
79
|
+
"README.md::dist/ltcai-8.4.0-py3-none-any.whl",
|
|
80
|
+
"README.md::dist/ltcai-8.4.0.tar.gz",
|
|
81
|
+
"README.md::dist/ltcai-8.4.0.vsix",
|
|
82
|
+
"README.md::ltcai-8.4.0.tgz",
|
|
73
83
|
"scripts/validate_release_artifacts.py",
|
|
74
84
|
"scripts/release_smoke.py",
|
|
75
85
|
"Dockerfile",
|
|
@@ -85,12 +95,12 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
85
95
|
title="Release story is documented and honest",
|
|
86
96
|
evidence=[
|
|
87
97
|
"README.md",
|
|
88
|
-
"README.md::The current release is **8.
|
|
89
|
-
"SECURITY.md::8.
|
|
90
|
-
"vscode-extension/README.md::**8.
|
|
91
|
-
"docs/CHANGELOG.md::## [8.
|
|
98
|
+
"README.md::The current release is **8.4.0",
|
|
99
|
+
"SECURITY.md::8.4.x (latest)",
|
|
100
|
+
"vscode-extension/README.md::**8.4.0",
|
|
101
|
+
"docs/CHANGELOG.md::## [8.4.0]",
|
|
92
102
|
"FEATURE_STATUS.md",
|
|
93
|
-
"RELEASE_NOTES_v8.
|
|
103
|
+
"RELEASE_NOTES_v8.4.0.md",
|
|
94
104
|
"latticeai/core/agent.py::SingleAgentRuntime",
|
|
95
105
|
"latticeai/core/agent.py::AgentRuntime = SingleAgentRuntime",
|
|
96
106
|
"lattice_brain/runtime/contracts.py::runtime-boundary/v1",
|
|
@@ -101,6 +111,27 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
101
111
|
"latticeai/services/tool_dispatch.py::rollback_file",
|
|
102
112
|
],
|
|
103
113
|
),
|
|
114
|
+
ProductGate(
|
|
115
|
+
id="ecosystem-path",
|
|
116
|
+
title="Community and plugin growth path is explicit",
|
|
117
|
+
evidence=[
|
|
118
|
+
"docs/COMMUNITY_AND_PLUGINS.md::LatticeAI 8.4.0",
|
|
119
|
+
"docs/PLUGIN_SDK.md",
|
|
120
|
+
"plugins/README.md",
|
|
121
|
+
"plugins/hello-world/plugin.json",
|
|
122
|
+
],
|
|
123
|
+
),
|
|
124
|
+
ProductGate(
|
|
125
|
+
id="ingestion-graph-coverage",
|
|
126
|
+
title="Graph and ingestion integration coverage guards the Brain",
|
|
127
|
+
evidence=[
|
|
128
|
+
"tests/unit/test_ingestion_pipeline.py::test_upload_result_enters_unified_ingestion_pipeline",
|
|
129
|
+
"tests/unit/test_ingestion_pipeline.py::test_ingestion_preserves_workspace_scope_for_duplicate_content",
|
|
130
|
+
"tests/integration/test_ingest_graph_retrieval.py",
|
|
131
|
+
"tests/unit/test_lattice_brain_isolation.py",
|
|
132
|
+
"tests/unit/test_retrieval_benchmark_corpus.py",
|
|
133
|
+
],
|
|
134
|
+
),
|
|
104
135
|
ProductGate(
|
|
105
136
|
id="quality-gates",
|
|
106
137
|
title="Quality is guarded by repeatable gates",
|
package/llm_router.py
CHANGED
|
@@ -1,32 +1,11 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Compatibility shim: physically moved to ``latticeai.models.router``.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Aliases itself to the physical module so router globals, identity checks, and
|
|
4
|
+
monkeypatching keep working through the old import path.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
from latticeai.models.router import ( # noqa: F401 — explicit key surface
|
|
9
|
-
AsyncOpenAI,
|
|
10
|
-
BRAND_NAME,
|
|
11
|
-
HF_MODELS_ROOT,
|
|
12
|
-
LLMRouter,
|
|
13
|
-
OPENAI_COMPATIBLE_PROVIDERS,
|
|
14
|
-
SYSTEM_PROMPT,
|
|
15
|
-
ensure_mlx_runtime,
|
|
16
|
-
hf_model_dir,
|
|
17
|
-
normalize_branding,
|
|
18
|
-
parse_model_ref,
|
|
19
|
-
)
|
|
7
|
+
import sys
|
|
20
8
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"HF_MODELS_ROOT",
|
|
25
|
-
"LLMRouter",
|
|
26
|
-
"OPENAI_COMPATIBLE_PROVIDERS",
|
|
27
|
-
"SYSTEM_PROMPT",
|
|
28
|
-
"ensure_mlx_runtime",
|
|
29
|
-
"hf_model_dir",
|
|
30
|
-
"normalize_branding",
|
|
31
|
-
"parse_model_ref",
|
|
32
|
-
]
|
|
9
|
+
import latticeai.models.router as _impl
|
|
10
|
+
|
|
11
|
+
sys.modules[__name__] = _impl
|
package/mcp_registry.py
CHANGED
|
@@ -1,28 +1,11 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Compatibility shim: physically moved to ``latticeai.core.mcp_registry``.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Note: the remote-registry cache lives in ``latticeai.core.mcp_registry``
|
|
7
|
-
module globals — code that *assigns* cache attributes (e.g.
|
|
8
|
-
``_REMOTE_REGISTRY_FETCHED_AT``) must import the real module, not this shim.
|
|
3
|
+
Aliases itself to the physical module so registry cache state, identity checks,
|
|
4
|
+
and monkeypatching keep working through the old import path.
|
|
9
5
|
"""
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
SKILLS_DIR,
|
|
15
|
-
_KNOWN_REPO_LICENSES,
|
|
16
|
-
_MARKETPLACE_API,
|
|
17
|
-
_MARKETPLACE_RAW,
|
|
18
|
-
_THIRD_PARTY_SKILL_SOURCES,
|
|
19
|
-
_extract_skill_desc,
|
|
20
|
-
_fetch_plugin_directory,
|
|
21
|
-
_fetch_plugin_skills,
|
|
22
|
-
_fetch_remote_mcp_registry,
|
|
23
|
-
_fetch_skills_marketplace,
|
|
24
|
-
_get_combined_registry,
|
|
25
|
-
install_skill,
|
|
26
|
-
)
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
import latticeai.core.mcp_registry as _impl
|
|
27
10
|
|
|
28
|
-
|
|
11
|
+
sys.modules[__name__] = _impl
|