| |
| |
| |
| |
| |
| |
|
|
| let passed = 0; |
| let failed = 0; |
|
|
| function test(name, fn) { |
| try { |
| 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'); |
| } |
|
|
| class OpenAIRequestError extends Error { |
| constructor(message, status = 400, type = 'invalid_request_error', code = 'invalid_request') { |
| super(message); |
| this.name = 'OpenAIRequestError'; |
| this.status = status; |
| this.type = type; |
| this.code = code; |
| } |
| } |
|
|
| function unsupportedImageFileError(fileId) { |
| const suffix = fileId ? ` (file_id: ${fileId})` : ''; |
| return new OpenAIRequestError( |
| `Unsupported content part: image_file${suffix}. This proxy does not support OpenAI Files API image references. Please send the image as image_url, input_image, data URI, or a local file path instead.`, |
| 400, |
| 'invalid_request_error', |
| 'unsupported_content_part' |
| ); |
| } |
|
|
| function extractOpenAIContentBlocks(msg) { |
| if (msg.content === null || msg.content === undefined) return ''; |
| if (typeof msg.content === 'string') return msg.content; |
| if (Array.isArray(msg.content)) { |
| const blocks = []; |
| for (const p of msg.content) { |
| if (p.type === 'text' || p.type === 'input_text') { |
| if (p.text) blocks.push({ type: 'text', text: p.text }); |
| } else if (p.type === 'image_file' && p.image_file) { |
| throw unsupportedImageFileError(p.image_file.file_id); |
| } |
| } |
| return blocks.length > 0 ? blocks : ''; |
| } |
| return String(msg.content); |
| } |
|
|
| console.log('\n📦 [1] image_file 显式报错\n'); |
|
|
| test('image_file 应抛出 OpenAIRequestError', () => { |
| let thrown; |
| try { |
| extractOpenAIContentBlocks({ |
| role: 'user', |
| content: [ |
| { type: 'input_text', text: '请描述图片' }, |
| { type: 'image_file', image_file: { file_id: 'file_123' } }, |
| ], |
| }); |
| } catch (e) { |
| thrown = e; |
| } |
|
|
| assert(thrown instanceof OpenAIRequestError, 'should throw OpenAIRequestError'); |
| assert(thrown.message.includes('image_file'), 'message should mention image_file'); |
| assert(thrown.message.includes('file_123'), 'message should include file_id'); |
| assert(thrown.status === 400, 'status should be 400'); |
| assert(thrown.type === 'invalid_request_error', 'type should be invalid_request_error'); |
| assert(thrown.code === 'unsupported_content_part', 'code should be unsupported_content_part'); |
| }); |
|
|
| test('普通文本块仍可正常通过', () => { |
| const blocks = extractOpenAIContentBlocks({ |
| role: 'user', |
| content: [{ type: 'input_text', text: 'hello' }], |
| }); |
| assert(Array.isArray(blocks), 'blocks should be array'); |
| assert(blocks[0].text === 'hello', 'text block should remain intact'); |
| }); |
|
|
| console.log('\n' + '═'.repeat(55)); |
| console.log(` 结果: ${passed} 通过 / ${failed} 失败 / ${passed + failed} 总计`); |
| console.log('═'.repeat(55) + '\n'); |
|
|
| if (failed > 0) process.exit(1); |
|
|