customer-master-smoke-test.js 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  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. displayName: '测试客户',
  13. maskedId: '16***34',
  14. source: 'live',
  15. mode: 'review',
  16. analysis: { completenessScore: 50 },
  17. messages: [{ id: 'm1', role: 'customer', content: '预算 200 万,想看三室', timestamp: '2026-07-17T01:00:00Z' }],
  18. customerIntelligence: {
  19. profile: { budgetWan: 200, layout: '三室', preferredRegion: '新北区' },
  20. profileEvidence: { budgetWan: { text: '预算 200 万', sourceMessageId: 'm1', updatedAt: '2026-07-17T01:00:00Z' } },
  21. profileUpdatedAt: '2026-07-17T01:00:00Z',
  22. tags: ['高预算'],
  23. tasks: [{ id: 't1', title: '确认用途', status: 'open', evidence: '用途尚未明确' }],
  24. alerts: [{ id: 'a1', title: '需求已成形', status: 'open', severity: 'high', evidence: '预算和户型明确' }],
  25. summary: { openTasks: 1, openAlerts: 1, highAlerts: 1 },
  26. },
  27. lastMessageAt: '2026-07-17T01:00:00Z',
  28. updatedAt: '2026-07-17T01:00:00Z',
  29. };
  30. const { createCustomerMasterService } = require('../mcp/src/dashboard/customer-master-service');
  31. const projectionPath = path.join(tempDir, 'customers', 'index.json');
  32. const service = createCustomerMasterService({
  33. projectionPath,
  34. getConversations: () => ({ status: 'ok', data: { conversations: [conversation] } }),
  35. updateCustomerProfile: (id, input) => {
  36. updateCall = { id, input };
  37. return { status: 'ok', assistantMessage: '主档已更新', summary: { changedFields: Object.keys(input.profile || {}) } };
  38. },
  39. });
  40. const hub = service.hub();
  41. assert.equal(hub.status, 'ok');
  42. assert.equal(hub.summary.customerCount, 1);
  43. assert.equal(hub.summary.profiledCount, 1);
  44. assert.equal(hub.summary.priorityCount, 1);
  45. assert.equal(hub.data.customers[0].source, '真实企微会话');
  46. assert.equal(hub.data.customers[0].evidenceCoverage, 33);
  47. assert.equal(hub.data.customers[0].openTaskCount, 1);
  48. assert(fs.existsSync(projectionPath));
  49. const projection = fs.readFileSync(projectionPath, 'utf8');
  50. assert.doesNotMatch(projection, /预算 200 万,想看三室|预算 200 万/);
  51. assert.doesNotMatch(projection, /externalUserId|contact_id/);
  52. const updated = service.update('conversation-live-1', { profile: { intent: '自住' }, reason: '人工确认' });
  53. assert.equal(updated.status, 'ok');
  54. assert.equal(updateCall.id, 'conversation-live-1');
  55. assert.equal(updateCall.input.profile.intent, '自住');
  56. assert.equal(updateCall.input.reason, '人工确认');
  57. process.stdout.write(`${JSON.stringify({ status: 'ok', checks: 13, customers: hub.summary.customerCount, evidenceProjectionSafe: true }, null, 2)}\n`);
  58. }
  59. main().catch(error => {
  60. process.stderr.write(`${error.stack || error.message}\n`);
  61. process.exitCode = 1;
  62. }).finally(() => {
  63. try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch {}
  64. });