From 878d9aa4ab1b7088b8c04538537243ebcb83db30 Mon Sep 17 00:00:00 2001 From: Abhinav-kodes <183825080+Abhinav-kodes@users.noreply.github.com> Date: Sun, 10 May 2026 01:44:53 +0530 Subject: [PATCH 1/3] fix(sdk-python): correct router port and bootstrap session race - Fix hardcoded port 18081 to 8081 in agent_runtime_usage.py to match the default kubectl port-forward mapping (8081:8080) - Fix bootstrap_session_id() to read x-agentcube-session-id header before raise_for_status(); router injects header even on non-2xx responses (e.g. 404 for GET / on agents that only handle POST) - Downgrade log level to debug for non-2xx bootstrap with valid session - Enrich ValueError message with status code and response body snippet - Fix missing status_code in bootstrap mock test Signed-off-by: Abhinav Singh Signed-off-by: Abhinav-kodes <183825080+Abhinav-kodes@users.noreply.github.com> --- .../clients/agent_runtime_data_plane.py | 19 ++++++++++++------- sdk-python/examples/agent_runtime_usage.py | 4 ++-- sdk-python/tests/test_agent_runtime.py | 1 + 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/sdk-python/agentcube/clients/agent_runtime_data_plane.py b/sdk-python/agentcube/clients/agent_runtime_data_plane.py index 01f83f66..cec24da5 100644 --- a/sdk-python/agentcube/clients/agent_runtime_data_plane.py +++ b/sdk-python/agentcube/clients/agent_runtime_data_plane.py @@ -56,14 +56,19 @@ def bootstrap_session_id(self) -> str: self.base_url, timeout=(self.connect_timeout, self.timeout), ) - resp.raise_for_status() - session_id = resp.headers.get(self.SESSION_HEADER) - if not session_id: - raise ValueError( - f"Missing required response header: {self.SESSION_HEADER}" - ) - return session_id + if session_id: + if resp.status_code >= 400: + self.logger.warning( + f"Bootstrap request returned status {resp.status_code}, " + f"but session ID was found: {session_id}" + ) + return session_id + resp.raise_for_status() + raise ValueError( + f"Missing required response header: {self.SESSION_HEADER} " + f"(Status: {resp.status_code}, Response: {resp.text[:100]})" + ) def invoke( self, diff --git a/sdk-python/examples/agent_runtime_usage.py b/sdk-python/examples/agent_runtime_usage.py index fbaa228a..e997d44f 100644 --- a/sdk-python/examples/agent_runtime_usage.py +++ b/sdk-python/examples/agent_runtime_usage.py @@ -17,7 +17,7 @@ # first time: it will create a new pod agent_client_v1 = AgentRuntimeClient( agent_name="my-agent", - router_url="http://localhost:18081", + router_url="http://localhost:8081", namespace="default", verbose=True, ) @@ -31,7 +31,7 @@ # second time: it will try to reuse the pod created before agent_client_v2 = AgentRuntimeClient( agent_name="my-agent", - router_url="http://localhost:18081", + router_url="http://localhost:8081", namespace="default", session_id=agent_client_v1.session_id, verbose=True, diff --git a/sdk-python/tests/test_agent_runtime.py b/sdk-python/tests/test_agent_runtime.py index f9c36abd..31076ca9 100644 --- a/sdk-python/tests/test_agent_runtime.py +++ b/sdk-python/tests/test_agent_runtime.py @@ -95,6 +95,7 @@ class TestAgentRuntimeDataPlaneClient(unittest.TestCase): def test_bootstrap_session_id_extracts_header(self, mock_create_session): sess = Mock() resp = Mock() + resp.status_code = 200 resp.raise_for_status.return_value = None resp.headers = {"x-agentcube-session-id": "abc"} sess.get.return_value = resp From 19a6f521f7ca085ed43da0ea2edb0be8feb26f13 Mon Sep 17 00:00:00 2001 From: Abhinav Singh Date: Sun, 10 May 2026 09:34:50 +0530 Subject: [PATCH 2/3] test(sdk-python): add non-2xx bootstrap session coverage Signed-off-by: Abhinav Singh --- sdk-python/tests/test_agent_runtime.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sdk-python/tests/test_agent_runtime.py b/sdk-python/tests/test_agent_runtime.py index 31076ca9..849c2778 100644 --- a/sdk-python/tests/test_agent_runtime.py +++ b/sdk-python/tests/test_agent_runtime.py @@ -110,6 +110,26 @@ def test_bootstrap_session_id_extracts_header(self, mock_create_session): ) self.assertEqual(client.bootstrap_session_id(), "abc") + @patch("agentcube.clients.agent_runtime_data_plane.create_session") + def test_bootstrap_session_id_returns_header_on_non_2xx(self, mock_create_session): + sess = Mock() + resp = Mock() + resp.status_code = 404 + resp.raise_for_status.side_effect = requests.exceptions.HTTPError(response=resp) + resp.headers = {"x-agentcube-session-id": "session-from-404"} + sess.get.return_value = resp + mock_create_session.return_value = sess + + from agentcube.clients.agent_runtime_data_plane import AgentRuntimeDataPlaneClient + + client = AgentRuntimeDataPlaneClient( + router_url="http://router", + namespace="default", + agent_name="agent-a", + ) + self.assertEqual(client.bootstrap_session_id(), "session-from-404") + resp.raise_for_status.assert_not_called() + @patch("agentcube.clients.agent_runtime_data_plane.create_session") def test_invoke_sends_session_header(self, mock_create_session): sess = Mock() From b46aed0d65aaa56631f1b620cdad5dcafd7bde45 Mon Sep 17 00:00:00 2001 From: Abhinav Singh Date: Sun, 10 May 2026 09:55:18 +0530 Subject: [PATCH 3/3] fix(sdk-python): downgrade bootstrap log to debug, avoid resp.text in error Signed-off-by: Abhinav Singh --- sdk-python/agentcube/clients/agent_runtime_data_plane.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sdk-python/agentcube/clients/agent_runtime_data_plane.py b/sdk-python/agentcube/clients/agent_runtime_data_plane.py index cec24da5..00eadec3 100644 --- a/sdk-python/agentcube/clients/agent_runtime_data_plane.py +++ b/sdk-python/agentcube/clients/agent_runtime_data_plane.py @@ -59,15 +59,19 @@ def bootstrap_session_id(self) -> str: session_id = resp.headers.get(self.SESSION_HEADER) if session_id: if resp.status_code >= 400: - self.logger.warning( + self.logger.debug( f"Bootstrap request returned status {resp.status_code}, " f"but session ID was found: {session_id}" ) return session_id resp.raise_for_status() + content_type = resp.headers.get("Content-Type") + content_length = resp.headers.get("Content-Length") raise ValueError( f"Missing required response header: {self.SESSION_HEADER} " - f"(Status: {resp.status_code}, Response: {resp.text[:100]})" + f"(status: {resp.status_code}, " + f"content-type: {content_type}, " + f"content-length: {content_length})" ) def invoke(