Files
X-Financial/server/src/app/schemas/steward.py

246 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import Any, Literal
from pydantic import BaseModel, Field
StewardTaskType = str
StewardAssignedAgent = str
StewardPlanningSource = str # 放宽:支持 llm_function_call / rule_fallback / scene_handler:* / context_resume
StewardPlanNextAction = str # 放宽:支持 confirm_flow / confirm_task / delegate_task / none / answer_only
StewardRequestedAction = Literal["preview", "save_draft", "submit"]
StewardSlotDecisionSource = Literal["llm_function_call", "rule_fallback"]
StewardSlotNextAction = Literal["ask_user", "render_preview"]
StewardRuntimeDecisionSource = Literal["llm_function_call", "rule_fallback"]
StewardRuntimeNextAction = Literal[
"plan_new_tasks",
"continue_selected_flow",
"submit_current_application",
"continue_next_task",
"fill_current_slot",
"ask_user",
"cancel_current_action",
"no_op",
]
StewardActionType = str
StewardActionStatus = Literal["completed", "planned", "pending_confirmation", "blocked"]
StewardActionExecutionStatus = Literal["succeeded", "blocked", "needs_confirmation", "failed"]
StewardTaskStatus = Literal[
"planned",
"needs_confirmation",
"ready_to_delegate",
"delegated",
"completed",
"blocked",
]
StewardConfirmationStatus = Literal["pending", "confirmed", "rejected"]
StewardFlowId = str
StewardPendingFlowStatus = Literal["none", "pending", "confirmed", "rejected"]
class StewardAttachmentInput(BaseModel):
name: str = Field(description="附件原始文件名。")
media_type: str = Field(default="", description="附件 MIME 类型。")
ocr_summary: str = Field(default="", description="可选 OCR 摘要。")
ocr_fields: dict[str, Any] = Field(default_factory=dict, description="可选 OCR 结构化字段。")
class StewardPlanRequest(BaseModel):
message: str = Field(description="用户在首页输入的自然语言任务。")
user_id: str | None = Field(default=None, description="当前用户 ID。")
client_now_iso: str | None = Field(default=None, description="客户端当前时间 ISO 字符串。")
attachments: list[StewardAttachmentInput] = Field(default_factory=list, description="随本次输入上传的附件。")
context_json: dict[str, Any] = Field(default_factory=dict, description="调用方上下文。")
class StewardThinkingEvent(BaseModel):
event_id: str = Field(description="过程摘要事件 ID。")
stage: str = Field(description="阶段编码。")
title: str = Field(description="面向用户展示的阶段标题。")
content: str = Field(description="面向用户展示的过程摘要。")
status: str = Field(default="completed", description="事件状态。")
class StewardActionStep(BaseModel):
step_id: str = Field(description="动作步骤 ID。")
action_type: StewardActionType = Field(description="白名单动作类型。")
label: str = Field(description="用户可见动作名称。")
target_task_id: str = Field(default="", description="关联的小财管家任务 ID。")
status: StewardActionStatus = Field(default="planned", description="动作规划状态。")
requires_confirmation: bool = Field(default=False, description="执行前是否需要用户确认。")
depends_on: list[str] = Field(default_factory=list, description="前置动作步骤 ID。")
payload: dict[str, Any] = Field(default_factory=dict, description="动作执行需要的确定性载荷。")
class StewardTask(BaseModel):
task_id: str = Field(description="小财管家任务 ID。")
task_type: StewardTaskType = Field(description="任务类型。")
assigned_agent: StewardAssignedAgent = Field(description="建议分派的下游助手。")
title: str = Field(description="任务标题。")
summary: str = Field(description="任务摘要。")
status: StewardTaskStatus = Field(default="needs_confirmation", description="任务状态。")
confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="识别置信度。")
requested_action: StewardRequestedAction = Field(default="preview", description="用户希望执行的动作:预览、保存草稿或提交。")
ontology_fields: dict[str, str] = Field(default_factory=dict, description="归一化后的业务本体字段。")
missing_fields: list[str] = Field(default_factory=list, description="仍缺失的本体字段。")
confirmation_required: bool = Field(default=True, description="执行前是否需要用户确认。")
action_steps: list[StewardActionStep] = Field(default_factory=list, description="当前任务的白名单动作步骤。")
class StewardAttachmentGroup(BaseModel):
group_id: str = Field(description="附件归集组 ID。")
target_task_id: str | None = Field(default=None, description="建议归属的任务 ID。")
scene: str = Field(description="归集场景编码。")
scene_label: str = Field(description="归集场景展示名。")
attachment_names: list[str] = Field(default_factory=list, description="建议纳入的附件名称。")
excluded_attachment_names: list[str] = Field(default_factory=list, description="建议排除或单独处理的附件名称。")
confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="归集置信度。")
rationale: str = Field(default="", description="归集依据。")
confirmation_required: bool = Field(default=True, description="归集前是否需要用户确认。")
class StewardConfirmationAction(BaseModel):
confirmation_id: str = Field(description="确认动作 ID。")
action_type: str = Field(description="确认动作类型。")
label: str = Field(description="确认按钮文案。")
description: str = Field(default="", description="确认动作说明。")
target_task_id: str | None = Field(default=None, description="关联任务 ID。")
attachment_group_id: str | None = Field(default=None, description="关联附件归集组 ID。")
status: StewardConfirmationStatus = Field(default="pending", description="确认状态。")
payload: dict[str, Any] = Field(default_factory=dict, description="确认后继续执行所需载荷。")
class StewardCandidateFlow(BaseModel):
flow_id: StewardFlowId = Field(description="候选业务流程。")
label: str = Field(description="用户可见候选流程名称。")
confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="候选流程置信度。")
reason: str = Field(default="", description="候选流程依据。")
ontology_fields: dict[str, str] = Field(default_factory=dict, description="候选流程可继承的 canonical ontology 字段。")
missing_fields: list[str] = Field(default_factory=list, description="候选流程仍缺失的 canonical ontology 字段。")
class StewardPendingFlowConfirmation(BaseModel):
status: StewardPendingFlowStatus = Field(default="none", description="候选流程确认状态。")
source_message: str = Field(default="", description="触发候选流程确认的用户原始输入。")
reason: str = Field(default="", description="需要确认流程方向的原因。")
candidate_flows: list[StewardCandidateFlow] = Field(default_factory=list, description="候选业务流程。")
class StewardPlanResponse(BaseModel):
plan_id: str = Field(description="小财管家计划 ID。")
plan_status: str = Field(default="needs_confirmation", description="计划状态。")
planning_source: StewardPlanningSource = Field(default="rule_fallback", description="计划生成来源。")
next_action: StewardPlanNextAction = Field(default="confirm_task", description="计划完成后的下一步动作。")
conversation_id: str = Field(default="", description="持久化会话 ID。")
steward_state: dict[str, Any] = Field(default_factory=dict, description="小财管家跨轮业务状态。")
summary: str = Field(description="计划摘要。")
thinking_events: list[StewardThinkingEvent] = Field(default_factory=list, description="过程摘要事件。")
tasks: list[StewardTask] = Field(default_factory=list, description="拆解后的任务。")
action_steps: list[StewardActionStep] = Field(default_factory=list, description="本计划的全量白名单动作步骤。")
attachment_groups: list[StewardAttachmentGroup] = Field(default_factory=list, description="附件归集建议。")
confirmation_groups: list[StewardConfirmationAction] = Field(default_factory=list, description="等待用户确认的动作。")
pending_flow_confirmation: StewardPendingFlowConfirmation = Field(
default_factory=StewardPendingFlowConfirmation,
description="申请/报销流程不明确时等待用户确认的候选流程。",
)
candidate_flows: list[StewardCandidateFlow] = Field(default_factory=list, description="等待用户确认的候选流程快捷列表。")
model_call_traces: list[dict[str, Any]] = Field(default_factory=list, description="模型工具调用轨迹。")
suggested_prompts: list[str] = Field(
default_factory=list,
description="当 plan_status 为 off_topic 等场景时,给用户的推荐话术示例。",
)
class StewardActionExecuteRequest(BaseModel):
action_type: str = Field(description="待执行的白名单动作类型。未知动作会被 executor 阻断。")
message: str = Field(default="", description="触发该动作的用户原始话术。")
plan_id: str = Field(default="", description="关联的小财管家计划 ID。")
conversation_id: str | None = Field(default=None, description="关联会话 ID。")
task: StewardTask | None = Field(default=None, description="动作所属任务快照。")
action_step: StewardActionStep | None = Field(default=None, description="规划侧生成的动作步骤快照。")
confirmed: bool = Field(default=False, description="用户是否已确认执行该动作。")
context_json: dict[str, Any] = Field(default_factory=dict, description="前端或运行时补充上下文。")
client_trace_id: str = Field(
default="",
max_length=120,
description="前端稳定幂等 ID申请预览签发、保存和提交动作必须显式提供。",
)
decision_id: str = Field(
default="",
max_length=36,
description="服务端签发的申请预览决策 ID保存和提交申请时必须显式提供。",
)
class StewardActionExecuteResponse(BaseModel):
action_type: str = Field(description="实际处理的动作类型。")
status: StewardActionExecutionStatus = Field(description="动作执行状态。")
execution_source: str = Field(default="langgraph_action", description="执行来源或兜底来源。")
fallback_used: bool = Field(default=False, description="是否走了规则兜底执行。")
requires_confirmation: bool = Field(default=False, description="是否仍需用户确认。")
message: str = Field(description="面向用户展示的执行结果。")
blocked_reasons: list[str] = Field(default_factory=list, description="阻断原因。")
result_payload: dict[str, Any] = Field(default_factory=dict, description="业务服务返回的结构化结果。")
trace: list[dict[str, Any]] = Field(default_factory=list, description="动作执行轨迹。")
class StewardSlotOption(BaseModel):
label: str = Field(description="用户可见选项文案。")
value: str = Field(description="写回本体字段的选项值。")
field_key: str = Field(description="对应 canonical ontology field。")
description: str = Field(default="", description="选项说明。")
class StewardSlotDecisionRequest(BaseModel):
task_type: StewardTaskType = Field(description="当前小财管家正在推进的任务类型。")
user_message: str = Field(description="用户原始话术或小财管家携带的任务上下文。")
ontology_fields: dict[str, str] = Field(default_factory=dict, description="当前已抽取的 canonical ontology 字段。")
missing_fields: list[str] = Field(default_factory=list, description="上游意图识别给出的 canonical 缺失字段。")
task_context: dict[str, Any] = Field(default_factory=dict, description="当前任务、附件、申请预览等上下文。")
class StewardSlotDecisionResponse(BaseModel):
decision_source: StewardSlotDecisionSource = Field(default="rule_fallback", description="字段决策来源。")
next_action: StewardSlotNextAction = Field(description="下一步应追问用户还是展示核对结果。")
required_fields: list[str] = Field(default_factory=list, description="模型认为当前业务需要的 canonical 字段。")
missing_fields: list[str] = Field(default_factory=list, description="当前仍缺失的 canonical 字段。")
question: str = Field(default="", description="需要追问时展示给用户的问题。")
options: list[StewardSlotOption] = Field(default_factory=list, description="可直接选择的补充选项。")
rationale: str = Field(default="", description="面向用户的简短判断依据,不暴露推理链。")
model_call_traces: list[dict[str, Any]] = Field(default_factory=list, description="模型工具调用轨迹。")
class StewardRuntimeDecisionRequest(BaseModel):
user_message: str = Field(description="用户当前输入。")
session_type: str = Field(default="steward", description="当前前端会话类型。")
runtime_state: dict[str, Any] = Field(default_factory=dict, description="小财管家运行时上下文。")
context_json: dict[str, Any] = Field(default_factory=dict, description="调用方补充上下文。")
class StewardRuntimeDecisionResponse(BaseModel):
decision_source: StewardRuntimeDecisionSource = Field(default="rule_fallback", description="运行时决策来源。")
next_action: StewardRuntimeNextAction = Field(description="小财管家下一步动作。")
target_task_id: str = Field(default="", description="关联的小财管家任务 ID。")
target_message_id: str = Field(default="", description="关联的前端消息 ID。")
field_key: str = Field(default="", description="补字段时对应 canonical ontology field。")
field_value: str = Field(default="", description="补字段时用户提供的字段值。")
confirmation_required: bool = Field(default=False, description="执行该动作前是否仍需要用户二次确认。")
question: str = Field(default="", description="需要追问用户时展示的问题。")
response_text: str = Field(default="", description="无需调用工具时给用户的简短回复。")
rationale: str = Field(default="", description="面向用户的简短判断依据,不暴露推理链。")
steward_state: dict[str, Any] = Field(default_factory=dict, description="小财管家更新后的跨轮业务状态。")
model_call_traces: list[dict[str, Any]] = Field(default_factory=list, description="模型工具调用轨迹。")
class StewardFlowStatePatch(BaseModel):
active_flow: StewardFlowId = Field(description="本轮对话正在推进的业务流程。")
flow_id: StewardFlowId = Field(description="需要合并字段的目标业务流程。")
intent: str = Field(default="", description="本轮识别出的业务意图。")
status: str = Field(default="collecting", description="流程状态。")
fields: dict[str, Any] = Field(default_factory=dict, description="待写入流程的本体字段 patch。")
missing_fields: list[str] = Field(default_factory=list, description="仍缺失的 canonical ontology 字段。")
application_claim_id: str = Field(default="", description="出差申请流程已生成的申请单 ID。")
linked_application_claim_id: str = Field(default="", description="报销流程关联的申请单 ID。")
attachments: list[dict[str, Any]] = Field(default_factory=list, description="流程关联附件摘要。")
evidence: list[dict[str, Any]] = Field(default_factory=list, description="字段来源证据。")