Skip to content

Commit 3a558a8

Browse files
author
remote-swe-app[bot]
committed
feat: Save images locally and provide path info in message
1 parent d10e68a commit 3a558a8

File tree

1 file changed

+77
-23
lines changed

1 file changed

+77
-23
lines changed

worker/src/agent/common/messages.ts

+77-23
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { PutCommand, UpdateCommand, paginateQuery, TransactWriteCommand } from '
33
import { getBytesFromKey } from './s3';
44
import sharp from 'sharp';
55
import { ddb, TableName } from './ddb';
6+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
7+
import path from 'path';
8+
import { fileTypeFromBuffer } from 'file-type';
69

710
// Maximum input token count before applying middle-out strategy
811
export const MAX_INPUT_TOKEN = 80_000;
@@ -199,29 +202,80 @@ const preProcessMessageContent = async (content: Message['content']) => {
199202
};
200203

201204
const imageCache: Record<string, Buffer> = {};
205+
// Image sequence number, reset when the process is killed
206+
let imageSeqNo = 0;
207+
208+
// Ensure the images directory exists
209+
const ensureImagesDirectory = () => {
210+
const imagesDir = path.join(process.env.HOME || '', '.remote_swe_workspace', 'images');
211+
if (!existsSync(imagesDir)) {
212+
mkdirSync(imagesDir, { recursive: true });
213+
}
214+
return imagesDir;
215+
};
216+
217+
// Save image to local filesystem and return the path
218+
const saveImageToLocalFs = async (imageBuffer: Buffer): Promise<string> => {
219+
const imagesDir = ensureImagesDirectory();
220+
221+
// Since we're converting to webp above, we know the extension
222+
const extension = 'webp';
223+
224+
// Create path with sequence number
225+
const fileName = `image${imageSeqNo}.${extension}`;
226+
const filePath = path.join(imagesDir, fileName);
227+
228+
// Write image to file
229+
writeFileSync(filePath, imageBuffer);
230+
231+
// Increment sequence number for next image
232+
imageSeqNo++;
233+
234+
// Return the path in the format specified in the issue
235+
return `.remote_swe_workspace/images/${fileName}`;
236+
};
237+
202238
const postProcessMessageContent = async (content: string) => {
203-
return await Promise.all(
204-
JSON.parse(content).map(async (c: any) => {
205-
if (!('image' in c)) return c;
206-
// embed images
207-
const s3Key = c.image.source.s3Key;
208-
let webp: Buffer;
209-
if (s3Key in imageCache) {
210-
webp = imageCache[s3Key];
211-
} else {
212-
const file = await getBytesFromKey(s3Key);
213-
// using sharp, convert file to webp
214-
webp = await sharp(file).webp({ lossless: false, quality: 80 }).toBuffer();
215-
imageCache[s3Key] = webp;
216-
}
217-
return {
218-
image: {
219-
format: 'webp',
220-
source: {
221-
bytes: webp,
222-
},
239+
const contentArray = JSON.parse(content);
240+
const resultArray = [];
241+
242+
for (const c of contentArray) {
243+
if (!('image' in c)) {
244+
resultArray.push(c);
245+
continue;
246+
}
247+
248+
// Process image
249+
const s3Key = c.image.source.s3Key;
250+
let imageBuffer: Buffer;
251+
252+
if (s3Key in imageCache) {
253+
imageBuffer = imageCache[s3Key];
254+
} else {
255+
const file = await getBytesFromKey(s3Key);
256+
// Convert file to webp
257+
imageBuffer = await sharp(file).webp({ lossless: false, quality: 80 }).toBuffer();
258+
imageCache[s3Key] = imageBuffer;
259+
}
260+
261+
// Add image to result
262+
resultArray.push({
263+
image: {
264+
format: 'webp',
265+
source: {
266+
bytes: imageBuffer,
223267
},
224-
};
225-
})
226-
);
268+
},
269+
});
270+
271+
// Save image to local filesystem
272+
const localPath = await saveImageToLocalFs(imageBuffer);
273+
274+
// Add a text block after the image with the path information
275+
resultArray.push({
276+
text: `the image is stored locally on ${localPath}`,
277+
});
278+
}
279+
280+
return resultArray;
227281
};

0 commit comments

Comments
 (0)