初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -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]})
|
||||
Reference in new issue
Block a user