jarvis-ai-assistant 0.1.128__py3-none-any.whl → 0.1.130__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 jarvis-ai-assistant might be problematic. Click here for more details.

Files changed (32) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +26 -31
  3. jarvis/jarvis_agent/main.py +77 -0
  4. jarvis/jarvis_c2rust/c2rust.yaml +734 -0
  5. jarvis/jarvis_code_agent/builtin_input_handler.py +43 -0
  6. jarvis/jarvis_code_agent/code_agent.py +82 -156
  7. jarvis/jarvis_code_agent/file_input_handler.py +88 -0
  8. jarvis/jarvis_code_agent/patch.py +262 -80
  9. jarvis/jarvis_code_agent/shell_input_handler.py +8 -2
  10. jarvis/jarvis_dev/main.py +832 -740
  11. jarvis/jarvis_multi_agent/__init__.py +113 -92
  12. jarvis/jarvis_platform/registry.py +0 -1
  13. jarvis/jarvis_tools/create_sub_agent.py +1 -8
  14. jarvis/jarvis_tools/git_commiter.py +2 -1
  15. jarvis/jarvis_tools/read_code.py +143 -0
  16. jarvis/jarvis_tools/registry.py +35 -39
  17. jarvis/jarvis_tools/tool_generator.py +45 -17
  18. jarvis/jarvis_utils/__init__.py +17 -17
  19. jarvis/jarvis_utils/config.py +87 -51
  20. jarvis/jarvis_utils/embedding.py +49 -48
  21. jarvis/jarvis_utils/git_utils.py +34 -34
  22. jarvis/jarvis_utils/globals.py +26 -26
  23. jarvis/jarvis_utils/input.py +61 -45
  24. jarvis/jarvis_utils/methodology.py +22 -22
  25. jarvis/jarvis_utils/output.py +64 -64
  26. jarvis/jarvis_utils/utils.py +2 -2
  27. {jarvis_ai_assistant-0.1.128.dist-info → jarvis_ai_assistant-0.1.130.dist-info}/METADATA +1 -1
  28. {jarvis_ai_assistant-0.1.128.dist-info → jarvis_ai_assistant-0.1.130.dist-info}/RECORD +32 -27
  29. {jarvis_ai_assistant-0.1.128.dist-info → jarvis_ai_assistant-0.1.130.dist-info}/entry_points.txt +2 -0
  30. {jarvis_ai_assistant-0.1.128.dist-info → jarvis_ai_assistant-0.1.130.dist-info}/LICENSE +0 -0
  31. {jarvis_ai_assistant-0.1.128.dist-info → jarvis_ai_assistant-0.1.130.dist-info}/WHEEL +0 -0
  32. {jarvis_ai_assistant-0.1.128.dist-info → jarvis_ai_assistant-0.1.130.dist-info}/top_level.txt +0 -0
@@ -5,92 +5,78 @@ import yaml
5
5
 
6
6
  from jarvis.jarvis_agent import Agent
7
7
  from jarvis.jarvis_agent.output_handler import OutputHandler
8
+ from jarvis.jarvis_tools.registry import ToolRegistry
9
+ from jarvis.jarvis_utils.input import get_multiline_input
8
10
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
11
+ from jarvis.jarvis_utils.utils import init_env
9
12
 
10
13
 
11
- class AgentConfig:
12
- def __init__(self, **config):
13
- self.system_prompt = config.get('system_prompt', '')
14
- self.name = config.get('name', 'Jarvis')
15
- self.description = config.get('description', '')
16
- self.is_sub_agent = config.get('is_sub_agent', False)
17
- self.output_handler = config.get('output_handler', [])
18
- self.platform = config.get('platform')
19
- self.model_name = config.get('model_name')
20
- self.summary_prompt = config.get('summary_prompt')
21
- self.auto_complete = config.get('auto_complete', False)
22
- self.input_handler = config.get('input_handler')
23
- self.max_context_length = config.get('max_context_length')
24
- self.execute_tool_confirm = config.get('execute_tool_confirm')
25
-
26
14
  class MultiAgent(OutputHandler):
27
- def __init__(self, configs: List[AgentConfig], main_agent_name: str):
28
- self.agents_config = configs
15
+ def __init__(self, agents_config: List[Dict], main_agent_name: str):
16
+ self.agents_config = agents_config
29
17
  self.agents = {}
30
18
  self.init_agents()
31
19
  self.main_agent_name = main_agent_name
32
20
 
33
21
  def prompt(self) -> str:
34
22
  return f"""
35
- # 🤖 多智能体消息处理系统
36
- 您是多智能体系统的一部分,通过结构化消息进行通信。
37
-
38
- # 🎯 核心规则
39
- ## 关键操作规则
40
- - 每轮只能执行一个操作:
41
- - 要么使用一个工具(文件操作、询问用户等)
42
- - 要么发送一条消息给其他智能体
43
- - 切勿在同一轮中同时进行这两种操作
44
-
45
- ## 消息流控制
46
- - 发送消息后等待响应
47
- - 处理响应后再进行下一步操作
48
- - 切勿同时发送多条消息
49
- - 切勿将消息与工具调用混合使用
50
-
51
- # 📝 消息格式
23
+ # 多智能体协作系统
24
+
25
+ ## 身份与角色定位
26
+ - **核心职责**:作为多智能体系统的协调者,通过结构化消息实现高效协作
27
+ - **关键能力**:消息路由、任务分发、结果整合、流程协调
28
+ - **工作范围**:在多个专业智能体之间建立有效沟通渠道
29
+
30
+ ## 交互原则与策略
31
+ ### 消息处理规范
32
+ - **单一操作原则**:每轮只执行一个操作(工具调用或消息发送)
33
+ - **完整性原则**:确保消息包含所有必要信息,避免歧义
34
+ - **明确性原则**:清晰表达意图、需求和期望结果
35
+ - **上下文保留**:在消息中包含足够的背景信息
36
+
37
+ ### 消息格式标准
52
38
  ```
53
39
  <SEND_MESSAGE>
54
40
  to: 智能体名称 # 目标智能体名称
55
41
  content: |
56
- 消息内容 # 消息内容
57
- 可使用多行 # 如果需要
58
- 保持正确的缩进
42
+ # 消息主题
43
+
44
+ ## 背景信息
45
+ [提供必要的上下文和背景]
46
+
47
+ ## 具体需求
48
+ [明确表达期望完成的任务]
49
+
50
+ ## 相关资源
51
+ [列出相关文档、数据或工具]
52
+
53
+ ## 期望结果
54
+ [描述期望的输出格式和内容]
59
55
  </SEND_MESSAGE>
60
56
  ```
61
57
 
62
- # 🔄 操作顺序
63
- 1. 选择最重要的操作
64
- - 评估优先级
65
- - 选择一个操作
66
- - 执行该操作
67
-
68
- 2. 等待响应
69
- - 处理结果/响应
70
- - 计划下一步操作
71
- - 等待下一轮
72
-
73
- 3. 处理响应
74
- - 处理收到的消息
75
- - 需要时回复发送者
76
- - 根据响应继续任务
77
-
78
- # 👥 可用智能体
79
- {chr(10).join([f"- {c.name}: {c.description}" for c in self.agents_config])}
80
-
81
- # ❗ 重要规则
82
- 1. 每轮只能执行一个操作
83
- 2. 等待响应
84
- 3. 处理后再进行下一步
85
- 4. 回复消息
86
- 5. 需要时转发任务
87
-
88
- # 💡 提示
89
- - 第一个操作将被执行
90
- - 额外的操作将被忽略
91
- - 总是先处理响应
92
- - 需要时发送消息以继续任务
93
- - 处理并回复收到的消息
58
+ ## 协作流程规范
59
+ ### 任务分发流程
60
+ 1. **需求分析**:理解用户需求并确定最适合的智能体
61
+ 2. **任务分解**:将复杂任务分解为可管理的子任务
62
+ 3. **精准分发**:根据专长将任务分配给合适的智能体
63
+ 4. **结果整合**:收集各智能体的输出并整合为连贯结果
64
+
65
+ ### 消息流控制
66
+ 1. **单向流动**:发送消息后等待响应,避免消息风暴
67
+ 2. **优先级管理**:处理紧急消息优先,保持任务顺序
68
+ 3. **状态跟踪**:记录每个任务的当前状态和处理进度
69
+ 4. **异常处理**:优雅处理超时、错误和意外响应
70
+
71
+ ## 可用智能体资源
72
+ {chr(10).join([f"- **{c['name']}**: {c.get('description', '')}" for c in self.agents_config])}
73
+
74
+ ## 最佳实践指南
75
+ 1. **任务明确化**:每个消息专注于单一、明确的任务
76
+ 2. **信息充分性**:提供足够信息让接收者能独立完成任务
77
+ 3. **反馈循环**:建立清晰的反馈机制,及时调整方向
78
+ 4. **知识共享**:确保关键信息在相关智能体间共享
79
+ 5. **协作效率**:避免不必要的消息传递,减少协调开销
94
80
  """
95
81
 
96
82
  def can_handle(self, response: str) -> bool:
@@ -128,29 +114,22 @@ content: |
128
114
  return ret
129
115
 
130
116
  def init_agents(self):
131
- for agent_config in self.agents_config:
132
- agent = Agent(system_prompt=agent_config.system_prompt,
133
- name=agent_config.name,
134
- description=agent_config.description,
135
- model_name=agent_config.model_name,
136
- platform=agent_config.platform,
137
- max_context_length=agent_config.max_context_length,
138
- execute_tool_confirm=agent_config.execute_tool_confirm,
139
- input_handler=agent_config.input_handler,
140
- use_methodology=False,
141
- record_methodology=False,
142
- need_summary=False,
143
- auto_complete=agent_config.auto_complete,
144
- summary_prompt=agent_config.summary_prompt,
145
- is_sub_agent=agent_config.is_sub_agent,
146
- output_handler=[*agent_config.output_handler, self],
147
- )
148
-
149
- self.agents[agent_config.name] = agent
150
-
151
- def run(self, user_input: str, file_list: Optional[List[str]] = None) -> str:
117
+ for config in self.agents_config:
118
+ output_handler = config.get('output_handler', [])
119
+ if len(output_handler) == 0:
120
+ output_handler = [
121
+ ToolRegistry(),
122
+ self,
123
+ ]
124
+ else:
125
+ output_handler.append(self)
126
+ config['output_handler'] = output_handler
127
+ agent = Agent(**config)
128
+ self.agents[config['name']] = agent
129
+
130
+ def run(self, user_input: str) -> str:
152
131
  last_agent = self.main_agent_name
153
- msg = self.agents[self.main_agent_name].run(user_input, file_list)
132
+ msg = self.agents[self.main_agent_name].run(user_input)
154
133
  while msg:
155
134
  if isinstance(msg, str):
156
135
  return msg
@@ -167,4 +146,46 @@ content: {msg['content']}
167
146
  PrettyOutput.print(f"{last_agent} 正在向 {msg['to']} 发送消息...", OutputType.INFO)
168
147
  last_agent = self.agents[msg['to']].name
169
148
  msg = self.agents[msg['to']].run(prompt)
170
- return ""
149
+ return ""
150
+
151
+
152
+ def main():
153
+ """从YAML配置文件初始化并运行多智能体系统
154
+
155
+ Returns:
156
+ 最终处理结果
157
+ """
158
+ init_env()
159
+ import argparse
160
+ parser = argparse.ArgumentParser(description="多智能体系统启动器")
161
+ parser.add_argument("--config", "-c", required=True, help="YAML配置文件路径")
162
+ parser.add_argument("--input", "-i", help="用户输入(可选)")
163
+ args = parser.parse_args()
164
+
165
+ try:
166
+ with open(args.config, 'r') as f:
167
+ config_data = yaml.safe_load(f)
168
+
169
+ # 获取agents配置
170
+ agents_config = config_data.get('agents', [])
171
+
172
+ main_agent_name = config_data.get('main_agent', '')
173
+ if not main_agent_name:
174
+ raise ValueError("必须指定main_agent作为主智能体")
175
+
176
+ # 创建并运行多智能体系统
177
+ multi_agent = MultiAgent(agents_config, main_agent_name)
178
+ user_input = args.input if args.input is not None else get_multiline_input("请输入内容(输入空行结束):")
179
+ if user_input == "":
180
+ return
181
+ return multi_agent.run(user_input)
182
+
183
+ except yaml.YAMLError as e:
184
+ raise ValueError(f"YAML配置文件解析错误: {str(e)}")
185
+ except Exception as e:
186
+ raise RuntimeError(f"多智能体系统初始化失败: {str(e)}")
187
+
188
+
189
+ if __name__ == "__main__":
190
+ result = main()
191
+
@@ -16,7 +16,6 @@ REQUIRED_METHODS = [
16
16
  ('set_model_name', ['model_name']),
17
17
  ('get_model_list', []),
18
18
  ('set_suppress_output', ['suppress']),
19
- ('upload_files', ['file_list'])
20
19
  ]
21
20
 
22
21
  class PlatformRegistry:
@@ -30,12 +30,6 @@ class SubAgentTool:
30
30
  "description": "任务的完成目标",
31
31
  "default": ""
32
32
  },
33
- "files": {
34
- "type": "array",
35
- "items": {"type": "string"},
36
- "description": "相关文件路径列表,用于文件问答和处理",
37
- "default": []
38
- }
39
33
  },
40
34
  "required": ["agent_name", "task", "context", "goal"]
41
35
  }
@@ -48,7 +42,6 @@ class SubAgentTool:
48
42
  task = args["task"]
49
43
  context = args.get("context", "")
50
44
  goal = args.get("goal", "")
51
- files = args.get("files", [])
52
45
 
53
46
  PrettyOutput.print(f"创建子代理: {agent_name}", OutputType.INFO)
54
47
 
@@ -69,7 +62,7 @@ class SubAgentTool:
69
62
 
70
63
  # Run sub-agent, pass file list
71
64
  PrettyOutput.print("子代理开始执行任务...", OutputType.INFO)
72
- result = sub_agent.run(task_description, file_list=files)
65
+ result = sub_agent.run(task_description)
73
66
 
74
67
  return {
75
68
  "success": True,
@@ -9,7 +9,7 @@ from jarvis.jarvis_platform.registry import PlatformRegistry
9
9
  import sys
10
10
  import argparse
11
11
 
12
- from jarvis.jarvis_utils.git_utils import has_uncommitted_changes
12
+ from jarvis.jarvis_utils.git_utils import find_git_root, has_uncommitted_changes
13
13
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
14
14
  from jarvis.jarvis_utils.utils import init_env
15
15
 
@@ -51,6 +51,7 @@ class GitCommitTool:
51
51
  def execute(self, args: Dict) -> Dict[str, Any]:
52
52
  """Execute automatic commit process with support for multi-line messages and special characters"""
53
53
  try:
54
+ find_git_root()
54
55
  if not has_uncommitted_changes():
55
56
  PrettyOutput.print("没有未提交的更改", OutputType.SUCCESS)
56
57
  return {"success": True, "stdout": "No changes to commit", "stderr": ""}
@@ -0,0 +1,143 @@
1
+ from typing import Dict, Any
2
+ import os
3
+
4
+ from yaspin import yaspin
5
+
6
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
7
+
8
+ class ReadCodeTool:
9
+ name = "read_code"
10
+ description = "用于读取代码文件并在每行前添加行号的工具"
11
+ parameters = {
12
+ "type": "object",
13
+ "properties": {
14
+ "files": {
15
+ "type": "array",
16
+ "items": {
17
+ "type": "object",
18
+ "properties": {
19
+ "path": {"type": "string"},
20
+ "start_line": {"type": "number", "default": 1},
21
+ "end_line": {"type": "number", "default": -1}
22
+ },
23
+ "required": ["path"]
24
+ },
25
+ "description": "要读取的文件列表"
26
+ }
27
+ },
28
+ "required": ["files"]
29
+ }
30
+
31
+ def _handle_single_file(self, filepath: str, start_line: int = 1, end_line: int = -1) -> Dict[str, Any]:
32
+ try:
33
+ abs_path = os.path.abspath(filepath)
34
+ with yaspin(text=f"正在读取文件: {abs_path}...", color="cyan") as spinner:
35
+ # 文件存在性检查
36
+ if not os.path.exists(abs_path):
37
+ return {
38
+ "success": False,
39
+ "stdout": "",
40
+ "stderr": f"文件不存在: {abs_path}"
41
+ }
42
+
43
+ # 文件大小限制检查(10MB)
44
+ if os.path.getsize(abs_path) > 10 * 1024 * 1024:
45
+ return {
46
+ "success": False,
47
+ "stdout": "",
48
+ "stderr": "文件过大 (>10MB)"
49
+ }
50
+
51
+ # 读取文件内容
52
+ with open(abs_path, 'r', encoding='utf-8') as f:
53
+ lines = f.readlines()
54
+
55
+ total_lines = len(lines)
56
+
57
+ # 处理特殊值-1表示文件末尾
58
+ if end_line == -1:
59
+ end_line = total_lines
60
+ else:
61
+ end_line = max(1, min(end_line, total_lines)) if end_line >= 0 else total_lines + end_line + 1
62
+
63
+ start_line = max(1, min(start_line, total_lines)) if start_line >= 0 else total_lines + start_line + 1
64
+
65
+ if start_line > end_line:
66
+ spinner.fail("❌")
67
+ return {
68
+ "success": False,
69
+ "stdout": "",
70
+ "stderr": f"无效的行范围 [{start_line}-{end_line}] (总行数: {total_lines})"
71
+ }
72
+
73
+ # 添加行号并构建输出内容
74
+ selected_lines = lines[start_line-1:end_line]
75
+ numbered_content = "".join(
76
+ [f"{i:4d} | {line}"
77
+ for i, line in enumerate(selected_lines, start=start_line)]
78
+ )
79
+
80
+ # 构建输出格式
81
+ output = (
82
+ f"\n🔍 文件: {abs_path}\n"
83
+ f"📄 原始行号: {start_line}-{end_line} (共{end_line - start_line + 1}行) | 显示行号: 1-{len(selected_lines)}\n\n"
84
+ f"{numbered_content}\n"
85
+ f"{'='*80}\n"
86
+ )
87
+ spinner.text = f"文件读取完成: {abs_path}"
88
+ spinner.ok("✅")
89
+ return {
90
+ "success": True,
91
+ "stdout": output,
92
+ "stderr": ""
93
+ }
94
+
95
+ except Exception as e:
96
+ PrettyOutput.print(str(e), OutputType.ERROR)
97
+ return {
98
+ "success": False,
99
+ "stdout": "",
100
+ "stderr": f"文件读取失败: {str(e)}"
101
+ }
102
+
103
+ def execute(self, args: Dict) -> Dict[str, Any]:
104
+ try:
105
+ if "files" not in args or not isinstance(args["files"], list):
106
+ return {
107
+ "success": False,
108
+ "stdout": "",
109
+ "stderr": "参数中必须包含文件列表"
110
+ }
111
+
112
+ all_outputs = []
113
+ overall_success = True
114
+
115
+ for file_info in args["files"]:
116
+ if not isinstance(file_info, dict) or "path" not in file_info:
117
+ continue
118
+
119
+ result = self._handle_single_file(
120
+ file_info["path"].strip(),
121
+ file_info.get("start_line", 1),
122
+ file_info.get("end_line", -1)
123
+ )
124
+
125
+ if result["success"]:
126
+ all_outputs.append(result["stdout"])
127
+ else:
128
+ all_outputs.append(f"❌ {file_info['path']}: {result['stderr']}")
129
+ overall_success = False
130
+
131
+ return {
132
+ "success": overall_success,
133
+ "stdout": "\n".join(all_outputs),
134
+ "stderr": ""
135
+ }
136
+
137
+ except Exception as e:
138
+ PrettyOutput.print(str(e), OutputType.ERROR)
139
+ return {
140
+ "success": False,
141
+ "stdout": "",
142
+ "stderr": f"代码读取失败: {str(e)}"
143
+ }
@@ -354,45 +354,41 @@ arguments:
354
354
  if result["success"]:
355
355
  # If the output exceeds 4k characters, use a large model to summarize
356
356
  if get_context_token_count(output) > self.max_token_count:
357
- with yaspin(text="正在总结输出...", color="yellow") as spinner:
358
- try:
359
-
360
- model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
361
-
362
- # If the output exceeds the maximum context length, only take the last part
363
- max_count = self.max_token_count
364
- if get_context_token_count(output) > max_count:
365
- output_to_summarize = output[-max_count:]
366
- truncation_notice = f"\n(注意:由于输出过长,仅总结最后 {max_count} 个字符)"
367
- else:
368
- output_to_summarize = output
369
- truncation_notice = ""
370
-
371
- prompt = f"""请总结以下工具的执行结果,提取关键信息和重要结果。注意:
372
- 1. 保留所有重要的数值、路径、错误信息等
373
- 2. 保持结果的准确性
374
- 3. 用简洁的语言描述主要内容
375
- 4. 如果有错误信息,确保包含在总结中
376
-
377
- 工具名称: {name}
378
- 执行结果:
379
- {output_to_summarize}
380
-
381
- 请提供总结:"""
382
-
383
- summary = model.chat_until_success(prompt)
384
- output = f"""--- 原始输出过长,以下是总结 ---{truncation_notice}
385
-
386
- {summary}
387
-
388
- --- 总结结束 ---"""
389
- spinner.text = "总结完成"
390
- spinner.ok("")
391
- except Exception as e:
392
- spinner.text = "总结失败"
393
- spinner.fail("❌")
394
- PrettyOutput.print(f"总结失败: {str(e)}", OutputType.ERROR)
395
- output = f"输出过长 ({len(output)} 字符),建议查看原始输出。\n前300字符预览:\n{output[:300]}..."
357
+ PrettyOutput.section("输出过长,正在总结...", OutputType.SYSTEM)
358
+ try:
359
+
360
+ model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
361
+ model.set_suppress_output(False)
362
+ # If the output exceeds the maximum context length, only take the last part
363
+ max_count = self.max_token_count
364
+ if get_context_token_count(output) > max_count:
365
+ output_to_summarize = output[-max_count:]
366
+ truncation_notice = f"\n(注意:由于输出过长,仅总结最后 {max_count} 个字符)"
367
+ else:
368
+ output_to_summarize = output
369
+ truncation_notice = ""
370
+
371
+ prompt = f"""请总结以下工具的执行结果,提取关键信息和重要结果。注意:
372
+ 1. 保留所有重要的数值、路径、错误信息等
373
+ 2. 保持结果的准确性
374
+ 3. 用简洁的语言描述主要内容
375
+ 4. 如果有错误信息,确保包含在总结中
376
+
377
+ 工具名称: {name}
378
+ 执行结果:
379
+ {output_to_summarize}
380
+
381
+ 请提供总结:"""
382
+
383
+ summary = model.chat_until_success(prompt)
384
+ output = f"""--- 原始输出过长,以下是总结 ---{truncation_notice}
385
+
386
+ {summary}
387
+
388
+ --- 总结结束 ---"""
389
+ except Exception as e:
390
+ PrettyOutput.print(f"总结失败: {str(e)}", OutputType.ERROR)
391
+ output = f"输出过长 ({len(output)} 字符),建议查看原始输出。\n前300字符预览:\n{output[:300]}..."
396
392
  return output
397
393
 
398
394
  except Exception as e:
@@ -9,6 +9,8 @@ from yaspin import yaspin
9
9
  from jarvis.jarvis_platform.registry import PlatformRegistry
10
10
 
11
11
  class ToolGenerator:
12
+ """工具生成器类,用于自动创建与Jarvis系统集成的新工具"""
13
+
12
14
  name = "tool_generator"
13
15
  description = "使用LLM自动生成与系统集成的新工具"
14
16
  parameters = {
@@ -31,8 +33,14 @@ class ToolGenerator:
31
33
  }
32
34
 
33
35
  def execute(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
34
- """Generate and save a new tool using LLM"""
35
- # Get fresh model instance for each execution
36
+ """
37
+ 执行工具生成过程
38
+ Args:
39
+ arguments: 包含工具生成所需参数的字典
40
+ Returns:
41
+ 包含执行结果的字典,包含success、stdout和stderr字段
42
+ """
43
+ # 获取代码生成平台实例
36
44
  model = PlatformRegistry.get_global_platform_registry().get_codegen_platform()
37
45
 
38
46
  try:
@@ -40,37 +48,37 @@ class ToolGenerator:
40
48
  description = arguments["description"]
41
49
  input_spec = arguments["input_spec"]
42
50
 
43
- # Generate tool implementation using LLM
51
+ # 使用LLM生成工具实现代码
44
52
  with yaspin(text="正在生成工具...", color="cyan") as spinner:
45
53
  prompt = self._create_prompt(tool_name, description, input_spec)
46
54
  llm_response = model.chat_until_success(prompt)
47
55
  spinner.text = "工具生成完成"
48
56
  spinner.ok("✅")
49
57
 
50
- # Extract implementation with more flexible parsing
58
+ # 从LLM响应中提取实现代码
51
59
  with yaspin(text="正在提取工具实现...", color="cyan") as spinner:
52
60
  implementation = self._extract_code(llm_response)
53
61
  if not implementation:
54
62
  return {
55
63
  "success": False,
56
64
  "stdout": "",
57
- "stderr": "Could not extract valid Python code from LLM response"
65
+ "stderr": "无法从LLM响应中提取有效的Python代码"
58
66
  }
59
67
  spinner.text = "工具实现提取完成"
60
68
  spinner.ok("✅")
61
69
 
62
- # Validate return value format
70
+ # 验证生成的工具代码是否符合返回值格式要求
63
71
  with yaspin(text="正在验证工具返回值格式...", color="cyan") as spinner:
64
72
  if not self._validate_return_value_format(implementation):
65
73
  return {
66
74
  "success": False,
67
75
  "stdout": "",
68
- "stderr": "Generated tool does not follow required return value format"
76
+ "stderr": "生成的工具不符合要求的返回值格式"
69
77
  }
70
78
  spinner.text = "工具返回值格式验证完成"
71
79
  spinner.ok("✅")
72
80
 
73
- # Save the new tool
81
+ # 保存生成的新工具
74
82
  with yaspin(text="正在保存工具...", color="cyan") as spinner:
75
83
  tools_dir = Path.home() / ".jarvis" / "tools"
76
84
  tools_dir.mkdir(parents=True, exist_ok=True)
@@ -83,7 +91,7 @@ class ToolGenerator:
83
91
 
84
92
  return {
85
93
  "success": True,
86
- "stdout": f"Tool successfully generated at: {tool_file}",
94
+ "stdout": f"工具成功生成于: {tool_file}",
87
95
  "stderr": ""
88
96
  }
89
97
 
@@ -91,11 +99,19 @@ class ToolGenerator:
91
99
  return {
92
100
  "success": False,
93
101
  "stdout": "",
94
- "stderr": f"Tool generation failed: {str(e)}"
102
+ "stderr": f"工具生成失败: {str(e)}"
95
103
  }
96
104
 
97
105
  def _create_prompt(self, tool_name: str, description: str, input_spec: str) -> str:
98
- """创建用于工具生成的LLM提示"""
106
+ """
107
+ 创建用于工具生成的LLM提示
108
+ Args:
109
+ tool_name: 工具名称
110
+ description: 工具描述
111
+ input_spec: 输入规范
112
+ Returns:
113
+ 格式化后的提示字符串
114
+ """
99
115
  example_code = '''
100
116
  <TOOL>
101
117
  from typing import Dict, Any
@@ -176,20 +192,32 @@ class CustomTool:
176
192
  '''
177
193
 
178
194
  def _extract_code(self, response: str) -> str:
179
- """Flexibly extract Python code from LLM response"""
180
- # Find the first occurrence of <TOOL> and </TOOL>
195
+ """
196
+ 从LLM响应中提取Python代码
197
+ Args:
198
+ response: LLM的响应字符串
199
+ Returns:
200
+ 提取到的Python代码字符串
201
+ """
202
+ # 查找第一个<TOOL>和</TOOL>标签之间的内容
181
203
  sm = re.search(r'<TOOL>(.*?)</TOOL>', response, re.DOTALL)
182
204
  if sm:
183
205
  return sm.group(1)
184
206
  return ""
185
207
 
186
208
  def _validate_return_value_format(self, code: str) -> bool:
187
- """Validate that execute method returns correct format"""
209
+ """
210
+ 验证execute方法的返回值格式是否正确
211
+ Args:
212
+ code: 要验证的代码字符串
213
+ Returns:
214
+ 布尔值,表示格式是否正确
215
+ """
188
216
  required_fields = ["success", "stdout", "stderr"]
189
- # Look for execute method
217
+ # 检查execute方法是否存在
190
218
  if "def execute(self, args: Dict) -> Dict:" not in code and \
191
219
  "def execute(self, args: Dict) -> Dict[str, Any]:" not in code:
192
220
  return False
193
221
 
194
- # Check for required fields in return statement
195
- return all(field in code for field in required_fields)
222
+ # 检查返回值中是否包含所有必需字段
223
+ return all(field in code for field in required_fields)