| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- 'use strict';
- const assert = require('assert/strict');
- const {
- FUTURE_PROMISE_REASON_CODES: REASONS,
- extractActionClaims,
- normalizeActionEvidence,
- verifyFuturePromises,
- } = require('../mcp/src/core/response-future-promise-verifier');
- let assertions = 0;
- function check(condition, message) {
- assertions += 1;
- assert(condition, message);
- }
- function equal(actual, expected, message) {
- assertions += 1;
- assert.equal(actual, expected, message);
- }
- function hasReason(result, reason) {
- check(result.reasonCodes.includes(reason), `${reason} missing: ${result.reasonCodes.join(',')}`);
- }
- function successfulTool(tool, result, extra = {}) {
- return { tool, status: 'completed', result, ...extra };
- }
- const noEvidence = verifyFuturePromises({ reply: '我稍后核实库存,再通知您。' });
- equal(noEvidence.passed, false, 'future promises without evidence must fail');
- equal(noEvidence.failedClaimIds.length, 2, 'verify and notify should be independent claims');
- hasReason(noEvidence, REASONS.FUTURE_ACTION_MISSING_EVIDENCE);
- const matchingEvidence = verifyFuturePromises({
- reply: '库存已经核实,结果已通知您。',
- toolTrace: [successfulTool('inventory_verify', { ok: true, subject: '库存', available: true })],
- outboundEvidence: { status: 'delivered', subject: '库存', result: { delivered: true } },
- });
- equal(matchingEvidence.passed, true, 'matching successful evidence should pass');
- equal(matchingEvidence.claims.length, 2);
- check(matchingEvidence.claims.every(claim => claim.evidenceMatched), 'all matching claims should carry evidence');
- check(matchingEvidence.claims.every(claim => claim.evidenceRefs.length === 1), 'evidence refs should be stable and compact');
- const unrelatedTool = verifyFuturePromises({
- reply: '库存已经核实。',
- toolTrace: [successfulTool('knowledge_search', { ok: true, subject: '品牌介绍' })],
- });
- equal(unrelatedTool.passed, false, 'unrelated tool result must not support stock verification');
- hasReason(unrelatedTool, REASONS.ACTION_EVIDENCE_UNRELATED);
- const citationBypass = verifyFuturePromises({
- reply: '我会稍后核实价格。',
- citations: [{ content: '价格说明' }],
- });
- equal(citationBypass.passed, false, 'citations are not execution evidence');
- hasReason(citationBypass, REASONS.FUTURE_ACTION_MISSING_EVIDENCE);
- const scopedUncertainty = verifyFuturePromises({ reply: '价格已经确认,其他信息待核验。' });
- equal(scopedUncertainty.passed, false, 'uncertainty in another clause must not protect a performed claim');
- hasReason(scopedUncertainty, REASONS.PERFORMED_ACTION_MISSING_EVIDENCE);
- const conditionalOffer = verifyFuturePromises({ reply: '可以为您核验,是否需要?' });
- equal(conditionalOffer.passed, true, 'conditional proposal is safe');
- equal(conditionalOffer.claims[0].requiresEvidence, false);
- hasReason(conditionalOffer, REASONS.SAFE_CONDITIONAL_OFFER);
- const missingInput = verifyFuturePromises({ reply: '请提供订单号,我再为您核实。' });
- equal(missingInput.passed, true, 'requesting missing input before continuing is safe');
- equal(missingInput.claims[0].requiresEvidence, false);
- hasReason(missingInput, REASONS.SAFE_MISSING_INPUT_REQUEST);
- const handoffMissing = verifyFuturePromises({ reply: '已经转交人工专员。' });
- equal(handoffMissing.passed, false, 'performed handoff requires evidence');
- equal(handoffMissing.claims[0].action, 'handoff');
- hasReason(handoffMissing, REASONS.PERFORMED_ACTION_MISSING_EVIDENCE);
- const handoffPassed = verifyFuturePromises({
- reply: '已经转交人工专员。',
- handoffEvidence: { status: 'completed', handoffId: 'handoff-test' },
- });
- equal(handoffPassed.passed, true, 'completed handoff evidence should pass');
- hasReason(handoffPassed, REASONS.PERFORMED_ACTION_VERIFIED);
- const outboundNotHandoff = verifyFuturePromises({
- reply: '已经转交人工专员。',
- outboundEvidence: { status: 'delivered', result: { delivered: true } },
- });
- equal(outboundNotHandoff.passed, false, 'outbound delivery cannot prove a handoff');
- hasReason(outboundNotHandoff, REASONS.ACTION_EVIDENCE_UNRELATED);
- const processingMissing = verifyFuturePromises({ reply: '正在处理您的退款。' });
- equal(processingMissing.passed, false, 'in-progress processing requires evidence');
- hasReason(processingMissing, REASONS.IN_PROGRESS_ACTION_MISSING_EVIDENCE);
- const activeCrossCheckMissing = verifyFuturePromises({ reply: '我现在核对执行条件,确认后回复您。' });
- equal(activeCrossCheckMissing.passed, false, 'first-person active cross-check requires evidence');
- hasReason(activeCrossCheckMissing, REASONS.IN_PROGRESS_ACTION_MISSING_EVIDENCE);
- const processingPassed = verifyFuturePromises({
- reply: '正在处理您的退款。',
- toolTrace: [successfulTool('process_refund', { ok: true, subject: '退款' })],
- });
- equal(processingPassed.passed, true, 'successful matching process evidence should pass');
- hasReason(processingPassed, REASONS.IN_PROGRESS_ACTION_VERIFIED);
- const failedEvidence = verifyFuturePromises({
- reply: '价格已经核实。',
- toolTrace: [{ tool: 'price_verify', status: 'failed', result: { ok: false, subject: '价格' } }],
- });
- equal(failedEvidence.passed, false, 'failed matching tool must not support a claim');
- hasReason(failedEvidence, REASONS.ACTION_EVIDENCE_FAILED);
- const callbackMissing = verifyFuturePromises({ reply: '我会尽快给您回电。' });
- equal(callbackMissing.passed, false, 'callback promise requires successful call evidence');
- equal(callbackMissing.claims[0].action, 'callback');
- const callbackPassed = verifyFuturePromises({
- reply: '已经给您回电。',
- toolTrace: [successfulTool('call_customer', { success: true, subject: '电话' })],
- });
- equal(callbackPassed.passed, true, 'call evidence should prove callback');
- const submitPassed = verifyFuturePromises({
- reply: '退款申请已经提交。',
- toolTrace: [successfulTool('submit_refund_request', { ok: true, subject: '退款申请', requestId: 'fixture' })],
- });
- equal(submitPassed.passed, true, 'matching submit evidence should prove submission');
- equal(submitPassed.claims.length, 2, 'refund and submit actions are independently evidenced by one matching tool');
- const cancelPassed = verifyFuturePromises({
- reply: '订单已经取消。',
- toolTrace: [successfulTool('cancel_order', { ok: true, subject: '订单' })],
- });
- equal(cancelPassed.passed, true, 'matching cancel evidence should pass');
- const safeNecessity = verifyFuturePromises({ reply: '当前价格需要核验。' });
- equal(safeNecessity.passed, true, 'honest necessity is not an execution claim');
- equal(safeNecessity.claims.length, 0);
- hasReason(safeNecessity, REASONS.NO_ACTION_CLAIMS);
- const noClaims = verifyFuturePromises({ reply: '当前资料不足,请提供订单号。' });
- equal(noClaims.passed, true);
- equal(noClaims.checks.length, 3);
- check(noClaims.checks.every(item => (
- typeof item.id === 'string'
- && typeof item.passed === 'boolean'
- && typeof item.weight === 'number'
- && typeof item.hard === 'boolean'
- && typeof item.detail === 'string'
- )), 'checks must keep the stable quality-check shape');
- const extracted = extractActionClaims('我稍后核实价格,再通知您。');
- equal(extracted.length, 2);
- check(extracted.every((claim, index) => claim.id === `claim_${index + 1}`), 'claim ids must be deterministic');
- const normalized = normalizeActionEvidence({
- handoffEvidence: { status: 'completed' },
- outboundEvidence: { delivered: true },
- });
- equal(normalized.length, 2);
- check(normalized.every(item => item.success), 'explicit success is required and preserved');
- check(normalized.some(item => item.actionIds.includes('handoff')));
- check(normalized.some(item => item.actionIds.includes('notify')));
- console.log(JSON.stringify({
- ok: true,
- assertions,
- cases: 21,
- checks: ['future_promise_evidence', 'performed_action_evidence', 'conditional_proposal_safety'],
- reasonCodes: Object.values(REASONS),
- }, null, 2));
|