openai / openai-node

The official Node.js / Typescript library for the OpenAI API
https://www.npmjs.com/package/openai
Apache License 2.0
7.87k stars 852 forks source link

Structured Outputs fail with gpt4o when Zod schema includes pattern #983

Open jbeoris opened 2 months ago

jbeoris commented 2 months ago

Confirm this is a Node library issue and not an underlying OpenAI API issue

Describe the bug

There is currently an issue when passing a Zod schema containg z.ZodStrings with patterns the new gpt4o structure outputs API with the NodeJS library.

For instance:

const MySchema = z.object({ myString: z.string().includes('my-pattern') })

results in the following error:

BadRequestError: 400 Invalid schema for response_format 'my-schema': In context=('properties', 'myString'), 'pattern' is not permitted

I have temporarily fixed this by wrapping all schemas passed to this endpoint with the following recursive removal code below.

function removeStringIncludes(schema: z.ZodTypeAny): z.ZodTypeAny {
  if (schema instanceof z.ZodString) {
    return z.string();
  } else if (schema instanceof z.ZodObject) {
    const newShape: { [k: string]: z.ZodTypeAny } = {};
    Object.entries(schema.shape).forEach(([key, value]) => {
      newShape[key] = removeStringIncludes(value as z.ZodTypeAny);
    });
    return z.object(newShape);
  } else if (schema instanceof z.ZodArray) {
    return z.array(removeStringIncludes(schema.element));
  } else if (schema instanceof z.ZodEnum) {
    return z.enum(schema._def.values.map((v: any) => removeStringIncludes(v)));
  } else if (schema instanceof z.ZodUnion) {
    return z.union(schema.options.map(removeStringIncludes));
  } else if (schema instanceof z.ZodIntersection) {
    return z.intersection(
      removeStringIncludes(schema._def.left),
      removeStringIncludes(schema._def.right)
    );
  }

  return schema;
}

It would be nice for OpenAI to support all schemas, as there are lots of validations baked into Zod schemas that are really convenient and having to work around this and strip them out while passing them to the API is tedious and weakens the power of the almighty Zod.

To Reproduce

pass this schema via zodResponseFormat(mySchema, 'schema') to the new structure outputs endpoint with the sdk.

const MySchema = z.object({ myString: z.string().includes('my-pattern') })'

Code snippets

No response

OS

macOS

Node version

Node v18.18.2

Library version

openai v4.55.0

sreeprasannar commented 2 months ago

what exactly is the problem with this schema? what does it mean?

BadRequestError: 400 Invalid schema for response_format 'my-schema': In context=('properties', 'myString'), 'pattern' is not permitted

does it mean the specific keyword pattern is not permitted?

peterje commented 2 months ago

what exactly is the problem with this schema? what does it mean?

BadRequestError: 400 Invalid schema for response_format 'my-schema': In context=('properties', 'myString'), 'pattern' is not permitted

does it mean the specific keyword pattern is not permitted?

Yes. pattern is not supported