formulahendry / formulahendry/acp-ui
ACP UI does not render tool calls correctly when no assistant thought/message exists yet
- Dominant language
- Vue
- Stars
- 476
- Forks
- 47
- PR merge metrics
- No merged PRs in 30d
Description
Hi maintainers,
I found a rendering issue in ACP UI related to `session/update` events for tools.
### Summary
ACP UI appears to attach `tool_call` updates only when there is an active assistant message/thought in the current turn.
If a `tool_call` arrives before any assistant chunk/thought exists, ACP UI ignores it completely: nothing is shown on screen.
The same event is visible in ACP Inspector, so the event is being emitted correctly but not displayed by ACP UI.
### Why this matters
From the ACP protocol perspective, `tool_call` and `tool_call_update` are valid updates on their own.
They should not require a pre-existing assistant message to be visible in the UI.
### Observed behavior
- Agent sends `session/update` with:
- `update.sessionUpdate = "tool_call"`
- `update.toolCallId`, `title`, `status`, etc.
- If no assistant thought/message is currently active in the UI state, the `tool_call` is fully ignored by ACP UI (it does not appear in chat at all).
- The same `tool_call` can be confirmed in ACP Inspector.
- Later `tool_call_update` events cannot be shown either because there is no attached/created tool entry in ACP UI state.
### Expected behavior
ACP UI should render `tool_call` events even when they arrive before any assistant thought/message chunk in the same turn.
### Reproduction steps
1. Run an ACP agent that emits `tool_call` immediately when a tool starts.
2. Ensure the agent does **not** emit assistant text/thought before the first `tool_call`.
3. Send a prompt that triggers a tool.
4. Open ACP UI chat and inspect tool rendering.
5. Observe that ACP UI shows no tool call at all, while ACP Inspector shows the `tool_call` event.
### Example payload shape
```json
{
"type": "session/update",
"update": {
"sessionUpdate": "tool_call",
"toolCallId": "call_123",
"title": "Searching docs",
"status": "in_progress"
}
}
```
Follow-up update:
```json
{
"type": "session/update",
"update": {
"sessionUpdate": "tool_call_update",
"toolCallId": "call_123",
"status": "completed",
"content": "Done"
}
}
```
### Protocol note
This seems to be a frontend store/rendering assumption, not an ACP protocol requirement.
### Suggested fix
- In `tool_call` handling, if there is no current assistant message, create a synthetic assistant container and attach the tool call to it.
- Alternatively, render tool calls as first-class timeline items independent of assistant message chunks.
- Keep `tool_call_update` update-by-`toolCallId`, but allow creating missing entries as a fallback.
### Workaround currently used
A server-side workaround is to emit an assistant thought chunk before the first `tool_call`.
This makes ACP UI render correctly, but it should not be required for protocol-compliant agents.
### Screenshots
- Screenshot 1: without first assistant thought/message (tool call is ignored and not shown in ACP UI)
(Note all the `session/update` messages in the "ACP Traffic" tab)
- Screenshot 2: with first assistant thought/message (tool call appears in ACP UI)
Thanks for your work on ACP UI. I can provide a full event trace if helpful.
Contributor guide
No contributing guide indexed for this repository
Research direction
No files or tests are named; start at the frontend store/rendering entry point that handles `tool_call` and `tool_call_update` session events. Reproduce with a tool call sent before any assistant thought, then verify that the tool appears in ACP UI and that its later update changes the same entry.
Written by the indexing model from the issue text.
Assessment
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100