Skip to content

Commit d954ba6

Browse files
ctawiahcursoragent
andauthored
feat: AgentControl data model, parsing & interpolation (AIC-2662) (#171)
**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 **Related issues** - Implements [AIC-2662](https://launchdarkly.atlassian.net/browse/AIC-2662) — Step 2 of the Java AI SDK (epic [AIC-2629](https://launchdarkly.atlassian.net/browse/AIC-2629)). - Foundation (AIC-2661, #170) has merged; this PR is now based on `main`. **Describe the solution you've provided** Step 2 of the Java AI SDK: the AICONF **data model** and the **defensive JSON-protocol parsing** layer. No `LDAIClient` methods, tracker, or evaluation (those are AIC-2663+). > **Scope note:** Mustache interpolation has been **pulled out of this PR**. Per the SDK team's supply-chain guidance we will not link the external `com.samskivert:jmustache` artifact. The Mustache engine will be **vendored** (source copied into an internal, relocated package) together with the `Interpolator` in [AIC-2695](https://launchdarkly.atlassian.net/browse/AIC-2695), which gates the v1.0 release (AIC-2666). This PR therefore has **no third-party templating dependency**. _Public data model_ — `com.launchdarkly.sdk.server.ai.datamodel` (immutable, builder-based, documented): - `LDMessage` (`Role` enum + content), `ModelConfig` (name/parameters/custom), `ProviderConfig`, `ToolConfig` (root-level tool), `JudgeConfiguration` (+ nested `Judge`), and the `AIConfigMode` enum. _Internal parsing_ — `com.launchdarkly.sdk.server.ai.internal` (excluded from published Javadoc/sources): - `LDValueConverter` — depth-capped (`MAX_DEPTH = 100`) `LDValue` → plain Java tree. Integral numbers within ±2^53 decode to `Long`, otherwise `Double`. - `AIConfigParser` + `AIConfigFlagValue` — `LDValue` → strongly-typed parse. Malformed/missing/wrong-typed fields **never throw**; tools fall back to `model.parameters.tools[]`; `evaluationMetricKey` resolves to the first non-blank of `evaluationMetricKey` / `evaluationMetricKeys[]`; `_ldMeta` scalars are boxed to preserve tri-state `enabled` (absent ≠ false). **Design decisions (documented in code)** - **Data-model placement:** kept in `...server.ai.datamodel` rather than extracting a shared module now, to avoid premature abstraction; can relocate if a client-side AI SDK ever needs it. - **Boxed vs primitive:** `_ldMeta` scalars (`enabled`/`version`) are boxed in the parsed value so "absent" is distinguishable from a concrete value; resolved configs (later step) will use primitives with documented defaults. - **Number precision:** whole numbers outside ±2^53 cannot be represented exactly and decode to the nearest `Double`. **Additional context** Field shapes and behaviors mirror the Python (`python-server-sdk-ai`) and JS (`js-core/packages/sdk/server-ai`) reference SDKs for parity. 22 unit tests cover defensive parsing fallbacks and number/tool/metric-key resolution; full module build (compile + checkstyle main/test + javadoc + tests) is green. [AIC-2662]: https://launchdarkly.atlassian.net/browse/AIC-2662?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [AIC-2629]: https://launchdarkly.atlassian.net/browse/AIC-2629?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [AIC-2695]: https://launchdarkly.atlassian.net/browse/AIC-2695?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > New library surface and internal parsers only; no client evaluation or runtime wiring yet, with broad unit test coverage for malformed payloads. > > **Overview** > Adds the **Java server AI SDK data model and defensive flag-variation parsing** for AI Configs (AIC-2662). Mustache interpolation is **not** in this PR; `build.gradle` documents vendoring Mustache in AIC-2695 instead of linking `jmustache`. > > **Public API** — New `LDAIConfigTypes` in `datamodel` groups immutable nested types: `Mode`, `Message` (+ `Role`), `Model`, `Provider`, `Tool`, and `JudgeConfiguration` (+ `Judge`), with builders where needed and `Message.withContent` reserved for future interpolation. > > **Internal parsing** — `AIConfigParser` maps `LDValue` → `AIConfigFlagValue` without throwing on bad input; `LDValueConverter` turns nested JSON into plain Java maps/lists with depth cap (`MAX_DEPTH = 100`) and integral-number handling within ±2^53. Parsing covers `_ldMeta` (boxed `enabled` for absent vs false), tools (root `tools` over `model.parameters.tools[]`), and evaluation metric key (scalar then first non-blank in `evaluationMetricKeys[]`). > > **Build** — Javadoc no longer sets `failOnError = false` now that public types exist; empty `sonatype*` entries removed from `gradle.properties`. Unit tests cover parser and converter edge cases. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 69416f0. 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 f40c86e commit d954ba6

8 files changed

Lines changed: 1647 additions & 13 deletions

File tree

lib/sdk/server-ai/build.gradle

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ ext.versions = [
4545
// The *lowest* version of the base SDK we are compatible with. LDClientInterface
4646
// appears in this library's public signature, so it is exposed as an `api` dependency.
4747
"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.
48+
// NOTE: the Mustache templating engine (for AI Config message/instruction interpolation) is
49+
// intentionally not declared here. Per the SDK team's supply-chain guidance we will not link the
50+
// external com.samskivert:jmustache artifact; the library will be vendored (source copied into an
51+
// internal, relocated package) along with the Interpolator in AIC-2695, which must land before the
52+
// v1.0 release (AIC-2666).
5153
]
5254

5355
ext.libraries = [:]
@@ -74,11 +76,6 @@ java {
7476
javadoc {
7577
// exclude internal implementation classes from the published API documentation
7678
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
8279
options {
8380
// suppress noisy "no comment" warnings; checkstyle enforces Javadoc on the public surface
8481
addStringOption('Xdoclint:all,-missing', '-quiet')
Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
11
#x-release-please-start-version
22
version=0.1.0
33
#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=

0 commit comments

Comments
 (0)