Skip to content

Commit 18e8c4c

Browse files
InTheCloudDankinyokliongithub-actions[bot]dependabot[bot]tanderson-ld
authored
feat: Add AI SDK for Server-Side JavaScript. (#619)
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Ryan Lamb <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Todd Anderson <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Menelik Zafir <[email protected]> Co-authored-by: “Menelik <“[email protected]”>
1 parent 14bb099 commit 18e8c4c

39 files changed

+1132
-2
lines changed

.github/workflows/manual-publish-docs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ on:
2020
- packages/store/node-server-sdk-dynamodb
2121
- packages/telemetry/node-server-sdk-otel
2222
- packages/sdk/browser
23+
- packages/sdk/server-ai
2324
name: Publish Documentation
2425
jobs:
2526
build-publish:

.github/workflows/manual-publish.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ on:
3333
- packages/telemetry/node-server-sdk-otel
3434
- packages/tooling/jest
3535
- packages/sdk/browser
36+
- packages/sdk/server-ai
3637
prerelease:
3738
description: 'Is this a prerelease. If so, then the latest tag will not be updated in npm.'
3839
type: boolean

.github/workflows/release-please.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ jobs:
2525
package-tooling-jest-release: ${{ steps.release.outputs['packages/tooling/jest--release_created'] }}
2626
package-react-universal-release: ${{ steps.release.outputs['packages/sdk/react-universal--release_created'] }}
2727
package-browser-released: ${{ steps.release.outputs['packages/sdk/browser--release_created'] }}
28+
package-server-ai-released: ${{ steps.release.outputs['packages/sdk/server-ai--release_created'] }}
2829
steps:
2930
- uses: googleapis/release-please-action@v4
3031
id: release
@@ -377,3 +378,23 @@ jobs:
377378
with:
378379
workspace_path: packages/sdk/react-universal
379380
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}
381+
382+
release-server-ai:
383+
runs-on: ubuntu-latest
384+
needs: ['release-please', 'release-sdk-server']
385+
permissions:
386+
id-token: write
387+
contents: write
388+
if: ${{ always() && !failure() && !cancelled() && needs.release-please.outputs.package-server-ai-released == 'true'}}
389+
steps:
390+
- uses: actions/checkout@v4
391+
- uses: actions/setup-node@v4
392+
with:
393+
node-version: 20.x
394+
registry-url: 'https://registry.npmjs.org'
395+
- id: release-react-native
396+
name: Full release of packages/sdk/server-ai
397+
uses: ./actions/full-release
398+
with:
399+
workspace_path: packages/sdk/server-ai
400+
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}

.github/workflows/server-ai.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: sdk/server-ai
2+
3+
on:
4+
push:
5+
branches: [main, 'feat/**']
6+
paths-ignore:
7+
- '**.md' #Do not need to run CI for markdown changes.
8+
pull_request:
9+
branches: [main, 'feat/**']
10+
paths-ignore:
11+
- '**.md'
12+
13+
jobs:
14+
build-test-node-server-otel:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: actions/setup-node@v4
19+
with:
20+
node-version: 20.x
21+
registry-url: 'https://registry.npmjs.org'
22+
- id: shared
23+
name: Shared CI Steps
24+
uses: ./actions/ci
25+
with:
26+
workspace_name: '@launchdarkly/server-sdk-ai'
27+
workspace_path: packages/sdk/server-ai
28+
- name: Build bedrock example
29+
run: |
30+
yarn workspaces focus @launchdarkly/hello-ai-bedrock
31+
yarn workspace @launchdarkly/hello-ai-bedrock lint
32+
yarn workspaces foreach -pR --topological-dev --from '@launchdarkly/hello-ai-bedrock' run build
33+
- name: Build OpenAI example
34+
run: |
35+
yarn workspaces focus @launchdarkly/hello-openai
36+
yarn workspace @launchdarkly/hello-openai lint
37+
yarn workspaces foreach -pR --topological-dev --from '@launchdarkly/hello-openai' run build

.release-please-manifest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@
1313
"packages/shared/sdk-client": "1.12.0",
1414
"packages/sdk/react-native": "10.9.2",
1515
"packages/telemetry/node-server-sdk-otel": "1.1.1",
16-
"packages/sdk/browser": "0.3.0"
16+
"packages/sdk/browser": "0.3.0",
17+
"packages/sdk/server-ai": "0.0.0"
1718
}

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
"packages/tooling/jest/example/react-native-example",
2626
"packages/sdk/browser",
2727
"packages/sdk/browser/contract-tests/entity",
28-
"packages/sdk/browser/contract-tests/adapter"
28+
"packages/sdk/browser/contract-tests/adapter",
29+
"packages/sdk/server-ai",
30+
"packages/sdk/server-ai/examples/bedrock",
31+
"packages/sdk/server-ai/examples/openai"
2932
],
3033
"private": true,
3134
"scripts": {

packages/sdk/server-ai/README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# LaunchDarkly AI SDK for Server-Side JavaScript
2+
3+
# ⛔️⛔️⛔️⛔️
4+
5+
> [!CAUTION]
6+
> This library is a alpha version and should not be considered ready for production use while this message is visible.
7+
8+
# ☝️☝️☝️☝️☝️☝️
9+
10+
## LaunchDarkly overview
11+
12+
[LaunchDarkly](https://www.launchdarkly.com) is a feature management platform that serves over 100 billion feature flags daily to help teams build better software, faster. [Get started](https://docs.launchdarkly.com/home/getting-started) using LaunchDarkly today!
13+
14+
[![Twitter Follow](https://img.shields.io/twitter/follow/launchdarkly.svg?style=social&label=Follow&maxAge=2592000)](https://twitter.com/intent/follow?screen_name=launchdarkly)
15+
16+
## Quick Setup
17+
18+
This assumes that you have already installed the LaunchDarkly Node.js SDK, or a compatible edge
19+
SDK.
20+
21+
1. Install this package with `npm` or `yarn`:
22+
23+
```shell
24+
npm install @launchdarkly/server-sdk-ai --save
25+
```
26+
27+
2. Create an AI SDK instance:
28+
29+
```typescript
30+
// The ldClient instance should be created based on the instructions in the relevant SDK.
31+
const aiClient = initAi(ldClient);
32+
```
33+
34+
3. Evaluate a model configuration:
35+
```typescript
36+
const config = await aiClient.modelConfig(
37+
aiConfigKey!,
38+
context,
39+
{ enabled: false },
40+
{ myVariable: 'My User Defined Variable' },
41+
);
42+
```
43+
44+
For an example of how to use the config please refer to the examples folder.
45+
46+
## Contributing
47+
48+
We encourage pull requests and other contributions from the community. Check out our [contributing guidelines](CONTRIBUTING.md) for instructions on how to contribute to this SDK.
49+
50+
## About LaunchDarkly
51+
52+
- LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard. With LaunchDarkly, you can:
53+
- Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases.
54+
- Gradually roll out a feature to an increasing percentage of users, and track the effect that the feature has on key metrics (for instance, how likely is a user to complete a purchase if they have feature A versus feature B?).
55+
- Turn off a feature that you realize is causing performance problems in production, without needing to re-deploy, or even restart the application with a changed configuration file.
56+
- Grant access to certain features based on user attributes, like payment plan (eg: users on the ‘gold’ plan get access to more features than users in the ‘silver’ plan).
57+
- Disable parts of your application to facilitate maintenance, without taking everything offline.
58+
- LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies. Check out [our documentation](https://docs.launchdarkly.com/sdk) for a complete list.
59+
- Explore LaunchDarkly
60+
- [launchdarkly.com](https://www.launchdarkly.com/ 'LaunchDarkly Main Website') for more information
61+
- [docs.launchdarkly.com](https://docs.launchdarkly.com/ 'LaunchDarkly Documentation') for our documentation and SDK reference guides
62+
- [apidocs.launchdarkly.com](https://apidocs.launchdarkly.com/ 'LaunchDarkly API Documentation') for our API documentation
63+
- [blog.launchdarkly.com](https://blog.launchdarkly.com/ 'LaunchDarkly Blog Documentation') for the latest product updates
64+
65+
[node-otel-ci-badge]: https://github.com/launchdarkly/js-core/actions/workflows/node-otel.yml/badge.svg
66+
[node-otel-ci]: https://github.com/launchdarkly/js-core/actions/workflows/node-otel.yml
67+
[node-otel-npm-badge]: https://img.shields.io/npm/v/@launchdarkly/node-server-sdk-otel.svg?style=flat-square
68+
[node-otel-npm-link]: https://www.npmjs.com/package/@launchdarkly/node-server-sdk-otel
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# LaunchDarkly AI SDK for AWS Bedrock Example
2+
3+
This package demonstrates the integration of LaunchDarkly's AI SDK with AWS Bedrock, allowing you to leverage LaunchDarkly's AI Config capabilities in AI-powered applications using AWS Bedrock.
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 configuration key (defaults to 'sample-ai-config' if not set)
28+
29+
Additionally, ensure you have proper AWS credentials configured to access Bedrock services.
30+
31+
## Usage
32+
33+
The main script (`index.js`) demonstrates how to:
34+
35+
1. Initialize the LaunchDarkly SDK
36+
2. Set up a user context
37+
3. Initialize the LaunchDarkly AI client
38+
4. Retrieve an AI model configuration
39+
5. Send a prompt to AWS Bedrock
40+
6. Track token usage
41+
42+
To run the example (in the bedrock directory):
43+
44+
```bash
45+
yarn start
46+
```
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"name": "@launchdarkly/hello-ai-bedrock",
3+
"version": "0.1.0",
4+
"description": "LaunchDarkly AI SDK for Node.js",
5+
"private": true,
6+
"main": "dist/index.js",
7+
"types": "dist/index.d.ts",
8+
"type": "commonjs",
9+
"scripts": {
10+
"build": "tsc",
11+
"start": "yarn build && node ./dist/index.js",
12+
"lint": "npx eslint . --ext .ts",
13+
"prettier": "prettier --write '**/*.@(js|ts|tsx|json|css)' --ignore-path ../../../.prettierignore",
14+
"lint:fix": "yarn run lint --fix",
15+
"check": "yarn prettier && yarn lint && yarn build && yarn test"
16+
},
17+
"keywords": [
18+
"launchdarkly",
19+
"ai",
20+
"llm"
21+
],
22+
"author": "LaunchDarkly",
23+
"license": "Apache-2.0",
24+
"dependencies": {
25+
"@aws-sdk/client-bedrock-runtime": "^3.679.0",
26+
"@launchdarkly/node-server-sdk": "^9.7.1",
27+
"@launchdarkly/server-sdk-ai": "0.1.0"
28+
},
29+
"devDependencies": {
30+
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
31+
"@tsconfig/node20": "20.1.4",
32+
"@typescript-eslint/eslint-plugin": "^6.20.0",
33+
"@typescript-eslint/parser": "^6.20.0",
34+
"eslint": "^8.45.0",
35+
"eslint-config-airbnb-base": "^15.0.0",
36+
"eslint-config-airbnb-typescript": "^17.1.0",
37+
"eslint-config-prettier": "^8.8.0",
38+
"eslint-plugin-import": "^2.27.5",
39+
"eslint-plugin-jest": "^27.6.3",
40+
"eslint-plugin-prettier": "^5.0.0",
41+
"jest": "^29.7.0",
42+
"prettier": "^3.0.0",
43+
"rimraf": "^5.0.5",
44+
"typedoc": "0.25.0",
45+
"typescript": "^5.5.3"
46+
},
47+
"directories": {
48+
"example": "example"
49+
},
50+
"repository": {
51+
"type": "git",
52+
"url": "github.com/launchdarkly/js-core"
53+
}
54+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/* eslint-disable no-console */
2+
import { BedrockRuntimeClient, ConverseCommand, Message } from '@aws-sdk/client-bedrock-runtime';
3+
4+
import { init } from '@launchdarkly/node-server-sdk';
5+
import { initAi } from '@launchdarkly/server-sdk-ai';
6+
7+
const sdkKey = process.env.LAUNCHDARKLY_SDK_KEY;
8+
const aiConfigKey = process.env.LAUNCHDARKLY_AI_CONFIG_KEY || 'sample-ai-config';
9+
const awsClient = new BedrockRuntimeClient({ region: 'us-east-1' });
10+
11+
if (!sdkKey) {
12+
console.error('*** Please set the LAUNCHDARKLY_SDK_KEY env first');
13+
process.exit(1);
14+
}
15+
16+
if (!aiConfigKey) {
17+
console.error('*** Please set the LAUNCHDARKLY_AI_CONFIG_KEY env first');
18+
process.exit(1);
19+
}
20+
21+
const ldClient = init(sdkKey);
22+
23+
// Set up the context properties
24+
const context = {
25+
kind: 'user',
26+
key: 'example-user-key',
27+
name: 'Sandy',
28+
};
29+
30+
function mapPromptToConversation(
31+
prompt: { role: 'user' | 'assistant' | 'system'; content: string }[],
32+
): Message[] {
33+
return prompt.map((item) => ({
34+
// Bedrock doesn't support systems in the converse command.
35+
role: item.role !== 'system' ? item.role : 'user',
36+
content: [{ text: item.content }],
37+
}));
38+
}
39+
40+
async function main() {
41+
try {
42+
await ldClient.waitForInitialization({ timeout: 10 });
43+
console.log('*** SDK successfully initialized');
44+
} catch (error) {
45+
console.log(`*** SDK failed to initialize: ${error}`);
46+
process.exit(1);
47+
}
48+
49+
const aiClient = initAi(ldClient);
50+
51+
const aiConfig = await aiClient.modelConfig(
52+
aiConfigKey!,
53+
context,
54+
{
55+
model: {
56+
modelId: 'my-default-model',
57+
},
58+
enabled: true,
59+
},
60+
{
61+
myVariable: 'My User Defined Variable',
62+
},
63+
);
64+
const { tracker } = aiConfig;
65+
66+
const completion = tracker.trackBedrockConverse(
67+
await awsClient.send(
68+
new ConverseCommand({
69+
modelId: aiConfig.config.model?.modelId ?? 'no-model',
70+
messages: mapPromptToConversation(aiConfig.config.prompt ?? []),
71+
}),
72+
),
73+
);
74+
console.log('AI Response:', completion.output?.message?.content?.[0]?.text ?? 'no-response');
75+
console.log('Success.');
76+
}
77+
78+
main();

0 commit comments

Comments
 (0)