Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 lib/sdk/server-ai/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ ext.libraries = [:]
dependencies {
// Exposed on the public API surface (LDClientInterface), therefore `api` not `implementation`.
api "com.launchdarkly:launchdarkly-java-server-sdk:${versions.sdk}"
implementation "com.launchdarkly:launchdarkly-java-sdk-common:2.5.0"

testImplementation "org.hamcrest:hamcrest-all:1.3"
testImplementation "junit:junit:4.13.2"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.launchdarkly.sdk.server.ai.internal;

import com.launchdarkly.sdk.LDValue;
import com.launchdarkly.sdk.LDValueConverter;
import com.launchdarkly.sdk.LDValueType;
import com.launchdarkly.sdk.server.ai.datamodel.LDAIConfigTypes.JudgeConfiguration;
import com.launchdarkly.sdk.server.ai.datamodel.LDAIConfigTypes.Message;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.launchdarkly.sdk.server.ai.internal;

import com.launchdarkly.sdk.LDContext;
import com.launchdarkly.sdk.LDContextEncoder;
import com.launchdarkly.sdk.server.ai.internal.mustache.Mustache;
import com.launchdarkly.sdk.server.ai.internal.mustache.Template;

Expand Down Expand Up @@ -61,7 +62,7 @@ public String interpolate(String template, Map<String, Object> variables, LDCont
merged.putAll(variables);
}
// ldctx is added last so it always wins over any caller-supplied "ldctx" entry.
merged.put("ldctx", contextToMap(context));
merged.put("ldctx", LDContextEncoder.encode(context));
return render(template, merged);
}

Expand All @@ -83,51 +84,4 @@ private String render(String template, Map<String, Object> variables) {
Template compiled = templateCache.computeIfAbsent(template, compiler::compile);
return compiled.execute(variables);
}

/**
* Encodes the evaluation context directly into the nested map structure exposed to templates as
* {@code ldctx}, without round-tripping through JSON serialization. A single-kind context becomes
* a map of its attributes; a multi-kind context becomes
* {@code {"kind":"multi", "key":<fully-qualified key>, <kind>: {...}}} with one nested map per
* individual context.
*/
private static Map<String, Object> contextToMap(LDContext context) {
if (context == null || !context.isValid()) {
return new HashMap<>();
}
if (context.isMultiple()) {
Map<String, Object> map = new HashMap<>();
map.put("kind", "multi");
map.put("key", context.getFullyQualifiedKey());
int count = context.getIndividualContextCount();
for (int i = 0; i < count; i++) {
LDContext individual = context.getIndividualContext(i);
if (individual != null) {
// Mirror LaunchDarkly's standard context JSON: the per-kind objects nested under a
// multi-kind context omit "kind" because it is already implied by the property key.
map.put(individual.getKind().toString(), singleContextToMap(individual, false));
}
}
return map;
}
return singleContextToMap(context, true);
}

private static Map<String, Object> singleContextToMap(LDContext context, boolean includeKind) {
Map<String, Object> map = new HashMap<>();
if (includeKind) {
map.put("kind", context.getKind().toString());
}
map.put("key", context.getKey());
if (context.getName() != null) {
map.put("name", context.getName());
}
map.put("anonymous", context.isAnonymous());
// Custom attribute values can be arbitrary JSON; convert each LDValue to a plain Java value
// (depth-capped) so nested objects/arrays remain addressable from templates.
for (String attribute : context.getCustomAttributeNames()) {
map.put(attribute, LDValueConverter.toJavaObject(context.getValue(attribute)));
}
return map;
}
}

This file was deleted.

This file was deleted.

Loading