Skip to content

Commit a8e7bbb

Browse files
committed
chore: Add managed-agent example to server-sdk-ai (#1358)
1 parent 6dbae78 commit a8e7bbb

7 files changed

Lines changed: 213 additions & 18 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"packages/sdk/server-ai/examples/chat-judge",
4949
"packages/sdk/server-ai/examples/direct-judge",
5050
"packages/sdk/server-ai/examples/openai",
51+
"packages/sdk/server-ai/examples/managed-agent",
5152
"packages/sdk/server-ai/examples/tracked-chat",
5253
"packages/sdk/server-ai/examples/chat-observability",
5354
"packages/sdk/server-ai/examples/openai-observability",
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Managed Agent Example
2+
3+
This example demonstrates how to use the LaunchDarkly AI SDK agent functionality with multiple providers for managed agent interactions.
4+
5+
## Prerequisites
6+
7+
1. A LaunchDarkly account and SDK key
8+
1. An OpenAI API key (for the AI provider)
9+
1. Node.js 16 or later
10+
11+
## Setup
12+
13+
1. Install dependencies:
14+
```bash
15+
yarn install
16+
```
17+
18+
1. Set up environment variables:
19+
```bash
20+
cp .env.example .env
21+
```
22+
23+
Edit `.env` and add your keys:
24+
```
25+
LAUNCHDARKLY_SDK_KEY=your-sdk-key-here
26+
OPENAI_API_KEY=your-openai-api-key-here
27+
LAUNCHDARKLY_AI_CONFIG_KEY=sample-ai-agent-config
28+
```
29+
30+
1. Create an AI Config in LaunchDarkly:
31+
- Navigate to the AI Configs section in your LaunchDarkly dashboard
32+
- Create a new AI Config with the key `sample-agent-config` and the **Agent** mode
33+
- Add a variation with the following settings:
34+
- **Model Selection**: Select "OpenAI" as the provider and "gpt-3.5-turbo" as the model
35+
- **Instructions**: "You are a helpful assistant for {{companyName}}. You should be friendly and informative."
36+
- Save the variation
37+
- Update the default target rule to use the newly created variation
38+
39+
## Running the Example
40+
41+
```bash
42+
yarn start
43+
```
44+
45+
This will:
46+
1. Initialize the LaunchDarkly client
47+
1. Create an agent using the AI Config
48+
1. Send a prompt to the agent and display the response
49+
1. Automatically track interaction metrics (duration, tokens, success/error)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "@launchdarkly/managed-agent-example",
3+
"private": true,
4+
"version": "1.0.0",
5+
"description": "Example demonstrating LaunchDarkly AI SDK agent functionality with multiple providers",
6+
"type": "module",
7+
"scripts": {
8+
"build": "tsc",
9+
"start": "yarn build && node ./dist/index.js"
10+
},
11+
"dependencies": {
12+
"@ai-sdk/google": "^2.0.20",
13+
"@langchain/core": "^1.1.42",
14+
"@langchain/google-genai": "^1.0.3",
15+
"@langchain/openai": "^0.5.0",
16+
"@launchdarkly/node-server-sdk": "9.10.13",
17+
"@launchdarkly/server-sdk-ai": "0.18.1",
18+
"@launchdarkly/server-sdk-ai-langchain": "0.6.1",
19+
"@launchdarkly/server-sdk-ai-openai": "0.5.8",
20+
"@launchdarkly/server-sdk-ai-vercel": "0.5.8",
21+
"dotenv": "^16.0.0",
22+
"langchain": "^1.3.5"
23+
},
24+
"devDependencies": {
25+
"@types/node": "^20.0.0",
26+
"tsx": "^4.0.0",
27+
"typescript": "^5.0.0"
28+
}
29+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* eslint-disable no-console */
2+
import 'dotenv/config';
3+
4+
import { init, type LDContext } from '@launchdarkly/node-server-sdk';
5+
import { initAi } from '@launchdarkly/server-sdk-ai';
6+
7+
// Environment variables
8+
const sdkKey = process.env.LAUNCHDARKLY_SDK_KEY;
9+
const aiConfigKey = process.env.LAUNCHDARKLY_AI_CONFIG_KEY || 'sample-agent-config';
10+
11+
// Validate required environment variables
12+
if (!sdkKey) {
13+
console.error('*** Please set the LAUNCHDARKLY_SDK_KEY env first');
14+
process.exit(1);
15+
}
16+
17+
// Initialize LaunchDarkly client
18+
const ldClient = init(sdkKey);
19+
20+
// Set up the context properties. This context should appear on your LaunchDarkly contexts dashboard
21+
// soon after you run the demo.
22+
const context: LDContext = {
23+
kind: 'user',
24+
key: 'example-user-key',
25+
name: 'Sandy',
26+
};
27+
28+
async function main() {
29+
try {
30+
await ldClient.waitForInitialization({ timeout: 10 });
31+
console.log('*** SDK successfully initialized');
32+
} catch (error) {
33+
console.log(`*** SDK failed to initialize: ${error}`);
34+
process.exit(1);
35+
}
36+
37+
const aiClient = initAi(ldClient);
38+
39+
// Get AI agent configuration from LaunchDarkly.
40+
//
41+
// Pass a defaultValue for improved resiliency when the flag is unavailable or LaunchDarkly is unreachable; omit for a disabled default.
42+
// Example:
43+
// const defaultValue = {
44+
// enabled: true,
45+
// model: { name: 'gpt-4' },
46+
// provider: { name: 'openai' },
47+
// instructions: 'You are a helpful research assistant for {{companyName}}.'
48+
// };
49+
// const agent = await aiClient.createAgent(aiConfigKey, context, defaultValue, { companyName: 'LaunchDarkly' });
50+
const agent = await aiClient.createAgent(aiConfigKey, context, undefined, {
51+
companyName: 'LaunchDarkly',
52+
});
53+
54+
if (!agent) {
55+
console.log('*** AI agent configuration is not enabled');
56+
process.exit(0);
57+
}
58+
59+
// Example of using the agent functionality
60+
console.log('\n*** Starting agent invocation:');
61+
try {
62+
const userInput = 'Hello! Can you help me understand how your company can help me?';
63+
console.log('User Input:', userInput);
64+
65+
const result = await agent.run(userInput);
66+
67+
console.log('AI Response:', result.content);
68+
69+
console.log('Success.');
70+
} catch (err) {
71+
console.error('Error:', err);
72+
}
73+
}
74+
75+
main();
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2022",
4+
"module": "ESNext",
5+
"moduleResolution": "node",
6+
"esModuleInterop": true,
7+
"allowSyntheticDefaultImports": true,
8+
"strict": true,
9+
"skipLibCheck": true,
10+
"forceConsistentCasingInFileNames": true,
11+
"outDir": "./dist",
12+
"rootDir": "./src",
13+
"declaration": true,
14+
"sourceMap": true
15+
},
16+
"include": ["src/**/*"],
17+
"exclude": ["node_modules", "dist"]
18+
}

packages/sdk/server-ai/examples/vercel-ai/src/index.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import { generateText, streamText } from 'ai';
44

55
import { init, type LDClient, type LDContext } from '@launchdarkly/node-server-sdk';
66
import { initAi } from '@launchdarkly/server-sdk-ai';
7-
import { VercelProvider } from '@launchdarkly/server-sdk-ai-vercel';
7+
import {
8+
convertMessagesToVercel,
9+
getAIMetricsFromResponse,
10+
getAIMetricsFromStream,
11+
VercelRunnerFactory,
12+
} from '@launchdarkly/server-sdk-ai-vercel';
813

914
// Environment variables
1015
const sdkKey = process.env.LAUNCHDARKLY_SDK_KEY ?? '';
@@ -59,24 +64,22 @@ async function main() {
5964

6065
console.log('Using model:', aiConfig.model?.name);
6166

67+
const model = openai(aiConfig.model?.name || 'gpt-4');
68+
const parameters = VercelRunnerFactory.mapParameters(aiConfig.model?.parameters);
69+
6270
try {
6371
const userMessage = {
6472
role: 'user' as const,
6573
content: 'What can you help me with?',
6674
};
6775

68-
// Example of using generateText (non-streaming)
6976
console.log('\n*** Generating text:');
7077

71-
// Convert config to Vercel AI SDK format
72-
const vercelConfig = VercelProvider.toVercelAISDK(aiConfig, openai, {
73-
nonInterpolatedMessages: [userMessage],
74-
});
78+
const messages = convertMessagesToVercel([...(aiConfig.messages || []), userMessage]);
7579

76-
// Call the model and track metrics for the ai config
7780
const tracker = aiConfig.createTracker!();
78-
const result = await tracker.trackMetricsOf(VercelProvider.getAIMetricsFromResponse, () =>
79-
generateText({ ...vercelConfig, messages: vercelConfig.messages ?? [] }),
81+
const result = await tracker.trackMetricsOf(getAIMetricsFromResponse, () =>
82+
generateText({ ...parameters, model, messages }),
8083
);
8184

8285
console.log('Response:', result.text);
@@ -91,21 +94,16 @@ async function main() {
9194
content: 'Count from 1 to 5.',
9295
};
9396

94-
// Example of using generateText (non-streaming)
9597
console.log('\n*** Streaming text:');
96-
// Convert config to Vercel AI SDK format
97-
const vercelConfig = VercelProvider.toVercelAISDK(aiConfig, openai, {
98-
nonInterpolatedMessages: [userMessage],
99-
});
10098

101-
// Stream is returned immediately (synchronously), metrics tracked in background
99+
const messages = convertMessagesToVercel([...(aiConfig.messages || []), userMessage]);
100+
102101
const streamTracker = aiConfig.createTracker!();
103102
const streamResult = streamTracker.trackStreamMetricsOf(
104-
() => streamText({ ...vercelConfig, messages: vercelConfig.messages ?? [] }),
105-
VercelProvider.getAIMetricsFromStream,
103+
() => streamText({ ...parameters, model, messages }),
104+
getAIMetricsFromStream,
106105
);
107106

108-
// Consume the stream immediately - no await needed before this!
109107
for await (const textPart of streamResult.textStream) {
110108
process.stdout.write(textPart);
111109
}

release-please-config.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
"path": "/packages/sdk/server-ai/examples/tracked-chat/package.json",
1010
"jsonpath": "$.dependencies['@launchdarkly/server-sdk-ai-langchain']"
1111
},
12+
{
13+
"type": "json",
14+
"path": "/packages/sdk/server-ai/examples/managed-agent/package.json",
15+
"jsonpath": "$.dependencies['@launchdarkly/server-sdk-ai-langchain']"
16+
},
1217
{
1318
"type": "json",
1419
"path": "/packages/sdk/server-ai/examples/chat-judge/package.json",
@@ -35,6 +40,11 @@
3540
"path": "/packages/sdk/server-ai/examples/tracked-chat/package.json",
3641
"jsonpath": "$.dependencies['@launchdarkly/server-sdk-ai-vercel']"
3742
},
43+
{
44+
"type": "json",
45+
"path": "/packages/sdk/server-ai/examples/managed-agent/package.json",
46+
"jsonpath": "$.dependencies['@launchdarkly/server-sdk-ai-vercel']"
47+
},
3848
{
3949
"type": "json",
4050
"path": "/packages/sdk/server-ai/examples/chat-judge/package.json",
@@ -61,6 +71,11 @@
6171
"path": "/packages/sdk/server-ai/examples/tracked-chat/package.json",
6272
"jsonpath": "$.dependencies['@launchdarkly/server-sdk-ai-openai']"
6373
},
74+
{
75+
"type": "json",
76+
"path": "/packages/sdk/server-ai/examples/managed-agent/package.json",
77+
"jsonpath": "$.dependencies['@launchdarkly/server-sdk-ai-openai']"
78+
},
6479
{
6580
"type": "json",
6681
"path": "/packages/sdk/server-ai/examples/chat-judge/package.json",
@@ -158,6 +173,11 @@
158173
"path": "/packages/sdk/server-ai/examples/tracked-chat/package.json",
159174
"jsonpath": "$.dependencies['@launchdarkly/node-server-sdk']"
160175
},
176+
{
177+
"type": "json",
178+
"path": "/packages/sdk/server-ai/examples/managed-agent/package.json",
179+
"jsonpath": "$.dependencies['@launchdarkly/node-server-sdk']"
180+
},
161181
{
162182
"type": "json",
163183
"path": "/packages/sdk/server-ai/examples/chat-judge/package.json",
@@ -252,6 +272,11 @@
252272
"path": "examples/tracked-chat/package.json",
253273
"jsonpath": "$.dependencies['@launchdarkly/server-sdk-ai']"
254274
},
275+
{
276+
"type": "json",
277+
"path": "examples/managed-agent/package.json",
278+
"jsonpath": "$.dependencies['@launchdarkly/server-sdk-ai']"
279+
},
255280
{
256281
"type": "json",
257282
"path": "examples/chat-judge/package.json",

0 commit comments

Comments
 (0)