ag-ui-protocol / ag-ui-protocol/ag-ui

[Bug]: .NET AGUI.Client buffers tool-call updates until all TOOL_CALL_RESULT events arrive

未關閉
#2,577 1 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
bug
主要語言
Python
星號
15.9k
分支
1.4k
平均合併
1 天 17 小時
30 天內合併 PR
163

描述

### Pre-flight Checklist

- [x] I have searched [existing issues](https://github.com/ag-ui-protocol/ag-ui/issues) and this hasn't been reported yet.
- [x] I am using the **latest** version AG-UI.

### Describe the Bug

## Summary

`AGUI.Client`'s `IChatClient` adapter does not surface a `FunctionCallContent` update when the corresponding `TOOL_CALL_END` event is received. Instead, it buffers the call until a `TOOL_CALL_RESULT` arrives. With parallel tool calls, it waits until **all** pending results arrive before releasing any of the buffered call/result updates.

This makes long-running backend tools invisible to consumers while they are executing. A UI cannot show an in-progress state: the tool call and result appear together only after execution has completed.

The AG-UI wire stream contains the lifecycle events at the expected times; the observable delay is introduced while converting `BaseEvent` objects into `ChatResponseUpdate` objects.

### Steps to Reproduce

1. Install `AGUI.Client` 0.0.6 and consume an AG-UI endpoint through `AGUIChatClient.GetStreamingResponseAsync(...)`.
2. Have the endpoint emit a backend tool lifecycle with a noticeable delay before the result:

```text
RUN_STARTED
TOOL_CALL_START(call_1, slow_tool)
TOOL_CALL_ARGS(call_1, {...})
TOOL_CALL_END(call_1)
# wait several seconds while the tool executes
TOOL_CALL_RESULT(call_1, ...)
RUN_FINISHED
```

3. Enumerate the returned `ChatResponseUpdate` stream and log the arrival time and content type of every update.
4. Observe that no update containing `FunctionCallContent` is yielded after `TOOL_CALL_END`.
5. Observe that after `TOOL_CALL_RESULT`, the buffered `FunctionCallContent` and `FunctionResultContent` updates are yielded together.
6. Repeat with two parallel tool calls. Even if the first tool finishes earlier, no buffered tool update is released until the last pending result arrives.

### Expected Behavior

After `TOOL_CALL_END` has completed the tool name and arguments, the client should immediately yield a `ChatResponseUpdate` containing `FunctionCallContent`. This gives consumers a window in which the call exists without a result and can be displayed as running.

When `TOOL_CALL_RESULT` arrives later, the client should yield the corresponding `FunctionResultContent` update.

Parallel calls should be surfaced and completed independently by `toolCallId`; one slow tool should not delay visibility of unrelated calls.

### Environment

```text
AG-UI packages:
- AGUI.Client 0.0.6
- AGUI.Abstractions 0.0.6
- AGUI.Formatting 0.0.6

Runtime:
- .NET 10.0
- Blazor UI consuming IChatClient streaming updates

Server used during reproduction:
- Microsoft.Agents.AI.Hosting.AGUI.AspNetCore 1.19.0-preview.260822.1
```

### Screenshots

_No response_

### Logs & Errors

```shell

```

### Additional Context

## Root cause

In the source commit packaged by `AGUI.Client` 0.0.6 (`9f393021ecbd6bcc62dc4b1ad5a6ac4b797565f4`):

- [`ToolCallBuilder.EndToolCall`](https://github.com/ag-ui-protocol/ag-ui/blob/9f393021ecbd6bcc62dc4b1ad5a6ac4b797565f4/sdks/dotnet/src/AGUI.Client/Internal/ToolCallBuilder.cs#L62-L93) creates the `FunctionCallContent` but adds its update to `_buffer`.
- [`ToolCallBuilder.AddResult`](https://github.com/ag-ui-protocol/ag-ui/blob/9f393021ecbd6bcc62dc4b1ad5a6ac4b797565f4/sdks/dotnet/src/AGUI.Client/Internal/ToolCallBuilder.cs#L102-L115) returns the buffered updates only when `_pendingToolCallIds.Count == 0`.

Consequently, a single call is hidden until its result and a parallel batch is hidden until the final result.

## Impact

- Progress indicators and running/pulse states cannot be implemented through the `IChatClient` streaming surface.
- Long-running tools make the UI appear stalled.
- Parallel tool activity arrives in a burst rather than reflecting actual execution timing.

## Related issues

This resembles #1668 at the UX/protocol level, but that issue concerned the Spring integration. It is also distinct from #2359, which concerns .NET server-side suppression on continuation runs. This report concerns buffering in the .NET `AGUI.Client` event-to-`ChatResponseUpdate` conversion.

A possible fix would be to yield the completed `FunctionCallContent` update at `TOOL_CALL_END` and yield each result independently, while retaining any special buffering needed for interrupt/approval handling.

貢獻指南

開啟貢獻指南

評估

這個 Issue 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。