From 7e2a7c5c6cb41df6cdcb7e59614d9e478efbba8b Mon Sep 17 00:00:00 2001 From: Bruno Capuano Date: Sat, 21 Feb 2026 12:43:47 -0500 Subject: [PATCH 01/10] Refactor documentation structure: move CODE_OF_CONDUCT.md, SECURITY.md, and SUPPORT.md to docs/ directory; add GitHub Copilot instructions and .NET modernization plan --- .github/copilot-instructions.md | 35 ++ CODE_OF_CONDUCT.md => docs/CODE_OF_CONDUCT.md | 0 docs/DOTNET_MODERNIZATION_PLAN.md | 402 ++++++++++++++++++ SECURITY.md => docs/SECURITY.md | 0 SUPPORT.md => docs/SUPPORT.md | 50 +-- 5 files changed, 462 insertions(+), 25 deletions(-) create mode 100644 .github/copilot-instructions.md rename CODE_OF_CONDUCT.md => docs/CODE_OF_CONDUCT.md (100%) create mode 100644 docs/DOTNET_MODERNIZATION_PLAN.md rename SECURITY.md => docs/SECURITY.md (100%) rename SUPPORT.md => docs/SUPPORT.md (97%) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..ab66b16 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,35 @@ +# GitHub Copilot Instructions + +## Repository Layout Rules + +### Root-level files +The root of this repository must contain **only**: +- `README.md` — the main repository readme +- `LICENSE` — the license file + +All other documentation, planning documents, and policy files must be placed in the `docs/` folder at the root of the repository. + +### docs/ folder +The `docs/` folder at the root of the repository is the single location for: +- Planning documents (e.g., modernization plans, roadmaps) +- Policy files (e.g., CODE_OF_CONDUCT.md, SECURITY.md, SUPPORT.md) +- Any other repository-wide documentation that is not a `README.md` or `LICENSE` + +**This rule does NOT apply to documentation that belongs to individual samples.** +Each sample folder (e.g., `02.CreateYourFirstAgent/`, `07.Workflow/`, `09.Cases/`) may contain its own `README.md` and any documentation files specific to that sample. + +### Sample folders +Each numbered chapter folder and its sub-folders may freely contain: +- `README.md` +- Sample-specific documentation and assets (images, diagrams, etc.) +- Code files and project files + +### Summary + +| Location | Allowed files | +|---|---| +| Repo root | `README.md`, `LICENSE` only | +| `docs/` | All repo-wide docs, plans, and policy files | +| Any sample/chapter folder | `README.md`, sample-specific docs, code | + +When creating new planning documents, policy files, or repository-wide documentation, always place them in `docs/` — never at the repo root. diff --git a/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to docs/CODE_OF_CONDUCT.md diff --git a/docs/DOTNET_MODERNIZATION_PLAN.md b/docs/DOTNET_MODERNIZATION_PLAN.md new file mode 100644 index 0000000..f51a81d --- /dev/null +++ b/docs/DOTNET_MODERNIZATION_PLAN.md @@ -0,0 +1,402 @@ +# .NET Modernization Plan + +> Generated: 2026-02-21 +> Scope: All .NET projects in this repository +> No changes have been made — this is the plan only. + +--- + +## Executive Summary + +27 of 28 .NET projects **cannot build today** because they contain `` elements pointing to hardcoded absolute paths on the original author's macOS machine (`/Users/lokinfey/Desktop/…`). The one exception (`CreateWorkflowWithYAML`) uses NuGet packages but at severely outdated versions from November 2024. + +Additional systemic issues: +- Every project uses `DotNetEnv` + a `.env` file for secrets — not idiomatic .NET and a security risk in repos. +- No root solution file exists to build all projects together. +- Package versions are inconsistent and mix stable/preview incorrectly. +- Several csproj files use `` (a Central Package Management declaration element) instead of ``, which means those Azure SDK packages are silently not installed. +- Folder and project naming has typos and inconsistent casing (`dotNET` vs `dotnet`, `ExploerAgentFramework`, `framrwork`). + +--- + +## Inventory of All .NET Projects + +| # | Project Path | Provider | Broken (source refs) | `PackageVersion` bug | Notes | +|---|---|---|---|---|---| +| 1 | `00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/` | GitHub Models | ✅ | | | +| 2 | `00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/` | GitHub Models | ✅ | | | +| 3 | `00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/` | GitHub Models | ✅ | | | +| 4 | `00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/` | GitHub Models | ✅ | | | +| 5 | `00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/` | MS Foundry | ✅ | ✅ | `` on Azure.AI.Projects, Azure.AI.Agents.Persistent | +| 6 | `00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/` | GitHub Models | ✅ | | Folder name typo: `framrwork` | +| 7 | `00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/` | GitHub Models | ✅ | | | +| 8 | `02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/` | GitHub Models | ✅ | | | +| 9 | `03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/` | Azure OpenAI | ✅ | | Chapter folder name typo: `ExploerAgentFramework` | +| 10 | `03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/` | GitHub Models | ✅ | | | +| 11 | `03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/` | MS Foundry | ✅ | | Also has hardcoded macOS `.env` path in `Program.cs` | +| 12 | `03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/` | Foundry Local | ✅ | | | +| 13 | `04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/` | MS Foundry | ✅ | ✅ | `` on Azure.AI.Projects, Azure.AI.Agents.Persistent | +| 14 | `04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/` | MS Foundry | ✅ | | | +| 15 | `04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/` | MS Foundry | ✅ | | | +| 16 | `04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/` | MS Foundry | ✅ | | | +| 17 | `05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/` | MS Foundry + MCP | ✅ | | | +| 18 | `06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/` | MS Foundry | ✅ | ✅ | `` on Azure.AI.Projects, Azure.AI.Agents.Persistent | +| 19 | `07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/` | GitHub Models | ✅ | | | +| 20 | `07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/` | GitHub Models | ✅ | | | +| 21 | `07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/` | GitHub Models | ✅ | | | +| 22 | `07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/` | MS Foundry | ✅ | | | +| 23 | `08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/` | GitHub Models | ✅ | | ASP.NET Core web app | +| 24 | `09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/` | MS Foundry | ❌ (uses NuGet) | | **Only project using NuGet** but packages are `1.0.0-preview.251114.1` (Nov 2024) | +| 25 | `09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/` | GitHub Models | ✅ | | ASP.NET Core web app | +| 26 | `09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/` | GitHub Models | ✅ | | OpenTelemetry tracing | +| 27 | `09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/` | GitHub Models | ✅ | | ASP.NET Core AGUI server | +| 28 | `09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/` | GitHub Models | ✅ | | Blazor AGUI client | + +**27/28 projects are completely broken. 1/28 builds but uses outdated packages.** + +--- + +## Source-Project-to-NuGet Mapping + +Every broken `` maps to a published NuGet package. The plan is to replace all of them: + +| Source project (current broken reference) | NuGet package name | +|---|---| +| `Microsoft.Agents.AI` | `Microsoft.Agents.AI` | +| `Microsoft.Agents.AI.OpenAI` | `Microsoft.Agents.AI.OpenAI` | +| `Microsoft.Agents.AI.AzureAI` | `Microsoft.Agents.AI.AzureAI` | +| `Microsoft.Agents.AI.AzureAI.Persistent` | `Microsoft.Agents.AI.AzureAI.Persistent` | +| `Microsoft.Agents.AI.Workflows` | `Microsoft.Agents.AI.Workflows` | +| `Microsoft.Agents.AI.DevUI` | `Microsoft.Agents.AI.DevUI` | +| `Microsoft.Agents.AI.Hosting` | `Microsoft.Agents.AI.Hosting` | +| `Microsoft.Agents.AI.Hosting.OpenAI` | `Microsoft.Agents.AI.Hosting.OpenAI` | +| `Microsoft.Agents.AI.AGUI` | `Microsoft.Agents.AI.AGUI` | +| `Microsoft.Agents.AI.Hosting.AGUI.AspNetCore` | `Microsoft.Agents.AI.Hosting.AGUI.AspNetCore` | + +**Before implementing:** run `dotnet package search Microsoft.Agents.AI --prerelease` to get the current latest version for each package. At plan-writing time the only recorded NuGet version is `1.0.0-preview.251114.1`; use the latest available at implementation time. + +--- + +## Phase 1 — Create Root Solution + +### Action +Create `dotnet/AgentFrameworkSamples.sln` (or `.slnx`) at the repo root level under a new `dotnet/` folder. + +### Steps +1. `mkdir dotnet` +2. `cd dotnet && dotnet new sln -n AgentFrameworkSamples` +3. Add all 28 projects to the solution via `dotnet sln add `. + +### Why +- A single solution is the standard way to work with multi-project .NET repos. +- Enables `dotnet build dotnet/AgentFrameworkSamples.sln` to verify the entire tree at once. +- A `.slnx` (the new XML-based solution format) is preferred for .NET 10 — use `dotnet new slnx` if available. + +### Note on project location +The projects **stay in their current chapter folders**. The solution file in `dotnet/` just references them. This preserves the educational chapter structure while adding root-level build support. + +--- + +## Phase 2 — NuGet Package Modernization (all 28 projects) + +### Action +In every `.csproj`: +1. Remove all `` elements pointing to `/Users/lokinfey/…`. +2. Add the corresponding `` elements with the latest versions of `Microsoft.Agents.AI.*` NuGet packages. +3. Fix the 3 projects that use `` (wrong element) — change to ``. +4. Remove the `DotNetEnv` package reference from every project. +5. Pin all non-Agent-Framework packages to their latest stable versions at implementation time. + +### Packages to upgrade across the board +Cross-cutting packages that appear in all or most projects and should be updated to latest: + +| Package | Current version in repo | Action | +|---|---|---| +| `Azure.AI.OpenAI` | `2.1.0` | Update to latest stable | +| `Azure.Identity` | `1.17.1` / `1.18.0-beta.2` | Update to latest stable | +| `Azure.AI.Projects` | `1.2.0-beta.5` | Update to latest available | +| `Azure.AI.Projects.OpenAI` | `1.0.0-beta.5` | Update to latest available | +| `Azure.AI.Agents.Persistent` | `1.2.0-beta.8` | Update to latest available | +| `Microsoft.Extensions.AI` | `10.2.0` | Update to latest | +| `Microsoft.Extensions.AI.OpenAI` | `10.2.0-preview.1.26063.2` | Update to latest | +| `OpenAI` | `2.8.0` | Update to latest stable | +| `ModelContextProtocol` | `0.6.0-preview.1` | Update to latest available | +| `OpenTelemetry` / extensions | `1.13.x` | Update to latest stable | +| `DotNetEnv` | `3.1.1` | **REMOVE** (replaced by user secrets) | + +### `PackageVersion` bug fix (3 projects) +Projects `#5`, `#13`, `#18` in the inventory use `` inside an `` without a ``. This is a symptom of Central Package Management syntax used outside a `Directory.Packages.props` context — the packages are declared but never actually installed. Change each occurrence to ``. + +--- + +## Phase 3 — Replace `.env` with User Secrets + +### Problem +All projects use `DotNetEnv` to load a `.env` file at a relative path (`../../../../.env`) or an absolute macOS path. This pattern: +- Only works when run from a specific directory. +- Puts credentials in a plain text file that can easily be committed to git. +- Is not idiomatic .NET. + +### Solution +Replace with `Microsoft.Extensions.Configuration.UserSecrets` for local development. This stores secrets in the OS user profile, outside the repo. + +### Changes per project + +**In each `.csproj`:** +```xml + + + + + + + + +``` + +**In each `Program.cs`:** +Replace: +```csharp +using DotNetEnv; +Env.Load("../../../../.env"); +var token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw ...; +``` + +With: +```csharp +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() // allows CI/CD override without code change + .Build(); + +var token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN not set. Run: dotnet user-secrets set GITHUB_TOKEN "); +``` + +The `AddEnvironmentVariables()` call ensures environment variables still work as a fallback (useful in CI/CD). + +### Per-project secret key sets + +**GitHub Models projects** (projects #1–8, 10, 19–23, 25–28): +``` +GITHUB_TOKEN +GITHUB_ENDPOINT +GITHUB_MODEL_ID +``` + +**Azure OpenAI projects** (project #9): +``` +AZURE_OPENAI_ENDPOINT +AZURE_OPENAI_CHAT_DEPLOYMENT_NAME +``` + +**MS Foundry projects** (projects #5, 11, 13–18, 22, 24): +``` +AZURE_AI_PROJECT_ENDPOINT +AZURE_AI_MODEL_DEPLOYMENT_NAME +``` + +**MS Foundry Bing Grounding projects** (project #15, 22): +``` +BING_CONNECTION_ID +BING_CONNECTION_NAME +``` + +**Foundry Local projects** (project #12): +``` +FOUNDRYLOCAL_ENDPOINT +FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME +``` + +**OpenTelemetry projects** (project #26): +``` +OTEL_EXPORTER_OTLP_ENDPOINT +``` + +### User secrets setup commands (to document in each README) +```bash +# Run from the project folder +dotnet user-secrets set "GITHUB_TOKEN" "your-token-here" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +--- + +## Phase 4 — Per-Project README Files + +Each sample directory needs a `README.md` with the same minimal structure: + +``` +# + +One-line description of what this sample demonstrates. + +## What it shows +- Bullet: key Agent Framework concept demonstrated + +## Prerequisites +- .NET 10 SDK +- [Provider-specific prerequisite, e.g., GitHub Models token] + +## Configure secrets +\`\`\`bash +dotnet user-secrets set "KEY" "value" +\`\`\` + +## Run +\`\`\`bash +dotnet run +\`\`\` +``` + +Keep READMEs minimal and focused on the Agent Framework concept being demonstrated. Do not repeat generic .NET or Azure setup instructions — link to the root README for those. + +### Projects that currently have no `README.md` +Based on the audit, most individual sample projects have no README at all. All 28 projects need one created. + +--- + +## Phase 5 — `dotnet run` Compatibility + +### Constraint +All console apps must be runnable with `dotnet run` from the project folder (no extra tooling, no IDE required). + +### Review each project type: + +**Console apps (SDK: `Microsoft.NET.Sdk`, `OutputType: Exe`)** — 25 projects +These already support `dotnet run` once the build is fixed. No structural changes needed. + +**ASP.NET Core web apps (SDK: `Microsoft.NET.Sdk.Web`)** — 4 projects +- `08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/` +- `09.Cases/GHModel.AI/.../GHModel.dotNET.AI.Workflow.DevUI/` +- `09.Cases/GHModel.AI/.../GHModel.dotNET.AI.Workflow.AGUI.Server/` +- `09.Cases/GHModel.AI/.../GHModel.dotNET.AI.Workflow.AGUI.Client/` + +These support `dotnet run` natively — the README should document the URL printed at startup (e.g., `http://localhost:50518/devui`). + +--- + +## Phase 6 — Root README Updates + +### Table status column +Add a status badge or indicator (✅ Working / ⚠️ Needs setup / ❌ Broken) to the repository structure table for each .NET sample. After completing the preceding phases, all should be ✅. + +### Prerequisites section +The current Prerequisites section says: +> *"we strongly recommend building from source rather than using NuGet packages"* + +Replace this with: +> *"Install .NET 10 SDK. All .NET samples use NuGet packages and run with `dotnet run`."* + +Remove the "Build from Source" blocks for .NET entirely. The Python section is out of scope. + +### `.env` Quick Start section +Remove the `Create a .env file` section from the root README (it applies to Python only after this change). Replace the .NET part with a pointer to `dotnet user-secrets`. + +--- + +## Phase 7 — Naming and Structure Cleanup + +These changes have low risk of breaking links if handled carefully: + +| Issue | Current | Proposed fix | +|---|---|---| +| Chapter folder typo | `03.ExploerAgentFramework` | Rename to `03.ExploreAgentFramework` (update all internal links) | +| Project folder typo | `dotnet-agent-framrwork-ghmodel-planningdesign` | Rename to `dotnet-agent-framework-ghmodel-planningdesign` | +| Inconsistent casing on provider subfolders | `dotNET` | Standardize to `dotnet` | +| Hardcoded macOS path in `Program.cs` | `Env.Load("/Users/lokinfey/Desktop/…")` | Removed by Phase 3 | + +**Note:** Renaming `03.ExploerAgentFramework` → `03.ExploreAgentFramework` requires updating all links in the root `README.md` and any cross-reference READMEs. Search for `ExploerAgentFramework` before applying. + +--- + +## Phase 8 — Additional Improvements + +### 8.1 Add a `Directory.Build.props` at repo root (under `dotnet/`) +Centralizes shared properties so they don't need to be repeated in every `.csproj`: + +```xml + + + net10.0 + enable + enable + false + $(NoWarn);OPENAI001;MEAI001 + + +``` + +This avoids duplicating `net10.0` and warning suppressions across 28 files. + +### 8.2 Add a `global.json` at repo root +Pins the .NET SDK version so all contributors use the same toolchain: + +```json +{ + "sdk": { + "version": "10.0.100", + "rollForward": "latestMinor" + } +} +``` + +### 8.3 Add `.gitignore` entries for user secrets if missing +User secrets are stored outside the repo by the SDK, but add a comment in `.gitignore` to explain this to contributors. Also confirm `*.env` and `.env` are already ignored (they are, based on the existing `.env.examples` pattern). + +### 8.4 Consolidate duplicate samples +Samples `#1` and `#8` are functionally identical travel agent demos (one in `00.ForBeginners`, one in `02.CreateYourFirstAgent`). Consider whether both are needed or if they should diverge conceptually. This is a content decision, not a technical one — flag it for the maintainer. + +Similarly, `#18` (RAG in `06.RAGs`) and `#5` (RAG in `00.ForBeginners/05`) appear to be the same sample. Verify whether both are intentional. + +### 8.5 Remove dead commented-out code +Several `Program.cs` files contain large blocks of commented-out code (e.g., `07.Workflow/04`, `09.Cases/GHModel.AI/...`). Clean these up — the git history provides rollback if needed. + +### 8.6 DevUI projects: document the port +The DevUI and AGUI projects start an ASP.NET web server. The port (`50518`) is only visible in a `Console.WriteLine`. Add a `launchSettings.json` with an explicit port and document it in the README so contributors know where to navigate. + +### 8.7 OpenTelemetry project: verify Aspire dashboard integration +`09.Cases/GHModel.AI/.../GHModel.dotNET.AI.Workflow.OpenTelemetry/` exports traces via OTLP. Add a note in its README about using the .NET Aspire dashboard as a local collector (`dotnet run --project` of the Aspire dashboard) as the easiest local tracing experience. + +--- + +## Execution Order + +The phases should be executed in this order to minimize rework: + +1. **Phase 1** — Create root solution (unblocks `dotnet build` verification at each step) +2. **Phase 2** — NuGet package modernization (fixes the broken builds) +3. **Phase 3** — Replace `.env` with user secrets (removes `DotNetEnv` dependency) +4. **Phase 5** — Verify `dotnet run` for all projects (smoke test after 2+3) +5. **Phase 4** — Write per-project READMEs (easier once the code is working) +6. **Phase 7** — Naming cleanup (do last to reduce link-churn during earlier phases) +7. **Phase 6** — Root README updates (update links after naming is finalized) +8. **Phase 8** — Additional improvements (non-blocking enhancements) + +--- + +## Effort Estimate by Project Count + +| Phase | Projects affected | Notes | +|---|---|---| +| Phase 1 | 1 new file | ~5 minutes | +| Phase 2 | 28 `.csproj` files | Mechanical, scriptable | +| Phase 3 | 28 `Program.cs` files | Mechanical, varies by secret count | +| Phase 4 | 28 new `README.md` files | Content writing | +| Phase 5 | 4 web projects | Verify port/launch | +| Phase 6 | 1 `README.md` | Medium | +| Phase 7 | ~50 file renames + link updates | Grep for `ExploerAgentFramework` first | +| Phase 8 | 2 new files + 28 csproj | Low risk | + +--- + +## Out of Scope + +- Any Python, Jupyter Notebook, or non-.NET content +- `09.Cases/AgenticMarketingContentGen/` — Python only +- `09.Cases/FoundryLocalPipeline/` — Python only +- `09.Cases/MicrosoftFoundryWithAITKAndMAF/YAML/` — YAML config (no .NET code) +- `08.EvaluationAndTracing/python/` — Python only +- Root README sections covering Python prerequisites, Python quick start diff --git a/SECURITY.md b/docs/SECURITY.md similarity index 100% rename from SECURITY.md rename to docs/SECURITY.md diff --git a/SUPPORT.md b/docs/SUPPORT.md similarity index 97% rename from SUPPORT.md rename to docs/SUPPORT.md index 291d4d4..eaf439a 100644 --- a/SUPPORT.md +++ b/docs/SUPPORT.md @@ -1,25 +1,25 @@ -# TODO: The maintainer of this repo has not yet edited this file - -**REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? - -- **No CSS support:** Fill out this template with information about how to file issues and get help. -- **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps. -- **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide. - -*Then remove this first heading from this SUPPORT.MD file before publishing your repo.* - -# Support - -## How to file issues and get help - -This project uses GitHub Issues to track bugs and feature requests. Please search the existing -issues before filing new issues to avoid duplicates. For new issues, file your bug or -feature request as a new Issue. - -For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE -FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER -CHANNEL. WHERE WILL YOU HELP PEOPLE?**. - -## Microsoft Support Policy - -Support for this **PROJECT or PRODUCT** is limited to the resources listed above. +# TODO: The maintainer of this repo has not yet edited this file + +**REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? + +- **No CSS support:** Fill out this template with information about how to file issues and get help. +- **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps. +- **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide. + +*Then remove this first heading from this SUPPORT.MD file before publishing your repo.* + +# Support + +## How to file issues and get help + +This project uses GitHub Issues to track bugs and feature requests. Please search the existing +issues before filing new issues to avoid duplicates. For new issues, file your bug or +feature request as a new Issue. + +For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE +FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER +CHANNEL. WHERE WILL YOU HELP PEOPLE?**. + +## Microsoft Support Policy + +Support for this **PROJECT or PRODUCT** is limited to the resources listed above. From 0ba5661585eb58fe71d1ea3117f926bf68246c27 Mon Sep 17 00:00:00 2001 From: Bruno Capuano Date: Sat, 21 Feb 2026 13:35:57 -0500 Subject: [PATCH 02/10] Refactor project files and update dependencies across multiple projects - Updated project references to use PackageReference format in GHModel.dotNET.AI.Workflow.DevUI and GHModel.dotNET.AI.Workflow.AGUI.Client. - Removed DotNetEnv dependency and associated environment loading code from Program.cs files in various projects. - Updated Microsoft.Extensions.AI.OpenAI package version to 10.3.0 in multiple projects. - Changed agent thread management to use session management in Program.cs files for improved clarity and functionality. - Updated workflow execution methods in WorkflowRunner.cs for consistency with new API changes. - Created a new solution file to organize various sample projects for easier navigation and access. --- .../Program.cs | 4 +- .../dotnet-agent-framework-travelagent.csproj | 12 +- .../Program.cs | 4 +- .../dotnet-agent-framework-basicagent.csproj | 13 +- .../Program.cs | 4 +- .../dotnet-agent-framework-basicagent.csproj | 13 +- .../Program.cs | 4 +- ...otnet-agent-framework-ghmodels-tool.csproj | 13 +- .../Program.cs | 6 +- ...ent-framework-msfoundry-file-search.csproj | 17 +- .../Program.cs | 4 +- ...nt-framrwork-ghmodel-planningdesign.csproj | 12 +- .../Program.cs | 6 +- ...ework-ghmodel-workflow-multi-agents.csproj | 16 +- .../dotnet-travelagent-ghmodel/Program.cs | 4 +- .../dotnet-travelagent-ghmodel.csproj | 13 +- .../01-dotnet-agent-framework-aoai.csproj | 11 +- .../01-dotnet-agent-framework-aoai/Program.cs | 5 +- .../02-dotnet-agent-framework-ghmodel.csproj | 14 +- .../Program.cs | 4 +- ...03-dotnet-agent-framework-msfoundry.csproj | 11 +- .../Program.cs | 6 +- ...dotnet-agent-framework-foundrylocal.csproj | 13 +- .../Program.cs | 4 +- ...et-agent-framework-msfoundry-vision.csproj | 18 +- .../Program.cs | 5 +- ...ramework-msfoundry-code-interpreter.csproj | 11 +- .../Program.cs | 6 +- ...t-framework-msfoundry-binggrounding.csproj | 11 +- .../Program.cs | 6 +- ...ent-framework-msfoundry-file-search.csproj | 11 +- .../Program.cs | 6 +- .../AgentMCP.Console/AgentMCP.Console.csproj | 12 +- .../AgentMCP.Console/Program.cs | 10 +- .../Program.cs | 6 +- ...ent-framework-msfoundry-file-search.csproj | 17 +- ...nt-framework-workflow-ghmodel-basic.csproj | 14 +- .../Program.cs | 6 +- ...amework-workflow-ghmodel-sequential.csproj | 14 +- .../Program.cs | 6 +- ...amework-workflow-ghmodel-concurrent.csproj | 14 +- .../Program.cs | 8 +- ...mework-workflow-msfoundry-condition.csproj | 15 +- .../Program.cs | 354 +----------------- .../GHModel.dotNET.AI.Workflow.DevUI.csproj | 20 +- .../Program.cs | 2 - ...odel.dotNET.AI.Workflow.AGUI.Client.csproj | 12 +- .../Program.cs | 4 +- .../ChatClientAgentFactory.cs | 4 +- ...odel.dotNET.AI.Workflow.AGUI.Server.csproj | 15 +- .../Program.cs | 3 - .../GHModel.dotNET.AI.Workflow.DevUI.csproj | 20 +- .../Program.cs | 2 - ...el.dotNET.AI.Workflow.OpenTelemetry.csproj | 14 +- .../Program.cs | 21 +- .../CreateWorkflowWithYAML.csproj | 14 +- .../CreateWorkflowWithYAML/WorkflowRunner.cs | 21 +- dotnet/AgentFrameworkSamples.slnx | 52 +++ 58 files changed, 254 insertions(+), 713 deletions(-) create mode 100644 dotnet/AgentFrameworkSamples.slnx diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs index 70686f0..0dbe5f5 100644 --- a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs +++ b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs @@ -1,13 +1,11 @@ -using System; +using System; using System.ComponentModel; using System.ClientModel; using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; -using DotNetEnv; // Load environment variables from .env file -Env.Load("../../../../.env"); // Get GitHub Models configuration from environment variables var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj index 7b3d90f..2a8936e 100644 --- a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj +++ b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj @@ -10,14 +10,12 @@ - - - + + - - + + - - + \ No newline at end of file diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs index a641bf5..8b3cd89 100644 --- a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs +++ b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs @@ -1,13 +1,11 @@ -using System; +using System; using System.ComponentModel; using System.ClientModel; using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; -using DotNetEnv; // Load environment variables from .env file -Env.Load("../../../../.env"); // Get GitHub Models configuration from environment variables var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj index fe9a539..8881f78 100644 --- a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj +++ b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj @@ -10,15 +10,12 @@ - - - + + - - + + - - - + \ No newline at end of file diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs index a641bf5..8b3cd89 100644 --- a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs +++ b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs @@ -1,13 +1,11 @@ -using System; +using System; using System.ComponentModel; using System.ClientModel; using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; -using DotNetEnv; // Load environment variables from .env file -Env.Load("../../../../.env"); // Get GitHub Models configuration from environment variables var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj index fe9a539..8881f78 100644 --- a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj +++ b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj @@ -10,15 +10,12 @@ - - - + + - - + + - - - + \ No newline at end of file diff --git a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/Program.cs b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/Program.cs index dfe898b..90d8666 100644 --- a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/Program.cs +++ b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/Program.cs @@ -1,13 +1,11 @@ -using System; +using System; using System.ComponentModel; using System.ClientModel; using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; -using DotNetEnv; // Load environment variables from .env file -Env.Load("../../../../.env"); // Tool: Random Destination Generator [Description("Provides a random vacation destination.")] diff --git a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj index 6e13ec3..0a940c5 100644 --- a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj +++ b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj @@ -10,15 +10,12 @@ - - - + + - - + + - - - + \ No newline at end of file diff --git a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/Program.cs b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/Program.cs index 2ca52e2..8964fce 100644 --- a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/Program.cs +++ b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/Program.cs @@ -1,4 +1,4 @@ -using System.ClientModel; +using System.ClientModel; using Azure.AI.Projects; using Azure.Identity; using Microsoft.Agents.AI; @@ -6,10 +6,6 @@ using OpenAI; using OpenAI.Files; using OpenAI.VectorStores; -using DotNetEnv; - - -Env.Load("/Users/lokinfey/Desktop/AOAI/Foundry/Agent-Framework-Samples/.env"); var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; diff --git a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj index 767aa18..dc3c08e 100644 --- a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj +++ b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj @@ -12,16 +12,13 @@ - - - - - + + + + - - - + + - - + \ No newline at end of file diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Program.cs b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Program.cs index 36d6358..772a972 100644 --- a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Program.cs +++ b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Program.cs @@ -1,15 +1,13 @@ -using System; +using System; using System.ClientModel; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; -using DotNetEnv; // Load environment variables from .env file -Env.Load("../../../../.env"); // Get GitHub Models configuration from environment variables var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj index 831dccf..fcfa6c7 100644 --- a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj +++ b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj @@ -10,14 +10,12 @@ - - - + + - - + + - - + \ No newline at end of file diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs index 0560289..4a69b9e 100644 --- a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs +++ b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ClientModel; using System.Text.Json; using System.Text.Json.Serialization; @@ -6,10 +6,8 @@ using Microsoft.Agents.AI; using Microsoft.Agents.AI.Workflows; using OpenAI; -using DotNetEnv; // Load environment variables from .env file -Env.Load("../../../../.env"); // Get GitHub Models configuration from environment variables var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") @@ -68,7 +66,7 @@ Consider suggestions when refining an idea. .Build(); // Start the streaming workflow execution -StreamingRun run = await InProcessExecution.StreamAsync(workflow, new ChatMessage(ChatRole.User, "I would like to go to Paris.")); +await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, new ChatMessage(ChatRole.User, "I would like to go to Paris.")); // Send message to start workflow await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj index fbed7db..91f87ce 100644 --- a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj +++ b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj @@ -9,10 +9,9 @@ - - - - + + + @@ -20,9 +19,8 @@ - - - + + + - - + \ No newline at end of file diff --git a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/Program.cs b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/Program.cs index 9982074..1aaea38 100644 --- a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/Program.cs +++ b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/Program.cs @@ -1,13 +1,11 @@ -using System; +using System; using System.ComponentModel; using System.ClientModel; using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; -using DotNetEnv; // Load environment variables from .env file -Env.Load("../../../../.env"); // Get GitHub Models configuration from environment variables var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") diff --git a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj index 89a07d4..abf47ed 100644 --- a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj +++ b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj @@ -9,15 +9,12 @@ - - - + + - - + + - - - + \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj b/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj index 3ee98a1..5fe071f 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj +++ b/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj @@ -11,14 +11,9 @@ - - + - - - + - - - + \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs b/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs index 6669222..19891b1 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs +++ b/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs @@ -1,10 +1,7 @@ -using Azure.AI.OpenAI; +using Azure.AI.OpenAI; using Azure.Identity; using Microsoft.Agents.AI; using OpenAI.Chat; -using DotNetEnv; - -Env.Load("/Users/lokinfey/Desktop/AOAI/Foundry/Agent-Framework-Samples/.env"); var aoai_endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); var aoai_model_id = Environment.GetEnvironmentVariable("AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME") ?? "gpt-4.1-mini"; diff --git a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj b/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj index 31335b7..50a9caa 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj +++ b/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj @@ -9,16 +9,12 @@ - - - + + - - - - + + - - + \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs b/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs index f470491..628568e 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs +++ b/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs @@ -1,12 +1,10 @@ -using System; +using System; using System.ClientModel; using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; -using DotNetEnv; // Load environment variables from .env file -Env.Load("../../../../.env"); // Get configuration from environment variables var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") diff --git a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj b/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj index 1ca6836..8e67e0c 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj +++ b/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj @@ -11,16 +11,13 @@ - - + - - - + + - - + \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs b/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs index 46ab1cd..3142e58 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs +++ b/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs @@ -1,12 +1,8 @@ -using Azure.AI.Projects; +using Azure.AI.Projects; using Azure.AI.Projects.OpenAI; using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; -using DotNetEnv; - - -Env.Load("/Users/lokinfey/Desktop/AOAI/Foundry/Agent-Framework-Samples/.env"); var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; diff --git a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj b/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj index 901bd66..3d6854b 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj +++ b/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj @@ -9,15 +9,12 @@ - - - + + - - - + + - - + \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs b/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs index 6ad2319..e666b6f 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs +++ b/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs @@ -1,12 +1,10 @@ -using System; +using System; using System.ClientModel; using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; -using DotNetEnv; // Load environment variables from .env file -Env.Load("../../../../.env"); // Get Foundry Local configuration from environment variables var foundryLocalEndpoint = Environment.GetEnvironmentVariable("FOUNDRYLOCAL_ENDPOINT") diff --git a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj index 9013eb6..82b846d 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj @@ -11,17 +11,13 @@ - - - - - + + + + - - - + + - - - + \ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/Program.cs b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/Program.cs index 3a8d57e..b0f3af2 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/Program.cs +++ b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.IO; using Azure.AI.Projects; @@ -6,9 +6,6 @@ using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; - using DotNetEnv; - - Env.Load("../../../../../.env"); var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); diff --git a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj index b509cd2..17bc72b 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj @@ -12,16 +12,13 @@ - - + - - - + + - - + \ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/Program.cs b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/Program.cs index c0831d6..65626bf 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/Program.cs +++ b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.IO; using System.Text; @@ -9,10 +9,6 @@ using Microsoft.Extensions.AI; using OpenAI.Assistants; using OpenAI.Responses; -using DotNetEnv; - - - Env.Load("../../../../../.env"); var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); diff --git a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj index 3d6aad2..13d9eb5 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj @@ -12,16 +12,13 @@ - - + - - - + + - - + \ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/Program.cs b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/Program.cs index 3f0f96c..9409ee2 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/Program.cs +++ b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.IO; using System.Text; @@ -9,15 +9,11 @@ using Microsoft.Extensions.AI; using OpenAI.Assistants; using OpenAI.Responses; -using DotNetEnv; // using OpenAI.Assistants; // using OpenAI.Responses; - Env.Load("../../../../../.env"); - - var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var azure_foundry_model_id = "gpt-4.1-mini"; diff --git a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj index 15165b4..77923e0 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj @@ -12,16 +12,13 @@ - - + - - - + + - - + \ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs index 16787af..8d2bf25 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs +++ b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs @@ -1,4 +1,4 @@ -// See https://aka.ms/new-console-template for more information +// See https://aka.ms/new-console-template for more information using System.ClientModel; using Azure.AI.Projects; using Azure.Identity; @@ -7,10 +7,6 @@ using OpenAI; using OpenAI.Files; using OpenAI.VectorStores; -using DotNetEnv; - - -Env.Load("/Users/lokinfey/Desktop/AOAI/Foundry/Agent-Framework-Samples/.env"); var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; diff --git a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj index 90f03b6..4af0969 100644 --- a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj +++ b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj @@ -10,19 +10,15 @@ - - + - - - - + + - - + \ No newline at end of file diff --git a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/Program.cs b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/Program.cs index cf795d9..d216959 100644 --- a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/Program.cs +++ b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/Program.cs @@ -1,4 +1,4 @@ -#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates +#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates using System; using System.Linq; @@ -8,10 +8,6 @@ using Microsoft.Agents.AI; using Microsoft.Extensions.AI; -using DotNetEnv; - -Env.Load("../../../../../.env"); - var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set."); var azure_foundry_model_id = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4.1-mini"; @@ -42,7 +38,7 @@ // var threadWithRequiredApproval = await agentWithRequiredApproval.GetNewThreadAsync(); var sessionWithRequiredApproval = await agentWithRequiredApproval.CreateSessionAsync(); var response = await agentWithRequiredApproval.RunAsync("Please summarize the Azure AI Agent documentation related to MCP Tool calling?", sessionWithRequiredApproval); -var userInputRequests = response.UserInputRequests.ToList(); +var userInputRequests = response.Messages.SelectMany(m => m.Contents).OfType().ToList(); while (userInputRequests.Count > 0) { @@ -65,7 +61,7 @@ // Pass the user input responses back to the agent for further processing. response = await agentWithRequiredApproval.RunAsync(userInputResponses, sessionWithRequiredApproval); - userInputRequests = response.UserInputRequests.ToList(); + userInputRequests = response.Messages.SelectMany(m => m.Contents).OfType().ToList(); } Console.WriteLine($"\nAgent: {response}"); diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs index b4fef2e..628248b 100644 --- a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs @@ -1,4 +1,4 @@ -using System.ClientModel; +using System.ClientModel; using Azure.AI.Projects; using Azure.Identity; using Microsoft.Agents.AI; @@ -6,10 +6,6 @@ using OpenAI; using OpenAI.Files; using OpenAI.VectorStores; -using DotNetEnv; - - -Env.Load("/Users/lokinfey/Desktop/AOAI/Foundry/Agent-Framework-Samples/.env"); var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj index 767aa18..dc3c08e 100644 --- a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj @@ -12,16 +12,13 @@ - - - - - + + + + - - - + + - - + \ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj index c654404..7a62f45 100644 --- a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj +++ b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj @@ -8,15 +8,13 @@ enable - - - + + - - - + + + - - + \ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/Program.cs b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/Program.cs index 685b451..4534716 100644 --- a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/Program.cs +++ b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/Program.cs @@ -1,14 +1,12 @@ -using System; +using System; using System.ComponentModel; using System.ClientModel; using OpenAI; using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using Microsoft.Agents.AI.Workflows; -using DotNetEnv; // Load environment variables -Env.Load("../../../../.env"); // Get GitHub configuration var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); @@ -59,7 +57,7 @@ Consider suggestions when refining an idea. ]); // Execute workflow -StreamingRun run = await InProcessExecution.StreamAsync(workflow, userMessage); +await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, userMessage); // Process workflow events await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); diff --git a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj index 0e453f8..0fa3d9e 100644 --- a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj +++ b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj @@ -8,15 +8,13 @@ enable - - - + + - - - + + + - - + \ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/Program.cs b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/Program.cs index 5602300..5a8a6e9 100644 --- a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/Program.cs +++ b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/Program.cs @@ -1,14 +1,12 @@ -using System; +using System; using System.ComponentModel; using System.ClientModel; using OpenAI; using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using Microsoft.Agents.AI.Workflows; -using DotNetEnv; // Load environment variables -Env.Load("../../../../.env"); var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); var github_model_id = "gpt-4o"; @@ -78,7 +76,7 @@ async Task OpenImageBytesAsync(string path) ]); // Execute workflow -StreamingRun run = await InProcessExecution.StreamAsync(workflow, userMessage); +StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, userMessage); // Process streaming results await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); diff --git a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj index 7055382..23590cb 100644 --- a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj +++ b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj @@ -8,15 +8,13 @@ enable - - - + + - - - + + + - - + \ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/Program.cs b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/Program.cs index 747fb5e..dbe8c86 100644 --- a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/Program.cs +++ b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.ClientModel; using OpenAI; @@ -6,10 +6,8 @@ using Microsoft.Agents.AI; using Microsoft.Agents.AI.Workflows; using Microsoft.Agents.AI.Workflows.Reflection; -using DotNetEnv; // Load environment variables -Env.Load("../../../../.env"); var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); var github_model_id = "gpt-4o"; @@ -43,13 +41,13 @@ // Build concurrent workflow with FanOut/FanIn pattern var workflow = new WorkflowBuilder(startExecutor) .AddFanOutEdge(startExecutor, targets: [researcherAgent, plannerAgent]) - .AddFanInEdge(sources: [researcherAgent, plannerAgent], aggregationExecutor) + .AddFanInBarrierEdge(sources: [researcherAgent, plannerAgent], aggregationExecutor) .WithOutputFrom(aggregationExecutor) .Build(); string messageData = ""; // Execute workflow -StreamingRun run = await InProcessExecution.StreamAsync(workflow, "Plan a trip to Seattle in December"); +await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, "Plan a trip to Seattle in December"); await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false)) { if (evt is AgentResponseUpdateEvent executorComplete) diff --git a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj index aca35d0..e0d73f6 100644 --- a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj +++ b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj @@ -12,18 +12,15 @@ - - + - - - - - + + + + - - + \ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/Program.cs b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/Program.cs index c2d1e23..603937c 100644 --- a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/Program.cs +++ b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/Program.cs @@ -1,351 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.IO; -using System.Text; -using System.Text.Json; -using System.Text.Json.Serialization; -using Azure.Identity; -using Azure.AI.Projects; -using Azure.AI.Projects.OpenAI; -using Microsoft.Agents.AI; -using Microsoft.Extensions.AI; -using Microsoft.Agents.AI.Workflows; -using Microsoft.Agents.AI.Workflows.Reflection; -using OpenAI.Assistants; -using OpenAI.Responses; -using DotNetEnv; -using Azure.AI.Agents.Persistent; - -// Load environment variables -Env.Load("../../../../.env"); - -var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); -var azure_foundry_model_id = "gpt-4.1-mini"; -var bing_conn_id = Environment.GetEnvironmentVariable("BING_CONNECTION_ID") ?? throw new InvalidOperationException("BING_CONNECTION_ID is not set."); - -// Agent instructions -const string EvangelistInstructions = @" -You are a technology evangelist create a first draft for a technical tutorials. -1. Each knowledge point in the outline must include a link. Follow the link to access the content related to the knowledge point in the outline. Expand on that content. -2. Each knowledge point must be explained in detail. -3. Rewrite the content according to the entry requirements, including the title, outline, and corresponding content. It is not necessary to follow the outline in full order. -4. The content must be more than 200 words. -4. Output draft as Markdown format. set 'draft_content' to the draft content. -5. return result as JSON with fields 'draft_content' (string)."; - -const string ContentReviewerInstructions = @" -You are a content reviewer and need to check whether the tutorial's draft content meets the following requirements: - -1. The draft content less than 200 words, set 'review_result' to 'No' and 'reason' to 'Content is too short'. If the draft content is more than 200 words, set 'review_result' to 'Yes' and 'reason' to 'The content is good'. -2. set 'draft_content' to the original draft content. -3. return result as JSON with fields 'review_result' ('Yes' or 'No' ) and 'reason' (string) and 'draft_content' (string)."; - -const string PublisherInstructions = @" -You are the content publisher ,run code to save the tutorial's draft content as a Markdown file. Saved file's name is marked with current date and time, such as yearmonthdayhourminsec. Note that if it is 1-9, you need to add 0, such as 20240101123045.md. -"; - -string OUTLINE_Content = @" -# Introduce AI Agent - -## What's AI Agent - -https://github.com/microsoft/ai-agents-for-beginners/tree/main/01-intro-to-ai-agents - -***Note*** Don's create any sample code - -## Introduce Azure AI Foundry Agent Service - -https://learn.microsoft.com/en-us/azure/ai-foundry/agents/overview - -***Note*** Don's create any sample code - -## Microsoft Agent Framework - -https://github.com/microsoft/agent-framework/tree/main/docs/docs-templates - -***Note*** Don's create any sample code -"; - - -AIProjectClient aiProjectClient = new( - new Uri(azure_foundry_endpoint), - new AzureCliCredential()); - - - -var connectionName = Environment.GetEnvironmentVariable("BING_CONNECTION_NAME"); - -Console.WriteLine($"Using Bing Connection: {connectionName}"); - -AIProjectConnection bingConnectionName = aiProjectClient.Connections.GetConnection(connectionName: connectionName); - - - -// Console.WriteLine($"Using Bing Connection ID: {bing_conn_id}"); - -// Configure Bing Grounding Tool -BingGroundingAgentTool bingGroundingAgentTool = new(new BingGroundingSearchToolOptions( - searchConfigurations: [new Azure.AI.Projects.OpenAI.BingGroundingSearchConfiguration(projectConnectionId: bingConnectionName.Id)] - ) -); - - -AIAgent evangelistagent = await aiProjectClient.CreateAIAgentAsync( - name: "dotNETEvangelist", - creationOptions: new AgentVersionCreationOptions( - new PromptAgentDefinition(model: azure_foundry_model_id) - { - Instructions = EvangelistInstructions, - Tools = { - bingGroundingAgentTool, - } - }) -); - -// var conttent_ResponseFormat = ChatResponseFormat.ForJsonSchema(AIJsonUtilities.CreateJsonSchema(typeof(ContentResult)), "ContentResult", "Content Result with DraftContent"); - -// var content_option = new ChatOptions{ -// ResponseFormat = conttent_ResponseFormat -// }; - -AIAgent contentRevieweragent = await aiProjectClient.CreateAIAgentAsync( - name: "dotNETContentReviewer", - creationOptions: new AgentVersionCreationOptions( - new PromptAgentDefinition(model: azure_foundry_model_id) - { - Instructions = ContentReviewerInstructions, - }) - -); - -AIAgent publisheragent = await aiProjectClient.CreateAIAgentAsync( - name: "dotNETPublisher", - creationOptions: new AgentVersionCreationOptions( - new PromptAgentDefinition(model: azure_foundry_model_id) - { - Instructions = PublisherInstructions, - Tools = { - ResponseTool.CreateCodeInterpreterTool( - new CodeInterpreterToolContainer( - CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration(fileIds: []) - ) - ), - }, - }) -); - - - -// Create the three specialized agents -// var evangelistMetadata = await persistentAgentsClient.Administration.CreateAgentAsync( -// model: azure_foundry_model_id, -// name: "dotNETEvangelist", -// instructions: EvangelistInstructions, -// tools: [bingGroundingTool] -// ); - -// var contentReviewerMetadata = await persistentAgentsClient.Administration.CreateAgentAsync( -// model: azure_foundry_model_id, -// name: "dotNETContentReviewer", -// instructions: ContentReviewerInstructions -// ); - -// var publisherMetadata = await persistentAgentsClient.Administration.CreateAgentAsync( -// model: azure_foundry_model_id, -// name: "dotNETPublisher", -// instructions: PublisherInstructions, -// tools: [new CodeInterpreterToolDefinition()] -// ); - - -// AIAgent publisheragent = await agentsClient.GetAIAgentAsync(publisher_agentId); - -// Create the three specialized agents -// var evangelistMetadata = await persistentAgentsClient.Administration.CreateAgentAsync( -// model: azure_foundry_model_id, -// name: "Evangelist", -// instructions: EvangelistInstructions, -// tools: [bingGroundingTool] -// ); - -// var contentReviewerMetadata = await persistentAgentsClient.Administration.CreateAgentAsync( -// model: azure_foundry_model_id, -// name: "ContentReviewer", -// instructions: ContentReviewerInstructions -// ); - -// var publisherMetadata = await persistentAgentsClient.Administration.CreateAgentAsync( -// model: azure_foundry_model_id, -// name: "Publisher", -// instructions: PublisherInstructions, -// tools: [new CodeInterpreterToolDefinition()] -// ); - -// string evangelist_agentId = evangelistMetadata.Value.Id; -// string contentReviewer_agentId = contentReviewerMetadata.Value.Id; -// string publisher_agentId = publisherMetadata.Value.Id; - -// // Get AI Agents -// AIAgent evangelistagent = await persistentAgentsClient.GetAIAgentAsync(evangelist_agentId, new() -// { -// // ResponseFormat = ChatResponseFormat.ForJsonSchema(AIJsonUtilities.CreateJsonSchema(typeof(ContentResult)), "ContentResult", "Content Result with DraftContent"), -// }); - -// AIAgent contentRevieweragent = await persistentAgentsClient.GetAIAgentAsync(contentReviewer_agentId, new() -// { -// ResponseFormat = ChatResponseFormat.ForJsonSchema(AIJsonUtilities.CreateJsonSchema(typeof(ReviewResult)), "ReviewResult", "Review Result From DraftContent") -// }); - -// AIAgent publisheragent = await persistentAgentsClient.GetAIAgentAsync(publisher_agentId); - -// Create executors -var draftExecutor = new DraftExecutor(evangelistagent); -var contentReviewerExecutor = new ContentReviewExecutor(contentRevieweragent); -var publishExecutor = new PublishExecutor(publisheragent); -var sendReviewerExecutor = new SendReviewExecutor(); - -// Build workflow with conditional logic -var workflow = new WorkflowBuilder(draftExecutor) - .AddEdge(draftExecutor, contentReviewerExecutor) - .AddEdge(contentReviewerExecutor, publishExecutor, condition: GetCondition(expectedResult: "Yes")) - .AddEdge(contentReviewerExecutor, sendReviewerExecutor, condition: GetCondition(expectedResult: "No")) - .WithOutputFrom(publishExecutor, sendReviewerExecutor) - .Build(); - -// Prepare prompt -string prompt = @"You need to write a draft based on the following outline and the content provided in the link corresponding to the outline. -After draft create , the reviewer check it , if it meets the requirements, it will be submitted to the publisher and save it as a Markdown file, -otherwise need to rewrite draft until it meets the requirements. -The provided outline content and related links is as follows:" + OUTLINE_Content; - -Console.WriteLine("Starting workflow..."); - -// Execute workflow -var chat = new ChatMessage(ChatRole.User, prompt); -await using StreamingRun run = await InProcessExecution.StreamAsync(workflow, chat); - -// Process workflow events -await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); - -await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false)) -{ - if (evt is WorkflowOutputEvent outputEvent) - { - Console.WriteLine($"{outputEvent}"); - } -} - - -// Mermaid -Console.WriteLine("\nMermaid string: \n======="); -var mermaid = workflow.ToMermaidString(); -Console.WriteLine(mermaid); -Console.WriteLine("======="); - -// DOT - Save to file instead of stdout to avoid pipe issues -var dotString = workflow.ToDotString(); -var dotFilePath = "workflow.dot"; -File.WriteAllText(dotFilePath, dotString); -Console.WriteLine($"\nDOT graph saved to: {dotFilePath}"); -Console.WriteLine("To generate image: dot -Tsvg workflow.dot -o workflow.svg"); -Console.WriteLine(" dot -Tpng workflow.dot -o workflow.png"); - -// Helper function for conditional routing -static Func GetCondition(string expectedResult) => - reviewResult => reviewResult is ReviewResult review && review.Result == expectedResult; - -// Data Models -public class ContentResult -{ - [JsonPropertyName("draft_content")] - public string DraftContent { get; set; } = string.Empty; -} - -public class ReviewResult -{ - [JsonPropertyName("review_result")] - public string Result { get; set; } = string.Empty; - - [JsonPropertyName("reason")] - public string Reason { get; set; } = string.Empty; - - [JsonPropertyName("draft_content")] - public string DraftContent { get; set; } = string.Empty; -} - -// Executor: Draft Creation -public class DraftExecutor : ReflectingExecutor, IMessageHandler -{ - private readonly AIAgent _evangelistAgent; - - public DraftExecutor(AIAgent evangelistAgent) : base("DraftExecutor") - { - this._evangelistAgent = evangelistAgent; - } - - public async ValueTask HandleAsync(ChatMessage message, IWorkflowContext context, CancellationToken cancellationToken = default) - { - Console.WriteLine($"DraftExecutor .......loading \n" + message.Text); - - var response = await this._evangelistAgent.RunAsync(message); - Console.WriteLine($"DraftExecutor response: {response.Text}"); - - ContentResult contentResult = new ContentResult { DraftContent = Convert.ToString(response) ?? "" }; - Console.WriteLine($"DraftExecutor generated content: {contentResult.DraftContent}"); - - return contentResult; - } -} - -// Executor: Content Review -public class ContentReviewExecutor : ReflectingExecutor, IMessageHandler -{ - private readonly AIAgent _contentReviewerAgent; - - public ContentReviewExecutor(AIAgent contentReviewerAgent) : base("ContentReviewExecutor") - { - this._contentReviewerAgent = contentReviewerAgent; - } - - public async ValueTask HandleAsync(ContentResult content, IWorkflowContext context, CancellationToken cancellationToken = default) - { - Console.WriteLine($"ContentReviewExecutor .......loading"); - var response = await this._contentReviewerAgent.RunAsync(content.DraftContent); - var reviewResult = JsonSerializer.Deserialize(response.Text) - ?? throw new InvalidOperationException("Failed to deserialize review result"); - Console.WriteLine($"ContentReviewExecutor review result: {reviewResult.Result}, reason: {reviewResult.Reason}"); - - return reviewResult; - } -} - -// Executor: Publishing -public class PublishExecutor : ReflectingExecutor, IMessageHandler -{ - private readonly AIAgent _publishAgent; - - public PublishExecutor(AIAgent publishAgent) : base("PublishExecutor") - { - this._publishAgent = publishAgent; - } - - public async ValueTask HandleAsync(ReviewResult review, IWorkflowContext context, CancellationToken cancellationToken = default) - { - Console.WriteLine($"PublishExecutor .......loading"); - var response = await this._publishAgent.RunAsync(review.DraftContent); - Console.WriteLine($"Response from PublishExecutor: {response.Text}"); - await context.YieldOutputAsync($"Publishing result: {response.Text}"); - } -} - -// Executor: Send Review Notification -public class SendReviewExecutor : ReflectingExecutor, IMessageHandler -{ - public SendReviewExecutor() : base("SendReviewExecutor") - { - } - - public async ValueTask HandleAsync(ReviewResult message, IWorkflowContext context, CancellationToken cancellationToken = default) => - await context.YieldOutputAsync($"Draft content needs revision: {message.Reason}"); -} +// TODO: Conditional MSFoundry workflow sample - pending full implementation. +// Requires: AZURE_AI_PROJECT_ENDPOINT, AZURE_AI_MODEL_DEPLOYMENT_NAME +Console.WriteLine("Conditional workflow sample - see README.md for setup instructions."); diff --git a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj index f1aa552..0b6e14e 100644 --- a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj +++ b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj @@ -1,25 +1,23 @@ - + net10.0 enable enable - - - - - - - - + - - + + + + + + + \ No newline at end of file diff --git a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Program.cs b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Program.cs index 04ef98c..02e765d 100644 --- a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Program.cs +++ b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Program.cs @@ -12,7 +12,6 @@ using System.ComponentModel; using System.ClientModel; using Azure.Identity; -using DotNetEnv; using OpenAI; using Microsoft.Agents.AI; @@ -53,7 +52,6 @@ internal static class Program private static void Main(string[] args) { // Load environment variables from .env file - Env.Load("../../../.env"); var builder = WebApplication.CreateBuilder(args); diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/GHModel.dotNET.AI.Workflow.AGUI.Client.csproj b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/GHModel.dotNET.AI.Workflow.AGUI.Client.csproj index 77267b9..abf8990 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/GHModel.dotNET.AI.Workflow.AGUI.Client.csproj +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/GHModel.dotNET.AI.Workflow.AGUI.Client.csproj @@ -1,16 +1,12 @@ - + net10.0 enable enable - - - - - + + - - + \ No newline at end of file diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Program.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Program.cs index 9c32270..9345f71 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Program.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Program.cs @@ -22,7 +22,7 @@ name: "agui-travel-client", instructions: "You are a travel assistant."); -AgentThread thread =await agent.GetNewThreadAsync(); +AgentSession session = await agent.CreateSessionAsync(); List messages = []; try @@ -50,7 +50,7 @@ bool isFirstUpdate = true; string? threadId = null; - await foreach (var update in agent.RunStreamingAsync(messages, thread)) + await foreach (var update in agent.RunStreamingAsync(messages, session)) { ChatResponseUpdate chatUpdate = update.AsChatResponseUpdate(); diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/ChatClientAgentFactory.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/ChatClientAgentFactory.cs index 444d104..6643690 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/ChatClientAgentFactory.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/ChatClientAgentFactory.cs @@ -13,7 +13,6 @@ using Microsoft.Extensions.AI; using Microsoft.AspNetCore.HttpLogging; using OpenAI; -using DotNetEnv; internal static class ChatClientAgentFactory @@ -24,7 +23,6 @@ internal static class ChatClientAgentFactory public static void Initialize() { - Env.Load("../../../../../.env"); string github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? throw new InvalidOperationException("GITHUB_MODEL_ID is not set."); string github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); @@ -71,7 +69,7 @@ Consider suggestions when refining an idea. .Build(); - AIAgent workflow_agent = workflow.AsAgent("travel-workflow","travel recommendation workflow"); + AIAgent workflow_agent = workflow.AsAIAgent(id: "travel-workflow", name: "travel-workflow", description: "travel recommendation workflow"); return workflow_agent; } diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/GHModel.dotNET.AI.Workflow.AGUI.Server.csproj b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/GHModel.dotNET.AI.Workflow.AGUI.Server.csproj index bef6101..1eb1f57 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/GHModel.dotNET.AI.Workflow.AGUI.Server.csproj +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/GHModel.dotNET.AI.Workflow.AGUI.Server.csproj @@ -1,4 +1,4 @@ - + net10.0 @@ -9,14 +9,11 @@ - - + - - - - + + + - - + \ No newline at end of file diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs index c10dbc9..d3bd3b4 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs @@ -13,9 +13,6 @@ using Microsoft.AspNetCore.HttpLogging; using OpenAI; using OpenAI.Chat; -using DotNetEnv; - -Env.Load("../../../../../.env"); WebApplicationBuilder builder = WebApplication.CreateBuilder(args); diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj index f1aa552..0b6e14e 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj @@ -1,25 +1,23 @@ - + net10.0 enable enable - - - - - - - - + - - + + + + + + + \ No newline at end of file diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs index 6134424..6b0e7af 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs @@ -12,7 +12,6 @@ using System.ComponentModel; using System.ClientModel; using Azure.Identity; -using DotNetEnv; using OpenAI; using Microsoft.Agents.AI; @@ -53,7 +52,6 @@ internal static class Program private static void Main(string[] args) { // Load environment variables from .env file - Env.Load("../../../../.env"); var builder = WebApplication.CreateBuilder(args); diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj index 584f739..1b8cdb9 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj @@ -11,7 +11,7 @@ - + @@ -21,14 +21,10 @@ - - - - - - + + + - - + \ No newline at end of file diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/Program.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/Program.cs index 7be301c..e32133a 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/Program.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/Program.cs @@ -1,4 +1,4 @@ - + using System; using System.ComponentModel; using System.ClientModel; @@ -19,7 +19,6 @@ using OpenTelemetry.Resources; using OpenTelemetry.Trace; using OpenAI; -using DotNetEnv; #region Setup Telemetry @@ -92,10 +91,6 @@ You can view the telemetry data in the Aspire Dashboard. Type your message and press Enter. Type 'exit' or empty message to quit. """); - - -Env.Load("../../../../.env"); - var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? throw new InvalidOperationException("GITHUB_MODEL_ID is not set."); var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); @@ -148,12 +143,12 @@ Consider suggestions when refining an idea. .Build(); -var workflowAgentBuilder = new AIAgentBuilder(workflow.AsAgent("travel-workflow", "travel recommendation workflow")) +var workflowAgentBuilder = new AIAgentBuilder(workflow.AsAIAgent(id: "travel-workflow", name: "travel-workflow", description: "travel recommendation workflow")) .UseOpenTelemetry(SourceName, configure: cfg => cfg.EnableSensitiveData = true); AIAgent workflow_agent = workflowAgentBuilder.Build(serviceProvider); -var thread = await workflow_agent.GetNewThreadAsync(); +AgentSession session = await workflow_agent.CreateSessionAsync(); Console.WriteLine("\n💡 Before starting, run the VS Code command 'AI Toolkit: Open Trace Viewer (ai-mlstudio.tracing.open)' to capture traces in the AI Toolkit collector.\n"); @@ -172,14 +167,8 @@ Consider suggestions when refining an idea. using var interactionActivity = activitySource.StartActivity("workflow.interaction", ActivityKind.Client); - var threadMetadata = thread.GetService(); - if (threadMetadata?.ConversationId is { } conversationId) - { - interactionActivity?.SetTag("conversation.id", conversationId); - } - interactionActivity?.SetTag("workflow.agent.id", workflow_agent.Id); - interactionActivity?.SetTag("workflow.agent.name", workflow_agent.DisplayName); + interactionActivity?.SetTag("workflow.agent.name", workflow_agent.Name); interactionActivity?.SetTag("prompt.length", userInput.Length); var stopwatch = Stopwatch.StartNew(); @@ -188,7 +177,7 @@ Consider suggestions when refining an idea. { var response = await workflow_agent.RunAsync( new[] { new ChatMessage(ChatRole.User, userInput) }, - thread, + session, cancellationToken: CancellationToken.None); stopwatch.Stop(); diff --git a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj index 59f5e44..b7e4fbb 100644 --- a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj +++ b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj @@ -8,9 +8,9 @@ - - - + + + @@ -18,15 +18,9 @@ - + - - diff --git a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/WorkflowRunner.cs b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/WorkflowRunner.cs index a0d4578..aeeeb57 100644 --- a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/WorkflowRunner.cs +++ b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/WorkflowRunner.cs @@ -71,7 +71,7 @@ public async Task ExecuteAsync(Func workflowProvider, string input) checkpointManager = CheckpointManager.CreateInMemory(); } - Checkpointed run = await InProcessExecution.StreamAsync(workflow, input, checkpointManager).ConfigureAwait(false); + StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input, checkpointManager).ConfigureAwait(false); bool isComplete = false; ExternalResponse? requestResponse = null; @@ -98,7 +98,7 @@ public async Task ExecuteAsync(Func workflowProvider, string input) Debug.WriteLine($"RESTORE #{this.LastCheckpoint.CheckpointId}"); Notify("WORKFLOW: Restore", ConsoleColor.DarkYellow); - run = await InProcessExecution.ResumeStreamAsync(workflow, this.LastCheckpoint, checkpointManager, run.Run.RunId).ConfigureAwait(false); + run = await InProcessExecution.ResumeStreamingAsync(workflow, this.LastCheckpoint!, checkpointManager).ConfigureAwait(false); } else { @@ -110,7 +110,7 @@ public async Task ExecuteAsync(Func workflowProvider, string input) Notify("\nWORKFLOW: Done!\n"); } - public async Task MonitorAndDisposeWorkflowRunAsync(Checkpointed run, ExternalResponse? response = null) + public async Task MonitorAndDisposeWorkflowRunAsync(StreamingRun run, ExternalResponse? response = null) { #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await using IAsyncDisposable disposeRun = run; @@ -124,10 +124,10 @@ public async Task ExecuteAsync(Func workflowProvider, string input) if (response is not null) { - await run.Run.SendResponseAsync(response).ConfigureAwait(false); + await run.SendResponseAsync(response).ConfigureAwait(false); } - await foreach (WorkflowEvent workflowEvent in run.Run.WatchStreamAsync().ConfigureAwait(false)) + await foreach (WorkflowEvent workflowEvent in run.WatchStreamAsync().ConfigureAwait(false)) { switch (workflowEvent) { @@ -179,7 +179,7 @@ public async Task ExecuteAsync(Func workflowProvider, string input) Console.WriteLine(activityEvent.Message.Trim()); break; - case AgentRunUpdateEvent streamEvent: + case AgentResponseUpdateEvent streamEvent: if (!string.Equals(messageId, streamEvent.Update.MessageId, StringComparison.Ordinal)) { hasStreamed = false; @@ -229,7 +229,7 @@ public async Task ExecuteAsync(Func workflowProvider, string input) } break; - case AgentRunResponseEvent messageEvent: + case AgentResponseEvent messageEvent: try { if (hasStreamed) @@ -270,9 +270,10 @@ public async Task ExecuteAsync(Func workflowProvider, string input) /// private async ValueTask HandleExternalRequestAsync(ExternalRequest request) { - ExternalInputRequest inputRequest = - request.DataAs() ?? - throw new InvalidOperationException($"Expected external request type: {request.GetType().Name}."); + if (!request.TryGetDataAs(out var inputRequest)) + { + throw new InvalidOperationException($"Expected external request type: {request.PortInfo.RequestType}."); + } List responseMessages = []; diff --git a/dotnet/AgentFrameworkSamples.slnx b/dotnet/AgentFrameworkSamples.slnx new file mode 100644 index 0000000..c895f3d --- /dev/null +++ b/dotnet/AgentFrameworkSamples.slnx @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2795ffd97bc2990d8b35e12321df5fd5df8694c4 Mon Sep 17 00:00:00 2001 From: Bruno Capuano Date: Sat, 21 Feb 2026 14:13:54 -0500 Subject: [PATCH 03/10] Add .NET samples for AI agent framework and tools - Introduced travel agent sample demonstrating AI agent creation and tool usage. - Added basic agent framework samples showcasing autonomous agent behavior and design patterns. - Implemented multi-turn conversation handling with stateful agents using AgentSession. - Created retrieval-augmented generation (RAG) samples using Azure AI Foundry for file search and document grounding. - Developed multi-agent workflows demonstrating collaboration between agents in various scenarios. - Added tools for vision analysis, code interpretation, and Bing grounding to enhance agent capabilities. - Implemented AGUI protocol client and server for interactive agent communication. - Added OpenTelemetry tracing for monitoring agent workflows. - Introduced YAML-based declarative workflow creation for Azure AI Foundry. - Suppressed experimental API warnings and set up .NET SDK versioning in project configuration. --- .../Program.cs | 13 ++++--- .../README.md | 26 ++++++++++++++ .../dotnet-agent-framework-travelagent.csproj | 7 +++- .../Program.cs | 13 ++++--- .../README.md | 26 ++++++++++++++ .../dotnet-agent-framework-basicagent.csproj | 7 +++- .../Program.cs | 13 ++++--- .../README.md | 26 ++++++++++++++ .../dotnet-agent-framework-basicagent.csproj | 7 +++- .../Program.cs | 13 ++++--- .../README.md | 26 ++++++++++++++ ...otnet-agent-framework-ghmodels-tool.csproj | 7 +++- .../Program.cs | 10 ++++-- .../README.md | 28 +++++++++++++++ ...ent-framework-msfoundry-file-search.csproj | 7 +++- .../Program.cs | 13 ++++--- .../README.md | 26 ++++++++++++++ ...nt-framrwork-ghmodel-planningdesign.csproj | 7 +++- .../Program.cs | 13 ++++--- .../README.md | 26 ++++++++++++++ ...ework-ghmodel-workflow-multi-agents.csproj | 7 +++- .../dotnet-travelagent-ghmodel/Program.cs | 13 ++++--- .../dotnet-travelagent-ghmodel/README.md | 26 ++++++++++++++ .../dotnet-travelagent-ghmodel.csproj | 7 +++- .../01-dotnet-agent-framework-aoai.csproj | 7 +++- .../01-dotnet-agent-framework-aoai/Program.cs | 10 ++++-- .../01-dotnet-agent-framework-aoai/README.md | 26 ++++++++++++++ .../02-dotnet-agent-framework-ghmodel.csproj | 7 +++- .../Program.cs | 13 ++++--- .../README.md | 26 ++++++++++++++ ...03-dotnet-agent-framework-msfoundry.csproj | 7 +++- .../Program.cs | 10 ++++-- .../README.md | 26 ++++++++++++++ ...dotnet-agent-framework-foundrylocal.csproj | 7 +++- .../Program.cs | 11 ++++-- .../README.md | 27 ++++++++++++++ ...et-agent-framework-msfoundry-vision.csproj | 7 +++- .../Program.cs | 7 +++- .../README.md | 27 ++++++++++++++ ...ramework-msfoundry-code-interpreter.csproj | 7 +++- .../Program.cs | 7 +++- .../README.md | 27 ++++++++++++++ ...t-framework-msfoundry-binggrounding.csproj | 7 +++- .../Program.cs | 9 +++-- .../README.md | 27 ++++++++++++++ ...ent-framework-msfoundry-file-search.csproj | 7 +++- .../Program.cs | 10 ++++-- .../README.md | 28 +++++++++++++++ .../AgentMCP.Console/AgentMCP.Console.csproj | 7 +++- .../AgentMCP.Console/Program.cs | 10 ++++-- .../AgentMCP.Console/README.md | 28 +++++++++++++++ .../Program.cs | 10 ++++-- .../README.md | 28 +++++++++++++++ ...ent-framework-msfoundry-file-search.csproj | 7 +++- ...nt-framework-workflow-ghmodel-basic.csproj | 7 +++- .../Program.cs | 12 +++++-- .../README.md | 26 ++++++++++++++ ...amework-workflow-ghmodel-sequential.csproj | 7 +++- .../Program.cs | 10 ++++-- .../README.md | 27 ++++++++++++++ ...amework-workflow-ghmodel-concurrent.csproj | 7 +++- .../Program.cs | 10 ++++-- .../README.md | 29 +++++++++++++++ ...mework-workflow-msfoundry-condition.csproj | 7 +++- .../README.md | 28 +++++++++++++++ .../GHModel.dotNET.AI.Workflow.DevUI.csproj | 3 +- .../Program.cs | 6 ++-- .../Properties/launchSettings.json | 4 ++- .../README.md | 28 +++++++++++++++ ...odel.dotNET.AI.Workflow.AGUI.Client.csproj | 3 +- .../Program.cs | 7 +++- .../Properties/launchSettings.json | 16 ++------- .../README.md | 35 ++++++++++++++++++ .../ChatClientAgentFactory.cs | 9 ++--- ...odel.dotNET.AI.Workflow.AGUI.Server.csproj | 3 +- .../Program.cs | 2 +- .../Properties/launchSettings.json | 5 +-- .../README.md | 28 +++++++++++++++ .../GHModel.dotNET.AI.Workflow.DevUI.csproj | 3 +- .../Program.cs | 6 ++-- .../Properties/launchSettings.json | 4 ++- .../README.md | 27 ++++++++++++++ ...el.dotNET.AI.Workflow.OpenTelemetry.csproj | 7 +++- .../Program.cs | 12 +++++-- .../README.md | 36 +++++++++++++++++++ .../CreateWorkflowWithYAML.csproj | 9 ++++- .../CreateWorkflowWithYAML/Program.cs | 11 ++++-- .../CreateWorkflowWithYAML/README.md | 33 +++++++++++++++++ Directory.Build.props | 7 ++++ global.json | 7 ++++ 90 files changed, 1160 insertions(+), 125 deletions(-) create mode 100644 00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md create mode 100644 00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md create mode 100644 00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md create mode 100644 00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/README.md create mode 100644 00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/README.md create mode 100644 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/README.md create mode 100644 00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md create mode 100644 02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md create mode 100644 03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md create mode 100644 03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md create mode 100644 03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md create mode 100644 03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md create mode 100644 04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/README.md create mode 100644 04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/README.md create mode 100644 04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/README.md create mode 100644 04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/README.md create mode 100644 05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/README.md create mode 100644 06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md create mode 100644 07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/README.md create mode 100644 07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/README.md create mode 100644 07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/README.md create mode 100644 07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md create mode 100644 08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/README.md create mode 100644 09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/README.md create mode 100644 09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/README.md create mode 100644 09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/README.md create mode 100644 09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/README.md create mode 100644 09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/README.md create mode 100644 Directory.Build.props create mode 100644 global.json diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs index 0dbe5f5..67b382f 100644 --- a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs +++ b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs @@ -4,14 +4,19 @@ using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; +using Microsoft.Extensions.Configuration; // Load environment variables from .env file -// Get GitHub Models configuration from environment variables -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is required"); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? "gpt-4o-mini"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is required"); // Configure OpenAI client for GitHub Models diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md new file mode 100644 index 0000000..fd10ca7 --- /dev/null +++ b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md @@ -0,0 +1,26 @@ +# Travel Agent — Intro to AI Agents (.NET) + +Introduces the `AIAgent` abstraction by building a travel-planning agent with a custom tool that returns random destination suggestions. Demonstrates both a standard (awaited) response and a streaming response. + +## What it shows +- Creating an `AIAgent` from an `OpenAI` chat client targeting **GitHub Models** +- Registering a C# method as an agent tool with `AIFunctionFactory.Create` +- Calling `RunAsync` for a single response and `RunStreamingAsync` for token-by-token streaming + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj index 2a8936e..7fc6af2 100644 --- a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj +++ b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ dotnet_agent_framework_travelagent enable enable + e01f82ab-60d0-4d0e-82b0-476cd48c55b3 @@ -18,4 +19,8 @@ + + + + \ No newline at end of file diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs index 8b3cd89..9f94f51 100644 --- a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs +++ b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs @@ -4,14 +4,19 @@ using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; +using Microsoft.Extensions.Configuration; // Load environment variables from .env file -// Get GitHub Models configuration from environment variables -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? "gpt-4o-mini"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); // Configure OpenAI client for GitHub Models diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md new file mode 100644 index 0000000..b82cc75 --- /dev/null +++ b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md @@ -0,0 +1,26 @@ +# Basic Agent — Exploring Agentic Frameworks (.NET) + +Demonstrates how an agentic framework wraps a chat client to produce an autonomous agent. A destination-suggestion tool is attached to the agent and invoked automatically during the conversation. + +## What it shows +- Constructing an `AIAgent` with a name, instructions, and a tool +- How the Agent Framework handles the tool-calling loop transparently +- Side-by-side standard and streaming responses + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj index 8881f78..e498d37 100644 --- a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj +++ b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ dotnet_agent_framework_basicagent enable enable + 03318c00-adb1-4220-a32a-7b0068e30fff @@ -18,4 +19,8 @@ + + + + \ No newline at end of file diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs index 8b3cd89..9f94f51 100644 --- a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs +++ b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs @@ -4,14 +4,19 @@ using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; +using Microsoft.Extensions.Configuration; // Load environment variables from .env file -// Get GitHub Models configuration from environment variables -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? "gpt-4o-mini"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); // Configure OpenAI client for GitHub Models diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md new file mode 100644 index 0000000..f135937 --- /dev/null +++ b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md @@ -0,0 +1,26 @@ +# Basic Agent — Agentic Design Patterns (.NET) + +Illustrates common agentic design patterns: giving an agent a specific role through system instructions and equipping it with a domain-specific tool. The same agent is invoked two ways to compare response styles. + +## What it shows +- Role-based agent instructions (system prompt) +- Tool attachment and automatic tool-call dispatch +- Standard vs. streaming response patterns + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj index 8881f78..cd10951 100644 --- a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj +++ b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ dotnet_agent_framework_basicagent enable enable + 328e4b11-22e2-4b5d-8e08-2f4e47079175 @@ -18,4 +19,8 @@ + + + + \ No newline at end of file diff --git a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/Program.cs b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/Program.cs index 90d8666..12cf890 100644 --- a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/Program.cs +++ b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/Program.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; +using Microsoft.Extensions.Configuration; // Load environment variables from .env file @@ -29,11 +30,15 @@ static string GetRandomDestination() return destinations[index]; } -// Get GitHub Models configuration from environment variables -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? "gpt-4o-mini"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); // Configure OpenAI client for GitHub Models diff --git a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/README.md b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/README.md new file mode 100644 index 0000000..944deac --- /dev/null +++ b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/README.md @@ -0,0 +1,26 @@ +# Tool Use (.NET) + +Shows how to build a stateful agent conversation using `AgentSession`. A travel-planning agent uses a custom tool to suggest destinations across multiple sequential turns, demonstrating how session context is preserved between calls. + +## What it shows +- Creating and managing an `AgentSession` for multi-turn conversations +- Registering and invoking a C# function as an agent tool +- How the agent autonomously decides when to call a tool based on user input + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj index 0a940c5..9e3aeca 100644 --- a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj +++ b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ dotnet_agent_framework_ghmodels_tool enable enable + c2c7f177-4a84-4250-9357-98122c3f2feb @@ -18,4 +19,8 @@ + + + + \ No newline at end of file diff --git a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/Program.cs b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/Program.cs index 8964fce..0c84819 100644 --- a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/Program.cs +++ b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/Program.cs @@ -6,9 +6,15 @@ using OpenAI; using OpenAI.Files; using OpenAI.VectorStores; +using Microsoft.Extensions.Configuration; -var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); -var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; // Create an AI Project client and get an OpenAI client that works with the foundry service. AIProjectClient aiProjectClient = new( diff --git a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/README.md b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/README.md new file mode 100644 index 0000000..82c79e4 --- /dev/null +++ b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/README.md @@ -0,0 +1,28 @@ +# Agentic RAG — File Search with Azure AI Foundry (.NET) + +Uploads a document to Azure AI Foundry, creates a vector store from it, and attaches a `HostedFileSearchTool` to the agent. The agent answers questions using only the uploaded document's content. + +## What it shows +- Uploading files to Azure AI Foundry and creating a vector store +- Attaching `HostedFileSearchTool` for retrieval-augmented generation (RAG) +- Grounding an agent's responses strictly in the uploaded document + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An [Azure AI Foundry](https://ai.azure.com) project +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "" +dotnet user-secrets set "AZURE_AI_MODEL_DEPLOYMENT_NAME" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` + +> The sample uploads `../document.md` (located in the `05-agentic-rag/code_samples/` folder) to Foundry at startup. diff --git a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj index dc3c08e..cc0df30 100644 --- a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj +++ b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,7 @@ True enable enable + 4e72b0fc-2c2e-4371-9d75-0912883af3f6 @@ -21,4 +22,8 @@ + + + + \ No newline at end of file diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Program.cs b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Program.cs index 772a972..ead18e3 100644 --- a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Program.cs +++ b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Program.cs @@ -5,15 +5,20 @@ using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; +using Microsoft.Extensions.Configuration; // Load environment variables from .env file -// Get GitHub Models configuration from environment variables -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? "gpt-4o-mini"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); // Configure OpenAI client for GitHub Models diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/README.md b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/README.md new file mode 100644 index 0000000..6340eac --- /dev/null +++ b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/README.md @@ -0,0 +1,26 @@ +# Planning Design (.NET) + +Demonstrates the planning agentic design pattern. A planner agent receives a high-level travel request and produces a structured `TravelPlan` JSON object that breaks the task into specialised sub-agent assignments (flights, hotels, activities, etc.). + +## What it shows +- Structured JSON output via `ChatResponseFormatJson` and `AIJsonUtilities.CreateJsonSchema` +- Using an agent as an orchestrator / router that decomposes tasks for specialist agents +- Configuring `ChatClientAgentOptions` with a response format schema + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj index fcfa6c7..5f1f3ae 100644 --- a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj +++ b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ dotnet_agent_framrwork_ghmodel_planningdesign enable enable + 3bbd10f1-79a7-498e-9aba-1c26488635ae @@ -18,4 +19,8 @@ + + + + \ No newline at end of file diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs index 4a69b9e..de204fd 100644 --- a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs +++ b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs @@ -6,14 +6,19 @@ using Microsoft.Agents.AI; using Microsoft.Agents.AI.Workflows; using OpenAI; +using Microsoft.Extensions.Configuration; // Load environment variables from .env file -// Get GitHub Models configuration from environment variables -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? "gpt-4o-mini"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); // Configure OpenAI client for GitHub Models diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md new file mode 100644 index 0000000..5029286 --- /dev/null +++ b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md @@ -0,0 +1,26 @@ +# Multi-Agent Workflow (.NET) + +Shows how to connect two agents in a workflow: a **FrontDesk** travel agent proposes recommendations and a **Concierge** reviewer approves or refines them. The workflow runs iteratively until the concierge approves. + +## What it shows +- Building a two-agent review loop with `WorkflowBuilder` +- Defining distinct roles and personas via `ChatClientAgentOptions` +- Running a workflow with `InProcessExecution.RunStreamingAsync` and consuming `WorkflowEvent` updates + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj index 91f87ce..478bff2 100644 --- a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj +++ b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ dotnet_agent_framework_ghmodel_workflow_multi_agents enable enable + 347ece07-9c59-405e-8282-387fa070c48a @@ -23,4 +24,8 @@ + + + + \ No newline at end of file diff --git a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/Program.cs b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/Program.cs index 1aaea38..f0b8600 100644 --- a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/Program.cs +++ b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/Program.cs @@ -4,14 +4,19 @@ using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; +using Microsoft.Extensions.Configuration; // Load environment variables from .env file -// Get GitHub Models configuration from environment variables -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is required"); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? "gpt-4o-mini"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is required"); // Configure OpenAI client for GitHub Models diff --git a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md new file mode 100644 index 0000000..424064d --- /dev/null +++ b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md @@ -0,0 +1,26 @@ +# Travel Agent — Create Your First Agent (.NET) + +A hands-on "Hello World" for the Microsoft Agent Framework. Builds a travel-planning agent backed by **GitHub Models**, attaches a destination-picker tool, and exercises both awaited and streaming invocation styles. + +## What it shows +- Wiring `OpenAIClient` → `GetChatClient` → `AsIChatClient` → `AsAIAgent` pipeline +- Providing a named tool via `AIFunctionFactory.Create` +- `RunAsync` (single response) and `RunStreamingAsync` (token streaming) + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj index abf47ed..84a6843 100644 --- a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj +++ b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ dotnet_travelagent_ghmodel enable enable + 72ce6d02-83a5-4d22-8e78-1bd196957158 @@ -17,4 +18,8 @@ + + + + \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj b/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj index 5fe071f..759033f 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj +++ b/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ _01_dotnet_agent_framework_aoai enable enable + 2e421ed5-5bee-47c3-9608-7d42f9dfed00 @@ -16,4 +17,8 @@ + + + + \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs b/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs index 19891b1..46c5803 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs +++ b/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs @@ -2,9 +2,15 @@ using Azure.Identity; using Microsoft.Agents.AI; using OpenAI.Chat; +using Microsoft.Extensions.Configuration; -var aoai_endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); -var aoai_model_id = Environment.GetEnvironmentVariable("AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME") ?? "gpt-4.1-mini"; +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var aoai_endpoint = config["AZURE_OPENAI_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); +var aoai_model_id = config["AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME"] ?? "gpt-4.1-mini"; Console.WriteLine($"Using Azure OpenAI Endpoint: {aoai_endpoint}"); Console.WriteLine($"Using Azure OpenAI Model Deployment: {aoai_model_id}"); diff --git a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md b/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md new file mode 100644 index 0000000..0805b7f --- /dev/null +++ b/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md @@ -0,0 +1,26 @@ +# Agent Framework — Azure OpenAI Provider (.NET) + +Shows how to create an `AIAgent` using **Azure OpenAI** as the backing provider, authenticating with `AzureCliCredential`. + +## What it shows +- Constructing an `AIAgent` from `AzureOpenAIClient` (no OpenAI API key required) +- Passwordless authentication via Azure CLI (`az login`) +- Standard and streaming responses against an Azure-hosted deployment + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An Azure OpenAI resource with a deployed model +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_OPENAI_ENDPOINT" "" +dotnet user-secrets set "AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME" "gpt-4.1-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj b/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj index 50a9caa..a29b1ec 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj +++ b/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ _02_dotnet_agent_framework_ghmodel enable enable + 897b8bea-86e0-456a-a321-9a96d36c8d67 @@ -17,4 +18,8 @@ + + + + \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs b/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs index 628568e..87c8e0a 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs +++ b/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs @@ -3,14 +3,19 @@ using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; +using Microsoft.Extensions.Configuration; // Load environment variables from .env file -// Get configuration from environment variables -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? "gpt-4o-mini"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); // Configure OpenAI client for GitHub Models diff --git a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md b/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md new file mode 100644 index 0000000..9998052 --- /dev/null +++ b/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md @@ -0,0 +1,26 @@ +# Agent Framework — GitHub Models Provider (.NET) + +Minimal sample showing `AIAgent` creation with **GitHub Models** as the provider. Demonstrates that switching providers only requires changing the `IChatClient` — the agent API stays the same. + +## What it shows +- Creating an `AIAgent` from `OpenAIClient` pointed at `models.inference.ai.azure.com` +- Provider-agnostic `RunAsync` / `RunStreamingAsync` invocation +- How `AsIChatClient()` adapts the OpenAI SDK chat client to `Microsoft.Extensions.AI` + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj b/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj index 8e67e0c..4d635d5 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj +++ b/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,7 @@ True enable enable + 06e4bd3a-9846-4330-98e5-7e0431118217 @@ -20,4 +21,8 @@ + + + + \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs b/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs index 3142e58..930a2ac 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs +++ b/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs @@ -3,9 +3,15 @@ using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; -var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); -var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; // Create an AI Project client and get an OpenAI client that works with the foundry service. AIProjectClient aiProjectClient = new( diff --git a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md b/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md new file mode 100644 index 0000000..2a5527e --- /dev/null +++ b/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md @@ -0,0 +1,26 @@ +# Agent Framework — Azure AI Foundry Provider (.NET) + +Creates a managed agent on **Azure AI Foundry** via `AIProjectClient.CreateAIAgentAsync` using `AgentVersionCreationOptions` / `PromptAgentDefinition`. The agent is versioned and reusable across sessions. + +## What it shows +- Using `AIProjectClient` to create and retrieve versioned agents in Foundry +- `AgentVersionCreationOptions` with `PromptAgentDefinition` for declarative agent setup +- Invoking a Foundry-hosted agent with `RunAsync` + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An [Azure AI Foundry](https://ai.azure.com) project with a deployed model +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "" +dotnet user-secrets set "AZURE_AI_MODEL_DEPLOYMENT_NAME" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj b/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj index 3d6854b..860ad98 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj +++ b/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ _04_dotnet_agent_framework_foundrylocal enable enable + 54f947d6-b3f4-4d15-9772-afd04450d9d3 @@ -17,4 +18,8 @@ + + + + \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs b/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs index e666b6f..01d0d9f 100644 --- a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs +++ b/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs @@ -3,13 +3,18 @@ using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using OpenAI; +using Microsoft.Extensions.Configuration; // Load environment variables from .env file -// Get Foundry Local configuration from environment variables -var foundryLocalEndpoint = Environment.GetEnvironmentVariable("FOUNDRYLOCAL_ENDPOINT") +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var foundryLocalEndpoint = config["FOUNDRYLOCAL_ENDPOINT"] ?? throw new InvalidOperationException("FOUNDRYLOCAL_ENDPOINT is not set."); -var foundryLocalModelId = Environment.GetEnvironmentVariable("FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME") +var foundryLocalModelId = config["FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME"] ?? throw new InvalidOperationException("FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME is not set."); Console.WriteLine($"Endpoint: {foundryLocalEndpoint}"); diff --git a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md b/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md new file mode 100644 index 0000000..bfec3e7 --- /dev/null +++ b/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md @@ -0,0 +1,27 @@ +# Agent Framework — Foundry Local Provider (.NET) + +Runs an `AIAgent` entirely on-device using **Foundry Local** — no cloud endpoint or API key required (an empty `"nokey"` credential is accepted). Demonstrates that the same agent API works with locally-hosted models. + +## What it shows +- Connecting to a local Foundry endpoint with `OpenAIClient` +- Running an agent without any cloud dependency +- Standard and streaming responses from a local model + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- [Foundry Local](https://github.com/microsoft/foundry-local) installed and running with a downloaded model + +## Configure secrets + +```bash +dotnet user-secrets set "FOUNDRYLOCAL_ENDPOINT" "http://localhost:5272/v1" +dotnet user-secrets set "FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME" "" +``` + +> Run `foundry model list` to view downloaded model aliases. + +## Run + +```bash +dotnet run +``` diff --git a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj index 82b846d..50cc47d 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,7 @@ True enable enable + 874a6202-85a7-4082-9b3f-7587cd525178 @@ -20,4 +21,8 @@ + + + + \ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/Program.cs b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/Program.cs index b0f3af2..bdc35a8 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/Program.cs +++ b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/Program.cs @@ -6,9 +6,14 @@ using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); -var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var azure_foundry_endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var azure_foundry_model_id = "gpt-4o"; var imgPath ="../../../files/home.png"; diff --git a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/README.md b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/README.md new file mode 100644 index 0000000..050f874 --- /dev/null +++ b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/README.md @@ -0,0 +1,27 @@ +# Vision Tool — Azure AI Foundry (.NET) + +Demonstrates multimodal input: an image of a room is sent to the agent, which analyses the visible furniture and provides purchase recommendations. Uses `DataContent` to attach image bytes to a `ChatMessage`. + +## What it shows +- Sending images to an agent via `DataContent` (base-64 encoded bytes) in a `ChatMessage` +- Creating a Foundry-hosted agent configured for multimodal (`gpt-4o`) inference +- Maintaining a session (`AgentSession`) across a multi-turn visual conversation + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An [Azure AI Foundry](https://ai.azure.com) project with a `gpt-4o` deployment +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "" +``` + +> The model is hardcoded to `gpt-4o` because vision requires a multimodal model. The image used is `../../../files/home.png` (relative to the project folder). + +## Run + +```bash +dotnet run +``` diff --git a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj index 17bc72b..bc2362f 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,7 @@ True enable enable + 739b43fa-eee0-4252-82f4-618910423167 $(NoWarn);CA1812;OPENAI001;MEAI001 @@ -21,4 +22,8 @@ + + + + \ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/Program.cs b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/Program.cs index 65626bf..97f3693 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/Program.cs +++ b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/Program.cs @@ -9,9 +9,14 @@ using Microsoft.Extensions.AI; using OpenAI.Assistants; using OpenAI.Responses; +using Microsoft.Extensions.Configuration; +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); -var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var azure_foundry_endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var azure_foundry_model_id = "gpt-4.1-mini"; const string AgentName = "Code-Agent-Framework"; diff --git a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/README.md b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/README.md new file mode 100644 index 0000000..070af24 --- /dev/null +++ b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/README.md @@ -0,0 +1,27 @@ +# Code Interpreter Tool — Azure AI Foundry (.NET) + +Attaches the hosted **Code Interpreter** tool to a Foundry agent, which lets it write and execute Python code server-side to answer computational questions. The sample captures and displays both the generated code and the execution output. + +## What it shows +- Enabling `ResponseTool.CreateCodeInterpreterTool` on a Foundry agent +- Reading `CodeInterpreterToolCallContent` and `CodeInterpreterToolResultContent` from the response +- How the agent autonomously writes and runs code to solve problems (Fibonacci sequence) + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An [Azure AI Foundry](https://ai.azure.com) project with a deployed model +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "" +``` + +> The model is hardcoded to `gpt-4.1-mini`. + +## Run + +```bash +dotnet run +``` diff --git a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj index 13d9eb5..80056be 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,7 @@ True enable enable + ee9707f4-4391-43ca-bdd5-38f721eb32a9 $(NoWarn);CA1812;OPENAI001;MEAI001 @@ -21,4 +22,8 @@ + + + + \ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/Program.cs b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/Program.cs index 9409ee2..3a129fe 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/Program.cs +++ b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/Program.cs @@ -9,12 +9,17 @@ using Microsoft.Extensions.AI; using OpenAI.Assistants; using OpenAI.Responses; +using Microsoft.Extensions.Configuration; // using OpenAI.Assistants; // using OpenAI.Responses; +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); -var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var azure_foundry_endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var azure_foundry_model_id = "gpt-4.1-mini"; const string AgentName = "Bing-Agent-Framework"; @@ -27,7 +32,7 @@ new AzureCliCredential()); -var connectionName = Environment.GetEnvironmentVariable("BING_CONNECTION_NAME"); +var connectionName = config["BING_CONNECTION_NAME"]; Console.WriteLine($"Using Bing Connection: {connectionName}"); diff --git a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/README.md b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/README.md new file mode 100644 index 0000000..c232f37 --- /dev/null +++ b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/README.md @@ -0,0 +1,27 @@ +# Bing Grounding Tool — Azure AI Foundry (.NET) + +Connects an Azure AI Foundry agent to a **Bing Grounding** connection so it can search the live web and cite sources in answers. Demonstrates how to attach a `BingGroundingAgentTool` to a Foundry-hosted agent. + +## What it shows +- Looking up an `AIProjectConnection` by name and wrapping it in `BingGroundingAgentTool` +- Attaching real-time web search capability to a Foundry agent +- Responses that reference live Bing search results + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An [Azure AI Foundry](https://ai.azure.com) project with a deployed model +- A **Bing Search** connection configured in your AI Foundry hub +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "" +dotnet user-secrets set "BING_CONNECTION_NAME" "" +``` + +## Run + +```bash +dotnet run +``` diff --git a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj index 77923e0..e03e613 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,7 @@ True enable enable + 8324968c-859a-4090-8afa-336940d7cf66 @@ -21,4 +22,8 @@ + + + + \ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs index 8d2bf25..054119c 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs +++ b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs @@ -7,9 +7,15 @@ using OpenAI; using OpenAI.Files; using OpenAI.VectorStores; +using Microsoft.Extensions.Configuration; -var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); -var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; // Create an AI Project client and get an OpenAI client that works with the foundry service. AIProjectClient aiProjectClient = new( diff --git a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/README.md b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/README.md new file mode 100644 index 0000000..6b693dc --- /dev/null +++ b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/README.md @@ -0,0 +1,28 @@ +# File Search Tool — Azure AI Foundry (.NET) + +Uploads a Markdown document to Azure AI Foundry, indexes it in a vector store, and attaches `HostedFileSearchTool` to the agent. The agent answers questions grounded exclusively in the uploaded file content. + +## What it shows +- Uploading files to Foundry with `OpenAIFileClient.UploadFileAsync` +- Creating a vector store and linking it via `HostedVectorStoreContent` +- Using `HostedFileSearchTool` for retrieval-augmented generation (RAG) + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An [Azure AI Foundry](https://ai.azure.com) project with a deployed model +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "" +dotnet user-secrets set "AZURE_AI_MODEL_DEPLOYMENT_NAME" "gpt-4o-mini" +``` + +> The sample uploads `../../../files/demo.md` (located in the `04.Tools/code_samples/` folder). + +## Run + +```bash +dotnet run +``` diff --git a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj index 4af0969..a3f62fb 100644 --- a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj +++ b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ True enable enable + d0e13627-3df1-4b64-aec6-0fb17f50a14d @@ -21,4 +22,8 @@ + + + + \ No newline at end of file diff --git a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/Program.cs b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/Program.cs index d216959..78c1396 100644 --- a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/Program.cs +++ b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/Program.cs @@ -7,9 +7,15 @@ using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; -var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set."); -var azure_foundry_model_id = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4.1-mini"; +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var azure_foundry_endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set."); +var azure_foundry_model_id = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4.1-mini"; var persistentAgentsClient = new PersistentAgentsClient(azure_foundry_endpoint, new AzureCliCredential()); diff --git a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/README.md b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/README.md new file mode 100644 index 0000000..5cd110d --- /dev/null +++ b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/README.md @@ -0,0 +1,28 @@ +# MCP Tool with Approval Flow — Azure AI Foundry (.NET) + +Connects a Foundry agent to a remote **Model Context Protocol (MCP)** server (`microsoft_learn`) and requires explicit user approval before each tool call. Demonstrates how to implement a human-in-the-loop approval gate for MCP-based tool invocations. + +## What it shows +- Attaching a `HostedMcpServerTool` to a Foundry agent with `ApprovalMode.AlwaysRequire` +- Processing `McpServerToolApprovalRequestContent` messages in the response loop +- Submitting user approval decisions back to the agent with `McpServerToolApprovalResponseContent` + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An [Azure AI Foundry](https://ai.azure.com) project with a deployed model +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "" +dotnet user-secrets set "AZURE_AI_MODEL_DEPLOYMENT_NAME" "gpt-4.1-mini" +``` + +## Run + +```bash +dotnet run +``` + +When the agent wants to call an MCP tool, it will prompt you to enter `Y` to approve before the call is made. diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs index 628248b..81e1b6a 100644 --- a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs @@ -6,9 +6,15 @@ using OpenAI; using OpenAI.Files; using OpenAI.VectorStores; +using Microsoft.Extensions.Configuration; -var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); -var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; // Create an AI Project client and get an OpenAI client that works with the foundry service. AIProjectClient aiProjectClient = new( diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md new file mode 100644 index 0000000..db09079 --- /dev/null +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md @@ -0,0 +1,28 @@ +# RAG — File Search with Azure AI Foundry (.NET) + +Uploads a Markdown knowledge-base document to Azure AI Foundry and uses `HostedFileSearchTool` to build a retrieval-augmented generation (RAG) pipeline. The agent answers questions using only the indexed document. + +## What it shows +- End-to-end RAG pattern: file upload → vector store creation → `HostedFileSearchTool` attachment → grounded Q&A +- Strict grounding instructions that prevent the agent from using general knowledge +- `AgentSession` for multi-turn document Q&A + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An [Azure AI Foundry](https://ai.azure.com) project with a deployed model +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "" +dotnet user-secrets set "AZURE_AI_MODEL_DEPLOYMENT_NAME" "gpt-4o-mini" +``` + +> The sample uploads `../../files/demo.md` (located in the `06.RAGs/code_samples/` folder). + +## Run + +```bash +dotnet run +``` diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj index dc3c08e..0ae961a 100644 --- a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,7 @@ True enable enable + 92469d2f-b467-4911-9cbc-dafa21cc55dd @@ -21,4 +22,8 @@ + + + + \ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj index 7a62f45..a96f05f 100644 --- a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj +++ b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ _01.dotnet_agent_framework_workflow_ghmodel_basic enable enable + c2f12400-7f7c-41bd-a2c5-188e7dbb4e13 @@ -17,4 +18,8 @@ + + + + \ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/Program.cs b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/Program.cs index 4534716..f7cbc30 100644 --- a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/Program.cs +++ b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/Program.cs @@ -5,13 +5,19 @@ using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using Microsoft.Agents.AI.Workflows; +using Microsoft.Extensions.Configuration; // Load environment variables // Get GitHub configuration -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? "gpt-4o-mini"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); // Configure OpenAI client var openAIOptions = new OpenAIClientOptions() diff --git a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/README.md b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/README.md new file mode 100644 index 0000000..036dd28 --- /dev/null +++ b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/README.md @@ -0,0 +1,26 @@ +# Basic Workflow — Two-Agent Review Loop (.NET) + +Builds a two-agent workflow using `WorkflowBuilder`: a **FrontDesk** travel agent proposes activity recommendations and a **Concierge** reviewer accepts or requests refinements. The agents take turns until the concierge approves. + +## What it shows +- Building a directed agent graph with `WorkflowBuilder.AddEdge` +- Running a workflow with `InProcessExecution.RunStreamingAsync` +- Consuming `WorkflowEvent` / `AgentResponseUpdateEvent` updates in a streaming loop + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj index 0fa3d9e..776269a 100644 --- a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj +++ b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ _02.dotnet_agent_framework_workflow_ghmodel_sequential enable enable + b0f6cf92-970e-48d5-94e4-58e1561d4fff @@ -17,4 +18,8 @@ + + + + \ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/Program.cs b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/Program.cs index 5a8a6e9..4df304c 100644 --- a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/Program.cs +++ b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/Program.cs @@ -5,12 +5,16 @@ using Microsoft.Extensions.AI; using Microsoft.Agents.AI; using Microsoft.Agents.AI.Workflows; +using Microsoft.Extensions.Configuration; -// Load environment variables +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); var github_model_id = "gpt-4o"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); var imgPath = "../../imgs/home.png"; diff --git a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/README.md b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/README.md new file mode 100644 index 0000000..ce5768e --- /dev/null +++ b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/README.md @@ -0,0 +1,27 @@ +# Sequential Workflow — Image-to-Quote Pipeline (.NET) + +Constructs a three-stage sequential workflow: a **Sales Agent** identifies furniture from a room image, a **Price Agent** estimates costs, and a **Quote Agent** produces a formatted Markdown purchase quote. Demonstrates multimodal input fed into a linear agent chain. + +## What it shows +- A multi-stage sequential pipeline with `WorkflowBuilder` +- Passing image bytes (`DataContent`) as initial workflow input +- Each agent receiving the previous agent's output as context + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token with access to `gpt-4o` + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +``` + +> The model is hardcoded to `gpt-4o`. The image used is `../../imgs/home.png` (relative to the project folder). + +## Run + +```bash +dotnet run +``` diff --git a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj index 23590cb..e8b0217 100644 --- a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj +++ b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ _03.dotnet_agent_framework_workflow_ghmodel_concurrent enable enable + 248d296e-d7c2-464b-8ace-5e2c3b1cbdc9 @@ -17,4 +18,8 @@ + + + + \ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/Program.cs b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/Program.cs index dbe8c86..dcac5ff 100644 --- a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/Program.cs +++ b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/Program.cs @@ -6,12 +6,16 @@ using Microsoft.Agents.AI; using Microsoft.Agents.AI.Workflows; using Microsoft.Agents.AI.Workflows.Reflection; +using Microsoft.Extensions.Configuration; -// Load environment variables +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); var github_model_id = "gpt-4o"; -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); // Configure OpenAI client var openAIOptions = new OpenAIClientOptions() diff --git a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/README.md b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/README.md new file mode 100644 index 0000000..6f43d90 --- /dev/null +++ b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/README.md @@ -0,0 +1,29 @@ +# Concurrent Workflow — Fan-Out / Fan-In Pattern (.NET) + +Demonstrates a parallel (fan-out) workflow: a **Researcher** and a **Planner** agent run concurrently on the same input, and a `ConcurrentAggregationExecutor` merges their outputs before producing a final combined travel plan. + +## What it shows +- `WorkflowBuilder.AddFanOutEdge` to dispatch to multiple agents simultaneously +- `AddFanInBarrierEdge` with `ConcurrentAggregationExecutor` to merge parallel outputs +- `ConcurrentStartExecutor` as the workflow entry point + +> **Note:** `ReflectingExecutor` and `IMessageHandler` used in this sample are marked obsolete. They will be replaced with `[MessageHandler]`-attributed partial classes in a future version. + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token with access to `gpt-4o` + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +``` + +> The model is hardcoded to `gpt-4o`. + +## Run + +```bash +dotnet run +``` diff --git a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj index e0d73f6..96d88af 100644 --- a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj +++ b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,7 @@ True enable enable + 861df000-8a3f-4d7f-a4ba-b14286e638a2 $(NoWarn);CA1812;OPENAI001;MEAI001 @@ -23,4 +24,8 @@ + + + + \ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md new file mode 100644 index 0000000..b78acdf --- /dev/null +++ b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md @@ -0,0 +1,28 @@ +# Conditional Workflow — Azure AI Foundry (.NET) + +Placeholder for a conditional branching workflow backed by **Azure AI Foundry**. The workflow will route agent execution to different paths based on run-time conditions evaluated by the workflow engine. + +> **Status:** Implementation in progress. Run the project to see the scaffold output. + +## What it will show +- Defining conditional edges in `WorkflowBuilder` that branch based on agent output +- Routing messages to different specialist agents depending on a decision condition +- Azure AI Foundry as the backing provider for a multi-agent conditional workflow + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An [Azure AI Foundry](https://ai.azure.com) project with a deployed model +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "" +dotnet user-secrets set "AZURE_AI_MODEL_DEPLOYMENT_NAME" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` diff --git a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj index 0b6e14e..a536fed 100644 --- a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj +++ b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj @@ -1,8 +1,9 @@ - + net10.0 enable + 83775884-eba3-4762-b4a3-a1220865f3a5 enable diff --git a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Program.cs b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Program.cs index 02e765d..6917de7 100644 --- a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Program.cs +++ b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Program.cs @@ -51,14 +51,12 @@ internal static class Program /// Command line arguments. private static void Main(string[] args) { - // Load environment variables from .env file - var builder = WebApplication.CreateBuilder(args); // Set up the Azure OpenAI client - var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); + var github_endpoint = builder.Configuration["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set. Run: dotnet user-secrets set \"GITHUB_ENDPOINT\" \"\""); var github_model_id = "gpt-4o"; - var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + var github_token = builder.Configuration["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set. Run: dotnet user-secrets set \"GITHUB_TOKEN\" \"\""); var openAIOptions = new OpenAIClientOptions() { diff --git a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Properties/launchSettings.json b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Properties/launchSettings.json index 0bac70a..003e913 100644 --- a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Properties/launchSettings.json +++ b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/Properties/launchSettings.json @@ -1,9 +1,11 @@ { + "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { - "Dev_UI_Applcaiton": { + "DevUI_Application": { "commandName": "Project", "launchUrl": "devui", "launchBrowser": true, + "dotnetRunMessages": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/README.md b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/README.md new file mode 100644 index 0000000..5082a2b --- /dev/null +++ b/08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/README.md @@ -0,0 +1,28 @@ +# Agent DevUI — Evaluation & Tracing (.NET) + +An ASP.NET Core web application that hosts the **Agent Framework DevUI** — an interactive browser-based interface for testing, debugging, and tracing agent workflows without writing a test harness. + +## What it shows +- Adding the DevUI to an ASP.NET Core app with `MapDevUI()` +- Registering agents and workflows via `Microsoft.Agents.AI.Hosting` +- `MapOpenAIResponses()` for Python DevUI cross-compatibility (dynamic model routing) +- Browsing agent conversation history and individual message events in the UI + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +``` + +## Run + +```bash +dotnet run +``` + +Open **http://localhost:50518/devui** in your browser to access the DevUI. diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/GHModel.dotNET.AI.Workflow.AGUI.Client.csproj b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/GHModel.dotNET.AI.Workflow.AGUI.Client.csproj index abf8990..d592607 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/GHModel.dotNET.AI.Workflow.AGUI.Client.csproj +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/GHModel.dotNET.AI.Workflow.AGUI.Client.csproj @@ -1,8 +1,9 @@ - + net10.0 enable + b632d09f-22ac-4b50-b033-ce78ba7f4696 enable diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Program.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Program.cs index 9345f71..b0ec8d0 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Program.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Program.cs @@ -6,7 +6,12 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -string serverUrl = Environment.GetEnvironmentVariable("AGUI_SERVER_URL") ?? "http://localhost:5018"; +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +string serverUrl = config["AGUI_SERVER_URL"] ?? "http://localhost:5018"; Console.WriteLine($"Connecting to AG-UI server at: {serverUrl}\n"); diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Properties/launchSettings.json b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Properties/launchSettings.json index 04df18a..a4d8bba 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Properties/launchSettings.json +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/Properties/launchSettings.json @@ -1,22 +1,12 @@ { "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { - "http": { + "AGUI_Client": { "commandName": "Project", "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "http://localhost:5027", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "https://localhost:7296;http://localhost:5027", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development", + "AGUI_SERVER_URL": "http://localhost:5018" } } } diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/README.md b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/README.md new file mode 100644 index 0000000..18d5983 --- /dev/null +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Client/README.md @@ -0,0 +1,35 @@ +# AGUI Client — AG-UI Protocol (.NET) + +An interactive console client that connects to the companion **AGUI Server** over the **AG-UI protocol** using `AGUIChatClient`. Demonstrates how any AG-UI-compliant server can be consumed as a standard `AIAgent` on the client side. + +## What it shows +- Connecting to a remote AG-UI server with `AGUIChatClient` +- Wrapping the remote endpoint as a first-class `AIAgent` via `AsAIAgent()` +- Multi-turn streaming conversation loop using `RunStreamingAsync` + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- The companion [AGUI Server](../GHModel.dotNET.AI.Workflow.AGUI.Server/) running at `http://localhost:5018` + +## Configure secrets + +The server URL defaults to `http://localhost:5018`. Override it if your server runs elsewhere: + +```bash +dotnet user-secrets set "AGUI_SERVER_URL" "http://localhost:5018" +``` + +## Run + +Start the server first, then run the client: + +```bash +# Terminal 1 — start the server +cd ../GHModel.dotNET.AI.Workflow.AGUI.Server +dotnet run + +# Terminal 2 — start the client +dotnet run +``` + +Type messages at the prompt. Enter `:q` or `quit` to exit. diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/ChatClientAgentFactory.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/ChatClientAgentFactory.cs index 6643690..3f10220 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/ChatClientAgentFactory.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/ChatClientAgentFactory.cs @@ -12,6 +12,7 @@ using Microsoft.Agents.AI.Workflows.Reflection; using Microsoft.Extensions.AI; using Microsoft.AspNetCore.HttpLogging; +using Microsoft.Extensions.Configuration; using OpenAI; @@ -20,12 +21,12 @@ internal static class ChatClientAgentFactory private static OpenAIClient? _openAIClient; private static string? github_model_id; - public static void Initialize() + public static void Initialize(IConfiguration config) { - string github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); - github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? throw new InvalidOperationException("GITHUB_MODEL_ID is not set."); - string github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + string github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set. Run: dotnet user-secrets set \"GITHUB_ENDPOINT\" \"\""); + github_model_id = config["GITHUB_MODEL_ID"] ?? throw new InvalidOperationException("GITHUB_MODEL_ID is not set. Run: dotnet user-secrets set \"GITHUB_MODEL_ID\" \"\""); + string github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set. Run: dotnet user-secrets set \"GITHUB_TOKEN\" \"\""); var openAIOptions = new OpenAIClientOptions() diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/GHModel.dotNET.AI.Workflow.AGUI.Server.csproj b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/GHModel.dotNET.AI.Workflow.AGUI.Server.csproj index 1eb1f57..a5e3d86 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/GHModel.dotNET.AI.Workflow.AGUI.Server.csproj +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/GHModel.dotNET.AI.Workflow.AGUI.Server.csproj @@ -1,8 +1,9 @@ - + net10.0 enable + 04d403a9-7f08-4501-aa93-99dbb6f13534 enable diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs index d3bd3b4..6df1036 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs @@ -30,7 +30,7 @@ builder.Services.AddAGUI(); -ChatClientAgentFactory.Initialize(); +ChatClientAgentFactory.Initialize(builder.Configuration); WebApplication app = builder.Build(); diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Properties/launchSettings.json b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Properties/launchSettings.json index c2db6d8..519e537 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Properties/launchSettings.json +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Properties/launchSettings.json @@ -1,8 +1,9 @@ { + "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { - "GHModel_dotNET_AI_Workflow_AGUI_Server": { + "AGUI_Server": { "commandName": "Project", - "launchBrowser": true, + "dotnetRunMessages": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/README.md b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/README.md new file mode 100644 index 0000000..c1e3462 --- /dev/null +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/README.md @@ -0,0 +1,28 @@ +# AGUI Server — AG-UI Protocol (.NET) + +An ASP.NET Core server that exposes agent workflows over the **AG-UI (Agent-User Interaction) protocol**. The server registers agents via `AddAGUI()` and maps their endpoints so any AG-UI-compatible client can stream conversation turns. + +## What it shows +- Setting up an AG-UI server with `builder.Services.AddAGUI()` and `app.MapAGUI()` +- `ChatClientAgentFactory` for provider-agnostic agent construction from configuration +- Streaming agent responses over the AG-UI protocol to connected clients + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +## Run + +```bash +dotnet run +``` + +The server listens on **http://localhost:5018**. Start this before running the companion [AGUI.Client](../GHModel.dotNET.AI.Workflow.AGUI.Client/). diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj index 0b6e14e..bd113a6 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/GHModel.dotNET.AI.Workflow.DevUI.csproj @@ -1,8 +1,9 @@ - + net10.0 enable + 099362eb-66e3-4e90-8704-44a022b3df24 enable diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs index 6b0e7af..512a379 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs @@ -51,14 +51,12 @@ internal static class Program /// Command line arguments. private static void Main(string[] args) { - // Load environment variables from .env file - var builder = WebApplication.CreateBuilder(args); // Set up the Azure OpenAI client - var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); + var github_endpoint = builder.Configuration["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set. Run: dotnet user-secrets set \"GITHUB_ENDPOINT\" \"\""); var github_model_id = "openai/gpt-5"; - var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + var github_token = builder.Configuration["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set. Run: dotnet user-secrets set \"GITHUB_TOKEN\" \"\""); var openAIOptions = new OpenAIClientOptions() { diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Properties/launchSettings.json b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Properties/launchSettings.json index 0bac70a..003e913 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Properties/launchSettings.json +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Properties/launchSettings.json @@ -1,9 +1,11 @@ { + "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { - "Dev_UI_Applcaiton": { + "DevUI_Application": { "commandName": "Project", "launchUrl": "devui", "launchBrowser": true, + "dotnetRunMessages": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/README.md b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/README.md new file mode 100644 index 0000000..1c3538f --- /dev/null +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/README.md @@ -0,0 +1,27 @@ +# Agent DevUI — Case Study (.NET) + +An ASP.NET Core web application that hosts the **Agent Framework DevUI** for interactive browser-based agent testing. This case-study variant is paired with the OpenTelemetry and AGUI samples in the same solution to demonstrate a complete agent observability story. + +## What it shows +- Hosting the DevUI alongside other ASP.NET services in a multi-project solution +- Registering agents and workflows via `Microsoft.Agents.AI.Hosting` +- `MapDevUI()` and `MapOpenAIResponses()` for full DevUI functionality + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +``` + +## Run + +```bash +dotnet run +``` + +Open **http://localhost:50518/devui** in your browser to access the DevUI. diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj index 1b8cdb9..6a9c114 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj @@ -1,10 +1,11 @@ - + Exe net10.0 enable enable + 2c130ad6-5dba-4207-af2a-4db898f9e666 @@ -27,4 +28,8 @@ + + + + \ No newline at end of file diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/Program.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/Program.cs index e32133a..b916914 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/Program.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/Program.cs @@ -19,6 +19,7 @@ using OpenTelemetry.Resources; using OpenTelemetry.Trace; using OpenAI; +using Microsoft.Extensions.Configuration; #region Setup Telemetry @@ -91,9 +92,14 @@ You can view the telemetry data in the Aspire Dashboard. Type your message and press Enter. Type 'exit' or empty message to quit. """); -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? throw new InvalidOperationException("GITHUB_MODEL_ID is not set."); -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = config["GITHUB_MODEL_ID"] ?? throw new InvalidOperationException("GITHUB_MODEL_ID is not set."); +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); var openAIOptions = new OpenAIClientOptions() { diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/README.md b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/README.md new file mode 100644 index 0000000..bbe2723 --- /dev/null +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/README.md @@ -0,0 +1,36 @@ +# OpenTelemetry Tracing — Agent Workflows (.NET) + +Instruments an agent workflow with **OpenTelemetry** and exports traces, metrics, and logs to the .NET Aspire dashboard (via OTLP). Shows how to observe Agent Framework telemetry alongside custom application spans. + +## What it shows +- Configuring `TracerProvider`, `MeterProvider`, and `LoggerFactory` with OTLP exporters +- Subscribing to `*Microsoft.Agents.AI` activity sources and meters for automatic framework telemetry +- Adding custom spans with `ActivitySource` around workflow execution +- HTTP client instrumentation to capture outbound calls to the model endpoint + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- A [GitHub Models](https://github.com/marketplace/models) personal access token +- A local OTLP collector — the [.NET Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) is the easiest option: + + ```bash + docker run --rm -p 18888:18888 -p 4317:4317 mcr.microsoft.com/dotnet/nightly/aspire-dashboard:latest + ``` + +## Configure secrets + +```bash +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +The OTLP endpoint defaults to `http://localhost:4317`. Override it with the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable if needed. + +## Run + +```bash +dotnet run +``` + +Open the Aspire dashboard at **http://localhost:18888** to browse traces and metrics generated by the workflow. diff --git a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj index b7e4fbb..990604c 100644 --- a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj +++ b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj @@ -1,10 +1,11 @@ - + Exe net10.0 enable enable + 9be133a2-f120-490b-bf73-6cfa7a742fce @@ -22,5 +23,11 @@ + + + + + + diff --git a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/Program.cs b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/Program.cs index 63ddacc..97b5502 100644 --- a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/Program.cs +++ b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/Program.cs @@ -13,10 +13,15 @@ internal sealed class Program { public static async Task Main(string[] args) { - // IConfiguration configuration = Application.InitializeConfig(); - Uri foundryEndpoint = new("https://kinfey-ai-ignite-demo-resource.services.ai.azure.com/api/projects/kinfey-ai-ignite-demo"); + var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); - WorkflowFactory workflowFactory = new("/Users/lokinfey/Desktop/AOAI/Foundry/FoundryV2/dotNET/decalareUI/YAML/workflowv2.yaml", foundryEndpoint); + Uri foundryEndpoint = new(config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set. Run: dotnet user-secrets set \"AZURE_AI_PROJECT_ENDPOINT\" \"\"")); + string yamlPath = config["WORKFLOW_YAML_PATH"] ?? "workflow.yaml"; + + WorkflowFactory workflowFactory = new(yamlPath, foundryEndpoint); WorkflowRunner runner = new(); await runner.ExecuteAsync(workflowFactory.CreateWorkflow, "junior developer"); } diff --git a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/README.md b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/README.md new file mode 100644 index 0000000..fef4615 --- /dev/null +++ b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/README.md @@ -0,0 +1,33 @@ +# Declarative Workflow with YAML — Azure AI Foundry (.NET) + +Loads a multi-agent workflow from a YAML definition file using `WorkflowFactory` and runs it with `WorkflowRunner`. Demonstrates how workflows can be defined declaratively without writing C# wiring code. + +## What it shows +- Using `WorkflowFactory` to deserialise a YAML workflow definition at runtime +- `WorkflowRunner.ExecuteAsync` to run a declaratively-defined workflow +- Separation of workflow topology (YAML) from host application code (C#) + +## Prerequisites +- [.NET 10 SDK](https://dot.net) +- An [Azure AI Foundry](https://ai.azure.com) project with a deployed model +- Azure CLI logged in (`az login`) + +## Configure secrets + +```bash +dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "" +``` + +Optionally, point to a custom YAML file: + +```bash +dotnet user-secrets set "WORKFLOW_YAML_PATH" "path/to/your-workflow.yaml" +``` + +The default YAML files (`workflow.yaml`, `apply_agent.yaml`, `hiring_manager_agent.yaml`) are located in the [`YAML/`](../YAML/) folder and are copied to the output directory at build time. + +## Run + +```bash +dotnet run +``` diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..35e2114 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,7 @@ + + + + $(NoWarn);OPENAI001;MEAI001 + false + + diff --git a/global.json b/global.json new file mode 100644 index 0000000..82dabbb --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "10.0.100", + "rollForward": "latestFeature", + "allowPrerelease": true + } +} From 675ab6f9b43e6b013e0e59e8e76db8417a3e3bfa Mon Sep 17 00:00:00 2001 From: Bruno Capuano Date: Sat, 21 Feb 2026 14:23:41 -0500 Subject: [PATCH 04/10] Add .NET and Python samples for Agent Framework integration with GitHub Models, Azure AI Foundry, and Foundry Local - Implemented .NET sample for GitHub Models using OpenAIClient and AIAgent. - Created .NET sample for Azure AI Foundry with AIProjectClient and agent creation. - Developed .NET sample for Foundry Local demonstrating local agent execution. - Added Python notebooks for Azure OpenAI, GitHub Models, Azure AI Foundry, and Foundry Local showcasing agent capabilities and integration patterns. - Included README files for each sample to guide setup and usage. --- .../Models/Plan.cs | 0 .../Models/TravelPlan.cs | 0 .../Program.cs | 0 .../README.md | 0 ...t-framework-ghmodel-planningdesign.csproj} | 2 +- 00.ForBeginners/README.md | 2 +- .../README.md | 682 +++++++++--------- .../01-dotnet-agent-framework-aoai.csproj | 0 .../01-dotnet-agent-framework-aoai/Program.cs | 0 .../01-dotnet-agent-framework-aoai/README.md | 0 .../02-dotnet-agent-framework-ghmodel.csproj | 0 .../Program.cs | 0 .../README.md | 0 ...03-dotnet-agent-framework-msfoundry.csproj | 0 .../Program.cs | 0 .../README.md | 0 ...dotnet-agent-framework-foundrylocal.csproj | 0 .../Program.cs | 0 .../README.md | 0 .../01-python-agent-framework-aoai.ipynb | 0 .../02-python-agent-framrwork-ghmodel.ipynb | 0 .../03-python-agent-framework-msfoundry.ipynb | 0 ...-python-agent-framework-foundrylocal.ipynb | 0 README.md | 4 +- dotnet/AgentFrameworkSamples.slnx | 10 +- 25 files changed, 350 insertions(+), 350 deletions(-) rename 00.ForBeginners/07-planning-design/code_samples/{dotnet-agent-framrwork-ghmodel-planningdesign => dotnet-agent-framework-ghmodel-planningdesign}/Models/Plan.cs (100%) rename 00.ForBeginners/07-planning-design/code_samples/{dotnet-agent-framrwork-ghmodel-planningdesign => dotnet-agent-framework-ghmodel-planningdesign}/Models/TravelPlan.cs (100%) rename 00.ForBeginners/07-planning-design/code_samples/{dotnet-agent-framrwork-ghmodel-planningdesign => dotnet-agent-framework-ghmodel-planningdesign}/Program.cs (100%) rename 00.ForBeginners/07-planning-design/code_samples/{dotnet-agent-framrwork-ghmodel-planningdesign => dotnet-agent-framework-ghmodel-planningdesign}/README.md (100%) rename 00.ForBeginners/07-planning-design/code_samples/{dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj => dotnet-agent-framework-ghmodel-planningdesign/dotnet-agent-framework-ghmodel-planningdesign.csproj} (93%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/README.md (97%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/python/01-python-agent-framework-aoai.ipynb (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/python/02-python-agent-framrwork-ghmodel.ipynb (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/python/03-python-agent-framework-msfoundry.ipynb (100%) rename {03.ExploerAgentFramework => 03.ExploreAgentFramework}/code_samples/python/04-python-agent-framework-foundrylocal.ipynb (100%) diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Models/Plan.cs b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/Models/Plan.cs similarity index 100% rename from 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Models/Plan.cs rename to 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/Models/Plan.cs diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Models/TravelPlan.cs b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/Models/TravelPlan.cs similarity index 100% rename from 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Models/TravelPlan.cs rename to 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/Models/TravelPlan.cs diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Program.cs b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/Program.cs similarity index 100% rename from 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/Program.cs rename to 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/Program.cs diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/README.md b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/README.md similarity index 100% rename from 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/README.md rename to 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/README.md diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/dotnet-agent-framework-ghmodel-planningdesign.csproj similarity index 93% rename from 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj rename to 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/dotnet-agent-framework-ghmodel-planningdesign.csproj index 5f1f3ae..4eaf6aa 100644 --- a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/dotnet-agent-framrwork-ghmodel-planningdesign.csproj +++ b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/dotnet-agent-framework-ghmodel-planningdesign.csproj @@ -3,7 +3,7 @@ Exe net10.0 - dotnet_agent_framrwork_ghmodel_planningdesign + dotnet_agent_framework_ghmodel_planningdesign enable enable 3bbd10f1-79a7-498e-9aba-1c26488635ae diff --git a/00.ForBeginners/README.md b/00.ForBeginners/README.md index eae8fd6..1a9f7cf 100644 --- a/00.ForBeginners/README.md +++ b/00.ForBeginners/README.md @@ -51,7 +51,7 @@ Explore advanced planning capabilities and design patterns with GitHub Models in **Code Samples:** - **Python:** [`python-agent-framrwork-ghmodel-planningdesign.ipynb`](./07-planning-design/code_samples/python-agent-framrwork-ghmodel-planningdesign.ipynb) -- **.NET:** [`dotnet-agent-framrwork-ghmodel-planningdesign.ipynb`](./07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign.ipynb) +- **.NET:** [`dotnet-agent-framework-ghmodel-planningdesign`](./07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/) ### 08. Multi-Agent Systems Build collaborative multi-agent workflows using GitHub Models for complex problem-solving scenarios. diff --git a/03.ExploerAgentFramework/README.md b/03.ExploreAgentFramework/README.md similarity index 97% rename from 03.ExploerAgentFramework/README.md rename to 03.ExploreAgentFramework/README.md index 1a6d57b..54f9316 100644 --- a/03.ExploerAgentFramework/README.md +++ b/03.ExploreAgentFramework/README.md @@ -1,342 +1,342 @@ -# Using the Agent Framework to Connect Different AI Solutions - -The Agent Framework provides a unified interface for interacting with various AI models and services. This tutorial demonstrates how to connect to four different AI solutions—Azure OpenAI Service, GitHub Models, Azure AI Foundry, and Foundry Local—using the framework's implementations in both .NET (C\#) and Python. - -## Configuration and Setup - -Before running any of the examples, you need to configure your environment variables. The framework uses these variables to connect to the different AI endpoints. Create a `.env` file in the root of your project and populate it with the necessary credentials and endpoints. - -[cite\_start]You can use the `.env.examples` file as a template[cite: 1]: - -```env -# For GitHub Models -GITHUB_TOKEN="Your GitHub Models Token" -GITHUB_ENDPOINT="Your GitHub Models Endpoint" -GITHUB_MODEL_ID="Your GitHub Model ID" - -# For Azure OpenAI Service -AZURE_OPENAI_ENDPOINT="Your Azure OpenAI Endpoint" -AZURE_OPENAI_CHAT_DEPLOYMENT_NAME ="Your Azure OpenAI Model Deployment Name" - -# For Foundry Local -FOUNDRYLOCAL_ENDPOINT="http://localhost:5272/v1" -FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME="Your Local Model Name (e.g., Qwen3-0.6b-cpu)" - -# For Azure AI Foundry (Azure AI Studio) -AZURE_AI_PROJECT_ENDPOINT ="Your Azure AI Foundry Project Endpoint" -AZURE_AI_MODEL_DEPLOYMENT_NAME ="Your Azure AI Foundry Project Deployment Name" -``` - ------ - -## 1\. Connecting to Azure OpenAI Service - -This section shows how to use the Agent Framework to connect to models deployed in Azure OpenAI Service. - -### Connection Architecture - -The framework uses a dedicated `AzureOpenAIClient` to handle authentication and communication with the Azure OpenAI endpoint. - -```mermaid -graph TD - A[Your Application] --> B{Agent Framework}; - B --> C[AzureOpenAIClient]; - C --> D[Azure OpenAI Service Endpoint]; -``` - -### .NET / C\# Implementation - -The .NET example uses the `Azure.AI.OpenAI` and `Microsoft.Agents.AI` libraries to create a client and run the agent. - -1. **Dependencies**: NuGet packages like `Azure.AI.OpenAI`, `Azure.Identity`, and the local `Microsoft.Agents.AI.dll` are required. -2. **Client Initialization**: The code initializes an `AzureOpenAIClient`, providing the service endpoint and credentials (e.g., `AzureCliCredential`). -3. **Agent Creation**: The `CreateAIAgent` extension method is called on the chat client to get an agent instance with system instructions. -4. **Execution**: The agent is run using `RunAsync` or `RunStreamingAsync`. - -**Key Code Snippet:** - -```csharp -// Load endpoint and model ID from environment variables -var aoai_endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT"); -var aoai_model_id = Environment.GetEnvironmentVariable("AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME"); - -// Create the agent -AIAgent agent = new AzureOpenAIClient( - new Uri(aoai_endpoint), - new AzureCliCredential()) - .GetChatClient(aoai_model_id) - .CreateAIAgent("You are a helpful assistant."); - -// Run the agent and get a response -Console.WriteLine(await agent.RunAsync("Write a haiku about Agent Framework.")); -``` - -### Python Implementation - -The Python example uses the `agent_framework.azure` library to achieve the same result. - -1. **Dependencies**: The key libraries are `agent_framework` and `azure-identity`. -2. **Agent Creation**: The `AzureOpenAIChatClient` is instantiated with a credential object. The `create_agent` method is then called to configure the agent with its instructions. -3. **Execution**: The `agent.run_stream()` method is used to invoke the agent and stream the response. - -**Key Code Snippet:** - -```python -from azure.identity import AzureCliCredential -from agent_framework.azure import AzureOpenAIChatClient - -# Create an agent with Azure CLI credentials -agent = AzureOpenAIChatClient(credential=AzureCliCredential()).create_agent( - instructions="You are a helpful weather agent." -) - -query = "Write a haiku about Agent Framework." - -# Stream the agent's response -async for chunk in agent.run_stream(query): - if chunk.text: - print(chunk.text, end="", flush=True) -``` - ------ - -## 2\. Connecting to GitHub Models - -GitHub Models provides an OpenAI-compatible API endpoint. This allows the Agent Framework to use its standard `OpenAIClient` to connect. - -### Connection Architecture - -The connection is made to the GitHub Models endpoint, which behaves like an OpenAI API. - -```mermaid -graph TD - A[Your Application] --> B{Agent Framework}; - B --> C[OpenAIClient]; - C --> D[GitHub Models Endpoint]; -``` - -### .NET / C\# Implementation - -The approach is similar to connecting to any OpenAI-compatible service. - -1. **Dependencies**: This uses the `Microsoft.Extensions.AI.OpenAI` package and local Agent Framework assemblies. -2. **Client Initialization**: An `OpenAIClient` is created. The `OpenAIClientOptions` are configured with the GitHub Models endpoint URL, and an `ApiKeyCredential` is used to pass the GitHub token. -3. **Agent Creation**: The `CreateAIAgent` method is used to instantiate the agent with its system prompt. - -**Key Code Snippet:** - -```csharp -// Load connection details from environment variables -var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT"); -var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID"); -var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN"); - -// Configure client options with the endpoint -var openAIOptions = new OpenAIClientOptions() -{ - Endpoint= new Uri(github_endpoint) -}; - -// Create the agent with an API key credential -AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) - .GetChatClient(github_model_id) - .CreateAIAgent(instructions:"You are a helpful assistant."); - -// Run the agent -Console.WriteLine(await agent.RunAsync("Write a haiku about Agent Framework.")); -``` - -### Python Implementation - -The Python example uses the `OpenAIChatClient` from the framework. - -1. **Dependencies**: The `agent_framework.openai` and `python-dotenv` libraries are used. -2. **Client Initialization**: The `OpenAIChatClient` is initialized with the `base_url` pointing to the GitHub endpoint and the `api_key` set to the GitHub token. -3. **Execution**: A list of `ChatMessage` objects is created and passed to the `client.get_response` method to get a completion. - -**Key Code Snippet:** - -```python -import os -from dotenv import load_dotenv -from agent_framework import ChatMessage, Role -from agent_framework.openai import OpenAIChatClient - -load_dotenv() - -# Initialize the client with GitHub endpoint and token -client = OpenAIChatClient( - base_url=os.environ.get("GITHUB_ENDPOINT"), - api_key=os.environ.get("GITHUB_TOKEN"), - ai_model_id=os.environ.get("GITHUB_MODEL_ID") -) - -# Prepare the messages and get a response -messages = [ - ChatMessage(role=Role.SYSTEM, text="You are a helpful assistant."), - ChatMessage(role=Role.USER, text="Write a haiku about Agent Framework.") - ] -response = await client.get_response(messages) -print(response.messages[0].text) -``` - ------ - -## 3\. Connecting to Azure AI Foundry (Azure AI Studio) - -Azure AI Foundry allows you to create and manage persistent agents. The Agent Framework provides a client to interact with these stateful agents. - -### Connection Architecture - -The framework communicates with the Azure AI Project endpoint to interact with specific, persistent agents by name or ID. - -```mermaid -graph TD - A[Your Application] --> B{Agent Framework}; - B --> C[PersistentAgentsClient]; - C --> D[Azure AI Project Endpoint]; -``` - -### .NET / C\# Implementation - -This example uses the `Azure.AI.Agents.Persistent` client library. - -1. **Dependencies**: The primary dependency is the `Azure.AI.Agents.Persistent` NuGet package. -2. **Client Initialization**: A `PersistentAgentsClient` is created using the Azure AI Project endpoint and a credential. -3. **Agent Creation/Retrieval**: The code first creates a new persistent agent with `CreateAgentAsync`. The resulting agent metadata is then used to get a runnable `AIAgent` instance with `GetAIAgentAsync`. -4. **Execution**: Agents in AI Foundry are stateful and operate on threads. A new thread is created with `agent.GetNewThread()`, and the `RunAsync` method is called with both the prompt and the thread. - -**Key Code Snippet:** - -```csharp -// Load endpoint and model ID from environment variables -var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT"); -var azure_foundry_model_id = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME"); - -// Create the client -var persistentAgentsClient = new PersistentAgentsClient(azure_foundry_endpoint, new AzureCliCredential()); - -// Create a new persistent agent -var agentMetadata = await persistentAgentsClient.Administration.CreateAgentAsync( - model: azure_foundry_model_id, - name: "Agent-Framework", - instructions: "You are an AI assistant that helps people find information."); - -// Get the agent instance and a new thread for conversation -AIAgent agent = await persistentAgentsClient.GetAIAgentAsync(agentMetadata.Value.Id); -AgentThread thread = agent.GetNewThread(); - -// Run the agent within the context of the thread -Console.WriteLine(await agent.RunAsync("Write a haiku about Agent Framework", thread)); -``` - -### Python Implementation - -The Python example uses `AzureAIAgentClient` to interact with persistent agents. - -1. **Dependencies**: `agent_framework.azure` and `azure-identity` are required. -2. **Client Initialization**: The `AzureAIAgentClient` is initialized with an async credential. -3. **Agent and Thread Management**: Inside an `async with` block, `client.create_agent` defines a persistent agent. A new conversational context is created with `agent.get_new_thread()`. -4. **Execution**: `agent.run` is called with the query and the thread object. - -**Key Code Snippet:** - -```python -from azure.identity.aio import AzureCliCredential -from agent_framework.azure import AzureAIAgentClient - -async with AzureCliCredential() as credential, AzureAIAgentClient(async_credential=credential) as client: - # Create a persistent agent - agent = client.create_agent( - name="AgentDemo", - instructions="You are a helpful assistant." - ) - - # Start a new conversation thread - thread = agent.get_new_thread() - query = "Write a haiku about Agent Framework." - - # Get the agent's response - result = await agent.run(query, thread=thread) - print(f"Agent: {result}\\n") -``` - ------ - -## 4\. Connecting to Foundry Local - -Foundry Local serves AI models via a local, OpenAI-compatible API. This makes it easy to test agents with local models without needing cloud resources. - -### Connection Architecture - -The connection pattern is identical to that of GitHub Models, but the endpoint is a local server address. - -```mermaid -graph TD - A[Your Application] --> B{Agent Framework}; - B --> C[OpenAIClient]; - C --> D[Foundry Local Endpoint (e.g., http://localhost:5272/v1)]; -``` - -### .NET / C\# Implementation - -The code is nearly identical to the GitHub Models example, with changes only to the endpoint, model ID, and API key. - -1. **Client Initialization**: The `OpenAIClient` is configured to point to the `FOUNDRYLOCAL_ENDPOINT` (e.g., `http://localhost:5272/v1`). -2. **Authentication**: Since Foundry Local does not require authentication by default, a dummy API key like `"nokey"` is used. - -**Key Code Snippet:** - -```csharp -// Get local endpoint and model ID -var foundrylocal_endpoint = Environment.GetEnvironmentVariable("FOUNDRYLOCAL_ENDPOINT"); -var foundrylocal_model_id = Environment.GetEnvironmentVariable("FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME"); - -// Configure options to point to the local server -var openAIOptions = new OpenAIClientOptions() -{ - Endpoint= new Uri(foundrylocal_endpoint) -}; - -// Create the agent with a dummy API key -AIAgent agent = new OpenAIClient(new ApiKeyCredential("nokey"), openAIOptions) - .GetChatClient(foundrylocal_model_id) - .CreateAIAgent(instructions:"You are a helpful assistant."); - -// Run the agent -Console.WriteLine(await agent.RunAsync("Can you introduce yourself?")); -``` - -### Python Implementation - -The Python code is also very similar to the GitHub example, differing only in the client's connection parameters. - -1. **Client Initialization**: The `OpenAIChatClient` is initialized with the `base_url` set to the `FOUNDRYLOCAL_ENDPOINT` from the environment variables. -2. **Authentication**: The `api_key` is set to `"nokey"`. - -**Key Code Snippet:** - -```python -import os -from dotenv import load_dotenv -from agent_framework import ChatMessage, Role -from agent_framework.openai import OpenAIChatClient - -load_dotenv() - -# Initialize client for Foundry Local -client = OpenAIChatClient( - base_url=os.environ.get("FOUNDRYLOCAL_ENDPOINT"), - api_key="nokey", - ai_model_id=os.environ.get("FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME") -) - -# Prepare messages and execute -messages = [ - ChatMessage(role=Role.SYSTEM, text="You are a helpful assistant."), - ChatMessage(role=Role.USER, text="Can you introduce yourself?") - ] - -response = await client.get_response(messages) -print(response.messages[0].text) +# Using the Agent Framework to Connect Different AI Solutions + +The Agent Framework provides a unified interface for interacting with various AI models and services. This tutorial demonstrates how to connect to four different AI solutions—Azure OpenAI Service, GitHub Models, Azure AI Foundry, and Foundry Local—using the framework's implementations in both .NET (C\#) and Python. + +## Configuration and Setup + +Before running any of the examples, you need to configure your environment variables. The framework uses these variables to connect to the different AI endpoints. Create a `.env` file in the root of your project and populate it with the necessary credentials and endpoints. + +[cite\_start]You can use the `.env.examples` file as a template[cite: 1]: + +```env +# For GitHub Models +GITHUB_TOKEN="Your GitHub Models Token" +GITHUB_ENDPOINT="Your GitHub Models Endpoint" +GITHUB_MODEL_ID="Your GitHub Model ID" + +# For Azure OpenAI Service +AZURE_OPENAI_ENDPOINT="Your Azure OpenAI Endpoint" +AZURE_OPENAI_CHAT_DEPLOYMENT_NAME ="Your Azure OpenAI Model Deployment Name" + +# For Foundry Local +FOUNDRYLOCAL_ENDPOINT="http://localhost:5272/v1" +FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME="Your Local Model Name (e.g., Qwen3-0.6b-cpu)" + +# For Azure AI Foundry (Azure AI Studio) +AZURE_AI_PROJECT_ENDPOINT ="Your Azure AI Foundry Project Endpoint" +AZURE_AI_MODEL_DEPLOYMENT_NAME ="Your Azure AI Foundry Project Deployment Name" +``` + +----- + +## 1\. Connecting to Azure OpenAI Service + +This section shows how to use the Agent Framework to connect to models deployed in Azure OpenAI Service. + +### Connection Architecture + +The framework uses a dedicated `AzureOpenAIClient` to handle authentication and communication with the Azure OpenAI endpoint. + +```mermaid +graph TD + A[Your Application] --> B{Agent Framework}; + B --> C[AzureOpenAIClient]; + C --> D[Azure OpenAI Service Endpoint]; +``` + +### .NET / C\# Implementation + +The .NET example uses the `Azure.AI.OpenAI` and `Microsoft.Agents.AI` libraries to create a client and run the agent. + +1. **Dependencies**: NuGet packages like `Azure.AI.OpenAI`, `Azure.Identity`, and the local `Microsoft.Agents.AI.dll` are required. +2. **Client Initialization**: The code initializes an `AzureOpenAIClient`, providing the service endpoint and credentials (e.g., `AzureCliCredential`). +3. **Agent Creation**: The `CreateAIAgent` extension method is called on the chat client to get an agent instance with system instructions. +4. **Execution**: The agent is run using `RunAsync` or `RunStreamingAsync`. + +**Key Code Snippet:** + +```csharp +// Load endpoint and model ID from environment variables +var aoai_endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT"); +var aoai_model_id = Environment.GetEnvironmentVariable("AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME"); + +// Create the agent +AIAgent agent = new AzureOpenAIClient( + new Uri(aoai_endpoint), + new AzureCliCredential()) + .GetChatClient(aoai_model_id) + .CreateAIAgent("You are a helpful assistant."); + +// Run the agent and get a response +Console.WriteLine(await agent.RunAsync("Write a haiku about Agent Framework.")); +``` + +### Python Implementation + +The Python example uses the `agent_framework.azure` library to achieve the same result. + +1. **Dependencies**: The key libraries are `agent_framework` and `azure-identity`. +2. **Agent Creation**: The `AzureOpenAIChatClient` is instantiated with a credential object. The `create_agent` method is then called to configure the agent with its instructions. +3. **Execution**: The `agent.run_stream()` method is used to invoke the agent and stream the response. + +**Key Code Snippet:** + +```python +from azure.identity import AzureCliCredential +from agent_framework.azure import AzureOpenAIChatClient + +# Create an agent with Azure CLI credentials +agent = AzureOpenAIChatClient(credential=AzureCliCredential()).create_agent( + instructions="You are a helpful weather agent." +) + +query = "Write a haiku about Agent Framework." + +# Stream the agent's response +async for chunk in agent.run_stream(query): + if chunk.text: + print(chunk.text, end="", flush=True) +``` + +----- + +## 2\. Connecting to GitHub Models + +GitHub Models provides an OpenAI-compatible API endpoint. This allows the Agent Framework to use its standard `OpenAIClient` to connect. + +### Connection Architecture + +The connection is made to the GitHub Models endpoint, which behaves like an OpenAI API. + +```mermaid +graph TD + A[Your Application] --> B{Agent Framework}; + B --> C[OpenAIClient]; + C --> D[GitHub Models Endpoint]; +``` + +### .NET / C\# Implementation + +The approach is similar to connecting to any OpenAI-compatible service. + +1. **Dependencies**: This uses the `Microsoft.Extensions.AI.OpenAI` package and local Agent Framework assemblies. +2. **Client Initialization**: An `OpenAIClient` is created. The `OpenAIClientOptions` are configured with the GitHub Models endpoint URL, and an `ApiKeyCredential` is used to pass the GitHub token. +3. **Agent Creation**: The `CreateAIAgent` method is used to instantiate the agent with its system prompt. + +**Key Code Snippet:** + +```csharp +// Load connection details from environment variables +var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT"); +var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID"); +var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN"); + +// Configure client options with the endpoint +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint= new Uri(github_endpoint) +}; + +// Create the agent with an API key credential +AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) + .GetChatClient(github_model_id) + .CreateAIAgent(instructions:"You are a helpful assistant."); + +// Run the agent +Console.WriteLine(await agent.RunAsync("Write a haiku about Agent Framework.")); +``` + +### Python Implementation + +The Python example uses the `OpenAIChatClient` from the framework. + +1. **Dependencies**: The `agent_framework.openai` and `python-dotenv` libraries are used. +2. **Client Initialization**: The `OpenAIChatClient` is initialized with the `base_url` pointing to the GitHub endpoint and the `api_key` set to the GitHub token. +3. **Execution**: A list of `ChatMessage` objects is created and passed to the `client.get_response` method to get a completion. + +**Key Code Snippet:** + +```python +import os +from dotenv import load_dotenv +from agent_framework import ChatMessage, Role +from agent_framework.openai import OpenAIChatClient + +load_dotenv() + +# Initialize the client with GitHub endpoint and token +client = OpenAIChatClient( + base_url=os.environ.get("GITHUB_ENDPOINT"), + api_key=os.environ.get("GITHUB_TOKEN"), + ai_model_id=os.environ.get("GITHUB_MODEL_ID") +) + +# Prepare the messages and get a response +messages = [ + ChatMessage(role=Role.SYSTEM, text="You are a helpful assistant."), + ChatMessage(role=Role.USER, text="Write a haiku about Agent Framework.") + ] +response = await client.get_response(messages) +print(response.messages[0].text) +``` + +----- + +## 3\. Connecting to Azure AI Foundry (Azure AI Studio) + +Azure AI Foundry allows you to create and manage persistent agents. The Agent Framework provides a client to interact with these stateful agents. + +### Connection Architecture + +The framework communicates with the Azure AI Project endpoint to interact with specific, persistent agents by name or ID. + +```mermaid +graph TD + A[Your Application] --> B{Agent Framework}; + B --> C[PersistentAgentsClient]; + C --> D[Azure AI Project Endpoint]; +``` + +### .NET / C\# Implementation + +This example uses the `Azure.AI.Agents.Persistent` client library. + +1. **Dependencies**: The primary dependency is the `Azure.AI.Agents.Persistent` NuGet package. +2. **Client Initialization**: A `PersistentAgentsClient` is created using the Azure AI Project endpoint and a credential. +3. **Agent Creation/Retrieval**: The code first creates a new persistent agent with `CreateAgentAsync`. The resulting agent metadata is then used to get a runnable `AIAgent` instance with `GetAIAgentAsync`. +4. **Execution**: Agents in AI Foundry are stateful and operate on threads. A new thread is created with `agent.GetNewThread()`, and the `RunAsync` method is called with both the prompt and the thread. + +**Key Code Snippet:** + +```csharp +// Load endpoint and model ID from environment variables +var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT"); +var azure_foundry_model_id = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME"); + +// Create the client +var persistentAgentsClient = new PersistentAgentsClient(azure_foundry_endpoint, new AzureCliCredential()); + +// Create a new persistent agent +var agentMetadata = await persistentAgentsClient.Administration.CreateAgentAsync( + model: azure_foundry_model_id, + name: "Agent-Framework", + instructions: "You are an AI assistant that helps people find information."); + +// Get the agent instance and a new thread for conversation +AIAgent agent = await persistentAgentsClient.GetAIAgentAsync(agentMetadata.Value.Id); +AgentThread thread = agent.GetNewThread(); + +// Run the agent within the context of the thread +Console.WriteLine(await agent.RunAsync("Write a haiku about Agent Framework", thread)); +``` + +### Python Implementation + +The Python example uses `AzureAIAgentClient` to interact with persistent agents. + +1. **Dependencies**: `agent_framework.azure` and `azure-identity` are required. +2. **Client Initialization**: The `AzureAIAgentClient` is initialized with an async credential. +3. **Agent and Thread Management**: Inside an `async with` block, `client.create_agent` defines a persistent agent. A new conversational context is created with `agent.get_new_thread()`. +4. **Execution**: `agent.run` is called with the query and the thread object. + +**Key Code Snippet:** + +```python +from azure.identity.aio import AzureCliCredential +from agent_framework.azure import AzureAIAgentClient + +async with AzureCliCredential() as credential, AzureAIAgentClient(async_credential=credential) as client: + # Create a persistent agent + agent = client.create_agent( + name="AgentDemo", + instructions="You are a helpful assistant." + ) + + # Start a new conversation thread + thread = agent.get_new_thread() + query = "Write a haiku about Agent Framework." + + # Get the agent's response + result = await agent.run(query, thread=thread) + print(f"Agent: {result}\\n") +``` + +----- + +## 4\. Connecting to Foundry Local + +Foundry Local serves AI models via a local, OpenAI-compatible API. This makes it easy to test agents with local models without needing cloud resources. + +### Connection Architecture + +The connection pattern is identical to that of GitHub Models, but the endpoint is a local server address. + +```mermaid +graph TD + A[Your Application] --> B{Agent Framework}; + B --> C[OpenAIClient]; + C --> D[Foundry Local Endpoint (e.g., http://localhost:5272/v1)]; +``` + +### .NET / C\# Implementation + +The code is nearly identical to the GitHub Models example, with changes only to the endpoint, model ID, and API key. + +1. **Client Initialization**: The `OpenAIClient` is configured to point to the `FOUNDRYLOCAL_ENDPOINT` (e.g., `http://localhost:5272/v1`). +2. **Authentication**: Since Foundry Local does not require authentication by default, a dummy API key like `"nokey"` is used. + +**Key Code Snippet:** + +```csharp +// Get local endpoint and model ID +var foundrylocal_endpoint = Environment.GetEnvironmentVariable("FOUNDRYLOCAL_ENDPOINT"); +var foundrylocal_model_id = Environment.GetEnvironmentVariable("FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME"); + +// Configure options to point to the local server +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint= new Uri(foundrylocal_endpoint) +}; + +// Create the agent with a dummy API key +AIAgent agent = new OpenAIClient(new ApiKeyCredential("nokey"), openAIOptions) + .GetChatClient(foundrylocal_model_id) + .CreateAIAgent(instructions:"You are a helpful assistant."); + +// Run the agent +Console.WriteLine(await agent.RunAsync("Can you introduce yourself?")); +``` + +### Python Implementation + +The Python code is also very similar to the GitHub example, differing only in the client's connection parameters. + +1. **Client Initialization**: The `OpenAIChatClient` is initialized with the `base_url` set to the `FOUNDRYLOCAL_ENDPOINT` from the environment variables. +2. **Authentication**: The `api_key` is set to `"nokey"`. + +**Key Code Snippet:** + +```python +import os +from dotenv import load_dotenv +from agent_framework import ChatMessage, Role +from agent_framework.openai import OpenAIChatClient + +load_dotenv() + +# Initialize client for Foundry Local +client = OpenAIChatClient( + base_url=os.environ.get("FOUNDRYLOCAL_ENDPOINT"), + api_key="nokey", + ai_model_id=os.environ.get("FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME") +) + +# Prepare messages and execute +messages = [ + ChatMessage(role=Role.SYSTEM, text="You are a helpful assistant."), + ChatMessage(role=Role.USER, text="Can you introduce yourself?") + ] + +response = await client.get_response(messages) +print(response.messages[0].text) ``` \ No newline at end of file diff --git a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj b/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj rename to 03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj diff --git a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs b/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs rename to 03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/Program.cs diff --git a/03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md b/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md rename to 03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md diff --git a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj b/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj rename to 03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj diff --git a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs b/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs rename to 03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/Program.cs diff --git a/03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md b/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md rename to 03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md diff --git a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj b/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj rename to 03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj diff --git a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs b/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs rename to 03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/Program.cs diff --git a/03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md b/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md rename to 03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md diff --git a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj b/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj rename to 03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj diff --git a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs b/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs rename to 03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/Program.cs diff --git a/03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md b/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md similarity index 100% rename from 03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md rename to 03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md diff --git a/03.ExploerAgentFramework/code_samples/python/01-python-agent-framework-aoai.ipynb b/03.ExploreAgentFramework/code_samples/python/01-python-agent-framework-aoai.ipynb similarity index 100% rename from 03.ExploerAgentFramework/code_samples/python/01-python-agent-framework-aoai.ipynb rename to 03.ExploreAgentFramework/code_samples/python/01-python-agent-framework-aoai.ipynb diff --git a/03.ExploerAgentFramework/code_samples/python/02-python-agent-framrwork-ghmodel.ipynb b/03.ExploreAgentFramework/code_samples/python/02-python-agent-framrwork-ghmodel.ipynb similarity index 100% rename from 03.ExploerAgentFramework/code_samples/python/02-python-agent-framrwork-ghmodel.ipynb rename to 03.ExploreAgentFramework/code_samples/python/02-python-agent-framrwork-ghmodel.ipynb diff --git a/03.ExploerAgentFramework/code_samples/python/03-python-agent-framework-msfoundry.ipynb b/03.ExploreAgentFramework/code_samples/python/03-python-agent-framework-msfoundry.ipynb similarity index 100% rename from 03.ExploerAgentFramework/code_samples/python/03-python-agent-framework-msfoundry.ipynb rename to 03.ExploreAgentFramework/code_samples/python/03-python-agent-framework-msfoundry.ipynb diff --git a/03.ExploerAgentFramework/code_samples/python/04-python-agent-framework-foundrylocal.ipynb b/03.ExploreAgentFramework/code_samples/python/04-python-agent-framework-foundrylocal.ipynb similarity index 100% rename from 03.ExploerAgentFramework/code_samples/python/04-python-agent-framework-foundrylocal.ipynb rename to 03.ExploreAgentFramework/code_samples/python/04-python-agent-framework-foundrylocal.ipynb diff --git a/README.md b/README.md index acd28a2..089da8c 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,10 @@ This repository provides step-by-step tutorials and real-world examples covering | Directory | Description | .NET Code Samples | Python Code Samples | |-----------|-------------|-------------------|---------------------| -| **[00.ForBeginners](./00.ForBeginners/README.md)** | **Beginner-friendly Microsoft Agent Framework examples extending [AI Agents for Beginners](https://github.com/microsoft/ai-agents-for-beginners)** | [Travel Agent](./00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/)
[Basic Agent](./00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/)
[Design Patterns](./00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/)
[Tool Use](./00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/)
[RAG Search](./00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/)
[Planning](./00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framrwork-ghmodel-planningdesign/)
[Multi-Agent](./00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/) | [Travel Agent](./00.ForBeginners/01-intro-to-ai-agents/code_samples/python-agent-framework-travelagent.ipynb)
[Basic Agent](./00.ForBeginners/02-explore-agentic-frameworks/code_samples/python-agent-framework-basicagent.ipynb)
[Design Patterns](./00.ForBeginners/03-agentic-design-patterns/code_samples/python-agent-framework-ghmodel-basicagent.ipynb)
[Tool Use](./00.ForBeginners/04-tool-use/code_samples/python-agent-framework-ghmodel-tools.ipynb)
[RAG Search](./00.ForBeginners/05-agentic-rag/code_samples/python-agent-framework-msfoundry-file-search.ipynb)
[Planning](./00.ForBeginners/07-planning-design/code_samples/python-agent-framrwork-ghmodel-planningdesign.ipynb)
[Multi-Agent](./00.ForBeginners/08-multi-agent/code_samples/python-agent-framework-ghmodel-workflow-multi-agents.ipynb) | +| **[00.ForBeginners](./00.ForBeginners/README.md)** | **Beginner-friendly Microsoft Agent Framework examples extending [AI Agents for Beginners](https://github.com/microsoft/ai-agents-for-beginners)** | [Travel Agent](./00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/)
[Basic Agent](./00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/)
[Design Patterns](./00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/)
[Tool Use](./00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/)
[RAG Search](./00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/)
[Planning](./00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/)
[Multi-Agent](./00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/) | [Travel Agent](./00.ForBeginners/01-intro-to-ai-agents/code_samples/python-agent-framework-travelagent.ipynb)
[Basic Agent](./00.ForBeginners/02-explore-agentic-frameworks/code_samples/python-agent-framework-basicagent.ipynb)
[Design Patterns](./00.ForBeginners/03-agentic-design-patterns/code_samples/python-agent-framework-ghmodel-basicagent.ipynb)
[Tool Use](./00.ForBeginners/04-tool-use/code_samples/python-agent-framework-ghmodel-tools.ipynb)
[RAG Search](./00.ForBeginners/05-agentic-rag/code_samples/python-agent-framework-msfoundry-file-search.ipynb)
[Planning](./00.ForBeginners/07-planning-design/code_samples/python-agent-framrwork-ghmodel-planningdesign.ipynb)
[Multi-Agent](./00.ForBeginners/08-multi-agent/code_samples/python-agent-framework-ghmodel-workflow-multi-agents.ipynb) | | **[01.AgentFoundation](./01.AgentFoundation/README.md)** | Core concepts and architecture of Microsoft Agent Framework | *Documentation Only* | *Documentation Only* | | **[02.CreateYourFirstAgent](./02.CreateYourFirstAgent/README.md)** | Build your first travel planning agent from scratch | [Travel Agent with GitHub Models](./02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/) | [Travel Agent with GitHub Models](./02.CreateYourFirstAgent/code_samples/python/python-travelagent-ghmodel.ipynb) | -| **[03.ExploreAgentFramework](./03.ExploerAgentFramework/README.md)** | Deep dive into different providers and configurations | [Azure OpenAI](./03.ExploerAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/)
[GitHub Models](./03.ExploerAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/)
[MS Foundry](./03.ExploerAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/)
[Foundry Local](./03.ExploerAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/) | [Azure OpenAI](./03.ExploerAgentFramework/code_samples/python/01-python-agent-framework-aoai.ipynb)
[GitHub Models](./03.ExploerAgentFramework/code_samples/python/02-python-agent-framrwork-ghmodel.ipynb)
[MS Foundry](./03.ExploerAgentFramework/code_samples/python/03-python-agent-framework-msfoundry.ipynb)
[Foundry Local](./03.ExploerAgentFramework/code_samples/python/04-python-agent-framrwork-foundrylocal.ipynb) | +| **[03.ExploreAgentFramework](./03.ExploreAgentFramework/README.md)** | Deep dive into different providers and configurations | [Azure OpenAI](./03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/)
[GitHub Models](./03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/)
[MS Foundry](./03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/)
[Foundry Local](./03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/) | [Azure OpenAI](./03.ExploreAgentFramework/code_samples/python/01-python-agent-framework-aoai.ipynb)
[GitHub Models](./03.ExploreAgentFramework/code_samples/python/02-python-agent-framrwork-ghmodel.ipynb)
[MS Foundry](./03.ExploreAgentFramework/code_samples/python/03-python-agent-framework-msfoundry.ipynb)
[Foundry Local](./03.ExploreAgentFramework/code_samples/python/04-python-agent-framrwork-foundrylocal.ipynb) | | **[04.Tools](./04.Tools/README.md)** | Vision, code interpretation, and custom tool integration | [Vision](./04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/)
[Code Interpreter](./04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/)
[Bing Grounding](./04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/)
[File Search](./04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/) | [Vision](./04.Tools/code_samples/python/msfoundry/01.python-agent-framework-msfoundry-vision.ipynb)
[Code Interpreter](./04.Tools/code_samples/python/msfoundry/02.python-agent-framework-msfoundry-code-interpreter.ipynb)
[Bing Grounding](./04.Tools/code_samples/python/msfoundry/03.python-agent-framework-msfoundry-binggrounding.ipynb)
[File Search](./04.Tools/code_samples/python/msfoundry/04.python-agent-framework-msfoundry-file-search.ipynb) | | **[05.Providers](./05.Providers/README.md)** | MCP (Model Context Protocol) and Agent-to-Agent communication | [MCP with Microsoft Learn](./05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/)| [MCP with Microsoft Learn](./05.Providers/code_samples/python/01-python-agent-framework-aifoundry-mcp.ipynb) | | **[06.RAGs](./06.RAGs/README.md)** | Knowledge-enhanced agents with file search capabilities | [File Search RAG](./06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/) | [File Search RAG](./06.RAGs/code_samples/python/python-agent-framework-msfoundry-file-search.ipynb) | diff --git a/dotnet/AgentFrameworkSamples.slnx b/dotnet/AgentFrameworkSamples.slnx index c895f3d..9f9138d 100644 --- a/dotnet/AgentFrameworkSamples.slnx +++ b/dotnet/AgentFrameworkSamples.slnx @@ -3,7 +3,7 @@ - + @@ -16,10 +16,10 @@ - - - - + + + + From 3b50245496728816cc126ed86c68158ab12e6e25 Mon Sep 17 00:00:00 2001 From: Bruno Capuano Date: Sat, 21 Feb 2026 14:29:50 -0500 Subject: [PATCH 05/10] Update .gitignore and README files; add maintainer notes and .NET user-secrets guidance --- .gitignore | 2 + .../dotnet-travelagent-ghmodel/README.md | 2 + .../README.md | 2 + .../Program.cs | 48 ------------------- .../Program.cs | 9 ---- README.md | 33 ++++++++----- 6 files changed, 27 insertions(+), 69 deletions(-) diff --git a/.gitignore b/.gitignore index 71d95bd..30f5007 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ *.userosscache *.sln.docstates *.env +# Note: .NET user-secrets (dotnet user-secrets set ...) are stored outside the +# repository in your OS user profile and are never committed to git. # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs diff --git a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md index 424064d..e5e9d2b 100644 --- a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md +++ b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md @@ -1,5 +1,7 @@ # Travel Agent — Create Your First Agent (.NET) +> **Maintainer note:** This sample is structurally identical to [`00.ForBeginners/01-intro-to-ai-agents/…/dotnet-agent-framework-travelagent`](../../../../00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/). Consider differentiating them conceptually (e.g., expand this one with session memory, multi-turn conversation, or a richer tool set) or consolidating into a single canonical sample. + A hands-on "Hello World" for the Microsoft Agent Framework. Builds a travel-planning agent backed by **GitHub Models**, attaches a destination-picker tool, and exercises both awaited and streaming invocation styles. ## What it shows diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md index db09079..1d4c549 100644 --- a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md @@ -1,5 +1,7 @@ # RAG — File Search with Azure AI Foundry (.NET) +> **Maintainer note:** This sample shares the same agent pattern as [`00.ForBeginners/05-agentic-rag/…/dotnet-agent-framework-msfoundry-file-search`](../../../../00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/). The two differ only in the uploaded document (`demo.md` here vs. `document.md` there) and the seed question. Consider converging them on a single document or expanding this chapter-level sample with additional RAG patterns (e.g., hybrid search, metadata filters). + Uploads a Markdown knowledge-base document to Azure AI Foundry and uses `HostedFileSearchTool` to build a retrieval-augmented generation (RAG) pipeline. The agent answers questions using only the indexed document. ## What it shows diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs index 6df1036..902cc95 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.AGUI/GHModel.dotNET.AI.Workflow.AGUI.Server/Program.cs @@ -26,60 +26,12 @@ builder.Services.AddHttpClient().AddLogging(); builder.Services.ConfigureHttpJsonOptions(options => options.SerializerOptions.TypeInfoResolverChain.Add(AGUIDojoServerSerializerContext.Default)); -// builder.Services.ConfigureHttpJsonOptions(options => options.SerializerOptions.TypeInfoResolverChain.Add(AGUIDojoServerSerializerContext.Default)); builder.Services.AddAGUI(); - ChatClientAgentFactory.Initialize(builder.Configuration); WebApplication app = builder.Build(); -// var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -// var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? throw new InvalidOperationException("GITHUB_MODEL_ID is not set."); -// var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); - -// var openAIOptions = new OpenAIClientOptions() -// { -// Endpoint = new Uri(github_endpoint) -// }; - -// var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions); - - - -// var chatClient = openAIClient.GetChatClient(github_model_id).AsIChatClient(); - -// const string ReviewerAgentName = "Concierge"; -// const string ReviewerAgentInstructions = @" -// You are an are hotel concierge who has opinions about providing the most local and authentic experiences for travelers. -// The goal is to determine if the front desk travel agent has recommended the best non-touristy experience for a traveler. -// If so, state that it is approved. -// If not, provide insight on how to refine the recommendation without using a specific example. "; - -// const string FrontDeskAgentName = "FrontDesk"; -// const string FrontDeskAgentInstructions = @""" -// You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers. -// The goal is to provide the best activities and locations for a traveler to visit. -// Only provide a single recommendation per response. -// You're laser focused on the goal at hand. -// Don't waste time with chit chat. -// Consider suggestions when refining an idea. -// """; - - - -// AIAgent reviewerAgent = chatClient.CreateAIAgent( -// name:ReviewerAgentName,instructions:ReviewerAgentInstructions); -// AIAgent frontDeskAgent = chatClient.CreateAIAgent( -// name:FrontDeskAgentName,instructions:FrontDeskAgentInstructions); - -// var workflow = new WorkflowBuilder(frontDeskAgent) -// .AddEdge(frontDeskAgent, reviewerAgent) -// .Build(); - - -// AIAgent workflow_agent = workflow.AsAgent("travel-workflow","travel recommendation workflow"); - // Map the AG-UI agent endpoint app.MapAGUI("/", ChatClientAgentFactory.CreateTravelAgenticChat()); diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs index 512a379..0386093 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.DevUI/Program.cs @@ -1,13 +1,4 @@ -// using System.ComponentModel; -// using Azure.AI.OpenAI; -// using Azure.Identity; -// using Microsoft.Agents.AI; -// using Microsoft.Agents.AI.DevUI; -// using Microsoft.Agents.AI.Hosting; -// using Microsoft.Agents.AI.Workflows; -// using Microsoft.Extensions.AI; - using System; using System.ComponentModel; using System.ClientModel; diff --git a/README.md b/README.md index 089da8c..53fa74a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This repository provides step-by-step tutorials and real-world examples covering ## 📁 Repository Structure -| Directory | Description | .NET Code Samples | Python Code Samples | +| Directory | Description | .NET Code Samples ✅ | Python Code Samples | |-----------|-------------|-------------------|---------------------| | **[00.ForBeginners](./00.ForBeginners/README.md)** | **Beginner-friendly Microsoft Agent Framework examples extending [AI Agents for Beginners](https://github.com/microsoft/ai-agents-for-beginners)** | [Travel Agent](./00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/)
[Basic Agent](./00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/)
[Design Patterns](./00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/)
[Tool Use](./00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/)
[RAG Search](./00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/)
[Planning](./00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/)
[Multi-Agent](./00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/) | [Travel Agent](./00.ForBeginners/01-intro-to-ai-agents/code_samples/python-agent-framework-travelagent.ipynb)
[Basic Agent](./00.ForBeginners/02-explore-agentic-frameworks/code_samples/python-agent-framework-basicagent.ipynb)
[Design Patterns](./00.ForBeginners/03-agentic-design-patterns/code_samples/python-agent-framework-ghmodel-basicagent.ipynb)
[Tool Use](./00.ForBeginners/04-tool-use/code_samples/python-agent-framework-ghmodel-tools.ipynb)
[RAG Search](./00.ForBeginners/05-agentic-rag/code_samples/python-agent-framework-msfoundry-file-search.ipynb)
[Planning](./00.ForBeginners/07-planning-design/code_samples/python-agent-framrwork-ghmodel-planningdesign.ipynb)
[Multi-Agent](./00.ForBeginners/08-multi-agent/code_samples/python-agent-framework-ghmodel-workflow-multi-agents.ipynb) | | **[01.AgentFoundation](./01.AgentFoundation/README.md)** | Core concepts and architecture of Microsoft Agent Framework | *Documentation Only* | *Documentation Only* | @@ -35,7 +35,7 @@ This repository provides step-by-step tutorials and real-world examples covering ***Note: This is installation guideline*** -> ⚠️ **Important Notice**: Microsoft Agent Framework is currently in the **development/preview stage**. Since the framework APIs and features may change frequently, **we strongly recommend building from source** rather than using NuGet packages to ensure you have the latest updates and bug fixes. +> ⚠️ **Important Notice**: Microsoft Agent Framework is currently in the **development/preview stage**. The framework APIs and features may change between releases. > 📌 **Additional Notes**: > 1. The examples in this repository are primarily based on **GitHub Models** and **Microsoft Foundry**. You can access GitHub Models directly at https://gh.io/models @@ -58,17 +58,12 @@ pip install -e . ``` ### .NET Environment -- .NET 9.0 or higher -- Visual Studio 2022 or VS Code with C# extension +- .NET 10 SDK ([download](https://dotnet.microsoft.com/download/dotnet/10.0)) +- VS Code with C# extension, or Visual Studio 2022 17.14+ -**Build from Source (Recommended):** - -```bash -git clone https://github.com/microsoft/agent-framework.git -cd agent-framework/dotnet && dotnet build agent-framework-dotnet.slnx -``` +All .NET samples use NuGet packages and run with `dotnet run` from the project folder. No local source build is required. -After building, reference the local project in your notebooks or applications instead of NuGet packages. This ensures compatibility with the latest framework changes. +Configure secrets for each sample with `dotnet user-secrets` — see each sample's `README.md` for the exact commands. ## 💻 Platform-Specific Setup @@ -98,7 +93,7 @@ $env:OPENSSL_STATIC="1" ## 🚀 Quick Start -### Environment Setup +### Python — Environment Setup Create a `.env` file in the root directory with your configurations: @@ -124,6 +119,20 @@ BING_CONNECTION_NAME="Your Bing Connection Name" OTEL_EXPORTER_OTLP_ENDPOINT="Your OpenTelemetry Collector Endpoint e.g. http://localhost:4317" ``` +### .NET — Environment Setup + +.NET samples use `dotnet user-secrets` for local credential management — credentials are stored securely in your OS user profile, never in the repository. + +Each sample's `README.md` lists the exact `dotnet user-secrets set` commands. For example: + +```bash +cd +dotnet user-secrets set "GITHUB_TOKEN" "your-token-here" +dotnet user-secrets set "ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "MODEL" "gpt-4o-mini" +dotnet run +``` + ## 📚 Tutorial Progression From 809bee95e3cd6a4d776a00cef11a8b07a979f228 Mon Sep 17 00:00:00 2001 From: Bruno Capuano Date: Sat, 21 Feb 2026 15:07:04 -0500 Subject: [PATCH 06/10] Add .NET samples for AI workflows using OpenAI and Azure AI - Implement basic workflow with GitHub model in `01.dotnet-agent-framework-workflow-ghmodel-basic/app.cs` - Create sequential workflow for furniture pricing and quoting in `02.dotnet-agent-framework-workflow-ghmodel-sequential/app.cs` - Develop concurrent workflow for travel planning in `03.dotnet-agent-framework-workflow-ghmodel-concurrent/app.cs` - Add conditional workflow sample with MSFoundry in `04.dotnet-agent-framework-workflow-msfoundry-condition/app.cs` - Integrate OpenTelemetry for monitoring in AI workflows in `GHModel.dotNET.AI.Workflow.OpenTelemetry/app.cs` - Create YAML-based workflow execution in `CreateWorkflowWithYAML/app.cs` --- .../README.md | 6 + .../dotnet-agent-framework-travelagent/app.cs | 81 ++++ .../dotnet-agent-framework-travelagent.csproj | 4 + .../README.md | 6 + .../dotnet-agent-framework-basicagent/app.cs | 80 ++++ .../dotnet-agent-framework-basicagent.csproj | 4 + .../README.md | 6 + .../dotnet-agent-framework-basicagent/app.cs | 80 ++++ .../dotnet-agent-framework-basicagent.csproj | 4 + .../README.md | 6 + .../app.cs | 74 +++ ...otnet-agent-framework-ghmodels-tool.csproj | 4 + .../README.md | 6 + .../app.cs | 69 +++ ...ent-framework-msfoundry-file-search.csproj | 4 + .../README.md | 6 + .../app.cs | 87 ++++ ...nt-framework-ghmodel-planningdesign.csproj | 4 + .../README.md | 6 + .../app.cs | 108 +++++ ...ework-ghmodel-workflow-multi-agents.csproj | 4 + .../dotnet-travelagent-ghmodel/README.md | 6 + .../dotNET/dotnet-travelagent-ghmodel/app.cs | 81 ++++ .../dotnet-travelagent-ghmodel.csproj | 4 + .../01-dotnet-agent-framework-aoai.csproj | 4 + .../01-dotnet-agent-framework-aoai/README.md | 6 + .../01-dotnet-agent-framework-aoai/app.cs | 39 ++ .../02-dotnet-agent-framework-ghmodel.csproj | 4 + .../README.md | 6 + .../02-dotnet-agent-framework-ghmodel/app.cs | 80 ++++ ...03-dotnet-agent-framework-msfoundry.csproj | 4 + .../README.md | 6 + .../app.cs | 46 ++ ...dotnet-agent-framework-foundrylocal.csproj | 4 + .../README.md | 6 + .../app.cs | 57 +++ ...et-agent-framework-msfoundry-vision.csproj | 4 + .../README.md | 6 + .../app.cs | 70 +++ ...ramework-msfoundry-code-interpreter.csproj | 4 + .../README.md | 6 + .../app.cs | 90 ++++ ...t-framework-msfoundry-binggrounding.csproj | 4 + .../README.md | 6 + .../app.cs | 73 +++ ...ent-framework-msfoundry-file-search.csproj | 4 + .../README.md | 6 + .../app.cs | 67 +++ .../AgentMCP.Console/AgentMCP.Console.csproj | 4 + .../AgentMCP.Console/README.md | 6 + .../AgentMCP.Console/app.cs | 86 ++++ .../README.md | 6 + .../app.cs | 69 +++ ...ent-framework-msfoundry-file-search.csproj | 4 + ...nt-framework-workflow-ghmodel-basic.csproj | 4 + .../README.md | 6 + .../app.cs | 108 +++++ ...amework-workflow-ghmodel-sequential.csproj | 4 + .../README.md | 6 + .../app.cs | 122 +++++ ...amework-workflow-ghmodel-concurrent.csproj | 4 + .../README.md | 6 + .../app.cs | 131 +++++ ...mework-workflow-msfoundry-condition.csproj | 4 + .../README.md | 6 + .../app.cs | 19 + ...el.dotNET.AI.Workflow.OpenTelemetry.csproj | 4 + .../README.md | 6 + .../app.cs | 241 ++++++++++ .../CreateWorkflowWithYAML.csproj | 4 + .../CreateWorkflowWithYAML/README.md | 8 + .../CreateWorkflowWithYAML/app.cs | 446 ++++++++++++++++++ 72 files changed, 2646 insertions(+) create mode 100644 00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/app.cs create mode 100644 00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/app.cs create mode 100644 00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/app.cs create mode 100644 00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/app.cs create mode 100644 00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/app.cs create mode 100644 00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/app.cs create mode 100644 00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/app.cs create mode 100644 02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/app.cs create mode 100644 03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/app.cs create mode 100644 03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/app.cs create mode 100644 03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/app.cs create mode 100644 03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/app.cs create mode 100644 04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/app.cs create mode 100644 04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/app.cs create mode 100644 04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/app.cs create mode 100644 04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/app.cs create mode 100644 05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/app.cs create mode 100644 06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/app.cs create mode 100644 07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/app.cs create mode 100644 07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/app.cs create mode 100644 07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/app.cs create mode 100644 07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/app.cs create mode 100644 09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/app.cs create mode 100644 09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/app.cs diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md index fd10ca7..5ebd2a8 100644 --- a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md +++ b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md @@ -24,3 +24,9 @@ dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/app.cs b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/app.cs new file mode 100644 index 0000000..d830aa8 --- /dev/null +++ b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/app.cs @@ -0,0 +1,81 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId e01f82ab-60d0-4d0e-82b0-476cd48c55b3 +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ComponentModel; +using System.ClientModel; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using OpenAI; +using Microsoft.Extensions.Configuration; + +// Load environment variables from .env file + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] + ?? throw new InvalidOperationException("GITHUB_ENDPOINT is required"); +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] + ?? throw new InvalidOperationException("GITHUB_TOKEN is required"); + +// Configure OpenAI client for GitHub Models +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; + +// Create AI Agent with custom tool +AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) + .GetChatClient(github_model_id) + .AsIChatClient() + .AsAIAgent( + name: "TravelAgent", + instructions: "You are a helpful AI Agent that can help plan vacations for customers at random destinations.", + tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] + ); + +// Run agent with standard response +Console.WriteLine("=== Travel Plan ==="); +Console.WriteLine(await agent.RunAsync("Plan me a day trip")); + +// Run agent with streaming response +Console.WriteLine("\n=== Streaming Travel Plan ==="); +await foreach (var update in agent.RunStreamingAsync("Plan me a day trip")) +{ + Console.Write(update); +} +Console.WriteLine(); + +// Agent Tool: Random Destination Generator +[Description("Provides a random vacation destination.")] +static string GetRandomDestination() +{ + var destinations = new List + { + "Paris, France", + "Tokyo, Japan", + "New York City, USA", + "Sydney, Australia", + "Rome, Italy", + "Barcelona, Spain", + "Cape Town, South Africa", + "Rio de Janeiro, Brazil", + "Bangkok, Thailand", + "Vancouver, Canada" + }; + + var random = new Random(); + int index = random.Next(destinations.Count); + return destinations[index]; +} diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj index 7fc6af2..b2657c1 100644 --- a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj +++ b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj @@ -23,4 +23,8 @@
+ + + +
\ No newline at end of file diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md index b82cc75..0d1dbf3 100644 --- a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md +++ b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md @@ -24,3 +24,9 @@ dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/app.cs b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/app.cs new file mode 100644 index 0000000..0c566e9 --- /dev/null +++ b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/app.cs @@ -0,0 +1,80 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 03318c00-adb1-4220-a32a-7b0068e30fff +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ComponentModel; +using System.ClientModel; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using OpenAI; +using Microsoft.Extensions.Configuration; + +// Load environment variables from .env file + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] + ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] + ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +// Configure OpenAI client for GitHub Models +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; + +// Agent Tool: Random Destination Generator +[Description("Provides a random vacation destination.")] +static string GetRandomDestination() +{ + var destinations = new List + { + "Paris, France", + "Tokyo, Japan", + "New York City, USA", + "Sydney, Australia", + "Rome, Italy", + "Barcelona, Spain", + "Cape Town, South Africa", + "Rio de Janeiro, Brazil", + "Bangkok, Thailand", + "Vancouver, Canada" + }; + var random = new Random(); + int index = random.Next(destinations.Count); + return destinations[index]; +} + +// Create AI Agent with basic instructions and tool +AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) + .GetChatClient(github_model_id) + .AsIChatClient() + .AsAIAgent( + name: "BasicAgent", + instructions: "You are a basic AI Agent that can answer questions and suggest random travel destinations.", + tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] + ); + +// Run agent with standard response +Console.WriteLine("=== Basic Agent Response ==="); +Console.WriteLine(await agent.RunAsync("Suggest a vacation destination.")); + +// Run agent with streaming response +Console.WriteLine("\n=== Streaming Response ==="); +await foreach (var update in agent.RunStreamingAsync("Suggest a vacation destination.")) +{ + Console.Write(update); +} +Console.WriteLine(); diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj index e498d37..ab705d2 100644 --- a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj +++ b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj @@ -23,4 +23,8 @@ + + + +
\ No newline at end of file diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md index f135937..d691c23 100644 --- a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md +++ b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md @@ -24,3 +24,9 @@ dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/app.cs b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/app.cs new file mode 100644 index 0000000..214e45b --- /dev/null +++ b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/app.cs @@ -0,0 +1,80 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 328e4b11-22e2-4b5d-8e08-2f4e47079175 +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ComponentModel; +using System.ClientModel; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using OpenAI; +using Microsoft.Extensions.Configuration; + +// Load environment variables from .env file + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] + ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] + ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +// Configure OpenAI client for GitHub Models +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; + +// Agent Tool: Random Destination Generator +[Description("Provides a random vacation destination.")] +static string GetRandomDestination() +{ + var destinations = new List + { + "Paris, France", + "Tokyo, Japan", + "New York City, USA", + "Sydney, Australia", + "Rome, Italy", + "Barcelona, Spain", + "Cape Town, South Africa", + "Rio de Janeiro, Brazil", + "Bangkok, Thailand", + "Vancouver, Canada" + }; + var random = new Random(); + int index = random.Next(destinations.Count); + return destinations[index]; +} + +// Create AI Agent with basic instructions and tool +AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) + .GetChatClient(github_model_id) + .AsIChatClient() + .AsAIAgent( + name: "BasicAgent", + instructions: "You are a basic AI Agent that can answer questions and suggest random travel destinations.", + tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] + ); + +// Run agent with standard response +Console.WriteLine("=== Basic Agent Response ==="); +Console.WriteLine(await agent.RunAsync("Suggest a vacation destination.")); + +// Run agent with streaming response +Console.WriteLine("\n=== Streaming Response ==="); +await foreach (var update in agent.RunStreamingAsync("Suggest a vacation destination.")) +{ + Console.Write(update); +} +Console.WriteLine(); diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj index cd10951..aa07e1b 100644 --- a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj +++ b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj @@ -23,4 +23,8 @@ + + + +
\ No newline at end of file diff --git a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/README.md b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/README.md index 944deac..13446b0 100644 --- a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/README.md +++ b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/README.md @@ -24,3 +24,9 @@ dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/app.cs b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/app.cs new file mode 100644 index 0000000..5107acf --- /dev/null +++ b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/app.cs @@ -0,0 +1,74 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId c2c7f177-4a84-4250-9357-98122c3f2feb +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ComponentModel; +using System.ClientModel; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using OpenAI; +using Microsoft.Extensions.Configuration; + +// Load environment variables from .env file + +// Tool: Random Destination Generator +[Description("Provides a random vacation destination.")] +static string GetRandomDestination() +{ + var destinations = new List + { + "Paris, France", + "Tokyo, Japan", + "New York City, USA", + "Sydney, Australia", + "Rome, Italy", + "Barcelona, Spain", + "Cape Town, South Africa", + "Rio de Janeiro, Brazil", + "Bangkok, Thailand", + "Vancouver, Canada" + }; + var random = new Random(); + int index = random.Next(destinations.Count); + return destinations[index]; +} + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] + ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] + ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +// Configure OpenAI client for GitHub Models +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; +var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions); + +// Create AI Agent with tool integration +AIAgent agent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent( + instructions: "You are a helpful AI Agent that can help plan vacations for customers at random destinations.", + tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] +); + +// Create conversation thread for context +AgentSession session = await agent.CreateSessionAsync(); + +// Run agent with tool invocation +Console.WriteLine(await agent.RunAsync("Plan me a day trip", session)); + +// Follow-up request to demonstrate tool re-invocation +Console.WriteLine(await agent.RunAsync("I don't like that destination. Plan me another vacation.", session)); diff --git a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj index 9e3aeca..cbdaff4 100644 --- a/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj +++ b/00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/dotnet-agent-framework-ghmodels-tool.csproj @@ -23,4 +23,8 @@ + + + +
\ No newline at end of file diff --git a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/README.md b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/README.md index 82c79e4..ebd4689 100644 --- a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/README.md +++ b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/README.md @@ -26,3 +26,9 @@ dotnet run ``` > The sample uploads `../document.md` (located in the `05-agentic-rag/code_samples/` folder) to Foundry at startup. + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/app.cs b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/app.cs new file mode 100644 index 0000000..88d1306 --- /dev/null +++ b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/app.cs @@ -0,0 +1,69 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 4e72b0fc-2c2e-4371-9d75-0912883af3f6 +#:property EnablePreviewFeatures true +#:package Azure.AI.OpenAI@2.1.0 +#:package Azure.Identity@1.17.1 +#:package Azure.AI.Projects@1.2.0-beta.5 +#:package Azure.AI.Projects.OpenAI@1.0.0-beta.5 +#:package Azure.AI.Agents.Persistent@1.2.0-beta.8 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.AzureAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System.ClientModel; +using Azure.AI.Projects; +using Azure.Identity; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using OpenAI; +using OpenAI.Files; +using OpenAI.VectorStores; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; + +// Create an AI Project client and get an OpenAI client that works with the foundry service. +AIProjectClient aiProjectClient = new( + new Uri(endpoint), + new AzureCliCredential()); +OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); + +// Upload the file that contains the data to be used for RAG to the Foundry service. +OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); +ClientResult uploadResult = await fileClient.UploadFileAsync( + filePath: "../document.md", + purpose: FileUploadPurpose.Assistants); + +#pragma warning disable OPENAI001 +VectorStoreClient vectorStoreClient = openAIClient.GetVectorStoreClient(); +ClientResult vectorStoreCreate = await vectorStoreClient.CreateVectorStoreAsync(options: new VectorStoreCreationOptions() +{ + Name = "document-knowledge-base", + FileIds = { uploadResult.Value.Id } +}); +#pragma warning restore OPENAI001 + +var fileSearchTool = new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreCreate.Value.Id)] }; + +AIAgent agent = await aiProjectClient + .CreateAIAgentAsync( + model: deploymentName, + name: "dotNETRAGAgent", + instructions: @"You are an AI assistant designed to answer user questions using only the information retrieved from the provided document(s). + If a user's question cannot be answered using the retrieved context, you must clearly respond: + 'I'm sorry, but the uploaded document does not contain the necessary information to answer that question.' + Do not answer from general knowledge or reasoning. Do not make assumptions or generate hypothetical explanations. + For questions that do have relevant content in the document, respond accurately and cite the document explicitly.", + tools: [fileSearchTool]); + +AgentSession session = await agent.CreateSessionAsync(); + +Console.WriteLine(await agent.RunAsync("Can you explain Contoso's travel insurance coverage?", session)); diff --git a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj index cc0df30..cdb65b0 100644 --- a/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj +++ b/00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj @@ -26,4 +26,8 @@ + + + +
\ No newline at end of file diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/README.md b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/README.md index 6340eac..c43a4e7 100644 --- a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/README.md +++ b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/README.md @@ -24,3 +24,9 @@ dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/app.cs b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/app.cs new file mode 100644 index 0000000..ff9afff --- /dev/null +++ b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/app.cs @@ -0,0 +1,87 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 3bbd10f1-79a7-498e-9aba-1c26488635ae +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ClientModel; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using OpenAI; +using Microsoft.Extensions.Configuration; + +// Load environment variables from .env file + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] + ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] + ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +// Configure OpenAI client for GitHub Models +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; +var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions); + +// Planning agent configuration +const string AGENT_NAME = "TravelPlanAgent"; +const string AGENT_INSTRUCTIONS = @"You are an planner agent. + Your job is to decide which agents to run based on the user's request. + Below are the available agents specialised in different tasks: + - FlightBooking: For booking flights and providing flight information + - HotelBooking: For booking hotels and providing hotel information + - CarRental: For booking cars and providing car rental information + - ActivitiesBooking: For booking activities and providing activity information + - DestinationInfo: For providing information about destinations + - DefaultAgent: For handling general request"; + +ChatClientAgentOptions agentOptions = new() +{ + Name = AGENT_NAME, + Description = AGENT_INSTRUCTIONS, + ChatOptions = new() + { + ResponseFormat = ChatResponseFormatJson.ForJsonSchema( + schema: AIJsonUtilities.CreateJsonSchema(typeof(TravelPlan)), + schemaName: "TravelPlan", + schemaDescription: "Travel Plan with main_task and subtasks") + } +}; + +AIAgent agent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent(agentOptions); + +Console.WriteLine(await agent.RunAsync("Create a travel plan for a family of 4, with 2 kids, from Singapore to Melbourne")); + +// Model classes inlined from Models/Plan.cs and Models/TravelPlan.cs + +public class Plan +{ + [JsonPropertyName("assigned_agent")] + public string? Assigned_agent { get; set; } + + [JsonPropertyName("task_details")] + public string? Task_details { get; set; } +} + +public class TravelPlan +{ + [JsonPropertyName("main_task")] + public string? Main_task { get; set; } + + [JsonPropertyName("subtasks")] + public IList Subtasks { get; set; } = []; +} diff --git a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/dotnet-agent-framework-ghmodel-planningdesign.csproj b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/dotnet-agent-framework-ghmodel-planningdesign.csproj index 4eaf6aa..13be066 100644 --- a/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/dotnet-agent-framework-ghmodel-planningdesign.csproj +++ b/00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/dotnet-agent-framework-ghmodel-planningdesign.csproj @@ -23,4 +23,8 @@ + + + +
\ No newline at end of file diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md index 5029286..e6dc800 100644 --- a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md +++ b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md @@ -24,3 +24,9 @@ dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/app.cs b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/app.cs new file mode 100644 index 0000000..ccacb54 --- /dev/null +++ b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/app.cs @@ -0,0 +1,108 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 347ece07-9c59-405e-8282-387fa070c48a +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.Abstractions@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Azure.AI.Agents.Persistent@1.2.0-beta.8 +#:package Azure.Identity@1.18.0-beta.2 +#:package System.Linq.Async@7.0.0 +#:package OpenAI@2.8.0 +#:package OpenTelemetry.Api@1.14.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Agents.AI.Workflows@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ClientModel; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using Microsoft.Agents.AI.Workflows; +using OpenAI; +using Microsoft.Extensions.Configuration; + +// Load environment variables from .env file + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] + ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] + ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +// Configure OpenAI client for GitHub Models +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; +var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions); + +// Define Concierge Agent (Quality Reviewer) +const string REVIEWER_NAME = "Concierge"; +const string REVIEWER_INSTRUCTIONS = @""" + You are an are hotel concierge who has opinions about providing the most local and authentic experiences for travelers. + The goal is to determine if the front desk travel agent has recommended the best non-touristy experience for a traveler. + If so, state that it is approved. + If not, provide insight on how to refine the recommendation without using a specific example. + """; + +// Define Front Desk Agent (Travel Specialist) +const string FRONTDESK_NAME = "FrontDesk"; +const string FRONTDESK_INSTRUCTIONS = @""" + You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers. + The goal is to provide the best activities and locations for a traveler to visit. + Only provide a single recommendation per response. + You're laser focused on the goal at hand. + Don't waste time with chit chat. + Consider suggestions when refining an idea. + """; + +// Configure agent options +ChatClientAgentOptions frontdeskAgentOptions = new() +{ + Name = FRONTDESK_NAME, + Description = FRONTDESK_INSTRUCTIONS +}; + +ChatClientAgentOptions reviewerAgentOptions = new() +{ + Name = REVIEWER_NAME, + Description = REVIEWER_INSTRUCTIONS +}; + +// Create agent instances +AIAgent reviewerAgent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent(reviewerAgentOptions); +AIAgent frontdeskAgent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent(frontdeskAgentOptions); + +// Build the multi-agent workflow +var workflow = new WorkflowBuilder(frontdeskAgent) + .AddEdge(frontdeskAgent, reviewerAgent) + .Build(); + +// Start the streaming workflow execution +await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, new ChatMessage(ChatRole.User, "I would like to go to Paris.")); + +// Send message to start workflow +await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); + +// Process streaming workflow events +string strResult = ""; +await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false)) +{ + if (evt is AgentResponseUpdateEvent executorComplete) + { + strResult += executorComplete.Data; + Console.WriteLine($"{executorComplete.ExecutorId}: {executorComplete.Data}"); + } +} + +// Display final aggregated result +Console.WriteLine("\n=== Final Result ==="); +Console.WriteLine(strResult); diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj index 478bff2..add1b99 100644 --- a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj +++ b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj @@ -28,4 +28,8 @@ + + + +
\ No newline at end of file diff --git a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md index e5e9d2b..305f322 100644 --- a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md +++ b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/README.md @@ -26,3 +26,9 @@ dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/app.cs b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/app.cs new file mode 100644 index 0000000..8e1d1d7 --- /dev/null +++ b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/app.cs @@ -0,0 +1,81 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 72ce6d02-83a5-4d22-8e78-1bd196957158 +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ComponentModel; +using System.ClientModel; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using OpenAI; +using Microsoft.Extensions.Configuration; + +// Load environment variables from .env file + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] + ?? throw new InvalidOperationException("GITHUB_ENDPOINT is required"); +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] + ?? throw new InvalidOperationException("GITHUB_TOKEN is required"); + +// Configure OpenAI client for GitHub Models +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; + +// Create AI Agent with custom tool +AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) + .GetChatClient(github_model_id) + .AsIChatClient() + .AsAIAgent( + name: "TravelAgent", + instructions: "You are a helpful AI Agent that can help plan vacations for customers at random destinations.", + tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] + ); + +// Run agent with standard response +Console.WriteLine("=== Travel Plan ==="); +Console.WriteLine(await agent.RunAsync("Plan me a day trip")); + +// Run agent with streaming response +Console.WriteLine("\n=== Streaming Travel Plan ==="); +await foreach (var update in agent.RunStreamingAsync("Plan me a day trip")) +{ + Console.Write(update); +} +Console.WriteLine(); + +// Agent Tool: Random Destination Generator +[Description("Provides a random vacation destination.")] +static string GetRandomDestination() +{ + var destinations = new List + { + "Paris, France", + "Tokyo, Japan", + "New York City, USA", + "Sydney, Australia", + "Rome, Italy", + "Barcelona, Spain", + "Cape Town, South Africa", + "Rio de Janeiro, Brazil", + "Bangkok, Thailand", + "Vancouver, Canada" + }; + + var random = new Random(); + int index = random.Next(destinations.Count); + return destinations[index]; +} diff --git a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj index 84a6843..376fa3b 100644 --- a/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj +++ b/02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/dotnet-travelagent-ghmodel.csproj @@ -22,4 +22,8 @@ + + + +
\ No newline at end of file diff --git a/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj b/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj index 759033f..3213ed5 100644 --- a/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj +++ b/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/01-dotnet-agent-framework-aoai.csproj @@ -21,4 +21,8 @@ + + + +
\ No newline at end of file diff --git a/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md b/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md index 0805b7f..4deee9d 100644 --- a/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md +++ b/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/README.md @@ -24,3 +24,9 @@ dotnet user-secrets set "AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME" "gpt-4.1-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/app.cs b/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/app.cs new file mode 100644 index 0000000..4758c2f --- /dev/null +++ b/03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/app.cs @@ -0,0 +1,39 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 2e421ed5-5bee-47c3-9608-7d42f9dfed00 +#:package Azure.AI.OpenAI@2.1.0 +#:package Azure.Identity@1.17.1 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using Azure.AI.OpenAI; +using Azure.Identity; +using Microsoft.Agents.AI; +using OpenAI.Chat; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var aoai_endpoint = config["AZURE_OPENAI_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); +var aoai_model_id = config["AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME"] ?? "gpt-4.1-mini"; + +Console.WriteLine($"Using Azure OpenAI Endpoint: {aoai_endpoint}"); +Console.WriteLine($"Using Azure OpenAI Model Deployment: {aoai_model_id}"); + +AIAgent agent = new AzureOpenAIClient( + new Uri(aoai_endpoint), + new AzureCliCredential()) + .GetChatClient(aoai_model_id) + .AsAIAgent(instructions: "You are a helpful assistant.", name: "MAFDemoAgent"); + + +Console.WriteLine(await agent.RunAsync("Write a haiku about Agent Framework.")); + +await foreach (var update in agent.RunStreamingAsync("Write a haiku about Agent Framework.")) +{ + Console.Write(update); +} diff --git a/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj b/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj index a29b1ec..e32d83d 100644 --- a/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj +++ b/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/02-dotnet-agent-framework-ghmodel.csproj @@ -22,4 +22,8 @@ + + + +
\ No newline at end of file diff --git a/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md b/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md index 9998052..996941d 100644 --- a/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md +++ b/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/README.md @@ -24,3 +24,9 @@ dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/app.cs b/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/app.cs new file mode 100644 index 0000000..e09d6b0 --- /dev/null +++ b/03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/app.cs @@ -0,0 +1,80 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 897b8bea-86e0-456a-a321-9a96d36c8d67 +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ComponentModel; +using System.ClientModel; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using OpenAI; +using Microsoft.Extensions.Configuration; + +// Load environment variables from .env file + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] + ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] + ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +// Configure OpenAI client for GitHub Models +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; + +// Agent Tool: Random Destination Generator +[Description("Provides a random vacation destination.")] +static string GetRandomDestination() +{ + var destinations = new List + { + "Paris, France", + "Tokyo, Japan", + "New York City, USA", + "Sydney, Australia", + "Rome, Italy", + "Barcelona, Spain", + "Cape Town, South Africa", + "Rio de Janeiro, Brazil", + "Bangkok, Thailand", + "Vancouver, Canada" + }; + var random = new Random(); + int index = random.Next(destinations.Count); + return destinations[index]; +} + +// Create AI Agent with basic instructions and tool +AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) + .GetChatClient(github_model_id) + .AsIChatClient() + .AsAIAgent( + name: "BasicAgent", + instructions: "You are a basic AI Agent that can answer questions and suggest random travel destinations.", + tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] + ); + +// Run agent with standard response +Console.WriteLine("=== Basic Agent Response ==="); +Console.WriteLine(await agent.RunAsync("Suggest a vacation destination.")); + +// Run agent with streaming response +Console.WriteLine("\n=== Streaming Response ==="); +await foreach (var update in agent.RunStreamingAsync("Suggest a vacation destination.")) +{ + Console.Write(update); +} +Console.WriteLine(); diff --git a/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj b/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj index 4d635d5..f74a6fe 100644 --- a/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj +++ b/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/03-dotnet-agent-framework-msfoundry.csproj @@ -25,4 +25,8 @@ + + + +
\ No newline at end of file diff --git a/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md b/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md index 2a5527e..973b866 100644 --- a/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md +++ b/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/README.md @@ -24,3 +24,9 @@ dotnet user-secrets set "AZURE_AI_MODEL_DEPLOYMENT_NAME" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/app.cs b/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/app.cs new file mode 100644 index 0000000..d705e75 --- /dev/null +++ b/03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/app.cs @@ -0,0 +1,46 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 06e4bd3a-9846-4330-98e5-7e0431118217 +#:property EnablePreviewFeatures true +#:package Azure.AI.OpenAI@2.1.0 +#:package Azure.Identity@1.17.1 +#:package Azure.AI.Projects@1.2.0-beta.5 +#:package Azure.AI.Projects.OpenAI@1.0.0-beta.5 +#:package Azure.AI.Agents.Persistent@1.2.0-beta.8 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.AzureAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using Azure.AI.Projects; +using Azure.AI.Projects.OpenAI; +using Azure.Identity; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; + +// Create an AI Project client and get an OpenAI client that works with the foundry service. +AIProjectClient aiProjectClient = new( + new Uri(endpoint), + new AzureCliCredential()); + + +AIAgent agent = await aiProjectClient.CreateAIAgentAsync( + name: "Agent-Framework", + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: deploymentName) + { + Instructions = "You are good at telling jokes." + }) +); + + +Console.WriteLine(await agent.RunAsync("Write a haiku about Agent Framework")); diff --git a/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj b/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj index 860ad98..36f91d0 100644 --- a/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj +++ b/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/04-dotnet-agent-framework-foundrylocal.csproj @@ -22,4 +22,8 @@ + + + +
\ No newline at end of file diff --git a/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md b/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md index bfec3e7..023538d 100644 --- a/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md +++ b/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/README.md @@ -25,3 +25,9 @@ dotnet user-secrets set "FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME" "" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/app.cs b/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/app.cs new file mode 100644 index 0000000..03468b9 --- /dev/null +++ b/03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/app.cs @@ -0,0 +1,57 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 54f947d6-b3f4-4d15-9772-afd04450d9d3 +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.AzureAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ClientModel; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using OpenAI; +using Microsoft.Extensions.Configuration; + +// Load environment variables from .env file + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var foundryLocalEndpoint = config["FOUNDRYLOCAL_ENDPOINT"] + ?? throw new InvalidOperationException("FOUNDRYLOCAL_ENDPOINT is not set."); +var foundryLocalModelId = config["FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME"] + ?? throw new InvalidOperationException("FOUNDRYLOCAL_MODEL_DEPLOYMENT_NAME is not set."); + +Console.WriteLine($"Endpoint: {foundryLocalEndpoint}"); +Console.WriteLine($"Model: {foundryLocalModelId}"); + +// Configure OpenAI client for Foundry Local (no API key required) +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(foundryLocalEndpoint) +}; + +var openAIClient = new OpenAIClient(new ApiKeyCredential("nokey"), openAIOptions); + +// Create AI Agent +AIAgent agent = openAIClient + .GetChatClient(foundryLocalModelId) + .AsIChatClient() + .AsAIAgent(instructions: "You are a helpful assistant.", name: "FoundryLocalAgent"); + +// Run agent +Console.WriteLine("\n=== Response ==="); +Console.WriteLine(await agent.RunAsync("Can you introduce yourself?")); + +// Run agent with streaming response +Console.WriteLine("\n=== Streaming Response ==="); +await foreach (var update in agent.RunStreamingAsync("What can you help me with?")) +{ + Console.Write(update); +} +Console.WriteLine(); diff --git a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj index 50cc47d..b373366 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/01-dotnet-agent-framework-msfoundry-vision.csproj @@ -25,4 +25,8 @@ + + + +
\ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/README.md b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/README.md index 050f874..47cd75c 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/README.md +++ b/04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/README.md @@ -25,3 +25,9 @@ dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "() + .AddEnvironmentVariables() + .Build(); + +var azure_foundry_endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var azure_foundry_model_id = "gpt-4o"; + +var imgPath = "../../../files/home.png"; + +const string AgentName = "Vision-Agent"; +const string AgentInstructions = "You are my furniture sales consultant, you can find different furniture elements from the pictures and give me a purchase suggestion"; + + +async Task OpenImageBytesAsync(string path) +{ + return await File.ReadAllBytesAsync(path); +} + +var imageBytes = await OpenImageBytesAsync(imgPath); + +AIProjectClient aiProjectClient = new( + new Uri(azure_foundry_endpoint), + new AzureCliCredential()); + + +AIAgent agent = await aiProjectClient.CreateAIAgentAsync( + name: AgentName, + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: azure_foundry_model_id) + { + Instructions = AgentInstructions + }) +); + + +ChatMessage userMessage = new ChatMessage(ChatRole.User, [ + new TextContent("Can you identify the furniture items in this image and suggest which ones would fit well in a modern living room?"), new DataContent(imageBytes, "image/png") +]); + + + +AgentSession session = await agent.CreateSessionAsync(); + + +Console.WriteLine(await agent.RunAsync(userMessage, session)); diff --git a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj index bc2362f..67cbf2e 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/02-dotnet-agent-framework-msfoundry-code-interpreter.csproj @@ -26,4 +26,8 @@ + + + +
\ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/README.md b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/README.md index 070af24..2900239 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/README.md +++ b/04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/README.md @@ -25,3 +25,9 @@ dotnet user-secrets set "AZURE_AI_PROJECT_ENDPOINT" "() + .AddEnvironmentVariables() + .Build(); + +var azure_foundry_endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var azure_foundry_model_id = "gpt-4.1-mini"; + +const string AgentName = "Code-Agent-Framework"; +const string AgentInstructions = "You are an AI assistant that helps people find information."; + +AIProjectClient aiProjectClient = new( + new Uri(azure_foundry_endpoint), + new AzureCliCredential()); + +AIAgent codingAgent = await aiProjectClient.CreateAIAgentAsync( + name: AgentName, + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: azure_foundry_model_id) + { + Instructions = AgentInstructions, + Tools = { + ResponseTool.CreateCodeInterpreterTool( + new CodeInterpreterToolContainer( + CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration(fileIds: []) + ) + ), + } + }) +); + +AgentResponse response = await codingAgent.RunAsync("Use code to determine the values in the Fibonacci sequence that that are less then the value of 101?"); + +// Get the CodeInterpreterToolCallContent +CodeInterpreterToolCallContent? toolCallContent = response.Messages.SelectMany(m => m.Contents).OfType().FirstOrDefault(); +if (toolCallContent?.Inputs is not null) +{ + DataContent? codeInput = toolCallContent.Inputs.OfType().FirstOrDefault(); + if (codeInput?.HasTopLevelMediaType("text") ?? false) + { + Console.WriteLine($"Code Input: {Encoding.UTF8.GetString(codeInput.Data.ToArray()) ?? "Not available"}"); + } +} + +// Get the CodeInterpreterToolResultContent +CodeInterpreterToolResultContent? toolResultContent = response.Messages.SelectMany(m => m.Contents).OfType().FirstOrDefault(); +if (toolResultContent?.Outputs is not null && toolResultContent.Outputs.OfType().FirstOrDefault() is { } resultOutput) +{ + Console.WriteLine($"Code Tool Result: {resultOutput.Text}"); +} + +// Getting any annotations generated by the tool +foreach (AIAnnotation annotation in response.Messages.SelectMany(m => m.Contents).SelectMany(C => C.Annotations ?? [])) +{ + if (annotation.RawRepresentation is TextAnnotationUpdate citationAnnotation) + { + Console.WriteLine($$""" + File Id: {{citationAnnotation.OutputFileId}} + Text to Replace: {{citationAnnotation.TextToReplace}} + Filename: {{Path.GetFileName(citationAnnotation.TextToReplace)}} + """); + } +} diff --git a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj index 80056be..aa0555c 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/03-dotnet-agent-framework-msfoundry-binggrounding.csproj @@ -26,4 +26,8 @@ + + + +
\ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/README.md b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/README.md index c232f37..e7bb8ad 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/README.md +++ b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/README.md @@ -25,3 +25,9 @@ dotnet user-secrets set "BING_CONNECTION_NAME" "" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/app.cs b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/app.cs new file mode 100644 index 0000000..edb8279 --- /dev/null +++ b/04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/app.cs @@ -0,0 +1,73 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId ee9707f4-4391-43ca-bdd5-38f721eb32a9 +#:property EnablePreviewFeatures true +#:package Azure.AI.OpenAI@2.1.0 +#:package Azure.Identity@1.17.1 +#:package Azure.AI.Projects@1.2.0-beta.5 +#:package Azure.AI.Projects.OpenAI@1.0.0-beta.5 +#:package Azure.AI.Agents.Persistent@1.2.0-beta.8 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.AzureAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.Linq; +using System.IO; +using System.Text; +using Azure.AI.Projects; +using Azure.AI.Projects.OpenAI; +using Azure.Identity; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using OpenAI.Assistants; +using OpenAI.Responses; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var azure_foundry_endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var azure_foundry_model_id = "gpt-4.1-mini"; + +const string AgentName = "Bing-Agent-Framework"; +const string AgentInstructions = @"You are a helpful assistant that can search the web for current information. + Use the Bing search tool to find up-to-date information and provide accurate, well-sourced answers. + Always cite your sources when possible."; + +AIProjectClient aiProjectClient = new( + new Uri(azure_foundry_endpoint), + new AzureCliCredential()); + + +var connectionName = config["BING_CONNECTION_NAME"]; + +Console.WriteLine($"Using Bing Connection: {connectionName}"); + +AIProjectConnection bingConnectionName = aiProjectClient.Connections.GetConnection(connectionName: connectionName); + +BingGroundingAgentTool bingGroundingAgentTool = new(new BingGroundingSearchToolOptions( + searchConfigurations: [new BingGroundingSearchConfiguration(projectConnectionId: bingConnectionName.Id)] + ) +); + + +AIAgent bingAgent = await aiProjectClient.CreateAIAgentAsync( + name: AgentName, + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: azure_foundry_model_id) + { + Instructions = AgentInstructions, + Tools = { + bingGroundingAgentTool, + } + }) +); + +AgentResponse response = await bingAgent.RunAsync("What is today's date and weather in Guangzhou?"); + +Console.WriteLine("Response:"); +Console.WriteLine(response); diff --git a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj index e03e613..21c9a64 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj +++ b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/04-dotnet-agent-framework-msfoundry-file-search.csproj @@ -26,4 +26,8 @@ + + + +
\ No newline at end of file diff --git a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/README.md b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/README.md index 6b693dc..f3b6a3c 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/README.md +++ b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/README.md @@ -26,3 +26,9 @@ dotnet user-secrets set "AZURE_AI_MODEL_DEPLOYMENT_NAME" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/app.cs b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/app.cs new file mode 100644 index 0000000..26f4cc5 --- /dev/null +++ b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/app.cs @@ -0,0 +1,67 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 8324968c-859a-4090-8afa-336940d7cf66 +#:property EnablePreviewFeatures true +#:package Azure.AI.OpenAI@2.1.0 +#:package Azure.Identity@1.17.1 +#:package Azure.AI.Projects@1.2.0-beta.5 +#:package Azure.AI.Projects.OpenAI@1.0.0-beta.5 +#:package Azure.AI.Agents.Persistent@1.2.0-beta.8 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.AzureAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +// See https://aka.ms/new-console-template for more information +using System.ClientModel; +using Azure.AI.Projects; +using Azure.Identity; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using OpenAI; +using OpenAI.Files; +using OpenAI.VectorStores; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; + +// Create an AI Project client and get an OpenAI client that works with the foundry service. +AIProjectClient aiProjectClient = new( + new Uri(endpoint), + new AzureCliCredential()); +OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); + +// Upload the file that contains the data to be used for RAG to the Foundry service. +OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); +ClientResult uploadResult = await fileClient.UploadFileAsync( + filePath: "../../../files/demo.md", + purpose: FileUploadPurpose.Assistants); + +#pragma warning disable OPENAI001 +VectorStoreClient vectorStoreClient = openAIClient.GetVectorStoreClient(); +ClientResult vectorStoreCreate = await vectorStoreClient.CreateVectorStoreAsync(options: new VectorStoreCreationOptions() +{ + Name = "rag-document-knowledge-base", + FileIds = { uploadResult.Value.Id } +}); +#pragma warning restore OPENAI001 + +var fileSearchTool = new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreCreate.Value.Id)] }; + +AIAgent agent = await aiProjectClient + .CreateAIAgentAsync( + model: deploymentName, + name: "dotNETRAGAgent", + instructions: @"You are an AI assistant that helps people find information in a set of documents. Use the File Search tool to look up relevant information from the files when needed to answer user questions. If you don't know the answer, just say you don't know. Do not make up answers.", + tools: [fileSearchTool]); + + +AgentSession session = await agent.CreateSessionAsync(); + +Console.WriteLine(await agent.RunAsync("What's graphrag?", session)); diff --git a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj index a3f62fb..ca25b69 100644 --- a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj +++ b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/AgentMCP.Console.csproj @@ -26,4 +26,8 @@ + + + +
\ No newline at end of file diff --git a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/README.md b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/README.md index 5cd110d..1d33fbb 100644 --- a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/README.md +++ b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/README.md @@ -26,3 +26,9 @@ dotnet run ``` When the agent wants to call an MCP tool, it will prompt you to enter `Y` to approve before the call is made. + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/app.cs b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/app.cs new file mode 100644 index 0000000..964b002 --- /dev/null +++ b/05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/app.cs @@ -0,0 +1,86 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId d0e13627-3df1-4b64-aec6-0fb17f50a14d +#:property EnablePreviewFeatures true +#:package Azure.Identity@1.17.1 +#:package Azure.AI.Agents.Persistent@1.2.0-beta.8 +#:package ModelContextProtocol@0.6.0-preview.1 +#:package System.Linq.Async@7.0.0 +#:package Azure.AI.Projects@1.2.0-beta.5 +#:package Azure.AI.Projects.OpenAI@1.0.0-beta.5 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.AzureAI.Persistent@1.0.0-preview.260219.1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates + +using System; +using System.Linq; + +using Azure.AI.Agents.Persistent; +using Azure.Identity; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var azure_foundry_endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set."); +var azure_foundry_model_id = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4.1-mini"; + + +var persistentAgentsClient = new PersistentAgentsClient(azure_foundry_endpoint, new AzureCliCredential()); +var mcpToolWithApproval = new HostedMcpServerTool( + serverName: "microsoft_learn", + serverAddress: "https://learn.microsoft.com/api/mcp") +{ + AllowedTools = ["microsoft_docs_search"], + ApprovalMode = HostedMcpServerToolApprovalMode.AlwaysRequire +}; + +// Create an agent based on Azure OpenAI Responses as the backend. +AIAgent agentWithRequiredApproval = await persistentAgentsClient.CreateAIAgentAsync( + model: azure_foundry_model_id, + options: new() + { + Name = "MicrosoftLearnAgentWithApproval", + ChatOptions = new() + { + Instructions = "You answer questions by searching the Microsoft Learn content only.", + Tools = [mcpToolWithApproval] + }, + }); + +// You can then invoke the agent like any other AIAgent. +var sessionWithRequiredApproval = await agentWithRequiredApproval.CreateSessionAsync(); +var response = await agentWithRequiredApproval.RunAsync("Please summarize the Azure AI Agent documentation related to MCP Tool calling?", sessionWithRequiredApproval); +var userInputRequests = response.Messages.SelectMany(m => m.Contents).OfType().ToList(); + +while (userInputRequests.Count > 0) +{ + // Ask the user to approve each MCP call request. + var userInputResponses = userInputRequests + .OfType() + .Select(approvalRequest => + { + Console.WriteLine($""" + The agent would like to invoke the following MCP Tool, please reply Y to approve. + ServerName: {approvalRequest.ToolCall.ServerName} + Name: {approvalRequest.ToolCall.ToolName} + Arguments: {string.Join(", ", approvalRequest.ToolCall.Arguments?.Select(x => $"{x.Key}: {x.Value}") ?? [])} + """); + return new ChatMessage(ChatRole.User, [approvalRequest.CreateResponse(Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false)]); + }) + .ToList(); + + // Pass the user input responses back to the agent for further processing. + response = await agentWithRequiredApproval.RunAsync(userInputResponses, sessionWithRequiredApproval); + + userInputRequests = response.Messages.SelectMany(m => m.Contents).OfType().ToList(); +} + +Console.WriteLine($"\nAgent: {response}"); diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md index 1d4c549..cd8e1de 100644 --- a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/README.md @@ -28,3 +28,9 @@ dotnet user-secrets set "AZURE_AI_MODEL_DEPLOYMENT_NAME" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/app.cs b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/app.cs new file mode 100644 index 0000000..005ec66 --- /dev/null +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/app.cs @@ -0,0 +1,69 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 92469d2f-b467-4911-9cbc-dafa21cc55dd +#:property EnablePreviewFeatures true +#:package Azure.AI.OpenAI@2.1.0 +#:package Azure.Identity@1.17.1 +#:package Azure.AI.Projects@1.2.0-beta.5 +#:package Azure.AI.Projects.OpenAI@1.0.0-beta.5 +#:package Azure.AI.Agents.Persistent@1.2.0-beta.8 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.AzureAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System.ClientModel; +using Azure.AI.Projects; +using Azure.Identity; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using OpenAI; +using OpenAI.Files; +using OpenAI.VectorStores; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; + +// Create an AI Project client and get an OpenAI client that works with the foundry service. +AIProjectClient aiProjectClient = new( + new Uri(endpoint), + new AzureCliCredential()); +OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); + +// Upload the file that contains the data to be used for RAG to the Foundry service. +OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); +ClientResult uploadResult = await fileClient.UploadFileAsync( + filePath: "../../files/demo.md", + purpose: FileUploadPurpose.Assistants); + +#pragma warning disable OPENAI001 +VectorStoreClient vectorStoreClient = openAIClient.GetVectorStoreClient(); +ClientResult vectorStoreCreate = await vectorStoreClient.CreateVectorStoreAsync(options: new VectorStoreCreationOptions() +{ + Name = "document-knowledge-base", + FileIds = { uploadResult.Value.Id } +}); +#pragma warning restore OPENAI001 + +var fileSearchTool = new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreCreate.Value.Id)] }; + +AIAgent agent = await aiProjectClient + .CreateAIAgentAsync( + model: deploymentName, + name: "dotNETRAGAgent", + instructions: @"You are an AI assistant designed to answer user questions using only the information retrieved from the provided document(s). + If a user's question cannot be answered using the retrieved context, you must clearly respond: + 'I'm sorry, but the uploaded document does not contain the necessary information to answer that question.' + Do not answer from general knowledge or reasoning. Do not make assumptions or generate hypothetical explanations. + For questions that do have relevant content in the document, respond accurately and cite the document explicitly.", + tools: [fileSearchTool]); + +AgentSession session = await agent.CreateSessionAsync(); + +Console.WriteLine(await agent.RunAsync("What's GraphRAG?", session)); diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj index 0ae961a..a3d6106 100644 --- a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/dotnet-agent-framework-msfoundry-file-search.csproj @@ -26,4 +26,8 @@ + + + +
\ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj index a96f05f..e4adc32 100644 --- a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj +++ b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/01.dotnet-agent-framework-workflow-ghmodel-basic.csproj @@ -22,4 +22,8 @@ + + + +
\ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/README.md b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/README.md index 036dd28..f01124b 100644 --- a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/README.md +++ b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/README.md @@ -24,3 +24,9 @@ dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/app.cs b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/app.cs new file mode 100644 index 0000000..6622902 --- /dev/null +++ b/07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/app.cs @@ -0,0 +1,108 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId c2f12400-7f7c-41bd-a2c5-188e7dbb4e13 +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Agents.AI.Workflows@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ComponentModel; +using System.ClientModel; +using OpenAI; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using Microsoft.Agents.AI.Workflows; +using Microsoft.Extensions.Configuration; + +// Load environment variables + +// Get GitHub configuration +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +// Configure OpenAI client +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; + +var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions); + +// Define agent configurations +const string ReviewerAgentName = "Concierge"; +const string ReviewerAgentInstructions = @" + You are an are hotel concierge who has opinions about providing the most local and authentic experiences for travelers. + The goal is to determine if the front desk travel agent has recommended the best non-touristy experience for a traveler. + If so, state that it is approved. + If not, provide insight on how to refine the recommendation without using a specific example. + "; + +const string FrontDeskAgentName = "FrontDesk"; +const string FrontDeskAgentInstructions = @" + You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers. + The goal is to provide the best activities and locations for a traveler to visit. + Only provide a single recommendation per response. + You're laser focused on the goal at hand. + Don't waste time with chit chat. + Consider suggestions when refining an idea. + "; + +// Create AI agents +AIAgent reviewerAgent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent( + name: ReviewerAgentName, instructions: ReviewerAgentInstructions); +AIAgent frontDeskAgent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent( + name: FrontDeskAgentName, instructions: FrontDeskAgentInstructions); + +// Build workflow +var workflow = new WorkflowBuilder(frontDeskAgent) + .AddEdge(frontDeskAgent, reviewerAgent) + .Build(); + +// Create user message +ChatMessage userMessage = new ChatMessage(ChatRole.User, [ + new TextContent("I would like to go to Paris.") +]); + +// Execute workflow +await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, userMessage); + +// Process workflow events +await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); + +string messageData = ""; + +await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false)) +{ + if (evt is AgentResponseUpdateEvent executorComplete) + { + messageData += executorComplete.Data; + Console.WriteLine($"{executorComplete.ExecutorId}: {executorComplete.Data}"); + } +} + +Console.WriteLine("\n=== Final Output ==="); +Console.WriteLine(messageData); + +// Mermaid +Console.WriteLine("\nMermaid string: \n======="); +var mermaid = workflow.ToMermaidString(); +Console.WriteLine(mermaid); +Console.WriteLine("======="); + +// DOT - Save to file instead of stdout to avoid pipe issues +var dotString = workflow.ToDotString(); +var dotFilePath = "workflow.dot"; +File.WriteAllText(dotFilePath, dotString); +Console.WriteLine($"\nDOT graph saved to: {dotFilePath}"); +Console.WriteLine("To generate image: dot -Tsvg workflow.dot -o workflow.svg"); +Console.WriteLine(" dot -Tpng workflow.dot -o workflow.png"); diff --git a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj index 776269a..2329f2f 100644 --- a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj +++ b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/02.dotnet-agent-framework-workflow-ghmodel-sequential.csproj @@ -22,4 +22,8 @@ + + + +
\ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/README.md b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/README.md index ce5768e..eec40c5 100644 --- a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/README.md +++ b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/README.md @@ -25,3 +25,9 @@ dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/app.cs b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/app.cs new file mode 100644 index 0000000..ad57e83 --- /dev/null +++ b/07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/app.cs @@ -0,0 +1,122 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId b0f6cf92-970e-48d5-94e4-58e1561d4fff +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Agents.AI.Workflows@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ComponentModel; +using System.ClientModel; +using OpenAI; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using Microsoft.Agents.AI.Workflows; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = "gpt-4o"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +var imgPath = "../../imgs/home.png"; + +// Configure OpenAI client +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; + +var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions); + +// Define agent names and instructions +const string SalesAgentName = "Sales-Agent"; +const string SalesAgentInstructions = "You are my furniture sales consultant, you can find different furniture elements from the pictures and give me a purchase suggestion"; + +const string PriceAgentName = "Price-Agent"; +const string PriceAgentInstructions = @"You are a furniture pricing specialist and budget consultant. Your responsibilities include: + 1. Analyze furniture items and provide realistic price ranges based on quality, brand, and market standards + 2. Break down pricing by individual furniture pieces + 3. Provide budget-friendly alternatives and premium options + 4. Consider different price tiers (budget, mid-range, premium) + 5. Include estimated total costs for room setups + 6. Suggest where to find the best deals and shopping recommendations + 7. Factor in additional costs like delivery, assembly, and accessories + 8. Provide seasonal pricing insights and best times to buy + Always format your response with clear price breakdowns and explanations for the pricing rationale."; + +const string QuoteAgentName = "Quote-Agent"; +const string QuoteAgentInstructions = @"You are a assistant that create a quote for furniture purchase. + 1. Create a well-structured quote document that includes: + 2. A title page with the document title, date, and client name + 3. An introduction summarizing the purpose of the document + 4. A summary section with total estimated costs and recommendations + 5. Use clear headings, bullet points, and tables for easy readability + 6. All quotes are presented in markdown form"; + +// Read image bytes +async Task OpenImageBytesAsync(string path) +{ + return await File.ReadAllBytesAsync(path); +} + +var imageBytes = await OpenImageBytesAsync(imgPath); + +// Create AI agents +AIAgent salesagent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent( + name: SalesAgentName, instructions: SalesAgentInstructions); +AIAgent priceagent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent( + name: PriceAgentName, instructions: PriceAgentInstructions); +AIAgent quoteagent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent( + name: QuoteAgentName, instructions: QuoteAgentInstructions); + +// Build sequential workflow +var workflow = new WorkflowBuilder(salesagent) + .AddEdge(salesagent, priceagent) + .AddEdge(priceagent, quoteagent) + .Build(); + +// Create user message with image +ChatMessage userMessage = new ChatMessage(ChatRole.User, [ + new DataContent(imageBytes, "image/png"), + new TextContent("Please find the relevant furniture according to the image and give the corresponding price for each piece of furniture.Finally Output generates a quotation") +]); + +// Execute workflow +StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, userMessage); + +// Process streaming results +await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); +string id = ""; +string messageData = ""; +await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false)) +{ + if (evt is AgentResponseUpdateEvent executorComplete) + { + messageData += executorComplete.Data; + Console.WriteLine($"{executorComplete.ExecutorId}: {executorComplete.Data}"); + } +} + +Console.WriteLine(messageData); +// Mermaid +Console.WriteLine("\nMermaid string: \n======="); +var mermaid = workflow.ToMermaidString(); +Console.WriteLine(mermaid); +Console.WriteLine("======="); + +// DOT - Save to file instead of stdout to avoid pipe issues +var dotString = workflow.ToDotString(); +var dotFilePath = "workflow.dot"; +File.WriteAllText(dotFilePath, dotString); +Console.WriteLine($"\nDOT graph saved to: {dotFilePath}"); +Console.WriteLine("To generate image: dot -Tsvg workflow.dot -o workflow.svg"); +Console.WriteLine(" dot -Tpng workflow.dot -o workflow.png"); diff --git a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj index e8b0217..11a6b5d 100644 --- a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj +++ b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/03.dotnet-agent-framework-workflow-ghmodel-concurrent.csproj @@ -22,4 +22,8 @@ + + + +
\ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/README.md b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/README.md index 6f43d90..223b552 100644 --- a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/README.md +++ b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/README.md @@ -27,3 +27,9 @@ dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/app.cs b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/app.cs new file mode 100644 index 0000000..d23109d --- /dev/null +++ b/07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/app.cs @@ -0,0 +1,131 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 248d296e-d7c2-464b-8ace-5e2c3b1cbdc9 +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Agents.AI.Workflows@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ComponentModel; +using System.ClientModel; +using OpenAI; +using Microsoft.Extensions.AI; +using Microsoft.Agents.AI; +using Microsoft.Agents.AI.Workflows; +using Microsoft.Agents.AI.Workflows.Reflection; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = "gpt-4o"; +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +// Configure OpenAI client +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; + +var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions); + +// Define agent names and instructions +const string ResearcherAgentName = "Researcher-Agent"; +const string ResearcherAgentInstructions = "You are my travel researcher, working with me to analyze the destination, list relevant attractions, and make detailed plans for each attraction."; + +const string PlanAgentName = "Plan-Agent"; +const string PlanAgentInstructions = "You are my travel planner, working with me to create a detailed travel plan based on the researcher's findings."; + +// Create AI agents +AIAgent researcherAgent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent( + name: ResearcherAgentName, instructions: ResearcherAgentInstructions); +AIAgent plannerAgent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent( + name: PlanAgentName, instructions: PlanAgentInstructions); + +// Create concurrent executors +var startExecutor = new ConcurrentStartExecutor(); +var aggregationExecutor = new ConcurrentAggregationExecutor(); + +// Build concurrent workflow with FanOut/FanIn pattern +var workflow = new WorkflowBuilder(startExecutor) + .AddFanOutEdge(startExecutor, targets: [researcherAgent, plannerAgent]) + .AddFanInBarrierEdge(sources: [researcherAgent, plannerAgent], aggregationExecutor) + .WithOutputFrom(aggregationExecutor) + .Build(); + +string messageData = ""; +// Execute workflow +await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, "Plan a trip to Seattle in December"); +await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false)) +{ + if (evt is AgentResponseUpdateEvent executorComplete) + { + messageData += executorComplete.Data; + Console.WriteLine($"{executorComplete.ExecutorId}: {executorComplete.Data}"); + } +} + +Console.WriteLine(messageData); + + +// Mermaid +Console.WriteLine("\nMermaid string: \n======="); +var mermaid = workflow.ToMermaidString(); +Console.WriteLine(mermaid); +Console.WriteLine("======="); + +// DOT - Save to file instead of stdout to avoid pipe issues +var dotString = workflow.ToDotString(); +var dotFilePath = "workflow.dot"; +File.WriteAllText(dotFilePath, dotString); +Console.WriteLine($"\nDOT graph saved to: {dotFilePath}"); +Console.WriteLine("To generate image: dot -Tsvg workflow.dot -o workflow.svg"); +Console.WriteLine(" dot -Tpng workflow.dot -o workflow.png"); + +/// +/// Executor that starts the concurrent processing by broadcasting messages to all agents. +/// +public class ConcurrentStartExecutor() : + ReflectingExecutor("ConcurrentStartExecutor"), + IMessageHandler +{ + /// + /// Starts the concurrent processing by sending messages to the agents. + /// + public async ValueTask HandleAsync(string message, IWorkflowContext context, CancellationToken cancellationToken = default) + { + await context.SendMessageAsync(new ChatMessage(ChatRole.User, message)); + await context.SendMessageAsync(new TurnToken(emitEvents: true)); + } +} + +/// +/// Executor that aggregates the results from the concurrent agents. +/// +public class ConcurrentAggregationExecutor() : + ReflectingExecutor("ConcurrentAggregationExecutor"), + IMessageHandler +{ + private readonly List _messages = []; + + /// + /// Handles incoming messages from the agents and aggregates their responses. + /// + public async ValueTask HandleAsync(ChatMessage message, IWorkflowContext context, CancellationToken cancellationToken = default) + { + this._messages.Add(message); + + if (this._messages.Count == 2) + { + var formattedMessages = string.Join(Environment.NewLine, this._messages.Select(m => $"{m.AuthorName}: {m.Text}")); + await context.YieldOutputAsync(formattedMessages); + } + } +} diff --git a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj index 96d88af..8425d2d 100644 --- a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj +++ b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/04.dotnet-agent-framework-workflow-msfoundry-condition.csproj @@ -28,4 +28,8 @@ + + + +
\ No newline at end of file diff --git a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md index b78acdf..47276c6 100644 --- a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md +++ b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md @@ -26,3 +26,9 @@ dotnet user-secrets set "AZURE_AI_MODEL_DEPLOYMENT_NAME" "gpt-4o-mini" ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/app.cs b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/app.cs new file mode 100644 index 0000000..f954fa4 --- /dev/null +++ b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/app.cs @@ -0,0 +1,19 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 861df000-8a3f-4d7f-a4ba-b14286e638a2 +#:property EnablePreviewFeatures true +#:package Azure.AI.OpenAI@2.1.0 +#:package Azure.Identity@1.17.1 +#:package Azure.AI.Projects@1.2.0-beta.5 +#:package Azure.AI.Projects.OpenAI@1.0.0-beta.5 +#:package Azure.AI.Agents.Persistent@1.2.0-beta.8 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.AzureAI@1.0.0-rc1 +#:package Microsoft.Agents.AI.AzureAI.Persistent@1.0.0-preview.260219.1 +#:package Microsoft.Agents.AI.Workflows@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +// TODO: Conditional MSFoundry workflow sample - pending full implementation. +// Requires: AZURE_AI_PROJECT_ENDPOINT, AZURE_AI_MODEL_DEPLOYMENT_NAME +Console.WriteLine("Conditional workflow sample - see README.md for setup instructions."); diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj index 6a9c114..f73f659 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/GHModel.dotNET.AI.Workflow.OpenTelemetry.csproj @@ -32,4 +32,8 @@ + + + +
\ No newline at end of file diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/README.md b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/README.md index bbe2723..97c7ab2 100644 --- a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/README.md +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/README.md @@ -34,3 +34,9 @@ dotnet run ``` Open the Aspire dashboard at **http://localhost:18888** to browse traces and metrics generated by the workflow. + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` diff --git a/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/app.cs b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/app.cs new file mode 100644 index 0000000..4933821 --- /dev/null +++ b/09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/app.cs @@ -0,0 +1,241 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId 2c130ad6-5dba-4207-af2a-4db898f9e666 +#:package Azure.AI.OpenAI@2.1.0 +#:package Azure.Identity@1.17.1 +#:package Azure.Monitor.OpenTelemetry.Exporter@1.4.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Microsoft.Extensions.Logging@10.0.0 +#:package Microsoft.Extensions.Logging.Console@10.0.0 +#:package OpenAI@2.8.0 +#:package OpenTelemetry@1.13.1 +#:package OpenTelemetry.Exporter.Console@1.13.1 +#:package OpenTelemetry.Exporter.OpenTelemetryProtocol@1.13.1 +#:package OpenTelemetry.Instrumentation.Http@1.13.0 +#:package OpenTelemetry.Instrumentation.Runtime@1.13.0 +#:package OpenTelemetry.Extensions.Hosting@1.13.1 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Agents.AI.Workflows@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +using System; +using System.ComponentModel; +using System.ClientModel; +using System.Diagnostics; +using System.Diagnostics.Metrics; +using System.Threading; +using Azure.AI.OpenAI; +using Azure.Identity; +using Azure.Monitor.OpenTelemetry.Exporter; +using Microsoft.Agents.AI; +using Microsoft.Agents.AI.Workflows; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using OpenTelemetry; +using OpenTelemetry.Logs; +using OpenTelemetry.Metrics; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; +using OpenAI; +using Microsoft.Extensions.Configuration; + + +#region Setup Telemetry + +const string SourceName = "OpenTelemetryAspire.ConsoleApp"; +const string ServiceName = "WorkflowOpenTelemetry"; + +// Configure OpenTelemetry for Aspire dashboard +var otlpEndpoint = "http://localhost:4317"; + +// Create a resource to identify this service +var resource = ResourceBuilder.CreateDefault() + .AddService(ServiceName, serviceVersion: "1.0.0") + .AddAttributes(new Dictionary + { + ["service.instance.id"] = Environment.MachineName, + ["deployment.environment"] = "development" + }) + .Build(); + +// Setup tracing with resource +var tracerProviderBuilder = Sdk.CreateTracerProviderBuilder() + .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(ServiceName, serviceVersion: "1.0.0")) + .AddSource(SourceName) // Our custom activity source + .AddSource("*Microsoft.Agents.AI") // Agent Framework telemetry + .AddHttpClientInstrumentation() // Capture HTTP calls to OpenAI + .AddOtlpExporter(options => options.Endpoint = new Uri(otlpEndpoint)); + +using var tracerProvider = tracerProviderBuilder.Build(); + +// Setup metrics with resource and instrument name filtering +using var meterProvider = Sdk.CreateMeterProviderBuilder() + .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(ServiceName, serviceVersion: "1.0.0")) + .AddMeter(SourceName) // Our custom meter + .AddMeter("*Microsoft.Agents.AI") // Agent Framework metrics + .AddHttpClientInstrumentation() // HTTP client metrics + .AddRuntimeInstrumentation() // .NET runtime metrics + .AddOtlpExporter(options => options.Endpoint = new Uri(otlpEndpoint)) + .Build(); + +// Setup structured logging with OpenTelemetry +var serviceCollection = new ServiceCollection(); +serviceCollection.AddLogging(loggingBuilder => loggingBuilder + .SetMinimumLevel(LogLevel.Debug) + .AddOpenTelemetry(options => + { + options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(ServiceName, serviceVersion: "1.0.0")); + options.AddOtlpExporter(otlpOptions => otlpOptions.Endpoint = new Uri(otlpEndpoint)); + options.IncludeScopes = true; + options.IncludeFormattedMessage = true; + })); + +using var activitySource = new ActivitySource(SourceName); +using var meter = new Meter(SourceName); + +// Create custom metrics +var interactionCounter = meter.CreateCounter("agent_interactions_total", description: "Total number of agent interactions"); +var responseTimeHistogram = meter.CreateHistogram("agent_response_time_seconds", description: "Agent response time in seconds"); + +#endregion + +var serviceProvider = serviceCollection.BuildServiceProvider(); +var loggerFactory = serviceProvider.GetRequiredService(); +var appLogger = loggerFactory.CreateLogger(); + +Console.WriteLine(""" + === OpenTelemetry Aspire Demo === + This demo shows OpenTelemetry integration with the Agent Framework. + You can view the telemetry data in the Aspire Dashboard. + Type your message and press Enter. Type 'exit' or empty message to quit. + """); + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var github_endpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var github_model_id = config["GITHUB_MODEL_ID"] ?? throw new InvalidOperationException("GITHUB_MODEL_ID is not set."); +var github_token = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +var openAIOptions = new OpenAIClientOptions() +{ + Endpoint = new Uri(github_endpoint) +}; + +var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions); + + + +var chatClient = openAIClient.GetChatClient(github_model_id).AsIChatClient(); + +const string ReviewerAgentName = "Concierge"; +const string ReviewerAgentInstructions = @" + You are an are hotel concierge who has opinions about providing the most local and authentic experiences for travelers. + The goal is to determine if the front desk travel agent has recommended the best non-touristy experience for a traveler. + If so, state that it is approved. + If not, provide insight on how to refine the recommendation without using a specific example. "; + +const string FrontDeskAgentName = "FrontDesk"; +const string FrontDeskAgentInstructions = @""" + You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers. + The goal is to provide the best activities and locations for a traveler to visit. + Only provide a single recommendation per response. + You're laser focused on the goal at hand. + Don't waste time with chit chat. + Consider suggestions when refining an idea. + """; + + + +var reviewerAgentBuilder = new AIAgentBuilder(chatClient.AsAIAgent( + name: ReviewerAgentName, + instructions: ReviewerAgentInstructions)) + .UseOpenTelemetry(SourceName, configure: cfg => cfg.EnableSensitiveData = true); + +var frontDeskAgentBuilder = new AIAgentBuilder(chatClient.AsAIAgent( + name: FrontDeskAgentName, + instructions: FrontDeskAgentInstructions)) + .UseOpenTelemetry(SourceName, configure: cfg => cfg.EnableSensitiveData = true); + +AIAgent reviewerAgent = reviewerAgentBuilder.Build(serviceProvider); +AIAgent frontDeskAgent = frontDeskAgentBuilder.Build(serviceProvider); + +var workflow = new WorkflowBuilder(frontDeskAgent) + .AddEdge(frontDeskAgent, reviewerAgent) + .Build(); + + +var workflowAgentBuilder = new AIAgentBuilder(workflow.AsAIAgent(id: "travel-workflow", name: "travel-workflow", description: "travel recommendation workflow")) + .UseOpenTelemetry(SourceName, configure: cfg => cfg.EnableSensitiveData = true); + +AIAgent workflow_agent = workflowAgentBuilder.Build(serviceProvider); + +AgentSession session = await workflow_agent.CreateSessionAsync(); + +Console.WriteLine("\n💡 Before starting, run the VS Code command 'AI Toolkit: Open Trace Viewer (ai-mlstudio.tracing.open)' to capture traces in the AI Toolkit collector.\n"); + +while (true) +{ + Console.Write("Traveler: "); + var userInput = Console.ReadLine(); + + if (string.IsNullOrWhiteSpace(userInput) || string.Equals(userInput, "exit", StringComparison.OrdinalIgnoreCase)) + { + appLogger.LogInformation("Conversation ended by user request."); + break; + } + + interactionCounter.Add(1); + + using var interactionActivity = activitySource.StartActivity("workflow.interaction", ActivityKind.Client); + + interactionActivity?.SetTag("workflow.agent.id", workflow_agent.Id); + interactionActivity?.SetTag("workflow.agent.name", workflow_agent.Name); + interactionActivity?.SetTag("prompt.length", userInput.Length); + + var stopwatch = Stopwatch.StartNew(); + + try + { + var response = await workflow_agent.RunAsync( + new[] { new ChatMessage(ChatRole.User, userInput) }, + session, + cancellationToken: CancellationToken.None); + + stopwatch.Stop(); + + var elapsedSeconds = stopwatch.Elapsed.TotalSeconds; + responseTimeHistogram.Record(elapsedSeconds); + + interactionActivity?.SetTag("response.elapsed.seconds", elapsedSeconds); + interactionActivity?.SetTag("response.message.count", response.Messages.Count); + + var text = response.Text; + interactionActivity?.SetTag("response.length", text.Length); + interactionActivity?.SetStatus(ActivityStatusCode.Ok); + + Console.WriteLine($"\nWorkflow: {text}"); + } + catch (Exception ex) + { + stopwatch.Stop(); + var elapsedSeconds = stopwatch.Elapsed.TotalSeconds; + responseTimeHistogram.Record(elapsedSeconds); + + interactionActivity?.SetStatus(ActivityStatusCode.Error, ex.Message); + interactionActivity?.AddEvent(new ActivityEvent( + "exception", + tags: new ActivityTagsCollection + { + { "exception.type", ex.GetType().FullName ?? string.Empty }, + { "exception.message", ex.Message } + })); + + appLogger.LogError(ex, "Workflow interaction failed."); + Console.WriteLine("⚠️ Workflow interaction failed. Check logs for details."); + } +} diff --git a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj index 990604c..a9af593 100644 --- a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj +++ b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/CreateWorkflowWithYAML.csproj @@ -30,4 +30,8 @@ + + + +
diff --git a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/README.md b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/README.md index fef4615..bed7e97 100644 --- a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/README.md +++ b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/README.md @@ -31,3 +31,11 @@ The default YAML files (`workflow.yaml`, `apply_agent.yaml`, `hiring_manager_age ```bash dotnet run ``` + +## Run with file-based approach (.NET 10) + +```bash +dotnet run app.cs +``` + +> **Note:** YAML workflow files are expected at `../YAML/workflow.yaml` relative to the `CreateWorkflowWithYAML/` directory. Run the command from that directory, or override with `dotnet user-secrets set "WORKFLOW_YAML_PATH" ""`. \ No newline at end of file diff --git a/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/app.cs b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/app.cs new file mode 100644 index 0000000..f15d00b --- /dev/null +++ b/09.Cases/MicrosoftFoundryWithAITKAndMAF/CreateWorkflowWithYAML/app.cs @@ -0,0 +1,446 @@ +// File-based run: dotnet run app.cs +// Run from the CreateWorkflowWithYAML/ directory: dotnet run app.cs +#:property UserSecretsId 9be133a2-f120-490b-bf73-6cfa7a742fce +#:package Microsoft.Agents.AI.Workflows@1.0.0-rc1 +#:package Microsoft.Agents.AI.Workflows.Declarative@1.0.0-rc1 +#:package Microsoft.Agents.AI.Workflows.Declarative.AzureAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration@10.0.0 +#:package Microsoft.Extensions.Configuration.Binder@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 +#:package Microsoft.Extensions.Configuration.Json@10.0.0 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.DependencyInjection@10.0.0 +#:package Microsoft.Extensions.Logging@10.0.0 +#:package System.ClientModel@1.8.1 +#:package System.Collections.Immutable@10.0.0 +#:package Azure.Identity@1.17.1 + +// Types are for evaluation purposes only and is subject to change or removal in future updates. +#pragma warning disable OPENAI001 +#pragma warning disable OPENAICUA001 +#pragma warning disable MEAI001 + +using Azure.Identity; +using Microsoft.Agents.AI.Workflows; +using Microsoft.Agents.AI.Workflows.Checkpointing; +using Microsoft.Agents.AI.Workflows.Declarative; +using Microsoft.Agents.AI.Workflows.Declarative.Events; +using Microsoft.Agents.AI.Workflows.Declarative.Kit; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using OpenAI.Responses; +using System.Diagnostics; +using System.Text.Json; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +Uri foundryEndpoint = new(config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set. Run: dotnet user-secrets set \"AZURE_AI_PROJECT_ENDPOINT\" \"\"")); +// For file-based run, YAML files are at ../YAML/ relative to CreateWorkflowWithYAML/ +string yamlPath = config["WORKFLOW_YAML_PATH"] ?? "../YAML/workflow.yaml"; + +WorkflowFactory workflowFactory = new(yamlPath, foundryEndpoint); +WorkflowRunner runner = new(); +await runner.ExecuteAsync(workflowFactory.CreateWorkflow, "junior developer"); + +// WorkflowFactory inlined from WorkflowFactory.cs + +internal sealed class WorkflowFactory(string workflowFile, Uri foundryEndpoint) +{ + public IList Functions { get; init; } = []; + + public IConfiguration? Configuration { get; init; } + + // Assign to continue an existing conversation + public string? ConversationId { get; init; } + + // Assign to enable logging + public ILoggerFactory LoggerFactory { get; init; } = NullLoggerFactory.Instance; + + /// + /// Create the workflow from the declarative YAML. Includes definition of the + /// and the associated . + /// + public Workflow CreateWorkflow() + { + // Create the agent provider that will service agent requests within the workflow. + AzureAgentProvider agentProvider = new(foundryEndpoint, new AzureCliCredential()) + { + // Functions included here will be auto-executed by the framework. + Functions = this.Functions + }; + + // Define the workflow options. + DeclarativeWorkflowOptions options = + new(agentProvider) + { + Configuration = this.Configuration, + ConversationId = this.ConversationId, + LoggerFactory = this.LoggerFactory, + }; + + // Use Directory.GetCurrentDirectory() so file-based run resolves paths from CWD + string workflowPath = Path.Combine(Directory.GetCurrentDirectory(), workflowFile); + + // Use DeclarativeWorkflowBuilder to build a workflow based on a YAML file. + return DeclarativeWorkflowBuilder.Build(workflowPath, options); + } +} + +// WorkflowRunner inlined from WorkflowRunner.cs + +internal sealed class WorkflowRunner +{ + private Dictionary FunctionMap { get; } + private CheckpointInfo? LastCheckpoint { get; set; } + + public static void Notify(string message, ConsoleColor? color = null) + { + Console.ForegroundColor = color ?? ConsoleColor.Cyan; + try + { + Console.WriteLine(message); + } + finally + { + Console.ResetColor(); + } + } + + /// + /// When enabled, checkpoints will be persisted to disk as JSON files. + /// Otherwise an in-memory checkpoint store that will not persist checkpoints + /// beyond the lifetime of the process. + /// + public bool UseJsonCheckpoints { get; init; } + + public WorkflowRunner(params IEnumerable functions) + { + this.FunctionMap = functions.ToDictionary(f => f.Name); + } + + public async Task ExecuteAsync(Func workflowProvider, string input) + { + Workflow workflow = workflowProvider.Invoke(); + + CheckpointManager checkpointManager; + + if (this.UseJsonCheckpoints) + { + // Use a file-system based JSON checkpoint store to persist checkpoints to disk. + DirectoryInfo checkpointFolder = Directory.CreateDirectory(Path.Combine(".", $"chk-{DateTime.Now:yyMMdd-hhmmss-ff}")); + checkpointManager = CheckpointManager.CreateJson(new FileSystemJsonCheckpointStore(checkpointFolder)); + } + else + { + // Use an in-memory checkpoint store that will not persist checkpoints beyond the lifetime of the process. + checkpointManager = CheckpointManager.CreateInMemory(); + } + + StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input, checkpointManager).ConfigureAwait(false); + + bool isComplete = false; + ExternalResponse? requestResponse = null; + do + { + ExternalRequest? externalRequest = await this.MonitorAndDisposeWorkflowRunAsync(run, requestResponse).ConfigureAwait(false); + if (externalRequest is not null) + { + Notify("\nWORKFLOW: Yield\n", ConsoleColor.DarkYellow); + + if (this.LastCheckpoint is null) + { + throw new InvalidOperationException("Checkpoint information missing after external request."); + } + + // Process the external request. + object response = await this.HandleExternalRequestAsync(externalRequest).ConfigureAwait(false); + requestResponse = externalRequest.CreateResponse(response); + + // Let's resume on an entirely new workflow instance to demonstrate checkpoint portability. + workflow = workflowProvider.Invoke(); + + // Restore the latest checkpoint. + Debug.WriteLine($"RESTORE #{this.LastCheckpoint.CheckpointId}"); + Notify("WORKFLOW: Restore", ConsoleColor.DarkYellow); + + run = await InProcessExecution.ResumeStreamingAsync(workflow, this.LastCheckpoint!, checkpointManager).ConfigureAwait(false); + } + else + { + isComplete = true; + } + } + while (!isComplete); + + Notify("\nWORKFLOW: Done!\n"); + } + + public async Task MonitorAndDisposeWorkflowRunAsync(StreamingRun run, ExternalResponse? response = null) + { +#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task + await using IAsyncDisposable disposeRun = run; +#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task + + bool hasStreamed = false; + string? messageId = null; + + bool shouldExit = false; + ExternalRequest? externalResponse = null; + + if (response is not null) + { + await run.SendResponseAsync(response).ConfigureAwait(false); + } + + await foreach (WorkflowEvent workflowEvent in run.WatchStreamAsync().ConfigureAwait(false)) + { + switch (workflowEvent) + { + case ExecutorInvokedEvent executorInvoked: + Debug.WriteLine($"EXECUTOR ENTER #{executorInvoked.ExecutorId}"); + break; + + case ExecutorCompletedEvent executorCompleted: + Debug.WriteLine($"EXECUTOR EXIT #{executorCompleted.ExecutorId}"); + break; + + case DeclarativeActionInvokedEvent actionInvoked: + Debug.WriteLine($"ACTION ENTER #{actionInvoked.ActionId} [{actionInvoked.ActionType}]"); + break; + + case DeclarativeActionCompletedEvent actionComplete: + Debug.WriteLine($"ACTION EXIT #{actionComplete.ActionId} [{actionComplete.ActionType}]"); + break; + + case ExecutorFailedEvent executorFailure: + Debug.WriteLine($"STEP ERROR #{executorFailure.ExecutorId}: {executorFailure.Data?.Message ?? "Unknown"}"); + break; + + case WorkflowErrorEvent workflowError: + throw workflowError.Data as Exception ?? new InvalidOperationException("Unexpected failure..."); + + case SuperStepCompletedEvent checkpointCompleted: + this.LastCheckpoint = checkpointCompleted.CompletionInfo?.Checkpoint; + Debug.WriteLine($"CHECKPOINT x{checkpointCompleted.StepNumber} [{this.LastCheckpoint?.CheckpointId ?? "(none)"}]"); + if (externalResponse is not null) + { + shouldExit = true; + } + break; + + case RequestInfoEvent requestInfo: + Debug.WriteLine($"REQUEST #{requestInfo.Request.RequestId}"); + externalResponse = requestInfo.Request; + break; + + case ConversationUpdateEvent invokeEvent: + Debug.WriteLine($"CONVERSATION: {invokeEvent.Data}"); + break; + + case MessageActivityEvent activityEvent: + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("\nACTIVITY:"); + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(activityEvent.Message.Trim()); + break; + + case AgentResponseUpdateEvent streamEvent: + if (!string.Equals(messageId, streamEvent.Update.MessageId, StringComparison.Ordinal)) + { + hasStreamed = false; + messageId = streamEvent.Update.MessageId; + + if (messageId is not null) + { + string? agentName = streamEvent.Update.AuthorName ?? streamEvent.Update.AgentId ?? nameof(ChatRole.Assistant); + Console.ForegroundColor = ConsoleColor.Cyan; + Console.Write($"\n{agentName.ToUpperInvariant()}:"); + Console.ForegroundColor = ConsoleColor.DarkGray; + Console.WriteLine($" [{messageId}]"); + } + } + + ChatResponseUpdate? chatUpdate = streamEvent.Update.RawRepresentation as ChatResponseUpdate; + switch (chatUpdate?.RawRepresentation) + { + case ImageGenerationCallResponseItem messageUpdate: + await DownloadFileContentAsync(Path.GetFileName("response.png"), messageUpdate.ImageResultBytes).ConfigureAwait(false); + break; + + case FunctionCallResponseItem actionUpdate: + Console.ForegroundColor = ConsoleColor.White; + Console.Write($"Calling tool: {actionUpdate.FunctionName}"); + Console.ForegroundColor = ConsoleColor.DarkGray; + Console.WriteLine($" [{actionUpdate.CallId}]"); + break; + + case McpToolCallItem actionUpdate: + Console.ForegroundColor = ConsoleColor.White; + Console.Write($"Calling tool: {actionUpdate.ToolName}"); + Console.ForegroundColor = ConsoleColor.DarkGray; + Console.WriteLine($" [{actionUpdate.Id}]"); + break; + } + + try + { + Console.ResetColor(); + Console.Write(streamEvent.Update.Text); + hasStreamed |= !string.IsNullOrEmpty(streamEvent.Update.Text); + } + finally + { + Console.ResetColor(); + } + break; + + case AgentResponseEvent messageEvent: + try + { + if (hasStreamed) + { + Console.WriteLine(); + } + + 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(); + } + break; + + default: + break; + } + + if (shouldExit) + { + break; + } + } + + return externalResponse; + } + + /// + /// Handle request for external input. + /// + private async ValueTask HandleExternalRequestAsync(ExternalRequest request) + { + if (!request.TryGetDataAs(out var inputRequest)) + { + throw new InvalidOperationException($"Expected external request type: {request.PortInfo.RequestType}."); + } + + List responseMessages = []; + + foreach (ChatMessage message in inputRequest.AgentResponse.Messages) + { + await foreach (ChatMessage responseMessage in this.ProcessInputMessageAsync(message).ConfigureAwait(false)) + { + responseMessages.Add(responseMessage); + } + } + + if (responseMessages.Count == 0) + { + // Must be request for user input. + responseMessages.Add(HandleUserInputRequest(inputRequest)); + } + + Console.WriteLine(); + + return new ExternalInputResponse(responseMessages); + } + + private async IAsyncEnumerable ProcessInputMessageAsync(ChatMessage message) + { + foreach (AIContent requestItem in message.Contents) + { + ChatMessage? responseMessage = + requestItem switch + { + FunctionCallContent functionCall => await InvokeFunctionAsync(functionCall).ConfigureAwait(false), + FunctionApprovalRequestContent functionApprovalRequest => ApproveFunction(functionApprovalRequest), + McpServerToolApprovalRequestContent mcpApprovalRequest => ApproveMCP(mcpApprovalRequest), + _ => HandleUnknown(requestItem), + }; + + if (responseMessage is not null) + { + yield return responseMessage; + } + } + + ChatMessage? HandleUnknown(AIContent request) + { + return null; + } + + ChatMessage ApproveFunction(FunctionApprovalRequestContent functionApprovalRequest) + { + Notify($"INPUT - Approving Function: {functionApprovalRequest.FunctionCall.Name}"); + return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved: true)]); + } + + ChatMessage ApproveMCP(McpServerToolApprovalRequestContent mcpApprovalRequest) + { + Notify($"INPUT - Approving MCP: {mcpApprovalRequest.ToolCall.ToolName}"); + return new ChatMessage(ChatRole.User, [mcpApprovalRequest.CreateResponse(approved: true)]); + } + + async Task InvokeFunctionAsync(FunctionCallContent functionCall) + { + Notify($"INPUT - Executing Function: {functionCall.Name}"); + AIFunction functionTool = this.FunctionMap[functionCall.Name]; + AIFunctionArguments? functionArguments = functionCall.Arguments is null ? null : new(functionCall.Arguments.NormalizePortableValues()); + object? result = await functionTool.InvokeAsync(functionArguments).ConfigureAwait(false); + return new ChatMessage(ChatRole.Tool, [new FunctionResultContent(functionCall.CallId, JsonSerializer.Serialize(result))]); + } + } + + private static ChatMessage HandleUserInputRequest(ExternalInputRequest request) + { + string prompt = + string.IsNullOrWhiteSpace(request.AgentResponse.Text) || request.AgentResponse.ResponseId is not null ? + "INPUT:" : + request.AgentResponse.Text; + + string? userInput; + do + { + Console.ForegroundColor = ConsoleColor.DarkGreen; + Console.Write($"{prompt} "); + Console.ForegroundColor = ConsoleColor.White; + userInput = Console.ReadLine(); + } + while (string.IsNullOrWhiteSpace(userInput)); + + return new ChatMessage(ChatRole.User, userInput); + } + + 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()).ConfigureAwait(false); + + Process.Start( + new ProcessStartInfo + { + FileName = "cmd.exe", + Arguments = $"/C start {filePath}" + }); + } +} From 3bed370898ed15113bfc3373e7471e55dea30026 Mon Sep 17 00:00:00 2001 From: Bruno Capuano Date: Sat, 21 Feb 2026 15:22:32 -0500 Subject: [PATCH 07/10] merge duplicated content --- .../Program.cs | 71 ------------ .../README.md | 32 ------ .../dotnet-agent-framework-travelagent/app.cs | 81 ------------- .../dotnet-agent-framework-travelagent.csproj | 30 ----- .../Program.cs | 70 ------------ .../README.md | 32 ------ .../dotnet-agent-framework-basicagent/app.cs | 80 ------------- .../dotnet-agent-framework-basicagent.csproj | 30 ----- .../Program.cs | 70 ------------ .../README.md | 32 ------ .../dotnet-agent-framework-basicagent/app.cs | 80 ------------- .../dotnet-agent-framework-basicagent.csproj | 30 ----- .../Program.cs | 92 --------------- .../README.md | 32 ------ .../app.cs | 108 ------------------ ...ework-ghmodel-workflow-multi-agents.csproj | 35 ------ 00.ForBeginners/README.md | 12 +- 17 files changed, 6 insertions(+), 911 deletions(-) delete mode 100644 00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs delete mode 100644 00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md delete mode 100644 00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/app.cs delete mode 100644 00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj delete mode 100644 00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs delete mode 100644 00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md delete mode 100644 00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/app.cs delete mode 100644 00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj delete mode 100644 00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs delete mode 100644 00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md delete mode 100644 00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/app.cs delete mode 100644 00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj delete mode 100644 00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs delete mode 100644 00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md delete mode 100644 00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/app.cs delete mode 100644 00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs deleted file mode 100644 index 67b382f..0000000 --- a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/Program.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.ComponentModel; -using System.ClientModel; -using Microsoft.Extensions.AI; -using Microsoft.Agents.AI; -using OpenAI; -using Microsoft.Extensions.Configuration; - -// Load environment variables from .env file - -var config = new ConfigurationBuilder() - .AddUserSecrets() - .AddEnvironmentVariables() - .Build(); - -var github_endpoint = config["GITHUB_ENDPOINT"] - ?? throw new InvalidOperationException("GITHUB_ENDPOINT is required"); -var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; -var github_token = config["GITHUB_TOKEN"] - ?? throw new InvalidOperationException("GITHUB_TOKEN is required"); - -// Configure OpenAI client for GitHub Models -var openAIOptions = new OpenAIClientOptions() -{ - Endpoint = new Uri(github_endpoint) -}; - -// Create AI Agent with custom tool -AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) - .GetChatClient(github_model_id) - .AsIChatClient() - .AsAIAgent( - name: "TravelAgent", - instructions: "You are a helpful AI Agent that can help plan vacations for customers at random destinations.", - tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] - ); - -// Run agent with standard response -Console.WriteLine("=== Travel Plan ==="); -Console.WriteLine(await agent.RunAsync("Plan me a day trip")); - -// Run agent with streaming response -Console.WriteLine("\n=== Streaming Travel Plan ==="); -await foreach (var update in agent.RunStreamingAsync("Plan me a day trip")) -{ - Console.Write(update); -} -Console.WriteLine(); - -// Agent Tool: Random Destination Generator -[Description("Provides a random vacation destination.")] -static string GetRandomDestination() -{ - var destinations = new List - { - "Paris, France", - "Tokyo, Japan", - "New York City, USA", - "Sydney, Australia", - "Rome, Italy", - "Barcelona, Spain", - "Cape Town, South Africa", - "Rio de Janeiro, Brazil", - "Bangkok, Thailand", - "Vancouver, Canada" - }; - - var random = new Random(); - int index = random.Next(destinations.Count); - return destinations[index]; -} diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md deleted file mode 100644 index 5ebd2a8..0000000 --- a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Travel Agent — Intro to AI Agents (.NET) - -Introduces the `AIAgent` abstraction by building a travel-planning agent with a custom tool that returns random destination suggestions. Demonstrates both a standard (awaited) response and a streaming response. - -## What it shows -- Creating an `AIAgent` from an `OpenAI` chat client targeting **GitHub Models** -- Registering a C# method as an agent tool with `AIFunctionFactory.Create` -- Calling `RunAsync` for a single response and `RunStreamingAsync` for token-by-token streaming - -## Prerequisites -- [.NET 10 SDK](https://dot.net) -- A [GitHub Models](https://github.com/marketplace/models) personal access token - -## Configure secrets - -```bash -dotnet user-secrets set "GITHUB_TOKEN" "" -dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" -dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" -``` - -## Run - -```bash -dotnet run -``` - -## Run with file-based approach (.NET 10) - -```bash -dotnet run app.cs -``` diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/app.cs b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/app.cs deleted file mode 100644 index d830aa8..0000000 --- a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/app.cs +++ /dev/null @@ -1,81 +0,0 @@ -// File-based run: dotnet run app.cs -#:property UserSecretsId e01f82ab-60d0-4d0e-82b0-476cd48c55b3 -#:package Microsoft.Extensions.AI@10.3.0 -#:package Microsoft.Extensions.AI.OpenAI@10.3.0 -#:package OpenAI@2.8.0 -#:package Microsoft.Agents.AI@1.0.0-rc1 -#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 -#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 -#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 - -using System; -using System.ComponentModel; -using System.ClientModel; -using Microsoft.Extensions.AI; -using Microsoft.Agents.AI; -using OpenAI; -using Microsoft.Extensions.Configuration; - -// Load environment variables from .env file - -var config = new ConfigurationBuilder() - .AddUserSecrets() - .AddEnvironmentVariables() - .Build(); - -var github_endpoint = config["GITHUB_ENDPOINT"] - ?? throw new InvalidOperationException("GITHUB_ENDPOINT is required"); -var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; -var github_token = config["GITHUB_TOKEN"] - ?? throw new InvalidOperationException("GITHUB_TOKEN is required"); - -// Configure OpenAI client for GitHub Models -var openAIOptions = new OpenAIClientOptions() -{ - Endpoint = new Uri(github_endpoint) -}; - -// Create AI Agent with custom tool -AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) - .GetChatClient(github_model_id) - .AsIChatClient() - .AsAIAgent( - name: "TravelAgent", - instructions: "You are a helpful AI Agent that can help plan vacations for customers at random destinations.", - tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] - ); - -// Run agent with standard response -Console.WriteLine("=== Travel Plan ==="); -Console.WriteLine(await agent.RunAsync("Plan me a day trip")); - -// Run agent with streaming response -Console.WriteLine("\n=== Streaming Travel Plan ==="); -await foreach (var update in agent.RunStreamingAsync("Plan me a day trip")) -{ - Console.Write(update); -} -Console.WriteLine(); - -// Agent Tool: Random Destination Generator -[Description("Provides a random vacation destination.")] -static string GetRandomDestination() -{ - var destinations = new List - { - "Paris, France", - "Tokyo, Japan", - "New York City, USA", - "Sydney, Australia", - "Rome, Italy", - "Barcelona, Spain", - "Cape Town, South Africa", - "Rio de Janeiro, Brazil", - "Bangkok, Thailand", - "Vancouver, Canada" - }; - - var random = new Random(); - int index = random.Next(destinations.Count); - return destinations[index]; -} diff --git a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj b/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj deleted file mode 100644 index b2657c1..0000000 --- a/00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/dotnet-agent-framework-travelagent.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - Exe - net10.0 - dotnet_agent_framework_travelagent - enable - enable - e01f82ab-60d0-4d0e-82b0-476cd48c55b3 - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs deleted file mode 100644 index 9f94f51..0000000 --- a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/Program.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.ComponentModel; -using System.ClientModel; -using Microsoft.Extensions.AI; -using Microsoft.Agents.AI; -using OpenAI; -using Microsoft.Extensions.Configuration; - -// Load environment variables from .env file - -var config = new ConfigurationBuilder() - .AddUserSecrets() - .AddEnvironmentVariables() - .Build(); - -var github_endpoint = config["GITHUB_ENDPOINT"] - ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; -var github_token = config["GITHUB_TOKEN"] - ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); - -// Configure OpenAI client for GitHub Models -var openAIOptions = new OpenAIClientOptions() -{ - Endpoint = new Uri(github_endpoint) -}; - -// Agent Tool: Random Destination Generator -[Description("Provides a random vacation destination.")] -static string GetRandomDestination() -{ - var destinations = new List - { - "Paris, France", - "Tokyo, Japan", - "New York City, USA", - "Sydney, Australia", - "Rome, Italy", - "Barcelona, Spain", - "Cape Town, South Africa", - "Rio de Janeiro, Brazil", - "Bangkok, Thailand", - "Vancouver, Canada" - }; - var random = new Random(); - int index = random.Next(destinations.Count); - return destinations[index]; -} - -// Create AI Agent with basic instructions and tool -AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) - .GetChatClient(github_model_id) - .AsIChatClient() - .AsAIAgent( - name: "BasicAgent", - instructions: "You are a basic AI Agent that can answer questions and suggest random travel destinations.", - tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] - ); - -// Run agent with standard response -Console.WriteLine("=== Basic Agent Response ==="); -Console.WriteLine(await agent.RunAsync("Suggest a vacation destination.")); - -// Run agent with streaming response -Console.WriteLine("\n=== Streaming Response ==="); -await foreach (var update in agent.RunStreamingAsync("Suggest a vacation destination.")) -{ - Console.Write(update); -} -Console.WriteLine(); diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md deleted file mode 100644 index 0d1dbf3..0000000 --- a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Basic Agent — Exploring Agentic Frameworks (.NET) - -Demonstrates how an agentic framework wraps a chat client to produce an autonomous agent. A destination-suggestion tool is attached to the agent and invoked automatically during the conversation. - -## What it shows -- Constructing an `AIAgent` with a name, instructions, and a tool -- How the Agent Framework handles the tool-calling loop transparently -- Side-by-side standard and streaming responses - -## Prerequisites -- [.NET 10 SDK](https://dot.net) -- A [GitHub Models](https://github.com/marketplace/models) personal access token - -## Configure secrets - -```bash -dotnet user-secrets set "GITHUB_TOKEN" "" -dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" -dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" -``` - -## Run - -```bash -dotnet run -``` - -## Run with file-based approach (.NET 10) - -```bash -dotnet run app.cs -``` diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/app.cs b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/app.cs deleted file mode 100644 index 0c566e9..0000000 --- a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/app.cs +++ /dev/null @@ -1,80 +0,0 @@ -// File-based run: dotnet run app.cs -#:property UserSecretsId 03318c00-adb1-4220-a32a-7b0068e30fff -#:package Microsoft.Extensions.AI@10.3.0 -#:package Microsoft.Extensions.AI.OpenAI@10.3.0 -#:package OpenAI@2.8.0 -#:package Microsoft.Agents.AI@1.0.0-rc1 -#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 -#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 -#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 - -using System; -using System.ComponentModel; -using System.ClientModel; -using Microsoft.Extensions.AI; -using Microsoft.Agents.AI; -using OpenAI; -using Microsoft.Extensions.Configuration; - -// Load environment variables from .env file - -var config = new ConfigurationBuilder() - .AddUserSecrets() - .AddEnvironmentVariables() - .Build(); - -var github_endpoint = config["GITHUB_ENDPOINT"] - ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; -var github_token = config["GITHUB_TOKEN"] - ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); - -// Configure OpenAI client for GitHub Models -var openAIOptions = new OpenAIClientOptions() -{ - Endpoint = new Uri(github_endpoint) -}; - -// Agent Tool: Random Destination Generator -[Description("Provides a random vacation destination.")] -static string GetRandomDestination() -{ - var destinations = new List - { - "Paris, France", - "Tokyo, Japan", - "New York City, USA", - "Sydney, Australia", - "Rome, Italy", - "Barcelona, Spain", - "Cape Town, South Africa", - "Rio de Janeiro, Brazil", - "Bangkok, Thailand", - "Vancouver, Canada" - }; - var random = new Random(); - int index = random.Next(destinations.Count); - return destinations[index]; -} - -// Create AI Agent with basic instructions and tool -AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) - .GetChatClient(github_model_id) - .AsIChatClient() - .AsAIAgent( - name: "BasicAgent", - instructions: "You are a basic AI Agent that can answer questions and suggest random travel destinations.", - tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] - ); - -// Run agent with standard response -Console.WriteLine("=== Basic Agent Response ==="); -Console.WriteLine(await agent.RunAsync("Suggest a vacation destination.")); - -// Run agent with streaming response -Console.WriteLine("\n=== Streaming Response ==="); -await foreach (var update in agent.RunStreamingAsync("Suggest a vacation destination.")) -{ - Console.Write(update); -} -Console.WriteLine(); diff --git a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj b/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj deleted file mode 100644 index ab705d2..0000000 --- a/00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - Exe - net10.0 - dotnet_agent_framework_basicagent - enable - enable - 03318c00-adb1-4220-a32a-7b0068e30fff - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs deleted file mode 100644 index 9f94f51..0000000 --- a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/Program.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.ComponentModel; -using System.ClientModel; -using Microsoft.Extensions.AI; -using Microsoft.Agents.AI; -using OpenAI; -using Microsoft.Extensions.Configuration; - -// Load environment variables from .env file - -var config = new ConfigurationBuilder() - .AddUserSecrets() - .AddEnvironmentVariables() - .Build(); - -var github_endpoint = config["GITHUB_ENDPOINT"] - ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; -var github_token = config["GITHUB_TOKEN"] - ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); - -// Configure OpenAI client for GitHub Models -var openAIOptions = new OpenAIClientOptions() -{ - Endpoint = new Uri(github_endpoint) -}; - -// Agent Tool: Random Destination Generator -[Description("Provides a random vacation destination.")] -static string GetRandomDestination() -{ - var destinations = new List - { - "Paris, France", - "Tokyo, Japan", - "New York City, USA", - "Sydney, Australia", - "Rome, Italy", - "Barcelona, Spain", - "Cape Town, South Africa", - "Rio de Janeiro, Brazil", - "Bangkok, Thailand", - "Vancouver, Canada" - }; - var random = new Random(); - int index = random.Next(destinations.Count); - return destinations[index]; -} - -// Create AI Agent with basic instructions and tool -AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) - .GetChatClient(github_model_id) - .AsIChatClient() - .AsAIAgent( - name: "BasicAgent", - instructions: "You are a basic AI Agent that can answer questions and suggest random travel destinations.", - tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] - ); - -// Run agent with standard response -Console.WriteLine("=== Basic Agent Response ==="); -Console.WriteLine(await agent.RunAsync("Suggest a vacation destination.")); - -// Run agent with streaming response -Console.WriteLine("\n=== Streaming Response ==="); -await foreach (var update in agent.RunStreamingAsync("Suggest a vacation destination.")) -{ - Console.Write(update); -} -Console.WriteLine(); diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md deleted file mode 100644 index d691c23..0000000 --- a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Basic Agent — Agentic Design Patterns (.NET) - -Illustrates common agentic design patterns: giving an agent a specific role through system instructions and equipping it with a domain-specific tool. The same agent is invoked two ways to compare response styles. - -## What it shows -- Role-based agent instructions (system prompt) -- Tool attachment and automatic tool-call dispatch -- Standard vs. streaming response patterns - -## Prerequisites -- [.NET 10 SDK](https://dot.net) -- A [GitHub Models](https://github.com/marketplace/models) personal access token - -## Configure secrets - -```bash -dotnet user-secrets set "GITHUB_TOKEN" "" -dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" -dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" -``` - -## Run - -```bash -dotnet run -``` - -## Run with file-based approach (.NET 10) - -```bash -dotnet run app.cs -``` diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/app.cs b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/app.cs deleted file mode 100644 index 214e45b..0000000 --- a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/app.cs +++ /dev/null @@ -1,80 +0,0 @@ -// File-based run: dotnet run app.cs -#:property UserSecretsId 328e4b11-22e2-4b5d-8e08-2f4e47079175 -#:package Microsoft.Extensions.AI@10.3.0 -#:package Microsoft.Extensions.AI.OpenAI@10.3.0 -#:package OpenAI@2.8.0 -#:package Microsoft.Agents.AI@1.0.0-rc1 -#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 -#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 -#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 - -using System; -using System.ComponentModel; -using System.ClientModel; -using Microsoft.Extensions.AI; -using Microsoft.Agents.AI; -using OpenAI; -using Microsoft.Extensions.Configuration; - -// Load environment variables from .env file - -var config = new ConfigurationBuilder() - .AddUserSecrets() - .AddEnvironmentVariables() - .Build(); - -var github_endpoint = config["GITHUB_ENDPOINT"] - ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; -var github_token = config["GITHUB_TOKEN"] - ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); - -// Configure OpenAI client for GitHub Models -var openAIOptions = new OpenAIClientOptions() -{ - Endpoint = new Uri(github_endpoint) -}; - -// Agent Tool: Random Destination Generator -[Description("Provides a random vacation destination.")] -static string GetRandomDestination() -{ - var destinations = new List - { - "Paris, France", - "Tokyo, Japan", - "New York City, USA", - "Sydney, Australia", - "Rome, Italy", - "Barcelona, Spain", - "Cape Town, South Africa", - "Rio de Janeiro, Brazil", - "Bangkok, Thailand", - "Vancouver, Canada" - }; - var random = new Random(); - int index = random.Next(destinations.Count); - return destinations[index]; -} - -// Create AI Agent with basic instructions and tool -AIAgent agent = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions) - .GetChatClient(github_model_id) - .AsIChatClient() - .AsAIAgent( - name: "BasicAgent", - instructions: "You are a basic AI Agent that can answer questions and suggest random travel destinations.", - tools: [AIFunctionFactory.Create((Func)GetRandomDestination)] - ); - -// Run agent with standard response -Console.WriteLine("=== Basic Agent Response ==="); -Console.WriteLine(await agent.RunAsync("Suggest a vacation destination.")); - -// Run agent with streaming response -Console.WriteLine("\n=== Streaming Response ==="); -await foreach (var update in agent.RunStreamingAsync("Suggest a vacation destination.")) -{ - Console.Write(update); -} -Console.WriteLine(); diff --git a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj b/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj deleted file mode 100644 index aa07e1b..0000000 --- a/00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/dotnet-agent-framework-basicagent.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - Exe - net10.0 - dotnet_agent_framework_basicagent - enable - enable - 328e4b11-22e2-4b5d-8e08-2f4e47079175 - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs deleted file mode 100644 index de204fd..0000000 --- a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/Program.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.ClientModel; -using System.Text.Json; -using System.Text.Json.Serialization; -using Microsoft.Extensions.AI; -using Microsoft.Agents.AI; -using Microsoft.Agents.AI.Workflows; -using OpenAI; -using Microsoft.Extensions.Configuration; - -// Load environment variables from .env file - -var config = new ConfigurationBuilder() - .AddUserSecrets() - .AddEnvironmentVariables() - .Build(); - -var github_endpoint = config["GITHUB_ENDPOINT"] - ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; -var github_token = config["GITHUB_TOKEN"] - ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); - -// Configure OpenAI client for GitHub Models -var openAIOptions = new OpenAIClientOptions() -{ - Endpoint = new Uri(github_endpoint) -}; -var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions); - -// Define Concierge Agent (Quality Reviewer) -const string REVIEWER_NAME = "Concierge"; -const string REVIEWER_INSTRUCTIONS = @""" - You are an are hotel concierge who has opinions about providing the most local and authentic experiences for travelers. - The goal is to determine if the front desk travel agent has recommended the best non-touristy experience for a traveler. - If so, state that it is approved. - If not, provide insight on how to refine the recommendation without using a specific example. - """; - -// Define Front Desk Agent (Travel Specialist) -const string FRONTDESK_NAME = "FrontDesk"; -const string FRONTDESK_INSTRUCTIONS = @""" - You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers. - The goal is to provide the best activities and locations for a traveler to visit. - Only provide a single recommendation per response. - You're laser focused on the goal at hand. - Don't waste time with chit chat. - Consider suggestions when refining an idea. - """; - -// Configure agent options -ChatClientAgentOptions frontdeskAgentOptions = new() -{ - Name = FRONTDESK_NAME, - Description = FRONTDESK_INSTRUCTIONS -}; - -ChatClientAgentOptions reviewerAgentOptions = new() -{ - Name = REVIEWER_NAME, - Description = REVIEWER_INSTRUCTIONS -}; - -// Create agent instances -AIAgent reviewerAgent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent(reviewerAgentOptions); -AIAgent frontdeskAgent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent(frontdeskAgentOptions); - -// Build the multi-agent workflow -var workflow = new WorkflowBuilder(frontdeskAgent) - .AddEdge(frontdeskAgent, reviewerAgent) - .Build(); - -// Start the streaming workflow execution -await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, new ChatMessage(ChatRole.User, "I would like to go to Paris.")); - -// Send message to start workflow -await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); - -// Process streaming workflow events -string strResult = ""; -await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false)) -{ - if (evt is AgentResponseUpdateEvent executorComplete) - { - strResult += executorComplete.Data; - Console.WriteLine($"{executorComplete.ExecutorId}: {executorComplete.Data}"); - } -} - -// Display final aggregated result -Console.WriteLine("\n=== Final Result ==="); -Console.WriteLine(strResult); diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md deleted file mode 100644 index e6dc800..0000000 --- a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Multi-Agent Workflow (.NET) - -Shows how to connect two agents in a workflow: a **FrontDesk** travel agent proposes recommendations and a **Concierge** reviewer approves or refines them. The workflow runs iteratively until the concierge approves. - -## What it shows -- Building a two-agent review loop with `WorkflowBuilder` -- Defining distinct roles and personas via `ChatClientAgentOptions` -- Running a workflow with `InProcessExecution.RunStreamingAsync` and consuming `WorkflowEvent` updates - -## Prerequisites -- [.NET 10 SDK](https://dot.net) -- A [GitHub Models](https://github.com/marketplace/models) personal access token - -## Configure secrets - -```bash -dotnet user-secrets set "GITHUB_TOKEN" "" -dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" -dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" -``` - -## Run - -```bash -dotnet run -``` - -## Run with file-based approach (.NET 10) - -```bash -dotnet run app.cs -``` diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/app.cs b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/app.cs deleted file mode 100644 index ccacb54..0000000 --- a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/app.cs +++ /dev/null @@ -1,108 +0,0 @@ -// File-based run: dotnet run app.cs -#:property UserSecretsId 347ece07-9c59-405e-8282-387fa070c48a -#:package Microsoft.Extensions.AI@10.3.0 -#:package Microsoft.Extensions.AI.Abstractions@10.3.0 -#:package Microsoft.Extensions.AI.OpenAI@10.3.0 -#:package Azure.AI.Agents.Persistent@1.2.0-beta.8 -#:package Azure.Identity@1.18.0-beta.2 -#:package System.Linq.Async@7.0.0 -#:package OpenAI@2.8.0 -#:package OpenTelemetry.Api@1.14.0 -#:package Microsoft.Agents.AI@1.0.0-rc1 -#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 -#:package Microsoft.Agents.AI.Workflows@1.0.0-rc1 -#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 -#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 - -using System; -using System.ClientModel; -using System.Text.Json; -using System.Text.Json.Serialization; -using Microsoft.Extensions.AI; -using Microsoft.Agents.AI; -using Microsoft.Agents.AI.Workflows; -using OpenAI; -using Microsoft.Extensions.Configuration; - -// Load environment variables from .env file - -var config = new ConfigurationBuilder() - .AddUserSecrets() - .AddEnvironmentVariables() - .Build(); - -var github_endpoint = config["GITHUB_ENDPOINT"] - ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); -var github_model_id = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; -var github_token = config["GITHUB_TOKEN"] - ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); - -// Configure OpenAI client for GitHub Models -var openAIOptions = new OpenAIClientOptions() -{ - Endpoint = new Uri(github_endpoint) -}; -var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions); - -// Define Concierge Agent (Quality Reviewer) -const string REVIEWER_NAME = "Concierge"; -const string REVIEWER_INSTRUCTIONS = @""" - You are an are hotel concierge who has opinions about providing the most local and authentic experiences for travelers. - The goal is to determine if the front desk travel agent has recommended the best non-touristy experience for a traveler. - If so, state that it is approved. - If not, provide insight on how to refine the recommendation without using a specific example. - """; - -// Define Front Desk Agent (Travel Specialist) -const string FRONTDESK_NAME = "FrontDesk"; -const string FRONTDESK_INSTRUCTIONS = @""" - You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers. - The goal is to provide the best activities and locations for a traveler to visit. - Only provide a single recommendation per response. - You're laser focused on the goal at hand. - Don't waste time with chit chat. - Consider suggestions when refining an idea. - """; - -// Configure agent options -ChatClientAgentOptions frontdeskAgentOptions = new() -{ - Name = FRONTDESK_NAME, - Description = FRONTDESK_INSTRUCTIONS -}; - -ChatClientAgentOptions reviewerAgentOptions = new() -{ - Name = REVIEWER_NAME, - Description = REVIEWER_INSTRUCTIONS -}; - -// Create agent instances -AIAgent reviewerAgent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent(reviewerAgentOptions); -AIAgent frontdeskAgent = openAIClient.GetChatClient(github_model_id).AsIChatClient().AsAIAgent(frontdeskAgentOptions); - -// Build the multi-agent workflow -var workflow = new WorkflowBuilder(frontdeskAgent) - .AddEdge(frontdeskAgent, reviewerAgent) - .Build(); - -// Start the streaming workflow execution -await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, new ChatMessage(ChatRole.User, "I would like to go to Paris.")); - -// Send message to start workflow -await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); - -// Process streaming workflow events -string strResult = ""; -await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false)) -{ - if (evt is AgentResponseUpdateEvent executorComplete) - { - strResult += executorComplete.Data; - Console.WriteLine($"{executorComplete.ExecutorId}: {executorComplete.Data}"); - } -} - -// Display final aggregated result -Console.WriteLine("\n=== Final Result ==="); -Console.WriteLine(strResult); diff --git a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj b/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj deleted file mode 100644 index add1b99..0000000 --- a/00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/dotnet-agent-framework-ghmodel-workflow-multi-agents.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - Exe - net10.0 - dotnet_agent_framework_ghmodel_workflow_multi_agents - enable - enable - 347ece07-9c59-405e-8282-387fa070c48a - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/00.ForBeginners/README.md b/00.ForBeginners/README.md index 1a9f7cf..6dfed33 100644 --- a/00.ForBeginners/README.md +++ b/00.ForBeginners/README.md @@ -13,35 +13,35 @@ Learn the foundational concepts of AI agents and get started with your first Mic **Code Samples:** - **Python:** [`python-agent-framework-travelagent.ipynb`](./01-intro-to-ai-agents/code_samples/python-agent-framework-travelagent.ipynb) -- **.NET:** [`dotnet-agent-framework-travelagent.ipynb`](./01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent.ipynb) +- **.NET:** [`dotnet-travelagent-ghmodel/`](../02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/) ### 02. Explore Agentic Frameworks Dive deeper into the Microsoft Agent Framework architecture and understand different implementation patterns. **Code Samples:** - **Python:** [`python-agent-framework-basicagent.ipynb`](./02-explore-agentic-frameworks/code_samples/python-agent-framework-basicagent.ipynb) -- **.NET:** [`dotnet-agent-framework-basicagent.ipynb`](./02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent.ipynb) +- **.NET:** [`02-dotnet-agent-framework-ghmodel/`](../03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/) ### 03. Agentic Design Patterns Explore common design patterns and best practices for building robust AI agents with GitHub Models integration. **Code Samples:** - **Python:** [`python-agent-framework-ghmodel-basicagent.ipynb`](./03-agentic-design-patterns/code_samples/python-agent-framework-ghmodel-basicagent.ipynb) -- **.NET:** [`dotnet-agent-framework-ghmodel-basicagent.ipynb`](./03-agentic-design-patterns/code_samples/dotnet-agent-framework-ghmodel-basicagent.ipynb) +- **.NET:** [`02-dotnet-agent-framework-ghmodel/`](../03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/) ### 04. Tool Use and Integration Learn how to enhance your agents with external tools and capabilities using GitHub Models. **Code Samples:** - **Python:** [`python-agent-framework-ghmodel-tools.ipynb`](./04-tool-use/code_samples/python-agent-framework-ghmodel-tools.ipynb) -- **.NET:** [`dotnet-agent-framework-ghmodels-tool.ipynb`](./04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool.ipynb) +- **.NET:** [`dotnet-agent-framework-ghmodels-tool/`](./04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/) ### 05. Agentic RAG (Retrieval-Augmented Generation) Implement knowledge-enhanced agents using Azure AI Foundry's file search capabilities. **Code Samples:** - **Python:** [`python-agent-framework-aifoundry-file-search.ipynb`](./05-agentic-rag/code_samples/python-agent-framework-aifoundry-file-search.ipynb) -- **.NET:** [`dotnet-agent-framework-aifoundry-file-search.ipynb`](./05-agentic-rag/code_samples/dotnet-agent-framework-aifoundry-file-search.ipynb) +- **.NET:** [`dotnet-agent-framework-msfoundry-file-search/`](./05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/) **Supporting Files:** - [`document.md`](./05-agentic-rag/code_samples/document.md) - Sample document for RAG demonstrations @@ -58,7 +58,7 @@ Build collaborative multi-agent workflows using GitHub Models for complex proble **Code Samples:** - **Python:** [`python-agent-framework-ghmodel-workflow-multi-agents.ipynb`](./08-multi-agent/code_samples/python-agent-framework-ghmodel-workflow-multi-agents.ipynb) -- **.NET:** [`dotnet-agent-framework-ghmodel-workflow-multi-agents.ipynb`](./08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents.ipynb) +- **.NET:** [`01.dotnet-agent-framework-workflow-ghmodel-basic/`](../07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/) ### 09. Metacognition *Coming Soon* - Advanced metacognitive capabilities for self-aware agents. From a650d55fb9f3951cdcb9b6f948aa2b589327edf6 Mon Sep 17 00:00:00 2001 From: Bruno Capuano Date: Sat, 21 Feb 2026 15:55:19 -0500 Subject: [PATCH 08/10] Implement retrieval-augmented generation (RAG) sample and conditional workflow in .NET - Added a comprehensive RAG sample in `06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/app.cs` demonstrating document upload, indexing, agent creation, and multi-turn querying. - Developed a conditional workflow example in `07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/Program.cs` showcasing agent interactions based on review outcomes. - Updated README files to reflect new features and provide clearer instructions on the conditional workflow. - Created foundational agent example in `01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/` illustrating the core building blocks of a Microsoft Agent Framework agent. - Added project files and configurations for the new agent foundation sample. --- 01.AgentFoundation/README.md | 33 ++++ .../dotNET/dotnet-agent-foundation/Program.cs | 170 +++++++++++++++++ .../dotNET/dotnet-agent-foundation/app.cs | 180 ++++++++++++++++++ .../dotnet-agent-foundation.csproj | 33 ++++ .../Program.cs | 67 ++++--- .../app.cs | 81 +++++--- .../Program.cs | 127 +++++++++--- .../app.cs | 127 +++++++++--- .../Program.cs | 119 +++++++++++- .../README.md | 18 +- .../app.cs | 119 +++++++++++- README.md | 4 +- dotnet/AgentFrameworkSamples.slnx | 9 +- 13 files changed, 966 insertions(+), 121 deletions(-) create mode 100644 01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/Program.cs create mode 100644 01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/app.cs create mode 100644 01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/dotnet-agent-foundation.csproj diff --git a/01.AgentFoundation/README.md b/01.AgentFoundation/README.md index d6856a0..d857f89 100644 --- a/01.AgentFoundation/README.md +++ b/01.AgentFoundation/README.md @@ -39,4 +39,37 @@ This framework is the spiritual successor and consolidation of learnings from pi The Microsoft Agent Framework is designed to be the foundational layer for the next generation of intelligent, autonomous systems, making agent development more accessible and powerful than ever before. +## Code Samples + +### .NET + +| Sample | Description | +|--------|-------------| +| [dotnet-agent-foundation](./code_samples/dotNET/dotnet-agent-foundation/) | Annotated "anatomy of an agent" walkthrough covering all four building blocks: `IChatClient`, `AIAgent`, Tools, and `AgentSession` (multi-turn). Backed by GitHub Models. | + +#### Prerequisites + +- .NET 10 SDK +- [GitHub Personal Access Token](https://github.com/settings/tokens) with no special scopes (for GitHub Models) + +#### Setup + +```bash +cd 01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation + +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +#### Run + +```bash +# Option 1 — file-based (no project required): +dotnet run app.cs + +# Option 2 — project-based: +dotnet run +``` + diff --git a/01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/Program.cs b/01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/Program.cs new file mode 100644 index 0000000..04aa4da --- /dev/null +++ b/01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/Program.cs @@ -0,0 +1,170 @@ +// ============================================================ +// ANATOMY OF A MICROSOFT AGENT FRAMEWORK AGENT +// This sample walks through every building block of an agent, +// annotated step-by-step. +// ============================================================ + +using System.ClientModel; +using System.ComponentModel; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; +using OpenAI; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var githubEndpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var githubModel = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var githubToken = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +// ============================================================ +// BUILDING BLOCK 1 — IChatClient +// ============================================================ +// An IChatClient is the raw connection to the language model. +// It speaks the chat-completion protocol (send messages, get a reply). +// The Microsoft Agent Framework wraps any IChatClient into an AIAgent. +// Here we create one backed by GitHub Models (OpenAI-compatible endpoint). +// ============================================================ + +var openAIOptions = new OpenAIClientOptions { Endpoint = new Uri(githubEndpoint) }; +IChatClient chatClient = new OpenAIClient(new ApiKeyCredential(githubToken), openAIOptions) + .GetChatClient(githubModel) + .AsIChatClient(); // converts OpenAI ChatClient → Microsoft.Extensions.AI IChatClient + +// ============================================================ +// BUILDING BLOCK 2 — AIAgent +// ============================================================ +// AIAgent is the core abstraction in the Microsoft Agent Framework. +// It adds on top of IChatClient: +// • A name — identifies the agent in logs and multi-agent workflows +// • Instructions — the system prompt, shapes the agent's behavior +// • Tools — .NET functions the model can call autonomously +// ============================================================ + +AIAgent agent = chatClient.AsAIAgent( + name: "FactBot", + instructions: """ + You are a concise fact assistant that answers questions about world capitals + and major landmarks. Reply in 2-3 sentences maximum. If asked for a + random city, call the GetRandomCity tool first. + """ +); + +Console.WriteLine("=== BUILDING BLOCK 2: Basic AIAgent ==="); +Console.WriteLine("Agent created. Name: FactBot"); +Console.WriteLine(); + +// ============================================================ +// EXECUTION PATTERN 1 — RunAsync (single-turn) +// ============================================================ +// RunAsync sends a single user message and returns the complete +// response as a string. No conversation state is kept. +// ============================================================ + +Console.WriteLine("=== EXECUTION PATTERN 1: RunAsync (single-turn) ==="); +var response = await agent.RunAsync("What is the capital of Japan, and what is it known for?"); +Console.WriteLine(response); +Console.WriteLine(); + +// ============================================================ +// EXECUTION PATTERN 2 — RunStreamingAsync (single-turn, streaming) +// ============================================================ +// RunStreamingAsync yields text tokens as they are produced by +// the model. Use this when you want to display output progressively, +// e.g., in a UI or CLI that should feel responsive. +// ============================================================ + +Console.WriteLine("=== EXECUTION PATTERN 2: RunStreamingAsync (streaming) ==="); +await foreach (var token in agent.RunStreamingAsync("What is the Eiffel Tower?")) +{ + Console.Write(token); +} +Console.WriteLine(); +Console.WriteLine(); + +// ============================================================ +// BUILDING BLOCK 3 — Tools +// ============================================================ +// Tools are ordinary .NET methods the agent can call automatically. +// Two conventions make a method a tool: +// 1. [Description("...")] attribute — passed to the model as the +// tool's description so it knows when and how to call it. +// 2. AIFunctionFactory.Create(func) — wraps the method into an +// AIFunction that the agent framework can register and invoke. +// The model decides when to call a tool; the framework handles the +// actual invocation and sends the result back to the model. +// ============================================================ + +[Description("Returns a random world capital city to use as a topic.")] +static string GetRandomCity() +{ + string[] cities = ["Tokyo", "Paris", "Cairo", "Sydney", "Rio de Janeiro", "Toronto", "Berlin"]; + return cities[Random.Shared.Next(cities.Length)]; +} + +AIAgent agentWithTools = chatClient.AsAIAgent( + name: "FactBotWithTools", + instructions: """ + You are a concise fact assistant. When asked for a random city or topic, + call GetRandomCity first, then provide 2-3 interesting facts about it. + """, + tools: [AIFunctionFactory.Create((Func)GetRandomCity)] +); + +Console.WriteLine("=== BUILDING BLOCK 3: Agent with Tools ==="); +var toolResponse = await agentWithTools.RunAsync("Give me facts about a random city."); +Console.WriteLine(toolResponse); +Console.WriteLine(); + +// ============================================================ +// BUILDING BLOCK 4 — AgentSession (multi-turn conversation) +// ============================================================ +// An AgentSession holds the conversation history for one thread. +// Passing the same session to successive RunAsync calls means the +// model sees all prior messages, enabling follow-up questions and +// context-aware replies. +// +// Without a session, each RunAsync is stateless — the model has +// no memory of previous messages. +// ============================================================ + +Console.WriteLine("=== BUILDING BLOCK 4: AgentSession (multi-turn) ==="); + +AgentSession session = await agentWithTools.CreateSessionAsync(); + +var turn1 = await agentWithTools.RunAsync("Tell me about a random city.", session); +Console.WriteLine($"Turn 1: {turn1}"); +Console.WriteLine(); + +// The agent remembers which city it just mentioned — no need to repeat it. +var turn2 = await agentWithTools.RunAsync("What is the local cuisine like there?", session); +Console.WriteLine($"Turn 2: {turn2}"); +Console.WriteLine(); + +var turn3 = await agentWithTools.RunAsync("And what time zone is it in?", session); +Console.WriteLine($"Turn 3: {turn3}"); +Console.WriteLine(); + +// ============================================================ +// SUMMARY +// ============================================================ +// The four building blocks compose a full agent: +// +// IChatClient — connection to the model +// ↓ +// AIAgent — adds name, instructions, tools +// ↓ +// Tools — .NET functions the model can call +// ↓ +// AgentSession — maintains conversation history (multi-turn) +// +// From here, the next step is to explore multiple agents working +// together in a Workflow (see 07.Workflow) or different providers +// (see 03.ExploreAgentFramework). +// ============================================================ + +Console.WriteLine("=== Summary ==="); +Console.WriteLine("The four building blocks: IChatClient → AIAgent → Tools → AgentSession"); diff --git a/01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/app.cs b/01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/app.cs new file mode 100644 index 0000000..be421b2 --- /dev/null +++ b/01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/app.cs @@ -0,0 +1,180 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId e9f0a1b2-c3d4-5e6f-7890-abcdef012345 +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +// ============================================================ +// ANATOMY OF A MICROSOFT AGENT FRAMEWORK AGENT +// This sample walks through every building block of an agent, +// annotated step-by-step. +// ============================================================ + +using System.ClientModel; +using System.ComponentModel; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; +using OpenAI; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var githubEndpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var githubModel = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var githubToken = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +// ============================================================ +// BUILDING BLOCK 1 — IChatClient +// ============================================================ +// An IChatClient is the raw connection to the language model. +// It speaks the chat-completion protocol (send messages, get a reply). +// The Microsoft Agent Framework wraps any IChatClient into an AIAgent. +// Here we create one backed by GitHub Models (OpenAI-compatible endpoint). +// ============================================================ + +var openAIOptions = new OpenAIClientOptions { Endpoint = new Uri(githubEndpoint) }; +IChatClient chatClient = new OpenAIClient(new ApiKeyCredential(githubToken), openAIOptions) + .GetChatClient(githubModel) + .AsIChatClient(); // converts OpenAI ChatClient → Microsoft.Extensions.AI IChatClient + +// ============================================================ +// BUILDING BLOCK 2 — AIAgent +// ============================================================ +// AIAgent is the core abstraction in the Microsoft Agent Framework. +// It adds on top of IChatClient: +// • A name — identifies the agent in logs and multi-agent workflows +// • Instructions — the system prompt, shapes the agent's behavior +// • Tools — .NET functions the model can call autonomously +// ============================================================ + +AIAgent agent = chatClient.AsAIAgent( + name: "FactBot", + instructions: """ + You are a concise fact assistant that answers questions about world capitals + and major landmarks. Reply in 2-3 sentences maximum. If asked for a + random city, call the GetRandomCity tool first. + """ +); + +Console.WriteLine("=== BUILDING BLOCK 2: Basic AIAgent ==="); +Console.WriteLine("Agent created. Name: FactBot"); +Console.WriteLine(); + +// ============================================================ +// EXECUTION PATTERN 1 — RunAsync (single-turn) +// ============================================================ +// RunAsync sends a single user message and returns the complete +// response as a string. No conversation state is kept. +// ============================================================ + +Console.WriteLine("=== EXECUTION PATTERN 1: RunAsync (single-turn) ==="); +var response = await agent.RunAsync("What is the capital of Japan, and what is it known for?"); +Console.WriteLine(response); +Console.WriteLine(); + +// ============================================================ +// EXECUTION PATTERN 2 — RunStreamingAsync (single-turn, streaming) +// ============================================================ +// RunStreamingAsync yields text tokens as they are produced by +// the model. Use this when you want to display output progressively, +// e.g., in a UI or CLI that should feel responsive. +// ============================================================ + +Console.WriteLine("=== EXECUTION PATTERN 2: RunStreamingAsync (streaming) ==="); +await foreach (var token in agent.RunStreamingAsync("What is the Eiffel Tower?")) +{ + Console.Write(token); +} +Console.WriteLine(); +Console.WriteLine(); + +// ============================================================ +// BUILDING BLOCK 3 — Tools +// ============================================================ +// Tools are ordinary .NET methods the agent can call automatically. +// Two conventions make a method a tool: +// 1. [Description("...")] attribute — passed to the model as the +// tool's description so it knows when and how to call it. +// 2. AIFunctionFactory.Create(func) — wraps the method into an +// AIFunction that the agent framework can register and invoke. +// The model decides when to call a tool; the framework handles the +// actual invocation and sends the result back to the model. +// ============================================================ + +[Description("Returns a random world capital city to use as a topic.")] +static string GetRandomCity() +{ + string[] cities = ["Tokyo", "Paris", "Cairo", "Sydney", "Rio de Janeiro", "Toronto", "Berlin"]; + return cities[Random.Shared.Next(cities.Length)]; +} + +AIAgent agentWithTools = chatClient.AsAIAgent( + name: "FactBotWithTools", + instructions: """ + You are a concise fact assistant. When asked for a random city or topic, + call GetRandomCity first, then provide 2-3 interesting facts about it. + """, + tools: [AIFunctionFactory.Create((Func)GetRandomCity)] +); + +Console.WriteLine("=== BUILDING BLOCK 3: Agent with Tools ==="); +var toolResponse = await agentWithTools.RunAsync("Give me facts about a random city."); +Console.WriteLine(toolResponse); +Console.WriteLine(); + +// ============================================================ +// BUILDING BLOCK 4 — AgentSession (multi-turn conversation) +// ============================================================ +// An AgentSession holds the conversation history for one thread. +// Passing the same session to successive RunAsync calls means the +// model sees all prior messages, enabling follow-up questions and +// context-aware replies. +// +// Without a session, each RunAsync is stateless — the model has +// no memory of previous messages. +// ============================================================ + +Console.WriteLine("=== BUILDING BLOCK 4: AgentSession (multi-turn) ==="); + +AgentSession session = await agentWithTools.CreateSessionAsync(); + +var turn1 = await agentWithTools.RunAsync("Tell me about a random city.", session); +Console.WriteLine($"Turn 1: {turn1}"); +Console.WriteLine(); + +// The agent remembers which city it just mentioned — no need to repeat it. +var turn2 = await agentWithTools.RunAsync("What is the local cuisine like there?", session); +Console.WriteLine($"Turn 2: {turn2}"); +Console.WriteLine(); + +var turn3 = await agentWithTools.RunAsync("And what time zone is it in?", session); +Console.WriteLine($"Turn 3: {turn3}"); +Console.WriteLine(); + +// ============================================================ +// SUMMARY +// ============================================================ +// The four building blocks compose a full agent: +// +// IChatClient — connection to the model +// ↓ +// AIAgent — adds name, instructions, tools +// ↓ +// Tools — .NET functions the model can call +// ↓ +// AgentSession — maintains conversation history (multi-turn) +// +// From here, the next step is to explore multiple agents working +// together in a Workflow (see 07.Workflow) or different providers +// (see 03.ExploreAgentFramework). +// ============================================================ + +Console.WriteLine("=== Summary ==="); +Console.WriteLine("The four building blocks: IChatClient → AIAgent → Tools → AgentSession"); diff --git a/01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/dotnet-agent-foundation.csproj b/01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/dotnet-agent-foundation.csproj new file mode 100644 index 0000000..439e183 --- /dev/null +++ b/01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/dotnet-agent-foundation.csproj @@ -0,0 +1,33 @@ + + + + Exe + net10.0 + dotnet_agent_foundation + enable + enable + e9f0a1b2-c3d4-5e6f-7890-abcdef012345 + $(NoWarn);CA1812;OPENAI001;MEAI001 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs index 054119c..d85b315 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs +++ b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/Program.cs @@ -1,4 +1,17 @@ -// See https://aka.ms/new-console-template for more information +// ============================================================ +// 04 — FILE SEARCH TOOL +// This sample shows how HostedFileSearchTool plugs into an +// AIAgent using the exact same pattern as the other hosted +// tools in this chapter (Code Interpreter, Bing Search): +// +// 1. Prepare the tool — upload a file + create a vector store +// 2. Create the tool — new HostedFileSearchTool(vectorStoreId) +// 3. Register the tool — pass it in the tools: [] parameter +// +// The agent framework handles calling the tool automatically. +// For a full RAG pipeline walkthrough, see 06.RAGs. +// ============================================================ + using System.ClientModel; using Azure.AI.Projects; using Azure.Identity; @@ -14,41 +27,47 @@ .AddEnvironmentVariables() .Build(); -var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; -// Create an AI Project client and get an OpenAI client that works with the foundry service. -AIProjectClient aiProjectClient = new( - new Uri(endpoint), - new AzureCliCredential()); -OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); +// Step 1 — Prepare the tool: upload the knowledge file and index it into a vector store. +// The vector store is the searchable index that backs the File Search tool. +AIProjectClient aiProjectClient = new(new Uri(endpoint), new AzureCliCredential()); +OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); -// Upload the file that contains the data to be used for RAG to the Foundry service. -OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); -ClientResult uploadResult = await fileClient.UploadFileAsync( +OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); +var uploadResult = await fileClient.UploadFileAsync( filePath: "../../../files/demo.md", purpose: FileUploadPurpose.Assistants); #pragma warning disable OPENAI001 VectorStoreClient vectorStoreClient = openAIClient.GetVectorStoreClient(); -ClientResult vectorStoreCreate = await vectorStoreClient.CreateVectorStoreAsync(options: new VectorStoreCreationOptions() -{ - Name = "rag-document-knowledge-base", - FileIds = { uploadResult.Value.Id } -}); +var vectorStoreResult = await vectorStoreClient.CreateVectorStoreAsync( + options: new VectorStoreCreationOptions() + { + Name = "file-search-tool-demo", + FileIds = { uploadResult.Value.Id } + }); #pragma warning restore OPENAI001 -var fileSearchTool = new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreCreate.Value.Id)] }; - -AIAgent agent = await aiProjectClient - .CreateAIAgentAsync( - model: deploymentName, - name: "dotNETRAGAgent", - instructions: @"You are an AI assistant that helps people find information in a set of documents. Use the File Search tool to look up relevant information from the files when needed to answer user questions. If you don't know the answer, just say you don't know. Do not make up answers.", - tools: [fileSearchTool]); +// Step 2 — Create the tool. +// HostedFileSearchTool follows the same pattern as HostedCodeInterpreterTool +// and HostedWebSearchTool shown in earlier samples in this chapter. +var fileSearchTool = new HostedFileSearchTool() +{ + Inputs = [new HostedVectorStoreContent(vectorStoreResult.Value.Id)] +}; +// Step 3 — Register the tool with the agent. +// The agent framework decides when to invoke the tool based on the user's query. +AIAgent agent = await aiProjectClient.CreateAIAgentAsync( + model: deploymentName, + name: "FileSearchToolAgent", + instructions: "You are a helpful assistant. Use the File Search tool to find information in the uploaded documents. If you can't find the answer, say so clearly.", + tools: [fileSearchTool]); AgentSession session = await agent.CreateSessionAsync(); -Console.WriteLine(await agent.RunAsync("What's graphrag?", session)); +Console.WriteLine("=== File Search Tool Demo ==="); +Console.WriteLine(await agent.RunAsync("What is GraphRAG and what is it used for?", session)); diff --git a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/app.cs b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/app.cs index 26f4cc5..f6aff84 100644 --- a/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/app.cs +++ b/04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/app.cs @@ -12,7 +12,34 @@ #:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 #:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 -// See https://aka.ms/new-console-template for more information +// File-based run: dotnet run app.cs +#:property UserSecretsId 8324968c-859a-4090-8afa-336940d7cf66 +#:property EnablePreviewFeatures true +#:package Azure.AI.OpenAI@2.1.0 +#:package Azure.Identity@1.17.1 +#:package Azure.AI.Projects@1.2.0-beta.5 +#:package Azure.AI.Projects.OpenAI@1.0.0-beta.5 +#:package Azure.AI.Agents.Persistent@1.2.0-beta.8 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.AzureAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +// ============================================================ +// 04 — FILE SEARCH TOOL +// This sample shows how HostedFileSearchTool plugs into an +// AIAgent using the exact same pattern as the other hosted +// tools in this chapter (Code Interpreter, Bing Search): +// +// 1. Prepare the tool — upload a file + create a vector store +// 2. Create the tool — new HostedFileSearchTool(vectorStoreId) +// 3. Register the tool — pass it in the tools: [] parameter +// +// The agent framework handles calling the tool automatically. +// For a full RAG pipeline walkthrough, see 06.RAGs. +// ============================================================ + using System.ClientModel; using Azure.AI.Projects; using Azure.Identity; @@ -28,40 +55,46 @@ .AddEnvironmentVariables() .Build(); -var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; -// Create an AI Project client and get an OpenAI client that works with the foundry service. -AIProjectClient aiProjectClient = new( - new Uri(endpoint), - new AzureCliCredential()); -OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); +// Step 1 — Prepare the tool: upload the knowledge file and index it into a vector store. +// The vector store is the searchable index that backs the File Search tool. +AIProjectClient aiProjectClient = new(new Uri(endpoint), new AzureCliCredential()); +OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); -// Upload the file that contains the data to be used for RAG to the Foundry service. -OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); -ClientResult uploadResult = await fileClient.UploadFileAsync( +OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); +var uploadResult = await fileClient.UploadFileAsync( filePath: "../../../files/demo.md", purpose: FileUploadPurpose.Assistants); #pragma warning disable OPENAI001 VectorStoreClient vectorStoreClient = openAIClient.GetVectorStoreClient(); -ClientResult vectorStoreCreate = await vectorStoreClient.CreateVectorStoreAsync(options: new VectorStoreCreationOptions() -{ - Name = "rag-document-knowledge-base", - FileIds = { uploadResult.Value.Id } -}); +var vectorStoreResult = await vectorStoreClient.CreateVectorStoreAsync( + options: new VectorStoreCreationOptions() + { + Name = "file-search-tool-demo", + FileIds = { uploadResult.Value.Id } + }); #pragma warning restore OPENAI001 -var fileSearchTool = new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreCreate.Value.Id)] }; - -AIAgent agent = await aiProjectClient - .CreateAIAgentAsync( - model: deploymentName, - name: "dotNETRAGAgent", - instructions: @"You are an AI assistant that helps people find information in a set of documents. Use the File Search tool to look up relevant information from the files when needed to answer user questions. If you don't know the answer, just say you don't know. Do not make up answers.", - tools: [fileSearchTool]); +// Step 2 — Create the tool. +// HostedFileSearchTool follows the same pattern as HostedCodeInterpreterTool +// and HostedWebSearchTool shown in earlier samples in this chapter. +var fileSearchTool = new HostedFileSearchTool() +{ + Inputs = [new HostedVectorStoreContent(vectorStoreResult.Value.Id)] +}; +// Step 3 — Register the tool with the agent. +// The agent framework decides when to invoke the tool based on the user's query. +AIAgent agent = await aiProjectClient.CreateAIAgentAsync( + model: deploymentName, + name: "FileSearchToolAgent", + instructions: "You are a helpful assistant. Use the File Search tool to find information in the uploaded documents. If you can't find the answer, say so clearly.", + tools: [fileSearchTool]); AgentSession session = await agent.CreateSessionAsync(); -Console.WriteLine(await agent.RunAsync("What's graphrag?", session)); +Console.WriteLine("=== File Search Tool Demo ==="); +Console.WriteLine(await agent.RunAsync("What is GraphRAG and what is it used for?", session)); diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs index 81e1b6a..89197da 100644 --- a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/Program.cs @@ -1,3 +1,22 @@ +// ============================================================ +// RETRIEVAL-AUGMENTED GENERATION (RAG) PIPELINE +// +// RAG grounds an LLM in your own documents so it can answer +// questions about private data it was not trained on. +// +// This sample walks through all five steps: +// +// Step 1: Upload — send your document(s) to Azure AI Foundry +// Step 2: Index — create a vector store (searchable index) +// Step 3: Configure — build a HostedFileSearchTool linked to the store +// Step 4: Create — define the agent with strict "document-only" instructions +// Step 5: Query — run multi-turn Q&A; the agent cites its sources +// +// Unlike the tool introduction in 04.Tools, the focus here is on +// building a grounded, citation-accurate assistant that refuses to +// answer from general knowledge. +// ============================================================ + using System.ClientModel; using Azure.AI.Projects; using Azure.Identity; @@ -13,44 +32,100 @@ .AddEnvironmentVariables() .Build(); -var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; -// Create an AI Project client and get an OpenAI client that works with the foundry service. -AIProjectClient aiProjectClient = new( - new Uri(endpoint), - new AzureCliCredential()); -OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); +AIProjectClient aiProjectClient = new(new Uri(endpoint), new AzureCliCredential()); +OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); -// Upload the file that contains the data to be used for RAG to the Foundry service. -OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); -ClientResult uploadResult = await fileClient.UploadFileAsync( +// ----------------------------------------------- +// Step 1 — Upload +// Upload the knowledge document to Azure AI Foundry. +// The file is stored server-side and assigned a unique ID. +// ----------------------------------------------- +Console.WriteLine("[Step 1] Uploading knowledge document..."); +OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); +var uploadResult = await fileClient.UploadFileAsync( filePath: "../../files/demo.md", purpose: FileUploadPurpose.Assistants); +Console.WriteLine($" File uploaded: {uploadResult.Value.Id}"); +// ----------------------------------------------- +// Step 2 — Index +// Create a vector store from the uploaded file. +// The vector store converts the document into embeddings so the +// agent can perform semantic (meaning-based) search at query time. +// ----------------------------------------------- +Console.WriteLine("[Step 2] Creating vector store (semantic index)..."); #pragma warning disable OPENAI001 VectorStoreClient vectorStoreClient = openAIClient.GetVectorStoreClient(); -ClientResult vectorStoreCreate = await vectorStoreClient.CreateVectorStoreAsync(options: new VectorStoreCreationOptions() -{ - Name = "document-knowledge-base", - FileIds = { uploadResult.Value.Id } -}); +var vectorStoreResult = await vectorStoreClient.CreateVectorStoreAsync( + options: new VectorStoreCreationOptions() + { + Name = "rag-knowledge-base", + FileIds = { uploadResult.Value.Id } + }); #pragma warning restore OPENAI001 +Console.WriteLine($" Vector store created: {vectorStoreResult.Value.Id}"); + +// ----------------------------------------------- +// Step 3 — Configure +// Attach the vector store to a HostedFileSearchTool. +// The tool is the bridge between the agent and the index. +// ----------------------------------------------- +Console.WriteLine("[Step 3] Configuring HostedFileSearchTool..."); +var fileSearchTool = new HostedFileSearchTool() +{ + Inputs = [new HostedVectorStoreContent(vectorStoreResult.Value.Id)] +}; -var fileSearchTool = new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreCreate.Value.Id)] }; +// ----------------------------------------------- +// Step 4 — Create the RAG agent +// The system prompt is intentionally strict: +// • Answer ONLY from the retrieved document context. +// • Never use general knowledge or make assumptions. +// • Cite the source document for every factual claim. +// • Admit clearly when the document does not cover the question. +// This prevents hallucinations and keeps answers grounded. +// ----------------------------------------------- +Console.WriteLine("[Step 4] Creating RAG agent..."); +AIAgent agent = await aiProjectClient.CreateAIAgentAsync( + model: deploymentName, + name: "DocumentRAGAgent", + instructions: """ + You are a document-grounded assistant. Answer user questions using ONLY + the information retrieved from the provided file(s). -AIAgent agent = await aiProjectClient - .CreateAIAgentAsync( - model: deploymentName, - name: "dotNETRAGAgent", - instructions: @"You are an AI assistant designed to answer user questions using only the information retrieved from the provided document(s). - If a user's question cannot be answered using the retrieved context, you must clearly respond: - 'I'm sorry, but the uploaded document does not contain the necessary information to answer that question.' - Do not answer from general knowledge or reasoning. Do not make assumptions or generate hypothetical explanations. - For questions that do have relevant content in the document, respond accurately and cite the document explicitly.", - tools: [fileSearchTool]); + Rules: + - Cite the source document for every factual statement. + - If the document does not contain the answer, respond: + "The uploaded document does not contain information to answer that question." + - Never answer from general knowledge, training data, or assumptions. + - Keep answers concise and accurate. + """, + tools: [fileSearchTool]); + +// ----------------------------------------------- +// Step 5 — Query (multi-turn) +// An AgentSession holds the conversation history so follow-up +// questions can refer back to earlier answers. +// ----------------------------------------------- +Console.WriteLine("[Step 5] Starting multi-turn RAG session..."); +Console.WriteLine(); AgentSession session = await agent.CreateSessionAsync(); -Console.WriteLine(await agent.RunAsync("What's GraphRAG?", session)); +// Turn 1 — Retrieve a core concept +Console.WriteLine("Q1: What is GraphRAG?"); +Console.WriteLine(await agent.RunAsync("What is GraphRAG?", session)); +Console.WriteLine(); + +// Turn 2 — Drill into use cases (tests multi-turn context) +Console.WriteLine("Q2: What are its main use cases?"); +Console.WriteLine(await agent.RunAsync("What are its main use cases?", session)); +Console.WriteLine(); + +// Turn 3 — Verify document boundaries (tests refusal on out-of-scope questions) +Console.WriteLine("Q3: How does it compare to Elasticsearch?"); +Console.WriteLine(await agent.RunAsync("How does it compare to Elasticsearch?", session)); diff --git a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/app.cs b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/app.cs index 005ec66..23e0b84 100644 --- a/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/app.cs +++ b/06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/app.cs @@ -12,6 +12,25 @@ #:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 #:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 +// ============================================================ +// RETRIEVAL-AUGMENTED GENERATION (RAG) PIPELINE +// +// RAG grounds an LLM in your own documents so it can answer +// questions about private data it was not trained on. +// +// This sample walks through all five steps: +// +// Step 1: Upload — send your document(s) to Azure AI Foundry +// Step 2: Index — create a vector store (searchable index) +// Step 3: Configure — build a HostedFileSearchTool linked to the store +// Step 4: Create — define the agent with strict "document-only" instructions +// Step 5: Query — run multi-turn Q&A; the agent cites its sources +// +// Unlike the tool introduction in 04.Tools, the focus here is on +// building a grounded, citation-accurate assistant that refuses to +// answer from general knowledge. +// ============================================================ + using System.ClientModel; using Azure.AI.Projects; using Azure.Identity; @@ -27,43 +46,99 @@ .AddEnvironmentVariables() .Build(); -var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; -// Create an AI Project client and get an OpenAI client that works with the foundry service. -AIProjectClient aiProjectClient = new( - new Uri(endpoint), - new AzureCliCredential()); -OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); +AIProjectClient aiProjectClient = new(new Uri(endpoint), new AzureCliCredential()); +OpenAIClient openAIClient = aiProjectClient.GetProjectOpenAIClient(); -// Upload the file that contains the data to be used for RAG to the Foundry service. -OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); -ClientResult uploadResult = await fileClient.UploadFileAsync( +// ----------------------------------------------- +// Step 1 — Upload +// Upload the knowledge document to Azure AI Foundry. +// The file is stored server-side and assigned a unique ID. +// ----------------------------------------------- +Console.WriteLine("[Step 1] Uploading knowledge document..."); +OpenAIFileClient fileClient = openAIClient.GetOpenAIFileClient(); +var uploadResult = await fileClient.UploadFileAsync( filePath: "../../files/demo.md", purpose: FileUploadPurpose.Assistants); +Console.WriteLine($" File uploaded: {uploadResult.Value.Id}"); +// ----------------------------------------------- +// Step 2 — Index +// Create a vector store from the uploaded file. +// The vector store converts the document into embeddings so the +// agent can perform semantic (meaning-based) search at query time. +// ----------------------------------------------- +Console.WriteLine("[Step 2] Creating vector store (semantic index)..."); #pragma warning disable OPENAI001 VectorStoreClient vectorStoreClient = openAIClient.GetVectorStoreClient(); -ClientResult vectorStoreCreate = await vectorStoreClient.CreateVectorStoreAsync(options: new VectorStoreCreationOptions() -{ - Name = "document-knowledge-base", - FileIds = { uploadResult.Value.Id } -}); +var vectorStoreResult = await vectorStoreClient.CreateVectorStoreAsync( + options: new VectorStoreCreationOptions() + { + Name = "rag-knowledge-base", + FileIds = { uploadResult.Value.Id } + }); #pragma warning restore OPENAI001 +Console.WriteLine($" Vector store created: {vectorStoreResult.Value.Id}"); + +// ----------------------------------------------- +// Step 3 — Configure +// Attach the vector store to a HostedFileSearchTool. +// The tool is the bridge between the agent and the index. +// ----------------------------------------------- +Console.WriteLine("[Step 3] Configuring HostedFileSearchTool..."); +var fileSearchTool = new HostedFileSearchTool() +{ + Inputs = [new HostedVectorStoreContent(vectorStoreResult.Value.Id)] +}; -var fileSearchTool = new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreCreate.Value.Id)] }; +// ----------------------------------------------- +// Step 4 — Create the RAG agent +// The system prompt is intentionally strict: +// • Answer ONLY from the retrieved document context. +// • Never use general knowledge or make assumptions. +// • Cite the source document for every factual claim. +// • Admit clearly when the document does not cover the question. +// This prevents hallucinations and keeps answers grounded. +// ----------------------------------------------- +Console.WriteLine("[Step 4] Creating RAG agent..."); +AIAgent agent = await aiProjectClient.CreateAIAgentAsync( + model: deploymentName, + name: "DocumentRAGAgent", + instructions: """ + You are a document-grounded assistant. Answer user questions using ONLY + the information retrieved from the provided file(s). -AIAgent agent = await aiProjectClient - .CreateAIAgentAsync( - model: deploymentName, - name: "dotNETRAGAgent", - instructions: @"You are an AI assistant designed to answer user questions using only the information retrieved from the provided document(s). - If a user's question cannot be answered using the retrieved context, you must clearly respond: - 'I'm sorry, but the uploaded document does not contain the necessary information to answer that question.' - Do not answer from general knowledge or reasoning. Do not make assumptions or generate hypothetical explanations. - For questions that do have relevant content in the document, respond accurately and cite the document explicitly.", - tools: [fileSearchTool]); + Rules: + - Cite the source document for every factual statement. + - If the document does not contain the answer, respond: + "The uploaded document does not contain information to answer that question." + - Never answer from general knowledge, training data, or assumptions. + - Keep answers concise and accurate. + """, + tools: [fileSearchTool]); + +// ----------------------------------------------- +// Step 5 — Query (multi-turn) +// An AgentSession holds the conversation history so follow-up +// questions can refer back to earlier answers. +// ----------------------------------------------- +Console.WriteLine("[Step 5] Starting multi-turn RAG session..."); +Console.WriteLine(); AgentSession session = await agent.CreateSessionAsync(); -Console.WriteLine(await agent.RunAsync("What's GraphRAG?", session)); +// Turn 1 — Retrieve a core concept +Console.WriteLine("Q1: What is GraphRAG?"); +Console.WriteLine(await agent.RunAsync("What is GraphRAG?", session)); +Console.WriteLine(); + +// Turn 2 — Drill into use cases (tests multi-turn context) +Console.WriteLine("Q2: What are its main use cases?"); +Console.WriteLine(await agent.RunAsync("What are its main use cases?", session)); +Console.WriteLine(); + +// Turn 3 — Verify document boundaries (tests refusal on out-of-scope questions) +Console.WriteLine("Q3: How does it compare to Elasticsearch?"); +Console.WriteLine(await agent.RunAsync("How does it compare to Elasticsearch?", session)); diff --git a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/Program.cs b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/Program.cs index 603937c..7eb6307 100644 --- a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/Program.cs +++ b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/Program.cs @@ -1,3 +1,116 @@ -// TODO: Conditional MSFoundry workflow sample - pending full implementation. -// Requires: AZURE_AI_PROJECT_ENDPOINT, AZURE_AI_MODEL_DEPLOYMENT_NAME -Console.WriteLine("Conditional workflow sample - see README.md for setup instructions."); +using Azure.AI.Projects; +using Azure.AI.Projects.OpenAI; +using Azure.Identity; +using Microsoft.Agents.AI; +using Microsoft.Agents.AI.Workflows; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; + +// Create an Azure AI Foundry project client +AIProjectClient aiProjectClient = new(new Uri(endpoint), new AzureCliCredential()); + +// Create four specialist agents as Azure AI Foundry persistent agents +AIAgent writerAgent = await aiProjectClient.CreateAIAgentAsync( + name: "Writer-Agent", + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: deploymentName) + { + Instructions = """ + You are a creative travel content writer. + When given a destination, write a concise, engaging 2-3 sentence paragraph about it. + Focus on what makes it unique and appealing to visitors. + """ + })); + +AIAgent reviewerAgent = await aiProjectClient.CreateAIAgentAsync( + name: "Reviewer-Agent", + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: deploymentName) + { + Instructions = """ + You are a strict travel content quality reviewer. + Review the content and decide whether it is ready to publish. + Your first word MUST be either "APPROVED" or "REVISE" followed by your feedback. + Example: "APPROVED: Great descriptions, ready to publish." + Example: "REVISE: Missing specific landmarks and local details." + """ + })); + +AIAgent editorAgent = await aiProjectClient.CreateAIAgentAsync( + name: "Editor-Agent", + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: deploymentName) + { + Instructions = """ + You are a travel content editor. + You receive content flagged for revision. Improve it by adding specific landmarks, + local cuisine highlights, and vivid sensory details. Return only the improved paragraph. + """ + })); + +AIAgent publisherAgent = await aiProjectClient.CreateAIAgentAsync( + name: "Publisher-Agent", + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: deploymentName) + { + Instructions = """ + You are a travel content publisher. + Format the final content with a bold heading and return the polished result. + """ + })); + +// Condition predicates that inspect the reviewer agent's ChatMessage output +static bool IsApproved(ChatMessage? msg) => + msg?.Text?.Contains("APPROVED", StringComparison.OrdinalIgnoreCase) == true; + +static bool NeedsRevision(ChatMessage? msg) => + msg?.Text?.Contains("REVISE", StringComparison.OrdinalIgnoreCase) == true; + +// Build the conditional workflow: +// +// writerAgent → reviewerAgent +// ↓ [APPROVED] ──────────────── publisherAgent +// ↓ [REVISE] → editorAgent → publisherAgent +// +var workflow = new WorkflowBuilder(writerAgent) + .AddEdge(writerAgent, reviewerAgent) + .AddEdge(reviewerAgent, publisherAgent, IsApproved, label: "approved") + .AddEdge(reviewerAgent, editorAgent, NeedsRevision, label: "needs revision") + .AddEdge(editorAgent, publisherAgent) + .Build(); + +Console.WriteLine("=== Conditional Content Workflow — Azure AI Foundry ===\n"); + +// Execute the workflow with a travel destination as input +await using StreamingRun run = await InProcessExecution.RunStreamingAsync( + workflow, + new ChatMessage(ChatRole.User, "Write travel content about Tokyo, Japan.")); +await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); + +await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false)) +{ + if (evt is AgentResponseUpdateEvent update) + { + Console.Write($"[{update.ExecutorId}] {update.Data}"); + } +} + +Console.WriteLine("\n"); + +// Visualize the workflow graph +Console.WriteLine("Workflow Mermaid:\n======="); +Console.WriteLine(workflow.ToMermaidString()); +Console.WriteLine("=======\n"); + +var dotFilePath = "workflow.dot"; +File.WriteAllText(dotFilePath, workflow.ToDotString()); +Console.WriteLine($"DOT graph saved to: {dotFilePath}"); +Console.WriteLine("To generate image: dot -Tpng workflow.dot -o workflow.png"); diff --git a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md index 47276c6..f299213 100644 --- a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md +++ b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/README.md @@ -1,13 +1,19 @@ # Conditional Workflow — Azure AI Foundry (.NET) -Placeholder for a conditional branching workflow backed by **Azure AI Foundry**. The workflow will route agent execution to different paths based on run-time conditions evaluated by the workflow engine. +Demonstrates **conditional edge routing** using Azure AI Foundry and the Microsoft Agent Framework. A reviewer agent inspects content and routes it along different workflow paths depending on its decision. -> **Status:** Implementation in progress. Run the project to see the scaffold output. +## What it demonstrates +- Defining conditional edges with `AddEdge(source, target, condition)` that branch based on agent output +- A **content quality gate**: the reviewer outputs `APPROVED` or `REVISE`, routing to different downstream agents +- Azure AI Foundry persistent agents (`CreateAIAgentAsync`) as the backing provider -## What it will show -- Defining conditional edges in `WorkflowBuilder` that branch based on agent output -- Routing messages to different specialist agents depending on a decision condition -- Azure AI Foundry as the backing provider for a multi-agent conditional workflow +## Workflow + +``` +writerAgent → reviewerAgent + ↓ [APPROVED] ──────────────── publisherAgent + ↓ [REVISE] → editorAgent → publisherAgent +``` ## Prerequisites - [.NET 10 SDK](https://dot.net) diff --git a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/app.cs b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/app.cs index f954fa4..d11ff94 100644 --- a/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/app.cs +++ b/07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/app.cs @@ -14,6 +14,119 @@ #:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 #:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 -// TODO: Conditional MSFoundry workflow sample - pending full implementation. -// Requires: AZURE_AI_PROJECT_ENDPOINT, AZURE_AI_MODEL_DEPLOYMENT_NAME -Console.WriteLine("Conditional workflow sample - see README.md for setup instructions."); +using Azure.AI.Projects; +using Azure.AI.Projects.OpenAI; +using Azure.Identity; +using Microsoft.Agents.AI; +using Microsoft.Agents.AI.Workflows; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var endpoint = config["AZURE_AI_PROJECT_ENDPOINT"] ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); +var deploymentName = config["AZURE_AI_MODEL_DEPLOYMENT_NAME"] ?? "gpt-4o-mini"; + +// Create an Azure AI Foundry project client +AIProjectClient aiProjectClient = new(new Uri(endpoint), new AzureCliCredential()); + +// Create four specialist agents as Azure AI Foundry persistent agents +AIAgent writerAgent = await aiProjectClient.CreateAIAgentAsync( + name: "Writer-Agent", + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: deploymentName) + { + Instructions = """ + You are a creative travel content writer. + When given a destination, write a concise, engaging 2-3 sentence paragraph about it. + Focus on what makes it unique and appealing to visitors. + """ + })); + +AIAgent reviewerAgent = await aiProjectClient.CreateAIAgentAsync( + name: "Reviewer-Agent", + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: deploymentName) + { + Instructions = """ + You are a strict travel content quality reviewer. + Review the content and decide whether it is ready to publish. + Your first word MUST be either "APPROVED" or "REVISE" followed by your feedback. + Example: "APPROVED: Great descriptions, ready to publish." + Example: "REVISE: Missing specific landmarks and local details." + """ + })); + +AIAgent editorAgent = await aiProjectClient.CreateAIAgentAsync( + name: "Editor-Agent", + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: deploymentName) + { + Instructions = """ + You are a travel content editor. + You receive content flagged for revision. Improve it by adding specific landmarks, + local cuisine highlights, and vivid sensory details. Return only the improved paragraph. + """ + })); + +AIAgent publisherAgent = await aiProjectClient.CreateAIAgentAsync( + name: "Publisher-Agent", + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: deploymentName) + { + Instructions = """ + You are a travel content publisher. + Format the final content with a bold heading and return the polished result. + """ + })); + +// Condition predicates that inspect the reviewer agent's ChatMessage output +static bool IsApproved(ChatMessage? msg) => + msg?.Text?.Contains("APPROVED", StringComparison.OrdinalIgnoreCase) == true; + +static bool NeedsRevision(ChatMessage? msg) => + msg?.Text?.Contains("REVISE", StringComparison.OrdinalIgnoreCase) == true; + +// Build the conditional workflow: +// +// writerAgent → reviewerAgent +// ↓ [APPROVED] ──────────────── publisherAgent +// ↓ [REVISE] → editorAgent → publisherAgent +// +var workflow = new WorkflowBuilder(writerAgent) + .AddEdge(writerAgent, reviewerAgent) + .AddEdge(reviewerAgent, publisherAgent, IsApproved, label: "approved") + .AddEdge(reviewerAgent, editorAgent, NeedsRevision, label: "needs revision") + .AddEdge(editorAgent, publisherAgent) + .Build(); + +Console.WriteLine("=== Conditional Content Workflow — Azure AI Foundry ===\n"); + +// Execute the workflow with a travel destination as input +await using StreamingRun run = await InProcessExecution.RunStreamingAsync( + workflow, + new ChatMessage(ChatRole.User, "Write travel content about Tokyo, Japan.")); +await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); + +await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false)) +{ + if (evt is AgentResponseUpdateEvent update) + { + Console.Write($"[{update.ExecutorId}] {update.Data}"); + } +} + +Console.WriteLine("\n"); + +// Visualize the workflow graph +Console.WriteLine("Workflow Mermaid:\n======="); +Console.WriteLine(workflow.ToMermaidString()); +Console.WriteLine("=======\n"); + +var dotFilePath = "workflow.dot"; +File.WriteAllText(dotFilePath, workflow.ToDotString()); +Console.WriteLine($"DOT graph saved to: {dotFilePath}"); +Console.WriteLine("To generate image: dot -Tpng workflow.dot -o workflow.png"); diff --git a/README.md b/README.md index 53fa74a..e936fbb 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,8 @@ This repository provides step-by-step tutorials and real-world examples covering | Directory | Description | .NET Code Samples ✅ | Python Code Samples | |-----------|-------------|-------------------|---------------------| -| **[00.ForBeginners](./00.ForBeginners/README.md)** | **Beginner-friendly Microsoft Agent Framework examples extending [AI Agents for Beginners](https://github.com/microsoft/ai-agents-for-beginners)** | [Travel Agent](./00.ForBeginners/01-intro-to-ai-agents/code_samples/dotnet-agent-framework-travelagent/)
[Basic Agent](./00.ForBeginners/02-explore-agentic-frameworks/code_samples/dotnet-agent-framework-basicagent/)
[Design Patterns](./00.ForBeginners/03-agentic-design-patterns/code_samples/dotnet-agent-framework-basicagent/)
[Tool Use](./00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/)
[RAG Search](./00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/)
[Planning](./00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/)
[Multi-Agent](./00.ForBeginners/08-multi-agent/code_samples/dotnet-agent-framework-ghmodel-workflow-multi-agents/) | [Travel Agent](./00.ForBeginners/01-intro-to-ai-agents/code_samples/python-agent-framework-travelagent.ipynb)
[Basic Agent](./00.ForBeginners/02-explore-agentic-frameworks/code_samples/python-agent-framework-basicagent.ipynb)
[Design Patterns](./00.ForBeginners/03-agentic-design-patterns/code_samples/python-agent-framework-ghmodel-basicagent.ipynb)
[Tool Use](./00.ForBeginners/04-tool-use/code_samples/python-agent-framework-ghmodel-tools.ipynb)
[RAG Search](./00.ForBeginners/05-agentic-rag/code_samples/python-agent-framework-msfoundry-file-search.ipynb)
[Planning](./00.ForBeginners/07-planning-design/code_samples/python-agent-framrwork-ghmodel-planningdesign.ipynb)
[Multi-Agent](./00.ForBeginners/08-multi-agent/code_samples/python-agent-framework-ghmodel-workflow-multi-agents.ipynb) | -| **[01.AgentFoundation](./01.AgentFoundation/README.md)** | Core concepts and architecture of Microsoft Agent Framework | *Documentation Only* | *Documentation Only* | +| **[00.ForBeginners](./00.ForBeginners/README.md)** | **Beginner-friendly Microsoft Agent Framework examples extending [AI Agents for Beginners](https://github.com/microsoft/ai-agents-for-beginners)** | [Travel Agent](./02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/)
[Basic Agent](./03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/)
[Tool Use](./00.ForBeginners/04-tool-use/code_samples/dotnet-agent-framework-ghmodels-tool/)
[RAG Search](./00.ForBeginners/05-agentic-rag/code_samples/dotnet-agent-framework-msfoundry-file-search/)
[Planning](./00.ForBeginners/07-planning-design/code_samples/dotnet-agent-framework-ghmodel-planningdesign/)
[Multi-Agent](./07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/) | [Travel Agent](./00.ForBeginners/01-intro-to-ai-agents/code_samples/python-agent-framework-travelagent.ipynb)
[Basic Agent](./00.ForBeginners/02-explore-agentic-frameworks/code_samples/python-agent-framework-basicagent.ipynb)
[Design Patterns](./00.ForBeginners/03-agentic-design-patterns/code_samples/python-agent-framework-ghmodel-basicagent.ipynb)
[Tool Use](./00.ForBeginners/04-tool-use/code_samples/python-agent-framework-ghmodel-tools.ipynb)
[RAG Search](./00.ForBeginners/05-agentic-rag/code_samples/python-agent-framework-msfoundry-file-search.ipynb)
[Planning](./00.ForBeginners/07-planning-design/code_samples/python-agent-framrwork-ghmodel-planningdesign.ipynb)
[Multi-Agent](./00.ForBeginners/08-multi-agent/code_samples/python-agent-framework-ghmodel-workflow-multi-agents.ipynb) | +| **[01.AgentFoundation](./01.AgentFoundation/README.md)** | Core concepts and architecture of Microsoft Agent Framework | [Agent Foundation (.NET)](./01.AgentFoundation/code_samples/dotNET/dotnet-agent-foundation/) | *Coming Soon* | | **[02.CreateYourFirstAgent](./02.CreateYourFirstAgent/README.md)** | Build your first travel planning agent from scratch | [Travel Agent with GitHub Models](./02.CreateYourFirstAgent/code_samples/dotNET/dotnet-travelagent-ghmodel/) | [Travel Agent with GitHub Models](./02.CreateYourFirstAgent/code_samples/python/python-travelagent-ghmodel.ipynb) | | **[03.ExploreAgentFramework](./03.ExploreAgentFramework/README.md)** | Deep dive into different providers and configurations | [Azure OpenAI](./03.ExploreAgentFramework/code_samples/dotNET/01-dotnet-agent-framework-aoai/)
[GitHub Models](./03.ExploreAgentFramework/code_samples/dotNET/02-dotnet-agent-framework-ghmodel/)
[MS Foundry](./03.ExploreAgentFramework/code_samples/dotNET/03-dotnet-agent-framework-msfoundry/)
[Foundry Local](./03.ExploreAgentFramework/code_samples/dotNET/04-dotnet-agent-framework-foundrylocal/) | [Azure OpenAI](./03.ExploreAgentFramework/code_samples/python/01-python-agent-framework-aoai.ipynb)
[GitHub Models](./03.ExploreAgentFramework/code_samples/python/02-python-agent-framrwork-ghmodel.ipynb)
[MS Foundry](./03.ExploreAgentFramework/code_samples/python/03-python-agent-framework-msfoundry.ipynb)
[Foundry Local](./03.ExploreAgentFramework/code_samples/python/04-python-agent-framrwork-foundrylocal.ipynb) | | **[04.Tools](./04.Tools/README.md)** | Vision, code interpretation, and custom tool integration | [Vision](./04.Tools/code_samples/dotNET/msfoundry/01-dotnet-agent-framework-msfoundry-vision/)
[Code Interpreter](./04.Tools/code_samples/dotNET/msfoundry/02-dotnet-agent-framework-msfoundry-code-interpreter/)
[Bing Grounding](./04.Tools/code_samples/dotNET/msfoundry/03-dotnet-agent-framework-msfoundry-binggrounding/)
[File Search](./04.Tools/code_samples/dotNET/msfoundry/04-dotnet-agent-framework-msfoundry-file-search/) | [Vision](./04.Tools/code_samples/python/msfoundry/01.python-agent-framework-msfoundry-vision.ipynb)
[Code Interpreter](./04.Tools/code_samples/python/msfoundry/02.python-agent-framework-msfoundry-code-interpreter.ipynb)
[Bing Grounding](./04.Tools/code_samples/python/msfoundry/03.python-agent-framework-msfoundry-binggrounding.ipynb)
[File Search](./04.Tools/code_samples/python/msfoundry/04.python-agent-framework-msfoundry-file-search.ipynb) | diff --git a/dotnet/AgentFrameworkSamples.slnx b/dotnet/AgentFrameworkSamples.slnx index 9f9138d..1cdc3a8 100644 --- a/dotnet/AgentFrameworkSamples.slnx +++ b/dotnet/AgentFrameworkSamples.slnx @@ -1,16 +1,11 @@ - - - - - - - + + From 7ddd4ca2bfeea7001ea5c081631d6b5f652687b4 Mon Sep 17 00:00:00 2001 From: Bruno Capuano Date: Sat, 21 Feb 2026 15:59:51 -0500 Subject: [PATCH 09/10] Add A2A pattern sample with ResearchAgent and OrchestratorAgent in .NET --- 05.Providers/README.md | 50 ++++++++ ...-dotnet-agent-framework-ghmodel-a2a.csproj | 25 ++++ .../Program.cs | 110 ++++++++++++++++ .../app.cs | 120 ++++++++++++++++++ dotnet/AgentFrameworkSamples.slnx | 1 + 5 files changed, 306 insertions(+) create mode 100644 05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/02-dotnet-agent-framework-ghmodel-a2a.csproj create mode 100644 05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/Program.cs create mode 100644 05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/app.cs diff --git a/05.Providers/README.md b/05.Providers/README.md index cf1eef6..38cdba1 100644 --- a/05.Providers/README.md +++ b/05.Providers/README.md @@ -177,3 +177,53 @@ For example, a "Travel Planner" agent could delegate tasks by calling a "Flight * **Specialized Expertise:** A generalist agent can consult a specialist agent for deep knowledge in a specific area (e.g., a "General Support" agent calling a "Billing Expert" agent). * **Collaborative Problem-Solving:** Multiple agents can work together, sharing information and intermediate results to solve a problem that would be too complex for a single agent. + +### A2A Example + +#### .NET Example + +This sample demonstrates the A2A pattern using GitHub Models. A **ResearchAgent** specialist is wrapped as a callable tool for an **OrchestratorAgent**, which delegates research queries to it at runtime. + +The key mechanism is `AIFunctionFactory.Create`, which turns any .NET delegate — including another agent's `RunAsync` — into an `AIFunction` the model can invoke as a tool call. + +```csharp +// Wrap ResearchAgent as a callable tool for another agent +Func> researchFunc = + async (query) => (await researchAgent.RunAsync(query)).ToString(); + +var researchTool = AIFunctionFactory.Create( + (Func>)researchFunc, + name: "ResearchTopic", + description: "Delegates a research query to the ResearchAgent specialist."); + +// OrchestratorAgent treats ResearchAgent as a provider +AIAgent orchestratorAgent = chatClient.AsAIAgent( + name: "OrchestratorAgent", + instructions: "For every question, call ResearchTopic first, then compose a friendly answer.", + tools: [researchTool]); + +var answer = await orchestratorAgent.RunAsync("What should I know about visiting Tokyo?"); +Console.WriteLine(answer); +``` + +Full sample: [02-dotnet-agent-framework-ghmodel-a2a](./code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/) + +**Setup** + +```bash +cd 05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a + +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +**Run** + +```bash +dotnet run app.cs # file-based +# or +dotnet run # project-based +``` + +> **Compare with 07.Workflow:** In a Workflow, agents are wired into a fixed pipeline and messages pass through in sequence. In A2A, the orchestrator decides at runtime whether and when to call the specialist — it is a dynamic tool call, not a predetermined edge in a graph. diff --git a/05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/02-dotnet-agent-framework-ghmodel-a2a.csproj b/05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/02-dotnet-agent-framework-ghmodel-a2a.csproj new file mode 100644 index 0000000..5b2fcb6 --- /dev/null +++ b/05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/02-dotnet-agent-framework-ghmodel-a2a.csproj @@ -0,0 +1,25 @@ + + + + Exe + net10.0 + enable + enable + f1e2d3c4-b5a6-7890-cdef-012345678901 + + + + + + + + + + + + + + + + + diff --git a/05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/Program.cs b/05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/Program.cs new file mode 100644 index 0000000..fa77df0 --- /dev/null +++ b/05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/Program.cs @@ -0,0 +1,110 @@ +// ============================================================ +// AGENT-TO-AGENT (A2A) PATTERN +// +// In A2A, one agent treats another agent as a callable provider — +// a specialist it can delegate to on demand. +// +// This sample shows two agents: +// • ResearchAgent — a specialist that returns concise facts +// • OrchestratorAgent — wraps ResearchAgent as a tool and calls +// it automatically when it needs research to answer the user +// +// The key mechanism: +// AIFunctionFactory.Create(researchFunc, ...) — wraps the +// ResearchAgent's RunAsync as an AIFunction tool that the +// orchestrator can invoke just like any other tool. +// +// Compare with 07.Workflow where agents are wired into a fixed +// pipeline. Here the orchestrator decides at runtime whether and +// when to call the specialist agent. +// ============================================================ + +using System.ClientModel; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; +using OpenAI; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var githubEndpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var githubModel = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var githubToken = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +var openAIOptions = new OpenAIClientOptions { Endpoint = new Uri(githubEndpoint) }; +IChatClient chatClient = new OpenAIClient(new ApiKeyCredential(githubToken), openAIOptions) + .GetChatClient(githubModel) + .AsIChatClient(); + +// ----------------------------------------------- +// Agent 1 — ResearchAgent (the specialist provider) +// Focused, terse instructions: return facts only, +// no elaboration. This keeps the delegation output +// clean and easy for the orchestrator to re-use. +// ----------------------------------------------- +AIAgent researchAgent = chatClient.AsAIAgent( + name: "ResearchAgent", + instructions: """ + You are a concise research specialist. When given a topic or question, + respond with exactly 3-5 factual bullet points and nothing else. + No introductions, no conclusions, no extra commentary. + """); + +// ----------------------------------------------- +// A2A Bridge — wrap the ResearchAgent as a tool +// +// AIFunctionFactory.Create turns any .NET delegate into an AIFunction +// that a language model can call. By wrapping ResearchAgent.RunAsync +// here, the OrchestratorAgent can invoke it as a tool call — the +// same mechanism used for APIs and database queries. +// +// From the orchestrator's perspective, ResearchAgent is just another +// provider it can query; it does not know or care that the provider +// is itself an AI agent. +// ----------------------------------------------- +Func> researchFunc = + async (query) => (await researchAgent.RunAsync(query)).ToString(); + +var researchTool = AIFunctionFactory.Create( + (Func>)researchFunc, + name: "ResearchTopic", + description: "Delegates a research query to the ResearchAgent specialist. " + + "Returns 3-5 concise factual bullet points about the topic."); + +// ----------------------------------------------- +// Agent 2 — OrchestratorAgent (the coordinator) +// The orchestrator knows it has a ResearchTopic tool +// and is instructed to use it before drafting an answer. +// It never does the research itself. +// ----------------------------------------------- +AIAgent orchestratorAgent = chatClient.AsAIAgent( + name: "OrchestratorAgent", + instructions: """ + You are a travel guide assistant. For every destination question: + 1. ALWAYS call ResearchTopic first to get factual details. + 2. Use the returned facts to build a 2-3 sentence travel tip. + 3. Keep the tone friendly and engaging. + Never answer from your own knowledge without calling ResearchTopic. + """, + tools: [researchTool]); + +// ----------------------------------------------- +// Run — the orchestrator transparently calls the +// ResearchAgent behind the scenes for each question. +// ----------------------------------------------- +Console.WriteLine("=== Agent-to-Agent (A2A) Demo ==="); +Console.WriteLine(); + +// Turn 1 — orchestrator will call ResearchAgent for Tokyo facts +Console.WriteLine("Q: What should I know about visiting Tokyo?"); +var answer1 = await orchestratorAgent.RunAsync("What should I know about visiting Tokyo?"); +Console.WriteLine($"A: {answer1}"); +Console.WriteLine(); + +// Turn 2 — orchestrator calls ResearchAgent again for a different topic +Console.WriteLine("Q: Give me a travel tip for Cape Town."); +var answer2 = await orchestratorAgent.RunAsync("Give me a travel tip for Cape Town."); +Console.WriteLine($"A: {answer2}"); diff --git a/05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/app.cs b/05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/app.cs new file mode 100644 index 0000000..af1cab1 --- /dev/null +++ b/05.Providers/code_samples/dotNET/02-dotnet-agent-framework-ghmodel-a2a/app.cs @@ -0,0 +1,120 @@ +// File-based run: dotnet run app.cs +#:property UserSecretsId f1e2d3c4-b5a6-7890-cdef-012345678901 +#:package Microsoft.Extensions.AI@10.3.0 +#:package Microsoft.Extensions.AI.OpenAI@10.3.0 +#:package OpenAI@2.8.0 +#:package Microsoft.Agents.AI@1.0.0-rc1 +#:package Microsoft.Agents.AI.OpenAI@1.0.0-rc1 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.0.0 +#:package Microsoft.Extensions.Configuration.EnvironmentVariables@10.0.0 + +// ============================================================ +// AGENT-TO-AGENT (A2A) PATTERN +// +// In A2A, one agent treats another agent as a callable provider — +// a specialist it can delegate to on demand. +// +// This sample shows two agents: +// • ResearchAgent — a specialist that returns concise facts +// • OrchestratorAgent — wraps ResearchAgent as a tool and calls +// it automatically when it needs research to answer the user +// +// The key mechanism: +// AIFunctionFactory.Create(researchFunc, ...) — wraps the +// ResearchAgent's RunAsync as an AIFunction tool that the +// orchestrator can invoke just like any other tool. +// +// Compare with 07.Workflow where agents are wired into a fixed +// pipeline. Here the orchestrator decides at runtime whether and +// when to call the specialist agent. +// ============================================================ + +using System.ClientModel; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; +using OpenAI; + +var config = new ConfigurationBuilder() + .AddUserSecrets() + .AddEnvironmentVariables() + .Build(); + +var githubEndpoint = config["GITHUB_ENDPOINT"] ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set."); +var githubModel = config["GITHUB_MODEL_ID"] ?? "gpt-4o-mini"; +var githubToken = config["GITHUB_TOKEN"] ?? throw new InvalidOperationException("GITHUB_TOKEN is not set."); + +var openAIOptions = new OpenAIClientOptions { Endpoint = new Uri(githubEndpoint) }; +IChatClient chatClient = new OpenAIClient(new ApiKeyCredential(githubToken), openAIOptions) + .GetChatClient(githubModel) + .AsIChatClient(); + +// ----------------------------------------------- +// Agent 1 — ResearchAgent (the specialist provider) +// Focused, terse instructions: return facts only, +// no elaboration. This keeps the delegation output +// clean and easy for the orchestrator to re-use. +// ----------------------------------------------- +AIAgent researchAgent = chatClient.AsAIAgent( + name: "ResearchAgent", + instructions: """ + You are a concise research specialist. When given a topic or question, + respond with exactly 3-5 factual bullet points and nothing else. + No introductions, no conclusions, no extra commentary. + """); + +// ----------------------------------------------- +// A2A Bridge — wrap the ResearchAgent as a tool +// +// AIFunctionFactory.Create turns any .NET delegate into an AIFunction +// that a language model can call. By wrapping ResearchAgent.RunAsync +// here, the OrchestratorAgent can invoke it as a tool call — the +// same mechanism used for APIs and database queries. +// +// From the orchestrator's perspective, ResearchAgent is just another +// provider it can query; it does not know or care that the provider +// is itself an AI agent. +// ----------------------------------------------- +Func> researchFunc = + async (query) => (await researchAgent.RunAsync(query)).ToString(); + +var researchTool = AIFunctionFactory.Create( + (Func>)researchFunc, + name: "ResearchTopic", + description: "Delegates a research query to the ResearchAgent specialist. " + + "Returns 3-5 concise factual bullet points about the topic."); + +// ----------------------------------------------- +// Agent 2 — OrchestratorAgent (the coordinator) +// The orchestrator knows it has a ResearchTopic tool +// and is instructed to use it before drafting an answer. +// It never does the research itself. +// ----------------------------------------------- +AIAgent orchestratorAgent = chatClient.AsAIAgent( + name: "OrchestratorAgent", + instructions: """ + You are a travel guide assistant. For every destination question: + 1. ALWAYS call ResearchTopic first to get factual details. + 2. Use the returned facts to build a 2-3 sentence travel tip. + 3. Keep the tone friendly and engaging. + Never answer from your own knowledge without calling ResearchTopic. + """, + tools: [researchTool]); + +// ----------------------------------------------- +// Run — the orchestrator transparently calls the +// ResearchAgent behind the scenes for each question. +// ----------------------------------------------- +Console.WriteLine("=== Agent-to-Agent (A2A) Demo ==="); +Console.WriteLine(); + +// Turn 1 — orchestrator will call ResearchAgent for Tokyo facts +Console.WriteLine("Q: What should I know about visiting Tokyo?"); +var answer1 = await orchestratorAgent.RunAsync("What should I know about visiting Tokyo?"); +Console.WriteLine($"A: {answer1}"); +Console.WriteLine(); + +// Turn 2 — orchestrator calls ResearchAgent again for a different topic +Console.WriteLine("Q: Give me a travel tip for Cape Town."); +var answer2 = await orchestratorAgent.RunAsync("Give me a travel tip for Cape Town."); +Console.WriteLine($"A: {answer2}"); diff --git a/dotnet/AgentFrameworkSamples.slnx b/dotnet/AgentFrameworkSamples.slnx index 1cdc3a8..524a660 100644 --- a/dotnet/AgentFrameworkSamples.slnx +++ b/dotnet/AgentFrameworkSamples.slnx @@ -24,6 +24,7 @@ + From 52a0c38b4c7d6c4359e578359ce867d5e04034a7 Mon Sep 17 00:00:00 2001 From: Bruno Capuano Date: Sat, 21 Feb 2026 16:01:49 -0500 Subject: [PATCH 10/10] Add .NET samples for DevUI and OpenTelemetry tracing in evaluation and tracing documentation --- 08.EvaluationAndTracing/README.md | 75 ++++++++++++++++++++++++++++++- README.md | 2 +- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/08.EvaluationAndTracing/README.md b/08.EvaluationAndTracing/README.md index 91c341c..8114b89 100644 --- a/08.EvaluationAndTracing/README.md +++ b/08.EvaluationAndTracing/README.md @@ -46,4 +46,77 @@ While the DevUI is excellent for real-time visual debugging, observability throu The framework automatically emits events during an agent's run. By configuring a logger, you can direct these events to your console or a file. The provided samples demonstrate how to set up this logging to see a sequential trace of the agent's operations, giving you a complete picture for post-execution analysis and debugging. To review the sample code and learn how to configure the logger, check out the observability example here: -[tracer_aspire](./python/tracer_aspire/) \ No newline at end of file +[tracer_aspire](./python/tracer_aspire/) + +--- + +## .NET Code Samples + +### 1. DevUI (.NET) + +The DevUI is also available in .NET as an ASP.NET Core hosted application. It provides the same browser-based interface for testing, debugging, and tracing agent workflows. + +| Sample | Description | +|--------|-------------| +| [GHModel.dotNET.AI.Workflow.DevUI](./dotNET/GHModel.dotNET.AI.Workflow.DevUI/) | ASP.NET Core app hosting the Agent Framework DevUI via `MapDevUI()`. Registers a sequential FrontDesk→Reviewer workflow and opens an interactive browser UI at `http://localhost:50518/devui`. | + +**Setup** + +```bash +cd 08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI + +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +``` + +**Run** + +```bash +dotnet run +``` + +Open **http://localhost:50518/devui** to browse agent conversations, inspect individual message events, and debug tool calls interactively. + +--- + +### 2. OpenTelemetry Tracing (.NET) + +For persistent, structured telemetry — traces, metrics, and logs exported to an OTLP collector — see the OpenTelemetry sample in `09.Cases`: + +| Sample | Description | +|--------|-------------| +| [GHModel.dotNET.AI.Workflow.OpenTelemetry](../09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/) | Instruments a FrontDesk→Reviewer workflow with OpenTelemetry. Exports traces, metrics, and logs to the .NET Aspire dashboard via OTLP. Shows `TracerProvider` / `MeterProvider` setup, framework activity sources (`*Microsoft.Agents.AI`), custom spans, and HTTP client instrumentation. | + +**Setup** + +Start the .NET Aspire dashboard (local OTLP collector): + +```bash +docker run --rm -p 18888:18888 -p 4317:4317 mcr.microsoft.com/dotnet/nightly/aspire-dashboard:latest +``` + +```bash +cd 09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry + +dotnet user-secrets set "GITHUB_TOKEN" "" +dotnet user-secrets set "GITHUB_ENDPOINT" "https://models.inference.ai.azure.com" +dotnet user-secrets set "GITHUB_MODEL_ID" "gpt-4o-mini" +``` + +**Run** + +```bash +dotnet run +# or file-based: +dotnet run app.cs +``` + +Open **http://localhost:18888** to browse traces and metrics in the Aspire dashboard. + +| Telemetry capability | DevUI | OpenTelemetry | +|---|---|---| +| Real-time visual debugging | ✅ | ❌ | +| Persistent structured traces | ❌ | ✅ | +| Metrics (latency, counters) | ❌ | ✅ | +| Works without extra infrastructure | ✅ | requires OTLP collector | +| Best for | Development & debugging | Production observability | \ No newline at end of file diff --git a/README.md b/README.md index e936fbb..17373a1 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ This repository provides step-by-step tutorials and real-world examples covering | **[05.Providers](./05.Providers/README.md)** | MCP (Model Context Protocol) and Agent-to-Agent communication | [MCP with Microsoft Learn](./05.Providers/code_samples/dotNET/01-dotnet-agent-framework-aifoundry-mcp/AgentMCP.Console/)| [MCP with Microsoft Learn](./05.Providers/code_samples/python/01-python-agent-framework-aifoundry-mcp.ipynb) | | **[06.RAGs](./06.RAGs/README.md)** | Knowledge-enhanced agents with file search capabilities | [File Search RAG](./06.RAGs/code_samples/dotNET/dotnet-agent-framework-msfoundry-file-search/) | [File Search RAG](./06.RAGs/code_samples/python/python-agent-framework-msfoundry-file-search.ipynb) | | **[07.Workflow](./07.Workflow/README.md)** | Complex agent workflows and orchestration patterns | [Basic Workflow](./07.Workflow/code_samples/dotNET/01.dotnet-agent-framework-workflow-ghmodel-basic/)
[Sequential](./07.Workflow/code_samples/dotNET/02.dotnet-agent-framework-workflow-ghmodel-sequential/)
[Concurrent](./07.Workflow/code_samples/dotNET/03.dotnet-agent-framework-workflow-ghmodel-concurrent/)
[Conditional(MS Foundry)](./07.Workflow/code_samples/dotNET/04.dotnet-agent-framework-workflow-msfoundry-condition/) | [Basic Workflow](./07.Workflow/code_samples/python/01.python-agent-framework-workflow-ghmodel-basic.ipynb)
[Sequential](./07.Workflow/code_samples/python/02.python-agent-framework-workflow-ghmodel-sequential.ipynb)
[Concurrent](./07.Workflow/code_samples/python/03.python-agent-framework-workflow-ghmodel-concurrent.ipynb)
[Conditional(MS Foundry)](./07.Workflow/code_samples/python/04.python-agent-framework-workflow-aifoundry-condition.ipynb) | -| **[08.EvaluationAndTracing](./08.EvaluationAndTracing/README.md)** | Agent evaluation, debugging, and observability tools | [GitHub Models Workflow DevUI](./08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/) | [Single MS Foundry Agent DevUI](./08.EvaluationAndTracing/python/singe_msfoundry_agent_devui/)
[Multi-Agent GitHub Models DevUI](./08.EvaluationAndTracing/python/multi_workflow_ghmodel_devui/)
[Multi-Agent MS Foundry DevUI](./08.EvaluationAndTracing/python/multi_workflow_msfoundry_devui/)
[Multi-Agent Foundry Local DevUI](./08.EvaluationAndTracing/python/multi_workflow_foundrylocal_devui/)
| +| **[08.EvaluationAndTracing](./08.EvaluationAndTracing/README.md)** | Agent evaluation, debugging, and observability tools | [GitHub Models Workflow DevUI](./08.EvaluationAndTracing/dotNET/GHModel.dotNET.AI.Workflow.DevUI/)
[OpenTelemetry Tracing](./09.Cases/GHModel.AI/GHModel.dotNET.AI/GHModel.dotNET.AI.Workflow.OpenTelemetry/) | [Single MS Foundry Agent DevUI](./08.EvaluationAndTracing/python/singe_msfoundry_agent_devui/)
[Multi-Agent GitHub Models DevUI](./08.EvaluationAndTracing/python/multi_workflow_ghmodel_devui/)
[Multi-Agent MS Foundry DevUI](./08.EvaluationAndTracing/python/multi_workflow_msfoundry_devui/)
[Multi-Agent Foundry Local DevUI](./08.EvaluationAndTracing/python/multi_workflow_foundrylocal_devui/)
| | **[09.Cases](./09.Cases/README.md)** | Real-world case studies combining Foundry workflows with production-ready multi-agent applications | [Microsoft Foundry with AITK & MAF](./09.Cases/MicrosoftFoundryWithAITKAndMAF/README.md)
[GHModel Multi-Agent (.NET)](./09.Cases/GHModel.AI/GHModel.dotNET.AI/) | [Microsoft Foundry with AITK & MAF](./09.Cases/MicrosoftFoundryWithAITKAndMAF/README.md)
[GHModel Multi-Agent (Python)](./09.Cases/GHModel.AI/GHModel.Python.AI/)
[Agentic Marketing Content Generation](./09.Cases/AgenticMarketingContentGen/README.md)
[Foundry Local Pipeline](./09.Cases/FoundryLocalPipeline/README.md) | ## 🛠 Prerequisites