ltcai 8.2.0 → 8.3.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.
Files changed (44) hide show
  1. package/README.md +21 -19
  2. package/docs/CHANGELOG.md +32 -0
  3. package/docs/COMMUNITY_AND_PLUGINS.md +43 -0
  4. package/docs/DEVELOPMENT.md +8 -8
  5. package/docs/LEGACY_COMPATIBILITY.md +22 -2
  6. package/docs/ONBOARDING.md +38 -0
  7. package/docs/TRUST_MODEL.md +1 -1
  8. package/docs/WHY_LATTICE.md +5 -4
  9. package/docs/kg-schema.md +3 -3
  10. package/lattice_brain/__init__.py +1 -1
  11. package/lattice_brain/graph/ingest.py +40 -8
  12. package/lattice_brain/runtime/agent_runtime.py +22 -37
  13. package/lattice_brain/runtime/multi_agent.py +1 -1
  14. package/lattice_brain/workflow.py +26 -1
  15. package/latticeai/__init__.py +1 -1
  16. package/latticeai/api/knowledge_graph.py +33 -0
  17. package/latticeai/api/local_files.py +2 -0
  18. package/latticeai/api/tools.py +1 -0
  19. package/latticeai/api/workflow_designer.py +5 -4
  20. package/latticeai/core/legacy_compatibility.py +174 -0
  21. package/latticeai/core/marketplace.py +1 -1
  22. package/latticeai/core/workspace_os.py +1 -1
  23. package/latticeai/services/architecture_readiness.py +37 -3
  24. package/latticeai/services/model_engines.py +12 -21
  25. package/latticeai/services/model_runtime.py +7 -26
  26. package/latticeai/services/product_readiness.py +36 -14
  27. package/llm_router.py +7 -28
  28. package/mcp_registry.py +7 -24
  29. package/package.json +1 -1
  30. package/scripts/pts-claudecode-discord-bridge.mjs +2 -1
  31. package/src-tauri/Cargo.lock +1 -1
  32. package/src-tauri/Cargo.toml +1 -1
  33. package/src-tauri/tauri.conf.json +1 -1
  34. package/static/app/asset-manifest.json +10 -10
  35. package/static/app/assets/{Act-D9jIknFd.js → Act-D5mo4tE4.js} +1 -1
  36. package/static/app/assets/{Brain-CFOtWbPN.js → Brain-BVWyQw8A.js} +1 -1
  37. package/static/app/assets/{Capture-Q4WYzwr5.js → Capture-C1R6GT0t.js} +1 -1
  38. package/static/app/assets/{Library-C5Q2yWee.js → Library-C2wIxpTs.js} +1 -1
  39. package/static/app/assets/{System-BLbjdr1_.js → System-DE5GRyQR.js} +1 -1
  40. package/static/app/assets/{index-BqammyNu.js → index-CoiuIFFP.js} +3 -3
  41. package/static/app/assets/{primitives-Br8uSfZ4.js → primitives-BdsUNXa6.js} +1 -1
  42. package/static/app/assets/{textarea-BnhNs1_X.js → textarea-e7qaj6Hm.js} +1 -1
  43. package/static/app/index.html +1 -1
  44. package/static/sw.js +1 -1
@@ -13,6 +13,7 @@ from fastapi import APIRouter, HTTPException, Request
13
13
  from pydantic import BaseModel
14
14
 
15
15
  from latticeai.api.ui_redirects import app_redirect
16
+ from lattice_brain.ingestion import IngestionItem
16
17
 
17
18
 
18
19
  class KnowledgeGraphIngestRequest(BaseModel):
@@ -61,6 +62,7 @@ def create_knowledge_graph_router(
61
62
  require_user: Callable[[Request], str],
62
63
  static_dir: Path,
63
64
  allowed_workspaces_for: Optional[Callable[[Optional[str]], Any]] = None,
65
+ ingestion_pipeline: Any = None,
64
66
  ) -> APIRouter:
65
67
  router = APIRouter()
66
68
 
@@ -191,6 +193,37 @@ def create_knowledge_graph_router(
191
193
  if event_type not in {"message", "ai_response", "note"}:
192
194
  raise HTTPException(status_code=400, detail="지원하는 type: message, ai_response, note")
193
195
  role = req.role or ("assistant" if event_type == "ai_response" else "user")
196
+ if ingestion_pipeline is not None:
197
+ source_type = "chat_message" if event_type in {"message", "ai_response"} else "note"
198
+ result = ingestion_pipeline.ingest(
199
+ IngestionItem(
200
+ source_type=source_type,
201
+ title=req.title,
202
+ text=req.content,
203
+ source_uri=req.source,
204
+ owner=req.user_email or current_user,
205
+ workspace_id=workspace_id,
206
+ conversation_id=req.conversation_id,
207
+ metadata={
208
+ "type": req.type,
209
+ "role": role,
210
+ "source": req.source or "mcp",
211
+ "user_nickname": req.user_nickname,
212
+ "raw": {
213
+ "type": req.type,
214
+ "title": req.title,
215
+ "content": req.content,
216
+ "workspace_id": workspace_id,
217
+ "metadata": req.metadata or {},
218
+ },
219
+ **(req.metadata or {}),
220
+ },
221
+ ),
222
+ user_email=req.user_email or current_user,
223
+ )
224
+ if result.status != "ok":
225
+ raise HTTPException(status_code=500, detail=result.detail or result.status)
226
+ return result.as_dict()
194
227
  return kg.ingest_message(
195
228
  role,
196
229
  req.content,
@@ -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
 
@@ -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
- WorkflowError,
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=[{"action": n.get("type"), "node": n.get("id")} for n in req.nodes],
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=[{"action": n.get("type"), "node": n.get("id")} for n in definition["nodes"]],
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=[{"action": n.get("type"), "node": n.get("id")} for n in definition["nodes"]],
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.3.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.3.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
+ ]
@@ -11,7 +11,7 @@ from copy import deepcopy
11
11
  from typing import Any, Dict, List, Optional
12
12
 
13
13
 
14
- MARKETPLACE_VERSION = "8.2.0"
14
+ MARKETPLACE_VERSION = "8.3.0"
15
15
  TEMPLATE_KINDS = ("plugin", "workflow", "agent")
16
16
 
17
17
 
@@ -49,7 +49,7 @@ __all__ = [
49
49
  "remove_skill_directory",
50
50
  ]
51
51
 
52
- WORKSPACE_OS_VERSION = "8.2.0"
52
+ WORKSPACE_OS_VERSION = "8.3.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.2.0 keeps the major architecture priorities under an explicit release
4
- contract while Brain Brief improves the product surface. AgentRuntime, ToolRegistry,
3
+ 8.3.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
- ARCHITECTURE_VERSION_TARGET = "8.2.0"
19
+
20
+ ARCHITECTURE_VERSION_TARGET = "8.3.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
  }
@@ -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
- # use late import for progress payload
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
- try:
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
- try:
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
- try:
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,10 +30,6 @@ from latticeai.models.router import (
43
30
  hf_model_dir,
44
31
  parse_model_ref,
45
32
  )
46
- from latticeai.core.model_compat import (
47
- friendly_model_runtime_error as _friendly_model_runtime_error,
48
- model_runtime_compatibility as _model_runtime_compatibility,
49
- )
50
33
  from latticeai.core.model_resolution import ModelResolution as _ModelResolution
51
34
  from .model_engines import (
52
35
  ensure_lmstudio_server as _ensure_lmstudio_server,
@@ -67,15 +50,13 @@ from .model_engines import (
67
50
  LOCAL_SERVER_PROCESSES as _LOCAL_SERVER_PROCESSES,
68
51
  )
69
52
 
70
- # Rebind extracted engines for legacy module globals
71
- ensure_lmstudio_server = _ensure_lmstudio_server
72
- ensure_ollama_server = _ensure_ollama_server
73
- ensure_vllm_server = _ensure_vllm_server
74
- ensure_llamacpp_server = _ensure_llamacpp_server
75
- pull_ollama_model_with_progress = _pull_ollama_model_with_progress
76
- get_ollama_pulled_models = _get_ollama_pulled_models
77
- engine_support_status = _engine_support_status
78
- install_engine = _install_engine
53
+
54
+ def _missing_current_user(_request: Request) -> Optional[str]:
55
+ return None
56
+
57
+
58
+ def _missing_user_api_key(_email: Optional[str], _provider: str) -> Optional[str]:
59
+ return None
79
60
 
80
61
  # Server decomp: proper ModelRuntimeState class for globals/wiring
81
62
  class ModelRuntimeState:
@@ -1,9 +1,9 @@
1
- """Machine-checkable *product* readiness gates for the 8.2 line.
1
+ """Machine-checkable *product* readiness gates for the 8.3 line.
2
2
 
3
3
  Where ``architecture_readiness`` proves the internal structure is sound, this
4
- module answers the product question the 8.2 release exists to settle: *is the
5
- Brain experience still release-ready now that the home screen explains what to
6
- notice and what to do next?* It does so honestly: every gate is backed by
4
+ module answers the product question the 8.3 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.2.0"
21
+ PRODUCT_VERSION_TARGET = "8.3.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",
@@ -66,10 +67,10 @@ PRODUCT_GATES: List[ProductGate] = [
66
67
  evidence=[
67
68
  "package.json::release:artifacts",
68
69
  "package.json::release:validate",
69
- "README.md::dist/ltcai-8.2.0-py3-none-any.whl",
70
- "README.md::dist/ltcai-8.2.0.tar.gz",
71
- "README.md::dist/ltcai-8.2.0.vsix",
72
- "README.md::ltcai-8.2.0.tgz",
70
+ "README.md::dist/ltcai-8.3.0-py3-none-any.whl",
71
+ "README.md::dist/ltcai-8.3.0.tar.gz",
72
+ "README.md::dist/ltcai-8.3.0.vsix",
73
+ "README.md::ltcai-8.3.0.tgz",
73
74
  "scripts/validate_release_artifacts.py",
74
75
  "scripts/release_smoke.py",
75
76
  "Dockerfile",
@@ -85,12 +86,12 @@ PRODUCT_GATES: List[ProductGate] = [
85
86
  title="Release story is documented and honest",
86
87
  evidence=[
87
88
  "README.md",
88
- "README.md::The current release is **8.2.0",
89
- "SECURITY.md::8.2.x (latest)",
90
- "vscode-extension/README.md::**8.2.0",
91
- "docs/CHANGELOG.md::## [8.2.0]",
89
+ "README.md::The current release is **8.3.0",
90
+ "SECURITY.md::8.3.x (latest)",
91
+ "vscode-extension/README.md::**8.3.0",
92
+ "docs/CHANGELOG.md::## [8.3.0]",
92
93
  "FEATURE_STATUS.md",
93
- "RELEASE_NOTES_v8.2.0.md",
94
+ "RELEASE_NOTES_v8.3.0.md",
94
95
  "latticeai/core/agent.py::SingleAgentRuntime",
95
96
  "latticeai/core/agent.py::AgentRuntime = SingleAgentRuntime",
96
97
  "lattice_brain/runtime/contracts.py::runtime-boundary/v1",
@@ -101,6 +102,27 @@ PRODUCT_GATES: List[ProductGate] = [
101
102
  "latticeai/services/tool_dispatch.py::rollback_file",
102
103
  ],
103
104
  ),
105
+ ProductGate(
106
+ id="ecosystem-path",
107
+ title="Community and plugin growth path is explicit",
108
+ evidence=[
109
+ "docs/COMMUNITY_AND_PLUGINS.md::LatticeAI 8.3.0",
110
+ "docs/PLUGIN_SDK.md",
111
+ "plugins/README.md",
112
+ "plugins/hello-world/plugin.json",
113
+ ],
114
+ ),
115
+ ProductGate(
116
+ id="ingestion-graph-coverage",
117
+ title="Graph and ingestion integration coverage guards the Brain",
118
+ evidence=[
119
+ "tests/unit/test_ingestion_pipeline.py::test_upload_result_enters_unified_ingestion_pipeline",
120
+ "tests/unit/test_ingestion_pipeline.py::test_ingestion_preserves_workspace_scope_for_duplicate_content",
121
+ "tests/integration/test_ingest_graph_retrieval.py",
122
+ "tests/unit/test_lattice_brain_isolation.py",
123
+ "tests/unit/test_retrieval_benchmark_corpus.py",
124
+ ],
125
+ ),
104
126
  ProductGate(
105
127
  id="quality-gates",
106
128
  title="Quality is guarded by repeatable gates",
package/llm_router.py CHANGED
@@ -1,32 +1,11 @@
1
- """Deprecation shim the LLM router moved to ``latticeai.models.router`` in v4.
1
+ """Compatibility shim: physically moved to ``latticeai.models.router``.
2
2
 
3
- This root module remains importable for the deprecation window and will be
4
- removed in a future major release. Import from ``latticeai.models.router``.
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
- from latticeai.models.router import * # noqa: F401,F403
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
- __all__ = [
22
- "AsyncOpenAI",
23
- "BRAND_NAME",
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