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,214 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Generic
3
+ import yaml
4
+ import os
5
+
6
+ from agents import Agent, RunConfig, RunHooks, RunResult, RunResultStreaming, Runner, TContext, TResponseInputItem, set_trace_processors
7
+ from siada.agent_hub.coder.tracing.logger_tracing_processor import create_detailed_logger
8
+ from siada.foundation.code_agent_context import CodeAgentContext
9
+ from siada.models.converter import ModelSettingsConverter
10
+ from siada.provider.provider_factory import get_provider
11
+ from siada.session import RunningSessionManager
12
+ from siada.tools.coder.ask_followup_question import ask_followup_question
13
+ from siada.tools.coder.repo_map.repo_map import RepoMap
14
+ from siada.tools.coder.repo_map.token_counter import TokenCounterModel
15
+ from siada.tools.coder.repo_map.io import SilentIO
16
+
17
+ import logging
18
+
19
+ class SiadaAgent(Agent[Generic[TContext]], ABC):
20
+
21
+ @abstractmethod
22
+ async def get_context(self) -> TContext:
23
+ """
24
+ Get the context object for this agent.
25
+
26
+ Returns:
27
+ TContext: The context object containing relevant information for the agent's execution.
28
+ """
29
+ pass
30
+
31
+ @abstractmethod
32
+ async def run(self, user_input: str, context: TContext) -> RunResult:
33
+ """
34
+ Execute the agent with the given user input and context.
35
+
36
+ Args:
37
+ user_input (str): The input provided by the user.
38
+ context (TContext): The context object containing relevant information for execution.
39
+
40
+ Returns:
41
+ RunResult: The result of the agent's execution.
42
+ """
43
+ pass
44
+
45
+ @abstractmethod
46
+ async def run_streamed(self, user_input: str, context: TContext) -> RunResultStreaming:
47
+ """
48
+ Execute Streamed the agent with the given user input and context
49
+
50
+ Args:
51
+ user_input (str): The input provided by the user.
52
+ context (TContext): The context object containing relevant information for execution.
53
+
54
+ Returns:
55
+ RunResultStreaming: The stream result of the agent's execution.
56
+ """
57
+ pass
58
+
59
+ def get_interactive_mode(self) -> bool:
60
+ """
61
+ 获取当前的交互模式状态
62
+
63
+ Returns:
64
+ bool: True为交互模式,False为非交互模式
65
+ """
66
+ # 检查是否有--prompt参数,如果有则为非交互模式
67
+ import sys
68
+ return '--prompt' not in sys.argv and '-p' not in sys.argv
69
+
70
+ def get_repo_map_model_name(self) -> str:
71
+ """
72
+ Get the model name used for repo map generation
73
+
74
+ Returns:
75
+ str: Model name, defaults to claude-sonnet-4
76
+ """
77
+ try:
78
+ # Read configuration file
79
+ config_path = os.path.join(os.getcwd(), "agent_config.yaml")
80
+ if os.path.exists(config_path):
81
+ with open(config_path, 'r', encoding='utf-8') as f:
82
+ config = yaml.safe_load(f)
83
+ llm_config = config.get('llm_config', {})
84
+ return llm_config.get('model_name', 'claude-sonnet-4')
85
+ except Exception as e:
86
+ logging.warning(f"Failed to read agent config file for repo map model name: {str(e)}")
87
+
88
+ # If reading configuration fails, use default value
89
+ return 'claude-sonnet-4'
90
+
91
+ def get_repo_map_instance(self, root_dir: str):
92
+ """
93
+ Get RepoMap instance
94
+
95
+ Args:
96
+ root_dir (str): Repository root directory
97
+
98
+ Returns:
99
+ RepoMap: Configured RepoMap instance
100
+ """
101
+ try:
102
+
103
+ # Read configuration
104
+ config_path = os.path.join(os.getcwd(), "agent_config.yaml")
105
+ llm_config = {}
106
+ if os.path.exists(config_path):
107
+ try:
108
+ with open(config_path, 'r', encoding='utf-8') as f:
109
+ config = yaml.safe_load(f)
110
+ llm_config = config.get('llm_config', {})
111
+ except Exception as e:
112
+ logging.warning(f"Failed to read agent config file for repo map instance: {str(e)}")
113
+
114
+ # Get configuration parameters
115
+ model_name = llm_config.get('model_name', 'claude-sonnet-4')
116
+ repo_map_tokens = llm_config.get('repo_map_tokens', 8192)
117
+ repo_map_mul_no_files = llm_config.get('repo_map_mul_no_files', 16)
118
+ repo_verbose = llm_config.get('repo_verbose', True)
119
+
120
+ # Create components
121
+ token_counter = TokenCounterModel(model_name)
122
+ io = SilentIO() # Use silent IO to avoid output interference
123
+
124
+ return RepoMap(
125
+ root=root_dir,
126
+ main_model=token_counter,
127
+ io=io,
128
+ verbose=repo_verbose,
129
+ map_tokens=repo_map_tokens,
130
+ map_mul_no_files=repo_map_mul_no_files
131
+ )
132
+ except Exception as e:
133
+ logging.warning(f"Failed to create RepoMap instance for root directory '{root_dir}': {str(e)}")
134
+ # If creation fails, return None
135
+ return None
136
+
137
+ async def prepare_run_environment(
138
+ self,
139
+ context: TContext | None = None,
140
+ ):
141
+ running_session = context.session
142
+ if running_session is None:
143
+ running_session = RunningSessionManager.get_default_session()
144
+ context.session = running_session
145
+
146
+ llm_config = running_session.siada_config.llm_config
147
+ model_settings = ModelSettingsConverter.convert_model_settings(llm_config)
148
+ model_provider_name = llm_config.provider
149
+ model_provider = get_provider(model_provider_name)
150
+
151
+ # Store provider name (string) in context for client factory
152
+ context.provider = model_provider_name
153
+
154
+ # if running_session.running_config.interactive:
155
+ # ## in the interactive mode, we need to add the ask_followup_question tool
156
+ # if ask_followup_question not in self.tools:
157
+ # self.tools.append(ask_followup_question)
158
+
159
+ run_config = RunConfig(
160
+ tracing_disabled=running_session.siada_config.tracing_disabled,
161
+ model=llm_config.model_name,
162
+ model_provider=model_provider,
163
+ model_settings=model_settings
164
+ )
165
+
166
+ session = running_session.state.openai_session
167
+ return run_config, session
168
+
169
+ async def run_impl(
170
+ self,
171
+ starting_agent: Agent[TContext],
172
+ input: str | list[TResponseInputItem],
173
+ context: TContext | None = None,
174
+ max_turns: int = 10,
175
+ hooks: RunHooks[TContext] | None = None,
176
+ previous_response_id: str | None = None,
177
+ ) -> RunResult:
178
+
179
+ run_config, session = await self.prepare_run_environment(context)
180
+
181
+ return await Runner.run(
182
+ starting_agent=starting_agent,
183
+ input=input,
184
+ context=context,
185
+ max_turns=max_turns,
186
+ hooks=hooks,
187
+ run_config=run_config,
188
+ previous_response_id=previous_response_id,
189
+ session=session,
190
+ )
191
+
192
+ async def run_streamed_impl(
193
+ self,
194
+ starting_agent: Agent[TContext],
195
+ input: str | list[TResponseInputItem],
196
+ context: TContext | None = None,
197
+ max_turns: int = 10,
198
+ hooks: RunHooks[TContext] | None = None,
199
+ run_config: RunConfig | None = None,
200
+ previous_response_id: str | None = None,
201
+ ) -> RunResultStreaming:
202
+
203
+ run_config, session = await self.prepare_run_environment(context)
204
+
205
+ return Runner.run_streamed(
206
+ starting_agent=starting_agent,
207
+ input=input,
208
+ context=context,
209
+ max_turns=max_turns,
210
+ hooks=hooks,
211
+ run_config=run_config,
212
+ previous_response_id=previous_response_id,
213
+ session=session,
214
+ )
File without changes
@@ -0,0 +1,67 @@
1
+
2
+
3
+
4
+
5
+
6
+
7
+ import os
8
+ import yaml
9
+ from dataclasses import dataclass, asdict, field
10
+ from pathlib import Path
11
+ from typing import Optional, Dict, Any
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class LLMConfig:
16
+ """LLM configuration class"""
17
+ model: Optional[str] = None
18
+ provider: Optional[str] = None
19
+
20
+ @classmethod
21
+ def from_dict(cls, data: Dict[str, Any]) -> 'LLMConfig':
22
+ """Create LLMConfig instance from dictionary"""
23
+ return cls(
24
+ model=data.get('model'),
25
+ provider=data.get('provider')
26
+ )
27
+
28
+ def to_dict(self) -> Dict[str, Any]:
29
+ """Convert to dictionary"""
30
+ return asdict(self)
31
+
32
+
33
+ def _get_default_config_path() -> Path:
34
+ """Get default configuration file path"""
35
+ home_dir = Path.home()
36
+ return home_dir / '.siada-cli' / 'conf.yaml'
37
+
38
+ @dataclass(frozen=True)
39
+ class Config:
40
+ """Main configuration class (immutable)"""
41
+ llm_config: LLMConfig = field(default_factory=LLMConfig)
42
+
43
+ def load_conf(config_path: Optional[Path] = None) -> 'Config':
44
+ """Load configuration from YAML file"""
45
+ if config_path is None:
46
+ config_path = _get_default_config_path()
47
+
48
+ llm_config = LLMConfig()
49
+
50
+ try:
51
+ if config_path.exists():
52
+ with open(config_path, 'r', encoding='utf-8') as file:
53
+ data = yaml.safe_load(file) or {}
54
+
55
+ # Load LLM configuration
56
+ if 'llm_config' in data:
57
+ llm_config = LLMConfig.from_dict(data['llm_config'])
58
+ # If config file doesn't exist, return default values without creating directories
59
+
60
+ except yaml.YAMLError as e:
61
+ print(f"Warning: Configuration file format error: {e}")
62
+ except Exception as e:
63
+ print(f"Warning: Failed to load configuration file: {e}")
64
+
65
+ return Config(llm_config=llm_config)
66
+
67
+
@@ -0,0 +1,3 @@
1
+ """
2
+ Siada Hub 命令行工具入口点
3
+ """
File without changes
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env python
2
+
3
+ import argparse
4
+ import os
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ import configargparse
9
+ import shtab
10
+
11
+ from siada import __version__
12
+ from siada.services.siada_runner import SiadaRunner
13
+
14
+
15
+ def default_env_file(git_root):
16
+ return os.path.join(git_root, ".env") if git_root else ".env"
17
+
18
+
19
+ def get_parser(default_config_files, git_root):
20
+ parser = configargparse.ArgumentParser(
21
+ description="Siada-CLI is AI pair programming in your terminal",
22
+ add_config_file_help=True,
23
+ default_config_files=default_config_files,
24
+ config_file_parser_class=configargparse.YAMLConfigFileParser,
25
+ auto_env_var_prefix="SIADA_",
26
+ )
27
+
28
+ # Load agent configurations from config file
29
+ try:
30
+ agent_configs = SiadaRunner._load_agent_config()
31
+ # Get enabled agent types for choices
32
+ agent_choices = [name for name, config in agent_configs.items()
33
+ if config.get('enabled', False) and config.get('class')]
34
+ except Exception as e:
35
+ # Fallback to default if config loading fails
36
+ agent_configs = {}
37
+ agent_choices = ['bugfix', 'coder', 'fegen', 'bugreproduce']
38
+ print(f"Warning: Failed to load agent config, using defaults: {e}")
39
+
40
+ ##########
41
+ group = parser.add_argument_group("agent config")
42
+
43
+ group.add_argument(
44
+ "--agent",
45
+ "-a",
46
+ metavar="AGENT",
47
+ choices=agent_choices,
48
+ default="coder",
49
+ help=f"Specify the agent type to use (choices: {', '.join(agent_choices)}, default: coder)",
50
+ )
51
+
52
+ # Generate individual agent command arguments
53
+ for agent_name in agent_choices:
54
+ agent_config = agent_configs.get(agent_name, {})
55
+ description = agent_config.get('description', f'{agent_name.title()} agent')
56
+
57
+ group.add_argument(
58
+ f"--{agent_name}",
59
+ action="store_const",
60
+ dest="agent",
61
+ const=agent_name,
62
+ help=f"Use {description}",
63
+ )
64
+
65
+ ##########
66
+ group = parser.add_argument_group("prompt config")
67
+ group.add_argument(
68
+ "--prompt",
69
+ "-p",
70
+ metavar="PROMPT",
71
+ default=None,
72
+ help="Specify the prompt, if provided, it will be activated for the no interaction mode",
73
+ )
74
+
75
+ ##########
76
+ group = parser.add_argument_group("API Keys and settings")
77
+ group.add_argument(
78
+ "--env-file",
79
+ metavar="ENV_FILE",
80
+ default=default_env_file(git_root),
81
+ help="Specify the .env file to load (default: .env in git root)",
82
+ ).complete = shtab.FILE
83
+
84
+ group.add_argument(
85
+ "--set-env",
86
+ action="append",
87
+ metavar="ENV_VAR_NAME=value",
88
+ help="Set an environment variable (to control API settings, can be used multiple times)",
89
+ default=[],
90
+ )
91
+
92
+ group = parser.add_argument_group("Model settings")
93
+
94
+ group.add_argument(
95
+ "--model",
96
+ metavar="MODEL",
97
+ default=None,
98
+ help="Specify the model to use for the main chat",
99
+ )
100
+
101
+ group.add_argument(
102
+ "--list-models",
103
+ "--models",
104
+ action="store_true",
105
+ help="List all available models",
106
+ )
107
+
108
+ group.add_argument(
109
+ "--reasoning-effort",
110
+ type=str,
111
+ help="Set the reasoning_effort API parameter (default: not set)",
112
+ )
113
+ group.add_argument(
114
+ "--thinking-tokens",
115
+ type=str,
116
+ help=(
117
+ "Set the thinking token budget for models that support it. Use 0 to disable. (default:"
118
+ " not set)"
119
+ ),
120
+ )
121
+
122
+ group.add_argument(
123
+ "--provider",
124
+ choices=["openrouter", "li"],
125
+ default=None,
126
+ help="Specify the provider to use for the main chat (choices: openrouter, li, default: li)",
127
+ metavar="PROVIDER",
128
+ )
129
+
130
+ group = parser.add_argument_group("Output settings")
131
+ group.add_argument(
132
+ "--theme",
133
+ choices=["default", "dark", "light"],
134
+ default="dark",
135
+ help="Select color theme: default, dark, or light (default: None, auto-detect or use individual mode flags)",
136
+ )
137
+
138
+ group.add_argument(
139
+ "--pretty",
140
+ action=argparse.BooleanOptionalAction,
141
+ default=True,
142
+ help="Enable/disable pretty, colorized output (default: True)",
143
+ )
144
+
145
+ group.add_argument(
146
+ "--fancy-input",
147
+ action=argparse.BooleanOptionalAction,
148
+ default=True,
149
+ help="Enable/disable fancy input (default: True)",
150
+ )
151
+
152
+ group = parser.add_argument_group("Upgrading")
153
+ group.add_argument(
154
+ "--version",
155
+ action="version",
156
+ version=f"%(prog)s {__version__}",
157
+ help="Show the version number and exit",
158
+ )
159
+
160
+ ######
161
+ group = parser.add_argument_group("Other settings")
162
+
163
+ group.add_argument(
164
+ "--vim",
165
+ action="store_true",
166
+ help="Use VI editing mode in the terminal (default: False)",
167
+ default=False,
168
+ )
169
+ group.add_argument(
170
+ "-v",
171
+ "--verbose",
172
+ action="store_true",
173
+ help="Enable verbose output",
174
+ default=False,
175
+ )
176
+
177
+ group.add_argument(
178
+ "--encoding",
179
+ default="utf-8",
180
+ help="Specify the encoding for input and output (default: utf-8)",
181
+ )
182
+
183
+ group.add_argument(
184
+ "--editor",
185
+ help="Specify which editor to use for the /editor command",
186
+ )
187
+
188
+ group.add_argument(
189
+ "--disable-console-output",
190
+ action=argparse.BooleanOptionalAction,
191
+ default=True,
192
+ help="Disable console output for debugging (default: True)",
193
+ )
194
+
195
+ return parser
File without changes
@@ -0,0 +1,107 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Optional, Any
3
+ import traceback
4
+
5
+ from siada.entrypoint.interaction.config import RunningConfig
6
+ from siada.entrypoint.interaction.turn_models import TurnInput, TurnOutput, TurnType
7
+
8
+
9
+ class RunTurn(ABC):
10
+ """Abstract base class for interaction turns"""
11
+
12
+ def __init__(self, config: RunningConfig, session: Any, slash_commands: Any):
13
+ """Initialize turn with configuration and session
14
+
15
+ Args:
16
+ config: InteractionConfig with execution parameters
17
+ session: Current session instance
18
+ """
19
+ self.config = config
20
+ self.session = session
21
+ self.slash_commands = slash_commands
22
+
23
+ # Data tracking
24
+ self.input_data: Optional[TurnInput] = None
25
+ self.output_data: Optional[TurnOutput] = None
26
+ self.start_time: Optional[float] = None
27
+ self.end_time: Optional[float] = None
28
+ self.error: Optional[Exception] = None
29
+
30
+ @abstractmethod
31
+ def execute(self, turn_input: TurnInput) -> TurnOutput:
32
+ """Execute the turn with given input
33
+
34
+ Args:
35
+ turn_input: Input data for this turn
36
+
37
+ Returns:
38
+ TurnOutput: Result of turn execution
39
+ """
40
+ pass
41
+
42
+ def can_handle(self, user_input: str) -> bool:
43
+ """Check if this turn type can handle the given input
44
+
45
+ Args:
46
+ user_input: Raw user input string
47
+
48
+ Returns:
49
+ bool: True if this turn can handle the input
50
+ """
51
+ return True
52
+
53
+ def prepare_input(self, raw_input: str) -> TurnInput:
54
+ """Prepare turn input from raw user input
55
+
56
+ Args:
57
+ raw_input: Raw user input string
58
+
59
+ Returns:
60
+ TurnInput: Prepared input for turn execution
61
+ """
62
+ return TurnInput(use_input=raw_input)
63
+
64
+ def get_turn_type(self) -> TurnType:
65
+ """Get the type of this turn
66
+
67
+ Returns:
68
+ TurnType: Type of this turn
69
+ """
70
+ return TurnType.CONVERSATION
71
+
72
+ def validate_input(self, turn_input: TurnInput) -> bool:
73
+ """Validate turn input
74
+
75
+ Args:
76
+ turn_input: Input to validate
77
+
78
+ Returns:
79
+ bool: True if input is valid
80
+ """
81
+ return bool(turn_input.use_input and turn_input.use_input.strip())
82
+
83
+ def handle_error(self, error: Exception) -> TurnOutput:
84
+ """Handle execution error
85
+
86
+ Args:
87
+ error: Exception that occurred
88
+
89
+ Returns:
90
+ TurnOutput: Error response
91
+ """
92
+ self.error = error
93
+
94
+ full_traceback = traceback.format_exc()
95
+ self.config.io.print_error(f"Error occurred: {str(error)}\n\nFull traceback:\n{full_traceback}")
96
+
97
+ return TurnOutput(
98
+ output=f"Error: {str(error)}",
99
+ metadata={"error_type": type(error).__name__},
100
+ next_action=None,
101
+ )
102
+
103
+ def _get_timestamp(self) -> float:
104
+ """Get current timestamp"""
105
+ import time
106
+
107
+ return time.time()
@@ -0,0 +1,30 @@
1
+ """
2
+ Configuration classes for interaction module
3
+ """
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Optional
7
+ from rlcompleter import Completer
8
+
9
+ from siada.io.color_settings import RunningConfigColorSettings
10
+ from siada.io.io import InputOutput
11
+ from siada.models.model_run_config import ModelRunConfig
12
+
13
+
14
+ @dataclass
15
+ class RunningConfig:
16
+ """Configuration data class for interaction controller"""
17
+
18
+ # Required fields (no default values)
19
+ llm_config: ModelRunConfig
20
+ io: InputOutput
21
+ workspace: str
22
+ agent_name: str
23
+
24
+ # Optional fields (with default values)
25
+ completer: Optional[Completer] = None
26
+ running_color_settings: Optional[RunningConfigColorSettings] = None
27
+ max_turns: int = 10
28
+ tracing_disabled: bool = False
29
+ console_output: bool = False
30
+ interactive: bool = True