ltcai 2.0.0 → 2.2.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 +140 -589
  2. package/auto_setup.py +17 -17
  3. package/docs/CHANGELOG.md +99 -0
  4. package/docs/MULTI_AGENT_RUNTIME.md +23 -5
  5. package/docs/PLUGIN_SDK.md +21 -8
  6. package/docs/REALTIME_COLLABORATION.md +19 -6
  7. package/docs/V2_ARCHITECTURE.md +65 -33
  8. package/docs/WORKFLOW_DESIGNER.md +18 -8
  9. package/docs/architecture.md +127 -135
  10. package/docs/kg-schema.md +3 -3
  11. package/docs/public-deploy.md +2 -3
  12. package/knowledge_graph.py +2 -2
  13. package/latticeai/__init__.py +1 -1
  14. package/latticeai/api/agents.py +57 -1
  15. package/latticeai/api/marketplace.py +81 -0
  16. package/latticeai/api/models.py +8 -0
  17. package/latticeai/api/plugins.py +1 -1
  18. package/latticeai/api/realtime.py +1 -1
  19. package/latticeai/api/workflow_designer.py +10 -1
  20. package/latticeai/core/config.py +1 -1
  21. package/latticeai/core/graph_curator.py +2 -2
  22. package/latticeai/core/marketplace.py +178 -0
  23. package/latticeai/core/model_compat.py +7 -63
  24. package/latticeai/core/model_resolution.py +1 -1
  25. package/latticeai/core/multi_agent.py +359 -68
  26. package/latticeai/core/plugins.py +29 -13
  27. package/latticeai/core/realtime.py +1 -1
  28. package/latticeai/core/workflow_engine.py +1 -1
  29. package/latticeai/core/workspace_os.py +257 -10
  30. package/latticeai/server_app.py +17 -5
  31. package/latticeai/services/model_catalog.py +105 -153
  32. package/latticeai/services/model_recommendation.py +28 -17
  33. package/latticeai/services/model_runtime.py +2 -2
  34. package/latticeai/services/platform_runtime.py +9 -5
  35. package/llm_router.py +80 -92
  36. package/ltcai_cli.py +2 -3
  37. package/package.json +2 -2
  38. package/static/agents.html +47 -3
  39. package/static/chat.html +5 -6
  40. package/static/plugins.html +51 -0
  41. package/static/scripts/chat.js +34 -36
  42. package/static/workflows.html +22 -0
  43. package/static/workspace.html +1 -1
  44. package/telegram_bot.py +1 -1
@@ -1,156 +1,148 @@
1
- # Lattice AI — 아키텍처
2
-
3
- ## 전체 구조
4
-
5
- ```
6
- ┌─────────────────────────────────────────────────────────┐
7
- │ 클라이언트 레이어 │
8
- │ 웹 UI (chat.html) │ VS Code 확장 │ Telegram 봇 │
9
- └──────────────────────────┬──────────────────────────────┘
10
- HTTP / SSE
11
- ┌──────────────────────────▼──────────────────────────────┐
12
- │ server.py FastAPI (port 4825) │
13
- │ │
14
- │ /chat /agent /models /tools/* /mcp/* /garden │
15
- │ /account /admin /auth/sso /knowledge-graph /graph │
16
- └────┬──────────┬──────────┬──────────┬───────────────────┘
17
- │ │ │ │
18
- ▼ ▼ ▼ ▼
19
- llm_router tools.py knowledge_ p_reinforce
20
- .py graph.py .py
21
-
22
- ├── MLX (mlx_lm / mlx_vlm) ← Apple Silicon 로컬
23
- ├── OpenAI SDK ← openai / groq / together / openrouter
24
- └── Ollama / vLLM REST ← 로컬 서버 연동
1
+ # Lattice AI Architecture
2
+
3
+ Lattice AI v2.2.0 is a local-first **AI Knowledge OS**. The architecture is
4
+ organized around one durable center: the Knowledge Graph. Models, tools,
5
+ agents, workflows, and UI modes are replaceable layers that operate on top of
6
+ the graph.
7
+
8
+ ## Architecture Goals
9
+
10
+ - Keep user knowledge local-first by default.
11
+ - Treat multimodal input as the normal path, not an add-on.
12
+ - Preserve evidence, decisions, files, artifacts, and work history.
13
+ - Keep models replaceable and policy-governed.
14
+ - Explain risk and source facts instead of hiding capability.
15
+ - Keep basic and advanced modes feature-equivalent.
16
+ - Keep admin-only capabilities explicit and auditable.
17
+
18
+ ## System View
19
+
20
+ ```mermaid
21
+ flowchart TD
22
+ User["User files, screenshots, chats, notes, code, work logs"]
23
+ Ingestion["Multimodal ingestion"]
24
+ Extract["Entity, relation, evidence extraction"]
25
+ Graph["Knowledge Graph"]
26
+ Context["Graph context builder"]
27
+ Models["Multimodal model runtime"]
28
+ Agents["Agent runtime and workflows"]
29
+ Outputs["Advice, analysis, documents, automation"]
30
+ Admin["Admin policy and audit"]
31
+
32
+ User --> Ingestion
33
+ Ingestion --> Extract
34
+ Extract --> Graph
35
+ Graph --> Context
36
+ Context --> Models
37
+ Models --> Agents
38
+ Agents --> Outputs
39
+ Admin --> Models
40
+ Admin --> Graph
25
41
  ```
26
42
 
27
- ## 파일별 역할
28
-
29
- | 파일 | 역할 |
30
- |------|------|
31
- | `server.py` | FastAPI 앱, 모든 HTTP 엔드포인트, 인증/세션/CORS/rate limit |
32
- | `ltcai_cli.py` | CLI 엔트리포인트 (`LTCAI` 명령), `doctor` 서브커맨드, uvicorn 실행 |
33
- | `llm_router.py` | 로컬(MLX/Ollama) ↔ 클라우드(OpenAI/Groq/…) 라우팅, 스트리밍 SSE |
34
- | `tools.py` | 에이전트 도구 구현: read_file, edit_file, grep, run_command, todo_write/read, 스크린샷 등 |
35
- | `knowledge_graph.py` | SQLite 지식 그래프 (노드/엣지/청크), Graph RAG 컨텍스트 주입 |
36
- | `p_reinforce.py` | P-Reinforce 지식 정원 엔진, `~/.ltcai-brain/` 분류 저장 |
37
- | `telegram_bot.py` | 로컬 AI Telegram 미러 봇 |
38
- | `codex_telegram_bot.py` | 클라우드 Codex Telegram 봇 (GPT + GitHub 이슈) |
39
- | `vscode-extension/` | TypeScript VS Code 확장 |
40
- | `static/` | 웹 UI HTML (chat, account, admin, graph), PWA manifest/SW |
41
- | `bin/ltcai.js` | npm CLI 엔트리포인트 (Python 환경 자동 부트스트랩) |
42
-
43
- ## 데이터 흐름
44
-
45
- ### 채팅 요청
43
+ ## Durable Core
46
44
 
47
- ```
48
- 브라우저 → POST /chat
49
- → server.py: 인증 확인, rate limit
50
- → llm_router.py: 모델 선택 (로컬/클라우드)
51
- → knowledge_graph.py: Graph RAG 컨텍스트 조회 + 주입
52
- → LLM 스트리밍 응답 (SSE)
53
- → knowledge_graph.py: 메시지/응답 인제스트
54
- ```
45
+ The Knowledge Graph stores the durable user and organization memory:
55
46
 
56
- ### 에이전트 요청
47
+ - files and document evidence
48
+ - images and screenshots
49
+ - conversations and notes
50
+ - user decisions
51
+ - work history
52
+ - generated artifacts
53
+ - agent and workflow events
57
54
 
58
- ```
59
- 브라우저/VS Code POST /agent
60
- → server.py: 인증 확인, rate limit (6/분)
61
- → llm_router.py: Discover→Plan→Implement→Verify 루프 (max 25스텝)
62
- → tools.py: read_file / edit_file / grep / run_command / todo_*
63
- → 각 스텝 결과 스트리밍
64
- ```
55
+ The LLM is not the product core. It is an execution worker that can be replaced
56
+ when hardware, policy, or user preference changes.
65
57
 
66
- ### 문서 업로드
58
+ ## Multimodal Ingestion
67
59
 
68
- ```
69
- 브라우저 POST /upload
70
- → server.py: magic-number 검증, rate limit (12/분)
71
- → tools.py: PDF/DOCX/XLSX/PPTX 파싱
72
- → knowledge_graph.py: Chunk/Page/Sheet/Slide 노드 인제스트
73
- → blob 저장: ~/.ltcai/knowledge_graph_blobs/
74
- ```
60
+ Lattice AI assumes users will provide source material directly. The expected
61
+ input set includes:
75
62
 
76
- ## 데이터 저장소
63
+ - PDF
64
+ - Word
65
+ - Excel
66
+ - PowerPoint
67
+ - images
68
+ - screenshots
69
+ - chat history
70
+ - notes
71
+ - web content
72
+ - code
73
+ - work logs
77
74
 
78
- ```
79
- ~/.ltcai/
80
- ├── users.json # 사용자 계정 (scrypt 해시)
81
- ├── sessions.json # 세션 토큰 (24h TTL)
82
- ├── chat_history.json # 채팅 히스토리
83
- ├── knowledge_graph.sqlite # Graph RAG SQLite DB
84
- ├── knowledge_graph_blobs/ # 원본 업로드 파일
85
- ├── mcp_installs.json # MCP 서버 설치 목록
86
- └── todos.json # 에이전트 TODO 리스트
87
-
88
- ~/.ltcai-brain/
89
- ├── INDEX.md
90
- ├── 00_Raw/
91
- ├── 10_Wiki/
92
- ├── 20_Skills/
93
- ├── 30_Projects/
94
- └── 40_Log/
95
- ```
96
-
97
- ## 인증 흐름
98
-
99
- ```
100
- POST /login (username + password)
101
- → scrypt 검증
102
- → 세션 토큰 생성 (UUID, 24h TTL)
103
- → Set-Cookie: session=<token>; HttpOnly; SameSite=Lax
104
-
105
- 모든 민감 엔드포인트:
106
- → _require_auth(): 쿠키 검증 → User 반환 또는 401
107
- ```
108
-
109
- SSO (OIDC):
110
-
111
- ```
112
- GET /auth/sso/login → 리디렉션 (Entra ID / Okta)
113
- GET /auth/sso/callback?code=... → 토큰 교환 → 세션 생성
114
- ```
75
+ The architecture must not ask users to convert these to plain text before AI can
76
+ work on them.
115
77
 
116
- ## MCP 연동
78
+ ## Model Runtime Policy
117
79
 
118
- `/mcp/tools` 에이전트 도구 카탈로그를 MCP 형식으로 노출
119
- Claude Desktop / Cursor의 MCP 설정에 `http://localhost:4825/mcp` 추가 시 직접 도구 사용 가능.
80
+ Local recommended models must be multimodal. The v2.2 local runtime policy is:
120
81
 
121
- 자세한 내용: [mcp-tools.md](mcp-tools.md)
82
+ - macOS Apple Silicon: MLX-VLM first
83
+ - Windows: llama.cpp multimodal path, with LM Studio as a user-friendly option
84
+ - Linux: llama.cpp or vLLM multimodal path depending on GPU support
85
+ - Ollama: kept as an option, not the default priority
122
86
 
123
- ---
87
+ The removed path is the old text-only MLX-LM recommendation route. Low-spec
88
+ machines use smaller or quantized multimodal models.
124
89
 
125
- ## PPT 명세와의 정렬 (2026-05 추가)
90
+ ## Model Source Disclosure
126
91
 
127
- `lattice_ai_full_spec.pptx` (UI 명세서) 맞춰 가지 보강 모듈이 추가됐다.
128
- 어떤 슬라이드가 어떤 파일에 매핑되는지 한눈에:
92
+ Model catalog entries carry source disclosure fields:
129
93
 
130
- | PPT 슬라이드 | 의미 | 구현 파일 |
131
- |--------------|------|-----------|
132
- | 14 (세 가지 약속) | Cross-platform · Auto-setup · Graph 원칙 | (전체 아키텍처) |
133
- | 15·19 (크로스플랫폼·디자인 토큰) | 공유 토큰 = 단일 진실 근원 | [`static/css/tokens.css`](../static/css/tokens.css) |
134
- | 16·17 (자동 환경 매트릭스·5단계) | OS·HW 감지 → 모델 추천 → 설치 → 검증 → 프리셋 | [`auto_setup.py`](../auto_setup.py) |
135
- | 20·21·22 (KG 노드·엣지·데이터 모델) | 10 NodeType / 12 EdgeType + embedding + confidence | [`kg_schema.py`](../kg_schema.py), [`docs/kg-schema.md`](kg-schema.md) |
136
- | 24 (통합 아키텍처) | 6 레이어 (UI / Logic / AI Core / KG / Storage / Auto-Setup) | 이 문서 + 위 파일들 |
94
+ 1. `source_country`
95
+ 2. `source_company`
96
+ 3. `execution_method`
97
+ 4. `internet_requirement`
98
+ 5. `model_name`
137
99
 
138
- ### 신규 모듈 빠른 참조
100
+ These are first-class model facts, not advanced-only metadata.
139
101
 
140
- ```bash
141
- # 자동 환경 세팅 5단계
142
- python3 auto_setup.py probe # ① 시스템 감지
143
- python3 auto_setup.py recommend # ② 모델 추천
144
- python3 auto_setup.py plan # ③ 설치 계획 (실행 안 함)
145
- python3 auto_setup.py plan --apply # ③ 실제 설치 (위험)
146
- python3 auto_setup.py verify # ④ 검증
147
- python3 auto_setup.py preset # ⑤ 프리셋
148
- python3 auto_setup.py all # 전체 흐름
102
+ ## Recommendation Flow
149
103
 
150
- # KG v2 스키마
151
- python3 kg_schema.py init ~/.ltcai/kg_v2.db
152
- python3 kg_schema.py migrate ~/.ltcai/knowledge_graph.db # legacy → v2
153
- python3 kg_schema.py stats ~/.ltcai/knowledge_graph.db
104
+ ```text
105
+ hardware scan
106
+ -> CPU/GPU/RAM/disk/OS analysis
107
+ -> multimodal model shortlist
108
+ -> same-family old generation removal
109
+ -> source disclosure
110
+ -> recommendation reason
111
+ -> download/install/load/verify
154
112
  ```
155
113
 
156
- 전체 명세 구현 매핑은 [`spec-vs-impl.md`](spec-vs-impl.md) 참고.
114
+ The current default recommendation family is Gemma 4. Qwen3-VL and Llama 4
115
+ remain current multimodal alternatives.
116
+
117
+ ## Modes
118
+
119
+ Basic mode and advanced mode have the same feature access.
120
+
121
+ - Basic mode uses plain language and source facts.
122
+ - Advanced mode adds execution, memory, quantization, and load/unload detail.
123
+ - Admin mode adds actual authority: user management, permissions, audit logs,
124
+ organization policy, security policy, sensitive-data monitoring, model approval
125
+ policy, and Private VPC.
126
+
127
+ ## Main Modules
128
+
129
+ | Module | Responsibility |
130
+ | --- | --- |
131
+ | `latticeai/services/model_catalog.py` | Multimodal model catalog, source metadata, aliases |
132
+ | `latticeai/services/model_recommendation.py` | Hardware-aware multimodal recommendation |
133
+ | `latticeai/services/model_runtime.py` | Download, load, server, and runtime orchestration |
134
+ | `llm_router.py` | MLX-VLM and OpenAI-compatible model routing |
135
+ | `knowledge_graph.py` | Graph storage, extraction, local folder graph RAG |
136
+ | `latticeai/core/context_builder.py` | Graph context for generation |
137
+ | `latticeai/core/workspace_os.py` | Workspace state, timeline, snapshots, memory |
138
+ | `latticeai/core/multi_agent.py` | Planner/executor/reviewer/researcher orchestration |
139
+ | `latticeai/core/workflow_engine.py` | Workflow definitions and run history |
140
+ | `latticeai/core/plugins.py` | Plugin manifest, registry, permission boundary |
141
+ | `latticeai/core/security.py` | Local security primitives |
142
+
143
+ ## Compatibility
144
+
145
+ v2.2.0 preserves the additive Workspace OS and API compatibility posture from
146
+ v2.x. Existing graph/workspace data is migrated non-destructively. The release
147
+ does remove current recommendation entries for old or text-only model paths, but
148
+ it does not destructively mutate existing user graph data.
package/docs/kg-schema.md CHANGED
@@ -56,7 +56,7 @@ Edge {
56
56
  weight float [0..1] // 관계의 ‘강도’
57
57
  confidence float [0..1] // 추출/추론의 ‘신뢰도’
58
58
  evidence string[] // 근거 (메시지/청크 ID 리스트)
59
- created_by string // extractor:llm-gemma-3-12b | rule:regex | user
59
+ created_by string // extractor:llm-gemma-4-12b | rule:regex | user
60
60
  created_at ISO8601 UTC
61
61
  }
62
62
  ```
@@ -106,7 +106,7 @@ Edge {
106
106
  "weight": 0.82,
107
107
  "confidence": 0.91,
108
108
  "evidence": ["chunk:01HX7K…#p3", "chunk:01HX7K…#p11"],
109
- "created_by": "extractor:llm-gemma-3-12b"
109
+ "created_by": "extractor:llm-gemma-4-12b"
110
110
  }
111
111
  }
112
112
  ```
@@ -197,7 +197,7 @@ store.upsert_edge(Edge(
197
197
  type=EdgeType.MENTIONS,
198
198
  weight=0.82, confidence=0.91,
199
199
  evidence=["chunk:01HX7K…#p3"],
200
- created_by="extractor:llm-gemma-3-12b",
200
+ created_by="extractor:llm-gemma-4-12b",
201
201
  ))
202
202
 
203
203
  # 이웃 탐색
@@ -131,7 +131,6 @@ yourdomain.com {
131
131
  openai:gpt-4o-mini
132
132
  openai:gpt-4o
133
133
  openrouter:openai/gpt-4o-mini
134
- groq:llama-3.1-8b-instant
135
- groq:llama-3.3-70b-versatile
136
- together:meta-llama/Llama-3.3-70B-Instruct-Turbo
134
+ openrouter:qwen/qwen3-vl-235b-a22b-instruct
135
+ together:Qwen/Qwen3-VL-32B-Instruct
137
136
  ```
@@ -523,7 +523,7 @@ def _extract_concepts_rules(text: str, limit: int = 12) -> List[str]:
523
523
  2. Multi-word proper nouns (Lattice AI, GPT-4o, Claude Sonnet)
524
524
  3. Single capitalized proper nouns not at sentence start (Claude, Python, FastAPI)
525
525
  4. Korean compound technical terms (멀티모달, 에이전트, 그래프RAG)
526
- 5. Hyphenated / versioned identifiers (gpt-4o, mlx-lm, llama-3.3)
526
+ 5. Hyphenated / versioned identifiers (gpt-4o, mlx-vlm, gemma-4)
527
527
  """
528
528
  text = str(text or "")
529
529
  seen: dict = {} # concept_lower → original form
@@ -586,7 +586,7 @@ def _extract_concepts_rules(text: str, limit: int = 12) -> List[str]:
586
586
  if len(m) >= 3 or cnt >= 2:
587
587
  _add(m)
588
588
 
589
- # 6. Hyphenated / versioned identifiers (gpt-4o, llama-3.3, mlx-lm)
589
+ # 6. Hyphenated / versioned identifiers (gpt-4o, gemma-4, mlx-vlm)
590
590
  for m in re.findall(r'\b([a-zA-Z][a-zA-Z0-9]*(?:-[a-zA-Z0-9.]+)+)\b', text):
591
591
  if len(m) >= 4:
592
592
  _add(m)
@@ -1,3 +1,3 @@
1
1
  """Lattice AI - modular server package."""
2
2
 
3
- __version__ = "2.0.0"
3
+ __version__ = "2.2.0"
@@ -1,4 +1,4 @@
1
- """Multi-Agent Runtime 2.0 API router (v2.0).
1
+ """Multi-Agent Runtime API router (v2).
2
2
 
3
3
  Exposes the built-in agent roles and an orchestrated run endpoint that connects
4
4
  to Workspace, Memory, Knowledge Graph, Workflow runs, and the Timeline. Paths
@@ -22,6 +22,12 @@ class AgentRunRequest(BaseModel):
22
22
  max_retries: int = 2
23
23
 
24
24
 
25
+ class MemorySnapshotRequest(BaseModel):
26
+ label: str = "agent memory snapshot"
27
+ reason: str = ""
28
+ memory_ids: List[str] = []
29
+
30
+
25
31
  def create_agents_router(
26
32
  *,
27
33
  store,
@@ -66,6 +72,49 @@ def create_agents_router(
66
72
  scope = gate_read(request)
67
73
  return store.list_agents(workspace_id=scope)
68
74
 
75
+ @router.get("/agents/api/handoffs")
76
+ async def agent_handoffs(request: Request, run_id: str = ""):
77
+ require_user(request)
78
+ scope = gate_read(request)
79
+ return store.list_handoffs(workspace_id=scope, run_id=run_id or None)
80
+
81
+ @router.get("/agents/api/runs/{run_id}")
82
+ async def agent_run_detail(run_id: str, request: Request):
83
+ require_user(request)
84
+ scope = gate_read(request)
85
+ try:
86
+ return {"run": store.get_agent_run(run_id, workspace_id=scope)}
87
+ except FileNotFoundError as exc:
88
+ raise HTTPException(status_code=404, detail=f"Agent run not found: {run_id}") from exc
89
+
90
+ @router.get("/agents/api/runs/{run_id}/replay")
91
+ async def agent_run_replay(run_id: str, request: Request):
92
+ require_user(request)
93
+ scope = gate_read(request)
94
+ try:
95
+ return {"replay": store.replay_agent_run(run_id, workspace_id=scope)}
96
+ except FileNotFoundError as exc:
97
+ raise HTTPException(status_code=404, detail=f"Agent run not found: {run_id}") from exc
98
+
99
+ @router.get("/agents/api/memory/snapshots")
100
+ async def agent_memory_snapshots(request: Request, limit: int = 50):
101
+ require_user(request)
102
+ scope = gate_read(request)
103
+ return store.list_memory_snapshots(workspace_id=scope, limit=limit)
104
+
105
+ @router.post("/agents/api/memory/snapshots")
106
+ async def agent_memory_snapshot(req: MemorySnapshotRequest, request: Request):
107
+ current_user = require_user(request)
108
+ scope = gate_write(request)
109
+ snapshot = store.create_memory_snapshot(
110
+ label=req.label,
111
+ reason=req.reason,
112
+ memory_ids=req.memory_ids or None,
113
+ user_email=current_user or None,
114
+ workspace_id=scope,
115
+ )
116
+ return {"snapshot": snapshot}
117
+
69
118
  @router.post("/agents/api/run")
70
119
  async def agent_run(req: AgentRunRequest, request: Request):
71
120
  current_user = require_user(request)
@@ -88,6 +137,13 @@ def create_agents_router(
88
137
  output_text=result.output,
89
138
  timeline=result.timeline,
90
139
  relationships=[ROLE_AGENT_IDS.get(r, f"agent:{r}") for r in result.roles_run],
140
+ handoffs=result.handoffs,
141
+ context_packets=result.context_packets,
142
+ plan=result.plan,
143
+ plan_review=result.plan_review,
144
+ review_history=result.review_history,
145
+ retry_history=result.retry_history,
146
+ memory_snapshots=result.memory_snapshots,
91
147
  user_email=current_user or None,
92
148
  graph=workspace_graph(),
93
149
  workspace_id=scope,
@@ -0,0 +1,81 @@
1
+ """Marketplace foundation API (local templates only)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Callable, Dict, Optional
6
+
7
+ from fastapi import APIRouter, HTTPException, Request
8
+ from pydantic import BaseModel
9
+
10
+
11
+ class TemplateImportRequest(BaseModel):
12
+ data: Dict[str, Any] = {}
13
+
14
+
15
+ class TemplateInstallRequest(BaseModel):
16
+ data: Dict[str, Any] = {}
17
+
18
+
19
+ def create_marketplace_router(
20
+ *,
21
+ store,
22
+ catalog,
23
+ require_user: Callable[[Request], str],
24
+ gate_read: Callable[[Request], Optional[str]],
25
+ gate_write: Callable[[Request], Optional[str]],
26
+ workspace_graph: Callable[[], Any],
27
+ ) -> APIRouter:
28
+ from latticeai.core.marketplace import MarketplaceError
29
+
30
+ router = APIRouter()
31
+
32
+ @router.get("/marketplace/templates")
33
+ async def list_templates(request: Request, kind: Optional[str] = None):
34
+ require_user(request)
35
+ gate_read(request)
36
+ try:
37
+ return catalog.list_templates(kind=kind)
38
+ except MarketplaceError as exc:
39
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
40
+
41
+ @router.get("/marketplace/templates/{kind}/{template_id}/export")
42
+ async def export_template(kind: str, template_id: str, request: Request):
43
+ require_user(request)
44
+ gate_read(request)
45
+ try:
46
+ return catalog.export_template(kind, template_id)
47
+ except MarketplaceError as exc:
48
+ raise HTTPException(status_code=404, detail=str(exc)) from exc
49
+
50
+ @router.post("/marketplace/templates/import")
51
+ async def import_template(req: TemplateImportRequest, request: Request):
52
+ require_user(request)
53
+ gate_read(request)
54
+ try:
55
+ return {"template": catalog.import_template(req.data)}
56
+ except MarketplaceError as exc:
57
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
58
+
59
+ @router.post("/marketplace/templates/install")
60
+ async def install_template(req: TemplateInstallRequest, request: Request):
61
+ user = require_user(request)
62
+ scope = gate_write(request)
63
+ try:
64
+ installed = catalog.install_template(
65
+ req.data,
66
+ store=store,
67
+ user_email=user or None,
68
+ workspace_id=scope,
69
+ graph=workspace_graph(),
70
+ )
71
+ except MarketplaceError as exc:
72
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
73
+ return {"installed": installed}
74
+
75
+ @router.get("/marketplace/templates/registry")
76
+ async def template_registry(request: Request):
77
+ require_user(request)
78
+ gate_read(request)
79
+ return {"registry": store.list_template_registry()}
80
+
81
+ return router
@@ -100,9 +100,17 @@ def create_models_router(
100
100
  base = {
101
101
  "id": item["id"],
102
102
  "name": item["name"],
103
+ "model_name": item.get("model_name") or item.get("name"),
103
104
  "tag": item["tag"],
104
105
  "size": item["size"],
105
106
  "display_name": item.get("name") or item.get("id"),
107
+ "modality": item.get("modality") or "multimodal",
108
+ "source_country": item.get("source_country"),
109
+ "source_company": item.get("source_company"),
110
+ "execution_method": item.get("execution_method"),
111
+ "run_location": item.get("run_location"),
112
+ "internet_requirement": item.get("internet_requirement"),
113
+ "source_display_order": item.get("source_display_order"),
106
114
  }
107
115
  short_id = str(item["id"]).lower()
108
116
  aliases = MODEL_ENGINE_ALIASES.get(short_id) or {}
@@ -1,4 +1,4 @@
1
- """Plugin SDK API router (v2.0).
1
+ """Plugin SDK API router (v2).
2
2
 
3
3
  Surfaces the :class:`latticeai.core.plugins.PluginRegistry` over HTTP using the
4
4
  same router-factory convention as the rest of ``latticeai.api`` (server_app
@@ -1,4 +1,4 @@
1
- """Realtime Collaboration API router (v2.0).
1
+ """Realtime Collaboration API router (v2).
2
2
 
3
3
  Server-Sent-Events stream + presence + activity feed over
4
4
  :class:`latticeai.core.realtime.RealtimeBus`. Workspace isolation is enforced by
@@ -1,4 +1,4 @@
1
- """Workflow Designer API router (v2.0).
1
+ """Workflow Designer API router (v2).
2
2
 
3
3
  Create / edit / validate / execute / inspect / export / import workflows plus
4
4
  run history, layered on :mod:`latticeai.core.workflow_engine` and the existing
@@ -174,6 +174,15 @@ def create_workflow_designer_router(
174
174
  scope = gate_read(request)
175
175
  return store.list_workflow_runs(limit=limit, workspace_id=scope)
176
176
 
177
+ @router.get("/workflows/api/runs/{run_id}/replay")
178
+ async def workflow_run_replay(run_id: str, request: Request):
179
+ require_user(request)
180
+ scope = gate_read(request)
181
+ try:
182
+ return {"replay": store.replay_workflow_run(run_id, workspace_id=scope)}
183
+ except FileNotFoundError as exc:
184
+ raise HTTPException(status_code=404, detail=f"Workflow run not found: {run_id}") from exc
185
+
177
186
  @router.get("/workflows/api/export/{workflow_id}")
178
187
  async def export_definition(workflow_id: str, request: Request):
179
188
  require_user(request)
@@ -131,7 +131,7 @@ class Config:
131
131
  admin_emails = [item.strip().lower() for item in _value(env, "LATTICEAI_ADMIN_EMAILS", "").split(",") if item.strip()]
132
132
 
133
133
  public_model = _value(env, "LATTICEAI_PUBLIC_MODEL", _value(env, "LATTICEAI_DEFAULT_MODEL", "openai:gpt-4o-mini"))
134
- local_model = _value(env, "LATTICEAI_LOCAL_MODEL", "mlx-community/gemma-4-26b-a4b-it-4bit")
134
+ local_model = _value(env, "LATTICEAI_LOCAL_MODEL", "mlx-community/gemma-4-12b-it-4bit")
135
135
 
136
136
  data_dir = Path(_value(env, "LATTICEAI_DATA_DIR", str(Path.home() / ".ltcai")))
137
137
  static_dir = Path(_value(env, "LATTICEAI_STATIC_DIR", str(base_dir / "static")))
@@ -231,9 +231,9 @@ def extract_topic_candidates(
231
231
 
232
232
  DEFAULT_ALIAS_GROUPS: List[List[str]] = [
233
233
  ["lattice ai", "latticeai", "래티스 ai", "래티스ai", "내 앱", "내 ai"],
234
- ["gpt-oss", "gpt oss", "openai gpt-oss"],
234
+ ["gemma-4", "gemma 4", "google gemma"],
235
235
  ["gemma 4", "gemma4", "google gemma 4"],
236
- ["llama 3", "llama3", "meta llama 3"],
236
+ ["llama 4", "llama4", "meta llama 4", "llama scout"],
237
237
  ]
238
238
 
239
239