Skip to content

[Feature]: **Title**: BaseReActAgentRunner.stream() returns deprecated coarse-grained Flux<Event> and does not surface the fine-grained AgentEvent stream **Labels**: bug / enhancement / a2a #2552

Open

Description

@zcw888

Description

The A2A server's BaseReActAgentRunner.stream(...) currently delegates to the deprecated ReActAgent.stream(List<Msg>) which returns Flux<io.agentscope.core.agent.Event> (the coarse-grained v1 event type). As a result, A2A sub-agents cannot emit / consume the fine-grained AgentEvent hierarchy (Flux<io.agentscope.core.event.AgentEvent>) that covers the full agent lifecycle (reasoning chunks, tool calls/results, HITL RequireUserConfirmEvent, AgentResultEvent, etc.).

Location

agentscope-extensions/.../a2a/.../server/executor/runner/BaseReActAgentRunner.java

@Override
public Flux<Event> stream(List<Msg> requestMessages, AgentRequestOptions options) {
    ...
    ReActAgent agent = buildReActAgent();
    agentCache.put(options.getTaskId(), agent);
    return agent.stream(requestMessages)                     // <-- deprecated coarse-grained API
            .doFinally(signal -> agentCache.remove(options.getTaskId()));
}

ReActAgent itself already provides the replacement API:

  • Flux<Event> stream(...) — @Deprecated(since = "2.0.0", forRemoval = true)
  • Flux<AgentEvent> streamEvents(List<Msg>) / streamEvents(List<Msg>, RuntimeContext) — the recommended fine-grained stream

Impact / Why it matters

  1. Lost observability & control: AgentEvent carries the full lifecycle (reasoning chunks, tool invocations, RequireUserConfirmEvent for human-in-the-loop, final AgentResultEvent). With only Flux<Event>, A2A handlers (e.g. AgentScopeAgentExecutor's streaming/blocking FluxEventHandler) cannot distinguish event semantics reliably and must rely on the legacy EventType mapping.
  2. HITL breakage: When a tool requires confirmation, the fine-grained RequireUserConfirmEvent is the only typed signal. The coarse Event stream does not expose it cleanly, so A2A callers cannot implement human-in-the-loop approval flows properly.
  3. Forward-compat: stream(...) is marked forRemoval = true, so this runner will break once it is removed.

Proposed fix

Make BaseReActAgentRunner (or its AgentRunner contract) support AgentEvent, e.g.:

@Override
public Flux<AgentEvent> streamEvents(List<Msg> requestMessages, AgentRequestOptions options) {
    if (agentCache.containsKey(options.getTaskId())) {
        throw new IllegalStateException("Agent already exists for taskId: " + options.getTaskId());
    }
    ReActAgent agent = buildReActAgent();
    agentCache.put(options.getTaskId(), agent);
    return agent.streamEvents(requestMessages)                 // fine-grained, full lifecycle
            .doFinally(signal -> agentCache.remove(options.getTaskId()));
}

and optionally keep a backward-compatible stream(...) that adapts AgentEvent → Event for callers still on the v1 API.

Environment

  • agentscope-java (agentscope-examples/boba-tea-shop A2A setup)
  • ReActAgent streamEvents available since 2.0.0; stream(...) deprecated for removal.

Reproduction (conceptual)

  1. Implement an AgentRunner extending BaseReActAgentRunner.
  2. Subscribe to runner.stream(msgs, options).
  3. Observe that emitted elements are io.agentscope.core.agent.Event, never io.agentscope.core.event.AgentEvent — so lifecycle/HITL events are unavailable to the A2A executor.

Activity

  1. mikemikimike commented on Sep 12, 2026

    @mikemikimike
    Contributor

    I rechecked issue #2552 against the current main base. Commit d588528, merged as PR #2222, already migrates the A2A server runner and executor to the fine-grained AgentEvent/streamEvents API requested here. PR #2577 still contains an additional compatibility layer, but it also makes the deprecated stream() method required and may break existing custom AgentRunner implementations. Could a maintainer please confirm whether this issue is already resolved by #2222 and whether #2577 should be closed or reduced to a remaining, clearly scoped change?

  2. mikemikimike commented on Sep 22, 2026

    @mikemikimike
    Contributor

    Implemented the remaining review follow-ups in PR #2577, commit b5a58287:

    • The stop-and-reuse regression test now subscribes to the second stream, exercising lazy re-registration.
    • Added migration guidance for UnsupportedAgentEventStreamException versus a plain UnsupportedOperationException in the AgentRunner Javadoc and v2 English/Chinese changelogs.

    Validation completed:

    • Focused A2A tests: 44 passed.
    • Reactor clean verify: core 2,323 tests (8 existing skips), A2A client 111, A2A server 146.
    • All 7 GitHub checks passed, including Ubuntu and Windows builds.
  3. oss-maintainer commented on Sep 24, 2026

    @oss-maintainer
    Collaborator

    Issue Evaluation

    Category: enhancement | Status: Already addressed on main — the remaining gap is the HITL event mapping, not the runner API

    Checked against main@3c1c29c01 (static code review, no runtime reproduction):

    • BaseReActAgentRunner no longer exposes the deprecated coarse-grained stream at all; it implements streamEvents and delegates to the fine-grained API (agentscope-extensions/agentscope-extensions-protocol/agentscope-extensions-a2a/agentscope-extensions-a2a-server/src/main/java/io/agentscope/core/a2a/server/executor/runner/BaseReActAgentRunner.java:52-61):

      @Override
      public Flux<AgentEvent> streamEvents(List<Msg> requestMessages, AgentRequestOptions options) { ... return agent.streamEvents(requestMessages) ... }
    • The AgentRunner contract itself is AgentEvent-based (.../executor/runner/AgentRunner.java:52-58), and the executor consumes that directly (.../executor/AgentScopeAgentExecutor.java:112).

    • ReActAgent.streamEvents(List<Msg>) / streamEvents(List<Msg>, RuntimeContext) exist (agentscope-core/src/main/java/io/agentscope/core/ReActAgent.java:1123-1183); the legacy @Deprecated(forRemoval = true) Flux<Event> stream(...) remains at :972-998 but is not used by the A2A server module.

    • Git history on main shows this file arriving already migrated; the only main commit touching it is 3c1c29c01. d588528b5 feat(a2a): migrate server runner to streamEvents (#2222) and d887181e1 feat(a2a): expose fine-grained agent event stream are not ancestors of main (they are on the merged-PR/branch refs), and a local checkout of PR fix(a2a): map HITL confirmation events to A2A #2577 still carries the old Flux<Event> stream(...) shape — i.e. that branch is behind the current state, not ahead of it.

    What is genuinely still open is the second half of the report: the executor's handlers whitelist only a subset of event types — TEXT_BLOCK_DELTA, THINKING_BLOCK_DELTA, TOOL_RESULT_*, HINT_BLOCK, AGENT_RESULT (AgentScopeAgentExecutor.java:273-284 and :330-385) — and do not map RequireUserConfirmEvent or other permission/HITL events to A2A output, so an A2A caller still cannot drive a human-in-the-loop approval round-trip.

    Suggestion: keep this issue open only for that HITL mapping (narrow the scope), or close it and track the event-mapping subset separately. We are not generating a PR here — the runner change already exists on main, and PR #2577 covers an older version of the same code, so a bot PR would duplicate or conflict with in-flight work.

    Automated evaluation by github-manager-bot.

  4. mikemikimike commented on Sep 26, 2026

    @mikemikimike
    Contributor

    The remaining A2A human-in-the-loop mapping and resume path is implemented in PR #2577: #2577

    The latest review follow-up makes invalid confirmation responses fail the waiting task, requires one result per pending tool call, bounds paused-agent retention, and handles stop/resume/expiry races. It also documents edited tool arguments and the task status message required for resume.

    Validation: 48 focused A2A tests passed; the A2A server reactor clean verify passed; all 7 current GitHub checks passed, including Ubuntu and Windows builds.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/buildBuild, CI, BOM, distributionarea/core/agentAgent runtime, pipeline, hooks, planarea/core/toolTool, skill, RAG abstractionsarea/ext/integrationExternal protocols & middleware integrationsenhancementNew feature or request

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions