fix(ai): normalize tool call ids and handoff tests fixes #821

This commit is contained in:
Mario Zechner
2026-01-19 00:10:49 +01:00
parent 298af5c1c2
commit 2c7c23b865
19 changed files with 570 additions and 1376 deletions

View File

@@ -87,6 +87,7 @@ export const streamOpenAIResponses: StreamFunction<"openai-responses"> = (
const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
const client = createClient(model, context, apiKey);
const params = buildParams(model, context, options);
options?.onPayload?.(params);
const openaiStream = await client.responses.create(
params,
options?.signal ? { signal: options.signal } : undefined,
@@ -417,7 +418,23 @@ function buildParams(model: Model<"openai-responses">, context: Context, options
function convertMessages(model: Model<"openai-responses">, context: Context): ResponseInput {
const messages: ResponseInput = [];
const transformedMessages = transformMessages(context.messages, model);
const normalizeToolCallId = (id: string): string => {
const allowedProviders = new Set(["openai", "openai-codex", "opencode"]);
if (!allowedProviders.has(model.provider)) return id;
if (!id.includes("|")) return id;
const [callId, itemId] = id.split("|");
const sanitizedCallId = callId.replace(/[^a-zA-Z0-9_-]/g, "_");
let sanitizedItemId = itemId.replace(/[^a-zA-Z0-9_-]/g, "_");
// OpenAI Responses API requires item id to start with "fc"
if (!sanitizedItemId.startsWith("fc")) {
sanitizedItemId = `fc_${sanitizedItemId}`;
}
const normalizedCallId = sanitizedCallId.length > 64 ? sanitizedCallId.slice(0, 64) : sanitizedCallId;
const normalizedItemId = sanitizedItemId.length > 64 ? sanitizedItemId.slice(0, 64) : sanitizedItemId;
return `${normalizedCallId}|${normalizedItemId}`;
};
const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
if (context.systemPrompt) {
const role = model.reasoning ? "developer" : "system";