fix: enable image attachments in chat messages for Claude API
Images were previously converted to markdown data URLs which Claude API
treats as plain text, not as actual images.
Changes:
- Add parseMessageWithAttachments() that returns {message, images[]}
- Pass images through the stack to session.prompt() as content blocks
- Filter null/empty attachments before parsing
- Strip data URL prefix if client sends it
This enables iOS and other clients to send images that Claude can actually see.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Peter Steinberger
parent
0279f09459
commit
c4e76eb635
@@ -13,7 +13,10 @@ import {
|
||||
isChatStopCommandText,
|
||||
resolveChatRunExpiresAtMs,
|
||||
} from "../chat-abort.js";
|
||||
import { buildMessageWithAttachments } from "../chat-attachments.js";
|
||||
import {
|
||||
type ChatImageContent,
|
||||
parseMessageWithAttachments,
|
||||
} from "../chat-attachments.js";
|
||||
import {
|
||||
ErrorCodes,
|
||||
errorShape,
|
||||
@@ -181,29 +184,34 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
};
|
||||
const stopCommand = isChatStopCommandText(p.message);
|
||||
const normalizedAttachments =
|
||||
p.attachments?.map((a) => ({
|
||||
type: typeof a?.type === "string" ? a.type : undefined,
|
||||
mimeType: typeof a?.mimeType === "string" ? a.mimeType : undefined,
|
||||
fileName: typeof a?.fileName === "string" ? a.fileName : undefined,
|
||||
content:
|
||||
typeof a?.content === "string"
|
||||
? a.content
|
||||
: ArrayBuffer.isView(a?.content)
|
||||
? Buffer.from(
|
||||
a.content.buffer,
|
||||
a.content.byteOffset,
|
||||
a.content.byteLength,
|
||||
).toString("base64")
|
||||
: undefined,
|
||||
})) ?? [];
|
||||
let messageWithAttachments = p.message;
|
||||
p.attachments
|
||||
?.map((a) => ({
|
||||
type: typeof a?.type === "string" ? a.type : undefined,
|
||||
mimeType: typeof a?.mimeType === "string" ? a.mimeType : undefined,
|
||||
fileName: typeof a?.fileName === "string" ? a.fileName : undefined,
|
||||
content:
|
||||
typeof a?.content === "string"
|
||||
? a.content
|
||||
: ArrayBuffer.isView(a?.content)
|
||||
? Buffer.from(
|
||||
a.content.buffer,
|
||||
a.content.byteOffset,
|
||||
a.content.byteLength,
|
||||
).toString("base64")
|
||||
: undefined,
|
||||
}))
|
||||
.filter((a) => a.content && a.mimeType) ?? [];
|
||||
let parsedMessage = p.message;
|
||||
let parsedImages: ChatImageContent[] = [];
|
||||
if (normalizedAttachments.length > 0) {
|
||||
try {
|
||||
messageWithAttachments = buildMessageWithAttachments(
|
||||
const parsed = parseMessageWithAttachments(
|
||||
p.message,
|
||||
normalizedAttachments,
|
||||
{ maxBytes: 5_000_000 },
|
||||
);
|
||||
parsedMessage = parsed.message;
|
||||
parsedImages = parsed.images;
|
||||
} catch (err) {
|
||||
respond(
|
||||
false,
|
||||
@@ -312,7 +320,8 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
|
||||
void agentCommand(
|
||||
{
|
||||
message: messageWithAttachments,
|
||||
message: parsedMessage,
|
||||
images: parsedImages.length > 0 ? parsedImages : undefined,
|
||||
sessionId,
|
||||
sessionKey: p.sessionKey,
|
||||
runId: clientRunId,
|
||||
|
||||
Reference in New Issue
Block a user