Update tool panel
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import Optional, Dict, Any
|
||||
from typing import Optional, Dict, Any, List
|
||||
import time
|
||||
import uuid
|
||||
import httpx
|
||||
from datetime import datetime
|
||||
|
||||
from ..db import get_db
|
||||
from ..models import LLMModel, ASRModel
|
||||
from ..models import LLMModel, ASRModel, ToolResource
|
||||
from ..schemas import ToolResourceCreate, ToolResourceOut, ToolResourceUpdate
|
||||
|
||||
router = APIRouter(prefix="/tools", tags=["Tools & Autotest"])
|
||||
|
||||
@@ -83,6 +85,36 @@ TOOL_REGISTRY = {
|
||||
},
|
||||
}
|
||||
|
||||
TOOL_CATEGORY_MAP = {
|
||||
"search": "query",
|
||||
"weather": "query",
|
||||
"translate": "query",
|
||||
"knowledge": "query",
|
||||
"calculator": "system",
|
||||
"code_interpreter": "system",
|
||||
}
|
||||
|
||||
TOOL_ICON_MAP = {
|
||||
"search": "Globe",
|
||||
"weather": "CloudSun",
|
||||
"translate": "Globe",
|
||||
"knowledge": "Box",
|
||||
"calculator": "Terminal",
|
||||
"code_interpreter": "Terminal",
|
||||
}
|
||||
|
||||
|
||||
def _builtin_tool_to_resource(tool_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": tool_id,
|
||||
"name": payload.get("name", tool_id),
|
||||
"description": payload.get("description", ""),
|
||||
"category": TOOL_CATEGORY_MAP.get(tool_id, "system"),
|
||||
"icon": TOOL_ICON_MAP.get(tool_id, "Wrench"),
|
||||
"enabled": True,
|
||||
"is_system": True,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/list")
|
||||
def list_available_tools():
|
||||
@@ -98,6 +130,122 @@ def get_tool_detail(tool_id: str):
|
||||
return TOOL_REGISTRY[tool_id]
|
||||
|
||||
|
||||
# ============ Tool Resource CRUD ============
|
||||
@router.get("/resources")
|
||||
def list_tool_resources(
|
||||
category: Optional[str] = None,
|
||||
enabled: Optional[bool] = None,
|
||||
include_system: bool = True,
|
||||
page: int = 1,
|
||||
limit: int = 100,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""获取工具资源列表(内置工具 + 自定义工具)。"""
|
||||
merged: List[Dict[str, Any]] = []
|
||||
|
||||
if include_system:
|
||||
for tool_id, payload in TOOL_REGISTRY.items():
|
||||
merged.append(_builtin_tool_to_resource(tool_id, payload))
|
||||
|
||||
query = db.query(ToolResource)
|
||||
if category:
|
||||
query = query.filter(ToolResource.category == category)
|
||||
if enabled is not None:
|
||||
query = query.filter(ToolResource.enabled == enabled)
|
||||
custom_tools = query.order_by(ToolResource.created_at.desc()).all()
|
||||
|
||||
for item in custom_tools:
|
||||
merged.append({
|
||||
"id": item.id,
|
||||
"name": item.name,
|
||||
"description": item.description,
|
||||
"category": item.category,
|
||||
"icon": item.icon,
|
||||
"enabled": item.enabled,
|
||||
"is_system": item.is_system,
|
||||
})
|
||||
|
||||
if category:
|
||||
merged = [item for item in merged if item.get("category") == category]
|
||||
if enabled is not None:
|
||||
merged = [item for item in merged if item.get("enabled") == enabled]
|
||||
|
||||
total = len(merged)
|
||||
start = max(page - 1, 0) * limit
|
||||
end = start + limit
|
||||
return {"total": total, "page": page, "limit": limit, "list": merged[start:end]}
|
||||
|
||||
|
||||
@router.get("/resources/{id}", response_model=ToolResourceOut)
|
||||
def get_tool_resource(id: str, db: Session = Depends(get_db)):
|
||||
"""获取单个工具资源详情。"""
|
||||
if id in TOOL_REGISTRY:
|
||||
tool = _builtin_tool_to_resource(id, TOOL_REGISTRY[id])
|
||||
return ToolResourceOut(**tool)
|
||||
|
||||
item = db.query(ToolResource).filter(ToolResource.id == id).first()
|
||||
if not item:
|
||||
raise HTTPException(status_code=404, detail="Tool resource not found")
|
||||
return item
|
||||
|
||||
|
||||
@router.post("/resources", response_model=ToolResourceOut)
|
||||
def create_tool_resource(data: ToolResourceCreate, db: Session = Depends(get_db)):
|
||||
"""创建自定义工具资源。"""
|
||||
candidate_id = (data.id or "").strip()
|
||||
if candidate_id and candidate_id in TOOL_REGISTRY:
|
||||
raise HTTPException(status_code=400, detail="Tool ID conflicts with system tool")
|
||||
|
||||
item = ToolResource(
|
||||
id=candidate_id or f"tool_{str(uuid.uuid4())[:8]}",
|
||||
user_id=1,
|
||||
name=data.name,
|
||||
description=data.description,
|
||||
category=data.category,
|
||||
icon=data.icon,
|
||||
enabled=data.enabled,
|
||||
is_system=False,
|
||||
)
|
||||
db.add(item)
|
||||
db.commit()
|
||||
db.refresh(item)
|
||||
return item
|
||||
|
||||
|
||||
@router.put("/resources/{id}", response_model=ToolResourceOut)
|
||||
def update_tool_resource(id: str, data: ToolResourceUpdate, db: Session = Depends(get_db)):
|
||||
"""更新自定义工具资源。"""
|
||||
if id in TOOL_REGISTRY:
|
||||
raise HTTPException(status_code=400, detail="System tools are read-only")
|
||||
|
||||
item = db.query(ToolResource).filter(ToolResource.id == id).first()
|
||||
if not item:
|
||||
raise HTTPException(status_code=404, detail="Tool resource not found")
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(item, field, value)
|
||||
item.updated_at = datetime.utcnow()
|
||||
|
||||
db.commit()
|
||||
db.refresh(item)
|
||||
return item
|
||||
|
||||
|
||||
@router.delete("/resources/{id}")
|
||||
def delete_tool_resource(id: str, db: Session = Depends(get_db)):
|
||||
"""删除自定义工具资源。"""
|
||||
if id in TOOL_REGISTRY:
|
||||
raise HTTPException(status_code=400, detail="System tools cannot be deleted")
|
||||
|
||||
item = db.query(ToolResource).filter(ToolResource.id == id).first()
|
||||
if not item:
|
||||
raise HTTPException(status_code=404, detail="Tool resource not found")
|
||||
db.delete(item)
|
||||
db.commit()
|
||||
return {"message": "Deleted successfully"}
|
||||
|
||||
|
||||
# ============ Autotest ============
|
||||
class AutotestResult:
|
||||
"""自动测试结果"""
|
||||
|
||||
Reference in New Issue
Block a user