mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-04-25 11:18:22 +00:00
* feat(agent): 为AgentConfig添加skills字段并更新lead_agent系统提示 在AgentConfig中添加skills字段以支持配置agent可用技能 更新lead_agent的系统提示模板以包含可用技能信息 * fix: resolve agent skill configuration edge cases and add tests * Update backend/packages/harness/deerflow/agents/lead_agent/prompt.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor(agent): address PR review comments for skills configuration - Add detailed docstring to `skills` field in `AgentConfig` to clarify the semantics of `None` vs `[]`. - Add unit tests in `test_custom_agent.py` to verify `load_agent_config()` correctly parses omitted skills and explicit empty lists. - Fix `test_make_lead_agent_empty_skills_passed_correctly` to include `agent_name` in the runtime config, ensuring it exercises the real code path. * docs: 添加关于按代理过滤技能的配置说明 在配置示例文件和文档中添加说明,解释如何通过代理的config.yaml文件限制加载的技能 --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
97 lines
3.9 KiB
Python
97 lines
3.9 KiB
Python
from pathlib import Path
|
|
|
|
from deerflow.agents.lead_agent.prompt import get_skills_prompt_section
|
|
from deerflow.config.agents_config import AgentConfig
|
|
from deerflow.skills.types import Skill
|
|
|
|
|
|
def _make_skill(name: str) -> Skill:
|
|
return Skill(
|
|
name=name,
|
|
description=f"Description for {name}",
|
|
license="MIT",
|
|
skill_dir=Path(f"/tmp/{name}"),
|
|
skill_file=Path(f"/tmp/{name}/SKILL.md"),
|
|
relative_path=Path(name),
|
|
category="public",
|
|
enabled=True,
|
|
)
|
|
|
|
|
|
def test_get_skills_prompt_section_returns_empty_when_no_skills_match(monkeypatch):
|
|
skills = [_make_skill("skill1"), _make_skill("skill2")]
|
|
monkeypatch.setattr("deerflow.agents.lead_agent.prompt.load_skills", lambda enabled_only: skills)
|
|
|
|
result = get_skills_prompt_section(available_skills={"non_existent_skill"})
|
|
assert result == ""
|
|
|
|
|
|
def test_get_skills_prompt_section_returns_empty_when_available_skills_empty(monkeypatch):
|
|
skills = [_make_skill("skill1"), _make_skill("skill2")]
|
|
monkeypatch.setattr("deerflow.agents.lead_agent.prompt.load_skills", lambda enabled_only: skills)
|
|
|
|
result = get_skills_prompt_section(available_skills=set())
|
|
assert result == ""
|
|
|
|
|
|
def test_get_skills_prompt_section_returns_skills(monkeypatch):
|
|
skills = [_make_skill("skill1"), _make_skill("skill2")]
|
|
monkeypatch.setattr("deerflow.agents.lead_agent.prompt.load_skills", lambda enabled_only: skills)
|
|
|
|
result = get_skills_prompt_section(available_skills={"skill1"})
|
|
assert "skill1" in result
|
|
assert "skill2" not in result
|
|
|
|
|
|
def test_get_skills_prompt_section_returns_all_when_available_skills_is_none(monkeypatch):
|
|
skills = [_make_skill("skill1"), _make_skill("skill2")]
|
|
monkeypatch.setattr("deerflow.agents.lead_agent.prompt.load_skills", lambda enabled_only: skills)
|
|
|
|
result = get_skills_prompt_section(available_skills=None)
|
|
assert "skill1" in result
|
|
assert "skill2" in result
|
|
|
|
|
|
def test_make_lead_agent_empty_skills_passed_correctly(monkeypatch):
|
|
from unittest.mock import MagicMock
|
|
|
|
from deerflow.agents.lead_agent import agent as lead_agent_module
|
|
|
|
# Mock dependencies
|
|
monkeypatch.setattr(lead_agent_module, "get_app_config", lambda: MagicMock())
|
|
monkeypatch.setattr(lead_agent_module, "_resolve_model_name", lambda x=None: "default-model")
|
|
monkeypatch.setattr(lead_agent_module, "create_chat_model", lambda **kwargs: "model")
|
|
monkeypatch.setattr("deerflow.tools.get_available_tools", lambda **kwargs: [])
|
|
monkeypatch.setattr(lead_agent_module, "_build_middlewares", lambda *args, **kwargs: [])
|
|
monkeypatch.setattr(lead_agent_module, "create_agent", lambda **kwargs: kwargs)
|
|
|
|
class MockModelConfig:
|
|
supports_thinking = False
|
|
|
|
mock_app_config = MagicMock()
|
|
mock_app_config.get_model_config.return_value = MockModelConfig()
|
|
monkeypatch.setattr(lead_agent_module, "get_app_config", lambda: mock_app_config)
|
|
|
|
captured_skills = []
|
|
|
|
def mock_apply_prompt_template(**kwargs):
|
|
captured_skills.append(kwargs.get("available_skills"))
|
|
return "mock_prompt"
|
|
|
|
monkeypatch.setattr(lead_agent_module, "apply_prompt_template", mock_apply_prompt_template)
|
|
|
|
# Case 1: Empty skills list
|
|
monkeypatch.setattr(lead_agent_module, "load_agent_config", lambda x: AgentConfig(name="test", skills=[]))
|
|
lead_agent_module.make_lead_agent({"configurable": {"agent_name": "test"}})
|
|
assert captured_skills[-1] == set()
|
|
|
|
# Case 2: None skills list
|
|
monkeypatch.setattr(lead_agent_module, "load_agent_config", lambda x: AgentConfig(name="test", skills=None))
|
|
lead_agent_module.make_lead_agent({"configurable": {"agent_name": "test"}})
|
|
assert captured_skills[-1] is None
|
|
|
|
# Case 3: Some skills list
|
|
monkeypatch.setattr(lead_agent_module, "load_agent_config", lambda x: AgentConfig(name="test", skills=["skill1"]))
|
|
lead_agent_module.make_lead_agent({"configurable": {"agent_name": "test"}})
|
|
assert captured_skills[-1] == {"skill1"}
|