Source code for agent_inspect.tools.error_analysis.tool_call_error_analysis

import asyncio
import logging
from abc import abstractmethod
from typing import List, Dict, Any, Optional, Tuple

from agent_inspect.tools.error_analysis.base_error_analysis import ErrorAnalysis
from agent_inspect.models.tools.analysis_models import (
    ToolCallErrorAnalysisDataSample,
    ToolCallErrorAnalysisResult,
    AnalyzedToolValidation,
)


[docs] class ToolCallErrorAnalysis(ErrorAnalysis): """Abstract base class for tool call-based error analysis implementations. This class provides common functionality for analyzing errors in tool call validations. Tool call analysis focuses on lower-level tool execution errors such as: - Wrong tool selection - Incorrect tool inputs - Incorrect tool output handling Subclasses implement specific algorithms (semi-supervised, deterministic) for identifying and clustering these errors. :param config: Optional configuration dictionary. Supported keys: - **max_workers**: Maximum number of concurrent workers (default: 20) :param error_clusters: Optional list of predefined error clusters for classification. """ def __init__(self, config: Optional[Dict[str, Any]] = None): super().__init__(config) # ==================== Public API ====================
[docs] async def analyze_batch_async( self, data_samples: List[ToolCallErrorAnalysisDataSample] ) -> ToolCallErrorAnalysisResult: """Async version of :meth:`~agent_inspect.tools.error_analysis.tool_call_error_analysis.ErrorAnalysis.analyze_batch`. Performs error analysis on a batch of data samples with tool call validations. Use this method when calling from an async context (i.e., when an event loop is already running). Returns the :obj:`~agent_inspect.models.tools.analysis_models.ToolCallErrorAnalysisResult` containing the clustered error types with their associated tool call validations. :param data_samples: a :obj:`~typing.List` of :obj:`~agent_inspect.models.tools.analysis_models.ToolCallErrorAnalysisDataSample` objects to perform error analysis on. Each data sample contains multiple tool call validations. :return: an :obj:`~agent_inspect.models.tools.analysis_models.ToolCallErrorAnalysisResult` object containing the error analysis results: - :obj:`~agent_inspect.models.tools.analysis_models.ToolCallErrorAnalysisResult.analyzed_validations_clustered_by_errors`: Dictionary mapping clustered error types to lists of incomplete tool call validations exhibiting those errors. """ logging.info(f"Starting tool call error analysis for {len(data_samples)} data samples.") # Process all tool validations concurrently (async pattern) loop = asyncio.get_running_loop() loop.set_default_executor(self.executor) tasks = [] for data_sample in data_samples: for validation_result in data_sample.tool_call_validations: # Skip completed validations if validation_result.is_completed: continue tasks.append( self._classify_single_validation( validation_result, data_sample.data_sample_id, data_sample.agent_run_id, ) ) all_analyzed_validations = await asyncio.gather(*tasks) # Group by cluster_label clustered_by_errors: Dict[str, List[AnalyzedToolValidation]] = {} for analyzed, cluster_label in all_analyzed_validations: if cluster_label not in clustered_by_errors: clustered_by_errors[cluster_label] = [] clustered_by_errors[cluster_label].append(analyzed) logging.info( f"Tool call error analysis complete. Found {len(clustered_by_errors)} error clusters." ) return ToolCallErrorAnalysisResult( analyzed_validations_clustered_by_errors=clustered_by_errors )
[docs] def analyze_batch( self, data_samples: List[ToolCallErrorAnalysisDataSample] ) -> ToolCallErrorAnalysisResult: """Analyze a batch of data samples and return results. This is a synchronous wrapper around :meth:`analyze_batch_async`. Use this method when calling from a synchronous context. If you're already in an async context (i.e., inside an async function with an event loop running), use :meth:`analyze_batch_async` instead. :param data_samples: a :obj:`~typing.List` of :obj:`~agent_inspect.models.tools.analysis_models.ToolCallErrorAnalysisDataSample` objects to analyze. :return: an :obj:`~agent_inspect.models.tools.analysis_models.ToolCallErrorAnalysisResult` object with clustered errors. """ try: asyncio.get_running_loop() except RuntimeError: return asyncio.run(self.analyze_batch_async(data_samples)) else: raise RuntimeError( "analyze_batch cannot be called from an async context. Use analyze_batch_async instead." )
# ==================== Abstract Methods (to be implemented by subclasses) ==================== @abstractmethod async def _classify_single_validation( self, validation_result, data_sample_id: int, agent_run_id: Optional[int] ) -> Tuple[AnalyzedToolValidation, str]: """Classify a single tool validation into an error cluster. This method is algorithm-specific: - Semi-supervised: Uses LLM to classify into predefined clusters - Deterministic: Uses regex patterns to classify deterministically :param validation_result: Tool call validation result to classify. :param data_sample_id: ID of the data sample. :param agent_run_id: Optional agent run ID. :return: Tuple of (:obj:`~agent_inspect.models.tools.analysis_models.AnalyzedToolValidation`, cluster_label) where cluster_label is the error category string. """ pass