Forked from vadimfedenko/analyze-images
Forked from vadimfedenko/analyze-images
scripts / image-lifetime-smoke.cjs
const assert = require('node:assert/strict');
const { Chat, ChatMessage } = require('@lmstudio/sdk');
const { inlineImage } = require('../dist/inlineImage');
const { fileDigest, hashBytes, IMAGE_LIMIT } = require('../dist/attachmentIdentity');
(async () => {
const bytes = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aWQAAAABJRU5ErkJggg==', 'base64');
const disconnectedClient = { files: {
prepareImageBase64() { throw Error('Disconnected upload client'); },
getLocalFileAbsolutePath() { throw Error('ENOENT: deleted user-files'); },
} };
const message = ChatMessage.from('Keep this image across restarts.');
message.appendFile(inlineImage(disconnectedClient, 'test.png', bytes));
const chat = Chat.empty(); chat.append(message);
// Serialize the real SDK message data as LM Studio does when saving a chat.
const disk = JSON.stringify(chat.getMessagesArray().map(message => ({role: message.getRole(), content: [
{type: 'text', text: message.getText()},
...message.getFiles(disconnectedClient).map(file => ({type: 'file', name: file.name, identifier: file.identifier, sizeBytes: file.sizeBytes, fileType: file.type})),
]})));
const restored = Chat.from({messages: JSON.parse(disk)});
const file = restored.getMessagesArray()[0].getFiles(disconnectedClient)[0];
assert.deepEqual(Buffer.from(file.identifier.slice(7), 'base64'), bytes);
assert.equal(await fileDigest(file, {remaining: bytes.length}), hashBytes(bytes));
assert.equal(await fileDigest(file, {remaining: bytes.length - 1}), undefined);
assert.throws(() => inlineImage(disconnectedClient, 'too-large.png', Buffer.alloc(IMAGE_LIMIT + 1)), /size limit/);
assert.throws(() => inlineImage(disconnectedClient, 'empty.png', Buffer.alloc(0)), /size limit/);
console.log('PASS: serialized inline images survive disconnected clients and missing user-files; byte identity and limits remain enforced.');
})().catch(error => {console.error(error); process.exitCode = 1;});
scripts / image-lifetime-smoke.cjs
const assert = require('node:assert/strict');
const { Chat, ChatMessage } = require('@lmstudio/sdk');
const { inlineImage } = require('../dist/inlineImage');
const { fileDigest, hashBytes, IMAGE_LIMIT } = require('../dist/attachmentIdentity');
(async () => {
const bytes = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aWQAAAABJRU5ErkJggg==', 'base64');
const disconnectedClient = { files: {
prepareImageBase64() { throw Error('Disconnected upload client'); },
getLocalFileAbsolutePath() { throw Error('ENOENT: deleted user-files'); },
} };
const message = ChatMessage.from('Keep this image across restarts.');
message.appendFile(inlineImage(disconnectedClient, 'test.png', bytes));
const chat = Chat.empty(); chat.append(message);
// Serialize the real SDK message data as LM Studio does when saving a chat.
const disk = JSON.stringify(chat.getMessagesArray().map(message => ({role: message.getRole(), content: [
{type: 'text', text: message.getText()},
...message.getFiles(disconnectedClient).map(file => ({type: 'file', name: file.name, identifier: file.identifier, sizeBytes: file.sizeBytes, fileType: file.type})),
]})));
const restored = Chat.from({messages: JSON.parse(disk)});
const file = restored.getMessagesArray()[0].getFiles(disconnectedClient)[0];
assert.deepEqual(Buffer.from(file.identifier.slice(7), 'base64'), bytes);
assert.equal(await fileDigest(file, {remaining: bytes.length}), hashBytes(bytes));
assert.equal(await fileDigest(file, {remaining: bytes.length - 1}), undefined);
assert.throws(() => inlineImage(disconnectedClient, 'too-large.png', Buffer.alloc(IMAGE_LIMIT + 1)), /size limit/);
assert.throws(() => inlineImage(disconnectedClient, 'empty.png', Buffer.alloc(0)), /size limit/);
console.log('PASS: serialized inline images survive disconnected clients and missing user-files; byte identity and limits remain enforced.');
})().catch(error => {console.error(error); process.exitCode = 1;});