Incompatibility between json schema anyOf and VAPI...
# support
j
I have a json schema which I am already using in openAI for an strict response directly from them. I want to reuse it so I can use the same schema from vapi ( as I expect the json schema to be the same VAPI will send to openAI ) . As per openAI docs we need to spefy every optional field as nullable instead of optional to be able to consistently get the full answer. This generates a lot of anyOf in the schema joining the result and type: null. When setting the schema in VAPI via API or UI in both cases I get an error with those fields: function.parameters.properties.recipe.properties.ingredients.items.properties.unit.type must be one of the following values: string, number, integer, boolean, array, object, null, or an array containing only these values "unit": { "anyOf": [ { "type": "string", "enum": [ "kg", "g", "l", "ml", "ud" ] }, { "type": "null" } ], "description": "Unit of the ingredient" },
v
I've looked into your issue with the JSON schema
anyOf
construct in VAPI, but I couldn't find a definitive solution in our documentation. Based on the error message, it seems VAPI might not fully support the
anyOf
construct in the same way OpenAI does. I found that VAPI has its own schema format that adapts to different models like OpenAI and Anthropic, which might explain the incompatibility you're experiencing. According to some information I found, "We have developed our own schema and format for the tools, as Anthropic has different chat completion models that operate according to their specifications, and similarly for OpenAI" [from Discord discussions](https://discord.com/channels/1211482211119796234/1211483291191083018/threads/1332510949940133960). I've escalated your query to our technical team for a definitive answer and possible workaround. They'll be able to provide specific guidance on how to handle nullable optional fields in VAPI's JSON schema implementation. In the meantime, you might want to try using a simpler schema structure without
anyOf
if possible, or check if using the
strict
parameter when creating OpenAI functions in VAPI helps (mentioned in our [changelog](https://docs.vapi.ai/changelog/2024/10/7)). Someone from our team will get back to you soon with more specific help! 👍
j
When generating my JSON schema if I change all .nullable() by .optional() then it works for vapi, but it won't work for openAI, as they need it: https://platform.openai.com/docs/guides/function-calling?api-mode=chat&strict-mode=enabled#strict-mode
This might be related with another topic I raised about VAPI answer not strictly following the schema
For the record. Added this on my side for now: function mapAnyOfWithNullToOptionalParameters(schema: any): any { const newOptionalProperties: string[] = [] if (schema.anyOf) { return mapAnyOfWithNullToOptionalParameters(schema.anyOf.find((item: any) => item.type !== 'null')) } if (schema.type === 'object' && schema.properties) { return { ...schema, properties: Object.fromEntries( Object.entries(schema.properties).map(([key, value]) => { if (typeof value === 'object' && value && 'anyOf' in value) { newOptionalProperties.push(key) } return [key, mapAnyOfWithNullToOptionalParameters(value)] }), ), required: schema.required?.filter((key: string) => !newOptionalProperties.includes(key)) ?? [], } } if (schema.type === 'array') { return { ...schema, items: mapAnyOfWithNullToOptionalParameters(schema.items), } } return schema }
@User
k
Thank you for reaching out to us. We've received your message and will get back to you as soon as possible.
Hi, checking if this is resolved/solved for you?
j
It is not solved
k
Hi, I was out of office for a few days and was unable to respond to your message earlier. I apologize for any inconvenience this may have caused.
s
Your workaround approach using mapAnyOfWithNullToOptionalParameters is an excellent solution that addresses the issue.
Your current implementation works well. For completeness, here's a slightly refactored version:
Copy code
ts
function mapAnyOfWithNullToOptionalParameters(schema: any): any {
    // Handle direct anyOf at current level
    if (schema.anyOf) {
        const nonNullSchema = schema.anyOf.find((item: any) => item.type !== 'null');
        return mapAnyOfWithNullToOptionalParameters(nonNullSchema || {});
    }
    
    // Process object properties
    if (schema.type === 'object' && schema.properties) {
        const newOptionalProperties: string[] = [];
        const processedProperties = Object.fromEntries(
            Object.entries(schema.properties).map(([key, value]) => {
                if (typeof value === 'object' && value && 'anyOf' in value) {
                    newOptionalProperties.push(key);
                }
                return [key, mapAnyOfWithNullToOptionalParameters(value)];
            })
        );
        
        return {
            ...schema,
            properties: processedProperties,
            required: schema.required?.filter((key: string) => !newOptionalProperties.includes(key)) || [],
        };
    }
    
    // Process array items
    if (schema.type === 'array' && schema.items) {
        return {
            ...schema,
            items: mapAnyOfWithNullToOptionalParameters(schema.items),
        };
    }
    
    return schema;
}
Another approach would be to create middleware that intercepts and converts schemas before sending them to VAPI:
Copy code
ts

async function callVAPIWithSchema(schema) {
    const vapiCompatibleSchema = mapAnyOfWithNullToOptionalParameters(schema);
    // Use vapiCompatibleSchema with VAPI
}
@Jorge The solution you've implemented addresses the core issue while allowing you to maintain a single source of schema truth that can be adapted to both OpenAI and VAPI requirements.
let me check with team on this, what else can be done.