Skip to content
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

feat: Add AI SDK for Server-Side JavaScript. #619

Merged
merged 62 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
1e700c0
basic model
InTheCloudDan Sep 2, 2024
76dd721
add package that was dropped from rebase
InTheCloudDan Sep 3, 2024
6f393f7
change to map, switch type to Record
InTheCloudDan Sep 3, 2024
92ff33e
fix type in other location
InTheCloudDan Sep 3, 2024
d4c4fd9
change Record to string string everywhere
InTheCloudDan Sep 3, 2024
97365a0
switch back to unknown
InTheCloudDan Sep 3, 2024
488bc09
update interpolate function signature and escape within function call
InTheCloudDan Sep 3, 2024
679fb26
new package
InTheCloudDan Sep 6, 2024
5b1336e
add tracker
InTheCloudDan Sep 10, 2024
0a2586c
fix inadvertantly removed comment
InTheCloudDan Sep 10, 2024
4abed57
switch to variation ID
InTheCloudDan Sep 11, 2024
48b9a0f
fix package name
InTheCloudDan Oct 11, 2024
d34cb66
update naming
InTheCloudDan Oct 11, 2024
8ed5d9d
remove types file
InTheCloudDan Oct 16, 2024
76f25cc
exports
InTheCloudDan Oct 16, 2024
cf7582c
update example
InTheCloudDan Oct 16, 2024
c88ad2d
update how variationId is passed into tracker
InTheCloudDan Oct 16, 2024
9f78679
Update tracking methods
InTheCloudDan Oct 25, 2024
da3024f
whitespace changes
InTheCloudDan Oct 25, 2024
9ce1049
fix file organization
InTheCloudDan Oct 25, 2024
9c4e69f
openai and bedrock examples
InTheCloudDan Oct 25, 2024
f95775b
Merge branch 'main' into dob/modelConfig
kinyoklion Nov 4, 2024
5ea8a83
feat: AI Tracking to AI SDK (#652)
InTheCloudDan Nov 4, 2024
fcad822
Merge branch 'dob/modelConfig' of github.com:launchdarkly/js-server-s…
kinyoklion Nov 4, 2024
59d0c27
Merge branch 'dob/modelConfig' into feat/dob/REL-3130/aiExamples
kinyoklion Nov 4, 2024
95fa2bc
Build updates.
kinyoklion Nov 4, 2024
817d4f0
Fix bedrock example.
kinyoklion Nov 4, 2024
7d91ea8
Commenting improvements.
kinyoklion Nov 4, 2024
f87f30d
Refine typing.
kinyoklion Nov 4, 2024
b6804f0
Building bedrock example.
kinyoklion Nov 4, 2024
6106c82
Refactoring and cleanup.
kinyoklion Nov 4, 2024
c8d3c05
Renaming.
kinyoklion Nov 4, 2024
96185fb
Add more comments.
kinyoklion Nov 4, 2024
8eb4ad3
Convert openai example to typescript.
kinyoklion Nov 4, 2024
dddd5e7
CI and docs.
kinyoklion Nov 4, 2024
318da7d
Linting.
kinyoklion Nov 4, 2024
3c7aa41
Renames.
kinyoklion Nov 4, 2024
c1b1f3e
Lint
kinyoklion Nov 4, 2024
ef4c8ac
Example build changes.
kinyoklion Nov 4, 2024
f361b9b
Move AI package.
kinyoklion Nov 4, 2024
7043d26
Rename AIClient file to LDAIClient.
kinyoklion Nov 4, 2024
3d8697e
Merge branch 'main' into dob/modelConfig
kinyoklion Nov 4, 2024
e79b713
lint fix
InTheCloudDan Nov 5, 2024
c75ba9d
update examples to emit
InTheCloudDan Nov 5, 2024
fb05b7e
Better OpenAI types.
kinyoklion Nov 5, 2024
a4ce22e
Plurals
kinyoklion Nov 5, 2024
43e9a5d
Broaden server compatibility
kinyoklion Nov 5, 2024
1626a9d
Lint
kinyoklion Nov 5, 2024
4186201
Discussion feedback.
kinyoklion Nov 5, 2024
d0e487b
Change versionId to versionKey.
kinyoklion Nov 5, 2024
29024c1
Lint rules.
kinyoklion Nov 5, 2024
a0c9eca
Trivago lint.
kinyoklion Nov 5, 2024
3cb1b89
Add release configuration.
kinyoklion Nov 5, 2024
e78a10d
Merge branch 'main' into dob/modelConfig
kinyoklion Nov 5, 2024
3c5780c
Readme improvements. Example improvements.
kinyoklion Nov 5, 2024
e36bc35
Update example readme files.
kinyoklion Nov 5, 2024
69086da
Add beta notice.
kinyoklion Nov 5, 2024
205e600
Add markdown type annotation.
kinyoklion Nov 5, 2024
6379a78
Add release configuration to update examples.
kinyoklion Nov 5, 2024
e20a498
Make sure examples are not published to NPM.
kinyoklion Nov 5, 2024
807fa19
Node version.
kinyoklion Nov 5, 2024
4ff029b
Build example deps.
kinyoklion Nov 5, 2024
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
1 change: 1 addition & 0 deletions .github/workflows/manual-publish-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ on:
- packages/store/node-server-sdk-dynamodb
- packages/telemetry/node-server-sdk-otel
- packages/sdk/browser
- packages/sdk/server-ai
name: Publish Documentation
jobs:
build-publish:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/manual-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ on:
- packages/telemetry/node-server-sdk-otel
- packages/tooling/jest
- packages/sdk/browser
- packages/sdk/server-ai
prerelease:
description: 'Is this a prerelease. If so, then the latest tag will not be updated in npm.'
type: boolean
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
package-tooling-jest-release: ${{ steps.release.outputs['packages/tooling/jest--release_created'] }}
package-react-universal-release: ${{ steps.release.outputs['packages/sdk/react-universal--release_created'] }}
package-browser-released: ${{ steps.release.outputs['packages/sdk/browser--release_created'] }}
package-server-ai-released: ${{ steps.release.outputs['packages/sdk/server-ai--release_created'] }}
steps:
- uses: googleapis/release-please-action@v4
id: release
Expand Down Expand Up @@ -377,3 +378,23 @@ jobs:
with:
workspace_path: packages/sdk/react-universal
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}

release-server-ai:
runs-on: ubuntu-latest
needs: ['release-please', 'release-sdk-server']
permissions:
id-token: write
contents: write
if: ${{ always() && !failure() && !cancelled() && needs.release-please.outputs.package-server-ai-released == 'true'}}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.x
registry-url: 'https://registry.npmjs.org'
- id: release-react-native
name: Full release of packages/sdk/server-ai
uses: ./actions/full-release
with:
workspace_path: packages/sdk/server-ai
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}
37 changes: 37 additions & 0 deletions .github/workflows/server-ai.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: sdk/server-ai

on:
push:
branches: [main, 'feat/**']
paths-ignore:
- '**.md' #Do not need to run CI for markdown changes.
pull_request:
branches: [main, 'feat/**']
paths-ignore:
- '**.md'

jobs:
build-test-node-server-otel:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.x
registry-url: 'https://registry.npmjs.org'
- id: shared
name: Shared CI Steps
uses: ./actions/ci
with:
workspace_name: '@launchdarkly/server-sdk-ai'
workspace_path: packages/sdk/server-ai
- name: Build bedrock example
run: |
yarn workspaces focus @launchdarkly/hello-ai-bedrock
yarn workspace @launchdarkly/hello-ai-bedrock lint
yarn workspaces foreach -pR --topological-dev --from '@launchdarkly/hello-ai-bedrock' run build
- name: Build OpenAI example
run: |
yarn workspaces focus @launchdarkly/hello-openai
yarn workspace @launchdarkly/hello-openai lint
yarn workspaces foreach -pR --topological-dev --from '@launchdarkly/hello-openai' run build
3 changes: 2 additions & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
"packages/shared/sdk-client": "1.12.0",
"packages/sdk/react-native": "10.9.2",
"packages/telemetry/node-server-sdk-otel": "1.1.1",
"packages/sdk/browser": "0.3.0"
"packages/sdk/browser": "0.3.0",
"packages/sdk/server-ai": "0.0.0"
}
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
"packages/tooling/jest/example/react-native-example",
"packages/sdk/browser",
"packages/sdk/browser/contract-tests/entity",
"packages/sdk/browser/contract-tests/adapter"
"packages/sdk/browser/contract-tests/adapter",
"packages/sdk/server-ai",
"packages/sdk/server-ai/examples/bedrock",
"packages/sdk/server-ai/examples/openai"
],
"private": true,
"scripts": {
Expand Down
68 changes: 68 additions & 0 deletions packages/sdk/server-ai/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# LaunchDarkly AI SDK for Server-Side JavaScript

# ⛔️⛔️⛔️⛔️

> [!CAUTION]
> This library is a alpha version and should not be considered ready for production use while this message is visible.

# ☝️☝️☝️☝️☝️☝️

## LaunchDarkly overview

[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!

[![Twitter Follow](https://img.shields.io/twitter/follow/launchdarkly.svg?style=social&label=Follow&maxAge=2592000)](https://twitter.com/intent/follow?screen_name=launchdarkly)

## Quick Setup

This assumes that you have already installed the LaunchDarkly Node.js SDK, or a compatible edge
SDK.

1. Install this package with `npm` or `yarn`:

```shell
npm install @launchdarkly/server-sdk-ai --save
```

2. Create an AI SDK instance:

```typescript
// The ldClient instance should be created based on the instructions in the relevant SDK.
const aiClient = initAi(ldClient);
```

3. Evaluate a model configuration:
```typescript
const config = await aiClient.modelConfig(
aiConfigKey!,
context,
{ enabled: false },
{ myVariable: 'My User Defined Variable' },
);
```

For an example of how to use the config please refer to the examples folder.

## Contributing

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.

## About LaunchDarkly

- 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:
- 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.
- 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?).
- 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.
- 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).
- Disable parts of your application to facilitate maintenance, without taking everything offline.
- 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.
- Explore LaunchDarkly
- [launchdarkly.com](https://www.launchdarkly.com/ 'LaunchDarkly Main Website') for more information
- [docs.launchdarkly.com](https://docs.launchdarkly.com/ 'LaunchDarkly Documentation') for our documentation and SDK reference guides
- [apidocs.launchdarkly.com](https://apidocs.launchdarkly.com/ 'LaunchDarkly API Documentation') for our API documentation
- [blog.launchdarkly.com](https://blog.launchdarkly.com/ 'LaunchDarkly Blog Documentation') for the latest product updates

[node-otel-ci-badge]: https://github.com/launchdarkly/js-core/actions/workflows/node-otel.yml/badge.svg
[node-otel-ci]: https://github.com/launchdarkly/js-core/actions/workflows/node-otel.yml
[node-otel-npm-badge]: https://img.shields.io/npm/v/@launchdarkly/node-server-sdk-otel.svg?style=flat-square
[node-otel-npm-link]: https://www.npmjs.com/package/@launchdarkly/node-server-sdk-otel
46 changes: 46 additions & 0 deletions packages/sdk/server-ai/examples/bedrock/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# LaunchDarkly AI SDK for AWS Bedrock Example

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.

## Installation and Build

When running as part of the js-core mono-repo the project will use local dependencies.
As such those dependencies need built.

In the root of the repository run:

```bash
yarn
```

And then

```bash
yarn build
```

## Configuration

Before running the example, make sure to set the following environment variables:

- `LAUNCHDARKLY_SDK_KEY`: Your LaunchDarkly SDK key
- `LAUNCHDARKLY_AI_CONFIG_KEY`: Your LaunchDarkly AI configuration key (defaults to 'sample-ai-config' if not set)

Additionally, ensure you have proper AWS credentials configured to access Bedrock services.

## Usage

The main script (`index.js`) demonstrates how to:

1. Initialize the LaunchDarkly SDK
2. Set up a user context
3. Initialize the LaunchDarkly AI client
4. Retrieve an AI model configuration
5. Send a prompt to AWS Bedrock
6. Track token usage

To run the example (in the bedrock directory):

```bash
yarn start
```
54 changes: 54 additions & 0 deletions packages/sdk/server-ai/examples/bedrock/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "@launchdarkly/hello-ai-bedrock",
"version": "0.1.0",
"description": "LaunchDarkly AI SDK for Node.js",
"private": true,
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "commonjs",
"scripts": {
"build": "tsc",
"start": "yarn build && node ./dist/index.js",
"lint": "npx eslint . --ext .ts",
"prettier": "prettier --write '**/*.@(js|ts|tsx|json|css)' --ignore-path ../../../.prettierignore",
"lint:fix": "yarn run lint --fix",
"check": "yarn prettier && yarn lint && yarn build && yarn test"
},
"keywords": [
"launchdarkly",
"ai",
"llm"
],
"author": "LaunchDarkly",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/client-bedrock-runtime": "^3.679.0",
"@launchdarkly/node-server-sdk": "^9.7.1",
"@launchdarkly/server-sdk-ai": "0.1.0"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
"@tsconfig/node20": "20.1.4",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"eslint": "^8.45.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jest": "^27.6.3",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.7.0",
"prettier": "^3.0.0",
"rimraf": "^5.0.5",
"typedoc": "0.25.0",
"typescript": "^5.5.3"
},
"directories": {
"example": "example"
},
"repository": {
"type": "git",
"url": "github.com/launchdarkly/js-core"
}
}
78 changes: 78 additions & 0 deletions packages/sdk/server-ai/examples/bedrock/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* eslint-disable no-console */
import { BedrockRuntimeClient, ConverseCommand, Message } from '@aws-sdk/client-bedrock-runtime';

import { init } from '@launchdarkly/node-server-sdk';
import { initAi } from '@launchdarkly/server-sdk-ai';

const sdkKey = process.env.LAUNCHDARKLY_SDK_KEY;
const aiConfigKey = process.env.LAUNCHDARKLY_AI_CONFIG_KEY || 'sample-ai-config';
const awsClient = new BedrockRuntimeClient({ region: 'us-east-1' });

if (!sdkKey) {
console.error('*** Please set the LAUNCHDARKLY_SDK_KEY env first');
process.exit(1);
}

if (!aiConfigKey) {
console.error('*** Please set the LAUNCHDARKLY_AI_CONFIG_KEY env first');
process.exit(1);
}

const ldClient = init(sdkKey);

// Set up the context properties
const context = {
kind: 'user',
key: 'example-user-key',
name: 'Sandy',
};

function mapPromptToConversation(
prompt: { role: 'user' | 'assistant' | 'system'; content: string }[],
): Message[] {
return prompt.map((item) => ({
// Bedrock doesn't support systems in the converse command.
role: item.role !== 'system' ? item.role : 'user',
content: [{ text: item.content }],
}));
}

async function main() {
try {
await ldClient.waitForInitialization({ timeout: 10 });
console.log('*** SDK successfully initialized');
} catch (error) {
console.log(`*** SDK failed to initialize: ${error}`);
process.exit(1);
}

const aiClient = initAi(ldClient);

const aiConfig = await aiClient.modelConfig(
aiConfigKey!,
context,
{
model: {
modelId: 'my-default-model',
},
enabled: true,
},
{
myVariable: 'My User Defined Variable',
},
);
const { tracker } = aiConfig;

const completion = tracker.trackBedrockConverse(
await awsClient.send(
new ConverseCommand({
modelId: aiConfig.config.model?.modelId ?? 'no-model',
messages: mapPromptToConversation(aiConfig.config.prompt ?? []),
}),
),
);
console.log('AI Response:', completion.output?.message?.content?.[0]?.text ?? 'no-response');
console.log('Success.');
}

main();
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": "./tsconfig.json",
"include": ["/**/*.ts", "/**/*.tsx"],
"exclude": ["node_modules"]
}
22 changes: 22 additions & 0 deletions packages/sdk/server-ai/examples/bedrock/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"noEmit": false,
"outDir": "dist",
"baseUrl": ".",
"allowUnusedLabels": false,
"allowUnreachableCode": false,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"sourceMap": true,
"resolveJsonModule": true,
"module": "CommonJS",
"moduleResolution": "Node"
},
"include": ["src"],
"exclude": ["dist", "node_modules"]
}
Loading