| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- 'use strict';
- // Regression coverage for the relay callback boundary. The callback must
- // return before model generation completes, while the queued job still owns
- // the normal quality/delivery path.
- const assert = require('assert/strict');
- const fs = require('fs');
- const os = require('os');
- const path = require('path');
- const { AgentWorkbenchDb } = require('../mcp/src/core/agent-workbench-db');
- const { AgentWorkbenchService } = require('../mcp/src/core/agent-workbench-service');
- const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
- async function waitFor(check, timeoutMs = 1000) {
- const deadline = Date.now() + timeoutMs;
- while (Date.now() < deadline) {
- if (check()) return;
- await wait(10);
- }
- assert.equal(check(), true, '后台生成在限定时间内未完成');
- }
- function createFixture(agent) {
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-callback-generation-'));
- const db = new AgentWorkbenchDb(path.join(dir, 'workbench.db'), {
- defaultMode: 'autopilot',
- autoSendConfidence: 0.8,
- });
- const sent = [];
- const service = new AgentWorkbenchService({
- db,
- agent,
- qiwei: {
- isConfigured: () => true,
- async sendText(toId, content) {
- sent.push({ toId, content });
- return { isSendSuccess: true, msgServerId: `callback-out-${sent.length}` };
- },
- },
- config: {
- accountKey: 'callback-generation-smoke',
- agent: { provider: 'fixture', model: 'fixture', apiKey: 'fixture', generationRetryAttempts: 1, generationRetryBaseMs: 0, qualityPassScore: 60 },
- qiwei: { allowedSenders: ['callback-contact'] },
- memory: { enabled: false },
- },
- });
- return { dir, db, service, sent };
- }
- function output() {
- return {
- content: '已收到,我先按当前信息整理下一步。',
- confidence: 0.96,
- intent: '信息确认',
- reason: '异步回调测试固定输出。',
- requiresHuman: false,
- profileUpdates: {},
- tasks: [],
- alerts: [],
- citations: [],
- toolTrace: [],
- };
- }
- async function main() {
- let release;
- const generationGate = new Promise(resolve => { release = resolve; });
- let calls = 0;
- const fixture = createFixture({
- modelClient: { isConfigured: () => true },
- async run() {
- calls += 1;
- await generationGate;
- return output();
- },
- });
- try {
- const startedAt = Date.now();
- const queued = await fixture.service.ingestInbound({
- externalId: 'callback-async-1',
- contactId: 'callback-contact',
- contactName: '回调异步测试',
- content: '请介绍一下服务',
- }, { awaitGeneration: false, allowAutoSend: true });
- assert.equal(queued.status, 'generation_queued');
- assert(Date.now() - startedAt < 300, '回调不应等待模型生成');
- assert.equal(fixture.sent.length, 0, '模型完成前不能发送');
- await waitFor(() => calls === 1);
- release();
- await waitFor(() => fixture.sent.length === 1);
- assert.equal(fixture.sent[0].toId, 'callback-contact');
- assert.equal(fixture.db.listAudit(100).some(item => item.action === 'autopilot_message_sent'), true);
- } finally {
- fixture.service.stopBackgroundWorkers();
- fixture.db.close();
- fs.rmSync(fixture.dir, { recursive: true, force: true });
- }
- const failed = createFixture({
- modelClient: { isConfigured: () => true },
- async run() { throw new Error('fixture generation contract error'); },
- });
- try {
- const queued = await failed.service.ingestInbound({
- externalId: 'callback-async-failure',
- contactId: 'callback-contact',
- contactName: '回调失败测试',
- content: '普通问题',
- }, { awaitGeneration: false, allowAutoSend: true });
- assert.equal(queued.status, 'generation_queued');
- await waitFor(() => failed.db.listAudit(100).some(item => item.action === 'agent_failed'));
- assert.equal(failed.sent.length, 0, '生成失败不得发送空消息');
- } finally {
- failed.service.stopBackgroundWorkers();
- failed.db.close();
- fs.rmSync(failed.dir, { recursive: true, force: true });
- }
- process.stdout.write(JSON.stringify({ status: 'passed', checks: [
- 'relay callback returns generation_queued before model completion',
- 'background generation preserves autopilot delivery',
- 'background failure is audited without crashing the callback',
- ] }, null, 2) + '\n');
- }
- main().catch(error => {
- process.stderr.write(JSON.stringify({ status: 'failed', message: error.message, stack: error.stack }, null, 2) + '\n');
- process.exitCode = 1;
- });
|