mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-07-21 10:15:47 +00:00
fix(skills): reuse the resolved app config in the no-arg skills prompt section (#4160)
get_skills_prompt_section() without app_config resolved get_app_config() only to read container_path, then let the enabled-skills load fall back to the warm cache. On a cold start the cache is empty and the first call returns an empty skills list while the synchronously-loaded disabled section is populated, so manually assembled agents (create_deerflow_agent style integrations) got a prompt with no enabled skills. Rebind the resolved config so the storage and enabled-skills loads below use it too; when no config is resolvable the cache-only fallback is unchanged. Adds a cold-cache regression test. Fixes #4144 Co-authored-by: fancyboi999 <fancyboi999@users.noreply.github.com>
This commit is contained in:
co-authored by
fancyboi999
parent
e7e9c51988
commit
16919f7c52
@@ -805,10 +805,16 @@ def get_skills_prompt_section(
|
||||
try:
|
||||
from deerflow.config import get_app_config
|
||||
|
||||
config = get_app_config()
|
||||
container_base_path = config.skills.container_path
|
||||
skill_evolution_enabled = config.skill_evolution.enabled
|
||||
# Rebind so the storage/enabled-skills loads below use this resolved
|
||||
# config too. Reading only container_path here and then letting
|
||||
# get_enabled_skills_for_config(None) fall back to the warm cache
|
||||
# rendered an empty enabled-skills list on a cold start while the
|
||||
# synchronously-loaded disabled section was populated (#4144).
|
||||
app_config = get_app_config()
|
||||
container_base_path = app_config.skills.container_path
|
||||
skill_evolution_enabled = app_config.skill_evolution.enabled
|
||||
except Exception:
|
||||
app_config = None
|
||||
container_base_path = DEFAULT_SKILLS_CONTAINER_PATH
|
||||
skill_evolution_enabled = False
|
||||
else:
|
||||
|
||||
@@ -11,7 +11,7 @@ class NamedTool:
|
||||
self.name = name
|
||||
|
||||
|
||||
def _make_skill(name: str, allowed_tools: list[str] | None = None) -> Skill:
|
||||
def _make_skill(name: str, allowed_tools: list[str] | None = None, *, enabled: bool = True) -> Skill:
|
||||
return Skill(
|
||||
name=name,
|
||||
description=f"Description for {name}",
|
||||
@@ -21,7 +21,7 @@ def _make_skill(name: str, allowed_tools: list[str] | None = None) -> Skill:
|
||||
relative_path=Path(name),
|
||||
category="public",
|
||||
allowed_tools=tuple(allowed_tools) if allowed_tools is not None else None,
|
||||
enabled=True,
|
||||
enabled=enabled,
|
||||
)
|
||||
|
||||
|
||||
@@ -80,6 +80,36 @@ def test_get_skills_prompt_section_returns_all_when_available_skills_is_none(mon
|
||||
assert "skill2" in result
|
||||
|
||||
|
||||
def test_get_skills_prompt_section_no_arg_cold_cache_loads_enabled_skills(monkeypatch):
|
||||
"""#4144: a fresh process calling the no-arg helper must not render an empty
|
||||
enabled-skills list while the synchronously-loaded disabled section is populated."""
|
||||
import threading
|
||||
|
||||
from deerflow.agents.lead_agent import prompt as prompt_mod
|
||||
|
||||
skills = [_make_skill("skill1"), _make_skill("skill2", enabled=False)]
|
||||
mock_storage = SimpleNamespace(load_skills=lambda *, enabled_only: [s for s in skills if s.enabled or not enabled_only])
|
||||
monkeypatch.setattr("deerflow.agents.lead_agent.prompt.get_or_new_skill_storage", lambda **kwargs: mock_storage)
|
||||
monkeypatch.setattr("deerflow.agents.lead_agent.prompt.get_or_new_user_skill_storage", lambda user_id, **kwargs: mock_storage)
|
||||
monkeypatch.setattr(
|
||||
"deerflow.config.get_app_config",
|
||||
lambda: SimpleNamespace(
|
||||
skills=SimpleNamespace(container_path="/mnt/skills", use="deerflow.skills.storage.local_skill_storage:LocalSkillStorage", get_skills_path=lambda: Path("/tmp/skills")),
|
||||
skill_evolution=SimpleNamespace(enabled=False),
|
||||
),
|
||||
)
|
||||
# Cold cache: no warmed enabled-skills list, and the background refresh must
|
||||
# not fill it mid-test — the reporter's cold start loses exactly this race.
|
||||
monkeypatch.setattr(prompt_mod, "_enabled_skills_cache", None)
|
||||
monkeypatch.setattr(prompt_mod, "_ensure_enabled_skills_cache", lambda: threading.Event())
|
||||
|
||||
result = get_skills_prompt_section(available_skills=None)
|
||||
|
||||
assert "<available_skills>" in result
|
||||
assert "skill1" in result
|
||||
assert "<disabled_skills>" in result
|
||||
|
||||
|
||||
def test_get_skills_prompt_section_includes_slash_activation_guidance(monkeypatch):
|
||||
skills = [_make_skill("data-analysis")]
|
||||
monkeypatch.setattr("deerflow.agents.lead_agent.prompt._get_enabled_skills", lambda: skills)
|
||||
|
||||
Reference in New Issue
Block a user