mirror of
https://github.com/anthropics/claude-code-sdk-python.git
synced 2025-12-23 09:19:52 +00:00
fix: handle Windows command line length limit for --agents option (#245)
Some checks are pending
Lint / lint (push) Waiting to run
Test / test (ubuntu-latest, 3.13) (push) Waiting to run
Test / test (macos-latest, 3.10) (push) Waiting to run
Test / test (macos-latest, 3.11) (push) Waiting to run
Test / test (macos-latest, 3.13) (push) Waiting to run
Test / test (ubuntu-latest, 3.10) (push) Waiting to run
Test / test (ubuntu-latest, 3.11) (push) Waiting to run
Test / test (windows-latest, 3.10) (push) Waiting to run
Test / test-e2e (macos-latest, 3.10) (push) Blocked by required conditions
Test / test-e2e (windows-latest, 3.11) (push) Blocked by required conditions
Test / test (ubuntu-latest, 3.12) (push) Waiting to run
Test / test (macos-latest, 3.12) (push) Waiting to run
Test / test (windows-latest, 3.11) (push) Waiting to run
Test / test (windows-latest, 3.12) (push) Waiting to run
Test / test (windows-latest, 3.13) (push) Waiting to run
Test / test-examples (3.12) (push) Blocked by required conditions
Test / test-e2e (macos-latest, 3.11) (push) Blocked by required conditions
Test / test-e2e (macos-latest, 3.12) (push) Blocked by required conditions
Test / test-e2e (macos-latest, 3.13) (push) Blocked by required conditions
Test / test-e2e (ubuntu-latest, 3.10) (push) Blocked by required conditions
Test / test-e2e (ubuntu-latest, 3.11) (push) Blocked by required conditions
Test / test-e2e (ubuntu-latest, 3.12) (push) Blocked by required conditions
Test / test-e2e (ubuntu-latest, 3.13) (push) Blocked by required conditions
Test / test-e2e (windows-latest, 3.10) (push) Blocked by required conditions
Test / test-e2e (windows-latest, 3.12) (push) Blocked by required conditions
Test / test-e2e (windows-latest, 3.13) (push) Blocked by required conditions
Test / test-examples (3.10) (push) Blocked by required conditions
Test / test-examples (3.11) (push) Blocked by required conditions
Test / test-examples (3.13) (push) Blocked by required conditions
Some checks are pending
Lint / lint (push) Waiting to run
Test / test (ubuntu-latest, 3.13) (push) Waiting to run
Test / test (macos-latest, 3.10) (push) Waiting to run
Test / test (macos-latest, 3.11) (push) Waiting to run
Test / test (macos-latest, 3.13) (push) Waiting to run
Test / test (ubuntu-latest, 3.10) (push) Waiting to run
Test / test (ubuntu-latest, 3.11) (push) Waiting to run
Test / test (windows-latest, 3.10) (push) Waiting to run
Test / test-e2e (macos-latest, 3.10) (push) Blocked by required conditions
Test / test-e2e (windows-latest, 3.11) (push) Blocked by required conditions
Test / test (ubuntu-latest, 3.12) (push) Waiting to run
Test / test (macos-latest, 3.12) (push) Waiting to run
Test / test (windows-latest, 3.11) (push) Waiting to run
Test / test (windows-latest, 3.12) (push) Waiting to run
Test / test (windows-latest, 3.13) (push) Waiting to run
Test / test-examples (3.12) (push) Blocked by required conditions
Test / test-e2e (macos-latest, 3.11) (push) Blocked by required conditions
Test / test-e2e (macos-latest, 3.12) (push) Blocked by required conditions
Test / test-e2e (macos-latest, 3.13) (push) Blocked by required conditions
Test / test-e2e (ubuntu-latest, 3.10) (push) Blocked by required conditions
Test / test-e2e (ubuntu-latest, 3.11) (push) Blocked by required conditions
Test / test-e2e (ubuntu-latest, 3.12) (push) Blocked by required conditions
Test / test-e2e (ubuntu-latest, 3.13) (push) Blocked by required conditions
Test / test-e2e (windows-latest, 3.10) (push) Blocked by required conditions
Test / test-e2e (windows-latest, 3.12) (push) Blocked by required conditions
Test / test-e2e (windows-latest, 3.13) (push) Blocked by required conditions
Test / test-examples (3.10) (push) Blocked by required conditions
Test / test-examples (3.11) (push) Blocked by required conditions
Test / test-examples (3.13) (push) Blocked by required conditions
## Summary Fixes #238 - Resolves "command line too long" error on Windows when using multiple subagents with long prompts. ## Problem On Windows, the command line length is limited to 8191 characters (cmd.exe). When using multiple subagents with long prompts, the `--agents` JSON argument can easily exceed this limit, causing the error: ``` 命令行太长。 (command line too long) Fatal error in message reader: Command failed with exit code 1 ``` ## Solution This PR implements automatic detection and handling of command line length limits: 1. **Platform-specific limits**: - Windows: 8000 characters (safe margin below 8191) - Other platforms: 100,000 characters 2. **Automatic fallback**: When the command line would exceed the limit: - Write agents JSON to a temporary file - Use Claude CLI's `@filepath` syntax to reference the file - Clean up temp files when transport is closed 3. **Zero breaking changes**: The fix is transparent to users - it automatically activates only when needed ## Changes - Add `platform` and `tempfile` imports - Add `_CMD_LENGTH_LIMIT` constant with platform-specific values - Track temporary files in `self._temp_files` list - Modify `_build_command()` to detect long command lines and use temp files - Clean up temp files in `close()` method ## Testing - ✅ All existing tests pass (122 tests) - ✅ Linting and type checking pass - ✅ Minimal changes - only 47 lines added/modified - ✅ Solution transparently handles the Windows command line limit ## Test plan - [x] Test on Windows with multiple subagents and long prompts - [x] Verify temp files are created and cleaned up properly - [x] Verify normal operation (short command lines) is unaffected - [x] Test cross-platform compatibility (limit only applies on Windows) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
923d3d4620
commit
41e220cc2c
1 changed files with 47 additions and 1 deletions
|
|
@ -3,9 +3,11 @@
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from collections.abc import AsyncIterable, AsyncIterator
|
||||
from contextlib import suppress
|
||||
from dataclasses import asdict
|
||||
|
|
@ -29,6 +31,11 @@ logger = logging.getLogger(__name__)
|
|||
_DEFAULT_MAX_BUFFER_SIZE = 1024 * 1024 # 1MB buffer limit
|
||||
MINIMUM_CLAUDE_CODE_VERSION = "2.0.0"
|
||||
|
||||
# Platform-specific command line length limits
|
||||
# Windows cmd.exe has a limit of 8191 characters, use 8000 for safety
|
||||
# Other platforms have much higher limits
|
||||
_CMD_LENGTH_LIMIT = 8000 if platform.system() == "Windows" else 100000
|
||||
|
||||
|
||||
class SubprocessCLITransport(Transport):
|
||||
"""Subprocess transport using Claude Code CLI."""
|
||||
|
|
@ -57,6 +64,7 @@ class SubprocessCLITransport(Transport):
|
|||
if options.max_buffer_size is not None
|
||||
else _DEFAULT_MAX_BUFFER_SIZE
|
||||
)
|
||||
self._temp_files: list[str] = [] # Track temporary files for cleanup
|
||||
|
||||
def _find_cli(self) -> str:
|
||||
"""Find Claude Code CLI binary."""
|
||||
|
|
@ -173,7 +181,8 @@ class SubprocessCLITransport(Transport):
|
|||
name: {k: v for k, v in asdict(agent_def).items() if v is not None}
|
||||
for name, agent_def in self._options.agents.items()
|
||||
}
|
||||
cmd.extend(["--agents", json.dumps(agents_dict)])
|
||||
agents_json = json.dumps(agents_dict)
|
||||
cmd.extend(["--agents", agents_json])
|
||||
|
||||
sources_value = (
|
||||
",".join(self._options.setting_sources)
|
||||
|
|
@ -199,6 +208,37 @@ class SubprocessCLITransport(Transport):
|
|||
# String mode: use --print with the prompt
|
||||
cmd.extend(["--print", "--", str(self._prompt)])
|
||||
|
||||
# Check if command line is too long (Windows limitation)
|
||||
cmd_str = " ".join(cmd)
|
||||
if len(cmd_str) > _CMD_LENGTH_LIMIT and self._options.agents:
|
||||
# Command is too long - use temp file for agents
|
||||
# Find the --agents argument and replace its value with @filepath
|
||||
try:
|
||||
agents_idx = cmd.index("--agents")
|
||||
agents_json_value = cmd[agents_idx + 1]
|
||||
|
||||
# Create a temporary file
|
||||
# ruff: noqa: SIM115
|
||||
temp_file = tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".json", delete=False, encoding="utf-8"
|
||||
)
|
||||
temp_file.write(agents_json_value)
|
||||
temp_file.close()
|
||||
|
||||
# Track for cleanup
|
||||
self._temp_files.append(temp_file.name)
|
||||
|
||||
# Replace agents JSON with @filepath reference
|
||||
cmd[agents_idx + 1] = f"@{temp_file.name}"
|
||||
|
||||
logger.info(
|
||||
f"Command line length ({len(cmd_str)}) exceeds limit ({_CMD_LENGTH_LIMIT}). "
|
||||
f"Using temp file for --agents: {temp_file.name}"
|
||||
)
|
||||
except (ValueError, IndexError) as e:
|
||||
# This shouldn't happen, but log it just in case
|
||||
logger.warning(f"Failed to optimize command line length: {e}")
|
||||
|
||||
return cmd
|
||||
|
||||
async def connect(self) -> None:
|
||||
|
|
@ -309,6 +349,12 @@ class SubprocessCLITransport(Transport):
|
|||
"""Close the transport and clean up resources."""
|
||||
self._ready = False
|
||||
|
||||
# Clean up temporary files first (before early return)
|
||||
for temp_file in self._temp_files:
|
||||
with suppress(Exception):
|
||||
Path(temp_file).unlink(missing_ok=True)
|
||||
self._temp_files.clear()
|
||||
|
||||
if not self._process:
|
||||
return
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue