mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-30 05:54:43 +00:00
refactor(agents): extract tool-error warning helpers
This commit is contained in:
@@ -21,18 +21,50 @@ import {
|
||||
import { isLikelyMutatingToolName } from "../../tool-mutation.js";
|
||||
|
||||
type ToolMetaEntry = { toolName: string; meta?: string };
|
||||
type LastToolError = {
|
||||
toolName: string;
|
||||
meta?: string;
|
||||
error?: string;
|
||||
mutatingAction?: boolean;
|
||||
actionFingerprint?: string;
|
||||
};
|
||||
|
||||
const RECOVERABLE_TOOL_ERROR_KEYWORDS = [
|
||||
"required",
|
||||
"missing",
|
||||
"invalid",
|
||||
"must be",
|
||||
"must have",
|
||||
"needs",
|
||||
"requires",
|
||||
] as const;
|
||||
|
||||
function isRecoverableToolError(error: string | undefined): boolean {
|
||||
const errorLower = (error ?? "").toLowerCase();
|
||||
return RECOVERABLE_TOOL_ERROR_KEYWORDS.some((keyword) => errorLower.includes(keyword));
|
||||
}
|
||||
|
||||
function shouldShowToolErrorWarning(params: {
|
||||
lastToolError: LastToolError;
|
||||
hasUserFacingReply: boolean;
|
||||
suppressToolErrors: boolean;
|
||||
}): boolean {
|
||||
const isMutatingToolError =
|
||||
params.lastToolError.mutatingAction ?? isLikelyMutatingToolName(params.lastToolError.toolName);
|
||||
if (isMutatingToolError) {
|
||||
return true;
|
||||
}
|
||||
if (params.suppressToolErrors) {
|
||||
return false;
|
||||
}
|
||||
return !params.hasUserFacingReply && !isRecoverableToolError(params.lastToolError.error);
|
||||
}
|
||||
|
||||
export function buildEmbeddedRunPayloads(params: {
|
||||
assistantTexts: string[];
|
||||
toolMetas: ToolMetaEntry[];
|
||||
lastAssistant: AssistantMessage | undefined;
|
||||
lastToolError?: {
|
||||
toolName: string;
|
||||
meta?: string;
|
||||
error?: string;
|
||||
mutatingAction?: boolean;
|
||||
actionFingerprint?: string;
|
||||
};
|
||||
lastToolError?: LastToolError;
|
||||
config?: OpenClawConfig;
|
||||
sessionKey: string;
|
||||
provider?: string;
|
||||
@@ -219,23 +251,11 @@ export function buildEmbeddedRunPayloads(params: {
|
||||
const lastAssistantWasToolUse = params.lastAssistant?.stopReason === "toolUse";
|
||||
const hasUserFacingReply =
|
||||
replyItems.length > 0 && !lastAssistantHasToolCalls && !lastAssistantWasToolUse;
|
||||
// Check if this is a recoverable/internal tool error that shouldn't be shown to users
|
||||
// when there's already a user-facing reply (the model should have retried).
|
||||
const errorLower = (params.lastToolError.error ?? "").toLowerCase();
|
||||
const isRecoverableError =
|
||||
errorLower.includes("required") ||
|
||||
errorLower.includes("missing") ||
|
||||
errorLower.includes("invalid") ||
|
||||
errorLower.includes("must be") ||
|
||||
errorLower.includes("must have") ||
|
||||
errorLower.includes("needs") ||
|
||||
errorLower.includes("requires");
|
||||
const isMutatingToolError =
|
||||
params.lastToolError.mutatingAction ??
|
||||
isLikelyMutatingToolName(params.lastToolError.toolName);
|
||||
const shouldShowToolError =
|
||||
isMutatingToolError ||
|
||||
(!hasUserFacingReply && !isRecoverableError && !params.config?.messages?.suppressToolErrors);
|
||||
const shouldShowToolError = shouldShowToolErrorWarning({
|
||||
lastToolError: params.lastToolError,
|
||||
hasUserFacingReply,
|
||||
suppressToolErrors: Boolean(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.
|
||||
|
||||
Reference in New Issue
Block a user