@igoruehara/canvas-flow 0.1.13 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/bin/canvas-flow.js +61 -3
- package/package.json +1 -1
- package/public/assets/index-BUVXJRGV.js +767 -0
- package/public/assets/{index-PCQkqMUe.css → index-D-m2588h.css} +1 -1
- package/public/index.html +2 -2
- package/server/provider-config/provider-config-controller.d.ts +35 -0
- package/server/provider-config/provider-config-controller.js +15 -0
- package/server/provider-config/provider-config-controller.js.map +1 -1
- package/server/provider-config/provider-config-service.d.ts +54 -0
- package/server/provider-config/provider-config-service.js +251 -11
- package/server/provider-config/provider-config-service.js.map +1 -1
- package/server/queue/sqs-transition-service.js +6 -0
- package/server/queue/sqs-transition-service.js.map +1 -1
- package/server/rag/rag-service.d.ts +4 -2
- package/server/rag/rag-service.js +44 -25
- package/server/rag/rag-service.js.map +1 -1
- package/server/runner/runner-controller.d.ts +8 -0
- package/server/runner/runner-service.d.ts +20 -0
- package/server/runner/runner-service.js +295 -13
- package/server/runner/runner-service.js.map +1 -1
- package/templates/config.example.json +11 -0
- package/templates/config.production.example.json +11 -0
- package/public/assets/index-CAYKh0bn.js +0 -767
|
@@ -1006,11 +1006,15 @@ export declare class RunnerController {
|
|
|
1006
1006
|
} | {
|
|
1007
1007
|
ok: boolean;
|
|
1008
1008
|
received: number;
|
|
1009
|
+
synced: number;
|
|
1010
|
+
syncResults: any[];
|
|
1009
1011
|
ignored: boolean;
|
|
1010
1012
|
results?: undefined;
|
|
1011
1013
|
} | {
|
|
1012
1014
|
ok: boolean;
|
|
1013
1015
|
received: any;
|
|
1016
|
+
synced: number;
|
|
1017
|
+
syncResults: any[];
|
|
1014
1018
|
results: any[];
|
|
1015
1019
|
ignored?: undefined;
|
|
1016
1020
|
}>;
|
|
@@ -1033,11 +1037,15 @@ export declare class RunnerController {
|
|
|
1033
1037
|
} | {
|
|
1034
1038
|
ok: boolean;
|
|
1035
1039
|
received: number;
|
|
1040
|
+
synced: number;
|
|
1041
|
+
syncResults: any[];
|
|
1036
1042
|
ignored: boolean;
|
|
1037
1043
|
results?: undefined;
|
|
1038
1044
|
} | {
|
|
1039
1045
|
ok: boolean;
|
|
1040
1046
|
received: any;
|
|
1047
|
+
synced: number;
|
|
1048
|
+
syncResults: any[];
|
|
1041
1049
|
results: any[];
|
|
1042
1050
|
ignored?: undefined;
|
|
1043
1051
|
}>;
|
|
@@ -132,6 +132,8 @@ export declare class RunnerService implements OnModuleInit, OnModuleDestroy {
|
|
|
132
132
|
private refreshOpenAIClient;
|
|
133
133
|
private getOpenAIClient;
|
|
134
134
|
private normalizeFlowLlmProvider;
|
|
135
|
+
private isRuntimeLlmProviderConfigured;
|
|
136
|
+
private resolveRuntimeLlmProvider;
|
|
135
137
|
private getOpenAIClientForProvider;
|
|
136
138
|
private getChatModelForProvider;
|
|
137
139
|
private flowLlmProvider;
|
|
@@ -1600,10 +1602,20 @@ export declare class RunnerService implements OnModuleInit, OnModuleDestroy {
|
|
|
1600
1602
|
private normalizeFlowAttachmentFiles;
|
|
1601
1603
|
private enrichFlowReplyDataWithAttachmentUrls;
|
|
1602
1604
|
private extractFlowReplyData;
|
|
1605
|
+
private extractMetaWhatsappMessageText;
|
|
1606
|
+
private normalizeWhatsappPhone;
|
|
1607
|
+
private inferWhatsappHistoryRole;
|
|
1603
1608
|
private extractMetaWhatsappMessages;
|
|
1604
1609
|
private extractBlipWhatsappMessages;
|
|
1605
1610
|
private extractSinchWhatsappMessages;
|
|
1606
1611
|
private extractWhatsappMessages;
|
|
1612
|
+
private pushMetaWhatsappSyncMessage;
|
|
1613
|
+
private getMetaWhatsappMessageArray;
|
|
1614
|
+
private extractMetaWhatsappHistoryEvents;
|
|
1615
|
+
private extractMetaWhatsappSyncEvents;
|
|
1616
|
+
private extractWhatsappSyncEvents;
|
|
1617
|
+
private buildWhatsappSyncDedupeKey;
|
|
1618
|
+
private persistWhatsappSyncEvents;
|
|
1607
1619
|
private getAssistantText;
|
|
1608
1620
|
private whatsappDeliveryKey;
|
|
1609
1621
|
private buildWhatsappDedupeKey;
|
|
@@ -1738,22 +1750,30 @@ export declare class RunnerService implements OnModuleInit, OnModuleDestroy {
|
|
|
1738
1750
|
runWhatsappWebhook(flowId: string, payload: any): Promise<{
|
|
1739
1751
|
ok: boolean;
|
|
1740
1752
|
received: number;
|
|
1753
|
+
synced: number;
|
|
1754
|
+
syncResults: any[];
|
|
1741
1755
|
ignored: boolean;
|
|
1742
1756
|
results?: undefined;
|
|
1743
1757
|
} | {
|
|
1744
1758
|
ok: boolean;
|
|
1745
1759
|
received: any;
|
|
1760
|
+
synced: number;
|
|
1761
|
+
syncResults: any[];
|
|
1746
1762
|
results: any[];
|
|
1747
1763
|
ignored?: undefined;
|
|
1748
1764
|
}>;
|
|
1749
1765
|
runWhatsappMainWebhook(agentId: string, payload: any): Promise<{
|
|
1750
1766
|
ok: boolean;
|
|
1751
1767
|
received: number;
|
|
1768
|
+
synced: number;
|
|
1769
|
+
syncResults: any[];
|
|
1752
1770
|
ignored: boolean;
|
|
1753
1771
|
results?: undefined;
|
|
1754
1772
|
} | {
|
|
1755
1773
|
ok: boolean;
|
|
1756
1774
|
received: any;
|
|
1775
|
+
synced: number;
|
|
1776
|
+
syncResults: any[];
|
|
1757
1777
|
results: any[];
|
|
1758
1778
|
ignored?: undefined;
|
|
1759
1779
|
}>;
|
|
@@ -173,12 +173,37 @@ let RunnerService = class RunnerService {
|
|
|
173
173
|
return 'bedrock';
|
|
174
174
|
return '';
|
|
175
175
|
}
|
|
176
|
+
isRuntimeLlmProviderConfigured(settings, provider) {
|
|
177
|
+
if (provider === 'openai')
|
|
178
|
+
return Boolean(String(settings.openai?.apiKey || '').trim());
|
|
179
|
+
if (provider === 'azure') {
|
|
180
|
+
return Boolean(String(settings.azureOpenai?.endpoint || '').trim() &&
|
|
181
|
+
String(settings.azureOpenai?.apiKey || '').trim());
|
|
182
|
+
}
|
|
183
|
+
if (provider === 'gemini')
|
|
184
|
+
return Boolean(String(settings.gemini?.apiKey || '').trim());
|
|
185
|
+
if (provider === 'claude')
|
|
186
|
+
return Boolean(String(settings.claude?.apiKey || '').trim());
|
|
187
|
+
if (provider === 'grok')
|
|
188
|
+
return Boolean(String(settings.grok?.apiKey || '').trim());
|
|
189
|
+
if (provider === 'bedrock') {
|
|
190
|
+
return Boolean(String(settings.bedrock?.apiKey || '').trim() &&
|
|
191
|
+
String(settings.bedrock?.baseUrl || '').trim());
|
|
192
|
+
}
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
resolveRuntimeLlmProvider(settings, provider) {
|
|
196
|
+
const requested = this.normalizeFlowLlmProvider(provider);
|
|
197
|
+
if (requested && this.isRuntimeLlmProviderConfigured(settings, requested))
|
|
198
|
+
return requested;
|
|
199
|
+
return this.normalizeFlowLlmProvider(settings?.llmProvider || '') || requested || undefined;
|
|
200
|
+
}
|
|
176
201
|
async getOpenAIClientForProvider(provider, agentId) {
|
|
177
202
|
const normalized = this.normalizeFlowLlmProvider(provider);
|
|
178
203
|
if (!normalized && !agentId)
|
|
179
204
|
return await this.getOpenAIClient();
|
|
180
205
|
const settings = await this.getProviderSettings(agentId);
|
|
181
|
-
const runtime = this.providerConfigService.toOpenAIRuntimeConfig(settings, normalized);
|
|
206
|
+
const runtime = this.providerConfigService.toOpenAIRuntimeConfig(settings, this.resolveRuntimeLlmProvider(settings, normalized));
|
|
182
207
|
return (0, openai_provider_1.createOpenAIClient)(this.configService, runtime);
|
|
183
208
|
}
|
|
184
209
|
async getChatModelForProvider(provider, model, agentId) {
|
|
@@ -186,7 +211,7 @@ let RunnerService = class RunnerService {
|
|
|
186
211
|
if (!normalized && !agentId)
|
|
187
212
|
return await this.getChatModel(model);
|
|
188
213
|
const settings = await this.getProviderSettings(agentId);
|
|
189
|
-
const runtime = this.providerConfigService.toOpenAIRuntimeConfig(settings, normalized);
|
|
214
|
+
const runtime = this.providerConfigService.toOpenAIRuntimeConfig(settings, this.resolveRuntimeLlmProvider(settings, normalized));
|
|
190
215
|
return (0, openai_provider_1.getOpenAIChatModel)(this.configService, model, runtime);
|
|
191
216
|
}
|
|
192
217
|
flowLlmProvider(config, fallback) {
|
|
@@ -10392,6 +10417,10 @@ let RunnerService = class RunnerService {
|
|
|
10392
10417
|
'businessAccountId',
|
|
10393
10418
|
'phoneNumberId',
|
|
10394
10419
|
'accessToken',
|
|
10420
|
+
'embeddedSignupAppId',
|
|
10421
|
+
'embeddedSignupConfigId',
|
|
10422
|
+
'embeddedSignupAppSecret',
|
|
10423
|
+
'embeddedSignupSolutionId',
|
|
10395
10424
|
'blipContractId',
|
|
10396
10425
|
'blipAuthorizationKey',
|
|
10397
10426
|
'sinchProjectId',
|
|
@@ -10407,6 +10436,10 @@ let RunnerService = class RunnerService {
|
|
|
10407
10436
|
return true;
|
|
10408
10437
|
if (String(whatsapp.deliveryMode || 'provider') === 'apiResponse')
|
|
10409
10438
|
return true;
|
|
10439
|
+
if (String(whatsapp.onboardingMode || 'manual') !== 'manual')
|
|
10440
|
+
return true;
|
|
10441
|
+
if (whatsapp.coexistenceEnabled === true || whatsapp.syncMessageEchoes === false || whatsapp.syncHistory === true)
|
|
10442
|
+
return true;
|
|
10410
10443
|
if (whatsapp.autoReply === false)
|
|
10411
10444
|
return true;
|
|
10412
10445
|
if (String(whatsapp.sinchApiMode || 'conversation') === 'relay' || String(whatsapp.sinchApiMode || '') === 'broker')
|
|
@@ -12073,23 +12106,50 @@ let RunnerService = class RunnerService {
|
|
|
12073
12106
|
const parsed = this.parsePossibleJsonValue(raw);
|
|
12074
12107
|
return this.isPlainObject(parsed) ? await this.enrichFlowReplyDataWithAttachmentUrls(parsed, config, flowId) : undefined;
|
|
12075
12108
|
}
|
|
12109
|
+
extractMetaWhatsappMessageText(message, flowReplyData) {
|
|
12110
|
+
return (message?.text?.body ||
|
|
12111
|
+
message?.button?.payload ||
|
|
12112
|
+
message?.button?.text ||
|
|
12113
|
+
message?.interactive?.button_reply?.id ||
|
|
12114
|
+
message?.interactive?.button_reply?.title ||
|
|
12115
|
+
message?.interactive?.list_reply?.id ||
|
|
12116
|
+
message?.interactive?.list_reply?.title ||
|
|
12117
|
+
(flowReplyData ? JSON.stringify(flowReplyData) : '') ||
|
|
12118
|
+
message?.interactive?.nfm_reply?.body ||
|
|
12119
|
+
message?.image?.caption ||
|
|
12120
|
+
message?.document?.caption ||
|
|
12121
|
+
message?.audio?.id ||
|
|
12122
|
+
message?.video?.caption ||
|
|
12123
|
+
message?.contacts?.[0]?.name?.formatted_name ||
|
|
12124
|
+
'');
|
|
12125
|
+
}
|
|
12126
|
+
normalizeWhatsappPhone(value) {
|
|
12127
|
+
return String(value || '').replace(/[^\d]/g, '');
|
|
12128
|
+
}
|
|
12129
|
+
inferWhatsappHistoryRole(message, customerPhone, businessPhone) {
|
|
12130
|
+
const from = this.normalizeWhatsappPhone(message?.from);
|
|
12131
|
+
const to = this.normalizeWhatsappPhone(message?.to || message?.recipient_id);
|
|
12132
|
+
const customer = this.normalizeWhatsappPhone(customerPhone);
|
|
12133
|
+
const business = this.normalizeWhatsappPhone(businessPhone);
|
|
12134
|
+
if (customer && from === customer)
|
|
12135
|
+
return 'user';
|
|
12136
|
+
if (customer && to === customer)
|
|
12137
|
+
return 'assistant';
|
|
12138
|
+
if (business && from === business)
|
|
12139
|
+
return 'assistant';
|
|
12140
|
+
return message?.from_me === true || message?.fromMe === true ? 'assistant' : 'user';
|
|
12141
|
+
}
|
|
12076
12142
|
async extractMetaWhatsappMessages(payload, config, flowId) {
|
|
12077
12143
|
const messages = [];
|
|
12078
12144
|
for (const entry of payload?.entry || []) {
|
|
12079
12145
|
for (const change of entry?.changes || []) {
|
|
12146
|
+
const field = String(change?.field || '');
|
|
12147
|
+
if (['smb_message_echoes', 'history', 'smb_app_state_sync'].includes(field))
|
|
12148
|
+
continue;
|
|
12080
12149
|
const value = change?.value || {};
|
|
12081
12150
|
for (const message of value?.messages || []) {
|
|
12082
12151
|
const flowReplyData = await this.extractFlowReplyData(message, config, flowId);
|
|
12083
|
-
const text = message
|
|
12084
|
-
message?.button?.payload ||
|
|
12085
|
-
message?.button?.text ||
|
|
12086
|
-
message?.interactive?.button_reply?.id ||
|
|
12087
|
-
message?.interactive?.button_reply?.title ||
|
|
12088
|
-
message?.interactive?.list_reply?.id ||
|
|
12089
|
-
message?.interactive?.list_reply?.title ||
|
|
12090
|
-
(flowReplyData ? JSON.stringify(flowReplyData) : '') ||
|
|
12091
|
-
message?.interactive?.nfm_reply?.body ||
|
|
12092
|
-
'';
|
|
12152
|
+
const text = this.extractMetaWhatsappMessageText(message, flowReplyData);
|
|
12093
12153
|
if (!text)
|
|
12094
12154
|
continue;
|
|
12095
12155
|
messages.push({
|
|
@@ -12158,6 +12218,216 @@ let RunnerService = class RunnerService {
|
|
|
12158
12218
|
return this.extractSinchWhatsappMessages(payload);
|
|
12159
12219
|
return await this.extractMetaWhatsappMessages(payload, config, flowId);
|
|
12160
12220
|
}
|
|
12221
|
+
pushMetaWhatsappSyncMessage(events, params) {
|
|
12222
|
+
const message = params.message || {};
|
|
12223
|
+
const value = params.value || {};
|
|
12224
|
+
const metadata = value?.metadata || {};
|
|
12225
|
+
const text = this.extractMetaWhatsappMessageText(message);
|
|
12226
|
+
if (!text)
|
|
12227
|
+
return;
|
|
12228
|
+
const customerPhone = String(params.customerPhone ||
|
|
12229
|
+
message?.to ||
|
|
12230
|
+
message?.recipient_id ||
|
|
12231
|
+
message?.customer_phone_number ||
|
|
12232
|
+
message?.customerPhoneNumber ||
|
|
12233
|
+
message?.contacts?.[0]?.wa_id ||
|
|
12234
|
+
message?.from ||
|
|
12235
|
+
'').trim();
|
|
12236
|
+
const role = params.role || this.inferWhatsappHistoryRole(message, customerPhone, metadata?.display_phone_number);
|
|
12237
|
+
const from = role === 'assistant'
|
|
12238
|
+
? customerPhone || String(message?.to || message?.recipient_id || message?.from || '').trim()
|
|
12239
|
+
: String(message?.from || customerPhone || '').trim();
|
|
12240
|
+
if (!from)
|
|
12241
|
+
return;
|
|
12242
|
+
events.push({
|
|
12243
|
+
provider: 'meta',
|
|
12244
|
+
syncKind: params.kind,
|
|
12245
|
+
role,
|
|
12246
|
+
from,
|
|
12247
|
+
text,
|
|
12248
|
+
messageId: message?.id,
|
|
12249
|
+
timestamp: message?.timestamp,
|
|
12250
|
+
phoneNumberId: metadata?.phone_number_id,
|
|
12251
|
+
displayPhoneNumber: metadata?.display_phone_number,
|
|
12252
|
+
raw: message,
|
|
12253
|
+
});
|
|
12254
|
+
}
|
|
12255
|
+
getMetaWhatsappMessageArray(value) {
|
|
12256
|
+
if (Array.isArray(value?.messages))
|
|
12257
|
+
return value.messages;
|
|
12258
|
+
if (Array.isArray(value?.message_echoes))
|
|
12259
|
+
return value.message_echoes;
|
|
12260
|
+
if (Array.isArray(value?.smb_message_echoes))
|
|
12261
|
+
return value.smb_message_echoes;
|
|
12262
|
+
if (Array.isArray(value?.data?.messages))
|
|
12263
|
+
return value.data.messages;
|
|
12264
|
+
if (this.isPlainObject(value?.message))
|
|
12265
|
+
return [value.message];
|
|
12266
|
+
return [];
|
|
12267
|
+
}
|
|
12268
|
+
extractMetaWhatsappHistoryEvents(events, historySource, value) {
|
|
12269
|
+
const histories = Array.isArray(historySource) ? historySource : [historySource].filter(Boolean);
|
|
12270
|
+
histories.forEach((history) => {
|
|
12271
|
+
const threads = Array.isArray(history?.threads) ? history.threads : [];
|
|
12272
|
+
threads.forEach((thread) => {
|
|
12273
|
+
const customerPhone = String(thread?.id || thread?.wa_id || thread?.phone || '').trim();
|
|
12274
|
+
const messages = Array.isArray(thread?.messages) ? thread.messages : [];
|
|
12275
|
+
messages.forEach((message) => {
|
|
12276
|
+
this.pushMetaWhatsappSyncMessage(events, {
|
|
12277
|
+
message,
|
|
12278
|
+
kind: 'history',
|
|
12279
|
+
value,
|
|
12280
|
+
customerPhone,
|
|
12281
|
+
});
|
|
12282
|
+
});
|
|
12283
|
+
});
|
|
12284
|
+
});
|
|
12285
|
+
}
|
|
12286
|
+
extractMetaWhatsappSyncEvents(payload, config) {
|
|
12287
|
+
const whatsapp = config?.whatsapp || {};
|
|
12288
|
+
const syncEchoes = whatsapp.syncMessageEchoes !== false;
|
|
12289
|
+
const syncHistory = whatsapp.syncHistory === true;
|
|
12290
|
+
const events = [];
|
|
12291
|
+
if (syncEchoes && String(payload?.event || '') === 'smb_message_echoes') {
|
|
12292
|
+
const data = payload?.data || {};
|
|
12293
|
+
this.getMetaWhatsappMessageArray(data).forEach((message) => {
|
|
12294
|
+
this.pushMetaWhatsappSyncMessage(events, {
|
|
12295
|
+
message,
|
|
12296
|
+
kind: 'message_echo',
|
|
12297
|
+
value: data,
|
|
12298
|
+
role: 'assistant',
|
|
12299
|
+
});
|
|
12300
|
+
});
|
|
12301
|
+
}
|
|
12302
|
+
if (syncHistory && String(payload?.event || '') === 'history') {
|
|
12303
|
+
const data = payload?.data || {};
|
|
12304
|
+
this.extractMetaWhatsappHistoryEvents(events, data?.history || data, data);
|
|
12305
|
+
}
|
|
12306
|
+
for (const entry of payload?.entry || []) {
|
|
12307
|
+
for (const change of entry?.changes || []) {
|
|
12308
|
+
const field = String(change?.field || '');
|
|
12309
|
+
const value = change?.value || {};
|
|
12310
|
+
if (field === 'smb_message_echoes' && syncEchoes) {
|
|
12311
|
+
this.getMetaWhatsappMessageArray(value).forEach((message) => {
|
|
12312
|
+
this.pushMetaWhatsappSyncMessage(events, {
|
|
12313
|
+
message,
|
|
12314
|
+
kind: 'message_echo',
|
|
12315
|
+
value,
|
|
12316
|
+
role: 'assistant',
|
|
12317
|
+
});
|
|
12318
|
+
});
|
|
12319
|
+
}
|
|
12320
|
+
if (field === 'history' && syncHistory) {
|
|
12321
|
+
this.extractMetaWhatsappHistoryEvents(events, value?.history || value, value);
|
|
12322
|
+
}
|
|
12323
|
+
}
|
|
12324
|
+
}
|
|
12325
|
+
return events;
|
|
12326
|
+
}
|
|
12327
|
+
async extractWhatsappSyncEvents(payload, config) {
|
|
12328
|
+
const provider = this.normalizeWhatsappProvider(config);
|
|
12329
|
+
if (provider !== 'meta')
|
|
12330
|
+
return [];
|
|
12331
|
+
return this.extractMetaWhatsappSyncEvents(payload, config);
|
|
12332
|
+
}
|
|
12333
|
+
buildWhatsappSyncDedupeKey(flowRecord, event) {
|
|
12334
|
+
const providerMessageId = String(event?.messageId || '').trim();
|
|
12335
|
+
const fallback = providerMessageId || (0, crypto_1.createHash)('sha1')
|
|
12336
|
+
.update(JSON.stringify({
|
|
12337
|
+
kind: event?.syncKind,
|
|
12338
|
+
role: event?.role,
|
|
12339
|
+
from: event?.from,
|
|
12340
|
+
text: event?.text,
|
|
12341
|
+
timestamp: event?.timestamp,
|
|
12342
|
+
}))
|
|
12343
|
+
.digest('hex');
|
|
12344
|
+
return [
|
|
12345
|
+
flowRecord?.organizationId || 'global',
|
|
12346
|
+
flowRecord?.agentId || 'default-agent',
|
|
12347
|
+
flowRecord?._id || 'flow',
|
|
12348
|
+
event?.provider || 'whatsapp',
|
|
12349
|
+
event?.syncKind || 'sync',
|
|
12350
|
+
fallback,
|
|
12351
|
+
].join(':');
|
|
12352
|
+
}
|
|
12353
|
+
async persistWhatsappSyncEvents(flowRecord, flowId, events) {
|
|
12354
|
+
const results = [];
|
|
12355
|
+
for (const event of events) {
|
|
12356
|
+
const conversationId = `whatsapp-${event.from}`;
|
|
12357
|
+
const conversationOwnerId = `whatsapp:${event.from}`;
|
|
12358
|
+
const dedupeKey = this.buildWhatsappSyncDedupeKey(flowRecord, event);
|
|
12359
|
+
const dedupe = await this.sqsTransitionService.tryStartMessageDedupe({
|
|
12360
|
+
dedupeKey,
|
|
12361
|
+
organizationId: flowRecord?.organizationId,
|
|
12362
|
+
agentId: flowRecord?.agentId,
|
|
12363
|
+
flowId,
|
|
12364
|
+
conversationId,
|
|
12365
|
+
channel: 'whatsapp',
|
|
12366
|
+
provider: event.provider || 'meta',
|
|
12367
|
+
providerMessageId: event.messageId,
|
|
12368
|
+
});
|
|
12369
|
+
if (!dedupe.acquired) {
|
|
12370
|
+
results.push({
|
|
12371
|
+
from: event.from,
|
|
12372
|
+
messageId: event.messageId,
|
|
12373
|
+
syncKind: event.syncKind,
|
|
12374
|
+
duplicate: true,
|
|
12375
|
+
skipped: true,
|
|
12376
|
+
status: dedupe.status,
|
|
12377
|
+
});
|
|
12378
|
+
continue;
|
|
12379
|
+
}
|
|
12380
|
+
try {
|
|
12381
|
+
await this.memoryService.addTurn({
|
|
12382
|
+
agentId: flowRecord?.agentId,
|
|
12383
|
+
conversationId,
|
|
12384
|
+
role: event.role === 'assistant' ? 'assistant' : 'user',
|
|
12385
|
+
content: event.text,
|
|
12386
|
+
metadata: {
|
|
12387
|
+
kind: 'message',
|
|
12388
|
+
source: 'whatsapp_coexistence',
|
|
12389
|
+
syncKind: event.syncKind,
|
|
12390
|
+
organizationId: flowRecord?.organizationId,
|
|
12391
|
+
flowId,
|
|
12392
|
+
entryFlowId: flowId,
|
|
12393
|
+
activeFlowId: flowId,
|
|
12394
|
+
conversationOwnerId,
|
|
12395
|
+
whatsapp: {
|
|
12396
|
+
provider: event.provider || 'meta',
|
|
12397
|
+
from: event.from,
|
|
12398
|
+
messageId: event.messageId,
|
|
12399
|
+
phoneNumberId: event.phoneNumberId,
|
|
12400
|
+
displayPhoneNumber: event.displayPhoneNumber,
|
|
12401
|
+
timestamp: event.timestamp,
|
|
12402
|
+
syncKind: event.syncKind,
|
|
12403
|
+
},
|
|
12404
|
+
},
|
|
12405
|
+
});
|
|
12406
|
+
await this.sqsTransitionService.completeMessageDedupe(dedupeKey);
|
|
12407
|
+
results.push({
|
|
12408
|
+
from: event.from,
|
|
12409
|
+
messageId: event.messageId,
|
|
12410
|
+
syncKind: event.syncKind,
|
|
12411
|
+
role: event.role,
|
|
12412
|
+
synced: true,
|
|
12413
|
+
});
|
|
12414
|
+
}
|
|
12415
|
+
catch (error) {
|
|
12416
|
+
await this.sqsTransitionService.failMessageDedupe(dedupeKey, error);
|
|
12417
|
+
(0, observability_1.logEvent)('error', 'whatsapp.sync.failed', {
|
|
12418
|
+
flowId,
|
|
12419
|
+
agentId: flowRecord?.agentId,
|
|
12420
|
+
conversationId,
|
|
12421
|
+
provider: event.provider,
|
|
12422
|
+
providerMessageId: event.messageId,
|
|
12423
|
+
syncKind: event.syncKind,
|
|
12424
|
+
error: (0, observability_1.getErrorDetails)(error),
|
|
12425
|
+
});
|
|
12426
|
+
throw error;
|
|
12427
|
+
}
|
|
12428
|
+
}
|
|
12429
|
+
return results;
|
|
12430
|
+
}
|
|
12161
12431
|
getAssistantText(messages) {
|
|
12162
12432
|
return messages
|
|
12163
12433
|
.filter((message) => message.role === 'assistant' && message.text)
|
|
@@ -14043,8 +14313,18 @@ let RunnerService = class RunnerService {
|
|
|
14043
14313
|
const versionInfo = await this.canvasFlowService.resolveFlowVersionAsync(flowRecord, payload?.flowVersion || payload?.version || releaseFlowVersion);
|
|
14044
14314
|
const config = await this.resolveRuntimeFlowConfig(versionInfo.config, flowRecord?.agentId, flowRecord?.organizationId);
|
|
14045
14315
|
const messages = await this.extractWhatsappMessages(payload, config, String(flowRecord?._id || flowId));
|
|
14316
|
+
const syncEvents = await this.extractWhatsappSyncEvents(payload, config);
|
|
14317
|
+
const syncResults = syncEvents.length
|
|
14318
|
+
? await this.persistWhatsappSyncEvents(flowRecord, String(flowRecord?._id || flowId), syncEvents)
|
|
14319
|
+
: [];
|
|
14046
14320
|
if (!messages.length) {
|
|
14047
|
-
return {
|
|
14321
|
+
return {
|
|
14322
|
+
ok: true,
|
|
14323
|
+
received: 0,
|
|
14324
|
+
synced: syncResults.length,
|
|
14325
|
+
syncResults,
|
|
14326
|
+
ignored: syncResults.length === 0,
|
|
14327
|
+
};
|
|
14048
14328
|
}
|
|
14049
14329
|
const results = [];
|
|
14050
14330
|
for (const message of messages) {
|
|
@@ -14228,6 +14508,8 @@ let RunnerService = class RunnerService {
|
|
|
14228
14508
|
return {
|
|
14229
14509
|
ok: true,
|
|
14230
14510
|
received: messages.length,
|
|
14511
|
+
synced: syncResults.length,
|
|
14512
|
+
syncResults,
|
|
14231
14513
|
results,
|
|
14232
14514
|
};
|
|
14233
14515
|
}
|