presets.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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. # 默认不预置 skills,项目按需在 presets.json 或 RunConfig.skills 中指定
  26. AGENT_PRESETS = {
  27. "default": AgentPreset(
  28. allowed_tools=None,
  29. max_iterations=30,
  30. skills=[],
  31. description="默认 Agent,拥有全部工具权限",
  32. ),
  33. "delegate": AgentPreset(
  34. allowed_tools=None,
  35. max_iterations=30,
  36. 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=[],
  44. description="探索型 Agent,只读权限,用于代码分析",
  45. ),
  46. "evaluate": AgentPreset(
  47. allowed_tools=["read_file", "grep_content", "glob_files", "goal"],
  48. max_iterations=10,
  49. skills=[],
  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. - prompt_vars: 变量字典,用于替换 prompt 中的 %variable% 占位符
  87. Args:
  88. json_path: presets.json 文件路径
  89. """
  90. import json
  91. json_path = Path(json_path)
  92. if not json_path.exists():
  93. raise FileNotFoundError(f"presets.json 不存在: {json_path}")
  94. with open(json_path, "r", encoding="utf-8") as f:
  95. presets_data = json.load(f)
  96. base_dir = json_path.parent
  97. for name, cfg in presets_data.items():
  98. # 提取 prompt_vars(不传给 AgentPreset)
  99. prompt_vars = cfg.pop("prompt_vars", None)
  100. # 处理 system_prompt_file
  101. if "system_prompt_file" in cfg:
  102. prompt_file = cfg.pop("system_prompt_file")
  103. prompt_path = base_dir / prompt_file
  104. system_prompt = load_system_prompt_from_file(str(prompt_path))
  105. # 应用变量替换
  106. if prompt_vars and isinstance(prompt_vars, dict):
  107. for var_name, var_value in prompt_vars.items():
  108. placeholder = f"%{var_name}%"
  109. if placeholder in system_prompt:
  110. system_prompt = system_prompt.replace(placeholder, str(var_value))
  111. cfg["system_prompt"] = system_prompt
  112. preset = AgentPreset(**cfg)
  113. register_preset(name, preset)