fix(acp): address review feedback on media attachment forwarding

- 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 <noreply@anthropic.com>
This commit is contained in:
lumen claw 2026-03-09 05:53:47 -07:00
parent e57fd4bbb1
commit 74d9fb6741
2 changed files with 18 additions and 2 deletions

View File

@ -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 {

View File

@ -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<AcpTurnAttachment[]> {
const mediaAttachments = normalizeAttachments(ctx);
const results: AcpTurnAttachment[] = [];
@ -72,6 +74,13 @@ async function resolveAcpAttachments(ctx: FinalizedMsgContext): Promise<AcpTurnA
continue;
}
try {
const stat = await fs.stat(filePath);
if (stat.size > 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 {