Skip to content

Commit 28962e5

Browse files
ctawiahcursoragent
andauthored
chore: scaffold LaunchDarkly Java AI SDK module foundation (AIC-2661) (#170)
**Requirements** - [x] I have added test coverage for new or changed functionality - [x] I have followed the repository's [pull request submission guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests) - [x] I have validated my changes against all supported platform versions > Note on test coverage: this is the foundation step (AIC-2661) and intentionally ships **no SDK behavior**, so there is nothing to unit test yet. The module is validated by `./gradlew build` (compile + checkstyle + javadoc + jacoco) and `./gradlew publishToMavenLocal`. Test coverage begins in Step 2 (AIC-2662). Validated locally on Temurin/OpenJDK 17; CI exercises the full JDK 8/11/17 matrix. **Related issues** - Epic: [AIC-2629 — Java AI SDK](https://launchdarkly.atlassian.net/browse/AIC-2629) - This PR: [AIC-2661 — Step 1: Foundation](https://launchdarkly.atlassian.net/browse/AIC-2661) **Describe the solution you've provided** Stands up the new `lib/sdk/server-ai` Gradle module from scratch with the same build, quality-gate, and release machinery as sibling modules (`lib/sdk/server`, `lib/java-server-sdk-otel`, `lib/java-server-sdk-redis-store`), so every later step in the epic lands on a solid, CI-enforced base. - **Module setup:** `build.gradle` (`java-library`, Java 8 source/target), `settings.gradle`, `gradle.properties` (release-please `version=0.1.0` markers), `checkstyle.xml`, `.gitignore`, `.gitattributes`, `CHANGELOG.md`, `README.md`, Gradle wrapper, and a documented `package-info.java`. - **Dependencies:** `api 'com.launchdarkly:launchdarkly-java-server-sdk:7.14.0'` (it appears in the public signature via `LDClientInterface`). A Mustache templating dependency is **not** added in this PR — it will be introduced in a later step (AIC-2662) once its audit (license / maintenance / transitive deps) is complete. The published POM therefore declares only the base SDK dependency. - **Quality gates:** checkstyle + jacoco, matching the actual repo standard. Signing is skipped for local/CI builds via `LD_SKIP_SIGNING`. - **Internal-visibility convention:** non-API code will live under `com.launchdarkly.sdk.server.ai.internal`, which is excluded from the published Javadoc and sources jars (configured in `build.gradle`, documented in `README.md` / `package-info.java`). - **CI:** `.github/workflows/java-server-sdk-ai.yml` runs the shared CI composite over a **JDK 8 / 11 / 17** matrix. - **Release:** registered in `.release-please-manifest.json` (`0.1.0`) and `release-please-config.json` (`launchdarkly-java-server-sdk-ai`, `extra-files: [gradle.properties]`). Verified locally: `./gradlew clean build` → BUILD SUCCESSFUL; `./gradlew publishToMavenLocal` → `com.launchdarkly:launchdarkly-java-server-sdk-ai:0.1.0` (jar/sources/javadoc/pom). **Describe alternatives you've considered** - **Module placement:** placed under `lib/sdk/` next to the core SDK (`lib/sdk/server`), mirroring the JS reference layout (`packages/sdk/server-ai`), rather than the flat `lib/java-server-sdk-*` add-on pattern used by the otel/redis integrations. - **Quality gates:** the ticket text mentioned error-prone/spotbugs, but no sibling module enforces them; aligned with the repo standard (checkstyle + jacoco) instead to avoid inconsistent CI friction. - **CI scope:** siblings run Java 8 only; opted for an 8/11/17 matrix to match the ticket's intent and genuinely test forward compatibility. **Additional context** - This is the first of six PRs in the epic. No SDK behavior is implemented here — data model, client, tracker, and evaluation land in AIC-2662 through AIC-2666. - The Mustache dependency and its audit are deferred to AIC-2662. - `javadoc { failOnError = false }` is a temporary shim because an otherwise-empty module trips javadoc's "no classes to document" error; there is a `TODO(AIC-2662)` to restore `failOnError = true` once the first public types land. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Infrastructure-only scaffolding with no product logic; only adds a new publishable module and CI/release wiring. > > **Overview** > Adds a new **`lib/sdk/server-ai`** Gradle module for **`launchdarkly-java-server-sdk-ai`** (v0.1.0) as the foundation for the Server-Side AI SDK—no AI Config APIs or runtime behavior yet, only **`package-info.java`** under `com.launchdarkly.sdk.server.ai`. > > The build mirrors sibling libraries: Java 8 target, **`api`** dependency on **`launchdarkly-java-server-sdk:7.14.0`**, checkstyle/jacoco, Maven publish/signing (with **`LD_SKIP_SIGNING`**), and exclusion of **`com.launchdarkly.sdk.server.ai.internal`** from published Javadoc/sources. Javadoc **`failOnError`** is temporarily disabled until public types land. > > **CI** is wired via **`.github/workflows/java-server-sdk-ai.yml`**, running the shared composite action against **`lib/sdk/server-ai`** on a **JDK 8 / 11 / 17** matrix. **Release Please** entries were added in **`.release-please-manifest.json`** and **`release-please-config.json`**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1800281. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 2eefa47 commit 28962e5

16 files changed

Lines changed: 652 additions & 0 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
strategy:
16+
matrix:
17+
java-version: [8, 11, 17]
18+
runs-on: ubuntu-latest
19+
steps:
20+
- uses: actions/checkout@v3
21+
22+
- name: Shared CI Steps
23+
uses: ./.github/actions/ci
24+
with:
25+
workspace_path: 'lib/sdk/server-ai'
26+
java_version: ${{ matrix.java-version }}

.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/sdk/server-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/sdk/server-ai/.gitattributes

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#
2+
# https://help.github.com/articles/dealing-with-line-endings/
3+
#
4+
# Linux start script should use lf
5+
/gradlew text eol=lf
6+
7+
# These are Windows script files and should use crlf
8+
*.bat text eol=crlf
9+

lib/sdk/server-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/sdk/server-ai/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Change log
2+
3+
All notable changes to the LaunchDarkly Server-Side AI SDK for Java will be documented in this file.
4+
This project adheres to [Semantic Versioning](http://semver.org).

lib/sdk/server-ai/README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# LaunchDarkly Server-Side AI SDK for Java
2+
3+
[![Circle CI](https://img.shields.io/badge/status-in%20development-orange)](https://github.com/launchdarkly/java-core)
4+
5+
> **Status:** In active development toward `v1.0.0`. APIs are not yet stable.
6+
7+
This library provides LaunchDarkly AI Config support for the LaunchDarkly Server-Side SDK for Java.
8+
It is built on top of [`launchdarkly-java-server-sdk`](https://github.com/launchdarkly/java-core/tree/main/lib/sdk/server)
9+
and lets you retrieve, interpolate, and track AI Configs (models, providers, messages, agents, and judges)
10+
managed in the LaunchDarkly dashboard.
11+
12+
## Supported Java versions
13+
14+
This library has a minimum Java version of 8.
15+
16+
## Getting started
17+
18+
This module is part of the [`java-core`](https://github.com/launchdarkly/java-core) monorepo and is
19+
published to Maven Central as `com.launchdarkly:launchdarkly-java-server-sdk-ai`.
20+
21+
Full usage documentation, including AI Config retrieval, tracking, and manual judge evaluation, will be
22+
added as the SDK is built out (see epic AIC-2629).
23+
24+
## Internal API convention
25+
26+
Public, supported types live directly under `com.launchdarkly.sdk.server.ai` (and its documented
27+
subpackages). Anything under `com.launchdarkly.sdk.server.ai.internal` is implementation detail: it is
28+
**not** part of the supported API, is excluded from the published Javadoc and sources jars, and may
29+
change without notice.
30+
31+
## Contributing
32+
33+
We encourage pull requests and other contributions from the community. Check out our
34+
[contributing guidelines](../../CONTRIBUTING.md) for instructions on how to contribute.
35+
36+
## About LaunchDarkly
37+
38+
LaunchDarkly is a feature management platform that serves trillions of feature flags daily to help teams
39+
build better software, faster. [Get started](https://launchdarkly.com) using LaunchDarkly today!

lib/sdk/server-ai/build.gradle

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
2+
buildscript {
3+
repositories {
4+
mavenCentral()
5+
mavenLocal()
6+
}
7+
}
8+
9+
plugins {
10+
id "java"
11+
id "java-library"
12+
id "checkstyle"
13+
id "jacoco"
14+
id "signing"
15+
id "maven-publish"
16+
id "io.github.gradle-nexus.publish-plugin" version "1.3.0"
17+
id "idea"
18+
}
19+
20+
configurations.all {
21+
// check for updates every build for dependencies with: 'changing: true'
22+
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
23+
}
24+
25+
repositories {
26+
mavenLocal()
27+
// Before LaunchDarkly release artifacts get synced to Maven Central they are here along with snapshots:
28+
maven { url "https://oss.sonatype.org/content/groups/public/" }
29+
mavenCentral()
30+
}
31+
32+
allprojects {
33+
group = 'com.launchdarkly'
34+
version = "${version}"
35+
archivesBaseName = 'launchdarkly-java-server-sdk-ai'
36+
sourceCompatibility = 1.8
37+
targetCompatibility = 1.8
38+
}
39+
40+
ext {
41+
sdkBasePackage = "com.launchdarkly.sdk.server.ai"
42+
}
43+
44+
ext.versions = [
45+
// The *lowest* version of the base SDK we are compatible with. LDClientInterface
46+
// appears in this library's public signature, so it is exposed as an `api` dependency.
47+
"sdk": "7.14.0"
48+
// NOTE: a Mustache templating dependency (for AI Config message/instruction interpolation)
49+
// will be added in a later step once it has been fully audited (license / maintenance /
50+
// transitive deps). See AIC-2662.
51+
]
52+
53+
ext.libraries = [:]
54+
55+
dependencies {
56+
// Exposed on the public API surface (LDClientInterface), therefore `api` not `implementation`.
57+
api "com.launchdarkly:launchdarkly-java-server-sdk:${versions.sdk}"
58+
59+
testImplementation "org.hamcrest:hamcrest-all:1.3"
60+
testImplementation "junit:junit:4.13.2"
61+
testImplementation "org.mockito:mockito-core:3.12.4"
62+
}
63+
64+
// Non-public implementation detail lives in `com.launchdarkly.sdk.server.ai.internal` and its
65+
// subpackages. We deliberately exclude it from the published Javadoc and sources jars so it is
66+
// not part of the supported, documented surface. See package-info / README for the convention.
67+
def internalPackageGlob = "**/com/launchdarkly/sdk/server/ai/internal/**"
68+
69+
java {
70+
withJavadocJar()
71+
withSourcesJar()
72+
}
73+
74+
javadoc {
75+
// exclude internal implementation classes from the published API documentation
76+
exclude internalPackageGlob
77+
// The foundation module (AIC-2661) intentionally ships no public types yet, only
78+
// package-info.java. The javadoc tool reports "No public or protected classes found to
79+
// document" in that state, so we tolerate it here. TODO(AIC-2662): set failOnError = true
80+
// once the data-model public types land.
81+
failOnError = false
82+
options {
83+
// suppress noisy "no comment" warnings; checkstyle enforces Javadoc on the public surface
84+
addStringOption('Xdoclint:all,-missing', '-quiet')
85+
}
86+
}
87+
88+
tasks.named('sourcesJar') {
89+
// keep internal implementation classes out of the published sources jar
90+
exclude internalPackageGlob
91+
}
92+
93+
test {
94+
testLogging {
95+
events "passed", "skipped", "failed", "standardOut", "standardError"
96+
showStandardStreams = true
97+
exceptionFormat = 'full'
98+
}
99+
}
100+
101+
jacoco {
102+
toolVersion = "0.8.11"
103+
}
104+
105+
jacocoTestReport {
106+
reports {
107+
xml.required = true
108+
html.required = true
109+
}
110+
}
111+
112+
checkstyle {
113+
toolVersion = "9.3"
114+
configFile = file("${project.rootDir}/checkstyle.xml")
115+
}
116+
117+
idea {
118+
module {
119+
downloadJavadoc = true
120+
downloadSources = true
121+
}
122+
}
123+
124+
publishing {
125+
publications {
126+
mavenJava(MavenPublication) {
127+
from components.java
128+
129+
groupId = 'com.launchdarkly'
130+
artifactId = project.archivesBaseName
131+
132+
pom {
133+
name = project.archivesBaseName
134+
description = 'LaunchDarkly Server-Side AI SDK for Java'
135+
url = 'https://github.com/launchdarkly/java-core'
136+
licenses {
137+
license {
138+
name = 'The Apache License, Version 2.0'
139+
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
140+
}
141+
}
142+
developers {
143+
developer {
144+
name = 'LaunchDarkly'
145+
email = 'team@launchdarkly.com'
146+
}
147+
}
148+
scm {
149+
connection = 'scm:git:git://github.com/launchdarkly/java-core.git'
150+
developerConnection = 'scm:git:ssh:git@github.com:launchdarkly/java-core.git'
151+
url = 'https://github.com/launchdarkly/java-core'
152+
}
153+
}
154+
}
155+
}
156+
repositories {
157+
mavenLocal()
158+
}
159+
}
160+
161+
nexusPublishing {
162+
clientTimeout = java.time.Duration.ofMinutes(2) // we've seen extremely long delays in creating repositories
163+
repositories {
164+
sonatype {
165+
nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
166+
snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))
167+
}
168+
}
169+
}
170+
171+
signing {
172+
sign publishing.publications.mavenJava
173+
}
174+
175+
tasks.withType(Sign) {
176+
onlyIf { !"1".equals(project.findProperty("LD_SKIP_SIGNING")) } // so we can build jars for testing in CI
177+
}

lib/sdk/server-ai/checkstyle.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0"?>
2+
<!DOCTYPE module PUBLIC
3+
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
4+
"https://checkstyle.org/dtds/configuration_1_3.dtd">
5+
<module name="Checker">
6+
<module name="TreeWalker">
7+
<module name="JavadocMethod">
8+
<property name="accessModifiers" value="public"/>
9+
</module>
10+
<module name="JavadocType">
11+
<property name="scope" value="public"/>
12+
</module>
13+
</module>
14+
</module>
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.

0 commit comments

Comments
 (0)