From b2548ce489a23082c2b71b23a91c94f6226d896c Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 18 Mar 2026 03:37:40 +0100 Subject: [PATCH] fix(ai): normalize replayed responses tool call ids closes #2328 --- .../src/providers/openai-responses-shared.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/ai/src/providers/openai-responses-shared.ts b/packages/ai/src/providers/openai-responses-shared.ts index ba15ee75..e74e6d13 100644 --- a/packages/ai/src/providers/openai-responses-shared.ts +++ b/packages/ai/src/providers/openai-responses-shared.ts @@ -91,21 +91,22 @@ export function convertResponsesMessages( ): ResponseInput { const messages: ResponseInput = []; + const normalizeIdPart = (part: string): string => { + const sanitized = part.replace(/[^a-zA-Z0-9_-]/g, "_"); + const normalized = sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized; + return normalized.replace(/_+$/, ""); + }; + const normalizeToolCallId = (id: string): string => { - if (!allowedToolCallProviders.has(model.provider)) return id; - if (!id.includes("|")) return id; + if (!allowedToolCallProviders.has(model.provider)) return normalizeIdPart(id); + if (!id.includes("|")) return normalizeIdPart(id); const [callId, itemId] = id.split("|"); - const sanitizedCallId = callId.replace(/[^a-zA-Z0-9_-]/g, "_"); - let sanitizedItemId = itemId.replace(/[^a-zA-Z0-9_-]/g, "_"); + const normalizedCallId = normalizeIdPart(callId); + let normalizedItemId = normalizeIdPart(itemId); // OpenAI Responses API requires item id to start with "fc" - if (!sanitizedItemId.startsWith("fc")) { - sanitizedItemId = `fc_${sanitizedItemId}`; + if (!normalizedItemId.startsWith("fc")) { + normalizedItemId = normalizeIdPart(`fc_${normalizedItemId}`); } - // Truncate to 64 chars and strip trailing underscores (OpenAI Codex rejects them) - let normalizedCallId = sanitizedCallId.length > 64 ? sanitizedCallId.slice(0, 64) : sanitizedCallId; - let normalizedItemId = sanitizedItemId.length > 64 ? sanitizedItemId.slice(0, 64) : sanitizedItemId; - normalizedCallId = normalizedCallId.replace(/_+$/, ""); - normalizedItemId = normalizedItemId.replace(/_+$/, ""); return `${normalizedCallId}|${normalizedItemId}`; };