Private
Public Access
0
0

docs(ai_client): add SQLite-granularity docstrings to tool execution functions

Also fixes return-type discrepancy in tests/test_ai_client_tool_loop.py mock by wrapping NormalizedResponse inside Result.
This commit is contained in:
2026-06-13 18:05:12 -04:00
parent 94b9e2217a
commit 82f21d7f55
2 changed files with 102 additions and 7 deletions
+98 -4
View File
@@ -671,10 +671,33 @@ async def _execute_tool_calls_concurrently(
patch_callback: Optional[Callable[[str, str], Optional[str]]] = None
) -> list[tuple[str, str, str, str]]: # tool_name, call_id, output, original_name
"""
Executes multiple tool calls concurrently using asyncio.gather.
Returns a list of (tool_name, call_id, output, original_name).
Executes tool calls concurrently using asyncio.gather.
Functional Purpose:
Concurrently dispatches tool calls to _execute_single_tool_call_async.
Parameters & Inputs:
calls (list[Any]): List of tool calls.
base_dir (str): Workspace path.
pre_tool_callback (Optional[Callable]): HITL/approval callback.
qa_callback (Optional[Callable]): QA verification callback.
r_idx (int): Round index.
provider (str): LLM provider.
patch_callback (Optional[Callable]): Patch verification callback.
Returns:
list[tuple[str, str, str, str]]: List of (tool_name, call_id, output, original_name).
Immediate-Mode DAG / Thread Context:
Called by: run_with_tool_loop
Calls: _execute_single_tool_call_async
SSDL:
`[I:gather] => o-> [I:_execute_single_tool_call_async] -> [M] -> [T:tool_results]`
Thread Boundaries:
Runs in the active asyncio event loop thread.
[C: tests/test_async_tools.py:test_execute_tool_calls_concurrently_exception_handling, tests/test_async_tools.py:test_execute_tool_calls_concurrently_timing]
"""
monitor = performance_monitor.get_monitor()
@@ -729,6 +752,44 @@ def run_with_tool_loop(
send_func: Optional[Callable[[int], NormalizedResponse]] = None,
on_pre_dispatch: Optional[Callable[[int, list[dict[str, Any]]], list[dict[str, Any]]]] = None,
) -> str:
"""
Orchestrates the LLM conversation loop, executing tool calls and updating history.
Functional Purpose:
Runs a multi-round tool loop (up to MAX_TOOL_ROUNDS + 2). It dispatches client requests,
executes any generated tool calls concurrently, updates history, and repeats until completion.
Parameters & Inputs:
client (Any): Active client instance.
request (Union[OpenAICompatibleRequest, Callable]): Initial request or builder callback.
capabilities (Optional[VendorCapabilities]): Capabilities config.
pre_tool_callback (Optional[Callable]): Human-in-the-loop validation callback.
qa_callback (Optional[Callable]): QA verification callback.
stream_callback (Optional[Callable]): Streaming callback.
patch_callback (Optional[Callable]): Verification callback for code patches.
base_dir (str): Base workspace directory.
vendor_name (str): The vendor name.
history_lock (Optional[threading.Lock]): Lock for thread safety on history.
history (Optional[list[dict[str, Any]]]): Conversation history.
trim_func (Optional[Callable]): Trimming callback for history.
reasoning_extractor (Optional[Callable]): Callback to extract reasoning content.
send_func (Optional[Callable]): Dispatch sender callback.
on_pre_dispatch (Optional[Callable]): Callback to adjust tools.
Returns:
str: The final text response returned by the LLM.
Immediate-Mode DAG / Thread Context:
Called by: _send_anthropic, _send_deepseek, _send_minimax, _send_qwen, _send_llama,
_send_grok, _send_llama_native
Calls: dispatch_send, _execute_tool_calls_concurrently
SSDL:
`o-> [I:dispatch_send] -> [B:tool_calls?] => [I:_execute_tool_calls_concurrently] -> [T:response_text]`
Thread Boundaries:
Runs synchronously in caller thread; synchronizes history modifications using history_lock.
"""
def _default_send(_round_idx: int) -> NormalizedResponse:
from src.openai_compatible import send_openai_compatible as _send_oc
assert capabilities is not None, "capabilities required when send_func is not provided"
@@ -794,6 +855,39 @@ async def _execute_single_tool_call_async(
tier: str | None = None,
patch_callback: Optional[Callable[[str, str], Optional[str]]] = None
) -> tuple[str, str, str, str]:
"""
Executes a single tool call asynchronously, checking the approval clutch.
Functional Purpose:
Executes a tool call (either PowerShell script or MCP tool) based on tool approval clutch settings.
Uses pre_tool_callback for human approval when required.
Parameters & Inputs:
name (str): The name of the tool to execute.
args (dict[str, Any]): Arguments passed to the tool.
call_id (str): Unique call identifier.
base_dir (str): Workspace root directory.
pre_tool_callback (Optional[Callable]): Hook for HITL validation.
qa_callback (Optional[Callable]): QA verification callback.
r_idx (int): Current tool loop round index.
tier (str | None): Active MMA orchestration tier.
patch_callback (Optional[Callable]): Verification callback for code patches.
Returns:
tuple[str, str, str, str]: A tuple containing (tool_name, call_id, output, original_name).
Immediate-Mode DAG / Thread Context:
Called by: _execute_tool_calls_concurrently
Calls: set_current_tier, events.emit, _append_comms, _run_script,
pre_tool_callback, mcp_client.async_dispatch
SSDL:
`[I:CheckClutch] -> [B:Approved?] -> [I:run_powershell] -> [T:output]`
Thread Boundaries:
Runs in the active asyncio event loop thread; offloads blocking synchronous calls
(like pre_tool_callback and _run_script) to separate worker threads using asyncio.to_thread.
"""
set_current_tier(tier)
out = ""
tool_executed = False
+4 -3
View File
@@ -16,6 +16,7 @@ from __future__ import annotations
from typing import Any
from unittest.mock import MagicMock, patch
import pytest
from src.result_types import Result
from src.openai_compatible import NormalizedResponse, OpenAICompatibleRequest
from src.ai_client import run_with_tool_loop
from src.vendor_capabilities import VendorCapabilities
@@ -24,13 +25,13 @@ from src.vendor_capabilities import VendorCapabilities
def caps() -> VendorCapabilities:
return VendorCapabilities(vendor="test", model="test-model", tool_calling=True, context_window=8192)
def _make_normalized_response(text: str = "ok", tool_calls: list[dict[str, Any]] | None = None) -> NormalizedResponse:
return NormalizedResponse(
def _make_normalized_response(text: str = "ok", tool_calls: list[dict[str, Any]] | None = None) -> Result[NormalizedResponse]:
return Result(data=NormalizedResponse(
text=text, tool_calls=tool_calls or [],
usage_input_tokens=10, usage_output_tokens=5,
usage_cache_read_tokens=0, usage_cache_creation_tokens=0,
raw_response=None,
)
))
def test_run_with_tool_loop_no_tool_calls_returns_immediately(caps: VendorCapabilities) -> None:
client = MagicMock()