Update file attachment messages to use centralized copy management

Replace hardcoded "provided below" strings with "included below" and migrate to centralized Copy enum system for consistent messaging across Claude, Gemini, Mistral, and OpenAI implementations.
This commit is contained in:
Andrew Beal 2026-03-22 23:11:31 +00:00
parent 5f63f7c744
commit 0d0f23ae7d
5 changed files with 41 additions and 37 deletions

View file

@ -74,7 +74,7 @@ export class Conversation {
name: functionResponse.name,
response: {
results: responseResults,
...(binaryResults.length > 0 && {message: "The contents of the files are provided below."})
...(binaryResults.length > 0 && {message: "The contents of the files are included below."})
}
}
};
@ -85,7 +85,7 @@ export class Conversation {
functionResponse: {
name: functionResponse.name,
response: {
message: "Files retrieved successfully. The contents of the files are provided below.",
message: "Files retrieved successfully. The contents of the files are included below.",
count: binaryResults.length
}
}

View file

@ -13,6 +13,7 @@ import { SettingsService } from '../../Services/SettingsService';
import { AIProvider } from '../../Enums/ApiProvider';
import { AbortService } from '../../Services/AbortService';
import { Exception } from '../../Helpers/Exception';
import { Copy, replaceCopy } from 'Enums/Copy';
describe('Claude', () => {
let claude: Claude;
@ -795,7 +796,7 @@ describe('Claude', () => {
expect(result[0].content.length).toBeGreaterThan(1);
// Should have filename text block from formatBinaryFiles
const filenameBlock = result[0].content.find((block: any) => block.type === 'text' && block.text === `The contents of the file 'test-image.png' are provided below.`);
const filenameBlock = result[0].content.find((block: any) => block.type === 'text' && block.text === replaceCopy(Copy.AttachedFile, ["test-image.png"]));
expect(filenameBlock).toBeDefined();
// Should have image content blocks from formatBinaryFiles
@ -828,7 +829,7 @@ describe('Claude', () => {
expect(result[0].content.length).toBeGreaterThan(1);
// Should have filename text block from formatBinaryFiles
const filenameBlock = result[0].content.find((block: any) => block.type === 'text' && block.text === `The contents of the file 'document.pdf' are provided below.`);
const filenameBlock = result[0].content.find((block: any) => block.type === 'text' && block.text === replaceCopy(Copy.AttachedFile, ["document.pdf"]));
expect(filenameBlock).toBeDefined();
// Should have document content blocks from formatBinaryFiles
@ -1241,7 +1242,7 @@ describe('Claude', () => {
expect(parsed).toHaveLength(2);
expect(parsed[0]).toEqual({
type: 'text',
text: `The contents of the file 'report.pdf' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["report.pdf"])
});
expect(parsed[1]).toEqual({
type: 'document',
@ -1269,7 +1270,7 @@ describe('Claude', () => {
expect(parsed).toHaveLength(2);
expect(parsed[0]).toEqual({
type: 'text',
text: `The contents of the file 'photo.jpg' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["photo.jpg"])
});
expect(parsed[1]).toEqual({
type: 'image',
@ -1410,7 +1411,7 @@ describe('Claude', () => {
expect(parsed).toHaveLength(6);
// PDF file
expect(parsed[0]).toEqual({ type: 'text', text: `The contents of the file 'doc.pdf' are provided below.` });
expect(parsed[0]).toEqual({ type: 'text', text: replaceCopy(Copy.AttachedFile, ["doc.pdf"]) });
expect(parsed[1]).toEqual({
type: 'document',
source: {
@ -1420,7 +1421,7 @@ describe('Claude', () => {
});
// JPEG image
expect(parsed[2]).toEqual({ type: 'text', text: `The contents of the file 'image.jpg' are provided below.` });
expect(parsed[2]).toEqual({ type: 'text', text: replaceCopy(Copy.AttachedFile, ["image.jpg"]) });
expect(parsed[3]).toEqual({
type: 'image',
source: {
@ -1430,7 +1431,7 @@ describe('Claude', () => {
});
// PNG image
expect(parsed[4]).toEqual({ type: 'text', text: `The contents of the file 'screenshot.png' are provided below.` });
expect(parsed[4]).toEqual({ type: 'text', text: replaceCopy(Copy.AttachedFile, ["screenshot.png"]) });
expect(parsed[5]).toEqual({
type: 'image',
source: {
@ -1477,14 +1478,14 @@ describe('Claude', () => {
expect(parsed).toHaveLength(5);
expect(parsed[0].type).toBe('text');
expect(parsed[0].text).toBe(`The contents of the file 'good.jpg' are provided below.`);
expect(parsed[0].text).toBe(replaceCopy(Copy.AttachedFile, ["good.jpg"]));
expect(parsed[1].type).toBe('image');
expect(parsed[2]).toEqual({
type: 'text',
text: 'Unsupported mime type \'image/bmp\': bad.bmp'
});
expect(parsed[3].type).toBe('text');
expect(parsed[3].text).toBe(`The contents of the file 'doc.pdf' are provided below.`);
expect(parsed[3].text).toBe(replaceCopy(Copy.AttachedFile, ["doc.pdf"]));
expect(parsed[4].type).toBe('document');
});
@ -1532,9 +1533,9 @@ describe('Claude', () => {
const parsed = JSON.parse(result);
expect(parsed).toHaveLength(4);
expect(parsed[0].text).toBe(`The contents of the file 'document.PDF' are provided below.`);
expect(parsed[0].text).toBe(replaceCopy(Copy.AttachedFile, ["document.PDF"]));
expect(parsed[1].type).toBe('document');
expect(parsed[2].text).toBe(`The contents of the file 'photo.JPG' are provided below.`);
expect(parsed[2].text).toBe(replaceCopy(Copy.AttachedFile, ["photo.JPG"]));
expect(parsed[3].type).toBe('image');
});
@ -1561,7 +1562,7 @@ describe('Claude', () => {
const result = claude.formatBinaryFiles([attachment as any]);
const parsed = JSON.parse(result);
expect(parsed[0].text).toBe(`The contents of the file 'report (final) v2.pdf' are provided below.`);
expect(parsed[0].text).toBe(replaceCopy(Copy.AttachedFile, ["report (final) v2.pdf"]));
});
it('should handle JPEG files with .jpeg extension', () => {

View file

@ -12,6 +12,7 @@ import { SettingsService } from '../../Services/SettingsService';
import { AIProvider } from '../../Enums/ApiProvider';
import { AbortService } from '../../Services/AbortService';
import { Exception } from '../../Helpers/Exception';
import { Copy, replaceCopy } from 'Enums/Copy';
describe('Gemini', () => {
let gemini: Gemini;
@ -1135,7 +1136,7 @@ describe('Gemini', () => {
expect(parsed).toHaveLength(2);
expect(parsed[0]).toEqual({
text: `The contents of the file 'report.pdf' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["report.pdf"])
});
expect(parsed[1]).toEqual({
fileData: {
@ -1161,7 +1162,7 @@ describe('Gemini', () => {
expect(parsed).toHaveLength(2);
expect(parsed[0]).toEqual({
text: `The contents of the file 'photo.jpg' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["photo.jpg"])
});
expect(parsed[1]).toEqual({
fileData: {
@ -1271,7 +1272,7 @@ describe('Gemini', () => {
expect(parsed).toHaveLength(6);
// PDF file
expect(parsed[0]).toEqual({ text: `The contents of the file 'doc.pdf' are provided below.` });
expect(parsed[0]).toEqual({ text: replaceCopy(Copy.AttachedFile, ["doc.pdf"]) });
expect(parsed[1]).toEqual({
fileData: {
mimeType: 'application/pdf',
@ -1280,7 +1281,7 @@ describe('Gemini', () => {
});
// JPEG image
expect(parsed[2]).toEqual({ text: `The contents of the file 'image.jpg' are provided below.` });
expect(parsed[2]).toEqual({ text: replaceCopy(Copy.AttachedFile, ["image.jpg"]) });
expect(parsed[3]).toEqual({
fileData: {
mimeType: 'image/jpeg',
@ -1289,7 +1290,7 @@ describe('Gemini', () => {
});
// PNG image
expect(parsed[4]).toEqual({ text: `The contents of the file 'screenshot.png' are provided below.` });
expect(parsed[4]).toEqual({ text: replaceCopy(Copy.AttachedFile, ["screenshot.png"]) });
expect(parsed[5]).toEqual({
fileData: {
mimeType: 'image/png',
@ -1334,12 +1335,12 @@ describe('Gemini', () => {
expect(parsed).toHaveLength(5);
expect(parsed[0]).toEqual({ text: `The contents of the file 'good.jpg' are provided below.` });
expect(parsed[0]).toEqual({ text: replaceCopy(Copy.AttachedFile, ["good.jpg"]) });
expect(parsed[1]).toHaveProperty('fileData');
expect(parsed[2]).toEqual({
text: 'Unsupported mime type \'image/bmp\': bad.bmp'
});
expect(parsed[3]).toEqual({ text: `The contents of the file 'doc.pdf' are provided below.` });
expect(parsed[3]).toEqual({ text: replaceCopy(Copy.AttachedFile, ["doc.pdf"]) });
expect(parsed[4]).toHaveProperty('fileData');
});
@ -1369,7 +1370,7 @@ describe('Gemini', () => {
const parsed = JSON.parse(result);
expect(parsed).toHaveLength(2); // Only successful upload
expect(parsed[0]).toEqual({ text: `The contents of the file 'success.pdf' are provided below.` });
expect(parsed[0]).toEqual({ text: replaceCopy(Copy.AttachedFile, ["success.pdf"]) });
expect(parsed[1]).toEqual({
fileData: {
mimeType: 'application/pdf',
@ -1399,7 +1400,7 @@ describe('Gemini', () => {
const result = gemini.formatBinaryFiles([attachment as any]);
const parsed = JSON.parse(result);
expect(parsed[0].text).toBe(`The contents of the file 'report (final) v2.pdf' are provided below.`);
expect(parsed[0].text).toBe(replaceCopy(Copy.AttachedFile, ["report (final) v2.pdf"]));
});
it('should handle JPEG files with .jpeg extension', () => {

View file

@ -13,6 +13,7 @@ import { AIProvider } from '../../Enums/ApiProvider';
import { AbortService } from '../../Services/AbortService';
import { Exception } from '../../Helpers/Exception';
import { AITool } from 'Enums/AITool';
import { Copy, replaceCopy } from 'Enums/Copy';
describe('Mistral', () => {
let mistral: Mistral;
@ -705,7 +706,7 @@ describe('Mistral', () => {
expect(parsed).toHaveLength(2);
expect(parsed[0]).toEqual({
type: 'text',
text: `The contents of the file 'report.pdf' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["report.pdf"])
});
expect(parsed[1]).toEqual({
type: 'document_url',
@ -730,7 +731,7 @@ describe('Mistral', () => {
expect(parsed).toHaveLength(2);
expect(parsed[0]).toEqual({
type: 'text',
text: `The contents of the file 'photo.jpg' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["photo.jpg"])
});
expect(parsed[1]).toEqual({
type: 'image_url',
@ -808,14 +809,14 @@ describe('Mistral', () => {
expect(parsed).toHaveLength(4);
// PDF file
expect(parsed[0]).toEqual({ type: 'text', text: `The contents of the file 'doc.pdf' are provided below.` });
expect(parsed[0]).toEqual({ type: 'text', text: replaceCopy(Copy.AttachedFile, ["doc.pdf"]) });
expect(parsed[1]).toEqual({
type: 'document_url',
document_url: 'https://signed-url.com/file_1'
});
// JPEG image
expect(parsed[2]).toEqual({ type: 'text', text: `The contents of the file 'image.jpg' are provided below.` });
expect(parsed[2]).toEqual({ type: 'text', text: replaceCopy(Copy.AttachedFile, ["image.jpg"]) });
expect(parsed[3]).toEqual({
type: 'image_url',
image_url: 'https://signed-url.com/file_2'

View file

@ -12,6 +12,7 @@ import { SettingsService } from '../../Services/SettingsService';
import { AIProvider } from '../../Enums/ApiProvider';
import { Exception } from '../../Helpers/Exception';
import { AbortService } from '../../Services/AbortService';
import { Copy, replaceCopy } from 'Enums/Copy';
describe('OpenAI', () => {
let openai: OpenAI;
@ -1016,7 +1017,7 @@ describe('OpenAI', () => {
expect(parsed[0].content).toHaveLength(2);
expect(parsed[0].content[0]).toEqual({
type: 'input_text',
text: `The contents of the file 'report.pdf' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["report.pdf"])
});
expect(parsed[0].content[1]).toEqual({
type: 'input_file',
@ -1043,7 +1044,7 @@ describe('OpenAI', () => {
expect(parsed[0].content).toHaveLength(2);
expect(parsed[0].content[0]).toEqual({
type: 'input_text',
text: `The contents of the file 'photo.jpg' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["photo.jpg"])
});
expect(parsed[0].content[1]).toEqual({
type: 'input_image',
@ -1069,7 +1070,7 @@ describe('OpenAI', () => {
expect(parsed[0].content).toHaveLength(2);
expect(parsed[0].content[0]).toEqual({
type: 'input_text',
text: `The contents of the file 'diagram.png' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["diagram.png"])
});
expect(parsed[0].content[1]).toEqual({
type: 'input_image',
@ -1095,7 +1096,7 @@ describe('OpenAI', () => {
expect(parsed[0].content).toHaveLength(2);
expect(parsed[0].content[0]).toEqual({
type: 'input_text',
text: `The contents of the file 'modern.webp' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["modern.webp"])
});
expect(parsed[0].content[1]).toEqual({
type: 'input_image',
@ -1184,7 +1185,7 @@ describe('OpenAI', () => {
expect(parsed[0].content[0]).toEqual({
type: 'input_text',
text: `The contents of the file 'doc.pdf' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["doc.pdf"])
});
expect(parsed[0].content[1]).toEqual({
type: 'input_file',
@ -1193,7 +1194,7 @@ describe('OpenAI', () => {
expect(parsed[0].content[2]).toEqual({
type: 'input_text',
text: `The contents of the file 'image.jpg' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["image.jpg"])
});
expect(parsed[0].content[3]).toEqual({
type: 'input_image',
@ -1202,7 +1203,7 @@ describe('OpenAI', () => {
expect(parsed[0].content[4]).toEqual({
type: 'input_text',
text: `The contents of the file 'screenshot.png' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["screenshot.png"])
});
expect(parsed[0].content[5]).toEqual({
type: 'input_image',
@ -1249,7 +1250,7 @@ describe('OpenAI', () => {
expect(parsed[0].content[0]).toEqual({
type: 'input_text',
text: `The contents of the file 'good.jpg' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["good.jpg"])
});
expect(parsed[0].content[1].type).toBe('input_image');
expect(parsed[0].content[2]).toEqual({
@ -1258,7 +1259,7 @@ describe('OpenAI', () => {
});
expect(parsed[0].content[3]).toEqual({
type: 'input_text',
text: `The contents of the file 'doc.pdf' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["doc.pdf"])
});
expect(parsed[0].content[4].type).toBe('input_file');
});
@ -1292,7 +1293,7 @@ describe('OpenAI', () => {
expect(parsed[0].content).toHaveLength(2); // Text + file reference
expect(parsed[0].content[0]).toEqual({
type: 'input_text',
text: `The contents of the file 'success.pdf' are provided below.`
text: replaceCopy(Copy.AttachedFile, ["success.pdf"])
});
expect(parsed[0].content[1]).toEqual({
type: 'input_file',