Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c920fc1
Fix: Load dotenv in agent.ts before AgentApplication instantiates
rahuldevikar761 Jan 23, 2026
7efd5bc
Merge branch 'main' of https://github.com/microsoft/Agent365-Samples
rahuldevikar761 Jan 23, 2026
d69473b
Merge branch 'main' of https://github.com/microsoft/Agent365-Samples
rahuldevikar761 Jan 25, 2026
0787e88
Merge branch 'main' of https://github.com/microsoft/Agent365-Samples
rahuldevikar761 Jan 26, 2026
cfb8048
Add E2E Integration Tests
rahuldevikar761 Jan 26, 2026
b59f38c
Restore E2E test workflow for agent samples
rahuldevikar761 Jan 26, 2026
593ccca
Refactor Start-Agent.ps1 with updated comments
rahuldevikar761 Jan 27, 2026
e225bfc
Restore E2E tests for agent samples
rahuldevikar761 Jan 27, 2026
1cdb755
Improve error handling in Start-Agent.ps1
rahuldevikar761 Jan 27, 2026
770407f
Update Start-Agent.ps1 with new comments and structure
rahuldevikar761 Jan 27, 2026
7300864
Update print statement from 'Hello' to 'Goodbye'
rahuldevikar761 Jan 27, 2026
8b60d32
Enhance Start-Agent.ps1 with runtime checks and logging
rahuldevikar761 Jan 27, 2026
da97048
Update Start-Agent.ps1
rahuldevikar761 Jan 27, 2026
1c20001
Update log capture script for agent logs
rahuldevikar761 Jan 27, 2026
78e5ab1
Update e2e-agent-samples.yml
rahuldevikar761 Jan 27, 2026
a372f3f
Add GitHub Actions E2E workflow with self-contained tests
rahuldevikar761 Jan 27, 2026
d22c67e
Add /api/health endpoint to dotnet samples for CI/CD health checks
rahuldevikar761 Jan 27, 2026
d3f6934
Fix DateTime reference - use fully qualified System.DateTime
rahuldevikar761 Jan 27, 2026
f3d964e
Add null check for response before accessing StatusCode
rahuldevikar761 Jan 27, 2026
b77c497
Add E2E test status badges to README
rahuldevikar761 Jan 27, 2026
e87c96a
Address PR review comments
rahuldevikar761 Jan 27, 2026
0c09fbd
Add nightly schedule to run E2E tests at 10 PM UTC
rahuldevikar761 Jan 27, 2026
3bc1c87
Add nightly schedule to run E2E tests at 10 PM UTC
rahuldevikar761 Jan 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
666 changes: 666 additions & 0 deletions .github/workflows/e2e-agent-samples.yml

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
# Microsoft Agent 365 SDK Samples and Prompts

[![E2E Tests](https://github.com/microsoft/Agent365-Samples/actions/workflows/e2e-agent-samples.yml/badge.svg)](https://github.com/microsoft/Agent365-Samples/actions/workflows/e2e-agent-samples.yml)

This repository contains sample agents and prompts for building with the Microsoft Agent 365 SDK. The Microsoft Agent 365 SDK extends the Microsoft 365 Agents SDK with enterprise-grade capabilities for building sophisticated agents. It provides comprehensive tooling for observability, notifications, runtime utilities, and development tools that help developers create production-ready agents for platforms including M365, Teams, Copilot Studio, and Webchat.

- **Sample agents** are available in C# (.NET), Python, and Node.js/TypeScript
- **Prompts** to help you get started with AI-powered development tools like Cursor IDE

## E2E Test Status

| Sample | Status |
|--------|--------|
| Python OpenAI | [![Python OpenAI](https://github.com/microsoft/Agent365-Samples/actions/workflows/e2e-agent-samples.yml/badge.svg?job=python-openai)](https://github.com/microsoft/Agent365-Samples/actions/workflows/e2e-agent-samples.yml) |
| Node.js OpenAI | [![Node.js OpenAI](https://github.com/microsoft/Agent365-Samples/actions/workflows/e2e-agent-samples.yml/badge.svg?job=nodejs-openai)](https://github.com/microsoft/Agent365-Samples/actions/workflows/e2e-agent-samples.yml) |
| .NET Semantic Kernel | [![.NET SK](https://github.com/microsoft/Agent365-Samples/actions/workflows/e2e-agent-samples.yml/badge.svg?job=dotnet-semantic-kernel)](https://github.com/microsoft/Agent365-Samples/actions/workflows/e2e-agent-samples.yml) |
| .NET Agent Framework | [![.NET AF](https://github.com/microsoft/Agent365-Samples/actions/workflows/e2e-agent-samples.yml/badge.svg?job=dotnet-agent-framework)](https://github.com/microsoft/Agent365-Samples/actions/workflows/e2e-agent-samples.yml) |

> #### Note:
> Use the information in this README to contribute to this open-source project. To learn about using this SDK in your projects, refer to the [Microsoft Agent 365 Developer documentation](https://learn.microsoft.com/en-us/microsoft-agent-365/developer/).

Expand Down
2 changes: 2 additions & 0 deletions dotnet/agent-framework/sample-agent/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ await AgentMetrics.InvokeObservedHttpOperation("agent.process_message", async ()
}).ConfigureAwait(false);
});

// Health check endpoint for CI/CD pipelines and monitoring
app.MapGet("/api/health", () => Results.Ok(new { status = "healthy", timestamp = System.DateTime.UtcNow }));

if (app.Environment.IsDevelopment() || app.Environment.EnvironmentName == "Playground")
{
Expand Down
25 changes: 14 additions & 11 deletions dotnet/semantic-kernel/sample-agent/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@
builder.Services.AddAgenticTracingExporter();

// Add A365 tracing with Semantic Kernel integration
builder.AddA365Tracing(config =>
builder.AddA365Tracing(config =>
{
config.WithSemanticKernel();
config.WithSemanticKernel();
});


Expand Down Expand Up @@ -98,21 +98,24 @@

// This receives incoming messages from Azure Bot Service or other SDK Agents
var incomingRoute = app.MapPost("/api/messages", async (HttpRequest request, HttpResponse response, IAgentHttpAdapter adapter, IAgent agent, CancellationToken cancellationToken) =>
{
await AgentMetrics.InvokeObservedHttpOperation("agent.process_message", async () =>
{
await adapter.ProcessAsync(request, response, agent, cancellationToken);
}).ConfigureAwait(false);
{
await AgentMetrics.InvokeObservedHttpOperation("agent.process_message", async () =>
{
await adapter.ProcessAsync(request, response, agent, cancellationToken);
}).ConfigureAwait(false);
});

// Health check endpoint for CI/CD pipelines and monitoring
app.MapGet("/api/health", () => Results.Ok(new { status = "healthy", timestamp = System.DateTime.UtcNow }));

if (app.Environment.IsDevelopment() || app.Environment.EnvironmentName == "Playground")
{
app.MapGet("/", () => "Agent 365 Semantic Kernel Example Agent");
app.UseDeveloperExceptionPage();
app.MapControllers().AllowAnonymous();
// Hard coded for brevity and ease of testing.
// In production, this should be set in configuration.
app.MapControllers().AllowAnonymous();

// Hard coded for brevity and ease of testing.
// In production, this should be set in configuration.
app.Urls.Add($"http://localhost:3978");
}
else
Expand Down
92 changes: 92 additions & 0 deletions scripts/e2e/Acquire-BearerToken.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

<#
.SYNOPSIS
Acquires a bearer token using Resource Owner Password Credentials (ROPC) flow.

.DESCRIPTION
MCP servers only support delegated (user) permissions, not application permissions.
This script uses ROPC flow with a test service account to acquire user-delegated
tokens in the CI/CD pipeline.

.PARAMETER ClientId
The application (client) ID with MCP permissions.

.PARAMETER TenantId
The Azure AD tenant ID.

.PARAMETER Username
The test service account UPN (should be excluded from MFA).

.PARAMETER Password
The test service account password.

.PARAMETER Scope
The scope to request. Defaults to MCP scope.

.OUTPUTS
Returns the access token as a string.

.EXAMPLE
$token = ./Acquire-BearerToken.ps1 -ClientId $clientId -TenantId $tenantId -Username $user -Password $pass
#>

param(
[Parameter(Mandatory = $true)]
[string]$ClientId,

[Parameter(Mandatory = $true)]
[string]$TenantId,

[Parameter(Mandatory = $true)]
[string]$Username,

[Parameter(Mandatory = $true)]
[string]$Password,

[Parameter(Mandatory = $false)]
[string]$Scope = "ea9ffc3e-8a23-4a7d-836d-234d7c7565c1/.default"
)

$ErrorActionPreference = "Stop"

Write-Host "Acquiring bearer token for MCP servers using ROPC flow..." -ForegroundColor Cyan
Write-Host "MCP servers require delegated (user) tokens, not service principal tokens" -ForegroundColor Gray

$body = @{
grant_type = "password"
client_id = $ClientId
scope = $Scope
username = $Username
password = $Password
}

$tokenEndpoint = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token"

try {
$response = Invoke-RestMethod -Uri $tokenEndpoint -Method POST -Body $body -ContentType "application/x-www-form-urlencoded"
$token = $response.access_token

if ([string]::IsNullOrEmpty($token)) {
throw "Token response did not contain access_token"
}

$tokenLength = $token.Length
$expiresIn = $response.expires_in
Write-Host "Bearer token acquired successfully" -ForegroundColor Green
Write-Host " Token length: $tokenLength characters" -ForegroundColor Gray
Write-Host " Expires in: $expiresIn seconds" -ForegroundColor Gray

# Return the token
return $token
}
catch {
Write-Error "Failed to acquire bearer token via ROPC: $_"
Write-Host "Ensure the following variables are set:" -ForegroundColor Yellow
Write-Host " - ClientId: App registration with MCP permissions" -ForegroundColor Yellow
Write-Host " - TenantId: Azure AD tenant ID" -ForegroundColor Yellow
Write-Host " - Username: Service account UPN (excluded from MFA)" -ForegroundColor Yellow
Write-Host " - Password: Service account password" -ForegroundColor Yellow
throw
}
86 changes: 86 additions & 0 deletions scripts/e2e/Capture-AgentLogs.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

<#
.SYNOPSIS
Captures and displays agent logs for debugging.

.DESCRIPTION
Reads agent log files and displays them with sensitive values redacted.
Comment thread
rahuldevikar761 marked this conversation as resolved.

.PARAMETER AgentPath
The path to the agent directory.

.EXAMPLE
./Capture-AgentLogs.ps1 -AgentPath "./sample-agent"
#>

param(
[Parameter(Mandatory = $true)]
[string]$AgentPath
)

Write-Host "========================================" -ForegroundColor Cyan
Write-Host "AGENT LOGS (transcript)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan

$logFile = Join-Path $AgentPath "agent.log"
if (Test-Path $logFile) {
Write-Host "Agent transcript file found at: $logFile" -ForegroundColor Green
Write-Host "----------------------------------------"
Get-Content $logFile
Write-Host "----------------------------------------"
Comment thread
rahuldevikar761 marked this conversation as resolved.
Write-Host "End of agent transcript" -ForegroundColor Green
}
else {
Write-Host "No agent.log file found at: $logFile" -ForegroundColor Yellow
}

# Check command output log
$outputLogFile = Join-Path $AgentPath "agent-output.log"
if (Test-Path $outputLogFile) {
$outputContent = Get-Content $outputLogFile -Raw
if (-not [string]::IsNullOrWhiteSpace($outputContent)) {
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "AGENT COMMAND OUTPUT" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host $outputContent
}
}

# Show .env file contents (redacted)
$envFile = Join-Path $AgentPath ".env"
if (Test-Path $envFile) {
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ".ENV FILE (secrets redacted)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Get-Content $envFile | ForEach-Object {
if ($_ -match '^(BEARER_TOKEN|.*SECRET|.*PASSWORD|.*KEY)=') {
$name = $_ -replace '=.*', ''
$value = $_ -replace '^[^=]+=', ''
Write-Host "$name=***REDACTED*** (length: $($value.Length))"
}
else {
Write-Host $_
}
}
}

# Show wrapper script (redacted)
$wrapperScript = Join-Path $AgentPath "run-agent.ps1"
if (Test-Path $wrapperScript) {
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "WRAPPER SCRIPT (tokens redacted)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Get-Content $wrapperScript | ForEach-Object {
if ($_ -match "BEARER_TOKEN\s*=\s*'") {
Write-Host "`$env:BEARER_TOKEN = '***REDACTED***'"
}
else {
Write-Host $_
}
}
}
42 changes: 42 additions & 0 deletions scripts/e2e/Copy-ToolingManifest.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

<#
.SYNOPSIS
Copies the centralized ToolingManifest.json to a sample agent directory.

.DESCRIPTION
Creates a standardized ToolingManifest.json for E2E testing with MCP servers.

.PARAMETER TargetPath
The path to the sample agent directory.

.EXAMPLE
./Copy-ToolingManifest.ps1 -TargetPath "./python/openai/sample-agent"
#>

param(
[Parameter(Mandatory = $true)]
[string]$TargetPath
)

$ErrorActionPreference = "Stop"

Write-Host "Copying ToolingManifest.json to: $TargetPath" -ForegroundColor Cyan
Comment thread
rahuldevikar761 marked this conversation as resolved.

# Standard ToolingManifest.json for E2E testing
$manifest = @{
mcpServers = @(
@{
mcpServerName = "mcp_MailTools"
mcpServerUniqueName = "mcp_MailTools"
}
)
}

$manifestPath = Join-Path $TargetPath "ToolingManifest.json"
$manifest | ConvertTo-Json -Depth 5 | Out-File -FilePath $manifestPath -Encoding utf8

Write-Host "ToolingManifest.json created at: $manifestPath" -ForegroundColor Green
Write-Host "Contents:" -ForegroundColor Gray
Get-Content $manifestPath | Write-Host
Loading