agentscope-ai / agentscope-ai/agentscope-java
[Feature]: Let onActing middleware write a tool_result for a denied/filtered tool call (per-call selective deny)
- 主要語言
- Java
- 星號
- 5.6k
- 分支
- 1.3k
- 平均合併
- 4 天 12 小時
- 30 天內合併 PR
- 77
描述
### Summary
A middleware can filter `ActingInput.toolCalls()` in `onActing`, but there is no way to write the corresponding `ToolResultBlock` for a removed/denied call. As a result, a policy middleware that wants to deny a **single** tool call has no choice but to abort the **entire** run.
### Why
- `resultHolder` is a local `AtomicReference>>` created in `ReActAgent.acting()` and written inside `runToolBatch`'s `Flux.create` sink — isolated from the middleware chain.
- `ActingInput` exposes only `toolCalls()`; `MiddlewareBase.onActing`'s `next` is `Function>` — no result-write slot.
So if a middleware denies one tool call, the model still emitted that `tool_use` but receives no matching `tool_result` → the provider conversation API breaks → the only safe option is aborting the whole run, instead of returning a `denied: ` result and letting the model adapt and continue.
The framework already does exactly this for the HITL/permission flow — `applyConfirmResults` writes `ToolResultBlock.text(...).withIdAndName(id, name).withState(DENIED)` into the context for a user-denied call — but that path is not reachable from a custom `onActing` middleware.
### Request
Expose a result-write path to `onActing` so a policy middleware can substitute a synthetic result for a single denied call, e.g.:
- a `Consumer>>` (or `BiConsumer`) on `ActingInput`, **or**
- an `onActingResult(ToolUseBlock, ToolResultBlock)` hook on `MiddlewareBase`.
### Use case
Per-input policy authorization (e.g. OPA/ABAC) that denies a single tool invocation by its arguments without killing the run — the model sees `denied: ` for that call and continues with the others.
貢獻指南
評估
這個 Issue 還沒有評估資料。