""" Agent Presets - Agent 类型预设配置 定义不同类型 Agent 的工具权限和运行参数。 用户可通过 .agent/presets.json 覆盖或添加预设。 """ from dataclasses import dataclass, field from typing import Optional, List from pathlib import Path @dataclass class AgentPreset: """Agent 预设配置""" # 工具权限 allowed_tools: Optional[List[str]] = None # None 表示允许全部 denied_tools: Optional[List[str]] = None # 黑名单 # 运行参数 max_iterations: int = 30 temperature: Optional[float] = None # System Prompt(完全自定义 system prompt;None = 使用默认模板 + skills) system_prompt: Optional[str] = None # Skills(注入 system prompt 的 skill 名称列表;None = 加载全部) skills: Optional[List[str]] = None # 描述 description: Optional[str] = None # 内置预设 _DEFAULT_SKILLS = ["planning", "research", "browser"] AGENT_PRESETS = { "default": AgentPreset( allowed_tools=None, max_iterations=30, skills=_DEFAULT_SKILLS, description="默认 Agent,拥有全部工具权限", ), "delegate": AgentPreset( allowed_tools=None, max_iterations=30, skills=_DEFAULT_SKILLS, description="委托子 Agent,拥有全部工具权限(由 agent 工具创建)", ), "explore": AgentPreset( allowed_tools=["read", "glob", "grep", "list_files"], denied_tools=["write", "edit", "bash", "task"], max_iterations=15, skills=["planning"], description="探索型 Agent,只读权限,用于代码分析", ), "evaluate": AgentPreset( allowed_tools=["read_file", "grep_content", "glob_files", "goal"], max_iterations=10, skills=["planning"], description="评估型 Agent,只读权限,用于结果评估", ), } def get_preset(name: str) -> AgentPreset: """获取预设配置""" if name not in AGENT_PRESETS: raise ValueError(f"Unknown preset: {name}. Available: {list(AGENT_PRESETS.keys())}") return AGENT_PRESETS[name] def register_preset(name: str, preset: AgentPreset) -> None: """注册自定义预设""" AGENT_PRESETS[name] = preset def load_system_prompt_from_file(path: str) -> str: """ 从 .prompt 文件加载 system prompt Args: path: .prompt 文件路径(相对或绝对) Returns: system prompt 文本 Raises: FileNotFoundError: 文件不存在 ValueError: 文件格式错误或缺少 $system$ 分节 """ from agent.llm.prompts import load_prompt prompt_path = Path(path) if not prompt_path.is_absolute(): # 相对路径:相对于当前工作目录 prompt_path = Path.cwd() / prompt_path config, messages = load_prompt(prompt_path) if "system" not in messages: raise ValueError(f".prompt 文件缺少 $system$ 分节: {path}") return messages["system"] def load_presets_from_json(json_path: str) -> None: """ 从 JSON 文件加载预设配置 支持特殊字段: - system_prompt_file: 从 .prompt 文件加载 system prompt(相对于 JSON 文件所在目录) Args: json_path: presets.json 文件路径 """ import json json_path = Path(json_path) if not json_path.exists(): raise FileNotFoundError(f"presets.json 不存在: {json_path}") with open(json_path, "r", encoding="utf-8") as f: presets_data = json.load(f) base_dir = json_path.parent for name, cfg in presets_data.items(): # 处理 system_prompt_file if "system_prompt_file" in cfg: prompt_file = cfg.pop("system_prompt_file") prompt_path = base_dir / prompt_file cfg["system_prompt"] = load_system_prompt_from_file(str(prompt_path)) preset = AgentPreset(**cfg) register_preset(name, preset)