fix: delete agent 500 error + dynamic personality + deployment guide
- Fix delete agent 500: clean up FK records (agent_llm_logs, permissions, schedules, executions, team_members) and unbind goals/tasks before delete - Remove hardcoded personality templates in Android, replace with dynamic system prompt generation from name + description - Set promptSectionsEnabled=false to bypass PromptComposer for personality - Add Tencent Cloud Linux deployment guide (Docker Compose) - Accumulated backend service updates, frontend UI fixes, Android app changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Path
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Path, Request
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -33,6 +33,8 @@ class ToolCreate(BaseModel):
|
||||
implementation_type: str # builtin / http / code / workflow
|
||||
implementation_config: Optional[dict] = None
|
||||
is_public: bool = False
|
||||
status: str = "active" # active / draft / deprecated
|
||||
tags: Optional[List[str]] = None
|
||||
|
||||
|
||||
class ToolResponse(BaseModel):
|
||||
@@ -44,6 +46,8 @@ class ToolResponse(BaseModel):
|
||||
implementation_type: str
|
||||
implementation_config: Optional[dict] = None
|
||||
is_public: bool = False
|
||||
status: str = "active"
|
||||
tags: Optional[List[str]] = None
|
||||
use_count: int = 0
|
||||
user_id: Optional[str] = None
|
||||
created_at: str = ""
|
||||
@@ -86,6 +90,8 @@ def _tool_to_dict(tool: Tool) -> dict:
|
||||
"implementation_type": tool.implementation_type,
|
||||
"implementation_config": tool.implementation_config,
|
||||
"is_public": tool.is_public,
|
||||
"status": tool.status if hasattr(tool, "status") else "active",
|
||||
"tags": tool.tags if hasattr(tool, "tags") else None,
|
||||
"use_count": tool.use_count,
|
||||
"user_id": tool.user_id,
|
||||
"created_at": tool.created_at.isoformat() if tool.created_at else "",
|
||||
@@ -139,12 +145,18 @@ async def list_tools(
|
||||
category: Optional[str] = Query(None, description="按分类筛选"),
|
||||
search: Optional[str] = Query(None, description="搜索关键词"),
|
||||
scope: Optional[str] = Query("public", description="public / mine / all"),
|
||||
status: Optional[str] = Query(None, description="状态筛选: active/draft/deprecated"),
|
||||
workspace_id: Optional[str] = Query(None, description="工作区ID筛选"),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: Optional[User] = Depends(get_current_user),
|
||||
):
|
||||
"""浏览工具市场(含内置工具 + 数据库工具)。"""
|
||||
query = db.query(Tool)
|
||||
|
||||
# 工作区筛选
|
||||
if workspace_id:
|
||||
query = query.filter(Tool.workspace_id == workspace_id)
|
||||
|
||||
if scope == "public":
|
||||
query = query.filter(Tool.is_public == True)
|
||||
elif scope == "mine":
|
||||
@@ -152,6 +164,12 @@ async def list_tools(
|
||||
raise HTTPException(status_code=401, detail="需登录")
|
||||
query = query.filter(Tool.user_id == current_user.id)
|
||||
|
||||
if status:
|
||||
query = query.filter(Tool.status == status)
|
||||
else:
|
||||
# 默认只显示 active 状态的工具(排除 deprecated)
|
||||
query = query.filter((Tool.status == "active") | (Tool.status == None))
|
||||
|
||||
if category:
|
||||
query = query.filter(Tool.category == category)
|
||||
if search:
|
||||
@@ -216,10 +234,20 @@ async def get_tool(
|
||||
@router.post("", response_model=ToolResponse, status_code=201)
|
||||
async def create_tool(
|
||||
tool_data: ToolCreate,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""创建自定义工具。"""
|
||||
# 从 JWT 提取当前工作区 ID
|
||||
from app.core.security import decode_access_token
|
||||
ws_id = None
|
||||
auth_header = request.headers.get("Authorization", "")
|
||||
if auth_header.startswith("Bearer "):
|
||||
payload = decode_access_token(auth_header[7:])
|
||||
if payload:
|
||||
ws_id = payload.get("ws") or None
|
||||
|
||||
existing = db.query(Tool).filter(Tool.name == tool_data.name).first()
|
||||
if existing:
|
||||
raise HTTPException(status_code=400, detail=f"工具名 '{tool_data.name}' 已存在")
|
||||
@@ -237,20 +265,24 @@ async def create_tool(
|
||||
implementation_type=tool_data.implementation_type,
|
||||
implementation_config=tool_data.implementation_config,
|
||||
is_public=tool_data.is_public,
|
||||
status=tool_data.status,
|
||||
tags=tool_data.tags,
|
||||
user_id=current_user.id,
|
||||
workspace_id=ws_id,
|
||||
)
|
||||
db.add(tool)
|
||||
db.commit()
|
||||
db.refresh(tool)
|
||||
logger.info("工具已创建: %s (type=%s)", tool.name, tool.implementation_type)
|
||||
logger.info("工具已创建: %s (type=%s, status=%s)", tool.name, tool.implementation_type, tool.status)
|
||||
|
||||
# 刷新注册表
|
||||
tool_registry._custom_tool_configs[tool.name] = {
|
||||
**(tool.implementation_config or {}),
|
||||
"_type": tool.implementation_type,
|
||||
"_db_id": tool.id,
|
||||
}
|
||||
tool_registry._tool_schemas[tool.name] = tool.function_schema
|
||||
# 仅 active 状态注入注册表
|
||||
if tool.status == "active" or tool.status is None:
|
||||
tool_registry._custom_tool_configs[tool.name] = {
|
||||
**(tool.implementation_config or {}),
|
||||
"_type": tool.implementation_type,
|
||||
"_db_id": tool.id,
|
||||
}
|
||||
tool_registry._tool_schemas[tool.name] = tool.function_schema
|
||||
|
||||
return _tool_to_dict(tool)
|
||||
|
||||
@@ -317,12 +349,27 @@ async def delete_tool(
|
||||
db.commit()
|
||||
|
||||
# 清理注册表
|
||||
tool_registry._custom_tool_configs.pop(tool.name, None)
|
||||
tool_registry._tool_schemas.pop(tool.name, None)
|
||||
tool_registry.unregister_tool(tool.name)
|
||||
|
||||
return {"message": "工具已删除"}
|
||||
|
||||
|
||||
@router.post("/reload")
|
||||
async def reload_tools(db: Session = Depends(get_db)):
|
||||
"""从数据库重新加载所有自定义工具到注册表(热更新)。"""
|
||||
# 清除旧的自定义工具
|
||||
for name in list(tool_registry._custom_tool_configs.keys()):
|
||||
if name not in tool_registry._builtin_tools:
|
||||
tool_registry._custom_tool_configs.pop(name, None)
|
||||
tool_registry._tool_schemas.pop(name, None)
|
||||
|
||||
# 重新加载
|
||||
tool_registry.load_tools_from_db(db)
|
||||
count = len(tool_registry._custom_tool_configs)
|
||||
logger.info("工具热更新完成,已加载 %d 个自定义工具", count)
|
||||
return {"message": f"工具注册表已刷新", "custom_tool_count": count}
|
||||
|
||||
|
||||
# ─── 工具测试 ──────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user