Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/agents/run_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,13 @@
ContextSerializer = Callable[[Any], Mapping[str, Any]]
ContextDeserializer = Callable[[Mapping[str, Any]], Any]

# Schema version for serialization compatibility
CURRENT_SCHEMA_VERSION = "1.0"
# RunState schema policy.
# 1. Bump CURRENT_SCHEMA_VERSION when serialized shape/semantics change.
# 2. Keep older readable versions in SUPPORTED_SCHEMA_VERSIONS for backward reads.
# 3. to_json() always emits CURRENT_SCHEMA_VERSION.
# 4. Forward compatibility is intentionally fail-fast (older SDKs reject newer versions).
CURRENT_SCHEMA_VERSION = "1.1"
SUPPORTED_SCHEMA_VERSIONS = frozenset({"1.0", CURRENT_SCHEMA_VERSION})

_FUNCTION_OUTPUT_ADAPTER: TypeAdapter[FunctionCallOutput] = TypeAdapter(FunctionCallOutput)
_COMPUTER_OUTPUT_ADAPTER: TypeAdapter[ComputerCallOutput] = TypeAdapter(ComputerCallOutput)
Expand Down Expand Up @@ -1894,10 +1899,12 @@ async def _build_run_state_from_json(
schema_version = state_json.get("$schemaVersion")
if not schema_version:
raise UserError("Run state is missing schema version")
if schema_version != CURRENT_SCHEMA_VERSION:
if schema_version not in SUPPORTED_SCHEMA_VERSIONS:
supported_versions = ", ".join(sorted(SUPPORTED_SCHEMA_VERSIONS))
raise UserError(
f"Run state schema version {schema_version} is not supported. "
f"Please use version {CURRENT_SCHEMA_VERSION}"
f"Supported versions are: {supported_versions}. "
f"New snapshots are written as version {CURRENT_SCHEMA_VERSION}."
)

agent_map = _build_agent_map(initial_agent)
Expand Down
30 changes: 29 additions & 1 deletion tests/test_run_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
)
from agents.run_state import (
CURRENT_SCHEMA_VERSION,
SUPPORTED_SCHEMA_VERSIONS,
RunState,
_build_agent_map,
_deserialize_items,
Expand Down Expand Up @@ -286,11 +287,13 @@ async def test_throws_error_if_schema_version_is_missing_or_invalid(self):
await RunState.from_string(agent, str_data)

json_data["$schemaVersion"] = "0.1"
supported_versions = ", ".join(sorted(SUPPORTED_SCHEMA_VERSIONS))
with pytest.raises(
Exception,
match=(
f"Run state schema version 0.1 is not supported. "
f"Please use version {CURRENT_SCHEMA_VERSION}"
f"Supported versions are: {supported_versions}. "
f"New snapshots are written as version {CURRENT_SCHEMA_VERSION}."
),
):
await RunState.from_string(agent, json.dumps(json_data))
Expand Down Expand Up @@ -3330,6 +3333,31 @@ async def test_from_json_unsupported_schema_version(self):
with pytest.raises(UserError, match="Run state schema version 2.0 is not supported"):
await RunState.from_json(agent, state_json)

@pytest.mark.asyncio
async def test_from_json_accepts_previous_schema_version(self):
"""Test that from_json accepts a previous, explicitly supported schema version."""
agent = Agent(name="TestAgent")
state_json = {
"$schemaVersion": "1.0",
"original_input": "test",
"current_agent": {"name": "TestAgent"},
"context": {
"context": {"foo": "bar"},
"usage": {"requests": 0, "input_tokens": 0, "output_tokens": 0, "total_tokens": 0},
"approvals": {},
},
"max_turns": 3,
"current_turn": 0,
"model_responses": [],
"generated_items": [],
}

restored = await RunState.from_json(agent, state_json)
assert restored._current_agent is not None
assert restored._current_agent.name == "TestAgent"
assert restored._context is not None
assert restored._context.context == {"foo": "bar"}

@pytest.mark.asyncio
async def test_from_json_agent_not_found(self):
"""Test that from_json raises error when agent is not found in agent map."""
Expand Down