toolplane-python-client 0.1.0__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.
- toolplane/__init__.py +106 -0
- toolplane/common/__init__.py +93 -0
- toolplane/common/base_config.py +129 -0
- toolplane/common/base_connection_manager.py +171 -0
- toolplane/common/base_session_manager.py +321 -0
- toolplane/common/base_tool_manager.py +347 -0
- toolplane/common/constants.py +47 -0
- toolplane/common/utils.py +310 -0
- toolplane/core/__init__.py +67 -0
- toolplane/core/config.py +107 -0
- toolplane/core/connection.py +285 -0
- toolplane/core/errors.py +298 -0
- toolplane/core/machine.py +480 -0
- toolplane/core/request.py +775 -0
- toolplane/core/session.py +332 -0
- toolplane/core/session_context.py +514 -0
- toolplane/core/task.py +130 -0
- toolplane/core/tool.py +329 -0
- toolplane/http_core/__init__.py +37 -0
- toolplane/http_core/http_config.py +97 -0
- toolplane/http_core/http_connection.py +409 -0
- toolplane/http_core/http_machine.py +298 -0
- toolplane/http_core/http_request.py +748 -0
- toolplane/http_core/http_session.py +348 -0
- toolplane/http_core/http_session_context.py +491 -0
- toolplane/http_core/http_task.py +101 -0
- toolplane/http_core/http_tool.py +400 -0
- toolplane/interfaces/__init__.py +27 -0
- toolplane/interfaces/client_interface.py +122 -0
- toolplane/interfaces/connection_interface.py +193 -0
- toolplane/interfaces/event_interface.py +290 -0
- toolplane/interfaces/request_interface.py +439 -0
- toolplane/interfaces/session_interface.py +288 -0
- toolplane/interfaces/tool_interface.py +441 -0
- toolplane/proto/__init__.py +0 -0
- toolplane/proto/service_pb2.py +315 -0
- toolplane/proto/service_pb2_grpc.py +2240 -0
- toolplane/provider_cli.py +268 -0
- toolplane/provider_registry.py +77 -0
- toolplane/provider_runtime.py +302 -0
- toolplane/toolkits/__init__.py +0 -0
- toolplane/toolkits/standalone_tools/__init__.py +0 -0
- toolplane/toolkits/standalone_tools/create_directory.py +94 -0
- toolplane/toolkits/standalone_tools/create_file.py +124 -0
- toolplane/toolkits/standalone_tools/file_search.py +229 -0
- toolplane/toolkits/standalone_tools/grep_search.py +372 -0
- toolplane/toolkits/standalone_tools/launcher.py +146 -0
- toolplane/toolkits/standalone_tools/list_dir.py +395 -0
- toolplane/toolkits/standalone_tools/read_file.py +346 -0
- toolplane/toolkits/standalone_tools/replace_string_in_file.py +407 -0
- toolplane/toolkits/standalone_tools/run_tests.py +66 -0
- toolplane/toolkits/standalone_tools/semantic_search.py +485 -0
- toolplane/toolkits/standalone_tools/standalone_toolkit.py +979 -0
- toolplane/toolkits/standalone_tools/test_failure_analysis.py +618 -0
- toolplane/toolkits/standalone_tools/test_standalone_toolkit.py +517 -0
- toolplane/toolkits/swe/__init__.py +35 -0
- toolplane/toolkits/swe/create_directory.py +15 -0
- toolplane/toolkits/swe/create_file.py +15 -0
- toolplane/toolkits/swe/descriptions.py +273 -0
- toolplane/toolkits/swe/execute_bash.py +93 -0
- toolplane/toolkits/swe/file_editor.py +775 -0
- toolplane/toolkits/swe/file_search.py +16 -0
- toolplane/toolkits/swe/finish.py +50 -0
- toolplane/toolkits/swe/grep_search.py +19 -0
- toolplane/toolkits/swe/list_dir.py +407 -0
- toolplane/toolkits/swe/read_file.py +18 -0
- toolplane/toolkits/swe/replace_string_in_file.py +17 -0
- toolplane/toolkits/swe/search.py +260 -0
- toolplane/toolkits/swe/semantic_search.py +20 -0
- toolplane/toolkits/swe/str_replace_editor.py +647 -0
- toolplane/toolkits/swe/submit.py +29 -0
- toolplane/toolkits/swe/swe_toolkit.py +1296 -0
- toolplane/toolplane_client.py +686 -0
- toolplane/toolplane_http_client.py +681 -0
- toolplane/utils/__init__.py +3 -0
- toolplane/utils/schema.py +146 -0
- toolplane_python_client-0.1.0.dist-info/METADATA +543 -0
- toolplane_python_client-0.1.0.dist-info/RECORD +81 -0
- toolplane_python_client-0.1.0.dist-info/WHEEL +5 -0
- toolplane_python_client-0.1.0.dist-info/entry_points.txt +2 -0
- toolplane_python_client-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,979 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Standalone Toolkit for LangChain Integration
|
|
4
|
+
|
|
5
|
+
This module provides a comprehensive set of standalone development tools
|
|
6
|
+
wrapped as LangChain tools for AI agent integration.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
|
13
|
+
|
|
14
|
+
from langchain.tools import BaseTool
|
|
15
|
+
from langchain_core.callbacks.manager import (
|
|
16
|
+
AsyncCallbackManagerForToolRun,
|
|
17
|
+
CallbackManagerForToolRun,
|
|
18
|
+
)
|
|
19
|
+
from pydantic import BaseModel, Field
|
|
20
|
+
|
|
21
|
+
# Import functions from standalone tools
|
|
22
|
+
try:
|
|
23
|
+
from .create_directory import create_directory
|
|
24
|
+
from .create_file import create_file
|
|
25
|
+
from .file_search import file_search
|
|
26
|
+
from .grep_search import grep_search
|
|
27
|
+
from .list_dir import list_dir
|
|
28
|
+
from .read_file import read_file
|
|
29
|
+
from .replace_string_in_file import replace_string_in_file
|
|
30
|
+
from .semantic_search import semantic_search
|
|
31
|
+
from .test_failure_analysis import analyze_test_failures
|
|
32
|
+
except ImportError:
|
|
33
|
+
# Fallback for when running as standalone
|
|
34
|
+
from standalone_tools.create_directory import create_directory
|
|
35
|
+
from standalone_tools.create_file import create_file
|
|
36
|
+
from standalone_tools.file_search import file_search
|
|
37
|
+
from standalone_tools.grep_search import grep_search
|
|
38
|
+
from standalone_tools.list_dir import list_dir
|
|
39
|
+
from standalone_tools.read_file import read_file
|
|
40
|
+
from standalone_tools.replace_string_in_file import replace_string_in_file
|
|
41
|
+
from standalone_tools.semantic_search import semantic_search
|
|
42
|
+
from standalone_tools.test_failure_analysis import analyze_test_failures
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# Input Models for each tool
|
|
46
|
+
class CreateDirectoryInput(BaseModel):
|
|
47
|
+
dir_path: str = Field(description="The absolute path to the directory to create")
|
|
48
|
+
mode: Optional[int] = Field(
|
|
49
|
+
default=0o755, description="Permission mode for the directory"
|
|
50
|
+
)
|
|
51
|
+
parents: Optional[bool] = Field(
|
|
52
|
+
default=True, description="Create parent directories if they don't exist"
|
|
53
|
+
)
|
|
54
|
+
exist_ok: Optional[bool] = Field(
|
|
55
|
+
default=True, description="Don't raise error if directory already exists"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class CreateFileInput(BaseModel):
|
|
60
|
+
file_path: str = Field(description="The absolute path to the file to create")
|
|
61
|
+
content: str = Field(description="The content to write to the file")
|
|
62
|
+
encoding: Optional[str] = Field(
|
|
63
|
+
default="utf-8", description="The encoding to use for the file"
|
|
64
|
+
)
|
|
65
|
+
mode: Optional[str] = Field(default="w", description="The file creation mode")
|
|
66
|
+
auto_create_dirs: Optional[bool] = Field(
|
|
67
|
+
default=True, description="Create parent directories if they don't exist"
|
|
68
|
+
)
|
|
69
|
+
overwrite: Optional[bool] = Field(
|
|
70
|
+
default=False, description="Overwrite the file if it already exists"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class FetchWebpageInput(BaseModel):
|
|
75
|
+
urls: List[str] = Field(description="List of URLs to fetch content from")
|
|
76
|
+
query: str = Field(description="The query to search for in the web page's content")
|
|
77
|
+
timeout: Optional[int] = Field(default=30, description="Request timeout in seconds")
|
|
78
|
+
max_content_length: Optional[int] = Field(
|
|
79
|
+
default=50000, description="Maximum content length to process"
|
|
80
|
+
)
|
|
81
|
+
user_agent: Optional[str] = Field(
|
|
82
|
+
default=None, description="Custom user agent string"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class FileSearchInput(BaseModel):
|
|
87
|
+
query: str = Field(description="Glob pattern to search for files")
|
|
88
|
+
max_results: Optional[int] = Field(
|
|
89
|
+
default=None, description="Maximum number of results to return"
|
|
90
|
+
)
|
|
91
|
+
include_hidden: Optional[bool] = Field(
|
|
92
|
+
default=False, description="Include hidden files in results"
|
|
93
|
+
)
|
|
94
|
+
sort_by: Optional[str] = Field(
|
|
95
|
+
default="name", description="Sort results by 'name', 'size', or 'modified'"
|
|
96
|
+
)
|
|
97
|
+
reverse_sort: Optional[bool] = Field(
|
|
98
|
+
default=False, description="Reverse the sort order"
|
|
99
|
+
)
|
|
100
|
+
show_details: Optional[bool] = Field(
|
|
101
|
+
default=False, description="Show file details like size and modification time"
|
|
102
|
+
)
|
|
103
|
+
base_path: Optional[str] = Field(
|
|
104
|
+
default=None, description="Base directory to search from"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class GrepSearchInput(BaseModel):
|
|
109
|
+
query: str = Field(description="The pattern to search for in files")
|
|
110
|
+
is_regexp: bool = Field(description="Whether the pattern is a regex")
|
|
111
|
+
include_pattern: Optional[str] = Field(
|
|
112
|
+
default=None, description="Search files matching this glob pattern"
|
|
113
|
+
)
|
|
114
|
+
max_results: Optional[int] = Field(
|
|
115
|
+
default=None, description="Maximum number of results to return"
|
|
116
|
+
)
|
|
117
|
+
context_lines: Optional[int] = Field(
|
|
118
|
+
default=0, description="Number of context lines to show around matches"
|
|
119
|
+
)
|
|
120
|
+
ignore_case: Optional[bool] = Field(
|
|
121
|
+
default=False, description="Perform case-insensitive search"
|
|
122
|
+
)
|
|
123
|
+
whole_word: Optional[bool] = Field(
|
|
124
|
+
default=False, description="Match whole words only"
|
|
125
|
+
)
|
|
126
|
+
invert_match: Optional[bool] = Field(
|
|
127
|
+
default=False, description="Show lines that don't match the pattern"
|
|
128
|
+
)
|
|
129
|
+
base_path: Optional[str] = Field(
|
|
130
|
+
default=None, description="Base directory to search from"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class ListDirInput(BaseModel):
|
|
135
|
+
path: str = Field(description="The absolute path to the directory to list")
|
|
136
|
+
show_hidden: Optional[bool] = Field(
|
|
137
|
+
default=False, description="Show hidden files and directories"
|
|
138
|
+
)
|
|
139
|
+
show_details: Optional[bool] = Field(
|
|
140
|
+
default=False, description="Show detailed information like size and permissions"
|
|
141
|
+
)
|
|
142
|
+
sort_by: Optional[str] = Field(
|
|
143
|
+
default="name", description="Sort by 'name', 'size', 'modified', or 'type'"
|
|
144
|
+
)
|
|
145
|
+
reverse_sort: Optional[bool] = Field(
|
|
146
|
+
default=False, description="Reverse the sort order"
|
|
147
|
+
)
|
|
148
|
+
recursive: Optional[bool] = Field(
|
|
149
|
+
default=False, description="List contents recursively"
|
|
150
|
+
)
|
|
151
|
+
max_depth: Optional[int] = Field(
|
|
152
|
+
default=3, description="Maximum depth for recursive listing"
|
|
153
|
+
)
|
|
154
|
+
file_filter: Optional[str] = Field(
|
|
155
|
+
default=None, description="Filter files by extension"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class ReadFileInput(BaseModel):
|
|
160
|
+
file_path: str = Field(description="The absolute path of the file to read")
|
|
161
|
+
start_line: int = Field(
|
|
162
|
+
description="The line number to start reading from (1-based)"
|
|
163
|
+
)
|
|
164
|
+
end_line: int = Field(
|
|
165
|
+
description="The inclusive line number to end reading at (1-based, -1 for end)"
|
|
166
|
+
)
|
|
167
|
+
encoding: Optional[str] = Field(
|
|
168
|
+
default=None, description="The encoding to use for reading the file"
|
|
169
|
+
)
|
|
170
|
+
show_line_numbers: Optional[bool] = Field(
|
|
171
|
+
default=True, description="Show line numbers in output"
|
|
172
|
+
)
|
|
173
|
+
highlight_syntax: Optional[bool] = Field(
|
|
174
|
+
default=False, description="Attempt to highlight syntax"
|
|
175
|
+
)
|
|
176
|
+
max_line_length: Optional[int] = Field(
|
|
177
|
+
default=1000, description="Maximum line length before truncation"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class ReplaceStringInput(BaseModel):
|
|
182
|
+
file_path: str = Field(description="The absolute path to the file to edit")
|
|
183
|
+
old_string: str = Field(description="The string to be replaced")
|
|
184
|
+
new_string: str = Field(description="The replacement string")
|
|
185
|
+
create_backup: Optional[bool] = Field(
|
|
186
|
+
default=True, description="Create a backup before editing"
|
|
187
|
+
)
|
|
188
|
+
dry_run: Optional[bool] = Field(
|
|
189
|
+
default=False, description="Show what would be changed without making changes"
|
|
190
|
+
)
|
|
191
|
+
whole_word: Optional[bool] = Field(
|
|
192
|
+
default=False, description="Only replace whole words"
|
|
193
|
+
)
|
|
194
|
+
ignore_case: Optional[bool] = Field(
|
|
195
|
+
default=False, description="Perform case-insensitive matching"
|
|
196
|
+
)
|
|
197
|
+
max_replacements: Optional[int] = Field(
|
|
198
|
+
default=None, description="Maximum number of replacements to make"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class SemanticSearchInput(BaseModel):
|
|
203
|
+
query: str = Field(description="The search query in natural language")
|
|
204
|
+
max_results: Optional[int] = Field(
|
|
205
|
+
default=10, description="Maximum number of results to return"
|
|
206
|
+
)
|
|
207
|
+
file_types: Optional[List[str]] = Field(
|
|
208
|
+
default=None, description="File types to search in"
|
|
209
|
+
)
|
|
210
|
+
similarity_threshold: Optional[float] = Field(
|
|
211
|
+
default=0.1, description="Minimum similarity score to include"
|
|
212
|
+
)
|
|
213
|
+
context_size: Optional[int] = Field(
|
|
214
|
+
default=3, description="Number of lines of context around matches"
|
|
215
|
+
)
|
|
216
|
+
search_path: Optional[str] = Field(
|
|
217
|
+
default=None, description="Directory to search in"
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class WebSearchInput(BaseModel):
|
|
222
|
+
query: str = Field(description="The search query")
|
|
223
|
+
max_results: Optional[int] = Field(
|
|
224
|
+
default=10, description="Maximum number of results to return"
|
|
225
|
+
)
|
|
226
|
+
search_engine: Optional[str] = Field(
|
|
227
|
+
default="duckduckgo", description="Search engine to use"
|
|
228
|
+
)
|
|
229
|
+
include_content: Optional[bool] = Field(
|
|
230
|
+
default=False, description="Include page content in results"
|
|
231
|
+
)
|
|
232
|
+
content_length: Optional[int] = Field(
|
|
233
|
+
default=1000, description="Maximum content length to extract"
|
|
234
|
+
)
|
|
235
|
+
filter_domain: Optional[str] = Field(
|
|
236
|
+
default=None, description="Only include results from this domain"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class TestFailureAnalysisInput(BaseModel):
|
|
241
|
+
test_output: Optional[str] = Field(
|
|
242
|
+
default=None, description="Path to test output file or direct test output"
|
|
243
|
+
)
|
|
244
|
+
test_framework: Optional[str] = Field(
|
|
245
|
+
default=None, description="Test framework used"
|
|
246
|
+
)
|
|
247
|
+
verbose: Optional[bool] = Field(default=False, description="Show detailed analysis")
|
|
248
|
+
suggest_fixes: Optional[bool] = Field(
|
|
249
|
+
default=True, description="Suggest potential fixes"
|
|
250
|
+
)
|
|
251
|
+
group_by_type: Optional[bool] = Field(
|
|
252
|
+
default=True, description="Group failures by error type"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
# Tool Classes
|
|
257
|
+
class CreateDirectoryTool(BaseTool):
|
|
258
|
+
"""📁 Create directories with enhanced features and permission handling."""
|
|
259
|
+
|
|
260
|
+
name: str = "create_directory"
|
|
261
|
+
description: str = """Create a directory structure with enhanced features.
|
|
262
|
+
|
|
263
|
+
This tool creates directories recursively (like mkdir -p) and provides
|
|
264
|
+
additional features like permission handling and validation.
|
|
265
|
+
|
|
266
|
+
Best for:
|
|
267
|
+
- Creating project directory structures
|
|
268
|
+
- Setting up development environments
|
|
269
|
+
- Organizing file systems
|
|
270
|
+
- Batch directory creation"""
|
|
271
|
+
|
|
272
|
+
args_schema: Type[BaseModel] = CreateDirectoryInput
|
|
273
|
+
|
|
274
|
+
def _run(
|
|
275
|
+
self,
|
|
276
|
+
dir_path: str,
|
|
277
|
+
mode: Optional[int] = 0o755,
|
|
278
|
+
parents: Optional[bool] = True,
|
|
279
|
+
exist_ok: Optional[bool] = True,
|
|
280
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
281
|
+
) -> str:
|
|
282
|
+
try:
|
|
283
|
+
success = create_directory(
|
|
284
|
+
dir_path=dir_path,
|
|
285
|
+
mode=mode or 0o755,
|
|
286
|
+
parents=parents if parents is not None else True,
|
|
287
|
+
exist_ok=exist_ok if exist_ok is not None else True,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
if success:
|
|
291
|
+
return f"Directory created successfully: {dir_path}"
|
|
292
|
+
else:
|
|
293
|
+
return f"Failed to create directory: {dir_path}"
|
|
294
|
+
|
|
295
|
+
except Exception as e:
|
|
296
|
+
return f"Error creating directory: {str(e)}"
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
class CreateFileTool(BaseTool):
|
|
300
|
+
"""📄 Create files with specified content and automatic directory creation."""
|
|
301
|
+
|
|
302
|
+
name: str = "create_file"
|
|
303
|
+
description: str = """Create a new file with the given content and automatically creates
|
|
304
|
+
parent directories if they don't exist. It includes validation and error handling.
|
|
305
|
+
|
|
306
|
+
Best for:
|
|
307
|
+
- Creating new source files
|
|
308
|
+
- Generating configuration files
|
|
309
|
+
- Setting up project templates
|
|
310
|
+
- Batch file creation"""
|
|
311
|
+
|
|
312
|
+
args_schema: Type[BaseModel] = CreateFileInput
|
|
313
|
+
|
|
314
|
+
def _run(
|
|
315
|
+
self,
|
|
316
|
+
file_path: str,
|
|
317
|
+
content: str,
|
|
318
|
+
encoding: Optional[str] = "utf-8",
|
|
319
|
+
mode: Optional[str] = "w",
|
|
320
|
+
auto_create_dirs: Optional[bool] = True,
|
|
321
|
+
overwrite: Optional[bool] = False,
|
|
322
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
323
|
+
) -> str:
|
|
324
|
+
try:
|
|
325
|
+
success = create_file(
|
|
326
|
+
file_path=file_path,
|
|
327
|
+
content=content,
|
|
328
|
+
encoding=encoding or "utf-8",
|
|
329
|
+
mode=mode or "w",
|
|
330
|
+
auto_create_dirs=(
|
|
331
|
+
auto_create_dirs if auto_create_dirs is not None else True
|
|
332
|
+
),
|
|
333
|
+
overwrite=overwrite if overwrite is not None else False,
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
if success:
|
|
337
|
+
return f"File created successfully: {file_path}"
|
|
338
|
+
else:
|
|
339
|
+
return f"Failed to create file: {file_path}"
|
|
340
|
+
|
|
341
|
+
except Exception as e:
|
|
342
|
+
return f"Error creating file: {str(e)}"
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class FileSearchTool(BaseTool):
|
|
346
|
+
"""🔍 Search for files using glob patterns with advanced features."""
|
|
347
|
+
|
|
348
|
+
name: str = "file_search"
|
|
349
|
+
description: str = """Search for files using glob patterns and provides additional
|
|
350
|
+
filtering and sorting options. It returns file paths matching the pattern.
|
|
351
|
+
|
|
352
|
+
Best for:
|
|
353
|
+
- Finding files by pattern
|
|
354
|
+
- Project file discovery
|
|
355
|
+
- Build system file location
|
|
356
|
+
- Code organization analysis"""
|
|
357
|
+
|
|
358
|
+
args_schema: Type[BaseModel] = FileSearchInput
|
|
359
|
+
|
|
360
|
+
def _run(
|
|
361
|
+
self,
|
|
362
|
+
query: str,
|
|
363
|
+
max_results: Optional[int] = None,
|
|
364
|
+
include_hidden: Optional[bool] = False,
|
|
365
|
+
sort_by: Optional[str] = "name",
|
|
366
|
+
reverse_sort: Optional[bool] = False,
|
|
367
|
+
show_details: Optional[bool] = False,
|
|
368
|
+
base_path: Optional[str] = None,
|
|
369
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
370
|
+
) -> str:
|
|
371
|
+
try:
|
|
372
|
+
results = file_search(
|
|
373
|
+
query=query,
|
|
374
|
+
max_results=max_results,
|
|
375
|
+
include_hidden=include_hidden or False,
|
|
376
|
+
sort_by=sort_by or "name",
|
|
377
|
+
reverse_sort=reverse_sort or False,
|
|
378
|
+
show_details=show_details or False,
|
|
379
|
+
base_path=base_path,
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
if not results:
|
|
383
|
+
return f"No files found matching pattern: {query}"
|
|
384
|
+
|
|
385
|
+
# Format results for display
|
|
386
|
+
output = [f"Found {len(results)} files matching pattern: {query}"]
|
|
387
|
+
|
|
388
|
+
if show_details:
|
|
389
|
+
output.append("-" * 80)
|
|
390
|
+
for result in results:
|
|
391
|
+
file_type = "DIR" if result["is_dir"] else "FILE"
|
|
392
|
+
size_str = f"{result['size']} bytes" if result["is_file"] else "-"
|
|
393
|
+
output.append(f"{result['name']:<40} {file_type:<5} {size_str}")
|
|
394
|
+
else:
|
|
395
|
+
for result in results:
|
|
396
|
+
suffix = "/" if result["is_dir"] else ""
|
|
397
|
+
output.append(f"{result['path']}{suffix}")
|
|
398
|
+
|
|
399
|
+
return "\n".join(output)
|
|
400
|
+
|
|
401
|
+
except Exception as e:
|
|
402
|
+
return f"Error searching files: {str(e)}"
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
class GrepSearchTool(BaseTool):
|
|
406
|
+
"""🔎 Fast text search in files using grep-like functionality."""
|
|
407
|
+
|
|
408
|
+
name: str = "grep_search"
|
|
409
|
+
description: str = """Perform fast text search in files using exact strings or regex patterns.
|
|
410
|
+
It provides context lines, file filtering, and other advanced search options.
|
|
411
|
+
|
|
412
|
+
Best for:
|
|
413
|
+
- Code pattern searching
|
|
414
|
+
- Log file analysis
|
|
415
|
+
- Documentation searching
|
|
416
|
+
- Multi-file text analysis"""
|
|
417
|
+
|
|
418
|
+
args_schema: Type[BaseModel] = GrepSearchInput
|
|
419
|
+
|
|
420
|
+
def _run(
|
|
421
|
+
self,
|
|
422
|
+
query: str,
|
|
423
|
+
is_regexp: bool,
|
|
424
|
+
include_pattern: Optional[str] = None,
|
|
425
|
+
max_results: Optional[int] = None,
|
|
426
|
+
context_lines: Optional[int] = 0,
|
|
427
|
+
ignore_case: Optional[bool] = False,
|
|
428
|
+
whole_word: Optional[bool] = False,
|
|
429
|
+
invert_match: Optional[bool] = False,
|
|
430
|
+
base_path: Optional[str] = None,
|
|
431
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
432
|
+
) -> str:
|
|
433
|
+
try:
|
|
434
|
+
results = grep_search(
|
|
435
|
+
query=query,
|
|
436
|
+
is_regexp=is_regexp,
|
|
437
|
+
include_pattern=include_pattern,
|
|
438
|
+
max_results=max_results,
|
|
439
|
+
context_lines=context_lines or 0,
|
|
440
|
+
ignore_case=ignore_case or False,
|
|
441
|
+
whole_word=whole_word or False,
|
|
442
|
+
invert_match=invert_match or False,
|
|
443
|
+
base_path=base_path,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
if not results:
|
|
447
|
+
return f"No matches found for pattern: {query}"
|
|
448
|
+
|
|
449
|
+
# Format results for display
|
|
450
|
+
total_matches = sum(r["total_matches"] for r in results)
|
|
451
|
+
output = [f"Found {total_matches} matches in {len(results)} files"]
|
|
452
|
+
output.append("=" * 60)
|
|
453
|
+
|
|
454
|
+
for result in results:
|
|
455
|
+
if "error" in result:
|
|
456
|
+
output.append(f"Error in {result['file']}: {result['error']}")
|
|
457
|
+
continue
|
|
458
|
+
|
|
459
|
+
output.append(f"\nFile: {result['file']}")
|
|
460
|
+
output.append(f"Matches: {result['total_matches']}")
|
|
461
|
+
output.append("-" * 40)
|
|
462
|
+
|
|
463
|
+
for match in result["matches"][:5]: # Show first 5 matches
|
|
464
|
+
if context_lines and match.get("context"):
|
|
465
|
+
for ctx in match["context"]:
|
|
466
|
+
prefix = ">" if ctx["is_match"] else " "
|
|
467
|
+
output.append(
|
|
468
|
+
f"{prefix}{ctx['line_number']:4d}: {ctx['content']}"
|
|
469
|
+
)
|
|
470
|
+
else:
|
|
471
|
+
output.append(f"{match['line_number']:4d}: {match['content']}")
|
|
472
|
+
|
|
473
|
+
return "\n".join(output)
|
|
474
|
+
|
|
475
|
+
except Exception as e:
|
|
476
|
+
return f"Error searching with grep: {str(e)}"
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
class ListDirTool(BaseTool):
|
|
480
|
+
"""📂 List directory contents with enhanced features."""
|
|
481
|
+
|
|
482
|
+
name: str = "list_dir"
|
|
483
|
+
description: str = """List the contents of a directory with various display options,
|
|
484
|
+
sorting capabilities, and filtering features.
|
|
485
|
+
|
|
486
|
+
Best for:
|
|
487
|
+
- Directory exploration
|
|
488
|
+
- Project structure analysis
|
|
489
|
+
- File system navigation
|
|
490
|
+
- Content organization"""
|
|
491
|
+
|
|
492
|
+
args_schema: Type[BaseModel] = ListDirInput
|
|
493
|
+
|
|
494
|
+
def _run(
|
|
495
|
+
self,
|
|
496
|
+
path: str,
|
|
497
|
+
show_hidden: Optional[bool] = False,
|
|
498
|
+
show_details: Optional[bool] = False,
|
|
499
|
+
sort_by: Optional[str] = "name",
|
|
500
|
+
reverse_sort: Optional[bool] = False,
|
|
501
|
+
recursive: Optional[bool] = False,
|
|
502
|
+
max_depth: Optional[int] = 3,
|
|
503
|
+
file_filter: Optional[str] = None,
|
|
504
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
505
|
+
) -> str:
|
|
506
|
+
try:
|
|
507
|
+
results = list_dir(
|
|
508
|
+
path=path,
|
|
509
|
+
show_hidden=show_hidden or False,
|
|
510
|
+
show_details=show_details or False,
|
|
511
|
+
sort_by=sort_by or "name",
|
|
512
|
+
reverse_sort=reverse_sort or False,
|
|
513
|
+
recursive=recursive or False,
|
|
514
|
+
max_depth=max_depth or 3,
|
|
515
|
+
file_filter=file_filter,
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
if not results:
|
|
519
|
+
return f"No contents found in directory: {path}"
|
|
520
|
+
|
|
521
|
+
# Format results for display
|
|
522
|
+
output = [f"Contents of {path}:"]
|
|
523
|
+
|
|
524
|
+
if show_details:
|
|
525
|
+
output.append(f"{'Name':<40} {'Type':<5} {'Size':<10}")
|
|
526
|
+
output.append("-" * 60)
|
|
527
|
+
|
|
528
|
+
for result in results:
|
|
529
|
+
file_type = "DIR" if result["is_dir"] else "FILE"
|
|
530
|
+
if result["is_symlink"]:
|
|
531
|
+
file_type = "LINK"
|
|
532
|
+
|
|
533
|
+
size_str = f"{result['size']} bytes" if result["is_file"] else "-"
|
|
534
|
+
indent = " " * result.get("depth", 0)
|
|
535
|
+
|
|
536
|
+
output.append(
|
|
537
|
+
f"{indent}{result['name']:<40} {file_type:<5} {size_str}"
|
|
538
|
+
)
|
|
539
|
+
else:
|
|
540
|
+
for result in results:
|
|
541
|
+
suffix = "/" if result["is_dir"] else ""
|
|
542
|
+
indent = " " * result.get("depth", 0)
|
|
543
|
+
output.append(f"{indent}{result['name']}{suffix}")
|
|
544
|
+
|
|
545
|
+
return "\n".join(output)
|
|
546
|
+
|
|
547
|
+
except Exception as e:
|
|
548
|
+
return f"Error listing directory: {str(e)}"
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
class ReadFileTool(BaseTool):
|
|
552
|
+
"""📖 Read file contents with line range support and encoding detection."""
|
|
553
|
+
|
|
554
|
+
name: str = "read_file"
|
|
555
|
+
description: str = """Read the contents of a file with support for line ranges,
|
|
556
|
+
encoding detection, and various output formats.
|
|
557
|
+
|
|
558
|
+
Best for:
|
|
559
|
+
- Code review and analysis
|
|
560
|
+
- Configuration file inspection
|
|
561
|
+
- Log file examination
|
|
562
|
+
- Content verification"""
|
|
563
|
+
|
|
564
|
+
args_schema: Type[BaseModel] = ReadFileInput
|
|
565
|
+
|
|
566
|
+
def _run(
|
|
567
|
+
self,
|
|
568
|
+
file_path: str,
|
|
569
|
+
start_line: int,
|
|
570
|
+
end_line: int,
|
|
571
|
+
encoding: Optional[str] = None,
|
|
572
|
+
show_line_numbers: Optional[bool] = True,
|
|
573
|
+
highlight_syntax: Optional[bool] = False,
|
|
574
|
+
max_line_length: Optional[int] = 1000,
|
|
575
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
576
|
+
) -> str:
|
|
577
|
+
try:
|
|
578
|
+
result = read_file(
|
|
579
|
+
file_path=file_path,
|
|
580
|
+
start_line=start_line,
|
|
581
|
+
end_line=end_line,
|
|
582
|
+
encoding=encoding,
|
|
583
|
+
show_line_numbers=(
|
|
584
|
+
show_line_numbers if show_line_numbers is not None else True
|
|
585
|
+
),
|
|
586
|
+
highlight_syntax=highlight_syntax or False,
|
|
587
|
+
max_line_length=max_line_length or 1000,
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
if not result["success"]:
|
|
591
|
+
return f"Error: {result['error']}"
|
|
592
|
+
|
|
593
|
+
# Format output
|
|
594
|
+
output = []
|
|
595
|
+
output.append(f"File: {result['file_path']}")
|
|
596
|
+
output.append(
|
|
597
|
+
f"Lines: {result['start_line']}-{result['end_line']} (of {result['total_lines']})"
|
|
598
|
+
)
|
|
599
|
+
output.append(f"Encoding: {result['encoding']}")
|
|
600
|
+
if result["file_language"]:
|
|
601
|
+
output.append(f"Language: {result['file_language']}")
|
|
602
|
+
output.append("-" * 60)
|
|
603
|
+
|
|
604
|
+
# Content
|
|
605
|
+
for line_info in result["content"]:
|
|
606
|
+
if result["show_line_numbers"]:
|
|
607
|
+
line_num = f"{line_info['line_number']:4d}"
|
|
608
|
+
content = line_info["content"]
|
|
609
|
+
|
|
610
|
+
# Show truncation indicator
|
|
611
|
+
if line_info["original_length"] > len(content):
|
|
612
|
+
truncated = " [truncated]"
|
|
613
|
+
else:
|
|
614
|
+
truncated = ""
|
|
615
|
+
|
|
616
|
+
output.append(f"{line_num}: {content}{truncated}")
|
|
617
|
+
else:
|
|
618
|
+
output.append(line_info["content"])
|
|
619
|
+
|
|
620
|
+
return "\n".join(output)
|
|
621
|
+
|
|
622
|
+
except Exception as e:
|
|
623
|
+
return f"Error reading file: {str(e)}"
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
class ReplaceStringTool(BaseTool):
|
|
627
|
+
"""🔄 Replace strings in files with safety checks and backup options."""
|
|
628
|
+
|
|
629
|
+
name: str = "replace_string"
|
|
630
|
+
description: str = """Replace strings in files with validation, backup options,
|
|
631
|
+
and various safety features to prevent accidental data loss.
|
|
632
|
+
|
|
633
|
+
Best for:
|
|
634
|
+
- Code refactoring
|
|
635
|
+
- Configuration updates
|
|
636
|
+
- Batch text replacements
|
|
637
|
+
- Safe file modifications"""
|
|
638
|
+
|
|
639
|
+
args_schema: Type[BaseModel] = ReplaceStringInput
|
|
640
|
+
|
|
641
|
+
def _run(
|
|
642
|
+
self,
|
|
643
|
+
file_path: str,
|
|
644
|
+
old_string: str,
|
|
645
|
+
new_string: str,
|
|
646
|
+
create_backup: Optional[bool] = True,
|
|
647
|
+
dry_run: Optional[bool] = False,
|
|
648
|
+
whole_word: Optional[bool] = False,
|
|
649
|
+
ignore_case: Optional[bool] = False,
|
|
650
|
+
max_replacements: Optional[int] = None,
|
|
651
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
652
|
+
) -> str:
|
|
653
|
+
try:
|
|
654
|
+
result = replace_string_in_file(
|
|
655
|
+
file_path=file_path,
|
|
656
|
+
old_string=old_string,
|
|
657
|
+
new_string=new_string,
|
|
658
|
+
create_backup=create_backup if create_backup is not None else True,
|
|
659
|
+
dry_run=dry_run or False,
|
|
660
|
+
whole_word=whole_word or False,
|
|
661
|
+
ignore_case=ignore_case or False,
|
|
662
|
+
max_replacements=max_replacements,
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
if not result["success"]:
|
|
666
|
+
return f"Error: {result['error']}"
|
|
667
|
+
|
|
668
|
+
output = [result["message"]]
|
|
669
|
+
|
|
670
|
+
if result.get("dry_run") and "changes_preview" in result:
|
|
671
|
+
output.append("\nChanges preview:")
|
|
672
|
+
for change in result["changes_preview"]:
|
|
673
|
+
output.append(
|
|
674
|
+
f"\nMatch {change['match_number']} at line {change['line_number']}:"
|
|
675
|
+
)
|
|
676
|
+
output.append(f"Before: {change['before']}")
|
|
677
|
+
output.append(f"After: {change['after']}")
|
|
678
|
+
|
|
679
|
+
if result.get("backup_created"):
|
|
680
|
+
output.append(f"Backup created: {result['backup_path']}")
|
|
681
|
+
|
|
682
|
+
return "\n".join(output)
|
|
683
|
+
|
|
684
|
+
except Exception as e:
|
|
685
|
+
return f"Error replacing string: {str(e)}"
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
class SemanticSearchTool(BaseTool):
|
|
689
|
+
"""🧠 Semantic search for relevant code using text similarity."""
|
|
690
|
+
|
|
691
|
+
name: str = "semantic_search"
|
|
692
|
+
description: str = """Perform semantic search across code and documentation files using
|
|
693
|
+
text similarity algorithms to find relevant content based on natural language queries.
|
|
694
|
+
|
|
695
|
+
Best for:
|
|
696
|
+
- Finding relevant code snippets
|
|
697
|
+
- Documentation discovery
|
|
698
|
+
- Code understanding and navigation
|
|
699
|
+
- Knowledge base search"""
|
|
700
|
+
|
|
701
|
+
args_schema: Type[BaseModel] = SemanticSearchInput
|
|
702
|
+
|
|
703
|
+
def _run(
|
|
704
|
+
self,
|
|
705
|
+
query: str,
|
|
706
|
+
max_results: Optional[int] = 10,
|
|
707
|
+
file_types: Optional[List[str]] = None,
|
|
708
|
+
similarity_threshold: Optional[float] = 0.1,
|
|
709
|
+
context_size: Optional[int] = 3,
|
|
710
|
+
search_path: Optional[str] = None,
|
|
711
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
712
|
+
) -> str:
|
|
713
|
+
try:
|
|
714
|
+
results = semantic_search(
|
|
715
|
+
query=query,
|
|
716
|
+
max_results=max_results or 10,
|
|
717
|
+
file_types=file_types,
|
|
718
|
+
similarity_threshold=similarity_threshold or 0.1,
|
|
719
|
+
context_size=context_size or 3,
|
|
720
|
+
search_path=search_path,
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
if not results:
|
|
724
|
+
return f"No results found for query: {query}"
|
|
725
|
+
|
|
726
|
+
# Format results for display
|
|
727
|
+
output = [f"Semantic search results for: {query}"]
|
|
728
|
+
output.append(f"Found {len(results)} results")
|
|
729
|
+
output.append("=" * 80)
|
|
730
|
+
|
|
731
|
+
for i, result in enumerate(results, 1):
|
|
732
|
+
output.append(
|
|
733
|
+
f"\nResult {i}: {result['file_path']}:{result['line_number']}"
|
|
734
|
+
)
|
|
735
|
+
output.append(f"Similarity Score: {result['similarity_score']:.3f}")
|
|
736
|
+
output.append(f"File Type: {result['file_type']}")
|
|
737
|
+
|
|
738
|
+
if result.get("match_type") == "function_definition":
|
|
739
|
+
output.append(f"Function: {result.get('function_name', 'unknown')}")
|
|
740
|
+
|
|
741
|
+
output.append("Context:")
|
|
742
|
+
for context_line in result["context"]:
|
|
743
|
+
marker = ">>>" if context_line["is_match"] else " "
|
|
744
|
+
output.append(
|
|
745
|
+
f"{marker} {context_line['line_number']:4d}: {context_line['content']}"
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
output.append("-" * 80)
|
|
749
|
+
|
|
750
|
+
return "\n".join(output)
|
|
751
|
+
|
|
752
|
+
except Exception as e:
|
|
753
|
+
return f"Error performing semantic search: {str(e)}"
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
class TestFailureAnalysisTool(BaseTool):
|
|
757
|
+
"""🔧 Test failure analysis tool for examining and debugging test failures."""
|
|
758
|
+
|
|
759
|
+
name: str = "test_failure_analysis"
|
|
760
|
+
description: str = """Analyze test failures, provide detailed error analysis, and suggest
|
|
761
|
+
potential fixes based on common failure patterns.
|
|
762
|
+
|
|
763
|
+
Best for:
|
|
764
|
+
- Debugging test failures
|
|
765
|
+
- Test maintenance
|
|
766
|
+
- Error pattern recognition
|
|
767
|
+
- Development workflow optimization"""
|
|
768
|
+
|
|
769
|
+
args_schema: Type[BaseModel] = TestFailureAnalysisInput
|
|
770
|
+
|
|
771
|
+
def _run(
|
|
772
|
+
self,
|
|
773
|
+
test_output: Optional[str] = None,
|
|
774
|
+
test_framework: Optional[str] = None,
|
|
775
|
+
verbose: Optional[bool] = False,
|
|
776
|
+
suggest_fixes: Optional[bool] = True,
|
|
777
|
+
group_by_type: Optional[bool] = True,
|
|
778
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
779
|
+
) -> str:
|
|
780
|
+
try:
|
|
781
|
+
analysis = analyze_test_failures(
|
|
782
|
+
test_output=test_output,
|
|
783
|
+
test_framework=test_framework,
|
|
784
|
+
verbose=verbose or False,
|
|
785
|
+
suggest_fixes=suggest_fixes if suggest_fixes is not None else True,
|
|
786
|
+
group_by_type=group_by_type if group_by_type is not None else True,
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
# Format analysis results
|
|
790
|
+
output = []
|
|
791
|
+
|
|
792
|
+
# Header
|
|
793
|
+
output.append("TEST FAILURE ANALYSIS")
|
|
794
|
+
output.append("=" * 50)
|
|
795
|
+
|
|
796
|
+
# Summary
|
|
797
|
+
if "summary" in analysis:
|
|
798
|
+
summary = analysis["summary"]
|
|
799
|
+
output.append(f"Total failures: {summary['total_failures']}")
|
|
800
|
+
output.append(f"Unique tests: {summary['unique_tests']}")
|
|
801
|
+
output.append(f"Unique files: {summary['unique_files']}")
|
|
802
|
+
output.append(f"Most common error: {summary['most_common_error']}")
|
|
803
|
+
output.append("")
|
|
804
|
+
|
|
805
|
+
# Error groups
|
|
806
|
+
if "error_groups" in analysis:
|
|
807
|
+
output.append("ERROR GROUPS:")
|
|
808
|
+
output.append("-" * 30)
|
|
809
|
+
for error_type, group_failures in analysis["error_groups"].items():
|
|
810
|
+
output.append(f"{error_type}: {len(group_failures)} failures")
|
|
811
|
+
for failure in group_failures[:3]: # Show first 3
|
|
812
|
+
output.append(f" - {failure['test_name']}")
|
|
813
|
+
if len(group_failures) > 3:
|
|
814
|
+
output.append(f" ... and {len(group_failures) - 3} more")
|
|
815
|
+
output.append("")
|
|
816
|
+
|
|
817
|
+
# Suggestions
|
|
818
|
+
if analysis.get("suggestions"):
|
|
819
|
+
output.append("SUGGESTIONS:")
|
|
820
|
+
output.append("-" * 30)
|
|
821
|
+
for suggestion in analysis["suggestions"]:
|
|
822
|
+
output.append(
|
|
823
|
+
f"[{suggestion['priority'].upper()}] {suggestion['message']}"
|
|
824
|
+
)
|
|
825
|
+
for action in suggestion["actions"]:
|
|
826
|
+
output.append(f" • {action}")
|
|
827
|
+
output.append("")
|
|
828
|
+
|
|
829
|
+
# Detailed failures
|
|
830
|
+
if analysis.get("failures"):
|
|
831
|
+
output.append("DETAILED FAILURES:")
|
|
832
|
+
output.append("-" * 30)
|
|
833
|
+
for i, failure in enumerate(
|
|
834
|
+
analysis["failures"][:5], 1
|
|
835
|
+
): # Show first 5
|
|
836
|
+
output.append(f"{i}. {failure['test_name']}")
|
|
837
|
+
if failure.get("file_path"):
|
|
838
|
+
output.append(
|
|
839
|
+
f" File: {failure['file_path']}:{failure.get('line_number', 'N/A')}"
|
|
840
|
+
)
|
|
841
|
+
output.append(f" Error: {failure['error_type']}")
|
|
842
|
+
output.append(f" Message: {failure['error_message'][:100]}...")
|
|
843
|
+
output.append("")
|
|
844
|
+
|
|
845
|
+
if len(analysis["failures"]) > 5:
|
|
846
|
+
output.append(
|
|
847
|
+
f"... and {len(analysis['failures']) - 5} more failures"
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
return "\n".join(output)
|
|
851
|
+
|
|
852
|
+
except Exception as e:
|
|
853
|
+
return f"Error analyzing test failures: {str(e)}"
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
def get_standalone_toolkit() -> List[BaseTool]:
|
|
857
|
+
"""Get all standalone tools with proper initialization.
|
|
858
|
+
|
|
859
|
+
Returns:
|
|
860
|
+
List of initialized standalone tools ready for LangChain integration.
|
|
861
|
+
"""
|
|
862
|
+
return [
|
|
863
|
+
CreateDirectoryTool(),
|
|
864
|
+
CreateFileTool(),
|
|
865
|
+
FileSearchTool(),
|
|
866
|
+
GrepSearchTool(),
|
|
867
|
+
ListDirTool(),
|
|
868
|
+
ReadFileTool(),
|
|
869
|
+
ReplaceStringTool(),
|
|
870
|
+
SemanticSearchTool(),
|
|
871
|
+
TestFailureAnalysisTool(),
|
|
872
|
+
]
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
def get_file_tools() -> List[BaseTool]:
|
|
876
|
+
"""Get only file-related tools."""
|
|
877
|
+
return [
|
|
878
|
+
CreateDirectoryTool(),
|
|
879
|
+
CreateFileTool(),
|
|
880
|
+
ListDirTool(),
|
|
881
|
+
ReadFileTool(),
|
|
882
|
+
ReplaceStringTool(),
|
|
883
|
+
]
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
def get_search_tools() -> List[BaseTool]:
|
|
887
|
+
"""Get only search-related tools."""
|
|
888
|
+
return [
|
|
889
|
+
FileSearchTool(),
|
|
890
|
+
GrepSearchTool(),
|
|
891
|
+
SemanticSearchTool(),
|
|
892
|
+
]
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
def get_analysis_tools() -> List[BaseTool]:
|
|
896
|
+
"""Get only analysis-related tools."""
|
|
897
|
+
return [
|
|
898
|
+
TestFailureAnalysisTool(),
|
|
899
|
+
SemanticSearchTool(),
|
|
900
|
+
]
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
# Tool selection guide for LLMs
|
|
904
|
+
STANDALONE_TOOL_SELECTION_GUIDE = """
|
|
905
|
+
🛠️ STANDALONE TOOLKIT SELECTION GUIDE FOR AI AGENTS:
|
|
906
|
+
|
|
907
|
+
📁 FILE OPERATIONS:
|
|
908
|
+
1. **create_directory** - Create directory structures with permissions
|
|
909
|
+
2. **create_file** - Create files with content and auto-directory creation
|
|
910
|
+
3. **list_dir** - List directory contents with filtering and sorting
|
|
911
|
+
4. **read_file** - Read file contents with line ranges and encoding detection
|
|
912
|
+
5. **replace_string** - Replace strings in files with backup and validation
|
|
913
|
+
|
|
914
|
+
🔍 SEARCH OPERATIONS:
|
|
915
|
+
6. **file_search** - Find files using glob patterns
|
|
916
|
+
7. **grep_search** - Fast text search in files with regex support
|
|
917
|
+
8. **semantic_search** - Semantic code search using text similarity
|
|
918
|
+
|
|
919
|
+
🌐 WEB OPERATIONS:
|
|
920
|
+
9. **fetch_webpage** - Fetch and search web page content
|
|
921
|
+
10. **web_search** - Search the web for information
|
|
922
|
+
|
|
923
|
+
🔧 ANALYSIS OPERATIONS:
|
|
924
|
+
11. **test_failure_analysis** - Analyze test failures and suggest fixes
|
|
925
|
+
|
|
926
|
+
⚠️ WORKFLOW RECOMMENDATIONS:
|
|
927
|
+
1. Use create_directory/create_file for project setup
|
|
928
|
+
2. Use file_search to locate files by pattern
|
|
929
|
+
3. Use grep_search for content-based searches
|
|
930
|
+
4. Use semantic_search for natural language code queries
|
|
931
|
+
5. Use read_file to examine specific file contents
|
|
932
|
+
6. Use replace_string for safe file modifications
|
|
933
|
+
7. Use web_search for external information
|
|
934
|
+
8. Use test_failure_analysis for debugging tests
|
|
935
|
+
|
|
936
|
+
💡 BEST PRACTICES:
|
|
937
|
+
- Always use dry_run=True for replace_string before actual changes
|
|
938
|
+
- Use appropriate file_types filters for semantic_search
|
|
939
|
+
- Combine tools for comprehensive analysis workflows
|
|
940
|
+
- Use context_lines in grep_search for better understanding
|
|
941
|
+
- Enable show_details in file operations for thorough analysis
|
|
942
|
+
|
|
943
|
+
🔧 EXAMPLE USAGE PATTERNS:
|
|
944
|
+
# Find Python files and search for functions
|
|
945
|
+
file_search(query="*.py", show_details=True)
|
|
946
|
+
grep_search(query="def ", is_regexp=True, include_pattern="*.py")
|
|
947
|
+
|
|
948
|
+
# Safe file modification
|
|
949
|
+
replace_string(file_path="config.py", old_string="DEBUG = False",
|
|
950
|
+
new_string="DEBUG = True", dry_run=True)
|
|
951
|
+
|
|
952
|
+
# Semantic code search
|
|
953
|
+
semantic_search(query="authentication function", file_types=[".py"])
|
|
954
|
+
|
|
955
|
+
# Web research
|
|
956
|
+
web_search(query="Python async programming best practices")
|
|
957
|
+
"""
|
|
958
|
+
|
|
959
|
+
# Export all tools and utilities
|
|
960
|
+
__all__ = [
|
|
961
|
+
# Tool classes
|
|
962
|
+
"CreateDirectoryTool",
|
|
963
|
+
"CreateFileTool",
|
|
964
|
+
"FileSearchTool",
|
|
965
|
+
"GrepSearchTool",
|
|
966
|
+
"ListDirTool",
|
|
967
|
+
"ReadFileTool",
|
|
968
|
+
"ReplaceStringTool",
|
|
969
|
+
"SemanticSearchTool",
|
|
970
|
+
"TestFailureAnalysisTool",
|
|
971
|
+
# Tool getters
|
|
972
|
+
"get_standalone_toolkit",
|
|
973
|
+
"get_file_tools",
|
|
974
|
+
"get_search_tools",
|
|
975
|
+
"get_analysis_tools",
|
|
976
|
+
"get_web_tools",
|
|
977
|
+
# Guide
|
|
978
|
+
"STANDALONE_TOOL_SELECTION_GUIDE",
|
|
979
|
+
]
|