-
Notifications
You must be signed in to change notification settings - Fork 2.2k
.NET: docs/workflow fileinput sample dotnet #7913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Vincent Biret (baywet)
merged 7 commits into
main
from
docs/workflow-fileinput-sample-dotnet
Aug 27, 2026
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
c4d0259
docs: adds a workflow file input example in dotnet
baywet bc0eb76
fix: switches to a hosted file since model doesn't support the data c…
baywet 860c36d
fix: simplify declarative file input sample
Copilot b83d2f2
fix: upload fixed file input fixture
Copilot 9a20b30
fix: preserve workflow result on cleanup failure
Copilot b4decdc
refactor: clarify uploaded file naming
Copilot 1a86390
docs: removes outdated command
baywet File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
dotnet/samples/03-workflows/Declarative/FileInput/FileInput.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFrameworks>net10.0</TargetFrameworks> | ||
| <Nullable>enable</Nullable> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| </PropertyGroup> | ||
|
|
||
| <PropertyGroup> | ||
| <InjectIsExternalInitOnLegacy>true</InjectIsExternalInitOnLegacy> | ||
| <InjectSharedFoundryAgents>true</InjectSharedFoundryAgents> | ||
| <InjectSharedWorkflowsExecution>true</InjectSharedWorkflowsExecution> | ||
| <InjectSharedWorkflowsSettings>true</InjectSharedWorkflowsSettings> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Azure.AI.Projects" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.Binder" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.Json" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" /> | ||
| <PackageReference Include="Microsoft.Extensions.DependencyInjection" /> | ||
| <PackageReference Include="Microsoft.Extensions.Logging" /> | ||
| <PackageReference Include="OpenAI" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Workflows.Declarative\Microsoft.Agents.AI.Workflows.Declarative.csproj" /> | ||
| <ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Workflows.Declarative.Foundry\Microsoft.Agents.AI.Workflows.Declarative.Foundry.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <None Include="FileInput.yaml"> | ||
| <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||
| </None> | ||
| <None Include="ProductBrief.txt"> | ||
| <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||
| </None> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
30 changes: 30 additions & 0 deletions
30
dotnet/samples/03-workflows/Declarative/FileInput/FileInput.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # | ||
| # This workflow demonstrates accepting file-based input as workflow input. | ||
| # | ||
| kind: Workflow | ||
| trigger: | ||
|
|
||
| kind: OnConversationStart | ||
| id: workflow_demo | ||
| actions: | ||
|
|
||
| # Show that the workflow can inspect the text portion of the message. | ||
| # The uploaded file is already attached to the conversation and is available | ||
| # to agent-backed actions that use System.ConversationId. | ||
| - kind: SendActivity | ||
| id: announce_file_input | ||
| activity: |- | ||
| Received file-based workflow input. | ||
|
|
||
| Prompt: | ||
| {System.LastMessage.Text} | ||
|
|
||
| # Invoke an agent in the original conversation. The workflow root already added | ||
| # the file-bearing user message to this conversation before the first action ran. | ||
| - kind: InvokeAzureAgent | ||
| id: summarize_file | ||
| conversationId: =System.ConversationId | ||
| agent: | ||
| name: FileInputAgent | ||
| output: | ||
| autoSend: true |
16 changes: 16 additions & 0 deletions
16
dotnet/samples/03-workflows/Declarative/FileInput/ProductBrief.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| Product: Contoso Trail Bottle | ||
|
|
||
| The Contoso Trail Bottle is a lightweight stainless-steel water bottle designed | ||
| for hikers, commuters, and students. It keeps drinks cold for 24 hours, fits in | ||
| standard backpack side pockets, and uses a leak-resistant twist lid. | ||
|
|
||
| Audience: | ||
| - Weekend hikers | ||
| - Urban commuters | ||
| - Students who want a durable reusable bottle | ||
|
|
||
| Key differentiators: | ||
| - Recycled stainless-steel body | ||
| - Dishwasher-safe lid | ||
| - Replaceable silicone gasket | ||
| - Optional clip loop for backpacks |
127 changes: 127 additions & 0 deletions
127
dotnet/samples/03-workflows/Declarative/FileInput/Program.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| using Azure.AI.Projects; | ||
| using Azure.AI.Projects.Agents; | ||
| using Azure.Identity; | ||
| using Microsoft.Extensions.AI; | ||
| using Microsoft.Extensions.Configuration; | ||
| using OpenAI.Files; | ||
| using Shared.Foundry; | ||
| using Shared.Workflows; | ||
|
|
||
| namespace Demo.Workflows.Declarative.FileInput; | ||
|
|
||
| /// <summary> | ||
| /// Demonstrate how to provide file-based input to a declarative workflow. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// See the README.md file in this folder and the parent folder (../README.md) for | ||
| /// detailed information about the configuration required to run this sample. | ||
| /// </remarks> | ||
| internal sealed class Program | ||
| { | ||
| public static async Task Main() | ||
| { | ||
| // Initialize configuration | ||
| IConfiguration configuration = Application.InitializeConfig(); | ||
| Uri foundryEndpoint = new(configuration.GetValue(Application.Settings.FoundryEndpoint)); | ||
|
|
||
| // Ensure sample agents exist in Foundry. | ||
| await CreateAgentAsync(foundryEndpoint, configuration); | ||
|
|
||
| string filePath = Path.Combine(AppContext.BaseDirectory, "ProductBrief.txt"); | ||
| await using UploadedFile uploadedFile = await UploadInputFileAsync(foundryEndpoint, filePath); | ||
|
|
||
| // Create the workflow factory. This class demonstrates how to initialize a | ||
| // declarative workflow from a YAML file. Once the workflow is created, it | ||
| // can be executed just like any regular workflow. | ||
| WorkflowFactory workflowFactory = new("FileInput.yaml", foundryEndpoint); | ||
|
|
||
| // Execute the workflow with a ChatMessage that contains both text and an uploaded | ||
| // file reference. Agent-backed actions can use the same workflow conversation to | ||
| // access the file. | ||
| WorkflowRunner runner = new(); | ||
| await runner.ExecuteAsync(workflowFactory.CreateWorkflow, CreateInputMessage(uploadedFile.FileId)); | ||
| } | ||
|
|
||
| private static async Task CreateAgentAsync(Uri foundryEndpoint, IConfiguration configuration) | ||
| { | ||
| // 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(foundryEndpoint, new DefaultAzureCredential()); | ||
|
|
||
| await aiProjectClient.CreateAgentAsync( | ||
| agentName: "FileInputAgent", | ||
| agentDefinition: DefineFileInputAgent(configuration), | ||
| agentDescription: "Summarizes files provided as declarative workflow input."); | ||
| } | ||
|
|
||
| private static DeclarativeAgentDefinition DefineFileInputAgent(IConfiguration configuration) => | ||
| new(configuration.GetValue(Application.Settings.FoundryModel)) | ||
| { | ||
| Instructions = | ||
| """ | ||
| You summarize files that are provided as user input to a workflow. | ||
|
|
||
| When a file is attached, inspect the file content and provide: | ||
| - A short summary | ||
| - Important facts or entities | ||
| - One suggested follow-up question | ||
|
|
||
| If no file content is available, explain that you did not receive a file. | ||
| """ | ||
| }; | ||
|
|
||
| private static async Task<UploadedFile> UploadInputFileAsync(Uri foundryEndpoint, string filePath) | ||
| { | ||
| // 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(foundryEndpoint, new DefaultAzureCredential()); | ||
| OpenAIFileClient fileClient = aiProjectClient.GetProjectOpenAIClient().GetOpenAIFileClient(); | ||
|
|
||
| using FileStream fileStream = File.OpenRead(filePath); | ||
| OpenAIFile openAIFile = await fileClient.UploadFileAsync( | ||
| fileStream, | ||
| Path.GetFileName(filePath), | ||
| FileUploadPurpose.Assistants).ConfigureAwait(false); | ||
|
|
||
| Console.ForegroundColor = ConsoleColor.Cyan; | ||
| try | ||
| { | ||
| Console.WriteLine($"FILE: {openAIFile.Id}"); | ||
| } | ||
| finally | ||
| { | ||
| Console.ResetColor(); | ||
| } | ||
|
|
||
| return new UploadedFile(fileClient, openAIFile.Id); | ||
| } | ||
|
|
||
| private static ChatMessage CreateInputMessage(string fileId) | ||
| { | ||
| return new ChatMessage( | ||
| ChatRole.User, | ||
| [ | ||
| new TextContent("Summarize the attached file for a launch announcement. File name: ProductBrief.txt"), | ||
| new HostedFileContent(fileId), | ||
| ]); | ||
| } | ||
|
|
||
| private sealed record UploadedFile(OpenAIFileClient FileClient, string FileId) : IAsyncDisposable | ||
| { | ||
| public async ValueTask DisposeAsync() | ||
| { | ||
| try | ||
| { | ||
| await this.FileClient.DeleteFileAsync(this.FileId).ConfigureAwait(false); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Console.Error.WriteLine($"Unable to delete uploaded file {this.FileId}: {ex.Message}"); | ||
| } | ||
| } | ||
| } | ||
| } |
15 changes: 15 additions & 0 deletions
15
dotnet/samples/03-workflows/Declarative/FileInput/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Declarative workflow file input | ||
|
|
||
| This sample demonstrates how to provide file-based input to a declarative workflow. It uploads the bundled `ProductBrief.txt` file to the Foundry project, converts the uploaded file reference into a `ChatMessage` with both `TextContent` and `HostedFileContent`, then starts a YAML-defined workflow with that message. | ||
|
|
||
| The workflow displays `System.LastMessage.Text`, then invokes a Foundry-backed agent in the same workflow conversation so the uploaded file is available to the agent. | ||
|
|
||
| ## Run the sample | ||
|
|
||
| Configure the common declarative workflow settings described in the parent [README](../README.md), then run: | ||
|
|
||
| ```pwsh | ||
| dotnet run | ||
| ``` | ||
|
|
||
| The sample always uploads `ProductBrief.txt` from this project. The program creates a `ChatMessage` whose content includes the prompt and uploaded file reference, then starts the workflow with that message. The YAML invokes the agent with `conversationId: =System.ConversationId` so the agent sees the same conversation item that contains the file. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.