fix(core): 插件拒绝工具时把 ctx.Response 的理由透给模型

before_toolcall 的 ctx.Response 是插件写的**拒绝理由**,但工具结果被写死成
「工具 X 已被插件拒绝」,理由从不到达模型——模型于是不知道能不能重试,
会反复重试被拒的调用。抽出 denialResultText 并在有理由时原样透出。
This commit is contained in:
JianFeeeee
2026-09-14 16:45:04 +08:00
parent c252915083
commit 9eebd96ab7
2 changed files with 36 additions and 1 deletions

View File

@ -5,6 +5,7 @@ import (
"testing"
agentAPI "gitcode.com/JianFeeeee/HomeAgent/internal/agent/api"
sdk "gitcode.com/JianFeeeee/homeagent-sdk/sdk"
)
// appendPlaceholder 复刻 process() 循环顶部的补位逻辑。
@ -115,3 +116,23 @@ func TestIsOutputDeliveryTool(t *testing.T) {
}
}
}
// 插件在 before_toolcall 里给出的拒绝理由必须原样进入工具结果。
// 若被通用文案覆盖,模型不知道「为什么被拒 / 能不能重试」,会反复重试同一个调用。
func TestDenialReasonReachesModel(t *testing.T) {
reason := "QQ 权限策略拒绝私人资源工具 calendar_list;请不要重试"
ctx := &sdk.StageContext{Response: &reason}
if got := denialResultText(ctx, "calendar_list"); got != reason {
t.Fatalf("拒绝理由被丢弃,实际: %q", got)
}
// 插件没给理由时退回通用文案(保持既有行为)。
if got := denialResultText(&sdk.StageContext{}, "calendar_list"); !strings.Contains(got, "已被插件拒绝") {
t.Fatalf("无理由时应退回通用文案,实际: %q", got)
}
// 空白理由不算理由。
blank := " "
if got := denialResultText(&sdk.StageContext{Response: &blank}, "x"); !strings.Contains(got, "已被插件拒绝") {
t.Fatalf("空白理由应退回通用文案,实际: %q", got)
}
}