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,410 @@
1
+ import inspect
2
+ from siada.services.model_info_service import ModelInfoService
3
+ import siada.session.session_models
4
+ import sys
5
+
6
+ import litellm
7
+ from prompt_toolkit.completion import Completion, PathCompleter
8
+ from prompt_toolkit.document import Document
9
+
10
+ import siada.io.io
11
+ from siada.models.model_run_config import ModelRunConfig
12
+ from siada.support.editor import pipe_editor
13
+ from siada.tools.coder.cmd_runner import run_cmd_impl as run_cmd
14
+
15
+
16
+ class SwitchEvent:
17
+ def __init__(self, **kwargs):
18
+ self.kwargs = kwargs
19
+
20
+
21
+ class SlashCommands:
22
+
23
+ def clone(self):
24
+ return SlashCommands(
25
+ io=self.io,
26
+ verbose=self.verbose,
27
+ editor=self.editor,
28
+ )
29
+
30
+ def __init__(
31
+ self,
32
+ io : siada.io.io.InputOutput,
33
+ verbose=False,
34
+ editor=None,
35
+ ):
36
+ self.io = io
37
+ self.verbose = verbose
38
+ self.help = None
39
+ self.editor = editor
40
+
41
+ # def cmd_model(self, args):
42
+
43
+ # model_name = args.strip()
44
+ # if not model_name:
45
+ # self.io.print_info("No model name provided")
46
+ # return
47
+
48
+ # model = ModelRunConfig(model_name)
49
+ # return SwitchEvent(model=model)
50
+
51
+ # def cmd_agent(self, args):
52
+ # "Switch to a different agent type"
53
+
54
+ # agent_name = args.strip()
55
+
56
+ # try:
57
+ # from siada.services.siada_runner import SiadaRunner
58
+
59
+ # # Load agent configurations
60
+ # agent_configs = SiadaRunner._load_agent_config()
61
+ # # Get all available agent types (only enabled ones)
62
+ # available_agents = {name: config for name, config in agent_configs.items()
63
+ # if config.get('class') and config.get('enabled', True)}
64
+
65
+ # if not agent_name:
66
+ # self.io.print_info("Available agents:\n")
67
+ # max_name_length = max(len(name) for name in available_agents.keys()) if available_agents else 0
68
+ # for name, config in available_agents.items():
69
+ # description = config.get('description', f'{name.title()} agent')
70
+ # self.io.print_info(f"- {name:<{max_name_length}} : {description}")
71
+ # self.io.print_info("\nUsage: /agent <agent_name>")
72
+ # return
73
+
74
+ # # Normalize agent name (lowercase, remove underscores/hyphens)
75
+ # normalized_name = agent_name.lower().replace('_', '').replace('-', '')
76
+
77
+ # # Find matching agent config
78
+ # agent_config = available_agents.get(normalized_name)
79
+
80
+ # if agent_config is None:
81
+ # available_names = list(available_agents.keys())
82
+ # self.io.print_error(f"Unknown agent: '{agent_name}'")
83
+ # self.io.print_info(f"Available agents: {', '.join(available_names)}")
84
+ # return
85
+
86
+ # # Check if agent class is implemented
87
+ # if not agent_config.get('class'):
88
+ # self.io.print_error(f"Agent '{agent_name}' is not implemented yet")
89
+ # return
90
+
91
+ # self.io.print_info(f"Switching to {agent_name} agent...")
92
+
93
+ # # Return SwitchEvent to change agent
94
+ # return SwitchEvent(agent=normalized_name)
95
+
96
+ # except Exception as e:
97
+ # self.io.print_error(f"Failed to switch agent: {e}")
98
+ # if self.verbose:
99
+ # import traceback
100
+ # self.io.print_error(traceback.format_exc())
101
+
102
+
103
+ def cmd_shell(self, args):
104
+ "Open a shell"
105
+ self.io.print_info("Switching to shell mode...")
106
+ return SwitchEvent(shell=True)
107
+
108
+ def completions_model(self):
109
+ return ModelInfoService.get_model_names()
110
+
111
+ def cmd_models(self, args):
112
+ "Search the list of available models"
113
+
114
+ args = args.strip()
115
+
116
+ # models.print_matching_models(self.io, args)
117
+ models = ModelInfoService.get_model_names()
118
+ for model in models:
119
+ self.io.print_info(f"- {model}")
120
+
121
+
122
+
123
+ def is_command(self, inp):
124
+ return inp[0] in "/!"
125
+
126
+ def get_raw_completions(self, cmd):
127
+ assert cmd.startswith("/")
128
+ cmd = cmd[1:]
129
+ cmd = cmd.replace("-", "_")
130
+
131
+ raw_completer = getattr(self, f"completions_raw_{cmd}", None)
132
+ return raw_completer
133
+
134
+ def get_completions(self, cmd):
135
+ assert cmd.startswith("/")
136
+ cmd = cmd[1:]
137
+
138
+ cmd = cmd.replace("-", "_")
139
+ fun = getattr(self, f"completions_{cmd}", None)
140
+ if not fun:
141
+ return
142
+ return sorted(fun())
143
+
144
+ def get_commands(self):
145
+ commands = []
146
+ for attr in dir(self):
147
+ if not attr.startswith("cmd_"):
148
+ continue
149
+ cmd = attr[4:]
150
+ cmd = cmd.replace("_", "-")
151
+ commands.append("/" + cmd)
152
+
153
+ return commands
154
+
155
+ def do_run(self, session, cmd_name, args):
156
+ cmd_name = cmd_name.replace("-", "_")
157
+ cmd_method_name = f"cmd_{cmd_name}"
158
+ cmd_method = getattr(self, cmd_method_name, None)
159
+ if not cmd_method:
160
+ self.io.print_info(f"Error: Command {cmd_name} not found.")
161
+ return
162
+
163
+ try:
164
+ # 检查方法的参数签名
165
+ sig = inspect.signature(cmd_method)
166
+ params = list(sig.parameters.keys())
167
+
168
+ # 如果方法有 session 参数,则传递 session 和 args
169
+ if 'session' in params:
170
+ return cmd_method(session, args)
171
+ else:
172
+ # 否则只传递 args
173
+ return cmd_method(args)
174
+ except Exception as err:
175
+ self.io.print_error(f"Unable to complete {cmd_name}: {err}")
176
+
177
+ def matching_commands(self, inp):
178
+ words = inp.strip().split()
179
+ if not words:
180
+ return
181
+
182
+ first_word = words[0]
183
+ rest_inp = inp[len(words[0]) :].strip()
184
+
185
+ all_commands = self.get_commands()
186
+ matching_commands = [cmd for cmd in all_commands if cmd.startswith(first_word)]
187
+ return matching_commands, first_word, rest_inp
188
+
189
+ def run(self, session, inp):
190
+ """
191
+ Run a command.
192
+ any method called cmd_xxx becomes a command automatically.
193
+ each one must take an args param.
194
+ """
195
+ if inp.startswith("!"):
196
+ return self.do_run(session, "run", inp[1:])
197
+
198
+ res = self.matching_commands(inp)
199
+ if res is None:
200
+ return
201
+ matching_commands, first_word, rest_inp = res
202
+ if len(matching_commands) == 1:
203
+ command = matching_commands[0][1:]
204
+ return self.do_run(session, command, rest_inp)
205
+ elif first_word in matching_commands:
206
+ command = first_word[1:]
207
+ return self.do_run(session, command, rest_inp)
208
+ elif len(matching_commands) > 1:
209
+ self.io.print_error(f"Ambiguous command: {', '.join(matching_commands)}")
210
+ else:
211
+ self.io.print_error(f"Invalid command: {first_word}")
212
+
213
+ def completions_raw_read_only(self, document, complete_event):
214
+ # Get the text before the cursor
215
+ text = document.text_before_cursor
216
+
217
+ # Skip the first word and the space after it
218
+ after_command = text.split()[-1]
219
+
220
+ # Create a new Document object with the text after the command
221
+ new_document = Document(after_command, cursor_position=len(after_command))
222
+
223
+ def get_paths():
224
+ return [self.coder.root] if self.coder.root else None
225
+
226
+ path_completer = PathCompleter(
227
+ get_paths=get_paths,
228
+ only_directories=False,
229
+ expanduser=True,
230
+ )
231
+
232
+ # Adjust the start_position to replace all of 'after_command'
233
+ adjusted_start_position = -len(after_command)
234
+
235
+ # Collect all completions
236
+ all_completions = []
237
+
238
+ # Iterate over the completions and modify them
239
+ for completion in path_completer.get_completions(new_document, complete_event):
240
+ quoted_text = self.quote_fname(after_command + completion.text)
241
+ all_completions.append(
242
+ Completion(
243
+ text=quoted_text,
244
+ start_position=adjusted_start_position,
245
+ display=completion.display,
246
+ style=completion.style,
247
+ selected_style=completion.selected_style,
248
+ )
249
+ )
250
+
251
+ # Add completions from the 'add' command
252
+ add_completions = self.completions_add()
253
+ for completion in add_completions:
254
+ if after_command in completion:
255
+ all_completions.append(
256
+ Completion(
257
+ text=completion,
258
+ start_position=adjusted_start_position,
259
+ display=completion,
260
+ )
261
+ )
262
+
263
+ # Sort all completions based on their text
264
+ sorted_completions = sorted(all_completions, key=lambda c: c.text)
265
+
266
+ # Yield the sorted completions
267
+ for completion in sorted_completions:
268
+ yield completion
269
+
270
+ def cmd_run(self, session, args, add_on_nonzero_exit=False):
271
+ "Run a shell command (alias: !)"
272
+ exit_status, combined_output = run_cmd(
273
+ args,
274
+ verbose=self.verbose,
275
+ error_print=self.io.print_error,
276
+ cwd=session.siada_config.workspace,
277
+ )
278
+ return combined_output
279
+
280
+ def cmd_exit(self, args):
281
+ "Exit the application"
282
+ sys.exit()
283
+
284
+ def cmd_quit(self, args):
285
+ "Exit the application"
286
+ self.cmd_exit(args)
287
+
288
+ def basic_help(self):
289
+ commands = sorted(self.get_commands())
290
+ pad = max(len(cmd) for cmd in commands)
291
+ pad = "{cmd:" + str(pad) + "}"
292
+ for cmd in commands:
293
+ cmd_method_name = f"cmd_{cmd[1:]}".replace("-", "_")
294
+ cmd_method = getattr(self, cmd_method_name, None)
295
+ cmd = pad.format(cmd=cmd)
296
+ if cmd_method:
297
+ description = cmd_method.__doc__
298
+ self.io.print_info(f"{cmd} {description}")
299
+ else:
300
+ self.io.print_info(f"{cmd} No description available.")
301
+ self.io.print_info()
302
+ self.io.print_info("Use `/help <question>` to ask questions about how to use siadahub.")
303
+
304
+ def get_help_md(self):
305
+ "Show help about all commands in markdown"
306
+
307
+ res = """
308
+ |Command|Description|
309
+ |:------|:----------|
310
+ """
311
+ commands = sorted(self.get_commands())
312
+ for cmd in commands:
313
+ cmd_method_name = f"cmd_{cmd[1:]}".replace("-", "_")
314
+ cmd_method = getattr(self, cmd_method_name, None)
315
+ if cmd_method:
316
+ description = cmd_method.__doc__
317
+ res += f"| **{cmd}** | {description} |\n"
318
+ else:
319
+ res += f"| **{cmd}** | |\n"
320
+
321
+ res += "\n"
322
+ return res
323
+
324
+ # def cmd_map(self, args):
325
+ # "Print out the current repository map"
326
+ # repo_map = self.coder.get_repo_map()
327
+ # if repo_map:
328
+ # self.io.print_info(repo_map)
329
+ # else:
330
+ # self.io.print_info("No repository map available.")
331
+
332
+ # def cmd_map_refresh(self, args):
333
+ # "Force a refresh of the repository map"
334
+ # repo_map = self.coder.get_repo_map(force_refresh=True)
335
+ # if repo_map:
336
+ # self.io.print_info("The repo map has been refreshed, use /map to view it.")
337
+
338
+
339
+ def cmd_multiline_mode(self, args):
340
+ "Toggle multiline mode (swaps behavior of Enter and Meta+Enter)"
341
+ self.io.toggle_multiline_mode()
342
+
343
+ def cmd_editor(self, initial_content=""):
344
+ "Open an editor to write a prompt"
345
+
346
+ user_input = pipe_editor(initial_content, suffix="md", editor=self.editor)
347
+ if user_input.strip():
348
+ self.io.set_placeholder(user_input.rstrip())
349
+
350
+ def cmd_edit(self, args=""):
351
+ "Siada for /editor: Open an editor to write a prompt"
352
+ return self.cmd_editor(args)
353
+
354
+ # def cmd_think_tokens(self, session, args):
355
+ # """Set the thinking token budget, eg: 8096, 8k, 10.5k, 0.5M, or 0 to disable."""
356
+
357
+ # model = session.interaction_config.model
358
+
359
+ # if not args.strip():
360
+ # # Display current value if no args are provided
361
+ # formatted_budget = model.get_thinking_tokens()
362
+ # if formatted_budget is None:
363
+ # self.io.print_info("Thinking tokens are not currently set.")
364
+ # else:
365
+ # budget = model.get_raw_thinking_tokens()
366
+ # self.io.print_info(
367
+ # f"Current thinking token budget: {budget:,} tokens ({formatted_budget})."
368
+ # )
369
+ # return
370
+
371
+ # value = args.strip()
372
+ # model.set_thinking_tokens(value)
373
+
374
+ # # Handle the special case of 0 to disable thinking tokens
375
+ # if value == "0":
376
+ # self.io.print_info("Thinking tokens disabled.")
377
+ # else:
378
+ # formatted_budget = model.get_thinking_tokens()
379
+ # budget = model.get_raw_thinking_tokens()
380
+ # self.io.print_info(
381
+ # f"Set thinking token budget to {budget:,} tokens ({formatted_budget})."
382
+ # )
383
+
384
+ # def cmd_reasoning_effort(self, session, args):
385
+ # "Set the reasoning effort level (values: number or low/medium/high depending on model)"
386
+ # model = session.interaction_config.model
387
+
388
+ # if not args.strip():
389
+ # # Display current value if no args are provided
390
+ # reasoning_value = model.get_reasoning_effort()
391
+ # if reasoning_value is None:
392
+ # self.io.print_info("Reasoning effort is not currently set.")
393
+ # else:
394
+ # self.io.print_info(f"Current reasoning effort: {reasoning_value}")
395
+ # return
396
+
397
+ # value = args.strip()
398
+ # model.set_reasoning_effort(value)
399
+ # reasoning_value = model.get_reasoning_effort()
400
+ # self.io.print_info(f"Set reasoning effort to {reasoning_value}")
401
+
402
+
403
+ def main():
404
+ md = SlashCommands(None, None).get_help_md()
405
+ print(md)
406
+
407
+
408
+ if __name__ == "__main__":
409
+ status = main()
410
+ sys.exit(status)