fix: skills 路由两个小修复
skills.py:
- update_curator_config 直接 await get_curator_config() 报错
('Depends' object has no attribute 'skill_evolution')。FastAPI 路由
默认参数 Depends(...) 只在请求时被框架解析,直接调用拿到的是依赖标记。
抽出 _build_curator_config_response(config) 让 GET 和 PUT 共用。
skill_manage_tool.py:
- 模型把 action='list' 当成可用动作误调 skill_manage 报
Unsupported action。补两个 read-only 别名 list/view,分别委派到
skill_list_tool 和 skill_view_tool,docstring 同步更新。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
c63811367e
commit
f5bc02d598
2 files changed
+37
-17
No files matched your search
@@ -608,21 +608,26 @@ class CuratorLogsResponse(BaseModel):
|
||||
last_run_at: str | None
|
||||
|
||||
|
||||
def _build_curator_config_response(config: AppConfig) -> CuratorConfigResponse:
|
||||
"""Pure helper so both the GET route and the post-PUT refresh share one shape."""
|
||||
evo = config.skill_evolution
|
||||
return CuratorConfigResponse(
|
||||
enabled=evo.enabled,
|
||||
moderation_model_name=evo.moderation_model_name,
|
||||
curator=CuratorSubConfig(
|
||||
enabled=evo.curator.enabled,
|
||||
interval_hours=evo.curator.interval_hours,
|
||||
stale_after_days=evo.curator.stale_after_days,
|
||||
archive_after_days=evo.curator.archive_after_days,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@router.get("/curator/config", response_model=CuratorConfigResponse, summary="Get Skill Evolution Config")
|
||||
async def get_curator_config(config: AppConfig = Depends(get_config)) -> CuratorConfigResponse:
|
||||
"""Return the current effective skill_evolution config (yaml defaults + skill_evolution.json overrides)."""
|
||||
try:
|
||||
evo = config.skill_evolution
|
||||
return CuratorConfigResponse(
|
||||
enabled=evo.enabled,
|
||||
moderation_model_name=evo.moderation_model_name,
|
||||
curator=CuratorSubConfig(
|
||||
enabled=evo.curator.enabled,
|
||||
interval_hours=evo.curator.interval_hours,
|
||||
stale_after_days=evo.curator.stale_after_days,
|
||||
archive_after_days=evo.curator.archive_after_days,
|
||||
),
|
||||
)
|
||||
return _build_curator_config_response(config)
|
||||
except Exception as e:
|
||||
logger.error("Failed to read curator config: %s", e, exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=f"Failed to read curator config: {str(e)}")
|
||||
@@ -636,6 +641,7 @@ async def update_curator_config(body: CuratorConfigRequest) -> CuratorConfigResp
|
||||
fields are rejected by the Pydantic model_validate call.
|
||||
"""
|
||||
try:
|
||||
from deerflow.config.app_config import get_app_config, reset_app_config
|
||||
from deerflow.config.skill_evolution_config import SkillEvolutionConfig
|
||||
from deerflow.config.skill_evolution_runtime import save_overrides
|
||||
|
||||
@@ -644,13 +650,12 @@ async def update_curator_config(body: CuratorConfigRequest) -> CuratorConfigResp
|
||||
SkillEvolutionConfig.model_validate(payload)
|
||||
save_overrides(payload)
|
||||
|
||||
# Force the next get_app_config() call to pick up the new overrides.
|
||||
# mtime check inside get_app_config() will trigger reload automatically,
|
||||
# but resetting here makes the response below reflect the new state.
|
||||
from deerflow.config.app_config import reset_app_config
|
||||
# Reset cache so the next get_app_config() picks up the new overrides
|
||||
# (the mtime check would catch it too, but resetting makes the response
|
||||
# below deterministically reflect the new state).
|
||||
reset_app_config()
|
||||
|
||||
return await get_curator_config()
|
||||
fresh_config = get_app_config()
|
||||
return _build_curator_config_response(fresh_config)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
|
||||
@@ -78,6 +78,10 @@ async def _skill_manage_impl(
|
||||
|
||||
Args:
|
||||
action: One of create, patch, edit, delete, write_file, remove_file.
|
||||
For listing or viewing skills, prefer the dedicated
|
||||
``skill_list`` / ``skill_view`` tools — but ``action='list'``
|
||||
and ``action='view'`` are accepted here as convenience
|
||||
aliases that delegate to those tools.
|
||||
name: Skill name in hyphen-case.
|
||||
content: New file content for create, edit, or write_file.
|
||||
path: Supporting file path for write_file or remove_file.
|
||||
@@ -85,6 +89,17 @@ async def _skill_manage_impl(
|
||||
replace: Replacement text for patch.
|
||||
expected_count: Optional expected number of replacements for patch.
|
||||
"""
|
||||
# Read-only aliases — delegate to the dedicated tools so a model that
|
||||
# over-uses skill_manage doesn't trip on Unsupported action errors.
|
||||
if action == "list":
|
||||
from deerflow.tools.builtins.skill_tools import skill_list_tool
|
||||
|
||||
return await _to_thread(skill_list_tool.invoke, {})
|
||||
if action == "view":
|
||||
from deerflow.tools.builtins.skill_tools import skill_view_tool
|
||||
|
||||
return await _to_thread(skill_view_tool.invoke, {"name": name})
|
||||
|
||||
name = SkillStorage.validate_skill_name(name)
|
||||
lock = _get_lock(name)
|
||||
thread_id = _get_thread_id(runtime)
|
||||
|
||||
Reference in new issue
Block a user