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.

Files changed (71) hide show
  1. {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/METADATA +1 -1
  2. {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/RECORD +71 -35
  3. autocoder/agent/agentic_filter.py +1 -1
  4. autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +1 -1
  5. autocoder/auto_coder_runner.py +121 -26
  6. autocoder/chat_auto_coder.py +81 -22
  7. autocoder/commands/auto_command.py +1 -1
  8. autocoder/common/__init__.py +2 -2
  9. autocoder/common/ac_style_command_parser/parser.py +27 -12
  10. autocoder/common/auto_coder_lang.py +78 -0
  11. autocoder/common/command_completer_v2.py +1 -1
  12. autocoder/common/file_monitor/test_file_monitor.py +307 -0
  13. autocoder/common/git_utils.py +7 -2
  14. autocoder/common/pruner/__init__.py +0 -0
  15. autocoder/common/pruner/agentic_conversation_pruner.py +197 -0
  16. autocoder/common/pruner/context_pruner.py +574 -0
  17. autocoder/common/pruner/conversation_pruner.py +132 -0
  18. autocoder/common/pruner/test_agentic_conversation_pruner.py +342 -0
  19. autocoder/common/pruner/test_context_pruner.py +546 -0
  20. autocoder/common/pull_requests/__init__.py +256 -0
  21. autocoder/common/pull_requests/base_provider.py +191 -0
  22. autocoder/common/pull_requests/config.py +66 -0
  23. autocoder/common/pull_requests/example.py +1 -0
  24. autocoder/common/pull_requests/exceptions.py +46 -0
  25. autocoder/common/pull_requests/manager.py +201 -0
  26. autocoder/common/pull_requests/models.py +164 -0
  27. autocoder/common/pull_requests/providers/__init__.py +23 -0
  28. autocoder/common/pull_requests/providers/gitcode_provider.py +19 -0
  29. autocoder/common/pull_requests/providers/gitee_provider.py +20 -0
  30. autocoder/common/pull_requests/providers/github_provider.py +214 -0
  31. autocoder/common/pull_requests/providers/gitlab_provider.py +29 -0
  32. autocoder/common/pull_requests/test_module.py +1 -0
  33. autocoder/common/pull_requests/utils.py +344 -0
  34. autocoder/common/tokens/__init__.py +77 -0
  35. autocoder/common/tokens/counter.py +231 -0
  36. autocoder/common/tokens/file_detector.py +105 -0
  37. autocoder/common/tokens/filters.py +111 -0
  38. autocoder/common/tokens/models.py +28 -0
  39. autocoder/common/v2/agent/agentic_edit.py +538 -590
  40. autocoder/common/v2/agent/agentic_edit_tools/__init__.py +8 -1
  41. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_read_tool_resolver.py +40 -0
  42. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +43 -0
  43. autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py +8 -0
  44. autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +1 -1
  45. autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +1 -1
  46. autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +33 -88
  47. autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +8 -8
  48. autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +118 -0
  49. autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +324 -0
  50. autocoder/common/v2/agent/agentic_edit_types.py +47 -4
  51. autocoder/common/v2/agent/runner/__init__.py +31 -0
  52. autocoder/common/v2/agent/runner/base_runner.py +106 -0
  53. autocoder/common/v2/agent/runner/event_runner.py +216 -0
  54. autocoder/common/v2/agent/runner/sdk_runner.py +40 -0
  55. autocoder/common/v2/agent/runner/terminal_runner.py +283 -0
  56. autocoder/common/v2/agent/runner/tool_display.py +191 -0
  57. autocoder/index/entry.py +1 -1
  58. autocoder/plugins/token_helper_plugin.py +107 -7
  59. autocoder/run_context.py +9 -0
  60. autocoder/sdk/__init__.py +114 -81
  61. autocoder/sdk/cli/handlers.py +2 -1
  62. autocoder/sdk/cli/main.py +9 -2
  63. autocoder/sdk/cli/options.py +4 -3
  64. autocoder/sdk/core/auto_coder_core.py +7 -152
  65. autocoder/sdk/core/bridge.py +5 -4
  66. autocoder/sdk/models/options.py +8 -6
  67. autocoder/version.py +1 -1
  68. {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/WHEEL +0 -0
  69. {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/entry_points.txt +0 -0
  70. {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/licenses/LICENSE +0 -0
  71. {auto_coder-0.1.399.dist-info → auto_coder-1.0.0.dist-info}/top_level.txt +0 -0
@@ -1,56 +1,34 @@
1
1
  import json
2
2
  import os
3
3
  import time
4
- from pydantic import BaseModel, Field
5
4
  import byzerllm
6
- from typing import List, Dict, Any, Union, Callable, Optional, Tuple
5
+ from typing import List, Dict, Any, Union, Optional, Tuple
7
6
  from autocoder.common.printer import Printer
8
- from rich.console import Console
9
- from rich.panel import Panel
10
- from pydantic import SkipValidation
11
- from byzerllm.utils.types import SingleOutputMeta
12
7
 
13
- from byzerllm.utils import (
14
- format_str_jinja2
15
- )
16
-
17
- from autocoder.common import AutoCoderArgs, git_utils, SourceCodeList, SourceCode
8
+ from autocoder.common import AutoCoderArgs, git_utils, SourceCodeList
18
9
  from autocoder.common.global_cancel import global_cancel
19
10
  from autocoder.common import detect_env
20
11
  from autocoder.common import shells
21
12
  from loguru import logger
22
- from autocoder.utils import llms as llms_utils
23
- from autocoder.common.auto_configure import config_readme
24
13
  from autocoder.utils.auto_project_type import ProjectTypeAnalyzer
25
- from rich.text import Text
14
+
26
15
  from autocoder.common.mcp_server import get_mcp_server, McpServerInfoRequest
27
16
  from autocoder.common import SourceCodeList
28
17
  from autocoder.common.utils_code_auto_generate import stream_chat_with_continue # Added import
29
18
  import re
30
19
  import xml.sax.saxutils
31
20
  import time # Added for sleep
32
- from typing import Iterator, Union, Type, Generator
33
- from xml.etree import ElementTree as ET
34
- from rich.console import Console # Added
35
- from rich.panel import Panel # Added
36
- from rich.syntax import Syntax # Added
37
- from rich.markdown import Markdown # Added
21
+ from typing import Union, Type, Generator
38
22
  from autocoder.events.event_manager_singleton import get_event_manager
39
- from autocoder.events.event_types import Event, EventType, EventMetadata
23
+ from autocoder.events.event_types import EventMetadata
40
24
  from autocoder.memory.active_context_manager import ActiveContextManager
41
25
  from autocoder.events import event_content as EventContentCreator
42
- from autocoder.shadows.shadow_manager import ShadowManager
43
- from autocoder.linters.shadow_linter import ShadowLinter
44
- from autocoder.compilers.shadow_compiler import ShadowCompiler
45
26
  from autocoder.common.action_yml_file_manager import ActionYmlFileManager
46
27
  from autocoder.common.auto_coder_lang import get_message
47
28
  from autocoder.common.save_formatted_log import save_formatted_log
48
- # Import the new display function
49
- from autocoder.common.v2.agent.agentic_tool_display import get_tool_display_message
50
29
  from autocoder.common.v2.agent.agentic_edit_types import FileChangeEntry
51
30
  from autocoder.utils.llms import get_single_llm
52
31
 
53
- from autocoder.common.file_checkpoint.models import FileChange as CheckpointFileChange
54
32
  from autocoder.common.file_checkpoint.manager import FileChangeManager as CheckpointFileChangeManager
55
33
  from autocoder.linters.normal_linter import NormalLinter
56
34
  from autocoder.compilers.normal_compiler import NormalCompiler
@@ -60,7 +38,8 @@ from autocoder.common.v2.agent.agentic_edit_tools import ( # Import specific re
60
38
  ReplaceInFileToolResolver, SearchFilesToolResolver, ListFilesToolResolver,
61
39
  ListCodeDefinitionNamesToolResolver, AskFollowupQuestionToolResolver,
62
40
  AttemptCompletionToolResolver, PlanModeRespondToolResolver, UseMcpToolResolver,
63
- UseRAGToolResolver, ListPackageInfoToolResolver
41
+ UseRAGToolResolver, ACModReadToolResolver, ACModWriteToolResolver, TodoReadToolResolver,
42
+ TodoWriteToolResolver
64
43
  )
65
44
  from autocoder.common.llm_friendly_package import LLMFriendlyPackageManager
66
45
  from autocoder.common.rulefiles.autocoderrules_utils import get_rules,auto_select_rules,get_required_and_index_rules
@@ -73,7 +52,8 @@ from autocoder.common.v2.agent.agentic_edit_types import (AgenticEditRequest, To
73
52
  ListFilesTool,
74
53
  ListCodeDefinitionNamesTool, AskFollowupQuestionTool,
75
54
  AttemptCompletionTool, PlanModeRespondTool, UseMcpTool,
76
- UseRAGTool, ListPackageInfoTool,
55
+ UseRAGTool, ACModReadTool, ACModWriteTool, TodoReadTool,
56
+ TodoWriteTool,
77
57
  TOOL_MODEL_MAP,
78
58
  # Event Types
79
59
  LLMOutputEvent, LLMThinkingEvent, ToolCallEvent,
@@ -98,19 +78,21 @@ TOOL_RESOLVER_MAP: Dict[Type[BaseTool], Type[BaseToolResolver]] = {
98
78
  SearchFilesTool: SearchFilesToolResolver,
99
79
  ListFilesTool: ListFilesToolResolver,
100
80
  ListCodeDefinitionNamesTool: ListCodeDefinitionNamesToolResolver,
101
- ListPackageInfoTool: ListPackageInfoToolResolver,
81
+ ACModReadTool: ACModReadToolResolver,
82
+ ACModWriteTool: ACModWriteToolResolver,
102
83
  AskFollowupQuestionTool: AskFollowupQuestionToolResolver,
103
84
  AttemptCompletionTool: AttemptCompletionToolResolver, # Will stop the loop anyway
104
85
  PlanModeRespondTool: PlanModeRespondToolResolver,
105
86
  UseMcpTool: UseMcpToolResolver,
106
- UseRAGTool: UseRAGToolResolver
87
+ UseRAGTool: UseRAGToolResolver,
88
+ TodoReadTool: TodoReadToolResolver,
89
+ TodoWriteTool: TodoWriteToolResolver
107
90
  }
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
91
+ from autocoder.common.conversations.get_conversation_manager import get_conversation_manager
92
+ from autocoder.common.pull_requests import create_pull_request
93
+ from autocoder.common.auto_coder_lang import get_message, get_message_with_format
94
+ from autocoder.common.pruner.agentic_conversation_pruner import AgenticConversationPruner
95
+ from copy import deepcopy
114
96
 
115
97
 
116
98
  # --- Tool Display Customization is now handled by agentic_tool_display.py ---
@@ -195,6 +177,9 @@ class AgenticEdit:
195
177
  # 对话管理器
196
178
  self.conversation_config =conversation_config
197
179
  self.conversation_manager = get_conversation_manager()
180
+
181
+ # Agentic 对话修剪器
182
+ self.agentic_pruner = AgenticConversationPruner(args=args, llm=self.context_prune_llm)
198
183
 
199
184
  if self.conversation_config.action == "new":
200
185
  conversation_id = self.conversation_manager.create_conversation(name=self.conversation_config.query or "New Conversation",
@@ -342,14 +327,37 @@ class AgenticEdit:
342
327
  <requires_approval>true or false</requires_approval>
343
328
  </execute_command>
344
329
 
345
- ## list_package_info
346
- Description: Request to retrieve information about a source code package, such as recent changes or documentation summary, to better understand the code context. It accepts a directory path (absolute or relative to the current project).
330
+ ## ac_mod_read
331
+ Description: Request to retrieve information about an AC Module - a language-agnostic module containing a .ac.mod.md file that provides complete functionality and can be used as an API. The .ac.mod.md file contains usage examples, core components, component dependencies, references to other AC modules, and testing information. It accepts a directory path (absolute or relative to the current project).
347
332
  Parameters:
348
- - path: (required) The source code package directory path.
333
+ - path: (required) The AC Module directory path (directory containing .ac.mod.md file).
349
334
  Usage:
350
- <list_package_info>
351
- <path>relative/or/absolute/package/path</path>
352
- </list_package_info>
335
+ <ac_mod_read>
336
+ <path>relative/or/absolute/ac/module/path</path>
337
+ </ac_mod_read>
338
+
339
+ ## ac_mod_write
340
+ Description: Request to create or update an AC Module's .ac.mod.md file. This tool allows you to define a new AC Module or modify an existing one by writing to its .ac.mod.md file. The file contains usage examples, core components, component dependencies, references to other AC modules, and testing information.
341
+ Parameters:
342
+ - path: (required) The AC Module directory path (directory where .ac.mod.md file should be created or updated).
343
+ - diff: (required) One or more SEARCH/REPLACE blocks following this exact format:
344
+ ```
345
+ <<<<<<< SEARCH
346
+ [exact content to find]
347
+ =======
348
+ [new content to replace with]
349
+ >>>>>>> REPLACE
350
+
351
+ This tool have the same usage as the replace_in_file tool, but it is used to update the AC Module's .ac.mod.md file.
352
+
353
+ Usage:
354
+
355
+ <ac_mod_write>
356
+ <path>relative/or/absolute/ac/module/path</path>
357
+ <diff>
358
+ Search and replace blocks here
359
+ </diff>
360
+ </ac_mod_write>
353
361
 
354
362
  ## read_file
355
363
  Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string.
@@ -453,7 +461,36 @@ class AgenticEdit:
453
461
  <options>
454
462
  Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]
455
463
  </options>
456
- </ask_followup_question>
464
+ </ask_followup_question>
465
+
466
+ ## todo_read
467
+ Description: Request to read the current todo list for the session. This tool helps you track progress, organize complex tasks, and understand the current status of ongoing work. Use this tool proactively to stay aware of task progress and demonstrate thoroughness.
468
+ Parameters:
469
+ - No parameters required
470
+ Usage:
471
+ <todo_read>
472
+ </todo_read>
473
+
474
+ ## todo_write
475
+ Description: Request to create and manage a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user. It also helps the user understand the progress of the task and overall progress of their request. Use this tool proactively for complex multi-step tasks, when explicitly requested by the user, or when you need to organize multiple operations.
476
+ Parameters:
477
+ - action: (required) The action to perform: 'create' (create new todo list), 'add_task' (add single task), 'update' (update existing task), 'mark_progress' (mark task as in progress), 'mark_completed' (mark task as completed)
478
+ - task_id: (optional) The ID of the task to update (required for update, mark_progress, mark_completed actions)
479
+ - content: (optional) The task content or description (required for create, add_task actions)
480
+ - priority: (optional) Task priority level: 'high', 'medium', 'low' (default: 'medium')
481
+ - status: (optional) Task status: 'pending', 'in_progress', 'completed' (default: 'pending')
482
+ - notes: (optional) Additional notes or details about the task
483
+ Usage:
484
+ <todo_write>
485
+ <action>create</action>
486
+ <content>
487
+ <task>Read the configuration file</task>
488
+ <task>Update the database settings</task>
489
+ <task>Test the connection</task>
490
+ <task>Deploy the changes</task>
491
+ </content>
492
+ <priority>high</priority>
493
+ </todo_write>
457
494
 
458
495
  ## attempt_completion
459
496
  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.
@@ -503,7 +540,7 @@ class AgenticEdit:
503
540
  {%if rag_server_info %}
504
541
  ### RAG_SERVER_LIST
505
542
  {{rag_server_info}}
506
- {%endif%}
543
+ {%endif%}
507
544
 
508
545
  # Tool Use Examples
509
546
 
@@ -577,7 +614,35 @@ class AgenticEdit:
577
614
  <server_name>github</server_name>
578
615
  <tool_name>create_issue</tool_name>
579
616
  <query>ower is octocat, repo is hello-world, title is Found a bug, body is I'm having a problem with this. labels is "bug" and "help wanted",assignees is "octocat"</query>
580
- </use_mcp_tool>
617
+ </use_mcp_tool>
618
+
619
+ ## Example 5: Reading the current todo list
620
+
621
+ <todo_read>
622
+ </todo_read>
623
+
624
+ ## Example 6: Creating a new todo list for a complex task
625
+
626
+ <todo_write>
627
+ <action>create</action>
628
+ <content>
629
+ <task>Analyze the existing codebase structure</task>
630
+ <task>Design the new feature architecture</task>
631
+ <task>Implement the core functionality</task>
632
+ <task>Add comprehensive tests</task>
633
+ <task>Update documentation</task>
634
+ <task>Review and refactor code</task>
635
+ </content>
636
+ <priority>high</priority>
637
+ </todo_write>
638
+
639
+ ## Example 7: Marking a specific task as completed
640
+
641
+ <todo_write>
642
+ <action>mark_completed</action>
643
+ <task_id>task_123</task_id>
644
+ <notes>Successfully implemented with 95% test coverage</notes>
645
+ </todo_write>
581
646
 
582
647
  # Tool Use Guidelines
583
648
  0. **ALWAYS START WITH THOROUGH SEARCH AND EXPLORATION.** Before making any code changes, use search tools (list_files, grep commands) to fully understand the codebase structure, existing patterns, and dependencies. This prevents errors and ensures your changes align with project conventions.
@@ -738,10 +803,10 @@ class AgenticEdit:
738
803
  - **Combine multiple approaches** for comprehensive understanding
739
804
 
740
805
  **Default workflow:**
741
- 1. `list_files` → understand structure
806
+ 1. `list_files`(without recursively) → understand structure (if needed)
742
807
  2. `grep` → find specific patterns/symbols
743
808
  3. `read_file` → examine details
744
- 4. Implement changes
809
+ 4. Implement changes
745
810
  5. `grep` → verify changes
746
811
 
747
812
  # Comprehensive Workflow
@@ -807,13 +872,7 @@ class AgenticEdit:
807
872
 
808
873
  More detail is on the EDITING FILES PART.
809
874
 
810
- ## Phase 5: Comprehensive Verification
811
-
812
- **File System Verification**
813
- <execute_command>
814
- <command>ls -la newfile.* 2>/dev/null || echo "Expected new files not found"</command>
815
- <requires_approval>false</requires_approval>
816
- </execute_command>
875
+ ## Phase 5: Comprehensive Verification
817
876
 
818
877
  **Code Integration Verification**
819
878
  <execute_command>
@@ -830,17 +889,7 @@ class AgenticEdit:
830
889
  <execute_command>
831
890
  <command>npm run lint 2>/dev/null || echo "Linting not configured"</command>
832
891
  <requires_approval>false</requires_approval>
833
- </execute_command>
834
-
835
- <execute_command>
836
- <command>npm test 2>/dev/null || echo "Testing not configured"</command>
837
- <requires_approval>false</requires_approval>
838
- </execute_command>
839
-
840
- <execute_command>
841
- <command>npm run build 2>/dev/null || echo "Build not configured"</command>
842
- <requires_approval>false</requires_approval>
843
- </execute_command>
892
+ </execute_command>
844
893
 
845
894
  **Documentation & Comments**
846
895
  - Verify that new functions/classes have appropriate documentation
@@ -878,6 +927,118 @@ class AgenticEdit:
878
927
 
879
928
  ====
880
929
 
930
+ TODO FILE TOOLS
931
+
932
+ The TODO tools help you manage and track task progress during complex coding sessions. They provide structured task management capabilities that enhance productivity and demonstrate thoroughness to users.
933
+
934
+ # todo_read
935
+
936
+ ## Purpose
937
+
938
+ - Read and display the current session's todo list to understand task progress
939
+ - Get an overview of all pending, in-progress, and completed tasks
940
+ - Track the status of complex multi-step operations
941
+
942
+ ## When to Use
943
+
944
+ Use this tool proactively and frequently to ensure awareness of current task status:
945
+
946
+ - **At the beginning of conversations** to see what's pending
947
+ - **Before starting new tasks** to prioritize work appropriately
948
+ - **When the user asks about previous tasks** or plans
949
+ - **Whenever you're uncertain about what to do next**
950
+ - **After completing tasks** to update understanding of remaining work
951
+ - **After every few messages** to ensure you're staying on track
952
+ - **Periodically during long sessions** to review progress and stay organized
953
+
954
+ ## Important Considerations
955
+
956
+ - This tool takes **no parameters** - leave the input completely blank or empty
957
+ - **DO NOT** include dummy objects, placeholder strings, or keys like "input" or "empty"
958
+ - **LEAVE IT BLANK** - the tool will automatically read the current session's todo list
959
+ - Returns formatted output showing tasks grouped by status (In Progress, Pending, Completed)
960
+ - Provides summary statistics about task completion rates
961
+
962
+ ## Benefits
963
+
964
+ - Helps maintain context and continuity across complex tasks
965
+ - Provides clear visibility into what has been accomplished and what remains
966
+ - Demonstrates organized approach to problem-solving
967
+ - Helps prioritize next steps based on current task status
968
+
969
+ # todo_write
970
+
971
+ ## Purpose
972
+
973
+ - Create and manage structured task lists for complex coding sessions
974
+ - Track progress on multi-step operations with status updates
975
+ - Organize work into manageable, prioritized tasks
976
+ - Provide clear progress visibility to users
977
+
978
+ ## When to Use
979
+
980
+ Use this tool proactively in these scenarios:
981
+
982
+ - **Complex multi-step tasks**: When a task requires 3 or more distinct steps or actions
983
+ - **Non-trivial and complex tasks**: Tasks that require careful planning or multiple operations
984
+ - **User explicitly requests todo list**: When the user directly asks you to use the todo list
985
+ - **User provides multiple tasks**: When users provide a list of things to be done (numbered or comma-separated)
986
+ - **After receiving new instructions**: Immediately capture user requirements as todos
987
+ - **When you start working on a task**: Mark it as in_progress BEFORE beginning work (ideally only one task should be in_progress at a time)
988
+ - **After completing a task**: Mark it as completed and add any new follow-up tasks discovered during implementation
989
+
990
+ ## When NOT to Use
991
+
992
+ Skip using this tool when:
993
+
994
+ - There is only a **single, straightforward task**
995
+ - The task is **trivial** and tracking it provides no organizational benefit
996
+ - The task can be completed in **less than 3 trivial steps**
997
+ - The task is **purely conversational or informational**
998
+
999
+ **NOTE**: Do not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.
1000
+
1001
+ ## Important Considerations
1002
+
1003
+ - Each task gets a unique ID that can be used for future updates
1004
+ - Task content for 'create' action should be formatted as a numbered list for multiple tasks
1005
+ - The system automatically tracks task creation and modification timestamps
1006
+ - Todo lists persist across tool calls within the same session
1007
+ - Use descriptive task names that clearly indicate what needs to be accomplished
1008
+
1009
+ ## Example Usage Scenario
1010
+
1011
+ ```
1012
+ User: I want to add a dark mode toggle to the application settings. Make sure you run the tests and build when you're done!
1013
+
1014
+ Assistant: I'll help add a dark mode toggle to your application settings. Let me create a todo list to track this implementation.
1015
+
1016
+ Creates todo list with the following items:
1017
+ 1. Create dark mode toggle component in Settings page
1018
+ 2. Add dark mode state management (context/store)
1019
+ 3. Implement CSS-in-JS styles for dark theme
1020
+ 4. Update existing components to support theme switching
1021
+ 5. Run tests and build process, addressing any failures or errors that occur
1022
+
1023
+ Thinking: The assistant used the todo list because:
1024
+ 1. Adding dark mode is a multi-step feature requiring UI, state management, and styling changes
1025
+ 2. The user explicitly requested tests and build be run afterward
1026
+ 3. The assistant inferred that tests and build need to pass by adding "Ensure tests and build succeed" as the final task
1027
+ ```
1028
+
1029
+ ## Workflow Tips
1030
+
1031
+ 1. **Start with creation**: Use 'create' action to establish the initial task list for complex projects
1032
+ 2. **Add tasks incrementally**: Use 'add_task' as new requirements emerge during implementation
1033
+ 3. **Track progress actively**: Use 'mark_progress' when starting work on a task
1034
+ 4. **Complete tasks promptly**: Use 'mark_completed' when tasks are finished
1035
+ 5. **Add context**: Use 'notes' parameter to record important decisions or challenges
1036
+ 6. **Review regularly**: Use todo_read to maintain awareness of overall progress
1037
+
1038
+ By using these TODO tools effectively, you can maintain better organization, provide clear progress visibility, and demonstrate a systematic approach to complex coding tasks.
1039
+
1040
+ ====
1041
+
881
1042
  EDITING FILES
882
1043
 
883
1044
  Before applying the editing techniques below, ensure you have followed the SEARCHING FILES methodology to fully understand the codebase context.
@@ -954,41 +1115,158 @@ class AgenticEdit:
954
1115
 
955
1116
  ====
956
1117
 
957
- PACKAGE CONTEXT INFORMATION
1118
+ AC MOD FILES
958
1119
 
959
- # Understanding Directory Context
1120
+ # AC Modules (.ac.mod.md)
960
1121
 
961
- ## Purpose
1122
+ ## What is an AC Module?
962
1123
 
963
- - Each directory in the project (especially source code directories) has implicit context information
964
- - This includes recent changes, important files, and their purposes
965
- - This contextual information helps you understand the role of the directory and the files in the directory
1124
+ Any directory containing a `.ac.mod.md` file is considered an AC Module - a language-agnostic module that provides complete functionality and can be used as an API. These modules are self-contained units with well-defined interfaces and comprehensive documentation.
966
1125
 
967
- ## Accessing Directory Context
1126
+ ## AC Module Structure
1127
+ - .ac.mod.md contains detailed information about:
1128
+ - Usage examples and quick start guides
1129
+ - Core components and their relationships
1130
+ - Dependencies between components
1131
+ - References to other AC modules it depends on
1132
+ - Testing instructions and examples
968
1133
 
969
- - Use the **list_package_info** tool to view this information for a specific directory
970
- - Do NOT use other tools like list_files to view this specialized context information
1134
+ ## When to Use AC Modules
971
1135
 
972
- ## When to Use
1136
+ 1. **Avoid duplicate implementation**: Check if functionality already exists in project AC modules before implementing new features
1137
+ 2. **Project understanding**: Review multiple AC modules to gain comprehensive knowledge of the entire project architecture
1138
+ 3. **File modification context**: When modifying files in a directory, check if it's an AC module or contains AC modules to understand the full impact
1139
+
1140
+ ## ac_mod_read
1141
+
1142
+ When to use:
1143
+ - Use the this tool to retrieve comprehensive information about an AC module
1144
+ - The tool reads the `.ac.mod.md` file and provides structured information about the module
1145
+
1146
+ Example:
1147
+
1148
+ <ac_mod_read>
1149
+ <path>src/autocoder/agent</path>
1150
+ </ac_mod_read>
1151
+
1152
+
1153
+ ## ac_mod_write
1154
+
1155
+ When to use:
1156
+ - When we edit files in an AC module, we should update the `.ac.mod.md` file to reflect the changes.
1157
+ - When the user directly asks you to create or update an AC module
1158
+
1159
+ Example:
1160
+
1161
+ <ac_mod_write>
1162
+ <path>src/autocoder/agent</path>
1163
+ <diff>
1164
+ search and replace blocks here
1165
+ </diff>
1166
+ </ac_mod_write>
1167
+
1168
+ The content of the `.ac.mod.md` file should be ***strictly following*** the structure of the example as follows:
1169
+
1170
+ <ac_mod_md_example>
1171
+ # [Module Name]
1172
+
1173
+ [One-sentence description of the module's core functionality and its role in the project]
1174
+
1175
+ ## Directory Structure
1176
+
1177
+ ```
1178
+ [module_path]/
1179
+ ├── [main_file1] # [Detailed function description]
1180
+ ├── [main_file2] # [Detailed function description]
1181
+ ├── [subdirectory]/ # [Subdirectory function description]
1182
+ │ └── [subfile] # [Subfile function description]
1183
+ └── .ac.mod.md # This document
1184
+ ```
1185
+
1186
+ ## Quick Start
1187
+
1188
+ ### Basic Usage
973
1189
 
974
- - When you need to understand what has recently changed in a directory
975
- - When you need insight into the purpose and organization of a directory
976
- - Before diving into detailed file exploration with other tools
1190
+ ```python
1191
+ # Import necessary modules
1192
+ from [module_path] import [MainClassName], [HelperClassName]
977
1193
 
978
- ## Example
1194
+ # 1. Initialize configuration
1195
+ [Specific initialization code example]
979
1196
 
980
- ```xml
981
- <list_package_info>
982
- <path>src/some/directory</path>
983
- </list_package_info>
1197
+ # 2. Create instance
1198
+ [Instance creation code example]
1199
+
1200
+ # 3. Basic usage
1201
+ [Basic usage code example]
984
1202
  ```
985
1203
 
986
- # Benefits
1204
+ ### Helper Functions
1205
+
1206
+ [Detailed explanation of helper functions provided by the module]
1207
+
1208
+ ### Configuration Management
1209
+
1210
+ [Explanation of configuration options and management methods]
1211
+
1212
+ ## Core Components
1213
+
1214
+ ### 1. [MainClassName] Main Class
1215
+ [YOU SHOULD KEEP THIS PART AS SIMPLIFIED AS POSSIBLE]
1216
+ **Core Features:**
1217
+ - [Feature1]: [Detailed description]
1218
+ - [Feature2]: [Detailed description]
1219
+
1220
+ **Main Methods:**
1221
+ - `[method1]()`: [Method functionality and parameter description]
1222
+ - `[method2]()`: [Method functionality and parameter description]
1223
+
1224
+ ### 2. [Module] Architecture
1225
+
1226
+ [Detailed explanation of the module's design and implementation]
1227
+
1228
+ ## Mermaid File Dependency Graph
1229
+ [Main description of dependencies within the module]
1230
+
1231
+ ```mermaid
1232
+ graph TB
1233
+ %% Core module definition
1234
+ [MainModule][MainModule<br/>Core functionality description]
1235
+ [SubModule1][SubModule1<br/>Functionality description]
1236
+
1237
+ %% Dependency relationships
1238
+ [MainModule] --> [SubModule1]
1239
+
1240
+ %% Style definitions
1241
+ classDef coreClass fill:#e1f5fe,stroke:#0277bd,stroke-width:2px
1242
+ classDef subClass fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1px
1243
+
1244
+ class [MainModule] coreClass
1245
+ class [SubModule1] subClass
1246
+ ```
987
1247
 
988
- - Quickly identifies recently modified files that may be relevant to your task
989
- - Provides high-level understanding of directory contents and purpose
990
- - Helps prioritize which files to examine in detail with tools like read_file, shell commands, or list_code_definition_names
1248
+ ## Dependency Relationships
1249
+ Dependencies on other modules with .ac.mod.md files, simply shown as a relative path list, for example:
991
1250
 
1251
+ - ../a/.ac.mod.md
1252
+ - ../../b/.ac.mod.md
1253
+
1254
+ ## Commands to Verify Module Functionality
1255
+
1256
+ Usually an executable command that can run a script or execute tests, for example:
1257
+
1258
+ ```
1259
+ node --experimental-transform-types ./a/b/c.ts
1260
+ ```
1261
+
1262
+ Or test execution commands:
1263
+
1264
+ ```
1265
+ pytest path/to/your/module/tests -v
1266
+ ```
1267
+ </ac_mod_md_example>
1268
+
1269
+
992
1270
  ====
993
1271
 
994
1272
  CAPABILITIES
@@ -1050,7 +1328,7 @@ class AgenticEdit:
1050
1328
  {% endfor %}
1051
1329
  </user_rule_or_document_files>
1052
1330
 
1053
- Make sure you always start your task by using the read_file tool to get the relevant RULE files listed in index.md based on the user's specific requirements.
1331
+ 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.
1054
1332
  {% endif %}
1055
1333
 
1056
1334
 
@@ -1255,9 +1533,9 @@ class AgenticEdit:
1255
1533
 
1256
1534
  self.current_conversations = conversations
1257
1535
 
1258
- # 计算初始对话窗口长度并触发事件
1536
+ # 计算初始对话窗口长度
1259
1537
  conversation_str = json.dumps(conversations, ensure_ascii=False)
1260
- current_tokens = count_tokens(conversation_str)
1538
+ current_tokens = count_tokens(conversation_str)
1261
1539
  yield WindowLengthChangeEvent(tokens_used=current_tokens)
1262
1540
 
1263
1541
  logger.info(
@@ -1289,12 +1567,12 @@ class AgenticEdit:
1289
1567
  f"Starting LLM interaction cycle. History size: {len(conversations)}")
1290
1568
 
1291
1569
  assistant_buffer = ""
1292
- logger.info("Initializing stream chat with LLM")
1570
+ logger.info("Initializing stream chat with LLM")
1293
1571
 
1294
- # ## 实际请求大模型
1572
+ # ## 实际请求大模型,并且我们会裁剪对话窗口长度
1295
1573
  llm_response_gen = stream_chat_with_continue(
1296
1574
  llm=self.llm,
1297
- conversations=conversations,
1575
+ conversations=self.agentic_pruner.prune_conversations(deepcopy(conversations)),
1298
1576
  llm_config={}, # Placeholder for future LLM configs
1299
1577
  args=self.args
1300
1578
  )
@@ -1920,513 +2198,183 @@ class AgenticEdit:
1920
2198
  def apply_changes(self):
1921
2199
  """
1922
2200
  Apply all tracked file changes to the original project directory.
1923
- """
1924
- diff_file_num = 0
1925
- if self.shadow_manager:
1926
- for (file_path, change) in self.get_all_file_changes().items():
1927
- # Ensure the directory exists before writing the file
1928
- dir_path = os.path.dirname(file_path)
1929
- if dir_path: # Ensure dir_path is not empty (for files in root)
1930
- os.makedirs(dir_path, exist_ok=True)
1931
-
1932
- with open(file_path, 'w', encoding='utf-8') as f:
1933
- f.write(change.content)
1934
- diff_file_num = len(self.get_all_file_changes())
1935
- else:
1936
- changes = self.checkpoint_manager.get_changes_by_group(self.args.event_file)
1937
- diff_file_num = len(changes)
1938
-
1939
- if diff_file_num > 0:
1940
- if not self.args.skip_commit:
1941
- try:
1942
- file_name = os.path.basename(self.args.file)
1943
- commit_result = git_utils.commit_changes(
1944
- self.args.source_dir,
1945
- f"{self.args.query}\nauto_coder_{file_name}",
1946
- )
1947
-
1948
- get_event_manager(self.args.event_file).write_result(
1949
- EventContentCreator.create_result(
1950
- content={
1951
- "have_commit":commit_result.success,
1952
- "commit_hash":commit_result.commit_hash,
1953
- "diff_file_num":diff_file_num,
1954
- "event_file":self.args.event_file
1955
- }), metadata=EventMetadata(
1956
- action_file=self.args.file,
1957
- is_streaming=False,
1958
- path="/agent/edit/apply_changes",
1959
- stream_out_type="/agent/edit").to_dict())
2201
+ """
2202
+ if not self.args.skip_commit:
2203
+ try:
2204
+ file_name = os.path.basename(self.args.file)
2205
+ commit_result = git_utils.commit_changes(
2206
+ self.args.source_dir,
2207
+ f"{self.args.query}\nauto_coder_{file_name}",
2208
+ )
2209
+
2210
+ get_event_manager(self.args.event_file).write_result(
2211
+ EventContentCreator.create_result(
2212
+ content={
2213
+ "have_commit":commit_result.success,
2214
+ "commit_hash":commit_result.commit_hash,
2215
+ "diff_file_num":len(commit_result.changed_files),
2216
+ "event_file":self.args.event_file
2217
+ }), metadata=EventMetadata(
2218
+ action_file=self.args.file,
2219
+ is_streaming=False,
2220
+ path="/agent/edit/apply_changes",
2221
+ stream_out_type="/agent/edit").to_dict())
2222
+
2223
+ action_yml_file_manager = ActionYmlFileManager(
2224
+ self.args.source_dir)
2225
+ action_file_name = os.path.basename(self.args.file)
2226
+ add_updated_urls = []
2227
+ commit_result.changed_files
2228
+ for file in commit_result.changed_files:
2229
+ add_updated_urls.append(
2230
+ os.path.join(self.args.source_dir, file))
2231
+
2232
+ self.args.add_updated_urls = add_updated_urls
2233
+ update_yaml_success = action_yml_file_manager.update_yaml_field(
2234
+ action_file_name, "add_updated_urls", add_updated_urls)
2235
+ if not update_yaml_success:
2236
+ self.printer.print_in_terminal(
2237
+ "yaml_save_error", style="red", yaml_file=action_file_name)
2238
+
2239
+ if self.args.enable_active_context:
2240
+ active_context_manager = ActiveContextManager(
2241
+ self.llm, self.args.source_dir)
2242
+ task_id = active_context_manager.process_changes(
2243
+ self.args)
2244
+ self.printer.print_in_terminal("active_context_background_task",
2245
+ style="blue",
2246
+ task_id=task_id)
2247
+ git_utils.print_commit_info(commit_result=commit_result)
2248
+
2249
+ # 检查是否需要创建 Pull Request
2250
+ if self.conversation_config and self.conversation_config.pull_request:
2251
+ self._create_pull_request(commit_result)
1960
2252
 
1961
- action_yml_file_manager = ActionYmlFileManager(
1962
- self.args.source_dir)
1963
- action_file_name = os.path.basename(self.args.file)
1964
- add_updated_urls = []
1965
- commit_result.changed_files
1966
- for file in commit_result.changed_files:
1967
- add_updated_urls.append(
1968
- os.path.join(self.args.source_dir, file))
1969
-
1970
- self.args.add_updated_urls = add_updated_urls
1971
- update_yaml_success = action_yml_file_manager.update_yaml_field(
1972
- action_file_name, "add_updated_urls", add_updated_urls)
1973
- if not update_yaml_success:
1974
- self.printer.print_in_terminal(
1975
- "yaml_save_error", style="red", yaml_file=action_file_name)
1976
-
1977
- if self.args.enable_active_context:
1978
- active_context_manager = ActiveContextManager(
1979
- self.llm, self.args.source_dir)
1980
- task_id = active_context_manager.process_changes(
1981
- self.args)
1982
- self.printer.print_in_terminal("active_context_background_task",
1983
- style="blue",
1984
- task_id=task_id)
1985
- git_utils.print_commit_info(commit_result=commit_result)
1986
- except Exception as e:
1987
- self.printer.print_str_in_terminal(
1988
- self.git_require_msg(
1989
- source_dir=self.args.source_dir, error=str(e)),
1990
- style="red"
1991
- )
2253
+ except Exception as e:
2254
+ self.printer.print_str_in_terminal(
2255
+ str(e),
2256
+ style="red"
2257
+ )
1992
2258
 
1993
-
1994
- def run_in_terminal(self, request: AgenticEditRequest):
2259
+ def _create_pull_request(self, commit_result):
1995
2260
  """
1996
- Runs the agentic edit process based on the request and displays
1997
- the interaction streamingly in the terminal using Rich.
1998
- """
1999
- import json
2000
- console = Console()
2001
- project_name = os.path.basename(os.path.abspath(self.args.source_dir))
2002
-
2003
- if self.conversation_config.action == "list":
2004
- conversations = self.conversation_manager.list_conversations()
2005
- # 只保留 conversation_id 和 name 字段
2006
- filtered_conversations = []
2007
- for conv in conversations:
2008
- filtered_conv = {
2009
- "conversation_id": conv.get("conversation_id"),
2010
- "name": conv.get("name")
2011
- }
2012
- filtered_conversations.append(filtered_conv)
2013
-
2014
- # 格式化 JSON 输出,使用 JSON 格式渲染而不是 Markdown
2015
- json_str = json.dumps(filtered_conversations, ensure_ascii=False, indent=4)
2016
- console.print(Panel(json_str,
2017
- title="🏁 Task Completion", border_style="green", title_align="left"))
2018
- return
2261
+ 创建 Pull Request(如果配置启用)
2019
2262
 
2020
-
2021
- if self.conversation_config.action == "new" and not request.user_input.strip():
2022
- console.print(Panel(Markdown(f"New conversation created: {self.conversation_manager.get_current_conversation_id()}"),
2023
- title="🏁 Task Completion", border_style="green", title_align="left"))
2024
- return
2025
-
2026
- console.rule(f"[bold cyan]Starting Agentic Edit: {project_name}[/]")
2027
- console.print(Panel(
2028
- f"[bold]{get_message('/agent/edit/user_query')}:[/bold]\n{request.user_input}", title=get_message("/agent/edit/objective"), border_style="blue"))
2029
-
2030
- # 用于累计TokenUsageEvent数据
2031
- accumulated_token_usage = {
2032
- "model_name": "",
2033
- "input_tokens": 0,
2034
- "output_tokens": 0,
2035
- "input_cost": 0.0,
2036
- "output_cost": 0.0
2037
- }
2038
-
2263
+ Args:
2264
+ commit_result: Git commit 结果对象
2265
+ """
2039
2266
  try:
2040
- self.apply_pre_changes()
2041
- event_stream = self.analyze(request)
2042
- for event in event_stream:
2043
- if isinstance(event, ConversationIdEvent):
2044
- console.print(f"[dim]Conversation ID: {event.conversation_id}[/dim]")
2045
- continue
2046
- if isinstance(event, TokenUsageEvent):
2047
- last_meta: SingleOutputMeta = event.usage
2048
- # Get model info for pricing
2049
- from autocoder.utils import llms as llm_utils
2050
- model_name = ",".join(llm_utils.get_llm_names(self.llm))
2051
- model_info = llm_utils.get_model_info(
2052
- model_name, self.args.product_mode) or {}
2053
- input_price = model_info.get(
2054
- "input_price", 0.0) if model_info else 0.0
2055
- output_price = model_info.get(
2056
- "output_price", 0.0) if model_info else 0.0
2057
-
2058
- # Calculate costs
2059
- input_cost = (last_meta.input_tokens_count *
2060
- input_price) / 1000000 # Convert to millions
2061
- # Convert to millions
2062
- output_cost = (
2063
- last_meta.generated_tokens_count * output_price) / 1000000
2064
-
2065
- # 添加日志记录
2066
- logger.info(f"Token Usage: Model={model_name}, Input Tokens={last_meta.input_tokens_count}, Output Tokens={last_meta.generated_tokens_count}, Input Cost=${input_cost:.6f}, Output Cost=${output_cost:.6f}")
2067
-
2068
- # 累计token使用情况
2069
- accumulated_token_usage["model_name"] = model_name
2070
- accumulated_token_usage["input_tokens"] += last_meta.input_tokens_count
2071
- accumulated_token_usage["output_tokens"] += last_meta.generated_tokens_count
2072
- accumulated_token_usage["input_cost"] += input_cost
2073
- accumulated_token_usage["output_cost"] += output_cost
2074
-
2075
- elif isinstance(event, WindowLengthChangeEvent):
2076
- # 显示当前会话的token数量
2077
- logger.info(f"当前会话总 tokens: {event.tokens_used}")
2078
- console.print(f"[dim]当前会话总 tokens: {event.tokens_used}[/dim]")
2079
-
2080
- elif isinstance(event, LLMThinkingEvent):
2081
- # Render thinking within a less prominent style, maybe grey?
2082
- console.print(f"[grey50]{event.text}[/grey50]", end="")
2083
- elif isinstance(event, LLMOutputEvent):
2084
- # Print regular LLM output, potentially as markdown if needed later
2085
- console.print(event.text, end="")
2086
- elif isinstance(event, ToolCallEvent):
2087
- # Skip displaying AttemptCompletionTool's tool call
2088
- if isinstance(event.tool, AttemptCompletionTool):
2089
- continue # Do not display AttemptCompletionTool tool call
2090
-
2091
- tool_name = type(event.tool).__name__
2092
- # Use the new internationalized display function
2093
- display_content = get_tool_display_message(event.tool)
2094
- console.print(Panel(
2095
- display_content, title=f"🛠️ Action: {tool_name}", border_style="blue", title_align="left"))
2096
-
2097
- elif isinstance(event, ToolResultEvent):
2098
- # Skip displaying AttemptCompletionTool's result
2099
- if event.tool_name == "AttemptCompletionTool":
2100
- continue # Do not display AttemptCompletionTool result
2101
-
2102
- if event.tool_name == "PlanModeRespondTool":
2103
- continue
2104
-
2105
- result = event.result
2106
- title = f"✅ Tool Result: {event.tool_name}" if result.success else f"❌ Tool Result: {event.tool_name}"
2107
- border_style = "green" if result.success else "red"
2108
- base_content = f"[bold]Status:[/bold] {'Success' if result.success else 'Failure'}\n"
2109
- base_content += f"[bold]Message:[/bold] {result.message}\n"
2110
-
2111
- def _format_content(content):
2112
- if len(content) > 200:
2113
- return f"{content[:100]}\n...\n{content[-100:]}"
2114
- else:
2115
- return content
2116
-
2117
- # Prepare panel for base info first
2118
- panel_content = [base_content]
2119
- syntax_content = None
2267
+ # 获取当前分支名
2268
+ current_branch = git_utils.get_current_branch(self.args.source_dir)
2269
+ if not current_branch:
2270
+ logger.warning(get_message("/agent/edit/pull_request/branch_name_failed"))
2271
+ return
2272
+
2273
+ # 准备 PR 标题和描述
2274
+ query = self.args.query or get_message("/agent/edit/pull_request/default_query")
2275
+ pr_title = get_message_with_format("/agent/edit/pull_request/title", query="{query[0:40]}...")
2276
+
2277
+ # 构建 PR 描述
2278
+ file_list = ""
2279
+ if commit_result.changed_files:
2280
+ for file_path in commit_result.changed_files:
2281
+ file_list += f"- `{file_path}`\n"
2282
+
2283
+ pr_description = get_message_with_format(
2284
+ "/agent/edit/pull_request/description",
2285
+ query=query,
2286
+ file_count=len(commit_result.changed_files or []),
2287
+ commit_hash=commit_result.commit_hash,
2288
+ file_list=file_list.strip(),
2289
+ source_branch=current_branch,
2290
+ target_branch="main",
2291
+ timestamp=time.strftime('%Y-%m-%d %H:%M:%S')
2292
+ )
2120
2293
 
2121
- if result.content is not None:
2122
- content_str = ""
2123
- try:
2124
- if isinstance(result.content, (dict, list)):
2125
- import json
2126
- content_str = json.dumps(
2127
- result.content, indent=2, ensure_ascii=False)
2128
- syntax_content = Syntax(
2129
- content_str, "json", theme="default", line_numbers=False)
2130
- elif isinstance(result.content, str) and ('\n' in result.content or result.content.strip().startswith('<')):
2131
- # Heuristic for code or XML/HTML
2132
- lexer = "python" # Default guess
2133
- if event.tool_name == "ReadFileTool" and isinstance(event.result.message, str):
2134
- # Try to guess lexer from file extension in message
2135
- if ".py" in event.result.message:
2136
- lexer = "python"
2137
- elif ".js" in event.result.message:
2138
- lexer = "javascript"
2139
- elif ".ts" in event.result.message:
2140
- lexer = "typescript"
2141
- elif ".html" in event.result.message:
2142
- lexer = "html"
2143
- elif ".css" in event.result.message:
2144
- lexer = "css"
2145
- elif ".json" in event.result.message:
2146
- lexer = "json"
2147
- elif ".xml" in event.result.message:
2148
- lexer = "xml"
2149
- elif ".md" in event.result.message:
2150
- lexer = "markdown"
2151
- else:
2152
- lexer = "text" # Fallback lexer
2153
- elif event.tool_name == "ExecuteCommandTool":
2154
- lexer = "shell"
2155
- else:
2156
- lexer = "text"
2157
-
2158
- syntax_content = Syntax(
2159
- _format_content(result.content), lexer, theme="default", line_numbers=True)
2160
- else:
2161
- content_str = str(result.content)
2162
- # Append simple string content directly
2163
- panel_content.append(
2164
- _format_content(content_str))
2165
- except Exception as e:
2166
- logger.warning(
2167
- f"Error formatting tool result content: {e}")
2168
- panel_content.append(
2169
- # Fallback
2170
- _format_content(str(result.content)))
2171
-
2172
- # Print the base info panel
2173
- console.print(Panel("\n".join(
2174
- panel_content), title=title, border_style=border_style, title_align="left"))
2175
- # Print syntax highlighted content separately if it exists
2176
- if syntax_content:
2177
- console.print(syntax_content)
2178
- elif isinstance(event, PlanModeRespondEvent):
2179
- console.print(Panel(Markdown(event.completion.response),
2180
- title="🏁 Task Completion", border_style="green", title_align="left"))
2181
-
2182
- elif isinstance(event, CompletionEvent):
2183
- # 在这里完成实际合并
2184
- try:
2185
- self.apply_changes()
2186
- except Exception as e:
2187
- logger.exception(
2188
- f"Error merging shadow changes to project: {e}")
2189
-
2190
- console.print(Panel(Markdown(event.completion.result),
2191
- title="🏁 Task Completion", border_style="green", title_align="left"))
2192
- if event.completion.command:
2193
- console.print(
2194
- f"[dim]Suggested command:[/dim] [bold cyan]{event.completion.command}[/]")
2195
- elif isinstance(event, ErrorEvent):
2196
- console.print(Panel(
2197
- f"[bold red]Error:[/bold red] {event.message}", title="🔥 Error", border_style="red", title_align="left"))
2198
-
2199
- time.sleep(0.1) # Small delay for better visual flow
2200
-
2201
- # 在处理完所有事件后打印累计的token使用情况
2202
- if accumulated_token_usage["input_tokens"] > 0:
2203
- self.printer.print_in_terminal(
2204
- "code_generation_complete",
2205
- duration=0.0,
2206
- input_tokens=accumulated_token_usage["input_tokens"],
2207
- output_tokens=accumulated_token_usage["output_tokens"],
2208
- input_cost=accumulated_token_usage["input_cost"],
2209
- output_cost=accumulated_token_usage["output_cost"],
2210
- speed=0.0,
2211
- model_names=accumulated_token_usage["model_name"],
2212
- sampling_count=1
2294
+ # 创建 Pull Request
2295
+ logger.info(get_message_with_format("/agent/edit/pull_request/creating", title=pr_title))
2296
+
2297
+ result = create_pull_request(
2298
+ repo_path=self.args.source_dir,
2299
+ title=pr_title,
2300
+ description=pr_description,
2301
+ )
2302
+
2303
+ if result.success:
2304
+ logger.info(get_message("/agent/edit/pull_request/success"))
2305
+ logger.info(f"PR URL: {result.pr_url}")
2306
+ logger.info(f"PR 编号: {result.pr_number}")
2307
+
2308
+ # 打印成功信息到终端
2309
+ self.printer.print_str_in_terminal(
2310
+ get_message("/agent/edit/pull_request/success"),
2311
+ style="green"
2213
2312
  )
2313
+ self.printer.print_str_in_terminal(f"PR URL: {result.pr_url}")
2314
+ self.printer.print_str_in_terminal(f"PR 编号: {result.pr_number}")
2214
2315
 
2215
- except Exception as e:
2216
- # 在处理异常时也打印累计的token使用情况
2217
- if accumulated_token_usage["input_tokens"] > 0:
2218
- self.printer.print_in_terminal(
2219
- "code_generation_complete",
2220
- duration=0.0,
2221
- input_tokens=accumulated_token_usage["input_tokens"],
2222
- output_tokens=accumulated_token_usage["output_tokens"],
2223
- input_cost=accumulated_token_usage["input_cost"],
2224
- output_cost=accumulated_token_usage["output_cost"],
2225
- speed=0.0,
2226
- model_names=accumulated_token_usage["model_name"],
2227
- sampling_count=1
2316
+ # 写入事件日志
2317
+ get_event_manager(self.args.event_file).write_result(
2318
+ EventContentCreator.create_result(
2319
+ content={
2320
+ "success": True,
2321
+ "pr_url": result.pr_url,
2322
+ "pr_number": result.pr_number,
2323
+ "source_branch": current_branch,
2324
+ "target_branch": "main",
2325
+ "platform": result.platform.value if result.platform else "unknown"
2326
+ }),
2327
+ metadata=EventMetadata(
2328
+ action_file=self.args.file,
2329
+ is_streaming=False,
2330
+ path="/agent/edit/pull_request_created",
2331
+ stream_out_type="/agent/edit"
2332
+ ).to_dict()
2228
2333
  )
2229
2334
 
2230
- logger.exception(
2231
- "An unexpected error occurred during agent execution:")
2232
- console.print(Panel(
2233
- f"[bold red]FATAL ERROR:[/bold red]\n{str(e)}", title="🔥 System Error", border_style="red"))
2234
- raise e
2235
- finally:
2236
- console.rule("[bold cyan]Agentic Edit Finished[/]")
2237
-
2238
- def run(self, request: AgenticEditRequest):
2239
- try:
2240
- event_stream = self.analyze(request)
2241
- for agent_event in event_stream:
2242
- yield agent_event
2335
+ else:
2336
+ error_msg = get_message_with_format("/agent/edit/pull_request/failed", error=result.error_message)
2337
+ logger.error(error_msg)
2338
+
2339
+ # 打印错误信息到终端
2340
+ self.printer.print_str_in_terminal(error_msg, style="red")
2341
+
2342
+ # 写入错误事件日志
2343
+ get_event_manager(self.args.event_file).write_error(
2344
+ EventContentCreator.create_error(
2345
+ error_code="PR_CREATION_FAILED",
2346
+ error_message=result.error_message,
2347
+ details={
2348
+ "source_branch": current_branch,
2349
+ "target_branch": "main"
2350
+ }
2351
+ ).to_dict(),
2352
+ metadata=EventMetadata(
2353
+ action_file=self.args.file,
2354
+ is_streaming=False,
2355
+ path="/agent/edit/pull_request_error",
2356
+ stream_out_type="/agent/edit"
2357
+ ).to_dict()
2358
+ )
2243
2359
 
2244
2360
  except Exception as e:
2245
- logger.exception(
2246
- "An unexpected error occurred during agent execution: {e}")
2247
- raise e
2248
-
2249
-
2250
- def run_with_events(self, request: AgenticEditRequest):
2251
- """
2252
- Runs the agentic edit process, converting internal events to the
2253
- standard event system format and writing them using the event manager.
2254
- """
2255
- event_manager = get_event_manager(self.args.event_file)
2256
- self.apply_pre_changes()
2257
-
2258
- try:
2259
- event_stream = self.analyze(request)
2260
- for agent_event in event_stream:
2261
- content = None
2262
- metadata = EventMetadata(
2361
+ error_msg = get_message_with_format("/agent/edit/pull_request/exception", error=str(e))
2362
+ logger.exception(error_msg)
2363
+
2364
+ # 打印异常信息到终端
2365
+ self.printer.print_str_in_terminal(error_msg, style="red")
2366
+
2367
+ # 写入异常事件日志
2368
+ get_event_manager(self.args.event_file).write_error(
2369
+ EventContentCreator.create_error(
2370
+ error_code="PR_CREATION_EXCEPTION",
2371
+ error_message=get_message_with_format("/agent/edit/pull_request/exception", error=str(e)),
2372
+ details={"exception_type": type(e).__name__}
2373
+ ).to_dict(),
2374
+ metadata=EventMetadata(
2263
2375
  action_file=self.args.file,
2264
2376
  is_streaming=False,
2265
- stream_out_type="/agent/edit")
2266
-
2267
- if isinstance(agent_event, LLMThinkingEvent):
2268
- content = EventContentCreator.create_stream_thinking(
2269
- content=agent_event.text)
2270
- metadata.is_streaming = True
2271
- metadata.path = "/agent/edit/thinking"
2272
- event_manager.write_stream(
2273
- content=content.to_dict(), metadata=metadata.to_dict())
2274
- elif isinstance(agent_event, LLMOutputEvent):
2275
- content = EventContentCreator.create_stream_content(
2276
- content=agent_event.text)
2277
- metadata.is_streaming = True
2278
- metadata.path = "/agent/edit/output"
2279
- event_manager.write_stream(content=content.to_dict(),
2280
- metadata=metadata.to_dict())
2281
- elif isinstance(agent_event, ToolCallEvent):
2282
- tool_name = type(agent_event.tool).__name__
2283
- metadata.path = "/agent/edit/tool/call"
2284
- content = EventContentCreator.create_result(
2285
- content={
2286
- "tool_name": tool_name,
2287
- **agent_event.tool.model_dump()
2288
- },
2289
- metadata={}
2290
- )
2291
- event_manager.write_result(
2292
- content=content.to_dict(), metadata=metadata.to_dict())
2293
- elif isinstance(agent_event, ToolResultEvent):
2294
- metadata.path = "/agent/edit/tool/result"
2295
- content = EventContentCreator.create_result(
2296
- content={
2297
- "tool_name": agent_event.tool_name,
2298
- **agent_event.result.model_dump()
2299
- },
2300
- metadata={}
2301
- )
2302
- event_manager.write_result(
2303
- content=content.to_dict(), metadata=metadata.to_dict())
2304
- elif isinstance(agent_event, PlanModeRespondEvent):
2305
- metadata.path = "/agent/edit/plan_mode_respond"
2306
- content = EventContentCreator.create_markdown_result(
2307
- content=agent_event.completion.response,
2308
- metadata={}
2309
- )
2310
- event_manager.write_result(
2311
- content=content.to_dict(), metadata=metadata.to_dict())
2312
-
2313
- elif isinstance(agent_event, TokenUsageEvent):
2314
- last_meta: SingleOutputMeta = agent_event.usage
2315
- # Get model info for pricing
2316
- from autocoder.utils import llms as llm_utils
2317
- model_name = ",".join(llm_utils.get_llm_names(self.llm))
2318
- model_info = llm_utils.get_model_info(
2319
- model_name, self.args.product_mode) or {}
2320
- input_price = model_info.get(
2321
- "input_price", 0.0) if model_info else 0.0
2322
- output_price = model_info.get(
2323
- "output_price", 0.0) if model_info else 0.0
2324
-
2325
- # Calculate costs
2326
- input_cost = (last_meta.input_tokens_count *
2327
- input_price) / 1000000 # Convert to millions
2328
- # Convert to millions
2329
- output_cost = (
2330
- last_meta.generated_tokens_count * output_price) / 1000000
2331
-
2332
- # 添加日志记录
2333
- logger.info(f"Token Usage Details: Model={model_name}, Input Tokens={last_meta.input_tokens_count}, Output Tokens={last_meta.generated_tokens_count}, Input Cost=${input_cost:.6f}, Output Cost=${output_cost:.6f}")
2334
-
2335
- # 直接将每次的 TokenUsageEvent 写入到事件中
2336
- metadata.path = "/agent/edit/token_usage"
2337
- content = EventContentCreator.create_result(content=EventContentCreator.ResultTokenStatContent(
2338
- model_name=model_name,
2339
- elapsed_time=0.0,
2340
- first_token_time=last_meta.first_token_time,
2341
- input_tokens=last_meta.input_tokens_count,
2342
- output_tokens=last_meta.generated_tokens_count,
2343
- input_cost=input_cost,
2344
- output_cost=output_cost
2345
- ).to_dict())
2346
- event_manager.write_result(content=content.to_dict(), metadata=metadata.to_dict())
2347
-
2348
-
2349
- elif isinstance(agent_event, CompletionEvent):
2350
- # 在这里完成实际合并
2351
- try:
2352
- self.apply_changes()
2353
- except Exception as e:
2354
- logger.exception(
2355
- f"Error merging shadow changes to project: {e}")
2356
-
2357
- metadata.path = "/agent/edit/completion"
2358
- content = EventContentCreator.create_completion(
2359
- success_code="AGENT_COMPLETE",
2360
- success_message="Agent attempted task completion.",
2361
- result={
2362
- "response": agent_event.completion.result
2363
- }
2364
- )
2365
- event_manager.write_completion(
2366
- content=content.to_dict(), metadata=metadata.to_dict())
2367
- elif isinstance(agent_event, WindowLengthChangeEvent):
2368
- # 处理窗口长度变化事件
2369
- metadata.path = "/agent/edit/window_length_change"
2370
- content = EventContentCreator.create_result(
2371
- content={
2372
- "tokens_used": agent_event.tokens_used
2373
- },
2374
- metadata={}
2375
- )
2376
- event_manager.write_result(
2377
- content=content.to_dict(), metadata=metadata.to_dict())
2378
-
2379
- # 记录日志
2380
- logger.info(f"当前会话总 tokens: {agent_event.tokens_used}")
2381
-
2382
- elif isinstance(agent_event, ConversationIdEvent):
2383
- metadata.path = "/agent/edit/conversation_id"
2384
- content = EventContentCreator.create_result(
2385
- content={
2386
- "conversation_id": agent_event.conversation_id
2387
- },
2388
- metadata={}
2389
- )
2390
- event_manager.write_result(content=content.to_dict(), metadata=metadata.to_dict())
2391
-
2392
- elif isinstance(agent_event, ErrorEvent):
2393
- metadata.path = "/agent/edit/error"
2394
- content = EventContentCreator.create_error(
2395
- error_code="AGENT_ERROR",
2396
- error_message=agent_event.message,
2397
- details={"agent_event_type": "ErrorEvent"}
2398
- )
2399
- event_manager.write_error(
2400
- content=content.to_dict(), metadata=metadata.to_dict())
2401
- else:
2402
- metadata.path = "/agent/edit/error"
2403
- logger.warning(
2404
- f"Unhandled agent event type: {type(agent_event)}")
2405
- content = EventContentCreator.create_error(
2406
- error_code="AGENT_ERROR",
2407
- error_message=f"Unhandled agent event type: {type(agent_event)}",
2408
- details={"agent_event_type": type(
2409
- agent_event).__name__}
2410
- )
2411
- event_manager.write_error(
2412
- content=content.to_dict(), metadata=metadata.to_dict())
2413
-
2414
- except Exception as e:
2415
- logger.exception(
2416
- "An unexpected error occurred during agent execution:")
2417
- metadata = EventMetadata(
2418
- action_file=self.args.file,
2419
- is_streaming=False,
2420
- stream_out_type="/agent/edit/error")
2421
-
2422
- # 发送累计的TokenUsageEvent数据(在错误情况下也需要发送)
2423
-
2424
- error_content = EventContentCreator.create_error(
2425
- error_code="AGENT_FATAL_ERROR",
2426
- error_message=f"An unexpected error occurred: {str(e)}",
2427
- details={"exception_type": type(e).__name__}
2428
- )
2429
- event_manager.write_error(
2430
- content=error_content.to_dict(), metadata=metadata.to_dict())
2431
- # Re-raise the exception if needed, or handle appropriately
2432
- raise e
2377
+ path="/agent/edit/pull_request_exception",
2378
+ stream_out_type="/agent/edit"
2379
+ ).to_dict()
2380
+ )