Files
Chris 904a5b843e Python / .NET Samples - Restructure and Improve Samples (Feature Branc… (#4092)
* Python: .NET Samples - Restructure and Improve Samples (Feature Branch) (#4091)

* Moved by agent (#4094)

* Fix readme links

* .NET Samples - Create `04-hosting` learning path step (#4098)

* Agent move

* Agent reorderd

* Remove A2A section from README 

Removed A2A section from the Getting Started README.

* Agent fixed links

* Fix broken sample links in durable-agents README (#4101)

* Initial plan

* Fix broken internal links in documentation

Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* Revert template link changes; keep only durable-agents README fix

Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* .NET Samples - Create `03-workflows` learning path step (#4102)

* Fix solution project path

* Python: Fix broken markdown links to repo resources (outside /docs) (#4105)

* Initial plan

* Fix broken markdown links to repo resources

Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* Update README to rename .NET Workflows Samples section

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* .NET Samples - Create `02-agents` learning path step (#4107)

* .NET: Fix broken relative link in GroupChatToolApproval README (#4108)

* Initial plan

* Fix broken link in GroupChatToolApproval README

Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* Update labeler configuration for workflow samples

* .NET - Reorder Agents samples to start from Step01 instead of Step04 (#4110)

* Fix solution

* Resolve new sample paths

* Move new AgentSkills and AgentWithMemory_Step04 samples

* Fix link

* Fix readme path

* fix: update stale dotnet/samples/Durable path reference in AGENTS.md

Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* Moved new sample

* Update solution

* Resolve merge (new sample)

* Sync to new sample - FoundryAgents_Step21_BingCustomSearch

* Updated README

* .NET Samples - Configuration Naming Update (#4149)

* .NET: Restore AzureFunctions index parity with ConsoleApps under DurableAgents samples (#4221)

* Clean-up `05_host_your_agent`

* Config setting consistency

* Refine samples

* AGENTS.md

* Move new samples

* Re-order samples

* Move new project and fixup solution

* Fixup model config

* Fix up new UT project

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
2026-02-26 00:56:10 +00:00

112 lines
4.6 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use File Search Tool with AI Agents.
using Azure.AI.Projects;
using Azure.AI.Projects.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.Assistants;
using OpenAI.Files;
using OpenAI.Responses;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
const string AgentInstructions = "You are a helpful assistant that can search through uploaded files to answer questions.";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
var projectOpenAIClient = aiProjectClient.GetProjectOpenAIClient();
var filesClient = projectOpenAIClient.GetProjectFilesClient();
var vectorStoresClient = projectOpenAIClient.GetProjectVectorStoresClient();
// 1. Create a temp file with test content and upload it.
string searchFilePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + "_lookup.txt");
File.WriteAllText(
path: searchFilePath,
contents: """
Employee Directory:
- Alice Johnson, 28 years old, Software Engineer, Engineering Department
- Bob Smith, 35 years old, Sales Manager, Sales Department
- Carol Williams, 42 years old, HR Director, Human Resources Department
- David Brown, 31 years old, Customer Support Lead, Support Department
"""
);
Console.WriteLine($"Uploading file: {searchFilePath}");
OpenAIFile uploadedFile = filesClient.UploadFile(
filePath: searchFilePath,
purpose: FileUploadPurpose.Assistants
);
Console.WriteLine($"Uploaded file, file ID: {uploadedFile.Id}");
// 2. Create a vector store with the uploaded file.
var vectorStoreResult = await vectorStoresClient.CreateVectorStoreAsync(
options: new() { FileIds = { uploadedFile.Id }, Name = "EmployeeDirectory_VectorStore" }
);
string vectorStoreId = vectorStoreResult.Value.Id;
Console.WriteLine($"Created vector store, vector store ID: {vectorStoreId}");
AIAgent agent = await CreateAgentWithMEAI();
// AIAgent agent = await CreateAgentWithNativeSDK();
// Run the agent
Console.WriteLine("\n--- Running File Search Agent ---");
AgentResponse response = await agent.RunAsync("Who is the youngest employee?");
Console.WriteLine($"Response: {response}");
// Getting any file citation annotations generated by the tool
foreach (AIAnnotation annotation in response.Messages.SelectMany(m => m.Contents).SelectMany(c => c.Annotations ?? []))
{
if (annotation.RawRepresentation is TextAnnotationUpdate citationAnnotation)
{
Console.WriteLine($$"""
File Citation:
File Id: {{citationAnnotation.OutputFileId}}
Text to Replace: {{citationAnnotation.TextToReplace}}
""");
}
}
// Cleanup.
Console.WriteLine("\n--- Cleanup ---");
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
await vectorStoresClient.DeleteVectorStoreAsync(vectorStoreId);
await filesClient.DeleteFileAsync(uploadedFile.Id);
File.Delete(searchFilePath);
Console.WriteLine("Cleanup completed successfully.");
// --- Agent Creation Options ---
#pragma warning disable CS8321 // Local function is declared but never used
// Option 1 - Using HostedFileSearchTool (MEAI + AgentFramework)
async Task<AIAgent> CreateAgentWithMEAI()
{
return await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
name: "FileSearchAgent-MEAI",
instructions: AgentInstructions,
tools: [new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreId)] }]);
}
// Option 2 - Using PromptAgentDefinition with ResponseTool.CreateFileSearchTool (Native SDK)
async Task<AIAgent> CreateAgentWithNativeSDK()
{
return await aiProjectClient.CreateAIAgentAsync(
name: "FileSearchAgent-NATIVE",
creationOptions: new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = AgentInstructions,
Tools = {
ResponseTool.CreateFileSearchTool(vectorStoreIds: [vectorStoreId])
}
})
);
}