auto-coder 0.1.361__py3-none-any.whl → 0.1.363__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.

Files changed (57) hide show
  1. {auto_coder-0.1.361.dist-info → auto_coder-0.1.363.dist-info}/METADATA +2 -1
  2. {auto_coder-0.1.361.dist-info → auto_coder-0.1.363.dist-info}/RECORD +57 -29
  3. autocoder/agent/auto_learn.py +249 -262
  4. autocoder/agent/base_agentic/__init__.py +0 -0
  5. autocoder/agent/base_agentic/agent_hub.py +169 -0
  6. autocoder/agent/base_agentic/agentic_lang.py +112 -0
  7. autocoder/agent/base_agentic/agentic_tool_display.py +180 -0
  8. autocoder/agent/base_agentic/base_agent.py +1582 -0
  9. autocoder/agent/base_agentic/default_tools.py +683 -0
  10. autocoder/agent/base_agentic/test_base_agent.py +82 -0
  11. autocoder/agent/base_agentic/tool_registry.py +425 -0
  12. autocoder/agent/base_agentic/tools/__init__.py +12 -0
  13. autocoder/agent/base_agentic/tools/ask_followup_question_tool_resolver.py +72 -0
  14. autocoder/agent/base_agentic/tools/attempt_completion_tool_resolver.py +37 -0
  15. autocoder/agent/base_agentic/tools/base_tool_resolver.py +35 -0
  16. autocoder/agent/base_agentic/tools/example_tool_resolver.py +46 -0
  17. autocoder/agent/base_agentic/tools/execute_command_tool_resolver.py +72 -0
  18. autocoder/agent/base_agentic/tools/list_files_tool_resolver.py +110 -0
  19. autocoder/agent/base_agentic/tools/plan_mode_respond_tool_resolver.py +35 -0
  20. autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +54 -0
  21. autocoder/agent/base_agentic/tools/replace_in_file_tool_resolver.py +156 -0
  22. autocoder/agent/base_agentic/tools/search_files_tool_resolver.py +134 -0
  23. autocoder/agent/base_agentic/tools/talk_to_group_tool_resolver.py +96 -0
  24. autocoder/agent/base_agentic/tools/talk_to_tool_resolver.py +79 -0
  25. autocoder/agent/base_agentic/tools/use_mcp_tool_resolver.py +44 -0
  26. autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +58 -0
  27. autocoder/agent/base_agentic/types.py +189 -0
  28. autocoder/agent/base_agentic/utils.py +100 -0
  29. autocoder/auto_coder.py +1 -1
  30. autocoder/auto_coder_runner.py +36 -14
  31. autocoder/chat/conf_command.py +11 -10
  32. autocoder/commands/auto_command.py +227 -159
  33. autocoder/common/__init__.py +2 -2
  34. autocoder/common/ignorefiles/ignore_file_utils.py +12 -8
  35. autocoder/common/result_manager.py +10 -2
  36. autocoder/common/rulefiles/autocoderrules_utils.py +169 -0
  37. autocoder/common/save_formatted_log.py +1 -1
  38. autocoder/common/v2/agent/agentic_edit.py +53 -41
  39. autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +15 -12
  40. autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +73 -1
  41. autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +132 -4
  42. autocoder/common/v2/agent/agentic_edit_types.py +1 -2
  43. autocoder/common/v2/agent/agentic_tool_display.py +2 -3
  44. autocoder/common/v2/code_auto_generate_editblock.py +3 -1
  45. autocoder/index/index.py +14 -8
  46. autocoder/privacy/model_filter.py +297 -35
  47. autocoder/rag/long_context_rag.py +424 -397
  48. autocoder/rag/test_doc_filter.py +393 -0
  49. autocoder/rag/test_long_context_rag.py +473 -0
  50. autocoder/rag/test_token_limiter.py +342 -0
  51. autocoder/shadows/shadow_manager.py +1 -3
  52. autocoder/utils/_markitdown.py +22 -3
  53. autocoder/version.py +1 -1
  54. {auto_coder-0.1.361.dist-info → auto_coder-0.1.363.dist-info}/LICENSE +0 -0
  55. {auto_coder-0.1.361.dist-info → auto_coder-0.1.363.dist-info}/WHEEL +0 -0
  56. {auto_coder-0.1.361.dist-info → auto_coder-0.1.363.dist-info}/entry_points.txt +0 -0
  57. {auto_coder-0.1.361.dist-info → auto_coder-0.1.363.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,82 @@
1
+ """
2
+ BaseAgent类和byzerllm.prompt装饰器的单元测试
3
+ """
4
+ import pytest
5
+ import os
6
+ import tempfile
7
+ import shutil
8
+ from unittest.mock import patch, MagicMock
9
+ import byzerllm
10
+
11
+ # 导入被测类
12
+ from autocoder.agent.base_agentic import BaseAgent
13
+ from autocoder.agent.base_agentic.types import BaseTool, AgentRequest, ToolResult
14
+ from autocoder.common import AutoCoderArgs, SourceCodeList, SourceCode
15
+
16
+ # 测试环境辅助函数
17
+ def create_test_environment(base_dir, structure):
18
+ """创建测试所需的文件/目录结构"""
19
+ for path, content in structure.items():
20
+ full_path = os.path.join(base_dir, path)
21
+ os.makedirs(os.path.dirname(full_path), exist_ok=True)
22
+ with open(full_path, 'w', encoding='utf-8') as f:
23
+ f.write(content)
24
+
25
+ # Pytest Fixture: 临时目录
26
+ @pytest.fixture(scope="function")
27
+ def temp_test_dir():
28
+ """提供一个临时的、测试后自动清理的目录"""
29
+ temp_dir = tempfile.mkdtemp()
30
+ print(f"Created temp dir for test: {temp_dir}")
31
+ yield temp_dir
32
+ print(f"Cleaning up temp dir: {temp_dir}")
33
+ shutil.rmtree(temp_dir)
34
+
35
+ # Pytest Fixture: 重置FileMonitor
36
+ @pytest.fixture
37
+ def setup_file_monitor(temp_test_dir):
38
+ """初始化FileMonitor,必须最先执行"""
39
+ try:
40
+ from autocoder.common.file_monitor.monitor import FileMonitor
41
+ # 重置FileMonitor实例,确保测试隔离性
42
+ monitor = FileMonitor(temp_test_dir)
43
+ monitor.reset_instance()
44
+ if not monitor.is_running():
45
+ monitor.start()
46
+ print(f"文件监控已启动: {temp_test_dir}")
47
+ else:
48
+ print(f"文件监控已在运行中: {monitor.root_dir}")
49
+ except Exception as e:
50
+ print(f"初始化文件监控出错: {e}")
51
+
52
+ # 加载规则文件
53
+ try:
54
+ from autocoder.common.rulefiles.autocoderrules_utils import get_rules, reset_rules_manager
55
+ reset_rules_manager() # 重置规则管理器,确保测试隔离性
56
+ rules = get_rules(temp_test_dir)
57
+ print(f"已加载规则: {len(rules)} 条")
58
+ except Exception as e:
59
+ print(f"加载规则出错: {e}")
60
+
61
+ return temp_test_dir
62
+
63
+ # Pytest Fixture: 加载tokenizer
64
+ @pytest.fixture
65
+ def load_tokenizer_fixture(setup_file_monitor):
66
+ """加载tokenizer,必须在FileMonitor和rules初始化之后"""
67
+ from autocoder.auto_coder_runner import load_tokenizer
68
+ load_tokenizer()
69
+ print("Tokenizer加载完成")
70
+ return True
71
+
72
+ # Pytest Fixture: mock的LLM
73
+ @pytest.fixture
74
+ def mock_llm():
75
+ """创建模拟的LLM对象"""
76
+ mock = MagicMock()
77
+ # 模拟chat_oai方法返回结果
78
+ mock.chat_oai.return_value = [{"role": "assistant", "content": "这是模拟的LLM回答"}]
79
+ # 设置必要的属性
80
+ mock.default_model_name = "mock_model"
81
+ return mock
82
+
@@ -0,0 +1,425 @@
1
+ from typing import Dict, Type, ClassVar, Optional, List
2
+ import logging
3
+ import inspect
4
+ from .types import BaseTool, ToolDescription, ToolExample
5
+ from .tools.base_tool_resolver import BaseToolResolver
6
+
7
+ from loguru import logger
8
+
9
+
10
+ class ToolRegistry:
11
+ """
12
+ 工具注册表,用于管理工具和对应的解析器
13
+ """
14
+ # 类变量,存储工具和解析器的映射关系
15
+ _tool_resolver_map: ClassVar[Dict[Type[BaseTool], Type[BaseToolResolver]]] = {}
16
+ _tag_model_map: ClassVar[Dict[str, Type[BaseTool]]] = {}
17
+
18
+ # 存储工具描述和示例
19
+ _tool_descriptions: ClassVar[Dict[str, ToolDescription]] = {}
20
+ _tool_examples: ClassVar[Dict[str, ToolExample]] = {}
21
+
22
+ # 存储工具使用指南
23
+ _tool_use_guidelines: ClassVar[Dict[str, str]] = {}
24
+
25
+ # 存储工具用例文档
26
+ _tools_case_doc: ClassVar[Dict[str, Dict[str, object]]] = {}
27
+
28
+ # 存储角色描述和通用描述
29
+ _role_descriptions: ClassVar[Dict[str, str]] = {}
30
+
31
+ # 存储默认工具集
32
+ _default_tools: ClassVar[Dict[str, Type[BaseTool]]] = {}
33
+
34
+ @classmethod
35
+ def register_tool(cls, tool_tag: str, tool_cls: Type[BaseTool], resolver_cls: Type[BaseToolResolver],
36
+ description: ToolDescription, example: ToolExample, use_guideline: str = "") -> None:
37
+ """
38
+ 注册工具和对应的解析器
39
+
40
+ Args:
41
+ tool_tag: XML标签名称
42
+ tool_cls: 工具类
43
+ resolver_cls: 解析器类
44
+ description: 工具描述,包含title和body,将用于生成提示
45
+ example: 工具使用示例,包含title和body,将用于生成提示
46
+ use_guideline: 工具使用指南,提供给LLM关于如何正确使用该工具的具体指导
47
+ """
48
+ if tool_cls in cls._tool_resolver_map:
49
+ logger.warning(f"工具 {tool_cls.__name__} 已经注册过,将被覆盖")
50
+
51
+ cls._tool_resolver_map[tool_cls] = resolver_cls
52
+ cls._tag_model_map[tool_tag] = tool_cls
53
+
54
+ # 注册描述和示例
55
+ cls._tool_descriptions[tool_tag] = description
56
+ cls._tool_examples[tool_tag] = example
57
+
58
+ # 注册使用指南
59
+ if use_guideline:
60
+ cls._tool_use_guidelines[tool_tag] = use_guideline
61
+
62
+ logger.info(f"成功注册工具: {tool_tag} -> {tool_cls.__name__} 使用解析器 {resolver_cls.__name__}")
63
+
64
+ @classmethod
65
+ def register_default_tool(cls, tool_tag: str, tool_cls: Type[BaseTool], resolver_cls: Type[BaseToolResolver],
66
+ description: ToolDescription, example: ToolExample, use_guideline: str = "") -> None:
67
+ """
68
+ 注册默认工具和对应的解析器,同时记录在默认工具集中
69
+
70
+ Args:
71
+ tool_tag: XML标签名称
72
+ tool_cls: 工具类
73
+ resolver_cls: 解析器类
74
+ description: 工具描述,包含title和body,将用于生成提示
75
+ example: 工具使用示例,包含title和body,将用于生成提示
76
+ use_guideline: 工具使用指南,提供给LLM关于如何正确使用该工具的具体指导
77
+ """
78
+ # 注册工具
79
+ cls.register_tool(tool_tag, tool_cls, resolver_cls, description, example, use_guideline)
80
+
81
+ # 添加到默认工具集
82
+ cls._default_tools[tool_tag] = tool_cls
83
+ logger.info(f"已将工具 {tool_tag} 添加到默认工具集")
84
+
85
+ @classmethod
86
+ def register_tools_case_doc(cls, case_name: str, tools: List[str], doc: str) -> None:
87
+ """
88
+ 注册工具用例文档
89
+
90
+ Args:
91
+ case_name: 用例名称
92
+ tools: 工具名称列表
93
+ doc: 用例文档说明
94
+ """
95
+ cls._tools_case_doc[case_name] = {
96
+ "tools": tools,
97
+ "doc": doc
98
+ }
99
+ logger.info(f"成功注册工具用例文档: {case_name}, 包含工具: {', '.join(tools)}")
100
+
101
+ @classmethod
102
+ def register_unified_tool(cls, tool_tag: str, tool_info: Dict) -> None:
103
+ """
104
+ 统一注册工具的所有相关信息
105
+
106
+ Args:
107
+ tool_tag: 工具标签
108
+ tool_info: 工具信息字典,包含以下字段:
109
+ - tool_cls: 工具类
110
+ - resolver_cls: 解析器类
111
+ - description: 工具描述对象
112
+ - example: 工具示例对象
113
+ - use_guideline: 工具使用指南(可选)
114
+ - category: 工具分类(可选)
115
+ - is_default: 是否为默认工具(可选,默认为False)
116
+ - case_docs: 关联的用例文档列表(可选)
117
+ """
118
+ # 提取工具信息
119
+ tool_cls = tool_info.get("tool_cls")
120
+ resolver_cls = tool_info.get("resolver_cls")
121
+ description = tool_info.get("description")
122
+ example = tool_info.get("example")
123
+ use_guideline = tool_info.get("use_guideline", "")
124
+ is_default = tool_info.get("is_default", False)
125
+ case_docs = tool_info.get("case_docs", [])
126
+
127
+ # 验证必要字段
128
+ if not all([tool_cls, resolver_cls, description]):
129
+ logger.error(f"注册工具 {tool_tag} 失败:缺少必要信息")
130
+ return
131
+
132
+ # 注册工具
133
+ if is_default:
134
+ cls.register_default_tool(
135
+ tool_tag=tool_tag,
136
+ tool_cls=tool_cls,
137
+ resolver_cls=resolver_cls,
138
+ description=description,
139
+ example=example,
140
+ use_guideline=use_guideline
141
+ )
142
+ else:
143
+ cls.register_tool(
144
+ tool_tag=tool_tag,
145
+ tool_cls=tool_cls,
146
+ resolver_cls=resolver_cls,
147
+ description=description,
148
+ example=example,
149
+ use_guideline=use_guideline
150
+ )
151
+
152
+ # 关联用例文档
153
+ for case_doc in case_docs:
154
+ if case_doc in cls._tools_case_doc:
155
+ if tool_tag not in cls._tools_case_doc[case_doc]["tools"]:
156
+ cls._tools_case_doc[case_doc]["tools"].append(tool_tag)
157
+ logger.info(f"将工具 {tool_tag} 添加到用例文档 {case_doc}")
158
+
159
+ logger.info(f"成功统一注册工具: {tool_tag}")
160
+
161
+
162
+ @classmethod
163
+ def unregister_tool(cls, tool_tag: str) -> bool:
164
+ """
165
+ 卸载一个已注册的工具
166
+
167
+ Args:
168
+ tool_tag: 工具标签
169
+
170
+ Returns:
171
+ 是否成功卸载
172
+ """
173
+ tool_cls = cls._tag_model_map.get(tool_tag)
174
+ if tool_cls is None:
175
+ logger.warning(f"找不到要卸载的工具: {tool_tag}")
176
+ return False
177
+
178
+ # 清除工具关联数据
179
+ if tool_cls in cls._tool_resolver_map:
180
+ del cls._tool_resolver_map[tool_cls]
181
+ if tool_tag in cls._tag_model_map:
182
+ del cls._tag_model_map[tool_tag]
183
+ if tool_tag in cls._tool_descriptions:
184
+ del cls._tool_descriptions[tool_tag]
185
+ if tool_tag in cls._tool_examples:
186
+ del cls._tool_examples[tool_tag]
187
+ if tool_tag in cls._tool_use_guidelines:
188
+ del cls._tool_use_guidelines[tool_tag]
189
+ if tool_tag in cls._default_tools:
190
+ del cls._default_tools[tool_tag]
191
+
192
+ # 清除工具在用例文档中的引用
193
+ for case_name, case_data in list(cls._tools_case_doc.items()):
194
+ if tool_tag in case_data["tools"]:
195
+ # 如果该工具是用例中唯一的工具,删除整个用例
196
+ if len(case_data["tools"]) == 1:
197
+ del cls._tools_case_doc[case_name]
198
+ logger.info(f"已删除依赖于工具 {tool_tag} 的用例文档: {case_name}")
199
+ else:
200
+ # 否则只从工具列表中移除该工具
201
+ case_data["tools"].remove(tool_tag)
202
+ logger.info(f"已从用例 {case_name} 中移除工具 {tool_tag}")
203
+
204
+ logger.info(f"成功卸载工具: {tool_tag}")
205
+ return True
206
+
207
+ @classmethod
208
+ def reset_to_default_tools(cls) -> None:
209
+ """
210
+ 重置为仅包含默认工具的状态,移除所有非默认工具
211
+ """
212
+ # 获取需要保留的工具标签
213
+ default_tags = set(cls._default_tools.keys())
214
+ # 获取所有当前工具标签
215
+ all_tags = set(cls._tag_model_map.keys())
216
+ # 计算要删除的标签
217
+ tags_to_remove = all_tags - default_tags
218
+
219
+ # 移除非默认工具
220
+ for tag in tags_to_remove:
221
+ cls.unregister_tool(tag)
222
+
223
+ logger.info(f"工具注册表已重置为默认工具集,保留了 {len(default_tags)} 个默认工具")
224
+
225
+ @classmethod
226
+ def is_default_tool(cls, tool_tag: str) -> bool:
227
+ """
228
+ 检查工具是否为默认工具
229
+
230
+ Args:
231
+ tool_tag: 工具标签
232
+
233
+ Returns:
234
+ 是否为默认工具
235
+ """
236
+ return tool_tag in cls._default_tools
237
+
238
+ @classmethod
239
+ def get_default_tools(cls) -> List[str]:
240
+ """
241
+ 获取所有默认工具标签
242
+
243
+ Returns:
244
+ 默认工具标签列表
245
+ """
246
+ return list(cls._default_tools.keys())
247
+
248
+ @classmethod
249
+ def register_role_description(cls, agent_type: str, description: str) -> None:
250
+ """
251
+ 注册代理角色描述
252
+
253
+ Args:
254
+ agent_type: 代理类型标识
255
+ description: 角色描述文本
256
+ """
257
+ cls._role_descriptions[agent_type] = description
258
+ logger.info(f"成功注册角色描述: {agent_type}")
259
+
260
+ @classmethod
261
+ def get_role_description(cls, agent_type: str) -> Optional[str]:
262
+ """
263
+ 获取代理角色描述
264
+
265
+ Args:
266
+ agent_type: 代理类型标识
267
+
268
+ Returns:
269
+ 角色描述文本,如果未找到则返回None
270
+ """
271
+ return cls._role_descriptions.get(agent_type)
272
+
273
+ @classmethod
274
+ def get_tool_description(cls, tool_tag: str) -> Optional[ToolDescription]:
275
+ """
276
+ 获取工具描述
277
+
278
+ Args:
279
+ tool_tag: 工具标签
280
+
281
+ Returns:
282
+ 工具描述对象,如果未找到则返回None
283
+ """
284
+ return cls._tool_descriptions.get(tool_tag)
285
+
286
+ @classmethod
287
+ def get_tool_example(cls, tool_tag: str) -> Optional[ToolExample]:
288
+ """
289
+ 获取工具示例
290
+
291
+ Args:
292
+ tool_tag: 工具标签
293
+
294
+ Returns:
295
+ 工具示例对象,如果未找到则返回None
296
+ """
297
+ return cls._tool_examples.get(tool_tag)
298
+
299
+ @classmethod
300
+ def get_tool_use_guideline(cls, tool_tag: str) -> Optional[str]:
301
+ """
302
+ 获取工具使用指南
303
+
304
+ Args:
305
+ tool_tag: 工具标签
306
+
307
+ Returns:
308
+ 工具使用指南,如果未找到则返回None
309
+ """
310
+ return cls._tool_use_guidelines.get(tool_tag)
311
+
312
+ @classmethod
313
+ def get_tools_case_doc(cls, case_name: str) -> Optional[Dict[str, object]]:
314
+ """
315
+ 获取工具用例文档
316
+
317
+ Args:
318
+ case_name: 用例名称
319
+
320
+ Returns:
321
+ 工具用例文档,包含tools和doc字段,如果未找到则返回None
322
+ """
323
+ return cls._tools_case_doc.get(case_name)
324
+
325
+ @classmethod
326
+ def get_all_tool_descriptions(cls) -> Dict[str, ToolDescription]:
327
+ """
328
+ 获取所有工具描述
329
+
330
+ Returns:
331
+ 工具描述字典,key为工具标签,value为描述对象
332
+ """
333
+ return cls._tool_descriptions.copy()
334
+
335
+ @classmethod
336
+ def get_all_tool_examples(cls) -> Dict[str, ToolExample]:
337
+ """
338
+ 获取所有工具示例
339
+
340
+ Returns:
341
+ 工具示例字典,key为工具标签,value为示例对象
342
+ """
343
+ return cls._tool_examples.copy()
344
+
345
+ @classmethod
346
+ def get_all_tool_use_guidelines(cls) -> Dict[str, str]:
347
+ """
348
+ 获取所有工具使用指南
349
+
350
+ Returns:
351
+ 工具使用指南字典,key为工具标签,value为使用指南文本
352
+ """
353
+ return cls._tool_use_guidelines.copy()
354
+
355
+ @classmethod
356
+ def get_all_tools_case_docs(cls) -> Dict[str, Dict[str, object]]:
357
+ """
358
+ 获取所有工具用例文档
359
+
360
+ Returns:
361
+ 工具用例文档字典,key为用例名称,value为包含tools和doc字段的字典
362
+ """
363
+ return cls._tools_case_doc.copy()
364
+
365
+ @classmethod
366
+ def get_resolver_for_tool(cls, tool_cls_or_instance) -> Type[BaseToolResolver]:
367
+ """
368
+ 获取工具对应的解析器类
369
+
370
+ Args:
371
+ tool_cls_or_instance: 工具类或工具实例
372
+
373
+ Returns:
374
+ 解析器类
375
+ """
376
+ # 如果传入的是实例,获取其类
377
+ if not inspect.isclass(tool_cls_or_instance):
378
+ tool_cls = type(tool_cls_or_instance)
379
+ else:
380
+ tool_cls = tool_cls_or_instance
381
+
382
+ return cls._tool_resolver_map.get(tool_cls)
383
+
384
+ @classmethod
385
+ def get_model_for_tag(cls, tool_tag: str) -> Type[BaseTool]:
386
+ """
387
+ 根据标签获取对应的工具类
388
+
389
+ Args:
390
+ tool_tag: 工具标签
391
+
392
+ Returns:
393
+ 工具类
394
+ """
395
+ return cls._tag_model_map.get(tool_tag)
396
+
397
+ @classmethod
398
+ def get_tool_resolver_map(cls) -> Dict[Type[BaseTool], Type[BaseToolResolver]]:
399
+ """
400
+ 获取工具和解析器的映射关系
401
+
402
+ Returns:
403
+ 工具和解析器的映射字典
404
+ """
405
+ return cls._tool_resolver_map.copy()
406
+
407
+ @classmethod
408
+ def get_tag_model_map(cls) -> Dict[str, Type[BaseTool]]:
409
+ """
410
+ 获取标签和工具的映射关系
411
+
412
+ Returns:
413
+ 标签和工具的映射字典
414
+ """
415
+ return cls._tag_model_map.copy()
416
+
417
+ @classmethod
418
+ def get_all_registered_tools(cls) -> List[str]:
419
+ """
420
+ 获取所有已注册的工具标签
421
+
422
+ Returns:
423
+ 工具标签列表
424
+ """
425
+ return list(cls._tag_model_map.keys())
@@ -0,0 +1,12 @@
1
+ """
2
+ 基础工具包,包含基础工具解析器和注册工具
3
+ """
4
+ from .base_tool_resolver import BaseToolResolver
5
+ from .talk_to_tool_resolver import TalkToToolResolver
6
+ from .talk_to_group_tool_resolver import TalkToGroupToolResolver
7
+
8
+ __all__ = [
9
+ "BaseToolResolver",
10
+ "TalkToToolResolver",
11
+ "TalkToGroupToolResolver"
12
+ ]
@@ -0,0 +1,72 @@
1
+ from typing import Dict, Any, Optional
2
+ from autocoder.agent.base_agentic.tools.base_tool_resolver import BaseToolResolver
3
+ from autocoder.agent.base_agentic.types import AskFollowupQuestionTool, ToolResult # Import ToolResult from types
4
+ from loguru import logger
5
+ import typing
6
+ from autocoder.common import AutoCoderArgs
7
+ from autocoder.run_context import get_run_context
8
+ from autocoder.events.event_manager_singleton import get_event_manager
9
+ from autocoder.events import event_content as EventContentCreator
10
+ from prompt_toolkit import PromptSession
11
+ from prompt_toolkit.styles import Style
12
+ from rich.console import Console
13
+ from rich.panel import Panel
14
+ from rich.text import Text
15
+ from autocoder.common.result_manager import ResultManager
16
+
17
+ if typing.TYPE_CHECKING:
18
+ from ..base_agent import BaseAgent
19
+
20
+ class AskFollowupQuestionToolResolver(BaseToolResolver):
21
+ def __init__(self, agent: Optional['BaseAgent'], tool: AskFollowupQuestionTool, args: AutoCoderArgs):
22
+ super().__init__(agent, tool, args)
23
+ self.tool: AskFollowupQuestionTool = tool # For type hinting
24
+ self.result_manager = ResultManager()
25
+
26
+ def resolve(self) -> ToolResult:
27
+ """
28
+ Packages the question and options to be handled by the main loop/UI.
29
+ This resolver doesn't directly ask the user but prepares the data for it.
30
+ """
31
+ question = self.tool.question
32
+ options = self.tool.options or []
33
+ options_text = "\n".join([f"{i+1}. {option}" for i, option in enumerate(options)])
34
+ if get_run_context().is_web():
35
+ answer = get_event_manager(
36
+ self.args.event_file).ask_user(prompt=question)
37
+ self.result_manager.append(content=answer + ("\n" + options_text if options_text else ""), meta={
38
+ "action": "ask_user",
39
+ "input": {
40
+ "question": question
41
+ }
42
+ })
43
+ return ToolResult(success=True, message="Follow-up question prepared.", content=answer)
44
+
45
+ console = Console()
46
+
47
+ # 创建一个醒目的问题面板
48
+ question_text = Text(question, style="bold cyan")
49
+ question_panel = Panel(
50
+ question_text,
51
+ title="[bold yellow]auto-coder.chat's Question[/bold yellow]",
52
+ border_style="blue",
53
+ expand=False
54
+ )
55
+
56
+ # 显示问题面板
57
+ console.print(question_panel)
58
+
59
+ session = PromptSession(
60
+ message=self.printer.get_message_from_key('tool_ask_user'))
61
+ try:
62
+ answer = session.prompt()
63
+ except KeyboardInterrupt:
64
+ answer = ""
65
+
66
+ # The actual asking logic resides outside the resolver, typically in the agent's main loop
67
+ # or UI interaction layer. The resolver's job is to validate and package the request.
68
+ if not answer:
69
+ return ToolResult(success=False, message="Error: Question not answered.")
70
+
71
+ # Indicate success in preparing the question data
72
+ return ToolResult(success=True, message="Follow-up question prepared.", content=answer)
@@ -0,0 +1,37 @@
1
+ from typing import Dict, Any, Optional
2
+ from autocoder.agent.base_agentic.tools.base_tool_resolver import BaseToolResolver
3
+ from autocoder.agent.base_agentic.types import AttemptCompletionTool, ToolResult # Import ToolResult from types
4
+ from loguru import logger
5
+ import typing
6
+ from autocoder.common import AutoCoderArgs
7
+ import os
8
+ import tempfile
9
+
10
+ if typing.TYPE_CHECKING:
11
+ from ..base_agent import BaseAgent
12
+
13
+ class AttemptCompletionToolResolver(BaseToolResolver):
14
+ def __init__(self, agent: Optional['BaseAgent'], tool: AttemptCompletionTool, args: AutoCoderArgs):
15
+ super().__init__(agent, tool, args)
16
+ self.tool: AttemptCompletionTool = tool # For type hinting
17
+
18
+ def resolve(self) -> ToolResult:
19
+ """
20
+ Packages the completion result and optional command to signal task completion.
21
+ """
22
+ result_text = self.tool.result
23
+ command = self.tool.command
24
+
25
+ logger.info(f"Resolving AttemptCompletionTool: Result='{result_text[:100]}...', Command='{command}'")
26
+
27
+ if not result_text:
28
+ return ToolResult(success=False, message="Error: Completion result cannot be empty.")
29
+
30
+ # The actual presentation of the result happens outside the resolver.
31
+ result_content = {
32
+ "result": result_text,
33
+ "command": command
34
+ }
35
+
36
+ # Indicate success in preparing the completion data
37
+ return ToolResult(success=True, message="Task completion attempted.", content=result_content)
@@ -0,0 +1,35 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, Dict, Optional, TYPE_CHECKING
3
+ from autocoder.common import AutoCoderArgs
4
+
5
+ if TYPE_CHECKING:
6
+ from autocoder.agent.base_agentic.base_agent import BaseAgent
7
+ from autocoder.agent.base_agentic.types import BaseTool, ToolResult
8
+
9
+
10
+ class BaseToolResolver(ABC):
11
+ """
12
+ 工具解析器的基类,所有工具解析器都应该继承此类
13
+ """
14
+ def __init__(self, agent: Optional['BaseAgent'], tool: 'BaseTool', args: AutoCoderArgs):
15
+ """
16
+ 初始化解析器
17
+
18
+ Args:
19
+ agent: 代理实例,可能为None
20
+ tool: 工具实例
21
+ args: 其他需要的参数,如项目目录等
22
+ """
23
+ self.agent = agent
24
+ self.tool = tool
25
+ self.args = args
26
+
27
+ @abstractmethod
28
+ def resolve(self) -> 'ToolResult':
29
+ """
30
+ 执行工具逻辑,返回结果
31
+
32
+ Returns:
33
+ ToolResult对象,表示成功或失败以及消息
34
+ """
35
+ pass