初始化提交

This commit is contained in:
chenxin committed 2026-08-21 16:00:13 +08:00
commit 887c1f449e
963 files changed
+166869

No files matched your search

+137
View File
@@ -0,0 +1,137 @@
"""运行时数据访问。"""
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.runtime import Event, Run
async def get_run(session: AsyncSession, run_id: str) -> Run | None:
return await session.get(Run, run_id)
async def list_runs(
session: AsyncSession,
*,
character_id: str | None = None,
session_id: str | None = None,
status: str | None = None,
page: int = 1,
page_size: int = 20,
) -> tuple[list[Run], int]:
"""按创建时间倒序分页返回 Run;可选按人物/会话/状态过滤,返回 (条目, 总数)。"""
conds = []
if character_id is not None:
conds.append(Run.character_id == character_id)
if session_id is not None:
conds.append(Run.session_id == session_id)
if status is not None:
conds.append(Run.status == status)
count_stmt = select(func.count()).select_from(Run)
list_stmt = select(Run)
if conds:
count_stmt = count_stmt.where(*conds)
list_stmt = list_stmt.where(*conds)
total = int((await session.execute(count_stmt)).scalar_one())
result = await session.execute(
list_stmt.order_by(Run.created_at.desc()).offset((page - 1) * page_size).limit(page_size)
)
return list(result.scalars().all()), total
async def count_events(session: AsyncSession, run_id: str) -> int:
result = await session.execute(
select(func.count()).select_from(Event).where(Event.run_id == run_id)
)
return int(result.scalar_one())
async def next_event_sequence(session: AsyncSession, run_id: str) -> int:
result = await session.execute(select(func.max(Event.sequence)).where(Event.run_id == run_id))
current = result.scalar_one_or_none()
return int(current or 0) + 1
async def get_event(session: AsyncSession, event_id: str) -> Event | None:
return await session.get(Event, event_id)
async def has_active_runs(
session: AsyncSession,
character_id: str,
) -> bool:
"""检查指定角色是否有活跃的进行中 run(大周天任务中断防护用)。"""
result = await session.execute(
select(func.count()).select_from(Run).where(
Run.character_id == character_id,
Run.status == "running",
)
)
return int(result.scalar_one()) > 0
async def list_events_by_run(
session: AsyncSession,
run_id: str,
*,
visibility: str | None = None,
limit: int = 200,
offset: int = 0,
) -> tuple[list[Event], int]:
"""按 run_id 查询事件,按 sequence 升序;可选 visibility 过滤。返回 (条目, 总数)。"""
conditions = [Event.run_id == run_id]
if visibility is not None:
conditions.append(Event.visibility == visibility)
total = int(
(
await session.execute(select(func.count()).select_from(Event).where(*conditions))
).scalar_one()
)
result = await session.execute(
select(Event).where(*conditions).order_by(Event.sequence.asc()).offset(offset).limit(limit)
)
return list(result.scalars().all()), total
async def list_public_events_after(
session: AsyncSession, run_id: str, *, after_sequence: int = 0, limit: int = 100
) -> list[Event]:
result = await session.execute(
select(Event)
.where(
Event.run_id == run_id,
Event.visibility == "public",
Event.sequence > after_sequence,
)
.order_by(Event.sequence.asc())
.limit(limit)
)
return list(result.scalars().all())
async def list_events_by_trace(session: AsyncSession, trace_id: str) -> list[Event]:
"""链路追踪:按 trace_id 查询运行事件,按 created_at 升序(与审计/幂等归并排序)。"""
result = await session.execute(
select(Event).where(Event.trace_id == trace_id).order_by(Event.created_at.asc())
)
return list(result.scalars().all())
async def summarize_by_trace(session: AsyncSession):
"""GROUP BY trace_id:(trace_id, 计数, 最近时间),仅 trace_id 非空。供链路追踪列表聚合。"""
result = await session.execute(
select(Event.trace_id, func.count(), func.max(Event.created_at))
.where(Event.trace_id.is_not(None))
.group_by(Event.trace_id)
)
return [(row[0], int(row[1]), row[2]) for row in result.all()]
async def list_session_ids_by_runs(session: AsyncSession, run_ids: list[str]) -> list[str]:
"""按 run_id 集合查询关联的 chat session_id 去重列表(链路追踪:run → 对话)。"""
if not run_ids:
return []
result = await session.execute(
select(Run.session_id).where(Run.id.in_(run_ids), Run.session_id.is_not(None))
)
return sorted({row[0] for row in result.all() if row[0]})