feat(ai): add personal expense application memory

This commit is contained in:
caoxiaozhu
2026-07-14 17:16:23 +08:00
parent 211f85d981
commit 54754b5502
36 changed files with 3579 additions and 74 deletions

View File

@@ -3,7 +3,9 @@ import assert from 'node:assert/strict'
import {
AI_APPLICATION_ACTION_SAVE_DRAFT,
AI_APPLICATION_ACTION_SUBMIT,
forgetAiApplicationMemory,
registerAiApplicationPreviewDecision,
resolveAiApplicationLearningReceipts,
runAiApplicationPreviewAction
} from '../src/services/aiApplicationPreviewActions.js'
@@ -138,7 +140,16 @@ async function testRegistrationUsesServerCanonicalPreview() {
fields: {
reason: '服务端规范事由',
amount: '1800元'
}
},
memoryApplications: [{
memoryId: 'memory-transport-1',
fieldKey: 'transport_mode',
value: '火车',
status: 'active',
evidenceCount: 4,
approvedEvidenceCount: 3,
message: '根据历史申请偏好填入'
}]
}
}
}
@@ -169,6 +180,62 @@ async function testRegistrationUsesServerCanonicalPreview() {
assert.equal(preview.fields.reason, '服务端规范事由')
assert.equal(preview.fields.location, '上海')
assert.equal(preview.decisionTrackingStatus, 'registered')
assert.deepEqual(preview.memoryApplications, [{
memoryId: 'memory-transport-1',
fieldKey: 'transport_mode',
fieldLabel: '出行方式',
value: '火车',
status: 'applied',
evidenceCount: 4,
approvedEvidenceCount: 3,
message: '根据历史申请偏好填入'
}])
}
async function testLearningReceiptNormalizationAndForgetEndpoint() {
const receipts = resolveAiApplicationLearningReceipts({
result: {
learning_receipts: [{
memory_id: 'memory-reason-1',
field_key: 'reason',
field_label: '申请事由',
value: '客户现场实施',
status: 'candidate',
evidence_count: 2,
approved_evidence_count: 1,
message: '再确认一次后可形成稳定偏好'
}]
}
})
assert.deepEqual(receipts, [{
memoryId: 'memory-reason-1',
fieldKey: 'reason',
fieldLabel: '申请事由',
value: '客户现场实施',
status: 'candidate',
evidenceCount: 2,
approvedEvidenceCount: 1,
message: '再确认一次后可形成稳定偏好'
}])
let capturedUrl = ''
let capturedOptions = null
global.fetch = async (url, options) => {
capturedUrl = String(url)
capturedOptions = options
return {
ok: true,
async json() {
return { status: 'forgotten' }
}
}
}
await forgetAiApplicationMemory('memory/reason 1')
assert.equal(
capturedUrl,
'/api/v1/expense-application-memories/memory%2Freason%201'
)
assert.equal(capturedOptions.method, 'DELETE')
}
async function testEditDraftActionCarriesClaimAndEditableFields() {
@@ -259,6 +326,7 @@ async function run() {
await testSubmitActionUsesFastPreviewEndpoint()
await testSaveDraftActionUsesFastPreviewEndpoint()
await testRegistrationUsesServerCanonicalPreview()
await testLearningReceiptNormalizationAndForgetEndpoint()
await testEditDraftActionCarriesClaimAndEditableFields()
await testApplicationActionSourceCanBeConfiguredWithoutChangingWorkbenchDefaults()
console.log('ai-application-preview-actions tests passed')