2026-05-30 15:46:51 +08:00
|
|
|
|
import assert from 'node:assert/strict'
|
|
|
|
|
|
import { readFileSync } from 'node:fs'
|
|
|
|
|
|
import test from 'node:test'
|
|
|
|
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION,
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_EXPENSE,
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_KNOWLEDGE,
|
2026-06-15 22:55:18 +08:00
|
|
|
|
ASSISTANT_SCOPE_SESSION_STEWARD,
|
2026-05-30 15:46:51 +08:00
|
|
|
|
inferAssistantScopeTarget
|
|
|
|
|
|
} from '../src/utils/assistantSessionScope.js'
|
|
|
|
|
|
import {
|
|
|
|
|
|
resolveWorkbenchSessionTypeFromOntology
|
|
|
|
|
|
} from '../src/utils/workbenchAssistantIntent.js'
|
|
|
|
|
|
|
|
|
|
|
|
const appShellRouteView = readFileSync(
|
|
|
|
|
|
fileURLToPath(new URL('../src/views/AppShellRouteView.vue', import.meta.url)),
|
|
|
|
|
|
'utf8'
|
|
|
|
|
|
)
|
|
|
|
|
|
const appShellComposable = readFileSync(
|
|
|
|
|
|
fileURLToPath(new URL('../src/composables/useAppShell.js', import.meta.url)),
|
|
|
|
|
|
'utf8'
|
|
|
|
|
|
)
|
|
|
|
|
|
const assistantScript = readFileSync(
|
|
|
|
|
|
fileURLToPath(new URL('../src/views/scripts/TravelReimbursementCreateView.js', import.meta.url)),
|
|
|
|
|
|
'utf8'
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
test('workbench prompt applies travel phrases to application assistant scope', () => {
|
|
|
|
|
|
assert.equal(inferAssistantScopeTarget('申请出差'), ASSISTANT_SCOPE_SESSION_APPLICATION)
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
|
inferAssistantScopeTarget('去北京出差3天,支撑国网仿生产环境部署'),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
|
inferAssistantScopeTarget('去国网出差3天,协助仿生产环境部署'),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
|
inferAssistantScopeTarget('下周去上海支撑客户系统上线,预计3天'),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
|
inferAssistantScopeTarget('安排去深圳客户现场验收项目'),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
|
inferAssistantScopeTarget('准备去国网现场做仿生产环境部署,差旅3天'),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION
|
|
|
|
|
|
)
|
2026-06-15 22:55:18 +08:00
|
|
|
|
assert.equal(
|
|
|
|
|
|
inferAssistantScopeTarget('2月20-23日去上海出差辅助国网仿生产环境部署'),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_STEWARD
|
|
|
|
|
|
)
|
2026-05-30 15:46:51 +08:00
|
|
|
|
assert.equal(
|
|
|
|
|
|
inferAssistantScopeTarget('我要报销去北京的费用'),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_EXPENSE
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
|
inferAssistantScopeTarget('我要报销去北京出差的费用'),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_EXPENSE
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
|
inferAssistantScopeTarget('去北京出差报销标准是多少'),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_KNOWLEDGE
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.notEqual(
|
|
|
|
|
|
inferAssistantScopeTarget('昨天去北京出差花了1000元'),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.match(appShellComposable, /fetchOntologyParse/)
|
|
|
|
|
|
assert.match(appShellComposable, /resolveWorkbenchSessionTypeFromOntology/)
|
|
|
|
|
|
assert.match(appShellComposable, /resolveWorkbenchSessionTypeFallback/)
|
|
|
|
|
|
assert.match(appShellRouteView, /:initial-session-type="smartEntryContext\.sessionType"/)
|
|
|
|
|
|
assert.match(assistantScript, /initialSessionType:\s*\{[\s\S]*type:\s*String/)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
test('workbench model routing maps ontology result before entering assistant', () => {
|
|
|
|
|
|
const travelOntology = {
|
|
|
|
|
|
scenario: 'expense',
|
|
|
|
|
|
intent: 'draft',
|
|
|
|
|
|
entities: [
|
|
|
|
|
|
{ type: 'expense_type', normalized_value: 'travel' }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
const reimbursementOntology = {
|
|
|
|
|
|
scenario: 'expense',
|
|
|
|
|
|
intent: 'draft',
|
|
|
|
|
|
entities: [
|
|
|
|
|
|
{ type: 'expense_type', normalized_value: 'travel' }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
const applicationOntology = {
|
|
|
|
|
|
scenario: 'expense',
|
|
|
|
|
|
intent: 'draft',
|
|
|
|
|
|
entities: [
|
|
|
|
|
|
{ type: 'document_type', normalized_value: 'expense_application' },
|
|
|
|
|
|
{ type: 'workflow_stage', normalized_value: 'pre_approval' }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
|
resolveWorkbenchSessionTypeFromOntology(
|
|
|
|
|
|
travelOntology,
|
|
|
|
|
|
'下周去上海支撑客户系统上线,预计3天',
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_EXPENSE
|
|
|
|
|
|
),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION
|
|
|
|
|
|
)
|
2026-06-15 22:55:18 +08:00
|
|
|
|
assert.equal(
|
|
|
|
|
|
resolveWorkbenchSessionTypeFromOntology(
|
|
|
|
|
|
travelOntology,
|
|
|
|
|
|
'2月20-23日去上海出差辅助国网仿生产环境部署',
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION
|
|
|
|
|
|
),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_STEWARD
|
|
|
|
|
|
)
|
2026-05-30 15:46:51 +08:00
|
|
|
|
assert.equal(
|
|
|
|
|
|
resolveWorkbenchSessionTypeFromOntology(
|
|
|
|
|
|
reimbursementOntology,
|
|
|
|
|
|
'我要报销去北京出差的费用',
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION
|
|
|
|
|
|
),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_EXPENSE
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
|
resolveWorkbenchSessionTypeFromOntology(
|
|
|
|
|
|
{ scenario: 'expense', intent: 'query', entities: reimbursementOntology.entities },
|
|
|
|
|
|
'去北京出差报销标准是多少',
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_KNOWLEDGE
|
|
|
|
|
|
),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_KNOWLEDGE
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
|
resolveWorkbenchSessionTypeFromOntology(
|
|
|
|
|
|
applicationOntology,
|
|
|
|
|
|
'国网仿生产环境部署',
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_EXPENSE
|
|
|
|
|
|
),
|
|
|
|
|
|
ASSISTANT_SCOPE_SESSION_APPLICATION
|
|
|
|
|
|
)
|
|
|
|
|
|
})
|
2026-06-15 22:55:18 +08:00
|
|
|
|
|
2026-06-18 22:12:24 +08:00
|
|
|
|
test('workbench smart entry blocks unsupported non-business input before ontology parsing', () => {
|
|
|
|
|
|
const openSmartEntryStart = appShellComposable.indexOf('async function openSmartEntry(payload')
|
|
|
|
|
|
const closeSmartEntryStart = appShellComposable.indexOf('function closeSmartEntry(')
|
|
|
|
|
|
assert.ok(openSmartEntryStart >= 0, 'expected an openSmartEntry entry point')
|
|
|
|
|
|
assert.ok(closeSmartEntryStart > openSmartEntryStart, 'expected closeSmartEntry to follow openSmartEntry')
|
|
|
|
|
|
|
|
|
|
|
|
const openSmartEntryBlock = appShellComposable.slice(openSmartEntryStart, closeSmartEntryStart)
|
|
|
|
|
|
const guardIndex = openSmartEntryBlock.indexOf('resolveAssistantScopeGuard(')
|
|
|
|
|
|
const blockedIndex = openSmartEntryBlock.indexOf('scopeGuard?.blocked')
|
|
|
|
|
|
const conversationIndex = openSmartEntryBlock.indexOf('buildUnsupportedBusinessScopeConversation(prompt')
|
|
|
|
|
|
const sessionTypeResolveIndex = openSmartEntryBlock.indexOf('resolveSmartEntrySessionType(payload)')
|
2026-06-15 22:55:18 +08:00
|
|
|
|
|
2026-06-18 22:12:24 +08:00
|
|
|
|
assert.ok(guardIndex >= 0, 'expected smart entry to use the business scope guard')
|
|
|
|
|
|
assert.ok(blockedIndex >= 0, 'expected smart entry to short-circuit blocked inputs')
|
|
|
|
|
|
assert.ok(conversationIndex >= 0, 'expected blocked smart entry inputs to seed an assistant conversation')
|
|
|
|
|
|
assert.ok(sessionTypeResolveIndex >= 0, 'expected smart entry to delegate session resolution')
|
2026-06-15 22:55:18 +08:00
|
|
|
|
assert.ok(
|
2026-06-18 22:12:24 +08:00
|
|
|
|
blockedIndex < sessionTypeResolveIndex,
|
|
|
|
|
|
'expected blocked inputs to stop before ontology-driven session resolution'
|
|
|
|
|
|
)
|
|
|
|
|
|
assert.ok(
|
|
|
|
|
|
conversationIndex < sessionTypeResolveIndex,
|
|
|
|
|
|
'expected unsupported input guidance to be prepared before session resolution'
|
2026-06-15 22:55:18 +08:00
|
|
|
|
)
|
|
|
|
|
|
})
|
2026-06-18 22:12:24 +08:00
|
|
|
|
|