openai / openai-node

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

openai-deno: Type-checking error for zodResponseFormat with Deno and deno.land imports #984

Open hammerlscs opened 1 month ago

hammerlscs commented 1 month ago

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

Describe the bug

Type-checking using "deno check" fails with either

error: TS2589 [ERROR]: Type instantiation is excessively deep and possibly infinite. response_format: zodResponseFormat(MathResponse, "math_response")

or

Fatal JavaScript out of memory: Reached heap limit

when using deno.land imports for OpenAI and Zod.

To Reproduce

(The example is from https://github.com/openai/openai-node/blob/master/helpers.md#auto-parsing-response-content-with-zod-schemas)

With deno.land imports

main.ts:

import { zodResponseFormat } from "openai/helpers/zod.ts";
import OpenAI from "openai/mod.ts";
import { z } from "zod";

const Step = z.object({
  explanation: z.string(),
  output: z.string(),
});

const MathResponse = z.object({
  steps: z.array(Step),
  final_answer: z.string(),
});

const client = new OpenAI();

const completion = await client.beta.chat.completions.parse({
  model: "gpt-4o-2024-08-06",
  messages: [
    { role: "system", content: "You are a helpful math tutor." },
    { role: "user", content: "solve 8x + 31 = 2" },
  ],
  response_format: zodResponseFormat(MathResponse, "math_response"),
});

console.dir(completion, { depth: 5 });

const message = completion.choices[0]?.message;
if (message?.parsed) {
  console.log(message.parsed.steps);
  console.log(`answer: ${message.parsed.final_answer}`);
}

with deno.json:

{
  "imports": {
    "zod": "https://deno.land/x/zod@v3.23.8/mod.ts",
    "openai/": "https://deno.land/x/openai@v4.55.4/"
  }
}

Running deno check main.ts fails with:

Check file://main.ts error: TS2589 [ERROR]: Type instantiation is excessively deep and possibly infinite. response_format: zodResponseFormat(MathResponse, "math_response"),

With npm imports

main.ts:

import { zodResponseFormat } from "openai/helpers/zod";
import OpenAI from "openai";
import { z } from "zod";

[same code]

with deno.json:

{
  "imports": {
    "zod": "npm:zod@3.23.8",
    "openai": "npm:openai@4.55.4",
    "openai/": "npm:/openai@4.55.4/"
  }
}

Running deno check main.ts with npm imports is successful

OS

macOS

Node version

deno 1.45.5, typescript 5.5.2

Library version

4.55.4

alexkates commented 1 month ago

Same bug with the following versions and example

import OpenAI from "https://deno.land/x/openai@v4.55.5/mod.ts";
import { zodResponseFormat } from "https://deno.land/x/openai@v4.55.5/helpers/zod.ts";
import { z } from "https://deno.land/x/zod@v3.23.8/mod.ts";
const WildlifeSchema = z.object({
  commonName: z.string(),
});

image

RobertCraigie commented 6 days ago

Thanks for the report. It'd be helpful if someone here could help us narrow down the issue, does this also result in a type error for you?

import { ResponseFormatJSONSchema } from 'openai/resources';
import z from 'zod';
import type { infer as zodInfer, ZodType } from 'zod';

export type AutoParseableResponseFormat<ParsedT> = ResponseFormatJSONSchema & {
  __output: ParsedT; // type-level only

  $brand: 'auto-parseable-response-format';
  $parseRaw(content: string): ParsedT;
};

export function zodTest<ZodInput extends ZodType>(
  zodObject: ZodInput,
  name: string,
  props?: Omit<ResponseFormatJSONSchema.JSONSchema, 'schema' | 'strict' | 'name'>,
): AutoParseableResponseFormat<zodInfer<ZodInput>> {
  throw new Error('not implemented');
}

const WildlifeSchema = z.object({
  commonName: z.string(),
});
const fmt = zodTest(WildlifeSchema, 'wildLifeSchema');
hammerlscs commented 6 days ago

No, Deno can successfully type-check your code. (I had to adjust your first import, import { ResponseFormatJSONSchema } from "openai/resources/shared.ts";)