@automagik/omni 2.260429.2 → 2.260429.4
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/db/drizzle/0032_genie_hosts.sql +32 -0
- package/db/drizzle/meta/_journal.json +7 -0
- package/dist/index.js +17 -2
- package/dist/server/index.js +509 -414
- package/package.json +10 -10
package/dist/server/index.js
CHANGED
|
@@ -224554,7 +224554,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
224554
224554
|
var require_package8 = __commonJS((exports, module) => {
|
|
224555
224555
|
module.exports = {
|
|
224556
224556
|
name: "@omni/api",
|
|
224557
|
-
version: "2.260429.
|
|
224557
|
+
version: "2.260429.4",
|
|
224558
224558
|
type: "module",
|
|
224559
224559
|
exports: {
|
|
224560
224560
|
".": {
|
|
@@ -229968,6 +229968,7 @@ __export(exports_schema, {
|
|
|
229968
229968
|
handoffLogs: () => handoffLogs,
|
|
229969
229969
|
globalSettingsRelations: () => globalSettingsRelations,
|
|
229970
229970
|
globalSettings: () => globalSettings,
|
|
229971
|
+
genieHosts: () => genieHosts,
|
|
229971
229972
|
followUpDisarmReasons: () => followUpDisarmReasons,
|
|
229972
229973
|
eventTypes: () => eventTypes,
|
|
229973
229974
|
eventPayloads: () => eventPayloads,
|
|
@@ -230023,7 +230024,7 @@ __export(exports_schema, {
|
|
|
230023
230024
|
accessRules: () => accessRules,
|
|
230024
230025
|
accessModes: () => accessModes
|
|
230025
230026
|
});
|
|
230026
|
-
var channelTypes, agentTypes, agentSystems, agentEntityTypes, debounceMode, splitDelayMode, replyFilterMode, agentSessionStrategies, ruleTypes, accessModes, settingValueTypes, apiKeyStatuses, apiKeyProfiles, eventTypes, contentTypes, chatTypes, messageSources, messageTypes, messageStatuses, deliveryStatuses, jobStatuses, providerSchemas, agentProviders, agents, agentRoutes, agentSessions, apiKeys, apiKeyAuditLogs, apiKeysRelations, apiKeyAuditLogsRelations, instances, persons, platformIdentities, conversations, chats, chatParticipants, omniGroups, messages2, omniEvents, handoffLogs, accessRules, globalSettings, settingChangeHistory, batchJobs, syncJobTypes, syncJobs, mediaContent, chatIdMappings, pluginStorage, agentProvidersRelations, agentsRelations, instancesRelations, syncJobsRelations, personsRelations, platformIdentitiesRelations, conversationsRelations, chatsRelations, chatParticipantsRelations, messagesRelations, omniEventsRelations, accessRulesRelations, globalSettingsRelations, settingChangeHistoryRelations, batchJobsRelations, mediaContentRelations, chatIdMappingsRelations, deadLetterStatuses, deadLetterEvents, payloadStorageConfig, payloadStages, eventPayloads, webhookSources, conditionOperators, actionTypes, automationDebounceModes, automations2, automationLogStatuses, automationLogs, consumerOffsets, automationsRelations, automationLogsRelations, triggerLogs, triggerLogsRelations, agentRoutesRelations, agentTaskStatuses, agentTasks, agentTasksRelations, turnStatuses, turnActions, turns, turnsRelations, followUpDisarmReasons, chatFollowUpState, chatFollowUpStateRelations, processedEvents;
|
|
230027
|
+
var channelTypes, agentTypes, agentSystems, agentEntityTypes, debounceMode, splitDelayMode, replyFilterMode, agentSessionStrategies, ruleTypes, accessModes, settingValueTypes, apiKeyStatuses, apiKeyProfiles, eventTypes, contentTypes, chatTypes, messageSources, messageTypes, messageStatuses, deliveryStatuses, jobStatuses, providerSchemas, agentProviders, agents, agentRoutes, agentSessions, apiKeys, apiKeyAuditLogs, apiKeysRelations, apiKeyAuditLogsRelations, instances, persons, platformIdentities, conversations, chats, chatParticipants, omniGroups, messages2, omniEvents, handoffLogs, accessRules, globalSettings, settingChangeHistory, batchJobs, syncJobTypes, syncJobs, mediaContent, chatIdMappings, pluginStorage, agentProvidersRelations, agentsRelations, instancesRelations, syncJobsRelations, personsRelations, platformIdentitiesRelations, conversationsRelations, chatsRelations, chatParticipantsRelations, messagesRelations, omniEventsRelations, accessRulesRelations, globalSettingsRelations, settingChangeHistoryRelations, batchJobsRelations, mediaContentRelations, chatIdMappingsRelations, deadLetterStatuses, deadLetterEvents, payloadStorageConfig, payloadStages, eventPayloads, webhookSources, conditionOperators, actionTypes, automationDebounceModes, automations2, automationLogStatuses, automationLogs, consumerOffsets, automationsRelations, automationLogsRelations, triggerLogs, triggerLogsRelations, agentRoutesRelations, agentTaskStatuses, agentTasks, agentTasksRelations, turnStatuses, turnActions, turns, turnsRelations, followUpDisarmReasons, chatFollowUpState, chatFollowUpStateRelations, processedEvents, genieHosts;
|
|
230027
230028
|
var init_schema2 = __esm(() => {
|
|
230028
230029
|
init_events();
|
|
230029
230030
|
init_drizzle_orm();
|
|
@@ -231327,6 +231328,20 @@ var init_schema2 = __esm(() => {
|
|
|
231327
231328
|
pk: primaryKey({ columns: [table3.eventId, table3.handler], name: "processed_events_pk" }),
|
|
231328
231329
|
processedAtIdx: index("processed_events_processed_at_idx").on(table3.processedAt)
|
|
231329
231330
|
}));
|
|
231331
|
+
genieHosts = pgTable("genie_hosts", {
|
|
231332
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
231333
|
+
pubkey: varchar("pubkey", { length: 64 }).notNull().unique(),
|
|
231334
|
+
hostname: varchar("hostname", { length: 255 }).notNull(),
|
|
231335
|
+
capabilities: jsonb("capabilities").notNull().default(sql`'{}'::jsonb`),
|
|
231336
|
+
scopes: text("scopes").array().notNull().default(sql`ARRAY['*']::text[]`),
|
|
231337
|
+
lastSeenAt: timestamp("last_seen_at"),
|
|
231338
|
+
revokedAt: timestamp("revoked_at"),
|
|
231339
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
231340
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow()
|
|
231341
|
+
}, (table3) => ({
|
|
231342
|
+
pubkeyUq: index("genie_hosts_pubkey_idx").on(table3.pubkey),
|
|
231343
|
+
activeIdx: index("genie_hosts_active_idx").on(table3.revokedAt)
|
|
231344
|
+
}));
|
|
231330
231345
|
});
|
|
231331
231346
|
|
|
231332
231347
|
// ../../node_modules/.bun/postgres@3.4.8/node_modules/postgres/src/query.js
|
|
@@ -280873,6 +280888,52 @@ var init_follow_up_sweeper = __esm(() => {
|
|
|
280873
280888
|
log84 = createLogger("follow-up-sweeper");
|
|
280874
280889
|
});
|
|
280875
280890
|
|
|
280891
|
+
// ../api/src/services/genie-hosts.ts
|
|
280892
|
+
class GenieHostsService {
|
|
280893
|
+
db;
|
|
280894
|
+
constructor(db2) {
|
|
280895
|
+
this.db = db2;
|
|
280896
|
+
}
|
|
280897
|
+
async register(input) {
|
|
280898
|
+
const existing = await this.findByPubkey(input.pubkey);
|
|
280899
|
+
if (existing) {
|
|
280900
|
+
log85.info("genie host handshake \u2014 idempotent reuse", { hostId: existing.id, hostname: existing.hostname });
|
|
280901
|
+
return existing;
|
|
280902
|
+
}
|
|
280903
|
+
const [created] = await this.db.insert(genieHosts).values({
|
|
280904
|
+
pubkey: input.pubkey,
|
|
280905
|
+
hostname: input.hostname,
|
|
280906
|
+
capabilities: input.capabilities ?? {}
|
|
280907
|
+
}).returning();
|
|
280908
|
+
if (!created) {
|
|
280909
|
+
throw new Error("failed to insert genie host");
|
|
280910
|
+
}
|
|
280911
|
+
log85.info("genie host registered", { hostId: created.id, hostname: created.hostname });
|
|
280912
|
+
return created;
|
|
280913
|
+
}
|
|
280914
|
+
async findByPubkey(pubkey) {
|
|
280915
|
+
const [row] = await this.db.select().from(genieHosts).where(eq(genieHosts.pubkey, pubkey)).limit(1);
|
|
280916
|
+
return row ?? null;
|
|
280917
|
+
}
|
|
280918
|
+
async findById(id) {
|
|
280919
|
+
const [row] = await this.db.select().from(genieHosts).where(eq(genieHosts.id, id)).limit(1);
|
|
280920
|
+
return row ?? null;
|
|
280921
|
+
}
|
|
280922
|
+
async listActive(limit2 = 100) {
|
|
280923
|
+
return this.db.select().from(genieHosts).where(isNull2(genieHosts.revokedAt)).orderBy(genieHosts.createdAt).limit(limit2);
|
|
280924
|
+
}
|
|
280925
|
+
async touchLastSeen(id) {
|
|
280926
|
+
await this.db.update(genieHosts).set({ lastSeenAt: new Date, updatedAt: new Date }).where(and2(eq(genieHosts.id, id), isNull2(genieHosts.revokedAt)));
|
|
280927
|
+
}
|
|
280928
|
+
}
|
|
280929
|
+
var log85;
|
|
280930
|
+
var init_genie_hosts = __esm(() => {
|
|
280931
|
+
init_src();
|
|
280932
|
+
init_src5();
|
|
280933
|
+
init_drizzle_orm();
|
|
280934
|
+
log85 = createLogger("genie-hosts");
|
|
280935
|
+
});
|
|
280936
|
+
|
|
280876
280937
|
// ../api/src/services/instances.ts
|
|
280877
280938
|
class InstanceService {
|
|
280878
280939
|
db;
|
|
@@ -281426,12 +281487,12 @@ class PayloadStoreService {
|
|
|
281426
281487
|
const { eventId, eventType, stage, payload } = options;
|
|
281427
281488
|
const config4 = await this.getConfig(eventType);
|
|
281428
281489
|
if (!shouldStoreStage(stage, config4)) {
|
|
281429
|
-
|
|
281490
|
+
log86.debug("Skipping payload storage", { eventId, eventType, stage, reason: "config-disabled" });
|
|
281430
281491
|
return null;
|
|
281431
281492
|
}
|
|
281432
281493
|
const insertData = preparePayloadInsert({ eventId, eventType, stage, payload });
|
|
281433
281494
|
const [result] = await this.db.insert(eventPayloads).values(insertData).returning();
|
|
281434
|
-
|
|
281495
|
+
log86.debug("Payload stored", {
|
|
281435
281496
|
eventId,
|
|
281436
281497
|
stage,
|
|
281437
281498
|
originalSize: result?.payloadSizeOriginal,
|
|
@@ -281463,7 +281524,7 @@ class PayloadStoreService {
|
|
|
281463
281524
|
deleteReason: reason,
|
|
281464
281525
|
payloadCompressed: ""
|
|
281465
281526
|
}).where(and2(eq(eventPayloads.eventId, eventId), isNull2(eventPayloads.deletedAt))).returning({ id: eventPayloads.id });
|
|
281466
|
-
|
|
281527
|
+
log86.info("Payloads soft-deleted", { eventId, count: result.length, deletedBy, reason });
|
|
281467
281528
|
return result.length;
|
|
281468
281529
|
}
|
|
281469
281530
|
async listConfigs() {
|
|
@@ -281485,7 +281546,7 @@ class PayloadStoreService {
|
|
|
281485
281546
|
}
|
|
281486
281547
|
}).returning();
|
|
281487
281548
|
this.configCache.delete(eventType);
|
|
281488
|
-
|
|
281549
|
+
log86.info("Payload storage config updated", { eventType });
|
|
281489
281550
|
if (!result) {
|
|
281490
281551
|
throw new Error("Failed to create/update payload storage config");
|
|
281491
281552
|
}
|
|
@@ -281537,17 +281598,17 @@ class PayloadStoreService {
|
|
|
281537
281598
|
totalDeleted += deleted.length;
|
|
281538
281599
|
}
|
|
281539
281600
|
if (totalDeleted > 0) {
|
|
281540
|
-
|
|
281601
|
+
log86.info("Cleaned up expired payloads", { count: totalDeleted });
|
|
281541
281602
|
}
|
|
281542
281603
|
return totalDeleted;
|
|
281543
281604
|
}
|
|
281544
281605
|
}
|
|
281545
|
-
var
|
|
281606
|
+
var log86;
|
|
281546
281607
|
var init_payload_store2 = __esm(() => {
|
|
281547
281608
|
init_src();
|
|
281548
281609
|
init_src5();
|
|
281549
281610
|
init_drizzle_orm();
|
|
281550
|
-
|
|
281611
|
+
log86 = createLogger("payload-store");
|
|
281551
281612
|
});
|
|
281552
281613
|
|
|
281553
281614
|
// ../api/src/services/persons.ts
|
|
@@ -281943,23 +282004,23 @@ var init_persons = __esm(() => {
|
|
|
281943
282004
|
// ../api/src/lib/idempotency.ts
|
|
281944
282005
|
async function withIdempotency(db2, eventId, handler, fn) {
|
|
281945
282006
|
if (!eventId) {
|
|
281946
|
-
|
|
282007
|
+
log87.warn("idempotency: missing event id, running without dedupe", { handler });
|
|
281947
282008
|
await fn();
|
|
281948
282009
|
return { executed: true };
|
|
281949
282010
|
}
|
|
281950
282011
|
const claim = await db2.insert(processedEvents).values({ eventId, handler }).onConflictDoNothing().returning({ eventId: processedEvents.eventId });
|
|
281951
282012
|
if (claim.length === 0) {
|
|
281952
|
-
|
|
282013
|
+
log87.info("idempotency: skipping replay", { eventId, handler });
|
|
281953
282014
|
return { executed: false };
|
|
281954
282015
|
}
|
|
281955
282016
|
await fn();
|
|
281956
282017
|
return { executed: true };
|
|
281957
282018
|
}
|
|
281958
|
-
var
|
|
282019
|
+
var log87;
|
|
281959
282020
|
var init_idempotency = __esm(() => {
|
|
281960
282021
|
init_src();
|
|
281961
282022
|
init_src5();
|
|
281962
|
-
|
|
282023
|
+
log87 = createLogger("idempotency");
|
|
281963
282024
|
});
|
|
281964
282025
|
|
|
281965
282026
|
// ../api/src/services/message-context.ts
|
|
@@ -281993,9 +282054,9 @@ async function initTurnEvents(natsUrl) {
|
|
|
281993
282054
|
maxReconnectAttempts: -1,
|
|
281994
282055
|
reconnectTimeWait: 2000
|
|
281995
282056
|
});
|
|
281996
|
-
|
|
282057
|
+
log88.info("Turn events NATS connected", { url: natsUrl });
|
|
281997
282058
|
} catch (error2) {
|
|
281998
|
-
|
|
282059
|
+
log88.warn("Failed to connect NATS for turn events", { error: String(error2) });
|
|
281999
282060
|
}
|
|
282000
282061
|
}
|
|
282001
282062
|
async function closeTurnEvents() {
|
|
@@ -282006,7 +282067,7 @@ async function closeTurnEvents() {
|
|
|
282006
282067
|
}
|
|
282007
282068
|
function publish(topic, payload) {
|
|
282008
282069
|
if (!nc || nc.isClosed()) {
|
|
282009
|
-
|
|
282070
|
+
log88.warn("Cannot publish turn event: NATS not connected", { topic });
|
|
282010
282071
|
return;
|
|
282011
282072
|
}
|
|
282012
282073
|
nc.publish(topic, sc2.encode(JSON.stringify(payload)));
|
|
@@ -282014,33 +282075,33 @@ function publish(topic, payload) {
|
|
|
282014
282075
|
function publishTurnOpen(instanceId, chatId, event) {
|
|
282015
282076
|
const topic = `omni.turn.open.${instanceId}.${chatId}`;
|
|
282016
282077
|
publish(topic, event);
|
|
282017
|
-
|
|
282078
|
+
log88.debug("Published turn.open", { turnId: event.turnId, instanceId, chatId });
|
|
282018
282079
|
}
|
|
282019
282080
|
function publishTurnDone(instanceId, chatId, event) {
|
|
282020
282081
|
const topic = `omni.turn.done.${instanceId}.${chatId}`;
|
|
282021
282082
|
publish(topic, event);
|
|
282022
|
-
|
|
282083
|
+
log88.debug("Published turn.done", { turnId: event.turnId, action: event.action, instanceId });
|
|
282023
282084
|
}
|
|
282024
282085
|
function publishTurnNudge(instanceId, chatId, event) {
|
|
282025
282086
|
const topic = `omni.turn.nudge.${instanceId}.${chatId}`;
|
|
282026
282087
|
publish(topic, event);
|
|
282027
|
-
|
|
282088
|
+
log88.debug("Published turn.nudge", { turnId: event.turnId, nudgeCount: event.nudgeCount, instanceId });
|
|
282028
282089
|
}
|
|
282029
282090
|
function publishTurnStalled(instanceId, chatId, event) {
|
|
282030
282091
|
const topic = `omni.turn.stalled.${instanceId}.${chatId}`;
|
|
282031
282092
|
publish(topic, event);
|
|
282032
|
-
|
|
282093
|
+
log88.debug("Published turn.stalled", { turnId: event.turnId, instanceId, chatId });
|
|
282033
282094
|
}
|
|
282034
282095
|
function publishTurnTimeout(instanceId, chatId, event) {
|
|
282035
282096
|
const topic = `omni.turn.timeout.${instanceId}.${chatId}`;
|
|
282036
282097
|
publish(topic, event);
|
|
282037
|
-
|
|
282098
|
+
log88.debug("Published turn.timeout", { turnId: event.turnId, instanceId });
|
|
282038
282099
|
}
|
|
282039
|
-
var import_nats7,
|
|
282100
|
+
var import_nats7, log88, sc2, nc = null;
|
|
282040
282101
|
var init_turn_events = __esm(() => {
|
|
282041
282102
|
init_src();
|
|
282042
282103
|
import_nats7 = __toESM(require_mod4(), 1);
|
|
282043
|
-
|
|
282104
|
+
log88 = createLogger("turn-events");
|
|
282044
282105
|
sc2 = import_nats7.StringCodec();
|
|
282045
282106
|
});
|
|
282046
282107
|
|
|
@@ -282077,7 +282138,7 @@ class DatabasePluginStorage {
|
|
|
282077
282138
|
const result = await this.db.select().from(pluginStorage).where(and2(eq(pluginStorage.pluginId, this.pluginId), eq(pluginStorage.key, fullKey), or2(isNull2(pluginStorage.expiresAt), gt(pluginStorage.expiresAt, new Date)))).limit(1);
|
|
282078
282139
|
const elapsed = Date.now() - t0;
|
|
282079
282140
|
if (elapsed > 500) {
|
|
282080
|
-
|
|
282141
|
+
log89.warn("Slow storage.get", {
|
|
282081
282142
|
pluginId: this.pluginId,
|
|
282082
282143
|
key: fullKey.slice(-80),
|
|
282083
282144
|
elapsedMs: elapsed
|
|
@@ -282211,19 +282272,19 @@ function getPluginStorage(pluginId) {
|
|
|
282211
282272
|
if (globalDb) {
|
|
282212
282273
|
storage = new DatabasePluginStorage(globalDb, pluginId);
|
|
282213
282274
|
} else {
|
|
282214
|
-
|
|
282275
|
+
log89.warn("Database not available, using in-memory storage", { pluginId });
|
|
282215
282276
|
storage = new InMemoryPluginStorage(pluginId);
|
|
282216
282277
|
}
|
|
282217
282278
|
storageInstances.set(pluginId, storage);
|
|
282218
282279
|
}
|
|
282219
282280
|
return storage;
|
|
282220
282281
|
}
|
|
282221
|
-
var
|
|
282282
|
+
var log89, globalDb = null, storageInstances;
|
|
282222
282283
|
var init_storage = __esm(() => {
|
|
282223
282284
|
init_src();
|
|
282224
282285
|
init_src5();
|
|
282225
282286
|
init_drizzle_orm();
|
|
282226
|
-
|
|
282287
|
+
log89 = createLogger("api:storage");
|
|
282227
282288
|
storageInstances = new Map;
|
|
282228
282289
|
});
|
|
282229
282290
|
|
|
@@ -282231,7 +282292,7 @@ var init_storage = __esm(() => {
|
|
|
282231
282292
|
function createPluginDatabase(db2) {
|
|
282232
282293
|
return {
|
|
282233
282294
|
async execute(_sql, _params) {
|
|
282234
|
-
|
|
282295
|
+
log90.warn("PluginDatabase execute() is not implemented. Use getDrizzle() for queries.");
|
|
282235
282296
|
return [];
|
|
282236
282297
|
},
|
|
282237
282298
|
getDrizzle() {
|
|
@@ -282260,12 +282321,12 @@ function createPluginContext(options) {
|
|
|
282260
282321
|
db: createPluginDatabase(db2)
|
|
282261
282322
|
};
|
|
282262
282323
|
}
|
|
282263
|
-
var
|
|
282324
|
+
var log90;
|
|
282264
282325
|
var init_context3 = __esm(() => {
|
|
282265
282326
|
init_src();
|
|
282266
282327
|
init_logger5();
|
|
282267
282328
|
init_storage();
|
|
282268
|
-
|
|
282329
|
+
log90 = createLogger("api:plugin-context");
|
|
282269
282330
|
});
|
|
282270
282331
|
|
|
282271
282332
|
// ../api/src/plugins/loader.ts
|
|
@@ -282392,7 +282453,7 @@ class MessageDebouncer {
|
|
|
282392
282453
|
if (this.inFlight.has(chatKey))
|
|
282393
282454
|
return;
|
|
282394
282455
|
if (config4.restartOnTyping && this.buffers.has(chatKey)) {
|
|
282395
|
-
|
|
282456
|
+
log91.debug("Restarting debounce timer on user typing", { chatKey });
|
|
282396
282457
|
this.restartTimer(chatKey, config4, true);
|
|
282397
282458
|
}
|
|
282398
282459
|
}
|
|
@@ -282432,7 +282493,7 @@ class MessageDebouncer {
|
|
|
282432
282493
|
try {
|
|
282433
282494
|
await this.onFlush(chatKey, messages4);
|
|
282434
282495
|
} catch (error2) {
|
|
282435
|
-
|
|
282496
|
+
log91.error("Error flushing debounced messages", { chatKey, error: String(error2) });
|
|
282436
282497
|
} finally {
|
|
282437
282498
|
this.inFlight.delete(chatKey);
|
|
282438
282499
|
const pending = this.buffers.get(chatKey);
|
|
@@ -282449,10 +282510,10 @@ class MessageDebouncer {
|
|
|
282449
282510
|
this.inFlight.clear();
|
|
282450
282511
|
}
|
|
282451
282512
|
}
|
|
282452
|
-
var
|
|
282513
|
+
var log91;
|
|
282453
282514
|
var init_message_debouncer = __esm(() => {
|
|
282454
282515
|
init_src();
|
|
282455
|
-
|
|
282516
|
+
log91 = createLogger("message-debouncer");
|
|
282456
282517
|
});
|
|
282457
282518
|
|
|
282458
282519
|
// ../api/src/plugins/message-persistence.ts
|
|
@@ -282560,7 +282621,7 @@ async function processSenderIdentity(services, payload, metadata, channel4) {
|
|
|
282560
282621
|
matchByChannel: channel4
|
|
282561
282622
|
});
|
|
282562
282623
|
if (isNew) {
|
|
282563
|
-
|
|
282624
|
+
log92.debug("Auto-created identity for sender", {
|
|
282564
282625
|
platformUserId: payload.from,
|
|
282565
282626
|
identityId: identity.id,
|
|
282566
282627
|
personId: person2?.id
|
|
@@ -282578,14 +282639,14 @@ async function fetchAndUpdateProfile(services, channel4, instanceId, userId, ide
|
|
|
282578
282639
|
const profile = await fetchProfile.call(plugin7, instanceId, userId);
|
|
282579
282640
|
if (profile.avatarUrl || profile.bio || profile.platformData) {
|
|
282580
282641
|
await services.persons.updateIdentityProfile(identityId, profile);
|
|
282581
|
-
|
|
282642
|
+
log92.debug("Updated identity with profile data", {
|
|
282582
282643
|
identityId,
|
|
282583
282644
|
hasAvatar: !!profile.avatarUrl,
|
|
282584
282645
|
hasBio: !!profile.bio
|
|
282585
282646
|
});
|
|
282586
282647
|
}
|
|
282587
282648
|
} catch (error2) {
|
|
282588
|
-
|
|
282649
|
+
log92.warn("Failed to fetch profile for new identity", { identityId, error: String(error2) });
|
|
282589
282650
|
}
|
|
282590
282651
|
}
|
|
282591
282652
|
function shouldUpdateChatName(current, incoming) {
|
|
@@ -282599,7 +282660,7 @@ async function persistLidMappings(services, chat2, chatExternalId, instanceId, r
|
|
|
282599
282660
|
const originalLidJid = rawPayload?.originalLidJid;
|
|
282600
282661
|
if (originalLidJid && chatExternalId.endsWith("@s.whatsapp.net")) {
|
|
282601
282662
|
services.chats.upsertLidMapping(instanceId, originalLidJid, chatExternalId).catch((err) => {
|
|
282602
|
-
|
|
282663
|
+
log92.debug("Failed to persist LID mapping (non-critical)", { error: String(err) });
|
|
282603
282664
|
});
|
|
282604
282665
|
if (!chat2.canonicalId) {
|
|
282605
282666
|
await services.chats.update(chat2.id, { canonicalId: chatExternalId });
|
|
@@ -282609,14 +282670,14 @@ async function persistLidMappings(services, chat2, chatExternalId, instanceId, r
|
|
|
282609
282670
|
const resolvedPhoneJid = rawPayload?.resolvedPhoneJid;
|
|
282610
282671
|
if (chatExternalId.endsWith("@lid") && resolvedPhoneJid) {
|
|
282611
282672
|
services.chats.upsertLidMapping(instanceId, chatExternalId, resolvedPhoneJid).catch((err) => {
|
|
282612
|
-
|
|
282673
|
+
log92.debug("Failed to persist LID\u2194phone mapping for LID-canonical chat (non-critical)", { error: String(err) });
|
|
282613
282674
|
});
|
|
282614
282675
|
if (!chat2.canonicalId) {
|
|
282615
282676
|
try {
|
|
282616
282677
|
await services.chats.update(chat2.id, { canonicalId: resolvedPhoneJid });
|
|
282617
282678
|
chat2.canonicalId = resolvedPhoneJid;
|
|
282618
282679
|
} catch (err) {
|
|
282619
|
-
|
|
282680
|
+
log92.debug("canonicalId backfill skipped \u2014 already claimed by another chat", {
|
|
282620
282681
|
chatId: chat2.id,
|
|
282621
282682
|
resolvedPhoneJid,
|
|
282622
282683
|
error: String(err)
|
|
@@ -282680,10 +282741,10 @@ function maybeUpdateRecency(services, instanceId, chatId, rawPayload, payload, p
|
|
|
282680
282741
|
const preview = sanitizeText(buildChatPreview(payload, rawPayload)) ?? "";
|
|
282681
282742
|
const isFromMe2 = rawPayload?.isFromMe === true;
|
|
282682
282743
|
services.chats.updateLastMessage(chatId, preview, platformTimestamp, isFromMe2).catch((error2) => {
|
|
282683
|
-
|
|
282744
|
+
log92.debug("Failed to update chat lastMessage (non-critical)", { error: String(error2) });
|
|
282684
282745
|
});
|
|
282685
282746
|
services.instances.updateLastMessageAt(instanceId, platformTimestamp).catch((error2) => {
|
|
282686
|
-
|
|
282747
|
+
log92.debug("Failed to update instance lastMessageAt (non-critical)", { error: String(error2) });
|
|
282687
282748
|
});
|
|
282688
282749
|
}
|
|
282689
282750
|
async function resolveOrCreateChat(services, instanceId, chatExternalId, chatType, channel4, effectiveName, canonicalId, rawPayload) {
|
|
@@ -282692,7 +282753,7 @@ async function resolveOrCreateChat(services, instanceId, chatExternalId, chatTyp
|
|
|
282692
282753
|
return services.chats.findByExternalIdSmart(instanceId, resolvedPhoneJid).then((phoneChat) => {
|
|
282693
282754
|
if (phoneChat) {
|
|
282694
282755
|
services.chats.upsertLidMapping(instanceId, chatExternalId, resolvedPhoneJid).catch((err) => {
|
|
282695
|
-
|
|
282756
|
+
log92.debug("Failed to persist LID mapping during chat pre-check (non-critical)", { error: String(err) });
|
|
282696
282757
|
});
|
|
282697
282758
|
return { chat: phoneChat, created: false };
|
|
282698
282759
|
}
|
|
@@ -282751,7 +282812,7 @@ async function handleMessageReceived(services, payload, metadata, eventTimestamp
|
|
|
282751
282812
|
});
|
|
282752
282813
|
await maybeRecordMessageEdit(services, created, rawPayload, message2.id, sanitizeText(payload.content.text) ?? undefined, platformTimestamp, payload.from);
|
|
282753
282814
|
if (created) {
|
|
282754
|
-
|
|
282815
|
+
log92.debug("Created message", { externalId: payload.externalId, chatId: chat2.id });
|
|
282755
282816
|
}
|
|
282756
282817
|
await maybeRecordParticipantActivity(services, chat2.id, payload.from);
|
|
282757
282818
|
maybeUpdateRecency(services, metadata.instanceId, chat2.id, rawPayload, payload, platformTimestamp);
|
|
@@ -282760,7 +282821,7 @@ function logMessageReceivedError(payload, error2) {
|
|
|
282760
282821
|
const rawPayload = payload.rawPayload;
|
|
282761
282822
|
const quotedMsg = rawPayload?.quotedMessage;
|
|
282762
282823
|
const longFields = findLongStrings(rawPayload, "raw.");
|
|
282763
|
-
|
|
282824
|
+
log92.error("Failed to persist message.received to unified model", {
|
|
282764
282825
|
externalId: payload.externalId,
|
|
282765
282826
|
error: String(error2),
|
|
282766
282827
|
fieldLengths: {
|
|
@@ -282782,7 +282843,7 @@ async function setupMessagePersistence(eventBus, services) {
|
|
|
282782
282843
|
const payload = event.payload;
|
|
282783
282844
|
const metadata = event.metadata;
|
|
282784
282845
|
if (!metadata.instanceId) {
|
|
282785
|
-
|
|
282846
|
+
log92.debug("Skipping message without instanceId", { externalId: payload.externalId });
|
|
282786
282847
|
return;
|
|
282787
282848
|
}
|
|
282788
282849
|
try {
|
|
@@ -282812,7 +282873,7 @@ async function setupMessagePersistence(eventBus, services) {
|
|
|
282812
282873
|
const metadata = event.metadata;
|
|
282813
282874
|
try {
|
|
282814
282875
|
if (!metadata.instanceId) {
|
|
282815
|
-
|
|
282876
|
+
log92.debug("Skipping sent message without instanceId", { externalId: payload.externalId });
|
|
282816
282877
|
return;
|
|
282817
282878
|
}
|
|
282818
282879
|
const chatExternalId = truncate3(payload.chatId, 255) ?? payload.chatId;
|
|
@@ -282835,18 +282896,18 @@ async function setupMessagePersistence(eventBus, services) {
|
|
|
282835
282896
|
replyToExternalId: truncate3(payload.replyToId, 255)
|
|
282836
282897
|
});
|
|
282837
282898
|
if (created) {
|
|
282838
|
-
|
|
282899
|
+
log92.debug("Created sent message", {
|
|
282839
282900
|
messageId: message2.id,
|
|
282840
282901
|
externalId: payload.externalId,
|
|
282841
282902
|
chatId: chat2.id
|
|
282842
282903
|
});
|
|
282843
282904
|
}
|
|
282844
|
-
services.chats.updateLastMessage(chat2.id, sanitizeText(payload.content.text ?? "") ?? "", new Date(event.timestamp), true).catch((err) =>
|
|
282905
|
+
services.chats.updateLastMessage(chat2.id, sanitizeText(payload.content.text ?? "") ?? "", new Date(event.timestamp), true).catch((err) => log92.debug("Failed to update chat recency (sent)", { error: String(err) }));
|
|
282845
282906
|
if (metadata.streamSequence) {
|
|
282846
282907
|
await services.consumerOffsets.updateOffset("message-persistence-sent", "MESSAGE", metadata.streamSequence, event.id);
|
|
282847
282908
|
}
|
|
282848
282909
|
} catch (error2) {
|
|
282849
|
-
|
|
282910
|
+
log92.error("Failed to persist message.sent to unified model", {
|
|
282850
282911
|
externalId: payload.externalId,
|
|
282851
282912
|
error: String(error2)
|
|
282852
282913
|
});
|
|
@@ -282870,18 +282931,18 @@ async function setupMessagePersistence(eventBus, services) {
|
|
|
282870
282931
|
return;
|
|
282871
282932
|
const chat2 = await services.chats.findByExternalIdSmart(metadata.instanceId, payload.chatId);
|
|
282872
282933
|
if (!chat2) {
|
|
282873
|
-
|
|
282934
|
+
log92.debug("Chat not found for message.delivered", { chatId: payload.chatId });
|
|
282874
282935
|
return;
|
|
282875
282936
|
}
|
|
282876
282937
|
const message2 = await services.messages.getByExternalId(chat2.id, payload.externalId);
|
|
282877
282938
|
if (!message2) {
|
|
282878
|
-
|
|
282939
|
+
log92.debug("Message not found for message.delivered", { externalId: payload.externalId });
|
|
282879
282940
|
return;
|
|
282880
282941
|
}
|
|
282881
282942
|
await services.messages.updateDeliveryStatus(message2.id, "delivered");
|
|
282882
|
-
|
|
282943
|
+
log92.debug("Updated message delivery status", { messageId: message2.id, status: "delivered" });
|
|
282883
282944
|
} catch (error2) {
|
|
282884
|
-
|
|
282945
|
+
log92.error("Failed to update delivery status", {
|
|
282885
282946
|
externalId: payload.externalId,
|
|
282886
282947
|
error: String(error2)
|
|
282887
282948
|
});
|
|
@@ -282904,18 +282965,18 @@ async function setupMessagePersistence(eventBus, services) {
|
|
|
282904
282965
|
return;
|
|
282905
282966
|
const chat2 = await services.chats.findByExternalIdSmart(metadata.instanceId, payload.chatId);
|
|
282906
282967
|
if (!chat2) {
|
|
282907
|
-
|
|
282968
|
+
log92.debug("Chat not found for message.read", { chatId: payload.chatId });
|
|
282908
282969
|
return;
|
|
282909
282970
|
}
|
|
282910
282971
|
const message2 = await services.messages.getByExternalId(chat2.id, payload.externalId);
|
|
282911
282972
|
if (!message2) {
|
|
282912
|
-
|
|
282973
|
+
log92.debug("Message not found for message.read", { externalId: payload.externalId });
|
|
282913
282974
|
return;
|
|
282914
282975
|
}
|
|
282915
282976
|
await services.messages.updateDeliveryStatus(message2.id, "read");
|
|
282916
|
-
|
|
282977
|
+
log92.debug("Updated message delivery status", { messageId: message2.id, status: "read" });
|
|
282917
282978
|
} catch (error2) {
|
|
282918
|
-
|
|
282979
|
+
log92.error("Failed to update read status", {
|
|
282919
282980
|
externalId: payload.externalId,
|
|
282920
282981
|
error: String(error2)
|
|
282921
282982
|
});
|
|
@@ -282944,12 +283005,12 @@ async function setupMessagePersistence(eventBus, services) {
|
|
|
282944
283005
|
if (gapMs > gapThresholdMs) {
|
|
282945
283006
|
const channelType = event.metadata.channelType ?? "whatsapp-baileys";
|
|
282946
283007
|
if (channelType === "discord") {
|
|
282947
|
-
|
|
283008
|
+
log92.info("Instance reconnected with message gap (Discord \u2014 skipping auto-backfill, use manual sync)", {
|
|
282948
283009
|
instanceId,
|
|
282949
283010
|
gapMinutes
|
|
282950
283011
|
});
|
|
282951
283012
|
} else {
|
|
282952
|
-
|
|
283013
|
+
log92.warn("Instance reconnected with message gap", {
|
|
282953
283014
|
instanceId,
|
|
282954
283015
|
lastMessageAt: lastMessageAt.toISOString(),
|
|
282955
283016
|
gapMinutes
|
|
@@ -282963,7 +283024,7 @@ async function setupMessagePersistence(eventBus, services) {
|
|
|
282963
283024
|
until: new Date().toISOString()
|
|
282964
283025
|
}
|
|
282965
283026
|
});
|
|
282966
|
-
|
|
283027
|
+
log92.info("Post-reconnect backfill triggered", {
|
|
282967
283028
|
instanceId,
|
|
282968
283029
|
jobId: job.id,
|
|
282969
283030
|
since: lastMessageAt.toISOString(),
|
|
@@ -282971,10 +283032,10 @@ async function setupMessagePersistence(eventBus, services) {
|
|
|
282971
283032
|
});
|
|
282972
283033
|
}
|
|
282973
283034
|
} else {
|
|
282974
|
-
|
|
283035
|
+
log92.debug("Instance reconnected, gap within threshold", { instanceId, gapMinutes });
|
|
282975
283036
|
}
|
|
282976
283037
|
} catch (error2) {
|
|
282977
|
-
|
|
283038
|
+
log92.warn("Post-reconnect gap check failed (non-critical)", {
|
|
282978
283039
|
instanceId,
|
|
282979
283040
|
error: String(error2)
|
|
282980
283041
|
});
|
|
@@ -282987,12 +283048,12 @@ async function setupMessagePersistence(eventBus, services) {
|
|
|
282987
283048
|
startFrom: "first",
|
|
282988
283049
|
concurrency: 5
|
|
282989
283050
|
});
|
|
282990
|
-
|
|
283051
|
+
log92.info("Message persistence initialized - populating unified chats/messages");
|
|
282991
283052
|
detectStartupGaps(services).catch((error2) => {
|
|
282992
|
-
|
|
283053
|
+
log92.warn("Startup gap detection failed (non-critical)", { error: String(error2) });
|
|
282993
283054
|
});
|
|
282994
283055
|
} catch (error2) {
|
|
282995
|
-
|
|
283056
|
+
log92.error("Failed to set up message persistence", { error: String(error2) });
|
|
282996
283057
|
throw error2;
|
|
282997
283058
|
}
|
|
282998
283059
|
}
|
|
@@ -283006,17 +283067,17 @@ async function detectStartupGaps(services) {
|
|
|
283006
283067
|
for (const consumerName of consumers) {
|
|
283007
283068
|
const offset = await services.consumerOffsets.getOffset(consumerName);
|
|
283008
283069
|
if (offset > 0) {
|
|
283009
|
-
|
|
283070
|
+
log92.info("Consumer startup offset", { consumer: consumerName, lastSequence: offset });
|
|
283010
283071
|
}
|
|
283011
283072
|
}
|
|
283012
283073
|
}
|
|
283013
|
-
var
|
|
283074
|
+
var log92, CONTENT_TYPE_MAP, INTERNAL_JID_SUFFIXES, MEDIA_BADGES2;
|
|
283014
283075
|
var init_message_persistence = __esm(() => {
|
|
283015
283076
|
init_src();
|
|
283016
283077
|
init_esm5();
|
|
283017
283078
|
init_sentry_scrub();
|
|
283018
283079
|
init_loader2();
|
|
283019
|
-
|
|
283080
|
+
log92 = createLogger("message-persistence");
|
|
283020
283081
|
CONTENT_TYPE_MAP = {
|
|
283021
283082
|
audio: "audio",
|
|
283022
283083
|
image: "image",
|
|
@@ -283130,7 +283191,7 @@ class ReactionDedup {
|
|
|
283130
283191
|
}
|
|
283131
283192
|
const msgCount = this.messageCounters.get(messageId) ?? 0;
|
|
283132
283193
|
if (msgCount >= this.maxPerMessage) {
|
|
283133
|
-
|
|
283194
|
+
log93.debug("Reaction per-message limit reached", { messageId, count: msgCount });
|
|
283134
283195
|
return true;
|
|
283135
283196
|
}
|
|
283136
283197
|
this.seen.set(key, Date.now());
|
|
@@ -283238,7 +283299,7 @@ async function sendTypingPresence(channel4, instanceId, chatId, state) {
|
|
|
283238
283299
|
await plugin7.sendTyping(instanceId, chatId, duration);
|
|
283239
283300
|
}
|
|
283240
283301
|
} catch (error2) {
|
|
283241
|
-
|
|
283302
|
+
log93.debug("Failed to send typing presence", { error: String(error2) });
|
|
283242
283303
|
}
|
|
283243
283304
|
}
|
|
283244
283305
|
async function sendTextMessage5(channel4, instanceId, chatId, text3, messageFormatMode = "convert", replyTo, correlationId, senderAgentId) {
|
|
@@ -283257,7 +283318,7 @@ async function sendTextMessage5(channel4, instanceId, chatId, text3, messageForm
|
|
|
283257
283318
|
}
|
|
283258
283319
|
async function sendErrorFeedback(channel4, instanceId, chatId, error2) {
|
|
283259
283320
|
const errorMsg = error2 instanceof Error ? error2.message : String(error2);
|
|
283260
|
-
|
|
283321
|
+
log93.error("agent_dispatch_error", { channel: channel4, instanceId, chatId, error: errorMsg });
|
|
283261
283322
|
const text3 = "\u26A0\uFE0F Sorry, I ran into an issue processing your message. Please try again.";
|
|
283262
283323
|
await sendTextMessage5(channel4, instanceId, chatId, text3);
|
|
283263
283324
|
}
|
|
@@ -283283,7 +283344,7 @@ async function runWithTransientDispatchRetry(fn, context15, options = {}) {
|
|
|
283283
283344
|
const delays = options.delaysMs ?? TRANSIENT_DISPATCH_RETRY_DELAYS_MS;
|
|
283284
283345
|
const transient = options.isTransient ?? isTransientDispatchError;
|
|
283285
283346
|
const sleeper = options.sleeper ?? sleep5;
|
|
283286
|
-
const logger7 = options.logger ??
|
|
283347
|
+
const logger7 = options.logger ?? log93;
|
|
283287
283348
|
let lastError;
|
|
283288
283349
|
for (let attempt = 0;attempt <= delays.length; attempt++) {
|
|
283289
283350
|
try {
|
|
@@ -283353,7 +283414,7 @@ function resolveMediaPath(mediaUrl) {
|
|
|
283353
283414
|
const fullPath = resolve3(MEDIA_BASE_PATH3, relativePath);
|
|
283354
283415
|
const basePath = resolve3(MEDIA_BASE_PATH3);
|
|
283355
283416
|
if (!fullPath.startsWith(`${basePath}/`) && fullPath !== basePath) {
|
|
283356
|
-
|
|
283417
|
+
log93.warn("Path traversal attempt blocked", { mediaUrl, resolved: fullPath, basePath });
|
|
283357
283418
|
return null;
|
|
283358
283419
|
}
|
|
283359
283420
|
return fullPath;
|
|
@@ -283423,17 +283484,17 @@ async function awaitMediaProcessing(services, instanceId, chatId, externalId, co
|
|
|
283423
283484
|
return MEDIA_WAIT_NULL;
|
|
283424
283485
|
const chat2 = await waitForRecord(() => services.chats.findByExternalIdSmart(instanceId, chatId));
|
|
283425
283486
|
if (!chat2) {
|
|
283426
|
-
|
|
283487
|
+
log93.warn("Chat not found for media wait", { instanceId, chatId });
|
|
283427
283488
|
return MEDIA_WAIT_NULL;
|
|
283428
283489
|
}
|
|
283429
283490
|
const msg = await waitForRecord(() => services.messages.getByExternalId(chat2.id, externalId));
|
|
283430
283491
|
if (!msg) {
|
|
283431
|
-
|
|
283492
|
+
log93.warn("Message not found for media wait after retries", { instanceId, chatId, externalId });
|
|
283432
283493
|
return MEDIA_WAIT_NULL;
|
|
283433
283494
|
}
|
|
283434
283495
|
const existing = checkProcessedColumn(msg, column2);
|
|
283435
283496
|
if (existing === "error") {
|
|
283436
|
-
|
|
283497
|
+
log93.warn("Media processing failed (DB)", { instanceId, chatId, externalId });
|
|
283437
283498
|
return MEDIA_WAIT_NULL;
|
|
283438
283499
|
}
|
|
283439
283500
|
if (existing !== "pending")
|
|
@@ -283494,7 +283555,7 @@ async function resolveQuotedMessage(services, instanceId, chatId, replyToId) {
|
|
|
283494
283555
|
const timeStr = time3 ? ` at ${time3}` : "";
|
|
283495
283556
|
return `[Quoting ${sender}${timeStr}: ${truncated}]`;
|
|
283496
283557
|
} catch (error2) {
|
|
283497
|
-
|
|
283558
|
+
log93.debug("Failed to resolve quoted message", { replyToId, error: String(error2) });
|
|
283498
283559
|
return null;
|
|
283499
283560
|
}
|
|
283500
283561
|
}
|
|
@@ -283535,7 +283596,7 @@ async function collectProcessedMedia(services, instance4, messages4) {
|
|
|
283535
283596
|
try {
|
|
283536
283597
|
result = await awaitMediaProcessing(services, instance4.id, m2.payload.chatId, m2.payload.externalId, contentType);
|
|
283537
283598
|
} catch (error2) {
|
|
283538
|
-
|
|
283599
|
+
log93.warn("Media await failed", { externalId: m2.payload.externalId, error: String(error2) });
|
|
283539
283600
|
result = MEDIA_WAIT_NULL;
|
|
283540
283601
|
}
|
|
283541
283602
|
if (result.content) {
|
|
@@ -283573,11 +283634,11 @@ async function resolveContactName(services, instanceId, jid, cacheMap) {
|
|
|
283573
283634
|
try {
|
|
283574
283635
|
const chat2 = await services.chats.findByExternalIdSmart(instanceId, jid);
|
|
283575
283636
|
if (chat2?.name) {
|
|
283576
|
-
|
|
283637
|
+
log93.debug("Contact name from DB fallback", { jid, name: chat2.name });
|
|
283577
283638
|
return chat2.name;
|
|
283578
283639
|
}
|
|
283579
283640
|
} catch (error2) {
|
|
283580
|
-
|
|
283641
|
+
log93.warn("Failed to query DB for contact", { jid, error: String(error2) });
|
|
283581
283642
|
}
|
|
283582
283643
|
return null;
|
|
283583
283644
|
}
|
|
@@ -283609,14 +283670,14 @@ async function applyJidMentionReplacement(services, instanceId, jid, jidToName,
|
|
|
283609
283670
|
async function replaceMentionsWithContactNames(services, instanceId, text3, mentionedJids, mentionedContacts) {
|
|
283610
283671
|
if (!mentionedJids?.length)
|
|
283611
283672
|
return text3;
|
|
283612
|
-
|
|
283673
|
+
log93.debug("Starting mention replacement", { mentionCount: mentionedJids.length });
|
|
283613
283674
|
const jidToName = buildJidNameMap(mentionedContacts);
|
|
283614
283675
|
const stats = { resolved: 0, replaced: 0, unresolved: 0, skipped: 0 };
|
|
283615
283676
|
let replacedText = text3;
|
|
283616
283677
|
for (const jid of mentionedJids) {
|
|
283617
283678
|
replacedText = await applyJidMentionReplacement(services, instanceId, jid, jidToName, replacedText, stats);
|
|
283618
283679
|
}
|
|
283619
|
-
|
|
283680
|
+
log93.debug("Mention replacement complete", {
|
|
283620
283681
|
original: text3,
|
|
283621
283682
|
replaced: replacedText,
|
|
283622
283683
|
mentionCount: mentionedJids.length,
|
|
@@ -283685,7 +283746,7 @@ async function fetchSenderMetadata(services, channel4, instanceId, senderId) {
|
|
|
283685
283746
|
platformUsername: identity?.platformUsername ?? undefined
|
|
283686
283747
|
};
|
|
283687
283748
|
} catch (error2) {
|
|
283688
|
-
|
|
283749
|
+
log93.debug("Failed to fetch sender identity metadata", { error: String(error2) });
|
|
283689
283750
|
return {};
|
|
283690
283751
|
}
|
|
283691
283752
|
}
|
|
@@ -283699,7 +283760,7 @@ async function fetchChatMetadata(services, instanceId, chatId, chatType) {
|
|
|
283699
283760
|
participantCount: chat2?.participantCount ?? undefined
|
|
283700
283761
|
};
|
|
283701
283762
|
} catch (error2) {
|
|
283702
|
-
|
|
283763
|
+
log93.debug("Failed to fetch chat metadata", { error: String(error2) });
|
|
283703
283764
|
return {};
|
|
283704
283765
|
}
|
|
283705
283766
|
}
|
|
@@ -283721,7 +283782,7 @@ async function routeStreamDelta(sender, delta) {
|
|
|
283721
283782
|
}
|
|
283722
283783
|
async function resolveStreamingCapabilities(services, instance4, channel4, chatId, traceId, db2) {
|
|
283723
283784
|
if (!instance4.agentStreamMode) {
|
|
283724
|
-
|
|
283785
|
+
log93.debug("Stream guard: agentStreamMode is falsy", {
|
|
283725
283786
|
instanceId: instance4.id,
|
|
283726
283787
|
agentStreamMode: instance4.agentStreamMode,
|
|
283727
283788
|
chatId
|
|
@@ -283730,7 +283791,7 @@ async function resolveStreamingCapabilities(services, instance4, channel4, chatI
|
|
|
283730
283791
|
}
|
|
283731
283792
|
const provider = await getAgentProvider(services, instance4, db2);
|
|
283732
283793
|
if (!provider?.triggerStream) {
|
|
283733
|
-
|
|
283794
|
+
log93.debug("Stream guard: provider has no triggerStream", {
|
|
283734
283795
|
instanceId: instance4.id,
|
|
283735
283796
|
hasProvider: !!provider,
|
|
283736
283797
|
chatId
|
|
@@ -283739,7 +283800,7 @@ async function resolveStreamingCapabilities(services, instance4, channel4, chatI
|
|
|
283739
283800
|
}
|
|
283740
283801
|
const plugin7 = await getPlugin(channel4);
|
|
283741
283802
|
if (!plugin7?.capabilities?.canStreamResponse || !plugin7.createStreamSender) {
|
|
283742
|
-
|
|
283803
|
+
log93.debug("Stream guard: channel does not support streaming", {
|
|
283743
283804
|
channel: channel4,
|
|
283744
283805
|
canStream: plugin7?.capabilities?.canStreamResponse,
|
|
283745
283806
|
chatId
|
|
@@ -283748,7 +283809,7 @@ async function resolveStreamingCapabilities(services, instance4, channel4, chatI
|
|
|
283748
283809
|
}
|
|
283749
283810
|
const streamKey = `${instance4.id}:${chatId}`;
|
|
283750
283811
|
if (activeStreams.has(streamKey)) {
|
|
283751
|
-
|
|
283812
|
+
log93.info("Stream guard: parallel stream blocked, falling back to accumulate", {
|
|
283752
283813
|
instanceId: instance4.id,
|
|
283753
283814
|
chatId,
|
|
283754
283815
|
traceId
|
|
@@ -283771,7 +283832,7 @@ async function consumeStream(generator, sender, instanceId, chatId, traceId) {
|
|
|
283771
283832
|
hadContent = true;
|
|
283772
283833
|
await routeStreamDelta(sender, delta);
|
|
283773
283834
|
}
|
|
283774
|
-
|
|
283835
|
+
log93.info("Streaming response complete", {
|
|
283775
283836
|
instanceId,
|
|
283776
283837
|
chatId,
|
|
283777
283838
|
durationMs: Date.now() - startTime2,
|
|
@@ -283904,7 +283965,7 @@ async function dispatchViaStreamingProvider(services, instance4, messages4, trig
|
|
|
283904
283965
|
}
|
|
283905
283966
|
return streamResult;
|
|
283906
283967
|
} catch (err) {
|
|
283907
|
-
|
|
283968
|
+
log93.error("Streaming dispatch failed, falling back", {
|
|
283908
283969
|
instanceId: instance4.id,
|
|
283909
283970
|
chatId,
|
|
283910
283971
|
error: String(err),
|
|
@@ -283988,7 +284049,7 @@ async function buildContextMessages(services, instance4, chatId, currentMessageI
|
|
|
283988
284049
|
return `[${name}${time3 ? ` - ${time3}` : ""}] ${text3}`;
|
|
283989
284050
|
});
|
|
283990
284051
|
} catch (error2) {
|
|
283991
|
-
|
|
284052
|
+
log93.warn("Failed to build context messages", { error: error2, chatId, instanceId: instance4.id });
|
|
283992
284053
|
return [];
|
|
283993
284054
|
}
|
|
283994
284055
|
}
|
|
@@ -284025,13 +284086,13 @@ async function dispatchViaTurnBasedProvider(services, instance4, provider, trigg
|
|
|
284025
284086
|
agentRecord = row;
|
|
284026
284087
|
}
|
|
284027
284088
|
if (!agentRecord) {
|
|
284028
|
-
|
|
284089
|
+
log93.error("Turn-based dispatch: agent not found", { instanceId: instance4.id, agentId: instance4.agentId });
|
|
284029
284090
|
return false;
|
|
284030
284091
|
}
|
|
284031
284092
|
const keyName = `agent:${agentRecord.name}`;
|
|
284032
284093
|
const scopedKey = await services.apiKeys.findByName(keyName);
|
|
284033
284094
|
if (!scopedKey) {
|
|
284034
|
-
|
|
284095
|
+
log93.error("Turn-based dispatch: scoped API key not found", { keyName, instanceId: instance4.id });
|
|
284035
284096
|
return false;
|
|
284036
284097
|
}
|
|
284037
284098
|
const turn = await services.turns.open({
|
|
@@ -284072,7 +284133,7 @@ async function dispatchViaTurnBasedProvider(services, instance4, provider, trigg
|
|
|
284072
284133
|
attributes: { provider_type: provider.schema, mode: "turn-based" }
|
|
284073
284134
|
});
|
|
284074
284135
|
}
|
|
284075
|
-
|
|
284136
|
+
log93.info("Turn-based dispatch: turn opened", {
|
|
284076
284137
|
turnId: turn.id,
|
|
284077
284138
|
instanceId: instance4.id,
|
|
284078
284139
|
chatId,
|
|
@@ -284088,7 +284149,7 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
|
|
|
284088
284149
|
return false;
|
|
284089
284150
|
const { messageTexts, mediaFiles } = await prepareAgentContent(services, instance4, messages4);
|
|
284090
284151
|
if (!messageTexts.length && !mediaFiles.length) {
|
|
284091
|
-
|
|
284152
|
+
log93.debug("No text or media content for provider trigger, skipping");
|
|
284092
284153
|
return false;
|
|
284093
284154
|
}
|
|
284094
284155
|
if (!messageTexts.length && mediaFiles.length) {
|
|
@@ -284129,12 +284190,12 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
|
|
|
284129
284190
|
recordJourneyCheckpoint(correlationId, "T9", JOURNEY_STAGES.T9);
|
|
284130
284191
|
await forwardToChainedInstance(instance4, parts, correlationId, messages4);
|
|
284131
284192
|
} else if (handoffTriggered) {
|
|
284132
|
-
|
|
284193
|
+
log93.info("Agent response suppressed \u2014 handoff triggered during run", {
|
|
284133
284194
|
instanceId: instance4.id,
|
|
284134
284195
|
chatId
|
|
284135
284196
|
});
|
|
284136
284197
|
}
|
|
284137
|
-
|
|
284198
|
+
log93.info("Agent response via IAgentProvider", {
|
|
284138
284199
|
instanceId: instance4.id,
|
|
284139
284200
|
chatId,
|
|
284140
284201
|
parts: result?.parts.length ?? 0,
|
|
@@ -284148,14 +284209,14 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
|
|
|
284148
284209
|
async function dispatchViaLegacy(services, instance4, messages4, triggerType, channel4, chatId, senderId, personId, senderName, traceId, perThreadExtraContext, senderAgentId) {
|
|
284149
284210
|
const { messageTexts, mediaFiles } = await prepareAgentContent(services, instance4, messages4);
|
|
284150
284211
|
if (perThreadExtraContext?.length) {
|
|
284151
|
-
|
|
284212
|
+
log93.warn("per_thread context available but legacy dispatch path has limited support \u2014 prepending as text", {
|
|
284152
284213
|
instanceId: instance4.id,
|
|
284153
284214
|
contextCount: perThreadExtraContext.length
|
|
284154
284215
|
});
|
|
284155
284216
|
messageTexts.unshift(...perThreadExtraContext);
|
|
284156
284217
|
}
|
|
284157
284218
|
if (!messageTexts.length && !mediaFiles.length) {
|
|
284158
|
-
|
|
284219
|
+
log93.debug("No text or media content in messages, skipping agent call");
|
|
284159
284220
|
return;
|
|
284160
284221
|
}
|
|
284161
284222
|
if (!messageTexts.length && mediaFiles.length) {
|
|
@@ -284189,7 +284250,7 @@ async function dispatchViaLegacy(services, instance4, messages4, triggerType, ch
|
|
|
284189
284250
|
recordJourneyCheckpoint(correlationId, "T8", JOURNEY_STAGES.T8);
|
|
284190
284251
|
await sendResponseParts(channel4, instance4.id, chatId, parts, getSplitDelayConfig(instance4), _fmtMode, replyTo, correlationId, senderAgentId);
|
|
284191
284252
|
recordJourneyCheckpoint(correlationId, "T9", JOURNEY_STAGES.T9);
|
|
284192
|
-
|
|
284253
|
+
log93.info("Agent response via legacy runner", {
|
|
284193
284254
|
instanceId: instance4.id,
|
|
284194
284255
|
chatId,
|
|
284195
284256
|
parts: result.parts.length,
|
|
@@ -284209,14 +284270,14 @@ async function performSessionReset(instance4, sessionId, chatId, services, db2,
|
|
|
284209
284270
|
sessionActuallyReset = true;
|
|
284210
284271
|
}
|
|
284211
284272
|
} catch (err) {
|
|
284212
|
-
|
|
284273
|
+
log93.warn("Failed to reset provider session", { error: String(err), instanceId: instance4.id, sessionId });
|
|
284213
284274
|
}
|
|
284214
284275
|
if (sessionActuallyReset) {
|
|
284215
284276
|
sessionActivityStore.recordReset(instance4.id, sessionId, Date.now());
|
|
284216
284277
|
eventBus.publish("session.reset", { instanceId: instance4.id, sessionId, timestamp: Date.now() }, { instanceId: instance4.id, channelType: channel4 }).catch((err) => {
|
|
284217
|
-
|
|
284278
|
+
log93.warn("Failed to publish session.reset event", { error: String(err), instanceId: instance4.id, sessionId });
|
|
284218
284279
|
});
|
|
284219
|
-
|
|
284280
|
+
log93.info("Session reset triggered", {
|
|
284220
284281
|
instanceId: instance4.id,
|
|
284221
284282
|
sessionId,
|
|
284222
284283
|
strategy: resetStrategy,
|
|
@@ -284259,7 +284320,7 @@ async function markPerThreadSessionInitialized(db2, instanceId, sessionId) {
|
|
|
284259
284320
|
target: [agentSessions.instanceId, agentSessions.sessionKey],
|
|
284260
284321
|
set: { lastUsedAt: now, updatedAt: now }
|
|
284261
284322
|
});
|
|
284262
|
-
|
|
284323
|
+
log93.info("per_thread session initialized", { instanceId, sessionId });
|
|
284263
284324
|
}
|
|
284264
284325
|
function mimeToContentType(mimeType) {
|
|
284265
284326
|
if (mimeType.startsWith("audio/"))
|
|
@@ -284298,7 +284359,7 @@ async function processMediaFile(msg, mimeType, mediaService) {
|
|
|
284298
284359
|
const result = await mediaService.process(localPath, mimeType, { caption: msg.content.caption });
|
|
284299
284360
|
return result.success && result.content ? result.content : null;
|
|
284300
284361
|
} catch (err) {
|
|
284301
|
-
|
|
284362
|
+
log93.debug("Media processing failed for history message", { error: String(err), messageId: msg.externalId });
|
|
284302
284363
|
return null;
|
|
284303
284364
|
} finally {
|
|
284304
284365
|
if (ownedTempFile) {
|
|
@@ -284335,7 +284396,7 @@ async function processHistoryMessage2(msg, mediaService, reactFn, unreactFn) {
|
|
|
284335
284396
|
async function fetchAndProcessThreadHistory(services, instance4, channel4, chatId, threadId2) {
|
|
284336
284397
|
const plugin7 = await getPlugin(channel4);
|
|
284337
284398
|
if (!plugin7?.fetchHistory) {
|
|
284338
|
-
|
|
284399
|
+
log93.debug("Channel plugin does not support fetchHistory", { instanceId: instance4.id, channel: channel4 });
|
|
284339
284400
|
return [];
|
|
284340
284401
|
}
|
|
284341
284402
|
let historyResult;
|
|
@@ -284346,7 +284407,7 @@ async function fetchAndProcessThreadHistory(services, instance4, channel4, chatI
|
|
|
284346
284407
|
limit: 200
|
|
284347
284408
|
});
|
|
284348
284409
|
} catch (err) {
|
|
284349
|
-
|
|
284410
|
+
log93.warn("fetchHistory failed, proceeding without thread context", {
|
|
284350
284411
|
error: String(err),
|
|
284351
284412
|
instanceId: instance4.id,
|
|
284352
284413
|
channel: channel4
|
|
@@ -284376,7 +284437,7 @@ async function fetchAndProcessThreadHistory(services, instance4, channel4, chatI
|
|
|
284376
284437
|
const results = await Promise.all(batch.map((msg) => processHistoryMessage2(msg, mediaService, reactFn, unreactFn)));
|
|
284377
284438
|
contextMessages.push(...results);
|
|
284378
284439
|
}
|
|
284379
|
-
|
|
284440
|
+
log93.info("Thread history fetched", {
|
|
284380
284441
|
instanceId: instance4.id,
|
|
284381
284442
|
channel: channel4,
|
|
284382
284443
|
chatId,
|
|
@@ -284387,7 +284448,7 @@ async function fetchAndProcessThreadHistory(services, instance4, channel4, chatI
|
|
|
284387
284448
|
return contextMessages;
|
|
284388
284449
|
}
|
|
284389
284450
|
async function handlePerThreadLazyInit(services, instance4, channel4, chatId, threadId2, sessionId, db2) {
|
|
284390
|
-
|
|
284451
|
+
log93.info("per_thread lazy init", {
|
|
284391
284452
|
instanceId: instance4.id,
|
|
284392
284453
|
channel: channel4,
|
|
284393
284454
|
chatId,
|
|
@@ -284398,7 +284459,7 @@ async function handlePerThreadLazyInit(services, instance4, channel4, chatId, th
|
|
|
284398
284459
|
try {
|
|
284399
284460
|
await markPerThreadSessionInitialized(db2, instance4.id, sessionId);
|
|
284400
284461
|
} catch (err) {
|
|
284401
|
-
|
|
284462
|
+
log93.warn("Failed to mark per_thread session initialized", {
|
|
284402
284463
|
error: String(err),
|
|
284403
284464
|
instanceId: instance4.id,
|
|
284404
284465
|
sessionId
|
|
@@ -284440,7 +284501,7 @@ async function dispatchToAgent(services, instance4, msgs, triggerType, channel4,
|
|
|
284440
284501
|
handled = await dispatchViaProvider(services, instance4, msgs, triggerType, channel4, chatId, senderId, personId, senderName, traceId, rawEvent, db2, perThreadExtraContext, senderAgentId);
|
|
284441
284502
|
}
|
|
284442
284503
|
} catch (providerError) {
|
|
284443
|
-
|
|
284504
|
+
log93.error("Provider dispatch failed, falling back to legacy", {
|
|
284444
284505
|
instanceId: instance4.id,
|
|
284445
284506
|
chatId,
|
|
284446
284507
|
error: String(providerError),
|
|
@@ -284449,7 +284510,7 @@ async function dispatchToAgent(services, instance4, msgs, triggerType, channel4,
|
|
|
284449
284510
|
}
|
|
284450
284511
|
if (handled)
|
|
284451
284512
|
return;
|
|
284452
|
-
|
|
284513
|
+
log93.debug("No IAgentProvider resolved or provider failed, using legacy agentRunner path", {
|
|
284453
284514
|
instanceId: instance4.id
|
|
284454
284515
|
});
|
|
284455
284516
|
await dispatchViaLegacy(services, instance4, msgs, triggerType, channel4, chatId, senderId, personId, senderName, traceId, perThreadExtraContext, senderAgentId);
|
|
@@ -284468,7 +284529,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
284468
284529
|
const ackHandle = startAck(plugin7, ackProvider, instance4.id, chatId, messageId, channel4, buildAckConfig(instance4));
|
|
284469
284530
|
const personId = await resolvePersonId(services, channel4, instance4.id, senderId, firstMessage.metadata.personId);
|
|
284470
284531
|
if (!personId) {
|
|
284471
|
-
|
|
284532
|
+
log93.warn("Could not resolve person ID, skipping agent", { instanceId: instance4.id, chatId, senderId });
|
|
284472
284533
|
ackHandle.remove();
|
|
284473
284534
|
return;
|
|
284474
284535
|
}
|
|
@@ -284476,7 +284537,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
284476
284537
|
const chatSettings = chatRecord?.settings;
|
|
284477
284538
|
const isAgentPaused = chatSettings?.agentPaused === true;
|
|
284478
284539
|
if (isAgentPaused) {
|
|
284479
|
-
|
|
284540
|
+
log93.debug("Agent paused (handoff active), skipping dispatch", { instanceId: instance4.id, chatId });
|
|
284480
284541
|
ackHandle.remove();
|
|
284481
284542
|
return;
|
|
284482
284543
|
}
|
|
@@ -284484,7 +284545,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
284484
284545
|
const resumedAt = new Date(chatSettings.agentResumedAt).getTime();
|
|
284485
284546
|
const msgTimestamp = extractPlatformTimestamp(firstMessage.payload.rawPayload, Date.now()).getTime();
|
|
284486
284547
|
if (msgTimestamp < resumedAt) {
|
|
284487
|
-
|
|
284548
|
+
log93.debug("Dropping pre-resume message (arrived during handoff window)", {
|
|
284488
284549
|
instanceId: instance4.id,
|
|
284489
284550
|
chatId,
|
|
284490
284551
|
msgTimestamp: new Date(msgTimestamp).toISOString(),
|
|
@@ -284499,7 +284560,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
284499
284560
|
const pushName = rawPayload.pushName ?? rawPayload.displayName ?? rawPayload.senderobj?.display ?? rawPayload.contextobj?.senderName;
|
|
284500
284561
|
const senderName = await services.agentRunner.getSenderName(personId, pushName);
|
|
284501
284562
|
const senderAgentId = await resolveDispatchSenderAgentId(db2, instance4);
|
|
284502
|
-
|
|
284563
|
+
log93.info("Dispatching to agent", {
|
|
284503
284564
|
instanceId: instance4.id,
|
|
284504
284565
|
chatId,
|
|
284505
284566
|
messageCount: messages4.length,
|
|
@@ -284513,14 +284574,14 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
284513
284574
|
const agentAckMessage = inst.agentAckMessage ?? null;
|
|
284514
284575
|
if (agentAckMessage) {
|
|
284515
284576
|
sendTextMessage5(channel4, instance4.id, chatId, agentAckMessage).catch((err) => {
|
|
284516
|
-
|
|
284577
|
+
log93.warn("Failed to send agent ack message", { instanceId: instance4.id, chatId, error: String(err) });
|
|
284517
284578
|
});
|
|
284518
284579
|
}
|
|
284519
284580
|
const perThreadExtraContext = await resolvePerThreadExtraContext(db2, services, instance4, channel4, chatId, senderId, firstMessage);
|
|
284520
284581
|
try {
|
|
284521
284582
|
await runWithTransientDispatchRetry(() => dispatchToAgent(services, instance4, messages4, triggerType, channel4, chatId, senderId, personId, senderName, traceId, senderAgentId, perThreadExtraContext, db2), { instanceId: instance4.id, chatId, traceId });
|
|
284522
284583
|
} catch (error2) {
|
|
284523
|
-
|
|
284584
|
+
log93.error("agent_dispatch_failed_after_retries", {
|
|
284524
284585
|
instanceId: instance4.id,
|
|
284525
284586
|
chatId,
|
|
284526
284587
|
error: String(error2),
|
|
@@ -284573,7 +284634,7 @@ function createOpenClawProviderInstance(provider, instance4) {
|
|
|
284573
284634
|
}
|
|
284574
284635
|
function createAgnoProvider(provider, instance4) {
|
|
284575
284636
|
if (!provider.apiKey) {
|
|
284576
|
-
|
|
284637
|
+
log93.warn("Provider has no API key, falling back to legacy path", { providerId: provider.id });
|
|
284577
284638
|
return null;
|
|
284578
284639
|
}
|
|
284579
284640
|
const client = createProviderClient({
|
|
@@ -284595,7 +284656,7 @@ function createClaudeCodeProviderInstance(provider, instance4, db2) {
|
|
|
284595
284656
|
const schemaConfig = provider.schemaConfig ?? {};
|
|
284596
284657
|
const projectPath = schemaConfig.projectPath;
|
|
284597
284658
|
if (!projectPath) {
|
|
284598
|
-
|
|
284659
|
+
log93.error("Claude Code provider missing projectPath", { providerId: provider.id });
|
|
284599
284660
|
throw new Error("Claude Code provider requires schemaConfig.projectPath");
|
|
284600
284661
|
}
|
|
284601
284662
|
return new ClaudeCodeAgentProvider(provider.id, provider.name, {
|
|
@@ -284626,7 +284687,7 @@ function createWebhookProvider(provider) {
|
|
|
284626
284687
|
}
|
|
284627
284688
|
function createAgUiProviderInstance(provider, instance4) {
|
|
284628
284689
|
if (!provider.apiKey) {
|
|
284629
|
-
|
|
284690
|
+
log93.warn("AG-UI provider has no API key, falling back to legacy path", { providerId: provider.id });
|
|
284630
284691
|
return null;
|
|
284631
284692
|
}
|
|
284632
284693
|
const schemaConfig = provider.schemaConfig ?? {};
|
|
@@ -284645,7 +284706,7 @@ function createAgUiProviderInstance(provider, instance4) {
|
|
|
284645
284706
|
}
|
|
284646
284707
|
function createA2AProviderInstance(provider, instance4) {
|
|
284647
284708
|
if (!provider.apiKey) {
|
|
284648
|
-
|
|
284709
|
+
log93.warn("A2A provider has no API key, falling back to legacy path", { providerId: provider.id });
|
|
284649
284710
|
return null;
|
|
284650
284711
|
}
|
|
284651
284712
|
const schemaConfig = provider.schemaConfig ?? {};
|
|
@@ -284666,7 +284727,7 @@ function createNatsGenieProviderInstance(provider, instance4) {
|
|
|
284666
284727
|
const schemaConfig = typeof provider.schemaConfig === "object" && provider.schemaConfig !== null ? provider.schemaConfig : {};
|
|
284667
284728
|
const agentName = typeof schemaConfig.agentName === "string" ? schemaConfig.agentName : "";
|
|
284668
284729
|
if (!agentName) {
|
|
284669
|
-
|
|
284730
|
+
log93.error("NATS Genie provider missing agentName in schemaConfig", { providerId: provider.id });
|
|
284670
284731
|
return null;
|
|
284671
284732
|
}
|
|
284672
284733
|
const natsUrl = typeof schemaConfig.natsUrl === "string" ? schemaConfig.natsUrl : "localhost:4222";
|
|
@@ -284683,7 +284744,7 @@ function createNatsGenieProviderInstance(provider, instance4) {
|
|
|
284683
284744
|
try {
|
|
284684
284745
|
await sendTextMessage5(channel4, instance4.id, chatId, content);
|
|
284685
284746
|
} catch (error2) {
|
|
284686
|
-
|
|
284747
|
+
log93.error("Failed to deliver agent reply", {
|
|
284687
284748
|
chatId,
|
|
284688
284749
|
instanceId: instance4.id,
|
|
284689
284750
|
providerId: provider.id,
|
|
@@ -284696,11 +284757,11 @@ function createNatsGenieProviderInstance(provider, instance4) {
|
|
|
284696
284757
|
const startWithRetry = async (attempt = 1) => {
|
|
284697
284758
|
try {
|
|
284698
284759
|
await natsProvider.startReplySubscription();
|
|
284699
|
-
|
|
284760
|
+
log93.info("NATS reply subscription started", { instanceId: instance4.id, attempt });
|
|
284700
284761
|
} catch (err) {
|
|
284701
284762
|
const delay2 = Math.min(2000 * 2 ** (attempt - 1), 60000);
|
|
284702
284763
|
if (attempt < 10) {
|
|
284703
|
-
|
|
284764
|
+
log93.warn("NATS reply subscription failed, retrying", {
|
|
284704
284765
|
instanceId: instance4.id,
|
|
284705
284766
|
providerId: provider.id,
|
|
284706
284767
|
attempt,
|
|
@@ -284709,7 +284770,7 @@ function createNatsGenieProviderInstance(provider, instance4) {
|
|
|
284709
284770
|
});
|
|
284710
284771
|
setTimeout(() => startWithRetry(attempt + 1), delay2);
|
|
284711
284772
|
} else {
|
|
284712
|
-
|
|
284773
|
+
log93.error("NATS reply subscription permanently failed", {
|
|
284713
284774
|
instanceId: instance4.id,
|
|
284714
284775
|
providerId: provider.id,
|
|
284715
284776
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -284749,7 +284810,7 @@ function resolveProvider(provider, instance4, db2) {
|
|
|
284749
284810
|
agentProvider = createNatsGenieProviderInstance(provider, instance4);
|
|
284750
284811
|
break;
|
|
284751
284812
|
default:
|
|
284752
|
-
|
|
284813
|
+
log93.debug("Provider schema not supported for IAgentProvider dispatch", {
|
|
284753
284814
|
schema: provider.schema,
|
|
284754
284815
|
providerId: provider.id
|
|
284755
284816
|
});
|
|
@@ -284770,7 +284831,7 @@ function invalidateProviderCache(providerId) {
|
|
|
284770
284831
|
removed++;
|
|
284771
284832
|
if (provider.dispose) {
|
|
284772
284833
|
provider.dispose().catch((err) => {
|
|
284773
|
-
|
|
284834
|
+
log93.warn("Error disposing provider on cache invalidation", { key, error: String(err) });
|
|
284774
284835
|
});
|
|
284775
284836
|
}
|
|
284776
284837
|
}
|
|
@@ -284779,14 +284840,14 @@ function invalidateProviderCache(providerId) {
|
|
|
284779
284840
|
try {
|
|
284780
284841
|
openclawClient.stop();
|
|
284781
284842
|
} catch (err) {
|
|
284782
|
-
|
|
284843
|
+
log93.warn("Error stopping OpenClaw client on cache invalidation", {
|
|
284783
284844
|
providerId,
|
|
284784
284845
|
error: String(err)
|
|
284785
284846
|
});
|
|
284786
284847
|
}
|
|
284787
284848
|
openclawClientPool.delete(providerId);
|
|
284788
284849
|
}
|
|
284789
|
-
|
|
284850
|
+
log93.debug("Provider cache invalidated", { providerId, removed });
|
|
284790
284851
|
}
|
|
284791
284852
|
async function getAgentProvider(services, instance4, db2) {
|
|
284792
284853
|
if (!instance4.agentProviderId)
|
|
@@ -284797,7 +284858,7 @@ async function getAgentProvider(services, instance4, db2) {
|
|
|
284797
284858
|
return null;
|
|
284798
284859
|
return resolveProvider(provider, instance4, db2);
|
|
284799
284860
|
} catch (error2) {
|
|
284800
|
-
|
|
284861
|
+
log93.warn("Failed to resolve agent provider, falling back to legacy", {
|
|
284801
284862
|
instanceId: instance4.id,
|
|
284802
284863
|
providerId: instance4.agentProviderId,
|
|
284803
284864
|
error: String(error2)
|
|
@@ -284861,7 +284922,7 @@ async function applyInstanceFkAndReturn(db2, instance4) {
|
|
|
284861
284922
|
}
|
|
284862
284923
|
async function resolveEffectiveInstance(services, db2, instance4, chatId, personId) {
|
|
284863
284924
|
if (!chatId) {
|
|
284864
|
-
|
|
284925
|
+
log93.debug("No internal chatId \u2014 using instance default agent", { instanceId: instance4.id, personId });
|
|
284865
284926
|
return applyInstanceFkAndReturn(db2, instance4);
|
|
284866
284927
|
}
|
|
284867
284928
|
const route = await services.routeResolver.resolve(instance4.id, chatId, personId);
|
|
@@ -284873,7 +284934,7 @@ async function resolveEffectiveInstance(services, db2, instance4, chatId, person
|
|
|
284873
284934
|
if (effectiveAgentFkId) {
|
|
284874
284935
|
await applyAgentFkOverrides(db2, effectiveAgentFkId, effectiveInstance);
|
|
284875
284936
|
}
|
|
284876
|
-
|
|
284937
|
+
log93.debug("Route resolved and merged", {
|
|
284877
284938
|
instanceId: instance4.id,
|
|
284878
284939
|
chatId,
|
|
284879
284940
|
personId,
|
|
@@ -284894,7 +284955,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
|
|
|
284894
284955
|
const internalChatId = chat2?.id;
|
|
284895
284956
|
const reactionPersonId = await resolvePersonId(services, channel4, baseInstance.id, payload.from, metadata.personId);
|
|
284896
284957
|
const { instance: instance4, routeId: _routeId } = await resolveEffectiveInstance(services, db2, baseInstance, internalChatId, reactionPersonId);
|
|
284897
|
-
|
|
284958
|
+
log93.info("Dispatching reaction trigger", {
|
|
284898
284959
|
instanceId: instance4.id,
|
|
284899
284960
|
chatId: externalChatId,
|
|
284900
284961
|
routeChatId: internalChatId ?? "none",
|
|
@@ -284935,7 +284996,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
|
|
|
284935
284996
|
const _fmtMode = instance4.messageFormatMode ?? "convert";
|
|
284936
284997
|
await sendResponseParts(channel4, instance4.id, externalChatId, result2.parts, getSplitDelayConfig(instance4), _fmtMode, payload.messageId);
|
|
284937
284998
|
}
|
|
284938
|
-
|
|
284999
|
+
log93.info("Reaction trigger response via provider", {
|
|
284939
285000
|
instanceId: instance4.id,
|
|
284940
285001
|
chatId: externalChatId,
|
|
284941
285002
|
routeChatId: internalChatId,
|
|
@@ -284947,7 +285008,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
|
|
|
284947
285008
|
});
|
|
284948
285009
|
return;
|
|
284949
285010
|
}
|
|
284950
|
-
|
|
285011
|
+
log93.debug("No IAgentProvider resolved, using legacy agentRunner path", {
|
|
284951
285012
|
instanceId: instance4.id
|
|
284952
285013
|
});
|
|
284953
285014
|
const personId = await resolvePersonId(services, channel4, instance4.id, payload.from, metadata.personId);
|
|
@@ -284973,7 +285034,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
|
|
|
284973
285034
|
const _fmtMode = instance4.messageFormatMode ?? "convert";
|
|
284974
285035
|
await sendResponseParts(channel4, instance4.id, externalChatId, result.parts, getSplitDelayConfig(instance4), _fmtMode, payload.messageId);
|
|
284975
285036
|
}
|
|
284976
|
-
|
|
285037
|
+
log93.info("Reaction trigger response via legacy runner", {
|
|
284977
285038
|
instanceId: instance4.id,
|
|
284978
285039
|
chatId: externalChatId,
|
|
284979
285040
|
routeChatId: internalChatId,
|
|
@@ -284982,7 +285043,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
|
|
|
284982
285043
|
traceId: metadata.traceId
|
|
284983
285044
|
});
|
|
284984
285045
|
} catch (error2) {
|
|
284985
|
-
|
|
285046
|
+
log93.error("Failed to process reaction trigger", {
|
|
284986
285047
|
instanceId: instance4.id,
|
|
284987
285048
|
chatId: externalChatId,
|
|
284988
285049
|
routeChatId: internalChatId,
|
|
@@ -285017,7 +285078,7 @@ function isTrashEmojiOnly(text3) {
|
|
|
285017
285078
|
}
|
|
285018
285079
|
async function isLidMatchingOwner(chatsService, instanceId, ownerIdentifier, ownerPhone, ownerIsLid, lidJid) {
|
|
285019
285080
|
if (ownerIsLid && extractPhoneFromJid(lidJid) === ownerPhone) {
|
|
285020
|
-
|
|
285081
|
+
log93.debug("LID mention matches owner LID directly", { lidJid, ownerIdentifier });
|
|
285021
285082
|
return true;
|
|
285022
285083
|
}
|
|
285023
285084
|
try {
|
|
@@ -285026,13 +285087,13 @@ async function isLidMatchingOwner(chatsService, instanceId, ownerIdentifier, own
|
|
|
285026
285087
|
return false;
|
|
285027
285088
|
const resolvedPhone = extractPhoneFromJid(mapping);
|
|
285028
285089
|
if (resolvedPhone === ownerPhone) {
|
|
285029
|
-
|
|
285090
|
+
log93.debug("LID resolved to instance owner via DB", { lidJid, resolvedPhone, ownerPhone });
|
|
285030
285091
|
return true;
|
|
285031
285092
|
}
|
|
285032
285093
|
if (ownerIsLid) {
|
|
285033
285094
|
const ownerMapping = await chatsService.findLidMapping(instanceId, ownerIdentifier);
|
|
285034
285095
|
if (ownerMapping && extractPhoneFromJid(ownerMapping) === resolvedPhone) {
|
|
285035
|
-
|
|
285096
|
+
log93.debug("LID resolved to owner via reverse mapping", { lidJid, resolvedPhone, ownerIdentifier });
|
|
285036
285097
|
return true;
|
|
285037
285098
|
}
|
|
285038
285099
|
}
|
|
@@ -285087,15 +285148,15 @@ function isInboundTooStale(rawPayload, maxAgeMinutes, now = Date.now()) {
|
|
|
285087
285148
|
}
|
|
285088
285149
|
async function shouldProcessMessage3(agentRunner, accessService, chatsService, messagesService, routeResolver, payload, metadata) {
|
|
285089
285150
|
if (!metadata.instanceId) {
|
|
285090
|
-
|
|
285151
|
+
log93.debug("No instanceId in metadata", { from: payload.from, chatId: payload.chatId });
|
|
285091
285152
|
return null;
|
|
285092
285153
|
}
|
|
285093
285154
|
if (payload.from === metadata.platformIdentityId) {
|
|
285094
|
-
|
|
285155
|
+
log93.debug("Message from self, skipping", { instanceId: metadata.instanceId, from: payload.from });
|
|
285095
285156
|
return null;
|
|
285096
285157
|
}
|
|
285097
285158
|
if (isTrashEmojiOnly(payload.content?.text)) {
|
|
285098
|
-
|
|
285159
|
+
log93.debug("Skipping trash emoji message (session-cleaner handles this)", {
|
|
285099
285160
|
instanceId: metadata.instanceId,
|
|
285100
285161
|
chatId: payload.chatId
|
|
285101
285162
|
});
|
|
@@ -285103,17 +285164,17 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
|
|
|
285103
285164
|
}
|
|
285104
285165
|
const chatId = payload.chatId ?? "";
|
|
285105
285166
|
if (isBroadcastOrNewsletter(chatId)) {
|
|
285106
|
-
|
|
285167
|
+
log93.debug("Skipping newsletter/broadcast message", { instanceId: metadata.instanceId, chatId });
|
|
285107
285168
|
return null;
|
|
285108
285169
|
}
|
|
285109
285170
|
const instance4 = await agentRunner.getInstanceWithProvider(metadata.instanceId);
|
|
285110
285171
|
if (!instance4?.agentId) {
|
|
285111
|
-
|
|
285172
|
+
log93.debug("Instance has no agentId", { instanceId: metadata.instanceId });
|
|
285112
285173
|
return null;
|
|
285113
285174
|
}
|
|
285114
285175
|
const staleness = isInboundTooStale(payload.rawPayload, instance4.inboundMaxAgeMinutes);
|
|
285115
285176
|
if (staleness.stale) {
|
|
285116
|
-
|
|
285177
|
+
log93.warn("Dropping stale inbound message", {
|
|
285117
285178
|
instanceId: instance4.id,
|
|
285118
285179
|
chatId: payload.chatId,
|
|
285119
285180
|
externalId: payload.externalId,
|
|
@@ -285124,7 +285185,7 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
|
|
|
285124
285185
|
return null;
|
|
285125
285186
|
}
|
|
285126
285187
|
if (!instanceTriggersOnEvent(instance4, "message.received")) {
|
|
285127
|
-
|
|
285188
|
+
log93.debug("Instance does not trigger on message.received", { instanceId: instance4.id });
|
|
285128
285189
|
return null;
|
|
285129
285190
|
}
|
|
285130
285191
|
const messageContext = buildMessageContext(payload, instance4);
|
|
@@ -285134,7 +285195,7 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
|
|
|
285134
285195
|
await resolveLidMentionBot(chatsService, metadata.instanceId, instance4.ownerIdentifier, mentionedJids, messageContext);
|
|
285135
285196
|
}
|
|
285136
285197
|
await resolveSlackThreadReply(chatsService, messagesService, instance4, payload, messageContext);
|
|
285137
|
-
|
|
285198
|
+
log93.debug("Message context built", {
|
|
285138
285199
|
instanceId: instance4.id,
|
|
285139
285200
|
chatId: payload.chatId,
|
|
285140
285201
|
isDirectMessage: messageContext.isDirectMessage,
|
|
@@ -285145,12 +285206,12 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
|
|
|
285145
285206
|
const effectiveReplyFilter = await resolveEffectiveReplyFilter(chatsService, routeResolver, instance4.id, payload.chatId, instance4.agentReplyFilter);
|
|
285146
285207
|
if (!effectiveReplyFilter && !nullFilterWarnedInstances.has(instance4.id)) {
|
|
285147
285208
|
nullFilterWarnedInstances.add(instance4.id);
|
|
285148
|
-
|
|
285209
|
+
log93.warn("instance has no agent_reply_filter configured \u2014 allowing all inbound messages", {
|
|
285149
285210
|
instanceId: instance4.id
|
|
285150
285211
|
});
|
|
285151
285212
|
}
|
|
285152
285213
|
if (!shouldAgentReply(effectiveReplyFilter, messageContext)) {
|
|
285153
|
-
|
|
285214
|
+
log93.info("Message did not pass reply filter", {
|
|
285154
285215
|
instanceId: instance4.id,
|
|
285155
285216
|
chatId: payload.chatId,
|
|
285156
285217
|
messageContext,
|
|
@@ -285174,7 +285235,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
|
|
|
285174
285235
|
const primaryId = payload.from ?? "";
|
|
285175
285236
|
let accessResult = await accessService.checkAccess(instance4, primaryId, channel4);
|
|
285176
285237
|
if (!accessResult.allowed && participantAlt && participantAlt !== primaryId) {
|
|
285177
|
-
|
|
285238
|
+
log93.warn("Access fallback to participantAlt", {
|
|
285178
285239
|
instanceId: instance4.id,
|
|
285179
285240
|
primaryId,
|
|
285180
285241
|
participantAlt,
|
|
@@ -285183,7 +285244,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
|
|
|
285183
285244
|
accessResult = await accessService.checkAccess(instance4, participantAlt, channel4);
|
|
285184
285245
|
}
|
|
285185
285246
|
if (!accessResult.allowed && resolvedSenderPhone && resolvedSenderPhone !== primaryId && resolvedSenderPhone !== participantAlt) {
|
|
285186
|
-
|
|
285247
|
+
log93.debug("Access fallback to resolvedSenderPhone (LID\u2192phone)", {
|
|
285187
285248
|
instanceId: instance4.id,
|
|
285188
285249
|
primaryId,
|
|
285189
285250
|
resolvedSenderPhone,
|
|
@@ -285193,7 +285254,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
|
|
|
285193
285254
|
}
|
|
285194
285255
|
if (accessResult.allowed)
|
|
285195
285256
|
return false;
|
|
285196
|
-
|
|
285257
|
+
log93.info("Access denied", {
|
|
285197
285258
|
instanceId: instance4.id,
|
|
285198
285259
|
chatId: payload.chatId,
|
|
285199
285260
|
from: payload.from,
|
|
@@ -285202,7 +285263,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
|
|
|
285202
285263
|
});
|
|
285203
285264
|
if (accessResult.mode === "allowlist" && !accessResult.rule && primaryId) {
|
|
285204
285265
|
accessService.requestPairing(instance4.id, primaryId, { channelType: instance4.channel }).catch((err) => {
|
|
285205
|
-
|
|
285266
|
+
log93.warn("Failed to create pairing request", { instanceId: instance4.id, from: primaryId, error: String(err) });
|
|
285206
285267
|
});
|
|
285207
285268
|
}
|
|
285208
285269
|
if (accessResult.rule?.action !== "silent_block" && accessResult.rule?.blockMessage) {
|
|
@@ -285219,7 +285280,7 @@ async function shouldProcessReaction(agentRunner, accessService, reactionDedup,
|
|
|
285219
285280
|
if (!instanceTriggersOnEvent(instance4, eventType))
|
|
285220
285281
|
return null;
|
|
285221
285282
|
if (!isReactionTrigger(instance4, payload.emoji)) {
|
|
285222
|
-
|
|
285283
|
+
log93.debug("Reaction emoji not in trigger list", { instanceId: instance4.id, emoji: payload.emoji });
|
|
285223
285284
|
return null;
|
|
285224
285285
|
}
|
|
285225
285286
|
const channel4 = metadata.channelType ?? instance4.channel;
|
|
@@ -285227,7 +285288,7 @@ async function shouldProcessReaction(agentRunner, accessService, reactionDedup,
|
|
|
285227
285288
|
if (accessDenied)
|
|
285228
285289
|
return null;
|
|
285229
285290
|
if (reactionDedup.isDuplicate(payload.messageId, payload.emoji, payload.from)) {
|
|
285230
|
-
|
|
285291
|
+
log93.debug("Duplicate reaction, skipping", {
|
|
285231
285292
|
instanceId: instance4.id,
|
|
285232
285293
|
messageId: payload.messageId,
|
|
285233
285294
|
emoji: payload.emoji
|
|
@@ -285260,7 +285321,7 @@ async function shouldRespondViaGate(instance4, messages4, chatType, settings) {
|
|
|
285260
285321
|
try {
|
|
285261
285322
|
const apiKey = await settings.getSecret("gemini.api_key", "GEMINI_API_KEY");
|
|
285262
285323
|
if (!apiKey) {
|
|
285263
|
-
|
|
285324
|
+
log93.warn("Gate: no Gemini API key, fail-open", { traceId });
|
|
285264
285325
|
return true;
|
|
285265
285326
|
}
|
|
285266
285327
|
const controller = new AbortController;
|
|
@@ -285278,13 +285339,13 @@ async function shouldRespondViaGate(instance4, messages4, chatType, settings) {
|
|
|
285278
285339
|
});
|
|
285279
285340
|
clearTimeout(timeout);
|
|
285280
285341
|
if (!res.ok) {
|
|
285281
|
-
|
|
285342
|
+
log93.warn("Gate: API error, fail-open", { traceId, status: res.status, durationMs: Date.now() - startMs });
|
|
285282
285343
|
return true;
|
|
285283
285344
|
}
|
|
285284
285345
|
const data = await res.json();
|
|
285285
285346
|
const answer = data.candidates?.[0]?.content?.parts?.[0]?.text?.trim().toLowerCase() ?? "";
|
|
285286
285347
|
const shouldRespond = !answer.startsWith("skip");
|
|
285287
|
-
|
|
285348
|
+
log93.info("Gate decision", {
|
|
285288
285349
|
traceId,
|
|
285289
285350
|
decision: shouldRespond ? "respond" : "skip",
|
|
285290
285351
|
rawAnswer: answer,
|
|
@@ -285298,14 +285359,14 @@ async function shouldRespondViaGate(instance4, messages4, chatType, settings) {
|
|
|
285298
285359
|
clearTimeout(timeout);
|
|
285299
285360
|
const errName = fetchError.name;
|
|
285300
285361
|
if (errName === "AbortError") {
|
|
285301
|
-
|
|
285362
|
+
log93.warn("Gate: timeout, fail-open", { traceId, durationMs: Date.now() - startMs });
|
|
285302
285363
|
} else {
|
|
285303
|
-
|
|
285364
|
+
log93.warn("Gate: fetch error, fail-open", { traceId, error: String(fetchError) });
|
|
285304
285365
|
}
|
|
285305
285366
|
return true;
|
|
285306
285367
|
}
|
|
285307
285368
|
} catch (error2) {
|
|
285308
|
-
|
|
285369
|
+
log93.warn("Gate: unexpected error, fail-open", { traceId, error: String(error2) });
|
|
285309
285370
|
return true;
|
|
285310
285371
|
}
|
|
285311
285372
|
}
|
|
@@ -285315,7 +285376,7 @@ async function shouldSkipViaGate(triggerType, firstMsg, instance4, messages4, se
|
|
|
285315
285376
|
const chatType = determineChatType(firstMsg.payload.chatId, firstMsg.metadata.channelType ?? instance4.channel, firstMsg.payload.rawPayload ?? {});
|
|
285316
285377
|
const shouldRespond = await shouldRespondViaGate(instance4, messages4, chatType, services.settings);
|
|
285317
285378
|
if (!shouldRespond) {
|
|
285318
|
-
|
|
285379
|
+
log93.info("Gate skipped response", {
|
|
285319
285380
|
instanceId: instance4.id,
|
|
285320
285381
|
chatId: firstMsg.payload.chatId,
|
|
285321
285382
|
triggerType,
|
|
@@ -285334,7 +285395,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285334
285395
|
const leakThreshold = 10 * 60000;
|
|
285335
285396
|
for (const [mediaId, pending] of mediaCompletions.entries()) {
|
|
285336
285397
|
if (now - pending.createdAt > leakThreshold) {
|
|
285337
|
-
|
|
285398
|
+
log93.warn("media_promise_leaked", { mediaId, ageMs: now - pending.createdAt });
|
|
285338
285399
|
pending.reject(new Error("media processing promise leaked (10min circuit breaker)"));
|
|
285339
285400
|
mediaCompletions.delete(mediaId);
|
|
285340
285401
|
}
|
|
@@ -285351,7 +285412,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285351
285412
|
} else {
|
|
285352
285413
|
const baseInstance = await agentRunner.getInstanceWithProvider(instanceId);
|
|
285353
285414
|
if (!baseInstance) {
|
|
285354
|
-
|
|
285415
|
+
log93.warn("Instance not found for debounced messages", { instanceId });
|
|
285355
285416
|
return;
|
|
285356
285417
|
}
|
|
285357
285418
|
const externalChatId = firstMsg.payload.chatId;
|
|
@@ -285406,7 +285467,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285406
285467
|
timestamp: event.timestamp
|
|
285407
285468
|
}, effectiveDebounceConfig);
|
|
285408
285469
|
} catch (error2) {
|
|
285409
|
-
|
|
285470
|
+
log93.error("Error processing message for dispatch", {
|
|
285410
285471
|
instanceId: metadata.instanceId,
|
|
285411
285472
|
error: String(error2)
|
|
285412
285473
|
});
|
|
@@ -285437,7 +285498,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285437
285498
|
traceId
|
|
285438
285499
|
}, event, db2);
|
|
285439
285500
|
} catch (error2) {
|
|
285440
|
-
|
|
285501
|
+
log93.error("Error processing reaction for dispatch", {
|
|
285441
285502
|
instanceId: metadata.instanceId,
|
|
285442
285503
|
error: String(error2)
|
|
285443
285504
|
});
|
|
@@ -285468,7 +285529,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285468
285529
|
traceId
|
|
285469
285530
|
}, event, db2);
|
|
285470
285531
|
} catch (error2) {
|
|
285471
|
-
|
|
285532
|
+
log93.error("Error processing reaction removal for dispatch", {
|
|
285472
285533
|
instanceId: metadata.instanceId,
|
|
285473
285534
|
error: String(error2)
|
|
285474
285535
|
});
|
|
@@ -285500,7 +285561,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285500
285561
|
debouncer.onUserTyping(metadata.instanceId, payload.chatId, debounceConfig);
|
|
285501
285562
|
}
|
|
285502
285563
|
} catch (error2) {
|
|
285503
|
-
|
|
285564
|
+
log93.debug("Error handling typing event", { error: String(error2) });
|
|
285504
285565
|
}
|
|
285505
285566
|
});
|
|
285506
285567
|
}, {
|
|
@@ -285528,15 +285589,15 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285528
285589
|
queue: "agent-dispatcher-media",
|
|
285529
285590
|
startFrom: "new"
|
|
285530
285591
|
});
|
|
285531
|
-
|
|
285592
|
+
log93.info("Agent dispatcher initialized (message + reaction + reaction-removed + media triggers)");
|
|
285532
285593
|
} catch (error2) {
|
|
285533
|
-
|
|
285594
|
+
log93.error("Failed to set up agent dispatcher", { error: String(error2) });
|
|
285534
285595
|
clearInterval(mediaCleanupInterval);
|
|
285535
285596
|
debouncer.clear();
|
|
285536
285597
|
throw error2;
|
|
285537
285598
|
}
|
|
285538
285599
|
return async () => {
|
|
285539
|
-
|
|
285600
|
+
log93.info("Shutting down agent dispatcher");
|
|
285540
285601
|
clearInterval(mediaCleanupInterval);
|
|
285541
285602
|
debouncer.clear();
|
|
285542
285603
|
for (const [mediaId, pending] of mediaCompletions.entries()) {
|
|
@@ -285548,7 +285609,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285548
285609
|
for (const [key, provider] of providerCache.entries()) {
|
|
285549
285610
|
if (provider.dispose) {
|
|
285550
285611
|
disposePromises.push(provider.dispose().catch((err) => {
|
|
285551
|
-
|
|
285612
|
+
log93.warn("Error disposing provider", { key, error: String(err) });
|
|
285552
285613
|
}));
|
|
285553
285614
|
}
|
|
285554
285615
|
}
|
|
@@ -285558,7 +285619,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285558
285619
|
try {
|
|
285559
285620
|
client.stop();
|
|
285560
285621
|
} catch (err) {
|
|
285561
|
-
|
|
285622
|
+
log93.warn("Error stopping OpenClaw client", { providerId: id, error: String(err) });
|
|
285562
285623
|
}
|
|
285563
285624
|
}));
|
|
285564
285625
|
}
|
|
@@ -285566,7 +285627,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285566
285627
|
let timeoutId;
|
|
285567
285628
|
const timeoutGuard = new Promise((resolve4) => {
|
|
285568
285629
|
timeoutId = setTimeout(() => {
|
|
285569
|
-
|
|
285630
|
+
log93.warn("Dispatcher shutdown timed out after 5s, proceeding");
|
|
285570
285631
|
resolve4([]);
|
|
285571
285632
|
}, 5000);
|
|
285572
285633
|
});
|
|
@@ -285579,10 +285640,10 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
285579
285640
|
}
|
|
285580
285641
|
providerCache.clear();
|
|
285581
285642
|
openclawClientPool.clear();
|
|
285582
|
-
|
|
285643
|
+
log93.info("Agent dispatcher shutdown complete");
|
|
285583
285644
|
};
|
|
285584
285645
|
}
|
|
285585
|
-
var
|
|
285646
|
+
var log93, _natsGenieProviderCtor, QUOTED_MESSAGE_MAX_CHARS = 4000, DM_HISTORY_LIMIT = 20, TRANSIENT_DISPATCH_ERROR_PATTERNS, TRANSIENT_DISPATCH_RETRY_DELAYS_MS, CHANNEL_MESSAGE_LIMITS, DEFAULT_MESSAGE_LIMIT = 4000, MEDIA_BASE_PATH3, MEDIA_ICONS, MEDIA_WAIT_NULL, mediaCompletions, mediaResultCache, DEFAULT_SEND_MEDIA_PATH_TYPES, BOT_PREFIX = "\uD83E\uDD16 ", activeStreams, sessionActivityStore, PROC_REACT_START, PROC_REACT_DONE = "\u2705", providerCache, openclawClientPool, nullFilterWarnedInstances, DEFAULT_GATE_MODEL = "gemini-3-flash-preview", GATE_TIMEOUT_MS = 3000, setupAgentResponder;
|
|
285586
285647
|
var init_agent_dispatcher = __esm(() => {
|
|
285587
285648
|
init_src2();
|
|
285588
285649
|
init_src();
|
|
@@ -285599,7 +285660,7 @@ var init_agent_dispatcher = __esm(() => {
|
|
|
285599
285660
|
init_message_persistence();
|
|
285600
285661
|
init_session_storage();
|
|
285601
285662
|
init_src7();
|
|
285602
|
-
|
|
285663
|
+
log93 = createLogger("agent-dispatcher");
|
|
285603
285664
|
_natsGenieProviderCtor = NatsGenieProvider;
|
|
285604
285665
|
TRANSIENT_DISPATCH_ERROR_PATTERNS = [
|
|
285605
285666
|
/ECONNREFUSED/i,
|
|
@@ -285760,7 +285821,7 @@ class RouteResolver {
|
|
|
285760
285821
|
}
|
|
285761
285822
|
async resolve(instanceId, chatId, personId) {
|
|
285762
285823
|
if (!UUID_RE2.test(chatId)) {
|
|
285763
|
-
|
|
285824
|
+
log94.debug("Skipping chat route resolution \u2014 chatId is not a valid UUID", {
|
|
285764
285825
|
instanceId,
|
|
285765
285826
|
chatId,
|
|
285766
285827
|
personId
|
|
@@ -285772,7 +285833,7 @@ class RouteResolver {
|
|
|
285772
285833
|
if (cached !== undefined) {
|
|
285773
285834
|
this.metrics.hits++;
|
|
285774
285835
|
const result = cached === NO_ROUTE ? null : cached;
|
|
285775
|
-
|
|
285836
|
+
log94.debug("Route cache hit", { instanceId, chatId, personId, hit: true, hasRoute: result !== null });
|
|
285776
285837
|
return result;
|
|
285777
285838
|
}
|
|
285778
285839
|
this.metrics.misses++;
|
|
@@ -285786,7 +285847,7 @@ class RouteResolver {
|
|
|
285786
285847
|
if (!dbRoute) {
|
|
285787
285848
|
this.metrics.sets++;
|
|
285788
285849
|
this.cache.set(cacheKey, NO_ROUTE);
|
|
285789
|
-
|
|
285850
|
+
log94.debug("No route found (using instance default, cached negative result)", {
|
|
285790
285851
|
instanceId,
|
|
285791
285852
|
chatId,
|
|
285792
285853
|
personId,
|
|
@@ -285800,7 +285861,7 @@ class RouteResolver {
|
|
|
285800
285861
|
};
|
|
285801
285862
|
this.metrics.sets++;
|
|
285802
285863
|
this.cache.set(cacheKey, route);
|
|
285803
|
-
|
|
285864
|
+
log94.debug("Route resolved from DB", {
|
|
285804
285865
|
instanceId,
|
|
285805
285866
|
chatId,
|
|
285806
285867
|
personId,
|
|
@@ -285813,12 +285874,12 @@ class RouteResolver {
|
|
|
285813
285874
|
invalidateRoute(routeId) {
|
|
285814
285875
|
this.cache.clear();
|
|
285815
285876
|
this.metrics.invalidations++;
|
|
285816
|
-
|
|
285877
|
+
log94.debug("Route cache invalidated", { routeId });
|
|
285817
285878
|
}
|
|
285818
285879
|
invalidateInstance(instanceId) {
|
|
285819
285880
|
this.cache.clear();
|
|
285820
285881
|
this.metrics.invalidations++;
|
|
285821
|
-
|
|
285882
|
+
log94.debug("Instance cache invalidated", { instanceId });
|
|
285822
285883
|
}
|
|
285823
285884
|
getMetrics() {
|
|
285824
285885
|
const total = this.metrics.hits + this.metrics.misses;
|
|
@@ -285833,13 +285894,13 @@ class RouteResolver {
|
|
|
285833
285894
|
return `${instanceId}:${chatId ?? "null"}:${personId ?? "null"}`;
|
|
285834
285895
|
}
|
|
285835
285896
|
}
|
|
285836
|
-
var
|
|
285897
|
+
var log94, UUID_RE2, NO_ROUTE;
|
|
285837
285898
|
var init_route_resolver = __esm(() => {
|
|
285838
285899
|
init_src();
|
|
285839
285900
|
init_src5();
|
|
285840
285901
|
init_drizzle_orm();
|
|
285841
285902
|
init_index_min();
|
|
285842
|
-
|
|
285903
|
+
log94 = createLogger("route-resolver");
|
|
285843
285904
|
UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
285844
285905
|
NO_ROUTE = Symbol("NO_ROUTE");
|
|
285845
285906
|
});
|
|
@@ -286074,7 +286135,7 @@ class SettingsService {
|
|
|
286074
286135
|
}
|
|
286075
286136
|
}
|
|
286076
286137
|
if (seeded > 0) {
|
|
286077
|
-
|
|
286138
|
+
log95.info("Seeded default settings", { count: seeded });
|
|
286078
286139
|
}
|
|
286079
286140
|
return seeded;
|
|
286080
286141
|
}
|
|
@@ -286135,12 +286196,12 @@ class SettingsService {
|
|
|
286135
286196
|
return "string";
|
|
286136
286197
|
}
|
|
286137
286198
|
}
|
|
286138
|
-
var
|
|
286199
|
+
var log95, DEFAULT_SETTINGS;
|
|
286139
286200
|
var init_settings = __esm(() => {
|
|
286140
286201
|
init_src();
|
|
286141
286202
|
init_src5();
|
|
286142
286203
|
init_drizzle_orm();
|
|
286143
|
-
|
|
286204
|
+
log95 = createLogger("settings");
|
|
286144
286205
|
DEFAULT_SETTINGS = [
|
|
286145
286206
|
{
|
|
286146
286207
|
key: "elevenlabs.api_key",
|
|
@@ -286663,7 +286724,7 @@ class TurnService {
|
|
|
286663
286724
|
if (!turn) {
|
|
286664
286725
|
throw new Error("Failed to create turn");
|
|
286665
286726
|
}
|
|
286666
|
-
|
|
286727
|
+
log96.info("Turn opened", {
|
|
286667
286728
|
turnId: turn.id,
|
|
286668
286729
|
instanceId: options.instanceId,
|
|
286669
286730
|
chatId: options.chatId,
|
|
@@ -286684,7 +286745,7 @@ class TurnService {
|
|
|
286684
286745
|
}).where(and2(eq(turns.id, turnId), eq(turns.status, "open"))).returning();
|
|
286685
286746
|
if (closed) {
|
|
286686
286747
|
const durationMs = now.getTime() - closed.startedAt.getTime();
|
|
286687
|
-
|
|
286748
|
+
log96.info("Turn closed", {
|
|
286688
286749
|
turnId,
|
|
286689
286750
|
action: options.action,
|
|
286690
286751
|
durationMs,
|
|
@@ -286758,7 +286819,7 @@ class TurnService {
|
|
|
286758
286819
|
closedReason: reason ?? "admin force-close"
|
|
286759
286820
|
}).where(and2(eq(turns.id, turnId), eq(turns.status, "open"))).returning();
|
|
286760
286821
|
if (closed) {
|
|
286761
|
-
|
|
286822
|
+
log96.info("Turn force-closed by admin", { turnId });
|
|
286762
286823
|
}
|
|
286763
286824
|
return closed ?? null;
|
|
286764
286825
|
}
|
|
@@ -286770,16 +286831,16 @@ class TurnService {
|
|
|
286770
286831
|
closedAt: now,
|
|
286771
286832
|
closedReason: reason ?? "admin bulk close"
|
|
286772
286833
|
}).where(eq(turns.status, "open")).returning({ id: turns.id });
|
|
286773
|
-
|
|
286834
|
+
log96.info("Bulk close completed", { closedCount: closed.length });
|
|
286774
286835
|
return closed.length;
|
|
286775
286836
|
}
|
|
286776
286837
|
}
|
|
286777
|
-
var
|
|
286838
|
+
var log96;
|
|
286778
286839
|
var init_turns = __esm(() => {
|
|
286779
286840
|
init_src();
|
|
286780
286841
|
init_src5();
|
|
286781
286842
|
init_drizzle_orm();
|
|
286782
|
-
|
|
286843
|
+
log96 = createLogger("turns");
|
|
286783
286844
|
});
|
|
286784
286845
|
|
|
286785
286846
|
// ../api/src/services/webhooks.ts
|
|
@@ -286938,7 +286999,8 @@ function createServices(db2, eventBus) {
|
|
|
286938
286999
|
turns: new TurnService(db2),
|
|
286939
287000
|
consumerOffsets: new ConsumerOffsetService(db2),
|
|
286940
287001
|
followUpLifecycle: new FollowUpLifecycleService(db2, eventBus),
|
|
286941
|
-
followUpSweeper: new FollowUpSweeperService(db2, eventBus)
|
|
287002
|
+
followUpSweeper: new FollowUpSweeperService(db2, eventBus),
|
|
287003
|
+
genieHosts: new GenieHostsService(db2)
|
|
286942
287004
|
};
|
|
286943
287005
|
}
|
|
286944
287006
|
var init_services = __esm(() => {
|
|
@@ -286967,6 +287029,7 @@ var init_services = __esm(() => {
|
|
|
286967
287029
|
init_events2();
|
|
286968
287030
|
init_follow_up_lifecycle();
|
|
286969
287031
|
init_follow_up_sweeper();
|
|
287032
|
+
init_genie_hosts();
|
|
286970
287033
|
init_instances();
|
|
286971
287034
|
init_messages3();
|
|
286972
287035
|
init_payload_store2();
|
|
@@ -287199,15 +287262,15 @@ function isClientError(error2) {
|
|
|
287199
287262
|
}
|
|
287200
287263
|
return false;
|
|
287201
287264
|
}
|
|
287202
|
-
var
|
|
287265
|
+
var log97, SENSITIVE_KEYS, ERROR_STATUS_MAP, CHANNEL_ERROR_MAP, PG_CLIENT_ERROR_CODES, errorHandler2 = (error2, c) => {
|
|
287203
287266
|
const requestId = c.get("requestId") ?? "unknown";
|
|
287204
287267
|
if (isClientError(error2)) {
|
|
287205
|
-
|
|
287268
|
+
log97.debug("Client error", {
|
|
287206
287269
|
requestId,
|
|
287207
287270
|
error: error2 instanceof Error ? error2.message : String(error2)
|
|
287208
287271
|
});
|
|
287209
287272
|
} else {
|
|
287210
|
-
|
|
287273
|
+
log97.error("Server error", {
|
|
287211
287274
|
requestId,
|
|
287212
287275
|
error: error2 instanceof Error ? error2.message : String(error2),
|
|
287213
287276
|
stack: error2 instanceof Error ? error2.stack : undefined
|
|
@@ -287235,7 +287298,7 @@ var init_error3 = __esm(() => {
|
|
|
287235
287298
|
init_esm5();
|
|
287236
287299
|
init_http_exception();
|
|
287237
287300
|
init_zod();
|
|
287238
|
-
|
|
287301
|
+
log97 = createLogger("api:error");
|
|
287239
287302
|
SENSITIVE_KEYS = new Set([
|
|
287240
287303
|
"password",
|
|
287241
287304
|
"token",
|
|
@@ -287481,22 +287544,22 @@ function createWebhookAuthMiddleware(config4) {
|
|
|
287481
287544
|
const token = c.req.header("x-telegram-bot-api-secret-token");
|
|
287482
287545
|
if (!token) {
|
|
287483
287546
|
const ip = c.req.header("x-forwarded-for") || c.req.header("x-real-ip") || "unknown";
|
|
287484
|
-
|
|
287547
|
+
log98.warn("Webhook request missing secret token", { ip });
|
|
287485
287548
|
return c.json({ error: { code: "UNAUTHORIZED", message: "Missing webhook secret token" } }, 401);
|
|
287486
287549
|
}
|
|
287487
287550
|
if (token !== webhookSecret) {
|
|
287488
287551
|
const ip = c.req.header("x-forwarded-for") || c.req.header("x-real-ip") || "unknown";
|
|
287489
|
-
|
|
287552
|
+
log98.warn("Webhook request with invalid secret token", { ip });
|
|
287490
287553
|
return c.json({ error: { code: "UNAUTHORIZED", message: "Invalid webhook secret token" } }, 401);
|
|
287491
287554
|
}
|
|
287492
287555
|
return next();
|
|
287493
287556
|
});
|
|
287494
287557
|
}
|
|
287495
|
-
var
|
|
287558
|
+
var log98;
|
|
287496
287559
|
var init_webhook_auth = __esm(() => {
|
|
287497
287560
|
init_src();
|
|
287498
287561
|
init_factory2();
|
|
287499
|
-
|
|
287562
|
+
log98 = createLogger("api:webhook-auth");
|
|
287500
287563
|
});
|
|
287501
287564
|
|
|
287502
287565
|
// ../api/src/plugin-state.ts
|
|
@@ -294320,7 +294383,7 @@ async function handleTrashEmojiMessage(services, db2, event) {
|
|
|
294320
294383
|
await runTrashEmojiCleanup(services, db2, instanceId, chatId, from);
|
|
294321
294384
|
});
|
|
294322
294385
|
if (!result.executed) {
|
|
294323
|
-
|
|
294386
|
+
log99.debug("Trash emoji event already processed (NATS redelivery skipped)", {
|
|
294324
294387
|
eventId: event.id,
|
|
294325
294388
|
instanceId,
|
|
294326
294389
|
chatId
|
|
@@ -294328,10 +294391,10 @@ async function handleTrashEmojiMessage(services, db2, event) {
|
|
|
294328
294391
|
}
|
|
294329
294392
|
}
|
|
294330
294393
|
async function runTrashEmojiCleanup(services, db2, instanceId, chatId, from) {
|
|
294331
|
-
|
|
294394
|
+
log99.info("Trash emoji detected, clearing session", { instanceId, chatId, from });
|
|
294332
294395
|
try {
|
|
294333
294396
|
const { sessionId, sessionStrategy } = await clearAgentSession(services, db2, instanceId, from, chatId);
|
|
294334
|
-
|
|
294397
|
+
log99.info("Session cleared successfully", { instanceId, sessionId, sessionStrategy });
|
|
294335
294398
|
try {
|
|
294336
294399
|
const dbChat = await services.chats.findByExternalIdSmart(instanceId, chatId);
|
|
294337
294400
|
if (dbChat?.id) {
|
|
@@ -294345,11 +294408,11 @@ async function runTrashEmojiCleanup(services, db2, instanceId, chatId, from) {
|
|
|
294345
294408
|
await services.chats.update(dbChat.id, {
|
|
294346
294409
|
settings: { agentPaused: false, agentResumedAt: new Date().toISOString() }
|
|
294347
294410
|
});
|
|
294348
|
-
|
|
294411
|
+
log99.info("Agent resumed after session clear (was paused by handoff)", { instanceId, chatId });
|
|
294349
294412
|
}
|
|
294350
294413
|
}
|
|
294351
294414
|
} catch (disarmError) {
|
|
294352
|
-
|
|
294415
|
+
log99.warn("Failed to disarm follow-up after session clear", {
|
|
294353
294416
|
instanceId,
|
|
294354
294417
|
chatId,
|
|
294355
294418
|
error: String(disarmError)
|
|
@@ -294357,9 +294420,9 @@ async function runTrashEmojiCleanup(services, db2, instanceId, chatId, from) {
|
|
|
294357
294420
|
}
|
|
294358
294421
|
try {
|
|
294359
294422
|
await sendMessage(services, instanceId, chatId, "\u2705 Conversa limpa! Sua sess\xE3o com o assistente foi resetada.");
|
|
294360
|
-
|
|
294423
|
+
log99.info("Sent session cleared confirmation", { instanceId, chatId });
|
|
294361
294424
|
} catch (sendError) {
|
|
294362
|
-
|
|
294425
|
+
log99.error("Failed to send confirmation message", { instanceId, chatId, error: String(sendError) });
|
|
294363
294426
|
}
|
|
294364
294427
|
} catch (error2) {
|
|
294365
294428
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -294370,14 +294433,14 @@ async function runTrashEmojiCleanup(services, db2, instanceId, chatId, from) {
|
|
|
294370
294433
|
"Session clearing not supported for"
|
|
294371
294434
|
];
|
|
294372
294435
|
if (skippableErrors.some((e) => errorMessage.includes(e))) {
|
|
294373
|
-
|
|
294436
|
+
log99.debug("Session clearing skipped", { instanceId, reason: errorMessage });
|
|
294374
294437
|
return;
|
|
294375
294438
|
}
|
|
294376
|
-
|
|
294439
|
+
log99.error("Failed to clear session", { instanceId, chatId, error: errorMessage });
|
|
294377
294440
|
try {
|
|
294378
294441
|
await sendMessage(services, instanceId, chatId, "\u274C Erro ao limpar sess\xE3o. Tente novamente.");
|
|
294379
294442
|
} catch (sendError) {
|
|
294380
|
-
|
|
294443
|
+
log99.error("Failed to send error message", { instanceId, chatId, error: String(sendError) });
|
|
294381
294444
|
}
|
|
294382
294445
|
}
|
|
294383
294446
|
}
|
|
@@ -294391,13 +294454,13 @@ async function setupSessionCleaner(eventBus, services, db2) {
|
|
|
294391
294454
|
startFrom: "new",
|
|
294392
294455
|
concurrency: 5
|
|
294393
294456
|
});
|
|
294394
|
-
|
|
294457
|
+
log99.info("Session cleaner initialized");
|
|
294395
294458
|
} catch (error2) {
|
|
294396
|
-
|
|
294459
|
+
log99.error("Failed to set up session cleaner", { error: String(error2) });
|
|
294397
294460
|
throw error2;
|
|
294398
294461
|
}
|
|
294399
294462
|
}
|
|
294400
|
-
var
|
|
294463
|
+
var log99;
|
|
294401
294464
|
var init_session_cleaner = __esm(() => {
|
|
294402
294465
|
init_src();
|
|
294403
294466
|
init_src5();
|
|
@@ -294406,7 +294469,7 @@ var init_session_cleaner = __esm(() => {
|
|
|
294406
294469
|
init_agent_runner();
|
|
294407
294470
|
init_agent_dispatcher();
|
|
294408
294471
|
init_loader2();
|
|
294409
|
-
|
|
294472
|
+
log99 = createLogger("session-cleaner");
|
|
294410
294473
|
});
|
|
294411
294474
|
|
|
294412
294475
|
// ../api/src/routes/v2/chats.ts
|
|
@@ -296650,12 +296713,12 @@ async function printQrCodeToTerminal(qrCode, instanceId) {
|
|
|
296650
296713
|
try {
|
|
296651
296714
|
const qrTerminalModule = await Promise.resolve().then(() => __toESM(require_main(), 1));
|
|
296652
296715
|
const qrTerminal = qrTerminalModule.default || qrTerminalModule;
|
|
296653
|
-
|
|
296716
|
+
log100.info("QR Code generated for WhatsApp", { instanceId });
|
|
296654
296717
|
qrTerminal.generate(qrCode, { small: true });
|
|
296655
296718
|
} catch (error2) {
|
|
296656
|
-
|
|
296719
|
+
log100.info("QR Code generated", { instanceId, qrCode: `${qrCode.substring(0, 50)}...` });
|
|
296657
296720
|
if (error2 instanceof Error && process.env.DEBUG) {
|
|
296658
|
-
|
|
296721
|
+
log100.debug("QR Terminal unavailable", { error: error2.message });
|
|
296659
296722
|
}
|
|
296660
296723
|
}
|
|
296661
296724
|
}
|
|
@@ -296667,13 +296730,13 @@ async function setupQrCodeListener(eventBus) {
|
|
|
296667
296730
|
await printQrCodeToTerminal(qrCode, instanceId);
|
|
296668
296731
|
});
|
|
296669
296732
|
} catch (error2) {
|
|
296670
|
-
|
|
296733
|
+
log100.warn("Failed to set up QR code listener", { error: String(error2) });
|
|
296671
296734
|
}
|
|
296672
296735
|
}
|
|
296673
|
-
var
|
|
296736
|
+
var log100, qrCodes;
|
|
296674
296737
|
var init_qr_store = __esm(() => {
|
|
296675
296738
|
init_src();
|
|
296676
|
-
|
|
296739
|
+
log100 = createLogger("api:qr-store");
|
|
296677
296740
|
qrCodes = new Map;
|
|
296678
296741
|
});
|
|
296679
296742
|
|
|
@@ -296694,29 +296757,29 @@ class AgentReplayService {
|
|
|
296694
296757
|
agentId: instances.agentId
|
|
296695
296758
|
}).from(instances).where(eq(instances.id, instanceId)).limit(1);
|
|
296696
296759
|
if (!instance4) {
|
|
296697
|
-
|
|
296760
|
+
log101.warn("Instance not found for replay", { instanceId });
|
|
296698
296761
|
return;
|
|
296699
296762
|
}
|
|
296700
296763
|
if (!instance4.agentId) {
|
|
296701
|
-
|
|
296764
|
+
log101.debug("Instance has no agent, skipping replay", { instanceId });
|
|
296702
296765
|
await this.updateLastSeenAt(instanceId);
|
|
296703
296766
|
return;
|
|
296704
296767
|
}
|
|
296705
296768
|
if (!instance4.replayEnabled) {
|
|
296706
|
-
|
|
296769
|
+
log101.debug("Replay disabled for instance", { instanceId });
|
|
296707
296770
|
await this.updateLastSeenAt(instanceId);
|
|
296708
296771
|
return;
|
|
296709
296772
|
}
|
|
296710
296773
|
const since = instance4.lastSeenAt ?? null;
|
|
296711
296774
|
if (!since) {
|
|
296712
|
-
|
|
296775
|
+
log101.debug("No lastSeenAt recorded, skipping replay (first connect)", { instanceId });
|
|
296713
296776
|
await this.updateLastSeenAt(instanceId);
|
|
296714
296777
|
return;
|
|
296715
296778
|
}
|
|
296716
|
-
|
|
296779
|
+
log101.info("Starting replay on reconnect", { instanceId, since: since.toISOString() });
|
|
296717
296780
|
try {
|
|
296718
296781
|
const result = await this.replayMissedMessages({ instanceId, since });
|
|
296719
|
-
|
|
296782
|
+
log101.info("Replay complete", {
|
|
296720
296783
|
instanceId,
|
|
296721
296784
|
replayed: result.replayed,
|
|
296722
296785
|
skipped: result.skipped,
|
|
@@ -296724,7 +296787,7 @@ class AgentReplayService {
|
|
|
296724
296787
|
});
|
|
296725
296788
|
await this.updateLastSeenAt(instanceId, result.until);
|
|
296726
296789
|
} catch (error2) {
|
|
296727
|
-
|
|
296790
|
+
log101.error("Replay failed", { instanceId, error: String(error2) });
|
|
296728
296791
|
}
|
|
296729
296792
|
}
|
|
296730
296793
|
async replayMissedMessages(options) {
|
|
@@ -296732,7 +296795,7 @@ class AgentReplayService {
|
|
|
296732
296795
|
const now = new Date;
|
|
296733
296796
|
const cutoff = new Date(now.getTime() - MAX_REPLAY_WINDOW_MS);
|
|
296734
296797
|
const since = options.since && options.since > cutoff ? options.since : cutoff;
|
|
296735
|
-
|
|
296798
|
+
log101.debug("Fetching missed messages", { instanceId, since: since.toISOString(), until: now.toISOString() });
|
|
296736
296799
|
let cursorTimestamp = since;
|
|
296737
296800
|
let cursorId = null;
|
|
296738
296801
|
let totalReplayed = 0;
|
|
@@ -296766,7 +296829,7 @@ class AgentReplayService {
|
|
|
296766
296829
|
if (rows.length === 0)
|
|
296767
296830
|
break;
|
|
296768
296831
|
if (rows.length === PAGE_SIZE) {
|
|
296769
|
-
|
|
296832
|
+
log101.warn("Replay page cap hit, fetching next page", {
|
|
296770
296833
|
instanceId,
|
|
296771
296834
|
limit: PAGE_SIZE,
|
|
296772
296835
|
cursor: cursorTimestamp.toISOString()
|
|
@@ -296794,7 +296857,7 @@ class AgentReplayService {
|
|
|
296794
296857
|
await this.redispatchMessage(instanceId, row);
|
|
296795
296858
|
replayed++;
|
|
296796
296859
|
} catch (error2) {
|
|
296797
|
-
|
|
296860
|
+
log101.warn("Failed to redispatch message during replay", {
|
|
296798
296861
|
instanceId,
|
|
296799
296862
|
messageId: row.id,
|
|
296800
296863
|
error: String(error2)
|
|
@@ -296851,12 +296914,12 @@ function mapMessageTypeToContentType(messageType) {
|
|
|
296851
296914
|
return "text";
|
|
296852
296915
|
}
|
|
296853
296916
|
}
|
|
296854
|
-
var
|
|
296917
|
+
var log101, MAX_REPLAY_WINDOW_MS;
|
|
296855
296918
|
var init_agent_replay = __esm(() => {
|
|
296856
296919
|
init_src();
|
|
296857
296920
|
init_src5();
|
|
296858
296921
|
init_drizzle_orm();
|
|
296859
|
-
|
|
296922
|
+
log101 = createLogger("agent-replay");
|
|
296860
296923
|
MAX_REPLAY_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
296861
296924
|
});
|
|
296862
296925
|
|
|
@@ -297026,15 +297089,15 @@ async function connectInstanceWithPlugin(plugin7, instanceId, options) {
|
|
|
297026
297089
|
async function triggerCreateConnection(channelRegistry2, channel4, instanceId, options) {
|
|
297027
297090
|
const plugin7 = getPluginFromRegistry(channelRegistry2, channel4);
|
|
297028
297091
|
if (!plugin7) {
|
|
297029
|
-
|
|
297092
|
+
log102.warn("No plugin found for channel", { channel: channel4 });
|
|
297030
297093
|
return;
|
|
297031
297094
|
}
|
|
297032
297095
|
const errorMessage = await connectInstanceWithPlugin(plugin7, instanceId, options);
|
|
297033
297096
|
if (errorMessage) {
|
|
297034
|
-
|
|
297097
|
+
log102.error("Failed to connect instance", { instanceId, error: errorMessage });
|
|
297035
297098
|
return;
|
|
297036
297099
|
}
|
|
297037
|
-
|
|
297100
|
+
log102.info("Triggered connection", { instanceId, channel: channel4 });
|
|
297038
297101
|
}
|
|
297039
297102
|
function buildTokenPersistUpdates(channel4, body) {
|
|
297040
297103
|
const updates = {};
|
|
@@ -297068,10 +297131,10 @@ async function handleAgentKeyProvisioning(services, instanceId, newAgentId, oldA
|
|
|
297068
297131
|
await services.apiKeys.update(existingKey.id, {
|
|
297069
297132
|
instanceIds: updated.length > 0 ? updated : null
|
|
297070
297133
|
});
|
|
297071
|
-
|
|
297134
|
+
log102.info("Removed instance from agent key", { keyName, instanceId });
|
|
297072
297135
|
}
|
|
297073
297136
|
} catch (err) {
|
|
297074
|
-
|
|
297137
|
+
log102.error("Failed to remove instance from old agent key", { oldAgentId, instanceId, error: String(err) });
|
|
297075
297138
|
}
|
|
297076
297139
|
}
|
|
297077
297140
|
if (newAgentId) {
|
|
@@ -297085,7 +297148,7 @@ async function handleAgentKeyProvisioning(services, instanceId, newAgentId, oldA
|
|
|
297085
297148
|
await services.apiKeys.update(existingKey.id, {
|
|
297086
297149
|
instanceIds: [...currentIds, instanceId]
|
|
297087
297150
|
});
|
|
297088
|
-
|
|
297151
|
+
log102.info("Added instance to existing agent key", { keyName, instanceId });
|
|
297089
297152
|
}
|
|
297090
297153
|
} else {
|
|
297091
297154
|
const agentScopes = Array.isArray(agent3.metadata?.omniScopes) ? agent3.metadata.omniScopes : [...DEFAULT_TURN_SCOPES];
|
|
@@ -297096,10 +297159,10 @@ async function handleAgentKeyProvisioning(services, instanceId, newAgentId, oldA
|
|
|
297096
297159
|
instanceIds: [instanceId],
|
|
297097
297160
|
createdBy: "system:auto-provision"
|
|
297098
297161
|
});
|
|
297099
|
-
|
|
297162
|
+
log102.info("Created scoped agent key", { keyName, instanceId, keyId: result.key.id });
|
|
297100
297163
|
}
|
|
297101
297164
|
} catch (err) {
|
|
297102
|
-
|
|
297165
|
+
log102.error("Failed to provision agent key", { newAgentId, instanceId, error: String(err) });
|
|
297103
297166
|
}
|
|
297104
297167
|
}
|
|
297105
297168
|
}
|
|
@@ -297232,7 +297295,7 @@ function getCacheKey(instanceId, guildId) {
|
|
|
297232
297295
|
function invalidateGuildCache(instanceId, guildId) {
|
|
297233
297296
|
guildConfigCache.delete(getCacheKey(instanceId, guildId));
|
|
297234
297297
|
}
|
|
297235
|
-
var
|
|
297298
|
+
var log102, instancesRoutes, instanceAccess2, listQuerySchema11, agentReplyFilterSchema, createInstanceSchema, updateInstanceSchema, DEFAULT_AGENT_REPLY_FILTER, SENSITIVE_INSTANCE_FIELDS, pairingCodeSchema, connectInstanceSchema, syncRequestSchema, listContactsQuerySchema, listGroupsQuerySchema, checkNumberSchema, updateBioSchema, blockContactSchema, resyncSchema, replaySchema, pairingActionSchema, guildConfigOverrideSchema, guildConfigCache, GUILD_CONFIG_TTL, presenceSchema;
|
|
297236
297299
|
var init_instances3 = __esm(() => {
|
|
297237
297300
|
init_dist6();
|
|
297238
297301
|
init_src();
|
|
@@ -297244,7 +297307,7 @@ var init_instances3 = __esm(() => {
|
|
|
297244
297307
|
init_qr_store();
|
|
297245
297308
|
init_access();
|
|
297246
297309
|
init_agent_replay();
|
|
297247
|
-
|
|
297310
|
+
log102 = createLogger("api:instances");
|
|
297248
297311
|
instancesRoutes = new Hono2;
|
|
297249
297312
|
instanceAccess2 = requireInstanceAccess((c) => c.req.param("id"));
|
|
297250
297313
|
listQuerySchema11 = exports_external.object({
|
|
@@ -297430,7 +297493,7 @@ var init_instances3 = __esm(() => {
|
|
|
297430
297493
|
agentIdTouched: data.agentId !== undefined
|
|
297431
297494
|
})) {
|
|
297432
297495
|
data.agentReplyFilter = DEFAULT_AGENT_REPLY_FILTER;
|
|
297433
|
-
|
|
297496
|
+
log102.info("Agent assigned without reply filter \u2014 defaulting to mode:all onDm:true (omni#443)", {
|
|
297434
297497
|
agentId: data.agentId,
|
|
297435
297498
|
defaultFilter: DEFAULT_AGENT_REPLY_FILTER
|
|
297436
297499
|
});
|
|
@@ -297484,7 +297547,7 @@ var init_instances3 = __esm(() => {
|
|
|
297484
297547
|
agentIdTouched: data.agentId !== undefined
|
|
297485
297548
|
})) {
|
|
297486
297549
|
data.agentReplyFilter = DEFAULT_AGENT_REPLY_FILTER;
|
|
297487
|
-
|
|
297550
|
+
log102.info("Agent assigned without reply filter \u2014 defaulting to mode:all onDm:true (omni#443)", {
|
|
297488
297551
|
instanceId: id,
|
|
297489
297552
|
agentId: data.agentId,
|
|
297490
297553
|
defaultFilter: DEFAULT_AGENT_REPLY_FILTER
|
|
@@ -297509,7 +297572,7 @@ var init_instances3 = __esm(() => {
|
|
|
297509
297572
|
try {
|
|
297510
297573
|
await plugin7.disconnect(id);
|
|
297511
297574
|
} catch (error2) {
|
|
297512
|
-
|
|
297575
|
+
log102.error("Failed to disconnect instance before delete", { instanceId: id, error: String(error2) });
|
|
297513
297576
|
}
|
|
297514
297577
|
}
|
|
297515
297578
|
await services.instances.delete(id);
|
|
@@ -297517,7 +297580,7 @@ var init_instances3 = __esm(() => {
|
|
|
297517
297580
|
try {
|
|
297518
297581
|
await plugin7.logout(id);
|
|
297519
297582
|
} catch (error2) {
|
|
297520
|
-
|
|
297583
|
+
log102.error("Failed to clear channel auth after delete", { instanceId: id, error: String(error2) });
|
|
297521
297584
|
}
|
|
297522
297585
|
}
|
|
297523
297586
|
return c.json({ success: true });
|
|
@@ -297681,7 +297744,7 @@ var init_instances3 = __esm(() => {
|
|
|
297681
297744
|
try {
|
|
297682
297745
|
await plugin7.disconnect(id);
|
|
297683
297746
|
} catch (error2) {
|
|
297684
|
-
|
|
297747
|
+
log102.error("Failed to disconnect instance", { instanceId: id, error: String(error2) });
|
|
297685
297748
|
}
|
|
297686
297749
|
}
|
|
297687
297750
|
}
|
|
@@ -297761,13 +297824,13 @@ var init_instances3 = __esm(() => {
|
|
|
297761
297824
|
try {
|
|
297762
297825
|
await plugin7.logout(id);
|
|
297763
297826
|
} catch (error2) {
|
|
297764
|
-
|
|
297827
|
+
log102.error("Failed to logout instance", { instanceId: id, error: String(error2) });
|
|
297765
297828
|
}
|
|
297766
297829
|
} else if (plugin7) {
|
|
297767
297830
|
try {
|
|
297768
297831
|
await plugin7.disconnect(id);
|
|
297769
297832
|
} catch (error2) {
|
|
297770
|
-
|
|
297833
|
+
log102.error("Failed to disconnect instance during logout", { instanceId: id, error: String(error2) });
|
|
297771
297834
|
}
|
|
297772
297835
|
}
|
|
297773
297836
|
}
|
|
@@ -298557,7 +298620,7 @@ var init_instances3 = __esm(() => {
|
|
|
298557
298620
|
...chatJids?.length ? { chatJids } : {}
|
|
298558
298621
|
}
|
|
298559
298622
|
});
|
|
298560
|
-
|
|
298623
|
+
log102.info("Resync triggered", {
|
|
298561
298624
|
instanceId: id,
|
|
298562
298625
|
jobId: job.id,
|
|
298563
298626
|
since: sinceDate.toISOString(),
|
|
@@ -298575,7 +298638,7 @@ var init_instances3 = __esm(() => {
|
|
|
298575
298638
|
});
|
|
298576
298639
|
} catch (error2) {
|
|
298577
298640
|
const message2 = error2 instanceof Error ? error2.message : "Unknown error";
|
|
298578
|
-
|
|
298641
|
+
log102.error("Failed to trigger resync", { instanceId: id, error: message2 });
|
|
298579
298642
|
return c.json({ error: { code: "RESYNC_FAILED", message: message2 } }, 500);
|
|
298580
298643
|
}
|
|
298581
298644
|
});
|
|
@@ -298604,7 +298667,7 @@ var init_instances3 = __esm(() => {
|
|
|
298604
298667
|
const sinceDate = since ? new Date(since) : undefined;
|
|
298605
298668
|
try {
|
|
298606
298669
|
const result = await replayService.replayMissedMessages({ instanceId: instance4.id, since: sinceDate });
|
|
298607
|
-
|
|
298670
|
+
log102.info("Manual replay triggered", {
|
|
298608
298671
|
instanceId: instance4.id,
|
|
298609
298672
|
replayed: result.replayed,
|
|
298610
298673
|
since: result.since.toISOString()
|
|
@@ -298620,7 +298683,7 @@ var init_instances3 = __esm(() => {
|
|
|
298620
298683
|
});
|
|
298621
298684
|
} catch (error2) {
|
|
298622
298685
|
const message2 = error2 instanceof Error ? error2.message : "Unknown error";
|
|
298623
|
-
|
|
298686
|
+
log102.error("Manual replay failed", { instanceId: id, error: message2 });
|
|
298624
298687
|
return c.json({ error: { code: "REPLAY_FAILED", message: message2 } }, 500);
|
|
298625
298688
|
}
|
|
298626
298689
|
});
|
|
@@ -298753,7 +298816,7 @@ var init_instances3 = __esm(() => {
|
|
|
298753
298816
|
plugin7.setGuildConfig(id, guildId, newConfig);
|
|
298754
298817
|
}
|
|
298755
298818
|
}
|
|
298756
|
-
|
|
298819
|
+
log102.info("Guild config updated", {
|
|
298757
298820
|
instanceId: id,
|
|
298758
298821
|
guildId,
|
|
298759
298822
|
apiKeyId: apiKey?.id,
|
|
@@ -298782,7 +298845,7 @@ var init_instances3 = __esm(() => {
|
|
|
298782
298845
|
plugin7.removeGuildConfig(id, guildId);
|
|
298783
298846
|
}
|
|
298784
298847
|
}
|
|
298785
|
-
|
|
298848
|
+
log102.info("Guild config deleted", {
|
|
298786
298849
|
instanceId: id,
|
|
298787
298850
|
guildId,
|
|
298788
298851
|
apiKeyId: apiKey?.id,
|
|
@@ -299418,7 +299481,7 @@ function isValidPathComponent(component) {
|
|
|
299418
299481
|
function isValidUUID(str2) {
|
|
299419
299482
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str2);
|
|
299420
299483
|
}
|
|
299421
|
-
var
|
|
299484
|
+
var log103, mediaRoutes, mediaStorage = null, ttsAudioFormatSchema, ttsRequestSchema, sttRequestSchema, imagineAspectRatioSchema, imagineRequestSchema, visionRequestSchema, filmAspectRatioSchema, filmRequestSchema, FILM_TIMEOUT_MS, FILM_POLL_INTERVAL_MS = 5000;
|
|
299422
299485
|
var init_media = __esm(() => {
|
|
299423
299486
|
init_dist6();
|
|
299424
299487
|
init_src();
|
|
@@ -299426,7 +299489,7 @@ var init_media = __esm(() => {
|
|
|
299426
299489
|
init_zod();
|
|
299427
299490
|
init_registry3();
|
|
299428
299491
|
init_media_storage();
|
|
299429
|
-
|
|
299492
|
+
log103 = createLogger("routes:media");
|
|
299430
299493
|
mediaRoutes = new Hono2;
|
|
299431
299494
|
ttsAudioFormatSchema = exports_external.enum(["mp3", "ogg", "opus", "wav", "pcm", "flac", "aac"]);
|
|
299432
299495
|
ttsRequestSchema = exports_external.object({
|
|
@@ -299445,7 +299508,7 @@ var init_media = __esm(() => {
|
|
|
299445
299508
|
provider = await providerRegistry.resolve("tts", body.provider);
|
|
299446
299509
|
} catch (err) {
|
|
299447
299510
|
const message2 = err instanceof Error ? err.message : "Unknown error";
|
|
299448
|
-
|
|
299511
|
+
log103.warn("TTS provider resolution failed", { provider: body.provider, error: message2 });
|
|
299449
299512
|
return c.json({
|
|
299450
299513
|
error: {
|
|
299451
299514
|
code: "PROVIDER_NOT_AVAILABLE",
|
|
@@ -299473,7 +299536,7 @@ var init_media = __esm(() => {
|
|
|
299473
299536
|
});
|
|
299474
299537
|
} catch (err) {
|
|
299475
299538
|
const message2 = err instanceof Error ? err.message : "Unknown error";
|
|
299476
|
-
|
|
299539
|
+
log103.error("TTS synthesis failed", { provider: provider.name, error: message2 });
|
|
299477
299540
|
return c.json({
|
|
299478
299541
|
error: {
|
|
299479
299542
|
code: "TTS_SYNTHESIS_FAILED",
|
|
@@ -299498,7 +299561,7 @@ var init_media = __esm(() => {
|
|
|
299498
299561
|
provider = await providerRegistry.resolve("stt", body.provider);
|
|
299499
299562
|
} catch (err) {
|
|
299500
299563
|
const message2 = err instanceof Error ? err.message : "Unknown error";
|
|
299501
|
-
|
|
299564
|
+
log103.warn("STT provider resolution failed", { provider: body.provider, error: message2 });
|
|
299502
299565
|
return c.json({
|
|
299503
299566
|
error: {
|
|
299504
299567
|
code: "PROVIDER_NOT_AVAILABLE",
|
|
@@ -299539,7 +299602,7 @@ var init_media = __esm(() => {
|
|
|
299539
299602
|
});
|
|
299540
299603
|
} catch (err) {
|
|
299541
299604
|
const message2 = err instanceof Error ? err.message : "Unknown error";
|
|
299542
|
-
|
|
299605
|
+
log103.error("STT transcription failed", { provider: provider.name, error: message2 });
|
|
299543
299606
|
return c.json({
|
|
299544
299607
|
error: {
|
|
299545
299608
|
code: "STT_TRANSCRIPTION_FAILED",
|
|
@@ -299567,7 +299630,7 @@ var init_media = __esm(() => {
|
|
|
299567
299630
|
provider = await providerRegistry.resolve("imagegen", body.provider);
|
|
299568
299631
|
} catch (err) {
|
|
299569
299632
|
const message2 = err instanceof Error ? err.message : "Unknown error";
|
|
299570
|
-
|
|
299633
|
+
log103.warn("Imagegen provider resolution failed", { provider: body.provider, error: message2 });
|
|
299571
299634
|
return c.json({
|
|
299572
299635
|
error: {
|
|
299573
299636
|
code: "PROVIDER_NOT_AVAILABLE",
|
|
@@ -299601,7 +299664,7 @@ var init_media = __esm(() => {
|
|
|
299601
299664
|
});
|
|
299602
299665
|
} catch (err) {
|
|
299603
299666
|
const message2 = err instanceof Error ? err.message : "Unknown error";
|
|
299604
|
-
|
|
299667
|
+
log103.error("Image generation failed", { provider: provider.name, error: message2 });
|
|
299605
299668
|
return c.json({
|
|
299606
299669
|
error: {
|
|
299607
299670
|
code: "IMAGE_GEN_FAILED",
|
|
@@ -299626,7 +299689,7 @@ var init_media = __esm(() => {
|
|
|
299626
299689
|
provider = await providerRegistry.resolve("vision", body.provider);
|
|
299627
299690
|
} catch (err) {
|
|
299628
299691
|
const message2 = err instanceof Error ? err.message : "Unknown error";
|
|
299629
|
-
|
|
299692
|
+
log103.warn("Vision provider resolution failed", { provider: body.provider, error: message2 });
|
|
299630
299693
|
return c.json({
|
|
299631
299694
|
error: {
|
|
299632
299695
|
code: "PROVIDER_NOT_AVAILABLE",
|
|
@@ -299665,7 +299728,7 @@ var init_media = __esm(() => {
|
|
|
299665
299728
|
});
|
|
299666
299729
|
} catch (err) {
|
|
299667
299730
|
const message2 = err instanceof Error ? err.message : "Unknown error";
|
|
299668
|
-
|
|
299731
|
+
log103.error("Vision description failed", { provider: provider.name, error: message2 });
|
|
299669
299732
|
return c.json({
|
|
299670
299733
|
error: {
|
|
299671
299734
|
code: "VISION_DESCRIBE_FAILED",
|
|
@@ -299693,7 +299756,7 @@ var init_media = __esm(() => {
|
|
|
299693
299756
|
provider = await providerRegistry.resolve("videogen", body.provider);
|
|
299694
299757
|
} catch (err) {
|
|
299695
299758
|
const message2 = err instanceof Error ? err.message : "Unknown error";
|
|
299696
|
-
|
|
299759
|
+
log103.warn("Videogen provider resolution failed", { provider: body.provider, error: message2 });
|
|
299697
299760
|
return c.json({
|
|
299698
299761
|
error: {
|
|
299699
299762
|
code: "PROVIDER_NOT_AVAILABLE",
|
|
@@ -299727,7 +299790,7 @@ var init_media = __esm(() => {
|
|
|
299727
299790
|
}
|
|
299728
299791
|
if (operation.state === "failed" || !operation.video) {
|
|
299729
299792
|
const message2 = operation.error ?? "Video generation failed without error";
|
|
299730
|
-
|
|
299793
|
+
log103.error("Videogen operation failed", { provider: provider.name, error: message2 });
|
|
299731
299794
|
return c.json({
|
|
299732
299795
|
error: {
|
|
299733
299796
|
code: "VIDEO_GEN_FAILED",
|
|
@@ -299738,7 +299801,7 @@ var init_media = __esm(() => {
|
|
|
299738
299801
|
}, 500);
|
|
299739
299802
|
}
|
|
299740
299803
|
const video = operation.video;
|
|
299741
|
-
|
|
299804
|
+
log103.info("Videogen operation complete", {
|
|
299742
299805
|
provider: provider.name,
|
|
299743
299806
|
operationId: operation.operationId,
|
|
299744
299807
|
sizeBytes: video.data.length,
|
|
@@ -299757,7 +299820,7 @@ var init_media = __esm(() => {
|
|
|
299757
299820
|
});
|
|
299758
299821
|
} catch (err) {
|
|
299759
299822
|
const message2 = err instanceof Error ? err.message : "Unknown error";
|
|
299760
|
-
|
|
299823
|
+
log103.error("Videogen request failed", { provider: provider.name, error: message2 });
|
|
299761
299824
|
return c.json({
|
|
299762
299825
|
error: {
|
|
299763
299826
|
code: "VIDEO_GEN_FAILED",
|
|
@@ -299964,7 +300027,7 @@ async function verifyMessageInstanceOwnership(services, message2, instanceId) {
|
|
|
299964
300027
|
});
|
|
299965
300028
|
}
|
|
299966
300029
|
}
|
|
299967
|
-
var
|
|
300030
|
+
var log104, mediaDownloadLog, messagesRoutes, UUID_REGEX, MessageSourceSchema, MessageTypeSchema, MessageStatusSchema, DeliveryStatusSchema, listQuerySchema13, createMessageSchema, updateMessageSchema, recordEditSchema, addReactionSchema, removeReactionSchema, updateDeliveryStatusSchema, MentionSchema, sendTextSchema, sendMediaSchema, sendReactionSchema, sendStickerSchema, sendContactSchema, sendLocationSchema, sendHandoffSchema, messageRefSchema, _mediaStorageForDownload = null, sendTtsSchema, forwardMessageSchema, sendPresenceSchema, markMessageReadSchema, markBatchReadSchema, sendPollSchema, sendEmbedSchema, editMessageChannelSchema, deleteMessageChannelSchema, starMessageSchema;
|
|
299968
300031
|
var init_messages5 = __esm(() => {
|
|
299969
300032
|
init_dist6();
|
|
299970
300033
|
init_src2();
|
|
@@ -299977,7 +300040,7 @@ var init_messages5 = __esm(() => {
|
|
|
299977
300040
|
init_date_query();
|
|
299978
300041
|
init_api_keys();
|
|
299979
300042
|
init_media_storage();
|
|
299980
|
-
|
|
300043
|
+
log104 = createLogger("routes:messages");
|
|
299981
300044
|
mediaDownloadLog = createLogger("routes:messages:media-download");
|
|
299982
300045
|
messagesRoutes = new Hono2;
|
|
299983
300046
|
UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
@@ -300539,7 +300602,7 @@ var init_messages5 = __esm(() => {
|
|
|
300539
300602
|
reactionMetadata.targetParticipant = participant;
|
|
300540
300603
|
}
|
|
300541
300604
|
} else {
|
|
300542
|
-
|
|
300605
|
+
log104.warn("Reaction target message not found in DB; deferring fromMe to channel plugin fallback (#386)", {
|
|
300543
300606
|
instanceId,
|
|
300544
300607
|
chatId: chat2.id,
|
|
300545
300608
|
messageId,
|
|
@@ -300547,7 +300610,7 @@ var init_messages5 = __esm(() => {
|
|
|
300547
300610
|
});
|
|
300548
300611
|
}
|
|
300549
300612
|
} else {
|
|
300550
|
-
|
|
300613
|
+
log104.warn("Reaction target chat not found in DB; deferring fromMe to channel plugin fallback (#386)", {
|
|
300551
300614
|
instanceId,
|
|
300552
300615
|
resolvedTo,
|
|
300553
300616
|
messageId,
|
|
@@ -300847,7 +300910,7 @@ var init_messages5 = __esm(() => {
|
|
|
300847
300910
|
channelHandoffSupported: hasNativeHandoff,
|
|
300848
300911
|
...data.motivoHandoff ? { motivoHandoff: data.motivoHandoff } : {}
|
|
300849
300912
|
}
|
|
300850
|
-
}).catch((err) =>
|
|
300913
|
+
}).catch((err) => log104.warn("Failed to persist handoff log", { error: String(err) }));
|
|
300851
300914
|
return c.json({
|
|
300852
300915
|
data: {
|
|
300853
300916
|
messageId: channelSendResult?.messageId ?? null,
|
|
@@ -301363,7 +301426,7 @@ var init_messages5 = __esm(() => {
|
|
|
301363
301426
|
const message2 = await services.messages.getById(messageId);
|
|
301364
301427
|
await verifyMessageInstanceOwnership(services, message2, instanceId);
|
|
301365
301428
|
resolvedMessageId = message2.externalId;
|
|
301366
|
-
|
|
301429
|
+
log104.debug("Resolved internal UUID to external ID", { messageId, externalId: resolvedMessageId });
|
|
301367
301430
|
}
|
|
301368
301431
|
try {
|
|
301369
301432
|
await plugin7.editMessage(instanceId, channelId, resolvedMessageId, text3);
|
|
@@ -302063,6 +302126,36 @@ var init_settings3 = __esm(() => {
|
|
|
302063
302126
|
});
|
|
302064
302127
|
});
|
|
302065
302128
|
|
|
302129
|
+
// ../api/src/routes/v2/trust.ts
|
|
302130
|
+
var trustRoutes, PUBKEY_PATTERN, handshakeSchema;
|
|
302131
|
+
var init_trust = __esm(() => {
|
|
302132
|
+
init_dist6();
|
|
302133
|
+
init_dist2();
|
|
302134
|
+
init_zod();
|
|
302135
|
+
trustRoutes = new Hono2;
|
|
302136
|
+
PUBKEY_PATTERN = /^[A-Za-z0-9_-]{43}=?$/;
|
|
302137
|
+
handshakeSchema = exports_external.object({
|
|
302138
|
+
pubkey: exports_external.string().regex(PUBKEY_PATTERN, "pubkey must be base64url-encoded 32 bytes (ed25519 public key)"),
|
|
302139
|
+
hostname: exports_external.string().min(1).max(255),
|
|
302140
|
+
capabilities: exports_external.record(exports_external.unknown()).optional()
|
|
302141
|
+
});
|
|
302142
|
+
trustRoutes.post("/handshake", zValidator("json", handshakeSchema), async (c) => {
|
|
302143
|
+
const input = c.req.valid("json");
|
|
302144
|
+
const services = c.get("services");
|
|
302145
|
+
const existing = await services.genieHosts.findByPubkey(input.pubkey);
|
|
302146
|
+
if (existing) {
|
|
302147
|
+
return c.json({ data: existing }, 200);
|
|
302148
|
+
}
|
|
302149
|
+
const host = await services.genieHosts.register(input);
|
|
302150
|
+
return c.json({ data: host }, 201);
|
|
302151
|
+
});
|
|
302152
|
+
trustRoutes.get("/hosts", async (c) => {
|
|
302153
|
+
const services = c.get("services");
|
|
302154
|
+
const items = await services.genieHosts.listActive();
|
|
302155
|
+
return c.json({ items });
|
|
302156
|
+
});
|
|
302157
|
+
});
|
|
302158
|
+
|
|
302066
302159
|
// ../api/src/routes/v2/turns.ts
|
|
302067
302160
|
function requireAdmin(c) {
|
|
302068
302161
|
const keyData = c.get("apiKey");
|
|
@@ -302525,6 +302618,7 @@ var init_v2 = __esm(() => {
|
|
|
302525
302618
|
init_processed_events();
|
|
302526
302619
|
init_providers4();
|
|
302527
302620
|
init_settings3();
|
|
302621
|
+
init_trust();
|
|
302528
302622
|
init_turns2();
|
|
302529
302623
|
init_voice2();
|
|
302530
302624
|
init_webhooks3();
|
|
@@ -302553,6 +302647,7 @@ var init_v2 = __esm(() => {
|
|
|
302553
302647
|
v2Routes.route("/keys", keysRoutes);
|
|
302554
302648
|
v2Routes.route("/context", contextRoutes);
|
|
302555
302649
|
v2Routes.route("/turns", turnsRoutes);
|
|
302650
|
+
v2Routes.route("/trust", trustRoutes);
|
|
302556
302651
|
v2Routes.route("/", payloadsRoutes);
|
|
302557
302652
|
v2Routes.route("/", webhooksRoutes);
|
|
302558
302653
|
v2Routes.route("/automations", automationsRoutes);
|
|
@@ -303024,12 +303119,12 @@ async function setupEventPersistence(eventBus, db2) {
|
|
|
303024
303119
|
const tracker = getJourneyTracker();
|
|
303025
303120
|
tracker.recordCheckpoint(metadata.correlationId, "T4", JOURNEY_STAGES.T4);
|
|
303026
303121
|
}
|
|
303027
|
-
|
|
303122
|
+
log105.debug("Persisted message.received", {
|
|
303028
303123
|
externalId: payload.externalId,
|
|
303029
303124
|
instanceId: metadata.instanceId
|
|
303030
303125
|
});
|
|
303031
303126
|
} catch (error2) {
|
|
303032
|
-
|
|
303127
|
+
log105.error("Failed to persist message.received", {
|
|
303033
303128
|
externalId: payload.externalId,
|
|
303034
303129
|
error: String(error2)
|
|
303035
303130
|
});
|
|
@@ -303066,12 +303161,12 @@ async function setupEventPersistence(eventBus, db2) {
|
|
|
303066
303161
|
chatUuid
|
|
303067
303162
|
};
|
|
303068
303163
|
await db2.insert(omniEvents).values(newEvent).onConflictDoNothing({ target: omniEvents.id });
|
|
303069
|
-
|
|
303164
|
+
log105.debug("Persisted message.sent", {
|
|
303070
303165
|
externalId: payload.externalId,
|
|
303071
303166
|
instanceId: metadata.instanceId
|
|
303072
303167
|
});
|
|
303073
303168
|
} catch (error2) {
|
|
303074
|
-
|
|
303169
|
+
log105.error("Failed to persist message.sent", {
|
|
303075
303170
|
externalId: payload.externalId,
|
|
303076
303171
|
error: String(error2)
|
|
303077
303172
|
});
|
|
@@ -303104,11 +303199,11 @@ async function setupEventPersistence(eventBus, db2) {
|
|
|
303104
303199
|
};
|
|
303105
303200
|
await db2.insert(omniEvents).values(newEvent).onConflictDoNothing({ target: omniEvents.id });
|
|
303106
303201
|
}
|
|
303107
|
-
|
|
303202
|
+
log105.debug("Persisted message.delivered", {
|
|
303108
303203
|
externalId: payload.externalId
|
|
303109
303204
|
});
|
|
303110
303205
|
} catch (error2) {
|
|
303111
|
-
|
|
303206
|
+
log105.error("Failed to persist message.delivered", {
|
|
303112
303207
|
externalId: payload.externalId,
|
|
303113
303208
|
error: String(error2)
|
|
303114
303209
|
});
|
|
@@ -303140,11 +303235,11 @@ async function setupEventPersistence(eventBus, db2) {
|
|
|
303140
303235
|
};
|
|
303141
303236
|
await db2.insert(omniEvents).values(newEvent).onConflictDoNothing({ target: omniEvents.id });
|
|
303142
303237
|
}
|
|
303143
|
-
|
|
303238
|
+
log105.debug("Persisted message.read", {
|
|
303144
303239
|
externalId: payload.externalId
|
|
303145
303240
|
});
|
|
303146
303241
|
} catch (error2) {
|
|
303147
|
-
|
|
303242
|
+
log105.error("Failed to persist message.read", {
|
|
303148
303243
|
externalId: payload.externalId,
|
|
303149
303244
|
error: String(error2)
|
|
303150
303245
|
});
|
|
@@ -303177,29 +303272,29 @@ async function setupEventPersistence(eventBus, db2) {
|
|
|
303177
303272
|
chatUuid
|
|
303178
303273
|
};
|
|
303179
303274
|
await db2.insert(omniEvents).values(newEvent).onConflictDoNothing({ target: omniEvents.id });
|
|
303180
|
-
|
|
303275
|
+
log105.debug("Persisted message.failed", {
|
|
303181
303276
|
chatId: payload.chatId,
|
|
303182
303277
|
error: payload.error
|
|
303183
303278
|
});
|
|
303184
303279
|
} catch (error2) {
|
|
303185
|
-
|
|
303280
|
+
log105.error("Failed to persist message.failed", {
|
|
303186
303281
|
chatId: payload.chatId,
|
|
303187
303282
|
error: String(error2)
|
|
303188
303283
|
});
|
|
303189
303284
|
}
|
|
303190
303285
|
}, { ...CONSUMER_OPTIONS, durable: "event-persistence-failed" });
|
|
303191
|
-
|
|
303286
|
+
log105.info("Event persistence initialized - listening for message events");
|
|
303192
303287
|
} catch (error2) {
|
|
303193
|
-
|
|
303288
|
+
log105.error("Failed to set up event persistence", { error: String(error2) });
|
|
303194
303289
|
throw error2;
|
|
303195
303290
|
}
|
|
303196
303291
|
}
|
|
303197
|
-
var
|
|
303292
|
+
var log105, CONSUMER_OPTIONS;
|
|
303198
303293
|
var init_event_persistence = __esm(() => {
|
|
303199
303294
|
init_src();
|
|
303200
303295
|
init_src5();
|
|
303201
303296
|
init_drizzle_orm();
|
|
303202
|
-
|
|
303297
|
+
log105 = createLogger("event-persistence");
|
|
303203
303298
|
CONSUMER_OPTIONS = {
|
|
303204
303299
|
queue: "event-persistence",
|
|
303205
303300
|
maxRetries: 3,
|
|
@@ -303277,10 +303372,10 @@ async function downloadMediaFromUrl(ctx, instanceId, messageId, mediaUrl, mimeTy
|
|
|
303277
303372
|
try {
|
|
303278
303373
|
const result = await ctx.mediaStorage.storeFromUrl(instanceId, messageId, mediaUrl, mimeType, platformTimestamp, fetchOptions);
|
|
303279
303374
|
await ctx.mediaStorage.updateMessageLocalPath(messageId, result.localPath);
|
|
303280
|
-
|
|
303375
|
+
log106.debug("Downloaded media from URL", { messageId, filePath: result.localPath });
|
|
303281
303376
|
return result.localPath;
|
|
303282
303377
|
} catch (error2) {
|
|
303283
|
-
|
|
303378
|
+
log106.error("Failed to download media", { error: String(error2), mediaUrl });
|
|
303284
303379
|
return null;
|
|
303285
303380
|
}
|
|
303286
303381
|
}
|
|
@@ -303294,7 +303389,7 @@ async function resolveMediaPath2(ctx, instanceId, chatId, externalId, content, m
|
|
|
303294
303389
|
chat2 = await ctx.services.chats.findByExternalIdSmart(instanceId, chatId);
|
|
303295
303390
|
}
|
|
303296
303391
|
if (!chat2) {
|
|
303297
|
-
|
|
303392
|
+
log106.debug("Chat not found, cannot process media", { chatId, externalId });
|
|
303298
303393
|
return null;
|
|
303299
303394
|
}
|
|
303300
303395
|
let message2 = await ctx.services.messages.getByExternalId(chat2.id, externalId);
|
|
@@ -303303,7 +303398,7 @@ async function resolveMediaPath2(ctx, instanceId, chatId, externalId, content, m
|
|
|
303303
303398
|
message2 = await ctx.services.messages.getByExternalId(chat2.id, externalId);
|
|
303304
303399
|
}
|
|
303305
303400
|
if (!message2) {
|
|
303306
|
-
|
|
303401
|
+
log106.debug("Message not found after waiting, cannot process media", { externalId });
|
|
303307
303402
|
return null;
|
|
303308
303403
|
}
|
|
303309
303404
|
let filePath = message2.mediaLocalPath;
|
|
@@ -303313,7 +303408,7 @@ async function resolveMediaPath2(ctx, instanceId, chatId, externalId, content, m
|
|
|
303313
303408
|
return null;
|
|
303314
303409
|
}
|
|
303315
303410
|
if (!filePath) {
|
|
303316
|
-
|
|
303411
|
+
log106.debug("No media file path available", { externalId });
|
|
303317
303412
|
return null;
|
|
303318
303413
|
}
|
|
303319
303414
|
return {
|
|
@@ -303334,11 +303429,11 @@ async function resolveSafeMediaContentEventId(ctx, eventId) {
|
|
|
303334
303429
|
if (event)
|
|
303335
303430
|
return event.id;
|
|
303336
303431
|
} catch (error2) {
|
|
303337
|
-
|
|
303432
|
+
log106.debug("Failed to validate media_content event FK", { eventId, error: String(error2) });
|
|
303338
303433
|
return null;
|
|
303339
303434
|
}
|
|
303340
303435
|
if (Date.now() >= deadline) {
|
|
303341
|
-
|
|
303436
|
+
log106.debug("Skipping media_content event FK; omni_event not found", { eventId });
|
|
303342
303437
|
return null;
|
|
303343
303438
|
}
|
|
303344
303439
|
await new Promise((resolve4) => setTimeout(resolve4, pollMs));
|
|
@@ -303367,7 +303462,7 @@ async function persistProcessingResult(ctx, messageId, eventId, result, contentT
|
|
|
303367
303462
|
processingTimeMs: result.processingTimeMs
|
|
303368
303463
|
});
|
|
303369
303464
|
} catch (error2) {
|
|
303370
|
-
|
|
303465
|
+
log106.warn("Failed to insert media_content record (non-critical)", {
|
|
303371
303466
|
messageId,
|
|
303372
303467
|
error: String(error2)
|
|
303373
303468
|
});
|
|
@@ -303387,13 +303482,13 @@ async function processMessageMedia(ctx, payload, metadata) {
|
|
|
303387
303482
|
const { content, externalId } = payload;
|
|
303388
303483
|
const mimeType = getMimeType2(content);
|
|
303389
303484
|
if (!mimeType || !ctx.mediaService.canProcess(mimeType)) {
|
|
303390
|
-
|
|
303485
|
+
log106.debug("MIME type not processable or missing", { mimeType, externalId });
|
|
303391
303486
|
return;
|
|
303392
303487
|
}
|
|
303393
303488
|
const media = await resolveMediaPath2(ctx, instanceId, payload.chatId, externalId, content, mimeType, metadata.channelType);
|
|
303394
303489
|
if (!media)
|
|
303395
303490
|
return;
|
|
303396
|
-
|
|
303491
|
+
log106.info("Processing media", { messageId: media.messageId, mimeType, filePath: media.fullPath });
|
|
303397
303492
|
const result = await ctx.mediaService.process(media.fullPath, mimeType, {
|
|
303398
303493
|
language: "pt",
|
|
303399
303494
|
caption: content.text,
|
|
@@ -303401,7 +303496,7 @@ async function processMessageMedia(ctx, payload, metadata) {
|
|
|
303401
303496
|
});
|
|
303402
303497
|
if (!result.success) {
|
|
303403
303498
|
const reason = result.errorMessage ?? "unknown";
|
|
303404
|
-
|
|
303499
|
+
log106.warn("Media processing failed", { messageId: media.messageId, error: reason });
|
|
303405
303500
|
const processingType = result.processingType ?? inferProcessingType(content.type);
|
|
303406
303501
|
const errorColumn = getContentFieldForType(processingType, content.type);
|
|
303407
303502
|
if (errorColumn) {
|
|
@@ -303426,7 +303521,7 @@ async function processMessageMedia(ctx, payload, metadata) {
|
|
|
303426
303521
|
return;
|
|
303427
303522
|
}
|
|
303428
303523
|
await persistProcessingResult(ctx, media.messageId, eventId, result, content.type);
|
|
303429
|
-
|
|
303524
|
+
log106.info("Media processing complete", {
|
|
303430
303525
|
messageId: media.messageId,
|
|
303431
303526
|
processingType: result.processingType,
|
|
303432
303527
|
provider: result.provider,
|
|
@@ -303466,7 +303561,7 @@ async function publishMediaCrashEvents(ctx, eventId, payload, metadata, error2)
|
|
|
303466
303561
|
error: reason
|
|
303467
303562
|
}, meta);
|
|
303468
303563
|
} catch (publishError) {
|
|
303469
|
-
|
|
303564
|
+
log106.error("Failed to publish media failure event", { error: String(publishError) });
|
|
303470
303565
|
}
|
|
303471
303566
|
}
|
|
303472
303567
|
async function resolveMediaIdForCrash(ctx, instanceId, payload) {
|
|
@@ -303478,7 +303573,7 @@ async function resolveMediaIdForCrash(ctx, instanceId, payload) {
|
|
|
303478
303573
|
return msg.id;
|
|
303479
303574
|
}
|
|
303480
303575
|
} catch (lookupError) {
|
|
303481
|
-
|
|
303576
|
+
log106.debug("Failed to resolve DB message UUID for crash handler, falling back to externalId", {
|
|
303482
303577
|
error: String(lookupError),
|
|
303483
303578
|
instanceId,
|
|
303484
303579
|
chatId: payload.chatId
|
|
@@ -303529,7 +303624,7 @@ async function setupMediaProcessor(eventBus, db2, services) {
|
|
|
303529
303624
|
channelType: metadata.channelType
|
|
303530
303625
|
});
|
|
303531
303626
|
} catch (error2) {
|
|
303532
|
-
|
|
303627
|
+
log106.error("Failed to process media", {
|
|
303533
303628
|
externalId: payload.externalId,
|
|
303534
303629
|
error: String(error2)
|
|
303535
303630
|
});
|
|
@@ -303544,14 +303639,14 @@ async function setupMediaProcessor(eventBus, db2, services) {
|
|
|
303544
303639
|
concurrency: 5
|
|
303545
303640
|
});
|
|
303546
303641
|
setGlobalCircuitBreakerStateChangeCallback((name, from, to) => {
|
|
303547
|
-
|
|
303642
|
+
log106.warn("Circuit breaker state change", { provider: name, from, to });
|
|
303548
303643
|
});
|
|
303549
303644
|
await eventBus.subscribePattern("media.health.request", async (event) => {
|
|
303550
303645
|
const tracker = getMediaHealthTracker();
|
|
303551
303646
|
const report = tracker.getReport();
|
|
303552
303647
|
const correlationId = event.metadata?.correlationId ?? event.id;
|
|
303553
303648
|
await eventBus.publishGeneric("system.media.health.response", { correlationId, report }, { source: "media-processor" });
|
|
303554
|
-
|
|
303649
|
+
log106.debug("Published media health report", {
|
|
303555
303650
|
correlationId,
|
|
303556
303651
|
totalRequests: report.overall.totalRequests,
|
|
303557
303652
|
successRate: report.overall.successRate
|
|
@@ -303560,16 +303655,16 @@ async function setupMediaProcessor(eventBus, db2, services) {
|
|
|
303560
303655
|
durable: "media-health-responder",
|
|
303561
303656
|
queue: "media-health-responder"
|
|
303562
303657
|
});
|
|
303563
|
-
|
|
303658
|
+
log106.info("Media processor initialized");
|
|
303564
303659
|
}
|
|
303565
|
-
var
|
|
303660
|
+
var log106, PROCESSABLE_MEDIA_TYPES;
|
|
303566
303661
|
var init_media_processor = __esm(() => {
|
|
303567
303662
|
init_src();
|
|
303568
303663
|
init_src5();
|
|
303569
303664
|
init_src7();
|
|
303570
303665
|
init_drizzle_orm();
|
|
303571
303666
|
init_media_storage();
|
|
303572
|
-
|
|
303667
|
+
log106 = createLogger("media-processor");
|
|
303573
303668
|
PROCESSABLE_MEDIA_TYPES = new Set(["audio", "image", "document", "video"]);
|
|
303574
303669
|
});
|
|
303575
303670
|
|
|
@@ -303641,7 +303736,7 @@ async function setupSyncWorker(eventBus, services, channelRegistry2, database) {
|
|
|
303641
303736
|
await eventBus.subscribe("sync.started", async (event) => {
|
|
303642
303737
|
const payload = event.payload;
|
|
303643
303738
|
const { jobId, instanceId, type, config: config4 } = payload;
|
|
303644
|
-
|
|
303739
|
+
log107.info("Processing sync job", { jobId, instanceId, type });
|
|
303645
303740
|
try {
|
|
303646
303741
|
await services.syncJobs.start(jobId);
|
|
303647
303742
|
const instance4 = await services.instances.getById(instanceId);
|
|
@@ -303668,12 +303763,12 @@ async function setupSyncWorker(eventBus, services, channelRegistry2, database) {
|
|
|
303668
303763
|
case "history-push":
|
|
303669
303764
|
break;
|
|
303670
303765
|
default:
|
|
303671
|
-
|
|
303766
|
+
log107.warn("Unknown sync type", { jobId, type });
|
|
303672
303767
|
await services.syncJobs.fail(jobId, `Unknown sync type: ${type}`);
|
|
303673
303768
|
}
|
|
303674
303769
|
} catch (error2) {
|
|
303675
303770
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
303676
|
-
|
|
303771
|
+
log107.error("Sync job failed", { jobId, error: errorMessage });
|
|
303677
303772
|
await services.syncJobs.fail(jobId, errorMessage);
|
|
303678
303773
|
}
|
|
303679
303774
|
}, {
|
|
@@ -303681,15 +303776,15 @@ async function setupSyncWorker(eventBus, services, channelRegistry2, database) {
|
|
|
303681
303776
|
queue: "sync-workers",
|
|
303682
303777
|
startFrom: "new"
|
|
303683
303778
|
});
|
|
303684
|
-
|
|
303779
|
+
log107.info("Sync worker initialized - listening for sync.started events");
|
|
303685
303780
|
} catch (error2) {
|
|
303686
|
-
|
|
303781
|
+
log107.error("Failed to set up sync worker", { error: String(error2) });
|
|
303687
303782
|
throw error2;
|
|
303688
303783
|
}
|
|
303689
303784
|
}
|
|
303690
303785
|
async function buildWhatsAppAnchors(instanceId, _services) {
|
|
303691
303786
|
if (!db2) {
|
|
303692
|
-
|
|
303787
|
+
log107.warn("Database not available for building anchors");
|
|
303693
303788
|
return [];
|
|
303694
303789
|
}
|
|
303695
303790
|
const result = await db2.execute(sql`
|
|
@@ -303725,20 +303820,20 @@ async function buildWhatsAppAnchors(instanceId, _services) {
|
|
|
303725
303820
|
});
|
|
303726
303821
|
}
|
|
303727
303822
|
}
|
|
303728
|
-
|
|
303823
|
+
log107.info("Built WhatsApp anchors", { instanceId, anchorCount: anchors.length });
|
|
303729
303824
|
return anchors;
|
|
303730
303825
|
}
|
|
303731
303826
|
function buildAnchorsForExplicitChatJids(jobId, chatJids, dbAnchors) {
|
|
303732
|
-
|
|
303827
|
+
log107.info("Using explicit chatJids for sync", { jobId, chatJids });
|
|
303733
303828
|
const anchors = [];
|
|
303734
303829
|
for (const jid of chatJids) {
|
|
303735
303830
|
const dbAnchor = dbAnchors.find((a3) => a3.chatJid === jid);
|
|
303736
303831
|
if (dbAnchor) {
|
|
303737
|
-
|
|
303832
|
+
log107.debug("Found DB anchor for chatJid", { jobId, chatJid: jid, anchorId: dbAnchor.messageKey.id });
|
|
303738
303833
|
anchors.push(dbAnchor);
|
|
303739
303834
|
continue;
|
|
303740
303835
|
}
|
|
303741
|
-
|
|
303836
|
+
log107.debug("No DB anchor for chatJid, will fetch recent", { jobId, chatJid: jid });
|
|
303742
303837
|
anchors.push({
|
|
303743
303838
|
chatJid: jid,
|
|
303744
303839
|
messageKey: { remoteJid: jid, id: "", fromMe: false },
|
|
@@ -303764,7 +303859,7 @@ async function discoverAnchorsFromPlugin(jobId, instanceId, plugin7, dbAnchors,
|
|
|
303764
303859
|
discovered.push({ chatJid: jid, messageKey: { remoteJid: jid, id: "", fromMe: false }, timestamp: Date.now() });
|
|
303765
303860
|
}
|
|
303766
303861
|
if (discovered.length > 0) {
|
|
303767
|
-
|
|
303862
|
+
log107.info("Discovered chats from DB + Baileys not in anchors", {
|
|
303768
303863
|
jobId,
|
|
303769
303864
|
discoveredCount: discovered.length,
|
|
303770
303865
|
fromDb: dbExternalIds.length,
|
|
@@ -303785,7 +303880,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
303785
303880
|
throw new Error(`No plugin found for channel type: ${channelType}`);
|
|
303786
303881
|
}
|
|
303787
303882
|
if (!("fetchHistory" in plugin7) || typeof plugin7.fetchHistory !== "function") {
|
|
303788
|
-
|
|
303883
|
+
log107.warn("Plugin does not support fetchHistory", { channelType });
|
|
303789
303884
|
await services.syncJobs.complete(jobId);
|
|
303790
303885
|
return;
|
|
303791
303886
|
}
|
|
@@ -303794,7 +303889,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
303794
303889
|
let fetched = 0;
|
|
303795
303890
|
let stored = 0;
|
|
303796
303891
|
let duplicates = 0;
|
|
303797
|
-
|
|
303892
|
+
log107.info("Starting message sync", {
|
|
303798
303893
|
jobId,
|
|
303799
303894
|
instanceId,
|
|
303800
303895
|
channelType,
|
|
@@ -303804,13 +303899,13 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
303804
303899
|
if (channelType === "whatsapp-baileys" && config4.chatJids?.length) {
|
|
303805
303900
|
const dbAnchors = await buildWhatsAppAnchors(instanceId, services);
|
|
303806
303901
|
anchors = await resolveWhatsAppAnchors(jobId, instanceId, config4, plugin7, dbAnchors, services);
|
|
303807
|
-
|
|
303902
|
+
log107.info("WhatsApp per-chat active sync", { jobId, anchorCount: anchors.length, chatJids: config4.chatJids });
|
|
303808
303903
|
} else if (channelType === "whatsapp-baileys") {
|
|
303809
303904
|
const dbAnchors = await buildWhatsAppAnchors(instanceId, services);
|
|
303810
303905
|
const discoveredAnchors = await discoverAnchorsFromPlugin(jobId, instanceId, plugin7, dbAnchors, services);
|
|
303811
303906
|
anchors = [...dbAnchors, ...discoveredAnchors];
|
|
303812
303907
|
if (anchors.length > 0) {
|
|
303813
|
-
|
|
303908
|
+
log107.info("WhatsApp default sync with DB+cache discovery", {
|
|
303814
303909
|
jobId,
|
|
303815
303910
|
instanceId,
|
|
303816
303911
|
dbAnchorCount: dbAnchors.length,
|
|
@@ -303818,7 +303913,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
303818
303913
|
totalAnchors: anchors.length
|
|
303819
303914
|
});
|
|
303820
303915
|
} else {
|
|
303821
|
-
|
|
303916
|
+
log107.info("WhatsApp passive sync (no prior data)", { jobId, instanceId });
|
|
303822
303917
|
}
|
|
303823
303918
|
}
|
|
303824
303919
|
const fetchOptions = {
|
|
@@ -303860,7 +303955,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
303860
303955
|
});
|
|
303861
303956
|
stored++;
|
|
303862
303957
|
} catch (error2) {
|
|
303863
|
-
|
|
303958
|
+
log107.warn("Failed to store synced message", {
|
|
303864
303959
|
externalId: msg.externalId,
|
|
303865
303960
|
error: String(error2)
|
|
303866
303961
|
});
|
|
@@ -303877,7 +303972,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
303877
303972
|
duplicates
|
|
303878
303973
|
});
|
|
303879
303974
|
await services.syncJobs.complete(jobId);
|
|
303880
|
-
|
|
303975
|
+
log107.info("Message sync completed", {
|
|
303881
303976
|
jobId,
|
|
303882
303977
|
fetched,
|
|
303883
303978
|
stored,
|
|
@@ -303924,14 +304019,14 @@ async function processContactsSync(jobId, instanceId, channelType, config4, serv
|
|
|
303924
304019
|
throw new Error(`No plugin found for channel type: ${channelType}`);
|
|
303925
304020
|
}
|
|
303926
304021
|
if (!("fetchContacts" in plugin7) || typeof plugin7.fetchContacts !== "function") {
|
|
303927
|
-
|
|
304022
|
+
log107.warn("Plugin does not support fetchContacts", { channelType });
|
|
303928
304023
|
await services.syncJobs.complete(jobId);
|
|
303929
304024
|
return;
|
|
303930
304025
|
}
|
|
303931
304026
|
let fetched = 0;
|
|
303932
304027
|
let stored = 0;
|
|
303933
304028
|
let linked = 0;
|
|
303934
|
-
|
|
304029
|
+
log107.info("Starting contacts sync", {
|
|
303935
304030
|
jobId,
|
|
303936
304031
|
instanceId,
|
|
303937
304032
|
channelType
|
|
@@ -303970,7 +304065,7 @@ async function processContactsSync(jobId, instanceId, channelType, config4, serv
|
|
|
303970
304065
|
await updateDmChatName(services, instanceId, c.platformUserId, c.name);
|
|
303971
304066
|
}
|
|
303972
304067
|
} catch (error2) {
|
|
303973
|
-
|
|
304068
|
+
log107.warn("Failed to store synced contact", {
|
|
303974
304069
|
platformUserId: c.platformUserId,
|
|
303975
304070
|
error: String(error2)
|
|
303976
304071
|
});
|
|
@@ -303987,7 +304082,7 @@ async function processContactsSync(jobId, instanceId, channelType, config4, serv
|
|
|
303987
304082
|
duplicates: 0
|
|
303988
304083
|
});
|
|
303989
304084
|
await services.syncJobs.complete(jobId);
|
|
303990
|
-
|
|
304085
|
+
log107.info("Contacts sync completed", {
|
|
303991
304086
|
jobId,
|
|
303992
304087
|
fetched,
|
|
303993
304088
|
stored,
|
|
@@ -304001,7 +304096,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
|
|
|
304001
304096
|
}
|
|
304002
304097
|
const fetchMethod = channelType === "discord" ? "fetchGuilds" : "fetchGroups";
|
|
304003
304098
|
if (!(fetchMethod in plugin7) || typeof plugin7[fetchMethod] !== "function") {
|
|
304004
|
-
|
|
304099
|
+
log107.warn(`Plugin does not support ${fetchMethod}`, { channelType });
|
|
304005
304100
|
await services.syncJobs.complete(jobId);
|
|
304006
304101
|
return;
|
|
304007
304102
|
}
|
|
@@ -304012,7 +304107,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
|
|
|
304012
304107
|
let fetched = 0;
|
|
304013
304108
|
let stored = 0;
|
|
304014
304109
|
let updated = 0;
|
|
304015
|
-
|
|
304110
|
+
log107.info("Starting groups sync", {
|
|
304016
304111
|
jobId,
|
|
304017
304112
|
instanceId,
|
|
304018
304113
|
channelType
|
|
@@ -304062,7 +304157,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
|
|
|
304062
304157
|
stored++;
|
|
304063
304158
|
}
|
|
304064
304159
|
} catch (error2) {
|
|
304065
|
-
|
|
304160
|
+
log107.warn("Failed to store synced group", {
|
|
304066
304161
|
externalId: g2.externalId,
|
|
304067
304162
|
error: String(error2)
|
|
304068
304163
|
});
|
|
@@ -304103,7 +304198,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
|
|
|
304103
304198
|
stored++;
|
|
304104
304199
|
}
|
|
304105
304200
|
} catch (error2) {
|
|
304106
|
-
|
|
304201
|
+
log107.warn("Failed to store synced guild", {
|
|
304107
304202
|
externalId: g2.externalId,
|
|
304108
304203
|
error: String(error2)
|
|
304109
304204
|
});
|
|
@@ -304118,7 +304213,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
|
|
|
304118
304213
|
duplicates: updated
|
|
304119
304214
|
});
|
|
304120
304215
|
await services.syncJobs.complete(jobId);
|
|
304121
|
-
|
|
304216
|
+
log107.info("Groups sync completed", {
|
|
304122
304217
|
jobId,
|
|
304123
304218
|
fetched,
|
|
304124
304219
|
stored,
|
|
@@ -304235,12 +304330,12 @@ async function setupHistoryPushTracker(eventBus, services) {
|
|
|
304235
304330
|
throw error2;
|
|
304236
304331
|
}
|
|
304237
304332
|
}
|
|
304238
|
-
var
|
|
304333
|
+
var log107, RATE_LIMITS2, db2 = null, historyPushLog;
|
|
304239
304334
|
var init_sync_worker = __esm(() => {
|
|
304240
304335
|
init_src();
|
|
304241
304336
|
init_src5();
|
|
304242
304337
|
init_drizzle_orm();
|
|
304243
|
-
|
|
304338
|
+
log107 = createLogger("sync-worker");
|
|
304244
304339
|
RATE_LIMITS2 = {
|
|
304245
304340
|
"whatsapp-baileys": 30,
|
|
304246
304341
|
discord: 50,
|
|
@@ -304255,7 +304350,7 @@ async function resolveChatId2(services, instanceId, externalId) {
|
|
|
304255
304350
|
const chat2 = await services.chats.findByExternalIdSmart(instanceId, externalId);
|
|
304256
304351
|
return chat2?.id ?? null;
|
|
304257
304352
|
} catch (err) {
|
|
304258
|
-
|
|
304353
|
+
log108.warn("follow-up-hooks: failed to resolve chatId", { instanceId, externalId, error: String(err) });
|
|
304259
304354
|
return null;
|
|
304260
304355
|
}
|
|
304261
304356
|
}
|
|
@@ -304344,15 +304439,15 @@ async function setupFollowUpHooks(eventBus, services) {
|
|
|
304344
304439
|
retryDelayMs: 500,
|
|
304345
304440
|
startFrom: "new"
|
|
304346
304441
|
});
|
|
304347
|
-
|
|
304442
|
+
log108.info("Follow-up hooks active (message.sent/received, chat.handoff_activated, chat.archived)");
|
|
304348
304443
|
} catch (error2) {
|
|
304349
|
-
|
|
304444
|
+
log108.error("Failed to set up follow-up hooks", { error: String(error2) });
|
|
304350
304445
|
}
|
|
304351
304446
|
}
|
|
304352
|
-
var
|
|
304447
|
+
var log108;
|
|
304353
304448
|
var init_follow_up_hooks = __esm(() => {
|
|
304354
304449
|
init_src();
|
|
304355
|
-
|
|
304450
|
+
log108 = createLogger("follow-up-hooks");
|
|
304356
304451
|
});
|
|
304357
304452
|
|
|
304358
304453
|
// ../api/src/plugins/instance-monitor.ts
|
|
@@ -304792,7 +304887,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
304792
304887
|
recordScheduledJob("dead-letter-auto-retry", "success", durationSec);
|
|
304793
304888
|
const pendingCount = await services.deadLetters.getPendingCount();
|
|
304794
304889
|
deadLettersPending.set(pendingCount);
|
|
304795
|
-
|
|
304890
|
+
log109.info("Dead letter auto-retry completed", result);
|
|
304796
304891
|
} catch (err) {
|
|
304797
304892
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304798
304893
|
recordScheduledJob("dead-letter-auto-retry", "failure", durationSec);
|
|
@@ -304814,7 +304909,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
304814
304909
|
recordScheduledJob("payload-cleanup", "success", durationSec);
|
|
304815
304910
|
const stats = await services.payloadStore.getStats();
|
|
304816
304911
|
payloadStorageSize.set(stats.totalSizeCompressed);
|
|
304817
|
-
|
|
304912
|
+
log109.info("Payload cleanup completed", { deleted });
|
|
304818
304913
|
} catch (err) {
|
|
304819
304914
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304820
304915
|
recordScheduledJob("payload-cleanup", "failure", durationSec);
|
|
@@ -304834,7 +304929,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
304834
304929
|
const deleted = await services.deadLetters.cleanupExpired();
|
|
304835
304930
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304836
304931
|
recordScheduledJob("dead-letter-cleanup", "success", durationSec);
|
|
304837
|
-
|
|
304932
|
+
log109.info("Dead letter cleanup completed", { deleted });
|
|
304838
304933
|
} catch (err) {
|
|
304839
304934
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304840
304935
|
recordScheduledJob("dead-letter-cleanup", "failure", durationSec);
|
|
@@ -304863,7 +304958,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
304863
304958
|
});
|
|
304864
304959
|
jobsCreated++;
|
|
304865
304960
|
} catch (err) {
|
|
304866
|
-
|
|
304961
|
+
log109.warn("Failed to create contacts sync job for instance", {
|
|
304867
304962
|
instanceId: instance4.id,
|
|
304868
304963
|
error: String(err)
|
|
304869
304964
|
});
|
|
@@ -304871,7 +304966,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
304871
304966
|
}
|
|
304872
304967
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304873
304968
|
recordScheduledJob("contacts-sync-daily", "success", durationSec);
|
|
304874
|
-
|
|
304969
|
+
log109.info("Daily contacts sync jobs created", { jobsCreated, instanceCount: instances2.length });
|
|
304875
304970
|
} catch (err) {
|
|
304876
304971
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304877
304972
|
recordScheduledJob("contacts-sync-daily", "failure", durationSec);
|
|
@@ -304900,7 +304995,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
304900
304995
|
});
|
|
304901
304996
|
jobsCreated++;
|
|
304902
304997
|
} catch (err) {
|
|
304903
|
-
|
|
304998
|
+
log109.warn("Failed to create groups sync job for instance", {
|
|
304904
304999
|
instanceId: instance4.id,
|
|
304905
305000
|
error: String(err)
|
|
304906
305001
|
});
|
|
@@ -304908,7 +305003,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
304908
305003
|
}
|
|
304909
305004
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304910
305005
|
recordScheduledJob("groups-sync-daily", "success", durationSec);
|
|
304911
|
-
|
|
305006
|
+
log109.info("Daily groups sync jobs created", { jobsCreated, instanceCount: instances2.length });
|
|
304912
305007
|
} catch (err) {
|
|
304913
305008
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304914
305009
|
recordScheduledJob("groups-sync-daily", "failure", durationSec);
|
|
@@ -304929,7 +305024,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
304929
305024
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304930
305025
|
recordScheduledJob("follow-up-sweeper", "success", durationSec);
|
|
304931
305026
|
if (stats.scanned > 0) {
|
|
304932
|
-
|
|
305027
|
+
log109.debug("Follow-up sweep tick", stats);
|
|
304933
305028
|
}
|
|
304934
305029
|
} catch (err) {
|
|
304935
305030
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
@@ -304959,7 +305054,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
304959
305054
|
}
|
|
304960
305055
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304961
305056
|
recordScheduledJob("unread-count-refresh", "success", durationSec);
|
|
304962
|
-
|
|
305057
|
+
log109.debug("Refreshed unread counts", { instanceCount: waInstances.length });
|
|
304963
305058
|
} catch (err) {
|
|
304964
305059
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
304965
305060
|
recordScheduledJob("unread-count-refresh", "failure", durationSec);
|
|
@@ -304970,7 +305065,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
304970
305065
|
});
|
|
304971
305066
|
updateSchedulerMetrics();
|
|
304972
305067
|
scheduler.start();
|
|
304973
|
-
|
|
305068
|
+
log109.info("Scheduler started", {
|
|
304974
305069
|
jobs: scheduler.listJobs().map((j) => ({
|
|
304975
305070
|
name: j.name,
|
|
304976
305071
|
cron: j.cron,
|
|
@@ -304990,14 +305085,14 @@ function updateSchedulerMetrics() {
|
|
|
304990
305085
|
function stopScheduler() {
|
|
304991
305086
|
const scheduler = getScheduler();
|
|
304992
305087
|
scheduler.stop();
|
|
304993
|
-
|
|
305088
|
+
log109.info("Scheduler stopped");
|
|
304994
305089
|
}
|
|
304995
|
-
var
|
|
305090
|
+
var log109;
|
|
304996
305091
|
var init_scheduler2 = __esm(() => {
|
|
304997
305092
|
init_src();
|
|
304998
305093
|
init_esm5();
|
|
304999
305094
|
init_sentry_scrub();
|
|
305000
|
-
|
|
305095
|
+
log109 = createLogger("scheduler:setup");
|
|
305001
305096
|
});
|
|
305002
305097
|
|
|
305003
305098
|
// ../api/src/services/turn-monitor.ts
|
|
@@ -305011,7 +305106,7 @@ class TurnMonitor {
|
|
|
305011
305106
|
start() {
|
|
305012
305107
|
if (this.intervalId)
|
|
305013
305108
|
return;
|
|
305014
|
-
|
|
305109
|
+
log110.info("Turn monitor started", {
|
|
305015
305110
|
pollIntervalMs: POLL_INTERVAL_MS2,
|
|
305016
305111
|
nudgeMs: NUDGE_THRESHOLD_MS,
|
|
305017
305112
|
defaultStalledMs: DEFAULT_STALLED_THRESHOLD_MS,
|
|
@@ -305023,7 +305118,7 @@ class TurnMonitor {
|
|
|
305023
305118
|
if (this.intervalId) {
|
|
305024
305119
|
clearInterval(this.intervalId);
|
|
305025
305120
|
this.intervalId = null;
|
|
305026
|
-
|
|
305121
|
+
log110.info("Turn monitor stopped");
|
|
305027
305122
|
}
|
|
305028
305123
|
}
|
|
305029
305124
|
async tick() {
|
|
@@ -305051,7 +305146,7 @@ class TurnMonitor {
|
|
|
305051
305146
|
}
|
|
305052
305147
|
}
|
|
305053
305148
|
} catch (error2) {
|
|
305054
|
-
|
|
305149
|
+
log110.error("Turn monitor tick failed", { error: String(error2) });
|
|
305055
305150
|
} finally {
|
|
305056
305151
|
this.running = false;
|
|
305057
305152
|
}
|
|
@@ -305064,13 +305159,13 @@ class TurnMonitor {
|
|
|
305064
305159
|
idleSec,
|
|
305065
305160
|
message: `Turn idle for ${idleSec}s. Are you still working?`
|
|
305066
305161
|
});
|
|
305067
|
-
|
|
305162
|
+
log110.info("Turn nudge emitted", { turnId, nudgeCount, idleSec });
|
|
305068
305163
|
}
|
|
305069
305164
|
async handleStalled(turnId, instanceId, chatId, stalledAtMs, threshold) {
|
|
305070
305165
|
await this.deps.turnService.incrementNudge(turnId);
|
|
305071
305166
|
const payload = { turnId, instanceId, chatId, stalledAtMs, threshold };
|
|
305072
305167
|
publishTurnStalled(instanceId, chatId, payload);
|
|
305073
|
-
|
|
305168
|
+
log110.warn("Turn stalled \u2014 internal event emitted (no channel message sent)", payload);
|
|
305074
305169
|
}
|
|
305075
305170
|
async handleTimeout(turnId, instanceId, chatId, idleSec, nudgeCount) {
|
|
305076
305171
|
const closed = await this.deps.turnService.close(turnId, {
|
|
@@ -305093,14 +305188,14 @@ class TurnMonitor {
|
|
|
305093
305188
|
nudgeCount,
|
|
305094
305189
|
messagesSent: closed.messagesSent
|
|
305095
305190
|
});
|
|
305096
|
-
|
|
305191
|
+
log110.info("Turn force-closed (timeout)", { turnId, duration, nudgeCount });
|
|
305097
305192
|
}
|
|
305098
305193
|
}
|
|
305099
|
-
var
|
|
305194
|
+
var log110, NUDGE_THRESHOLD_MS = 120000, DEFAULT_STALLED_THRESHOLD_MS = 600000, TIMEOUT_THRESHOLD_MS = 1800000, POLL_INTERVAL_MS2 = 1e4;
|
|
305100
305195
|
var init_turn_monitor = __esm(() => {
|
|
305101
305196
|
init_src();
|
|
305102
305197
|
init_turn_events();
|
|
305103
|
-
|
|
305198
|
+
log110 = createLogger("turn-monitor");
|
|
305104
305199
|
});
|
|
305105
305200
|
|
|
305106
305201
|
// ../api/src/utils/startup-banner.ts
|
|
@@ -305174,12 +305269,12 @@ function printStartupBanner(options) {
|
|
|
305174
305269
|
process.stdout.write(`${line3}
|
|
305175
305270
|
`);
|
|
305176
305271
|
}
|
|
305177
|
-
|
|
305272
|
+
log111.info("Server ready", { host, port, version: version4 });
|
|
305178
305273
|
}
|
|
305179
|
-
var
|
|
305274
|
+
var log111, COLORS3, BOX, ANSI_ESCAPE_PATTERN;
|
|
305180
305275
|
var init_startup_banner = __esm(() => {
|
|
305181
305276
|
init_src();
|
|
305182
|
-
|
|
305277
|
+
log111 = createLogger("api:startup");
|
|
305183
305278
|
COLORS3 = {
|
|
305184
305279
|
reset: "\x1B[0m",
|
|
305185
305280
|
dim: "\x1B[2m",
|
|
@@ -305237,7 +305332,7 @@ class VoiceStreamRegistry {
|
|
|
305237
305332
|
clients = new Map;
|
|
305238
305333
|
add(ws, client) {
|
|
305239
305334
|
this.clients.set(ws, client);
|
|
305240
|
-
|
|
305335
|
+
log112.info("Voice WS client connected", {
|
|
305241
305336
|
sessionId: client.params.sessionId,
|
|
305242
305337
|
format: client.params.format,
|
|
305243
305338
|
filterUser: client.params.filterUserId ?? "all"
|
|
@@ -305302,11 +305397,11 @@ function parseVoiceStreamParams(url) {
|
|
|
305302
305397
|
return null;
|
|
305303
305398
|
return { sessionId, apiKey, format: format === "pcm" ? "pcm" : "opus", filterUserId };
|
|
305304
305399
|
}
|
|
305305
|
-
var
|
|
305400
|
+
var log112, opusCodec = null;
|
|
305306
305401
|
var init_voice3 = __esm(() => {
|
|
305307
305402
|
init_src();
|
|
305308
305403
|
init_src3();
|
|
305309
|
-
|
|
305404
|
+
log112 = createLogger("ws:voice");
|
|
305310
305405
|
});
|
|
305311
305406
|
|
|
305312
305407
|
// ../api/src/index.ts
|
|
@@ -305540,7 +305635,7 @@ async function resolveCallAgentChatIds(services, ctx) {
|
|
|
305540
305635
|
senderId: ctx.senderId === ctx.chatId ? chat2.externalId : ctx.senderId
|
|
305541
305636
|
};
|
|
305542
305637
|
} catch {
|
|
305543
|
-
|
|
305638
|
+
log113.warn("call_agent: chat UUID not resolvable, using raw value (session may diverge)", {
|
|
305544
305639
|
chatId: ctx.chatId,
|
|
305545
305640
|
instanceId: ctx.instanceId
|
|
305546
305641
|
});
|
|
@@ -305549,23 +305644,23 @@ async function resolveCallAgentChatIds(services, ctx) {
|
|
|
305549
305644
|
}
|
|
305550
305645
|
async function setupEventBusServices(eventBus, services, db3) {
|
|
305551
305646
|
if (!eventBus) {
|
|
305552
|
-
|
|
305647
|
+
log113.warn("Skipping event bus services (no event bus)");
|
|
305553
305648
|
return;
|
|
305554
305649
|
}
|
|
305555
305650
|
try {
|
|
305556
305651
|
await setupMessagePersistence(eventBus, services);
|
|
305557
305652
|
} catch (error2) {
|
|
305558
|
-
|
|
305653
|
+
log113.error("Failed to set up message persistence", { error: String(error2) });
|
|
305559
305654
|
}
|
|
305560
305655
|
try {
|
|
305561
305656
|
await setupMediaProcessor(eventBus, db3, services);
|
|
305562
305657
|
} catch (error2) {
|
|
305563
|
-
|
|
305658
|
+
log113.error("Failed to set up media processor", { error: String(error2) });
|
|
305564
305659
|
}
|
|
305565
305660
|
try {
|
|
305566
305661
|
globalDispatcherCleanup = await setupAgentResponder(eventBus, services, db3);
|
|
305567
305662
|
} catch (error2) {
|
|
305568
|
-
|
|
305663
|
+
log113.error("Failed to set up agent dispatcher", { error: String(error2) });
|
|
305569
305664
|
}
|
|
305570
305665
|
try {
|
|
305571
305666
|
await services.automations.startEngine({
|
|
@@ -305641,34 +305736,34 @@ async function setupEventBusServices(eventBus, services, db3) {
|
|
|
305641
305736
|
}
|
|
305642
305737
|
});
|
|
305643
305738
|
} catch (error2) {
|
|
305644
|
-
|
|
305739
|
+
log113.error("Failed to start automation engine", { error: String(error2) });
|
|
305645
305740
|
}
|
|
305646
305741
|
try {
|
|
305647
305742
|
await setupSessionCleaner(eventBus, services, db3);
|
|
305648
305743
|
} catch (error2) {
|
|
305649
|
-
|
|
305744
|
+
log113.error("Failed to set up session cleaner", { error: String(error2) });
|
|
305650
305745
|
}
|
|
305651
305746
|
try {
|
|
305652
305747
|
await setupFollowUpHooks(eventBus, services);
|
|
305653
305748
|
} catch (error2) {
|
|
305654
|
-
|
|
305749
|
+
log113.error("Failed to set up follow-up hooks", { error: String(error2) });
|
|
305655
305750
|
}
|
|
305656
305751
|
if (globalChannelRegistry) {
|
|
305657
305752
|
try {
|
|
305658
305753
|
await setupSyncWorker(eventBus, services, globalChannelRegistry, db3);
|
|
305659
305754
|
} catch (error2) {
|
|
305660
|
-
|
|
305755
|
+
log113.error("Failed to set up sync worker", { error: String(error2) });
|
|
305661
305756
|
}
|
|
305662
305757
|
}
|
|
305663
305758
|
try {
|
|
305664
305759
|
await setupHistoryPushTracker(eventBus, services);
|
|
305665
305760
|
} catch (error2) {
|
|
305666
|
-
|
|
305761
|
+
log113.error("Failed to set up history-push tracker", { error: String(error2) });
|
|
305667
305762
|
}
|
|
305668
305763
|
try {
|
|
305669
305764
|
await initTurnEvents(NATS_URL);
|
|
305670
305765
|
} catch (error2) {
|
|
305671
|
-
|
|
305766
|
+
log113.error("Failed to initialize turn events", { error: String(error2) });
|
|
305672
305767
|
}
|
|
305673
305768
|
try {
|
|
305674
305769
|
globalTurnMonitor = new TurnMonitor({
|
|
@@ -305676,42 +305771,42 @@ async function setupEventBusServices(eventBus, services, db3) {
|
|
|
305676
305771
|
instanceService: services.instances
|
|
305677
305772
|
});
|
|
305678
305773
|
globalTurnMonitor.start();
|
|
305679
|
-
|
|
305774
|
+
log113.info("Turn monitor started");
|
|
305680
305775
|
} catch (error2) {
|
|
305681
|
-
|
|
305776
|
+
log113.error("Failed to start turn monitor", { error: String(error2) });
|
|
305682
305777
|
}
|
|
305683
305778
|
}
|
|
305684
305779
|
async function waitForDatabaseReady(db3, maxAttempts = 30) {
|
|
305685
|
-
|
|
305780
|
+
log113.info("Waiting for database readiness");
|
|
305686
305781
|
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
305687
305782
|
try {
|
|
305688
305783
|
await db3.execute(sql`SELECT 1`);
|
|
305689
|
-
|
|
305784
|
+
log113.info("Database ready", { attempt });
|
|
305690
305785
|
return;
|
|
305691
305786
|
} catch {
|
|
305692
305787
|
if (attempt === maxAttempts) {
|
|
305693
305788
|
throw new Error(`Database not ready after ${maxAttempts} attempts`);
|
|
305694
305789
|
}
|
|
305695
|
-
|
|
305790
|
+
log113.warn("Database not ready, retrying...", { attempt });
|
|
305696
305791
|
await new Promise((resolve4) => setTimeout(resolve4, 1000));
|
|
305697
305792
|
}
|
|
305698
305793
|
}
|
|
305699
305794
|
}
|
|
305700
305795
|
async function main() {
|
|
305701
|
-
|
|
305796
|
+
log113.info("Starting Omni API v2");
|
|
305702
305797
|
enableDefaultMetrics();
|
|
305703
305798
|
const pgserveConfig = resolvePgserveConfig();
|
|
305704
305799
|
const databaseUrl = await startEmbeddedPgserve(pgserveConfig);
|
|
305705
|
-
|
|
305800
|
+
log113.info("Connecting to database");
|
|
305706
305801
|
const db3 = createDb({ url: databaseUrl });
|
|
305707
305802
|
globalDbRef = db3;
|
|
305708
305803
|
const earlyShutdown = async () => {
|
|
305709
|
-
|
|
305804
|
+
log113.info("Shutdown during startup \u2014 cleaning up");
|
|
305710
305805
|
try {
|
|
305711
305806
|
await closeDb();
|
|
305712
305807
|
await stopEmbeddedPgserve();
|
|
305713
305808
|
} catch (err) {
|
|
305714
|
-
|
|
305809
|
+
log113.error("Cleanup failed during early shutdown", { error: String(err) });
|
|
305715
305810
|
} finally {
|
|
305716
305811
|
process.exit(1);
|
|
305717
305812
|
}
|
|
@@ -305725,7 +305820,7 @@ async function main() {
|
|
|
305725
305820
|
await stopEmbeddedPgserve();
|
|
305726
305821
|
throw error2;
|
|
305727
305822
|
}
|
|
305728
|
-
|
|
305823
|
+
log113.info("Running database migrations");
|
|
305729
305824
|
const migrationStart = Date.now();
|
|
305730
305825
|
const MIGRATION_TIMEOUT_MS = 60000;
|
|
305731
305826
|
try {
|
|
@@ -305738,17 +305833,17 @@ async function main() {
|
|
|
305738
305833
|
await stopEmbeddedPgserve();
|
|
305739
305834
|
throw error2;
|
|
305740
305835
|
}
|
|
305741
|
-
|
|
305836
|
+
log113.info("Database migrations complete", { durationMs: Date.now() - migrationStart });
|
|
305742
305837
|
try {
|
|
305743
305838
|
const driftReport = await verifyCriticalColumns(db3, API_CRITICAL_COLUMNS);
|
|
305744
305839
|
if (!driftReport.ok) {
|
|
305745
|
-
|
|
305840
|
+
log113.error(formatDriftReport(driftReport), { drift: driftReport.drift });
|
|
305746
305841
|
await closeDb();
|
|
305747
305842
|
await stopEmbeddedPgserve();
|
|
305748
305843
|
process.exit(1);
|
|
305749
305844
|
}
|
|
305750
305845
|
} catch (error2) {
|
|
305751
|
-
|
|
305846
|
+
log113.error("Schema drift check failed", { error: String(error2) });
|
|
305752
305847
|
await closeDb();
|
|
305753
305848
|
await stopEmbeddedPgserve();
|
|
305754
305849
|
process.exit(1);
|
|
@@ -305756,12 +305851,12 @@ async function main() {
|
|
|
305756
305851
|
try {
|
|
305757
305852
|
const [countRow] = await db3.select({ count: sql`count(*)::int` }).from(instances);
|
|
305758
305853
|
const rowCount = countRow?.count ?? 0;
|
|
305759
|
-
|
|
305854
|
+
log113.info("Post-migration content snapshot", { DB_ROW_COUNT_INSTANCES: rowCount });
|
|
305760
305855
|
if (rowCount === 0 && pgserveConfig.requireExisting) {
|
|
305761
|
-
|
|
305856
|
+
log113.error("PGSERVE_REQUIRE_EXISTING=true but instances table is empty after boot \u2014 verify PGSERVE_DATA points at the correct cluster (see #412).");
|
|
305762
305857
|
}
|
|
305763
305858
|
} catch (error2) {
|
|
305764
|
-
|
|
305859
|
+
log113.warn("Failed to read instances row count (non-fatal)", { error: String(error2) });
|
|
305765
305860
|
}
|
|
305766
305861
|
const eventBus = await connectToNats(db3);
|
|
305767
305862
|
if (eventBus) {
|
|
@@ -305779,9 +305874,9 @@ async function main() {
|
|
|
305779
305874
|
try {
|
|
305780
305875
|
await services.settings.seedDefaults();
|
|
305781
305876
|
} catch (error2) {
|
|
305782
|
-
|
|
305877
|
+
log113.error("Failed to seed default settings", { error: String(error2) });
|
|
305783
305878
|
}
|
|
305784
|
-
|
|
305879
|
+
log113.info("Initializing API key");
|
|
305785
305880
|
let apiKeyInfo;
|
|
305786
305881
|
try {
|
|
305787
305882
|
const keyResult = await services.apiKeys.initializePrimaryKey();
|
|
@@ -305791,17 +305886,17 @@ async function main() {
|
|
|
305791
305886
|
isFromEnv: keyResult.isFromEnv
|
|
305792
305887
|
};
|
|
305793
305888
|
if (keyResult.isNew) {
|
|
305794
|
-
|
|
305889
|
+
log113.info("Generated new primary API key");
|
|
305795
305890
|
} else if (keyResult.isFromEnv) {
|
|
305796
|
-
|
|
305891
|
+
log113.info("Using primary API key from environment");
|
|
305797
305892
|
} else {
|
|
305798
|
-
|
|
305893
|
+
log113.info("Using existing primary API key");
|
|
305799
305894
|
}
|
|
305800
305895
|
} catch (error2) {
|
|
305801
|
-
|
|
305896
|
+
log113.error("Failed to initialize primary API key", { error: String(error2) });
|
|
305802
305897
|
}
|
|
305803
305898
|
await setupEventBusServices(eventBus, services, db3);
|
|
305804
|
-
|
|
305899
|
+
log113.info("Starting scheduler");
|
|
305805
305900
|
setupScheduler(services, globalChannelRegistry);
|
|
305806
305901
|
const server = startBunServer(app);
|
|
305807
305902
|
printStartupBanner({
|
|
@@ -305815,7 +305910,7 @@ async function main() {
|
|
|
305815
305910
|
});
|
|
305816
305911
|
setupShutdownHandlers(server, earlyShutdown);
|
|
305817
305912
|
}
|
|
305818
|
-
var import__package3,
|
|
305913
|
+
var import__package3, log113, natsLog, pluginLog, shutdownLog, PORT, HOST, NATS_URL, voiceStreamRegistry, globalEventBus = null, globalChannelRegistry = null, globalInstanceMonitor = null, globalDispatcherCleanup = null, globalTurnMonitor = null, globalDbRef = null, UUID_RE3;
|
|
305819
305914
|
var init_src8 = __esm(() => {
|
|
305820
305915
|
init_instrument2();
|
|
305821
305916
|
init_src2();
|
|
@@ -305840,7 +305935,7 @@ var init_src8 = __esm(() => {
|
|
|
305840
305935
|
level: process.env.LOG_LEVEL ?? "info",
|
|
305841
305936
|
format: process.env.LOG_FORMAT ?? "auto"
|
|
305842
305937
|
});
|
|
305843
|
-
|
|
305938
|
+
log113 = createLogger("api:startup");
|
|
305844
305939
|
natsLog = createLogger("api:nats");
|
|
305845
305940
|
pluginLog = createLogger("api:plugins");
|
|
305846
305941
|
shutdownLog = createLogger("api:shutdown");
|
|
@@ -305850,7 +305945,7 @@ var init_src8 = __esm(() => {
|
|
|
305850
305945
|
voiceStreamRegistry = new VoiceStreamRegistry;
|
|
305851
305946
|
UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
305852
305947
|
main().catch((error2) => {
|
|
305853
|
-
|
|
305948
|
+
log113.error("Failed to start API server", { error: String(error2) });
|
|
305854
305949
|
process.exit(1);
|
|
305855
305950
|
});
|
|
305856
305951
|
});
|