@automagik/omni 2.260331.1 → 2.260404.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.
@@ -92,6 +92,13 @@
92
92
  "when": 1774721939291,
93
93
  "tag": "0012_large_wendell_rand",
94
94
  "breakpoints": true
95
+ },
96
+ {
97
+ "idx": 13,
98
+ "version": "7",
99
+ "when": 1775236890700,
100
+ "tag": "0013_curious_leo",
101
+ "breakpoints": true
95
102
  }
96
103
  ]
97
104
  }
@@ -2,7 +2,7 @@
2
2
  * Connect Command — omni connect <instance-id> <agent-name>
3
3
  *
4
4
  * One-command setup for Omni ↔ Genie NATS integration:
5
- * 1. Discovers agent via `genie dir get <agent-name> --json`
5
+ * 1. Discovers agent via `genie dir ls <agent-name> --json`
6
6
  * 2. Creates/updates Omni provider with schema `nats-genie`
7
7
  * 3. Creates Omni agent record linked to provider
8
8
  * 4. Updates instance to use the new agent
@@ -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;AAoJpC,wBAAgB,sBAAsB,IAAI,OAAO,CAinChD"}
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"}
package/dist/index.js CHANGED
@@ -76650,7 +76650,7 @@ import { fileURLToPath } from "url";
76650
76650
  // package.json
76651
76651
  var package_default = {
76652
76652
  name: "@automagik/omni",
76653
- version: "2.260331.1",
76653
+ version: "2.260404.1",
76654
76654
  description: "LLM-optimized CLI for Omni",
76655
76655
  type: "module",
76656
76656
  bin: {
@@ -79673,7 +79673,7 @@ function createConnectCommand() {
79673
79673
  info(`Discovering agent "${agentName}" from genie directory...`);
79674
79674
  let agentEntry;
79675
79675
  try {
79676
- const stdout = execFileSync("genie", ["dir", "get", agentName, "--json"], {
79676
+ const stdout = execFileSync("genie", ["dir", "ls", agentName, "--json"], {
79677
79677
  encoding: "utf-8",
79678
79678
  env: process.env,
79679
79679
  timeout: 1e4
@@ -81401,7 +81401,7 @@ function createInstallCommand() {
81401
81401
 
81402
81402
  // src/commands/instances.ts
81403
81403
  var import_qrcode_terminal = __toESM(require_main(), 1);
81404
- var VALID_CHANNELS2 = ["whatsapp-baileys", "whatsapp-cloud", "discord", "slack", "telegram"];
81404
+ var VALID_CHANNELS2 = ["whatsapp-baileys", "whatsapp-cloud", "discord", "slack", "telegram", "gupshup"];
81405
81405
  var VALID_SYNC_TYPES = ["profile", "messages", "contacts", "groups", "all"];
81406
81406
  function setVal(body, key, val) {
81407
81407
  if (val === "null")
@@ -81474,6 +81474,10 @@ function applyMiscFields(body, opts) {
81474
81474
  setVal(body, "discordBotToken", opts.discordToken);
81475
81475
  setVal(body, "slackBotToken", opts.slackBotToken);
81476
81476
  setVal(body, "slackAppToken", opts.slackAppToken);
81477
+ setVal(body, "gupshupApiKey", opts.gupshupApiKey);
81478
+ setVal(body, "gupshupAppName", opts.gupshupAppName);
81479
+ setVal(body, "gupshupSourcePhone", opts.gupshupSourcePhone);
81480
+ setVal(body, "webhookVerifyToken", opts.gupshupWebhookVerifyToken);
81477
81481
  if (opts.triggerEvents !== undefined) {
81478
81482
  const raw2 = opts.triggerEvents;
81479
81483
  body.triggerEvents = raw2 === "null" ? null : raw2.split(",").map((s) => s.trim());
@@ -81577,7 +81581,7 @@ function createInstancesCommand() {
81577
81581
  error(`Failed to get instance: ${message}`, undefined, 3);
81578
81582
  }
81579
81583
  });
81580
- 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("--is-default", "Set as default instance for channel").action(async (options) => {
81584
+ 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) => {
81581
81585
  const channel = options.channel;
81582
81586
  if (!VALID_CHANNELS2.includes(channel)) {
81583
81587
  error(`Invalid channel: ${channel}`, { validChannels: VALID_CHANNELS2 });
@@ -22377,6 +22377,7 @@ var init_channel = __esm(() => {
22377
22377
  "slack",
22378
22378
  "telegram",
22379
22379
  "a2a",
22380
+ "gupshup",
22380
22381
  "internal"
22381
22382
  ];
22382
22383
  CONTENT_TYPES = [
@@ -222785,7 +222786,7 @@ var init_sentry_scrub = __esm(() => {
222785
222786
  var require_package8 = __commonJS((exports, module) => {
222786
222787
  module.exports = {
222787
222788
  name: "@omni/api",
222788
- version: "2.260331.1",
222789
+ version: "2.260404.1",
222789
222790
  type: "module",
222790
222791
  exports: {
222791
222792
  ".": {
@@ -228237,6 +228238,7 @@ var init_schema2 = __esm(() => {
228237
228238
  "slack",
228238
228239
  "telegram",
228239
228240
  "a2a",
228241
+ "gupshup",
228240
228242
  "internal"
228241
228243
  ];
228242
228244
  agentTypes = ["agent", "team", "workflow"];
@@ -228478,6 +228480,10 @@ var init_schema2 = __esm(() => {
228478
228480
  slackSigningSecret: text("slack_signing_secret"),
228479
228481
  telegramBotToken: text("telegram_bot_token"),
228480
228482
  telegramReactionLevel: varchar("telegram_reaction_level", { length: 20 }).notNull().default("off"),
228483
+ gupshupApiKey: text("gupshup_api_key"),
228484
+ gupshupAppName: varchar("gupshup_app_name", { length: 255 }),
228485
+ gupshupSourcePhone: varchar("gupshup_source_phone", { length: 20 }),
228486
+ webhookVerifyToken: text("webhook_verify_token"),
228481
228487
  agentId: uuid("agent_id").references(() => agents.id, { onDelete: "set null" }),
228482
228488
  agentTimeout: integer("agent_timeout").notNull().default(60),
228483
228489
  agentStreamMode: boolean("agent_stream_mode").notNull().default(false),
@@ -332112,6 +332118,16 @@ function applyChannelSpecificConnectionOptions(options, input) {
332112
332118
  if (input.slackSigningSecret)
332113
332119
  options.signingSecret = input.slackSigningSecret;
332114
332120
  }
332121
+ if (input.channel === "gupshup") {
332122
+ if (input.gupshupApiKey)
332123
+ options.gupshupApiKey = input.gupshupApiKey;
332124
+ if (input.gupshupAppName)
332125
+ options.gupshupAppName = input.gupshupAppName;
332126
+ if (input.gupshupSourcePhone)
332127
+ options.gupshupSourcePhone = input.gupshupSourcePhone;
332128
+ if (input.webhookVerifyToken)
332129
+ options.webhookVerifyToken = input.webhookVerifyToken;
332130
+ }
332115
332131
  }
332116
332132
  function buildInstanceConnectionOptions(input) {
332117
332133
  const options = { forceNewQr: input.forceNewQr };
@@ -332304,6 +332320,10 @@ var init_instances3 = __esm(() => {
332304
332320
  slackBotToken: exports_external.string().optional().nullable().describe("Slack bot token (persisted for reconnection)"),
332305
332321
  slackAppToken: exports_external.string().optional().nullable().describe("Slack app token (persisted for reconnection)"),
332306
332322
  slackSigningSecret: exports_external.string().optional().nullable().describe("Slack signing secret (persisted for reconnection)"),
332323
+ gupshupApiKey: exports_external.string().optional().nullable().describe("Gupshup API key"),
332324
+ gupshupAppName: exports_external.string().optional().nullable().describe("Gupshup app name"),
332325
+ gupshupSourcePhone: exports_external.string().optional().nullable().describe("Gupshup source phone (E.164)"),
332326
+ webhookVerifyToken: exports_external.string().optional().nullable().describe("Gupshup webhook verify token"),
332307
332327
  readReceipts: exports_external.enum(["on", "off", "exclude-self"]).default("on").describe("Read receipt mode: on (default), off, or exclude-self (skip receipts for the instance own number)"),
332308
332328
  groupHistorySize: exports_external.number().int().min(0).max(200).default(50).describe("Number of context messages to include when dispatching to agent. Groups use the full value; DMs are capped at 20. (0 = disabled, max 200)"),
332309
332329
  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."),
@@ -332319,6 +332339,10 @@ var init_instances3 = __esm(() => {
332319
332339
  discordBotToken: exports_external.string().nullable().optional(),
332320
332340
  slackBotToken: exports_external.string().nullable().optional(),
332321
332341
  slackAppToken: exports_external.string().nullable().optional(),
332342
+ gupshupApiKey: exports_external.string().nullable().optional(),
332343
+ gupshupAppName: exports_external.string().nullable().optional(),
332344
+ gupshupSourcePhone: exports_external.string().nullable().optional(),
332345
+ webhookVerifyToken: exports_external.string().nullable().optional(),
332322
332346
  readReceipts: exports_external.enum(["on", "off", "exclude-self"]).optional(),
332323
332347
  markOnlineOnConnect: exports_external.boolean().optional(),
332324
332348
  groupHistorySize: exports_external.number().int().min(0).max(200).optional(),
@@ -332331,7 +332355,9 @@ var init_instances3 = __esm(() => {
332331
332355
  "discordBotToken",
332332
332356
  "slackBotToken",
332333
332357
  "slackAppToken",
332334
- "slackSigningSecret"
332358
+ "slackSigningSecret",
332359
+ "gupshupApiKey",
332360
+ "webhookVerifyToken"
332335
332361
  ];
332336
332362
  instancesRoutes.get("/", zValidator("query", listQuerySchema10), async (c) => {
332337
332363
  const { channel: channel4, status, limit: limit2, cursor } = c.req.valid("query");
@@ -332393,7 +332419,11 @@ var init_instances3 = __esm(() => {
332393
332419
  token: connectToken,
332394
332420
  telegramReactionLevel: instance4.telegramReactionLevel,
332395
332421
  slackAppToken: instance4.slackAppToken,
332396
- slackSigningSecret: instance4.slackSigningSecret
332422
+ slackSigningSecret: instance4.slackSigningSecret,
332423
+ gupshupApiKey: instance4.gupshupApiKey,
332424
+ gupshupAppName: instance4.gupshupAppName,
332425
+ gupshupSourcePhone: instance4.gupshupSourcePhone,
332426
+ webhookVerifyToken: instance4.webhookVerifyToken
332397
332427
  });
332398
332428
  const createPlugin = getPluginFromRegistry(channelRegistry2, data.channel);
332399
332429
  if (createPlugin && "loadGuildConfigs" in createPlugin && instance4.guildConfigOverrides) {
@@ -332556,7 +332586,11 @@ var init_instances3 = __esm(() => {
332556
332586
  telegramReactionLevel: instance4.telegramReactionLevel,
332557
332587
  slackAppToken: body.slackAppToken ?? instance4.slackAppToken,
332558
332588
  slackSigningSecret: body.slackSigningSecret ?? instance4.slackSigningSecret,
332559
- whatsapp: body.whatsapp
332589
+ whatsapp: body.whatsapp,
332590
+ gupshupApiKey: instance4.gupshupApiKey,
332591
+ gupshupAppName: instance4.gupshupAppName,
332592
+ gupshupSourcePhone: instance4.gupshupSourcePhone,
332593
+ webhookVerifyToken: instance4.webhookVerifyToken
332560
332594
  });
332561
332595
  if (!channelRegistry2) {
332562
332596
  return c.json({ error: { code: "NO_REGISTRY", message: "Channel registry not available" } }, 503);
@@ -336375,6 +336409,7 @@ function createApp(db2, eventBus = null, channelRegistry2 = null) {
336375
336409
  app.use("*", contextMiddleware);
336376
336410
  app.use("*", versionHeadersMiddleware);
336377
336411
  app.onError(errorHandler2);
336412
+ app.get("/health", (c) => c.redirect("/api/v2/health", 307));
336378
336413
  app.route("/api/v2", healthRoutes);
336379
336414
  app.route("/api/v2", openapiRoutes);
336380
336415
  if (process.env.A2A_ENABLED === "true") {
@@ -339792,12 +339827,52 @@ function createNatsGenieProviderInstance(provider, instance4) {
339792
339827
  return null;
339793
339828
  }
339794
339829
  const natsUrl = typeof schemaConfig.natsUrl === "string" ? schemaConfig.natsUrl : "localhost:4222";
339795
- return new NatsGenieProvider(provider.id, provider.name, {
339830
+ const channel4 = instance4.channel;
339831
+ const natsProvider = new NatsGenieProvider(provider.id, provider.name, {
339796
339832
  agentName,
339797
339833
  natsUrl,
339798
339834
  instanceId: instance4.id,
339799
- prefixSenderName: instance4.agentPrefixSenderName ?? true
339835
+ prefixSenderName: instance4.agentPrefixSenderName ?? true,
339836
+ onReply: async (chatId, content, metadata) => {
339837
+ try {
339838
+ await sendTextMessage5(channel4, instance4.id, chatId, content);
339839
+ } catch (error2) {
339840
+ log86.error("Failed to deliver agent reply", {
339841
+ chatId,
339842
+ instanceId: instance4.id,
339843
+ providerId: provider.id,
339844
+ agent: metadata?.agent,
339845
+ error: error2 instanceof Error ? error2.message : String(error2)
339846
+ });
339847
+ }
339848
+ }
339800
339849
  });
339850
+ const startWithRetry = async (attempt = 1) => {
339851
+ try {
339852
+ await natsProvider.startReplySubscription();
339853
+ log86.info("NATS reply subscription started", { instanceId: instance4.id, attempt });
339854
+ } catch (err) {
339855
+ const delay2 = Math.min(2000 * 2 ** (attempt - 1), 60000);
339856
+ if (attempt < 10) {
339857
+ log86.warn("NATS reply subscription failed, retrying", {
339858
+ instanceId: instance4.id,
339859
+ providerId: provider.id,
339860
+ attempt,
339861
+ nextRetryMs: delay2,
339862
+ error: err instanceof Error ? err.message : String(err)
339863
+ });
339864
+ setTimeout(() => startWithRetry(attempt + 1), delay2);
339865
+ } else {
339866
+ log86.error("NATS reply subscription permanently failed", {
339867
+ instanceId: instance4.id,
339868
+ providerId: provider.id,
339869
+ error: err instanceof Error ? err.message : String(err)
339870
+ });
339871
+ }
339872
+ }
339873
+ };
339874
+ startWithRetry();
339875
+ return natsProvider;
339801
339876
  }
339802
339877
  function resolveProvider(provider, instance4, db2) {
339803
339878
  const cacheKey = `${provider.id}:${instance4.id}`;
@@ -341439,6 +341514,16 @@ function buildInstanceConnectOptions(instance4) {
341439
341514
  options.signingSecret = instance4.slackSigningSecret;
341440
341515
  applySlackMetadata(options, instance4.profileMetadata);
341441
341516
  }
341517
+ if (instance4.channel === "gupshup") {
341518
+ if (instance4.gupshupApiKey)
341519
+ options.gupshupApiKey = instance4.gupshupApiKey;
341520
+ if (instance4.gupshupAppName)
341521
+ options.gupshupAppName = instance4.gupshupAppName;
341522
+ if (instance4.gupshupSourcePhone)
341523
+ options.gupshupSourcePhone = instance4.gupshupSourcePhone;
341524
+ if (instance4.webhookVerifyToken)
341525
+ options.webhookVerifyToken = instance4.webhookVerifyToken;
341526
+ }
341442
341527
  return options;
341443
341528
  }
341444
341529
  async function connectInstance(instance4, registry5) {
@@ -460672,6 +460757,14 @@ function buildMessageContent2(message2, buildVCard) {
460672
460757
  return builder(message2, buildVCard);
460673
460758
  }
460674
460759
 
460760
+ // ../channel-whatsapp/src/senders/contact.ts
460761
+ function computeWaid(digits) {
460762
+ if (digits.length === 13 && digits.startsWith("55") && digits.charAt(4) === "9") {
460763
+ return digits.slice(0, 4) + digits.slice(5);
460764
+ }
460765
+ return digits;
460766
+ }
460767
+
460675
460768
  // ../channel-whatsapp/src/senders/reaction.ts
460676
460769
  function buildReactionContent(targetJid, targetMessageId, emoji, fromMe = true) {
460677
460770
  return {
@@ -462163,7 +462256,10 @@ class WhatsAppPlugin extends BaseChannelPlugin {
462163
462256
  });
462164
462257
  const correlationId = message2.metadata?.correlationId;
462165
462258
  correlationId && this.captureT10(correlationId);
462166
- await sendReaction(sock, jid, targetMessageId, reactionEmoji, fromMe);
462259
+ const reactionMsgId = await sendReaction(sock, jid, targetMessageId, reactionEmoji, fromMe);
462260
+ if (reactionMsgId) {
462261
+ this.trackSentMessageId(instanceId, reactionMsgId);
462262
+ }
462167
462263
  correlationId && this.captureT11(correlationId);
462168
462264
  return {
462169
462265
  success: true,
@@ -462213,7 +462309,9 @@ class WhatsAppPlugin extends BaseChannelPlugin {
462213
462309
  buildVCard(contact) {
462214
462310
  const lines = ["BEGIN:VCARD", "VERSION:3.0", `FN:${contact.name}`];
462215
462311
  if (contact.phone) {
462216
- lines.push(`TEL;type=CELL:${contact.phone}`);
462312
+ const digits = contact.phone.replace(/[^\d]/g, "");
462313
+ const waid = computeWaid(digits);
462314
+ lines.push(`TEL;type=CELL;waid=${waid}:${contact.phone}`);
462217
462315
  }
462218
462316
  if (contact.email) {
462219
462317
  lines.push(`EMAIL:${contact.email}`);
@@ -462248,12 +462346,18 @@ class WhatsAppPlugin extends BaseChannelPlugin {
462248
462346
  async react(instanceId, chatId, messageId, emoji) {
462249
462347
  const sock = this.getSocket(instanceId);
462250
462348
  const jid = toJid(chatId);
462251
- await sendReaction(sock, jid, messageId, emoji, false);
462349
+ const reactionMsgId = await sendReaction(sock, jid, messageId, emoji, false);
462350
+ if (reactionMsgId) {
462351
+ this.trackSentMessageId(instanceId, reactionMsgId);
462352
+ }
462252
462353
  }
462253
462354
  async unreact(instanceId, chatId, messageId, _emoji) {
462254
462355
  const sock = this.getSocket(instanceId);
462255
462356
  const jid = toJid(chatId);
462256
- await removeReaction4(sock, jid, messageId, false);
462357
+ const reactionMsgId = await removeReaction4(sock, jid, messageId, false);
462358
+ if (reactionMsgId) {
462359
+ this.trackSentMessageId(instanceId, reactionMsgId);
462360
+ }
462257
462361
  }
462258
462362
  resolveMessageKey(instanceId, id, jid, isGroup, dataByExternalId, lidCache) {
462259
462363
  const raw = dataByExternalId.get(id);
@@ -463016,7 +463120,7 @@ class WhatsAppPlugin extends BaseChannelPlugin {
463016
463120
  emoji: ""
463017
463121
  });
463018
463122
  }
463019
- if (process.env.OMNI_DUAL_EMIT_REACTIONS !== "false") {
463123
+ if (process.env.OMNI_DUAL_EMIT_REACTIONS !== "false" && !isFromMe2) {
463020
463124
  await this.emitMessageReceived({
463021
463125
  instanceId,
463022
463126
  externalId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.260331.1",
3
+ "version": "2.260404.1",
4
4
  "description": "LLM-optimized CLI for Omni",
5
5
  "type": "module",
6
6
  "bin": {
@@ -33,14 +33,14 @@
33
33
  "qrcode-terminal": "^0.12.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@omni/api": "2.260323.1",
37
- "@omni/channel-discord": "2.260323.1",
38
- "@omni/channel-sdk": "2.260323.1",
39
- "@omni/channel-slack": "2.260323.1",
40
- "@omni/channel-telegram": "2.260323.1",
41
- "@omni/channel-whatsapp": "2.260323.1",
42
- "@omni/core": "2.260323.1",
43
- "@omni/sdk": "2.260323.1",
36
+ "@omni/api": "2.260331.1",
37
+ "@omni/channel-discord": "2.260331.1",
38
+ "@omni/channel-sdk": "2.260331.1",
39
+ "@omni/channel-slack": "2.260331.1",
40
+ "@omni/channel-telegram": "2.260331.1",
41
+ "@omni/channel-whatsapp": "2.260331.1",
42
+ "@omni/core": "2.260331.1",
43
+ "@omni/sdk": "2.260331.1",
44
44
  "@types/node": "^22.10.3",
45
45
  "@types/qrcode-terminal": "^0.12.2",
46
46
  "typescript": "^5.7.3"