auto-coder 2.0.0__py3-none-any.whl → 2.0.1__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-2.0.0.dist-info → auto_coder-2.0.1.dist-info}/METADATA +1 -1
- {auto_coder-2.0.0.dist-info → auto_coder-2.0.1.dist-info}/RECORD +19 -19
- autocoder/agent/entry_command_agent/chat.py +7 -17
- autocoder/auto_coder_runner.py +1 -9
- autocoder/common/file_handler/coding_handler.py +14 -6
- autocoder/common/llms/registry.py +29 -1
- autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +14 -7
- autocoder/completer/command_completer_v2.py +43 -0
- autocoder/dispacher/actions/action.py +268 -155
- autocoder/index/entry.py +1 -1
- autocoder/inner/agentic.py +1 -10
- autocoder/version.py +1 -1
- autocoder/workflow_agents/executor.py +177 -1
- autocoder/workflow_agents/loader.py +12 -0
- autocoder/workflow_agents/types.py +1 -0
- {auto_coder-2.0.0.dist-info → auto_coder-2.0.1.dist-info}/LICENSE +0 -0
- {auto_coder-2.0.0.dist-info → auto_coder-2.0.1.dist-info}/WHEEL +0 -0
- {auto_coder-2.0.0.dist-info → auto_coder-2.0.1.dist-info}/entry_points.txt +0 -0
- {auto_coder-2.0.0.dist-info → auto_coder-2.0.1.dist-info}/top_level.txt +0 -0
autocoder/index/entry.py
CHANGED
autocoder/inner/agentic.py
CHANGED
|
@@ -197,16 +197,7 @@ class RunAgentic:
|
|
|
197
197
|
|
|
198
198
|
# 3. 处理特殊对话操作
|
|
199
199
|
if self._handle_conversation_actions(conversation_config):
|
|
200
|
-
return conversation_config.conversation_id
|
|
201
|
-
|
|
202
|
-
# 4. 创建新对话
|
|
203
|
-
conversation_manager = get_conversation_manager()
|
|
204
|
-
conversation_id = conversation_manager.create_conversation(
|
|
205
|
-
name=query or "New Conversation",
|
|
206
|
-
description=query or "New Conversation",
|
|
207
|
-
)
|
|
208
|
-
conversation_manager.set_current_conversation(conversation_id)
|
|
209
|
-
conversation_config.conversation_id = conversation_id
|
|
200
|
+
return conversation_config.conversation_id
|
|
210
201
|
|
|
211
202
|
# 5. 配置过滤模式参数
|
|
212
203
|
args_copy = deepcopy(args)
|
autocoder/version.py
CHANGED
|
@@ -7,6 +7,8 @@ Subagent Workflow 执行器
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any, Dict, List, Optional, Set, Tuple
|
|
9
9
|
from copy import deepcopy
|
|
10
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
11
|
+
import json
|
|
10
12
|
from loguru import logger
|
|
11
13
|
|
|
12
14
|
from autocoder.common import AutoCoderArgs
|
|
@@ -421,6 +423,22 @@ class SubagentWorkflowExecutor:
|
|
|
421
423
|
step_id=step.id, status=StepStatus.FAILED, error=error_msg
|
|
422
424
|
)
|
|
423
425
|
|
|
426
|
+
# 检查是否需要并行执行
|
|
427
|
+
if step.replicas > 1:
|
|
428
|
+
return self._execute_step_parallel(step)
|
|
429
|
+
else:
|
|
430
|
+
return self._execute_step_single(step)
|
|
431
|
+
|
|
432
|
+
def _execute_step_single(self, step: StepSpec) -> StepResult:
|
|
433
|
+
"""
|
|
434
|
+
执行单个步骤(非并行)
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
step: 步骤规格
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
StepResult 对象
|
|
441
|
+
"""
|
|
424
442
|
try:
|
|
425
443
|
# 渲染用户输入
|
|
426
444
|
user_input = render_template(
|
|
@@ -433,7 +451,7 @@ class SubagentWorkflowExecutor:
|
|
|
433
451
|
conversation_config = self._get_conversation_config(step)
|
|
434
452
|
|
|
435
453
|
# 运行代理
|
|
436
|
-
agent = self.agents[
|
|
454
|
+
agent = self.agents[step.agent]
|
|
437
455
|
completion = agent.run(
|
|
438
456
|
user_input=user_input,
|
|
439
457
|
conversation_config=conversation_config,
|
|
@@ -487,3 +505,161 @@ class SubagentWorkflowExecutor:
|
|
|
487
505
|
return StepResult(
|
|
488
506
|
step_id=step.id, status=StepStatus.FAILED, error=error_msg
|
|
489
507
|
)
|
|
508
|
+
|
|
509
|
+
def _execute_step_parallel(self, step: StepSpec) -> StepResult:
|
|
510
|
+
"""
|
|
511
|
+
并行执行单个步骤的多个副本
|
|
512
|
+
|
|
513
|
+
Args:
|
|
514
|
+
step: 步骤规格
|
|
515
|
+
|
|
516
|
+
Returns:
|
|
517
|
+
StepResult 对象,包含合并后的结果
|
|
518
|
+
"""
|
|
519
|
+
logger.info(f"步骤 {step.id} 将并行执行 {step.replicas} 个副本")
|
|
520
|
+
|
|
521
|
+
# 渲染用户输入(所有副本使用相同输入)
|
|
522
|
+
try:
|
|
523
|
+
user_input = render_template(
|
|
524
|
+
step.with_args.get("user_input", ""), self.context
|
|
525
|
+
)
|
|
526
|
+
if not isinstance(user_input, str):
|
|
527
|
+
user_input = str(user_input)
|
|
528
|
+
except Exception as e:
|
|
529
|
+
error_msg = f"渲染输入失败: {str(e)}"
|
|
530
|
+
logger.error(f"步骤 {step.id} {error_msg}", exc_info=True)
|
|
531
|
+
return StepResult(
|
|
532
|
+
step_id=step.id, status=StepStatus.FAILED, error=error_msg
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
# 并行执行所有副本
|
|
536
|
+
agent = self.agents[step.agent]
|
|
537
|
+
results = []
|
|
538
|
+
errors = []
|
|
539
|
+
|
|
540
|
+
def run_replica(replica_idx: int):
|
|
541
|
+
"""运行单个副本"""
|
|
542
|
+
try:
|
|
543
|
+
logger.info(
|
|
544
|
+
f"步骤 {step.id} 副本 {replica_idx + 1}/{step.replicas} 开始执行"
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
# 获取会话配置(每个副本独立会话)
|
|
548
|
+
conversation_config = self._get_conversation_config(step)
|
|
549
|
+
|
|
550
|
+
# 运行代理
|
|
551
|
+
completion = agent.run(
|
|
552
|
+
user_input=user_input,
|
|
553
|
+
conversation_config=conversation_config,
|
|
554
|
+
args=self.args,
|
|
555
|
+
llm=self.llm,
|
|
556
|
+
cancel_token=self.cancel_token,
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
if completion is None:
|
|
560
|
+
return (replica_idx, None, "代理未返回结果")
|
|
561
|
+
|
|
562
|
+
logger.info(
|
|
563
|
+
f"步骤 {step.id} 副本 {replica_idx + 1}/{step.replicas} 执行完成"
|
|
564
|
+
)
|
|
565
|
+
return (replica_idx, completion.result, None)
|
|
566
|
+
|
|
567
|
+
except Exception as e:
|
|
568
|
+
error_msg = f"副本 {replica_idx + 1} 执行异常: {str(e)}"
|
|
569
|
+
logger.error(f"步骤 {step.id} {error_msg}", exc_info=True)
|
|
570
|
+
return (replica_idx, None, error_msg)
|
|
571
|
+
|
|
572
|
+
# 使用线程池并行执行
|
|
573
|
+
with ThreadPoolExecutor(max_workers=step.replicas) as executor:
|
|
574
|
+
futures = [executor.submit(run_replica, i) for i in range(step.replicas)]
|
|
575
|
+
|
|
576
|
+
for future in as_completed(futures):
|
|
577
|
+
replica_idx, result, error = future.result()
|
|
578
|
+
if error:
|
|
579
|
+
errors.append(f"副本 {replica_idx + 1}: {error}")
|
|
580
|
+
else:
|
|
581
|
+
results.append((replica_idx, result))
|
|
582
|
+
|
|
583
|
+
# 判断成功:任意一个成功即可(any-success 策略)
|
|
584
|
+
if not results:
|
|
585
|
+
# 全部失败
|
|
586
|
+
error_msg = f"所有 {step.replicas} 个副本都失败了: " + "; ".join(errors)
|
|
587
|
+
logger.error(f"步骤 {step.id} {error_msg}")
|
|
588
|
+
return StepResult(
|
|
589
|
+
step_id=step.id, status=StepStatus.FAILED, error=error_msg
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
# 至少有一个成功
|
|
593
|
+
logger.info(f"步骤 {step.id} 成功执行了 {len(results)}/{step.replicas} 个副本")
|
|
594
|
+
|
|
595
|
+
# 合并结果
|
|
596
|
+
merged_result = self._merge_replica_results(results, step)
|
|
597
|
+
|
|
598
|
+
# 更新上下文
|
|
599
|
+
self.context["_last_attempt_result"] = merged_result
|
|
600
|
+
|
|
601
|
+
# 提取输出(从合并后的结果中提取)
|
|
602
|
+
try:
|
|
603
|
+
outputs = extract_outputs(
|
|
604
|
+
outputs_map=step.outputs,
|
|
605
|
+
attempt_result=merged_result,
|
|
606
|
+
attempt_format=self.spec.attempt.format,
|
|
607
|
+
default_jsonpaths=self.spec.attempt.jsonpaths,
|
|
608
|
+
context=self.context,
|
|
609
|
+
)
|
|
610
|
+
except Exception as e:
|
|
611
|
+
logger.warning(f"步骤 {step.id} 提取输出失败: {e},使用空输出")
|
|
612
|
+
outputs = {}
|
|
613
|
+
|
|
614
|
+
# 注入内置变量:conversation_id
|
|
615
|
+
outputs["conversation_id"] = self._conversation_id
|
|
616
|
+
|
|
617
|
+
# 保存到上下文
|
|
618
|
+
if step.id not in self.context["steps"]:
|
|
619
|
+
self.context["steps"][step.id] = {"outputs": {}}
|
|
620
|
+
|
|
621
|
+
self.context["steps"][step.id]["outputs"].update(outputs)
|
|
622
|
+
logger.debug(f"步骤 {step.id} 输出: {list(outputs.keys())}")
|
|
623
|
+
|
|
624
|
+
return StepResult(
|
|
625
|
+
step_id=step.id,
|
|
626
|
+
status=StepStatus.SUCCESS,
|
|
627
|
+
attempt_result=merged_result,
|
|
628
|
+
outputs=outputs,
|
|
629
|
+
)
|
|
630
|
+
|
|
631
|
+
def _merge_replica_results(
|
|
632
|
+
self, results: List[Tuple[int, str]], step: StepSpec
|
|
633
|
+
) -> str:
|
|
634
|
+
"""
|
|
635
|
+
合并多个副本的结果
|
|
636
|
+
|
|
637
|
+
Args:
|
|
638
|
+
results: [(replica_idx, attempt_result), ...]
|
|
639
|
+
step: 步骤规格
|
|
640
|
+
|
|
641
|
+
Returns:
|
|
642
|
+
合并后的结果字符串
|
|
643
|
+
"""
|
|
644
|
+
# 按副本索引排序
|
|
645
|
+
sorted_results = sorted(results, key=lambda x: x[0])
|
|
646
|
+
attempt_results = [result for _, result in sorted_results]
|
|
647
|
+
|
|
648
|
+
# 根据 attempt.format 决定合并方式
|
|
649
|
+
if self.spec.attempt.format == "json":
|
|
650
|
+
# JSON 格式:尝试将多个结果打包成 JSON 数组
|
|
651
|
+
json_objects = []
|
|
652
|
+
for result in attempt_results:
|
|
653
|
+
try:
|
|
654
|
+
obj = json.loads(result)
|
|
655
|
+
json_objects.append(obj)
|
|
656
|
+
except json.JSONDecodeError:
|
|
657
|
+
# 如果解析失败,保留原始字符串
|
|
658
|
+
json_objects.append({"raw": result})
|
|
659
|
+
|
|
660
|
+
# 返回 JSON 数组字符串
|
|
661
|
+
return json.dumps(json_objects, ensure_ascii=False, indent=2)
|
|
662
|
+
else:
|
|
663
|
+
# Text 格式:用分隔符拼接
|
|
664
|
+
separator = "\n---\n"
|
|
665
|
+
return separator.join(attempt_results)
|
|
@@ -383,6 +383,17 @@ def parse_step_spec(
|
|
|
383
383
|
parse_step_conversation_config(conv_data, context) if conv_data else None
|
|
384
384
|
)
|
|
385
385
|
|
|
386
|
+
# 解析 replicas
|
|
387
|
+
replicas = data.get("replicas", 1)
|
|
388
|
+
if not isinstance(replicas, int) or replicas < 1:
|
|
389
|
+
raise WorkflowValidationError(
|
|
390
|
+
message="replicas 必须是正整数",
|
|
391
|
+
field_path=f"{context}.replicas",
|
|
392
|
+
expected="正整数(>= 1)",
|
|
393
|
+
actual=str(replicas),
|
|
394
|
+
suggestion="将 replicas 设置为正整数,如 2(表示并行运行2个副本)",
|
|
395
|
+
)
|
|
396
|
+
|
|
386
397
|
return StepSpec(
|
|
387
398
|
id=step_id,
|
|
388
399
|
agent=agent_id,
|
|
@@ -391,6 +402,7 @@ def parse_step_spec(
|
|
|
391
402
|
when=when_config,
|
|
392
403
|
outputs=outputs,
|
|
393
404
|
conversation=conversation,
|
|
405
|
+
replicas=replicas,
|
|
394
406
|
)
|
|
395
407
|
|
|
396
408
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|