mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 17:38:27 +00:00
fix: preserve bootstrap paths and expose failed mutations (#16131)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 385dcbd8a9
Co-authored-by: Swader <1430603+Swader@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
extractAssistantThinking,
|
||||
formatReasoningMessage,
|
||||
} from "../../pi-embedded-utils.js";
|
||||
import { isLikelyMutatingToolName } from "../../tool-mutation.js";
|
||||
|
||||
type ToolMetaEntry = { toolName: string; meta?: string };
|
||||
|
||||
@@ -25,7 +26,13 @@ export function buildEmbeddedRunPayloads(params: {
|
||||
assistantTexts: string[];
|
||||
toolMetas: ToolMetaEntry[];
|
||||
lastAssistant: AssistantMessage | undefined;
|
||||
lastToolError?: { toolName: string; meta?: string; error?: string };
|
||||
lastToolError?: {
|
||||
toolName: string;
|
||||
meta?: string;
|
||||
error?: string;
|
||||
mutatingAction?: boolean;
|
||||
actionFingerprint?: string;
|
||||
};
|
||||
config?: OpenClawConfig;
|
||||
sessionKey: string;
|
||||
provider?: string;
|
||||
@@ -223,22 +230,37 @@ export function buildEmbeddedRunPayloads(params: {
|
||||
errorLower.includes("must have") ||
|
||||
errorLower.includes("needs") ||
|
||||
errorLower.includes("requires");
|
||||
const isMutatingToolError =
|
||||
params.lastToolError.mutatingAction ??
|
||||
isLikelyMutatingToolName(params.lastToolError.toolName);
|
||||
const shouldShowToolError = isMutatingToolError || (!hasUserFacingReply && !isRecoverableError);
|
||||
|
||||
// Show tool errors only when:
|
||||
// 1. There's no user-facing reply AND the error is not recoverable
|
||||
// Recoverable errors (validation, missing params) are already in the model's context
|
||||
// and shouldn't be surfaced to users since the model should retry.
|
||||
if (!hasUserFacingReply && !isRecoverableError) {
|
||||
// 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.
|
||||
if (shouldShowToolError) {
|
||||
const toolSummary = formatToolAggregate(
|
||||
params.lastToolError.toolName,
|
||||
params.lastToolError.meta ? [params.lastToolError.meta] : undefined,
|
||||
{ markdown: useMarkdown },
|
||||
);
|
||||
const errorSuffix = params.lastToolError.error ? `: ${params.lastToolError.error}` : "";
|
||||
replyItems.push({
|
||||
text: `⚠️ ${toolSummary} failed${errorSuffix}`,
|
||||
isError: true,
|
||||
});
|
||||
const warningText = `⚠️ ${toolSummary} failed${errorSuffix}`;
|
||||
const normalizedWarning = normalizeTextForComparison(warningText);
|
||||
const duplicateWarning = normalizedWarning
|
||||
? replyItems.some((item) => {
|
||||
if (!item.text) {
|
||||
return false;
|
||||
}
|
||||
const normalizedExisting = normalizeTextForComparison(item.text);
|
||||
return normalizedExisting.length > 0 && normalizedExisting === normalizedWarning;
|
||||
})
|
||||
: false;
|
||||
if (!duplicateWarning) {
|
||||
replyItems.push({
|
||||
text: warningText,
|
||||
isError: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user