From 0d0f23ae7da6537ed5d74c6b436ed864e2fe0430 Mon Sep 17 00:00:00 2001 From: Andrew Beal Date: Sun, 22 Mar 2026 23:11:31 +0000 Subject: [PATCH] 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. --- Conversations/Conversation.ts | 4 ++-- __tests__/AIClasses/Claude.test.ts | 25 +++++++++++++------------ __tests__/AIClasses/Gemini.test.ts | 19 ++++++++++--------- __tests__/AIClasses/Mistral.test.ts | 9 +++++---- __tests__/AIClasses/OpenAI.test.ts | 21 +++++++++++---------- 5 files changed, 41 insertions(+), 37 deletions(-) diff --git a/Conversations/Conversation.ts b/Conversations/Conversation.ts index e49d661..f949a78 100644 --- a/Conversations/Conversation.ts +++ b/Conversations/Conversation.ts @@ -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 } } diff --git a/__tests__/AIClasses/Claude.test.ts b/__tests__/AIClasses/Claude.test.ts index d684dfa..ff602bf 100644 --- a/__tests__/AIClasses/Claude.test.ts +++ b/__tests__/AIClasses/Claude.test.ts @@ -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', () => { diff --git a/__tests__/AIClasses/Gemini.test.ts b/__tests__/AIClasses/Gemini.test.ts index 8033e30..d32e080 100644 --- a/__tests__/AIClasses/Gemini.test.ts +++ b/__tests__/AIClasses/Gemini.test.ts @@ -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', () => { diff --git a/__tests__/AIClasses/Mistral.test.ts b/__tests__/AIClasses/Mistral.test.ts index ba77cd9..7d35b8a 100644 --- a/__tests__/AIClasses/Mistral.test.ts +++ b/__tests__/AIClasses/Mistral.test.ts @@ -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' diff --git a/__tests__/AIClasses/OpenAI.test.ts b/__tests__/AIClasses/OpenAI.test.ts index 0085292..ff682c0 100644 --- a/__tests__/AIClasses/OpenAI.test.ts +++ b/__tests__/AIClasses/OpenAI.test.ts @@ -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',