agentscope-ai / agentscope-ai/agentscope-java
Core: publish AllToolsDeniedEvent and persist the ALL_TOOLS_DENIED terminal reason
- Dominant language
- Java
- Stars
- 5.6k
- Forks
- 1.3k
- Avg merge
- 4d 12h
- Merged PRs (30d)
- 77
Description
## Problem
The 2.0 all-tools-denied hook works inside the acting middleware chain, but its externally observable and persisted terminal semantics are incomplete.
Observed against `e3a412ed2cc944e401da861c8d5e464b967724e9`:
1. An ASK tool suspends normally.
2. A follow-up `ConfirmResult(confirmed=false)` for every pending tool causes `AllToolsDeniedEvent` to pass through `MiddlewareBase.onActing(...)`.
3. Middleware can return `RequestStopEvent(reason=ALL_TOOLS_DENIED)` and the current `AgentResultEvent.result.generateReason` becomes `ALL_TOOLS_DENIED`.
4. Neither `AllToolsDeniedEvent` nor the middleware `RequestStopEvent` is published by the external `streamEvents()` result.
5. The persisted last context message still carries the previous `MODEL_STOP`, so a fresh runtime cannot read back the actual all-denied terminal reason.
## Expected contract
- `streamEvents()` should publish the typed all-denied lifecycle boundary exactly once, including the stop event if it is the mechanism that terminates the turn.
- The terminal result/state persisted for `(userId, sessionId)` should retain `ALL_TOOLS_DENIED` (or an equivalent typed terminal fact) across state-store recreation.
- Tool results/denial facts must remain consistent: denied tools execute zero times and restart must not make them pending again.
- Multiple parallel tool calls where all are denied should produce one terminal transition; partial denial should not be mislabeled all-denied.
- Product hosts should not need to synthesize the event from text or maintain a separate terminal-state store.
## Acceptance
1. `RequireUserConfirmEvent -> all ConfirmResult(false) -> AllToolsDeniedEvent -> RequestStopEvent/AgentResultEvent` is visible through `streamEvents()` in deterministic order.
2. Fresh agent/state-store readback preserves the terminal reason.
3. Repeated readback/resume does not re-emit or re-execute the denied tool calls.
4. Partial approve/deny follows the normal continuation path and does not emit all-denied.
5. Middleware observers and external subscribers see the same terminal semantics.
This is separable from a larger long-running Goal mode; it closes the typed event/persistence behavior of the existing GA hook.
Contributor guide
Assessment
This issue has not been assessed yet.