Skip to content

Commit 7ab69a2

Browse files
committed
Scaffold Java AI SDK
1 parent 3cba5ef commit 7ab69a2

47 files changed

Lines changed: 5439 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: java-server-sdk-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-java-server-sdk-ai:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v3
18+
19+
- name: Shared CI Steps
20+
uses: ./.github/actions/ci
21+
with:
22+
workspace_path: 'lib/java-server-sdk-ai'
23+
java_version: 8

.release-please-manifest.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"lib/java-server-sdk-ai": "0.1.0",
23
"lib/java-server-sdk-otel": "0.2.0",
34
"lib/java-server-sdk-redis-store": "3.1.1",
45
"lib/shared/common": "2.4.0",

lib/java-server-sdk-ai/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Ignore Gradle project-specific cache directory
2+
.gradle
3+
4+
# Ignore Gradle build output directory
5+
build
6+
bin

lib/java-server-sdk-ai/README.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# LaunchDarkly Server-side AI SDK for Java
2+
3+
This package provides AI Config functionality for the LaunchDarkly Java Server SDK. It lets you manage prompts, models, and providers as LaunchDarkly AI Configs, interpolate variables into messages and instructions, and record AI metrics (duration, token usage, generation success, feedback, tool calls, and online judge evaluations) back to LaunchDarkly.
4+
5+
It is built on top of the [LaunchDarkly Java Server SDK](https://github.com/launchdarkly/java-server-sdk) and is feature-compatible with the [LaunchDarkly Server-side AI SDK for Python](https://github.com/launchdarkly/python-server-sdk-ai).
6+
7+
## LaunchDarkly overview
8+
9+
[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!
10+
11+
[![Twitter Follow](https://img.shields.io/twitter/follow/launchdarkly.svg?style=social&label=Follow&maxAge=2592000)](https://twitter.com/intent/follow?screen_name=launchdarkly)
12+
13+
## Supported Java versions
14+
15+
This package is compatible with Java 8 and above, matching the LaunchDarkly Java Server SDK.
16+
17+
## Getting started
18+
19+
1. Add the `launchdarkly-java-server-sdk-ai` package to your project, alongside the core Java Server SDK:
20+
21+
```
22+
dependencies {
23+
implementation "com.launchdarkly:launchdarkly-java-server-sdk:7+"
24+
implementation "com.launchdarkly:launchdarkly-java-server-sdk-ai:0.1.0"
25+
}
26+
```
27+
28+
2. Construct an `LDAIClient`, wrapping your existing `LDClient`:
29+
30+
```java
31+
import com.launchdarkly.sdk.*;
32+
import com.launchdarkly.sdk.server.*;
33+
import com.launchdarkly.sdk.server.ai.*;
34+
import com.launchdarkly.sdk.server.ai.datamodel.*;
35+
36+
LDClient ldClient = new LDClient("sdk-key-123abc");
37+
LDAIClient aiClient = new LDAIClient(ldClient);
38+
```
39+
40+
A single `LDAIClient` should be reused for the lifetime of your application.
41+
42+
## Completion configs
43+
44+
A completion config carries chat-style messages, a model, and a provider. Provide a default to use when the AI Config is unavailable, and any variables to interpolate into the messages.
45+
46+
```java
47+
import java.util.Collections;
48+
import java.util.Arrays;
49+
50+
LDContext context = LDContext.create("user-key-123abc");
51+
52+
AICompletionConfig config = aiClient.completionConfig(
53+
"my-ai-config",
54+
context,
55+
AICompletionConfigDefault.builder()
56+
.enabled(true)
57+
.model(new ModelConfig("gpt-4"))
58+
.messages(Arrays.asList(
59+
LDMessage.system("You are a helpful assistant named {{name}}.")))
60+
.build(),
61+
Collections.singletonMap("name", "Bailey"));
62+
63+
if (config.isEnabled()) {
64+
AIConfigTracker tracker = config.createTracker();
65+
String answer = tracker.trackDurationOf(() -> callYourModel(config));
66+
tracker.trackSuccess();
67+
}
68+
```
69+
70+
Message and instruction content is interpolated with Mustache templating. In addition to any
71+
variables you supply, an `ldctx` variable is always available, exposing the attributes of the
72+
evaluation context (for example `{{ldctx.name}}`, or `{{ldctx.user.name}}` for a multi-context).
73+
74+
## Agent configs
75+
76+
An agent config carries freeform `instructions` rather than chat messages. Retrieve a single agent
77+
with `agentConfig`, or several at once with `agentConfigs`:
78+
79+
```java
80+
AIAgentConfig agent = aiClient.agentConfig(
81+
"research_agent",
82+
context,
83+
AIAgentConfigDefault.builder()
84+
.enabled(true)
85+
.model(new ModelConfig("gpt-4"))
86+
.instructions("You are a research assistant specializing in {{topic}}.")
87+
.build(),
88+
Collections.singletonMap("topic", "climate change"));
89+
```
90+
91+
## Tracking metrics
92+
93+
The `AIConfigTracker` returned by `createTracker()` records metrics for a single AI run. Each scalar
94+
metric (duration, success/error, feedback, tokens, time-to-first-token) is recorded at most once per
95+
tracker; obtain a new tracker for each run.
96+
97+
```java
98+
AIConfigTracker tracker = config.createTracker();
99+
100+
tracker.trackDuration(durationMs);
101+
tracker.trackTokens(new TokenUsage(/* total */ 30, /* input */ 10, /* output */ 20));
102+
tracker.trackSuccess(); // or tracker.trackError();
103+
tracker.trackFeedback(FeedbackKind.POSITIVE);
104+
```
105+
106+
To associate deferred events (such as user feedback gathered later) with the original run, persist
107+
the tracker's resumption token and reconstruct the tracker from it:
108+
109+
```java
110+
String token = tracker.getResumptionToken();
111+
// ...later, possibly in a different process...
112+
AIConfigTracker resumed = aiClient.createTracker(token, context);
113+
resumed.trackFeedback(FeedbackKind.POSITIVE);
114+
```
115+
116+
## Contributing
117+
118+
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.
119+
120+
## About LaunchDarkly
121+
122+
- 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:
123+
- 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.
124+
- 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?).
125+
- 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.
126+
- 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).
127+
- Disable parts of your application to facilitate maintenance, without taking everything offline.
128+
- 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.
129+
- Explore LaunchDarkly
130+
- [launchdarkly.com](https://www.launchdarkly.com/ 'LaunchDarkly Main Website') for more information
131+
- [docs.launchdarkly.com](https://docs.launchdarkly.com/ 'LaunchDarkly Documentation') for our documentation and SDK reference guides
132+
- [apidocs.launchdarkly.com](https://apidocs.launchdarkly.com/ 'LaunchDarkly API Documentation') for our API documentation
133+
- [blog.launchdarkly.com](https://blog.launchdarkly.com/ 'LaunchDarkly Blog Documentation') for the latest product updates
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
plugins {
2+
// Apply the java-library plugin for API and implementation separation.
3+
id 'java-library'
4+
id 'maven-publish'
5+
id 'signing'
6+
id 'jacoco'
7+
id 'io.github.gradle-nexus.publish-plugin' version '1.3.0'
8+
}
9+
10+
repositories {
11+
// Use Maven Central for resolving dependencies.
12+
mavenCentral()
13+
maven { url 'https://oss.sonatype.org/content/groups/public/' }
14+
}
15+
16+
allprojects {
17+
group = 'com.launchdarkly'
18+
version = "${version}"
19+
archivesBaseName = 'launchdarkly-java-server-sdk-ai'
20+
sourceCompatibility = 1.8
21+
targetCompatibility = 1.8
22+
}
23+
24+
ext.versions = [
25+
"launchdarklyJavaServerSdk": "7.6.0",
26+
"jmustache" : "1.16",
27+
]
28+
29+
dependencies {
30+
// The AI SDK is a thin layer on top of a fully-configured Java server SDK client.
31+
api "com.launchdarkly:launchdarkly-java-server-sdk:${versions.launchdarklyJavaServerSdk}"
32+
33+
// Logic-less Mustache templating for prompt/instruction interpolation. jmustache is a
34+
// single, dependency-free jar, which keeps the AI SDK's transitive footprint small.
35+
implementation "com.samskivert:jmustache:${versions.jmustache}"
36+
37+
testImplementation 'junit:junit:4.13.2'
38+
testImplementation 'org.hamcrest:hamcrest:2.2'
39+
}
40+
41+
test {
42+
useJUnit()
43+
testLogging {
44+
events 'passed', 'skipped', 'failed'
45+
exceptionFormat 'full'
46+
showStandardStreams = false
47+
}
48+
}
49+
50+
java {
51+
withJavadocJar()
52+
withSourcesJar()
53+
}
54+
55+
javadoc {
56+
// Surface only the public API in generated documentation.
57+
options.addStringOption('Xdoclint:none', '-quiet')
58+
}
59+
60+
jacocoTestReport {
61+
reports {
62+
xml.required = true
63+
html.required = true
64+
}
65+
}
66+
67+
publishing {
68+
publications {
69+
mavenJava(MavenPublication) {
70+
from components.java
71+
72+
pom {
73+
name.set('LaunchDarkly Java Server-Side AI SDK')
74+
description.set('LaunchDarkly Server-Side AI SDK for Java, providing AI Config management, tracking, and online evaluation built on top of the LaunchDarkly Java Server SDK.')
75+
url.set('https://github.com/launchdarkly/java-core')
76+
licenses {
77+
license {
78+
name.set('The Apache License, Version 2.0')
79+
url.set('http://www.apache.org/licenses/LICENSE-2.0.txt')
80+
}
81+
}
82+
developers {
83+
developer {
84+
name.set('LaunchDarkly SDK Team')
85+
email.set('sdks@launchdarkly.com')
86+
}
87+
}
88+
scm {
89+
connection.set('scm:git:git://github.com/launchdarkly/java-core.git')
90+
developerConnection.set('scm:git:ssh:git@github.com:launchdarkly/java-core.git')
91+
url.set('https://github.com/launchdarkly/java-core')
92+
}
93+
}
94+
}
95+
}
96+
}
97+
98+
nexusPublishing {
99+
clientTimeout = java.time.Duration.ofMinutes(2)
100+
repositories {
101+
sonatype {
102+
nexusUrl.set(uri('https://ossrh-staging-api.central.sonatype.com/service/local/'))
103+
snapshotRepositoryUrl.set(uri('https://central.sonatype.com/repository/maven-snapshots/'))
104+
}
105+
}
106+
}
107+
108+
signing {
109+
// Only sign when explicitly publishing with credentials present.
110+
required { gradle.taskGraph.hasTask('publishToSonatype') }
111+
sign(publishing.publications['mavenJava'])
112+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#x-release-please-start-version
2+
version=0.1.0
3+
#x-release-please-end
4+
5+
# The following empty ossrh properties are used by LaunchDarkly's internal integration testing framework
6+
# and should not be needed for typical development purposes (including by third-party developers).
7+
sonatypeUsername=
8+
sonatypePassword=
60.2 KB
Binary file not shown.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
distributionBase=GRADLE_USER_HOME
2+
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
4+
networkTimeout=10000
5+
zipStoreBase=GRADLE_USER_HOME
6+
zipStorePath=wrapper/dists

0 commit comments

Comments
 (0)