11using NUnit . Framework ;
2+ using OpenAI . Files ;
23using OpenAI . Responses ;
34using OpenAI . Tests . Utility ;
5+ using OpenAI . VectorStores ;
46using System ;
57using System . ClientModel ;
8+ using System . ClientModel . Primitives ;
69using System . Collections . Generic ;
710using System . Linq ;
811using System . Text ;
@@ -335,5 +338,72 @@ public async Task MCPToolWithDisallowedTools()
335338 Assert . That ( response . OutputItems . OfType < McpToolCallItem > ( ) . ToList ( ) , Has . Count . EqualTo ( 0 ) ) ;
336339 }
337340
341+ [ Test ]
342+ public async Task FileSearch ( )
343+ {
344+ OpenAIFileClient fileClient = GetTestClient < OpenAIFileClient > ( TestScenario . Files ) ;
345+ OpenAIFile testFile = await fileClient . UploadFileAsync (
346+ BinaryData . FromString ( """
347+ Travis's favorite food is pizza.
348+ """ ) ,
349+ "test_favorite_foods.txt" ,
350+ FileUploadPurpose . UserData ) ;
351+ Validate ( testFile ) ;
352+
353+ VectorStoreClient vscClient = GetTestClient < VectorStoreClient > ( TestScenario . VectorStores ) ;
354+ VectorStore vectorStore = await vscClient . CreateVectorStoreAsync (
355+ new VectorStoreCreationOptions ( )
356+ {
357+ FileIds = { testFile . Id } ,
358+ } ) ;
359+ Validate ( vectorStore ) ;
360+
361+ OpenAIResponseClient client = GetTestClient ( ) ;
362+
363+ OpenAIResponse response = await client . CreateResponseAsync (
364+ "Using the file search tool, what's Travis's favorite food?" ,
365+ new ResponseCreationOptions ( )
366+ {
367+ Tools =
368+ {
369+ ResponseTool . CreateFileSearchTool ( vectorStoreIds : [ vectorStore . Id ] ) ,
370+ }
371+ } ) ;
372+ Assert . That ( response . OutputItems ? . Count , Is . EqualTo ( 2 ) ) ;
373+ FileSearchCallResponseItem fileSearchCall = response . OutputItems [ 0 ] as FileSearchCallResponseItem ;
374+ Assert . That ( fileSearchCall , Is . Not . Null ) ;
375+ Assert . That ( fileSearchCall ? . Status , Is . EqualTo ( FileSearchCallStatus . Completed ) ) ;
376+ Assert . That ( fileSearchCall ? . Queries , Has . Count . GreaterThan ( 0 ) ) ;
377+ MessageResponseItem message = response . OutputItems [ 1 ] as MessageResponseItem ;
378+ Assert . That ( message , Is . Not . Null ) ;
379+ ResponseContentPart messageContentPart = message . Content ? . FirstOrDefault ( ) ;
380+ Assert . That ( messageContentPart , Is . Not . Null ) ;
381+ Assert . That ( messageContentPart . Text , Does . Contain ( "pizza" ) ) ;
382+ Assert . That ( messageContentPart . OutputTextAnnotations , Is . Not . Null . And . Not . Empty ) ;
383+ FileCitationMessageAnnotation annotation = messageContentPart . OutputTextAnnotations [ 0 ] as FileCitationMessageAnnotation ;
384+ Assert . That ( annotation . FileId , Is . EqualTo ( testFile . Id ) ) ;
385+ Assert . That ( annotation . Index , Is . GreaterThan ( 0 ) ) ;
386+
387+ await foreach ( ResponseItem inputItem in client . GetResponseInputItemsAsync ( response . Id ) )
388+ {
389+ Console . WriteLine ( ModelReaderWriter . Write ( inputItem ) . ToString ( ) ) ;
390+ }
391+ }
392+
393+ private List < string > FileIdsToDelete = [ ] ;
394+ private List < string > VectorStoreIdsToDelete = [ ] ;
395+
396+ private void Validate < T > ( T input ) where T : class
397+ {
398+ if ( input is OpenAIFile file )
399+ {
400+ FileIdsToDelete . Add ( file . Id ) ;
401+ }
402+ if ( input is VectorStore vectorStore )
403+ {
404+ VectorStoreIdsToDelete . Add ( vectorStore . Id ) ;
405+ }
406+ }
407+
338408 private static OpenAIResponseClient GetTestClient ( string overrideModel = null ) => GetTestClient < OpenAIResponseClient > ( TestScenario . Responses , overrideModel ) ;
339409}
0 commit comments