📋 feat: Support Custom Content-Types in Action Descriptors (#9364)

This commit is contained in:
Sebastien Bruel 2025-08-30 12:02:40 +09:00 committed by GitHub
parent 49e8443ec5
commit 3a47deac07
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 81 additions and 2 deletions

View file

@ -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', () => {

View file

@ -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:

View file

@ -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,
);