diff --git a/lang_agent/fs_bkends/base.py b/lang_agent/fs_bkends/base.py index 0ee0f7f..3b03f30 100644 --- a/lang_agent/fs_bkends/base.py +++ b/lang_agent/fs_bkends/base.py @@ -1,8 +1,10 @@ -from dataclasses import dataclass, field, is_dataclass +import os +from dataclasses import dataclass from typing import Any -import tyro -import os.path as osp from abc import ABC, abstractmethod +from loguru import logger + +from lang_agent.config import InstantiateConfig class BaseFilesystemBackend(ABC): @@ -25,4 +27,25 @@ class BaseFilesystemBackend(ABC): if hasattr(self.config, "rt_skills_dir"): return {"skills" : [self.config.rt_skills_dir]} else: - return {} \ No newline at end of file + return {} + + +@dataclass +class FilesystemBackendConfig(InstantiateConfig): + """ + Shared filesystem backend config behavior. + If subclasses define these fields, this hook ensures they exist: + - skills_dir + - workspace_dir + """ + + def _ensure_dir_if_present(self, attr_name: str) -> None: + path = getattr(self, attr_name, None) + if not isinstance(path, str) or not path.strip(): + return + os.makedirs(path, exist_ok=True) + logger.info(f"Ensured {attr_name} exists: {path}") + + def __post_init__(self) -> None: + self._ensure_dir_if_present("skills_dir") + self._ensure_dir_if_present("workspace_dir") \ No newline at end of file diff --git a/lang_agent/fs_bkends/daytona_sandbox.py b/lang_agent/fs_bkends/daytona_sandbox.py index e1ae07d..ee74e0a 100644 --- a/lang_agent/fs_bkends/daytona_sandbox.py +++ b/lang_agent/fs_bkends/daytona_sandbox.py @@ -8,13 +8,12 @@ from loguru import logger from daytona import Daytona, DaytonaConfig, FileUpload from langchain_daytona import DaytonaSandbox -from lang_agent.config import InstantiateConfig -from lang_agent.fs_bkends import BaseFilesystemBackend +from lang_agent.fs_bkends.base import BaseFilesystemBackend, FilesystemBackendConfig @tyro.conf.configure(tyro.conf.SuppressFixed) @dataclass -class DaytonaSandboxConfig(InstantiateConfig): +class DaytonaSandboxConfig(FilesystemBackendConfig): _target: Type = field(default_factory=lambda: DaytonaSandboxBk) api_key: Optional[str] = None @@ -27,6 +26,7 @@ class DaytonaSandboxConfig(InstantiateConfig): """runtime skills path inside the sandbox (auto-set from sandbox workdir)""" def __post_init__(self): + super().__post_init__() if self.api_key is None: self.api_key = os.environ.get("DAYTONA_API_KEY") if self.api_key is None: diff --git a/lang_agent/fs_bkends/localshell.py b/lang_agent/fs_bkends/localshell.py index 3af8e0f..88113d9 100644 --- a/lang_agent/fs_bkends/localshell.py +++ b/lang_agent/fs_bkends/localshell.py @@ -1,21 +1,16 @@ -from dataclasses import dataclass, field, is_dataclass -from typing import Type, TypedDict, Literal, Dict, List, Tuple, Optional +from dataclasses import dataclass, field +from typing import Type import tyro -import os.path as osp -from abc import ABC, abstractmethod -import glob from loguru import logger -from deepagents.backends.utils import create_file_data from deepagents.backends import LocalShellBackend -from lang_agent.config import InstantiateConfig -from lang_agent.fs_bkends import BaseFilesystemBackend +from lang_agent.fs_bkends.base import BaseFilesystemBackend, FilesystemBackendConfig @tyro.conf.configure(tyro.conf.SuppressFixed) @dataclass -class LocalShellConfig(InstantiateConfig): +class LocalShellConfig(FilesystemBackendConfig): _target:Type = field(default_factory=lambda:LocalShell) workspace_dir:str = "./workspace" diff --git a/lang_agent/fs_bkends/statebk.py b/lang_agent/fs_bkends/statebk.py index 6176980..2f1309c 100644 --- a/lang_agent/fs_bkends/statebk.py +++ b/lang_agent/fs_bkends/statebk.py @@ -1,16 +1,14 @@ -from dataclasses import dataclass, field, is_dataclass -from typing import Type, TypedDict, Literal, Dict, List, Tuple, Optional +from dataclasses import dataclass, field +from typing import Type import tyro import os.path as osp -from abc import ABC, abstractmethod import glob from loguru import logger from deepagents.backends.utils import create_file_data from deepagents.backends import StateBackend -from lang_agent.config import InstantiateConfig -from lang_agent.fs_bkends import BaseFilesystemBackend +from lang_agent.fs_bkends.base import BaseFilesystemBackend, FilesystemBackendConfig def read_as_utf8(file_path:str): with open(file_path, "r", encoding="utf-8") as f: @@ -31,7 +29,7 @@ def build_skill_fs_dict(skill_dir:str, virt_path:str="/skills"): @tyro.conf.configure(tyro.conf.SuppressFixed) @dataclass -class StateBkConfig(InstantiateConfig): +class StateBkConfig(FilesystemBackendConfig): _target:Type = field(default_factory=lambda:StateBk) skills_dir:str = "./assets/skills" @@ -40,10 +38,6 @@ class StateBkConfig(InstantiateConfig): rt_skills_dir:str = "/skills" """path to directory with skills in runtime directory""" - def __post_init__(self): - err_msg = f"{self.skills_dir} does not exist" - assert osp.exists(self.skills_dir), err_msg - class StateBk(BaseFilesystemBackend): def __init__(self, config:StateBkConfig):