@automagik/omni 2.260422.5 → 2.260422.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.
@@ -0,0 +1,15 @@
1
+ -- #384: Drop inbound rate limiter on the dispatcher.
2
+ --
3
+ -- The `trigger_rate_limit` column gated raw inbound `message.received` events
4
+ -- (default 5 msgs / 60s per user-channel-instance) before they reached the
5
+ -- `MessageDebouncer`. Fast-typed conversational bursts — natural on WhatsApp —
6
+ -- routinely exceeded the cap and the limiter silently dropped messages with no
7
+ -- feedback, retry, or DLQ, corrupting agent context downstream.
8
+ --
9
+ -- The debouncer already collapses bursts into a single dispatch (messageCount:N),
10
+ -- so this cap was both redundant and actively harmful. The `RateLimiter` class,
11
+ -- inbound+reaction rate gates, and `trigger_rate_limit` column are all removed.
12
+ -- If backend-protection caps are later needed, they must be dispatch-level
13
+ -- (counting completed agent runs), not message-level.
14
+
15
+ ALTER TABLE "instances" DROP COLUMN "trigger_rate_limit";
@@ -197,6 +197,13 @@
197
197
  "when": 1776766900000,
198
198
  "tag": "0027_bridge_tmux_session",
199
199
  "breakpoints": true
200
+ },
201
+ {
202
+ "idx": 28,
203
+ "version": "7",
204
+ "when": 1777000000000,
205
+ "tag": "0028_drop_trigger_rate_limit",
206
+ "breakpoints": true
200
207
  }
201
208
  ]
202
209
  }
package/dist/index.js CHANGED
@@ -58796,7 +58796,6 @@ var init_schema2 = __esm(() => {
58796
58796
  triggerReactions: jsonb("trigger_reactions").$type(),
58797
58797
  triggerMentionPatterns: jsonb("trigger_mention_patterns").$type(),
58798
58798
  triggerMode: varchar("trigger_mode", { length: 20 }).notNull().default("round-trip"),
58799
- triggerRateLimit: integer("trigger_rate_limit").notNull().default(5),
58800
58799
  inboundMaxAgeMinutes: integer("inbound_max_age_minutes").notNull().default(10),
58801
58800
  profileName: varchar("profile_name", { length: 255 }),
58802
58801
  profilePicUrl: text("profile_pic_url"),
@@ -113804,7 +113803,7 @@ import { fileURLToPath } from "url";
113804
113803
  // package.json
113805
113804
  var package_default = {
113806
113805
  name: "@automagik/omni",
113807
- version: "2.260422.5",
113806
+ version: "2.260422.6",
113808
113807
  description: "LLM-optimized CLI for Omni",
113809
113808
  type: "module",
113810
113809
  bin: {
@@ -224451,7 +224451,7 @@ var init_sentry_scrub = __esm(() => {
224451
224451
  var require_package8 = __commonJS((exports, module) => {
224452
224452
  module.exports = {
224453
224453
  name: "@omni/api",
224454
- version: "2.260422.5",
224454
+ version: "2.260422.6",
224455
224455
  type: "module",
224456
224456
  exports: {
224457
224457
  ".": {
@@ -230193,7 +230193,6 @@ var init_schema2 = __esm(() => {
230193
230193
  triggerReactions: jsonb("trigger_reactions").$type(),
230194
230194
  triggerMentionPatterns: jsonb("trigger_mention_patterns").$type(),
230195
230195
  triggerMode: varchar("trigger_mode", { length: 20 }).notNull().default("round-trip"),
230196
- triggerRateLimit: integer("trigger_rate_limit").notNull().default(5),
230197
230196
  inboundMaxAgeMinutes: integer("inbound_max_age_minutes").notNull().default(10),
230198
230197
  profileName: varchar("profile_name", { length: 255 }),
230199
230198
  profilePicUrl: text("profile_pic_url"),
@@ -282871,38 +282870,6 @@ function createPluginAckProvider(plugin6) {
282871
282870
  };
282872
282871
  }
282873
282872
 
282874
- class RateLimiter {
282875
- counters = new Map;
282876
- windowMs;
282877
- constructor(windowMs = DEFAULT_RATE_WINDOW_MS) {
282878
- this.windowMs = windowMs;
282879
- }
282880
- isAllowed(userId, channelType, instanceId, maxPerMinute) {
282881
- const key = `${userId}:${channelType}:${instanceId}`;
282882
- const now = Date.now();
282883
- let timestamps = this.counters.get(key) ?? [];
282884
- timestamps = timestamps.filter((ts) => now - ts < this.windowMs);
282885
- if (timestamps.length >= maxPerMinute) {
282886
- log90.debug("Rate limit exceeded", { key, count: timestamps.length, limit: maxPerMinute });
282887
- return false;
282888
- }
282889
- timestamps.push(now);
282890
- this.counters.set(key, timestamps);
282891
- return true;
282892
- }
282893
- cleanup() {
282894
- const now = Date.now();
282895
- for (const [key, timestamps] of this.counters.entries()) {
282896
- const active = timestamps.filter((ts) => now - ts < this.windowMs);
282897
- if (active.length === 0) {
282898
- this.counters.delete(key);
282899
- } else {
282900
- this.counters.set(key, active);
282901
- }
282902
- }
282903
- }
282904
- }
282905
-
282906
282873
  class ReactionDedup {
282907
282874
  seen = new Map;
282908
282875
  maxEntries = 1e4;
@@ -284949,7 +284916,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
284949
284916
  }
284950
284917
  return true;
284951
284918
  }
284952
- async function shouldProcessReaction(agentRunner, accessService, rateLimiter, reactionDedup, payload, metadata, eventType = "reaction.received") {
284919
+ async function shouldProcessReaction(agentRunner, accessService, reactionDedup, payload, metadata, eventType = "reaction.received") {
284953
284920
  if (!metadata.instanceId)
284954
284921
  return null;
284955
284922
  const instance4 = await agentRunner.getInstanceWithProvider(metadata.instanceId);
@@ -284962,11 +284929,6 @@ async function shouldProcessReaction(agentRunner, accessService, rateLimiter, re
284962
284929
  return null;
284963
284930
  }
284964
284931
  const channel4 = metadata.channelType ?? instance4.channel;
284965
- const rateLimit = instance4.triggerRateLimit;
284966
- if (!rateLimiter.isAllowed(payload.from, channel4, instance4.id, rateLimit ?? DEFAULT_RATE_LIMIT)) {
284967
- log90.info("Rate limited reaction trigger", { instanceId: instance4.id, from: payload.from });
284968
- return null;
284969
- }
284970
284932
  const accessDenied = await checkAccessWithFallback(accessService, instance4, payload, channel4);
284971
284933
  if (accessDenied)
284972
284934
  return null;
@@ -285072,9 +285034,7 @@ async function shouldSkipViaGate(triggerType, firstMsg, instance4, messages4, se
285072
285034
  async function setupAgentDispatcher(eventBus, services, db2) {
285073
285035
  const agentRunner = services.agentRunner;
285074
285036
  const accessService = services.access;
285075
- const rateLimiter = new RateLimiter;
285076
285037
  const reactionDedup = new ReactionDedup;
285077
- const cleanupInterval2 = setInterval(() => rateLimiter.cleanup(), 60000);
285078
285038
  const mediaCleanupInterval = setInterval(() => {
285079
285039
  const now = Date.now();
285080
285040
  const leakThreshold = 10 * 60000;
@@ -285109,17 +285069,6 @@ async function setupAgentDispatcher(eventBus, services, db2) {
285109
285069
  const triggerType = classifyMessageTrigger(msgContext);
285110
285070
  if (await shouldSkipViaGate(triggerType, firstMsg, instance4, messages4, services))
285111
285071
  return;
285112
- const channel4 = firstMsg.metadata.channelType ?? instance4.channel;
285113
- const rateLimit = instance4.triggerRateLimit;
285114
- if (!rateLimiter.isAllowed(firstMsg.payload.from, channel4, instance4.id, rateLimit ?? DEFAULT_RATE_LIMIT)) {
285115
- log90.info("Rate limited (debounced trigger)", {
285116
- instanceId: instance4.id,
285117
- from: firstMsg.payload.from,
285118
- channel: channel4,
285119
- bufferedCount: messages4.length
285120
- });
285121
- return;
285122
- }
285123
285072
  if (firstMsg.metadata.journeyTracked && firstMsg.metadata.correlationId) {
285124
285073
  const tracker = getJourneyTracker();
285125
285074
  tracker.recordCheckpoint(firstMsg.metadata.correlationId, "T5", JOURNEY_STAGES.T5);
@@ -285179,7 +285128,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
285179
285128
  const payload = event.payload;
285180
285129
  const metadata = event.metadata;
285181
285130
  try {
285182
- const instance4 = await shouldProcessReaction(agentRunner, accessService, rateLimiter, reactionDedup, payload, metadata);
285131
+ const instance4 = await shouldProcessReaction(agentRunner, accessService, reactionDedup, payload, metadata);
285183
285132
  if (!instance4)
285184
285133
  return;
285185
285134
  const traceId = metadata.traceId ?? generateCorrelationId("trc");
@@ -285208,7 +285157,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
285208
285157
  const payload = event.payload;
285209
285158
  const metadata = event.metadata;
285210
285159
  try {
285211
- const instance4 = await shouldProcessReaction(agentRunner, accessService, rateLimiter, reactionDedup, payload, metadata, "reaction.removed");
285160
+ const instance4 = await shouldProcessReaction(agentRunner, accessService, reactionDedup, payload, metadata, "reaction.removed");
285212
285161
  if (!instance4)
285213
285162
  return;
285214
285163
  const traceId = metadata.traceId ?? generateCorrelationId("trc");
@@ -285278,14 +285227,12 @@ async function setupAgentDispatcher(eventBus, services, db2) {
285278
285227
  log90.info("Agent dispatcher initialized (message + reaction + reaction-removed + media triggers)");
285279
285228
  } catch (error2) {
285280
285229
  log90.error("Failed to set up agent dispatcher", { error: String(error2) });
285281
- clearInterval(cleanupInterval2);
285282
285230
  clearInterval(mediaCleanupInterval);
285283
285231
  debouncer.clear();
285284
285232
  throw error2;
285285
285233
  }
285286
285234
  return async () => {
285287
285235
  log90.info("Shutting down agent dispatcher");
285288
- clearInterval(cleanupInterval2);
285289
285236
  clearInterval(mediaCleanupInterval);
285290
285237
  debouncer.clear();
285291
285238
  for (const [mediaId, pending] of mediaCompletions.entries()) {
@@ -285331,7 +285278,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
285331
285278
  log90.info("Agent dispatcher shutdown complete");
285332
285279
  };
285333
285280
  }
285334
- var log90, _natsGenieProviderCtor, QUOTED_MESSAGE_MAX_CHARS = 4000, DM_HISTORY_LIMIT = 20, DEFAULT_RATE_LIMIT = 5, DEFAULT_RATE_WINDOW_MS = 60000, CHANNEL_MESSAGE_LIMITS, DEFAULT_MESSAGE_LIMIT = 4000, MEDIA_BASE_PATH3, MEDIA_ICONS, MEDIA_WAIT_NULL, mediaCompletions, mediaResultCache, DEFAULT_SEND_MEDIA_PATH_TYPES, BOT_PREFIX = "\uD83E\uDD16 ", activeStreams, sessionActivityStore, PROC_REACT_START, PROC_REACT_DONE = "\u2705", providerCache, openclawClientPool, nullFilterWarnedInstances, DEFAULT_GATE_MODEL = "gemini-3-flash-preview", GATE_TIMEOUT_MS = 3000, setupAgentResponder;
285281
+ var log90, _natsGenieProviderCtor, QUOTED_MESSAGE_MAX_CHARS = 4000, DM_HISTORY_LIMIT = 20, CHANNEL_MESSAGE_LIMITS, DEFAULT_MESSAGE_LIMIT = 4000, MEDIA_BASE_PATH3, MEDIA_ICONS, MEDIA_WAIT_NULL, mediaCompletions, mediaResultCache, DEFAULT_SEND_MEDIA_PATH_TYPES, BOT_PREFIX = "\uD83E\uDD16 ", activeStreams, sessionActivityStore, PROC_REACT_START, PROC_REACT_DONE = "\u2705", providerCache, openclawClientPool, nullFilterWarnedInstances, DEFAULT_GATE_MODEL = "gemini-3-flash-preview", GATE_TIMEOUT_MS = 3000, setupAgentResponder;
285335
285282
  var init_agent_dispatcher = __esm(() => {
285336
285283
  init_src2();
285337
285284
  init_src();
@@ -292993,6 +292940,39 @@ var init_dist6 = __esm(() => {
292993
292940
  init_zod();
292994
292941
  });
292995
292942
 
292943
+ // ../api/src/schemas/date-query.ts
292944
+ function parseDateOrIssue(paramName, v2, ctx) {
292945
+ const parsed = new Date(v2);
292946
+ if (Number.isNaN(parsed.getTime())) {
292947
+ ctx.addIssue({
292948
+ code: exports_external.ZodIssueCode.custom,
292949
+ message: `invalid ${paramName} parameter: expected ISO 8601 date string, got "${v2}"`
292950
+ });
292951
+ return exports_external.NEVER;
292952
+ }
292953
+ return parsed;
292954
+ }
292955
+ var optionalDateParam = (paramName) => exports_external.string().optional().transform((v2, ctx) => {
292956
+ if (v2 === undefined || v2 === "")
292957
+ return;
292958
+ return parseDateOrIssue(paramName, v2, ctx);
292959
+ }), requiredDateParam = (paramName) => exports_external.string({
292960
+ required_error: `${paramName} is required`,
292961
+ invalid_type_error: `${paramName} must be a string`
292962
+ }).transform((v2, ctx) => {
292963
+ if (v2 === "") {
292964
+ ctx.addIssue({
292965
+ code: exports_external.ZodIssueCode.custom,
292966
+ message: `${paramName} is required`
292967
+ });
292968
+ return exports_external.NEVER;
292969
+ }
292970
+ return parseDateOrIssue(paramName, v2, ctx);
292971
+ });
292972
+ var init_date_query = __esm(() => {
292973
+ init_zod();
292974
+ });
292975
+
292996
292976
  // ../api/src/routes/v2/access.ts
292997
292977
  var accessRoutes, listQuerySchema, createRuleSchema, updateRuleSchema, checkAccessSchema;
292998
292978
  var init_access3 = __esm(() => {
@@ -293000,6 +292980,7 @@ var init_access3 = __esm(() => {
293000
292980
  init_src();
293001
292981
  init_dist2();
293002
292982
  init_zod();
292983
+ init_date_query();
293003
292984
  accessRoutes = new Hono2;
293004
292985
  listQuerySchema = exports_external.object({
293005
292986
  instanceId: exports_external.string().uuid().optional(),
@@ -293014,7 +292995,7 @@ var init_access3 = __esm(() => {
293014
292995
  priority: exports_external.number().int().default(0).describe("Rule priority (higher = checked first)"),
293015
292996
  enabled: exports_external.boolean().default(true).describe("Whether rule is active"),
293016
292997
  reason: exports_external.string().optional().describe("Human-readable reason"),
293017
- expiresAt: exports_external.string().datetime().optional().transform((v2) => v2 ? new Date(v2) : undefined).describe("Optional expiration"),
292998
+ expiresAt: optionalDateParam("expiresAt").describe("Optional expiration (ISO 8601 date string)"),
293018
292999
  action: exports_external.enum(["block", "allow", "silent_block"]).default("block").describe("Action to take"),
293019
293000
  blockMessage: exports_external.string().optional().describe("Custom block message")
293020
293001
  });
@@ -294177,25 +294158,14 @@ function resolveContactName2(chat2, contactNames) {
294177
294158
  }
294178
294159
  return;
294179
294160
  }
294180
- var chatsRoutes, ChatTypeSchema, listQuerySchema6, createChatSchema, updateChatSchema, addParticipantSchema, updateParticipantRoleSchema, chatChannelActionSchema, muteActionSchema, labelBodySchema, optionalDateParam = (paramName) => exports_external.string().optional().transform((v2, ctx) => {
294181
- if (v2 === undefined || v2 === "")
294182
- return;
294183
- const parsed = new Date(v2);
294184
- if (Number.isNaN(parsed.getTime())) {
294185
- ctx.addIssue({
294186
- code: exports_external.ZodIssueCode.custom,
294187
- message: `invalid ${paramName} parameter: expected ISO 8601 date string, got "${v2}"`
294188
- });
294189
- return exports_external.NEVER;
294190
- }
294191
- return parsed;
294192
- }), listMessagesQuerySchema, markChatReadSchema, disappearingSchema, DISAPPEARING_DURATIONS, syncNamesSchema, clearSessionSchema;
294161
+ var chatsRoutes, ChatTypeSchema, listQuerySchema6, createChatSchema, updateChatSchema, addParticipantSchema, updateParticipantRoleSchema, chatChannelActionSchema, muteActionSchema, labelBodySchema, listMessagesQuerySchema, markChatReadSchema, disappearingSchema, DISAPPEARING_DURATIONS, syncNamesSchema, clearSessionSchema;
294193
294162
  var init_chats2 = __esm(() => {
294194
294163
  init_dist6();
294195
294164
  init_src();
294196
294165
  init_dist2();
294197
294166
  init_zod();
294198
294167
  init_session_cleaner();
294168
+ init_date_query();
294199
294169
  init_api_keys();
294200
294170
  chatsRoutes = new Hono2;
294201
294171
  ChatTypeSchema = exports_external.enum([
@@ -294843,12 +294813,13 @@ var init_dead_letters3 = __esm(() => {
294843
294813
  init_dist6();
294844
294814
  init_dist2();
294845
294815
  init_zod();
294816
+ init_date_query();
294846
294817
  deadLettersRoutes = new Hono2;
294847
294818
  listQuerySchema8 = exports_external.object({
294848
294819
  status: exports_external.string().optional().transform((v2) => v2?.split(",")),
294849
294820
  eventType: exports_external.string().optional().transform((v2) => v2?.split(",") ?? undefined),
294850
- since: exports_external.string().datetime().optional().transform((v2) => v2 ? new Date(v2) : undefined),
294851
- until: exports_external.string().datetime().optional().transform((v2) => v2 ? new Date(v2) : undefined),
294821
+ since: optionalDateParam("since"),
294822
+ until: optionalDateParam("until"),
294852
294823
  limit: exports_external.coerce.number().int().min(1).max(100).default(50),
294853
294824
  cursor: exports_external.string().optional()
294854
294825
  });
@@ -294908,11 +294879,12 @@ var init_event_ops3 = __esm(() => {
294908
294879
  init_dist6();
294909
294880
  init_dist2();
294910
294881
  init_zod();
294882
+ init_date_query();
294911
294883
  init_api_keys();
294912
294884
  eventOpsRoutes = new Hono2;
294913
294885
  replayOptionsSchema = exports_external.object({
294914
- since: exports_external.string().datetime().transform((v2) => new Date(v2)),
294915
- until: exports_external.string().datetime().optional().transform((v2) => v2 ? new Date(v2) : undefined),
294886
+ since: requiredDateParam("since"),
294887
+ until: optionalDateParam("until"),
294916
294888
  eventTypes: exports_external.array(exports_external.string()).optional(),
294917
294889
  instanceId: exports_external.string().uuid().optional(),
294918
294890
  limit: exports_external.number().int().positive().max(1e5).optional(),
@@ -294995,6 +294967,7 @@ var init_events4 = __esm(() => {
294995
294967
  init_src();
294996
294968
  init_dist2();
294997
294969
  init_zod();
294970
+ init_date_query();
294998
294971
  init_api_keys();
294999
294972
  eventsRoutes = new Hono2;
295000
294973
  listQuerySchema9 = exports_external.object({
@@ -295004,8 +294977,8 @@ var init_events4 = __esm(() => {
295004
294977
  eventType: exports_external.string().optional().transform((v2) => v2?.split(",")),
295005
294978
  contentType: exports_external.string().optional().transform((v2) => v2?.split(",")),
295006
294979
  direction: exports_external.enum(["inbound", "outbound"]).optional(),
295007
- since: exports_external.string().datetime().optional().transform((v2) => v2 ? new Date(v2) : undefined),
295008
- until: exports_external.string().datetime().optional().transform((v2) => v2 ? new Date(v2) : undefined),
294980
+ since: optionalDateParam("since"),
294981
+ until: optionalDateParam("until"),
295009
294982
  search: exports_external.string().optional(),
295010
294983
  limit: exports_external.coerce.number().int().min(1).max(100).default(50),
295011
294984
  cursor: exports_external.string().optional()
@@ -295026,16 +294999,16 @@ var init_events4 = __esm(() => {
295026
294999
  limit: exports_external.number().int().min(1).max(100).default(50)
295027
295000
  });
295028
295001
  analyticsQuerySchema = exports_external.object({
295029
- since: exports_external.string().datetime().optional().transform((v2) => v2 ? new Date(v2) : undefined),
295030
- until: exports_external.string().datetime().optional().transform((v2) => v2 ? new Date(v2) : undefined),
295002
+ since: optionalDateParam("since"),
295003
+ until: optionalDateParam("until"),
295031
295004
  instanceId: exports_external.string().uuid().optional(),
295032
295005
  granularity: exports_external.enum(["hourly", "daily"]).optional(),
295033
295006
  allTime: exports_external.coerce.boolean().optional()
295034
295007
  });
295035
295008
  timelineQuerySchema = exports_external.object({
295036
295009
  channels: exports_external.string().optional().transform((v2) => v2?.split(",")),
295037
- since: exports_external.string().datetime().optional().transform((v2) => v2 ? new Date(v2) : undefined),
295038
- until: exports_external.string().datetime().optional().transform((v2) => v2 ? new Date(v2) : undefined),
295010
+ since: optionalDateParam("since"),
295011
+ until: optionalDateParam("until"),
295039
295012
  limit: exports_external.coerce.number().int().min(1).max(100).default(50),
295040
295013
  cursor: exports_external.string().optional()
295041
295014
  });
@@ -303099,7 +303072,7 @@ function validateContactPhone(phone, platformUserId) {
303099
303072
  }
303100
303073
 
303101
303074
  // ../api/src/plugins/sync-worker.ts
303102
- class RateLimiter2 {
303075
+ class RateLimiter {
303103
303076
  lastRequest = 0;
303104
303077
  minIntervalMs;
303105
303078
  constructor(requestsPerMinute) {
@@ -303116,7 +303089,7 @@ class RateLimiter2 {
303116
303089
  }
303117
303090
  function getRateLimiter(channelType) {
303118
303091
  const rpm = RATE_LIMITS2[channelType] ?? RATE_LIMITS2.default ?? 20;
303119
- return new RateLimiter2(rpm);
303092
+ return new RateLimiter(rpm);
303120
303093
  }
303121
303094
  function parseSyncDepth(depth) {
303122
303095
  if (!depth)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.260422.5",
3
+ "version": "2.260422.6",
4
4
  "description": "LLM-optimized CLI for Omni",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,14 +36,14 @@
36
36
  "qrcode-terminal": "^0.12.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@omni/api": "2.260422.4",
40
- "@omni/channel-discord": "2.260422.4",
41
- "@omni/channel-sdk": "2.260422.4",
42
- "@omni/channel-slack": "2.260422.4",
43
- "@omni/channel-telegram": "2.260422.4",
44
- "@omni/channel-whatsapp": "2.260422.4",
45
- "@omni/core": "2.260422.4",
46
- "@omni/sdk": "2.260422.4",
39
+ "@omni/api": "2.260422.5",
40
+ "@omni/channel-discord": "2.260422.5",
41
+ "@omni/channel-sdk": "2.260422.5",
42
+ "@omni/channel-slack": "2.260422.5",
43
+ "@omni/channel-telegram": "2.260422.5",
44
+ "@omni/channel-whatsapp": "2.260422.5",
45
+ "@omni/core": "2.260422.5",
46
+ "@omni/sdk": "2.260422.5",
47
47
  "@types/node": "^22.10.3",
48
48
  "@types/qrcode-terminal": "^0.12.2",
49
49
  "typescript": "^5.7.3"