Files
cursor2api/test/unit-vision.mjs
小海 ed6181a5a9 fix: harden OpenAI multimodal compatibility and image handling
Tighten image path normalization, preserve multimodal request content across OpenAI-compatible endpoints, and fail fast on unsupported image_file inputs so clients get predictable behavior instead of silent degradation.

Made-with: Cursor
2026-03-17 15:03:39 +08:00

91 lines
2.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* test/unit-vision.mjs
*
* 单元测试Vision 拦截器仅处理 user 图片消息
* 运行方式node test/unit-vision.mjs
*/
let passed = 0;
let failed = 0;
async function test(name, fn) {
try {
await fn();
console.log(`${name}`);
passed++;
} catch (e) {
console.error(`${name}`);
console.error(` ${e.message}`);
failed++;
}
}
function assert(condition, msg) {
if (!condition) throw new Error(msg || 'Assertion failed');
}
async function applyVisionInterceptor(messages) {
for (const msg of messages) {
if (msg.role !== 'user') continue;
if (!Array.isArray(msg.content)) continue;
const newContent = [];
const imagesToAnalyze = [];
for (const block of msg.content) {
if (block.type === 'image') {
imagesToAnalyze.push(block);
} else {
newContent.push(block);
}
}
if (imagesToAnalyze.length > 0) {
newContent.push({
type: 'text',
text: `[System: The user attached ${imagesToAnalyze.length} image(s). Visual analysis/OCR extracted the following context:\nmock vision result]`,
});
msg.content = newContent;
}
}
}
console.log('\n📦 [1] Vision 角色范围\n');
await test('仅处理 user 消息中的图片', async () => {
const messages = [
{
role: 'assistant',
content: [
{ type: 'text', text: 'assistant says hi' },
{ type: 'image', source: { type: 'url', data: 'https://example.com/a.jpg' } },
],
},
{
role: 'user',
content: [
{ type: 'text', text: 'please inspect this image' },
{ type: 'image', source: { type: 'url', data: 'https://example.com/b.jpg' } },
],
},
];
await applyVisionInterceptor(messages);
assert(messages[0].content.some(block => block.type === 'image'), 'assistant image should remain untouched');
assert(messages[1].content.every(block => block.type !== 'image'), 'user images should be converted away');
assert(messages[1].content.some(block => block.type === 'text' && block.text.includes('mock vision result')), 'user message should receive vision text');
});
await test('忽略非数组内容的 user 消息', async () => {
const messages = [{ role: 'user', content: 'plain text only' }];
await applyVisionInterceptor(messages);
assert(messages[0].content === 'plain text only', 'plain text content should stay unchanged');
});
console.log('\n' + '═'.repeat(55));
console.log(` 结果: ${passed} 通过 / ${failed} 失败 / ${passed + failed} 总计`);
console.log('═'.repeat(55) + '\n');
if (failed > 0) process.exit(1);