diff --git a/apps/sim/providers/openai/utils.test.ts b/apps/sim/providers/openai/utils.test.ts index ae976233930..a2c574a570f 100644 --- a/apps/sim/providers/openai/utils.test.ts +++ b/apps/sim/providers/openai/utils.test.ts @@ -6,6 +6,7 @@ import { describe, expect, it } from 'vitest' import { ResolvedSecretTraceRegistry } from '@/executor/utils/resolved-secret-trace-registry' import { buildResponsesInputFromMessages, + convertToolsToResponses, parseResponsesUsage, toOpenAIModelUsage, } from '@/providers/openai/utils' @@ -155,3 +156,28 @@ describe('buildResponsesInputFromMessages', () => { ]) }) }) + +describe('convertToolsToResponses', () => { + it.each(['wrapped', 'flat'] as const)( + 'preserves optional inputs on %s tool definitions without implicit strict normalization', + (shape) => { + const parameters = { + type: 'object', + properties: { + fileId: { type: 'string' }, + folderPaths: { type: 'array', items: { type: 'string' } }, + offset: { type: 'number' }, + }, + required: ['fileId'], + } + const tool = { name: 'file_get_content', description: 'Read selected file text', parameters } + const converted = convertToolsToResponses([ + shape === 'wrapped' ? { type: 'function', function: tool } : tool, + ]) + + expect(converted).toEqual([{ type: 'function', strict: false, ...tool }]) + expect(converted[0].parameters).toBe(parameters) + expect(parameters.required).toEqual(['fileId']) + } + ) +}) diff --git a/apps/sim/providers/openai/utils.ts b/apps/sim/providers/openai/utils.ts index 0586bf8741f..536f3c94634 100644 --- a/apps/sim/providers/openai/utils.ts +++ b/apps/sim/providers/openai/utils.ts @@ -140,6 +140,7 @@ export async function* iterateResponsesStreamEvents( export interface ResponsesToolDefinition { type: 'function' + strict: false name: string description?: string parameters?: Record @@ -200,7 +201,8 @@ export function buildResponsesInputFromMessages( } /** - * Converts tool definitions to the Responses API format. + * Converts tool definitions without changing their required and optional inputs. + * Responses otherwise attempts strict normalization, which can require optional fields. */ export function convertToolsToResponses( tools: Array<{ @@ -220,6 +222,7 @@ export function convertToolsToResponses( return { type: 'function' as const, + strict: false as const, name, description: tool.function?.description ?? tool.description, parameters: tool.function?.parameters ?? tool.parameters,