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 +31 -21
- package/docs/CHANGELOG.md +65 -0
- package/docs/EDITION_STRATEGY.md +10 -4
- package/docs/ENTERPRISE.md +3 -1
- package/docs/MULTI_AGENT_RUNTIME.md +410 -0
- package/docs/PLUGIN_SDK.md +651 -0
- package/docs/REALTIME_COLLABORATION.md +410 -0
- package/docs/V2_ARCHITECTURE.md +528 -0
- package/docs/WORKFLOW_DESIGNER.md +475 -0
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/agents.py +98 -0
- package/latticeai/api/plugins.py +115 -0
- package/latticeai/api/realtime.py +91 -0
- package/latticeai/api/workflow_designer.py +207 -0
- package/latticeai/core/multi_agent.py +270 -0
- package/latticeai/core/plugins.py +400 -0
- package/latticeai/core/realtime.py +190 -0
- package/latticeai/core/workflow_engine.py +329 -0
- package/latticeai/core/workspace_os.py +155 -2
- package/latticeai/server_app.py +76 -2
- package/latticeai/services/platform_runtime.py +200 -0
- package/package.json +8 -2
- package/plugins/README.md +35 -0
- package/plugins/git-insights/plugin.json +15 -0
- package/plugins/hello-world/plugin.json +16 -0
- package/plugins/hello-world/skills/hello_skill/SKILL.md +15 -0
- package/static/activity.html +70 -0
- package/static/agents.html +92 -0
- package/static/platform.css +75 -0
- package/static/plugins.html +82 -0
- package/static/scripts/platform.js +64 -0
- package/static/workflows.html +121 -0
- package/static/workspace.html +5 -1
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
|
|
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
|
[](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
|
|
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
|
|
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
|
-
**
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
and
|
|
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,
|
|
373
|
-
|
|
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
|
-
| **
|
|
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
|
package/docs/EDITION_STRATEGY.md
CHANGED
|
@@ -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
|
|
9
|
-
local LLMs, knowledge graph, Personal **and** Organization
|
|
10
|
-
role-based membership, snapshots, memory, agents, workflows,
|
|
11
|
-
auditable timeline.
|
|
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 | ✅ |
|
package/docs/ENTERPRISE.md
CHANGED
|
@@ -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
|
|
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.
|