fix(advisor): inject max_uses_exceeded error result instead of raising exception

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).
This commit is contained in:
Ishaan Jaffer
2026-04-11 18:03:12 -07:00
parent 844e34b68b
commit d29f40d39f
@@ -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],