ltcai 3.6.0 → 4.0.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 +11 -7
- package/docs/V4_BRAIN_ARCHITECTURE.md +322 -0
- package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +509 -0
- package/docs/V4_IMPLEMENTATION_PLAN.md +470 -0
- package/docs/kg-schema.md +47 -53
- package/kg_schema.py +93 -10
- package/knowledge_graph.py +362 -33
- package/knowledge_graph_api.py +11 -127
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/admin.py +1 -1
- package/latticeai/api/agents.py +7 -1
- package/latticeai/api/auth.py +27 -4
- package/latticeai/api/chat.py +112 -76
- package/latticeai/api/health.py +1 -1
- package/latticeai/api/hooks.py +1 -1
- package/latticeai/api/knowledge_graph.py +146 -0
- package/latticeai/api/local_files.py +1 -1
- package/latticeai/api/mcp.py +23 -11
- package/latticeai/api/memory.py +1 -1
- package/latticeai/api/models.py +1 -1
- package/latticeai/api/network.py +81 -0
- package/latticeai/api/realtime.py +1 -1
- package/latticeai/api/search.py +26 -2
- package/latticeai/api/security_dashboard.py +2 -3
- package/latticeai/api/setup.py +2 -2
- package/latticeai/api/static_routes.py +2 -4
- package/latticeai/api/tools.py +3 -0
- package/latticeai/api/workflow_designer.py +46 -0
- package/latticeai/api/workspace.py +71 -49
- package/latticeai/app_factory.py +1710 -0
- package/latticeai/brain/__init__.py +18 -0
- package/latticeai/brain/context.py +213 -0
- package/latticeai/brain/conversations.py +236 -0
- package/latticeai/brain/identity.py +175 -0
- package/latticeai/brain/memory.py +102 -0
- package/latticeai/brain/network.py +205 -0
- package/latticeai/core/agent.py +31 -7
- package/latticeai/core/audit.py +0 -7
- package/latticeai/core/config.py +1 -1
- package/latticeai/core/context_builder.py +1 -2
- package/latticeai/core/enterprise.py +1 -1
- package/latticeai/core/graph_curator.py +2 -2
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/mcp_registry.py +791 -0
- package/latticeai/core/model_compat.py +1 -1
- package/latticeai/core/model_resolution.py +0 -1
- package/latticeai/core/multi_agent.py +238 -4
- package/latticeai/core/security.py +1 -1
- package/latticeai/core/sessions.py +37 -7
- package/latticeai/core/workflow_engine.py +114 -2
- package/latticeai/core/workspace_os.py +58 -10
- package/latticeai/models/__init__.py +7 -0
- package/latticeai/models/router.py +779 -0
- package/latticeai/server_app.py +29 -1536
- package/latticeai/services/agent_runtime.py +1 -0
- package/latticeai/services/app_context.py +75 -14
- package/latticeai/services/ingestion.py +47 -0
- package/latticeai/services/kg_portability.py +33 -3
- package/latticeai/services/memory_service.py +39 -11
- package/latticeai/services/model_runtime.py +2 -5
- package/latticeai/services/platform_runtime.py +100 -23
- package/latticeai/services/search_service.py +17 -8
- package/latticeai/services/tool_dispatch.py +12 -2
- package/latticeai/services/triggers.py +241 -0
- package/latticeai/services/upload_service.py +37 -12
- package/latticeai/services/workspace_service.py +31 -0
- package/llm_router.py +29 -772
- package/ltcai_cli.py +1 -2
- package/mcp_registry.py +25 -788
- package/p_reinforce.py +124 -14
- package/package.json +9 -7
- package/scripts/bump_version.py +99 -0
- package/scripts/generate_diagrams.py +0 -1
- package/scripts/lint_v3.mjs +82 -18
- package/scripts/validate_release_artifacts.py +0 -1
- package/scripts/wheel_smoke.py +142 -0
- package/server.py +11 -7
- package/setup_wizard.py +1142 -0
- package/static/account.html +2 -4
- package/static/admin.html +3 -5
- package/static/chat.html +3 -6
- package/static/graph.html +2 -4
- package/static/sw.js +81 -52
- package/static/v3/asset-manifest.json +20 -19
- package/static/v3/css/{lattice.base.e4cdd05d.css → lattice.base.49deefb5.css} +1 -1
- package/static/v3/css/lattice.base.css +1 -1
- package/static/v3/css/{lattice.components.9b49d614.css → lattice.components.cde18231.css} +1 -1
- package/static/v3/css/lattice.components.css +1 -1
- package/static/v3/css/{lattice.shell.8fcc9d33.css → lattice.shell.29d36d85.css} +1 -1
- package/static/v3/css/lattice.shell.css +1 -1
- package/static/v3/css/{lattice.tokens.e7018963.css → lattice.tokens.304cbc40.css} +3 -0
- package/static/v3/css/lattice.tokens.css +3 -0
- package/static/v3/css/{lattice.views.22f69117.css → lattice.views.0a18b6c5.css} +2 -2
- package/static/v3/css/lattice.views.css +2 -2
- package/static/v3/index.html +3 -4
- package/static/v3/js/{app.c541f955.js → app.356e6452.js} +1 -1
- package/static/v3/js/core/{api.33d6320e.js → api.7a308b89.js} +1 -1
- package/static/v3/js/core/{routes.2ce3815a.js → routes.7222343d.js} +22 -22
- package/static/v3/js/core/routes.js +22 -22
- package/static/v3/js/core/{shell.8c163e0e.js → shell.a1657f20.js} +4 -4
- package/static/v3/js/core/shell.js +1 -1
- package/static/v3/js/core/{store.34ebd5e6.js → store.204a08b2.js} +1 -1
- package/static/v3/js/core/store.js +1 -1
- package/static/v3/js/views/graph-canvas.17c15d65.js +509 -0
- package/static/v3/js/views/graph-canvas.js +509 -0
- package/static/v3/js/views/{hybrid-search.b22b97e0.js → hybrid-search.2fb63ed9.js} +1 -2
- package/static/v3/js/views/hybrid-search.js +1 -2
- package/static/v3/js/views/{knowledge-graph.a96040a5.js → knowledge-graph.5e40cbeb.js} +33 -37
- package/static/v3/js/views/knowledge-graph.js +33 -37
- package/static/vendor/chart.umd.min.js +20 -0
- package/static/vendor/fonts/inter-latin-300-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-400-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-500-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-600-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-700-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-800-normal.woff2 +0 -0
- package/static/vendor/fonts/inter.css +44 -0
- package/static/vendor/icons/tabler-icons.min.css +4 -0
- package/static/vendor/icons/tabler-icons.woff2 +0 -0
- package/static/vendor/marked.min.js +69 -0
- package/static/workspace.html +2 -2
- package/telegram_bot.py +1 -2
- package/tools/commands.py +4 -2
- package/tools/computer.py +1 -1
- package/tools/documents.py +1 -3
- package/tools/filesystem.py +0 -4
- package/tools/knowledge.py +1 -3
- package/tools/network.py +1 -3
- package/codex_telegram_bot.py +0 -195
- package/docs/assets/v3.4.0/agent-run.png +0 -0
- package/docs/assets/v3.4.0/agents.png +0 -0
- package/docs/assets/v3.4.0/before/chat-before.png +0 -0
- package/docs/assets/v3.4.0/before/files-before.png +0 -0
- package/docs/assets/v3.4.0/chat.png +0 -0
- package/docs/assets/v3.4.0/connect-folder.png +0 -0
- package/docs/assets/v3.4.0/files.png +0 -0
- package/docs/assets/v3.4.0/home.png +0 -0
- package/docs/assets/v3.4.0/hooks-dispatch.png +0 -0
- package/docs/assets/v3.4.0/knowledge-graph.png +0 -0
- package/docs/assets/v3.4.0/local-agent.png +0 -0
- package/docs/assets/v3.4.0/memory.png +0 -0
- package/docs/assets/v3.4.0/settings.png +0 -0
- package/docs/assets/v3.4.0/vision-input.png +0 -0
- package/docs/assets/v3.4.0/workflows.png +0 -0
- package/docs/assets/v3.4.1/e2e_runtime_log.txt +0 -42
- package/docs/assets/v3.4.1/hooks-dispatch.png +0 -0
- package/docs/assets/v3.4.1/local-agent.png +0 -0
- package/docs/images/admin-dashboard.png +0 -0
- package/docs/images/architecture.png +0 -0
- package/docs/images/enterprise.png +0 -0
- package/docs/images/graph.png +0 -0
- package/docs/images/hero.gif +0 -0
- package/docs/images/knowledge-graph.png +0 -0
- package/docs/images/lattice-ai-demo.gif +0 -0
- package/docs/images/lattice-ai-hero.png +0 -0
- package/docs/images/logo.svg +0 -33
- package/docs/images/mobile-responsive.png +0 -0
- package/docs/images/model-recommendation.png +0 -0
- package/docs/images/onboarding.png +0 -0
- package/docs/images/organization.png +0 -0
- package/docs/images/pipeline.png +0 -0
- package/docs/images/screenshot-admin.png +0 -0
- package/docs/images/screenshot-chat.png +0 -0
- package/docs/images/screenshot-graph.png +0 -0
- package/docs/images/skills.png +0 -0
- package/docs/images/workspace-dark.png +0 -0
- package/docs/images/workspace-light.png +0 -0
- package/docs/images/workspace.png +0 -0
- package/requirements.txt +0 -16
|
@@ -18,7 +18,7 @@ from pathlib import Path
|
|
|
18
18
|
from typing import Any, Callable, Dict, Iterable, List, Optional
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
WORKSPACE_OS_VERSION = "
|
|
21
|
+
WORKSPACE_OS_VERSION = "4.0.0"
|
|
22
22
|
|
|
23
23
|
# Workspace types separate single-user Personal workspaces from shared
|
|
24
24
|
# Organization workspaces. Both keep the same local-first JSON store; the type
|
|
@@ -430,7 +430,10 @@ class WorkspaceOSStore:
|
|
|
430
430
|
"version": WORKSPACE_OS_VERSION,
|
|
431
431
|
"identity": state.get("identity"),
|
|
432
432
|
"active_workspace": state.get("active_workspace"),
|
|
433
|
-
|
|
433
|
+
# The raw workspace registry (with member lists) must not leak to
|
|
434
|
+
# non-members; WorkspaceService.summary() adds a membership-filtered
|
|
435
|
+
# "workspace_registry" instead.
|
|
436
|
+
"workspace_count": len(state.get("workspaces") or {}),
|
|
434
437
|
"navigation": list(WORKSPACE_AREAS),
|
|
435
438
|
"feature_flags": state.get("feature_flags"),
|
|
436
439
|
"updated_at": state.get("updated_at"),
|
|
@@ -1229,15 +1232,26 @@ class WorkspaceOSStore:
|
|
|
1229
1232
|
]
|
|
1230
1233
|
return {"query": query, "memories": memories[: max(1, min(limit, 100))]}
|
|
1231
1234
|
|
|
1235
|
+
def get_memory(self, memory_id: str) -> Dict[str, Any]:
|
|
1236
|
+
record = next(
|
|
1237
|
+
(item for item in _listify(self.load_state().get("memories")) if item.get("id") == memory_id),
|
|
1238
|
+
None,
|
|
1239
|
+
)
|
|
1240
|
+
if record is None:
|
|
1241
|
+
raise FileNotFoundError(memory_id)
|
|
1242
|
+
return record
|
|
1243
|
+
|
|
1232
1244
|
def delete_memory(self, memory_id: str) -> Dict[str, Any]:
|
|
1233
1245
|
state = self.load_state()
|
|
1234
1246
|
memories = _listify(state.get("memories"))
|
|
1235
|
-
|
|
1236
|
-
if
|
|
1247
|
+
target = next((item for item in memories if item.get("id") == memory_id), None)
|
|
1248
|
+
if target is None:
|
|
1237
1249
|
raise FileNotFoundError(memory_id)
|
|
1238
|
-
state["memories"] =
|
|
1250
|
+
state["memories"] = [item for item in memories if item.get("id") != memory_id]
|
|
1239
1251
|
self.save_state(state)
|
|
1240
|
-
self.record_timeline_event(
|
|
1252
|
+
self.record_timeline_event(
|
|
1253
|
+
"memory", "memory_deleted", {"memory_id": memory_id}, workspace_id=target.get("workspace_id")
|
|
1254
|
+
)
|
|
1241
1255
|
return {"status": "ok", "memory_id": memory_id}
|
|
1242
1256
|
|
|
1243
1257
|
def create_memory_snapshot(
|
|
@@ -1306,12 +1320,15 @@ class WorkspaceOSStore:
|
|
|
1306
1320
|
memory_snapshots: Optional[List[Dict[str, Any]]] = None,
|
|
1307
1321
|
graph: Any = None,
|
|
1308
1322
|
workspace_id: Optional[str] = None,
|
|
1323
|
+
mode: str = "simulation",
|
|
1309
1324
|
) -> Dict[str, Any]:
|
|
1310
1325
|
state = self.load_state()
|
|
1311
1326
|
resolved_workspace = self._resolve_scope(workspace_id, state)
|
|
1312
1327
|
run = {
|
|
1313
1328
|
"id": f"agent-run-{_json_hash([agent_id, input_text, output_text, _now()])[:16]}",
|
|
1329
|
+
"record_schema_version": 2,
|
|
1314
1330
|
"agent_id": agent_id,
|
|
1331
|
+
"mode": mode,
|
|
1315
1332
|
"status": status,
|
|
1316
1333
|
"input": input_text,
|
|
1317
1334
|
"output_preview": output_text[:1000],
|
|
@@ -1328,14 +1345,19 @@ class WorkspaceOSStore:
|
|
|
1328
1345
|
"memory_snapshots": memory_snapshots or [],
|
|
1329
1346
|
"created_at": _now(),
|
|
1330
1347
|
}
|
|
1331
|
-
if
|
|
1348
|
+
if mode == "simulation":
|
|
1349
|
+
# Simulated runs are replay scaffolding, not experiences — they must
|
|
1350
|
+
# never enter the knowledge graph as real provenance.
|
|
1351
|
+
run["graph_node_id"] = None
|
|
1352
|
+
run["graph_skipped"] = "simulation runs are not recorded in the knowledge graph"
|
|
1353
|
+
elif graph is not None:
|
|
1332
1354
|
try:
|
|
1333
1355
|
ingested = graph.ingest_event(
|
|
1334
1356
|
"AgentRun",
|
|
1335
1357
|
f"{agent_id} {status}",
|
|
1336
1358
|
user_email=user_email,
|
|
1337
1359
|
source="workspace_os",
|
|
1338
|
-
metadata={"run_id": run["id"], "agent_id": agent_id, "status": status},
|
|
1360
|
+
metadata={"run_id": run["id"], "agent_id": agent_id, "status": status, "mode": mode},
|
|
1339
1361
|
)
|
|
1340
1362
|
run["graph_node_id"] = ingested.get("node_id")
|
|
1341
1363
|
except Exception as exc:
|
|
@@ -1427,14 +1449,18 @@ class WorkspaceOSStore:
|
|
|
1427
1449
|
user_email: Optional[str] = None,
|
|
1428
1450
|
graph: Any = None,
|
|
1429
1451
|
workspace_id: Optional[str] = None,
|
|
1452
|
+
mode: str = "simulation",
|
|
1453
|
+
pause: Optional[Dict[str, Any]] = None,
|
|
1430
1454
|
) -> Dict[str, Any]:
|
|
1431
1455
|
"""Persist a Workflow Designer execution into local-first run history."""
|
|
1432
1456
|
state = self.load_state()
|
|
1433
1457
|
resolved_workspace = self._resolve_scope(workspace_id, state)
|
|
1434
1458
|
run = {
|
|
1435
1459
|
"id": f"workflow-run-{_json_hash([workflow_id, name, status, _now()])[:16]}",
|
|
1460
|
+
"record_schema_version": 2,
|
|
1436
1461
|
"workflow_id": workflow_id,
|
|
1437
1462
|
"name": name or "workflow",
|
|
1463
|
+
"mode": mode,
|
|
1438
1464
|
"status": status,
|
|
1439
1465
|
"timeline": timeline or [],
|
|
1440
1466
|
"outputs": outputs or {},
|
|
@@ -1442,14 +1468,21 @@ class WorkspaceOSStore:
|
|
|
1442
1468
|
"workspace_id": resolved_workspace,
|
|
1443
1469
|
"created_at": _now(),
|
|
1444
1470
|
}
|
|
1445
|
-
if
|
|
1471
|
+
if pause:
|
|
1472
|
+
run["pause"] = pause
|
|
1473
|
+
if mode == "simulation":
|
|
1474
|
+
# Record-only node runners do no real work; their runs must not be
|
|
1475
|
+
# written into the knowledge graph as if they were real executions.
|
|
1476
|
+
run["graph_node_id"] = None
|
|
1477
|
+
run["graph_skipped"] = "simulation runs are not recorded in the knowledge graph"
|
|
1478
|
+
elif graph is not None:
|
|
1446
1479
|
try:
|
|
1447
1480
|
ingested = graph.ingest_event(
|
|
1448
1481
|
"WorkflowRun",
|
|
1449
1482
|
f"{run['name']} {status}",
|
|
1450
1483
|
user_email=user_email,
|
|
1451
1484
|
source="workspace_os",
|
|
1452
|
-
metadata={"run_id": run["id"], "workflow_id": workflow_id, "status": status},
|
|
1485
|
+
metadata={"run_id": run["id"], "workflow_id": workflow_id, "status": status, "mode": mode},
|
|
1453
1486
|
)
|
|
1454
1487
|
run["graph_node_id"] = ingested.get("node_id")
|
|
1455
1488
|
except Exception as exc:
|
|
@@ -1478,6 +1511,21 @@ class WorkspaceOSStore:
|
|
|
1478
1511
|
runs = [run for run in runs if run.get("workflow_id") == workflow_id]
|
|
1479
1512
|
return {"runs": list(reversed(runs[-max(1, min(limit, 300)):]))}
|
|
1480
1513
|
|
|
1514
|
+
def mark_workflow_run_resolved(
|
|
1515
|
+
self, run_id: str, *, resumed_run_id: str, approved: bool,
|
|
1516
|
+
workspace_id: Optional[str] = None,
|
|
1517
|
+
) -> Dict[str, Any]:
|
|
1518
|
+
"""Close out a paused run after its approval decision (one decision only)."""
|
|
1519
|
+
state = self.load_state()
|
|
1520
|
+
run = next((item for item in _listify(state.get("workflow_runs")) if item.get("id") == run_id), None)
|
|
1521
|
+
if run is None or (workspace_id and self._record_workspace(run) != str(workspace_id)):
|
|
1522
|
+
raise FileNotFoundError(run_id)
|
|
1523
|
+
run["status"] = "resumed" if approved else "denied"
|
|
1524
|
+
run["resolved_at"] = _now()
|
|
1525
|
+
run["resumed_run_id"] = resumed_run_id
|
|
1526
|
+
self.save_state(state)
|
|
1527
|
+
return run
|
|
1528
|
+
|
|
1481
1529
|
def get_workflow_run(self, run_id: str, workspace_id: Optional[str] = None) -> Dict[str, Any]:
|
|
1482
1530
|
run = next((item for item in _listify(self.load_state().get("workflow_runs")) if item.get("id") == run_id), None)
|
|
1483
1531
|
if not run or (workspace_id and self._record_workspace(run) != str(workspace_id)):
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""Model/provider boundary package.
|
|
2
|
+
|
|
3
|
+
``latticeai.models.router`` hosts the multi-engine LLM router (MLX-VLM,
|
|
4
|
+
Ollama, vLLM, llama.cpp, LM Studio, OpenAI-compatible providers), relocated
|
|
5
|
+
from the root ``llm_router.py`` in v4 (T2). The root module remains as a
|
|
6
|
+
deprecation shim.
|
|
7
|
+
"""
|