feat(agent): ACP-Client für strukturierte Agent-Ausgaben in TUI und UI #17

Merged
frank merged 3 commits from agent/issue-14-acp-strukturierte-agent-ausgaben-im-agen into main 2026-07-12 12:22:28 +02:00
Owner

Summary

  • Forge agiert als ACP-Client (JSON-RPC/stdio) für cursor-agent, opencode und Adapter-Pfade für codex/claude/pi
  • Strukturierte session/update-Events (Messages, Tool-Calls, Plans, Thinking) werden im TUI-Agent-Window und im Web-Dashboard (--ui) live angezeigt
  • Auto-Approve für session/request_permission; bei ACP-Startfehler Fallback auf Raw-Subprocess; README mit Plattform-Matrix

Test plan

  • go test ./internal/agent/... (Mock-ACP-Agent, Event-Rendering, UI-Status-API)
  • go test ./... und go vet ./...
  • Manuell: forge agent watch --tui --agent cursor-agent mit ACP-fähigem Agent
  • Manuell: forge agent watch --ui und Live-Output-Panel prüfen

Änderungen im Überblick

Neue Dateien: acp_client.go, acp_events.go, acp_runners.go + Tests

Kernlogik:

  • RunAgent versucht zuerst ACP (initializesession/newsession/prompt), sonst Raw-Modus
  • WatchStatus speichert typisierte RunEvents neben runLog
  • TUI rendert Events formatiert; Web-UI zeigt run_events/run_output im Status-API-Polling
  • Pipeline nutzt ACP-Text für Post-Run-Parsing (PR_TITLE, TODO_DONE:)

Abhängigkeit: github.com/coder/acp-go-sdk@v0.13.5 (vendored)

Commit: 1f9c805 auf Branch agent/issue-14-acp-strukturierte-agent-ausgaben-im-agen

Closes #14

## Summary - Forge agiert als ACP-Client (JSON-RPC/stdio) für `cursor-agent`, `opencode` und Adapter-Pfade für `codex`/`claude`/`pi` - Strukturierte `session/update`-Events (Messages, Tool-Calls, Plans, Thinking) werden im TUI-Agent-Window und im Web-Dashboard (`--ui`) live angezeigt - Auto-Approve für `session/request_permission`; bei ACP-Startfehler Fallback auf Raw-Subprocess; README mit Plattform-Matrix ## Test plan - [x] `go test ./internal/agent/...` (Mock-ACP-Agent, Event-Rendering, UI-Status-API) - [x] `go test ./...` und `go vet ./...` - [ ] Manuell: `forge agent watch --tui --agent cursor-agent` mit ACP-fähigem Agent - [ ] Manuell: `forge agent watch --ui` und Live-Output-Panel prüfen ## Änderungen im Überblick **Neue Dateien:** `acp_client.go`, `acp_events.go`, `acp_runners.go` + Tests **Kernlogik:** - `RunAgent` versucht zuerst ACP (`initialize` → `session/new` → `session/prompt`), sonst Raw-Modus - `WatchStatus` speichert typisierte `RunEvent`s neben `runLog` - TUI rendert Events formatiert; Web-UI zeigt `run_events`/`run_output` im Status-API-Polling - Pipeline nutzt ACP-Text für Post-Run-Parsing (`PR_TITLE`, `TODO_DONE:`) **Abhängigkeit:** `github.com/coder/acp-go-sdk@v0.13.5` (vendored) Commit: `1f9c805` auf Branch `agent/issue-14-acp-strukturierte-agent-ausgaben-im-agen` Closes #14
feat(agent): ACP client for structured agent output in TUI and UI
Some checks failed
CI / test (pull_request) Failing after 11s
CI / race (pull_request) Failing after 14s
1f9c805193
Connect to coding agents via Agent Client Protocol when available (cursor-agent,
opencode, codex/claude/pi adapters) with auto-approve permissions and fallback
to raw subprocess output. Render messages, tool calls, and plans in the watch TUI
and web dashboard; document the platform matrix in README.

Co-authored-by: Cursor <cursoragent@cursor.com>
Author
Owner

🔗 Linked to issue #14. Babysitting CI until green…

🔗 Linked to issue #14. Babysitting CI until green…
Author
Owner

forge agent finished implementation

  • Commit: feat(agent): ACP client for structured agent output in TUI and UI
  • Pull request: #17
  • Next: waiting for CI / babysitting fixes if needed
README.md                                          |   18 +-
 go.mod                                             |    1 +
 go.sum                                             |    2 +
 internal/agent/acp_client.go                       |  345 +
 internal/agent/acp_events.go                       |  186 +
 internal/agent/acp_mock_test.go                    |  145 +
 internal/agent/acp_runners.go                      |   69 +
 internal/agent/acp_test.go                         |   86 +
 internal/agent/pipeline.go                         |   16 +-
 internal/agent/runners.go                          |   23 +-
 internal/agent/status.go                           |   61 +
 internal/agent/tui.go                              |    2 +-
 internal/agent/tui_test.go                         |    5 +
 internal/agent/ui.go                               |   53 +
 internal/agent/ui_test.go                          |   33 +
 internal/cmd/agent.go                              |    2 +-
 vendor/github.com/coder/acp-go-sdk/.gitignore      |   10 +
 vendor/github.com/coder/acp-go-sdk/AGENTS.md       |   30 +
 vendor/github.com/coder/acp-go-sdk/LICENSE         |  201 +
 vendor/github.com/coder/acp-go-sdk/Makefile        |   94 +
 vendor/github.com/coder/acp-go-sdk/README.md       |  148 +
 vendor/github.com/coder/acp-go-sdk/RELEASING.md    |   91 +
 vendor/github.com/coder/acp-go-sdk/agent.go        |   33 +
 vendor/github.com/coder/acp-go-sdk/agent_gen.go    |  520 ++
 vendor/github.com/coder/acp-go-sdk/client.go       |   27 +
 vendor/github.com/coder/acp-go-sdk/client_gen.go   |  311 +
 vendor/github.com/coder/acp-go-sdk/communique.toml |   15 +
 vendor/github.com/coder/acp-go-sdk/connection.go   |  947 ++
 .../github.com/coder/acp-go-sdk/constants_gen.go   |   56 +
 vendor/github.com/coder/acp-go-sdk/doc.go          |    5 +
 vendor/github.com/coder/acp-go-sdk/errors.go       |   82 +
 vendor/github.com/coder/acp-go-sdk/extensions.go   |  103 +
 vendor/github.com/coder/acp-go-sdk/helpers.go      |  259 +
 vendor/github.com/coder/acp-go-sdk/helpers_gen.go  |  151 +
 vendor/github.com/coder/acp-go-sdk/mise.lock       |  261 +
 vendor/github.com/coder/acp-go-sdk/mise.toml       |   31 +
 vendor/github.com/coder/acp-go-sdk/treefmt.toml    |   29 +
 vendor/github.com/coder/acp-go-sdk/types_gen.go    | 9494 ++++++++++++++++++++
 vendor/github.com/coder/acp-go-sdk/version         |    1 +
 vendor/modules.txt                                 |    3 +
 40 files changed, 13941 insertions(+), 8 deletions(-)
Agent output (tail)
PR_TITLE: feat(agent): ACP-Client für strukturierte Agent-Ausgaben in TUI und UI
PR_BODY:
## Summary
- Forge agiert als ACP-Client (JSON-RPC/stdio) für `cursor-agent`, `opencode` und Adapter-Pfade für `codex`/`claude`/`pi`
- Strukturierte `session/update`-Events (Messages, Tool-Calls, Plans, Thinking) werden im TUI-Agent-Window und im Web-Dashboard (`--ui`) live angezeigt
- Auto-Approve für `session/request_permission`; bei ACP-Startfehler Fallback auf Raw-Subprocess; README mit Plattform-Matrix
## Test plan
- [x] `go test ./internal/agent/...` (Mock-ACP-Agent, Event-Rendering, UI-Status-API)
- [x] `go test ./...` und `go vet ./...`
- [ ] Manuell: `forge agent watch --tui --agent cursor-agent` mit ACP-fähigem Agent
- [ ] Manuell: `forge agent watch --ui` und Live-Output-Panel prüfen
## Änderungen im Überblick
**Neue Dateien:** `acp_client.go`, `acp_events.go`, `acp_runners.go` + Tests
**Kernlogik:**
- `RunAgent` versucht zuerst ACP (`initialize` → `session/new` → `session/prompt`), sonst Raw-Modus
- `WatchStatus` speichert typisierte `RunEvent`s neben `runLog`
- TUI rendert Events formatiert; Web-UI zeigt `run_events`/`run_output` im Status-API-Polling
- Pipeline nutzt ACP-Text für Post-Run-Parsing (`PR_TITLE`, `TODO_DONE:`)
**Abhängigkeit:** `github.com/coder/acp-go-sdk@v0.13.5` (vendored)
Commit: `1f9c805` auf Branch `agent/issue-14-acp-strukturierte-agent-ausgaben-im-agen`
✅ **forge agent finished implementation** - Commit: `feat(agent): ACP client for structured agent output in TUI and UI` - Pull request: https://repository.hildebrandt.io/frank/forgecli/pulls/17 - Next: waiting for CI / babysitting fixes if needed ``` README.md | 18 +- go.mod | 1 + go.sum | 2 + internal/agent/acp_client.go | 345 + internal/agent/acp_events.go | 186 + internal/agent/acp_mock_test.go | 145 + internal/agent/acp_runners.go | 69 + internal/agent/acp_test.go | 86 + internal/agent/pipeline.go | 16 +- internal/agent/runners.go | 23 +- internal/agent/status.go | 61 + internal/agent/tui.go | 2 +- internal/agent/tui_test.go | 5 + internal/agent/ui.go | 53 + internal/agent/ui_test.go | 33 + internal/cmd/agent.go | 2 +- vendor/github.com/coder/acp-go-sdk/.gitignore | 10 + vendor/github.com/coder/acp-go-sdk/AGENTS.md | 30 + vendor/github.com/coder/acp-go-sdk/LICENSE | 201 + vendor/github.com/coder/acp-go-sdk/Makefile | 94 + vendor/github.com/coder/acp-go-sdk/README.md | 148 + vendor/github.com/coder/acp-go-sdk/RELEASING.md | 91 + vendor/github.com/coder/acp-go-sdk/agent.go | 33 + vendor/github.com/coder/acp-go-sdk/agent_gen.go | 520 ++ vendor/github.com/coder/acp-go-sdk/client.go | 27 + vendor/github.com/coder/acp-go-sdk/client_gen.go | 311 + vendor/github.com/coder/acp-go-sdk/communique.toml | 15 + vendor/github.com/coder/acp-go-sdk/connection.go | 947 ++ .../github.com/coder/acp-go-sdk/constants_gen.go | 56 + vendor/github.com/coder/acp-go-sdk/doc.go | 5 + vendor/github.com/coder/acp-go-sdk/errors.go | 82 + vendor/github.com/coder/acp-go-sdk/extensions.go | 103 + vendor/github.com/coder/acp-go-sdk/helpers.go | 259 + vendor/github.com/coder/acp-go-sdk/helpers_gen.go | 151 + vendor/github.com/coder/acp-go-sdk/mise.lock | 261 + vendor/github.com/coder/acp-go-sdk/mise.toml | 31 + vendor/github.com/coder/acp-go-sdk/treefmt.toml | 29 + vendor/github.com/coder/acp-go-sdk/types_gen.go | 9494 ++++++++++++++++++++ vendor/github.com/coder/acp-go-sdk/version | 1 + vendor/modules.txt | 3 + 40 files changed, 13941 insertions(+), 8 deletions(-) ``` <details><summary>Agent output (tail)</summary> ``` PR_TITLE: feat(agent): ACP-Client für strukturierte Agent-Ausgaben in TUI und UI PR_BODY: ## Summary - Forge agiert als ACP-Client (JSON-RPC/stdio) für `cursor-agent`, `opencode` und Adapter-Pfade für `codex`/`claude`/`pi` - Strukturierte `session/update`-Events (Messages, Tool-Calls, Plans, Thinking) werden im TUI-Agent-Window und im Web-Dashboard (`--ui`) live angezeigt - Auto-Approve für `session/request_permission`; bei ACP-Startfehler Fallback auf Raw-Subprocess; README mit Plattform-Matrix ## Test plan - [x] `go test ./internal/agent/...` (Mock-ACP-Agent, Event-Rendering, UI-Status-API) - [x] `go test ./...` und `go vet ./...` - [ ] Manuell: `forge agent watch --tui --agent cursor-agent` mit ACP-fähigem Agent - [ ] Manuell: `forge agent watch --ui` und Live-Output-Panel prüfen ## Änderungen im Überblick **Neue Dateien:** `acp_client.go`, `acp_events.go`, `acp_runners.go` + Tests **Kernlogik:** - `RunAgent` versucht zuerst ACP (`initialize` → `session/new` → `session/prompt`), sonst Raw-Modus - `WatchStatus` speichert typisierte `RunEvent`s neben `runLog` - TUI rendert Events formatiert; Web-UI zeigt `run_events`/`run_output` im Status-API-Polling - Pipeline nutzt ACP-Text für Post-Run-Parsing (`PR_TITLE`, `TODO_DONE:`) **Abhängigkeit:** `github.com/coder/acp-go-sdk@v0.13.5` (vendored) Commit: `1f9c805` auf Branch `agent/issue-14-acp-strukturierte-agent-ausgaben-im-agen` ``` </details>
Author
Owner

☑️ ToDos checked off

  • Mindestens cursor-agent und opencode laufen über ACP und zeigen lesbare Events im TUI-Agent-Window.
  • Für codex (und idealerweise claude/pi) existiert ACP-Pfad via Adapter oder klar dokumentierter Fallback auf Raw-Output.
  • --ui zeigt Live-Agent-Output (mindestens Messages + Tool-Calls).
  • Headless-Runs brauchen keine interaktive Permission-UI (Auto-Approve-Policy).
  • Ohne ACP verfügbaren Runner bleibt das bisherige Verhalten erhalten.
  • Wiki/README dokumentieren den Modus und die Plattform-Matrix.
☑️ **ToDos checked off** - [x] Mindestens **cursor-agent** und **opencode** laufen über ACP und zeigen lesbare Events im TUI-Agent-Window. - [x] Für **codex** (und idealerweise **claude**/**pi**) existiert ACP-Pfad via Adapter *oder* klar dokumentierter Fallback auf Raw-Output. - [x] `--ui` zeigt Live-Agent-Output (mindestens Messages + Tool-Calls). - [x] Headless-Runs brauchen keine interaktive Permission-UI (Auto-Approve-Policy). - [x] Ohne ACP verfügbaren Runner bleibt das bisherige Verhalten erhalten. - [x] Wiki/README dokumentieren den Modus und die Plattform-Matrix.
Author
Owner

@agent build fixen und konflikte beheben.

die acp von codex etc müssen nicht integrationsgetestet werden, bleibe bei klaren unittests

@agent build fixen und konflikte beheben. die acp von codex etc müssen nicht integrationsgetestet werden, bleibe bei klaren unittests
Author
Owner

🔴 Watch: CI failed — prioritizing repair…

CI run #76 () finished with failure
URL: https://repository.hildebrandt.io/frank/forgecli/actions/runs/47
🔴 **Watch: CI failed** — prioritizing repair… ``` CI run #76 () finished with failure URL: https://repository.hildebrandt.io/frank/forgecli/actions/runs/47 ```
Author
Owner

⚠️ Merge conflict detected (attempt 1/3)

Re-running coding agent to merge/rebase and resolve conflicts…

⚠️ **Merge conflict detected** (attempt 1/3) Re-running coding agent to merge/rebase and resolve conflicts…
Author
Owner

🛠️ Pushed merge-conflict fix (attempt 1/3). Re-checking mergeability…

Merge-Konflikte für PR #17 sind behoben und als Commit 3de354f gespeichert (nicht gepusht).

Konfliktdateien

  1. internal/agent/status.go — ACP-Felder (runEvents, runACP) aus dem PR-Branch beibehalten.
  2. internal/agent/runners.go — Beide Seiten zusammengeführt:
    • Session-Resume (sessionID, EnsureSessionID) aus main
    • ACP-Pfad mit Fallback auf Raw-Output aus dem PR-Branch
    • Signatur: RunAgent(..., sessionID string, errW io.Writer, status *WatchStatus)
  3. internal/agent/pipeline.go — Agent-Aufrufe über p.runAgent() zentralisiert (Session-Persistenz aus main), mit agentErrW() und Status für TUI/ACP-Logging.

Tests

go test ./internal/agent/... — bestanden.
Der Forge-Agent-Watcher kann pushen und die Mergeability erneut prüfen.

🛠️ Pushed merge-conflict fix (attempt 1/3). Re-checking mergeability… Merge-Konflikte für PR #17 sind behoben und als Commit `3de354f` gespeichert (nicht gepusht). ### Konfliktdateien 1. **`internal/agent/status.go`** — ACP-Felder (`runEvents`, `runACP`) aus dem PR-Branch beibehalten. 2. **`internal/agent/runners.go`** — Beide Seiten zusammengeführt: - Session-Resume (`sessionID`, `EnsureSessionID`) aus `main` - ACP-Pfad mit Fallback auf Raw-Output aus dem PR-Branch - Signatur: `RunAgent(..., sessionID string, errW io.Writer, status *WatchStatus)` 3. **`internal/agent/pipeline.go`** — Agent-Aufrufe über `p.runAgent()` zentralisiert (Session-Persistenz aus `main`), mit `agentErrW()` und `Status` für TUI/ACP-Logging. ### Tests `go test ./internal/agent/...` — bestanden. Der Forge-Agent-Watcher kann pushen und die Mergeability erneut prüfen.
Author
Owner

⚠️ Merge conflict detected (attempt 2/3)

Re-running coding agent to merge/rebase and resolve conflicts…

⚠️ **Merge conflict detected** (attempt 2/3) Re-running coding agent to merge/rebase and resolve conflicts…
Merge origin/main into agent/issue-14 and resolve agent conflicts.
Some checks failed
CI / test (pull_request) Failing after 11s
CI / race (pull_request) Failing after 13s
3de354f6bf
Combine ACP structured output with session resume, PR watch fixes, and
centralize agent runs through Pipeline.runAgent for TUI logging.

Co-authored-by: Cursor <cursoragent@cursor.com>
Author
Owner

🛠️ Pushed merge-conflict fix (attempt 2/3). Re-checking mergeability…

  • Merge-Commit: 3de354fMerge origin/main into agent/issue-14 and resolve agent conflicts.
  • origin/main ist vollständig eingemergt (Already up to date)
  • Test-Merge von PR → main: ohne Konflikte
  • Keine Konfliktmarker in Projektdateien
  • go test ./internal/agent/... war zuvor grün

Auflösung (kurz)

Datei Lösung
status.go ACP-Felder (runEvents, runACP) beibehalten
runners.go Session-Resume + ACP mit Fallback kombiniert
pipeline.go Zentraler Aufruf über p.runAgent() mit TUI-Logging
Der Forge-Agent-Watcher kann pushen (falls noch nicht geschehen) und die Mergeability erneut prüfen — lokal sollte PR #17 mergebar sein.
🛠️ Pushed merge-conflict fix (attempt 2/3). Re-checking mergeability… - Merge-Commit: `3de354f` — *Merge origin/main into agent/issue-14 and resolve agent conflicts.* - `origin/main` ist vollständig eingemergt (`Already up to date`) - Test-Merge von PR → `main`: **ohne Konflikte** - Keine Konfliktmarker in Projektdateien - `go test ./internal/agent/...` war zuvor grün ### Auflösung (kurz) | Datei | Lösung | |---|---| | `status.go` | ACP-Felder (`runEvents`, `runACP`) beibehalten | | `runners.go` | Session-Resume + ACP mit Fallback kombiniert | | `pipeline.go` | Zentraler Aufruf über `p.runAgent()` mit TUI-Logging | Der Forge-Agent-Watcher kann pushen (falls noch nicht geschehen) und die Mergeability erneut prüfen — lokal sollte PR #17 mergebar sein.
Author
Owner

🔴 CI still failing (attempt 3/3)

CI run #76 () finished with failure
URL: https://repository.hildebrandt.io/frank/forgecli/actions/runs/47

Re-running coding agent…

🔴 **CI still failing** (attempt 3/3) ``` CI run #76 () finished with failure URL: https://repository.hildebrandt.io/frank/forgecli/actions/runs/47 ``` Re-running coding agent…
Author
Owner

🛠️ Pushed CI fix (attempt 3/3). Waiting for CI again…

CI-Fehler behoben — Commit 4fe60c5 (nicht gepusht).

Ursache

TestACPCommandForRunner in internal/agent/acp_test.go erwartete, dass cursor-agent, opencode und npx im Host-PATH liegen. Lokal war das der Fall, auf dem Forgejo-CI-Runner nicht — der Test schlug deshalb nach ~11 Sekunden fehl.

Fix

  • Der Test legt Stub-Binaries in ein Temp-Verzeichnis und setzt PATH darauf — reine Unit-Tests ohne echte Agent-CLIs (wie in den PR-Kommentaren gewünscht).
  • github.com/coder/acp-go-sdk in go.mod als direkte Dependency eingetragen (wird direkt importiert).

Verifikation

PATH="$(dirname $(which go)):/usr/bin:/bin" go test ./internal/agent/ -run TestACPCommandForRunner
make ci

Beides grün. Der Forge-Agent-Watcher kann pushen und CI erneut prüfen.

🛠️ Pushed CI fix (attempt 3/3). Waiting for CI again… CI-Fehler behoben — Commit `4fe60c5` (nicht gepusht). ### Ursache `TestACPCommandForRunner` in `internal/agent/acp_test.go` erwartete, dass `cursor-agent`, `opencode` und `npx` im **Host-PATH** liegen. Lokal war das der Fall, auf dem Forgejo-CI-Runner nicht — der Test schlug deshalb nach ~11 Sekunden fehl. ### Fix - Der Test legt Stub-Binaries in ein Temp-Verzeichnis und setzt `PATH` darauf — reine Unit-Tests ohne echte Agent-CLIs (wie in den PR-Kommentaren gewünscht). - `github.com/coder/acp-go-sdk` in `go.mod` als direkte Dependency eingetragen (wird direkt importiert). ### Verifikation ```bash PATH="$(dirname $(which go)):/usr/bin:/bin" go test ./internal/agent/ -run TestACPCommandForRunner make ci ``` Beides grün. Der Forge-Agent-Watcher kann pushen und CI erneut prüfen.
fix(agent): make ACP runner lookup test CI-safe.
All checks were successful
CI / test (pull_request) Successful in 16s
CI / race (pull_request) Successful in 16s
4fe60c558d
Stub PATH in TestACPCommandForRunner so it no longer depends on host
agent binaries, and declare acp-go-sdk as a direct module dependency.

Co-authored-by: Cursor <cursoragent@cursor.com>
frank merged commit 7e7e05f6ce into main 2026-07-12 12:22:28 +02:00
frank deleted branch agent/issue-14-acp-strukturierte-agent-ausgaben-im-agen 2026-07-12 12:22:32 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
frank/forgecli!17
No description provided.