fix(langgraph): Make Overwrite survive JSON roundtrips#8127
fix(langgraph): Make Overwrite survive JSON roundtrips#8127Sydney Runkle (sydney-runkle) wants to merge 1 commit into
Overwrite survive JSON roundtrips#8127Conversation
Overwrite survive JSON roundtrips
Overwrite survive JSON roundtripsOverwrite survive JSON roundtrips
| if value.get("type") == OVERWRITE and "value" in value: | ||
| return True, value["value"] |
There was a problem hiding this comment.
🟡 Extra-key dicts bypass reducers
This now treats any channel update dict with type == "__overwrite__" and a value key as an overwrite, even when the dict has additional application data. For example, a BinaryOperatorAggregate(dict, operator.or_) update of {"type": "__overwrite__", "value": 2, "b": 3} now replaces the channel with 2 instead of passing the dict to the reducer/merging it. The JSON-erased Overwrite shape produced by the new dataclass field is exactly {"value": ..., "type": "__overwrite__"}, so the discriminator check should be constrained to that exact shape to avoid hijacking legitimate dict values that happen to carry the same reserved-looking fields.
(Refers to lines 49-50)
Your feedback helps Open SWE learn. React with 👍 or 👎 to tell us if this review comment was useful.
| if value.get("type") == OVERWRITE and "value" in value: | |
| return True, value["value"] | |
| if len(value) == 2 and value.get("type") == OVERWRITE and "value" in value: | |
| return True, value["value"] |
There was a problem hiding this comment.
that's fine
| value: Any | ||
| """The value to write directly to the channel, bypassing any reducer.""" | ||
|
|
||
| type: Literal["__overwrite__"] = "__overwrite__" |
There was a problem hiding this comment.
cursor said we can use type: Literal["__overwrite__"] = OVERWRITE
not sure that is true
| Recognises three forms: | ||
|
|
||
| * The typed `Overwrite` dataclass instance. | ||
| * The sentinel-keyed `{"__overwrite__": value}` dict form. |
There was a problem hiding this comment.
maybe add more details where this is from -- seems like from user hand writing the return from a node?
#2553) ## Summary - JS `Overwrite` already survives JSON serialization because `Overwrite.toJSON()` emits the canonical `{ "__overwrite__": value }` sentinel, which `_getOverwriteValue` recognizes. - This adds recognition of the discriminator form `{ "type": "__overwrite__", value }` that results when a typed `Overwrite` from another runtime (notably a Python dataclass, post langchain-ai/langgraph#8127) is serialized through a JSON boundary and its type is erased. - Brings JS to full parity with Python's three-form `_get_overwrite` (instance, sentinel dict, discriminator dict), so `Overwrite` round-trips both directions across the JS↔Python API boundary. Delta-channel APIs remain Beta.
Add a
type: Literal["__overwrite__"]discriminator field toOverwriteand teach_get_overwrite()to recognise the dataclass-erased{"value": ..., "type": "__overwrite__"}form. This keepsOverwritesemantics intact across JSON boundaries that strip dataclass types (e.g.langgraph-api.serde.json_dumpb), without requiring callers to switch to the dict sentinel form.This was an oversight in the initial
Overwriteimplementation, it should be json serializable out of the box.Fixing langchain-ai/deepagents#3789