fix: BotSettingsResponse.skills 改为 list 类型,修复 settings 接口 500

The /api/v1/general-agent/settings endpoint returned HTTP 500 because
config/general_agent.json stores skills as a list while the response
model expected Optional[str]. Add _normalize_skills_list and apply it in
both get_general_agent_settings_api and get_bot_settings so list and
legacy comma-separated string inputs both yield a list output.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
朱潮 2026-06-23 10:11:19 +08:00
parent 6f2af8ecbf
commit 6835003d15

View File

@ -27,6 +27,15 @@ router = APIRouter()
# ============== 辅助函数 ============== # ============== 辅助函数 ==============
def _normalize_skills_list(value) -> List[str]:
"""Normalize skills value (list or comma-separated str) to a list of strings."""
if not value:
return []
if isinstance(value, str):
return [s.strip() for s in value.split(',') if s.strip()]
return list(value)
def copy_skills_folder(source_bot_id: str, target_bot_id: str) -> bool: def copy_skills_folder(source_bot_id: str, target_bot_id: str) -> bool:
""" """
复制智能体的 skills 文件夹 复制智能体的 skills 文件夹
@ -547,7 +556,7 @@ class BotSettingsUpdate(BaseModel):
enable_memori: Optional[bool] = None enable_memori: Optional[bool] = None
enable_thinking: Optional[bool] = None enable_thinking: Optional[bool] = None
tool_response: Optional[bool] = None tool_response: Optional[bool] = None
skills: Optional[str] = None skills: Optional[List[str]] = None
is_published: Optional[bool] = None # 是否发布到广场 is_published: Optional[bool] = None # 是否发布到广场
shell_env: Optional[dict] = None # 自定义 shell 环境变量 shell_env: Optional[dict] = None # 自定义 shell 环境变量
voice_speaker: Optional[str] = None # 语音音色 voice_speaker: Optional[str] = None # 语音音色
@ -591,7 +600,7 @@ class BotSettingsResponse(BaseModel):
enable_memori: bool enable_memori: bool
enable_thinking: bool enable_thinking: bool
tool_response: bool tool_response: bool
skills: Optional[str] skills: Optional[List[str]]
shell_env: Optional[dict] = None # 自定义 shell 环境变量 shell_env: Optional[dict] = None # 自定义 shell 环境变量
is_published: bool = False # 是否发布到广场 is_published: bool = False # 是否发布到广场
is_owner: bool = True # 是否是所有者 is_owner: bool = True # 是否是所有者
@ -1699,7 +1708,7 @@ async def get_general_agent_settings_api(authorization: Optional[str] = Header(N
enable_memori=settings.get("enable_memori", False), enable_memori=settings.get("enable_memori", False),
enable_thinking=settings.get("enable_thinking", False), enable_thinking=settings.get("enable_thinking", False),
tool_response=settings.get("tool_response", False), tool_response=settings.get("tool_response", False),
skills=settings.get("skills"), skills=_normalize_skills_list(settings.get("skills")),
shell_env=settings.get("shell_env") or {}, shell_env=settings.get("shell_env") or {},
is_published=False, is_published=False,
is_owner=False, is_owner=False,
@ -1869,14 +1878,10 @@ async def get_bot_settings(bot_uuid: str, authorization: Optional[str] = Header(
# 扫描 skills 需要的环境变量并合并到 shell_env # 扫描 skills 需要的环境变量并合并到 shell_env
shell_env = settings.get('shell_env') or {} shell_env = settings.get('shell_env') or {}
skills_list = settings.get('skills') skills_list = _normalize_skills_list(settings.get('skills'))
if skills_list: if skills_list:
from utils.multi_project_manager import scan_skill_env_keys from utils.multi_project_manager import scan_skill_env_keys
# skills 可能是逗号分隔的字符串,需要拆分成列表 skills_names = skills_list
if isinstance(skills_list, str):
skills_names = [s.strip() for s in skills_list.split(',') if s.strip()]
else:
skills_names = skills_list
required_keys = scan_skill_env_keys(bot_uuid, skills_names, Path("projects")) required_keys = scan_skill_env_keys(bot_uuid, skills_names, Path("projects"))
for key in required_keys: for key in required_keys:
if key not in shell_env: if key not in shell_env: