mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 13:50:49 +00:00
fix: gate immutable thinking replay repair to anthropic
This commit is contained in:
@@ -418,6 +418,7 @@ export async function sanitizeSessionHistory(params: {
|
||||
: sanitizedImages;
|
||||
const sanitizedToolCalls = sanitizeToolCallInputs(droppedThinking, {
|
||||
allowedToolNames: params.allowedToolNames,
|
||||
preserveImmutableThinkingTurns: policy.validateAnthropicTurns,
|
||||
});
|
||||
const repairedTools = policy.repairToolUseResultPairing
|
||||
? sanitizeToolUseResultPairing(sanitizedToolCalls, {
|
||||
|
||||
@@ -403,7 +403,10 @@ describe("sanitizeToolCallInputs", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const out = sanitizeToolCallInputs(input, { allowedToolNames: ["read"] });
|
||||
const out = sanitizeToolCallInputs(input, {
|
||||
allowedToolNames: ["read"],
|
||||
preserveImmutableThinkingTurns: true,
|
||||
});
|
||||
|
||||
expect(out).toEqual([]);
|
||||
});
|
||||
@@ -432,12 +435,52 @@ describe("sanitizeToolCallInputs", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const out = sanitizeToolCallInputs(input, { allowedToolNames: ["sessions_spawn"] });
|
||||
const out = sanitizeToolCallInputs(input, {
|
||||
allowedToolNames: ["sessions_spawn"],
|
||||
preserveImmutableThinkingTurns: true,
|
||||
});
|
||||
|
||||
expect(out).toEqual([]);
|
||||
expect(JSON.stringify(out)).not.toContain(secret);
|
||||
});
|
||||
|
||||
it("keeps generic thinking turns mutable when immutable preservation is disabled", () => {
|
||||
const input = castAgentMessages([
|
||||
{
|
||||
role: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "thinking",
|
||||
thinking: "Let me normalize this tool name.",
|
||||
thinkingSignature: "sig_generic",
|
||||
},
|
||||
{
|
||||
type: "toolCall",
|
||||
id: "call_read",
|
||||
name: " read ",
|
||||
arguments: { path: "README.md" },
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
const out = sanitizeToolCallInputs(input, { allowedToolNames: ["read"] });
|
||||
const assistant = out[0] as Extract<AgentMessage, { role: "assistant" }>;
|
||||
expect(assistant.content).toEqual([
|
||||
{
|
||||
type: "thinking",
|
||||
thinking: "Let me normalize this tool name.",
|
||||
thinkingSignature: "sig_generic",
|
||||
},
|
||||
{
|
||||
type: "toolCall",
|
||||
id: "call_read",
|
||||
name: "read",
|
||||
arguments: { path: "README.md" },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "trims leading whitespace from tool names",
|
||||
|
||||
@@ -176,7 +176,7 @@ function isReplaySafeThinkingAssistantTurn(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return sawToolCall || content.some((block) => isThinkingLikeBlock(block));
|
||||
return sawToolCall;
|
||||
}
|
||||
|
||||
function makeMissingToolResult(params: {
|
||||
@@ -232,6 +232,7 @@ export type ToolCallInputRepairReport = {
|
||||
|
||||
export type ToolCallInputRepairOptions = {
|
||||
allowedToolNames?: Iterable<string>;
|
||||
preserveImmutableThinkingTurns?: boolean;
|
||||
};
|
||||
|
||||
export type ErroredAssistantResultPolicy = "preserve" | "drop";
|
||||
@@ -269,6 +270,7 @@ export function repairToolCallInputs(
|
||||
let changed = false;
|
||||
const out: AgentMessage[] = [];
|
||||
const allowedToolNames = normalizeAllowedToolNames(options?.allowedToolNames);
|
||||
const preserveImmutableThinkingTurns = options?.preserveImmutableThinkingTurns === true;
|
||||
|
||||
for (const msg of messages) {
|
||||
if (!msg || typeof msg !== "object") {
|
||||
@@ -281,7 +283,11 @@ export function repairToolCallInputs(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg.content.some((block) => isThinkingLikeBlock(block))) {
|
||||
if (
|
||||
preserveImmutableThinkingTurns &&
|
||||
msg.content.some((block) => isThinkingLikeBlock(block)) &&
|
||||
countRawToolCallBlocks(msg.content) > 0
|
||||
) {
|
||||
// Signed Anthropic thinking blocks must remain byte-for-byte stable on
|
||||
// replay. Preserve the turn only if every sibling tool call is already
|
||||
// valid and requires no redaction or normalization. Otherwise drop the
|
||||
|
||||
Reference in New Issue
Block a user