Skip to content

feat(agui): support tool execution progress and fix stream delta loss#1240

Open
jujn wants to merge 2 commits intoagentscope-ai:mainfrom
jujn:feat_1222
Open

feat(agui): support tool execution progress and fix stream delta loss#1240
jujn wants to merge 2 commits intoagentscope-ai:mainfrom
jujn:feat_1222

Conversation

@jujn
Copy link
Copy Markdown
Contributor

@jujn jujn commented Apr 17, 2026

Description

Close #1222
This PR introduces support for real-time tool execution progress and addresses the streaming data loss edge cases.

Key Changes

  1. Support Tool Progress Stream: - Added enableToolProgressStream in AguiAdapterConfig.

    • Elegantly converts intermediate tool execution chunks (!event.isLast()) into ReasoningMessage events to display real-time progress on the frontend without modifying the AG-UI protocol.
  2. Fix Tail-End Data Loss:

    • Decoupled the isLast termination logic from the data extraction process in convertEvent().
    • Ensures that the final data chunks (Text, Reasoning, and Tool JSON args) carried by the termination packet are fully emitted before the state machine closes the component.

Checklist

Please check the following items before code is ready to be reviewed.

  • Code has been formatted with mvn spotless:apply
  • All tests are passing (mvn test)
  • Javadoc comments are complete and follow project conventions
  • Related documentation has been updated (e.g. links, examples, etc.)
  • Code is ready for review

@jujn jujn requested review from a team and Copilot April 17, 2026 14:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the AG-UI adapter’s streaming behavior by (1) optionally surfacing tool-execution progress in real time and (2) preventing “tail-end” deltas from being dropped when the terminating (isLast=true) packet still carries content.

Changes:

  • Added enableToolProgressStream to AguiAdapterConfig and wired it into StreamOptions.includeActingChunk.
  • Updated AguiAgentAdapter.convertEvent() to emit text/tool-args deltas even when event.isLast() is true, then close lifecycles afterward to avoid tail-data loss.
  • Added tests covering last-packet content preservation and tool progress streaming scenarios.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
agentscope-extensions/agentscope-extensions-agui/src/main/java/io/agentscope/core/agui/adapter/AguiAgentAdapter.java Adds acting-chunk option plumbing; adjusts last-event handling; introduces tool-progress-to-reasoning mapping.
agentscope-extensions/agentscope-extensions-agui/src/main/java/io/agentscope/core/agui/adapter/AguiAdapterConfig.java Adds new config flag and builder method for enabling tool progress stream.
agentscope-extensions/agentscope-extensions-agui/src/test/java/io/agentscope/core/agui/adapter/AguiAgentAdapterTest.java Adds/updates tests for tail-end preservation and tool progress streaming behavior.

Comment on lines 243 to 253
@@ -254,18 +252,57 @@ private List<AguiEvent> convertEvent(Event event, EventConversionState state) {
state.startToolCall(toolCallId);
}
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toolResult.getId() can be null (e.g., ToolEmitter chunks / ToolResultBlock.text() start with null id and are only populated from ToolUseBlock id, which can also be null). In that case, constructing ToolCallStart/ToolCallEnd will throw because AG-UI events require non-null toolCallId. Please add a null-handling strategy here (e.g., infer the active toolCallId from state when unambiguous, or generate a stable fallback ID and keep it consistent across chunks) to avoid runtime NPEs when tool IDs are missing.

Copilot uses AI. Check for mistakes.
Comment on lines 151 to +160
// Start message if not started
if (!state.hasStartedMessage(messageId)) {
events.add(
new AguiEvent.TextMessageStart(
state.threadId, state.runId, messageId, "assistant"));
state.startMessage(messageId);
}

if (!event.isLast()) {
// In incremental mode, text is already the delta
events.add(
new AguiEvent.TextMessageContent(
state.threadId, state.runId, messageId, text));
} else {
// End message if this is the last event
if (!state.hasEndedMessage(messageId)) {
events.add(
new AguiEvent.TextMessageEnd(
state.threadId, state.runId, messageId));
state.endMessage(messageId);
}
}
events.add(
new AguiEvent.TextMessageContent(
state.threadId, state.runId, messageId, text));
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Text deltas are now always emitted even when event.isLast() is true. If a TextMessageEnd was already emitted earlier for the same messageId (e.g., because a ToolUseBlock ended the active text message), this can result in TextMessageContent being sent after TextMessageEnd with no subsequent restart/end, which is an invalid lifecycle for many consumers. Consider suppressing content emission for ended messages, or introducing a continuation strategy (e.g., generate a new messageId for post-tool text) so that content is never emitted after an end event.

Copilot uses AI. Check for mistakes.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 17, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...agentscope/core/agui/adapter/AguiAgentAdapter.java 81.08% 0 Missing and 7 partials ⚠️

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: [功能建议] AGUI 中支持长时间运行的工具实时反馈执行情况

2 participants