Source code for tools.extend_tool_loop

"""Extend the tool-calling loop at runtime.

Allows the bot to grant itself additional tool-calling rounds when it
determines that the current limit is insufficient to complete a complex
multi-step task.
"""

from __future__ import annotations

import json
import logging

logger = logging.getLogger(__name__)

# Maximum additional rounds that can be requested in one call (still clamped
# by _ABSOLUTE_MAX_TOOL_ROUNDS minus current max).
_MAX_EXTENSION_PER_CALL = 20

# Hard ceiling for max_tool_rounds after extension (product policy).
_ABSOLUTE_MAX_TOOL_ROUNDS = 25

TOOL_NAME = "extend_tool_loop"
TOOL_DESCRIPTION = (
    "Grant yourself additional tool-calling rounds when you need more "
    "turns to complete a multi-step task. Use this when you realize "
    "you are running low on remaining tool rounds and still have work "
    "to do. Default extension is 5 rounds, up to 20 per call, and the "
    "total limit never exceeds 25 (if already at the cap, no rounds are added)."
)
TOOL_PARAMETERS = {
    "type": "object",
    "properties": {
        "rounds": {
            "type": "integer",
            "description": (
                "Number of additional tool-calling rounds to grant "
                "(default: 5, max: 20 per request, absolute max total rounds: 25)."
            ),
        },
    },
    "required": [],
}


[docs] async def run(rounds: int = 5, ctx=None) -> str: """Grant additional tool-calling rounds. Parameters ---------- rounds : int Number of extra rounds to add (capped per call and by absolute max). ctx : ToolContext Injected context with access to the OpenRouter client. """ openrouter = getattr(ctx, "openrouter", None) if openrouter is None: return json.dumps({ "success": False, "error": "OpenRouter client not available in context.", }) old_max = int(openrouter.max_tool_rounds) headroom = max(0, _ABSOLUTE_MAX_TOOL_ROUNDS - old_max) try: if rounds is None: requested = 5 else: requested = int(rounds) except (TypeError, ValueError): requested = 5 requested = max(1, min(requested, _MAX_EXTENSION_PER_CALL)) extension = min(requested, headroom) new_max = old_max + extension openrouter.max_tool_rounds = new_max if extension: logger.info( "Extended tool loop: %d -> %d rounds (+%d, cap %d)", old_max, new_max, extension, _ABSOLUTE_MAX_TOOL_ROUNDS, ) else: logger.info( "extend_tool_loop: no change (current=%d, cap=%d, headroom=%d)", old_max, _ABSOLUTE_MAX_TOOL_ROUNDS, headroom, ) return json.dumps({ "success": True, "added_rounds": extension, "previous_max_rounds": old_max, "new_max_rounds": new_max, "absolute_cap": _ABSOLUTE_MAX_TOOL_ROUNDS, "headroom_before": headroom, })