Skip to content

Commit f0b9b5d

Browse files
authored
feat: Add Vercel example for AI SDK (#927)
1 parent 6505516 commit f0b9b5d

File tree

9 files changed

+225
-3
lines changed

9 files changed

+225
-3
lines changed

.github/workflows/server-ai.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ on:
1111
- '**.md'
1212

1313
jobs:
14-
build-test-node-server-otel:
14+
build-test-server-sdk-ai:
1515
runs-on: ubuntu-latest
1616
steps:
1717
- uses: actions/checkout@v4
@@ -35,3 +35,8 @@ jobs:
3535
yarn workspaces focus @launchdarkly/hello-openai
3636
yarn workspace @launchdarkly/hello-openai lint
3737
yarn workspaces foreach -pR --topological-dev --from '@launchdarkly/hello-openai' run build
38+
- name: Build Vercel AI example
39+
run: |
40+
yarn workspaces focus @launchdarkly/hello-vercel-ai
41+
yarn workspace @launchdarkly/hello-vercel-ai lint
42+
yarn workspaces foreach -pR --topological-dev --from '@launchdarkly/hello-vercel-ai' run build

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"packages/sdk/server-ai",
3434
"packages/sdk/server-ai/examples/bedrock",
3535
"packages/sdk/server-ai/examples/openai",
36+
"packages/sdk/server-ai/examples/vercel-ai",
3637
"packages/telemetry/browser-telemetry",
3738
"contract-tests",
3839
"packages/sdk/combined-browser"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"extends": "./tsconfig.json",
3-
"include": ["/**/*.ts", "/**/*.tsx"],
3+
"include": ["**/*.ts", "**/*.tsx"],
44
"exclude": ["node_modules"]
55
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"extends": "./tsconfig.json",
3-
"include": ["/**/*.ts", "/**/*.tsx"],
3+
"include": ["**/*.ts", "**/*.tsx"],
44
"exclude": ["node_modules"]
55
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# LaunchDarkly AI SDK for OpenAI Example
2+
3+
This package demonstrates the integration of LaunchDarkly's AI SDK with OpenAI via Vercel AI, allowing you to leverage LaunchDarkly's AI Config capabilities in AI-powered applications using Vercel's services.
4+
5+
## Installation and Build
6+
7+
When running as part of the js-core mono-repo the project will use local dependencies.
8+
As such those dependencies need built.
9+
10+
In the root of the repository run:
11+
12+
```bash
13+
yarn
14+
```
15+
16+
And then
17+
18+
```bash
19+
yarn build
20+
```
21+
22+
## Configuration
23+
24+
Before running the example, make sure to set the following environment variables:
25+
26+
- `LAUNCHDARKLY_SDK_KEY`: Your LaunchDarkly SDK key
27+
- `LAUNCHDARKLY_AI_CONFIG_KEY`: Your LaunchDarkly AI Config key (defaults to 'sample-ai-config' if not set)
28+
- `OPENAI_API_KEY`: Your OpenAI API key
29+
30+
## Usage
31+
32+
The main script (`index.js`) demonstrates how to:
33+
34+
1. Initialize the LaunchDarkly SDK
35+
2. Set up a user context
36+
3. Initialize the LaunchDarkly AI client
37+
4. Retrieve an AI model configuration
38+
5. Send a prompt to a Vercel AI Model (OpenAI)
39+
6. Track token usage
40+
41+
To run the example (in the vercel-ai directory):
42+
43+
```bash
44+
yarn start
45+
```
46+
47+
## Note
48+
49+
This example uses OpenAI's chat completions API. Make sure your LaunchDarkly AI Config is set up correctly to work with OpenAI's models and API structure.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"name": "@launchdarkly/hello-vercel-ai",
3+
"version": "0.1.0",
4+
"description": "LaunchDarkly AI SDK for Node.js with Vercel AI",
5+
"private": true,
6+
"main": "dist/index.js",
7+
"types": "dist/index.d.ts",
8+
"scripts": {
9+
"build": "tsc",
10+
"start": "yarn build && node ./dist/index.js",
11+
"lint": "npx eslint . --ext .ts",
12+
"prettier": "prettier --write '**/*.@(js|ts|tsx|json|css)' --ignore-path ../../../.prettierignore",
13+
"lint:fix": "yarn run lint --fix",
14+
"check": "yarn prettier && yarn lint && yarn build && yarn test"
15+
},
16+
"keywords": [
17+
"launchdarkly",
18+
"ai",
19+
"llm"
20+
],
21+
"author": "LaunchDarkly",
22+
"license": "Apache-2.0",
23+
"dependencies": {
24+
"@ai-sdk/openai": "2.0.30",
25+
"@launchdarkly/node-server-sdk": "9.7.1",
26+
"@launchdarkly/server-sdk-ai": "0.11.3",
27+
"ai": "5.0.0",
28+
"zod": "^3.23.8"
29+
},
30+
"devDependencies": {
31+
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
32+
"@tsconfig/node20": "20.1.4",
33+
"@typescript-eslint/eslint-plugin": "^6.20.0",
34+
"@typescript-eslint/parser": "^6.20.0",
35+
"eslint": "^8.45.0",
36+
"eslint-config-airbnb-base": "^15.0.0",
37+
"eslint-config-airbnb-typescript": "^17.1.0",
38+
"eslint-config-prettier": "^8.8.0",
39+
"eslint-plugin-import": "^2.27.5",
40+
"eslint-plugin-jest": "^27.6.3",
41+
"eslint-plugin-prettier": "^5.0.0",
42+
"jest": "^29.7.0",
43+
"prettier": "^3.0.0",
44+
"rimraf": "^5.0.5",
45+
"typedoc": "0.25.0",
46+
"typescript": "^5.5.3"
47+
},
48+
"directories": {
49+
"example": "example"
50+
},
51+
"repository": {
52+
"type": "git",
53+
"url": "github.com/launchdarkly/js-core"
54+
}
55+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/* eslint-disable no-console */
2+
import { openai } from '@ai-sdk/openai';
3+
import { generateText, streamText } from 'ai';
4+
5+
import { init, type LDClient, type LDContext } from '@launchdarkly/node-server-sdk';
6+
import { initAi } from '@launchdarkly/server-sdk-ai';
7+
8+
// Environment variables
9+
const sdkKey = process.env.LAUNCHDARKLY_SDK_KEY ?? '';
10+
const aiConfigKey = process.env.LAUNCHDARKLY_AI_CONFIG_KEY || 'sample-ai-config';
11+
12+
// Validate required environment variables
13+
if (!sdkKey) {
14+
console.error('*** Please set the LAUNCHDARKLY_SDK_KEY env first');
15+
process.exit(1);
16+
}
17+
18+
let client: LDClient | undefined;
19+
20+
async function main() {
21+
// Initialize LaunchDarkly client
22+
client = init(sdkKey);
23+
24+
// Set up the context properties. This context should appear on your LaunchDarkly contexts dashboard
25+
const context: LDContext = {
26+
kind: 'user',
27+
key: 'example-user-key',
28+
name: 'Sandy',
29+
};
30+
31+
try {
32+
await client.waitForInitialization({ timeout: 10 });
33+
console.log('*** SDK successfully initialized');
34+
} catch (error) {
35+
console.log(`*** SDK failed to initialize: ${error}`);
36+
process.exit(1);
37+
}
38+
39+
const aiClient = initAi(client);
40+
41+
// Get AI configuration from LaunchDarkly
42+
const aiConfig = await aiClient.config(aiConfigKey, context, { model: { name: 'gpt-4' } });
43+
44+
if (!aiConfig.enabled) {
45+
console.log('*** AI configuration is not enabled');
46+
process.exit(0);
47+
}
48+
49+
console.log('Using model:', aiConfig.model?.name);
50+
51+
// Example of using generateText (non-streaming)
52+
console.log('\n*** Generating text:');
53+
try {
54+
const userMessage = {
55+
role: 'user' as const,
56+
content: 'What can you help me with?',
57+
};
58+
59+
const result = await aiConfig.tracker.trackVercelAISDKGenerateTextMetrics(() =>
60+
generateText(aiConfig.toVercelAISDK(openai, { nonInterpolatedMessages: [userMessage] })),
61+
);
62+
console.log('Response:', result.text);
63+
64+
process.stdout.write('Streaming Response: ');
65+
const streamResult = aiConfig.tracker.trackVercelAISDKStreamTextMetrics(() =>
66+
streamText(aiConfig.toVercelAISDK(openai, { nonInterpolatedMessages: [userMessage] })),
67+
);
68+
69+
// eslint-disable-next-line no-restricted-syntax
70+
for await (const textPart of streamResult.textStream) {
71+
process.stdout.write(textPart);
72+
}
73+
74+
console.log('\nSuccess.');
75+
} catch (err) {
76+
console.error('Error:', err);
77+
}
78+
}
79+
80+
main()
81+
.catch((e) => console.error(e))
82+
.finally(async () => {
83+
await client?.flush();
84+
client?.close();
85+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"include": ["**/*.ts", "**/*.tsx"],
4+
"exclude": ["node_modules"]
5+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"extends": "@tsconfig/node20/tsconfig.json",
3+
"compilerOptions": {
4+
"noEmit": false,
5+
"outDir": "dist",
6+
"baseUrl": ".",
7+
"allowUnusedLabels": false,
8+
"allowUnreachableCode": false,
9+
"noFallthroughCasesInSwitch": true,
10+
"noUncheckedIndexedAccess": true,
11+
"noUnusedLocals": true,
12+
"noUnusedParameters": true,
13+
"forceConsistentCasingInFileNames": true,
14+
"declaration": true,
15+
"sourceMap": true,
16+
"resolveJsonModule": true,
17+
"module": "CommonJS",
18+
"moduleResolution": "Node"
19+
},
20+
"include": ["src"],
21+
"exclude": ["dist", "node_modules"]
22+
}

0 commit comments

Comments
 (0)