Private
Public Access
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:
+98
-4
@@ -671,10 +671,33 @@ async def _execute_tool_calls_concurrently(
|
|||||||
patch_callback: Optional[Callable[[str, str], Optional[str]]] = None
|
patch_callback: Optional[Callable[[str, str], Optional[str]]] = None
|
||||||
) -> list[tuple[str, str, str, str]]: # tool_name, call_id, output, original_name
|
) -> list[tuple[str, str, str, str]]: # tool_name, call_id, output, original_name
|
||||||
"""
|
"""
|
||||||
|
Executes tool calls concurrently using asyncio.gather.
|
||||||
|
|
||||||
Executes multiple tool calls concurrently using asyncio.gather.
|
Functional Purpose:
|
||||||
Returns a list of (tool_name, call_id, output, original_name).
|
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]
|
[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()
|
monitor = performance_monitor.get_monitor()
|
||||||
@@ -729,6 +752,44 @@ def run_with_tool_loop(
|
|||||||
send_func: Optional[Callable[[int], NormalizedResponse]] = None,
|
send_func: Optional[Callable[[int], NormalizedResponse]] = None,
|
||||||
on_pre_dispatch: Optional[Callable[[int, list[dict[str, Any]]], list[dict[str, Any]]]] = None,
|
on_pre_dispatch: Optional[Callable[[int, list[dict[str, Any]]], list[dict[str, Any]]]] = None,
|
||||||
) -> str:
|
) -> 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:
|
def _default_send(_round_idx: int) -> NormalizedResponse:
|
||||||
from src.openai_compatible import send_openai_compatible as _send_oc
|
from src.openai_compatible import send_openai_compatible as _send_oc
|
||||||
assert capabilities is not None, "capabilities required when send_func is not provided"
|
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,
|
tier: str | None = None,
|
||||||
patch_callback: Optional[Callable[[str, str], Optional[str]]] = None
|
patch_callback: Optional[Callable[[str, str], Optional[str]]] = None
|
||||||
) -> tuple[str, str, str, str]:
|
) -> 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)
|
set_current_tier(tier)
|
||||||
out = ""
|
out = ""
|
||||||
tool_executed = False
|
tool_executed = False
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from __future__ import annotations
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
import pytest
|
import pytest
|
||||||
|
from src.result_types import Result
|
||||||
from src.openai_compatible import NormalizedResponse, OpenAICompatibleRequest
|
from src.openai_compatible import NormalizedResponse, OpenAICompatibleRequest
|
||||||
from src.ai_client import run_with_tool_loop
|
from src.ai_client import run_with_tool_loop
|
||||||
from src.vendor_capabilities import VendorCapabilities
|
from src.vendor_capabilities import VendorCapabilities
|
||||||
@@ -24,13 +25,13 @@ from src.vendor_capabilities import VendorCapabilities
|
|||||||
def caps() -> VendorCapabilities:
|
def caps() -> VendorCapabilities:
|
||||||
return VendorCapabilities(vendor="test", model="test-model", tool_calling=True, context_window=8192)
|
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:
|
def _make_normalized_response(text: str = "ok", tool_calls: list[dict[str, Any]] | None = None) -> Result[NormalizedResponse]:
|
||||||
return NormalizedResponse(
|
return Result(data=NormalizedResponse(
|
||||||
text=text, tool_calls=tool_calls or [],
|
text=text, tool_calls=tool_calls or [],
|
||||||
usage_input_tokens=10, usage_output_tokens=5,
|
usage_input_tokens=10, usage_output_tokens=5,
|
||||||
usage_cache_read_tokens=0, usage_cache_creation_tokens=0,
|
usage_cache_read_tokens=0, usage_cache_creation_tokens=0,
|
||||||
raw_response=None,
|
raw_response=None,
|
||||||
)
|
))
|
||||||
|
|
||||||
def test_run_with_tool_loop_no_tool_calls_returns_immediately(caps: VendorCapabilities) -> None:
|
def test_run_with_tool_loop_no_tool_calls_returns_immediately(caps: VendorCapabilities) -> None:
|
||||||
client = MagicMock()
|
client = MagicMock()
|
||||||
|
|||||||
Reference in New Issue
Block a user