fix: add image response support

Convert Google's inlineData format to Anthropic's image format:
- response-converter.js: Handle inlineData in non-streaming responses
- sse-parser.js: Parse inlineData for thinking models
- sse-streamer.js: Stream inlineData as image content blocks

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
liuwuyu118
2026-01-13 11:17:17 +08:00
parent 08b332b694
commit 860c0d6c2d
3 changed files with 49 additions and 1 deletions

View File

@@ -89,6 +89,11 @@ export async function parseThinkingSSEResponse(response, originalModel) {
if (!part.text) continue;
flushThinking();
accumulatedText += part.text;
} else if (part.inlineData) {
// Handle image content
flushThinking();
flushText();
finalParts.push(part);
}
}
} catch (e) {
@@ -105,7 +110,7 @@ export async function parseThinkingSSEResponse(response, originalModel) {
usageMetadata
};
const partTypes = finalParts.map(p => p.thought ? 'thought' : (p.functionCall ? 'functionCall' : 'text'));
const partTypes = finalParts.map(p => p.thought ? 'thought' : (p.functionCall ? 'functionCall' : (p.inlineData ? 'inlineData' : 'text')));
logger.debug('[CloudCode] Response received (SSE), part types:', partTypes);
if (finalParts.some(p => p.thought)) {
const thinkingPart = finalParts.find(p => p.thought);

View File

@@ -209,6 +209,39 @@ export async function* streamSSEResponse(response, originalModel) {
partial_json: JSON.stringify(part.functionCall.args || {})
}
};
} else if (part.inlineData) {
// Handle image content from Google format
if (currentBlockType === 'thinking' && currentThinkingSignature) {
yield {
type: 'content_block_delta',
index: blockIndex,
delta: { type: 'signature_delta', signature: currentThinkingSignature }
};
currentThinkingSignature = '';
}
if (currentBlockType !== null) {
yield { type: 'content_block_stop', index: blockIndex };
blockIndex++;
}
currentBlockType = 'image';
// Emit image block as a complete block
yield {
type: 'content_block_start',
index: blockIndex,
content_block: {
type: 'image',
source: {
type: 'base64',
media_type: part.inlineData.mimeType,
data: part.inlineData.data
}
}
};
yield { type: 'content_block_stop', index: blockIndex };
blockIndex++;
currentBlockType = null;
}
}