@letta-ai/letta-code 0.30.24 → 0.30.26

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 (55) hide show
  1. package/dist/agent-presets.js +1 -339
  2. package/dist/agent-presets.js.map +2 -2
  3. package/dist/channels-slack.js +319 -41
  4. package/dist/channels-slack.js.map +4 -3
  5. package/dist/channels-telegram.js +424 -0
  6. package/dist/channels-telegram.js.map +14 -0
  7. package/dist/mcp-client.js +2 -2
  8. package/dist/mcp-client.js.map +1 -1
  9. package/dist/types/agent/client-skills-watcher.d.ts +23 -0
  10. package/dist/types/agent/client-skills-watcher.d.ts.map +1 -0
  11. package/dist/types/agent/client-skills.d.ts.map +1 -1
  12. package/dist/types/agent/modify.d.ts.map +1 -1
  13. package/dist/types/backend/dev/pi-model-factory.d.ts.map +1 -1
  14. package/dist/types/channels/slack/attachment-primitives.d.ts +69 -0
  15. package/dist/types/channels/slack/attachment-primitives.d.ts.map +1 -0
  16. package/dist/types/channels/telegram/debounce.d.ts +22 -0
  17. package/dist/types/channels/telegram/debounce.d.ts.map +1 -0
  18. package/dist/types/channels/telegram/ingress.d.ts +35 -0
  19. package/dist/types/channels/telegram/ingress.d.ts.map +1 -0
  20. package/dist/types/channels/telegram/message-action-contract.d.ts +16 -0
  21. package/dist/types/channels/telegram/message-action-contract.d.ts.map +1 -0
  22. package/dist/types/channels/telegram/message-shapes.d.ts +154 -0
  23. package/dist/types/channels/telegram/message-shapes.d.ts.map +1 -0
  24. package/dist/types/channels/telegram/outbound.d.ts +21 -0
  25. package/dist/types/channels/telegram/outbound.d.ts.map +1 -0
  26. package/dist/types/channels-slack.d.ts +2 -0
  27. package/dist/types/channels-slack.d.ts.map +1 -1
  28. package/dist/types/channels-telegram.d.ts +20 -0
  29. package/dist/types/channels-telegram.d.ts.map +1 -0
  30. package/dist/types/cli/helpers/stream-debug.d.ts +6 -0
  31. package/dist/types/cli/helpers/stream-debug.d.ts.map +1 -0
  32. package/dist/types/cli/helpers/stream-stall-reconciler.d.ts +16 -0
  33. package/dist/types/cli/helpers/stream-stall-reconciler.d.ts.map +1 -0
  34. package/dist/types/cli/helpers/stream.d.ts +1 -0
  35. package/dist/types/cli/helpers/stream.d.ts.map +1 -1
  36. package/dist/types/tools/impl/bash.d.ts.map +1 -1
  37. package/dist/types/tools/impl/exec-command.d.ts +1 -0
  38. package/dist/types/tools/impl/exec-command.d.ts.map +1 -1
  39. package/dist/types/tools/impl/github-pull-request-tracker.d.ts +2 -0
  40. package/dist/types/tools/impl/github-pull-request-tracker.d.ts.map +1 -1
  41. package/dist/types/tools/impl/monitor.d.ts.map +1 -1
  42. package/dist/types/tools/impl/process_manager.d.ts +7 -1
  43. package/dist/types/tools/impl/process_manager.d.ts.map +1 -1
  44. package/dist/types/tools/impl/task.d.ts +2 -0
  45. package/dist/types/tools/impl/task.d.ts.map +1 -1
  46. package/dist/types/utils/openai-reasoning-effort.d.ts +6 -0
  47. package/dist/types/utils/openai-reasoning-effort.d.ts.map +1 -0
  48. package/dist/types/websocket/listener/constants.d.ts +0 -2
  49. package/dist/types/websocket/listener/constants.d.ts.map +1 -1
  50. package/dist/types/websocket/listener/types.d.ts +3 -0
  51. package/dist/types/websocket/listener/types.d.ts.map +1 -1
  52. package/letta.js +2741 -2642
  53. package/package.json +12 -1
  54. package/scripts/source-file-size-baseline.json +6 -7
  55. package/skills/teleporting-between-environments/SKILL.md +23 -9
@@ -1,17 +1,291 @@
1
+ // src/channels/slack/attachment-primitives.ts
2
+ var MAX_SLACK_ATTACHMENTS = 8;
3
+ var ALLOWED_SLACK_HOST_SUFFIXES = [
4
+ "slack.com",
5
+ "slack-edge.com",
6
+ "slack-files.com"
7
+ ];
8
+ function asRecord(value) {
9
+ return value && typeof value === "object" ? value : null;
10
+ }
11
+ function isNonEmptyString(value) {
12
+ return typeof value === "string" && value.trim().length > 0;
13
+ }
14
+ function normalizeSlackFileLike(value) {
15
+ const record = asRecord(value);
16
+ if (!record)
17
+ return null;
18
+ return {
19
+ id: isNonEmptyString(record.id) ? record.id : undefined,
20
+ name: isNonEmptyString(record.name) ? record.name : undefined,
21
+ mimetype: isNonEmptyString(record.mimetype) ? record.mimetype : undefined,
22
+ size: typeof record.size === "number" ? record.size : undefined,
23
+ url_private: isNonEmptyString(record.url_private) ? record.url_private : undefined,
24
+ url_private_download: isNonEmptyString(record.url_private_download) ? record.url_private_download : undefined
25
+ };
26
+ }
27
+ function normalizeSlackAttachmentLike(value) {
28
+ const record = asRecord(value);
29
+ if (!record)
30
+ return null;
31
+ const files = Array.isArray(record.files) ? record.files.map((entry) => normalizeSlackFileLike(entry)).filter((entry) => Boolean(entry)) : undefined;
32
+ return {
33
+ image_url: isNonEmptyString(record.image_url) ? record.image_url : undefined,
34
+ files
35
+ };
36
+ }
37
+ function collectSlackFiles(rawEvent) {
38
+ const record = asRecord(rawEvent);
39
+ if (!record)
40
+ return [];
41
+ const deduped = new Map;
42
+ const push = (file) => {
43
+ if (!file)
44
+ return;
45
+ const key = file.id ?? file.url_private_download ?? file.url_private ?? `${file.name ?? "attachment"}:${file.mimetype ?? ""}`;
46
+ deduped.set(key, file);
47
+ };
48
+ if (Array.isArray(record.files)) {
49
+ for (const entry of record.files)
50
+ push(normalizeSlackFileLike(entry));
51
+ }
52
+ if (Array.isArray(record.attachments)) {
53
+ record.attachments.map((entry) => normalizeSlackAttachmentLike(entry)).filter((entry) => Boolean(entry)).forEach((attachment, index) => {
54
+ for (const file of attachment.files ?? [])
55
+ push(file);
56
+ if (attachment.image_url) {
57
+ push({
58
+ id: `attachment-image-${index}`,
59
+ name: `attachment-image-${index}.png`,
60
+ url_private: attachment.image_url
61
+ });
62
+ }
63
+ });
64
+ }
65
+ return Array.from(deduped.values()).slice(0, MAX_SLACK_ATTACHMENTS);
66
+ }
67
+ function nextCursor(page) {
68
+ const value = page.response_metadata?.next_cursor;
69
+ return isNonEmptyString(value) ? value.trim() : undefined;
70
+ }
71
+ async function resolveSlackMessageFiles(params) {
72
+ if (isNonEmptyString(params.threadTs)) {
73
+ let cursor;
74
+ do {
75
+ const page2 = await params.client.conversations.replies({
76
+ channel: params.channelId,
77
+ ts: params.threadTs,
78
+ limit: 200,
79
+ inclusive: true,
80
+ ...cursor ? { cursor } : {}
81
+ });
82
+ const message2 = (page2.messages ?? []).find((entry) => entry.ts === params.messageTs);
83
+ if (message2)
84
+ return collectSlackFiles(message2);
85
+ cursor = nextCursor(page2);
86
+ } while (cursor);
87
+ return null;
88
+ }
89
+ const page = await params.client.conversations.history({
90
+ channel: params.channelId,
91
+ oldest: params.messageTs,
92
+ latest: params.messageTs,
93
+ inclusive: true,
94
+ limit: 1
95
+ });
96
+ const message = (page.messages ?? []).find((entry) => entry.ts === params.messageTs);
97
+ return message ? collectSlackFiles(message) : null;
98
+ }
99
+ function isAllowedSlackHostname(hostname) {
100
+ const normalized = hostname.trim().toLowerCase();
101
+ return ALLOWED_SLACK_HOST_SUFFIXES.some((suffix) => normalized === suffix || normalized.endsWith(`.${suffix}`));
102
+ }
103
+ function assertSlackFileUrl(rawUrl) {
104
+ const parsed = new URL(rawUrl);
105
+ if (parsed.protocol !== "https:") {
106
+ throw new Error(`Unsupported Slack file protocol: ${parsed.protocol}`);
107
+ }
108
+ if (!isAllowedSlackHostname(parsed.hostname)) {
109
+ throw new Error(`Refusing non-Slack attachment host: ${parsed.hostname}`);
110
+ }
111
+ return parsed;
112
+ }
113
+ function extensionForMimeType(mimeType) {
114
+ switch (mimeType?.toLowerCase()) {
115
+ case "image/png":
116
+ return ".png";
117
+ case "image/jpeg":
118
+ return ".jpg";
119
+ case "image/gif":
120
+ return ".gif";
121
+ case "image/webp":
122
+ return ".webp";
123
+ case "audio/aac":
124
+ return ".aac";
125
+ case "audio/m4a":
126
+ case "audio/mp4":
127
+ case "audio/x-m4a":
128
+ return ".m4a";
129
+ case "audio/mpeg":
130
+ return ".mp3";
131
+ case "audio/ogg":
132
+ return ".ogg";
133
+ case "audio/wav":
134
+ case "audio/x-wav":
135
+ return ".wav";
136
+ case "audio/webm":
137
+ return ".webm";
138
+ case "application/pdf":
139
+ return ".pdf";
140
+ case "text/plain":
141
+ return ".txt";
142
+ default:
143
+ return "";
144
+ }
145
+ }
146
+ function pathBaseName(pathname) {
147
+ const trimmed = pathname.replace(/\/+$/, "");
148
+ const separator = trimmed.lastIndexOf("/");
149
+ return trimmed.slice(separator + 1);
150
+ }
151
+ function extensionName(name) {
152
+ const base = pathBaseName(name);
153
+ if (base === "..")
154
+ return "";
155
+ const index = base.lastIndexOf(".");
156
+ return index > 0 ? base.slice(index) : "";
157
+ }
158
+ function resolveMimeType(name, fallback) {
159
+ if (fallback)
160
+ return fallback;
161
+ switch (extensionName(name).toLowerCase()) {
162
+ case ".png":
163
+ return "image/png";
164
+ case ".jpg":
165
+ case ".jpeg":
166
+ return "image/jpeg";
167
+ case ".gif":
168
+ return "image/gif";
169
+ case ".webp":
170
+ return "image/webp";
171
+ case ".aac":
172
+ return "audio/aac";
173
+ case ".m4a":
174
+ return "audio/mp4";
175
+ case ".mp3":
176
+ return "audio/mpeg";
177
+ case ".oga":
178
+ case ".ogg":
179
+ case ".opus":
180
+ return "audio/ogg";
181
+ case ".wav":
182
+ return "audio/wav";
183
+ case ".webm":
184
+ return "audio/webm";
185
+ case ".pdf":
186
+ return "application/pdf";
187
+ case ".txt":
188
+ case ".md":
189
+ return "text/plain";
190
+ default:
191
+ return;
192
+ }
193
+ }
194
+ function isGenericSlackMimeType(mimeType) {
195
+ const normalized = mimeType?.trim().toLowerCase();
196
+ return normalized === "application/octet-stream" || normalized === "binary/octet-stream";
197
+ }
198
+ function resolveSlackFileName(params) {
199
+ const hintedName = params.file.name ?? (params.url ? pathBaseName(new URL(params.url).pathname) : undefined) ?? `${params.file.id ?? "attachment"}${extensionForMimeType(params.file.mimetype)}`;
200
+ return extensionName(hintedName) || !params.mimeType ? hintedName : `${hintedName}${extensionForMimeType(params.mimeType)}`;
201
+ }
202
+ function resolveSlackFileMimeType(params) {
203
+ const preferredMimeType = params.responseMimeType && !isGenericSlackMimeType(params.responseMimeType) ? params.responseMimeType : params.file.mimetype && !isGenericSlackMimeType(params.file.mimetype) ? params.file.mimetype : undefined;
204
+ return resolveMimeType(params.fileName, preferredMimeType);
205
+ }
206
+ function resolveSlackFileMetadata(params) {
207
+ const hintedName = resolveSlackFileName({
208
+ file: params.file,
209
+ url: params.url
210
+ });
211
+ const mimeType = resolveSlackFileMimeType({
212
+ file: params.file,
213
+ fileName: hintedName,
214
+ responseMimeType: params.responseMimeType
215
+ });
216
+ return {
217
+ fileName: resolveSlackFileName({
218
+ file: params.file,
219
+ url: params.url,
220
+ mimeType
221
+ }),
222
+ mimeType
223
+ };
224
+ }
225
+ function parseContentLength(response) {
226
+ const header = response.headers.get("content-length");
227
+ if (!header)
228
+ return;
229
+ const value = Number(header);
230
+ return Number.isFinite(value) ? value : undefined;
231
+ }
232
+ async function fetchSlackFile(params) {
233
+ const rawUrl = params.file.url_private_download ?? params.file.url_private;
234
+ if (!rawUrl) {
235
+ throw new Error("Slack attachment does not include a private download URL.");
236
+ }
237
+ const parsed = assertSlackFileUrl(rawUrl);
238
+ const fetcher = params.fetcher ?? globalThis.fetch;
239
+ const authHeaders = { Authorization: `Bearer ${params.token}` };
240
+ const initial = await fetcher(parsed.href, {
241
+ headers: authHeaders,
242
+ redirect: "manual",
243
+ ...params.signal ? { signal: params.signal } : {}
244
+ });
245
+ let response = initial;
246
+ if (initial.status >= 300 && initial.status < 400) {
247
+ const location = initial.headers.get("location");
248
+ if (location) {
249
+ const resolved = new URL(location, parsed.href);
250
+ response = await fetcher(resolved.href, {
251
+ ...resolved.origin === parsed.origin ? { headers: authHeaders } : {},
252
+ redirect: "follow",
253
+ ...params.signal ? { signal: params.signal } : {}
254
+ });
255
+ }
256
+ }
257
+ if (!response.ok) {
258
+ throw new Error(`Slack attachment fetch failed with HTTP ${response.status}.`);
259
+ }
260
+ if (!response.body) {
261
+ throw new Error("Slack attachment response did not include a body.");
262
+ }
263
+ const responseMimeType = response.headers.get("content-type")?.split(";")[0]?.trim() || undefined;
264
+ const metadata = resolveSlackFileMetadata({
265
+ file: params.file,
266
+ url: rawUrl,
267
+ responseMimeType
268
+ });
269
+ return {
270
+ body: response.body,
271
+ ...metadata,
272
+ contentLength: parseContentLength(response)
273
+ };
274
+ }
1
275
  // src/channels/slack/bot-policy.ts
2
276
  function resolveSlackAllowBotsMode(value) {
3
277
  if (value === "mentions")
4
278
  return "mentions";
5
279
  return "off";
6
280
  }
7
- function isNonEmptyString(value) {
281
+ function isNonEmptyString2(value) {
8
282
  return typeof value === "string" && value.length > 0;
9
283
  }
10
284
  function isSlackBotAuthoredInboundMessage(message) {
11
- return isNonEmptyString(message.bot_id) || message.subtype === "bot_message";
285
+ return isNonEmptyString2(message.bot_id) || message.subtype === "bot_message";
12
286
  }
13
287
  function isOwnSlackBotInboundMessage(params) {
14
- return isNonEmptyString(params.botUserId) && params.message.user === params.botUserId || isNonEmptyString(params.botId) && params.message.bot_id === params.botId;
288
+ return isNonEmptyString2(params.botUserId) && params.message.user === params.botUserId || isNonEmptyString2(params.botId) && params.message.bot_id === params.botId;
15
289
  }
16
290
  function shouldAcceptSlackInboundBotMessage(params) {
17
291
  if (isOwnSlackBotInboundMessage({
@@ -28,11 +302,11 @@ function shouldAcceptSlackInboundBotMessage(params) {
28
302
  return mode === "mentions" && params.wasMentioned;
29
303
  }
30
304
  // src/channels/slack/public-utils.ts
31
- function isNonEmptyString2(value) {
305
+ function isNonEmptyString3(value) {
32
306
  return typeof value === "string" && value.length > 0;
33
307
  }
34
308
  function firstNonEmptyString(...values) {
35
- return values.find(isNonEmptyString2);
309
+ return values.find(isNonEmptyString3);
36
310
  }
37
311
  function resolveSlackChatType(chatId) {
38
312
  return chatId.startsWith("D") ? "direct" : "channel";
@@ -189,13 +463,13 @@ function hasRecordValue(value) {
189
463
  return value !== null && typeof value === "object";
190
464
  }
191
465
  function hasSlackMention(text, userId) {
192
- return isNonEmptyString2(text) && isNonEmptyString2(userId) && (text.includes(`<@${userId}>`) || text.includes(`<@${userId}|`));
466
+ return isNonEmptyString3(text) && isNonEmptyString3(userId) && (text.includes(`<@${userId}>`) || text.includes(`<@${userId}|`));
193
467
  }
194
468
  function isBotAuthoredMessage(message) {
195
- return isNonEmptyString2(message.bot_id) || message.subtype === "bot_message";
469
+ return isNonEmptyString3(message.bot_id) || message.subtype === "bot_message";
196
470
  }
197
471
  function resolveMessageSubtypeIgnoreReason(message) {
198
- const subtype = isNonEmptyString2(message.subtype) ? message.subtype : null;
472
+ const subtype = isNonEmptyString3(message.subtype) ? message.subtype : null;
199
473
  if (!subtype) {
200
474
  return null;
201
475
  }
@@ -215,14 +489,14 @@ function shouldSkipSlackMessageByLastSeen(params) {
215
489
  }
216
490
  function resolveSlackMessageIngressPolicy(params) {
217
491
  const { message } = params;
218
- if (!isNonEmptyString2(message.channel)) {
492
+ if (!isNonEmptyString3(message.channel)) {
219
493
  return { shouldRoute: false, reason: "missing_channel" };
220
494
  }
221
495
  const senderId = firstNonEmptyString(message.user, message.bot_id);
222
496
  if (!senderId) {
223
497
  return { shouldRoute: false, reason: "missing_sender" };
224
498
  }
225
- if (!isNonEmptyString2(message.ts)) {
499
+ if (!isNonEmptyString3(message.ts)) {
226
500
  return { shouldRoute: false, reason: "missing_timestamp" };
227
501
  }
228
502
  if (message.hidden === true) {
@@ -234,10 +508,10 @@ function resolveSlackMessageIngressPolicy(params) {
234
508
  }
235
509
  const chatType = resolveSlackChatType(message.channel);
236
510
  const threadId = chatType === "direct" ? firstNonEmptyString(message.thread_ts) ?? null : firstNonEmptyString(message.thread_ts, message.ts) ?? null;
237
- if (chatType === "channel" && !isNonEmptyString2(message.thread_ts)) {
511
+ if (chatType === "channel" && !isNonEmptyString3(message.thread_ts)) {
238
512
  return { shouldRoute: false, reason: "top_level_channel_message" };
239
513
  }
240
- const rawText = isNonEmptyString2(message.text) ? message.text : "";
514
+ const rawText = isNonEmptyString3(message.text) ? message.text : "";
241
515
  const wasMentioned = hasSlackMention(rawText, params.botUserId);
242
516
  if (chatType === "channel" && wasMentioned && params.appMentionEventWillHandleMentions === true) {
243
517
  return { shouldRoute: false, reason: "handled_by_app_mention" };
@@ -248,8 +522,8 @@ function resolveSlackMessageIngressPolicy(params) {
248
522
  shouldRoute: true,
249
523
  channelId: message.channel,
250
524
  senderId,
251
- ...isNonEmptyString2(message.user) ? { senderUserId: message.user } : {},
252
- ...isNonEmptyString2(message.bot_id) ? { senderBotId: message.bot_id } : {},
525
+ ...isNonEmptyString3(message.user) ? { senderUserId: message.user } : {},
526
+ ...isNonEmptyString3(message.bot_id) ? { senderBotId: message.bot_id } : {},
253
527
  messageId: message.ts,
254
528
  threadId,
255
529
  chatType,
@@ -263,23 +537,23 @@ function resolveSlackMessageIngressPolicy(params) {
263
537
  }
264
538
  function resolveSlackAppMentionIngressPolicy(params) {
265
539
  const { event } = params;
266
- if (!isNonEmptyString2(event.channel)) {
540
+ if (!isNonEmptyString3(event.channel)) {
267
541
  return { shouldRoute: false, reason: "missing_channel" };
268
542
  }
269
543
  const senderId = firstNonEmptyString(event.user, event.bot_id);
270
544
  if (!senderId) {
271
545
  return { shouldRoute: false, reason: "missing_sender" };
272
546
  }
273
- if (!isNonEmptyString2(event.ts)) {
547
+ if (!isNonEmptyString3(event.ts)) {
274
548
  return { shouldRoute: false, reason: "missing_timestamp" };
275
549
  }
276
- const rawText = isNonEmptyString2(event.text) ? event.text : "";
550
+ const rawText = isNonEmptyString3(event.text) ? event.text : "";
277
551
  return {
278
552
  shouldRoute: true,
279
553
  channelId: event.channel,
280
554
  senderId,
281
- ...isNonEmptyString2(event.user) ? { senderUserId: event.user } : {},
282
- ...isNonEmptyString2(event.bot_id) ? { senderBotId: event.bot_id } : {},
555
+ ...isNonEmptyString3(event.user) ? { senderUserId: event.user } : {},
556
+ ...isNonEmptyString3(event.bot_id) ? { senderBotId: event.bot_id } : {},
283
557
  messageId: event.ts,
284
558
  threadId: firstNonEmptyString(event.thread_ts, event.ts) ?? event.ts,
285
559
  chatType: "channel",
@@ -296,16 +570,16 @@ function resolveSlackReactionIngressPolicy(params) {
296
570
  if (item?.type !== "message") {
297
571
  return { shouldRoute: false, reason: "invalid_reaction_item" };
298
572
  }
299
- if (!isNonEmptyString2(item.channel)) {
573
+ if (!isNonEmptyString3(item.channel)) {
300
574
  return { shouldRoute: false, reason: "missing_channel" };
301
575
  }
302
- if (!isNonEmptyString2(params.event.user)) {
576
+ if (!isNonEmptyString3(params.event.user)) {
303
577
  return { shouldRoute: false, reason: "missing_sender" };
304
578
  }
305
- if (!isNonEmptyString2(item.ts)) {
579
+ if (!isNonEmptyString3(item.ts)) {
306
580
  return { shouldRoute: false, reason: "missing_timestamp" };
307
581
  }
308
- if (!isNonEmptyString2(params.event.reaction)) {
582
+ if (!isNonEmptyString3(params.event.reaction)) {
309
583
  return { shouldRoute: false, reason: "missing_reaction" };
310
584
  }
311
585
  if (params.event.user === params.botUserId) {
@@ -322,7 +596,7 @@ function resolveSlackReactionIngressPolicy(params) {
322
596
  action: params.action,
323
597
  emoji: params.event.reaction,
324
598
  targetMessageId,
325
- ...isNonEmptyString2(params.event.item_user) ? { targetSenderId: params.event.item_user } : {}
599
+ ...isNonEmptyString3(params.event.item_user) ? { targetSenderId: params.event.item_user } : {}
326
600
  };
327
601
  return {
328
602
  shouldRoute: true,
@@ -481,13 +755,13 @@ function getFallbackModelEntries(byHandle) {
481
755
  }
482
756
 
483
757
  // src/channels/slack/utils.ts
484
- function isNonEmptyString3(value) {
758
+ function isNonEmptyString4(value) {
485
759
  return typeof value === "string" && value.length > 0;
486
760
  }
487
761
  function firstNonEmptyString2(...values) {
488
- return values.find(isNonEmptyString3);
762
+ return values.find(isNonEmptyString4);
489
763
  }
490
- function asRecord(value) {
764
+ function asRecord2(value) {
491
765
  return value && typeof value === "object" ? value : null;
492
766
  }
493
767
  var IGNORED_SLACK_MESSAGE_SUBTYPES2 = new Set([
@@ -522,12 +796,12 @@ var WRAPPER_SLACK_MESSAGE_SUBTYPES2 = new Set([
522
796
  "message_replied"
523
797
  ]);
524
798
  function getSlackActionRecord(action, body) {
525
- const directAction = asRecord(action);
799
+ const directAction = asRecord2(action);
526
800
  if (directAction) {
527
801
  return directAction;
528
802
  }
529
- const actions = asRecord(body)?.actions;
530
- return Array.isArray(actions) ? asRecord(actions[0]) : null;
803
+ const actions = asRecord2(body)?.actions;
804
+ return Array.isArray(actions) ? asRecord2(actions[0]) : null;
531
805
  }
532
806
 
533
807
  // src/channels/slack/model-picker-blocks.ts
@@ -537,7 +811,7 @@ var SLACK_MODEL_OPTION_VALUE_LIMIT = 75;
537
811
  var SLACK_MODEL_SELECT_ACTION_ID = "letta_channel_model_select";
538
812
  function resolveSlackSelectedModel(action, body) {
539
813
  const actionRecord = getSlackActionRecord(action, body);
540
- const selectedOption = asRecord(actionRecord?.selected_option);
814
+ const selectedOption = asRecord2(actionRecord?.selected_option);
541
815
  return firstNonEmptyString2(selectedOption?.value, actionRecord?.value) ?? null;
542
816
  }
543
817
  function escapeSlackMrkdwn(text) {
@@ -897,14 +1171,14 @@ function formatSlackToolNameForDisplay(toolName) {
897
1171
  return toolName;
898
1172
  }
899
1173
  function resolveSlackConcreteActivity(event) {
900
- if (event.kind === "command" && isNonEmptyString2(event.command)) {
1174
+ if (event.kind === "command" && isNonEmptyString3(event.command)) {
901
1175
  return sanitizeSlackStatusText(formatSlackToolNameForDisplay(event.command), SLACK_LOADING_MESSAGE_MAX);
902
1176
  }
903
- if (event.kind !== "tool" || !isNonEmptyString2(event.toolName) || event.toolName.toLowerCase() === "messagechannel") {
1177
+ if (event.kind !== "tool" || !isNonEmptyString3(event.toolName) || event.toolName.toLowerCase() === "messagechannel") {
904
1178
  return null;
905
1179
  }
906
1180
  for (const description of [event.toolTitle, event.toolDetails]) {
907
- if (!isNonEmptyString2(description)) {
1181
+ if (!isNonEmptyString3(description)) {
908
1182
  continue;
909
1183
  }
910
1184
  const sanitized = sanitizeSlackStatusText(description, SLACK_LOADING_MESSAGE_MAX);
@@ -1056,22 +1330,22 @@ function createSlackStatusController(params) {
1056
1330
  const keepaliveByConversation = new Map;
1057
1331
  const clearedStaleReplyKeys = new Set;
1058
1332
  function getConversationKey(source) {
1059
- return source.channel === "slack" && isNonEmptyString2(source.agentId) && isNonEmptyString2(source.conversationId) ? `${source.agentId}:${source.conversationId}` : null;
1333
+ return source.channel === "slack" && isNonEmptyString3(source.agentId) && isNonEmptyString3(source.conversationId) ? `${source.agentId}:${source.conversationId}` : null;
1060
1334
  }
1061
1335
  function getLifecycleReplyKey(source) {
1062
- if (source.channel !== "slack" || !isNonEmptyString2(source.chatId)) {
1336
+ if (source.channel !== "slack" || !isNonEmptyString3(source.chatId)) {
1063
1337
  return null;
1064
1338
  }
1065
1339
  const replyToMessageId = resolveSlackProgressThreadTs(source);
1066
- return isNonEmptyString2(replyToMessageId) ? `${source.chatId}:${replyToMessageId}` : null;
1340
+ return isNonEmptyString3(replyToMessageId) ? `${source.chatId}:${replyToMessageId}` : null;
1067
1341
  }
1068
1342
  function getLifecycleErrorReplyKey(source) {
1069
- if (source.channel !== "slack" || !isNonEmptyString2(source.chatId)) {
1343
+ if (source.channel !== "slack" || !isNonEmptyString3(source.chatId)) {
1070
1344
  return null;
1071
1345
  }
1072
1346
  if (source.chatType === "direct" || resolveSlackChatType(source.chatId) === "direct") {
1073
1347
  const replyToMessageId = resolveSlackSourceThreadTs(source);
1074
- return isNonEmptyString2(replyToMessageId) ? `${source.chatId}:${replyToMessageId}` : `${source.chatId}:direct`;
1348
+ return isNonEmptyString3(replyToMessageId) ? `${source.chatId}:${replyToMessageId}` : `${source.chatId}:direct`;
1075
1349
  }
1076
1350
  return getLifecycleReplyKey(source);
1077
1351
  }
@@ -1230,7 +1504,7 @@ ${loadingText}`;
1230
1504
  markAutoClearedByKey(key);
1231
1505
  },
1232
1506
  markAutoClearedForMessage(msg) {
1233
- if (isNonEmptyString2(msg.agentId) && isNonEmptyString2(msg.conversationId)) {
1507
+ if (isNonEmptyString3(msg.agentId) && isNonEmptyString3(msg.conversationId)) {
1234
1508
  markAutoClearedByKey(`${msg.agentId}:${msg.conversationId}`);
1235
1509
  return;
1236
1510
  }
@@ -1269,6 +1543,8 @@ export {
1269
1543
  resolveSlackReactionIngressPolicy,
1270
1544
  resolveSlackOutboundThreadTs,
1271
1545
  resolveSlackMessageIngressPolicy,
1546
+ resolveSlackMessageFiles,
1547
+ resolveSlackFileMetadata,
1272
1548
  resolveSlackConcreteActivity,
1273
1549
  resolveSlackChatType,
1274
1550
  resolveSlackAppMentionIngressPolicy,
@@ -1277,13 +1553,15 @@ export {
1277
1553
  isProcessableSlackInboundMessage,
1278
1554
  isOwnSlackBotInboundMessage,
1279
1555
  formatSlackLifecycleErrorMessage,
1556
+ fetchSlackFile,
1280
1557
  createSlackStatusController,
1281
1558
  createSlackMessageActionAdapter,
1282
1559
  createSlackChannelSender,
1560
+ collectSlackFiles,
1283
1561
  buildSlackModelPickerBlocks,
1284
1562
  SLACK_MODEL_SELECT_ACTION_ID,
1285
1563
  SLACK_ASSISTANT_WORKING_STATUS,
1286
1564
  SLACK_ASSISTANT_STARTUP_STATUS
1287
1565
  };
1288
1566
 
1289
- //# debugId=00F2BC6B76D5D4FA64756E2164756E21
1567
+ //# debugId=DB8AFA417A95EA8864756E2164756E21