g3eIL's picture
Upload 80 files
77320e4 verified
import importlib
import os
from pathlib import Path
from typing import IO, Any
import yaml
class Loader(yaml.SafeLoader):
"""
A custom YAML loader that adds support for various custom tags:
- !include: includes a YAML file as a subdocument
- !prompt: returns a prompt class based on the specified string
- !tool: returns a tool class based on the specified string
- !env: returns the value of an environment variable
- !file: returns the contents of a file
"""
def __init__(self, stream: IO[Any]) -> None:
"""
Initializes a new instance of the Loader class.
:param stream: The stream to load YAML from.
:type stream: IOBase
"""
self._root = Path(stream.name).resolve().parent
super(Loader, self).__init__(stream)
self.add_constructor("!include", Loader.include)
self.add_constructor("!prompt", Loader.prompt)
self.add_constructor("!tool", Loader.tool)
self.add_constructor("!env", Loader.env)
self.add_constructor("!file", Loader.file)
def include(self, node: yaml.Node) -> Any:
"""
Loads a YAML file from a path relative to the current file. Use this tag to include other agent configs as plugins.
:param node: The YAML node to be loaded.
:type node: yaml.Node
:return: The loaded YAML file.
:rtype: Any
"""
filename = Path(self.construct_scalar(node))
if not filename.is_absolute():
filename = self._root / filename
with open(filename, 'r') as f:
return yaml.load(f, Loader)
def prompt(self, node: yaml.Node) -> Any:
"""
Returns a PromptTemplate class based on the specified string.
:param node: The YAML node representing the prompt string.
:type node: yaml.Node
:return: The prompt class.
:rtype: type
:raises AssertionError: If the resolved prompt class is not a subclass of PromptTemplate.
"""
from ..prompt import PromptTemplate, SimpleReactPrompt, ZeroShotReactPrompt
prompt = self.construct_scalar(node)
if '.' in prompt:
_path = prompt.split('.')
module = importlib.import_module('.'.join(_path[:-1]))
prompt_cls = getattr(module, _path[-1])
else:
prompt_cls = eval(prompt)
assert issubclass(prompt_cls.__class__, PromptTemplate)
return prompt_cls
def tool(self, node: yaml.Node) -> Any:
"""
Loads a Custom BaseTool class from a path relative to the current file.
:param node: The YAML node to be loaded.
:type node: yaml.Node
:return: The loaded BaseTool class.
:rtype: Any
"""
from ..tools import BaseTool, PythonSandBoxTool
tool = self.construct_scalar(node)
if '.' in tool:
_path = tool.split('.')
module = importlib.import_module('.'.join(_path[:-1]))
tool_cls = getattr(module, _path[-1])
else:
tool_cls = eval(tool)
assert issubclass(tool_cls, BaseTool)
return tool_cls
def env(self, node: yaml.Node) -> Any:
"""
Loads an environment variable from the current environment, defaults to an empty string if the variable is not set.
:param node: The YAML node to be loaded.
:type node: yaml.Node
:return: The loaded environment variable.
:rtype: Any
"""
return os.environ.get(self.construct_scalar(node), "")
def file(self, node: yaml.Node) -> Any:
"""
Loads any readable file from a path relative to the current file.
:param node: The YAML node to be loaded.
:type node: yaml.Node
:return: The loaded file.
:rtype: Any
"""
filename = Path(self.construct_scalar(node))
if not filename.is_absolute():
filename = self._root / filename
with open(filename, 'r') as f:
return f.read().strip()