@automagik/omni 2.260622.1 → 2.260624.2
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/dist/commands/send.d.ts.map +1 -1
- package/dist/index.js +62 -11
- package/dist/sdk/client.d.ts +9 -0
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/index.js +5 -1
- package/dist/sdk/types.generated.d.ts +40 -10
- package/dist/sdk/types.generated.d.ts.map +1 -1
- package/dist/server/index.js +271 -85
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -29993,7 +29993,7 @@ class AgnoClient {
|
|
|
29993
29993
|
function createAgnoClient(config2) {
|
|
29994
29994
|
return new AgnoClient(config2);
|
|
29995
29995
|
}
|
|
29996
|
-
var DEFAULT_TIMEOUT_MS =
|
|
29996
|
+
var DEFAULT_TIMEOUT_MS = 600000;
|
|
29997
29997
|
var init_agno_client = __esm(() => {
|
|
29998
29998
|
init_trace_context();
|
|
29999
29999
|
init_types7();
|
|
@@ -30661,6 +30661,25 @@ var init_claude_code_client = __esm(() => {
|
|
|
30661
30661
|
THINKING_TAG_RE = /<thinking>[\s\S]*?<\/thinking>\s*/g;
|
|
30662
30662
|
});
|
|
30663
30663
|
|
|
30664
|
+
// ../core/src/providers/customer-safe-errors.ts
|
|
30665
|
+
function isUnsafeCustomerFacingProviderText(text) {
|
|
30666
|
+
return Boolean(text && PROVIDER_ERROR_PATTERN.test(text));
|
|
30667
|
+
}
|
|
30668
|
+
function resolveSafeProviderErrorMessage(env = process.env) {
|
|
30669
|
+
const override = env.OMNI_SAFE_PROVIDER_ERROR_MESSAGE?.trim();
|
|
30670
|
+
return override || SAFE_PROVIDER_ERROR_MESSAGE;
|
|
30671
|
+
}
|
|
30672
|
+
function toSafeCustomerFallback(text, env = process.env) {
|
|
30673
|
+
if (isUnsafeCustomerFacingProviderText(text)) {
|
|
30674
|
+
return resolveSafeProviderErrorMessage(env);
|
|
30675
|
+
}
|
|
30676
|
+
return text ?? "";
|
|
30677
|
+
}
|
|
30678
|
+
var SAFE_PROVIDER_ERROR_MESSAGE = "T\xF4 com um probleminha t\xE9cnico aqui agora. J\xE1 estou avisando o time. Pode tentar de novo em alguns minutos? \uD83D\uDE4F", PROVIDER_ERROR_PATTERN;
|
|
30679
|
+
var init_customer_safe_errors = __esm(() => {
|
|
30680
|
+
PROVIDER_ERROR_PATTERN = /(litellm\.(BadRequestError|AuthenticationError|RateLimitError|APIError)|ModelProviderError|AnthropicException|Authentication Error|Invalid proxy server token|Received API Key|Available Model Group Fallbacks|credit balance is too low|Plans\s*&\s*Billing|\bsk-[A-Za-z0-9_-]{8,}|Bearer\s+[A-Za-z0-9._-]{20,}|api[_ -]?key\s*[=:])/i;
|
|
30681
|
+
});
|
|
30682
|
+
|
|
30664
30683
|
// ../core/src/providers/agno-provider.ts
|
|
30665
30684
|
class AgnoAgentProvider {
|
|
30666
30685
|
id;
|
|
@@ -30700,9 +30719,17 @@ class AgnoAgentProvider {
|
|
|
30700
30719
|
traceId: context2.traceId
|
|
30701
30720
|
});
|
|
30702
30721
|
const response = await this.client.run(request);
|
|
30703
|
-
const
|
|
30722
|
+
const customerContent = toSafeCustomerFallback(response.content);
|
|
30723
|
+
if (customerContent !== response.content) {
|
|
30724
|
+
log8.error("Blocked provider error from customer-facing Agno response", {
|
|
30725
|
+
agentId: this.config.agentId,
|
|
30726
|
+
runId: response.runId,
|
|
30727
|
+
traceId: context2.traceId
|
|
30728
|
+
});
|
|
30729
|
+
}
|
|
30730
|
+
const parts = this.config.enableAutoSplit !== false ? customerContent.split(`
|
|
30704
30731
|
|
|
30705
|
-
`).map((p2) => p2.trim()).filter(Boolean) : [
|
|
30732
|
+
`).map((p2) => p2.trim()).filter(Boolean) : [customerContent.trim()].filter(Boolean);
|
|
30706
30733
|
const durationMs = Date.now() - startTime;
|
|
30707
30734
|
log8.info("Agno agent responded", {
|
|
30708
30735
|
agentId: this.config.agentId,
|
|
@@ -30740,10 +30767,20 @@ class AgnoAgentProvider {
|
|
|
30740
30767
|
try {
|
|
30741
30768
|
for await (const chunk of this.client.stream(request)) {
|
|
30742
30769
|
if (chunk.content) {
|
|
30743
|
-
|
|
30770
|
+
const safeContent = toSafeCustomerFallback(chunk.content);
|
|
30771
|
+
if (safeContent !== chunk.content) {
|
|
30772
|
+
log8.error("Blocked provider error from customer-facing Agno stream chunk", {
|
|
30773
|
+
agentId: this.config.agentId,
|
|
30774
|
+
traceId: context2.traceId
|
|
30775
|
+
});
|
|
30776
|
+
yield { phase: "content", content: safeContent };
|
|
30777
|
+
continue;
|
|
30778
|
+
}
|
|
30779
|
+
yield { phase: "content", content: safeContent };
|
|
30744
30780
|
}
|
|
30745
30781
|
if (chunk.isComplete) {
|
|
30746
|
-
|
|
30782
|
+
const finalContent = chunk.fullContent ?? chunk.content ?? "";
|
|
30783
|
+
yield { phase: "final", content: toSafeCustomerFallback(finalContent) };
|
|
30747
30784
|
}
|
|
30748
30785
|
}
|
|
30749
30786
|
} catch (error) {
|
|
@@ -30753,7 +30790,7 @@ class AgnoAgentProvider {
|
|
|
30753
30790
|
traceId: context2.traceId,
|
|
30754
30791
|
error: message3
|
|
30755
30792
|
});
|
|
30756
|
-
yield { phase: "error", error:
|
|
30793
|
+
yield { phase: "error", error: resolveSafeProviderErrorMessage() };
|
|
30757
30794
|
}
|
|
30758
30795
|
}
|
|
30759
30796
|
async checkHealth() {
|
|
@@ -30796,6 +30833,7 @@ class AgnoAgentProvider {
|
|
|
30796
30833
|
var log8;
|
|
30797
30834
|
var init_agno_provider = __esm(() => {
|
|
30798
30835
|
init_logger();
|
|
30836
|
+
init_customer_safe_errors();
|
|
30799
30837
|
init_trace_context();
|
|
30800
30838
|
log8 = createLogger("provider:agno");
|
|
30801
30839
|
});
|
|
@@ -148890,6 +148928,9 @@ import { spawn } from "child_process";
|
|
|
148890
148928
|
import { promises as fs } from "fs";
|
|
148891
148929
|
import { tmpdir as tmpdir2 } from "os";
|
|
148892
148930
|
import { join as join5 } from "path";
|
|
148931
|
+
function spawnWithEvents(command, args) {
|
|
148932
|
+
return spawn(command, args);
|
|
148933
|
+
}
|
|
148893
148934
|
async function writeToTempFile(data) {
|
|
148894
148935
|
const path = join5(tmpdir2(), `audio-decode-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
|
|
148895
148936
|
await fs.writeFile(path, data);
|
|
@@ -148948,7 +148989,7 @@ async function decode2(input) {
|
|
|
148948
148989
|
function ffmpegDecode(inputPath, sampleRate) {
|
|
148949
148990
|
return new Promise((resolve, reject) => {
|
|
148950
148991
|
const chunks = [];
|
|
148951
|
-
const ffmpeg =
|
|
148992
|
+
const ffmpeg = spawnWithEvents("ffmpeg", [
|
|
148952
148993
|
"-i",
|
|
148953
148994
|
inputPath,
|
|
148954
148995
|
"-f",
|
|
@@ -155249,9 +155290,12 @@ import { tmpdir as tmpdir5 } from "os";
|
|
|
155249
155290
|
import { join as join10 } from "path";
|
|
155250
155291
|
import { Readable as Readable2 } from "stream";
|
|
155251
155292
|
import { pipeline as pipeline3 } from "stream/promises";
|
|
155293
|
+
function spawnWithEvents2(command, args) {
|
|
155294
|
+
return spawn2(command, args);
|
|
155295
|
+
}
|
|
155252
155296
|
async function isFFmpegAvailable() {
|
|
155253
155297
|
return new Promise((resolve) => {
|
|
155254
|
-
const proc =
|
|
155298
|
+
const proc = spawnWithEvents2("ffmpeg", ["-version"]);
|
|
155255
155299
|
proc.on("error", () => resolve(false));
|
|
155256
155300
|
proc.on("close", (code) => resolve(code === 0));
|
|
155257
155301
|
});
|
|
@@ -155306,7 +155350,7 @@ async function downloadToTemp(url) {
|
|
|
155306
155350
|
async function convertToOggOpus(inputPath) {
|
|
155307
155351
|
const outputPath = join10(tmpdir5(), `omni-audio-${Date.now()}-output.ogg`);
|
|
155308
155352
|
return new Promise((resolve, reject) => {
|
|
155309
|
-
const ffmpeg =
|
|
155353
|
+
const ffmpeg = spawnWithEvents2("ffmpeg", [
|
|
155310
155354
|
"-i",
|
|
155311
155355
|
inputPath,
|
|
155312
155356
|
"-c:a",
|
|
@@ -225245,7 +225289,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
225245
225289
|
var require_package7 = __commonJS((exports, module) => {
|
|
225246
225290
|
module.exports = {
|
|
225247
225291
|
name: "@omni/api",
|
|
225248
|
-
version: "2.
|
|
225292
|
+
version: "2.260624.2",
|
|
225249
225293
|
type: "module",
|
|
225250
225294
|
exports: {
|
|
225251
225295
|
".": {
|
|
@@ -311084,6 +311128,9 @@ import { spawn as spawn3 } from "child_process";
|
|
|
311084
311128
|
import { promises as fs10 } from "fs";
|
|
311085
311129
|
import { tmpdir as tmpdir6 } from "os";
|
|
311086
311130
|
import { join as join16 } from "path";
|
|
311131
|
+
function spawnWithEvents3(command, args) {
|
|
311132
|
+
return spawn3(command, args);
|
|
311133
|
+
}
|
|
311087
311134
|
|
|
311088
311135
|
class GeminiTtsProvider {
|
|
311089
311136
|
settings;
|
|
@@ -311254,7 +311301,7 @@ async function convertWavToOggOpus(wavBuffer) {
|
|
|
311254
311301
|
try {
|
|
311255
311302
|
await fs10.writeFile(inputPath, wavBuffer);
|
|
311256
311303
|
await new Promise((resolve2, reject) => {
|
|
311257
|
-
const ffmpeg =
|
|
311304
|
+
const ffmpeg = spawnWithEvents3("ffmpeg", [
|
|
311258
311305
|
"-i",
|
|
311259
311306
|
inputPath,
|
|
311260
311307
|
"-c:a",
|
|
@@ -311300,7 +311347,7 @@ async function getAudioDurationMs(audioBuffer) {
|
|
|
311300
311347
|
try {
|
|
311301
311348
|
await fs10.writeFile(tempPath, audioBuffer);
|
|
311302
311349
|
return await new Promise((resolve2) => {
|
|
311303
|
-
const ffprobe =
|
|
311350
|
+
const ffprobe = spawnWithEvents3("ffprobe", [
|
|
311304
311351
|
"-i",
|
|
311305
311352
|
tempPath,
|
|
311306
311353
|
"-show_entries",
|
|
@@ -312008,6 +312055,9 @@ import { spawn as spawn4 } from "child_process";
|
|
|
312008
312055
|
import { promises as fs12 } from "fs";
|
|
312009
312056
|
import { tmpdir as tmpdir8 } from "os";
|
|
312010
312057
|
import { join as join18 } from "path";
|
|
312058
|
+
function spawnWithEvents4(command, args) {
|
|
312059
|
+
return spawn4(command, args);
|
|
312060
|
+
}
|
|
312011
312061
|
|
|
312012
312062
|
class OpenAiTtsProvider {
|
|
312013
312063
|
settings;
|
|
@@ -312126,7 +312176,7 @@ async function convertAudio(input, from, to) {
|
|
|
312126
312176
|
try {
|
|
312127
312177
|
await fs12.writeFile(inputPath, input);
|
|
312128
312178
|
await new Promise((resolve2, reject) => {
|
|
312129
|
-
const ffmpeg =
|
|
312179
|
+
const ffmpeg = spawnWithEvents4("ffmpeg", [
|
|
312130
312180
|
"-hide_banner",
|
|
312131
312181
|
"-loglevel",
|
|
312132
312182
|
"error",
|
|
@@ -337005,7 +337055,7 @@ class AgentDispatchLimiter {
|
|
|
337005
337055
|
return `${context20.instanceId}:${context20.chatId}`;
|
|
337006
337056
|
}
|
|
337007
337057
|
}
|
|
337008
|
-
var DEFAULT_AGENT_DISPATCH_CONCURRENCY = 8, DEFAULT_AGENT_DISPATCH_QUEUE_MAX_DEPTH = 100, DEFAULT_AGENT_DISPATCH_QUEUE_MAX_WAIT_MS =
|
|
337058
|
+
var DEFAULT_AGENT_DISPATCH_CONCURRENCY = 8, DEFAULT_AGENT_DISPATCH_QUEUE_MAX_DEPTH = 100, DEFAULT_AGENT_DISPATCH_QUEUE_MAX_WAIT_MS = 600000, DEFAULT_AGENT_DISPATCH_PER_CHAT_CONCURRENCY = 1, AgentDispatchQueueFullError, AgentDispatchQueueTimeoutError;
|
|
337009
337059
|
var init_agent_dispatch_limiter = __esm(() => {
|
|
337010
337060
|
AgentDispatchQueueFullError = class AgentDispatchQueueFullError extends Error {
|
|
337011
337061
|
snapshot;
|
|
@@ -337482,9 +337532,9 @@ function findLongStrings(obj, prefix = "", minLength = 200) {
|
|
|
337482
337532
|
}
|
|
337483
337533
|
return result;
|
|
337484
337534
|
}
|
|
337485
|
-
function extractPlatformTimestamp(rawPayload,
|
|
337535
|
+
function extractPlatformTimestamp(rawPayload, _fallback) {
|
|
337486
337536
|
if (!rawPayload?.messageTimestamp)
|
|
337487
|
-
return
|
|
337537
|
+
return null;
|
|
337488
337538
|
const ts = rawPayload.messageTimestamp;
|
|
337489
337539
|
let tsNum = null;
|
|
337490
337540
|
if (typeof ts === "number") {
|
|
@@ -337492,10 +337542,12 @@ function extractPlatformTimestamp(rawPayload, fallback) {
|
|
|
337492
337542
|
} else if (typeof ts === "string") {
|
|
337493
337543
|
tsNum = Number(ts);
|
|
337494
337544
|
} else if (typeof ts === "object" && ts !== null && "low" in ts) {
|
|
337495
|
-
|
|
337545
|
+
const lo = ts.low >>> 0;
|
|
337546
|
+
const hi = (ts.high ?? 0) >>> 0;
|
|
337547
|
+
tsNum = hi * 4294967296 + lo;
|
|
337496
337548
|
}
|
|
337497
337549
|
if (!tsNum || Number.isNaN(tsNum))
|
|
337498
|
-
return
|
|
337550
|
+
return null;
|
|
337499
337551
|
return new Date(tsNum < 1000000000000 ? tsNum * 1000 : tsNum);
|
|
337500
337552
|
}
|
|
337501
337553
|
function buildChatPreview(payload, rawPayload) {
|
|
@@ -337728,6 +337780,7 @@ async function resolveOrCreateChat(services, instanceId, chatExternalId, chatTyp
|
|
|
337728
337780
|
}
|
|
337729
337781
|
async function handleMessageReceived(services, payload, metadata, eventTimestamp) {
|
|
337730
337782
|
const channel5 = metadata.channelType ?? "whatsapp";
|
|
337783
|
+
const isHistorySync = metadata.ingestMode === "history-sync";
|
|
337731
337784
|
const chatExternalId = truncate3(payload.chatId, 255) ?? payload.chatId;
|
|
337732
337785
|
const messageExternalId = truncate3(payload.externalId, 255) ?? payload.externalId;
|
|
337733
337786
|
const rawPayload = payload.rawPayload ? deepSanitize(payload.rawPayload) : undefined;
|
|
@@ -337744,11 +337797,18 @@ async function handleMessageReceived(services, payload, metadata, eventTimestamp
|
|
|
337744
337797
|
const senderDisplayName = resolveSenderDisplayName(payload.senderName, rawPayload, participantResult);
|
|
337745
337798
|
const quotedMessage = rawPayload?.quotedMessage;
|
|
337746
337799
|
const platformTimestamp = extractPlatformTimestamp(rawPayload, eventTimestamp);
|
|
337800
|
+
if (isHistorySync && platformTimestamp === null) {
|
|
337801
|
+
log98.debug("Skipping history-sync message without messageTimestamp", {
|
|
337802
|
+
externalId: payload.externalId,
|
|
337803
|
+
chatId: payload.chatId
|
|
337804
|
+
});
|
|
337805
|
+
return;
|
|
337806
|
+
}
|
|
337747
337807
|
const { message: message2, created } = await services.messages.findOrCreate(chat2.id, messageExternalId, {
|
|
337748
|
-
source: "realtime",
|
|
337808
|
+
source: isHistorySync ? "sync" : "realtime",
|
|
337749
337809
|
messageType: mapContentType(payload.content.type),
|
|
337750
337810
|
textContent: sanitizeText(payload.content.text),
|
|
337751
|
-
platformTimestamp,
|
|
337811
|
+
platformTimestamp: platformTimestamp ?? new Date(eventTimestamp),
|
|
337752
337812
|
senderPlatformUserId: truncate3(payload.from, 255),
|
|
337753
337813
|
senderDisplayName,
|
|
337754
337814
|
senderPersonId: personId,
|
|
@@ -337764,12 +337824,12 @@ async function handleMessageReceived(services, payload, metadata, eventTimestamp
|
|
|
337764
337824
|
isForwarded: !!(rawPayload?.isForwarded || rawPayload?.forwardingScore),
|
|
337765
337825
|
rawPayload
|
|
337766
337826
|
});
|
|
337767
|
-
await maybeRecordMessageEdit(services, created, rawPayload, message2.id, sanitizeText(payload.content.text) ?? undefined, platformTimestamp, payload.from);
|
|
337827
|
+
await maybeRecordMessageEdit(services, created, rawPayload, message2.id, sanitizeText(payload.content.text) ?? undefined, platformTimestamp ?? new Date(eventTimestamp), payload.from);
|
|
337768
337828
|
if (created) {
|
|
337769
337829
|
log98.debug("Created message", { externalId: payload.externalId, chatId: chat2.id });
|
|
337770
337830
|
}
|
|
337771
337831
|
await maybeRecordParticipantActivity(services, chat2.id, payload.from);
|
|
337772
|
-
maybeUpdateRecency(services, metadata.instanceId, chat2.id, rawPayload, payload, platformTimestamp);
|
|
337832
|
+
maybeUpdateRecency(services, metadata.instanceId, chat2.id, rawPayload, payload, platformTimestamp ?? new Date(eventTimestamp));
|
|
337773
337833
|
}
|
|
337774
337834
|
function logMessageReceivedError(payload, error3) {
|
|
337775
337835
|
const rawPayload = payload.rawPayload;
|
|
@@ -338392,11 +338452,19 @@ async function sendTextMessage5(channel5, instanceId, chatId, text3, messageForm
|
|
|
338392
338452
|
metadata: { messageFormatMode, correlationId, senderAgentId }
|
|
338393
338453
|
});
|
|
338394
338454
|
}
|
|
338395
|
-
|
|
338455
|
+
function resolveDispatchErrorMessage(instanceErrorMessage, env2 = process.env) {
|
|
338456
|
+
const instanceMsg = instanceErrorMessage?.trim();
|
|
338457
|
+
if (instanceMsg)
|
|
338458
|
+
return instanceMsg;
|
|
338459
|
+
const envMsg = env2.OMNI_AGENT_DISPATCH_ERROR_MESSAGE?.trim();
|
|
338460
|
+
if (envMsg)
|
|
338461
|
+
return envMsg;
|
|
338462
|
+
return DEFAULT_DISPATCH_ERROR_MESSAGE;
|
|
338463
|
+
}
|
|
338464
|
+
async function sendErrorFeedback(channel5, instanceId, chatId, error3, message2) {
|
|
338396
338465
|
const errorMsg = error3 instanceof Error ? error3.message : String(error3);
|
|
338397
338466
|
log99.error("agent_dispatch_error", { channel: channel5, instanceId, chatId, error: errorMsg });
|
|
338398
|
-
|
|
338399
|
-
await sendTextMessage5(channel5, instanceId, chatId, text3);
|
|
338467
|
+
await sendTextMessage5(channel5, instanceId, chatId, message2);
|
|
338400
338468
|
}
|
|
338401
338469
|
function sleep5(ms) {
|
|
338402
338470
|
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
@@ -339953,7 +340021,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
339953
340021
|
}
|
|
339954
340022
|
if (chatSettings?.agentResumedAt) {
|
|
339955
340023
|
const resumedAt = new Date(chatSettings.agentResumedAt).getTime();
|
|
339956
|
-
const msgTimestamp = extractPlatformTimestamp(firstMessage.payload.rawPayload, Date.now()).getTime();
|
|
340024
|
+
const msgTimestamp = (extractPlatformTimestamp(firstMessage.payload.rawPayload, Date.now()) ?? new Date).getTime();
|
|
339957
340025
|
if (msgTimestamp < resumedAt) {
|
|
339958
340026
|
log99.debug("Dropping pre-resume message (arrived during handoff window)", {
|
|
339959
340027
|
instanceId: instance4.id,
|
|
@@ -340003,7 +340071,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
340003
340071
|
error: String(error3),
|
|
340004
340072
|
traceId
|
|
340005
340073
|
});
|
|
340006
|
-
sendErrorFeedback(channel5, instance4.id, chatId, error3).catch(() => {});
|
|
340074
|
+
sendErrorFeedback(channel5, instance4.id, chatId, error3, resolveDispatchErrorMessage(null)).catch(() => {});
|
|
340007
340075
|
} finally {
|
|
340008
340076
|
ackHandle.remove();
|
|
340009
340077
|
}
|
|
@@ -340041,7 +340109,7 @@ function createOpenClawProviderInstance(provider, instance4) {
|
|
|
340041
340109
|
const schemaConfig = provider.schemaConfig ?? {};
|
|
340042
340110
|
const providerConfig = {
|
|
340043
340111
|
defaultAgentId: resolveRequiredAgentId(instance4, schemaConfig, provider.id, "defaultAgentId"),
|
|
340044
|
-
agentTimeoutMs: (instance4.agentTimeout ?? provider.defaultTimeout ??
|
|
340112
|
+
agentTimeoutMs: (instance4.agentTimeout ?? provider.defaultTimeout ?? 600) * 1000,
|
|
340045
340113
|
sendAckTimeoutMs: 1e4,
|
|
340046
340114
|
prefixSenderName: instance4.agentPrefixSenderName ?? true
|
|
340047
340115
|
};
|
|
@@ -340085,7 +340153,7 @@ function createClaudeCodeProviderInstance(provider, instance4, db2) {
|
|
|
340085
340153
|
maxTurns: schemaConfig.maxTurns,
|
|
340086
340154
|
pathToClaudeCodeExecutable: schemaConfig.pathToClaudeCodeExecutable
|
|
340087
340155
|
}, createSessionStorage(db2, provider.id), {
|
|
340088
|
-
timeoutMs: (instance4.agentTimeout ?? provider.defaultTimeout ??
|
|
340156
|
+
timeoutMs: (instance4.agentTimeout ?? provider.defaultTimeout ?? 600) * 1000,
|
|
340089
340157
|
enableAutoSplit: instance4.enableAutoSplit ?? true,
|
|
340090
340158
|
prefixSenderName: instance4.agentPrefixSenderName ?? true,
|
|
340091
340159
|
streamConfig: schemaConfig.streamConfig
|
|
@@ -340097,7 +340165,7 @@ function createWebhookProvider(provider) {
|
|
|
340097
340165
|
webhookUrl: provider.baseUrl,
|
|
340098
340166
|
apiKey: provider.apiKey ?? undefined,
|
|
340099
340167
|
mode: schemaConfig.mode ?? "round-trip",
|
|
340100
|
-
timeoutMs: (provider.defaultTimeout ??
|
|
340168
|
+
timeoutMs: (provider.defaultTimeout ?? 600) * 1000,
|
|
340101
340169
|
retries: schemaConfig.retries ?? 1
|
|
340102
340170
|
});
|
|
340103
340171
|
}
|
|
@@ -340570,7 +340638,7 @@ function isInboundTooStale(rawPayload, maxAgeMinutes, now = Date.now()) {
|
|
|
340570
340638
|
if (maxAgeMinutes <= 0) {
|
|
340571
340639
|
return { stale: false, ageMs: 0, maxAgeMs };
|
|
340572
340640
|
}
|
|
340573
|
-
const platformTs = extractPlatformTimestamp(rawPayload, now);
|
|
340641
|
+
const platformTs = extractPlatformTimestamp(rawPayload, now) ?? new Date(now);
|
|
340574
340642
|
const ageMs = now - platformTs.getTime();
|
|
340575
340643
|
return { stale: ageMs > maxAgeMs, ageMs, maxAgeMs };
|
|
340576
340644
|
}
|
|
@@ -341130,7 +341198,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
341130
341198
|
log99.info("Agent dispatcher shutdown complete");
|
|
341131
341199
|
};
|
|
341132
341200
|
}
|
|
341133
|
-
var import_api32, log99, agentDispatchLimiter, _natsGenieProviderCtor, QUOTED_MESSAGE_MAX_CHARS = 4000, DM_HISTORY_LIMIT = 20, LIFECYCLE_PREVIEW_MAX_CHARS = 160, LIFECYCLE_SENSITIVE_KEY_PARTS, 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, MEDIA_WAIT_TIMEOUT_MS = 30000, DEFAULT_SEND_MEDIA_PATH_TYPES, BOT_PREFIX = "\uD83E\uDD16 ", activeStreams, sessionActivityStore, PROC_REACT_START, PROC_REACT_DONE = "\u2705", providerCache, openclawClientPool, nullFilterWarnedInstances, ACTIVE_OWNER_IDENTIFIER_CACHE_TTL_MS = 1e4, cachedActiveOwnerIdentifiers = null, cachedActiveOwnerIdentifiersAt = 0, DEFAULT_GATE_MODEL = "gemini-3-flash-preview", GATE_TIMEOUT_MS = 3000, setupAgentResponder;
|
|
341201
|
+
var import_api32, log99, agentDispatchLimiter, _natsGenieProviderCtor, QUOTED_MESSAGE_MAX_CHARS = 4000, DM_HISTORY_LIMIT = 20, LIFECYCLE_PREVIEW_MAX_CHARS = 160, LIFECYCLE_SENSITIVE_KEY_PARTS, DEFAULT_DISPATCH_ERROR_MESSAGE = "\u26A0\uFE0F Sorry, I ran into an issue processing your message. Please try again.", 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, MEDIA_WAIT_TIMEOUT_MS = 30000, DEFAULT_SEND_MEDIA_PATH_TYPES, BOT_PREFIX = "\uD83E\uDD16 ", activeStreams, sessionActivityStore, PROC_REACT_START, PROC_REACT_DONE = "\u2705", providerCache, openclawClientPool, nullFilterWarnedInstances, ACTIVE_OWNER_IDENTIFIER_CACHE_TTL_MS = 1e4, cachedActiveOwnerIdentifiers = null, cachedActiveOwnerIdentifiersAt = 0, DEFAULT_GATE_MODEL = "gemini-3-flash-preview", GATE_TIMEOUT_MS = 3000, setupAgentResponder;
|
|
341134
341202
|
var init_agent_dispatcher = __esm(() => {
|
|
341135
341203
|
init_src2();
|
|
341136
341204
|
init_src();
|
|
@@ -342156,6 +342224,9 @@ import { spawn as spawn5 } from "child_process";
|
|
|
342156
342224
|
import { promises as fs15 } from "fs";
|
|
342157
342225
|
import { tmpdir as tmpdir12 } from "os";
|
|
342158
342226
|
import { join as join25 } from "path";
|
|
342227
|
+
function spawnWithEvents5(command, args) {
|
|
342228
|
+
return spawn5(command, args);
|
|
342229
|
+
}
|
|
342159
342230
|
var ELEVENLABS_API_URL = "https://api.elevenlabs.io/v1/text-to-speech", ELEVENLABS_VOICES_URL = "https://api.elevenlabs.io/v1/voices", TTSService;
|
|
342160
342231
|
var init_tts3 = __esm(() => {
|
|
342161
342232
|
init_src();
|
|
@@ -342265,7 +342336,7 @@ var init_tts3 = __esm(() => {
|
|
|
342265
342336
|
try {
|
|
342266
342337
|
await fs15.writeFile(inputPath, mp3Buffer);
|
|
342267
342338
|
await new Promise((resolve3, reject) => {
|
|
342268
|
-
const ffmpeg =
|
|
342339
|
+
const ffmpeg = spawnWithEvents5("ffmpeg", [
|
|
342269
342340
|
"-i",
|
|
342270
342341
|
inputPath,
|
|
342271
342342
|
"-c:a",
|
|
@@ -342311,7 +342382,7 @@ var init_tts3 = __esm(() => {
|
|
|
342311
342382
|
try {
|
|
342312
342383
|
await fs15.writeFile(tempPath, audioBuffer);
|
|
342313
342384
|
return await new Promise((resolve3) => {
|
|
342314
|
-
const ffprobe =
|
|
342385
|
+
const ffprobe = spawnWithEvents5("ffprobe", [
|
|
342315
342386
|
"-i",
|
|
342316
342387
|
tempPath,
|
|
342317
342388
|
"-show_entries",
|
|
@@ -347458,7 +347529,7 @@ function registerMessageSchemas(registry4) {
|
|
|
347458
347529
|
operationId: "sendPresence",
|
|
347459
347530
|
tags: ["Messages", "Presence"],
|
|
347460
347531
|
summary: "Send presence indicator",
|
|
347461
|
-
description: "Send typing/recording indicator in a chat.
|
|
347532
|
+
description: "Send typing/recording indicator in a chat. WhatsApp supports typing, recording, paused. Discord supports typing. Slack supports AI Assistant thread status via threadId or the active thread cache; omit duration to keep Slack status until reply cleanup or Slack timeout.",
|
|
347462
347533
|
request: { body: { content: { "application/json": { schema: SendPresenceSchema } } } },
|
|
347463
347534
|
responses: {
|
|
347464
347535
|
200: {
|
|
@@ -347644,13 +347715,22 @@ var init_messages4 = __esm(() => {
|
|
|
347644
347715
|
instanceId: exports_external.string().uuid().openapi({ description: "Instance ID to send from" }),
|
|
347645
347716
|
to: exports_external.string().min(1).openapi({ description: "Chat ID to show presence in" }),
|
|
347646
347717
|
type: exports_external.enum(["typing", "recording", "paused"]).openapi({ description: "Presence type" }),
|
|
347647
|
-
|
|
347718
|
+
threadId: exports_external.string().optional().openapi({ description: "Thread timestamp/id for thread-scoped presence surfaces such as Slack AI Assistant" }),
|
|
347719
|
+
status: exports_external.string().min(1).max(100).optional().openapi({ description: "Custom status text for channels that support text status, such as Slack AI Assistant" }),
|
|
347720
|
+
loadingMessages: exports_external.array(exports_external.string().min(1).max(100)).max(10).optional().openapi({ description: "Rotating loading messages for channels that support them, such as Slack AI Assistant" }),
|
|
347721
|
+
duration: exports_external.number().int().min(0).max(30000).optional().openapi({ description: "Duration in ms before auto-pause; omit for channel default, 0 = until paused" })
|
|
347648
347722
|
});
|
|
347649
347723
|
PresenceResponseSchema = exports_external.object({
|
|
347650
347724
|
instanceId: exports_external.string().uuid().openapi({ description: "Instance ID" }),
|
|
347651
347725
|
chatId: exports_external.string().openapi({ description: "Chat ID where presence was sent" }),
|
|
347652
347726
|
type: exports_external.string().openapi({ description: "Presence type sent" }),
|
|
347653
|
-
duration: exports_external.number().openapi({ description: "Duration in ms" })
|
|
347727
|
+
duration: exports_external.number().openapi({ description: "Duration in ms" }),
|
|
347728
|
+
threadId: exports_external.string().optional().openapi({ description: "Thread timestamp/id used by the presence renderer" }),
|
|
347729
|
+
delivered: exports_external.boolean().optional().openapi({ description: "Whether the channel reported the status as delivered" }),
|
|
347730
|
+
method: exports_external.string().optional().openapi({ description: "Channel-specific presence method used" }),
|
|
347731
|
+
reason: exports_external.string().optional().openapi({ description: "Reason when the channel no-opped or failed best-effort" }),
|
|
347732
|
+
status: exports_external.string().optional().openapi({ description: "Channel-specific status text sent" }),
|
|
347733
|
+
loadingMessages: exports_external.array(exports_external.string()).optional().openapi({ description: "Channel-specific rotating loading messages sent" })
|
|
347654
347734
|
});
|
|
347655
347735
|
MarkMessageReadSchema = exports_external.object({
|
|
347656
347736
|
instanceId: exports_external.string().uuid().openapi({ description: "Instance ID" })
|
|
@@ -356675,6 +356755,9 @@ async function computeCloseContactTerminalState(db2, chatUuid, outcome, auditRow
|
|
|
356675
356755
|
const closeUntil = cfg.cooldownMs !== null ? new Date(Date.now() + cfg.cooldownMs) : null;
|
|
356676
356756
|
return { terminal: false, escalated: false, closeUntil };
|
|
356677
356757
|
}
|
|
356758
|
+
function hasPresenceStatusSender(plugin7) {
|
|
356759
|
+
return typeof plugin7 === "object" && plugin7 !== null && "sendPresenceStatus" in plugin7 && typeof plugin7.sendPresenceStatus === "function";
|
|
356760
|
+
}
|
|
356678
356761
|
async function verifyMessageInstanceOwnership(services, message2, instanceId) {
|
|
356679
356762
|
if (!message2.chatId)
|
|
356680
356763
|
return;
|
|
@@ -357881,31 +357964,57 @@ var init_messages5 = __esm(() => {
|
|
|
357881
357964
|
instanceId: exports_external.string().uuid().describe("Instance ID to send from"),
|
|
357882
357965
|
to: exports_external.string().min(1).describe("Chat ID to show presence in"),
|
|
357883
357966
|
type: exports_external.enum(["typing", "recording", "paused"]).describe("Presence type"),
|
|
357884
|
-
|
|
357967
|
+
threadId: exports_external.string().min(1).optional().describe("Thread timestamp/id for thread-scoped presence surfaces"),
|
|
357968
|
+
status: exports_external.string().min(1).max(100).optional().describe("Custom status text for channels that support it"),
|
|
357969
|
+
loadingMessages: exports_external.array(exports_external.string().min(1).max(100)).max(10).optional().describe("Rotating loading messages for channels that support them"),
|
|
357970
|
+
duration: exports_external.number().int().min(0).max(30000).optional().describe("Duration in ms before auto-pause; omit for channel default, 0 = until paused")
|
|
357885
357971
|
});
|
|
357886
357972
|
messagesRoutes.post("/send/presence", zValidator("json", sendPresenceSchema), async (c) => {
|
|
357887
|
-
const { instanceId, to, type, duration } = c.req.valid("json");
|
|
357973
|
+
const { instanceId, to, type, duration, threadId: threadId2, status, loadingMessages } = c.req.valid("json");
|
|
357888
357974
|
const services = c.get("services");
|
|
357889
357975
|
checkInstanceAccess2(c.get("apiKey"), instanceId);
|
|
357890
|
-
const { instance: instance4, plugin: plugin7 } = await getPluginForInstance2(services, c.get("channelRegistry"), instanceId
|
|
357976
|
+
const { instance: instance4, plugin: plugin7 } = await getPluginForInstance2(services, c.get("channelRegistry"), instanceId);
|
|
357891
357977
|
const resolvedTo = await resolveRecipient(to, instance4.channel, services);
|
|
357892
|
-
|
|
357978
|
+
const canSendNativeTyping = plugin7.capabilities.canSendTyping === true;
|
|
357979
|
+
const canSendThreadStatus = hasPresenceStatusSender(plugin7);
|
|
357980
|
+
if (!canSendNativeTyping && !canSendThreadStatus) {
|
|
357893
357981
|
throw new OmniError({
|
|
357894
357982
|
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
357895
|
-
message: `Channel ${instance4.channel}
|
|
357983
|
+
message: `Channel ${instance4.channel} does not support typing indicators or thread status`,
|
|
357896
357984
|
context: { channelType: instance4.channel },
|
|
357897
357985
|
recoverable: false
|
|
357898
357986
|
});
|
|
357899
357987
|
}
|
|
357900
|
-
const effectiveDuration = type === "paused" ? 0 : duration;
|
|
357901
|
-
await plugin7.
|
|
357988
|
+
const effectiveDuration = type === "paused" ? 0 : duration ?? (canSendThreadStatus ? 0 : 5000);
|
|
357989
|
+
const presenceResult = canSendThreadStatus ? await plugin7.sendPresenceStatus(instanceId, resolvedTo, type, effectiveDuration, {
|
|
357990
|
+
threadId: threadId2,
|
|
357991
|
+
status,
|
|
357992
|
+
loadingMessages
|
|
357993
|
+
}) : await (async () => {
|
|
357994
|
+
if (!("sendTyping" in plugin7) || typeof plugin7.sendTyping !== "function") {
|
|
357995
|
+
throw new OmniError({
|
|
357996
|
+
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
357997
|
+
message: `Channel ${instance4.channel} plugin does not implement sendTyping`,
|
|
357998
|
+
context: { channelType: instance4.channel },
|
|
357999
|
+
recoverable: false
|
|
358000
|
+
});
|
|
358001
|
+
}
|
|
358002
|
+
await plugin7.sendTyping(instanceId, resolvedTo, effectiveDuration);
|
|
358003
|
+
return { delivered: true, method: "typing_indicator" };
|
|
358004
|
+
})();
|
|
357902
358005
|
return c.json({
|
|
357903
358006
|
success: true,
|
|
357904
358007
|
data: {
|
|
357905
358008
|
instanceId,
|
|
357906
358009
|
chatId: resolvedTo,
|
|
357907
358010
|
type,
|
|
357908
|
-
duration: effectiveDuration
|
|
358011
|
+
duration: effectiveDuration,
|
|
358012
|
+
threadId: presenceResult?.threadId ?? threadId2,
|
|
358013
|
+
delivered: presenceResult?.delivered ?? true,
|
|
358014
|
+
method: presenceResult?.method ?? "typing_indicator",
|
|
358015
|
+
reason: presenceResult?.reason,
|
|
358016
|
+
status: presenceResult?.status,
|
|
358017
|
+
loadingMessages: presenceResult?.loadingMessages
|
|
357909
358018
|
}
|
|
357910
358019
|
});
|
|
357911
358020
|
});
|
|
@@ -368022,38 +368131,39 @@ function setupReactionHandlers2(app, instanceId, botUserId, callbacks, logger5)
|
|
|
368022
368131
|
}
|
|
368023
368132
|
|
|
368024
368133
|
// ../channel-slack/src/handlers/typing.ts
|
|
368025
|
-
var TYPING_STATUS = "is typing...";
|
|
368026
368134
|
var CLEAR_STATUS = "";
|
|
368027
368135
|
async function setSlackThreadStatus(params) {
|
|
368028
|
-
const { client, channelId, threadTs, status, logger: logger5, instanceId } = params;
|
|
368136
|
+
const { client, channelId, threadTs, status, loadingMessages, logger: logger5, instanceId } = params;
|
|
368029
368137
|
if (!threadTs)
|
|
368030
|
-
return;
|
|
368138
|
+
return false;
|
|
368031
368139
|
const payload = {
|
|
368032
368140
|
channel_id: channelId,
|
|
368033
368141
|
thread_ts: threadTs,
|
|
368034
|
-
status
|
|
368142
|
+
status,
|
|
368143
|
+
...loadingMessages?.length ? { loading_messages: loadingMessages } : {}
|
|
368035
368144
|
};
|
|
368036
368145
|
try {
|
|
368037
368146
|
const clientAny = client;
|
|
368038
368147
|
if (typeof clientAny.assistant?.threads?.setStatus === "function") {
|
|
368039
368148
|
await clientAny.assistant.threads.setStatus(payload);
|
|
368040
|
-
return;
|
|
368149
|
+
return true;
|
|
368041
368150
|
}
|
|
368042
368151
|
if (typeof clientAny.apiCall === "function") {
|
|
368043
368152
|
await clientAny.apiCall("assistant.threads.setStatus", payload);
|
|
368153
|
+
return true;
|
|
368044
368154
|
}
|
|
368045
368155
|
} catch (err) {
|
|
368046
368156
|
logger5.warn("setSlackThreadStatus: failed", {
|
|
368047
368157
|
instanceId,
|
|
368048
368158
|
channelId,
|
|
368049
368159
|
threadTs,
|
|
368050
|
-
status,
|
|
368160
|
+
clearing: status.length === 0,
|
|
368161
|
+
statusLength: status.length,
|
|
368162
|
+
loadingMessageCount: loadingMessages?.length ?? 0,
|
|
368051
368163
|
error: String(err)
|
|
368052
368164
|
});
|
|
368053
368165
|
}
|
|
368054
|
-
|
|
368055
|
-
async function setTypingStatus(params) {
|
|
368056
|
-
return setSlackThreadStatus({ ...params, status: TYPING_STATUS });
|
|
368166
|
+
return false;
|
|
368057
368167
|
}
|
|
368058
368168
|
async function clearTypingStatus(params) {
|
|
368059
368169
|
return setSlackThreadStatus({ ...params, status: CLEAR_STATUS });
|
|
@@ -368553,6 +368663,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
368553
368663
|
debouncers = new Map;
|
|
368554
368664
|
threadCaches = new Map;
|
|
368555
368665
|
activeThreads = new Map;
|
|
368666
|
+
presenceStatusTimers = new Map;
|
|
368556
368667
|
pendingAckReactions = new Map;
|
|
368557
368668
|
async onInitialize(_context) {}
|
|
368558
368669
|
async onDestroy() {
|
|
@@ -368575,6 +368686,10 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
368575
368686
|
cache2.dispose();
|
|
368576
368687
|
}
|
|
368577
368688
|
this.threadCaches.clear();
|
|
368689
|
+
for (const timer of this.presenceStatusTimers.values()) {
|
|
368690
|
+
clearTimeout(timer);
|
|
368691
|
+
}
|
|
368692
|
+
this.presenceStatusTimers.clear();
|
|
368578
368693
|
this.activeThreads.clear();
|
|
368579
368694
|
this.pendingAckReactions.clear();
|
|
368580
368695
|
}
|
|
@@ -368673,6 +368788,12 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
368673
368788
|
if (key.startsWith(`${instanceId}:`))
|
|
368674
368789
|
this.activeThreads.delete(key);
|
|
368675
368790
|
}
|
|
368791
|
+
for (const [key, timer] of this.presenceStatusTimers) {
|
|
368792
|
+
if (!key.startsWith(`${instanceId}:`))
|
|
368793
|
+
continue;
|
|
368794
|
+
clearTimeout(timer);
|
|
368795
|
+
this.presenceStatusTimers.delete(key);
|
|
368796
|
+
}
|
|
368676
368797
|
for (const key of this.pendingAckReactions.keys()) {
|
|
368677
368798
|
if (key.startsWith(`${instanceId}:`))
|
|
368678
368799
|
this.pendingAckReactions.delete(key);
|
|
@@ -368777,27 +368898,75 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
368777
368898
|
};
|
|
368778
368899
|
}
|
|
368779
368900
|
async sendTyping(instanceId, chatId, duration) {
|
|
368901
|
+
await this.sendPresenceStatus(instanceId, chatId, duration === 0 ? "paused" : "typing", duration);
|
|
368902
|
+
}
|
|
368903
|
+
async sendPresenceStatus(instanceId, chatId, type, duration, options) {
|
|
368904
|
+
const method = "assistant.threads.setStatus";
|
|
368780
368905
|
const connection = this.connections.get(instanceId);
|
|
368781
368906
|
if (!connection)
|
|
368782
|
-
return;
|
|
368783
|
-
const threadTs = this.activeThreads.get(`${instanceId}:${chatId}`);
|
|
368907
|
+
return { delivered: false, method, reason: "not_connected" };
|
|
368908
|
+
const threadTs = options?.threadId ?? this.activeThreads.get(`${instanceId}:${chatId}`);
|
|
368784
368909
|
if (!threadTs)
|
|
368785
|
-
return;
|
|
368786
|
-
|
|
368787
|
-
|
|
368788
|
-
|
|
368789
|
-
|
|
368790
|
-
|
|
368791
|
-
|
|
368792
|
-
|
|
368793
|
-
|
|
368794
|
-
|
|
368795
|
-
|
|
368796
|
-
|
|
368797
|
-
|
|
368798
|
-
|
|
368799
|
-
|
|
368910
|
+
return { delivered: false, method, reason: "no_active_thread" };
|
|
368911
|
+
const shouldClear = type === "paused";
|
|
368912
|
+
const status = shouldClear ? "" : options?.status ?? (type === "recording" ? "is recording..." : "is typing...");
|
|
368913
|
+
const timerKey = this.presenceStatusTimerKey(instanceId, chatId, threadTs);
|
|
368914
|
+
const delivered = status === "" ? await clearTypingStatus({
|
|
368915
|
+
client: connection.client,
|
|
368916
|
+
channelId: chatId,
|
|
368917
|
+
threadTs,
|
|
368918
|
+
logger: this.logger
|
|
368919
|
+
}) : await setSlackThreadStatus({
|
|
368920
|
+
client: connection.client,
|
|
368921
|
+
channelId: chatId,
|
|
368922
|
+
threadTs,
|
|
368923
|
+
status,
|
|
368924
|
+
loadingMessages: options?.loadingMessages,
|
|
368925
|
+
logger: this.logger
|
|
368926
|
+
});
|
|
368927
|
+
if (delivered) {
|
|
368928
|
+
this.clearPresenceStatusTimer(timerKey);
|
|
368800
368929
|
}
|
|
368930
|
+
if (delivered && status !== "" && duration && duration > 0) {
|
|
368931
|
+
const timer = setTimeout(() => {
|
|
368932
|
+
if (this.presenceStatusTimers.get(timerKey) !== timer)
|
|
368933
|
+
return;
|
|
368934
|
+
this.presenceStatusTimers.delete(timerKey);
|
|
368935
|
+
clearTypingStatus({
|
|
368936
|
+
client: connection.client,
|
|
368937
|
+
channelId: chatId,
|
|
368938
|
+
threadTs,
|
|
368939
|
+
logger: this.logger
|
|
368940
|
+
}).catch((err) => {
|
|
368941
|
+
this.logger.warn("Slack presence status auto-clear failed", {
|
|
368942
|
+
instanceId,
|
|
368943
|
+
channelId: chatId,
|
|
368944
|
+
threadTs,
|
|
368945
|
+
error: String(err)
|
|
368946
|
+
});
|
|
368947
|
+
});
|
|
368948
|
+
}, duration);
|
|
368949
|
+
this.presenceStatusTimers.set(timerKey, timer);
|
|
368950
|
+
timer.unref?.();
|
|
368951
|
+
}
|
|
368952
|
+
return delivered ? { delivered: true, method, threadId: threadTs, status, loadingMessages: options?.loadingMessages } : {
|
|
368953
|
+
delivered: false,
|
|
368954
|
+
method,
|
|
368955
|
+
threadId: threadTs,
|
|
368956
|
+
status,
|
|
368957
|
+
loadingMessages: options?.loadingMessages,
|
|
368958
|
+
reason: "slack_status_failed"
|
|
368959
|
+
};
|
|
368960
|
+
}
|
|
368961
|
+
presenceStatusTimerKey(instanceId, channelId, threadTs) {
|
|
368962
|
+
return `${instanceId}:${channelId}:${threadTs}`;
|
|
368963
|
+
}
|
|
368964
|
+
clearPresenceStatusTimer(timerKey) {
|
|
368965
|
+
const timer = this.presenceStatusTimers.get(timerKey);
|
|
368966
|
+
if (!timer)
|
|
368967
|
+
return;
|
|
368968
|
+
clearTimeout(timer);
|
|
368969
|
+
this.presenceStatusTimers.delete(timerKey);
|
|
368801
368970
|
}
|
|
368802
368971
|
async editMessage(instanceId, channelId, messageTs, newText) {
|
|
368803
368972
|
const connection = this.getConnection(instanceId);
|
|
@@ -369039,6 +369208,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
369039
369208
|
threadTs: resolvedThread,
|
|
369040
369209
|
logger: this.logger
|
|
369041
369210
|
});
|
|
369211
|
+
this.clearPresenceStatusTimer(this.presenceStatusTimerKey(instanceId, channelId, resolvedThread));
|
|
369042
369212
|
}
|
|
369043
369213
|
getConnection(instanceId) {
|
|
369044
369214
|
const connection = this.connections.get(instanceId);
|
|
@@ -487766,30 +487936,44 @@ class WhatsAppPlugin extends BaseChannelPlugin {
|
|
|
487766
487936
|
}
|
|
487767
487937
|
this.reportHistorySyncProgress(instanceId, syncState, progress, isLatest, messages2.length);
|
|
487768
487938
|
}
|
|
487769
|
-
|
|
487770
|
-
if (!msg.key?.id || !msg.key?.remoteJid) {
|
|
487771
|
-
this.logger.debug("Skipping history message without key", { instanceId, hasKey: !!msg.key });
|
|
487772
|
-
return;
|
|
487773
|
-
}
|
|
487774
|
-
const timestamp = this.getMessageTimestamp(msg);
|
|
487939
|
+
isHistoryMessageWithinSyncRange(msg, timestamp, syncState, instanceId) {
|
|
487775
487940
|
if (syncState?.since && timestamp < syncState.since) {
|
|
487776
487941
|
this.logger.debug("Skipping history message - before since", {
|
|
487777
487942
|
instanceId,
|
|
487778
|
-
messageId: msg.key
|
|
487779
|
-
chatId: msg.key
|
|
487780
|
-
timestamp:
|
|
487943
|
+
messageId: msg.key?.id,
|
|
487944
|
+
chatId: msg.key?.remoteJid,
|
|
487945
|
+
timestamp: timestamp.toISOString(),
|
|
487781
487946
|
since: new Date(syncState.since).toISOString()
|
|
487782
487947
|
});
|
|
487783
|
-
return;
|
|
487948
|
+
return false;
|
|
487784
487949
|
}
|
|
487785
487950
|
if (syncState?.until && timestamp > syncState.until) {
|
|
487786
487951
|
this.logger.debug("Skipping history message - after until", {
|
|
487787
487952
|
instanceId,
|
|
487788
|
-
messageId: msg.key
|
|
487789
|
-
chatId: msg.key
|
|
487790
|
-
timestamp:
|
|
487953
|
+
messageId: msg.key?.id,
|
|
487954
|
+
chatId: msg.key?.remoteJid,
|
|
487955
|
+
timestamp: timestamp.toISOString(),
|
|
487791
487956
|
until: new Date(syncState.until).toISOString()
|
|
487792
487957
|
});
|
|
487958
|
+
return false;
|
|
487959
|
+
}
|
|
487960
|
+
return true;
|
|
487961
|
+
}
|
|
487962
|
+
async processHistoryMessage(instanceId, msg, syncState) {
|
|
487963
|
+
if (!msg.key?.id || !msg.key?.remoteJid) {
|
|
487964
|
+
this.logger.debug("Skipping history message without key", { instanceId, hasKey: !!msg.key });
|
|
487965
|
+
return;
|
|
487966
|
+
}
|
|
487967
|
+
const timestamp = this.getMessageTimestamp(msg);
|
|
487968
|
+
if (!timestamp) {
|
|
487969
|
+
this.logger.debug("Skipping history message without timestamp", {
|
|
487970
|
+
instanceId,
|
|
487971
|
+
messageId: msg.key.id,
|
|
487972
|
+
chatId: msg.key.remoteJid
|
|
487973
|
+
});
|
|
487974
|
+
return;
|
|
487975
|
+
}
|
|
487976
|
+
if (!this.isHistoryMessageWithinSyncRange(msg, timestamp, syncState, instanceId)) {
|
|
487793
487977
|
return;
|
|
487794
487978
|
}
|
|
487795
487979
|
const content = this.extractHistoryMessageContent(msg);
|
|
@@ -487878,8 +488062,10 @@ class WhatsAppPlugin extends BaseChannelPlugin {
|
|
|
487878
488062
|
}
|
|
487879
488063
|
getMessageTimestamp(msg) {
|
|
487880
488064
|
if (!msg.messageTimestamp)
|
|
487881
|
-
return
|
|
488065
|
+
return null;
|
|
487882
488066
|
const ts = typeof msg.messageTimestamp === "number" ? msg.messageTimestamp : Number(msg.messageTimestamp);
|
|
488067
|
+
if (!ts || Number.isNaN(ts))
|
|
488068
|
+
return null;
|
|
487883
488069
|
return new Date(ts * 1000);
|
|
487884
488070
|
}
|
|
487885
488071
|
reportHistorySyncProgress(instanceId, syncState, progress, isLatest, messageCount) {
|