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,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
|
+
]
|