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,44 @@
1
+ EDIT_DOCS= """Custom editing tool for viewing, creating and editing files in plain-text format
2
+ * State is persistent across command calls and discussions with the user
3
+ * If `path` is a text file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep
4
+ * The following binary file extensions can be viewed in Markdown format: [".xlsx", ".pptx", ".wav", ".mp3", ".m4a", ".flac", ".pdf", ".docx"]. IT DOES NOT HANDLE IMAGES.
5
+ * The `create` command cannot be used if the specified `path` already exists as a file
6
+ * If a `command` generates a long output, it will be truncated and marked with `<response clipped>`
7
+ * The `undo_edit` command will revert the last edit made to the file at `path`
8
+ * This tool can be used for creating and editing files in plain-text format.
9
+
10
+
11
+ Before using this tool:
12
+ 1. Use the view tool to understand the file's contents and context
13
+ 2. Verify the directory path is correct (only applicable when creating new files):
14
+ - Use the view tool to verify the parent directory exists and is the correct location
15
+
16
+ When making edits:
17
+ - Ensure the edit results in idiomatic, correct code
18
+ - Do not leave the code in a broken state
19
+ - Always use absolute file paths (starting with /)
20
+
21
+ CRITICAL REQUIREMENTS FOR USING THIS TOOL:
22
+
23
+ 1. EXACT MATCHING: The `old_str` parameter must match EXACTLY one or more consecutive lines from the file, including all whitespace and indentation. The tool will fail if `old_str` matches multiple locations or doesn't match exactly with the file content.
24
+
25
+ 2. UNIQUENESS: The `old_str` must uniquely identify a single instance in the file:
26
+ - Include sufficient context before and after the change point (3-5 lines recommended)
27
+ - If not unique, the replacement will not be performed
28
+
29
+ 3. REPLACEMENT: The `new_str` parameter should contain the edited lines that replace the `old_str`. Both strings must be different.
30
+
31
+ Remember: when making multiple file edits in a row to the same file, you should prefer to send all edits in a single message with multiple calls to this tool, rather than multiple messages with a single call each.
32
+
33
+ Args:
34
+ command: The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`.
35
+ path: Absolute path to file or directory, e.g. `/workspace/file.py` or `/workspace`.
36
+ file_text: Required parameter of `create` command, with the content of the file to be created.
37
+ old_str: Required parameter of `str_replace` command containing the string in `path` to replace.
38
+ new_str: Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert.
39
+ insert_line: Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`.
40
+ view_range: Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.
41
+
42
+
43
+
44
+ """
@@ -0,0 +1,200 @@
1
+ """
2
+ Context Compression Tool - Intelligently compresses conversation history using a model.
3
+ """
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ from typing import Any
8
+
9
+ from agents import RunContextWrapper, function_tool
10
+ from agents.items import TResponseInputItem
11
+ from openai.types.chat import ChatCompletionMessageParam
12
+ from siada.foundation.code_agent_context import CodeAgentContext
13
+ from siada.foundation.config import settings
14
+ from siada.provider.client_factory import get_client_with_kwargs
15
+ COMPRESS_DOCS = """Intelligently compress or summarize the conversation history within a specified range.
16
+
17
+ This tool should be called when the following situations occur:
18
+ 1. The conversation history is too long and needs to be partially archived.
19
+ 2. A task or topic has concluded, and the relevant conversation can be compressed.
20
+ 3. Some messages are no longer important for resolving the current main task and need to be cleared.
21
+ 4. The current conversation has deviated from the original topic and needs to be refocused.
22
+ 5. The message list contains a lot of redundant information, which reduces the efficiency of accessing important content.
23
+ 6. If the test required multiple steps to complete — or was not completed — you need to summarize the testing process.
24
+ 7. If the search involved multiple steps — or returned too many results — you need to summarize the search process.
25
+ ===
26
+
27
+ After summarizing, you must provide a recommendation for the next step.
28
+
29
+ Args:
30
+ reason: The reason why context compression is needed (required).
31
+ start_index: The starting index of the compression range (inclusive).
32
+ end_index: The ending index of the compression range (exclusive).
33
+
34
+ Returns:
35
+ A dictionary containing:
36
+ - status (int): 1 for success, 0 for failure.
37
+ - start_index (int): The starting index of the compression.
38
+ - end_index (int): The ending index of the compression.
39
+ - summary (str): The compression summary or error/status information.
40
+
41
+ Example Usage:
42
+
43
+ Original conversation history (messages 1-6):
44
+ [1] assistant: Search for files containing "config" keyword to find configuration files.
45
+ [2] tool: {"status": "success", "results": ["config.py", "app_config.py", "db_config.py", "test_config.py", "config.yaml", "nginx.conf", "docker-compose.yml"], "total": 47}
46
+ [3] assistant: Too many results. Search for "database config" specifically.
47
+ [4] tool: {"status": "success", "results": ["db_config.py", "database.conf", "config/db.yaml", "tests/db_config_test.py", "migrations/config.py"], "total": 23}
48
+ [5] assistant: Still too broad. Search for "database connection" in Python files only.
49
+ [6] tool: {"status": "success", "results": ["db_config.py", "models/base.py", "utils/db_helper.py", "services/db_service.py"], "total": 18}
50
+ [7] assistant: The search results are still not specific enough. Let me try a different approach.
51
+ [8] tool: {"status": "success", "message": "Search strategy needs refinement - too many generic matches"}
52
+
53
+ Compression call:
54
+ compress_context_tool(
55
+ reason="Search attempts yielded too many results, need to restart with better strategy",
56
+ start_index=1,
57
+ end_index=7,
58
+ )
59
+
60
+ Compressed result:
61
+ {
62
+ "status": 1,
63
+ "start_index": 1,
64
+ "end_index": 7,
65
+ "summary": "[Smart Compression Summary]\nReason for compression: Search attempts yielded too many results, need to restart with better strategy\nMultiple search attempts for configuration files returned excessive results (47, 23, 18 matches respectively), indicating search terms were too broad and strategy needs refinement."
66
+ }
67
+ """
68
+
69
+ @function_tool(
70
+ name_override="compress_context_tool", description_override=COMPRESS_DOCS, failure_error_function=None
71
+ )
72
+ async def compress_context_tool(
73
+ context: RunContextWrapper[CodeAgentContext],
74
+ reason: str,
75
+ start_index: int,
76
+ end_index: int,
77
+ ) -> dict[str, Any]:
78
+
79
+ return await _compress_context_tool(
80
+ context=context,
81
+ reason=reason,
82
+ start_index=start_index,
83
+ end_index=end_index
84
+ )
85
+
86
+ async def _compress_messages_with_model(messages: list[TResponseInputItem], reason: str, context: RunContextWrapper[CodeAgentContext]) -> str:
87
+
88
+
89
+ # Format messages
90
+ formatted_messages_content = []
91
+ for msg in messages:
92
+ role = msg.get("role", "unknown")
93
+ content_text = msg.get("content", "")
94
+ formatted_messages_content.append(f"{role}: {content_text}")
95
+
96
+ conversation_text = "\n".join(formatted_messages_content)
97
+
98
+ # Build the system prompt to guide the model for a high-quality summary
99
+ system_prompt = f"""You are a professional conversation summarization assistant. Your task is to generate a concise, accurate, and fluent English summary based on the provided conversation history.
100
+
101
+ The summary must meet the following requirements:
102
+ 1. **Preserve Core Information**: Accurately capture the key topics, important decisions, and critical information of the conversation.
103
+ 2. **Reflect Context**: The summary should clearly reflect the context and flow of the conversation, facilitating a seamless continuation.
104
+ 3. **State the Reason for Compression**: Clearly state the reason for this compression at the beginning of the summary: "{reason}".
105
+ 4. **Concise Language**: Use refined language, avoiding redundancy and unnecessary information.
106
+ 5. **Clear Format**: The summary should start with "[Smart Compression Summary]".
107
+
108
+ Please generate a summary based on the following conversation history:
109
+ ---
110
+ {conversation_text}
111
+ ---
112
+ """
113
+
114
+ # Construct the request to be sent to the model
115
+ model_messages: list[ChatCompletionMessageParam] = [
116
+ {"role": "system", "content": system_prompt},
117
+ {"role": "user", "content": "Please generate a summary based on the above conversation history and requirements."}
118
+ ]
119
+
120
+ # Call the model for a non-streaming request
121
+ default_kwargs = {
122
+ "model": settings.Claude_4_0_SONNET,
123
+ "messages": model_messages,
124
+ "stream": False,
125
+ "temperature": 0.2, # Lower temperature to ensure the determinism and accuracy of the summary
126
+ }
127
+
128
+ # Use get_client_with_kwargs to support context parameter overrides
129
+ client, complete_kwargs = get_client_with_kwargs(context.context, default_kwargs)
130
+ response = await client.chat_complete(**complete_kwargs)
131
+
132
+ # Extract the summary content from the response
133
+ if response and response.choices and response.choices[0].message:
134
+ summary = response.choices[0].message.content
135
+ if summary:
136
+ return summary.strip()
137
+
138
+ # If a valid summary cannot be obtained, return a default error message
139
+ return f"[Smart Compression Summary]\nReason for compression: {reason}\nSummary generation failed: Unable to retrieve valid summary content from the model."
140
+
141
+
142
+ def _create_failure_response(start_index: int, end_index: int, summary: str) -> dict[str, Any]:
143
+ """Creates a response dictionary indicating failure."""
144
+ return {
145
+ "status": 0,
146
+ "start_index": start_index,
147
+ "end_index": end_index,
148
+ "summary": summary
149
+ }
150
+
151
+
152
+ async def _compress_context_tool(
153
+ context: RunContextWrapper[CodeAgentContext],
154
+ reason: str,
155
+ start_index: int,
156
+ end_index: int,
157
+ ) -> dict[str, Any]:
158
+ if not context.context:
159
+ return _create_failure_response(start_index, end_index, "Error: Unable to get context information")
160
+
161
+ conversation_history = context.context.message_history
162
+ total_messages = len(conversation_history)
163
+
164
+ original_start_index = start_index
165
+ original_end_index = end_index
166
+
167
+ # --- Input Validation ---
168
+ if start_index < 0 or end_index > total_messages or start_index >= end_index:
169
+ summary = f"Error: Invalid compression range. Valid range: 0 <= start < end <= {total_messages}"
170
+ return _create_failure_response(original_start_index, original_end_index, summary)
171
+
172
+ # As per user requirements, never compress the first message
173
+ if start_index == 0:
174
+ start_index = 1 # Force start from index 1
175
+ if start_index >= end_index:
176
+ summary = "No compression needed: The specified range only contains or is invalid after the first message."
177
+ return _create_failure_response(original_start_index, original_end_index, summary)
178
+
179
+ messages_to_compress = conversation_history[start_index:end_index]
180
+ messages_to_compress_count = len(messages_to_compress)
181
+
182
+ if messages_to_compress_count == 0:
183
+ summary = f"No compression needed: No messages within the range {start_index}-{end_index}."
184
+ return _create_failure_response(start_index, end_index, summary)
185
+
186
+ # --- Compress using the model ---
187
+ try:
188
+ compression_summary = await _compress_messages_with_model(messages_to_compress, reason)
189
+ except Exception as e:
190
+ return _create_failure_response(start_index, end_index, f"Error: Model compression failed - {str(e)}")
191
+
192
+ # As per user requirements, this tool is only responsible for generating a summary and does not modify message_history
193
+ # The actual replacement operation will be completed by other tools
194
+
195
+ return {
196
+ "status": 1,
197
+ "start_index": start_index,
198
+ "end_index": end_index,
199
+ "summary": compression_summary
200
+ }
@@ -0,0 +1,220 @@
1
+ # ReadManyFiles Tool
2
+
3
+ A powerful tool for batch reading multiple files with intelligent filtering and support for various file types.
4
+
5
+ ## Features
6
+
7
+ - **Batch File Reading**: Read multiple files using glob patterns
8
+ - **Intelligent Filtering**: Built-in support for .gitignore rules and default exclusion patterns
9
+ - **Multiple File Types**: Support for text files, images, and PDFs
10
+ - **Async Processing**: Concurrent file processing for better performance
11
+ - **Security**: Path validation to ensure files are within workspace
12
+ - **Detailed Reporting**: Comprehensive statistics and error reporting
13
+
14
+ ## Quick Start
15
+
16
+ ### Basic Usage
17
+
18
+ ```python
19
+ import asyncio
20
+ from siada.tools.read_many_files_tool import read_files_by_patterns
21
+
22
+ async def main():
23
+ # Read all Python files in current directory
24
+ result = await read_files_by_patterns(
25
+ paths=["*.py"],
26
+ target_dir="."
27
+ )
28
+
29
+ print(f"Found {len(result.llmContent)} files")
30
+ print(result.returnDisplay)
31
+
32
+ asyncio.run(main())
33
+ ```
34
+
35
+ ### Advanced Usage
36
+
37
+ ```python
38
+ from siada.tools.read_many_files_tool import ReadManyFilesTool
39
+ from siada.tools.read_many_files.models import ReadManyFilesParams
40
+
41
+ async def advanced_example():
42
+ # Create tool instance
43
+ tool = ReadManyFilesTool("/path/to/project")
44
+
45
+ # Configure parameters
46
+ params = ReadManyFilesParams(
47
+ paths=["src/**/*.py", "docs/*.md"],
48
+ include=["*.test.py"],
49
+ exclude=["**/node_modules/**", "**/__pycache__/**"],
50
+ useDefaultExcludes=True,
51
+ file_filtering_options={
52
+ 'respect_git_ignore': True
53
+ }
54
+ )
55
+
56
+ # Execute
57
+ result = await tool.execute(params)
58
+
59
+ # Process results
60
+ for content in result.llmContent:
61
+ if isinstance(content, str):
62
+ print("Text file content:", content[:100] + "...")
63
+ else:
64
+ print("Binary file:", content.get('type', 'unknown'))
65
+ ```
66
+
67
+ ## Parameters
68
+
69
+ ### ReadManyFilesParams
70
+
71
+ - **paths** (List[str], required): File paths or glob patterns
72
+ - **include** (List[str], optional): Additional include patterns
73
+ - **exclude** (List[str], optional): Exclude patterns
74
+ - **recursive** (bool, default=True): Whether to search recursively
75
+ - **useDefaultExcludes** (bool, default=True): Apply default exclusion patterns
76
+ - **file_filtering_options** (Dict[str, bool], optional): Filtering configuration
77
+
78
+ ### Glob Patterns
79
+
80
+ The tool supports standard glob patterns:
81
+
82
+ - `*.py` - All Python files in current directory
83
+ - `**/*.py` - All Python files recursively
84
+ - `src/**/*.js` - All JavaScript files in src directory and subdirectories
85
+ - `docs/*.md` - All Markdown files in docs directory
86
+
87
+ ## File Type Support
88
+
89
+ ### Text Files
90
+
91
+ Supported extensions: `.py`, `.js`, `.ts`, `.md`, `.txt`, `.json`, `.yaml`, `.xml`, `.html`, `.css`, and many more.
92
+
93
+ Text files are read with automatic encoding detection and include content truncation for large files.
94
+
95
+ ### Image Files
96
+
97
+ Supported extensions: `.png`, `.jpg`, `.jpeg`, `.gif`, `.bmp`, `.webp`, `.svg`
98
+
99
+ Images are converted to base64-encoded Part objects for LLM processing. Must be explicitly requested by filename or extension.
100
+
101
+ ### PDF Files
102
+
103
+ Supported extension: `.pdf`
104
+
105
+ PDFs are converted to Part objects for LLM processing. Must be explicitly requested by filename.
106
+
107
+ ## Filtering
108
+
109
+ ### Default Excludes
110
+
111
+ The tool automatically excludes common non-source files:
112
+
113
+ - Dependency directories: `node_modules`, `__pycache__`, `venv`
114
+ - Version control: `.git`, `.svn`
115
+ - IDE files: `.vscode`, `.idea`
116
+ - Build outputs: `dist`, `build`, `target`
117
+ - Binary files: `.exe`, `.dll`, `.so`
118
+ - Compressed files: `.zip`, `.tar`, `.gz`
119
+
120
+ ### Git Ignore Support
121
+
122
+ The tool respects `.gitignore` files by default. This can be disabled by setting:
123
+
124
+ ```python
125
+ file_filtering_options={'respect_git_ignore': False}
126
+ ```
127
+
128
+ ## Output Format
129
+
130
+ ### ToolResult
131
+
132
+ The tool returns a `ToolResult` object with:
133
+
134
+ - **llmContent**: List of file contents (strings for text, Part objects for binary)
135
+ - **returnDisplay**: Human-readable summary with statistics
136
+
137
+ ### Text File Format
138
+
139
+ Text files are formatted with separators:
140
+
141
+ ```
142
+ --- /path/to/file.py ---
143
+
144
+ def hello():
145
+ print("Hello, World!")
146
+
147
+ ```
148
+
149
+ ## Error Handling
150
+
151
+ The tool gracefully handles various error conditions:
152
+
153
+ - File not found
154
+ - Permission denied
155
+ - Encoding errors
156
+ - Large files (automatic truncation)
157
+ - Binary files (skipped unless explicitly requested)
158
+
159
+ ## Performance
160
+
161
+ - **Concurrent Processing**: Files are processed concurrently with configurable limits
162
+ - **Memory Efficient**: Large files are truncated to prevent memory issues
163
+ - **Caching**: Git ignore rules are cached for better performance
164
+
165
+ ## Examples
166
+
167
+ ### Read Configuration Files
168
+
169
+ ```python
170
+ result = await read_files_by_patterns(
171
+ paths=["*.json", "*.yaml", "*.toml"],
172
+ target_dir="/path/to/config"
173
+ )
174
+ ```
175
+
176
+ ### Read Source Code (Excluding Tests)
177
+
178
+ ```python
179
+ result = await read_files_by_patterns(
180
+ paths=["src/**/*.py"],
181
+ exclude=["**/test_*.py", "**/tests/**"],
182
+ target_dir="/path/to/project"
183
+ )
184
+ ```
185
+
186
+ ### Read Documentation
187
+
188
+ ```python
189
+ result = await read_files_by_patterns(
190
+ paths=["docs/**/*.md", "README.md"],
191
+ target_dir="/path/to/project"
192
+ )
193
+ ```
194
+
195
+ ### Read Images (Explicit Request)
196
+
197
+ ```python
198
+ result = await read_files_by_patterns(
199
+ paths=["assets/*.png", "images/*.jpg"],
200
+ target_dir="/path/to/project"
201
+ )
202
+ ```
203
+
204
+ ## Testing
205
+
206
+ Run the test suite:
207
+
208
+ ```bash
209
+ pytest tests/tools/test_read_many_files_tool.py -v
210
+ ```
211
+
212
+ Run specific tests:
213
+
214
+ ```bash
215
+ pytest tests/tools/test_read_many_files_tool.py::TestReadManyFilesTool::test_execute_success -v
216
+ ```
217
+
218
+ ## License
219
+
220
+ This tool is part of the siada-agenthub project.
@@ -0,0 +1,25 @@
1
+ """
2
+ ReadManyFiles tool package.
3
+ """
4
+
5
+ from .models import (
6
+ ReadManyFilesParams,
7
+ ToolResult,
8
+ FileProcessResult,
9
+ ProcessingStats,
10
+ DEFAULT_EXCLUDES,
11
+ TEXT_FILE_EXTENSIONS,
12
+ IMAGE_FILE_EXTENSIONS,
13
+ PDF_FILE_EXTENSIONS,
14
+ )
15
+
16
+ __all__ = [
17
+ "ReadManyFilesParams",
18
+ "ToolResult",
19
+ "FileProcessResult",
20
+ "ProcessingStats",
21
+ "DEFAULT_EXCLUDES",
22
+ "TEXT_FILE_EXTENSIONS",
23
+ "IMAGE_FILE_EXTENSIONS",
24
+ "PDF_FILE_EXTENSIONS",
25
+ ]