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:
@@ -89,6 +89,11 @@ export async function parseThinkingSSEResponse(response, originalModel) {
|
|||||||
if (!part.text) continue;
|
if (!part.text) continue;
|
||||||
flushThinking();
|
flushThinking();
|
||||||
accumulatedText += part.text;
|
accumulatedText += part.text;
|
||||||
|
} else if (part.inlineData) {
|
||||||
|
// Handle image content
|
||||||
|
flushThinking();
|
||||||
|
flushText();
|
||||||
|
finalParts.push(part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -105,7 +110,7 @@ export async function parseThinkingSSEResponse(response, originalModel) {
|
|||||||
usageMetadata
|
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);
|
logger.debug('[CloudCode] Response received (SSE), part types:', partTypes);
|
||||||
if (finalParts.some(p => p.thought)) {
|
if (finalParts.some(p => p.thought)) {
|
||||||
const thinkingPart = finalParts.find(p => p.thought);
|
const thinkingPart = finalParts.find(p => p.thought);
|
||||||
|
|||||||
@@ -209,6 +209,39 @@ export async function* streamSSEResponse(response, originalModel) {
|
|||||||
partial_json: JSON.stringify(part.functionCall.args || {})
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,16 @@ export function convertGoogleToAnthropic(googleResponse, model) {
|
|||||||
|
|
||||||
anthropicContent.push(toolUseBlock);
|
anthropicContent.push(toolUseBlock);
|
||||||
hasToolCalls = true;
|
hasToolCalls = true;
|
||||||
|
} else if (part.inlineData) {
|
||||||
|
// Handle image content from Google format
|
||||||
|
anthropicContent.push({
|
||||||
|
type: 'image',
|
||||||
|
source: {
|
||||||
|
type: 'base64',
|
||||||
|
media_type: part.inlineData.mimeType,
|
||||||
|
data: part.inlineData.data
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user