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

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

Đang mở
#2,577 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
bug
Ngôn ngữ chính
Python
Star
15.9k
Fork
1.4k
Merge trung bình
1 ngày 17 giờ
Pull request đã merge (30 ngày)
163

Mô tả

### 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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.