@letta-ai/letta-code 0.29.4 → 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.
Files changed (30) hide show
  1. package/dist/memory-confinement.js +363 -0
  2. package/dist/memory-confinement.js.map +18 -0
  3. package/dist/types/channels/plugin-types.d.ts +2 -2
  4. package/dist/types/channels/plugin-types.d.ts.map +1 -1
  5. package/dist/types/channels/types.d.ts +15 -1
  6. package/dist/types/channels/types.d.ts.map +1 -1
  7. package/dist/types/memory-confinement.d.ts +13 -0
  8. package/dist/types/memory-confinement.d.ts.map +1 -0
  9. package/dist/types/permissions/memory-confinement-launcher.d.ts +20 -0
  10. package/dist/types/permissions/memory-confinement-launcher.d.ts.map +1 -0
  11. package/dist/types/permissions/sandbox-policy.d.ts +138 -0
  12. package/dist/types/permissions/sandbox-policy.d.ts.map +1 -0
  13. package/dist/types/sandbox/availability.d.ts +60 -0
  14. package/dist/types/sandbox/availability.d.ts.map +1 -0
  15. package/dist/types/sandbox/bwrap.d.ts +36 -0
  16. package/dist/types/sandbox/bwrap.d.ts.map +1 -0
  17. package/dist/types/sandbox/policy.d.ts +79 -0
  18. package/dist/types/sandbox/policy.d.ts.map +1 -0
  19. package/dist/types/sandbox/seatbelt.d.ts +39 -0
  20. package/dist/types/sandbox/seatbelt.d.ts.map +1 -0
  21. package/dist/types/sandbox/wrap.d.ts +18 -0
  22. package/dist/types/sandbox/wrap.d.ts.map +1 -0
  23. package/dist/types/types/protocol_v2.d.ts +2 -0
  24. package/dist/types/types/protocol_v2.d.ts.map +1 -1
  25. package/dist/types/utils/local-backend-paths.d.ts +23 -0
  26. package/dist/types/utils/local-backend-paths.d.ts.map +1 -0
  27. package/letta.js +523 -387
  28. package/package.json +11 -1
  29. package/scripts/isolated-unit-tests.json +5 -0
  30. package/scripts/source-file-size-baseline.json +5 -5
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.4",
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
  ],
@@ -127383,6 +127393,9 @@ function validatePiProviderRegistration(providerName, config3) {
127383
127393
  }
127384
127394
 
127385
127395
  // src/backend/dev/pi-provider-mod-registry.ts
127396
+ function getPiProviderRegistryRevision() {
127397
+ return revisionCounter;
127398
+ }
127386
127399
  function bumpProviderRevision(providerName) {
127387
127400
  revisionCounter += 1;
127388
127401
  providerRevisions.set(providerName, revisionCounter);
@@ -145935,6 +145948,32 @@ var init_mode = __esm(() => {
145935
145948
  permissionMode = new PermissionModeManager;
145936
145949
  });
145937
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
+
145938
145977
  // src/channels/slack/bot-policy.ts
145939
145978
  function isValidSlackAllowBotsConfigValue(value) {
145940
145979
  return value === undefined || value === false || value === "mentions";
@@ -145949,14 +145988,14 @@ function resolveSlackAllowBotsMode(value) {
145949
145988
  return "mentions";
145950
145989
  return "off";
145951
145990
  }
145952
- function isNonEmptyString(value) {
145991
+ function isNonEmptyString2(value) {
145953
145992
  return typeof value === "string" && value.length > 0;
145954
145993
  }
145955
145994
  function isSlackBotAuthoredInboundMessage(message) {
145956
- return isNonEmptyString(message.bot_id) || message.subtype === "bot_message";
145995
+ return isNonEmptyString2(message.bot_id) || message.subtype === "bot_message";
145957
145996
  }
145958
145997
  function isOwnSlackBotInboundMessage(params) {
145959
- 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;
145960
145999
  }
145961
146000
  function shouldAcceptSlackInboundBotMessage(params) {
145962
146001
  if (isOwnSlackBotInboundMessage({
@@ -146122,6 +146161,9 @@ var init_config2 = __esm(() => {
146122
146161
  };
146123
146162
  discordConfigCodec = {
146124
146163
  parse(parsed) {
146164
+ if (!isValidDiscordAllowBotsConfigValue(parsed.allow_bots)) {
146165
+ throw new Error("Invalid Discord allow_bots config");
146166
+ }
146125
146167
  const rawAllowedChannels = parsed.allowed_channels;
146126
146168
  let allowedChannels;
146127
146169
  if (Array.isArray(rawAllowedChannels)) {
@@ -146137,6 +146179,7 @@ var init_config2 = __esm(() => {
146137
146179
  dmPolicy: parsed.dm_policy ?? "pairing",
146138
146180
  allowedUsers: parsed.allowed_users ?? [],
146139
146181
  allowedChannels,
146182
+ allowBots: normalizeDiscordAllowBotsMode(parsed.allow_bots),
146140
146183
  transcribeVoice: parsed.transcribe_voice === true,
146141
146184
  autoThreadOnMention: typeof parsed.auto_thread_on_mention === "boolean" ? parsed.auto_thread_on_mention : undefined,
146142
146185
  threadPolicyByChannel: typeof parsed.thread_policy_by_channel === "object" && !Array.isArray(parsed.thread_policy_by_channel) ? parsed.thread_policy_by_channel : undefined,
@@ -146370,7 +146413,7 @@ var init_plugin = __esm(() => {
146370
146413
  });
146371
146414
 
146372
146415
  // src/channels/schema-config.ts
146373
- function isNonEmptyString2(value) {
146416
+ function isNonEmptyString3(value) {
146374
146417
  return typeof value === "string" && value.length > 0;
146375
146418
  }
146376
146419
  function parseSelectOptions(value) {
@@ -146383,7 +146426,7 @@ function parseSelectOptions(value) {
146383
146426
  if (!isRecord(entry)) {
146384
146427
  return null;
146385
146428
  }
146386
- if (!isNonEmptyString2(entry.value) || !isNonEmptyString2(entry.label)) {
146429
+ if (!isNonEmptyString3(entry.value) || !isNonEmptyString3(entry.label)) {
146387
146430
  return null;
146388
146431
  }
146389
146432
  if (seen.has(entry.value)) {
@@ -146402,10 +146445,10 @@ function parseField(value) {
146402
146445
  if (typeof type3 !== "string" || !FIELD_TYPES.has(type3)) {
146403
146446
  return null;
146404
146447
  }
146405
- if (!isNonEmptyString2(value.key) || !FIELD_KEY_PATTERN.test(value.key)) {
146448
+ if (!isNonEmptyString3(value.key) || !FIELD_KEY_PATTERN.test(value.key)) {
146406
146449
  return null;
146407
146450
  }
146408
- if (!isNonEmptyString2(value.label)) {
146451
+ if (!isNonEmptyString3(value.label)) {
146409
146452
  return null;
146410
146453
  }
146411
146454
  if (value.description !== undefined && typeof value.description !== "string") {
@@ -148127,11 +148170,7 @@ function resolveTelegramInputFileConstructor(mod) {
148127
148170
  return InputFile;
148128
148171
  }
148129
148172
  function resolveTelegramOutboundThreadId(msg) {
148130
- const threadId = msg.threadId?.trim();
148131
- if (!threadId) {
148132
- return null;
148133
- }
148134
- return msg.chatId.trim().startsWith("-") ? threadId : null;
148173
+ return msg.threadId?.trim() || null;
148135
148174
  }
148136
148175
  function buildTelegramReplyOptions(msg) {
148137
148176
  const options3 = {};
@@ -149405,7 +149444,7 @@ function createTelegramAdapter(config3) {
149405
149444
  }
149406
149445
  const telegramBot = await ensureBot();
149407
149446
  const threadId = resolveTelegramOutboundThreadId(source2);
149408
- const replyToMessageId = threadId ?? source2.messageId;
149447
+ const replyToMessageId = source2.messageId;
149409
149448
  let reply_parameters;
149410
149449
  if (replyToMessageId) {
149411
149450
  const numericReplyToMessageId = Number(replyToMessageId);
@@ -149579,10 +149618,16 @@ function createTelegramAdapter(config3) {
149579
149618
  },
149580
149619
  async sendDirectReply(chatId, text, options3) {
149581
149620
  const telegramBot = await ensureBot();
149621
+ const threadId = resolveTelegramOutboundThreadId({
149622
+ threadId: options3?.threadId
149623
+ });
149582
149624
  const reply_parameters = options3?.replyToMessageId ? {
149583
149625
  message_id: Number(options3.replyToMessageId)
149584
149626
  } : undefined;
149585
- 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
+ });
149586
149631
  },
149587
149632
  async handleTurnLifecycleEvent(event2) {
149588
149633
  if (!running)
@@ -149621,7 +149666,7 @@ function createTelegramAdapter(config3) {
149621
149666
  async handleControlRequestEvent(event2) {
149622
149667
  const telegramBot = await ensureBot();
149623
149668
  const threadId = resolveTelegramOutboundThreadId(event2.source);
149624
- const replyToMessageId = threadId ?? event2.source.messageId;
149669
+ const replyToMessageId = event2.source.messageId;
149625
149670
  const reply_parameters = replyToMessageId ? { message_id: Number(replyToMessageId) } : undefined;
149626
149671
  await telegramBot.api.sendMessage(event2.source.chatId, formatChannelControlRequestPrompt(event2), {
149627
149672
  ...threadId ? { message_thread_id: Number(threadId) } : {},
@@ -149898,6 +149943,7 @@ function normalizeLoadedAccount(account) {
149898
149943
  if (isDiscordChannelAccount(next)) {
149899
149944
  const migrated = migratePermissionMode(next.defaultPermissionMode ?? "standard");
149900
149945
  next.defaultPermissionMode = migrated ?? "standard";
149946
+ next.allowBots = normalizeDiscordAllowBotsMode(next.allowBots);
149901
149947
  if (!("auto_thread_on_mention" in raw) && !("autoThreadOnMention" in raw)) {
149902
149948
  next.autoThreadOnMention = true;
149903
149949
  }
@@ -149960,6 +150006,7 @@ function makeDefaultLegacyAccount(channelId) {
149960
150006
  allowedChannels: config3.allowedChannels ? Array.isArray(config3.allowedChannels) ? [...config3.allowedChannels] : { ...config3.allowedChannels } : undefined,
149961
150007
  autoThreadOnMention: config3.autoThreadOnMention ?? true,
149962
150008
  threadPolicyByChannel: config3.threadPolicyByChannel,
150009
+ allowBots: config3.allowBots ?? false,
149963
150010
  agentId: null,
149964
150011
  defaultPermissionMode: config3.defaultPermissionMode ?? "standard",
149965
150012
  createdAt: now,
@@ -150246,15 +150293,18 @@ function shouldSendTelegramRichMessage(params) {
150246
150293
  return params.request.action === "send" && params.route.chatType === "direct" && richPrivateChatDefaultEnabled(params.route) && !params.request.mediaPath?.trim();
150247
150294
  }
150248
150295
  function resolveTelegramRouteThreadId(ctx) {
150249
- const threadId = ctx.request.threadId ?? ctx.route.threadId ?? null;
150250
- const trimmed = threadId?.trim();
150251
- if (!trimmed) {
150252
- return null;
150296
+ const requestThreadId = ctx.request.threadId?.trim();
150297
+ if (requestThreadId) {
150298
+ return requestThreadId;
150253
150299
  }
150254
150300
  if (ctx.route.chatType === "direct") {
150255
150301
  return null;
150256
150302
  }
150257
- 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;
150258
150308
  }
150259
150309
  var telegramMessageActions;
150260
150310
  var init_message_actions = __esm(() => {
@@ -150508,11 +150558,11 @@ function resolveSlackAppConstructor(mod) {
150508
150558
  }
150509
150559
  return App;
150510
150560
  }
150511
- function isNonEmptyString3(value) {
150561
+ function isNonEmptyString4(value) {
150512
150562
  return typeof value === "string" && value.length > 0;
150513
150563
  }
150514
150564
  function firstNonEmptyString(...values2) {
150515
- return values2.find(isNonEmptyString3);
150565
+ return values2.find(isNonEmptyString4);
150516
150566
  }
150517
150567
  function asRecord2(value) {
150518
150568
  return value && typeof value === "object" ? value : null;
@@ -150590,7 +150640,7 @@ function resolveSlackUserDisplayName(userInfo) {
150590
150640
  return firstNonEmptyString(profile?.display_name, profile?.real_name, user?.name);
150591
150641
  }
150592
150642
  function isSlackFlatChannelThreadOpener(source2) {
150593
- 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);
150594
150644
  }
150595
150645
  var IGNORED_SLACK_MESSAGE_SUBTYPES, WRAPPER_SLACK_MESSAGE_SUBTYPES;
150596
150646
  var init_utils5 = __esm(() => {
@@ -150637,7 +150687,7 @@ async function resolveSlackAccountDisplayName(botToken, appToken) {
150637
150687
  socketMode: true
150638
150688
  });
150639
150689
  const auth = await app.client.auth.test({ token: botToken });
150640
- if (isNonEmptyString3(auth.user_id)) {
150690
+ if (isNonEmptyString4(auth.user_id)) {
150641
150691
  try {
150642
150692
  const userInfo = await app.client.users.info({
150643
150693
  token: botToken,
@@ -150649,7 +150699,7 @@ async function resolveSlackAccountDisplayName(botToken, appToken) {
150649
150699
  }
150650
150700
  } catch {}
150651
150701
  }
150652
- return isNonEmptyString3(auth.user) ? auth.user : undefined;
150702
+ return isNonEmptyString4(auth.user) ? auth.user : undefined;
150653
150703
  }
150654
150704
  var init_account_display2 = __esm(() => {
150655
150705
  init_runtime2();
@@ -151350,7 +151400,7 @@ var init_feedback2 = __esm(() => {
151350
151400
  init_plugin_registry();
151351
151401
  });
151352
151402
 
151353
- // src/channels/commands.ts
151403
+ // src/channels/registry-presentation.ts
151354
151404
  function channelDisplayName3(channelId) {
151355
151405
  try {
151356
151406
  return getChannelDisplayName(channelId);
@@ -151358,6 +151408,168 @@ function channelDisplayName3(channelId) {
151358
151408
  return channelId;
151359
151409
  }
151360
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
+ }
151361
151573
  function listChannelSlashCommands() {
151362
151574
  return CHANNEL_SLASH_COMMANDS.map((definition) => ({
151363
151575
  ...definition,
@@ -151434,7 +151646,7 @@ function isSlackMentionControlCommand(msg, command) {
151434
151646
  return command.raw.startsWith("!") || isSlackMentionSlashCommand(msg, command);
151435
151647
  }
151436
151648
  function buildChannelHelpMessage(channelId) {
151437
- const displayName = channelDisplayName3(channelId);
151649
+ const displayName = channelDisplayName4(channelId);
151438
151650
  if (channelId === "slack") {
151439
151651
  return [
151440
151652
  `${displayName} is connected to Letta Code.`,
@@ -151466,7 +151678,7 @@ function buildChannelHelpMessage(channelId) {
151466
151678
  `);
151467
151679
  }
151468
151680
  function buildUnsupportedChannelCommandMessage(channelId, command) {
151469
- const displayName = channelDisplayName3(channelId);
151681
+ const displayName = channelDisplayName4(channelId);
151470
151682
  const isBang = command.raw.startsWith("!");
151471
151683
  const commandKind = isBang ? "bang" : "slash";
151472
151684
  const supportedCommands = isBang ? supportedBangCommandsText() : channelId === "slack" ? supportedSlackMentionSlashCommandsText() : supportedCommandsText();
@@ -151480,7 +151692,7 @@ function buildUnsupportedChannelCommandMessage(channelId, command) {
151480
151692
  `);
151481
151693
  }
151482
151694
  function buildChannelStatusMessage(msg, context3) {
151483
- const displayName = channelDisplayName3(msg.channel);
151695
+ const displayName = channelDisplayName4(msg.channel);
151484
151696
  const route = context3.route;
151485
151697
  const routeStatus = route ? "Connected to a Letta agent conversation." : "No route is connected for this chat yet.";
151486
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.";
@@ -151508,7 +151720,7 @@ function buildChannelStatusMessage(msg, context3) {
151508
151720
  `);
151509
151721
  }
151510
151722
  function buildChannelNoRouteMessage(channelId) {
151511
- const displayName = channelDisplayName3(channelId);
151723
+ const displayName = channelDisplayName4(channelId);
151512
151724
  return [
151513
151725
  `${displayName} could not find an existing route for this chat.`,
151514
151726
  "Send a normal message first and follow the pairing instructions, then try again."
@@ -151517,23 +151729,23 @@ function buildChannelNoRouteMessage(channelId) {
151517
151729
  `);
151518
151730
  }
151519
151731
  function buildChannelPausedMessage(channelId, route) {
151520
- const displayName = channelDisplayName3(channelId);
151732
+ const displayName = channelDisplayName4(channelId);
151521
151733
  const conversation = route.conversationId ? ` Conversation: ${route.conversationId}.` : "";
151522
151734
  return `${displayName} paused agent routing for this chat.${conversation} Send /resume here to turn replies back on.`;
151523
151735
  }
151524
151736
  function buildChannelAlreadyPausedMessage(channelId) {
151525
- 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.`;
151526
151738
  }
151527
151739
  function buildChannelResumedMessage(channelId, route) {
151528
- const displayName = channelDisplayName3(channelId);
151740
+ const displayName = channelDisplayName4(channelId);
151529
151741
  const conversation = route.conversationId ? ` Conversation: ${route.conversationId}.` : "";
151530
151742
  return `${displayName} resumed agent routing for this chat.${conversation} Normal messages here will go to the connected agent again.`;
151531
151743
  }
151532
151744
  function buildChannelAlreadyActiveMessage(channelId) {
151533
- return `${channelDisplayName3(channelId)} agent routing is already active for this chat.`;
151745
+ return `${channelDisplayName4(channelId)} agent routing is already active for this chat.`;
151534
151746
  }
151535
151747
  function buildChannelCancelUnavailableMessage(channelId) {
151536
- const displayName = channelDisplayName3(channelId);
151748
+ const displayName = channelDisplayName4(channelId);
151537
151749
  return [
151538
151750
  `${displayName} received /cancel, but this chat is not connected to an active Letta Code conversation yet.`,
151539
151751
  "Send a normal message first to connect this chat to an agent."
@@ -151542,15 +151754,15 @@ function buildChannelCancelUnavailableMessage(channelId) {
151542
151754
  `);
151543
151755
  }
151544
151756
  function buildChannelCancelNoActiveTurnMessage(channelId) {
151545
- const displayName = channelDisplayName3(channelId);
151757
+ const displayName = channelDisplayName4(channelId);
151546
151758
  return `${displayName} received /cancel, but there is no in-progress agent turn to cancel for this chat.`;
151547
151759
  }
151548
151760
  function buildChannelCancelAcceptedMessage(channelId) {
151549
- const displayName = channelDisplayName3(channelId);
151761
+ const displayName = channelDisplayName4(channelId);
151550
151762
  return `${displayName} cancelled the in-progress agent turn for this chat.`;
151551
151763
  }
151552
151764
  function buildChannelChatLinkMessage(channelId, route, chatUrl) {
151553
- const displayName = channelDisplayName3(channelId);
151765
+ const displayName = channelDisplayName4(channelId);
151554
151766
  return [
151555
151767
  `${displayName} chat for this route: ${chatUrl}`,
151556
151768
  `Agent: ${route.agentId}.`,
@@ -151559,27 +151771,27 @@ function buildChannelChatLinkMessage(channelId, route, chatUrl) {
151559
151771
  `);
151560
151772
  }
151561
151773
  function buildChannelChatUnavailableMessage(channelId, route) {
151562
- const displayName = channelDisplayName3(channelId);
151774
+ const displayName = channelDisplayName4(channelId);
151563
151775
  return `${displayName} chat UI is not available for local backend agent ${route.agentId}.`;
151564
151776
  }
151565
151777
  function buildChannelDetachUnsupportedMessage(channelId) {
151566
- const displayName = channelDisplayName3(channelId);
151778
+ const displayName = channelDisplayName4(channelId);
151567
151779
  return `${displayName} can only detach Slack channel threads.`;
151568
151780
  }
151569
151781
  function buildChannelDetachedMessage(channelId) {
151570
- const displayName = channelDisplayName3(channelId);
151782
+ const displayName = channelDisplayName4(channelId);
151571
151783
  return `${displayName} detached this thread. I will ignore follow-up replies here until someone mentions the app again.`;
151572
151784
  }
151573
151785
  function buildChannelAlreadyDetachedMessage(channelId) {
151574
- const displayName = channelDisplayName3(channelId);
151786
+ const displayName = channelDisplayName4(channelId);
151575
151787
  return `${displayName} is already detached from this thread. Mention the app again to reattach.`;
151576
151788
  }
151577
151789
  function buildChannelNewConversationMessage(channelId, route) {
151578
- const displayName = channelDisplayName3(channelId);
151790
+ const displayName = channelDisplayName4(channelId);
151579
151791
  return `${displayName} started a new conversation for this chat. Conversation: ${route.conversationId}.`;
151580
151792
  }
151581
151793
  function buildChannelNewConversationUnavailableMessage(channelId) {
151582
- const displayName = channelDisplayName3(channelId);
151794
+ const displayName = channelDisplayName4(channelId);
151583
151795
  return `${displayName} cannot start a new conversation for this chat because no agent is configured.`;
151584
151796
  }
151585
151797
  function getModelEntryRank(entry) {
@@ -151638,7 +151850,7 @@ function buildChannelModelNotFoundText(channelId) {
151638
151850
  return `Model not found. Use ${modelCommandPrefix(channelId)} list to see available models.`;
151639
151851
  }
151640
151852
  function buildChannelCurrentModelMessage(channelId, params) {
151641
- const displayName = channelDisplayName3(channelId);
151853
+ const displayName = channelDisplayName4(channelId);
151642
151854
  const scope = params.scope === "agent" ? "agent" : "conversation";
151643
151855
  const handleText = params.modelHandle && params.modelHandle !== params.modelLabel ? ` (${params.modelHandle})` : "";
151644
151856
  const switchCommand = modelCommandPrefix(channelId);
@@ -151666,7 +151878,7 @@ function appendModelEntrySection(lines, channelId, title, entries, limit3) {
151666
151878
  }
151667
151879
  }
151668
151880
  function buildChannelModelListMessage(channelId, params) {
151669
- const displayName = channelDisplayName3(channelId);
151881
+ const displayName = channelDisplayName4(channelId);
151670
151882
  const limit3 = params.limit ?? DEFAULT_CHANNEL_MODEL_LIST_LIMIT;
151671
151883
  const entries = params.entries;
151672
151884
  const byHandle = buildModelEntriesByHandle(entries);
@@ -151699,33 +151911,33 @@ function buildChannelModelListMessage(channelId, params) {
151699
151911
  `);
151700
151912
  }
151701
151913
  function buildChannelModelListUnavailableMessage(channelId, error54) {
151702
- const displayName = channelDisplayName3(channelId);
151914
+ const displayName = channelDisplayName4(channelId);
151703
151915
  return `${displayName} could not load the model list: ${error54}`;
151704
151916
  }
151705
151917
  function buildChannelCurrentModelUnavailableMessage(channelId, error54) {
151706
- const displayName = channelDisplayName3(channelId);
151918
+ const displayName = channelDisplayName4(channelId);
151707
151919
  return `${displayName} could not load the current model: ${error54}`;
151708
151920
  }
151709
151921
  function buildChannelModelUpdatedMessage(channelId, params) {
151710
- const displayName = channelDisplayName3(channelId);
151922
+ const displayName = channelDisplayName4(channelId);
151711
151923
  const scope = params.appliedTo === "agent" ? "agent" : "conversation";
151712
151924
  const handleText = params.modelHandle === params.modelLabel ? "" : ` (${params.modelHandle})`;
151713
151925
  return `${displayName} updated this ${scope}'s model to ${params.modelLabel}${handleText}.`;
151714
151926
  }
151715
151927
  function buildChannelModelUpdateFailedMessage(channelId, identifier2, error54) {
151716
- const displayName = channelDisplayName3(channelId);
151928
+ const displayName = channelDisplayName4(channelId);
151717
151929
  return `${displayName} could not switch this chat's routed model to ${identifier2}: ${error54}`;
151718
151930
  }
151719
151931
  function buildChannelModelUnavailableMessage(channelId) {
151720
- const displayName = channelDisplayName3(channelId);
151932
+ const displayName = channelDisplayName4(channelId);
151721
151933
  return `${displayName} cannot use /model because the listener is not ready yet. Try again in a moment.`;
151722
151934
  }
151723
151935
  function buildChannelReflectionUnavailableMessage(channelId) {
151724
- const displayName = channelDisplayName3(channelId);
151936
+ const displayName = channelDisplayName4(channelId);
151725
151937
  return `${displayName} cannot start reflection for this chat because the listener is not ready yet. Try again in a moment.`;
151726
151938
  }
151727
151939
  function buildChannelReloadUnavailableMessage(channelId) {
151728
- const displayName = channelDisplayName3(channelId);
151940
+ const displayName = channelDisplayName4(channelId);
151729
151941
  return `${displayName} cannot reload listener settings for this chat because the listener is not ready yet. Try again in a moment.`;
151730
151942
  }
151731
151943
  async function handleScopedCommand(params) {
@@ -151759,12 +151971,12 @@ async function tryHandleChannelSlashCommand(adapter, msg, options3 = {}) {
151759
151971
  const isBangCommand = command.raw.startsWith("!");
151760
151972
  const isSlackMentionControl = isSlackMentionControlCommand(msg, command);
151761
151973
  if (isBangCommand && !isSupportedSlackMentionCommand(command.name)) {
151762
- 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));
151763
151975
  return true;
151764
151976
  }
151765
151977
  const canonicalName = canonicalizeChannelCommandName(command.name);
151766
151978
  if (options3.commandGate && !canRunChannelCommand(options3.commandGate, canonicalName)) {
151767
- 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));
151768
151980
  return true;
151769
151981
  }
151770
151982
  const reply = normalizeDirectReplyPayload(await (async () => {
@@ -151869,6 +152081,7 @@ var init_commands = __esm(() => {
151869
152081
  init_access_control();
151870
152082
  init_feedback2();
151871
152083
  init_plugin_registry();
152084
+ init_registry_presentation();
151872
152085
  CHANNEL_SLASH_COMMANDS = [
151873
152086
  {
151874
152087
  name: "help",
@@ -152522,11 +152735,11 @@ var init_progress_formatting = __esm(() => {
152522
152735
  });
152523
152736
 
152524
152737
  // src/channels/slack/public-utils.ts
152525
- function isNonEmptyString4(value) {
152738
+ function isNonEmptyString5(value) {
152526
152739
  return typeof value === "string" && value.length > 0;
152527
152740
  }
152528
152741
  function firstNonEmptyString3(...values2) {
152529
- return values2.find(isNonEmptyString4);
152742
+ return values2.find(isNonEmptyString5);
152530
152743
  }
152531
152744
  function normalizeSlackText(text) {
152532
152745
  return text.replace(/^(?:\s*<@[A-Z0-9]+>\s*)+/, "").trim();
@@ -152562,14 +152775,14 @@ function formatSlackToolNameForDisplay(toolName) {
152562
152775
  return toolName;
152563
152776
  }
152564
152777
  function resolveSlackConcreteActivity(event2) {
152565
- if (event2.kind === "command" && isNonEmptyString4(event2.command)) {
152778
+ if (event2.kind === "command" && isNonEmptyString5(event2.command)) {
152566
152779
  return sanitizeSlackStatusText(formatSlackToolNameForDisplay(event2.command), SLACK_STATUS_TEXT_MAX);
152567
152780
  }
152568
- if (event2.kind !== "tool" || !isNonEmptyString4(event2.toolName) || event2.toolName.toLowerCase() === "messagechannel") {
152781
+ if (event2.kind !== "tool" || !isNonEmptyString5(event2.toolName) || event2.toolName.toLowerCase() === "messagechannel") {
152569
152782
  return null;
152570
152783
  }
152571
152784
  for (const description of [event2.toolTitle, event2.toolDetails]) {
152572
- if (!isNonEmptyString4(description)) {
152785
+ if (!isNonEmptyString5(description)) {
152573
152786
  continue;
152574
152787
  }
152575
152788
  const sanitized = sanitizeSlackStatusText(description, SLACK_STATUS_TEXT_MAX);
@@ -152671,12 +152884,12 @@ Run \`${toolName}\`?`
152671
152884
  ];
152672
152885
  }
152673
152886
  function parseSlackApprovalActionPayload(value) {
152674
- if (!isNonEmptyString3(value)) {
152887
+ if (!isNonEmptyString4(value)) {
152675
152888
  return null;
152676
152889
  }
152677
152890
  try {
152678
152891
  const parsed = JSON.parse(value);
152679
- if (!isNonEmptyString3(parsed.requestId) || parsed.decision !== "allow" && parsed.decision !== "deny") {
152892
+ if (!isNonEmptyString4(parsed.requestId) || parsed.decision !== "allow" && parsed.decision !== "deny") {
152680
152893
  return null;
152681
152894
  }
152682
152895
  return { requestId: parsed.requestId, decision: parsed.decision };
@@ -152899,16 +153112,16 @@ async function mapSlackThreadMessage(message, attachmentOptions, sourceThreadId)
152899
153112
  const attachments = await resolveSlackMessageAttachments(message, attachmentOptions, sourceThreadId);
152900
153113
  return {
152901
153114
  text: resolveSlackThreadMessageText(message),
152902
- userId: isNonEmptyString5(message.user) ? message.user : undefined,
152903
- botId: isNonEmptyString5(message.bot_id) ? message.bot_id : undefined,
152904
- 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,
152905
153118
  ...attachments.length > 0 ? { attachments } : {}
152906
153119
  };
152907
153120
  }
152908
153121
  function asRecord4(value) {
152909
153122
  return value && typeof value === "object" ? value : null;
152910
153123
  }
152911
- function isNonEmptyString5(value) {
153124
+ function isNonEmptyString6(value) {
152912
153125
  return typeof value === "string" && value.trim().length > 0;
152913
153126
  }
152914
153127
  function normalizeSlackFileLike(value) {
@@ -152917,12 +153130,12 @@ function normalizeSlackFileLike(value) {
152917
153130
  return null;
152918
153131
  }
152919
153132
  return {
152920
- id: isNonEmptyString5(record5.id) ? record5.id : undefined,
152921
- name: isNonEmptyString5(record5.name) ? record5.name : undefined,
152922
- 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,
152923
153136
  size: typeof record5.size === "number" ? record5.size : undefined,
152924
- url_private: isNonEmptyString5(record5.url_private) ? record5.url_private : undefined,
152925
- 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
152926
153139
  };
152927
153140
  }
152928
153141
  function normalizeSlackAttachmentLike(value) {
@@ -152932,12 +153145,12 @@ function normalizeSlackAttachmentLike(value) {
152932
153145
  }
152933
153146
  const files = Array.isArray(record5.files) ? record5.files.map((entry) => normalizeSlackFileLike(entry)).filter((entry) => Boolean(entry)) : undefined;
152934
153147
  return {
152935
- text: isNonEmptyString5(record5.text) ? record5.text : undefined,
152936
- fallback: isNonEmptyString5(record5.fallback) ? record5.fallback : undefined,
152937
- pretext: isNonEmptyString5(record5.pretext) ? record5.pretext : undefined,
152938
- author_name: isNonEmptyString5(record5.author_name) ? record5.author_name : undefined,
152939
- title: isNonEmptyString5(record5.title) ? record5.title : undefined,
152940
- 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,
152941
153154
  files
152942
153155
  };
152943
153156
  }
@@ -152970,7 +153183,7 @@ function resolveSlackThreadMessageText(message) {
152970
153183
  if (text) {
152971
153184
  return text;
152972
153185
  }
152973
- 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) : [];
152974
153187
  if (attachmentTexts.length > 0) {
152975
153188
  return attachmentTexts.join(`
152976
153189
 
@@ -153277,7 +153490,7 @@ async function resolveSlackFilesAsAttachments(params) {
153277
153490
  return resolved;
153278
153491
  }
153279
153492
  function resolveSlackThreadAttachmentOptions(params) {
153280
- if (!isNonEmptyString5(params.accountId) || !isNonEmptyString5(params.token)) {
153493
+ if (!isNonEmptyString6(params.accountId) || !isNonEmptyString6(params.token)) {
153281
153494
  return;
153282
153495
  }
153283
153496
  return {
@@ -153304,7 +153517,7 @@ async function resolveSlackMessageAttachments(message, attachmentOptions, source
153304
153517
  token: attachmentOptions.token,
153305
153518
  files: collectSlackFiles(message),
153306
153519
  sourceMessageId: message.ts,
153307
- sourceThreadId: sourceThreadId ?? (isNonEmptyString5(message.thread_ts) ? message.thread_ts : null),
153520
+ sourceThreadId: sourceThreadId ?? (isNonEmptyString6(message.thread_ts) ? message.thread_ts : null),
153308
153521
  transcribeVoice: attachmentOptions.transcribeVoice
153309
153522
  });
153310
153523
  }
@@ -153314,8 +153527,8 @@ async function resolveSlackInboundAttachments(params) {
153314
153527
  accountId: params.accountId,
153315
153528
  token: params.token,
153316
153529
  files: collectSlackFiles(params.rawEvent),
153317
- sourceMessageId: isNonEmptyString5(rawEvent?.ts) ? rawEvent.ts : undefined,
153318
- 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,
153319
153532
  transcribeVoice: params.transcribeVoice
153320
153533
  });
153321
153534
  }
@@ -153388,7 +153601,7 @@ async function resolveSlackThreadHistory(params) {
153388
153601
  ...cursor ? { cursor } : {}
153389
153602
  });
153390
153603
  for (const message of response.messages ?? []) {
153391
- if (params.include === "bot" && !isNonEmptyString5(message.bot_id)) {
153604
+ if (params.include === "bot" && !isNonEmptyString6(message.bot_id)) {
153392
153605
  continue;
153393
153606
  }
153394
153607
  if (!hasSlackThreadMessageContent(message, attachmentOptions)) {
@@ -153452,11 +153665,11 @@ var init_media2 = __esm(() => {
153452
153665
  });
153453
153666
 
153454
153667
  // src/channels/slack/attachment-download.ts
153455
- function isNonEmptyString6(value) {
153668
+ function isNonEmptyString7(value) {
153456
153669
  return typeof value === "string" && value.trim().length > 0;
153457
153670
  }
153458
153671
  async function resolveCanonicalSlackMessage(params) {
153459
- if (isNonEmptyString6(params.threadTs)) {
153672
+ if (isNonEmptyString7(params.threadTs)) {
153460
153673
  let cursor;
153461
153674
  do {
153462
153675
  const response2 = await params.client.conversations.replies({
@@ -153471,7 +153684,7 @@ async function resolveCanonicalSlackMessage(params) {
153471
153684
  return message;
153472
153685
  }
153473
153686
  const nextCursor = response2.response_metadata?.next_cursor;
153474
- cursor = isNonEmptyString6(nextCursor) ? nextCursor.trim() : undefined;
153687
+ cursor = isNonEmptyString7(nextCursor) ? nextCursor.trim() : undefined;
153475
153688
  } while (cursor);
153476
153689
  return null;
153477
153690
  }
@@ -153623,7 +153836,7 @@ function createSlackInboundDebounceController(params) {
153623
153836
  const deduped = [];
153624
153837
  for (const entry of entries) {
153625
153838
  const messageId = entry.inbound.messageId;
153626
- const messageKey = isNonEmptyString3(messageId) ? `${entry.inbound.chatId}:${messageId}` : null;
153839
+ const messageKey = isNonEmptyString4(messageId) ? `${entry.inbound.chatId}:${messageId}` : null;
153627
153840
  if (!messageKey) {
153628
153841
  deduped.push(entry);
153629
153842
  continue;
@@ -153658,7 +153871,7 @@ function createSlackInboundDebounceController(params) {
153658
153871
  if (pending?.size === 0)
153659
153872
  pendingTopLevelKeys.delete(conversationKey);
153660
153873
  }
153661
- if (isNonEmptyString3(last.inbound.messageId)) {
153874
+ if (isNonEmptyString4(last.inbound.messageId)) {
153662
153875
  const seenKey = `${last.inbound.chatId}:${last.inbound.messageId}`;
153663
153876
  pruneAppMentionMaps(Date.now());
153664
153877
  if (last.opts.source === "app_mention") {
@@ -153737,13 +153950,13 @@ function hasRecordValue(value) {
153737
153950
  return value !== null && typeof value === "object";
153738
153951
  }
153739
153952
  function hasSlackMention(text, userId) {
153740
- return isNonEmptyString4(text) && isNonEmptyString4(userId) && (text.includes(`<@${userId}>`) || text.includes(`<@${userId}|`));
153953
+ return isNonEmptyString5(text) && isNonEmptyString5(userId) && (text.includes(`<@${userId}>`) || text.includes(`<@${userId}|`));
153741
153954
  }
153742
153955
  function isBotAuthoredMessage(message) {
153743
- return isNonEmptyString4(message.bot_id) || message.subtype === "bot_message";
153956
+ return isNonEmptyString5(message.bot_id) || message.subtype === "bot_message";
153744
153957
  }
153745
153958
  function resolveMessageSubtypeIgnoreReason(message) {
153746
- const subtype = isNonEmptyString4(message.subtype) ? message.subtype : null;
153959
+ const subtype = isNonEmptyString5(message.subtype) ? message.subtype : null;
153747
153960
  if (!subtype) {
153748
153961
  return null;
153749
153962
  }
@@ -153757,14 +153970,14 @@ function resolveMessageSubtypeIgnoreReason(message) {
153757
153970
  }
153758
153971
  function resolveSlackMessageIngressPolicy(params) {
153759
153972
  const { message } = params;
153760
- if (!isNonEmptyString4(message.channel)) {
153973
+ if (!isNonEmptyString5(message.channel)) {
153761
153974
  return { shouldRoute: false, reason: "missing_channel" };
153762
153975
  }
153763
153976
  const senderId = firstNonEmptyString3(message.user, message.bot_id);
153764
153977
  if (!senderId) {
153765
153978
  return { shouldRoute: false, reason: "missing_sender" };
153766
153979
  }
153767
- if (!isNonEmptyString4(message.ts)) {
153980
+ if (!isNonEmptyString5(message.ts)) {
153768
153981
  return { shouldRoute: false, reason: "missing_timestamp" };
153769
153982
  }
153770
153983
  if (message.hidden === true) {
@@ -153776,10 +153989,10 @@ function resolveSlackMessageIngressPolicy(params) {
153776
153989
  }
153777
153990
  const chatType = resolveSlackChatType2(message.channel);
153778
153991
  const threadId = chatType === "direct" ? firstNonEmptyString3(message.thread_ts) ?? null : firstNonEmptyString3(message.thread_ts, message.ts) ?? null;
153779
- if (chatType === "channel" && !isNonEmptyString4(message.thread_ts)) {
153992
+ if (chatType === "channel" && !isNonEmptyString5(message.thread_ts)) {
153780
153993
  return { shouldRoute: false, reason: "top_level_channel_message" };
153781
153994
  }
153782
- const rawText = isNonEmptyString4(message.text) ? message.text : "";
153995
+ const rawText = isNonEmptyString5(message.text) ? message.text : "";
153783
153996
  const wasMentioned = hasSlackMention(rawText, params.botUserId);
153784
153997
  const isAgentThread = params.isAgentThread === true;
153785
153998
  const effectiveMention = isBotAuthoredMessage(message) ? wasMentioned : wasMentioned || isAgentThread;
@@ -153787,8 +154000,8 @@ function resolveSlackMessageIngressPolicy(params) {
153787
154000
  shouldRoute: true,
153788
154001
  channelId: message.channel,
153789
154002
  senderId,
153790
- ...isNonEmptyString4(message.user) ? { senderUserId: message.user } : {},
153791
- ...isNonEmptyString4(message.bot_id) ? { senderBotId: message.bot_id } : {},
154003
+ ...isNonEmptyString5(message.user) ? { senderUserId: message.user } : {},
154004
+ ...isNonEmptyString5(message.bot_id) ? { senderBotId: message.bot_id } : {},
153792
154005
  messageId: message.ts,
153793
154006
  threadId,
153794
154007
  chatType,
@@ -153801,23 +154014,23 @@ function resolveSlackMessageIngressPolicy(params) {
153801
154014
  }
153802
154015
  function resolveSlackAppMentionIngressPolicy(params) {
153803
154016
  const { event: event2 } = params;
153804
- if (!isNonEmptyString4(event2.channel)) {
154017
+ if (!isNonEmptyString5(event2.channel)) {
153805
154018
  return { shouldRoute: false, reason: "missing_channel" };
153806
154019
  }
153807
154020
  const senderId = firstNonEmptyString3(event2.user, event2.bot_id);
153808
154021
  if (!senderId) {
153809
154022
  return { shouldRoute: false, reason: "missing_sender" };
153810
154023
  }
153811
- if (!isNonEmptyString4(event2.ts)) {
154024
+ if (!isNonEmptyString5(event2.ts)) {
153812
154025
  return { shouldRoute: false, reason: "missing_timestamp" };
153813
154026
  }
153814
- const rawText = isNonEmptyString4(event2.text) ? event2.text : "";
154027
+ const rawText = isNonEmptyString5(event2.text) ? event2.text : "";
153815
154028
  return {
153816
154029
  shouldRoute: true,
153817
154030
  channelId: event2.channel,
153818
154031
  senderId,
153819
- ...isNonEmptyString4(event2.user) ? { senderUserId: event2.user } : {},
153820
- ...isNonEmptyString4(event2.bot_id) ? { senderBotId: event2.bot_id } : {},
154032
+ ...isNonEmptyString5(event2.user) ? { senderUserId: event2.user } : {},
154033
+ ...isNonEmptyString5(event2.bot_id) ? { senderBotId: event2.bot_id } : {},
153821
154034
  messageId: event2.ts,
153822
154035
  threadId: firstNonEmptyString3(event2.thread_ts, event2.ts) ?? event2.ts,
153823
154036
  chatType: "channel",
@@ -153885,7 +154098,7 @@ function createSlackIngressController(params) {
153885
154098
  }
153886
154099
  }
153887
154100
  function markIngressMessageSeen(channelId, messageId) {
153888
- if (!isNonEmptyString3(channelId) || !isNonEmptyString3(messageId)) {
154101
+ if (!isNonEmptyString4(channelId) || !isNonEmptyString4(messageId)) {
153889
154102
  return false;
153890
154103
  }
153891
154104
  const key = `${channelId}:${messageId}`;
@@ -153896,12 +154109,12 @@ function createSlackIngressController(params) {
153896
154109
  return false;
153897
154110
  }
153898
154111
  function rememberMessageThread(messageId, threadId) {
153899
- if (isNonEmptyString3(messageId)) {
154112
+ if (isNonEmptyString4(messageId)) {
153900
154113
  knownThreadIdsByMessageId.set(messageId, threadId);
153901
154114
  }
153902
154115
  }
153903
154116
  async function resolveUserName(app, userId) {
153904
- if (!isNonEmptyString3(userId))
154117
+ if (!isNonEmptyString4(userId))
153905
154118
  return;
153906
154119
  const cached2 = knownUserDisplayNames.get(userId);
153907
154120
  if (cached2)
@@ -153917,10 +154130,10 @@ function createSlackIngressController(params) {
153917
154130
  return userId;
153918
154131
  }
153919
154132
  async function resolveInboundSenderName(app, userId, botId) {
153920
- if (isNonEmptyString3(userId)) {
154133
+ if (isNonEmptyString4(userId)) {
153921
154134
  return resolveUserName(app, userId);
153922
154135
  }
153923
- return isNonEmptyString3(botId) ? `Bot (${botId})` : undefined;
154136
+ return isNonEmptyString4(botId) ? `Bot (${botId})` : undefined;
153924
154137
  }
153925
154138
  function shouldAcceptInboundMessageByBotPolicy(input) {
153926
154139
  return shouldAcceptSlackInboundBotMessage({
@@ -153948,7 +154161,7 @@ function createSlackIngressController(params) {
153948
154161
  return;
153949
154162
  const rawMessage = asRecord2(message);
153950
154163
  const channelId = rawMessage?.channel;
153951
- if (!rawMessage || !isNonEmptyString3(channelId)) {
154164
+ if (!rawMessage || !isNonEmptyString4(channelId)) {
153952
154165
  return;
153953
154166
  }
153954
154167
  const basePolicy = resolveSlackMessageIngressPolicy({
@@ -153970,7 +154183,7 @@ function createSlackIngressController(params) {
153970
154183
  transcribeVoice: config3.transcribeVoice === true
153971
154184
  });
153972
154185
  const senderName = await resolveInboundSenderName(app, basePolicy.senderUserId, basePolicy.senderBotId);
153973
- 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);
153974
154187
  const policy = resolveSlackMessageIngressPolicy({
153975
154188
  message: rawMessage,
153976
154189
  botUserId: params.getBotUserId(),
@@ -154073,10 +154286,10 @@ function createSlackIngressController(params) {
154073
154286
  }) => {
154074
154287
  await ack();
154075
154288
  const adapter = params.getAdapter();
154076
- 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)) {
154077
154290
  return;
154078
154291
  }
154079
- const args = isNonEmptyString3(command.text) ? command.text.trim() : "";
154292
+ const args = isNonEmptyString4(command.text) ? command.text.trim() : "";
154080
154293
  try {
154081
154294
  await adapter.onMessage({
154082
154295
  channel: "slack",
@@ -154140,7 +154353,7 @@ function createSlackIngressController(params) {
154140
154353
  const item = asRecord2(event2.item);
154141
154354
  const chatId = item?.channel;
154142
154355
  const targetMessageId = item?.ts;
154143
- 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()) {
154144
154357
  return;
154145
154358
  }
154146
154359
  const chatType = resolveSlackChatType(chatId);
@@ -154164,7 +154377,7 @@ function createSlackIngressController(params) {
154164
154377
  action: action3,
154165
154378
  emoji: event2.reaction,
154166
154379
  targetMessageId,
154167
- targetSenderId: isNonEmptyString3(event2.item_user) ? event2.item_user : undefined
154380
+ targetSenderId: isNonEmptyString4(event2.item_user) ? event2.item_user : undefined
154168
154381
  },
154169
154382
  raw: event2
154170
154383
  });
@@ -154210,22 +154423,22 @@ function createSlackStatusController(params) {
154210
154423
  const keepaliveByConversation = new Map;
154211
154424
  const clearedStaleReplyKeys = new Set;
154212
154425
  function getConversationKey(source2) {
154213
- 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;
154214
154427
  }
154215
154428
  function getLifecycleReplyKey(source2) {
154216
- if (source2.channel !== "slack" || !isNonEmptyString4(source2.chatId)) {
154429
+ if (source2.channel !== "slack" || !isNonEmptyString5(source2.chatId)) {
154217
154430
  return null;
154218
154431
  }
154219
154432
  const replyToMessageId = resolveSlackProgressThreadTs(source2);
154220
- return isNonEmptyString4(replyToMessageId) ? `${source2.chatId}:${replyToMessageId}` : null;
154433
+ return isNonEmptyString5(replyToMessageId) ? `${source2.chatId}:${replyToMessageId}` : null;
154221
154434
  }
154222
154435
  function getLifecycleErrorReplyKey(source2) {
154223
- if (source2.channel !== "slack" || !isNonEmptyString4(source2.chatId)) {
154436
+ if (source2.channel !== "slack" || !isNonEmptyString5(source2.chatId)) {
154224
154437
  return null;
154225
154438
  }
154226
154439
  if (source2.chatType === "direct" || resolveSlackChatType2(source2.chatId) === "direct") {
154227
154440
  const replyToMessageId = resolveSlackSourceThreadTs2(source2);
154228
- return isNonEmptyString4(replyToMessageId) ? `${source2.chatId}:${replyToMessageId}` : `${source2.chatId}:direct`;
154441
+ return isNonEmptyString5(replyToMessageId) ? `${source2.chatId}:${replyToMessageId}` : `${source2.chatId}:direct`;
154229
154442
  }
154230
154443
  return getLifecycleReplyKey(source2);
154231
154444
  }
@@ -154384,7 +154597,7 @@ ${loadingText}`;
154384
154597
  markAutoClearedByKey(key);
154385
154598
  },
154386
154599
  markAutoClearedForMessage(msg) {
154387
- if (isNonEmptyString4(msg.agentId) && isNonEmptyString4(msg.conversationId)) {
154600
+ if (isNonEmptyString5(msg.agentId) && isNonEmptyString5(msg.conversationId)) {
154388
154601
  markAutoClearedByKey(`${msg.agentId}:${msg.conversationId}`);
154389
154602
  return;
154390
154603
  }
@@ -154432,7 +154645,7 @@ function truncateThreadLabel(text, maxLength3 = 80) {
154432
154645
  return normalized.length <= maxLength3 ? normalized : `${normalized.slice(0, maxLength3 - 1).trimEnd()}…`;
154433
154646
  }
154434
154647
  function buildThreadLabel(msg, starterText) {
154435
- 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}` : "";
154436
154649
  const preview = truncateThreadLabel(starterText ?? msg.text);
154437
154650
  const threadLabel = msg.chatType === "direct" ? "Slack DM thread" : "Slack thread";
154438
154651
  if (preview)
@@ -154442,12 +154655,12 @@ function buildThreadLabel(msg, starterText) {
154442
154655
  function buildChannelContextLabel(msg) {
154443
154656
  if (msg.chatType !== "channel")
154444
154657
  return;
154445
- 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}` : "";
154446
154659
  return roomLabel ? `Slack channel context${roomLabel} before thread start` : "Slack channel context before thread start";
154447
154660
  }
154448
154661
  async function prepareSlackInboundMessage(params) {
154449
154662
  const { msg, config: config3 } = params;
154450
- if (msg.channel !== "slack" || !isNonEmptyString3(msg.threadId) || !isNonEmptyString3(msg.messageId)) {
154663
+ if (msg.channel !== "slack" || !isNonEmptyString4(msg.threadId) || !isNonEmptyString4(msg.messageId)) {
154451
154664
  return msg;
154452
154665
  }
154453
154666
  const isFirstRouteTurn = params.options?.isFirstRouteTurn === true;
@@ -154496,18 +154709,18 @@ async function prepareSlackInboundMessage(params) {
154496
154709
  return msg;
154497
154710
  }
154498
154711
  const userIds = new Set;
154499
- if (isNonEmptyString3(starter?.userId))
154712
+ if (isNonEmptyString4(starter?.userId))
154500
154713
  userIds.add(starter.userId);
154501
154714
  for (const entry of history) {
154502
- if (isNonEmptyString3(entry.userId))
154715
+ if (isNonEmptyString4(entry.userId))
154503
154716
  userIds.add(entry.userId);
154504
154717
  }
154505
154718
  await Promise.all(Array.from(userIds).map((userId) => params.resolveUserName(app, userId)));
154506
154719
  const resolveSenderName = (userId, botId) => {
154507
- if (isNonEmptyString3(userId)) {
154720
+ if (isNonEmptyString4(userId)) {
154508
154721
  return params.getKnownUserDisplayName(userId) ?? userId;
154509
154722
  }
154510
- return isNonEmptyString3(botId) ? `Bot (${botId})` : undefined;
154723
+ return isNonEmptyString4(botId) ? `Bot (${botId})` : undefined;
154511
154724
  };
154512
154725
  return {
154513
154726
  ...msg,
@@ -154666,7 +154879,7 @@ function createSlackAdapter(config3) {
154666
154879
  if (!running)
154667
154880
  return;
154668
154881
  if (event2.type === "queued") {
154669
- 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)) {
154670
154883
  await status.activate(event2.source, SLACK_ASSISTANT_STARTUP_STATUS, SLACK_ASSISTANT_STARTUP_STATUS);
154671
154884
  }
154672
154885
  return;
@@ -154728,7 +154941,7 @@ function createSlackAdapter(config3) {
154728
154941
  if (msg.mediaPath) {
154729
154942
  const result = await uploadSlackFile(client, msg);
154730
154943
  const threadId = msg.threadId ?? msg.replyToMessageId ?? null;
154731
- if (resolveSlackChatType(msg.chatId) === "channel" && isNonEmptyString3(threadId)) {
154944
+ if (resolveSlackChatType(msg.chatId) === "channel" && isNonEmptyString4(threadId)) {
154732
154945
  agentThreadTracker.remember(msg.chatId, threadId);
154733
154946
  }
154734
154947
  status.markAutoClearedForMessage(msg);
@@ -154739,7 +154952,7 @@ function createSlackAdapter(config3) {
154739
154952
  threadId: msg.threadId,
154740
154953
  replyToMessageId: msg.replyToMessageId
154741
154954
  });
154742
- const footnote = isNonEmptyString3(msg.agentId) && isNonEmptyString3(msg.conversationId) ? buildSlackChatFootnote({
154955
+ const footnote = isNonEmptyString4(msg.agentId) && isNonEmptyString4(msg.conversationId) ? buildSlackChatFootnote({
154743
154956
  agentId: msg.agentId,
154744
154957
  conversationId: msg.conversationId
154745
154958
  }) : "";
@@ -154752,7 +154965,7 @@ function createSlackAdapter(config3) {
154752
154965
  });
154753
154966
  const outboundThreadId = threadTs ?? (resolveSlackChatType(msg.chatId) === "channel" ? response.ts ?? null : null);
154754
154967
  ingress.rememberMessageThread(response.ts, outboundThreadId);
154755
- if (resolveSlackChatType(msg.chatId) === "channel" && isNonEmptyString3(outboundThreadId)) {
154968
+ if (resolveSlackChatType(msg.chatId) === "channel" && isNonEmptyString4(outboundThreadId)) {
154756
154969
  agentThreadTracker.remember(msg.chatId, outboundThreadId);
154757
154970
  }
154758
154971
  status.markAutoClearedForMessage(msg);
@@ -154775,7 +154988,7 @@ function createSlackAdapter(config3) {
154775
154988
  });
154776
154989
  const outboundThreadId = threadTs ?? (resolveSlackChatType(chatId) === "channel" ? response.ts ?? null : null);
154777
154990
  ingress.rememberMessageThread(response.ts, outboundThreadId);
154778
- if (resolveSlackChatType(chatId) === "channel" && isNonEmptyString3(outboundThreadId)) {
154991
+ if (resolveSlackChatType(chatId) === "channel" && isNonEmptyString4(outboundThreadId)) {
154779
154992
  agentThreadTracker.remember(chatId, outboundThreadId);
154780
154993
  }
154781
154994
  status.markAutoClearedForMessage({
@@ -154801,7 +155014,7 @@ function createSlackAdapter(config3) {
154801
155014
  if (event2.kind === "generic_tool_approval" && response.ts) {
154802
155015
  approvals.rememberPrompt(event2, response.ts);
154803
155016
  }
154804
- if (resolveSlackChatType(event2.source.chatId) === "channel" && isNonEmptyString3(outboundThreadId)) {
155017
+ if (resolveSlackChatType(event2.source.chatId) === "channel" && isNonEmptyString4(outboundThreadId)) {
154805
155018
  agentThreadTracker.remember(event2.source.chatId, outboundThreadId);
154806
155019
  }
154807
155020
  status.markAutoCleared(event2.source);
@@ -154817,8 +155030,8 @@ function createSlackAdapter(config3) {
154817
155030
  const slackApp = await ensureApp();
154818
155031
  const auth = await slackApp.client.auth.test();
154819
155032
  const authRecord = auth;
154820
- botUserId = isNonEmptyString3(authRecord.user_id) ? authRecord.user_id : null;
154821
- 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;
154822
155035
  await slackApp.start();
154823
155036
  running = true;
154824
155037
  console.log(`[Slack] App started for workspace ${auth.team ?? "unknown"} (dm_policy: ${config3.dmPolicy})`);
@@ -156041,7 +156254,7 @@ function formatDiscordDeliveryError(error54) {
156041
156254
  }
156042
156255
 
156043
156256
  // src/channels/discord/utils.ts
156044
- function isNonEmptyString7(value) {
156257
+ function isNonEmptyString8(value) {
156045
156258
  return typeof value === "string" && value.length > 0;
156046
156259
  }
156047
156260
  function isDiscordTextChannel(channel) {
@@ -156108,7 +156321,7 @@ function shouldAutoThreadOnDiscordMention(account, channelId) {
156108
156321
  return account.autoThreadOnMention ?? false;
156109
156322
  }
156110
156323
  function buildDiscordIngressMessageKey(accountId, messageId) {
156111
- if (!isNonEmptyString7(accountId) || !isNonEmptyString7(messageId)) {
156324
+ if (!isNonEmptyString8(accountId) || !isNonEmptyString8(messageId)) {
156112
156325
  return null;
156113
156326
  }
156114
156327
  return `${accountId}:${messageId}`;
@@ -156192,13 +156405,13 @@ function createDiscordAdapter(config3) {
156192
156405
  return false;
156193
156406
  }
156194
156407
  function getLifecycleMessageKey(source2) {
156195
- if (source2.channel !== "discord" || !isNonEmptyString7(source2.chatId) || !isNonEmptyString7(source2.messageId)) {
156408
+ if (source2.channel !== "discord" || !isNonEmptyString8(source2.chatId) || !isNonEmptyString8(source2.messageId)) {
156196
156409
  return null;
156197
156410
  }
156198
156411
  return `${source2.chatId}:${source2.messageId}`;
156199
156412
  }
156200
156413
  function getLifecycleReplyKey(source2) {
156201
- if (source2.channel !== "discord" || !isNonEmptyString7(source2.chatId)) {
156414
+ if (source2.channel !== "discord" || !isNonEmptyString8(source2.chatId)) {
156202
156415
  return null;
156203
156416
  }
156204
156417
  return [
@@ -156211,7 +156424,7 @@ function createDiscordAdapter(config3) {
156211
156424
  if (source2.channel !== "discord")
156212
156425
  return null;
156213
156426
  const channelId = source2.threadId ?? source2.chatId;
156214
- return isNonEmptyString7(channelId) ? channelId : null;
156427
+ return isNonEmptyString8(channelId) ? channelId : null;
156215
156428
  }
156216
156429
  function getTypingSourceKey(source2) {
156217
156430
  const channelId = getTypingChannelId(source2);
@@ -156263,7 +156476,7 @@ function createDiscordAdapter(config3) {
156263
156476
  return true;
156264
156477
  }
156265
156478
  async function sendLifecycleReaction(source2, emoji3, remove = false) {
156266
- if (!client || !isNonEmptyString7(source2.messageId))
156479
+ if (!client || !isNonEmptyString8(source2.messageId))
156267
156480
  return;
156268
156481
  try {
156269
156482
  const channel = await client.channels.fetch(source2.chatId);
@@ -156504,15 +156717,23 @@ function createDiscordAdapter(config3) {
156504
156717
  client.on("messageCreate", async (message) => {
156505
156718
  if (!adapter.onMessage)
156506
156719
  return;
156507
- if (message.author.bot)
156508
- return;
156509
156720
  const content = (message.content ?? "").trim();
156510
156721
  const userId = message.author.id;
156511
156722
  if (!userId)
156512
156723
  return;
156724
+ const effectiveBotUserId = botUserId ?? client?.user?.id ?? null;
156513
156725
  const chatType = resolveDiscordChatType(message.guildId);
156514
156726
  const isThread = isThreadMessage(message);
156515
- 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
+ }
156516
156737
  if (chatType === "direct") {
156517
156738
  if (markIngressMessageSeen(message.id))
156518
156739
  return;
@@ -156538,7 +156759,9 @@ function createDiscordAdapter(config3) {
156538
156759
  await adapter.onMessage(inbound2);
156539
156760
  } catch (error54) {
156540
156761
  console.error("[Discord] Error handling DM:", error54);
156541
- await notifyDiscordDeliveryError(message, error54);
156762
+ if (!message.author.bot) {
156763
+ await notifyDiscordDeliveryError(message, error54);
156764
+ }
156542
156765
  }
156543
156766
  return;
156544
156767
  }
@@ -156593,7 +156816,9 @@ function createDiscordAdapter(config3) {
156593
156816
  await adapter.onMessage(inbound);
156594
156817
  } catch (error54) {
156595
156818
  console.error("[Discord] Error handling guild message:", error54);
156596
- await notifyDiscordDeliveryError(message, error54);
156819
+ if (!message.author.bot) {
156820
+ await notifyDiscordDeliveryError(message, error54);
156821
+ }
156597
156822
  }
156598
156823
  });
156599
156824
  const handleReactionEvent = async (reaction, user, action3) => {
@@ -156802,7 +157027,7 @@ function createDiscordAdapter(config3) {
156802
157027
  clearTypingForChannel(chatId);
156803
157028
  },
156804
157029
  async prepareInboundMessage(msg, options3) {
156805
- 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) {
156806
157031
  return msg;
156807
157032
  }
156808
157033
  const starter = await resolveDiscordThreadStarter({
@@ -160855,168 +161080,6 @@ var init_app_urls = __esm(() => {
160855
161080
  LETTA_CHAT_API_KEYS_URL = `${CHAT_BASE}/preferences/api-keys`;
160856
161081
  });
160857
161082
 
160858
- // src/channels/registry-presentation.ts
160859
- function channelDisplayName4(channelId) {
160860
- try {
160861
- return getChannelDisplayName(channelId);
160862
- } catch {
160863
- return channelId;
160864
- }
160865
- }
160866
- function normalizeAgentId(agentId) {
160867
- const normalized = agentId?.trim();
160868
- return normalized ? normalized : null;
160869
- }
160870
- function getConfiguredAgentId(config3) {
160871
- if (!config3 || typeof config3 !== "object")
160872
- return null;
160873
- const source2 = config3;
160874
- return normalizeAgentId(source2.agentId) ?? normalizeAgentId(source2.binding?.agentId);
160875
- }
160876
- function buildPairingInstructions(channelId, code2, options3 = {}) {
160877
- const displayName = channelDisplayName4(channelId);
160878
- const configuredAgentId = normalizeAgentId(options3.agentId);
160879
- const pairingCommand = `letta channels pair --channel ${channelId} --code ${code2} --agent ${configuredAgentId ?? "<agent-id>"}`;
160880
- const agentLookupLines = configuredAgentId ? [] : ["Find the target agent with: letta agents list"];
160881
- if (!isFirstPartyChannelPlugin(channelId)) {
160882
- return [
160883
- "Connect this chat to a Letta agent.",
160884
- "",
160885
- `Pairing code: ${code2}`,
160886
- "",
160887
- "CLI on the listener machine:",
160888
- pairingCommand,
160889
- ...agentLookupLines,
160890
- "",
160891
- "This code expires in 15 minutes."
160892
- ].join(`
160893
- `);
160894
- }
160895
- return [
160896
- "Connect this chat to a Letta agent.",
160897
- "",
160898
- `Pairing code: ${code2}`,
160899
- "",
160900
- `In Letta Code: open Channels > ${displayName} and approve this pending chat.`,
160901
- "",
160902
- "CLI on the listener machine:",
160903
- pairingCommand,
160904
- ...agentLookupLines,
160905
- "",
160906
- "This code expires in 15 minutes."
160907
- ].join(`
160908
- `);
160909
- }
160910
- function buildUnboundRouteInstructions(channelId, chatId) {
160911
- const displayName = channelDisplayName4(channelId);
160912
- if (!isFirstPartyChannelPlugin(channelId)) {
160913
- return `This chat isn't connected to a Letta agent yet.
160914
-
160915
- ` + `On the machine where your listener runs:
160916
-
160917
- ` + `letta channels route add --channel ${channelId} --chat-id ${chatId} --agent <agent-id>
160918
-
160919
- ` + `Find your agent id with letta agents list.`;
160920
- }
160921
- return `This chat isn't connected to a Letta agent yet.
160922
-
160923
- ` + `Open Channels > ${displayName} in Letta Code and connect this chat there.
160924
-
160925
- ` + `Chat ID: ${chatId}`;
160926
- }
160927
- function buildSlackAppSetupInstructions() {
160928
- return `This Slack app isn't connected to a Letta agent yet.
160929
-
160930
- ` + "Open Channels > Slack in Letta Code, choose which agent this app should represent, and try again.";
160931
- }
160932
- function truncateChannelSummaryPreview(text, maxLength3 = 72) {
160933
- const normalized = text.replace(/\s+/g, " ").trim();
160934
- if (!normalized)
160935
- return null;
160936
- if (normalized.length <= maxLength3)
160937
- return normalized;
160938
- return `${normalized.slice(0, maxLength3 - 1).trimEnd()}…`;
160939
- }
160940
- function buildSlackConversationSummary(msg) {
160941
- if (msg.chatType === "direct") {
160942
- if (msg.threadId?.trim()) {
160943
- const preview3 = truncateChannelSummaryPreview(msg.text);
160944
- return preview3 ? `[Slack] DM thread with ${msg.senderName?.trim() || msg.senderId}: ${preview3}` : `[Slack] DM thread with ${msg.senderName?.trim() || msg.senderId}`;
160945
- }
160946
- return `[Slack] DM with ${msg.senderName?.trim() || msg.senderId}`;
160947
- }
160948
- const preview2 = truncateChannelSummaryPreview(msg.text);
160949
- const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
160950
- if (preview2)
160951
- return `[Slack] Thread${channelLabel}: ${preview2}`;
160952
- return `[Slack] Thread${channelLabel || ` ${msg.chatId}`}`;
160953
- }
160954
- function buildDiscordConversationSummary(msg) {
160955
- if (msg.chatType === "direct") {
160956
- return `[Discord] DM with ${msg.senderName?.trim() || msg.senderId}`;
160957
- }
160958
- const preview2 = truncateChannelSummaryPreview(msg.text);
160959
- const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
160960
- if (preview2)
160961
- return `[Discord] Thread${channelLabel}: ${preview2}`;
160962
- return `[Discord] Thread${channelLabel || ` ${msg.chatId}`}`;
160963
- }
160964
- function buildTelegramConversationSummary(msg) {
160965
- if (msg.chatType === "direct") {
160966
- return `[Telegram] DM with ${msg.senderName?.trim() || msg.senderId}`;
160967
- }
160968
- const preview2 = truncateChannelSummaryPreview(msg.text);
160969
- const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
160970
- if (preview2)
160971
- return `[Telegram] Topic${channelLabel}: ${preview2}`;
160972
- return `[Telegram] Topic${channelLabel || ` ${msg.chatId}`}`;
160973
- }
160974
- function buildWhatsAppConversationSummary(msg) {
160975
- if (msg.chatType === "direct") {
160976
- return `[WhatsApp] DM with ${msg.senderName?.trim() || msg.senderId}`;
160977
- }
160978
- const preview2 = truncateChannelSummaryPreview(msg.text);
160979
- const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
160980
- if (preview2)
160981
- return `[WhatsApp] Group${channelLabel}: ${preview2}`;
160982
- return `[WhatsApp] Group${channelLabel || ` ${msg.chatId}`}`;
160983
- }
160984
- function buildSignalConversationSummary(msg) {
160985
- if (msg.chatType === "direct") {
160986
- return `[Signal] DM with ${msg.senderName?.trim() || msg.senderId}`;
160987
- }
160988
- const preview2 = truncateChannelSummaryPreview(msg.text);
160989
- const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
160990
- if (preview2)
160991
- return `[Signal] Group${channelLabel}: ${preview2}`;
160992
- return `[Signal] Group${channelLabel || ` ${msg.chatId}`}`;
160993
- }
160994
- function buildChannelTurnSource(route, msg) {
160995
- return {
160996
- channel: msg.channel,
160997
- accountId: msg.accountId,
160998
- chatId: msg.chatId,
160999
- chatType: msg.chatType,
161000
- senderId: msg.senderId,
161001
- senderTeamId: msg.senderTeamId,
161002
- messageId: msg.messageId,
161003
- threadId: msg.threadId,
161004
- agentId: route.agentId,
161005
- conversationId: route.conversationId
161006
- };
161007
- }
161008
- function buildDirectReplyOptions(msg) {
161009
- if (!msg.messageId && !msg.threadId)
161010
- return;
161011
- return {
161012
- replyToMessageId: msg.threadId ?? msg.messageId ?? undefined,
161013
- threadId: msg.threadId ?? null
161014
- };
161015
- }
161016
- var init_registry_presentation = __esm(() => {
161017
- init_plugin_registry();
161018
- });
161019
-
161020
161083
  // src/channels/routing.ts
161021
161084
  var exports_routing = {};
161022
161085
  __export(exports_routing, {
@@ -161027,8 +161090,10 @@ __export(exports_routing, {
161027
161090
  removeRouteInMemory: () => removeRouteInMemory,
161028
161091
  removeRoute: () => removeRoute,
161029
161092
  loadRoutes: () => loadRoutes,
161093
+ loadRouteForInboundMessage: () => loadRouteForInboundMessage,
161030
161094
  getRoutesForChannel: () => getRoutesForChannel,
161031
161095
  getRouteRaw: () => getRouteRaw,
161096
+ getRouteForInboundMessage: () => getRouteForInboundMessage,
161032
161097
  getRoute: () => getRoute,
161033
161098
  getAllRoutes: () => getAllRoutes,
161034
161099
  clearAllRoutes: () => clearAllRoutes,
@@ -161131,6 +161196,28 @@ function getRoute(channel, chatId, accountId, threadId) {
161131
161196
  function getRouteRaw(channel, chatId, accountId, threadId) {
161132
161197
  return routesByKey.get(routeKey(channel, chatId, accountId, threadId));
161133
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
+ }
161134
161221
  function getRoutesForChannel(channelId, accountId) {
161135
161222
  const prefix = accountId === undefined ? `${channelId}:` : `${channelId}:${normalizeAccountId3(accountId)}:`;
161136
161223
  const routes = [];
@@ -161212,16 +161299,10 @@ var init_routing = __esm(() => {
161212
161299
 
161213
161300
  // src/channels/registry-commands.ts
161214
161301
  function createChannelCommandRouter(deps) {
161215
- function findRawRouteForMessage(msg) {
161216
- return getRouteRaw(msg.channel, msg.chatId, msg.accountId, msg.threadId) ?? null;
161217
- }
161218
161302
  function loadAndFindRawRouteForMessage(msg) {
161219
- const route = findRawRouteForMessage(msg);
161220
- if (route) {
161221
- return route;
161222
- }
161223
- loadRoutes(msg.channel);
161224
- return findRawRouteForMessage(msg);
161303
+ return loadRouteForInboundMessage(msg, msg.accountId, {
161304
+ includeDisabled: true
161305
+ });
161225
161306
  }
161226
161307
  async function handlePauseResumeSlashCommand(commandName, msg) {
161227
161308
  const route = loadAndFindRawRouteForMessage(msg);
@@ -161471,15 +161552,9 @@ function createChannelCommandRouter(deps) {
161471
161552
  });
161472
161553
  }
161473
161554
  function getCancelRoute(msg) {
161474
- let route = deps.getRoute(msg.channel, msg.chatId, msg.accountId, msg.threadId);
161475
- if (route) {
161476
- return route;
161477
- }
161478
- loadRoutes(msg.channel);
161479
- route = deps.getRoute(msg.channel, msg.chatId, msg.accountId, msg.threadId);
161480
- if (route) {
161555
+ const route = loadRouteForInboundMessage(msg, msg.accountId);
161556
+ if (route)
161481
161557
  return route;
161482
- }
161483
161558
  if (msg.channel !== "slack" || msg.chatType !== "channel" || msg.threadId != null) {
161484
161559
  return null;
161485
161560
  }
@@ -162340,7 +162415,7 @@ function createChannelInboundRouter(deps) {
162340
162415
  return;
162341
162416
  }
162342
162417
  if (resolveChannelAccessScope(msg.chatType) === "dm") {
162343
- await adapter.sendDirectReply(msg.chatId, buildChannelAccessDeniedMessage(msg.channel));
162418
+ await adapter.sendDirectReply(msg.chatId, buildChannelAccessDeniedMessage(msg.channel), buildDirectReplyOptions(msg));
162344
162419
  } else {
162345
162420
  console.log(`[channels] Dropped ${msg.channel} group message from unauthorized sender ${msg.senderId} in chat ${msg.chatId}`);
162346
162421
  }
@@ -162352,14 +162427,7 @@ function createChannelInboundRouter(deps) {
162352
162427
  if (deps.commands.shouldDropUnroutedSlackThreadInput(msg, accountId, config3)) {
162353
162428
  return;
162354
162429
  }
162355
- const getStatusRoute = () => {
162356
- let statusRoute = getRoute(msg.channel, msg.chatId, accountId, msg.threadId);
162357
- if (!statusRoute) {
162358
- loadRoutes(msg.channel);
162359
- statusRoute = getRoute(msg.channel, msg.chatId, accountId, msg.threadId);
162360
- }
162361
- return statusRoute;
162362
- };
162430
+ const getStatusRoute = () => loadRouteForInboundMessage(msg, accountId);
162363
162431
  if (await tryHandleChannelSlashCommand(adapter, msg, {
162364
162432
  statusContext: {
162365
162433
  adapterRunning: adapter.isRunning(),
@@ -162509,16 +162577,12 @@ function createChannelInboundRouter(deps) {
162509
162577
  });
162510
162578
  await adapter.sendDirectReply(msg.chatId, buildPairingInstructions(msg.channel, code2, {
162511
162579
  agentId: getConfiguredAgentId(config3)
162512
- }));
162580
+ }), buildDirectReplyOptions(msg));
162513
162581
  return;
162514
162582
  }
162515
- let route = getRoute(msg.channel, msg.chatId, accountId, msg.threadId);
162516
- if (!route) {
162517
- loadRoutes(msg.channel);
162518
- route = getRoute(msg.channel, msg.chatId, accountId, msg.threadId);
162519
- }
162583
+ const route = loadRouteForInboundMessage(msg, accountId);
162520
162584
  if (!route) {
162521
- await adapter.sendDirectReply(msg.chatId, buildUnboundRouteInstructions(msg.channel, msg.chatId));
162585
+ await adapter.sendDirectReply(msg.chatId, buildUnboundRouteInstructions(msg.channel, msg.chatId), buildDirectReplyOptions(msg));
162522
162586
  return;
162523
162587
  }
162524
162588
  const preparedMessage = adapter.prepareInboundMessage ? await adapter.prepareInboundMessage(msg, { isFirstRouteTurn: false }) : msg;
@@ -345981,6 +346045,7 @@ async function loadLocalMods(options3) {
345981
346045
  const builtinCommandIds = new Set([...options3.builtinCommandIds ?? []]);
345982
346046
  const reservedToolNames = new Set([...options3.reservedToolNames ?? []]);
345983
346047
  const registry2 = createEmptyModRegistry(sources, generation2, capabilities, options3.registerCapabilitiesGlobally !== false);
346048
+ options3.onRegistryCreated?.(registry2);
345984
346049
  for (const source2 of sources) {
345985
346050
  for (const diagnostic of source2.diagnostics ?? []) {
345986
346051
  const owner = createModOwner(diagnostic.path, source2, generation2);
@@ -346191,6 +346256,13 @@ function createModEngine(options3) {
346191
346256
  const nextRegistry = await loadLocalMods({
346192
346257
  ...modOptions,
346193
346258
  generation: loadGeneration,
346259
+ onRegistryCreated: (registry2) => {
346260
+ loadingRegistry = registry2;
346261
+ if (!disposed && loadGeneration === generation2) {
346262
+ activeRegistry = registry2;
346263
+ publish();
346264
+ }
346265
+ },
346194
346266
  onChange: () => {
346195
346267
  if (!disposed && loadingRegistry && loadGeneration === generation2) {
346196
346268
  activeRegistry = loadingRegistry;
@@ -353068,10 +353140,7 @@ function inferAccountIdFromChannelTurnSources(params) {
353068
353140
  }
353069
353141
  const accountIds = new Set;
353070
353142
  for (const source2 of params.channelTurnSources ?? []) {
353071
- if (source2.channel !== params.input.channel || source2.chatId !== chatId || source2.agentId !== params.scope.agentId || source2.conversationId !== params.scope.conversationId) {
353072
- continue;
353073
- }
353074
- 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) {
353075
353144
  continue;
353076
353145
  }
353077
353146
  if (source2.accountId?.trim()) {
@@ -353174,7 +353243,7 @@ async function message_channel(args) {
353174
353243
  accountId: resolvedAccountId,
353175
353244
  channelTurnSources: args.channelTurnSources
353176
353245
  });
353177
- 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);
353178
353247
  executionContext = {
353179
353248
  request: buildMessageChannelRequest(input, input.chatId, requestThreadId),
353180
353249
  route: route2,
@@ -381951,6 +382020,17 @@ var init_local_backend = __esm(() => {
381951
382020
 
381952
382021
  // src/backend/backend.ts
381953
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
+ }
381954
382034
 
381955
382035
  class APIBackend {
381956
382036
  capabilities = {
@@ -382022,7 +382102,7 @@ class APIBackend {
382022
382102
  }
382023
382103
  async listConversationMessages(conversationId, body, options3) {
382024
382104
  const client = await this.getClient();
382025
- return client.conversations.messages.list(conversationId, body, options3);
382105
+ return client.conversations.messages.list(conversationId, toApiConversationMessageListBody(body), options3);
382026
382106
  }
382027
382107
  async compactConversationMessages(conversationId, body, options3) {
382028
382108
  const client = await this.getClient();
@@ -382160,7 +382240,7 @@ async function configureDevBackend(name) {
382160
382240
  function __testSetBackend(nextBackend) {
382161
382241
  backend = nextBackend ?? createInitialBackend();
382162
382242
  }
382163
- var backend = null;
382243
+ var DEFAULT_CONVERSATION_MESSAGE_ORDER = "desc", backend = null;
382164
382244
  var init_backend = __esm(() => {
382165
382245
  init_backend_mode();
382166
382246
  init_local_backend();
@@ -382179,6 +382259,7 @@ __export(exports_backend, {
382179
382259
  configureDevBackend: () => configureDevBackend,
382180
382260
  configureBackendMode: () => configureBackendMode,
382181
382261
  __testSetBackend: () => __testSetBackend,
382262
+ DEFAULT_CONVERSATION_MESSAGE_ORDER: () => DEFAULT_CONVERSATION_MESSAGE_ORDER,
382182
382263
  APIBackend: () => APIBackend
382183
382264
  });
382184
382265
  var init_backend2 = __esm(() => {
@@ -423944,6 +424025,7 @@ var init_account_config2 = __esm(() => {
423944
424025
  "token",
423945
424026
  "agent_id",
423946
424027
  "allowed_channels",
424028
+ "allow_bots",
423947
424029
  "default_permission_mode",
423948
424030
  "transcribe_voice",
423949
424031
  "auto_thread_on_mention",
@@ -423959,7 +424041,7 @@ var init_account_config2 = __esm(() => {
423959
424041
  return false;
423960
424042
  }
423961
424043
  }
423962
- 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);
423963
424045
  },
423964
424046
  toAccountPatch(config3) {
423965
424047
  const allowedChannels = isAllowedChannels(config3.allowed_channels) ? Array.isArray(config3.allowed_channels) ? [...config3.allowed_channels] : { ...config3.allowed_channels } : undefined;
@@ -423968,6 +424050,7 @@ var init_account_config2 = __esm(() => {
423968
424050
  agentId: isNullableString2(config3.agent_id) ? config3.agent_id : undefined,
423969
424051
  defaultPermissionMode: isDefaultPermissionMode(config3.default_permission_mode) ? migratePermissionMode(config3.default_permission_mode) : undefined,
423970
424052
  allowedChannels,
424053
+ allowBots: config3.allow_bots !== undefined && isValidDiscordAllowBotsConfigValue(config3.allow_bots) ? normalizeDiscordAllowBotsMode(config3.allow_bots) : undefined,
423971
424054
  transcribeVoice: isBoolean(config3.transcribe_voice) ? config3.transcribe_voice : undefined,
423972
424055
  autoThreadOnMention: isBoolean(config3.auto_thread_on_mention) ? config3.auto_thread_on_mention : undefined,
423973
424056
  threadPolicyByChannel: typeof config3.thread_policy_by_channel === "object" && !Array.isArray(config3.thread_policy_by_channel) ? { ...config3.thread_policy_by_channel } : undefined,
@@ -423982,6 +424065,7 @@ var init_account_config2 = __esm(() => {
423982
424065
  agent_id: account.agentId,
423983
424066
  default_permission_mode: account.defaultPermissionMode ?? "standard",
423984
424067
  allowed_channels: serializeAllowedChannels(account.allowedChannels),
424068
+ allow_bots: account.allowBots ?? false,
423985
424069
  transcribe_voice: account.transcribeVoice === true,
423986
424070
  auto_thread_on_mention: account.autoThreadOnMention ?? false,
423987
424071
  thread_policy_by_channel: account.threadPolicyByChannel ?? {},
@@ -423996,6 +424080,7 @@ var init_account_config2 = __esm(() => {
423996
424080
  agent_id: account.agentId,
423997
424081
  default_permission_mode: account.defaultPermissionMode ?? "standard",
423998
424082
  allowed_channels: serializeAllowedChannels(account.allowedChannels),
424083
+ allow_bots: account.allowBots ?? false,
423999
424084
  transcribe_voice: account.transcribeVoice === true,
424000
424085
  auto_thread_on_mention: account.autoThreadOnMention ?? false,
424001
424086
  thread_policy_by_channel: account.threadPolicyByChannel ?? {},
@@ -424561,6 +424646,7 @@ function createAccountFromPatch(channelId, accountId, patch2) {
424561
424646
  allowedChannels: normalizedPatch.allowedChannels ?? [],
424562
424647
  autoThreadOnMention: normalizedPatch.autoThreadOnMention ?? false,
424563
424648
  threadPolicyByChannel: normalizedPatch.threadPolicyByChannel,
424649
+ allowBots: normalizedPatch.allowBots ?? false,
424564
424650
  acknowledgeMessageReaction: normalizedPatch.acknowledgeMessageReaction,
424565
424651
  removeStaleRoutes: normalizedPatch.removeStaleRoutes,
424566
424652
  inboundDebounceMs: normalizedPatch.inboundDebounceMs,
@@ -424676,6 +424762,7 @@ function mergeAccountPatch(existing, patch2) {
424676
424762
  allowedChannels: normalizedPatch.allowedChannels ?? existing.allowedChannels,
424677
424763
  autoThreadOnMention: normalizedPatch.autoThreadOnMention ?? existing.autoThreadOnMention,
424678
424764
  threadPolicyByChannel: normalizedPatch.threadPolicyByChannel ?? existing.threadPolicyByChannel,
424765
+ allowBots: normalizedPatch.allowBots ?? existing.allowBots ?? false,
424679
424766
  acknowledgeMessageReaction: normalizedPatch.acknowledgeMessageReaction ?? existing.acknowledgeMessageReaction,
424680
424767
  removeStaleRoutes: normalizedPatch.removeStaleRoutes ?? existing.removeStaleRoutes,
424681
424768
  inboundDebounceMs: normalizedPatch.inboundDebounceMs ?? existing.inboundDebounceMs,
@@ -424841,6 +424928,7 @@ function toAccountSnapshot(account) {
424841
424928
  autoThreadOnMention: account.autoThreadOnMention ?? false,
424842
424929
  threadPolicyByChannel: account.threadPolicyByChannel ?? {},
424843
424930
  acknowledgeMessageReaction: account.acknowledgeMessageReaction ?? false,
424931
+ allowBots: account.allowBots ?? false,
424844
424932
  removeStaleRoutes: account.removeStaleRoutes ?? false,
424845
424933
  inboundDebounceMs: account.inboundDebounceMs,
424846
424934
  createdAt: account.createdAt,
@@ -425006,6 +425094,7 @@ function getChannelConfigSnapshot(channelId, accountId) {
425006
425094
  autoThreadOnMention: account.autoThreadOnMention ?? false,
425007
425095
  threadPolicyByChannel: account.threadPolicyByChannel ?? {},
425008
425096
  acknowledgeMessageReaction: account.acknowledgeMessageReaction ?? false,
425097
+ allowBots: account.allowBots ?? false,
425009
425098
  removeStaleRoutes: account.removeStaleRoutes ?? false,
425010
425099
  inboundDebounceMs: account.inboundDebounceMs
425011
425100
  };
@@ -446603,6 +446692,40 @@ function getPageItems(page) {
446603
446692
  }
446604
446693
  return [];
446605
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
+ }
446606
446729
  async function handleAgentConversationManagementCommand(parsed, socket, safeSocketSend) {
446607
446730
  const backend3 = getBackend();
446608
446731
  if (parsed.type === "agent_list") {
@@ -446835,12 +446958,14 @@ async function handleAgentConversationManagementCommand(parsed, socket, safeSock
446835
446958
  }
446836
446959
  if (parsed.type === "conversation_messages_list") {
446837
446960
  try {
446838
- const page = await backend3.listConversationMessages(parsed.conversation_id, parsed.query);
446961
+ const page = await listConversationMessagePage(backend3, parsed.conversation_id, parsed.query);
446839
446962
  safeSocketSend(socket, {
446840
446963
  type: "conversation_messages_list_response",
446841
446964
  request_id: parsed.request_id,
446842
446965
  success: true,
446843
- messages: getPageItems(page)
446966
+ messages: page.messages,
446967
+ next_before: page.nextBefore,
446968
+ has_more: page.hasMore
446844
446969
  }, "listener_conversation_management_send_failed", "listener_conversation_management");
446845
446970
  } catch (error54) {
446846
446971
  safeSocketSend(socket, {
@@ -446848,6 +446973,8 @@ async function handleAgentConversationManagementCommand(parsed, socket, safeSock
446848
446973
  request_id: parsed.request_id,
446849
446974
  success: false,
446850
446975
  messages: [],
446976
+ next_before: null,
446977
+ has_more: false,
446851
446978
  error: getErrorMessage4(error54, "Failed to list conversation messages")
446852
446979
  }, "listener_conversation_management_send_failed", "listener_conversation_management");
446853
446980
  }
@@ -448784,7 +448911,7 @@ function normalizeCatalogSource(source2) {
448784
448911
  return source2.trim().replace(/\/+$/, "");
448785
448912
  }
448786
448913
  }
448787
- function isNonEmptyString8(value) {
448914
+ function isNonEmptyString9(value) {
448788
448915
  return typeof value === "string" && value.length > 0;
448789
448916
  }
448790
448917
  function isPositiveFiniteNumber(value) {
@@ -448805,13 +448932,13 @@ function isRecord9(value) {
448805
448932
  function hasEntryIdentity(entry) {
448806
448933
  if (!isRecord9(entry))
448807
448934
  return false;
448808
- return isNonEmptyString8(entry.id) && isNonEmptyString8(entry.handle) && isNonEmptyString8(entry.label);
448935
+ return isNonEmptyString9(entry.id) && isNonEmptyString9(entry.handle) && isNonEmptyString9(entry.label);
448809
448936
  }
448810
448937
  function isValidEntry(entry) {
448811
448938
  if (!hasEntryIdentity(entry))
448812
448939
  return false;
448813
448940
  const candidate = entry;
448814
- 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));
448815
448942
  }
448816
448943
  function isValidCachedModel(entry) {
448817
448944
  if (!hasEntryIdentity(entry))
@@ -451468,11 +451595,11 @@ function hasExistingOtidAlias(aliasMap, canonical, nextOtid) {
451468
451595
  return false;
451469
451596
  }
451470
451597
  function resolveAssistantLineId(b3, chunk) {
451471
- const messageId = typeof chunk.id === "string" ? chunk.id : undefined;
451598
+ const messageId2 = typeof chunk.id === "string" ? chunk.id : undefined;
451472
451599
  const otid = typeof chunk.otid === "string" ? chunk.otid : undefined;
451473
- const canonicalFromMessageId = messageId ? b3.assistantCanonicalByMessageId.get(messageId) : undefined;
451600
+ const canonicalFromMessageId = messageId2 ? b3.assistantCanonicalByMessageId.get(messageId2) : undefined;
451474
451601
  const canonicalFromOtid = otid ? b3.assistantCanonicalByOtid.get(otid) : undefined;
451475
- let canonical = canonicalFromMessageId || canonicalFromOtid || messageId || otid;
451602
+ let canonical = canonicalFromMessageId || canonicalFromOtid || messageId2 || otid;
451476
451603
  if (!canonical)
451477
451604
  return;
451478
451605
  if (otid && !canonicalFromOtid && canonicalFromMessageId) {
@@ -451495,27 +451622,27 @@ function resolveAssistantLineId(b3, chunk) {
451495
451622
  }
451496
451623
  debugLog("accumulator", `Assistant id/otid alias conflict resolved to ${canonical}`);
451497
451624
  }
451498
- if (messageId) {
451499
- b3.assistantCanonicalByMessageId.set(messageId, canonical);
451625
+ if (messageId2) {
451626
+ b3.assistantCanonicalByMessageId.set(messageId2, canonical);
451500
451627
  }
451501
451628
  if (otid) {
451502
451629
  b3.assistantCanonicalByOtid.set(otid, canonical);
451503
451630
  }
451504
451631
  const lineId = resolveLineIdForKind(b3, canonical, "assistant");
451505
451632
  if (lineId !== canonical) {
451506
- if (messageId)
451507
- b3.assistantCanonicalByMessageId.set(messageId, lineId);
451633
+ if (messageId2)
451634
+ b3.assistantCanonicalByMessageId.set(messageId2, lineId);
451508
451635
  if (otid)
451509
451636
  b3.assistantCanonicalByOtid.set(otid, lineId);
451510
451637
  }
451511
451638
  return lineId;
451512
451639
  }
451513
451640
  function resolveReasoningLineId(b3, chunk) {
451514
- const messageId = typeof chunk.id === "string" ? chunk.id : undefined;
451641
+ const messageId2 = typeof chunk.id === "string" ? chunk.id : undefined;
451515
451642
  const otid = typeof chunk.otid === "string" ? chunk.otid : undefined;
451516
- const canonicalFromMessageId = messageId ? b3.reasoningCanonicalByMessageId.get(messageId) : undefined;
451643
+ const canonicalFromMessageId = messageId2 ? b3.reasoningCanonicalByMessageId.get(messageId2) : undefined;
451517
451644
  const canonicalFromOtid = otid ? b3.reasoningCanonicalByOtid.get(otid) : undefined;
451518
- let canonical = canonicalFromMessageId || canonicalFromOtid || messageId || otid;
451645
+ let canonical = canonicalFromMessageId || canonicalFromOtid || messageId2 || otid;
451519
451646
  if (!canonical)
451520
451647
  return;
451521
451648
  if (otid && !canonicalFromOtid && canonicalFromMessageId) {
@@ -451538,16 +451665,16 @@ function resolveReasoningLineId(b3, chunk) {
451538
451665
  }
451539
451666
  debugLog("accumulator", `Reasoning id/otid alias conflict resolved to ${canonical}`);
451540
451667
  }
451541
- if (messageId) {
451542
- b3.reasoningCanonicalByMessageId.set(messageId, canonical);
451668
+ if (messageId2) {
451669
+ b3.reasoningCanonicalByMessageId.set(messageId2, canonical);
451543
451670
  }
451544
451671
  if (otid) {
451545
451672
  b3.reasoningCanonicalByOtid.set(otid, canonical);
451546
451673
  }
451547
451674
  const lineId = resolveLineIdForKind(b3, canonical, "reasoning");
451548
451675
  if (lineId !== canonical) {
451549
- if (messageId)
451550
- b3.reasoningCanonicalByMessageId.set(messageId, lineId);
451676
+ if (messageId2)
451677
+ b3.reasoningCanonicalByMessageId.set(messageId2, lineId);
451551
451678
  if (otid)
451552
451679
  b3.reasoningCanonicalByOtid.set(otid, lineId);
451553
451680
  }
@@ -451605,13 +451732,13 @@ function onChunk(b3, chunk, ctx) {
451605
451732
  }
451606
451733
  handleOtidTransition(b3, id2);
451607
451734
  const delta2 = chunk.reasoning;
451608
- const messageId = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451735
+ const messageId2 = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451609
451736
  const line = ensure(b3, id2, () => ({
451610
451737
  kind: "reasoning",
451611
451738
  id: id2,
451612
451739
  text: "",
451613
451740
  phase: "streaming",
451614
- messageId
451741
+ messageId: messageId2
451615
451742
  }));
451616
451743
  if (delta2) {
451617
451744
  const newText = normalizeReasoningSectionBoundaries(line.text + delta2);
@@ -451620,11 +451747,11 @@ function onChunk(b3, chunk, ctx) {
451620
451747
  b3.byId.set(id2, {
451621
451748
  ...line,
451622
451749
  text: newText,
451623
- messageId: messageId ?? line.messageId
451750
+ messageId: messageId2 ?? line.messageId
451624
451751
  });
451625
451752
  }
451626
- } else if (messageId && line.messageId !== messageId) {
451627
- b3.byId.set(id2, { ...line, messageId });
451753
+ } else if (messageId2 && line.messageId !== messageId2) {
451754
+ b3.byId.set(id2, { ...line, messageId: messageId2 });
451628
451755
  }
451629
451756
  break;
451630
451757
  }
@@ -451635,13 +451762,13 @@ function onChunk(b3, chunk, ctx) {
451635
451762
  break;
451636
451763
  handleOtidTransition(b3, id2);
451637
451764
  const delta2 = extractTextPart(chunk.content);
451638
- const messageId = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451765
+ const messageId2 = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451639
451766
  const line = ensure(b3, id2, () => ({
451640
451767
  kind: "assistant",
451641
451768
  id: id2,
451642
451769
  text: "",
451643
451770
  phase: "streaming",
451644
- messageId
451771
+ messageId: messageId2
451645
451772
  }));
451646
451773
  if (delta2) {
451647
451774
  const newText = line.text + delta2;
@@ -451650,20 +451777,20 @@ function onChunk(b3, chunk, ctx) {
451650
451777
  b3.byId.set(id2, {
451651
451778
  ...line,
451652
451779
  text: newText,
451653
- messageId: messageId ?? line.messageId
451780
+ messageId: messageId2 ?? line.messageId
451654
451781
  });
451655
451782
  }
451656
- } else if (messageId && line.messageId !== messageId) {
451657
- b3.byId.set(id2, { ...line, messageId });
451783
+ } else if (messageId2 && line.messageId !== messageId2) {
451784
+ b3.byId.set(id2, { ...line, messageId: messageId2 });
451658
451785
  }
451659
451786
  break;
451660
451787
  }
451661
451788
  case "user_message": {
451662
451789
  const chunkWithIds = chunk;
451663
- const messageId = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451790
+ const messageId2 = typeof chunkWithIds.id === "string" ? chunkWithIds.id : undefined;
451664
451791
  const otid = typeof chunkWithIds.otid === "string" ? chunkWithIds.otid : undefined;
451665
451792
  const mappedLineId = otid ? b3.userLineIdByOtid.get(otid) : undefined;
451666
- const lineId = mappedLineId || otid || messageId;
451793
+ const lineId = mappedLineId || otid || messageId2;
451667
451794
  if (!lineId)
451668
451795
  break;
451669
451796
  handleOtidTransition(b3, lineId);
@@ -451687,14 +451814,14 @@ function onChunk(b3, chunk, ctx) {
451687
451814
  kind: "user",
451688
451815
  id: lineId,
451689
451816
  text: rawText,
451690
- messageId,
451817
+ messageId: messageId2,
451691
451818
  otid
451692
451819
  }));
451693
451820
  if (line.kind === "user") {
451694
451821
  b3.byId.set(lineId, {
451695
451822
  ...line,
451696
451823
  text: line.text || rawText,
451697
- messageId: messageId ?? line.messageId,
451824
+ messageId: messageId2 ?? line.messageId,
451698
451825
  otid: otid ?? line.otid
451699
451826
  });
451700
451827
  }
@@ -499514,6 +499641,8 @@ function ModelSelector({
499514
499641
  const [byokProviderAliases, setByokProviderAliases] = import_react91.useState(() => buildByokProviderAliases([]));
499515
499642
  const [openAICompatibleProxyHandles, setOpenAICompatibleProxyHandles] = import_react91.useState(() => getCachedOpenAICompatibleProxyHandles() ?? new Set);
499516
499643
  const [openAICompatibleProxyProviders, setOpenAICompatibleProxyProviders] = import_react91.useState(new Set);
499644
+ const providerRegistryRevision = import_react91.useSyncExternalStore(subscribePiProviderRegistry, getPiProviderRegistryRevision, getPiProviderRegistryRevision);
499645
+ const previousProviderRegistryRevision = import_react91.useRef(providerRegistryRevision);
499517
499646
  const mountedRef = import_react91.useRef(true);
499518
499647
  import_react91.useEffect(() => {
499519
499648
  mountedRef.current = true;
@@ -499576,8 +499705,12 @@ function ModelSelector({
499576
499705
  }
499577
499706
  });
499578
499707
  import_react91.useEffect(() => {
499708
+ if (previousProviderRegistryRevision.current !== providerRegistryRevision) {
499709
+ previousProviderRegistryRevision.current = providerRegistryRevision;
499710
+ clearAvailableModelsCache();
499711
+ }
499579
499712
  loadModels.current(forceRefreshOnMount ?? false);
499580
- }, [forceRefreshOnMount]);
499713
+ }, [forceRefreshOnMount, providerRegistryRevision]);
499581
499714
  import_react91.useEffect(() => {
499582
499715
  if (localModelCatalog) {
499583
499716
  setByokProviderAliases(buildByokProviderAliases([]));
@@ -500263,6 +500396,7 @@ var init_ModelSelector = __esm(async () => {
500263
500396
  init_available_models();
500264
500397
  init_model();
500265
500398
  init_remote_model_catalog();
500399
+ init_pi_provider_mod_registry();
500266
500400
  init_byok_providers();
500267
500401
  init_settings_manager();
500268
500402
  init_colors();
@@ -500549,8 +500683,9 @@ function ProviderSelector({
500549
500683
  const [awsProfiles, setAwsProfiles] = import_react94.useState([]);
500550
500684
  const [profileIndex, setProfileIndex] = import_react94.useState(0);
500551
500685
  const [isLoadingProfiles, setIsLoadingProfiles] = import_react94.useState(false);
500552
- const providers = import_react94.useMemo(() => getProviderConfigs(selectedTarget), [selectedTarget]);
500553
- const filteredProviders = import_react94.useMemo(() => filterProviderConfigs(providers, searchQuery), [providers, searchQuery]);
500686
+ import_react94.useSyncExternalStore(subscribePiProviderRegistry, getPiProviderRegistryRevision, getPiProviderRegistryRevision);
500687
+ const providers = getProviderConfigs(selectedTarget);
500688
+ const filteredProviders = filterProviderConfigs(providers, searchQuery);
500554
500689
  const showProviderStoreTabs = shouldShowProviderStoreTabs(hasCloudCredentials2);
500555
500690
  const connectedProviders = import_react94.useMemo(() => connectedProvidersByTarget[selectedTarget] ?? new Map, [connectedProvidersByTarget, selectedTarget]);
500556
500691
  const isLoading = isProviderTargetLoading({
@@ -501824,6 +501959,7 @@ function ProviderSelector({
501824
501959
  var import_react94, jsx_dev_runtime70, SOLID_LINE17 = "─", VISIBLE_PROVIDERS = 8;
501825
501960
  var init_ProviderSelector = __esm(async () => {
501826
501961
  init_available_models();
501962
+ init_pi_provider_mod_registry();
501827
501963
  init_use_terminal_width();
501828
501964
  init_byok_providers();
501829
501965
  init_chatgpt_usage_service();
@@ -541297,4 +541433,4 @@ function registerBunOAuthFlows() {
541297
541433
  registerBunOAuthFlows();
541298
541434
  await init_src5().then(() => exports_src2);
541299
541435
 
541300
- //# debugId=D4FE51D0A61DE3F364756E2164756E21
541436
+ //# debugId=EDD0BAA906B8C7B064756E2164756E21