feat: 新增技能置顶功能
- 后端:新增 PUT /skills/custom/{name}/featured 接口,在 usage 中实现 set_featured 与 featured 字段(与 pinned 正交,仅影响排序)
- 前端:新增 setSkillFeatured API、置顶/取消置顶操作及中英文文案
- ScheduledTasksPage:优化助手选择下拉框的宽度与文本换行
- config.yaml:整理 log_system 配置块
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
b117bb1dc2
commit
eaa061dd06
11 files changed
+318
-171
No files matched your search
@@ -122,6 +122,7 @@ class SkillResponse(BaseModel):
|
||||
created_at: datetime | None = Field(default=None, description="Skill creation timestamp when known")
|
||||
state: str = Field(default="active", description="Lifecycle state: active, stale, or archived")
|
||||
pinned: bool = Field(default=False, description="Whether this skill is pinned (excluded from curation)")
|
||||
featured: bool = Field(default=False, description="Whether this skill is pinned to the top of the list (sort only)")
|
||||
source: str = Field(default="upload", description="Origin: 'agent' for agent-created, 'upload' for user-uploaded")
|
||||
owner_user_id: str | None = Field(default=None, description="Custom skill owner (null = built-in or legacy)")
|
||||
published: bool = Field(default=False, description="Whether the owner has made this skill visible to other users")
|
||||
@@ -294,6 +295,7 @@ def _skill_to_response(
|
||||
created_at=created_at,
|
||||
state=entry.get("state", "active"),
|
||||
pinned=entry.get("pinned", False),
|
||||
featured=entry.get("featured", False),
|
||||
source=entry.get("source", "upload"),
|
||||
owner_user_id=owner_user_id,
|
||||
published=published,
|
||||
@@ -1469,6 +1471,42 @@ async def update_custom_skill_pinned(
|
||||
raise HTTPException(status_code=500, detail=f"Failed to update pinned: {e}")
|
||||
|
||||
|
||||
class SkillFeaturedRequest(BaseModel):
|
||||
"""Request body for pinning a custom skill to the top of the list."""
|
||||
|
||||
featured: bool = Field(..., description="Whether to pin the skill to the top of the list (sort only)")
|
||||
|
||||
|
||||
@router.put(
|
||||
"/skills/custom/{skill_name}/featured",
|
||||
response_model=SkillResponse,
|
||||
summary="Pin or Unpin a Custom Skill to Top",
|
||||
description="Pin a skill to the top of the list (sort only; orthogonal to pinned/anti-archive). Only the owner or admins may invoke.",
|
||||
)
|
||||
async def update_custom_skill_featured(
|
||||
skill_name: str,
|
||||
body: SkillFeaturedRequest,
|
||||
request: Request,
|
||||
config: AppConfig = Depends(get_config),
|
||||
skill_store: SkillStore = Depends(get_skill_store),
|
||||
) -> SkillResponse:
|
||||
try:
|
||||
skill_name = skill_name.replace("\r\n", "").replace("\n", "")
|
||||
user_id = _current_user_id(request)
|
||||
is_admin = _is_admin_user(request)
|
||||
record, _mode = await _get_editable_skill_or_raise(skill_store, skill_name, user_id, is_admin=is_admin)
|
||||
|
||||
from deerflow.skills.usage import set_featured as _usage_set_featured
|
||||
|
||||
_usage_set_featured(skill_name, body.featured)
|
||||
return _reload_skill_response(skill_name, record, config)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("Failed to update featured for %s: %s", skill_name, e, exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=f"Failed to update featured: {e}")
|
||||
|
||||
|
||||
@router.get("/skills/custom/{skill_name}/history", response_model=CustomSkillHistoryResponse, summary="Get Custom Skill History")
|
||||
async def get_custom_skill_history(skill_name: str, config: AppConfig = Depends(get_config)) -> CustomSkillHistoryResponse:
|
||||
try:
|
||||
|
||||
@@ -210,10 +210,7 @@ auth_login:
|
||||
|
||||
# 日志系统入口(仅管理员可见):右下角「设置」菜单中会多出一个「日志系统」入口,
|
||||
# 点击后在新标签页打开下面的 url。enabled 关掉则不显示该入口。
|
||||
log_system:
|
||||
enabled: true
|
||||
url: "https://your-log-system.example.com"
|
||||
label: "日志系统"
|
||||
|
||||
|
||||
database:
|
||||
backend: sqlite
|
||||
@@ -300,3 +297,8 @@ ai_writing:
|
||||
keyword_model: deepseek-chat # 检索词生成专用模型,留空回退写作主模型
|
||||
rank_model: deepseek-chat # 素材排序专用模型,留空回退写作主模型
|
||||
max_materials: 20 # 合并去重后的素材总量上限,范围 [1, 100],默认 20
|
||||
|
||||
log_system:
|
||||
enabled: true
|
||||
url: "https://your-log-system.example.com"
|
||||
label: "日志系统"
|
||||
@@ -36,6 +36,7 @@ _DEFAULT_ENTRY: dict = {
|
||||
"created_at": None,
|
||||
"state": STATE_ACTIVE,
|
||||
"pinned": False,
|
||||
"featured": False,
|
||||
"archived_at": None,
|
||||
"source": SOURCE_UPLOAD,
|
||||
}
|
||||
@@ -141,6 +142,11 @@ def set_pinned(name: str, pinned: bool) -> None:
|
||||
_update_entry(name, {"pinned": pinned})
|
||||
|
||||
|
||||
def set_featured(name: str, featured: bool) -> None:
|
||||
"""置顶/取消置顶。与 pinned(防归档)正交,仅影响列表排序展示。"""
|
||||
_update_entry(name, {"featured": featured})
|
||||
|
||||
|
||||
def forget(name: str) -> None:
|
||||
try:
|
||||
with _usage_lock:
|
||||
|
||||
Reference in new issue
Block a user