From 0fa68836910d1872b97d82d4b4772c9de07cbbe1 Mon Sep 17 00:00:00 2001
From: Chris <66376200+crickman@users.noreply.github.com>
Date: Tue, 9 Sep 2025 15:29:25 -0700
Subject: [PATCH] Clean-up (#677)
---
.../DeclarativeWorkflow.csproj | 33 --
dotnet/samples/DeclarativeWorkflow/Program.cs | 304 ------------------
dotnet/samples/DeclarativeWorkflow/README.md | 88 -----
.../Workflows/Declarative/README.md | 4 +-
4 files changed, 2 insertions(+), 427 deletions(-)
delete mode 100644 dotnet/samples/DeclarativeWorkflow/DeclarativeWorkflow.csproj
delete mode 100644 dotnet/samples/DeclarativeWorkflow/Program.cs
delete mode 100644 dotnet/samples/DeclarativeWorkflow/README.md
diff --git a/dotnet/samples/DeclarativeWorkflow/DeclarativeWorkflow.csproj b/dotnet/samples/DeclarativeWorkflow/DeclarativeWorkflow.csproj
deleted file mode 100644
index ee1a58754c..0000000000
--- a/dotnet/samples/DeclarativeWorkflow/DeclarativeWorkflow.csproj
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
- Exe
- net9.0
- net9.0
- $(ProjectsDebugTargetFrameworks)
- enable
- disable
- 5ee045b0-aea3-4f08-8d31-32d1a6f8fed0
- $(NoWarn);CA1812
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dotnet/samples/DeclarativeWorkflow/Program.cs b/dotnet/samples/DeclarativeWorkflow/Program.cs
deleted file mode 100644
index c480e96c23..0000000000
--- a/dotnet/samples/DeclarativeWorkflow/Program.cs
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading.Tasks;
-using Azure.AI.Agents.Persistent;
-using Azure.Identity;
-using Microsoft.Agents.Workflows;
-using Microsoft.Agents.Workflows.Declarative;
-using Microsoft.Extensions.AI;
-using Microsoft.Extensions.Configuration;
-
-namespace Demo.DeclarativeWorkflow;
-
-///
-/// HOW TO: Create a workflow from a declartive (yaml based) definition.
-///
-///
-/// Configuration
-/// Define FOUNDRY_PROJECT_ENDPOINT as a user-secret or environment variable that
-/// points to your Foundry project endpoint.
-/// Usage
-/// Provide the path to the workflow definition file as the first argument.
-/// All other arguments are intepreted as a queue of inputs.
-/// When no input is queued, interactive input is requested from the console.
-///
-internal sealed class Program
-{
- public static async Task Main(string[] args)
- {
- Program program = new(args);
- await program.ExecuteAsync();
- }
-
- private async Task ExecuteAsync()
- {
- // Read and parse the declarative workflow.
- Notify($"WORKFLOW: Parsing {Path.GetFullPath(this.WorkflowFile)}");
-
- Stopwatch timer = Stopwatch.StartNew();
-
- // Use DeclarativeWorkflowBuilder to build a workflow based on a YAML file.
- DeclarativeWorkflowOptions options =
- new(new FoundryAgentProvider(this.FoundryEndpoint, new AzureCliCredential()))
- {
- Configuration = this.Configuration
- };
- Workflow workflow = DeclarativeWorkflowBuilder.Build(this.WorkflowFile, options);
-
- Notify($"\nWORKFLOW: Defined {timer.Elapsed}");
-
- Notify("\nWORKFLOW: Starting...");
-
- // Run the workflow, just like any other workflow
- string input = this.GetWorkflowInput();
- StreamingRun run = await InProcessExecution.StreamAsync(workflow, input);
- await this.MonitorWorkflowRunAsync(run);
-
- Notify("\nWORKFLOW: Done!");
- }
-
- private const string DefaultWorkflow = "HelloWorld.yaml";
- private const string ConfigKeyFoundryEndpoint = "FOUNDRY_PROJECT_ENDPOINT";
-
- private static readonly Dictionary s_nameCache = [];
- private static readonly HashSet s_fileCache = [];
-
- private string WorkflowFile { get; }
- private string? WorkflowInput { get; }
- private string FoundryEndpoint { get; }
- private PersistentAgentsClient FoundryClient { get; }
- private IConfiguration Configuration { get; }
-
- private Program(string[] args)
- {
- this.WorkflowFile = ParseWorkflowFile(args);
- this.WorkflowInput = ParseWorkflowInput(args);
-
- this.Configuration = InitializeConfig();
-
- this.FoundryEndpoint = this.Configuration[ConfigKeyFoundryEndpoint] ?? throw new InvalidOperationException($"Undefined configuration setting: {ConfigKeyFoundryEndpoint}");
- this.FoundryClient = new PersistentAgentsClient(this.FoundryEndpoint, new AzureCliCredential());
- }
-
- private async Task MonitorWorkflowRunAsync(StreamingRun run)
- {
- string? messageId = null;
-
- await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
- {
- if (evt is ExecutorInvokeEvent executorInvoked)
- {
- Debug.WriteLine($"STEP ENTER #{executorInvoked.ExecutorId}");
- }
- else if (evt is ExecutorCompleteEvent executorComplete)
- {
- Debug.WriteLine($"STEP EXIT #{executorComplete.ExecutorId}");
- }
- else if (evt is ExecutorFailureEvent executorFailure)
- {
- Debug.WriteLine($"STEP ERROR #{executorFailure.ExecutorId}: {executorFailure.Data?.Message ?? "Unknown"}");
- }
- else if (evt is ConversationUpdateEvent invokeEvent)
- {
- Debug.WriteLine($"CONVERSATION: {invokeEvent.Data}");
- }
- else if (evt is AgentRunUpdateEvent streamEvent)
- {
- if (!string.Equals(messageId, streamEvent.Update.MessageId, StringComparison.Ordinal))
- {
- messageId = streamEvent.Update.MessageId;
-
- if (messageId is not null)
- {
- string? agentId = streamEvent.Update.AuthorName;
- if (agentId is not null)
- {
- if (!s_nameCache.TryGetValue(agentId, out string? realName))
- {
- PersistentAgent agent = await this.FoundryClient.Administration.GetAgentAsync(agentId);
- s_nameCache[agentId] = agent.Name;
- realName = agent.Name;
- }
- agentId = realName;
- }
- agentId ??= nameof(ChatRole.Assistant);
- Console.ForegroundColor = ConsoleColor.Cyan;
- Console.Write($"\n{agentId.ToUpperInvariant()}:");
- Console.ForegroundColor = ConsoleColor.DarkGray;
- Console.WriteLine($" [{messageId}]");
- }
- }
-
- ChatResponseUpdate? chatUpdate = streamEvent.Update.RawRepresentation as ChatResponseUpdate;
- switch (chatUpdate?.RawRepresentation)
- {
- case MessageContentUpdate messageUpdate:
- string? fileId = messageUpdate.ImageFileId ?? messageUpdate.TextAnnotation?.OutputFileId;
- if (fileId is not null && s_fileCache.Add(fileId))
- {
- BinaryData content = await this.FoundryClient.Files.GetFileContentAsync(fileId);
- await DownloadFileContentAsync(Path.GetFileName(messageUpdate.TextAnnotation?.TextToReplace ?? "response.png"), content);
- }
- break;
- }
- try
- {
- Console.ResetColor();
- Console.Write(streamEvent.Data);
- }
- finally
- {
- Console.ResetColor();
- }
- }
- else if (evt is AgentRunResponseEvent messageEvent)
- {
- try
- {
- Console.WriteLine();
- if (messageEvent.Response.AgentId is null)
- {
- Console.ForegroundColor = ConsoleColor.Cyan;
- Console.WriteLine("ACTIVITY:");
- Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine(messageEvent.Response?.Text.Trim());
- }
- else
- {
- if (messageEvent.Response.Usage is not null)
- {
- Console.ForegroundColor = ConsoleColor.DarkGray;
- Console.WriteLine($"[Tokens Total: {messageEvent.Response.Usage.TotalTokenCount}, Input: {messageEvent.Response.Usage.InputTokenCount}, Output: {messageEvent.Response.Usage.OutputTokenCount}]");
- }
- }
- }
- finally
- {
- Console.ResetColor();
- }
- }
- }
- }
-
- private static string ParseWorkflowFile(string[] args)
- {
- string workflowFile = args.FirstOrDefault() ?? DefaultWorkflow;
-
- if (!File.Exists(workflowFile) && !Path.IsPathFullyQualified(workflowFile))
- {
- string? repoFolder = GetRepoFolder();
- if (repoFolder is not null)
- {
- workflowFile = Path.Combine(repoFolder, "Workflows", workflowFile);
- workflowFile = Path.ChangeExtension(workflowFile, ".yaml");
- }
- }
-
- if (!File.Exists(workflowFile))
- {
- throw new InvalidOperationException($"Unable to locate workflow: {Path.GetFullPath(workflowFile)}.");
- }
-
- return workflowFile;
-
- static string? GetRepoFolder()
- {
- DirectoryInfo? current = new(Directory.GetCurrentDirectory());
-
- while (current is not null)
- {
- if (Directory.Exists(Path.Combine(current.FullName, ".git")))
- {
- return current.FullName;
- }
-
- current = current.Parent;
- }
-
- return null;
- }
- }
-
- private string GetWorkflowInput()
- {
- string? input = this.WorkflowInput;
-
- try
- {
- Console.ForegroundColor = ConsoleColor.DarkGreen;
-
- Console.Write("\nINPUT: ");
-
- Console.ForegroundColor = ConsoleColor.White;
-
- if (!string.IsNullOrWhiteSpace(input))
- {
- Console.WriteLine(input);
- return input;
- }
- while (string.IsNullOrWhiteSpace(input))
- {
- input = Console.ReadLine();
- }
-
- return input.Trim();
- }
- finally
- {
- Console.ResetColor();
- }
- }
-
- private static string? ParseWorkflowInput(string[] args)
- {
- if (args.Length == 0)
- {
- return null;
- }
-
- string[] workflowInput = [.. args.Skip(1)];
-
- return workflowInput.FirstOrDefault();
- }
-
- // Load configuration from user-secrets
- private static IConfigurationRoot InitializeConfig() =>
- new ConfigurationBuilder()
- .AddUserSecrets(Assembly.GetExecutingAssembly())
- .AddEnvironmentVariables()
- .Build();
-
- private static void Notify(string message)
- {
- Console.ForegroundColor = ConsoleColor.Cyan;
- try
- {
- Console.WriteLine(message);
- }
- finally
- {
- Console.ResetColor();
- }
- }
-
- private static async ValueTask DownloadFileContentAsync(string filename, BinaryData content)
- {
- string filePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(filename));
- filePath = Path.ChangeExtension(filePath, ".png");
-
- await File.WriteAllBytesAsync(filePath, content.ToArray());
-
- Process.Start(
- new ProcessStartInfo
- {
- FileName = "cmd.exe",
- Arguments = $"/C start {filePath}"
- });
- }
-}
diff --git a/dotnet/samples/DeclarativeWorkflow/README.md b/dotnet/samples/DeclarativeWorkflow/README.md
deleted file mode 100644
index 5229bd50c2..0000000000
--- a/dotnet/samples/DeclarativeWorkflow/README.md
+++ /dev/null
@@ -1,88 +0,0 @@
-# Summary
-
-This demo showcases the ability to parse a declarative Foundry Workflow file (YAML) to build a `Workflow<>`
-be executed using the same pattern as any code-based workflow.
-
-## Configuration
-
-This demo requires configuration to access agents an [Azure Foundry Project](https://learn.microsoft.com/azure/ai-foundry).
-
-#### Settings
-
-We suggest using .NET [Secret Manager](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets)
-to avoid the risk of leaking secrets into the repository, branches and pull requests.
-You can also use environment variables if you prefer.
-
-To set your secrets as an environment variable (PowerShell):
-
-```pwsh
-$env:FOUNDRY_PROJECT_ENDPOINT="https://..."
-```
-
-To set your secrets with .NET Secret Manager:
-
-1. From the root of the respository, navigate the console to the project folder:
-
- ```
- cd dotnet/demos/DeclarativeWorkflow
- ```
-
-2. Examine existing secret definitions:
-
- ```
- dotnet user-secrets list
- ```
-
-3. If needed, perform first time initialization:
-
- ```
- dotnet user-secrets init
- ```
-
-4. Define setting that identifies your Azure Foundry Project (endpoint):
-
- ```
- dotnet user-secrets set "FOUNDRY_PROJECT_ENDPOINT" "https://..."
- ```
-
-#### Authorization
-
-Use [_Azure CLI_](https://learn.microsoft.com/cli/azure/authenticate-azure-cli) to authorize access to your Azure Foundry Project:
-
- ```
- az login
- az account get-access-token
- ```
-
-#### Agents
-
-The sample workflows rely on agents defined in your Azure Foundry Project.
-
-To create agents, run the [`Create.ps1`](../../../workflows/) script.
-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.
-
-> Note: `Create.ps1` relies upon the `FOUNDRY_PROJECT_ENDPOINT` setting.
-
-## Execution
-
-Run the demo from the console by specifying a path to a declarative (YAML) workflow file.
-The repository has example workflows available in the root [`/workflows`](../../../workflows) folder.
-
-1. From the root of the respository, navigate the console to the project folder:
-
- ```sh
- cd dotnet/demos/DeclarativeWorkflow
-
- ```
-
-2. Run the demo referencing a sample workflow by name:
-
- ```sh
- dotnet run HelloWorld
- ```
-
-3. Run the demo with a path to any workflow file:
-
- ```sh
- dotnet run c:/myworkflows/HelloWorld.yaml
- ```
diff --git a/dotnet/samples/GettingStarted/Workflows/Declarative/README.md b/dotnet/samples/GettingStarted/Workflows/Declarative/README.md
index 57101c9b21..0ddda6992d 100644
--- a/dotnet/samples/GettingStarted/Workflows/Declarative/README.md
+++ b/dotnet/samples/GettingStarted/Workflows/Declarative/README.md
@@ -24,7 +24,7 @@ To set your secrets with .NET Secret Manager:
1. From the root of the repository, navigate the console to the project folder:
```
- cd dotnet/samples/GettingStarted/Workflows/Declarative
+ cd dotnet/samples/GettingStarted/Workflows/Declarative/DeclarativeWorkflow
```
2. Examine existing secret definitions:
@@ -71,7 +71,7 @@ The repository has example workflows available in the root [`/workflows`](../../
1. From the root of the repository, navigate the console to the project folder:
```sh
- cd dotnet/samples/GettingStarted/Workflows/Declarative
+ cd dotnet/samples/GettingStarted/Workflows/Declarative/DeclarativeWorkflow
```
2. Run the demo referencing a sample workflow by name: