Expanded ACP support
Can now send chain-of-thought messages Manage terminals Control agent working directory Adding more tool support and notifications Some session management Added image support Added slash commands
This commit is contained in:
+233
@@ -0,0 +1,233 @@
|
||||
# Honker ACP Bridge — Implementation Plan
|
||||
|
||||
## Current State
|
||||
|
||||
What's implemented today:
|
||||
- ✅ Initialize ACP connection to Goose (`goose acp` over stdio)
|
||||
- ✅ Create new sessions (one per Signal contact)
|
||||
- ✅ Send text prompts and collect text responses
|
||||
- ✅ Interactive permission requests over Signal (numbered options)
|
||||
- ✅ Signal-cli lifecycle management and socket communication
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Essential — Make the Bridge Robust
|
||||
|
||||
### 1.1 Terminal Execution (Client ← Agent)
|
||||
**Priority: HIGH — Goose cannot function without this**
|
||||
|
||||
Goose's primary tool is running shell commands. The ACP protocol has the agent
|
||||
ask the *client* to execute commands via `create_terminal`, then polls output
|
||||
with `terminal_output` and `wait_for_terminal_exit`.
|
||||
|
||||
Currently we return `None` for all terminal methods, which means Goose can't
|
||||
run any commands. We need to:
|
||||
|
||||
- `create_terminal(command, args, cwd, env)` → spawn a real subprocess, return
|
||||
a `terminal_id`
|
||||
- `terminal_output(terminal_id)` → return accumulated stdout/stderr
|
||||
- `wait_for_terminal_exit(terminal_id)` → await process completion, return exit code
|
||||
- `release_terminal(terminal_id)` → clean up
|
||||
- `kill_terminal(terminal_id)` → kill the subprocess
|
||||
|
||||
Implementation: a `TerminalManager` class that tracks running subprocesses
|
||||
keyed by terminal_id.
|
||||
|
||||
### 1.2 File System Operations (Client ← Agent)
|
||||
**Priority: HIGH — Goose cannot edit code without this**
|
||||
|
||||
The agent asks the client to read/write files:
|
||||
|
||||
- `read_text_file(path, line, limit)` → read from the local filesystem, return content
|
||||
- `write_text_file(path, content)` → write to the local filesystem
|
||||
|
||||
Currently we return `None`, so Goose can't read or write files.
|
||||
These should be straightforward to implement against the local filesystem.
|
||||
|
||||
We should also advertise these capabilities in `ClientCapabilities` during
|
||||
`initialize`:
|
||||
```python
|
||||
ClientCapabilities(
|
||||
fs=FileSystemCapabilities(read_text_file=True, write_text_file=True),
|
||||
terminal=True,
|
||||
)
|
||||
```
|
||||
|
||||
### 1.3 Cancellation
|
||||
**Priority: MEDIUM**
|
||||
|
||||
Allow Signal users to cancel a running prompt. The user could send a special
|
||||
command (e.g. `/cancel`) while a prompt is in progress. We'd call
|
||||
`conn.cancel(session_id)` to tell Goose to stop.
|
||||
|
||||
The `PromptResponse.stop_reason` already distinguishes `cancelled` from
|
||||
`end_turn`, `max_tokens`, `refusal`, and `max_turn_requests` — we should
|
||||
handle each appropriately in the reply.
|
||||
|
||||
### 1.4 Stop Reason Handling
|
||||
**Priority: MEDIUM**
|
||||
|
||||
Currently we only look at the response text. We should handle all stop reasons:
|
||||
- `end_turn` — normal completion (current behavior)
|
||||
- `max_tokens` — context limit hit; notify user
|
||||
- `max_turn_requests` — agent hit its turn limit; notify user
|
||||
- `refusal` — agent refused the request; notify user
|
||||
- `cancelled` — user cancelled; acknowledge
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Enriched Feedback
|
||||
|
||||
### 2.1 Tool Call Notifications
|
||||
**Priority: MEDIUM**
|
||||
|
||||
Forward tool activity as status messages so the Signal user knows what Goose
|
||||
is doing while working. On `ToolCallStart`, send a brief message like:
|
||||
"🔧 Running: `ls -la /src`"
|
||||
|
||||
On `ToolCallProgress` with status updates, optionally send progress. We need
|
||||
to be careful not to spam — batch or throttle these.
|
||||
|
||||
### 2.2 Agent Thoughts
|
||||
**Priority: LOW-MEDIUM**
|
||||
|
||||
`AgentThoughtChunk` contains the agent's chain-of-thought reasoning. Could
|
||||
forward these optionally (config flag) as italicized or prefixed messages.
|
||||
Useful for debugging but noisy for everyday use.
|
||||
|
||||
### 2.3 Plan Updates
|
||||
**Priority: LOW-MEDIUM**
|
||||
|
||||
`AgentPlanUpdate` sends a structured plan with entries (content, priority,
|
||||
status). Could render as a checklist:
|
||||
```
|
||||
📋 Plan:
|
||||
✅ Read the project structure
|
||||
🔄 Implement the new feature
|
||||
⬚ Write tests
|
||||
⬚ Update documentation
|
||||
```
|
||||
|
||||
### 2.4 Usage/Cost Updates
|
||||
**Priority: LOW**
|
||||
|
||||
`UsageUpdate` reports token usage (size, used) and optional `Cost` (amount,
|
||||
currency). Could send periodic summaries or on-demand via a `/usage` command.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Session Management
|
||||
|
||||
### 3.1 Session Persistence (Load/Resume)
|
||||
**Priority: MEDIUM**
|
||||
|
||||
Goose supports `load_session` and `resume_session`. We could persist the
|
||||
session_id→contact mapping in SQLite (as the README mentions) and restore
|
||||
sessions across honker restarts.
|
||||
|
||||
- `load_session(cwd, session_id)` — restore conversation history
|
||||
- `resume_session(cwd, session_id)` — resume an interrupted session
|
||||
- `list_sessions()` — list available sessions
|
||||
- `close_session(session_id)` — explicitly end a session
|
||||
|
||||
User commands: `/sessions`, `/load <id>`, `/new` (force new session)
|
||||
|
||||
### 3.2 Session Commands
|
||||
**Priority: MEDIUM**
|
||||
|
||||
Signal user sends special commands (prefix with `/`):
|
||||
- `/new` — start a fresh session
|
||||
- `/sessions` — list previous sessions
|
||||
- `/load <id>` — resume a previous session
|
||||
- `/cancel` — cancel current prompt
|
||||
- `/mode <mode>` — change session mode (via `set_session_mode`)
|
||||
- `/model <model>` — change model (via `set_session_model`)
|
||||
- `/usage` — show token usage / cost
|
||||
|
||||
### 3.3 Session Modes
|
||||
**Priority: LOW**
|
||||
|
||||
Goose supports modes (e.g., "auto" vs "manual" approval). `set_session_mode`
|
||||
and `CurrentModeUpdate` notifications. Could expose via `/mode` command.
|
||||
|
||||
### 3.4 Session Configuration
|
||||
**Priority: LOW**
|
||||
|
||||
`set_config_option` lets the client change boolean/select config options.
|
||||
`ConfigOptionUpdate` notifications report changes. Could expose via a
|
||||
`/config` command.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Rich Content
|
||||
|
||||
### 4.1 Image Support (Input)
|
||||
**Priority: MEDIUM**
|
||||
|
||||
Signal users can send images. signal-cli provides attachment data. ACP
|
||||
supports `ImageContentBlock` in prompts (with base64 `data` and `mime_type`).
|
||||
We could forward Signal image attachments to Goose as image content blocks.
|
||||
|
||||
### 4.2 Image Support (Output)
|
||||
**Priority: LOW**
|
||||
|
||||
If Goose responds with `ImageContentBlock` in agent messages, we could send
|
||||
them as Signal attachments. Less common but possible.
|
||||
|
||||
### 4.3 File/Resource Content
|
||||
**Priority: LOW**
|
||||
|
||||
`ResourceContentBlock` and `EmbeddedResourceContentBlock` in agent messages.
|
||||
Could send file contents as Signal attachments or inline code blocks.
|
||||
|
||||
### 4.4 Audio Support
|
||||
**Priority: LOW**
|
||||
|
||||
ACP has `AudioContentBlock`. Signal supports voice messages. Theoretically
|
||||
bridgeable but Goose doesn't currently use audio.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Advanced / Optional
|
||||
|
||||
### 5.1 Multi-User Concurrency
|
||||
**Priority: MEDIUM**
|
||||
|
||||
Currently each contact gets their own session, and prompts run as async tasks.
|
||||
But there's no protection against a user sending a second message while the
|
||||
first is still processing. Options:
|
||||
- Queue messages per-user (process sequentially)
|
||||
- Allow concurrent prompts (may confuse Goose session state)
|
||||
- Tell the user "please wait" if a prompt is in progress
|
||||
|
||||
### 5.2 Group Messaging
|
||||
**Priority: LOW**
|
||||
|
||||
Signal groups could map to shared Goose sessions. Would need the account
|
||||
number (already in config) for group message handling. signal-cli has
|
||||
different envelope structure for group messages.
|
||||
|
||||
### 5.3 Extension Methods
|
||||
**Priority: LOW**
|
||||
|
||||
`ext_method` and `ext_notification` are catch-alls for custom protocol
|
||||
extensions. Log them for now; implement specific ones if Goose uses them.
|
||||
|
||||
### 5.4 MCP Server Configuration
|
||||
**Priority: LOW**
|
||||
|
||||
`new_session` accepts `mcp_servers` to connect external tool servers. Could
|
||||
be configured per-contact or globally in honker config.
|
||||
|
||||
---
|
||||
|
||||
## Decisions Made
|
||||
|
||||
1. **Terminal execution**: Permission gate is enough. No additional sandboxing.
|
||||
2. **Tool call notifications**: Light — send "🔧 Running: ..." on tool start.
|
||||
Goose already keeps extensive logs at `~/.local/state/goose/logs/`.
|
||||
3. **Agent thoughts**: Opt-in via config flag (`forward_thoughts: true`).
|
||||
4. **Cancellation UX**: `/cancel` plus general `/command` prefix convention.
|
||||
5. **Multi-user concurrency**: "Please wait" — reject concurrent prompts per user.
|
||||
6. **Image attachments**: Yes, wire up in Phase 1.
|
||||
7. **Working directory**: Global config option (`working_directory`).
|
||||
Reference in New Issue
Block a user