import assert from 'node:assert/strict' import test from 'node:test' import { resolveWorkbenchIntentFrame } from '../src/composables/workbenchAiMode/workbenchIntentFrameModel.js' import { resolveWorkbenchIntentActionRoute } from '../src/composables/workbenchAiMode/workbenchIntentActionPolicy.js' import { buildAiDocumentQueryMessage, buildAiDocumentQueryThinkingEvents, resolveAiDocumentQueryIntent } from '../src/utils/aiDocumentQueryModel.js' const today = '2026-06-24' test('workbench intent frame resolves contextual draft deletion as confirm-only current target', () => { const frame = resolveWorkbenchIntentFrame('请删除刚才那个草稿', { today }) assert.equal(frame?.action, 'delete') assert.equal(frame?.objectType, 'draft') assert.equal(frame?.targetMode, 'current_context') assert.equal(frame?.safetyLevel, 'confirm_required') assert.equal(frame?.riskLevel, 'high') assert.equal(frame?.requiresCandidateSearch, false) assert.equal(frame?.requiresSelection, false) assert.equal(frame?.requiresConfirmation, true) assert.equal(frame?.executionMode, 'need_confirmation') assert.equal(frame?.policyDecision, 'need_confirmation') assert.equal(frame?.filters.status?.label, '草稿') assert.equal(frame?.normalizedQuery, '我的草稿单据') }) test('workbench intent frame sends filtered draft deletion to candidate search', () => { const frame = resolveWorkbenchIntentFrame('删除3天前的草稿', { today }) const route = resolveWorkbenchIntentActionRoute(frame) assert.equal(frame?.action, 'delete') assert.equal(frame?.objectType, 'draft') assert.equal(frame?.targetMode, 'filtered_candidates') assert.equal(frame?.safetyLevel, 'confirm_required') assert.equal(frame?.riskLevel, 'high') assert.equal(frame?.requiresCandidateSearch, true) assert.equal(frame?.requiresSelection, true) assert.equal(frame?.requiresConfirmation, true) assert.equal(frame?.executionMode, 'query_candidates') assert.equal(frame?.policyDecision, 'query_candidates') assert.equal(frame?.filters.timeRange?.start, '2026-06-21') assert.equal(frame?.filters.timeRange?.end, '2026-06-21') assert.equal(frame?.normalizedQuery, '我的 3天前 草稿单据') assert.equal(route.nextStep, 'query_candidates') assert.equal(route.queryPrompt, '我的 3天前 草稿单据') assert.equal(route.requiresSelection, true) assert.equal(route.requiresConfirmation, true) }) test('workbench intent frame preserves application draft deletion filters', () => { const frame = resolveWorkbenchIntentFrame('删除申请单草稿', { today }) const route = resolveWorkbenchIntentActionRoute(frame) const queryIntent = resolveAiDocumentQueryIntent(route.queryPrompt, { today }) assert.equal(frame?.action, 'delete') assert.equal(frame?.objectType, 'draft') assert.equal(frame?.filters.documentType, 'application') assert.equal(frame?.filters.status?.label, '草稿') assert.equal(frame?.targetMode, 'filtered_candidates') assert.equal(frame?.safetyLevel, 'confirm_required') assert.equal(frame?.riskLevel, 'high') assert.equal(frame?.requiresCandidateSearch, true) assert.equal(frame?.requiresSelection, true) assert.equal(frame?.requiresConfirmation, true) assert.equal(frame?.executionMode, 'query_candidates') assert.equal(route.queryPrompt, '我的 草稿 申请单') assert.equal(queryIntent?.source, 'mine') assert.equal(queryIntent?.documentType, 'application') assert.equal(queryIntent?.statusFilter?.label, '草稿') }) test('workbench document query thinking exposes destructive action policy before filtering', () => { const frame = resolveWorkbenchIntentFrame('删除申请单草稿', { today }) const intent = resolveAiDocumentQueryIntent(resolveWorkbenchIntentActionRoute(frame).queryPrompt, { today }) const events = buildAiDocumentQueryThinkingEvents(intent, { commandFrame: frame }) assert.equal(events[0].eventId, 'document-command-policy') assert.match(events[0].title, /识别高风险操作意图/) assert.match(events[0].content, /删除/) assert.match(events[0].content, /不会直接执行/) assert.match(events[0].content, /先筛选候选/) }) test('workbench high-risk command result explains confirmation boundary and labels detail shortcut', () => { const frame = resolveWorkbenchIntentFrame('删除申请单草稿', { today }) const intent = resolveAiDocumentQueryIntent(resolveWorkbenchIntentActionRoute(frame).queryPrompt, { today }) const message = buildAiDocumentQueryMessage(intent, [{ id: 'draft-application-1', claim_no: 'AP-DRAFT-001', document_type_code: 'application', expense_type: 'travel_application', status: 'draft', reason: '测试申请草稿', created_at: '2026-06-24T09:00:00Z', risk_flags_json: [], risk_summary: '无' }], { commandFrame: frame }) assert.match(message, /系统不会直接删除相关单据/) assert.match(message, /请点击下方候选单据里的快捷按钮/) assert.match(message, /进入单据详情核对后再操作/) assert.match(message, />进入详情确认删除 { const frame = resolveWorkbenchIntentFrame('审核合规没有风险的申请', { today }) const route = resolveWorkbenchIntentActionRoute(frame) assert.equal(frame?.action, 'approve') assert.equal(frame?.objectType, 'application') assert.equal(frame?.targetMode, 'filtered_candidates') assert.equal(frame?.safetyLevel, 'confirm_required') assert.equal(frame?.riskLevel, 'high') assert.equal(frame?.requiresCandidateSearch, true) assert.equal(frame?.requiresSelection, true) assert.equal(frame?.requiresConfirmation, true) assert.equal(frame?.executionMode, 'query_candidates') assert.equal(frame?.policyDecision, 'query_candidates') assert.equal(frame?.filters.risk?.level, 'none') assert.equal(frame?.filters.documentType, 'application') assert.equal(frame?.normalizedQuery, '待我审核 无风险 申请单') assert.equal(route.nextStep, 'query_candidates') assert.equal(route.queryPrompt, '待我审核 无风险 申请单') assert.equal(route.requiresSelection, true) assert.equal(route.requiresConfirmation, true) }) test('workbench intent frame keeps approval policy questions out of document actions', () => { const frame = resolveWorkbenchIntentFrame('审批规则怎么走', { today }) const route = resolveWorkbenchIntentActionRoute(frame) assert.equal(frame?.action, 'ask_policy') assert.equal(frame?.safetyLevel, 'read_only') assert.equal(frame?.riskLevel, 'read_only') assert.equal(frame?.requiresCandidateSearch, false) assert.equal(frame?.requiresSelection, false) assert.equal(frame?.requiresConfirmation, false) assert.equal(frame?.executionMode, 'answer_only') assert.equal(frame?.policyDecision, 'answer_only') assert.equal(route.nextStep, 'pass_through') }) test('workbench intent frame keeps rules as policy guardrails instead of executable side effects', () => { const highRiskFrame = resolveWorkbenchIntentFrame('审核合规没有风险的申请', { today }) const highRiskRoute = resolveWorkbenchIntentActionRoute(highRiskFrame) const queryFrame = resolveWorkbenchIntentFrame('查3天前的申请单', { today }) const queryRoute = resolveWorkbenchIntentActionRoute(queryFrame) assert.equal(highRiskFrame?.policyDecision, 'query_candidates') assert.equal(highRiskFrame?.requiresSelection, true) assert.equal(highRiskFrame?.requiresConfirmation, true) assert.notEqual(highRiskRoute.nextStep, 'execute_allowed') assert.equal(queryFrame?.riskLevel, 'read_only') assert.equal(queryFrame?.requiresCandidateSearch, true) assert.equal(queryFrame?.requiresSelection, false) assert.equal(queryFrame?.requiresConfirmation, false) assert.equal(queryFrame?.policyDecision, 'query_candidates') assert.equal(queryRoute.nextStep, 'query_candidates') })