From c552f71e287dc2e35f6288f71ae03ae1b9a51954 Mon Sep 17 00:00:00 2001 From: "DESKTOP-72TV0V4\\caoxiaozhu" Date: Sat, 21 Mar 2026 11:28:20 +0800 Subject: [PATCH] feat: add Skill API endpoints Co-Authored-By: Claude Opus 4.6 --- backend/app/main.py | 2 + backend/app/routers/__init__.py | 1 + backend/app/routers/skill.py | 112 ++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 backend/app/routers/skill.py diff --git a/backend/app/main.py b/backend/app/main.py index 53b2238..7912fab 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -13,6 +13,7 @@ from app.routers import ( todo_router, settings_router, folder_router, + skill_router, ) from app.routers.scheduler import router as scheduler_router from app.services.scheduler_service import start_scheduler, stop_scheduler, get_scheduler_status @@ -59,6 +60,7 @@ app.include_router(agent_router) app.include_router(todo_router) app.include_router(settings_router) app.include_router(folder_router) +app.include_router(skill_router) app.include_router(scheduler_router) diff --git a/backend/app/routers/__init__.py b/backend/app/routers/__init__.py index f0f3826..0a0279e 100644 --- a/backend/app/routers/__init__.py +++ b/backend/app/routers/__init__.py @@ -8,3 +8,4 @@ from app.routers.agent import router as agent_router from app.routers.todo import router as todo_router from app.routers.settings import router as settings_router from app.routers.folder import router as folder_router +from app.routers.skill import router as skill_router diff --git a/backend/app/routers/skill.py b/backend/app/routers/skill.py new file mode 100644 index 0000000..29a62b8 --- /dev/null +++ b/backend/app/routers/skill.py @@ -0,0 +1,112 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy import select +from app.database import get_db +from app.models.skill import Skill +from app.models.user import User +from app.routers.auth import get_current_user +from app.schemas.skill import SkillCreate, SkillOut, SkillUpdate + +router = APIRouter(prefix="/api/skills", tags=["Skill"]) + + +@router.post("", response_model=SkillOut, status_code=201) +async def create_skill( + data: SkillCreate, + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + skill = Skill( + name=data.name, + description=data.description, + instructions=data.instructions, + agent_type=data.agent_type, + tools=data.tools, + required_context=data.required_context, + output_format=data.output_format, + visibility=data.visibility, + team_id=data.team_id, + is_active=data.is_active, + owner_id=current_user.id, + ) + db.add(skill) + await db.commit() + await db.refresh(skill) + return skill + + +@router.get("", response_model=list[SkillOut]) +async def list_skills( + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + result = await db.execute( + select(Skill).where(Skill.owner_id == current_user.id).order_by(Skill.created_at.desc()) + ) + return result.scalars().all() + + +@router.get("/{skill_id}", response_model=SkillOut) +async def get_skill( + skill_id: str, + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + result = await db.execute(select(Skill).where(Skill.id == skill_id)) + skill = result.scalar_one_or_none() + if not skill: + raise HTTPException(status_code=404, detail="Skill not found") + return skill + + +@router.put("/{skill_id}", response_model=SkillOut) +async def update_skill( + skill_id: str, + data: SkillUpdate, + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + result = await db.execute(select(Skill).where(Skill.id == skill_id)) + skill = result.scalar_one_or_none() + if not skill: + raise HTTPException(status_code=404, detail="Skill not found") + + if data.name is not None: + skill.name = data.name + if data.description is not None: + skill.description = data.description + if data.instructions is not None: + skill.instructions = data.instructions + if data.agent_type is not None: + skill.agent_type = data.agent_type + if data.tools is not None: + skill.tools = data.tools + if data.required_context is not None: + skill.required_context = data.required_context + if data.output_format is not None: + skill.output_format = data.output_format + if data.visibility is not None: + skill.visibility = data.visibility + if data.team_id is not None: + skill.team_id = data.team_id + if data.is_active is not None: + skill.is_active = data.is_active + + await db.commit() + await db.refresh(skill) + return skill + + +@router.delete("/{skill_id}", status_code=204) +async def delete_skill( + skill_id: str, + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +): + result = await db.execute(select(Skill).where(Skill.id == skill_id)) + skill = result.scalar_one_or_none() + if not skill: + raise HTTPException(status_code=404, detail="Skill not found") + + await db.delete(skill) + await db.commit()