siada-cli 0.0.1__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 (215) hide show
  1. agent_config.yaml +34 -0
  2. siada/__init__.py +13 -0
  3. siada/agent_hub/__init__.py +10 -0
  4. siada/agent_hub/coder/bug_fix_agent.py +398 -0
  5. siada/agent_hub/coder/code_gen_agent.py +235 -0
  6. siada/agent_hub/coder/fe_gen_agent.py +37 -0
  7. siada/agent_hub/coder/issue_review_agent.py +68 -0
  8. siada/agent_hub/coder/prompt/__init__.py +0 -0
  9. siada/agent_hub/coder/prompt/base/__init__.py +0 -0
  10. siada/agent_hub/coder/prompt/base/capabilities.py +18 -0
  11. siada/agent_hub/coder/prompt/base/non_interactive.py +14 -0
  12. siada/agent_hub/coder/prompt/base/prompt_builder.py +33 -0
  13. siada/agent_hub/coder/prompt/base/rules.py +40 -0
  14. siada/agent_hub/coder/prompt/base/tool_use.py +14 -0
  15. siada/agent_hub/coder/prompt/bug_prompt/bug_fix_prompt.py +51 -0
  16. siada/agent_hub/coder/prompt/bug_prompt/rules.py +53 -0
  17. siada/agent_hub/coder/prompt/code_gen_prompt.py +45 -0
  18. siada/agent_hub/coder/prompt/fe_gen_prompt.py +45 -0
  19. siada/agent_hub/coder/prompt/issue_review_prompt.py +121 -0
  20. siada/agent_hub/coder/tracing/__init__.py +22 -0
  21. siada/agent_hub/coder/tracing/logger_tracing_processor.py +458 -0
  22. siada/agent_hub/hooks/__init__.py +0 -0
  23. siada/agent_hub/hooks/io_hooks.py +30 -0
  24. siada/agent_hub/siada_agent.py +214 -0
  25. siada/config/__init__.py +0 -0
  26. siada/config/config_loader.py +67 -0
  27. siada/entrypoint/__init__.py +3 -0
  28. siada/entrypoint/args_parser/__init__.py +0 -0
  29. siada/entrypoint/args_parser/args.py +195 -0
  30. siada/entrypoint/interaction/__init__.py +0 -0
  31. siada/entrypoint/interaction/base_turn.py +107 -0
  32. siada/entrypoint/interaction/config.py +30 -0
  33. siada/entrypoint/interaction/controller.py +122 -0
  34. siada/entrypoint/interaction/nointeractive_controller.py +27 -0
  35. siada/entrypoint/interaction/turn/interface.py +116 -0
  36. siada/entrypoint/interaction/turn/models.py +34 -0
  37. siada/entrypoint/interaction/turn/run_turn.py +641 -0
  38. siada/entrypoint/interaction/turn_factory.py +35 -0
  39. siada/entrypoint/interaction/turn_models.py +28 -0
  40. siada/entrypoint/siadahub.py +413 -0
  41. siada/foundation/__init__.py +0 -0
  42. siada/foundation/code_agent_context.py +48 -0
  43. siada/foundation/config.py +59 -0
  44. siada/foundation/constants.py +2 -0
  45. siada/foundation/context.py +76 -0
  46. siada/foundation/logging.py +341 -0
  47. siada/foundation/tools/__init__.py +0 -0
  48. siada/foundation/tools/get_git_diff.py +105 -0
  49. siada/io/__init__.py +0 -0
  50. siada/io/banner.py +148 -0
  51. siada/io/color_settings.py +207 -0
  52. siada/io/color_utils.py +16 -0
  53. siada/io/components/__init__.py +0 -0
  54. siada/io/components/mdstream.py +204 -0
  55. siada/io/console_printer.py +68 -0
  56. siada/io/io.py +661 -0
  57. siada/io/key_bindings.py +129 -0
  58. siada/io/notification_command.py +40 -0
  59. siada/io/test_banner.py +64 -0
  60. siada/models/__init__.py +0 -0
  61. siada/models/agent.py +47 -0
  62. siada/models/coder/__init__.py +0 -0
  63. siada/models/converter.py +27 -0
  64. siada/models/model_base_config.py +121 -0
  65. siada/models/model_run_config.py +153 -0
  66. siada/provider/__init__.py +0 -0
  67. siada/provider/client_factory.py +112 -0
  68. siada/provider/llm_client.py +11 -0
  69. siada/provider/openrouter/__init__.py +0 -0
  70. siada/provider/openrouter/coverter.py +17 -0
  71. siada/provider/openrouter/openroute_provider.py +33 -0
  72. siada/provider/provider_factory.py +53 -0
  73. siada/queries/tree-sitter-language-pack/README.md +7 -0
  74. siada/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
  75. siada/queries/tree-sitter-language-pack/c-tags.scm +9 -0
  76. siada/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
  77. siada/queries/tree-sitter-language-pack/commonlisp-tags.scm +122 -0
  78. siada/queries/tree-sitter-language-pack/cpp-tags.scm +15 -0
  79. siada/queries/tree-sitter-language-pack/csharp-tags.scm +26 -0
  80. siada/queries/tree-sitter-language-pack/d-tags.scm +26 -0
  81. siada/queries/tree-sitter-language-pack/dart-tags.scm +92 -0
  82. siada/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
  83. siada/queries/tree-sitter-language-pack/elixir-tags.scm +54 -0
  84. siada/queries/tree-sitter-language-pack/elm-tags.scm +19 -0
  85. siada/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
  86. siada/queries/tree-sitter-language-pack/go-tags.scm +42 -0
  87. siada/queries/tree-sitter-language-pack/java-tags.scm +20 -0
  88. siada/queries/tree-sitter-language-pack/javascript-tags.scm +88 -0
  89. siada/queries/tree-sitter-language-pack/lua-tags.scm +34 -0
  90. siada/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
  91. siada/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +98 -0
  92. siada/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
  93. siada/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
  94. siada/queries/tree-sitter-language-pack/python-tags.scm +14 -0
  95. siada/queries/tree-sitter-language-pack/r-tags.scm +21 -0
  96. siada/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
  97. siada/queries/tree-sitter-language-pack/ruby-tags.scm +64 -0
  98. siada/queries/tree-sitter-language-pack/rust-tags.scm +60 -0
  99. siada/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
  100. siada/queries/tree-sitter-language-pack/swift-tags.scm +51 -0
  101. siada/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
  102. siada/queries/tree-sitter-languages/README.md +23 -0
  103. siada/queries/tree-sitter-languages/c-tags.scm +9 -0
  104. siada/queries/tree-sitter-languages/c_sharp-tags.scm +46 -0
  105. siada/queries/tree-sitter-languages/cpp-tags.scm +15 -0
  106. siada/queries/tree-sitter-languages/dart-tags.scm +91 -0
  107. siada/queries/tree-sitter-languages/elisp-tags.scm +8 -0
  108. siada/queries/tree-sitter-languages/elixir-tags.scm +54 -0
  109. siada/queries/tree-sitter-languages/elm-tags.scm +19 -0
  110. siada/queries/tree-sitter-languages/go-tags.scm +30 -0
  111. siada/queries/tree-sitter-languages/hcl-tags.scm +77 -0
  112. siada/queries/tree-sitter-languages/java-tags.scm +20 -0
  113. siada/queries/tree-sitter-languages/javascript-tags.scm +88 -0
  114. siada/queries/tree-sitter-languages/kotlin-tags.scm +27 -0
  115. siada/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
  116. siada/queries/tree-sitter-languages/ocaml_interface-tags.scm +98 -0
  117. siada/queries/tree-sitter-languages/php-tags.scm +26 -0
  118. siada/queries/tree-sitter-languages/python-tags.scm +12 -0
  119. siada/queries/tree-sitter-languages/ql-tags.scm +26 -0
  120. siada/queries/tree-sitter-languages/ruby-tags.scm +64 -0
  121. siada/queries/tree-sitter-languages/rust-tags.scm +60 -0
  122. siada/queries/tree-sitter-languages/scala-tags.scm +65 -0
  123. siada/queries/tree-sitter-languages/typescript-tags.scm +41 -0
  124. siada/services/__init__.py +30 -0
  125. siada/services/at_file_recommendation_design_document.md +1213 -0
  126. siada/services/code_context_manager.py +136 -0
  127. siada/services/enhanced_fix_result_check.py +546 -0
  128. siada/services/execution_trace_collector.py +207 -0
  129. siada/services/file_recommendation/__init__.py +136 -0
  130. siada/services/file_recommendation/core/__init__.py +17 -0
  131. siada/services/file_recommendation/core/completion_engine.py +351 -0
  132. siada/services/file_recommendation/core/config.py +62 -0
  133. siada/services/file_recommendation/core/file_discovery.py +353 -0
  134. siada/services/file_recommendation/core/suggestion.py +110 -0
  135. siada/services/file_recommendation/utils/__init__.py +22 -0
  136. siada/services/file_recommendation/utils/path_utils.py +138 -0
  137. siada/services/file_recommendation/utils/text_utils.py +253 -0
  138. siada/services/fix_result_check.py +377 -0
  139. siada/services/handle_at_command/README.md +247 -0
  140. siada/services/handle_at_command/__init__.py +115 -0
  141. siada/services/handle_at_command/exceptions.py +46 -0
  142. siada/services/handle_at_command/models.py +92 -0
  143. siada/services/handle_at_command/parser.py +189 -0
  144. siada/services/handle_at_command/processor.py +321 -0
  145. siada/services/handle_at_command/resolver.py +318 -0
  146. siada/services/handle_at_command/utils.py +345 -0
  147. siada/services/model_info_service.py +103 -0
  148. siada/services/siada_runner.py +170 -0
  149. siada/session/__init__.py +29 -0
  150. siada/session/session_manager.py +66 -0
  151. siada/session/session_models.py +43 -0
  152. siada/support/__init__.py +0 -0
  153. siada/support/completer.py +204 -0
  154. siada/support/editor.py +146 -0
  155. siada/support/envprocessor.py +54 -0
  156. siada/support/repo.py +51 -0
  157. siada/support/slash_commands.py +410 -0
  158. siada/support/spinner.py +320 -0
  159. siada/tools/__init__.py +0 -0
  160. siada/tools/ast/README.md +345 -0
  161. siada/tools/ast/ast_tool.py +341 -0
  162. siada/tools/ast/models.py +11 -0
  163. siada/tools/coder/__init__.py +0 -0
  164. siada/tools/coder/ask_followup_question.py +70 -0
  165. siada/tools/coder/cmd_runner.py +132 -0
  166. siada/tools/coder/file_operator.py +284 -0
  167. siada/tools/coder/file_search/README.md +223 -0
  168. siada/tools/coder/file_search/__init__.py +10 -0
  169. siada/tools/coder/file_search/bin/rg-linux-arm64 +0 -0
  170. siada/tools/coder/file_search/bin/rg-linux-x64 +0 -0
  171. siada/tools/coder/file_search/bin/rg-macos-arm64 +0 -0
  172. siada/tools/coder/file_search/bin/rg-macos-x64 +0 -0
  173. siada/tools/coder/file_search/bin/rg.exe +0 -0
  174. siada/tools/coder/file_search/search.py +437 -0
  175. siada/tools/coder/file_search/setup_package.py +150 -0
  176. siada/tools/coder/file_search/test_search.py +142 -0
  177. siada/tools/coder/files.py +147 -0
  178. siada/tools/coder/fix_attempt_completion.py +58 -0
  179. siada/tools/coder/issue_review_completion.py +29 -0
  180. siada/tools/coder/observation/__init__.py +0 -0
  181. siada/tools/coder/observation/error.py +22 -0
  182. siada/tools/coder/observation/file_observation.py +216 -0
  183. siada/tools/coder/observation/observation.py +71 -0
  184. siada/tools/coder/repo_map/__init__.py +157 -0
  185. siada/tools/coder/repo_map/dump.py +29 -0
  186. siada/tools/coder/repo_map/io.py +226 -0
  187. siada/tools/coder/repo_map/repo_map.py +881 -0
  188. siada/tools/coder/repo_map/special.py +203 -0
  189. siada/tools/coder/repo_map/token_counter.py +154 -0
  190. siada/tools/coder/repo_map/waiting.py +221 -0
  191. siada/tools/coder/reproduce_completion.py +39 -0
  192. siada/tools/coder/run_cmd.py +60 -0
  193. siada/tools/coder/test_completion.py +25 -0
  194. siada/tools/coder/tool_docs.py +44 -0
  195. siada/tools/compression_tool.py +200 -0
  196. siada/tools/read_many_files/README.md +220 -0
  197. siada/tools/read_many_files/__init__.py +25 -0
  198. siada/tools/read_many_files/file_processor.py +486 -0
  199. siada/tools/read_many_files/filters.py +326 -0
  200. siada/tools/read_many_files/formatters.py +204 -0
  201. siada/tools/read_many_files/models.py +189 -0
  202. siada/tools/read_many_files_tool.py +233 -0
  203. siada/tools/tool_call_format/__init__.py +55 -0
  204. siada/tools/tool_call_format/file_to_language.py +231 -0
  205. siada/tools/tool_call_format/formatter_factory.py +80 -0
  206. siada/tools/tool_call_format/formatters.py +282 -0
  207. siada/tools/tool_call_format/tool_call_formatter.py +54 -0
  208. siada/tools/web/__init__.py +0 -0
  209. siada/tools/web/web_crawl.py +208 -0
  210. siada/utils.py +194 -0
  211. siada_cli-0.0.1.dist-info/LICENSE +201 -0
  212. siada_cli-0.0.1.dist-info/METADATA +457 -0
  213. siada_cli-0.0.1.dist-info/RECORD +215 -0
  214. siada_cli-0.0.1.dist-info/WHEEL +4 -0
  215. siada_cli-0.0.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,189 @@
1
+ """
2
+ ReadManyFiles tool data models and structures.
3
+ """
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import List, Dict, Optional, Union, Any
7
+
8
+
9
+ @dataclass
10
+ class ReadManyFilesParams:
11
+ """ReadManyFiles tool input parameters"""
12
+
13
+ # Required parameters
14
+ paths: List[str] # File paths or directory paths array, relative to tool config target directory
15
+ # Can directly use glob patterns
16
+ # Example: ['src/**/*.py', 'docs/*.md']
17
+
18
+ # Optional parameters
19
+ include: Optional[List[str]] = None # Additional include glob patterns
20
+ # Example: ["*.test.ts"]
21
+
22
+ exclude: Optional[List[str]] = None # Exclude glob patterns
23
+ # Example: ["*.log", "dist/**"]
24
+
25
+ recursive: bool = True # Whether to search recursively
26
+ # Mainly controlled by "**" in glob patterns
27
+
28
+ useDefaultExcludes: bool = True # Whether to apply default exclude patterns
29
+
30
+ file_filtering_options: Optional[Dict[str, bool]] = None
31
+ # File filtering options
32
+ # {
33
+ # 'respect_git_ignore': bool, # Default: True
34
+ # }
35
+
36
+
37
+ @dataclass
38
+ class ToolResult:
39
+ """Tool execution result"""
40
+
41
+ llmContent: Union[List[str], List[Any], List[Union[str, Any]]]
42
+ # Content returned to LLM
43
+ # - For text files: formatted string array
44
+ # - For images/PDF: Part object array
45
+ # - Mixed content: mixed array of strings and Part objects
46
+
47
+ returnDisplay: str
48
+ # Content returned to user interface display
49
+ # Contains detailed summary information of processing results
50
+
51
+
52
+ @dataclass
53
+ class FileProcessResult:
54
+ """Single file processing result"""
55
+
56
+ success: bool
57
+ path: str
58
+ content: Optional[Any] = None
59
+ reason: Optional[str] = None
60
+ file_type: Optional[str] = None
61
+ size: Optional[int] = None
62
+
63
+
64
+ @dataclass
65
+ class ProcessingStats:
66
+ """File processing statistics"""
67
+
68
+ total_files_found: int = 0
69
+ processed_files: int = 0
70
+ skipped_files: int = 0
71
+ text_files: int = 0
72
+ image_files: int = 0
73
+ pdf_files: int = 0
74
+ binary_files: int = 0
75
+ error_files: int = 0
76
+ total_size: int = 0
77
+ processing_time: float = 0.0
78
+
79
+
80
+ # Default exclude patterns
81
+ DEFAULT_EXCLUDES = [
82
+ # Dependency directories
83
+ '**/node_modules/**',
84
+ '**/__pycache__/**',
85
+ '**/venv/**',
86
+ '**/env/**',
87
+ '**/.env/**',
88
+
89
+ # Version control
90
+ '**/.git/**',
91
+ '**/.svn/**',
92
+ '**/.hg/**',
93
+
94
+ # IDE configuration
95
+ '**/.vscode/**',
96
+ '**/.idea/**',
97
+ '**/.eclipse/**',
98
+
99
+ # Build output
100
+ '**/dist/**',
101
+ '**/build/**',
102
+ '**/target/**',
103
+ '**/coverage/**',
104
+ '**/out/**',
105
+
106
+ # Compiled files
107
+ '**/*.pyc',
108
+ '**/*.pyo',
109
+ '**/*.class',
110
+ '**/*.jar',
111
+ '**/*.war',
112
+ '**/*.o',
113
+ '**/*.obj',
114
+
115
+ # Binary files
116
+ '**/*.bin',
117
+ '**/*.exe',
118
+ '**/*.dll',
119
+ '**/*.so',
120
+ '**/*.dylib',
121
+
122
+ # Compressed files
123
+ '**/*.zip',
124
+ '**/*.tar',
125
+ '**/*.gz',
126
+ '**/*.bz2',
127
+ '**/*.rar',
128
+ '**/*.7z',
129
+
130
+ # Office documents (unless explicitly requested)
131
+ '**/*.doc',
132
+ '**/*.docx',
133
+ '**/*.xls',
134
+ '**/*.xlsx',
135
+ '**/*.ppt',
136
+ '**/*.pptx',
137
+ '**/*.odt',
138
+ '**/*.ods',
139
+ '**/*.odp',
140
+
141
+ # System files
142
+ '**/.DS_Store',
143
+ '**/Thumbs.db',
144
+ '**/.env',
145
+ '**/.env.local',
146
+ '**/.env.*.local',
147
+
148
+ # Log files
149
+ '**/*.log',
150
+ '**/logs/**',
151
+
152
+ # Cache directories
153
+ '**/.cache/**',
154
+ '**/cache/**',
155
+ '**/.tmp/**',
156
+ '**/tmp/**',
157
+
158
+ # Package manager files
159
+ '**/package-lock.json',
160
+ '**/yarn.lock',
161
+ '**/poetry.lock',
162
+ '**/Pipfile.lock',
163
+
164
+ # Gemini history files
165
+ '**/GEMINI.md',
166
+ ]
167
+
168
+ # Supported text file extensions
169
+ TEXT_FILE_EXTENSIONS = {
170
+ '.py', '.js', '.ts', '.jsx', '.tsx', '.java', '.c', '.cpp', '.cc', '.cxx',
171
+ '.h', '.hpp', '.cs', '.php', '.rb', '.go', '.rs', '.swift', '.kt', '.scala',
172
+ '.clj', '.hs', '.ml', '.fs', '.vb', '.pl', '.sh', '.bash', '.zsh', '.fish',
173
+ '.ps1', '.bat', '.cmd', '.html', '.htm', '.xml', '.css', '.scss', '.sass',
174
+ '.less', '.json', '.yaml', '.yml', '.toml', '.ini', '.cfg', '.conf',
175
+ '.properties', '.env', '.md', '.rst', '.txt', '.log', '.sql', '.r',
176
+ '.m', '.mm', '.dart', '.lua', '.vim', '.dockerfile', '.makefile',
177
+ '.cmake', '.gradle', '.maven', '.ant', '.sbt', '.cabal', '.nix'
178
+ }
179
+
180
+ # Supported image file extensions
181
+ IMAGE_FILE_EXTENSIONS = {
182
+ '.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.svg', '.ico',
183
+ '.tiff', '.tif', '.psd', '.ai', '.eps'
184
+ }
185
+
186
+ # Supported PDF file extensions
187
+ PDF_FILE_EXTENSIONS = {
188
+ '.pdf'
189
+ }
@@ -0,0 +1,233 @@
1
+ """
2
+ ReadManyFiles tool - Batch read multiple files with intelligent filtering.
3
+
4
+ This tool provides functionality to read multiple files based on glob patterns,
5
+ with support for text files, images, and PDFs. It includes intelligent filtering
6
+ using .gitignore rules and default exclusion patterns.
7
+ """
8
+
9
+ import os
10
+ import time
11
+ import asyncio
12
+ from typing import Dict, Any, Optional
13
+
14
+ from .read_many_files.models import ReadManyFilesParams, ToolResult
15
+ from .read_many_files.file_processor import FileProcessor
16
+ from .read_many_files.filters import FileFilter
17
+ from .read_many_files.formatters import ResultFormatter
18
+
19
+
20
+ class ReadManyFilesTool:
21
+ """ReadManyFiles tool implementation"""
22
+
23
+ def __init__(self, target_dir: Optional[str] = None):
24
+ """
25
+ Initialize ReadManyFiles tool
26
+
27
+ Args:
28
+ target_dir: Target directory for file operations (defaults to current working directory)
29
+ """
30
+ self.target_dir = target_dir or os.getcwd()
31
+ self.file_processor = FileProcessor(self.target_dir)
32
+ self.file_filter = FileFilter(self.target_dir)
33
+ self.formatter = ResultFormatter(self.target_dir)
34
+
35
+ def validate_params(self, params: ReadManyFilesParams) -> Optional[str]:
36
+ """
37
+ Validate input parameters
38
+
39
+ Args:
40
+ params: ReadManyFilesParams object
41
+
42
+ Returns:
43
+ Error message if validation fails, None if valid
44
+ """
45
+ if not params.paths:
46
+ return "Parameter 'paths' is required and cannot be empty"
47
+
48
+ if not isinstance(params.paths, list):
49
+ return "Parameter 'paths' must be a list"
50
+
51
+ if any(not isinstance(path, str) for path in params.paths):
52
+ return "All items in 'paths' must be strings"
53
+
54
+ if params.include and not isinstance(params.include, list):
55
+ return "Parameter 'include' must be a list if provided"
56
+
57
+ if params.exclude and not isinstance(params.exclude, list):
58
+ return "Parameter 'exclude' must be a list if provided"
59
+
60
+ return None
61
+
62
+ def merge_filtering_options(self, params: ReadManyFilesParams) -> Dict[str, bool]:
63
+ """
64
+ Merge filtering options with defaults
65
+
66
+ Args:
67
+ params: ReadManyFilesParams object
68
+
69
+ Returns:
70
+ Dictionary of filtering options
71
+ """
72
+ default_options = {
73
+ 'respect_git_ignore': True
74
+ }
75
+
76
+ if params.file_filtering_options:
77
+ default_options.update(params.file_filtering_options)
78
+
79
+ return default_options
80
+
81
+ async def execute(self, params: ReadManyFilesParams, signal=None) -> ToolResult:
82
+ """
83
+ Execute the ReadManyFiles tool
84
+
85
+ Args:
86
+ params: ReadManyFilesParams object with tool parameters
87
+ signal: Cancellation signal (optional)
88
+
89
+ Returns:
90
+ ToolResult object with processing results
91
+ """
92
+ start_time = time.time()
93
+
94
+ try:
95
+ # 1. Parameter validation
96
+ validation_error = self.validate_params(params)
97
+ if validation_error:
98
+ return ToolResult(**self.formatter.create_error_result(validation_error))
99
+
100
+ # 2. Configuration initialization
101
+ file_filtering_options = self.merge_filtering_options(params)
102
+
103
+ # 3. Build search patterns
104
+ search_patterns = params.paths + (params.include or [])
105
+ if not search_patterns:
106
+ return ToolResult(**self.formatter.create_info_result("No search patterns provided"))
107
+
108
+ exclusion_patterns = self.file_filter.build_exclusion_patterns(params)
109
+
110
+ # 4. Execute file search
111
+ all_files = await self.file_processor.search_files_with_glob(
112
+ search_patterns, exclusion_patterns, signal
113
+ )
114
+
115
+ if not all_files:
116
+ return ToolResult(**self.formatter.create_info_result(
117
+ "No files found matching the specified patterns"
118
+ ))
119
+
120
+ # 5. Apply ignore filters
121
+ filtered_files, filter_counts = self.file_filter.apply_gitignore_filters(
122
+ all_files, file_filtering_options
123
+ )
124
+
125
+ # 6. Security validation
126
+ validated_files = self.file_filter.validate_workspace_security(filtered_files)
127
+
128
+ if not validated_files:
129
+ return ToolResult(**self.formatter.create_info_result(
130
+ "No files remain after filtering and security validation"
131
+ ))
132
+
133
+ # 7. Read file contents
134
+ content_parts, processed_files, skipped_files = await self.file_processor.process_files(
135
+ validated_files, params.paths
136
+ )
137
+
138
+ # 8. Add filter statistics to skipped files
139
+ filter_skip_info = self.formatter.build_filter_skip_info(filter_counts)
140
+ skipped_files.extend(filter_skip_info)
141
+
142
+ # 9. Update processing time
143
+ end_time = time.time()
144
+ self.file_processor.stats.processing_time = end_time - start_time
145
+
146
+ # 10. Build and return result
147
+ result_dict = self.formatter.build_result(
148
+ content_parts, processed_files, skipped_files, self.file_processor.stats
149
+ )
150
+
151
+ return ToolResult(**result_dict)
152
+
153
+ except Exception as error:
154
+ return ToolResult(**self.formatter.create_error_result(
155
+ f"Unexpected error during file processing: {str(error)}"
156
+ ))
157
+
158
+
159
+ # Main function for tool execution
160
+ async def read_many_files(params: ReadManyFilesParams,
161
+ target_dir: Optional[str] = None,
162
+ signal=None) -> ToolResult:
163
+ """
164
+ Read multiple files based on glob patterns
165
+
166
+ Args:
167
+ params: ReadManyFilesParams object with tool parameters
168
+ target_dir: Target directory for file operations (optional)
169
+ signal: Cancellation signal (optional)
170
+
171
+ Returns:
172
+ ToolResult object with processing results
173
+ """
174
+ tool = ReadManyFilesTool(target_dir)
175
+ return await tool.execute(params, signal)
176
+
177
+
178
+ # Convenience function for direct usage
179
+ async def read_files_by_patterns(paths: list,
180
+ include: Optional[list] = None,
181
+ exclude: Optional[list] = None,
182
+ target_dir: Optional[str] = None,
183
+ use_default_excludes: bool = True,
184
+ respect_git_ignore: bool = True) -> ToolResult:
185
+ """
186
+ Convenience function to read files by patterns
187
+
188
+ Args:
189
+ paths: List of file paths or glob patterns
190
+ include: Additional include patterns (optional)
191
+ exclude: Exclude patterns (optional)
192
+ target_dir: Target directory (optional)
193
+ use_default_excludes: Whether to use default exclusion patterns
194
+ respect_git_ignore: Whether to respect .gitignore rules
195
+
196
+ Returns:
197
+ ToolResult object with processing results
198
+ """
199
+ params = ReadManyFilesParams(
200
+ paths=paths,
201
+ include=include,
202
+ exclude=exclude,
203
+ useDefaultExcludes=use_default_excludes,
204
+ file_filtering_options={
205
+ 'respect_git_ignore': respect_git_ignore
206
+ }
207
+ )
208
+
209
+ return await read_many_files(params, target_dir)
210
+
211
+
212
+ if __name__ == "__main__":
213
+ # Example usage
214
+ import asyncio
215
+
216
+ async def main():
217
+ # Example: Read all Python files in current directory
218
+ result = await read_files_by_patterns(
219
+ paths=["**/*.py"],
220
+ exclude=["**/test_*.py", "**/__pycache__/**"]
221
+ )
222
+
223
+ print("LLM Content:")
224
+ for content in result.llmContent:
225
+ if isinstance(content, str):
226
+ print(content[:200] + "..." if len(content) > 200 else content)
227
+ else:
228
+ print(f"[Binary content: {content.get('type', 'unknown')}]")
229
+
230
+ print("\nDisplay Message:")
231
+ print(result.returnDisplay)
232
+
233
+ asyncio.run(main())
@@ -0,0 +1,55 @@
1
+ """
2
+ Tool Call Formatter 模块
3
+
4
+ 提供工具调用参数格式化功能,包括:
5
+ - ToolCallFormatter 抽象基类接口
6
+ - ToolCallFormatterFactory 工厂类
7
+ - 各种具体的 formatter 实现
8
+ - ParameterInterceptor 参数拦截装饰器
9
+ """
10
+
11
+ from .tool_call_formatter import ToolCallFormatter
12
+ from .formatter_factory import ToolCallFormatterFactory
13
+ from .formatters import (
14
+ DefaultFormatter,
15
+ ListCodeDefinitionNamesFormatter,
16
+ SearchFormatter,
17
+ CommandFormatter,
18
+ FixAttemptCompletionFormatter,
19
+ ReproduceCompletionFormatter,
20
+ FileEditFormatter,
21
+ AskFollowupQuestionFormatter,
22
+ )
23
+
24
+ # 自动注册所有formatter
25
+ def _register_all_formatters():
26
+ """自动注册所有可用的formatter"""
27
+ formatters = [
28
+ DefaultFormatter,
29
+ SearchFormatter,
30
+ CommandFormatter,
31
+ FixAttemptCompletionFormatter,
32
+ ReproduceCompletionFormatter,
33
+ FileEditFormatter,
34
+ AskFollowupQuestionFormatter,
35
+ ListCodeDefinitionNamesFormatter,
36
+ ]
37
+
38
+ for formatter_class in formatters:
39
+ ToolCallFormatterFactory.register_formatter(formatter_class)
40
+
41
+ # 在模块导入时自动注册
42
+ _register_all_formatters()
43
+
44
+ # 导出的公共接口
45
+ __all__ = [
46
+ 'ToolCallFormatter',
47
+ 'ToolCallFormatterFactory',
48
+ 'DefaultFormatter',
49
+ 'FileReadFormatter',
50
+ 'SearchFormatter',
51
+ 'CommandFormatter',
52
+ 'ParameterInterceptor',
53
+ 'parameter_interceptor',
54
+ 'simple_interceptor',
55
+ ]