Skip to content

Commit 6d0f28e

Browse files
crickmanCopilot
andauthored
.NET Workflows - Re-enable Declarative Integration Tests (#1080)
* Investigate * Next * Update initialization * Should be ok * Agent definition dx * Link agent definitions * Link agent definitions * Path resolution #2 * Fix path resolution * Another pass * Another * Better * One more * Whoopsie * Update dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/Framework/AgentFactory.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Namespace * Cleanup * Temp config for pipeline * Another temp workaround * Test config: Bing Grounding Tool * Update template * Next pass * Ok now * Cleanup * Test note --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 9a59b86 commit 6d0f28e

File tree

23 files changed

+83
-54
lines changed

23 files changed

+83
-54
lines changed

.github/workflows/dotnet-build-and-test.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ jobs:
5454
.
5555
.github
5656
dotnet
57+
workflow-samples
5758
- name: Setup dotnet
5859
uses: actions/setup-dotnet@v5.0.0
5960
with:
@@ -136,6 +137,10 @@ jobs:
136137
# Azure AI Foundry
137138
AzureAI__Endpoint: ${{ secrets.AZUREAI__ENDPOINT }}
138139
AzureAI__DeploymentName: ${{ vars.AZUREAI__DEPLOYMENTNAME }}
140+
AzureAI__BingConnectionId: ${{ vars.AZUREAI__BINGCONECTIONID }}
141+
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
142+
FOUNDRY_MODEL_DEPLOYMENT_NAME: ${{ vars.FOUNDRY_MODEL_DEPLOYMENT_NAME }}
143+
FOUNDRY_CONNECTION_GROUNDING_TOOL: ${{ vars.FOUNDRY_CONNECTION_GROUNDING_TOOL }}
139144

140145
# Generate test reports and check coverage
141146
- name: Generate test reports

dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ Before you begin, ensure you have the following prerequisites:
1111
Set the following environment variables:
1212

1313
```powershell
14-
$env:AZURE_FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project" # Replace with your Azure Foundry resource endpoint
15-
$env:AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini
14+
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project" # Replace with your Azure Foundry resource endpoint
15+
$env:FOUNDRY_MODEL_DEPLOYMENT_NAME="gpt-4.1-mini" # Optional, defaults to gpt-4.1-mini
1616
```

dotnet/samples/GettingStarted/Workflows/Declarative/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace Demo.DeclarativeWorkflow;
1717
/// </summary>
1818
/// <remarks>
1919
/// <b>Configuration</b>
20-
/// Define AZURE_FOUNDRY_PROJECT_ENDPOINT as a user-secret or environment variable that
20+
/// Define FOUNDRY_PROJECT_ENDPOINT as a user-secret or environment variable that
2121
/// points to your Foundry project endpoint.
2222
/// <b>Usage</b>
2323
/// Provide the path to the workflow definition file as the first argument.

dotnet/samples/GettingStarted/Workflows/Declarative/README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,13 @@ To set your secrets with .NET Secret Manager:
4242
4. Define setting that identifies your Azure Foundry Project (endpoint):
4343
4444
```
45-
dotnet user-secrets set "AZURE_FOUNDRY_PROJECT_ENDPOINT" "https://..."
45+
dotnet user-secrets set "FOUNDRY_PROJECT_ENDPOINT" "https://..."
46+
```
47+
48+
5. Define setting that identifies your Azure Foundry Model Deployment (endpoint):
49+
50+
```
51+
dotnet user-secrets set "FOUNDRY_MODEL_DEPLOYMENT_NAME" "https://..."
4652
```
4753
4854
#### Authorization
@@ -61,7 +67,7 @@ The sample workflows rely on agents defined in your Azure Foundry Project.
6167
To create agents, run the [`Create.ps1`](../../../../../workflow-samples/setup/) script.
6268
This will create the agents used in the sample workflows in your Azure Foundry Project and format a script you can copy and use to configure your environment.
6369
64-
> Note: `Create.ps1` relies upon the `AZURE_FOUNDRY_PROJECT_ENDPOINT` setting.
70+
> Note: `Create.ps1` relies upon the `FOUNDRY_PROJECT_ENDPOINT` and `FOUNDRY_MODEL_DEPLOYMENT_NAME` settings.
6571
6672
## Execution
6773

dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/CodeGen/AddConversationMessageTemplate.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,15 @@ public override string TransformText()
5959
"ow new DeclarativeActionException($\"Conversation identifier must be defined: {th" +
6060
"is.Id}\");\n }\n ChatMessage newMessage = new(ChatRole.");
6161
this.Write(this.ToStringHelper.ToStringWithCulture(FormatEnum(this.Model.Role, RoleMap)));
62-
this.Write(", [.. this.GetContentAsync(context).ToEnumerable()]) { AdditionalProperties = thi" +
63-
"s.GetMetadata() };\n await agentProvider.CreateMessageAsync(conversationId" +
64-
", newMessage, cancellationToken).ConfigureAwait(false);");
62+
this.Write(", await this.GetContentAsync(context).ConfigureAwait(false)) { AdditionalProperti" +
63+
"es = this.GetMetadata() };\n await agentProvider.CreateMessageAsync(conver" +
64+
"sationId, newMessage, cancellationToken).ConfigureAwait(false);");
6565

6666
AssignVariable(this.Message, "newMessage");
6767

68-
this.Write("\n return default;\n }\n\n private async IAsyncEnumerable<AIContent> Get" +
69-
"ContentAsync(IWorkflowContext context)\n {");
68+
this.Write("\n return default;\n }\n\n private async ValueTask<IList<AIContent>> Get" +
69+
"ContentAsync(IWorkflowContext context)\n {\n List<AIContent> content = [" +
70+
"];\n ");
7071

7172
int index = 0;
7273
foreach (AddConversationMessageContent content in this.Model.Content)
@@ -76,23 +77,28 @@ public override string TransformText()
7677
AgentMessageContentType contentType = content.Type.Value;
7778
if (contentType == AgentMessageContentType.ImageUrl)
7879
{
79-
this.Write("\n yield return new UriContent(contentValue, \"image/*\");");
80+
this.Write("\n content.Add(UriContent(contentValue");
81+
this.Write(this.ToStringHelper.ToStringWithCulture(index));
82+
this.Write(", \"image/*\"));");
8083

8184
}
8285
else if (contentType == AgentMessageContentType.ImageFile)
8386
{
84-
this.Write("\n yield return new HostedFileContent(contentValue);");
87+
this.Write("\n content.Add(new HostedFileContent(contentValue");
88+
this.Write(this.ToStringHelper.ToStringWithCulture(index));
89+
this.Write("));");
8590

8691
}
8792
else
8893
{
89-
this.Write("\n yield return new TextContent(contentValue");
94+
this.Write("\n content.Add(new TextContent(contentValue");
9095
this.Write(this.ToStringHelper.ToStringWithCulture(index));
91-
this.Write(");");
96+
this.Write("));");
9297

9398
}
9499
}
95-
this.Write("\n }\n\n private AdditionalPropertiesDictionary? GetMetadata()\n {");
100+
this.Write("\n return content;\n }\n\n private AdditionalPropertiesDictionary? GetMe" +
101+
"tadata()\n {");
96102

97103
EvaluateRecordExpression<object>(this.Model.Metadata, "metadata");
98104
this.Write("\n\n if (metadata is null)\n {\n return null; \n }\n" +

dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/CodeGen/AddConversationMessageTemplate.tt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,17 @@ internal sealed class <#= this.Name #>Executor(FormulaSession session, WorkflowA
1616
{
1717
throw new DeclarativeActionException($"Conversation identifier must be defined: {this.Id}");
1818
}
19-
ChatMessage newMessage = new(ChatRole.<#= FormatEnum(this.Model.Role, RoleMap) #>, [.. this.GetContentAsync(context).ToEnumerable()]) { AdditionalProperties = this.GetMetadata() };
19+
ChatMessage newMessage = new(ChatRole.<#= FormatEnum(this.Model.Role, RoleMap) #>, await this.GetContentAsync(context).ConfigureAwait(false)) { AdditionalProperties = this.GetMetadata() };
2020
await agentProvider.CreateMessageAsync(conversationId, newMessage, cancellationToken).ConfigureAwait(false);<#
2121
AssignVariable(this.Message, "newMessage");
2222
#>
2323
return default;
2424
}
2525

26-
private async IAsyncEnumerable<AIContent> GetContentAsync(IWorkflowContext context)
27-
{<#
26+
private async ValueTask<IList<AIContent>> GetContentAsync(IWorkflowContext context)
27+
{
28+
List<AIContent> content = [];
29+
<#
2830
int index = 0;
2931
foreach (AddConversationMessageContent content in this.Model.Content)
3032
{
@@ -33,17 +35,18 @@ internal sealed class <#= this.Name #>Executor(FormulaSession session, WorkflowA
3335
AgentMessageContentType contentType = content.Type.Value;
3436
if (contentType == AgentMessageContentType.ImageUrl)
3537
{#>
36-
yield return new UriContent(contentValue, "image/*");<#
38+
content.Add(UriContent(contentValue<#= index #>, "image/*"));<#
3739
}
3840
else if (contentType == AgentMessageContentType.ImageFile)
3941
{#>
40-
yield return new HostedFileContent(contentValue);<#
42+
content.Add(new HostedFileContent(contentValue<#= index #>));<#
4143
}
4244
else
4345
{#>
44-
yield return new TextContent(contentValue<#= index #>);<#
46+
content.Add(new TextContent(contentValue<#= index #>));<#
4547
}
4648
}#>
49+
return content;
4750
}
4851

4952
private AdditionalPropertiesDictionary? GetMetadata()

dotnet/src/Shared/IntegrationTests/AzureAIConfiguration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ internal sealed class AzureAIConfiguration
1010
public string Endpoint { get; set; }
1111

1212
public string DeploymentName { get; set; }
13+
14+
public string BingConnectionId { get; set; }
1315
}

dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/Agents/TestAgent.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ type: foundry_agent
22
name: BasicAgent
33
description: Basic agent for integration tests
44
model:
5-
id: ${AzureAI:DeploymentMini}
5+
id: ${FOUNDRY_MODEL_DEPLOYMENT_NAME}

dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/AzureAgentProviderTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public sealed class AzureAgentProviderTest(ITestOutputHelper output) : Integrati
1818
{
1919
private AzureAIConfiguration? _configuration;
2020

21-
[Fact(Skip = "Needs configuration")]
21+
[Fact]
2222
public async Task ConversationTestAsync()
2323
{
2424
// Arrange
@@ -48,7 +48,7 @@ public async Task ConversationTestAsync()
4848
Assert.Equal(messages[3].Text, message.Text);
4949
}
5050

51-
[Fact(Skip = "Needs configuration")]
51+
[Fact]
5252
public async Task GetAgentTestAsync()
5353
{
5454
// Arrange

dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/DeclarativeCodeGenTest.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3+
using System;
34
using System.IO;
45
using System.Linq;
56
using System.Threading.Tasks;
@@ -15,17 +16,17 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests;
1516
public sealed class DeclarativeCodeGenTest(ITestOutputHelper output) : WorkflowTest(output)
1617
{
1718
[Theory]
18-
[InlineData("SendActivity.yaml", "SendActivity.json", Skip = "Needs configuration")]
19-
[InlineData("InvokeAgent.yaml", "InvokeAgent.json", Skip = "Needs configuration")]
20-
[InlineData("ConversationMessages.yaml", "ConversationMessages.json", Skip = "Needs configuration")]
19+
[InlineData("SendActivity.yaml", "SendActivity.json")]
20+
[InlineData("InvokeAgent.yaml", "InvokeAgent.json")]
21+
[InlineData("ConversationMessages.yaml", "ConversationMessages.json")]
2122
public Task ValidateCaseAsync(string workflowFileName, string testcaseFileName) =>
22-
this.RunWorkflowAsync(Path.Combine("Workflows", workflowFileName), testcaseFileName);
23+
this.RunWorkflowAsync(Path.Combine(Environment.CurrentDirectory, "Workflows", workflowFileName), testcaseFileName);
2324

2425
[Theory]
25-
[InlineData("Marketing.yaml", "Marketing.json", Skip = "Needs configuration")]
26-
[InlineData("MathChat.yaml", "MathChat.json", Skip = "Needs configuration")]
27-
[InlineData("DeepResearch.yaml", "DeepResearch.json", Skip = "Needs configuration")]
28-
[InlineData("HumanInLoop.yaml", "HumanInLoop.json", Skip = "TODO")]
26+
[InlineData("Marketing.yaml", "Marketing.json")]
27+
[InlineData("MathChat.yaml", "MathChat.json")]
28+
[InlineData("DeepResearch.yaml", "DeepResearch.json", Skip = "Long running")]
29+
[InlineData("HumanInLoop.yaml", "HumanInLoop.json", Skip = "Needs test support")]
2930
public Task ValidateScenarioAsync(string workflowFileName, string testcaseFileName) =>
3031
this.RunWorkflowAsync(Path.Combine(GetRepoFolder(), "workflow-samples", workflowFileName), testcaseFileName);
3132

0 commit comments

Comments
 (0)