Skip to content

Commit

Permalink
Saving runtime configuration in root directory automatically (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
DavdGao authored Feb 2, 2024
1 parent 70f6d8c commit ad54862
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 22 deletions.
14 changes: 7 additions & 7 deletions src/agentscope/_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import Optional, Union, Sequence
from agentscope import agents
from .agents import AgentBase
from ._runtime import Runtime
from ._runtime import _runtime
from .file_manager import file_manager
from .utils.logging_utils import LOG_LEVEL, setup_logger
from .utils.monitor import MonitorFactory
Expand Down Expand Up @@ -73,7 +73,7 @@ def init(
_INIT_SETTINGS["model_configs"] = model_configs
_INIT_SETTINGS["project"] = project
_INIT_SETTINGS["name"] = name
_INIT_SETTINGS["runtime_id"] = Runtime.runtime_id
_INIT_SETTINGS["runtime_id"] = _runtime.runtime_id
_INIT_SETTINGS["save_dir"] = save_dir
_INIT_SETTINGS["save_api_invoke"] = save_api_invoke
_INIT_SETTINGS["save_log"] = save_log
Expand Down Expand Up @@ -119,7 +119,7 @@ def init_process(
save_log: bool = False,
logger_level: LOG_LEVEL = _DEFAULT_LOG_LEVEL,
) -> None:
"""A entry to initialize the package in a process.
"""An entry to initialize the package in a process.
Args:
project (`Optional[str]`, defaults to `None`):
Expand Down Expand Up @@ -147,12 +147,12 @@ def init_process(
read_model_configs(model_configs)

# Init the runtime
Runtime.project = project
Runtime.name = name
_runtime.project = project
_runtime.name = name
if runtime_id is not None:
Runtime.runtime_id = runtime_id
_runtime.runtime_id = runtime_id

# Init file manager
# Init file manager and save configs by default
file_manager.init(save_dir, save_api_invoke)

# Init monitor
Expand Down
54 changes: 48 additions & 6 deletions src/agentscope/_runtime.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,64 @@
# -*- coding: utf-8 -*-
"""Manage the id for each runtime"""
from datetime import datetime
from typing import Any

from agentscope.utils.tools import _get_timestamp
from agentscope.utils.tools import _generate_random_code

_RUNTIME_ID_FORMAT = "run_%Y%m%d-%H%M%S_{}"
_RUNTIME_TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S"


class Runtime:
"""Used to record the runtime information."""
class _Runtime:
"""A singleton class used to record the runtime information, which will
be initialized when the package is imported."""

project: str = None
"""The project name, which is used to identify the project."""

name: str = None
"""The name for runtime, which is used to identify this runtime."""

runtime_id: str = _get_timestamp(_RUNTIME_ID_FORMAT).format(
_generate_random_code(),
)
runtime_id: str = None
"""The id for runtime, which is used to identify the this runtime and
name the saving directory."""
name the saving directory."""

_timestamp: datetime = datetime.now()
"""The timestamp of when the runtime is initialized."""

_instance = None

def __new__(cls, *args: Any, **kwargs: Any) -> Any:
"""Create a singleton instance."""
if not cls._instance:
cls._instance = super(_Runtime, cls).__new__(
cls,
*args,
**kwargs,
)
return cls._instance

def __init__(self) -> None:
"""Generate random project name, runtime name and default
runtime_id when the package is initialized. After that, user can set
them by calling `agentscope.init(project="xxx", name="xxx",
runtime_id="xxx")`."""

self.project = _generate_random_code()
self.name = _generate_random_code(uppercase=False)

# Obtain time from timestamp in string format, and then turn it into
# runtime ID format
self.runtime_id = _get_timestamp(
_RUNTIME_ID_FORMAT,
self._timestamp,
).format(self.name)

@property
def timestamp(self) -> str:
"""Get the current timestamp in specific format."""
return self._timestamp.strftime(_RUNTIME_TIMESTAMP_FORMAT)


_runtime = _Runtime()
3 changes: 3 additions & 0 deletions src/agentscope/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
_DEFAULT_SUBDIR_CODE = "code"
_DEFAULT_SUBDIR_FILE = "file"
_DEFAULT_SUBDIR_INVOKE = "invoke"
_DEFAULT_CFG_NAME = ".config"
_DEFAULT_IMAGE_NAME = "image_{}_{}.png"
_DEFAULT_SQLITE_DB_PATH = "agentscope.db"


# for model wrapper
_DEFAULT_MAX_RETRIES = 3
_DEFAULT_MESSAGES_KEY = "inputs"
Expand Down
34 changes: 29 additions & 5 deletions src/agentscope/file_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import numpy as np

from agentscope._runtime import Runtime
from agentscope._runtime import _runtime
from agentscope.utils.tools import _download_file, _get_timestamp
from agentscope.utils.tools import _generate_random_code
from agentscope.constants import (
Expand All @@ -16,6 +16,7 @@
_DEFAULT_SUBDIR_INVOKE,
_DEFAULT_SQLITE_DB_PATH,
_DEFAULT_IMAGE_NAME,
_DEFAULT_CFG_NAME,
)


Expand Down Expand Up @@ -44,19 +45,24 @@ def __new__(cls, *args: Any, **kwargs: Any) -> Any:
def _get_and_create_subdir(self, subdir: str) -> str:
"""Get the path of the subdir and create the subdir if it does not
exist."""
path = os.path.join(self.dir, Runtime.runtime_id, subdir)
path = os.path.join(self.dir, _runtime.runtime_id, subdir)
if not os.path.exists(path):
os.makedirs(path)
return path

def _get_file_path(self, file_name: str) -> str:
"""Get the path of the file."""
return os.path.join(self.dir, Runtime.runtime_id, file_name)
return os.path.join(self.dir, _runtime.runtime_id, file_name)

@property
def dir_root(self) -> str:
"""The root directory to save code, information and logs."""
return os.path.join(self.dir, _runtime.runtime_id)

@property
def dir_log(self) -> str:
"""The directory for saving logs."""
return os.path.join(self.dir, Runtime.runtime_id)
return os.path.join(self.dir, _runtime.runtime_id)

@property
def dir_file(self) -> str:
Expand All @@ -82,12 +88,30 @@ def path_db(self) -> str:
def init(self, save_dir: str, save_api_invoke: bool = False) -> None:
"""Set the directory for saving files."""
self.dir = save_dir
runtime_dir = os.path.join(save_dir, Runtime.runtime_id)
runtime_dir = os.path.join(save_dir, _runtime.runtime_id)
if not os.path.exists(runtime_dir):
os.makedirs(runtime_dir)

self.save_api_invoke = save_api_invoke

# Save the project and name to the runtime directory
self._save_config()

def _save_config(self) -> None:
"""Save the configuration of the runtime in its root directory."""
cfg = {
"project": _runtime.project,
"name": _runtime.name,
"id": _runtime.runtime_id,
"timestamp": _runtime.timestamp,
}
with open(
os.path.join(self.dir_root, _DEFAULT_CFG_NAME),
"w",
encoding="utf-8",
) as file:
json.dump(cfg, file, indent=4)

def save_api_invocation(
self,
prefix: str,
Expand Down
25 changes: 21 additions & 4 deletions src/agentscope/utils/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@ def extract_json_str(json_str: str) -> str:
return json_str[start_index:]


def _get_timestamp(format_: str = "%Y-%m-%d %H:%M:%S") -> str:
def _get_timestamp(
format_: str = "%Y-%m-%d %H:%M:%S",
time: datetime.datetime = None,
) -> str:
"""Get current timestamp."""
return datetime.datetime.now().strftime(format_)
if time is None:
return datetime.datetime.now().strftime(format_)
else:
return time.strftime(format_)


def to_openai_dict(item: dict) -> dict:
Expand Down Expand Up @@ -140,7 +146,18 @@ def _download_file(url: str, path_file: str, max_retries: int = 3) -> bool:
return False


def _generate_random_code(length: int = 6) -> str:
def _generate_random_code(
length: int = 6,
uppercase: bool = True,
lowercase: bool = True,
digits: bool = True,
) -> str:
"""Get random code."""
characters = string.ascii_letters + string.digits
characters = ""
if uppercase:
characters += string.ascii_uppercase
if lowercase:
characters += string.ascii_lowercase
if digits:
characters += string.digits
return "".join(secrets.choice(characters) for i in range(length))

0 comments on commit ad54862

Please sign in to comment.