feat: port quality, escalation, KB version, site-map KB, experiments and metrics

This commit is contained in:
wangliang
2026-10-23 11:41:09 +08:00
parent 81b49c9350
commit b778570045
33 changed files with 2446 additions and 344 deletions
+4 -1
View File
@@ -1,11 +1,12 @@
'use strict';
const { ToolError } = require('./errors');
const { attachChatToOpportunity } = require('./chat-log');
const STAGES = new Set(['NEW', 'SCREENING', 'MEETING', 'PROPOSAL', 'CUSTOMER']);
// 对齐旧 bridge leadPipeline:指纹去重、跨渠道复用/同步、阶段推进、CRM 故障 fail-closed。
function createOpportunityService({ cfg, twenty, leadStore }) {
function createOpportunityService({ cfg, twenty, leadStore, client }) {
function splitName(full) {
const parts = String(full || '').trim().split(/[\s.]+/).filter(Boolean);
if (parts.length >= 2) return { firstName: parts[0], lastName: parts.slice(1).join(' ') };
@@ -140,6 +141,7 @@ function createOpportunityService({ cfg, twenty, leadStore }) {
}
const noteId = await twenty.createNote(summary);
if (noteId) await twenty.linkNoteToOpportunity(noteId, existing.id);
setImmediate(() => attachChatToOpportunity({ client, twenty, convUuid: conversationUuid, opportunityId: existing.id }).catch(() => {}));
const stage = await advanceStage({ ctx, state, slots, email: slots.email || email });
return {
created: false,
@@ -187,6 +189,7 @@ function createOpportunityService({ cfg, twenty, leadStore }) {
if (noteId) await twenty.linkNoteToOpportunity(noteId, opp.id);
const dueAt = new Date(Date.now() + 3 * 86400 * 1000).toISOString();
const taskId = await twenty.createTask(`Follow up: ${slots.company}`, summary, dueAt, opp.id);
setImmediate(() => attachChatToOpportunity({ client, twenty, convUuid: conversationUuid, opportunityId: opp.id }).catch(() => {}));
const stage = await advanceStage({ ctx, state, slots, email: slots.email || email });
return {