-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add .NET Server AI SDK examples #2
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
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
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
There are no files selected for viewing
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 |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| name: server-sdk-ai | ||
| on: | ||
| schedule: | ||
| # * is a special character in YAML so you have to quote this string | ||
| - cron: '0 9 * * *' | ||
| push: | ||
| branches: [ main, 'feat/**' ] | ||
| paths: | ||
| - 'server-sdk-ai/**' | ||
| - '.github/workflows/server-sdk-ai.yml' | ||
| pull_request: | ||
| branches: [ main, 'feat/**' ] | ||
| paths: | ||
| - 'server-sdk-ai/**' | ||
| - '.github/workflows/server-sdk-ai.yml' | ||
|
|
||
| jobs: | ||
| build: | ||
| strategy: | ||
| matrix: | ||
| os: [ubuntu-latest, windows-latest] | ||
| fail-fast: false | ||
| runs-on: ${{ matrix.os }} | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | ||
|
|
||
| - name: Setup dotnet build tools | ||
| uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 | ||
| with: | ||
| dotnet-version: 8.0 | ||
|
|
||
| # Build-only: these examples call external model providers and need | ||
| # provider credentials to run, so CI just compiles them to catch build errors. | ||
| - name: Build server-sdk-ai examples | ||
| shell: bash | ||
| run: | | ||
| set -e | ||
| for proj in $(find server-sdk-ai -name '*.csproj' | sort); do | ||
| echo "::group::Building $proj" | ||
| dotnet build "$proj" | ||
| echo "::endgroup::" | ||
| done |
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,2 +1,5 @@ | ||
| # Repository Maintainers | ||
| * @launchdarkly/team-sdk-net | ||
|
|
||
| # AI examples | ||
| /server-sdk-ai/ @launchdarkly/team-ai-agents @launchdarkly/team-ai-evals |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # LaunchDarkly .NET Server AI SDK examples | ||
|
|
||
| Examples for the [`LaunchDarkly.ServerSdk.Ai`](https://www.nuget.org/packages/LaunchDarkly.ServerSdk.Ai) package. | ||
|
|
||
| For more comprehensive instructions, you can visit the [AI Configs Quickstart](https://docs.launchdarkly.com/home/ai-configs/quickstart) or the [.NET AI SDK reference guide](https://docs.launchdarkly.com/sdk/ai/dotnet). | ||
|
|
||
| Each example is a self-contained .NET console application you can run independently. | ||
|
|
||
| ## Getting Started | ||
|
|
||
| These examples show how to integrate LaunchDarkly AI with different providers. | ||
|
|
||
| | Provider | Example | Description | | ||
| |----------|----------------------------------------------------------|------------------------------------------------------------------| | ||
| | OpenAI | [Chat Completions](./frameworks/openai/chat-completions/) | `CompletionConfig` with OpenAI, automatic metrics tracking | | ||
| | Bedrock | [Converse](./frameworks/bedrock/converse/) | `CompletionConfig` with the AWS Bedrock Converse API, metrics tracking | | ||
|
|
||
| ## Features | ||
|
|
||
| These examples focus on the LaunchDarkly AI SDK itself. They are **provider-agnostic** — they retrieve and resolve AI Configs, then exercise the tracker API with synthetic operations rather than calling any model provider. | ||
|
|
||
| | Example | Description | | ||
| |------------------------------------------------------|-----------------------------------------------------------------------------------------| | ||
| | [Completion Config](./features/completion-config/) | Default values, Mustache variables, model parameter extraction, tool enumeration, and `TrackMetricsOf` | | ||
| | [Agent Config](./features/agent-config/) | Agent instructions and tools; `TrackMetricsOf` and `TrackToolCall` | | ||
| | [Judge Config](./features/judge-config/) | Judge config retrieval and `TrackJudgeResult` | |
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 |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # Your LaunchDarkly server-side SDK key | ||
| LAUNCHDARKLY_SDK_KEY= | ||
|
|
||
| # Override to use a different AI Config key | ||
| LAUNCHDARKLY_AGENT_KEY=sample-agent |
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 |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net8.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="LaunchDarkly.ServerSdk" Version="8.*" /> | ||
| <PackageReference Include="LaunchDarkly.ServerSdk.Ai" Version="0.*" /> | ||
| <PackageReference Include="DotNetEnv" Version="3.*" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
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 |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| LaunchDarkly .NET Server AI SDK Agent Config example | ||
| Copyright 2026 Catamorphic, Co. | ||
|
|
||
| This product includes software developed at LaunchDarkly (https://launchdarkly.com/). |
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 |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| using DotNetEnv; | ||
| using LaunchDarkly.Sdk; | ||
| using LaunchDarkly.Sdk.Server; | ||
| using LaunchDarkly.Sdk.Server.Ai; | ||
| using LaunchDarkly.Sdk.Server.Ai.Adapters; | ||
| using LaunchDarkly.Sdk.Server.Ai.Config; | ||
| using LaunchDarkly.Sdk.Server.Ai.Tracking; | ||
|
|
||
| Env.TraversePath().Load(); | ||
|
|
||
| var sdkKey = Environment.GetEnvironmentVariable("LAUNCHDARKLY_SDK_KEY"); | ||
| if (string.IsNullOrEmpty(sdkKey)) | ||
| { | ||
| Console.Error.WriteLine( | ||
| "LaunchDarkly SDK key is required: set the LAUNCHDARKLY_SDK_KEY environment variable and try again."); | ||
| return; | ||
| } | ||
|
|
||
| // Set agentKey to the AI config key you want to evaluate. | ||
| var agentKey = Environment.GetEnvironmentVariable("LAUNCHDARKLY_AGENT_KEY") | ||
| ?? "sample-agent"; | ||
|
|
||
| var ldClient = new LdClient(Configuration.Builder(sdkKey).Build()); | ||
| if (!ldClient.Initialized) | ||
| { | ||
| Console.Error.WriteLine( | ||
| "*** SDK failed to initialize. Please check your internet connection and SDK credential for any typo."); | ||
| ldClient.Dispose(); | ||
| return; | ||
| } | ||
| Console.WriteLine("*** SDK successfully initialized!"); | ||
|
|
||
| var aiClient = new LdAiClient(new LdClientAdapter(ldClient)); | ||
|
|
||
| // Set up the evaluation context. This context should appear on your | ||
| // LaunchDarkly contexts dashboard soon after you run the demo. | ||
| var context = Context.Builder(ContextKind.Of("user"), "example-user-key") | ||
| .Name("Sandy") | ||
| .Build(); | ||
|
|
||
| // Default agent config used when the AI Config is unreachable or missing. | ||
| var defaultValue = LdAiAgentConfigDefault.New() | ||
| .Enable() | ||
| .SetModelName("gpt-4") | ||
| .SetModelProviderName("openai") | ||
| .SetInstructions("You are a helpful research assistant for {{companyName}}.") | ||
| .Build(); | ||
|
|
||
| try | ||
| { | ||
| var agentConfig = aiClient.AgentConfig( | ||
| agentKey, | ||
| context, | ||
| defaultValue, | ||
| variables: new Dictionary<string, object> | ||
| { | ||
| ["companyName"] = "LaunchDarkly" | ||
| }); | ||
|
|
||
| if (!agentConfig.Enabled) | ||
| { | ||
| Console.WriteLine($"Agent config '{agentKey}' is disabled."); | ||
| return; | ||
| } | ||
|
|
||
| Console.WriteLine(); | ||
| Console.WriteLine($"Resolved agent model: {agentConfig.Model.Name} (provider: {agentConfig.Provider.Name})"); | ||
| Console.WriteLine(); | ||
| Console.WriteLine("Agent instructions (Mustache variables interpolated):"); | ||
| Console.WriteLine(agentConfig.Instructions); | ||
|
|
||
| if (agentConfig.Tools.Count > 0) | ||
| { | ||
| Console.WriteLine(); | ||
| Console.WriteLine("Configured tools (map to your provider's function-calling API):"); | ||
| foreach (var (name, tool) in agentConfig.Tools) | ||
| { | ||
| Console.WriteLine($" {name}: {tool.Description} (type: {tool.Type})"); | ||
| } | ||
| } | ||
|
|
||
| var tracker = agentConfig.CreateTracker(); | ||
|
|
||
| // To keep this example provider-agnostic, the operation below is a | ||
| // synthetic stand-in for an actual model call — see the getting-started/* | ||
| // examples for end-to-end integrations with OpenAI or AWS Bedrock. The | ||
| // tracker API is exercised exactly the same way regardless of provider. | ||
| Console.WriteLine(); | ||
| Console.WriteLine("Running a synthetic agent invocation wrapped in TrackMetricsOf..."); | ||
|
|
||
| var result = await tracker.TrackMetricsOf( | ||
| SyntheticMetrics, | ||
| async () => | ||
| { | ||
| await Task.Delay(150); | ||
| return new SyntheticResult( | ||
| Content: "[simulated agent response]", | ||
| InputTokens: 80, | ||
| OutputTokens: 120, | ||
| ToolsInvoked: new[] { "search", "calculator" }); | ||
| }); | ||
|
|
||
| // Record each tool invocation on the tracker so it appears in the | ||
| // metric summary. In a real integration these names would come from | ||
| // the provider's tool-use response. | ||
| foreach (var toolName in result.ToolsInvoked) | ||
| { | ||
| tracker.TrackToolCall(toolName); | ||
| } | ||
|
|
||
| Console.WriteLine(); | ||
| Console.WriteLine("Simulated agent response:"); | ||
| Console.WriteLine(result.Content); | ||
|
|
||
| PrintSummary(tracker.Summary); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Console.Error.WriteLine($"Error: {ex.Message}"); | ||
| } | ||
| finally | ||
| { | ||
| ldClient.FlushAndWait(TimeSpan.FromSeconds(5)); | ||
| ldClient.Dispose(); | ||
| } | ||
|
|
||
| static AiMetrics SyntheticMetrics(SyntheticResult result) => new( | ||
| success: true, | ||
| tokens: new Usage( | ||
| Total: result.InputTokens + result.OutputTokens, | ||
| Input: result.InputTokens, | ||
| Output: result.OutputTokens)); | ||
|
|
||
| static void PrintSummary(MetricSummary summary) | ||
| { | ||
| Console.WriteLine(); | ||
| Console.WriteLine("Done! The tracker captured the following metrics:"); | ||
| Console.WriteLine($" Duration: {summary.DurationMs}ms"); | ||
| Console.WriteLine($" Success: {summary.Success}"); | ||
| if (summary.Tokens is { } tokens) | ||
| { | ||
| Console.WriteLine($" Input tokens: {tokens.Input}"); | ||
| Console.WriteLine($" Output tokens: {tokens.Output}"); | ||
| Console.WriteLine($" Total tokens: {tokens.Total}"); | ||
| } | ||
| } | ||
|
|
||
| internal sealed record SyntheticResult( | ||
| string Content, | ||
| int InputTokens, | ||
| int OutputTokens, | ||
| IReadOnlyList<string> ToolsInvoked); |
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 |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Agent Config | ||
|
|
||
| This example focuses on the LaunchDarkly AI SDK itself — it is **provider-agnostic** and does not call OpenAI, Bedrock, Anthropic, or any other model. The actual agent invocation is replaced with a synthetic operation so you can see the SDK's tracking surface clearly. For end-to-end provider integrations see the [getting-started examples](../../frameworks). | ||
|
|
||
| It demonstrates: | ||
|
|
||
| - Retrieving agent instructions and tools from LaunchDarkly via `LdAiClient.AgentConfig` | ||
| - Using the builder pattern (`LdAiAgentConfigDefault.New()`) to declare a fallback default | ||
| - Interpolating Mustache placeholders in agent instructions | ||
| - Enumerating the tools attached to the agent (so they can be mapped to your provider's function-calling API) | ||
| - Tracking metrics via `tracker.TrackMetricsOf` and recording individual tool invocations via `tracker.TrackToolCall` | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - .NET 8.0 SDK | ||
| - A LaunchDarkly account and a server-side SDK key | ||
|
|
||
| ## Setup | ||
|
|
||
| 1. [Create an AI Config](https://launchdarkly.com/docs/home/ai-configs/create) of type **Agent** in LaunchDarkly with the key `sample-agent`. Set the instructions (you may include Mustache placeholders such as `{{companyName}}`), choose a provider and model. | ||
| 2. Copy `.env.example` to `.env` and fill in your SDK key: | ||
| ```sh | ||
| cp .env.example .env | ||
| ``` | ||
| 3. Restore dependencies: | ||
| ```sh | ||
| dotnet restore | ||
| ``` | ||
|
|
||
| ## Run | ||
|
|
||
| ```sh | ||
| dotnet run | ||
| ``` |
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 |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # Your LaunchDarkly server-side SDK key | ||
| LAUNCHDARKLY_SDK_KEY= | ||
|
|
||
| # Override to use a different AI Config key | ||
| LAUNCHDARKLY_COMPLETION_KEY=sample-completion |
16 changes: 16 additions & 0 deletions
16
server-sdk-ai/features/completion-config/CompletionConfig.csproj
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 |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net8.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="LaunchDarkly.ServerSdk" Version="8.*" /> | ||
| <PackageReference Include="LaunchDarkly.ServerSdk.Ai" Version="0.*" /> | ||
| <PackageReference Include="DotNetEnv" Version="3.*" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
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 |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| LaunchDarkly .NET Server AI SDK Completion Config example | ||
| Copyright 2026 Catamorphic, Co. | ||
|
|
||
| This product includes software developed at LaunchDarkly (https://launchdarkly.com/). |
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.