Source code for fermilink.agents.claude_agent

from __future__ import annotations

from pathlib import Path

from fermilink.agent_runtime import (
    DEFAULT_SANDBOX_POLICY,
    normalize_reasoning_effort,
    normalize_sandbox_policy,
)
from fermilink.agents.base import ProviderAgent


[docs] class ClaudeAgent(ProviderAgent): """Claude provider adapter with provider-native CLI translation.""" REASONING_MAP = {"xhigh": "high"} SANDBOX_PERMISSION_MODE = { "read-only": "plan", "workspace-write": "acceptEdits", } @property def provider(self) -> str: return "claude" @property def bin_env_key(self) -> str: return "FERMILINK_CLAUDE_BIN" @property def default_binary(self) -> str: return "claude"
[docs] def uses_json_stream(self) -> bool: return True
[docs] def workspace_instruction_alias_name(self) -> str | None: return "CLAUDE.md"
[docs] def build_exec_command( self, *, provider_bin: str, repo_dir: Path, prompt: str, sandbox_policy: str = DEFAULT_SANDBOX_POLICY, sandbox_mode: str | None = None, model: str | None = None, reasoning_effort: str | None = None, json_output: bool = True, ) -> list[str]: normalized_policy = normalize_sandbox_policy(sandbox_policy) cmd = [provider_bin, "--print", "--add-dir", str(Path(repo_dir))] if json_output: # Claude requires --verbose when using --print + stream-json output. cmd.extend(["--verbose", "--output-format", "stream-json"]) if normalized_policy == "bypass": cmd.extend(["--permission-mode", "bypassPermissions"]) elif isinstance(sandbox_mode, str) and sandbox_mode.strip(): permission_mode = self.SANDBOX_PERMISSION_MODE.get(sandbox_mode.strip()) if isinstance(permission_mode, str): cmd.extend(["--permission-mode", permission_mode]) if isinstance(model, str) and model.strip(): cmd.extend(["--model", model.strip()]) normalized_effort = normalize_reasoning_effort(reasoning_effort) if isinstance(normalized_effort, str) and normalized_effort: translated = self.REASONING_MAP.get(normalized_effort, normalized_effort) cmd.extend(["--effort", translated]) cmd.append(prompt) return cmd