emdash-core 0.1.33__py3-none-any.whl → 0.1.60__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- emdash_core/agent/agents.py +93 -23
- emdash_core/agent/background.py +481 -0
- emdash_core/agent/hooks.py +419 -0
- emdash_core/agent/inprocess_subagent.py +114 -10
- emdash_core/agent/mcp/config.py +78 -2
- emdash_core/agent/prompts/main_agent.py +88 -1
- emdash_core/agent/prompts/plan_mode.py +65 -44
- emdash_core/agent/prompts/subagents.py +96 -8
- emdash_core/agent/prompts/workflow.py +215 -50
- emdash_core/agent/providers/models.py +1 -1
- emdash_core/agent/providers/openai_provider.py +10 -0
- emdash_core/agent/research/researcher.py +154 -45
- emdash_core/agent/runner/agent_runner.py +157 -19
- emdash_core/agent/runner/context.py +28 -9
- emdash_core/agent/runner/sdk_runner.py +29 -2
- emdash_core/agent/skills.py +81 -1
- emdash_core/agent/toolkit.py +87 -11
- emdash_core/agent/toolkits/__init__.py +117 -18
- emdash_core/agent/toolkits/base.py +87 -2
- emdash_core/agent/toolkits/explore.py +18 -0
- emdash_core/agent/toolkits/plan.py +18 -0
- emdash_core/agent/tools/__init__.py +2 -0
- emdash_core/agent/tools/coding.py +344 -52
- emdash_core/agent/tools/lsp.py +361 -0
- emdash_core/agent/tools/skill.py +21 -1
- emdash_core/agent/tools/task.py +27 -23
- emdash_core/agent/tools/task_output.py +262 -32
- emdash_core/agent/verifier/__init__.py +11 -0
- emdash_core/agent/verifier/manager.py +295 -0
- emdash_core/agent/verifier/models.py +97 -0
- emdash_core/{swarm/worktree_manager.py → agent/worktree.py} +19 -1
- emdash_core/api/agent.py +451 -5
- emdash_core/api/research.py +3 -3
- emdash_core/api/router.py +0 -4
- emdash_core/context/longevity.py +197 -0
- emdash_core/context/providers/explored_areas.py +83 -39
- emdash_core/context/reranker.py +35 -144
- emdash_core/context/simple_reranker.py +500 -0
- emdash_core/context/tool_relevance.py +84 -0
- emdash_core/core/config.py +8 -0
- emdash_core/graph/__init__.py +8 -1
- emdash_core/graph/connection.py +24 -3
- emdash_core/graph/writer.py +7 -1
- emdash_core/ingestion/repository.py +17 -198
- emdash_core/models/agent.py +14 -0
- emdash_core/server.py +1 -6
- emdash_core/sse/stream.py +16 -1
- emdash_core/utils/__init__.py +0 -2
- emdash_core/utils/git.py +103 -0
- emdash_core/utils/image.py +147 -160
- {emdash_core-0.1.33.dist-info → emdash_core-0.1.60.dist-info}/METADATA +7 -5
- {emdash_core-0.1.33.dist-info → emdash_core-0.1.60.dist-info}/RECORD +54 -58
- emdash_core/api/swarm.py +0 -223
- emdash_core/db/__init__.py +0 -67
- emdash_core/db/auth.py +0 -134
- emdash_core/db/models.py +0 -91
- emdash_core/db/provider.py +0 -222
- emdash_core/db/providers/__init__.py +0 -5
- emdash_core/db/providers/supabase.py +0 -452
- emdash_core/swarm/__init__.py +0 -17
- emdash_core/swarm/merge_agent.py +0 -383
- emdash_core/swarm/session_manager.py +0 -274
- emdash_core/swarm/swarm_runner.py +0 -226
- emdash_core/swarm/task_definition.py +0 -137
- emdash_core/swarm/worker_spawner.py +0 -319
- {emdash_core-0.1.33.dist-info → emdash_core-0.1.60.dist-info}/WHEEL +0 -0
- {emdash_core-0.1.33.dist-info → emdash_core-0.1.60.dist-info}/entry_points.txt +0 -0
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Provides specialized toolkits for different agent types.
|
|
4
4
|
Each toolkit contains a curated set of tools appropriate for the agent's purpose.
|
|
5
|
+
|
|
6
|
+
Custom agents from .emdash/agents/*.md are also supported and use the Explore toolkit
|
|
7
|
+
by default (unless they specify different tools in their frontmatter).
|
|
5
8
|
"""
|
|
6
9
|
|
|
7
10
|
from pathlib import Path
|
|
8
|
-
from typing import TYPE_CHECKING, Dict, Type
|
|
11
|
+
from typing import TYPE_CHECKING, Dict, Type, Optional
|
|
9
12
|
|
|
10
13
|
if TYPE_CHECKING:
|
|
11
14
|
from .base import BaseToolkit
|
|
@@ -20,45 +23,141 @@ TOOLKIT_REGISTRY: Dict[str, str] = {
|
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
|
|
26
|
+
def _get_custom_agents(repo_root: Optional[Path] = None) -> dict:
|
|
27
|
+
"""Load custom agents from .emdash/agents/ directory.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
repo_root: Repository root (defaults to cwd)
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Dict mapping agent name to CustomAgent
|
|
34
|
+
"""
|
|
35
|
+
from ..agents import load_agents
|
|
36
|
+
from ...utils.logger import log
|
|
37
|
+
|
|
38
|
+
agents_dir = (repo_root or Path.cwd()) / ".emdash" / "agents"
|
|
39
|
+
log.debug(f"Loading custom agents from: {agents_dir} (exists={agents_dir.exists()})")
|
|
40
|
+
agents = load_agents(agents_dir)
|
|
41
|
+
log.debug(f"Loaded custom agents: {list(agents.keys())}")
|
|
42
|
+
return agents
|
|
43
|
+
|
|
44
|
+
|
|
23
45
|
def get_toolkit(subagent_type: str, repo_root: Path) -> "BaseToolkit":
|
|
24
46
|
"""Get toolkit for agent type.
|
|
25
47
|
|
|
26
48
|
Args:
|
|
27
|
-
subagent_type: Type of agent (e.g., "Explore", "Plan")
|
|
49
|
+
subagent_type: Type of agent (e.g., "Explore", "Plan", or custom agent name)
|
|
28
50
|
repo_root: Root directory of the repository
|
|
29
51
|
|
|
30
52
|
Returns:
|
|
31
53
|
Toolkit instance
|
|
32
54
|
|
|
33
55
|
Raises:
|
|
34
|
-
ValueError: If agent type is not registered
|
|
56
|
+
ValueError: If agent type is not registered or found
|
|
57
|
+
"""
|
|
58
|
+
# Check built-in agents first
|
|
59
|
+
if subagent_type in TOOLKIT_REGISTRY:
|
|
60
|
+
import importlib
|
|
61
|
+
module_path, class_name = TOOLKIT_REGISTRY[subagent_type].rsplit(":", 1)
|
|
62
|
+
module = importlib.import_module(module_path)
|
|
63
|
+
toolkit_class = getattr(module, class_name)
|
|
64
|
+
return toolkit_class(repo_root)
|
|
65
|
+
|
|
66
|
+
# Check custom agents
|
|
67
|
+
custom_agents = _get_custom_agents(repo_root)
|
|
68
|
+
if subagent_type in custom_agents:
|
|
69
|
+
# Custom agents use Explore toolkit by default (read-only, safe)
|
|
70
|
+
# This gives them: glob, grep, read_file, list_files, semantic_search
|
|
71
|
+
# Plus any MCP servers defined in the agent's frontmatter
|
|
72
|
+
import importlib
|
|
73
|
+
from ...utils.logger import log
|
|
74
|
+
|
|
75
|
+
custom_agent = custom_agents[subagent_type]
|
|
76
|
+
module_path, class_name = TOOLKIT_REGISTRY["Explore"].rsplit(":", 1)
|
|
77
|
+
module = importlib.import_module(module_path)
|
|
78
|
+
toolkit_class = getattr(module, class_name)
|
|
79
|
+
|
|
80
|
+
# Pass MCP servers if defined
|
|
81
|
+
mcp_servers = custom_agent.mcp_servers if custom_agent.mcp_servers else None
|
|
82
|
+
if mcp_servers:
|
|
83
|
+
log.info(f"Custom agent '{subagent_type}' has {len(mcp_servers)} MCP servers")
|
|
84
|
+
|
|
85
|
+
return toolkit_class(repo_root, mcp_servers=mcp_servers)
|
|
86
|
+
|
|
87
|
+
# Not found
|
|
88
|
+
available = list_agent_types(repo_root)
|
|
89
|
+
raise ValueError(
|
|
90
|
+
f"Unknown agent type: {subagent_type}. Available: {available}"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def list_agent_types(repo_root: Optional[Path] = None) -> list[str]:
|
|
95
|
+
"""List all available agent types (built-in + custom).
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
repo_root: Repository root for finding custom agents
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
List of agent type names
|
|
35
102
|
"""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
raise ValueError(
|
|
39
|
-
f"Unknown agent type: {subagent_type}. Available: {available}"
|
|
40
|
-
)
|
|
103
|
+
# Start with built-in agents
|
|
104
|
+
types = list(TOOLKIT_REGISTRY.keys())
|
|
41
105
|
|
|
42
|
-
#
|
|
43
|
-
|
|
106
|
+
# Add custom agents
|
|
107
|
+
custom_agents = _get_custom_agents(repo_root)
|
|
108
|
+
for name in custom_agents.keys():
|
|
109
|
+
if name not in types:
|
|
110
|
+
types.append(name)
|
|
44
111
|
|
|
45
|
-
|
|
46
|
-
module = importlib.import_module(module_path)
|
|
47
|
-
toolkit_class = getattr(module, class_name)
|
|
48
|
-
return toolkit_class(repo_root)
|
|
112
|
+
return types
|
|
49
113
|
|
|
50
114
|
|
|
51
|
-
def
|
|
52
|
-
"""
|
|
115
|
+
def get_agents_with_descriptions(repo_root: Optional[Path] = None) -> list[dict]:
|
|
116
|
+
"""Get all agents with their names and descriptions.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
repo_root: Repository root for finding custom agents
|
|
53
120
|
|
|
54
121
|
Returns:
|
|
55
|
-
List of
|
|
122
|
+
List of dicts with 'name' and 'description' keys
|
|
123
|
+
"""
|
|
124
|
+
from ..prompts.subagents import BUILTIN_AGENTS
|
|
125
|
+
|
|
126
|
+
agents = []
|
|
127
|
+
|
|
128
|
+
# Built-in agents
|
|
129
|
+
for name, description in BUILTIN_AGENTS.items():
|
|
130
|
+
agents.append({"name": name, "description": description})
|
|
131
|
+
|
|
132
|
+
# Custom agents
|
|
133
|
+
custom_agents = _get_custom_agents(repo_root)
|
|
134
|
+
for name, agent in custom_agents.items():
|
|
135
|
+
agents.append({
|
|
136
|
+
"name": name,
|
|
137
|
+
"description": agent.description or "Custom agent"
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
return agents
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def get_custom_agent(name: str, repo_root: Optional[Path] = None):
|
|
144
|
+
"""Get a specific custom agent by name.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
name: Agent name
|
|
148
|
+
repo_root: Repository root
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
CustomAgent or None
|
|
56
152
|
"""
|
|
57
|
-
|
|
153
|
+
custom_agents = _get_custom_agents(repo_root)
|
|
154
|
+
return custom_agents.get(name)
|
|
58
155
|
|
|
59
156
|
|
|
60
157
|
__all__ = [
|
|
61
158
|
"get_toolkit",
|
|
62
159
|
"list_agent_types",
|
|
160
|
+
"get_agents_with_descriptions",
|
|
161
|
+
"get_custom_agent",
|
|
63
162
|
"TOOLKIT_REGISTRY",
|
|
64
163
|
]
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Optional
|
|
5
|
+
from typing import TYPE_CHECKING, Optional
|
|
6
6
|
|
|
7
7
|
from ..tools.base import BaseTool, ToolResult
|
|
8
8
|
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ..agents import AgentMCPServerConfig
|
|
11
|
+
from ..mcp.manager import MCPServerManager
|
|
12
|
+
|
|
9
13
|
|
|
10
14
|
class BaseToolkit(ABC):
|
|
11
15
|
"""Abstract base class for sub-agent toolkits.
|
|
@@ -15,20 +19,30 @@ class BaseToolkit(ABC):
|
|
|
15
19
|
- Registering appropriate tools
|
|
16
20
|
- Providing OpenAI function schemas
|
|
17
21
|
- Executing tools by name
|
|
22
|
+
- Managing per-agent MCP servers (optional)
|
|
18
23
|
"""
|
|
19
24
|
|
|
20
25
|
# List of tool names this toolkit provides (for documentation)
|
|
21
26
|
TOOLS: list[str] = []
|
|
22
27
|
|
|
23
|
-
def __init__(
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
repo_root: Path,
|
|
31
|
+
mcp_servers: Optional[list["AgentMCPServerConfig"]] = None,
|
|
32
|
+
):
|
|
24
33
|
"""Initialize the toolkit.
|
|
25
34
|
|
|
26
35
|
Args:
|
|
27
36
|
repo_root: Root directory of the repository
|
|
37
|
+
mcp_servers: Optional list of MCP server configurations for this agent
|
|
28
38
|
"""
|
|
29
39
|
self.repo_root = repo_root.resolve()
|
|
30
40
|
self._tools: dict[str, BaseTool] = {}
|
|
41
|
+
self._mcp_manager: Optional["MCPServerManager"] = None
|
|
42
|
+
self._mcp_servers_config = mcp_servers or []
|
|
43
|
+
|
|
31
44
|
self._register_tools()
|
|
45
|
+
self._init_mcp_servers()
|
|
32
46
|
|
|
33
47
|
@abstractmethod
|
|
34
48
|
def _register_tools(self) -> None:
|
|
@@ -38,6 +52,77 @@ class BaseToolkit(ABC):
|
|
|
38
52
|
"""
|
|
39
53
|
pass
|
|
40
54
|
|
|
55
|
+
def _init_mcp_servers(self) -> None:
|
|
56
|
+
"""Initialize MCP servers for this agent if configured.
|
|
57
|
+
|
|
58
|
+
Creates an MCPServerManager with the agent's MCP server configs
|
|
59
|
+
and registers the tools from those servers. Only enabled servers
|
|
60
|
+
are started.
|
|
61
|
+
"""
|
|
62
|
+
if not self._mcp_servers_config:
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
# Filter to only enabled servers
|
|
66
|
+
enabled_servers = [s for s in self._mcp_servers_config if s.enabled]
|
|
67
|
+
if not enabled_servers:
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
from ..mcp.config import MCPServerConfig, MCPConfigFile
|
|
71
|
+
from ..mcp.manager import MCPServerManager
|
|
72
|
+
from ..mcp.tool_factory import create_tools_from_mcp
|
|
73
|
+
from ...utils.logger import log
|
|
74
|
+
|
|
75
|
+
log.info(f"Initializing {len(enabled_servers)} MCP servers for agent")
|
|
76
|
+
|
|
77
|
+
# Create a temporary config file object with our servers
|
|
78
|
+
config = MCPConfigFile()
|
|
79
|
+
for server_cfg in enabled_servers:
|
|
80
|
+
mcp_config = MCPServerConfig(
|
|
81
|
+
name=server_cfg.name,
|
|
82
|
+
command=server_cfg.command,
|
|
83
|
+
args=server_cfg.args,
|
|
84
|
+
env=server_cfg.env,
|
|
85
|
+
enabled=True,
|
|
86
|
+
timeout=server_cfg.timeout,
|
|
87
|
+
)
|
|
88
|
+
config.add_server(mcp_config)
|
|
89
|
+
|
|
90
|
+
# Create manager with in-memory config (not from file)
|
|
91
|
+
self._mcp_manager = MCPServerManager(repo_root=self.repo_root)
|
|
92
|
+
self._mcp_manager._config = config # Inject our config directly
|
|
93
|
+
|
|
94
|
+
# Start all servers and register tools
|
|
95
|
+
try:
|
|
96
|
+
started = self._mcp_manager.start_all_enabled()
|
|
97
|
+
log.info(f"Started MCP servers for agent: {started}")
|
|
98
|
+
|
|
99
|
+
# Create tool wrappers and register them
|
|
100
|
+
mcp_tools = create_tools_from_mcp(self._mcp_manager)
|
|
101
|
+
for tool in mcp_tools:
|
|
102
|
+
self.register_tool(tool)
|
|
103
|
+
log.debug(f"Registered MCP tool: {tool.name}")
|
|
104
|
+
|
|
105
|
+
except Exception as e:
|
|
106
|
+
log.warning(f"Failed to initialize MCP servers for agent: {e}")
|
|
107
|
+
|
|
108
|
+
def shutdown(self) -> None:
|
|
109
|
+
"""Shutdown the toolkit and cleanup resources.
|
|
110
|
+
|
|
111
|
+
Stops any running MCP servers.
|
|
112
|
+
"""
|
|
113
|
+
if self._mcp_manager:
|
|
114
|
+
from ...utils.logger import log
|
|
115
|
+
log.info("Shutting down agent MCP servers")
|
|
116
|
+
self._mcp_manager.shutdown_all()
|
|
117
|
+
self._mcp_manager = None
|
|
118
|
+
|
|
119
|
+
def __del__(self):
|
|
120
|
+
"""Cleanup on garbage collection."""
|
|
121
|
+
try:
|
|
122
|
+
self.shutdown()
|
|
123
|
+
except Exception:
|
|
124
|
+
pass
|
|
125
|
+
|
|
41
126
|
def register_tool(self, tool: BaseTool) -> None:
|
|
42
127
|
"""Register a tool.
|
|
43
128
|
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
"""Explorer toolkit - read-only tools for fast codebase exploration."""
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
5
|
|
|
5
6
|
from .base import BaseToolkit
|
|
6
7
|
from ..tools.coding import ReadFileTool, ListFilesTool
|
|
7
8
|
from ..tools.search import SemanticSearchTool, GrepTool, GlobTool
|
|
8
9
|
from ...utils.logger import log
|
|
9
10
|
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from ..agents import AgentMCPServerConfig
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
class ExploreToolkit(BaseToolkit):
|
|
12
16
|
"""Read-only toolkit for fast codebase exploration.
|
|
@@ -16,6 +20,7 @@ class ExploreToolkit(BaseToolkit):
|
|
|
16
20
|
- Listing directory contents
|
|
17
21
|
- Searching with patterns (grep, glob)
|
|
18
22
|
- Semantic code search
|
|
23
|
+
- MCP server tools (if configured)
|
|
19
24
|
|
|
20
25
|
All tools are read-only - no file modifications allowed.
|
|
21
26
|
"""
|
|
@@ -28,6 +33,19 @@ class ExploreToolkit(BaseToolkit):
|
|
|
28
33
|
"semantic_search",
|
|
29
34
|
]
|
|
30
35
|
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
repo_root: Path,
|
|
39
|
+
mcp_servers: Optional[list["AgentMCPServerConfig"]] = None,
|
|
40
|
+
):
|
|
41
|
+
"""Initialize the explore toolkit.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
repo_root: Root directory of the repository
|
|
45
|
+
mcp_servers: Optional MCP server configurations for this agent
|
|
46
|
+
"""
|
|
47
|
+
super().__init__(repo_root, mcp_servers=mcp_servers)
|
|
48
|
+
|
|
31
49
|
def _register_tools(self) -> None:
|
|
32
50
|
"""Register read-only exploration tools."""
|
|
33
51
|
# File reading
|
|
@@ -5,12 +5,16 @@ The main agent (in plan mode) writes the plan to .emdash/<feature>.md.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from pathlib import Path
|
|
8
|
+
from typing import TYPE_CHECKING, Optional
|
|
8
9
|
|
|
9
10
|
from .base import BaseToolkit
|
|
10
11
|
from ..tools.coding import ReadFileTool, ListFilesTool
|
|
11
12
|
from ..tools.search import SemanticSearchTool, GrepTool, GlobTool
|
|
12
13
|
from ...utils.logger import log
|
|
13
14
|
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from ..agents import AgentMCPServerConfig
|
|
17
|
+
|
|
14
18
|
|
|
15
19
|
class PlanToolkit(BaseToolkit):
|
|
16
20
|
"""Read-only toolkit for Plan subagent.
|
|
@@ -24,6 +28,7 @@ class PlanToolkit(BaseToolkit):
|
|
|
24
28
|
- glob: Find files by pattern
|
|
25
29
|
- grep: Search file contents
|
|
26
30
|
- semantic_search: AI-powered code search
|
|
31
|
+
- MCP server tools (if configured)
|
|
27
32
|
"""
|
|
28
33
|
|
|
29
34
|
TOOLS = [
|
|
@@ -34,6 +39,19 @@ class PlanToolkit(BaseToolkit):
|
|
|
34
39
|
"semantic_search",
|
|
35
40
|
]
|
|
36
41
|
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
repo_root: Path,
|
|
45
|
+
mcp_servers: Optional[list["AgentMCPServerConfig"]] = None,
|
|
46
|
+
):
|
|
47
|
+
"""Initialize the plan toolkit.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
repo_root: Root directory of the repository
|
|
51
|
+
mcp_servers: Optional MCP server configurations for this agent
|
|
52
|
+
"""
|
|
53
|
+
super().__init__(repo_root, mcp_servers=mcp_servers)
|
|
54
|
+
|
|
37
55
|
def _register_tools(self) -> None:
|
|
38
56
|
"""Register read-only exploration tools."""
|
|
39
57
|
# All read-only exploration tools
|
|
@@ -56,6 +56,7 @@ from .coding import (
|
|
|
56
56
|
CodingTool,
|
|
57
57
|
ReadFileTool,
|
|
58
58
|
WriteToFileTool,
|
|
59
|
+
EditFileTool,
|
|
59
60
|
ApplyDiffTool,
|
|
60
61
|
DeleteFileTool,
|
|
61
62
|
ListFilesTool,
|
|
@@ -124,6 +125,7 @@ __all__ = [
|
|
|
124
125
|
"CodingTool",
|
|
125
126
|
"ReadFileTool",
|
|
126
127
|
"WriteToFileTool",
|
|
128
|
+
"EditFileTool",
|
|
127
129
|
"ApplyDiffTool",
|
|
128
130
|
"DeleteFileTool",
|
|
129
131
|
"ListFilesTool",
|