Compare commits

...
Author SHA1 Message Date
Tao Chen 565933a829 Fix more workflow samples 2026-03-30 17:15:57 -07:00
Tao Chen bfd2f671d5 Fix workflows HIL sample 2026-03-30 11:56:44 -07:00
Tao Chen 120a9f4c42 Increase idle timeout 2026-03-30 09:41:41 -07:00
Tao Chen c305017b4e Merge branch 'main' into local-branch-fix-samples-and-sample-validation 2026-03-30 08:15:48 -07:00
CopilotGitHubrogerbarretocopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
4527dee64b Python: fix: update PyRIT repository link from Azure/PyRIT to microsoft/PyRIT (#4960)
* Initial plan

* fix: update PyRIT repository link from Azure/PyRIT to microsoft/PyRIT

Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/830b8ccf-a79c-49b6-90c9-3bb3e740bc06

Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>
2026-03-30 14:48:08 +00:00
f45fc7d402 .NET: [Breaking] Update Foundry Agents for Responses API (#4502)
* Stage

* Add FoundryAgentClient, model param, chatClientFactory, and RAPI samples

- Add model parameter to FoundryAgentClient simple constructor
- Add chatClientFactory parameter to both constructors
- Switch to OpenAI.GetProjectResponsesClientForModel for direct Responses API usage
- Add FoundryAgents-RAPI samples (Step01 Basics, Step02 Multiturn, Step03 FunctionTools)
- Add solution folder entry for FoundryAgents-RAPI samples

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add auto-discovery constructor and simplify RAPI samples

- Add FoundryAgentClient constructor that reads AZURE_AI_PROJECT_ENDPOINT and
  AZURE_AI_MODEL_DEPLOYMENT_NAME from environment variables with DefaultAzureCredential
- Simplify RAPI samples to use auto-discovery (no env var or credential code)
- Remove Azure.Identity direct references from sample csproj files
- Update READMEs to document environment variable requirements

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add remaining RAPI samples (Step04-Step12)

- Step04: Function tools with human-in-the-loop approvals
- Step05: Structured output with typed responses
- Step06: Persisted conversations with session serialization
- Step07: Observability with OpenTelemetry
- Step08: Dependency injection with hosted service
- Step10: Image multi-modality
- Step11: Agent as function tool (agent composition)
- Step12: Middleware (PII, guardrails, function logging, HITL approval)
- Update solution file and folder README with all new samples

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add all RAPI samples (Step09-Step23) and switch to AzureCliCredential

- Step09: MCP client as tools (GitHub server via stdio)
- Step13: Plugins with dependency injection
- Step14: Code Interpreter tool
- Step15: Computer Use tool with screenshot simulation
- Step16: File Search with vector stores
- Step17: OpenAPI tools (REST Countries API)
- Step18: Bing Custom Search
- Step19: SharePoint grounding
- Step20: Microsoft Fabric
- Step21: Web Search with citations
- Step22: Memory Search with multi-turn conversations
- Step23: Local MCP via HTTP (Microsoft Learn)
- Switch all samples (Step04-Step12) to use AzureCliCredential with env vars
- Update solution file and README with all 23 samples
- All 23 samples build successfully, tested Step05/06/11/13/21

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Switch Step01-03 samples to AzureCliCredential for consistency

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Clarify connection ID format in SharePoint and Fabric READMEs

Document that SHAREPOINT_PROJECT_CONNECTION_ID and FABRIC_PROJECT_CONNECTION_ID
should use the connection name (e.g., 'SharepointTestTool'), not the full ARM
resource URI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Normalize env vars, fix structured output, update READMEs with connection ID formats

- Normalize AZURE_FOUNDRY_PROJECT_* env vars to AZURE_AI_PROJECT_ENDPOINT / AZURE_AI_MODEL_DEPLOYMENT_NAME across all samples (Steps 18-22 READMEs + Steps 19-20 Program.cs)
- Fix RAPI Step05 StructuredOutput to use full constructor with ResponseFormat for streaming JSON
- Update Deep Research sample to use AzureCliCredential
- Enrich Bing Grounding README with full ARM resource URI format
- Fix Bing Custom Search README env var mismatch (BING_CUSTOM_SEARCH_* -> AZURE_AI_CUSTOM_SEARCH_*)
- Add finding instructions for connection ID and instance name in Bing Custom Search READMEs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Refactor memory samples and switch to DefaultAzureCredential

- Refactor RAPI Step22 MemorySearch: extract store setup to EnsureMemoryStoreAsync local function
- Refactor non-RAPI Step22 MemorySearch: same pattern with explicit memory lifecycle
- Set UpdateDelay=0 on MemoryUpdateOptions and MemorySearchPreviewTool for faster ingestion
- Use WaitForMemoriesUpdateAsync with 500ms polling interval
- Switch Step19 SharePoint, Step20 Fabric, Step22 MemorySearch (both) to DefaultAzureCredential
- Remove SearchOptions from MemorySearchPreviewTool (causes unknown parameter error)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Switch all RAPI samples to DefaultAzureCredential and format

- Replace AzureCliCredential with DefaultAzureCredential across all 20 RAPI samples
- Run dotnet format on all RAPI and non-RAPI Foundry samples
- AzureAI unit tests: 341 passed (net10.0 + net472)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Rename to Microsoft Foundry, add metadata, rename RAPI folder

- Replace 'Azure AI Foundry' / 'Azure Foundry' with 'Microsoft Foundry' in all docs, comments, and XML docs
- Update FoundryAgentClient metadata provider name to 'microsoft.foundry'
- Rename FoundryAgents-RAPI folder to FoundryResponseAgents
- Rewrite FoundryResponseAgents README with comparison table vs Foundry Agents
- Update slnx and parent README with new folder references

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR review: simplify sample comments and fix DeepResearch credential

- Remove 'no server-side agent' and 'Responses API directly' phrasing from comments
- Simplify to 'Create a FoundryAgentClient' per review feedback
- Switch Agent_Step15_DeepResearch to DefaultAzureCredential

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Restore full DefaultAzureCredential warning comment in DeepResearch sample

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add ADR 0020: Foundry agent type naming convention

Proposes naming options for a new MAF type wrapping versioned
Foundry agents (Prompt, ContainerApp, Hosted, Workflow) to
distinguish from the existing FoundryResponsesAgent (RAPI path).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Simplify FoundryResponsesAgent samples with env-var constructors and rename folders

- Add env-var constructors to FoundryResponsesAgent (simple + options-based)
- Fix Constructor 1 model optionality (no longer throws on missing AZURE_AI_MODEL_DEPLOYMENT_NAME)
- Add ApplyModelDeploymentFallback helper for options-based constructor
- Update all 23 FoundryResponseAgents samples to remove Environment.GetEnvironmentVariable boilerplate
- Condense 6 simple samples to one-liner constructor calls
- Add XML doc remarks about auto-resolved parameters on all constructors
- Rename FoundryAgents -> FoundryVersionedAgents (server-side, versioned)
- Rename FoundryResponseAgents -> FoundryAgents (now the default path forward)
- Update .slnx and README cross-references for new folder names

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add FoundryAITool factory, rename RAPI folders, and clean up references

- Create FoundryAITool static factory class with 17 methods wrapping AgentTool.Create* and ResponseTool.Create* into AITool returns
- Rename 23 FoundryAgentsRAPI_* subfolders to FoundryAgents_* (drop RAPI prefix)
- Rename .csproj files and update .slnx references accordingly
- Update 12 samples (6 FoundryAgents + 6 FoundryVersionedAgents) to use FoundryAITool
- Replace all FoundryResponsesAgent references with FoundryAgent in comments and READMEs
- Update sample READMEs to reference FoundryAITool methods

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Rename FoundryVersionedAgents subfolders from FoundryAgents_* to FoundryVersionedAgents_*

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add FoundryVersionedAgent class and refactor extension method internals

- Create FoundryVersionedAgent with private ctor and async static factory methods
  (CreateAIAgentAsync/GetAIAgentAsync) with env-var and explicit endpoint tiers
- Extract shared internal helpers from AzureAIProjectChatClientExtensions:
  CreateChatClientAgent, CreateAgentVersionFromOptionsAsync,
  CreateAgentVersionWithProtocolAsync (tools overload),
  CreateChatClientAgentOptions, GetAgentRecordByNameAsync, ThrowIfInvalidAgentName
- Extension methods now delegate to shared internal helpers
- All 49 existing samples continue to build successfully

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add CreateConversationSessionAsync, DeleteAIAgentAsync, auto-resolve model, simplify samples

- Add CreateConversationSessionAsync to FoundryAgent and FoundryVersionedAgent
  (returns ChatClientAgentSession, creates server-side conversation + session in one call)
- Add DeleteAIAgentAsync static method to FoundryVersionedAgent
- Make model parameter optional in env-var factory overloads (auto-resolves from
  AZURE_AI_MODEL_DEPLOYMENT_NAME)
- Update all FoundryVersionedAgents samples to use DeleteAIAgentAsync
- Remove deploymentName env var from samples where only used for model parameter
- Use CreateConversationSessionAsync in Step02_MultiturnConversation
- Use explicit types instead of var for agent/session variables
- All 49 samples build successfully

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove manual AIProjectClient construction from FoundryVersionedAgents samples

- Replace manual AIProjectClient construction with GetService<AIProjectClient>()
  from the FoundryVersionedAgent in all dual-option and tool-specific samples
- Remove AZURE_AI_PROJECT_ENDPOINT env var reads from updated samples
- Remove Azure.Identity usings where no longer needed
- Only Step01.1, Step01.2, Eval_Step01 retain manual construction (pedagogical samples)
- All 49 samples build successfully

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Replace aiProjectClient extension calls with FoundryVersionedAgent factories in all samples

- Replace aiProjectClient.CreateAIAgentAsync with FoundryVersionedAgent.CreateAIAgentAsync
  in Option 2 (Native SDK) paths across Steps 14-21
- Replace aiProjectClient.Agents.DeleteAgentAsync with FoundryVersionedAgent.DeleteAIAgentAsync
- Remove unused AIProjectClient variables and using directives
- Only Step01.1, Step01.2, Eval_Step01 retain direct AIProjectClient usage (pedagogical)
- Step16, Step22 use GetService<AIProjectClient>() for file/memory operations

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove unused using directives from Step01.2, Step09, Eval_Step02

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update ADR 0020 with accepted decision: Option 6

- Add Option 6 detailing FoundryAgent, FoundryVersionedAgent, FoundryAITool,
  env-var auto-discovery, and self-contained factory patterns
- Mark decision as accepted with rationale
- Update current state and metadata sections

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update Step01 basics samples to use FoundryVersionedAgent factories

- Step01.1: Replace manual AIProjectClient/AsAIAgent with FoundryVersionedAgent.CreateAIAgentAsync/GetAIAgentAsync/DeleteAIAgentAsync
- Step01.2: Replace manual AIProjectClient with FoundryVersionedAgent.CreateAIAgentAsync/DeleteAIAgentAsync
- Remove env var boilerplate and Azure.Identity dependency

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add DeleteAIAgentVersionAsync to FoundryVersionedAgent

- DeleteAIAgentAsync: deletes the agent and all its versions (existing)
- DeleteAIAgentVersionAsync: deletes only the specific version associated with the agent instance
- Internally delegates to Agents.DeleteAgentAsync vs Agents.DeleteAgentVersionAsync

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix cleanup comments: DeleteAIAgentAsync deletes the agent and all its versions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update all FoundryVersionedAgents READMEs for FoundryVersionedAgent and auto-discovery

- Rewrite main README with FoundryVersionedAgent usage, auto-discovery table, code example
- Fix sample table links from FoundryAgents_Step* to FoundryVersionedAgents_Step*
- Add FoundryAITool references in tool-specific sample descriptions
- Update individual READMEs: fix stale paths, add auto-discovery note after env var blocks
- Update tool references: AgentTool/ResponseTool -> FoundryAITool
- Update parent 02-agents/README.md with FoundryVersionedAgent description

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Revert unrelated AGUI and Hosting.OpenAI formatting changes to main

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove env-var auto-discovery, add AsAIAgent, mark extensions Obsolete

- Remove 2 env-var constructors from FoundryAgent (keep explicit endpoint ctors)
- Remove 5 env-var factory methods from FoundryVersionedAgent (keep explicit ones)
- Add 3 AsAIAgent static methods to FoundryVersionedAgent (AgentVersion/AgentRecord/AgentReference)
- Mark all 8 AIProjectClient extension methods as [Obsolete] pointing to FoundryVersionedAgent
- Remove ApplyModelDeploymentFallback, env var constants, Azure.Identity usings from source

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update all samples to use explicit endpoint, credential, and model parameters

- Add explicit Environment.GetEnvironmentVariable reads for AZURE_AI_PROJECT_ENDPOINT
  and AZURE_AI_MODEL_DEPLOYMENT_NAME to all 48 sample files
- Pass new Uri(endpoint), new DefaultAzureCredential(), deploymentName to
  FoundryAgent constructors and FoundryVersionedAgent factory methods
- Add using Azure.Identity where missing
- Matches repo-wide pattern used by other non-Foundry samples
- All 49 samples build successfully

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate remaining samples and source from obsoleted extension methods

- Migrate AgentProviders, AgentWithRAG, AgentWithMemory, HostedWorkflow samples to FoundryVersionedAgent
- Migrate AzureAgentProvider.cs to FoundryVersionedAgent.AsAIAgent
- Migrate AzureAIProjectChatClientTests.cs to FoundryVersionedAgent.GetAIAgentAsync
- Remove pragma suppressions from migrated files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add unit tests for FoundryAgent and FoundryVersionedAgent

- FoundryAgentTests.cs: 14 tests covering constructors, validation,
  properties, metadata, GetService, chat client factory, user-agent header
- FoundryVersionedAgentTests.cs: 31 tests covering CreateAIAgentAsync,
  GetAIAgentAsync, AsAIAgent (3 overloads), DeleteAIAgentAsync,
  DeleteAIAgentVersionAsync, validation, invalid names, metadata, GetService

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Finalize Foundry agent migration

Align FoundryAgent and FoundryVersionedAgent samples, docs, and tests with the explicit configuration model, clean up stale README guidance, and fix AzureAI unit test validation/build issues.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Apply formatter cleanup after validation

Capture the dotnet format follow-up changes produced during branch validation so the committed state matches the successfully built and tested branch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add integration tests for FoundryAgent and FoundryVersionedAgent

Mark old AIProjectClient extension-method integration tests as obsolete and add new integration test suites for both FoundryAgent (Responses API) and FoundryVersionedAgent (versioned agents). All 71 non-skipped tests pass against the live Foundry service.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update ADR 0020 with test coverage details

Add integration test coverage note to the Current State section of ADR 0020.

* Simplify Foundry agents and validate moved samples

* Rename FoundryAgent integration tests to ResponsesAgent

The test classes exercise the non-versioned Responses path via
AIProjectClient.AsAIAgent(), not the removed FoundryAgent wrapper type.
Rename files and class names to reflect the actual test surface.

* Update documentation for ChatClientAgent usage

Added example usage of ChatClientAgent with JokerAgent.

* Refactor ChatClientAgent instantiation for clarity

* Revise agent type naming and usage examples

Updated documentation to reflect changes in agent creation methods and added examples for using `ChatClientAgent`.

* Fix Azure SDK namespace migration after rebase

Update Azure.AI.Projects.OpenAI references to Azure.AI.Projects.Agents
and Azure.AI.Extensions.OpenAI to match Azure.AI.Projects 2.0.0-beta.2.

- Replace deprecated namespace across samples, tests, and src
- Fix renamed types: OpenAPIFunctionDefinition -> OpenApiFunctionDefinition,
  BingCustomSearchToolParameters -> BingCustomSearchToolOptions,
  BrowserAutomationToolParameters -> BrowserAutomationToolOptions
- Fix API changes: AgentRecord.Versions -> GetLatestVersion(),
  ResponsesClient constructor, FunctionApprovalRequestContent ->
  ToolApprovalRequestContent
- Apply dotnet format

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address merge markers

* Replace obsolete GetAIAgentAsync with AsAIAgent in samples

Switch Agent_Step07_AsMcpTool and A2AServer to use the non-obsolete
PersistentAgentsClient.AsAIAgent(PersistentAgent) extension instead
of the deprecated GetAIAgentAsync, fixing CS0618 build errors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix broken markdown links in Responses sample READMEs

Replace stale ChatClientAgents_Step* folder references with the
correct Agent_Step* names across all Responses sample READMEs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix format errors and address PR review comments

- Fix charset and remove unused using in AzureAIProjectResponsesChatClient
- Fix doc comment tags (code -> c) in FoundryAITool
- Fix stray period in LocalMCP sample comment
- Fix grammar in FoundryMemoryProvider xmldoc
- Fix AIProjectClientAgentRunStreamingConversationTests base class

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Apply dotnet format fixes to PR-changed files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix build errors from format pass and apply naming conventions

- Fix static call to CreateSessionAsync in Step02 samples and extension tests
- Use expression-bodied lambda in FoundryMemoryProvider (RCS1021)
- Apply PascalCase naming to const fields in ResponsesAgentExtensionCreateTests (IDE1006)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Introduce FoundryAgent sealed type and update AsAIAgent extensions

- Add FoundryAgent sealed class wrapping ChatClientAgent with:
  - Public ctors: (projectEndpoint, credential, model, instructions) and (agentEndpoint, credential)
  - Internal ctor: (AIProjectClient, ChatClientAgent) for extension use
  - CreateConversationSessionAsync() for server-side conversations
  - GetService<ChatClientAgent>() and GetService<AIProjectClient>()
  - MEAI user-agent policy on internally-created AIProjectClient
- Change all AsAIAgent extension return types from ChatClientAgent to FoundryAgent
- Update all samples and tests to use FoundryAgent type
- Add 16 FoundryAgentTests covering ctors, GetService, UserAgent, RunAsync
- Fix pre-existing Agent_Step12_Plugins build error

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Collapse sample folders and add FoundryAgent_Step01 sample

- Move all Responses/* samples up to AgentsWithFoundry/ (flat structure)
- Remove entire Versioned/ folder (26 samples)
- Add FoundryAgent_Step01 sample showing direct FoundryAgent ctor usage
- Update slnx to reflect flat folder structure
- Fix csproj ProjectReference paths for new depth

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update READMEs for flat AgentsWithFoundry structure

- Rewrite AgentsWithFoundry/README.md with FoundryAgent quick start
- Fix cd commands and paths in 11 sample READMEs
- Update 02-agents/README.md to single Foundry link
- Update AGENTS.md tree to flat structure
- Fix AgentWithMemory cross-reference

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix FoundryAgent_Step01 sample with full create/run/delete lifecycle

Show the complete server-side agent lifecycle: create version with
native SDK, wrap as FoundryAgent via AsAIAgent, run, then delete.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Revert RAPI samples to use AIAgent instead of FoundryAgent

RAPI samples should not reference FoundryAgent directly. Restored
original sample code with only ChatClientAgent -> AIAgent type change
to accommodate the AsAIAgent return type.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Convert versioned-pattern samples to pure RAPI

Step09, Step13, Step17, Step22 were using CreateAgentVersionAsync +
PromptAgentDefinition which is the versioned pattern. Converted to
use AsAIAgent(model, instructions, tools) which is the RAPI path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix format issues from Docker CI check

- FoundryAgent_Step01: CRLF -> LF
- Agent_Step09: missing final newline
- Agent_Step11_Middleware: add internal modifier, final newline
- Agent_Step02: remove redundant cast (IDE0004)
- Agent_Step08: simplify name (IDE0001)
- FoundryAgentTests: s_ prefix, Async suffix naming conventions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Switch Step09 MCP sample to Microsoft Learn HTTP endpoint

Replace npx stdio GitHub MCP server with the public Microsoft Learn
MCP endpoint (https://learn.microsoft.com/api/mcp) using HTTP transport.
No external tooling required to run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix missing final newline in Step09 MCP sample

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR review: use DelegatingAIAgent, clean up Step01 sample

- FoundryAgent now inherits DelegatingAIAgent instead of AIAgent,
  removing manual delegation boilerplate (westey-m feedback)
- Simplified Agent_Step01_Basics to single agent creation path,
  moved composable IChatClient approach to README (westey-m feedback)
- Fixed FoundryAgentTests param name assertion

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update sample using Project specialized type instead

* Address PR review feedback: DefaultAzureCredential warnings, sample simplifications, format fixes

- Add DefaultAzureCredential production warning comments to ~25 samples
- Simplify Anthropic and OpenAI Step01 samples to single agent
- Convert Step11 Middleware regex patterns to [GeneratedRegex]
- Remove unnecessary cleanup comment from Step06
- Fix Step09 README MCP transport description
- Enhance FoundryAgent xmldoc with non-persistent agent comparison

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Split Step02, simplify RAG Step04, sharpen Step23 differentiation

- Split Step02 into 02.1 (simple multi-turn via sessions) and 02.2 (server-side conversations via CreateConversationSessionAsync)
- RAG Step04: replace HostedFileSearchTool + MEAI wrapping with native OpenAI FileSearchTool
- Step23: clarify DelegatingAIFunction wrapping pattern vs Step09 basic MCP

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix Hosted MCP sample: use ResponseTool.CreateMcpTool and move tool to PromptAgentDefinition

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix broken README link after Step02 split

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address Sergey round 3 feedback: branding, README nav, sample rename

- Replace 'Azure AI Foundry' with 'Microsoft Foundry' in ADR 0020
- Fix 3 READMEs: 'ChatClientAgents' → 'AgentsWithFoundry' sample directory
- Rename FoundryAgent_Step01 → Agent_Step00_FoundryAgentLifecycle for naming consistency

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-30 12:09:02 +00:00
ca02146ee4 .NET: BugFix #3433 ChatClientAgent streaming responses missing messageid (#4615)
* Changes

* Fix ChatClientAgent streaming responses missing MessageId

Generate fallback MessageId in ChatClientAgent.RunCoreStreamingAsync when
the underlying LLM provider does not set ChatResponseUpdate.MessageId.
Without a MessageId the AGUI converter's null==null check silently drops
all text content, causing CopilotKit Zod validation errors.

Changes:
- ChatClientAgent: generate msg_{Guid} fallback via ??= in streaming loop
- AgentResponseExtensions: sync wrapper MessageId back to RawRepresentation
  in AsChatResponseUpdate() so downstream consumers see the value
- Add unit tests for both fixes and AGUI streaming MessageId scenarios

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR #4615 review comments

- Fix MessageId seeding: use first-seen provider MessageId (or generate
  fallback) and apply consistently to all chunks in the stream, preventing
  message splitting when providers set MessageId only on the first chunk
- Add test for mixed MessageId scenario (first chunk only)
- Fix skipped TextStreaming test: assert Empty (not NotEmpty) to match
  actual null==null behavior
- Fix skipped ToolCalls test: assert empty ParentMessageId to match
  actual empty-string passthrough behavior

* Handle empty MessageId in AsChatResponseUpdate sync

Treat empty/whitespace MessageId the same as null when syncing from
the AgentResponseUpdate wrapper back to RawRepresentation. Providers
that return empty string MessageId (e.g. tool call responses) now get
the wrapper value recovered correctly.

Add test for empty string MessageId recovery scenario.

* Move MessageId fallback generation to AGUI layer

Move fallback MessageId generation from ChatClientAgent to
AsAGUIEventStreamAsync, addressing the architectural concern that
MessageId is nullable in the AIAgent abstraction and the requirement
for non-null values is specific to the AGUI protocol.

The AGUI layer now generates a fallback MessageId for null or
empty/whitespace values, covering all agent types (not just
ChatClientAgent) including external implementations.

Changes:
- Revert MessageId generation from ChatClientAgent.RunCoreStreamingAsync
- Add fallback MessageId generation in AsAGUIEventStreamAsync for
  null/empty MessageId values (handles both null and whitespace)
- Unskip and update AGUI tests to verify fallback generation
- Update ChatClientAgent tests to reflect passthrough behavior

* Revert AsChatResponseUpdate MessageId sync-back

Remove the MessageId sync-back logic from AsChatResponseUpdate() as it
is no longer needed. With fallback generation moved to the AGUI layer,
the abstraction layer should not mutate the RawRepresentation object.

Revert to the original passthrough behavior for AsChatResponseUpdate()
and update tests accordingly.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-30 11:55:30 +00:00
3627b9b911 .NET: Skip flaky integration tests blocking merge queue (#4972)
* Skip flaky integration tests blocking merge queue

Skip 7 timing-dependent integration tests that are causing a 73% failure
rate in the merge queue over the past 3 days. All failures are
LLM-latency/timeout related and occur across unrelated PRs.

Skipped tests:
- ConsoleAppSamplesValidation.ReliableStreamingSampleValidationAsync
- ConsoleAppSamplesValidation.SingleAgentOrchestrationHITLSampleValidationAsync
- ConsoleAppSamplesValidation.LongRunningToolsSampleValidationAsync
- SamplesValidation.LongRunningToolsSampleValidationAsync (AzureFunctions)
- SamplesValidation.ReliableStreamingSampleValidationAsync (AzureFunctions)
- ExternalClientTests.CallFunctionToolsAsync
- ExternalClientTests.CallLongRunningFunctionToolsAsync

Tracking issue: https://github.com/microsoft/agent-framework/issues/4971

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Extract skip reason to const per review feedback

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-30 10:51:21 +00:00
Tao Chen 6c44d04950 Correct env vars 2026-03-25 14:03:53 -07:00
Tao Chen f74b527f78 Fix workflow dependency 2026-03-25 11:39:13 -07:00
Tao Chen f7831be114 Fix workflow samples 2026-03-25 11:35:31 -07:00
Tao Chen e6a86b4d87 Fix sample paths 2026-03-25 11:13:05 -07:00
Tao Chen 5f68216863 First samples 1st batch 2026-03-25 11:00:17 -07:00
263 changed files with 4554 additions and 4206 deletions
@@ -34,7 +34,7 @@ runs:
- name: Test Copilot CLI
shell: bash
run: copilot -p "What can you do in one sentence?"
run: copilot --version && copilot -p "What can you do in one sentence?"
- name: Azure CLI Login
uses: azure/login@v2
+29 -94
View File
@@ -67,11 +67,13 @@ jobs:
# Azure AI configuration
AZURE_AI_PROJECT_ENDPOINT: ${{ vars.AZURE_AI_PROJECT_ENDPOINT }}
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
# Azure OpenAI configuration
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__EMBEDDINGDEPLOYMENTNAME }}
AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }}
# OpenAI configuration
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }}
@@ -97,6 +99,8 @@ jobs:
- name: Create .env for samples
run: |
echo "FOUNDRY_PROJECT_ENDPOINT=$FOUNDRY_PROJECT_ENDPOINT" >> .env
echo "FOUNDRY_MODEL=$FOUNDRY_MODEL" >> .env
echo "AZURE_AI_PROJECT_ENDPOINT=$AZURE_AI_PROJECT_ENDPOINT" >> .env
echo "AZURE_AI_MODEL_DEPLOYMENT_NAME=$AZURE_AI_MODEL_DEPLOYMENT_NAME" >> .env
echo "AZURE_OPENAI_ENDPOINT=$AZURE_OPENAI_ENDPOINT" >> .env
@@ -125,6 +129,7 @@ jobs:
environment: integration
env:
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
OPENAI_MODEL: ${{ vars.OPENAI__CHATMODELID }}
OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }}
OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }}
defaults:
@@ -144,6 +149,7 @@ jobs:
- name: Create .env for samples
run: |
echo "OPENAI_API_KEY=$OPENAI_API_KEY" >> .env
echo "OPENAI_MODEL=$OPENAI_MODEL" >> .env
echo "OPENAI_CHAT_MODEL_ID=$OPENAI_CHAT_MODEL_ID" >> .env
echo "OPENAI_RESPONSES_MODEL_ID=$OPENAI_RESPONSES_MODEL_ID" >> .env
@@ -158,8 +164,8 @@ jobs:
name: validation-report-02-agents-openai
path: python/samples/sample_validation/reports/
validate-02-agents-azure-openai:
name: Validate 02-agents/providers/azure_openai
validate-02-agents-azure:
name: Validate 02-agents/providers/azure
runs-on: ubuntu-latest
environment: integration
env:
@@ -190,93 +196,13 @@ jobs:
- name: Run sample validation
run: |
cd scripts && uv run python -m sample_validation --subdir 02-agents/providers/azure_openai --save-report --report-name 02-agents-azure-openai
cd scripts && uv run python -m sample_validation --subdir 02-agents/providers/azure --save-report --report-name 02-agents-azure
- name: Upload validation report
uses: actions/upload-artifact@v7
if: always()
with:
name: validation-report-02-agents-azure-openai
path: python/samples/sample_validation/reports/
validate-02-agents-azure-ai:
name: Validate 02-agents/providers/azure_ai
runs-on: ubuntu-latest
environment: integration
env:
AZURE_AI_PROJECT_ENDPOINT: ${{ vars.AZURE_AI_PROJECT_ENDPOINT }}
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
AZURE_AI_CHAT_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__EMBEDDINGDEPLOYMENTNAME }}
BING_CONNECTION_ID: ${{ secrets.BING_CONNECTION_ID }}
defaults:
run:
working-directory: python
steps:
- uses: actions/checkout@v6
- name: Setup environment
uses: ./.github/actions/sample-validation-setup
with:
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
os: ${{ runner.os }}
- name: Create .env for samples
run: |
echo "AZURE_AI_PROJECT_ENDPOINT=$AZURE_AI_PROJECT_ENDPOINT" >> .env
echo "AZURE_AI_MODEL_DEPLOYMENT_NAME=$AZURE_AI_MODEL_DEPLOYMENT_NAME" >> .env
echo "AZURE_AI_CHAT_MODEL_DEPLOYMENT_NAME=$AZURE_AI_CHAT_MODEL_DEPLOYMENT_NAME" >> .env
echo "AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME=$AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME" >> .env
echo "BING_CONNECTION_ID=$BING_CONNECTION_ID" >> .env
- name: Run sample validation
run: |
cd scripts && uv run python -m sample_validation --subdir 02-agents/providers/azure_ai --save-report --report-name 02-agents-azure-ai
- name: Upload validation report
uses: actions/upload-artifact@v7
if: always()
with:
name: validation-report-02-agents-azure-ai
path: python/samples/sample_validation/reports/
validate-02-agents-azure-ai-agent:
name: Validate 02-agents/providers/azure_ai_agent
runs-on: ubuntu-latest
environment: integration
env:
AZURE_AI_PROJECT_ENDPOINT: ${{ vars.AZURE_AI_PROJECT_ENDPOINT }}
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
defaults:
run:
working-directory: python
steps:
- uses: actions/checkout@v6
- name: Setup environment
uses: ./.github/actions/sample-validation-setup
with:
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
os: ${{ runner.os }}
- name: Create .env for samples
run: |
echo "AZURE_AI_PROJECT_ENDPOINT=$AZURE_AI_PROJECT_ENDPOINT" >> .env
echo "AZURE_AI_MODEL_DEPLOYMENT_NAME=$AZURE_AI_MODEL_DEPLOYMENT_NAME" >> .env
- name: Run sample validation
run: |
cd scripts && uv run python -m sample_validation --subdir 02-agents/providers/azure_ai_agent --save-report --report-name 02-agents-azure-ai-agent
- name: Upload validation report
uses: actions/upload-artifact@v7
if: always()
with:
name: validation-report-02-agents-azure-ai-agent
name: validation-report-02-agents-azure
path: python/samples/sample_validation/reports/
validate-02-agents-anthropic:
@@ -409,11 +335,13 @@ jobs:
name: validation-report-02-agents-ollama
path: python/samples/sample_validation/reports/
validate-02-agents-foundry-local:
name: Validate 02-agents/providers/foundry_local
if: false # Temporarily disabled - requires local Foundry setup
validate-02-agents-foundry:
name: Validate 02-agents/providers/foundry
runs-on: ubuntu-latest
environment: integration
env:
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
defaults:
run:
working-directory: python
@@ -428,15 +356,20 @@ jobs:
azure-subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
os: ${{ runner.os }}
- name: Create .env for samples
run: |
echo "FOUNDRY_PROJECT_ENDPOINT=$FOUNDRY_PROJECT_ENDPOINT" >> .env
echo "FOUNDRY_MODEL=$FOUNDRY_MODEL" >> .env
- name: Run sample validation
run: |
cd scripts && uv run python -m sample_validation --subdir 02-agents/providers/foundry_local --save-report --report-name 02-agents-foundry-local
cd scripts && uv run python -m sample_validation --subdir 02-agents/providers/foundry --save-report --report-name 02-agents-foundry
- name: Upload validation report
uses: actions/upload-artifact@v7
if: always()
with:
name: validation-report-02-agents-foundry-local
name: validation-report-02-agents-foundry
path: python/samples/sample_validation/reports/
validate-02-agents-copilotstudio:
@@ -516,6 +449,8 @@ jobs:
environment: integration
env:
# Azure AI configuration
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
AZURE_AI_PROJECT_ENDPOINT: ${{ vars.AZURE_AI_PROJECT_ENDPOINT }}
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
# Azure OpenAI configuration
@@ -538,6 +473,8 @@ jobs:
- name: Create .env for samples
run: |
echo "FOUNDRY_PROJECT_ENDPOINT=$FOUNDRY_PROJECT_ENDPOINT" >> .env
echo "FOUNDRY_MODEL=$FOUNDRY_MODEL" >> .env
echo "AZURE_AI_PROJECT_ENDPOINT=$AZURE_AI_PROJECT_ENDPOINT" >> .env
echo "AZURE_AI_MODEL_DEPLOYMENT_NAME=$AZURE_AI_MODEL_DEPLOYMENT_NAME" >> .env
echo "AZURE_OPENAI_ENDPOINT=$AZURE_OPENAI_ENDPOINT" >> .env
@@ -759,14 +696,12 @@ jobs:
- validate-01-get-started
- validate-02-agents
- validate-02-agents-openai
- validate-02-agents-azure-openai
- validate-02-agents-azure-ai
- validate-02-agents-azure-ai-agent
- validate-02-agents-azure
- validate-02-agents-anthropic
- validate-02-agents-github-copilot
- validate-02-agents-amazon
- validate-02-agents-ollama
- validate-02-agents-foundry-local
- validate-02-agents-foundry
- validate-02-agents-copilotstudio
- validate-02-agents-custom
- validate-03-workflows
@@ -0,0 +1,125 @@
---
status: accepted
contact: rogerbarreto
date: 2026-03-06
deciders: rogerbarreto, alliscode
consulted: ""
informed: ""
---
# Foundry agent surface stays centered on `ChatClientAgent`
## Context
The Microsoft Foundry integration exposes two distinct usage patterns:
1. Direct Responses usage, where callers provide model, instructions, and tools at runtime.
2. Server-side versioned agents, where callers create and manage `AgentVersion` resources through `AIProjectClient.Agents`.
We briefly explored adding public wrapper types such as `FoundryAgent`, `FoundryVersionedAgent`, and `FoundryResponsesChatClient` to make those paths feel more specialized. That direction created extra public types, duplicated existing `ChatClientAgent` behavior, and pushed samples toward compatibility helpers instead of the native Azure SDK flow.
## Decision
Keep the public surface centered on `ChatClientAgent`.
- Direct Responses scenarios use `AIProjectClient.AsAIAgent(...)`.
- Server-side versioned scenarios use native `AIProjectClient.Agents` APIs to create or retrieve agent resources, then wrap `AgentRecord` or `AgentVersion` with `AIProjectClient.AsAIAgent(...)`.
- Compatibility helpers such as `AIProjectClient.CreateAIAgentAsync(...)` and `AIProjectClient.GetAIAgentAsync(...)` remain only as obsolete migration shims.
- Public wrapper types `FoundryAgent`, `FoundryVersionedAgent`, `FoundryResponsesChatClient`, and `FoundryResponsesChatClientAgent` are not part of the chosen direction.
## Why
- `ChatClientAgent` is already the framework abstraction used everywhere else.
- `AIProjectClient` is the native Azure SDK entry point for versioned agent lifecycle operations.
- A single agent abstraction avoids parallel type hierarchies for the same backend.
- Samples become clearer when they show either:
- direct Responses construction via `AIProjectClient.AsAIAgent(...)`, or
- native Foundry resource management via `AIProjectClient.Agents`.
## Consequences
### Direct Responses path
Use the convenience overloads on `AIProjectClient`:
```csharp
AIProjectClient aiProjectClient = new(new Uri(endpoint), credential);
ChatClientAgent agent = aiProjectClient.AsAIAgent(
model: deploymentName,
instructions: "You are good at telling jokes.",
name: "JokerAgent");
```
Or use composed `ChatClientAgent`
```csharp
ProjectResponsesClient projectResponsesClient = new(new Uri(endpoint), new DefaultAzureCredential(), new AgentReference($"model:{deploymentName}"));
ChatClientAgent agent = new(
chatClient: projectResponsesClient.AsIChatClient(),
instructions: "You are good at telling jokes.",
name: "JokerAgent");
```
This path is code-first and does not create a persistent server-side agent.
### Versioned agent path
Use the convenience overloads on `AIProjectClient`:
```csharp
AIProjectClient aiProjectClient = new(new Uri(endpoint), credential);
AgentVersion version = await aiProjectClient.Agents.CreateAgentVersionAsync(
"JokerAgent",
new AgentVersionCreationOptions(
new PromptAgentDefinition(deploymentName)
{
Instructions = "You are good at telling jokes."
}));
ChatClientAgent agent = aiProjectClient.AsAIAgent(version);
```
Or use composed `ChatClientAgent`
```csharp
AIProjectClient aiProjectClient = new(new Uri(endpoint), credential);
AgentVersion version = await aiProjectClient.Agents.CreateAgentVersionAsync(
"JokerAgent",
new AgentVersionCreationOptions(
new PromptAgentDefinition(deploymentName)
{
Instructions = "You are good at telling jokes."
}));
ProjectResponsesClient projectResponsesClient = aiProjectClient
.GetProjectOpenAIClient()
.GetProjectResponsesClientForAgent(new AgentReference(version.Name, version.Version));
ChatClientAgent agent = new(
chatClient: projectResponsesClient.AsIChatClient(),
name: "JokerAgent");
```
### Samples
- `FoundryAgents/` samples show the direct Responses path with `AIProjectClient.AsAIAgent(...)`.
- `FoundryVersionedAgents/` samples should show native `AIProjectClient.Agents` create/get/delete flows plus `AsAIAgent(...)`.
### Compatibility APIs
Obsolete helper extensions remain only to ease migration of existing code. New samples and new guidance should not be written against them.
## Rejected direction
Do not introduce or preserve separate public wrapper types whose main purpose is to forward to `ChatClientAgent` while carrying Foundry-specific naming.
That approach:
- duplicates lifecycle concepts already present on `AIProjectClient`,
- fragments the public API,
- complicates samples and docs,
- and makes migration harder by encouraging wrapper-specific affordances.
+30 -31
View File
@@ -1,4 +1,4 @@
<Solution>
<Solution>
<Configurations>
<BuildType Name="Debug" />
<BuildType Name="Publish" />
@@ -121,6 +121,34 @@
<Project Path="samples/02-agents/AgentWithAnthropic/Agent_Anthropic_Step03_UsingFunctionTools/Agent_Anthropic_Step03_UsingFunctionTools.csproj" />
<Project Path="samples/02-agents/AgentWithAnthropic/Agent_Anthropic_Step04_UsingSkills/Agent_Anthropic_Step04_UsingSkills.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AgentsWithFoundry/">
<File Path="samples/02-agents/AgentsWithFoundry/README.md" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step00_FoundryAgentLifecycle/Agent_Step00_FoundryAgentLifecycle.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step01_Basics/Agent_Step01_Basics.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step02.1_MultiturnConversation/Agent_Step02.1_MultiturnConversation.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step02.2_MultiturnWithServerConversations/Agent_Step02.2_MultiturnWithServerConversations.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step03_UsingFunctionTools/Agent_Step03_UsingFunctionTools.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step04_UsingFunctionToolsWithApprovals/Agent_Step04_UsingFunctionToolsWithApprovals.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step05_StructuredOutput/Agent_Step05_StructuredOutput.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step06_PersistedConversations/Agent_Step06_PersistedConversations.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step07_Observability/Agent_Step07_Observability.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step08_DependencyInjection/Agent_Step08_DependencyInjection.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step09_UsingMcpClientAsTools/Agent_Step09_UsingMcpClientAsTools.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step10_UsingImages/Agent_Step10_UsingImages.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step11_AsFunctionTool/Agent_Step11_AsFunctionTool.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step12_Middleware/Agent_Step12_Middleware.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step13_Plugins/Agent_Step13_Plugins.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step14_CodeInterpreter/Agent_Step14_CodeInterpreter.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step15_ComputerUse/Agent_Step15_ComputerUse.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step16_FileSearch/Agent_Step16_FileSearch.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step17_OpenAPITools/Agent_Step17_OpenAPITools.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step18_BingCustomSearch/Agent_Step18_BingCustomSearch.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step19_SharePoint/Agent_Step19_SharePoint.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step20_MicrosoftFabric/Agent_Step20_MicrosoftFabric.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step21_WebSearch/Agent_Step21_WebSearch.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step22_MemorySearch/Agent_Step22_MemorySearch.csproj" />
<Project Path="samples/02-agents/AgentsWithFoundry/Agent_Step23_LocalMCP/Agent_Step23_LocalMCP.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AgentWithMemory/">
<File Path="samples/02-agents/AgentWithMemory/README.md" />
<Project Path="samples/02-agents/AgentWithMemory/AgentWithMemory_Step01_ChatHistoryMemory/AgentWithMemory_Step01_ChatHistoryMemory.csproj" />
@@ -143,35 +171,6 @@
<Project Path="samples/02-agents/AgentWithRAG/AgentWithRAG_Step03_CustomRAGDataSource/AgentWithRAG_Step03_CustomRAGDataSource.csproj" />
<Project Path="samples/02-agents/AgentWithRAG/AgentWithRAG_Step04_FoundryServiceRAG/AgentWithRAG_Step04_FoundryServiceRAG.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/FoundryAgents/">
<File Path="samples/02-agents/FoundryAgents/README.md" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Evaluations_Step01_RedTeaming/FoundryAgents_Evaluations_Step01_RedTeaming.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Evaluations_Step02_SelfReflection/FoundryAgents_Evaluations_Step02_SelfReflection.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step01.1_Basics/FoundryAgents_Step01.1_Basics.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step01.2_Running/FoundryAgents_Step01.2_Running.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step02_MultiturnConversation/FoundryAgents_Step02_MultiturnConversation.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step03_UsingFunctionTools/FoundryAgents_Step03_UsingFunctionTools.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step04_UsingFunctionToolsWithApprovals/FoundryAgents_Step04_UsingFunctionToolsWithApprovals.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step05_StructuredOutput/FoundryAgents_Step05_StructuredOutput.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step06_PersistedConversations/FoundryAgents_Step06_PersistedConversations.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step07_Observability/FoundryAgents_Step07_Observability.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step08_DependencyInjection/FoundryAgents_Step08_DependencyInjection.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step09_UsingMcpClientAsTools/FoundryAgents_Step09_UsingMcpClientAsTools.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step10_UsingImages/FoundryAgents_Step10_UsingImages.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step11_AsFunctionTool/FoundryAgents_Step11_AsFunctionTool.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step12_Middleware/FoundryAgents_Step12_Middleware.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step13_Plugins/FoundryAgents_Step13_Plugins.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step14_CodeInterpreter/FoundryAgents_Step14_CodeInterpreter.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step15_ComputerUse/FoundryAgents_Step15_ComputerUse.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step16_FileSearch/FoundryAgents_Step16_FileSearch.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step17_OpenAPITools/FoundryAgents_Step17_OpenAPITools.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step18_BingCustomSearch/FoundryAgents_Step18_BingCustomSearch.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step19_SharePoint/FoundryAgents_Step19_SharePoint.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step20_MicrosoftFabric/FoundryAgents_Step20_MicrosoftFabric.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step21_WebSearch/FoundryAgents_Step21_WebSearch.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step22_MemorySearch/FoundryAgents_Step22_MemorySearch.csproj" />
<Project Path="samples/02-agents/FoundryAgents/FoundryAgents_Step23_LocalMCP/FoundryAgents_Step23_LocalMCP.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/ModelContextProtocol/">
<File Path="samples/02-agents/ModelContextProtocol/README.md" />
<Project Path="samples/02-agents/ModelContextProtocol/Agent_MCP_Server/Agent_MCP_Server.csproj" />
@@ -318,8 +317,8 @@
<Folder Name="/Samples/05-end-to-end/AspNetAgentAuthorization/">
<File Path="samples/05-end-to-end/AspNetAgentAuthorization/docker-compose.yml" />
<File Path="samples/05-end-to-end/AspNetAgentAuthorization/README.md" />
<Project Path="samples/05-end-to-end/AspNetAgentAuthorization/Service/Service.csproj" />
<Project Path="samples/05-end-to-end/AspNetAgentAuthorization/RazorWebClient/RazorWebClient.csproj" />
<Project Path="samples/05-end-to-end/AspNetAgentAuthorization/Service/Service.csproj" />
</Folder>
<Folder Name="/Solution Items/">
<File Path=".editorconfig" />
@@ -70,7 +70,7 @@ while ((input = Console.ReadLine()) != null && !input.Equals("exit", StringCompa
if (approvalRequest.AdditionalProperties != null)
{
approvalResponse.AdditionalProperties = new AdditionalPropertiesDictionary();
approvalResponse.AdditionalProperties = [];
foreach (var kvp in approvalRequest.AdditionalProperties)
{
approvalResponse.AdditionalProperties[kvp.Key] = kvp.Value;
@@ -131,9 +131,9 @@ internal sealed class ServerFunctionApprovalClientAgent : DelegatingAIAgent
transformedContents ??= CopyContentsUpToIndex(message.Contents, contentIndex);
approvalCalls.Remove(functionResult.CallId);
}
else if (transformedContents != null)
else
{
transformedContents.Add(content);
transformedContents?.Add(content);
}
}
@@ -155,10 +155,10 @@ internal sealed class ServerFunctionApprovalClientAgent : DelegatingAIAgent
result ??= CopyMessagesUpToIndex(messages, messageIndex);
result.Add(newMessage);
}
else if (result != null)
else
{
// We're already copying messages, so copy this unchanged message too
result.Add(message);
result?.Add(message);
}
// If result is null, we haven't made any changes yet, so keep processing
}
@@ -57,16 +57,10 @@ internal sealed class ServerFunctionApprovalAgent : DelegatingAIAgent
throw new InvalidOperationException("Invalid request_approval tool call");
}
var request = toolCall.Arguments.TryGetValue("request", out var reqObj) &&
var request = (toolCall.Arguments.TryGetValue("request", out var reqObj) &&
reqObj is JsonElement argsElement &&
argsElement.Deserialize(jsonSerializerOptions.GetTypeInfo(typeof(ApprovalRequest))) is ApprovalRequest approvalRequest &&
approvalRequest != null ? approvalRequest : null;
if (request == null)
{
throw new InvalidOperationException("Failed to deserialize approval request from tool call");
}
approvalRequest != null ? approvalRequest : null) ?? throw new InvalidOperationException("Failed to deserialize approval request from tool call");
return new ToolApprovalRequestContent(
requestId: request.ApprovalId,
new FunctionCallContent(
@@ -77,17 +71,11 @@ internal sealed class ServerFunctionApprovalAgent : DelegatingAIAgent
private static ToolApprovalResponseContent ConvertToolResultToApprovalResponse(FunctionResultContent result, ToolApprovalRequestContent approval, JsonSerializerOptions jsonSerializerOptions)
{
var approvalResponse = result.Result is JsonElement je ?
var approvalResponse = (result.Result is JsonElement je ?
(ApprovalResponse?)je.Deserialize(jsonSerializerOptions.GetTypeInfo(typeof(ApprovalResponse))) :
result.Result is string str ?
(ApprovalResponse?)JsonSerializer.Deserialize(str, jsonSerializerOptions.GetTypeInfo(typeof(ApprovalResponse))) :
result.Result as ApprovalResponse;
if (approvalResponse == null)
{
throw new InvalidOperationException("Failed to deserialize approval response from tool result");
}
result.Result as ApprovalResponse) ?? throw new InvalidOperationException("Failed to deserialize approval response from tool result");
return approval.CreateResponse(approvalResponse.Approved);
}
#pragma warning restore MEAI001
@@ -121,7 +109,7 @@ internal sealed class ServerFunctionApprovalAgent : DelegatingAIAgent
// Track approval ID to original call ID mapping
_ = new Dictionary<string, string>();
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
Dictionary<string, ToolApprovalRequestContent> trackedRequestApprovalToolCalls = new(); // Remote approvals
Dictionary<string, ToolApprovalRequestContent> trackedRequestApprovalToolCalls = []; // Remote approvals
for (int messageIndex = 0; messageIndex < messages.Count; messageIndex++)
{
var message = messages[messageIndex];
@@ -146,7 +134,7 @@ internal sealed class ServerFunctionApprovalAgent : DelegatingAIAgent
});
}
else if (content is FunctionResultContent toolResult &&
trackedRequestApprovalToolCalls.TryGetValue(toolResult.CallId, out var approval) == true)
trackedRequestApprovalToolCalls.TryGetValue(toolResult.CallId, out var approval))
{
result ??= CopyMessagesUpToIndex(messages, messageIndex);
transformedContents ??= CopyContentsUpToIndex(message.Contents, j);
@@ -161,9 +149,9 @@ internal sealed class ServerFunctionApprovalAgent : DelegatingAIAgent
AdditionalProperties = message.AdditionalProperties
});
}
else if (result != null)
else
{
result.Add(message);
result?.Add(message);
}
}
}
@@ -72,10 +72,9 @@ internal sealed class StatefulAgent<TState> : DelegatingAIAgent
if (content is DataContent dataContent && dataContent.MediaType == "application/json")
{
// Deserialize the state
TState? newState = JsonSerializer.Deserialize(
if (JsonSerializer.Deserialize(
dataContent.Data.Span,
this._jsonSerializerOptions.GetTypeInfo(typeof(TState))) as TState;
if (newState != null)
this._jsonSerializerOptions.GetTypeInfo(typeof(TState))) is TState newState)
{
this.State = newState;
}
@@ -6,6 +6,7 @@ using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AzureAI;
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";
@@ -30,14 +31,18 @@ var createdAgentVersion = aiProjectClient.Agents.CreateAgentVersion(agentName: J
// agentVersion.Name = <agentName>
// You can use an AIAgent with an already created server side agent version.
AIAgent existingJokerAgent = aiProjectClient.AsAIAgent(createdAgentVersion);
FoundryAgent existingJokerAgent = aiProjectClient.AsAIAgent(createdAgentVersion);
// You can also create another AIAgent version by providing the same name with a different definition.
AIAgent newJokerAgent = await aiProjectClient.CreateAIAgentAsync(name: JokerName, model: deploymentName, instructions: "You are extremely hilarious at telling jokes.");
AgentVersion newJokerAgentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
JokerName,
new AgentVersionCreationOptions(new PromptAgentDefinition(model: deploymentName) { Instructions = "You are extremely hilarious at telling jokes." }));
FoundryAgent newJokerAgent = aiProjectClient.AsAIAgent(newJokerAgentVersion);
// You can also get the AIAgent latest version just providing its name.
AIAgent jokerAgentLatest = await aiProjectClient.GetAIAgentAsync(name: JokerName);
var latestAgentVersion = jokerAgentLatest.GetService<AgentVersion>()!;
AgentRecord jokerAgentRecord = await aiProjectClient.Agents.GetAgentAsync(JokerName);
FoundryAgent jokerAgentLatest = aiProjectClient.AsAIAgent(jokerAgentRecord);
AgentVersion latestAgentVersion = jokerAgentRecord.GetLatestVersion();
// The AIAgent version can be accessed via the GetService method.
Console.WriteLine($"Latest agent version id: {latestAgentVersion.Id}");
@@ -5,20 +5,13 @@
using Anthropic;
using Anthropic.Core;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
var apiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY") ?? throw new InvalidOperationException("ANTHROPIC_API_KEY is not set.");
var model = Environment.GetEnvironmentVariable("ANTHROPIC_CHAT_MODEL_NAME") ?? "claude-haiku-4-5";
AIAgent agent = new AnthropicClient(new ClientOptions { ApiKey = apiKey })
AIAgent agent =
new AnthropicClient(new ClientOptions { ApiKey = apiKey })
.AsAIAgent(model: model, instructions: "You are good at telling jokes.", name: "Joker");
// Invoke the agent and output the text result.
var response = await agent.RunAsync("Tell me a joke about a pirate.");
Console.WriteLine(response);
// Invoke the agent with streaming support.
await foreach (var update in agent.RunStreamingAsync("Tell me a joke about a pirate."))
{
Console.WriteLine(update);
}
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
@@ -11,6 +11,7 @@ using System.Text.Json;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AzureAI;
using Microsoft.Agents.AI.FoundryMemory;
string foundryEndpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
@@ -19,6 +20,9 @@ string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLO
string embeddingModelName = Environment.GetEnvironmentVariable("AZURE_AI_EMBEDDING_DEPLOYMENT_NAME") ?? "text-embedding-ada-002";
// Create an AIProjectClient for Foundry with Azure Identity authentication.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
DefaultAzureCredential credential = new();
AIProjectClient projectClient = new(new Uri(foundryEndpoint), credential);
@@ -33,11 +37,15 @@ FoundryMemoryProvider memoryProvider = new(
memoryStoreName,
stateInitializer: _ => new(new FoundryMemoryProviderScope("sample-user-123")));
AIAgent agent = await projectClient.CreateAIAgentAsync(deploymentName,
options: new ChatClientAgentOptions()
FoundryAgent agent = projectClient.AsAIAgent(
new ChatClientAgentOptions()
{
Name = "TravelAssistantWithFoundryMemory",
ChatOptions = new() { Instructions = "You are a friendly travel assistant. Use known memories about the user when responding, and do not invent details." },
ChatOptions = new()
{
ModelId = deploymentName,
Instructions = "You are a friendly travel assistant. Use known memories about the user when responding, and do not invent details."
},
AIContextProviders = [memoryProvider]
});
@@ -1,4 +1,4 @@
# Agent Framework Retrieval Augmented Generation (RAG)
# Agent Framework Retrieval Augmented Generation (RAG)
These samples show how to create an agent with the Agent Framework that uses Memory to remember previous conversations or facts from previous conversations.
@@ -10,4 +10,4 @@ These samples show how to create an agent with the Agent Framework that uses Mem
|[Memory with Azure AI Foundry](./AgentWithMemory_Step04_MemoryUsingFoundry/)|This sample demonstrates how to create and run an agent that uses Azure AI Foundry's managed memory service to extract and retrieve individual memories.|
|[Bounded Chat History with Overflow](./AgentWithMemory_Step05_BoundedChatHistory/)|This sample demonstrates how to create a bounded chat history provider that overflows older messages to a vector store and recalls them as memories.|
> **See also**: [Memory Search with Foundry Agents](../FoundryAgents/FoundryAgents_Step22_MemorySearch/) - demonstrates using the built-in Memory Search tool with Azure Foundry Agents.
> **See also**: [Memory Search with Foundry Agents](../AgentsWithFoundry/Agent_Step22_MemorySearch/) - demonstrates using the built-in Memory Search tool with Azure Foundry agents.
@@ -4,28 +4,14 @@
using System.ClientModel;
using Microsoft.Agents.AI;
using OpenAI;
using OpenAI.Chat;
using OpenAI.Responses;
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var model = Environment.GetEnvironmentVariable("OPENAI_CHAT_MODEL_NAME") ?? "gpt-4o-mini";
AIAgent agent = new OpenAIClient(apiKey)
.GetChatClient(model)
.AsAIAgent(instructions: "You are good at telling jokes.", name: "Joker");
AIAgent agent =
new ResponsesClient(new ApiKeyCredential(apiKey))
.AsAIAgent(model: model, instructions: "You are good at telling jokes.", name: "Joker");
UserChatMessage chatMessage = new("Tell me a joke about a pirate.");
// Invoke the agent and output the text result.
ChatCompletion chatCompletion = await agent.RunAsync([chatMessage]);
Console.WriteLine(chatCompletion.Content.Last().Text);
// Invoke the agent with streaming support.
AsyncCollectionResult<StreamingChatCompletionUpdate> completionUpdates = agent.RunStreamingAsync([chatMessage]);
await foreach (StreamingChatCompletionUpdate completionUpdate in completionUpdates)
{
if (completionUpdate.ContentUpdate.Count > 0)
{
Console.WriteLine(completionUpdate.ContentUpdate[0].Text);
}
}
// Once you have the agent, you can invoke it like any other AIAgent.
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
@@ -4,11 +4,13 @@
using System.ClientModel;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Agents.AI.AzureAI;
using OpenAI;
using OpenAI.Files;
using OpenAI.Responses;
using OpenAI.VectorStores;
var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
@@ -37,14 +39,20 @@ ClientResult<VectorStore> vectorStoreCreate = await vectorStoreClient.CreateVect
FileIds = { uploadResult.Value.Id }
});
var fileSearchTool = new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreCreate.Value.Id)] };
// Use the native OpenAI SDK FileSearchTool directly with the vector store ID.
#pragma warning disable OPENAI001
FileSearchTool fileSearchTool = new([vectorStoreCreate.Value.Id]);
#pragma warning restore OPENAI001
AIAgent agent = await aiProjectClient
.CreateAIAgentAsync(
model: deploymentName,
name: "AskContoso",
instructions: "You are a helpful support specialist for Contoso Outdoors. Answer questions using the provided context and cite the source document when available.",
tools: [fileSearchTool]);
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
"AskContoso",
new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = "You are a helpful support specialist for Contoso Outdoors. Answer questions using the provided context and cite the source document when available.",
Tools = { fileSearchTool }
}));
FoundryAgent agent = aiProjectClient.AsAIAgent(agentVersion);
AgentSession session = await agent.CreateSessionAsync();
@@ -3,6 +3,7 @@
// This sample shows how to expose an AI agent as an MCP tool.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.DependencyInjection;
@@ -18,11 +19,17 @@ var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYME
var aiProjectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
// Create a server side agent and expose it as an AIAgent.
AIAgent agent = await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
instructions: "You are good at telling jokes, and you always start each joke with 'Aye aye, captain!'.",
name: "Joker",
description: "An agent that tells jokes.");
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
"Joker",
new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = "You are good at telling jokes, and you always start each joke with 'Aye aye, captain!'.",
})
{
Description = "An agent that tells jokes.",
});
AIAgent agent = aiProjectClient.AsAIAgent(agentVersion);
// Convert the agent to an AIFunction and then to an MCP tool.
// The agent name and description will be used as the mcp tool name and description.
@@ -189,9 +189,9 @@ async Task<AgentResponse> PIIMiddleware(IEnumerable<ChatMessage> messages, Agent
// Regex patterns for PII detection (simplified for demonstration)
Regex[] piiPatterns =
[
new(@"\b\d{3}-\d{3}-\d{4}\b", RegexOptions.Compiled), // Phone number (e.g., 123-456-7890)
new(@"\b[\w\.-]+@[\w\.-]+\.\w+\b", RegexOptions.Compiled), // Email address
new(@"\b[A-Z][a-z]+\s[A-Z][a-z]+\b", RegexOptions.Compiled) // Full name (e.g., John Doe)
MyRegex(), // Phone number (e.g., 123-456-7890)
EmailRegex(), // Email address
FullNameRegex() // Full name (e.g., John Doe)
];
foreach (var pattern in piiPatterns)
@@ -309,3 +309,15 @@ internal sealed class DateTimeContextProvider : MessageAIContextProvider
]);
}
}
internal partial class Program
{
[GeneratedRegex(@"\b\d{3}-\d{3}-\d{4}\b", RegexOptions.Compiled)]
private static partial Regex MyRegex();
[GeneratedRegex(@"\b[\w\.-]+@[\w\.-]+\.\w+\b", RegexOptions.Compiled)]
private static partial Regex EmailRegex();
[GeneratedRegex(@"\b[A-Z][a-z]+\s[A-Z][a-z]+\b", RegexOptions.Compiled)]
private static partial Regex FullNameRegex();
}
@@ -17,10 +17,10 @@ var bingConnectionId = Environment.GetEnvironmentVariable("AZURE_AI_BING_CONNECT
PersistentAgentsAdministrationClientOptions persistentAgentsClientOptions = new();
persistentAgentsClientOptions.Retry.NetworkTimeout = TimeSpan.FromMinutes(20);
// Get a client to create/retrieve server side agents with.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
// Get a client to create/retrieve server side agents with.
PersistentAgentsClient persistentAgentsClient = new(endpoint, new DefaultAzureCredential(), persistentAgentsClientOptions);
// Define and configure the Deep Research tool.
@@ -23,12 +23,14 @@ Before running this sample, ensure you have:
Pay special attention to the purple `Note` boxes in the Azure documentation.
**Note**: The Bing Connection ID must be from the **project**, not the resource. It has the following format:
**Note**: The Bing Grounding Connection ID must be the **full ARM resource URI** from the project, not just the connection name. It has the following format:
```
/subscriptions/<sub_id>/resourceGroups/<rg_name>/providers/<provider_name>/accounts/<account_name>/projects/<project_name>/connections/<connection_name>
/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.CognitiveServices/accounts/<account>/projects/<project>/connections/<connection-name>
```
You can find this in the Azure AI Foundry portal under **Management > Connected resources**, or retrieve it programmatically via the connections API (`.id` property).
## Environment Variables
Set the following environment variables:
@@ -37,8 +39,8 @@ Set the following environment variables:
# Replace with your Azure AI Foundry project endpoint
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-project.services.ai.azure.com/"
# Replace with your Bing connection ID from the project
$env:AZURE_AI_BING_CONNECTION_ID="/subscriptions/.../connections/your-bing-connection"
# Replace with your Bing Grounding connection ID (full ARM resource URI)
$env:AZURE_AI_BING_CONNECTION_ID="/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.CognitiveServices/accounts/<account>/projects/<project>/connections/<connection-name>"
# Optional, defaults to o3-deep-research
$env:AZURE_AI_REASONING_DEPLOYMENT_NAME="o3-deep-research"
@@ -24,12 +24,12 @@ var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT
Func<Task<string[]>> loadNextThreeCalendarEvents = async () =>
{
// In a real implementation, this method would connect to a calendar service
return new string[]
{
return
[
"Doctor's appointment today at 15:00",
"Team meeting today at 17:00",
"Birthday party today at 20:00"
};
];
};
// Create an agent with an AI context provider attached that aggregates two other providers:
@@ -87,7 +87,7 @@ namespace SampleApp
internal sealed class TodoListAIContextProvider : AIContextProvider
{
private static List<string> GetTodoItems(AgentSession? session)
=> session?.StateBag.GetValue<List<string>>(nameof(TodoListAIContextProvider)) ?? new List<string>();
=> session?.StateBag.GetValue<List<string>>(nameof(TodoListAIContextProvider)) ?? [];
private static void SetTodoItems(AgentSession? session, List<string> items)
=> session?.StateBag.SetValue(nameof(TodoListAIContextProvider), items);
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to create, use, and clean up a FoundryAgent backed by a server-side
// versioned agent in Azure AI Foundry. It demonstrates the full lifecycle:
// create agent version -> wrap as FoundryAgent -> run -> delete.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI.AzureAI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
const string JokerName = "JokerAgent";
// Create the AIProjectClient to manage server-side agents.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new AzureCliCredential());
// Create a server-side agent version using the native SDK.
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
JokerName,
new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = "You are good at telling jokes.",
}));
// Wrap the agent version as a FoundryAgent using the AsAIAgent extension.
FoundryAgent agent = aiProjectClient.AsAIAgent(agentVersion);
// Once you have the agent, you can invoke it like any other AIAgent.
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
// Cleanup: deletes the agent and all its versions.
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
@@ -0,0 +1,23 @@
# Agent Step 00 - FoundryAgent Lifecycle
This sample demonstrates the full lifecycle of a `FoundryAgent` backed by a server-side versioned agent in Microsoft Foundry: create → run → delete.
## Prerequisites
- A Microsoft Foundry project endpoint
- A model deployment name (defaults to `gpt-4o-mini`)
- Azure CLI installed and authenticated
## Environment Variables
| Variable | Description | Required |
| --- | --- | --- |
| `AZURE_AI_PROJECT_ENDPOINT` | Microsoft Foundry project endpoint | Yes |
| `AZURE_AI_MODEL_DEPLOYMENT_NAME` | Model deployment name | No (defaults to `gpt-4o-mini`) |
## Running the sample
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step00_FoundryAgentLifecycle
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,20 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to create and run a basic agent with AIProjectClient.AsAIAgent(...).
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIAgent agent =
new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
.AsAIAgent(model: deploymentName, instructions: "You are good at telling jokes.", name: "JokerAgent");
// Once you have the agent, you can invoke it like any other AIAgent.
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
@@ -0,0 +1,55 @@
# Creating and Running a Basic Agent with the Responses API
This sample demonstrates how to create and run a basic AI agent using the `ChatClientAgent`, which uses the Microsoft Foundry Responses API directly without creating server-side agent definitions.
## What this sample demonstrates
- Creating a `ChatClientAgent` with instructions and a model
- Running a simple single-turn conversation
- No server-side agent creation or cleanup required
## Prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (for Azure credential authentication)
**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Microsoft Foundry resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
Navigate to the AgentsWithFoundry sample directory and run:
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step01_Basics
```
## Alternative: Composable approach
You can also create the same agent by composing the underlying `IChatClient` directly. This gives you full control over the chat client pipeline:
```csharp
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = new ChatClientAgent(
chatClient: aiProjectClient.GetProjectOpenAIClient().GetProjectResponsesClient().AsIChatClient(deploymentName),
instructions: "You are good at telling jokes.",
name: "JokerAgent");
```
This approach is useful when you need to customize the chat client pipeline or swap providers (e.g., Anthropic, OpenAI) while keeping the same agent code.
@@ -9,8 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Azure.Identity" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to create a multi-turn conversation agent using sessions.
// Context is preserved across multiple runs via response ID chaining in the session.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIAgent agent = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
.AsAIAgent(deploymentName, instructions: "You are good at telling jokes.", name: "JokerAgent");
// Create a session to maintain context across multiple runs.
AgentSession session = await agent.CreateSessionAsync();
// First turn
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));
// Second turn — the agent remembers the first turn via the session.
Console.WriteLine(await agent.RunAsync("Now add some emojis to the joke and tell it in the voice of a pirate's parrot.", session));
@@ -0,0 +1,36 @@
# Multi-turn Conversation
This sample demonstrates how to implement multi-turn conversations where context is preserved across multiple agent runs using sessions and response ID chaining.
## What this sample demonstrates
- Creating an agent with instructions
- Using sessions to maintain conversation context across multiple runs
- Response ID chaining for multi-turn conversations
- No server-side conversation creation required
## Prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (for Azure credential authentication)
**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Microsoft Foundry resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
Navigate to the AgentsWithFoundry sample directory and run:
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step02.1_MultiturnConversation
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,34 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use server-side conversations with a FoundryAgent.
// Server-side conversations persist on the Foundry service and are visible in the Foundry Project UI.
// Use this when you need conversation history to be stored and accessible server-side.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AzureAI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
FoundryAgent agent = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
.AsAIAgent(deploymentName, instructions: "You are good at telling jokes.", name: "JokerAgent");
// CreateConversationSessionAsync creates a server-side ProjectConversation
// that persists on the Foundry service and is visible in the Foundry Project UI.
AgentSession session = await agent.CreateConversationSessionAsync();
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));
Console.WriteLine(await agent.RunAsync("Now add some emojis to the joke and tell it in the voice of a pirate's parrot.", session));
// Streaming with server-side conversation context.
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync("Tell me another joke, but about a ninja this time.", session))
{
Console.Write(update);
}
Console.WriteLine();
@@ -0,0 +1,36 @@
# Multi-turn Conversation with Server-Side Conversations
This sample demonstrates how to use server-side conversations with a `FoundryAgent`. Server-side conversations persist on the Foundry service and are visible in the Foundry Project UI, making them ideal when you need conversation history to be stored and accessible server-side.
## What this sample demonstrates
- Creating a `FoundryAgent` with instructions
- Using `CreateConversationSessionAsync` to create a server-side `ProjectConversation`
- Multi-turn conversations with both text and streaming output
- Server-side conversation persistence visible in the Foundry Project UI
## Prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (for Azure credential authentication)
**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Microsoft Foundry resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
Navigate to the AgentsWithFoundry sample directory and run:
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step02.2_MultiturnWithServerConversations
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample demonstrates how to use function tools.
using System.ComponentModel;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
// Define the function tool.
AITool tool = AIFunctionFactory.Create(GetWeather);
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a AIAgent with function tools.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a helpful assistant that can get weather information.",
name: "WeatherAssistant",
tools: [tool]);
// Non-streaming agent interaction with function tools.
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?", session));
// Streaming agent interaction with function tools.
session = await agent.CreateSessionAsync();
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync("What is the weather like in Amsterdam?", session))
{
Console.Write(update);
}
@@ -0,0 +1,37 @@
# Using Function Tools with the Responses API
This sample demonstrates how to use function tools with the `ChatClientAgent`, allowing the agent to call custom functions to retrieve information.
## What this sample demonstrates
- Creating function tools using `AIFunctionFactory`
- Passing function tools to a `ChatClientAgent`
- Running agents with function tools (text output)
- Running agents with function tools (streaming output)
- No server-side agent creation or cleanup required
## Prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (for Azure credential authentication)
**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Microsoft Foundry resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
Navigate to the AgentsWithFoundry sample directory and run:
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step03_UsingFunctionTools
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -1,9 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample demonstrates how to use an agent with function tools that require a human in the loop for approvals.
// It shows both non-streaming and streaming agent interactions using weather-related tools.
// If the agent is hosted in a service, with a remote user, combine this sample with the Persisted Conversations sample to persist the chat history
// while the agent is waiting for user input.
using System.ComponentModel;
using Azure.AI.Projects;
@@ -11,18 +8,13 @@ using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// Create a sample function tool that the agent can use.
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
const string AssistantInstructions = "You are a helpful assistant that can get weather information.";
const string AssistantName = "WeatherAssistant";
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
@@ -30,16 +22,16 @@ AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredent
ApprovalRequiredAIFunction approvalTool = new(AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather)));
// Create AIAgent directly
AIAgent agent = await aiProjectClient.CreateAIAgentAsync(name: AssistantName, model: deploymentName, instructions: AssistantInstructions, tools: [approvalTool]);
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a helpful assistant that can get weather information.",
name: "WeatherAssistant",
tools: [approvalTool]);
// Call the agent with approval-required function tools.
// The agent will request approval before invoking the function.
AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync("What is the weather like in Amsterdam?", session);
// Check if there are any approval requests.
// For simplicity, we are assuming here that only function approvals are pending.
List<ToolApprovalRequestContent> approvalRequests = response.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().ToList();
while (approvalRequests.Count > 0)
@@ -53,13 +45,8 @@ while (approvalRequests.Count > 0)
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved)]);
});
// Pass the user input responses back to the agent for further processing.
response = await agent.RunAsync(userInputMessages, session);
approvalRequests = response.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().ToList();
}
Console.WriteLine($"\nAgent: {response}");
// Cleanup by agent name removes the agent version created.
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
@@ -0,0 +1,30 @@
# Using Function Tools with Approvals via the Responses API
This sample demonstrates how to use function tools that require human-in-the-loop approval before execution.
## What this sample demonstrates
- Creating function tools that require approval using `ApprovalRequiredAIFunction`
- Handling approval requests from the agent
- Passing approval responses back to the agent
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step04_UsingFunctionToolsWithApprovals
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -15,29 +15,23 @@ using SampleApp;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
const string AssistantInstructions = "You are a helpful assistant that extracts structured information about people.";
const string AssistantName = "StructuredOutputAssistant";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create ChatClientAgent directly
ChatClientAgent agent = await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
new ChatClientAgentOptions()
AIAgent agent = aiProjectClient.AsAIAgent(new ChatClientAgentOptions
{
Name = "StructuredOutputAssistant",
ChatOptions = new()
{
Name = AssistantName,
ChatOptions = new()
{
Instructions = AssistantInstructions,
ResponseFormat = Microsoft.Extensions.AI.ChatResponseFormat.ForJsonSchema<PersonInfo>()
}
});
ModelId = deploymentName,
Instructions = "You are a helpful assistant that extracts structured information about people.",
ResponseFormat = Microsoft.Extensions.AI.ChatResponseFormat.ForJsonSchema<PersonInfo>()
}
});
// Set PersonInfo as the type parameter of RunAsync method to specify the expected structured output from the agent and invoke the agent with some unstructured input.
// Set PersonInfo as the type parameter of RunAsync method to specify the expected structured output.
AgentResponse<PersonInfo> response = await agent.RunAsync<PersonInfo>("Please provide information about John Smith, who is a 35-year-old software engineer.");
// Access the structured output via the Result property of the agent response.
@@ -46,39 +40,21 @@ Console.WriteLine($"Name: {response.Result.Name}");
Console.WriteLine($"Age: {response.Result.Age}");
Console.WriteLine($"Occupation: {response.Result.Occupation}");
// Create the ChatClientAgent with the specified name, instructions, and expected structured output the agent should produce.
ChatClientAgent agentWithPersonInfo = await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
new ChatClientAgentOptions()
{
Name = AssistantName,
ChatOptions = new()
{
Instructions = AssistantInstructions,
ResponseFormat = Microsoft.Extensions.AI.ChatResponseFormat.ForJsonSchema<PersonInfo>()
}
});
// Invoke the agent with streaming support, then deserialize the assembled response.
IAsyncEnumerable<AgentResponseUpdate> updates = agent.RunStreamingAsync("Please provide information about Jane Doe, who is a 28-year-old data scientist.");
// Invoke the agent with some unstructured input while streaming, to extract the structured information from.
IAsyncEnumerable<AgentResponseUpdate> updates = agentWithPersonInfo.RunStreamingAsync("Please provide information about John Smith, who is a 35-year-old software engineer.");
// Assemble all the parts of the streamed output, since we can only deserialize once we have the full json,
// then deserialize the response into the PersonInfo class.
PersonInfo personInfo = JsonSerializer.Deserialize<PersonInfo>((await updates.ToAgentResponseAsync()).Text, JsonSerializerOptions.Web)
?? throw new InvalidOperationException("Failed to deserialize the streamed response into PersonInfo.");
Console.WriteLine("Assistant Output:");
Console.WriteLine("\nStreaming Assistant Output:");
Console.WriteLine($"Name: {personInfo.Name}");
Console.WriteLine($"Age: {personInfo.Age}");
Console.WriteLine($"Occupation: {personInfo.Occupation}");
// Cleanup by agent name removes the agent version created.
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
namespace SampleApp
{
/// <summary>
/// Represents information about a person, including their name, age, and occupation, matched to the JSON schema used in the agent.
/// Represents information about a person.
/// </summary>
[Description("Information about a person including their name, age, and occupation")]
public class PersonInfo
@@ -0,0 +1,29 @@
# Structured Output with the Responses API
This sample demonstrates how to configure an agent to produce structured output using JSON schema.
## What this sample demonstrates
- Using `RunAsync<T>()` to get typed structured output from the agent
- Deserializing streamed responses into structured types
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step05_StructuredOutput
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to create and use a simple AI agent with a conversation that can be persisted to disk.
// This sample shows how to persist and resume conversations.
using System.Text.Json;
using Azure.AI.Projects;
@@ -10,16 +10,14 @@ using Microsoft.Agents.AI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
const string JokerInstructions = "You are good at telling jokes.";
const string JokerName = "JokerAgent";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = await aiProjectClient.CreateAIAgentAsync(name: JokerName, model: deploymentName, instructions: JokerInstructions);
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are good at telling jokes.",
name: "JokerAgent");
// Start a new session for the agent conversation.
AgentSession session = await agent.CreateSessionAsync();
@@ -42,6 +40,3 @@ AgentSession resumedSession = await agent.DeserializeSessionAsync(reloadedSerial
// Run the agent again with the resumed session.
Console.WriteLine(await agent.RunAsync("Now tell the same joke in the voice of a pirate, and add some emojis to the joke.", resumedSession));
// Cleanup by agent name removes the agent version created.
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
@@ -0,0 +1,30 @@
# Persisted Conversations with the Responses API
This sample demonstrates how to persist and resume agent conversations using session serialization.
## What this sample demonstrates
- Serializing agent sessions to JSON for persistence
- Saving and loading sessions from disk
- Resuming conversations with preserved context
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step06_PersistedConversations
```
@@ -9,8 +9,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" />
<PackageReference Include="OpenTelemetry" />
<PackageReference Include="OpenTelemetry.Exporter.Console" />
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to create and use a simple AI agent with Azure Foundry Agents as the backend that logs telemetry using OpenTelemetry.
// This sample shows how to add OpenTelemetry observability to an agent.
using Azure.AI.Projects;
using Azure.Identity;
@@ -9,15 +9,11 @@ using Microsoft.Agents.AI;
using OpenTelemetry;
using OpenTelemetry.Trace;
string? applicationInsightsConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING");
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
string? applicationInsightsConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING");
const string JokerInstructions = "You are good at telling jokes.";
const string JokerName = "JokerAgent";
// Create TracerProvider with console exporter
// This will output the telemetry data to the console.
// Create TracerProvider with console exporter.
string sourceName = Guid.NewGuid().ToString("N");
TracerProviderBuilder tracerProviderBuilder = Sdk.CreateTracerProviderBuilder()
.AddSource(sourceName)
@@ -28,14 +24,16 @@ if (!string.IsNullOrWhiteSpace(applicationInsightsConnectionString))
}
using var tracerProvider = tracerProviderBuilder.Build();
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Define the agent you want to create. (Prompt Agent in this case)
AIAgent agent = (await aiProjectClient.CreateAIAgentAsync(name: JokerName, model: deploymentName, instructions: JokerInstructions))
AIAgent agent = aiProjectClient
.AsAIAgent(
deploymentName,
instructions: "You are good at telling jokes.",
name: "JokerAgent")
.AsBuilder()
.UseOpenTelemetry(sourceName: sourceName)
.Build();
@@ -48,8 +46,7 @@ Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session
session = await agent.CreateSessionAsync();
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync("Tell me a joke about a pirate.", session))
{
Console.WriteLine(update);
Console.Write(update);
}
// Cleanup by agent name removes the agent version created.
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
Console.WriteLine();
@@ -0,0 +1,31 @@
# Observability with the Responses API
This sample demonstrates how to add OpenTelemetry observability to an agent using console and Azure Monitor exporters.
## What this sample demonstrates
- Configuring OpenTelemetry tracing with console exporter
- Optional Azure Application Insights integration
- Using `.AsBuilder().UseOpenTelemetry()` to add telemetry to the agent
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
$env:APPLICATIONINSIGHTS_CONNECTION_STRING="..." # Optional
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step07_Observability
```
@@ -11,8 +11,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
@@ -0,0 +1,83 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use dependency injection to register a AIAgent and use it from a hosted service.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SampleApp;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are good at telling jokes.",
name: "JokerAgent");
// Create a host builder that we will register services with and then run.
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// Add the AI agent to the service collection.
builder.Services.AddSingleton(agent);
// Add a sample service that will use the agent to respond to user input.
builder.Services.AddHostedService<SampleService>();
// Build and run the host.
using IHost host = builder.Build();
await host.RunAsync().ConfigureAwait(false);
namespace SampleApp
{
/// <summary>
/// A sample service that uses an AI agent to respond to user input.
/// </summary>
internal sealed class SampleService(AIAgent agent, IHostApplicationLifetime appLifetime) : IHostedService
{
private AgentSession? _session;
public async Task StartAsync(CancellationToken cancellationToken)
{
this._session = await agent.CreateSessionAsync(cancellationToken);
_ = this.RunAsync(appLifetime.ApplicationStopping);
}
public async Task RunAsync(CancellationToken cancellationToken)
{
await Task.Delay(100, cancellationToken);
while (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine("\nAgent: Ask me to tell you a joke about a specific topic. To exit just press Ctrl+C or enter without any input.\n");
Console.Write("> ");
string? input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
{
appLifetime.StopApplication();
break;
}
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(input, this._session, cancellationToken: cancellationToken))
{
Console.Write(update);
}
Console.WriteLine();
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
Console.WriteLine("\nShutting down...");
return Task.CompletedTask;
}
}
}
@@ -0,0 +1,30 @@
# Dependency Injection with the Responses API
This sample demonstrates how to register a `ChatClientAgent` in a dependency injection container and use it from a hosted service.
## What this sample demonstrates
- Registering `ChatClientAgent` as an `AIAgent` in the service collection
- Using the agent from a `IHostedService` with an interactive chat loop
- Streaming responses in a hosted service context
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step08_DependencyInjection
```
@@ -6,16 +6,15 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>$(NoWarn);CA1812</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="ModelContextProtocol" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use MCP client tools with an agent.
// It connects to the Microsoft Learn MCP server via HTTP and uses its tools.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Client;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// Connect to the Microsoft Learn MCP server via HTTP (Streamable HTTP transport).
Console.WriteLine("Connecting to MCP server at https://learn.microsoft.com/api/mcp ...");
await using McpClient mcpClient = await McpClient.CreateAsync(new HttpClientTransport(new()
{
Endpoint = new Uri("https://learn.microsoft.com/api/mcp"),
Name = "Microsoft Learn MCP",
}));
// Retrieve the list of tools available on the MCP server.
IList<McpClientTool> mcpTools = await mcpClient.ListToolsAsync();
Console.WriteLine($"MCP tools available: {string.Join(", ", mcpTools.Select(t => t.Name))}");
List<AITool> agentTools = [.. mcpTools.Cast<AITool>()];
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a helpful assistant that can help with Microsoft documentation questions. Use the Microsoft Learn MCP tool to search for documentation.",
name: "DocsAgent",
tools: agentTools);
Console.WriteLine($"Agent '{agent.Name}' created. Asking a question...\n");
const string Prompt = "How does one create an Azure storage account using az cli?";
Console.WriteLine($"User: {Prompt}\n");
Console.WriteLine($"Agent: {await agent.RunAsync(Prompt)}");
@@ -0,0 +1,29 @@
# Using MCP Client as Tools with the Responses API
This sample shows how to use MCP (Model Context Protocol) client tools with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Connecting to an MCP server via HTTP client transport
- Retrieving MCP tools and passing them to a `ChatClientAgent`
- Using MCP tools for agent interactions without server-side agent creation
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
- Node.js installed (for npx/MCP server)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="assets\walkway.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use Image Multi-Modality with an AI agent.
// This sample shows how to use image multi-modality with an agent.
using Azure.AI.Projects;
using Azure.Identity;
@@ -10,29 +10,25 @@ using Microsoft.Extensions.AI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o";
const string VisionInstructions = "You are a helpful agent that can analyze images";
const string VisionName = "VisionAgent";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Define the agent you want to create. (Prompt Agent in this case)
AIAgent agent = await aiProjectClient.CreateAIAgentAsync(name: VisionName, model: deploymentName, instructions: VisionInstructions);
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a helpful agent that can analyze images.",
name: "VisionAgent");
ChatMessage message = new(ChatRole.User, [
new TextContent("What do you see in this image?"),
await DataContent.LoadFromAsync("Assets/walkway.jpg"),
await DataContent.LoadFromAsync("assets/walkway.jpg"),
]);
AgentSession session = await agent.CreateSessionAsync();
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(message, session))
{
Console.WriteLine(update);
Console.Write(update);
}
// Cleanup by agent name removes the agent version created.
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
Console.WriteLine();
@@ -0,0 +1,30 @@
# Using Images with the Responses API
This sample demonstrates how to use image multi-modality with an agent.
## What this sample demonstrates
- Loading images using `DataContent.LoadFromAsync`
- Sending images alongside text to the agent
- Streaming the agent's image analysis response
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and a vision-capable model deployment (e.g., `gpt-4o`)
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step10_UsingImages
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to create and use an Azure Foundry Agents AI agent as a function tool.
// This sample shows how to use one agent as a function tool for another agent.
using System.ComponentModel;
using Azure.AI.Projects;
@@ -8,43 +8,29 @@ using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
const string WeatherInstructions = "You answer questions about the weather.";
const string WeatherName = "WeatherAgent";
const string MainInstructions = "You are a helpful assistant who responds in French.";
const string MainName = "MainAgent";
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create the weather agent with function tools.
AITool weatherTool = AIFunctionFactory.Create(GetWeather);
AIAgent weatherAgent = await aiProjectClient.CreateAIAgentAsync(
name: WeatherName,
model: deploymentName,
instructions: WeatherInstructions,
AIAgent weatherAgent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You answer questions about the weather.",
name: "WeatherAgent",
tools: [weatherTool]);
// Create the main agent, and provide the weather agent as a function tool.
AIAgent agent = await aiProjectClient.CreateAIAgentAsync(
name: MainName,
model: deploymentName,
instructions: MainInstructions,
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a helpful assistant who responds in French.",
name: "MainAgent",
tools: [weatherAgent.AsAIFunction()]);
// Invoke the agent and output the text result.
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?", session));
// Cleanup by agent name removes the agent versions created.
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
await aiProjectClient.Agents.DeleteAgentAsync(weatherAgent.Name);
@@ -0,0 +1,30 @@
# Agent as a Function Tool with the Responses API
This sample demonstrates how to use one agent as a function tool for another agent.
## What this sample demonstrates
- Creating a specialized agent (weather) with function tools
- Exposing an agent as a function tool using `.AsAIFunction()`
- Composing agents where one agent delegates to another
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step11_AsFunctionTool
```
@@ -3,15 +3,13 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Azure.AI.Projects" />
</ItemGroup>
<ItemGroup>
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows multiple middleware layers working together with Azure Foundry Agents:
// This sample shows multiple middleware layers working together with a ChatClientAgent:
// agent run (PII filtering and guardrails),
// function invocation (logging and result overrides), and human-in-the-loop
// approval workflows for sensitive function calls.
@@ -12,19 +12,6 @@ using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
// Get Azure AI Foundry configuration from environment variables
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = System.Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o";
const string AssistantInstructions = "You are an AI assistant that helps people find information.";
const string AssistantName = "InformationAssistant";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
@@ -33,14 +20,20 @@ static string GetWeather([Description("The location to get the weather for.")] s
static string GetDateTime()
=> DateTimeOffset.Now.ToString();
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AITool dateTimeTool = AIFunctionFactory.Create(GetDateTime, name: nameof(GetDateTime));
AITool getWeatherTool = AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather));
// Define the agent you want to create. (Prompt Agent in this case)
AIAgent originalAgent = await aiProjectClient.CreateAIAgentAsync(
name: AssistantName,
model: deploymentName,
instructions: AssistantInstructions,
AIAgent originalAgent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are an AI assistant that helps people find information.",
name: "InformationAssistant",
tools: [getWeatherTool, dateTimeTool]);
// Adding middleware to the agent level
@@ -63,24 +56,17 @@ AgentResponse piiResponse = await middlewareEnabledAgent.RunAsync("My name is Jo
Console.WriteLine($"Pii filtered response: {piiResponse}");
Console.WriteLine("\n\n=== Example 3: Agent function middleware ===");
// Agent function middleware support is limited to agents that wraps a upstream ChatClientAgent or derived from it.
AgentResponse functionCallResponse = await middlewareEnabledAgent.RunAsync("What's the current time and the weather in Seattle?", session);
Console.WriteLine($"Function calling response: {functionCallResponse}");
// Special per-request middleware agent.
Console.WriteLine("\n\n=== Example 4: Middleware with human in the loop function approval ===");
AIAgent humanInTheLoopAgent = await aiProjectClient.CreateAIAgentAsync(
AIAgent humanInTheLoopAgent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a Human in the loop testing AI assistant that helps people find information.",
name: "HumanInTheLoopAgent",
model: deploymentName,
instructions: "You are an Human in the loop testing AI assistant that helps people find information.",
// Adding a function with approval required
tools: [new ApprovalRequiredAIFunction(AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather)))]);
// Using the ConsolePromptingApprovalMiddleware for a specific request to handle user approval during function calls.
AgentResponse response = await humanInTheLoopAgent
.AsBuilder()
.Use(ConsolePromptingApprovalMiddleware, null)
@@ -108,7 +94,6 @@ async ValueTask<object?> FunctionCallOverrideWeather(AIAgent agent, FunctionInvo
if (context.Function.Name == nameof(GetWeather))
{
// Override the result of the GetWeather function
result = "The weather is sunny with a high of 25°C.";
}
Console.WriteLine($"Function Name: {context!.Function.Name} - Middleware 2 Post-Invoke");
@@ -118,18 +103,16 @@ async ValueTask<object?> FunctionCallOverrideWeather(AIAgent agent, FunctionInvo
// This middleware redacts PII information from input and output messages.
async Task<AgentResponse> PIIMiddleware(IEnumerable<ChatMessage> messages, AgentSession? session, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken)
{
// Redact PII information from input messages
var filteredMessages = FilterMessages(messages);
Console.WriteLine("Pii Middleware - Filtered Messages Pre-Run");
var response = await innerAgent.RunAsync(filteredMessages, session, options, cancellationToken).ConfigureAwait(false);
var agentResponse = await innerAgent.RunAsync(filteredMessages, session, options, cancellationToken).ConfigureAwait(false);
// Redact PII information from output messages
response.Messages = FilterMessages(response.Messages);
agentResponse.Messages = FilterMessages(agentResponse.Messages);
Console.WriteLine("Pii Middleware - Filtered Messages Post-Run");
return response;
return agentResponse;
static IList<ChatMessage> FilterMessages(IEnumerable<ChatMessage> messages)
{
@@ -138,11 +121,10 @@ async Task<AgentResponse> PIIMiddleware(IEnumerable<ChatMessage> messages, Agent
static string FilterPii(string content)
{
// Regex patterns for PII detection (simplified for demonstration)
Regex[] piiPatterns = [
new(@"\b\d{3}-\d{3}-\d{4}\b", RegexOptions.Compiled), // Phone number (e.g., 123-456-7890)
new(@"\b[\w\.-]+@[\w\.-]+\.\w+\b", RegexOptions.Compiled), // Email address
new(@"\b[A-Z][a-z]+\s[A-Z][a-z]+\b", RegexOptions.Compiled) // Full name (e.g., John Doe)
MyRegex(),
EmailRegex(),
FullNameRegex()
];
foreach (var pattern in piiPatterns)
@@ -157,20 +139,17 @@ async Task<AgentResponse> PIIMiddleware(IEnumerable<ChatMessage> messages, Agent
// This middleware enforces guardrails by redacting certain keywords from input and output messages.
async Task<AgentResponse> GuardrailMiddleware(IEnumerable<ChatMessage> messages, AgentSession? session, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken)
{
// Redact keywords from input messages
var filteredMessages = FilterMessages(messages);
Console.WriteLine("Guardrail Middleware - Filtered messages Pre-Run");
// Proceed with the agent run
var response = await innerAgent.RunAsync(filteredMessages, session, options, cancellationToken);
var agentResponse = await innerAgent.RunAsync(filteredMessages, session, options, cancellationToken);
// Redact keywords from output messages
response.Messages = FilterMessages(response.Messages);
agentResponse.Messages = FilterMessages(agentResponse.Messages);
Console.WriteLine("Guardrail Middleware - Filtered messages Post-Run");
return response;
return agentResponse;
List<ChatMessage> FilterMessages(IEnumerable<ChatMessage> messages)
{
@@ -194,16 +173,13 @@ async Task<AgentResponse> GuardrailMiddleware(IEnumerable<ChatMessage> messages,
// This middleware handles Human in the loop console interaction for any user approval required during function calling.
async Task<AgentResponse> ConsolePromptingApprovalMiddleware(IEnumerable<ChatMessage> messages, AgentSession? session, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken)
{
AgentResponse response = await innerAgent.RunAsync(messages, session, options, cancellationToken);
AgentResponse agentResponse = await innerAgent.RunAsync(messages, session, options, cancellationToken);
// For simplicity, we are assuming here that only function approvals are pending.
List<ToolApprovalRequestContent> approvalRequests = response.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().ToList();
List<ToolApprovalRequestContent> approvalRequests = agentResponse.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().ToList();
while (approvalRequests.Count > 0)
{
// Ask the user to approve each function call request.
// Pass the user input responses back to the agent for further processing.
response.Messages = approvalRequests
agentResponse.Messages = approvalRequests
.ConvertAll(functionApprovalRequest =>
{
Console.WriteLine($"The agent would like to invoke the following function, please reply Y to approve: Name {((FunctionCallContent)functionApprovalRequest.ToolCall).Name}");
@@ -211,13 +187,22 @@ async Task<AgentResponse> ConsolePromptingApprovalMiddleware(IEnumerable<ChatMes
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved)]);
});
response = await innerAgent.RunAsync(response.Messages, session, options, cancellationToken);
agentResponse = await innerAgent.RunAsync(agentResponse.Messages, session, options, cancellationToken);
approvalRequests = response.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().ToList();
approvalRequests = agentResponse.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().ToList();
}
return response;
return agentResponse;
}
// Cleanup by agent name removes the agent version created.
await aiProjectClient.Agents.DeleteAgentAsync(middlewareEnabledAgent.Name);
internal partial class Program
{
[GeneratedRegex(@"\b\d{3}-\d{3}-\d{4}\b", RegexOptions.Compiled)]
private static partial Regex MyRegex();
[GeneratedRegex(@"\b[\w\.-]+@[\w\.-]+\.\w+\b", RegexOptions.Compiled)]
private static partial Regex EmailRegex();
[GeneratedRegex(@"\b[A-Z][a-z]+\s[A-Z][a-z]+\b", RegexOptions.Compiled)]
private static partial Regex FullNameRegex();
}
@@ -0,0 +1,31 @@
# Middleware with the Responses API
This sample demonstrates multiple middleware layers working together: PII filtering, guardrails, function invocation logging, and human-in-the-loop approval.
## What this sample demonstrates
- Agent-level run middleware (PII filtering, guardrail enforcement)
- Function-level middleware (logging, result overrides)
- Human-in-the-loop approval workflows for sensitive function calls
- Using `.AsBuilder().Use()` to compose middleware
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\Agent_Step12_Middleware
```
@@ -10,13 +10,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,153 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use plugins with an AI agent. Plugin classes can
// depend on other services that need to be injected. In this sample, the
// AgentPlugin class uses the WeatherProvider and CurrentTimeProvider classes
// to get weather and current time information. Both services are registered
// in the service collection and injected into the plugin.
// Plugin classes may have many methods, but only some are intended to be used
// as AI functions. The AsAITools method of the plugin class shows how to specify
// which methods should be exposed to the AI agent.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using SampleApp;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
const string AssistantInstructions = "You are a helpful assistant that helps people find information.";
const string AssistantName = "PluginAssistant";
// Create a service collection to hold the agent plugin and its dependencies.
ServiceCollection services = new();
services.AddSingleton<WeatherProvider>();
services.AddSingleton<CurrentTimeProvider>();
services.AddSingleton<AgentPlugin>(); // The plugin depends on WeatherProvider and CurrentTimeProvider registered above.
IServiceProvider serviceProvider = services.BuildServiceProvider();
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a ChatClientAgent with the options-based constructor to pass services.
AIAgent agent = aiProjectClient.AsAIAgent(new ChatClientAgentOptions
{
Name = AssistantName,
ChatOptions = new() { ModelId = deploymentName, Instructions = AssistantInstructions, Tools = serviceProvider.GetRequiredService<AgentPlugin>().AsAITools().ToList() }
},
services: serviceProvider);
// Invoke the agent and output the text result.
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("Tell me current time and weather in Seattle.", session));
namespace SampleApp
{
/// <summary>
/// The agent plugin that provides weather and current time information.
/// </summary>
internal sealed class AgentPlugin
{
private readonly WeatherProvider _weatherProvider;
/// <summary>
/// Initializes a new instance of the <see cref="AgentPlugin"/> class.
/// </summary>
/// <param name="weatherProvider">The weather provider to get weather information.</param>
public AgentPlugin(WeatherProvider weatherProvider)
{
this._weatherProvider = weatherProvider;
}
/// <summary>
/// Gets the weather information for the specified location.
/// </summary>
/// <remarks>
/// This method demonstrates how to use the dependency that was injected into the plugin class.
/// </remarks>
/// <param name="location">The location to get the weather for.</param>
/// <returns>The weather information for the specified location.</returns>
public string GetWeather(string location)
{
return this._weatherProvider.GetWeather(location);
}
/// <summary>
/// Gets the current date and time for the specified location.
/// </summary>
/// <remarks>
/// This method demonstrates how to resolve a dependency using the service provider passed to the method.
/// </remarks>
/// <param name="sp">The service provider to resolve the <see cref="CurrentTimeProvider"/>.</param>
/// <param name="location">The location to get the current time for.</param>
/// <returns>The current date and time as a <see cref="DateTimeOffset"/>.</returns>
public DateTimeOffset GetCurrentTime(IServiceProvider sp, string location)
{
CurrentTimeProvider currentTimeProvider = sp.GetRequiredService<CurrentTimeProvider>();
return currentTimeProvider.GetCurrentTime(location);
}
/// <summary>
/// Returns the functions provided by this plugin.
/// </summary>
/// <remarks>
/// In real world scenarios, a class may have many methods and only a subset of them may be intended to be exposed as AI functions.
/// This method demonstrates how to explicitly specify which methods should be exposed to the AI agent.
/// </remarks>
/// <returns>The functions provided by this plugin.</returns>
public IEnumerable<AITool> AsAITools()
{
yield return AIFunctionFactory.Create(this.GetWeather);
yield return AIFunctionFactory.Create(this.GetCurrentTime);
}
}
internal sealed class WeatherProvider
{
private readonly string _weatherSummary = "cloudy with a high of 15°C";
/// <summary>
/// The weather provider that returns weather information.
/// </summary>
/// <summary>
/// Gets the weather information for the specified location.
/// </summary>
/// <remarks>
/// The weather information is hardcoded for demonstration purposes.
/// In a real application, this could call a weather API to get actual weather data.
/// </remarks>
/// <param name="location">The location to get the weather for.</param>
/// <returns>The weather information for the specified location.</returns>
public string GetWeather(string location)
{
return $"The weather in {location} is {this._weatherSummary}.";
}
}
internal sealed class CurrentTimeProvider
{
private readonly TimeProvider _timeProvider = TimeProvider.System;
/// <summary>
/// Provides the current date and time.
/// </summary>
/// <remarks>
/// This class returns the current date and time using the system's clock.
/// </remarks>
/// <summary>
/// Gets the current date and time.
/// </summary>
/// <param name="location">The location to get the current time for (not used in this implementation).</param>
/// <returns>The current date and time as a <see cref="DateTimeOffset"/>.</returns>
public DateTimeOffset GetCurrentTime(string location)
{
return this._timeProvider.GetLocalNow();
}
}
}
@@ -0,0 +1,29 @@
# Using Plugins with the Responses API
This sample shows how to use plugins with a `ChatClientAgent` using the Responses API directly, with dependency injection for plugin services.
## What this sample demonstrates
- Creating plugin classes with injected dependencies
- Registering services and building a service provider
- Passing `services` to the `ChatClientAgent` via the options-based constructor
- Using `AIFunctionFactory` to expose plugin methods as AI tools
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -9,7 +9,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Azure.Identity" />
</ItemGroup>
@@ -1,61 +1,31 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use Code Interpreter Tool with AI Agents.
// This sample shows how to use Code Interpreter Tool with AIProjectClient.AsAIAgent(...).
using System.Text;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.Assistants;
using OpenAI.Responses;
const string AgentInstructions = "You are a personal math tutor. When asked a math question, write and run code using the python tool to answer the question.";
const string AgentName = "CoderAgent-RAPI";
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
const string AgentInstructions = "You are a personal math tutor. When asked a math question, write and run code using the python tool to answer the question.";
const string AgentNameMEAI = "CoderAgent-MEAI";
const string AgentNameNative = "CoderAgent-NATIVE";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Option 1 - Using HostedCodeInterpreterTool + AgentOptions (MEAI + AgentFramework)
// Create the server side agent version
AIAgent agentOption1 = await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
name: AgentNameMEAI,
AIAgent agent = aiProjectClient.AsAIAgent(
deploymentName,
instructions: AgentInstructions,
name: AgentName,
tools: [new HostedCodeInterpreterTool() { Inputs = [] }]);
// Option 2 - Using PromptAgentDefinition SDK native type
// Create the server side agent version
AIAgent agentOption2 = await aiProjectClient.CreateAIAgentAsync(
name: AgentNameNative,
creationOptions: new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = AgentInstructions,
Tools = {
ResponseTool.CreateCodeInterpreterTool(
new CodeInterpreterToolContainer(
CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration(fileIds: [])
)
),
}
})
);
// Either invoke option1 or option2 agent, should have same result
// Option 1
AgentResponse response = await agentOption1.RunAsync("I need to solve the equation sin(x) + x^2 = 42");
// Option 2
// AgentResponse response = await agentOption2.RunAsync("I need to solve the equation sin(x) + x^2 = 42");
AgentResponse response = await agent.RunAsync("I need to solve the equation sin(x) + x^2 = 42");
// Get the CodeInterpreterToolCallContent
CodeInterpreterToolCallContent? toolCallContent = response.Messages.SelectMany(m => m.Contents).OfType<CodeInterpreterToolCallContent>().FirstOrDefault();
@@ -87,7 +57,3 @@ foreach (AIAnnotation annotation in response.Messages.SelectMany(m => m.Contents
""");
}
}
// Cleanup by agent name removes the agent version created.
await aiProjectClient.Agents.DeleteAgentAsync(agentOption1.Name);
await aiProjectClient.Agents.DeleteAgentAsync(agentOption2.Name);
@@ -0,0 +1,28 @@
# Code Interpreter with the Responses API
This sample shows how to use the Code Interpreter tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Using `HostedCodeInterpreterTool` with `ChatClientAgent`
- Extracting code input and output from agent responses
- Handling code interpreter annotations and file citations
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -1,11 +1,11 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use Computer Use Tool with AI Agents.
// This sample shows how to use Computer Use Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AzureAI;
using Microsoft.Extensions.AI;
using OpenAI.Responses;
@@ -15,59 +15,32 @@ internal sealed class Program
{
private static async Task Main(string[] args)
{
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "computer-use-preview";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
const string AgentInstructions = @"
You are a computer automation assistant.
Be direct and efficient. When you reach the search results page, read and describe the actual search result titles and descriptions you can see.
";
const string AgentNameMEAI = "ComputerAgent-MEAI";
const string AgentNameNative = "ComputerAgent-NATIVE";
const string AgentName = "ComputerAgent-RAPI";
// Option 1 - Using ComputerUseTool + AgentOptions (MEAI + AgentFramework)
// Create AIAgent directly
AIAgent agentOption1 = await aiProjectClient.CreateAIAgentAsync(
name: AgentNameMEAI,
model: deploymentName,
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "computer-use-preview";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a AIAgent with ComputerUseTool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: AgentName,
description: "Computer automation agent with screen interaction capabilities.",
tools: [
ResponseTool.CreateComputerTool(ComputerToolEnvironment.Browser, 1026, 769).AsAITool(),
FoundryAITool.CreateComputerTool(ComputerToolEnvironment.Browser, 1026, 769),
]);
// Option 2 - Using PromptAgentDefinition SDK native type
// Create the server side agent version
AIAgent agentOption2 = await aiProjectClient.CreateAIAgentAsync(
name: AgentNameNative,
creationOptions: new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = AgentInstructions,
Tools = { ResponseTool.CreateComputerTool(
environment: new ComputerToolEnvironment("windows"),
displayWidth: 1026,
displayHeight: 769) }
})
);
// Either invoke option1 or option2 agent, should have same result
// Option 1
await InvokeComputerUseAgentAsync(agentOption1);
// Option 2
//await InvokeComputerUseAgentAsync(agentOption2);
// Cleanup by agent name removes the agent version created.
await aiProjectClient.Agents.DeleteAgentAsync(agentOption1.Name);
await aiProjectClient.Agents.DeleteAgentAsync(agentOption2.Name);
await InvokeComputerUseAgentAsync(agent);
}
private static async Task InvokeComputerUseAgentAsync(AIAgent agent)
@@ -94,10 +67,8 @@ internal sealed class Program
// Initial request with screenshot - start with Bing search page
Console.WriteLine("Starting computer automation session (initial screenshot: cua_browser_search.png)...");
// IMPORTANT: Computer-use with the Azure Agents API differs from the vanilla OpenAI Responses API.
// The Azure Agents API rejects requests that include previous_response_id alongside
// computer_call_output items. To work around this, each call uses a fresh session (avoiding
// previous_response_id) and re-sends the full conversation context as input items instead.
// We use PreviousResponseId to chain calls, sending only the new computer_call_output items
// instead of re-sending the full context.
AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync(message, session: session, options: runOptions);
@@ -161,31 +132,15 @@ internal sealed class Program
Console.WriteLine("Sending action result back to agent...");
// Build the follow-up messages with full conversation context.
// The Azure Agents API rejects previous_response_id when computer_call_output items are
// present, so we must re-send all prior output items (reasoning, computer_call, etc.)
// as input items alongside the computer_call_output to maintain conversation continuity.
List<ChatMessage> followUpMessages = [];
// Re-send all response output items as an assistant message so the API has full context
List<AIContent> priorOutputContents = response.Messages
.SelectMany(m => m.Contents)
.ToList();
followUpMessages.Add(new ChatMessage(ChatRole.Assistant, priorOutputContents));
// Add the computer_call_output as a user message
// Send only the computer_call_output — the session carries PreviousResponseId for context continuity.
AIContent callOutput = new()
{
RawRepresentation = new ComputerCallOutputResponseItem(
currentCallId,
output: ComputerCallOutput.CreateScreenshotOutput(new BinaryData(screenInfo.ImageBytes), "image/png"))
};
followUpMessages.Add(new ChatMessage(ChatRole.User, [callOutput]));
// Create a fresh session so ConversationId does not carry over a previous_response_id.
// Without this, the Azure Agents API returns an error when computer_call_output is present.
session = await agent.CreateSessionAsync();
response = await agent.RunAsync(followUpMessages, session: session, options: runOptions);
response = await agent.RunAsync([new ChatMessage(ChatRole.User, [callOutput])], session: session, options: runOptions);
}
}
}
@@ -0,0 +1,29 @@
# Computer Use with the Responses API
This sample shows how to use the Computer Use tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Using `FoundryAITool.CreateComputerTool()` with `ChatClientAgent`
- Processing computer call actions (click, type, key press)
- Managing the computer use interaction loop with screenshots
- Handling the Azure Agents API workaround for `previous_response_id` with `computer_call_output`
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="computer-use-preview"
```
## Run the sample
```powershell
dotnet run
```
@@ -9,7 +9,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Azure.Identity" />
</ItemGroup>
@@ -1,22 +1,20 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use File Search Tool with AI Agents.
// This sample shows how to use File Search Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.Assistants;
using OpenAI.Files;
using OpenAI.Responses;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
const string AgentInstructions = "You are a helpful assistant that can search through uploaded files to answer questions.";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// We need the AIProjectClient to upload files and create vector stores.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
@@ -52,8 +50,11 @@ var vectorStoreResult = await vectorStoresClient.CreateVectorStoreAsync(
string vectorStoreId = vectorStoreResult.Value.Id;
Console.WriteLine($"Created vector store, vector store ID: {vectorStoreId}");
AIAgent agent = await CreateAgentWithMEAI();
// AIAgent agent = await CreateAgentWithNativeSDK();
// Create a AIAgent with HostedFileSearchTool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: "FileSearchAgent-RAPI",
tools: [new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreId)] }]);
// Run the agent
Console.WriteLine("\n--- Running File Search Agent ---");
@@ -73,39 +74,9 @@ foreach (AIAnnotation annotation in response.Messages.SelectMany(m => m.Contents
}
}
// Cleanup.
// Cleanup file resources.
Console.WriteLine("\n--- Cleanup ---");
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
await vectorStoresClient.DeleteVectorStoreAsync(vectorStoreId);
await filesClient.DeleteFileAsync(uploadedFile.Id);
File.Delete(searchFilePath);
Console.WriteLine("Cleanup completed successfully.");
// --- Agent Creation Options ---
#pragma warning disable CS8321 // Local function is declared but never used
// Option 1 - Using HostedFileSearchTool (MEAI + AgentFramework)
async Task<AIAgent> CreateAgentWithMEAI()
{
return await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
name: "FileSearchAgent-MEAI",
instructions: AgentInstructions,
tools: [new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreId)] }]);
}
// Option 2 - Using PromptAgentDefinition with ResponseTool.CreateFileSearchTool (Native SDK)
async Task<AIAgent> CreateAgentWithNativeSDK()
{
return await aiProjectClient.CreateAIAgentAsync(
name: "FileSearchAgent-NATIVE",
creationOptions: new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = AgentInstructions,
Tools = {
ResponseTool.CreateFileSearchTool(vectorStoreIds: [vectorStoreId])
}
})
);
}
@@ -0,0 +1,29 @@
# File Search with the Responses API
This sample shows how to use the File Search tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Uploading files and creating vector stores via `AIProjectClient`
- Using `HostedFileSearchTool` with `ChatClientAgent`
- Handling file citation annotations in agent responses
- Cleaning up file resources after use
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -6,15 +6,14 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>$(NoWarn);IDE0059</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
@@ -6,16 +6,32 @@ using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using OpenAI.Responses;
using Microsoft.Agents.AI.AzureAI;
using Microsoft.Extensions.AI;
// Warning: DefaultAzureCredential is intended for simplicity in development. For production scenarios, consider using a more specific credential.
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
const string AgentInstructions = "You are a helpful assistant that can use the countries API to retrieve information about countries by their currency code.";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// A simple OpenAPI specification for the REST Countries API
const string CountriesOpenApiSpec = """
AITool openApiTool = FoundryAITool.CreateOpenApiTool(CreateOpenAPIFunctionDefinition());
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: "OpenAPIToolsAgent",
tools: [openApiTool]);
// Run the agent with a question about countries
Console.WriteLine(await agent.RunAsync("What countries use the Euro (EUR) as their currency? Please list them."));
OpenApiFunctionDefinition CreateOpenAPIFunctionDefinition()
{
// A simple OpenAPI specification for the REST Countries API
const string CountriesOpenApiSpec = """
{
"openapi": "3.1.0",
"info": {
@@ -68,49 +84,12 @@ const string CountriesOpenApiSpec = """
}
""";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create the OpenAPI function definition
var openApiFunction = new OpenApiFunctionDefinition(
"get_countries",
BinaryData.FromString(CountriesOpenApiSpec),
new OpenAPIAnonymousAuthenticationDetails())
{
Description = "Retrieve information about countries by currency code"
};
AIAgent agent = await CreateAgentWithMEAI();
// AIAgent agent = await CreateAgentWithNativeSDK();
// Run the agent with a question about countries
Console.WriteLine(await agent.RunAsync("What countries use the Euro (EUR) as their currency? Please list them."));
// Cleanup by deleting the agent
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
// --- Agent Creation Options ---
// Option 1 - Using AsAITool wrapping for OpenApiTool (MEAI + AgentFramework)
async Task<AIAgent> CreateAgentWithMEAI()
{
return await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
name: "OpenAPIToolsAgent-MEAI",
instructions: AgentInstructions,
tools: [((ResponseTool)AgentTool.CreateOpenApiTool(openApiFunction)).AsAITool()]);
}
// Option 2 - Using PromptAgentDefinition with AgentTool.CreateOpenApiTool (Native SDK)
async Task<AIAgent> CreateAgentWithNativeSDK()
{
return await aiProjectClient.CreateAIAgentAsync(
name: "OpenAPIToolsAgent-NATIVE",
creationOptions: new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = AgentInstructions,
Tools = { (ResponseTool)AgentTool.CreateOpenApiTool(openApiFunction) }
})
);
// Create the OpenAPI function definition
return new(
"get_countries",
BinaryData.FromString(CountriesOpenApiSpec),
new OpenAPIAnonymousAuthenticationDetails())
{
Description = "Retrieve information about countries by currency code"
};
}
@@ -0,0 +1,29 @@
# OpenAPI Tools with the Responses API
This sample shows how to use OpenAPI tools with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Defining an OpenAPI specification inline
- Creating an `OpenAPIFunctionDefinition` for the REST Countries API
- Using `FoundryAITool.CreateOpenApiTool()` with `ChatClientAgent`
- Server-side execution of OpenAPI tool calls
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -9,7 +9,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Azure.Identity" />
</ItemGroup>
@@ -1,15 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use Bing Custom Search Tool with AI Agents.
// This sample shows how to use Bing Custom Search Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using OpenAI.Responses;
using Microsoft.Agents.AI.AzureAI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
string connectionId = Environment.GetEnvironmentVariable("AZURE_AI_CUSTOM_SEARCH_CONNECTION_ID") ?? throw new InvalidOperationException("AZURE_AI_CUSTOM_SEARCH_CONNECTION_ID is not set.");
string instanceName = Environment.GetEnvironmentVariable("AZURE_AI_CUSTOM_SEARCH_INSTANCE_NAME") ?? throw new InvalidOperationException("AZURE_AI_CUSTOM_SEARCH_INSTANCE_NAME is not set.");
@@ -18,19 +16,24 @@ const string AgentInstructions = """
Use the available Bing Custom Search tools to answer questions and perform tasks.
""";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// Bing Custom Search tool parameters
BingCustomSearchToolOptions bingCustomSearchToolParameters = new([
new BingCustomSearchConfiguration(connectionId, instanceName)
]);
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Bing Custom Search tool parameters shared by both options
BingCustomSearchToolOptions bingCustomSearchToolParameters = new([
new BingCustomSearchConfiguration(connectionId, instanceName)
]);
AIAgent agent = await CreateAgentWithMEAIAsync();
// AIAgent agent = await CreateAgentWithNativeSDKAsync();
// Create a AIAgent with Bing Custom Search tool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: "BingCustomSearchAgent-RAPI",
tools: [FoundryAITool.CreateBingCustomSearchTool(bingCustomSearchToolParameters)]);
Console.WriteLine($"Created agent: {agent.Name}");
@@ -42,35 +45,3 @@ foreach (var message in response.Messages)
{
Console.WriteLine(message.Text);
}
// Cleanup by deleting the agent
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
Console.WriteLine($"\nDeleted agent: {agent.Name}");
// --- Agent Creation Options ---
// Option 1 - Using AsAITool wrapping for the ResponseTool returned by AgentTool.CreateBingCustomSearchTool (MEAI + AgentFramework)
async Task<AIAgent> CreateAgentWithMEAIAsync()
{
return await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
name: "BingCustomSearchAgent-MEAI",
instructions: AgentInstructions,
tools: [((ResponseTool)AgentTool.CreateBingCustomSearchTool(bingCustomSearchToolParameters)).AsAITool()]);
}
// Option 2 - Using PromptAgentDefinition with AgentTool.CreateBingCustomSearchTool (Native SDK)
async Task<AIAgent> CreateAgentWithNativeSDKAsync()
{
return await aiProjectClient.CreateAIAgentAsync(
name: "BingCustomSearchAgent-NATIVE",
creationOptions: new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = AgentInstructions,
Tools = {
(ResponseTool)AgentTool.CreateBingCustomSearchTool(bingCustomSearchToolParameters),
}
})
);
}
@@ -0,0 +1,36 @@
# Bing Custom Search with the Responses API
This sample shows how to use the Bing Custom Search tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Configuring `BingCustomSearchToolParameters` with connection ID and instance name
- Using `FoundryAITool.CreateBingCustomSearchTool()` with `ChatClientAgent`
- Processing search results from agent responses
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
- Bing Custom Search resource configured with a connection ID
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
$env:AZURE_AI_CUSTOM_SEARCH_CONNECTION_ID="your-connection-id" # The full ARM resource URI, e.g., "/subscriptions/.../connections/your-bing-connection"
$env:AZURE_AI_CUSTOM_SEARCH_INSTANCE_NAME="your-instance-name" # The Bing Custom Search configuration name (from Azure portal)
```
### Finding the connection ID and instance name
- **Connection ID** (`AZURE_AI_CUSTOM_SEARCH_CONNECTION_ID`): The full ARM resource URI including the `/projects/<name>/connections/<connection-name>` segment. Find the connection name in your Foundry project under **Management center** → **Connected resources**.
- **Instance Name** (`AZURE_AI_CUSTOM_SEARCH_INSTANCE_NAME`): The **configuration name** from your Bing Custom Search resource (Azure portal → your Bing Custom Search resource → **Configurations**). This is _not_ the Azure resource name or the connection name — it's the name of the specific search configuration that defines which domains/sites to search against.
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -1,15 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use SharePoint Grounding Tool with AI Agents.
// This sample shows how to use SharePoint Grounding Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using OpenAI.Responses;
using Microsoft.Agents.AI.AzureAI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
string sharepointConnectionId = Environment.GetEnvironmentVariable("SHAREPOINT_PROJECT_CONNECTION_ID") ?? throw new InvalidOperationException("SHAREPOINT_PROJECT_CONNECTION_ID is not set.");
const string AgentInstructions = """
@@ -17,18 +15,23 @@ const string AgentInstructions = """
Use the available SharePoint tools to answer questions and perform tasks.
""";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
// Create SharePoint tool options with project connection
var sharepointOptions = new SharePointGroundingToolOptions();
sharepointOptions.ProjectConnections.Add(new ToolProjectConnection(sharepointConnectionId));
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create SharePoint tool options with project connection
var sharepointOptions = new SharePointGroundingToolOptions();
sharepointOptions.ProjectConnections.Add(new ToolProjectConnection(sharepointConnectionId));
AIAgent agent = await CreateAgentWithMEAIAsync();
// AIAgent agent = await CreateAgentWithNativeSDKAsync();
// Create a AIAgent with SharePoint tool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: "SharePointAgent-RAPI",
tools: [FoundryAITool.CreateSharepointTool(sharepointOptions)]);
Console.WriteLine($"Created agent: {agent.Name}");
@@ -52,33 +55,3 @@ foreach (var message in response.Messages)
}
}
}
// Cleanup by agent name removes the agent version created.
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
Console.WriteLine($"\nDeleted agent: {agent.Name}");
// --- Agent Creation Options ---
// Option 1 - Using AgentTool.CreateSharepointTool + AsAITool() (MEAI + AgentFramework)
async Task<AIAgent> CreateAgentWithMEAIAsync()
{
return await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
name: "SharePointAgent-MEAI",
instructions: AgentInstructions,
tools: [((ResponseTool)AgentTool.CreateSharepointTool(sharepointOptions)).AsAITool()]);
}
// Option 2 - Using PromptAgentDefinition SDK native type
async Task<AIAgent> CreateAgentWithNativeSDKAsync()
{
return await aiProjectClient.CreateAIAgentAsync(
name: "SharePointAgent-NATIVE",
creationOptions: new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = AgentInstructions,
Tools = { AgentTool.CreateSharepointTool(sharepointOptions) }
})
);
}
@@ -0,0 +1,30 @@
# SharePoint Grounding with the Responses API
This sample shows how to use the SharePoint Grounding tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Configuring `SharePointGroundingToolOptions` with project connections
- Using `FoundryAITool.CreateSharepointTool()` with `ChatClientAgent`
- Displaying grounding annotations from agent responses
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
- SharePoint connection configured in your Microsoft Foundry project
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
$env:SHAREPOINT_PROJECT_CONNECTION_ID="your-sharepoint-connection-id" # The full ARM resource URI, e.g., "/subscriptions/.../connections/SharepointTestTool"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use Microsoft Fabric Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AzureAI;
string fabricConnectionId = Environment.GetEnvironmentVariable("FABRIC_PROJECT_CONNECTION_ID") ?? throw new InvalidOperationException("FABRIC_PROJECT_CONNECTION_ID is not set.");
const string AgentInstructions = "You are a helpful assistant with access to Microsoft Fabric data. Answer questions based on data available through your Fabric connection.";
// Configure Microsoft Fabric tool options with project connection
var fabricToolOptions = new FabricDataAgentToolOptions();
fabricToolOptions.ProjectConnections.Add(new ToolProjectConnection(fabricConnectionId));
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a AIAgent with Microsoft Fabric tool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: "FabricAgent-RAPI",
tools: [FoundryAITool.CreateMicrosoftFabricTool(fabricToolOptions)]);
Console.WriteLine($"Created agent: {agent.Name}");
// Run the agent with a sample query
AgentResponse response = await agent.RunAsync("What data is available in the connected Fabric workspace?");
Console.WriteLine("\n=== Agent Response ===");
foreach (var message in response.Messages)
{
Console.WriteLine(message.Text);
}
@@ -0,0 +1,30 @@
# Microsoft Fabric with the Responses API
This sample shows how to use the Microsoft Fabric tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Configuring `FabricDataAgentToolOptions` with project connections
- Using `FoundryAITool.CreateMicrosoftFabricTool()` with `ChatClientAgent`
- Querying data available through a Fabric connection
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
- Microsoft Fabric connection configured in your Microsoft Foundry project
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
$env:FABRIC_PROJECT_CONNECTION_ID="your-fabric-connection-id" # The full ARM resource URI, e.g., "/subscriptions/.../connections/FabricTestTool"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use the Web Search Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.Responses;
const string AgentInstructions = "You are a helpful assistant that can search the web to find current information and answer questions accurately.";
const string AgentName = "WebSearchAgent-RAPI";
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a AIAgent with HostedWebSearchTool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: AgentName,
tools: [new HostedWebSearchTool()]);
AgentResponse response = await agent.RunAsync("What's the weather today in Seattle?");
// Get the text response
Console.WriteLine($"Response: {response.Text}");
// Getting any annotations/citations generated by the web search tool
foreach (AIAnnotation annotation in response.Messages.SelectMany(m => m.Contents).SelectMany(c => c.Annotations ?? []))
{
Console.WriteLine($"Annotation: {annotation}");
if (annotation.RawRepresentation is UriCitationMessageAnnotation urlCitation)
{
Console.WriteLine($$"""
Title: {{urlCitation.Title}}
URL: {{urlCitation.Uri}}
""");
}
}
@@ -0,0 +1,28 @@
# Web Search with the Responses API
This sample shows how to use the Web Search tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Using `HostedWebSearchTool` with `ChatClientAgent`
- Processing web search citations and annotations
- Extracting URL citation details (title, URL) from responses
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -9,6 +9,8 @@ using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AzureAI;
using Microsoft.Extensions.AI;
using OpenAI.Responses;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
@@ -22,27 +24,25 @@ const string AgentInstructions = """
When a user shares personal details or preferences, remember them for future conversations.
""";
const string AgentNameMEAI = "MemorySearchAgent-MEAI";
const string AgentNameNative = "MemorySearchAgent-NATIVE";
const string AgentName = "MemorySearchAgent";
// Scope identifies the user or context for memory isolation.
// Using a unique user identifier ensures memories are private to that user.
string userScope = $"user_{Environment.MachineName}";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
DefaultAzureCredential credential = new();
AIProjectClient aiProjectClient = new(new Uri(endpoint), credential);
MemorySearchPreviewTool memorySearchTool = new(memoryStoreName, userScope) { UpdateDelayInSecs = 0 };
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create agent using the RAPI path with the MemorySearch tool
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: AgentName,
tools: [FoundryAITool.FromResponseTool(memorySearchTool)]);
// Ensure the memory store exists and has memories to retrieve.
await EnsureMemoryStoreAsync();
// Create the Memory Search tool configuration
MemorySearchPreviewTool memorySearchTool = new(memoryStoreName, userScope) { UpdateDelayInSecs = 0 };
// Create agent using Option 1 (MEAI) or Option 2 (Native SDK)
AIAgent agent = await CreateAgentWithMEAI();
// AIAgent agent = await CreateAgentWithNativeSDK();
try
{
Console.WriteLine("Agent created with Memory Search tool. Starting conversation...\n");
@@ -73,41 +73,14 @@ try
}
finally
{
// Cleanup: Delete the agent and memory store.
// Cleanup: Delete the memory store (no server-side agent to clean up in RAPI path).
Console.WriteLine("\nCleaning up...");
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
Console.WriteLine("Agent deleted.");
await aiProjectClient.MemoryStores.DeleteMemoryStoreAsync(memoryStoreName);
Console.WriteLine("Memory store deleted.");
}
#pragma warning disable CS8321 // Local function is declared but never used
// Option 1 - Using MemorySearchTool wrapped as MEAI AITool
async Task<AIAgent> CreateAgentWithMEAI()
{
return await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
name: AgentNameMEAI,
instructions: AgentInstructions,
tools: [((ResponseTool)memorySearchTool).AsAITool()]);
}
// Option 2 - Using PromptAgentDefinition with MemorySearchTool (Native SDK)
async Task<AIAgent> CreateAgentWithNativeSDK()
{
return await aiProjectClient.CreateAIAgentAsync(
name: AgentNameNative,
creationOptions: new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = AgentInstructions,
Tools = { memorySearchTool }
})
);
}
// Helpers — kept at the bottom so the main agent flow above stays clean.
async Task EnsureMemoryStoreAsync()
{
Console.WriteLine($"Creating memory store '{memoryStoreName}'...");
@@ -123,19 +96,37 @@ async Task EnsureMemoryStoreAsync()
Console.WriteLine("Memory store created.");
}
// Explicitly add memories from a simulated prior conversation.
Console.WriteLine("Storing memories from a prior conversation...");
MemoryUpdateOptions memoryOptions = new(userScope) { UpdateDelay = 0 };
memoryOptions.Items.Add(ResponseItem.CreateUserMessageItem("My name is Alice and I love programming in C#."));
memoryOptions.Items.Add(ResponseItem.CreateUserMessageItem("My name is Alice and I prefer C#."));
MemoryUpdateResult updateResult = await aiProjectClient.MemoryStores.WaitForMemoriesUpdateAsync(
memoryStoreName: memoryStoreName,
pollingInterval: 500,
options: memoryOptions);
options: memoryOptions,
pollingInterval: 500);
if (updateResult.Status == MemoryStoreUpdateStatus.Failed)
{
throw new InvalidOperationException($"Memory update failed: {updateResult.ErrorDetails}");
}
Console.WriteLine($"Memory update completed (status: {updateResult.Status}).\n");
Console.WriteLine($"Memory update completed (status: {updateResult.Status}).");
// Quick verification that memories are searchable.
Console.WriteLine("Verifying stored memories...");
MemorySearchOptions searchOptions = new(userScope)
{
Items = { ResponseItem.CreateUserMessageItem("What are Alice's preferences?") }
};
MemoryStoreSearchResponse searchResult = await aiProjectClient.MemoryStores.SearchMemoriesAsync(
memoryStoreName: memoryStoreName,
options: searchOptions);
foreach (var memory in searchResult.Memories)
{
Console.WriteLine($" - {memory.MemoryItem.Content}");
}
Console.WriteLine();
}
@@ -0,0 +1,31 @@
# Memory Search with the Responses API
This sample demonstrates how to use the Memory Search tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Configuring `MemorySearchPreviewTool` with a memory store and user scope
- Using memory search for cross-conversation recall
- Inspecting `MemorySearchToolCallResponseItem` results
- User profile persistence across conversations
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
- A memory store created beforehand via Azure Portal or Python SDK
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
$env:AZURE_AI_MEMORY_STORE_ID="your-memory-store-name"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
<PackageReference Include="ModelContextProtocol" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -1,24 +1,20 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample demonstrates how to use a local MCP (Model Context Protocol) client with Azure Foundry Agents.
// The MCP tools are resolved locally by connecting directly to the MCP server via HTTP,
// and then passed to the Foundry agent as client-side tools.
// This sample uses the Microsoft Learn MCP endpoint to search documentation.
// This sample demonstrates how to wrap MCP tools with a DelegatingAIFunction to add custom behavior (e.g., logging).
// Compare with Step09 which shows basic MCP tool usage without wrapping.
// The LoggingMcpTool pattern is useful for diagnostics, metering, or adding approval logic around tool calls.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Client;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
using SampleApp;
const string AgentInstructions = "You are a helpful assistant that can help with Microsoft documentation questions. Use the Microsoft Learn MCP tool to search for documentation.";
const string AgentName = "DocsAgent";
const string AgentName = "DocsAgent-RAPI";
// Connect to the MCP server locally via HTTP (Streamable HTTP transport).
// The MCP server is hosted at Microsoft Learn and provides documentation search capabilities.
Console.WriteLine("Connecting to MCP server at https://learn.microsoft.com/api/mcp ...");
await using McpClient mcpClient = await McpClient.CreateAsync(new HttpClientTransport(new()
@@ -34,53 +30,48 @@ Console.WriteLine($"MCP tools available: {string.Join(", ", mcpTools.Select(t =>
// Wrap each MCP tool with a DelegatingAIFunction to log local invocations.
List<AITool> wrappedTools = mcpTools.Select(tool => (AITool)new LoggingMcpTool(tool)).ToList();
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create the agent with the locally-resolved MCP tools.
AIAgent agent = await aiProjectClient.CreateAIAgentAsync(
model: deploymentName,
name: AgentName,
// Create a AIAgent with the locally-resolved MCP tools.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: AgentName,
tools: wrappedTools);
Console.WriteLine($"Agent '{agent.Name}' created successfully.");
try
{
// First query
const string Prompt1 = "How does one create an Azure storage account using az cli?";
Console.WriteLine($"\nUser: {Prompt1}\n");
AgentResponse response1 = await agent.RunAsync(Prompt1);
Console.WriteLine($"Agent: {response1}");
// First query
const string Prompt1 = "How does one create an Azure storage account using az cli?";
Console.WriteLine($"\nUser: {Prompt1}\n");
AgentResponse response1 = await agent.RunAsync(Prompt1);
Console.WriteLine($"Agent: {response1}");
Console.WriteLine("\n=======================================\n");
Console.WriteLine("\n=======================================\n");
// Second query
const string Prompt2 = "What is Microsoft Agent Framework?";
Console.WriteLine($"User: {Prompt2}\n");
AgentResponse response2 = await agent.RunAsync(Prompt2);
Console.WriteLine($"Agent: {response2}");
}
finally
{
// Cleanup by removing the agent when done
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
Console.WriteLine($"\nAgent '{agent.Name}' deleted.");
}
// Second query
const string Prompt2 = "What is Microsoft Agent Framework?";
Console.WriteLine($"User: {Prompt2}\n");
AgentResponse response2 = await agent.RunAsync(Prompt2);
Console.WriteLine($"Agent: {response2}");
/// <summary>
/// Wraps an MCP tool to log when it is invoked locally,
/// confirming that the MCP call is happening client-side.
/// </summary>
internal sealed class LoggingMcpTool(AIFunction innerFunction) : DelegatingAIFunction(innerFunction)
namespace SampleApp
{
protected override ValueTask<object?> InvokeCoreAsync(AIFunctionArguments arguments, CancellationToken cancellationToken)
/// <summary>
/// Wraps an MCP tool to log when it is invoked locally,
/// confirming that the MCP call is happening client-side.
/// </summary>
internal sealed class LoggingMcpTool(AIFunction innerFunction) : DelegatingAIFunction(innerFunction)
{
Console.WriteLine($" >> [LOCAL MCP] Invoking tool '{this.Name}' locally...");
return base.InvokeCoreAsync(arguments, cancellationToken);
protected override ValueTask<object?> InvokeCoreAsync(AIFunctionArguments arguments, CancellationToken cancellationToken)
{
Console.WriteLine($" >> [LOCAL MCP] Invoking tool '{this.Name}' locally...");
return base.InvokeCoreAsync(arguments, cancellationToken);
}
}
}
@@ -0,0 +1,29 @@
# Local MCP with the Responses API
This sample demonstrates how to use a local MCP (Model Context Protocol) client with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Connecting to an MCP server via HTTP (Streamable HTTP transport)
- Resolving MCP tools locally and wrapping them with logging
- Using `DelegatingAIFunction` to add custom behavior to MCP tools
- Passing locally-resolved MCP tools to `ChatClientAgent`
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (`az login`)
Set the following environment variables:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,81 @@
# Getting started with Foundry Agents
These samples demonstrate how to use Azure AI Foundry with Agent Framework.
## Quick start
The simplest way to create a Foundry agent is using the `FoundryAgent` type directly:
```csharp
FoundryAgent agent = new(
new Uri(endpoint),
new AzureCliCredential(),
model: "gpt-4o-mini",
instructions: "You are good at telling jokes.",
name: "JokerAgent");
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
```
Or using the `AIProjectClient.AsAIAgent(...)` extensions:
```csharp
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
FoundryAgent agent = aiProjectClient.AsAIAgent(
model: deploymentName,
instructions: "You are good at telling jokes.",
name: "JokerAgent");
```
## Prerequisites
- .NET 10 SDK or later
- Foundry project endpoint
- Azure CLI installed and authenticated
Set:
```powershell
$env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
```
Some samples require extra tool-specific environment variables. See each sample for details.
## Samples
| Sample | Description |
| --- | --- |
| [FoundryAgent lifecycle](./Agent_Step00_FoundryAgentLifecycle/) | Create a FoundryAgent directly with endpoint and credentials |
| [Basics (Responses API)](./Agent_Step01_Basics/) | Create and run an agent using AsAIAgent extensions |
| [Multi-turn conversation](./Agent_Step02.1_MultiturnConversation/) | Multi-turn using sessions and response ID chaining |
| [Multi-turn with server conversations](./Agent_Step02.2_MultiturnWithServerConversations/) | Server-side conversations visible in Foundry UI |
| [Using function tools](./Agent_Step03_UsingFunctionTools/) | Function tools |
| [Function tools with approvals](./Agent_Step04_UsingFunctionToolsWithApprovals/) | Human-in-the-loop approval |
| [Structured output](./Agent_Step05_StructuredOutput/) | Structured output with JSON schema |
| [Persisted conversations](./Agent_Step06_PersistedConversations/) | Persisting and resuming conversations |
| [Observability](./Agent_Step07_Observability/) | OpenTelemetry observability |
| [Dependency injection](./Agent_Step08_DependencyInjection/) | DI with a hosted service |
| [Using MCP client as tools](./Agent_Step09_UsingMcpClientAsTools/) | MCP client tools |
| [Using images](./Agent_Step10_UsingImages/) | Image multi-modality |
| [Agent as function tool](./Agent_Step11_AsFunctionTool/) | Agent as a function tool for another |
| [Middleware](./Agent_Step12_Middleware/) | Multiple middleware layers |
| [Plugins](./Agent_Step13_Plugins/) | Plugins with dependency injection |
| [Code interpreter](./Agent_Step14_CodeInterpreter/) | Code interpreter tool |
| [Computer use](./Agent_Step15_ComputerUse/) | Computer use tool |
| [File search](./Agent_Step16_FileSearch/) | File search tool |
| [OpenAPI tools](./Agent_Step17_OpenAPITools/) | OpenAPI tools |
| [Bing custom search](./Agent_Step18_BingCustomSearch/) | Bing Custom Search tool |
| [SharePoint](./Agent_Step19_SharePoint/) | SharePoint grounding tool |
| [Microsoft Fabric](./Agent_Step20_MicrosoftFabric/) | Microsoft Fabric tool |
| [Web search](./Agent_Step21_WebSearch/) | Web search tool |
| [Memory search](./Agent_Step22_MemorySearch/) | Memory search tool |
| [Local MCP](./Agent_Step23_LocalMCP/) | Local MCP client with HTTP transport |
## Running the samples
```powershell
cd dotnet/samples/02-agents/AgentsWithFoundry
dotnet run --project .\FoundryAgent_Step01
```

Some files were not shown because too many files have changed in this diff Show More