174 lines
7.5 KiB
JavaScript
174 lines
7.5 KiB
JavaScript
|
|
import {
|
|||
|
|
ASSISTANT_SCOPE_ACTION_SWITCH,
|
|||
|
|
} from '../../utils/assistantSessionScope.js'
|
|||
|
|
import {
|
|||
|
|
SESSION_TYPE_APPLICATION,
|
|||
|
|
SESSION_TYPE_EXPENSE
|
|||
|
|
} from './travelReimbursementConversationModel.js'
|
|||
|
|
|
|||
|
|
const TASK_TYPE_LABELS = {
|
|||
|
|
expense_application: '费用申请',
|
|||
|
|
reimbursement: '费用报销'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const AGENT_LABELS = {
|
|||
|
|
application_assistant: '申请助手',
|
|||
|
|
reimbursement_assistant: '报销助手'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function buildStewardPlanRequest({ rawText = '', files = [], currentUser = {} } = {}) {
|
|||
|
|
const safeFiles = Array.isArray(files) ? files : []
|
|||
|
|
return {
|
|||
|
|
message: String(rawText || '').trim(),
|
|||
|
|
user_id: String(currentUser.username || currentUser.name || 'anonymous').trim() || 'anonymous',
|
|||
|
|
client_now_iso: new Date().toISOString(),
|
|||
|
|
attachments: safeFiles.map((file) => ({
|
|||
|
|
name: String(file?.name || '').trim(),
|
|||
|
|
media_type: String(file?.type || '').trim()
|
|||
|
|
})).filter((item) => item.name),
|
|||
|
|
context_json: {
|
|||
|
|
entry_source: 'workbench',
|
|||
|
|
session_type: 'steward',
|
|||
|
|
role_codes: Array.isArray(currentUser.roleCodes) ? currentUser.roleCodes : [],
|
|||
|
|
username: currentUser.username || '',
|
|||
|
|
name: currentUser.name || currentUser.username || '',
|
|||
|
|
department_name: currentUser.departmentName || currentUser.department || '',
|
|||
|
|
employee_grade: currentUser.grade || ''
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function normalizeStewardPlan(rawPlan = {}, options = {}) {
|
|||
|
|
const visibleThinkingEventCount = Number.isFinite(options.visibleThinkingEventCount)
|
|||
|
|
? Number(options.visibleThinkingEventCount)
|
|||
|
|
: Number(rawPlan.visibleThinkingEventCount || rawPlan.visible_thinking_event_count || 0)
|
|||
|
|
return {
|
|||
|
|
planId: String(rawPlan.plan_id || rawPlan.planId || ''),
|
|||
|
|
planStatus: String(rawPlan.plan_status || rawPlan.planStatus || ''),
|
|||
|
|
summary: String(rawPlan.summary || ''),
|
|||
|
|
visibleThinkingEventCount,
|
|||
|
|
thinkingEvents: Array.isArray(rawPlan.thinking_events)
|
|||
|
|
? rawPlan.thinking_events.map((item) => ({
|
|||
|
|
eventId: String(item.event_id || item.eventId || ''),
|
|||
|
|
stage: String(item.stage || ''),
|
|||
|
|
title: String(item.title || ''),
|
|||
|
|
content: String(item.content || ''),
|
|||
|
|
status: String(item.status || 'completed')
|
|||
|
|
}))
|
|||
|
|
: [],
|
|||
|
|
tasks: Array.isArray(rawPlan.tasks)
|
|||
|
|
? rawPlan.tasks.map((item) => ({
|
|||
|
|
taskId: String(item.task_id || item.taskId || ''),
|
|||
|
|
taskType: String(item.task_type || item.taskType || ''),
|
|||
|
|
taskTypeLabel: TASK_TYPE_LABELS[String(item.task_type || item.taskType || '')] || '财务任务',
|
|||
|
|
assignedAgent: String(item.assigned_agent || item.assignedAgent || ''),
|
|||
|
|
assignedAgentLabel: AGENT_LABELS[String(item.assigned_agent || item.assignedAgent || '')] || '财务助手',
|
|||
|
|
title: String(item.title || ''),
|
|||
|
|
summary: String(item.summary || ''),
|
|||
|
|
status: String(item.status || ''),
|
|||
|
|
confidence: Number(item.confidence || 0),
|
|||
|
|
ontologyFields: item.ontology_fields || item.ontologyFields || {},
|
|||
|
|
missingFields: Array.isArray(item.missing_fields || item.missingFields)
|
|||
|
|
? item.missing_fields || item.missingFields
|
|||
|
|
: [],
|
|||
|
|
confirmationRequired: item.confirmation_required ?? item.confirmationRequired ?? true
|
|||
|
|
}))
|
|||
|
|
: [],
|
|||
|
|
attachmentGroups: Array.isArray(rawPlan.attachment_groups)
|
|||
|
|
? rawPlan.attachment_groups.map((item) => ({
|
|||
|
|
groupId: String(item.group_id || item.groupId || ''),
|
|||
|
|
targetTaskId: String(item.target_task_id || item.targetTaskId || ''),
|
|||
|
|
scene: String(item.scene || ''),
|
|||
|
|
sceneLabel: String(item.scene_label || item.sceneLabel || ''),
|
|||
|
|
attachmentNames: Array.isArray(item.attachment_names || item.attachmentNames)
|
|||
|
|
? item.attachment_names || item.attachmentNames
|
|||
|
|
: [],
|
|||
|
|
excludedAttachmentNames: Array.isArray(item.excluded_attachment_names || item.excludedAttachmentNames)
|
|||
|
|
? item.excluded_attachment_names || item.excludedAttachmentNames
|
|||
|
|
: [],
|
|||
|
|
confidence: Number(item.confidence || 0),
|
|||
|
|
rationale: String(item.rationale || ''),
|
|||
|
|
confirmationRequired: item.confirmation_required ?? item.confirmationRequired ?? true
|
|||
|
|
}))
|
|||
|
|
: [],
|
|||
|
|
confirmationGroups: Array.isArray(rawPlan.confirmation_groups)
|
|||
|
|
? rawPlan.confirmation_groups
|
|||
|
|
: []
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function buildStewardPlanMessageText(plan) {
|
|||
|
|
const normalized = normalizeStewardPlan(plan)
|
|||
|
|
const taskLines = normalized.tasks.map((task, index) =>
|
|||
|
|
`${index + 1}. ${task.title || task.taskTypeLabel},交给${task.assignedAgentLabel}。`
|
|||
|
|
)
|
|||
|
|
return [
|
|||
|
|
'**小财管家已完成任务拆解。**',
|
|||
|
|
'',
|
|||
|
|
normalized.summary || `我识别到 ${normalized.tasks.length} 个待处理任务,请确认后继续执行。`,
|
|||
|
|
'',
|
|||
|
|
...taskLines
|
|||
|
|
].join('\n')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function buildStewardSuggestedActions(plan) {
|
|||
|
|
const normalized = normalizeStewardPlan(plan)
|
|||
|
|
const taskById = new Map(normalized.tasks.map((task) => [task.taskId, task]))
|
|||
|
|
const groupById = new Map(normalized.attachmentGroups.map((group) => [group.groupId, group]))
|
|||
|
|
return normalized.confirmationGroups.map((action) => {
|
|||
|
|
const actionType = String(action.action_type || action.actionType || '').trim()
|
|||
|
|
const taskId = String(action.target_task_id || action.targetTaskId || '').trim()
|
|||
|
|
const groupId = String(action.attachment_group_id || action.attachmentGroupId || '').trim()
|
|||
|
|
const task = taskById.get(taskId)
|
|||
|
|
const group = groupById.get(groupId)
|
|||
|
|
const targetSessionType = actionType === 'confirm_create_application'
|
|||
|
|
? SESSION_TYPE_APPLICATION
|
|||
|
|
: SESSION_TYPE_EXPENSE
|
|||
|
|
return {
|
|||
|
|
label: String(action.label || '确认继续处理'),
|
|||
|
|
description: String(action.description || ''),
|
|||
|
|
icon: actionType === 'confirm_create_application'
|
|||
|
|
? 'mdi mdi-file-plus-outline'
|
|||
|
|
: actionType === 'confirm_attachment_group'
|
|||
|
|
? 'mdi mdi-folder-check-outline'
|
|||
|
|
: 'mdi mdi-receipt-text-plus-outline',
|
|||
|
|
action_type: ASSISTANT_SCOPE_ACTION_SWITCH,
|
|||
|
|
payload: {
|
|||
|
|
session_type: targetSessionType,
|
|||
|
|
carry_text: buildStewardCarryText(actionType, task, group),
|
|||
|
|
carry_files: actionType !== 'confirm_create_application',
|
|||
|
|
auto_submit: true,
|
|||
|
|
steward_confirmation_id: String(action.confirmation_id || action.confirmationId || ''),
|
|||
|
|
steward_plan_id: normalized.planId
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function buildStewardCarryText(actionType, task, group) {
|
|||
|
|
if (actionType === 'confirm_attachment_group' && group) {
|
|||
|
|
return [
|
|||
|
|
`我确认将以下附件归集为${group.sceneLabel || '当前报销任务'},请继续整理报销核对信息。`,
|
|||
|
|
`附件:${group.attachmentNames.join('、') || '待确认'}`,
|
|||
|
|
group.excludedAttachmentNames.length
|
|||
|
|
? `暂不归集:${group.excludedAttachmentNames.join('、')}`
|
|||
|
|
: ''
|
|||
|
|
].filter(Boolean).join('\n')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!task) {
|
|||
|
|
return '我确认继续处理这项财务任务,请按现有流程核对信息。'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const fields = Object.entries(task.ontologyFields || {})
|
|||
|
|
.filter(([, value]) => String(value || '').trim())
|
|||
|
|
.map(([key, value]) => `${key}: ${value}`)
|
|||
|
|
return [
|
|||
|
|
`我确认处理“小财管家”识别的任务:${task.title || task.taskTypeLabel}。`,
|
|||
|
|
task.summary ? `任务摘要:${task.summary}` : '',
|
|||
|
|
fields.length ? `本体字段:${fields.join(';')}` : '',
|
|||
|
|
task.missingFields.length ? `待补充字段:${task.missingFields.join('、')}` : '',
|
|||
|
|
'请按现有流程生成核对结果,并在需要入库、绑定附件或提交审批前让我再次确认。'
|
|||
|
|
].filter(Boolean).join('\n')
|
|||
|
|
}
|