customer-master-smoke-test.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. const assert = require('assert');
  2. const fs = require('fs');
  3. const os = require('os');
  4. const path = require('path');
  5. const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-customer-master-'));
  6. process.env.QIWEI_OUTPUTS_DIR = tempDir;
  7. process.env.QIWEI_AGENT_DB_PATH = path.join(tempDir, 'messages', 'agent-workbench.db');
  8. async function main() {
  9. let updateCall = null;
  10. const conversation = {
  11. id: 'conversation-live-1',
  12. channelId: 'external-contact-1',
  13. displayName: '测试客户',
  14. maskedId: '16***34',
  15. source: 'live',
  16. mode: 'review',
  17. analysis: { completenessScore: 50 },
  18. messages: [{ id: 'm1', role: 'customer', content: '预算 20 万,想了解企业培训服务', timestamp: '2026-07-17T01:00:00Z' }],
  19. customerIntelligence: {
  20. profile: { budgetWan: 20, need: '企业培训服务', timeline: '本月内' },
  21. profileEvidence: { budgetWan: { text: '预算 20 万', sourceMessageId: 'm1', updatedAt: '2026-07-17T01:00:00Z' } },
  22. profileUpdatedAt: '2026-07-17T01:00:00Z',
  23. tags: ['高预算'],
  24. tasks: [{ id: 't1', title: '确认用途', status: 'open', evidence: '用途尚未明确' }],
  25. alerts: [{ id: 'a1', title: '需求已成形', status: 'open', severity: 'high', evidence: '预算和服务需求明确' }],
  26. summary: { openTasks: 1, openAlerts: 1, highAlerts: 1 },
  27. },
  28. lastMessageAt: '2026-07-17T01:00:00Z',
  29. updatedAt: '2026-07-17T01:00:00Z',
  30. };
  31. const { createCustomerMasterService } = require('../mcp/src/dashboard/customer-master-service');
  32. const projectionPath = path.join(tempDir, 'customers', 'index.json');
  33. const service = createCustomerMasterService({
  34. projectionPath,
  35. getConversations: () => ({ status: 'ok', data: { conversations: [conversation] } }),
  36. updateCustomerProfile: (id, input) => {
  37. updateCall = { id, input };
  38. return { status: 'ok', assistantMessage: '主档已更新', summary: { changedFields: Object.keys(input.profile || {}) } };
  39. },
  40. });
  41. const hub = service.hub();
  42. assert.equal(hub.status, 'ok');
  43. assert.equal(hub.summary.customerCount, 1);
  44. assert.equal(hub.summary.profiledCount, 1);
  45. assert.equal(hub.summary.priorityCount, 1);
  46. assert.equal(hub.data.customers[0].source, '真实企微会话');
  47. assert.equal(hub.data.customers[0].evidenceCoverage, 33);
  48. assert.equal(hub.data.customers[0].externalUserId, 'external-contact-1');
  49. assert.equal(hub.data.customers[0].openTaskCount, 1);
  50. assert(fs.existsSync(projectionPath));
  51. const projection = fs.readFileSync(projectionPath, 'utf8');
  52. assert.doesNotMatch(projection, /预算 20 万,想了解企业培训服务|预算 20 万/);
  53. assert.doesNotMatch(projection, /externalUserId|contact_id/);
  54. const updated = service.update('conversation-live-1', { profile: { intent: '采购服务' }, reason: '人工确认' });
  55. assert.equal(updated.status, 'ok');
  56. assert.equal(updateCall.id, 'conversation-live-1');
  57. assert.equal(updateCall.input.profile.intent, '采购服务');
  58. assert.equal(updateCall.input.reason, '人工确认');
  59. process.stdout.write(`${JSON.stringify({ status: 'ok', checks: 14, customers: hub.summary.customerCount, evidenceProjectionSafe: true }, null, 2)}\n`);
  60. }
  61. main().catch(error => {
  62. process.stderr.write(`${error.stack || error.message}\n`);
  63. process.exitCode = 1;
  64. }).finally(() => {
  65. try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch {}
  66. });