Description
When using ACP-backed providers (such as Antigravity) with asynchronous background tools, two interrelated issues corrupt assistant message formatting and clutter thread history:
-
Abrupt Assistant Segment Severing on Background Tool Updates:
In AcpSessionRuntime.ts, closeActiveAssistantSegment is invoked unconditionally upon receiving any ToolCallUpdated event:
if (event._tag === "ToolCallUpdated") {
yield* closeActiveAssistantSegment({
queue,
assistantSegmentRef,
});
If a background command finishes while the assistant is actively streaming a response (such as a markdown table, code block, or link), the active segment is severed mid-stream. The remainder of the response is placed in a new segment/bubble without the preceding context, breaking Markdown formatting (e.g. unclosed links [text](http://... cut off before closing parenthesis, and tables split mid-cell where succeeding rows become raw pipe-separated text | row | data |).
-
Harness Telemetry Parroting (<SYSTEM_MESSAGE>) & Ghost Segments:
When background tasks complete, reactive system notifications are delivered into the provider context:
The following is a <SYSTEM_MESSAGE> not actually sent by the user. It is provided by the system as important information to pay attention to.
<SYSTEM_MESSAGE>
[Message] timestamp=... sender=.../task-170 priority=... content=Task id finished with result: exit code 0
</SYSTEM_MESSAGE>
Certain models (e.g. gemini-3.8-flash-high) occasionally parrot this telemetry into their response deltas. Because each tool invocation or update resets the segment lifecycle, this results in an explosion of separate chat bubbles (e.g. 40+ bubbles in a single turn) containing only raw <SYSTEM_MESSAGE> XML boilerplate.
-
Double Message ID Prefix Bug:
In ProviderRuntimeIngestion.ts, assistantSegmentMessageId prepends assistant: to baseKey. Since ACP's itemId already begins with assistant:, this results in duplicated prefixes in the database (assistant:assistant:c19d...).
Reproduction Example
Send the following prompt in a thread with an ACP provider supporting background execution:
First, start a background command with run_command and WaitMsBeforeAsync=500:
`sleep 3 && echo "Background task finished successfully"`
Immediately after starting that command (without waiting for it), stream a 50-row Markdown table with columns | Index | Name | Status | Timestamp |.
Keep writing the rows continuously so that the background task finishes while you are actively streaming the middle of the table.
Actual Behavior:
- The assistant begins streaming the table in Bubble 1.
- When
sleep 3 finishes, ToolCallUpdated is fired.
closeActiveAssistantSegment cuts Bubble 1 off mid-table.
- Bubble 2 begins with the remaining rows, but without table headers. The markdown parser fails to render a table, displaying raw
| characters and broken elements.
- In turns with heavy background tasking, echoed
<SYSTEM_MESSAGE> notifications spam the chat UI as individual bubbles.
Expected Behavior:
- Background tool completions that do not require tool call insertion should not sever an active assistant streaming segment mid-token or mid-block.
- Provider streaming sanitizers should suppress leaked harness telemetry
<SYSTEM_MESSAGE>...</SYSTEM_MESSAGE>.
- Empty or whitespace-only assistant segments should not be projected as empty bubbles.
- Message IDs should be cleanly normalized without double
assistant:assistant: prefixes.
Description
When using ACP-backed providers (such as Antigravity) with asynchronous background tools, two interrelated issues corrupt assistant message formatting and clutter thread history:
Abrupt Assistant Segment Severing on Background Tool Updates:
In
AcpSessionRuntime.ts,closeActiveAssistantSegmentis invoked unconditionally upon receiving anyToolCallUpdatedevent:If a background command finishes while the assistant is actively streaming a response (such as a markdown table, code block, or link), the active segment is severed mid-stream. The remainder of the response is placed in a new segment/bubble without the preceding context, breaking Markdown formatting (e.g. unclosed links
[text](http://...cut off before closing parenthesis, and tables split mid-cell where succeeding rows become raw pipe-separated text| row | data |).Harness Telemetry Parroting (
<SYSTEM_MESSAGE>) & Ghost Segments:When background tasks complete, reactive system notifications are delivered into the provider context:
Certain models (e.g.
gemini-3.8-flash-high) occasionally parrot this telemetry into their response deltas. Because each tool invocation or update resets the segment lifecycle, this results in an explosion of separate chat bubbles (e.g. 40+ bubbles in a single turn) containing only raw<SYSTEM_MESSAGE>XML boilerplate.Double Message ID Prefix Bug:
In
ProviderRuntimeIngestion.ts,assistantSegmentMessageIdprependsassistant:tobaseKey. Since ACP'sitemIdalready begins withassistant:, this results in duplicated prefixes in the database (assistant:assistant:c19d...).Reproduction Example
Send the following prompt in a thread with an ACP provider supporting background execution:
Actual Behavior:
sleep 3finishes,ToolCallUpdatedis fired.closeActiveAssistantSegmentcuts Bubble 1 off mid-table.|characters and broken elements.<SYSTEM_MESSAGE>notifications spam the chat UI as individual bubbles.Expected Behavior:
<SYSTEM_MESSAGE>...</SYSTEM_MESSAGE>.assistant:assistant:prefixes.