mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-07 01:48:53 +00:00
Refine tool config ownership
This commit is contained in:
parent
15964fb466
commit
8a51059bdf
@ -5,17 +5,22 @@ from __future__ import annotations
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from nanobot.agent.tools.base import Tool, tool_parameters
|
from nanobot.agent.tools.base import Tool, tool_parameters
|
||||||
from nanobot.agent.tools.schema import (
|
from nanobot.agent.tools.schema import ArraySchema, BooleanSchema, IntegerSchema, StringSchema, tool_parameters_schema
|
||||||
ArraySchema,
|
|
||||||
BooleanSchema,
|
|
||||||
IntegerSchema,
|
|
||||||
StringSchema,
|
|
||||||
tool_parameters_schema,
|
|
||||||
)
|
|
||||||
from nanobot.apps.cli import CliAppError, CliAppManager, CliAppsRuntimeConfig
|
|
||||||
from nanobot.config.tool_configs import CliAppsToolConfig
|
|
||||||
from nanobot.security.workspace_access import current_tool_workspace
|
from nanobot.security.workspace_access import current_tool_workspace
|
||||||
|
from nanobot.apps.cli import CliAppError, CliAppManager, CliAppsRuntimeConfig
|
||||||
|
from nanobot.config_base import Base
|
||||||
|
|
||||||
|
|
||||||
|
class CliAppsToolConfig(Base):
|
||||||
|
"""CLI Apps tool configuration."""
|
||||||
|
|
||||||
|
enable: bool = True
|
||||||
|
install_timeout: int = Field(default=300, ge=1, le=3600)
|
||||||
|
run_timeout: int = Field(default=60, ge=1, le=600)
|
||||||
|
catalog_ttl_seconds: int = Field(default=3600, ge=60, le=86_400)
|
||||||
|
|
||||||
|
|
||||||
@tool_parameters(
|
@tool_parameters(
|
||||||
|
|||||||
@ -16,11 +16,17 @@ from nanobot.agent.tools.schema import (
|
|||||||
StringSchema,
|
StringSchema,
|
||||||
tool_parameters_schema,
|
tool_parameters_schema,
|
||||||
)
|
)
|
||||||
from nanobot.config.tool_configs import FileToolsConfig
|
from nanobot.config_base import Base
|
||||||
from nanobot.security.workspace_access import current_tool_workspace
|
from nanobot.security.workspace_access import current_tool_workspace
|
||||||
from nanobot.utils.helpers import build_image_content_blocks, detect_image_mime
|
from nanobot.utils.helpers import build_image_content_blocks, detect_image_mime
|
||||||
|
|
||||||
|
|
||||||
|
class FileToolsConfig(Base):
|
||||||
|
"""Filesystem tools configuration."""
|
||||||
|
|
||||||
|
enable: bool = True # built-in file tools on by default
|
||||||
|
|
||||||
|
|
||||||
class _FsTool(Tool):
|
class _FsTool(Tool):
|
||||||
"""Shared base for filesystem tools — common init and path resolution."""
|
"""Shared base for filesystem tools — common init and path resolution."""
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,8 @@ from __future__ import annotations
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from nanobot.agent.tools.base import Tool, tool_parameters
|
from nanobot.agent.tools.base import Tool, tool_parameters
|
||||||
from nanobot.agent.tools.schema import (
|
from nanobot.agent.tools.schema import (
|
||||||
ArraySchema,
|
ArraySchema,
|
||||||
@ -12,14 +14,14 @@ from nanobot.agent.tools.schema import (
|
|||||||
StringSchema,
|
StringSchema,
|
||||||
tool_parameters_schema,
|
tool_parameters_schema,
|
||||||
)
|
)
|
||||||
|
from nanobot.security.workspace_access import current_tool_workspace
|
||||||
from nanobot.config.paths import get_media_dir
|
from nanobot.config.paths import get_media_dir
|
||||||
from nanobot.config.tool_configs import ImageGenerationToolConfig
|
from nanobot.config_base import Base
|
||||||
from nanobot.providers.image_generation import (
|
from nanobot.providers.image_generation import (
|
||||||
ImageGenerationError,
|
ImageGenerationError,
|
||||||
ImageGenerationProvider,
|
ImageGenerationProvider,
|
||||||
get_image_gen_provider,
|
get_image_gen_provider,
|
||||||
)
|
)
|
||||||
from nanobot.security.workspace_access import current_tool_workspace
|
|
||||||
from nanobot.security.workspace_policy import WorkspaceBoundaryError, resolve_allowed_path
|
from nanobot.security.workspace_policy import WorkspaceBoundaryError, resolve_allowed_path
|
||||||
from nanobot.utils.artifacts import (
|
from nanobot.utils.artifacts import (
|
||||||
ArtifactError,
|
ArtifactError,
|
||||||
@ -32,6 +34,17 @@ if TYPE_CHECKING:
|
|||||||
from nanobot.config.schema import ProviderConfig
|
from nanobot.config.schema import ProviderConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ImageGenerationToolConfig(Base):
|
||||||
|
"""Image generation tool configuration."""
|
||||||
|
enabled: bool = False
|
||||||
|
provider: str = "openrouter"
|
||||||
|
model: str = "openai/gpt-5.4-image-2"
|
||||||
|
default_aspect_ratio: str = "1:1"
|
||||||
|
default_image_size: str = "1K"
|
||||||
|
max_images_per_turn: int = Field(default=4, ge=1, le=8)
|
||||||
|
save_dir: str = "generated"
|
||||||
|
|
||||||
|
|
||||||
@tool_parameters(
|
@tool_parameters(
|
||||||
tool_parameters_schema(
|
tool_parameters_schema(
|
||||||
prompt=StringSchema(
|
prompt=StringSchema(
|
||||||
|
|||||||
@ -10,12 +10,18 @@ from loguru import logger
|
|||||||
from nanobot.agent.tools.base import Tool
|
from nanobot.agent.tools.base import Tool
|
||||||
from nanobot.agent.tools.context import ContextAware, RequestContext
|
from nanobot.agent.tools.context import ContextAware, RequestContext
|
||||||
from nanobot.agent.tools.runtime_state import RuntimeState
|
from nanobot.agent.tools.runtime_state import RuntimeState
|
||||||
from nanobot.config.tool_configs import MyToolConfig
|
from nanobot.config_base import Base
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from nanobot.agent.subagent import SubagentStatus
|
from nanobot.agent.subagent import SubagentStatus
|
||||||
|
|
||||||
|
|
||||||
|
class MyToolConfig(Base):
|
||||||
|
"""Self-inspection tool configuration."""
|
||||||
|
enable: bool = True
|
||||||
|
allow_set: bool = False
|
||||||
|
|
||||||
|
|
||||||
def _has_real_attr(obj: Any, key: str) -> bool:
|
def _has_real_attr(obj: Any, key: str) -> bool:
|
||||||
"""Check if obj has a real (explicitly set) attribute, not auto-generated by mock."""
|
"""Check if obj has a real (explicitly set) attribute, not auto-generated by mock."""
|
||||||
if isinstance(obj, dict):
|
if isinstance(obj, dict):
|
||||||
|
|||||||
@ -13,6 +13,7 @@ from pathlib import Path
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from nanobot.agent.tools.base import Tool, tool_parameters
|
from nanobot.agent.tools.base import Tool, tool_parameters
|
||||||
from nanobot.agent.tools.context import current_request_session_key
|
from nanobot.agent.tools.context import current_request_session_key
|
||||||
@ -33,7 +34,7 @@ from nanobot.agent.tools.schema import (
|
|||||||
tool_parameters_schema,
|
tool_parameters_schema,
|
||||||
)
|
)
|
||||||
from nanobot.config.paths import get_media_dir
|
from nanobot.config.paths import get_media_dir
|
||||||
from nanobot.config.tool_configs import ExecToolConfig
|
from nanobot.config_base import Base
|
||||||
from nanobot.security.workspace_access import current_scope_allows_loopback, current_tool_workspace
|
from nanobot.security.workspace_access import current_scope_allows_loopback, current_tool_workspace
|
||||||
from nanobot.security.workspace_policy import is_path_within
|
from nanobot.security.workspace_policy import is_path_within
|
||||||
|
|
||||||
@ -50,6 +51,18 @@ _WORKSPACE_BOUNDARY_NOTE = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ExecToolConfig(Base):
|
||||||
|
"""Shell exec tool configuration."""
|
||||||
|
enable: bool = True
|
||||||
|
timeout: int = Field(default=60, ge=0) # Hard timeout (s); 0 = no limit. Not capped by the per-call max.
|
||||||
|
path_prepend: str = ""
|
||||||
|
path_append: str = ""
|
||||||
|
sandbox: str = ""
|
||||||
|
allowed_env_keys: list[str] = Field(default_factory=list)
|
||||||
|
allow_patterns: list[str] = Field(default_factory=list)
|
||||||
|
deny_patterns: list[str] = Field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
class _PreparedCommand:
|
class _PreparedCommand:
|
||||||
command: str
|
command: str
|
||||||
|
|||||||
@ -12,6 +12,7 @@ from urllib.parse import quote, urljoin, urlparse
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from nanobot.agent.tools.base import Tool, tool_parameters
|
from nanobot.agent.tools.base import Tool, tool_parameters
|
||||||
from nanobot.agent.tools.schema import (
|
from nanobot.agent.tools.schema import (
|
||||||
@ -20,7 +21,7 @@ from nanobot.agent.tools.schema import (
|
|||||||
StringSchema,
|
StringSchema,
|
||||||
tool_parameters_schema,
|
tool_parameters_schema,
|
||||||
)
|
)
|
||||||
from nanobot.config.tool_configs import WebFetchConfig, WebSearchConfig, WebToolsConfig
|
from nanobot.config_base import Base
|
||||||
from nanobot.utils.helpers import build_image_content_blocks
|
from nanobot.utils.helpers import build_image_content_blocks
|
||||||
|
|
||||||
# Shared constants
|
# Shared constants
|
||||||
@ -34,6 +35,29 @@ _VOLCENGINE_TIME_RANGES = {"OneDay", "OneWeek", "OneMonth", "OneYear"}
|
|||||||
_VOLCENGINE_DATE_RANGE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}\.\.\d{4}-\d{2}-\d{2}$")
|
_VOLCENGINE_DATE_RANGE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}\.\.\d{4}-\d{2}-\d{2}$")
|
||||||
|
|
||||||
|
|
||||||
|
class WebSearchConfig(Base):
|
||||||
|
"""Web search configuration."""
|
||||||
|
provider: str = "duckduckgo"
|
||||||
|
api_key: str = ""
|
||||||
|
base_url: str = ""
|
||||||
|
max_results: int = 5
|
||||||
|
timeout: int = 30
|
||||||
|
|
||||||
|
|
||||||
|
class WebFetchConfig(Base):
|
||||||
|
"""Web fetch tool configuration."""
|
||||||
|
use_jina_reader: bool = True
|
||||||
|
|
||||||
|
|
||||||
|
class WebToolsConfig(Base):
|
||||||
|
"""Web tools configuration."""
|
||||||
|
enable: bool = True
|
||||||
|
proxy: str | None = None
|
||||||
|
user_agent: str | None = None
|
||||||
|
search: WebSearchConfig = Field(default_factory=WebSearchConfig)
|
||||||
|
fetch: WebFetchConfig = Field(default_factory=WebFetchConfig)
|
||||||
|
|
||||||
|
|
||||||
def _strip_tags(text: str) -> str:
|
def _strip_tags(text: str) -> str:
|
||||||
"""Remove HTML tags and decode entities."""
|
"""Remove HTML tags and decode entities."""
|
||||||
text = re.sub(r'<script[\s\S]*?</script>', '', text, flags=re.I)
|
text = re.sub(r'<script[\s\S]*?</script>', '', text, flags=re.I)
|
||||||
|
|||||||
@ -2,25 +2,33 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Literal
|
from typing import TYPE_CHECKING, Any, Literal
|
||||||
|
|
||||||
from pydantic import AliasChoices, ConfigDict, Field, model_validator
|
from pydantic import AliasChoices, ConfigDict, Field, model_validator
|
||||||
from pydantic_settings import BaseSettings
|
from pydantic_settings import BaseSettings
|
||||||
|
|
||||||
import nanobot.config.tool_configs as _tool_configs
|
|
||||||
from nanobot.config_base import Base
|
from nanobot.config_base import Base
|
||||||
from nanobot.cron.types import CronSchedule
|
from nanobot.cron.types import CronSchedule
|
||||||
|
|
||||||
CliAppsToolConfig = _tool_configs.CliAppsToolConfig
|
if TYPE_CHECKING:
|
||||||
ExecToolConfig = _tool_configs.ExecToolConfig
|
from nanobot.agent.tools.cli_apps import CliAppsToolConfig
|
||||||
FileToolsConfig = _tool_configs.FileToolsConfig
|
from nanobot.agent.tools.filesystem import FileToolsConfig
|
||||||
ImageGenerationToolConfig = _tool_configs.ImageGenerationToolConfig
|
from nanobot.agent.tools.image_generation import ImageGenerationToolConfig
|
||||||
MCPServerConfig = _tool_configs.MCPServerConfig
|
from nanobot.agent.tools.self import MyToolConfig
|
||||||
MyToolConfig = _tool_configs.MyToolConfig
|
from nanobot.agent.tools.shell import ExecToolConfig
|
||||||
ToolsConfig = _tool_configs.ToolsConfig
|
from nanobot.agent.tools.web import WebToolsConfig
|
||||||
WebFetchConfig = _tool_configs.WebFetchConfig
|
|
||||||
WebSearchConfig = _tool_configs.WebSearchConfig
|
_TOOL_CONFIG_REF_NAMES = frozenset({
|
||||||
WebToolsConfig = _tool_configs.WebToolsConfig
|
"CliAppsToolConfig",
|
||||||
|
"ExecToolConfig",
|
||||||
|
"FileToolsConfig",
|
||||||
|
"ImageGenerationToolConfig",
|
||||||
|
"MyToolConfig",
|
||||||
|
"WebFetchConfig",
|
||||||
|
"WebSearchConfig",
|
||||||
|
"WebToolsConfig",
|
||||||
|
})
|
||||||
|
_tool_config_refs_ready = False
|
||||||
|
|
||||||
|
|
||||||
class ChannelsConfig(Base):
|
class ChannelsConfig(Base):
|
||||||
@ -294,6 +302,68 @@ class GatewayConfig(Base):
|
|||||||
heartbeat: HeartbeatConfig = Field(default_factory=HeartbeatConfig)
|
heartbeat: HeartbeatConfig = Field(default_factory=HeartbeatConfig)
|
||||||
|
|
||||||
|
|
||||||
|
class MCPServerConfig(Base):
|
||||||
|
"""MCP server connection configuration (stdio or HTTP)."""
|
||||||
|
|
||||||
|
type: Literal["stdio", "sse", "streamableHttp"] | None = None # auto-detected if omitted
|
||||||
|
command: str = "" # Stdio: command to run (e.g. "npx")
|
||||||
|
args: list[str] = Field(default_factory=list) # Stdio: command arguments
|
||||||
|
env: dict[str, str] = Field(default_factory=dict) # Stdio: extra env vars
|
||||||
|
cwd: str = "" # Stdio: working directory for MCP server runtime artifacts
|
||||||
|
url: str = "" # HTTP/SSE: endpoint URL
|
||||||
|
headers: dict[str, str] = Field(default_factory=dict) # HTTP/SSE: custom headers
|
||||||
|
tool_timeout: int = 30 # seconds before a tool call is cancelled
|
||||||
|
enabled_tools: list[str] = Field(default_factory=lambda: ["*"]) # Only register these tools; accepts raw MCP names or wrapped mcp_<server>_<tool> names; ["*"] = all tools; [] = no tools
|
||||||
|
|
||||||
|
|
||||||
|
def _lazy_default(module_path: str, class_name: str) -> Any:
|
||||||
|
"""Deferred import helper for ToolsConfig default factories."""
|
||||||
|
import importlib
|
||||||
|
module = importlib.import_module(module_path)
|
||||||
|
return getattr(module, class_name)()
|
||||||
|
|
||||||
|
|
||||||
|
class ToolsConfig(Base):
|
||||||
|
"""Tools configuration.
|
||||||
|
|
||||||
|
Field types for tool-specific sub-configs are resolved via model_rebuild()
|
||||||
|
at the bottom of this file so tool config classes can stay next to their
|
||||||
|
tool implementations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
web: WebToolsConfig = Field(default_factory=lambda: _lazy_default("nanobot.agent.tools.web", "WebToolsConfig"))
|
||||||
|
exec: ExecToolConfig = Field(default_factory=lambda: _lazy_default("nanobot.agent.tools.shell", "ExecToolConfig"))
|
||||||
|
file: FileToolsConfig = Field(default_factory=lambda: _lazy_default("nanobot.agent.tools.filesystem", "FileToolsConfig"))
|
||||||
|
cli_apps: CliAppsToolConfig = Field(default_factory=lambda: _lazy_default("nanobot.agent.tools.cli_apps", "CliAppsToolConfig"))
|
||||||
|
my: MyToolConfig = Field(default_factory=lambda: _lazy_default("nanobot.agent.tools.self", "MyToolConfig"))
|
||||||
|
image_generation: ImageGenerationToolConfig = Field(
|
||||||
|
default_factory=lambda: _lazy_default("nanobot.agent.tools.image_generation", "ImageGenerationToolConfig"),
|
||||||
|
)
|
||||||
|
restrict_to_workspace: bool = False # policy intent: keep tool access inside workspace when possible
|
||||||
|
webui_allow_local_service_access: bool = Field(
|
||||||
|
default=True,
|
||||||
|
validation_alias=AliasChoices(
|
||||||
|
"webuiAllowLocalServiceAccess",
|
||||||
|
"webui_allow_local_service_access",
|
||||||
|
"allowLocalPreviewAccess",
|
||||||
|
"allow_local_preview_access",
|
||||||
|
),
|
||||||
|
) # allow WebUI Full Access shell checks against localhost services; legacy allowLocalPreviewAccess still reads
|
||||||
|
mcp_servers: dict[str, MCPServerConfig] = Field(default_factory=dict)
|
||||||
|
ssrf_whitelist: list[str] = Field(default_factory=list) # CIDR ranges to exempt from SSRF blocking (e.g. ["100.64.0.0/10"] for Tailscale)
|
||||||
|
|
||||||
|
def __init__(self, **values: Any) -> None:
|
||||||
|
if not type(self).__pydantic_complete__:
|
||||||
|
_resolve_tool_config_refs()
|
||||||
|
super().__init__(**values)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def model_validate(cls, obj: Any, *args: Any, **kwargs: Any) -> "ToolsConfig":
|
||||||
|
if not cls.__pydantic_complete__:
|
||||||
|
_resolve_tool_config_refs()
|
||||||
|
return super().model_validate(obj, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Config(BaseSettings):
|
class Config(BaseSettings):
|
||||||
"""Root configuration for nanobot."""
|
"""Root configuration for nanobot."""
|
||||||
|
|
||||||
@ -309,6 +379,17 @@ class Config(BaseSettings):
|
|||||||
validation_alias=AliasChoices("modelPresets", "model_presets"),
|
validation_alias=AliasChoices("modelPresets", "model_presets"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __init__(self, **values: Any) -> None:
|
||||||
|
if not type(self).__pydantic_complete__:
|
||||||
|
_resolve_tool_config_refs()
|
||||||
|
super().__init__(**values)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def model_validate(cls, obj: Any, *args: Any, **kwargs: Any) -> "Config":
|
||||||
|
if not cls.__pydantic_complete__:
|
||||||
|
_resolve_tool_config_refs()
|
||||||
|
return super().model_validate(obj, *args, **kwargs)
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def _validate_model_preset(self) -> "Config":
|
def _validate_model_preset(self) -> "Config":
|
||||||
if "default" in self.model_presets:
|
if "default" in self.model_presets:
|
||||||
@ -496,3 +577,47 @@ class Config(BaseSettings):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
model_config = ConfigDict(env_prefix="NANOBOT_", env_nested_delimiter="__")
|
model_config = ConfigDict(env_prefix="NANOBOT_", env_nested_delimiter="__")
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_tool_config_refs() -> None:
|
||||||
|
"""Resolve forward references in ToolsConfig by importing tool config classes.
|
||||||
|
|
||||||
|
Must be called after all modules are loaded (breaks circular imports).
|
||||||
|
Re-exports the classes into this module's namespace so existing imports
|
||||||
|
like ``from nanobot.config.schema import ExecToolConfig`` continue to work.
|
||||||
|
"""
|
||||||
|
global _tool_config_refs_ready
|
||||||
|
if _tool_config_refs_ready:
|
||||||
|
return
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from nanobot.agent.tools.cli_apps import CliAppsToolConfig
|
||||||
|
from nanobot.agent.tools.filesystem import FileToolsConfig
|
||||||
|
from nanobot.agent.tools.image_generation import ImageGenerationToolConfig
|
||||||
|
from nanobot.agent.tools.self import MyToolConfig
|
||||||
|
from nanobot.agent.tools.shell import ExecToolConfig
|
||||||
|
from nanobot.agent.tools.web import WebFetchConfig, WebSearchConfig, WebToolsConfig
|
||||||
|
|
||||||
|
# Re-export into this module's namespace
|
||||||
|
mod = sys.modules[__name__]
|
||||||
|
mod.ExecToolConfig = ExecToolConfig # type: ignore[attr-defined]
|
||||||
|
mod.FileToolsConfig = FileToolsConfig # type: ignore[attr-defined]
|
||||||
|
mod.CliAppsToolConfig = CliAppsToolConfig # type: ignore[attr-defined]
|
||||||
|
mod.WebToolsConfig = WebToolsConfig # type: ignore[attr-defined]
|
||||||
|
mod.WebSearchConfig = WebSearchConfig # type: ignore[attr-defined]
|
||||||
|
mod.WebFetchConfig = WebFetchConfig # type: ignore[attr-defined]
|
||||||
|
mod.MyToolConfig = MyToolConfig # type: ignore[attr-defined]
|
||||||
|
mod.ImageGenerationToolConfig = ImageGenerationToolConfig # type: ignore[attr-defined]
|
||||||
|
|
||||||
|
ToolsConfig.model_rebuild()
|
||||||
|
Config.model_rebuild()
|
||||||
|
_tool_config_refs_ready = True
|
||||||
|
|
||||||
|
|
||||||
|
def __getattr__(name: str) -> Any:
|
||||||
|
if name in _TOOL_CONFIG_REF_NAMES:
|
||||||
|
_resolve_tool_config_refs()
|
||||||
|
if name in globals():
|
||||||
|
return globals()[name]
|
||||||
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||||
|
|||||||
@ -1,119 +0,0 @@
|
|||||||
"""Tool configuration models with no tool-runtime imports."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from typing import Literal
|
|
||||||
|
|
||||||
from pydantic import AliasChoices, Field
|
|
||||||
|
|
||||||
from nanobot.config_base import Base
|
|
||||||
|
|
||||||
|
|
||||||
class WebSearchConfig(Base):
|
|
||||||
"""Web search configuration."""
|
|
||||||
|
|
||||||
provider: str = "duckduckgo"
|
|
||||||
api_key: str = ""
|
|
||||||
base_url: str = ""
|
|
||||||
max_results: int = 5
|
|
||||||
timeout: int = 30
|
|
||||||
|
|
||||||
|
|
||||||
class WebFetchConfig(Base):
|
|
||||||
"""Web fetch tool configuration."""
|
|
||||||
|
|
||||||
use_jina_reader: bool = True
|
|
||||||
|
|
||||||
|
|
||||||
class WebToolsConfig(Base):
|
|
||||||
"""Web tools configuration."""
|
|
||||||
|
|
||||||
enable: bool = True
|
|
||||||
proxy: str | None = None
|
|
||||||
user_agent: str | None = None
|
|
||||||
search: WebSearchConfig = Field(default_factory=WebSearchConfig)
|
|
||||||
fetch: WebFetchConfig = Field(default_factory=WebFetchConfig)
|
|
||||||
|
|
||||||
|
|
||||||
class ExecToolConfig(Base):
|
|
||||||
"""Shell exec tool configuration."""
|
|
||||||
|
|
||||||
enable: bool = True
|
|
||||||
timeout: int = Field(default=60, ge=0)
|
|
||||||
path_prepend: str = ""
|
|
||||||
path_append: str = ""
|
|
||||||
sandbox: str = ""
|
|
||||||
allowed_env_keys: list[str] = Field(default_factory=list)
|
|
||||||
allow_patterns: list[str] = Field(default_factory=list)
|
|
||||||
deny_patterns: list[str] = Field(default_factory=list)
|
|
||||||
|
|
||||||
|
|
||||||
class FileToolsConfig(Base):
|
|
||||||
"""Filesystem tools configuration."""
|
|
||||||
|
|
||||||
enable: bool = True
|
|
||||||
|
|
||||||
|
|
||||||
class CliAppsToolConfig(Base):
|
|
||||||
"""CLI Apps tool configuration."""
|
|
||||||
|
|
||||||
enable: bool = True
|
|
||||||
install_timeout: int = Field(default=300, ge=1, le=3600)
|
|
||||||
run_timeout: int = Field(default=60, ge=1, le=600)
|
|
||||||
catalog_ttl_seconds: int = Field(default=3600, ge=60, le=86_400)
|
|
||||||
|
|
||||||
|
|
||||||
class MyToolConfig(Base):
|
|
||||||
"""Self-inspection tool configuration."""
|
|
||||||
|
|
||||||
enable: bool = True
|
|
||||||
allow_set: bool = False
|
|
||||||
|
|
||||||
|
|
||||||
class ImageGenerationToolConfig(Base):
|
|
||||||
"""Image generation tool configuration."""
|
|
||||||
|
|
||||||
enabled: bool = False
|
|
||||||
provider: str = "openrouter"
|
|
||||||
model: str = "openai/gpt-5.4-image-2"
|
|
||||||
default_aspect_ratio: str = "1:1"
|
|
||||||
default_image_size: str = "1K"
|
|
||||||
max_images_per_turn: int = Field(default=4, ge=1, le=8)
|
|
||||||
save_dir: str = "generated"
|
|
||||||
|
|
||||||
|
|
||||||
class MCPServerConfig(Base):
|
|
||||||
"""MCP server connection configuration (stdio or HTTP)."""
|
|
||||||
|
|
||||||
type: Literal["stdio", "sse", "streamableHttp"] | None = None
|
|
||||||
command: str = ""
|
|
||||||
args: list[str] = Field(default_factory=list)
|
|
||||||
env: dict[str, str] = Field(default_factory=dict)
|
|
||||||
cwd: str = ""
|
|
||||||
url: str = ""
|
|
||||||
headers: dict[str, str] = Field(default_factory=dict)
|
|
||||||
tool_timeout: int = 30
|
|
||||||
enabled_tools: list[str] = Field(default_factory=lambda: ["*"])
|
|
||||||
|
|
||||||
|
|
||||||
class ToolsConfig(Base):
|
|
||||||
"""Tools configuration."""
|
|
||||||
|
|
||||||
web: WebToolsConfig = Field(default_factory=WebToolsConfig)
|
|
||||||
exec: ExecToolConfig = Field(default_factory=ExecToolConfig)
|
|
||||||
file: FileToolsConfig = Field(default_factory=FileToolsConfig)
|
|
||||||
cli_apps: CliAppsToolConfig = Field(default_factory=CliAppsToolConfig)
|
|
||||||
my: MyToolConfig = Field(default_factory=MyToolConfig)
|
|
||||||
image_generation: ImageGenerationToolConfig = Field(default_factory=ImageGenerationToolConfig)
|
|
||||||
restrict_to_workspace: bool = False
|
|
||||||
webui_allow_local_service_access: bool = Field(
|
|
||||||
default=True,
|
|
||||||
validation_alias=AliasChoices(
|
|
||||||
"webuiAllowLocalServiceAccess",
|
|
||||||
"webui_allow_local_service_access",
|
|
||||||
"allowLocalPreviewAccess",
|
|
||||||
"allow_local_preview_access",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
mcp_servers: dict[str, MCPServerConfig] = Field(default_factory=dict)
|
|
||||||
ssrf_whitelist: list[str] = Field(default_factory=list)
|
|
||||||
Loading…
x
Reference in New Issue
Block a user