Repository navigation
Updating Csharp and python MAF samples to GA. #1070
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Mohit Pavan Kumar Gadamsetty (mohitpavan)
merged 12 commits into
main
from
users/mohit/bat-ga-mcp-csharp-maf
Oct 15, 2026
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
79f5faa
feat: migrate C# MAF browser automation to GA MCP
mohitpavan a244e1f
fix: surface browser live view from MCP results
mohitpavan cb578fb
Copilot review.
mohitpavan 14b9f35
Merge branch 'main' of https://github.com/microsoft-foundry/foundry-s…
mohitpavan 19b60a1
Move Python MAF browser automation into the MAF branch
mohitpavan 70bfe17
Merge branch 'main' of https://github.com/microsoft-foundry/foundry-s…
mohitpavan 8bbc843
MAF fix.
mohitpavan 7ff76f3
eval change.
mohitpavan c32220d
updating to template from manifest.
mohitpavan f9f5f51
copilot comment.
mohitpavan c3d1436
copilot comment.
mohitpavan b540417
Changes to stay awake for the sessions for continuity. the idle timeo…
mohitpavan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
314 changes: 65 additions & 249 deletions
314
samples/csharp/hosted-agents/agent-framework/browser-automation/README.md
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 0 additions & 6 deletions
6
...s/csharp/hosted-agents/agent-framework/browser-automation/src/bat-csharp-maf/.env.example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,3 @@ | ||
| # Required | ||
| FOUNDRY_PROJECT_ENDPOINT=https://<account>.services.ai.azure.com/api/projects/<project> | ||
| AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4.1 | ||
|
|
||
| # Optional — override the default toolbox name | ||
| TOOLBOX_NAME=browser-automation-tools | ||
|
|
||
| # Timeouts | ||
| BROWSER_AGENT_PLAYWRIGHT_CLI_TIMEOUT_SECONDS=180 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 37 additions & 68 deletions
105
...les/csharp/hosted-agents/agent-framework/browser-automation/src/bat-csharp-maf/Program.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,117 +1,86 @@ | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| /* | ||
| * Browser Automation — Agent Framework (MAF) hosted agent for C# | ||
| * | ||
| * Browser automation agent that uses Foundry Toolbox to provision a remote | ||
| * Chromium browser and playwright-cli to drive it. Demonstrates: | ||
| * - MAF AIAgent with AddFoundryToolboxes for automatic MCP tool discovery | ||
| * - Function invocation middleware to intercept create_session results | ||
| * - AgentSkillsProvider for progressive skill disclosure | ||
| * - LiveViewUrlMiddleware: injects live_view_url post-call | ||
| * | ||
| * Required environment variables: | ||
| * FOUNDRY_PROJECT_ENDPOINT — Foundry project endpoint (auto-injected) | ||
| * AZURE_AI_MODEL_DEPLOYMENT_NAME — Model deployment name | ||
| * | ||
| * Optional: | ||
| * BROWSER_AGENT_PLAYWRIGHT_CLI_TIMEOUT_SECONDS — CLI timeout (default: 180) | ||
| */ | ||
|
|
||
| using Azure.AI.Projects; | ||
| using Azure.Core; | ||
| using Azure.Identity; | ||
| using BrowserAutomation; | ||
| using DotNetEnv; | ||
| using Microsoft.Agents.AI; | ||
| using Microsoft.Agents.AI.Foundry.Hosting; | ||
| using Microsoft.Extensions.AI; | ||
| using BrowserAutomation; | ||
|
|
||
| Env.NoClobber().TraversePath().Load(); | ||
|
|
||
| // ── Configuration ──────────────────────────────────────────────────────────── | ||
| var projectEndpoint = new Uri(Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") | ||
| var projectEndpoint = new Uri( | ||
| Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") | ||
| ?? Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") | ||
| ?? Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") | ||
| ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT environment variable is not set.")); | ||
| var deployment = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") | ||
| ?? throw new InvalidOperationException( | ||
| "FOUNDRY_PROJECT_ENDPOINT environment variable is not set.")); | ||
| var deployment = | ||
| Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") | ||
| ?? Environment.GetEnvironmentVariable("BROWSER_AGENT_MODEL") | ||
| ?? throw new InvalidOperationException("AZURE_AI_MODEL_DEPLOYMENT_NAME environment variable is not set."); | ||
| ?? throw new InvalidOperationException( | ||
| "AZURE_AI_MODEL_DEPLOYMENT_NAME environment variable is not set."); | ||
| var toolboxName = Environment.GetEnvironmentVariable("TOOLBOX_NAME") | ||
| ?? "browser-automation-tools"; | ||
|
|
||
| var toolboxName = "browser-automation-tools"; | ||
| var playwrightCliTimeout = int.TryParse(Environment.GetEnvironmentVariable("BROWSER_AGENT_PLAYWRIGHT_CLI_TIMEOUT_SECONDS"), out var t) ? t : 180; | ||
|
|
||
| // Ensure FOUNDRY_AGENT_TOOLSET_ENDPOINT is set — platform doesn't always inject it | ||
| if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("FOUNDRY_AGENT_TOOLSET_ENDPOINT"))) | ||
| if (string.IsNullOrEmpty( | ||
| Environment.GetEnvironmentVariable("FOUNDRY_AGENT_TOOLSET_ENDPOINT"))) | ||
| { | ||
| var toolsetEndpoint = $"{projectEndpoint.ToString().TrimEnd('/')}/toolboxes"; | ||
| Environment.SetEnvironmentVariable("FOUNDRY_AGENT_TOOLSET_ENDPOINT", toolsetEndpoint); | ||
| Environment.SetEnvironmentVariable( | ||
| "FOUNDRY_AGENT_TOOLSET_ENDPOINT", | ||
| $"{projectEndpoint.ToString().TrimEnd('/')}/toolboxes"); | ||
| } | ||
|
|
||
| // ── Skills directory ───────────────────────────────────────────────────────── | ||
| var skillsDir = Path.Combine(AppContext.BaseDirectory, "skills"); | ||
| if (!Directory.Exists(skillsDir)) | ||
| skillsDir = Path.Combine(Directory.GetCurrentDirectory(), "skills"); | ||
|
|
||
| // ── System prompt (loaded from prompts/base.md) ────────────────────────────── | ||
| var promptsDir = Path.Combine(AppContext.BaseDirectory, "prompts"); | ||
| if (!Directory.Exists(promptsDir)) | ||
| promptsDir = Path.Combine(Directory.GetCurrentDirectory(), "prompts"); | ||
| var systemPrompt = File.ReadAllText(Path.Combine(promptsDir, "base.md")); | ||
|
|
||
| // ── Local tools (playwright-cli + get_live_view_url) ───────────────────────── | ||
| List<AITool> localTools = | ||
| [ | ||
| Tools.MakeRunPlaywrightCli(playwrightCliTimeout), | ||
| Tools.MakeCloseBrowserSession(playwrightCliTimeout), | ||
| Tools.MakeGetLiveViewUrl(), | ||
| ]; | ||
|
|
||
| // ── Skills provider (progressive disclosure, no approval gate) ─────────────── | ||
| var skillsProvider = new AgentSkillsProvider(skillsDir, options: new AgentSkillsProviderOptions | ||
| { | ||
| DisableLoadSkillApproval = true, | ||
| DisableRunSkillScriptApproval = true, | ||
| }); | ||
| var skillsProvider = new AgentSkillsProvider( | ||
| skillsDir, | ||
| options: new AgentSkillsProviderOptions | ||
| { | ||
| DisableLoadSkillApproval = true, | ||
| DisableRunSkillScriptApproval = true, | ||
| }); | ||
|
|
||
| // ── Create agent ───────────────────────────────────────────────────────────── | ||
| // Toolbox MCP tools (create_session etc.) are injected automatically by | ||
| // AddFoundryToolboxes via the hosting layer — no manual McpClient needed. | ||
| AIAgent baseAgent = new AIProjectClient(projectEndpoint, new DefaultAzureCredential()) | ||
| AIAgent baseAgent = new AIProjectClient( | ||
| projectEndpoint, | ||
| new DefaultAzureCredential()) | ||
| .AsAIAgent(new ChatClientAgentOptions | ||
| { | ||
| Name = "browser-automation", | ||
| Description = "A browser automation agent using Playwright via Foundry Toolbox", | ||
| Description = "A browser automation agent using Azure Playwright tools", | ||
| ChatOptions = new ChatOptions | ||
| { | ||
| ModelId = deployment, | ||
| Instructions = systemPrompt, | ||
| Tools = localTools, | ||
| }, | ||
| AIContextProviders = [skillsProvider], | ||
| }); | ||
|
|
||
| // ── Middleware pipeline ────────────────────────────────────────────────────── | ||
| // 1. Function invocation middleware: intercepts create_session results to store | ||
| // cdp_url + live_view_url server-side (model never sees them). | ||
| // 2. Agent-level middleware: injects live_view_url into response post-call. | ||
| var agent = baseAgent | ||
| .AsBuilder() | ||
| .Use(Middlewares.FunctionInvocationMiddleware) | ||
| .Use(Middlewares.LiveViewUrlMiddleware, Middlewares.LiveViewUrlStreamingMiddleware) | ||
| .Use( | ||
| Middlewares.LiveViewUrlMiddleware, | ||
| Middlewares.LiveViewUrlStreamingMiddleware) | ||
| .Build(); | ||
|
|
||
| // ── Host setup ─────────────────────────────────────────────────────────────── | ||
| var builder = AgentHost.CreateBuilder(args); | ||
| builder.Services.AddFoundryResponses(agent); | ||
|
|
||
| // Pass a credential that forces https://ai.azure.com/.default scope for toolbox auth. | ||
| // The framework's FoundryToolboxBearerTokenHandler uses cognitiveservices.azure.com which | ||
| // some regions reject. This wrapper overrides the scope while using DefaultAzureCredential. | ||
| var toolboxCredential = new ToolboxScopedCredential(new DefaultAzureCredential()); | ||
|
|
||
| builder.Services.AddFoundryToolboxes(toolboxCredential, opt => opt.ApiVersion = "v1", toolboxName); | ||
| builder.RegisterProtocol("responses", endpoints => endpoints.MapFoundryResponses()); | ||
| builder.Services.AddFoundryToolboxes( | ||
| new ToolboxScopedCredential(new DefaultAzureCredential()), | ||
| options => options.ApiVersion = "v1", | ||
| toolboxName); | ||
| builder.RegisterProtocol( | ||
| "responses", | ||
| endpoints => endpoints.MapFoundryResponses()); | ||
|
|
||
| var app = builder.Build(); | ||
| app.Run(); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.