refactor: use common LDValueConverter and LDContextEncoder in AI SDK#188
Merged
Merged
Conversation
3 tasks
…hy/AIC-2940/impl-common-context-encoder
tanderson-ld
approved these changes
Jul 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wires configured judges into completion and agent configs so online evaluation actually runs. Previously
completionConfig/agentConfigalways attachedEvaluator.noop()regardless of a config'sjudgeConfiguration, so judges were dormant (intentionally descoped in v1.0 — see #180). This completes that wiring.Applications supply a
Runnerper judge via a newAIRunnerProvider; the SDK builds a realEvaluatorfrom thejudgeConfiguration. Behavior is unchanged when no provider is configured — everything falls back toEvaluator.noop().New type
The application implements this to wrap any model provider. The client calls it once per judge key when building an
Evaluatorfor a completion or agent config that carries ajudgeConfiguration.New constructor
LDAIClientImplchangesThe hard-coded
Evaluator.noop()in the completion and agent paths (both the resolved-variation and default paths) is replaced withbuildEvaluator(judgeConfiguration, context, variables). Judge configs themselves still wireEvaluator.noop()internally — judges do not evaluate themselves.Per-judge sampling rates continue to flow from the
JudgeConfigurationthroughEvaluator.evaluate— theJudgeConfigurationremains the source of truth. Judge configs are fetched through the internal evaluation path, so building an evaluator does not emit judge usage-metric events.Fallback / isolation behavior
Evaluator.noop()when no provider is configured, thejudgeConfigurationis absent/empty, or every judge fails to construct.nullrunner from the provider, or an exception during construction skips only that judge (logged); the parent config is still built with the surviving judges.Migration
None required. Additive only — a new interface plus a new constructor overload. Existing callers behave identically (noop evaluator). Online evaluation is opt-in by passing an
AIRunnerProvider.Test plan
./gradlew :lib:sdk:server-ai:testpassescompletionConfigWithJudgeConfigAndProviderBuildsRealEvaluator— real (non-noop) evaluator builtagentConfigWithJudgeConfigAndProviderBuildsRealEvaluator— same for agent configscompletionConfigWithNoJudgesYieldsNoopEvaluator— nojudgeConfiguration→ noopcompletionConfigWithNullRunnerProviderYieldsNoopEvaluator— two-arg constructor → noop even with ajudgeConfigurationdisabledJudgeConfigIsFilteredAndEvaluatorIsNoop— disabled judge skipped and loggednullRunnerFromProviderSkipsThatJudge— provider returns null → judge skipped, loggedthrowingRunnerProviderSkipsThatJudgeButKeepsOthers— one bad judge skipped, others surviveAdditional context
judgeConfigurationis fetched and constructed eagerly at config-retrieval time (one flag evaluation per judge key), even if the evaluator is never invoked.message_history/response_to_evaluatevariables or strip legacy judge template messages before evaluation. Not a regression.Note
Low Risk
Internal refactor behind existing parsers/interpolation; risk is mainly behavioral parity if shared encoder/converter semantics differ slightly from the removed local code.
Overview
Replaces duplicated server-ai internals with
launchdarkly-java-sdk-common(2.5.0).server-ainow depends onlaunchdarkly-java-sdk-commonand drops the localLDValueConverterimplementation (and its unit tests).AIConfigParserstill maps model/tool JSON viaLDValueConverter.toMap, but that type now comes fromcom.launchdarkly.sdk.Interpolatorno longer builds theldctxMustache variable with privatecontextToMap/singleContextToMaphelpers; it usesLDContextEncoder.encode(context)instead, while keeping the same rule that caller-suppliedldctxis overridden.No public API changes; this is internal parsing/interpolation alignment with other Java SDKs.
Reviewed by Cursor Bugbot for commit 3ca7b7f. Bugbot is set up for automated code reviews on this repo. Configure here.