@elizaos/plugin-agent-orchestrator 2.0.0-beta.1 → 2.0.11-beta.7
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/CHANGELOG.md +6 -8
- package/README.md +102 -30
- package/docs/SUBAGENT_FLOW_AND_PARITY.md +138 -0
- package/docs/default-eliza-skills-and-agent-bridge-plan.md +9 -15
- package/docs/economics-goal-runbook.md +140 -0
- package/docs/multi-account-orchestration.md +76 -0
- package/docs/orchestrator-buildout-followups.md +124 -0
- package/docs/orchestrator-dashboard-task-widget-secrets-assessment.md +174 -0
- package/docs/orchestrator-dashboard-task-widget-secrets-design.md +301 -0
- package/docs/research/orchestrator-view-research-report.md +273 -0
- package/docs/sub-agent-routing.md +53 -23
- package/package.json +108 -25
- package/PROJECT.md +0 -119
- package/dist/browser/index.browser.js +0 -21051
- package/dist/browser/index.browser.js.map +0 -29
- package/dist/browser/index.d.ts +0 -2
- package/dist/cjs/index.d.ts +0 -2
- package/dist/cjs/index.node.cjs +0 -20491
- package/dist/cjs/index.node.js.map +0 -72
- package/dist/index.d.ts +0 -2
- package/dist/node/index.browser.d.ts +0 -3
- package/dist/node/index.browser.d.ts.map +0 -1
- package/dist/node/index.d.ts +0 -2
- package/dist/node/index.d.ts.map +0 -1
- package/dist/node/index.node.d.ts +0 -4
- package/dist/node/index.node.d.ts.map +0 -1
- package/dist/node/index.node.js +0 -20471
- package/dist/node/index.node.js.map +0 -72
- package/dist/node/src/actions/cancel-task.d.ts +0 -3
- package/dist/node/src/actions/cancel-task.d.ts.map +0 -1
- package/dist/node/src/actions/coding-task-handlers.d.ts +0 -69
- package/dist/node/src/actions/coding-task-handlers.d.ts.map +0 -1
- package/dist/node/src/actions/coding-task-helpers.d.ts +0 -35
- package/dist/node/src/actions/coding-task-helpers.d.ts.map +0 -1
- package/dist/node/src/actions/common.d.ts +0 -56
- package/dist/node/src/actions/common.d.ts.map +0 -1
- package/dist/node/src/actions/create-task.d.ts +0 -8
- package/dist/node/src/actions/create-task.d.ts.map +0 -1
- package/dist/node/src/actions/eval-metadata.d.ts +0 -11
- package/dist/node/src/actions/eval-metadata.d.ts.map +0 -1
- package/dist/node/src/actions/finalize-workspace.d.ts +0 -11
- package/dist/node/src/actions/finalize-workspace.d.ts.map +0 -1
- package/dist/node/src/actions/list-agents.d.ts +0 -4
- package/dist/node/src/actions/list-agents.d.ts.map +0 -1
- package/dist/node/src/actions/manage-issues.d.ts +0 -11
- package/dist/node/src/actions/manage-issues.d.ts.map +0 -1
- package/dist/node/src/actions/provision-workspace.d.ts +0 -11
- package/dist/node/src/actions/provision-workspace.d.ts.map +0 -1
- package/dist/node/src/actions/sandbox-stub.d.ts +0 -21
- package/dist/node/src/actions/sandbox-stub.d.ts.map +0 -1
- package/dist/node/src/actions/send-to-agent.d.ts +0 -4
- package/dist/node/src/actions/send-to-agent.d.ts.map +0 -1
- package/dist/node/src/actions/spawn-agent.d.ts +0 -8
- package/dist/node/src/actions/spawn-agent.d.ts.map +0 -1
- package/dist/node/src/actions/stop-agent.d.ts +0 -4
- package/dist/node/src/actions/stop-agent.d.ts.map +0 -1
- package/dist/node/src/actions/task-control.d.ts +0 -3
- package/dist/node/src/actions/task-control.d.ts.map +0 -1
- package/dist/node/src/actions/task-history.d.ts +0 -3
- package/dist/node/src/actions/task-history.d.ts.map +0 -1
- package/dist/node/src/actions/task-share.d.ts +0 -3
- package/dist/node/src/actions/task-share.d.ts.map +0 -1
- package/dist/node/src/actions/task-thread-target.d.ts +0 -11
- package/dist/node/src/actions/task-thread-target.d.ts.map +0 -1
- package/dist/node/src/actions/tasks.d.ts +0 -88
- package/dist/node/src/actions/tasks.d.ts.map +0 -1
- package/dist/node/src/api/agent-routes.d.ts +0 -18
- package/dist/node/src/api/agent-routes.d.ts.map +0 -1
- package/dist/node/src/api/bridge-routes.d.ts +0 -32
- package/dist/node/src/api/bridge-routes.d.ts.map +0 -1
- package/dist/node/src/api/coordinator-routes.d.ts +0 -22
- package/dist/node/src/api/coordinator-routes.d.ts.map +0 -1
- package/dist/node/src/api/hook-routes.d.ts +0 -18
- package/dist/node/src/api/hook-routes.d.ts.map +0 -1
- package/dist/node/src/api/issue-routes.d.ts +0 -17
- package/dist/node/src/api/issue-routes.d.ts.map +0 -1
- package/dist/node/src/api/parent-context-routes.d.ts +0 -17
- package/dist/node/src/api/parent-context-routes.d.ts.map +0 -1
- package/dist/node/src/api/route-utils.d.ts +0 -18
- package/dist/node/src/api/route-utils.d.ts.map +0 -1
- package/dist/node/src/api/routes.d.ts +0 -23
- package/dist/node/src/api/routes.d.ts.map +0 -1
- package/dist/node/src/api/workspace-routes.d.ts +0 -17
- package/dist/node/src/api/workspace-routes.d.ts.map +0 -1
- package/dist/node/src/index.d.ts +0 -32
- package/dist/node/src/index.d.ts.map +0 -1
- package/dist/node/src/providers/action-examples.d.ts +0 -14
- package/dist/node/src/providers/action-examples.d.ts.map +0 -1
- package/dist/node/src/providers/active-sub-agents.d.ts +0 -15
- package/dist/node/src/providers/active-sub-agents.d.ts.map +0 -1
- package/dist/node/src/providers/active-workspace-context.d.ts +0 -13
- package/dist/node/src/providers/active-workspace-context.d.ts.map +0 -1
- package/dist/node/src/providers/available-agents.d.ts +0 -4
- package/dist/node/src/providers/available-agents.d.ts.map +0 -1
- package/dist/node/src/register-routes.d.ts +0 -11
- package/dist/node/src/register-routes.d.ts.map +0 -1
- package/dist/node/src/routes/coding-agents-fallback-routes.d.ts +0 -19
- package/dist/node/src/routes/coding-agents-fallback-routes.d.ts.map +0 -1
- package/dist/node/src/services/acp-service.d.ts +0 -61
- package/dist/node/src/services/acp-service.d.ts.map +0 -1
- package/dist/node/src/services/acpx-subprocess.d.ts +0 -3
- package/dist/node/src/services/acpx-subprocess.d.ts.map +0 -1
- package/dist/node/src/services/agent-credentials.d.ts +0 -23
- package/dist/node/src/services/agent-credentials.d.ts.map +0 -1
- package/dist/node/src/services/agent-metrics.d.ts +0 -30
- package/dist/node/src/services/agent-metrics.d.ts.map +0 -1
- package/dist/node/src/services/agent-selection.d.ts +0 -53
- package/dist/node/src/services/agent-selection.d.ts.map +0 -1
- package/dist/node/src/services/ansi-utils.d.ts +0 -64
- package/dist/node/src/services/ansi-utils.d.ts.map +0 -1
- package/dist/node/src/services/claude-code-skill-installer.d.ts +0 -33
- package/dist/node/src/services/claude-code-skill-installer.d.ts.map +0 -1
- package/dist/node/src/services/config-env.d.ts +0 -23
- package/dist/node/src/services/config-env.d.ts.map +0 -1
- package/dist/node/src/services/coordinator-event-normalizer.d.ts +0 -50
- package/dist/node/src/services/coordinator-event-normalizer.d.ts.map +0 -1
- package/dist/node/src/services/custom-validator-runner.d.ts +0 -66
- package/dist/node/src/services/custom-validator-runner.d.ts.map +0 -1
- package/dist/node/src/services/debug-capture.d.ts +0 -38
- package/dist/node/src/services/debug-capture.d.ts.map +0 -1
- package/dist/node/src/services/json-model-output.d.ts +0 -2
- package/dist/node/src/services/json-model-output.d.ts.map +0 -1
- package/dist/node/src/services/parent-agent-broker.d.ts +0 -21
- package/dist/node/src/services/parent-agent-broker.d.ts.map +0 -1
- package/dist/node/src/services/pty-auto-response.d.ts +0 -30
- package/dist/node/src/services/pty-auto-response.d.ts.map +0 -1
- package/dist/node/src/services/pty-init.d.ts +0 -55
- package/dist/node/src/services/pty-init.d.ts.map +0 -1
- package/dist/node/src/services/pty-service.d.ts +0 -218
- package/dist/node/src/services/pty-service.d.ts.map +0 -1
- package/dist/node/src/services/pty-session-io.d.ts +0 -49
- package/dist/node/src/services/pty-session-io.d.ts.map +0 -1
- package/dist/node/src/services/pty-spawn.d.ts +0 -104
- package/dist/node/src/services/pty-spawn.d.ts.map +0 -1
- package/dist/node/src/services/pty-types.d.ts +0 -94
- package/dist/node/src/services/pty-types.d.ts.map +0 -1
- package/dist/node/src/services/repo-input.d.ts +0 -16
- package/dist/node/src/services/repo-input.d.ts.map +0 -1
- package/dist/node/src/services/session-event-queue.d.ts +0 -25
- package/dist/node/src/services/session-event-queue.d.ts.map +0 -1
- package/dist/node/src/services/session-store.d.ts +0 -107
- package/dist/node/src/services/session-store.d.ts.map +0 -1
- package/dist/node/src/services/skill-callback-bridge.d.ts +0 -78
- package/dist/node/src/services/skill-callback-bridge.d.ts.map +0 -1
- package/dist/node/src/services/skill-essentials.d.ts +0 -16
- package/dist/node/src/services/skill-essentials.d.ts.map +0 -1
- package/dist/node/src/services/skill-lifeops-context-broker.d.ts +0 -20
- package/dist/node/src/services/skill-lifeops-context-broker.d.ts.map +0 -1
- package/dist/node/src/services/skill-manifest.d.ts +0 -48
- package/dist/node/src/services/skill-manifest.d.ts.map +0 -1
- package/dist/node/src/services/skill-recommender.d.ts +0 -51
- package/dist/node/src/services/skill-recommender.d.ts.map +0 -1
- package/dist/node/src/services/spawn-trajectory.d.ts +0 -23
- package/dist/node/src/services/spawn-trajectory.d.ts.map +0 -1
- package/dist/node/src/services/stall-classifier.d.ts +0 -69
- package/dist/node/src/services/stall-classifier.d.ts.map +0 -1
- package/dist/node/src/services/structured-proof-bridge.d.ts +0 -99
- package/dist/node/src/services/structured-proof-bridge.d.ts.map +0 -1
- package/dist/node/src/services/sub-agent-router.d.ts +0 -38
- package/dist/node/src/services/sub-agent-router.d.ts.map +0 -1
- package/dist/node/src/services/swarm-coordinator-prompts.d.ts +0 -93
- package/dist/node/src/services/swarm-coordinator-prompts.d.ts.map +0 -1
- package/dist/node/src/services/swarm-coordinator.d.ts +0 -473
- package/dist/node/src/services/swarm-coordinator.d.ts.map +0 -1
- package/dist/node/src/services/swarm-decision-loop.d.ts +0 -69
- package/dist/node/src/services/swarm-decision-loop.d.ts.map +0 -1
- package/dist/node/src/services/swarm-event-triage.d.ts +0 -49
- package/dist/node/src/services/swarm-event-triage.d.ts.map +0 -1
- package/dist/node/src/services/swarm-history.d.ts +0 -27
- package/dist/node/src/services/swarm-history.d.ts.map +0 -1
- package/dist/node/src/services/swarm-idle-watchdog.d.ts +0 -22
- package/dist/node/src/services/swarm-idle-watchdog.d.ts.map +0 -1
- package/dist/node/src/services/task-acceptance.d.ts +0 -8
- package/dist/node/src/services/task-acceptance.d.ts.map +0 -1
- package/dist/node/src/services/task-agent-auth.d.ts +0 -69
- package/dist/node/src/services/task-agent-auth.d.ts.map +0 -1
- package/dist/node/src/services/task-agent-frameworks.d.ts +0 -90
- package/dist/node/src/services/task-agent-frameworks.d.ts.map +0 -1
- package/dist/node/src/services/task-kind.d.ts +0 -3
- package/dist/node/src/services/task-kind.d.ts.map +0 -1
- package/dist/node/src/services/task-policy.d.ts +0 -17
- package/dist/node/src/services/task-policy.d.ts.map +0 -1
- package/dist/node/src/services/task-registry.d.ts +0 -550
- package/dist/node/src/services/task-registry.d.ts.map +0 -1
- package/dist/node/src/services/task-share.d.ts +0 -18
- package/dist/node/src/services/task-share.d.ts.map +0 -1
- package/dist/node/src/services/task-validation.d.ts +0 -69
- package/dist/node/src/services/task-validation.d.ts.map +0 -1
- package/dist/node/src/services/task-verifier-runner.d.ts +0 -5
- package/dist/node/src/services/task-verifier-runner.d.ts.map +0 -1
- package/dist/node/src/services/trajectory-context.d.ts +0 -73
- package/dist/node/src/services/trajectory-context.d.ts.map +0 -1
- package/dist/node/src/services/trajectory-feedback.d.ts +0 -53
- package/dist/node/src/services/trajectory-feedback.d.ts.map +0 -1
- package/dist/node/src/services/types.d.ts +0 -152
- package/dist/node/src/services/types.d.ts.map +0 -1
- package/dist/node/src/services/workspace-git-ops.d.ts +0 -28
- package/dist/node/src/services/workspace-git-ops.d.ts.map +0 -1
- package/dist/node/src/services/workspace-github.d.ts +0 -60
- package/dist/node/src/services/workspace-github.d.ts.map +0 -1
- package/dist/node/src/services/workspace-lifecycle.d.ts +0 -18
- package/dist/node/src/services/workspace-lifecycle.d.ts.map +0 -1
- package/dist/node/src/services/workspace-service.d.ts +0 -122
- package/dist/node/src/services/workspace-service.d.ts.map +0 -1
- package/dist/node/src/services/workspace-types.d.ts +0 -81
- package/dist/node/src/services/workspace-types.d.ts.map +0 -1
- package/dist/node/src/setup-routes.d.ts +0 -9
- package/dist/node/src/setup-routes.d.ts.map +0 -1
- package/dist/node/vitest.config.d.ts +0 -3
- package/dist/node/vitest.config.d.ts.map +0 -1
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# Orchestrator dashboard, in-chat task widget, and secrets widgets — design
|
|
2
|
+
|
|
3
|
+
Date: 2026-06-05. Companion to
|
|
4
|
+
[`orchestrator-buildout-followups.md`](./orchestrator-buildout-followups.md).
|
|
5
|
+
|
|
6
|
+
This is a code-grounded, intentionally small design for three connected gaps the
|
|
7
|
+
goal hook calls out, in priority order:
|
|
8
|
+
|
|
9
|
+
1. **Orchestrator view should read as a *dashboard*** of ongoing tasks — quick
|
|
10
|
+
active/finished/needs-attention counts at the top, a minimal card list
|
|
11
|
+
underneath, click a card to drill into the existing full inspector.
|
|
12
|
+
2. **Task creation should drop a live `TaskWidget` into the chat** that shows
|
|
13
|
+
status and is clickable. The chat conversation continues; the agent keeps
|
|
14
|
+
task context; the orchestrator view's action bar stays view-dependent on the
|
|
15
|
+
currently-selected task.
|
|
16
|
+
3. **Sensitive-request widgets in chat (form / OAuth / secret) must
|
|
17
|
+
actually work and be tested**, with no secret material echoed to chat.
|
|
18
|
+
|
|
19
|
+
Scope is intentionally narrow. The existing
|
|
20
|
+
[`OrchestratorWorkbench.tsx`](../src/OrchestratorWorkbench.tsx) (4142 LOC) is
|
|
21
|
+
mature — rail, inspector, action bar, timeline, operator drawer, plan editor.
|
|
22
|
+
We do not redesign it. We add a thin glance strip, fix the gaps, and lock
|
|
23
|
+
behavior in tests.
|
|
24
|
+
|
|
25
|
+
## What exists today (ground truth)
|
|
26
|
+
|
|
27
|
+
- `OrchestratorWorkbench` renders `/orchestrator`. Header has Pause All / Resume
|
|
28
|
+
All / New Task; a filter dropdown shows status + count; rail renders
|
|
29
|
+
`TaskCardList` cards. Selecting a card swaps the rail for a full-pane task
|
|
30
|
+
room with timeline + inspector (`data-testid="orchestrator-inspector"`).
|
|
31
|
+
Inspector action bar is already view-dependent: validating → Approve/Reject,
|
|
32
|
+
archived → Reopen, active → Pause/Resume, plus Fork/Restart/Add Agent.
|
|
33
|
+
- `MessageContent.tsx` dispatches 7 segment kinds: `text`, `config`, `ui-spec`,
|
|
34
|
+
`choice`, `followups`, `form`, `permission`, `analysis-xml`. **There is no
|
|
35
|
+
`task-widget` kind**. A `[TASK:id]title[/TASK]` block in an assistant message
|
|
36
|
+
renders as plain text today.
|
|
37
|
+
- `SensitiveRequestBlock` (in `MessageContent.tsx`) renders inline-secret form
|
|
38
|
+
widgets driven by `message.secretRequest`. It is tested
|
|
39
|
+
(`MessageContent.sensitive-request.test.tsx`). It supports `form.kind ===
|
|
40
|
+
"secret"` only; **OAuth is not wired** — `owner-app-inline-adapter.ts`
|
|
41
|
+
explicitly rejects any non-secret kind.
|
|
42
|
+
- `task-coordinator-gui-interactions.spec.ts` covers list, search, open detail,
|
|
43
|
+
archive, reopen. `orchestrator-gui-workbench.spec.ts` covers the rich rail
|
|
44
|
+
and inspector controls (priority change, restart-with-plan, add agent,
|
|
45
|
+
pause/resume, retry/rerun). **Neither covers a chat task widget or any
|
|
46
|
+
sensitive-request widget.**
|
|
47
|
+
|
|
48
|
+
## Design
|
|
49
|
+
|
|
50
|
+
### 1. `OrchestratorGlanceStrip` — at-a-glance dashboard tile
|
|
51
|
+
|
|
52
|
+
A single pinned row above the rail, four count tiles + the existing usage chip.
|
|
53
|
+
No new state — derived from the same `/api/orchestrator/status` payload the
|
|
54
|
+
header reads. Each tile is a button that sets the filter and scrolls the rail
|
|
55
|
+
to the top.
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
59
|
+
│ ● 3 Active ◐ 1 Validating ⚠ 0 Blocked ✓ 12 Done 12.3K · $0.42 │
|
|
60
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Rules:
|
|
64
|
+
|
|
65
|
+
- **One row, fixed height.** ~32px. No subtitle text under counts.
|
|
66
|
+
- **Color = state, not decoration.** `ok` for Active, `accent` for Validating,
|
|
67
|
+
`warn` for Blocked, `muted` for Done.
|
|
68
|
+
- **Zero = `muted` text + de-emphasized tile.** Zero counts never animate.
|
|
69
|
+
- **Click filters.** Click "Active" → filter "active". Click "Blocked" →
|
|
70
|
+
filter "blocked" (rolls up `waiting_on_user` per existing status fan-out).
|
|
71
|
+
- **Hidden when there are zero tasks total** — the empty state already covers
|
|
72
|
+
this case.
|
|
73
|
+
|
|
74
|
+
Test ids: `orchestrator-glance`, `orchestrator-glance-active`,
|
|
75
|
+
`orchestrator-glance-validating`, `orchestrator-glance-blocked`,
|
|
76
|
+
`orchestrator-glance-done`.
|
|
77
|
+
|
|
78
|
+
Implementation: new component `OrchestratorGlanceStrip.tsx` rendered in
|
|
79
|
+
`OrchestratorWorkbench.tsx` directly above the rail. It reads
|
|
80
|
+
`taskCount`/`activeTaskCount`/`blockedTaskCount`/`validatingTaskCount` from
|
|
81
|
+
the same status payload `WorkbenchHeader` already consumes; we promote a small
|
|
82
|
+
counts derivation out so both call sites stay in sync.
|
|
83
|
+
|
|
84
|
+
### 2. `TaskWidget` — inline chat widget for an orchestrator task
|
|
85
|
+
|
|
86
|
+
A new segment kind in `MessageContent`. The agent emits
|
|
87
|
+
`[TASK:<threadId>]<title>[/TASK]` after a successful `TASKS_CREATE`, and the
|
|
88
|
+
chat renderer replaces it with a live widget.
|
|
89
|
+
|
|
90
|
+
Anatomy (one compact card, ~64px tall):
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
┌────────────────────────────────────────────────────────┐
|
|
94
|
+
│ ▶ Build Kanban planner app [Open] │
|
|
95
|
+
│ ● active · 2/2 agents · 3m ago · ~12.3K │
|
|
96
|
+
└────────────────────────────────────────────────────────┘
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Rules:
|
|
100
|
+
|
|
101
|
+
- **One title line + one status line.** No goal, no acceptance criteria, no
|
|
102
|
+
artifact list. Those live in the orchestrator inspector.
|
|
103
|
+
- **Status line is structured, not prose.** Status dot + label, agents
|
|
104
|
+
active/total, relative last activity, token total. Tokens hidden when
|
|
105
|
+
`usageState === "unavailable"`.
|
|
106
|
+
- **Click → navigate `/orchestrator?taskId=<id>`** (the workbench already
|
|
107
|
+
reads `?task=` via `readInitialTaskId`; we alias `?taskId=` to it).
|
|
108
|
+
- **Live updates by polling**, not WebSocket. Reuses the workbench's
|
|
109
|
+
`POLL_INTERVAL_MS = 5000` (kept in one place — exported, not duplicated). On
|
|
110
|
+
unmount, polling stops. When the underlying task is terminal
|
|
111
|
+
(`done`/`failed`/`archived`/`closed`), polling stops and the status freezes.
|
|
112
|
+
- **One outstanding fetch per widget.** Concurrent renders share a tiny
|
|
113
|
+
per-thread cache so two widgets in scrollback don't quadruple traffic.
|
|
114
|
+
- **No action buttons inline.** Action belongs to the workbench's
|
|
115
|
+
view-dependent action bar (we are explicit about this — the goal asks the
|
|
116
|
+
workbench to own actions when on a task).
|
|
117
|
+
- **Failure mode is silent.** If the task 404s (deleted), the widget shrinks
|
|
118
|
+
to "Task removed." in muted text; it never throws into the chat.
|
|
119
|
+
|
|
120
|
+
Backend hook: after `TASKS_CREATE` succeeds, the action's response text gets
|
|
121
|
+
`[TASK:${task.id}]${task.title}[/TASK]` appended. This is a one-line change in
|
|
122
|
+
`tasks.ts` (the `create` runner already returns a callback with prose).
|
|
123
|
+
|
|
124
|
+
Segment parser: extend the existing regex sweep in
|
|
125
|
+
`MessageContent.parseSegments` with a `[TASK:...]...[/TASK]` pattern, ordered
|
|
126
|
+
after `[FORM]` and before plain text. The matcher requires `threadId` to be a
|
|
127
|
+
UUID-shaped string (lowercase a–f0-9-) to avoid trivial injection from
|
|
128
|
+
unrelated text.
|
|
129
|
+
|
|
130
|
+
Test ids: `task-widget`, `task-widget-status`, `task-widget-open`.
|
|
131
|
+
|
|
132
|
+
### 3. View-dependent action bar in the workbench
|
|
133
|
+
|
|
134
|
+
Already exists in `TaskInspector` (`OrchestratorWorkbench.tsx` lines
|
|
135
|
+
2007–2187). It is correctly state-conditional but every button is always
|
|
136
|
+
rendered (just disabled when N/A). The minimal change is grouping and hiding:
|
|
137
|
+
|
|
138
|
+
- **Hide the entire "Edit" group** (Fork, Restart, Add Agent, Edit Plan) when
|
|
139
|
+
`task.status` is in {`done`, `failed`, `archived`, `closed`}. Terminal tasks
|
|
140
|
+
should only expose Reopen (and Delete).
|
|
141
|
+
- **Hide priority dropdown for terminal tasks.** Priority is meaningless once
|
|
142
|
+
closed.
|
|
143
|
+
- **Keep validating-task Approve/Reject as the only primary affordance.**
|
|
144
|
+
Other buttons collapse into an overflow.
|
|
145
|
+
|
|
146
|
+
This is small — three `if` guards. Locked in by an inspector test that
|
|
147
|
+
toggles status and asserts visibility.
|
|
148
|
+
|
|
149
|
+
### 4. Sensitive-request widgets — what's working and what we add
|
|
150
|
+
|
|
151
|
+
Working today: inline form for `kind: "secret"`. We tighten and extend.
|
|
152
|
+
|
|
153
|
+
**a. `SensitiveRequestBlock` polish (existing component, small fix)**
|
|
154
|
+
|
|
155
|
+
- Distinguish `pending` (gray "Pending"), `saving` (spinner + "Saving…"),
|
|
156
|
+
`saved` (green "Saved" + redacted preview "•••• (saved)"),
|
|
157
|
+
`failed` (red "Failed — retry"), `expired` (muted "Expired").
|
|
158
|
+
- On `saved`, the form **never re-renders the password input** for the same
|
|
159
|
+
request id, even if the message re-mounts. Backed by a tiny per-requestId
|
|
160
|
+
saved-state cache in component scope.
|
|
161
|
+
- Reason and instruction text already render; we make sure they never include
|
|
162
|
+
the secret value (server-side sanitization is the actual guarantee; the
|
|
163
|
+
widget asserts `value` is never substituted into `instruction` or `reason`
|
|
164
|
+
via `MessageContent.sensitive-request.test.tsx`).
|
|
165
|
+
|
|
166
|
+
**b. `OAuthRequestBlock` (new, in `MessageContent.tsx`)**
|
|
167
|
+
|
|
168
|
+
Renders when `message.secretRequest.form.kind === "oauth"`. Shape:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
┌────────────────────────────────────────────┐
|
|
172
|
+
│ Connect GitHub │
|
|
173
|
+
│ Needed for: managing PRs on this task │
|
|
174
|
+
│ │
|
|
175
|
+
│ [ Connect with GitHub → ] Pending │
|
|
176
|
+
└────────────────────────────────────────────┘
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Rules:
|
|
180
|
+
|
|
181
|
+
- **One button.** It calls `client.startSensitiveRequestOAuth(requestId)`
|
|
182
|
+
which returns `{ authorizationUrl, state }` and opens it in a popup
|
|
183
|
+
(`window.open` with a sized rect). Same-origin fallback for embedded
|
|
184
|
+
environments where popups are blocked.
|
|
185
|
+
- **No token ever passed through chat.** The OAuth callback fulfills the
|
|
186
|
+
request server-side; the widget polls
|
|
187
|
+
`GET /api/sensitive-requests/:id/status` every 2s, up to `expiresAt`, and
|
|
188
|
+
stops on terminal states.
|
|
189
|
+
- **Visible state machine:** `Pending` → `Authorizing…` → `Saved` |
|
|
190
|
+
`Failed — retry` | `Expired`.
|
|
191
|
+
- **Cancel.** A small `Cancel` link sends `DELETE
|
|
192
|
+
/api/sensitive-requests/:id` and flips to `Cancelled`.
|
|
193
|
+
|
|
194
|
+
Backend wiring is a sibling of the inline adapter:
|
|
195
|
+
`packages/app-core/src/services/sensitive-requests/owner-app-oauth-adapter.ts`.
|
|
196
|
+
The adapter's `deliver()` accepts `request.target.kind === "oauth"` requests
|
|
197
|
+
(new target kind), builds an envelope with `form: { kind: "oauth", provider,
|
|
198
|
+
scopes, label, submitLabel: "Connect …" }`, and sends the inline chat content.
|
|
199
|
+
The OAuth callback handler lands tokens in `sharedVault` exactly like the
|
|
200
|
+
existing GitHub OAuth flow; only the *trigger* differs.
|
|
201
|
+
|
|
202
|
+
We do **not** ship a generic OAuth backend in this slice. We ship the widget +
|
|
203
|
+
its parser + a fixture-backed e2e + a unit test for envelope construction.
|
|
204
|
+
A follow-up wires production providers (per
|
|
205
|
+
[`orchestrator-buildout-followups.md`](./orchestrator-buildout-followups.md)
|
|
206
|
+
section B).
|
|
207
|
+
|
|
208
|
+
**c. `FormRequest` (existing `[FORM]` widget) — unchanged**
|
|
209
|
+
|
|
210
|
+
The non-sensitive `[FORM]` widget already works
|
|
211
|
+
(`form-request.tsx`). It is referenced here only to draw the line: that
|
|
212
|
+
widget's submission **is echoed to chat** because it carries non-secret data.
|
|
213
|
+
Sensitive requests must never reuse it.
|
|
214
|
+
|
|
215
|
+
### Security guarantees we explicitly maintain
|
|
216
|
+
|
|
217
|
+
- The secret/OAuth widgets must never push the value or token into the chat
|
|
218
|
+
message stream. The current inline adapter calls
|
|
219
|
+
`client.updateSecrets(secrets)` directly and ignores its message channel
|
|
220
|
+
for the value; we keep that, and add an integration test that scrapes the
|
|
221
|
+
recorded chat-message stream after a successful save and asserts no field
|
|
222
|
+
value appears.
|
|
223
|
+
- OAuth callbacks must never include tokens in URL fragments delivered to the
|
|
224
|
+
chat surface. The popup posts the result to the server; the chat surface
|
|
225
|
+
only sees `status` transitions.
|
|
226
|
+
- Widget rendering is gated on `delivery.canCollectValueInCurrentChannel ===
|
|
227
|
+
true`. Public/group surfaces continue to render the existing
|
|
228
|
+
status-only card pointing at the owner app.
|
|
229
|
+
|
|
230
|
+
## Tests
|
|
231
|
+
|
|
232
|
+
All under existing infra (`packages/ui` vitest for components,
|
|
233
|
+
`packages/app/test/ui-smoke` Playwright for the route).
|
|
234
|
+
|
|
235
|
+
1. **Component (vitest, packages/ui):**
|
|
236
|
+
- `MessageContent.task-widget.test.tsx` — `[TASK:id]title[/TASK]` parses to a
|
|
237
|
+
`TaskWidget`; renders title; polls once and renders status; click
|
|
238
|
+
dispatches navigation.
|
|
239
|
+
- `MessageContent.sensitive-request.test.tsx` (extend) — status transitions;
|
|
240
|
+
saved-state cache survives remount; instruction never contains the
|
|
241
|
+
entered value.
|
|
242
|
+
- `MessageContent.oauth-request.test.tsx` — OAuth widget shows Connect,
|
|
243
|
+
opens popup (mocked `window.open`), polls status, lands on `Saved`.
|
|
244
|
+
|
|
245
|
+
2. **Plugin (vitest, plugin-agent-orchestrator):**
|
|
246
|
+
- `create-task-emits-task-block.test.ts` — `TASKS_CREATE` runner output
|
|
247
|
+
contains `[TASK:${id}]${title}[/TASK]`.
|
|
248
|
+
- `owner-app-oauth-adapter.test.ts` — envelope shape; rejects non-OAuth
|
|
249
|
+
kind; emits an inline content with `form.kind === "oauth"`.
|
|
250
|
+
|
|
251
|
+
3. **Playwright (packages/app):**
|
|
252
|
+
- Extend `orchestrator-gui-workbench.spec.ts` with a `glance strip` test —
|
|
253
|
+
fixture seeds 3 active / 1 validating / 12 done; assert tile counts;
|
|
254
|
+
click Validating → filter switches; assert rail shows only the validating
|
|
255
|
+
task.
|
|
256
|
+
- New `task-widget-in-chat.spec.ts` — boot the chat route, send a
|
|
257
|
+
"create task X" prompt, mock the orchestrator POST to return a fixture
|
|
258
|
+
task, assert a `task-widget` appears, status flips to active when the
|
|
259
|
+
mocked poll returns active, click `task-widget-open` lands on
|
|
260
|
+
`/orchestrator?taskId=…` with that task selected and its inspector
|
|
261
|
+
visible.
|
|
262
|
+
- New `sensitive-request-in-chat.spec.ts` —
|
|
263
|
+
(a) seed a secret request, fill the password, submit, assert
|
|
264
|
+
`client.updateSecrets` was called with that field, assert the password
|
|
265
|
+
is **never** posted to any chat-message endpoint;
|
|
266
|
+
(b) seed an OAuth request, click Connect, mock popup `postMessage`
|
|
267
|
+
completion, assert status flips to Saved without any token appearing in
|
|
268
|
+
the chat-message stream.
|
|
269
|
+
|
|
270
|
+
4. **Scenario runner (`packages/scenario-runner`):** add a `task-creation`
|
|
271
|
+
scenario that drives the e2e create → widget → click → workbench path
|
|
272
|
+
against the real orchestrator routes, using the fake-ACP transport already
|
|
273
|
+
used by the orchestrator unit tests. Gated under `test:e2e:manual` because
|
|
274
|
+
it needs the ACP transport pinned, matching the existing convention.
|
|
275
|
+
|
|
276
|
+
## Out of scope (explicitly)
|
|
277
|
+
|
|
278
|
+
- Replacing the 5s poll with SSE/WS — that's
|
|
279
|
+
[`orchestrator-buildout-followups.md`](./orchestrator-buildout-followups.md)
|
|
280
|
+
section D and design-touching.
|
|
281
|
+
- A general "remote/mobile orchestrator" — same followups section D.
|
|
282
|
+
- Re-anchoring planner follow-ups to durable goal — section F.
|
|
283
|
+
- Real production OAuth providers beyond the widget — see followups B.
|
|
284
|
+
|
|
285
|
+
## Rollout
|
|
286
|
+
|
|
287
|
+
One PR per slice keeps blast radius small and lets the visual review run on
|
|
288
|
+
each:
|
|
289
|
+
|
|
290
|
+
1. Slice 1: `OrchestratorGlanceStrip` + counts derivation + tests.
|
|
291
|
+
2. Slice 2: `task-widget` segment + `TaskWidget` component +
|
|
292
|
+
`TASKS_CREATE` emission + unit tests.
|
|
293
|
+
3. Slice 3: `task-widget-in-chat.spec.ts`.
|
|
294
|
+
4. Slice 4: Sensitive-request polish + OAuth widget + adapter +
|
|
295
|
+
`sensitive-request-in-chat.spec.ts`.
|
|
296
|
+
5. Slice 5: View-dependent inspector cleanup (hide Edit group on terminal,
|
|
297
|
+
hide priority on terminal) + inspector test.
|
|
298
|
+
|
|
299
|
+
Each slice ships and gets an audit pass. No slice is "done" until the
|
|
300
|
+
relevant Playwright spec is green locally and the chat / `/orchestrator`
|
|
301
|
+
route renders cleanly under the workbench audit pass.
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# Orchestrator View Research Report
|
|
2
|
+
|
|
3
|
+
Date: 2026-05-30
|
|
4
|
+
|
|
5
|
+
## High-Level Goal
|
|
6
|
+
|
|
7
|
+
Build an `/orchestrator` experience for ElizaOS that treats work as durable tasks, not disposable chats. The main orchestrator room should remain open indefinitely, create and fork task rooms from natural language or explicit UI controls, provision Claude/Codex/OpenCode/Eliza sub-agents using persistent `/goal`-style prompts, and never present a task as done until acceptance criteria, verification, and final handoff are complete. The UI must expose task status, room messages, sub-agent activity, model/provider/subscription selection, token spend, pause/resume/archive/delete controls, secure and local-insecure secret collection, voice/chat-controllable view actions, searchable paginated history, remote/mobile access, and route/action-specific automated plus screenshot/manual verification.
|
|
8
|
+
|
|
9
|
+
## Current Status And Remaining Work
|
|
10
|
+
|
|
11
|
+
This report started as a research snapshot. The current branch now has a first durable `/api/orchestrator/*` task surface, `/orchestrator` plugin view registration, task-thread client methods backed by real routes, mandatory goal wrappers for direct coding-agent spawn/send paths, usage aggregation from ACP result usage, and dispatcher-level credential bridge wiring. Treat older unsupported-feature statements below as historical context when they conflict with this section.
|
|
12
|
+
|
|
13
|
+
Remaining work:
|
|
14
|
+
|
|
15
|
+
- Replace caller-supplied validation with registered verification hooks that collect durable evidence before `done`.
|
|
16
|
+
- Add end-to-end coverage for every declared orchestrator view capability, TUI endpoint, and task lifecycle mutation.
|
|
17
|
+
- Add screenshot/manual review for the orchestrator UI and any shared cloud frontend changes before declaring UI work complete.
|
|
18
|
+
- Finish provider/subscription settings cleanup and internationalize every new orchestrator string.
|
|
19
|
+
- Prove remote/mobile access against a local desktop agent and against cloud-connected agents.
|
|
20
|
+
|
|
21
|
+
## Executive Findings
|
|
22
|
+
|
|
23
|
+
The repository already has three partial layers that should be joined rather than rebuilt from scratch:
|
|
24
|
+
|
|
25
|
+
- `plugins/plugin-agent-orchestrator` owns ACP subprocess sessions, agent selection, routing, workspace lifecycle, sub-agent progress, and task actions.
|
|
26
|
+
- `plugins/plugin-task-coordinator` owns a plugin view bundle at `/task-coordinator` plus task/session panels, but it is currently wired to mostly stubbed task-thread client methods.
|
|
27
|
+
- `packages/ui` owns the app shell, dynamic plugin views, built-in `/tasks` page, chat sidebar widgets, task-coordinator slots, route resolution, i18n, and local smoke coverage.
|
|
28
|
+
|
|
29
|
+
The main blocker is that the desired product model is "task thread with room, messages, sub-agents, goal, telemetry, and lifecycle", while the implemented backend model exposed to UI is mostly "ACP session list". Typed task-thread shapes exist in `packages/ui/src/api/client-types-cloud.ts`, and `CodingAgentTasksPanel` already expects thread APIs, but `ElizaClient` returns empty/null for task-thread list/detail/archive/reopen. The `/api/coding-agents/metrics` route returns `{}`, and no route currently exposes per-agent token usage.
|
|
30
|
+
|
|
31
|
+
## Current Backend State
|
|
32
|
+
|
|
33
|
+
`plugin-agent-orchestrator` registers raw HTTP routes for coding agents, workspace, and issues, but not task-thread coordinator APIs. The route table includes `/api/coding-agents`, `/api/coding-agents/spawn`, `/api/coding-agents/metrics`, per-agent send/stop/output, parent-context/memory/active-workspaces, workspace, and issue routes in `plugins/plugin-agent-orchestrator/src/setup-routes.ts:81`.
|
|
34
|
+
|
|
35
|
+
The active session routes can list sessions, spawn sessions, send input, stop sessions, and read output. Relevant gaps:
|
|
36
|
+
|
|
37
|
+
- `/api/coding-agents/metrics` currently returns `{}` in `plugins/plugin-agent-orchestrator/src/api/agent-routes.ts:274`.
|
|
38
|
+
- `/api/coding-agents/workspace-files` returns an empty file list in `plugins/plugin-agent-orchestrator/src/api/agent-routes.ts:337`.
|
|
39
|
+
- `/api/coding-agents/settings` does expose preferred framework, configured subscription provider, and framework availability in `plugins/plugin-agent-orchestrator/src/api/agent-routes.ts:391`.
|
|
40
|
+
- `/api/coding-agents` lists raw ACP sessions from `ctx.acpService.listSessions()` in `plugins/plugin-agent-orchestrator/src/api/agent-routes.ts:441`.
|
|
41
|
+
- `/api/coding-agents/spawn` passes `initialTask: taskText` directly in `plugins/plugin-agent-orchestrator/src/api/agent-routes.ts:553`; it does not enforce a goal wrapper on direct API spawns.
|
|
42
|
+
- `/api/coding-agents/:id/send` passes user input directly to `sendToSession` in `plugins/plugin-agent-orchestrator/src/api/agent-routes.ts:610`; it does not enforce a goal wrapper on direct sends.
|
|
43
|
+
- Credential bridge routes exist, but the main dispatcher does not import or call `handleBridgeRoutes`; the bridge module itself still says to hook it from `routes.ts` in `plugins/plugin-agent-orchestrator/src/api/bridge-routes.ts:230`. This blocks secure credential retrieval from the current route surface.
|
|
44
|
+
|
|
45
|
+
The action path is richer. `TASKS_SPAWN_AGENT` constructs task-room/worktree-room metadata, route hints, initial task metadata, and swarming instructions. It tells agents to keep working until finished or blocked in `plugins/plugin-agent-orchestrator/src/actions/tasks.ts:375`, spawns with `initialTask: taskWithRouteHints` in `plugins/plugin-agent-orchestrator/src/actions/tasks.ts:723`, and records session metadata including task room, worktree route, label, source, and `initialTask` in `plugins/plugin-agent-orchestrator/src/actions/tasks.ts:729`. However, it intentionally returns `continueChain: false` immediately after spawn in `plugins/plugin-agent-orchestrator/src/actions/tasks.ts:762` so the parent turn ends while the sub-agent works asynchronously. That is the opposite of the requested "orchestrator does not return until goal completion" behavior unless the new task/goal runner adds a durable task status contract outside the single chat turn.
|
|
46
|
+
|
|
47
|
+
`TASKS_SEND_TO_AGENT` also sends direct follow-up text unless it is reacting to a routed incomplete completion, where it builds a stronger "continue original task" follow-up in `plugins/plugin-agent-orchestrator/src/actions/tasks.ts:856`. This should become a mandatory `/goal` envelope for Claude/Codex/OpenCode/Eliza prompts, not a best-effort retry phrase.
|
|
48
|
+
|
|
49
|
+
## Current UI State
|
|
50
|
+
|
|
51
|
+
`plugin-task-coordinator` already declares a GUI view at `/task-coordinator`, an XR view at `/task-coordinator`, and a TUI view at `/task-coordinator/tui` in `plugins/plugin-task-coordinator/src/index.ts:6`. The GUI exports `CodingAgentTasksPanel`; the TUI exposes capabilities for listing sessions, listing task threads, opening a thread, stopping a session, and refreshing.
|
|
52
|
+
|
|
53
|
+
`packages/ui` can route dynamic plugin views by matching `ViewRegistryEntry.path` and loading their `bundleUrl` through `DynamicViewLoader` in `packages/ui/src/App.tsx:451`. Built-in static views include `tasks`, which renders `TasksPageView` in `packages/ui/src/App.tsx:542`. The navigation type and path map include `tasks`, but not `orchestrator`, in `packages/ui/src/navigation/index.ts:44` and `packages/ui/src/navigation/index.ts:318`.
|
|
54
|
+
|
|
55
|
+
`packages/ui/src/slots/task-coordinator-slots.tsx` deliberately keeps app-core from importing the plugin directly and instead lets plugins register task-coordinator components into slots. This is the right pattern to preserve if `/orchestrator` remains a frontend plugin view, but it also means `plugin-agent-orchestrator` cannot simply add a React file without introducing a browser build and a view-registration story.
|
|
56
|
+
|
|
57
|
+
The current task panel is a useful seed, but not enough for the requested view. `CodingAgentTasksPanel` polls `client.listCodingAgentTaskThreads` every 5 seconds in `plugins/plugin-task-coordinator/src/CodingAgentTasksPanel.tsx:680`, loads selected thread details, and has archive/reopen handlers in `plugins/plugin-task-coordinator/src/CodingAgentTasksPanel.tsx:802`. The client methods behind those calls currently return empty/null/false in `packages/ui/src/api/client-agent.ts:3403`, so local task rooms and history are not truly available.
|
|
58
|
+
|
|
59
|
+
Chat sidebar widgets are registered for app runs and activity under `agent-orchestrator` in `packages/ui/src/widgets/registry.ts:67`, but they are not the requested full-room orchestration surface.
|
|
60
|
+
|
|
61
|
+
There is no first-class `/orchestrator` route in desktop or cloud today. Desktop has a built-in `tasks` tab and `/apps/tasks` surface, while `plugin-task-coordinator` registers `/task-coordinator`. Cloud is further behind for this specific feature: inline cloud agent chat is intentionally not wired yet, and public cloud chat is character-room text streaming rather than orchestrator/task-room state.
|
|
62
|
+
|
|
63
|
+
Slash-chat support is also not built in for this product yet. Existing slash behavior is tied to saved/custom action expansion, not built-in `/orchestrator`, `/task`, `/spawn`, or `/tasks` commands. The first version should decide whether slash commands call the orchestrator API directly or translate into planner-visible task requests.
|
|
64
|
+
|
|
65
|
+
## Data Model Required
|
|
66
|
+
|
|
67
|
+
Add a durable orchestrator task model owned by `plugin-agent-orchestrator`:
|
|
68
|
+
|
|
69
|
+
- `orchestrator_tasks`: id, title, goal, status, priority, owner, worldId, mainRoomId, taskRoomId, archive/delete flags, created/updated/closed timestamps, acceptance criteria, current plan, parent/fork source, provider policy, pause state.
|
|
70
|
+
- `orchestrator_task_sessions`: taskId, sessionId, agentType, providerSource, model, goalPrompt, workdir, status, active tool, lastActivityAt, spawnedAt, stoppedAt, completionSummary, retry count, token totals.
|
|
71
|
+
- `orchestrator_task_events`: taskId, sessionId, eventType, summary, data, timestamp.
|
|
72
|
+
- `orchestrator_task_messages`: taskId, roomId, messageId, sender kind, content refs, searchable text, timestamp. Prefer referencing existing runtime memories where possible instead of duplicating message bodies.
|
|
73
|
+
- `orchestrator_task_usage`: taskId, sessionId, provider, model, input/output/reasoning/cache tokens, cost estimate, source event id, timestamp.
|
|
74
|
+
- `orchestrator_task_artifacts`: taskId, sessionId, path/URI, artifact type, title, verification status.
|
|
75
|
+
- `orchestrator_task_decisions`: taskId, decision type, action selected, prompt excerpt, reasoning summary, timestamp.
|
|
76
|
+
|
|
77
|
+
The existing UI thread types in `packages/ui/src/api/client-types-cloud.ts:987` are close, but they need room/message fields, token usage, provider/model usage, pause state, and task fork lineage. The existing `CodingAgentTaskThreadDetail` already includes sessions, decisions, events, artifacts, transcripts, and pending decisions in `packages/ui/src/api/client-types-cloud.ts:1104`; extend this instead of inventing an incompatible parallel shape.
|
|
78
|
+
|
|
79
|
+
Usage capture needs backend work. ACP usage events are currently treated as informational and not surfaced in `plugins/plugin-agent-orchestrator/src/services/acp-service.ts:1639`, so token/cost UI cannot be accurate until those events are persisted and aggregated.
|
|
80
|
+
|
|
81
|
+
## Prompt And Goal Semantics
|
|
82
|
+
|
|
83
|
+
The requested behavior should be implemented as a task runner contract, not by expecting one HTTP response or one chat turn to remain open forever. The orchestrator should create a durable goal record, spawn agents with a mandatory goal wrapper, and continue dispatching, verifying, retrying, pausing, or escalating until the goal status is terminal.
|
|
84
|
+
|
|
85
|
+
Required prompt policy:
|
|
86
|
+
|
|
87
|
+
- Every `spawnSession` initial task for Claude, Codex, OpenCode, ElizaOS, and Pi Agent must pass through a single `buildGoalPrompt(...)` function.
|
|
88
|
+
- Every `sendToSession` follow-up from direct API, UI, or planner action must pass through `buildGoalFollowUp(...)`.
|
|
89
|
+
- The wrapper must include: goal, acceptance criteria, room IDs, workdir, allowed capabilities, "do not finish until complete or genuinely blocked", "verify before final", "report token/tool status when available", and "return structured completion fields".
|
|
90
|
+
- Direct API spawns in `agent-routes.ts` must get the same wrapper as `TASKS_SPAWN_AGENT`; currently they bypass route hints and goal semantics.
|
|
91
|
+
- Direct API sends in `agent-routes.ts` must get the same wrapper as `TASKS_SEND_TO_AGENT`; currently they pass raw input.
|
|
92
|
+
- When a sub-agent claims completion, the router should transition task state to `validating`, run verification hooks, and only mark `done` after proof passes.
|
|
93
|
+
- The durable task runner should keep a structured objective, blocked reason, retry/resume budget, validation state, and completion summary. Today goal persistence is prompt text plus ACP session metadata, not a true `/goal` record.
|
|
94
|
+
|
|
95
|
+
The parent orchestrator should not "return done" while a task remains active. In UI terms, this means the chat can acknowledge "task created and running", but task status remains active until validation completes. In agent terms, any final answer about the task must be gated on the durable task state, not just the sub-agent's `task_complete` event.
|
|
96
|
+
|
|
97
|
+
## API Surface Needed
|
|
98
|
+
|
|
99
|
+
Add coordinator routes under `/api/coding-agents/coordinator/*` or alias them to `/api/orchestrator/*`:
|
|
100
|
+
|
|
101
|
+
- `GET /api/orchestrator/status`: aggregate active tasks, sessions, provider usage, token spend, paused state.
|
|
102
|
+
- `GET /api/orchestrator/tasks?cursor=&status=&search=&includeArchived=`
|
|
103
|
+
- `POST /api/orchestrator/tasks`: create task from structured form or inferred chat action.
|
|
104
|
+
- `GET /api/orchestrator/tasks/:taskId`
|
|
105
|
+
- `PATCH /api/orchestrator/tasks/:taskId`: update title, goal, acceptance criteria, priority.
|
|
106
|
+
- `POST /api/orchestrator/tasks/:taskId/pause`
|
|
107
|
+
- `POST /api/orchestrator/tasks/:taskId/resume`
|
|
108
|
+
- `POST /api/orchestrator/tasks/:taskId/archive`
|
|
109
|
+
- `DELETE /api/orchestrator/tasks/:taskId`
|
|
110
|
+
- `POST /api/orchestrator/tasks/:taskId/fork`
|
|
111
|
+
- `POST /api/orchestrator/tasks/:taskId/messages`: user joins a task room.
|
|
112
|
+
- `GET /api/orchestrator/tasks/:taskId/messages?cursor=&limit=`
|
|
113
|
+
- `GET /api/orchestrator/tasks/:taskId/events?cursor=&limit=`
|
|
114
|
+
- `GET /api/orchestrator/tasks/:taskId/usage`
|
|
115
|
+
- `POST /api/orchestrator/tasks/:taskId/agents`: add sub-agent.
|
|
116
|
+
- `POST /api/orchestrator/tasks/:taskId/agents/:sessionId/stop`
|
|
117
|
+
- `POST /api/orchestrator/pause-all`
|
|
118
|
+
- `POST /api/orchestrator/resume-all`
|
|
119
|
+
|
|
120
|
+
Keep compatibility by mapping `client.listCodingAgentTaskThreads`, `getCodingAgentTaskThread`, `archiveCodingAgentTaskThread`, and `reopenCodingAgentTaskThread` to these real routes instead of returning stubs.
|
|
121
|
+
|
|
122
|
+
Also register and dispatch credential bridge routes if they are part of provider setup or sub-agent secret retrieval. Leaving `bridge-routes.ts` present but unmounted creates a false sense of security coverage.
|
|
123
|
+
|
|
124
|
+
Normalize the coding-agent preflight contract at the same time. Current frontend code paths expect an object with `installed`/`available` style fields, while the backend preflight route returns an array of preflight rows. This can make the code button and task affordances appear unreliably.
|
|
125
|
+
|
|
126
|
+
## Route And View Registration Recommendation
|
|
127
|
+
|
|
128
|
+
Use `/orchestrator` as the primary product route.
|
|
129
|
+
|
|
130
|
+
Preferred implementation path:
|
|
131
|
+
|
|
132
|
+
1. Rename or duplicate `plugin-task-coordinator` view registration so GUI path `/orchestrator` loads the new orchestrator component, with `/task-coordinator` retained as a compatibility alias.
|
|
133
|
+
2. Keep `plugin-agent-orchestrator` as the backend owner and add all durable task/coordinator routes there.
|
|
134
|
+
3. Keep `packages/ui` slots for shared app-shell embedding, but move the full orchestrator product UI into the plugin view bundle to avoid hardcoding a large new static page in `packages/ui`.
|
|
135
|
+
4. Add `orchestrator` to the UI navigation type/path map only if it needs a first-class built-in tab. If it is a plugin view with `desktopTabEnabled`, dynamic view routing can load it by path without adding a built-in tab.
|
|
136
|
+
|
|
137
|
+
This preserves the existing package boundary: Node orchestration backend in `plugin-agent-orchestrator`, React view bundle in a browser-capable plugin package, and generic shell/view infrastructure in `packages/ui`.
|
|
138
|
+
|
|
139
|
+
Do not start with cloud `/orchestrator` as the primary implementation path. Build the desktop/local route and backend task contract first, then bridge the same API shape into cloud once cloud-side agent chat/task containers expose durable task-room state.
|
|
140
|
+
|
|
141
|
+
## UX Requirements
|
|
142
|
+
|
|
143
|
+
The `/orchestrator` screen should be an operational workbench:
|
|
144
|
+
|
|
145
|
+
- Left rail: ongoing tasks with status, priority, latest activity, active sub-agent count, token spend, provider icons, pause/archive affordances, search, filters, archived toggle, and plus button.
|
|
146
|
+
- Center: selected room timeline with user, orchestrator, and sub-agent messages; system events collapsed by default; paginated search and jump-to-time.
|
|
147
|
+
- Right rail or inspector: sub-agent roster, current tool/activity, workdir/repo, active branch, artifacts, verification checklist, acceptance criteria, token/cost breakdown, provider/subscription state.
|
|
148
|
+
- Composer: sends to selected room, can also create/fork/update tasks via chat intent.
|
|
149
|
+
- Task creation: plus button opens a compact structured form, but any field can be inferred from chat.
|
|
150
|
+
- Controls: pause task, pause all agents, resume, archive, delete, fork, add agent, stop agent, change provider/model, copy/share task link.
|
|
151
|
+
- Voice/chat actions: every clickable action must have a view capability and natural-language route so "pause this task", "fork it", "show Codex only", or "add Claude to this room" works while the view is open.
|
|
152
|
+
- Settings: provider/subscription management must show Eliza Cloud, local Eliza, Claude, Codex/OpenAI, OpenCode, and any configured cloud routes; copy must be fully internationalized and avoid leaking tokens.
|
|
153
|
+
|
|
154
|
+
Avoid a marketing layout. This is an operator console: dense, stable, quiet, readable, and optimized for scanning.
|
|
155
|
+
|
|
156
|
+
## Secret And OAuth Flow
|
|
157
|
+
|
|
158
|
+
The codebase already has sensitive request infrastructure for secure inline owner-app secret requests and local route submission. `owner-app-inline-adapter` builds owner-only secret forms, and `sensitive-request-routes.ts` supports create/get/submit/cancel flows. Extend this for orchestrator provider setup:
|
|
159
|
+
|
|
160
|
+
- Secure cloud path: OAuth and API secrets stored in Eliza Cloud or scoped cloud vault, never pasted into public chat.
|
|
161
|
+
- Secure local path: local vault/secret manager when available.
|
|
162
|
+
- Insecure local fallback: explicit "stored locally/insecure" mode for fully local use where cloud is unavailable.
|
|
163
|
+
- Form inference: chat can start an OAuth/secret request, the form opens prefilled with inferred provider/scope, and user can submit in UI.
|
|
164
|
+
- Audit: every secret request emits redacted audit events.
|
|
165
|
+
- Tests: verify redaction, route auth, submission, cancellation, cloud unavailable fallback, and no accidental secret echo in messages/events/transcripts.
|
|
166
|
+
|
|
167
|
+
## Remote And Mobile Access
|
|
168
|
+
|
|
169
|
+
The requested "phone as remote to desktop agent" mode needs explicit scope:
|
|
170
|
+
|
|
171
|
+
- Local desktop runtime exposes a remote pairing/tunnel endpoint with auth and revocation.
|
|
172
|
+
- Mobile connects as a remote client to the desktop agent, not as a separate agent owner.
|
|
173
|
+
- Cloud mode connects all clients to the cloud-hosted state.
|
|
174
|
+
- The orchestrator task state must sync through the same API shape in both local-remote and cloud modes.
|
|
175
|
+
- Long-running task updates should use websocket/SSE where available, with polling fallback matching current 5-second polling.
|
|
176
|
+
|
|
177
|
+
## Test And Verification Plan
|
|
178
|
+
|
|
179
|
+
Backend unit coverage:
|
|
180
|
+
|
|
181
|
+
- Route registration includes every new `/api/orchestrator/*` and coordinator compatibility route.
|
|
182
|
+
- Direct HTTP handler tests for `/api/coding-agents` list/spawn/get/send/stop/output, including missing service, invalid body, spawn workdir rejection, concurrency limit, and output fallback.
|
|
183
|
+
- Task create/list/detail/search/pagination/archive/delete/fork/pause/resume.
|
|
184
|
+
- Session spawn and send always call goal-wrapper builders.
|
|
185
|
+
- Direct API spawn/send and planner action spawn/send produce equivalent goal envelopes.
|
|
186
|
+
- Sub-agent completion does not mark done until validation passes.
|
|
187
|
+
- Token usage aggregation handles missing provider usage, partial usage, duplicate events, and multiple providers.
|
|
188
|
+
- Credential bridge routes are mounted, authorized, redacted, and unavailable in modes that should not expose them.
|
|
189
|
+
- Store fallback works for SQL, file, and memory session stores.
|
|
190
|
+
- Access policy rejects unauthorized remote/mobile clients.
|
|
191
|
+
|
|
192
|
+
UI component coverage:
|
|
193
|
+
|
|
194
|
+
- Empty state, loading state, error state, active task, blocked task, validating task, done task, archived task.
|
|
195
|
+
- Search, pagination, task selection, task creation form, plus button, fork, pause, pause all, resume, archive, delete confirmation, add sub-agent, stop sub-agent.
|
|
196
|
+
- Token/cost visualizations with zero/unknown/large values.
|
|
197
|
+
- Provider settings and i18n keys for all visible strings.
|
|
198
|
+
- Voice/chat capability calls for every action.
|
|
199
|
+
- Preflight response normalization so provider/setup affordances render consistently.
|
|
200
|
+
- `mapAcpSessionsToCodingAgentSessions`, `getCodingAgentStatus`, `stopCodingAgent`, scratch workspace actions, and PTY subscribe/send/resize/buffer client helpers.
|
|
201
|
+
|
|
202
|
+
End-to-end coverage:
|
|
203
|
+
|
|
204
|
+
- Create task by plus button.
|
|
205
|
+
- Create task by chat message.
|
|
206
|
+
- Fork task from chat.
|
|
207
|
+
- Add Claude/Codex/OpenCode/Eliza sub-agent where available, with mocked providers in CI.
|
|
208
|
+
- Pause one task stops/suspends all attached agents.
|
|
209
|
+
- Pause all affects all running tasks.
|
|
210
|
+
- Archive/delete removes from active list and preserves/cleans history according to mode.
|
|
211
|
+
- Search and paginate main orchestrator room history and task room history.
|
|
212
|
+
- Secret request: secure cloud, secure local, insecure local fallback.
|
|
213
|
+
- Remote phone connects to desktop agent and controls an active task.
|
|
214
|
+
- Cloud client and desktop client see the same task state.
|
|
215
|
+
- Slash commands `/task`, `/tasks`, `/spawn`, and `/stop` route to the intended task APIs or planner requests with destructive-action confirmation.
|
|
216
|
+
- Validation failure triggers retry/reopen, not `done`.
|
|
217
|
+
- Token spend updates per sub-agent and aggregate.
|
|
218
|
+
- Terminal/output management: buffered output loads, live `pty-output` appends, interrupt sends Ctrl-C, terminal input sends a line, and stop posts to the session stop endpoint.
|
|
219
|
+
- Failure handling: `/api/coding-agents` 503, thread list failure, detail failure, output fetch failure, and stop failure all render actionable UI without swallowing the error silently.
|
|
220
|
+
|
|
221
|
+
Existing coverage to extend:
|
|
222
|
+
|
|
223
|
+
- `plugins/plugin-agent-orchestrator/__tests__/unit/register-routes.test.ts` verifies route loader registration.
|
|
224
|
+
- `plugins/plugin-agent-orchestrator/__tests__/unit/sub-agent-router.test.ts` verifies task-complete synthetic memory routing.
|
|
225
|
+
- `packages/app/test/ui-smoke/plugin-views-visual.spec.ts:76` already includes `/task-coordinator`.
|
|
226
|
+
- `packages/app/test/ui-smoke/all-pages-clicksafe.spec.ts:477` stubs coding-agent preflight/status routes.
|
|
227
|
+
- `packages/cloud-frontend/AGENTS.md` requires `bun run --cwd packages/cloud-frontend audit:cloud` plus manual review for any `packages/cloud-frontend` UI change.
|
|
228
|
+
|
|
229
|
+
Manual visual review:
|
|
230
|
+
|
|
231
|
+
- For `packages/ui` / plugin view changes, run local app UI smoke and plugin-view visual specs, capture desktop and mobile screenshots of `/orchestrator`, `/orchestrator?archived=1`, task detail, settings/provider setup, and secret request forms.
|
|
232
|
+
- Until an app-wide manual-review protocol exists, require screenshots for `/task-coordinator`, `/task-coordinator/tui`, chat with active sub-agent chip, and terminal drawer/side-panel as compatibility surfaces.
|
|
233
|
+
- If any `packages/cloud-frontend` files are touched, follow the mandatory cloud visual audit loop exactly and leave no affected route at `needs-work` or `broken`.
|
|
234
|
+
- For meaningful redesign, iterate screenshots at least five times, tracking issues fixed per loop.
|
|
235
|
+
|
|
236
|
+
## Highest Risks
|
|
237
|
+
|
|
238
|
+
- Treating ACP sessions as tasks will lose room history, fork lineage, and durable status. A real task store is required.
|
|
239
|
+
- Letting direct API routes bypass goal-wrapper semantics will create inconsistent worker behavior.
|
|
240
|
+
- Marking completion from `task_complete` alone will violate the "certain complete" requirement.
|
|
241
|
+
- Token accounting may not be available uniformly across Claude/Codex/OpenCode/Eliza; the UI must distinguish measured, estimated, and unavailable usage.
|
|
242
|
+
- Existing archive, reopen, and pause action paths report unsupported ACP-only mode, so current UI archive/reopen affordances cannot work until task-thread lifecycle exists.
|
|
243
|
+
- Putting the full UI in `plugin-agent-orchestrator` without a browser build will break current package boundaries.
|
|
244
|
+
- Building cloud UI before cloud task-room APIs exist will produce a decorative shell, not a working orchestrator.
|
|
245
|
+
- Preflight response mismatch can hide or misstate provider availability.
|
|
246
|
+
- Existing Playwright coverage proves plugin-view renderability, not the management workflows; without dedicated mocked workflow specs, regressions in stop, archive, thread detail, terminal output, and error states will slip through.
|
|
247
|
+
- "100% e2e coverage" is aspirational unless scoped to reachable user flows and backed by mocked provider harnesses; live Claude/Codex tests must stay gated.
|
|
248
|
+
- Secrets can leak through transcripts, task messages, or debug logs unless every sensitive request path redacts by default.
|
|
249
|
+
|
|
250
|
+
## Recommended Build Sequence
|
|
251
|
+
|
|
252
|
+
1. Backend task store and routes: create task/thread persistence, expose coordinator APIs, wire compatibility client methods.
|
|
253
|
+
2. Goal wrapper: centralize spawn/send prompt wrapping and enforce it on both action and HTTP routes.
|
|
254
|
+
3. Usage telemetry: capture token/cost events where providers expose them and surface estimated/unavailable states otherwise.
|
|
255
|
+
4. View registration: ship `/orchestrator` plugin view, keep `/task-coordinator` alias.
|
|
256
|
+
5. UI workbench: task rail, room timeline, sub-agent inspector, controls, create/fork flows, i18n.
|
|
257
|
+
6. Chat/voice capabilities: add view actions for every UI control and natural-language task commands.
|
|
258
|
+
7. Secret/OAuth forms: integrate sensitive-request flows into provider setup and task execution blockers.
|
|
259
|
+
8. Remote/mobile: unify cloud/local-remote state APIs and websocket/polling updates.
|
|
260
|
+
9. Tests and visual audits: build the e2e matrix, mocked providers, live gated smokes, screenshot review artifacts, and regression docs.
|
|
261
|
+
|
|
262
|
+
## Acceptance Criteria
|
|
263
|
+
|
|
264
|
+
- `/orchestrator` opens as a first-class view and `/task-coordinator` remains compatible or redirects.
|
|
265
|
+
- A user can create, fork, pause, resume, archive, delete, search, and inspect tasks by UI and chat/voice.
|
|
266
|
+
- Each task has a durable room, message history, event history, sub-agent roster, status, goal, acceptance criteria, artifacts, and usage.
|
|
267
|
+
- Claude/Codex/OpenCode/Eliza workers always receive goal-wrapped prompts and follow-ups.
|
|
268
|
+
- The orchestrator never reports a task as `done` until validation passes or a human explicitly overrides.
|
|
269
|
+
- Provider defaults follow configured subscription readiness: user-owned Claude/OpenAI where available, otherwise Eliza Cloud/local policy.
|
|
270
|
+
- Secure and local-insecure secret setup paths are clear, tested, and redacted.
|
|
271
|
+
- Desktop, mobile remote, and cloud clients observe consistent task state.
|
|
272
|
+
- Every visible string is internationalized.
|
|
273
|
+
- Every button/flow/input/view has automated coverage or a documented impossible-to-automate reason plus manual screenshot review.
|