fix(bedrock): Bedrock-aware _rebuild_anthropic_client helper on interrupt

Three interrupt-recovery sites in run_agent.py rebuilt self._anthropic_client
with build_anthropic_client(self._anthropic_api_key, ...) unconditionally.
When provider=bedrock + api_mode=anthropic_messages (AnthropicBedrock SDK
path), self._anthropic_api_key is the sentinel 'aws-sdk' — build_anthropic_client
doesn't accept that and the rebuild either crashed or produced a non-functional
client.

Extract a _rebuild_anthropic_client() helper that dispatches to
build_anthropic_bedrock_client(region) when provider='bedrock', falling back
to build_anthropic_client() for native Anthropic and other anthropic_messages
providers (MiniMax, Kimi, Alibaba, etc.). Three inline rebuild sites now call
the helper.

Partial salvage of #14680 by @bsgdigital — only the _rebuild_anthropic_client
helper. The normalize_model_name Bedrock-prefix piece was subsumed by #14664,
and the aux client aws_sdk branch was subsumed by #14770 (both in the same
salvage PR as this commit).
This commit is contained in:
bsgdigital 2026-04-24 07:24:47 -07:00 committed by Teknium
parent a9ccb03ccc
commit 7c3e5706d8

View file

@ -5432,6 +5432,26 @@ class AIAgent:
self._try_refresh_anthropic_client_credentials() self._try_refresh_anthropic_client_credentials()
return self._anthropic_client.messages.create(**api_kwargs) 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): def _interruptible_api_call(self, api_kwargs: dict):
""" """
Run the API call in a background thread so the main conversation loop Run the API call in a background thread so the main conversation loop
@ -5539,14 +5559,8 @@ class AIAgent:
) )
try: try:
if self.api_mode == "anthropic_messages": if self.api_mode == "anthropic_messages":
from agent.anthropic_adapter import build_anthropic_client
self._anthropic_client.close() self._anthropic_client.close()
self._anthropic_client = build_anthropic_client( self._rebuild_anthropic_client()
self._anthropic_api_key,
getattr(self, "_anthropic_base_url", None),
timeout=get_provider_request_timeout(self.provider, self.model),
)
else: else:
rc = request_client_holder.get("client") rc = request_client_holder.get("client")
if rc is not None: if rc is not None:
@ -5571,14 +5585,8 @@ class AIAgent:
# seed future retries. # seed future retries.
try: try:
if self.api_mode == "anthropic_messages": if self.api_mode == "anthropic_messages":
from agent.anthropic_adapter import build_anthropic_client
self._anthropic_client.close() self._anthropic_client.close()
self._anthropic_client = build_anthropic_client( self._rebuild_anthropic_client()
self._anthropic_api_key,
getattr(self, "_anthropic_base_url", None),
timeout=get_provider_request_timeout(self.provider, self.model),
)
else: else:
request_client = request_client_holder.get("client") request_client = request_client_holder.get("client")
if request_client is not None: if request_client is not None:
@ -6428,14 +6436,8 @@ class AIAgent:
if self._interrupt_requested: if self._interrupt_requested:
try: try:
if self.api_mode == "anthropic_messages": if self.api_mode == "anthropic_messages":
from agent.anthropic_adapter import build_anthropic_client
self._anthropic_client.close() self._anthropic_client.close()
self._anthropic_client = build_anthropic_client( self._rebuild_anthropic_client()
self._anthropic_api_key,
getattr(self, "_anthropic_base_url", None),
timeout=get_provider_request_timeout(self.provider, self.model),
)
else: else:
request_client = request_client_holder.get("client") request_client = request_client_holder.get("client")
if request_client is not None: if request_client is not None: