@letta-ai/letta-code 0.29.5 → 0.29.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.
package/letta.js CHANGED
@@ -5462,7 +5462,7 @@ var package_default;
5462
5462
  var init_package = __esm(() => {
5463
5463
  package_default = {
5464
5464
  name: "@letta-ai/letta-code",
5465
- version: "0.29.5",
5465
+ version: "0.29.6",
5466
5466
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5467
5467
  type: "module",
5468
5468
  packageManager: "bun@1.3.0",
@@ -5482,6 +5482,8 @@ var init_package = __esm(() => {
5482
5482
  "dist/app-server-client.js.map",
5483
5483
  "dist/app-server-client.cjs",
5484
5484
  "dist/app-server-client.cjs.map",
5485
+ "dist/memory-confinement.js",
5486
+ "dist/memory-confinement.js.map",
5485
5487
  "dist/agent-presets.js",
5486
5488
  "dist/agent-presets.js.map",
5487
5489
  "dist/channels-public.js",
@@ -5503,6 +5505,11 @@ var init_package = __esm(() => {
5503
5505
  require: "./dist/app-server-client.cjs",
5504
5506
  default: "./dist/app-server-client.js"
5505
5507
  },
5508
+ "./memory-confinement": {
5509
+ types: "./dist/types/memory-confinement.d.ts",
5510
+ import: "./dist/memory-confinement.js",
5511
+ default: "./dist/memory-confinement.js"
5512
+ },
5506
5513
  "./protocol": {
5507
5514
  types: "./dist/types/types/protocol.d.ts"
5508
5515
  },
@@ -5622,6 +5629,9 @@ var init_package = __esm(() => {
5622
5629
  "app-server-client": [
5623
5630
  "./dist/types/app-server-client.d.ts"
5624
5631
  ],
5632
+ "memory-confinement": [
5633
+ "./dist/types/memory-confinement.d.ts"
5634
+ ],
5625
5635
  channels: [
5626
5636
  "./dist/types/channels-public.d.ts"
5627
5637
  ],
@@ -145938,6 +145948,32 @@ var init_mode = __esm(() => {
145938
145948
  permissionMode = new PermissionModeManager;
145939
145949
  });
145940
145950
 
145951
+ // src/channels/discord/bot-policy.ts
145952
+ function isNonEmptyString(value) {
145953
+ return typeof value === "string" && value.length > 0;
145954
+ }
145955
+ function isValidDiscordAllowBotsConfigValue(value) {
145956
+ return value === undefined || value === false || value === "mentions";
145957
+ }
145958
+ function normalizeDiscordAllowBotsMode(value) {
145959
+ return value === "mentions" ? "mentions" : false;
145960
+ }
145961
+ function hasExplicitDiscordUserMention(message, userId) {
145962
+ if (!isNonEmptyString(userId) || typeof message.content !== "string") {
145963
+ return false;
145964
+ }
145965
+ return message.content.includes(`<@${userId}>`) || message.content.includes(`<@!${userId}>`);
145966
+ }
145967
+ function shouldAcceptDiscordInboundBotMessage(input) {
145968
+ const author = input.message.author;
145969
+ if (author?.bot !== true)
145970
+ return true;
145971
+ if (isNonEmptyString(input.botUserId) && author.id === input.botUserId) {
145972
+ return false;
145973
+ }
145974
+ return input.allowBots === "mentions" && input.wasExplicitlyMentioned;
145975
+ }
145976
+
145941
145977
  // src/channels/slack/bot-policy.ts
145942
145978
  function isValidSlackAllowBotsConfigValue(value) {
145943
145979
  return value === undefined || value === false || value === "mentions";
@@ -145952,14 +145988,14 @@ function resolveSlackAllowBotsMode(value) {
145952
145988
  return "mentions";
145953
145989
  return "off";
145954
145990
  }
145955
- function isNonEmptyString(value) {
145991
+ function isNonEmptyString2(value) {
145956
145992
  return typeof value === "string" && value.length > 0;
145957
145993
  }
145958
145994
  function isSlackBotAuthoredInboundMessage(message) {
145959
- return isNonEmptyString(message.bot_id) || message.subtype === "bot_message";
145995
+ return isNonEmptyString2(message.bot_id) || message.subtype === "bot_message";
145960
145996
  }
145961
145997
  function isOwnSlackBotInboundMessage(params) {
145962
- return isNonEmptyString(params.botUserId) && params.message.user === params.botUserId || isNonEmptyString(params.botId) && params.message.bot_id === params.botId;
145998
+ return isNonEmptyString2(params.botUserId) && params.message.user === params.botUserId || isNonEmptyString2(params.botId) && params.message.bot_id === params.botId;
145963
145999
  }
145964
146000
  function shouldAcceptSlackInboundBotMessage(params) {
145965
146001
  if (isOwnSlackBotInboundMessage({
@@ -146125,6 +146161,9 @@ var init_config2 = __esm(() => {
146125
146161
  };
146126
146162
  discordConfigCodec = {
146127
146163
  parse(parsed) {
146164
+ if (!isValidDiscordAllowBotsConfigValue(parsed.allow_bots)) {
146165
+ throw new Error("Invalid Discord allow_bots config");
146166
+ }
146128
146167
  const rawAllowedChannels = parsed.allowed_channels;
146129
146168
  let allowedChannels;
146130
146169
  if (Array.isArray(rawAllowedChannels)) {
@@ -146140,6 +146179,7 @@ var init_config2 = __esm(() => {
146140
146179
  dmPolicy: parsed.dm_policy ?? "pairing",
146141
146180
  allowedUsers: parsed.allowed_users ?? [],
146142
146181
  allowedChannels,
146182
+ allowBots: normalizeDiscordAllowBotsMode(parsed.allow_bots),
146143
146183
  transcribeVoice: parsed.transcribe_voice === true,
146144
146184
  autoThreadOnMention: typeof parsed.auto_thread_on_mention === "boolean" ? parsed.auto_thread_on_mention : undefined,
146145
146185
  threadPolicyByChannel: typeof parsed.thread_policy_by_channel === "object" && !Array.isArray(parsed.thread_policy_by_channel) ? parsed.thread_policy_by_channel : undefined,
@@ -146373,7 +146413,7 @@ var init_plugin = __esm(() => {
146373
146413
  });
146374
146414
 
146375
146415
  // src/channels/schema-config.ts
146376
- function isNonEmptyString2(value) {
146416
+ function isNonEmptyString3(value) {
146377
146417
  return typeof value === "string" && value.length > 0;
146378
146418
  }
146379
146419
  function parseSelectOptions(value) {
@@ -146386,7 +146426,7 @@ function parseSelectOptions(value) {
146386
146426
  if (!isRecord(entry)) {
146387
146427
  return null;
146388
146428
  }
146389
- if (!isNonEmptyString2(entry.value) || !isNonEmptyString2(entry.label)) {
146429
+ if (!isNonEmptyString3(entry.value) || !isNonEmptyString3(entry.label)) {
146390
146430
  return null;
146391
146431
  }
146392
146432
  if (seen.has(entry.value)) {
@@ -146405,10 +146445,10 @@ function parseField(value) {
146405
146445
  if (typeof type3 !== "string" || !FIELD_TYPES.has(type3)) {
146406
146446
  return null;
146407
146447
  }
146408
- if (!isNonEmptyString2(value.key) || !FIELD_KEY_PATTERN.test(value.key)) {
146448
+ if (!isNonEmptyString3(value.key) || !FIELD_KEY_PATTERN.test(value.key)) {
146409
146449
  return null;
146410
146450
  }
146411
- if (!isNonEmptyString2(value.label)) {
146451
+ if (!isNonEmptyString3(value.label)) {
146412
146452
  return null;
146413
146453
  }
146414
146454
  if (value.description !== undefined && typeof value.description !== "string") {
@@ -148130,11 +148170,7 @@ function resolveTelegramInputFileConstructor(mod) {
148130
148170
  return InputFile;
148131
148171
  }
148132
148172
  function resolveTelegramOutboundThreadId(msg) {
148133
- const threadId = msg.threadId?.trim();
148134
- if (!threadId) {
148135
- return null;
148136
- }
148137
- return msg.chatId.trim().startsWith("-") ? threadId : null;
148173
+ return msg.threadId?.trim() || null;
148138
148174
  }
148139
148175
  function buildTelegramReplyOptions(msg) {
148140
148176
  const options3 = {};
@@ -149408,7 +149444,7 @@ function createTelegramAdapter(config3) {
149408
149444
  }
149409
149445
  const telegramBot = await ensureBot();
149410
149446
  const threadId = resolveTelegramOutboundThreadId(source2);
149411
- const replyToMessageId = threadId ?? source2.messageId;
149447
+ const replyToMessageId = source2.messageId;
149412
149448
  let reply_parameters;
149413
149449
  if (replyToMessageId) {
149414
149450
  const numericReplyToMessageId = Number(replyToMessageId);
@@ -149582,10 +149618,16 @@ function createTelegramAdapter(config3) {
149582
149618
  },
149583
149619
  async sendDirectReply(chatId, text, options3) {
149584
149620
  const telegramBot = await ensureBot();
149621
+ const threadId = resolveTelegramOutboundThreadId({
149622
+ threadId: options3?.threadId
149623
+ });
149585
149624
  const reply_parameters = options3?.replyToMessageId ? {
149586
149625
  message_id: Number(options3.replyToMessageId)
149587
149626
  } : undefined;
149588
- await telegramBot.api.sendMessage(chatId, text, reply_parameters ? { reply_parameters } : {});
149627
+ await telegramBot.api.sendMessage(chatId, text, {
149628
+ ...threadId ? { message_thread_id: Number(threadId) } : {},
149629
+ ...reply_parameters ? { reply_parameters } : {}
149630
+ });
149589
149631
  },
149590
149632
  async handleTurnLifecycleEvent(event2) {
149591
149633
  if (!running)
@@ -149624,7 +149666,7 @@ function createTelegramAdapter(config3) {
149624
149666
  async handleControlRequestEvent(event2) {
149625
149667
  const telegramBot = await ensureBot();
149626
149668
  const threadId = resolveTelegramOutboundThreadId(event2.source);
149627
- const replyToMessageId = threadId ?? event2.source.messageId;
149669
+ const replyToMessageId = event2.source.messageId;
149628
149670
  const reply_parameters = replyToMessageId ? { message_id: Number(replyToMessageId) } : undefined;
149629
149671
  await telegramBot.api.sendMessage(event2.source.chatId, formatChannelControlRequestPrompt(event2), {
149630
149672
  ...threadId ? { message_thread_id: Number(threadId) } : {},
@@ -149901,6 +149943,7 @@ function normalizeLoadedAccount(account) {
149901
149943
  if (isDiscordChannelAccount(next)) {
149902
149944
  const migrated = migratePermissionMode(next.defaultPermissionMode ?? "standard");
149903
149945
  next.defaultPermissionMode = migrated ?? "standard";
149946
+ next.allowBots = normalizeDiscordAllowBotsMode(next.allowBots);
149904
149947
  if (!("auto_thread_on_mention" in raw) && !("autoThreadOnMention" in raw)) {
149905
149948
  next.autoThreadOnMention = true;
149906
149949
  }
@@ -149963,6 +150006,7 @@ function makeDefaultLegacyAccount(channelId) {
149963
150006
  allowedChannels: config3.allowedChannels ? Array.isArray(config3.allowedChannels) ? [...config3.allowedChannels] : { ...config3.allowedChannels } : undefined,
149964
150007
  autoThreadOnMention: config3.autoThreadOnMention ?? true,
149965
150008
  threadPolicyByChannel: config3.threadPolicyByChannel,
150009
+ allowBots: config3.allowBots ?? false,
149966
150010
  agentId: null,
149967
150011
  defaultPermissionMode: config3.defaultPermissionMode ?? "standard",
149968
150012
  createdAt: now,
@@ -150249,15 +150293,18 @@ function shouldSendTelegramRichMessage(params) {
150249
150293
  return params.request.action === "send" && params.route.chatType === "direct" && richPrivateChatDefaultEnabled(params.route) && !params.request.mediaPath?.trim();
150250
150294
  }
150251
150295
  function resolveTelegramRouteThreadId(ctx) {
150252
- const threadId = ctx.request.threadId ?? ctx.route.threadId ?? null;
150253
- const trimmed = threadId?.trim();
150254
- if (!trimmed) {
150255
- return null;
150296
+ const requestThreadId = ctx.request.threadId?.trim();
150297
+ if (requestThreadId) {
150298
+ return requestThreadId;
150256
150299
  }
150257
150300
  if (ctx.route.chatType === "direct") {
150258
150301
  return null;
150259
150302
  }
150260
- return ctx.route.chatId.trim().startsWith("-") ? trimmed : null;
150303
+ const routeThreadId = ctx.route.threadId?.trim();
150304
+ if (!routeThreadId) {
150305
+ return null;
150306
+ }
150307
+ return ctx.route.chatId.trim().startsWith("-") ? routeThreadId : null;
150261
150308
  }
150262
150309
  var telegramMessageActions;
150263
150310
  var init_message_actions = __esm(() => {
@@ -150511,11 +150558,11 @@ function resolveSlackAppConstructor(mod) {
150511
150558
  }
150512
150559
  return App;
150513
150560
  }
150514
- function isNonEmptyString3(value) {
150561
+ function isNonEmptyString4(value) {
150515
150562
  return typeof value === "string" && value.length > 0;
150516
150563
  }
150517
150564
  function firstNonEmptyString(...values2) {
150518
- return values2.find(isNonEmptyString3);
150565
+ return values2.find(isNonEmptyString4);
150519
150566
  }
150520
150567
  function asRecord2(value) {
150521
150568
  return value && typeof value === "object" ? value : null;
@@ -150593,7 +150640,7 @@ function resolveSlackUserDisplayName(userInfo) {
150593
150640
  return firstNonEmptyString(profile?.display_name, profile?.real_name, user?.name);
150594
150641
  }
150595
150642
  function isSlackFlatChannelThreadOpener(source2) {
150596
- return source2.chatType === "channel" && isNonEmptyString3(source2.messageId) && (!isNonEmptyString3(source2.threadId) || source2.threadId === source2.messageId);
150643
+ return source2.chatType === "channel" && isNonEmptyString4(source2.messageId) && (!isNonEmptyString4(source2.threadId) || source2.threadId === source2.messageId);
150597
150644
  }
150598
150645
  var IGNORED_SLACK_MESSAGE_SUBTYPES, WRAPPER_SLACK_MESSAGE_SUBTYPES;
150599
150646
  var init_utils5 = __esm(() => {
@@ -150640,7 +150687,7 @@ async function resolveSlackAccountDisplayName(botToken, appToken) {
150640
150687
  socketMode: true
150641
150688
  });
150642
150689
  const auth = await app.client.auth.test({ token: botToken });
150643
- if (isNonEmptyString3(auth.user_id)) {
150690
+ if (isNonEmptyString4(auth.user_id)) {
150644
150691
  try {
150645
150692
  const userInfo = await app.client.users.info({
150646
150693
  token: botToken,
@@ -150652,7 +150699,7 @@ async function resolveSlackAccountDisplayName(botToken, appToken) {
150652
150699
  }
150653
150700
  } catch {}
150654
150701
  }
150655
- return isNonEmptyString3(auth.user) ? auth.user : undefined;
150702
+ return isNonEmptyString4(auth.user) ? auth.user : undefined;
150656
150703
  }
150657
150704
  var init_account_display2 = __esm(() => {
150658
150705
  init_runtime2();
@@ -151353,7 +151400,7 @@ var init_feedback2 = __esm(() => {
151353
151400
  init_plugin_registry();
151354
151401
  });
151355
151402
 
151356
- // src/channels/commands.ts
151403
+ // src/channels/registry-presentation.ts
151357
151404
  function channelDisplayName3(channelId) {
151358
151405
  try {
151359
151406
  return getChannelDisplayName(channelId);
@@ -151361,6 +151408,168 @@ function channelDisplayName3(channelId) {
151361
151408
  return channelId;
151362
151409
  }
151363
151410
  }
151411
+ function normalizeAgentId(agentId) {
151412
+ const normalized = agentId?.trim();
151413
+ return normalized ? normalized : null;
151414
+ }
151415
+ function getConfiguredAgentId(config3) {
151416
+ if (!config3 || typeof config3 !== "object")
151417
+ return null;
151418
+ const source2 = config3;
151419
+ return normalizeAgentId(source2.agentId) ?? normalizeAgentId(source2.binding?.agentId);
151420
+ }
151421
+ function buildPairingInstructions(channelId, code2, options3 = {}) {
151422
+ const displayName = channelDisplayName3(channelId);
151423
+ const configuredAgentId = normalizeAgentId(options3.agentId);
151424
+ const pairingCommand = `letta channels pair --channel ${channelId} --code ${code2} --agent ${configuredAgentId ?? "<agent-id>"}`;
151425
+ const agentLookupLines = configuredAgentId ? [] : ["Find the target agent with: letta agents list"];
151426
+ if (!isFirstPartyChannelPlugin(channelId)) {
151427
+ return [
151428
+ "Connect this chat to a Letta agent.",
151429
+ "",
151430
+ `Pairing code: ${code2}`,
151431
+ "",
151432
+ "CLI on the listener machine:",
151433
+ pairingCommand,
151434
+ ...agentLookupLines,
151435
+ "",
151436
+ "This code expires in 15 minutes."
151437
+ ].join(`
151438
+ `);
151439
+ }
151440
+ return [
151441
+ "Connect this chat to a Letta agent.",
151442
+ "",
151443
+ `Pairing code: ${code2}`,
151444
+ "",
151445
+ `In Letta Code: open Channels > ${displayName} and approve this pending chat.`,
151446
+ "",
151447
+ "CLI on the listener machine:",
151448
+ pairingCommand,
151449
+ ...agentLookupLines,
151450
+ "",
151451
+ "This code expires in 15 minutes."
151452
+ ].join(`
151453
+ `);
151454
+ }
151455
+ function buildUnboundRouteInstructions(channelId, chatId) {
151456
+ const displayName = channelDisplayName3(channelId);
151457
+ if (!isFirstPartyChannelPlugin(channelId)) {
151458
+ return `This chat isn't connected to a Letta agent yet.
151459
+
151460
+ ` + `On the machine where your listener runs:
151461
+
151462
+ ` + `letta channels route add --channel ${channelId} --chat-id ${chatId} --agent <agent-id>
151463
+
151464
+ ` + `Find your agent id with letta agents list.`;
151465
+ }
151466
+ return `This chat isn't connected to a Letta agent yet.
151467
+
151468
+ ` + `Open Channels > ${displayName} in Letta Code and connect this chat there.
151469
+
151470
+ ` + `Chat ID: ${chatId}`;
151471
+ }
151472
+ function buildSlackAppSetupInstructions() {
151473
+ return `This Slack app isn't connected to a Letta agent yet.
151474
+
151475
+ ` + "Open Channels > Slack in Letta Code, choose which agent this app should represent, and try again.";
151476
+ }
151477
+ function truncateChannelSummaryPreview(text, maxLength3 = 72) {
151478
+ const normalized = text.replace(/\s+/g, " ").trim();
151479
+ if (!normalized)
151480
+ return null;
151481
+ if (normalized.length <= maxLength3)
151482
+ return normalized;
151483
+ return `${normalized.slice(0, maxLength3 - 1).trimEnd()}…`;
151484
+ }
151485
+ function buildSlackConversationSummary(msg) {
151486
+ if (msg.chatType === "direct") {
151487
+ if (msg.threadId?.trim()) {
151488
+ const preview2 = truncateChannelSummaryPreview(msg.text);
151489
+ return preview2 ? `[Slack] DM thread with ${msg.senderName?.trim() || msg.senderId}: ${preview2}` : `[Slack] DM thread with ${msg.senderName?.trim() || msg.senderId}`;
151490
+ }
151491
+ return `[Slack] DM with ${msg.senderName?.trim() || msg.senderId}`;
151492
+ }
151493
+ const preview = truncateChannelSummaryPreview(msg.text);
151494
+ const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
151495
+ if (preview)
151496
+ return `[Slack] Thread${channelLabel}: ${preview}`;
151497
+ return `[Slack] Thread${channelLabel || ` ${msg.chatId}`}`;
151498
+ }
151499
+ function buildDiscordConversationSummary(msg) {
151500
+ if (msg.chatType === "direct") {
151501
+ return `[Discord] DM with ${msg.senderName?.trim() || msg.senderId}`;
151502
+ }
151503
+ const preview = truncateChannelSummaryPreview(msg.text);
151504
+ const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
151505
+ if (preview)
151506
+ return `[Discord] Thread${channelLabel}: ${preview}`;
151507
+ return `[Discord] Thread${channelLabel || ` ${msg.chatId}`}`;
151508
+ }
151509
+ function buildTelegramConversationSummary(msg) {
151510
+ if (msg.chatType === "direct") {
151511
+ return `[Telegram] DM with ${msg.senderName?.trim() || msg.senderId}`;
151512
+ }
151513
+ const preview = truncateChannelSummaryPreview(msg.text);
151514
+ const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
151515
+ if (preview)
151516
+ return `[Telegram] Topic${channelLabel}: ${preview}`;
151517
+ return `[Telegram] Topic${channelLabel || ` ${msg.chatId}`}`;
151518
+ }
151519
+ function buildWhatsAppConversationSummary(msg) {
151520
+ if (msg.chatType === "direct") {
151521
+ return `[WhatsApp] DM with ${msg.senderName?.trim() || msg.senderId}`;
151522
+ }
151523
+ const preview = truncateChannelSummaryPreview(msg.text);
151524
+ const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
151525
+ if (preview)
151526
+ return `[WhatsApp] Group${channelLabel}: ${preview}`;
151527
+ return `[WhatsApp] Group${channelLabel || ` ${msg.chatId}`}`;
151528
+ }
151529
+ function buildSignalConversationSummary(msg) {
151530
+ if (msg.chatType === "direct") {
151531
+ return `[Signal] DM with ${msg.senderName?.trim() || msg.senderId}`;
151532
+ }
151533
+ const preview = truncateChannelSummaryPreview(msg.text);
151534
+ const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
151535
+ if (preview)
151536
+ return `[Signal] Group${channelLabel}: ${preview}`;
151537
+ return `[Signal] Group${channelLabel || ` ${msg.chatId}`}`;
151538
+ }
151539
+ function buildChannelTurnSource(route, msg) {
151540
+ return {
151541
+ channel: msg.channel,
151542
+ accountId: msg.accountId,
151543
+ chatId: msg.chatId,
151544
+ chatType: msg.chatType,
151545
+ senderId: msg.senderId,
151546
+ senderTeamId: msg.senderTeamId,
151547
+ messageId: msg.messageId,
151548
+ threadId: msg.threadId,
151549
+ agentId: route.agentId,
151550
+ conversationId: route.conversationId
151551
+ };
151552
+ }
151553
+ function buildDirectReplyOptions(msg) {
151554
+ if (!msg.messageId && !msg.threadId)
151555
+ return;
151556
+ return {
151557
+ replyToMessageId: msg.messageId ?? undefined,
151558
+ threadId: msg.threadId ?? null
151559
+ };
151560
+ }
151561
+ var init_registry_presentation = __esm(() => {
151562
+ init_plugin_registry();
151563
+ });
151564
+
151565
+ // src/channels/commands.ts
151566
+ function channelDisplayName4(channelId) {
151567
+ try {
151568
+ return getChannelDisplayName(channelId);
151569
+ } catch {
151570
+ return channelId;
151571
+ }
151572
+ }
151364
151573
  function listChannelSlashCommands() {
151365
151574
  return CHANNEL_SLASH_COMMANDS.map((definition) => ({
151366
151575
  ...definition,
@@ -151437,7 +151646,7 @@ function isSlackMentionControlCommand(msg, command) {
151437
151646
  return command.raw.startsWith("!") || isSlackMentionSlashCommand(msg, command);
151438
151647
  }
151439
151648
  function buildChannelHelpMessage(channelId) {
151440
- const displayName = channelDisplayName3(channelId);
151649
+ const displayName = channelDisplayName4(channelId);
151441
151650
  if (channelId === "slack") {
151442
151651
  return [
151443
151652
  `${displayName} is connected to Letta Code.`,
@@ -151469,7 +151678,7 @@ function buildChannelHelpMessage(channelId) {
151469
151678
  `);
151470
151679
  }
151471
151680
  function buildUnsupportedChannelCommandMessage(channelId, command) {
151472
- const displayName = channelDisplayName3(channelId);
151681
+ const displayName = channelDisplayName4(channelId);
151473
151682
  const isBang = command.raw.startsWith("!");
151474
151683
  const commandKind = isBang ? "bang" : "slash";
151475
151684
  const supportedCommands = isBang ? supportedBangCommandsText() : channelId === "slack" ? supportedSlackMentionSlashCommandsText() : supportedCommandsText();
@@ -151483,7 +151692,7 @@ function buildUnsupportedChannelCommandMessage(channelId, command) {
151483
151692
  `);
151484
151693
  }
151485
151694
  function buildChannelStatusMessage(msg, context3) {
151486
- const displayName = channelDisplayName3(msg.channel);
151695
+ const displayName = channelDisplayName4(msg.channel);
151487
151696
  const route = context3.route;
151488
151697
  const routeStatus = route ? "Connected to a Letta agent conversation." : "No route is connected for this chat yet.";
151489
151698
  const accountStatus = !context3.accountConfigured ? "No channel account is configured for this receiver." : context3.accountEnabled === false ? "Channel account is configured but disabled." : "Channel account is configured and enabled.";
@@ -151511,7 +151720,7 @@ function buildChannelStatusMessage(msg, context3) {
151511
151720
  `);
151512
151721
  }
151513
151722
  function buildChannelNoRouteMessage(channelId) {
151514
- const displayName = channelDisplayName3(channelId);
151723
+ const displayName = channelDisplayName4(channelId);
151515
151724
  return [
151516
151725
  `${displayName} could not find an existing route for this chat.`,
151517
151726
  "Send a normal message first and follow the pairing instructions, then try again."
@@ -151520,23 +151729,23 @@ function buildChannelNoRouteMessage(channelId) {
151520
151729
  `);
151521
151730
  }
151522
151731
  function buildChannelPausedMessage(channelId, route) {
151523
- const displayName = channelDisplayName3(channelId);
151732
+ const displayName = channelDisplayName4(channelId);
151524
151733
  const conversation = route.conversationId ? ` Conversation: ${route.conversationId}.` : "";
151525
151734
  return `${displayName} paused agent routing for this chat.${conversation} Send /resume here to turn replies back on.`;
151526
151735
  }
151527
151736
  function buildChannelAlreadyPausedMessage(channelId) {
151528
- return `${channelDisplayName3(channelId)} agent routing is already paused for this chat. Send /resume here to turn replies back on.`;
151737
+ return `${channelDisplayName4(channelId)} agent routing is already paused for this chat. Send /resume here to turn replies back on.`;
151529
151738
  }
151530
151739
  function buildChannelResumedMessage(channelId, route) {
151531
- const displayName = channelDisplayName3(channelId);
151740
+ const displayName = channelDisplayName4(channelId);
151532
151741
  const conversation = route.conversationId ? ` Conversation: ${route.conversationId}.` : "";
151533
151742
  return `${displayName} resumed agent routing for this chat.${conversation} Normal messages here will go to the connected agent again.`;
151534
151743
  }
151535
151744
  function buildChannelAlreadyActiveMessage(channelId) {
151536
- return `${channelDisplayName3(channelId)} agent routing is already active for this chat.`;
151745
+ return `${channelDisplayName4(channelId)} agent routing is already active for this chat.`;
151537
151746
  }
151538
151747
  function buildChannelCancelUnavailableMessage(channelId) {
151539
- const displayName = channelDisplayName3(channelId);
151748
+ const displayName = channelDisplayName4(channelId);
151540
151749
  return [
151541
151750
  `${displayName} received /cancel, but this chat is not connected to an active Letta Code conversation yet.`,
151542
151751
  "Send a normal message first to connect this chat to an agent."
@@ -151545,15 +151754,15 @@ function buildChannelCancelUnavailableMessage(channelId) {
151545
151754
  `);
151546
151755
  }
151547
151756
  function buildChannelCancelNoActiveTurnMessage(channelId) {
151548
- const displayName = channelDisplayName3(channelId);
151757
+ const displayName = channelDisplayName4(channelId);
151549
151758
  return `${displayName} received /cancel, but there is no in-progress agent turn to cancel for this chat.`;
151550
151759
  }
151551
151760
  function buildChannelCancelAcceptedMessage(channelId) {
151552
- const displayName = channelDisplayName3(channelId);
151761
+ const displayName = channelDisplayName4(channelId);
151553
151762
  return `${displayName} cancelled the in-progress agent turn for this chat.`;
151554
151763
  }
151555
151764
  function buildChannelChatLinkMessage(channelId, route, chatUrl) {
151556
- const displayName = channelDisplayName3(channelId);
151765
+ const displayName = channelDisplayName4(channelId);
151557
151766
  return [
151558
151767
  `${displayName} chat for this route: ${chatUrl}`,
151559
151768
  `Agent: ${route.agentId}.`,
@@ -151562,27 +151771,27 @@ function buildChannelChatLinkMessage(channelId, route, chatUrl) {
151562
151771
  `);
151563
151772
  }
151564
151773
  function buildChannelChatUnavailableMessage(channelId, route) {
151565
- const displayName = channelDisplayName3(channelId);
151774
+ const displayName = channelDisplayName4(channelId);
151566
151775
  return `${displayName} chat UI is not available for local backend agent ${route.agentId}.`;
151567
151776
  }
151568
151777
  function buildChannelDetachUnsupportedMessage(channelId) {
151569
- const displayName = channelDisplayName3(channelId);
151778
+ const displayName = channelDisplayName4(channelId);
151570
151779
  return `${displayName} can only detach Slack channel threads.`;
151571
151780
  }
151572
151781
  function buildChannelDetachedMessage(channelId) {
151573
- const displayName = channelDisplayName3(channelId);
151782
+ const displayName = channelDisplayName4(channelId);
151574
151783
  return `${displayName} detached this thread. I will ignore follow-up replies here until someone mentions the app again.`;
151575
151784
  }
151576
151785
  function buildChannelAlreadyDetachedMessage(channelId) {
151577
- const displayName = channelDisplayName3(channelId);
151786
+ const displayName = channelDisplayName4(channelId);
151578
151787
  return `${displayName} is already detached from this thread. Mention the app again to reattach.`;
151579
151788
  }
151580
151789
  function buildChannelNewConversationMessage(channelId, route) {
151581
- const displayName = channelDisplayName3(channelId);
151790
+ const displayName = channelDisplayName4(channelId);
151582
151791
  return `${displayName} started a new conversation for this chat. Conversation: ${route.conversationId}.`;
151583
151792
  }
151584
151793
  function buildChannelNewConversationUnavailableMessage(channelId) {
151585
- const displayName = channelDisplayName3(channelId);
151794
+ const displayName = channelDisplayName4(channelId);
151586
151795
  return `${displayName} cannot start a new conversation for this chat because no agent is configured.`;
151587
151796
  }
151588
151797
  function getModelEntryRank(entry) {
@@ -151641,7 +151850,7 @@ function buildChannelModelNotFoundText(channelId) {
151641
151850
  return `Model not found. Use ${modelCommandPrefix(channelId)} list to see available models.`;
151642
151851
  }
151643
151852
  function buildChannelCurrentModelMessage(channelId, params) {
151644
- const displayName = channelDisplayName3(channelId);
151853
+ const displayName = channelDisplayName4(channelId);
151645
151854
  const scope = params.scope === "agent" ? "agent" : "conversation";
151646
151855
  const handleText = params.modelHandle && params.modelHandle !== params.modelLabel ? ` (${params.modelHandle})` : "";
151647
151856
  const switchCommand = modelCommandPrefix(channelId);
@@ -151669,7 +151878,7 @@ function appendModelEntrySection(lines, channelId, title, entries, limit3) {
151669
151878
  }
151670
151879
  }
151671
151880
  function buildChannelModelListMessage(channelId, params) {
151672
- const displayName = channelDisplayName3(channelId);
151881
+ const displayName = channelDisplayName4(channelId);
151673
151882
  const limit3 = params.limit ?? DEFAULT_CHANNEL_MODEL_LIST_LIMIT;
151674
151883
  const entries = params.entries;
151675
151884
  const byHandle = buildModelEntriesByHandle(entries);
@@ -151702,33 +151911,33 @@ function buildChannelModelListMessage(channelId, params) {
151702
151911
  `);
151703
151912
  }
151704
151913
  function buildChannelModelListUnavailableMessage(channelId, error54) {
151705
- const displayName = channelDisplayName3(channelId);
151914
+ const displayName = channelDisplayName4(channelId);
151706
151915
  return `${displayName} could not load the model list: ${error54}`;
151707
151916
  }
151708
151917
  function buildChannelCurrentModelUnavailableMessage(channelId, error54) {
151709
- const displayName = channelDisplayName3(channelId);
151918
+ const displayName = channelDisplayName4(channelId);
151710
151919
  return `${displayName} could not load the current model: ${error54}`;
151711
151920
  }
151712
151921
  function buildChannelModelUpdatedMessage(channelId, params) {
151713
- const displayName = channelDisplayName3(channelId);
151922
+ const displayName = channelDisplayName4(channelId);
151714
151923
  const scope = params.appliedTo === "agent" ? "agent" : "conversation";
151715
151924
  const handleText = params.modelHandle === params.modelLabel ? "" : ` (${params.modelHandle})`;
151716
151925
  return `${displayName} updated this ${scope}'s model to ${params.modelLabel}${handleText}.`;
151717
151926
  }
151718
151927
  function buildChannelModelUpdateFailedMessage(channelId, identifier2, error54) {
151719
- const displayName = channelDisplayName3(channelId);
151928
+ const displayName = channelDisplayName4(channelId);
151720
151929
  return `${displayName} could not switch this chat's routed model to ${identifier2}: ${error54}`;
151721
151930
  }
151722
151931
  function buildChannelModelUnavailableMessage(channelId) {
151723
- const displayName = channelDisplayName3(channelId);
151932
+ const displayName = channelDisplayName4(channelId);
151724
151933
  return `${displayName} cannot use /model because the listener is not ready yet. Try again in a moment.`;
151725
151934
  }
151726
151935
  function buildChannelReflectionUnavailableMessage(channelId) {
151727
- const displayName = channelDisplayName3(channelId);
151936
+ const displayName = channelDisplayName4(channelId);
151728
151937
  return `${displayName} cannot start reflection for this chat because the listener is not ready yet. Try again in a moment.`;
151729
151938
  }
151730
151939
  function buildChannelReloadUnavailableMessage(channelId) {
151731
- const displayName = channelDisplayName3(channelId);
151940
+ const displayName = channelDisplayName4(channelId);
151732
151941
  return `${displayName} cannot reload listener settings for this chat because the listener is not ready yet. Try again in a moment.`;
151733
151942
  }
151734
151943
  async function handleScopedCommand(params) {
@@ -151762,12 +151971,12 @@ async function tryHandleChannelSlashCommand(adapter, msg, options3 = {}) {
151762
151971
  const isBangCommand = command.raw.startsWith("!");
151763
151972
  const isSlackMentionControl = isSlackMentionControlCommand(msg, command);
151764
151973
  if (isBangCommand && !isSupportedSlackMentionCommand(command.name)) {
151765
- await adapter.sendDirectReply(msg.chatId, buildUnsupportedChannelCommandMessage(msg.channel, command), msg.threadId ? { replyToMessageId: msg.threadId } : undefined);
151974
+ await adapter.sendDirectReply(msg.chatId, buildUnsupportedChannelCommandMessage(msg.channel, command), buildDirectReplyOptions(msg));
151766
151975
  return true;
151767
151976
  }
151768
151977
  const canonicalName = canonicalizeChannelCommandName(command.name);
151769
151978
  if (options3.commandGate && !canRunChannelCommand(options3.commandGate, canonicalName)) {
151770
- await adapter.sendDirectReply(msg.chatId, buildChannelCommandDeniedMessage(msg.channel, canonicalName, options3.commandGate), msg.threadId ? { replyToMessageId: msg.threadId } : undefined);
151979
+ await adapter.sendDirectReply(msg.chatId, buildChannelCommandDeniedMessage(msg.channel, canonicalName, options3.commandGate), buildDirectReplyOptions(msg));
151771
151980
  return true;
151772
151981
  }
151773
151982
  const reply = normalizeDirectReplyPayload(await (async () => {
@@ -151872,6 +152081,7 @@ var init_commands = __esm(() => {
151872
152081
  init_access_control();
151873
152082
  init_feedback2();
151874
152083
  init_plugin_registry();
152084
+ init_registry_presentation();
151875
152085
  CHANNEL_SLASH_COMMANDS = [
151876
152086
  {
151877
152087
  name: "help",
@@ -152525,11 +152735,11 @@ var init_progress_formatting = __esm(() => {
152525
152735
  });
152526
152736
 
152527
152737
  // src/channels/slack/public-utils.ts
152528
- function isNonEmptyString4(value) {
152738
+ function isNonEmptyString5(value) {
152529
152739
  return typeof value === "string" && value.length > 0;
152530
152740
  }
152531
152741
  function firstNonEmptyString3(...values2) {
152532
- return values2.find(isNonEmptyString4);
152742
+ return values2.find(isNonEmptyString5);
152533
152743
  }
152534
152744
  function normalizeSlackText(text) {
152535
152745
  return text.replace(/^(?:\s*<@[A-Z0-9]+>\s*)+/, "").trim();
@@ -152565,14 +152775,14 @@ function formatSlackToolNameForDisplay(toolName) {
152565
152775
  return toolName;
152566
152776
  }
152567
152777
  function resolveSlackConcreteActivity(event2) {
152568
- if (event2.kind === "command" && isNonEmptyString4(event2.command)) {
152778
+ if (event2.kind === "command" && isNonEmptyString5(event2.command)) {
152569
152779
  return sanitizeSlackStatusText(formatSlackToolNameForDisplay(event2.command), SLACK_STATUS_TEXT_MAX);
152570
152780
  }
152571
- if (event2.kind !== "tool" || !isNonEmptyString4(event2.toolName) || event2.toolName.toLowerCase() === "messagechannel") {
152781
+ if (event2.kind !== "tool" || !isNonEmptyString5(event2.toolName) || event2.toolName.toLowerCase() === "messagechannel") {
152572
152782
  return null;
152573
152783
  }
152574
152784
  for (const description of [event2.toolTitle, event2.toolDetails]) {
152575
- if (!isNonEmptyString4(description)) {
152785
+ if (!isNonEmptyString5(description)) {
152576
152786
  continue;
152577
152787
  }
152578
152788
  const sanitized = sanitizeSlackStatusText(description, SLACK_STATUS_TEXT_MAX);
@@ -152674,12 +152884,12 @@ Run \`${toolName}\`?`
152674
152884
  ];
152675
152885
  }
152676
152886
  function parseSlackApprovalActionPayload(value) {
152677
- if (!isNonEmptyString3(value)) {
152887
+ if (!isNonEmptyString4(value)) {
152678
152888
  return null;
152679
152889
  }
152680
152890
  try {
152681
152891
  const parsed = JSON.parse(value);
152682
- if (!isNonEmptyString3(parsed.requestId) || parsed.decision !== "allow" && parsed.decision !== "deny") {
152892
+ if (!isNonEmptyString4(parsed.requestId) || parsed.decision !== "allow" && parsed.decision !== "deny") {
152683
152893
  return null;
152684
152894
  }
152685
152895
  return { requestId: parsed.requestId, decision: parsed.decision };
@@ -152902,16 +153112,16 @@ async function mapSlackThreadMessage(message, attachmentOptions, sourceThreadId)
152902
153112
  const attachments = await resolveSlackMessageAttachments(message, attachmentOptions, sourceThreadId);
152903
153113
  return {
152904
153114
  text: resolveSlackThreadMessageText(message),
152905
- userId: isNonEmptyString5(message.user) ? message.user : undefined,
152906
- botId: isNonEmptyString5(message.bot_id) ? message.bot_id : undefined,
152907
- ts: isNonEmptyString5(message.ts) ? message.ts : undefined,
153115
+ userId: isNonEmptyString6(message.user) ? message.user : undefined,
153116
+ botId: isNonEmptyString6(message.bot_id) ? message.bot_id : undefined,
153117
+ ts: isNonEmptyString6(message.ts) ? message.ts : undefined,
152908
153118
  ...attachments.length > 0 ? { attachments } : {}
152909
153119
  };
152910
153120
  }
152911
153121
  function asRecord4(value) {
152912
153122
  return value && typeof value === "object" ? value : null;
152913
153123
  }
152914
- function isNonEmptyString5(value) {
153124
+ function isNonEmptyString6(value) {
152915
153125
  return typeof value === "string" && value.trim().length > 0;
152916
153126
  }
152917
153127
  function normalizeSlackFileLike(value) {
@@ -152920,12 +153130,12 @@ function normalizeSlackFileLike(value) {
152920
153130
  return null;
152921
153131
  }
152922
153132
  return {
152923
- id: isNonEmptyString5(record5.id) ? record5.id : undefined,
152924
- name: isNonEmptyString5(record5.name) ? record5.name : undefined,
152925
- mimetype: isNonEmptyString5(record5.mimetype) ? record5.mimetype : undefined,
153133
+ id: isNonEmptyString6(record5.id) ? record5.id : undefined,
153134
+ name: isNonEmptyString6(record5.name) ? record5.name : undefined,
153135
+ mimetype: isNonEmptyString6(record5.mimetype) ? record5.mimetype : undefined,
152926
153136
  size: typeof record5.size === "number" ? record5.size : undefined,
152927
- url_private: isNonEmptyString5(record5.url_private) ? record5.url_private : undefined,
152928
- url_private_download: isNonEmptyString5(record5.url_private_download) ? record5.url_private_download : undefined
153137
+ url_private: isNonEmptyString6(record5.url_private) ? record5.url_private : undefined,
153138
+ url_private_download: isNonEmptyString6(record5.url_private_download) ? record5.url_private_download : undefined
152929
153139
  };
152930
153140
  }
152931
153141
  function normalizeSlackAttachmentLike(value) {
@@ -152935,12 +153145,12 @@ function normalizeSlackAttachmentLike(value) {
152935
153145
  }
152936
153146
  const files = Array.isArray(record5.files) ? record5.files.map((entry) => normalizeSlackFileLike(entry)).filter((entry) => Boolean(entry)) : undefined;
152937
153147
  return {
152938
- text: isNonEmptyString5(record5.text) ? record5.text : undefined,
152939
- fallback: isNonEmptyString5(record5.fallback) ? record5.fallback : undefined,
152940
- pretext: isNonEmptyString5(record5.pretext) ? record5.pretext : undefined,
152941
- author_name: isNonEmptyString5(record5.author_name) ? record5.author_name : undefined,
152942
- title: isNonEmptyString5(record5.title) ? record5.title : undefined,
152943
- image_url: isNonEmptyString5(record5.image_url) ? record5.image_url : undefined,
153148
+ text: isNonEmptyString6(record5.text) ? record5.text : undefined,
153149
+ fallback: isNonEmptyString6(record5.fallback) ? record5.fallback : undefined,
153150
+ pretext: isNonEmptyString6(record5.pretext) ? record5.pretext : undefined,
153151
+ author_name: isNonEmptyString6(record5.author_name) ? record5.author_name : undefined,
153152
+ title: isNonEmptyString6(record5.title) ? record5.title : undefined,
153153
+ image_url: isNonEmptyString6(record5.image_url) ? record5.image_url : undefined,
152944
153154
  files
152945
153155
  };
152946
153156
  }
@@ -152973,7 +153183,7 @@ function resolveSlackThreadMessageText(message) {
152973
153183
  if (text) {
152974
153184
  return text;
152975
153185
  }
152976
- const attachmentTexts = Array.isArray(message.attachments) ? message.attachments.map((entry) => normalizeSlackAttachmentLike(entry)).filter((entry) => Boolean(entry)).map((attachment) => resolveSlackAttachmentText(attachment)).filter(isNonEmptyString5) : [];
153186
+ const attachmentTexts = Array.isArray(message.attachments) ? message.attachments.map((entry) => normalizeSlackAttachmentLike(entry)).filter((entry) => Boolean(entry)).map((attachment) => resolveSlackAttachmentText(attachment)).filter(isNonEmptyString6) : [];
152977
153187
  if (attachmentTexts.length > 0) {
152978
153188
  return attachmentTexts.join(`
152979
153189
 
@@ -153280,7 +153490,7 @@ async function resolveSlackFilesAsAttachments(params) {
153280
153490
  return resolved;
153281
153491
  }
153282
153492
  function resolveSlackThreadAttachmentOptions(params) {
153283
- if (!isNonEmptyString5(params.accountId) || !isNonEmptyString5(params.token)) {
153493
+ if (!isNonEmptyString6(params.accountId) || !isNonEmptyString6(params.token)) {
153284
153494
  return;
153285
153495
  }
153286
153496
  return {
@@ -153307,7 +153517,7 @@ async function resolveSlackMessageAttachments(message, attachmentOptions, source
153307
153517
  token: attachmentOptions.token,
153308
153518
  files: collectSlackFiles(message),
153309
153519
  sourceMessageId: message.ts,
153310
- sourceThreadId: sourceThreadId ?? (isNonEmptyString5(message.thread_ts) ? message.thread_ts : null),
153520
+ sourceThreadId: sourceThreadId ?? (isNonEmptyString6(message.thread_ts) ? message.thread_ts : null),
153311
153521
  transcribeVoice: attachmentOptions.transcribeVoice
153312
153522
  });
153313
153523
  }
@@ -153317,8 +153527,8 @@ async function resolveSlackInboundAttachments(params) {
153317
153527
  accountId: params.accountId,
153318
153528
  token: params.token,
153319
153529
  files: collectSlackFiles(params.rawEvent),
153320
- sourceMessageId: isNonEmptyString5(rawEvent?.ts) ? rawEvent.ts : undefined,
153321
- sourceThreadId: isNonEmptyString5(rawEvent?.thread_ts) ? rawEvent.thread_ts : null,
153530
+ sourceMessageId: isNonEmptyString6(rawEvent?.ts) ? rawEvent.ts : undefined,
153531
+ sourceThreadId: isNonEmptyString6(rawEvent?.thread_ts) ? rawEvent.thread_ts : null,
153322
153532
  transcribeVoice: params.transcribeVoice
153323
153533
  });
153324
153534
  }
@@ -153391,7 +153601,7 @@ async function resolveSlackThreadHistory(params) {
153391
153601
  ...cursor ? { cursor } : {}
153392
153602
  });
153393
153603
  for (const message of response.messages ?? []) {
153394
- if (params.include === "bot" && !isNonEmptyString5(message.bot_id)) {
153604
+ if (params.include === "bot" && !isNonEmptyString6(message.bot_id)) {
153395
153605
  continue;
153396
153606
  }
153397
153607
  if (!hasSlackThreadMessageContent(message, attachmentOptions)) {
@@ -153455,11 +153665,11 @@ var init_media2 = __esm(() => {
153455
153665
  });
153456
153666
 
153457
153667
  // src/channels/slack/attachment-download.ts
153458
- function isNonEmptyString6(value) {
153668
+ function isNonEmptyString7(value) {
153459
153669
  return typeof value === "string" && value.trim().length > 0;
153460
153670
  }
153461
153671
  async function resolveCanonicalSlackMessage(params) {
153462
- if (isNonEmptyString6(params.threadTs)) {
153672
+ if (isNonEmptyString7(params.threadTs)) {
153463
153673
  let cursor;
153464
153674
  do {
153465
153675
  const response2 = await params.client.conversations.replies({
@@ -153474,7 +153684,7 @@ async function resolveCanonicalSlackMessage(params) {
153474
153684
  return message;
153475
153685
  }
153476
153686
  const nextCursor = response2.response_metadata?.next_cursor;
153477
- cursor = isNonEmptyString6(nextCursor) ? nextCursor.trim() : undefined;
153687
+ cursor = isNonEmptyString7(nextCursor) ? nextCursor.trim() : undefined;
153478
153688
  } while (cursor);
153479
153689
  return null;
153480
153690
  }
@@ -153626,7 +153836,7 @@ function createSlackInboundDebounceController(params) {
153626
153836
  const deduped = [];
153627
153837
  for (const entry of entries) {
153628
153838
  const messageId = entry.inbound.messageId;
153629
- const messageKey = isNonEmptyString3(messageId) ? `${entry.inbound.chatId}:${messageId}` : null;
153839
+ const messageKey = isNonEmptyString4(messageId) ? `${entry.inbound.chatId}:${messageId}` : null;
153630
153840
  if (!messageKey) {
153631
153841
  deduped.push(entry);
153632
153842
  continue;
@@ -153661,7 +153871,7 @@ function createSlackInboundDebounceController(params) {
153661
153871
  if (pending?.size === 0)
153662
153872
  pendingTopLevelKeys.delete(conversationKey);
153663
153873
  }
153664
- if (isNonEmptyString3(last.inbound.messageId)) {
153874
+ if (isNonEmptyString4(last.inbound.messageId)) {
153665
153875
  const seenKey = `${last.inbound.chatId}:${last.inbound.messageId}`;
153666
153876
  pruneAppMentionMaps(Date.now());
153667
153877
  if (last.opts.source === "app_mention") {
@@ -153740,13 +153950,13 @@ function hasRecordValue(value) {
153740
153950
  return value !== null && typeof value === "object";
153741
153951
  }
153742
153952
  function hasSlackMention(text, userId) {
153743
- return isNonEmptyString4(text) && isNonEmptyString4(userId) && (text.includes(`<@${userId}>`) || text.includes(`<@${userId}|`));
153953
+ return isNonEmptyString5(text) && isNonEmptyString5(userId) && (text.includes(`<@${userId}>`) || text.includes(`<@${userId}|`));
153744
153954
  }
153745
153955
  function isBotAuthoredMessage(message) {
153746
- return isNonEmptyString4(message.bot_id) || message.subtype === "bot_message";
153956
+ return isNonEmptyString5(message.bot_id) || message.subtype === "bot_message";
153747
153957
  }
153748
153958
  function resolveMessageSubtypeIgnoreReason(message) {
153749
- const subtype = isNonEmptyString4(message.subtype) ? message.subtype : null;
153959
+ const subtype = isNonEmptyString5(message.subtype) ? message.subtype : null;
153750
153960
  if (!subtype) {
153751
153961
  return null;
153752
153962
  }
@@ -153760,14 +153970,14 @@ function resolveMessageSubtypeIgnoreReason(message) {
153760
153970
  }
153761
153971
  function resolveSlackMessageIngressPolicy(params) {
153762
153972
  const { message } = params;
153763
- if (!isNonEmptyString4(message.channel)) {
153973
+ if (!isNonEmptyString5(message.channel)) {
153764
153974
  return { shouldRoute: false, reason: "missing_channel" };
153765
153975
  }
153766
153976
  const senderId = firstNonEmptyString3(message.user, message.bot_id);
153767
153977
  if (!senderId) {
153768
153978
  return { shouldRoute: false, reason: "missing_sender" };
153769
153979
  }
153770
- if (!isNonEmptyString4(message.ts)) {
153980
+ if (!isNonEmptyString5(message.ts)) {
153771
153981
  return { shouldRoute: false, reason: "missing_timestamp" };
153772
153982
  }
153773
153983
  if (message.hidden === true) {
@@ -153779,10 +153989,10 @@ function resolveSlackMessageIngressPolicy(params) {
153779
153989
  }
153780
153990
  const chatType = resolveSlackChatType2(message.channel);
153781
153991
  const threadId = chatType === "direct" ? firstNonEmptyString3(message.thread_ts) ?? null : firstNonEmptyString3(message.thread_ts, message.ts) ?? null;
153782
- if (chatType === "channel" && !isNonEmptyString4(message.thread_ts)) {
153992
+ if (chatType === "channel" && !isNonEmptyString5(message.thread_ts)) {
153783
153993
  return { shouldRoute: false, reason: "top_level_channel_message" };
153784
153994
  }
153785
- const rawText = isNonEmptyString4(message.text) ? message.text : "";
153995
+ const rawText = isNonEmptyString5(message.text) ? message.text : "";
153786
153996
  const wasMentioned = hasSlackMention(rawText, params.botUserId);
153787
153997
  const isAgentThread = params.isAgentThread === true;
153788
153998
  const effectiveMention = isBotAuthoredMessage(message) ? wasMentioned : wasMentioned || isAgentThread;
@@ -153790,8 +154000,8 @@ function resolveSlackMessageIngressPolicy(params) {
153790
154000
  shouldRoute: true,
153791
154001
  channelId: message.channel,
153792
154002
  senderId,
153793
- ...isNonEmptyString4(message.user) ? { senderUserId: message.user } : {},
153794
- ...isNonEmptyString4(message.bot_id) ? { senderBotId: message.bot_id } : {},
154003
+ ...isNonEmptyString5(message.user) ? { senderUserId: message.user } : {},
154004
+ ...isNonEmptyString5(message.bot_id) ? { senderBotId: message.bot_id } : {},
153795
154005
  messageId: message.ts,
153796
154006
  threadId,
153797
154007
  chatType,
@@ -153804,23 +154014,23 @@ function resolveSlackMessageIngressPolicy(params) {
153804
154014
  }
153805
154015
  function resolveSlackAppMentionIngressPolicy(params) {
153806
154016
  const { event: event2 } = params;
153807
- if (!isNonEmptyString4(event2.channel)) {
154017
+ if (!isNonEmptyString5(event2.channel)) {
153808
154018
  return { shouldRoute: false, reason: "missing_channel" };
153809
154019
  }
153810
154020
  const senderId = firstNonEmptyString3(event2.user, event2.bot_id);
153811
154021
  if (!senderId) {
153812
154022
  return { shouldRoute: false, reason: "missing_sender" };
153813
154023
  }
153814
- if (!isNonEmptyString4(event2.ts)) {
154024
+ if (!isNonEmptyString5(event2.ts)) {
153815
154025
  return { shouldRoute: false, reason: "missing_timestamp" };
153816
154026
  }
153817
- const rawText = isNonEmptyString4(event2.text) ? event2.text : "";
154027
+ const rawText = isNonEmptyString5(event2.text) ? event2.text : "";
153818
154028
  return {
153819
154029
  shouldRoute: true,
153820
154030
  channelId: event2.channel,
153821
154031
  senderId,
153822
- ...isNonEmptyString4(event2.user) ? { senderUserId: event2.user } : {},
153823
- ...isNonEmptyString4(event2.bot_id) ? { senderBotId: event2.bot_id } : {},
154032
+ ...isNonEmptyString5(event2.user) ? { senderUserId: event2.user } : {},
154033
+ ...isNonEmptyString5(event2.bot_id) ? { senderBotId: event2.bot_id } : {},
153824
154034
  messageId: event2.ts,
153825
154035
  threadId: firstNonEmptyString3(event2.thread_ts, event2.ts) ?? event2.ts,
153826
154036
  chatType: "channel",
@@ -153888,7 +154098,7 @@ function createSlackIngressController(params) {
153888
154098
  }
153889
154099
  }
153890
154100
  function markIngressMessageSeen(channelId, messageId) {
153891
- if (!isNonEmptyString3(channelId) || !isNonEmptyString3(messageId)) {
154101
+ if (!isNonEmptyString4(channelId) || !isNonEmptyString4(messageId)) {
153892
154102
  return false;
153893
154103
  }
153894
154104
  const key = `${channelId}:${messageId}`;
@@ -153899,12 +154109,12 @@ function createSlackIngressController(params) {
153899
154109
  return false;
153900
154110
  }
153901
154111
  function rememberMessageThread(messageId, threadId) {
153902
- if (isNonEmptyString3(messageId)) {
154112
+ if (isNonEmptyString4(messageId)) {
153903
154113
  knownThreadIdsByMessageId.set(messageId, threadId);
153904
154114
  }
153905
154115
  }
153906
154116
  async function resolveUserName(app, userId) {
153907
- if (!isNonEmptyString3(userId))
154117
+ if (!isNonEmptyString4(userId))
153908
154118
  return;
153909
154119
  const cached2 = knownUserDisplayNames.get(userId);
153910
154120
  if (cached2)
@@ -153920,10 +154130,10 @@ function createSlackIngressController(params) {
153920
154130
  return userId;
153921
154131
  }
153922
154132
  async function resolveInboundSenderName(app, userId, botId) {
153923
- if (isNonEmptyString3(userId)) {
154133
+ if (isNonEmptyString4(userId)) {
153924
154134
  return resolveUserName(app, userId);
153925
154135
  }
153926
- return isNonEmptyString3(botId) ? `Bot (${botId})` : undefined;
154136
+ return isNonEmptyString4(botId) ? `Bot (${botId})` : undefined;
153927
154137
  }
153928
154138
  function shouldAcceptInboundMessageByBotPolicy(input) {
153929
154139
  return shouldAcceptSlackInboundBotMessage({
@@ -153951,7 +154161,7 @@ function createSlackIngressController(params) {
153951
154161
  return;
153952
154162
  const rawMessage = asRecord2(message);
153953
154163
  const channelId = rawMessage?.channel;
153954
- if (!rawMessage || !isNonEmptyString3(channelId)) {
154164
+ if (!rawMessage || !isNonEmptyString4(channelId)) {
153955
154165
  return;
153956
154166
  }
153957
154167
  const basePolicy = resolveSlackMessageIngressPolicy({
@@ -153973,7 +154183,7 @@ function createSlackIngressController(params) {
153973
154183
  transcribeVoice: config3.transcribeVoice === true
153974
154184
  });
153975
154185
  const senderName = await resolveInboundSenderName(app, basePolicy.senderUserId, basePolicy.senderBotId);
153976
- const isAgentThread = basePolicy.chatType === "channel" && isNonEmptyString3(basePolicy.threadId) && params.agentThreadTracker.has(channelId, basePolicy.threadId);
154186
+ const isAgentThread = basePolicy.chatType === "channel" && isNonEmptyString4(basePolicy.threadId) && params.agentThreadTracker.has(channelId, basePolicy.threadId);
153977
154187
  const policy = resolveSlackMessageIngressPolicy({
153978
154188
  message: rawMessage,
153979
154189
  botUserId: params.getBotUserId(),
@@ -154076,10 +154286,10 @@ function createSlackIngressController(params) {
154076
154286
  }) => {
154077
154287
  await ack();
154078
154288
  const adapter = params.getAdapter();
154079
- if (!adapter.onMessage || !isNonEmptyString3(command.command) || !isNonEmptyString3(command.channel_id) || !isNonEmptyString3(command.user_id)) {
154289
+ if (!adapter.onMessage || !isNonEmptyString4(command.command) || !isNonEmptyString4(command.channel_id) || !isNonEmptyString4(command.user_id)) {
154080
154290
  return;
154081
154291
  }
154082
- const args = isNonEmptyString3(command.text) ? command.text.trim() : "";
154292
+ const args = isNonEmptyString4(command.text) ? command.text.trim() : "";
154083
154293
  try {
154084
154294
  await adapter.onMessage({
154085
154295
  channel: "slack",
@@ -154143,7 +154353,7 @@ function createSlackIngressController(params) {
154143
154353
  const item = asRecord2(event2.item);
154144
154354
  const chatId = item?.channel;
154145
154355
  const targetMessageId = item?.ts;
154146
- if (!adapter.onMessage || item?.type !== "message" || !isNonEmptyString3(chatId) || !isNonEmptyString3(targetMessageId) || !isNonEmptyString3(event2.user) || !isNonEmptyString3(event2.reaction) || event2.user === params.getBotUserId()) {
154356
+ if (!adapter.onMessage || item?.type !== "message" || !isNonEmptyString4(chatId) || !isNonEmptyString4(targetMessageId) || !isNonEmptyString4(event2.user) || !isNonEmptyString4(event2.reaction) || event2.user === params.getBotUserId()) {
154147
154357
  return;
154148
154358
  }
154149
154359
  const chatType = resolveSlackChatType(chatId);
@@ -154167,7 +154377,7 @@ function createSlackIngressController(params) {
154167
154377
  action: action3,
154168
154378
  emoji: event2.reaction,
154169
154379
  targetMessageId,
154170
- targetSenderId: isNonEmptyString3(event2.item_user) ? event2.item_user : undefined
154380
+ targetSenderId: isNonEmptyString4(event2.item_user) ? event2.item_user : undefined
154171
154381
  },
154172
154382
  raw: event2
154173
154383
  });
@@ -154213,22 +154423,22 @@ function createSlackStatusController(params) {
154213
154423
  const keepaliveByConversation = new Map;
154214
154424
  const clearedStaleReplyKeys = new Set;
154215
154425
  function getConversationKey(source2) {
154216
- return source2.channel === "slack" && isNonEmptyString4(source2.agentId) && isNonEmptyString4(source2.conversationId) ? `${source2.agentId}:${source2.conversationId}` : null;
154426
+ return source2.channel === "slack" && isNonEmptyString5(source2.agentId) && isNonEmptyString5(source2.conversationId) ? `${source2.agentId}:${source2.conversationId}` : null;
154217
154427
  }
154218
154428
  function getLifecycleReplyKey(source2) {
154219
- if (source2.channel !== "slack" || !isNonEmptyString4(source2.chatId)) {
154429
+ if (source2.channel !== "slack" || !isNonEmptyString5(source2.chatId)) {
154220
154430
  return null;
154221
154431
  }
154222
154432
  const replyToMessageId = resolveSlackProgressThreadTs(source2);
154223
- return isNonEmptyString4(replyToMessageId) ? `${source2.chatId}:${replyToMessageId}` : null;
154433
+ return isNonEmptyString5(replyToMessageId) ? `${source2.chatId}:${replyToMessageId}` : null;
154224
154434
  }
154225
154435
  function getLifecycleErrorReplyKey(source2) {
154226
- if (source2.channel !== "slack" || !isNonEmptyString4(source2.chatId)) {
154436
+ if (source2.channel !== "slack" || !isNonEmptyString5(source2.chatId)) {
154227
154437
  return null;
154228
154438
  }
154229
154439
  if (source2.chatType === "direct" || resolveSlackChatType2(source2.chatId) === "direct") {
154230
154440
  const replyToMessageId = resolveSlackSourceThreadTs2(source2);
154231
- return isNonEmptyString4(replyToMessageId) ? `${source2.chatId}:${replyToMessageId}` : `${source2.chatId}:direct`;
154441
+ return isNonEmptyString5(replyToMessageId) ? `${source2.chatId}:${replyToMessageId}` : `${source2.chatId}:direct`;
154232
154442
  }
154233
154443
  return getLifecycleReplyKey(source2);
154234
154444
  }
@@ -154387,7 +154597,7 @@ ${loadingText}`;
154387
154597
  markAutoClearedByKey(key);
154388
154598
  },
154389
154599
  markAutoClearedForMessage(msg) {
154390
- if (isNonEmptyString4(msg.agentId) && isNonEmptyString4(msg.conversationId)) {
154600
+ if (isNonEmptyString5(msg.agentId) && isNonEmptyString5(msg.conversationId)) {
154391
154601
  markAutoClearedByKey(`${msg.agentId}:${msg.conversationId}`);
154392
154602
  return;
154393
154603
  }
@@ -154435,7 +154645,7 @@ function truncateThreadLabel(text, maxLength3 = 80) {
154435
154645
  return normalized.length <= maxLength3 ? normalized : `${normalized.slice(0, maxLength3 - 1).trimEnd()}…`;
154436
154646
  }
154437
154647
  function buildThreadLabel(msg, starterText) {
154438
- const roomLabel = msg.chatType === "channel" && isNonEmptyString3(msg.chatLabel) && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
154648
+ const roomLabel = msg.chatType === "channel" && isNonEmptyString4(msg.chatLabel) && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
154439
154649
  const preview = truncateThreadLabel(starterText ?? msg.text);
154440
154650
  const threadLabel = msg.chatType === "direct" ? "Slack DM thread" : "Slack thread";
154441
154651
  if (preview)
@@ -154445,12 +154655,12 @@ function buildThreadLabel(msg, starterText) {
154445
154655
  function buildChannelContextLabel(msg) {
154446
154656
  if (msg.chatType !== "channel")
154447
154657
  return;
154448
- const roomLabel = isNonEmptyString3(msg.chatLabel) && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
154658
+ const roomLabel = isNonEmptyString4(msg.chatLabel) && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
154449
154659
  return roomLabel ? `Slack channel context${roomLabel} before thread start` : "Slack channel context before thread start";
154450
154660
  }
154451
154661
  async function prepareSlackInboundMessage(params) {
154452
154662
  const { msg, config: config3 } = params;
154453
- if (msg.channel !== "slack" || !isNonEmptyString3(msg.threadId) || !isNonEmptyString3(msg.messageId)) {
154663
+ if (msg.channel !== "slack" || !isNonEmptyString4(msg.threadId) || !isNonEmptyString4(msg.messageId)) {
154454
154664
  return msg;
154455
154665
  }
154456
154666
  const isFirstRouteTurn = params.options?.isFirstRouteTurn === true;
@@ -154499,18 +154709,18 @@ async function prepareSlackInboundMessage(params) {
154499
154709
  return msg;
154500
154710
  }
154501
154711
  const userIds = new Set;
154502
- if (isNonEmptyString3(starter?.userId))
154712
+ if (isNonEmptyString4(starter?.userId))
154503
154713
  userIds.add(starter.userId);
154504
154714
  for (const entry of history) {
154505
- if (isNonEmptyString3(entry.userId))
154715
+ if (isNonEmptyString4(entry.userId))
154506
154716
  userIds.add(entry.userId);
154507
154717
  }
154508
154718
  await Promise.all(Array.from(userIds).map((userId) => params.resolveUserName(app, userId)));
154509
154719
  const resolveSenderName = (userId, botId) => {
154510
- if (isNonEmptyString3(userId)) {
154720
+ if (isNonEmptyString4(userId)) {
154511
154721
  return params.getKnownUserDisplayName(userId) ?? userId;
154512
154722
  }
154513
- return isNonEmptyString3(botId) ? `Bot (${botId})` : undefined;
154723
+ return isNonEmptyString4(botId) ? `Bot (${botId})` : undefined;
154514
154724
  };
154515
154725
  return {
154516
154726
  ...msg,
@@ -154669,7 +154879,7 @@ function createSlackAdapter(config3) {
154669
154879
  if (!running)
154670
154880
  return;
154671
154881
  if (event2.type === "queued") {
154672
- if (isSlackFlatChannelThreadOpener(event2.source) && isNonEmptyString3(event2.source.messageId) && !agentThreadTracker.has(event2.source.chatId, event2.source.messageId)) {
154882
+ if (isSlackFlatChannelThreadOpener(event2.source) && isNonEmptyString4(event2.source.messageId) && !agentThreadTracker.has(event2.source.chatId, event2.source.messageId)) {
154673
154883
  await status.activate(event2.source, SLACK_ASSISTANT_STARTUP_STATUS, SLACK_ASSISTANT_STARTUP_STATUS);
154674
154884
  }
154675
154885
  return;
@@ -154731,7 +154941,7 @@ function createSlackAdapter(config3) {
154731
154941
  if (msg.mediaPath) {
154732
154942
  const result = await uploadSlackFile(client, msg);
154733
154943
  const threadId = msg.threadId ?? msg.replyToMessageId ?? null;
154734
- if (resolveSlackChatType(msg.chatId) === "channel" && isNonEmptyString3(threadId)) {
154944
+ if (resolveSlackChatType(msg.chatId) === "channel" && isNonEmptyString4(threadId)) {
154735
154945
  agentThreadTracker.remember(msg.chatId, threadId);
154736
154946
  }
154737
154947
  status.markAutoClearedForMessage(msg);
@@ -154742,7 +154952,7 @@ function createSlackAdapter(config3) {
154742
154952
  threadId: msg.threadId,
154743
154953
  replyToMessageId: msg.replyToMessageId
154744
154954
  });
154745
- const footnote = isNonEmptyString3(msg.agentId) && isNonEmptyString3(msg.conversationId) ? buildSlackChatFootnote({
154955
+ const footnote = isNonEmptyString4(msg.agentId) && isNonEmptyString4(msg.conversationId) ? buildSlackChatFootnote({
154746
154956
  agentId: msg.agentId,
154747
154957
  conversationId: msg.conversationId
154748
154958
  }) : "";
@@ -154755,7 +154965,7 @@ function createSlackAdapter(config3) {
154755
154965
  });
154756
154966
  const outboundThreadId = threadTs ?? (resolveSlackChatType(msg.chatId) === "channel" ? response.ts ?? null : null);
154757
154967
  ingress.rememberMessageThread(response.ts, outboundThreadId);
154758
- if (resolveSlackChatType(msg.chatId) === "channel" && isNonEmptyString3(outboundThreadId)) {
154968
+ if (resolveSlackChatType(msg.chatId) === "channel" && isNonEmptyString4(outboundThreadId)) {
154759
154969
  agentThreadTracker.remember(msg.chatId, outboundThreadId);
154760
154970
  }
154761
154971
  status.markAutoClearedForMessage(msg);
@@ -154778,7 +154988,7 @@ function createSlackAdapter(config3) {
154778
154988
  });
154779
154989
  const outboundThreadId = threadTs ?? (resolveSlackChatType(chatId) === "channel" ? response.ts ?? null : null);
154780
154990
  ingress.rememberMessageThread(response.ts, outboundThreadId);
154781
- if (resolveSlackChatType(chatId) === "channel" && isNonEmptyString3(outboundThreadId)) {
154991
+ if (resolveSlackChatType(chatId) === "channel" && isNonEmptyString4(outboundThreadId)) {
154782
154992
  agentThreadTracker.remember(chatId, outboundThreadId);
154783
154993
  }
154784
154994
  status.markAutoClearedForMessage({
@@ -154804,7 +155014,7 @@ function createSlackAdapter(config3) {
154804
155014
  if (event2.kind === "generic_tool_approval" && response.ts) {
154805
155015
  approvals.rememberPrompt(event2, response.ts);
154806
155016
  }
154807
- if (resolveSlackChatType(event2.source.chatId) === "channel" && isNonEmptyString3(outboundThreadId)) {
155017
+ if (resolveSlackChatType(event2.source.chatId) === "channel" && isNonEmptyString4(outboundThreadId)) {
154808
155018
  agentThreadTracker.remember(event2.source.chatId, outboundThreadId);
154809
155019
  }
154810
155020
  status.markAutoCleared(event2.source);
@@ -154820,8 +155030,8 @@ function createSlackAdapter(config3) {
154820
155030
  const slackApp = await ensureApp();
154821
155031
  const auth = await slackApp.client.auth.test();
154822
155032
  const authRecord = auth;
154823
- botUserId = isNonEmptyString3(authRecord.user_id) ? authRecord.user_id : null;
154824
- botId = isNonEmptyString3(authRecord.bot_id) ? authRecord.bot_id : null;
155033
+ botUserId = isNonEmptyString4(authRecord.user_id) ? authRecord.user_id : null;
155034
+ botId = isNonEmptyString4(authRecord.bot_id) ? authRecord.bot_id : null;
154825
155035
  await slackApp.start();
154826
155036
  running = true;
154827
155037
  console.log(`[Slack] App started for workspace ${auth.team ?? "unknown"} (dm_policy: ${config3.dmPolicy})`);
@@ -156044,7 +156254,7 @@ function formatDiscordDeliveryError(error54) {
156044
156254
  }
156045
156255
 
156046
156256
  // src/channels/discord/utils.ts
156047
- function isNonEmptyString7(value) {
156257
+ function isNonEmptyString8(value) {
156048
156258
  return typeof value === "string" && value.length > 0;
156049
156259
  }
156050
156260
  function isDiscordTextChannel(channel) {
@@ -156111,7 +156321,7 @@ function shouldAutoThreadOnDiscordMention(account, channelId) {
156111
156321
  return account.autoThreadOnMention ?? false;
156112
156322
  }
156113
156323
  function buildDiscordIngressMessageKey(accountId, messageId) {
156114
- if (!isNonEmptyString7(accountId) || !isNonEmptyString7(messageId)) {
156324
+ if (!isNonEmptyString8(accountId) || !isNonEmptyString8(messageId)) {
156115
156325
  return null;
156116
156326
  }
156117
156327
  return `${accountId}:${messageId}`;
@@ -156195,13 +156405,13 @@ function createDiscordAdapter(config3) {
156195
156405
  return false;
156196
156406
  }
156197
156407
  function getLifecycleMessageKey(source2) {
156198
- if (source2.channel !== "discord" || !isNonEmptyString7(source2.chatId) || !isNonEmptyString7(source2.messageId)) {
156408
+ if (source2.channel !== "discord" || !isNonEmptyString8(source2.chatId) || !isNonEmptyString8(source2.messageId)) {
156199
156409
  return null;
156200
156410
  }
156201
156411
  return `${source2.chatId}:${source2.messageId}`;
156202
156412
  }
156203
156413
  function getLifecycleReplyKey(source2) {
156204
- if (source2.channel !== "discord" || !isNonEmptyString7(source2.chatId)) {
156414
+ if (source2.channel !== "discord" || !isNonEmptyString8(source2.chatId)) {
156205
156415
  return null;
156206
156416
  }
156207
156417
  return [
@@ -156214,7 +156424,7 @@ function createDiscordAdapter(config3) {
156214
156424
  if (source2.channel !== "discord")
156215
156425
  return null;
156216
156426
  const channelId = source2.threadId ?? source2.chatId;
156217
- return isNonEmptyString7(channelId) ? channelId : null;
156427
+ return isNonEmptyString8(channelId) ? channelId : null;
156218
156428
  }
156219
156429
  function getTypingSourceKey(source2) {
156220
156430
  const channelId = getTypingChannelId(source2);
@@ -156266,7 +156476,7 @@ function createDiscordAdapter(config3) {
156266
156476
  return true;
156267
156477
  }
156268
156478
  async function sendLifecycleReaction(source2, emoji3, remove = false) {
156269
- if (!client || !isNonEmptyString7(source2.messageId))
156479
+ if (!client || !isNonEmptyString8(source2.messageId))
156270
156480
  return;
156271
156481
  try {
156272
156482
  const channel = await client.channels.fetch(source2.chatId);
@@ -156507,15 +156717,23 @@ function createDiscordAdapter(config3) {
156507
156717
  client.on("messageCreate", async (message) => {
156508
156718
  if (!adapter.onMessage)
156509
156719
  return;
156510
- if (message.author.bot)
156511
- return;
156512
156720
  const content = (message.content ?? "").trim();
156513
156721
  const userId = message.author.id;
156514
156722
  if (!userId)
156515
156723
  return;
156724
+ const effectiveBotUserId = botUserId ?? client?.user?.id ?? null;
156516
156725
  const chatType = resolveDiscordChatType(message.guildId);
156517
156726
  const isThread = isThreadMessage(message);
156518
- const wasMentioned = chatType === "channel" && hasBotMention(message);
156727
+ const hasParsedBotMention = hasBotMention(message);
156728
+ const wasMentioned = chatType === "channel" && hasParsedBotMention;
156729
+ if (!shouldAcceptDiscordInboundBotMessage({
156730
+ message,
156731
+ allowBots: config3.allowBots,
156732
+ botUserId: effectiveBotUserId,
156733
+ wasExplicitlyMentioned: hasParsedBotMention && hasExplicitDiscordUserMention(message, effectiveBotUserId)
156734
+ })) {
156735
+ return;
156736
+ }
156519
156737
  if (chatType === "direct") {
156520
156738
  if (markIngressMessageSeen(message.id))
156521
156739
  return;
@@ -156541,7 +156759,9 @@ function createDiscordAdapter(config3) {
156541
156759
  await adapter.onMessage(inbound2);
156542
156760
  } catch (error54) {
156543
156761
  console.error("[Discord] Error handling DM:", error54);
156544
- await notifyDiscordDeliveryError(message, error54);
156762
+ if (!message.author.bot) {
156763
+ await notifyDiscordDeliveryError(message, error54);
156764
+ }
156545
156765
  }
156546
156766
  return;
156547
156767
  }
@@ -156596,7 +156816,9 @@ function createDiscordAdapter(config3) {
156596
156816
  await adapter.onMessage(inbound);
156597
156817
  } catch (error54) {
156598
156818
  console.error("[Discord] Error handling guild message:", error54);
156599
- await notifyDiscordDeliveryError(message, error54);
156819
+ if (!message.author.bot) {
156820
+ await notifyDiscordDeliveryError(message, error54);
156821
+ }
156600
156822
  }
156601
156823
  });
156602
156824
  const handleReactionEvent = async (reaction, user, action3) => {
@@ -156805,7 +157027,7 @@ function createDiscordAdapter(config3) {
156805
157027
  clearTypingForChannel(chatId);
156806
157028
  },
156807
157029
  async prepareInboundMessage(msg, options3) {
156808
- if (!options3?.isFirstRouteTurn || msg.channel !== "discord" || msg.chatType !== "channel" || !isNonEmptyString7(msg.threadId) || !client) {
157030
+ if (!options3?.isFirstRouteTurn || msg.channel !== "discord" || msg.chatType !== "channel" || !isNonEmptyString8(msg.threadId) || !client) {
156809
157031
  return msg;
156810
157032
  }
156811
157033
  const starter = await resolveDiscordThreadStarter({
@@ -160858,168 +161080,6 @@ var init_app_urls = __esm(() => {
160858
161080
  LETTA_CHAT_API_KEYS_URL = `${CHAT_BASE}/preferences/api-keys`;
160859
161081
  });
160860
161082
 
160861
- // src/channels/registry-presentation.ts
160862
- function channelDisplayName4(channelId) {
160863
- try {
160864
- return getChannelDisplayName(channelId);
160865
- } catch {
160866
- return channelId;
160867
- }
160868
- }
160869
- function normalizeAgentId(agentId) {
160870
- const normalized = agentId?.trim();
160871
- return normalized ? normalized : null;
160872
- }
160873
- function getConfiguredAgentId(config3) {
160874
- if (!config3 || typeof config3 !== "object")
160875
- return null;
160876
- const source2 = config3;
160877
- return normalizeAgentId(source2.agentId) ?? normalizeAgentId(source2.binding?.agentId);
160878
- }
160879
- function buildPairingInstructions(channelId, code2, options3 = {}) {
160880
- const displayName = channelDisplayName4(channelId);
160881
- const configuredAgentId = normalizeAgentId(options3.agentId);
160882
- const pairingCommand = `letta channels pair --channel ${channelId} --code ${code2} --agent ${configuredAgentId ?? "<agent-id>"}`;
160883
- const agentLookupLines = configuredAgentId ? [] : ["Find the target agent with: letta agents list"];
160884
- if (!isFirstPartyChannelPlugin(channelId)) {
160885
- return [
160886
- "Connect this chat to a Letta agent.",
160887
- "",
160888
- `Pairing code: ${code2}`,
160889
- "",
160890
- "CLI on the listener machine:",
160891
- pairingCommand,
160892
- ...agentLookupLines,
160893
- "",
160894
- "This code expires in 15 minutes."
160895
- ].join(`
160896
- `);
160897
- }
160898
- return [
160899
- "Connect this chat to a Letta agent.",
160900
- "",
160901
- `Pairing code: ${code2}`,
160902
- "",
160903
- `In Letta Code: open Channels > ${displayName} and approve this pending chat.`,
160904
- "",
160905
- "CLI on the listener machine:",
160906
- pairingCommand,
160907
- ...agentLookupLines,
160908
- "",
160909
- "This code expires in 15 minutes."
160910
- ].join(`
160911
- `);
160912
- }
160913
- function buildUnboundRouteInstructions(channelId, chatId) {
160914
- const displayName = channelDisplayName4(channelId);
160915
- if (!isFirstPartyChannelPlugin(channelId)) {
160916
- return `This chat isn't connected to a Letta agent yet.
160917
-
160918
- ` + `On the machine where your listener runs:
160919
-
160920
- ` + `letta channels route add --channel ${channelId} --chat-id ${chatId} --agent <agent-id>
160921
-
160922
- ` + `Find your agent id with letta agents list.`;
160923
- }
160924
- return `This chat isn't connected to a Letta agent yet.
160925
-
160926
- ` + `Open Channels > ${displayName} in Letta Code and connect this chat there.
160927
-
160928
- ` + `Chat ID: ${chatId}`;
160929
- }
160930
- function buildSlackAppSetupInstructions() {
160931
- return `This Slack app isn't connected to a Letta agent yet.
160932
-
160933
- ` + "Open Channels > Slack in Letta Code, choose which agent this app should represent, and try again.";
160934
- }
160935
- function truncateChannelSummaryPreview(text, maxLength3 = 72) {
160936
- const normalized = text.replace(/\s+/g, " ").trim();
160937
- if (!normalized)
160938
- return null;
160939
- if (normalized.length <= maxLength3)
160940
- return normalized;
160941
- return `${normalized.slice(0, maxLength3 - 1).trimEnd()}…`;
160942
- }
160943
- function buildSlackConversationSummary(msg) {
160944
- if (msg.chatType === "direct") {
160945
- if (msg.threadId?.trim()) {
160946
- const preview3 = truncateChannelSummaryPreview(msg.text);
160947
- return preview3 ? `[Slack] DM thread with ${msg.senderName?.trim() || msg.senderId}: ${preview3}` : `[Slack] DM thread with ${msg.senderName?.trim() || msg.senderId}`;
160948
- }
160949
- return `[Slack] DM with ${msg.senderName?.trim() || msg.senderId}`;
160950
- }
160951
- const preview2 = truncateChannelSummaryPreview(msg.text);
160952
- const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
160953
- if (preview2)
160954
- return `[Slack] Thread${channelLabel}: ${preview2}`;
160955
- return `[Slack] Thread${channelLabel || ` ${msg.chatId}`}`;
160956
- }
160957
- function buildDiscordConversationSummary(msg) {
160958
- if (msg.chatType === "direct") {
160959
- return `[Discord] DM with ${msg.senderName?.trim() || msg.senderId}`;
160960
- }
160961
- const preview2 = truncateChannelSummaryPreview(msg.text);
160962
- const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
160963
- if (preview2)
160964
- return `[Discord] Thread${channelLabel}: ${preview2}`;
160965
- return `[Discord] Thread${channelLabel || ` ${msg.chatId}`}`;
160966
- }
160967
- function buildTelegramConversationSummary(msg) {
160968
- if (msg.chatType === "direct") {
160969
- return `[Telegram] DM with ${msg.senderName?.trim() || msg.senderId}`;
160970
- }
160971
- const preview2 = truncateChannelSummaryPreview(msg.text);
160972
- const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
160973
- if (preview2)
160974
- return `[Telegram] Topic${channelLabel}: ${preview2}`;
160975
- return `[Telegram] Topic${channelLabel || ` ${msg.chatId}`}`;
160976
- }
160977
- function buildWhatsAppConversationSummary(msg) {
160978
- if (msg.chatType === "direct") {
160979
- return `[WhatsApp] DM with ${msg.senderName?.trim() || msg.senderId}`;
160980
- }
160981
- const preview2 = truncateChannelSummaryPreview(msg.text);
160982
- const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
160983
- if (preview2)
160984
- return `[WhatsApp] Group${channelLabel}: ${preview2}`;
160985
- return `[WhatsApp] Group${channelLabel || ` ${msg.chatId}`}`;
160986
- }
160987
- function buildSignalConversationSummary(msg) {
160988
- if (msg.chatType === "direct") {
160989
- return `[Signal] DM with ${msg.senderName?.trim() || msg.senderId}`;
160990
- }
160991
- const preview2 = truncateChannelSummaryPreview(msg.text);
160992
- const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
160993
- if (preview2)
160994
- return `[Signal] Group${channelLabel}: ${preview2}`;
160995
- return `[Signal] Group${channelLabel || ` ${msg.chatId}`}`;
160996
- }
160997
- function buildChannelTurnSource(route, msg) {
160998
- return {
160999
- channel: msg.channel,
161000
- accountId: msg.accountId,
161001
- chatId: msg.chatId,
161002
- chatType: msg.chatType,
161003
- senderId: msg.senderId,
161004
- senderTeamId: msg.senderTeamId,
161005
- messageId: msg.messageId,
161006
- threadId: msg.threadId,
161007
- agentId: route.agentId,
161008
- conversationId: route.conversationId
161009
- };
161010
- }
161011
- function buildDirectReplyOptions(msg) {
161012
- if (!msg.messageId && !msg.threadId)
161013
- return;
161014
- return {
161015
- replyToMessageId: msg.threadId ?? msg.messageId ?? undefined,
161016
- threadId: msg.threadId ?? null
161017
- };
161018
- }
161019
- var init_registry_presentation = __esm(() => {
161020
- init_plugin_registry();
161021
- });
161022
-
161023
161083
  // src/channels/routing.ts
161024
161084
  var exports_routing = {};
161025
161085
  __export(exports_routing, {
@@ -161030,8 +161090,10 @@ __export(exports_routing, {
161030
161090
  removeRouteInMemory: () => removeRouteInMemory,
161031
161091
  removeRoute: () => removeRoute,
161032
161092
  loadRoutes: () => loadRoutes,
161093
+ loadRouteForInboundMessage: () => loadRouteForInboundMessage,
161033
161094
  getRoutesForChannel: () => getRoutesForChannel,
161034
161095
  getRouteRaw: () => getRouteRaw,
161096
+ getRouteForInboundMessage: () => getRouteForInboundMessage,
161035
161097
  getRoute: () => getRoute,
161036
161098
  getAllRoutes: () => getAllRoutes,
161037
161099
  clearAllRoutes: () => clearAllRoutes,
@@ -161134,6 +161196,28 @@ function getRoute(channel, chatId, accountId, threadId) {
161134
161196
  function getRouteRaw(channel, chatId, accountId, threadId) {
161135
161197
  return routesByKey.get(routeKey(channel, chatId, accountId, threadId));
161136
161198
  }
161199
+ function selectRoute(route, includeDisabled) {
161200
+ if (!route || !includeDisabled && route.enabled === false)
161201
+ return null;
161202
+ return route;
161203
+ }
161204
+ function getRouteForInboundMessage(msg, accountId, options3 = {}) {
161205
+ const includeDisabled = options3.includeDisabled === true;
161206
+ const exactRoute = getRouteRaw(msg.channel, msg.chatId, accountId, msg.threadId);
161207
+ if (exactRoute)
161208
+ return selectRoute(exactRoute, includeDisabled);
161209
+ if (msg.channel !== "telegram" || msg.chatType !== "direct" || !msg.threadId?.trim()) {
161210
+ return null;
161211
+ }
161212
+ return selectRoute(getRouteRaw(msg.channel, msg.chatId, accountId, null), includeDisabled);
161213
+ }
161214
+ function loadRouteForInboundMessage(msg, accountId, options3) {
161215
+ const route = getRouteForInboundMessage(msg, accountId, options3);
161216
+ if (route)
161217
+ return route;
161218
+ loadRoutes(msg.channel);
161219
+ return getRouteForInboundMessage(msg, accountId, options3);
161220
+ }
161137
161221
  function getRoutesForChannel(channelId, accountId) {
161138
161222
  const prefix = accountId === undefined ? `${channelId}:` : `${channelId}:${normalizeAccountId3(accountId)}:`;
161139
161223
  const routes = [];
@@ -161215,16 +161299,10 @@ var init_routing = __esm(() => {
161215
161299
 
161216
161300
  // src/channels/registry-commands.ts
161217
161301
  function createChannelCommandRouter(deps) {
161218
- function findRawRouteForMessage(msg) {
161219
- return getRouteRaw(msg.channel, msg.chatId, msg.accountId, msg.threadId) ?? null;
161220
- }
161221
161302
  function loadAndFindRawRouteForMessage(msg) {
161222
- const route = findRawRouteForMessage(msg);
161223
- if (route) {
161224
- return route;
161225
- }
161226
- loadRoutes(msg.channel);
161227
- return findRawRouteForMessage(msg);
161303
+ return loadRouteForInboundMessage(msg, msg.accountId, {
161304
+ includeDisabled: true
161305
+ });
161228
161306
  }
161229
161307
  async function handlePauseResumeSlashCommand(commandName, msg) {
161230
161308
  const route = loadAndFindRawRouteForMessage(msg);
@@ -161474,15 +161552,9 @@ function createChannelCommandRouter(deps) {
161474
161552
  });
161475
161553
  }
161476
161554
  function getCancelRoute(msg) {
161477
- let route = deps.getRoute(msg.channel, msg.chatId, msg.accountId, msg.threadId);
161478
- if (route) {
161479
- return route;
161480
- }
161481
- loadRoutes(msg.channel);
161482
- route = deps.getRoute(msg.channel, msg.chatId, msg.accountId, msg.threadId);
161483
- if (route) {
161555
+ const route = loadRouteForInboundMessage(msg, msg.accountId);
161556
+ if (route)
161484
161557
  return route;
161485
- }
161486
161558
  if (msg.channel !== "slack" || msg.chatType !== "channel" || msg.threadId != null) {
161487
161559
  return null;
161488
161560
  }
@@ -162343,7 +162415,7 @@ function createChannelInboundRouter(deps) {
162343
162415
  return;
162344
162416
  }
162345
162417
  if (resolveChannelAccessScope(msg.chatType) === "dm") {
162346
- await adapter.sendDirectReply(msg.chatId, buildChannelAccessDeniedMessage(msg.channel));
162418
+ await adapter.sendDirectReply(msg.chatId, buildChannelAccessDeniedMessage(msg.channel), buildDirectReplyOptions(msg));
162347
162419
  } else {
162348
162420
  console.log(`[channels] Dropped ${msg.channel} group message from unauthorized sender ${msg.senderId} in chat ${msg.chatId}`);
162349
162421
  }
@@ -162355,14 +162427,7 @@ function createChannelInboundRouter(deps) {
162355
162427
  if (deps.commands.shouldDropUnroutedSlackThreadInput(msg, accountId, config3)) {
162356
162428
  return;
162357
162429
  }
162358
- const getStatusRoute = () => {
162359
- let statusRoute = getRoute(msg.channel, msg.chatId, accountId, msg.threadId);
162360
- if (!statusRoute) {
162361
- loadRoutes(msg.channel);
162362
- statusRoute = getRoute(msg.channel, msg.chatId, accountId, msg.threadId);
162363
- }
162364
- return statusRoute;
162365
- };
162430
+ const getStatusRoute = () => loadRouteForInboundMessage(msg, accountId);
162366
162431
  if (await tryHandleChannelSlashCommand(adapter, msg, {
162367
162432
  statusContext: {
162368
162433
  adapterRunning: adapter.isRunning(),
@@ -162512,16 +162577,12 @@ function createChannelInboundRouter(deps) {
162512
162577
  });
162513
162578
  await adapter.sendDirectReply(msg.chatId, buildPairingInstructions(msg.channel, code2, {
162514
162579
  agentId: getConfiguredAgentId(config3)
162515
- }));
162580
+ }), buildDirectReplyOptions(msg));
162516
162581
  return;
162517
162582
  }
162518
- let route = getRoute(msg.channel, msg.chatId, accountId, msg.threadId);
162519
- if (!route) {
162520
- loadRoutes(msg.channel);
162521
- route = getRoute(msg.channel, msg.chatId, accountId, msg.threadId);
162522
- }
162583
+ const route = loadRouteForInboundMessage(msg, accountId);
162523
162584
  if (!route) {
162524
- await adapter.sendDirectReply(msg.chatId, buildUnboundRouteInstructions(msg.channel, msg.chatId));
162585
+ await adapter.sendDirectReply(msg.chatId, buildUnboundRouteInstructions(msg.channel, msg.chatId), buildDirectReplyOptions(msg));
162525
162586
  return;
162526
162587
  }
162527
162588
  const preparedMessage = adapter.prepareInboundMessage ? await adapter.prepareInboundMessage(msg, { isFirstRouteTurn: false }) : msg;
@@ -353079,10 +353140,7 @@ function inferAccountIdFromChannelTurnSources(params) {
353079
353140
  }
353080
353141
  const accountIds = new Set;
353081
353142
  for (const source2 of params.channelTurnSources ?? []) {
353082
- if (source2.channel !== params.input.channel || source2.chatId !== chatId || source2.agentId !== params.scope.agentId || source2.conversationId !== params.scope.conversationId) {
353083
- continue;
353084
- }
353085
- if (params.input.threadId !== undefined && (source2.threadId ?? null) !== (params.input.threadId ?? null)) {
353143
+ if (source2.channel !== params.input.channel || source2.chatId !== chatId || source2.agentId !== params.scope.agentId || source2.conversationId !== params.scope.conversationId || params.input.threadId !== null && source2.threadId !== params.input.threadId) {
353086
353144
  continue;
353087
353145
  }
353088
353146
  if (source2.accountId?.trim()) {
@@ -353185,7 +353243,7 @@ async function message_channel(args) {
353185
353243
  accountId: resolvedAccountId,
353186
353244
  channelTurnSources: args.channelTurnSources
353187
353245
  });
353188
- const requestThreadId = input.action === "download-file" ? input.threadId : inferredThreadId ?? route2.threadId ?? input.threadId;
353246
+ const requestThreadId = input.action === "download-file" ? input.threadId : inferredThreadId ?? (input.channel === "telegram" && route2.chatType === "direct" ? input.threadId : route2.threadId ?? input.threadId);
353189
353247
  executionContext = {
353190
353248
  request: buildMessageChannelRequest(input, input.chatId, requestThreadId),
353191
353249
  route: route2,
@@ -381962,6 +382020,17 @@ var init_local_backend = __esm(() => {
381962
382020
 
381963
382021
  // src/backend/backend.ts
381964
382022
  import { homedir as homedir26 } from "node:os";
382023
+ function toApiConversationMessageListBody(body) {
382024
+ const order = body?.order ?? DEFAULT_CONVERSATION_MESSAGE_ORDER;
382025
+ if (!body || order !== "desc" || !body.before && !body.after) {
382026
+ return body;
382027
+ }
382028
+ return {
382029
+ ...body,
382030
+ before: body.after,
382031
+ after: body.before
382032
+ };
382033
+ }
381965
382034
 
381966
382035
  class APIBackend {
381967
382036
  capabilities = {
@@ -382033,7 +382102,7 @@ class APIBackend {
382033
382102
  }
382034
382103
  async listConversationMessages(conversationId, body, options3) {
382035
382104
  const client = await this.getClient();
382036
- return client.conversations.messages.list(conversationId, body, options3);
382105
+ return client.conversations.messages.list(conversationId, toApiConversationMessageListBody(body), options3);
382037
382106
  }
382038
382107
  async compactConversationMessages(conversationId, body, options3) {
382039
382108
  const client = await this.getClient();
@@ -382171,7 +382240,7 @@ async function configureDevBackend(name) {
382171
382240
  function __testSetBackend(nextBackend) {
382172
382241
  backend = nextBackend ?? createInitialBackend();
382173
382242
  }
382174
- var backend = null;
382243
+ var DEFAULT_CONVERSATION_MESSAGE_ORDER = "desc", backend = null;
382175
382244
  var init_backend = __esm(() => {
382176
382245
  init_backend_mode();
382177
382246
  init_local_backend();
@@ -382190,6 +382259,7 @@ __export(exports_backend, {
382190
382259
  configureDevBackend: () => configureDevBackend,
382191
382260
  configureBackendMode: () => configureBackendMode,
382192
382261
  __testSetBackend: () => __testSetBackend,
382262
+ DEFAULT_CONVERSATION_MESSAGE_ORDER: () => DEFAULT_CONVERSATION_MESSAGE_ORDER,
382193
382263
  APIBackend: () => APIBackend
382194
382264
  });
382195
382265
  var init_backend2 = __esm(() => {
@@ -423955,6 +424025,7 @@ var init_account_config2 = __esm(() => {
423955
424025
  "token",
423956
424026
  "agent_id",
423957
424027
  "allowed_channels",
424028
+ "allow_bots",
423958
424029
  "default_permission_mode",
423959
424030
  "transcribe_voice",
423960
424031
  "auto_thread_on_mention",
@@ -423970,7 +424041,7 @@ var init_account_config2 = __esm(() => {
423970
424041
  return false;
423971
424042
  }
423972
424043
  }
423973
- return (config3.token === undefined || isString2(config3.token)) && (config3.agent_id === undefined || isNullableString2(config3.agent_id)) && (config3.allowed_channels === undefined || isAllowedChannels(config3.allowed_channels)) && (config3.default_permission_mode === undefined || isDefaultPermissionMode(config3.default_permission_mode)) && (config3.transcribe_voice === undefined || isBoolean(config3.transcribe_voice)) && (config3.auto_thread_on_mention === undefined || isBoolean(config3.auto_thread_on_mention)) && (config3.thread_policy_by_channel === undefined || typeof config3.thread_policy_by_channel === "object" && !Array.isArray(config3.thread_policy_by_channel) && config3.thread_policy_by_channel !== null && Object.values(config3.thread_policy_by_channel).every((v2) => v2 === true || v2 === false)) && (config3.acknowledge_message_reaction === undefined || isBoolean(config3.acknowledge_message_reaction)) && (config3.remove_stale_routes === undefined || isBoolean(config3.remove_stale_routes)) && (config3.inbound_debounce_ms === undefined || typeof config3.inbound_debounce_ms === "number" && Number.isFinite(config3.inbound_debounce_ms) && config3.inbound_debounce_ms >= 0 && config3.inbound_debounce_ms <= 1e4);
424044
+ return (config3.token === undefined || isString2(config3.token)) && (config3.agent_id === undefined || isNullableString2(config3.agent_id)) && (config3.allowed_channels === undefined || isAllowedChannels(config3.allowed_channels)) && (config3.allow_bots === undefined || isValidDiscordAllowBotsConfigValue(config3.allow_bots)) && (config3.default_permission_mode === undefined || isDefaultPermissionMode(config3.default_permission_mode)) && (config3.transcribe_voice === undefined || isBoolean(config3.transcribe_voice)) && (config3.auto_thread_on_mention === undefined || isBoolean(config3.auto_thread_on_mention)) && (config3.thread_policy_by_channel === undefined || typeof config3.thread_policy_by_channel === "object" && !Array.isArray(config3.thread_policy_by_channel) && config3.thread_policy_by_channel !== null && Object.values(config3.thread_policy_by_channel).every((v2) => v2 === true || v2 === false)) && (config3.acknowledge_message_reaction === undefined || isBoolean(config3.acknowledge_message_reaction)) && (config3.remove_stale_routes === undefined || isBoolean(config3.remove_stale_routes)) && (config3.inbound_debounce_ms === undefined || typeof config3.inbound_debounce_ms === "number" && Number.isFinite(config3.inbound_debounce_ms) && config3.inbound_debounce_ms >= 0 && config3.inbound_debounce_ms <= 1e4);
423974
424045
  },
423975
424046
  toAccountPatch(config3) {
423976
424047
  const allowedChannels = isAllowedChannels(config3.allowed_channels) ? Array.isArray(config3.allowed_channels) ? [...config3.allowed_channels] : { ...config3.allowed_channels } : undefined;
@@ -423979,6 +424050,7 @@ var init_account_config2 = __esm(() => {
423979
424050
  agentId: isNullableString2(config3.agent_id) ? config3.agent_id : undefined,
423980
424051
  defaultPermissionMode: isDefaultPermissionMode(config3.default_permission_mode) ? migratePermissionMode(config3.default_permission_mode) : undefined,
423981
424052
  allowedChannels,
424053
+ allowBots: config3.allow_bots !== undefined && isValidDiscordAllowBotsConfigValue(config3.allow_bots) ? normalizeDiscordAllowBotsMode(config3.allow_bots) : undefined,
423982
424054
  transcribeVoice: isBoolean(config3.transcribe_voice) ? config3.transcribe_voice : undefined,
423983
424055
  autoThreadOnMention: isBoolean(config3.auto_thread_on_mention) ? config3.auto_thread_on_mention : undefined,
423984
424056
  threadPolicyByChannel: typeof config3.thread_policy_by_channel === "object" && !Array.isArray(config3.thread_policy_by_channel) ? { ...config3.thread_policy_by_channel } : undefined,
@@ -423993,6 +424065,7 @@ var init_account_config2 = __esm(() => {
423993
424065
  agent_id: account.agentId,
423994
424066
  default_permission_mode: account.defaultPermissionMode ?? "standard",
423995
424067
  allowed_channels: serializeAllowedChannels(account.allowedChannels),
424068
+ allow_bots: account.allowBots ?? false,
423996
424069
  transcribe_voice: account.transcribeVoice === true,
423997
424070
  auto_thread_on_mention: account.autoThreadOnMention ?? false,
423998
424071
  thread_policy_by_channel: account.threadPolicyByChannel ?? {},
@@ -424007,6 +424080,7 @@ var init_account_config2 = __esm(() => {
424007
424080
  agent_id: account.agentId,
424008
424081
  default_permission_mode: account.defaultPermissionMode ?? "standard",
424009
424082
  allowed_channels: serializeAllowedChannels(account.allowedChannels),
424083
+ allow_bots: account.allowBots ?? false,
424010
424084
  transcribe_voice: account.transcribeVoice === true,
424011
424085
  auto_thread_on_mention: account.autoThreadOnMention ?? false,
424012
424086
  thread_policy_by_channel: account.threadPolicyByChannel ?? {},
@@ -424572,6 +424646,7 @@ function createAccountFromPatch(channelId, accountId, patch2) {
424572
424646
  allowedChannels: normalizedPatch.allowedChannels ?? [],
424573
424647
  autoThreadOnMention: normalizedPatch.autoThreadOnMention ?? false,
424574
424648
  threadPolicyByChannel: normalizedPatch.threadPolicyByChannel,
424649
+ allowBots: normalizedPatch.allowBots ?? false,
424575
424650
  acknowledgeMessageReaction: normalizedPatch.acknowledgeMessageReaction,
424576
424651
  removeStaleRoutes: normalizedPatch.removeStaleRoutes,
424577
424652
  inboundDebounceMs: normalizedPatch.inboundDebounceMs,
@@ -424687,6 +424762,7 @@ function mergeAccountPatch(existing, patch2) {
424687
424762
  allowedChannels: normalizedPatch.allowedChannels ?? existing.allowedChannels,
424688
424763
  autoThreadOnMention: normalizedPatch.autoThreadOnMention ?? existing.autoThreadOnMention,
424689
424764
  threadPolicyByChannel: normalizedPatch.threadPolicyByChannel ?? existing.threadPolicyByChannel,
424765
+ allowBots: normalizedPatch.allowBots ?? existing.allowBots ?? false,
424690
424766
  acknowledgeMessageReaction: normalizedPatch.acknowledgeMessageReaction ?? existing.acknowledgeMessageReaction,
424691
424767
  removeStaleRoutes: normalizedPatch.removeStaleRoutes ?? existing.removeStaleRoutes,
424692
424768
  inboundDebounceMs: normalizedPatch.inboundDebounceMs ?? existing.inboundDebounceMs,
@@ -424852,6 +424928,7 @@ function toAccountSnapshot(account) {
424852
424928
  autoThreadOnMention: account.autoThreadOnMention ?? false,
424853
424929
  threadPolicyByChannel: account.threadPolicyByChannel ?? {},
424854
424930
  acknowledgeMessageReaction: account.acknowledgeMessageReaction ?? false,
424931
+ allowBots: account.allowBots ?? false,
424855
424932
  removeStaleRoutes: account.removeStaleRoutes ?? false,
424856
424933
  inboundDebounceMs: account.inboundDebounceMs,
424857
424934
  createdAt: account.createdAt,
@@ -425017,6 +425094,7 @@ function getChannelConfigSnapshot(channelId, accountId) {
425017
425094
  autoThreadOnMention: account.autoThreadOnMention ?? false,
425018
425095
  threadPolicyByChannel: account.threadPolicyByChannel ?? {},
425019
425096
  acknowledgeMessageReaction: account.acknowledgeMessageReaction ?? false,
425097
+ allowBots: account.allowBots ?? false,
425020
425098
  removeStaleRoutes: account.removeStaleRoutes ?? false,
425021
425099
  inboundDebounceMs: account.inboundDebounceMs
425022
425100
  };
@@ -446614,6 +446692,40 @@ function getPageItems(page) {
446614
446692
  }
446615
446693
  return [];
446616
446694
  }
446695
+ function messageId(message) {
446696
+ if (!message || typeof message !== "object")
446697
+ return null;
446698
+ const id2 = message.id;
446699
+ return typeof id2 === "string" && id2.length > 0 ? id2 : null;
446700
+ }
446701
+ async function listConversationMessagePage(backend3, conversationId, query2 = {}) {
446702
+ const normalizedQuery = query2 ?? {};
446703
+ const limit3 = normalizedQuery.limit ?? 50;
446704
+ const order = normalizedQuery.order ?? DEFAULT_CONVERSATION_MESSAGE_ORDER;
446705
+ const page = await backend3.listConversationMessages(conversationId, normalizedQuery);
446706
+ const untrimmedMessages = getPageItems(page);
446707
+ const messages = untrimmedMessages.slice(0, limit3);
446708
+ const oldestMessage = order === "asc" ? messages[0] : messages[messages.length - 1];
446709
+ const nextBefore = messageId(oldestMessage);
446710
+ if (!nextBefore || messages.length < limit3) {
446711
+ return { messages, nextBefore, hasMore: false };
446712
+ }
446713
+ if (untrimmedMessages.length > limit3) {
446714
+ return { messages, nextBefore, hasMore: true };
446715
+ }
446716
+ const probe2 = await backend3.listConversationMessages(conversationId, {
446717
+ ...normalizedQuery,
446718
+ after: undefined,
446719
+ before: nextBefore,
446720
+ order: "desc",
446721
+ limit: 1
446722
+ });
446723
+ return {
446724
+ messages,
446725
+ nextBefore,
446726
+ hasMore: getPageItems(probe2).length > 0
446727
+ };
446728
+ }
446617
446729
  async function handleAgentConversationManagementCommand(parsed, socket, safeSocketSend) {
446618
446730
  const backend3 = getBackend();
446619
446731
  if (parsed.type === "agent_list") {
@@ -446846,12 +446958,14 @@ async function handleAgentConversationManagementCommand(parsed, socket, safeSock
446846
446958
  }
446847
446959
  if (parsed.type === "conversation_messages_list") {
446848
446960
  try {
446849
- const page = await backend3.listConversationMessages(parsed.conversation_id, parsed.query);
446961
+ const page = await listConversationMessagePage(backend3, parsed.conversation_id, parsed.query);
446850
446962
  safeSocketSend(socket, {
446851
446963
  type: "conversation_messages_list_response",
446852
446964
  request_id: parsed.request_id,
446853
446965
  success: true,
446854
- messages: getPageItems(page)
446966
+ messages: page.messages,
446967
+ next_before: page.nextBefore,
446968
+ has_more: page.hasMore
446855
446969
  }, "listener_conversation_management_send_failed", "listener_conversation_management");
446856
446970
  } catch (error54) {
446857
446971
  safeSocketSend(socket, {
@@ -446859,6 +446973,8 @@ async function handleAgentConversationManagementCommand(parsed, socket, safeSock
446859
446973
  request_id: parsed.request_id,
446860
446974
  success: false,
446861
446975
  messages: [],
446976
+ next_before: null,
446977
+ has_more: false,
446862
446978
  error: getErrorMessage4(error54, "Failed to list conversation messages")
446863
446979
  }, "listener_conversation_management_send_failed", "listener_conversation_management");
446864
446980
  }
@@ -448795,7 +448911,7 @@ function normalizeCatalogSource(source2) {
448795
448911
  return source2.trim().replace(/\/+$/, "");
448796
448912
  }
448797
448913
  }
448798
- function isNonEmptyString8(value) {
448914
+ function isNonEmptyString9(value) {
448799
448915
  return typeof value === "string" && value.length > 0;
448800
448916
  }
448801
448917
  function isPositiveFiniteNumber(value) {
@@ -448816,13 +448932,13 @@ function isRecord9(value) {
448816
448932
  function hasEntryIdentity(entry) {
448817
448933
  if (!isRecord9(entry))
448818
448934
  return false;
448819
- return isNonEmptyString8(entry.id) && isNonEmptyString8(entry.handle) && isNonEmptyString8(entry.label);
448935
+ return isNonEmptyString9(entry.id) && isNonEmptyString9(entry.handle) && isNonEmptyString9(entry.label);
448820
448936
  }
448821
448937
  function isValidEntry(entry) {
448822
448938
  if (!hasEntryIdentity(entry))
448823
448939
  return false;
448824
448940
  const candidate = entry;
448825
- return isNonEmptyString8(candidate.brand) && isPositiveFiniteNumber(candidate.maxContextWindow) && isOptionalString(candidate.description) && isOptionalString(candidate.shortLabel) && isOptionalBoolean(candidate.isFeatured) && isOptionalBoolean(candidate.isDefault) && isOptionalBoolean(candidate.free) && isOptionalPositiveFiniteNumber(candidate.contextWindow) && isOptionalPositiveFiniteNumber(candidate.maxOutputTokens) && (candidate.config === undefined || isRecord9(candidate.config));
448941
+ return isNonEmptyString9(candidate.brand) && isPositiveFiniteNumber(candidate.maxContextWindow) && isOptionalString(candidate.description) && isOptionalString(candidate.shortLabel) && isOptionalBoolean(candidate.isFeatured) && isOptionalBoolean(candidate.isDefault) && isOptionalBoolean(candidate.free) && isOptionalPositiveFiniteNumber(candidate.contextWindow) && isOptionalPositiveFiniteNumber(candidate.maxOutputTokens) && (candidate.config === undefined || isRecord9(candidate.config));
448826
448942
  }
448827
448943
  function isValidCachedModel(entry) {
448828
448944
  if (!hasEntryIdentity(entry))
@@ -451479,11 +451595,11 @@ function hasExistingOtidAlias(aliasMap, canonical, nextOtid) {
451479
451595
  return false;
451480
451596
  }
451481
451597
  function resolveAssistantLineId(b3, chunk) {
451482
- const messageId = typeof chunk.id === "string" ? chunk.id : undefined;
451598
+ const messageId2 = typeof chunk.id === "string" ? chunk.id : undefined;
451483
451599
  const otid = typeof chunk.otid === "string" ? chunk.otid : undefined;
451484
- const canonicalFromMessageId = messageId ? b3.assistantCanonicalByMessageId.get(messageId) : undefined;
451600
+ const canonicalFromMessageId = messageId2 ? b3.assistantCanonicalByMessageId.get(messageId2) : undefined;
451485
451601
  const canonicalFromOtid = otid ? b3.assistantCanonicalByOtid.get(otid) : undefined;
451486
- let canonical = canonicalFromMessageId || canonicalFromOtid || messageId || otid;
451602
+ let canonical = canonicalFromMessageId || canonicalFromOtid || messageId2 || otid;
451487
451603
  if (!canonical)
451488
451604
  return;
451489
451605
  if (otid && !canonicalFromOtid && canonicalFromMessageId) {
@@ -451506,27 +451622,27 @@ function resolveAssistantLineId(b3, chunk) {
451506
451622
  }
451507
451623
  debugLog("accumulator", `Assistant id/otid alias conflict resolved to ${canonical}`);
451508
451624
  }
451509
- if (messageId) {
451510
- b3.assistantCanonicalByMessageId.set(messageId, canonical);
451625
+ if (messageId2) {
451626
+ b3.assistantCanonicalByMessageId.set(messageId2, canonical);
451511
451627
  }
451512
451628
  if (otid) {
451513
451629
  b3.assistantCanonicalByOtid.set(otid, canonical);
451514
451630
  }
451515
451631
  const lineId = resolveLineIdForKind(b3, canonical, "assistant");
451516
451632
  if (lineId !== canonical) {
451517
- if (messageId)
451518
- b3.assistantCanonicalByMessageId.set(messageId, lineId);
451633
+ if (messageId2)
451634
+ b3.assistantCanonicalByMessageId.set(messageId2, lineId);
451519
451635
  if (otid)
451520
451636
  b3.assistantCanonicalByOtid.set(otid, lineId);
451521
451637
  }
451522
451638
  return lineId;
451523
451639
  }
451524
451640
  function resolveReasoningLineId(b3, chunk) {
451525
- const messageId = typeof chunk.id === "string" ? chunk.id : undefined;
451641
+ const messageId2 = typeof chunk.id === "string" ? chunk.id : undefined;
451526
451642
  const otid = typeof chunk.otid === "string" ? chunk.otid : undefined;
451527
- const canonicalFromMessageId = messageId ? b3.reasoningCanonicalByMessageId.get(messageId) : undefined;
451643
+ const canonicalFromMessageId = messageId2 ? b3.reasoningCanonicalByMessageId.get(messageId2) : undefined;
451528
451644
  const canonicalFromOtid = otid ? b3.reasoningCanonicalByOtid.get(otid) : undefined;
451529
- let canonical = canonicalFromMessageId || canonicalFromOtid || messageId || otid;
451645
+ let canonical = canonicalFromMessageId || canonicalFromOtid || messageId2 || otid;
451530
451646
  if (!canonical)
451531
451647
  return;
451532
451648
  if (otid && !canonicalFromOtid && canonicalFromMessageId) {
@@ -451549,16 +451665,16 @@ function resolveReasoningLineId(b3, chunk) {
451549
451665
  }
451550
451666
  debugLog("accumulator", `Reasoning id/otid alias conflict resolved to ${canonical}`);
451551
451667
  }
451552
- if (messageId) {
451553
- b3.reasoningCanonicalByMessageId.set(messageId, canonical);
451668
+ if (messageId2) {
451669
+ b3.reasoningCanonicalByMessageId.set(messageId2, canonical);
451554
451670
  }
451555
451671
  if (otid) {
451556
451672
  b3.reasoningCanonicalByOtid.set(otid, canonical);
451557
451673
  }
451558
451674
  const lineId = resolveLineIdForKind(b3, canonical, "reasoning");
451559
451675
  if (lineId !== canonical) {
451560
- if (messageId)
451561
- b3.reasoningCanonicalByMessageId.set(messageId, lineId);
451676
+ if (messageId2)
451677
+ b3.reasoningCanonicalByMessageId.set(messageId2, lineId);
451562
451678
  if (otid)
451563
451679
  b3.reasoningCanonicalByOtid.set(otid, lineId);
451564
451680
  }
@@ -451616,13 +451732,13 @@ function onChunk(b3, chunk, ctx) {
451616
451732
  }
451617
451733
  handleOtidTransition(b3, id2);
451618
451734
  const delta2 = chunk.reasoning;
451619
- const messageId = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451735
+ const messageId2 = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451620
451736
  const line = ensure(b3, id2, () => ({
451621
451737
  kind: "reasoning",
451622
451738
  id: id2,
451623
451739
  text: "",
451624
451740
  phase: "streaming",
451625
- messageId
451741
+ messageId: messageId2
451626
451742
  }));
451627
451743
  if (delta2) {
451628
451744
  const newText = normalizeReasoningSectionBoundaries(line.text + delta2);
@@ -451631,11 +451747,11 @@ function onChunk(b3, chunk, ctx) {
451631
451747
  b3.byId.set(id2, {
451632
451748
  ...line,
451633
451749
  text: newText,
451634
- messageId: messageId ?? line.messageId
451750
+ messageId: messageId2 ?? line.messageId
451635
451751
  });
451636
451752
  }
451637
- } else if (messageId && line.messageId !== messageId) {
451638
- b3.byId.set(id2, { ...line, messageId });
451753
+ } else if (messageId2 && line.messageId !== messageId2) {
451754
+ b3.byId.set(id2, { ...line, messageId: messageId2 });
451639
451755
  }
451640
451756
  break;
451641
451757
  }
@@ -451646,13 +451762,13 @@ function onChunk(b3, chunk, ctx) {
451646
451762
  break;
451647
451763
  handleOtidTransition(b3, id2);
451648
451764
  const delta2 = extractTextPart(chunk.content);
451649
- const messageId = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451765
+ const messageId2 = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451650
451766
  const line = ensure(b3, id2, () => ({
451651
451767
  kind: "assistant",
451652
451768
  id: id2,
451653
451769
  text: "",
451654
451770
  phase: "streaming",
451655
- messageId
451771
+ messageId: messageId2
451656
451772
  }));
451657
451773
  if (delta2) {
451658
451774
  const newText = line.text + delta2;
@@ -451661,20 +451777,20 @@ function onChunk(b3, chunk, ctx) {
451661
451777
  b3.byId.set(id2, {
451662
451778
  ...line,
451663
451779
  text: newText,
451664
- messageId: messageId ?? line.messageId
451780
+ messageId: messageId2 ?? line.messageId
451665
451781
  });
451666
451782
  }
451667
- } else if (messageId && line.messageId !== messageId) {
451668
- b3.byId.set(id2, { ...line, messageId });
451783
+ } else if (messageId2 && line.messageId !== messageId2) {
451784
+ b3.byId.set(id2, { ...line, messageId: messageId2 });
451669
451785
  }
451670
451786
  break;
451671
451787
  }
451672
451788
  case "user_message": {
451673
451789
  const chunkWithIds = chunk;
451674
- const messageId = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451790
+ const messageId2 = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451675
451791
  const otid = typeof chunkWithIds.otid === "string" ? chunkWithIds.otid : undefined;
451676
451792
  const mappedLineId = otid ? b3.userLineIdByOtid.get(otid) : undefined;
451677
- const lineId = mappedLineId || otid || messageId;
451793
+ const lineId = mappedLineId || otid || messageId2;
451678
451794
  if (!lineId)
451679
451795
  break;
451680
451796
  handleOtidTransition(b3, lineId);
@@ -451698,14 +451814,14 @@ function onChunk(b3, chunk, ctx) {
451698
451814
  kind: "user",
451699
451815
  id: lineId,
451700
451816
  text: rawText,
451701
- messageId,
451817
+ messageId: messageId2,
451702
451818
  otid
451703
451819
  }));
451704
451820
  if (line.kind === "user") {
451705
451821
  b3.byId.set(lineId, {
451706
451822
  ...line,
451707
451823
  text: line.text || rawText,
451708
- messageId: messageId ?? line.messageId,
451824
+ messageId: messageId2 ?? line.messageId,
451709
451825
  otid: otid ?? line.otid
451710
451826
  });
451711
451827
  }
@@ -541317,4 +541433,4 @@ function registerBunOAuthFlows() {
541317
541433
  registerBunOAuthFlows();
541318
541434
  await init_src5().then(() => exports_src2);
541319
541435
 
541320
- //# debugId=E5837E6C26403C1164756E2164756E21
541436
+ //# debugId=EDD0BAA906B8C7B064756E2164756E21