auto-coder 0.1.363__py3-none-any.whl → 0.1.364__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.363.dist-info → auto_coder-0.1.364.dist-info}/METADATA +2 -2
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.364.dist-info}/RECORD +33 -18
- autocoder/agent/base_agentic/tools/execute_command_tool_resolver.py +1 -1
- autocoder/auto_coder_runner.py +2 -0
- autocoder/common/__init__.py +2 -0
- autocoder/common/file_checkpoint/__init__.py +21 -0
- autocoder/common/file_checkpoint/backup.py +264 -0
- autocoder/common/file_checkpoint/examples.py +217 -0
- autocoder/common/file_checkpoint/manager.py +404 -0
- autocoder/common/file_checkpoint/models.py +156 -0
- autocoder/common/file_checkpoint/store.py +383 -0
- autocoder/common/file_checkpoint/test_backup.py +242 -0
- autocoder/common/file_checkpoint/test_manager.py +570 -0
- autocoder/common/file_checkpoint/test_models.py +360 -0
- autocoder/common/file_checkpoint/test_store.py +327 -0
- autocoder/common/file_checkpoint/test_utils.py +297 -0
- autocoder/common/file_checkpoint/utils.py +119 -0
- autocoder/common/rulefiles/autocoderrules_utils.py +114 -55
- autocoder/common/save_formatted_log.py +76 -5
- autocoder/common/v2/agent/agentic_edit.py +318 -197
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +27 -4
- autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +322 -0
- autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +83 -61
- autocoder/compilers/normal_compiler.py +64 -0
- autocoder/events/event_manager_singleton.py +133 -4
- autocoder/linters/normal_linter.py +373 -0
- autocoder/linters/python_linter.py +4 -2
- autocoder/version.py +1 -1
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.364.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.364.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.364.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.364.dist-info}/top_level.txt +0 -0
|
@@ -40,9 +40,15 @@ from autocoder.linters.shadow_linter import ShadowLinter
|
|
|
40
40
|
from autocoder.compilers.shadow_compiler import ShadowCompiler
|
|
41
41
|
from autocoder.common.action_yml_file_manager import ActionYmlFileManager
|
|
42
42
|
from autocoder.common.auto_coder_lang import get_message
|
|
43
|
+
from autocoder.common.save_formatted_log import save_formatted_log
|
|
43
44
|
# Import the new display function
|
|
44
45
|
from autocoder.common.v2.agent.agentic_tool_display import get_tool_display_message
|
|
45
46
|
from autocoder.common.v2.agent.agentic_edit_types import FileChangeEntry
|
|
47
|
+
|
|
48
|
+
from autocoder.common.file_checkpoint.models import FileChange as CheckpointFileChange
|
|
49
|
+
from autocoder.common.file_checkpoint.manager import FileChangeManager as CheckpointFileChangeManager
|
|
50
|
+
from autocoder.linters.normal_linter import NormalLinter
|
|
51
|
+
from autocoder.compilers.normal_compiler import NormalCompiler
|
|
46
52
|
from autocoder.common.v2.agent.agentic_edit_tools import ( # Import specific resolvers
|
|
47
53
|
BaseToolResolver,
|
|
48
54
|
ExecuteCommandToolResolver, ReadFileToolResolver, WriteToFileToolResolver,
|
|
@@ -51,7 +57,7 @@ from autocoder.common.v2.agent.agentic_edit_tools import ( # Import specific re
|
|
|
51
57
|
AttemptCompletionToolResolver, PlanModeRespondToolResolver, UseMcpToolResolver,
|
|
52
58
|
ListPackageInfoToolResolver
|
|
53
59
|
)
|
|
54
|
-
from autocoder.common.rulefiles.autocoderrules_utils import get_rules
|
|
60
|
+
from autocoder.common.rulefiles.autocoderrules_utils import get_rules,auto_select_rules,get_required_and_index_rules
|
|
55
61
|
from autocoder.common.v2.agent.agentic_edit_types import (AgenticEditRequest, ToolResult,
|
|
56
62
|
MemoryConfig, CommandConfig, BaseTool,
|
|
57
63
|
ExecuteCommandTool, ReadFileTool,
|
|
@@ -101,7 +107,7 @@ class AgenticEdit:
|
|
|
101
107
|
args: AutoCoderArgs,
|
|
102
108
|
memory_config: MemoryConfig,
|
|
103
109
|
command_config: Optional[CommandConfig] = None,
|
|
104
|
-
conversation_name:
|
|
110
|
+
conversation_name:Optional[str] = "current"
|
|
105
111
|
):
|
|
106
112
|
self.llm = llm
|
|
107
113
|
self.args = args
|
|
@@ -116,11 +122,22 @@ class AgenticEdit:
|
|
|
116
122
|
self.project_type_analyzer = ProjectTypeAnalyzer(
|
|
117
123
|
args=args, llm=self.llm)
|
|
118
124
|
|
|
119
|
-
self.shadow_manager = ShadowManager(
|
|
120
|
-
|
|
121
|
-
self.
|
|
122
|
-
self.
|
|
123
|
-
|
|
125
|
+
# self.shadow_manager = ShadowManager(
|
|
126
|
+
# args.source_dir, args.event_file, args.ignore_clean_shadows)
|
|
127
|
+
self.shadow_manager = None
|
|
128
|
+
# self.shadow_linter = ShadowLinter(self.shadow_manager, verbose=False)
|
|
129
|
+
self.shadow_compiler = None
|
|
130
|
+
# self.shadow_compiler = ShadowCompiler(self.shadow_manager, verbose=False)
|
|
131
|
+
self.shadow_linter = None
|
|
132
|
+
|
|
133
|
+
self.checkpoint_manager = CheckpointFileChangeManager(
|
|
134
|
+
project_dir=args.source_dir,
|
|
135
|
+
backup_dir=os.path.join(args.source_dir,".auto-coder","checkpoint"),
|
|
136
|
+
store_dir=os.path.join(args.source_dir,".auto-coder","checkpoint_store"),
|
|
137
|
+
max_history=50)
|
|
138
|
+
self.linter = NormalLinter(args.source_dir,verbose=False)
|
|
139
|
+
self.compiler = NormalCompiler(args.source_dir,verbose=False)
|
|
140
|
+
|
|
124
141
|
|
|
125
142
|
self.mcp_server_info = ""
|
|
126
143
|
try:
|
|
@@ -663,12 +680,14 @@ class AgenticEdit:
|
|
|
663
680
|
The following rules are provided by the user, and you must follow them strictly.
|
|
664
681
|
|
|
665
682
|
{% for key, value in extra_docs.items() %}
|
|
666
|
-
<
|
|
683
|
+
<user_rule_file>
|
|
667
684
|
##File: {{ key }}
|
|
668
685
|
{{ value }}
|
|
669
|
-
</
|
|
670
|
-
{% endfor %}
|
|
686
|
+
</user_rule_file>
|
|
687
|
+
{% endfor %}
|
|
688
|
+
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.
|
|
671
689
|
{% endif %}
|
|
690
|
+
|
|
672
691
|
|
|
673
692
|
====
|
|
674
693
|
|
|
@@ -694,14 +713,15 @@ class AgenticEdit:
|
|
|
694
713
|
{% if file_paths_str %}
|
|
695
714
|
====
|
|
696
715
|
The following are files that the user is currently focusing on.
|
|
697
|
-
Make sure you always start your
|
|
716
|
+
Make sure you always start your task by using the read_file tool to get the content of the files.
|
|
698
717
|
<files>
|
|
699
718
|
{{file_paths_str}}
|
|
700
719
|
</files>
|
|
701
720
|
{% endif %}
|
|
702
|
-
"""
|
|
703
|
-
|
|
704
|
-
extra_docs = get_rules()
|
|
721
|
+
"""
|
|
722
|
+
## auto_select_rules(context=request.user_input, llm=self.llm,args=self.args) rules =
|
|
723
|
+
# extra_docs = get_rules()
|
|
724
|
+
extra_docs = get_required_and_index_rules()
|
|
705
725
|
|
|
706
726
|
env_info = detect_env()
|
|
707
727
|
shell_type = "bash"
|
|
@@ -790,9 +810,7 @@ class AgenticEdit:
|
|
|
790
810
|
|
|
791
811
|
logger.info(
|
|
792
812
|
f"Initial conversation history size: {len(conversations)}")
|
|
793
|
-
|
|
794
|
-
logger.info(f"Conversation history: {json.dumps(conversations, indent=2,ensure_ascii=False)}")
|
|
795
|
-
|
|
813
|
+
|
|
796
814
|
iteration_count = 0
|
|
797
815
|
tool_executed = False
|
|
798
816
|
while True:
|
|
@@ -828,7 +846,7 @@ class AgenticEdit:
|
|
|
828
846
|
event_count = 0
|
|
829
847
|
for event in parsed_events:
|
|
830
848
|
event_count += 1
|
|
831
|
-
logger.info(f"Processing event #{event_count}: {type(event).__name__}")
|
|
849
|
+
# logger.info(f"Processing event #{event_count}: {type(event).__name__}")
|
|
832
850
|
global_cancel.check_and_raise(token=self.args.event_file)
|
|
833
851
|
if isinstance(event, (LLMOutputEvent, LLMThinkingEvent)):
|
|
834
852
|
assistant_buffer += event.text
|
|
@@ -861,6 +879,7 @@ class AgenticEdit:
|
|
|
861
879
|
yield CompletionEvent(completion=tool_obj, completion_xml=tool_xml)
|
|
862
880
|
logger.info(
|
|
863
881
|
"AgenticEdit analyze loop finished due to AttemptCompletion.")
|
|
882
|
+
save_formatted_log(self.args.source_dir, json.dumps(conversations, ensure_ascii=False), "agentic_conversation")
|
|
864
883
|
return
|
|
865
884
|
|
|
866
885
|
if isinstance(tool_obj, PlanModeRespondTool):
|
|
@@ -870,6 +889,7 @@ class AgenticEdit:
|
|
|
870
889
|
yield PlanModeRespondEvent(completion=tool_obj, completion_xml=tool_xml)
|
|
871
890
|
logger.info(
|
|
872
891
|
"AgenticEdit analyze loop finished due to PlanModeRespond.")
|
|
892
|
+
save_formatted_log(self.args.source_dir, json.dumps(conversations, ensure_ascii=False), "agentic_conversation")
|
|
873
893
|
return
|
|
874
894
|
|
|
875
895
|
# Resolve the tool
|
|
@@ -972,6 +992,7 @@ class AgenticEdit:
|
|
|
972
992
|
continue
|
|
973
993
|
|
|
974
994
|
logger.info(f"AgenticEdit analyze loop finished after {iteration_count} iterations.")
|
|
995
|
+
save_formatted_log(self.args.source_dir, json.dumps(conversations, ensure_ascii=False), "agentic_conversation")
|
|
975
996
|
|
|
976
997
|
def stream_and_parse_llm_response(
|
|
977
998
|
self, generator: Generator[Tuple[str, Any], None, None]
|
|
@@ -1187,174 +1208,28 @@ class AgenticEdit:
|
|
|
1187
1208
|
elif buffer:
|
|
1188
1209
|
# Yield remaining plain text
|
|
1189
1210
|
yield LLMOutputEvent(text=buffer)
|
|
1190
|
-
|
|
1191
|
-
def run_with_events(self, request: AgenticEditRequest):
|
|
1192
|
-
"""
|
|
1193
|
-
Runs the agentic edit process, converting internal events to the
|
|
1194
|
-
standard event system format and writing them using the event manager.
|
|
1195
|
-
"""
|
|
1196
|
-
event_manager = get_event_manager(self.args.event_file)
|
|
1197
|
-
self.apply_pre_changes()
|
|
1198
|
-
|
|
1199
|
-
try:
|
|
1200
|
-
event_stream = self.analyze(request)
|
|
1201
|
-
for agent_event in event_stream:
|
|
1202
|
-
content = None
|
|
1203
|
-
metadata = EventMetadata(
|
|
1204
|
-
action_file=self.args.file,
|
|
1205
|
-
is_streaming=False,
|
|
1206
|
-
stream_out_type="/agent/edit")
|
|
1207
|
-
|
|
1208
|
-
if isinstance(agent_event, LLMThinkingEvent):
|
|
1209
|
-
content = EventContentCreator.create_stream_thinking(
|
|
1210
|
-
content=agent_event.text)
|
|
1211
|
-
metadata.is_streaming = True
|
|
1212
|
-
metadata.path = "/agent/edit/thinking"
|
|
1213
|
-
event_manager.write_stream(
|
|
1214
|
-
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1215
|
-
elif isinstance(agent_event, LLMOutputEvent):
|
|
1216
|
-
content = EventContentCreator.create_stream_content(
|
|
1217
|
-
content=agent_event.text)
|
|
1218
|
-
metadata.is_streaming = True
|
|
1219
|
-
metadata.path = "/agent/edit/output"
|
|
1220
|
-
event_manager.write_stream(content=content.to_dict(),
|
|
1221
|
-
metadata=metadata.to_dict())
|
|
1222
|
-
elif isinstance(agent_event, ToolCallEvent):
|
|
1223
|
-
tool_name = type(agent_event.tool).__name__
|
|
1224
|
-
metadata.path = "/agent/edit/tool/call"
|
|
1225
|
-
content = EventContentCreator.create_result(
|
|
1226
|
-
content={
|
|
1227
|
-
"tool_name": tool_name,
|
|
1228
|
-
**agent_event.tool.model_dump()
|
|
1229
|
-
},
|
|
1230
|
-
metadata={}
|
|
1231
|
-
)
|
|
1232
|
-
event_manager.write_result(
|
|
1233
|
-
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1234
|
-
elif isinstance(agent_event, ToolResultEvent):
|
|
1235
|
-
metadata.path = "/agent/edit/tool/result"
|
|
1236
|
-
content = EventContentCreator.create_result(
|
|
1237
|
-
content={
|
|
1238
|
-
"tool_name": agent_event.tool_name,
|
|
1239
|
-
**agent_event.result.model_dump()
|
|
1240
|
-
},
|
|
1241
|
-
metadata={}
|
|
1242
|
-
)
|
|
1243
|
-
event_manager.write_result(
|
|
1244
|
-
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1245
|
-
elif isinstance(agent_event, PlanModeRespondEvent):
|
|
1246
|
-
metadata.path = "/agent/edit/plan_mode_respond"
|
|
1247
|
-
content = EventContentCreator.create_markdown_result(
|
|
1248
|
-
content=agent_event.completion.response,
|
|
1249
|
-
metadata={}
|
|
1250
|
-
)
|
|
1251
|
-
event_manager.write_result(
|
|
1252
|
-
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1253
|
-
|
|
1254
|
-
elif isinstance(agent_event, TokenUsageEvent):
|
|
1255
|
-
last_meta: SingleOutputMeta = agent_event.usage
|
|
1256
|
-
# Get model info for pricing
|
|
1257
|
-
from autocoder.utils import llms as llm_utils
|
|
1258
|
-
model_name = ",".join(llm_utils.get_llm_names(self.llm))
|
|
1259
|
-
model_info = llm_utils.get_model_info(
|
|
1260
|
-
model_name, self.args.product_mode) or {}
|
|
1261
|
-
input_price = model_info.get(
|
|
1262
|
-
"input_price", 0.0) if model_info else 0.0
|
|
1263
|
-
output_price = model_info.get(
|
|
1264
|
-
"output_price", 0.0) if model_info else 0.0
|
|
1265
|
-
|
|
1266
|
-
# Calculate costs
|
|
1267
|
-
input_cost = (last_meta.input_tokens_count *
|
|
1268
|
-
input_price) / 1000000 # Convert to millions
|
|
1269
|
-
# Convert to millions
|
|
1270
|
-
output_cost = (
|
|
1271
|
-
last_meta.generated_tokens_count * output_price) / 1000000
|
|
1272
|
-
|
|
1273
|
-
# 添加日志记录
|
|
1274
|
-
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}")
|
|
1275
|
-
|
|
1276
|
-
get_event_manager(self.args.event_file).write_result(
|
|
1277
|
-
EventContentCreator.create_result(content=EventContentCreator.ResultTokenStatContent(
|
|
1278
|
-
model_name=model_name,
|
|
1279
|
-
elapsed_time=0.0,
|
|
1280
|
-
first_token_time=last_meta.first_token_time,
|
|
1281
|
-
input_tokens=last_meta.input_tokens_count,
|
|
1282
|
-
output_tokens=last_meta.generated_tokens_count,
|
|
1283
|
-
input_cost=input_cost,
|
|
1284
|
-
output_cost=output_cost
|
|
1285
|
-
).to_dict()), metadata=metadata.to_dict())
|
|
1286
|
-
|
|
1287
|
-
elif isinstance(agent_event, CompletionEvent):
|
|
1288
|
-
# 在这里完成实际合并
|
|
1289
|
-
try:
|
|
1290
|
-
self.apply_changes()
|
|
1291
|
-
except Exception as e:
|
|
1292
|
-
logger.exception(
|
|
1293
|
-
f"Error merging shadow changes to project: {e}")
|
|
1294
|
-
|
|
1295
|
-
metadata.path = "/agent/edit/completion"
|
|
1296
|
-
content = EventContentCreator.create_completion(
|
|
1297
|
-
success_code="AGENT_COMPLETE",
|
|
1298
|
-
success_message="Agent attempted task completion.",
|
|
1299
|
-
result={
|
|
1300
|
-
"response": agent_event.completion.result
|
|
1301
|
-
}
|
|
1302
|
-
)
|
|
1303
|
-
event_manager.write_completion(
|
|
1304
|
-
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1305
|
-
elif isinstance(agent_event, ErrorEvent):
|
|
1306
|
-
metadata.path = "/agent/edit/error"
|
|
1307
|
-
content = EventContentCreator.create_error(
|
|
1308
|
-
error_code="AGENT_ERROR",
|
|
1309
|
-
error_message=agent_event.message,
|
|
1310
|
-
details={"agent_event_type": "ErrorEvent"}
|
|
1311
|
-
)
|
|
1312
|
-
event_manager.write_error(
|
|
1313
|
-
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1314
|
-
else:
|
|
1315
|
-
metadata.path = "/agent/edit/error"
|
|
1316
|
-
logger.warning(
|
|
1317
|
-
f"Unhandled agent event type: {type(agent_event)}")
|
|
1318
|
-
content = EventContentCreator.create_error(
|
|
1319
|
-
error_code="AGENT_ERROR",
|
|
1320
|
-
error_message=f"Unhandled agent event type: {type(agent_event)}",
|
|
1321
|
-
details={"agent_event_type": type(
|
|
1322
|
-
agent_event).__name__}
|
|
1323
|
-
)
|
|
1324
|
-
event_manager.write_error(
|
|
1325
|
-
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1326
|
-
|
|
1327
|
-
except Exception as e:
|
|
1328
|
-
logger.exception(
|
|
1329
|
-
"An unexpected error occurred during agent execution:")
|
|
1330
|
-
metadata = EventMetadata(
|
|
1331
|
-
action_file=self.args.file,
|
|
1332
|
-
is_streaming=False,
|
|
1333
|
-
stream_out_type="/agent/edit/error")
|
|
1334
|
-
error_content = EventContentCreator.create_error(
|
|
1335
|
-
error_code="AGENT_FATAL_ERROR",
|
|
1336
|
-
error_message=f"An unexpected error occurred: {str(e)}",
|
|
1337
|
-
details={"exception_type": type(e).__name__}
|
|
1338
|
-
)
|
|
1339
|
-
event_manager.write_error(
|
|
1340
|
-
content=error_content.to_dict(), metadata=metadata.to_dict())
|
|
1341
|
-
# Re-raise the exception if needed, or handle appropriately
|
|
1342
|
-
raise e
|
|
1211
|
+
|
|
1343
1212
|
|
|
1344
1213
|
def apply_pre_changes(self):
|
|
1345
1214
|
# get the file name
|
|
1346
1215
|
file_name = os.path.basename(self.args.file)
|
|
1347
1216
|
if not self.args.skip_commit:
|
|
1348
1217
|
try:
|
|
1218
|
+
commit_result = git_utils.commit_changes(
|
|
1219
|
+
self.args.source_dir, f"auto_coder_pre_{file_name}")
|
|
1349
1220
|
get_event_manager(self.args.event_file).write_result(
|
|
1350
1221
|
EventContentCreator.create_result(
|
|
1351
|
-
content=
|
|
1222
|
+
content={
|
|
1223
|
+
"have_commit":commit_result.success,
|
|
1224
|
+
"commit_hash":commit_result.commit_hash,
|
|
1225
|
+
"diff_file_num":len(commit_result.changed_files),
|
|
1226
|
+
"event_file":self.args.event_file
|
|
1227
|
+
}), metadata=EventMetadata(
|
|
1352
1228
|
action_file=self.args.file,
|
|
1353
1229
|
is_streaming=False,
|
|
1354
1230
|
path="/agent/edit/apply_pre_changes",
|
|
1355
1231
|
stream_out_type="/agent/edit").to_dict())
|
|
1356
|
-
|
|
1357
|
-
self.args.source_dir, f"auto_coder_pre_{file_name}")
|
|
1232
|
+
|
|
1358
1233
|
except Exception as e:
|
|
1359
1234
|
self.printer.print_in_terminal("git_init_required",
|
|
1360
1235
|
source_dir=self.args.source_dir, error=str(e))
|
|
@@ -1364,16 +1239,22 @@ class AgenticEdit:
|
|
|
1364
1239
|
"""
|
|
1365
1240
|
Apply all tracked file changes to the original project directory.
|
|
1366
1241
|
"""
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1242
|
+
diff_file_num = 0
|
|
1243
|
+
if self.shadow_manager:
|
|
1244
|
+
for (file_path, change) in self.get_all_file_changes().items():
|
|
1245
|
+
# Ensure the directory exists before writing the file
|
|
1246
|
+
dir_path = os.path.dirname(file_path)
|
|
1247
|
+
if dir_path: # Ensure dir_path is not empty (for files in root)
|
|
1248
|
+
os.makedirs(dir_path, exist_ok=True)
|
|
1249
|
+
|
|
1250
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
1251
|
+
f.write(change.content)
|
|
1252
|
+
diff_file_num = len(self.get_all_file_changes())
|
|
1253
|
+
else:
|
|
1254
|
+
changes = self.checkpoint_manager.get_changes_by_group(self.args.event_file)
|
|
1255
|
+
diff_file_num = len(changes)
|
|
1256
|
+
|
|
1257
|
+
if diff_file_num > 0:
|
|
1377
1258
|
if not self.args.skip_commit:
|
|
1378
1259
|
try:
|
|
1379
1260
|
file_name = os.path.basename(self.args.file)
|
|
@@ -1381,13 +1262,20 @@ class AgenticEdit:
|
|
|
1381
1262
|
self.args.source_dir,
|
|
1382
1263
|
f"{self.args.query}\nauto_coder_{file_name}",
|
|
1383
1264
|
)
|
|
1384
|
-
|
|
1265
|
+
|
|
1385
1266
|
get_event_manager(self.args.event_file).write_result(
|
|
1386
1267
|
EventContentCreator.create_result(
|
|
1387
|
-
content=
|
|
1268
|
+
content={
|
|
1269
|
+
"have_commit":commit_result.success,
|
|
1270
|
+
"commit_hash":commit_result.commit_hash,
|
|
1271
|
+
"diff_file_num":diff_file_num,
|
|
1272
|
+
"event_file":self.args.event_file
|
|
1273
|
+
}), metadata=EventMetadata(
|
|
1388
1274
|
action_file=self.args.file,
|
|
1389
1275
|
is_streaming=False,
|
|
1276
|
+
path="/agent/edit/apply_changes",
|
|
1390
1277
|
stream_out_type="/agent/edit").to_dict())
|
|
1278
|
+
|
|
1391
1279
|
action_yml_file_manager = ActionYmlFileManager(
|
|
1392
1280
|
self.args.source_dir)
|
|
1393
1281
|
action_file_name = os.path.basename(self.args.file)
|
|
@@ -1433,6 +1321,15 @@ class AgenticEdit:
|
|
|
1433
1321
|
console.print(Panel(
|
|
1434
1322
|
f"[bold]{get_message('/agent/edit/user_query')}:[/bold]\n{request.user_input}", title=get_message("/agent/edit/objective"), border_style="blue"))
|
|
1435
1323
|
|
|
1324
|
+
# 用于累计TokenUsageEvent数据
|
|
1325
|
+
accumulated_token_usage = {
|
|
1326
|
+
"model_name": "",
|
|
1327
|
+
"input_tokens": 0,
|
|
1328
|
+
"output_tokens": 0,
|
|
1329
|
+
"input_cost": 0.0,
|
|
1330
|
+
"output_cost": 0.0
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1436
1333
|
try:
|
|
1437
1334
|
self.apply_pre_changes()
|
|
1438
1335
|
event_stream = self.analyze(request)
|
|
@@ -1459,17 +1356,12 @@ class AgenticEdit:
|
|
|
1459
1356
|
# 添加日志记录
|
|
1460
1357
|
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}")
|
|
1461
1358
|
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
output_cost=output_cost,
|
|
1469
|
-
speed=0.0,
|
|
1470
|
-
model_names=model_name,
|
|
1471
|
-
sampling_count=1
|
|
1472
|
-
)
|
|
1359
|
+
# 累计token使用情况
|
|
1360
|
+
accumulated_token_usage["model_name"] = model_name
|
|
1361
|
+
accumulated_token_usage["input_tokens"] += last_meta.input_tokens_count
|
|
1362
|
+
accumulated_token_usage["output_tokens"] += last_meta.generated_tokens_count
|
|
1363
|
+
accumulated_token_usage["input_cost"] += input_cost
|
|
1364
|
+
accumulated_token_usage["output_cost"] += output_cost
|
|
1473
1365
|
|
|
1474
1366
|
if isinstance(event, LLMThinkingEvent):
|
|
1475
1367
|
# Render thinking within a less prominent style, maybe grey?
|
|
@@ -1592,7 +1484,35 @@ class AgenticEdit:
|
|
|
1592
1484
|
|
|
1593
1485
|
time.sleep(0.1) # Small delay for better visual flow
|
|
1594
1486
|
|
|
1487
|
+
# 在处理完所有事件后打印累计的token使用情况
|
|
1488
|
+
if accumulated_token_usage["input_tokens"] > 0:
|
|
1489
|
+
self.printer.print_in_terminal(
|
|
1490
|
+
"code_generation_complete",
|
|
1491
|
+
duration=0.0,
|
|
1492
|
+
input_tokens=accumulated_token_usage["input_tokens"],
|
|
1493
|
+
output_tokens=accumulated_token_usage["output_tokens"],
|
|
1494
|
+
input_cost=accumulated_token_usage["input_cost"],
|
|
1495
|
+
output_cost=accumulated_token_usage["output_cost"],
|
|
1496
|
+
speed=0.0,
|
|
1497
|
+
model_names=accumulated_token_usage["model_name"],
|
|
1498
|
+
sampling_count=1
|
|
1499
|
+
)
|
|
1500
|
+
|
|
1595
1501
|
except Exception as e:
|
|
1502
|
+
# 在处理异常时也打印累计的token使用情况
|
|
1503
|
+
if accumulated_token_usage["input_tokens"] > 0:
|
|
1504
|
+
self.printer.print_in_terminal(
|
|
1505
|
+
"code_generation_complete",
|
|
1506
|
+
duration=0.0,
|
|
1507
|
+
input_tokens=accumulated_token_usage["input_tokens"],
|
|
1508
|
+
output_tokens=accumulated_token_usage["output_tokens"],
|
|
1509
|
+
input_cost=accumulated_token_usage["input_cost"],
|
|
1510
|
+
output_cost=accumulated_token_usage["output_cost"],
|
|
1511
|
+
speed=0.0,
|
|
1512
|
+
model_names=accumulated_token_usage["model_name"],
|
|
1513
|
+
sampling_count=1
|
|
1514
|
+
)
|
|
1515
|
+
|
|
1596
1516
|
logger.exception(
|
|
1597
1517
|
"An unexpected error occurred during agent execution:")
|
|
1598
1518
|
console.print(Panel(
|
|
@@ -1600,3 +1520,204 @@ class AgenticEdit:
|
|
|
1600
1520
|
raise e
|
|
1601
1521
|
finally:
|
|
1602
1522
|
console.rule("[bold cyan]Agentic Edit Finished[/]")
|
|
1523
|
+
|
|
1524
|
+
def run_with_events(self, request: AgenticEditRequest):
|
|
1525
|
+
"""
|
|
1526
|
+
Runs the agentic edit process, converting internal events to the
|
|
1527
|
+
standard event system format and writing them using the event manager.
|
|
1528
|
+
"""
|
|
1529
|
+
event_manager = get_event_manager(self.args.event_file)
|
|
1530
|
+
self.apply_pre_changes()
|
|
1531
|
+
|
|
1532
|
+
# 用于累计TokenUsageEvent数据
|
|
1533
|
+
accumulated_token_usage = {
|
|
1534
|
+
"model_name": "",
|
|
1535
|
+
"elapsed_time": 0.0,
|
|
1536
|
+
"first_token_time": 0.0,
|
|
1537
|
+
"input_tokens": 0,
|
|
1538
|
+
"output_tokens": 0,
|
|
1539
|
+
"input_cost": 0.0,
|
|
1540
|
+
"output_cost": 0.0
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
try:
|
|
1544
|
+
event_stream = self.analyze(request)
|
|
1545
|
+
for agent_event in event_stream:
|
|
1546
|
+
content = None
|
|
1547
|
+
metadata = EventMetadata(
|
|
1548
|
+
action_file=self.args.file,
|
|
1549
|
+
is_streaming=False,
|
|
1550
|
+
stream_out_type="/agent/edit")
|
|
1551
|
+
|
|
1552
|
+
if isinstance(agent_event, LLMThinkingEvent):
|
|
1553
|
+
content = EventContentCreator.create_stream_thinking(
|
|
1554
|
+
content=agent_event.text)
|
|
1555
|
+
metadata.is_streaming = True
|
|
1556
|
+
metadata.path = "/agent/edit/thinking"
|
|
1557
|
+
event_manager.write_stream(
|
|
1558
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1559
|
+
elif isinstance(agent_event, LLMOutputEvent):
|
|
1560
|
+
content = EventContentCreator.create_stream_content(
|
|
1561
|
+
content=agent_event.text)
|
|
1562
|
+
metadata.is_streaming = True
|
|
1563
|
+
metadata.path = "/agent/edit/output"
|
|
1564
|
+
event_manager.write_stream(content=content.to_dict(),
|
|
1565
|
+
metadata=metadata.to_dict())
|
|
1566
|
+
elif isinstance(agent_event, ToolCallEvent):
|
|
1567
|
+
tool_name = type(agent_event.tool).__name__
|
|
1568
|
+
metadata.path = "/agent/edit/tool/call"
|
|
1569
|
+
content = EventContentCreator.create_result(
|
|
1570
|
+
content={
|
|
1571
|
+
"tool_name": tool_name,
|
|
1572
|
+
**agent_event.tool.model_dump()
|
|
1573
|
+
},
|
|
1574
|
+
metadata={}
|
|
1575
|
+
)
|
|
1576
|
+
event_manager.write_result(
|
|
1577
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1578
|
+
elif isinstance(agent_event, ToolResultEvent):
|
|
1579
|
+
metadata.path = "/agent/edit/tool/result"
|
|
1580
|
+
content = EventContentCreator.create_result(
|
|
1581
|
+
content={
|
|
1582
|
+
"tool_name": agent_event.tool_name,
|
|
1583
|
+
**agent_event.result.model_dump()
|
|
1584
|
+
},
|
|
1585
|
+
metadata={}
|
|
1586
|
+
)
|
|
1587
|
+
event_manager.write_result(
|
|
1588
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1589
|
+
elif isinstance(agent_event, PlanModeRespondEvent):
|
|
1590
|
+
metadata.path = "/agent/edit/plan_mode_respond"
|
|
1591
|
+
content = EventContentCreator.create_markdown_result(
|
|
1592
|
+
content=agent_event.completion.response,
|
|
1593
|
+
metadata={}
|
|
1594
|
+
)
|
|
1595
|
+
event_manager.write_result(
|
|
1596
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1597
|
+
|
|
1598
|
+
elif isinstance(agent_event, TokenUsageEvent):
|
|
1599
|
+
last_meta: SingleOutputMeta = agent_event.usage
|
|
1600
|
+
# Get model info for pricing
|
|
1601
|
+
from autocoder.utils import llms as llm_utils
|
|
1602
|
+
model_name = ",".join(llm_utils.get_llm_names(self.llm))
|
|
1603
|
+
model_info = llm_utils.get_model_info(
|
|
1604
|
+
model_name, self.args.product_mode) or {}
|
|
1605
|
+
input_price = model_info.get(
|
|
1606
|
+
"input_price", 0.0) if model_info else 0.0
|
|
1607
|
+
output_price = model_info.get(
|
|
1608
|
+
"output_price", 0.0) if model_info else 0.0
|
|
1609
|
+
|
|
1610
|
+
# Calculate costs
|
|
1611
|
+
input_cost = (last_meta.input_tokens_count *
|
|
1612
|
+
input_price) / 1000000 # Convert to millions
|
|
1613
|
+
# Convert to millions
|
|
1614
|
+
output_cost = (
|
|
1615
|
+
last_meta.generated_tokens_count * output_price) / 1000000
|
|
1616
|
+
|
|
1617
|
+
# 添加日志记录
|
|
1618
|
+
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}")
|
|
1619
|
+
|
|
1620
|
+
# 累计TokenUsageEvent数据而不是立即发送
|
|
1621
|
+
accumulated_token_usage["model_name"] = model_name
|
|
1622
|
+
if accumulated_token_usage["first_token_time"] == 0.0:
|
|
1623
|
+
accumulated_token_usage["first_token_time"] = last_meta.first_token_time
|
|
1624
|
+
accumulated_token_usage["input_tokens"] += last_meta.input_tokens_count
|
|
1625
|
+
accumulated_token_usage["output_tokens"] += last_meta.generated_tokens_count
|
|
1626
|
+
accumulated_token_usage["input_cost"] += input_cost
|
|
1627
|
+
accumulated_token_usage["output_cost"] += output_cost
|
|
1628
|
+
|
|
1629
|
+
elif isinstance(agent_event, CompletionEvent):
|
|
1630
|
+
# 在这里完成实际合并
|
|
1631
|
+
try:
|
|
1632
|
+
self.apply_changes()
|
|
1633
|
+
except Exception as e:
|
|
1634
|
+
logger.exception(
|
|
1635
|
+
f"Error merging shadow changes to project: {e}")
|
|
1636
|
+
|
|
1637
|
+
# 发送累计的TokenUsageEvent数据
|
|
1638
|
+
get_event_manager(self.args.event_file).write_result(
|
|
1639
|
+
EventContentCreator.create_result(content=EventContentCreator.ResultTokenStatContent(
|
|
1640
|
+
model_name=accumulated_token_usage["model_name"],
|
|
1641
|
+
elapsed_time=0.0,
|
|
1642
|
+
first_token_time=accumulated_token_usage["first_token_time"],
|
|
1643
|
+
input_tokens=accumulated_token_usage["input_tokens"],
|
|
1644
|
+
output_tokens=accumulated_token_usage["output_tokens"],
|
|
1645
|
+
input_cost=accumulated_token_usage["input_cost"],
|
|
1646
|
+
output_cost=accumulated_token_usage["output_cost"]
|
|
1647
|
+
).to_dict()), metadata=metadata.to_dict())
|
|
1648
|
+
|
|
1649
|
+
metadata.path = "/agent/edit/completion"
|
|
1650
|
+
content = EventContentCreator.create_completion(
|
|
1651
|
+
success_code="AGENT_COMPLETE",
|
|
1652
|
+
success_message="Agent attempted task completion.",
|
|
1653
|
+
result={
|
|
1654
|
+
"response": agent_event.completion.result
|
|
1655
|
+
}
|
|
1656
|
+
)
|
|
1657
|
+
event_manager.write_completion(
|
|
1658
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1659
|
+
elif isinstance(agent_event, ErrorEvent):
|
|
1660
|
+
# 发送累计的TokenUsageEvent数据(在错误情况下也需要发送)
|
|
1661
|
+
if accumulated_token_usage["input_tokens"] > 0:
|
|
1662
|
+
get_event_manager(self.args.event_file).write_result(
|
|
1663
|
+
EventContentCreator.create_result(content=EventContentCreator.ResultTokenStatContent(
|
|
1664
|
+
model_name=accumulated_token_usage["model_name"],
|
|
1665
|
+
elapsed_time=0.0,
|
|
1666
|
+
first_token_time=accumulated_token_usage["first_token_time"],
|
|
1667
|
+
input_tokens=accumulated_token_usage["input_tokens"],
|
|
1668
|
+
output_tokens=accumulated_token_usage["output_tokens"],
|
|
1669
|
+
input_cost=accumulated_token_usage["input_cost"],
|
|
1670
|
+
output_cost=accumulated_token_usage["output_cost"]
|
|
1671
|
+
).to_dict()), metadata=metadata.to_dict())
|
|
1672
|
+
|
|
1673
|
+
metadata.path = "/agent/edit/error"
|
|
1674
|
+
content = EventContentCreator.create_error(
|
|
1675
|
+
error_code="AGENT_ERROR",
|
|
1676
|
+
error_message=agent_event.message,
|
|
1677
|
+
details={"agent_event_type": "ErrorEvent"}
|
|
1678
|
+
)
|
|
1679
|
+
event_manager.write_error(
|
|
1680
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1681
|
+
else:
|
|
1682
|
+
metadata.path = "/agent/edit/error"
|
|
1683
|
+
logger.warning(
|
|
1684
|
+
f"Unhandled agent event type: {type(agent_event)}")
|
|
1685
|
+
content = EventContentCreator.create_error(
|
|
1686
|
+
error_code="AGENT_ERROR",
|
|
1687
|
+
error_message=f"Unhandled agent event type: {type(agent_event)}",
|
|
1688
|
+
details={"agent_event_type": type(
|
|
1689
|
+
agent_event).__name__}
|
|
1690
|
+
)
|
|
1691
|
+
event_manager.write_error(
|
|
1692
|
+
content=content.to_dict(), metadata=metadata.to_dict())
|
|
1693
|
+
|
|
1694
|
+
except Exception as e:
|
|
1695
|
+
logger.exception(
|
|
1696
|
+
"An unexpected error occurred during agent execution:")
|
|
1697
|
+
metadata = EventMetadata(
|
|
1698
|
+
action_file=self.args.file,
|
|
1699
|
+
is_streaming=False,
|
|
1700
|
+
stream_out_type="/agent/edit/error")
|
|
1701
|
+
|
|
1702
|
+
# 发送累计的TokenUsageEvent数据(在错误情况下也需要发送)
|
|
1703
|
+
if accumulated_token_usage["input_tokens"] > 0:
|
|
1704
|
+
get_event_manager(self.args.event_file).write_result(
|
|
1705
|
+
EventContentCreator.create_result(content=EventContentCreator.ResultTokenStatContent(
|
|
1706
|
+
model_name=accumulated_token_usage["model_name"],
|
|
1707
|
+
elapsed_time=0.0,
|
|
1708
|
+
first_token_time=accumulated_token_usage["first_token_time"],
|
|
1709
|
+
input_tokens=accumulated_token_usage["input_tokens"],
|
|
1710
|
+
output_tokens=accumulated_token_usage["output_tokens"],
|
|
1711
|
+
input_cost=accumulated_token_usage["input_cost"],
|
|
1712
|
+
output_cost=accumulated_token_usage["output_cost"]
|
|
1713
|
+
).to_dict()), metadata=metadata.to_dict())
|
|
1714
|
+
|
|
1715
|
+
error_content = EventContentCreator.create_error(
|
|
1716
|
+
error_code="AGENT_FATAL_ERROR",
|
|
1717
|
+
error_message=f"An unexpected error occurred: {str(e)}",
|
|
1718
|
+
details={"exception_type": type(e).__name__}
|
|
1719
|
+
)
|
|
1720
|
+
event_manager.write_error(
|
|
1721
|
+
content=error_content.to_dict(), metadata=metadata.to_dict())
|
|
1722
|
+
# Re-raise the exception if needed, or handle appropriately
|
|
1723
|
+
raise e
|