From 74d9fb6741b16ad403cb7723469f3085e3eab38d Mon Sep 17 00:00:00 2001 From: lumen claw Date: Mon, 9 Mar 2026 05:53:47 -0700 Subject: [PATCH] fix(acp): address review feedback on media attachment forwarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - runtime.ts: skip empty text block when input.text is empty; only emit type: "image" blocks for image/* MIME types — non-image attachments (documents, PDFs, audio, video) are silently skipped as the ACP protocol does not define a binary content block for them - dispatch-acp.ts: add 10 MB file size guard in resolveAcpAttachments to prevent unbounded memory allocation when large files are inbound Co-Authored-By: Claude Sonnet 4.6 --- extensions/acpx/src/runtime.ts | 11 +++++++++-- src/auto-reply/reply/dispatch-acp.ts | 9 +++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/extensions/acpx/src/runtime.ts b/extensions/acpx/src/runtime.ts index 4f7ff263a2a..9e711c530b3 100644 --- a/extensions/acpx/src/runtime.ts +++ b/extensions/acpx/src/runtime.ts @@ -311,9 +311,16 @@ export class AcpxRuntime implements AcpRuntime { }); if (input.attachments && input.attachments.length > 0) { - const blocks: unknown[] = [{ type: "text", text: input.text }]; + const blocks: unknown[] = []; + if (input.text) { + blocks.push({ type: "text", text: input.text }); + } for (const attachment of input.attachments) { - blocks.push({ type: "image", mimeType: attachment.mediaType, data: attachment.data }); + if (attachment.mediaType.startsWith("image/")) { + blocks.push({ type: "image", mimeType: attachment.mediaType, data: attachment.data }); + } + // Non-image attachments (documents, PDFs, audio, video) are not supported + // as binary content blocks in the ACP protocol — skip silently. } child.stdin.end(JSON.stringify(blocks)); } else { diff --git a/src/auto-reply/reply/dispatch-acp.ts b/src/auto-reply/reply/dispatch-acp.ts index 94bf9c83c4e..1f5b69beb6f 100644 --- a/src/auto-reply/reply/dispatch-acp.ts +++ b/src/auto-reply/reply/dispatch-acp.ts @@ -63,6 +63,8 @@ function resolveAcpPromptText(ctx: FinalizedMsgContext): string { ]).trim(); } +const ACP_ATTACHMENT_MAX_BYTES = 10 * 1024 * 1024; // 10 MB — consistent with Telegram mediaMaxMb default + async function resolveAcpAttachments(ctx: FinalizedMsgContext): Promise { const mediaAttachments = normalizeAttachments(ctx); const results: AcpTurnAttachment[] = []; @@ -72,6 +74,13 @@ async function resolveAcpAttachments(ctx: FinalizedMsgContext): Promise ACP_ATTACHMENT_MAX_BYTES) { + logVerbose( + `dispatch-acp: skipping attachment ${filePath} (${stat.size} bytes exceeds ${ACP_ATTACHMENT_MAX_BYTES} byte limit)`, + ); + continue; + } const buf = await fs.readFile(filePath); results.push({ mediaType: attachment.mime ?? "application/octet-stream", data: buf.toString("base64") }); } catch {