docs: 更新协议文档,删除废弃计划文档

- 更新 http-error-codes, user-points-chat-data-protocol
- 更新 divination-run-protocol, profile-protocol
- 删除废弃的后端和前端设计计划文档
This commit is contained in:
qzl
2026-04-08 17:23:02 +08:00
parent 49fc9a116f
commit e80a82bef4
57 changed files with 4117 additions and 2269 deletions
+71 -13
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
from datetime import date, datetime, time, timedelta, timezone
from decimal import Decimal
from typing import Protocol
from typing import Any, Protocol
from uuid import UUID, uuid4
from sqlalchemy import Select, func, select
@@ -45,8 +45,10 @@ class AgentRepository:
detail="Invalid session_id",
) from exc
stmt = select(AgentChatSession.user_id).where(
AgentChatSession.id == session_uuid
stmt = (
select(AgentChatSession.user_id)
.where(AgentChatSession.id == session_uuid)
.where(AgentChatSession.deleted_at.is_(None))
)
owner_id = (await self._session.execute(stmt)).scalar_one_or_none()
if owner_id is None:
@@ -103,10 +105,18 @@ class AgentRepository:
code="AGENT_SESSION_ID_INVALID",
detail="Invalid session_id",
) from exc
session = await self._session.get(AgentChatSession, session_uuid)
if session is not None:
await self._session.delete(session)
await self._session.flush()
stmt = (
select(AgentChatSession)
.where(AgentChatSession.id == session_uuid)
.with_for_update()
)
session = (await self._session.execute(stmt)).scalar_one_or_none()
if session is None:
return
if session.deleted_at is not None:
return
session.deleted_at = datetime.now(timezone.utc)
await self._session.flush()
async def persist_user_message(
self,
@@ -263,6 +273,37 @@ class AgentRepository:
"messages": snapshot_messages,
}
async def get_session_messages(
self,
*,
session_id: str,
visibility_mask: int | None = None,
) -> list[dict[str, object]]:
try:
session_uuid = UUID(session_id)
except ValueError as exc:
raise ApiProblemError(
status_code=422,
code="AGENT_SESSION_ID_INVALID",
detail="Invalid session_id",
) from exc
message_stmt = (
select(AgentChatMessage)
.where(AgentChatMessage.session_id == session_uuid)
.where(AgentChatMessage.deleted_at.is_(None))
.order_by(AgentChatMessage.seq.asc())
)
message_stmt = self._apply_visibility_filter(
stmt=message_stmt,
visibility_mask=visibility_mask,
)
messages = (await self._session.execute(message_stmt)).scalars().all()
snapshot_messages: list[dict[str, object]] = []
for message in messages:
snapshot_messages.append(await self._to_snapshot_message(message))
return snapshot_messages
async def get_recent_messages_by_user_window(
self,
*,
@@ -371,16 +412,32 @@ class AgentRepository:
.where(AgentChatMessage.deleted_at.is_(None))
.where(AgentChatMessage.role == AgentChatMessageRole.ASSISTANT)
.order_by(AgentChatMessage.created_at.desc())
.limit(1)
.limit(20)
)
message_stmt = self._apply_visibility_filter(
stmt=message_stmt,
visibility_mask=visibility_mask,
)
message = (await self._session.execute(message_stmt)).scalar_one_or_none()
if message is None:
candidate_messages = (
(await self._session.execute(message_stmt)).scalars().all()
)
if not candidate_messages:
continue
snapshots.append(await self._to_snapshot_message(message))
selected_snapshot: dict[str, object] | None = None
for message in candidate_messages:
snapshot = await self._to_snapshot_message(message)
metadata = snapshot.get("metadata")
if not isinstance(metadata, dict):
continue
agent_output = metadata.get("agent_output")
if not isinstance(agent_output, dict):
continue
derived = agent_output.get("divination_derived")
if isinstance(derived, dict) and derived:
selected_snapshot = snapshot
break
if selected_snapshot is not None:
snapshots.append(selected_snapshot)
snapshots.sort(
key=lambda item: str(item.get("timestamp") or ""),
@@ -416,6 +473,7 @@ class AgentRepository:
payload_model = AgentChatMessageSchema.model_validate(
{
"id": str(message.id),
"session_id": str(message.session_id),
"seq": int(message.seq),
"role": role,
"content": message.content,
@@ -434,9 +492,9 @@ class AgentRepository:
def _apply_visibility_filter(
self,
*,
stmt: Select,
stmt: Select[Any],
visibility_mask: int | None,
) -> Select:
) -> Select[Any]:
if visibility_mask is None:
return stmt
required_mask = max(int(visibility_mask), 0)