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
+74
View File
@@ -0,0 +1,74 @@
"""``PersonaTemplateDatabase`` — list_templates 查询逻辑单元测试。"""
from __future__ import annotations
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from kilostar.core.postgres_database.module.persona_template import PersonaTemplateDatabase
def _make_db():
session = AsyncMock()
session.__aenter__ = AsyncMock(return_value=session)
session.__aexit__ = AsyncMock(return_value=False)
session_maker = MagicMock(return_value=session)
return PersonaTemplateDatabase(session_maker), session
@pytest.mark.anyio
async def test_list_owner_and_builtin_uses_or():
"""owner_id + include_builtin=True 应构造 OR 条件,不拉出其他人的模板。"""
db, session = _make_db()
execute_result = MagicMock()
execute_result.scalars.return_value.all.return_value = []
session.execute = AsyncMock(return_value=execute_result)
result = await db.list_templates(owner_id="alice", include_builtin=True)
assert result == []
# 确认 execute 被调用(OR 条件路径走通)
session.execute.assert_awaited_once()
@pytest.mark.anyio
async def test_list_owner_only():
db, session = _make_db()
execute_result = MagicMock()
execute_result.scalars.return_value.all.return_value = []
session.execute = AsyncMock(return_value=execute_result)
await db.list_templates(owner_id="alice", include_builtin=False)
session.execute.assert_awaited_once()
@pytest.mark.anyio
async def test_list_builtin_only():
db, session = _make_db()
execute_result = MagicMock()
execute_result.scalars.return_value.all.return_value = []
session.execute = AsyncMock(return_value=execute_result)
await db.list_templates(owner_id=None, include_builtin=True)
session.execute.assert_awaited_once()
@pytest.mark.anyio
async def test_delete_nonexistent_returns_false():
db, session = _make_db()
execute_result = MagicMock()
execute_result.scalar_one_or_none.return_value = None
session.execute = AsyncMock(return_value=execute_result)
result = await db.delete_template("missing")
assert result is False
@pytest.mark.anyio
async def test_update_nonexistent_returns_none():
db, session = _make_db()
execute_result = MagicMock()
execute_result.scalar_one_or_none.return_value = None
session.execute = AsyncMock(return_value=execute_result)
result = await db.update_template("missing", name="new")
assert result is None