tool.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. """
  2. Goal 工具 - 计划管理
  3. 提供 goal 工具供 LLM 管理执行计划。
  4. """
  5. from typing import Optional, List, TYPE_CHECKING
  6. if TYPE_CHECKING:
  7. from agent.goal.models import GoalTree
  8. def goal_tool(
  9. tree: "GoalTree",
  10. add: Optional[str] = None,
  11. done: Optional[str] = None,
  12. abandon: Optional[str] = None,
  13. focus: Optional[str] = None,
  14. ) -> str:
  15. """
  16. 管理执行计划。
  17. Args:
  18. tree: GoalTree 实例
  19. add: 添加目标(逗号分隔多个)。添加到当前 focus 的 goal 下作为子目标。
  20. done: 完成当前目标,值为 summary
  21. abandon: 放弃当前目标,值为原因
  22. focus: 切换焦点到指定内部 id
  23. Returns:
  24. 更新后的计划状态文本
  25. """
  26. changes = []
  27. # 1. 处理 abandon(先处理,因为可能需要在 add 新目标前放弃旧的)
  28. if abandon is not None:
  29. if not tree.current_id:
  30. return "错误:没有当前目标可以放弃"
  31. goal = tree.abandon(tree.current_id, abandon)
  32. display_id = tree._generate_display_id(goal)
  33. changes.append(f"已放弃: {display_id}. {goal.description}")
  34. # 2. 处理 done
  35. if done is not None:
  36. if not tree.current_id:
  37. return "错误:没有当前目标可以完成"
  38. goal = tree.complete(tree.current_id, done)
  39. display_id = tree._generate_display_id(goal)
  40. changes.append(f"已完成: {display_id}. {goal.description}")
  41. # 检查是否有级联完成的父目标
  42. if goal.parent_id:
  43. parent = tree.find(goal.parent_id)
  44. if parent and parent.status == "completed":
  45. parent_display_id = tree._generate_display_id(parent)
  46. changes.append(f"自动完成: {parent_display_id}. {parent.description}(所有子目标已完成)")
  47. # 3. 处理 focus(在 add 之前,这样 add 可以添加到新焦点下)
  48. if focus is not None:
  49. # focus 参数可以是内部 ID 或显示 ID
  50. # 先尝试作为内部 ID 查找
  51. goal = tree.find(focus)
  52. # 如果找不到,尝试根据显示 ID 查找
  53. if not goal:
  54. # 通过遍历所有 goal 查找匹配的显示 ID
  55. for g in tree.goals:
  56. if tree._generate_display_id(g) == focus:
  57. goal = g
  58. break
  59. if not goal:
  60. return f"错误:找不到目标 {focus}"
  61. tree.focus(goal.id)
  62. display_id = tree._generate_display_id(goal)
  63. changes.append(f"切换焦点: {display_id}. {goal.description}")
  64. # 4. 处理 add
  65. if add is not None:
  66. descriptions = [d.strip() for d in add.split(",") if d.strip()]
  67. if descriptions:
  68. # 添加到当前焦点下(如果有焦点),否则添加到顶层
  69. parent_id = tree.current_id
  70. new_goals = tree.add_goals(descriptions, parent_id=parent_id)
  71. if parent_id:
  72. parent_display_id = tree._generate_display_id(tree.find(parent_id))
  73. changes.append(f"在 {parent_display_id} 下添加 {len(new_goals)} 个子目标")
  74. else:
  75. changes.append(f"添加 {len(new_goals)} 个顶层目标")
  76. # 如果没有焦点且添加了目标,自动 focus 到第一个新目标
  77. if not tree.current_id and new_goals:
  78. tree.focus(new_goals[0].id)
  79. display_id = tree._generate_display_id(new_goals[0])
  80. changes.append(f"自动切换焦点: {display_id}")
  81. # 返回当前状态
  82. result = []
  83. if changes:
  84. result.append("## 更新")
  85. result.extend(f"- {c}" for c in changes)
  86. result.append("")
  87. result.append("## Current Plan")
  88. result.append(tree.to_prompt())
  89. return "\n".join(result)
  90. def create_goal_tool_schema() -> dict:
  91. """创建 goal 工具的 JSON Schema"""
  92. return {
  93. "name": "goal",
  94. "description": """管理执行计划。
  95. - add: 添加目标(逗号分隔多个)。添加到当前 focus 的 goal 下作为子目标。
  96. - done: 完成当前目标,值为 summary
  97. - abandon: 放弃当前目标,值为原因(会触发 context 压缩)
  98. - focus: 切换焦点到指定 id(可以是内部 ID 或显示 ID)
  99. 示例:
  100. - goal(add="分析代码, 实现功能, 测试") - 添加顶层目标
  101. - goal(focus="2", add="设计接口, 实现代码") - 切换到目标2,并添加子目标
  102. - goal(done="发现用户模型在 models/user.py") - 完成当前目标
  103. - goal(abandon="方案A需要Redis,环境没有", add="实现方案B") - 放弃当前并添加新目标
  104. 注意:内部 ID 是纯自增数字("1", "2", "3"),显示 ID 是带层级的("1", "2.1", "2.2")。
  105. focus 参数可以使用任意格式的 ID。
  106. """,
  107. "parameters": {
  108. "type": "object",
  109. "properties": {
  110. "add": {
  111. "type": "string",
  112. "description": "添加目标(逗号分隔多个)。添加到当前 focus 的 goal 下作为子目标。"
  113. },
  114. "done": {
  115. "type": "string",
  116. "description": "完成当前目标,值为 summary"
  117. },
  118. "abandon": {
  119. "type": "string",
  120. "description": "放弃当前目标,值为原因"
  121. },
  122. "focus": {
  123. "type": "string",
  124. "description": "切换焦点到指定 goal id(可以是内部 ID 或显示 ID)"
  125. }
  126. },
  127. "required": []
  128. }
  129. }