agentscope-ai / agentscope-ai/agentscope-java

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

Aberta
#2,552 1 comentário 0 reações 0 responsáveis Ver no GitHub
area/build area/core/agent area/core/tool area/ext/integration enhancement
Linguagem predominante
Java
Estrelas
5.6k
Forks
1.3k
Merge médio
4d 12h
PRs com merge (30d)
77

Descrição

## Description

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

### Location

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

```java
@Override
public Flux stream(List 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 stream(...)` — `@Deprecated(since = "2.0.0", forRemoval = true)`
- `Flux streamEvents(List)` / `streamEvents(List, 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`, 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.:

```java
@Override
public Flux streamEvents(List 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.

Guia de contribuição

Abrir o guia de contribuição

Avaliação

Esta issue ainda não foi avaliada.

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.