Files
server-core/app/api/routers/bootstrap.py
T

79 lines
2.9 KiB
Python

# -*- coding: utf-8 -*-
"""智能体引导(bootstrap)路由。
返回"所有用户首次启动 / 每次登录都必须初始化的官方预置智能体"定义 ——
由运营端管理后台配置(official_agents 表),不再硬编码。
这是全局定义(对所有用户相同),因此**公开**(无需登录),本地据此在首次启动
和每次登录时初始化本地 workspace,避免本地硬编码默认智能体。
支持 ``?scope=`` 过滤身份级别:opc(桌面端)/park(园区端)/operator(运营端)/all。
默认 opc(桌面端是主要消费方;旧客户端无参请求仍返回桌面端集合)。
"""
from __future__ import annotations
import json as _json
from fastapi import APIRouter, Depends
from starlette.requests import Request
from ..dependencies import get_db
from ...infrastructure.repositories import Database
router = APIRouter(tags=["bootstrap"])
_DOC_KEYS = ("soul", "profile", "heartbeat", "memory")
def _parse_docs(raw: str) -> dict:
"""解析文档 JSON 字段;失败时返回空对象(不影响下发)。"""
try:
data = _json.loads(raw or "{}")
except (ValueError, TypeError):
return {}
if not isinstance(data, dict):
return {}
return {
"user": str(data.get("user", "") or ""),
"server": str(data.get("server", "") or ""),
}
def _match_scope(agent_scope: str, requested: str) -> bool:
"""agent.scope 是否覆盖请求 scope:all 覆盖一切;逗号分隔列表含请求值。"""
agent_scope = (agent_scope or "opc").strip()
if not agent_scope or agent_scope == "all":
return True
return requested in [s.strip() for s in agent_scope.split(",")]
@router.get("/agent-bootstrap", summary="必初始化官方智能体定义")
async def agent_bootstrap(
request: Request,
db: Database = Depends(get_db),
):
"""返回服务端配置的官方预置智能体(启用中),供桌面端登录/启动同步。"""
scope = (request.query_params.get("scope") or "opc").strip() or "opc"
if scope == "all":
scope = "opc" # all 请求场景按全量:下放时以列表值过滤
seeds = await db.official_agents.active()
out = []
for seed in seeds:
if not _match_scope(seed.get("scope", "opc"), scope):
continue
docs = {k: _parse_docs(seed.get(k) or "{}") for k in _DOC_KEYS}
out.append(
{
"id": seed["id"],
"name": seed["name"],
"description": seed.get("description", ""),
"language": seed.get("language", "zh"),
"model_name": seed.get("model_name", ""),
"template_type": seed.get("template_type", "common"),
"deletable": seed.get("deletable", True),
"use_fixed_soul": seed.get("use_fixed_soul", False),
"scope": seed.get("scope", "opc"),
"documents": docs,
}
)
return out