@automagik/omni 2.260409.4 → 2.260409.6

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.
@@ -113,6 +113,20 @@
113
113
  "when": 1775404179968,
114
114
  "tag": "0015_burly_trauma",
115
115
  "breakpoints": true
116
+ },
117
+ {
118
+ "idx": 16,
119
+ "version": "7",
120
+ "when": 1775767816830,
121
+ "tag": "0016_instance_fallback_config",
122
+ "breakpoints": true
123
+ },
124
+ {
125
+ "idx": 17,
126
+ "version": "7",
127
+ "when": 1775772342374,
128
+ "tag": "0017_drop_agent_fallback",
129
+ "breakpoints": true
116
130
  }
117
131
  ]
118
132
  }
@@ -1 +1 @@
1
- {"version":3,"file":"instances.d.ts","sourceRoot":"","sources":["../../src/commands/instances.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwJpC,wBAAgB,sBAAsB,IAAI,OAAO,CAsnChD"}
1
+ {"version":3,"file":"instances.d.ts","sourceRoot":"","sources":["../../src/commands/instances.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgKpC,wBAAgB,sBAAsB,IAAI,OAAO,CAgoChD"}
package/dist/index.js CHANGED
@@ -76972,7 +76972,7 @@ import { fileURLToPath } from "url";
76972
76972
  // package.json
76973
76973
  var package_default = {
76974
76974
  name: "@automagik/omni",
76975
- version: "2.260409.4",
76975
+ version: "2.260409.6",
76976
76976
  description: "LLM-optimized CLI for Omni",
76977
76977
  type: "module",
76978
76978
  bin: {
@@ -80766,7 +80766,7 @@ function getMediaType(path) {
80766
80766
  }
80767
80767
  async function closeTurn(client, action, successMsg, reason) {
80768
80768
  try {
80769
- const turnId = process.env.OMNI_TURN_ID;
80769
+ const turnId = process.env.OMNI_TURN_ID || undefined;
80770
80770
  const extraHeaders = {};
80771
80771
  if (process.env.OMNI_INSTANCE)
80772
80772
  extraHeaders["x-omni-instance"] = process.env.OMNI_INSTANCE;
@@ -82847,6 +82847,11 @@ function applyAckFields(body, opts) {
82847
82847
  body.ackTimeoutMs = Number(opts.ackTimeout);
82848
82848
  }
82849
82849
  }
82850
+ function applyStalledFields(body, opts) {
82851
+ if (opts.agentStalledTimeoutMs !== undefined) {
82852
+ body.agentStalledTimeoutMs = Number(opts.agentStalledTimeoutMs);
82853
+ }
82854
+ }
82850
82855
  function buildInstanceBody(opts) {
82851
82856
  const body = {};
82852
82857
  applyAgentFields(body, opts);
@@ -82856,6 +82861,7 @@ function buildInstanceBody(opts) {
82856
82861
  applyGateFields(body, opts);
82857
82862
  applyMiscFields(body, opts);
82858
82863
  applyAckFields(body, opts);
82864
+ applyStalledFields(body, opts);
82859
82865
  return body;
82860
82866
  }
82861
82867
  async function resolveBase64Image(options) {
@@ -82932,7 +82938,7 @@ function createInstancesCommand() {
82932
82938
  error(`Failed to get instance: ${message}`, undefined, 3);
82933
82939
  }
82934
82940
  });
82935
- instances.command("create").description("Create a new instance (supports all API fields)").requiredOption("--name <name>", "Instance name").requiredOption("--channel <type>", `Channel type (${VALID_CHANNELS2.join(", ")})`).option("--agent-fk-id <uuid>", 'Agent FK UUID (references agents table, use "null" to clear)').option("--agent-provider <id>", "Agent provider ID").option("--agent <id>", "Agent ID").option("--agent-type <type>", "Agent type: agent, team, or workflow").option("--agent-timeout <seconds>", "Agent timeout in seconds", (v) => Number.parseInt(v, 10)).option("--agent-stream-mode", "Enable streaming responses").option("--agent-session-strategy <strategy>", "Session strategy: per_user, per_chat, per_user_per_chat").option("--agent-prefix-sender-name", "Prefix messages with sender name").option("--no-agent-prefix-sender-name", "Disable sender name prefix").option("--agent-wait-for-media", "Wait for media processing before dispatch").option("--no-agent-wait-for-media", "Dispatch immediately without waiting for media").option("--agent-send-media-path", "Include file path in formatted media text").option("--no-agent-send-media-path", "Exclude file path from formatted media text").option("--agent-send-media-path-types <types>", "Content types that receive file path (comma-separated: image,video,document)").option("--reply-filter-mode <mode>", "Reply filter: all or filtered").option("--reply-on-dm", "Reply to DMs").option("--no-reply-on-dm", "Ignore DMs").option("--reply-on-mention", "Reply when @mentioned").option("--no-reply-on-mention", "Ignore @mentions").option("--reply-on-reply", "Reply when message is reply to bot").option("--no-reply-on-reply", "Ignore replies").option("--reply-on-name", "Reply when bot name appears in text").option("--no-reply-on-name", "Ignore name matches").option("--reply-name-patterns <patterns>", "Custom name patterns (comma-separated)").option("--enable-auto-split", "Split responses on double newlines").option("--no-enable-auto-split", "Disable auto-split").option("--message-format-mode <mode>", "Format mode: convert or passthrough").option("--debounce-mode <mode>", "Debounce mode: disabled, fixed, or randomized").option("--debounce-min <ms>", "Minimum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-max <ms>", "Maximum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-restart-on-typing", "Restart debounce timer on typing").option("--debounce-group <ms>", "Group chat debounce in ms", (v) => Number.parseInt(v, 10)).option("--agent-gate", "Enable LLM response gate").option("--agent-gate-model <model>", "Model for response gate").option("--agent-gate-prompt <prompt>", "Custom gate prompt").option("--tts-voice <id>", "ElevenLabs voice ID").option("--tts-model <id>", "ElevenLabs model ID").option("--access-mode <mode>", "Access mode: disabled, blocklist, or allowlist").option("--reaction-ack <mode>", "Reaction ack mode (on|off)").option("--reaction-ack-emoji <json>", "Per-channel emoji map as JSON").option("--ack-timeout <ms>", "Ack timeout in milliseconds", (v) => Number.parseInt(v, 10)).option("--token <token>", "Generic bot token (auto-resolves to channel-specific field)").option("--telegram-token <token>", "Telegram bot token").option("--discord-token <token>", "Discord bot token").option("--slack-bot-token <token>", "Slack bot token").option("--slack-app-token <token>", "Slack app token").option("--gupshup-api-key <key>", "Gupshup API key").option("--gupshup-app-name <name>", "Gupshup app name").option("--gupshup-source-phone <phone>", "Gupshup source phone (E.164)").option("--gupshup-webhook-verify-token <token>", "Gupshup webhook verify token").option("--is-default", "Set as default instance for channel").action(async (options) => {
82941
+ instances.command("create").description("Create a new instance (supports all API fields)").requiredOption("--name <name>", "Instance name").requiredOption("--channel <type>", `Channel type (${VALID_CHANNELS2.join(", ")})`).option("--agent-fk-id <uuid>", 'Agent FK UUID (references agents table, use "null" to clear)').option("--agent-provider <id>", "Agent provider ID").option("--agent <id>", "Agent ID").option("--agent-type <type>", "Agent type: agent, team, or workflow").option("--agent-timeout <seconds>", "Agent timeout in seconds", (v) => Number.parseInt(v, 10)).option("--agent-stream-mode", "Enable streaming responses").option("--agent-session-strategy <strategy>", "Session strategy: per_user, per_chat, per_user_per_chat").option("--agent-prefix-sender-name", "Prefix messages with sender name").option("--no-agent-prefix-sender-name", "Disable sender name prefix").option("--agent-wait-for-media", "Wait for media processing before dispatch").option("--no-agent-wait-for-media", "Dispatch immediately without waiting for media").option("--agent-send-media-path", "Include file path in formatted media text").option("--no-agent-send-media-path", "Exclude file path from formatted media text").option("--agent-send-media-path-types <types>", "Content types that receive file path (comma-separated: image,video,document)").option("--reply-filter-mode <mode>", "Reply filter: all or filtered").option("--reply-on-dm", "Reply to DMs").option("--no-reply-on-dm", "Ignore DMs").option("--reply-on-mention", "Reply when @mentioned").option("--no-reply-on-mention", "Ignore @mentions").option("--reply-on-reply", "Reply when message is reply to bot").option("--no-reply-on-reply", "Ignore replies").option("--reply-on-name", "Reply when bot name appears in text").option("--no-reply-on-name", "Ignore name matches").option("--reply-name-patterns <patterns>", "Custom name patterns (comma-separated)").option("--enable-auto-split", "Split responses on double newlines").option("--no-enable-auto-split", "Disable auto-split").option("--message-format-mode <mode>", "Format mode: convert or passthrough").option("--debounce-mode <mode>", "Debounce mode: disabled, fixed, or randomized").option("--debounce-min <ms>", "Minimum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-max <ms>", "Maximum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-restart-on-typing", "Restart debounce timer on typing").option("--debounce-group <ms>", "Group chat debounce in ms", (v) => Number.parseInt(v, 10)).option("--agent-gate", "Enable LLM response gate").option("--agent-gate-model <model>", "Model for response gate").option("--agent-gate-prompt <prompt>", "Custom gate prompt").option("--tts-voice <id>", "ElevenLabs voice ID").option("--tts-model <id>", "ElevenLabs model ID").option("--access-mode <mode>", "Access mode: disabled, blocklist, or allowlist").option("--reaction-ack <mode>", "Reaction ack mode (on|off)").option("--reaction-ack-emoji <json>", "Per-channel emoji map as JSON").option("--ack-timeout <ms>", "Ack timeout in milliseconds", (v) => Number.parseInt(v, 10)).option("--agent-stalled-timeout-ms <ms>", "Idle threshold in ms before the internal turn.stalled event fires (no channel message is ever sent)", (v) => Number.parseInt(v, 10)).option("--token <token>", "Generic bot token (auto-resolves to channel-specific field)").option("--telegram-token <token>", "Telegram bot token").option("--discord-token <token>", "Discord bot token").option("--slack-bot-token <token>", "Slack bot token").option("--slack-app-token <token>", "Slack app token").option("--gupshup-api-key <key>", "Gupshup API key").option("--gupshup-app-name <name>", "Gupshup app name").option("--gupshup-source-phone <phone>", "Gupshup source phone (E.164)").option("--gupshup-webhook-verify-token <token>", "Gupshup webhook verify token").option("--is-default", "Set as default instance for channel").action(async (options) => {
82936
82942
  const channel = options.channel;
82937
82943
  if (!VALID_CHANNELS2.includes(channel)) {
82938
82944
  error(`Invalid channel: ${channel}`, { validChannels: VALID_CHANNELS2 });
@@ -83193,7 +83199,7 @@ function createInstancesCommand() {
83193
83199
  throw new Error(err?.error?.message ?? `HTTP ${response.status}`);
83194
83200
  }
83195
83201
  }
83196
- instances.command("update <id>").description("Update an instance (supports all API fields)").option("--name <name>", "Instance name").option("--is-default", "Set as default instance for channel").option("--no-is-default", "Unset as default instance for channel").option("--agent-fk-id <uuid>", 'Agent FK UUID (references agents table, use "null" to clear)').option("--agent-provider <id>", 'Agent provider ID (use "null" to clear)').option("--agent <id>", 'Agent ID (use "null" to clear)').option("--agent-type <type>", "Agent type: agent, team, or workflow").option("--agent-timeout <seconds>", "Agent timeout in seconds", (v) => Number.parseInt(v, 10)).option("--agent-stream-mode", "Enable streaming responses").option("--no-agent-stream-mode", "Disable streaming responses").option("--agent-session-strategy <strategy>", "Session strategy: per_user, per_chat, per_user_per_chat").option("--agent-prefix-sender-name", "Prefix messages with sender name").option("--no-agent-prefix-sender-name", "Disable sender name prefix").option("--agent-wait-for-media", "Wait for media processing before dispatch").option("--no-agent-wait-for-media", "Dispatch immediately without waiting for media").option("--agent-send-media-path", "Include file path in formatted media text").option("--no-agent-send-media-path", "Exclude file path from formatted media text").option("--agent-send-media-path-types <types>", "Content types that receive file path (comma-separated: image,video,document)").option("--reply-filter-mode <mode>", "Reply filter: all or filtered").option("--reply-on-dm", "Reply to DMs (requires --reply-filter-mode filtered)").option("--no-reply-on-dm", "Ignore DMs").option("--reply-on-mention", "Reply when @mentioned").option("--no-reply-on-mention", "Ignore @mentions").option("--reply-on-reply", "Reply when message is reply to bot").option("--no-reply-on-reply", "Ignore replies").option("--reply-on-name", "Reply when bot name appears in text").option("--no-reply-on-name", "Ignore name matches").option("--reply-name-patterns <patterns>", "Custom name patterns (comma-separated)").option("--clear-reply-filter", "Remove reply filter (set to null)").option("--enable-auto-split", "Split responses on double newlines").option("--no-enable-auto-split", "Disable auto-split").option("--message-format-mode <mode>", "Format mode: convert or passthrough").option("--debounce-mode <mode>", "Debounce mode: disabled, fixed, or randomized").option("--debounce-min <ms>", "Minimum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-max <ms>", "Maximum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-restart-on-typing", "Restart debounce timer on typing").option("--no-debounce-restart-on-typing", "Do not restart debounce on typing").option("--debounce-group <ms>", 'Group chat debounce in ms (use "null" to inherit)', (v) => v === "null" ? null : Number.parseInt(v, 10)).option("--agent-gate", "Enable LLM response gate").option("--no-agent-gate", "Disable LLM response gate").option("--agent-gate-model <model>", 'Model for response gate (use "null" for default)').option("--agent-gate-prompt <prompt>", 'Custom gate prompt (use "null" for default)').option("--tts-voice <id>", 'ElevenLabs voice ID (use "null" to clear)').option("--tts-model <id>", 'ElevenLabs model ID (use "null" to clear)').option("--access-mode <mode>", "Access mode: disabled, blocklist, or allowlist").option("--reaction-ack <mode>", "Reaction ack mode (on|off)").option("--reaction-ack-emoji <json>", "Per-channel emoji map as JSON").option("--ack-timeout <ms>", "Ack timeout in milliseconds", (v) => Number.parseInt(v, 10)).option("--token <token>", "Generic bot token (auto-resolves to channel-specific field)").option("--telegram-token <token>", 'Telegram bot token (use "null" to clear)').option("--discord-token <token>", 'Discord bot token (use "null" to clear)').option("--slack-bot-token <token>", 'Slack bot token (use "null" to clear)').option("--slack-app-token <token>", 'Slack app token (use "null" to clear)').option("--trigger-events <events>", 'Trigger events (comma-separated, use "null" to clear)').option("--profile-name <name>", "Update WhatsApp display name (push name)").action(async (rawId, options) => {
83202
+ instances.command("update <id>").description("Update an instance (supports all API fields)").option("--name <name>", "Instance name").option("--is-default", "Set as default instance for channel").option("--no-is-default", "Unset as default instance for channel").option("--agent-fk-id <uuid>", 'Agent FK UUID (references agents table, use "null" to clear)').option("--agent-provider <id>", 'Agent provider ID (use "null" to clear)').option("--agent <id>", 'Agent ID (use "null" to clear)').option("--agent-type <type>", "Agent type: agent, team, or workflow").option("--agent-timeout <seconds>", "Agent timeout in seconds", (v) => Number.parseInt(v, 10)).option("--agent-stream-mode", "Enable streaming responses").option("--no-agent-stream-mode", "Disable streaming responses").option("--agent-session-strategy <strategy>", "Session strategy: per_user, per_chat, per_user_per_chat").option("--agent-prefix-sender-name", "Prefix messages with sender name").option("--no-agent-prefix-sender-name", "Disable sender name prefix").option("--agent-wait-for-media", "Wait for media processing before dispatch").option("--no-agent-wait-for-media", "Dispatch immediately without waiting for media").option("--agent-send-media-path", "Include file path in formatted media text").option("--no-agent-send-media-path", "Exclude file path from formatted media text").option("--agent-send-media-path-types <types>", "Content types that receive file path (comma-separated: image,video,document)").option("--reply-filter-mode <mode>", "Reply filter: all or filtered").option("--reply-on-dm", "Reply to DMs (requires --reply-filter-mode filtered)").option("--no-reply-on-dm", "Ignore DMs").option("--reply-on-mention", "Reply when @mentioned").option("--no-reply-on-mention", "Ignore @mentions").option("--reply-on-reply", "Reply when message is reply to bot").option("--no-reply-on-reply", "Ignore replies").option("--reply-on-name", "Reply when bot name appears in text").option("--no-reply-on-name", "Ignore name matches").option("--reply-name-patterns <patterns>", "Custom name patterns (comma-separated)").option("--clear-reply-filter", "Remove reply filter (set to null)").option("--enable-auto-split", "Split responses on double newlines").option("--no-enable-auto-split", "Disable auto-split").option("--message-format-mode <mode>", "Format mode: convert or passthrough").option("--debounce-mode <mode>", "Debounce mode: disabled, fixed, or randomized").option("--debounce-min <ms>", "Minimum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-max <ms>", "Maximum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-restart-on-typing", "Restart debounce timer on typing").option("--no-debounce-restart-on-typing", "Do not restart debounce on typing").option("--debounce-group <ms>", 'Group chat debounce in ms (use "null" to inherit)', (v) => v === "null" ? null : Number.parseInt(v, 10)).option("--agent-gate", "Enable LLM response gate").option("--no-agent-gate", "Disable LLM response gate").option("--agent-gate-model <model>", 'Model for response gate (use "null" for default)').option("--agent-gate-prompt <prompt>", 'Custom gate prompt (use "null" for default)').option("--tts-voice <id>", 'ElevenLabs voice ID (use "null" to clear)').option("--tts-model <id>", 'ElevenLabs model ID (use "null" to clear)').option("--access-mode <mode>", "Access mode: disabled, blocklist, or allowlist").option("--reaction-ack <mode>", "Reaction ack mode (on|off)").option("--reaction-ack-emoji <json>", "Per-channel emoji map as JSON").option("--ack-timeout <ms>", "Ack timeout in milliseconds", (v) => Number.parseInt(v, 10)).option("--agent-stalled-timeout-ms <ms>", "Idle threshold in ms before the internal turn.stalled event fires (no channel message is ever sent)", (v) => Number.parseInt(v, 10)).option("--token <token>", "Generic bot token (auto-resolves to channel-specific field)").option("--telegram-token <token>", 'Telegram bot token (use "null" to clear)').option("--discord-token <token>", 'Discord bot token (use "null" to clear)').option("--slack-bot-token <token>", 'Slack bot token (use "null" to clear)').option("--slack-app-token <token>", 'Slack app token (use "null" to clear)').option("--trigger-events <events>", 'Trigger events (comma-separated, use "null" to clear)').option("--profile-name <name>", "Update WhatsApp display name (push name)").action(async (rawId, options) => {
83197
83203
  const client = getClient();
83198
83204
  try {
83199
83205
  const id = await resolveInstanceId(rawId);
@@ -222829,7 +222829,7 @@ var init_sentry_scrub = __esm(() => {
222829
222829
  var require_package8 = __commonJS((exports, module) => {
222830
222830
  module.exports = {
222831
222831
  name: "@omni/api",
222832
- version: "2.260409.4",
222832
+ version: "2.260409.6",
222833
222833
  type: "module",
222834
222834
  exports: {
222835
222835
  ".": {
@@ -228600,6 +228600,7 @@ var init_schema2 = __esm(() => {
228600
228600
  lastMessageAt: timestamp("last_message_at"),
228601
228601
  replayEnabled: boolean("replay_enabled").notNull().default(true),
228602
228602
  lastSeenAt: timestamp("last_seen_at"),
228603
+ agentStalledTimeoutMs: integer("agent_stalled_timeout_ms").notNull().default(600000),
228603
228604
  agentChainToInstanceId: uuid("agent_chain_to_instance_id").references(() => instances.id, {
228604
228605
  onDelete: "set null"
228605
228606
  }),
@@ -359213,7 +359214,8 @@ var init_instances3 = __esm(() => {
359213
359214
  markOnlineOnConnect: exports_external.boolean().default(true).describe("Mark the instance as online when connecting to WhatsApp (default: true). Set to false to preserve phone push notifications."),
359214
359215
  reactionAck: exports_external.enum(["on", "off"]).default("off").describe("Reaction ack mode: on to send a reaction while agent processes"),
359215
359216
  reactionAckEmoji: exports_external.record(exports_external.string()).optional().nullable().describe('Per-channel emoji map for reaction ack (e.g. {"whatsapp":"\\u2705"})'),
359216
- ackTimeoutMs: exports_external.number().int().min(0).max(120000).default(30000).describe("Ack timeout in milliseconds (max 120000)")
359217
+ ackTimeoutMs: exports_external.number().int().min(0).max(120000).default(30000).describe("Ack timeout in milliseconds (max 120000)"),
359218
+ agentStalledTimeoutMs: exports_external.number().int().min(0).default(600000).describe("Idle threshold in ms before the internal turn.stalled event fires (no channel message is ever sent)")
359217
359219
  });
359218
359220
  updateInstanceSchema = createInstanceSchema.partial().extend({
359219
359221
  agentId: exports_external.string().uuid().nullable().optional(),
@@ -359232,7 +359234,8 @@ var init_instances3 = __esm(() => {
359232
359234
  groupHistorySize: exports_external.number().int().min(0).max(200).optional(),
359233
359235
  reactionAck: exports_external.enum(["on", "off"]).optional(),
359234
359236
  reactionAckEmoji: exports_external.record(exports_external.string()).nullable().optional(),
359235
- ackTimeoutMs: exports_external.number().int().min(0).max(120000).optional()
359237
+ ackTimeoutMs: exports_external.number().int().min(0).max(120000).optional(),
359238
+ agentStalledTimeoutMs: exports_external.number().int().min(0).optional()
359236
359239
  });
359237
359240
  SENSITIVE_INSTANCE_FIELDS = [
359238
359241
  "telegramBotToken",
@@ -362075,11 +362078,14 @@ var init_messages5 = __esm(() => {
362075
362078
  });
362076
362079
  }
362077
362080
  const resolvedTo = await resolveRecipient(to, instance4.channel, services);
362081
+ let fromMe = false;
362078
362082
  const chat2 = await services.chats.findByExternalIdSmart(instanceId, resolvedTo);
362079
362083
  if (chat2) {
362080
362084
  const target = await services.messages.getByExternalId(chat2.id, messageId);
362081
362085
  if (!target) {
362082
362086
  log90.warn("Target message not found in DB, sending reaction anyway", { messageId, chatId: chat2.id });
362087
+ } else {
362088
+ fromMe = target.isFromMe === true;
362083
362089
  }
362084
362090
  }
362085
362091
  const outgoingMessage = {
@@ -362088,7 +362094,8 @@ var init_messages5 = __esm(() => {
362088
362094
  type: "reaction",
362089
362095
  emoji,
362090
362096
  targetMessageId: messageId
362091
- }
362097
+ },
362098
+ metadata: { fromMe }
362092
362099
  };
362093
362100
  const result = await plugin6.sendMessage(instanceId, outgoingMessage);
362094
362101
  if (!result.success) {
@@ -363538,6 +363545,11 @@ function publishTurnNudge(instanceId, chatId, event) {
363538
363545
  publish(topic, event);
363539
363546
  log91.debug("Published turn.nudge", { turnId: event.turnId, nudgeCount: event.nudgeCount, instanceId });
363540
363547
  }
363548
+ function publishTurnStalled(instanceId, chatId, event) {
363549
+ const topic = `omni.turn.stalled.${instanceId}.${chatId}`;
363550
+ publish(topic, event);
363551
+ log91.debug("Published turn.stalled", { turnId: event.turnId, instanceId, chatId });
363552
+ }
363541
363553
  function publishTurnTimeout(instanceId, chatId, event) {
363542
363554
  const topic = `omni.turn.timeout.${instanceId}.${chatId}`;
363543
363555
  publish(topic, event);
@@ -369755,7 +369767,7 @@ class TurnMonitor {
369755
369767
  log102.info("Turn monitor started", {
369756
369768
  pollIntervalMs: POLL_INTERVAL_MS2,
369757
369769
  nudgeMs: NUDGE_THRESHOLD_MS,
369758
- fallbackMs: FALLBACK_THRESHOLD_MS,
369770
+ defaultStalledMs: DEFAULT_STALLED_THRESHOLD_MS,
369759
369771
  timeoutMs: TIMEOUT_THRESHOLD_MS
369760
369772
  });
369761
369773
  this.intervalId = setInterval(() => this.tick(), POLL_INTERVAL_MS2);
@@ -369780,8 +369792,10 @@ class TurnMonitor {
369780
369792
  await this.handleTimeout(turn.id, turn.instanceId, turn.chatId, idleSec, turn.nudgeCount);
369781
369793
  continue;
369782
369794
  }
369783
- if (idleMs >= FALLBACK_THRESHOLD_MS && turn.nudgeCount === 2) {
369784
- await this.handleFallback(turn.id, turn.instanceId, turn.chatId, idleSec);
369795
+ const instance4 = await this.deps.instanceService.getById(turn.instanceId).catch(() => null);
369796
+ const stalledThresholdMs = instance4?.agentStalledTimeoutMs ?? DEFAULT_STALLED_THRESHOLD_MS;
369797
+ if (idleMs >= stalledThresholdMs && turn.nudgeCount === 2) {
369798
+ await this.handleStalled(turn.id, turn.instanceId, turn.chatId, idleMs, stalledThresholdMs);
369785
369799
  continue;
369786
369800
  }
369787
369801
  const expectedNudges = Math.floor(idleMs / NUDGE_THRESHOLD_MS);
@@ -369805,16 +369819,11 @@ class TurnMonitor {
369805
369819
  });
369806
369820
  log102.info("Turn nudge emitted", { turnId, nudgeCount, idleSec });
369807
369821
  }
369808
- async handleFallback(turnId, instanceId, chatId, idleSec) {
369822
+ async handleStalled(turnId, instanceId, chatId, stalledAtMs, threshold) {
369809
369823
  await this.deps.turnService.incrementNudge(turnId);
369810
- if (this.deps.sendFallback) {
369811
- try {
369812
- await this.deps.sendFallback(instanceId, chatId, "\u23F1 Still processing your request...");
369813
- log102.info("Fallback message sent", { turnId, idleSec });
369814
- } catch (error2) {
369815
- log102.error("Failed to send fallback message", { turnId, error: String(error2) });
369816
- }
369817
- }
369824
+ const payload = { turnId, instanceId, chatId, stalledAtMs, threshold };
369825
+ publishTurnStalled(instanceId, chatId, payload);
369826
+ log102.warn("Turn stalled \u2014 internal event emitted (no channel message sent)", payload);
369818
369827
  }
369819
369828
  async handleTimeout(turnId, instanceId, chatId, idleSec, nudgeCount) {
369820
369829
  const closed = await this.deps.turnService.close(turnId, {
@@ -369824,19 +369833,10 @@ class TurnMonitor {
369824
369833
  if (!closed)
369825
369834
  return;
369826
369835
  const duration = closed.closedAt ? closed.closedAt.getTime() - closed.startedAt.getTime() : idleSec * 1000;
369827
- const fallbackSent = !!this.deps.sendFallback;
369828
- if (this.deps.sendFallback) {
369829
- try {
369830
- await this.deps.sendFallback(instanceId, chatId, "\u23F1 Request timed out. Please try again.");
369831
- } catch (error2) {
369832
- log102.error("Failed to send timeout fallback", { turnId, error: String(error2) });
369833
- }
369834
- }
369835
369836
  publishTurnTimeout(instanceId, chatId, {
369836
369837
  turnId,
369837
369838
  duration,
369838
- nudgeCount,
369839
- fallbackSent
369839
+ nudgeCount
369840
369840
  });
369841
369841
  publishTurnDone(instanceId, chatId, {
369842
369842
  turnId,
@@ -369849,7 +369849,7 @@ class TurnMonitor {
369849
369849
  log102.info("Turn force-closed (timeout)", { turnId, duration, nudgeCount });
369850
369850
  }
369851
369851
  }
369852
- var log102, NUDGE_THRESHOLD_MS = 120000, FALLBACK_THRESHOLD_MS = 600000, TIMEOUT_THRESHOLD_MS = 1800000, POLL_INTERVAL_MS2 = 1e4;
369852
+ var log102, NUDGE_THRESHOLD_MS = 120000, DEFAULT_STALLED_THRESHOLD_MS = 600000, TIMEOUT_THRESHOLD_MS = 1800000, POLL_INTERVAL_MS2 = 1e4;
369853
369853
  var init_turn_monitor = __esm(() => {
369854
369854
  init_src();
369855
369855
  init_turn_events();
@@ -370152,15 +370152,7 @@ async function setupEventBusServices(eventBus, services, db3) {
370152
370152
  try {
370153
370153
  globalTurnMonitor = new TurnMonitor({
370154
370154
  turnService: services.turns,
370155
- sendFallback: async (instanceId, chatId, text3) => {
370156
- const instance4 = await services.instances.getById(instanceId);
370157
- if (!instance4)
370158
- return;
370159
- const plugin6 = await getPlugin(instance4.channel);
370160
- if (!plugin6)
370161
- return;
370162
- await plugin6.sendMessage(instanceId, { to: chatId, content: { type: "text", text: text3 } });
370163
- }
370155
+ instanceService: services.instances
370164
370156
  });
370165
370157
  globalTurnMonitor.start();
370166
370158
  log104.info("Turn monitor started");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.260409.4",
3
+ "version": "2.260409.6",
4
4
  "description": "LLM-optimized CLI for Omni",
5
5
  "type": "module",
6
6
  "bin": {