Files
NexQuant/rdagent/utils/agent/tpl.py
T

96 lines
3.2 KiB
Python
Raw Normal View History

2024-07-25 11:15:22 +08:00
"""
Here are some infrastructure to build a agent
2024-07-25 11:15:22 +08:00
The motivation of template and AgentOutput Design
2024-07-25 11:15:22 +08:00
"""
import inspect
2024-07-25 11:15:22 +08:00
from pathlib import Path
from typing import Any
2024-07-25 11:15:22 +08:00
import yaml
from jinja2 import Environment, StrictUndefined
2024-07-25 11:15:22 +08:00
from rdagent.core.utils import SingletonBaseClass
from rdagent.log import rdagent_logger as logger
2024-07-25 11:15:22 +08:00
DIRNAME = Path(__file__).absolute().resolve().parent
PROJ_PATH = DIRNAME.parent.parent
# class T(SingletonBaseClass): TODO: singleton does not support args now.
2024-09-29 18:43:17 +08:00
class RDAT:
"""
RD-Agent's Template
Use the simplest way to (C)reate a Template and (r)ender it!!
"""
2024-07-25 11:15:22 +08:00
def __init__(self, uri: str):
"""
here are some uri usages
2024-07-25 11:15:22 +08:00
case 1) "a.b.c:x.y.z"
It will load DIRNAME/a/b/c.yaml as `yaml` and load yaml[x][y][z]
Form example, if you want to load "rdagent/scenarios/kaggle/experiment/prompts.yaml"
`a.b.c` should be "scenarios.kaggle.experiment.prompts" and "rdagent" should be exclude
2024-07-25 11:15:22 +08:00
case 2) ".c:x.y.z"
It will load c.yaml in caller's (who call `T(uri)`) directory as `yaml` and load yaml[x][y][z]
the loaded content will be saved in `self.template`
"""
self.uri = uri
2024-07-25 11:15:22 +08:00
# Inspect the calling stack to get the caller's directory
stack = inspect.stack()
caller_frame = stack[1]
caller_module = inspect.getmodule(caller_frame[0])
if caller_module and caller_module.__file__:
caller_dir = Path(caller_module.__file__).parent
else:
caller_dir = DIRNAME
2024-07-25 11:15:22 +08:00
# Parse the URI
path_part, yaml_path = uri.split(":")
yaml_keys = yaml_path.split(".")
2024-07-25 11:15:22 +08:00
if path_part.startswith("."):
2024-07-25 11:15:22 +08:00
yaml_file_path = caller_dir / f"{path_part[1:].replace('.', '/')}.yaml"
try:
# modify the uri to a raltive path to the project for easier finding prompts.yaml
self.uri = f"{str(caller_dir.resolve().relative_to(PROJ_PATH)).replace('/', '.')}{uri}"
except ValueError:
pass
2024-07-25 11:15:22 +08:00
else:
yaml_file_path = (PROJ_PATH / path_part.replace(".", "/")).with_suffix(".yaml")
2024-07-25 11:15:22 +08:00
# Load the YAML file
with open(yaml_file_path, "r") as file:
2024-07-25 11:15:22 +08:00
yaml_content = yaml.safe_load(file)
# Traverse the YAML content to get the desired template
for key in yaml_keys:
yaml_content = yaml_content[key]
self.template = yaml_content
def r(self, **context: Any) -> str:
2024-07-25 11:15:22 +08:00
"""
Render the template with the given context.
"""
rendered = Environment(undefined=StrictUndefined).from_string(self.template).render(**context).strip("\n")
while "\n\n\n" in rendered:
rendered = rendered.replace("\n\n\n", "\n\n")
rendered = "\n".join(line for line in rendered.splitlines() if line.strip())
logger.log_object(
obj={
"uri": self.uri,
"template": self.template,
"context": context,
"rendered": rendered,
},
tag="debug_tpl",
)
return rendered
2024-09-29 18:43:17 +08:00
T = RDAT # shortcuts