from abc import ABC, abstractmethod from email import message from urllib import response from litellm.utils import ModelResponse import json from function_schema import get_function_schema from typing import Any, List, Tuple class BaseLLM(ABC): def __init__(self, api_key:str=None, model:str=None, tools:dict=None): self.api_key = api_key self.model = model self.tools = tools @property def tools_schema(self) -> List[dict] | None: if self.tools: tool_func = self.tools.values() return self.get_tools_schema(tool_func) return None @abstractmethod def _chat(self, messages:list[str], **kargs:Any) -> ModelResponse: pass def chat(self, messages:list, **kargs): message = self._chat(messages, **kargs) message, tool_results = self._handle_tool_calls(message, **kargs) if tool_results: print('tool message: ', message) messages.append(message.choices[0].message) for tool_result in tool_results: messages.append(tool_result) message = self._chat(messages, **kargs) return message def _handle_tool_calls(self, message:ModelResponse, **kwargs) -> Tuple[ModelResponse, List[dict]]: if (self.tools is None) or (message.choices[0].finish_reason != 'tool_calls'): return message, None tool_results = [] tools_to_call = message.choices[0].message.tool_calls for tool in tools_to_call: tool_args = json.loads(tool.function.arguments) tool_func = self.tools.get(tool.function.name, None) if tool_func: print("Calling tool: ", tool.function.name) tool_result = tool_func(**tool_args) print("Result of tool: ", tool_result) tool_results.append({ 'role': 'tool', "tool_call_id": tool.id, 'name': tool.function.name, 'content': str(tool_result), }) return message, tool_results def get_tools_schema(self, tools): def make_schema(tool): return {'type': 'function', 'function': get_function_schema(tool)} return [make_schema(tool) for tool in tools]