agentscope-ai / agentscope-ai/agentscope-java

[Feature]: Let onActing middleware write a tool_result for a denied/filtered tool call (per-call selective deny)

未關閉
#1,766 1 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
area/core/tool enhancement
主要語言
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 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。