presets.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. """
  2. Agent Presets - Agent 类型预设配置
  3. 定义不同类型 Agent 的工具权限和运行参数。
  4. 用户可通过 .agent/presets.json 覆盖或添加预设。
  5. """
  6. from dataclasses import dataclass, field
  7. from typing import Optional, List
  8. from pathlib import Path
  9. @dataclass
  10. class AgentPreset:
  11. """Agent 预设配置"""
  12. # 工具权限
  13. allowed_tools: Optional[List[str]] = None # None 表示允许全部
  14. denied_tools: Optional[List[str]] = None # 黑名单
  15. # 运行参数
  16. max_iterations: int = 30
  17. temperature: Optional[float] = None
  18. # System Prompt(完全自定义 system prompt;None = 使用默认模板 + skills)
  19. system_prompt: Optional[str] = None
  20. # Skills(注入 system prompt 的 skill 名称列表;None = 加载全部)
  21. skills: Optional[List[str]] = None
  22. # 描述
  23. description: Optional[str] = None
  24. # 内置预设
  25. _DEFAULT_SKILLS = ["planning", "research", "browser"]
  26. AGENT_PRESETS = {
  27. "default": AgentPreset(
  28. allowed_tools=None,
  29. max_iterations=30,
  30. skills=_DEFAULT_SKILLS,
  31. description="默认 Agent,拥有全部工具权限",
  32. ),
  33. "delegate": AgentPreset(
  34. allowed_tools=None,
  35. max_iterations=30,
  36. skills=_DEFAULT_SKILLS,
  37. description="委托子 Agent,拥有全部工具权限(由 agent 工具创建)",
  38. ),
  39. "explore": AgentPreset(
  40. allowed_tools=["read", "glob", "grep", "list_files"],
  41. denied_tools=["write", "edit", "bash", "task"],
  42. max_iterations=15,
  43. skills=["planning"],
  44. description="探索型 Agent,只读权限,用于代码分析",
  45. ),
  46. "evaluate": AgentPreset(
  47. allowed_tools=["read_file", "grep_content", "glob_files", "goal"],
  48. max_iterations=10,
  49. skills=["planning"],
  50. description="评估型 Agent,只读权限,用于结果评估",
  51. ),
  52. }
  53. def get_preset(name: str) -> AgentPreset:
  54. """获取预设配置"""
  55. if name not in AGENT_PRESETS:
  56. raise ValueError(f"Unknown preset: {name}. Available: {list(AGENT_PRESETS.keys())}")
  57. return AGENT_PRESETS[name]
  58. def register_preset(name: str, preset: AgentPreset) -> None:
  59. """注册自定义预设"""
  60. AGENT_PRESETS[name] = preset
  61. def load_system_prompt_from_file(path: str) -> str:
  62. """
  63. 从 .prompt 文件加载 system prompt
  64. Args:
  65. path: .prompt 文件路径(相对或绝对)
  66. Returns:
  67. system prompt 文本
  68. Raises:
  69. FileNotFoundError: 文件不存在
  70. ValueError: 文件格式错误或缺少 $system$ 分节
  71. """
  72. from agent.llm.prompts import load_prompt
  73. prompt_path = Path(path)
  74. if not prompt_path.is_absolute():
  75. # 相对路径:相对于当前工作目录
  76. prompt_path = Path.cwd() / prompt_path
  77. config, messages = load_prompt(prompt_path)
  78. if "system" not in messages:
  79. raise ValueError(f".prompt 文件缺少 $system$ 分节: {path}")
  80. return messages["system"]
  81. def load_presets_from_json(json_path: str) -> None:
  82. """
  83. 从 JSON 文件加载预设配置
  84. 支持特殊字段:
  85. - system_prompt_file: 从 .prompt 文件加载 system prompt(相对于 JSON 文件所在目录)
  86. Args:
  87. json_path: presets.json 文件路径
  88. """
  89. import json
  90. json_path = Path(json_path)
  91. if not json_path.exists():
  92. raise FileNotFoundError(f"presets.json 不存在: {json_path}")
  93. with open(json_path, "r", encoding="utf-8") as f:
  94. presets_data = json.load(f)
  95. base_dir = json_path.parent
  96. for name, cfg in presets_data.items():
  97. # 处理 system_prompt_file
  98. if "system_prompt_file" in cfg:
  99. prompt_file = cfg.pop("system_prompt_file")
  100. prompt_path = base_dir / prompt_file
  101. cfg["system_prompt"] = load_system_prompt_from_file(str(prompt_path))
  102. preset = AgentPreset(**cfg)
  103. register_preset(name, preset)