From 4acfcc2d399f71647a4186c2e3948d624cc4e3be Mon Sep 17 00:00:00 2001 From: sarahdeaton Date: Tue, 9 Dec 2025 09:33:42 -0800 Subject: [PATCH 01/18] Add license and terms section to README. (#399) Add "License and terms" section to README clarifying that use of the SDK is governed by Anthropic's Commercial Terms of Service --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2111986..bcbe969 100644 --- a/README.md +++ b/README.md @@ -351,6 +351,6 @@ The package is published to PyPI via the GitHub Actions workflow in `.github/wor The workflow tracks both the package version and the bundled CLI version separately, allowing you to release a new package version with an updated CLI without code changes. -## License +## License and terms -MIT +Use of this SDK is governed by Anthropic's [Commercial Terms of Service](https://www.anthropic.com/legal/commercial-terms), including when you use it to power products and services that you make available to your own customers and end users, except to the extent a specific component or dependency is covered by a different license as indicated in that component's LICENSE file. From 53482d8955565197261a393859fd4813dd62cb2b Mon Sep 17 00:00:00 2001 From: Noah Zweben Date: Tue, 9 Dec 2025 10:16:03 -0800 Subject: [PATCH 02/18] feat: add file checkpointing and rewind_files support (#395) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Add `enable_file_checkpointing` option to `ClaudeAgentOptions` - Add `rewind_files(user_message_id)` method to `ClaudeSDKClient` and `Query` - Add `SDKControlRewindFilesRequest` type for the control protocol - Set `CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING` env var when enabled This adds Python SDK support for the file rewind feature from claude-cli-internal PR #11265. ## Test plan - [x] Verified imports work correctly - [x] Verified linting passes (`ruff check`) - [x] Verified existing tests still pass (106 passed, pre-existing failures unrelated to this change) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Co-authored-by: Ashwin Bhat --- src/claude_agent_sdk/_internal/query.py | 15 +++++++++++ .../_internal/transport/subprocess_cli.py | 4 +++ src/claude_agent_sdk/client.py | 27 +++++++++++++++++++ src/claude_agent_sdk/types.py | 10 +++++++ 4 files changed, 56 insertions(+) diff --git a/src/claude_agent_sdk/_internal/query.py b/src/claude_agent_sdk/_internal/query.py index 8f0ac19..c30fc15 100644 --- a/src/claude_agent_sdk/_internal/query.py +++ b/src/claude_agent_sdk/_internal/query.py @@ -539,6 +539,21 @@ class Query: } ) + async def rewind_files(self, user_message_id: str) -> None: + """Rewind tracked files to their state at a specific user message. + + Requires file checkpointing to be enabled via the `enable_file_checkpointing` option. + + Args: + user_message_id: UUID of the user message to rewind to + """ + await self._send_control_request( + { + "subtype": "rewind_files", + "user_message_id": user_message_id, + } + ) + async def stream_input(self, stream: AsyncIterable[dict[str, Any]]) -> None: """Stream input messages to transport. diff --git a/src/claude_agent_sdk/_internal/transport/subprocess_cli.py b/src/claude_agent_sdk/_internal/transport/subprocess_cli.py index c7c7420..a4882db 100644 --- a/src/claude_agent_sdk/_internal/transport/subprocess_cli.py +++ b/src/claude_agent_sdk/_internal/transport/subprocess_cli.py @@ -384,6 +384,10 @@ class SubprocessCLITransport(Transport): "CLAUDE_AGENT_SDK_VERSION": __version__, } + # Enable file checkpointing if requested + if self._options.enable_file_checkpointing: + process_env["CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING"] = "true" + if self._cwd: process_env["PWD"] = self._cwd diff --git a/src/claude_agent_sdk/client.py b/src/claude_agent_sdk/client.py index 742d7d6..2f74260 100644 --- a/src/claude_agent_sdk/client.py +++ b/src/claude_agent_sdk/client.py @@ -261,6 +261,33 @@ class ClaudeSDKClient: raise CLIConnectionError("Not connected. Call connect() first.") await self._query.set_model(model) + async def rewind_files(self, user_message_id: str) -> None: + """Rewind tracked files to their state at a specific user message. + + Requires file checkpointing to be enabled via the `enable_file_checkpointing` option + when creating the ClaudeSDKClient. + + Args: + user_message_id: UUID of the user message to rewind to. This should be + the `uuid` field from a `UserMessage` received during the conversation. + + Example: + ```python + options = ClaudeAgentOptions(enable_file_checkpointing=True) + async with ClaudeSDKClient(options) as client: + await client.query("Make some changes to my files") + async for msg in client.receive_response(): + if isinstance(msg, UserMessage): + checkpoint_id = msg.uuid # Save this for later + + # Later, rewind to that point + await client.rewind_files(checkpoint_id) + ``` + """ + if not self._query: + raise CLIConnectionError("Not connected. Call connect() first.") + await self._query.rewind_files(user_message_id) + async def get_server_info(self) -> dict[str, Any] | None: """Get server initialization info including available commands and output styles. diff --git a/src/claude_agent_sdk/types.py b/src/claude_agent_sdk/types.py index fa6ca35..6d71322 100644 --- a/src/claude_agent_sdk/types.py +++ b/src/claude_agent_sdk/types.py @@ -673,6 +673,10 @@ class ClaudeAgentOptions: # Output format for structured outputs (matches Messages API structure) # Example: {"type": "json_schema", "schema": {"type": "object", "properties": {...}}} output_format: dict[str, Any] | None = None + # Enable file checkpointing to track file changes during the session. + # When enabled, files can be rewound to their state at any user message + # using `ClaudeSDKClient.rewind_files()`. + enable_file_checkpointing: bool = False # SDK Control Protocol @@ -713,6 +717,11 @@ class SDKControlMcpMessageRequest(TypedDict): message: Any +class SDKControlRewindFilesRequest(TypedDict): + subtype: Literal["rewind_files"] + user_message_id: str + + class SDKControlRequest(TypedDict): type: Literal["control_request"] request_id: str @@ -723,6 +732,7 @@ class SDKControlRequest(TypedDict): | SDKControlSetPermissionModeRequest | SDKHookCallbackRequest | SDKControlMcpMessageRequest + | SDKControlRewindFilesRequest ) From 5b912962e200fbd37b8c872b443c57abfb05085d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 10:53:45 -0800 Subject: [PATCH 03/18] chore: release v0.1.15 (#408) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR updates the version to 0.1.15 after publishing to PyPI. ## Changes - Updated version in `pyproject.toml` to 0.1.15 - Updated version in `src/claude_agent_sdk/_version.py` to 0.1.15 - Updated `CHANGELOG.md` with release notes ## Release Information - Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.15/ - Bundled CLI version: 2.0.62 - Install with: `pip install claude-agent-sdk==0.1.15` 🤖 Generated by GitHub Actions --------- Co-authored-by: github-actions[bot] Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude --- CHANGELOG.md | 10 ++++++++++ pyproject.toml | 2 +- src/claude_agent_sdk/_version.py | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32775ae..f492776 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 0.1.15 + +### New Features + +- **File checkpointing and rewind**: Added `enable_file_checkpointing` option to `ClaudeAgentOptions` and `rewind_files(user_message_id)` method to `ClaudeSDKClient` and `Query`. This enables reverting file changes made during a session back to a specific checkpoint, useful for exploring different approaches or recovering from unwanted modifications (#395) + +### Documentation + +- Added license and terms section to README (#399) + ## 0.1.14 ### Internal/Other Changes diff --git a/pyproject.toml b/pyproject.toml index 5e39d17..10b0bad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "claude-agent-sdk" -version = "0.1.14" +version = "0.1.15" description = "Python SDK for Claude Code" readme = "README.md" requires-python = ">=3.10" diff --git a/src/claude_agent_sdk/_version.py b/src/claude_agent_sdk/_version.py index b02a634..d9b37ab 100644 --- a/src/claude_agent_sdk/_version.py +++ b/src/claude_agent_sdk/_version.py @@ -1,3 +1,3 @@ """Version information for claude-agent-sdk.""" -__version__ = "0.1.14" +__version__ = "0.1.15" From 3cbb9e56be1f5b947d640f0b05710d7d032781be Mon Sep 17 00:00:00 2001 From: lif <1835304752@qq.com> Date: Fri, 12 Dec 2025 02:55:01 +0800 Subject: [PATCH 04/18] fix: parse error field in AssistantMessage to enable rate limit detection (#405) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes #401 Enables applications to detect API errors (especially `rate_limit` errors) by properly parsing the `error` field in `AssistantMessage`. ## Problem The SDK defines `AssistantMessage.error` (including `"rate_limit"`), but the message parser never extracted this field from the CLI response. This made it impossible for applications to: - Detect when rate limits are hit - Implement retry logic - Handle other API errors gracefully ## Solution Added error field extraction in the message parser: ```python return AssistantMessage( content=content_blocks, model=data["message"]["model"], parent_tool_use_id=data.get("parent_tool_use_id"), error=data["message"].get("error"), # ← Now extracts error field ) ``` ## Changes **Modified: `src/claude_agent_sdk/_internal/message_parser.py`** The parser now extracts the `error` field from API responses and populates it in the `AssistantMessage` object. ## Usage Example Applications can now detect and handle rate limits: ```python async for message in client.receive_response(): if isinstance(message, AssistantMessage): if message.error == "rate_limit": print("Rate limit hit! Implementing backoff...") await asyncio.sleep(60) # Retry logic here elif message.error: print(f"API error: {message.error}") ``` ## Testing - ✅ Passed ruff linting and formatting - ✅ Passed mypy type checking - ✅ All existing tests pass ## Type of Change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) ## Impact This fix enables production applications to: - Implement proper error handling for API errors - Build robust retry logic for rate limits - Provide better user feedback when errors occur - Avoid silent failures when the API returns errors --- 🤖 Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy Co-authored-by: Claude Co-authored-by: Happy --- src/claude_agent_sdk/_internal/message_parser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/claude_agent_sdk/_internal/message_parser.py b/src/claude_agent_sdk/_internal/message_parser.py index 694c52c..312e4c0 100644 --- a/src/claude_agent_sdk/_internal/message_parser.py +++ b/src/claude_agent_sdk/_internal/message_parser.py @@ -120,6 +120,7 @@ def parse_message(data: dict[str, Any]) -> Message: content=content_blocks, model=data["message"]["model"], parent_tool_use_id=data.get("parent_tool_use_id"), + error=data["message"].get("error"), ) except KeyError as e: raise MessageParseError( From d2b3477a4e527d4e3934bda91bcd93392e432d0b Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 12 Dec 2025 23:32:48 +0000 Subject: [PATCH 05/18] chore: bump bundled CLI version to 2.0.68 --- src/claude_agent_sdk/_cli_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/claude_agent_sdk/_cli_version.py b/src/claude_agent_sdk/_cli_version.py index 4f74ef2..06930ab 100644 --- a/src/claude_agent_sdk/_cli_version.py +++ b/src/claude_agent_sdk/_cli_version.py @@ -1,3 +1,3 @@ """Bundled Claude Code CLI version.""" -__cli_version__ = "2.0.62" +__cli_version__ = "2.0.68" From a1c338726f25f887cfed2e45eea7bd5049ea9cbf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 16:26:36 -0800 Subject: [PATCH 06/18] chore: release v0.1.16 (#412) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR updates the version to 0.1.16 after publishing to PyPI. ## Changes - Updated version in `pyproject.toml` to 0.1.16 - Updated version in `src/claude_agent_sdk/_version.py` to 0.1.16 - Updated `CHANGELOG.md` with release notes ## Release Information - Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.16/ - Bundled CLI version: 2.0.68 - Install with: `pip install claude-agent-sdk==0.1.16` 🤖 Generated by GitHub Actions --------- Co-authored-by: github-actions[bot] Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude --- CHANGELOG.md | 10 ++++++++++ pyproject.toml | 2 +- src/claude_agent_sdk/_version.py | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f492776..e252c83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 0.1.16 + +### Bug Fixes + +- **Rate limit detection**: Fixed parsing of the `error` field in `AssistantMessage`, enabling applications to detect and handle API errors like rate limits. Previously, the `error` field was defined but never populated from CLI responses (#405) + +### Internal/Other Changes + +- Updated bundled Claude CLI to version 2.0.68 + ## 0.1.15 ### New Features diff --git a/pyproject.toml b/pyproject.toml index 10b0bad..84f6172 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "claude-agent-sdk" -version = "0.1.15" +version = "0.1.16" description = "Python SDK for Claude Code" readme = "README.md" requires-python = ">=3.10" diff --git a/src/claude_agent_sdk/_version.py b/src/claude_agent_sdk/_version.py index d9b37ab..4fd71fa 100644 --- a/src/claude_agent_sdk/_version.py +++ b/src/claude_agent_sdk/_version.py @@ -1,3 +1,3 @@ """Version information for claude-agent-sdk.""" -__version__ = "0.1.15" +__version__ = "0.1.16" From f834ba9e1586ea2e31353fafcb41f78b7b9eab51 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 13 Dec 2025 01:00:44 +0000 Subject: [PATCH 07/18] chore: bump bundled CLI version to 2.0.69 --- src/claude_agent_sdk/_cli_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/claude_agent_sdk/_cli_version.py b/src/claude_agent_sdk/_cli_version.py index 06930ab..079e323 100644 --- a/src/claude_agent_sdk/_cli_version.py +++ b/src/claude_agent_sdk/_cli_version.py @@ -1,3 +1,3 @@ """Bundled Claude Code CLI version.""" -__cli_version__ = "2.0.68" +__cli_version__ = "2.0.69" From 0ae5c3285c0f9b58c3430d609ed839701f9b8874 Mon Sep 17 00:00:00 2001 From: Noah Zweben Date: Mon, 15 Dec 2025 09:03:58 -0800 Subject: [PATCH 08/18] Add UUID to UserMessage response type to improve devX for rewind (#418) --- src/claude_agent_sdk/_internal/message_parser.py | 3 +++ src/claude_agent_sdk/client.py | 13 +++++++++---- src/claude_agent_sdk/types.py | 1 + tests/test_message_parser.py | 15 +++++++++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/claude_agent_sdk/_internal/message_parser.py b/src/claude_agent_sdk/_internal/message_parser.py index 312e4c0..4bfe814 100644 --- a/src/claude_agent_sdk/_internal/message_parser.py +++ b/src/claude_agent_sdk/_internal/message_parser.py @@ -48,6 +48,7 @@ def parse_message(data: dict[str, Any]) -> Message: case "user": try: parent_tool_use_id = data.get("parent_tool_use_id") + uuid = data.get("uuid") if isinstance(data["message"]["content"], list): user_content_blocks: list[ContentBlock] = [] for block in data["message"]["content"]: @@ -74,10 +75,12 @@ def parse_message(data: dict[str, Any]) -> Message: ) return UserMessage( content=user_content_blocks, + uuid=uuid, parent_tool_use_id=parent_tool_use_id, ) return UserMessage( content=data["message"]["content"], + uuid=uuid, parent_tool_use_id=parent_tool_use_id, ) except KeyError as e: diff --git a/src/claude_agent_sdk/client.py b/src/claude_agent_sdk/client.py index 2f74260..18ab818 100644 --- a/src/claude_agent_sdk/client.py +++ b/src/claude_agent_sdk/client.py @@ -264,8 +264,10 @@ class ClaudeSDKClient: async def rewind_files(self, user_message_id: str) -> None: """Rewind tracked files to their state at a specific user message. - Requires file checkpointing to be enabled via the `enable_file_checkpointing` option - when creating the ClaudeSDKClient. + Requires: + - `enable_file_checkpointing=True` to track file changes + - `extra_args={"replay-user-messages": None}` to receive UserMessage + objects with `uuid` in the response stream Args: user_message_id: UUID of the user message to rewind to. This should be @@ -273,11 +275,14 @@ class ClaudeSDKClient: Example: ```python - options = ClaudeAgentOptions(enable_file_checkpointing=True) + options = ClaudeAgentOptions( + enable_file_checkpointing=True, + extra_args={"replay-user-messages": None}, + ) async with ClaudeSDKClient(options) as client: await client.query("Make some changes to my files") async for msg in client.receive_response(): - if isinstance(msg, UserMessage): + if isinstance(msg, UserMessage) and msg.uuid: checkpoint_id = msg.uuid # Save this for later # Later, rewind to that point diff --git a/src/claude_agent_sdk/types.py b/src/claude_agent_sdk/types.py index 6d71322..9c09345 100644 --- a/src/claude_agent_sdk/types.py +++ b/src/claude_agent_sdk/types.py @@ -562,6 +562,7 @@ class UserMessage: """User message.""" content: str | list[ContentBlock] + uuid: str | None = None parent_tool_use_id: str | None = None diff --git a/tests/test_message_parser.py b/tests/test_message_parser.py index 60bcc53..cd18952 100644 --- a/tests/test_message_parser.py +++ b/tests/test_message_parser.py @@ -31,6 +31,21 @@ class TestMessageParser: assert isinstance(message.content[0], TextBlock) assert message.content[0].text == "Hello" + def test_parse_user_message_with_uuid(self): + """Test parsing a user message with uuid field (issue #414). + + The uuid field is needed for file checkpointing with rewind_files(). + """ + data = { + "type": "user", + "uuid": "msg-abc123-def456", + "message": {"content": [{"type": "text", "text": "Hello"}]}, + } + message = parse_message(data) + assert isinstance(message, UserMessage) + assert message.uuid == "msg-abc123-def456" + assert len(message.content) == 1 + def test_parse_user_message_with_tool_use(self): """Test parsing a user message with tool_use block.""" data = { From 5752f38834373998800d58f10f745716d76b6102 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 15 Dec 2025 23:52:59 +0000 Subject: [PATCH 09/18] chore: bump bundled CLI version to 2.0.70 --- src/claude_agent_sdk/_cli_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/claude_agent_sdk/_cli_version.py b/src/claude_agent_sdk/_cli_version.py index 079e323..6309e4c 100644 --- a/src/claude_agent_sdk/_cli_version.py +++ b/src/claude_agent_sdk/_cli_version.py @@ -1,3 +1,3 @@ """Bundled Claude Code CLI version.""" -__cli_version__ = "2.0.69" +__cli_version__ = "2.0.70" From eba5675328703d47aa6210d6341a2fff9b06c43b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:41:49 -0800 Subject: [PATCH 10/18] chore: release v0.1.17 (#419) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR updates the version to 0.1.17 after publishing to PyPI. ## Changes - Updated version in `pyproject.toml` to 0.1.17 - Updated version in `src/claude_agent_sdk/_version.py` to 0.1.17 - Updated `CHANGELOG.md` with release notes ## Release Information - Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.17/ - Bundled CLI version: 2.0.70 - Install with: `pip install claude-agent-sdk==0.1.17` 🤖 Generated by GitHub Actions --------- Co-authored-by: github-actions[bot] Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude --- CHANGELOG.md | 10 ++++++++++ pyproject.toml | 2 +- src/claude_agent_sdk/_version.py | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e252c83..0b0ad22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 0.1.17 + +### New Features + +- **UserMessage UUID field**: Added `uuid` field to `UserMessage` response type, making it easier to use the `rewind_files()` method by providing direct access to message identifiers needed for file checkpointing (#418) + +### Internal/Other Changes + +- Updated bundled Claude CLI to version 2.0.70 + ## 0.1.16 ### Bug Fixes diff --git a/pyproject.toml b/pyproject.toml index 84f6172..0f3c76c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "claude-agent-sdk" -version = "0.1.16" +version = "0.1.17" description = "Python SDK for Claude Code" readme = "README.md" requires-python = ">=3.10" diff --git a/src/claude_agent_sdk/_version.py b/src/claude_agent_sdk/_version.py index 4fd71fa..e60bfef 100644 --- a/src/claude_agent_sdk/_version.py +++ b/src/claude_agent_sdk/_version.py @@ -1,3 +1,3 @@ """Version information for claude-agent-sdk.""" -__version__ = "0.1.16" +__version__ = "0.1.17" From 904c2ec33cc3339b480f47408b63771f57e521a3 Mon Sep 17 00:00:00 2001 From: Ashwin Bhat Date: Mon, 15 Dec 2025 16:53:23 -0800 Subject: [PATCH 11/18] chore: use CHANGELOG.md content for GitHub release notes (#420) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace auto-generated release notes with content extracted from CHANGELOG.md for the specific version being released. This provides more structured and consistent release notes with proper sections like Bug Fixes, New Features, etc. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude --- .github/workflows/create-release-tag.yml | 46 +++++++++++++++--------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/.github/workflows/create-release-tag.yml b/.github/workflows/create-release-tag.yml index 8d6b8e1..47f6c82 100644 --- a/.github/workflows/create-release-tag.yml +++ b/.github/workflows/create-release-tag.yml @@ -24,12 +24,6 @@ jobs: VERSION="${BRANCH_NAME#release/v}" echo "version=$VERSION" >> $GITHUB_OUTPUT - - name: Get previous release tag - id: previous_tag - run: | - PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "") - echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT - - name: Create and push tag run: | git config --local user.email "github-actions[bot]@users.noreply.github.com" @@ -46,14 +40,34 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - # Create release with auto-generated notes - gh release create "v${{ steps.extract_version.outputs.version }}" \ - --title "Release v${{ steps.extract_version.outputs.version }}" \ - --generate-notes \ - --notes-start-tag "${{ steps.previous_tag.outputs.previous_tag }}" \ - --notes "Published to PyPI: https://pypi.org/project/claude-agent-sdk/${{ steps.extract_version.outputs.version }}/ + VERSION="${{ steps.extract_version.outputs.version }}" - ### Installation - \`\`\`bash - pip install claude-agent-sdk==${{ steps.extract_version.outputs.version }} - \`\`\`" + # Extract changelog section for this version to a temp file + awk -v ver="$VERSION" ' + /^## / { + if (found) exit + if ($2 == ver) found=1 + next + } + found { print } + ' CHANGELOG.md > release_notes.md + + # Append install instructions + cat >> release_notes.md << 'EOF' + +--- + +**PyPI:** https://pypi.org/project/claude-agent-sdk/VERSION/ + +```bash +pip install claude-agent-sdk==VERSION +``` +EOF + + # Replace VERSION placeholder + sed -i "s/VERSION/$VERSION/g" release_notes.md + + # Create release with notes from file + gh release create "v$VERSION" \ + --title "v$VERSION" \ + --notes-file release_notes.md From a0ce44a3fabbc714df7a559a2855694569fe9585 Mon Sep 17 00:00:00 2001 From: Ashwin Bhat Date: Tue, 16 Dec 2025 10:53:13 -0800 Subject: [PATCH 12/18] Add Docker-based test infrastructure for e2e tests (#424) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Add `Dockerfile.test`: Python 3.12 image with Claude Code CLI installed - Add `scripts/test-docker.sh`: Local script to run tests in Docker - Add `test-e2e-docker` job to CI workflow that runs the full e2e suite in a container - Add `.dockerignore` to speed up Docker builds ## Context This helps catch Docker-specific issues like #406 where filesystem-based agents loaded via `setting_sources=["project"]` may silently fail in Docker environments. ## Local Usage ```bash # Run unit tests in Docker (no API key needed) ./scripts/test-docker.sh unit # Run e2e tests in Docker ANTHROPIC_API_KEY=sk-... ./scripts/test-docker.sh e2e # Run all tests ANTHROPIC_API_KEY=sk-... ./scripts/test-docker.sh all ``` ## Test plan - [x] Unit tests pass in Docker locally (129 passed) - [ ] CI job runs successfully 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude --- .claude/agents/test-agent.md | 9 +++ .dockerignore | 49 ++++++++++++ .github/workflows/test.yml | 18 +++++ Dockerfile.test | 29 +++++++ e2e-tests/test_agents_and_settings.py | 111 +++++++++++++++++++++----- examples/filesystem_agents.py | 107 +++++++++++++++++++++++++ scripts/test-docker.sh | 77 ++++++++++++++++++ 7 files changed, 381 insertions(+), 19 deletions(-) create mode 100644 .claude/agents/test-agent.md create mode 100644 .dockerignore create mode 100644 Dockerfile.test create mode 100644 examples/filesystem_agents.py create mode 100755 scripts/test-docker.sh diff --git a/.claude/agents/test-agent.md b/.claude/agents/test-agent.md new file mode 100644 index 0000000..6515827 --- /dev/null +++ b/.claude/agents/test-agent.md @@ -0,0 +1,9 @@ +--- +name: test-agent +description: A simple test agent for SDK testing +tools: Read +--- + +# Test Agent + +You are a simple test agent. When asked a question, provide a brief, helpful answer. diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d013f1b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,49 @@ +# Git +.git +.gitignore + +# Python +__pycache__ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.env +.venv +env/ +venv/ +ENV/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# Testing/Coverage +.coverage +.pytest_cache/ +htmlcov/ +.tox/ +.nox/ + +# Misc +*.log +.DS_Store diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d78d425..d581a8f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -81,6 +81,24 @@ jobs: run: | python -m pytest e2e-tests/ -v -m e2e + test-e2e-docker: + runs-on: ubuntu-latest + needs: test # Run after unit tests pass + # Run e2e tests in Docker to catch container-specific issues like #406 + + steps: + - uses: actions/checkout@v4 + + - name: Build Docker test image + run: docker build -f Dockerfile.test -t claude-sdk-test . + + - name: Run e2e tests in Docker + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + run: | + docker run --rm -e ANTHROPIC_API_KEY \ + claude-sdk-test python -m pytest e2e-tests/ -v -m e2e + test-examples: runs-on: ubuntu-latest needs: test-e2e # Run after e2e tests diff --git a/Dockerfile.test b/Dockerfile.test new file mode 100644 index 0000000..22adf2e --- /dev/null +++ b/Dockerfile.test @@ -0,0 +1,29 @@ +# Dockerfile for running SDK tests in a containerized environment +# This helps catch Docker-specific issues like #406 + +FROM python:3.12-slim + +# Install dependencies for Claude CLI and git (needed for some tests) +RUN apt-get update && apt-get install -y \ + curl \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Install Claude Code CLI +RUN curl -fsSL https://claude.ai/install.sh | bash +ENV PATH="/root/.local/bin:$PATH" + +# Set up working directory +WORKDIR /app + +# Copy the SDK source +COPY . . + +# Install SDK with dev dependencies +RUN pip install -e ".[dev]" + +# Verify CLI installation +RUN claude -v + +# Default: run unit tests +CMD ["python", "-m", "pytest", "tests/", "-v"] diff --git a/e2e-tests/test_agents_and_settings.py b/e2e-tests/test_agents_and_settings.py index 6e04066..3f6fc80 100644 --- a/e2e-tests/test_agents_and_settings.py +++ b/e2e-tests/test_agents_and_settings.py @@ -38,15 +38,88 @@ async def test_agent_definition(): async for message in client.receive_response(): if isinstance(message, SystemMessage) and message.subtype == "init": agents = message.data.get("agents", []) - assert isinstance( - agents, list - ), f"agents should be a list of strings, got: {type(agents)}" - assert ( - "test-agent" in agents - ), f"test-agent should be available, got: {agents}" + assert isinstance(agents, list), ( + f"agents should be a list of strings, got: {type(agents)}" + ) + assert "test-agent" in agents, ( + f"test-agent should be available, got: {agents}" + ) break +@pytest.mark.e2e +@pytest.mark.asyncio +async def test_filesystem_agent_loading(): + """Test that filesystem-based agents load via setting_sources and produce full response. + + This is the core test for issue #406. It verifies that when using + setting_sources=["project"] with a .claude/agents/ directory containing + agent definitions, the SDK: + 1. Loads the agents (they appear in init message) + 2. Produces a full response with AssistantMessage + 3. Completes with a ResultMessage + + The bug in #406 causes the iterator to complete after only the + init SystemMessage, never yielding AssistantMessage or ResultMessage. + """ + with tempfile.TemporaryDirectory() as tmpdir: + # Create a temporary project with a filesystem agent + project_dir = Path(tmpdir) + agents_dir = project_dir / ".claude" / "agents" + agents_dir.mkdir(parents=True) + + # Create a test agent file + agent_file = agents_dir / "fs-test-agent.md" + agent_file.write_text( + """--- +name: fs-test-agent +description: A filesystem test agent for SDK testing +tools: Read +--- + +# Filesystem Test Agent + +You are a simple test agent. When asked a question, provide a brief, helpful answer. +""" + ) + + options = ClaudeAgentOptions( + setting_sources=["project"], + cwd=project_dir, + max_turns=1, + ) + + messages = [] + async with ClaudeSDKClient(options=options) as client: + await client.query("Say hello in exactly 3 words") + async for msg in client.receive_response(): + messages.append(msg) + + # Must have at least init, assistant, result + message_types = [type(m).__name__ for m in messages] + + assert "SystemMessage" in message_types, "Missing SystemMessage (init)" + assert "AssistantMessage" in message_types, ( + f"Missing AssistantMessage - got only: {message_types}. " + "This may indicate issue #406 (silent failure with filesystem agents)." + ) + assert "ResultMessage" in message_types, "Missing ResultMessage" + + # Find the init message and check for the filesystem agent + for msg in messages: + if isinstance(msg, SystemMessage) and msg.subtype == "init": + agents = msg.data.get("agents", []) + # Agents are returned as strings (just names) + assert "fs-test-agent" in agents, ( + f"fs-test-agent not loaded from filesystem. Found: {agents}" + ) + break + + # On Windows, wait for file handles to be released before cleanup + if sys.platform == "win32": + await asyncio.sleep(0.5) + + @pytest.mark.e2e @pytest.mark.asyncio async def test_setting_sources_default(): @@ -74,12 +147,12 @@ async def test_setting_sources_default(): async for message in client.receive_response(): if isinstance(message, SystemMessage) and message.subtype == "init": output_style = message.data.get("output_style") - assert ( - output_style != "local-test-style" - ), f"outputStyle should NOT be from local settings (default is no settings), got: {output_style}" - assert ( - output_style == "default" - ), f"outputStyle should be 'default', got: {output_style}" + assert output_style != "local-test-style", ( + f"outputStyle should NOT be from local settings (default is no settings), got: {output_style}" + ) + assert output_style == "default", ( + f"outputStyle should be 'default', got: {output_style}" + ) break # On Windows, wait for file handles to be released before cleanup @@ -121,9 +194,9 @@ This is a test command. async for message in client.receive_response(): if isinstance(message, SystemMessage) and message.subtype == "init": commands = message.data.get("slash_commands", []) - assert ( - "testcmd" not in commands - ), f"testcmd should NOT be available with user-only sources, got: {commands}" + assert "testcmd" not in commands, ( + f"testcmd should NOT be available with user-only sources, got: {commands}" + ) break # On Windows, wait for file handles to be released before cleanup @@ -159,11 +232,11 @@ async def test_setting_sources_project_included(): async for message in client.receive_response(): if isinstance(message, SystemMessage) and message.subtype == "init": output_style = message.data.get("output_style") - assert ( - output_style == "local-test-style" - ), f"outputStyle should be from local settings, got: {output_style}" + assert output_style == "local-test-style", ( + f"outputStyle should be from local settings, got: {output_style}" + ) break # On Windows, wait for file handles to be released before cleanup if sys.platform == "win32": - await asyncio.sleep(0.5) \ No newline at end of file + await asyncio.sleep(0.5) diff --git a/examples/filesystem_agents.py b/examples/filesystem_agents.py new file mode 100644 index 0000000..e5f6904 --- /dev/null +++ b/examples/filesystem_agents.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +"""Example of loading filesystem-based agents via setting_sources. + +This example demonstrates how to load agents defined in .claude/agents/ files +using the setting_sources option. This is different from inline AgentDefinition +objects - these agents are loaded from markdown files on disk. + +This example tests the scenario from issue #406 where filesystem-based agents +loaded via setting_sources=["project"] may silently fail in certain environments. + +Usage: +./examples/filesystem_agents.py +""" + +import asyncio +from pathlib import Path + +from claude_agent_sdk import ( + AssistantMessage, + ClaudeAgentOptions, + ClaudeSDKClient, + ResultMessage, + SystemMessage, + TextBlock, +) + + +def extract_agents(msg: SystemMessage) -> list[str]: + """Extract agent names from system message init data.""" + if msg.subtype == "init": + agents = msg.data.get("agents", []) + # Agents can be either strings or dicts with a 'name' field + result = [] + for a in agents: + if isinstance(a, str): + result.append(a) + elif isinstance(a, dict): + result.append(a.get("name", "")) + return result + return [] + + +async def main(): + """Test loading filesystem-based agents.""" + print("=== Filesystem Agents Example ===") + print("Testing: setting_sources=['project'] with .claude/agents/test-agent.md") + print() + + # Use the SDK repo directory which has .claude/agents/test-agent.md + sdk_dir = Path(__file__).parent.parent + + options = ClaudeAgentOptions( + setting_sources=["project"], + cwd=sdk_dir, + ) + + message_types: list[str] = [] + agents_found: list[str] = [] + + async with ClaudeSDKClient(options=options) as client: + await client.query("Say hello in exactly 3 words") + + async for msg in client.receive_response(): + message_types.append(type(msg).__name__) + + if isinstance(msg, SystemMessage) and msg.subtype == "init": + agents_found = extract_agents(msg) + print(f"Init message received. Agents loaded: {agents_found}") + + elif isinstance(msg, AssistantMessage): + for block in msg.content: + if isinstance(block, TextBlock): + print(f"Assistant: {block.text}") + + elif isinstance(msg, ResultMessage): + print( + f"Result: subtype={msg.subtype}, cost=${msg.total_cost_usd or 0:.4f}" + ) + + print() + print("=== Summary ===") + print(f"Message types received: {message_types}") + print(f"Total messages: {len(message_types)}") + + # Validate the results + has_init = "SystemMessage" in message_types + has_assistant = "AssistantMessage" in message_types + has_result = "ResultMessage" in message_types + has_test_agent = "test-agent" in agents_found + + print() + if has_init and has_assistant and has_result: + print("SUCCESS: Received full response (init, assistant, result)") + else: + print("FAILURE: Did not receive full response") + print(f" - Init: {has_init}") + print(f" - Assistant: {has_assistant}") + print(f" - Result: {has_result}") + + if has_test_agent: + print("SUCCESS: test-agent was loaded from filesystem") + else: + print("WARNING: test-agent was NOT loaded (may not exist in .claude/agents/)") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/scripts/test-docker.sh b/scripts/test-docker.sh new file mode 100755 index 0000000..2cf9889 --- /dev/null +++ b/scripts/test-docker.sh @@ -0,0 +1,77 @@ +#!/bin/bash +# Run SDK tests in a Docker container +# This helps catch Docker-specific issues like #406 +# +# Usage: +# ./scripts/test-docker.sh [unit|e2e|all] +# +# Examples: +# ./scripts/test-docker.sh unit # Run unit tests only +# ANTHROPIC_API_KEY=sk-... ./scripts/test-docker.sh e2e # Run e2e tests +# ANTHROPIC_API_KEY=sk-... ./scripts/test-docker.sh all # Run all tests + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" + +cd "$PROJECT_DIR" + +usage() { + echo "Usage: $0 [unit|e2e|all]" + echo "" + echo "Commands:" + echo " unit - Run unit tests only (no API key needed)" + echo " e2e - Run e2e tests (requires ANTHROPIC_API_KEY)" + echo " all - Run both unit and e2e tests" + echo "" + echo "Examples:" + echo " $0 unit" + echo " ANTHROPIC_API_KEY=sk-... $0 e2e" + exit 1 +} + +echo "Building Docker test image..." +docker build -f Dockerfile.test -t claude-sdk-test . + +case "${1:-unit}" in + unit) + echo "" + echo "Running unit tests in Docker..." + docker run --rm claude-sdk-test \ + python -m pytest tests/ -v + ;; + e2e) + if [ -z "$ANTHROPIC_API_KEY" ]; then + echo "Error: ANTHROPIC_API_KEY environment variable is required for e2e tests" + echo "" + echo "Usage: ANTHROPIC_API_KEY=sk-... $0 e2e" + exit 1 + fi + echo "" + echo "Running e2e tests in Docker..." + docker run --rm -e ANTHROPIC_API_KEY \ + claude-sdk-test python -m pytest e2e-tests/ -v -m e2e + ;; + all) + echo "" + echo "Running unit tests in Docker..." + docker run --rm claude-sdk-test \ + python -m pytest tests/ -v + + echo "" + if [ -n "$ANTHROPIC_API_KEY" ]; then + echo "Running e2e tests in Docker..." + docker run --rm -e ANTHROPIC_API_KEY \ + claude-sdk-test python -m pytest e2e-tests/ -v -m e2e + else + echo "Skipping e2e tests (ANTHROPIC_API_KEY not set)" + fi + ;; + *) + usage + ;; +esac + +echo "" +echo "Done!" From 27575ae2ca7460c6a0f9224350b1f2941704b89d Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 16 Dec 2025 22:09:36 +0000 Subject: [PATCH 13/18] chore: bump bundled CLI version to 2.0.71 --- src/claude_agent_sdk/_cli_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/claude_agent_sdk/_cli_version.py b/src/claude_agent_sdk/_cli_version.py index 6309e4c..794eb56 100644 --- a/src/claude_agent_sdk/_cli_version.py +++ b/src/claude_agent_sdk/_cli_version.py @@ -1,3 +1,3 @@ """Bundled Claude Code CLI version.""" -__cli_version__ = "2.0.70" +__cli_version__ = "2.0.71" From 91e65b1927f4d3ab586e6a6eb8ce2d3fc78a152d Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 17 Dec 2025 21:59:10 +0000 Subject: [PATCH 14/18] chore: bump bundled CLI version to 2.0.72 --- src/claude_agent_sdk/_cli_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/claude_agent_sdk/_cli_version.py b/src/claude_agent_sdk/_cli_version.py index 794eb56..bcc7288 100644 --- a/src/claude_agent_sdk/_cli_version.py +++ b/src/claude_agent_sdk/_cli_version.py @@ -1,3 +1,3 @@ """Bundled Claude Code CLI version.""" -__cli_version__ = "2.0.71" +__cli_version__ = "2.0.72" From a3df9441286782f2c0fd476aaa99e1233c677ad2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 17:18:44 -0800 Subject: [PATCH 15/18] chore: release v0.1.18 (#428) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR updates the version to 0.1.18 after publishing to PyPI. ## Changes - Updated version in `pyproject.toml` to 0.1.18 - Updated version in `src/claude_agent_sdk/_version.py` to 0.1.18 - Updated `CHANGELOG.md` with release notes ## Release Information - Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.18/ - Bundled CLI version: 2.0.72 - Install with: `pip install claude-agent-sdk==0.1.18` 🤖 Generated by GitHub Actions --------- Co-authored-by: github-actions[bot] Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude --- CHANGELOG.md | 7 +++++++ pyproject.toml | 2 +- src/claude_agent_sdk/_version.py | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b0ad22..bfade18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.1.18 + +### Internal/Other Changes + +- **Docker-based test infrastructure**: Added Docker support for running e2e tests in containerized environments, helping catch Docker-specific issues (#424) +- Updated bundled Claude CLI to version 2.0.72 + ## 0.1.17 ### New Features diff --git a/pyproject.toml b/pyproject.toml index 0f3c76c..9058f3e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "claude-agent-sdk" -version = "0.1.17" +version = "0.1.18" description = "Python SDK for Claude Code" readme = "README.md" requires-python = ">=3.10" diff --git a/src/claude_agent_sdk/_version.py b/src/claude_agent_sdk/_version.py index e60bfef..de9a16c 100644 --- a/src/claude_agent_sdk/_version.py +++ b/src/claude_agent_sdk/_version.py @@ -1,3 +1,3 @@ """Version information for claude-agent-sdk.""" -__version__ = "0.1.17" +__version__ = "0.1.18" From 04347495b8ff309fb384fbf73749cacc1121b619 Mon Sep 17 00:00:00 2001 From: Ashwin Bhat Date: Wed, 17 Dec 2025 17:39:12 -0800 Subject: [PATCH 16/18] fix: resolve YAML syntax error in create-release-tag workflow (#429) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace heredoc with echo statements to fix YAML parsing issue. The unindented heredoc content was breaking out of the literal block scalar, causing `---` to be interpreted as a YAML document separator. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude --- .github/workflows/create-release-tag.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/create-release-tag.yml b/.github/workflows/create-release-tag.yml index 47f6c82..c50abab 100644 --- a/.github/workflows/create-release-tag.yml +++ b/.github/workflows/create-release-tag.yml @@ -53,16 +53,16 @@ jobs: ' CHANGELOG.md > release_notes.md # Append install instructions - cat >> release_notes.md << 'EOF' - ---- - -**PyPI:** https://pypi.org/project/claude-agent-sdk/VERSION/ - -```bash -pip install claude-agent-sdk==VERSION -``` -EOF + { + echo "" + echo "---" + echo "" + echo "**PyPI:** https://pypi.org/project/claude-agent-sdk/VERSION/" + echo "" + echo '```bash' + echo "pip install claude-agent-sdk==VERSION" + echo '```' + } >> release_notes.md # Replace VERSION placeholder sed -i "s/VERSION/$VERSION/g" release_notes.md From 57e8b6ecd54e4851e3111da4874bfcecec17c6a3 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 19 Dec 2025 00:16:21 +0000 Subject: [PATCH 17/18] chore: bump bundled CLI version to 2.0.73 --- src/claude_agent_sdk/_cli_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/claude_agent_sdk/_cli_version.py b/src/claude_agent_sdk/_cli_version.py index bcc7288..c855c1b 100644 --- a/src/claude_agent_sdk/_cli_version.py +++ b/src/claude_agent_sdk/_cli_version.py @@ -1,3 +1,3 @@ """Bundled Claude Code CLI version.""" -__cli_version__ = "2.0.72" +__cli_version__ = "2.0.73" From 3eb12c5a37f09f8fba65271cfbd6233ae100e0c7 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 19 Dec 2025 22:12:38 +0000 Subject: [PATCH 18/18] chore: bump bundled CLI version to 2.0.74 --- src/claude_agent_sdk/_cli_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/claude_agent_sdk/_cli_version.py b/src/claude_agent_sdk/_cli_version.py index c855c1b..8e7a72d 100644 --- a/src/claude_agent_sdk/_cli_version.py +++ b/src/claude_agent_sdk/_cli_version.py @@ -1,3 +1,3 @@ """Bundled Claude Code CLI version.""" -__cli_version__ = "2.0.73" +__cli_version__ = "2.0.74"