auto-coder 0.1.337__py3-none-any.whl → 0.1.338__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.337.dist-info → auto_coder-0.1.338.dist-info}/METADATA +1 -1
- {auto_coder-0.1.337.dist-info → auto_coder-0.1.338.dist-info}/RECORD +14 -14
- autocoder/auto_coder_runner.py +3 -1
- autocoder/common/auto_coder_lang.py +36 -0
- autocoder/common/v2/agent/agentic_edit.py +88 -42
- autocoder/common/v2/agent/agentic_edit_conversation.py +73 -8
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +17 -8
- autocoder/common/v2/agent/agentic_edit_types.py +5 -0
- autocoder/common/v2/agent/agentic_tool_display.py +1 -1
- autocoder/version.py +1 -1
- {auto_coder-0.1.337.dist-info → auto_coder-0.1.338.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.337.dist-info → auto_coder-0.1.338.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.337.dist-info → auto_coder-0.1.338.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.337.dist-info → auto_coder-0.1.338.dist-info}/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ autocoder/auto_coder_lang.py,sha256=Rtupq6N3_HT7JRhDKdgCBcwRaiAnyCOR_Gsp4jUomrI,
|
|
|
4
4
|
autocoder/auto_coder_rag.py,sha256=NesRm7sIJrRQL1xxm_lbMtM7gi-KrYv9f26RfBuloZE,35386
|
|
5
5
|
autocoder/auto_coder_rag_client_mcp.py,sha256=QRxUbjc6A8UmDMQ8lXgZkjgqtq3lgKYeatJbDY6rSo0,6270
|
|
6
6
|
autocoder/auto_coder_rag_mcp.py,sha256=-RrjNwFaS2e5v8XDIrKR-zlUNUE8UBaeOtojffBrvJo,8521
|
|
7
|
-
autocoder/auto_coder_runner.py,sha256=
|
|
7
|
+
autocoder/auto_coder_runner.py,sha256=Xrzeo9u7UIvIjKgaV12O-XItl10dhjogp-7TNIvqAP8,111518
|
|
8
8
|
autocoder/auto_coder_server.py,sha256=bLORGEclcVdbBVfM140JCI8WtdrU0jbgqdJIVVupiEU,20578
|
|
9
9
|
autocoder/benchmark.py,sha256=Ypomkdzd1T3GE6dRICY3Hj547dZ6_inqJbBJIp5QMco,4423
|
|
10
10
|
autocoder/chat_auto_coder.py,sha256=CthuvdjVjTQOVv-zREsl8OCsZHPSP9OQcIgHULrW2Ro,25842
|
|
@@ -14,7 +14,7 @@ autocoder/command_parser.py,sha256=fx1g9E6GaM273lGTcJqaFQ-hoksS_Ik2glBMnVltPCE,1
|
|
|
14
14
|
autocoder/lang.py,sha256=PFtATuOhHRnfpqHQkXr6p4C893JvpsgwTMif3l-GEi0,14321
|
|
15
15
|
autocoder/models.py,sha256=_SCar82QIeBFTZZBdM2jPS6atKVhHnvE0gX3V0CsxD4,11590
|
|
16
16
|
autocoder/run_context.py,sha256=IUfSO6_gp2Wt1blFWAmOpN0b0nDrTTk4LmtCYUBIoro,1643
|
|
17
|
-
autocoder/version.py,sha256=
|
|
17
|
+
autocoder/version.py,sha256=oUXeUGWr7ewx0MgKWn_rfyWO62ZnbdWizzFCRsj8frY,23
|
|
18
18
|
autocoder/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
autocoder/agent/agentic_edit.py,sha256=XsfePZ-t6M-uBSdG1VLZXk1goqXk2HPeJ_A8IYyBuWQ,58896
|
|
20
20
|
autocoder/agent/agentic_edit_types.py,sha256=oFcDd_cxJ2yH9Ed1uTpD3BipudgoIEWDMPb5pAkq4gI,3288
|
|
@@ -54,7 +54,7 @@ autocoder/common/action_yml_file_manager.py,sha256=DdF5P1R_B_chCnnqoA2IgogakWLZk
|
|
|
54
54
|
autocoder/common/anything2images.py,sha256=0ILBbWzY02M-CiWB-vzuomb_J1hVdxRcenAfIrAXq9M,25283
|
|
55
55
|
autocoder/common/anything2img.py,sha256=iZQmg8srXlD7N5uGl5b_ONKJMBjYoW8kPmokkG6ISF0,10118
|
|
56
56
|
autocoder/common/audio.py,sha256=Kn9nWKQddWnUrAz0a_ZUgjcu4VUU_IcZBigT7n3N3qc,7439
|
|
57
|
-
autocoder/common/auto_coder_lang.py,sha256=
|
|
57
|
+
autocoder/common/auto_coder_lang.py,sha256=ozoGTy4ZFn3YsO5zWhvAGCu54mK4LtnRfC2yCvrMc_8,42462
|
|
58
58
|
autocoder/common/auto_configure.py,sha256=D4N-fl9v8bKM5-Ds-uhkC2uGDmHH_ZjLJ759F8KXMKs,13129
|
|
59
59
|
autocoder/common/buildin_tokenizer.py,sha256=L7d5t39ZFvUd6EoMPXUhYK1toD0FHlRH1jtjKRGokWU,1236
|
|
60
60
|
autocoder/common/chunk_validation.py,sha256=BrR_ZWavW8IANuueEE7hS8NFAwEvm8TX34WnPx_1hs8,3030
|
|
@@ -126,10 +126,10 @@ autocoder/common/v2/code_editblock_manager.py,sha256=G0CIuV9Ki0FqMLnpA8nBT4pnkCN
|
|
|
126
126
|
autocoder/common/v2/code_manager.py,sha256=C403bS-f6urixwitlKHcml-J03hci-UyNwHJOqBiY6Q,9182
|
|
127
127
|
autocoder/common/v2/code_strict_diff_manager.py,sha256=v-J1kDyLg7tLGg_6_lbO9S4fNkx7M_L8Xr2G7fPptiU,9347
|
|
128
128
|
autocoder/common/v2/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
129
|
-
autocoder/common/v2/agent/agentic_edit.py,sha256=
|
|
130
|
-
autocoder/common/v2/agent/agentic_edit_conversation.py,sha256=
|
|
131
|
-
autocoder/common/v2/agent/agentic_edit_types.py,sha256=
|
|
132
|
-
autocoder/common/v2/agent/agentic_tool_display.py,sha256=
|
|
129
|
+
autocoder/common/v2/agent/agentic_edit.py,sha256=mw85tMint-m6MA7OrPmrwOOZw_uW_N7fboTGfXNQYcE,88790
|
|
130
|
+
autocoder/common/v2/agent/agentic_edit_conversation.py,sha256=2GZrw5f8Sh9GgUDnuFc2v7Q4syrm77kKEfXI6k6uEFY,7310
|
|
131
|
+
autocoder/common/v2/agent/agentic_edit_types.py,sha256=6qBLLmvdlcsbzrpMHsYQVIHqbOWubMXOnmkqTs1pBWQ,4629
|
|
132
|
+
autocoder/common/v2/agent/agentic_tool_display.py,sha256=M-fFfmCzAyYrT916tXbc8HZxbv4ePksR9WqvSrhcZIs,7345
|
|
133
133
|
autocoder/common/v2/agent/agentic_edit_tools/__init__.py,sha256=wGICCc1dYh07osB21j62zOQ9Ws0PyyOQ12UYRHmHrtI,1229
|
|
134
134
|
autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py,sha256=pjrukXjWXMIfUAUzoHzr7j2Onf1L7bxmjsUR1gGaFoA,2809
|
|
135
135
|
autocoder/common/v2/agent/agentic_edit_tools/attempt_completion_tool_resolver.py,sha256=82ZGKeRBSDKeead_XVBW4FxpiE-5dS7tBOk_3RZ6B5s,1511
|
|
@@ -139,7 +139,7 @@ autocoder/common/v2/agent/agentic_edit_tools/list_code_definition_names_tool_res
|
|
|
139
139
|
autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py,sha256=ERM5E7s2azQ8vcvogan4A_LZci8Pmhmxw1uQaNQhon4,5469
|
|
140
140
|
autocoder/common/v2/agent/agentic_edit_tools/plan_mode_respond_tool_resolver.py,sha256=SZwFUxK6d2BaKWqQXi_c3IVe2iffviF6VUXJA9T9sx0,1492
|
|
141
141
|
autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py,sha256=9Bh0KVbL0qiIqwChlb77biiBiETQ3zekxGe5Fj7hXAg,2800
|
|
142
|
-
autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py,sha256=
|
|
142
|
+
autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py,sha256=lpD4fCbVR8GTrynqXON69IjM94nPy3nuUL62Ashm5O4,7988
|
|
143
143
|
autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py,sha256=K-TcqY0z7nDupMkTRDAJdqW3z2Y_RUM_wUb-pOEVQRI,6044
|
|
144
144
|
autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py,sha256=wM2Xy4bcnD0TSLEmcM8rvvyyWenN5_KQnJMO6hJ8lTE,1716
|
|
145
145
|
autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py,sha256=UO4SrkDek3WDlRdlHH022W1roSNMdMcipJqDxRBlheM,3044
|
|
@@ -276,9 +276,9 @@ autocoder/utils/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
276
276
|
autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
277
277
|
autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=KW0mlmcHlStXi8-_6fXZ2-ifeJ5mgP0OV7DQFzCtIsw,14008
|
|
278
278
|
autocoder/utils/chat_auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
279
|
-
auto_coder-0.1.
|
|
280
|
-
auto_coder-0.1.
|
|
281
|
-
auto_coder-0.1.
|
|
282
|
-
auto_coder-0.1.
|
|
283
|
-
auto_coder-0.1.
|
|
284
|
-
auto_coder-0.1.
|
|
279
|
+
auto_coder-0.1.338.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
280
|
+
auto_coder-0.1.338.dist-info/METADATA,sha256=szlrczWaHSc5hCrxKrOcI6lPK2aeYHLQX-J42_mlg9o,2747
|
|
281
|
+
auto_coder-0.1.338.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
282
|
+
auto_coder-0.1.338.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
|
|
283
|
+
auto_coder-0.1.338.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
|
|
284
|
+
auto_coder-0.1.338.dist-info/RECORD,,
|
autocoder/auto_coder_runner.py
CHANGED
|
@@ -2835,7 +2835,9 @@ def auto_command(query: str,extra_args: Dict[str,Any]={}):
|
|
|
2835
2835
|
agent = AgenticEdit(llm=llm,args=args,files=SourceCodeList(sources=sources),
|
|
2836
2836
|
conversation_history=[],
|
|
2837
2837
|
memory_config=MemoryConfig(memory=memory,
|
|
2838
|
-
save_memory_func=save_memory), command_config=CommandConfig
|
|
2838
|
+
save_memory_func=save_memory), command_config=CommandConfig,
|
|
2839
|
+
conversation_name="current"
|
|
2840
|
+
)
|
|
2839
2841
|
agent.run_in_terminal(AgenticEditRequest(user_input=query))
|
|
2840
2842
|
return
|
|
2841
2843
|
|
|
@@ -837,6 +837,42 @@ MESSAGES = {
|
|
|
837
837
|
}
|
|
838
838
|
|
|
839
839
|
|
|
840
|
+
# 新增 ReplaceInFileToolResolver 国际化消息
|
|
841
|
+
MESSAGES.update({
|
|
842
|
+
"replace_in_file.access_denied": {
|
|
843
|
+
"en": "Error: Access denied. Attempted to modify file outside the project directory: {{file_path}}",
|
|
844
|
+
"zh": "错误:拒绝访问。尝试修改项目目录之外的文件:{{file_path}}"
|
|
845
|
+
},
|
|
846
|
+
"replace_in_file.file_not_found": {
|
|
847
|
+
"en": "Error: File not found at path: {{file_path}}",
|
|
848
|
+
"zh": "错误:未找到文件路径:{{file_path}}"
|
|
849
|
+
},
|
|
850
|
+
"replace_in_file.read_error": {
|
|
851
|
+
"en": "An error occurred while reading the file for replacement: {{error}}",
|
|
852
|
+
"zh": "读取待替换文件时发生错误:{{error}}"
|
|
853
|
+
},
|
|
854
|
+
"replace_in_file.no_valid_blocks": {
|
|
855
|
+
"en": "Error: No valid SEARCH/REPLACE blocks found in the provided diff.",
|
|
856
|
+
"zh": "错误:在提供的diff中未找到有效的SEARCH/REPLACE代码块。"
|
|
857
|
+
},
|
|
858
|
+
"replace_in_file.apply_failed": {
|
|
859
|
+
"en": "Failed to apply any changes. Errors:\n{{errors}}",
|
|
860
|
+
"zh": "未能应用任何更改。错误信息:\n{{errors}}"
|
|
861
|
+
},
|
|
862
|
+
"replace_in_file.apply_success": {
|
|
863
|
+
"en": "Successfully applied {{applied}}/{{total}} changes to file: {{file_path}}.",
|
|
864
|
+
"zh": "成功应用了 {{applied}}/{{total}} 个更改到文件:{{file_path}}。"
|
|
865
|
+
},
|
|
866
|
+
"replace_in_file.apply_success_with_warnings": {
|
|
867
|
+
"en": "Successfully applied {{applied}}/{{total}} changes to file: {{file_path}}.\nWarnings:\n{{errors}}",
|
|
868
|
+
"zh": "成功应用了 {{applied}}/{{total}} 个更改到文件:{{file_path}}。\n警告信息:\n{{errors}}"
|
|
869
|
+
},
|
|
870
|
+
"replace_in_file.write_error": {
|
|
871
|
+
"en": "An error occurred while writing the modified file: {{error}}",
|
|
872
|
+
"zh": "写入修改后的文件时发生错误:{{error}}"
|
|
873
|
+
}
|
|
874
|
+
})
|
|
875
|
+
|
|
840
876
|
def get_system_language():
|
|
841
877
|
try:
|
|
842
878
|
return locale.getdefaultlocale()[0][:2]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from autocoder.common.v2.agent.agentic_edit_conversation import AgenticConversation
|
|
1
2
|
from enum import Enum
|
|
2
3
|
from enum import Enum
|
|
3
4
|
import json
|
|
@@ -64,7 +65,7 @@ from autocoder.common.v2.agent.agentic_edit_types import (AgenticEditRequest, To
|
|
|
64
65
|
TOOL_MODEL_MAP,
|
|
65
66
|
# Event Types
|
|
66
67
|
LLMOutputEvent, LLMThinkingEvent, ToolCallEvent,
|
|
67
|
-
ToolResultEvent, CompletionEvent, ErrorEvent,TokenUsageEvent,
|
|
68
|
+
ToolResultEvent, CompletionEvent, PlanModeRespondEvent, ErrorEvent, TokenUsageEvent,
|
|
68
69
|
# Import specific tool types for display mapping
|
|
69
70
|
ReadFileTool, WriteToFileTool, ReplaceInFileTool, ExecuteCommandTool,
|
|
70
71
|
ListFilesTool, SearchFilesTool, ListCodeDefinitionNamesTool,
|
|
@@ -87,6 +88,7 @@ TOOL_RESOLVER_MAP: Dict[Type[BaseTool], Type[BaseToolResolver]] = {
|
|
|
87
88
|
UseMcpTool: UseMcpToolResolver,
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
|
|
90
92
|
# --- Tool Display Customization is now handled by agentic_tool_display.py ---
|
|
91
93
|
|
|
92
94
|
|
|
@@ -99,6 +101,7 @@ class AgenticEdit:
|
|
|
99
101
|
args: AutoCoderArgs,
|
|
100
102
|
memory_config: MemoryConfig,
|
|
101
103
|
command_config: Optional[CommandConfig] = None,
|
|
104
|
+
conversation_name: str = "current"
|
|
102
105
|
):
|
|
103
106
|
self.llm = llm
|
|
104
107
|
self.args = args
|
|
@@ -113,12 +116,15 @@ class AgenticEdit:
|
|
|
113
116
|
self.project_type_analyzer = ProjectTypeAnalyzer(
|
|
114
117
|
args=args, llm=self.llm)
|
|
115
118
|
|
|
119
|
+
self.conversation_manager = AgenticConversation(
|
|
120
|
+
args, self.conversation_history, conversation_name=conversation_name)
|
|
121
|
+
|
|
116
122
|
self.shadow_manager = ShadowManager(
|
|
117
123
|
args.source_dir, args.event_file, args.ignore_clean_shadows)
|
|
118
124
|
self.shadow_linter = ShadowLinter(self.shadow_manager, verbose=False)
|
|
119
125
|
self.shadow_compiler = ShadowCompiler(
|
|
120
|
-
self.shadow_manager, verbose=False)
|
|
121
|
-
|
|
126
|
+
self.shadow_manager, verbose=False)
|
|
127
|
+
|
|
122
128
|
self.mcp_server_info = ""
|
|
123
129
|
# try:
|
|
124
130
|
# self.mcp_server = get_mcp_server()
|
|
@@ -133,7 +139,7 @@ class AgenticEdit:
|
|
|
133
139
|
# logger.error(f"Error getting MCP server info: {str(e)}")
|
|
134
140
|
|
|
135
141
|
# 变更跟踪信息
|
|
136
|
-
# 格式: { file_path: FileChangeEntry(...) }
|
|
142
|
+
# 格式: { file_path: FileChangeEntry(...) }
|
|
137
143
|
self.file_changes: Dict[str, FileChangeEntry] = {}
|
|
138
144
|
|
|
139
145
|
def record_file_change(self, file_path: str, change_type: str, diff: Optional[str] = None, content: Optional[str] = None):
|
|
@@ -148,7 +154,8 @@ class AgenticEdit:
|
|
|
148
154
|
"""
|
|
149
155
|
entry = self.file_changes.get(file_path)
|
|
150
156
|
if entry is None:
|
|
151
|
-
entry = FileChangeEntry(
|
|
157
|
+
entry = FileChangeEntry(
|
|
158
|
+
type=change_type, diffs=[], content=content)
|
|
152
159
|
self.file_changes[file_path] = entry
|
|
153
160
|
else:
|
|
154
161
|
# 文件已经存在,可能之前是 added,现在又被 modified,或者多次 modified
|
|
@@ -185,8 +192,10 @@ class AgenticEdit:
|
|
|
185
192
|
for fname in files:
|
|
186
193
|
shadow_file_path = os.path.join(root, fname)
|
|
187
194
|
try:
|
|
188
|
-
project_file_path = self.shadow_manager.from_shadow_path(
|
|
189
|
-
|
|
195
|
+
project_file_path = self.shadow_manager.from_shadow_path(
|
|
196
|
+
shadow_file_path)
|
|
197
|
+
rel_path = os.path.relpath(
|
|
198
|
+
project_file_path, self.args.source_dir)
|
|
190
199
|
changed_files.append(rel_path)
|
|
191
200
|
except Exception:
|
|
192
201
|
# 非映射关系,忽略
|
|
@@ -391,7 +400,7 @@ class AgenticEdit:
|
|
|
391
400
|
Your query here
|
|
392
401
|
</query>
|
|
393
402
|
</use_mcp_tool>
|
|
394
|
-
|
|
403
|
+
|
|
395
404
|
{%if mcp_server_info %}
|
|
396
405
|
### MCP_SERVER_LIST
|
|
397
406
|
{{mcp_server_info}}
|
|
@@ -736,10 +745,14 @@ class AgenticEdit:
|
|
|
736
745
|
executes tools, and yields structured events for visualization until completion or error.
|
|
737
746
|
"""
|
|
738
747
|
system_prompt = self._analyze.prompt(request)
|
|
748
|
+
|
|
739
749
|
conversations = [
|
|
740
750
|
{"role": "system", "content": system_prompt},
|
|
741
|
-
|
|
742
|
-
|
|
751
|
+
] + self.conversation_manager.get_history()
|
|
752
|
+
conversations.append({
|
|
753
|
+
"role": "user", "content": request.user_input
|
|
754
|
+
})
|
|
755
|
+
self.conversation_manager.add_user_message(request.user_input)
|
|
743
756
|
logger.debug(
|
|
744
757
|
f"Initial conversation history size: {len(conversations)}")
|
|
745
758
|
|
|
@@ -749,17 +762,17 @@ class AgenticEdit:
|
|
|
749
762
|
f"Starting LLM interaction cycle. History size: {len(conversations)}")
|
|
750
763
|
tool_executed = False
|
|
751
764
|
assistant_buffer = ""
|
|
752
|
-
|
|
765
|
+
|
|
753
766
|
llm_response_gen = stream_chat_with_continue(
|
|
754
767
|
llm=self.llm,
|
|
755
768
|
conversations=conversations,
|
|
756
769
|
llm_config={}, # Placeholder for future LLM configs
|
|
757
770
|
args=self.args
|
|
758
771
|
)
|
|
759
|
-
|
|
772
|
+
|
|
760
773
|
meta_holder = byzerllm.MetaHolder()
|
|
761
774
|
parsed_events = self.stream_and_parse_llm_response(
|
|
762
|
-
llm_response_gen,meta_holder)
|
|
775
|
+
llm_response_gen, meta_holder)
|
|
763
776
|
|
|
764
777
|
for event in parsed_events:
|
|
765
778
|
global_cancel.check_and_raise()
|
|
@@ -777,6 +790,8 @@ class AgenticEdit:
|
|
|
777
790
|
"role": "assistant",
|
|
778
791
|
"content": assistant_buffer + tool_xml
|
|
779
792
|
})
|
|
793
|
+
self.conversation_manager.add_assistant_message(
|
|
794
|
+
assistant_buffer + tool_xml)
|
|
780
795
|
assistant_buffer = "" # Reset buffer after tool call
|
|
781
796
|
|
|
782
797
|
yield event # Yield the ToolCallEvent for display
|
|
@@ -790,6 +805,14 @@ class AgenticEdit:
|
|
|
790
805
|
"AgenticEdit analyze loop finished due to AttemptCompletion.")
|
|
791
806
|
return
|
|
792
807
|
|
|
808
|
+
if isinstance(tool_obj, PlanModeRespondTool):
|
|
809
|
+
logger.info(
|
|
810
|
+
"PlanModeRespondTool received. Finalizing session.")
|
|
811
|
+
yield PlanModeRespondEvent(completion=tool_obj, completion_xml=tool_xml)
|
|
812
|
+
logger.info(
|
|
813
|
+
"AgenticEdit analyze loop finished due to PlanModeRespond.")
|
|
814
|
+
return
|
|
815
|
+
|
|
793
816
|
# Resolve the tool
|
|
794
817
|
resolver_cls = TOOL_RESOLVER_MAP.get(type(tool_obj))
|
|
795
818
|
if not resolver_cls:
|
|
@@ -844,6 +867,7 @@ class AgenticEdit:
|
|
|
844
867
|
"role": "user", # Simulating the user providing the tool result
|
|
845
868
|
"content": error_xml
|
|
846
869
|
})
|
|
870
|
+
self.conversation_manager.add_user_message(error_xml)
|
|
847
871
|
logger.debug(
|
|
848
872
|
f"Added tool result to conversations for tool {type(tool_obj).__name__}")
|
|
849
873
|
break # After tool execution and result, break to start a new LLM cycle
|
|
@@ -862,6 +886,8 @@ class AgenticEdit:
|
|
|
862
886
|
if assistant_buffer:
|
|
863
887
|
conversations.append(
|
|
864
888
|
{"role": "assistant", "content": assistant_buffer})
|
|
889
|
+
self.conversation_manager.add_assistant_message(
|
|
890
|
+
assistant_buffer)
|
|
865
891
|
# If the loop ends without AttemptCompletion, it means the LLM finished talking
|
|
866
892
|
# without signaling completion. We might just stop or yield a final message.
|
|
867
893
|
# Let's assume it stops here.
|
|
@@ -870,7 +896,7 @@ class AgenticEdit:
|
|
|
870
896
|
logger.info("AgenticEdit analyze loop finished.")
|
|
871
897
|
|
|
872
898
|
def stream_and_parse_llm_response(
|
|
873
|
-
self, generator: Generator[Tuple[str, Any], None, None],meta_holder: byzerllm.MetaHolder
|
|
899
|
+
self, generator: Generator[Tuple[str, Any], None, None], meta_holder: byzerllm.MetaHolder
|
|
874
900
|
) -> Generator[Union[LLMOutputEvent, LLMThinkingEvent, ToolCallEvent, ErrorEvent], None, None]:
|
|
875
901
|
"""
|
|
876
902
|
Streamingly parses the LLM response generator, distinguishing between
|
|
@@ -1081,17 +1107,17 @@ class AgenticEdit:
|
|
|
1081
1107
|
Runs the agentic edit process, converting internal events to the
|
|
1082
1108
|
standard event system format and writing them using the event manager.
|
|
1083
1109
|
"""
|
|
1084
|
-
event_manager = get_event_manager(self.args.event_file)
|
|
1110
|
+
event_manager = get_event_manager(self.args.event_file)
|
|
1085
1111
|
|
|
1086
1112
|
try:
|
|
1087
1113
|
event_stream = self.analyze(request)
|
|
1088
1114
|
for agent_event in event_stream:
|
|
1089
1115
|
content = None
|
|
1090
1116
|
metadata = EventMetadata(
|
|
1091
|
-
action_file=self.args.event_file,
|
|
1092
|
-
is_streaming=False,
|
|
1117
|
+
action_file=self.args.event_file,
|
|
1118
|
+
is_streaming=False,
|
|
1093
1119
|
stream_out_type="/agent/edit")
|
|
1094
|
-
|
|
1120
|
+
|
|
1095
1121
|
if isinstance(agent_event, LLMThinkingEvent):
|
|
1096
1122
|
content = EventContentCreator.create_stream_thinking(
|
|
1097
1123
|
content=agent_event.text)
|
|
@@ -1134,7 +1160,8 @@ class AgenticEdit:
|
|
|
1134
1160
|
try:
|
|
1135
1161
|
self.apply_changes()
|
|
1136
1162
|
except Exception as e:
|
|
1137
|
-
logger.exception(
|
|
1163
|
+
logger.exception(
|
|
1164
|
+
f"Error merging shadow changes to project: {e}")
|
|
1138
1165
|
|
|
1139
1166
|
metadata.path = "/agent/edit/completion"
|
|
1140
1167
|
content = EventContentCreator.create_completion(
|
|
@@ -1144,7 +1171,8 @@ class AgenticEdit:
|
|
|
1144
1171
|
**agent_event.completion.model_dump()
|
|
1145
1172
|
}
|
|
1146
1173
|
)
|
|
1147
|
-
event_manager.write_completion(
|
|
1174
|
+
event_manager.write_completion(
|
|
1175
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1148
1176
|
elif isinstance(agent_event, ErrorEvent):
|
|
1149
1177
|
metadata.path = "/agent/edit/error"
|
|
1150
1178
|
content = EventContentCreator.create_error(
|
|
@@ -1152,7 +1180,8 @@ class AgenticEdit:
|
|
|
1152
1180
|
error_message=agent_event.message,
|
|
1153
1181
|
details={"agent_event_type": "ErrorEvent"}
|
|
1154
1182
|
)
|
|
1155
|
-
event_manager.write_error(
|
|
1183
|
+
event_manager.write_error(
|
|
1184
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1156
1185
|
else:
|
|
1157
1186
|
metadata.path = "/agent/edit/error"
|
|
1158
1187
|
logger.warning(
|
|
@@ -1163,7 +1192,8 @@ class AgenticEdit:
|
|
|
1163
1192
|
details={"agent_event_type": type(
|
|
1164
1193
|
agent_event).__name__}
|
|
1165
1194
|
)
|
|
1166
|
-
event_manager.write_error(
|
|
1195
|
+
event_manager.write_error(
|
|
1196
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1167
1197
|
|
|
1168
1198
|
except Exception as e:
|
|
1169
1199
|
logger.exception(
|
|
@@ -1174,15 +1204,16 @@ class AgenticEdit:
|
|
|
1174
1204
|
error_message=f"An unexpected error occurred: {str(e)}",
|
|
1175
1205
|
details={"exception_type": type(e).__name__}
|
|
1176
1206
|
)
|
|
1177
|
-
event_manager.write_error(
|
|
1207
|
+
event_manager.write_error(
|
|
1208
|
+
content=error_content.to_dict(), metadata=metadata.to_dict())
|
|
1178
1209
|
# Re-raise the exception if needed, or handle appropriately
|
|
1179
1210
|
raise e
|
|
1180
1211
|
|
|
1181
1212
|
def apply_changes(self):
|
|
1182
1213
|
"""
|
|
1183
1214
|
Apply all tracked file changes to the original project directory.
|
|
1184
|
-
"""
|
|
1185
|
-
for (file_path,change) in self.get_all_file_changes().items():
|
|
1215
|
+
"""
|
|
1216
|
+
for (file_path, change) in self.get_all_file_changes().items():
|
|
1186
1217
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
1187
1218
|
f.write(change.content)
|
|
1188
1219
|
|
|
@@ -1194,33 +1225,40 @@ class AgenticEdit:
|
|
|
1194
1225
|
self.args.source_dir,
|
|
1195
1226
|
f"{self.args.query}\nauto_coder_{file_name}",
|
|
1196
1227
|
)
|
|
1197
|
-
|
|
1198
|
-
action_yml_file_manager = ActionYmlFileManager(
|
|
1228
|
+
|
|
1229
|
+
action_yml_file_manager = ActionYmlFileManager(
|
|
1230
|
+
self.args.source_dir)
|
|
1199
1231
|
action_file_name = os.path.basename(self.args.file)
|
|
1200
1232
|
add_updated_urls = []
|
|
1201
1233
|
commit_result.changed_files
|
|
1202
1234
|
for file in commit_result.changed_files:
|
|
1203
|
-
add_updated_urls.append(
|
|
1235
|
+
add_updated_urls.append(
|
|
1236
|
+
os.path.join(self.args.source_dir, file))
|
|
1204
1237
|
|
|
1205
1238
|
self.args.add_updated_urls = add_updated_urls
|
|
1206
|
-
update_yaml_success = action_yml_file_manager.update_yaml_field(
|
|
1207
|
-
|
|
1208
|
-
|
|
1239
|
+
update_yaml_success = action_yml_file_manager.update_yaml_field(
|
|
1240
|
+
action_file_name, "add_updated_urls", add_updated_urls)
|
|
1241
|
+
if not update_yaml_success:
|
|
1242
|
+
self.printer.print_in_terminal(
|
|
1243
|
+
"yaml_save_error", style="red", yaml_file=action_file_name)
|
|
1209
1244
|
|
|
1210
1245
|
if self.args.enable_active_context:
|
|
1211
|
-
active_context_manager = ActiveContextManager(
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1246
|
+
active_context_manager = ActiveContextManager(
|
|
1247
|
+
self.llm, self.args.source_dir)
|
|
1248
|
+
task_id = active_context_manager.process_changes(
|
|
1249
|
+
self.args)
|
|
1250
|
+
self.printer.print_in_terminal("active_context_background_task",
|
|
1251
|
+
style="blue",
|
|
1252
|
+
task_id=task_id)
|
|
1216
1253
|
git_utils.print_commit_info(commit_result=commit_result)
|
|
1217
1254
|
except Exception as e:
|
|
1218
1255
|
self.printer.print_str_in_terminal(
|
|
1219
|
-
self.git_require_msg(
|
|
1256
|
+
self.git_require_msg(
|
|
1257
|
+
source_dir=self.args.source_dir, error=str(e)),
|
|
1220
1258
|
style="red"
|
|
1221
|
-
)
|
|
1259
|
+
)
|
|
1222
1260
|
else:
|
|
1223
|
-
self.printer.print_in_terminal("no_changes_made")
|
|
1261
|
+
self.printer.print_in_terminal("no_changes_made")
|
|
1224
1262
|
|
|
1225
1263
|
def run_in_terminal(self, request: AgenticEditRequest):
|
|
1226
1264
|
"""
|
|
@@ -1258,6 +1296,9 @@ class AgenticEdit:
|
|
|
1258
1296
|
if event.tool_name == "AttemptCompletionTool":
|
|
1259
1297
|
continue # Do not display AttemptCompletionTool result
|
|
1260
1298
|
|
|
1299
|
+
if event.tool_name == "PlanModeRespondTool":
|
|
1300
|
+
continue
|
|
1301
|
+
|
|
1261
1302
|
result = event.result
|
|
1262
1303
|
title = f"✅ Tool Result: {event.tool_name}" if result.success else f"❌ Tool Result: {event.tool_name}"
|
|
1263
1304
|
border_style = "green" if result.success else "red"
|
|
@@ -1274,7 +1315,7 @@ class AgenticEdit:
|
|
|
1274
1315
|
panel_content = [base_content]
|
|
1275
1316
|
syntax_content = None
|
|
1276
1317
|
|
|
1277
|
-
if result.content is not None:
|
|
1318
|
+
if result.content is not None:
|
|
1278
1319
|
content_str = ""
|
|
1279
1320
|
try:
|
|
1280
1321
|
if isinstance(result.content, (dict, list)):
|
|
@@ -1316,7 +1357,8 @@ class AgenticEdit:
|
|
|
1316
1357
|
else:
|
|
1317
1358
|
content_str = str(result.content)
|
|
1318
1359
|
# Append simple string content directly
|
|
1319
|
-
panel_content.append(
|
|
1360
|
+
panel_content.append(
|
|
1361
|
+
_format_content(content_str))
|
|
1320
1362
|
except Exception as e:
|
|
1321
1363
|
logger.warning(
|
|
1322
1364
|
f"Error formatting tool result content: {e}")
|
|
@@ -1329,13 +1371,17 @@ class AgenticEdit:
|
|
|
1329
1371
|
# Print syntax highlighted content separately if it exists
|
|
1330
1372
|
if syntax_content:
|
|
1331
1373
|
console.print(syntax_content)
|
|
1374
|
+
elif isinstance(event, PlanModeRespondEvent):
|
|
1375
|
+
console.print(Panel(Markdown(event.completion.response),
|
|
1376
|
+
title="🏁 Task Completion", border_style="green", title_align="left"))
|
|
1332
1377
|
|
|
1333
1378
|
elif isinstance(event, CompletionEvent):
|
|
1334
1379
|
# 在这里完成实际合并
|
|
1335
1380
|
try:
|
|
1336
1381
|
self.apply_changes()
|
|
1337
1382
|
except Exception as e:
|
|
1338
|
-
logger.exception(
|
|
1383
|
+
logger.exception(
|
|
1384
|
+
f"Error merging shadow changes to project: {e}")
|
|
1339
1385
|
|
|
1340
1386
|
console.print(Panel(Markdown(event.completion.result),
|
|
1341
1387
|
title="🏁 Task Completion", border_style="green", title_align="left"))
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# src/autocoder/common/v2/agent/agentic_edit_conversation.py
|
|
2
2
|
import os
|
|
3
3
|
import json
|
|
4
|
+
import uuid
|
|
4
5
|
from typing import List, Dict, Any, Optional
|
|
5
6
|
from autocoder.common import AutoCoderArgs
|
|
6
7
|
|
|
@@ -15,16 +16,32 @@ class AgenticConversation:
|
|
|
15
16
|
and retrieving the history.
|
|
16
17
|
"""
|
|
17
18
|
|
|
18
|
-
def __init__(self, args: AutoCoderArgs, initial_history: Optional[List[MessageType]] = None):
|
|
19
|
+
def __init__(self, args: AutoCoderArgs, initial_history: Optional[List[MessageType]] = None, conversation_name: Optional[str] = None):
|
|
19
20
|
"""
|
|
20
21
|
Initializes the conversation history.
|
|
21
22
|
|
|
22
23
|
Args:
|
|
23
24
|
initial_history: An optional list of messages to start with.
|
|
25
|
+
conversation_name: Optional conversation identifier. If provided, history is saved/loaded from a file named after it.
|
|
24
26
|
"""
|
|
25
27
|
self.project_path = args.source_dir
|
|
26
28
|
self._history: List[MessageType] = initial_history if initial_history is not None else []
|
|
27
|
-
|
|
29
|
+
|
|
30
|
+
# Determine the memory directory
|
|
31
|
+
memory_dir = os.path.join(self.project_path, ".auto-coder", "memory", "agentic_edit_memory")
|
|
32
|
+
os.makedirs(memory_dir, exist_ok=True)
|
|
33
|
+
|
|
34
|
+
# Determine conversation file path
|
|
35
|
+
if conversation_name:
|
|
36
|
+
filename = f"{conversation_name}.json"
|
|
37
|
+
else:
|
|
38
|
+
conversation_name = str(uuid.uuid4())
|
|
39
|
+
filename = f"{conversation_name}.json"
|
|
40
|
+
|
|
41
|
+
self.conversation_name = conversation_name
|
|
42
|
+
self.memory_file_path = os.path.join(memory_dir, filename)
|
|
43
|
+
|
|
44
|
+
# Load existing history if file exists
|
|
28
45
|
self._load_memory()
|
|
29
46
|
|
|
30
47
|
def add_message(self, role: str, content: Any, **kwargs):
|
|
@@ -67,14 +84,62 @@ class AgenticConversation:
|
|
|
67
84
|
|
|
68
85
|
def get_history(self) -> List[MessageType]:
|
|
69
86
|
"""
|
|
70
|
-
Returns the
|
|
71
|
-
|
|
87
|
+
Returns the latest 20 pairs of (user, assistant) conversation history.
|
|
88
|
+
Merges adjacent same-role messages into one, concatenated by newline.
|
|
89
|
+
Ensures that each user message is paired with the subsequent assistant response,
|
|
90
|
+
skips other roles, and that the last message is always assistant (drops trailing user if unpaired).
|
|
91
|
+
|
|
72
92
|
Returns:
|
|
73
|
-
A list of message dictionaries.
|
|
93
|
+
A list of message dictionaries, ordered chronologically.
|
|
74
94
|
"""
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
95
|
+
paired_history = []
|
|
96
|
+
pair_count = 0
|
|
97
|
+
pending_assistant = None
|
|
98
|
+
pending_user = None
|
|
99
|
+
|
|
100
|
+
# Traverse history in reverse to collect latest pairs with merging
|
|
101
|
+
for msg in reversed(self._history):
|
|
102
|
+
role = msg.get("role")
|
|
103
|
+
if role == "assistant":
|
|
104
|
+
if pending_assistant is None:
|
|
105
|
+
pending_assistant = dict(msg)
|
|
106
|
+
else:
|
|
107
|
+
# Merge with previous assistant
|
|
108
|
+
prev_content = pending_assistant.get("content", "")
|
|
109
|
+
curr_content = msg.get("content", "")
|
|
110
|
+
merged_content = (curr_content.strip() + "\n" + prev_content.strip()).strip()
|
|
111
|
+
pending_assistant["content"] = merged_content
|
|
112
|
+
elif role == "user":
|
|
113
|
+
if pending_user is None:
|
|
114
|
+
pending_user = dict(msg)
|
|
115
|
+
else:
|
|
116
|
+
# Merge with previous user
|
|
117
|
+
prev_content = pending_user.get("content", "")
|
|
118
|
+
curr_content = msg.get("content", "")
|
|
119
|
+
merged_content = (curr_content.strip() + "\n" + prev_content.strip()).strip()
|
|
120
|
+
pending_user["content"] = merged_content
|
|
121
|
+
|
|
122
|
+
if pending_assistant is not None:
|
|
123
|
+
# Have a full pair, insert in order
|
|
124
|
+
paired_history.insert(0, pending_user)
|
|
125
|
+
paired_history.insert(1, pending_assistant)
|
|
126
|
+
pair_count += 1
|
|
127
|
+
pending_assistant = None
|
|
128
|
+
pending_user = None
|
|
129
|
+
if pair_count >= 20:
|
|
130
|
+
break
|
|
131
|
+
else:
|
|
132
|
+
# User without assistant yet, continue accumulating
|
|
133
|
+
continue
|
|
134
|
+
else:
|
|
135
|
+
# Ignore other roles
|
|
136
|
+
continue
|
|
137
|
+
|
|
138
|
+
# Ensure last message is assistant, drop trailing user if unpaired
|
|
139
|
+
if paired_history and paired_history[-1].get("role") == "user":
|
|
140
|
+
paired_history.pop()
|
|
141
|
+
|
|
142
|
+
return paired_history
|
|
78
143
|
|
|
79
144
|
def clear_history(self):
|
|
80
145
|
"""Clears the conversation history."""
|
|
@@ -6,6 +6,7 @@ from autocoder.common import AutoCoderArgs
|
|
|
6
6
|
from autocoder.common.v2.agent.agentic_edit_tools.base_tool_resolver import BaseToolResolver
|
|
7
7
|
from autocoder.common.v2.agent.agentic_edit_types import ReplaceInFileTool, ToolResult # Import ToolResult from types
|
|
8
8
|
from loguru import logger
|
|
9
|
+
from autocoder.common.auto_coder_lang import get_message_with_format
|
|
9
10
|
if typing.TYPE_CHECKING:
|
|
10
11
|
from autocoder.common.v2.agent.agentic_edit import AgenticEdit
|
|
11
12
|
|
|
@@ -66,7 +67,7 @@ class ReplaceInFileToolResolver(BaseToolResolver):
|
|
|
66
67
|
|
|
67
68
|
# Security check
|
|
68
69
|
if not abs_file_path.startswith(abs_project_dir):
|
|
69
|
-
return ToolResult(success=False, message=
|
|
70
|
+
return ToolResult(success=False, message=get_message_with_format("replace_in_file.access_denied", file_path=file_path))
|
|
70
71
|
|
|
71
72
|
# Determine target path: shadow file if shadow_manager exists
|
|
72
73
|
target_path = abs_file_path
|
|
@@ -90,14 +91,14 @@ class ReplaceInFileToolResolver(BaseToolResolver):
|
|
|
90
91
|
f.write(original_content)
|
|
91
92
|
logger.info(f"[Shadow] Initialized shadow file from original: {target_path}")
|
|
92
93
|
else:
|
|
93
|
-
return ToolResult(success=False, message=
|
|
94
|
+
return ToolResult(success=False, message=get_message_with_format("replace_in_file.file_not_found", file_path=file_path))
|
|
94
95
|
except Exception as e:
|
|
95
96
|
logger.error(f"Error reading file for replace '{file_path}': {str(e)}")
|
|
96
|
-
return ToolResult(success=False, message=
|
|
97
|
+
return ToolResult(success=False, message=get_message_with_format("replace_in_file.read_error", error=str(e)))
|
|
97
98
|
|
|
98
99
|
parsed_blocks = self.parse_diff(diff_content)
|
|
99
100
|
if not parsed_blocks:
|
|
100
|
-
return ToolResult(success=False, message="
|
|
101
|
+
return ToolResult(success=False, message=get_message_with_format("replace_in_file.no_valid_blocks"))
|
|
101
102
|
|
|
102
103
|
current_content = original_content
|
|
103
104
|
applied_count = 0
|
|
@@ -121,7 +122,7 @@ class ReplaceInFileToolResolver(BaseToolResolver):
|
|
|
121
122
|
# continue applying remaining blocks
|
|
122
123
|
|
|
123
124
|
if applied_count == 0 and errors:
|
|
124
|
-
return ToolResult(success=False, message=
|
|
125
|
+
return ToolResult(success=False, message=get_message_with_format("replace_in_file.apply_failed", errors="\n".join(errors)))
|
|
125
126
|
|
|
126
127
|
try:
|
|
127
128
|
os.makedirs(os.path.dirname(target_path), exist_ok=True)
|
|
@@ -129,9 +130,17 @@ class ReplaceInFileToolResolver(BaseToolResolver):
|
|
|
129
130
|
f.write(current_content)
|
|
130
131
|
logger.info(f"Successfully applied {applied_count}/{len(parsed_blocks)} changes to file: {file_path}")
|
|
131
132
|
|
|
132
|
-
message = f"Successfully applied {applied_count}/{len(parsed_blocks)} changes to file: {file_path}."
|
|
133
133
|
if errors:
|
|
134
|
-
message
|
|
134
|
+
message = get_message_with_format("replace_in_file.apply_success_with_warnings",
|
|
135
|
+
applied=applied_count,
|
|
136
|
+
total=len(parsed_blocks),
|
|
137
|
+
file_path=file_path,
|
|
138
|
+
errors="\n".join(errors))
|
|
139
|
+
else:
|
|
140
|
+
message = get_message_with_format("replace_in_file.apply_success",
|
|
141
|
+
applied=applied_count,
|
|
142
|
+
total=len(parsed_blocks),
|
|
143
|
+
file_path=file_path)
|
|
135
144
|
|
|
136
145
|
# 变更跟踪,回调AgenticEdit
|
|
137
146
|
if self.agent:
|
|
@@ -141,4 +150,4 @@ class ReplaceInFileToolResolver(BaseToolResolver):
|
|
|
141
150
|
return ToolResult(success=True, message=message, content=current_content)
|
|
142
151
|
except Exception as e:
|
|
143
152
|
logger.error(f"Error writing replaced content to file '{file_path}': {str(e)}")
|
|
144
|
-
return ToolResult(success=False, message=
|
|
153
|
+
return ToolResult(success=False, message=get_message_with_format("replace_in_file.write_error", error=str(e)))
|
|
@@ -80,6 +80,11 @@ class TokenUsageEvent(BaseModel):
|
|
|
80
80
|
"""Represents the result of executing a tool."""
|
|
81
81
|
usage: Any
|
|
82
82
|
|
|
83
|
+
class PlanModeRespondEvent(BaseModel):
|
|
84
|
+
"""Represents the LLM attempting to complete the task."""
|
|
85
|
+
completion: SkipValidation[PlanModeRespondTool] # Skip validation
|
|
86
|
+
completion_xml: str
|
|
87
|
+
|
|
83
88
|
class CompletionEvent(BaseModel):
|
|
84
89
|
"""Represents the LLM attempting to complete the task."""
|
|
85
90
|
completion: SkipValidation[AttemptCompletionTool] # Skip validation
|
|
@@ -93,7 +93,7 @@ TOOL_DISPLAY_MESSAGES: Dict[Type[BaseTool], Dict[str, str]] = {
|
|
|
93
93
|
"[dim]工具:[/dim] [blue]{{ tool_name }}[/]\n"
|
|
94
94
|
"[dim]参数:[/dim] {{ arguments_snippet }}{{ ellipsis }}"
|
|
95
95
|
)
|
|
96
|
-
}
|
|
96
|
+
}
|
|
97
97
|
# AttemptCompletionTool is handled separately in the display loop
|
|
98
98
|
}
|
|
99
99
|
|
autocoder/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.338"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|