agentscope-ai / agentscope-ai/agentscope-java
[Bug]:ToolResultEvictionMiddleware does not evict
- Lingua principale
- Java
- Stelle
- 5.6k
- Fork
- 1.3k
- Merge medio
- 4g 12h
- PR unite (30g)
- 77
Descrizione
# 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.
Guida per i contributori
Apri la guida per i contributori
Valutazione
Questa issue non è ancora stata valutata.