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 验证 画像注入与历史携带
79 lines
3.4 KiB
Python
79 lines
3.4 KiB
Python
"""Agent 会话与消息表(FR-AGT-09 / T-P4-01)。
|
|
|
|
ag_conversation — 会话主表;title 取首条用户消息截断,last_message_at 是
|
|
列表排序与 90 天保留期清理(合规方案 §6)的时间锚点
|
|
ag_message — 消息表;retrieval_trace / rule_hits 是「每条回答可复盘」
|
|
的锚点,检索步骤(架构 §7.2 ④)落地前留空;assistant 行
|
|
以 call_id 关联 ob_ai_call,回复可一路追到成本账本
|
|
|
|
Reversible: 是。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Sequence
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
from sqlalchemy.dialects import postgresql
|
|
|
|
revision: str = "0007"
|
|
down_revision: str | None = "0006"
|
|
branch_labels: str | Sequence[str] | None = None
|
|
depends_on: str | Sequence[str] | None = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.create_table(
|
|
"ag_conversation",
|
|
sa.Column("conversation_id", sa.BigInteger(), nullable=False),
|
|
sa.Column("user_id", sa.BigInteger(), nullable=False),
|
|
sa.Column("title", sa.String(length=64), nullable=False, server_default=sa.text("''")),
|
|
sa.Column("message_count", sa.Integer(), nullable=False, server_default=sa.text("0")),
|
|
sa.Column("last_message_at", sa.DateTime(timezone=True), nullable=True),
|
|
sa.Column(
|
|
"created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()
|
|
),
|
|
sa.PrimaryKeyConstraint("conversation_id"),
|
|
)
|
|
op.create_index(
|
|
"ix_ag_conversation_user_active", "ag_conversation", ["user_id", "last_message_at"]
|
|
)
|
|
|
|
op.create_table(
|
|
"ag_message",
|
|
sa.Column("message_id", sa.BigInteger(), nullable=False),
|
|
sa.Column("conversation_id", sa.BigInteger(), nullable=False),
|
|
sa.Column("user_id", sa.BigInteger(), nullable=False),
|
|
sa.Column("role", sa.String(length=16), nullable=False),
|
|
sa.Column("content", sa.Text(), nullable=False),
|
|
sa.Column("call_id", sa.BigInteger(), nullable=True),
|
|
sa.Column("model", sa.String(length=64), nullable=True),
|
|
sa.Column("tokens_in", sa.Integer(), nullable=True),
|
|
sa.Column("tokens_out", sa.Integer(), nullable=True),
|
|
sa.Column("tokens_cached", sa.Integer(), nullable=True),
|
|
sa.Column("latency_ms", sa.Integer(), nullable=True),
|
|
sa.Column("cost_cents", sa.Numeric(14, 6), nullable=True),
|
|
sa.Column("retrieval_trace", postgresql.JSONB(), nullable=False),
|
|
sa.Column("rule_hits", postgresql.JSONB(), nullable=False),
|
|
sa.Column(
|
|
"created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()
|
|
),
|
|
sa.PrimaryKeyConstraint("message_id"),
|
|
sa.ForeignKeyConstraint(
|
|
["conversation_id"], ["ag_conversation.conversation_id"], ondelete="CASCADE"
|
|
),
|
|
)
|
|
op.create_index(
|
|
"ix_ag_message_conversation_created", "ag_message", ["conversation_id", "created_at"]
|
|
)
|
|
op.create_index("ix_ag_message_user_created", "ag_message", ["user_id", "created_at"])
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_index("ix_ag_message_user_created", table_name="ag_message")
|
|
op.drop_index("ix_ag_message_conversation_created", table_name="ag_message")
|
|
op.drop_table("ag_message")
|
|
op.drop_index("ix_ag_conversation_user_active", table_name="ag_conversation")
|
|
op.drop_table("ag_conversation")
|