ltcai 1.7.0 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  <div align="center">
2
2
  <img src="https://raw.githubusercontent.com/TaeSooPark-PTS/LatticeAI/main/docs/images/logo.svg" alt="Lattice AI" width="280"/>
3
3
  <br/>
4
- <strong>AI Workspace OS for local-first graph, memory, agents, workflows, skills, and timelines.</strong>
4
+ <strong>Lattice AI — Local-first Agentic Workspace Platform: plugins, visual workflows, multi-agent runs, and realtime activity over your graph, memory, skills, and timeline.</strong>
5
5
  <br/><br/>
6
6
 
7
7
  [![PyPI](https://img.shields.io/pypi/v/ltcai?label=PyPI&color=blue)](https://pypi.org/project/ltcai/)
@@ -24,7 +24,7 @@
24
24
 
25
25
  Most AI tools answer one chat at a time. They do not remember your folders, your project history, your previous decisions, or how your files relate to each other.
26
26
 
27
- **Lattice AI turns your local workspace into an AI Workspace OS.**
27
+ **Lattice AI turns your local workspace into a Local-first Agentic Workspace Platform.**
28
28
 
29
29
  It reads approved local folders, indexes chats and documents, builds a searchable knowledge graph, and connects the graph to snapshots, personal memory, agent runs, workflow history, skills, and an auditable timeline.
30
30
 
@@ -156,7 +156,7 @@ See [docs/architecture.md](docs/architecture.md) for request and data-flow detai
156
156
  </table>
157
157
 
158
158
  > Every image in this section is a **real screenshot** of the running app
159
- > (Lattice AI v1.7.0), captured with a headless browser.
159
+ > (Lattice AI v2.0.0), captured with a headless browser.
160
160
 
161
161
  ---
162
162
 
@@ -353,28 +353,38 @@ Supported routes include OpenAI-compatible APIs, OpenRouter, Groq, Together, xAI
353
353
 
354
354
  ## Current release
355
355
 
356
- **1.7.0 — Graph & Collaboration Release.** An additive UI and validation release
357
- for graph exploration, workspace health, Enterprise admin visibility, skills,
358
- screenshots, and visual smoke coverage.
359
-
360
- - **Graph Canvas** — expand/collapse, subgraph focus, relationship/path
361
- highlighting, shortest-path visualization, and click-through node navigation.
362
- - **Workspace Health** indexed files, graph nodes/relationships, installed
363
- skills, memories, agent runs, current model, last sync, and workspace status.
364
- - **Enterprise Admin UI** admin policies, audit export, SIEM export preview,
365
- organization settings, and capability status surfaced in `/admin`.
366
- - **Skill Marketplace completion** install progress, validation status,
367
- recommended/popular skills, updates, version, and source metadata.
368
- - **Screenshot automation + visual smoke tests** — `scripts/capture/*` and a
369
- scheduled Playwright workflow cover Workspace, Graph, Skills, Organization,
370
- and Enterprise screens.
356
+ **2.0.0 — Agentic Workspace Platform.** Lattice AI graduates from a local-first
357
+ AI *workspace* to a local-first **Agentic Workspace Platform**: four new
358
+ subsystems land as one cohesive, fully integrated platform — all additive, with
359
+ every v1.x surface preserved.
360
+
361
+ - **Plugin SDK** — versioned, permissioned plugins (`plugin.json` manifest,
362
+ allow-listed permissions, lifecycle, validation, and a safe execution
363
+ boundary) that **extend** existing skills/tools/workflows rather than replace
364
+ them. Ships two example plugins. See [docs/PLUGIN_SDK.md](docs/PLUGIN_SDK.md).
365
+ - **Workflow Designer** node-based workflows (trigger · tool · skill · plugin ·
366
+ agent · condition · output) with validation, execution, run history, and
367
+ export/import. Pre-2.0 workflow history keeps working.
368
+ See [docs/WORKFLOW_DESIGNER.md](docs/WORKFLOW_DESIGNER.md).
369
+ - **Multi-Agent Runtime 2.0** Planner · Executor · Reviewer · Researcher ·
370
+ Release roles with handoff, retry, and an observable timeline, connected to
371
+ workspace, memory, graph, and workflow runs.
372
+ See [docs/MULTI_AGENT_RUNTIME.md](docs/MULTI_AGENT_RUNTIME.md).
373
+ - **Realtime Collaboration** — presence + an activity feed over SSE, fed
374
+ automatically from every workspace timeline event; single-user local mode and
375
+ workspace isolation preserved. See [docs/REALTIME_COLLABORATION.md](docs/REALTIME_COLLABORATION.md).
376
+ - **Cross-system integration** — workflows run plugins/skills/agents, agent runs
377
+ run plugins/workflows, and all activity surfaces in the realtime feed, the
378
+ knowledge graph, and the workspace timeline. See [docs/V2_ARCHITECTURE.md](docs/V2_ARCHITECTURE.md).
371
379
  - **Compatibility preserved** — API schemas, `server:app`,
372
- `latticeai.server_app.app`, CLI, MCP, model, workspace, chat, KG, and VS Code
373
- extension surfaces remain backward compatible.
380
+ `latticeai.server_app.app`, CLI, MCP, model, workspace, chat, KG, existing
381
+ skills/snapshots/memories/agent history, and the VS Code extension remain
382
+ backward compatible. Changes are additive; no destructive migrations.
374
383
 
375
384
  | Version | Theme |
376
385
  |---|---|
377
- | **1.7.0** | Graph & Collaboration Release |
386
+ | **2.0.0** | Agentic Workspace Platform (Plugin SDK, Workflow Designer, Multi-Agent Runtime, Realtime) |
387
+ | 1.7.0 | Graph & Collaboration Release |
378
388
  | 1.6.0 | Product Experience Deepening (UX + real screenshots) |
379
389
  | 1.5.0 | Unified Product Release (CI/VSIX recovery, model recommendation, Enterprise PoC) |
380
390
  | 1.4.0 | Server App final decomposition |
package/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.0] - 2026-06-01
4
+
5
+ > Agentic Workspace Platform — Lattice AI becomes a local-first **Agentic
6
+ > Workspace Platform** with four integrated subsystems: Plugin SDK, Workflow
7
+ > Designer, Multi-Agent Runtime 2.0, and Realtime Collaboration. Backward
8
+ > compatible and additive: API paths/schemas, `server:app`,
9
+ > `latticeai.server_app.app`, CLI, Workspace/Chat/Model/MCP/KG APIs, existing
10
+ > skills/snapshots/memories/agent & workflow history, and VS Code extension
11
+ > commands remain stable. New Workspace OS state keys (`plugin_registry`,
12
+ > `workflow_runs`) are backfilled on load via deep-merge — no destructive
13
+ > migration.
14
+
15
+ ### Added
16
+
17
+ - **Plugin SDK** (`latticeai/core/plugins.py`, `latticeai/api/plugins.py`) —
18
+ `plugin.json` manifest, an allow-listed permission model, discovery,
19
+ validation, lifecycle (install/enable/disable/uninstall), and a permissioned
20
+ execution boundary. Plugins **extend** the existing skill registry (installing
21
+ a plugin registers its bundled skills) rather than replacing skills. Ships two
22
+ example plugins (`plugins/hello-world`, `plugins/git-insights`). Routes under
23
+ `/plugins/registry`, `/plugins/validate`, `/plugins/install`, `/plugins/enable`,
24
+ `/plugins/disable`, `/plugins/uninstall`, `/plugins/execute`, page `/plugins/sdk`.
25
+ - **Workflow Designer** (`latticeai/core/workflow_engine.py`,
26
+ `latticeai/api/workflow_designer.py`) — node-based workflows
27
+ (trigger/tool/skill/plugin/agent/condition/output), validation, a bounded
28
+ deterministic execution engine, run history, and JSON export/import. Legacy
29
+ `steps`-list workflows are auto-normalized so pre-2.0 history still runs.
30
+ Routes under `/workflows/api/*`, page `/workflows`.
31
+ - **Multi-Agent Runtime 2.0** (`latticeai/core/multi_agent.py`,
32
+ `latticeai/api/agents.py`) — Planner/Executor/Reviewer/Researcher/Release role
33
+ orchestration with handoff, bounded retry, and an observable timeline; runs
34
+ persist to agent history + knowledge graph + timeline. Deterministic by
35
+ default (no LLM required) with an injectable role runner. Routes under
36
+ `/agents/api/*`, page `/agents`.
37
+ - **Realtime Collaboration** (`latticeai/core/realtime.py`,
38
+ `latticeai/api/realtime.py`) — in-process pub/sub bus, presence, and an
39
+ activity feed over SSE. Wired as the Workspace OS `event_sink`, so every
40
+ timeline event flows to the feed automatically. Workspace isolation enforced;
41
+ single-user local mode preserved. Routes `/realtime/stream` (SSE),
42
+ `/realtime/feed`, `/realtime/presence*`, page `/activity`.
43
+ - **Cross-system integration** (`latticeai/services/platform_runtime.py`) —
44
+ workflows can run tools/skills/plugins/agents; agent runs can run
45
+ plugins/workflows; graph entities link to workflow runs and agent runs; all
46
+ activity surfaces in the unified timeline + realtime feed. Recursion is bounded
47
+ by construction.
48
+ - **Platform UI** — `static/plugins.html`, `workflows.html`, `agents.html`,
49
+ `activity.html` (+ shared `static/platform.css`, `static/scripts/platform.js`),
50
+ linked from the Workspace dashboard.
51
+ - **Docs** — `docs/V2_ARCHITECTURE.md`, `docs/PLUGIN_SDK.md`,
52
+ `docs/WORKFLOW_DESIGNER.md`, `docs/MULTI_AGENT_RUNTIME.md`,
53
+ `docs/REALTIME_COLLABORATION.md`.
54
+
55
+ ### Changed
56
+
57
+ - Python package, npm package, VS Code extension, Workspace OS, FastAPI app, and
58
+ `/health` version metadata aligned at `2.0.0`.
59
+ - `server_app` cross-system wiring extracted into
60
+ `latticeai/services/platform_runtime.py` to keep the assembly file lean.
61
+
62
+ ### Validation
63
+
64
+ - Unit (incl. new plugin/workflow/multi-agent/realtime suites), integration
65
+ smoke, startup/import, route-compatibility (full v1.x baseline preserved),
66
+ and release-artifact checks. Package-store publishing remains manual.
67
+
3
68
  ## [1.7.0] - 2026-06-01
4
69
 
5
70
  > Graph & Collaboration Release — Graph Canvas interactions, Enterprise Admin
@@ -5,10 +5,12 @@ the boundary stays predictable for contributors and users.
5
5
 
6
6
  ## Editions
7
7
 
8
- - **Community** — this repository, MIT licensed. Local-first AI Workspace OS:
9
- local LLMs, knowledge graph, Personal **and** Organization workspaces,
10
- role-based membership, snapshots, memory, agents, workflows, skills, and the
11
- auditable timeline. Community is a complete product.
8
+ - **Community** — this repository, MIT licensed. Local-first **Agentic Workspace
9
+ Platform**: local LLMs, knowledge graph, Personal **and** Organization
10
+ workspaces, role-based membership, snapshots, memory, agents, workflows,
11
+ skills, the auditable timeline, and the full v2.0 platform **Plugin SDK**,
12
+ **Workflow Designer**, **Multi-Agent Runtime 2.0**, and **Realtime
13
+ Collaboration**. Community is a complete product.
12
14
  - **Enterprise** — a separately-distributed plugin adding organization-scale
13
15
  governance, identity, compliance, and deployment capabilities. Distributed and
14
16
  licensed separately. See [ENTERPRISE.md](ENTERPRISE.md).
@@ -39,6 +41,10 @@ the boundary stays predictable for contributors and users.
39
41
  | Personal & Organization workspaces | ✅ | — |
40
42
  | Base roles (owner/admin/member/viewer) | ✅ | — |
41
43
  | Snapshots / memory / agents / workflows / skills | ✅ | — |
44
+ | Plugin SDK (manifest, lifecycle, permission boundary) | ✅ | RBAC/ABAC over plugin permissions |
45
+ | Workflow Designer (build/run/run-history) | ✅ | Org approval gates, scheduled triggers |
46
+ | Multi-Agent Runtime 2.0 (roles/handoff/retry) | ✅ | Policy-bounded autonomous runs |
47
+ | Realtime Collaboration (presence + activity feed) | ✅ | Cross-tenant fan-out, retention |
42
48
  | Audit timeline (local) | ✅ | — |
43
49
  | Capability seam & enum | ✅ (declares) | ✅ (implements) |
44
50
  | SSO/SCIM/IdP provisioning | seam only | ✅ |
@@ -9,7 +9,9 @@ Lattice AI follows an **open-core** model:
9
9
 
10
10
  - **Community** (this repository, MIT) is fully functional on its own: local
11
11
  LLMs, knowledge graph, Personal and Organization workspaces, roles, snapshots,
12
- memory, agents, workflows, skills, and the auditable timeline.
12
+ memory, agents, workflows, skills, the auditable timeline, and the full v2.0
13
+ Agentic Workspace Platform (Plugin SDK, Workflow Designer, Multi-Agent Runtime
14
+ 2.0, Realtime Collaboration).
13
15
  - **Enterprise** is a separately-distributed plugin that attaches advanced,
14
16
  organization-scale governance and deployment capabilities through a stable
15
17
  runtime seam. It is never bundled into the Community build.
@@ -0,0 +1,410 @@
1
+ # Lattice AI Multi-Agent Runtime 2.0
2
+
3
+ The Multi-Agent Runtime is the **orchestration layer** introduced in v2.0.0. It sits
4
+ *above* the v1.x single-agent state machine ([`AgentRuntime`](../latticeai/core/agent.py))
5
+ and coordinates a pipeline of named **roles** that hand off work to one another,
6
+ retry on a failing review, and emit a fully observable timeline.
7
+
8
+ - **Source of truth:** `latticeai/core/multi_agent.py`
9
+ - **HTTP surface:** `latticeai/api/agents.py`
10
+ - **Persistence / Knowledge Graph integration:** `latticeai/core/workspace_os.py`
11
+ (`WorkspaceOSStore.record_agent_run`)
12
+
13
+ ```python
14
+ MULTI_AGENT_VERSION = "2.0.0"
15
+ ```
16
+
17
+ ## How it relates to the v1 single-agent runtime
18
+
19
+ v1.x shipped a single-agent state machine — `AgentRuntime` driving
20
+ `PLAN → EXECUTE → VERIFY → DONE` (with `ROLLBACK` / `FAILED` recovery paths) over an
21
+ injected `AgentDeps` port. That runtime is unchanged.
22
+
23
+ v2.0 adds the *orchestration* layer on top: instead of one agent looping through
24
+ internal phases, the `MultiAgentOrchestrator` drives a **pipeline of distinct roles**
25
+ (researcher, planner, executor, reviewer, release) that hand off to one another and
26
+ can rewind on a failing review. The two layers are complementary — the v2
27
+ orchestrator coordinates roles; an individual role's runner could itself be backed by
28
+ the v1 `AgentRuntime` loop or an LLM, but that is an implementation choice behind the
29
+ injected runner port.
30
+
31
+ > **Compatibility.** The Multi-Agent Runtime is purely additive. The v1
32
+ > `AgentRuntime` state machine and its `/agent` endpoints are untouched, and the v2
33
+ > API is namespaced under `/agents` (plural) so it never collides with the existing
34
+ > single-agent `/agent` routes. Existing v1.x data is preserved; new runs are appended
35
+ > to workspace state and the Knowledge Graph alongside it.
36
+
37
+ ## Built-in roles (`AGENT_ROLES`)
38
+
39
+ The runtime defines five built-in roles. Each role id matches an entry in
40
+ `latticeai.core.workspace_os.DEFAULT_AGENTS`, so orchestrated runs reference the same
41
+ agents that already appear in the Workspace.
42
+
43
+ ```python
44
+ AGENT_ROLES = ("researcher", "planner", "executor", "reviewer", "release")
45
+
46
+ ROLE_AGENT_IDS = {
47
+ "researcher": "agent:researcher",
48
+ "planner": "agent:planner",
49
+ "executor": "agent:executor",
50
+ "reviewer": "agent:reviewer",
51
+ "release": "agent:release",
52
+ }
53
+ ```
54
+
55
+ | Role | Agent id | Responsibility |
56
+ | --- | --- | --- |
57
+ | `researcher` | `agent:researcher` | Gathers relevant context (workspace memory / graph) via an injected `context_provider`. |
58
+ | `planner` | `agent:planner` | Decomposes the goal into ordered, inspectable steps. |
59
+ | `executor` | `agent:executor` | Carries out steps; may drive an injected workflow / plugin runner. |
60
+ | `reviewer` | `agent:reviewer` | Judges the result and returns a `pass` / `retry` verdict. |
61
+ | `release` | `agent:release` | Finalizes / packages the outcome (optional). |
62
+
63
+ The `agent:*` ids correspond one-to-one with `DEFAULT_AGENTS` in `workspace_os`
64
+ (`agent:planner`, `agent:executor`, `agent:reviewer`, `agent:researcher`,
65
+ `agent:release`), which is why an orchestrated run can record relationships against
66
+ agents that the Workspace already knows about.
67
+
68
+ ### The core pipeline
69
+
70
+ `researcher` and `release` are optional stages — they run only when explicitly
71
+ requested. A quick, default run is therefore three stages:
72
+
73
+ ```python
74
+ CORE_PIPELINE = ("planner", "executor", "reviewer")
75
+ ```
76
+
77
+ When `MultiAgentOrchestrator.run(...)` is called without an explicit `roles` list, it
78
+ uses `CORE_PIPELINE`. Any roles passed in are filtered to the set of known
79
+ `AGENT_ROLES`; if nothing valid remains, it falls back to `CORE_PIPELINE`.
80
+
81
+ ## Orchestration: `MultiAgentOrchestrator.run`
82
+
83
+ ```python
84
+ def run(
85
+ self,
86
+ goal: str,
87
+ *,
88
+ user_email: Optional[str] = None,
89
+ workspace_id: Optional[str] = None,
90
+ inputs: Optional[Dict[str, Any]] = None,
91
+ roles: Optional[List[str]] = None,
92
+ max_retries: int = 2,
93
+ ) -> AgentRunResult:
94
+ ...
95
+ ```
96
+
97
+ `run` walks the resolved pipeline, threading a single `OrchestrationContext` through
98
+ every stage. As it goes it appends two kinds of events to an observable timeline:
99
+
100
+ - **`role` events** — emitted by `_run_role` for each stage, recording the role, its
101
+ `agent_id`, status (`ok` / `error`), the raw runner result, and start/end timestamps.
102
+ - **`handoff` events** — emitted via `OrchestrationContext.handoff(frm, to, note)`
103
+ whenever control passes from one role to the next (and on a retry rewind).
104
+
105
+ The timeline is also bracketed by a `start` event (carrying the goal and resolved
106
+ pipeline) and an `end` event (carrying the final status and retry count).
107
+
108
+ ### Retry: reviewer rewinds to executor
109
+
110
+ The pipeline is ordinarily linear, but the **reviewer can rewind** the pipeline to the
111
+ executor. After the reviewer runs, if its verdict is `retry` and the retry budget is
112
+ not yet exhausted, the orchestrator:
113
+
114
+ 1. increments `ctx.retries`,
115
+ 2. emits a `handoff("reviewer", "executor", note="retry #N: <reason>")`,
116
+ 3. resets the pipeline index back to the executor stage, and
117
+ 4. re-runs executor → reviewer.
118
+
119
+ This repeats until the verdict is `pass` or `ctx.retries` reaches `max_retries`.
120
+
121
+ ```text
122
+ planner → executor → reviewer ──pass──▶ (continue / end)
123
+
124
+ └──retry (and retries < max_retries)──▶ executor (rewind)
125
+ ```
126
+
127
+ ### Final status
128
+
129
+ The terminal status is derived from the final reviewer verdict and retry count:
130
+
131
+ | Condition | `status` |
132
+ | --- | --- |
133
+ | Final verdict `pass`, no retries | `ok` |
134
+ | Final verdict `pass`, after one or more retries | `retried_ok` |
135
+ | Final verdict not `pass` (retries exhausted) | `failed` |
136
+
137
+ ### `OrchestrationContext`
138
+
139
+ The mutable carrier threaded through every stage:
140
+
141
+ ```python
142
+ @dataclass
143
+ class OrchestrationContext:
144
+ goal: str
145
+ user_email: Optional[str] = None
146
+ workspace_id: Optional[str] = None
147
+ inputs: Dict[str, Any] = field(default_factory=dict)
148
+ plan: List[Dict[str, Any]] = field(default_factory=list)
149
+ research: List[str] = field(default_factory=list)
150
+ executed: List[Dict[str, Any]] = field(default_factory=list)
151
+ review: Dict[str, Any] = field(default_factory=dict)
152
+ timeline: List[Dict[str, Any]] = field(default_factory=list)
153
+ retries: int = 0
154
+ output: str = ""
155
+
156
+ def handoff(self, frm: str, to: str, note: str = "") -> None: ...
157
+ ```
158
+
159
+ ### `AgentRunResult`
160
+
161
+ `run` returns an `AgentRunResult`, which exposes `as_dict()` for serialization:
162
+
163
+ ```python
164
+ @dataclass
165
+ class AgentRunResult:
166
+ agent_id: str
167
+ status: str # ok | failed | retried_ok
168
+ output: str
169
+ timeline: List[Dict[str, Any]]
170
+ plan: List[Dict[str, Any]]
171
+ review: Dict[str, Any]
172
+ roles_run: List[str]
173
+ retries: int = 0
174
+ ```
175
+
176
+ ## The role runner is an injected port
177
+
178
+ Like the v1 runtime, the orchestrator is **pure logic over an injected `role_runner`
179
+ port**. It runs with no LLM and no server:
180
+
181
+ ```python
182
+ class MultiAgentOrchestrator:
183
+ def __init__(
184
+ self,
185
+ role_runner: Optional[Callable[[str, OrchestrationContext], Dict[str, Any]]] = None,
186
+ ):
187
+ self.role_runner = role_runner or default_role_runner()
188
+ ```
189
+
190
+ The runner is a single callable `(role: str, ctx: OrchestrationContext) -> Dict[str, Any]`.
191
+ The orchestration logic — pipeline walking, handoffs, retry rewind, timeline emission,
192
+ status derivation — does not depend on *how* a role does its work. This means a
193
+ **production deployment can swap in an LLM-backed runner without touching the
194
+ orchestration layer**: implement the same callable signature, pass it to the
195
+ constructor, and the pipeline behaves identically while individual roles gain
196
+ model-backed reasoning.
197
+
198
+ If a runner raises, `_run_role` captures the exception into the `role` event as
199
+ `status: "error"` with an `{"error": ...}` result, rather than crashing the run.
200
+
201
+ ## The default runner is deterministic and useful
202
+
203
+ `default_role_runner` builds a **dependency-free, deterministic** runner that
204
+ implements every built-in role with real (non-LLM) behavior. This is what makes
205
+ "agent runs can execute workflows / plugins" true in the community edition without
206
+ requiring a model.
207
+
208
+ ```python
209
+ def default_role_runner(
210
+ *,
211
+ workflow_runner: Optional[Callable[..., Any]] = None,
212
+ plugin_runner: Optional[Callable[..., Any]] = None,
213
+ context_provider: Optional[Callable[[str], List[str]]] = None,
214
+ ) -> Callable[[str, OrchestrationContext], Dict[str, Any]]:
215
+ ...
216
+ ```
217
+
218
+ Behavior by role:
219
+
220
+ - **`researcher`** — calls the injected `context_provider(goal)` (workspace memory) to
221
+ pull relevant context into `ctx.research`; returns the count and the first items.
222
+ - **`planner`** — decomposes the goal into ordered steps. If `inputs["steps"]` is a
223
+ non-empty list, each entry becomes a planned step; otherwise it produces a default
224
+ three-step plan (`Analyze` / `Execute` / `Verify the result`). Steps are written to
225
+ `ctx.plan`.
226
+ - **`executor`** — iterates the plan and marks each step `done`. A step may request a
227
+ workflow or plugin run; when the corresponding runner is injected, the executor
228
+ drives it (see below). Results are written to `ctx.executed` and a summary line to
229
+ `ctx.output`.
230
+ - **`reviewer`** — passes only if `ctx.executed` is non-empty and *every* executed step
231
+ has `status == "done"`; otherwise it returns `retry`. The verdict shape is:
232
+
233
+ ```json
234
+ {
235
+ "verdict": "pass",
236
+ "reason": "all steps completed",
237
+ "confidence": 0.9
238
+ }
239
+ ```
240
+
241
+ A failing review yields `{"verdict": "retry", "reason": "no steps executed", "confidence": 0.3}`.
242
+ - **`release`** — sets/keeps `ctx.output` and returns `{"released": true, "summary": ...}`.
243
+
244
+ An unrecognized role returns `{"role": role, "status": "noop"}`.
245
+
246
+ ### Agent → workflow and agent → plugin integration
247
+
248
+ The executor role is where Lattice's cross-feature integration happens. When the
249
+ `default_role_runner` is built with a `workflow_runner` and/or `plugin_runner`, a plan
250
+ step can drive them:
251
+
252
+ - A step's `workflow` (or `inputs["workflow"]`) is run via `workflow_runner(wf, ctx)`
253
+ on the first step (`index == 0`), capturing the result under `workflow_result` (or
254
+ `workflow_error` on failure).
255
+ - A step's `plugin` is run via `plugin_runner(pl, ctx)`, capturing `plugin_result` (or
256
+ `plugin_error`).
257
+
258
+ This is the **agent → workflow** and **agent → plugin** seam: an orchestrated agent run
259
+ can actually execute Workflows and Plugins, in the community edition, with no model
260
+ required.
261
+
262
+ ## Persistence and Knowledge Graph
263
+
264
+ After a run completes, the API persists it via
265
+ `WorkspaceOSStore.record_agent_run`, which both ingests a Knowledge Graph node and
266
+ records a Workspace timeline event:
267
+
268
+ ```python
269
+ def record_agent_run(
270
+ self,
271
+ *,
272
+ agent_id: str,
273
+ status: str,
274
+ input_text: str,
275
+ output_text: str,
276
+ user_email: Optional[str],
277
+ timeline: Optional[List[Dict[str, Any]]] = None,
278
+ relationships: Optional[List[str]] = None,
279
+ graph: Any = None,
280
+ workspace_id: Optional[str] = None,
281
+ ) -> Dict[str, Any]:
282
+ ...
283
+ ```
284
+
285
+ What it does:
286
+
287
+ - Builds a run record (`id`, `agent_id`, `status`, `input`, `output_preview` truncated
288
+ to 1000 chars, `user_email`, scoped `workspace_id`, `relationships`, `timeline`,
289
+ `created_at`).
290
+ - When a `graph` is supplied, calls `graph.ingest_event("AgentRun", ...)` and stores the
291
+ returned `graph_node_id` on the run (capturing `graph_error` if ingest fails).
292
+ - Appends the run to workspace state (retaining the most recent 300) and records an
293
+ `agent` / `agent_run` timeline event.
294
+
295
+ Runs are workspace-scoped; `list_agents(workspace_id=...)` returns the registered
296
+ `agents` plus the most recent runs for that scope.
297
+
298
+ ## HTTP API
299
+
300
+ The router is created by `create_agents_router(...)` in `latticeai/api/agents.py`. All
301
+ paths live under `/agents` (plural).
302
+
303
+ > **Compatibility.** `/agents` does **not** collide with the existing single-agent
304
+ > `/agent` endpoints — the trailing `s` keeps the v2 namespace fully separate, so v1
305
+ > clients continue to work unchanged.
306
+
307
+ ### `GET /agents` — UI page
308
+
309
+ Requires an authenticated user. Serves the `agents.html` Multi-Agent UI from the static
310
+ directory; returns `404` if the UI is not available or not found.
311
+
312
+ ### `GET /agents/api/roles`
313
+
314
+ Requires an authenticated user. Lists the built-in roles and the default pipeline.
315
+
316
+ ```json
317
+ {
318
+ "roles": [
319
+ {"role": "researcher", "agent_id": "agent:researcher"},
320
+ {"role": "planner", "agent_id": "agent:planner"},
321
+ {"role": "executor", "agent_id": "agent:executor"},
322
+ {"role": "reviewer", "agent_id": "agent:reviewer"},
323
+ {"role": "release", "agent_id": "agent:release"}
324
+ ],
325
+ "default_pipeline": ["planner", "executor", "reviewer"]
326
+ }
327
+ ```
328
+
329
+ ### `GET /agents/api/runs`
330
+
331
+ Requires an authenticated user; reads are scoped via `gate_read`. Returns the registered
332
+ agents plus recent runs for the resolved workspace scope (the result of
333
+ `store.list_agents(workspace_id=scope)`).
334
+
335
+ ```json
336
+ {
337
+ "agents": [ { "id": "agent:planner", "name": "Planner", "...": "..." } ],
338
+ "runs": [ { "id": "agent-run-...", "agent_id": "agent:executor", "status": "ok", "...": "..." } ]
339
+ }
340
+ ```
341
+
342
+ ### `POST /agents/api/run`
343
+
344
+ Requires an authenticated user; writes are scoped via `gate_write`. Runs the
345
+ orchestrator and persists the result.
346
+
347
+ **Request body** (`AgentRunRequest`):
348
+
349
+ ```json
350
+ {
351
+ "goal": "Summarize the open incidents and draft a status update",
352
+ "roles": ["researcher", "planner", "executor", "reviewer"],
353
+ "inputs": { "steps": ["Collect incidents", "Draft update"] },
354
+ "max_retries": 2
355
+ }
356
+ ```
357
+
358
+ | Field | Type | Default | Notes |
359
+ | --- | --- | --- | --- |
360
+ | `goal` | string | — | Required; a `400` is returned if blank. |
361
+ | `roles` | string[] | `[]` | Empty means the default `CORE_PIPELINE`. Unknown roles are filtered out. |
362
+ | `inputs` | object | `{}` | Passed through to the runner (e.g. `steps`, `workflow`). |
363
+ | `max_retries` | int | `2` | Clamped server-side to the range `0`–`5`. |
364
+
365
+ The endpoint resolves an orchestrator via the injected `orchestrator_factory(user, scope)`,
366
+ runs it, records the run with `store.record_agent_run(...)` (passing the
367
+ `workspace_graph()` for KG ingest and the run's `roles_run` as `relationships`), and
368
+ appends a `multi_agent_run` audit event.
369
+
370
+ **Response:**
371
+
372
+ ```json
373
+ {
374
+ "run": {
375
+ "id": "agent-run-…",
376
+ "agent_id": "agent:executor",
377
+ "status": "ok",
378
+ "input": "Summarize the open incidents and draft a status update",
379
+ "output_preview": "Completed 2 planned step(s) for: …",
380
+ "relationships": ["agent:researcher", "agent:planner", "agent:executor", "agent:reviewer"],
381
+ "timeline": [ { "event": "start", "...": "..." } ],
382
+ "graph_node_id": "…",
383
+ "created_at": "…"
384
+ },
385
+ "result": {
386
+ "agent_id": "agent:executor",
387
+ "status": "ok",
388
+ "output": "Completed 2 planned step(s) for: …",
389
+ "timeline": [ "…" ],
390
+ "plan": [ { "index": 0, "description": "Collect incidents", "status": "done" } ],
391
+ "review": { "verdict": "pass", "reason": "all steps completed", "confidence": 0.9 },
392
+ "roles_run": ["researcher", "planner", "executor", "reviewer"],
393
+ "retries": 0
394
+ }
395
+ }
396
+ ```
397
+
398
+ ## Timeline event reference
399
+
400
+ The orchestration timeline is a flat, ordered list of event objects. Event types:
401
+
402
+ | `event` | Emitted by | Key fields |
403
+ | --- | --- | --- |
404
+ | `start` | `run` (before the pipeline) | `goal`, `pipeline`, `timestamp` |
405
+ | `role` | `_run_role` (per stage) | `role`, `agent_id`, `status`, `result`, `started_at`, `timestamp` |
406
+ | `handoff` | `OrchestrationContext.handoff` | `from`, `to`, `note`, `timestamp` |
407
+ | `end` | `run` (after the pipeline) | `status`, `retries`, `timestamp` |
408
+
409
+ This timeline is returned on the run result and persisted with the run, so it drops
410
+ straight into the Workspace timeline and Knowledge Graph.