From d29f40d39f62f5cbb3384a48632cbd3a403eae3f Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Sat, 11 Apr 2026 18:03:12 -0700 Subject: [PATCH] fix(advisor): inject max_uses_exceeded error result instead of raising exception MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the advisor loop hits max_uses, inject a tool_result error so the executor sees the cap and continues without further advice — matches Anthropic server-side behaviour (error_code: max_uses_exceeded). --- .../messages/interceptors/advisor.py | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/interceptors/advisor.py b/litellm/llms/anthropic/experimental_pass_through/messages/interceptors/advisor.py index eae1fcdaaf..797fd535f4 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/interceptors/advisor.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/interceptors/advisor.py @@ -31,10 +31,6 @@ ADVISOR_TOOL_DESCRIPTION: str = _c.ADVISOR_TOOL_DESCRIPTION from .base import MessagesInterceptor -class AdvisorMaxIterationsError(Exception): - """Raised when the advisor loop exceeds max_uses.""" - - class AdvisorOrchestrationHandler(MessagesInterceptor): """Orchestrates the advisor tool loop for non-native providers.""" @@ -135,10 +131,12 @@ class AdvisorOrchestrationHandler(MessagesInterceptor): iteration += 1 if iteration > max_uses: - raise AdvisorMaxIterationsError( - f"Advisor orchestration loop exceeded max_uses={max_uses}. " - "Increase max_uses in the advisor tool definition or cap the request." + # Per Anthropic spec: inject max_uses_exceeded error result so the + # executor sees the cap and continues without further advice. + current_messages = _inject_max_uses_error( + current_messages, executor_response, advisor_use_block ) + continue # --- Build advisor context --- advisor_messages = _build_advisor_context( @@ -290,6 +288,35 @@ def _inject_advisor_turn( ] +def _inject_max_uses_error( + messages: List[Dict], + executor_response: Any, + advisor_use_block: Dict, +) -> List[Dict]: + """ + Inject a max_uses_exceeded error tool_result so the executor continues + without further advisor calls (mirrors Anthropic's server-side behaviour). + """ + executor_content = ( + executor_response.get("content") if isinstance(executor_response, dict) else [] + ) or [] + tool_use_id = advisor_use_block.get("id", "") + return [ + *messages, + {"role": "assistant", "content": executor_content}, + { + "role": "user", + "content": [ + { + "type": "tool_result", + "tool_use_id": tool_use_id, + "content": "Advisor unavailable: max_uses limit reached. Continue without advisor guidance.", + } + ], + }, + ] + + async def _call_messages_handler( model: str, messages: List[Dict],