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.
Files changed (81) hide show
  1. toolplane/__init__.py +106 -0
  2. toolplane/common/__init__.py +93 -0
  3. toolplane/common/base_config.py +129 -0
  4. toolplane/common/base_connection_manager.py +171 -0
  5. toolplane/common/base_session_manager.py +321 -0
  6. toolplane/common/base_tool_manager.py +347 -0
  7. toolplane/common/constants.py +47 -0
  8. toolplane/common/utils.py +310 -0
  9. toolplane/core/__init__.py +67 -0
  10. toolplane/core/config.py +107 -0
  11. toolplane/core/connection.py +285 -0
  12. toolplane/core/errors.py +298 -0
  13. toolplane/core/machine.py +480 -0
  14. toolplane/core/request.py +775 -0
  15. toolplane/core/session.py +332 -0
  16. toolplane/core/session_context.py +514 -0
  17. toolplane/core/task.py +130 -0
  18. toolplane/core/tool.py +329 -0
  19. toolplane/http_core/__init__.py +37 -0
  20. toolplane/http_core/http_config.py +97 -0
  21. toolplane/http_core/http_connection.py +409 -0
  22. toolplane/http_core/http_machine.py +298 -0
  23. toolplane/http_core/http_request.py +748 -0
  24. toolplane/http_core/http_session.py +348 -0
  25. toolplane/http_core/http_session_context.py +491 -0
  26. toolplane/http_core/http_task.py +101 -0
  27. toolplane/http_core/http_tool.py +400 -0
  28. toolplane/interfaces/__init__.py +27 -0
  29. toolplane/interfaces/client_interface.py +122 -0
  30. toolplane/interfaces/connection_interface.py +193 -0
  31. toolplane/interfaces/event_interface.py +290 -0
  32. toolplane/interfaces/request_interface.py +439 -0
  33. toolplane/interfaces/session_interface.py +288 -0
  34. toolplane/interfaces/tool_interface.py +441 -0
  35. toolplane/proto/__init__.py +0 -0
  36. toolplane/proto/service_pb2.py +315 -0
  37. toolplane/proto/service_pb2_grpc.py +2240 -0
  38. toolplane/provider_cli.py +268 -0
  39. toolplane/provider_registry.py +77 -0
  40. toolplane/provider_runtime.py +302 -0
  41. toolplane/toolkits/__init__.py +0 -0
  42. toolplane/toolkits/standalone_tools/__init__.py +0 -0
  43. toolplane/toolkits/standalone_tools/create_directory.py +94 -0
  44. toolplane/toolkits/standalone_tools/create_file.py +124 -0
  45. toolplane/toolkits/standalone_tools/file_search.py +229 -0
  46. toolplane/toolkits/standalone_tools/grep_search.py +372 -0
  47. toolplane/toolkits/standalone_tools/launcher.py +146 -0
  48. toolplane/toolkits/standalone_tools/list_dir.py +395 -0
  49. toolplane/toolkits/standalone_tools/read_file.py +346 -0
  50. toolplane/toolkits/standalone_tools/replace_string_in_file.py +407 -0
  51. toolplane/toolkits/standalone_tools/run_tests.py +66 -0
  52. toolplane/toolkits/standalone_tools/semantic_search.py +485 -0
  53. toolplane/toolkits/standalone_tools/standalone_toolkit.py +979 -0
  54. toolplane/toolkits/standalone_tools/test_failure_analysis.py +618 -0
  55. toolplane/toolkits/standalone_tools/test_standalone_toolkit.py +517 -0
  56. toolplane/toolkits/swe/__init__.py +35 -0
  57. toolplane/toolkits/swe/create_directory.py +15 -0
  58. toolplane/toolkits/swe/create_file.py +15 -0
  59. toolplane/toolkits/swe/descriptions.py +273 -0
  60. toolplane/toolkits/swe/execute_bash.py +93 -0
  61. toolplane/toolkits/swe/file_editor.py +775 -0
  62. toolplane/toolkits/swe/file_search.py +16 -0
  63. toolplane/toolkits/swe/finish.py +50 -0
  64. toolplane/toolkits/swe/grep_search.py +19 -0
  65. toolplane/toolkits/swe/list_dir.py +407 -0
  66. toolplane/toolkits/swe/read_file.py +18 -0
  67. toolplane/toolkits/swe/replace_string_in_file.py +17 -0
  68. toolplane/toolkits/swe/search.py +260 -0
  69. toolplane/toolkits/swe/semantic_search.py +20 -0
  70. toolplane/toolkits/swe/str_replace_editor.py +647 -0
  71. toolplane/toolkits/swe/submit.py +29 -0
  72. toolplane/toolkits/swe/swe_toolkit.py +1296 -0
  73. toolplane/toolplane_client.py +686 -0
  74. toolplane/toolplane_http_client.py +681 -0
  75. toolplane/utils/__init__.py +3 -0
  76. toolplane/utils/schema.py +146 -0
  77. toolplane_python_client-0.1.0.dist-info/METADATA +543 -0
  78. toolplane_python_client-0.1.0.dist-info/RECORD +81 -0
  79. toolplane_python_client-0.1.0.dist-info/WHEEL +5 -0
  80. toolplane_python_client-0.1.0.dist-info/entry_points.txt +2 -0
  81. toolplane_python_client-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,16 @@
1
+ """Re-exported from toolplane.toolkits.standalone_tools — the single
2
+ maintained copy of this tool. The SWE toolkit composes these safe
3
+ file tools with its own unsafe ones (execute_bash, file_editor).
4
+ """
5
+
6
+ from toolplane.toolkits.standalone_tools.file_search import ( # noqa: F401
7
+ file_search,
8
+ format_size,
9
+ main,
10
+ )
11
+
12
+ if __name__ == "__main__":
13
+ main()
14
+
15
+ if __name__ == "__main__":
16
+ main()
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Description: A simple finish tool with a "submit" command.
4
+
5
+ Notes about the `submit` command:
6
+ * When invoked with `--result`, the provided string is used for submitting required task results (e.g., localization files).
7
+ * If no `--result` is provided, it defaults to an empty string.
8
+
9
+ **Parameters:**
10
+ 1. **command** (`string`, required): The command to run. Currently allowed option is: `submit`.
11
+ - Allowed value: [`submit`]
12
+ 2. **result** (`string`, optional): The result text to submit. Defaults to an empty string.
13
+ """
14
+
15
+ import argparse
16
+ import sys
17
+
18
+
19
+ def submit(result: str = ""):
20
+ """
21
+ Submits a final result, printing a message that includes the result.
22
+ """
23
+ print("<<<Finished>>>")
24
+ # if result:
25
+ # print(f"Final result submitted: {result}")
26
+ # else:
27
+ # print("No result provided.")
28
+ # You can add more logic here as needed
29
+
30
+
31
+ def main():
32
+ parser = argparse.ArgumentParser(
33
+ description="submit tool: run the `submit` command with an optional `--result` argument."
34
+ )
35
+ parser.add_argument("command", help="Subcommand to run (currently only `submit`).")
36
+ parser.add_argument(
37
+ "--result", help="The result text to submit (optional).", default=""
38
+ )
39
+
40
+ args = parser.parse_args()
41
+
42
+ if args.command == "submit":
43
+ submit(args.result)
44
+ else:
45
+ print(f"Unknown command '{args.command}'. Only `submit` is supported.")
46
+ sys.exit(1)
47
+
48
+
49
+ if __name__ == "__main__":
50
+ main()
@@ -0,0 +1,19 @@
1
+ """Re-exported from toolplane.toolkits.standalone_tools — the single
2
+ maintained copy of this tool. The SWE toolkit composes these safe
3
+ file tools with its own unsafe ones (execute_bash, file_editor).
4
+ """
5
+
6
+ from toolplane.toolkits.standalone_tools.grep_search import ( # noqa: F401
7
+ get_all_text_files,
8
+ get_files_by_pattern,
9
+ grep_search,
10
+ is_text_file,
11
+ main,
12
+ search_file,
13
+ )
14
+
15
+ if __name__ == "__main__":
16
+ main()
17
+
18
+ if __name__ == "__main__":
19
+ main()
@@ -0,0 +1,407 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Description: List directory contents with enhanced features.
4
+
5
+ This tool lists the contents of a directory with various display options,
6
+ sorting capabilities, and filtering features.
7
+
8
+ Parameters:
9
+ path (string, required): The absolute path to the directory to list.
10
+ show_hidden (boolean, optional): Show hidden files and directories (default: False).
11
+ show_details (boolean, optional): Show detailed information like size and permissions (default: False).
12
+ sort_by (string, optional): Sort by 'name', 'size', 'modified', 'type' (default: 'name').
13
+ reverse_sort (boolean, optional): Reverse the sort order (default: False).
14
+ recursive (boolean, optional): List contents recursively (default: False).
15
+ max_depth (integer, optional): Maximum depth for recursive listing (default: 3).
16
+ file_filter (string, optional): Filter files by extension (e.g., '.py', '.txt').
17
+ """
18
+
19
+ import argparse
20
+ import os
21
+ import stat
22
+ import sys
23
+ import time
24
+ from pathlib import Path
25
+ from typing import Any, Dict, List, Optional
26
+
27
+
28
+ def list_dir(
29
+ path: str,
30
+ show_hidden: bool = False,
31
+ show_details: bool = False,
32
+ sort_by: str = "name",
33
+ reverse_sort: bool = False,
34
+ recursive: bool = False,
35
+ max_depth: int = 3,
36
+ file_filter: Optional[str] = None,
37
+ ) -> List[Dict[str, Any]]:
38
+ """
39
+ List directory contents with enhanced features.
40
+
41
+ Args:
42
+ path: The directory path to list
43
+ show_hidden: Show hidden files and directories
44
+ show_details: Show detailed information
45
+ sort_by: Sort by 'name', 'size', 'modified', 'type'
46
+ reverse_sort: Reverse the sort order
47
+ recursive: List contents recursively
48
+ max_depth: Maximum depth for recursive listing
49
+ file_filter: Filter files by extension
50
+
51
+ Returns:
52
+ List of dictionaries containing file/directory information
53
+ """
54
+ try:
55
+ dir_path = Path(path)
56
+
57
+ if not dir_path.exists():
58
+ print(f"Error: Directory '{path}' does not exist.", file=sys.stderr)
59
+ return []
60
+
61
+ if not dir_path.is_dir():
62
+ print(f"Error: '{path}' is not a directory.", file=sys.stderr)
63
+ return []
64
+
65
+ results = []
66
+
67
+ base_dir = dir_path.resolve()
68
+ if recursive:
69
+ results = _list_recursive(
70
+ dir_path, base_dir, show_hidden, max_depth, file_filter, current_depth=0
71
+ )
72
+ else:
73
+ results = _list_single_dir(dir_path, base_dir, show_hidden, file_filter)
74
+
75
+ # Add detailed information if requested
76
+ if show_details:
77
+ for result in results:
78
+ _add_detailed_info(result)
79
+
80
+ # Sort results
81
+ results = _sort_results(results, sort_by, reverse_sort)
82
+
83
+ return results
84
+
85
+ except PermissionError:
86
+ print(f"Error: Permission denied accessing '{path}'.", file=sys.stderr)
87
+ return []
88
+ except Exception as e:
89
+ print(f"Error listing directory '{path}': {e}", file=sys.stderr)
90
+ return []
91
+
92
+
93
+ def _list_single_dir(
94
+ dir_path: Path, base_dir: Path, show_hidden: bool, file_filter: Optional[str]
95
+ ) -> List[Dict[str, Any]]:
96
+ """List contents of a single directory."""
97
+ results = []
98
+
99
+ try:
100
+ for item in dir_path.iterdir():
101
+ # Skip hidden files if not requested
102
+ if not show_hidden and item.name.startswith("."):
103
+ continue
104
+
105
+ # Apply file filter
106
+ if file_filter and item.is_file() and not item.name.endswith(file_filter):
107
+ continue
108
+
109
+ try:
110
+ stat_info = item.stat()
111
+
112
+ result = {
113
+ "name": item.name,
114
+ "path": str(item.resolve()),
115
+ "relative_path": str(item.resolve().relative_to(base_dir)),
116
+ "is_file": item.is_file(),
117
+ "is_dir": item.is_dir(),
118
+ "is_symlink": item.is_symlink(),
119
+ "size": stat_info.st_size if item.is_file() else 0,
120
+ "modified": stat_info.st_mtime,
121
+ "modified_readable": time.strftime(
122
+ "%Y-%m-%d %H:%M:%S", time.localtime(stat_info.st_mtime)
123
+ ),
124
+ "permissions": stat.filemode(stat_info.st_mode),
125
+ "depth": 0,
126
+ }
127
+
128
+ results.append(result)
129
+
130
+ except (OSError, PermissionError):
131
+ # Skip items that can't be accessed
132
+ continue
133
+
134
+ except PermissionError:
135
+ pass
136
+
137
+ return results
138
+
139
+
140
+ def _list_recursive(
141
+ dir_path: Path,
142
+ base_dir: Path,
143
+ show_hidden: bool,
144
+ max_depth: int,
145
+ file_filter: Optional[str],
146
+ current_depth: int = 0,
147
+ ) -> List[Dict[str, Any]]:
148
+ """List directory contents recursively.
149
+
150
+ Includes items at depth == max_depth but does not recurse deeper.
151
+ """
152
+ results = []
153
+
154
+ try:
155
+ for item in dir_path.iterdir():
156
+ # Skip hidden files if not requested
157
+ if not show_hidden and item.name.startswith("."):
158
+ continue
159
+
160
+ # Apply file filter
161
+ if file_filter and item.is_file() and not item.name.endswith(file_filter):
162
+ continue
163
+
164
+ try:
165
+ stat_info = item.stat()
166
+
167
+ result = {
168
+ "name": item.name,
169
+ "path": str(item.resolve()),
170
+ "relative_path": str(item.resolve().relative_to(base_dir)),
171
+ "is_file": item.is_file(),
172
+ "is_dir": item.is_dir(),
173
+ "is_symlink": item.is_symlink(),
174
+ "size": stat_info.st_size if item.is_file() else 0,
175
+ "modified": stat_info.st_mtime,
176
+ "modified_readable": time.strftime(
177
+ "%Y-%m-%d %H:%M:%S", time.localtime(stat_info.st_mtime)
178
+ ),
179
+ "permissions": stat.filemode(stat_info.st_mode),
180
+ "depth": current_depth,
181
+ }
182
+
183
+ results.append(result)
184
+
185
+ # Recurse into subdirectories if we haven't reached max_depth
186
+ if (
187
+ item.is_dir()
188
+ and not item.is_symlink()
189
+ and current_depth < max_depth
190
+ ):
191
+ sub_results = _list_recursive(
192
+ item,
193
+ base_dir,
194
+ show_hidden,
195
+ max_depth,
196
+ file_filter,
197
+ current_depth + 1,
198
+ )
199
+ results.extend(sub_results)
200
+
201
+ except (OSError, PermissionError):
202
+ # Skip items that can't be accessed
203
+ continue
204
+
205
+ except PermissionError:
206
+ pass
207
+
208
+ return results
209
+
210
+
211
+ def _add_detailed_info(result: Dict[str, Any]) -> None:
212
+ """Add detailed information to a result entry."""
213
+ try:
214
+ path = Path(result["path"])
215
+ stat_info = path.stat()
216
+
217
+ result.update(
218
+ {
219
+ "owner_readable": bool(stat_info.st_mode & stat.S_IRUSR),
220
+ "owner_writable": bool(stat_info.st_mode & stat.S_IWUSR),
221
+ "owner_executable": bool(stat_info.st_mode & stat.S_IXUSR),
222
+ "group_readable": bool(stat_info.st_mode & stat.S_IRGRP),
223
+ "group_writable": bool(stat_info.st_mode & stat.S_IWGRP),
224
+ "group_executable": bool(stat_info.st_mode & stat.S_IXGRP),
225
+ "other_readable": bool(stat_info.st_mode & stat.S_IROTH),
226
+ "other_writable": bool(stat_info.st_mode & stat.S_IWOTH),
227
+ "other_executable": bool(stat_info.st_mode & stat.S_IXOTH),
228
+ "inode": stat_info.st_ino,
229
+ "device": stat_info.st_dev,
230
+ "nlink": stat_info.st_nlink,
231
+ "uid": stat_info.st_uid,
232
+ "gid": stat_info.st_gid,
233
+ "accessed": stat_info.st_atime,
234
+ "accessed_readable": time.strftime(
235
+ "%Y-%m-%d %H:%M:%S", time.localtime(stat_info.st_atime)
236
+ ),
237
+ "created": getattr(stat_info, "st_birthtime", stat_info.st_ctime),
238
+ "created_readable": time.strftime(
239
+ "%Y-%m-%d %H:%M:%S",
240
+ time.localtime(
241
+ getattr(stat_info, "st_birthtime", stat_info.st_ctime)
242
+ ),
243
+ ),
244
+ }
245
+ )
246
+ except (OSError, PermissionError):
247
+ pass
248
+
249
+
250
+ def _sort_results(
251
+ results: List[Dict[str, Any]], sort_by: str, reverse_sort: bool
252
+ ) -> List[Dict[str, Any]]:
253
+ """Sort results by the specified criteria."""
254
+ if sort_by == "name":
255
+ results.sort(key=lambda x: x["name"].lower(), reverse=reverse_sort)
256
+ elif sort_by == "size":
257
+ results.sort(key=lambda x: x["size"], reverse=reverse_sort)
258
+ elif sort_by == "modified":
259
+ results.sort(key=lambda x: x["modified"], reverse=reverse_sort)
260
+ elif sort_by == "type":
261
+ # Sort by type (directories first, then files)
262
+ results.sort(
263
+ key=lambda x: (not x["is_dir"], x["name"].lower()), reverse=reverse_sort
264
+ )
265
+
266
+ return results
267
+
268
+
269
+ def format_size(size_bytes: int) -> str:
270
+ """Format file size in human-readable format."""
271
+ if size_bytes == 0:
272
+ return "0 B"
273
+
274
+ units = ["B", "KB", "MB", "GB", "TB"]
275
+ i = 0
276
+ size = float(size_bytes)
277
+ while size >= 1024.0 and i < len(units) - 1:
278
+ size /= 1024.0
279
+ i += 1
280
+
281
+ return f"{size:.1f} {units[i]}"
282
+
283
+
284
+ def main():
285
+ parser = argparse.ArgumentParser(
286
+ description="List directory contents with enhanced features."
287
+ )
288
+ parser.add_argument(
289
+ "path", type=str, help="The absolute path to the directory to list"
290
+ )
291
+ parser.add_argument(
292
+ "--show_hidden",
293
+ action="store_true",
294
+ default=False,
295
+ help="Show hidden files and directories (default: False)",
296
+ )
297
+ parser.add_argument(
298
+ "--show_details",
299
+ action="store_true",
300
+ default=False,
301
+ help="Show detailed information like size and permissions (default: False)",
302
+ )
303
+ parser.add_argument(
304
+ "--sort_by",
305
+ choices=["name", "size", "modified", "type"],
306
+ default="name",
307
+ help="Sort by 'name', 'size', 'modified', or 'type' (default: name)",
308
+ )
309
+ parser.add_argument(
310
+ "--reverse_sort",
311
+ action="store_true",
312
+ default=False,
313
+ help="Reverse the sort order (default: False)",
314
+ )
315
+ parser.add_argument(
316
+ "--recursive",
317
+ action="store_true",
318
+ default=False,
319
+ help="List contents recursively (default: False)",
320
+ )
321
+ parser.add_argument(
322
+ "--max_depth",
323
+ type=int,
324
+ default=3,
325
+ help="Maximum depth for recursive listing (default: 3)",
326
+ )
327
+ parser.add_argument(
328
+ "--file_filter",
329
+ type=str,
330
+ help="Filter files by extension (e.g., '.py', '.txt')",
331
+ )
332
+ parser.add_argument(
333
+ "--output_format",
334
+ choices=["list", "table", "json", "tree"],
335
+ default="list",
336
+ help="Output format (default: list)",
337
+ )
338
+
339
+ args = parser.parse_args()
340
+
341
+ results = list_dir(
342
+ args.path,
343
+ show_hidden=args.show_hidden,
344
+ show_details=args.show_details,
345
+ sort_by=args.sort_by,
346
+ reverse_sort=args.reverse_sort,
347
+ recursive=args.recursive,
348
+ max_depth=args.max_depth,
349
+ file_filter=args.file_filter,
350
+ )
351
+
352
+ if not results:
353
+ sys.exit(1)
354
+
355
+ if args.output_format == "json":
356
+ import json
357
+
358
+ print(json.dumps(results, indent=2))
359
+
360
+ elif args.output_format == "table":
361
+ if args.show_details:
362
+ print(
363
+ f"{'Name':<30} {'Type':<5} {'Size':<10} {'Permissions':<12} {'Modified':<20}"
364
+ )
365
+ print("-" * 90)
366
+
367
+ for result in results:
368
+ file_type = "DIR" if result["is_dir"] else "FILE"
369
+ if result["is_symlink"]:
370
+ file_type = "LINK"
371
+
372
+ size_str = format_size(result["size"]) if result["is_file"] else "-"
373
+ indent = " " * result.get("depth", 0)
374
+
375
+ print(
376
+ f"{indent}{result['name']:<30} {file_type:<5} {size_str:<10} {result['permissions']:<12} {result['modified_readable']:<20}"
377
+ )
378
+ else:
379
+ print(f"{'Name':<40} {'Type':<5} {'Size':<10}")
380
+ print("-" * 60)
381
+
382
+ for result in results:
383
+ file_type = "DIR" if result["is_dir"] else "FILE"
384
+ if result["is_symlink"]:
385
+ file_type = "LINK"
386
+
387
+ size_str = format_size(result["size"]) if result["is_file"] else "-"
388
+ indent = " " * result.get("depth", 0)
389
+
390
+ print(f"{indent}{result['name']:<40} {file_type:<5} {size_str:<10}")
391
+
392
+ elif args.output_format == "tree":
393
+ for result in results:
394
+ indent = " " * result.get("depth", 0)
395
+ marker = "├── " if result.get("depth", 0) > 0 else ""
396
+ suffix = "/" if result["is_dir"] else ""
397
+
398
+ print(f"{indent}{marker}{result['name']}{suffix}")
399
+
400
+ else: # list format
401
+ for result in results:
402
+ suffix = "/" if result["is_dir"] else ""
403
+ print(f"{result['name']}{suffix}")
404
+
405
+
406
+ if __name__ == "__main__":
407
+ main()
@@ -0,0 +1,18 @@
1
+ """Re-exported from toolplane.toolkits.standalone_tools — the single
2
+ maintained copy of this tool. The SWE toolkit composes these safe
3
+ file tools with its own unsafe ones (execute_bash, file_editor).
4
+ """
5
+
6
+ from toolplane.toolkits.standalone_tools.read_file import ( # noqa: F401
7
+ detect_encoding,
8
+ format_output,
9
+ get_file_language,
10
+ main,
11
+ read_file,
12
+ )
13
+
14
+ if __name__ == "__main__":
15
+ main()
16
+
17
+ if __name__ == "__main__":
18
+ main()
@@ -0,0 +1,17 @@
1
+ """Re-exported from toolplane.toolkits.standalone_tools — the single
2
+ maintained copy of this tool. The SWE toolkit composes these safe
3
+ file tools with its own unsafe ones (execute_bash, file_editor).
4
+ """
5
+
6
+ from toolplane.toolkits.standalone_tools.replace_string_in_file import ( # noqa: F401
7
+ create_file_backup,
8
+ main,
9
+ replace_string_in_file,
10
+ validate_old_string_uniqueness,
11
+ )
12
+
13
+ if __name__ == "__main__":
14
+ main()
15
+
16
+ if __name__ == "__main__":
17
+ main()