ltcai 10.3.0 → 10.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 +37 -36
- package/docs/CHANGELOG.md +77 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/MYPY_BACKLOG.md +59 -92
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +1 -1
- package/docs/SURFACE_PARITY.md +33 -6
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/kg-schema.md +1 -1
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/context.py +23 -3
- package/lattice_brain/graph/_kg_common.py +164 -9
- package/lattice_brain/graph/_kg_contract.py +223 -0
- package/lattice_brain/graph/_kg_fsutil.py +1 -1
- package/lattice_brain/graph/curator.py +4 -4
- package/lattice_brain/graph/discovery.py +12 -1
- package/lattice_brain/graph/discovery_index.py +12 -1
- package/lattice_brain/graph/documents.py +17 -2
- package/lattice_brain/graph/ingest.py +12 -1
- package/lattice_brain/graph/proactive.py +9 -5
- package/lattice_brain/graph/projection.py +12 -1
- package/lattice_brain/graph/provenance.py +12 -1
- package/lattice_brain/graph/retrieval.py +12 -1
- package/lattice_brain/graph/retrieval_docgen.py +12 -1
- package/lattice_brain/graph/retrieval_reads.py +12 -1
- package/lattice_brain/graph/retrieval_vector.py +12 -1
- package/lattice_brain/graph/schema.py +6 -2
- package/lattice_brain/graph/write_master.py +12 -1
- package/lattice_brain/ingestion.py +1 -1
- package/lattice_brain/quality.py +5 -5
- package/lattice_brain/runtime/contracts.py +2 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/lattice_brain/workflow.py +10 -7
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/admin.py +2 -2
- package/latticeai/api/chat.py +19 -15
- package/latticeai/api/chat_agent_http.py +19 -7
- package/latticeai/api/chat_helpers.py +9 -8
- package/latticeai/api/chat_stream.py +2 -2
- package/latticeai/api/computer_use.py +2 -2
- package/latticeai/api/hooks.py +4 -2
- package/latticeai/api/local_files.py +8 -4
- package/latticeai/api/mcp.py +2 -2
- package/latticeai/api/models.py +5 -5
- package/latticeai/api/permissions.py +2 -2
- package/latticeai/api/search.py +5 -3
- package/latticeai/api/security_dashboard.py +3 -5
- package/latticeai/api/setup.py +3 -3
- package/latticeai/api/static_routes.py +7 -2
- package/latticeai/api/tools.py +9 -4
- package/latticeai/api/workspace.py +25 -22
- package/latticeai/app_factory.py +132 -1322
- package/latticeai/cli/entrypoint.py +1 -1
- package/latticeai/core/agent.py +28 -14
- package/latticeai/core/audit.py +5 -3
- package/latticeai/core/embedding_providers.py +19 -6
- package/latticeai/core/legacy_compatibility.py +1 -1
- package/latticeai/core/marketplace.py +2 -2
- package/latticeai/core/mcp_catalog.py +3 -1
- package/latticeai/core/model_compat.py +1 -1
- package/latticeai/core/plugins.py +1 -1
- package/latticeai/core/project_sessions.py +1 -1
- package/latticeai/core/run_explain.py +6 -4
- package/latticeai/core/workspace_os.py +0 -4
- package/latticeai/core/workspace_os_constants.py +1 -1
- package/latticeai/core/workspace_os_state.py +1 -1
- package/latticeai/core/workspace_snapshots.py +3 -3
- package/latticeai/integrations/telegram_bot.py +52 -3
- package/latticeai/models/router.py +61 -34
- package/latticeai/runtime/access_runtime.py +3 -1
- package/latticeai/runtime/build_phases.py +1417 -0
- package/latticeai/runtime/review_wiring.py +6 -1
- package/latticeai/runtime/runtime_context.py +276 -0
- package/latticeai/runtime/sso_config_runtime.py +1 -1
- package/latticeai/runtime/stages.py +8 -2
- package/latticeai/services/app_context.py +23 -0
- package/latticeai/services/architecture_readiness.py +1 -1
- package/latticeai/services/brain_intelligence.py +4 -2
- package/latticeai/services/cloud_streaming.py +5 -3
- package/latticeai/services/command_center.py +1 -1
- package/latticeai/services/evidence_actions.py +2 -1
- package/latticeai/services/hybrid_chat.py +1 -1
- package/latticeai/services/local_knowledge.py +25 -9
- package/latticeai/services/memory_service.py +8 -4
- package/latticeai/services/model_catalog.py +12 -12
- package/latticeai/services/model_engines.py +15 -17
- package/latticeai/services/model_loading.py +1 -1
- package/latticeai/services/model_runtime.py +31 -33
- package/latticeai/services/multimodal_streaming.py +10 -4
- package/latticeai/services/openai_compatible_adapter.py +4 -3
- package/latticeai/services/product_readiness.py +1 -1
- package/latticeai/services/run_executor.py +12 -3
- package/latticeai/services/search_service.py +1 -1
- package/latticeai/services/triggers.py +1 -1
- package/latticeai/setup/auto_setup.py +1 -1
- package/latticeai/setup/wizard.py +12 -3
- package/latticeai/tools/computer.py +3 -1
- package/latticeai/tools/documents.py +2 -2
- package/package.json +1 -1
- package/scripts/check_current_release_docs.mjs +1 -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 +36 -36
- package/static/app/assets/{Act-DrKIGZeJ.js → Act-BK__Y5VE.js} +1 -1
- package/static/app/assets/{AdminConsole-CEV1VefA.js → AdminConsole-ZrTyN8_F.js} +1 -1
- package/static/app/assets/{Brain-BZSXnwWU.js → Brain-CYHDXpPB.js} +1 -1
- package/static/app/assets/{BrainHome-CEBd86k6.js → BrainHome-bbJulb5g.js} +1 -1
- package/static/app/assets/{BrainSignals-O4s6R7av.js → BrainSignals-CesSPtUP.js} +1 -1
- package/static/app/assets/{Capture-AGbOxsg-.js → Capture-p5upXmz2.js} +1 -1
- package/static/app/assets/{CommandPalette-CeqBjCn2.js → CommandPalette-0zkyC0RY.js} +1 -1
- package/static/app/assets/{Library-CXnbNiQW.js → Library-Dt-vABI2.js} +1 -1
- package/static/app/assets/{LivingBrain-D9Iei2ZJ.js → LivingBrain-Bz-h6LBH.js} +1 -1
- package/static/app/assets/{ProductFlow-JlXiDfMM.js → ProductFlow-DAZ7DJCE.js} +1 -1
- package/static/app/assets/{ReviewCard-QQly2bTV.js → ReviewCard-Bv0WGbY6.js} +1 -1
- package/static/app/assets/{System-Bp9ZY4ER.js → System-BhrJQSD_.js} +1 -1
- package/static/app/assets/{activity-CxRPOQ2F.js → activity-AolpZJCH.js} +1 -1
- package/static/app/assets/{bot-1bcsWB2s.js → bot-CsVsT2nd.js} +1 -1
- package/static/app/assets/{brain-CxaeKCRM.js → brain-vuppco5y.js} +1 -1
- package/static/app/assets/{button-ZYFqGan7.js → button-1BP1PJZ3.js} +1 -1
- package/static/app/assets/{circle-pause-B5NOIqvk.js → circle-pause-5paeCOtq.js} +1 -1
- package/static/app/assets/{circle-play-BiJVFXf7.js → circle-play-By8mFYRV.js} +1 -1
- package/static/app/assets/{cpu-Vvq0OKTr.js → cpu-DvUQxdKe.js} +1 -1
- package/static/app/assets/{download-SEcXzkx1.js → download-CFqYG90a.js} +1 -1
- package/static/app/assets/{folder-open-Dw1ff_Qa.js → folder-open-CVSnp-Dp.js} +1 -1
- package/static/app/assets/{hard-drive-B00fR7_r.js → hard-drive-Ckr4Vd6-.js} +1 -1
- package/static/app/assets/{index-Dm9VXl1o.js → index--0zKF5Ow.js} +3 -3
- package/static/app/assets/{input-DtdWYQEa.js → input-D-JKquXU.js} +1 -1
- package/static/app/assets/{network-CpjBu0kI.js → network-DB88FZ2T.js} +1 -1
- package/static/app/assets/{primitives-CwsudBwc.js → primitives-D8U9OaIo.js} +1 -1
- package/static/app/assets/search-B8jsVTw_.js +1 -0
- package/static/app/assets/{shield-alert-CpjBc-gQ.js → shield-alert-DnsvO79P.js} +1 -1
- package/static/app/assets/{textarea-DUPyjHQs.js → textarea-4RchwbTa.js} +1 -1
- package/static/app/assets/{useFocusTrap-BWcMtCWH.js → useFocusTrap-CFJjy7cS.js} +1 -1
- package/static/app/assets/{useQuery-Dg5fPqTS.js → useQuery-3Reu-A4a.js} +1 -1
- package/static/app/assets/{users-BgcdTQGM.js → users-BTxYksxa.js} +1 -1
- package/static/app/assets/{utils-a3YXFtEO.js → utils-D02Vf-fw.js} +1 -1
- package/static/app/assets/{workspace-BMUEiXUm.js → workspace-CSJNgX-C.js} +1 -1
- package/static/app/index.html +3 -3
- package/static/sw.js +1 -1
- package/static/app/assets/search-CwEJWBEA.js +0 -1
|
@@ -11,7 +11,7 @@ import threading
|
|
|
11
11
|
import time
|
|
12
12
|
import urllib.request
|
|
13
13
|
from pathlib import Path
|
|
14
|
-
from typing import Dict, Optional, Tuple
|
|
14
|
+
from typing import Any, Dict, Optional, Tuple
|
|
15
15
|
|
|
16
16
|
from fastapi import APIRouter, HTTPException, Request
|
|
17
17
|
|
|
@@ -33,7 +33,7 @@ class PermissionGateway:
|
|
|
33
33
|
self.local_approval_ttl_seconds = 5 * 60
|
|
34
34
|
self.local_approval_lock = threading.Lock()
|
|
35
35
|
self.perm_queue_lock = threading.Lock()
|
|
36
|
-
self.local_approvals: Dict[str, Dict[str,
|
|
36
|
+
self.local_approvals: Dict[str, Dict[str, Any]] = {}
|
|
37
37
|
self.discord_permission_webhook_url = config.discord_permission_webhook
|
|
38
38
|
self.discord_bot_token = config.discord_bot_token
|
|
39
39
|
self.discord_permission_channel = config.discord_permission_channel
|
package/latticeai/api/search.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Any, Callable, Dict, Optional
|
|
5
|
+
from typing import Any, Callable, Dict, NoReturn, Optional
|
|
6
6
|
|
|
7
7
|
from fastapi import APIRouter, HTTPException, Request
|
|
8
8
|
from pydantic import BaseModel, Field
|
|
@@ -84,14 +84,16 @@ def create_search_router(
|
|
|
84
84
|
) -> APIRouter:
|
|
85
85
|
router = APIRouter()
|
|
86
86
|
|
|
87
|
-
def _guarded(request: Request) ->
|
|
87
|
+
def _guarded(request: Request) -> "_ScopedSearchService":
|
|
88
88
|
user = require_user(request)
|
|
89
89
|
allowed = None
|
|
90
90
|
if allowed_workspaces_for is not None and user:
|
|
91
91
|
allowed = allowed_workspaces_for(user)
|
|
92
92
|
return _ScopedSearchService(service, allowed)
|
|
93
93
|
|
|
94
|
-
def _raise_graph_error(exc: Exception) ->
|
|
94
|
+
def _raise_graph_error(exc: Exception) -> NoReturn:
|
|
95
|
+
# NoReturn, not None: every handler ends with this in its except
|
|
96
|
+
# branch, and without it each one reads as a missing return.
|
|
95
97
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
|
96
98
|
|
|
97
99
|
@router.post("/api/search/hybrid")
|
|
@@ -515,8 +515,6 @@ def create_security_router(
|
|
|
515
515
|
else:
|
|
516
516
|
raise HTTPException(status_code=400, detail="지원하지 않는 scope입니다.")
|
|
517
517
|
|
|
518
|
-
if not isinstance(rows, list):
|
|
519
|
-
rows = []
|
|
520
518
|
|
|
521
519
|
_log_view(admin_email, "export", f"{scope}:{fmt}", reason="export")
|
|
522
520
|
|
|
@@ -530,7 +528,7 @@ def create_security_router(
|
|
|
530
528
|
headers={"Content-Disposition": f"attachment; filename={filename}"},
|
|
531
529
|
)
|
|
532
530
|
if fmt == "csv":
|
|
533
|
-
body = _csv_dump(rows)
|
|
531
|
+
body = _csv_dump(rows) # type: ignore[assignment]
|
|
534
532
|
filename = f"security_{scope}.csv"
|
|
535
533
|
return Response(
|
|
536
534
|
content=body,
|
|
@@ -538,7 +536,7 @@ def create_security_router(
|
|
|
538
536
|
headers={"Content-Disposition": f"attachment; filename={filename}"},
|
|
539
537
|
)
|
|
540
538
|
if fmt in {"excel", "xlsx"}:
|
|
541
|
-
body = _excel_dump(rows)
|
|
539
|
+
body = _excel_dump(rows) # type: ignore[assignment]
|
|
542
540
|
filename = f"security_{scope}.xlsx"
|
|
543
541
|
return Response(
|
|
544
542
|
content=body,
|
|
@@ -547,7 +545,7 @@ def create_security_router(
|
|
|
547
545
|
)
|
|
548
546
|
if fmt == "pdf":
|
|
549
547
|
overview = build_sensitivity_report(get_history() or []).get("summary", {}) or {}
|
|
550
|
-
body = _pdf_report("Lattice AI Security Report", rows, overview)
|
|
548
|
+
body = _pdf_report("Lattice AI Security Report", rows, overview) # type: ignore[assignment]
|
|
551
549
|
filename = f"security_{scope}.pdf"
|
|
552
550
|
return Response(
|
|
553
551
|
content=body,
|
package/latticeai/api/setup.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Dict, List, Optional
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
6
|
|
|
7
7
|
from fastapi import APIRouter, HTTPException, Request
|
|
8
8
|
from fastapi.responses import StreamingResponse
|
|
@@ -63,7 +63,7 @@ def create_setup_router(
|
|
|
63
63
|
|
|
64
64
|
# ── Setup Wizard ─────────────────────────────────────────────────────────────
|
|
65
65
|
|
|
66
|
-
def setup_auto_state() -> Dict[str,
|
|
66
|
+
def setup_auto_state() -> Dict[str, Any]:
|
|
67
67
|
"""Return the PPT-aligned zero-config setup state used by setup UI/API."""
|
|
68
68
|
profile = auto_setup_probe()
|
|
69
69
|
recommendation = auto_setup_recommend(profile)
|
|
@@ -77,7 +77,7 @@ def create_setup_router(
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
|
|
80
|
-
def primary_setup_model(recs: Dict[str,
|
|
80
|
+
def primary_setup_model(recs: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
81
81
|
models = recs.get("models") if isinstance(recs, dict) else None
|
|
82
82
|
if not isinstance(models, list):
|
|
83
83
|
return None
|
|
@@ -9,7 +9,7 @@ import subprocess
|
|
|
9
9
|
import time
|
|
10
10
|
from dataclasses import dataclass
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Callable, Optional
|
|
12
|
+
from typing import Any, Callable, Dict, Optional
|
|
13
13
|
|
|
14
14
|
from fastapi import APIRouter, Cookie, HTTPException, Request
|
|
15
15
|
from fastapi.responses import FileResponse, HTMLResponse
|
|
@@ -253,7 +253,12 @@ def create_static_routes_router(
|
|
|
253
253
|
"""CPU / RAM / GPU(MLX) 사용량을 반환합니다."""
|
|
254
254
|
require_user(request)
|
|
255
255
|
import re as _re
|
|
256
|
-
result
|
|
256
|
+
result: Dict[str, Any] = {
|
|
257
|
+
"cpu_pct": 0.0,
|
|
258
|
+
"ram_pct": 0.0,
|
|
259
|
+
"gpu_mem_pct": 0.0,
|
|
260
|
+
"gpu_mem_gb": 0.0,
|
|
261
|
+
}
|
|
257
262
|
try:
|
|
258
263
|
# CPU
|
|
259
264
|
top_out = subprocess.run(["top", "-l", "1", "-n", "0"], capture_output=True, text=True, timeout=4).stdout
|
package/latticeai/api/tools.py
CHANGED
|
@@ -243,10 +243,15 @@ def create_tools_router(
|
|
|
243
243
|
api_router = APIRouter()
|
|
244
244
|
HOOKS = hooks
|
|
245
245
|
CONFIG = config
|
|
246
|
-
|
|
247
|
-
|
|
246
|
+
# These three are Optional in the signature only because the legacy
|
|
247
|
+
# kwarg form predates AppContext; the router cannot be built without
|
|
248
|
+
# them, so resolve once here rather than at every use.
|
|
249
|
+
if data_dir is None or static_dir is None:
|
|
250
|
+
raise RuntimeError("create_tools_router requires data_dir and static_dir")
|
|
251
|
+
DATA_DIR: Path = data_dir
|
|
252
|
+
STATIC_DIR: Path = static_dir
|
|
248
253
|
router = model_router
|
|
249
|
-
ENABLE_GRAPH = enable_graph
|
|
254
|
+
ENABLE_GRAPH: bool = bool(enable_graph)
|
|
250
255
|
KNOWLEDGE_GRAPH = knowledge_graph
|
|
251
256
|
LOCAL_KG_WATCHER = local_kg_watcher
|
|
252
257
|
_require_graph = require_graph
|
|
@@ -327,7 +332,7 @@ def create_tools_router(
|
|
|
327
332
|
or None
|
|
328
333
|
)
|
|
329
334
|
|
|
330
|
-
def _knowledge_scope(request: Request, current_user: str, *, write: bool) -> Dict[str,
|
|
335
|
+
def _knowledge_scope(request: Request, current_user: str, *, write: bool) -> Dict[str, Any]:
|
|
331
336
|
# Preserve the historical shared vault only for explicit single-user,
|
|
332
337
|
# no-auth local mode. Authenticated deployments always partition by
|
|
333
338
|
# both authorized workspace and account.
|
|
@@ -165,35 +165,38 @@ def create_workspace_router(context: AppContext) -> APIRouter:
|
|
|
165
165
|
router = APIRouter()
|
|
166
166
|
|
|
167
167
|
# Bind injected deps to the names the moved handler bodies expect.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
168
|
+
# `context.require(...)` for anything this router calls: an absent
|
|
169
|
+
# dependency now names itself here instead of surfacing as
|
|
170
|
+
# "'NoneType' object is not callable" inside a request handler.
|
|
171
|
+
service = context.require("workspace_service")
|
|
172
|
+
require_user = context.require("require_user")
|
|
173
|
+
require_admin = context.require("require_admin")
|
|
174
|
+
get_current_user = context.require("get_current_user")
|
|
175
|
+
append_audit_event = context.require("append_audit_event")
|
|
176
|
+
get_history = context.require("get_history")
|
|
177
|
+
get_audit_log = context.require("get_audit_log")
|
|
178
|
+
load_users = context.require("load_users")
|
|
179
|
+
scan_environment = context.require("scan_environment")
|
|
180
|
+
local_sysinfo = context.require("local_sysinfo")
|
|
181
|
+
get_recommendations = context.require("get_recommendations")
|
|
182
|
+
install_skill = context.require("install_skill")
|
|
183
|
+
remove_skill_directory = context.require("remove_skill_directory")
|
|
184
|
+
redact_secret_text = context.require("redact_secret_text")
|
|
185
|
+
capability_registry = context.require("capability_registry")
|
|
183
186
|
|
|
184
187
|
svc = service
|
|
185
188
|
WORKSPACE_OS = service.store
|
|
186
|
-
_workspace_graph = context.workspace_graph
|
|
187
|
-
_graph_stats_safe = context.graph_stats
|
|
188
|
-
_workspace_models_payload = context.workspace_models
|
|
189
|
-
_workspace_settings_payload = context.workspace_settings
|
|
190
|
-
_require_graph = context.require_graph
|
|
189
|
+
_workspace_graph = context.require("workspace_graph")
|
|
190
|
+
_graph_stats_safe = context.require("graph_stats")
|
|
191
|
+
_workspace_models_payload = context.require("workspace_models")
|
|
192
|
+
_workspace_settings_payload = context.require("workspace_settings")
|
|
193
|
+
_require_graph = context.require("require_graph")
|
|
191
194
|
KNOWLEDGE_GRAPH = context.knowledge_graph
|
|
192
195
|
LOCAL_KG_WATCHER = context.local_kg_watcher
|
|
193
196
|
SKILLS_DIR = context.skills_dir
|
|
194
197
|
LOCAL_MODEL = context.local_model
|
|
195
198
|
PUBLIC_MODEL = context.public_model
|
|
196
|
-
_fetch_skills_marketplace = context.fetch_skills_marketplace
|
|
199
|
+
_fetch_skills_marketplace = context.require("fetch_skills_marketplace")
|
|
197
200
|
_workspace_scope = _workspace_scope_from_request
|
|
198
201
|
|
|
199
202
|
def _gate_read(request: Request):
|
|
@@ -651,7 +654,7 @@ def create_workspace_router(context: AppContext) -> APIRouter:
|
|
|
651
654
|
@router.get("/workspace/vscode/status")
|
|
652
655
|
async def workspace_vscode_status(request: Request):
|
|
653
656
|
require_user(request)
|
|
654
|
-
last_seen = int(_VSCODE_STATUS.get("last_seen_ms") or 0)
|
|
657
|
+
last_seen = int(str(_VSCODE_STATUS.get("last_seen_ms") or 0))
|
|
655
658
|
now_ms = int(datetime.utcnow().timestamp() * 1000)
|
|
656
659
|
connected = last_seen > 0 and (now_ms - last_seen) < 60000
|
|
657
660
|
return {
|