Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions agent/anthropic_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -915,10 +915,18 @@ def normalize_model_name(model: str, preserve_dots: bool = False) -> str:
- Converts dots to hyphens in version numbers (OpenRouter uses dots,
Anthropic uses hyphens: claude-opus-4.6 → claude-opus-4-6), unless
preserve_dots is True (e.g. for Alibaba/DashScope: qwen3.5-plus).
- Bedrock cross-region inference profile IDs (us.*, eu.*, ap.*, global.*)
use dots as namespace separators — never mangle those.
"""
lower = model.lower()
if lower.startswith("anthropic/"):
model = model[len("anthropic/"):]
lower = model.lower()
# Bedrock inference profile IDs start with a region prefix followed by a dot
# (e.g. us.anthropic.claude-haiku-4-5-20251001-v1:0). Preserve as-is.
_BEDROCK_PREFIXES = ("us.", "eu.", "ap.", "global.")
if any(lower.startswith(p) for p in _BEDROCK_PREFIXES):
return model
if not preserve_dots:
# OpenRouter uses dots for version separators (claude-opus-4.6),
# Anthropic uses hyphens (claude-opus-4-6). Convert dots to hyphens.
Expand Down
18 changes: 18 additions & 0 deletions agent/auxiliary_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1885,6 +1885,24 @@ def _wrap_if_needed(client_obj, final_model_str: str, base_url_str: str = ""):
"directly supported, try 'auto'", provider)
return None, None

elif pconfig.auth_type == "aws_sdk":
# Bedrock provider — wrap AnthropicBedrock in AnthropicAuxiliaryClient
try:
from agent.bedrock_adapter import has_aws_credentials, resolve_bedrock_region
from agent.anthropic_adapter import build_anthropic_bedrock_client
except ImportError as exc:
logger.warning("resolve_provider_client: bedrock imports failed: %s", exc)
return None, None
if not has_aws_credentials():
logger.warning("resolve_provider_client: bedrock requested but no AWS credentials found")
return None, None
region = resolve_bedrock_region()
real_client = build_anthropic_bedrock_client(region)
final_model = _normalize_resolved_model(model or _read_main_model(), provider)
client = AnthropicAuxiliaryClient(real_client, final_model, "aws-sdk", f"https://bedrock-runtime.{region}.amazonaws.com")
logger.info("resolve_provider_client: bedrock (%s, region=%s)", final_model, region)
return (_to_async_client(client, final_model) if async_mode else (client, final_model))

logger.warning("resolve_provider_client: unhandled auth_type %s for %s",
pconfig.auth_type, provider)
return None, None
Expand Down
44 changes: 23 additions & 21 deletions run_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -5220,6 +5220,26 @@ def _anthropic_messages_create(self, api_kwargs: dict):
self._try_refresh_anthropic_client_credentials()
return self._anthropic_client.messages.create(**api_kwargs)

def _rebuild_anthropic_client(self) -> None:
"""Rebuild the Anthropic client after an interrupt or stale call.

Handles both direct Anthropic and Bedrock-hosted Anthropic models
correctly — rebuilding with the Bedrock SDK when provider is bedrock,
rather than always falling back to build_anthropic_client() which
requires a direct Anthropic API key.
"""
if getattr(self, "provider", None) == "bedrock":
from agent.anthropic_adapter import build_anthropic_bedrock_client
region = getattr(self, "_bedrock_region", "us-east-1") or "us-east-1"
self._anthropic_client = build_anthropic_bedrock_client(region)
else:
from agent.anthropic_adapter import build_anthropic_client
self._anthropic_client = build_anthropic_client(
self._anthropic_api_key,
getattr(self, "_anthropic_base_url", None),
timeout=get_provider_request_timeout(self.provider, self.model),
)

def _interruptible_api_call(self, api_kwargs: dict):
"""
Run the API call in a background thread so the main conversation loop
Expand Down Expand Up @@ -5318,14 +5338,8 @@ def _call():
)
try:
if self.api_mode == "anthropic_messages":
from agent.anthropic_adapter import build_anthropic_client

self._anthropic_client.close()
self._anthropic_client = build_anthropic_client(
self._anthropic_api_key,
getattr(self, "_anthropic_base_url", None),
timeout=get_provider_request_timeout(self.provider, self.model),
)
self._rebuild_anthropic_client()
else:
rc = request_client_holder.get("client")
if rc is not None:
Expand All @@ -5350,14 +5364,8 @@ def _call():
# seed future retries.
try:
if self.api_mode == "anthropic_messages":
from agent.anthropic_adapter import build_anthropic_client

self._anthropic_client.close()
self._anthropic_client = build_anthropic_client(
self._anthropic_api_key,
getattr(self, "_anthropic_base_url", None),
timeout=get_provider_request_timeout(self.provider, self.model),
)
self._rebuild_anthropic_client()
else:
request_client = request_client_holder.get("client")
if request_client is not None:
Expand Down Expand Up @@ -6198,14 +6206,8 @@ def _call():
if self._interrupt_requested:
try:
if self.api_mode == "anthropic_messages":
from agent.anthropic_adapter import build_anthropic_client

self._anthropic_client.close()
self._anthropic_client = build_anthropic_client(
self._anthropic_api_key,
getattr(self, "_anthropic_base_url", None),
timeout=get_provider_request_timeout(self.provider, self.model),
)
self._rebuild_anthropic_client()
else:
request_client = request_client_holder.get("client")
if request_client is not None:
Expand Down