auto-coder 0.1.206__tar.gz → 0.1.208__tar.gz
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.206 → auto_coder-0.1.208}/PKG-INFO +2 -2
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/auto_coder.egg-info/PKG-INFO +2 -2
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/auto_coder.egg-info/SOURCES.txt +3 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/auto_coder.egg-info/requires.txt +1 -1
- auto_coder-0.1.208/src/autocoder/agent/auto_demand_organizer.py +212 -0
- auto_coder-0.1.208/src/autocoder/agent/auto_guess_query.py +284 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/auto_coder.py +64 -19
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/auto_coder_rag.py +11 -2
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/benchmark.py +50 -47
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/chat_auto_coder.py +125 -17
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/command_args.py +21 -5
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/__init__.py +7 -1
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/code_auto_generate.py +32 -10
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/code_auto_generate_diff.py +85 -47
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/code_auto_generate_editblock.py +50 -28
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/code_auto_generate_strict_diff.py +79 -45
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/code_auto_merge.py +51 -15
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/code_auto_merge_diff.py +55 -2
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/code_auto_merge_editblock.py +84 -14
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/code_auto_merge_strict_diff.py +69 -32
- auto_coder-0.1.208/src/autocoder/common/code_modification_ranker.py +100 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/command_completer.py +6 -4
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/types.py +10 -2
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/dispacher/actions/action.py +141 -94
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/dispacher/actions/plugins/action_regex_project.py +35 -25
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/lang.py +9 -1
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/pyproject/__init__.py +4 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/long_context_rag.py +2 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/rag_entry.py +2 -2
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/suffixproject/__init__.py +2 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/tsproject/__init__.py +4 -0
- auto_coder-0.1.208/src/autocoder/version.py +1 -0
- auto_coder-0.1.206/src/autocoder/version.py +0 -1
- {auto_coder-0.1.206 → auto_coder-0.1.208}/LICENSE +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/README.md +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/setup.cfg +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/setup.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/auto_coder.egg-info/dependency_links.txt +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/auto_coder.egg-info/entry_points.txt +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/auto_coder.egg-info/top_level.txt +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/agent/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/agent/auto_filegroup.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/agent/auto_tool.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/agent/coder.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/agent/designer.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/agent/planner.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/agent/project_reader.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/auto_coder_lang.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/auto_coder_server.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/chat/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/chat_auto_coder_lang.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/JupyterClient.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/ShellClient.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/anything2images.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/audio.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/chunk_validation.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/cleaner.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/code_auto_execute.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/command_generator.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/command_templates.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/const.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/git_utils.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/image_to_page.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/interpreter.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/llm_rerank.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/recall_validation.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/screenshots.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/search.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/search_replace.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/sys_prompt.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/common/text.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/data/tokenizer.json +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/db/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/db/store.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/dispacher/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/dispacher/actions/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/dispacher/actions/copilot.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/dispacher/actions/plugins/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/dispacher/actions/plugins/action_translate.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/index/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/index/for_command.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/index/index.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/index/symbols_utils.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/api_server.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/cache/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/cache/base_cache.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/cache/byzer_storage_cache.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/cache/file_monitor_cache.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/cache/simple_cache.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/doc_filter.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/document_retriever.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/llm_wrapper.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/loaders/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/loaders/docx_loader.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/loaders/excel_loader.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/loaders/pdf_loader.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/loaders/ppt_loader.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/rag_config.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/raw_rag.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/relevant_utils.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/simple_directory_reader.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/simple_rag.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/stream_event/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/stream_event/event_writer.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/stream_event/types.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/token_checker.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/token_counter.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/token_limiter.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/types.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/utils.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/rag/variable_holder.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/regexproject/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/__init__.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/_markitdown.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/conversation_store.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/llm_client_interceptors.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/log_capture.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/multi_turn.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/operate_config_api.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/print_table.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/queue_communicate.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/request_event_queue.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/request_queue.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/rest.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/src/autocoder/utils/tests.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/tests/test_action_regex_project.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/tests/test_chat_auto_coder.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/tests/test_code_auto_merge_editblock.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/tests/test_command_completer.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/tests/test_planner.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/tests/test_queue_communicate.py +0 -0
- {auto_coder-0.1.206 → auto_coder-0.1.208}/tests/test_symbols_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: auto-coder
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.208
|
|
4
4
|
Summary: AutoCoder: AutoCoder
|
|
5
5
|
Author: allwefantasy
|
|
6
6
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
@@ -26,7 +26,7 @@ Requires-Dist: tabulate
|
|
|
26
26
|
Requires-Dist: jupyter_client
|
|
27
27
|
Requires-Dist: prompt-toolkit
|
|
28
28
|
Requires-Dist: tokenizers
|
|
29
|
-
Requires-Dist: byzerllm[saas]>=0.1.
|
|
29
|
+
Requires-Dist: byzerllm[saas]>=0.1.143
|
|
30
30
|
Requires-Dist: patch
|
|
31
31
|
Requires-Dist: diff_match_patch
|
|
32
32
|
Requires-Dist: GitPython
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: auto-coder
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.208
|
|
4
4
|
Summary: AutoCoder: AutoCoder
|
|
5
5
|
Author: allwefantasy
|
|
6
6
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
@@ -26,7 +26,7 @@ Requires-Dist: tabulate
|
|
|
26
26
|
Requires-Dist: jupyter_client
|
|
27
27
|
Requires-Dist: prompt-toolkit
|
|
28
28
|
Requires-Dist: tokenizers
|
|
29
|
-
Requires-Dist: byzerllm[saas]>=0.1.
|
|
29
|
+
Requires-Dist: byzerllm[saas]>=0.1.143
|
|
30
30
|
Requires-Dist: patch
|
|
31
31
|
Requires-Dist: diff_match_patch
|
|
32
32
|
Requires-Dist: GitPython
|
|
@@ -19,7 +19,9 @@ src/autocoder/command_args.py
|
|
|
19
19
|
src/autocoder/lang.py
|
|
20
20
|
src/autocoder/version.py
|
|
21
21
|
src/autocoder/agent/__init__.py
|
|
22
|
+
src/autocoder/agent/auto_demand_organizer.py
|
|
22
23
|
src/autocoder/agent/auto_filegroup.py
|
|
24
|
+
src/autocoder/agent/auto_guess_query.py
|
|
23
25
|
src/autocoder/agent/auto_tool.py
|
|
24
26
|
src/autocoder/agent/coder.py
|
|
25
27
|
src/autocoder/agent/designer.py
|
|
@@ -42,6 +44,7 @@ src/autocoder/common/code_auto_merge.py
|
|
|
42
44
|
src/autocoder/common/code_auto_merge_diff.py
|
|
43
45
|
src/autocoder/common/code_auto_merge_editblock.py
|
|
44
46
|
src/autocoder/common/code_auto_merge_strict_diff.py
|
|
47
|
+
src/autocoder/common/code_modification_ranker.py
|
|
45
48
|
src/autocoder/common/command_completer.py
|
|
46
49
|
src/autocoder/common/command_generator.py
|
|
47
50
|
src/autocoder/common/command_templates.py
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
from typing import List, Dict, Optional, Tuple
|
|
2
|
+
import os
|
|
3
|
+
import yaml
|
|
4
|
+
from loguru import logger
|
|
5
|
+
import byzerllm
|
|
6
|
+
import pydantic
|
|
7
|
+
import git
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DemandItem(pydantic.BaseModel):
|
|
11
|
+
"""单个需求项"""
|
|
12
|
+
type: str = pydantic.Field(description="需求类型:New/Update/Delete/Other")
|
|
13
|
+
description: str = pydantic.Field(description="需求描述")
|
|
14
|
+
reason: Optional[str] = pydantic.Field(description="需求原因", default=None)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class OrganizedDemands(pydantic.BaseModel):
|
|
18
|
+
"""整理后的需求列表,按组织划分"""
|
|
19
|
+
group_name: str = pydantic.Field(description="需求组名")
|
|
20
|
+
demands: List[DemandItem]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def load_yaml_config(yaml_file: str) -> Dict:
|
|
24
|
+
"""加载YAML配置文件"""
|
|
25
|
+
try:
|
|
26
|
+
with open(yaml_file, 'r', encoding='utf-8') as f:
|
|
27
|
+
return yaml.safe_load(f)
|
|
28
|
+
except Exception as e:
|
|
29
|
+
logger.error(f"Error loading yaml file {yaml_file}: {str(e)}")
|
|
30
|
+
return {}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AutoDemandOrganizer:
|
|
34
|
+
def __init__(self, llm: byzerllm.ByzerLLM,
|
|
35
|
+
project_dir: str,
|
|
36
|
+
skip_diff: bool = False,
|
|
37
|
+
file_size_limit: int = 100):
|
|
38
|
+
"""
|
|
39
|
+
初始化需求整理器
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
llm: ByzerLLM 实例
|
|
43
|
+
project_dir: 项目根目录
|
|
44
|
+
file_size_limit: 最多分析多少历史任务
|
|
45
|
+
"""
|
|
46
|
+
self.project_dir = project_dir
|
|
47
|
+
self.actions_dir = os.path.join(project_dir, "actions")
|
|
48
|
+
self.llm = llm
|
|
49
|
+
self.file_size_limit = file_size_limit
|
|
50
|
+
self.skip_diff = skip_diff
|
|
51
|
+
|
|
52
|
+
@byzerllm.prompt()
|
|
53
|
+
def organize_demands(self, querie_with_urls: List[Tuple[str, List[str], str]]) -> str:
|
|
54
|
+
"""
|
|
55
|
+
根据历史开发任务,整理出清晰的产品需求变更记录。
|
|
56
|
+
|
|
57
|
+
输入数据格式:
|
|
58
|
+
querie_with_urls 包含多个历史任务信息,每个任务由以下部分组成:
|
|
59
|
+
1. query: 任务需求描述
|
|
60
|
+
2. urls: 修改的文件路径列表
|
|
61
|
+
3. diff: Git diff信息,展示具体的代码修改
|
|
62
|
+
|
|
63
|
+
示例数据:
|
|
64
|
+
<queries>
|
|
65
|
+
{% for query,urls,diff in querie_with_urls %}
|
|
66
|
+
## {{ query }}
|
|
67
|
+
|
|
68
|
+
修改的文件:
|
|
69
|
+
{% for url in urls %}
|
|
70
|
+
- {{ url }}
|
|
71
|
+
{% endfor %}
|
|
72
|
+
{% if diff %}
|
|
73
|
+
|
|
74
|
+
代码变更:
|
|
75
|
+
```diff
|
|
76
|
+
{{ diff }}
|
|
77
|
+
```
|
|
78
|
+
{% endif %}
|
|
79
|
+
{% endfor %}
|
|
80
|
+
</queries>
|
|
81
|
+
|
|
82
|
+
整理规则:
|
|
83
|
+
1. 将每个任务拆分为多个独立的需求点
|
|
84
|
+
2. 为每个需求点添加类型标签:
|
|
85
|
+
- New: 新增功能
|
|
86
|
+
- Update: 功能更新
|
|
87
|
+
- Delete: 功能删除
|
|
88
|
+
- Other: 不确定的变更
|
|
89
|
+
3. 每个需求点应包含:
|
|
90
|
+
- 清晰的描述
|
|
91
|
+
- 相关原因(如果有)
|
|
92
|
+
- 涉及的文件列表(如果有)
|
|
93
|
+
4. 保持原始信息的完整性,不要遗漏任何细节
|
|
94
|
+
|
|
95
|
+
返回格式说明:
|
|
96
|
+
返回符合以下格式的JSON:
|
|
97
|
+
{
|
|
98
|
+
"group_name": "需求组名称",
|
|
99
|
+
"demands": [
|
|
100
|
+
{
|
|
101
|
+
"type": "需求类型",
|
|
102
|
+
"description": "需求描述",
|
|
103
|
+
"reason": "需求原因(可选)"
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
示例返回:
|
|
109
|
+
{
|
|
110
|
+
"group_name": "用户系统优化",
|
|
111
|
+
"demands": [
|
|
112
|
+
{
|
|
113
|
+
"type": "New",
|
|
114
|
+
"description": "新增用户登录功能",
|
|
115
|
+
"reason": "满足用户身份验证需求"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"type": "Update",
|
|
119
|
+
"description": "优化登录页面UI"
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
"""
|
|
124
|
+
pass
|
|
125
|
+
|
|
126
|
+
def parse_history_tasks(self) -> List[Dict]:
|
|
127
|
+
"""
|
|
128
|
+
解析历史任务信息
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
List[Dict]: 每个字典包含一个历史任务的信息
|
|
132
|
+
"""
|
|
133
|
+
# 获取所有YAML文件
|
|
134
|
+
action_files = [
|
|
135
|
+
f for f in os.listdir(self.actions_dir)
|
|
136
|
+
if f[:3].isdigit() and "_" in f and f.endswith('.yml')
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
# 按序号排序
|
|
140
|
+
def get_seq(name):
|
|
141
|
+
return int(name.split("_")[0])
|
|
142
|
+
|
|
143
|
+
# 获取最新的action文件列表
|
|
144
|
+
action_files = sorted(action_files, key=get_seq)
|
|
145
|
+
action_files.reverse()
|
|
146
|
+
|
|
147
|
+
action_files = action_files[:self.file_size_limit]
|
|
148
|
+
|
|
149
|
+
querie_with_urls_and_diffs = []
|
|
150
|
+
repo = git.Repo(self.project_dir)
|
|
151
|
+
|
|
152
|
+
# 收集所有query、urls和对应的commit diff
|
|
153
|
+
for yaml_file in action_files:
|
|
154
|
+
yaml_path = os.path.join(self.actions_dir, yaml_file)
|
|
155
|
+
config = load_yaml_config(yaml_path)
|
|
156
|
+
|
|
157
|
+
if not config:
|
|
158
|
+
continue
|
|
159
|
+
|
|
160
|
+
query = config.get('query', '')
|
|
161
|
+
urls = config.get('urls', [])
|
|
162
|
+
|
|
163
|
+
if query and urls:
|
|
164
|
+
commit_diff = ""
|
|
165
|
+
if not self.skip_diff:
|
|
166
|
+
# 计算文件的MD5用于匹配commit
|
|
167
|
+
import hashlib
|
|
168
|
+
file_md5 = hashlib.md5(open(yaml_path, 'rb').read()).hexdigest()
|
|
169
|
+
response_id = f"auto_coder_{yaml_file}_{file_md5}"
|
|
170
|
+
# 查找对应的commit
|
|
171
|
+
try:
|
|
172
|
+
for commit in repo.iter_commits():
|
|
173
|
+
if response_id in commit.message:
|
|
174
|
+
if commit.parents:
|
|
175
|
+
parent = commit.parents[0]
|
|
176
|
+
commit_diff = repo.git.diff(
|
|
177
|
+
parent.hexsha, commit.hexsha)
|
|
178
|
+
else:
|
|
179
|
+
commit_diff = repo.git.show(commit.hexsha)
|
|
180
|
+
break
|
|
181
|
+
except git.exc.GitCommandError as e:
|
|
182
|
+
logger.error(f"Git命令执行错误: {str(e)}")
|
|
183
|
+
except Exception as e:
|
|
184
|
+
logger.error(f"获取commit diff时出错: {str(e)}")
|
|
185
|
+
|
|
186
|
+
querie_with_urls_and_diffs.append((query, urls, commit_diff))
|
|
187
|
+
|
|
188
|
+
return querie_with_urls_and_diffs
|
|
189
|
+
|
|
190
|
+
def organize(self) -> Optional[OrganizedDemands]:
|
|
191
|
+
"""
|
|
192
|
+
整理需求变更
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
OrganizedDemands: 整理后的需求列表,如果整理失败则返回None
|
|
196
|
+
"""
|
|
197
|
+
history_tasks = self.parse_history_tasks()
|
|
198
|
+
|
|
199
|
+
if not history_tasks:
|
|
200
|
+
logger.warning("No history tasks found")
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
result = self.organize_demands.with_llm(self.llm).with_return_type(OrganizedDemands).run(
|
|
205
|
+
querie_with_urls=history_tasks
|
|
206
|
+
)
|
|
207
|
+
return result
|
|
208
|
+
except Exception as e:
|
|
209
|
+
import traceback
|
|
210
|
+
traceback.print_exc()
|
|
211
|
+
logger.error(f"Error organizing demands: {str(e)}")
|
|
212
|
+
return None
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
from typing import List, Dict, Any, Tuple, Optional
|
|
2
|
+
import os
|
|
3
|
+
import yaml
|
|
4
|
+
from loguru import logger
|
|
5
|
+
import byzerllm
|
|
6
|
+
import pydantic
|
|
7
|
+
import git
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.panel import Panel
|
|
10
|
+
from prompt_toolkit import prompt
|
|
11
|
+
from prompt_toolkit.formatted_text import FormattedText
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class NextQuery(pydantic.BaseModel):
|
|
16
|
+
"""下一个开发任务的描述和相关信息"""
|
|
17
|
+
query: str = pydantic.Field(description="任务需求描述")
|
|
18
|
+
urls: List[str] = pydantic.Field(description="预测可能需要修改的文件路径列表")
|
|
19
|
+
priority: int = pydantic.Field(description="任务优先级,1-5,5为最高优先级")
|
|
20
|
+
reason: str = pydantic.Field(description="为什么需要这个任务,以及为什么需要修改这些文件")
|
|
21
|
+
dependency_queries: List[str] = pydantic.Field(description="依赖的历史任务列表", default_factory=list)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def load_yaml_config(yaml_file: str) -> Dict:
|
|
25
|
+
"""加载YAML配置文件"""
|
|
26
|
+
try:
|
|
27
|
+
with open(yaml_file, 'r', encoding='utf-8') as f:
|
|
28
|
+
return yaml.safe_load(f)
|
|
29
|
+
except Exception as e:
|
|
30
|
+
logger.error(f"Error loading yaml file {yaml_file}: {str(e)}")
|
|
31
|
+
return {}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class AutoGuessQuery:
|
|
35
|
+
def __init__(self, llm: byzerllm.ByzerLLM,
|
|
36
|
+
project_dir: str,
|
|
37
|
+
skip_diff: bool = False,
|
|
38
|
+
file_size_limit: int = 100):
|
|
39
|
+
"""
|
|
40
|
+
初始化 AutoGuessQuery
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
llm: ByzerLLM 实例,用于生成下一步任务预测
|
|
44
|
+
project_dir: 项目根目录
|
|
45
|
+
skip_diff: 是否跳过获取 diff 信息
|
|
46
|
+
file_size_limit: 最多分析多少历史任务
|
|
47
|
+
"""
|
|
48
|
+
self.project_dir = project_dir
|
|
49
|
+
self.actions_dir = os.path.join(project_dir, "actions")
|
|
50
|
+
self.llm = llm
|
|
51
|
+
self.file_size_limit = file_size_limit
|
|
52
|
+
self.skip_diff = skip_diff
|
|
53
|
+
|
|
54
|
+
@byzerllm.prompt()
|
|
55
|
+
def guess_next_query(self, querie_with_urls: List[Tuple[str, List[str], str]], task_limit_size: int = 5) -> str:
|
|
56
|
+
"""
|
|
57
|
+
根据历史开发任务,预测接下来可能的多个开发任务,按照可能性从高到低排序。
|
|
58
|
+
|
|
59
|
+
输入数据格式:
|
|
60
|
+
querie_with_urls 包含多个历史任务信息,每个任务由以下部分组成:
|
|
61
|
+
1. query: 任务需求描述
|
|
62
|
+
2. urls: 修改的文件路径列表
|
|
63
|
+
3. diff: Git diff信息,展示具体的代码修改
|
|
64
|
+
|
|
65
|
+
示例数据:
|
|
66
|
+
<queries>
|
|
67
|
+
{% for query,urls,diff in querie_with_urls %}
|
|
68
|
+
## {{ query }}
|
|
69
|
+
|
|
70
|
+
修改的文件:
|
|
71
|
+
{% for url in urls %}
|
|
72
|
+
- {{ url }}
|
|
73
|
+
{% endfor %}
|
|
74
|
+
{% if diff %}
|
|
75
|
+
|
|
76
|
+
代码变更:
|
|
77
|
+
```diff
|
|
78
|
+
{{ diff }}
|
|
79
|
+
```
|
|
80
|
+
{% endif %}
|
|
81
|
+
{% endfor %}
|
|
82
|
+
</queries>
|
|
83
|
+
|
|
84
|
+
分析要求:
|
|
85
|
+
1. 分析历史任务的模式和规律
|
|
86
|
+
- 功能演进路径:项目功能是如何逐步完善的
|
|
87
|
+
- 代码变更模式:相似功能通常涉及哪些文件
|
|
88
|
+
- 依赖关系:新功能和已有功能的关联
|
|
89
|
+
|
|
90
|
+
2. 预测可能的任务时考虑:
|
|
91
|
+
- 完整性:现有功能是否有待完善的地方
|
|
92
|
+
- 扩展性:是否需要支持新的场景
|
|
93
|
+
- 健壮性:是否需要增加容错和异常处理
|
|
94
|
+
- 性能:是否有性能优化空间
|
|
95
|
+
- 交互性:是否需要改善用户体验
|
|
96
|
+
- 可维护性:是否需要重构或优化代码结构
|
|
97
|
+
|
|
98
|
+
返回格式说明:
|
|
99
|
+
返回一个JSON数组,数组中每个元素是一个NextQuery对象,按照可能性从高到低排序。每个对象包含:
|
|
100
|
+
1. query: 任务的具体描述
|
|
101
|
+
2. urls: 预计需要修改的文件列表
|
|
102
|
+
3. priority: 优先级(1-5)
|
|
103
|
+
4. reason: 为什么建议这个任务
|
|
104
|
+
5. dependency_queries: 相关的历史任务列表
|
|
105
|
+
|
|
106
|
+
示例返回:
|
|
107
|
+
[
|
|
108
|
+
{
|
|
109
|
+
"query": "添加任务预测的单元测试",
|
|
110
|
+
"urls": ["tests/test_auto_guess_query.py"],
|
|
111
|
+
"priority": 5,
|
|
112
|
+
"reason": "确保任务预测功能的正确性和稳定性对项目质量至关重要",
|
|
113
|
+
"dependency_queries": ["实现任务预测功能"]
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"query": "优化向量搜索性能",
|
|
117
|
+
"urls": ["src/autocoder/utils/search.py"],
|
|
118
|
+
"priority": 4,
|
|
119
|
+
"reason": "当前搜索速度较慢,需要添加向量索引提升性能",
|
|
120
|
+
"dependency_queries": ["实现向量搜索基础功能"]
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
注意:
|
|
125
|
+
1. 每个预测的任务都应该具体且可执行,而不是抽象的目标
|
|
126
|
+
2. 文件路径预测应该基于已有文件的实际路径
|
|
127
|
+
3. reason应该详细解释为什么这个任务重要,以及为什么需要修改这些文件
|
|
128
|
+
4. priority的指定需要考虑任务的紧迫性和重要性
|
|
129
|
+
3. 建议返回最多{{ task_limit_size }}个不同优先级的任务,覆盖不同的改进方向
|
|
130
|
+
"""
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
def parse_history_tasks(self) -> List[Dict]:
|
|
134
|
+
"""
|
|
135
|
+
解析历史任务信息
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
List[Dict]: 每个字典包含一个历史任务的信息
|
|
139
|
+
"""
|
|
140
|
+
# 获取所有YAML文件
|
|
141
|
+
action_files = [
|
|
142
|
+
f for f in os.listdir(self.actions_dir)
|
|
143
|
+
if f[:3].isdigit() and "_" in f and f.endswith('.yml')
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
# 按序号排序
|
|
147
|
+
def get_seq(name):
|
|
148
|
+
return int(name.split("_")[0])
|
|
149
|
+
|
|
150
|
+
# 获取最新的action文件列表
|
|
151
|
+
action_files = sorted(action_files, key=get_seq)
|
|
152
|
+
action_files.reverse()
|
|
153
|
+
|
|
154
|
+
action_files = action_files[:self.file_size_limit]
|
|
155
|
+
|
|
156
|
+
querie_with_urls_and_diffs = []
|
|
157
|
+
repo = git.Repo(self.project_dir)
|
|
158
|
+
|
|
159
|
+
# 收集所有query、urls和对应的commit diff
|
|
160
|
+
for yaml_file in action_files:
|
|
161
|
+
yaml_path = os.path.join(self.actions_dir, yaml_file)
|
|
162
|
+
config = load_yaml_config(yaml_path)
|
|
163
|
+
|
|
164
|
+
if not config:
|
|
165
|
+
continue
|
|
166
|
+
|
|
167
|
+
query = config.get('query', '')
|
|
168
|
+
urls = config.get('urls', [])
|
|
169
|
+
|
|
170
|
+
if query and urls:
|
|
171
|
+
commit_diff = ""
|
|
172
|
+
if not self.skip_diff:
|
|
173
|
+
# 计算文件的MD5用于匹配commit
|
|
174
|
+
import hashlib
|
|
175
|
+
file_md5 = hashlib.md5(open(yaml_path, 'rb').read()).hexdigest()
|
|
176
|
+
response_id = f"auto_coder_{yaml_file}_{file_md5}"
|
|
177
|
+
# 查找对应的commit
|
|
178
|
+
try:
|
|
179
|
+
for commit in repo.iter_commits():
|
|
180
|
+
if response_id in commit.message:
|
|
181
|
+
if commit.parents:
|
|
182
|
+
parent = commit.parents[0]
|
|
183
|
+
commit_diff = repo.git.diff(
|
|
184
|
+
parent.hexsha, commit.hexsha)
|
|
185
|
+
else:
|
|
186
|
+
commit_diff = repo.git.show(commit.hexsha)
|
|
187
|
+
break
|
|
188
|
+
except git.exc.GitCommandError as e:
|
|
189
|
+
logger.error(f"Git命令执行错误: {str(e)}")
|
|
190
|
+
except Exception as e:
|
|
191
|
+
logger.error(f"获取commit diff时出错: {str(e)}")
|
|
192
|
+
|
|
193
|
+
querie_with_urls_and_diffs.append((query, urls, commit_diff))
|
|
194
|
+
|
|
195
|
+
return querie_with_urls_and_diffs
|
|
196
|
+
|
|
197
|
+
def predict_next_tasks(self, task_limit_size: int = 5, is_human_as_model: bool = False) -> Optional[List[NextQuery]]:
|
|
198
|
+
"""
|
|
199
|
+
预测接下来可能的开发任务列表,按照可能性从高到低排序
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
task_limit_size: 返回的任务数量限制,默认5个
|
|
203
|
+
is_human_as_model: 是否人工模式,如果为True则输出prompt供人工编写结果
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
List[NextQuery]: 预测的任务列表,如果预测失败则返回None
|
|
207
|
+
"""
|
|
208
|
+
history_tasks = self.parse_history_tasks()
|
|
209
|
+
|
|
210
|
+
if not history_tasks:
|
|
211
|
+
logger.warning("No history tasks found")
|
|
212
|
+
return None
|
|
213
|
+
|
|
214
|
+
try:
|
|
215
|
+
if is_human_as_model:
|
|
216
|
+
console = Console()
|
|
217
|
+
|
|
218
|
+
# 生成prompt
|
|
219
|
+
prompt_content = self.guess_next_query.prompt(
|
|
220
|
+
querie_with_urls=history_tasks,
|
|
221
|
+
task_limit_size=task_limit_size
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
import pyperclip
|
|
226
|
+
pyperclip.copy(prompt_content)
|
|
227
|
+
console.print(
|
|
228
|
+
Panel(
|
|
229
|
+
"The prompt has been copied to clipboard. Please paste it into the LLM and input the response below.",
|
|
230
|
+
title="Instructions",
|
|
231
|
+
border_style="blue",
|
|
232
|
+
expand=False,
|
|
233
|
+
)
|
|
234
|
+
)
|
|
235
|
+
except Exception:
|
|
236
|
+
logger.warning("Clipboard not supported")
|
|
237
|
+
console.print(
|
|
238
|
+
Panel(
|
|
239
|
+
"The prompt could not be copied to clipboard. Please manually copy the following content:",
|
|
240
|
+
title="Instructions",
|
|
241
|
+
border_style="blue",
|
|
242
|
+
expand=False,
|
|
243
|
+
)
|
|
244
|
+
)
|
|
245
|
+
console.print(prompt_content)
|
|
246
|
+
|
|
247
|
+
lines = []
|
|
248
|
+
while True:
|
|
249
|
+
line = prompt(FormattedText([("#00FF00", "> ")]), multiline=False)
|
|
250
|
+
line_lower = line.strip().lower()
|
|
251
|
+
if line_lower in ["eof", "/eof"]:
|
|
252
|
+
break
|
|
253
|
+
elif line_lower in ["/clear"]:
|
|
254
|
+
lines = []
|
|
255
|
+
print("\033[2J\033[H") # Clear terminal screen
|
|
256
|
+
continue
|
|
257
|
+
elif line_lower in ["/break"]:
|
|
258
|
+
raise Exception("User requested to break the operation.")
|
|
259
|
+
lines.append(line)
|
|
260
|
+
|
|
261
|
+
result = "\n".join(lines)
|
|
262
|
+
|
|
263
|
+
# 从输入中抽取JSON字符串并解析
|
|
264
|
+
from byzerllm.utils.client import code_utils
|
|
265
|
+
import json
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
json_str = code_utils.extract_code(result)[0][1]
|
|
269
|
+
task_list = json.loads(json_str)
|
|
270
|
+
return [NextQuery(**task) for task in task_list]
|
|
271
|
+
except Exception as e:
|
|
272
|
+
logger.error(f"Error parsing input: {str(e)}")
|
|
273
|
+
return None
|
|
274
|
+
else:
|
|
275
|
+
result = self.guess_next_query.with_llm(self.llm).with_return_type(NextQuery).run(
|
|
276
|
+
querie_with_urls=history_tasks,
|
|
277
|
+
task_limit_size=task_limit_size
|
|
278
|
+
)
|
|
279
|
+
return result
|
|
280
|
+
except Exception as e:
|
|
281
|
+
import traceback
|
|
282
|
+
traceback.print_exc()
|
|
283
|
+
logger.error(f"Error predicting next task: {str(e)}")
|
|
284
|
+
return None
|