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.
- agent_config.yaml +34 -0
- siada/__init__.py +13 -0
- siada/agent_hub/__init__.py +10 -0
- siada/agent_hub/coder/bug_fix_agent.py +398 -0
- siada/agent_hub/coder/code_gen_agent.py +235 -0
- siada/agent_hub/coder/fe_gen_agent.py +37 -0
- siada/agent_hub/coder/issue_review_agent.py +68 -0
- siada/agent_hub/coder/prompt/__init__.py +0 -0
- siada/agent_hub/coder/prompt/base/__init__.py +0 -0
- siada/agent_hub/coder/prompt/base/capabilities.py +18 -0
- siada/agent_hub/coder/prompt/base/non_interactive.py +14 -0
- siada/agent_hub/coder/prompt/base/prompt_builder.py +33 -0
- siada/agent_hub/coder/prompt/base/rules.py +40 -0
- siada/agent_hub/coder/prompt/base/tool_use.py +14 -0
- siada/agent_hub/coder/prompt/bug_prompt/bug_fix_prompt.py +51 -0
- siada/agent_hub/coder/prompt/bug_prompt/rules.py +53 -0
- siada/agent_hub/coder/prompt/code_gen_prompt.py +45 -0
- siada/agent_hub/coder/prompt/fe_gen_prompt.py +45 -0
- siada/agent_hub/coder/prompt/issue_review_prompt.py +121 -0
- siada/agent_hub/coder/tracing/__init__.py +22 -0
- siada/agent_hub/coder/tracing/logger_tracing_processor.py +458 -0
- siada/agent_hub/hooks/__init__.py +0 -0
- siada/agent_hub/hooks/io_hooks.py +30 -0
- siada/agent_hub/siada_agent.py +214 -0
- siada/config/__init__.py +0 -0
- siada/config/config_loader.py +67 -0
- siada/entrypoint/__init__.py +3 -0
- siada/entrypoint/args_parser/__init__.py +0 -0
- siada/entrypoint/args_parser/args.py +195 -0
- siada/entrypoint/interaction/__init__.py +0 -0
- siada/entrypoint/interaction/base_turn.py +107 -0
- siada/entrypoint/interaction/config.py +30 -0
- siada/entrypoint/interaction/controller.py +122 -0
- siada/entrypoint/interaction/nointeractive_controller.py +27 -0
- siada/entrypoint/interaction/turn/interface.py +116 -0
- siada/entrypoint/interaction/turn/models.py +34 -0
- siada/entrypoint/interaction/turn/run_turn.py +641 -0
- siada/entrypoint/interaction/turn_factory.py +35 -0
- siada/entrypoint/interaction/turn_models.py +28 -0
- siada/entrypoint/siadahub.py +413 -0
- siada/foundation/__init__.py +0 -0
- siada/foundation/code_agent_context.py +48 -0
- siada/foundation/config.py +59 -0
- siada/foundation/constants.py +2 -0
- siada/foundation/context.py +76 -0
- siada/foundation/logging.py +341 -0
- siada/foundation/tools/__init__.py +0 -0
- siada/foundation/tools/get_git_diff.py +105 -0
- siada/io/__init__.py +0 -0
- siada/io/banner.py +148 -0
- siada/io/color_settings.py +207 -0
- siada/io/color_utils.py +16 -0
- siada/io/components/__init__.py +0 -0
- siada/io/components/mdstream.py +204 -0
- siada/io/console_printer.py +68 -0
- siada/io/io.py +661 -0
- siada/io/key_bindings.py +129 -0
- siada/io/notification_command.py +40 -0
- siada/io/test_banner.py +64 -0
- siada/models/__init__.py +0 -0
- siada/models/agent.py +47 -0
- siada/models/coder/__init__.py +0 -0
- siada/models/converter.py +27 -0
- siada/models/model_base_config.py +121 -0
- siada/models/model_run_config.py +153 -0
- siada/provider/__init__.py +0 -0
- siada/provider/client_factory.py +112 -0
- siada/provider/llm_client.py +11 -0
- siada/provider/openrouter/__init__.py +0 -0
- siada/provider/openrouter/coverter.py +17 -0
- siada/provider/openrouter/openroute_provider.py +33 -0
- siada/provider/provider_factory.py +53 -0
- siada/queries/tree-sitter-language-pack/README.md +7 -0
- siada/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
- siada/queries/tree-sitter-language-pack/c-tags.scm +9 -0
- siada/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
- siada/queries/tree-sitter-language-pack/commonlisp-tags.scm +122 -0
- siada/queries/tree-sitter-language-pack/cpp-tags.scm +15 -0
- siada/queries/tree-sitter-language-pack/csharp-tags.scm +26 -0
- siada/queries/tree-sitter-language-pack/d-tags.scm +26 -0
- siada/queries/tree-sitter-language-pack/dart-tags.scm +92 -0
- siada/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
- siada/queries/tree-sitter-language-pack/elixir-tags.scm +54 -0
- siada/queries/tree-sitter-language-pack/elm-tags.scm +19 -0
- siada/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
- siada/queries/tree-sitter-language-pack/go-tags.scm +42 -0
- siada/queries/tree-sitter-language-pack/java-tags.scm +20 -0
- siada/queries/tree-sitter-language-pack/javascript-tags.scm +88 -0
- siada/queries/tree-sitter-language-pack/lua-tags.scm +34 -0
- siada/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
- siada/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +98 -0
- siada/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
- siada/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
- siada/queries/tree-sitter-language-pack/python-tags.scm +14 -0
- siada/queries/tree-sitter-language-pack/r-tags.scm +21 -0
- siada/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
- siada/queries/tree-sitter-language-pack/ruby-tags.scm +64 -0
- siada/queries/tree-sitter-language-pack/rust-tags.scm +60 -0
- siada/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
- siada/queries/tree-sitter-language-pack/swift-tags.scm +51 -0
- siada/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
- siada/queries/tree-sitter-languages/README.md +23 -0
- siada/queries/tree-sitter-languages/c-tags.scm +9 -0
- siada/queries/tree-sitter-languages/c_sharp-tags.scm +46 -0
- siada/queries/tree-sitter-languages/cpp-tags.scm +15 -0
- siada/queries/tree-sitter-languages/dart-tags.scm +91 -0
- siada/queries/tree-sitter-languages/elisp-tags.scm +8 -0
- siada/queries/tree-sitter-languages/elixir-tags.scm +54 -0
- siada/queries/tree-sitter-languages/elm-tags.scm +19 -0
- siada/queries/tree-sitter-languages/go-tags.scm +30 -0
- siada/queries/tree-sitter-languages/hcl-tags.scm +77 -0
- siada/queries/tree-sitter-languages/java-tags.scm +20 -0
- siada/queries/tree-sitter-languages/javascript-tags.scm +88 -0
- siada/queries/tree-sitter-languages/kotlin-tags.scm +27 -0
- siada/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
- siada/queries/tree-sitter-languages/ocaml_interface-tags.scm +98 -0
- siada/queries/tree-sitter-languages/php-tags.scm +26 -0
- siada/queries/tree-sitter-languages/python-tags.scm +12 -0
- siada/queries/tree-sitter-languages/ql-tags.scm +26 -0
- siada/queries/tree-sitter-languages/ruby-tags.scm +64 -0
- siada/queries/tree-sitter-languages/rust-tags.scm +60 -0
- siada/queries/tree-sitter-languages/scala-tags.scm +65 -0
- siada/queries/tree-sitter-languages/typescript-tags.scm +41 -0
- siada/services/__init__.py +30 -0
- siada/services/at_file_recommendation_design_document.md +1213 -0
- siada/services/code_context_manager.py +136 -0
- siada/services/enhanced_fix_result_check.py +546 -0
- siada/services/execution_trace_collector.py +207 -0
- siada/services/file_recommendation/__init__.py +136 -0
- siada/services/file_recommendation/core/__init__.py +17 -0
- siada/services/file_recommendation/core/completion_engine.py +351 -0
- siada/services/file_recommendation/core/config.py +62 -0
- siada/services/file_recommendation/core/file_discovery.py +353 -0
- siada/services/file_recommendation/core/suggestion.py +110 -0
- siada/services/file_recommendation/utils/__init__.py +22 -0
- siada/services/file_recommendation/utils/path_utils.py +138 -0
- siada/services/file_recommendation/utils/text_utils.py +253 -0
- siada/services/fix_result_check.py +377 -0
- siada/services/handle_at_command/README.md +247 -0
- siada/services/handle_at_command/__init__.py +115 -0
- siada/services/handle_at_command/exceptions.py +46 -0
- siada/services/handle_at_command/models.py +92 -0
- siada/services/handle_at_command/parser.py +189 -0
- siada/services/handle_at_command/processor.py +321 -0
- siada/services/handle_at_command/resolver.py +318 -0
- siada/services/handle_at_command/utils.py +345 -0
- siada/services/model_info_service.py +103 -0
- siada/services/siada_runner.py +170 -0
- siada/session/__init__.py +29 -0
- siada/session/session_manager.py +66 -0
- siada/session/session_models.py +43 -0
- siada/support/__init__.py +0 -0
- siada/support/completer.py +204 -0
- siada/support/editor.py +146 -0
- siada/support/envprocessor.py +54 -0
- siada/support/repo.py +51 -0
- siada/support/slash_commands.py +410 -0
- siada/support/spinner.py +320 -0
- siada/tools/__init__.py +0 -0
- siada/tools/ast/README.md +345 -0
- siada/tools/ast/ast_tool.py +341 -0
- siada/tools/ast/models.py +11 -0
- siada/tools/coder/__init__.py +0 -0
- siada/tools/coder/ask_followup_question.py +70 -0
- siada/tools/coder/cmd_runner.py +132 -0
- siada/tools/coder/file_operator.py +284 -0
- siada/tools/coder/file_search/README.md +223 -0
- siada/tools/coder/file_search/__init__.py +10 -0
- siada/tools/coder/file_search/bin/rg-linux-arm64 +0 -0
- siada/tools/coder/file_search/bin/rg-linux-x64 +0 -0
- siada/tools/coder/file_search/bin/rg-macos-arm64 +0 -0
- siada/tools/coder/file_search/bin/rg-macos-x64 +0 -0
- siada/tools/coder/file_search/bin/rg.exe +0 -0
- siada/tools/coder/file_search/search.py +437 -0
- siada/tools/coder/file_search/setup_package.py +150 -0
- siada/tools/coder/file_search/test_search.py +142 -0
- siada/tools/coder/files.py +147 -0
- siada/tools/coder/fix_attempt_completion.py +58 -0
- siada/tools/coder/issue_review_completion.py +29 -0
- siada/tools/coder/observation/__init__.py +0 -0
- siada/tools/coder/observation/error.py +22 -0
- siada/tools/coder/observation/file_observation.py +216 -0
- siada/tools/coder/observation/observation.py +71 -0
- siada/tools/coder/repo_map/__init__.py +157 -0
- siada/tools/coder/repo_map/dump.py +29 -0
- siada/tools/coder/repo_map/io.py +226 -0
- siada/tools/coder/repo_map/repo_map.py +881 -0
- siada/tools/coder/repo_map/special.py +203 -0
- siada/tools/coder/repo_map/token_counter.py +154 -0
- siada/tools/coder/repo_map/waiting.py +221 -0
- siada/tools/coder/reproduce_completion.py +39 -0
- siada/tools/coder/run_cmd.py +60 -0
- siada/tools/coder/test_completion.py +25 -0
- siada/tools/coder/tool_docs.py +44 -0
- siada/tools/compression_tool.py +200 -0
- siada/tools/read_many_files/README.md +220 -0
- siada/tools/read_many_files/__init__.py +25 -0
- siada/tools/read_many_files/file_processor.py +486 -0
- siada/tools/read_many_files/filters.py +326 -0
- siada/tools/read_many_files/formatters.py +204 -0
- siada/tools/read_many_files/models.py +189 -0
- siada/tools/read_many_files_tool.py +233 -0
- siada/tools/tool_call_format/__init__.py +55 -0
- siada/tools/tool_call_format/file_to_language.py +231 -0
- siada/tools/tool_call_format/formatter_factory.py +80 -0
- siada/tools/tool_call_format/formatters.py +282 -0
- siada/tools/tool_call_format/tool_call_formatter.py +54 -0
- siada/tools/web/__init__.py +0 -0
- siada/tools/web/web_crawl.py +208 -0
- siada/utils.py +194 -0
- siada_cli-0.0.1.dist-info/LICENSE +201 -0
- siada_cli-0.0.1.dist-info/METADATA +457 -0
- siada_cli-0.0.1.dist-info/RECORD +215 -0
- siada_cli-0.0.1.dist-info/WHEEL +4 -0
- siada_cli-0.0.1.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def get_language_from_file_extension(filename: str) -> str:
|
|
6
|
+
"""
|
|
7
|
+
Get the language identifier for markdown code fences based on file extension.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
filename: The name of the file (can include path)
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
Language identifier string for markdown code fences
|
|
14
|
+
"""
|
|
15
|
+
if not filename:
|
|
16
|
+
return ""
|
|
17
|
+
|
|
18
|
+
# Extract the file extension (convert to lowercase for case-insensitive matching)
|
|
19
|
+
_, ext = os.path.splitext(filename.lower())
|
|
20
|
+
|
|
21
|
+
# Remove the leading dot
|
|
22
|
+
ext = ext.lstrip('.')
|
|
23
|
+
|
|
24
|
+
# Mapping of file extensions to language identifiers
|
|
25
|
+
extension_to_language = {
|
|
26
|
+
# Python
|
|
27
|
+
'py': 'python',
|
|
28
|
+
'pyw': 'python',
|
|
29
|
+
'pyi': 'python',
|
|
30
|
+
|
|
31
|
+
# JavaScript/TypeScript
|
|
32
|
+
'js': 'javascript',
|
|
33
|
+
'mjs': 'javascript',
|
|
34
|
+
'jsx': 'jsx',
|
|
35
|
+
'ts': 'typescript',
|
|
36
|
+
'tsx': 'tsx',
|
|
37
|
+
|
|
38
|
+
# Java/JVM languages
|
|
39
|
+
'java': 'java',
|
|
40
|
+
'kt': 'kotlin',
|
|
41
|
+
'kts': 'kotlin',
|
|
42
|
+
'scala': 'scala',
|
|
43
|
+
'sc': 'scala',
|
|
44
|
+
'groovy': 'groovy',
|
|
45
|
+
'gradle': 'gradle',
|
|
46
|
+
|
|
47
|
+
# C/C++
|
|
48
|
+
'c': 'c',
|
|
49
|
+
'h': 'c',
|
|
50
|
+
'cpp': 'cpp',
|
|
51
|
+
'cxx': 'cpp',
|
|
52
|
+
'cc': 'cpp',
|
|
53
|
+
'c++': 'cpp',
|
|
54
|
+
'hpp': 'cpp',
|
|
55
|
+
'hxx': 'cpp',
|
|
56
|
+
'hh': 'cpp',
|
|
57
|
+
|
|
58
|
+
# C#
|
|
59
|
+
'cs': 'csharp',
|
|
60
|
+
|
|
61
|
+
# Go
|
|
62
|
+
'go': 'go',
|
|
63
|
+
|
|
64
|
+
# Rust
|
|
65
|
+
'rs': 'rust',
|
|
66
|
+
|
|
67
|
+
# PHP
|
|
68
|
+
'php': 'php',
|
|
69
|
+
'php3': 'php',
|
|
70
|
+
'php4': 'php',
|
|
71
|
+
'php5': 'php',
|
|
72
|
+
'phtml': 'php',
|
|
73
|
+
|
|
74
|
+
# Ruby
|
|
75
|
+
'rb': 'ruby',
|
|
76
|
+
'rbw': 'ruby',
|
|
77
|
+
'rake': 'ruby',
|
|
78
|
+
'gemspec': 'ruby',
|
|
79
|
+
|
|
80
|
+
# Swift
|
|
81
|
+
'swift': 'swift',
|
|
82
|
+
|
|
83
|
+
# Objective-C
|
|
84
|
+
'm': 'objective-c',
|
|
85
|
+
'mm': 'objective-c',
|
|
86
|
+
|
|
87
|
+
# Dart
|
|
88
|
+
'dart': 'dart',
|
|
89
|
+
|
|
90
|
+
# R
|
|
91
|
+
'r': 'r',
|
|
92
|
+
|
|
93
|
+
# Shell scripting
|
|
94
|
+
'sh': 'bash',
|
|
95
|
+
'bash': 'bash',
|
|
96
|
+
'zsh': 'zsh',
|
|
97
|
+
'fish': 'fish',
|
|
98
|
+
'csh': 'csh',
|
|
99
|
+
'tcsh': 'tcsh',
|
|
100
|
+
|
|
101
|
+
# PowerShell
|
|
102
|
+
'ps1': 'powershell',
|
|
103
|
+
'psm1': 'powershell',
|
|
104
|
+
'psd1': 'powershell',
|
|
105
|
+
|
|
106
|
+
# SQL
|
|
107
|
+
'sql': 'sql',
|
|
108
|
+
'mysql': 'sql',
|
|
109
|
+
'pgsql': 'sql',
|
|
110
|
+
'plsql': 'sql',
|
|
111
|
+
|
|
112
|
+
# Web technologies
|
|
113
|
+
'html': 'html',
|
|
114
|
+
'htm': 'html',
|
|
115
|
+
'xhtml': 'html',
|
|
116
|
+
'css': 'css',
|
|
117
|
+
'scss': 'scss',
|
|
118
|
+
'sass': 'sass',
|
|
119
|
+
'less': 'less',
|
|
120
|
+
'styl': 'stylus',
|
|
121
|
+
|
|
122
|
+
# Markup and data formats
|
|
123
|
+
'xml': 'xml',
|
|
124
|
+
'xsl': 'xml',
|
|
125
|
+
'xslt': 'xml',
|
|
126
|
+
'svg': 'xml',
|
|
127
|
+
'json': 'json',
|
|
128
|
+
'yaml': 'yaml',
|
|
129
|
+
'yml': 'yaml',
|
|
130
|
+
'toml': 'toml',
|
|
131
|
+
'ini': 'ini',
|
|
132
|
+
'cfg': 'ini',
|
|
133
|
+
'conf': 'ini',
|
|
134
|
+
'properties': 'properties',
|
|
135
|
+
|
|
136
|
+
# Documentation
|
|
137
|
+
'md': 'markdown',
|
|
138
|
+
'markdown': 'markdown',
|
|
139
|
+
'mdown': 'markdown',
|
|
140
|
+
'mkd': 'markdown',
|
|
141
|
+
'rst': 'rst',
|
|
142
|
+
'tex': 'latex',
|
|
143
|
+
'latex': 'latex',
|
|
144
|
+
|
|
145
|
+
# Docker
|
|
146
|
+
'dockerfile': 'dockerfile',
|
|
147
|
+
|
|
148
|
+
# Other scripting languages
|
|
149
|
+
'lua': 'lua',
|
|
150
|
+
'pl': 'perl',
|
|
151
|
+
'pm': 'perl',
|
|
152
|
+
'py': 'python',
|
|
153
|
+
'vim': 'vim',
|
|
154
|
+
'vimrc': 'vim',
|
|
155
|
+
|
|
156
|
+
# Functional languages
|
|
157
|
+
'hs': 'haskell',
|
|
158
|
+
'lhs': 'haskell',
|
|
159
|
+
'elm': 'elm',
|
|
160
|
+
'ml': 'ocaml',
|
|
161
|
+
'mli': 'ocaml',
|
|
162
|
+
'fs': 'fsharp',
|
|
163
|
+
'fsi': 'fsharp',
|
|
164
|
+
'fsx': 'fsharp',
|
|
165
|
+
'clj': 'clojure',
|
|
166
|
+
'cljs': 'clojure',
|
|
167
|
+
'cljc': 'clojure',
|
|
168
|
+
'edn': 'clojure',
|
|
169
|
+
|
|
170
|
+
# Assembly
|
|
171
|
+
'asm': 'assembly',
|
|
172
|
+
's': 'assembly',
|
|
173
|
+
|
|
174
|
+
# Other formats
|
|
175
|
+
'cmake': 'cmake',
|
|
176
|
+
'make': 'makefile',
|
|
177
|
+
'makefile': 'makefile',
|
|
178
|
+
'dockerfile': 'dockerfile',
|
|
179
|
+
'gitignore': 'gitignore',
|
|
180
|
+
'gitconfig': 'gitconfig',
|
|
181
|
+
'editorconfig': 'editorconfig',
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
# Return the mapped language or the extension itself if not found
|
|
185
|
+
return extension_to_language.get(ext, ext if ext else "text")
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def get_language_from_filename(filename: str) -> str:
|
|
189
|
+
"""
|
|
190
|
+
Alias for get_language_from_file_extension for backward compatibility.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
filename: The name of the file (can include path)
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
Language identifier string for markdown code fences
|
|
197
|
+
"""
|
|
198
|
+
return get_language_from_file_extension(filename)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def is_supported_language(filename: str) -> bool:
|
|
202
|
+
"""
|
|
203
|
+
Check if the file extension is supported (has a known language mapping).
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
filename: The name of the file (can include path)
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
True if the language is explicitly supported, False otherwise
|
|
210
|
+
"""
|
|
211
|
+
if not filename:
|
|
212
|
+
return False
|
|
213
|
+
|
|
214
|
+
_, ext = os.path.splitext(filename.lower())
|
|
215
|
+
ext = ext.lstrip('.')
|
|
216
|
+
|
|
217
|
+
supported_extensions = {
|
|
218
|
+
'py', 'pyw', 'pyi', 'js', 'mjs', 'jsx', 'ts', 'tsx', 'java', 'kt', 'kts',
|
|
219
|
+
'scala', 'sc', 'groovy', 'gradle', 'c', 'h', 'cpp', 'cxx', 'cc', 'c++',
|
|
220
|
+
'hpp', 'hxx', 'hh', 'cs', 'go', 'rs', 'php', 'php3', 'php4', 'php5',
|
|
221
|
+
'phtml', 'rb', 'rbw', 'rake', 'gemspec', 'swift', 'm', 'mm', 'dart', 'r',
|
|
222
|
+
'sh', 'bash', 'zsh', 'fish', 'csh', 'tcsh', 'ps1', 'psm1', 'psd1', 'sql',
|
|
223
|
+
'mysql', 'pgsql', 'plsql', 'html', 'htm', 'xhtml', 'css', 'scss', 'sass',
|
|
224
|
+
'less', 'styl', 'xml', 'xsl', 'xslt', 'svg', 'json', 'yaml', 'yml', 'toml',
|
|
225
|
+
'ini', 'cfg', 'conf', 'properties', 'md', 'markdown', 'mdown', 'mkd', 'rst',
|
|
226
|
+
'tex', 'latex', 'dockerfile', 'lua', 'pl', 'pm', 'vim', 'vimrc', 'hs', 'lhs',
|
|
227
|
+
'elm', 'ml', 'mli', 'fs', 'fsi', 'fsx', 'clj', 'cljs', 'cljc', 'edn', 'asm',
|
|
228
|
+
's', 'cmake', 'make', 'makefile', 'gitignore', 'gitconfig', 'editorconfig'
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return ext in supported_extensions
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from typing import Dict, Optional, Type
|
|
2
|
+
|
|
3
|
+
from siada.tools.tool_call_format.formatters import DefaultFormatter
|
|
4
|
+
from .tool_call_formatter import ToolCallFormatter
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ToolCallFormatterFactory:
|
|
8
|
+
"""
|
|
9
|
+
Tool call formatter 工厂类
|
|
10
|
+
根据函数名创建相应的formatter实例
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
_formatters: Dict[str, Type[ToolCallFormatter]] = {}
|
|
14
|
+
_instances: Dict[str, ToolCallFormatter] = {}
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def register_formatter(cls, formatter_class: Type[ToolCallFormatter]) -> None:
|
|
18
|
+
"""
|
|
19
|
+
注册一个formatter类
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
formatter_class: Formatter类
|
|
23
|
+
"""
|
|
24
|
+
instance = formatter_class()
|
|
25
|
+
cls._formatters[instance.supported_function] = formatter_class
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def get_formatter(cls, function_name: str) -> Optional[ToolCallFormatter]:
|
|
29
|
+
"""
|
|
30
|
+
根据函数名获取相应的formatter实例
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
function_name: 函数名称
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
对应的formatter实例,如果不存在则返回None
|
|
37
|
+
"""
|
|
38
|
+
if function_name not in cls._formatters:
|
|
39
|
+
return DefaultFormatter()
|
|
40
|
+
|
|
41
|
+
if function_name not in cls._instances:
|
|
42
|
+
formatter_class = cls._formatters[function_name]
|
|
43
|
+
cls._instances[function_name] = formatter_class()
|
|
44
|
+
|
|
45
|
+
return cls._instances[function_name]
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def create_formatter(cls, function_name: str) -> Optional[ToolCallFormatter]:
|
|
49
|
+
"""
|
|
50
|
+
创建formatter实例(每次都创建新实例)
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
function_name: 函数名称
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
新的formatter实例,如果不存在则返回None
|
|
57
|
+
"""
|
|
58
|
+
if function_name not in cls._formatters:
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
formatter_class = cls._formatters[function_name]
|
|
62
|
+
return formatter_class()
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def list_supported_functions(cls) -> list[str]:
|
|
66
|
+
"""
|
|
67
|
+
列出所有支持的函数名
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
支持的函数名列表
|
|
71
|
+
"""
|
|
72
|
+
return list(cls._formatters.keys())
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def clear_registry(cls) -> None:
|
|
76
|
+
"""
|
|
77
|
+
清空注册的formatter(主要用于测试)
|
|
78
|
+
"""
|
|
79
|
+
cls._formatters.clear()
|
|
80
|
+
cls._instances.clear()
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from typing import Tuple
|
|
4
|
+
from siada.tools.coder.files import resolve_path
|
|
5
|
+
from siada.tools.tool_call_format.tool_call_formatter import ToolCallFormatter
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
from partial_json_parser import loads, MalformedJSON, ensure_json
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DefaultFormatter(ToolCallFormatter):
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def format_input(self, call_id: str, function_name: str, arguments: str) -> Tuple[str, bool]:
|
|
15
|
+
return arguments, True
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def supported_function(self) -> str:
|
|
19
|
+
return "default"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class FileEditFormatter(ToolCallFormatter):
|
|
23
|
+
"""
|
|
24
|
+
File operation formatter
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def format_input(
|
|
28
|
+
self, call_id: str, function_name: str, arguments: str
|
|
29
|
+
) -> Tuple[str, str, bool]:
|
|
30
|
+
|
|
31
|
+
# Valid command enumeration
|
|
32
|
+
VALID_COMMANDS = {"view", "create", "str_replace", "insert", "undo_edit"}
|
|
33
|
+
complete = False
|
|
34
|
+
content = ""
|
|
35
|
+
try:
|
|
36
|
+
# Use partial JSON parser to handle incomplete arguments
|
|
37
|
+
args = loads(arguments)
|
|
38
|
+
if arguments == ensure_json(arguments):
|
|
39
|
+
complete = True
|
|
40
|
+
|
|
41
|
+
# Safely extract values, handling potential None/missing keys
|
|
42
|
+
path = args.get("path", None) if args else ""
|
|
43
|
+
raw_command = args.get("command", None) if args else ""
|
|
44
|
+
file_text = args.get("file_text", None) if args else ""
|
|
45
|
+
old_str = args.get("old_str", None) if args else ""
|
|
46
|
+
new_str = args.get("new_str", None) if args else ""
|
|
47
|
+
view_range = args.get("view_range", None) if args else None
|
|
48
|
+
insert_line = args.get("insert_line", None) if args else None
|
|
49
|
+
|
|
50
|
+
# Validate command - only return valid commands, otherwise empty string
|
|
51
|
+
command = raw_command if raw_command in VALID_COMMANDS else ""
|
|
52
|
+
|
|
53
|
+
# If command is not valid, return empty string regardless of other parameters
|
|
54
|
+
if not command:
|
|
55
|
+
return "", False
|
|
56
|
+
|
|
57
|
+
# if path is a valid path, get the fence
|
|
58
|
+
fence = ""
|
|
59
|
+
if path:
|
|
60
|
+
from .file_to_language import get_language_from_file_extension
|
|
61
|
+
fence = get_language_from_file_extension(path)
|
|
62
|
+
|
|
63
|
+
if command == "view":
|
|
64
|
+
if complete:
|
|
65
|
+
if path:
|
|
66
|
+
# Safely check if path has file extension
|
|
67
|
+
try:
|
|
68
|
+
is_file = bool(os.path.splitext(str(path))[1]) # Has extension = likely a file
|
|
69
|
+
except Exception:
|
|
70
|
+
is_file = False # Default to directory if path is invalid
|
|
71
|
+
if is_file:
|
|
72
|
+
content = f"I will read the file `{path}"
|
|
73
|
+
if view_range and len(view_range) == 2:
|
|
74
|
+
content += f"` from line {view_range[0]} to line {view_range[1]}."
|
|
75
|
+
else:
|
|
76
|
+
content = f"I will view the directory `{path}`."
|
|
77
|
+
elif command == "create":
|
|
78
|
+
|
|
79
|
+
if path:
|
|
80
|
+
content = f"I will create the file `{path}"
|
|
81
|
+
if file_text and complete:
|
|
82
|
+
content += f"` with the following content:\n```{fence}\n{file_text}\n```"
|
|
83
|
+
elif command == "str_replace":
|
|
84
|
+
if path:
|
|
85
|
+
content = f"In the file `{path}"
|
|
86
|
+
if old_str is not None:
|
|
87
|
+
if new_str is not None:
|
|
88
|
+
content += f"`, I will replace the string:\n```{fence}\n{old_str}\n```"
|
|
89
|
+
if complete:
|
|
90
|
+
content += f"\nwith:\n```{fence}\n{new_str}\n```"
|
|
91
|
+
elif command == "insert":
|
|
92
|
+
|
|
93
|
+
if path:
|
|
94
|
+
content = f"In the file `{path}"
|
|
95
|
+
if insert_line is not None and new_str and complete:
|
|
96
|
+
content += f"`, I will insert the following text after line {insert_line}:\n```{fence}\n{new_str}\n```"
|
|
97
|
+
elif command == "undo_edit":
|
|
98
|
+
if path:
|
|
99
|
+
content = f"I will undo the last edit for the file `{path}"
|
|
100
|
+
if complete:
|
|
101
|
+
content += "`"
|
|
102
|
+
else:
|
|
103
|
+
# If command is not valid or empty, return empty content
|
|
104
|
+
content = ""
|
|
105
|
+
|
|
106
|
+
return content, complete
|
|
107
|
+
except Exception as e:
|
|
108
|
+
# Handle any parsing errors gracefully
|
|
109
|
+
return content + f"failed to parse arguments: {arguments}", False
|
|
110
|
+
|
|
111
|
+
def supports_streaming(self) -> bool:
|
|
112
|
+
"""FileEditFormatter supports streaming rendering"""
|
|
113
|
+
return True
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def supported_function(self) -> str:
|
|
117
|
+
return "edit_file"
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def get_style(self) -> str:
|
|
121
|
+
return "markdown"
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class SearchFormatter(ToolCallFormatter):
|
|
125
|
+
"""
|
|
126
|
+
Search formatter
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
def format_input(self, call_id: str, function_name: str, arguments: str) -> Tuple[str, bool]:
|
|
130
|
+
try:
|
|
131
|
+
args = json.loads(arguments)
|
|
132
|
+
cwd = args.get("cwd", os.getcwd())
|
|
133
|
+
directory_path = args.get("directory_path", "")
|
|
134
|
+
regex = args.get("regex", "")
|
|
135
|
+
file_pattern = args.get("file_pattern", "*")
|
|
136
|
+
content = f"I will search for: {regex} in {directory_path} with file pattern {file_pattern} in {cwd}"
|
|
137
|
+
return content, True
|
|
138
|
+
except json.JSONDecodeError:
|
|
139
|
+
return f"failed to parse arguments: {arguments}", False
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def supported_function(self) -> str:
|
|
143
|
+
return "search"
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class CommandFormatter(ToolCallFormatter):
|
|
147
|
+
"""
|
|
148
|
+
Command formatter
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
def format_input(self, call_id: str, function_name: str, arguments: str) -> Tuple[str, bool]:
|
|
152
|
+
try:
|
|
153
|
+
args = json.loads(arguments)
|
|
154
|
+
command = args.get("command", "")
|
|
155
|
+
return f"siada wants to run the following command: \n```bash \n{command}\n```", True
|
|
156
|
+
except json.JSONDecodeError:
|
|
157
|
+
return f"failed to parse arguments: {arguments}", False
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def supported_function(self) -> str:
|
|
161
|
+
return "run_cmd"
|
|
162
|
+
|
|
163
|
+
def get_style(self) -> str:
|
|
164
|
+
return "markdown"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class FixAttemptCompletionFormatter(ToolCallFormatter):
|
|
168
|
+
"""
|
|
169
|
+
Formatter for the fix_attempt_completion function.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
def format_input(
|
|
173
|
+
self, call_id: str, function_name: str, arguments: str
|
|
174
|
+
) -> Tuple[str, bool]:
|
|
175
|
+
|
|
176
|
+
complete = False
|
|
177
|
+
content = ""
|
|
178
|
+
try:
|
|
179
|
+
# Use partial JSON parser to handle incomplete arguments
|
|
180
|
+
args = loads(arguments)
|
|
181
|
+
# Check if JSON is complete by comparing with ensured version
|
|
182
|
+
ensured_json = ensure_json(arguments)
|
|
183
|
+
if arguments == ensured_json:
|
|
184
|
+
complete = True
|
|
185
|
+
|
|
186
|
+
# Safely extract values, handling potential None/missing keys
|
|
187
|
+
result = args.get("result", "") if args else ""
|
|
188
|
+
|
|
189
|
+
if result:
|
|
190
|
+
content = f"The bug fix task has been successfully completed:\n{result}"
|
|
191
|
+
if complete:
|
|
192
|
+
content += ""
|
|
193
|
+
|
|
194
|
+
return content, complete
|
|
195
|
+
except Exception as e:
|
|
196
|
+
return content + f"failed to parse arguments: {arguments}", False
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def supports_streaming(self) -> bool:
|
|
200
|
+
return False
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def supported_function(self) -> str:
|
|
204
|
+
return "fix_attempt_completion"
|
|
205
|
+
|
|
206
|
+
def get_style(self) -> str:
|
|
207
|
+
return "markdown"
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class ReproduceCompletionFormatter(ToolCallFormatter):
|
|
211
|
+
"""
|
|
212
|
+
Formatter for the reproduce_completion function.
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
def format_input(self, call_id: str, function_name: str, arguments: str) -> Tuple[str, bool]:
|
|
216
|
+
try:
|
|
217
|
+
args = json.loads(arguments)
|
|
218
|
+
test_case = args.get("test_case", "")
|
|
219
|
+
bug_analysis = args.get("bug_analysis", "")
|
|
220
|
+
content = f"This issue can be reproduced using test case : {test_case}.\n Analysis of the issue: {bug_analysis}"
|
|
221
|
+
return content, True
|
|
222
|
+
except json.JSONDecodeError:
|
|
223
|
+
return f"failed to parse arguments: {arguments}", False
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def supported_function(self) -> str:
|
|
227
|
+
return "reproduce_completion"
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class WebCrawlFormatter(ToolCallFormatter):
|
|
231
|
+
"""
|
|
232
|
+
Formatter for the web_crawl function.
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
def format_input(self, call_id: str, function_name: str, arguments: str) -> Tuple[str, bool]:
|
|
236
|
+
try:
|
|
237
|
+
args = json.loads(arguments)
|
|
238
|
+
url = args.get("url", "")
|
|
239
|
+
crawl_format = args.get("format", "text")
|
|
240
|
+
return f"siada wants to crawl the url: {url} with format {crawl_format}", True
|
|
241
|
+
except json.JSONDecodeError:
|
|
242
|
+
return f"failed to parse arguments: {arguments}", False
|
|
243
|
+
|
|
244
|
+
@property
|
|
245
|
+
def supported_function(self) -> str:
|
|
246
|
+
return "web_crawl"
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class AskFollowupQuestionFormatter(ToolCallFormatter):
|
|
250
|
+
"""
|
|
251
|
+
Formatter for the ask_followup_question function.
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
def format_input(self, call_id: str, function_name: str, arguments: str) -> Tuple[str, bool]:
|
|
255
|
+
try:
|
|
256
|
+
args = json.loads(arguments)
|
|
257
|
+
question = args.get("question", "")
|
|
258
|
+
return f"{question}", True
|
|
259
|
+
except json.JSONDecodeError:
|
|
260
|
+
return f"failed to parse arguments: {arguments}", False
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def supported_function(self) -> str:
|
|
264
|
+
return "ask_followup_question"
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class ListCodeDefinitionNamesFormatter(ToolCallFormatter):
|
|
268
|
+
"""
|
|
269
|
+
Formatter for the list_code_definition_names function.
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
def format_input(self, call_id: str, function_name: str, arguments: str) -> Tuple[str, bool]:
|
|
273
|
+
try:
|
|
274
|
+
args = json.loads(arguments)
|
|
275
|
+
file_name = args.get("file_name", "Unknown file")
|
|
276
|
+
return f"siada wants to analyze definitions in `{file_name}`", True
|
|
277
|
+
except json.JSONDecodeError:
|
|
278
|
+
return "failed to parse arguments: {arguments}", False
|
|
279
|
+
|
|
280
|
+
@property
|
|
281
|
+
def supported_function(self) -> str:
|
|
282
|
+
return "list_code_definition_names"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Dict, Tuple
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ToolCallFormatter(ABC):
|
|
6
|
+
"""
|
|
7
|
+
Tool call formatter interface
|
|
8
|
+
Used to format input parameters for different functions
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def format_input(self, call_id: str, function_name: str, arguments: str) -> Tuple[str, bool]:
|
|
13
|
+
"""
|
|
14
|
+
Format function input parameters
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
call_id: tool_call id
|
|
18
|
+
function_name: function name
|
|
19
|
+
arguments: raw parameter string
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
A tuple containing content and completeness flag (content, is_complete)
|
|
23
|
+
"""
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
def supports_streaming(self) -> bool:
|
|
27
|
+
"""
|
|
28
|
+
Whether streaming rendering is supported
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
True if this formatter supports streaming rendering, False otherwise
|
|
32
|
+
"""
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def supported_function(self) -> str:
|
|
38
|
+
"""
|
|
39
|
+
Return the supported function name
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
The supported function name
|
|
43
|
+
"""
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_style(self) -> str:
|
|
48
|
+
"""
|
|
49
|
+
Return the style
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
The style
|
|
53
|
+
"""
|
|
54
|
+
return "text"
|
|
File without changes
|