- useWorkbenchAiApplicationPreviewFlow/useWorkbenchAiActionRouter/useWorkbenchAiCommandIntents 支持 task1 完成后自动推进 task2,确认按钮直接拉起申请预览,草稿/提交成功后继续推进下一 task - workbenchAiIntentPlannerModel/workbenchAiMessageModel/workbenchAiCommandIntentModel 适配多 task 意图规划与消息结构 - aiApplicationPreviewActions/aiApplicationPrecheckModel/aiExpenseDraftModel/aiWorkbenchConversationStore 草稿与会话存储适配 - PersonalWorkbenchAiMode 与样式适配,更新 preview-actions/expense-draft/conversation-store/fast-preview/action-router/command-intent/intent-planner 测试
478 lines
21 KiB
JavaScript
478 lines
21 KiB
JavaScript
import assert from 'node:assert/strict'
|
||
import { readFileSync } from 'node:fs'
|
||
import test from 'node:test'
|
||
import { fileURLToPath } from 'node:url'
|
||
|
||
import {
|
||
WORKBENCH_AI_INTENT_SOURCE_MODEL,
|
||
WORKBENCH_AI_INTENT_SOURCE_RULE_FALLBACK,
|
||
WORKBENCH_AI_STEP_BUILD_APPLICATION_PREVIEW,
|
||
WORKBENCH_AI_STEP_SAVE_APPLICATION_DRAFT,
|
||
WORKBENCH_AI_STEP_RUN_DUPLICATE_PRECHECK,
|
||
WORKBENCH_AI_STEP_SUBMIT_APPLICATION,
|
||
WORKBENCH_AI_STEP_VALIDATE_REQUIRED_FIELDS,
|
||
buildRuleFallbackWorkbenchAiIntentPlan,
|
||
isLowConfidenceTravelApplicationPlan,
|
||
normalizeWorkbenchAiIntentPlan,
|
||
resolveExecutableTravelApplicationPlan,
|
||
shouldRequestWorkbenchAiIntentPlan
|
||
} from '../src/composables/workbenchAiMode/workbenchAiIntentPlannerModel.js'
|
||
import { buildInlineApplicationPreview } from '../src/composables/workbenchAiMode/workbenchAiApplicationPreviewModel.js'
|
||
import { createWorkbenchAiMessageRuntime } from '../src/composables/workbenchAiMode/workbenchAiMessageModel.js'
|
||
|
||
const personalWorkbenchAiModeScript = readFileSync(
|
||
fileURLToPath(new URL('../src/composables/workbenchAiMode/usePersonalWorkbenchAiMode.js', import.meta.url)),
|
||
'utf8'
|
||
)
|
||
const stewardFlowScript = readFileSync(
|
||
fileURLToPath(new URL('../src/composables/workbenchAiMode/useWorkbenchAiStewardFlow.js', import.meta.url)),
|
||
'utf8'
|
||
)
|
||
const applicationPreviewFlowScript = readFileSync(
|
||
fileURLToPath(new URL('../src/composables/workbenchAiMode/useWorkbenchAiApplicationPreviewFlow.js', import.meta.url)),
|
||
'utf8'
|
||
)
|
||
const planningThinkingModelScript = readFileSync(
|
||
fileURLToPath(new URL('../src/composables/workbenchAiMode/workbenchAiPlanningThinkingModel.js', import.meta.url)),
|
||
'utf8'
|
||
)
|
||
|
||
test('workbench AI intent planner normalizes model travel application submit plan into executable steps', () => {
|
||
const plan = normalizeWorkbenchAiIntentPlan({
|
||
planning_source: 'llm_function_call',
|
||
tasks: [{
|
||
task_type: 'expense_application',
|
||
assigned_agent: 'application_assistant',
|
||
requested_action: 'submit',
|
||
confidence: 0.91,
|
||
ontology_fields: {
|
||
time_range: '2026-02-20 至 2026-02-23',
|
||
location: '上海',
|
||
reason: '辅助国网仿生产服务器部署',
|
||
transport_mode: '火车'
|
||
}
|
||
}]
|
||
}, {
|
||
prompt: '去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交'
|
||
})
|
||
|
||
assert.equal(plan.source, WORKBENCH_AI_INTENT_SOURCE_MODEL)
|
||
assert.equal(plan.intent, 'create_travel_application')
|
||
assert.equal(plan.requestedAction, 'submit')
|
||
assert.deepEqual(plan.steps, [
|
||
WORKBENCH_AI_STEP_BUILD_APPLICATION_PREVIEW,
|
||
WORKBENCH_AI_STEP_VALIDATE_REQUIRED_FIELDS,
|
||
WORKBENCH_AI_STEP_RUN_DUPLICATE_PRECHECK,
|
||
WORKBENCH_AI_STEP_SUBMIT_APPLICATION
|
||
])
|
||
assert.deepEqual(plan.ontologyFields, {
|
||
time_range: '2026-02-20 至 2026-02-23',
|
||
location: '上海',
|
||
reason: '辅助国网仿生产服务器部署',
|
||
transport_mode: '火车'
|
||
})
|
||
assert.deepEqual(plan.slots, {
|
||
timeRange: '2026-02-20 至 2026-02-23',
|
||
location: '上海',
|
||
reason: '辅助国网仿生产服务器部署',
|
||
transportMode: '火车'
|
||
})
|
||
})
|
||
|
||
test('workbench AI intent planner keeps reimbursement task after first application task', () => {
|
||
const reimbursementTask = {
|
||
task_id: 'task-reimbursement-2',
|
||
task_type: 'reimbursement',
|
||
assigned_agent: 'reimbursement_assistant',
|
||
title: '业务招待费报销',
|
||
summary: '报销昨天的业务招待费 2000 元',
|
||
requested_action: 'preview',
|
||
confidence: 0.9,
|
||
ontology_fields: {
|
||
expense_type: 'entertainment',
|
||
expense_type_label: '业务招待费',
|
||
time_range: '2026-06-25',
|
||
amount: '2000元',
|
||
reason: '业务招待'
|
||
},
|
||
missing_fields: []
|
||
}
|
||
const plan = normalizeWorkbenchAiIntentPlan({
|
||
planning_source: 'llm_function_call',
|
||
tasks: [{
|
||
task_id: 'task-application-1',
|
||
task_type: 'expense_application',
|
||
assigned_agent: 'application_assistant',
|
||
requested_action: 'preview',
|
||
confidence: 0.93,
|
||
ontology_fields: {
|
||
expense_type: 'travel',
|
||
time_range: '2026-02-20 至 2026-02-23',
|
||
location: '上海',
|
||
reason: '服务国网服务器部署'
|
||
},
|
||
missing_fields: ['transport_mode']
|
||
}, reimbursementTask]
|
||
}, {
|
||
prompt: '2月20-23日去上海出差3天,服务国网服务器部署,并且报销昨天的业务招待费2000元'
|
||
})
|
||
|
||
assert.deepEqual(plan.stewardRemainingTasks, [reimbursementTask])
|
||
assert.deepEqual(resolveExecutableTravelApplicationPlan(plan).stewardRemainingTasks, [reimbursementTask])
|
||
})
|
||
|
||
test('workbench AI intent planner prefers server action steps when present', () => {
|
||
const plan = normalizeWorkbenchAiIntentPlan({
|
||
planning_source: 'llm_function_call',
|
||
tasks: [{
|
||
task_type: 'expense_application',
|
||
assigned_agent: 'application_assistant',
|
||
requested_action: 'submit',
|
||
confidence: 0.91,
|
||
ontology_fields: {
|
||
time_range: '2026-02-20 至 2026-02-23',
|
||
location: '上海',
|
||
reason: '辅助国网仿生产服务器部署',
|
||
transport_mode: '火车'
|
||
},
|
||
action_steps: [
|
||
{ action_type: 'fill_application_fields' },
|
||
{ action_type: 'build_application_preview' },
|
||
{ action_type: 'validate_required_fields' },
|
||
{ action_type: 'save_application_draft' }
|
||
]
|
||
}]
|
||
}, {
|
||
prompt: '2026-02-20 至 2026-02-23,去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交'
|
||
})
|
||
|
||
assert.deepEqual(plan.steps, [
|
||
WORKBENCH_AI_STEP_BUILD_APPLICATION_PREVIEW,
|
||
WORKBENCH_AI_STEP_VALIDATE_REQUIRED_FIELDS,
|
||
WORKBENCH_AI_STEP_SAVE_APPLICATION_DRAFT
|
||
])
|
||
})
|
||
|
||
test('workbench AI intent planner falls back to rule plan for compact travel direct submit', () => {
|
||
const plan = buildRuleFallbackWorkbenchAiIntentPlan('去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交')
|
||
|
||
assert.equal(plan.source, WORKBENCH_AI_INTENT_SOURCE_RULE_FALLBACK)
|
||
assert.equal(plan.intent, 'create_travel_application')
|
||
assert.equal(plan.requestedAction, 'submit')
|
||
assert.deepEqual(plan.steps, [
|
||
WORKBENCH_AI_STEP_BUILD_APPLICATION_PREVIEW,
|
||
WORKBENCH_AI_STEP_VALIDATE_REQUIRED_FIELDS,
|
||
WORKBENCH_AI_STEP_RUN_DUPLICATE_PRECHECK,
|
||
WORKBENCH_AI_STEP_SUBMIT_APPLICATION
|
||
])
|
||
})
|
||
|
||
test('workbench AI intent planner detects compact travel save-draft variant before rules are enough', () => {
|
||
const prompt = '2026-02-20 至 2026-02-23,上海出差,国网仿生产服务器部署,火车,保存草稿。'
|
||
const plan = buildRuleFallbackWorkbenchAiIntentPlan(prompt)
|
||
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan(prompt), true)
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('帮我查询上海差旅标准'), true)
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('1'), false)
|
||
assert.equal(plan.source, WORKBENCH_AI_INTENT_SOURCE_RULE_FALLBACK)
|
||
assert.equal(plan.intent, 'create_travel_application')
|
||
assert.equal(plan.requestedAction, 'save_draft')
|
||
assert.deepEqual(plan.steps, [
|
||
WORKBENCH_AI_STEP_BUILD_APPLICATION_PREVIEW,
|
||
WORKBENCH_AI_STEP_VALIDATE_REQUIRED_FIELDS,
|
||
WORKBENCH_AI_STEP_SAVE_APPLICATION_DRAFT
|
||
])
|
||
assert.deepEqual(resolveExecutableTravelApplicationPlan(plan), {
|
||
expenseType: 'travel',
|
||
expenseTypeLabel: '差旅费',
|
||
sourceText: prompt,
|
||
ontologyFields: {},
|
||
autoSubmit: false,
|
||
autoSaveDraft: true,
|
||
requestedSubmit: false,
|
||
submitRequiresConfirmation: false
|
||
})
|
||
})
|
||
|
||
test('workbench AI intent planner turns model fields and action into executable application preview payload', () => {
|
||
const prompt = '2026-02-20 至 2026-02-23,上海出差,国网仿生产服务器部署,火车,保存草稿。'
|
||
const plan = normalizeWorkbenchAiIntentPlan({
|
||
planning_source: 'llm_function_call',
|
||
tasks: [{
|
||
task_type: 'expense_application',
|
||
assigned_agent: 'application_assistant',
|
||
requested_action: 'save_draft',
|
||
confidence: 0.95,
|
||
ontology_fields: {
|
||
time_range: '2026-02-20 至 2026-02-23',
|
||
location: '上海',
|
||
reason: '国网仿生产服务器部署',
|
||
transport_mode: '火车'
|
||
},
|
||
missing_fields: []
|
||
}]
|
||
}, { prompt })
|
||
|
||
assert.deepEqual(resolveExecutableTravelApplicationPlan(plan), {
|
||
expenseType: 'travel',
|
||
expenseTypeLabel: '差旅费',
|
||
sourceText: prompt,
|
||
ontologyFields: {
|
||
time_range: '2026-02-20 至 2026-02-23',
|
||
location: '上海',
|
||
reason: '国网仿生产服务器部署',
|
||
transport_mode: '火车'
|
||
},
|
||
autoSubmit: false,
|
||
autoSaveDraft: true,
|
||
requestedSubmit: false,
|
||
submitRequiresConfirmation: false
|
||
})
|
||
})
|
||
|
||
test('workbench AI intent planner turns single application candidate flow into executable preview payload', () => {
|
||
const prompt = '2026-02-20 至 2026-02-23,去上海出差,辅助国网仿生产服务器部署,交通火车'
|
||
const plan = normalizeWorkbenchAiIntentPlan({
|
||
planning_source: 'rule_fallback',
|
||
plan_status: 'needs_flow_confirmation',
|
||
pending_flow_confirmation: {
|
||
status: 'pending',
|
||
candidate_flows: [{
|
||
flow_id: 'travel_application',
|
||
label: '先发起出差申请',
|
||
confidence: 0.86,
|
||
ontology_fields: {
|
||
expense_type: 'travel',
|
||
time_range: '2026-02-20 至 2026-02-23',
|
||
location: '上海',
|
||
reason: '辅助国网仿生产服务器部署',
|
||
transport_mode: '火车'
|
||
},
|
||
missing_fields: []
|
||
}]
|
||
}
|
||
}, { prompt })
|
||
|
||
assert.equal(plan.source, WORKBENCH_AI_INTENT_SOURCE_RULE_FALLBACK)
|
||
assert.equal(plan.intent, 'create_travel_application')
|
||
assert.equal(plan.requestedAction, 'preview')
|
||
assert.deepEqual(resolveExecutableTravelApplicationPlan(plan), {
|
||
expenseType: 'travel',
|
||
expenseTypeLabel: '差旅费',
|
||
sourceText: prompt,
|
||
ontologyFields: {
|
||
expense_type: 'travel',
|
||
time_range: '2026-02-20 至 2026-02-23',
|
||
location: '上海',
|
||
reason: '辅助国网仿生产服务器部署',
|
||
transport_mode: '火车'
|
||
},
|
||
autoSubmit: false,
|
||
autoSaveDraft: false,
|
||
requestedSubmit: false,
|
||
submitRequiresConfirmation: false
|
||
})
|
||
})
|
||
|
||
test('workbench AI application preview prefers model ontology fields over local text guesses', () => {
|
||
const preview = buildInlineApplicationPreview(
|
||
'差旅费',
|
||
'2026-02-20 至 2026-02-23,上海出差,国网仿生产服务器部署,火车,保存草稿。',
|
||
{ name: '李文静', grade: 'P5', location: '武汉' },
|
||
{
|
||
ontologyFields: {
|
||
time_range: '2026-02-20 至 2026-02-23',
|
||
location: '上海',
|
||
reason: '国网仿生产服务器部署',
|
||
transport_mode: '火车'
|
||
}
|
||
}
|
||
)
|
||
|
||
assert.equal(preview.fields.time, '2026-02-20 至 2026-02-23')
|
||
assert.equal(preview.fields.location, '上海')
|
||
assert.equal(preview.fields.reason, '国网仿生产服务器部署')
|
||
assert.equal(preview.fields.transportMode, '火车')
|
||
})
|
||
|
||
test('workbench AI intent planner rejects policy question and requires confirmation for direct-submit request', () => {
|
||
assert.equal(buildRuleFallbackWorkbenchAiIntentPlan('帮我查询上海差旅标准'), null)
|
||
|
||
const request = resolveExecutableTravelApplicationPlan(
|
||
buildRuleFallbackWorkbenchAiIntentPlan('去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交')
|
||
)
|
||
|
||
assert.deepEqual(request, {
|
||
expenseType: 'travel',
|
||
expenseTypeLabel: '差旅费',
|
||
sourceText: '去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交',
|
||
ontologyFields: {},
|
||
autoSubmit: false,
|
||
autoSaveDraft: false,
|
||
requestedSubmit: true,
|
||
submitRequiresConfirmation: true
|
||
})
|
||
})
|
||
|
||
test('workbench AI message runtime persists direct-submit confirmation metadata', () => {
|
||
const { createInlineMessage, normalizeRuntimeMessage, serializeRuntimeMessage } = createWorkbenchAiMessageRuntime()
|
||
const message = createInlineMessage('assistant', '申请核对表', {
|
||
applicationPreview: { fields: { location: '上海' } },
|
||
requestedSubmit: true,
|
||
submitRequiresConfirmation: true
|
||
})
|
||
|
||
const serialized = serializeRuntimeMessage(message)
|
||
assert.equal(serialized.requestedSubmit, true)
|
||
assert.equal(serialized.submitRequiresConfirmation, true)
|
||
|
||
const normalized = normalizeRuntimeMessage(serialized)
|
||
assert.equal(normalized.requestedSubmit, true)
|
||
assert.equal(normalized.submitRequiresConfirmation, true)
|
||
})
|
||
|
||
test('workbench AI mode asks steward model plan before fallback execution', () => {
|
||
assert.match(stewardFlowScript, /async function resolveInlineExecutionPlan\(prompt, entry = \{\}, files = \[\], options = \{\}\)/)
|
||
assert.match(stewardFlowScript, /fetchStewardPlan\(planRequest/)
|
||
assert.match(stewardFlowScript, /timeoutMs:\s*35000/)
|
||
assert.match(personalWorkbenchAiModeScript, /async function executeModelPlannedWorkbenchIntent\(cleanPrompt, entry = \{\}, files = \[\]\)/)
|
||
assert.match(personalWorkbenchAiModeScript, /await stewardFlow\.resolveInlineExecutionPlan\(cleanPrompt, entry, files,\s*\{/)
|
||
assert.match(personalWorkbenchAiModeScript, /normalizeWorkbenchAiIntentPlan\(modelPlan,\s*\{\s*prompt:\s*cleanPrompt/)
|
||
assert.match(personalWorkbenchAiModeScript, /buildRuleFallbackWorkbenchAiIntentPlan\(cleanPrompt\)/)
|
||
assert.match(personalWorkbenchAiModeScript, /shouldRequestWorkbenchAiIntentPlan\(cleanPrompt\)/)
|
||
assert.match(personalWorkbenchAiModeScript, /resolveExecutableTravelApplicationPlan\(intentPlan\)/)
|
||
assert.doesNotMatch(personalWorkbenchAiModeScript, /fallbackIntentPlan/)
|
||
assert.match(personalWorkbenchAiModeScript, /autoSaveDraft:\s*travelApplicationRequest\.autoSaveDraft/)
|
||
assert.match(personalWorkbenchAiModeScript, /requestedSubmit:\s*travelApplicationRequest\.requestedSubmit/)
|
||
assert.match(personalWorkbenchAiModeScript, /submitRequiresConfirmation:\s*travelApplicationRequest\.submitRequiresConfirmation/)
|
||
assert.match(personalWorkbenchAiModeScript, /ontologyFields:\s*travelApplicationRequest\.ontologyFields/)
|
||
assert.match(personalWorkbenchAiModeScript, /stewardRemainingTasks:\s*travelApplicationRequest\.stewardRemainingTasks/)
|
||
assert.match(personalWorkbenchAiModeScript, /onPreviewReadyForNextTask:\s*startModelPlannedNextTask/)
|
||
assert.match(personalWorkbenchAiModeScript, /onApplicationActionCompleted:\s*startModelPlannedNextTask/)
|
||
assert.match(applicationPreviewFlowScript, /options\.autoSaveDraft/)
|
||
assert.match(applicationPreviewFlowScript, /options\.onPreviewReadyForNextTask/)
|
||
assert.match(applicationPreviewFlowScript, /onApplicationActionCompleted\(\s*targetMessage\.stewardRemainingTasks/)
|
||
assert.doesNotMatch(applicationPreviewFlowScript, /options\.autoSubmit && normalizeApplicationPreview\(preview\)\.readyToSubmit/)
|
||
assert.match(applicationPreviewFlowScript, /ontologyFields:\s*options\.ontologyFields/)
|
||
assert.match(applicationPreviewFlowScript, /executeInlineApplicationPreviewAction\(AI_APPLICATION_ACTION_SAVE_DRAFT/)
|
||
assert.match(applicationPreviewFlowScript, /buildInlineApplicationPreview\([\s\S]*ontologyFields:\s*options\.ontologyFields/)
|
||
assert.doesNotMatch(personalWorkbenchAiModeScript, /const travelApplicationRequest = resolveInlineTravelApplicationRequest\(cleanPrompt\)/)
|
||
})
|
||
|
||
test('workbench AI mode shows a visible planning response before waiting for steward model plan', () => {
|
||
assert.match(personalWorkbenchAiModeScript, /function startModelPlanningConversation\(cleanPrompt, entry = \{\}\)/)
|
||
assert.match(personalWorkbenchAiModeScript, /conversationMessages\.value\.push\(createInlineMessage\('user', cleanPrompt\)\)/)
|
||
assert.match(personalWorkbenchAiModeScript, /正在识别意图,准备拆解申请、报销和附件任务/)
|
||
assert.match(
|
||
personalWorkbenchAiModeScript,
|
||
/const plannerPendingMessage = startModelPlanningConversation\(cleanPrompt, entry\)[\s\S]*await stewardFlow\.resolveInlineExecutionPlan\(cleanPrompt, entry, files,\s*\{/
|
||
)
|
||
assert.match(
|
||
personalWorkbenchAiModeScript,
|
||
/pendingMessageId:\s*plannerPendingMessage\?\.id/
|
||
)
|
||
assert.match(applicationPreviewFlowScript, /options\.pendingMessageId/)
|
||
})
|
||
|
||
test('workbench AI mode streams planning thinking into the pending message', () => {
|
||
assert.match(planningThinkingModelScript, /buildModelPlanningProgressSchedule/)
|
||
assert.match(planningThinkingModelScript, /判断办理意图/)
|
||
assert.match(planningThinkingModelScript, /抽取关键信息/)
|
||
assert.match(planningThinkingModelScript, /规划执行步骤/)
|
||
assert.match(planningThinkingModelScript, /准备兜底策略/)
|
||
assert.match(personalWorkbenchAiModeScript, /function startModelPlanningProgressUpdates\(messageId\)/)
|
||
assert.match(personalWorkbenchAiModeScript, /globalThis\.setTimeout\(\(\) => \{\s*updateModelPlanningThinkingEvent\(messageId, event\)/)
|
||
assert.match(personalWorkbenchAiModeScript, /const stopPlanningProgressUpdates = startModelPlanningProgressUpdates\(plannerPendingMessage\.id\)/)
|
||
assert.match(personalWorkbenchAiModeScript, /stopPlanningProgressUpdates\(\)/)
|
||
assert.match(
|
||
personalWorkbenchAiModeScript,
|
||
/await stewardFlow\.resolveInlineExecutionPlan\(cleanPrompt, entry, files,\s*\{\s*pendingMessageId:\s*plannerPendingMessage\.id\s*\}\)/
|
||
)
|
||
assert.match(stewardFlowScript, /async function resolveInlineExecutionPlan\(prompt, entry = \{\}, files = \[\], options = \{\}\)/)
|
||
assert.match(stewardFlowScript, /fetchInlineStewardPlan\(planningMessageId, planRequest,\s*\{[\s\S]*includeAnswerDelta:\s*false/)
|
||
assert.match(applicationPreviewFlowScript, /mergeWorkbenchAiThinkingEvents\(previousThinkingEvents,\s*\[/)
|
||
})
|
||
|
||
test('workbench AI mode reuses planning pending message for regular steward replies', () => {
|
||
assert.match(
|
||
personalWorkbenchAiModeScript,
|
||
/stewardFlow\.requestInlineAssistantReply\(cleanPrompt, entry, files,\s*\{\s*pendingMessageId:\s*plannerPendingMessage\.id\s*\}\)/
|
||
)
|
||
assert.doesNotMatch(
|
||
personalWorkbenchAiModeScript,
|
||
/replaceInlineMessage\(plannerPendingMessage\.id,\s*createInlineMessage\('assistant', '已完成意图识别,继续为您整理回复。'/
|
||
)
|
||
assert.match(stewardFlowScript, /async function requestInlineAssistantReply\(prompt, entry = \{\}, files = \[\], options = \{\}\)/)
|
||
assert.match(stewardFlowScript, /const reusablePendingMessageId = String\(options\.pendingMessageId \|\| ''\)\.trim\(\)/)
|
||
assert.match(stewardFlowScript, /reusablePendingMessageId \? replaceInlineMessage\(reusablePendingMessageId, pendingMessage\) : conversationMessages\.value\.push\(pendingMessage\)/)
|
||
})
|
||
|
||
test('isLowConfidenceTravelApplicationPlan gates preview behind confirmation when model confidence is low', () => {
|
||
const lowConfidenceModelPlan = normalizeWorkbenchAiIntentPlan({
|
||
planning_source: 'llm_function_call',
|
||
tasks: [{
|
||
task_type: 'expense_application',
|
||
assigned_agent: 'application_assistant',
|
||
requested_action: 'preview',
|
||
confidence: 0.4,
|
||
ontology_fields: { location: '上海', reason: '部署' }
|
||
}]
|
||
}, { prompt: '上海那边好像要过去一趟搞部署' })
|
||
|
||
assert.equal(lowConfidenceModelPlan.source, WORKBENCH_AI_INTENT_SOURCE_MODEL)
|
||
assert.equal(isLowConfidenceTravelApplicationPlan(lowConfidenceModelPlan), true)
|
||
|
||
const highConfidenceModelPlan = normalizeWorkbenchAiIntentPlan({
|
||
planning_source: 'llm_function_call',
|
||
tasks: [{
|
||
task_type: 'expense_application',
|
||
assigned_agent: 'application_assistant',
|
||
requested_action: 'preview',
|
||
confidence: 0.9,
|
||
ontology_fields: { location: '上海' }
|
||
}]
|
||
}, { prompt: '去上海出差' })
|
||
|
||
assert.equal(isLowConfidenceTravelApplicationPlan(highConfidenceModelPlan), false)
|
||
|
||
const ruleFallbackPlan = buildRuleFallbackWorkbenchAiIntentPlan('去上海出差,辅助部署,交通火车')
|
||
assert.equal(ruleFallbackPlan.source, WORKBENCH_AI_INTENT_SOURCE_RULE_FALLBACK)
|
||
assert.equal(isLowConfidenceTravelApplicationPlan(ruleFallbackPlan), false)
|
||
|
||
const explicitSubmitLowConfidence = normalizeWorkbenchAiIntentPlan({
|
||
planning_source: 'llm_function_call',
|
||
tasks: [{
|
||
task_type: 'expense_application',
|
||
assigned_agent: 'application_assistant',
|
||
requested_action: 'submit',
|
||
confidence: 0.3,
|
||
ontology_fields: { location: '上海' }
|
||
}]
|
||
}, { prompt: '直接提交' })
|
||
|
||
assert.equal(explicitSubmitLowConfidence.requestedAction, 'submit')
|
||
assert.equal(isLowConfidenceTravelApplicationPlan(explicitSubmitLowConfidence), false)
|
||
|
||
assert.equal(isLowConfidenceTravelApplicationPlan(null), false)
|
||
})
|
||
|
||
test('workbench AI mode routes low confidence travel application plan to confirmation prompt', () => {
|
||
assert.match(personalWorkbenchAiModeScript, /isLowConfidenceTravelApplicationPlan\(intentPlan\)/)
|
||
assert.match(personalWorkbenchAiModeScript, /function startModelPlannedTravelApplicationConfirmation\(/)
|
||
assert.match(personalWorkbenchAiModeScript, /action_type:\s*'ai_application_confirm_intent'/)
|
||
assert.match(personalWorkbenchAiModeScript, /需要确认:您是要发起出差申请吗/)
|
||
})
|
||
|
||
test('shouldRequestWorkbenchAiIntentPlan skips chitchat and only triggers on business keywords', () => {
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('你好'), false)
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('谢谢'), false)
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('嗯'), false)
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('ok'), false)
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('1'), false)
|
||
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('帮我查报销'), true)
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('我要出差'), true)
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('帮我查询上海差旅标准'), true)
|
||
assert.equal(shouldRequestWorkbenchAiIntentPlan('删除3天前的草稿'), true)
|
||
})
|