diff --git a/.github/workflows/python-test-coverage-report.yml b/.github/workflows/python-test-coverage-report.yml
index 9ea5b8022d..81a506f277 100644
--- a/.github/workflows/python-test-coverage-report.yml
+++ b/.github/workflows/python-test-coverage-report.yml
@@ -39,7 +39,7 @@ jobs:
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
- name: Pytest coverage comment
id: coverageComment
- uses: MishaKav/pytest-coverage-comment@v1.1.57
+ uses: MishaKav/pytest-coverage-comment@v1.1.59
with:
github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
issue-number: ${{ env.PR_NUMBER }}
diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props
index 1907443a5a..67397efff4 100644
--- a/dotnet/Directory.Packages.props
+++ b/dotnet/Directory.Packages.props
@@ -7,15 +7,15 @@
- 9.5.2
+ 13.0.0
-
+
-
+
@@ -23,18 +23,18 @@
-
+
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
@@ -45,39 +45,39 @@
-
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -102,7 +102,7 @@
-
+
@@ -114,7 +114,7 @@
-
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
@@ -134,7 +134,7 @@
allruntime; build; native; contentfiles; analyzers; buildtransitive
-
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 7049dbf466..9835bfe830 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -65,6 +65,7 @@
+
@@ -123,6 +124,7 @@
+
@@ -175,7 +177,6 @@
-
@@ -313,6 +314,7 @@
+
diff --git a/dotnet/nuget/nuget-package.props b/dotnet/nuget/nuget-package.props
index baaa579bf1..500a0a8eb0 100644
--- a/dotnet/nuget/nuget-package.props
+++ b/dotnet/nuget/nuget-package.props
@@ -2,9 +2,9 @@
1.0.0
- $(VersionPrefix)-$(VersionSuffix).251110.2
- $(VersionPrefix)-preview.251110.2
- 1.0.0-preview.251110.2
+ $(VersionPrefix)-$(VersionSuffix).251111.1
+ $(VersionPrefix)-preview.251111.1
+ 1.0.0-preview.251111.1Debug;Release;Publishtrue
diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step18_DeepResearch/Agent_Step18_DeepResearch.csproj b/dotnet/samples/GettingStarted/Agents/Agent_Step18_DeepResearch/Agent_Step18_DeepResearch.csproj
new file mode 100644
index 0000000000..11c7beb3bf
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Agents/Agent_Step18_DeepResearch/Agent_Step18_DeepResearch.csproj
@@ -0,0 +1,20 @@
+
+
+
+ Exe
+ net9.0
+
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step18_DeepResearch/Program.cs b/dotnet/samples/GettingStarted/Agents/Agent_Step18_DeepResearch/Program.cs
new file mode 100644
index 0000000000..f6aa825a54
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Agents/Agent_Step18_DeepResearch/Program.cs
@@ -0,0 +1,52 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample shows how to create an Azure AI Foundry Agent with the Deep Research Tool.
+
+using Azure.AI.Agents.Persistent;
+using Azure.Identity;
+using Microsoft.Agents.AI;
+
+var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
+var deepResearchDeploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEEP_RESEARCH_DEPLOYMENT_NAME") ?? "o3-deep-research";
+var modelDeploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o";
+var bingConnectionId = Environment.GetEnvironmentVariable("BING_CONNECTION_ID") ?? throw new InvalidOperationException("BING_CONNECTION_ID is not set.");
+
+// Configure extended network timeout for long-running Deep Research tasks.
+PersistentAgentsAdministrationClientOptions persistentAgentsClientOptions = new();
+persistentAgentsClientOptions.Retry.NetworkTimeout = TimeSpan.FromMinutes(20);
+
+// Get a client to create/retrieve server side agents with.
+PersistentAgentsClient persistentAgentsClient = new(endpoint, new AzureCliCredential(), persistentAgentsClientOptions);
+
+// Define and configure the Deep Research tool.
+DeepResearchToolDefinition deepResearchTool = new(new DeepResearchDetails(
+ bingGroundingConnections: [new(bingConnectionId)],
+ model: deepResearchDeploymentName)
+ );
+
+// Create an agent with the Deep Research tool on the Azure AI agent service.
+AIAgent agent = await persistentAgentsClient.CreateAIAgentAsync(
+ model: modelDeploymentName,
+ name: "DeepResearchAgent",
+ instructions: "You are a helpful Agent that assists in researching scientific topics.",
+ tools: [deepResearchTool]);
+
+const string Task = "Research the current state of studies on orca intelligence and orca language, " +
+ "including what is currently known about orcas' cognitive capabilities and communication systems.";
+
+Console.WriteLine($"# User: '{Task}'");
+Console.WriteLine();
+
+try
+{
+ AgentThread thread = agent.GetNewThread();
+
+ await foreach (var response in agent.RunStreamingAsync(Task, thread))
+ {
+ Console.Write(response.Text);
+ }
+}
+finally
+{
+ await persistentAgentsClient.Administration.DeleteAgentAsync(agent.Id);
+}
diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step18_DeepResearch/README.md b/dotnet/samples/GettingStarted/Agents/Agent_Step18_DeepResearch/README.md
new file mode 100644
index 0000000000..0404054306
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Agents/Agent_Step18_DeepResearch/README.md
@@ -0,0 +1,47 @@
+# What this sample demonstrates
+
+This sample demonstrates how to create an Azure AI Agent with the Deep Research Tool, which leverages the o3-deep-research reasoning model to perform comprehensive research on complex topics.
+
+Key features:
+- Configuring and using the Deep Research Tool with Bing grounding
+- Creating a persistent AI agent with deep research capabilities
+- Executing deep research queries and retrieving results
+
+## Prerequisites
+
+Before running this sample, ensure you have:
+
+1. An Azure AI Foundry project set up
+2. A deep research model deployment (e.g., o3-deep-research)
+3. A model deployment (e.g., gpt-4o)
+4. A Bing Connection configured in your Azure AI Foundry project
+5. Azure CLI installed and authenticated
+
+**Important**: Please visit the following documentation for detailed setup instructions:
+- [Deep Research Tool Documentation](https://aka.ms/agents-deep-research)
+- [Research Tool Setup](https://learn.microsoft.com/en-us/azure/ai-foundry/agents/how-to/tools/deep-research#research-tool-setup)
+
+Pay special attention to the purple `Note` boxes in the Azure documentation.
+
+**Note**: The Bing Connection ID must be from the **project**, not the resource. It has the following format:
+
+```
+/subscriptions//resourceGroups//providers//accounts//projects//connections/
+```
+
+## Environment Variables
+
+Set the following environment variables:
+
+```powershell
+# Replace with your Azure AI Foundry project endpoint
+$env:AZURE_FOUNDRY_PROJECT_ENDPOINT="https://your-project.services.ai.azure.com/"
+
+# Replace with your Bing connection ID from the project
+$env:BING_CONNECTION_ID="/subscriptions/.../connections/your-bing-connection"
+
+# Optional, defaults to o3-deep-research
+$env:AZURE_FOUNDRY_PROJECT_DEEP_RESEARCH_DEPLOYMENT_NAME="o3-deep-research"
+
+# Optional, defaults to gpt-4o
+$env:AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME="gpt-4o"
diff --git a/dotnet/samples/GettingStarted/Agents/README.md b/dotnet/samples/GettingStarted/Agents/README.md
index b93e9ceb72..f510b03faf 100644
--- a/dotnet/samples/GettingStarted/Agents/README.md
+++ b/dotnet/samples/GettingStarted/Agents/README.md
@@ -44,6 +44,7 @@ Before you begin, ensure you have the following prerequisites:
|[Using plugins with an agent](./Agent_Step15_Plugins/)|This sample demonstrates how to use plugins with an agent|
|[Reducing chat history size](./Agent_Step16_ChatReduction/)|This sample demonstrates how to reduce the chat history to constrain its size, where chat history is maintained locally|
|[Background responses](./Agent_Step17_BackgroundResponses/)|This sample demonstrates how to use background responses for long-running operations with polling and resumption support|
+|[Deep research with an agent](./Agent_Step18_DeepResearch/)|This sample demonstrates how to use the Deep Research Tool to perform comprehensive research on complex topics|
## Running the samples from the console
diff --git a/dotnet/samples/GettingStarted/Workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs b/dotnet/samples/GettingStarted/Workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs
index 653ebdf4c2..e418ca7131 100644
--- a/dotnet/samples/GettingStarted/Workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs
+++ b/dotnet/samples/GettingStarted/Workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs
@@ -16,7 +16,7 @@ internal static class WorkflowFactory
internal static Workflow BuildWorkflow(IChatClient chatClient)
{
// Create executors
- var startExecutor = new ConcurrentStartExecutor();
+ var startExecutor = new ChatForwardingExecutor("Start");
var aggregationExecutor = new ConcurrentAggregationExecutor();
AIAgent frenchAgent = GetLanguageAgent("French", chatClient);
AIAgent englishAgent = GetLanguageAgent("English", chatClient);
@@ -38,33 +38,11 @@ internal static class WorkflowFactory
private static ChatClientAgent GetLanguageAgent(string targetLanguage, IChatClient chatClient) =>
new(chatClient, instructions: $"You're a helpful assistant who always responds in {targetLanguage}.", name: $"{targetLanguage}Agent");
- ///
- /// Executor that starts the concurrent processing by sending messages to the agents.
- ///
- private sealed class ConcurrentStartExecutor() : Executor("ConcurrentStartExecutor")
- {
- protected override RouteBuilder ConfigureRoutes(RouteBuilder routeBuilder)
- {
- return routeBuilder
- .AddHandler>(this.RouteMessages)
- .AddHandler(this.RouteTurnTokenAsync);
- }
-
- private ValueTask RouteMessages(List messages, IWorkflowContext context, CancellationToken cancellationToken)
- {
- return context.SendMessageAsync(messages, cancellationToken: cancellationToken);
- }
-
- private ValueTask RouteTurnTokenAsync(TurnToken token, IWorkflowContext context, CancellationToken cancellationToken)
- {
- return context.SendMessageAsync(token, cancellationToken: cancellationToken);
- }
- }
-
///
/// Executor that aggregates the results from the concurrent agents.
///
- private sealed class ConcurrentAggregationExecutor() : Executor>("ConcurrentAggregationExecutor")
+ private sealed class ConcurrentAggregationExecutor() :
+ Executor>("ConcurrentAggregationExecutor"), IResettableExecutor
{
private readonly List _messages = [];
@@ -85,5 +63,12 @@ internal static class WorkflowFactory
await context.YieldOutputAsync(formattedMessages, cancellationToken);
}
}
+
+ ///
+ public ValueTask ResetAsync()
+ {
+ this._messages.Clear();
+ return default;
+ }
}
}
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/ConfirmInput/ConfirmInput.csproj b/dotnet/samples/GettingStarted/Workflows/Declarative/ConfirmInput/ConfirmInput.csproj
index a78fbddbd7..b7c6379101 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/ConfirmInput/ConfirmInput.csproj
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/ConfirmInput/ConfirmInput.csproj
@@ -28,6 +28,7 @@
+
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/ConfirmInput/Program.cs b/dotnet/samples/GettingStarted/Workflows/Declarative/ConfirmInput/Program.cs
index 5ecda10049..2117bf8b07 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/ConfirmInput/Program.cs
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/ConfirmInput/Program.cs
@@ -10,7 +10,7 @@ namespace Demo.Workflows.Declarative.ConfirmInput;
/// and confirm it matches the original input.
///
///
-/// See the README.md file in the parent folder (../Declarative/README.md) for detailed
+/// See the README.md file in the parent folder (../README.md) for detailed
/// information the configuration required to run this sample.
///
internal sealed class Program
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/DeepResearch/DeepResearch.csproj b/dotnet/samples/GettingStarted/Workflows/Declarative/DeepResearch/DeepResearch.csproj
index c4d542056d..619c727b1b 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/DeepResearch/DeepResearch.csproj
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/DeepResearch/DeepResearch.csproj
@@ -28,6 +28,7 @@
+
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/DeepResearch/Program.cs b/dotnet/samples/GettingStarted/Workflows/Declarative/DeepResearch/Program.cs
index 0d1368d7ac..b3a7be9171 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/DeepResearch/Program.cs
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/DeepResearch/Program.cs
@@ -14,7 +14,7 @@ namespace Demo.Workflows.Declarative.DeepResearch;
/// using the Magentic orchestration pattern developed by AutoGen.
///
///
-/// See the README.md file in the parent folder (../Declarative/README.md) for detailed
+/// See the README.md file in the parent folder (../README.md) for detailed
/// information the configuration required to run this sample.
///
internal sealed class Program
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/ExecuteCode/ExecuteCode.csproj b/dotnet/samples/GettingStarted/Workflows/Declarative/ExecuteCode/ExecuteCode.csproj
index 838f0f1e4f..ca7c10cde3 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/ExecuteCode/ExecuteCode.csproj
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/ExecuteCode/ExecuteCode.csproj
@@ -29,6 +29,7 @@
+
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/ExecuteWorkflow/ExecuteWorkflow.csproj b/dotnet/samples/GettingStarted/Workflows/Declarative/ExecuteWorkflow/ExecuteWorkflow.csproj
index f5475b66f4..1fb6abe55d 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/ExecuteWorkflow/ExecuteWorkflow.csproj
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/ExecuteWorkflow/ExecuteWorkflow.csproj
@@ -28,6 +28,7 @@
+
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/FunctionTools/FunctionTools.csproj b/dotnet/samples/GettingStarted/Workflows/Declarative/FunctionTools/FunctionTools.csproj
index 239df72098..888a48f5df 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/FunctionTools/FunctionTools.csproj
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/FunctionTools/FunctionTools.csproj
@@ -28,6 +28,7 @@
+
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/FunctionTools/Program.cs b/dotnet/samples/GettingStarted/Workflows/Declarative/FunctionTools/Program.cs
index 170f9b08a0..2549312b95 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/FunctionTools/Program.cs
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/FunctionTools/Program.cs
@@ -15,7 +15,7 @@ namespace Demo.Workflows.Declarative.FunctionTools;
/// with function tools assigned. Exits the loop when the user enters "exit".
///
///
-/// See the README.md file in the parent folder (../Declarative/README.md) for detailed
+/// See the README.md file in the parent folder (../README.md) for detailed
/// information the configuration required to run this sample.
///
internal sealed class Program
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/GenerateCode/Program.cs b/dotnet/samples/GettingStarted/Workflows/Declarative/GenerateCode/Program.cs
index 859b74b194..54c77d4077 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/GenerateCode/Program.cs
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/GenerateCode/Program.cs
@@ -42,7 +42,7 @@ internal sealed class Program
Console.WriteLine(code);
}
- private const string DefaultWorkflow = "HelloWorld.yaml";
+ private const string DefaultWorkflow = "Marketing.yaml";
private string WorkflowFile { get; }
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/InputArguments/InputArguments.csproj b/dotnet/samples/GettingStarted/Workflows/Declarative/InputArguments/InputArguments.csproj
new file mode 100644
index 0000000000..51582438eb
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/InputArguments/InputArguments.csproj
@@ -0,0 +1,40 @@
+
+
+
+ Exe
+ net9.0
+ net9.0
+ $(ProjectsDebugTargetFrameworks)
+ enable
+ enable
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/InputArguments/InputArguments.yaml b/dotnet/samples/GettingStarted/Workflows/Declarative/InputArguments/InputArguments.yaml
new file mode 100644
index 0000000000..3f602d0e7b
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/InputArguments/InputArguments.yaml
@@ -0,0 +1,97 @@
+#
+# This workflow demonstrates providing input arguments to an agent.
+#
+# Example input:
+# I'd like to go on vacation.
+#
+kind: Workflow
+trigger:
+
+ kind: OnConversationStart
+ id: workflow_demo
+ actions:
+
+ # Capture the original user message for input to the location-aware agent
+ - kind: SetVariable
+ id: set_count_increment
+ variable: Local.InputMessage
+ value: =System.LastMessage
+
+ # Invoke the triage agent to determine location requirements
+ - kind: InvokeAzureAgent
+ id: solicit_input
+ conversationId: =System.ConversationId
+ agent:
+ name: LocationTriageAgent
+ input:
+ messages: =Local.ActionMessage
+ output:
+ messages: Local.TriageResponse
+
+ # Request input from the user based on the triage response
+ - kind: RequestExternalInput
+ id: request_requirements
+ variable: Local.NextInput
+
+ # Capture the most recent interaction for evaluation
+ - kind: SetTextVariable
+ id: set_status_message
+ variable: Local.LocationStatusInput
+ value: |-
+ AGENT - {MessageText(Local.TriageResponse)}
+
+ USER - {MessageText(Local.NextInput)}
+
+ # Evaluate the status of the location triage
+ - kind: InvokeAzureAgent
+ id: evaluate_location
+ agent:
+ name: LocationCaptureAgent
+ input:
+ messages: =UserMessage(Local.LocationStatusInput)
+ output:
+ responseObject: Local.LocationResponse
+
+ # Determine if the location information is complete
+ - kind: ConditionGroup
+ id: check_completion
+ conditions:
+
+ - condition: |-
+ =Local.LocationResponse.is_location_defined = false Or
+ Local.LocationResponse.is_location_confirmed = false
+ id: check_done
+ actions:
+
+ # Capture the action message for input to the triage agent
+ - kind: SetVariable
+ id: set_next_message
+ variable: Local.ActionMessage
+ value: =AgentMessage(Local.LocationResponse.action)
+
+ - kind: GotoAction
+ id: goto_solicit_input
+ actionId: solicit_input
+
+ elseActions:
+
+ # Create a new conversation so the prior context does not interfere
+ - kind: CreateConversation
+ id: conversation_location
+ conversationId: Local.LocationConversationId
+
+ # Invoke the location-aware agent with the location argument
+ # and loop until the user types "EXIT"
+ - kind: InvokeAzureAgent
+ id: location_response
+ conversationId: =Local.LocationConversationId
+ agent:
+ name: LocationAwareAgent
+ input:
+ messages: =Local.InputMessage
+ arguments:
+ location: =Local.LocationResponse.place
+ externalLoop:
+ when: =Upper(System.LastMessage.Text) <> "EXIT"
+ output:
+ autoSend: true
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/InputArguments/Program.cs b/dotnet/samples/GettingStarted/Workflows/Declarative/InputArguments/Program.cs
new file mode 100644
index 0000000000..ff12ccd874
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/InputArguments/Program.cs
@@ -0,0 +1,147 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Azure.AI.Agents;
+using Azure.Identity;
+using Microsoft.Extensions.Configuration;
+using OpenAI.Responses;
+using Shared.Foundry;
+using Shared.Workflows;
+
+namespace Demo.Workflows.Declarative.InputArguments;
+
+///
+/// Demonstrate a workflow that consumes input arguments to dynamically enhance the agent
+/// instructions. Exits the loop when the user enters "exit".
+///
+///
+/// See the README.md file in the parent folder (../README.md) for detailed
+/// information the configuration required to run this sample.
+///
+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)
+ {
+ AgentClient agentsClient = new(foundryEndpoint, new AzureCliCredential());
+
+ await agentsClient.CreateAgentAsync(
+ agentName: "LocationTriageAgent",
+ agentDefinition: DefineLocationTriageAgent(configuration),
+ agentDescription: "Chats with the user to solicit a location of interest.");
+
+ await agentsClient.CreateAgentAsync(
+ agentName: "LocationCaptureAgent",
+ agentDefinition: DefineLocationCaptureAgent(configuration),
+ agentDescription: "Evaluate the status of soliciting the location.");
+
+ await agentsClient.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.FoundryModelMini))
+ {
+ 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.FoundryModelMini))
+ {
+ 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.FoundryModelMini))
+ {
+ // 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",
+ }
+ }
+ };
+}
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/Marketing/Marketing.csproj b/dotnet/samples/GettingStarted/Workflows/Declarative/Marketing/Marketing.csproj
index 76792809a9..12599a1b79 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/Marketing/Marketing.csproj
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/Marketing/Marketing.csproj
@@ -28,6 +28,7 @@
+
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/Marketing/Program.cs b/dotnet/samples/GettingStarted/Workflows/Declarative/Marketing/Program.cs
index 20987c6bfe..edeb82419b 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/Marketing/Program.cs
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/Marketing/Program.cs
@@ -13,7 +13,7 @@ namespace Demo.Workflows.Declarative.Marketing;
/// sequentially engaging in a task.
///
///
-/// See the README.md file in the parent folder (../Declarative/README.md) for detailed
+/// See the README.md file in the parent folder (../README.md) for detailed
/// information the configuration required to run this sample.
///
internal sealed class Program
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/README.md b/dotnet/samples/GettingStarted/Workflows/Declarative/README.md
index 0418cfe8da..665c37101e 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/README.md
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/README.md
@@ -86,12 +86,14 @@ To run the sampes from the command line:
1. From the root of the repository, navigate the console to the project folder:
```sh
- cd dotnet/samples/GettingStarted/Workflows/Declarative/StudentTeacher
+ cd dotnet/samples/GettingStarted/Workflows/Declarative/Marketing
+ dotnet run Marketing
```
2. Run the demo and optionally provided input:
```sh
- dotnet run "How would you compute the value of PI?"
+ dotnet run "An eco-friendly stainless steel water bottle that keeps drinks cold for 24 hours."
+ dotnet run c:/myworkflows/Marketing.yaml
```
> The sample will allow for interactive input in the absence of an input argument.
\ No newline at end of file
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/StudentTeacher/Program.cs b/dotnet/samples/GettingStarted/Workflows/Declarative/StudentTeacher/Program.cs
index d2299add5f..bbe1c526d5 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/StudentTeacher/Program.cs
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/StudentTeacher/Program.cs
@@ -13,7 +13,7 @@ namespace Demo.Workflows.Declarative.StudentTeacher;
/// in an iterative conversation.
///
///
-/// See the README.md file in the parent folder (../Declarative/README.md) for detailed
+/// See the README.md file in the parent folder (../README.md) for detailed
/// information the configuration required to run this sample.
///
internal sealed class Program
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/StudentTeacher/StudentTeacher.csproj b/dotnet/samples/GettingStarted/Workflows/Declarative/StudentTeacher/StudentTeacher.csproj
index dae5bbef1f..7c210d6f96 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/StudentTeacher/StudentTeacher.csproj
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/StudentTeacher/StudentTeacher.csproj
@@ -28,6 +28,7 @@
+
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/ToolApproval/Program.cs b/dotnet/samples/GettingStarted/Workflows/Declarative/ToolApproval/Program.cs
index 01be1abfd5..736edadf8d 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/ToolApproval/Program.cs
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/ToolApproval/Program.cs
@@ -14,7 +14,7 @@ namespace Demo.Workflows.Declarative.ToolApproval;
/// has an MCP tool that requires approval. Exits the loop when the user enters "exit".
///
///
-/// See the README.md file in the parent folder (../Declarative/README.md) for detailed
+/// See the README.md file in the parent folder (../README.md) for detailed
/// information the configuration required to run this sample.
///
internal sealed class Program
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/ToolApproval/ToolApproval.csproj b/dotnet/samples/GettingStarted/Workflows/Declarative/ToolApproval/ToolApproval.csproj
index 5d5a013a33..6fa1cf12d9 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/ToolApproval/ToolApproval.csproj
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/ToolApproval/ToolApproval.csproj
@@ -28,6 +28,7 @@
+
diff --git a/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunOptions.cs b/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunOptions.cs
index c6a64915cf..7262979207 100644
--- a/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunOptions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunOptions.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
+using Microsoft.Extensions.AI;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI;
@@ -32,6 +33,7 @@ public class AgentRunOptions
_ = Throw.IfNull(options);
this.ContinuationToken = options.ContinuationToken;
this.AllowBackgroundResponses = options.AllowBackgroundResponses;
+ this.AdditionalProperties = options.AdditionalProperties?.Clone();
}
///
@@ -74,4 +76,18 @@ public class AgentRunOptions
///
///
public bool? AllowBackgroundResponses { get; set; }
+
+ ///
+ /// Gets or sets additional properties associated with these options.
+ ///
+ ///
+ /// An containing custom properties,
+ /// or if no additional properties are present.
+ ///
+ ///
+ /// Additional properties provide a way to include custom metadata or provider-specific
+ /// information that doesn't fit into the standard options schema. This is useful for
+ /// preserving implementation-specific details or extending the options with custom data.
+ ///
+ public AdditionalPropertiesDictionary? AdditionalProperties { get; set; }
}
diff --git a/dotnet/src/Microsoft.Agents.AI.AzureAI/AgentsClientExtensions.cs b/dotnet/src/Microsoft.Agents.AI.AzureAI/AgentsClientExtensions.cs
index 6261cac4ef..38f33bf230 100644
--- a/dotnet/src/Microsoft.Agents.AI.AzureAI/AgentsClientExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.AzureAI/AgentsClientExtensions.cs
@@ -136,7 +136,7 @@ public static class AgentClientExtensions
///
/// The client used to interact with Azure AI Agents. Cannot be .
/// The agent version to be converted. Cannot be .
- /// The tools to use when interacting with the agent. This is required when using prompt agent definitions with tools.
+ /// In-process invocable tools to be provided. If no tools are provided manual handling will be necessary to invoke in-process tools.
/// Provides a way to customize the creation of the underlying used by the agent.
/// An optional for configuring the underlying OpenAI client.
/// An optional to use for resolving services required by the instances being invoked.
@@ -156,7 +156,7 @@ public static class AgentClientExtensions
Throw.IfNull(agentClient);
Throw.IfNull(agentVersion);
- ValidateUsingToolsParameter(agentVersion, tools);
+ var allowDeclarativeMode = tools is not { Count: > 0 };
return CreateChatClientAgent(
agentClient,
@@ -164,7 +164,7 @@ public static class AgentClientExtensions
tools,
clientFactory,
openAIClientOptions,
- requireInvocableTools: true,
+ !allowDeclarativeMode,
services);
}
@@ -293,7 +293,6 @@ public static class AgentClientExtensions
new AgentVersionCreationOptions(new PromptAgentDefinition(model) { Instructions = instructions }) { Description = description },
clientFactory,
openAIClientOptions,
- requireInvocableTools: true,
services,
cancellationToken);
}
@@ -339,7 +338,6 @@ public static class AgentClientExtensions
new AgentVersionCreationOptions(new PromptAgentDefinition(model) { Instructions = instructions }) { Description = description },
clientFactory,
openAIClientOptions,
- requireInvocableTools: true,
services,
cancellationToken);
}
@@ -381,7 +379,7 @@ public static class AgentClientExtensions
Instructions = options.Instructions,
};
- ApplyToolsToAgentDefinition(agentDefinition, options.ChatOptions?.Tools, RequireInvocableTools);
+ ApplyToolsToAgentDefinition(agentDefinition, options.ChatOptions?.Tools);
AgentVersionCreationOptions? creationOptions = new(agentDefinition);
if (!string.IsNullOrWhiteSpace(options.Description))
@@ -440,7 +438,7 @@ public static class AgentClientExtensions
Instructions = options.Instructions,
};
- ApplyToolsToAgentDefinition(agentDefinition, options.ChatOptions?.Tools, RequireInvocableTools);
+ ApplyToolsToAgentDefinition(agentDefinition, options.ChatOptions?.Tools);
AgentVersionCreationOptions? creationOptions = new(agentDefinition);
if (!string.IsNullOrWhiteSpace(options.Description))
@@ -489,16 +487,13 @@ public static class AgentClientExtensions
Throw.IfNullOrWhitespace(name);
Throw.IfNull(creationOptions);
- var tools = (creationOptions.Definition as PromptAgentDefinition)?.Tools.Select(t => t.AsAITool()).ToList();
-
return CreateAIAgent(
agentClient,
name,
- tools,
+ tools: null,
creationOptions,
clientFactory,
openAIClientOptions,
- requireInvocableTools: false,
services: null,
cancellationToken);
}
@@ -531,16 +526,13 @@ public static class AgentClientExtensions
Throw.IfNull(agentClient);
Throw.IfNull(creationOptions);
- var tools = (creationOptions.Definition as PromptAgentDefinition)?.Tools.Select(t => t.AsAITool()).ToList();
-
return CreateAIAgentAsync(
agentClient,
name,
- tools,
+ tools: null,
creationOptions,
clientFactory,
openAIClientOptions,
- requireInvocableTools: false,
services: null,
cancellationToken);
}
@@ -594,7 +586,6 @@ public static class AgentClientExtensions
AgentVersionCreationOptions creationOptions,
Func? clientFactory,
OpenAIClientOptions? openAIClientOptions,
- bool requireInvocableTools,
IServiceProvider? services,
CancellationToken cancellationToken)
{
@@ -602,9 +593,12 @@ public static class AgentClientExtensions
Throw.IfNullOrWhitespace(name);
Throw.IfNull(creationOptions);
- tools ??= (creationOptions.Definition as PromptAgentDefinition)?.Tools.Select(t => t.AsAITool()).ToList();
+ var allowDeclarativeMode = tools is not { Count: > 0 };
- ApplyToolsToAgentDefinition(creationOptions.Definition, tools, requireInvocableTools);
+ if (!allowDeclarativeMode)
+ {
+ ApplyToolsToAgentDefinition(creationOptions.Definition, tools);
+ }
AgentVersion agentVersion = CreateAgentVersionWithProtocol(agentClient, name, creationOptions, cancellationToken);
@@ -614,7 +608,7 @@ public static class AgentClientExtensions
tools,
clientFactory,
openAIClientOptions,
- requireInvocableTools,
+ !allowDeclarativeMode,
services);
}
@@ -625,7 +619,6 @@ public static class AgentClientExtensions
AgentVersionCreationOptions creationOptions,
Func? clientFactory,
OpenAIClientOptions? openAIClientOptions,
- bool requireInvocableTools,
IServiceProvider? services,
CancellationToken cancellationToken)
{
@@ -633,9 +626,12 @@ public static class AgentClientExtensions
Throw.IfNull(agentClient);
Throw.IfNull(creationOptions);
- tools ??= (creationOptions.Definition as PromptAgentDefinition)?.Tools.Select(t => t.AsAITool()).ToList();
+ var allowDeclarativeMode = tools is not { Count: > 0 };
- ApplyToolsToAgentDefinition(creationOptions.Definition, tools, requireInvocableTools);
+ if (!allowDeclarativeMode)
+ {
+ ApplyToolsToAgentDefinition(creationOptions.Definition, tools);
+ }
AgentVersion agentVersion = await CreateAgentVersionWithProtocolAsync(agentClient, name, creationOptions, cancellationToken).ConfigureAwait(false);
@@ -645,7 +641,7 @@ public static class AgentClientExtensions
tools,
clientFactory,
openAIClientOptions,
- requireInvocableTools,
+ !allowDeclarativeMode,
services);
}
@@ -719,14 +715,11 @@ public static class AgentClientExtensions
// Check function tools
foreach (ResponseTool responseTool in definitionTools)
{
- if (responseTool is FunctionTool functionTool)
+ if (requireInvocableTools && responseTool is FunctionTool functionTool)
{
// Check if a tool with the same type and name exists in the provided tools.
- var matchingTool = chatOptions?.Tools?.FirstOrDefault(t =>
- requireInvocableTools
- ? t is AIFunction tf && functionTool.FunctionName == tf.Name // When invocable tools are required, match only AIFunction.
- : (t is AIFunctionDeclaration tfd && functionTool.FunctionName == tfd.Name) ? true // When not required, match AIFunctionDeclaration OR
- : (t.GetService() is FunctionTool ft && functionTool.FunctionName == ft.FunctionName)); // Match a FunctionTool converted AsAITool.
+ // When invocable tools are required, match only AIFunction.
+ var matchingTool = chatOptions?.Tools?.FirstOrDefault(t => t is AIFunction tf && functionTool.FunctionName == tf.Name);
if (matchingTool is null)
{
@@ -742,7 +735,7 @@ public static class AgentClientExtensions
(agentTools ??= []).Add(responseTool.AsAITool());
}
- if (missingTools is { Count: > 0 })
+ if (requireInvocableTools && missingTools is { Count: > 0 })
{
throw new InvalidOperationException($"The following prompt agent definition required tools were not provided: {string.Join(", ", missingTools)}");
}
@@ -796,35 +789,14 @@ public static class AgentClientExtensions
return agentOptions;
}
- /// For already created agent versions, retrieve the definition and validate the tools parameter.
- /// cannot be used. The parameter should be used instead.
- ///
- /// Because doesn't support in-proc tools (only declarative/definitions),
- /// the parameter needs to be the single source of truth for tools, and must be provided when using tools.
- ///
- private static void ValidateUsingToolsParameter(AgentVersion agentVersion, IList? tools)
- {
- if (agentVersion.Definition is PromptAgentDefinition { Tools.Count: > 0 } && tools is null or { Count: 0 })
- {
- throw new ArgumentException("When retrieving prompt agents with tools the tools parameter needs to be provided with the necessary tools.", nameof(tools));
- }
- }
-
///
- /// Adds the specified AI tools to a prompt agent definition, ensuring that all tools are compatible and, if required, invocable.
+ /// Adds the specified AI tools to a prompt agent definition, while also ensuring that all invocable tools are provided.
///
- /// This method ensures that only compatible and properly constructed tools are added to the agent definition.
- /// When is , all tools must be
- /// invocable AIFunctions, which can be created using AIFunctionFactory.Create. Tools are converted to ResponseTool
- /// instances before being added.
/// The agent definition to which the tools will be applied. Must be a PromptAgentDefinition to support tools.
/// A list of AI tools to add to the agent definition. If null or empty, no tools are added.
- /// Indicates whether all provided tools must be invocable AI functions. If set to , only
- /// invocable AIFunctions are accepted.
- /// Thrown if is not a .
- /// Thrown if is and a tool is an
- /// that is not invocable, or if a tool cannot be converted to a .
- private static void ApplyToolsToAgentDefinition(AgentDefinition agentDefinition, IList? tools, bool requireInvocableTools)
+ /// Thrown if tools were provided but is not a .
+ /// When providing functions, they need to be invokable AIFunctions.
+ private static void ApplyToolsToAgentDefinition(AgentDefinition agentDefinition, IList? tools)
{
if (tools is { Count: > 0 })
{
@@ -833,10 +805,14 @@ public static class AgentClientExtensions
throw new ArgumentException("Only prompt agent definitions support tools.", nameof(agentDefinition));
}
+ // When tools are provided, those should represent the complete set of tools for the agent definition.
+ // This is particularly important for existing agents so no duplication happens for what was already defined.
+ promptAgentDefinition.Tools.Clear();
+
foreach (var tool in tools)
{
// Ensure that any AIFunctions provided are In-Proc, not just the declarations.
- if (requireInvocableTools && tool is not AIFunction && (
+ if (tool is not AIFunction && (
tool.GetService() is not null // Declarative FunctionTool converted as AsAITool()
|| tool is AIFunctionDeclaration)) // AIFunctionDeclaration type
{
diff --git a/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/ChatCompletions/Models/Tool.cs b/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/ChatCompletions/Models/Tool.cs
index 87b0637b9b..412494eeaa 100644
--- a/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/ChatCompletions/Models/Tool.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/ChatCompletions/Models/Tool.cs
@@ -160,5 +160,5 @@ internal sealed record CustomToolFormat
/// Additional format properties (schema definition).
///
[JsonExtensionData]
- public Dictionary? AdditionalProperties { get; init; }
+ public Dictionary? AdditionalProperties { get; set; }
}
diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/AzureAgentProvider.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative.AzureAI/AzureAgentProvider.cs
similarity index 88%
rename from dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/AzureAgentProvider.cs
rename to dotnet/src/Microsoft.Agents.AI.Workflows.Declarative.AzureAI/AzureAgentProvider.cs
index d2f19aeb27..6bc72f45c8 100644
--- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/AzureAgentProvider.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative.AzureAI/AzureAgentProvider.cs
@@ -7,6 +7,7 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
+using System.Text.Json.Nodes;
using System.Threading;
using System.Threading.Tasks;
using Azure.AI.Agents;
@@ -32,6 +33,11 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
private AgentClient? _agentClient;
private ConversationClient? _conversationClient;
+ ///
+ /// Optional options used when creating the .
+ ///
+ public AgentClientOptions? ClientOptions { get; init; }
+
///
public override async Task CreateConversationAsync(CancellationToken cancellationToken = default)
{
@@ -78,10 +84,11 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
string? agentVersion,
string? conversationId,
IEnumerable? messages,
+ IDictionary? inputArguments,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
- AgentVersion agentDefinition = await this.QueryAgentAsync(agentId, agentVersion, cancellationToken).ConfigureAwait(false);
- AIAgent agent = await this.GetAgentAsync(agentDefinition, cancellationToken).ConfigureAwait(false);
+ AgentVersion agentVersionResult = await this.QueryAgentAsync(agentId, agentVersion, cancellationToken).ConfigureAwait(false);
+ AIAgent agent = await this.GetAgentAsync(agentVersionResult, cancellationToken).ConfigureAwait(false);
ChatOptions chatOptions =
new()
@@ -90,6 +97,14 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
AllowMultipleToolCalls = this.AllowMultipleToolCalls,
};
+ if (inputArguments is not null)
+ {
+ JsonNode jsonNode = ConvertDictionaryToJson(inputArguments);
+ ResponseCreationOptions responseCreationOptions = new();
+ responseCreationOptions.SetStructuredInputs(BinaryData.FromString(jsonNode.ToJsonString()));
+ chatOptions.RawRepresentationFactory = (_) => responseCreationOptions;
+ }
+
ChatClientAgentRunOptions runOptions = new(chatOptions);
IAsyncEnumerable agentResponse =
@@ -99,7 +114,7 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
await foreach (AgentRunResponseUpdate update in agentResponse.ConfigureAwait(false))
{
- update.AuthorName = agentDefinition.Name;
+ update.AuthorName = agentVersionResult.Name;
yield return update;
}
}
@@ -146,16 +161,7 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
AgentClient client = this.GetAgentClient();
- IList? tools = null;
- if (agentVersion.Definition is PromptAgentDefinition promptAgent)
- {
- tools =
- promptAgent.Tools
- .Select(tool => tool.AsAITool())
- .ToArray();
- }
-
- agent = client.GetAIAgent(agentVersion, tools, clientFactory: null, openAIClientOptions: null, services: null, cancellationToken);
+ agent = client.GetAIAgent(agentVersion, tools: null, clientFactory: null, openAIClientOptions: null, services: null, cancellationToken);
FunctionInvokingChatClient? functionInvokingClient = agent.GetService();
if (functionInvokingClient is not null)
@@ -215,7 +221,7 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
{
if (this._agentClient is null)
{
- AgentClientOptions clientOptions = new();
+ AgentClientOptions clientOptions = this.ClientOptions ?? new();
if (httpClient is not null)
{
diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative.AzureAI/Microsoft.Agents.AI.Workflows.Declarative.AzureAI.csproj b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative.AzureAI/Microsoft.Agents.AI.Workflows.Declarative.AzureAI.csproj
new file mode 100644
index 0000000000..c43c28aaf4
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative.AzureAI/Microsoft.Agents.AI.Workflows.Declarative.AzureAI.csproj
@@ -0,0 +1,41 @@
+
+
+
+ $(ProjectsTargetFrameworks)
+ $(ProjectsDebugTargetFrameworks)
+ preview
+ $(NoWarn);MEAI001;OPENAI001
+
+
+
+ true
+ true
+ true
+
+
+
+
+
+
+ Microsoft Agent Framework Declarative Workflows Azure AI
+ Provides Microsoft Agent Framework support for declarative workflows for Azure AI Agents.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/AgentProviderExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/AgentProviderExtensions.cs
index 170d5a52a9..037665e8b8 100644
--- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/AgentProviderExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/AgentProviderExtensions.cs
@@ -17,9 +17,10 @@ internal static class AgentProviderExtensions
string? conversationId,
bool autoSend,
IEnumerable? inputMessages = null,
+ IDictionary? inputArguments = null,
CancellationToken cancellationToken = default)
{
- IAsyncEnumerable agentUpdates = agentProvider.InvokeAgentAsync(agentName, null, conversationId, inputMessages, cancellationToken);
+ IAsyncEnumerable agentUpdates = agentProvider.InvokeAgentAsync(agentName, null, conversationId, inputMessages, inputArguments, cancellationToken);
// Enable "autoSend" behavior if this is the workflow conversation.
bool isWorkflowConversation = context.IsWorkflowConversation(conversationId, out string? workflowConversationId);
diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/FormulaValueExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/FormulaValueExtensions.cs
index 108dca7682..3e397f3e87 100644
--- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/FormulaValueExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/FormulaValueExtensions.cs
@@ -163,6 +163,24 @@ internal static class FormulaValueExtensions
}
}
}
+
+ public static JsonNode ToJson(this FormulaValue value) =>
+ value switch
+ {
+ BooleanValue booleanValue => JsonValue.Create(booleanValue.Value),
+ DecimalValue decimalValue => JsonValue.Create(decimalValue.Value),
+ NumberValue numberValue => JsonValue.Create(numberValue.Value),
+ DateValue dateValue => JsonValue.Create(dateValue.GetConvertedValue(TimeZoneInfo.Utc)),
+ DateTimeValue datetimeValue => JsonValue.Create(datetimeValue.GetConvertedValue(TimeZoneInfo.Utc)),
+ TimeValue timeValue => JsonValue.Create($"{timeValue.Value}"),
+ StringValue stringValue => JsonValue.Create(stringValue.Value),
+ GuidValue guidValue => JsonValue.Create(guidValue.Value),
+ RecordValue recordValue => recordValue.ToJson(),
+ TableValue tableValue => tableValue.ToJson(),
+ BlankValue => JsonValue.Create(string.Empty),
+ _ => $"[{value.GetType().Name}]",
+ };
+
public static RecordValue ToRecord(this Dictionary value) =>
FormulaValue.NewRecordFromFields(
value.Select(
@@ -256,23 +274,6 @@ internal static class FormulaValueExtensions
private static KeyValuePair GetKeyValuePair(this NamedValue value) => new(value.Name, value.Value.ToDataValue());
- private static JsonNode ToJson(this FormulaValue value) =>
- value switch
- {
- BooleanValue booleanValue => JsonValue.Create(booleanValue.Value),
- DecimalValue decimalValue => JsonValue.Create(decimalValue.Value),
- NumberValue numberValue => JsonValue.Create(numberValue.Value),
- DateValue dateValue => JsonValue.Create(dateValue.GetConvertedValue(TimeZoneInfo.Utc)),
- DateTimeValue datetimeValue => JsonValue.Create(datetimeValue.GetConvertedValue(TimeZoneInfo.Utc)),
- TimeValue timeValue => JsonValue.Create($"{timeValue.Value}"),
- StringValue stringValue => JsonValue.Create(stringValue.Value),
- GuidValue guidValue => JsonValue.Create(guidValue.Value),
- RecordValue recordValue => recordValue.ToJson(),
- TableValue tableValue => tableValue.ToJson(),
- BlankValue => JsonValue.Create(string.Empty),
- _ => $"[{value.GetType().Name}]",
- };
-
private static JsonArray ToJson(this TableValue value)
{
return new([.. GetJsonElements()]);
diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Kit/AgentExecutor.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Kit/AgentExecutor.cs
index 9e6a6884b6..45a5b47bd8 100644
--- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Kit/AgentExecutor.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Kit/AgentExecutor.cs
@@ -33,5 +33,5 @@ public abstract class AgentExecutor(string id, FormulaSession session, WorkflowA
bool autoSend,
IEnumerable? inputMessages = null,
CancellationToken cancellationToken = default)
- => agentProvider.InvokeAgentAsync(this.Id, context, agentName, conversationId, autoSend, inputMessages, cancellationToken);
+ => agentProvider.InvokeAgentAsync(this.Id, context, agentName, conversationId, autoSend, inputMessages, inputArguments: null, cancellationToken);
}
diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Microsoft.Agents.AI.Workflows.Declarative.csproj b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Microsoft.Agents.AI.Workflows.Declarative.csproj
index 17ce9f6c4f..1f466aac4e 100644
--- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Microsoft.Agents.AI.Workflows.Declarative.csproj
+++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Microsoft.Agents.AI.Workflows.Declarative.csproj
@@ -22,7 +22,6 @@
-
@@ -34,7 +33,6 @@
-
diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/InvokeAzureAgentExecutor.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/InvokeAzureAgentExecutor.cs
index cafece9a57..ed069a9b78 100644
--- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/InvokeAzureAgentExecutor.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/InvokeAzureAgentExecutor.cs
@@ -60,8 +60,8 @@ internal sealed class InvokeAzureAgentExecutor(InvokeAzureAgent model, WorkflowA
string? conversationId = this.GetConversationId();
string agentName = this.GetAgentName();
bool autoSend = this.GetAutoSendValue();
-
- AgentRunResponse agentResponse = await agentProvider.InvokeAgentAsync(this.Id, context, agentName, conversationId, autoSend, messages, cancellationToken).ConfigureAwait(false);
+ Dictionary? inputParameters = this.GetStructuredInputs();
+ AgentRunResponse agentResponse = await agentProvider.InvokeAgentAsync(this.Id, context, agentName, conversationId, autoSend, messages, inputParameters, cancellationToken).ConfigureAwait(false);
ChatMessage[] actionableMessages = FilterActionableContent(agentResponse).ToArray();
if (actionableMessages.Length > 0)
@@ -107,6 +107,23 @@ internal sealed class InvokeAzureAgentExecutor(InvokeAzureAgent model, WorkflowA
await context.SendResultMessageAsync(this.Id, result: null, cancellationToken).ConfigureAwait(false);
}
+ private Dictionary? GetStructuredInputs()
+ {
+ Dictionary? inputs = null;
+
+ if (this.AgentInput?.Arguments is not null)
+ {
+ inputs = [];
+
+ foreach (KeyValuePair argument in this.AgentInput.Arguments)
+ {
+ inputs[argument.Key] = this.Evaluator.GetValue(argument.Value).Value.ToObject();
+ }
+ }
+
+ return inputs;
+ }
+
private IEnumerable? GetInputMessages()
{
DataValue? userInput = null;
diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/SetVariableExecutor.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/SetVariableExecutor.cs
index 449e982982..81ed6e30d3 100644
--- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/SetVariableExecutor.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/SetVariableExecutor.cs
@@ -8,7 +8,6 @@ using Microsoft.Agents.AI.Workflows.Declarative.PowerFx;
using Microsoft.Bot.ObjectModel;
using Microsoft.Bot.ObjectModel.Abstractions;
using Microsoft.PowerFx.Types;
-using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Workflows.Declarative.ObjectModel;
@@ -17,17 +16,15 @@ internal sealed class SetVariableExecutor(SetVariable model, WorkflowFormulaStat
{
protected override async ValueTask