Files
agent-framework/dotnet/samples/03-workflows/Declarative/InputArguments/Program.cs
T
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

152 lines
6.9 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.Projects;
using Azure.AI.Projects.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using OpenAI.Responses;
using Shared.Foundry;
using Shared.Workflows;
namespace Demo.Workflows.Declarative.InputArguments;
/// <summary>
/// Demonstrate a workflow that consumes input arguments to dynamically enhance the agent
/// instructions. Exits the loop when the user enters "exit".
/// </summary>
/// <remarks>
/// See the README.md file in 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(string[] args)
{
// Initialize configuration
IConfiguration configuration = Application.InitializeConfig();
Uri foundryEndpoint = new(configuration.GetValue(Application.Settings.FoundryEndpoint));
// Ensure sample agents exist in Foundry.
await CreateAgentAsync(foundryEndpoint, configuration);
// Get input from command line or console
string workflowInput = Application.GetInput(args);
// 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("InputArguments.yaml", foundryEndpoint);
// Execute the workflow: The WorkflowRunner demonstrates how to execute
// a workflow, handle the workflow events, and providing external input.
// This also includes the ability to checkpoint workflow state and how to
// resume execution.
WorkflowRunner runner = new();
await runner.ExecuteAsync(workflowFactory.CreateWorkflow, workflowInput);
}
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: "LocationTriageAgent",
agentDefinition: DefineLocationTriageAgent(configuration),
agentDescription: "Chats with the user to solicit a location of interest.");
await aiProjectClient.CreateAgentAsync(
agentName: "LocationCaptureAgent",
agentDefinition: DefineLocationCaptureAgent(configuration),
agentDescription: "Evaluate the status of soliciting the location.");
await aiProjectClient.CreateAgentAsync(
agentName: "LocationAwareAgent",
agentDefinition: DefineLocationAwareAgent(configuration),
agentDescription: "Chats with the user with location awareness.");
}
private static PromptAgentDefinition DefineLocationTriageAgent(IConfiguration configuration) =>
new(configuration.GetValue(Application.Settings.FoundryModel))
{
Instructions =
"""
Your only job is to solicit a location from the user.
Always repeat back the location when addressing the user, except when it is not known.
"""
};
private static PromptAgentDefinition DefineLocationCaptureAgent(IConfiguration configuration) =>
new(configuration.GetValue(Application.Settings.FoundryModel))
{
Instructions =
"""
Request a location from the user. This location could be their own location
or perhaps a location they are interested in.
City level precision is sufficient.
If extrapolating region and country, confirm you have it right.
""",
TextOptions =
new ResponseTextOptions
{
TextFormat =
ResponseTextFormat.CreateJsonSchemaFormat(
"TaskEvaluation",
BinaryData.FromString(
"""
{
"type": "object",
"properties": {
"place": {
"type": "string",
"description": "Captures only your understanding of the location specified by the user without explanation, or 'unknown' if not yet defined."
},
"action": {
"type": "string",
"description": "The instruction for the next action to take regarding the need for additional detail or confirmation."
},
"is_location_defined": {
"type": "boolean",
"description": "True if the user location is understood."
},
"is_location_confirmed": {
"type": "boolean",
"description": "True if the user location is confirmed. An unambiguous location may be implicitly confirmed without explicit user confirmation."
}
},
"required": ["place", "action", "is_location_defined", "is_location_confirmed"],
"additionalProperties": false
}
"""),
jsonSchemaFormatDescription: null,
jsonSchemaIsStrict: true),
}
};
private static PromptAgentDefinition DefineLocationAwareAgent(IConfiguration configuration) =>
new(configuration.GetValue(Application.Settings.FoundryModel))
{
// Parameterized instructions reference the "location" input argument.
Instructions =
"""
Talk to the user about their request.
Their request is related to a specific location: {{location}}.
""",
StructuredInputs =
{
["location"] =
new StructuredInputDefinition
{
IsRequired = false,
DefaultValue = BinaryData.FromString(@"""unknown"""),
Description = "The user's location",
}
}
};
}