diff --git a/packages/data-provider/specs/actions.spec.ts b/packages/data-provider/specs/actions.spec.ts index 818c72c832..8e48b8e876 100644 --- a/packages/data-provider/specs/actions.spec.ts +++ b/packages/data-provider/specs/actions.spec.ts @@ -15,6 +15,7 @@ import { getWeatherOpenapiSpec, whimsicalOpenapiSpec, scholarAIOpenapiSpec, + formOpenAPISpec, swapidev, } from './openapiSpecs'; import { AuthorizationTypeEnum, AuthTypeEnum } from '../src/types/agents'; @@ -960,6 +961,34 @@ describe('openapiToFunction', () => { expect(requestBuilders).toHaveProperty('GetCurrentWeather'); expect(requestBuilders.GetCurrentWeather).toBeInstanceOf(ActionRequest); + expect(requestBuilders.GetCurrentWeather.contentType).toBe('application/json'); + }); + + it('preserves OpenAPI spec content-type', () => { + const { functionSignatures, requestBuilders } = openapiToFunction(formOpenAPISpec); + expect(functionSignatures.length).toBe(1); + expect(functionSignatures[0].name).toBe('SubmitForm'); + + const parameters = functionSignatures[0].parameters as ParametersSchema & { + properties: { + 'entry.123': { + type: 'string'; + }; + 'entry.456': { + type: 'string'; + }; + }; + }; + + expect(parameters).toBeDefined(); + expect(parameters.properties['entry.123']).toBeDefined(); + expect(parameters.properties['entry.123'].type).toBe('string'); + expect(parameters.properties['entry.456']).toBeDefined(); + expect(parameters.properties['entry.456'].type).toBe('string'); + + expect(requestBuilders).toHaveProperty('SubmitForm'); + expect(requestBuilders.SubmitForm).toBeInstanceOf(ActionRequest); + expect(requestBuilders.SubmitForm.contentType).toBe('application/x-www-form-urlencoded'); }); describe('openapiToFunction with $ref resolution', () => { diff --git a/packages/data-provider/specs/openapiSpecs.ts b/packages/data-provider/specs/openapiSpecs.ts index dc94068991..6357c4a8fe 100644 --- a/packages/data-provider/specs/openapiSpecs.ts +++ b/packages/data-provider/specs/openapiSpecs.ts @@ -162,6 +162,53 @@ export const whimsicalOpenapiSpec: OpenAPIV3.Document = { }, }; +export const formOpenAPISpec: OpenAPIV3.Document = { + openapi: '3.1.0', + info: { + title: 'Submit Google Form', + description: 'Submit data to a Google Forms', + version: 'v1.0.0', + }, + servers: [ + { + url: 'https://docs.google.com/forms', + }, + ], + paths: { + '/formResponse': { + post: { + description: 'Submit a Google Form', + operationId: 'SubmitForm', + requestBody: { + required: true, + content: { + 'application/x-www-form-urlencoded': { + schema: { + type: 'object', + properties: { + 'entry.123': { + type: 'string', + description: 'Name', + }, + 'entry.456': { + type: 'string', + description: 'Address', + }, + }, + }, + }, + }, + }, + deprecated: false, + responses: {}, + }, + }, + }, + components: { + schemas: {}, + }, +}; + export const scholarAIOpenapiSpec = ` openapi: 3.0.1 info: diff --git a/packages/data-provider/src/actions.ts b/packages/data-provider/src/actions.ts index cc768154e5..8d9c635c3b 100644 --- a/packages/data-provider/src/actions.ts +++ b/packages/data-provider/src/actions.ts @@ -500,10 +500,11 @@ export function openapiToFunction( } } + let contentType = ''; if (operationObj.requestBody) { const requestBody = operationObj.requestBody as RequestBodyObject; const content = requestBody.content; - const contentType = Object.keys(content ?? {})[0]; + contentType = Object.keys(content ?? {})[0]; const schema = content?.[contentType]?.schema; const resolvedSchema = resolveRef( schema as OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject, @@ -522,6 +523,8 @@ export function openapiToFunction( paramLocations[key] = 'body'; } } + + contentType = contentType ?? 'application/json'; } const functionSignature = new FunctionSignature( @@ -538,7 +541,7 @@ export function openapiToFunction( method, operationId, !!(operationObj['x-openai-isConsequential'] ?? false), - operationObj.requestBody ? 'application/json' : '', + contentType, paramLocations, );