Fix issue #4718: Enforce 40-char limit for OpenAI tool call IDs
OpenAI's API requires tool_call IDs to be <= 40 characters, but Clawdbot was not enforcing this limit for OpenAI providers after commit870bfa94e. Changes: - Re-enable tool call ID sanitization for OpenAI in transcript-policy.ts - The sanitization preserves tool_use/tool_result pairing via stable mapping - Add test case for 439-char ID (similar to reported 438-char issue) - Update test expectations to reflect OpenAI now gets sanitized IDs Root cause: Commit870bfa94edisabled sanitization to "preserve Pi pairing", but the sanitization logic already preserves pairing correctly via the resolve() function in tool-call-id.ts. Fixes openclaw/openclaw#4718
This commit is contained in:
parent
56ee224d4c
commit
ccac2aeec2
@ -94,7 +94,7 @@ describe("sanitizeSessionHistory", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("does not sanitize tool call ids for openai-responses", async () => {
|
||||
it("sanitizes tool call ids for openai-responses to enforce 40-char limit", async () => {
|
||||
vi.mocked(helpers.isGoogleModelApi).mockReturnValue(false);
|
||||
|
||||
await sanitizeSessionHistory({
|
||||
@ -108,7 +108,11 @@ describe("sanitizeSessionHistory", () => {
|
||||
expect(helpers.sanitizeSessionMessagesImages).toHaveBeenCalledWith(
|
||||
mockMessages,
|
||||
"session:history",
|
||||
expect.objectContaining({ sanitizeMode: "images-only", sanitizeToolCallIds: false }),
|
||||
expect.objectContaining({
|
||||
sanitizeMode: "images-only",
|
||||
sanitizeToolCallIds: true,
|
||||
toolCallIdMode: "strict",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@ -137,6 +137,39 @@ describe("sanitizeToolCallIdsForCloudCodeAssist", () => {
|
||||
expect(r1.toolCallId).toBe(a.id);
|
||||
expect(r2.toolCallId).toBe(b.id);
|
||||
});
|
||||
|
||||
it("enforces 40-char limit for very long IDs (issue #4718)", () => {
|
||||
// Simulate a very long tool call ID (like 438 chars reported in issue)
|
||||
const veryLongId = `call_${"x".repeat(434)}`;
|
||||
expect(veryLongId.length).toBe(439); // Verify we're testing a long ID
|
||||
|
||||
const input = [
|
||||
{
|
||||
role: "assistant",
|
||||
content: [{ type: "toolCall", id: veryLongId, name: "gitlab", arguments: {} }],
|
||||
},
|
||||
{
|
||||
role: "toolResult",
|
||||
toolCallId: veryLongId,
|
||||
toolName: "gitlab",
|
||||
content: [{ type: "text", text: "ok" }],
|
||||
},
|
||||
] satisfies AgentMessage[];
|
||||
|
||||
const out = sanitizeToolCallIdsForCloudCodeAssist(input);
|
||||
expect(out).not.toBe(input);
|
||||
|
||||
const assistant = out[0] as Extract<AgentMessage, { role: "assistant" }>;
|
||||
const toolCall = assistant.content?.[0] as { id?: string };
|
||||
expect(toolCall.id).toBeDefined();
|
||||
expect(toolCall.id?.length).toBeLessThanOrEqual(40);
|
||||
expect(toolCall.id?.length).toBeGreaterThan(0);
|
||||
expect(isValidCloudCodeAssistToolId(toolCall.id as string, "strict")).toBe(true);
|
||||
|
||||
const result = out[1] as Extract<AgentMessage, { role: "toolResult" }>;
|
||||
expect(result.toolCallId).toBe(toolCall.id);
|
||||
expect(result.toolCallId?.length).toBeLessThanOrEqual(40);
|
||||
});
|
||||
});
|
||||
|
||||
describe("strict mode (alphanumeric only)", () => {
|
||||
|
||||
@ -85,7 +85,8 @@ export function resolveTranscriptPolicy(params: {
|
||||
|
||||
const needsNonImageSanitize = isGoogle || isAnthropic || isMistral || isOpenRouterGemini;
|
||||
|
||||
const sanitizeToolCallIds = isGoogle || isMistral;
|
||||
// OpenAI requires tool call IDs <= 40 chars (issue #4718)
|
||||
const sanitizeToolCallIds = isGoogle || isMistral || isOpenAi;
|
||||
const toolCallIdMode: ToolCallIdMode | undefined = isMistral
|
||||
? "strict9"
|
||||
: sanitizeToolCallIds
|
||||
@ -99,7 +100,7 @@ export function resolveTranscriptPolicy(params: {
|
||||
|
||||
return {
|
||||
sanitizeMode: isOpenAi ? "images-only" : needsNonImageSanitize ? "full" : "images-only",
|
||||
sanitizeToolCallIds: !isOpenAi && sanitizeToolCallIds,
|
||||
sanitizeToolCallIds,
|
||||
toolCallIdMode,
|
||||
repairToolUseResultPairing: !isOpenAi && repairToolUseResultPairing,
|
||||
preserveSignatures: isAntigravityClaudeModel,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user