2024-08-06 18:52:58 -04:00
const { retrieveAndProcessFile } = require ( '~/server/services/Files/process' ) ;
const { processMessages } = require ( './manage' ) ;
jest . mock ( '~/server/services/Files/process' , ( ) => ( {
retrieveAndProcessFile : jest . fn ( ) ,
} ) ) ;
describe ( 'processMessages' , ( ) => {
let openai , client ;
beforeEach ( ( ) => {
openai = { } ;
client = {
processedFileIds : new Set ( ) ,
} ;
jest . clearAllMocks ( ) ;
retrieveAndProcessFile . mockReset ( ) ;
} ) ;
test ( 'handles normal case with single source' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value : 'This is a test ^1^ and another^1^' ,
annotations : [
{
type : 'file_citation' ,
start _index : 15 ,
end _index : 18 ,
file _citation : { file _id : 'file1' } ,
} ,
{
type : 'file_citation' ,
start _index : 30 ,
end _index : 33 ,
file _citation : { file _id : 'file1' } ,
} ,
] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
retrieveAndProcessFile . mockResolvedValue ( { filename : 'test.txt' } ) ;
const result = await processMessages ( { openai , client , messages } ) ;
expect ( result . text ) . toBe ( 'This is a test ^1^ and another^1^\n\n^1.^ test.txt' ) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
test ( 'handles multiple different sources' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value : 'This is a test ^1^ and another^2^' ,
annotations : [
{
type : 'file_citation' ,
start _index : 15 ,
end _index : 18 ,
file _citation : { file _id : 'file1' } ,
} ,
{
type : 'file_citation' ,
start _index : 30 ,
end _index : 33 ,
file _citation : { file _id : 'file2' } ,
} ,
] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
retrieveAndProcessFile
. mockResolvedValueOnce ( { filename : 'test1.txt' } )
. mockResolvedValueOnce ( { filename : 'test2.txt' } ) ;
const result = await processMessages ( { openai , client , messages } ) ;
expect ( result . text ) . toBe ( 'This is a test ^1^ and another^2^\n\n^1.^ test1.txt\n^2.^ test2.txt' ) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
test ( 'handles file retrieval failure' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value : 'This is a test ^1^' ,
annotations : [
{
type : 'file_citation' ,
start _index : 15 ,
end _index : 18 ,
file _citation : { file _id : 'file1' } ,
} ,
] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
retrieveAndProcessFile . mockRejectedValue ( new Error ( 'File not found' ) ) ;
const result = await processMessages ( { openai , client , messages } ) ;
expect ( result . text ) . toBe ( 'This is a test ^1^' ) ;
expect ( result . edited ) . toBe ( false ) ;
} ) ;
test ( 'handles citations without file ids' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value : 'This is a test ^1^' ,
annotations : [ { type : 'file_citation' , start _index : 15 , end _index : 18 } ] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
const result = await processMessages ( { openai , client , messages } ) ;
expect ( result . text ) . toBe ( 'This is a test ^1^' ) ;
expect ( result . edited ) . toBe ( false ) ;
} ) ;
test ( 'handles mixed valid and invalid citations' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value : 'This is a test ^1^ and ^2^ and ^3^' ,
annotations : [
{
type : 'file_citation' ,
start _index : 15 ,
end _index : 18 ,
file _citation : { file _id : 'file1' } ,
} ,
{ type : 'file_citation' , start _index : 23 , end _index : 26 } ,
{
type : 'file_citation' ,
start _index : 31 ,
end _index : 34 ,
file _citation : { file _id : 'file3' } ,
} ,
] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
retrieveAndProcessFile
. mockResolvedValueOnce ( { filename : 'test1.txt' } )
. mockResolvedValueOnce ( { filename : 'test3.txt' } ) ;
const result = await processMessages ( { openai , client , messages } ) ;
expect ( result . text ) . toBe (
'This is a test ^1^ and ^2^ and ^2^\n\n^1.^ test1.txt\n^2.^ test3.txt' ,
) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
test ( 'handles adjacent identical citations' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value : 'This is a test ^1^^1^ and ^1^ ^1^' ,
annotations : [
{
type : 'file_citation' ,
start _index : 15 ,
end _index : 18 ,
file _citation : { file _id : 'file1' } ,
} ,
{
type : 'file_citation' ,
start _index : 18 ,
end _index : 21 ,
file _citation : { file _id : 'file1' } ,
} ,
{
type : 'file_citation' ,
start _index : 26 ,
end _index : 29 ,
file _citation : { file _id : 'file1' } ,
} ,
{
type : 'file_citation' ,
start _index : 30 ,
end _index : 33 ,
file _citation : { file _id : 'file1' } ,
} ,
] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
retrieveAndProcessFile . mockResolvedValue ( { filename : 'test.txt' } ) ;
const result = await processMessages ( { openai , client , messages } ) ;
expect ( result . text ) . toBe ( 'This is a test ^1^ and ^1^\n\n^1.^ test.txt' ) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
test ( 'handles real data with multiple adjacent citations' , async ( ) => {
const messages = [
{
id : 'msg_XXXXXXXXXXXXXXXXXXXX' ,
object : 'thread.message' ,
created _at : 1722980324 ,
assistant _id : 'asst_XXXXXXXXXXXXXXXXXXXX' ,
thread _id : 'thread_XXXXXXXXXXXXXXXXXXXX' ,
run _id : 'run_XXXXXXXXXXXXXXXXXXXX' ,
status : 'completed' ,
incomplete _details : null ,
incomplete _at : null ,
completed _at : 1722980331 ,
role : 'assistant' ,
content : [
{
type : 'text' ,
text : {
value :
2025-12-15 17:55:25 -05:00
"The text you have uploaded is from the book \"Harry Potter and the Philosopher's Stone\" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:\n\n1. **Discovery and Invitation to Hogwarts**: Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry【11:2†source】【11:4†source】.\n\n2. **Shopping for Supplies**: Hagrid takes Harry to Diagon Alley to buy his school supplies, including his wand from Ollivander's【11:9†source】【11:14†source】.\n\n3. **Introduction to Hogwarts**: Harry is introduced to Hogwarts, the magical school where he will learn about magic and discover more about his own background【11:12†source】【11:18†source】.\n\n4. **Meeting Friends and Enemies**: At Hogwarts, Harry makes friends like Ron Weasley and Hermione Granger, and enemies like Draco Malfoy【11:16†source】.\n\n5. **Uncovering the Mystery**: Harry, along with Ron and Hermione, uncovers the mystery of the Philosopher's Stone and its connection to the dark wizard Voldemort【11:1†source】【11:10†source】【11:7†source】.\n\nThese points highlight Harry's initial experiences in the magical world and set the stage for his adventures at Hogwarts." ,
2024-08-06 18:52:58 -04:00
annotations : [
{
type : 'file_citation' ,
text : '【11:2†source】' ,
start _index : 420 ,
end _index : 433 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:4†source】' ,
start _index : 433 ,
end _index : 446 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:9†source】' ,
start _index : 578 ,
end _index : 591 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:14†source】' ,
start _index : 591 ,
end _index : 605 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:12†source】' ,
start _index : 767 ,
end _index : 781 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:18†source】' ,
start _index : 781 ,
end _index : 795 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:16†source】' ,
start _index : 935 ,
end _index : 949 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:1†source】' ,
start _index : 1114 ,
end _index : 1127 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:10†source】' ,
start _index : 1127 ,
end _index : 1141 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:7†source】' ,
start _index : 1141 ,
end _index : 1154 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
] ,
} ,
} ,
] ,
attachments : [ ] ,
metadata : { } ,
files : [
{
object : 'file' ,
id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
purpose : 'assistants' ,
filename : 'hp1.txt' ,
bytes : 439742 ,
created _at : 1722962139 ,
status : 'processed' ,
status _details : null ,
type : 'text/plain' ,
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
filepath :
'https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-XXXXXXXXXXXXXXXXXXXX/hp1.txt' ,
usage : 1 ,
user : 'XXXXXXXXXXXXXXXXXXXX' ,
context : 'assistants' ,
source : 'openai' ,
model : 'gpt-4o' ,
} ,
] ,
} ,
] ;
retrieveAndProcessFile . mockResolvedValue ( { filename : 'hp1.txt' } ) ;
const result = await processMessages ( {
openai : { } ,
client : { processedFileIds : new Set ( ) } ,
messages ,
} ) ;
const expectedText = ` The text you have uploaded is from the book "Harry Potter and the Philosopher's Stone" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:
1. * * Discovery and Invitation to Hogwarts * * : Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry ^ 1 ^ .
2. * * Shopping for Supplies * * : Hagrid takes Harry to Diagon Alley to buy his school supplies , including his wand from Ollivander ' s ^ 1 ^ .
3. * * Introduction to Hogwarts * * : Harry is introduced to Hogwarts , the magical school where he will learn about magic and discover more about his own background ^ 1 ^ .
4. * * Meeting Friends and Enemies * * : At Hogwarts , Harry makes friends like Ron Weasley and Hermione Granger , and enemies like Draco Malfoy ^ 1 ^ .
5. * * Uncovering the Mystery * * : Harry , along with Ron and Hermione , uncovers the mystery of the Philosopher ' s Stone and its connection to the dark wizard Voldemort ^ 1 ^ .
These points highlight Harry ' s initial experiences in the magical world and set the stage for his adventures at Hogwarts .
^ 1. ^ hp1 . txt ` ;
expect ( result . text ) . toBe ( expectedText ) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
test ( 'handles real data with multiple adjacent citations with multiple sources' , async ( ) => {
const messages = [
{
id : 'msg_XXXXXXXXXXXXXXXXXXXX' ,
object : 'thread.message' ,
created _at : 1722980324 ,
assistant _id : 'asst_XXXXXXXXXXXXXXXXXXXX' ,
thread _id : 'thread_XXXXXXXXXXXXXXXXXXXX' ,
run _id : 'run_XXXXXXXXXXXXXXXXXXXX' ,
status : 'completed' ,
incomplete _details : null ,
incomplete _at : null ,
completed _at : 1722980331 ,
role : 'assistant' ,
content : [
{
type : 'text' ,
text : {
value :
2025-12-15 17:55:25 -05:00
"The text you have uploaded is from the book \"Harry Potter and the Philosopher's Stone\" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:\n\n1. **Discovery and Invitation to Hogwarts**: Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry【11:2†source】【11:4†source】.\n\n2. **Shopping for Supplies**: Hagrid takes Harry to Diagon Alley to buy his school supplies, including his wand from Ollivander's【11:9†source】【11:14†source】.\n\n3. **Introduction to Hogwarts**: Harry is introduced to Hogwarts, the magical school where he will learn about magic and discover more about his own background【11:12†source】【11:18†source】.\n\n4. **Meeting Friends and Enemies**: At Hogwarts, Harry makes friends like Ron Weasley and Hermione Granger, and enemies like Draco Malfoy【11:16†source】.\n\n5. **Uncovering the Mystery**: Harry, along with Ron and Hermione, uncovers the mystery of the Philosopher's Stone and its connection to the dark wizard Voldemort【11:1†source】【11:10†source】【11:7†source】.\n\nThese points highlight Harry's initial experiences in the magical world and set the stage for his adventures at Hogwarts." ,
2024-08-06 18:52:58 -04:00
annotations : [
{
type : 'file_citation' ,
text : '【11:2†source】' ,
start _index : 420 ,
end _index : 433 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:4†source】' ,
start _index : 433 ,
end _index : 446 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:9†source】' ,
start _index : 578 ,
end _index : 591 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:14†source】' ,
start _index : 591 ,
end _index : 605 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:12†source】' ,
start _index : 767 ,
end _index : 781 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:18†source】' ,
start _index : 781 ,
end _index : 795 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:16†source】' ,
start _index : 935 ,
end _index : 949 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:1†source】' ,
start _index : 1114 ,
end _index : 1127 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:10†source】' ,
start _index : 1127 ,
end _index : 1141 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_citation' ,
text : '【11:7†source】' ,
start _index : 1141 ,
end _index : 1154 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
] ,
} ,
} ,
] ,
attachments : [ ] ,
metadata : { } ,
files : [
{
object : 'file' ,
id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
purpose : 'assistants' ,
filename : 'hp1.txt' ,
bytes : 439742 ,
created _at : 1722962139 ,
status : 'processed' ,
status _details : null ,
type : 'text/plain' ,
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
filepath :
'https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-XXXXXXXXXXXXXXXXXXXX/hp1.txt' ,
usage : 1 ,
user : 'XXXXXXXXXXXXXXXXXXXX' ,
context : 'assistants' ,
source : 'openai' ,
model : 'gpt-4o' ,
} ,
] ,
} ,
] ;
retrieveAndProcessFile . mockResolvedValue ( { filename : 'hp1.txt' } ) ;
const result = await processMessages ( {
openai : { } ,
client : { processedFileIds : new Set ( ) } ,
messages ,
} ) ;
const expectedText = ` The text you have uploaded is from the book "Harry Potter and the Philosopher's Stone" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:
1. * * Discovery and Invitation to Hogwarts * * : Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry ^ 1 ^ .
2. * * Shopping for Supplies * * : Hagrid takes Harry to Diagon Alley to buy his school supplies , including his wand from Ollivander ' s ^ 1 ^ .
3. * * Introduction to Hogwarts * * : Harry is introduced to Hogwarts , the magical school where he will learn about magic and discover more about his own background ^ 1 ^ .
4. * * Meeting Friends and Enemies * * : At Hogwarts , Harry makes friends like Ron Weasley and Hermione Granger , and enemies like Draco Malfoy ^ 1 ^ .
5. * * Uncovering the Mystery * * : Harry , along with Ron and Hermione , uncovers the mystery of the Philosopher ' s Stone and its connection to the dark wizard Voldemort ^ 1 ^ .
These points highlight Harry ' s initial experiences in the magical world and set the stage for his adventures at Hogwarts .
^ 1. ^ hp1 . txt ` ;
expect ( result . text ) . toBe ( expectedText ) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
test ( 'handles edge case with pre-existing citation-like text' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value :
2025-12-15 17:55:25 -05:00
"This is a test ^1^ with pre-existing citation-like text. Here's a real citation【11:2†source】." ,
2024-08-06 18:52:58 -04:00
annotations : [
{
type : 'file_citation' ,
text : '【11:2†source】' ,
start _index : 79 ,
end _index : 92 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
retrieveAndProcessFile . mockResolvedValue ( { filename : 'test.txt' } ) ;
const result = await processMessages ( {
openai : { } ,
client : { processedFileIds : new Set ( ) } ,
messages ,
} ) ;
const expectedText =
2025-12-15 17:55:25 -05:00
"This is a test ^1^ with pre-existing citation-like text. Here's a real citation^1^.\n\n^1.^ test.txt" ;
2024-08-06 18:52:58 -04:00
expect ( result . text ) . toBe ( expectedText ) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
test ( 'handles FILE_PATH annotation type' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value : 'Here is a file path: [file_path]' ,
annotations : [
{
type : 'file_path' ,
text : '[file_path]' ,
start _index : 21 ,
end _index : 32 ,
file _path : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
retrieveAndProcessFile . mockResolvedValue ( {
filename : 'test.txt' ,
filepath : '/path/to/test.txt' ,
} ) ;
const result = await processMessages ( {
openai : { } ,
client : { processedFileIds : new Set ( ) } ,
messages ,
} ) ;
const expectedText = 'Here is a file path: /path/to/test.txt' ;
expect ( result . text ) . toBe ( expectedText ) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
test ( 'handles FILE_CITATION annotation type' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value : 'Here is a citation: [citation]' ,
annotations : [
{
type : 'file_citation' ,
text : '[citation]' ,
start _index : 20 ,
end _index : 30 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
retrieveAndProcessFile . mockResolvedValue ( { filename : 'test.txt' } ) ;
const result = await processMessages ( {
openai : { } ,
client : { processedFileIds : new Set ( ) } ,
messages ,
} ) ;
const expectedText = 'Here is a citation: ^1^\n\n^1.^ test.txt' ;
expect ( result . text ) . toBe ( expectedText ) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
test ( 'handles multiple annotation types in a single message' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value :
'File path: [file_path]. Citation: [citation1]. Another citation: [citation2].' ,
annotations : [
{
type : 'file_path' ,
text : '[file_path]' ,
start _index : 11 ,
end _index : 22 ,
file _path : {
file _id : 'file-XXXXXXXXXXXXXXXX1' ,
} ,
} ,
{
type : 'file_citation' ,
text : '[citation1]' ,
start _index : 34 ,
end _index : 45 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXX2' ,
} ,
} ,
{
type : 'file_citation' ,
text : '[citation2]' ,
start _index : 65 ,
end _index : 76 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXX3' ,
} ,
} ,
] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
retrieveAndProcessFile . mockResolvedValueOnce ( {
filename : 'file1.txt' ,
filepath : '/path/to/file1.txt' ,
} ) ;
retrieveAndProcessFile . mockResolvedValueOnce ( { filename : 'file2.txt' } ) ;
retrieveAndProcessFile . mockResolvedValueOnce ( { filename : 'file3.txt' } ) ;
const result = await processMessages ( {
openai : { } ,
client : { processedFileIds : new Set ( ) } ,
messages ,
} ) ;
const expectedText =
'File path: /path/to/file1.txt. Citation: ^1^. Another citation: ^2^.\n\n^1.^ file2.txt\n^2.^ file3.txt' ;
expect ( result . text ) . toBe ( expectedText ) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
test ( 'handles annotation processing failure' , async ( ) => {
const messages = [
{
content : [
{
type : 'text' ,
text : {
value : 'This citation will fail: [citation]' ,
annotations : [
{
type : 'file_citation' ,
text : '[citation]' ,
start _index : 25 ,
end _index : 35 ,
file _citation : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
] ,
} ,
} ,
] ,
created _at : 1 ,
} ,
] ;
retrieveAndProcessFile . mockRejectedValue ( new Error ( 'File not found' ) ) ;
const result = await processMessages ( {
openai : { } ,
client : { processedFileIds : new Set ( ) } ,
messages ,
} ) ;
const expectedText = 'This citation will fail: [citation]' ;
expect ( result . text ) . toBe ( expectedText ) ;
expect ( result . edited ) . toBe ( false ) ;
} ) ;
test ( 'handles multiple FILE_PATH annotations with sandbox links' , async ( ) => {
const messages = [
{
id : 'msg_XXXXXXXXXXXXXXXXXXXX' ,
object : 'thread.message' ,
created _at : 1722983745 ,
assistant _id : 'asst_XXXXXXXXXXXXXXXXXXXX' ,
thread _id : 'thread_XXXXXXXXXXXXXXXXXXXX' ,
run _id : 'run_XXXXXXXXXXXXXXXXXXXX' ,
status : 'completed' ,
incomplete _details : null ,
incomplete _at : null ,
completed _at : 1722983747 ,
role : 'assistant' ,
content : [
{
type : 'text' ,
text : {
value :
'I have generated three dummy CSV files for you. You can download them using the links below:\n\n1. [Download Dummy Data 1](sandbox:/mnt/data/dummy_data1.csv)\n2. [Download Dummy Data 2](sandbox:/mnt/data/dummy_data2.csv)\n3. [Download Dummy Data 3](sandbox:/mnt/data/dummy_data3.csv)' ,
annotations : [
{
type : 'file_path' ,
text : 'sandbox:/mnt/data/dummy_data1.csv' ,
start _index : 121 ,
end _index : 154 ,
file _path : {
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
} ,
} ,
{
type : 'file_path' ,
text : 'sandbox:/mnt/data/dummy_data2.csv' ,
start _index : 183 ,
end _index : 216 ,
file _path : {
file _id : 'file-YYYYYYYYYYYYYYYYYYYY' ,
} ,
} ,
{
type : 'file_path' ,
text : 'sandbox:/mnt/data/dummy_data3.csv' ,
start _index : 245 ,
end _index : 278 ,
file _path : {
file _id : 'file-ZZZZZZZZZZZZZZZZZZZZ' ,
} ,
} ,
] ,
} ,
} ,
] ,
attachments : [
{
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
tools : [
{
type : 'code_interpreter' ,
} ,
] ,
} ,
{
file _id : 'file-YYYYYYYYYYYYYYYYYYYY' ,
tools : [
{
type : 'code_interpreter' ,
} ,
] ,
} ,
{
file _id : 'file-ZZZZZZZZZZZZZZZZZZZZ' ,
tools : [
{
type : 'code_interpreter' ,
} ,
] ,
} ,
] ,
metadata : { } ,
files : [
{
object : 'file' ,
id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
purpose : 'assistants_output' ,
filename : 'dummy_data1.csv' ,
bytes : 1925 ,
created _at : 1722983746 ,
status : 'processed' ,
status _details : null ,
type : 'text/csv' ,
file _id : 'file-XXXXXXXXXXXXXXXXXXXX' ,
filepath :
'https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-XXXXXXXXXXXXXXXXXXXX/dummy_data1.csv' ,
usage : 1 ,
user : 'XXXXXXXXXXXXXXXXXXXX' ,
context : 'assistants_output' ,
source : 'openai' ,
model : 'gpt-4o-mini' ,
} ,
{
object : 'file' ,
id : 'file-YYYYYYYYYYYYYYYYYYYY' ,
purpose : 'assistants_output' ,
filename : 'dummy_data2.csv' ,
bytes : 4221 ,
created _at : 1722983746 ,
status : 'processed' ,
status _details : null ,
type : 'text/csv' ,
file _id : 'file-YYYYYYYYYYYYYYYYYYYY' ,
filepath :
'https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-YYYYYYYYYYYYYYYYYYYY/dummy_data2.csv' ,
usage : 1 ,
user : 'XXXXXXXXXXXXXXXXXXXX' ,
context : 'assistants_output' ,
source : 'openai' ,
model : 'gpt-4o-mini' ,
} ,
{
object : 'file' ,
id : 'file-ZZZZZZZZZZZZZZZZZZZZ' ,
purpose : 'assistants_output' ,
filename : 'dummy_data3.csv' ,
bytes : 3534 ,
created _at : 1722983747 ,
status : 'processed' ,
status _details : null ,
type : 'text/csv' ,
file _id : 'file-ZZZZZZZZZZZZZZZZZZZZ' ,
filepath :
'https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-ZZZZZZZZZZZZZZZZZZZZ/dummy_data3.csv' ,
usage : 1 ,
user : 'XXXXXXXXXXXXXXXXXXXX' ,
context : 'assistants_output' ,
source : 'openai' ,
model : 'gpt-4o-mini' ,
} ,
] ,
} ,
] ;
const mockClient = {
processedFileIds : new Set ( ) ,
} ;
// Mock the retrieveAndProcessFile function for each file
retrieveAndProcessFile . mockImplementation ( ( { file _id } ) => {
const fileMap = {
'file-XXXXXXXXXXXXXXXXXXXX' : {
filename : 'dummy_data1.csv' ,
filepath :
'https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-XXXXXXXXXXXXXXXXXXXX/dummy_data1.csv' ,
} ,
'file-YYYYYYYYYYYYYYYYYYYY' : {
filename : 'dummy_data2.csv' ,
filepath :
'https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-YYYYYYYYYYYYYYYYYYYY/dummy_data2.csv' ,
} ,
'file-ZZZZZZZZZZZZZZZZZZZZ' : {
filename : 'dummy_data3.csv' ,
filepath :
'https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-ZZZZZZZZZZZZZZZZZZZZ/dummy_data3.csv' ,
} ,
} ;
return Promise . resolve ( fileMap [ file _id ] ) ;
} ) ;
const result = await processMessages ( { openai : { } , client : mockClient , messages } ) ;
const expectedText =
'I have generated three dummy CSV files for you. You can download them using the links below:\n\n1. [Download Dummy Data 1](https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-XXXXXXXXXXXXXXXXXXXX/dummy_data1.csv)\n2. [Download Dummy Data 2](https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-YYYYYYYYYYYYYYYYYYYY/dummy_data2.csv)\n3. [Download Dummy Data 3](https://api.openai.com/v1/files/XXXXXXXXXXXXXXXXXXXX/file-ZZZZZZZZZZZZZZZZZZZZ/dummy_data3.csv)' ;
expect ( result . text ) . toBe ( expectedText ) ;
expect ( result . edited ) . toBe ( true ) ;
} ) ;
} ) ;