5d2a14e50a
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
81 lines
2.5 KiB
Python
81 lines
2.5 KiB
Python
"""Invoca `claude -p` via subprocess y devuelve la respuesta como string."""
|
|
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
|
|
|
|
def _resolve_claude_bin() -> str | None:
|
|
"""Localiza claude CLI: PATH first, luego rutas convencionales."""
|
|
p = shutil.which("claude")
|
|
if p:
|
|
return p
|
|
# Fallback paths comunes (WSL subsession sin .profile cargado, etc).
|
|
home = os.path.expanduser("~")
|
|
candidates = [
|
|
f"{home}/.local/bin/claude",
|
|
"/usr/local/bin/claude",
|
|
"/opt/homebrew/bin/claude",
|
|
]
|
|
for c in candidates:
|
|
if os.path.isfile(c) and os.access(c, os.X_OK):
|
|
return c
|
|
return None
|
|
|
|
|
|
def claude_cli_prompt(
|
|
prompt: str,
|
|
timeout_s: int = 60,
|
|
model: str | None = None,
|
|
max_chars_response: int = 200_000,
|
|
extra_args: list[str] | None = None,
|
|
) -> str:
|
|
"""Invoca `claude -p "<prompt>"` via subprocess.
|
|
|
|
Args:
|
|
prompt: Texto del prompt a enviar a Claude.
|
|
timeout_s: Timeout en segundos antes de raise TimeoutExpired.
|
|
model: Modelo a usar (ej. "claude-opus-4-5"). None usa el default de `claude -p`.
|
|
max_chars_response: Trunca stdout a este numero de caracteres.
|
|
extra_args: Argumentos adicionales para el CLI (ej. ["--output-format", "json"]).
|
|
|
|
Returns:
|
|
Respuesta de Claude como texto (stdout), truncada a max_chars_response.
|
|
|
|
Raises:
|
|
FileNotFoundError: Si `claude` no esta en PATH ni rutas convencionales.
|
|
RuntimeError: Si exit code != 0 (incluye primeros 500 chars de stderr).
|
|
subprocess.TimeoutExpired: Si la llamada supera timeout_s segundos.
|
|
"""
|
|
claude_bin = _resolve_claude_bin()
|
|
if claude_bin is None:
|
|
raise FileNotFoundError(
|
|
"'claude' CLI no encontrado en PATH ni rutas convencionales "
|
|
"(~/.local/bin, /usr/local/bin, /opt/homebrew/bin). Instala Claude Code."
|
|
)
|
|
|
|
cmd = [claude_bin, "-p", prompt]
|
|
if model:
|
|
cmd.extend(["--model", model])
|
|
if extra_args:
|
|
cmd.extend(extra_args)
|
|
|
|
result = subprocess.run(
|
|
cmd,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=timeout_s,
|
|
)
|
|
|
|
if result.returncode != 0:
|
|
stderr_snippet = result.stderr[:500] if result.stderr else "(sin stderr)"
|
|
raise RuntimeError(
|
|
f"claude -p failed (exit {result.returncode}): {stderr_snippet}"
|
|
)
|
|
|
|
stdout = result.stdout
|
|
if len(stdout) > max_chars_response:
|
|
stdout = stdout[:max_chars_response]
|
|
|
|
return stdout
|