diff --git a/sdk/ai/Azure.AI.Agents/assets.json b/sdk/ai/Azure.AI.Agents/assets.json index f9174b1c73a6..20a5b6937fb9 100644 --- a/sdk/ai/Azure.AI.Agents/assets.json +++ b/sdk/ai/Azure.AI.Agents/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/ai/Azure.AI.Agents", - "Tag": "net/ai/Azure.AI.Agents_40ad414f20" + "Tag": "net/ai/Azure.AI.Agents_34436e25a0" } diff --git a/sdk/ai/Azure.AI.Agents/samples/Sample8_FileSearch.md b/sdk/ai/Azure.AI.Agents/samples/Sample8_FileSearch.md new file mode 100644 index 000000000000..73b7bc36f257 --- /dev/null +++ b/sdk/ai/Azure.AI.Agents/samples/Sample8_FileSearch.md @@ -0,0 +1,160 @@ +# Sample file search with agent in Azure.AI.Agents. + +In this example we will create the local file, upload it to Azure and will use it in the newly created `VectorStore` for file search. + +1. First, we need to create agent client and read the environment variables, which will be used in the next steps. + +```C# Snippet:Sample_CreateAgentClient_FileSearch +var projectEndpoint = System.Environment.GetEnvironmentVariable("PROJECT_ENDPOINT"); +var modelDeploymentName = System.Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME"); +AgentsClient client = new(endpoint: new Uri(projectEndpoint), tokenProvider: new DefaultAzureCredential()); +OpenAIClient openAIClient = client.GetOpenAIClient(); +``` + +2. We will create a toy example file and upload it using OpenAI mechanism. + +Synchronous sample: +```C# Snippet:Sample_UploadFile_FileSearch_Sync +string filePath = "sample_file_for_upload.txt"; +System.IO.File.WriteAllText( + path: filePath, + contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); +OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); +OpenAIFile uploadedFile = fileClient.UploadFile(filePath: filePath, purpose: FileUploadPurpose.Assistants); +System.IO.File.Delete(filePath); +``` + +Asynchronous sample: +```C# Snippet:Sample_UploadFile_FileSearch_Async +string filePath = "sample_file_for_upload.txt"; +System.IO.File.WriteAllText( + path: filePath, + contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); +OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); +OpenAIFile uploadedFile = await fileClient.UploadFileAsync(filePath: filePath, purpose: FileUploadPurpose.Assistants); +System.IO.File.Delete(filePath); +``` + +3. Create the `VectorStore` and provide it with uploaded file ID. + +Synchronous sample: +```C# Snippet:Sample_CreateVectorStore_FileSearch_Sync +VectorStoreClient vctStoreClient = openAIClient.GetVectorStoreClient(); +VectorStoreCreationOptions vctOptions = new() +{ + Name = "MySampleStore", + FileIds = { uploadedFile.Id } +}; +VectorStore vectorStore = vctStoreClient.CreateVectorStore(options: vctOptions); +``` + +Asynchronous sample: +```C# Snippet:Sample_CreateVectorStore_FileSearch_Async +VectorStoreClient vctStoreClient = openAIClient.GetVectorStoreClient(); +VectorStoreCreationOptions vctOptions = new() +{ + Name = "MySampleStore", + FileIds = { uploadedFile.Id } +}; +VectorStore vectorStore = await vctStoreClient.CreateVectorStoreAsync( + new VectorStoreCreationOptions() +); +``` + +2. Now we can create an agent capable of using File search. + +Synchronous sample: +```C# Snippet:Sample_CreateAgent_FileSearch_Sync +PromptAgentDefinition agentDefinition = new(model: modelDeploymentName) +{ + Instructions = "You are a helpful agent that can help fetch data from files you know about.", + Tools = { + ResponseTool.CreateFileSearchTool(vectorStoreIds: [vectorStore.Id]), + } +}; +AgentVersion agentVersion = client.CreateAgentVersion( + agentName: "myAgent", + definition: agentDefinition, options: null); +``` + +Asynchronous sample: +```C# Snippet:Sample_CreateAgent_FileSearch_Async +PromptAgentDefinition agentDefinition = new(model: modelDeploymentName) +{ + Instructions = "You are a helpful agent that can help fetch data from files you know about.", + Tools = { + ResponseTool.CreateFileSearchTool(vectorStoreIds: [vectorStore.Id]), + } +}; +AgentVersion agentVersion = await client.CreateAgentVersionAsync( + agentName: "myAgent", + definition: agentDefinition, options: null); +``` + +3. In this example we will ask a question to the file contents. + +Synchronous sample: +```C# Snippet:Sample_CreateResponse_FileSearch_Sync +OpenAIResponseClient responseClient = openAIClient.GetOpenAIResponseClient(modelDeploymentName); +ResponseCreationOptions responseOptions = new(); +responseOptions.SetAgentReference(new AgentReference(name: agentVersion.Name)); + +ResponseItem request = ResponseItem.CreateUserMessageItem("The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); +OpenAIResponse response = responseClient.CreateResponse( + [request], + responseOptions); +``` + +Asynchronous sample: +```C# Snippet:Sample_CreateResponse_FileSearch_Async +OpenAIResponseClient responseClient = openAIClient.GetOpenAIResponseClient(modelDeploymentName); +ResponseCreationOptions responseOptions = new(); +responseOptions.SetAgentReference(new AgentReference(name: agentVersion.Name)); + +ResponseItem request = ResponseItem.CreateUserMessageItem("The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); +OpenAIResponse response = await responseClient.CreateResponseAsync( + [request], + responseOptions); +``` + +4. Wait for the response and throw an exception if the response contains the error. + +Synchronous sample: +```C# Snippet:Sample_WaitForResponse_FileSearch_Sync +List updateItems = [request]; +while (response.Status != ResponseStatus.Incomplete && response.Status != ResponseStatus.Failed && response.Status != ResponseStatus.Completed) +{ + Thread.Sleep(TimeSpan.FromMilliseconds(500)); + response = responseClient.GetResponse(responseId: response.Id); +} +Assert.That(response.Status, Is.EqualTo(ResponseStatus.Completed)); +Console.WriteLine(response.GetOutputText()); +``` + +Asynchronous sample: +```C# Snippet:Sample_WaitForResponse_FileSearch_Async +List updateItems = [request]; +while (response.Status != ResponseStatus.Incomplete && response.Status != ResponseStatus.Failed && response.Status != ResponseStatus.Completed) +{ + await Task.Delay(TimeSpan.FromMilliseconds(500)); + response = await responseClient.GetResponseAsync(responseId: response.Id); +} +Assert.That(response.Status, Is.EqualTo(ResponseStatus.Completed)); +Console.WriteLine(response.GetOutputText()); +``` + +5. Finally, delete all the resources, we have created in this sample. + +Synchronous sample: +```C# Snippet:Sample_Cleanup_FileSearch_Sync +client.DeleteAgentVersion(agentName: agentVersion.Name, agentVersion: agentVersion.Version); +vctStoreClient.DeleteVectorStore(vectorStoreId: vectorStore.Id); +fileClient.DeleteFile(uploadedFile.Id); +``` + +Asynchronous sample: +```C# Snippet:Sample_Cleanup_FileSearch_Async +await client.DeleteAgentVersionAsync(agentName: agentVersion.Name, agentVersion: agentVersion.Version); +await vctStoreClient.DeleteVectorStoreAsync(vectorStoreId: vectorStore.Id); +await fileClient.DeleteFileAsync(uploadedFile.Id); +``` diff --git a/sdk/ai/Azure.AI.Agents/tests/AgentsSmokeTests.cs b/sdk/ai/Azure.AI.Agents/tests/AgentsSmokeTests.cs index ad3aad0500f6..c3778d2e7b0f 100644 --- a/sdk/ai/Azure.AI.Agents/tests/AgentsSmokeTests.cs +++ b/sdk/ai/Azure.AI.Agents/tests/AgentsSmokeTests.cs @@ -209,4 +209,10 @@ public void ItemDeserializationTest() AgentResponseItem asAgentItem = ModelReaderWriter.Read(itemBytes); } + + [TearDown] + public override void Cleanup() + { + // Nothing here + } } diff --git a/sdk/ai/Azure.AI.Agents/tests/AgentsTestBase.cs b/sdk/ai/Azure.AI.Agents/tests/AgentsTestBase.cs index da3e2c8c5663..bbcb73f22131 100644 --- a/sdk/ai/Azure.AI.Agents/tests/AgentsTestBase.cs +++ b/sdk/ai/Azure.AI.Agents/tests/AgentsTestBase.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection.Metadata.Ecma335; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -14,10 +13,11 @@ using Azure.AI.Projects; using Azure.Identity; using Microsoft.ClientModel.TestFramework; +using Microsoft.Extensions.Primitives; using NUnit.Framework; using OpenAI; -using OpenAI.Files; using OpenAI.Responses; +using OpenAI.VectorStores; namespace Azure.AI.Agents.Tests; @@ -93,42 +93,6 @@ public enum ToolType {ToolType.FileSearch, "673457"}, }; #endregion - #region ToolHelper - /// - /// Get the AgentDefinition, containing tool of a certain type. - /// - /// - /// - protected AgentDefinition GetAgentToolDefinition(ToolType toolType) - { - ResponseTool tool = toolType switch - { - // To run the Code interpreter and file search sample, please upload the file using code below. - // This code cannot be run during tests as recordings are not properly handled by the file upload. - // Upload the file. - // string filePath = "sample_file_for_upload.txt"; - // System.IO.File.WriteAllText( - // path: filePath, - // contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); - // OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); - // OpenAIFile uploadedFile = fileClient.UploadFile(filePath: filePath, purpose: FileUploadPurpose.Assistants); - // Console.WriteLine(uploadedFile.id) - ToolType.CodeInterpreter => ResponseTool.CreateCodeInterpreterTool( - new CodeInterpreterToolContainer( - CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration( - fileIds: [TestEnvironment.OPENAI_FILE_ID] - ) - ) - ), - _ => throw new InvalidOperationException($"Unknown tool type {toolType}") - }; - return new PromptAgentDefinition(TestEnvironment.MODELDEPLOYMENTNAME) - { - Instructions = ToolInstructions[toolType], - Tools = { tool }, - }; - } - #endregion protected OpenAIClientOptions TestOpenAIClientOptions { get @@ -153,6 +117,7 @@ protected OpenAIClientOptions TestOpenAIClientOptions protected const string AGENT_NAME = "cs_e2e_tests_client"; protected const string AGENT_NAME2 = "cs_e2e_tests_client2"; + protected const string VECTOR_STORE = "cs_e2e_tests_vector_store"; protected const string STREAMING_CONSTRAINT = "The test framework does not support iteration of stream in Sync mode."; private readonly List _conversationIDs = []; private readonly List _memoryStoreIDs = []; @@ -288,53 +253,114 @@ protected void IgnoreSampleMayBe() Assert.Ignore("Samples represented as tests only for validation of compilation."); } } + + #region ToolHelper + private async Task GetVectorStore(OpenAIClient openAIClient) + { + VectorStoreClient vctStoreClient = openAIClient.GetVectorStoreClient(); + VectorStoreCreationOptions vctOptions = new() + { + Name = VECTOR_STORE, + FileIds = { TestEnvironment.OPENAI_FILE_ID } + }; + return await vctStoreClient.CreateVectorStoreAsync( + vctOptions + ); + } + /// + /// Get the AgentDefinition, containing tool of a certain type. + /// + /// + /// + protected async Task GetAgentToolDefinition(ToolType toolType, OpenAIClient oaiClient) + { + ResponseTool tool = toolType switch + { + // To run the Code interpreter and file search sample, please upload the file using code below. + // This code cannot be run during tests as recordings are not properly handled by the file upload. + // Upload the file. + // string filePath = "sample_file_for_upload.txt"; + // System.IO.File.WriteAllText( + // path: filePath, + // contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); + // OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); + // OpenAIFile uploadedFile = fileClient.UploadFile(filePath: filePath, purpose: FileUploadPurpose.Assistants); + // Console.WriteLine(uploadedFile.id) + ToolType.CodeInterpreter => ResponseTool.CreateCodeInterpreterTool( + new CodeInterpreterToolContainer( + CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration( + fileIds: [TestEnvironment.OPENAI_FILE_ID] + ) + ) + ), + ToolType.FileSearch => ResponseTool.CreateFileSearchTool(vectorStoreIds: [(await GetVectorStore(oaiClient)).Id]), + _ => throw new InvalidOperationException($"Unknown tool type {toolType}") + }; + return new PromptAgentDefinition(TestEnvironment.MODELDEPLOYMENTNAME) + { + Instructions = ToolInstructions[toolType], + Tools = { tool }, + }; + } + #endregion #region Cleanup [TearDown] - public void Cleanup() + public virtual void Cleanup() { - //if (Mode == RecordedTestMode.Playback) - // return; - //Uri connectionString = new(TestEnvironment.PROJECT_ENDPOINT); - //AgentsClientOptions opts = new(); - //AgentsClient client = new(endpoint: connectionString, tokenProvider: TestEnvironment.Credential, options: opts); - //// Remove conversations. - //if (_conversations is not null) - //{ - // foreach (string id in _conversationIDs) - // { - // try - // { - // _conversations.DeleteConversation(conversationId: id); - // } - // catch (RequestFailedException ex) - // { - // // Throw only if it is the error other then "Not found." - // if (ex.Status != 404) - // throw; - // } - // } - //} - //if (_stores != null) - //{ - // foreach (string id in _memoryStoreIDs) - // { - // try - // { - // _stores.DeleteMemoryStore(memoryStoreId: id); - // } - // catch (RequestFailedException ex) - // { - // // Throw only if it is the error other then "Not found." - // if (ex.Status != 404) - // throw; - // } - // } - //} - //// Remove Agents. - //foreach (AgentObject ag in client.GetAgents().Where((x) => !string.IsNullOrEmpty(x.Name) && x.Name.StartsWith(AGENT_NAME))) - //{ - // client.DeleteAgentVersion(agentName: ag.Name, agentVersion: "1"); - //} + if (Mode == RecordedTestMode.Playback) + return; + Uri connectionString = new(TestEnvironment.PROJECT_ENDPOINT); + AgentsClientOptions opts = new(); + AgentsClient client = new(endpoint: connectionString, tokenProvider: TestEnvironment.Credential, options: opts); + // Remove conversations. + if (_conversations is not null) + { + foreach (string id in _conversationIDs) + { + try + { + _conversations.DeleteConversation(conversationId: id); + } + catch (RequestFailedException ex) + { + // Throw only if it is the error other then "Not found." + if (ex.Status != 404) + throw; + } + } + } + if (_stores != null) + { + foreach (string name in _memoryStoreIDs) + { + try + { + _stores.DeleteMemoryStore(name: name); + } + catch (RequestFailedException ex) + { + // Throw only if it is the error other then "Not found." + if (ex.Status != 404) + throw; + } + } + } + // Remove Vector stores + OpenAIClient oaiClient = client.GetOpenAIClient(); + VectorStoreClient oaiVctStoreClient = oaiClient.GetVectorStoreClient(); + foreach (VectorStore vct in oaiVctStoreClient.GetVectorStores().Where(x => (x.Name ?? "").Equals(VECTOR_STORE))) + { + oaiVctStoreClient.DeleteVectorStore(vectorStoreId: vct.Id); + } + // Remove Agents. + foreach (AgentVersion ag in client.GetAgentVersions(agentName: AGENT_NAME)) + { + client.DeleteAgentVersion(agentName: ag.Name, agentVersion: ag.Version); + } + foreach (AgentVersion ag in client.GetAgentVersions(agentName: AGENT_NAME2)) + { + client.DeleteAgentVersion(agentName: ag.Name, agentVersion: ag.Version); + } } #endregion #region Debug Method diff --git a/sdk/ai/Azure.AI.Agents/tests/AgentsTests.cs b/sdk/ai/Azure.AI.Agents/tests/AgentsTests.cs index 9aedd388e095..25cc75e39f15 100644 --- a/sdk/ai/Azure.AI.Agents/tests/AgentsTests.cs +++ b/sdk/ai/Azure.AI.Agents/tests/AgentsTests.cs @@ -9,9 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.ClientModel.TestFramework; -using Microsoft.VisualBasic; using NUnit.Framework; -using NUnit.Framework.Legacy; using OpenAI; using OpenAI.Responses; @@ -588,15 +586,16 @@ public async Task TestMemorySearch(bool useConversation) [RecordedTest] [TestCase(ToolType.CodeInterpreter)] + [TestCase(ToolType.FileSearch)] public async Task TestTool(ToolType toolType) { AgentsClient client = GetTestClient(); + OpenAIClient openAIClient = client.GetOpenAIClient(TestOpenAIClientOptions); AgentVersion agentVersion = await client.CreateAgentVersionAsync( agentName: AGENT_NAME, - definition: GetAgentToolDefinition(toolType), + definition: await GetAgentToolDefinition(toolType, openAIClient), options: null ); - OpenAIClient openAIClient = client.GetOpenAIClient(TestOpenAIClientOptions); OpenAIResponseClient responseClient = openAIClient.GetOpenAIResponseClient( TestEnvironment.MODELDEPLOYMENTNAME); AgentReference agentReference = new(name: agentVersion.Name) @@ -614,7 +613,7 @@ public async Task TestTool(ToolType toolType) Assert.That(response.GetOutputText(), Is.Not.Null.And.Not.Empty); if (ExpectedOutput.TryGetValue(toolType, out string expectedResponse)) { - StringAssert.Contains(expectedResponse, response.GetOutputText(), $"The output: \"{response.GetOutputText()}\" does not contain {expectedResponse}"); + Assert.That(response.GetOutputText(), Does.Contain(expectedResponse), $"The output: \"{response.GetOutputText()}\" does not contain {expectedResponse}"); } } diff --git a/sdk/ai/Azure.AI.Agents/tests/OtherOpenAIParityTests.cs b/sdk/ai/Azure.AI.Agents/tests/OtherOpenAIParityTests.cs index e4e4c585ea63..c63d44637408 100644 --- a/sdk/ai/Azure.AI.Agents/tests/OtherOpenAIParityTests.cs +++ b/sdk/ai/Azure.AI.Agents/tests/OtherOpenAIParityTests.cs @@ -32,7 +32,7 @@ public async Task FileUploadWorks(OpenAIClientMode clientMode, string rawPurpose AgentsClient agentsClient = GetTestClient(); OpenAIClient openAIClient = clientMode switch { - OpenAIClientMode.UseExternalOpenAI => new OpenAIClient(new ApiKeyCredential(Environment.GetEnvironmentVariable("OPENAI_API_KEY")), TestOpenAIClientOptions), + OpenAIClientMode.UseExternalOpenAI => new OpenAIClient(new ApiKeyCredential(TestEnvironment.ParseEnvironmentFile()["OPEN-API-KEY"]), TestOpenAIClientOptions), OpenAIClientMode.UseFDPOpenAI => agentsClient.GetOpenAIClient(TestOpenAIClientOptions), _ => throw new NotImplementedException() }; diff --git a/sdk/ai/Azure.AI.Agents/tests/Samples/Sample_FileSearch.cs b/sdk/ai/Azure.AI.Agents/tests/Samples/Sample_FileSearch.cs new file mode 100644 index 000000000000..10ee8be4c63e --- /dev/null +++ b/sdk/ai/Azure.AI.Agents/tests/Samples/Sample_FileSearch.cs @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Azure.Identity; +using Microsoft.ClientModel.TestFramework; +using NUnit.Framework; +using OpenAI; +using OpenAI.Files; +using OpenAI.Responses; +using OpenAI.VectorStores; + +namespace Azure.AI.Agents.Tests.Samples; + +public class Sample_FileSearch : AgentsTestBase +{ + [Test] + [AsyncOnly] + public async Task FileSearchAsync() + { + IgnoreSampleMayBe(); + #region Snippet:Sample_CreateAgentClient_FileSearch +#if SNIPPET + var projectEndpoint = System.Environment.GetEnvironmentVariable("PROJECT_ENDPOINT"); + var modelDeploymentName = System.Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME"); +#else + var projectEndpoint = TestEnvironment.PROJECT_ENDPOINT; + var modelDeploymentName = TestEnvironment.MODELDEPLOYMENTNAME; +#endif + AgentsClient client = new(endpoint: new Uri(projectEndpoint), tokenProvider: new DefaultAzureCredential()); + OpenAIClient openAIClient = client.GetOpenAIClient(); + #endregion + #region Snippet:Sample_UploadFile_FileSearch_Async + string filePath = "sample_file_for_upload.txt"; + File.WriteAllText( + path: filePath, + contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); + OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); + OpenAIFile uploadedFile = await fileClient.UploadFileAsync(filePath: filePath, purpose: FileUploadPurpose.Assistants); + File.Delete(filePath); + #endregion + #region Snippet:Sample_CreateVectorStore_FileSearch_Async + VectorStoreClient vctStoreClient = openAIClient.GetVectorStoreClient(); + VectorStoreCreationOptions options = new() + { + Name = "MySampleStore", + FileIds = { uploadedFile.Id } + }; + VectorStore vectorStore = await vctStoreClient.CreateVectorStoreAsync(options); + #endregion + #region Snippet:Sample_CreateAgent_FileSearch_Async + PromptAgentDefinition agentDefinition = new(model: modelDeploymentName) + { + Instructions = "You are a helpful agent that can help fetch data from files you know about.", + Tools = { ResponseTool.CreateFileSearchTool(vectorStoreIds: [vectorStore.Id]), } + }; + AgentVersion agentVersion = await client.CreateAgentVersionAsync( + agentName: "myAgent", + definition: agentDefinition, + options: null); + #endregion + #region Snippet:Sample_CreateResponse_FileSearch_Async + OpenAIResponseClient responseClient = openAIClient.GetOpenAIResponseClient(modelDeploymentName); + ResponseCreationOptions responseOptions = new(); + responseOptions.SetAgentReference(new AgentReference(name: agentVersion.Name)); + + ResponseItem request = ResponseItem.CreateUserMessageItem("The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); + OpenAIResponse response = await responseClient.CreateResponseAsync( + [request], + responseOptions); + #endregion + + #region Snippet:Sample_WaitForResponse_FileSearch_Async + List updateItems = [request]; + while (response.Status != ResponseStatus.Incomplete && response.Status != ResponseStatus.Failed && response.Status != ResponseStatus.Completed) + { + await Task.Delay(TimeSpan.FromMilliseconds(500)); + response = await responseClient.GetResponseAsync(responseId: response.Id); + } + Assert.That(response.Status, Is.EqualTo(ResponseStatus.Completed)); + Console.WriteLine(response.GetOutputText()); + #endregion + + #region Snippet:Sample_Cleanup_FileSearch_Async + await client.DeleteAgentVersionAsync(agentName: agentVersion.Name, agentVersion: agentVersion.Version); + await vctStoreClient.DeleteVectorStoreAsync(vectorStoreId: vectorStore.Id); + await fileClient.DeleteFileAsync(uploadedFile.Id); + #endregion + } + + [Test] + [SyncOnly] + public void FileSearchSync() + { + IgnoreSampleMayBe(); +#if SNIPPET + var projectEndpoint = System.Environment.GetEnvironmentVariable("PROJECT_ENDPOINT"); + var modelDeploymentName = System.Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME"); +#else + var projectEndpoint = TestEnvironment.PROJECT_ENDPOINT; + var modelDeploymentName = TestEnvironment.MODELDEPLOYMENTNAME; +#endif + AgentsClient client = new(endpoint: new Uri(projectEndpoint), tokenProvider: new DefaultAzureCredential()); + OpenAIClient openAIClient = client.GetOpenAIClient(); + + #region Snippet:Sample_UploadFile_FileSearch_Sync + string filePath = "sample_file_for_upload.txt"; + File.WriteAllText( + path: filePath, + contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); + OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); + OpenAIFile uploadedFile = fileClient.UploadFile(filePath: filePath, purpose: FileUploadPurpose.Assistants); + File.Delete(filePath); + #endregion + #region Snippet:Sample_CreateVectorStore_FileSearch_Sync + VectorStoreClient vctStoreClient = openAIClient.GetVectorStoreClient(); + VectorStoreCreationOptions options = new() + { + Name = "MySampleStore", + FileIds = { uploadedFile.Id } + }; + VectorStore vectorStore = vctStoreClient.CreateVectorStore(options: options); + #endregion + #region Snippet:Sample_CreateAgent_FileSearch_Sync + PromptAgentDefinition agentDefinition = new(model: modelDeploymentName) + { + Instructions = "You are a helpful agent that can help fetch data from files you know about.", + Tools = { ResponseTool.CreateFileSearchTool(vectorStoreIds: [vectorStore.Id]), } + }; + AgentVersion agentVersion = client.CreateAgentVersion( + agentName: "myAgent", + definition: agentDefinition, + options: null); + #endregion + #region Snippet:Sample_CreateResponse_FileSearch_Sync + OpenAIResponseClient responseClient = openAIClient.GetOpenAIResponseClient(modelDeploymentName); + ResponseCreationOptions responseOptions = new(); + responseOptions.SetAgentReference(new AgentReference(name: agentVersion.Name)); + + ResponseItem request = ResponseItem.CreateUserMessageItem("The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); + OpenAIResponse response = responseClient.CreateResponse( + [request], + responseOptions); + #endregion + + #region Snippet:Sample_WaitForResponse_FileSearch_Sync + List updateItems = [request]; + while (response.Status != ResponseStatus.Incomplete && response.Status != ResponseStatus.Failed && response.Status != ResponseStatus.Completed) + { + Thread.Sleep(TimeSpan.FromMilliseconds(500)); + response = responseClient.GetResponse(responseId: response.Id); + } + Assert.That(response.Status, Is.EqualTo(ResponseStatus.Completed)); + Console.WriteLine(response.GetOutputText()); + #endregion + + #region Snippet:Sample_Cleanup_FileSearch_Sync + client.DeleteAgentVersion(agentName: agentVersion.Name, agentVersion: agentVersion.Version); + vctStoreClient.DeleteVectorStore(vectorStoreId: vectorStore.Id); + fileClient.DeleteFile(uploadedFile.Id); + #endregion + } + + public Sample_FileSearch(bool isAsync) : base(isAsync) + { } +}