feat: 增强差旅报销审核流程与票据智能推理

优化本体解析和编排器的差旅场景处理能力,完善报销单草稿
保存和费用明细同步逻辑,前端报销创建页面增加行程推理和
票据审核交互,新增助手会话快照工具函数,补充单元测试。
This commit is contained in:
caoxiaozhu
2026-05-21 16:09:47 +08:00
parent f28d7e6d16
commit e701fa01da
33 changed files with 3033 additions and 337 deletions

View File

@@ -22,6 +22,9 @@ STATEFUL_CONTEXT_KEYS = (
"business_time_context",
)
REVIEW_FLOW_CONTEXT_KEYS = {
"draft_claim_id",
"draft_claim_no",
"draft_status",
"request_context",
"attachment_names",
"attachment_count",
@@ -131,7 +134,11 @@ class AgentConversationService:
resolved_retention_days = retention_days or self._resolve_retention_days()
cutoff = datetime.now(UTC) - timedelta(days=max(1, resolved_retention_days))
stmt = select(AgentConversation).where(AgentConversation.updated_at < cutoff)
expired_conversations = list(self.db.scalars(stmt).all())
expired_conversations = [
conversation
for conversation in self.db.scalars(stmt).all()
if not self._is_saved_conversation(conversation)
]
if not expired_conversations:
return 0
@@ -141,6 +148,13 @@ class AgentConversationService:
self.db.commit()
return len(expired_conversations)
@staticmethod
def _is_saved_conversation(conversation: AgentConversation) -> bool:
if str(conversation.draft_claim_id or "").strip():
return True
state_json = dict(conversation.state_json or {})
return bool(str(state_json.get("draft_claim_id") or "").strip())
def _resolve_retention_days(self) -> int:
try:
settings_row, _ = SettingsService(self.db).ensure_settings_ready()
@@ -232,6 +246,9 @@ class AgentConversationService:
context_json=merged,
message=message,
)
if not should_hydrate_review_flow:
for key in REVIEW_FLOW_CONTEXT_KEYS:
merged.pop(key, None)
merged["conversation_id"] = conversation.conversation_id
merged["conversation_history"] = self.list_message_history(
@@ -264,7 +281,12 @@ class AgentConversationService:
context_json: dict[str, Any],
message: str | None,
) -> bool:
if isinstance(context_json.get("expense_scene_selection"), dict):
return True
if AgentConversationService._resolve_draft_claim_id(context_json):
compact_message = str(message or "").replace(" ", "")
if compact_message and any(keyword in compact_message for keyword in NEW_EXPENSE_PROMPT_KEYWORDS):
return False
return True
if str(context_json.get("review_action") or "").strip():
return True