jarvis-ai-assistant 0.1.220__py3-none-any.whl → 0.1.222__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.
Files changed (32) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +110 -395
  3. jarvis/jarvis_agent/edit_file_handler.py +32 -185
  4. jarvis/jarvis_agent/jarvis.py +14 -9
  5. jarvis/jarvis_agent/main.py +13 -6
  6. jarvis/jarvis_agent/prompt_builder.py +57 -0
  7. jarvis/jarvis_agent/prompts.py +188 -0
  8. jarvis/jarvis_agent/protocols.py +30 -0
  9. jarvis/jarvis_agent/session_manager.py +84 -0
  10. jarvis/jarvis_agent/tool_executor.py +49 -0
  11. jarvis/jarvis_code_agent/code_agent.py +14 -23
  12. jarvis/jarvis_code_analysis/code_review.py +1 -1
  13. jarvis/jarvis_data/config_schema.json +13 -18
  14. jarvis/jarvis_git_details/main.py +1 -1
  15. jarvis/jarvis_platform/kimi.py +4 -2
  16. jarvis/jarvis_rag/__init__.py +2 -2
  17. jarvis/jarvis_rag/cache.py +28 -30
  18. jarvis/jarvis_rag/cli.py +141 -52
  19. jarvis/jarvis_rag/embedding_manager.py +32 -46
  20. jarvis/jarvis_rag/llm_interface.py +32 -34
  21. jarvis/jarvis_rag/query_rewriter.py +11 -12
  22. jarvis/jarvis_rag/rag_pipeline.py +40 -43
  23. jarvis/jarvis_rag/reranker.py +18 -18
  24. jarvis/jarvis_rag/retriever.py +29 -29
  25. jarvis/jarvis_tools/edit_file.py +11 -36
  26. jarvis/jarvis_utils/config.py +20 -25
  27. {jarvis_ai_assistant-0.1.220.dist-info → jarvis_ai_assistant-0.1.222.dist-info}/METADATA +25 -20
  28. {jarvis_ai_assistant-0.1.220.dist-info → jarvis_ai_assistant-0.1.222.dist-info}/RECORD +32 -27
  29. {jarvis_ai_assistant-0.1.220.dist-info → jarvis_ai_assistant-0.1.222.dist-info}/entry_points.txt +9 -0
  30. {jarvis_ai_assistant-0.1.220.dist-info → jarvis_ai_assistant-0.1.222.dist-info}/WHEEL +0 -0
  31. {jarvis_ai_assistant-0.1.220.dist-info → jarvis_ai_assistant-0.1.222.dist-info}/licenses/LICENSE +0 -0
  32. {jarvis_ai_assistant-0.1.220.dist-info → jarvis_ai_assistant-0.1.222.dist-info}/top_level.txt +0 -0
@@ -3,12 +3,8 @@ import re
3
3
  from typing import Any, Dict, List, Tuple
4
4
 
5
5
  from jarvis.jarvis_agent.output_handler import OutputHandler
6
- from jarvis.jarvis_platform.registry import PlatformRegistry
7
- from jarvis.jarvis_utils.git_utils import revert_file
8
- from jarvis.jarvis_utils.globals import get_interrupt, set_interrupt
9
6
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
10
7
  from jarvis.jarvis_utils.tag import ct, ot
11
- from jarvis.jarvis_utils.utils import is_context_overflow
12
8
 
13
9
 
14
10
  class EditFileHandler(OutputHandler):
@@ -69,13 +65,7 @@ class EditFileHandler(OutputHandler):
69
65
  ]
70
66
 
71
67
  print(f"📝 正在处理文件 {file_path}...")
72
- # 首先尝试fast_edit模式
73
68
  success, result = self._fast_edit(file_path, file_patches)
74
- if not success:
75
- # 如果fast_edit失败,尝试slow_edit模式
76
- success, result = EditFileHandler._slow_edit(
77
- file_path, file_patches, agent
78
- )
79
69
 
80
70
  if success:
81
71
  results.append(f"✅ 文件 {file_path} 修改成功")
@@ -173,7 +163,7 @@ class EditFileHandler(OutputHandler):
173
163
  1. 直接进行字符串替换,效率高
174
164
  2. 会自动处理缩进问题,尝试匹配不同缩进级别的代码
175
165
  3. 确保搜索文本在文件中唯一匹配
176
- 4. 如果失败会自动回滚修改
166
+ 4. 如果部分补丁失败,会继续应用剩余补丁,并报告失败信息
177
167
 
178
168
  Args:
179
169
  file_path: 要修改的文件路径,支持绝对路径和相对路径
@@ -181,8 +171,8 @@ class EditFileHandler(OutputHandler):
181
171
 
182
172
  Returns:
183
173
  Tuple[bool, str]:
184
- 返回处理结果元组,第一个元素表示是否成功(True/False),
185
- 第二个元素为结果信息,成功时为修改后的文件内容,失败时为错误信息
174
+ 返回处理结果元组,第一个元素表示是否所有补丁都成功应用,
175
+ 第二个元素为结果信息,全部成功时为修改后的文件内容,部分或全部失败时为错误信息
186
176
  """
187
177
  try:
188
178
  # 确保目录存在
@@ -197,13 +187,17 @@ class EditFileHandler(OutputHandler):
197
187
  # 应用所有补丁
198
188
  modified_content = file_content
199
189
  patch_count = 0
190
+ failed_patches: List[Dict[str, Any]] = []
191
+ successful_patches = 0
192
+
200
193
  for patch in patches:
194
+ patch_count += 1
201
195
  search_text = patch["SEARCH"]
202
196
  replace_text = patch["REPLACE"]
203
- patch_count += 1
204
197
 
205
198
  # 精确匹配搜索文本(保留原始换行和空格)
206
199
  exact_search = search_text
200
+ found = False
207
201
 
208
202
  if exact_search in modified_content:
209
203
  # 直接执行替换(保留所有原始格式)
@@ -211,8 +205,8 @@ class EditFileHandler(OutputHandler):
211
205
  exact_search, replace_text
212
206
  )
213
207
  print(f"✅ 补丁 #{patch_count} 应用成功")
208
+ found = True
214
209
  else:
215
- found = False
216
210
  # 如果匹配不到,并且search与replace块的首尾都是换行,尝试去掉第一个和最后一个换行
217
211
  if (
218
212
  search_text.startswith("\n")
@@ -261,184 +255,37 @@ class EditFileHandler(OutputHandler):
261
255
  found = True
262
256
  break
263
257
 
264
- if not found:
265
- PrettyOutput.print(
266
- f"搜索文本在文件中不存在:\n{search_text}",
267
- output_type=OutputType.WARNING,
268
- )
269
- return False, f"搜索文本在文件中不存在:\n{search_text}"
258
+ if found:
259
+ successful_patches += 1
260
+ else:
261
+ error_msg = "搜索文本在文件中不存在"
262
+ PrettyOutput.print(
263
+ f"{error_msg}:\n{search_text}",
264
+ output_type=OutputType.WARNING,
265
+ )
266
+ failed_patches.append({"patch": patch, "error": error_msg})
270
267
 
271
268
  # 写入修改后的内容
272
269
  with open(file_path, "w", encoding="utf-8") as f:
273
270
  f.write(modified_content)
274
271
 
275
- print(f"✅ 文件 {file_path} 修改完成,应用了 {patch_count} 个补丁")
276
- return True, modified_content
277
-
278
- except Exception as e:
279
- print(f"❌ 文件修改失败: {str(e)}")
280
- revert_file(file_path)
281
- return False, f"文件修改失败: {str(e)}"
282
-
283
- @staticmethod
284
- def _slow_edit(
285
- file_path: str, patches: List[Dict[str, str]], agent: Any
286
- ) -> Tuple[bool, str]:
287
- """使用AI模型生成补丁并应用到文件
288
-
289
- 当_fast_edit方法失败时调用此方法,使用AI模型生成更精确的补丁。
290
- 特点:
291
- 1. 适用于复杂修改场景或需要上下文理解的修改
292
- 2. 会自动处理大文件上传问题
293
- 3. 会尝试最多3次生成有效的补丁
294
- 4. 生成的补丁会再次通过_fast_edit方法应用
295
- 5. 如果失败会自动回滚修改
296
-
297
- Args:
298
- file_path: 要修改的文件路径,支持绝对路径和相对路径
299
- patches: 补丁列表,每个补丁包含search(搜索文本)和replace(替换文本)
300
- agent: 执行处理的agent实例,用于访问AI模型平台
301
-
302
- Returns:
303
- Tuple[bool, str]:
304
- 返回处理结果元组,第一个元素表示是否成功(True/False),
305
- 第二个元素为结果信息,成功时为修改后的文件内容,失败时为错误信息
306
- """
307
- try:
308
- model = PlatformRegistry().get_normal_platform()
309
-
310
- # 读取原始文件内容
311
- file_content = ""
312
- if os.path.exists(file_path):
313
- with open(file_path, "r", encoding="utf-8") as f:
314
- file_content = f.read()
315
-
316
- is_large_context = is_context_overflow(file_content)
317
- upload_success = False
318
-
319
- # 如果是大文件,尝试上传到模型平台
320
- if (
321
- is_large_context
322
- and model.support_upload_files()
323
- and model.upload_files([file_path])
324
- ):
325
- upload_success = True
326
-
327
- model.set_suppress_output(False)
328
-
329
- # 构建补丁内容
330
- patch_content = []
331
- for patch in patches:
332
- patch_content.append(
333
- {
334
- "SEARCH": patch["SEARCH"],
335
- "REPLACE": patch["REPLACE"],
336
- }
272
+ if failed_patches:
273
+ error_details = [
274
+ f" - 失败的补丁: \n{p['patch']['SEARCH']}\n 错误: {p['error']}"
275
+ for p in failed_patches
276
+ ]
277
+ summary = (
278
+ f"文件 {file_path} 修改部分成功。\n"
279
+ f"成功: {successful_patches}/{patch_count}, "
280
+ f"失败: {len(failed_patches)}/{patch_count}.\n"
281
+ f"失败详情:\n" + "\n".join(error_details)
337
282
  )
283
+ print(f"❌ {summary}")
284
+ return False, summary
338
285
 
339
- # 构建提示词
340
- main_prompt = f"""
341
- # 代码补丁生成专家指南
342
-
343
- ## 任务描述
344
- 你是一位精确的代码补丁生成专家,需要根据补丁描述生成精确的代码差异。
345
-
346
- ### 补丁内容
347
- ```
348
- {str(patch_content)}
349
- ```
350
-
351
- ## 补丁生成要求
352
- 1. **精确性**:严格按照补丁的意图修改代码
353
- 2. **格式一致性**:严格保持原始代码的格式风格,如果补丁中缩进或者空行与原代码不一致,则需要修正补丁中的缩进或者空行
354
- 3. **最小化修改**:只修改必要的代码部分,保持其他部分不变
355
- 4. **上下文完整性**:提供足够的上下文,确保补丁能准确应用
356
-
357
- ## 输出格式规范
358
- - 使用{ot("DIFF")}块包围每个需要修改的代码段
359
- - 每个{ot("DIFF")}块必须包含SEARCH部分和REPLACE部分
360
- - SEARCH部分是需要查找的原始代码
361
- - REPLACE部分是替换后的新代码
362
- - 确保SEARCH部分能在原文件中**唯一匹配**
363
- - 如果修改较大,可以使用多个{ot("DIFF")}块
364
-
365
- ## 输出模板
366
- {ot("DIFF")}
367
- {ot("SEARCH")}[需要查找的原始代码,包含足够上下文,避免出现可匹配多处的情况]{ct("SEARCH")}
368
- {ot("REPLACE")}[替换后的新代码]{ct("REPLACE")}
369
- {ct("DIFF")}
370
-
371
- {ot("DIFF")}
372
- {ot("SEARCH")}[另一处需要查找的原始代码,包含足够上下文,避免出现可匹配多处的情况]{ct("SEARCH")}
373
- {ot("REPLACE")}[另一处替换后的新代码]{ct("REPLACE")}
374
- {ct("DIFF")}
375
- """
376
-
377
- # 尝试最多3次生成补丁
378
- for _ in range(3):
379
- if is_large_context:
380
- if upload_success:
381
- response = model.chat_until_success(main_prompt)
382
- else:
383
- file_prompt = f"""
384
- # 原始代码
385
- {file_content}
386
- """
387
- response = model.chat_until_success(main_prompt + file_prompt)
388
- else:
389
- file_prompt = f"""
390
- # 原始代码
391
- {file_content}
392
- """
393
- response = model.chat_until_success(main_prompt + file_prompt)
394
-
395
- # 检查是否被中断
396
- if get_interrupt():
397
- set_interrupt(False)
398
- user_input = agent.multiline_inputer(
399
- "补丁应用被中断,请输入补充信息:"
400
- )
401
- if not user_input.strip():
402
- return False, "用户中断了补丁应用"
403
- return False, f"用户中断了补丁应用并提供了补充信息: {user_input}"
404
-
405
- # 解析生成的补丁
406
- diff_blocks = re.finditer(
407
- ot("DIFF")
408
- + r"\s*"
409
- + ot("SEARCH")
410
- + r"(.*?)"
411
- + ct("SEARCH")
412
- + r"\s*"
413
- + ot("REPLACE")
414
- + r"(.*?)"
415
- + ct("REPLACE")
416
- + r"\s*"
417
- + ct("DIFF"),
418
- response,
419
- re.DOTALL,
420
- )
421
-
422
- generated_patches = []
423
- for match in diff_blocks:
424
- generated_patches.append(
425
- {
426
- "SEARCH": match.group(1).strip(),
427
- "REPLACE": match.group(2).strip(),
428
- }
429
- )
430
-
431
- if generated_patches:
432
- # 尝试应用生成的补丁
433
- success, result = EditFileHandler._fast_edit(
434
- file_path, generated_patches
435
- )
436
- if success:
437
- return True, result
438
-
439
- return False, "AI模型无法生成有效的补丁"
286
+ print(f"✅ 文件 {file_path} 修改完成,应用了 {patch_count} 个补丁")
287
+ return True, modified_content
440
288
 
441
289
  except Exception as e:
442
290
  print(f"❌ 文件修改失败: {str(e)}")
443
- revert_file(file_path)
444
291
  return False, f"文件修改失败: {str(e)}"
@@ -109,8 +109,13 @@ def _select_task(tasks: Dict[str, str]) -> str:
109
109
  def main() -> None:
110
110
 
111
111
  parser = argparse.ArgumentParser(description="Jarvis AI assistant")
112
- parser.add_argument("-p", "--platform", type=str, help="Platform to use")
113
- parser.add_argument("-m", "--model", type=str, help="Model to use")
112
+ parser.add_argument(
113
+ "--llm_type",
114
+ type=str,
115
+ default="normal",
116
+ choices=["normal", "thinking"],
117
+ help="LLM type to use",
118
+ )
114
119
  parser.add_argument(
115
120
  "-t",
116
121
  "--task",
@@ -132,8 +137,7 @@ def main() -> None:
132
137
  try:
133
138
  agent = Agent(
134
139
  system_prompt=origin_agent_system_prompt,
135
- platform=args.platform,
136
- model_name=args.model,
140
+ llm_type=args.llm_type,
137
141
  input_handler=[shell_input_handler, builtin_input_handler],
138
142
  output_handler=[ToolRegistry()],
139
143
  need_summary=False,
@@ -151,11 +155,12 @@ def main() -> None:
151
155
  agent.run(args.task)
152
156
  sys.exit(0)
153
157
 
154
- tasks = _load_tasks()
155
- if tasks and (selected_task := _select_task(tasks)):
156
- PrettyOutput.print(f"开始执行任务: \n{selected_task}", OutputType.INFO)
157
- agent.run(selected_task)
158
- sys.exit(0)
158
+ if agent.first:
159
+ tasks = _load_tasks()
160
+ if tasks and (selected_task := _select_task(tasks)):
161
+ PrettyOutput.print(f"开始执行任务: \n{selected_task}", OutputType.INFO)
162
+ agent.run(selected_task)
163
+ sys.exit(0)
159
164
 
160
165
  user_input = get_multiline_input("请输入你的任务(输入空行退出):")
161
166
  if user_input:
@@ -20,9 +20,7 @@ def load_config(config_path: str) -> dict:
20
20
  dict: 配置字典
21
21
  """
22
22
  if not os.path.exists(config_path):
23
- PrettyOutput.print(
24
- f"配置文件 {config_path} 不存在,使用默认配置", OutputType.WARNING
25
- )
23
+ PrettyOutput.print(f"配置文件 {config_path} 不存在,使用默认配置", OutputType.WARNING)
26
24
  return {}
27
25
 
28
26
  with open(config_path, "r", encoding="utf-8", errors="ignore") as f:
@@ -45,16 +43,25 @@ def main():
45
43
  "-c", "--agent_definition", type=str, help="Path to agent definition file"
46
44
  )
47
45
  parser.add_argument("-t", "--task", type=str, help="Initial task to execute")
46
+ parser.add_argument(
47
+ "--llm_type",
48
+ type=str,
49
+ default="normal",
50
+ choices=["normal", "thinking"],
51
+ help="LLM type to use, overriding config",
52
+ )
48
53
  args = parser.parse_args()
49
54
 
50
55
  # Initialize environment
51
- init_env(
52
- "欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=args.config
53
- )
56
+ init_env("欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=args.config)
54
57
 
55
58
  # Load configuration
56
59
  config = load_config(args.agent_definition) if args.agent_definition else {}
57
60
 
61
+ # Override config with command-line arguments if provided
62
+ if args.llm_type:
63
+ config["llm_type"] = args.llm_type
64
+
58
65
  # Create and run agent
59
66
  try:
60
67
  agent = Agent(**config)
@@ -0,0 +1,57 @@
1
+ # -*- coding: utf-8 -*-
2
+ from typing import List
3
+
4
+ from jarvis.jarvis_agent.protocols import OutputHandlerProtocol
5
+
6
+
7
+ def build_action_prompt(output_handlers: List[OutputHandlerProtocol]) -> str:
8
+ """
9
+ Builds the action prompt string from a list of output handlers.
10
+
11
+ Args:
12
+ output_handlers: A list of output handler instances.
13
+
14
+ Returns:
15
+ A formatted string containing the action prompt.
16
+ """
17
+ action_prompt = """
18
+ <actions>
19
+ # 🧰 可用操作
20
+ 以下是您可以使用的操作:
21
+ """
22
+
23
+ # Add tool list overview
24
+ action_prompt += "\n<overview>\n## Action List\n"
25
+ action_prompt += (
26
+ "[" + ", ".join([handler.name() for handler in output_handlers]) + "]"
27
+ )
28
+ action_prompt += "\n</overview>"
29
+
30
+ # Add details for each tool
31
+ action_prompt += "\n\n<details>\n# 📝 Action Details\n"
32
+ for handler in output_handlers:
33
+ action_prompt += f"\n<tool>\n## {handler.name()}\n"
34
+ # Get the handler's prompt and ensure correct formatting
35
+ handler_prompt = handler.prompt().strip()
36
+ # Adjust indentation to maintain hierarchy
37
+ handler_prompt = "\n".join(
38
+ " " + line if line.strip() else line
39
+ for line in handler_prompt.split("\n")
40
+ )
41
+ action_prompt += handler_prompt + "\n</tool>\n"
42
+
43
+ # Add tool usage summary
44
+ action_prompt += """
45
+ </details>
46
+
47
+ <rules>
48
+ # ❗ 重要操作使用规则
49
+ 1. 一次对话只能使用一个操作,否则会出错
50
+ 2. 严格按照每个操作的格式执行
51
+ 3. 等待操作结果后再进行下一个操作
52
+ 4. 处理完结果后再调用新的操作
53
+ 5. 如果对操作使用不清楚,请请求帮助
54
+ </rules>
55
+ </actions>
56
+ """
57
+ return action_prompt
@@ -0,0 +1,188 @@
1
+ # -*- coding: utf-8 -*-
2
+ from jarvis.jarvis_utils.tag import ct, ot
3
+
4
+ DEFAULT_SUMMARY_PROMPT = """<report>
5
+ 请生成任务执行的简明总结报告,包括:
6
+
7
+ <content>
8
+ 1. 任务目标:任务重述
9
+ 2. 执行结果:成功/失败
10
+ 3. 关键信息:执行过程中提取的重要信息
11
+ 4. 重要发现:任何值得注意的发现
12
+ 5. 后续建议:如果有的话
13
+ </content>
14
+
15
+ <format>
16
+ 请使用简洁的要点描述,突出重要信息。
17
+ </format>
18
+ </report>
19
+ """
20
+
21
+ SUMMARY_REQUEST_PROMPT = """<summary_request>
22
+ <objective>
23
+ 请对当前对话历史进行简明扼要的总结,提取关键信息和重要决策点。这个总结将作为上下文继续任务,因此需要保留对后续对话至关重要的内容。
24
+ </objective>
25
+
26
+ <guidelines>
27
+ 1. 提取关键信息:任务目标、已确定的事实、重要决策、达成的共识
28
+ 2. 保留技术细节:命令、代码片段、文件路径、配置设置等技术细节
29
+ 3. 记录任务进展:已完成的步骤、当前所处阶段、待解决的问题
30
+ 4. 包含用户偏好:用户表达的明确偏好、限制条件或特殊要求
31
+ 5. 省略冗余内容:问候语、重复信息、不相关的讨论
32
+ </guidelines>
33
+
34
+ <format>
35
+ - 使用简洁、客观的语言
36
+ - 按时间顺序或主题组织信息
37
+ - 使用要点列表增强可读性
38
+ - 总结应控制在500词以内
39
+ </format>
40
+ </summary_request>
41
+ """
42
+
43
+
44
+ TASK_ANALYSIS_PROMPT = f"""<task_analysis>
45
+ <request>
46
+ 当前任务已结束,请分析该任务的解决方案:
47
+ 1. 首先检查现有工具或方法论是否已经可以完成该任务,如果可以,直接说明即可,无需生成新内容
48
+ 2. 如果现有工具/方法论不足,评估当前任务是否可以通过编写新工具来自动化解决
49
+ 3. 如果可以通过工具解决,请设计并提供工具代码
50
+ 4. 如果无法通过编写通用工具完成,评估当前的执行流程是否可以总结为通用方法论
51
+ 5. 如果以上都不可行,给出详细理由
52
+ 请根据分析结果采取相应行动:说明现有工具/方法论、创建新工具、生成新方法论或说明原因。
53
+ </request>
54
+ <evaluation_criteria>
55
+ 现有资源评估:
56
+ 1. 现有工具 - 检查系统中是否已有可以完成该任务的工具
57
+ 2. 现有方法论 - 检查是否已有适用于该任务的方法论
58
+ 3. 组合使用 - 评估现有工具和方法论组合使用是否可以解决问题
59
+ 工具评估标准:
60
+ 1. 通用性 - 该工具是否可以解决一类问题,而不仅仅是当前特定问题
61
+ 2. 自动化 - 该工具是否可以减少人工干预,提高效率
62
+ 3. 可靠性 - 该工具是否可以在不同场景下稳定工作
63
+ 4. 简单性 - 该工具是否易于使用,参数设计是否合理
64
+ 方法论评估标准:
65
+ 1. 方法论应聚焦于通用且可重复的解决方案流程
66
+ 2. 方法论应该具备足够的通用性,可应用于同类问题
67
+ 3. 特别注意用户在执行过程中提供的修正、反馈和改进建议
68
+ 4. 如果用户明确指出了某个解决步骤的优化方向,这应该被纳入方法论
69
+ 5. 方法论要严格按照实际的执行流程来总结,不要遗漏或增加任何步骤
70
+ </evaluation_criteria>
71
+ <tool_requirements>
72
+ 工具代码要求:
73
+ 1. 工具类名应与工具名称保持一致
74
+ 2. 必须包含name、description、parameters属性
75
+ 3. 必须实现execute方法处理输入参数
76
+ 4. 可选实现check方法验证环境
77
+ 5. 工具描述应详细说明用途、适用场景和使用示例
78
+ 6. 参数定义应遵循JSON Schema格式
79
+ 7. 不要包含特定任务的细节,保持通用性
80
+ 工具设计关键点:
81
+ 1. **使用PrettyOutput打印执行过程**:强烈建议在工具中使用PrettyOutput显示执行过程,
82
+ 这样用户可以了解工具在做什么,提升用户体验。示例:
83
+ ```python
84
+ from jarvis.jarvis_utils.output import PrettyOutput, OutputType
85
+ # 执行中打印信息
86
+ PrettyOutput.print("正在处理数据...", OutputType.INFO)
87
+ # 成功信息
88
+ PrettyOutput.print("操作成功完成", OutputType.SUCCESS)
89
+ # 警告信息
90
+ PrettyOutput.print("发现潜在问题", OutputType.WARNING)
91
+ # 错误信息
92
+ PrettyOutput.print("操作失败", OutputType.ERROR)
93
+ ```
94
+ 2. **结构化返回结果**:工具应该始终返回结构化的结果字典,包含以下字段:
95
+ - success: 布尔值,表示操作是否成功
96
+ - stdout: 字符串,包含工具的主要输出内容
97
+ - stderr: 字符串,包含错误信息(如果有)
98
+ 3. **异常处理**:工具应该妥善处理可能发生的异常,并在失败时清理已创建的资源
99
+ ```python
100
+ try:
101
+ # 执行逻辑
102
+ return {{
103
+ "success": True,
104
+ "stdout": "成功结果",
105
+ "stderr": ""
106
+ }}
107
+ except Exception as e:
108
+ PrettyOutput.print(f"操作失败: {{str(e)}}", OutputType.ERROR)
109
+ # 清理资源(如果有创建)
110
+ return {{
111
+ "success": False,
112
+ "stdout": "",
113
+ "stderr": f"操作失败: {{str(e)}}"
114
+ }}
115
+ ```
116
+ </tool_requirements>
117
+ <methodology_requirements>
118
+ 方法论格式要求:
119
+ 1. 问题重述: 简明扼要的问题归纳,不含特定细节
120
+ 2. 最优解决方案: 经过用户验证的、最终有效的解决方案(将每个步骤要使用的工具也列举出来)
121
+ 3. 注意事项: 执行中可能遇到的常见问题和注意点,尤其是用户指出的问题
122
+ 4. 可选步骤: 对于有多种解决路径的问题,标注出可选步骤和适用场景
123
+ </methodology_requirements>
124
+ <output_requirements>
125
+ 根据分析结果,输出以下三种情况之一:
126
+ 1. 如果现有工具/方法论可以解决,直接输出说明:
127
+ 已有工具/方法论可以解决该问题,无需创建新内容。
128
+ 可用的工具/方法论:[列出工具名称或方法论名称]
129
+ 使用方法:[简要说明如何使用]
130
+ 2. 工具创建(如果需要创建新工具):
131
+ {ot("TOOL_CALL")}
132
+ want: 创建新工具来解决XXX问题
133
+ name: generate_new_tool
134
+ arguments:
135
+ tool_name: 工具名称
136
+ tool_code: |2
137
+ # -*- coding: utf-8 -*-
138
+ from typing import Dict, Any
139
+ from jarvis.jarvis_utils.output import PrettyOutput, OutputType
140
+ class 工具名称:
141
+ name = "工具名称"
142
+ description = "Tool for text transformation"
143
+ Tool description
144
+ 适用场景:1. 格式化文本; 2. 处理标题; 3. 标准化输出
145
+ \"\"\"
146
+ parameters = {{
147
+ "type": "object",
148
+ "properties": {{
149
+ # 参数定义
150
+ }},
151
+ "required": []
152
+ }}
153
+ @staticmethod
154
+ def check() -> bool:
155
+ return True
156
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
157
+ try:
158
+ # 使用PrettyOutput显示执行过程
159
+ PrettyOutput.print("开始执行操作...", OutputType.INFO)
160
+ # 实现逻辑
161
+ # ...
162
+ PrettyOutput.print("操作已完成", OutputType.SUCCESS)
163
+ return {{
164
+ "success": True,
165
+ "stdout": "结果输出",
166
+ "stderr": ""
167
+ }}
168
+ except Exception as e:
169
+ PrettyOutput.print(f"操作失败: {{str(e)}}", OutputType.ERROR)
170
+ return {{
171
+ "success": False,
172
+ "stdout": "",
173
+ "stderr": f"操作失败: {{str(e)}}"
174
+ }}
175
+ {ct("TOOL_CALL")}
176
+ 3. 方法论创建(如果需要创建新方法论):
177
+ {ot("TOOL_CALL")}
178
+ want: 添加/更新xxxx的方法论
179
+ name: methodology
180
+ arguments:
181
+ operation: add/update
182
+ problem_type: 方法论类型,不要过于细节,也不要过于泛化
183
+ content: |2
184
+ 方法论内容
185
+ {ct("TOOL_CALL")}
186
+ 如果以上三种情况都不适用,则直接输出原因分析,不要使用工具调用格式。
187
+ </output_requirements>
188
+ </task_analysis>"""
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+ from typing import Any, Protocol, Tuple
3
+
4
+
5
+ class OutputHandlerProtocol(Protocol):
6
+ """
7
+ Defines the interface for an output handler, which is responsible for
8
+ processing the model's response, typically to execute a tool.
9
+ """
10
+
11
+ def name(self) -> str:
12
+ """Returns the name of the handler."""
13
+ ...
14
+
15
+ def can_handle(self, response: str) -> bool:
16
+ """Determines if this handler can process the given response."""
17
+ ...
18
+
19
+ def prompt(self) -> str:
20
+ """Returns the prompt snippet that describes the handler's functionality."""
21
+ ...
22
+
23
+ def handle(self, response: str, agent: Any) -> Tuple[bool, Any]:
24
+ """
25
+ Handles the response, executing the associated logic.
26
+
27
+ Returns:
28
+ A tuple containing a boolean (whether to return) and the result.
29
+ """
30
+ ...