vercel / ai

Build AI-powered applications with React, Svelte, Vue, and Solid
https://sdk.vercel.ai/docs
Other
10.31k stars 1.55k forks source link

Cannot use zod tuple() in tool schema #2271

Open revmischa opened 4 months ago

revmischa commented 4 months ago

Description

Create a tool schema that includes z.tuple()

⨯ AI_APICallError: Invalid schema for function 'render_chart': [{'type': 'number'}, {'type': 'number'}] is not of type 'object', 'boolean'.

Code example

...
tools: {
  render_chart: {
    parameters: z.object({
      bounds: z
        .union([z.number(), z.tuple([z.number(), z.number()])])
        .optional(),
    });
  }
}
...

Additional context

No response

lgrammel commented 4 months ago

Which model provider are you using? Do you have a stack trace?

revmischa commented 4 months ago

Using OpenAI

Uncaught (in promise) AI_APICallError: Invalid schema for function 'render_chart': [{'type': 'number'}, {'type': 'number'}] is not of type 'object', 'boolean'.
    at eval (webpack-internal:///(rsc)/../node_modules/.pnpm/@ai-sdk+provider-utils@0.0.6_zod@3.22.4/node_modules/@ai-sdk/provider-utils/dist/index.mjs:324:14)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async postToApi (webpack-internal:///(rsc)/../node_modules/.pnpm/@ai-sdk+provider-utils@0.0.6_zod@3.22.4/node_modules/@ai-sdk/provider-utils/dist/index.mjs:231:28)
    at async OpenAIChatLanguageModel.doStream (webpack-internal:///(rsc)/../node_modules/.pnpm/@ai-sdk+openai@0.0.10_zod@3.22.4/node_modules/@ai-sdk/openai/dist/index.mjs:277:50)
    at async _retryWithExponentialBackoff (webpack-internal:///(rsc)/../node_modules/.pnpm/ai@3.2.22_openai@4.20.1_react@18.2.0_solid-js@1.8.15_svelte@4.2.12_vue@3.4.21_typescript@5.3.3__zod@3.22.4/node_modules/ai/rsc/dist/rsc-server.mjs:211:16)
    at async streamUI (webpack-internal:///(rsc)/../node_modules/.pnpm/ai@3.2.22_openai@4.20.1_react@18.2.0_solid-js@1.8.15_svelte@4.2.12_vue@3.4.21_typescript@5.3.3__zod@3.22.4/node_modules/ai/rsc/dist/rsc-server.mjs:1532:20)
xnousnow commented 3 months ago

Not working with z.union() too. I think you can wrap union with some object

lgrammel commented 3 months ago

This seems to be a limitation of what the OpenAI API or the Zod to JSON schema conversion can handle.

@revmischa would a workaround where you inject objects (see below) work?

    tools: {
      render_chart: {
        parameters: z.object({
          bounds: z
            .union([z.number(), z.object({ x: z.number(), y: z.number() })])
            .optional(),
          content: z.string(),
        }),
      },
    },

(in general, more descriptive objects make it also easier to the LLM to fill in the right information)

revmischa commented 3 months ago

Unfortunately I am trying to make a tool to generate params for a library I didn't design so I can't really change the shape from a tuple to a dictionary and this is a tiny piece of a giant nested data structure so translating these bits would be non-trivial (but maybe a transform could do it?)

xnousnow commented 3 months ago

Would it be possible to address this by having the library replace the schema with a format such as { 1: ..., 2: ... } or z.array(...).length(...) when using tuple()?

revmischa commented 3 months ago

z.array(...).length(...)

z.array().length() probably generates the right thing but then typescript gets sad and I don't know how to cheer it up because the library wants this specific tuple type for that output type

Screenshot 2024-08-31 at 7 39 36 PM