auto-coder 0.1.398__py3-none-any.whl → 0.1.400__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.400.dist-info/METADATA +396 -0
- {auto_coder-0.1.398.dist-info → auto_coder-0.1.400.dist-info}/RECORD +82 -29
- {auto_coder-0.1.398.dist-info → auto_coder-0.1.400.dist-info}/WHEEL +1 -1
- {auto_coder-0.1.398.dist-info → auto_coder-0.1.400.dist-info}/entry_points.txt +2 -0
- autocoder/agent/base_agentic/base_agent.py +2 -2
- autocoder/agent/base_agentic/tools/replace_in_file_tool_resolver.py +1 -1
- autocoder/agent/entry_command_agent/__init__.py +29 -0
- autocoder/agent/entry_command_agent/auto_tool.py +61 -0
- autocoder/agent/entry_command_agent/chat.py +475 -0
- autocoder/agent/entry_command_agent/designer.py +53 -0
- autocoder/agent/entry_command_agent/generate_command.py +50 -0
- autocoder/agent/entry_command_agent/project_reader.py +58 -0
- autocoder/agent/entry_command_agent/voice2text.py +71 -0
- autocoder/auto_coder.py +23 -548
- autocoder/auto_coder_runner.py +511 -8
- autocoder/chat/rules_command.py +1 -1
- autocoder/chat_auto_coder.py +6 -1
- autocoder/common/ac_style_command_parser/__init__.py +15 -0
- autocoder/common/ac_style_command_parser/example.py +7 -0
- autocoder/{command_parser.py → common/ac_style_command_parser/parser.py} +28 -45
- autocoder/common/ac_style_command_parser/test_parser.py +516 -0
- autocoder/common/auto_coder_lang.py +78 -0
- autocoder/common/command_completer_v2.py +1 -1
- autocoder/common/command_file_manager/examples.py +22 -8
- autocoder/common/command_file_manager/manager.py +37 -6
- autocoder/common/conversations/get_conversation_manager.py +143 -0
- autocoder/common/conversations/manager.py +122 -11
- autocoder/common/conversations/storage/index_manager.py +89 -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 +62 -0
- autocoder/common/tokens/counter.py +211 -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 +312 -85
- autocoder/common/v2/agent/agentic_edit_types.py +11 -0
- autocoder/common/v2/code_auto_generate_editblock.py +10 -2
- autocoder/dispacher/__init__.py +10 -0
- autocoder/rags.py +0 -27
- autocoder/run_context.py +1 -0
- autocoder/sdk/__init__.py +188 -0
- autocoder/sdk/cli/__init__.py +15 -0
- autocoder/sdk/cli/__main__.py +26 -0
- autocoder/sdk/cli/completion_wrapper.py +38 -0
- autocoder/sdk/cli/formatters.py +211 -0
- autocoder/sdk/cli/handlers.py +175 -0
- autocoder/sdk/cli/install_completion.py +301 -0
- autocoder/sdk/cli/main.py +286 -0
- autocoder/sdk/cli/options.py +73 -0
- autocoder/sdk/constants.py +102 -0
- autocoder/sdk/core/__init__.py +20 -0
- autocoder/sdk/core/auto_coder_core.py +880 -0
- autocoder/sdk/core/bridge.py +500 -0
- autocoder/sdk/example.py +0 -0
- autocoder/sdk/exceptions.py +72 -0
- autocoder/sdk/models/__init__.py +19 -0
- autocoder/sdk/models/messages.py +209 -0
- autocoder/sdk/models/options.py +196 -0
- autocoder/sdk/models/responses.py +311 -0
- autocoder/sdk/session/__init__.py +32 -0
- autocoder/sdk/session/session.py +106 -0
- autocoder/sdk/session/session_manager.py +56 -0
- autocoder/sdk/utils/__init__.py +24 -0
- autocoder/sdk/utils/formatters.py +216 -0
- autocoder/sdk/utils/io_utils.py +302 -0
- autocoder/sdk/utils/validators.py +287 -0
- autocoder/version.py +2 -1
- auto_coder-0.1.398.dist-info/METADATA +0 -111
- autocoder/common/conversations/compatibility.py +0 -303
- autocoder/common/conversations/conversation_manager.py +0 -502
- autocoder/common/conversations/example.py +0 -152
- {auto_coder-0.1.398.dist-info → auto_coder-0.1.400.dist-info/licenses}/LICENSE +0 -0
- {auto_coder-0.1.398.dist-info → auto_coder-0.1.400.dist-info}/top_level.txt +0 -0
|
@@ -79,10 +79,12 @@ from autocoder.common.v2.agent.agentic_edit_types import (AgenticEditRequest, To
|
|
|
79
79
|
LLMOutputEvent, LLMThinkingEvent, ToolCallEvent,
|
|
80
80
|
ToolResultEvent, CompletionEvent, PlanModeRespondEvent, ErrorEvent, TokenUsageEvent,
|
|
81
81
|
WindowLengthChangeEvent,
|
|
82
|
+
ConversationIdEvent,
|
|
82
83
|
# Import specific tool types for display mapping
|
|
83
84
|
ReadFileTool, WriteToFileTool, ReplaceInFileTool, ExecuteCommandTool,
|
|
84
85
|
ListFilesTool, SearchFilesTool, ListCodeDefinitionNamesTool,
|
|
85
|
-
AskFollowupQuestionTool, UseMcpTool, AttemptCompletionTool
|
|
86
|
+
AskFollowupQuestionTool, UseMcpTool, AttemptCompletionTool,
|
|
87
|
+
AgenticEditConversationConfig
|
|
86
88
|
)
|
|
87
89
|
from autocoder.common.rag_manager import RAGManager
|
|
88
90
|
from autocoder.rag.token_counter import count_tokens
|
|
@@ -103,6 +105,14 @@ TOOL_RESOLVER_MAP: Dict[Type[BaseTool], Type[BaseToolResolver]] = {
|
|
|
103
105
|
UseMcpTool: UseMcpToolResolver,
|
|
104
106
|
UseRAGTool: UseRAGToolResolver
|
|
105
107
|
}
|
|
108
|
+
from autocoder.common.conversations.get_conversation_manager import (
|
|
109
|
+
get_conversation_manager,
|
|
110
|
+
get_conversation_manager_config,
|
|
111
|
+
reset_conversation_manager
|
|
112
|
+
)
|
|
113
|
+
from autocoder.common.conversations import ConversationManagerConfig
|
|
114
|
+
from autocoder.common.pull_requests import create_pull_request, detect_platform_from_repo
|
|
115
|
+
from autocoder.common.auto_coder_lang import get_message, get_message_with_format
|
|
106
116
|
|
|
107
117
|
|
|
108
118
|
# --- Tool Display Customization is now handled by agentic_tool_display.py ---
|
|
@@ -117,7 +127,8 @@ class AgenticEdit:
|
|
|
117
127
|
args: AutoCoderArgs,
|
|
118
128
|
memory_config: MemoryConfig,
|
|
119
129
|
command_config: Optional[CommandConfig] = None,
|
|
120
|
-
conversation_name:Optional[str] = "current"
|
|
130
|
+
conversation_name:Optional[str] = "current",
|
|
131
|
+
conversation_config:Optional[AgenticEditConversationConfig] = None
|
|
121
132
|
):
|
|
122
133
|
self.llm = llm
|
|
123
134
|
self.context_prune_llm = get_single_llm(args.context_prune_model or args.model,product_mode=args.product_mode)
|
|
@@ -127,7 +138,7 @@ class AgenticEdit:
|
|
|
127
138
|
self.files = files
|
|
128
139
|
# Removed self.max_iterations
|
|
129
140
|
# Note: This might need updating based on the new flow
|
|
130
|
-
self.conversation_history = conversation_history
|
|
141
|
+
self.conversation_history = conversation_history
|
|
131
142
|
|
|
132
143
|
self.current_conversations = []
|
|
133
144
|
self.memory_config = memory_config
|
|
@@ -183,6 +194,19 @@ class AgenticEdit:
|
|
|
183
194
|
# 格式: { file_path: FileChangeEntry(...) }
|
|
184
195
|
self.file_changes: Dict[str, FileChangeEntry] = {}
|
|
185
196
|
|
|
197
|
+
# 对话管理器
|
|
198
|
+
self.conversation_config =conversation_config
|
|
199
|
+
self.conversation_manager = get_conversation_manager()
|
|
200
|
+
|
|
201
|
+
if self.conversation_config.action == "new":
|
|
202
|
+
conversation_id = self.conversation_manager.create_conversation(name=self.conversation_config.query or "New Conversation",
|
|
203
|
+
description=self.conversation_config.query or "New Conversation")
|
|
204
|
+
self.conversation_manager.set_current_conversation(conversation_id)
|
|
205
|
+
|
|
206
|
+
if self.conversation_config.action == "resume" and self.conversation_config.conversation_id:
|
|
207
|
+
self.conversation_manager.set_current_conversation(self.conversation_config.conversation_id)
|
|
208
|
+
|
|
209
|
+
|
|
186
210
|
@byzerllm.prompt()
|
|
187
211
|
def generate_library_docs_prompt(self, libraries_with_paths: List[Dict[str, str]], docs_content: str) -> Dict[str, Any]:
|
|
188
212
|
"""
|
|
@@ -419,7 +443,7 @@ class AgenticEdit:
|
|
|
419
443
|
<list_code_definition_names>
|
|
420
444
|
<path>Directory path here</path>
|
|
421
445
|
</list_code_definition_names>
|
|
422
|
-
|
|
446
|
+
|
|
423
447
|
## ask_followup_question
|
|
424
448
|
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
|
|
425
449
|
Parameters:
|
|
@@ -431,7 +455,7 @@ class AgenticEdit:
|
|
|
431
455
|
<options>
|
|
432
456
|
Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]
|
|
433
457
|
</options>
|
|
434
|
-
</ask_followup_question>
|
|
458
|
+
</ask_followup_question>
|
|
435
459
|
|
|
436
460
|
## attempt_completion
|
|
437
461
|
Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
|
|
@@ -1028,7 +1052,7 @@ class AgenticEdit:
|
|
|
1028
1052
|
{% endfor %}
|
|
1029
1053
|
</user_rule_or_document_files>
|
|
1030
1054
|
|
|
1031
|
-
|
|
1055
|
+
You should decide based on the user's requirements whether to use the read_file tool to get the relevant files listed in index.md.
|
|
1032
1056
|
{% endif %}
|
|
1033
1057
|
|
|
1034
1058
|
|
|
@@ -1096,6 +1120,7 @@ class AgenticEdit:
|
|
|
1096
1120
|
"enable_active_context_in_generate": self.args.enable_active_context_in_generate,
|
|
1097
1121
|
"extra_docs": extra_docs,
|
|
1098
1122
|
"file_paths_str": file_paths_str,
|
|
1123
|
+
"agentic_auto_approve": self.args.enable_agentic_auto_approve,
|
|
1099
1124
|
}
|
|
1100
1125
|
|
|
1101
1126
|
# Removed _execute_command_result and execute_auto_command methods
|
|
@@ -1144,7 +1169,7 @@ class AgenticEdit:
|
|
|
1144
1169
|
"""
|
|
1145
1170
|
Analyzes the user request, interacts with the LLM, parses responses,
|
|
1146
1171
|
executes tools, and yields structured events for visualization until completion or error.
|
|
1147
|
-
"""
|
|
1172
|
+
"""
|
|
1148
1173
|
logger.info(f"Starting analyze method with user input: {request.user_input[:50]}...")
|
|
1149
1174
|
system_prompt = self._analyze.prompt(request)
|
|
1150
1175
|
logger.info(f"Generated system prompt with length: {len(system_prompt)}")
|
|
@@ -1154,7 +1179,7 @@ class AgenticEdit:
|
|
|
1154
1179
|
conversations = [
|
|
1155
1180
|
{"role": "system", "content": system_prompt},
|
|
1156
1181
|
]
|
|
1157
|
-
|
|
1182
|
+
|
|
1158
1183
|
# Add third-party library documentation information
|
|
1159
1184
|
try:
|
|
1160
1185
|
package_manager = LLMFriendlyPackageManager(
|
|
@@ -1199,12 +1224,36 @@ class AgenticEdit:
|
|
|
1199
1224
|
})
|
|
1200
1225
|
|
|
1201
1226
|
except Exception as e:
|
|
1202
|
-
logger.warning(f"Failed to load library documentation: {str(e)}")
|
|
1203
|
-
|
|
1227
|
+
logger.warning(f"Failed to load library documentation: {str(e)}")
|
|
1228
|
+
|
|
1229
|
+
if self.conversation_config.action == "resume":
|
|
1230
|
+
current_conversation = self.conversation_manager.get_current_conversation()
|
|
1231
|
+
# 如果继续的是当前的对话,将其消息加入到 conversations 中
|
|
1232
|
+
if current_conversation and current_conversation.get('messages'):
|
|
1233
|
+
for message in current_conversation['messages']:
|
|
1234
|
+
# 确保消息格式正确(包含 role 和 content 字段)
|
|
1235
|
+
if isinstance(message, dict) and 'role' in message and 'content' in message:
|
|
1236
|
+
conversations.append({
|
|
1237
|
+
"role": message['role'],
|
|
1238
|
+
"content": message['content']
|
|
1239
|
+
})
|
|
1240
|
+
logger.info(f"Resumed conversation with {len(current_conversation['messages'])} existing messages")
|
|
1241
|
+
|
|
1242
|
+
if self.conversation_manager.get_current_conversation_id() is None:
|
|
1243
|
+
conv_id = self.conversation_manager.create_conversation(name=self.conversation_config.query,description=self.conversation_config.query)
|
|
1244
|
+
self.conversation_manager.set_current_conversation(conv_id)
|
|
1245
|
+
|
|
1246
|
+
self.conversation_manager.set_current_conversation(self.conversation_manager.get_current_conversation_id())
|
|
1247
|
+
yield ConversationIdEvent(conversation_id=self.conversation_manager.get_current_conversation_id())
|
|
1248
|
+
|
|
1204
1249
|
conversations.append({
|
|
1205
1250
|
"role": "user", "content": request.user_input
|
|
1206
|
-
})
|
|
1251
|
+
})
|
|
1207
1252
|
|
|
1253
|
+
self.conversation_manager.append_message_to_current(
|
|
1254
|
+
role="user",
|
|
1255
|
+
content=request.user_input,
|
|
1256
|
+
metadata={})
|
|
1208
1257
|
|
|
1209
1258
|
self.current_conversations = conversations
|
|
1210
1259
|
|
|
@@ -1292,7 +1341,12 @@ class AgenticEdit:
|
|
|
1292
1341
|
conversations.append({
|
|
1293
1342
|
"role": "assistant",
|
|
1294
1343
|
"content": assistant_buffer + tool_xml
|
|
1295
|
-
})
|
|
1344
|
+
})
|
|
1345
|
+
self.conversation_manager.append_message_to_current(
|
|
1346
|
+
role="assistant",
|
|
1347
|
+
content=assistant_buffer + tool_xml,
|
|
1348
|
+
metadata={})
|
|
1349
|
+
|
|
1296
1350
|
assistant_buffer = "" # Reset buffer after tool call
|
|
1297
1351
|
|
|
1298
1352
|
# 计算当前对话的总 token 数量并触发事件
|
|
@@ -1311,7 +1365,7 @@ class AgenticEdit:
|
|
|
1311
1365
|
completion_event = CompletionEvent(completion=tool_obj, completion_xml=tool_xml)
|
|
1312
1366
|
logger.info(
|
|
1313
1367
|
"AgenticEdit analyze loop finished due to AttemptCompletion.")
|
|
1314
|
-
save_formatted_log(self.args.source_dir, json.dumps(conversations, ensure_ascii=False), "agentic_conversation")
|
|
1368
|
+
save_formatted_log(self.args.source_dir, json.dumps(conversations, ensure_ascii=False), "agentic_conversation")
|
|
1315
1369
|
mark_event_should_finish = True
|
|
1316
1370
|
should_yield_completion_event = True
|
|
1317
1371
|
continue
|
|
@@ -1387,6 +1441,10 @@ class AgenticEdit:
|
|
|
1387
1441
|
"role": "user", # Simulating the user providing the tool result
|
|
1388
1442
|
"content": error_xml
|
|
1389
1443
|
})
|
|
1444
|
+
self.conversation_manager.append_message_to_current(
|
|
1445
|
+
role="user",
|
|
1446
|
+
content=error_xml,
|
|
1447
|
+
metadata={})
|
|
1390
1448
|
|
|
1391
1449
|
# 计算当前对话的总 token 数量并触发事件
|
|
1392
1450
|
current_conversation_str = json.dumps(conversations, ensure_ascii=False)
|
|
@@ -1425,6 +1483,9 @@ class AgenticEdit:
|
|
|
1425
1483
|
logger.info("Adding new assistant message")
|
|
1426
1484
|
conversations.append(
|
|
1427
1485
|
{"role": "assistant", "content": assistant_buffer})
|
|
1486
|
+
self.conversation_manager.append_message_to_current(
|
|
1487
|
+
role="assistant", content=assistant_buffer,metadata={})
|
|
1488
|
+
|
|
1428
1489
|
elif last_message["role"] == "assistant":
|
|
1429
1490
|
logger.info("Appending to existing assistant message")
|
|
1430
1491
|
last_message["content"] += assistant_buffer
|
|
@@ -1441,6 +1502,11 @@ class AgenticEdit:
|
|
|
1441
1502
|
"role": "user",
|
|
1442
1503
|
"content": "NOTE: You must use an appropriate tool (such as read_file, write_to_file, execute_command, etc.) or explicitly complete the task (using attempt_completion). Do not provide text responses without taking concrete actions. Please select a suitable tool to continue based on the user's task."
|
|
1443
1504
|
})
|
|
1505
|
+
|
|
1506
|
+
self.conversation_manager.append_message_to_current(
|
|
1507
|
+
role="user",
|
|
1508
|
+
content="NOTE: You must use an appropriate tool (such as read_file, write_to_file, execute_command, etc.) or explicitly complete the task (using attempt_completion). Do not provide text responses without taking concrete actions. Please select a suitable tool to continue based on the user's task.",
|
|
1509
|
+
metadata={})
|
|
1444
1510
|
|
|
1445
1511
|
# 计算当前对话的总 token 数量并触发事件
|
|
1446
1512
|
current_conversation_str = json.dumps(conversations, ensure_ascii=False)
|
|
@@ -1580,9 +1646,9 @@ class AgenticEdit:
|
|
|
1580
1646
|
else:
|
|
1581
1647
|
yield ToolCallEvent(tool=tool_obj, tool_xml=reconstructed_xml)
|
|
1582
1648
|
else:
|
|
1583
|
-
yield ErrorEvent(message=f"Failed to parse tool: <{current_tool_tag}>")
|
|
1649
|
+
# yield ErrorEvent(message=f"Failed to parse tool: <{current_tool_tag}>")
|
|
1584
1650
|
# Optionally yield the raw XML as plain text?
|
|
1585
|
-
|
|
1651
|
+
yield LLMOutputEvent(text=f"Failed to parse tool: <{current_tool_tag}> {tool_xml}")
|
|
1586
1652
|
|
|
1587
1653
|
buffer = buffer[tool_block_end_index:]
|
|
1588
1654
|
in_tool_block = False
|
|
@@ -1856,85 +1922,219 @@ class AgenticEdit:
|
|
|
1856
1922
|
def apply_changes(self):
|
|
1857
1923
|
"""
|
|
1858
1924
|
Apply all tracked file changes to the original project directory.
|
|
1925
|
+
"""
|
|
1926
|
+
if not self.args.skip_commit:
|
|
1927
|
+
try:
|
|
1928
|
+
file_name = os.path.basename(self.args.file)
|
|
1929
|
+
commit_result = git_utils.commit_changes(
|
|
1930
|
+
self.args.source_dir,
|
|
1931
|
+
f"{self.args.query}\nauto_coder_{file_name}",
|
|
1932
|
+
)
|
|
1933
|
+
|
|
1934
|
+
get_event_manager(self.args.event_file).write_result(
|
|
1935
|
+
EventContentCreator.create_result(
|
|
1936
|
+
content={
|
|
1937
|
+
"have_commit":commit_result.success,
|
|
1938
|
+
"commit_hash":commit_result.commit_hash,
|
|
1939
|
+
"diff_file_num":len(commit_result.changed_files),
|
|
1940
|
+
"event_file":self.args.event_file
|
|
1941
|
+
}), metadata=EventMetadata(
|
|
1942
|
+
action_file=self.args.file,
|
|
1943
|
+
is_streaming=False,
|
|
1944
|
+
path="/agent/edit/apply_changes",
|
|
1945
|
+
stream_out_type="/agent/edit").to_dict())
|
|
1946
|
+
|
|
1947
|
+
action_yml_file_manager = ActionYmlFileManager(
|
|
1948
|
+
self.args.source_dir)
|
|
1949
|
+
action_file_name = os.path.basename(self.args.file)
|
|
1950
|
+
add_updated_urls = []
|
|
1951
|
+
commit_result.changed_files
|
|
1952
|
+
for file in commit_result.changed_files:
|
|
1953
|
+
add_updated_urls.append(
|
|
1954
|
+
os.path.join(self.args.source_dir, file))
|
|
1955
|
+
|
|
1956
|
+
self.args.add_updated_urls = add_updated_urls
|
|
1957
|
+
update_yaml_success = action_yml_file_manager.update_yaml_field(
|
|
1958
|
+
action_file_name, "add_updated_urls", add_updated_urls)
|
|
1959
|
+
if not update_yaml_success:
|
|
1960
|
+
self.printer.print_in_terminal(
|
|
1961
|
+
"yaml_save_error", style="red", yaml_file=action_file_name)
|
|
1962
|
+
|
|
1963
|
+
if self.args.enable_active_context:
|
|
1964
|
+
active_context_manager = ActiveContextManager(
|
|
1965
|
+
self.llm, self.args.source_dir)
|
|
1966
|
+
task_id = active_context_manager.process_changes(
|
|
1967
|
+
self.args)
|
|
1968
|
+
self.printer.print_in_terminal("active_context_background_task",
|
|
1969
|
+
style="blue",
|
|
1970
|
+
task_id=task_id)
|
|
1971
|
+
git_utils.print_commit_info(commit_result=commit_result)
|
|
1972
|
+
|
|
1973
|
+
# 检查是否需要创建 Pull Request
|
|
1974
|
+
if self.conversation_config and self.conversation_config.pull_request:
|
|
1975
|
+
self._create_pull_request(commit_result)
|
|
1976
|
+
|
|
1977
|
+
except Exception as e:
|
|
1978
|
+
self.printer.print_str_in_terminal(
|
|
1979
|
+
str(e),
|
|
1980
|
+
style="red"
|
|
1981
|
+
)
|
|
1982
|
+
|
|
1983
|
+
def _create_pull_request(self, commit_result):
|
|
1859
1984
|
"""
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
else:
|
|
1872
|
-
changes = self.checkpoint_manager.get_changes_by_group(self.args.event_file)
|
|
1873
|
-
diff_file_num = len(changes)
|
|
1985
|
+
创建 Pull Request(如果配置启用)
|
|
1986
|
+
|
|
1987
|
+
Args:
|
|
1988
|
+
commit_result: Git commit 结果对象
|
|
1989
|
+
"""
|
|
1990
|
+
try:
|
|
1991
|
+
# 获取当前分支名
|
|
1992
|
+
current_branch = git_utils.get_current_branch(self.args.source_dir)
|
|
1993
|
+
if not current_branch:
|
|
1994
|
+
logger.warning(get_message("/agent/edit/pull_request/branch_name_failed"))
|
|
1995
|
+
return
|
|
1874
1996
|
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1997
|
+
# 准备 PR 标题和描述
|
|
1998
|
+
query = self.args.query or get_message("/agent/edit/pull_request/default_query")
|
|
1999
|
+
pr_title = get_message_with_format("/agent/edit/pull_request/title", query=query[0:40])
|
|
2000
|
+
|
|
2001
|
+
# 构建 PR 描述
|
|
2002
|
+
file_list = ""
|
|
2003
|
+
if commit_result.changed_files:
|
|
2004
|
+
for file_path in commit_result.changed_files:
|
|
2005
|
+
file_list += f"- `{file_path}`\n"
|
|
2006
|
+
|
|
2007
|
+
pr_description = get_message_with_format(
|
|
2008
|
+
"/agent/edit/pull_request/description",
|
|
2009
|
+
query=query,
|
|
2010
|
+
file_count=len(commit_result.changed_files or []),
|
|
2011
|
+
commit_hash=commit_result.commit_hash,
|
|
2012
|
+
file_list=file_list.strip(),
|
|
2013
|
+
source_branch=current_branch,
|
|
2014
|
+
target_branch="main",
|
|
2015
|
+
timestamp=time.strftime('%Y-%m-%d %H:%M:%S')
|
|
2016
|
+
)
|
|
2017
|
+
|
|
2018
|
+
# 创建 Pull Request
|
|
2019
|
+
logger.info(get_message_with_format("/agent/edit/pull_request/creating", title=pr_title))
|
|
2020
|
+
|
|
2021
|
+
result = create_pull_request(
|
|
2022
|
+
repo_path=self.args.source_dir,
|
|
2023
|
+
title=pr_title,
|
|
2024
|
+
description=pr_description,
|
|
2025
|
+
)
|
|
2026
|
+
|
|
2027
|
+
if result.success:
|
|
2028
|
+
logger.info(get_message("/agent/edit/pull_request/success"))
|
|
2029
|
+
logger.info(f"PR URL: {result.pr_url}")
|
|
2030
|
+
logger.info(f"PR 编号: {result.pr_number}")
|
|
2031
|
+
|
|
2032
|
+
# 打印成功信息到终端
|
|
2033
|
+
self.printer.print_str_in_terminal(
|
|
2034
|
+
get_message("/agent/edit/pull_request/success"),
|
|
2035
|
+
style="green"
|
|
2036
|
+
)
|
|
2037
|
+
self.printer.print_str_in_terminal(f"PR URL: {result.pr_url}")
|
|
2038
|
+
self.printer.print_str_in_terminal(f"PR 编号: {result.pr_number}")
|
|
2039
|
+
|
|
2040
|
+
# 写入事件日志
|
|
2041
|
+
get_event_manager(self.args.event_file).write_result(
|
|
2042
|
+
EventContentCreator.create_result(
|
|
2043
|
+
content={
|
|
2044
|
+
"success": True,
|
|
2045
|
+
"pr_url": result.pr_url,
|
|
2046
|
+
"pr_number": result.pr_number,
|
|
2047
|
+
"source_branch": current_branch,
|
|
2048
|
+
"target_branch": "main",
|
|
2049
|
+
"platform": result.platform.value if result.platform else "unknown"
|
|
2050
|
+
}),
|
|
2051
|
+
metadata=EventMetadata(
|
|
2052
|
+
action_file=self.args.file,
|
|
2053
|
+
is_streaming=False,
|
|
2054
|
+
path="/agent/edit/pull_request_created",
|
|
2055
|
+
stream_out_type="/agent/edit"
|
|
2056
|
+
).to_dict()
|
|
2057
|
+
)
|
|
2058
|
+
|
|
2059
|
+
else:
|
|
2060
|
+
error_msg = get_message_with_format("/agent/edit/pull_request/failed", error=result.error_message)
|
|
2061
|
+
logger.error(error_msg)
|
|
2062
|
+
|
|
2063
|
+
# 打印错误信息到终端
|
|
2064
|
+
self.printer.print_str_in_terminal(error_msg, style="red")
|
|
2065
|
+
|
|
2066
|
+
# 写入错误事件日志
|
|
2067
|
+
get_event_manager(self.args.event_file).write_error(
|
|
2068
|
+
EventContentCreator.create_error(
|
|
2069
|
+
error_code="PR_CREATION_FAILED",
|
|
2070
|
+
error_message=result.error_message,
|
|
2071
|
+
details={
|
|
2072
|
+
"source_branch": current_branch,
|
|
2073
|
+
"target_branch": "main"
|
|
2074
|
+
}
|
|
2075
|
+
).to_dict(),
|
|
2076
|
+
metadata=EventMetadata(
|
|
2077
|
+
action_file=self.args.file,
|
|
2078
|
+
is_streaming=False,
|
|
2079
|
+
path="/agent/edit/pull_request_error",
|
|
2080
|
+
stream_out_type="/agent/edit"
|
|
2081
|
+
).to_dict()
|
|
2082
|
+
)
|
|
2083
|
+
|
|
2084
|
+
except Exception as e:
|
|
2085
|
+
error_msg = get_message_with_format("/agent/edit/pull_request/exception", error=str(e))
|
|
2086
|
+
logger.exception(error_msg)
|
|
2087
|
+
|
|
2088
|
+
# 打印异常信息到终端
|
|
2089
|
+
self.printer.print_str_in_terminal(error_msg, style="red")
|
|
2090
|
+
|
|
2091
|
+
# 写入异常事件日志
|
|
2092
|
+
get_event_manager(self.args.event_file).write_error(
|
|
2093
|
+
EventContentCreator.create_error(
|
|
2094
|
+
error_code="PR_CREATION_EXCEPTION",
|
|
2095
|
+
error_message=get_message_with_format("/agent/edit/pull_request/exception", error=str(e)),
|
|
2096
|
+
details={"exception_type": type(e).__name__}
|
|
2097
|
+
).to_dict(),
|
|
2098
|
+
metadata=EventMetadata(
|
|
2099
|
+
action_file=self.args.file,
|
|
2100
|
+
is_streaming=False,
|
|
2101
|
+
path="/agent/edit/pull_request_exception",
|
|
2102
|
+
stream_out_type="/agent/edit"
|
|
2103
|
+
).to_dict()
|
|
2104
|
+
)
|
|
1930
2105
|
|
|
1931
2106
|
def run_in_terminal(self, request: AgenticEditRequest):
|
|
1932
2107
|
"""
|
|
1933
2108
|
Runs the agentic edit process based on the request and displays
|
|
1934
2109
|
the interaction streamingly in the terminal using Rich.
|
|
1935
2110
|
"""
|
|
2111
|
+
import json
|
|
1936
2112
|
console = Console()
|
|
1937
2113
|
project_name = os.path.basename(os.path.abspath(self.args.source_dir))
|
|
2114
|
+
|
|
2115
|
+
if self.conversation_config.action == "list":
|
|
2116
|
+
conversations = self.conversation_manager.list_conversations()
|
|
2117
|
+
# 只保留 conversation_id 和 name 字段
|
|
2118
|
+
filtered_conversations = []
|
|
2119
|
+
for conv in conversations:
|
|
2120
|
+
filtered_conv = {
|
|
2121
|
+
"conversation_id": conv.get("conversation_id"),
|
|
2122
|
+
"name": conv.get("name")
|
|
2123
|
+
}
|
|
2124
|
+
filtered_conversations.append(filtered_conv)
|
|
2125
|
+
|
|
2126
|
+
# 格式化 JSON 输出,使用 JSON 格式渲染而不是 Markdown
|
|
2127
|
+
json_str = json.dumps(filtered_conversations, ensure_ascii=False, indent=4)
|
|
2128
|
+
console.print(Panel(json_str,
|
|
2129
|
+
title="🏁 Task Completion", border_style="green", title_align="left"))
|
|
2130
|
+
return
|
|
2131
|
+
|
|
2132
|
+
|
|
2133
|
+
if self.conversation_config.action == "new" and not request.user_input.strip():
|
|
2134
|
+
console.print(Panel(Markdown(f"New conversation created: {self.conversation_manager.get_current_conversation_id()}"),
|
|
2135
|
+
title="🏁 Task Completion", border_style="green", title_align="left"))
|
|
2136
|
+
return
|
|
2137
|
+
|
|
1938
2138
|
console.rule(f"[bold cyan]Starting Agentic Edit: {project_name}[/]")
|
|
1939
2139
|
console.print(Panel(
|
|
1940
2140
|
f"[bold]{get_message('/agent/edit/user_query')}:[/bold]\n{request.user_input}", title=get_message("/agent/edit/objective"), border_style="blue"))
|
|
@@ -1952,6 +2152,9 @@ class AgenticEdit:
|
|
|
1952
2152
|
self.apply_pre_changes()
|
|
1953
2153
|
event_stream = self.analyze(request)
|
|
1954
2154
|
for event in event_stream:
|
|
2155
|
+
if isinstance(event, ConversationIdEvent):
|
|
2156
|
+
console.print(f"[dim]Conversation ID: {event.conversation_id}[/dim]")
|
|
2157
|
+
continue
|
|
1955
2158
|
if isinstance(event, TokenUsageEvent):
|
|
1956
2159
|
last_meta: SingleOutputMeta = event.usage
|
|
1957
2160
|
# Get model info for pricing
|
|
@@ -2144,6 +2347,20 @@ class AgenticEdit:
|
|
|
2144
2347
|
finally:
|
|
2145
2348
|
console.rule("[bold cyan]Agentic Edit Finished[/]")
|
|
2146
2349
|
|
|
2350
|
+
def run(self, request: AgenticEditRequest):
|
|
2351
|
+
try:
|
|
2352
|
+
event_stream = self.analyze(request)
|
|
2353
|
+
for agent_event in event_stream:
|
|
2354
|
+
if isinstance(agent_event, CompletionEvent):
|
|
2355
|
+
self.apply_changes()
|
|
2356
|
+
yield agent_event
|
|
2357
|
+
|
|
2358
|
+
except Exception as e:
|
|
2359
|
+
logger.exception(
|
|
2360
|
+
"An unexpected error occurred during agent execution: {e}")
|
|
2361
|
+
raise e
|
|
2362
|
+
|
|
2363
|
+
|
|
2147
2364
|
def run_with_events(self, request: AgenticEditRequest):
|
|
2148
2365
|
"""
|
|
2149
2366
|
Runs the agentic edit process, converting internal events to the
|
|
@@ -2275,6 +2492,16 @@ class AgenticEdit:
|
|
|
2275
2492
|
|
|
2276
2493
|
# 记录日志
|
|
2277
2494
|
logger.info(f"当前会话总 tokens: {agent_event.tokens_used}")
|
|
2495
|
+
|
|
2496
|
+
elif isinstance(agent_event, ConversationIdEvent):
|
|
2497
|
+
metadata.path = "/agent/edit/conversation_id"
|
|
2498
|
+
content = EventContentCreator.create_result(
|
|
2499
|
+
content={
|
|
2500
|
+
"conversation_id": agent_event.conversation_id
|
|
2501
|
+
},
|
|
2502
|
+
metadata={}
|
|
2503
|
+
)
|
|
2504
|
+
event_manager.write_result(content=content.to_dict(), metadata=metadata.to_dict())
|
|
2278
2505
|
|
|
2279
2506
|
elif isinstance(agent_event, ErrorEvent):
|
|
2280
2507
|
metadata.path = "/agent/edit/error"
|
|
@@ -2284,7 +2511,7 @@ class AgenticEdit:
|
|
|
2284
2511
|
details={"agent_event_type": "ErrorEvent"}
|
|
2285
2512
|
)
|
|
2286
2513
|
event_manager.write_error(
|
|
2287
|
-
content=content.to_dict(), metadata=metadata.to_dict())
|
|
2514
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
2288
2515
|
else:
|
|
2289
2516
|
metadata.path = "/agent/edit/error"
|
|
2290
2517
|
logger.warning(
|
|
@@ -86,6 +86,11 @@ class TokenUsageEvent(BaseModel):
|
|
|
86
86
|
"""Represents the result of executing a tool."""
|
|
87
87
|
usage: Any
|
|
88
88
|
|
|
89
|
+
|
|
90
|
+
class ConversationIdEvent(BaseModel):
|
|
91
|
+
"""Represents the conversation id."""
|
|
92
|
+
conversation_id: str
|
|
93
|
+
|
|
89
94
|
class PlanModeRespondEvent(BaseModel):
|
|
90
95
|
"""Represents the LLM attempting to complete the task."""
|
|
91
96
|
completion: SkipValidation[PlanModeRespondTool] # Skip validation
|
|
@@ -177,3 +182,9 @@ class CommandConfig(BaseModel):
|
|
|
177
182
|
index_import: SkipValidation[Callable]
|
|
178
183
|
exclude_files: SkipValidation[Callable]
|
|
179
184
|
|
|
185
|
+
class AgenticEditConversationConfig(BaseModel):
|
|
186
|
+
conversation_name: Optional[str] = "current"
|
|
187
|
+
conversation_id: Optional[str] = None
|
|
188
|
+
action: Optional[str] = None
|
|
189
|
+
query: Optional[str] = None
|
|
190
|
+
pull_request: bool = False
|
|
@@ -52,7 +52,7 @@ class CodeAutoGenerateEditBlock:
|
|
|
52
52
|
package_context: str = ""
|
|
53
53
|
) -> str:
|
|
54
54
|
"""
|
|
55
|
-
如果你需要生成代码,对于每个需要更改的文件,你需要按 *SEARCH/REPLACE block* 的格式进行生成。
|
|
55
|
+
如果你需要生成代码,对于每个需要更改的文件,你需要按 *SEARCH/REPLACE block* 的格式进行生成。
|
|
56
56
|
|
|
57
57
|
# *SEARCH/REPLACE block* Rules:
|
|
58
58
|
|
|
@@ -196,7 +196,15 @@ class CodeAutoGenerateEditBlock:
|
|
|
196
196
|
<extra_context>
|
|
197
197
|
{{ context }}
|
|
198
198
|
</extra_context>
|
|
199
|
-
{%- endif %}
|
|
199
|
+
{%- endif %}
|
|
200
|
+
|
|
201
|
+
====
|
|
202
|
+
|
|
203
|
+
RULES PROVIDED BY SYSTEM
|
|
204
|
+
|
|
205
|
+
Before outputting the *SEARCH/REPLACE block* format, you must carefully think through the user's question and make a complete design. These thoughts and designs should be placed within the <thinking></thinking> tags.
|
|
206
|
+
|
|
207
|
+
====
|
|
200
208
|
|
|
201
209
|
{%- if extra_docs %}
|
|
202
210
|
====
|
autocoder/dispacher/__init__.py
CHANGED
|
@@ -8,6 +8,11 @@ from autocoder.dispacher.actions.action import (
|
|
|
8
8
|
from autocoder.dispacher.actions.plugins.action_regex_project import ActionRegexProject
|
|
9
9
|
from typing import Optional
|
|
10
10
|
import byzerllm
|
|
11
|
+
# from autocoder.common.conversations.get_conversation_manager import (
|
|
12
|
+
# get_conversation_manager,
|
|
13
|
+
# get_conversation_manager_config,
|
|
14
|
+
# reset_conversation_manager
|
|
15
|
+
# )
|
|
11
16
|
|
|
12
17
|
|
|
13
18
|
class Dispacher:
|
|
@@ -16,6 +21,11 @@ class Dispacher:
|
|
|
16
21
|
self.llm = llm
|
|
17
22
|
|
|
18
23
|
def dispach(self):
|
|
24
|
+
# manager = get_conversation_manager()
|
|
25
|
+
# if not manager.get_current_conversation():
|
|
26
|
+
# manager.create_conversation(name="New Conversation", description="New Conversation")
|
|
27
|
+
# manager.set_current_conversation(manager.get_current_conversation_id())
|
|
28
|
+
|
|
19
29
|
args = self.args
|
|
20
30
|
actions = [
|
|
21
31
|
ActionTSProject(args=args, llm=self.llm),
|