M2b:删除旧 chat 体系——线性会话/叩心/情绪/纪念日模型与页面退役(迁移 003 双向验证),runs 去会话外键,测试全量修剪
This commit is contained in:
1 parent
5f36e3785c
commit
ad9c9e942a
22 files changed
+424
-427
No files matched your search
@@ -262,14 +262,11 @@ async def get_trace(trace_id: str) -> TraceDetail:
|
||||
*[audit.character_id for audit in audits if audit.character_id],
|
||||
}
|
||||
)
|
||||
session_ids = (
|
||||
sorted(await runtime_repo.list_session_ids_by_runs(session, run_ids)) if run_ids else []
|
||||
)
|
||||
return TraceDetail(
|
||||
trace_id=trace_id,
|
||||
character_ids=character_ids,
|
||||
run_ids=run_ids,
|
||||
session_ids=session_ids,
|
||||
session_ids=[],
|
||||
items=items,
|
||||
)
|
||||
|
||||
@@ -342,15 +339,7 @@ async def list_traces(*, limit: int = 50) -> TraceListResponse:
|
||||
).all():
|
||||
_entry(tid)["character_ids"].add(cid)
|
||||
|
||||
# 对话归属(events.run_id → runs.session_id)
|
||||
for tid, sid in (
|
||||
await session.execute(
|
||||
select(Event.trace_id, Run.session_id)
|
||||
.join(Run, Event.run_id == Run.id)
|
||||
.where(Event.trace_id.is_not(None), Run.session_id.is_not(None))
|
||||
)
|
||||
).all():
|
||||
_entry(tid)["session_ids"].add(sid)
|
||||
# 对话归属随线性会话模型退役;镜树归属随 M2c 司命台重设计接入(tree_id 聚合)
|
||||
|
||||
total = len(merged)
|
||||
ordered = sorted(merged.values(), key=lambda e: e["last_seen"], reverse=True)
|
||||
|
||||
@@ -10,7 +10,6 @@ from app.core.time import utc_now
|
||||
from app.db.session import AsyncSessionLocal
|
||||
from app.models.character import Character
|
||||
from app.models.personality import PersonalityVersion
|
||||
from app.models.time_anniversary import TimeAnniversary
|
||||
from app.modules.character import (
|
||||
MODEL_POLICY_CREATE_DEFAULTS,
|
||||
SYSTEM_TEMPLATE_OWNER_SCOPE,
|
||||
@@ -19,7 +18,6 @@ from app.modules.character import (
|
||||
)
|
||||
from app.repositories import characters as character_repo
|
||||
from app.repositories import personality as personality_repo
|
||||
from app.repositories import time_anniversaries as anniversary_repo
|
||||
from app.repositories.json_utils import dumps, loads_dict
|
||||
from app.schemas.character import (
|
||||
ActivateCharacterResponse,
|
||||
@@ -232,7 +230,7 @@ async def create_character_from_template(
|
||||
session: AsyncSession, template: Character, owner_scope: str
|
||||
) -> Character:
|
||||
# 模板的 birthday 仅在兜底(空/缺失)时不继承;显式设置的有效生日原样保留,
|
||||
# 由 _ensure_default_birthday 写入子角色的 profile 与 time_anniversaries 表。
|
||||
# 由 _ensure_default_birthday 写入子角色的 profile。
|
||||
profile = loads_dict(template.profile_json)
|
||||
birthday = profile.get("birthday")
|
||||
if not (isinstance(birthday, str) and birthday.strip()):
|
||||
@@ -388,51 +386,17 @@ async def _audit_character(session: AsyncSession, character: Character, action:
|
||||
|
||||
|
||||
async def _ensure_default_birthday(session: AsyncSession, character: Character) -> None:
|
||||
"""birthday 缺失时用 created_at 兜底:写 profile.birthday 并建一条生日纪念日。
|
||||
"""birthday 缺失时用 created_at 兜底:仅写 profile.birthday。
|
||||
|
||||
- 仅在 profile.birthday 为空/缺失时触发默认兜底;用户或模板已设则不覆盖。
|
||||
- 无论 birthday 是否已设,只要角色尚无 birthday 纪念日,就建一条。
|
||||
- profile.birthday 与 TimeAnniversary.date 取 birthday 值(显式)或 created_at 的 ISO 日期。
|
||||
- 须在 character flush 后调用(依赖 id 与 created_at);同一事务内随外层 commit 落库。
|
||||
纪念日表(time_anniversaries)随旧时间模型退役删除;辰正(M8 重实现)落地后
|
||||
生日提醒改由时态感知按 profile.birthday 计算,不再预写行。
|
||||
"""
|
||||
profile = loads_dict(character.profile_json)
|
||||
birthday = profile.get("birthday")
|
||||
if isinstance(birthday, str) and birthday.strip():
|
||||
# birthday 已设但可能无对应纪念日(如从模板继承),仅 ISO 格式生日补建
|
||||
existing = await anniversary_repo.list_anniversaries(session, character.id)
|
||||
if not any(a.kind == "birthday" for a in existing):
|
||||
try:
|
||||
datetime.strptime(birthday, "%Y-%m-%d")
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
else:
|
||||
anniversary = TimeAnniversary(
|
||||
character_id=character.id,
|
||||
name=f"{character.display_name or character.name}·生辰",
|
||||
calendar="solar",
|
||||
date=birthday,
|
||||
recurs_yearly=True,
|
||||
kind="birthday",
|
||||
subject_type="character_self",
|
||||
source="auto",
|
||||
)
|
||||
await anniversary_repo.create_anniversary(session, anniversary)
|
||||
return
|
||||
birthday_iso = character.created_at.strftime("%Y-%m-%d")
|
||||
profile["birthday"] = birthday_iso
|
||||
profile["birthday"] = character.created_at.strftime("%Y-%m-%d")
|
||||
character.profile_json = dumps(profile)
|
||||
anniversary = TimeAnniversary(
|
||||
character_id=character.id,
|
||||
name=f"{character.display_name or character.name}·生辰",
|
||||
calendar="solar",
|
||||
date=birthday_iso,
|
||||
recurs_yearly=True,
|
||||
kind="birthday",
|
||||
subject_type="character_self",
|
||||
source="auto",
|
||||
)
|
||||
await anniversary_repo.create_anniversary(session, anniversary)
|
||||
|
||||
|
||||
async def create_character(
|
||||
session: AsyncSession,
|
||||
|
||||
@@ -28,14 +28,12 @@ async def create_run(
|
||||
session: AsyncSession,
|
||||
*,
|
||||
character_id: str,
|
||||
session_id: str | None,
|
||||
model_hint: str,
|
||||
goal: str = "回复用户消息",
|
||||
origin: str = "chat",
|
||||
) -> Run:
|
||||
run = Run(
|
||||
character_id=character_id,
|
||||
session_id=session_id,
|
||||
status="running",
|
||||
goal=goal,
|
||||
origin=origin,
|
||||
@@ -175,17 +173,15 @@ async def get_run_response(run_id: str) -> RunResponse:
|
||||
async def list_runs_response(
|
||||
*,
|
||||
character_id: str | None = None,
|
||||
session_id: str | None = None,
|
||||
status: str | None = None,
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
) -> Page[RunResponse]:
|
||||
"""Run 列表(按创建时间倒序);可选按人物/会话/状态过滤。归档页运行时间河数据源。"""
|
||||
"""Run 列表(按创建时间倒序);可选按人物/状态过滤。归档页运行时间河数据源。"""
|
||||
async with AsyncSessionLocal() as session:
|
||||
items, total = await runtime_repo.list_runs(
|
||||
session,
|
||||
character_id=character_id,
|
||||
session_id=session_id,
|
||||
status=status,
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
|
||||
@@ -6,7 +6,6 @@ from typing import Any
|
||||
from app.core.time import to_iso, utc_now
|
||||
from app.models.candidates import MemoryCandidate, ProfileCandidate
|
||||
from app.models.character import Character
|
||||
from app.models.chat import ChatMessage, ChatSession
|
||||
from app.models.governance import (
|
||||
AgentRosterEntry,
|
||||
GenerationPreferences,
|
||||
@@ -33,7 +32,6 @@ from app.schemas.admin import (
|
||||
)
|
||||
from app.schemas.candidates import MemoryCandidateResponse, ProfileCandidateResponse
|
||||
from app.schemas.character import CharacterResponse, CharacterSummaryResponse
|
||||
from app.schemas.chat import ChatMessageResponse, ChatSessionResponse
|
||||
from app.schemas.imports import ImportItemResponse, ImportJobResponse
|
||||
from app.schemas.memory import MemoryResponse
|
||||
from app.schemas.personality import PersonalityProposalResponse, PersonalityResponse
|
||||
@@ -125,42 +123,6 @@ def proposal_to_response(proposal: PersonalityProposal) -> PersonalityProposalRe
|
||||
)
|
||||
|
||||
|
||||
def chat_session_to_response(
|
||||
chat_session: ChatSession,
|
||||
*,
|
||||
message_count: int = 0,
|
||||
last_message_preview: str | None = None,
|
||||
) -> ChatSessionResponse:
|
||||
return ChatSessionResponse(
|
||||
session_id=chat_session.id,
|
||||
character_id=chat_session.character_id,
|
||||
title=chat_session.title,
|
||||
status=chat_session.status,
|
||||
created_at=to_iso(chat_session.created_at) or "",
|
||||
updated_at=to_iso(chat_session.updated_at) or "",
|
||||
message_count=message_count,
|
||||
last_message_preview=last_message_preview,
|
||||
)
|
||||
|
||||
|
||||
def chat_message_to_response(message: ChatMessage) -> ChatMessageResponse:
|
||||
return ChatMessageResponse(
|
||||
message_id=message.id,
|
||||
session_id=message.session_id,
|
||||
character_id=message.character_id,
|
||||
role=message.role,
|
||||
content=message.content,
|
||||
modality=message.modality,
|
||||
run_id=message.run_id,
|
||||
metadata=loads_dict(message.metadata_json),
|
||||
sensitivity=message.sensitivity,
|
||||
versions=loads_list(message.versions_json),
|
||||
active_version_idx=message.active_version_idx,
|
||||
created_at=to_iso(message.created_at) or "",
|
||||
deleted_at=to_iso(message.deleted_at),
|
||||
)
|
||||
|
||||
|
||||
def memory_to_response(memory: Memory) -> MemoryResponse:
|
||||
return MemoryResponse(
|
||||
id=memory.id,
|
||||
@@ -185,7 +147,6 @@ def run_to_response(run: Run) -> RunResponse:
|
||||
return RunResponse(
|
||||
id=run.id,
|
||||
character_id=run.character_id,
|
||||
session_id=run.session_id,
|
||||
status=run.status,
|
||||
kind=run.kind,
|
||||
goal=run.goal,
|
||||
|
||||
Reference in new issue
Block a user