feat(ai): add tenant-safe hierarchical expense learning
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
AI_APPLICATION_ACTION_SAVE_DRAFT,
|
||||
AI_APPLICATION_ACTION_SUBMIT,
|
||||
forgetAiApplicationMemory,
|
||||
normalizeAiApplicationMemory,
|
||||
registerAiApplicationPreviewDecision,
|
||||
resolveAiApplicationLearningReceipts,
|
||||
runAiApplicationPreviewAction
|
||||
@@ -148,6 +149,14 @@ async function testRegistrationUsesServerCanonicalPreview() {
|
||||
status: 'active',
|
||||
evidenceCount: 4,
|
||||
approvedEvidenceCount: 3,
|
||||
scope_type: 'department',
|
||||
scope_id: 'department-shanghai-delivery',
|
||||
scope_label: '上海交付部',
|
||||
source: 'admin_managed_org',
|
||||
priority: 200,
|
||||
effective_confidence: 0.92,
|
||||
conflicts: [{ scope_type: 'user', reason: 'lower_priority' }],
|
||||
can_revoke: false,
|
||||
message: '根据历史申请偏好填入'
|
||||
}]
|
||||
}
|
||||
@@ -188,6 +197,14 @@ async function testRegistrationUsesServerCanonicalPreview() {
|
||||
status: 'applied',
|
||||
evidenceCount: 4,
|
||||
approvedEvidenceCount: 3,
|
||||
scopeType: 'department',
|
||||
scopeId: 'department-shanghai-delivery',
|
||||
scopeLabel: '上海交付部',
|
||||
source: 'admin_managed_org',
|
||||
priority: 200,
|
||||
effectiveConfidence: 0.92,
|
||||
conflicts: [{ scope_type: 'user', reason: 'lower_priority' }],
|
||||
canRevoke: false,
|
||||
message: '根据历史申请偏好填入'
|
||||
}])
|
||||
}
|
||||
@@ -215,6 +232,14 @@ async function testLearningReceiptNormalizationAndForgetEndpoint() {
|
||||
status: 'candidate',
|
||||
evidenceCount: 2,
|
||||
approvedEvidenceCount: 1,
|
||||
scopeType: 'user',
|
||||
scopeId: '',
|
||||
scopeLabel: '个人偏好',
|
||||
source: 'verified_user_history',
|
||||
priority: 100,
|
||||
effectiveConfidence: null,
|
||||
conflicts: [],
|
||||
canRevoke: true,
|
||||
message: '再确认一次后可形成稳定偏好'
|
||||
}])
|
||||
|
||||
@@ -238,6 +263,52 @@ async function testLearningReceiptNormalizationAndForgetEndpoint() {
|
||||
assert.equal(capturedOptions.method, 'DELETE')
|
||||
}
|
||||
|
||||
function testHierarchicalMemoryNormalizationKeepsCompatibilityAndPermissions() {
|
||||
const enterpriseMemory = normalizeAiApplicationMemory({
|
||||
memory_id: 'memory-enterprise-transport',
|
||||
field_key: 'transport_mode',
|
||||
value: '火车',
|
||||
status: 'applied',
|
||||
scope_type: 'enterprise',
|
||||
scope_id: 'tenant-acme',
|
||||
scope_label: '企业统一制度',
|
||||
source: 'admin_managed_org',
|
||||
priority: '300',
|
||||
effective_confidence: '0.88',
|
||||
conflicts: [{ scope_type: 'department', reason: 'lower_priority' }],
|
||||
can_revoke: false
|
||||
})
|
||||
assert.deepEqual(enterpriseMemory, {
|
||||
memoryId: 'memory-enterprise-transport',
|
||||
fieldKey: 'transport_mode',
|
||||
fieldLabel: '出行方式',
|
||||
value: '火车',
|
||||
status: 'applied',
|
||||
evidenceCount: 0,
|
||||
approvedEvidenceCount: 0,
|
||||
scopeType: 'enterprise',
|
||||
scopeId: 'tenant-acme',
|
||||
scopeLabel: '企业统一制度',
|
||||
source: 'admin_managed_org',
|
||||
priority: 300,
|
||||
effectiveConfidence: 0.88,
|
||||
conflicts: [{ scope_type: 'department', reason: 'lower_priority' }],
|
||||
canRevoke: false,
|
||||
message: ''
|
||||
})
|
||||
|
||||
const legacyPersonalMemory = normalizeAiApplicationMemory({
|
||||
memoryId: 'memory-legacy-user',
|
||||
fieldKey: 'transport_mode',
|
||||
value: '飞机',
|
||||
status: 'active'
|
||||
})
|
||||
assert.equal(legacyPersonalMemory.scopeType, 'user')
|
||||
assert.equal(legacyPersonalMemory.source, 'verified_user_history')
|
||||
assert.equal(legacyPersonalMemory.canRevoke, true)
|
||||
assert.equal(legacyPersonalMemory.status, 'applied')
|
||||
}
|
||||
|
||||
async function testEditDraftActionCarriesClaimAndEditableFields() {
|
||||
let capturedOptions = null
|
||||
|
||||
@@ -327,6 +398,7 @@ async function run() {
|
||||
await testSaveDraftActionUsesFastPreviewEndpoint()
|
||||
await testRegistrationUsesServerCanonicalPreview()
|
||||
await testLearningReceiptNormalizationAndForgetEndpoint()
|
||||
testHierarchicalMemoryNormalizationKeepsCompatibilityAndPermissions()
|
||||
await testEditDraftActionCarriesClaimAndEditableFields()
|
||||
await testApplicationActionSourceCanBeConfiguredWithoutChangingWorkbenchDefaults()
|
||||
console.log('ai-application-preview-actions tests passed')
|
||||
|
||||
Reference in New Issue
Block a user