Skip to content

Commit dc0297e

Browse files
committed
test: assert protocol mismatch fails without retries
1 parent e996954 commit dc0297e

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

swe_af/agent_ai/providers/claude/client.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@
6262
}
6363
)
6464

65+
# Keep in sync with dependency pins in pyproject/requirements.
66+
_STABLE_SDK_VERSION = "0.1.20"
67+
6568
DEFAULT_TOOLS: list[str] = [
6669
Tool.READ,
6770
Tool.WRITE,
@@ -76,8 +79,6 @@
7679

7780
def _is_transient(error: str) -> bool:
7881
if _is_sdk_protocol_error(error):
79-
# Protocol/schema mismatch between SDK and upstream event stream
80-
# is deterministic and should fail fast with guidance.
8182
return False
8283
low = error.lower()
8384
return any(p in low for p in _TRANSIENT_PATTERNS)
@@ -101,7 +102,7 @@ def _build_sdk_protocol_error_message(raw_error: str, *, sdk_version: str | None
101102
f"{raw_error}. "
102103
f"Detected claude-agent-sdk version={version}. "
103104
"This is a known stream compatibility failure in some SDK versions. "
104-
"Use claude-agent-sdk==0.1.20 for SWE-AF stability."
105+
f"Use claude-agent-sdk=={_STABLE_SDK_VERSION} for SWE-AF stability."
105106
)
106107

107108

@@ -420,7 +421,7 @@ async def _run_with_retries(
420421

421422
last_exc = e
422423
_captured_stderr = "\n".join(stderr_lines[-50:]) if stderr_lines else ""
423-
if attempt < effective_retries and _is_transient(str(e)):
424+
if attempt < effective_retries and _is_transient(raw_error):
424425
if log_fh:
425426
_write_log(
426427
log_fh,

tests/test_claude_provider_compat.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import unittest
2+
from unittest.mock import AsyncMock
23

4+
from claude_agent_sdk import ClaudeAgentOptions
35
from swe_af.agent_ai.providers.claude.client import (
6+
ClaudeProviderClient,
47
_build_sdk_protocol_error_message,
58
_is_sdk_protocol_error,
69
_is_transient,
@@ -22,6 +25,36 @@ def test_protocol_error_message_contains_sdk_guidance(self) -> None:
2225
self.assertIn("version=0.1.39", msg)
2326
self.assertIn("claude-agent-sdk==0.1.20", msg)
2427

28+
def test_protocol_error_fails_fast_without_retries(self) -> None:
29+
err = "Unknown message type: rate_limit_event"
30+
client = ClaudeProviderClient()
31+
client._execute = AsyncMock(side_effect=RuntimeError(err))
32+
options = ClaudeAgentOptions(model="sonnet", cwd=".", max_turns=1)
33+
34+
async def _run() -> None:
35+
await client._run_with_retries(
36+
prompt="test",
37+
final_prompt="test",
38+
options=options,
39+
output_schema=None,
40+
output_path=None,
41+
effective_cwd=".",
42+
effective_model="sonnet",
43+
effective_env={},
44+
effective_perm=None,
45+
effective_retries=3,
46+
temp_files=[],
47+
stderr_lines=[],
48+
)
49+
50+
with self.assertRaises(RuntimeError) as ctx:
51+
import asyncio
52+
53+
asyncio.run(_run())
54+
55+
self.assertIn("claude-agent-sdk==0.1.20", str(ctx.exception))
56+
self.assertEqual(client._execute.await_count, 1)
57+
2558

2659
if __name__ == "__main__":
2760
unittest.main()

0 commit comments

Comments
 (0)