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 摘要。