Skip to content

Commit 6384c69

Browse files
qing-antclaude
andauthored
fix: remove duplicate version warning and include CLI path (#720)
## Summary Two small fixes to the CLI version warning in `_check_claude_version()`: 1. **Remove duplicate output** — The warning was emitted twice: once via `logger.warning()` and again via `print(..., file=sys.stderr)`. Users saw the same message repeated. Now only `logger.warning()` is used, which is the standard library approach for warning output. 2. **Include CLI path in the warning** — When the version is below minimum, the warning now shows which CLI binary was found (e.g., `/opt/node22/bin/claude`), making it easier to diagnose when multiple CLI installations exist. Fixes #359, fixes #360 ## Changes - `subprocess_cli.py`: Replace `print()` + `logger.warning(f"...")` with a single `logger.warning("...", ...)` using lazy `%s` formatting - `subprocess_cli.py`: Remove now-unused `import sys` - `test_transport.py`: Add two regression tests: - `test_version_warning_includes_cli_path` — verifies the warning includes version and CLI path, and that `print()` is not called - `test_version_warning_not_emitted_for_current_version` — verifies no warning for versions at or above minimum ## Verification - All 329 tests pass (`pytest tests/`) - Lint clean (`ruff check src/ tests/`) - Type check clean (`mypy src/`) - E2E verified with live SDK instance (v0.1.50, CLI 2.1.83) — query completes successfully Co-authored-by: Claude <noreply@anthropic.com>
1 parent d3d71fb commit 6384c69

2 files changed

Lines changed: 80 additions & 7 deletions

File tree

src/claude_agent_sdk/_internal/transport/subprocess_cli.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import platform
77
import re
88
import shutil
9-
import sys
109
from collections.abc import AsyncIterable, AsyncIterator
1110
from contextlib import suppress
1211
from pathlib import Path
@@ -625,13 +624,14 @@ async def _check_claude_version(self) -> None:
625624
]
626625

627626
if version_parts < min_parts:
628-
warning = (
629-
f"Warning: Claude Code version {version} is unsupported in the Agent SDK. "
630-
f"Minimum required version is {MINIMUM_CLAUDE_CODE_VERSION}. "
631-
"Some features may not work correctly."
627+
logger.warning(
628+
"Claude Code version %s at %s is unsupported in the Agent SDK. "
629+
"Minimum required version is %s. "
630+
"Some features may not work correctly.",
631+
version,
632+
self._cli_path,
633+
MINIMUM_CLAUDE_CODE_VERSION,
632634
)
633-
logger.warning(warning)
634-
print(warning, file=sys.stderr)
635635
except Exception:
636636
pass
637637
finally:

tests/test_transport.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,3 +1064,76 @@ def test_build_command_large_agents_work(self):
10641064
# No @filepath references should exist
10651065
cmd_str = " ".join(cmd)
10661066
assert "@" not in cmd_str
1067+
1068+
def test_version_warning_includes_cli_path(self):
1069+
"""Test that the version warning includes the CLI path and uses only logger.warning."""
1070+
1071+
async def _test():
1072+
transport = SubprocessCLITransport(
1073+
prompt="test",
1074+
options=make_options(),
1075+
)
1076+
1077+
with (
1078+
patch("anyio.open_process") as mock_exec,
1079+
patch(
1080+
"claude_agent_sdk._internal.transport.subprocess_cli.logger"
1081+
) as mock_logger,
1082+
patch("builtins.print") as mock_print,
1083+
):
1084+
# Mock version check returning an old version
1085+
mock_version_process = MagicMock()
1086+
mock_version_process.stdout = MagicMock()
1087+
mock_version_process.stdout.receive = AsyncMock(
1088+
return_value=b"1.0.0 (Claude Code)"
1089+
)
1090+
mock_version_process.terminate = MagicMock()
1091+
mock_version_process.wait = AsyncMock()
1092+
1093+
mock_exec.return_value = mock_version_process
1094+
1095+
await transport._check_claude_version()
1096+
1097+
# logger.warning should be called with version and CLI path
1098+
mock_logger.warning.assert_called_once()
1099+
args, _ = mock_logger.warning.call_args
1100+
assert args[1] == "1.0.0"
1101+
assert args[2] == DEFAULT_CLI_PATH
1102+
1103+
# print should NOT be called (no duplicate output)
1104+
mock_print.assert_not_called()
1105+
1106+
anyio.run(_test)
1107+
1108+
def test_version_warning_not_emitted_for_current_version(self):
1109+
"""Test that no warning is emitted when CLI version meets minimum."""
1110+
1111+
async def _test():
1112+
transport = SubprocessCLITransport(
1113+
prompt="test",
1114+
options=make_options(),
1115+
)
1116+
1117+
with (
1118+
patch("anyio.open_process") as mock_exec,
1119+
patch(
1120+
"claude_agent_sdk._internal.transport.subprocess_cli.logger"
1121+
) as mock_logger,
1122+
):
1123+
# Mock version check returning a current version
1124+
mock_version_process = MagicMock()
1125+
mock_version_process.stdout = MagicMock()
1126+
mock_version_process.stdout.receive = AsyncMock(
1127+
return_value=b"99.99.99 (Claude Code)"
1128+
)
1129+
mock_version_process.terminate = MagicMock()
1130+
mock_version_process.wait = AsyncMock()
1131+
1132+
mock_exec.return_value = mock_version_process
1133+
1134+
await transport._check_claude_version()
1135+
1136+
# No warning for a current version
1137+
mock_logger.warning.assert_not_called()
1138+
1139+
anyio.run(_test)

0 commit comments

Comments
 (0)