STET

agent_patch

runs/2026-02-27__21-30-28__gpt-5-4/flux-pr-5156/flux-pr-5156.1-of-1.2026-02-27__21-30-28__gpt-5-4/agent-logs/agent.patch

6223 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-5156.1-of-1.2026-02-27__21-30-28__gpt-5-4/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts b/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
index ec6267c..0d00c39 100644
--- a/tmp/agent-patch-flux-pr-5156.1-of-1.2026-02-27__21-30-28__gpt-5-4/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
+++ b/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
@@ -565,6 +565,28 @@ describe("toJSONSchema", () => {
     const schema = z.union([z.string(), z.null()]);
     expect(z.toJSONSchema(schema, { target: "openapi-3.0" })).toMatchInlineSnapshot(`
       {
+        "anyOf": [
+          {
+            "type": "string",
+          },
+          {
+            "enum": [
+              null,
+            ],
+            "nullable": true,
+            "type": "string",
+          },
+        ],
+      }
+    `);
+  });
+
+  test("null openapi", () => {
+    expect(z.toJSONSchema(z.null(), { target: "openapi-3.0" })).toMatchInlineSnapshot(`
+      {
+        "enum": [
+          null,
+        ],
         "nullable": true,
         "type": "string",
       }
@@ -737,6 +759,31 @@ describe("toJSONSchema", () => {
     `);
   });
 
+  test("tuple with null openapi", () => {
+    const schema = z.tuple([z.string(), z.null()]);
+    expect(z.toJSONSchema(schema, { target: "openapi-3.0" })).toMatchInlineSnapshot(`
+      {
+        "items": {
+          "anyOf": [
+            {
+              "type": "string",
+            },
+            {
+              "enum": [
+                null,
+              ],
+              "nullable": true,
+              "type": "string",
+            },
+          ],
+        },
+        "maxItems": 2,
+        "minItems": 2,
+        "type": "array",
+      }
+    `);
+  });
+
   test("tuple with rest openapi", () => {
     const schema = z.tuple([z.string(), z.number()]).rest(z.boolean());
     expect(z.toJSONSchema(schema, { target: "openapi-3.0" })).toMatchInlineSnapshot(`
diff --git a/tmp/agent-patch-flux-pr-5156.1-of-1.2026-02-27__21-30-28__gpt-5-4/app/packages/zod/src/v4/core/to-json-schema.ts b/app/packages/zod/src/v4/core/to-json-schema.ts
index 0f5e400..01ead57 100644
--- a/tmp/agent-patch-flux-pr-5156.1-of-1.2026-02-27__21-30-28__gpt-5-4/app/packages/zod/src/v4/core/to-json-schema.ts
+++ b/app/packages/zod/src/v4/core/to-json-schema.ts
@@ -4,6 +4,12 @@ import { $ZodRegistry, globalRegistry } from "./registries.js";
 import type * as schemas from "./schemas.js";
 import { getEnumValues } from "./util.js";
 
+function setOpenAPINullSchema(json: JSONSchema.BaseSchema) {
+  json.type = "string";
+  json.nullable = true;
+  json.enum = [null];
+}
+
 interface JSONSchemaGeneratorParams {
   /** A registry used to look up metadata for each schema. Any schema with an `id` property will be extracted as a $def.
    *  @default globalRegistry */
@@ -236,7 +242,11 @@ export class JSONSchemaGenerator {
             break;
           }
           case "null": {
-            _json.type = "null";
+            if (this.target === "openapi-3.0") {
+              _json.type = "string";
+              _json.nullable = true;
+              _json.enum = [null];
+            } else _json.type = "null";
             break;
           }
           case "any": {
@@ -332,18 +342,7 @@ export class JSONSchemaGenerator {
                 path: [...params.path, "anyOf", i],
               })
             );
-            if (this.target === "openapi-3.0") {
-              const nonNull = options.filter((x) => (x as any).type !== "null");
-              const hasNull = nonNull.length !== options.length;
-              if (nonNull.length === 1) {
-                Object.assign(json, nonNull[0]!);
-              } else {
-                json.anyOf = nonNull;
-              }
-              if (hasNull) (json as any).nullable = true;
-            } else {
-              json.anyOf = options;
-            }
+            json.anyOf = options;
             break;
           }
           case "intersection": {
@@ -478,17 +477,27 @@ export class JSONSchemaGenerator {
               // do nothing (an undefined literal was stripped)
             } else if (vals.length === 1) {
               const val = vals[0]!;
-              json.type = val === null ? ("null" as const) : (typeof val as any);
-              if (this.target === "draft-4" || this.target === "openapi-3.0") {
-                json.enum = [val];
+              if (val === null && this.target === "openapi-3.0") {
+                setOpenAPINullSchema(json);
               } else {
-                json.const = val;
+                json.type = val === null ? ("null" as const) : (typeof val as any);
+                if (this.target === "draft-4" || this.target === "openapi-3.0") {
+                  json.enum = [val];
+                } else {
+                  json.const = val;
+                }
               }
             } else {
               if (vals.every((v) => typeof v === "number")) json.type = "number";
               if (vals.every((v) => typeof v === "string")) json.type = "string";
               if (vals.every((v) => typeof v === "boolean")) json.type = "string";
-              if (vals.every((v) => v === null)) json.type = "null";
+              if (vals.every((v) => v === null)) {
+                if (this.target === "openapi-3.0") {
+                  setOpenAPINullSchema(json);
+                  break;
+                }
+                json.type = "null";
+              }
               json.enum = vals;
             }
             break;
@@ -532,12 +541,12 @@ export class JSONSchemaGenerator {
           }
 
           case "nullable": {
-            const inner = this.process(def.innerType, params);
             if (this.target === "openapi-3.0") {
-              Object.assign(_json, inner);
-              (_json as any).nullable = true;
+              this.process(def.innerType, params);
               result.ref = def.innerType;
+              (_json as any).nullable = true;
             } else {
+              const inner = this.process(def.innerType, params);
               _json.anyOf = [inner, { type: "null" }];
             }
             break;