diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx index 9cc20db18b..c3423c509a 100644 --- a/dotnet/agent-framework-dotnet.slnx +++ b/dotnet/agent-framework-dotnet.slnx @@ -31,6 +31,7 @@ + diff --git a/dotnet/eng/verify-samples/AgentsSamples.cs b/dotnet/eng/verify-samples/AgentsSamples.cs index 3e95524c07..512ce66027 100644 --- a/dotnet/eng/verify-samples/AgentsSamples.cs +++ b/dotnet/eng/verify-samples/AgentsSamples.cs @@ -836,6 +836,19 @@ internal static class AgentsSamples ], }, + new SampleDefinition + { + Name = "Agent_With_GitHubCopilot_BYOK", + ProjectPath = "samples/02-agents/AgentProviders/github-copilot/Agent_With_GitHubCopilot_BYOK", + RequiredEnvironmentVariables = ["BYOK_BASE_URL", "BYOK_API_KEY"], + OptionalEnvironmentVariables = ["BYOK_PROVIDER_TYPE", "BYOK_MODEL_ID"], + ExpectedOutputDescription = + [ + "The output should contain a user prompt and a response about the benefits of BYOK.", + "The output should not contain error messages or stack traces.", + ], + }, + new SampleDefinition { Name = "Agent_With_GoogleGemini", diff --git a/dotnet/samples/02-agents/AgentProviders/README.md b/dotnet/samples/02-agents/AgentProviders/README.md index 6592d7cdf0..407c4e8e4d 100644 --- a/dotnet/samples/02-agents/AgentProviders/README.md +++ b/dotnet/samples/02-agents/AgentProviders/README.md @@ -60,6 +60,7 @@ covering basics, function tools, structured output, middleware, MCP, code interp | Sample | Description | | --- | --- | | [GitHub Copilot](./github-copilot/Agent_With_GitHubCopilot/) | Create an AIAgent using GitHub Copilot SDK | +| [GitHub Copilot BYOK](./github-copilot/Agent_With_GitHubCopilot_BYOK/) | Route GitHub Copilot agent requests through your own endpoint (Bring Your Own Key) | ### [Google Gemini](./google-gemini/) diff --git a/dotnet/samples/02-agents/AgentProviders/github-copilot/Agent_With_GitHubCopilot_BYOK/Agent_With_GitHubCopilot_BYOK.csproj b/dotnet/samples/02-agents/AgentProviders/github-copilot/Agent_With_GitHubCopilot_BYOK/Agent_With_GitHubCopilot_BYOK.csproj new file mode 100644 index 0000000000..f9e3c1f2ee --- /dev/null +++ b/dotnet/samples/02-agents/AgentProviders/github-copilot/Agent_With_GitHubCopilot_BYOK/Agent_With_GitHubCopilot_BYOK.csproj @@ -0,0 +1,20 @@ + + + + Exe + net10.0 + + enable + enable + $(NoWarn);GHCP001 + + + + + + + + + + + diff --git a/dotnet/samples/02-agents/AgentProviders/github-copilot/Agent_With_GitHubCopilot_BYOK/Program.cs b/dotnet/samples/02-agents/AgentProviders/github-copilot/Agent_With_GitHubCopilot_BYOK/Program.cs new file mode 100644 index 0000000000..a7c42bd350 --- /dev/null +++ b/dotnet/samples/02-agents/AgentProviders/github-copilot/Agent_With_GitHubCopilot_BYOK/Program.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft. All rights reserved. + +// This sample shows how to configure a GitHub Copilot agent with BYOK (Bring Your Own Key), +// routing requests through your own endpoint (OpenAI, Azure OpenAI, Anthropic, or an +// OpenAI-compatible service such as vLLM/LiteLLM/Ollama) instead of the GitHub Copilot backend. +// +// SECURITY NOTE: BYOK uses static credentials (no automatic token refresh) and usage is tracked +// by your provider rather than GitHub. Keep API keys out of source control; load them from +// environment variables or a secret store, as shown here. + +using GitHub.Copilot; +using Microsoft.Agents.AI; + +string providerType = Environment.GetEnvironmentVariable("BYOK_PROVIDER_TYPE") ?? "openai"; +string baseUrl = Environment.GetEnvironmentVariable("BYOK_BASE_URL") + ?? throw new InvalidOperationException("The BYOK_BASE_URL environment variable is not set."); +string apiKey = Environment.GetEnvironmentVariable("BYOK_API_KEY") + ?? throw new InvalidOperationException("The BYOK_API_KEY environment variable is not set."); +string modelId = Environment.GetEnvironmentVariable("BYOK_MODEL_ID") ?? "gpt-4o"; + +// Create and start a Copilot client +await using CopilotClient copilotClient = new(); +await copilotClient.StartAsync(); + +// Provider routes the session through a custom endpoint instead of the GitHub Copilot backend. +// Type is "openai", "azure", or "anthropic". WireApi "completions" is the broadly compatible +// choice; use "responses" for providers that support the OpenAI Responses API. BYOK also +// requires Model to be set at the session level. +SessionConfig sessionConfig = new() +{ + Model = modelId, + Provider = new ProviderConfig + { + Type = providerType, + WireApi = "completions", + BaseUrl = baseUrl, + ApiKey = apiKey, + ModelId = modelId, + }, +}; + +AIAgent agent = copilotClient.AsAIAgent(sessionConfig, ownsClient: true); + +string prompt = "What are the benefits of using your own API keys with an agent framework?"; +Console.WriteLine($"User: {prompt}\n"); + +await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(prompt)) +{ + Console.Write(update); +} + +Console.WriteLine(); diff --git a/dotnet/samples/02-agents/AgentProviders/github-copilot/Agent_With_GitHubCopilot_BYOK/README.md b/dotnet/samples/02-agents/AgentProviders/github-copilot/Agent_With_GitHubCopilot_BYOK/README.md new file mode 100644 index 0000000000..cafadf45c3 --- /dev/null +++ b/dotnet/samples/02-agents/AgentProviders/github-copilot/Agent_With_GitHubCopilot_BYOK/README.md @@ -0,0 +1,76 @@ +# About BYOK (Bring Your Own Key) + +BYOK lets you route model requests through your own API keys and infrastructure instead of the +GitHub Copilot backend — useful for enterprise deployments, custom hosting, or direct billing +arrangements. See [GitHub's BYOK documentation](https://docs.github.com/en/copilot/how-tos/copilot-sdk/auth/byok) +for the full list of supported providers and configuration options. + +# Prerequisites + +Before you begin, ensure you have the following prerequisites: + +- .NET 10 SDK or later +- GitHub Copilot CLI installed and available in your PATH (or provide a custom path) +- An OpenAI, Azure OpenAI, Anthropic, or OpenAI-compatible endpoint and API key (e.g. vLLM, + LiteLLM, or Ollama) + +## Setting up GitHub Copilot CLI + +To use this sample, you need to have the GitHub Copilot CLI installed. You can install it by +following the instructions at: +https://github.com/github/copilot-sdk + +## Environment Variables + +| Variable | Description | Default | +|----------|-------------|---------| +| `BYOK_PROVIDER_TYPE` | Provider type (`openai`, `azure`, `anthropic`) | `openai` | +| `BYOK_BASE_URL` | Base URL of your provider endpoint | *(required)* | +| `BYOK_API_KEY` | API key for that endpoint | *(required)* | +| `BYOK_MODEL_ID` | Model name to request (e.g. "gpt-4o") | `gpt-4o` | + +## Running the Sample + +```powershell +dotnet run +``` + +The sample will: + +1. Create a GitHub Copilot client with default options +2. Configure a session with a `Provider` (BYOK) pointing at your own endpoint instead of the + default GitHub Copilot backend +3. Send a message to the agent +4. Stream the response + +## Advanced Usage + +```csharp +using GitHub.Copilot; +using Microsoft.Agents.AI; + +await using CopilotClient copilotClient = new(); +await copilotClient.StartAsync(); + +SessionConfig sessionConfig = new() +{ + // BYOK requires Model to also be set at the session level. + Model = "gpt-4o", + Provider = new ProviderConfig + { + Type = "azure", // or "openai", "anthropic" + WireApi = "completions", // or "responses" + BaseUrl = "https://api.example.com/v1", + ApiKey = "your-api-key", + ModelId = "your-model-id", // "deployment-name" + }, +}; + +AIAgent agent = copilotClient.AsAIAgent(sessionConfig, ownsClient: true); +AgentResponse response = await agent.RunAsync("Hello!"); +Console.WriteLine(response); +``` + +> **Note:** BYOK uses static credentials only — dynamic token refresh is not automatic, and +> model availability depends entirely on your provider's offerings. Usage is tracked through +> your provider rather than GitHub.