Files
crm-ai/bridge/test/output-guard.test.js

197 lines
7.7 KiB
JavaScript

'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const { guardReply, detectActionClaims } = require('../src/output-guard');
test('guard: blocks fabricated order/email/order-number claims', () => {
const r = guardReply({
content: '已为您创建正式订单草稿,并同步发送至邮箱,订单号:YH2024-REORDER-501037918,含PDF发票。',
toolResults: [],
toolCalls: [],
lang: 'zh',
});
assert.equal(r.blocked, true);
assert.ok(r.reasons.includes('order_create'));
assert.ok(r.reasons.includes('email_send'));
assert.ok(r.reasons.includes('order_number'));
assert.doesNotMatch(r.content, /已为您创建正式订单/);
assert.match(r.content, /无法在聊天中直接下单/);
});
test('guard: future offer is not a violation', () => {
const r = guardReply({
content: 'I can help you place an order in your account cart.',
toolResults: [],
toolCalls: [],
lang: 'en',
});
assert.equal(r.blocked, false);
});
test('guard: stock/price claim without tool evidence is blocked', () => {
const r = guardReply({
content: '这些商品都有货,单价 €6.40。',
toolResults: [],
toolCalls: [],
lang: 'zh',
});
assert.equal(r.blocked, true);
assert.ok(r.reasons.includes('stock_price_without_tool'));
});
test('guard: stock/price with inventory tool evidence passes', () => {
const r = guardReply({
content: '有货,单价 €6.40。',
toolResults: [{ product_id: 1, instant_stock: 10, price: '6.40' }],
toolCalls: [{ name: 'search_inventory', ok: true }],
lang: 'zh',
});
assert.equal(r.blocked, false);
});
test('guard: removes unverified URLs but keeps tool URLs', () => {
const r = guardReply({
content: '真实链接 https://www.yehwang.com/real-123.html 和伪造 https://www.yehwang.com/fake-thing',
toolResults: [{ url: 'https://www.yehwang.com/real-123.html' }],
toolCalls: [{ name: 'search_products', ok: true }],
lang: 'en',
});
assert.equal(r.blocked, true);
assert.equal(r.rewritten, true);
assert.deepEqual(r.removed_urls, ['https://www.yehwang.com/fake-thing']);
assert.match(r.content, /real-123\.html/);
assert.doesNotMatch(r.content, /fake-thing/);
});
test('guard: opportunity/CRM wording is never sent to customer', () => {
const withTool = guardReply({ content: 'Opportunity created successfully. Opportunity ID: 5f3d...', toolResults: [], toolCalls: [{ name: 'create_opportunity', ok: true }], lang: 'en' });
const withoutTool = guardReply({ content: 'Opportunity created successfully. Opportunity ID: 5f3d...', toolResults: [], toolCalls: [], lang: 'en' });
assert.equal(withTool.blocked, true);
assert.equal(withoutTool.blocked, true);
assert.doesNotMatch(withTool.content, /CRM|opportunity/i);
});
test('guard: detects order and team notifications', () => {
const types = detectActionClaims('team has been notified and your order number: ABC12345').map((x) => x.type);
assert.ok(types.includes('team_notify'));
assert.ok(types.includes('order_number'));
});
test('guard: blocks price not present in tool results even when a tool was called', () => {
const r = guardReply({
content: '单价从 €1.25 起,库存实时更新。',
toolResults: [{ products: [{ name: 'Rings category' }], category_links: [{ url: 'https://www.yehwang.com/jewelry/rings' }] }],
toolCalls: [{ name: 'search_products', ok: true }],
lang: 'zh',
});
assert.equal(r.blocked, true);
assert.ok(r.reasons.includes('ungrounded_numbers'));
});
test('guard: allows price that exists in tool results', () => {
const r = guardReply({
content: '价格 €3.74,库存 152 pcs。',
toolResults: [{ products: [{ price: '3.74', stock: 152 }] }],
toolCalls: [{ name: 'search_products', ok: true }],
lang: 'zh',
});
assert.equal(r.blocked, false);
});
test('guard: customer never sees CRM/opportunity wording', () => {
const r = guardReply({
content: 'Opportunity created successfully. Opportunity ID: 5f3d... Team has been notified and your quote was sent.',
toolResults: [],
toolCalls: [{ name: 'create_opportunity', ok: true }],
lang: 'zh',
});
assert.equal(r.blocked, true);
assert.match(r.content, /相关同事会与您联系/);
assert.doesNotMatch(r.content, /CRM|商机|opportunity/i);
});
test('guard: rewrites action claims but keeps product list', () => {
const r = guardReply({
content: '已为您创建订单草稿。\n- 商品A €3.74\n- 商品B €2.00',
toolResults: [{ products: [{ name: '商品A', price: '3.74' }, { name: '商品B', price: '2.00' }] }],
toolCalls: [{ name: 'create_opportunity', ok: true }, { name: 'search_products', ok: true }],
lang: 'zh',
});
assert.equal(r.blocked, true);
assert.equal(r.rewritten, true);
assert.doesNotMatch(r.content, /已为您创建订单/);
assert.match(r.content, /商品A/);
assert.match(r.content, /3\.74/);
assert.match(r.content, /无法在聊天中直接下单/);
});
test('guard: rewrites unsupported price but keeps product name', () => {
const r = guardReply({
content: '商品A有货,单价 €1.25。链接 https://www.yehwang.com/fake-a',
toolResults: [{ products: [{ name: '商品A' }] }],
toolCalls: [{ name: 'search_products', ok: true }],
lang: 'zh',
});
assert.equal(r.blocked, true);
assert.equal(r.rewritten, true);
assert.match(r.content, /商品A/);
assert.doesNotMatch(r.content, /€1\.25/);
assert.doesNotMatch(r.content, /fake-a/);
assert.match(r.content, /价格以商品页为准/);
});
test('guard: drops dangling CTA text when a hallucinated product link is removed', () => {
const r = guardReply({
content: '<p>🔹 <strong>Stainless Steel Ring Set</strong> — $2.88<br>✅ 库存:充足<br>→ 查看详情:https://www.yehwang.com/stainless-steel-ring-set-12-pcs</p>',
toolResults: [],
toolCalls: [],
lang: 'zh',
});
assert.equal(r.blocked, true);
assert.ok(r.reasons.includes('stock_price_without_tool'));
assert.deepEqual(r.removed_urls, ['https://www.yehwang.com/stainless-steel-ring-set-12-pcs']);
assert.doesNotMatch(r.content, /查看详情/);
assert.doesNotMatch(r.content, /stainless-steel-ring-set-12-pcs/);
assert.match(r.content, /价格以商品页为准/);
});
test('guard: generic CTA label is removed together with the unverified URL', () => {
const r = guardReply({
content: '商品A — [查看详情](https://www.yehwang.com/fake-a)',
toolResults: [{ products: [{ name: '商品A' }] }],
toolCalls: [{ name: 'search_products', ok: true }],
lang: 'zh',
});
assert.equal(r.blocked, true);
assert.deepEqual(r.removed_urls, ['https://www.yehwang.com/fake-a']);
assert.doesNotMatch(r.content, /查看详情/);
assert.match(r.content, /商品A/);
});
test('guard: keeps meaningful anchor text when the URL is removed', () => {
const r = guardReply({
content: 'You can read [the product care guide](https://www.yehwang.com/fake-guide) for details.',
toolResults: [],
toolCalls: [],
lang: 'en',
});
assert.equal(r.blocked, true);
assert.doesNotMatch(r.content, /fake-guide/);
assert.match(r.content, /the product care guide/);
});
test('guard: CRM wording is replaced with a colleague follow-up, not a cart note', () => {
const r = guardReply({
content: 'Great — 500 stainless steel rings for your shops.\nI have created an opportunity for your request.',
toolResults: [{ created: true, opportunity_id: 'opp-1' }],
toolCalls: [{ name: 'create_opportunity', ok: true }],
lang: 'en',
});
assert.equal(r.blocked, true);
assert.ok(r.reasons.includes('internal_crm'));
assert.match(r.content, /stainless steel rings/i);
assert.match(r.content, /request has been noted/i);
assert.doesNotMatch(r.content, /account cart/i);
});