128 lines
4.2 KiB
Python
128 lines
4.2 KiB
Python
from datetime import datetime, timezone
|
|
|
|
import pytest
|
|
|
|
from v1.agent.schemas import AgentSessionSnapshot, RunAgentInput
|
|
|
|
|
|
class TestRunAgentInput:
|
|
def test_requires_full_fields(self):
|
|
payload = {
|
|
"threadId": "t1",
|
|
"runId": "r1",
|
|
"state": {},
|
|
"messages": [],
|
|
"tools": [],
|
|
"context": [],
|
|
"forwardedProps": {},
|
|
}
|
|
model = RunAgentInput.model_validate(payload)
|
|
assert model.threadId == "t1"
|
|
assert model.runId == "r1"
|
|
assert model.parentRunId is None
|
|
assert model.state == {}
|
|
assert model.messages == []
|
|
assert model.tools == []
|
|
assert model.context == []
|
|
assert model.forwardedProps == {}
|
|
assert model.resume is None
|
|
|
|
def test_resume_optional(self):
|
|
payload = {
|
|
"threadId": "t1",
|
|
"runId": "r2",
|
|
"state": {},
|
|
"messages": [],
|
|
"tools": [],
|
|
"context": [],
|
|
"forwardedProps": {},
|
|
"resume": {"interruptId": "int-1", "payload": {"decision": "approved"}},
|
|
}
|
|
model = RunAgentInput.model_validate(payload)
|
|
assert model.resume is not None
|
|
assert model.resume["interruptId"] == "int-1"
|
|
assert model.resume["payload"]["decision"] == "approved"
|
|
|
|
def test_parent_run_id_optional(self):
|
|
payload = {
|
|
"threadId": "t1",
|
|
"runId": "r3",
|
|
"parentRunId": "p1",
|
|
"state": {"key": "value"},
|
|
"messages": [{"role": "user", "content": "hello"}],
|
|
"tools": [{"name": "ui.navigate_to"}],
|
|
"context": [{"type": "user", "id": "u1"}],
|
|
"forwardedProps": {"theme": "dark"},
|
|
}
|
|
model = RunAgentInput.model_validate(payload)
|
|
assert model.parentRunId == "p1"
|
|
assert model.state == {"key": "value"}
|
|
assert len(model.messages) == 1
|
|
assert model.messages[0]["role"] == "user"
|
|
|
|
|
|
class TestAgentSessionSnapshot:
|
|
def test_state_snapshot_v2_model_accepts_valid_payload(self):
|
|
payload = {
|
|
"version": 2,
|
|
"pending_tool_call": {
|
|
"interrupt_id": "int-1",
|
|
"tool_name": "srv.transfer_funds",
|
|
"tool_args": {"to": "u2", "amount": 100},
|
|
"status": "PENDING_APPROVAL",
|
|
"expires_at": "2026-03-03T12:00:00Z",
|
|
"decision": None,
|
|
"result": None,
|
|
"updated_at": "2026-03-03T11:59:00Z",
|
|
},
|
|
"run_context": {"thread_id": "t1", "run_id": "r1"},
|
|
}
|
|
|
|
model = AgentSessionSnapshot.model_validate(payload)
|
|
|
|
assert model.version == 2
|
|
assert model.pending_tool_call is not None
|
|
assert model.pending_tool_call.interrupt_id == "int-1"
|
|
assert model.pending_tool_call.updated_at == datetime(
|
|
2026, 3, 3, 11, 59, tzinfo=timezone.utc
|
|
)
|
|
|
|
def test_state_snapshot_v2_rejects_wrong_version(self):
|
|
payload = {
|
|
"version": 1,
|
|
"pending_tool_call": None,
|
|
"run_context": {"thread_id": "t1", "run_id": "r1"},
|
|
}
|
|
|
|
with pytest.raises(ValueError):
|
|
AgentSessionSnapshot.model_validate(payload)
|
|
|
|
def test_state_snapshot_v2_requires_pending_tool_call_key(self):
|
|
payload = {
|
|
"version": 2,
|
|
"run_context": {"thread_id": "t1", "run_id": "r1"},
|
|
}
|
|
|
|
with pytest.raises(ValueError):
|
|
AgentSessionSnapshot.model_validate(payload)
|
|
|
|
def test_state_snapshot_v2_rejects_extra_fields(self):
|
|
payload = {
|
|
"version": 2,
|
|
"pending_tool_call": {
|
|
"interrupt_id": "int-1",
|
|
"tool_name": "srv.transfer_funds",
|
|
"tool_args": {"to": "u2", "amount": 100},
|
|
"status": "PENDING_APPROVAL",
|
|
"expires_at": "2026-03-03T12:00:00Z",
|
|
"decision": None,
|
|
"result": None,
|
|
"updated_at": "2026-03-03T11:59:00Z",
|
|
"unexpected": True,
|
|
},
|
|
"run_context": {"thread_id": "t1", "run_id": "r1", "foo": "bar"},
|
|
}
|
|
|
|
with pytest.raises(ValueError):
|
|
AgentSessionSnapshot.model_validate(payload)
|