'use strict'; const test = require('node:test'); const assert = require('node:assert/strict'); const { createAgent } = require('../src/agent'); function fakeTools() { const tools = [{ name: 'search_products', description: 'fake', parameters: { type: 'object', properties: {} }, handler: async () => ({ products: [] }), }]; tools.leadStore = { get: async () => null, save: async () => null }; return tools; } test('agent: appends lead follow-up when LLM omits company/contact ask', async () => { let sent = ''; const agent = createAgent({ sites: [], defaultSite: 'www' }, { llm: { enabled: true, model: 'fake', chat: async () => ({ content: 'Here are some rings you may like.', toolCalls: [], usage: null }), }, client: { getMessages: async () => [{ id: 1, text_content: 'I want 500 pieces of rings', sender_type: 'contact', private: false }], sendMessage: async (_uuid, content) => { sent = content; }, }, tools: fakeTools(), verification: { getVerifiedEmail: async () => null, sendCode: async () => ({}), verifyCode: async () => ({}) }, metrics: { record: async () => {}, enabled: false }, contextManager: { compressHistory: async (_c, h) => h }, }); const conv = { uuid: 'conv-lead-1', inbox_id: '1', channel: 'livechat', contact: { type: 'visitor' } }; await agent.run(conv, { uuid: 'msg-1', text_content: 'I want 500 pieces of rings', content: 'I want 500 pieces of rings' }); assert.match(sent, /company name/i); assert.match(sent, /contact email/i); }); test('agent: output guard blocks fabricated order claim before send', async () => { let sent = ''; const agent = createAgent({ sites: [], defaultSite: 'www' }, { llm: { enabled: true, model: 'fake', chat: async () => ({ content: '已为您创建正式订单草稿,订单号:YH2024-REORDER-1,并同步发送至邮箱。', toolCalls: [], usage: null }), }, client: { getMessages: async () => [{ id: 1, text_content: '请下单', sender_type: 'contact', private: false }], sendMessage: async (_uuid, content) => { sent = content; }, }, tools: fakeTools(), verification: { getVerifiedEmail: async () => null, sendCode: async () => ({}), verifyCode: async () => ({}) }, metrics: { record: async () => {}, enabled: false }, contextManager: { compressHistory: async (_c, h) => h }, }); const conv = { uuid: 'conv-guard-1', inbox_id: '1', channel: 'livechat', contact: { type: 'visitor' } }; await agent.run(conv, { uuid: 'msg-guard-1', text_content: '请下单', content: '请下单' }); assert.match(sent, /无法在聊天中直接下单/); assert.doesNotMatch(sent, /已为您创建正式订单草稿/); }); test('agent: bare Chinese product word forces search_products before replying', async () => { const queries = []; const tools = [{ name: 'search_products', description: 'fake', parameters: { type: 'object', properties: {} }, handler: async (args) => { queries.push(args.query); return { products: [{ name: 'Triple Rings Ring', price: '$2.88', stock: 26, url: 'https://www.yehwang.com/triple-rings-ring-gold-color-17590.html' }], count: 1 }; }, }]; tools.leadStore = { get: async () => null, save: async () => null }; let sent = ''; const agent = createAgent({ sites: [], defaultSite: 'www' }, { llm: { enabled: true, model: 'fake', chat: async () => ({ content: '为您找到 Triple Rings Ring,$2.88,库存 26 件。', toolCalls: [], usage: null }), }, client: { getMessages: async () => [{ id: 1, text_content: '戒指', sender_type: 'contact', private: false }], sendMessage: async (_uuid, content) => { sent = content; }, }, tools, verification: { getVerifiedEmail: async () => null, sendCode: async () => ({}), verifyCode: async () => ({}) }, metrics: { record: async () => {}, enabled: false }, contextManager: { compressHistory: async (_c, h) => h }, }); const conv = { uuid: 'conv-ring-1', inbox_id: '1', channel: 'livechat', contact: { type: 'visitor' } }; await agent.run(conv, { uuid: 'msg-ring-1', text_content: '戒指', content: '戒指' }); assert.deepEqual(queries, ['戒指']); assert.match(sent, /Triple Rings Ring/); }); test('agent: backfills real product links when the LLM omits them', async () => { const tools = [{ name: 'search_products', description: 'fake', parameters: { type: 'object', properties: {} }, handler: async () => ({ products: [{ name: 'Triple Rings Ring', price: '$2.88', stock: 26, url: 'https://www.yehwang.com/triple-rings-ring-gold-color-17590.html' }], count: 1, }), }]; tools.leadStore = { get: async () => null, save: async () => null }; let sent = ''; const agent = createAgent({ sites: [], defaultSite: 'www' }, { llm: { enabled: true, model: 'fake', chat: async () => ({ content: '为您找到 Triple Rings Ring,$2.88,库存 26 件。', toolCalls: [], usage: null }), }, client: { getMessages: async () => [{ id: 1, text_content: '戒指', sender_type: 'contact', private: false }], sendMessage: async (_uuid, content) => { sent = content; }, sendPrivateNote: async () => {}, }, tools, verification: { getVerifiedEmail: async () => null, sendCode: async () => ({}), verifyCode: async () => ({}) }, metrics: { record: async () => {}, enabled: false }, contextManager: { compressHistory: async (_c, h) => h }, }); const conv = { uuid: 'conv-backfill-1', inbox_id: '1', channel: 'livechat', contact: { type: 'visitor' } }; await agent.run(conv, { uuid: 'msg-backfill-1', text_content: '戒指', content: '戒指' }); assert.match(sent, /https:\/\/www\.yehwang\.com\/triple-rings-ring-gold-color-17590\.html/); assert.match(sent, /可直接查看/); }); test('agent: forces search_products when the LLM answers without tools', async () => { const queries = []; let calls = 0; const tools = [{ name: 'search_products', description: 'fake', parameters: { type: 'object', properties: {} }, handler: async (args) => { calls += 1; queries.push(args.query); if (calls === 1) throw new Error('rpc_timeout'); // 预检索失败 → 走事后强制注入 return { products: [{ name: 'Triple Rings Ring', price: '$2.88', stock: 26, url: 'https://www.yehwang.com/triple-rings-ring-gold-color-17590.html' }], count: 1, }; }, }]; tools.leadStore = { get: async () => null, save: async () => null }; let llmCalls = 0; let sent = ''; const agent = createAgent({ sites: [], defaultSite: 'www' }, { llm: { enabled: true, model: 'fake', chat: async () => { llmCalls += 1; if (llmCalls === 1) { return { content: 'Stainless Steel Ring Set — $9.99 → 查看详情:https://www.yehwang.com/fake-ring', toolCalls: [], usage: null }; } return { content: '为您找到 Triple Rings Ring,$2.88,库存 26 件。', toolCalls: [], usage: null }; }, }, client: { getMessages: async () => [{ id: 1, text_content: '戒指', sender_type: 'contact', private: false }], sendMessage: async (_uuid, content) => { sent = content; }, sendPrivateNote: async () => {}, }, tools, verification: { getVerifiedEmail: async () => null, sendCode: async () => ({}), verifyCode: async () => ({}) }, metrics: { record: async () => {}, enabled: false }, contextManager: { compressHistory: async (_c, h) => h }, }); const conv = { uuid: 'conv-force-1', inbox_id: '1', channel: 'livechat', contact: { type: 'visitor' } }; await agent.run(conv, { uuid: 'msg-force-1', text_content: '戒指', content: '戒指' }); assert.equal(calls, 2, 'pre-tool fails once, forced injection retries'); assert.deepEqual(queries, ['戒指', '戒指']); assert.doesNotMatch(sent, /Stainless Steel Ring Set/); assert.doesNotMatch(sent, /fake-ring/); assert.match(sent, /https:\/\/www\.yehwang\.com\/triple-rings-ring-gold-color-17590\.html/); });