@letta-ai/letta-code 0.28.5 → 0.28.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/letta.js CHANGED
@@ -4837,7 +4837,7 @@ var package_default;
4837
4837
  var init_package = __esm(() => {
4838
4838
  package_default = {
4839
4839
  name: "@letta-ai/letta-code",
4840
- version: "0.28.5",
4840
+ version: "0.28.6",
4841
4841
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
4842
4842
  type: "module",
4843
4843
  packageManager: "bun@1.3.0",
@@ -6204,6 +6204,7 @@ var init_backend_mode = __esm(() => {
6204
6204
  var exports_agent_tags = {};
6205
6205
  __export(exports_agent_tags, {
6206
6206
  buildCreatedAgentTags: () => buildCreatedAgentTags,
6207
+ ONBOARDING_ORIGIN_TAG: () => ONBOARDING_ORIGIN_TAG,
6207
6208
  LETTA_CODE_SUBAGENT_TAG: () => LETTA_CODE_SUBAGENT_TAG,
6208
6209
  LETTA_CODE_ORIGIN_TAG: () => LETTA_CODE_ORIGIN_TAG,
6209
6210
  GIT_MEMORY_ENABLED_TAG: () => GIT_MEMORY_ENABLED_TAG
@@ -6221,7 +6222,7 @@ function buildCreatedAgentTags(options = {}) {
6221
6222
  }
6222
6223
  return Array.from(new Set(tags));
6223
6224
  }
6224
- var LETTA_CODE_ORIGIN_TAG = "origin:letta-code", LETTA_CODE_SUBAGENT_TAG = "role:subagent", GIT_MEMORY_ENABLED_TAG = "git-memory-enabled";
6225
+ var LETTA_CODE_ORIGIN_TAG = "origin:letta-code", ONBOARDING_ORIGIN_TAG = "origin:onboarding", LETTA_CODE_SUBAGENT_TAG = "role:subagent", GIT_MEMORY_ENABLED_TAG = "git-memory-enabled";
6225
6226
 
6226
6227
  // src/utils/text-files.ts
6227
6228
  import { readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
@@ -168409,238 +168410,91 @@ var init_approval_controller = __esm(async () => {
168409
168410
  await init_presentation();
168410
168411
  });
168411
168412
 
168412
- // src/channels/slack/file-upload.ts
168413
- import { readFile as readFile4 } from "node:fs/promises";
168414
- import { basename as basename7, extname as extname3 } from "node:path";
168415
- function resolveUploadMimeType(filePath) {
168416
- switch (extname3(filePath).toLowerCase()) {
168417
- case ".png":
168418
- return "image/png";
168419
- case ".jpg":
168420
- case ".jpeg":
168421
- return "image/jpeg";
168422
- case ".gif":
168423
- return "image/gif";
168424
- case ".webp":
168425
- return "image/webp";
168426
- case ".pdf":
168427
- return "application/pdf";
168428
- case ".txt":
168429
- return "text/plain";
168430
- case ".md":
168431
- return "text/markdown";
168432
- default:
168433
- return;
168434
- }
168435
- }
168436
- async function uploadSlackFile(slackClient, msg) {
168437
- if (!msg.mediaPath) {
168438
- throw new Error("mediaPath is required for Slack file uploads.");
168439
- }
168440
- const buffer = await readFile4(msg.mediaPath);
168441
- const uploadFileName = msg.fileName ?? basename7(msg.mediaPath);
168442
- const uploadTitle = msg.title ?? uploadFileName;
168443
- const uploadMimeType = resolveUploadMimeType(uploadFileName);
168444
- const uploadUrlResp = await slackClient.files.getUploadURLExternal({
168445
- filename: uploadFileName,
168446
- length: buffer.length
168447
- });
168448
- if (!uploadUrlResp.ok || !uploadUrlResp.upload_url || !uploadUrlResp.file_id) {
168449
- throw new Error(`Failed to get Slack upload URL: ${uploadUrlResp.error ?? "unknown error"}`);
168450
- }
168451
- const uploadResp = await fetch(uploadUrlResp.upload_url, {
168452
- method: "POST",
168453
- ...uploadMimeType ? { headers: { "Content-Type": uploadMimeType } } : {},
168454
- body: buffer
168455
- });
168456
- if (!uploadResp.ok) {
168457
- throw new Error(`Failed to upload Slack file: HTTP ${uploadResp.status}`);
168458
- }
168459
- const threadTs = resolveSlackOutboundThreadTs({
168460
- chatId: msg.chatId,
168461
- threadId: msg.threadId,
168462
- replyToMessageId: msg.replyToMessageId
168463
- });
168464
- const completeResp = await slackClient.files.completeUploadExternal({
168465
- files: [{ id: uploadUrlResp.file_id, title: uploadTitle }],
168466
- channel_id: msg.chatId,
168467
- ...msg.text.trim() ? { initial_comment: msg.text } : {},
168468
- ...threadTs ? { thread_ts: threadTs } : {}
168469
- });
168470
- if (!completeResp.ok) {
168471
- throw new Error(`Failed to complete Slack upload: ${completeResp.error ?? "unknown error"}`);
168472
- }
168473
- return { messageId: uploadUrlResp.file_id };
168474
- }
168475
- var init_file_upload = __esm(() => {
168476
- init_utils5();
168477
- });
168478
-
168479
- // src/channels/slack/inbound-debounce.ts
168480
- function buildSlackDebounceKey(rawMessage, accountId) {
168481
- const senderId = rawMessage.user ?? rawMessage.bot_id ?? null;
168482
- if (!senderId)
168483
- return null;
168484
- const messageTs = rawMessage.ts ?? rawMessage.event_ts;
168485
- const isDm = rawMessage.channel.startsWith("D");
168486
- const scope = rawMessage.thread_ts ? `${rawMessage.channel}:${rawMessage.thread_ts}` : rawMessage.parent_user_id && messageTs ? `${rawMessage.channel}:maybe-thread:${messageTs}` : messageTs && !isDm ? `${rawMessage.channel}:${messageTs}` : rawMessage.channel;
168487
- return `slack:${accountId}:${scope}:${senderId}`;
168488
- }
168489
- function buildTopLevelSlackConversationKey(rawMessage, accountId) {
168490
- if (rawMessage.thread_ts || rawMessage.parent_user_id)
168491
- return null;
168492
- if (rawMessage.channel.startsWith("D"))
168493
- return null;
168494
- const senderId = rawMessage.user ?? rawMessage.bot_id;
168495
- return senderId ? `slack:${accountId}:${rawMessage.channel}:${senderId}` : null;
168496
- }
168497
- function resolveSlackInboundDebounceMs(config3) {
168498
- const raw = process.env.LETTA_SLACK_INBOUND_DEBOUNCE_MS;
168499
- if (typeof raw === "string" && raw.trim() !== "") {
168500
- const envOverride = Number(raw);
168501
- if (Number.isFinite(envOverride) && envOverride >= 0) {
168502
- return Math.trunc(envOverride);
168503
- }
168504
- }
168505
- const fromConfig = config3.inboundDebounceMs;
168506
- return typeof fromConfig === "number" && Number.isFinite(fromConfig) && fromConfig >= 0 ? Math.trunc(fromConfig) : 0;
168413
+ // src/channels/slack/attachment-stream.ts
168414
+ import { randomUUID as randomUUID8 } from "node:crypto";
168415
+ import { mkdir as mkdir4, open as open2, rename, rm as rm2 } from "node:fs/promises";
168416
+ import { join as join12 } from "node:path";
168417
+ function sanitizeFileName(name) {
168418
+ const normalized = name.trim().replace(/[^\w.-]+/g, "_");
168419
+ return normalized.length > 0 ? normalized : "attachment";
168507
168420
  }
168508
- function createSlackInboundDebounceController(params) {
168509
- const { config: config3 } = params;
168510
- const debounceMs = resolveSlackInboundDebounceMs(config3);
168511
- const pendingTopLevelKeys = new Map;
168512
- const appMentionRetryKeys = new Map;
168513
- const appMentionDispatchedKeys = new Map;
168514
- function pruneAppMentionMaps(now) {
168515
- for (const [key, expiresAt] of appMentionRetryKeys) {
168516
- if (expiresAt <= now)
168517
- appMentionRetryKeys.delete(key);
168518
- }
168519
- for (const [key, expiresAt] of appMentionDispatchedKeys) {
168520
- if (expiresAt <= now)
168521
- appMentionDispatchedKeys.delete(key);
168522
- }
168523
- }
168524
- function dedupeEntries(entries) {
168525
- const indexByMessageKey = new Map;
168526
- const deduped = [];
168527
- for (const entry of entries) {
168528
- const messageId = entry.inbound.messageId;
168529
- const messageKey = isNonEmptyString2(messageId) ? `${entry.inbound.chatId}:${messageId}` : null;
168530
- if (!messageKey) {
168531
- deduped.push(entry);
168532
- continue;
168421
+ async function saveSlackAttachmentStream(params) {
168422
+ const inboundDir = join12(getChannelDir("slack"), "inbound", sanitizeFileName(params.accountId));
168423
+ await mkdir4(inboundDir, { recursive: true });
168424
+ const filePath = join12(inboundDir, `${Date.now()}-${randomUUID8()}-${sanitizeFileName(params.fileName)}`);
168425
+ const temporaryPath = `${filePath}.partial`;
168426
+ const fileHandle = await open2(temporaryPath, "wx");
168427
+ const reader = params.body.getReader();
168428
+ let sizeBytes = 0;
168429
+ let completed = false;
168430
+ try {
168431
+ while (true) {
168432
+ const { done, value } = await reader.read();
168433
+ if (done) {
168434
+ break;
168533
168435
  }
168534
- const existingIndex = indexByMessageKey.get(messageKey);
168535
- if (existingIndex === undefined) {
168536
- indexByMessageKey.set(messageKey, deduped.length);
168537
- deduped.push(entry);
168436
+ if (!value?.byteLength) {
168538
168437
  continue;
168539
168438
  }
168540
- const current = deduped[existingIndex];
168541
- if (current && current.opts.source !== "app_mention" && current.inbound.isMention !== true) {
168542
- deduped[existingIndex] = entry;
168439
+ sizeBytes += value.byteLength;
168440
+ if (params.maxBytes !== undefined && sizeBytes > params.maxBytes) {
168441
+ throw new SlackAttachmentDownloadError("exceeds_auto_download_limit", `Slack attachment exceeds automatic download limit (${params.maxBytes} bytes).`);
168543
168442
  }
168544
- }
168545
- return deduped;
168546
- }
168547
- const debouncer = createInboundDebouncer({
168548
- debounceMs,
168549
- buildKey: ({ raw }) => buildSlackDebounceKey(raw, config3.accountId),
168550
- shouldDebounce: ({ inbound }) => !inbound.attachments?.length && !inbound.reaction,
168551
- onFlush: async (entries) => {
168552
- const dedupedEntries = dedupeEntries(entries);
168553
- const last = dedupedEntries[dedupedEntries.length - 1];
168554
- if (!last)
168555
- return;
168556
- const flushedKey = buildSlackDebounceKey(last.raw, config3.accountId);
168557
- const conversationKey = buildTopLevelSlackConversationKey(last.raw, config3.accountId);
168558
- if (flushedKey && conversationKey) {
168559
- const pending = pendingTopLevelKeys.get(conversationKey);
168560
- pending?.delete(flushedKey);
168561
- if (pending?.size === 0)
168562
- pendingTopLevelKeys.delete(conversationKey);
168563
- }
168564
- if (isNonEmptyString2(last.inbound.messageId)) {
168565
- const seenKey = `${last.inbound.chatId}:${last.inbound.messageId}`;
168566
- pruneAppMentionMaps(Date.now());
168567
- if (last.opts.source === "app_mention") {
168568
- appMentionDispatchedKeys.set(seenKey, Date.now() + APP_MENTION_RETRY_TTL_MS);
168569
- } else if (appMentionDispatchedKeys.has(seenKey)) {
168570
- appMentionDispatchedKeys.delete(seenKey);
168571
- appMentionRetryKeys.delete(seenKey);
168572
- return;
168443
+ let offset = 0;
168444
+ while (offset < value.byteLength) {
168445
+ const { bytesWritten } = await fileHandle.write(value, offset, value.byteLength - offset);
168446
+ if (bytesWritten <= 0) {
168447
+ throw new Error("Slack attachment write made no progress.");
168573
168448
  }
168574
- appMentionRetryKeys.delete(seenKey);
168449
+ offset += bytesWritten;
168575
168450
  }
168576
- const onMessage = params.getOnMessage();
168577
- if (!onMessage)
168451
+ }
168452
+ completed = true;
168453
+ } finally {
168454
+ if (!completed) {
168455
+ await reader.cancel().catch(() => {
168578
168456
  return;
168579
- const text = dedupedEntries.length === 1 ? last.inbound.text : dedupedEntries.map((entry) => entry.inbound.text).filter(Boolean).join(`
168580
- `);
168581
- try {
168582
- await onMessage({
168583
- ...last.inbound,
168584
- text,
168585
- isMention: dedupedEntries.some((entry) => entry.opts.wasMentioned || entry.inbound.isMention === true)
168586
- });
168587
- } catch (error54) {
168588
- console.error("[Slack] Error handling debounced inbound message:", error54);
168589
- }
168590
- },
168591
- onError: (error54) => {
168592
- console.error("[Slack] Inbound debounce flush failed:", error54 instanceof Error ? error54.message : error54);
168457
+ });
168593
168458
  }
168594
- });
168595
- return {
168596
- async dispatch(entry) {
168597
- const debounceKey = buildSlackDebounceKey(entry.raw, config3.accountId);
168598
- const conversationKey = buildTopLevelSlackConversationKey(entry.raw, config3.accountId);
168599
- const canDebounce = debounceMs > 0 && !entry.inbound.attachments?.length && !entry.inbound.reaction && Boolean(debounceKey);
168600
- if (!canDebounce && conversationKey) {
168601
- for (const pendingKey of Array.from(pendingTopLevelKeys.get(conversationKey) ?? [])) {
168602
- try {
168603
- await debouncer.flushKey(pendingKey);
168604
- } catch {}
168605
- }
168606
- }
168607
- if (canDebounce && debounceKey && conversationKey) {
168608
- const pending = pendingTopLevelKeys.get(conversationKey) ?? new Set;
168609
- pending.add(debounceKey);
168610
- pendingTopLevelKeys.set(conversationKey, pending);
168611
- }
168612
- await debouncer.enqueue(entry);
168613
- },
168614
- rememberAppMentionRetry(seenKey) {
168615
- const now = Date.now();
168616
- pruneAppMentionMaps(now);
168617
- appMentionRetryKeys.set(seenKey, now + APP_MENTION_RETRY_TTL_MS);
168618
- },
168619
- consumeAppMentionRetry(seenKey) {
168620
- pruneAppMentionMaps(Date.now());
168621
- if (!appMentionRetryKeys.has(seenKey))
168622
- return false;
168623
- appMentionRetryKeys.delete(seenKey);
168624
- return true;
168625
- },
168626
- clear() {
168627
- pendingTopLevelKeys.clear();
168628
- appMentionRetryKeys.clear();
168629
- appMentionDispatchedKeys.clear();
168459
+ try {
168460
+ reader.releaseLock();
168461
+ } catch {}
168462
+ await fileHandle.close().catch(() => {
168463
+ return;
168464
+ });
168465
+ if (!completed) {
168466
+ await rm2(temporaryPath, { force: true }).catch(() => {
168467
+ return;
168468
+ });
168630
168469
  }
168631
- };
168470
+ }
168471
+ try {
168472
+ await rename(temporaryPath, filePath);
168473
+ } catch (error54) {
168474
+ await rm2(temporaryPath, { force: true }).catch(() => {
168475
+ return;
168476
+ });
168477
+ throw error54;
168478
+ }
168479
+ return { localPath: filePath, sizeBytes };
168632
168480
  }
168633
- var APP_MENTION_RETRY_TTL_MS = 60000;
168634
- var init_inbound_debounce = __esm(() => {
168635
- init_utils5();
168481
+ var SlackAttachmentDownloadError;
168482
+ var init_attachment_stream = __esm(() => {
168483
+ init_config2();
168484
+ SlackAttachmentDownloadError = class SlackAttachmentDownloadError extends Error {
168485
+ reason;
168486
+ constructor(reason, message) {
168487
+ super(message);
168488
+ this.reason = reason;
168489
+ this.name = "SlackAttachmentDownloadError";
168490
+ }
168491
+ };
168636
168492
  });
168637
168493
 
168638
168494
  // src/channels/slack/media.ts
168639
- import { randomUUID as randomUUID8 } from "node:crypto";
168640
- import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile6 } from "node:fs/promises";
168641
- import { basename as basename8, extname as extname4, join as join12 } from "node:path";
168642
- async function mapSlackThreadMessage(message, attachmentOptions) {
168643
- const attachments = await resolveSlackMessageAttachments(message, attachmentOptions);
168495
+ import { basename as basename7, extname as extname3 } from "node:path";
168496
+ async function mapSlackThreadMessage(message, attachmentOptions, sourceThreadId) {
168497
+ const attachments = await resolveSlackMessageAttachments(message, attachmentOptions, sourceThreadId);
168644
168498
  return {
168645
168499
  text: resolveSlackThreadMessageText(message),
168646
168500
  userId: isNonEmptyString3(message.user) ? message.user : undefined,
@@ -168741,10 +168595,6 @@ function assertSlackFileUrl(rawUrl) {
168741
168595
  }
168742
168596
  return parsed;
168743
168597
  }
168744
- function sanitizeFileName(name) {
168745
- const normalized = name.trim().replace(/[^\w.-]+/g, "_");
168746
- return normalized.length > 0 ? normalized : "attachment";
168747
- }
168748
168598
  function extensionForMimeType2(mimeType) {
168749
168599
  switch (mimeType?.toLowerCase()) {
168750
168600
  case "image/png":
@@ -168782,7 +168632,7 @@ function resolveMimeType(name, fallback) {
168782
168632
  if (fallback) {
168783
168633
  return fallback;
168784
168634
  }
168785
- switch (extname4(name).toLowerCase()) {
168635
+ switch (extname3(name).toLowerCase()) {
168786
168636
  case ".png":
168787
168637
  return "image/png";
168788
168638
  case ".jpg":
@@ -168858,51 +168708,93 @@ async function fetchWithSlackAuth(url2, token) {
168858
168708
  }
168859
168709
  return fetch(resolved.href, { redirect: "follow" });
168860
168710
  }
168861
- async function saveSlackAttachment(params) {
168862
- const inboundDir = join12(getChannelDir("slack"), "inbound", sanitizeFileName(params.accountId));
168863
- await mkdir4(inboundDir, { recursive: true });
168864
- const filePath = join12(inboundDir, `${Date.now()}-${randomUUID8()}-${sanitizeFileName(params.fileName)}`);
168865
- await writeFile6(filePath, params.buffer);
168866
- return filePath;
168711
+ function resolveSlackAttachmentFileName(params) {
168712
+ const hintedName = params.file.name ?? (params.url ? basename7(new URL(params.url).pathname) : undefined) ?? `${params.file.id ?? "attachment"}${extensionForMimeType2(params.file.mimetype)}`;
168713
+ return extname3(hintedName) || !params.mimeType ? hintedName : `${hintedName}${extensionForMimeType2(params.mimeType)}`;
168714
+ }
168715
+ function resolveSlackAttachmentMimeType(params) {
168716
+ const preferredMimeType = params.responseMimeType && !isGenericSlackMimeType(params.responseMimeType) ? params.responseMimeType : params.file.mimetype && !isGenericSlackMimeType(params.file.mimetype) ? params.file.mimetype : undefined;
168717
+ return resolveMimeType(params.fileName, preferredMimeType);
168718
+ }
168719
+ function createUndownloadedSlackAttachment(params) {
168720
+ const fileName = resolveSlackAttachmentFileName({ file: params.file });
168721
+ const mimeType = resolveSlackAttachmentMimeType({
168722
+ file: params.file,
168723
+ fileName
168724
+ });
168725
+ return {
168726
+ id: params.file.id,
168727
+ name: fileName,
168728
+ mimeType,
168729
+ sizeBytes: params.file.size,
168730
+ kind: resolveAttachmentKind(mimeType),
168731
+ sourceMessageId: params.sourceMessageId,
168732
+ ...params.sourceThreadId ? { sourceThreadId: params.sourceThreadId } : {},
168733
+ downloadReason: params.reason,
168734
+ ...params.reason === "exceeds_auto_download_limit" ? { autoDownloadLimitBytes: MAX_SLACK_ATTACHMENT_BYTES } : {}
168735
+ };
168867
168736
  }
168868
- async function downloadSlackAttachment(params) {
168737
+ async function materializeSlackAttachment(params) {
168738
+ if (params.maxBytes !== undefined && typeof params.file.size === "number" && params.file.size > params.maxBytes) {
168739
+ throw new SlackAttachmentDownloadError("exceeds_auto_download_limit", `Slack attachment is ${params.file.size} bytes; automatic download limit is ${params.maxBytes} bytes.`);
168740
+ }
168869
168741
  const url2 = params.file.url_private_download ?? params.file.url_private;
168870
168742
  if (!url2) {
168871
- return null;
168743
+ throw new SlackAttachmentDownloadError("missing_download_url", "Slack attachment does not include a private download URL.");
168872
168744
  }
168873
- const response = await fetchWithSlackAuth(url2, params.token);
168745
+ const response = await fetchWithSlackAuth(url2, params.token).catch((error54) => {
168746
+ throw new SlackAttachmentDownloadError("download_failed", error54 instanceof Error ? error54.message : "Slack attachment fetch failed.");
168747
+ });
168874
168748
  if (!response.ok) {
168875
- return null;
168749
+ throw new SlackAttachmentDownloadError("download_failed", `Slack attachment fetch failed with HTTP ${response.status}.`);
168876
168750
  }
168877
- const arrayBuffer = await response.arrayBuffer();
168878
- if (arrayBuffer.byteLength > MAX_SLACK_ATTACHMENT_BYTES) {
168879
- return null;
168751
+ const contentLengthHeader = response.headers.get("content-length");
168752
+ const contentLength = contentLengthHeader ? Number(contentLengthHeader) : undefined;
168753
+ if (params.maxBytes !== undefined && contentLength !== undefined && Number.isFinite(contentLength) && contentLength > params.maxBytes) {
168754
+ await response.body?.cancel().catch(() => {
168755
+ return;
168756
+ });
168757
+ throw new SlackAttachmentDownloadError("exceeds_auto_download_limit", `Slack attachment is ${contentLength} bytes; automatic download limit is ${params.maxBytes} bytes.`);
168880
168758
  }
168881
- const buffer = Buffer.from(arrayBuffer);
168882
- const hintedName = params.file.name ?? basename8(new URL(url2).pathname) ?? `${params.file.id ?? "attachment"}${extensionForMimeType2(params.file.mimetype)}`;
168883
168759
  const responseMimeType = response.headers.get("content-type")?.split(";")[0]?.trim() || undefined;
168884
- const fileMimeType = params.file.mimetype;
168885
- const preferredMimeType = responseMimeType && !isGenericSlackMimeType(responseMimeType) ? responseMimeType : fileMimeType && !isGenericSlackMimeType(fileMimeType) ? fileMimeType : undefined;
168886
- const mimeType = resolveMimeType(hintedName, preferredMimeType);
168887
- const fileName = extname4(hintedName) || !mimeType ? hintedName : `${hintedName}${extensionForMimeType2(mimeType)}`;
168888
- const localPath = await saveSlackAttachment({
168760
+ const hintedName = resolveSlackAttachmentFileName({
168761
+ file: params.file,
168762
+ url: url2
168763
+ });
168764
+ const mimeType = resolveSlackAttachmentMimeType({
168765
+ file: params.file,
168766
+ fileName: hintedName,
168767
+ responseMimeType
168768
+ });
168769
+ const fileName = resolveSlackAttachmentFileName({
168770
+ file: params.file,
168771
+ url: url2,
168772
+ mimeType
168773
+ });
168774
+ if (!response.body) {
168775
+ throw new SlackAttachmentDownloadError("download_failed", "Slack attachment response did not include a body.");
168776
+ }
168777
+ const saved = await saveSlackAttachmentStream({
168889
168778
  accountId: params.accountId,
168890
168779
  fileName,
168891
- buffer
168780
+ body: response.body,
168781
+ maxBytes: params.maxBytes
168892
168782
  });
168893
168783
  const kind = resolveAttachmentKind(mimeType);
168894
168784
  const attachment = {
168895
168785
  id: params.file.id,
168896
168786
  name: fileName,
168897
168787
  mimeType,
168898
- sizeBytes: buffer.byteLength,
168788
+ sizeBytes: saved.sizeBytes,
168899
168789
  kind,
168900
- localPath
168790
+ localPath: saved.localPath,
168791
+ sourceMessageId: params.sourceMessageId,
168792
+ ...params.sourceThreadId ? { sourceThreadId: params.sourceThreadId } : {}
168901
168793
  };
168902
168794
  if (kind === "audio" && params.transcribeVoice) {
168903
168795
  const { isTranscriptionConfigured: isTranscriptionConfigured2, transcribeAudioFile: transcribeAudioFile2 } = await Promise.resolve().then(() => (init_transcription(), exports_transcription));
168904
168796
  if (isTranscriptionConfigured2()) {
168905
- const result = await transcribeAudioFile2(localPath);
168797
+ const result = await transcribeAudioFile2(saved.localPath);
168906
168798
  if (result.success && result.text) {
168907
168799
  attachment.transcription = result.text;
168908
168800
  } else if (result.error) {
@@ -168953,13 +168845,28 @@ async function resolveSlackFilesAsAttachments(params) {
168953
168845
  if (params.files.length === 0) {
168954
168846
  return [];
168955
168847
  }
168956
- const resolved = await Promise.all(params.files.map((file3) => downloadSlackAttachment({
168957
- accountId: params.accountId,
168958
- token: params.token,
168959
- file: file3,
168960
- transcribeVoice: params.transcribeVoice
168961
- }).catch(() => null)));
168962
- return resolved.filter((attachment) => Boolean(attachment));
168848
+ const resolved = await Promise.all(params.files.map(async (file3) => {
168849
+ try {
168850
+ return await materializeSlackAttachment({
168851
+ accountId: params.accountId,
168852
+ token: params.token,
168853
+ file: file3,
168854
+ sourceMessageId: params.sourceMessageId,
168855
+ sourceThreadId: params.sourceThreadId,
168856
+ maxBytes: MAX_SLACK_ATTACHMENT_BYTES,
168857
+ transcribeVoice: params.transcribeVoice
168858
+ });
168859
+ } catch (error54) {
168860
+ const reason = error54 instanceof SlackAttachmentDownloadError ? error54.reason : "download_failed";
168861
+ return createUndownloadedSlackAttachment({
168862
+ file: file3,
168863
+ sourceMessageId: params.sourceMessageId,
168864
+ sourceThreadId: params.sourceThreadId,
168865
+ reason
168866
+ });
168867
+ }
168868
+ }));
168869
+ return resolved;
168963
168870
  }
168964
168871
  function resolveSlackThreadAttachmentOptions(params) {
168965
168872
  if (!isNonEmptyString3(params.accountId) || !isNonEmptyString3(params.token)) {
@@ -168980,7 +168887,7 @@ function hasSlackThreadMessageContent(message, attachmentOptions) {
168980
168887
  function hasHydratedSlackThreadMessageContent(message) {
168981
168888
  return message.text.length > 0 || Boolean(message.attachments?.length);
168982
168889
  }
168983
- async function resolveSlackMessageAttachments(message, attachmentOptions) {
168890
+ async function resolveSlackMessageAttachments(message, attachmentOptions, sourceThreadId) {
168984
168891
  if (!attachmentOptions) {
168985
168892
  return [];
168986
168893
  }
@@ -168988,14 +168895,19 @@ async function resolveSlackMessageAttachments(message, attachmentOptions) {
168988
168895
  accountId: attachmentOptions.accountId,
168989
168896
  token: attachmentOptions.token,
168990
168897
  files: collectSlackFiles(message),
168898
+ sourceMessageId: message.ts,
168899
+ sourceThreadId: sourceThreadId ?? (isNonEmptyString3(message.thread_ts) ? message.thread_ts : null),
168991
168900
  transcribeVoice: attachmentOptions.transcribeVoice
168992
168901
  });
168993
168902
  }
168994
168903
  async function resolveSlackInboundAttachments(params) {
168904
+ const rawEvent = asRecord4(params.rawEvent);
168995
168905
  return resolveSlackFilesAsAttachments({
168996
168906
  accountId: params.accountId,
168997
168907
  token: params.token,
168998
168908
  files: collectSlackFiles(params.rawEvent),
168909
+ sourceMessageId: isNonEmptyString3(rawEvent?.ts) ? rawEvent.ts : undefined,
168910
+ sourceThreadId: isNonEmptyString3(rawEvent?.thread_ts) ? rawEvent.thread_ts : null,
168999
168911
  transcribeVoice: params.transcribeVoice
169000
168912
  });
169001
168913
  }
@@ -169017,7 +168929,7 @@ async function resolveSlackCurrentMessageAttachments(params) {
169017
168929
  });
169018
168930
  const message = (response.messages ?? []).find((entry) => entry.ts === params.messageTs);
169019
168931
  if (message) {
169020
- return resolveSlackMessageAttachments(message, attachmentOptions);
168932
+ return resolveSlackMessageAttachments(message, attachmentOptions, params.threadTs);
169021
168933
  }
169022
168934
  const nextCursor = response.response_metadata?.next_cursor;
169023
168935
  cursor = typeof nextCursor === "string" && nextCursor.trim().length > 0 ? nextCursor.trim() : undefined;
@@ -169043,7 +168955,7 @@ async function resolveSlackThreadStarter(params) {
169043
168955
  if (!hasSlackThreadMessageContent(message, attachmentOptions)) {
169044
168956
  return null;
169045
168957
  }
169046
- const mapped3 = await mapSlackThreadMessage(message, attachmentOptions);
168958
+ const mapped3 = await mapSlackThreadMessage(message, attachmentOptions, params.threadTs);
169047
168959
  return hasHydratedSlackThreadMessageContent(mapped3) ? mapped3 : null;
169048
168960
  } catch {
169049
168961
  return null;
@@ -169088,7 +169000,7 @@ async function resolveSlackThreadHistory(params) {
169088
169000
  const nextCursor = response.response_metadata?.next_cursor;
169089
169001
  cursor = typeof nextCursor === "string" && nextCursor.trim().length > 0 ? nextCursor.trim() : undefined;
169090
169002
  } while (cursor);
169091
- const mapped3 = await Promise.all(retained.map((message) => mapSlackThreadMessage(message, attachmentOptions)));
169003
+ const mapped3 = await Promise.all(retained.map((message) => mapSlackThreadMessage(message, attachmentOptions, params.threadTs)));
169092
169004
  return mapped3.filter(hasHydratedSlackThreadMessageContent);
169093
169005
  } catch {
169094
169006
  return [];
@@ -169122,7 +169034,7 @@ async function resolveSlackChannelHistory(params) {
169122
169034
  }
169123
169035
  var MAX_SLACK_ATTACHMENTS = 8, MAX_SLACK_ATTACHMENT_BYTES, ALLOWED_SLACK_HOST_SUFFIXES;
169124
169036
  var init_media2 = __esm(() => {
169125
- init_config2();
169037
+ init_attachment_stream();
169126
169038
  MAX_SLACK_ATTACHMENT_BYTES = 20 * 1024 * 1024;
169127
169039
  ALLOWED_SLACK_HOST_SUFFIXES = [
169128
169040
  "slack.com",
@@ -169131,6 +169043,286 @@ var init_media2 = __esm(() => {
169131
169043
  ];
169132
169044
  });
169133
169045
 
169046
+ // src/channels/slack/attachment-download.ts
169047
+ function isNonEmptyString4(value) {
169048
+ return typeof value === "string" && value.trim().length > 0;
169049
+ }
169050
+ async function resolveCanonicalSlackMessage(params) {
169051
+ if (isNonEmptyString4(params.threadTs)) {
169052
+ let cursor;
169053
+ do {
169054
+ const response2 = await params.client.conversations.replies({
169055
+ channel: params.channelId,
169056
+ ts: params.threadTs,
169057
+ limit: 200,
169058
+ inclusive: true,
169059
+ ...cursor ? { cursor } : {}
169060
+ });
169061
+ const message = (response2.messages ?? []).find((entry) => entry.ts === params.messageTs);
169062
+ if (message) {
169063
+ return message;
169064
+ }
169065
+ const nextCursor = response2.response_metadata?.next_cursor;
169066
+ cursor = isNonEmptyString4(nextCursor) ? nextCursor.trim() : undefined;
169067
+ } while (cursor);
169068
+ return null;
169069
+ }
169070
+ const response = await params.client.conversations.history({
169071
+ channel: params.channelId,
169072
+ oldest: params.messageTs,
169073
+ latest: params.messageTs,
169074
+ inclusive: true,
169075
+ limit: 1
169076
+ });
169077
+ return (response.messages ?? []).find((entry) => entry.ts === params.messageTs) ?? null;
169078
+ }
169079
+ async function downloadSlackAttachmentById(params) {
169080
+ const message = await resolveCanonicalSlackMessage(params);
169081
+ if (!message) {
169082
+ throw new Error(`Slack message ${params.messageTs} was not found in chat ${params.channelId}.`);
169083
+ }
169084
+ const file3 = collectSlackFiles(message).find((entry) => entry.id === params.attachmentId);
169085
+ if (!file3) {
169086
+ throw new Error(`Slack attachment ${params.attachmentId} is not attached to message ${params.messageTs}.`);
169087
+ }
169088
+ return await materializeSlackAttachment({
169089
+ accountId: params.accountId,
169090
+ token: params.token,
169091
+ file: file3,
169092
+ sourceMessageId: params.messageTs,
169093
+ sourceThreadId: params.threadTs ?? null
169094
+ });
169095
+ }
169096
+ var init_attachment_download = __esm(() => {
169097
+ init_media2();
169098
+ });
169099
+
169100
+ // src/channels/slack/file-upload.ts
169101
+ import { readFile as readFile4 } from "node:fs/promises";
169102
+ import { basename as basename8, extname as extname4 } from "node:path";
169103
+ function resolveUploadMimeType(filePath) {
169104
+ switch (extname4(filePath).toLowerCase()) {
169105
+ case ".png":
169106
+ return "image/png";
169107
+ case ".jpg":
169108
+ case ".jpeg":
169109
+ return "image/jpeg";
169110
+ case ".gif":
169111
+ return "image/gif";
169112
+ case ".webp":
169113
+ return "image/webp";
169114
+ case ".pdf":
169115
+ return "application/pdf";
169116
+ case ".txt":
169117
+ return "text/plain";
169118
+ case ".md":
169119
+ return "text/markdown";
169120
+ default:
169121
+ return;
169122
+ }
169123
+ }
169124
+ async function uploadSlackFile(slackClient, msg) {
169125
+ if (!msg.mediaPath) {
169126
+ throw new Error("mediaPath is required for Slack file uploads.");
169127
+ }
169128
+ const buffer = await readFile4(msg.mediaPath);
169129
+ const uploadFileName = msg.fileName ?? basename8(msg.mediaPath);
169130
+ const uploadTitle = msg.title ?? uploadFileName;
169131
+ const uploadMimeType = resolveUploadMimeType(uploadFileName);
169132
+ const uploadUrlResp = await slackClient.files.getUploadURLExternal({
169133
+ filename: uploadFileName,
169134
+ length: buffer.length
169135
+ });
169136
+ if (!uploadUrlResp.ok || !uploadUrlResp.upload_url || !uploadUrlResp.file_id) {
169137
+ throw new Error(`Failed to get Slack upload URL: ${uploadUrlResp.error ?? "unknown error"}`);
169138
+ }
169139
+ const uploadResp = await fetch(uploadUrlResp.upload_url, {
169140
+ method: "POST",
169141
+ ...uploadMimeType ? { headers: { "Content-Type": uploadMimeType } } : {},
169142
+ body: buffer
169143
+ });
169144
+ if (!uploadResp.ok) {
169145
+ throw new Error(`Failed to upload Slack file: HTTP ${uploadResp.status}`);
169146
+ }
169147
+ const threadTs = resolveSlackOutboundThreadTs({
169148
+ chatId: msg.chatId,
169149
+ threadId: msg.threadId,
169150
+ replyToMessageId: msg.replyToMessageId
169151
+ });
169152
+ const completeResp = await slackClient.files.completeUploadExternal({
169153
+ files: [{ id: uploadUrlResp.file_id, title: uploadTitle }],
169154
+ channel_id: msg.chatId,
169155
+ ...msg.text.trim() ? { initial_comment: msg.text } : {},
169156
+ ...threadTs ? { thread_ts: threadTs } : {}
169157
+ });
169158
+ if (!completeResp.ok) {
169159
+ throw new Error(`Failed to complete Slack upload: ${completeResp.error ?? "unknown error"}`);
169160
+ }
169161
+ return { messageId: uploadUrlResp.file_id };
169162
+ }
169163
+ var init_file_upload = __esm(() => {
169164
+ init_utils5();
169165
+ });
169166
+
169167
+ // src/channels/slack/inbound-debounce.ts
169168
+ function buildSlackDebounceKey(rawMessage, accountId) {
169169
+ const senderId = rawMessage.user ?? rawMessage.bot_id ?? null;
169170
+ if (!senderId)
169171
+ return null;
169172
+ const messageTs = rawMessage.ts ?? rawMessage.event_ts;
169173
+ const isDm = rawMessage.channel.startsWith("D");
169174
+ const scope = rawMessage.thread_ts ? `${rawMessage.channel}:${rawMessage.thread_ts}` : rawMessage.parent_user_id && messageTs ? `${rawMessage.channel}:maybe-thread:${messageTs}` : messageTs && !isDm ? `${rawMessage.channel}:${messageTs}` : rawMessage.channel;
169175
+ return `slack:${accountId}:${scope}:${senderId}`;
169176
+ }
169177
+ function buildTopLevelSlackConversationKey(rawMessage, accountId) {
169178
+ if (rawMessage.thread_ts || rawMessage.parent_user_id)
169179
+ return null;
169180
+ if (rawMessage.channel.startsWith("D"))
169181
+ return null;
169182
+ const senderId = rawMessage.user ?? rawMessage.bot_id;
169183
+ return senderId ? `slack:${accountId}:${rawMessage.channel}:${senderId}` : null;
169184
+ }
169185
+ function resolveSlackInboundDebounceMs(config3) {
169186
+ const raw = process.env.LETTA_SLACK_INBOUND_DEBOUNCE_MS;
169187
+ if (typeof raw === "string" && raw.trim() !== "") {
169188
+ const envOverride = Number(raw);
169189
+ if (Number.isFinite(envOverride) && envOverride >= 0) {
169190
+ return Math.trunc(envOverride);
169191
+ }
169192
+ }
169193
+ const fromConfig = config3.inboundDebounceMs;
169194
+ return typeof fromConfig === "number" && Number.isFinite(fromConfig) && fromConfig >= 0 ? Math.trunc(fromConfig) : 0;
169195
+ }
169196
+ function createSlackInboundDebounceController(params) {
169197
+ const { config: config3 } = params;
169198
+ const debounceMs = resolveSlackInboundDebounceMs(config3);
169199
+ const pendingTopLevelKeys = new Map;
169200
+ const appMentionRetryKeys = new Map;
169201
+ const appMentionDispatchedKeys = new Map;
169202
+ function pruneAppMentionMaps(now) {
169203
+ for (const [key, expiresAt] of appMentionRetryKeys) {
169204
+ if (expiresAt <= now)
169205
+ appMentionRetryKeys.delete(key);
169206
+ }
169207
+ for (const [key, expiresAt] of appMentionDispatchedKeys) {
169208
+ if (expiresAt <= now)
169209
+ appMentionDispatchedKeys.delete(key);
169210
+ }
169211
+ }
169212
+ function dedupeEntries(entries) {
169213
+ const indexByMessageKey = new Map;
169214
+ const deduped = [];
169215
+ for (const entry of entries) {
169216
+ const messageId = entry.inbound.messageId;
169217
+ const messageKey = isNonEmptyString2(messageId) ? `${entry.inbound.chatId}:${messageId}` : null;
169218
+ if (!messageKey) {
169219
+ deduped.push(entry);
169220
+ continue;
169221
+ }
169222
+ const existingIndex = indexByMessageKey.get(messageKey);
169223
+ if (existingIndex === undefined) {
169224
+ indexByMessageKey.set(messageKey, deduped.length);
169225
+ deduped.push(entry);
169226
+ continue;
169227
+ }
169228
+ const current = deduped[existingIndex];
169229
+ if (current && current.opts.source !== "app_mention" && current.inbound.isMention !== true) {
169230
+ deduped[existingIndex] = entry;
169231
+ }
169232
+ }
169233
+ return deduped;
169234
+ }
169235
+ const debouncer = createInboundDebouncer({
169236
+ debounceMs,
169237
+ buildKey: ({ raw }) => buildSlackDebounceKey(raw, config3.accountId),
169238
+ shouldDebounce: ({ inbound }) => !inbound.attachments?.length && !inbound.reaction,
169239
+ onFlush: async (entries) => {
169240
+ const dedupedEntries = dedupeEntries(entries);
169241
+ const last = dedupedEntries[dedupedEntries.length - 1];
169242
+ if (!last)
169243
+ return;
169244
+ const flushedKey = buildSlackDebounceKey(last.raw, config3.accountId);
169245
+ const conversationKey = buildTopLevelSlackConversationKey(last.raw, config3.accountId);
169246
+ if (flushedKey && conversationKey) {
169247
+ const pending = pendingTopLevelKeys.get(conversationKey);
169248
+ pending?.delete(flushedKey);
169249
+ if (pending?.size === 0)
169250
+ pendingTopLevelKeys.delete(conversationKey);
169251
+ }
169252
+ if (isNonEmptyString2(last.inbound.messageId)) {
169253
+ const seenKey = `${last.inbound.chatId}:${last.inbound.messageId}`;
169254
+ pruneAppMentionMaps(Date.now());
169255
+ if (last.opts.source === "app_mention") {
169256
+ appMentionDispatchedKeys.set(seenKey, Date.now() + APP_MENTION_RETRY_TTL_MS);
169257
+ } else if (appMentionDispatchedKeys.has(seenKey)) {
169258
+ appMentionDispatchedKeys.delete(seenKey);
169259
+ appMentionRetryKeys.delete(seenKey);
169260
+ return;
169261
+ }
169262
+ appMentionRetryKeys.delete(seenKey);
169263
+ }
169264
+ const onMessage = params.getOnMessage();
169265
+ if (!onMessage)
169266
+ return;
169267
+ const text = dedupedEntries.length === 1 ? last.inbound.text : dedupedEntries.map((entry) => entry.inbound.text).filter(Boolean).join(`
169268
+ `);
169269
+ try {
169270
+ await onMessage({
169271
+ ...last.inbound,
169272
+ text,
169273
+ isMention: dedupedEntries.some((entry) => entry.opts.wasMentioned || entry.inbound.isMention === true)
169274
+ });
169275
+ } catch (error54) {
169276
+ console.error("[Slack] Error handling debounced inbound message:", error54);
169277
+ }
169278
+ },
169279
+ onError: (error54) => {
169280
+ console.error("[Slack] Inbound debounce flush failed:", error54 instanceof Error ? error54.message : error54);
169281
+ }
169282
+ });
169283
+ return {
169284
+ async dispatch(entry) {
169285
+ const debounceKey = buildSlackDebounceKey(entry.raw, config3.accountId);
169286
+ const conversationKey = buildTopLevelSlackConversationKey(entry.raw, config3.accountId);
169287
+ const canDebounce = debounceMs > 0 && !entry.inbound.attachments?.length && !entry.inbound.reaction && Boolean(debounceKey);
169288
+ if (!canDebounce && conversationKey) {
169289
+ for (const pendingKey of Array.from(pendingTopLevelKeys.get(conversationKey) ?? [])) {
169290
+ try {
169291
+ await debouncer.flushKey(pendingKey);
169292
+ } catch {}
169293
+ }
169294
+ }
169295
+ if (canDebounce && debounceKey && conversationKey) {
169296
+ const pending = pendingTopLevelKeys.get(conversationKey) ?? new Set;
169297
+ pending.add(debounceKey);
169298
+ pendingTopLevelKeys.set(conversationKey, pending);
169299
+ }
169300
+ await debouncer.enqueue(entry);
169301
+ },
169302
+ rememberAppMentionRetry(seenKey) {
169303
+ const now = Date.now();
169304
+ pruneAppMentionMaps(now);
169305
+ appMentionRetryKeys.set(seenKey, now + APP_MENTION_RETRY_TTL_MS);
169306
+ },
169307
+ consumeAppMentionRetry(seenKey) {
169308
+ pruneAppMentionMaps(Date.now());
169309
+ if (!appMentionRetryKeys.has(seenKey))
169310
+ return false;
169311
+ appMentionRetryKeys.delete(seenKey);
169312
+ return true;
169313
+ },
169314
+ clear() {
169315
+ pendingTopLevelKeys.clear();
169316
+ appMentionRetryKeys.clear();
169317
+ appMentionDispatchedKeys.clear();
169318
+ }
169319
+ };
169320
+ }
169321
+ var APP_MENTION_RETRY_TTL_MS = 60000;
169322
+ var init_inbound_debounce = __esm(() => {
169323
+ init_utils5();
169324
+ });
169325
+
169134
169326
  // src/channels/slack/ingress-controller.ts
169135
169327
  function createSlackIngressController(params) {
169136
169328
  const { config: config3 } = params;
@@ -169863,6 +170055,18 @@ function createSlackAdapter(config3) {
169863
170055
  throw error54;
169864
170056
  }
169865
170057
  }
170058
+ async function downloadAttachment(params) {
170059
+ const slackApp = await ensureApp();
170060
+ return await downloadSlackAttachmentById({
170061
+ accountId: config3.accountId,
170062
+ token: config3.botToken,
170063
+ attachmentId: params.attachmentId,
170064
+ channelId: params.chatId,
170065
+ threadTs: params.threadId,
170066
+ messageTs: params.messageId,
170067
+ client: slackApp.client
170068
+ });
170069
+ }
169866
170070
  async function sendLifecycleErrorReply(source2, errorText) {
169867
170071
  const threadTs = resolveSlackSourceThreadTs(source2);
169868
170072
  const text = formatSlackLifecycleErrorMessage(errorText);
@@ -170065,6 +170269,7 @@ function createSlackAdapter(config3) {
170065
170269
  await Promise.all(status.getUniqueSources(event2.sources).map((source2) => status.activate(source2, SLACK_ASSISTANT_WORKING_STATUS, activity)));
170066
170270
  },
170067
170271
  sendMessage,
170272
+ downloadAttachment,
170068
170273
  sendDirectReply,
170069
170274
  handleControlRequestEvent,
170070
170275
  prepareInboundMessage: (msg, options3) => prepareSlackInboundMessage({
@@ -170084,6 +170289,7 @@ var init_adapter3 = __esm(async () => {
170084
170289
  init_model_picker_blocks();
170085
170290
  init_error_reporting();
170086
170291
  init_agent_thread_tracker();
170292
+ init_attachment_download();
170087
170293
  init_file_upload();
170088
170294
  init_inbound_debounce();
170089
170295
  init_ingress_controller();
@@ -170474,13 +170680,47 @@ async function reactInSlack(ctx) {
170474
170680
  });
170475
170681
  return request.remove ? `Reaction removed on slack (message_id: ${result.messageId})` : `Reaction added on slack (message_id: ${result.messageId})`;
170476
170682
  }
170683
+ async function downloadSlackFile(ctx) {
170684
+ const { request } = ctx;
170685
+ if (!request.attachmentId?.trim()) {
170686
+ return "Error: Slack download-file requires attachmentId.";
170687
+ }
170688
+ if (!request.messageId?.trim()) {
170689
+ return "Error: Slack download-file requires messageId from the attachment's Slack context.";
170690
+ }
170691
+ if (typeof ctx.adapter.downloadAttachment !== "function") {
170692
+ return "Error: Running Slack adapter does not support attachment downloads.";
170693
+ }
170694
+ const attachment = await ctx.adapter.downloadAttachment({
170695
+ attachmentId: request.attachmentId,
170696
+ chatId: request.chatId,
170697
+ threadId: request.threadId ?? null,
170698
+ messageId: request.messageId
170699
+ });
170700
+ if (!attachment.localPath) {
170701
+ return `Error: Slack attachment ${request.attachmentId} was not downloaded.`;
170702
+ }
170703
+ return `Slack attachment downloaded (local_path: ${attachment.localPath})`;
170704
+ }
170477
170705
  var slackMessageActions;
170478
170706
  var init_message_actions2 = __esm(() => {
170479
170707
  init_target_resolution();
170480
170708
  slackMessageActions = {
170481
170709
  describeMessageTool() {
170482
170710
  return {
170483
- actions: ["send", "react", "upload-file"]
170711
+ actions: ["send", "react", "upload-file", "download-file"],
170712
+ schema: {
170713
+ properties: {
170714
+ attachmentId: {
170715
+ type: "string",
170716
+ description: "Slack attachment id for action='download-file'. Copy attachment_id from the channel notification."
170717
+ },
170718
+ messageId: {
170719
+ type: "string",
170720
+ description: "Target Slack message id for action='react', or the source message id containing attachmentId for action='download-file'."
170721
+ }
170722
+ }
170723
+ }
170484
170724
  };
170485
170725
  },
170486
170726
  async resolveMessageTarget(params) {
@@ -170500,6 +170740,8 @@ var init_message_actions2 = __esm(() => {
170500
170740
  return await sendSlackMessage(ctx);
170501
170741
  case "react":
170502
170742
  return await reactInSlack(ctx);
170743
+ case "download-file":
170744
+ return await downloadSlackFile(ctx);
170503
170745
  default:
170504
170746
  return `Error: Action "${ctx.request.action}" is not supported on slack.`;
170505
170747
  }
@@ -170739,7 +170981,7 @@ function resolveDiscordChannelMode(channelId, parentChannelId, isThread, allowed
170739
170981
  // src/channels/discord/media.ts
170740
170982
  import { randomUUID as randomUUID10 } from "node:crypto";
170741
170983
  import { mkdirSync as mkdirSync6 } from "node:fs";
170742
- import { writeFile as writeFile7 } from "node:fs/promises";
170984
+ import { writeFile as writeFile6 } from "node:fs/promises";
170743
170985
  import { tmpdir as tmpdir2 } from "node:os";
170744
170986
  import { join as join13 } from "node:path";
170745
170987
  function ensureAttachmentsDir() {
@@ -170803,7 +171045,7 @@ async function resolveDiscordInboundAttachments(params) {
170803
171045
  console.warn(`[Discord] Skipping oversized attachment ${name}: ${buffer.byteLength} bytes`);
170804
171046
  continue;
170805
171047
  }
170806
- await writeFile7(localPath, buffer);
171048
+ await writeFile6(localPath, buffer);
170807
171049
  const entry = {
170808
171050
  id: attachment.id,
170809
171051
  name,
@@ -170909,7 +171151,7 @@ function formatDiscordDeliveryError(error54) {
170909
171151
  }
170910
171152
 
170911
171153
  // src/channels/discord/utils.ts
170912
- function isNonEmptyString4(value) {
171154
+ function isNonEmptyString5(value) {
170913
171155
  return typeof value === "string" && value.length > 0;
170914
171156
  }
170915
171157
  function isDiscordTextChannel(channel) {
@@ -170976,7 +171218,7 @@ function shouldAutoThreadOnDiscordMention(account, channelId) {
170976
171218
  return account.autoThreadOnMention ?? false;
170977
171219
  }
170978
171220
  function buildDiscordIngressMessageKey(accountId, messageId) {
170979
- if (!isNonEmptyString4(accountId) || !isNonEmptyString4(messageId)) {
171221
+ if (!isNonEmptyString5(accountId) || !isNonEmptyString5(messageId)) {
170980
171222
  return null;
170981
171223
  }
170982
171224
  return `${accountId}:${messageId}`;
@@ -171060,13 +171302,13 @@ function createDiscordAdapter(config3) {
171060
171302
  return false;
171061
171303
  }
171062
171304
  function getLifecycleMessageKey(source2) {
171063
- if (source2.channel !== "discord" || !isNonEmptyString4(source2.chatId) || !isNonEmptyString4(source2.messageId)) {
171305
+ if (source2.channel !== "discord" || !isNonEmptyString5(source2.chatId) || !isNonEmptyString5(source2.messageId)) {
171064
171306
  return null;
171065
171307
  }
171066
171308
  return `${source2.chatId}:${source2.messageId}`;
171067
171309
  }
171068
171310
  function getLifecycleReplyKey(source2) {
171069
- if (source2.channel !== "discord" || !isNonEmptyString4(source2.chatId)) {
171311
+ if (source2.channel !== "discord" || !isNonEmptyString5(source2.chatId)) {
171070
171312
  return null;
171071
171313
  }
171072
171314
  return [
@@ -171079,7 +171321,7 @@ function createDiscordAdapter(config3) {
171079
171321
  if (source2.channel !== "discord")
171080
171322
  return null;
171081
171323
  const channelId = source2.threadId ?? source2.chatId;
171082
- return isNonEmptyString4(channelId) ? channelId : null;
171324
+ return isNonEmptyString5(channelId) ? channelId : null;
171083
171325
  }
171084
171326
  function getTypingSourceKey(source2) {
171085
171327
  const channelId = getTypingChannelId(source2);
@@ -171131,7 +171373,7 @@ function createDiscordAdapter(config3) {
171131
171373
  return true;
171132
171374
  }
171133
171375
  async function sendLifecycleReaction(source2, emoji3, remove = false) {
171134
- if (!client || !isNonEmptyString4(source2.messageId))
171376
+ if (!client || !isNonEmptyString5(source2.messageId))
171135
171377
  return;
171136
171378
  try {
171137
171379
  const channel = await client.channels.fetch(source2.chatId);
@@ -171670,7 +171912,7 @@ function createDiscordAdapter(config3) {
171670
171912
  clearTypingForChannel(chatId);
171671
171913
  },
171672
171914
  async prepareInboundMessage(msg, options3) {
171673
- if (!options3?.isFirstRouteTurn || msg.channel !== "discord" || msg.chatType !== "channel" || !isNonEmptyString4(msg.threadId) || !client) {
171915
+ if (!options3?.isFirstRouteTurn || msg.channel !== "discord" || msg.chatType !== "channel" || !isNonEmptyString5(msg.threadId) || !client) {
171674
171916
  return msg;
171675
171917
  }
171676
171918
  const starter = await resolveDiscordThreadStarter({
@@ -172091,7 +172333,7 @@ var WHATSAPP_PHONE_SUFFIX = "@s.whatsapp.net", WHATSAPP_LID_SUFFIX = "@lid", WHA
172091
172333
 
172092
172334
  // src/channels/whatsapp/media.ts
172093
172335
  import { randomUUID as randomUUID12 } from "node:crypto";
172094
- import { mkdir as mkdir5, writeFile as writeFile8 } from "node:fs/promises";
172336
+ import { mkdir as mkdir5, writeFile as writeFile7 } from "node:fs/promises";
172095
172337
  import { basename as basename10, extname as extname5, join as join14 } from "node:path";
172096
172338
  function unwrapWhatsAppMessageContent(message) {
172097
172339
  if (!message || typeof message !== "object")
@@ -172273,7 +172515,7 @@ async function collectWhatsAppAttachments(params) {
172273
172515
  if (!buffer) {
172274
172516
  return { attachments: [attachment] };
172275
172517
  }
172276
- await writeFile8(localPath, buffer);
172518
+ await writeFile7(localPath, buffer);
172277
172519
  attachment.localPath = localPath;
172278
172520
  if (isVoice && params.transcribeVoice) {
172279
172521
  const result = await transcribeAudioFile(localPath);
@@ -177309,14 +177551,19 @@ function escapeXmlText(text) {
177309
177551
  function escapeXmlAttribute(text) {
177310
177552
  return escapeXmlText(text).replace(/"/g, "&quot;").replace(/'/g, "&apos;");
177311
177553
  }
177554
+ function formatMebibytes(bytes) {
177555
+ const mebibytes = bytes / (1024 * 1024);
177556
+ const rounded = mebibytes >= 100 ? Math.round(mebibytes).toString() : mebibytes.toFixed(1);
177557
+ return `${rounded.replace(/\.0$/, "")} MiB`;
177558
+ }
177312
177559
  function hasNotificationAttachmentPaths(msg) {
177313
- if (msg.attachments?.length) {
177560
+ if (msg.attachments?.some((attachment) => attachment.localPath)) {
177314
177561
  return true;
177315
177562
  }
177316
- if (msg.threadContext?.starter?.attachments?.length) {
177563
+ if (msg.threadContext?.starter?.attachments?.some((attachment) => attachment.localPath)) {
177317
177564
  return true;
177318
177565
  }
177319
- return Boolean(msg.threadContext?.history?.some((entry) => entry.attachments?.length));
177566
+ return Boolean(msg.threadContext?.history?.some((entry) => entry.attachments?.some((attachment) => attachment.localPath)));
177320
177567
  }
177321
177568
  function buildChannelReminderText(msg) {
177322
177569
  const localTime = escapeXmlText(getLocalTime());
@@ -177339,7 +177586,7 @@ function buildChannelReminderText(msg) {
177339
177586
  lines.splice(lines.length - 2, 0, threadLine);
177340
177587
  }
177341
177588
  if (msg.channel === "slack") {
177342
- lines.splice(lines.length - 2, 0, 'On Slack, MessageChannel also supports action="react" with emoji + messageId, and action="upload-file" with media.', 'For Slack requests that require nontrivial work or several tool calls, send a short MessageChannel action="send" acknowledgement before starting other tools. This gives the Slack user verbal acknowledgement and a View in web link. Do not do this for no-ops, reaction-only responses, or simple no-tool answers.');
177589
+ lines.splice(lines.length - 2, 0, 'On Slack, MessageChannel also supports action="react" with emoji + messageId, action="upload-file" with media, and action="download-file" with attachmentId + messageId.', 'For Slack requests that require nontrivial work or several tool calls, send a short MessageChannel action="send" acknowledgement before starting other tools. This gives the Slack user verbal acknowledgement and a View in web link. Do not do this for no-ops, reaction-only responses, or simple no-tool answers.');
177343
177590
  }
177344
177591
  if (msg.channel === "telegram") {
177345
177592
  lines.splice(lines.length - 2, 0, 'On Telegram, MessageChannel also supports action="react" with emoji + messageId, and action="upload-file" with media.');
@@ -177359,11 +177606,13 @@ function buildChannelReminderText(msg) {
177359
177606
  return lines.join(`
177360
177607
  `);
177361
177608
  }
177362
- function buildAttachmentXml(attachment) {
177363
- const attrs = [
177364
- `kind="${escapeXmlAttribute(attachment.kind)}"`,
177365
- `local_path="${escapeXmlAttribute(attachment.localPath)}"`
177366
- ];
177609
+ function buildAttachmentXml(attachment, context3) {
177610
+ const attrs = [`kind="${escapeXmlAttribute(attachment.kind)}"`];
177611
+ if (attachment.localPath) {
177612
+ attrs.push(`local_path="${escapeXmlAttribute(attachment.localPath)}"`);
177613
+ } else {
177614
+ attrs.push('download_status="not_downloaded"');
177615
+ }
177367
177616
  if (attachment.id) {
177368
177617
  attrs.push(`attachment_id="${escapeXmlAttribute(attachment.id)}"`);
177369
177618
  }
@@ -177376,6 +177625,19 @@ function buildAttachmentXml(attachment) {
177376
177625
  if (typeof attachment.sizeBytes === "number") {
177377
177626
  attrs.push(`size_bytes="${attachment.sizeBytes}"`);
177378
177627
  }
177628
+ const sourceMessageId = attachment.sourceMessageId ?? context3.messageId;
177629
+ if (!attachment.localPath && sourceMessageId) {
177630
+ attrs.push(`source_message_id="${escapeXmlAttribute(sourceMessageId)}"`);
177631
+ }
177632
+ if (!attachment.localPath && attachment.sourceThreadId) {
177633
+ attrs.push(`source_thread_id="${escapeXmlAttribute(attachment.sourceThreadId)}"`);
177634
+ }
177635
+ if (attachment.downloadReason) {
177636
+ attrs.push(`download_reason="${escapeXmlAttribute(attachment.downloadReason)}"`);
177637
+ }
177638
+ if (typeof attachment.autoDownloadLimitBytes === "number") {
177639
+ attrs.push(`auto_download_limit_bytes="${attachment.autoDownloadLimitBytes}"`);
177640
+ }
177379
177641
  const children = [];
177380
177642
  if (attachment.transcription) {
177381
177643
  children.push(`<attempted_transcription>${escapeXmlText(attachment.transcription)}</attempted_transcription>`);
@@ -177383,6 +177645,17 @@ function buildAttachmentXml(attachment) {
177383
177645
  if (attachment.transcriptionError) {
177384
177646
  children.push(`<attempted_transcription_error>${escapeXmlText(attachment.transcriptionError)}</attempted_transcription_error>`);
177385
177647
  }
177648
+ if (!attachment.localPath && context3.channel === "slack" && attachment.id && sourceMessageId) {
177649
+ const accountArg = context3.accountId ? `, accountId="${escapeXmlAttribute(context3.accountId)}"` : "";
177650
+ const threadArg = attachment.sourceThreadId ? `, threadId="${escapeXmlAttribute(attachment.sourceThreadId)}"` : "";
177651
+ const action3 = `MessageChannel with action="download-file", channel="slack", chat_id="${escapeXmlAttribute(context3.chatId)}"${accountArg}${threadArg}, attachmentId="${escapeXmlAttribute(attachment.id)}", and messageId="${escapeXmlAttribute(sourceMessageId)}"`;
177652
+ if (attachment.downloadReason === "exceeds_auto_download_limit") {
177653
+ const sizeNote = typeof attachment.sizeBytes === "number" ? `This file is ${formatMebibytes(attachment.sizeBytes)}${typeof attachment.autoDownloadLimitBytes === "number" ? `, above the ${formatMebibytes(attachment.autoDownloadLimitBytes)} automatic download limit` : ""}. ` : "";
177654
+ children.push(`<download-instruction>${sizeNote}Call ${action3}. The tool downloads the file into the same Slack inbound attachment directory and returns its local_path. Do not ask the sender to reattach it.</download-instruction>`);
177655
+ } else {
177656
+ children.push(`<download-retry>Automatic download did not complete. Call ${action3} to retry. The action may return a precise error if Slack still cannot provide the file.</download-retry>`);
177657
+ }
177658
+ }
177386
177659
  if (children.length > 0) {
177387
177660
  return `<attachment ${attrs.join(" ")}>
177388
177661
  ${children.join(`
@@ -177432,7 +177705,7 @@ ${escapeXmlText(replyContext.text)}
177432
177705
  }
177433
177706
  return `<reply-context${attrString} />`;
177434
177707
  }
177435
- function buildThreadContextEntryXml(tagName, entry) {
177708
+ function buildThreadContextEntryXml(tagName, entry, context3) {
177436
177709
  const attrs = [];
177437
177710
  if (entry.senderId) {
177438
177711
  attrs.push(`sender_id="${escapeXmlAttribute(entry.senderId)}"`);
@@ -177446,7 +177719,10 @@ function buildThreadContextEntryXml(tagName, entry) {
177446
177719
  const attrString = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
177447
177720
  const body = [
177448
177721
  ...entry.text ? [escapeXmlText(entry.text)] : [],
177449
- ...(entry.attachments ?? []).map(buildAttachmentXml)
177722
+ ...(entry.attachments ?? []).map((attachment) => buildAttachmentXml(attachment, {
177723
+ ...context3,
177724
+ messageId: entry.messageId
177725
+ }))
177450
177726
  ].join(`
177451
177727
  `);
177452
177728
  return `<${tagName}${attrString}>
@@ -177460,13 +177736,21 @@ function buildThreadContextXml(msg) {
177460
177736
  }
177461
177737
  const parts = [];
177462
177738
  if (threadContext.starter) {
177463
- parts.push(buildThreadContextEntryXml("thread-starter", threadContext.starter));
177739
+ parts.push(buildThreadContextEntryXml("thread-starter", threadContext.starter, {
177740
+ channel: msg.channel,
177741
+ accountId: msg.accountId,
177742
+ chatId: msg.chatId
177743
+ }));
177464
177744
  }
177465
177745
  const historyEntries = threadContext.history ?? [];
177466
177746
  if (historyEntries.length > 0) {
177467
177747
  parts.push([
177468
177748
  "<thread-history>",
177469
- ...historyEntries.map((entry) => buildThreadContextEntryXml("thread-message", entry)),
177749
+ ...historyEntries.map((entry) => buildThreadContextEntryXml("thread-message", entry, {
177750
+ channel: msg.channel,
177751
+ accountId: msg.accountId,
177752
+ chatId: msg.chatId
177753
+ })),
177470
177754
  "</thread-history>"
177471
177755
  ].join(`
177472
177756
  `));
@@ -177501,7 +177785,12 @@ function buildChannelNotificationXml(msg) {
177501
177785
  const reactionXml = buildReactionXml(msg);
177502
177786
  const replyContextXml = buildReplyContextXml(msg);
177503
177787
  const threadContextXml = buildThreadContextXml(msg);
177504
- const attachmentXml = (msg.attachments ?? []).map(buildAttachmentXml);
177788
+ const attachmentXml = (msg.attachments ?? []).map((attachment) => buildAttachmentXml(attachment, {
177789
+ channel: msg.channel,
177790
+ accountId: msg.accountId,
177791
+ chatId: msg.chatId,
177792
+ messageId: msg.messageId
177793
+ }));
177505
177794
  const body = [
177506
177795
  threadContextXml,
177507
177796
  replyContextXml,
@@ -179757,7 +180046,10 @@ This tool is currently scoped to a routed external channel turn. Plain assistant
179757
180046
  const slackWorkAcknowledgement = discovery.activeChannels.includes("slack") ? `
179758
180047
 
179759
180048
  For Slack requests that require nontrivial work or several tool calls, send one short MessageChannel call with action="send" before starting other tools. This gives the Slack user verbal acknowledgement and a View in web link. Do not do this for no-ops, reaction-only responses, or simple no-tool answers.` : "";
179760
- return `${description}${scopedReplyContract}${slackWorkAcknowledgement}
180049
+ const slackAttachmentDownload = discovery.activeChannels.includes("slack") ? `
180050
+
180051
+ Slack attachments that exceed the automatic download limit include an exact recovery instruction. Use action="download-file" with channel, chat_id, attachmentId, and messageId from that instruction. The action saves the file in the normal Slack inbound attachment directory and returns its local_path.` : "";
180052
+ return `${description}${scopedReplyContract}${slackWorkAcknowledgement}${slackAttachmentDownload}
179761
180053
 
179762
180054
  Currently active channels: ${channelList}. Available actions across the active channels: ${actionList}. The JSON schema reflects the currently active channel plugins.`;
179763
180055
  }
@@ -183455,7 +183747,7 @@ var init_apply_patch = __esm(() => {
183455
183747
  });
183456
183748
 
183457
183749
  // src/tools/impl/artifact-files.ts
183458
- import { mkdir as mkdir6, readFile as readFile6, stat as stat3, writeFile as writeFile9 } from "node:fs/promises";
183750
+ import { mkdir as mkdir6, readFile as readFile5, stat as stat3, writeFile as writeFile8 } from "node:fs/promises";
183459
183751
  import { homedir as homedir9 } from "node:os";
183460
183752
  import { dirname as dirname7, isAbsolute as isAbsolute5, join as join19, relative as relative2, resolve as resolve8 } from "node:path";
183461
183753
  function assertArtifactsExperimentEnabled(toolName) {
@@ -183513,7 +183805,7 @@ async function read_artifact_file(args) {
183513
183805
  if (stats.size > MAX_READ_FILE_BYTES) {
183514
183806
  throw new Error(`read_artifact_file: file is too large to read (${stats.size} bytes)`);
183515
183807
  }
183516
- const buffer = await readFile6(absolutePath);
183808
+ const buffer = await readFile5(absolutePath);
183517
183809
  return {
183518
183810
  path: relativePath,
183519
183811
  content: buffer.toString(encoding),
@@ -183527,7 +183819,7 @@ async function write_artifact_file(args) {
183527
183819
  const encoding = getEncoding(args.encoding);
183528
183820
  const buffer = Buffer.from(args.content, encoding);
183529
183821
  await mkdir6(dirname7(absolutePath), { recursive: true });
183530
- await writeFile9(absolutePath, buffer);
183822
+ await writeFile8(absolutePath, buffer);
183531
183823
  return {
183532
183824
  path: relativePath,
183533
183825
  bytes: buffer.byteLength,
@@ -184216,6 +184508,9 @@ class TurnLifecycle {
184216
184508
  get activeRunId() {
184217
184509
  return this.#state.kind === "active" ? this.#state.runId : null;
184218
184510
  }
184511
+ get executingToolCallIds() {
184512
+ return this.#state.kind === "active" || this.#state.kind === "cancelling" ? this.#state.executingToolCallIds : [];
184513
+ }
184219
184514
  get lastStopReason() {
184220
184515
  return this.#lastStopReason;
184221
184516
  }
@@ -187370,7 +187665,7 @@ var init_worktree_lock = __esm(() => {
187370
187665
 
187371
187666
  // src/websocket/listener/remote-settings.ts
187372
187667
  import { existsSync as existsSync20, readFileSync as readFileSync16 } from "node:fs";
187373
- import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
187668
+ import { mkdir as mkdir7, writeFile as writeFile9 } from "node:fs/promises";
187374
187669
  import { homedir as homedir16 } from "node:os";
187375
187670
  import path12 from "node:path";
187376
187671
  function getRemoteSettingsPath() {
@@ -187414,7 +187709,7 @@ function saveRemoteSettings(updates) {
187414
187709
  };
187415
187710
  const snapshot = _cache;
187416
187711
  const settingsPath = getRemoteSettingsPath();
187417
- mkdir7(path12.dirname(settingsPath), { recursive: true }).then(() => writeFile10(settingsPath, JSON.stringify(snapshot, null, 2))).catch(() => {});
187712
+ mkdir7(path12.dirname(settingsPath), { recursive: true }).then(() => writeFile9(settingsPath, JSON.stringify(snapshot, null, 2))).catch(() => {});
187418
187713
  }
187419
187714
  function loadLegacyCwdCache() {
187420
187715
  try {
@@ -188209,7 +188504,7 @@ var require_filesystem = __commonJS((exports, module3) => {
188209
188504
  fs5.close(fd, () => {});
188210
188505
  return buffer.subarray(0, bytesRead);
188211
188506
  };
188212
- var readFile7 = (path13) => new Promise((resolve13, reject) => {
188507
+ var readFile6 = (path13) => new Promise((resolve13, reject) => {
188213
188508
  fs5.open(path13, "r", (err, fd) => {
188214
188509
  if (err) {
188215
188510
  reject(err);
@@ -188226,7 +188521,7 @@ var require_filesystem = __commonJS((exports, module3) => {
188226
188521
  LDD_PATH,
188227
188522
  SELF_PATH,
188228
188523
  readFileSync: readFileSync19,
188229
- readFile: readFile7
188524
+ readFile: readFile6
188230
188525
  };
188231
188526
  });
188232
188527
 
@@ -188268,7 +188563,7 @@ var require_elf = __commonJS((exports, module3) => {
188268
188563
  var require_detect_libc = __commonJS((exports, module3) => {
188269
188564
  var childProcess = __require("child_process");
188270
188565
  var { isLinux, getReport } = require_process();
188271
- var { LDD_PATH, SELF_PATH, readFile: readFile7, readFileSync: readFileSync19 } = require_filesystem();
188566
+ var { LDD_PATH, SELF_PATH, readFile: readFile6, readFileSync: readFileSync19 } = require_filesystem();
188272
188567
  var { interpreterPath } = require_elf();
188273
188568
  var cachedFamilyInterpreter;
188274
188569
  var cachedFamilyFilesystem;
@@ -188348,7 +188643,7 @@ var require_detect_libc = __commonJS((exports, module3) => {
188348
188643
  }
188349
188644
  cachedFamilyFilesystem = null;
188350
188645
  try {
188351
- const lddContent = await readFile7(LDD_PATH);
188646
+ const lddContent = await readFile6(LDD_PATH);
188352
188647
  cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
188353
188648
  } catch (e2) {}
188354
188649
  return cachedFamilyFilesystem;
@@ -188370,7 +188665,7 @@ var require_detect_libc = __commonJS((exports, module3) => {
188370
188665
  }
188371
188666
  cachedFamilyInterpreter = null;
188372
188667
  try {
188373
- const selfContent = await readFile7(SELF_PATH);
188668
+ const selfContent = await readFile6(SELF_PATH);
188374
188669
  const path13 = interpreterPath(selfContent);
188375
188670
  cachedFamilyInterpreter = familyFromInterpreterPath(path13);
188376
188671
  } catch (e2) {}
@@ -188430,7 +188725,7 @@ var require_detect_libc = __commonJS((exports, module3) => {
188430
188725
  }
188431
188726
  cachedVersionFilesystem = null;
188432
188727
  try {
188433
- const lddContent = await readFile7(LDD_PATH);
188728
+ const lddContent = await readFile6(LDD_PATH);
188434
188729
  const versionMatch = lddContent.match(RE_GLIBC_VERSION);
188435
188730
  if (versionMatch) {
188436
188731
  cachedVersionFilesystem = versionMatch[1];
@@ -194624,7 +194919,7 @@ __export(exports_image_resize_sips, {
194624
194919
  convertHeicToJpegWithSips: () => convertHeicToJpegWithSips
194625
194920
  });
194626
194921
  import { execFile as execFile2 } from "node:child_process";
194627
- import { mkdtemp, readFile as readFile7, rm as rm2, writeFile as writeFile11 } from "node:fs/promises";
194922
+ import { mkdtemp, readFile as readFile6, rm as rm3, writeFile as writeFile10 } from "node:fs/promises";
194628
194923
  import { tmpdir as tmpdir6 } from "node:os";
194629
194924
  import { join as join29 } from "node:path";
194630
194925
  function execFileAsync2(file3, args) {
@@ -194643,7 +194938,7 @@ async function convertHeicToJpegWithSips(buffer) {
194643
194938
  const inputPath = join29(workDir, "input.heic");
194644
194939
  const outputPath = join29(workDir, "output.jpg");
194645
194940
  try {
194646
- await writeFile11(inputPath, buffer);
194941
+ await writeFile10(inputPath, buffer);
194647
194942
  await execFileAsync2("/usr/bin/sips", [
194648
194943
  "-s",
194649
194944
  "format",
@@ -194655,9 +194950,9 @@ async function convertHeicToJpegWithSips(buffer) {
194655
194950
  "--out",
194656
194951
  outputPath
194657
194952
  ]);
194658
- return Buffer.from(await readFile7(outputPath));
194953
+ return Buffer.from(await readFile6(outputPath));
194659
194954
  } finally {
194660
- await rm2(workDir, { recursive: true, force: true });
194955
+ await rm3(workDir, { recursive: true, force: true });
194661
194956
  }
194662
194957
  }
194663
194958
  var init_image_resize_sips = () => {};
@@ -194737,13 +195032,40 @@ async function normalizeMessageContentImages(content, resize = resizeImageIfNeed
194737
195032
  const filteredParts = normalizedParts.filter((part) => part !== null);
194738
195033
  return didChange ? filteredParts : content;
194739
195034
  }
194740
- async function normalizeMessageImageParts(messages, resize = resizeImageIfNeeded3) {
195035
+ async function normalizeApprovalImages(message, resize, failureMode) {
195036
+ if (!Array.isArray(message.approvals)) {
195037
+ return message;
195038
+ }
195039
+ let didChange = false;
195040
+ const approvals = await Promise.all(message.approvals.map(async (approval) => {
195041
+ if (!("tool_return" in approval)) {
195042
+ return approval;
195043
+ }
195044
+ const toolReturn = await normalizeMessageContentImages(approval.tool_return, resize, failureMode);
195045
+ if (toolReturn === approval.tool_return) {
195046
+ return approval;
195047
+ }
195048
+ didChange = true;
195049
+ return {
195050
+ ...approval,
195051
+ tool_return: toolReturn
195052
+ };
195053
+ }));
195054
+ return didChange ? { ...message, approvals } : message;
195055
+ }
195056
+ async function normalizeMessageImageParts(messages, options3 = {}) {
194741
195057
  let didChange = false;
195058
+ const resize = options3.resize ?? resizeImageIfNeeded3;
194742
195059
  const normalizedMessages = await Promise.all(messages.map(async (message) => {
195060
+ const failureMode = getImageFailureMode(message, options3.failureModesByMessageOtid);
194743
195061
  if (!("content" in message)) {
194744
- return message;
195062
+ const normalizedApproval = await normalizeApprovalImages(message, resize, failureMode);
195063
+ if (normalizedApproval !== message) {
195064
+ didChange = true;
195065
+ }
195066
+ return normalizedApproval;
194745
195067
  }
194746
- const normalizedContent = await normalizeMessageContentImages(message.content, resize);
195068
+ const normalizedContent = await normalizeMessageContentImages(message.content, resize, failureMode);
194747
195069
  if (normalizedContent !== message.content) {
194748
195070
  didChange = true;
194749
195071
  return {
@@ -194755,18 +195077,51 @@ async function normalizeMessageImageParts(messages, resize = resizeImageIfNeeded
194755
195077
  }));
194756
195078
  return didChange ? normalizedMessages : messages;
194757
195079
  }
195080
+ function getImageFailureMode(message, failureModesByMessageOtid) {
195081
+ if (!failureModesByMessageOtid) {
195082
+ return "strict";
195083
+ }
195084
+ const otid = message.otid;
195085
+ return typeof otid === "string" ? failureModesByMessageOtid[otid] ?? "strict" : "strict";
195086
+ }
195087
+ function buildImageFailureModesByMessageOtid(messages, failureMode) {
195088
+ const entries = [];
195089
+ for (const message of messages) {
195090
+ if (!("content" in message)) {
195091
+ continue;
195092
+ }
195093
+ const otid = message.otid;
195094
+ if (typeof otid === "string" && otid.length > 0) {
195095
+ entries.push([otid, failureMode]);
195096
+ }
195097
+ }
195098
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
195099
+ }
195100
+ function mergeImageFailureModesByMessageOtid(...failureModes) {
195101
+ const presentModes = failureModes.filter((modes) => modes !== undefined);
195102
+ return presentModes.length > 0 ? Object.assign({}, ...presentModes) : undefined;
195103
+ }
194758
195104
  function assertSupportedBase64ImageMediaTypes(messages) {
194759
195105
  for (const message of messages) {
194760
- if (!("content" in message) || typeof message.content === "string") {
195106
+ if ("content" in message) {
195107
+ assertSupportedBase64ImageContent(message.content);
194761
195108
  continue;
194762
195109
  }
194763
- for (const part of message.content) {
194764
- if (!isBase64ImageContentPart(part)) {
195110
+ for (const approval of message.approvals ?? []) {
195111
+ if (!("tool_return" in approval)) {
194765
195112
  continue;
194766
195113
  }
194767
- if (!isSupportedBase64ImageMediaType(part.source.media_type)) {
194768
- throw new Error(`Unsupported base64 image media type after normalization: ${part.source.media_type}`);
194769
- }
195114
+ assertSupportedBase64ImageContent(approval.tool_return);
195115
+ }
195116
+ }
195117
+ }
195118
+ function assertSupportedBase64ImageContent(content) {
195119
+ if (typeof content === "string") {
195120
+ return;
195121
+ }
195122
+ for (const part of content) {
195123
+ if (isBase64ImageContentPart(part) && !isSupportedBase64ImageMediaType(part.source.media_type)) {
195124
+ throw new Error(`Unsupported base64 image media type after normalization: ${part.source.media_type}`);
194770
195125
  }
194771
195126
  }
194772
195127
  }
@@ -194979,7 +195334,7 @@ __export(exports_skills2, {
194979
195334
  GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR
194980
195335
  });
194981
195336
  import { existsSync as existsSync22 } from "node:fs";
194982
- import { readdir as readdir3, readFile as readFile8, realpath, stat as stat4 } from "node:fs/promises";
195337
+ import { readdir as readdir3, readFile as readFile7, realpath, stat as stat4 } from "node:fs/promises";
194983
195338
  import { dirname as dirname12, join as join30 } from "node:path";
194984
195339
  import { fileURLToPath as fileURLToPath3 } from "node:url";
194985
195340
  function getBundledSkillsPath() {
@@ -195151,7 +195506,7 @@ async function findSkillFiles(currentPath, rootPath, skills, errors7, source2, v
195151
195506
  }
195152
195507
  }
195153
195508
  async function parseSkillFile(filePath, rootPath, source2) {
195154
- const content = await readFile8(filePath, "utf-8");
195509
+ const content = await readFile7(filePath, "utf-8");
195155
195510
  const { frontmatter, body } = parseFrontmatter(content);
195156
195511
  const normalizedRoot = rootPath.endsWith("/") ? rootPath.slice(0, -1) : rootPath;
195157
195512
  const relativePath = filePath.slice(normalizedRoot.length + 1);
@@ -195585,12 +195940,15 @@ function getStreamRequestContext(stream11) {
195585
195940
  return streamRequestContexts.get(stream11);
195586
195941
  }
195587
195942
  function buildConversationMessagesCreateRequestBody(conversationId, messages, opts = { streamTokens: true, background: true }, clientTools, clientSkills = []) {
195943
+ return buildRequestBodyFromPreparedMessages(conversationId, normalizeOutgoingApprovalMessages(messages, opts.approvalNormalization), opts, clientTools, clientSkills);
195944
+ }
195945
+ function buildRequestBodyFromPreparedMessages(conversationId, messages, opts, clientTools, clientSkills) {
195588
195946
  const isDefaultConversation = conversationId === "default";
195589
195947
  if (isDefaultConversation && !opts.agentId) {
195590
195948
  throw new Error("agentId is required in opts when using default conversation");
195591
195949
  }
195592
195950
  return {
195593
- messages: normalizeOutgoingApprovalMessages(messages, opts.approvalNormalization),
195951
+ messages,
195594
195952
  streaming: true,
195595
195953
  stream_tokens: opts.streamTokens ?? true,
195596
195954
  include_pings: true,
@@ -195612,7 +195970,10 @@ async function sendMessageStreamWithBackend(backend, conversationId, messages, o
195612
195970
  }) {
195613
195971
  const requestStartTime = isTimingsEnabled() ? performance.now() : undefined;
195614
195972
  const requestStartedAtMs = Date.now();
195615
- const normalizedMessages = opts.skipImageNormalization ? messages : await normalizeMessageImageParts(messages);
195973
+ const canonicalMessages = normalizeOutgoingApprovalMessages(messages, opts.approvalNormalization);
195974
+ const normalizedMessages = await normalizeMessageImageParts(canonicalMessages, {
195975
+ failureModesByMessageOtid: opts.imageFailureModesByMessageOtid
195976
+ });
195616
195977
  assertSupportedBase64ImageMediaTypes(normalizedMessages);
195617
195978
  const preparedToolContext = opts.preparedToolContext ? opts.preparedToolContext : await (async () => {
195618
195979
  await waitForToolsetReady();
@@ -195631,7 +195992,7 @@ async function sendMessageStreamWithBackend(backend, conversationId, messages, o
195631
195992
  const isApprovalContinuation = isApprovalContinuationRequest(normalizedMessages);
195632
195993
  const canUsePreviousResponseState = isApprovalContinuation && opts.allowResponseStateReuse === true;
195633
195994
  const previousResponseId = canUsePreviousResponseState ? responseStateIdsByScope.get(responseStateScope) : undefined;
195634
- const requestBody = buildConversationMessagesCreateRequestBody(conversationId, normalizedMessages, opts, clientTools, clientSkills);
195995
+ const requestBody = buildRequestBodyFromPreparedMessages(conversationId, normalizedMessages, opts, clientTools, clientSkills);
195635
195996
  if (isDebugEnabled()) {
195636
195997
  debugLog("agent-message", "sendMessageStream: conversationId=%s, agentId=%s", conversationId, opts.agentId ?? "(none)");
195637
195998
  const formattedSkills = clientSkills.map((skill) => `${skill.name} (${skill.location})`);
@@ -198443,7 +198804,7 @@ var require_typescript = __commonJS((exports, module3) => {
198443
198804
  walkUpParenthesizedTypesAndGetParentAndChild: () => walkUpParenthesizedTypesAndGetParentAndChild,
198444
198805
  whitespaceOrMapCommentRegExp: () => whitespaceOrMapCommentRegExp,
198445
198806
  writeCommentRange: () => writeCommentRange,
198446
- writeFile: () => writeFile12,
198807
+ writeFile: () => writeFile11,
198447
198808
  writeFileEnsuringDirectories: () => writeFileEnsuringDirectories,
198448
198809
  zipWith: () => zipWith
198449
198810
  });
@@ -204235,7 +204596,7 @@ ${lanes.join(`
204235
204596
  writeOutputIsTTY() {
204236
204597
  return process.stdout.isTTY;
204237
204598
  },
204238
- readFile: readFile9,
204599
+ readFile: readFile8,
204239
204600
  writeFile: writeFile22,
204240
204601
  watchFile: watchFile2,
204241
204602
  watchDirectory,
@@ -204428,7 +204789,7 @@ ${lanes.join(`
204428
204789
  function fsWatchWorker(fileOrDirectory, recursive, callback) {
204429
204790
  return _fs.watch(fileOrDirectory, fsSupportsRecursiveFsWatch ? { persistent: true, recursive: !!recursive } : { persistent: true }, callback);
204430
204791
  }
204431
- function readFile9(fileName, _encoding) {
204792
+ function readFile8(fileName, _encoding) {
204432
204793
  let buffer;
204433
204794
  try {
204434
204795
  buffer = _fs.readFileSync(fileName);
@@ -215752,7 +216113,7 @@ ${lanes.join(`
215752
216113
  sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) : sourceFilePath;
215753
216114
  return combinePaths(newDirPath, sourceFilePath);
215754
216115
  }
215755
- function writeFile12(host, diagnostics2, fileName, text, writeByteOrderMark, sourceFiles, data) {
216116
+ function writeFile11(host, diagnostics2, fileName, text, writeByteOrderMark, sourceFiles, data) {
215756
216117
  host.writeFile(fileName, text, writeByteOrderMark, (hostErrorMessage) => {
215757
216118
  diagnostics2.add(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage));
215758
216119
  }, sourceFiles, data);
@@ -226205,8 +226566,8 @@ ${lanes.join(`
226205
226566
  return;
226206
226567
  }
226207
226568
  function tryRenameExternalModule(factory2, moduleName, sourceFile) {
226208
- const rename = sourceFile.renamedDependencies && sourceFile.renamedDependencies.get(moduleName.text);
226209
- return rename ? factory2.createStringLiteral(rename) : undefined;
226569
+ const rename2 = sourceFile.renamedDependencies && sourceFile.renamedDependencies.get(moduleName.text);
226570
+ return rename2 ? factory2.createStringLiteral(rename2) : undefined;
226210
226571
  }
226211
226572
  function tryGetModuleNameFromFile(factory2, file3, host, options3) {
226212
226573
  if (!file3) {
@@ -228735,8 +229096,8 @@ ${lanes.join(`
228735
229096
  function isMissingList(arr) {
228736
229097
  return !!arr.isMissingList;
228737
229098
  }
228738
- function parseBracketedList(kind, parseElement, open2, close) {
228739
- if (parseExpected(open2)) {
229099
+ function parseBracketedList(kind, parseElement, open3, close) {
229100
+ if (parseExpected(open3)) {
228740
229101
  const result = parseDelimitedList(kind, parseElement);
228741
229102
  parseExpected(close);
228742
229103
  return result;
@@ -230441,12 +230802,12 @@ ${lanes.join(`
230441
230802
  parseExpected(20);
230442
230803
  return finishNode(factory2.createJsxSpreadAttribute(expression), pos);
230443
230804
  }
230444
- function parseJsxClosingElement(open2, inExpressionContext) {
230805
+ function parseJsxClosingElement(open3, inExpressionContext) {
230445
230806
  const pos = getNodePos();
230446
230807
  parseExpected(31);
230447
230808
  const tagName = parseJsxElementName();
230448
230809
  if (parseExpected(32, undefined, false)) {
230449
- if (inExpressionContext || !tagNamesAreEquivalent(open2.tagName, tagName)) {
230810
+ if (inExpressionContext || !tagNamesAreEquivalent(open3.tagName, tagName)) {
230450
230811
  nextToken();
230451
230812
  } else {
230452
230813
  scanJsxText();
@@ -235375,7 +235736,7 @@ ${lanes.join(`
235375
235736
  const possibleOption = getSpellingSuggestion(unknownOption, diagnostics2.optionDeclarations, getOptionName);
235376
235737
  return possibleOption ? createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics2.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) : createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics2.unknownOptionDiagnostic, unknownOptionErrorText || unknownOption);
235377
235738
  }
235378
- function parseCommandLineWorker(diagnostics2, commandLine, readFile9) {
235739
+ function parseCommandLineWorker(diagnostics2, commandLine, readFile8) {
235379
235740
  const options3 = {};
235380
235741
  let watchOptions;
235381
235742
  const fileNames = [];
@@ -235413,7 +235774,7 @@ ${lanes.join(`
235413
235774
  }
235414
235775
  }
235415
235776
  function parseResponseFile(fileName) {
235416
- const text = tryReadFile(fileName, readFile9 || ((fileName2) => sys.readFile(fileName2)));
235777
+ const text = tryReadFile(fileName, readFile8 || ((fileName2) => sys.readFile(fileName2)));
235417
235778
  if (!isString(text)) {
235418
235779
  errors7.push(text);
235419
235780
  return;
@@ -235516,8 +235877,8 @@ ${lanes.join(`
235516
235877
  unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1,
235517
235878
  optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument
235518
235879
  };
235519
- function parseCommandLine(commandLine, readFile9) {
235520
- return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile9);
235880
+ function parseCommandLine(commandLine, readFile8) {
235881
+ return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile8);
235521
235882
  }
235522
235883
  function getOptionFromName(optionName, allowShort) {
235523
235884
  return getOptionDeclarationFromName(getOptionsNameMap, optionName, allowShort);
@@ -235585,8 +235946,8 @@ ${lanes.join(`
235585
235946
  result.originalFileName = result.fileName;
235586
235947
  return parseJsonSourceFileConfigFileContent(result, host, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd), undefined, extraFileExtensions, extendedConfigCache, watchOptionsToExtend);
235587
235948
  }
235588
- function readConfigFile(fileName, readFile9) {
235589
- const textOrDiagnostic = tryReadFile(fileName, readFile9);
235949
+ function readConfigFile(fileName, readFile8) {
235950
+ const textOrDiagnostic = tryReadFile(fileName, readFile8);
235590
235951
  return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic };
235591
235952
  }
235592
235953
  function parseConfigFileTextToJson(fileName, jsonText) {
@@ -235596,14 +235957,14 @@ ${lanes.join(`
235596
235957
  error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : undefined
235597
235958
  };
235598
235959
  }
235599
- function readJsonConfigFile(fileName, readFile9) {
235600
- const textOrDiagnostic = tryReadFile(fileName, readFile9);
235960
+ function readJsonConfigFile(fileName, readFile8) {
235961
+ const textOrDiagnostic = tryReadFile(fileName, readFile8);
235601
235962
  return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : { fileName, parseDiagnostics: [textOrDiagnostic] };
235602
235963
  }
235603
- function tryReadFile(fileName, readFile9) {
235964
+ function tryReadFile(fileName, readFile8) {
235604
235965
  let text;
235605
235966
  try {
235606
- text = readFile9(fileName);
235967
+ text = readFile8(fileName);
235607
235968
  } catch (e2) {
235608
235969
  return createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e2.message);
235609
235970
  }
@@ -298345,7 +298706,7 @@ ${lanes.join(`
298345
298706
  return;
298346
298707
  }
298347
298708
  const buildInfo = host.getBuildInfo() || { version: version2 };
298348
- writeFile12(host, emitterDiagnostics, buildInfoPath, getBuildInfoText(buildInfo), false, undefined, { buildInfo });
298709
+ writeFile11(host, emitterDiagnostics, buildInfoPath, getBuildInfoText(buildInfo), false, undefined, { buildInfo });
298349
298710
  emittedFilesList == null || emittedFilesList.push(buildInfoPath);
298350
298711
  }
298351
298712
  function emitJsFileOrBundle(sourceFileOrBundle, jsFilePath, sourceMapFilePath) {
@@ -298504,14 +298865,14 @@ ${lanes.join(`
298504
298865
  }
298505
298866
  if (sourceMapFilePath) {
298506
298867
  const sourceMap = sourceMapGenerator.toString();
298507
- writeFile12(host, emitterDiagnostics, sourceMapFilePath, sourceMap, false, sourceFiles);
298868
+ writeFile11(host, emitterDiagnostics, sourceMapFilePath, sourceMap, false, sourceFiles);
298508
298869
  }
298509
298870
  } else {
298510
298871
  writer.writeLine();
298511
298872
  }
298512
298873
  const text = writer.getText();
298513
298874
  const data = { sourceMapUrlPos, diagnostics: transform22.diagnostics };
298514
- writeFile12(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, data);
298875
+ writeFile11(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, data);
298515
298876
  writer.clear();
298516
298877
  return !data.skippedDtsWrite;
298517
298878
  }
@@ -303033,12 +303394,12 @@ ${lanes.join(`
303033
303394
  function createCompilerHost(options3, setParentNodes) {
303034
303395
  return createCompilerHostWorker(options3, setParentNodes);
303035
303396
  }
303036
- function createGetSourceFile(readFile9, setParentNodes) {
303397
+ function createGetSourceFile(readFile8, setParentNodes) {
303037
303398
  return (fileName, languageVersionOrOptions, onError) => {
303038
303399
  let text;
303039
303400
  try {
303040
303401
  mark("beforeIORead");
303041
- text = readFile9(fileName);
303402
+ text = readFile8(fileName);
303042
303403
  mark("afterIORead");
303043
303404
  measure("I/O Read", "beforeIORead", "afterIORead");
303044
303405
  } catch (e2) {
@@ -303829,7 +304190,7 @@ ${lanes.join(`
303829
304190
  getRedirectFromOutput,
303830
304191
  forEachResolvedProjectReference: forEachResolvedProjectReference2
303831
304192
  });
303832
- const readFile9 = host.readFile.bind(host);
304193
+ const readFile8 = host.readFile.bind(host);
303833
304194
  (_e = tracing) == null || _e.push(tracing.Phase.Program, "shouldProgramCreateNewSourceFiles", { hasOldProgram: !!oldProgram });
303834
304195
  const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options3);
303835
304196
  (_f = tracing) == null || _f.pop();
@@ -304005,7 +304366,7 @@ ${lanes.join(`
304005
304366
  shouldTransformImportCall,
304006
304367
  emitBuildInfo,
304007
304368
  fileExists,
304008
- readFile: readFile9,
304369
+ readFile: readFile8,
304009
304370
  directoryExists,
304010
304371
  getSymlinkCache,
304011
304372
  realpath: (_o = host.realpath) == null ? undefined : _o.bind(host),
@@ -330306,11 +330667,11 @@ ${newComment.split(`
330306
330667
  }
330307
330668
  function convertNamedExport(sourceFile, assignment, changes, exports2) {
330308
330669
  const { text } = assignment.left.name;
330309
- const rename = exports2.get(text);
330310
- if (rename !== undefined) {
330670
+ const rename2 = exports2.get(text);
330671
+ if (rename2 !== undefined) {
330311
330672
  const newNodes = [
330312
- makeConst(undefined, rename, assignment.right),
330313
- makeExportDeclaration([factory.createExportSpecifier(false, rename, text)])
330673
+ makeConst(undefined, rename2, assignment.right),
330674
+ makeExportDeclaration([factory.createExportSpecifier(false, rename2, text)])
330314
330675
  ];
330315
330676
  changes.replaceNodeWithNodes(sourceFile, assignment.parent, newNodes);
330316
330677
  } else {
@@ -346930,11 +347291,11 @@ ${content}
346930
347291
  }
346931
347292
  return createOutliningSpanFromBounds(node.getStart(sourceFile), node.getEnd(), "code");
346932
347293
  }
346933
- function spanForObjectOrArrayLiteral(node, open2 = 19) {
346934
- return spanForNode(node, false, !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent), open2);
347294
+ function spanForObjectOrArrayLiteral(node, open3 = 19) {
347295
+ return spanForNode(node, false, !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent), open3);
346935
347296
  }
346936
- function spanForNode(hintSpanNode, autoCollapse = false, useFullStart = true, open2 = 19, close = open2 === 19 ? 20 : 24) {
346937
- const openToken = findChildOfKind(n, open2, sourceFile);
347297
+ function spanForNode(hintSpanNode, autoCollapse = false, useFullStart = true, open3 = 19, close = open3 === 19 ? 20 : 24) {
347298
+ const openToken = findChildOfKind(n, open3, sourceFile);
346938
347299
  const closeToken = findChildOfKind(n, close, sourceFile);
346939
347300
  return openToken && closeToken && spanBetweenTokens(openToken, closeToken, hintSpanNode, sourceFile, autoCollapse, useFullStart);
346940
347301
  }
@@ -349202,9 +349563,9 @@ ${options3.prefix}` : `
349202
349563
  return end;
349203
349564
  }
349204
349565
  function getClassOrObjectBraceEnds(cls, sourceFile) {
349205
- const open2 = findChildOfKind(cls, 19, sourceFile);
349566
+ const open3 = findChildOfKind(cls, 19, sourceFile);
349206
349567
  const close = findChildOfKind(cls, 20, sourceFile);
349207
- return [open2 == null ? undefined : open2.end, close == null ? undefined : close.end];
349568
+ return [open3 == null ? undefined : open3.end, close == null ? undefined : close.end];
349208
349569
  }
349209
349570
  function getMembersOrProperties(node) {
349210
349571
  return isObjectLiteralExpression(node) ? node.properties : node.members;
@@ -354443,7 +354804,7 @@ ${options3.prefix}` : `
354443
354804
  walkUpParenthesizedTypesAndGetParentAndChild: () => walkUpParenthesizedTypesAndGetParentAndChild,
354444
354805
  whitespaceOrMapCommentRegExp: () => whitespaceOrMapCommentRegExp,
354445
354806
  writeCommentRange: () => writeCommentRange,
354446
- writeFile: () => writeFile12,
354807
+ writeFile: () => writeFile11,
354447
354808
  writeFileEnsuringDirectories: () => writeFileEnsuringDirectories,
354448
354809
  zipWith: () => zipWith
354449
354810
  });
@@ -367648,7 +368009,8 @@ function buildLoopStatus(runtime, params) {
367648
368009
  if (!listener) {
367649
368010
  return {
367650
368011
  status: "WAITING_ON_INPUT",
367651
- active_run_ids: []
368012
+ active_run_ids: [],
368013
+ executing_tool_call_ids: []
367652
368014
  };
367653
368015
  }
367654
368016
  const scope = getScopeForRuntime(runtime, params);
@@ -367660,7 +368022,8 @@ function buildLoopStatus(runtime, params) {
367660
368022
  const status = interruptedCacheActive ? !conversationRuntime?.isProcessing ? "WAITING_ON_INPUT" : conversationRuntime?.loopStatus === "WAITING_ON_APPROVAL" ? "WAITING_ON_INPUT" : conversationRuntime?.loopStatus ?? "WAITING_ON_INPUT" : recovered && recovered.pendingRequestIds.size > 0 && conversationRuntime?.loopStatus === "WAITING_ON_INPUT" ? "WAITING_ON_APPROVAL" : conversationRuntime?.loopStatus ?? "WAITING_ON_INPUT";
367661
368023
  return {
367662
368024
  status,
367663
- active_run_ids: interruptedCacheActive && !conversationRuntime?.isProcessing ? [] : conversationRuntime?.activeRunId ? [conversationRuntime.activeRunId] : []
368025
+ active_run_ids: interruptedCacheActive && !conversationRuntime?.isProcessing ? [] : conversationRuntime?.activeRunId ? [conversationRuntime.activeRunId] : [],
368026
+ executing_tool_call_ids: status === "EXECUTING_CLIENT_SIDE_TOOL" && conversationRuntime ? [...conversationRuntime.turnLifecycle.executingToolCallIds] : []
367664
368027
  };
367665
368028
  }
367666
368029
  function buildQueueSnapshot(runtime, params) {
@@ -368286,7 +368649,7 @@ import {
368286
368649
  lstat,
368287
368650
  mkdir as mkdir8,
368288
368651
  readdir as readdir5,
368289
- readFile as readFile9,
368652
+ readFile as readFile8,
368290
368653
  realpath as realpath2,
368291
368654
  rmdir,
368292
368655
  stat as stat6,
@@ -368523,7 +368886,7 @@ async function readProvisionConfig(primaryRoot) {
368523
368886
  include: []
368524
368887
  };
368525
368888
  try {
368526
- const raw = await readFile9(path19.join(primaryRoot, ".letta", "settings.json"), "utf8");
368889
+ const raw = await readFile8(path19.join(primaryRoot, ".letta", "settings.json"), "utf8");
368527
368890
  const parsed = JSON.parse(raw);
368528
368891
  const worktree = parsed.worktree;
368529
368892
  if (!worktree) {
@@ -368615,7 +368978,7 @@ async function copyLocalSettingsFile(primaryRoot, worktreePath) {
368615
368978
  }
368616
368979
  async function readWorktreeIncludeEntries(primaryRoot) {
368617
368980
  try {
368618
- const raw = await readFile9(path19.join(primaryRoot, ".worktreeinclude"), "utf8");
368981
+ const raw = await readFile8(path19.join(primaryRoot, ".worktreeinclude"), "utf8");
368619
368982
  return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
368620
368983
  } catch {
368621
368984
  return [];
@@ -371120,15 +371483,15 @@ var require_parse3 = __commonJS((exports, module3) => {
371120
371483
  }
371121
371484
  if (value === "{" && opts.nobrace !== true) {
371122
371485
  increment("braces");
371123
- const open2 = {
371486
+ const open3 = {
371124
371487
  type: "brace",
371125
371488
  value,
371126
371489
  output: "(",
371127
371490
  outputIndex: state.output.length,
371128
371491
  tokensIndex: state.tokens.length
371129
371492
  };
371130
- braces.push(open2);
371131
- push(open2);
371493
+ braces.push(open3);
371494
+ push(open3);
371132
371495
  continue;
371133
371496
  }
371134
371497
  if (value === "}") {
@@ -371779,12 +372142,12 @@ var init_list_directory_gemini = __esm(() => {
371779
372142
  import { existsSync as existsSync27 } from "node:fs";
371780
372143
  import {
371781
372144
  mkdir as mkdir9,
371782
- readFile as readFile10,
371783
- rename,
371784
- rm as rm3,
372145
+ readFile as readFile9,
372146
+ rename as rename2,
372147
+ rm as rm4,
371785
372148
  stat as stat8,
371786
372149
  unlink as unlink2,
371787
- writeFile as writeFile12
372150
+ writeFile as writeFile11
371788
372151
  } from "node:fs/promises";
371789
372152
  import { dirname as dirname14, isAbsolute as isAbsolute15, relative as relative3, resolve as resolve18 } from "node:path";
371790
372153
  async function getMemoryWriteSyncMode() {
@@ -371865,7 +372228,7 @@ async function applyMemoryCommand(memoryDir, args) {
371865
372228
  throw new Error(`memory create: block already exists at ${pathArg}`);
371866
372229
  }
371867
372230
  await mkdir9(dirname14(filePath), { recursive: true });
371868
- await writeFile12(filePath, rendered, "utf8");
372231
+ await writeFile11(filePath, rendered, "utf8");
371869
372232
  return [relPath];
371870
372233
  }
371871
372234
  if (command === "str_replace") {
@@ -371882,7 +372245,7 @@ async function applyMemoryCommand(memoryDir, args) {
371882
372245
  }
371883
372246
  const nextBody = `${file3.body.slice(0, idx)}${newString}${file3.body.slice(idx + oldString.length)}`;
371884
372247
  const rendered = renderMemoryFile(file3.frontmatter, nextBody);
371885
- await writeFile12(filePath, rendered, "utf8");
372248
+ await writeFile11(filePath, rendered, "utf8");
371886
372249
  return [relPath];
371887
372250
  }
371888
372251
  if (command === "insert") {
@@ -371905,7 +372268,7 @@ async function applyMemoryCommand(memoryDir, args) {
371905
372268
  const nextBody = existingLines.join(`
371906
372269
  `);
371907
372270
  const rendered = renderMemoryFile(file3.frontmatter, nextBody);
371908
- await writeFile12(filePath, rendered, "utf8");
372271
+ await writeFile11(filePath, rendered, "utf8");
371909
372272
  return [relPath];
371910
372273
  }
371911
372274
  if (command === "delete") {
@@ -371914,7 +372277,7 @@ async function applyMemoryCommand(memoryDir, args) {
371914
372277
  const targetPath = resolveMemoryPath(memoryDir, label);
371915
372278
  if (existsSync27(targetPath) && (await stat8(targetPath)).isDirectory()) {
371916
372279
  const relPath2 = toRepoRelative(memoryDir, targetPath);
371917
- await rm3(targetPath, { recursive: true, force: false });
372280
+ await rm4(targetPath, { recursive: true, force: false });
371918
372281
  return [relPath2];
371919
372282
  }
371920
372283
  const filePath = resolveMemoryFilePath(memoryDir, label);
@@ -371937,7 +372300,7 @@ async function applyMemoryCommand(memoryDir, args) {
371937
372300
  }
371938
372301
  await loadEditableMemoryFile(oldFilePath, oldPathArg);
371939
372302
  await mkdir9(dirname14(newFilePath), { recursive: true });
371940
- await rename(oldFilePath, newFilePath);
372303
+ await rename2(oldFilePath, newFilePath);
371941
372304
  return [oldRelPath, newRelPath];
371942
372305
  }
371943
372306
  if (command === "update_description") {
@@ -371951,7 +372314,7 @@ async function applyMemoryCommand(memoryDir, args) {
371951
372314
  ...file3.frontmatter,
371952
372315
  description: newDescription
371953
372316
  }, file3.body);
371954
- await writeFile12(filePath, rendered, "utf8");
372317
+ await writeFile11(filePath, rendered, "utf8");
371955
372318
  return [relPath];
371956
372319
  }
371957
372320
  throw new Error(`Unsupported memory command: ${command}`);
@@ -372042,7 +372405,7 @@ function toRepoRelative(memoryDir, absolutePath) {
372042
372405
  return rel.replace(/\\/g, "/");
372043
372406
  }
372044
372407
  async function loadEditableMemoryFile(filePath, sourcePath) {
372045
- const content = await readFile10(filePath, "utf8").catch((error54) => {
372408
+ const content = await readFile9(filePath, "utf8").catch((error54) => {
372046
372409
  const message = error54 instanceof Error ? error54.message : String(error54);
372047
372410
  throw new Error(`memory: failed to read ${sourcePath}: ${message}`);
372048
372411
  });
@@ -372138,7 +372501,7 @@ var init_memory4 = __esm(() => {
372138
372501
 
372139
372502
  // src/tools/impl/memory-apply-patch.ts
372140
372503
  import { existsSync as existsSync28 } from "node:fs";
372141
- import { access, mkdir as mkdir10, rm as rm4, stat as stat9, unlink as unlink3 } from "node:fs/promises";
372504
+ import { access, mkdir as mkdir10, rm as rm5, stat as stat9, unlink as unlink3 } from "node:fs/promises";
372142
372505
  import { dirname as dirname15, isAbsolute as isAbsolute16, relative as relative4, resolve as resolve19 } from "node:path";
372143
372506
  async function getMemoryWriteSyncMode2() {
372144
372507
  const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
@@ -372291,7 +372654,7 @@ async function applyMemoryPatch(memoryDir, input) {
372291
372654
  continue;
372292
372655
  const stats = await stat9(absPath);
372293
372656
  if (stats.isDirectory()) {
372294
- await rm4(absPath, { recursive: true, force: false });
372657
+ await rm5(absPath, { recursive: true, force: false });
372295
372658
  } else {
372296
372659
  await unlink3(absPath);
372297
372660
  }
@@ -373302,6 +373665,7 @@ function normalizeMessageChannelInput(args) {
373302
373665
  replyToMessageId: firstNonEmptyString3(args.replyTo),
373303
373666
  threadId: firstNonEmptyString3(args.threadId) ?? null,
373304
373667
  messageId: firstNonEmptyString3(args.messageId),
373668
+ attachmentId: firstNonEmptyString3(args.attachmentId),
373305
373669
  emoji: firstNonEmptyString3(args.emoji),
373306
373670
  remove: firstDefinedBoolean(args.remove),
373307
373671
  mediaPath: firstNonEmptyString3(args.media),
@@ -373318,6 +373682,7 @@ function buildMessageChannelRequest(input, chatId, threadId) {
373318
373682
  replyToMessageId: input.replyToMessageId,
373319
373683
  threadId: threadId ?? input.threadId ?? null,
373320
373684
  messageId: input.messageId,
373685
+ attachmentId: input.attachmentId,
373321
373686
  emoji: input.emoji,
373322
373687
  remove: input.remove,
373323
373688
  mediaPath: input.mediaPath,
@@ -373423,6 +373788,9 @@ async function message_channel(args) {
373423
373788
  if (typeof input === "string") {
373424
373789
  return input;
373425
373790
  }
373791
+ if (input.channel === "slack" && input.action === "download-file" && input.target) {
373792
+ return "Error: Slack download-file requires chat_id from a routed channel context; target is not supported.";
373793
+ }
373426
373794
  try {
373427
373795
  let executionContext;
373428
373796
  if (input.chatId) {
@@ -373449,8 +373817,9 @@ async function message_channel(args) {
373449
373817
  accountId: resolvedAccountId,
373450
373818
  channelTurnSources: args.channelTurnSources
373451
373819
  });
373820
+ const requestThreadId = input.action === "download-file" ? input.threadId : inferredThreadId ?? route2.threadId ?? input.threadId;
373452
373821
  executionContext = {
373453
- request: buildMessageChannelRequest(input, input.chatId, inferredThreadId ?? route2.threadId ?? input.threadId),
373822
+ request: buildMessageChannelRequest(input, input.chatId, requestThreadId),
373454
373823
  route: route2,
373455
373824
  adapter: adapter2,
373456
373825
  plugin: plugin2
@@ -375765,10 +376134,10 @@ globstar while`, file3, fr, pattern4, pr, swallowee);
375765
376134
  }
375766
376135
  return filtered.join("/");
375767
376136
  }).join("|");
375768
- const [open2, close] = set3.length > 1 ? ["(?:", ")"] : ["", ""];
375769
- re = "^" + open2 + re + close + "$";
376137
+ const [open3, close] = set3.length > 1 ? ["(?:", ")"] : ["", ""];
376138
+ re = "^" + open3 + re + close + "$";
375770
376139
  if (this.partial) {
375771
- re = "^(?:\\/|" + open2 + re.slice(1, -1) + close + ")$";
376140
+ re = "^(?:\\/|" + open3 + re.slice(1, -1) + close + ")$";
375772
376141
  }
375773
376142
  if (this.negate)
375774
376143
  re = "^(?!" + re + ").+$";
@@ -381759,7 +382128,7 @@ __export(exports_skill, {
381759
382128
  getResolvedSkillsDir: () => getResolvedSkillsDir
381760
382129
  });
381761
382130
  import { existsSync as existsSync29, readdirSync as readdirSync10 } from "node:fs";
381762
- import { readFile as readFile11 } from "node:fs/promises";
382131
+ import { readFile as readFile10 } from "node:fs/promises";
381763
382132
  import { dirname as dirname16, join as join34 } from "node:path";
381764
382133
  function getMemorySkillsDirs2(agentId) {
381765
382134
  const dirs = new Set;
@@ -381791,41 +382160,41 @@ async function readSkillContent(skillId, skillsDir, agentId) {
381791
382160
  for (const projectSkillsDir of projectSkillsDirs) {
381792
382161
  const projectSkillPath = join34(projectSkillsDir, skillId, "SKILL.md");
381793
382162
  try {
381794
- const content = await readFile11(projectSkillPath, "utf-8");
382163
+ const content = await readFile10(projectSkillPath, "utf-8");
381795
382164
  return { content, path: projectSkillPath };
381796
382165
  } catch {}
381797
382166
  }
381798
382167
  if (agentId) {
381799
382168
  const agentSkillPath = join34(getAgentSkillsDir(agentId), skillId, "SKILL.md");
381800
382169
  try {
381801
- const content = await readFile11(agentSkillPath, "utf-8");
382170
+ const content = await readFile10(agentSkillPath, "utf-8");
381802
382171
  return { content, path: agentSkillPath };
381803
382172
  } catch {}
381804
382173
  }
381805
382174
  for (const memorySkillsDir of getMemorySkillsDirs2(agentId)) {
381806
382175
  const memorySkillPath = join34(memorySkillsDir, skillId, "SKILL.md");
381807
382176
  try {
381808
- const content = await readFile11(memorySkillPath, "utf-8");
382177
+ const content = await readFile10(memorySkillPath, "utf-8");
381809
382178
  return { content, path: memorySkillPath };
381810
382179
  } catch {}
381811
382180
  }
381812
382181
  const globalSkillPath = join34(GLOBAL_SKILLS_DIR, skillId, "SKILL.md");
381813
382182
  try {
381814
- const content = await readFile11(globalSkillPath, "utf-8");
382183
+ const content = await readFile10(globalSkillPath, "utf-8");
381815
382184
  return { content, path: globalSkillPath };
381816
382185
  } catch {}
381817
382186
  const bundledSkills = await getBundledSkills();
381818
382187
  const bundledSkill = bundledSkills.find((s2) => s2.id === skillId);
381819
382188
  if (bundledSkill?.path && isSkillAvailableForAgent(bundledSkill, agentId)) {
381820
382189
  try {
381821
- const content = await readFile11(bundledSkill.path, "utf-8");
382190
+ const content = await readFile10(bundledSkill.path, "utf-8");
381822
382191
  return { content, path: bundledSkill.path };
381823
382192
  } catch {}
381824
382193
  }
381825
382194
  try {
381826
382195
  const bundledSkillsDir = join34(process.cwd(), "skills", "skills");
381827
382196
  const bundledSkillPath = join34(bundledSkillsDir, skillId, "SKILL.md");
381828
- const content = await readFile11(bundledSkillPath, "utf-8");
382197
+ const content = await readFile10(bundledSkillPath, "utf-8");
381829
382198
  return { content, path: bundledSkillPath };
381830
382199
  } catch {
381831
382200
  throw new Error(`Skill "${skillId}" not found. Check that the skill name is correct and that it appears in the available skills list.`);
@@ -387720,8 +388089,8 @@ globstar while`, file3, fr, pattern4, pr, swallowee);
387720
388089
  });
387721
388090
  return pp.filter((p) => p !== GLOBSTAR2).join("/");
387722
388091
  }).join("|");
387723
- const [open2, close] = set3.length > 1 ? ["(?:", ")"] : ["", ""];
387724
- re = "^" + open2 + re + close + "$";
388092
+ const [open3, close] = set3.length > 1 ? ["(?:", ")"] : ["", ""];
388093
+ re = "^" + open3 + re + close + "$";
387725
388094
  if (this.negate)
387726
388095
  re = "^(?!" + re + ").+$";
387727
388096
  try {
@@ -395009,7 +395378,7 @@ class LocalStore {
395009
395378
  }
395010
395379
  this.ensureAgent(agentId);
395011
395380
  const conversationId = this.nextConversationId();
395012
- const conversation = createLocalConversationRecord(conversationId, agentId, this.conversationSeq, body);
395381
+ const conversation = this.withConversationModelDefaults(createLocalConversationRecord(conversationId, agentId, this.conversationSeq, body));
395013
395382
  const key = this.conversationKey(conversation.id, agentId);
395014
395383
  this.conversations.set(key, conversation);
395015
395384
  this.localMessagesByConversationKey.set(key, []);
@@ -395028,32 +395397,31 @@ class LocalStore {
395028
395397
  }
395029
395398
  const created = this.ensureConversation(conversationId);
395030
395399
  const updated2 = updateLocalConversationRecord(created, body, currentIsoTimestamp());
395031
- const projected = this.applyConversationModelDefaults(updated2, body, created);
395400
+ const projected = this.withConversationModelDefaults(updated2);
395032
395401
  this.conversations.set(this.conversationKey(conversationId, created.agent_id), projected);
395033
395402
  this.persistConversationState(conversationId, created.agent_id);
395034
395403
  return projected;
395035
395404
  }
395036
- const updated = this.applyConversationModelDefaults(updateLocalConversationRecord(current, body, currentIsoTimestamp()), body, current);
395405
+ const updated = this.withConversationModelDefaults(updateLocalConversationRecord(current, body, currentIsoTimestamp()));
395037
395406
  this.conversations.set(this.conversationKey(conversationId, current.agent_id), updated);
395038
395407
  this.persistConversationState(conversationId, current.agent_id);
395039
395408
  return updated;
395040
395409
  }
395041
- applyConversationModelDefaults(conversation, body, previousConversation) {
395042
- const requestedModel = body.model;
395410
+ withConversationModelDefaults(conversation) {
395411
+ const requestedModel = conversation.model;
395043
395412
  if (typeof requestedModel !== "string")
395044
395413
  return conversation;
395045
395414
  const normalizedRequestedModel = normalizeLocalModelHandle(requestedModel, isRecord(conversation.model_settings) ? conversation.model_settings : {});
395046
- if (previousConversation.model === normalizedRequestedModel)
395047
- return conversation;
395048
395415
  const defaults5 = this.modelSettingsDefaultsForModel(normalizedRequestedModel);
395049
395416
  if (!defaults5 || Object.keys(defaults5).length === 0)
395050
395417
  return conversation;
395051
395418
  const existingSettings = isRecord(conversation.model_settings) ? conversation.model_settings : {};
395052
395419
  return {
395053
395420
  ...conversation,
395421
+ model: normalizedRequestedModel,
395054
395422
  model_settings: {
395055
- ...existingSettings,
395056
- ...defaults5
395423
+ ...defaults5,
395424
+ ...existingSettings
395057
395425
  }
395058
395426
  };
395059
395427
  }
@@ -395949,7 +396317,7 @@ class LocalStore {
395949
396317
  const existing = this.conversations.get(key);
395950
396318
  if (existing && options3.forceRefresh !== true)
395951
396319
  return existing;
395952
- const normalizedInput = normalizeStoredLocalModelRecord(input);
396320
+ const normalizedInput = this.withConversationModelDefaults(normalizeStoredLocalModelRecord(input));
395953
396321
  const timing = transcriptTimingForConversationDir(conversationDir);
395954
396322
  const requiresFullTimestampRepair = isSyntheticLocalTimestamp(normalizedInput.created_at) || isSyntheticLocalTimestamp(normalizedInput.updated_at) || isSyntheticLocalTimestamp(normalizedInput.last_message_at);
395955
396323
  const conversation = requiresFullTimestampRepair ? normalizedInput : repairSyntheticConversationTimestamps(normalizedInput, [], timing);
@@ -399092,24 +399460,6 @@ var init_local_model_config = __esm(() => {
399092
399460
  UNSUPPORTED_LOCAL_CHATGPT_OAUTH_MODELS = new Set(["gpt-5.6-luna"]);
399093
399461
  });
399094
399462
 
399095
- // src/backend/dev/pi-output-budget.ts
399096
- function assertViablePiOutputBudget(model, context3, requestedMaxTokens) {
399097
- if (model.provider !== "llama-cpp")
399098
- return;
399099
- const requested = requestedMaxTokens ?? model.maxTokens;
399100
- if (!Number.isFinite(requested) || requested <= 0)
399101
- return;
399102
- const clamped = clampMaxTokensToContext(model, context3, requested);
399103
- const minimum3 = Math.min(requested, MIN_VIABLE_OUTPUT_TOKENS);
399104
- if (clamped >= minimum3)
399105
- return;
399106
- throw new Error(`Context window of ${model.contextWindow} tokens leaves only ${clamped} output token${clamped === 1 ? "" : "s"}; at least ${minimum3} are required. Compact the conversation or increase the context window.`);
399107
- }
399108
- var MIN_VIABLE_OUTPUT_TOKENS = 1024;
399109
- var init_pi_output_budget = __esm(() => {
399110
- init_simple_options();
399111
- });
399112
-
399113
399463
  // src/backend/local/local-context-estimate.ts
399114
399464
  function positiveUsageNumber(value) {
399115
399465
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
@@ -399458,7 +399808,7 @@ function createProviderLettaStream(events, contextTokensEstimate) {
399458
399808
  }
399459
399809
  pendingStopReason = {
399460
399810
  message_type: "stop_reason",
399461
- stop_reason: sawToolCall || part.reason === "toolUse" ? "requires_approval" : "end_turn"
399811
+ stop_reason: sawToolCall || part.reason === "toolUse" ? "requires_approval" : part.reason === "length" ? "max_tokens_exceeded" : "end_turn"
399462
399812
  };
399463
399813
  continue;
399464
399814
  }
@@ -399968,7 +400318,6 @@ class PiStreamAdapter {
399968
400318
  messageCount: context3.messages.length,
399969
400319
  contextWindow: resolved.model.contextWindow
399970
400320
  });
399971
- assertViablePiOutputBudget(resolved.model, context3, options3.maxTokens);
399972
400321
  const result = this.runStream(resolved.model, context3, options3);
399973
400322
  let streamError;
399974
400323
  let finalMessage;
@@ -400109,7 +400458,6 @@ var init_pi_stream_adapter = __esm(() => {
400109
400458
  init_context_window_overflow();
400110
400459
  init_local_provider_errors();
400111
400460
  init_pi_model_factory();
400112
- init_pi_output_budget();
400113
400461
  init_provider_turn_executor();
400114
400462
  LOCAL_PROVIDER_ADAPTIVE_IMAGE_ELISION_AFTER_RETRIES = LOCAL_PROVIDER_MAX_RETRIES - 1;
400115
400463
  PiProviderError = class PiProviderError extends Error {
@@ -423600,18 +423948,18 @@ var stdoutColor, stderrColor, GENERATOR, STYLER, IS_EMPTY, levelMapping, styles4
423600
423948
  return getModelAnsi("rgb", level, type3, ...ansi_styles_default2.hexToRgb(...arguments_));
423601
423949
  }
423602
423950
  return ansi_styles_default2[type3][model](...arguments_);
423603
- }, usedModels, proto, createStyler = (open2, close, parent) => {
423951
+ }, usedModels, proto, createStyler = (open3, close, parent) => {
423604
423952
  let openAll;
423605
423953
  let closeAll;
423606
423954
  if (parent === undefined) {
423607
- openAll = open2;
423955
+ openAll = open3;
423608
423956
  closeAll = close;
423609
423957
  } else {
423610
- openAll = parent.openAll + open2;
423958
+ openAll = parent.openAll + open3;
423611
423959
  closeAll = close + parent.closeAll;
423612
423960
  }
423613
423961
  return {
423614
- open: open2,
423962
+ open: open3,
423615
423963
  close,
423616
423964
  openAll,
423617
423965
  closeAll,
@@ -441385,7 +441733,7 @@ var init_conversation_search = __esm(() => {
441385
441733
  });
441386
441734
 
441387
441735
  // src/utils/file-lock.ts
441388
- import { open as open2, readFile as readFile14, stat as stat10, unlink as unlink4 } from "node:fs/promises";
441736
+ import { open as open3, readFile as readFile13, stat as stat10, unlink as unlink4 } from "node:fs/promises";
441389
441737
  async function withFileLock(lockPath, fn, options3) {
441390
441738
  const opts = { ...DEFAULT_OPTIONS, ...options3 };
441391
441739
  const release = await acquireFileLock(lockPath, opts);
@@ -441403,7 +441751,7 @@ async function acquireFileLock(lockPath, opts) {
441403
441751
  });
441404
441752
  while (true) {
441405
441753
  try {
441406
- const handle2 = await open2(lockPath, "wx");
441754
+ const handle2 = await open3(lockPath, "wx");
441407
441755
  try {
441408
441756
  await handle2.writeFile(payload, "utf-8");
441409
441757
  await handle2.close();
@@ -441439,7 +441787,7 @@ async function acquireFileLock(lockPath, opts) {
441439
441787
  async function tryReapStaleLock(lockPath, staleMs) {
441440
441788
  let raw2;
441441
441789
  try {
441442
- raw2 = await readFile14(lockPath, "utf-8");
441790
+ raw2 = await readFile13(lockPath, "utf-8");
441443
441791
  } catch {
441444
441792
  return true;
441445
441793
  }
@@ -441496,9 +441844,9 @@ import {
441496
441844
  appendFile,
441497
441845
  mkdir as mkdir12,
441498
441846
  readdir as readdir8,
441499
- readFile as readFile15,
441847
+ readFile as readFile14,
441500
441848
  stat as stat11,
441501
- writeFile as writeFile13
441849
+ writeFile as writeFile12
441502
441850
  } from "node:fs/promises";
441503
441851
  import { join as join46 } from "node:path";
441504
441852
  function buildReflectionSubagentPrompt(input) {
@@ -441556,7 +441904,7 @@ async function collectParentMemoryFiles(memoryDir) {
441556
441904
  continue;
441557
441905
  }
441558
441906
  try {
441559
- const content = await readFile15(entryPath, "utf-8");
441907
+ const content = await readFile14(entryPath, "utf-8");
441560
441908
  const { frontmatter } = parseFrontmatter(content);
441561
441909
  const description = typeof frontmatter.description === "string" ? frontmatter.description : undefined;
441562
441910
  files.push({
@@ -441885,11 +442233,11 @@ function lineToTranscriptEntry(line, capturedAt) {
441885
442233
  }
441886
442234
  async function ensurePaths(paths) {
441887
442235
  await mkdir12(paths.rootDir, { recursive: true });
441888
- await writeFile13(paths.transcriptPath, "", { encoding: "utf-8", flag: "a" });
442236
+ await writeFile12(paths.transcriptPath, "", { encoding: "utf-8", flag: "a" });
441889
442237
  }
441890
442238
  async function readTranscriptLines(paths) {
441891
442239
  try {
441892
- const raw2 = await readFile15(paths.transcriptPath, "utf-8");
442240
+ const raw2 = await readFile14(paths.transcriptPath, "utf-8");
441893
442241
  return raw2.split(`
441894
442242
  `).map((line) => line.trim()).filter((line) => line.length > 0);
441895
442243
  } catch {
@@ -441962,7 +442310,7 @@ function buildUnreflectedStateFromTranscript(lines) {
441962
442310
  async function readState(paths) {
441963
442311
  let raw2 = null;
441964
442312
  try {
441965
- raw2 = await readFile15(paths.statePath, "utf-8");
442313
+ raw2 = await readFile14(paths.statePath, "utf-8");
441966
442314
  } catch {
441967
442315
  raw2 = null;
441968
442316
  }
@@ -441987,7 +442335,7 @@ async function readState(paths) {
441987
442335
  }
441988
442336
  async function writeState(paths, state) {
441989
442337
  state.steps_since_last_successful_reflection = Math.max(0, state.total_completed_steps - state.reflected_completed_steps);
441990
- await writeFile13(paths.statePath, `${JSON.stringify(state, null, 2)}
442338
+ await writeFile12(paths.statePath, `${JSON.stringify(state, null, 2)}
441991
442339
  `, "utf-8");
441992
442340
  }
441993
442341
  function buildPayloadPath(rootDir, kind) {
@@ -442365,7 +442713,7 @@ async function buildReflectionAutoPayload(options3) {
442365
442713
  candidates: sortedCandidates
442366
442714
  };
442367
442715
  const candidatesPath = buildPayloadPath(payloadRoot, "candidates");
442368
- await writeFile13(candidatesPath, `${JSON.stringify(candidateSet, null, 2)}
442716
+ await writeFile12(candidatesPath, `${JSON.stringify(candidateSet, null, 2)}
442369
442717
  `, "utf-8");
442370
442718
  return { candidatesPath, candidates: candidateSet };
442371
442719
  }
@@ -442373,7 +442721,7 @@ function isReflectionAutoPriority(value) {
442373
442721
  return value === "high" || value === "medium" || value === "low";
442374
442722
  }
442375
442723
  async function readReflectionAutoSelection(options3) {
442376
- const raw2 = options3.selectionReport ?? (options3.selectionOutputPath ? await readFile15(options3.selectionOutputPath, "utf-8") : "");
442724
+ const raw2 = options3.selectionReport ?? (options3.selectionOutputPath ? await readFile14(options3.selectionOutputPath, "utf-8") : "");
442377
442725
  const parsed = parseReflectionAutoSelectionJson(raw2);
442378
442726
  if (!parsed || typeof parsed !== "object") {
442379
442727
  throw new Error("Reflection selector did not return valid JSON.");
@@ -442493,7 +442841,7 @@ async function buildAutoReflectionPayload(agentId, conversationId, systemPrompt)
442493
442841
  return null;
442494
442842
  }
442495
442843
  const payloadPath = buildPayloadPath(paths.rootDir, "auto");
442496
- await writeFile13(payloadPath, transcript, "utf-8");
442844
+ await writeFile12(payloadPath, transcript, "utf-8");
442497
442845
  state.last_reflection_started_at = new Date().toISOString();
442498
442846
  await writeState(paths, state);
442499
442847
  return {
@@ -442582,7 +442930,7 @@ async function buildMultiReflectionPayload(options3) {
442582
442930
  return null;
442583
442931
  }
442584
442932
  const payloadPath2 = buildPayloadPath(payloadRoot, "slice");
442585
- await writeFile13(payloadPath2, transcript, "utf-8");
442933
+ await writeFile12(payloadPath2, transcript, "utf-8");
442586
442934
  state.last_reflection_started_at = new Date().toISOString();
442587
442935
  await writeState(paths, state);
442588
442936
  return {
@@ -442624,7 +442972,7 @@ async function buildMultiReflectionPayload(options3) {
442624
442972
  transcripts
442625
442973
  };
442626
442974
  const payloadPath = buildPayloadPath(payloadRoot, "multi");
442627
- await writeFile13(payloadPath, `${JSON.stringify(manifest, null, 2)}
442975
+ await writeFile12(payloadPath, `${JSON.stringify(manifest, null, 2)}
442628
442976
  `, "utf-8");
442629
442977
  return {
442630
442978
  payloadPath,
@@ -443433,19 +443781,18 @@ function getListenerBlockedReason(lifecycle, pendingApprovalsLen) {
443433
443781
  return null;
443434
443782
  }
443435
443783
 
443436
- // src/websocket/listener/queue.ts
443437
- var exports_queue = {};
443438
- __export(exports_queue, {
443439
- shouldQueueInboundMessage: () => shouldQueueInboundMessage,
443440
- shouldProcessInboundMessageDirectly: () => shouldProcessInboundMessageDirectly,
443441
- scheduleQueuePump: () => scheduleQueuePump,
443442
- pickBatchActingUserId: () => pickBatchActingUserId,
443443
- normalizeMessageContentImages: () => normalizeMessageContentImages2,
443444
- normalizeInboundMessages: () => normalizeInboundMessages,
443445
- getQueueItemsScope: () => getQueueItemsScope,
443446
- getQueueItemScope: () => getQueueItemScope,
443447
- consumeQueuedTurn: () => consumeQueuedTurn
443784
+ // src/websocket/listener/image-policy.ts
443785
+ function getInboundImageFailureMode(incoming) {
443786
+ return (incoming?.channelTurnSources?.length ?? 0) > 0 ? "drop" : "strict";
443787
+ }
443788
+ function getInboundImageFailureModes(incoming) {
443789
+ return getInboundImageFailureMode(incoming) === "drop" ? buildImageFailureModesByMessageOtid(incoming.messages, "drop") : undefined;
443790
+ }
443791
+ var init_image_policy = __esm(async () => {
443792
+ await init_message_image_normalization();
443448
443793
  });
443794
+
443795
+ // src/websocket/listener/queue.ts
443449
443796
  function getQueueItemScope(item) {
443450
443797
  if (!item) {
443451
443798
  return {};
@@ -443549,27 +443896,6 @@ async function buildChannelTurnProgressBuilder(agentId) {
443549
443896
  return createChannelTurnProgressBuilder();
443550
443897
  }
443551
443898
  }
443552
- async function normalizeMessageContentImages2(content, resize = resizeImageIfNeeded3, failureMode = "strict") {
443553
- return await normalizeMessageContentImages(content, resize, failureMode);
443554
- }
443555
- async function normalizeInboundMessages(messages, resize = resizeImageIfNeeded3, options3 = {}) {
443556
- let didChange = false;
443557
- const normalizedMessages = await Promise.all(messages.map(async (message) => {
443558
- if (!("content" in message)) {
443559
- return message;
443560
- }
443561
- const normalizedContent = await normalizeMessageContentImages2(message.content, resize, options3.imageFailureMode ?? "strict");
443562
- if (normalizedContent !== message.content) {
443563
- didChange = true;
443564
- return {
443565
- ...message,
443566
- content: normalizedContent
443567
- };
443568
- }
443569
- return message;
443570
- }));
443571
- return didChange ? normalizedMessages : messages;
443572
- }
443573
443899
  function getPrimaryQueueMessageItem(items3) {
443574
443900
  for (const item of items3) {
443575
443901
  if (item.kind === "message") {
@@ -443670,10 +443996,18 @@ function consumeQueuedTurn(runtime) {
443670
443996
  let hasTaskNotification = false;
443671
443997
  let hasCronPrompt = false;
443672
443998
  let hasModContinue = false;
443999
+ let batchImageFailureMode = null;
443673
444000
  for (const item of queuedItems) {
443674
444001
  if (!isCoalescable(item.kind) || !hasSameQueueScope(firstQueuedItem, item)) {
443675
444002
  break;
443676
444003
  }
444004
+ if (item.kind === "message") {
444005
+ const itemImageFailureMode = getInboundImageFailureMode(runtime.queuedMessagesByItemId.get(item.id));
444006
+ if (batchImageFailureMode !== null && itemImageFailureMode !== batchImageFailureMode) {
444007
+ break;
444008
+ }
444009
+ batchImageFailureMode = itemImageFailureMode;
444010
+ }
443677
444011
  queueLen += 1;
443678
444012
  if (item.kind === "message") {
443679
444013
  hasMessage = true;
@@ -443806,8 +444140,7 @@ var init_queue = __esm(async () => {
443806
444140
  init_runtime6();
443807
444141
  await __promiseAll([
443808
444142
  init_progress_builder(),
443809
- init_image_resize(),
443810
- init_message_image_normalization(),
444143
+ init_image_policy(),
443811
444144
  init_protocol_outbound()
443812
444145
  ]);
443813
444146
  });
@@ -446200,7 +446533,7 @@ __export(exports_custom, {
446200
446533
  COMMANDS_DIR: () => COMMANDS_DIR
446201
446534
  });
446202
446535
  import { existsSync as existsSync43 } from "node:fs";
446203
- import { readdir as readdir9, readFile as readFile16 } from "node:fs/promises";
446536
+ import { readdir as readdir9, readFile as readFile15 } from "node:fs/promises";
446204
446537
  import { basename as basename20, dirname as dirname24, join as join48 } from "node:path";
446205
446538
  async function getCustomCommands() {
446206
446539
  if (cachedCommands !== null) {
@@ -446259,7 +446592,7 @@ async function findCommandFiles(currentPath, rootPath, commands, source2) {
446259
446592
  } catch (_error) {}
446260
446593
  }
446261
446594
  async function parseCommandFile(filePath, rootPath, source2) {
446262
- const content = await readFile16(filePath, "utf-8");
446595
+ const content = await readFile15(filePath, "utf-8");
446263
446596
  const { frontmatter, body: body3 } = parseFrontmatter(content);
446264
446597
  const id2 = basename20(filePath, ".md");
446265
446598
  const relativePath = dirname24(filePath).slice(rootPath.length);
@@ -446418,7 +446751,7 @@ var init_init_command = __esm(() => {
446418
446751
  });
446419
446752
 
446420
446753
  // src/cli/helpers/skill-name-frontmatter-repair.ts
446421
- import { readdir as readdir10, readFile as readFile17, stat as stat12, writeFile as writeFile14 } from "node:fs/promises";
446754
+ import { readdir as readdir10, readFile as readFile16, stat as stat12, writeFile as writeFile13 } from "node:fs/promises";
446422
446755
  import { basename as basename21, dirname as dirname25, join as join49, relative as relative8 } from "node:path";
446423
446756
  async function pathExists(path32) {
446424
446757
  try {
@@ -446525,7 +446858,7 @@ async function repairMissingSkillNameFrontmatter(memoryDir) {
446525
446858
  const displayPath = relative8(memoryDir, skillFile).replace(/\\/g, "/");
446526
446859
  result.scanned++;
446527
446860
  try {
446528
- const content = await readFile17(skillFile, "utf8");
446861
+ const content = await readFile16(skillFile, "utf8");
446529
446862
  const repair3 = repairSkillNameFrontmatterContent(content, basename21(dirname25(skillFile)));
446530
446863
  if (repair3.reason) {
446531
446864
  result.skipped.push({ path: displayPath, reason: repair3.reason });
@@ -446534,7 +446867,7 @@ async function repairMissingSkillNameFrontmatter(memoryDir) {
446534
446867
  if (!repair3.changed) {
446535
446868
  continue;
446536
446869
  }
446537
- await writeFile14(skillFile, repair3.content, "utf8");
446870
+ await writeFile13(skillFile, repair3.content, "utf8");
446538
446871
  result.repaired.push(displayPath);
446539
446872
  } catch (error54) {
446540
446873
  result.skipped.push({
@@ -447623,7 +447956,7 @@ function isCreateAgentCommand(value) {
447623
447956
  if (!value || typeof value !== "object")
447624
447957
  return false;
447625
447958
  const c = value;
447626
- return c.type === "create_agent" && typeof c.request_id === "string" && (c.personality === "memo" || c.personality === "blank" || c.personality === "tutorial" || c.personality === "linus" || c.personality === "kawaii") && (c.model === undefined || typeof c.model === "string") && (c.pin_global === undefined || typeof c.pin_global === "boolean");
447959
+ return c.type === "create_agent" && typeof c.request_id === "string" && (c.personality === "memo" || c.personality === "blank" || c.personality === "tutorial" || c.personality === "linus" || c.personality === "kawaii") && (c.model === undefined || typeof c.model === "string") && (c.tags === undefined || isStringArray6(c.tags)) && (c.pin_global === undefined || typeof c.pin_global === "boolean");
447627
447960
  }
447628
447961
  function isAgentListCommand(value) {
447629
447962
  if (!value || typeof value !== "object")
@@ -451105,6 +451438,19 @@ function emitToolExecutionFinishedEvents(socket, runtime, params) {
451105
451438
  });
451106
451439
  }
451107
451440
  }
451441
+ function emitToolExecutionAbortedEvents(socket, runtime, params) {
451442
+ for (const toolCallId of params.toolCallIds) {
451443
+ const delta2 = {
451444
+ ...createLifecycleMessageBase("client_tool_end", params.runId),
451445
+ tool_call_id: toolCallId,
451446
+ status: "error"
451447
+ };
451448
+ emitCanonicalMessageDelta(socket, runtime, delta2, {
451449
+ agent_id: params.agentId,
451450
+ conversation_id: params.conversationId
451451
+ });
451452
+ }
451453
+ }
451108
451454
  function createToolExecutionOutputEmitter(socket, runtime, params) {
451109
451455
  const outputByToolCallId = new Map;
451110
451456
  const emitToolOutput = (toolCallId, outputState) => {
@@ -451695,6 +452041,17 @@ var init_approval_suggestions = __esm(async () => {
451695
452041
  ]);
451696
452042
  });
451697
452043
 
452044
+ // src/websocket/listener/continuation-input.ts
452045
+ function appendQueuedTurnToInput(input, queuedTurn) {
452046
+ return {
452047
+ input: [...input, ...queuedTurn.messages],
452048
+ imageFailureModesByMessageOtid: getInboundImageFailureModes(queuedTurn)
452049
+ };
452050
+ }
452051
+ var init_continuation_input = __esm(async () => {
452052
+ await init_image_policy();
452053
+ });
452054
+
451698
452055
  // src/websocket/listener/turn-terminal.ts
451699
452056
  function finishListenerTurn(runtime, lease, options3) {
451700
452057
  const transition = runtime.turnLifecycle.finish(lease, options3.stopReason);
@@ -452119,25 +452476,25 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
452119
452476
  conversationId: recovered.conversationId,
452120
452477
  shouldEmit: () => runtime.turnLifecycle.isCurrent(recoveryLease)
452121
452478
  });
452122
- await ensureSecretsHydrated(runtime.listener, recovered.agentId);
452123
- if (!runtime.turnLifecycle.isCurrent(recoveryLease)) {
452124
- return true;
452125
- }
452126
- const preparedToolContext = await prepareToolExecutionContext({
452127
- agentId: recovered.agentId,
452128
- conversationId: recovered.conversationId,
452129
- workingDirectory,
452130
- permissionModeState: getOrCreateConversationPermissionModeStateRef(runtime.listener, recovered.agentId, recovered.conversationId),
452131
- modEvents: ensureListenerModAdapter(runtime.listener).events
452132
- });
452133
- if (!runtime.turnLifecycle.isCurrent(recoveryLease)) {
452134
- return true;
452135
- }
452136
- runtime.currentToolset = preparedToolContext.toolset;
452137
- runtime.currentToolsetPreference = preparedToolContext.toolsetPreference;
452138
- runtime.currentLoadedTools = preparedToolContext.preparedToolContext.loadedToolNames;
452139
452479
  let approvalResults;
452140
452480
  try {
452481
+ await ensureSecretsHydrated(runtime.listener, recovered.agentId);
452482
+ if (!runtime.turnLifecycle.isCurrent(recoveryLease)) {
452483
+ return true;
452484
+ }
452485
+ const preparedToolContext = await prepareToolExecutionContext({
452486
+ agentId: recovered.agentId,
452487
+ conversationId: recovered.conversationId,
452488
+ workingDirectory,
452489
+ permissionModeState: getOrCreateConversationPermissionModeStateRef(runtime.listener, recovered.agentId, recovered.conversationId),
452490
+ modEvents: ensureListenerModAdapter(runtime.listener).events
452491
+ });
452492
+ if (!runtime.turnLifecycle.isCurrent(recoveryLease)) {
452493
+ return true;
452494
+ }
452495
+ runtime.currentToolset = preparedToolContext.toolset;
452496
+ runtime.currentToolsetPreference = preparedToolContext.toolsetPreference;
452497
+ runtime.currentLoadedTools = preparedToolContext.preparedToolContext.loadedToolNames;
452141
452498
  approvalResults = await executeApprovals(decisions, undefined, {
452142
452499
  abortSignal: recoveryLease.signal,
452143
452500
  onStreamingOutput: emitToolExecutionOutput,
@@ -452149,6 +452506,17 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
452149
452506
  } : undefined,
452150
452507
  channelTurnSources: executionChannelTurnSources
452151
452508
  });
452509
+ } catch (error54) {
452510
+ emitToolExecutionOutput.flush();
452511
+ if (runtime.turnLifecycle.isCurrent(recoveryLease)) {
452512
+ emitToolExecutionAbortedEvents(socket, runtime, {
452513
+ toolCallIds: approvedToolCallIds,
452514
+ runId: executionRunId,
452515
+ agentId: recovered.agentId,
452516
+ conversationId: recovered.conversationId
452517
+ });
452518
+ }
452519
+ throw error54;
452152
452520
  } finally {
452153
452521
  emitToolExecutionOutput.flush();
452154
452522
  }
@@ -452168,7 +452536,7 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
452168
452536
  return true;
452169
452537
  }
452170
452538
  emitRuntimeStateUpdates(runtime, scope);
452171
- const continuationMessages = [
452539
+ let continuationMessages = [
452172
452540
  {
452173
452541
  type: "approval",
452174
452542
  approvals: approvalResults,
@@ -452176,11 +452544,13 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
452176
452544
  }
452177
452545
  ];
452178
452546
  let continuationBatchId = `batch-recovered-${crypto.randomUUID()}`;
452547
+ let queuedChannelTurnSources;
452179
452548
  const consumedQueuedTurn = consumeQueuedTurn(runtime);
452180
452549
  if (consumedQueuedTurn) {
452181
452550
  const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
452182
452551
  continuationBatchId = dequeuedBatch.batchId;
452183
- continuationMessages.push(...queuedTurn.messages);
452552
+ continuationMessages = appendQueuedTurnToInput(continuationMessages, queuedTurn).input;
452553
+ queuedChannelTurnSources = queuedTurn.channelTurnSources;
452184
452554
  emitDequeuedUserMessage(socket, runtime, queuedTurn, dequeuedBatch);
452185
452555
  }
452186
452556
  if (!runtime.turnLifecycle.isCurrent(recoveryLease)) {
@@ -452190,7 +452560,8 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
452190
452560
  type: "message",
452191
452561
  agentId: recovered.agentId,
452192
452562
  conversationId: recovered.conversationId,
452193
- messages: continuationMessages
452563
+ messages: continuationMessages,
452564
+ ...queuedChannelTurnSources?.length ? { channelTurnSources: queuedChannelTurnSources } : {}
452194
452565
  }, socket, runtime, opts?.onStatusChange, opts?.connectionId, continuationBatchId, recoveryLease);
452195
452566
  if (runtime.turnLifecycle.isCurrent(recoveryLease)) {
452196
452567
  throw new Error("Recovered continuation returned without finalizing");
@@ -452261,6 +452632,7 @@ var init_recovery = __esm(async () => {
452261
452632
  init_stream(),
452262
452633
  init_toolset(),
452263
452634
  init_approval_suggestions(),
452635
+ init_continuation_input(),
452264
452636
  init_interrupts(),
452265
452637
  init_mod_adapter2(),
452266
452638
  init_protocol_outbound(),
@@ -452490,17 +452862,20 @@ async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
452490
452862
  return null;
452491
452863
  }
452492
452864
  try {
452493
- const continuationMessages = [
452865
+ let continuationMessages = [
452494
452866
  {
452495
452867
  type: "approval",
452496
452868
  approvals: approvalResults,
452497
452869
  otid: crypto.randomUUID()
452498
452870
  }
452499
452871
  ];
452872
+ let queuedImageFailureModes;
452500
452873
  const consumedQueuedTurn = consumeQueuedTurn(runtime);
452501
452874
  if (consumedQueuedTurn) {
452502
452875
  const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
452503
- continuationMessages.push(...queuedTurn.messages);
452876
+ const appended = appendQueuedTurnToInput(continuationMessages, queuedTurn);
452877
+ continuationMessages = appended.input;
452878
+ queuedImageFailureModes = appended.imageFailureModesByMessageOtid;
452504
452879
  emitDequeuedUserMessage(socket, runtime, queuedTurn, dequeuedBatch);
452505
452880
  }
452506
452881
  const continuationMessagesWithSkillContent = injectQueuedSkillContent(continuationMessages);
@@ -452509,7 +452884,8 @@ async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
452509
452884
  streamTokens: true,
452510
452885
  background: true,
452511
452886
  workingDirectory: recoveryWorkingDirectory,
452512
- preparedToolContext: preparedToolContext.preparedToolContext
452887
+ preparedToolContext: preparedToolContext.preparedToolContext,
452888
+ ...queuedImageFailureModes ? { imageFailureModesByMessageOtid: queuedImageFailureModes } : {}
452513
452889
  }, socket, runtime, turnLease, { allowApprovalRecovery: false });
452514
452890
  assertCurrentTurnLease();
452515
452891
  if (recoverySendResult.kind !== "stream") {
@@ -452850,6 +453226,7 @@ var init_send = __esm(async () => {
452850
453226
  init_message(),
452851
453227
  init_toolset(),
452852
453228
  init_approval(),
453229
+ init_continuation_input(),
452853
453230
  init_mod_adapter2(),
452854
453231
  init_protocol_outbound(),
452855
453232
  init_queue(),
@@ -455231,6 +455608,17 @@ async function handleApprovalStop(params) {
455231
455608
  channelTurnSources: runtime.activeChannelTurn?.sources,
455232
455609
  onFileWrite
455233
455610
  });
455611
+ } catch (error54) {
455612
+ emitToolExecutionOutput.flush();
455613
+ if (!shouldInterrupt()) {
455614
+ emitToolExecutionAbortedEvents(socket, runtime, {
455615
+ toolCallIds: lastExecutingToolCallIds,
455616
+ runId: executionRunId,
455617
+ agentId,
455618
+ conversationId
455619
+ });
455620
+ }
455621
+ throw error54;
455234
455622
  } finally {
455235
455623
  emitToolExecutionOutput.flush();
455236
455624
  }
@@ -455254,7 +455642,7 @@ async function handleApprovalStop(params) {
455254
455642
  if (shouldInterrupt()) {
455255
455643
  return interruptTermination();
455256
455644
  }
455257
- const nextInput = [
455645
+ let nextInput = [
455258
455646
  {
455259
455647
  type: "approval",
455260
455648
  approvals: persistedExecutionResults,
@@ -455262,11 +455650,14 @@ async function handleApprovalStop(params) {
455262
455650
  }
455263
455651
  ];
455264
455652
  let continuationBatchId = dequeuedBatchId;
455653
+ let queuedImageFailureModes;
455265
455654
  const consumedQueuedTurn = consumeQueuedTurn(runtime);
455266
455655
  if (consumedQueuedTurn) {
455267
455656
  const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
455268
455657
  continuationBatchId = dequeuedBatch.batchId;
455269
- nextInput.push(...queuedTurn.messages);
455658
+ const appended = appendQueuedTurnToInput(nextInput, queuedTurn);
455659
+ nextInput = appended.input;
455660
+ queuedImageFailureModes = appended.imageFailureModesByMessageOtid;
455270
455661
  emitDequeuedUserMessage(socket, runtime, queuedTurn, dequeuedBatch);
455271
455662
  }
455272
455663
  const nextInputWithSkillContent = injectQueuedSkillContent(nextInput);
@@ -455279,8 +455670,11 @@ async function handleApprovalStop(params) {
455279
455670
  });
455280
455671
  let sendResult;
455281
455672
  try {
455673
+ const sendOptions = buildSendOptions() ?? {};
455674
+ const imageFailureModesByMessageOtid = mergeImageFailureModesByMessageOtid(sendOptions.imageFailureModesByMessageOtid, queuedImageFailureModes);
455282
455675
  sendResult = await sendApprovalContinuationWithRetry(conversationId, nextInputWithSkillContent, {
455283
- ...buildSendOptions(),
455676
+ ...sendOptions,
455677
+ ...imageFailureModesByMessageOtid ? { imageFailureModesByMessageOtid } : {},
455284
455678
  ...continuationWasFullyAutoHandled ? { allowResponseStateReuse: true } : {}
455285
455679
  }, socket, runtime, turnLease, { providerFallback });
455286
455680
  } catch (error54) {
@@ -455348,8 +455742,10 @@ var init_turn_approval = __esm(async () => {
455348
455742
  init_transport();
455349
455743
  await __promiseAll([
455350
455744
  init_approval_execution(),
455745
+ init_message_image_normalization(),
455351
455746
  init_approval(),
455352
455747
  init_approval_suggestions(),
455748
+ init_continuation_input(),
455353
455749
  init_interrupts(),
455354
455750
  init_protocol_outbound(),
455355
455751
  init_queue(),
@@ -456518,14 +456914,7 @@ async function prepareListenerTurn(params) {
456518
456914
  if (connectionId) {
456519
456915
  onStatusChange?.("processing", connectionId);
456520
456916
  }
456521
- const { normalizeInboundMessages: normalizeInboundMessages2 } = await init_queue().then(() => exports_queue);
456522
- const normalizedMessages = await normalizeInboundMessages2(msg.messages, undefined, {
456523
- imageFailureMode: (msg.channelTurnSources?.length ?? 0) > 0 ? "drop" : "strict"
456524
- });
456525
- if (isInterrupted()) {
456526
- return { kind: "interrupted" };
456527
- }
456528
- trackListenerUserInput(normalizedMessages, "unknown");
456917
+ trackListenerUserInput(msg.messages, "unknown");
456529
456918
  const messagesToSend = [];
456530
456919
  let queuedInterruptedToolCallIds = [];
456531
456920
  const consumed = consumeInterruptQueue(runtime, agentId, conversationId);
@@ -456533,12 +456922,16 @@ async function prepareListenerTurn(params) {
456533
456922
  messagesToSend.push(consumed.approvalMessage);
456534
456923
  queuedInterruptedToolCallIds = consumed.interruptedToolCallIds;
456535
456924
  }
456536
- messagesToSend.push(...normalizedMessages.map((message) => ("content" in message) && !message.otid ? {
456925
+ messagesToSend.push(...msg.messages.map((message) => ("content" in message) && !message.otid ? {
456537
456926
  ...message,
456538
456927
  otid: "client_message_id" in message && typeof message.client_message_id === "string" ? message.client_message_id : crypto.randomUUID()
456539
456928
  } : message));
456929
+ const imageFailureModesByMessageOtid = getInboundImageFailureModes({
456930
+ channelTurnSources: msg.channelTurnSources,
456931
+ messages: messagesToSend
456932
+ });
456540
456933
  let inboundUserTranscriptLines = buildInboundUserTranscriptLines(messagesToSend);
456541
- const firstMessage = normalizedMessages[0];
456934
+ const firstMessage = msg.messages[0];
456542
456935
  const isApprovalMessage = firstMessage && "type" in firstMessage && firstMessage.type === "approval" && "approvals" in firstMessage;
456543
456936
  let cachedAgent = null;
456544
456937
  if (!isApprovalMessage) {
@@ -456650,6 +457043,7 @@ async function prepareListenerTurn(params) {
456650
457043
  kind: "ready",
456651
457044
  getCachedAgent: () => cachedAgent,
456652
457045
  currentInput,
457046
+ imageFailureModesByMessageOtid,
456653
457047
  inboundUserTranscriptLines,
456654
457048
  pendingNormalizationInterruptedToolCallIds: [
456655
457049
  ...queuedInterruptedToolCallIds
@@ -456668,6 +457062,7 @@ var init_turn_setup = __esm(async () => {
456668
457062
  init_warmup();
456669
457063
  await __promiseAll([
456670
457064
  init_toolset(),
457065
+ init_image_policy(),
456671
457066
  init_interrupts(),
456672
457067
  init_mod_adapter2(),
456673
457068
  init_turn_events()
@@ -456802,7 +457197,9 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
456802
457197
  workingDirectory: turnWorkingDirectory,
456803
457198
  permissionModeState: turnPermissionModeState,
456804
457199
  preparedToolContext: preparedToolContext.preparedToolContext,
456805
- skipImageNormalization: true,
457200
+ ...setup.imageFailureModesByMessageOtid ? {
457201
+ imageFailureModesByMessageOtid: setup.imageFailureModesByMessageOtid
457202
+ } : {},
456806
457203
  ...providerFallback.overrideModel ? { overrideModel: providerFallback.overrideModel } : {},
456807
457204
  ...msg.actingUserId ? { actingUserId: msg.actingUserId } : {},
456808
457205
  ...pendingNormalizationInterruptedToolCallIds.length > 0 ? {
@@ -461156,7 +461553,7 @@ var init_grep_in_files = __esm(() => {
461156
461553
  });
461157
461554
 
461158
461555
  // src/websocket/listener/file-commands.ts
461159
- import { readdir as readdir11, readFile as readFile18 } from "node:fs/promises";
461556
+ import { readdir as readdir11, readFile as readFile17 } from "node:fs/promises";
461160
461557
  import { homedir as homedir30 } from "node:os";
461161
461558
  import path35 from "node:path";
461162
461559
  function trackListenerError2(errorType, error54, context4) {
@@ -461211,7 +461608,7 @@ async function getIgnoreConfig(root2) {
461211
461608
  return cached3;
461212
461609
  let patterns2 = [];
461213
461610
  try {
461214
- const content = await readFile18(path35.join(absRoot, ".letta", ".lettaignore"), "utf-8");
461611
+ const content = await readFile17(path35.join(absRoot, ".letta", ".lettaignore"), "utf-8");
461215
461612
  patterns2 = parseLettaIgnore(content);
461216
461613
  } catch {
461217
461614
  patterns2 = [];
@@ -463954,7 +464351,7 @@ function handleMemoryProtocolCommand(parsed, context4) {
463954
464351
  ensureLocalMemfsCheckout: ensureLocalMemfsCheckout2,
463955
464352
  isMemfsEnabledOnServer: isMemfsEnabledOnServer2
463956
464353
  } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
463957
- const { readFile: readFile19 } = await import("node:fs/promises");
464354
+ const { readFile: readFile18 } = await import("node:fs/promises");
463958
464355
  const { existsSync: existsSync46 } = await import("node:fs");
463959
464356
  const { isAbsolute: isAbsolute24, join: join52, normalize: normalize5, relative: relative13, sep: sep6 } = await import("node:path");
463960
464357
  if (isAbsolute24(parsed.path) || parsed.path.length === 0) {
@@ -463980,7 +464377,7 @@ function handleMemoryProtocolCommand(parsed, context4) {
463980
464377
  return;
463981
464378
  }
463982
464379
  }
463983
- const buffer = await readFile19(absolutePath);
464380
+ const buffer = await readFile18(absolutePath);
463984
464381
  const content = encoding === "base64" ? buffer.toString("base64") : buffer.toString("utf-8");
463985
464382
  const pathspec = rel.split(sep6).join("/");
463986
464383
  safeSocketSend(socket, {
@@ -464020,7 +464417,7 @@ function handleMemoryProtocolCommand(parsed, context4) {
464020
464417
  isMemfsEnabledOnServer: isMemfsEnabledOnServer2
464021
464418
  } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
464022
464419
  const { commitMemoryWrite: commitMemoryWrite2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
464023
- const { writeFile: writeFile15, mkdir: mkdir13 } = await import("node:fs/promises");
464420
+ const { writeFile: writeFile14, mkdir: mkdir13 } = await import("node:fs/promises");
464024
464421
  const { existsSync: existsSync46 } = await import("node:fs");
464025
464422
  const { dirname: dirname27, isAbsolute: isAbsolute24, join: join52, normalize: normalize5, relative: relative13, sep: sep6 } = await import("node:path");
464026
464423
  if (isAbsolute24(parsed.path) || parsed.path.length === 0) {
@@ -464048,7 +464445,7 @@ function handleMemoryProtocolCommand(parsed, context4) {
464048
464445
  }
464049
464446
  const buffer = encoding === "base64" ? Buffer.from(parsed.content, "base64") : Buffer.from(parsed.content, "utf-8");
464050
464447
  await mkdir13(dirname27(absolutePath), { recursive: true });
464051
- await writeFile15(absolutePath, buffer);
464448
+ await writeFile14(absolutePath, buffer);
464052
464449
  const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
464053
464450
  const backend4 = getBackend2();
464054
464451
  const memorySyncMode = backend4.capabilities.localMemfs && !backend4.capabilities.remoteMemfs ? "local" : undefined;
@@ -464688,7 +465085,8 @@ async function handleCreateAgentCommand(parsed, socket, safeSocketSend) {
464688
465085
  const { createAgentForPersonality: createAgentForPersonality2 } = await Promise.resolve().then(() => (init_personality(), exports_personality));
464689
465086
  const result = await createAgentForPersonality2({
464690
465087
  personalityId: parsed.personality,
464691
- model: parsed.model
465088
+ model: parsed.model,
465089
+ ...parsed.tags && { tags: parsed.tags }
464692
465090
  });
464693
465091
  if (parsed.pin_global !== false) {
464694
465092
  settingsManager.pinAgent(result.agent.id);
@@ -467177,7 +467575,7 @@ var execFile15, __dirname2, localXdgOpenPath, platform8, arch3, pTryEach = async
467177
467575
  }
467178
467576
  subprocess.unref();
467179
467577
  return subprocess;
467180
- }, open3 = (target2, options3) => {
467578
+ }, open4 = (target2, options3) => {
467181
467579
  if (typeof target2 !== "string") {
467182
467580
  throw new TypeError("Expected a `target`");
467183
467581
  }
@@ -467246,14 +467644,14 @@ var init_open = __esm(() => {
467246
467644
  }));
467247
467645
  defineLazyProperty(apps, "browser", () => "browser");
467248
467646
  defineLazyProperty(apps, "browserPrivate", () => "browserPrivate");
467249
- open_default = open3;
467647
+ open_default = open4;
467250
467648
  });
467251
467649
 
467252
467650
  // src/cli/commands/connect-oauth-core.ts
467253
467651
  async function openOAuthBrowser(authorizationUrl) {
467254
467652
  try {
467255
- const { default: open4 } = await Promise.resolve().then(() => (init_open(), exports_open));
467256
- const subprocess = await open4(authorizationUrl, { wait: false });
467653
+ const { default: open5 } = await Promise.resolve().then(() => (init_open(), exports_open));
467654
+ const subprocess = await open5(authorizationUrl, { wait: false });
467257
467655
  subprocess.on("error", () => {});
467258
467656
  } catch {}
467259
467657
  }
@@ -469560,8 +469958,6 @@ var init_client7 = __esm(async () => {
469560
469958
  shouldAttemptPostStopApprovalRecovery,
469561
469959
  markAwaitingAcceptedApprovalContinuationRunId,
469562
469960
  resolveStaleApprovals,
469563
- normalizeMessageContentImages: normalizeMessageContentImages2,
469564
- normalizeInboundMessages,
469565
469961
  consumeQueuedTurn,
469566
469962
  handleIncomingMessage,
469567
469963
  handleApprovalResponseInput,
@@ -470005,7 +470401,7 @@ function ConstellationLoginView({
470005
470401
  const deviceData = await requestDeviceCode();
470006
470402
  setUserCode(deviceData.user_code);
470007
470403
  setVerificationUri(deviceData.verification_uri_complete);
470008
- Promise.resolve().then(() => (init_open(), exports_open)).then(({ default: open4 }) => open4(deviceData.verification_uri_complete, { wait: false })).then((subprocess) => {
470404
+ Promise.resolve().then(() => (init_open(), exports_open)).then(({ default: open5 }) => open5(deviceData.verification_uri_complete, { wait: false })).then((subprocess) => {
470009
470405
  subprocess.on("error", () => {});
470010
470406
  }).catch(() => {});
470011
470407
  const deviceId = settingsManager.getOrCreateDeviceId();
@@ -471930,7 +472326,7 @@ __export(exports_skills3, {
471930
472326
  GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR2
471931
472327
  });
471932
472328
  import { existsSync as existsSync54 } from "node:fs";
471933
- import { readdir as readdir15, readFile as readFile22, realpath as realpath6, stat as stat15 } from "node:fs/promises";
472329
+ import { readdir as readdir15, readFile as readFile21, realpath as realpath6, stat as stat15 } from "node:fs/promises";
471934
472330
  import { dirname as dirname31, join as join62 } from "node:path";
471935
472331
  import { fileURLToPath as fileURLToPath8 } from "node:url";
471936
472332
  function getBundledSkillsPath2() {
@@ -472102,7 +472498,7 @@ async function findSkillFiles2(currentPath, rootPath, skills, errors7, source2,
472102
472498
  }
472103
472499
  }
472104
472500
  async function parseSkillFile2(filePath, rootPath, source2) {
472105
- const content = await readFile22(filePath, "utf-8");
472501
+ const content = await readFile21(filePath, "utf-8");
472106
472502
  const { frontmatter, body: body3 } = parseFrontmatter(content);
472107
472503
  const normalizedRoot = rootPath.endsWith("/") ? rootPath.slice(0, -1) : rootPath;
472108
472504
  const relativePath = filePath.slice(normalizedRoot.length + 1);
@@ -472162,9 +472558,9 @@ var init_skills4 = __esm(() => {
472162
472558
  var exports_fs = {};
472163
472559
  __export(exports_fs, {
472164
472560
  writeJsonFile: () => writeJsonFile2,
472165
- writeFile: () => writeFile17,
472561
+ writeFile: () => writeFile16,
472166
472562
  readJsonFile: () => readJsonFile4,
472167
- readFile: () => readFile23,
472563
+ readFile: () => readFile22,
472168
472564
  mkdir: () => mkdir15,
472169
472565
  exists: () => exists2
472170
472566
  });
@@ -472175,10 +472571,10 @@ import {
472175
472571
  mkdirSync as mkdirSync38
472176
472572
  } from "node:fs";
472177
472573
  import { dirname as dirname32 } from "node:path";
472178
- async function readFile23(path39) {
472574
+ async function readFile22(path39) {
472179
472575
  return fsReadFileSync2(path39, { encoding: "utf-8" });
472180
472576
  }
472181
- async function writeFile17(path39, content) {
472577
+ async function writeFile16(path39, content) {
472182
472578
  const dir = dirname32(path39);
472183
472579
  if (!existsSync55(dir)) {
472184
472580
  mkdirSync38(dir, { recursive: true });
@@ -472192,14 +472588,14 @@ async function mkdir15(path39, options3) {
472192
472588
  mkdirSync38(path39, options3);
472193
472589
  }
472194
472590
  async function readJsonFile4(path39) {
472195
- const text2 = await readFile23(path39);
472591
+ const text2 = await readFile22(path39);
472196
472592
  return JSON.parse(text2);
472197
472593
  }
472198
472594
  async function writeJsonFile2(path39, data, options3) {
472199
472595
  const indent = options3?.indent ?? 2;
472200
472596
  const content = `${JSON.stringify(data, null, indent)}
472201
472597
  `;
472202
- await writeFile17(path39, content);
472598
+ await writeFile16(path39, content);
472203
472599
  }
472204
472600
  var init_fs2 = () => {};
472205
472601
 
@@ -472398,7 +472794,7 @@ import {
472398
472794
  execFile as execFile17
472399
472795
  } from "node:child_process";
472400
472796
  import { accessSync as accessSync2, constants as constants4, realpathSync as realpathSync6 } from "node:fs";
472401
- import { readdir as readdir16, rm as rm6 } from "node:fs/promises";
472797
+ import { readdir as readdir16, rm as rm7 } from "node:fs/promises";
472402
472798
  import { dirname as dirname33, join as join63 } from "node:path";
472403
472799
  import { promisify as promisify15 } from "node:util";
472404
472800
  function debugLog4(...args) {
@@ -472630,7 +473026,7 @@ async function cleanupOrphanedDirs2(globalPath) {
472630
473026
  if (entry.startsWith(".letta-code-")) {
472631
473027
  const orphanPath = join63(lettaAiDir, entry);
472632
473028
  debugLog4("Cleaning orphaned temp directory:", orphanPath);
472633
- await rm6(orphanPath, { recursive: true, force: true });
473029
+ await rm7(orphanPath, { recursive: true, force: true });
472634
473030
  }
472635
473031
  }
472636
473032
  } catch {}
@@ -474098,7 +474494,7 @@ __export(exports_import, {
474098
474494
  extractSkillsFromAf: () => extractSkillsFromAf
474099
474495
  });
474100
474496
  import { createReadStream as createReadStream2 } from "node:fs";
474101
- import { access as access2, chmod, mkdir as mkdir16, readFile as readFile24, writeFile as writeFile18 } from "node:fs/promises";
474497
+ import { access as access2, chmod, mkdir as mkdir16, readFile as readFile23, writeFile as writeFile17 } from "node:fs/promises";
474102
474498
  import { dirname as dirname34, isAbsolute as isAbsolute25, relative as relative13, resolve as resolve36, sep as sep7, win32 as win325 } from "node:path";
474103
474499
  function validateImportedSkillName(name) {
474104
474500
  const trimmedName = name.trim();
@@ -474199,7 +474595,7 @@ async function importAgentFromFile(options3) {
474199
474595
  }
474200
474596
  async function extractSkillsFromAf(afPath, destDir) {
474201
474597
  const extracted = [];
474202
- const content = await readFile24(afPath, "utf-8");
474598
+ const content = await readFile23(afPath, "utf-8");
474203
474599
  const afData = JSON.parse(content);
474204
474600
  if (!afData.skills || !Array.isArray(afData.skills)) {
474205
474601
  return [];
@@ -474228,7 +474624,7 @@ async function writeSkillFiles(skillDir, files) {
474228
474624
  async function writeSkillFile(skillDir, filePath, content) {
474229
474625
  const fullPath = resolveImportedSkillFilePath(skillDir, filePath);
474230
474626
  await mkdir16(dirname34(fullPath), { recursive: true });
474231
- await writeFile18(fullPath, content, "utf-8");
474627
+ await writeFile17(fullPath, content, "utf-8");
474232
474628
  const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
474233
474629
  if (isScript) {
474234
474630
  try {
@@ -474281,7 +474677,7 @@ function parseRegistryHandle(handle2) {
474281
474677
  async function importAgentFromRegistry(options3) {
474282
474678
  const { tmpdir: tmpdir10 } = await import("node:os");
474283
474679
  const { join: join68 } = await import("node:path");
474284
- const { writeFile: writeFile19, unlink: unlink5 } = await import("node:fs/promises");
474680
+ const { writeFile: writeFile18, unlink: unlink5 } = await import("node:fs/promises");
474285
474681
  const { author, name } = parseRegistryHandle(options3.handle);
474286
474682
  const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/refs/heads/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}/${name}.af`;
474287
474683
  const response = await fetch(rawUrl);
@@ -474293,7 +474689,7 @@ async function importAgentFromRegistry(options3) {
474293
474689
  }
474294
474690
  const afContent = await response.text();
474295
474691
  const tempPath = join68(tmpdir10(), `letta-import-${author}-${name}-${Date.now()}.af`);
474296
- await writeFile19(tempPath, afContent, "utf-8");
474692
+ await writeFile18(tempPath, afContent, "utf-8");
474297
474693
  try {
474298
474694
  const result = await importAgentFromFile({
474299
474695
  filePath: tempPath,
@@ -474401,7 +474797,8 @@ async function ensureDefaultAgents(backend4, options3) {
474401
474797
  const createOptions = personality === "tutorial" ? {
474402
474798
  ...await buildCreateAgentOptionsForPersonality2({
474403
474799
  personalityId: "tutorial",
474404
- model
474800
+ model,
474801
+ tags: [ONBOARDING_ORIGIN_TAG]
474405
474802
  }),
474406
474803
  memoryPromptMode
474407
474804
  } : {
@@ -479108,7 +479505,7 @@ var init_queued_message_parts = __esm(() => {
479108
479505
  // src/cli/helpers/reflection-arena-hf-upload.ts
479109
479506
  import { execFile as execFileCb5 } from "node:child_process";
479110
479507
  import { existsSync as existsSync60 } from "node:fs";
479111
- import { appendFile as appendFile2, chmod as chmod2, mkdir as mkdir17, writeFile as writeFile19 } from "node:fs/promises";
479508
+ import { appendFile as appendFile2, chmod as chmod2, mkdir as mkdir17, writeFile as writeFile18 } from "node:fs/promises";
479112
479509
  import { homedir as homedir38 } from "node:os";
479113
479510
  import { join as join69 } from "node:path";
479114
479511
  import { promisify as promisify16 } from "node:util";
@@ -479147,7 +479544,7 @@ async function runGit6(cwd2, args, env5) {
479147
479544
  }
479148
479545
  async function writeGitAskpass(repoRoot) {
479149
479546
  const askpassPath = join69(repoRoot, "hf-askpass.sh");
479150
- await writeFile19(askpassPath, [
479547
+ await writeFile18(askpassPath, [
479151
479548
  "#!/bin/sh",
479152
479549
  'case "$1" in',
479153
479550
  " *Username*) printf '%s\\n' 'hf_user' ;;",
@@ -479232,7 +479629,7 @@ var init_reflection_arena_hf_upload = __esm(() => {
479232
479629
  // src/cli/helpers/reflection-arena.ts
479233
479630
  import { execFile as execFileCb6 } from "node:child_process";
479234
479631
  import { randomInt, randomUUID as randomUUID30 } from "node:crypto";
479235
- import { appendFile as appendFile3, mkdir as mkdir18, readFile as readFile25, writeFile as writeFile20 } from "node:fs/promises";
479632
+ import { appendFile as appendFile3, mkdir as mkdir18, readFile as readFile24, writeFile as writeFile19 } from "node:fs/promises";
479236
479633
  import { homedir as homedir39 } from "node:os";
479237
479634
  import { join as join70 } from "node:path";
479238
479635
  import { promisify as promisify17 } from "node:util";
@@ -479277,11 +479674,11 @@ function getReflectionArenaRunPath(runId) {
479277
479674
  }
479278
479675
  async function saveReflectionArenaRun(run) {
479279
479676
  await mkdir18(getReflectionArenaRunsDir(), { recursive: true });
479280
- await writeFile20(getReflectionArenaRunPath(run.runId), `${JSON.stringify(run, null, 2)}
479677
+ await writeFile19(getReflectionArenaRunPath(run.runId), `${JSON.stringify(run, null, 2)}
479281
479678
  `, "utf-8");
479282
479679
  }
479283
479680
  async function loadReflectionArenaRun(runId) {
479284
- const raw2 = await readFile25(getReflectionArenaRunPath(runId), "utf-8");
479681
+ const raw2 = await readFile24(getReflectionArenaRunPath(runId), "utf-8");
479285
479682
  return JSON.parse(raw2);
479286
479683
  }
479287
479684
  async function updateReflectionArenaRun(runId, update2) {
@@ -479473,7 +479870,7 @@ async function appendChoiceRecord(run) {
479473
479870
  }
479474
479871
  async function readTranscriptPayloadForTelemetry(payloadPath) {
479475
479872
  try {
479476
- const transcript = await readFile25(payloadPath, "utf-8");
479873
+ const transcript = await readFile24(payloadPath, "utf-8");
479477
479874
  return {
479478
479875
  transcriptPayload: transcript.slice(0, REFLECTION_ARENA_TELEMETRY_TRANSCRIPT_MAX_CHARS),
479479
479876
  transcriptPayloadChars: transcript.length,
@@ -494711,7 +495108,7 @@ var init_McpConnectFlow = __esm(async () => {
494711
495108
  const authorizationUrl = event2.url;
494712
495109
  setAuthUrl(authorizationUrl);
494713
495110
  setConnectionStatus("Opening browser for authorization...");
494714
- Promise.resolve().then(() => (init_open(), exports_open)).then(({ default: open4 }) => open4(authorizationUrl)).catch(() => {});
495111
+ Promise.resolve().then(() => (init_open(), exports_open)).then(({ default: open5 }) => open5(authorizationUrl)).catch(() => {});
494715
495112
  }
494716
495113
  break;
494717
495114
  case "waiting_for_auth" /* WAITING_FOR_AUTH */:
@@ -500905,7 +501302,7 @@ var init_PersonalitySelector = __esm(async () => {
500905
501302
  });
500906
501303
 
500907
501304
  // src/utils/aws-credentials.ts
500908
- import { readFile as readFile26 } from "node:fs/promises";
501305
+ import { readFile as readFile25 } from "node:fs/promises";
500909
501306
  import { homedir as homedir45 } from "node:os";
500910
501307
  import { join as join77 } from "node:path";
500911
501308
  async function parseAwsCredentials() {
@@ -500913,11 +501310,11 @@ async function parseAwsCredentials() {
500913
501310
  const configPath = join77(homedir45(), ".aws", "config");
500914
501311
  const profiles = new Map;
500915
501312
  try {
500916
- const content = await readFile26(credentialsPath, "utf-8");
501313
+ const content = await readFile25(credentialsPath, "utf-8");
500917
501314
  parseIniFile(content, profiles, false);
500918
501315
  } catch {}
500919
501316
  try {
500920
- const content = await readFile26(configPath, "utf-8");
501317
+ const content = await readFile25(configPath, "utf-8");
500921
501318
  parseIniFile(content, profiles, true);
500922
501319
  } catch {}
500923
501320
  return Array.from(profiles.values());
@@ -528291,7 +528688,7 @@ The deployment target for this project is CITATION-DOGFOOD-OK.
528291
528688
 
528292
528689
  // src/mods/learning-harness.ts
528293
528690
  import { spawn as spawn13 } from "node:child_process";
528294
- import { access as access3, copyFile as copyFile2, mkdir as mkdir19, readFile as readFile27, writeFile as writeFile21 } from "node:fs/promises";
528691
+ import { access as access3, copyFile as copyFile2, mkdir as mkdir19, readFile as readFile26, writeFile as writeFile20 } from "node:fs/promises";
528295
528692
  import path42 from "node:path";
528296
528693
  function slugify2(value) {
528297
528694
  const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -528539,14 +528936,14 @@ async function existingPath(filePath) {
528539
528936
  return await fileExists(filePath) ? filePath : undefined;
528540
528937
  }
528541
528938
  async function writeJsonArtifact(filePath, value) {
528542
- await writeFile21(filePath, `${JSON.stringify(value, null, 2)}
528939
+ await writeFile20(filePath, `${JSON.stringify(value, null, 2)}
528543
528940
  `, "utf8");
528544
528941
  }
528545
528942
  async function writeCommandArtifacts(prefix, command, args, result) {
528546
- await writeFile21(`${prefix}.command.txt`, `${renderCommand(command, args)}
528943
+ await writeFile20(`${prefix}.command.txt`, `${renderCommand(command, args)}
528547
528944
  `, "utf8");
528548
- await writeFile21(`${prefix}.stdout`, result.stdout, "utf8");
528549
- await writeFile21(`${prefix}.stderr`, result.stderr, "utf8");
528945
+ await writeFile20(`${prefix}.stdout`, result.stdout, "utf8");
528946
+ await writeFile20(`${prefix}.stderr`, result.stderr, "utf8");
528550
528947
  await writeJsonArtifact(`${prefix}.result.json`, result);
528551
528948
  }
528552
528949
  async function prepareMemoryFiles(memoryDir, memoryFiles) {
@@ -528554,7 +528951,7 @@ async function prepareMemoryFiles(memoryDir, memoryFiles) {
528554
528951
  for (const [relativePath, content] of Object.entries(memoryFiles ?? {})) {
528555
528952
  const filePath = safeJoin(memoryDir, relativePath);
528556
528953
  await mkdir19(path42.dirname(filePath), { recursive: true });
528557
- await writeFile21(filePath, content, "utf8");
528954
+ await writeFile20(filePath, content, "utf8");
528558
528955
  }
528559
528956
  }
528560
528957
  function renderEvaluationPrompt(prompt, memoryDir) {
@@ -529217,7 +529614,7 @@ function renderProposerGuide(params) {
529217
529614
  `;
529218
529615
  }
529219
529616
  async function writeHistoryArtifacts(params) {
529220
- await writeFile21(params.historyPath, renderHistoryIndex({
529617
+ await writeFile20(params.historyPath, renderHistoryIndex({
529221
529618
  attempts: params.attempts,
529222
529619
  historyManifestPath: params.historyManifestPath,
529223
529620
  proposerGuidePath: params.proposerGuidePath,
@@ -529225,7 +529622,7 @@ async function writeHistoryArtifacts(params) {
529225
529622
  spec: params.spec
529226
529623
  }), "utf8");
529227
529624
  await writeJsonArtifact(params.historyManifestPath, buildHistoryManifest(params));
529228
- await writeFile21(params.proposerGuidePath, renderProposerGuide(params), "utf8");
529625
+ await writeFile20(params.proposerGuidePath, renderProposerGuide(params), "utf8");
529229
529626
  }
529230
529627
  async function defaultCommandRunner(command, args, options3) {
529231
529628
  const startedAt = Date.now();
@@ -529316,7 +529713,7 @@ function createScenarioSuiteEvaluator(params) {
529316
529713
  outputFormat
529317
529714
  })
529318
529715
  ];
529319
- await writeFile21(hasConfiguredScenarios ? path42.join(scenarioDir, "prompt.md") : path42.join(context4.runDir, "eval-prompt.md"), evalPrompt, "utf8");
529716
+ await writeFile20(hasConfiguredScenarios ? path42.join(scenarioDir, "prompt.md") : path42.join(context4.runDir, "eval-prompt.md"), evalPrompt, "utf8");
529320
529717
  const scenarioEvalResult = await context4.runner(context4.cliCommand, evalArgs, {
529321
529718
  cwd: context4.repoRoot,
529322
529719
  env: {
@@ -529508,7 +529905,7 @@ async function runModLearningCandidate(params) {
529508
529905
  outputFormat: "json"
529509
529906
  })
529510
529907
  ];
529511
- await writeFile21(path42.join(runDir, "generation-prompt.md"), generationPrompt, "utf8");
529908
+ await writeFile20(path42.join(runDir, "generation-prompt.md"), generationPrompt, "utf8");
529512
529909
  generationResult = await params.runner(params.cliCommand, generationArgs, {
529513
529910
  cwd: repoRoot,
529514
529911
  env: {
@@ -529587,7 +529984,7 @@ async function runModLearningCandidate(params) {
529587
529984
  spec: options3.spec
529588
529985
  };
529589
529986
  await writeJsonArtifact(path42.join(runDir, "report.json"), report);
529590
- await writeFile21(reportPath, renderMarkdownReport(report), "utf8");
529987
+ await writeFile20(reportPath, renderMarkdownReport(report), "utf8");
529591
529988
  await writeCandidateManifest(report);
529592
529989
  emitProgress("done", params.candidateCount > 1 ? `Optimization iteration ${params.candidateIndex}/${params.candidateCount} complete` : "mod optimization complete", {
529593
529990
  attempts: [...params.previousAttempts, summarizeAttempt(report)],
@@ -529765,7 +530162,7 @@ async function runModLearning(options3) {
529765
530162
  spec: normalizedOptions.spec
529766
530163
  });
529767
530164
  await writeJsonArtifact(path42.join(runDir, "report.json"), report);
529768
- await writeFile21(reportPath, renderMarkdownReport(report), "utf8");
530165
+ await writeFile20(reportPath, renderMarkdownReport(report), "utf8");
529769
530166
  normalizedOptions.onProgress?.({
529770
530167
  candidateCount,
529771
530168
  candidateIndex: selectedCandidateIndex,
@@ -529783,7 +530180,7 @@ async function runModLearning(options3) {
529783
530180
  return report;
529784
530181
  }
529785
530182
  async function readModLearningEnv(envPath) {
529786
- return JSON.parse(await readFile27(envPath, "utf8"));
530183
+ return JSON.parse(await readFile26(envPath, "utf8"));
529787
530184
  }
529788
530185
  var init_learning_harness = __esm(async () => {
529789
530186
  await init_mod_engine();
@@ -532163,7 +532560,7 @@ var exports_export = {};
532163
532560
  __export(exports_export, {
532164
532561
  packageSkills: () => packageSkills
532165
532562
  });
532166
- import { readdir as readdir17, readFile as readFile28 } from "node:fs/promises";
532563
+ import { readdir as readdir17, readFile as readFile27 } from "node:fs/promises";
532167
532564
  import { relative as relative16, resolve as resolve40 } from "node:path";
532168
532565
  async function packageSkills(agentId, skillsDir) {
532169
532566
  const skills = [];
@@ -532184,7 +532581,7 @@ async function packageSkills(agentId, skillsDir) {
532184
532581
  const skillDir = resolve40(baseDir, entry.name);
532185
532582
  const skillMdPath = resolve40(skillDir, "SKILL.md");
532186
532583
  try {
532187
- await readFile28(skillMdPath, "utf-8");
532584
+ await readFile27(skillMdPath, "utf-8");
532188
532585
  } catch {
532189
532586
  console.warn(`Skipping invalid skill ${entry.name}: missing SKILL.md`);
532190
532587
  continue;
@@ -532216,7 +532613,7 @@ async function readSkillFiles(skillDir) {
532216
532613
  if (entry.isDirectory()) {
532217
532614
  await walk(fullPath);
532218
532615
  } else {
532219
- const content = await readFile28(fullPath, "utf-8");
532616
+ const content = await readFile27(fullPath, "utf-8");
532220
532617
  const relativePath = relative16(skillDir, fullPath).replace(/\\/g, "/");
532221
532618
  files[relativePath] = content;
532222
532619
  }
@@ -533035,7 +533432,7 @@ ${SYSTEM_REMINDER_CLOSE}`),
533035
533432
  const adeUrl = buildChatUrl(agentId, {
533036
533433
  conversationId: conversationIdRef.current
533037
533434
  });
533038
- Promise.resolve().then(() => (init_open(), exports_open)).then(({ default: open4 }) => open4(adeUrl, { wait: false })).catch(() => {});
533435
+ Promise.resolve().then(() => (init_open(), exports_open)).then(({ default: open5 }) => open5(adeUrl, { wait: false })).catch(() => {});
533039
533436
  cmd.finish(`Opening ADE...
533040
533437
  → ${adeUrl}`, true);
533041
533438
  return { submitted: true };
@@ -538994,7 +539391,8 @@ async function ensureDefaultAgents2(backend4, options3) {
538994
539391
  const createOptions = personality === "tutorial" ? {
538995
539392
  ...await buildCreateAgentOptionsForPersonality2({
538996
539393
  personalityId: "tutorial",
538997
- model
539394
+ model,
539395
+ tags: [ONBOARDING_ORIGIN_TAG]
538998
539396
  }),
538999
539397
  memoryPromptMode
539000
539398
  } : {
@@ -539242,7 +539640,7 @@ __export(exports_import2, {
539242
539640
  extractSkillsFromAf: () => extractSkillsFromAf2
539243
539641
  });
539244
539642
  import { createReadStream as createReadStream3 } from "node:fs";
539245
- import { access as access4, chmod as chmod3, mkdir as mkdir20, readFile as readFile29, writeFile as writeFile22 } from "node:fs/promises";
539643
+ import { access as access4, chmod as chmod3, mkdir as mkdir20, readFile as readFile28, writeFile as writeFile21 } from "node:fs/promises";
539246
539644
  import { dirname as dirname38, isAbsolute as isAbsolute27, relative as relative17, resolve as resolve41, sep as sep8, win32 as win326 } from "node:path";
539247
539645
  function validateImportedSkillName2(name) {
539248
539646
  const trimmedName = name.trim();
@@ -539343,7 +539741,7 @@ async function importAgentFromFile2(options3) {
539343
539741
  }
539344
539742
  async function extractSkillsFromAf2(afPath, destDir) {
539345
539743
  const extracted = [];
539346
- const content = await readFile29(afPath, "utf-8");
539744
+ const content = await readFile28(afPath, "utf-8");
539347
539745
  const afData = JSON.parse(content);
539348
539746
  if (!afData.skills || !Array.isArray(afData.skills)) {
539349
539747
  return [];
@@ -539372,7 +539770,7 @@ async function writeSkillFiles2(skillDir, files) {
539372
539770
  async function writeSkillFile2(skillDir, filePath, content) {
539373
539771
  const fullPath = resolveImportedSkillFilePath2(skillDir, filePath);
539374
539772
  await mkdir20(dirname38(fullPath), { recursive: true });
539375
- await writeFile22(fullPath, content, "utf-8");
539773
+ await writeFile21(fullPath, content, "utf-8");
539376
539774
  const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
539377
539775
  if (isScript) {
539378
539776
  try {
@@ -539425,7 +539823,7 @@ function parseRegistryHandle2(handle2) {
539425
539823
  async function importAgentFromRegistry2(options3) {
539426
539824
  const { tmpdir: tmpdir12 } = await import("node:os");
539427
539825
  const { join: join84 } = await import("node:path");
539428
- const { writeFile: writeFile23, unlink: unlink5 } = await import("node:fs/promises");
539826
+ const { writeFile: writeFile22, unlink: unlink5 } = await import("node:fs/promises");
539429
539827
  const { author, name } = parseRegistryHandle2(options3.handle);
539430
539828
  const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER2}/${AGENT_REGISTRY_REPO2}/refs/heads/${AGENT_REGISTRY_BRANCH2}/agents/@${author}/${name}/${name}.af`;
539431
539829
  const response = await fetch(rawUrl);
@@ -539437,7 +539835,7 @@ async function importAgentFromRegistry2(options3) {
539437
539835
  }
539438
539836
  const afContent = await response.text();
539439
539837
  const tempPath = join84(tmpdir12(), `letta-import-${author}-${name}-${Date.now()}.af`);
539440
- await writeFile23(tempPath, afContent, "utf-8");
539838
+ await writeFile22(tempPath, afContent, "utf-8");
539441
539839
  try {
539442
539840
  const result = await importAgentFromFile2({
539443
539841
  filePath: tempPath,
@@ -544527,7 +544925,7 @@ import WebSocket7, { WebSocketServer } from "ws";
544527
544925
 
544528
544926
  // src/websocket/app-server-auth.ts
544529
544927
  import { createHash as createHash5, createHmac, timingSafeEqual } from "node:crypto";
544530
- import { readFile as readFile13 } from "node:fs/promises";
544928
+ import { readFile as readFile12 } from "node:fs/promises";
544531
544929
  import { isIP as isIP2 } from "node:net";
544532
544930
  import { isAbsolute as isAbsolute22 } from "node:path";
544533
544931
  var INVALID_AUTHORIZATION_HEADER_MESSAGE = "invalid authorization header";
@@ -544771,7 +545169,7 @@ function bearerTokenFromHeaders(headers) {
544771
545169
  async function readTrimmedSecret(path31) {
544772
545170
  let raw2;
544773
545171
  try {
544774
- raw2 = await readFile13(path31, "utf8");
545172
+ raw2 = await readFile12(path31, "utf8");
544775
545173
  } catch (error54) {
544776
545174
  const message = error54 instanceof Error ? error54.message : String(error54);
544777
545175
  throw new Error(`failed to read websocket auth secret ${path31}: ${message}`);
@@ -546624,7 +547022,7 @@ init_reflection_transcript();
546624
547022
  import { createHash as createHash7 } from "node:crypto";
546625
547023
 
546626
547024
  // src/cli/subcommands/dream-sources/openhands.ts
546627
- import { readdir as readdir12, readFile as readFile19, stat as stat14 } from "node:fs/promises";
547025
+ import { readdir as readdir12, readFile as readFile18, stat as stat14 } from "node:fs/promises";
546628
547026
  import { join as join52 } from "node:path";
546629
547027
  var RESULT_TEXT_TRUNCATE_LIMIT = 4000;
546630
547028
  function joinTextContent(content) {
@@ -546751,7 +547149,7 @@ async function readOpenHandsEventDir(dir) {
546751
547149
  }
546752
547150
  const events = [];
546753
547151
  for (const name of fileNames) {
546754
- const raw2 = await readFile19(join52(eventsDir, name), "utf-8");
547152
+ const raw2 = await readFile18(join52(eventsDir, name), "utf-8");
546755
547153
  const event2 = safeJsonParseOr(raw2, null);
546756
547154
  if (event2 && typeof event2 === "object") {
546757
547155
  events.push(event2);
@@ -546766,17 +547164,17 @@ var openHandsAdapter = {
546766
547164
  if (info?.isDirectory()) {
546767
547165
  return convertOpenHandsEvents(await readOpenHandsEventDir(locator));
546768
547166
  }
546769
- const raw2 = await readFile19(locator, "utf-8");
547167
+ const raw2 = await readFile18(locator, "utf-8");
546770
547168
  return convertOpenHandsEvents(parseOpenHandsEventsFile(raw2, locator));
546771
547169
  }
546772
547170
  };
546773
547171
 
546774
547172
  // src/cli/subcommands/dream-sources/transcript.ts
546775
- import { readFile as readFile20 } from "node:fs/promises";
547173
+ import { readFile as readFile19 } from "node:fs/promises";
546776
547174
  var transcriptAdapter = {
546777
547175
  type: "transcript",
546778
547176
  async convert(locator) {
546779
- const raw2 = await readFile20(locator, "utf-8");
547177
+ const raw2 = await readFile19(locator, "utf-8");
546780
547178
  const entries = [];
546781
547179
  for (const line of raw2.split(`
546782
547180
  `)) {
@@ -546828,7 +547226,7 @@ async function stageFromSource(agentId, parsed) {
546828
547226
  init_memory_filesystem2();
546829
547227
  init_memory_git();
546830
547228
  import { execFileSync as execFileSync7 } from "node:child_process";
546831
- import { mkdir as mkdir13, readFile as readFile21, rm as rm5, writeFile as writeFile15 } from "node:fs/promises";
547229
+ import { mkdir as mkdir13, readFile as readFile20, rm as rm6, writeFile as writeFile14 } from "node:fs/promises";
546832
547230
  import { basename as basename25, dirname as dirname27, join as join53 } from "node:path";
546833
547231
  function resolveDreamTarget(spec) {
546834
547232
  const fileName = basename25(spec);
@@ -546904,7 +547302,7 @@ function buildTargetInstruction(target2) {
546904
547302
  }
546905
547303
  async function readExistingTarget(target2) {
546906
547304
  try {
546907
- return await readFile21(target2.path, "utf-8");
547305
+ return await readFile20(target2.path, "utf-8");
546908
547306
  } catch {
546909
547307
  return null;
546910
547308
  }
@@ -546932,7 +547330,7 @@ async function syncTargetIntoMemory(agentId, target2, content) {
546932
547330
  }
546933
547331
  const absPath = join53(memoryDir, relPath);
546934
547332
  await mkdir13(dirname27(absPath), { recursive: true });
546935
- await writeFile15(absPath, addManagedFrontmatter(content, target2.kind), "utf-8");
547333
+ await writeFile14(absPath, addManagedFrontmatter(content, target2.kind), "utf-8");
546936
547334
  try {
546937
547335
  const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
546938
547336
  const syncMode = getBackend2().capabilities.localMemfs ? "local" : "remote";
@@ -546949,7 +547347,7 @@ async function syncTargetIntoMemory(agentId, target2, content) {
546949
547347
  });
546950
547348
  return { synced: result.committed };
546951
547349
  } catch (error54) {
546952
- await rm5(absPath, { force: true });
547350
+ await rm6(absPath, { force: true });
546953
547351
  throw error54;
546954
547352
  }
546955
547353
  }
@@ -546965,7 +547363,7 @@ function readTargetFromMemory(agentId, target2) {
546965
547363
  }
546966
547364
  async function writeTarget(target2, content) {
546967
547365
  await mkdir13(dirname27(target2.path), { recursive: true });
546968
- await writeFile15(target2.path, content, "utf-8");
547366
+ await writeFile14(target2.path, content, "utf-8");
546969
547367
  }
546970
547368
 
546971
547369
  // src/cli/subcommands/dream.ts
@@ -548860,7 +549258,7 @@ async function runMemorySubcommand(argv) {
548860
549258
  init_backend2();
548861
549259
  init_message_search();
548862
549260
  init_settings_manager();
548863
- import { writeFile as writeFile16 } from "node:fs/promises";
549261
+ import { writeFile as writeFile15 } from "node:fs/promises";
548864
549262
  import { resolve as resolve31 } from "node:path";
548865
549263
  import { parseArgs as parseArgs12 } from "node:util";
548866
549264
  function printUsage9() {
@@ -549205,7 +549603,7 @@ async function runMessagesSubcommand(argv, deps = {}) {
549205
549603
  `).trim();
549206
549604
  if (outputPathRaw && typeof outputPathRaw === "string") {
549207
549605
  const outputPath = resolve31(process.cwd(), outputPathRaw);
549208
- await writeFile16(outputPath, `${transcript}
549606
+ await writeFile15(outputPath, `${transcript}
549209
549607
  `, "utf-8");
549210
549608
  console.log(JSON.stringify({
549211
549609
  conversation_id: conversationId,
@@ -554966,4 +555364,4 @@ Error during initialization: ${message}`);
554966
555364
  }
554967
555365
  main2();
554968
555366
 
554969
- //# debugId=8218A0B8DF5E5AFE64756E2164756E21
555367
+ //# debugId=8DBFF6903CD7B1D064756E2164756E21