Skip to content

Conversation

@tkattkat
Copy link
Collaborator

why

migrate from zod v3 to v4

what changed

test plan

@changeset-bot
Copy link

changeset-bot bot commented Oct 22, 2025

⚠️ No Changeset found

Latest commit: 4658860

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Summary

This PR migrates the codebase from Zod v3 to v4 by updating the peer dependency and refactoring internal schema access patterns throughout the codebase.

Key changes:

  • Updated Zod peer dependency from 3.25.67 to 4.0.0
  • Changed all imports from zod/v3 to zod across 79 files
  • Refactored packages/core/lib/utils.ts to use Zod 4's internal API (_zod.def instead of _def)
  • Added imports from zod/v4/core to access internal type definitions
  • Updated type names from Zod v3 conventions (e.g., ZodArray, ZodObject) to v4 conventions (e.g., array, object)
  • Moved LLMParsedResponse type from inference.ts to LLMClient.ts with backward-compatible re-export
  • Updated ExtractResult type constraint from z.AnyZodObject to z.ZodObject

Issues found:

  • Uses Zod's internal API from zod/v4/core which is not part of the public API contract and may break in future versions
  • No changeset file added despite this being a breaking dependency change

Confidence Score: 2/5

  • This PR has significant risks due to reliance on undocumented internal APIs and missing changeset
  • Score reflects two critical concerns: (1) the migration relies heavily on Zod's internal API (zod/v4/core) which is not part of the public API contract and could break in future releases, and (2) no changeset was added despite this being a peer dependency update that affects all users. The broad scope of changes (79 files) increases risk, though most changes are straightforward import updates. The complex schema introspection logic in utils.ts needs validation that the internal API access pattern is stable.
  • Pay close attention to packages/core/lib/utils.ts which uses undocumented internal APIs from zod/v4/core. Also verify a changeset is added before merge.

Important Files Changed

File Analysis

Filename Score Overview
packages/core/package.json 5/5 Updated Zod peer dependency from 3.25.67 to 4.0.0
packages/core/lib/utils.ts 3/5 Major refactor to use Zod 4 internal API (_zod.def instead of _def). Uses zod/v4/core imports for internal types. Added comprehensive type casting helpers.
packages/core/lib/inference.ts 5/5 Changed import from zod/v3 to zod. Moved LLMParsedResponse type to LLMClient.ts and re-exported for backward compatibility.
packages/core/lib/v3/llm/LLMClient.ts 4/5 Changed import from zod/v3 to zod. Added LLMParsedResponse interface and createChatCompletion method overloads for better type safety.

Sequence Diagram

sequenceDiagram
    participant App as Application Code
    participant Zod as Zod Library
    participant Utils as utils.ts
    participant Inference as inference.ts
    participant LLM as LLMClient
    
    Note over App,LLM: Zod v3 → v4 Migration Flow
    
    App->>Zod: Import from "zod" (v4)
    Note over App,Zod: Changed from "zod/v3"
    
    App->>Utils: Call toGeminiSchema(schema)
    Utils->>Zod: Access schema._zod.def.type
    Note over Utils,Zod: v4: _zod.def instead of _def
    Utils->>Zod: Import types from "zod/v4/core"
    Note over Utils,Zod: Internal API access
    Utils->>Utils: Cast to ZodWithInternals<T>
    Utils-->>App: Return converted schema
    
    App->>Utils: Call transformSchema(schema)
    Utils->>Zod: Check schema type via getZodType()
    Utils->>Zod: Access _zod.def.element/shape/etc
    Utils->>Utils: Transform URL fields
    Utils-->>App: Return transformed schema
    
    App->>Inference: Call extract()/observe()/act()
    Inference->>LLM: createChatCompletion(options)
    LLM->>Zod: Parse response with schema
    LLM-->>Inference: Return LLMParsedResponse<T>
    Note over Inference,LLM: Type moved to LLMClient.ts
    Inference-->>App: Return typed result
Loading

78 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +17 to +28
import type {
$ZodArrayInternals,
$ZodObjectInternals,
$ZodStringInternals,
$ZodUnionInternals,
$ZodIntersectionInternals,
$ZodOptionalInternals,
$ZodNullableInternals,
$ZodPipeInternals,
$ZodEnumInternals,
$ZodLiteralInternals,
} from "zod/v4/core";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: imports from zod/v4/core access Zod's internal API which is not part of the public API contract and may break in future releases

check Zod 4 release notes to confirm this is the recommended migration path, or consider alternatives like using public API methods or zod-to-json-schema for schema introspection

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/lib/utils.ts
Line: 17:28

Comment:
**logic:** imports from `zod/v4/core` access Zod's internal API which is not part of the public API contract and may break in future releases

check Zod 4 release notes to confirm this is the recommended migration path, or consider alternatives like using public API methods or `zod-to-json-schema` for schema introspection

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 188 to 201
export function getZodType(schema: z.ZodTypeAny): string {
return schema._def.typeName;
// In Zod 4, the type is accessed via _zod.def.type
const schemaWithDef = schema as unknown as {
_zod?: { def?: { type?: string } };
};

if (schemaWithDef._zod?.def?.type) {
return schemaWithDef._zod.def.type;
}

throw new Error(
`Unable to determine Zod schema type. Schema: ${JSON.stringify(schema)}`,
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: verify this error path is reachable and provides useful debugging info - if _zod.def.type doesn't exist, the JSON.stringify may not produce meaningful output for debugging schema issues

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/lib/utils.ts
Line: 188:201

Comment:
**style:** verify this error path is reachable and provides useful debugging info - if `_zod.def.type` doesn't exist, the JSON.stringify may not produce meaningful output for debugging schema issues

How can I resolve this? If you propose a fix, please make it concise.

tkattkat and others added 9 commits October 28, 2025 12:10
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
import { ChatOpenAI } from "@langchain/openai";

async function example() {
// @ts-expect-error Type instantiation is excessively deep and possibly infinite
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this fail without this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants