
























@@ -1,10 +1,28 @@
11import type { AssistantMessage } from "@earendil-works/pi-ai";
2-import { describe, expect, it } from "vitest";
2+import { beforeEach, describe, expect, it, vi } from "vitest";
3+import type { OpenClawConfig } from "../../config/types.openclaw.js";
34import { MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE } from "../../shared/assistant-error-format.js";
45import { makeAssistantMessageFixture } from "../test-helpers/assistant-message-fixtures.js";
56import { formatAssistantErrorText } from "./errors.js";
678+const { toolPolicyAuditInfo } = vi.hoisted(() => ({
9+toolPolicyAuditInfo: vi.fn(),
10+}));
11+12+vi.mock("../../logging/subsystem.js", () => ({
13+createSubsystemLogger: () => ({
14+debug: vi.fn(),
15+error: vi.fn(),
16+info: toolPolicyAuditInfo,
17+warn: vi.fn(),
18+}),
19+}));
20+721describe("formatAssistantErrorText streaming JSON parse classification", () => {
22+beforeEach(() => {
23+toolPolicyAuditInfo.mockClear();
24+});
25+826const makeAssistantError = (errorMessage: string): AssistantMessage =>
927makeAssistantMessageFixture({
1028 errorMessage,
@@ -35,4 +53,42 @@ describe("formatAssistantErrorText streaming JSON parse classification", () => {
3553"LLM request rejected: Expected value in JSON at position 12 for messages.0.content",
3654);
3755});
56+57+it("audits a sandbox tool-policy block once per assistant error", () => {
58+const cfg: OpenClawConfig = {
59+agents: {
60+defaults: {
61+sandbox: { mode: "non-main", scope: "agent" },
62+},
63+},
64+tools: {
65+sandbox: {
66+tools: {
67+deny: ["browser"],
68+},
69+},
70+},
71+};
72+const msg = makeAssistantError("unknown tool: browser");
73+74+expect(
75+formatAssistantErrorText(msg, { cfg, sessionKey: "agent:main:mobilechat:g1" }),
76+).toContain('Tool "browser" blocked by sandbox tool policy');
77+expect(
78+formatAssistantErrorText(msg, { cfg, sessionKey: "agent:main:mobilechat:g1" }),
79+).toContain('Tool "browser" blocked by sandbox tool policy');
80+81+expect(toolPolicyAuditInfo).toHaveBeenCalledTimes(1);
82+expect(toolPolicyAuditInfo).toHaveBeenCalledWith(
83+"sandbox tool policy blocked browser via tools.sandbox.tools.deny; matched browser",
84+{
85+tool: "browser",
86+ruleKind: "deny",
87+ruleSource: "global",
88+configKey: "tools.sandbox.tools.deny",
89+matchedRule: "browser",
90+sandboxMode: "non-main",
91+},
92+);
93+});
3894});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。