@elizaos/plugin-agent-orchestrator 2.0.0-alpha.9 → 2.0.3-beta.2

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 (75) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/LICENSE +21 -0
  3. package/README.md +232 -0
  4. package/docs/SUBAGENT_FLOW_AND_PARITY.md +138 -0
  5. package/docs/default-eliza-skills-and-agent-bridge-plan.md +225 -0
  6. package/docs/economics-goal-runbook.md +140 -0
  7. package/docs/multi-account-orchestration.md +76 -0
  8. package/docs/orchestrator-buildout-followups.md +124 -0
  9. package/docs/orchestrator-dashboard-task-widget-secrets-assessment.md +174 -0
  10. package/docs/orchestrator-dashboard-task-widget-secrets-design.md +301 -0
  11. package/docs/research/orchestrator-view-research-report.md +273 -0
  12. package/docs/sub-agent-routing.md +227 -0
  13. package/package.json +197 -38
  14. package/dist/index.d.ts +0 -21
  15. package/dist/index.d.ts.map +0 -1
  16. package/dist/index.js +0 -21120
  17. package/dist/index.js.map +0 -109
  18. package/dist/src/actions/messaging.d.ts +0 -24
  19. package/dist/src/actions/messaging.d.ts.map +0 -1
  20. package/dist/src/actions/peek-subagent.d.ts +0 -3
  21. package/dist/src/actions/peek-subagent.d.ts.map +0 -1
  22. package/dist/src/actions/subagent-management.d.ts +0 -7
  23. package/dist/src/actions/subagent-management.d.ts.map +0 -1
  24. package/dist/src/actions/task-management.d.ts +0 -9
  25. package/dist/src/actions/task-management.d.ts.map +0 -1
  26. package/dist/src/config.d.ts +0 -4
  27. package/dist/src/config.d.ts.map +0 -1
  28. package/dist/src/providers/orchestrator-config.d.ts +0 -80
  29. package/dist/src/providers/orchestrator-config.d.ts.map +0 -1
  30. package/dist/src/providers/task-context.d.ts +0 -3
  31. package/dist/src/providers/task-context.d.ts.map +0 -1
  32. package/dist/src/services/agent-orchestrator-service.d.ts +0 -59
  33. package/dist/src/services/agent-orchestrator-service.d.ts.map +0 -1
  34. package/dist/src/services/messaging-service.d.ts +0 -111
  35. package/dist/src/services/messaging-service.d.ts.map +0 -1
  36. package/dist/src/services/sandbox-service.d.ts +0 -103
  37. package/dist/src/services/sandbox-service.d.ts.map +0 -1
  38. package/dist/src/services/subagent-service.d.ts +0 -140
  39. package/dist/src/services/subagent-service.d.ts.map +0 -1
  40. package/dist/src/sub-agents/adapter.d.ts +0 -13
  41. package/dist/src/sub-agents/adapter.d.ts.map +0 -1
  42. package/dist/src/sub-agents/claude-agent-sdk-sub-agent.d.ts +0 -18
  43. package/dist/src/sub-agents/claude-agent-sdk-sub-agent.d.ts.map +0 -1
  44. package/dist/src/sub-agents/codex-sdk-sub-agent.d.ts +0 -18
  45. package/dist/src/sub-agents/codex-sdk-sub-agent.d.ts.map +0 -1
  46. package/dist/src/sub-agents/eliza-sub-agent.d.ts +0 -27
  47. package/dist/src/sub-agents/eliza-sub-agent.d.ts.map +0 -1
  48. package/dist/src/sub-agents/elizaos-native-sub-agent.d.ts +0 -61
  49. package/dist/src/sub-agents/elizaos-native-sub-agent.d.ts.map +0 -1
  50. package/dist/src/sub-agents/index.d.ts +0 -10
  51. package/dist/src/sub-agents/index.d.ts.map +0 -1
  52. package/dist/src/sub-agents/opencode-sub-agent.d.ts +0 -44
  53. package/dist/src/sub-agents/opencode-sub-agent.d.ts.map +0 -1
  54. package/dist/src/sub-agents/registry.d.ts +0 -3
  55. package/dist/src/sub-agents/registry.d.ts.map +0 -1
  56. package/dist/src/sub-agents/sweagent-sub-agent.d.ts +0 -19
  57. package/dist/src/sub-agents/sweagent-sub-agent.d.ts.map +0 -1
  58. package/dist/src/sub-agents/tools.d.ts +0 -15
  59. package/dist/src/sub-agents/tools.d.ts.map +0 -1
  60. package/dist/src/sub-agents/types.d.ts +0 -170
  61. package/dist/src/sub-agents/types.d.ts.map +0 -1
  62. package/dist/src/types/index.d.ts +0 -12
  63. package/dist/src/types/index.d.ts.map +0 -1
  64. package/dist/src/types/messaging.d.ts +0 -202
  65. package/dist/src/types/messaging.d.ts.map +0 -1
  66. package/dist/src/types/sandbox.d.ts +0 -228
  67. package/dist/src/types/sandbox.d.ts.map +0 -1
  68. package/dist/src/types/subagent.d.ts +0 -232
  69. package/dist/src/types/subagent.d.ts.map +0 -1
  70. package/dist/src/types.d.ts +0 -138
  71. package/dist/src/types.d.ts.map +0 -1
  72. package/dist/src/utils/index.d.ts +0 -7
  73. package/dist/src/utils/index.d.ts.map +0 -1
  74. package/dist/src/utils/session.d.ts +0 -184
  75. package/dist/src/utils/session.d.ts.map +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,60 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 (unreleased)
4
+
5
+ ACP-based spawn, sub-agent routing, and workspace services into
6
+ a single package at `plugins/plugin-agent-orchestrator`. Internal
7
+ `@elizaos/plugin-acpx` callers were rewritten to the package.
8
+
9
+ ### Added
10
+
11
+ - `SubAgentRouter` service: subscribes to `AcpService.onSessionEvent`,
12
+ posts terminal events (`task_complete`, `error`, `blocked`) as
13
+ synthetic inbound memories addressed to the original
14
+ `roomId`/`userId`/`messageId` captured at spawn time. Lets the main
15
+ agent's normal action layer decide `REPLY` / `SEND_TO_AGENT` / both.
16
+ - `activeSubAgentsProvider`: cache-stable view of routed sub-agent
17
+ sessions. Sorted by sessionId, structural-only fields, status bucketing
18
+ (`ready`/`running`/`busy`/`tool_running`/`authenticating` → `"active"`)
19
+ so transient flips don't invalidate the prefix cache.
20
+ - Round-trip cap: per-session inject counter; force-stops after
21
+ `ACPX_SUB_AGENT_ROUND_TRIP_CAP` (default 32) and surfaces a single
22
+ `round_trip_cap_exceeded` notice with `subAgentRoundTrip` /
23
+ `subAgentRoundTripCap` / `subAgentCapExceeded: true`.
24
+ - Live e2e test (`__tests__/live/sub-agent-router.live.test.ts`) gated on
25
+ `RUN_LIVE_ACPX=1` plus `acpx --version`.
26
+ - `spawnAgentAction` now threads `source: content.source` into spawn
27
+ metadata for parity with `createTaskAction`.
28
+
29
+ ### Changed
30
+
31
+ - Package renamed from `@elizaos/plugin-acpx` → `@elizaos/plugin-agent-orchestrator`.
32
+ - `SubAgentRouter` derives the per-session sub-agent UUID locally via SHA1
33
+ instead of importing `createUniqueUuid` from `@elizaos/core`. This keeps
34
+ the router's import surface type-only.
35
+ - Browser build dropped: this package owns Node-only services
36
+ (`AcpService`, `CodingWorkspaceService`, child_process spawn).
37
+
38
+ ### Fixed
39
+
40
+ - `task-agent-frameworks.ts` `normalizeTaskAgentAdapterForModelPrefs`:
41
+ removed three duplicate switch cases (`opencode` / `open-code` /
42
+ `open code`) that were dead code after the matching cases earlier in
43
+ the same switch.
44
+ - Greptile-flagged bugs from PR #7463 (already on develop pre-rename):
45
+ `"errored"` → `"error"` status normalization,
46
+ `listSessions`/`getSession` for FileSessionStore + RuntimeDbSessionStore,
47
+ `enforceSessionLimit` excluding both `"error"` and `"errored"`.
48
+
49
+ ### Removed
50
+
51
+ - Removed the legacy swarm/terminal implementation family. The plugin now
52
+ has one task-agent transport: `AcpService` + `SubAgentRouter`.
53
+
54
+ ## 0.1.0
55
+
56
+ Pre-consolidation. Bootstrap package scaffold for `@elizaos/plugin-acpx`
57
+ under its original name. Initial ACP subprocess service, session store
58
+ adapters, six canonical actions (`CREATE_TASK`, `SPAWN_AGENT`,
59
+ `SEND_TO_AGENT`, `STOP_AGENT`, `LIST_AGENTS`, `CANCEL_TASK`), and the
60
+ `availableAgentsProvider`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 @stwd / 0xSolace
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,232 @@
1
+ # @elizaos/plugin-agent-orchestrator
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@elizaos/plugin-agent-orchestrator.svg)](https://www.npmjs.com/package/@elizaos/plugin-agent-orchestrator)
4
+ [![CI](https://github.com/elizaos/eliza/actions/workflows/ci.yml/badge.svg)](https://github.com/elizaos/eliza/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
+
7
+ The canonical orchestration plugin for elizaOS task agents. Spawns local coding agents (elizaos, pi-agent, opencode, codex, claude) through Agent Client Protocol transports, routes their output back through the runtime so the main agent decides what to do, and bundles workspace lifecycle, GitHub PR integration, task share, and supporting services in a single package.
8
+
9
+ > Naming: this plugin is *not* the same thing as `@elizaos/plugin-acp`. That package is Shaw's ACP gateway client (IDE bridge over a remote ACP gateway). `@elizaos/plugin-agent-orchestrator` is the *task backend* that runs coding agents as subprocesses on the same host as the runtime.
10
+
11
+ ## What it does
12
+
13
+ The plugin combines three concerns:
14
+
15
+ 1. **Spawn** coding agents via ACP. The default path embeds ACP JSON-RPC session management in this plugin and talks directly to an ACP-compatible agent process; the legacy path can still shell out to [`acpx`](https://github.com/openclaw/acpx) when `ELIZA_ACP_TRANSPORT=cli`.
16
+ 2. **Route** sub-agent terminal events (`task_complete`, `error`, `blocked`) and swarm coordination events back into the runtime as synthetic inbound messages addressed to the task room, worktree room, or original `roomId`/`userId`/`messageId`. The main agent's normal action layer then decides whether to `REPLY` to the user, `SEND_TO_AGENT` to push the sub-agent further, ask the task creator a question, or coordinate with other agents. See [`docs/sub-agent-routing.md`](./docs/sub-agent-routing.md).
17
+ 3. **Coordinate** workspace lifecycle (clone, branch, commit, push, PR open) and GitHub issue management for repo-hosted tasks.
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install @elizaos/plugin-agent-orchestrator
23
+ ```
24
+
25
+ Native TypeScript ACP is the default transport. Set the default coding agent with `ELIZA_ACP_DEFAULT_AGENT` (`elizaos`, `pi-agent`, or `opencode` are the primary supported defaults):
26
+
27
+ ```bash
28
+ export ELIZA_ACP_TRANSPORT=native
29
+ export ELIZA_ACP_DEFAULT_AGENT=elizaos
30
+ export ELIZA_ELIZAOS_ACP_COMMAND="elizaos"
31
+ export ELIZA_PI_AGENT_ACP_COMMAND="pi-agent"
32
+ export ELIZA_CODEX_ACP_COMMAND="npx -y @zed-industries/codex-acp@0.14.0"
33
+ export ELIZA_CLAUDE_ACP_COMMAND="npx -y @agentclientprotocol/claude-agent-acp@0.34.0"
34
+ ```
35
+
36
+ Authenticate the underlying agent you plan to use before spawning sessions. Native Codex and Claude defaults use `npx`, so pin or replace those commands in production if you do not want runtime downloads.
37
+
38
+ The legacy command-wrapper path remains available for compatibility:
39
+
40
+ ```bash
41
+ npm install -g acpx@latest
42
+ export ELIZA_ACP_TRANSPORT=cli
43
+ ```
44
+
45
+ Adapter packaging decision: this release does not vendor the Codex or Claude ACP adapter packages. Native transport is the default; Codex and Claude use pinned `npx` commands unless deployment config overrides them. OpenCode is the exception: the package prefers the bundled OpenCode shim when available, then falls back to `opencode acp`.
46
+
47
+ `coding-agent-adapters` is a runtime registry/API dependency used by this plugin's agent inventory and routes; it is not a bundled Codex or Claude ACP adapter executable.
48
+
49
+ ## Quick start
50
+
51
+ ```ts
52
+ import agentOrchestratorPlugin from "@elizaos/plugin-agent-orchestrator";
53
+
54
+ export default {
55
+ plugins: [agentOrchestratorPlugin],
56
+ };
57
+ ```
58
+
59
+ ## Action surface
60
+
61
+ All actions are virtual sub-operations of the single `TASKS` parent action, promoted via `promoteSubactionsToActions` with the `TASKS_` prefix.
62
+
63
+ | Promoted action | Sub-operation | Purpose |
64
+ | --- | --- | --- |
65
+ | `TASKS_CREATE` | `create` | One-shot: spawn + prompt + return. Captures origin metadata for routing. |
66
+ | `TASKS_SPAWN_AGENT` | `spawn_agent` | Start a long-lived ACP coding-agent session. Returns active session info. |
67
+ | `TASKS_SEND` | `send` | Send a follow-up prompt to a running session (`SEND_TO_AGENT` simile). |
68
+ | `TASKS_STOP_AGENT` | `stop_agent` | Cooperatively cancel + close a session. |
69
+ | `TASKS_LIST_AGENTS` | `list_agents` | List active and persisted sessions. |
70
+ | `TASKS_CANCEL` | `cancel` | Cancel an in-flight task while preserving history. |
71
+ | `TASKS_HISTORY` | `history` | Retrieve past task sessions. |
72
+ | `TASKS_CONTROL` | `control` | Lifecycle control: pause/resume/stop/continue/archive/reopen. |
73
+ | `TASKS_SHARE` | `share` | Share a task session. |
74
+ | `TASKS_PROVISION_WORKSPACE` | `provision_workspace` | Clone repo, create git worktree for a task. |
75
+ | `TASKS_SUBMIT_WORKSPACE` | `submit_workspace` | Commit, push, open PR for a workspace. |
76
+ | `TASKS_MANAGE_ISSUES` | `manage_issues` | GitHub issue create/list/get/update/comment/close/reopen/add_labels. |
77
+ | `TASKS_ARCHIVE` | `archive` | Archive a completed coding task. |
78
+ | `TASKS_REOPEN` | `reopen` | Reopen an archived task. |
79
+
80
+ ## Providers
81
+
82
+ - `AVAILABLE_AGENTS` — adapter inventory + raw session list.
83
+ - `ACTIVE_SUB_AGENTS` — cache-stable view of currently-routed sub-agent sessions; sorted by sessionId, structural fields only (no timestamps, no message excerpts), so the planner-visible block stays cached across status flips.
84
+ - `ACTIVE_WORKSPACE_CONTEXT` — live workspace/session state.
85
+ - `CODING_AGENT_EXAMPLES` — structured action call examples.
86
+ - `CODING_SESSION_CHANGES` — real git changeset for "show me the diff" queries.
87
+
88
+ ## Services
89
+
90
+ - `AcpService` — ACP subprocess lifecycle, session state, event emission, and transport selection. Registers under `ACP_SUBPROCESS_SERVICE`.
91
+ - `OrchestratorTaskService` — durable task store, sub-agent lifecycle API, event bridge from ACP to task records. Registers under `ORCHESTRATOR_TASK_SERVICE`.
92
+ - `SubAgentRouter` — subscribes to `AcpService.onSessionEvent`, posts terminal-event synthetic memories to `runtime.messageService.handleMessage`. Registers under `ACPX_SUB_AGENT_ROUTER`. Per-session round-trip cap (`ACPX_SUB_AGENT_ROUND_TRIP_CAP`, default 32) force-stops runaway loops. Disable with `ACPX_SUB_AGENT_ROUTER_DISABLED=1`.
93
+ - `CodingWorkspaceService` — git workspace lifecycle helpers. Registers under `CODING_WORKSPACE_SERVICE`.
94
+
95
+ ```ts
96
+ import { AcpService, SubAgentRouter } from "@elizaos/plugin-agent-orchestrator";
97
+
98
+ const acp = runtime.getService("ACP_SUBPROCESS_SERVICE") as AcpService;
99
+
100
+ const { sessionId } = await acp.spawnSession({
101
+ agentType: "codex",
102
+ workdir: "/tmp/my-task",
103
+ approvalPreset: "permissive",
104
+ metadata: {
105
+ roomId: message.roomId,
106
+ userId: message.entityId,
107
+ messageId: message.id,
108
+ label: "fix bug 42",
109
+ },
110
+ });
111
+
112
+ const result = await acp.sendPrompt(sessionId, "what is 7 + 8?");
113
+ console.log(result.finalText); // "15"
114
+ console.log(result.stopReason); // "end_turn"
115
+ console.log(result.durationMs); // 4864
116
+ ```
117
+
118
+ ### Subscribing to events
119
+
120
+ ```ts
121
+ acp.onSessionEvent((sessionId, eventName, data) => {
122
+ // eventName: "ready" | "message" | "tool_running" | "task_complete" | "stopped" | "error" | "blocked" | "login_required" | "reconnected"
123
+ // data shape depends on eventName, see SessionEventName in src/services/types.ts
124
+ });
125
+ ```
126
+
127
+ The `task_complete` event:
128
+
129
+ ```ts
130
+ { response: string, durationMs: number, stopReason: "end_turn" | "error" | string }
131
+ ```
132
+
133
+ You usually don't subscribe directly — `SubAgentRouter` already does, and routes terminal events into the runtime. Subscribe only if you need raw access (e.g. dashboards).
134
+
135
+ ## Configuration
136
+
137
+ All configuration is via environment variables. Use `ELIZA_ACP_TRANSPORT=native` for the embedded TypeScript ACP client and `ELIZA_ACP_TRANSPORT=cli` only when you deliberately want the existing `acpx` wrapper.
138
+
139
+ | Variable | Default | Purpose |
140
+ | --- | --- | --- |
141
+ | `ELIZA_ACP_TRANSPORT` | `native` | Transport mode. Accepted values include `native`/`direct` and `cli`/`acpx`. |
142
+ | `ELIZA_ACP_CLI` | `acpx` | ACPX executable name or absolute path for the CLI transport. |
143
+ | `ELIZA_ACP_DEFAULT_AGENT` | `elizaos` | Default agent type. Primary choices: `elizaos`, `pi-agent`, `opencode`. |
144
+ | `ELIZA_ELIZAOS_ACP_COMMAND` | `elizaos` | Native elizaOS ACP command. |
145
+ | `ELIZA_PI_AGENT_ACP_COMMAND` | `pi-agent` | Native Pi Agent ACP command. |
146
+ | `ELIZA_CODEX_ACP_COMMAND` | `npx -y @zed-industries/codex-acp@0.14.0` | Native Codex ACP command. |
147
+ | `ELIZA_CLAUDE_ACP_COMMAND` | `npx -y @agentclientprotocol/claude-agent-acp@0.34.0` | Native Claude ACP command. |
148
+ | `ELIZA_OPENCODE_ACP_COMMAND` | bundled shim or `opencode acp` | Native OpenCode ACP command override. |
149
+ | `ELIZA_ACP_DEFAULT_APPROVAL` | `autonomous` | Approval preset (`read-only`, `auto`, `permissive`, `autonomous`, `full-access`). |
150
+ | `ELIZA_ACP_PROMPT_TIMEOUT_MS` / `ACPX_DEFAULT_TIMEOUT_MS` | `300000` (5m) | Per-prompt timeout. |
151
+ | `ELIZA_ACP_STATE_DIR` | `~/.eliza/plugin-acp` | Where to persist session state when no runtime DB. |
152
+ | `ACPX_DEFAULT_CWD` | runtime cwd | Base directory for spawned agent workdirs. |
153
+ | `ELIZA_ACP_MAX_SESSIONS` | `8` | Concurrent session cap. |
154
+ | `ACPX_SUB_AGENT_ROUTER_DISABLED` | unset | Set to `1` to keep the router service registered but unbound (test/staging). |
155
+ | `ACPX_SUB_AGENT_ROUND_TRIP_CAP` | `32` | Per-session inject cap before force-stop to prevent ping-pong loops. |
156
+ | `ACPX_PROGRESS_MODE` / `ELIZA_SUB_AGENT_PROGRESS_MODE` | `compact` | Sub-agent progress UX: `compact` delays and edits one status message, `threaded` preserves per-task threads, `silent` disables visible progress. |
157
+ | `ACPX_PROGRESS_DELAY_MS` / `ELIZA_SUB_AGENT_PROGRESS_DELAY_MS` | `15000` | Delay before the first visible progress message, so short tasks only show the final answer. |
158
+ | `ACPX_PROGRESS_REACTIONS` / `ELIZA_SUB_AGENT_PROGRESS_REACTIONS` | unset | Set to `1` to add progress reactions in `threaded` mode. |
159
+
160
+ ### Native transport status
161
+
162
+ Native transport is an ACP JSON-RPC client. It currently handles `initialize`, `session/new`, `session/prompt`, cooperative `session/cancel`, `session/close`, file reads/writes scoped to the session workspace, permission requests, and basic terminal requests from the agent.
163
+
164
+ Use the CLI transport only when you need the existing `acpx` command wrapper semantics.
165
+
166
+ ## Persistence
167
+
168
+ Session state is persisted with a tiered backend:
169
+
170
+ 1. If `runtime.databaseAdapter` exposes SQL methods, sessions live in the `acp_sessions` table.
171
+ 2. Otherwise, JSON file at `$ELIZA_ACP_STATE_DIR/sessions.json` (atomic writes via temp+rename).
172
+ 3. Last resort: in-memory `Map` (warns that sessions won't survive restart).
173
+
174
+ ## End-to-end smoke tests
175
+
176
+ Two smokes ship with the repo:
177
+
178
+ ```bash
179
+ # Raw AcpService against installed acpx + codex:
180
+ npm install -g acpx@latest
181
+ # authenticate codex first
182
+ npm run build
183
+ node tests/e2e/acp-codex-smoke.mjs
184
+
185
+ # Full router loop (vitest, gated):
186
+ RUN_LIVE_ACPX=1 bun run test
187
+
188
+ # Native ACP adapter smoke (gated, no-op unless enabled):
189
+ RUN_LIVE_NATIVE_ACP=1 node tests/e2e/live-native-acp-smoke.mjs
190
+ ```
191
+
192
+ `acp-codex-smoke.mjs` exercises the legacy `acpx` path by spawning a real codex session, sending "what is 7 + 8?", and verifying `task_complete` fires with response `"15"`. The vitest live test (`__tests__/live/sub-agent-router.live.test.ts`) verifies the synthetic Memory routes back from a real subprocess into a test `messageService.handleMessage` with all routing keys intact. Both no-op (skip) when `acpx` isn't installed.
193
+
194
+ `live-native-acp-smoke.mjs` sets `ELIZA_ACP_TRANSPORT=native`, starts a native ACP adapter over stdio, sends a tiny math prompt, and verifies the prompt response ended with `stopReason: "end_turn"` and final text containing `15`. Optional providers require explicit commands:
195
+
196
+ ```bash
197
+ RUN_LIVE_NATIVE_ACP=1 LIVE_NATIVE_ACP_AGENT=claude ELIZA_CLAUDE_ACP_COMMAND="npx -y @agentclientprotocol/claude-agent-acp@0.34.0" node tests/e2e/live-native-acp-smoke.mjs
198
+ RUN_LIVE_NATIVE_ACP=1 LIVE_NATIVE_ACP_AGENT=opencode ELIZA_OPENCODE_ACP_COMMAND="opencode acp" node tests/e2e/live-native-acp-smoke.mjs
199
+ ```
200
+
201
+ The native smoke skips successfully when `RUN_LIVE_NATIVE_ACP` is unset, when an optional provider command is not configured, or when the adapter reports missing authentication/credentials. Use `RUN_LIVE_NATIVE_ACP=1 bun run test -- __tests__/live/native-acp-smoke.live.test.ts` to run the same smoke through Vitest.
202
+
203
+ Native transport is covered by unit tests under `__tests__/unit/acp-native-transport.test.ts` and by the gated live smoke above.
204
+
205
+ ## Package scripts
206
+
207
+ | Script | Purpose |
208
+ | --- | --- |
209
+ | `bun run build` / `bun run build:ts` | Build Node ESM, CJS, and declaration outputs. |
210
+ | `bun run dev` | Rebuild in watch mode. |
211
+ | `bun run typecheck` | Run TypeScript without emitting files. |
212
+ | `bun run test` | Run the plugin vitest suite. |
213
+ | `bun run test:unit` | Run unit tests only. |
214
+ | `bun run test:e2e:manual` | Run the manual `acp-codex-smoke.mjs` smoke against installed/authenticated `acpx` + Codex. |
215
+ | `bun run test:watch` | Run the vitest suite in watch mode. |
216
+ | `bun run lint:check` | Run Biome checks without writing changes. |
217
+ | `bun run lint` | Run Biome checks with write/unsafe fixes. |
218
+ | `bun run format:check` | Check formatting. |
219
+ | `bun run format` | Write formatting changes. |
220
+ | `bun run clean` | Remove local build/cache outputs. |
221
+
222
+ ## Status
223
+
224
+ `2.0.3-beta.14` — package. ACP subprocess sessions are the only task-agent spawn path. The native ACP client is the default (`ELIZA_ACP_TRANSPORT=native`).
225
+
226
+ ## Contributing
227
+
228
+ PRs welcome. Run `npm run typecheck && npm test` before opening.
229
+
230
+ ## License
231
+
232
+ MIT. See [LICENSE](./LICENSE).
@@ -0,0 +1,138 @@
1
+ # Sub-agent flow & Codex / Claude-Code parity review
2
+
3
+ A thorough walk of how the main agent creates a task, spawns sub-agents,
4
+ provisions them, and communicates — across the elizaOS, Codex, and Claude
5
+ frameworks — plus an honest parity assessment against standalone Codex CLI and
6
+ Claude Code, and the concrete open items.
7
+
8
+ ## 1. End-to-end flow
9
+
10
+ ```
11
+ user msg → planner → TASKS_CREATE ─────────────► durable task (status: open)
12
+ │ roomId, taskRoomId, ownerUserId,
13
+ │ originalRequest, acceptanceCriteria
14
+
15
+ TASKS_SPAWN_AGENT ────────────► AcpService.spawnSession(SpawnOptions)
16
+ │ goal-prompt.ts wraps agentType, workdir, goalPrompt,
17
+ │ the goal + rooms + approvalPreset, metadata{roomId,
18
+ │ acceptance criteria source, label, worldId, userId}
19
+
20
+ ACP subprocess (native JSON-RPC over stdio)
21
+ elizaos | codex | claude | opencode | pi-agent
22
+ │ session/new → session/prompt(goal)
23
+
24
+ events: ready · tool_running · message · reasoning · plan ·
25
+ blocked · task_complete · error · usage_update
26
+
27
+ ┌────────────────┴───────────────────────────────┐
28
+ ▼ ▼
29
+ OrchestratorTaskService.onSessionEvent SubAgentRouter.handleEvent
30
+ (durable: addEvent / updateSession / (synthetic Memory → planner;
31
+ recordMessage; task_complete → "validating") round-trip cap = 32)
32
+
33
+
34
+ planner ↔ subAgentCompletionResponseEvaluator
35
+ → reply to user OR TASKS_SEND_TO_AGENT
36
+ ```
37
+
38
+ **Key files:** task create `actions/tasks.ts:685` → `services/orchestrator-task-service.ts:746`;
39
+ spawn `actions/tasks.ts:743` → `services/acp-service.ts:511`; goal wrap
40
+ `services/goal-prompt.ts:129`; event bridge `orchestrator-task-service.ts:519`;
41
+ routing `services/sub-agent-router.ts`; completion gate
42
+ `orchestrator-task-service.ts:608` (`task_complete` → `validating`, never straight
43
+ to `done`); evaluator `evaluators/sub-agent-completion.ts`.
44
+
45
+ **Provisioning** happens at spawn: `acp-service.ts` resolves the workdir, captures
46
+ a git baseline SHA + dirty set (for the completion changeset), and writes a
47
+ sub-agent `AGENTS.md`/`CLAUDE.md` identity manifest on bare workdirs
48
+ (`sub-agent-identity.ts`). Explicit repo clone / worktree / branch / commit / push
49
+ / PR is `CodingWorkspaceService` (`workspace-*.ts`), driven by
50
+ `TASKS_PROVISION_WORKSPACE` / `TASKS_SUBMIT_WORKSPACE`.
51
+
52
+ ## 2. Sub-agent rooms per task
53
+
54
+ - `roomId` = the originating user channel (where the final reply goes).
55
+ `taskRoomId` = a dedicated task-scoped room; all sessions' messages
56
+ (`senderKind: user|orchestrator|sub_agent|system`) append there. Exposed via
57
+ `GET /api/orchestrator/tasks/:id/messages`, `/timeline`, and `/stream` (SSE).
58
+ - The in-app **task view** (`plugin-task-coordinator/src/OrchestratorWorkbench.tsx`)
59
+ renders this as a per-task message room: the merged timeline + per-sub-agent
60
+ sessions list + plan + diff + usage + recovery, with near-live polling.
61
+ - On chat connectors, the **progress thread** (`index.ts emitProgress`) routes all
62
+ sub-agent narration into a per-task Discord thread / Telegram forum topic
63
+ (capability-gated on `create_thread` + `post_to_thread` + threaded progress
64
+ mode), keeping the main channel clean. This is the "task info as threads in TG
65
+ and Discord" surface.
66
+
67
+ ## 3. Inter-agent communication
68
+
69
+ **Topology: hub-and-spoke.** Sub-agents do not address each other directly. Each
70
+ talks only to the parent:
71
+ - parent → sub: initial goal prompt; mid-flight `TASKS_SEND_TO_AGENT`; live user
72
+ messages in the task room are auto-forwarded to the active session
73
+ (`index.ts` MESSAGE_RECEIVED listener).
74
+ - sub → parent: terminal ACP events → synthetic memories; plus a sub-agent can
75
+ emit `USE_SKILL parent-agent {…}` which the router dispatches to the
76
+ parent-agent broker (`parent-agent-dispatch.ts` / `parent-agent-broker.ts`) and
77
+ replies back over the session.
78
+ - sub → parent context: loopback-only bridge `GET /api/coding-agents/:id/context/*`
79
+ (parent character, current room, memory search, active workspaces).
80
+
81
+ Multiple sub-agents per task are supported (`sessions[]`), unsynchronized; the
82
+ router de-dupes concurrent `task_complete` so only the first posts to the user.
83
+
84
+ ## 4. Framework matrix (elizaOS / Codex / Claude)
85
+
86
+ All run as ACP subprocesses over the native JSON-RPC transport
87
+ (`acp-native-transport.ts`); spawn command per framework is env-overridable
88
+ (`ELIZA_{ELIZAOS,CODEX,CLAUDE,OPENCODE,PI_AGENT}_ACP_COMMAND`; Codex/Claude default
89
+ to pinned `npx` ACP shims). The orchestrator implements the ACP client side of:
90
+ `session/new`, `session/prompt`, `session/cancel`, `session/update` (streaming
91
+ `agent_message_chunk` / `agent_thought_chunk` / `tool_call` / `plan`),
92
+ `session/request_permission`, `fs/read_text_file`, `fs/write_text_file`, and the
93
+ `terminal/*` family. Approval presets (`readonly|standard|permissive|autonomous`)
94
+ gate file/terminal ops. Credentials reach sub-agents via the loopback credential
95
+ tunnel (`bridge-routes.ts`); host connector tokens are denylisted from the child
96
+ env, and Claude OAuth-subscription tokens are stripped so the child uses its own
97
+ subscription.
98
+
99
+ ## 5. Parity vs standalone Codex CLI / Claude Code
100
+
101
+ **At parity:** multi-framework spawn + routing; file read/write; terminal exec;
102
+ plan/reasoning/tool streaming; approval gates; real git-diff capture & surfacing
103
+ (`coding-session-changes.ts`); token usage; orphaned-session recovery on restart;
104
+ durable task store + task view; per-task threads on connectors.
105
+
106
+ **Partial:** plan/todo events are emitted by OpenCode but not uniformly by
107
+ Codex/Claude; diff surfacing truncates (20 files / 50 lines) with no inline
108
+ per-line review UI; sub-agents run `--no-terminal` (event-driven, no interactive
109
+ TUI — correct for orchestration, but differs from a human at the CLI).
110
+
111
+ **Gaps:**
112
+ 1. **MCP forwarding** — ✅ implemented (opt-in). `acp-native-transport.ts`
113
+ forwards `ELIZA_ACP_MCP_SERVERS` (a JSON array of stdio/http MCP server
114
+ configs) into `session/new.mcpServers` via `parseAcpMcpServersEnv`, so
115
+ sub-agents get the parent's MCP tools (Codex / Claude-Code parity). Defaults
116
+ to `[]` (prior behavior) so spawning never regresses. Remaining: auto-inherit
117
+ the parent runtime's MCP set without explicit env config (needs a runtime
118
+ MCP-config surface, which doesn't exist yet).
119
+ 2. **Sub-agent nesting** (open) — no spawn-child API; a sub-agent cannot delegate
120
+ to its own sub-agents (single level of orchestration). Feature-level work.
121
+ 3. **Inline code-review surface** — diffs are captured but there's no structured
122
+ per-file/line review/approve UI in the task view.
123
+
124
+ ## 6. Open items checklist
125
+
126
+ - [x] Interaction protocol (forms / choice + custom / secret / task) across app + TG + Discord
127
+ - [x] Pick-an-option round-trip on both connectors; secret/OAuth DM link-out on both
128
+ - [x] Per-task threads on TG + Discord (orchestrator-driven; both connectors now capable)
129
+ - [x] Task view with sub-agent message room (OrchestratorWorkbench)
130
+ - [x] Real interaction-widget + connector round-trip tests
131
+ - [x] MCP server forwarding to sub-agents (opt-in via `ELIZA_ACP_MCP_SERVERS`)
132
+ - [ ] Sub-agent nesting / delegation (gap #2 — feature-level)
133
+ - [ ] Inline diff review UI in the task view (gap #3)
134
+ - [ ] Live connector E2E (needs TG/Discord credentials) + orchestrator HTTP task-flow E2E
135
+ - [ ] Optional: `outgoing_before_deliver` central interaction normalization hook
136
+
137
+ See `@elizaos/core` `src/messaging/interactions/README.md` for the interaction
138
+ protocol; this doc covers the orchestration + sub-agent layer.