-
Notifications
You must be signed in to change notification settings - Fork 1.1k
.NET: Restructure .NET samples: progressive learning path (01→05) #3765
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
.NET: Restructure .NET samples: progressive learning path (01→05) #3765
Conversation
There was a problem hiding this 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-started→05-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 Functionslocal.settings.jsonfiles.
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> |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| <div>@((MarkupString)text)</div> | |
| <div>@text</div> |
| } | ||
|
|
||
| @code { | ||
| private static readonly ConditionalWeakTable<ChatMessage, ChatMessageItem> SubscribersLookup = new(); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
|
|
||
| protected override void OnInitialized() | ||
| { | ||
| SubscribersLookup.AddOrUpdate(Message, this); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| SubscribersLookup.AddOrUpdate(Message, this); | |
| SubscribersLookup.Remove(Message); | |
| SubscribersLookup.Add(Message, this); |
| 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 |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| 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 } | |
| ] | |
| }); |
| Ollama, | ||
| OpenAI, | ||
| AzureOpenAI, | ||
| AzureAIInference, |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| AzureAIInference, |
| 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' }); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| elem.scrollIntoView({ behavior: ChatMessages._isFirstAutoScroll ? 'instant' : 'smooth' }); | |
| elem.scrollIntoView({ behavior: ChatMessages._isFirstAutoScroll ? 'auto' : 'smooth' }); |
| } | ||
| else | ||
| { | ||
| throw new ArgumentException("Either A2AServer:ApiKey or A2AServer:ConnectionString & agentId must be provided"); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| 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"); |
| ChatClientAgent narrator = new( | ||
| chatClient, | ||
| """ | ||
| You are are the narrator of a puzzle involving knights (who always tell the truth) and knaves (who always lie). |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| 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). |
…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.
3f352b1 to
5aa9f39
Compare
Summary
Restructures the .NET samples into a clear progressive learning path with 5 sections:
Key design decisions
.csdemonstrates a single topic// <name>/// </name>tags for docs:::codereferencesEnvironment.GetEnvironmentVariable()with clear variable namesAIProjectClientWhat changed
_to_delete/for reviewer inspection (not deleted)README.mdwith new category structureRelated PRs
semantic-kernel-prrepo)