fix(sandbox): merge idempotent sandbox state updates (#3518)

* fix(sandbox): merge idempotent sandbox state updates

* fix(sandbox): merge idempotent sandbox state updates
This commit is contained in:
liuchuan01
2026-06-13 22:40:48 +08:00
committed by GitHub
parent c91dacc8e2
commit 8955b3222a
2 changed files with 69 additions and 1 deletions
@@ -18,6 +18,27 @@ class ViewedImageData(TypedDict):
mime_type: str
def merge_sandbox(existing: SandboxState | None, new: SandboxState | None) -> SandboxState | None:
"""Reducer for sandbox state - accepts idempotent writes only.
Multiple sandbox tools can initialize lazily in the same graph step and
emit the same sandbox_id via Command(update=...). LangGraph needs an
explicit reducer for that shared state key. Different sandbox ids in the
same thread indicate a lifecycle/isolation bug, so fail closed instead of
choosing one silently.
"""
if new is None:
return existing
if existing is None:
return new
existing_id = existing.get("sandbox_id")
new_id = new.get("sandbox_id")
if existing_id == new_id:
return existing
raise ValueError(f"Conflicting sandbox state updates: {existing_id!r} != {new_id!r}")
def merge_artifacts(existing: list[str] | None, new: list[str] | None) -> list[str]:
"""Reducer for artifacts list - merges and deduplicates artifacts."""
if existing is None:
@@ -85,7 +106,7 @@ def merge_promoted(existing: PromotedTools | None, new: PromotedTools | None) ->
class ThreadState(AgentState):
sandbox: NotRequired[SandboxState | None]
sandbox: Annotated[NotRequired[SandboxState | None], merge_sandbox]
thread_data: NotRequired[ThreadDataState | None]
title: NotRequired[str | None]
artifacts: Annotated[list[str], merge_artifacts]