241 lines
4.0 KiB
Python
241 lines
4.0 KiB
Python
# Auto-extracted from chat.py during Phase 1 refactor (Strangler Fig).
|
|
# Source of truth: scripts/phase1_extract.py. Do not hand-merge back.
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, Response
|
|
from sqlalchemy.orm import Session
|
|
from sqlalchemy import and_, desc, asc, func
|
|
from pydantic import BaseModel, Field
|
|
from typing import Optional
|
|
import uuid
|
|
from datetime import datetime, timezone, timedelta
|
|
import re
|
|
import json
|
|
import asyncio
|
|
import math
|
|
import httpx
|
|
import os
|
|
import logging
|
|
from ..database import get_db, SessionLocal
|
|
from ..models import (
|
|
|
|
|
|
|
|
User, Conversation, Message, AIModel, ModelProvider, TokenUsageLog,
|
|
|
|
|
|
|
|
KnowledgeBase, KnowledgeDocument, KnowledgeDocumentChunk, EvolutionSkill,
|
|
|
|
|
|
|
|
EvolutionTrajectory, MarketApp, AppPurchase, AppInstallation,
|
|
|
|
|
|
|
|
MCPServer,
|
|
|
|
|
|
|
|
gen_uuid
|
|
|
|
|
|
|
|
)
|
|
from ..auth import get_current_user
|
|
from ..platform_knowledge import get_platform_knowledge
|
|
from ..mcp_client import list_mcp_tools, call_mcp_tool
|
|
from ..middleware.log_service import LogService
|
|
from ..capability_registry import resolve_auto_model
|
|
|
|
def _resolve_market_mcp(db: Session, mcp_ids: list, user_id: str) -> list:
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
加载用户选择的 MCP 应用配置(MarketApp.type == 'mcp')。
|
|
|
|
|
|
|
|
返回: [{id, name, transport, endpoint, description}]
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
if not mcp_ids:
|
|
|
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mcps = db.query(MarketApp).filter(
|
|
|
|
|
|
|
|
MarketApp.id.in_(mcp_ids),
|
|
|
|
|
|
|
|
MarketApp.type == "mcp"
|
|
|
|
|
|
|
|
).all()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
results = []
|
|
|
|
|
|
|
|
for m in mcps:
|
|
|
|
|
|
|
|
config = {}
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
if m.skill_content:
|
|
|
|
|
|
|
|
config = json.loads(m.skill_content)
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
|
|
config = {}
|
|
|
|
|
|
|
|
results.append({
|
|
|
|
|
|
|
|
"id": m.id,
|
|
|
|
|
|
|
|
"name": m.name,
|
|
|
|
|
|
|
|
"transport": m.mcp_transport or config.get("transport", "stdio"),
|
|
|
|
|
|
|
|
"endpoint": m.agent_endpoint or config.get("endpoint", "") or config.get("url", ""),
|
|
|
|
|
|
|
|
"description": m.description or config.get("description", ""),
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return results
|
|
|
|
def _resolve_active_mcp_servers(db: Session, mcp_ids: list) -> list:
|
|
|
|
"""
|
|
|
|
解析用户选中的 MCP 服务连接信息(来自 mcp_servers 表,import 与后台添加通用)。
|
|
|
|
返回: [{id, name, description, transport, endpoint, url, headers}]
|
|
|
|
"""
|
|
|
|
if not mcp_ids:
|
|
|
|
return []
|
|
|
|
servers = db.query(MCPServer).filter(
|
|
|
|
MCPServer.id.in_(mcp_ids),
|
|
|
|
MCPServer.is_enabled == True,
|
|
|
|
).all()
|
|
|
|
out = []
|
|
|
|
for s in servers:
|
|
|
|
try:
|
|
|
|
headers = json.loads(s.headers) if isinstance(s.headers, str) else (s.headers or {})
|
|
|
|
except Exception:
|
|
|
|
headers = {}
|
|
|
|
out.append({
|
|
|
|
"id": s.id,
|
|
|
|
"name": s.name,
|
|
|
|
"description": s.description or "",
|
|
|
|
"transport": s.transport_type or "streamable_http",
|
|
|
|
"endpoint": s.url or "",
|
|
|
|
"url": s.url or "",
|
|
|
|
"headers": headers,
|
|
|
|
})
|
|
|
|
return out
|
|
|
|
def _list_enabled_mcp_servers(db: Session) -> list:
|
|
"""返回平台所有已启用(is_enabled=True)的 MCP 服务清单,供 AI 准确回答"平台有哪些 MCP"。"""
|
|
servers = db.query(MCPServer).filter(MCPServer.is_enabled == True).all()
|
|
out = []
|
|
for s in servers:
|
|
try:
|
|
headers = json.loads(s.headers) if isinstance(s.headers, str) else (s.headers or {})
|
|
except Exception:
|
|
headers = {}
|
|
out.append({
|
|
"id": s.id,
|
|
"name": s.name,
|
|
"description": s.description or "",
|
|
"transport": s.transport_type or "streamable_http",
|
|
"endpoint": s.url or "",
|
|
"url": s.url or "",
|
|
"headers": headers,
|
|
})
|
|
return out
|