| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- 'use strict';
- const assert = require('assert/strict');
- const {
- APPLIED_ACTION_STATUSES,
- CONFIRMING_EVIDENCE_TYPES,
- createJourneyDefinition,
- createJourneyState,
- applyJourneyFacts,
- isStageComplete,
- planAppliedAction,
- executeAppliedAction,
- confirmAppliedAction,
- serializeJourneyState,
- buildConversationStateSnapshot,
- } = require('../mcp/src/core/agent-conversation-journey');
- function confirmation(type, id, at) {
- return { type, id, at, success: true };
- }
- function main() {
- const definition = createJourneyDefinition({
- id: 'generic-consultation',
- initialStageId: 'understand',
- stages: [
- { id: 'understand', requiredFacts: ['goal'] },
- { id: 'qualify', requiredFacts: ['constraints.budget', 'constraints.timeline'] },
- { id: 'recommend', requiredFacts: ['selection'] },
- { id: 'commit', requiredFacts: ['commitment'] },
- ],
- });
- assert.deepEqual(APPLIED_ACTION_STATUSES, ['planned', 'executed', 'confirmed']);
- assert.deepEqual(CONFIRMING_EVIDENCE_TYPES, ['send', 'tool', 'handoff']);
- const initial = createJourneyState(definition, { at: '2026-08-06T01:00:00.000Z' });
- const observed = applyJourneyFacts(definition, initial, {
- constraints: { timeline: 'soon', budget: 100 },
- goal: 'compare options',
- }, { at: '2026-08-06T01:01:00.000Z' });
- assert.equal(initial.facts.goal, undefined);
- assert.equal(observed.currentStageId, 'understand');
- assert.equal(isStageComplete(definition, observed, 'qualify'), true);
- const planned = planAppliedAction(definition, observed, {
- key: 'reply:message-1',
- kind: 'reply',
- transition: { mode: 'auto' },
- payload: { draftId: 'draft-1' },
- at: '2026-08-06T01:02:00.000Z',
- });
- assert.equal(planned.currentStageId, 'understand');
- assert.equal(planned.appliedActions[0].status, 'planned');
- const executed = executeAppliedAction(definition, planned, {
- key: 'reply:message-1',
- evidence: { type: 'send', id: 'attempt-1', success: false },
- at: '2026-08-06T01:03:00.000Z',
- });
- assert.equal(executed.currentStageId, 'understand');
- assert.equal(executed.appliedActions[0].status, 'executed');
- assert.throws(() => confirmAppliedAction(definition, executed, {
- key: 'reply:message-1',
- evidence: { type: 'draft', id: 'draft-1', success: true },
- }), /Unsupported action evidence type/);
- assert.throws(() => confirmAppliedAction(definition, executed, {
- key: 'reply:message-1',
- evidence: { type: 'send', id: 'message-1', success: false },
- }), /successful evidence/);
- const advanced = confirmAppliedAction(definition, executed, {
- key: 'reply:message-1',
- evidence: confirmation('send', 'message-1', '2026-08-06T01:04:00.000Z'),
- });
- assert.equal(advanced.currentStageId, 'recommend');
- assert.equal(advanced.appliedActions[0].status, 'confirmed');
- assert.deepEqual(advanced.appliedActions[0].transitionResult.skippedStageIds, ['qualify']);
- assert(advanced.stageHistory.some(entry => entry.kind === 'skip' && entry.stageId === 'qualify'));
- const backPlanned = planAppliedAction(definition, advanced, {
- key: 'handoff:requalify',
- kind: 'human_handoff',
- transition: { mode: 'back', targetStageId: 'qualify' },
- });
- const backed = confirmAppliedAction(definition, backPlanned, {
- key: 'handoff:requalify',
- evidence: confirmation('handoff', 'handoff-1', '2026-08-06T01:05:00.000Z'),
- });
- assert.equal(backed.currentStageId, 'qualify');
- assert.equal(backed.stageHistory.at(-1).kind, 'back');
- const reenterPlanned = planAppliedAction(definition, backed, {
- key: 'tool:refresh-qualification',
- kind: 'refresh',
- transition: { mode: 'reenter', targetStageId: 'qualify' },
- });
- const reentered = confirmAppliedAction(definition, reenterPlanned, {
- key: 'tool:refresh-qualification',
- evidence: confirmation('tool', 'tool-run-1', '2026-08-06T01:06:00.000Z'),
- });
- assert.equal(reentered.currentStageId, 'qualify');
- assert.equal(reentered.stageHistory.at(-1).kind, 'reenter');
- const skipPlanned = planAppliedAction(definition, reentered, {
- key: 'reply:direct-commit',
- kind: 'reply',
- transition: { mode: 'to', targetStageId: 'commit' },
- });
- const skipped = confirmAppliedAction(definition, skipPlanned, {
- key: 'reply:direct-commit',
- evidence: confirmation('send', 'message-2', '2026-08-06T01:07:00.000Z'),
- });
- assert.equal(skipped.currentStageId, 'commit');
- assert.deepEqual(skipped.appliedActions.at(-1).transitionResult.skippedStageIds, ['recommend']);
- const deduped = planAppliedAction(definition, skipped, {
- key: 'reply:direct-commit',
- kind: 'reply',
- transition: { mode: 'to', targetStageId: 'commit' },
- });
- assert.equal(deduped.appliedActions.length, skipped.appliedActions.length);
- assert.equal(deduped.sequence, skipped.sequence);
- assert.throws(() => planAppliedAction(definition, skipped, {
- key: 'reply:direct-commit',
- kind: 'different-action',
- transition: { mode: 'none' },
- }), /key conflict/);
- const serialized = serializeJourneyState(skipped);
- assert.equal(serialized, serializeJourneyState(JSON.parse(serialized)));
- const reordered = {
- ...skipped,
- facts: {
- goal: skipped.facts.goal,
- constraints: {
- budget: skipped.facts.constraints.budget,
- timeline: skipped.facts.constraints.timeline,
- },
- },
- };
- assert.equal(serialized, serializeJourneyState(reordered));
- assert(skipped.appliedActions.every(action => APPLIED_ACTION_STATUSES.includes(action.status)));
- const snapshot = buildConversationStateSnapshot({
- inboundContent: '预算 20 万,想预约明天下午到店',
- messages: [{ role: 'user', content: '想了解企业服务收费' }],
- profile: { budget: '20万' },
- });
- assert.equal(snapshot.knownConstraints.budget.source, 'conversation');
- assert.equal(snapshot.highIntent.active, true);
- assert.equal(snapshot.highIntent.kind, 'schedule_intake');
- assert(snapshot.knownFields.includes('budget'));
- assert(snapshot.knownFields.includes('appointmentIntent'));
- process.stdout.write(`${JSON.stringify({
- status: 'ok',
- checks: 30,
- finalStage: skipped.currentStageId,
- actions: skipped.appliedActions.length,
- historyEntries: skipped.stageHistory.length,
- snapshotFields: snapshot.knownFields,
- }, null, 2)}\n`);
- }
- try { main(); }
- catch (error) {
- process.stderr.write(`${error.stack || error.message}\n`);
- process.exit(1);
- }
|