* partial * working schema builder, tested that it matches the hand-written schemas * correct another schema diff * refactor * basic working test * refactored preset creation to use yaml files * added docstring-parser * add code for dynamic function linking in agent loading * pretty schema diff printer * support pulling from ~/.memgpt/functions/*.py * clean * allow looking for system prompts in ~/.memgpt/system_prompts * create ~/.memgpt/system_prompts if it doesn't exist * pull presets from ~/.memgpt/presets in addition to examples folder * add support for loading agent configs that have additional keys --------- Co-authored-by: Sarah Wooders <sarahwooders@gmail.com>
78 lines
3.1 KiB
Python
78 lines
3.1 KiB
Python
import importlib
|
|
import inspect
|
|
import os
|
|
|
|
|
|
from memgpt.functions.schema_generator import generate_schema
|
|
from memgpt.constants import MEMGPT_DIR
|
|
|
|
|
|
def load_function_set(set_name):
|
|
"""Load the functions and generate schema for them"""
|
|
function_dict = {}
|
|
|
|
module_name = f"memgpt.functions.function_sets.{set_name}"
|
|
base_functions = importlib.import_module(module_name)
|
|
|
|
for attr_name in dir(base_functions):
|
|
# Get the attribute
|
|
attr = getattr(base_functions, attr_name)
|
|
|
|
# Check if it's a callable function and not a built-in or special method
|
|
if inspect.isfunction(attr) and attr.__module__ == base_functions.__name__:
|
|
if attr_name in function_dict:
|
|
raise ValueError(f"Found a duplicate of function name '{attr_name}'")
|
|
|
|
generated_schema = generate_schema(attr)
|
|
function_dict[attr_name] = {
|
|
"python_function": attr,
|
|
"json_schema": generated_schema,
|
|
}
|
|
|
|
if len(function_dict) == 0:
|
|
raise ValueError(f"No functions found in module {module_name}")
|
|
return function_dict
|
|
|
|
|
|
def load_all_function_sets(merge=True):
|
|
# functions/examples/*.py
|
|
scripts_dir = os.path.dirname(os.path.abspath(__file__)) # Get the directory of the current script
|
|
function_sets_dir = os.path.join(scripts_dir, "function_sets") # Path to the function_sets directory
|
|
# List all .py files in the directory (excluding __init__.py)
|
|
example_module_files = [f for f in os.listdir(function_sets_dir) if f.endswith(".py") and f != "__init__.py"]
|
|
|
|
# ~/.memgpt/functions/*.py
|
|
user_scripts_dir = os.path.join(MEMGPT_DIR, "functions")
|
|
# create if missing
|
|
if not os.path.exists(user_scripts_dir):
|
|
os.makedirs(user_scripts_dir)
|
|
user_module_files = [f for f in os.listdir(user_scripts_dir) if f.endswith(".py") and f != "__init__.py"]
|
|
|
|
# combine them both (pull from both examples and user-provided)
|
|
all_module_files = example_module_files + user_module_files
|
|
|
|
schemas_and_functions = {}
|
|
for file in all_module_files:
|
|
# Convert filename to module name
|
|
module_name = f"memgpt.functions.function_sets.{file[:-3]}" # Remove '.py' from filename
|
|
|
|
try:
|
|
# Load the function set
|
|
function_set = load_function_set(file[:-3]) # Pass the module part of the name
|
|
schemas_and_functions[module_name] = function_set
|
|
except ValueError as e:
|
|
print(f"Error loading function set '{module_name}': {e}")
|
|
|
|
if merge:
|
|
# Put all functions from all sets into the same level dict
|
|
merged_functions = {}
|
|
for set_name, function_set in schemas_and_functions.items():
|
|
for function_name, function_info in function_set.items():
|
|
if function_name in merged_functions:
|
|
raise ValueError(f"Duplicate function name '{function_name}' found in function set '{set_name}'")
|
|
merged_functions[function_name] = function_info
|
|
return merged_functions
|
|
else:
|
|
# Nested dict where the top level is organized by the function set name
|
|
return schemas_and_functions
|