@automagik/omni 2.260901.1 → 2.260901.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/index.js CHANGED
@@ -12312,6 +12312,7 @@ var init_types3 = __esm(() => {
12312
12312
  "batch-job.cancelled",
12313
12313
  "batch-job.failed",
12314
12314
  "agent.state.changed",
12315
+ "agent.run.cancel_requested",
12315
12316
  "agent.task.created",
12316
12317
  "agent.task.updated",
12317
12318
  "agent.task.completed",
@@ -128288,7 +128289,7 @@ import { fileURLToPath } from "url";
128288
128289
  // package.json
128289
128290
  var package_default = {
128290
128291
  name: "@automagik/omni",
128291
- version: "2.260901.1",
128292
+ version: "2.260901.2",
128292
128293
  description: "LLM-optimized CLI for Omni",
128293
128294
  type: "module",
128294
128295
  bin: {
@@ -174,6 +174,7 @@ var init_types2 = __esm(() => {
174
174
  "batch-job.cancelled",
175
175
  "batch-job.failed",
176
176
  "agent.state.changed",
177
+ "agent.run.cancel_requested",
177
178
  "agent.task.created",
178
179
  "agent.task.updated",
179
180
  "agent.task.completed",
@@ -36795,7 +36796,7 @@ function ensureCleanup() {
36795
36796
  }
36796
36797
  }
36797
36798
  function startAck(plugin2, ackProvider, instanceId, chatId, messageId, channel2, config2) {
36798
- const noopHandle = { remove() {} };
36799
+ const noopHandle = { remove() {}, release() {} };
36799
36800
  if (config2.reactionAck !== "on") {
36800
36801
  return noopHandle;
36801
36802
  }
@@ -36830,6 +36831,12 @@ function startAck(plugin2, ackProvider, instanceId, chatId, messageId, channel2,
36830
36831
  if (ackProvider) {
36831
36832
  ackProvider.removeAck(instanceId, chatId, messageId, emoji).catch(() => {});
36832
36833
  }
36834
+ },
36835
+ release() {
36836
+ if (removed)
36837
+ return;
36838
+ removed = true;
36839
+ clearTimeout(timer);
36833
36840
  }
36834
36841
  };
36835
36842
  }
@@ -242894,7 +242901,7 @@ var init_sentry_scrub = __esm(() => {
242894
242901
  var require_package7 = __commonJS((exports, module) => {
242895
242902
  module.exports = {
242896
242903
  name: "@omni/api",
242897
- version: "2.260901.1",
242904
+ version: "2.260901.2",
242898
242905
  type: "module",
242899
242906
  exports: {
242900
242907
  ".": {
@@ -343539,14 +343546,16 @@ var init_loader2 = __esm(() => {
343539
343546
  class MessageDebouncer {
343540
343547
  buffers = new Map;
343541
343548
  timers = new Map;
343542
- inFlight = new Set;
343549
+ inFlight = new Map;
343543
343550
  firstBufferedAt = new Map;
343544
343551
  lastConfig = new Map;
343545
343552
  onFlush;
343546
343553
  now;
343547
- constructor(onFlush, now = Date.now) {
343554
+ options;
343555
+ constructor(onFlush, now = Date.now, options = {}) {
343548
343556
  this.onFlush = onFlush;
343549
343557
  this.now = now;
343558
+ this.options = options;
343550
343559
  }
343551
343560
  getChatKey(instanceId, chatId) {
343552
343561
  return `${instanceId}:${chatId}`;
@@ -343559,8 +343568,19 @@ class MessageDebouncer {
343559
343568
  if (!this.firstBufferedAt.has(chatKey))
343560
343569
  this.firstBufferedAt.set(chatKey, this.now());
343561
343570
  this.lastConfig.set(chatKey, config4);
343562
- if (this.inFlight.has(chatKey))
343571
+ if (this.inFlight.has(chatKey)) {
343572
+ const blockingTraceId = this.inFlight.get(chatKey);
343573
+ const queuePosition = buffer3.length;
343574
+ log89.info("agent_dispatch_queued", {
343575
+ instanceId,
343576
+ chatId,
343577
+ traceId: message2.metadata.traceId,
343578
+ queuePosition,
343579
+ blockingTraceId
343580
+ });
343581
+ this.options.onQueuedBehindActiveRun?.({ instanceId, chatId, message: message2, queuePosition, blockingTraceId });
343563
343582
  return;
343583
+ }
343564
343584
  this.restartTimer(chatKey, config4);
343565
343585
  }
343566
343586
  hasPending(instanceId, chatId) {
@@ -343621,7 +343641,7 @@ class MessageDebouncer {
343621
343641
  clearTimeout(timer2);
343622
343642
  if (!messages4?.length)
343623
343643
  return;
343624
- this.inFlight.add(chatKey);
343644
+ this.inFlight.set(chatKey, messages4[0]?.metadata.traceId);
343625
343645
  try {
343626
343646
  await this.onFlush(chatKey, messages4);
343627
343647
  } catch (error3) {
@@ -345473,6 +345493,51 @@ async function fetchChatMetadata(services, instanceId, chatId, chatType, trusted
345473
345493
  return {};
345474
345494
  }
345475
345495
  }
345496
+ function runAbortKey(instanceId, chatId, threadId2) {
345497
+ return `${instanceId}:${chatId}:${threadId2 ?? ""}`;
345498
+ }
345499
+ async function cancelActiveAgentRun(instanceId, chatId, reason, opts) {
345500
+ let entry = activeRunAborts.get(runAbortKey(instanceId, chatId, opts?.threadId));
345501
+ if (!entry && opts?.threadId) {
345502
+ entry = activeRunAborts.get(runAbortKey(instanceId, chatId));
345503
+ }
345504
+ if (!entry) {
345505
+ log91.info("Agent run cancel requested but nothing in flight", {
345506
+ instanceId,
345507
+ chatId,
345508
+ threadId: opts?.threadId,
345509
+ reason
345510
+ });
345511
+ return false;
345512
+ }
345513
+ if (opts?.requestedAt !== undefined && entry.startedAt > opts.requestedAt) {
345514
+ log91.info("Agent run cancel ignored \u2014 run started after the stop request", {
345515
+ instanceId,
345516
+ chatId,
345517
+ threadId: opts?.threadId,
345518
+ startedAt: entry.startedAt,
345519
+ requestedAt: opts.requestedAt,
345520
+ reason
345521
+ });
345522
+ return false;
345523
+ }
345524
+ log91.info("Cancelling in-flight agent run", {
345525
+ instanceId,
345526
+ chatId,
345527
+ threadId: opts?.threadId,
345528
+ reason,
345529
+ hasActiveStream: !!entry.sender
345530
+ });
345531
+ entry.controller.abort();
345532
+ if (entry.sender) {
345533
+ try {
345534
+ await (entry.sender.cancel ? entry.sender.cancel() : entry.sender.abort());
345535
+ } catch (err2) {
345536
+ log91.warn("Stream sender cancel failed during run cancellation", { instanceId, chatId, error: String(err2) });
345537
+ }
345538
+ }
345539
+ return true;
345540
+ }
345476
345541
  async function routeStreamDelta(sender, delta) {
345477
345542
  switch (delta.phase) {
345478
345543
  case "thinking":
@@ -345693,6 +345758,10 @@ async function dispatchViaStreamingProvider(services, instance4, messages4, trig
345693
345758
  const sender = resolved.createSender(instance4.id, chatId, replyToId, chatType, { formatMode });
345694
345759
  const streamKey = `${instance4.id}:${chatId}`;
345695
345760
  activeStreams.set(streamKey, sender);
345761
+ const cancelController = new AbortController;
345762
+ const runKey = runAbortKey(instance4.id, chatId, rawThreadId);
345763
+ activeRunAborts.set(runKey, { controller: cancelController, startedAt: Date.now(), sender });
345764
+ trigger.abortSignal = cancelController.signal;
345696
345765
  const streamDispatchStart = Date.now();
345697
345766
  try {
345698
345767
  const generator = resolved.provider.triggerStream(trigger);
@@ -345707,8 +345776,12 @@ async function dispatchViaStreamingProvider(services, instance4, messages4, trig
345707
345776
  attributes: { provider_type: resolved.provider.schema }
345708
345777
  });
345709
345778
  }
345710
- return streamResult;
345779
+ return cancelController.signal.aborted ? true : streamResult;
345711
345780
  } catch (err2) {
345781
+ if (cancelController.signal.aborted) {
345782
+ log91.info("Streaming dispatch cancelled by user", { instanceId: instance4.id, chatId, traceId });
345783
+ return true;
345784
+ }
345712
345785
  log91.error("Streaming dispatch failed, falling back", {
345713
345786
  instanceId: instance4.id,
345714
345787
  chatId,
@@ -345721,6 +345794,7 @@ async function dispatchViaStreamingProvider(services, instance4, messages4, trig
345721
345794
  return false;
345722
345795
  } finally {
345723
345796
  activeStreams.delete(streamKey);
345797
+ activeRunAborts.delete(runKey);
345724
345798
  }
345725
345799
  }
345726
345800
  function formatMediaContent(msg) {
@@ -345919,6 +345993,38 @@ async function dispatchViaTurnBasedProvider(services, instance4, provider, trigg
345919
345993
  });
345920
345994
  return true;
345921
345995
  }
345996
+ function resolveReplySuppression(flags) {
345997
+ if (flags.handoffTriggered)
345998
+ return "handoff_triggered";
345999
+ if (flags.errorHandoffDone)
346000
+ return "error_handoff";
346001
+ if (flags.supersededByNewerInbound)
346002
+ return "superseded_by_newer_inbound";
346003
+ if (flags.runCancelled)
346004
+ return "run_cancelled_by_user";
346005
+ return null;
346006
+ }
346007
+ async function triggerProviderWithCancellation(provider, trigger, spanAttributes, instanceId, chatId, traceId) {
346008
+ const cancelController = new AbortController;
346009
+ const runKey = runAbortKey(instanceId, chatId, trigger.source.threadId);
346010
+ activeRunAborts.set(runKey, { controller: cancelController, startedAt: Date.now() });
346011
+ try {
346012
+ const result = await withLifecycleSpan("omni.dispatch_to_agno", spanAttributes, () => provider.trigger({
346013
+ ...trigger,
346014
+ abortSignal: cancelController.signal,
346015
+ traceContext: activeProviderTraceContext() ?? trigger.traceContext
346016
+ }));
346017
+ return { result, cancelled: cancelController.signal.aborted };
346018
+ } catch (err2) {
346019
+ if (cancelController.signal.aborted) {
346020
+ log91.info("Agent run cancelled by user during dispatch", { instanceId, chatId, traceId });
346021
+ return null;
346022
+ }
346023
+ throw err2;
346024
+ } finally {
346025
+ activeRunAborts.delete(runKey);
346026
+ }
346027
+ }
345922
346028
  async function dispatchViaProvider(services, instance4, messages4, triggerType, channel5, chatId, senderId, personId, senderName, traceId, rawEvent, db2, extraContextMessages, senderAgentId) {
345923
346029
  const provider = await getAgentProvider(services, instance4, db2);
345924
346030
  if (!provider)
@@ -345988,11 +346094,14 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
345988
346094
  }
345989
346095
  const correlationId = messages4[0]?.metadata.correlationId;
345990
346096
  const dispatchStart = Date.now();
345991
- const result = await withLifecycleSpan("omni.dispatch_to_agno", buildLifecycleSpanAttributes({
346097
+ const triggerOutcome = await triggerProviderWithCancellation(provider, trigger, buildLifecycleSpanAttributes({
345992
346098
  ...lifecycleBase,
345993
346099
  stage: "dispatch_to_agno",
345994
346100
  extra: { trigger_type: triggerType, provider_id: provider.id, provider_schema: provider.schema }
345995
- }), () => provider.trigger({ ...trigger, traceContext: activeProviderTraceContext() ?? trigger.traceContext }));
346101
+ }), instance4.id, chatId, traceId);
346102
+ if (!triggerOutcome)
346103
+ return true;
346104
+ const { result, cancelled: runCancelled } = triggerOutcome;
345996
346105
  const dispatchDurationMs = Date.now() - dispatchStart;
345997
346106
  if (sentryEnabled()) {
345998
346107
  exports_public_api2.count("agent.dispatch", 1, { attributes: { provider_type: provider.schema } });
@@ -346005,7 +346114,13 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
346005
346114
  const handoffTriggered = chatAfterRun?.settings?.agentPaused === true;
346006
346115
  const supersededByNewerInbound = !handoffTriggered && isReplySuperseded(instance4, chatId);
346007
346116
  const errorHandoffDone = await maybeTriggerErrorHandoff(services, db2, channel5, instance4, chatId, result?.metadata.customerErrorBlocked === true, handoffTriggered, messages4[0]?.metadata.trustedTenantId);
346008
- if (result && result.parts.length > 0 && !handoffTriggered && !errorHandoffDone && !supersededByNewerInbound) {
346117
+ const suppressReason = resolveReplySuppression({
346118
+ handoffTriggered,
346119
+ errorHandoffDone,
346120
+ supersededByNewerInbound,
346121
+ runCancelled
346122
+ });
346123
+ if (result && result.parts.length > 0 && !suppressReason) {
346009
346124
  const selfChat = isSelfChat(chatId, instance4.ownerIdentifier);
346010
346125
  const rawParts = selfChat ? result.parts.map((p2) => `${BOT_PREFIX}${p2}`) : result.parts;
346011
346126
  const parts = await Promise.all(rawParts.map((part) => executeBeforeMessageWriteHooks(instance4.id, chatId, part)));
@@ -346021,13 +346136,9 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
346021
346136
  }), () => sendResponseParts(channel5, instance4.id, chatId, parts, getSplitDelayConfig(instance4), _fmtMode, replyTo, correlationId, senderAgentId));
346022
346137
  recordJourneyCheckpoint(correlationId, "T9", JOURNEY_STAGES.T9);
346023
346138
  await forwardToChainedInstance(instance4, parts, correlationId, messages4);
346024
- } else if (handoffTriggered) {
346025
- log91.info("Agent response suppressed \u2014 handoff triggered during run", {
346026
- instanceId: instance4.id,
346027
- chatId
346028
- });
346029
- } else if (supersededByNewerInbound) {
346030
- log91.info("Agent response discarded \u2014 superseded by newer inbound", {
346139
+ } else if (suppressReason) {
346140
+ log91.info("Agent response suppressed", {
346141
+ reason: suppressReason,
346031
346142
  instanceId: instance4.id,
346032
346143
  chatId,
346033
346144
  parts: result?.parts.length ?? 0,
@@ -346370,6 +346481,34 @@ function buildAckConfig(instance4) {
346370
346481
  ackTimeoutMs: inst.ackTimeoutMs ?? 30000
346371
346482
  };
346372
346483
  }
346484
+ function takeQueuedAck(chatKey) {
346485
+ const entry = queuedMessageAcks.get(chatKey);
346486
+ queuedMessageAcks.delete(chatKey);
346487
+ return entry?.handle;
346488
+ }
346489
+ async function ackQueuedMessage(info2) {
346490
+ const chatKey = `${info2.instanceId}:${info2.chatId}`;
346491
+ try {
346492
+ const existing = queuedMessageAcks.get(chatKey);
346493
+ if (existing && Date.now() - existing.at < QUEUED_ACK_TIMEOUT_MS)
346494
+ return;
346495
+ const instance4 = info2.message.metadata.resolvedInstance;
346496
+ const messageId = info2.message.payload.externalId;
346497
+ if (!instance4 || !messageId)
346498
+ return;
346499
+ const entry = { at: Date.now() };
346500
+ queuedMessageAcks.set(chatKey, entry);
346501
+ const channel5 = info2.message.metadata.channelType ?? instance4.channel;
346502
+ const plugin10 = await getPlugin(channel5) ?? null;
346503
+ entry.handle = startAck(plugin10, createPluginAckProvider(plugin10), instance4.id, info2.chatId, messageId, channel5, {
346504
+ ...buildAckConfig(instance4),
346505
+ ackTimeoutMs: QUEUED_ACK_TIMEOUT_MS
346506
+ });
346507
+ } catch (error3) {
346508
+ queuedMessageAcks.delete(chatKey);
346509
+ log91.debug("Failed to ack queued message", { chatId: info2.chatId, error: String(error3) });
346510
+ }
346511
+ }
346373
346512
  async function dispatchToAgent(services, instance4, msgs, triggerType, channel5, chatId, senderId, personId, senderName, traceId, senderAgentId, perThreadExtraContext, db2) {
346374
346513
  const firstMsg = msgs[0];
346375
346514
  if (!firstMsg)
@@ -347463,10 +347602,13 @@ async function setupAgentDispatcher(eventBus, services, db2) {
347463
347602
  }
347464
347603
  }
347465
347604
  }, 60000);
347466
- const debouncer = new MessageDebouncer(async (_chatKey, messages4) => {
347605
+ const onDebouncedFlush = async (chatKey, messages4) => {
347606
+ const queuedAck = takeQueuedAck(chatKey);
347467
347607
  const firstMsg = messages4[0];
347468
- if (!firstMsg)
347608
+ if (!firstMsg) {
347609
+ queuedAck?.remove();
347469
347610
  return;
347611
+ }
347470
347612
  const instanceId = firstMsg.metadata.instanceId;
347471
347613
  let instance4;
347472
347614
  if (firstMsg.metadata.resolvedInstance) {
@@ -347475,6 +347617,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
347475
347617
  const baseInstance = await runDispatchDb(db2, firstMsg.metadata.trustedTenantId, () => agentRunner.getInstanceWithProvider(instanceId));
347476
347618
  if (!baseInstance) {
347477
347619
  log91.warn("Instance not found for debounced messages", { instanceId });
347620
+ queuedAck?.remove();
347478
347621
  return;
347479
347622
  }
347480
347623
  const externalChatId = firstMsg.payload.chatId;
@@ -347484,13 +347627,19 @@ async function setupAgentDispatcher(eventBus, services, db2) {
347484
347627
  }
347485
347628
  const msgContext = buildMessageContext(firstMsg.payload, instance4);
347486
347629
  const triggerType = classifyMessageTrigger(msgContext);
347487
- if (await shouldSkipViaGate(triggerType, firstMsg, instance4, messages4, services))
347630
+ if (await shouldSkipViaGate(triggerType, firstMsg, instance4, messages4, services)) {
347631
+ queuedAck?.remove();
347488
347632
  return;
347633
+ }
347489
347634
  if (firstMsg.metadata.journeyTracked && firstMsg.metadata.correlationId) {
347490
347635
  const tracker = getJourneyTracker();
347491
347636
  tracker.recordCheckpoint(firstMsg.metadata.correlationId, "T5", JOURNEY_STAGES.T5);
347492
347637
  }
347638
+ queuedAck?.release();
347493
347639
  await processAgentResponse(services, instance4, messages4, triggerType, db2, eventBus);
347640
+ };
347641
+ const debouncer = new MessageDebouncer(onDebouncedFlush, Date.now, {
347642
+ onQueuedBehindActiveRun: (info2) => void ackQueuedMessage(info2)
347494
347643
  });
347495
347644
  activeMessageDebouncer = debouncer;
347496
347645
  try {
@@ -347656,7 +347805,24 @@ async function setupAgentDispatcher(eventBus, services, db2) {
347656
347805
  queue: "agent-dispatcher-media",
347657
347806
  startFrom: "new"
347658
347807
  });
347659
- log91.info("Agent dispatcher initialized (message + reaction + reaction-removed + media triggers)");
347808
+ await eventBus.subscribe("agent.run.cancel_requested", async (event) => {
347809
+ const payload = event.payload;
347810
+ try {
347811
+ await cancelActiveAgentRun(payload.instanceId, payload.chatId, payload.reason, {
347812
+ threadId: payload.threadId,
347813
+ requestedAt: payload.requestedAt
347814
+ });
347815
+ } catch (error3) {
347816
+ log91.error("Error cancelling agent run", {
347817
+ instanceId: payload.instanceId,
347818
+ chatId: payload.chatId,
347819
+ error: String(error3)
347820
+ });
347821
+ }
347822
+ }, {
347823
+ startFrom: "new"
347824
+ });
347825
+ log91.info("Agent dispatcher initialized (message + reaction + reaction-removed + media + cancel triggers)");
347660
347826
  } catch (error3) {
347661
347827
  log91.error("Failed to set up agent dispatcher", { error: String(error3) });
347662
347828
  clearInterval(mediaCleanupInterval);
@@ -347710,7 +347876,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
347710
347876
  log91.info("Agent dispatcher shutdown complete");
347711
347877
  };
347712
347878
  }
347713
- 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, sessionActivityStore, PROC_REACT_START, PROC_REACT_DONE = "\u2705", 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;
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;
347714
347880
  var init_agent_dispatcher = __esm(() => {
347715
347881
  init_src2();
347716
347882
  init_src();
@@ -347767,8 +347933,10 @@ var init_agent_dispatcher = __esm(() => {
347767
347933
  mediaResultCache = new Map;
347768
347934
  DEFAULT_SEND_MEDIA_PATH_TYPES = ["image", "video", "document"];
347769
347935
  activeStreams = new Map;
347936
+ activeRunAborts = new Map;
347770
347937
  sessionActivityStore = new InMemorySessionActivityStore;
347771
347938
  PROC_REACT_START = { audio: "\uD83C\uDFA7", image: "\uD83D\uDC40", video: "\uD83D\uDC40", document: "\uD83D\uDC40" };
347939
+ queuedMessageAcks = new Map;
347772
347940
  providerCache = new Map;
347773
347941
  openclawClientPool = new Map;
347774
347942
  _openClawClientCtor = OpenClawClient;
@@ -385208,6 +385376,23 @@ async function checkBoltHealth(connection) {
385208
385376
  }
385209
385377
  }
385210
385378
 
385379
+ // ../channel-slack/src/handlers/agent-sessions.ts
385380
+ function setupAgentSessionHandlers(app, instanceId, callbacks, logger5) {
385381
+ app.event("agent_session_stopped", async ({ event }) => {
385382
+ const evt = event;
385383
+ const channelId = evt.channel;
385384
+ if (!channelId)
385385
+ return;
385386
+ const threadTs = evt.thread_ts;
385387
+ const userId = evt.user;
385388
+ const eventTs = evt.event_ts;
385389
+ const streamingMessageTs = Array.isArray(evt.streaming_message_ts) ? evt.streaming_message_ts : [];
385390
+ logger5.info("Agent session stopped by user", { instanceId, channelId, threadTs, userId, streamingMessageTs });
385391
+ await callbacks.onSessionStopped(instanceId, { channelId, threadTs, userId, streamingMessageTs, eventTs });
385392
+ });
385393
+ logger5.info("Agent session handlers registered", { instanceId });
385394
+ }
385395
+
385211
385396
  // ../channel-slack/src/handlers/commands.ts
385212
385397
  function setupCommandHandlers(app, instanceId, commandNames, callbacks, logger5) {
385213
385398
  for (const commandName of commandNames) {
@@ -385687,10 +385872,62 @@ function setupReactionHandlers2(app, instanceId, botUserId, callbacks, logger5)
385687
385872
 
385688
385873
  // ../channel-slack/src/handlers/typing.ts
385689
385874
  var CLEAR_STATUS = "";
385875
+ var AGENT_API_UNAVAILABLE_ERRORS = new Set([
385876
+ "unknown_method",
385877
+ "feature_disabled",
385878
+ "method_deprecated",
385879
+ "missing_scope",
385880
+ "not_allowed_token_type"
385881
+ ]);
385882
+ var agentApiUnavailable = new WeakSet;
385883
+ function slackErrorCode(err2) {
385884
+ return err2?.data?.error;
385885
+ }
385690
385886
  async function setSlackThreadStatus(params) {
385691
385887
  const { client, channelId, threadTs, status, loadingMessages, logger: logger5, instanceId } = params;
385692
- if (!threadTs)
385693
- return false;
385888
+ if (!threadTs) {
385889
+ logger5.debug("setSlackThreadStatus: skipped, no thread timestamp", {
385890
+ instanceId,
385891
+ channelId,
385892
+ reason: "no_thread_ts",
385893
+ clearing: status.length === 0
385894
+ });
385895
+ return { delivered: false };
385896
+ }
385897
+ const clearing = status.length === 0;
385898
+ const logContext = {
385899
+ instanceId,
385900
+ channelId,
385901
+ threadTs,
385902
+ clearing,
385903
+ statusLength: status.length,
385904
+ loadingMessageCount: loadingMessages?.length ?? 0
385905
+ };
385906
+ if (typeof client.apiCall === "function" && !agentApiUnavailable.has(client)) {
385907
+ try {
385908
+ await client.apiCall("agents.sessions.setStatus", {
385909
+ channel_id: channelId,
385910
+ thread_ts: threadTs,
385911
+ status: clearing ? "active" : "processing"
385912
+ });
385913
+ return { delivered: true, method: "agents.sessions.setStatus" };
385914
+ } catch (err2) {
385915
+ const code = slackErrorCode(err2);
385916
+ if (code && AGENT_API_UNAVAILABLE_ERRORS.has(code)) {
385917
+ agentApiUnavailable.add(client);
385918
+ logger5.info("agents.sessions.setStatus unavailable, falling back to assistant.threads.setStatus", {
385919
+ instanceId,
385920
+ channelId,
385921
+ error: code
385922
+ });
385923
+ } else {
385924
+ logger5.warn("agents.sessions.setStatus failed, trying legacy fallback", {
385925
+ ...logContext,
385926
+ error: String(err2)
385927
+ });
385928
+ }
385929
+ }
385930
+ }
385694
385931
  const payload = {
385695
385932
  channel_id: channelId,
385696
385933
  thread_ts: threadTs,
@@ -385698,27 +385935,19 @@ async function setSlackThreadStatus(params) {
385698
385935
  ...loadingMessages?.length ? { loading_messages: loadingMessages } : {}
385699
385936
  };
385700
385937
  try {
385701
- const clientAny = client;
385702
- if (typeof clientAny.assistant?.threads?.setStatus === "function") {
385703
- await clientAny.assistant.threads.setStatus(payload);
385704
- return true;
385938
+ const legacyClient = client;
385939
+ if (typeof legacyClient.assistant?.threads?.setStatus === "function") {
385940
+ await legacyClient.assistant.threads.setStatus(payload);
385941
+ return { delivered: true, method: "assistant.threads.setStatus" };
385705
385942
  }
385706
- if (typeof clientAny.apiCall === "function") {
385707
- await clientAny.apiCall("assistant.threads.setStatus", payload);
385708
- return true;
385943
+ if (typeof legacyClient.apiCall === "function") {
385944
+ await legacyClient.apiCall("assistant.threads.setStatus", payload);
385945
+ return { delivered: true, method: "assistant.threads.setStatus" };
385709
385946
  }
385710
385947
  } catch (err2) {
385711
- logger5.warn("setSlackThreadStatus: failed", {
385712
- instanceId,
385713
- channelId,
385714
- threadTs,
385715
- clearing: status.length === 0,
385716
- statusLength: status.length,
385717
- loadingMessageCount: loadingMessages?.length ?? 0,
385718
- error: String(err2)
385719
- });
385948
+ logger5.warn("setSlackThreadStatus: failed", { ...logContext, error: String(err2) });
385720
385949
  }
385721
- return false;
385950
+ return { delivered: false, method: "assistant.threads.setStatus" };
385722
385951
  }
385723
385952
  async function clearTypingStatus(params) {
385724
385953
  return setSlackThreadStatus({ ...params, status: CLEAR_STATUS });
@@ -385893,6 +386122,7 @@ function createSlackStreamSender(options) {
385893
386122
  let finalized = false;
385894
386123
  let pendingContent;
385895
386124
  let throttleTimer;
386125
+ let lastContent = "";
385896
386126
  function formatText(text) {
385897
386127
  return formatMode === "passthrough" ? text : markdownToMrkdwn(text);
385898
386128
  }
@@ -385951,6 +386181,8 @@ function createSlackStreamSender(options) {
385951
386181
  }
385952
386182
  }
385953
386183
  async function finalize(text) {
386184
+ if (finalized)
386185
+ return;
385954
386186
  finalized = true;
385955
386187
  if (throttleTimer) {
385956
386188
  clearTimeout(throttleTimer);
@@ -385976,31 +386208,60 @@ function createSlackStreamSender(options) {
385976
386208
  await sendInitial(chunk);
385977
386209
  }
385978
386210
  }
386211
+ async function deleteDraft() {
386212
+ if (draftTs && !finalized) {
386213
+ try {
386214
+ await client.chat.delete({ channel: channelId, ts: draftTs });
386215
+ } catch {}
386216
+ }
386217
+ finalized = true;
386218
+ }
386219
+ async function cancelKeepingPartial() {
386220
+ if (finalized)
386221
+ return;
386222
+ if (lastContent.trim()) {
386223
+ await finalize(lastContent);
386224
+ return;
386225
+ }
386226
+ await deleteDraft();
386227
+ }
385979
386228
  if (streamMode === "off") {
385980
386229
  return {
385981
386230
  async onThinkingDelta(_delta) {},
385982
386231
  async onContentDelta(_delta) {},
385983
386232
  async onFinal(delta) {
385984
- await sendInitial(delta.content);
386233
+ if (finalized)
386234
+ return;
385985
386235
  finalized = true;
386236
+ await sendInitial(delta.content);
385986
386237
  },
385987
386238
  async onError(delta) {
385988
- await sendInitial(`Error: ${delta.error}`);
386239
+ if (finalized)
386240
+ return;
385989
386241
  finalized = true;
386242
+ await sendInitial(`Error: ${delta.error}`);
385990
386243
  },
385991
386244
  async abort() {
385992
386245
  finalized = true;
386246
+ },
386247
+ async cancel() {
386248
+ finalized = true;
385993
386249
  }
385994
386250
  };
385995
386251
  }
385996
386252
  if (streamMode === "status_final") {
385997
386253
  return {
385998
386254
  async onThinkingDelta(_delta) {
386255
+ if (finalized)
386256
+ return;
385999
386257
  if (!draftTs) {
386000
386258
  await sendInitial("_Thinking..._");
386001
386259
  }
386002
386260
  },
386003
- async onContentDelta(_delta) {
386261
+ async onContentDelta(delta) {
386262
+ if (finalized)
386263
+ return;
386264
+ lastContent = delta.content;
386004
386265
  if (!draftTs) {
386005
386266
  await sendInitial("_Thinking..._");
386006
386267
  }
@@ -386012,17 +386273,17 @@ function createSlackStreamSender(options) {
386012
386273
  await finalize(`Error: ${delta.error}`);
386013
386274
  },
386014
386275
  async abort() {
386015
- if (draftTs && !finalized) {
386016
- try {
386017
- await client.chat.delete({ channel: channelId, ts: draftTs });
386018
- } catch {}
386019
- }
386020
- finalized = true;
386276
+ await deleteDraft();
386277
+ },
386278
+ async cancel() {
386279
+ await cancelKeepingPartial();
386021
386280
  }
386022
386281
  };
386023
386282
  }
386024
386283
  return {
386025
386284
  async onThinkingDelta(delta) {
386285
+ if (finalized)
386286
+ return;
386026
386287
  const text = `_${delta.thinking}_`;
386027
386288
  if (!draftTs) {
386028
386289
  await sendInitial(text);
@@ -386031,7 +386292,10 @@ function createSlackStreamSender(options) {
386031
386292
  }
386032
386293
  },
386033
386294
  async onContentDelta(delta) {
386295
+ if (finalized)
386296
+ return;
386034
386297
  const text = delta.content;
386298
+ lastContent = text;
386035
386299
  if (!draftTs) {
386036
386300
  await sendInitial(text);
386037
386301
  } else {
@@ -386045,12 +386309,10 @@ function createSlackStreamSender(options) {
386045
386309
  await finalize(`Error: ${delta.error}`);
386046
386310
  },
386047
386311
  async abort() {
386048
- if (draftTs && !finalized) {
386049
- try {
386050
- await client.chat.delete({ channel: channelId, ts: draftTs });
386051
- } catch {}
386052
- }
386053
- finalized = true;
386312
+ await deleteDraft();
386313
+ },
386314
+ async cancel() {
386315
+ await cancelKeepingPartial();
386054
386316
  }
386055
386317
  };
386056
386318
  }
@@ -386142,6 +386404,8 @@ function createNativeStreamSender(options) {
386142
386404
  async onContentDelta(delta) {
386143
386405
  if (fallback)
386144
386406
  return fallback.onContentDelta(delta);
386407
+ if (stopped)
386408
+ return;
386145
386409
  const content = delta.content;
386146
386410
  if (!content)
386147
386411
  return;
@@ -386168,6 +386432,11 @@ function createNativeStreamSender(options) {
386168
386432
  if (fallback)
386169
386433
  return fallback.abort();
386170
386434
  await stopStream();
386435
+ },
386436
+ async cancel() {
386437
+ if (fallback)
386438
+ return fallback.cancel ? fallback.cancel() : fallback.abort();
386439
+ await stopStream();
386171
386440
  }
386172
386441
  };
386173
386442
  }
@@ -386561,6 +386830,10 @@ class SlackPlugin extends BaseChannelPlugin {
386561
386830
  async abort() {
386562
386831
  await base2.abort();
386563
386832
  cleanup();
386833
+ },
386834
+ async cancel() {
386835
+ await (base2.cancel ? base2.cancel() : base2.abort());
386836
+ cleanup();
386564
386837
  }
386565
386838
  };
386566
386839
  }
@@ -386568,29 +386841,43 @@ class SlackPlugin extends BaseChannelPlugin {
386568
386841
  await this.sendPresenceStatus(instanceId, chatId, duration === 0 ? "paused" : "typing", duration);
386569
386842
  }
386570
386843
  async sendPresenceStatus(instanceId, chatId, type, duration, options) {
386571
- const method = "assistant.threads.setStatus";
386844
+ const nominalMethod = "agents.sessions.setStatus";
386572
386845
  const connection = this.connections.get(instanceId);
386573
386846
  if (!connection)
386574
- return { delivered: false, method, reason: "not_connected" };
386847
+ return { delivered: false, method: nominalMethod, reason: "not_connected" };
386575
386848
  const threadTs = options?.threadId ?? this.activeThreads.get(`${instanceId}:${chatId}`);
386576
- if (!threadTs)
386577
- return { delivered: false, method, reason: "no_active_thread" };
386849
+ if (!threadTs) {
386850
+ this.logger.debug("Slack presence status skipped", {
386851
+ instanceId,
386852
+ chatId,
386853
+ type,
386854
+ reason: "no_active_thread"
386855
+ });
386856
+ return { delivered: false, method: nominalMethod, reason: "no_active_thread" };
386857
+ }
386578
386858
  const shouldClear = type === "paused";
386579
386859
  const status = shouldClear ? "" : options?.status ?? (type === "recording" ? "is recording..." : "is typing...");
386580
386860
  const timerKey = this.presenceStatusTimerKey(instanceId, chatId, threadTs);
386581
- const delivered = status === "" ? await clearTypingStatus({
386861
+ const statusResult = status === "" ? await clearTypingStatus({
386582
386862
  client: connection.actingClient,
386583
386863
  channelId: chatId,
386584
386864
  threadTs,
386585
- logger: this.logger
386865
+ logger: this.logger,
386866
+ instanceId
386586
386867
  }) : await setSlackThreadStatus({
386587
386868
  client: connection.actingClient,
386588
386869
  channelId: chatId,
386589
386870
  threadTs,
386590
386871
  status,
386591
386872
  loadingMessages: options?.loadingMessages,
386592
- logger: this.logger
386873
+ logger: this.logger,
386874
+ instanceId
386593
386875
  });
386876
+ const { delivered, method } = statusResult;
386877
+ const usedLegacy = method === "assistant.threads.setStatus";
386878
+ const sessionStatus = shouldClear ? "active" : "processing";
386879
+ const appliedStatus = !delivered || usedLegacy ? status : sessionStatus;
386880
+ const appliedLoadingMessages = !delivered || usedLegacy ? options?.loadingMessages : undefined;
386594
386881
  if (delivered) {
386595
386882
  this.clearPresenceStatusTimer(timerKey);
386596
386883
  }
@@ -386616,12 +386903,18 @@ class SlackPlugin extends BaseChannelPlugin {
386616
386903
  this.presenceStatusTimers.set(timerKey, timer);
386617
386904
  timer.unref?.();
386618
386905
  }
386619
- return delivered ? { delivered: true, method, threadId: threadTs, status, loadingMessages: options?.loadingMessages } : {
386620
- delivered: false,
386906
+ return delivered ? {
386907
+ delivered: true,
386621
386908
  method,
386622
386909
  threadId: threadTs,
386623
- status,
386624
- loadingMessages: options?.loadingMessages,
386910
+ status: appliedStatus,
386911
+ loadingMessages: appliedLoadingMessages
386912
+ } : {
386913
+ delivered: false,
386914
+ method: method ?? nominalMethod,
386915
+ threadId: threadTs,
386916
+ status: appliedStatus,
386917
+ loadingMessages: appliedLoadingMessages,
386625
386918
  reason: "slack_status_failed"
386626
386919
  };
386627
386920
  }
@@ -386942,6 +387235,37 @@ class SlackPlugin extends BaseChannelPlugin {
386942
387235
  break;
386943
387236
  }
386944
387237
  }
387238
+ async handleAgentSessionStopped(instanceId, connection, args) {
387239
+ const parsedEventTs = args.eventTs ? Number.parseFloat(args.eventTs) : Number.NaN;
387240
+ const requestedAt = Number.isFinite(parsedEventTs) ? Math.round(parsedEventTs * 1000) : Date.now();
387241
+ try {
387242
+ await this.eventBus.publish("agent.run.cancel_requested", {
387243
+ instanceId,
387244
+ chatId: args.channelId,
387245
+ threadId: args.threadTs,
387246
+ requestedBy: args.userId,
387247
+ requestedAt,
387248
+ reason: "user_stop"
387249
+ }, {
387250
+ instanceId,
387251
+ channelType: this.id,
387252
+ source: `channel:${this.id}`
387253
+ });
387254
+ } catch (err2) {
387255
+ this.logger.error("Failed to publish agent.run.cancel_requested", {
387256
+ instanceId,
387257
+ chatId: args.channelId,
387258
+ error: String(err2)
387259
+ });
387260
+ }
387261
+ await clearTypingStatus({
387262
+ client: connection.actingClient,
387263
+ channelId: args.channelId,
387264
+ threadTs: args.threadTs ?? this.activeThreads.get(`${instanceId}:${args.channelId}`),
387265
+ logger: this.logger,
387266
+ instanceId
387267
+ });
387268
+ }
386945
387269
  trackActiveThread(instanceId, channelId, threadTs) {
386946
387270
  this.activeThreads.set(`${instanceId}:${channelId}`, threadTs);
386947
387271
  }
@@ -387059,6 +387383,11 @@ class SlackPlugin extends BaseChannelPlugin {
387059
387383
  await this.handleReactionReceived(instId, messageId, chatId, userId, emoji, action);
387060
387384
  }
387061
387385
  }, this.logger);
387386
+ setupAgentSessionHandlers(connection.app, instanceId, {
387387
+ onSessionStopped: async (instId, args) => {
387388
+ await this.handleAgentSessionStopped(instId, connection, args);
387389
+ }
387390
+ }, this.logger);
387062
387391
  setupInteractionHandlers2(connection.app, instanceId, {
387063
387392
  onInteraction: async (_instId, payload) => {
387064
387393
  await this.handleInteraction(payload);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.260901.1",
3
+ "version": "2.260901.2",
4
4
  "description": "LLM-optimized CLI for Omni",
5
5
  "type": "module",
6
6
  "bin": {