Skip to content

Commit f59f26d

Browse files
fix(adk): re-send task_id/agent_id in state updates for backend compatibility (#405)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 23858df commit f59f26d

2 files changed

Lines changed: 72 additions & 0 deletions

File tree

src/agentex/lib/core/services/adk/state.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,12 @@ async def update_state(
9898
"state": state,
9999
},
100100
) as span:
101+
# Send task_id/agent_id in the body for backends predating
102+
# scale-agentex#278, which still require them (newer ones ignore them).
101103
state_model = await self._agentex_client.states.update(
102104
state_id=state_id,
103105
state=state,
106+
extra_body={"task_id": task_id, "agent_id": agent_id},
104107
)
105108
if span:
106109
span.output = state_model.model_dump()
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""Tests for StateService forwarding task_id/agent_id to the SDK client.
2+
3+
Regression guard for the 0.13.0 incident: the generated client dropped
4+
task_id/agent_id from states.update(), so the ADK stopped sending them in the
5+
body and every state write 422'd against backends predating scale-agentex#278.
6+
"""
7+
8+
from __future__ import annotations
9+
10+
from datetime import datetime, timezone
11+
from unittest.mock import Mock, AsyncMock
12+
13+
from agentex.types.state import State
14+
from agentex.lib.core.services.adk.state import StateService
15+
16+
_TS = datetime(2026, 5, 13, 18, 30, 0, tzinfo=timezone.utc)
17+
18+
19+
def _make_state() -> State:
20+
return State(
21+
id="s1",
22+
agent_id="a1",
23+
task_id="t1",
24+
state={"k": "v"},
25+
created_at=_TS,
26+
)
27+
28+
29+
def _mock_span():
30+
span = Mock()
31+
span.output = None
32+
33+
async def __aenter__(_self):
34+
return span
35+
36+
async def __aexit__(_self, *args):
37+
return None
38+
39+
span.__aenter__ = __aenter__
40+
span.__aexit__ = __aexit__
41+
return span
42+
43+
44+
def _make_service() -> tuple[AsyncMock, StateService]:
45+
client = AsyncMock()
46+
tracer = Mock()
47+
trace = Mock()
48+
trace.span.return_value = _mock_span()
49+
tracer.trace.return_value = trace
50+
return client, StateService(agentex_client=client, tracer=tracer)
51+
52+
53+
class TestUpdateStateSendsParentIdentifiers:
54+
async def test_task_id_and_agent_id_sent_in_body(self) -> None:
55+
client, svc = _make_service()
56+
client.states.update.return_value = _make_state()
57+
58+
await svc.update_state(
59+
state_id="s1",
60+
task_id="t1",
61+
agent_id="a1",
62+
state={"k": "v"},
63+
)
64+
65+
kwargs = client.states.update.call_args.kwargs
66+
assert kwargs["state_id"] == "s1"
67+
# task_id/agent_id must ride in extra_body — the generated client dropped
68+
# them from the typed signature, but old backends still require them.
69+
assert kwargs["extra_body"] == {"task_id": "t1", "agent_id": "a1"}

0 commit comments

Comments
 (0)