import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import test from 'node:test'
import { fileURLToPath } from 'node:url'
import {
buildWorkbenchDocumentCommandFollowupGuidance,
buildWorkbenchDraftDeletionGuidance,
isWorkbenchDraftDeletionIntent,
resolveLatestWorkbenchDocumentCommandContext,
resolveLatestWorkbenchDraftPayload
} from '../src/composables/workbenchAiMode/workbenchAiCommandIntentModel.js'
const personalWorkbenchAiModeScript = readFileSync(
fileURLToPath(new URL('../src/composables/workbenchAiMode/usePersonalWorkbenchAiMode.js', import.meta.url)),
'utf8'
)
const commandIntentsScript = readFileSync(
fileURLToPath(new URL('../src/composables/workbenchAiMode/useWorkbenchAiCommandIntents.js', import.meta.url)),
'utf8'
)
test('workbench command intent detects draft deletion phrases without broad delete matching', () => {
assert.equal(isWorkbenchDraftDeletionIntent('删除草稿'), true)
assert.equal(isWorkbenchDraftDeletionIntent('把刚才保存的草稿删掉'), true)
assert.equal(isWorkbenchDraftDeletionIntent('删除这个申请单'), true)
assert.equal(isWorkbenchDraftDeletionIntent('删除附件'), false)
assert.equal(isWorkbenchDraftDeletionIntent('草稿还要补什么'), false)
})
test('workbench command intent resolves latest draft payload from conversation context', () => {
const payload = resolveLatestWorkbenchDraftPayload([
{
role: 'assistant',
draftPayload: {
claim_id: 'old-draft',
claim_no: 'AOLD001',
status: 'draft'
}
},
{
role: 'assistant',
suggestedActions: [{
action_type: 'open_application_detail',
payload: {
claim_id: 'latest-draft',
claim_no: 'ALATEST1',
status: 'draft'
}
}]
}
])
assert.deepEqual(payload, {
claimId: 'latest-draft',
claimNo: 'ALATEST1',
status: 'draft',
documentType: 'application'
})
})
test('workbench command intent skips submitted documents when deleting draft', () => {
const payload = resolveLatestWorkbenchDraftPayload([
{
role: 'assistant',
draftPayload: {
claim_id: 'submitted-application',
claim_no: 'ASUBMIT1',
status: 'submitted'
}
}
])
assert.equal(payload, null)
})
test('workbench draft deletion guidance opens detail instead of deleting directly', () => {
const guidance = buildWorkbenchDraftDeletionGuidance({
claimId: 'latest-draft',
claimNo: 'ALATEST1',
documentType: 'application'
})
assert.match(guidance.content, /已识别到您想删除草稿/)
assert.match(guidance.content, /不会直接替您删除/)
assert.equal(guidance.suggestedActions.length, 1)
assert.equal(guidance.suggestedActions[0].action_type, 'open_application_detail')
assert.equal(guidance.suggestedActions[0].payload.claim_id, 'latest-draft')
assert.equal(guidance.suggestedActions[0].payload.claim_no, 'ALATEST1')
})
test('workbench command intent reuses previous approval candidates for follow-up approval command', () => {
const context = resolveLatestWorkbenchDocumentCommandContext([
{
role: 'assistant',
content: [
'### 已查询到相关单据',
'',
'',
'查看详情',
'',
'',
'查看详情',
''
].join('\n')
}
], { action: 'approve', safetyLevel: 'confirm_required' })
assert.equal(context?.candidates.length, 2)
assert.deepEqual(context.candidates[0], {
claimId: 'approval-1',
claimNo: 'AP-APPROVAL-001',
documentType: 'application',
actionLabel: '查看详情'
})
const guidance = buildWorkbenchDocumentCommandFollowupGuidance(context, { action: 'approve' })
assert.match(guidance.content, /已接上刚才查询到的待审单据/)
assert.match(guidance.content, /AP-APPROVAL-001/)
assert.match(guidance.content, /RE-APPROVAL-002/)
assert.equal(guidance.suggestedActions.length, 2)
assert.equal(guidance.suggestedActions[0].action_type, 'open_application_detail')
assert.equal(guidance.suggestedActions[0].payload.claim_id, 'approval-1')
assert.equal(guidance.suggestedActions[0].payload.command_action, 'approve')
})
test('workbench draft deletion intent is wired before draft slot continuation', () => {
assert.match(commandIntentsScript, /isWorkbenchDraftDeletionIntent/)
assert.match(commandIntentsScript, /resolveLatestWorkbenchDocumentCommandContext/)
assert.match(commandIntentsScript, /buildWorkbenchDocumentCommandFollowupGuidance/)
assert.match(commandIntentsScript, /function handleInlineDraftDeletionIntent\(cleanPrompt, entry = \{\}\)/)
assert.match(commandIntentsScript, /resolveLatestWorkbenchDraftPayload\(conversationMessages\.value\)/)
assert.match(commandIntentsScript, /buildWorkbenchDraftDeletionGuidance\(draftPayload\)/)
assert.match(personalWorkbenchAiModeScript, /useWorkbenchAiCommandIntents/)
const startIndex = personalWorkbenchAiModeScript.indexOf('function startInlineConversation')
const startBlock = personalWorkbenchAiModeScript.slice(startIndex)
const deleteIntentIndex = startBlock.indexOf('if (commandIntents.handleInlineDraftDeletionIntent(cleanPrompt, entry))')
const draftContinuationIndex = startBlock.indexOf('if (aiExpenseDraft.value && !isAiExpenseDraftComplete(aiExpenseDraft.value))')
assert.ok(deleteIntentIndex >= 0)
assert.ok(draftContinuationIndex > deleteIntentIndex)
})