feat: add messages.suppressToolErrors config option (#16620)
Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 9ae4394b81bf0a68a5dfbcfe39fb60a21689ac49 Co-authored-by: vai-oro <258511217+vai-oro@users.noreply.github.com> Co-authored-by: sebslight <19554889+sebslight@users.noreply.github.com> Reviewed-by: @sebslight
This commit is contained in:
@@ -11,6 +11,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Discord: allow exec approval prompts to target channels or both DM+channel via `channels.discord.execApprovals.target`. (#16051) Thanks @leonnardo.
|
||||
- Sandbox: add `sandbox.browser.binds` to configure browser-container bind mounts separately from exec containers. (#16230) Thanks @seheepeak.
|
||||
- Discord: add debug logging for message routing decisions to improve `--debug` tracing. (#16202) Thanks @jayleekr.
|
||||
- Agents: add optional `messages.suppressToolErrors` config to hide non-mutating tool-failure warnings from user-facing chat while still surfacing mutating failures. (#16620) Thanks @vai-oro.
|
||||
|
||||
### Fixes
|
||||
|
||||
|
||||
@@ -278,6 +278,42 @@ describe("buildEmbeddedRunPayloads", () => {
|
||||
expect(payloads).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("suppresses non-mutating non-recoverable tool errors when messages.suppressToolErrors is enabled", () => {
|
||||
const payloads = buildEmbeddedRunPayloads({
|
||||
assistantTexts: [],
|
||||
toolMetas: [],
|
||||
lastAssistant: undefined,
|
||||
lastToolError: { toolName: "browser", error: "connection timeout" },
|
||||
config: { messages: { suppressToolErrors: true } },
|
||||
sessionKey: "session:telegram",
|
||||
inlineToolResultsAllowed: false,
|
||||
verboseLevel: "off",
|
||||
reasoningLevel: "off",
|
||||
toolResultFormat: "plain",
|
||||
});
|
||||
|
||||
expect(payloads).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("still shows mutating tool errors when messages.suppressToolErrors is enabled", () => {
|
||||
const payloads = buildEmbeddedRunPayloads({
|
||||
assistantTexts: [],
|
||||
toolMetas: [],
|
||||
lastAssistant: undefined,
|
||||
lastToolError: { toolName: "write", error: "connection timeout" },
|
||||
config: { messages: { suppressToolErrors: true } },
|
||||
sessionKey: "session:telegram",
|
||||
inlineToolResultsAllowed: false,
|
||||
verboseLevel: "off",
|
||||
reasoningLevel: "off",
|
||||
toolResultFormat: "plain",
|
||||
});
|
||||
|
||||
expect(payloads).toHaveLength(1);
|
||||
expect(payloads[0]?.isError).toBe(true);
|
||||
expect(payloads[0]?.text).toContain("connection timeout");
|
||||
});
|
||||
|
||||
it("shows recoverable tool errors for mutating tools", () => {
|
||||
const payloads = buildEmbeddedRunPayloads({
|
||||
assistantTexts: [],
|
||||
|
||||
@@ -233,7 +233,9 @@ export function buildEmbeddedRunPayloads(params: {
|
||||
const isMutatingToolError =
|
||||
params.lastToolError.mutatingAction ??
|
||||
isLikelyMutatingToolName(params.lastToolError.toolName);
|
||||
const shouldShowToolError = isMutatingToolError || (!hasUserFacingReply && !isRecoverableError);
|
||||
const shouldShowToolError =
|
||||
isMutatingToolError ||
|
||||
(!hasUserFacingReply && !isRecoverableError && !params.config?.messages?.suppressToolErrors);
|
||||
|
||||
// Always surface mutating tool failures so we do not silently confirm actions that did not happen.
|
||||
// Otherwise, keep the previous behavior and only surface non-recoverable failures when no reply exists.
|
||||
|
||||
@@ -325,6 +325,8 @@ export const FIELD_HELP: Record<string, string> = {
|
||||
"Max reply-back turns between requester and target (0–5).",
|
||||
"channels.telegram.customCommands":
|
||||
"Additional Telegram bot menu commands (merged with native; conflicts ignored).",
|
||||
"messages.suppressToolErrors":
|
||||
"When true, suppress ⚠️ tool-error warnings from being shown to the user. The agent already sees errors in context and can retry. Default: false.",
|
||||
"messages.ackReaction": "Emoji reaction used to acknowledge inbound messages (empty disables).",
|
||||
"messages.ackReactionScope":
|
||||
'When to send ack reactions ("group-mentions", "group-all", "direct", "all").',
|
||||
|
||||
@@ -219,6 +219,7 @@ export const FIELD_LABELS: Record<string, string> = {
|
||||
"browser.remoteCdpHandshakeTimeoutMs": "Remote CDP Handshake Timeout (ms)",
|
||||
"session.dmScope": "DM Session Scope",
|
||||
"session.agentToAgent.maxPingPongTurns": "Agent-to-Agent Ping-Pong Turns",
|
||||
"messages.suppressToolErrors": "Suppress Tool Error Warnings",
|
||||
"messages.ackReaction": "Ack Reaction Emoji",
|
||||
"messages.ackReactionScope": "Ack Reaction Scope",
|
||||
"messages.inbound.debounceMs": "Inbound Message Debounce (ms)",
|
||||
|
||||
@@ -82,6 +82,8 @@ export type MessagesConfig = {
|
||||
ackReactionScope?: "group-mentions" | "group-all" | "direct" | "all";
|
||||
/** Remove ack reaction after reply is sent (default: false). */
|
||||
removeAckAfterReply?: boolean;
|
||||
/** When true, suppress ⚠️ tool-error warnings from being shown to the user. Default: false. */
|
||||
suppressToolErrors?: boolean;
|
||||
/** Text-to-speech settings for outbound replies. */
|
||||
tts?: TtsConfig;
|
||||
};
|
||||
|
||||
@@ -114,6 +114,7 @@ export const MessagesSchema = z
|
||||
ackReaction: z.string().optional(),
|
||||
ackReactionScope: z.enum(["group-mentions", "group-all", "direct", "all"]).optional(),
|
||||
removeAckAfterReply: z.boolean().optional(),
|
||||
suppressToolErrors: z.boolean().optional(),
|
||||
tts: TtsConfigSchema,
|
||||
})
|
||||
.strict()
|
||||
|
||||
Reference in New Issue
Block a user