feat(web): AI 工作台意图规划与规划思考模型
- 新增 workbenchAiIntentPlannerModel,基于 LLM function_call 解析建单/草稿/提交意图,区分 model 与 rule_fallback 来源 - 新增 workbenchAiPlanningThinkingModel 合并规划思考事件流,按 eventId 去重合并 - application gate/preview 模型接入意图规划,usePersonalWorkbenchAiMode/useWorkbenchAiStewardFlow/useWorkbenchAiActionRouter 链路适配,支持上下文提交 - steward 服务与 stewardPlanModel 适配新动作结构,receipt-folder-view 微调样式 - 新增 intent-planner-model/application-context-submit/steward-actions-service 测试,更新 gate-model/action-router/plan-message-copy/fast-preview 测试
This commit is contained in:
@@ -27,6 +27,10 @@ import {
|
||||
extractInlineApplicationDraftPayload
|
||||
} from './workbenchAiApplicationPreviewModel.js'
|
||||
import { AI_ATTACHMENT_ASSOCIATION_CONFIRM_ACTION } from './workbenchAiMessageModel.js'
|
||||
import {
|
||||
completeWorkbenchAiThinkingEvents,
|
||||
mergeWorkbenchAiThinkingEvents
|
||||
} from './workbenchAiPlanningThinkingModel.js'
|
||||
import {
|
||||
isOrphanInlineApplicationPreviewMessage,
|
||||
resolveInlineApplicationPreviewTextAction,
|
||||
@@ -202,6 +206,26 @@ export function useWorkbenchAiApplicationPreviewFlow({
|
||||
].join('\n\n')
|
||||
}
|
||||
|
||||
function hasSavedInlineApplicationDraft(message = {}, options = {}) {
|
||||
const draftPayload = message?.draftPayload || options.draftPayload || null
|
||||
if (!draftPayload || typeof draftPayload !== 'object') {
|
||||
return false
|
||||
}
|
||||
const claimId = String(draftPayload.claim_id || draftPayload.claimId || '').trim()
|
||||
const claimNo = String(draftPayload.claim_no || draftPayload.claimNo || '').trim()
|
||||
const status = String(draftPayload.status || '').trim().toLowerCase()
|
||||
return Boolean((claimId || claimNo) && status !== 'submitted')
|
||||
}
|
||||
|
||||
function isContextualInlineApplicationSubmitText(text = '') {
|
||||
const normalized = String(text || '').replace(/\s+/g, '').trim()
|
||||
return Boolean(
|
||||
normalized &&
|
||||
/提交/.test(normalized) &&
|
||||
/(这个|这张|当前|上面|上述|刚才|申请单|单据|草稿|领导|审核|审批)/.test(normalized)
|
||||
)
|
||||
}
|
||||
|
||||
function resolveLatestInlineApplicationPreviewMessage() {
|
||||
return resolveLatestApplicationPreviewMessage(conversationMessages.value)
|
||||
}
|
||||
@@ -334,7 +358,12 @@ export function useWorkbenchAiApplicationPreviewFlow({
|
||||
return true
|
||||
}
|
||||
|
||||
if (isSubmit && !options.confirmed) {
|
||||
const shouldSubmitSavedDraftDirectly = isSubmit &&
|
||||
!options.confirmed &&
|
||||
hasSavedInlineApplicationDraft(targetMessage, options) &&
|
||||
isContextualInlineApplicationSubmitText(userText)
|
||||
|
||||
if (isSubmit && !options.confirmed && !shouldSubmitSavedDraftDirectly) {
|
||||
requestInlineApplicationSubmitConfirmation(targetMessage, { ...options, userText })
|
||||
return true
|
||||
}
|
||||
@@ -474,11 +503,16 @@ export function useWorkbenchAiApplicationPreviewFlow({
|
||||
pushInlineUserMessage(options.userMessage || '确认发起出差申请')
|
||||
}
|
||||
|
||||
const existingPendingMessage = options.pendingMessageId
|
||||
? conversationMessages.value.find((item) => item.id === options.pendingMessageId)
|
||||
: null
|
||||
const previousThinkingEvents = completeWorkbenchAiThinkingEvents(resolveInlineThinkingEvents(existingPendingMessage))
|
||||
const pendingMessage = createInlineMessage('assistant', '正在生成申请核对表,请稍等...', {
|
||||
id: options.pendingMessageId,
|
||||
pending: true,
|
||||
stewardPlan: {
|
||||
streamStatus: 'streaming',
|
||||
thinkingEvents: [
|
||||
thinkingEvents: mergeWorkbenchAiThinkingEvents(previousThinkingEvents, [
|
||||
{
|
||||
eventId: 'application-preview-build',
|
||||
title: '整理申请表字段',
|
||||
@@ -491,19 +525,25 @@ export function useWorkbenchAiApplicationPreviewFlow({
|
||||
content: '正在刷新差旅规则和费用测算,完成后会直接展示核对表。',
|
||||
status: 'pending'
|
||||
}
|
||||
]
|
||||
])
|
||||
}
|
||||
})
|
||||
conversationMessages.value.push(pendingMessage)
|
||||
if (options.pendingMessageId) {
|
||||
replaceInlineMessage(options.pendingMessageId, pendingMessage)
|
||||
} else {
|
||||
conversationMessages.value.push(pendingMessage)
|
||||
}
|
||||
persistCurrentConversation()
|
||||
scrollInlineConversationToBottom()
|
||||
|
||||
try {
|
||||
const preview = await refreshApplicationPreviewEstimate(
|
||||
buildInlineApplicationPreview(expenseTypeLabel || expenseType, previewSourceText, currentUser.value || {})
|
||||
buildInlineApplicationPreview(expenseTypeLabel || expenseType, previewSourceText, currentUser.value || {}, {
|
||||
ontologyFields: options.ontologyFields
|
||||
})
|
||||
)
|
||||
const content = buildLocalApplicationPreviewMessage(preview)
|
||||
replaceInlineMessage(pendingMessage.id, createInlineMessage('assistant', content, {
|
||||
const previewMessage = createInlineMessage('assistant', content, {
|
||||
id: pendingMessage.id,
|
||||
applicationPreview: preview,
|
||||
suggestedActions: buildInlineApplicationPreviewSuggestedActions(preview),
|
||||
@@ -512,7 +552,20 @@ export function useWorkbenchAiApplicationPreviewFlow({
|
||||
thinkingEvents: completeInlineThinkingEvents(resolveInlineThinkingEvents(pendingMessage))
|
||||
},
|
||||
text: content
|
||||
}))
|
||||
})
|
||||
replaceInlineMessage(pendingMessage.id, previewMessage)
|
||||
if (options.autoSubmit && normalizeApplicationPreview(preview).readyToSubmit) {
|
||||
await executeInlineApplicationPreviewAction(AI_APPLICATION_ACTION_SUBMIT, previewMessage, {
|
||||
confirmed: true,
|
||||
skipUserMessage: true,
|
||||
userText: options.userMessage || '直接提交'
|
||||
})
|
||||
} else if (options.autoSaveDraft) {
|
||||
await executeInlineApplicationPreviewAction(AI_APPLICATION_ACTION_SAVE_DRAFT, previewMessage, {
|
||||
skipUserMessage: true,
|
||||
userText: options.userMessage || '保存草稿'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
replaceInlineMessage(pendingMessage.id, createInlineMessage('assistant', error?.message || '申请核对表生成失败,请稍后重试。', {
|
||||
id: pendingMessage.id,
|
||||
|
||||
Reference in New Issue
Block a user