import logging from typing import Optional class ToolExecutionError(Exception): """ Exception raised when a tool fails to execute as expected. Args: message (str): User-facing error message. code (str, optional): Machine-readable error code. user_message (Optional[str], optional): Message safe to show to end users. original_exception (Optional[Exception], optional): The original exception, if any. """ def __init__(self, message: str, code: str = "TOOL_EXECUTION_ERROR", user_message: Optional[str] = None, original_exception: Optional[Exception] = None): super().__init__(message) self.message = message self.code = code self.user_message = user_message or "An error occurred while executing the tool." self.original_exception = original_exception # Set up a basic logger for the tools package logger = logging.getLogger("tools") logger.setLevel(logging.INFO) handler = logging.StreamHandler() formatter = logging.Formatter('[%(asctime)s] %(levelname)s %(name)s: %(message)s') handler.setFormatter(formatter) if not logger.hasHandlers(): logger.addHandler(handler) import json import re from jinja2 import Environment, FileSystemLoader # Set up Jinja2 environment for prompt templates env = Environment(loader=FileSystemLoader("prompts")) def load_prompt(template_name: str, **vars) -> str: tpl = env.get_template(template_name) return tpl.render(**vars) def clean_json(text: str) -> dict | list: """Remove ASCII control bytes and return parsed JSON.""" safe = re.sub(r"[\x00-\x1F\x7F]", "", text) return json.loads(safe) def extract_fenced_json(raw: str) -> str: """Get the text between , or fallback to raw.""" m = re.search(r"([\s\S]*?)", raw) return m.group(1).strip() if m else raw def safe_parse(raw: str) -> dict | list: """Strip control chars then json.loads, with fallback.""" fragment = extract_fenced_json(raw) clean = re.sub(r"[\x00-\x1F\x7F]", "", fragment) try: return json.loads(clean) except json.JSONDecodeError: # try to grab first {...} or [...] m = re.search(r"(\{[\s\S]*\}|\[[\s\S]*\])", clean) if m: return json.loads(m.group(1)) raise