agentscope-ai / agentscope-ai/agentscope-java

Core: publish AllToolsDeniedEvent and persist the ALL_TOOLS_DENIED terminal reason

Open
#2,141 1 comment 0 reactions 0 assignees View on GitHub
area/core enhancement
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.