Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 43 additions & 0 deletions .github/workflows/server-sdk-ai.yml
Comment thread
jsonbailey marked this conversation as resolved.
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
3 changes: 3 additions & 0 deletions CODEOWNERS
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
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ or the [.NET SDK reference guide](https://docs.launchdarkly.com/sdk/server-side/

## SDKs

| SDK | Package | Examples |
|-----------------|--------------------------|--------------------------------|
| .NET Server SDK | `LaunchDarkly.ServerSdk` | [`server-sdk/`](./server-sdk/) |
| SDK | Package | Examples |
|--------------------|-----------------------------|------------------------------------------|
| .NET Server SDK | `LaunchDarkly.ServerSdk` | [`server-sdk/`](./server-sdk/) |
| .NET Server AI SDK | `LaunchDarkly.ServerSdk.Ai` | [`server-sdk-ai/`](./server-sdk-ai/) |

## Requirements

Expand Down
26 changes: 26 additions & 0 deletions server-sdk-ai/README.md
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` |
5 changes: 5 additions & 0 deletions server-sdk-ai/features/agent-config/.env.example
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
16 changes: 16 additions & 0 deletions server-sdk-ai/features/agent-config/AgentConfig.csproj
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>
4 changes: 4 additions & 0 deletions server-sdk-ai/features/agent-config/NOTICE
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/).
152 changes: 152 additions & 0 deletions server-sdk-ai/features/agent-config/Program.cs
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);
34 changes: 34 additions & 0 deletions server-sdk-ai/features/agent-config/README.md
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
```
5 changes: 5 additions & 0 deletions server-sdk-ai/features/completion-config/.env.example
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
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>
4 changes: 4 additions & 0 deletions server-sdk-ai/features/completion-config/NOTICE
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/).
Loading
Loading