auto-coder 0.1.399__py3-none-any.whl → 1.0.0__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.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/METADATA +1 -1
- {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/RECORD +71 -35
- autocoder/agent/agentic_filter.py +1 -1
- autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +1 -1
- autocoder/auto_coder_runner.py +121 -26
- autocoder/chat_auto_coder.py +81 -22
- autocoder/commands/auto_command.py +1 -1
- autocoder/common/__init__.py +2 -2
- autocoder/common/ac_style_command_parser/parser.py +27 -12
- autocoder/common/auto_coder_lang.py +78 -0
- autocoder/common/command_completer_v2.py +1 -1
- autocoder/common/file_monitor/test_file_monitor.py +307 -0
- autocoder/common/git_utils.py +7 -2
- autocoder/common/pruner/__init__.py +0 -0
- autocoder/common/pruner/agentic_conversation_pruner.py +197 -0
- autocoder/common/pruner/context_pruner.py +574 -0
- autocoder/common/pruner/conversation_pruner.py +132 -0
- autocoder/common/pruner/test_agentic_conversation_pruner.py +342 -0
- autocoder/common/pruner/test_context_pruner.py +546 -0
- autocoder/common/pull_requests/__init__.py +256 -0
- autocoder/common/pull_requests/base_provider.py +191 -0
- autocoder/common/pull_requests/config.py +66 -0
- autocoder/common/pull_requests/example.py +1 -0
- autocoder/common/pull_requests/exceptions.py +46 -0
- autocoder/common/pull_requests/manager.py +201 -0
- autocoder/common/pull_requests/models.py +164 -0
- autocoder/common/pull_requests/providers/__init__.py +23 -0
- autocoder/common/pull_requests/providers/gitcode_provider.py +19 -0
- autocoder/common/pull_requests/providers/gitee_provider.py +20 -0
- autocoder/common/pull_requests/providers/github_provider.py +214 -0
- autocoder/common/pull_requests/providers/gitlab_provider.py +29 -0
- autocoder/common/pull_requests/test_module.py +1 -0
- autocoder/common/pull_requests/utils.py +344 -0
- autocoder/common/tokens/__init__.py +77 -0
- autocoder/common/tokens/counter.py +231 -0
- autocoder/common/tokens/file_detector.py +105 -0
- autocoder/common/tokens/filters.py +111 -0
- autocoder/common/tokens/models.py +28 -0
- autocoder/common/v2/agent/agentic_edit.py +538 -590
- autocoder/common/v2/agent/agentic_edit_tools/__init__.py +8 -1
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_read_tool_resolver.py +40 -0
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +43 -0
- autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py +8 -0
- autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +1 -1
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +1 -1
- autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +33 -88
- autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +8 -8
- autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +118 -0
- autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +324 -0
- autocoder/common/v2/agent/agentic_edit_types.py +47 -4
- autocoder/common/v2/agent/runner/__init__.py +31 -0
- autocoder/common/v2/agent/runner/base_runner.py +106 -0
- autocoder/common/v2/agent/runner/event_runner.py +216 -0
- autocoder/common/v2/agent/runner/sdk_runner.py +40 -0
- autocoder/common/v2/agent/runner/terminal_runner.py +283 -0
- autocoder/common/v2/agent/runner/tool_display.py +191 -0
- autocoder/index/entry.py +1 -1
- autocoder/plugins/token_helper_plugin.py +107 -7
- autocoder/run_context.py +9 -0
- autocoder/sdk/__init__.py +114 -81
- autocoder/sdk/cli/handlers.py +2 -1
- autocoder/sdk/cli/main.py +9 -2
- autocoder/sdk/cli/options.py +4 -3
- autocoder/sdk/core/auto_coder_core.py +7 -152
- autocoder/sdk/core/bridge.py +5 -4
- autocoder/sdk/models/options.py +8 -6
- autocoder/version.py +1 -1
- {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
from typing import List, Dict, Any, Union
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
import byzerllm
|
|
6
|
+
from autocoder.common.printer import Printer
|
|
7
|
+
from autocoder.rag.token_counter import count_tokens
|
|
8
|
+
from loguru import logger
|
|
9
|
+
from autocoder.common import AutoCoderArgs
|
|
10
|
+
from autocoder.common.save_formatted_log import save_formatted_log
|
|
11
|
+
|
|
12
|
+
class AgenticPruneStrategy(BaseModel):
|
|
13
|
+
name: str
|
|
14
|
+
description: str
|
|
15
|
+
config: Dict[str, Any] = {"safe_zone_tokens": 0}
|
|
16
|
+
|
|
17
|
+
class AgenticConversationPruner:
|
|
18
|
+
"""
|
|
19
|
+
Specialized conversation pruner for agentic conversations that cleans up tool outputs.
|
|
20
|
+
|
|
21
|
+
This pruner specifically targets tool result messages (role='user', content contains '<tool_result>')
|
|
22
|
+
and replaces their content with a placeholder message to reduce token usage while maintaining
|
|
23
|
+
conversation flow.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, args: AutoCoderArgs, llm: Union[byzerllm.ByzerLLM, byzerllm.SimpleByzerLLM]):
|
|
27
|
+
self.args = args
|
|
28
|
+
self.llm = llm
|
|
29
|
+
self.printer = Printer()
|
|
30
|
+
self.replacement_message = "This message has been cleared. If you still want to get this information, you can call the tool again to retrieve it."
|
|
31
|
+
|
|
32
|
+
self.strategies = {
|
|
33
|
+
"tool_output_cleanup": AgenticPruneStrategy(
|
|
34
|
+
name="tool_output_cleanup",
|
|
35
|
+
description="Clean up tool output results by replacing content with placeholder messages",
|
|
36
|
+
config={"safe_zone_tokens": self.args.conversation_prune_safe_zone_tokens}
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
def get_available_strategies(self) -> List[Dict[str, Any]]:
|
|
41
|
+
"""Get all available pruning strategies"""
|
|
42
|
+
return [strategy.model_dump() for strategy in self.strategies.values()]
|
|
43
|
+
|
|
44
|
+
def prune_conversations(self, conversations: List[Dict[str, Any]],
|
|
45
|
+
strategy_name: str = "tool_output_cleanup") -> List[Dict[str, Any]]:
|
|
46
|
+
"""
|
|
47
|
+
Prune conversations by cleaning up tool outputs.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
conversations: Original conversation list
|
|
51
|
+
strategy_name: Strategy name
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
Pruned conversation list
|
|
55
|
+
"""
|
|
56
|
+
safe_zone_tokens = self.args.conversation_prune_safe_zone_tokens
|
|
57
|
+
current_tokens = count_tokens(json.dumps(conversations, ensure_ascii=False))
|
|
58
|
+
|
|
59
|
+
if current_tokens <= safe_zone_tokens:
|
|
60
|
+
return conversations
|
|
61
|
+
|
|
62
|
+
strategy = self.strategies.get(strategy_name, self.strategies["tool_output_cleanup"])
|
|
63
|
+
|
|
64
|
+
if strategy.name == "tool_output_cleanup":
|
|
65
|
+
return self._tool_output_cleanup_prune(conversations, strategy.config)
|
|
66
|
+
else:
|
|
67
|
+
logger.warning(f"Unknown strategy: {strategy_name}, using tool_output_cleanup instead")
|
|
68
|
+
return self._tool_output_cleanup_prune(conversations, strategy.config)
|
|
69
|
+
|
|
70
|
+
def _tool_output_cleanup_prune(self, conversations: List[Dict[str, Any]],
|
|
71
|
+
config: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
72
|
+
"""
|
|
73
|
+
Clean up tool outputs by replacing their content with placeholder messages.
|
|
74
|
+
|
|
75
|
+
This method:
|
|
76
|
+
1. Identifies tool result messages (role='user' with '<tool_result' in content)
|
|
77
|
+
2. Starts from the first tool output and progressively cleans them
|
|
78
|
+
3. Stops when token count is within safe zone
|
|
79
|
+
"""
|
|
80
|
+
safe_zone_tokens = config.get("safe_zone_tokens", 50 * 1024)
|
|
81
|
+
processed_conversations = conversations.copy()
|
|
82
|
+
|
|
83
|
+
# Find all tool result message indices
|
|
84
|
+
tool_result_indices = []
|
|
85
|
+
for i, conv in enumerate(processed_conversations):
|
|
86
|
+
if (conv.get("role") == "user" and
|
|
87
|
+
isinstance(conv.get("content"), str) and
|
|
88
|
+
self._is_tool_result_message(conv.get("content", ""))):
|
|
89
|
+
tool_result_indices.append(i)
|
|
90
|
+
|
|
91
|
+
logger.info(f"Found {len(tool_result_indices)} tool result messages to potentially clean")
|
|
92
|
+
|
|
93
|
+
# Clean tool outputs one by one, starting from the first one
|
|
94
|
+
for tool_index in tool_result_indices:
|
|
95
|
+
current_tokens = count_tokens(json.dumps(processed_conversations, ensure_ascii=False))
|
|
96
|
+
|
|
97
|
+
if current_tokens <= safe_zone_tokens:
|
|
98
|
+
logger.info(f"Token count ({current_tokens}) is within safe zone ({safe_zone_tokens}), stopping cleanup")
|
|
99
|
+
break
|
|
100
|
+
|
|
101
|
+
# Extract tool name for a more specific replacement message
|
|
102
|
+
tool_name = self._extract_tool_name(processed_conversations[tool_index]["content"])
|
|
103
|
+
replacement_content = self._generate_replacement_message(tool_name)
|
|
104
|
+
|
|
105
|
+
# Replace the content
|
|
106
|
+
original_content = processed_conversations[tool_index]["content"]
|
|
107
|
+
processed_conversations[tool_index]["content"] = replacement_content
|
|
108
|
+
|
|
109
|
+
logger.info(f"Cleaned tool result at index {tool_index} (tool: {tool_name}), "
|
|
110
|
+
f"reduced from {len(original_content)} to {len(replacement_content)} characters")
|
|
111
|
+
|
|
112
|
+
final_tokens = count_tokens(json.dumps(processed_conversations, ensure_ascii=False))
|
|
113
|
+
logger.info(f"Cleanup completed. Token count: {current_tokens} -> {final_tokens}")
|
|
114
|
+
|
|
115
|
+
save_formatted_log(self.args.source_dir, json.dumps(conversations, ensure_ascii=False), "agentic_pruned_conversation")
|
|
116
|
+
|
|
117
|
+
return processed_conversations
|
|
118
|
+
|
|
119
|
+
def _is_tool_result_message(self, content: str) -> bool:
|
|
120
|
+
"""
|
|
121
|
+
Check if a message content contains tool result XML.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
content: Message content to check
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
True if content contains tool result format
|
|
128
|
+
"""
|
|
129
|
+
return "<tool_result" in content and "tool_name=" in content
|
|
130
|
+
|
|
131
|
+
def _extract_tool_name(self, content: str) -> str:
|
|
132
|
+
"""
|
|
133
|
+
Extract tool name from tool result XML content.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
content: Tool result XML content
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Tool name or 'unknown' if not found
|
|
140
|
+
"""
|
|
141
|
+
# Pattern to match: <tool_result tool_name='...' or <tool_result tool_name="..."
|
|
142
|
+
pattern = r"<tool_result[^>]*tool_name=['\"]([^'\"]+)['\"]"
|
|
143
|
+
match = re.search(pattern, content)
|
|
144
|
+
|
|
145
|
+
if match:
|
|
146
|
+
return match.group(1)
|
|
147
|
+
return "unknown"
|
|
148
|
+
|
|
149
|
+
def _generate_replacement_message(self, tool_name: str) -> str:
|
|
150
|
+
"""
|
|
151
|
+
Generate a replacement message for a cleaned tool result.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
tool_name: Name of the tool that was called
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
Replacement message string
|
|
158
|
+
"""
|
|
159
|
+
if tool_name and tool_name != "unknown":
|
|
160
|
+
return (f"<tool_result tool_name='{tool_name}' success='true'>"
|
|
161
|
+
f"<message>Content cleared to save tokens</message>"
|
|
162
|
+
f"<content>{self.replacement_message}</content>"
|
|
163
|
+
f"</tool_result>")
|
|
164
|
+
else:
|
|
165
|
+
return f"<tool_result success='true'><message>[Content cleared to save tokens, you can call the tool again to get the tool result.]</message><content>{self.replacement_message}</content></tool_result>"
|
|
166
|
+
|
|
167
|
+
def get_cleanup_statistics(self, original_conversations: List[Dict[str, Any]],
|
|
168
|
+
pruned_conversations: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
169
|
+
"""
|
|
170
|
+
Get statistics about the cleanup process.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
original_conversations: Original conversation list
|
|
174
|
+
pruned_conversations: Pruned conversation list
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Dictionary with cleanup statistics
|
|
178
|
+
"""
|
|
179
|
+
original_tokens = count_tokens(json.dumps(original_conversations, ensure_ascii=False))
|
|
180
|
+
pruned_tokens = count_tokens(json.dumps(pruned_conversations, ensure_ascii=False))
|
|
181
|
+
|
|
182
|
+
# Count cleaned tool results
|
|
183
|
+
cleaned_count = 0
|
|
184
|
+
for orig, pruned in zip(original_conversations, pruned_conversations):
|
|
185
|
+
if (orig.get("role") == "user" and
|
|
186
|
+
self._is_tool_result_message(orig.get("content", "")) and
|
|
187
|
+
orig.get("content") != pruned.get("content")):
|
|
188
|
+
cleaned_count += 1
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
"original_tokens": original_tokens,
|
|
192
|
+
"pruned_tokens": pruned_tokens,
|
|
193
|
+
"tokens_saved": original_tokens - pruned_tokens,
|
|
194
|
+
"compression_ratio": pruned_tokens / original_tokens if original_tokens > 0 else 1.0,
|
|
195
|
+
"tool_results_cleaned": cleaned_count,
|
|
196
|
+
"total_messages": len(original_conversations)
|
|
197
|
+
}
|