Source code for contextgem.internal.exceptions

# SPDX-FileCopyrightText: Shcherbak AI AS
# SPDX-License-Identifier: Apache-2.0

"""
Module defining custom exceptions for the ContextGem framework.
"""

from __future__ import annotations


# Base exception


[docs] class ContextGemError(Exception): """ Base class of the exceptions that the framework raises when a run fails, i.e. of :class:`ModelAPIError`, :class:`ModelExtractionError` and :class:`LLMToolLoopLimitError`. Catch it to handle any of them in one clause, e.g. ``except ContextGemError``. An error in the calling code, e.g. an invalid argument or an object that cannot be used where it is passed, is raised as ``ValueError`` or ``TypeError`` instead, which includes the ``ValidationError`` of pydantic, a subclass of ``ValueError``. A file that cannot be read or written, e.g. by ``from_disk()`` or ``to_disk()``, raises ``OSError``. Can be imported from ``contextgem``. :ivar message: Human-readable error description :vartype message: str :ivar retry_count: Number of retries attempted before failure :vartype retry_count: int or None :ivar original_error: The underlying exception that caused the failure :vartype original_error: Exception or None """ def __init__( self, message: str, retry_count: int | None = None, original_error: Exception | None = None, ): """ Initialize the exception. :param message: Human-readable error description :type message: str :param retry_count: Number of retries attempted before failure :type retry_count: int or None :param original_error: The underlying exception that caused the failure :type original_error: Exception or None """ super().__init__(message) self.message = message self.retry_count = retry_count self.original_error = original_error def __str__(self) -> str: """ Return a string representation of the exception. :return: Formatted error message with retry and original error information :rtype: str """ base_msg = self.message if self.retry_count is not None: base_msg += f" (after {self.retry_count} retries)" if self.original_error is not None: base_msg += f" - Original error: {self.original_error}" return base_msg
# Model exceptions
[docs] class ModelExtractionError(ContextGemError): """ Exception raised by the extraction methods when a model returns data that cannot be used, and there is no fallback model left to try. This is the case when: - the response of an LLM cannot be parsed or validated, also after the LLM was asked again ``max_retries_invalid_data`` times; - the response of a decision model cannot be used, e.g. the model refused to answer a question of a concept. A decision model is not asked again. If ``raise_exception_on_extraction_error=False`` is passed to the extraction method, a warning is logged instead. Can be imported from ``contextgem``. :ivar message: Human-readable error description :vartype message: str :ivar retry_count: Number of times that the model the error is for, i.e. the last model that was tried, was called again after it returned invalid data. The first call of the model, also of a fallback model, is not counted. :vartype retry_count: int or None :ivar original_error: The underlying exception that caused the failure :vartype original_error: Exception or None """
[docs] class ModelAPIError(ContextGemError): """ Exception raised when a request to a model fails for good, and there is no fallback model left to try. This is the case when: - the request fails with a non-transient error, e.g. an invalid request or a failed authentication; - the request fails with a transient error (request timeout, rate limit, server or connection error), also after ``num_retries_failed_request`` retries; - the response of an LLM is cut off at the max output tokens during extraction, or is empty in a chat. During extraction, if ``raise_exception_on_extraction_error=False`` is passed to the extraction method, a warning is logged instead. Can be imported from ``contextgem``. :ivar message: Human-readable error description :vartype message: str :ivar retry_count: Number of retries attempted for the failed request :vartype retry_count: int or None :ivar original_error: The underlying exception that caused the failure :vartype original_error: Exception or None """
# Tool calling / tooling exceptions
[docs] class LLMToolLoopLimitError(ContextGemError): """ Exception raised from a chat when the tool-calling loop reaches the configured ``tool_max_rounds`` limit and the LLM continues requesting tools. Typically indicates that the LLM is stuck in a loop or needs more rounds to complete the workflow. Consider increasing ``tool_max_rounds`` or adjusting the tool instructions or the tool choice. Can be imported from ``contextgem``. """
# Warnings
[docs] class ContextGemWarning(UserWarning): """ Category of the warnings that the framework issues for something in the calling code that will not have the expected effect, e.g. tools set on an LLM that is used for extraction, or an output language set together with a custom system message. Such a warning is attributed to the line of the calling code that caused it, where possible. The warnings are Python warnings, not log messages, i.e. the logging level does not affect them. To filter them, use this category, e.g. ``warnings.filterwarnings("ignore", category=ContextGemWarning)``, or make them errors, e.g. in the tests of the calling code: a filter by the module of the framework does not match a warning attributed to the calling code. What happens while the framework runs, e.g. an extraction that fails when ``raise_exception_on_extraction_error=False`` is passed to the extraction method, is logged instead. Can be imported from ``contextgem``. """
class _ToolReturnValueError(Exception): """ Internal exception that carries the error for an invalid value returned by a tool function (a value other than a non-empty string) out of the tool-calling loop, so that it is not handled as an error of the LLM API: it is an error in the calling code. It is never raised to the calling code: the error it carries is raised instead. :ivar error: The error for the invalid value returned by the tool function :vartype error: Exception """ def __init__(self, error: Exception): """ Initialize the exception. :param error: The error for the invalid value returned by the tool function :type error: Exception """ super().__init__(str(error)) self.error = error # Decision model exceptions class _InvalidDecisionResponseError(ValueError): """ Internal exception raised when the answer of a decision model to a question cannot be used, which makes the whole response of the model invalid: the answer is missing, refused, of another kind than the question, without the needed probabilities, with a probability outside [0, 1], with options other than the options offered, or with a zero probability of each option. A refused answer to the question of an aspect can be used, as "not included in the aspect", unless the model refused to answer the question on every paragraph. :ivar question_name: Name of the question whose answer cannot be used :vartype question_name: str :ivar reason: What is wrong with the answer :vartype reason: str :ivar text_position: Position of the text that the question was asked on, among the texts that the questions of the same call were asked on, if it is known :vartype text_position: int | None :ivar location: Where the text that the question was asked on is, as a part of a message, e.g. " on paragraph 3 of 5 (index 2)". Empty if it is not known, or if the text is not a part of a larger one. :vartype location: str """ def __init__(self, question_name: str, reason: str): """ Initialize the exception. :param question_name: Name of the question whose answer cannot be used :type question_name: str :param reason: What is wrong with the answer :type reason: str """ super().__init__( f"Invalid answer to the decision question `{question_name}`: {reason}" ) self.question_name = question_name self.reason = reason self.text_position: int | None = None self.location: str = ""