CI / lint / typecheck / import-linter / tests / secrets (push) Canceled after 0s
- agent: ag_conversation/ag_message 表(迁移0007),上下文组装注入最近报告画像摘要 (report.profile.latest_profile_summary 经 apps 层闭包注入,同层不互调),历史带最近 AGENT_HISTORY_TURNS=10 轮;POST/GET /agent/conversations 与消息历史接口 - agent 修复:ChatRequest.conversation_id 改 str(雪花ID超2^53,JS Number丢精度); _build_context 挪进 reserve commit 后同一 try,异常走 refund 兜底 - report: rp_feedback(维度反馈 upsert,认同率/修正率 SQL 可算,T-P3-21 最小版—— L1 记忆未建,不回写结论)+ rp_reservation(预约留资幂等,T-P3-22,预约率口径 行数/full_report.card_view 去重曝光,门槛≥8%),迁移0008 - 测试:全量 606 passed;ruff/mypy/lint-imports 全绿;E2E 真实 deepseek-v4-flash 验证 画像注入与历史携带
44 lines
1.6 KiB
Python
44 lines
1.6 KiB
Python
"""预约留资服务(T-P3-22)。
|
||
|
||
topic 预留通用性,首期只有 full_report(全面报告上线提醒)。
|
||
幂等口径:UniqueConstraint(user_id, topic)——重复预约返回已有记录
|
||
(created=false,HTTP 仍 200),绝不堆行。
|
||
|
||
指标口径:预约率 = rp_reservation(topic='full_report') 行数 ÷ 埋点
|
||
full_report.card_view 去重曝光数;决策门槛 ≥8%(产品方案 §2.2.3)。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from packages.domain.ids import next_id
|
||
from packages.report import repo
|
||
from packages.shared.models import RpReservation
|
||
|
||
|
||
@dataclass(frozen=True, slots=True)
|
||
class ReservationResult:
|
||
reservation: RpReservation
|
||
created: bool # false=幂等命中已有记录
|
||
|
||
|
||
class ReservationService:
|
||
def __init__(self, session: AsyncSession) -> None:
|
||
self._session = session
|
||
|
||
async def reserve(self, *, user_id: int, topic: str) -> ReservationResult:
|
||
"""幂等预约:同 user+topic 已存在即返回原记录。"""
|
||
existing = await repo.get_reservation(self._session, user_id=user_id, topic=topic)
|
||
if existing is not None:
|
||
return ReservationResult(reservation=existing, created=False)
|
||
row = RpReservation(reservation_id=next_id(), user_id=user_id, topic=topic)
|
||
self._session.add(row)
|
||
await self._session.flush()
|
||
return ReservationResult(reservation=row, created=True)
|
||
|
||
async def list_topics(self, *, user_id: int, topic: str | None = None) -> list[str]:
|
||
return await repo.list_reservation_topics(self._session, user_id=user_id, topic=topic)
|