Calling tool from assistant using structured output

I have an assistant using Structured Output. I want it to call my tools adhearing to the JSON schema specified in my tools schema but I’m having an hard time figuring out how to use recursive references.

I have a “searchProducts” function which has a “title” title parameter. The idea is that you can call the tool with a “title” or using “AND” or “OR” e.g. if I want to search for “Foo” it would just do { title: "Foo" } but if you would do either “Foo” or “Bar” it would be { or: [{ title: "Foo" }, { title: "Bar" }] }

Now I want to to reference the fields using a definition so I can nest it in any level. The only way to use ref is to define those on root level according to the Structured Output documentation. I don’t know if the Structured Output JSON schema and the tools schema is aligned/merged at some level but at least I don’t know how to set it up. I’ve tried to place the filters in the root of the json schema (which makes it possible to use from within the structured output) but my “tools” section doesn’t see it.

This is my test code:

import OpenAI from 'openai'

const openAIClient = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })

const assistant = await openAIClient.beta.assistants.create({
  model: 'gpt-4o-2024-11-20',
  response_format: {
    type: 'json_schema',
    json_schema: {
      name: 'searchProducts Test',
      description: 'A test for the searchProducts function',
      schema: {
        $defs: {
          filters: {
            type: 'object',
            properties: {
              title: { type: 'string' }
            },
            required: ['title'],
            additionalProperties: false
          }
        },
  
        type: 'object',
        properties: {
          name: { type: 'string' }
        },
        required: ['name'],
        additionalProperties: false
      },
      strict: true
    }
  },
  tools: [
    {
      type: 'function',
      function: {
        name: 'searchProducts',
        description: 'A function to search for products',
        parameters: {
          type: 'object',
          properties: {
            filters: {
              type: 'object',
              description: 'The filter conditions to apply.',
              anyOf: [
                { id: 'title', type: 'string' },
                {
                  type: 'object',
                  properties: {
                    and: {
                      type: 'array',
                      items: { $ref: '#/$defs/filters' },
                      description: 'Logical AND of sub-filters.'
                    }
                  },
                  required: ['and']
                },
                {
                  type: 'object',
                  properties: {
                    or: {
                      type: 'array',
                      items: { $ref: '#/$defs/filters' },
                      description: 'Logical OR of sub-filters.'
                    }
                  },
                  required: ['or']
                }
              ]
            }
          },
          required: ['filters'],
          additionalProperties: false
        },
        strict: true
      }
    }
  ]
})

Running this code will give me

error: 400 Invalid schema for function 'searchProducts': In context=('properties', 'filters', 'anyOf', '1', 'properties', 'and', 'items'), reference to component '#/$defs/filters' which was not found in the schema.
 code: "invalid_function_parameters"

I think the error message makes sense but I’m not sure where else to place the def … I can’t fit it into the “tools” structure anywhere and it seems like the tools json isn’t merged with the json_schema of the assistant.

Any suggestions for me?