feat: 人设模板系统、节点调度标签、pydantic-settings收敛、错误处理增强

新增persona_template表和CRUD API,BaseIndividualModel增加node_affinity和template_origin_id字段,
WorkerCluster支持多集群Ray资源调度,环境变量收敛到pydantic-settings统一校验,
数据库异常转换为结构化BusinessError/RetryableError,系统节点支持custom_system_prompt。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 06:07:46 +00:00
parent f3a92a793e
commit 8f1398c591
23 changed files with 582 additions and 48 deletions
+4 -3
View File
@@ -21,6 +21,7 @@ from fastapi.responses import FileResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from kilostar.utils.standalone_proxy import _STANDALONE
from kilostar.utils.settings import get_settings
if not _STANDALONE:
from ray import serve
@@ -51,13 +52,13 @@ _api_logger = get_logger("api")
def _get_locale(request: Request) -> str | None:
"""从请求头解析首选语言,供异常 handler 使用。"""
return request.headers.get("accept-language") or None
app = FastAPI()
_cors_origins_env = os.environ.get("KILOSTAR_CORS_ORIGINS", "")
_is_dev = os.environ.get("KILOSTAR_ENV", "production").lower() in ("dev", "development")
_settings = get_settings()
_cors_origins_env = _settings.kilostar_cors_origins
_is_dev = _settings.security.kilostar_env.lower() in ("dev", "development")
if not _cors_origins_env and _is_dev:
_cors_origins_env = "*"
elif not _cors_origins_env:
+4 -2
View File
@@ -266,8 +266,10 @@ async def send_message(
if not user_id and not group_id:
raise ValueError("必须指定 user_id 或 group_id 之一")
base = base_url or os.environ.get("ONEBOT_HTTP_URL", "http://127.0.0.1:5700")
token = access_token or os.environ.get("ONEBOT_ACCESS_TOKEN")
from kilostar.utils.settings import get_settings
_ob = get_settings().onebot
base = base_url or _ob.onebot_http_url
token = access_token or _ob.onebot_access_token or None
if group_id:
action = "send_group_msg"
+7
View File
@@ -106,3 +106,10 @@ async def query_system_logs(
offset=offset,
)
return {"logs": logs, "count": len(logs)}
@system_router.get("/api/v1/system/node-labels")
async def get_node_labels(
_: TokenData = Depends(Accessor.get_current_user),
):
return {"node_labels": ["cpu", "core", "gpu"]}