Skip to content

Conversation

@eavanvalkenburg
Copy link
Member

Summary

Restructures the .NET samples into a clear progressive learning path with 5 sections:

  • 01-get-started/ — 6 numbered steps (hello agent → hosting), each adding one concept
  • 02-agents/ — Deep-dive concept samples: tools/, middleware/, conversations/, providers/
  • 03-workflows/ — One folder per workflow pattern (sequential, concurrent, branching, HITL, etc.)
  • 04-hosting/ — Multi-project solutions: a2a, ag-ui, azure-functions, openai-endpoints
  • 05-end-to-end/ — Complete apps: agent-web-chat, agui-web-chat, m365-agent, purview

Key design decisions

  • One concept per file — each .cs demonstrates a single topic
  • Snippet tags — all samples include // <name> / // </name> tags for docs :::code references
  • Explicit env varsEnvironment.GetEnvironmentVariable() with clear variable names
  • Default provider — Azure AI Foundry via AIProjectClient
  • Single-file for 01-03 — top-level statements; 04/05 are multi-project solutions
  • AGENTS.md — documents structure, conventions, and file→docs mapping for future maintainers

What changed

  • ~90 new sample files created across 5 sections
  • ~624 old files moved to _to_delete/ for reviewer inspection (not deleted)
  • Updated README.md with new category structure

Related PRs

Copilot AI review requested due to automatic review settings February 9, 2026 16:04
@markwallace-microsoft markwallace-microsoft added documentation Improvements or additions to documentation .NET labels Feb 9, 2026
@github-actions github-actions bot changed the title Restructure .NET samples: progressive learning path (01→05) .NET: Restructure .NET samples: progressive learning path (01→05) Feb 9, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Restructures the .NET samples into a progressive learning path (01→05), adds/updates documentation to reflect the new layout, and stages legacy samples under _to_delete/ for review.

Changes:

  • Added new sample hierarchy (01-get-started05-end-to-end) with updated section-level READMEs and conventions.
  • Added many new single-file workflow/agent/tool/provider samples with docs snippet tags.
  • Moved older multi-project samples into dotnet/samples/_to_delete/ and removed several Azure Functions local.settings.json files.

Reviewed changes

Copilot reviewed 127 out of 817 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
dotnet/samples/AGENTS.md Documents the new sample structure, conventions, and docs mapping.
dotnet/samples/01-get-started/README.md Introduces the progressive “get started” steps and links deeper sections.
dotnet/samples/01-get-started/01_HelloAgent.cs Step 1 sample using Foundry default provider + snippet tags.
dotnet/samples/01-get-started/02_AddTools.cs Step 2 sample adding tools + streaming.
dotnet/samples/01-get-started/03_MultiTurn.cs Step 3 multi-turn conversation sample (Foundry conversations).
dotnet/samples/01-get-started/04_Memory.cs Step 4 memory sample using vector store + context provider.
dotnet/samples/01-get-started/05_FirstWorkflow.cs Step 5 workflow intro sample.
dotnet/samples/01-get-started/06_HostYourAgent.cs Step 6 hosting sample consuming A2A skills as tools.
dotnet/samples/02-agents/README.md Index for agents/tools/middleware/conversations/providers samples.
dotnet/samples/02-agents/BackgroundResponses.cs Demonstrates background responses polling/resumption.
dotnet/samples/02-agents/DeclarativeAgents.cs Demonstrates YAML-defined agents.
dotnet/samples/02-agents/Observability.cs Demonstrates OpenTelemetry for agents/chat clients.
dotnet/samples/02-agents/Rag.cs Demonstrates RAG with vector search.
dotnet/samples/02-agents/StructuredOutput.cs Demonstrates typed structured output and streaming deserialization.
dotnet/samples/02-agents/conversations/CustomStorage.cs Shows custom chat history storage via vector store.
dotnet/samples/02-agents/conversations/PersistentConversation.cs Shows session serialization/deserialization.
dotnet/samples/02-agents/middleware/*.cs Adds middleware concept samples (guardrails, PII, approval, etc.).
dotnet/samples/02-agents/providers/*.cs Adds provider samples (Foundry, Azure OpenAI, OpenAI, Anthropic, Ollama, Copilot, etc.).
dotnet/samples/02-agents/tools/*.cs Adds tool samples (function tools, approval, MCP, file/web search, code interpreter).
dotnet/samples/03-workflows/README.md Index for workflow patterns.
dotnet/samples/03-workflows//.cs Adds workflow pattern samples (sequential, branching, HITL, checkpoints, visualization, etc.).
dotnet/samples/04-hosting/README.md New hosting/protocol section index.
dotnet/samples/05-end-to-end/README.md New end-to-end apps section index.
dotnet/samples/Durable/Agents/AzureFunctions/*/local.settings.json Removes local settings files from Azure Functions samples.
dotnet/samples/_to_delete/** Stages legacy samples/projects for reviewer inspection (not deleted).

</div>
<div class="assistant-message-header">Assistant</div>
<div class="assistant-message-text">
<div>@((MarkupString)text)</div>
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rendering model-provided text as MarkupString will render raw HTML and can enable XSS (the model can output <script>/event handlers). Prefer rendering as plain text (default Blazor encoding), or sanitize/allowlist HTML before converting to MarkupString.

Suggested change
<div>@((MarkupString)text)</div>
<div>@text</div>

Copilot uses AI. Check for mistakes.
}

@code {
private static readonly ConditionalWeakTable<ChatMessage, ChatMessageItem> SubscribersLookup = new();
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConditionalWeakTable<TKey,TValue> does not have an AddOrUpdate API in the BCL. This will not compile unless a custom extension method is in scope (none is shown here). Use Remove + Add, or use GetValue/GetOrCreateValue patterns to register/update entries.

Copilot uses AI. Check for mistakes.

protected override void OnInitialized()
{
SubscribersLookup.AddOrUpdate(Message, this);
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConditionalWeakTable<TKey,TValue> does not have an AddOrUpdate API in the BCL. This will not compile unless a custom extension method is in scope (none is shown here). Use Remove + Add, or use GetValue/GetOrCreateValue patterns to register/update entries.

Suggested change
SubscribersLookup.AddOrUpdate(Message, this);
SubscribersLookup.Remove(Message);
SubscribersLookup.Add(Message, this);

Copilot uses AI. Check for mistakes.
Comment on lines +103 to +118
var csTask = cs.GetValueAsync(default).AsTask();
if (!csTask.IsCompletedSuccessfully)
{
throw new InvalidOperationException("Connection string could not be resolved!");
}

#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits
builder.WithInitialState(new CustomResourceSnapshot
{
ResourceType = "Azure AI Inference Model",
State = KnownResourceStates.Running,
Properties = [
new("ConnectionString", csTask.Result ) { IsSensitive = true }
]
});
#pragma warning restore VSTHRD002
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetValueAsync(...).AsTask() is very likely to be incomplete at this point, causing a throw in normal run mode. If you must resolve synchronously for WithInitialState, block explicitly (e.g., GetAwaiter().GetResult() under the pragma) or refactor to avoid resolving here (e.g., store the ReferenceExpression/defer snapshot population). As written, this can make startup fail nondeterministically.

Suggested change
var csTask = cs.GetValueAsync(default).AsTask();
if (!csTask.IsCompletedSuccessfully)
{
throw new InvalidOperationException("Connection string could not be resolved!");
}
#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits
builder.WithInitialState(new CustomResourceSnapshot
{
ResourceType = "Azure AI Inference Model",
State = KnownResourceStates.Running,
Properties = [
new("ConnectionString", csTask.Result ) { IsSensitive = true }
]
});
#pragma warning restore VSTHRD002
#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits
var connectionString = cs.GetValueAsync(default).GetAwaiter().GetResult();
#pragma warning restore VSTHRD002
builder.WithInitialState(new CustomResourceSnapshot
{
ResourceType = "Azure AI Inference Model",
State = KnownResourceStates.Running,
Properties = [
new("ConnectionString", connectionString ) { IsSensitive = true }
]
});

Copilot uses AI. Check for mistakes.
Ollama,
OpenAI,
AzureOpenAI,
AzureAIInference,
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClientChatProvider includes AzureAIInference, but the corresponding factory switch in ChatClientExtensions doesn’t handle it (it will throw NotSupportedException). Either add an AzureAIInference branch in the switch (and document the expected connection string keys), or remove the enum value to avoid advertising a supported provider that cannot be constructed.

Suggested change
AzureAIInference,

Copilot uses AI. Check for mistakes.
const addedUserMessage = mutations.some(m => Array.from(m.addedNodes).some(n => n.parentElement === this && n.classList?.contains('user-message')));
const elem = this.lastElementChild;
if (ChatMessages._isFirstAutoScroll || addedUserMessage || this._elemIsNearScrollBoundary(elem, 300)) {
elem.scrollIntoView({ behavior: ChatMessages._isFirstAutoScroll ? 'instant' : 'smooth' });
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scrollIntoView’s behavior values are typically 'auto' | 'smooth'. 'instant' is not consistently supported across browsers and may be ignored. Consider using 'auto' for the first scroll to ensure cross-browser behavior.

Suggested change
elem.scrollIntoView({ behavior: ChatMessages._isFirstAutoScroll ? 'instant' : 'smooth' });
elem.scrollIntoView({ behavior: ChatMessages._isFirstAutoScroll ? 'auto' : 'smooth' });

Copilot uses AI. Check for mistakes.
}
else
{
throw new ArgumentException("Either A2AServer:ApiKey or A2AServer:ConnectionString & agentId must be provided");
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message references configuration keys (A2AServer:ApiKey / A2AServer:ConnectionString) that aren’t what the code reads (it reads OPENAI_API_KEY and AZURE_FOUNDRY_PROJECT_ENDPOINT, plus agentId). Update the message to match the actual required inputs so users can fix the configuration quickly.

Suggested change
throw new ArgumentException("Either A2AServer:ApiKey or A2AServer:ConnectionString & agentId must be provided");
throw new ArgumentException("Either OPENAI_API_KEY or AZURE_FOUNDRY_PROJECT_ENDPOINT and agentId must be provided");

Copilot uses AI. Check for mistakes.
ChatClientAgent narrator = new(
chatClient,
"""
You are are the narrator of a puzzle involving knights (who always tell the truth) and knaves (who always lie).
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct the duplicated word 'are' in the prompt text.

Suggested change
You are are the narrator of a puzzle involving knights (who always tell the truth) and knaves (who always lie).
You are the narrator of a puzzle involving knights (who always tell the truth) and knaves (who always lie).

Copilot uses AI. Check for mistakes.
…o _to_delete

New structure:
- 01-get-started/ (6 progressive samples, single-file .cs)
- 02-agents/ (tools, middleware, conversations, providers)
- 03-workflows/ (9 workflow patterns)
- 04-hosting/ (a2a, ag-ui, azure-functions, openai-endpoints - multi-project)
- 05-end-to-end/ (full apps)
- _to_delete/ (old samples for reviewer reference)

Uses Azure AI Foundry Responses API via AIProjectClient as default provider.
Old files preserved in _to_delete/ for review before deletion.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation .NET

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants