agentscope-ai / agentscope-ai/agentscope-java

[Bug]:ToolResultEvictionMiddleware does not evict

Abierto
#1,695 0 comentarios 0 reacciones 0 asignados Ver en GitHub
area/core/agent bug
Lenguaje dominante
Java
Estrellas
5.6k
Forks
1.3k
Merge medio
4 d 12 h
PR fusionados (30 d)
77

Descripción

# Bug: ToolResultEvictionMiddleware does not evict — `doOnComplete` fires before tool results are written to context

## Problem

`ToolResultEvictionMiddleware` never evicts oversized tool results. The `evictAddedToolResults()` callback always finds zero new messages and exits immediately.

## Root Cause

The `onActing` middleware hook wraps only `actingStream()`, which emits streaming events (`ToolResultEndEvent`, etc.) but does **not** write results to `AgentState.contextMutable()`.

Tool result messages are written to context in `notifyPostActingHook()` — which is called in `acting()`'s outer `.flatMap()`, **after** the middleware chain has already completed.

Execution order:

```
actingStream() Flux completes
→ doOnComplete(() -> evictAddedToolResults()) fires ← eviction runs HERE
→ contextMutable()[sizeBefore..end] is EMPTY ← nothing to evict
→ (outer flatMap) notifyPostActingHook() ← results written HERE (too late)
→ state.contextMutable().add(resultMsg)
```

Relevant lines in `ReActAgent.java`:
- **2129–2138**: middleware chain wraps only `actingCore = actingStream()`
- **2173–2174**: `notifyPostActingHook()` called outside the middleware chain
- **2728–2729**: `state.contextMutable().add(resultMsg)` — actual write point

## Fix Suggestion

Bring `notifyPostActingHook()` inside the middleware-wrapped scope so that tool results are in `contextMutable()` before the `onActing` Flux completes.

**Option A (minimal):** Extend `actingCore` to include the post-acting context write, then remove the duplicate call from the outer `flatMap`:

```java
Function> actingCore = ai ->
actingStream(ai.toolCalls(), replyId, resultHolder)
.thenMany(
Mono.defer(() -> Flux.fromIterable(resultHolder.get())
.concatMap(this::notifyPostActingHook)
.then(Mono.empty())));
```

**Option B (alternative):** Move eviction to the `onReasoning` hook's pre-step — check `contextMutable()` for oversized TOOL messages at the start of each reasoning round, before building the prompt. This avoids restructuring `actingCore` entirely.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.