[PR #5296] langgraph[fix]: remove deprecated pydantic logic + fix schema gen behavior for typed dicts #4351

Closed
opened 2026-02-20 17:50:03 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/langchain-ai/langgraph/pull/5296

State: closed
Merged: Yes


Fixes https://github.com/langchain-ai/langgraph/issues/4360

  1. Remove deprecated use of __fields__
  2. Remove deprecated use of .schema()
  3. Remove deprecated access of model_fields on an instance (instead access on class)
  4. Remove definitions of get_input_schema and get_output_schema from compiled state graph. Instead, migrate to direct json schema gen.
  5. Updated lockfile to use latest pydantic

More on 4:
Previously, if a user used a TypedDict input/output/state schema, we decomposed the typed dict and generated a pydantic model instead. This doesn't work with things like Required / NotRequired which are typed dict specific.

Now, we're directly generating json schema from either pydantic models of type adapters of said typed dicts.

Perf wise, might want to add a cache. Let's see.

Example of new and improved typed dict behavior:

from typing_extensions import TypedDict, Required, NotRequired
from pydantic import TypeAdapter
from pprint import pprint


class Base(TypedDict):
    a: str
    b: str | None

class Sub(Base, total=False):
    c: str
    d: str | None
    e: Required[str]
    f: NotRequired[str]

ta = TypeAdapter(Sub)
pprint(ta.json_schema())

"""
{'properties': {'a': {'title': 'A', 'type': 'string'},
                'b': {'anyOf': [{'type': 'string'}, {'type': 'null'}],
                      'title': 'B'},
                'c': {'title': 'C', 'type': 'string'},
                'd': {'anyOf': [{'type': 'string'}, {'type': 'null'}],
                      'title': 'D'},
                'e': {'title': 'E', 'type': 'string'},
                'f': {'title': 'F', 'type': 'string'}},
 'required': ['a', 'b', 'e'],
 'title': 'Sub',
 'type': 'object'}
"""

In this case:

  • a is required, Base has total=True by default
  • b is required, Base has total=True by default and | None aka Optional doesn't imply NotRequired
  • c is not required bc Sub has total=False
  • d is not required bc Sub has total=False
  • e is required bc of Required
  • f is not required bc of NotRequired
**Original Pull Request:** https://github.com/langchain-ai/langgraph/pull/5296 **State:** closed **Merged:** Yes --- Fixes https://github.com/langchain-ai/langgraph/issues/4360 1. Remove deprecated use of `__fields__` 2. Remove deprecated use of `.schema()` 3. Remove deprecated access of `model_fields` on an instance (instead access on class) 4. Remove definitions of `get_input_schema` and `get_output_schema` from compiled state graph. Instead, migrate to direct json schema gen. 5. Updated lockfile to use latest pydantic More on 4: Previously, if a user used a `TypedDict` input/output/state schema, we decomposed the typed dict and generated a pydantic model instead. This doesn't work with things like `Required` / `NotRequired` which are typed dict specific. Now, we're directly generating json schema from either pydantic models of type adapters of said typed dicts. Perf wise, might want to add a cache. Let's see. Example of new and improved typed dict behavior: ```py from typing_extensions import TypedDict, Required, NotRequired from pydantic import TypeAdapter from pprint import pprint class Base(TypedDict): a: str b: str | None class Sub(Base, total=False): c: str d: str | None e: Required[str] f: NotRequired[str] ta = TypeAdapter(Sub) pprint(ta.json_schema()) """ {'properties': {'a': {'title': 'A', 'type': 'string'}, 'b': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'B'}, 'c': {'title': 'C', 'type': 'string'}, 'd': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'D'}, 'e': {'title': 'E', 'type': 'string'}, 'f': {'title': 'F', 'type': 'string'}}, 'required': ['a', 'b', 'e'], 'title': 'Sub', 'type': 'object'} """ ``` In this case: * `a` is required, `Base` has `total=True` by default * `b` is required, `Base` has `total=True` by default and `| None` aka `Optional` doesn't imply `NotRequired` * `c` is not required bc `Sub` has `total=False` * `d` is not required bc `Sub` has `total=False` * `e` is required bc of `Required` * `f` is not required bc of `NotRequired`
yindo added the pull-request label 2026-02-20 17:50:03 -05:00
yindo closed this issue 2026-02-20 17:50:03 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#4351