@automagik/omni 2.260901.3 → 2.260902.1
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/commands/webhooks.d.ts +29 -0
- package/dist/commands/webhooks.d.ts.map +1 -1
- package/dist/index.js +92 -16
- package/dist/sdk/client.d.ts +81 -12
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/types.generated.d.ts +215 -3
- package/dist/sdk/types.generated.d.ts.map +1 -1
- package/dist/server/index.js +230 -94
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -242901,7 +242901,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
242901
242901
|
var require_package7 = __commonJS((exports, module) => {
|
|
242902
242902
|
module.exports = {
|
|
242903
242903
|
name: "@omni/api",
|
|
242904
|
-
version: "2.
|
|
242904
|
+
version: "2.260902.1",
|
|
242905
242905
|
type: "module",
|
|
242906
242906
|
exports: {
|
|
242907
242907
|
".": {
|
|
@@ -345619,6 +345619,10 @@ async function consumeStream(generator, sender, instanceId, chatId, traceId) {
|
|
|
345619
345619
|
function extractThreadId(messages4) {
|
|
345620
345620
|
return (messages4[0]?.payload.rawPayload ?? {}).threadId;
|
|
345621
345621
|
}
|
|
345622
|
+
function extractCancelThreadId(messages4) {
|
|
345623
|
+
const parsed = CancelThreadPayloadSchema.safeParse(messages4[0]?.payload.rawPayload ?? {});
|
|
345624
|
+
return (parsed.success ? parsed.data.cancelThreadId : undefined) ?? extractThreadId(messages4);
|
|
345625
|
+
}
|
|
345622
345626
|
function extractKhalSessionId(messages4) {
|
|
345623
345627
|
for (const message2 of messages4) {
|
|
345624
345628
|
const rawPayload = message2.payload.rawPayload ?? {};
|
|
@@ -345759,8 +345763,9 @@ async function dispatchViaStreamingProvider(services, instance4, messages4, trig
|
|
|
345759
345763
|
const streamKey = `${instance4.id}:${chatId}`;
|
|
345760
345764
|
activeStreams.set(streamKey, sender);
|
|
345761
345765
|
const cancelController = new AbortController;
|
|
345762
|
-
const runKey = runAbortKey(instance4.id, chatId,
|
|
345763
|
-
|
|
345766
|
+
const runKey = runAbortKey(instance4.id, chatId, extractCancelThreadId(messages4));
|
|
345767
|
+
const runEntry = { controller: cancelController, startedAt: Date.now(), sender };
|
|
345768
|
+
activeRunAborts.set(runKey, runEntry);
|
|
345764
345769
|
trigger.abortSignal = cancelController.signal;
|
|
345765
345770
|
const streamDispatchStart = Date.now();
|
|
345766
345771
|
try {
|
|
@@ -345794,7 +345799,8 @@ async function dispatchViaStreamingProvider(services, instance4, messages4, trig
|
|
|
345794
345799
|
return false;
|
|
345795
345800
|
} finally {
|
|
345796
345801
|
activeStreams.delete(streamKey);
|
|
345797
|
-
activeRunAborts.
|
|
345802
|
+
if (activeRunAborts.get(runKey) === runEntry)
|
|
345803
|
+
activeRunAborts.delete(runKey);
|
|
345798
345804
|
}
|
|
345799
345805
|
}
|
|
345800
345806
|
function formatMediaContent(msg) {
|
|
@@ -346004,10 +346010,11 @@ function resolveReplySuppression(flags) {
|
|
|
346004
346010
|
return "run_cancelled_by_user";
|
|
346005
346011
|
return null;
|
|
346006
346012
|
}
|
|
346007
|
-
async function triggerProviderWithCancellation(provider, trigger, spanAttributes, instanceId, chatId, traceId) {
|
|
346013
|
+
async function triggerProviderWithCancellation(provider, trigger, spanAttributes, instanceId, chatId, traceId, cancelThreadId = trigger.source.threadId) {
|
|
346008
346014
|
const cancelController = new AbortController;
|
|
346009
|
-
const runKey = runAbortKey(instanceId, chatId,
|
|
346010
|
-
|
|
346015
|
+
const runKey = runAbortKey(instanceId, chatId, cancelThreadId);
|
|
346016
|
+
const runEntry = { controller: cancelController, startedAt: Date.now() };
|
|
346017
|
+
activeRunAborts.set(runKey, runEntry);
|
|
346011
346018
|
try {
|
|
346012
346019
|
const result = await withLifecycleSpan("omni.dispatch_to_agno", spanAttributes, () => provider.trigger({
|
|
346013
346020
|
...trigger,
|
|
@@ -346022,7 +346029,8 @@ async function triggerProviderWithCancellation(provider, trigger, spanAttributes
|
|
|
346022
346029
|
}
|
|
346023
346030
|
throw err2;
|
|
346024
346031
|
} finally {
|
|
346025
|
-
activeRunAborts.
|
|
346032
|
+
if (activeRunAborts.get(runKey) === runEntry)
|
|
346033
|
+
activeRunAborts.delete(runKey);
|
|
346026
346034
|
}
|
|
346027
346035
|
}
|
|
346028
346036
|
async function dispatchViaProvider(services, instance4, messages4, triggerType, channel5, chatId, senderId, personId, senderName, traceId, rawEvent, db2, extraContextMessages, senderAgentId) {
|
|
@@ -346098,7 +346106,7 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
|
|
|
346098
346106
|
...lifecycleBase,
|
|
346099
346107
|
stage: "dispatch_to_agno",
|
|
346100
346108
|
extra: { trigger_type: triggerType, provider_id: provider.id, provider_schema: provider.schema }
|
|
346101
|
-
}), instance4.id, chatId, traceId);
|
|
346109
|
+
}), instance4.id, chatId, traceId, extractCancelThreadId(messages4));
|
|
346102
346110
|
if (!triggerOutcome)
|
|
346103
346111
|
return true;
|
|
346104
346112
|
const { result, cancelled: runCancelled } = triggerOutcome;
|
|
@@ -346488,6 +346496,7 @@ function takeQueuedAck(chatKey) {
|
|
|
346488
346496
|
}
|
|
346489
346497
|
async function ackQueuedMessage(info2) {
|
|
346490
346498
|
const chatKey = `${info2.instanceId}:${info2.chatId}`;
|
|
346499
|
+
let entry;
|
|
346491
346500
|
try {
|
|
346492
346501
|
const existing = queuedMessageAcks.get(chatKey);
|
|
346493
346502
|
if (existing && Date.now() - existing.at < QUEUED_ACK_TIMEOUT_MS)
|
|
@@ -346496,16 +346505,22 @@ async function ackQueuedMessage(info2) {
|
|
|
346496
346505
|
const messageId = info2.message.payload.externalId;
|
|
346497
346506
|
if (!instance4 || !messageId)
|
|
346498
346507
|
return;
|
|
346499
|
-
|
|
346508
|
+
entry = { at: Date.now() };
|
|
346500
346509
|
queuedMessageAcks.set(chatKey, entry);
|
|
346501
346510
|
const channel5 = info2.message.metadata.channelType ?? instance4.channel;
|
|
346502
346511
|
const plugin10 = await getPlugin(channel5) ?? null;
|
|
346503
|
-
|
|
346512
|
+
const handle = startAck(plugin10, createPluginAckProvider(plugin10), instance4.id, info2.chatId, messageId, channel5, {
|
|
346504
346513
|
...buildAckConfig(instance4),
|
|
346505
346514
|
ackTimeoutMs: QUEUED_ACK_TIMEOUT_MS
|
|
346506
346515
|
});
|
|
346516
|
+
if (queuedMessageAcks.get(chatKey) !== entry) {
|
|
346517
|
+
handle.release();
|
|
346518
|
+
return;
|
|
346519
|
+
}
|
|
346520
|
+
entry.handle = handle;
|
|
346507
346521
|
} catch (error3) {
|
|
346508
|
-
queuedMessageAcks.
|
|
346522
|
+
if (entry && queuedMessageAcks.get(chatKey) === entry)
|
|
346523
|
+
queuedMessageAcks.delete(chatKey);
|
|
346509
346524
|
log91.debug("Failed to ack queued message", { chatId: info2.chatId, error: String(error3) });
|
|
346510
346525
|
}
|
|
346511
346526
|
}
|
|
@@ -347876,7 +347891,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
347876
347891
|
log91.info("Agent dispatcher shutdown complete");
|
|
347877
347892
|
};
|
|
347878
347893
|
}
|
|
347879
|
-
var import_api32, log91, agentDispatchLimiter, _natsGenieProviderCtor, QUOTED_MESSAGE_MAX_CHARS = 4000, DM_HISTORY_LIMIT = 20, LIFECYCLE_PREVIEW_MAX_CHARS = 160, LIFECYCLE_SENSITIVE_KEY_PARTS, PRESENCE_DEFAULT_MIN_MS = 5000, PRESENCE_DEFAULT_MAX_WAIT_MS = 30000, activeMessageDebouncer = null, DEFAULT_DISPATCH_ERROR_MESSAGE = "Opa, tive um probleminha aqui \uD83D\uDE05 Pode mandar de novo?", DEFAULT_ERROR_HANDOFF_MESSAGE = "T\xF4 com um probleminha t\xE9cnico aqui agora. Logo algu\xE9m do time vai entrar em contato com voc\xEA.", 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, activeRunAborts, sessionActivityStore, PROC_REACT_START, PROC_REACT_DONE = "\u2705", queuedMessageAcks, QUEUED_ACK_TIMEOUT_MS = 120000, providerCache, openclawClientPool, _openClawClientCtor, nullFilterWarnedInstances, ACTIVE_OWNER_IDENTIFIER_CACHE_TTL_MS = 1e4, cachedActiveOwnerIdentifiers = null, cachedActiveOwnerIdentifiersAt = 0, tenantCachedActiveOwnerIdentifiers, DEFAULT_GATE_MODEL = "gemini-3-flash-preview", GATE_TIMEOUT_MS = 3000, setupAgentResponder;
|
|
347894
|
+
var import_api32, log91, agentDispatchLimiter, _natsGenieProviderCtor, QUOTED_MESSAGE_MAX_CHARS = 4000, DM_HISTORY_LIMIT = 20, LIFECYCLE_PREVIEW_MAX_CHARS = 160, LIFECYCLE_SENSITIVE_KEY_PARTS, PRESENCE_DEFAULT_MIN_MS = 5000, PRESENCE_DEFAULT_MAX_WAIT_MS = 30000, activeMessageDebouncer = null, DEFAULT_DISPATCH_ERROR_MESSAGE = "Opa, tive um probleminha aqui \uD83D\uDE05 Pode mandar de novo?", DEFAULT_ERROR_HANDOFF_MESSAGE = "T\xF4 com um probleminha t\xE9cnico aqui agora. Logo algu\xE9m do time vai entrar em contato com voc\xEA.", 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, activeRunAborts, CancelThreadPayloadSchema, sessionActivityStore, PROC_REACT_START, PROC_REACT_DONE = "\u2705", queuedMessageAcks, QUEUED_ACK_TIMEOUT_MS = 120000, providerCache, openclawClientPool, _openClawClientCtor, nullFilterWarnedInstances, ACTIVE_OWNER_IDENTIFIER_CACHE_TTL_MS = 1e4, cachedActiveOwnerIdentifiers = null, cachedActiveOwnerIdentifiersAt = 0, tenantCachedActiveOwnerIdentifiers, DEFAULT_GATE_MODEL = "gemini-3-flash-preview", GATE_TIMEOUT_MS = 3000, setupAgentResponder;
|
|
347880
347895
|
var init_agent_dispatcher = __esm(() => {
|
|
347881
347896
|
init_src2();
|
|
347882
347897
|
init_src();
|
|
@@ -347884,6 +347899,7 @@ var init_agent_dispatcher = __esm(() => {
|
|
|
347884
347899
|
init_src8();
|
|
347885
347900
|
init_esm5();
|
|
347886
347901
|
init_drizzle_orm();
|
|
347902
|
+
init_zod();
|
|
347887
347903
|
init_idempotency();
|
|
347888
347904
|
init_sentry_scrub();
|
|
347889
347905
|
init_agent_runner();
|
|
@@ -347934,6 +347950,7 @@ var init_agent_dispatcher = __esm(() => {
|
|
|
347934
347950
|
DEFAULT_SEND_MEDIA_PATH_TYPES = ["image", "video", "document"];
|
|
347935
347951
|
activeStreams = new Map;
|
|
347936
347952
|
activeRunAborts = new Map;
|
|
347953
|
+
CancelThreadPayloadSchema = exports_external.object({ cancelThreadId: exports_external.string().min(1).optional() });
|
|
347937
347954
|
sessionActivityStore = new InMemorySessionActivityStore;
|
|
347938
347955
|
PROC_REACT_START = { audio: "\uD83C\uDFA7", image: "\uD83D\uDC40", video: "\uD83D\uDC40", document: "\uD83D\uDC40" };
|
|
347939
347956
|
queuedMessageAcks = new Map;
|
|
@@ -352912,9 +352929,23 @@ function openProviderSecrets(tenantId, row) {
|
|
|
352912
352929
|
|
|
352913
352930
|
class ProviderService {
|
|
352914
352931
|
db;
|
|
352932
|
+
clientCacheInvalidators = [];
|
|
352915
352933
|
constructor(db2) {
|
|
352916
352934
|
this.db = db2;
|
|
352917
352935
|
}
|
|
352936
|
+
onProviderChanged(invalidate) {
|
|
352937
|
+
this.clientCacheInvalidators.push(invalidate);
|
|
352938
|
+
}
|
|
352939
|
+
invalidateCaches(providerId) {
|
|
352940
|
+
runAfterTenantCommit(() => {
|
|
352941
|
+
invalidateProviderCache(providerId);
|
|
352942
|
+
for (const invalidate of this.clientCacheInvalidators) {
|
|
352943
|
+
try {
|
|
352944
|
+
invalidate(providerId);
|
|
352945
|
+
} catch {}
|
|
352946
|
+
}
|
|
352947
|
+
});
|
|
352948
|
+
}
|
|
352918
352949
|
get tenantId() {
|
|
352919
352950
|
return currentTenantScope()?.tenantId ?? null;
|
|
352920
352951
|
}
|
|
@@ -352955,7 +352986,7 @@ class ProviderService {
|
|
|
352955
352986
|
if (!updated) {
|
|
352956
352987
|
throw new NotFoundError("AgentProvider", id);
|
|
352957
352988
|
}
|
|
352958
|
-
|
|
352989
|
+
this.invalidateCaches(id);
|
|
352959
352990
|
return openProviderSecrets(tenantId, updated);
|
|
352960
352991
|
}
|
|
352961
352992
|
async delete(id) {
|
|
@@ -352963,7 +352994,7 @@ class ProviderService {
|
|
|
352963
352994
|
if (!result.length) {
|
|
352964
352995
|
throw new NotFoundError("AgentProvider", id);
|
|
352965
352996
|
}
|
|
352966
|
-
|
|
352997
|
+
this.invalidateCaches(id);
|
|
352967
352998
|
}
|
|
352968
352999
|
async checkHealth(id) {
|
|
352969
353000
|
const provider = await this.getById(id);
|
|
@@ -355406,6 +355437,9 @@ function createServices(db2, eventBus) {
|
|
|
355406
355437
|
batchJobs2.setAuthPlane(authPlane.db);
|
|
355407
355438
|
const mediaStorage = new MediaStorageService(db2);
|
|
355408
355439
|
mediaStorage.setTenantAdmissibilityCheck((tenantId) => isTenantWorkAdmissible(authPlane.db, tenantId));
|
|
355440
|
+
const providers2 = new ProviderService(db2);
|
|
355441
|
+
const agentRunner = new AgentRunnerService(db2);
|
|
355442
|
+
providers2.onProviderChanged((providerId) => agentRunner.clearCache(providerId));
|
|
355409
355443
|
return {
|
|
355410
355444
|
agents: new AgentService(db2, eventBus),
|
|
355411
355445
|
agentState: new AgentStateService(eventBus),
|
|
@@ -355418,7 +355452,7 @@ function createServices(db2, eventBus) {
|
|
|
355418
355452
|
events: new EventService(db2),
|
|
355419
355453
|
settings,
|
|
355420
355454
|
access: new AccessService(db2, eventBus, accessCache),
|
|
355421
|
-
providers:
|
|
355455
|
+
providers: providers2,
|
|
355422
355456
|
routes: new RouteService(db2, routeResolver),
|
|
355423
355457
|
routeResolver,
|
|
355424
355458
|
deadLetters,
|
|
@@ -355430,7 +355464,7 @@ function createServices(db2, eventBus) {
|
|
|
355430
355464
|
messages: new MessageService(db2, eventBus),
|
|
355431
355465
|
syncJobs: new SyncJobService(db2, eventBus),
|
|
355432
355466
|
batchJobs: batchJobs2,
|
|
355433
|
-
agentRunner
|
|
355467
|
+
agentRunner,
|
|
355434
355468
|
tts,
|
|
355435
355469
|
turns: new TurnService(db2),
|
|
355436
355470
|
consumerOffsets: new ConsumerOffsetService(db2),
|
|
@@ -355833,6 +355867,13 @@ var init_error3 = __esm(() => {
|
|
|
355833
355867
|
});
|
|
355834
355868
|
|
|
355835
355869
|
// ../api/src/middleware/rate-limit.ts
|
|
355870
|
+
function resolveClientIp(trustedProxyHeaderValue, remoteAddr) {
|
|
355871
|
+
const raw2 = trustedProxyHeaderValue ?? remoteAddr;
|
|
355872
|
+
if (!raw2)
|
|
355873
|
+
return;
|
|
355874
|
+
const hops = raw2.split(",").map((hop) => hop.trim()).filter(Boolean);
|
|
355875
|
+
return hops.at(-1);
|
|
355876
|
+
}
|
|
355836
355877
|
function createRateLimiter2(config4 = RATE_LIMITS.general, keyPrefix = "ratelimit") {
|
|
355837
355878
|
return createMiddleware(async (c, next) => {
|
|
355838
355879
|
const apiKey = c.get("apiKey");
|
|
@@ -355840,8 +355881,7 @@ function createRateLimiter2(config4 = RATE_LIMITS.general, keyPrefix = "ratelimi
|
|
|
355840
355881
|
const trustedProxyIp = trustedProxyHeader ? c.req.header(trustedProxyHeader) : undefined;
|
|
355841
355882
|
const server = c.env;
|
|
355842
355883
|
const remoteAddr = server?.remoteAddr ?? server?.requestIP?.(c.req.raw)?.address;
|
|
355843
|
-
const
|
|
355844
|
-
const normalizedIp = rawIp?.split(",")[0]?.trim() || undefined;
|
|
355884
|
+
const normalizedIp = resolveClientIp(trustedProxyIp, remoteAddr);
|
|
355845
355885
|
const identifier = apiKey?.id ? `api:${apiKey.id}` : normalizedIp ? `ip:${normalizedIp}` : "anon";
|
|
355846
355886
|
const key = `${keyPrefix}:${identifier}`;
|
|
355847
355887
|
const now = Date.now();
|
|
@@ -360507,7 +360547,10 @@ var init_messages4 = __esm(() => {
|
|
|
360507
360547
|
instanceId: exports_external.string().uuid().openapi({ description: "Instance UUID" }),
|
|
360508
360548
|
to: exports_external.string().openapi({ description: "Recipient" }),
|
|
360509
360549
|
audioSizeKb: exports_external.number().openapi({ description: "Audio size in KB" }),
|
|
360510
|
-
durationMs: exports_external.number().openapi({ description: "Audio duration in ms" })
|
|
360550
|
+
durationMs: exports_external.number().openapi({ description: "Audio duration in ms" }),
|
|
360551
|
+
senderAgentId: exports_external.string().uuid().nullable().optional().openapi({
|
|
360552
|
+
description: "Present when the request set sentBy: 'agent' \u2014 the agent the send was attributed to, or null when the instance has no configured agent (attribution did not happen)"
|
|
360553
|
+
})
|
|
360511
360554
|
});
|
|
360512
360555
|
});
|
|
360513
360556
|
|
|
@@ -361627,6 +361670,7 @@ var init_voice = __esm(() => {
|
|
|
361627
361670
|
|
|
361628
361671
|
// ../api/src/schemas/openapi/webhooks.ts
|
|
361629
361672
|
function registerWebhookSchemas(registry4) {
|
|
361673
|
+
registry4.register("WebhookSignatureConfig", WebhookSignatureConfigSchema);
|
|
361630
361674
|
registry4.register("WebhookSource", WebhookSourceSchema);
|
|
361631
361675
|
registry4.register("CreateWebhookSourceRequest", CreateWebhookSourceSchema);
|
|
361632
361676
|
registry4.register("TriggerEventRequest", TriggerEventSchema);
|
|
@@ -361767,16 +361811,22 @@ function registerWebhookSchemas(registry4) {
|
|
|
361767
361811
|
}
|
|
361768
361812
|
var WebhookSignatureConfigSchema, WebhookSourceSchema, CreateWebhookSourceSchema, TriggerEventSchema, WebhookReceiveResponseSchema;
|
|
361769
361813
|
var init_webhooks2 = __esm(() => {
|
|
361814
|
+
init_src5();
|
|
361770
361815
|
init_zod_openapi();
|
|
361771
361816
|
init_common4();
|
|
361772
361817
|
WebhookSignatureConfigSchema = exports_external.object({
|
|
361773
|
-
algorithm: exports_external.enum(
|
|
361818
|
+
algorithm: exports_external.enum(webhookSignatureAlgorithms).openapi({
|
|
361774
361819
|
description: "How to verify: HMAC over the raw request body, or direct token match"
|
|
361775
361820
|
}),
|
|
361776
|
-
header: exports_external.string().openapi({
|
|
361777
|
-
|
|
361778
|
-
|
|
361821
|
+
header: exports_external.string().min(1).max(200).openapi({
|
|
361822
|
+
description: "Header carrying the signature/token (e.g. X-Hub-Signature-256). 1-200 characters"
|
|
361823
|
+
}),
|
|
361824
|
+
prefix: exports_external.string().max(50).optional().openapi({
|
|
361825
|
+
description: 'Prefix before the hex digest (e.g. "sha256="), at most 50 characters. HMAC algorithms only \u2014 rejected with token-match'
|
|
361779
361826
|
})
|
|
361827
|
+
}).refine((config4) => config4.algorithm !== "token-match" || config4.prefix === undefined, {
|
|
361828
|
+
message: "prefix is not applicable to algorithm 'token-match'",
|
|
361829
|
+
path: ["prefix"]
|
|
361780
361830
|
});
|
|
361781
361831
|
WebhookSourceSchema = exports_external.object({
|
|
361782
361832
|
id: exports_external.string().uuid().openapi({ description: "Source UUID" }),
|
|
@@ -361790,14 +361840,14 @@ var init_webhooks2 = __esm(() => {
|
|
|
361790
361840
|
updatedAt: exports_external.string().datetime().openapi({ description: "Last update timestamp" })
|
|
361791
361841
|
});
|
|
361792
361842
|
CreateWebhookSourceSchema = exports_external.object({
|
|
361793
|
-
name: exports_external.string().min(1).max(100).openapi({ description: "Unique source name" }),
|
|
361843
|
+
name: exports_external.string().min(1).max(100).openapi({ description: "Unique source name (e.g., github, stripe, agno)" }),
|
|
361794
361844
|
description: exports_external.string().optional().openapi({ description: "Description" }),
|
|
361795
361845
|
expectedHeaders: exports_external.record(exports_external.string(), exports_external.boolean()).optional().openapi({ description: "Headers to validate" }),
|
|
361796
361846
|
signatureConfig: WebhookSignatureConfigSchema.nullable().optional().openapi({
|
|
361797
|
-
description: "Signature verification config; required for the source to be reachable on the public ingress"
|
|
361847
|
+
description: "Signature verification config; required for the source to be reachable on the public ingress. " + "Always paired with signatureSecret: a config without a stored secret is rejected (400), and clearing " + "the config (null) also clears the stored secret."
|
|
361798
361848
|
}),
|
|
361799
361849
|
signatureSecret: exports_external.string().min(8).max(512).nullable().optional().openapi({
|
|
361800
|
-
description: "Shared secret used by signatureConfig (write-only, never returned)"
|
|
361850
|
+
description: "Shared secret used by signatureConfig (write-only, never returned; 8-512 characters). Cannot be set " + "without a signatureConfig (given in the same request, or already stored on update); null clears it."
|
|
361801
361851
|
}),
|
|
361802
361852
|
enabled: exports_external.boolean().default(true).openapi({ description: "Whether enabled" })
|
|
361803
361853
|
});
|
|
@@ -366451,7 +366501,7 @@ class AgentReplayService {
|
|
|
366451
366501
|
SELECT 1 FROM ${messages2} AS reply
|
|
366452
366502
|
WHERE reply.chat_id = ${messages2.chatId}
|
|
366453
366503
|
AND reply.is_from_me = true
|
|
366454
|
-
AND
|
|
366504
|
+
AND (reply.raw_payload -> 'omniSystemNotice') IS DISTINCT FROM 'true'::jsonb
|
|
366455
366505
|
AND reply.platform_timestamp > ${messages2.platformTimestamp}
|
|
366456
366506
|
AND reply.deleted_at IS NULL
|
|
366457
366507
|
)`, cursorId ? or2(gt(messages2.platformTimestamp, cursorTimestamp), and2(eq(messages2.platformTimestamp, cursorTimestamp), gt(messages2.id, cursorId))) : gt(messages2.platformTimestamp, cursorTimestamp), lte(messages2.platformTimestamp, now))).orderBy(asc(messages2.platformTimestamp), asc(messages2.id)).limit(PAGE_SIZE));
|
|
@@ -374151,35 +374201,41 @@ var init_voice2 = __esm(() => {
|
|
|
374151
374201
|
});
|
|
374152
374202
|
});
|
|
374153
374203
|
|
|
374204
|
+
// ../api/src/utils/json-body.ts
|
|
374205
|
+
function parseJsonObjectBody(rawBody) {
|
|
374206
|
+
if (!rawBody)
|
|
374207
|
+
return {};
|
|
374208
|
+
let parsed;
|
|
374209
|
+
try {
|
|
374210
|
+
parsed = JSON.parse(rawBody);
|
|
374211
|
+
} catch {
|
|
374212
|
+
throw new ValidationError2(NOT_AN_OBJECT);
|
|
374213
|
+
}
|
|
374214
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
374215
|
+
throw new ValidationError2(NOT_AN_OBJECT);
|
|
374216
|
+
}
|
|
374217
|
+
return parsed;
|
|
374218
|
+
}
|
|
374219
|
+
var NOT_AN_OBJECT = "Request body must be a JSON object";
|
|
374220
|
+
var init_json_body = __esm(() => {
|
|
374221
|
+
init_src();
|
|
374222
|
+
});
|
|
374223
|
+
|
|
374154
374224
|
// ../api/src/routes/v2/webhooks.ts
|
|
374155
374225
|
function sanitizeSource(source) {
|
|
374156
374226
|
const { signatureSecret, ...rest } = source;
|
|
374157
374227
|
return { ...rest, hasSignatureSecret: Boolean(signatureSecret) };
|
|
374158
374228
|
}
|
|
374159
|
-
var webhooksRoutes,
|
|
374229
|
+
var webhooksRoutes, createWebhookSourceSchema, updateWebhookSourceSchema, listQuerySchema21, triggerEventSchema;
|
|
374160
374230
|
var init_webhooks3 = __esm(() => {
|
|
374161
374231
|
init_dist6();
|
|
374162
|
-
init_src5();
|
|
374163
374232
|
init_dist2();
|
|
374164
374233
|
init_zod();
|
|
374234
|
+
init_webhooks2();
|
|
374165
374235
|
init_api_keys();
|
|
374236
|
+
init_json_body();
|
|
374166
374237
|
webhooksRoutes = new Hono2;
|
|
374167
|
-
|
|
374168
|
-
algorithm: exports_external.enum(webhookSignatureAlgorithms).describe("How to verify: HMAC over the raw body, or token match"),
|
|
374169
|
-
header: exports_external.string().min(1).max(200).describe("Header carrying the signature/token (e.g. X-Hub-Signature-256)"),
|
|
374170
|
-
prefix: exports_external.string().max(50).optional().describe("Prefix before the hex digest (HMAC algorithms only)")
|
|
374171
|
-
}).refine((config4) => config4.algorithm !== "token-match" || config4.prefix === undefined, {
|
|
374172
|
-
message: "prefix is not applicable to algorithm 'token-match'",
|
|
374173
|
-
path: ["prefix"]
|
|
374174
|
-
});
|
|
374175
|
-
createWebhookSourceSchema = exports_external.object({
|
|
374176
|
-
name: exports_external.string().min(1).max(100).describe("Unique source name (e.g., github, stripe, agno)"),
|
|
374177
|
-
description: exports_external.string().optional().describe("Description of the webhook source"),
|
|
374178
|
-
expectedHeaders: exports_external.record(exports_external.string(), exports_external.boolean()).optional().describe("Headers to validate"),
|
|
374179
|
-
signatureConfig: signatureConfigSchema.nullable().optional().describe("Signature verification config"),
|
|
374180
|
-
signatureSecret: exports_external.string().min(8).max(512).nullable().optional().describe("Shared secret (write-only)"),
|
|
374181
|
-
enabled: exports_external.boolean().default(true).describe("Whether source is enabled")
|
|
374182
|
-
});
|
|
374238
|
+
createWebhookSourceSchema = CreateWebhookSourceSchema;
|
|
374183
374239
|
updateWebhookSourceSchema = createWebhookSourceSchema.partial();
|
|
374184
374240
|
listQuerySchema21 = exports_external.object({
|
|
374185
374241
|
enabled: exports_external.coerce.boolean().optional()
|
|
@@ -374219,12 +374275,7 @@ var init_webhooks3 = __esm(() => {
|
|
|
374219
374275
|
const sourceName = c.req.param("source");
|
|
374220
374276
|
const services = c.get("services");
|
|
374221
374277
|
const rawBody = await c.req.text();
|
|
374222
|
-
|
|
374223
|
-
try {
|
|
374224
|
-
payload = rawBody ? JSON.parse(rawBody) : {};
|
|
374225
|
-
} catch {
|
|
374226
|
-
payload = {};
|
|
374227
|
-
}
|
|
374278
|
+
const payload = parseJsonObjectBody(rawBody);
|
|
374228
374279
|
const headers = {};
|
|
374229
374280
|
for (const [key, value] of Object.entries(c.req.header())) {
|
|
374230
374281
|
headers[key.toLowerCase()] = value ?? "";
|
|
@@ -375524,18 +375575,14 @@ function createApp(db2, eventBus = null, channelRegistry2 = null) {
|
|
|
375524
375575
|
const sourceName = c.req.param("source");
|
|
375525
375576
|
const services2 = c.get("services");
|
|
375526
375577
|
const rawBody = await c.req.text();
|
|
375527
|
-
let payload
|
|
375528
|
-
|
|
375529
|
-
|
|
375530
|
-
|
|
375531
|
-
|
|
375532
|
-
|
|
375533
|
-
parsed = undefined;
|
|
375534
|
-
}
|
|
375535
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
375536
|
-
return c.json({ error: { code: "VALIDATION", message: "Request body must be a JSON object" } }, 400);
|
|
375578
|
+
let payload;
|
|
375579
|
+
try {
|
|
375580
|
+
payload = parseJsonObjectBody(rawBody);
|
|
375581
|
+
} catch (error3) {
|
|
375582
|
+
if (error3 instanceof ValidationError2) {
|
|
375583
|
+
return c.json({ error: { code: "VALIDATION", message: error3.message } }, 400);
|
|
375537
375584
|
}
|
|
375538
|
-
|
|
375585
|
+
throw error3;
|
|
375539
375586
|
}
|
|
375540
375587
|
const headers = {};
|
|
375541
375588
|
for (const [key, value] of Object.entries(c.req.header())) {
|
|
@@ -375638,6 +375685,7 @@ var init_app = __esm(() => {
|
|
|
375638
375685
|
init_v2();
|
|
375639
375686
|
init_platform_tenants2();
|
|
375640
375687
|
init_a2a_discovery();
|
|
375688
|
+
init_json_body();
|
|
375641
375689
|
httpLog = createLogger("http");
|
|
375642
375690
|
});
|
|
375643
375691
|
|
|
@@ -385399,16 +385447,33 @@ async function checkBoltHealth(connection) {
|
|
|
385399
385447
|
}
|
|
385400
385448
|
|
|
385401
385449
|
// ../channel-slack/src/handlers/agent-sessions.ts
|
|
385450
|
+
init_zod();
|
|
385451
|
+
var AgentSessionStoppedEventSchema = exports_external.object({
|
|
385452
|
+
channel: exports_external.string().min(1),
|
|
385453
|
+
thread_ts: exports_external.string().optional(),
|
|
385454
|
+
user: exports_external.string().optional(),
|
|
385455
|
+
event_ts: exports_external.string().optional(),
|
|
385456
|
+
streaming_message_ts: exports_external.array(exports_external.string()).optional()
|
|
385457
|
+
}).passthrough();
|
|
385402
385458
|
function setupAgentSessionHandlers(app, instanceId, callbacks, logger5) {
|
|
385403
385459
|
app.event("agent_session_stopped", async ({ event }) => {
|
|
385404
|
-
const
|
|
385405
|
-
|
|
385406
|
-
if (!channelId)
|
|
385460
|
+
const channelHint = event?.channel;
|
|
385461
|
+
if (typeof channelHint !== "string" || channelHint.length === 0)
|
|
385407
385462
|
return;
|
|
385408
|
-
const
|
|
385409
|
-
|
|
385410
|
-
|
|
385411
|
-
|
|
385463
|
+
const parsed = AgentSessionStoppedEventSchema.safeParse(event);
|
|
385464
|
+
if (!parsed.success) {
|
|
385465
|
+
logger5.warn("Ignoring malformed agent_session_stopped event", {
|
|
385466
|
+
instanceId,
|
|
385467
|
+
channelId: channelHint,
|
|
385468
|
+
issues: parsed.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
|
385469
|
+
});
|
|
385470
|
+
return;
|
|
385471
|
+
}
|
|
385472
|
+
const channelId = parsed.data.channel;
|
|
385473
|
+
const threadTs = parsed.data.thread_ts;
|
|
385474
|
+
const userId = parsed.data.user;
|
|
385475
|
+
const eventTs = parsed.data.event_ts;
|
|
385476
|
+
const streamingMessageTs = parsed.data.streaming_message_ts ?? [];
|
|
385412
385477
|
logger5.info("Agent session stopped by user", { instanceId, channelId, threadTs, userId, streamingMessageTs });
|
|
385413
385478
|
await callbacks.onSessionStopped(instanceId, { channelId, threadTs, userId, streamingMessageTs, eventTs });
|
|
385414
385479
|
});
|
|
@@ -385739,6 +385804,7 @@ function buildRawPayload(meta, msg, extra) {
|
|
|
385739
385804
|
ts: meta.ts,
|
|
385740
385805
|
threadTs: meta.threadTs,
|
|
385741
385806
|
threadId: !meta.isDm && meta.threadTs ? meta.threadTs : undefined,
|
|
385807
|
+
cancelThreadId: meta.threadTs,
|
|
385742
385808
|
channelType: meta.channelType,
|
|
385743
385809
|
teamId: meta.teamId,
|
|
385744
385810
|
isDm: meta.isDm,
|
|
@@ -386354,6 +386420,7 @@ function createNativeStreamSender(options) {
|
|
|
386354
386420
|
} = options;
|
|
386355
386421
|
let streamer;
|
|
386356
386422
|
let lastSentContent = "";
|
|
386423
|
+
let streamTs;
|
|
386357
386424
|
let stopped = false;
|
|
386358
386425
|
let fallback;
|
|
386359
386426
|
function buildFallback() {
|
|
@@ -386384,7 +386451,7 @@ function createNativeStreamSender(options) {
|
|
|
386384
386451
|
channel: channelId,
|
|
386385
386452
|
...threadTs ? { thread_ts: threadTs } : {}
|
|
386386
386453
|
});
|
|
386387
|
-
await streamer.append({ markdown_text: firstChunk });
|
|
386454
|
+
noteStreamTs(await streamer.append({ markdown_text: firstChunk }));
|
|
386388
386455
|
lastSentContent = firstChunk;
|
|
386389
386456
|
} catch (err2) {
|
|
386390
386457
|
logger5.warn("native-stream: chat.startStream failed, falling back to replace mode", {
|
|
@@ -386394,12 +386461,27 @@ function createNativeStreamSender(options) {
|
|
|
386394
386461
|
fallback = buildFallback();
|
|
386395
386462
|
}
|
|
386396
386463
|
}
|
|
386464
|
+
function noteStreamTs(response) {
|
|
386465
|
+
if (streamTs || typeof response !== "object" || response === null)
|
|
386466
|
+
return;
|
|
386467
|
+
const ts = response.ts;
|
|
386468
|
+
if (typeof ts === "string" && ts.length > 0)
|
|
386469
|
+
streamTs = ts;
|
|
386470
|
+
}
|
|
386471
|
+
function resolveStreamTs() {
|
|
386472
|
+
if (streamTs)
|
|
386473
|
+
return streamTs;
|
|
386474
|
+
const fromStreamer = streamer?.streamTs;
|
|
386475
|
+
if (typeof fromStreamer === "string" && fromStreamer.length > 0)
|
|
386476
|
+
streamTs = fromStreamer;
|
|
386477
|
+
return streamTs;
|
|
386478
|
+
}
|
|
386397
386479
|
async function appendDelta(newContent) {
|
|
386398
386480
|
const delta = newContent.slice(lastSentContent.length);
|
|
386399
386481
|
if (!delta)
|
|
386400
386482
|
return;
|
|
386401
386483
|
try {
|
|
386402
|
-
await streamer?.append({ markdown_text: delta });
|
|
386484
|
+
noteStreamTs(await streamer?.append({ markdown_text: delta }));
|
|
386403
386485
|
lastSentContent = newContent;
|
|
386404
386486
|
} catch (err2) {
|
|
386405
386487
|
logger5.warn("native-stream: append failed", { error: String(err2) });
|
|
@@ -386459,6 +386541,16 @@ function createNativeStreamSender(options) {
|
|
|
386459
386541
|
if (fallback)
|
|
386460
386542
|
return fallback.cancel ? fallback.cancel() : fallback.abort();
|
|
386461
386543
|
await stopStream();
|
|
386544
|
+
},
|
|
386545
|
+
markStoppedByPlatform(stoppedTs) {
|
|
386546
|
+
if (fallback || stopped || !streamer)
|
|
386547
|
+
return false;
|
|
386548
|
+
const ts = resolveStreamTs();
|
|
386549
|
+
if (!ts || !stoppedTs.includes(ts))
|
|
386550
|
+
return false;
|
|
386551
|
+
stopped = true;
|
|
386552
|
+
logger5.debug("native-stream: stream already halted by Slack, skipping chat.stopStream", { channelId, ts });
|
|
386553
|
+
return true;
|
|
386462
386554
|
}
|
|
386463
386555
|
};
|
|
386464
386556
|
}
|
|
@@ -386620,6 +386712,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
386620
386712
|
activeThreads = new Map;
|
|
386621
386713
|
presenceStatusTimers = new Map;
|
|
386622
386714
|
pendingAckReactions = new Map;
|
|
386715
|
+
activeNativeStreams = new Map;
|
|
386623
386716
|
async onInitialize(_context) {}
|
|
386624
386717
|
async onDestroy() {
|
|
386625
386718
|
for (const [instanceId, connection] of this.connections) {
|
|
@@ -386647,6 +386740,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
386647
386740
|
this.presenceStatusTimers.clear();
|
|
386648
386741
|
this.activeThreads.clear();
|
|
386649
386742
|
this.pendingAckReactions.clear();
|
|
386743
|
+
this.activeNativeStreams.clear();
|
|
386650
386744
|
}
|
|
386651
386745
|
async connect(instanceId, config2) {
|
|
386652
386746
|
const existing = this.connections.get(instanceId);
|
|
@@ -386751,6 +386845,10 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
386751
386845
|
clearTimeout(timer);
|
|
386752
386846
|
this.presenceStatusTimers.delete(key);
|
|
386753
386847
|
}
|
|
386848
|
+
for (const key of this.activeNativeStreams.keys()) {
|
|
386849
|
+
if (key.startsWith(`${instanceId}:`))
|
|
386850
|
+
this.activeNativeStreams.delete(key);
|
|
386851
|
+
}
|
|
386754
386852
|
for (const key of this.pendingAckReactions.keys()) {
|
|
386755
386853
|
if (key.startsWith(`${instanceId}:`))
|
|
386756
386854
|
this.pendingAckReactions.delete(key);
|
|
@@ -386812,29 +386910,40 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
386812
386910
|
const threadTs = this.resolveThreadTs(replyToMode, replyToMessageId, undefined);
|
|
386813
386911
|
const streamMode = resolveStreamMode(slackConfig.streamMode);
|
|
386814
386912
|
const throttleMs = resolveStreamThrottle(slackConfig.streamThrottleMs);
|
|
386815
|
-
const
|
|
386816
|
-
|
|
386817
|
-
|
|
386818
|
-
|
|
386819
|
-
|
|
386820
|
-
|
|
386821
|
-
|
|
386822
|
-
|
|
386823
|
-
|
|
386824
|
-
|
|
386825
|
-
|
|
386826
|
-
|
|
386827
|
-
|
|
386828
|
-
|
|
386829
|
-
|
|
386830
|
-
|
|
386831
|
-
|
|
386832
|
-
|
|
386833
|
-
|
|
386834
|
-
|
|
386835
|
-
|
|
386836
|
-
|
|
386913
|
+
const streamKey = `${instanceId}:${chatId}`;
|
|
386914
|
+
let native;
|
|
386915
|
+
let base2;
|
|
386916
|
+
if (streamMode === "native") {
|
|
386917
|
+
native = createNativeStreamSender({
|
|
386918
|
+
client: connection.actingClient,
|
|
386919
|
+
channelId: chatId,
|
|
386920
|
+
threadTs,
|
|
386921
|
+
throttleMs,
|
|
386922
|
+
username: slackConfig.defaultUsername,
|
|
386923
|
+
iconUrl: slackConfig.defaultIconUrl,
|
|
386924
|
+
iconEmoji: slackConfig.defaultIconEmoji,
|
|
386925
|
+
formatMode: options?.formatMode ?? "convert",
|
|
386926
|
+
logger: this.logger
|
|
386927
|
+
});
|
|
386928
|
+
base2 = native;
|
|
386929
|
+
this.trackNativeStream(streamKey, native);
|
|
386930
|
+
} else {
|
|
386931
|
+
base2 = createSlackStreamSender({
|
|
386932
|
+
client: connection.actingClient,
|
|
386933
|
+
channelId: chatId,
|
|
386934
|
+
threadTs,
|
|
386935
|
+
streamMode,
|
|
386936
|
+
throttleMs,
|
|
386937
|
+
username: slackConfig.defaultUsername,
|
|
386938
|
+
iconUrl: slackConfig.defaultIconUrl,
|
|
386939
|
+
iconEmoji: slackConfig.defaultIconEmoji,
|
|
386940
|
+
formatMode: options?.formatMode ?? "convert",
|
|
386941
|
+
logger: this.logger
|
|
386942
|
+
});
|
|
386943
|
+
}
|
|
386837
386944
|
const cleanup = () => {
|
|
386945
|
+
if (native)
|
|
386946
|
+
this.untrackNativeStream(streamKey, native);
|
|
386838
386947
|
this.removeAckReaction(instanceId, chatId, connection, replyToMessageId, threadTs);
|
|
386839
386948
|
this.clearActiveTyping(instanceId, chatId, connection, threadTs).catch(() => {});
|
|
386840
386949
|
};
|
|
@@ -386859,6 +386968,32 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
386859
386968
|
}
|
|
386860
386969
|
};
|
|
386861
386970
|
}
|
|
386971
|
+
trackNativeStream(streamKey, sender) {
|
|
386972
|
+
let set = this.activeNativeStreams.get(streamKey);
|
|
386973
|
+
if (!set) {
|
|
386974
|
+
set = new Set;
|
|
386975
|
+
this.activeNativeStreams.set(streamKey, set);
|
|
386976
|
+
}
|
|
386977
|
+
set.add(sender);
|
|
386978
|
+
}
|
|
386979
|
+
untrackNativeStream(streamKey, sender) {
|
|
386980
|
+
const set = this.activeNativeStreams.get(streamKey);
|
|
386981
|
+
if (!set)
|
|
386982
|
+
return;
|
|
386983
|
+
set.delete(sender);
|
|
386984
|
+
if (set.size === 0)
|
|
386985
|
+
this.activeNativeStreams.delete(streamKey);
|
|
386986
|
+
}
|
|
386987
|
+
markStreamsStoppedByPlatform(instanceId, channelId, stoppedTs) {
|
|
386988
|
+
if (stoppedTs.length === 0)
|
|
386989
|
+
return;
|
|
386990
|
+
const senders2 = this.activeNativeStreams.get(`${instanceId}:${channelId}`);
|
|
386991
|
+
if (!senders2)
|
|
386992
|
+
return;
|
|
386993
|
+
for (const sender of senders2) {
|
|
386994
|
+
sender.markStoppedByPlatform(stoppedTs);
|
|
386995
|
+
}
|
|
386996
|
+
}
|
|
386862
386997
|
async sendTyping(instanceId, chatId, duration) {
|
|
386863
386998
|
await this.sendPresenceStatus(instanceId, chatId, duration === 0 ? "paused" : "typing", duration);
|
|
386864
386999
|
}
|
|
@@ -387260,6 +387395,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
387260
387395
|
async handleAgentSessionStopped(instanceId, connection, args) {
|
|
387261
387396
|
const parsedEventTs = args.eventTs ? Number.parseFloat(args.eventTs) : Number.NaN;
|
|
387262
387397
|
const requestedAt = Number.isFinite(parsedEventTs) ? Math.round(parsedEventTs * 1000) : Date.now();
|
|
387398
|
+
this.markStreamsStoppedByPlatform(instanceId, args.channelId, args.streamingMessageTs ?? []);
|
|
387263
387399
|
try {
|
|
387264
387400
|
await this.eventBus.publish("agent.run.cancel_requested", {
|
|
387265
387401
|
instanceId,
|