auto-coder 0.1.355__py3-none-any.whl → 0.1.356__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.355.dist-info → auto_coder-0.1.356.dist-info}/METADATA +1 -1
- {auto_coder-0.1.355.dist-info → auto_coder-0.1.356.dist-info}/RECORD +19 -17
- autocoder/agent/auto_learn.py +631 -0
- autocoder/auto_coder_runner.py +9 -10
- autocoder/chat/rules_command.py +458 -0
- autocoder/chat_auto_coder.py +5 -0
- autocoder/chat_auto_coder_lang.py +130 -0
- autocoder/common/auto_coder_lang.py +9 -1
- autocoder/common/command_completer_v2.py +39 -0
- autocoder/common/rulefiles/autocoderrules_utils.py +83 -0
- autocoder/common/v2/agent/agentic_edit.py +1 -1
- autocoder/rag/loaders/image_loader.py +25 -13
- autocoder/rag/long_context_rag.py +2 -2
- autocoder/utils/model_provider_selector.py +14 -2
- autocoder/version.py +1 -1
- {auto_coder-0.1.355.dist-info → auto_coder-0.1.356.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.355.dist-info → auto_coder-0.1.356.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.355.dist-info → auto_coder-0.1.356.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.355.dist-info → auto_coder-0.1.356.dist-info}/top_level.txt +0 -0
|
@@ -41,6 +41,7 @@ COMMAND_HIERARCHY = {
|
|
|
41
41
|
"/clear": {},
|
|
42
42
|
"/cls": {},
|
|
43
43
|
"/debug": {},
|
|
44
|
+
"/rules": {"/list", "/get", "/remove", "/analyze", "/commit", "/help"},
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
class CommandCompleterV2(Completer):
|
|
@@ -86,6 +87,7 @@ class CommandCompleterV2(Completer):
|
|
|
86
87
|
"/ask": self._handle_text_with_symbols, # Treat like chat for @/@@
|
|
87
88
|
"/summon": self._handle_text_with_symbols,
|
|
88
89
|
"/design": self._handle_design,
|
|
90
|
+
"/rules": self._handle_rules,
|
|
89
91
|
# Add handlers for other commands if they need specific logic beyond @/@@
|
|
90
92
|
# Default handler for plain text or commands not explicitly handled
|
|
91
93
|
"default": self._handle_text_with_symbols,
|
|
@@ -438,6 +440,43 @@ class CommandCompleterV2(Completer):
|
|
|
438
440
|
elif word.startswith("<"): # Potential tag completion
|
|
439
441
|
yield from self._handle_img_tag(document, complete_event, word, text)
|
|
440
442
|
|
|
443
|
+
def _handle_rules(self, document: Document, complete_event: CompleteEvent, word: str, text: str) -> Iterable[Completion]:
|
|
444
|
+
"""处理 /rules 命令的补全,支持子命令和规则文件路径。同时支持 @ 和 @@ 符号。"""
|
|
445
|
+
args_text = text[len("/rules"):].lstrip()
|
|
446
|
+
parts = args_text.split()
|
|
447
|
+
last_part = parts[-1] if parts and not text.endswith(" ") else ""
|
|
448
|
+
|
|
449
|
+
# 补全子命令
|
|
450
|
+
if not args_text or (len(parts) == 1 and not text.endswith(" ") and parts[0].startswith("/")):
|
|
451
|
+
for sub_cmd in COMMAND_HIERARCHY["/rules"]:
|
|
452
|
+
if sub_cmd.startswith(last_part):
|
|
453
|
+
yield Completion(sub_cmd, start_position=-len(last_part))
|
|
454
|
+
return
|
|
455
|
+
|
|
456
|
+
# 根据子命令补全参数
|
|
457
|
+
if parts and parts[0] == "/list" or parts[0] == "/get" or parts[0] == "/remove":
|
|
458
|
+
# 获取规则文件或目录补全,可以是通配符
|
|
459
|
+
# 这里可以简单地提供文件路径补全
|
|
460
|
+
yield from self._complete_file_paths(last_part, text)
|
|
461
|
+
# 也可以添加常用通配符补全
|
|
462
|
+
common_patterns = ["*.md", "*.rules", "*.txt"]
|
|
463
|
+
for pattern in common_patterns:
|
|
464
|
+
if pattern.startswith(last_part):
|
|
465
|
+
yield Completion(pattern, start_position=-len(last_part))
|
|
466
|
+
return
|
|
467
|
+
|
|
468
|
+
# 对于 /commit 子命令,补全 /query
|
|
469
|
+
if parts and parts[0] == "/commit":
|
|
470
|
+
if "/query".startswith(last_part):
|
|
471
|
+
yield Completion("/query", start_position=-len(last_part))
|
|
472
|
+
return
|
|
473
|
+
|
|
474
|
+
# 支持 @ 和 @@ 符号的补全,不管当前命令是什么
|
|
475
|
+
if word.startswith("@") and not word.startswith("@@"):
|
|
476
|
+
yield from self._handle_at_completion(document, complete_event, word, text)
|
|
477
|
+
elif word.startswith("@@"):
|
|
478
|
+
yield from self._handle_double_at_completion(document, complete_event, word, text)
|
|
479
|
+
|
|
441
480
|
|
|
442
481
|
# --- Symbol/Tag Handlers ---
|
|
443
482
|
def _handle_at_completion(self, document: Document, complete_event: CompleteEvent, word: str, text: str) -> Iterable[Completion]:
|
|
@@ -4,6 +4,9 @@ from threading import Lock
|
|
|
4
4
|
import threading
|
|
5
5
|
from typing import Dict, List, Optional
|
|
6
6
|
from loguru import logger
|
|
7
|
+
import re
|
|
8
|
+
import yaml
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
7
10
|
|
|
8
11
|
# 尝试导入 FileMonitor
|
|
9
12
|
try:
|
|
@@ -15,6 +18,15 @@ except ImportError:
|
|
|
15
18
|
Change = None
|
|
16
19
|
|
|
17
20
|
|
|
21
|
+
class RuleFile(BaseModel):
|
|
22
|
+
"""规则文件的Pydantic模型"""
|
|
23
|
+
description: str = Field(default="", description="规则的描述")
|
|
24
|
+
globs: List[str] = Field(default_factory=list, description="文件匹配模式列表")
|
|
25
|
+
always_apply: bool = Field(default=False, alias="alwaysApply", description="是否总是应用规则")
|
|
26
|
+
content: str = Field(default="", description="规则文件的正文内容")
|
|
27
|
+
file_path: str = Field(default="", description="规则文件的路径")
|
|
28
|
+
|
|
29
|
+
|
|
18
30
|
class AutocoderRulesManager:
|
|
19
31
|
"""
|
|
20
32
|
管理和监控 autocoderrules 目录中的规则文件。
|
|
@@ -157,9 +169,66 @@ class AutocoderRulesManager:
|
|
|
157
169
|
self._load_rules()
|
|
158
170
|
logger.info("已重新加载规则")
|
|
159
171
|
|
|
172
|
+
def parse_rule_file(self, file_path: str) -> RuleFile:
|
|
173
|
+
"""
|
|
174
|
+
解析规则文件并返回结构化的Pydantic模型对象
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
file_path: 规则文件的路径
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
RuleFile: 包含规则文件结构化内容的Pydantic模型
|
|
181
|
+
"""
|
|
182
|
+
if not os.path.exists(file_path) or not file_path.endswith('.md'):
|
|
183
|
+
logger.warning(f"无效的规则文件路径: {file_path}")
|
|
184
|
+
return RuleFile(file_path=file_path)
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
188
|
+
content = f.read()
|
|
189
|
+
|
|
190
|
+
# 解析YAML头部和Markdown内容
|
|
191
|
+
yaml_pattern = re.compile(r'^---\s*\n(.*?)\n---\s*\n', re.DOTALL)
|
|
192
|
+
yaml_match = yaml_pattern.search(content)
|
|
193
|
+
|
|
194
|
+
metadata = {}
|
|
195
|
+
markdown_content = content
|
|
196
|
+
|
|
197
|
+
if yaml_match:
|
|
198
|
+
yaml_content = yaml_match.group(1)
|
|
199
|
+
try:
|
|
200
|
+
metadata = yaml.safe_load(yaml_content)
|
|
201
|
+
# 移除YAML部分,仅保留Markdown内容
|
|
202
|
+
markdown_content = content[yaml_match.end():]
|
|
203
|
+
except Exception as e:
|
|
204
|
+
logger.warning(f"解析规则文件YAML头部时出错: {e}")
|
|
205
|
+
|
|
206
|
+
# 创建并返回Pydantic模型
|
|
207
|
+
rule = RuleFile(
|
|
208
|
+
description=metadata.get('description', ''),
|
|
209
|
+
globs=metadata.get('globs', []),
|
|
210
|
+
always_apply=metadata.get('alwaysApply', False),
|
|
211
|
+
content=markdown_content.strip(),
|
|
212
|
+
file_path=file_path
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
return rule
|
|
216
|
+
|
|
217
|
+
except Exception as e:
|
|
218
|
+
logger.warning(f"解析规则文件时出错: {file_path}, 错误: {e}")
|
|
219
|
+
return RuleFile(file_path=file_path)
|
|
220
|
+
|
|
160
221
|
def get_rules(self) -> Dict[str, str]:
|
|
161
222
|
"""获取所有规则文件内容"""
|
|
162
223
|
return self._rules.copy()
|
|
224
|
+
|
|
225
|
+
def get_parsed_rules(self) -> List[RuleFile]:
|
|
226
|
+
"""获取所有解析后的规则文件"""
|
|
227
|
+
parsed_rules = []
|
|
228
|
+
for file_path in self._rules:
|
|
229
|
+
parsed_rule = self.parse_rule_file(file_path)
|
|
230
|
+
parsed_rules.append(parsed_rule)
|
|
231
|
+
return parsed_rules
|
|
163
232
|
|
|
164
233
|
|
|
165
234
|
# 对外提供单例
|
|
@@ -171,3 +240,17 @@ def get_rules(project_root: Optional[str] = None) -> Dict[str, str]:
|
|
|
171
240
|
if _rules_manager is None:
|
|
172
241
|
_rules_manager = AutocoderRulesManager(project_root=project_root)
|
|
173
242
|
return _rules_manager.get_rules()
|
|
243
|
+
|
|
244
|
+
def get_parsed_rules(project_root: Optional[str] = None) -> List[RuleFile]:
|
|
245
|
+
"""获取所有解析后的规则文件,可指定项目根目录"""
|
|
246
|
+
global _rules_manager
|
|
247
|
+
if _rules_manager is None:
|
|
248
|
+
_rules_manager = AutocoderRulesManager(project_root=project_root)
|
|
249
|
+
return _rules_manager.get_parsed_rules()
|
|
250
|
+
|
|
251
|
+
def parse_rule_file(file_path: str, project_root: Optional[str] = None) -> RuleFile:
|
|
252
|
+
"""解析指定的规则文件,可指定项目根目录"""
|
|
253
|
+
global _rules_manager
|
|
254
|
+
if _rules_manager is None:
|
|
255
|
+
_rules_manager = AutocoderRulesManager(project_root=project_root)
|
|
256
|
+
return _rules_manager.parse_rule_file(file_path)
|
|
@@ -814,7 +814,7 @@ Below are some files the user is focused on, and the content is up to date. Thes
|
|
|
814
814
|
event_count = 0
|
|
815
815
|
for event in parsed_events:
|
|
816
816
|
event_count += 1
|
|
817
|
-
logger.info(f"Processing event #{event_count}: {type(event).__name__}")
|
|
817
|
+
logger.info(f"Processing event #{event_count}: {type(event).__name__}")
|
|
818
818
|
global_cancel.check_and_raise(token=self.args.event_file)
|
|
819
819
|
if isinstance(event, (LLMOutputEvent, LLMThinkingEvent)):
|
|
820
820
|
assistant_buffer += event.text
|
|
@@ -33,6 +33,9 @@ class ImageLoader:
|
|
|
33
33
|
and converting the content to markdown format.
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
|
+
# 存储不同参数组合的PaddleOCR实例
|
|
37
|
+
_ocr_instances = {}
|
|
38
|
+
|
|
36
39
|
@staticmethod
|
|
37
40
|
def parse_diff(diff_content: str) -> List[Tuple[str, str]]:
|
|
38
41
|
"""
|
|
@@ -106,19 +109,28 @@ class ImageLoader:
|
|
|
106
109
|
print("paddleocr not installed")
|
|
107
110
|
return ""
|
|
108
111
|
|
|
109
|
-
#
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
112
|
+
# 创建一个参数的哈希键,用于在缓存中存储OCR实例
|
|
113
|
+
param_key = f"{lang}_{use_angle_cls}_{page_num}_{det_model_dir}_{rec_model_dir}_{hash(frozenset(kwargs.items()) if kwargs else 0)}"
|
|
114
|
+
|
|
115
|
+
# 检查是否已经有对应参数的OCR实例
|
|
116
|
+
if param_key not in ImageLoader._ocr_instances:
|
|
117
|
+
try:
|
|
118
|
+
# 初始化OCR并缓存
|
|
119
|
+
ImageLoader._ocr_instances[param_key] = PaddleOCR(
|
|
120
|
+
use_angle_cls=use_angle_cls,
|
|
121
|
+
lang=lang,
|
|
122
|
+
page_num=page_num,
|
|
123
|
+
det_model_dir=det_model_dir,
|
|
124
|
+
rec_model_dir=rec_model_dir,
|
|
125
|
+
**kwargs
|
|
126
|
+
)
|
|
127
|
+
logger.info(f"初始化新的PaddleOCR实例,参数:{param_key}")
|
|
128
|
+
except Exception:
|
|
129
|
+
traceback.print_exc()
|
|
130
|
+
return ""
|
|
131
|
+
|
|
132
|
+
# 使用缓存的OCR实例
|
|
133
|
+
ocr = ImageLoader._ocr_instances[param_key]
|
|
122
134
|
|
|
123
135
|
try:
|
|
124
136
|
ext = os.path.splitext(file_path)[1].lower()
|
|
@@ -27,7 +27,7 @@ from autocoder.rag.relevant_utils import (
|
|
|
27
27
|
DocFilterResult
|
|
28
28
|
)
|
|
29
29
|
from autocoder.rag.token_checker import check_token_limit
|
|
30
|
-
from autocoder.rag.token_counter import RemoteTokenCounter, TokenCounter
|
|
30
|
+
from autocoder.rag.token_counter import RemoteTokenCounter, TokenCounter,count_tokens
|
|
31
31
|
from autocoder.rag.token_limiter import TokenLimiter
|
|
32
32
|
from tokenizers import Tokenizer
|
|
33
33
|
from autocoder.rag.variable_holder import VariableHolder
|
|
@@ -782,7 +782,7 @@ class LongContextRAG:
|
|
|
782
782
|
)
|
|
783
783
|
|
|
784
784
|
# 记录令牌统计
|
|
785
|
-
request_tokens = sum([doc.
|
|
785
|
+
request_tokens = sum([count_tokens(doc.source_code) for doc in relevant_docs])
|
|
786
786
|
target_model = target_llm.default_model_name
|
|
787
787
|
logger.info(
|
|
788
788
|
f"=== LLM Request ===\n"
|
|
@@ -26,7 +26,7 @@ PROVIDER_INFO_LIST = [
|
|
|
26
26
|
name="volcano",
|
|
27
27
|
endpoint="https://ark.cn-beijing.volces.com/api/v3",
|
|
28
28
|
r1_model="deepseek-r1-250120",
|
|
29
|
-
v3_model="deepseek-v3-
|
|
29
|
+
v3_model="deepseek-v3-250324",
|
|
30
30
|
api_key="",
|
|
31
31
|
r1_input_price=2.0,
|
|
32
32
|
r1_output_price=8.0,
|
|
@@ -55,6 +55,17 @@ PROVIDER_INFO_LIST = [
|
|
|
55
55
|
v3_input_price=2.0,
|
|
56
56
|
v3_output_price=8.0,
|
|
57
57
|
),
|
|
58
|
+
ProviderInfo(
|
|
59
|
+
name="openrouter",
|
|
60
|
+
endpoint="https://openrouter.ai/api/v1",
|
|
61
|
+
r1_model="deepseek/deepseek-r1",
|
|
62
|
+
v3_model="deepseek/deepseek-chat-v3-0324",
|
|
63
|
+
api_key="",
|
|
64
|
+
r1_input_price=0.0,
|
|
65
|
+
r1_output_price=0.0,
|
|
66
|
+
v3_input_price=0.0,
|
|
67
|
+
v3_output_price=0.0,
|
|
68
|
+
)
|
|
58
69
|
]
|
|
59
70
|
|
|
60
71
|
dialog_style = Style.from_dict({
|
|
@@ -147,7 +158,8 @@ class ModelProviderSelector:
|
|
|
147
158
|
values=[
|
|
148
159
|
("volcano", self.printer.get_message_from_key("model_provider_volcano")),
|
|
149
160
|
("siliconflow", self.printer.get_message_from_key("model_provider_siliconflow")),
|
|
150
|
-
("deepseek", self.printer.get_message_from_key("model_provider_deepseek"))
|
|
161
|
+
("deepseek", self.printer.get_message_from_key("model_provider_deepseek")),
|
|
162
|
+
("openrouter", self.printer.get_message_from_key("model_provider_openrouter"))
|
|
151
163
|
],
|
|
152
164
|
style=dialog_style
|
|
153
165
|
).run()
|
autocoder/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.356"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|