Skip to content
Open
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
29 changes: 27 additions & 2 deletions lib/sdk/server-ai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,33 @@ This library has a minimum Java version of 8.
This module is part of the [`java-core`](https://github.com/launchdarkly/java-core) monorepo and is
published to Maven Central as `com.launchdarkly:launchdarkly-java-server-sdk-ai`.

Full usage documentation, including AI Config retrieval, tracking, and manual judge evaluation, will be
added as the SDK is built out (see epic AIC-2629).
Construct an `LDAIClient` from an initialized server-side `LDClient`, then retrieve a typed config:

```java
LDClient ldClient = new LDClient(sdkKey);
LDAIClient aiClient = new LDAIClientImpl(ldClient);

Map<String, Object> variables = new HashMap<>();
variables.put("username", "Sandy");

AICompletionConfig config = aiClient.completionConfig(
"my-ai-config-key",
context,
AICompletionConfigDefault.disabled(), // fallback when the flag is absent
variables);

if (config.isEnabled()) {
// config.getModel(), config.getProvider(), and config.getMessages() (already interpolated)
// are ready to pass to your model provider.
}
```

The companion `agentConfig`/`agentConfigs` and `judgeConfig` methods retrieve agent and judge
configs respectively. Within a prompt message or agent instruction, the evaluation context is
available as `{{ldctx}}` (for example `{{ldctx.key}}`).

Metric tracking and manual judge evaluation will be added as the SDK is built out (see epic
AIC-2629).

## Internal API convention

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.launchdarkly.sdk.server.ai;

import com.launchdarkly.sdk.server.ai.datamodel.LDAIConfigTypes.Mode;
import com.launchdarkly.sdk.server.ai.datamodel.LDAIConfigTypes.JudgeConfiguration;
import com.launchdarkly.sdk.server.ai.datamodel.LDAIConfigTypes.Model;
import com.launchdarkly.sdk.server.ai.datamodel.LDAIConfigTypes.Provider;
import com.launchdarkly.sdk.server.ai.datamodel.LDAIConfigTypes.Tool;

import java.util.Collections;
import java.util.Map;
import java.util.function.Supplier;

/**
* A retrieved agent AI Config. This is the result of {@link LDAIClient#agentConfig} (and each entry
* returned by {@link LDAIClient#agentConfigs}).
* <p>
* The {@link #getInstructions() instructions} have already had their template interpolated with the
* supplied variables and evaluation context. Instances are immutable.
*/
public final class AIAgentConfig extends AIConfig {
private final String instructions;
private final JudgeConfiguration judgeConfiguration;
private final Map<String, Tool> tools;

AIAgentConfig(
String key,
boolean enabled,
Model model,
Provider provider,
String instructions,
JudgeConfiguration judgeConfiguration,
Map<String, Tool> tools,
Supplier<LDAIConfigTracker> trackerFactory) {
super(key, enabled, Mode.AGENT, model, provider, trackerFactory);
this.instructions = instructions;
this.judgeConfiguration = judgeConfiguration;
this.tools = tools == null ? null : Collections.unmodifiableMap(tools);
}

/**
* Returns the interpolated agent instructions.
*
* @return the instructions, or {@code null} if none were specified
*/
public String getInstructions() {
return instructions;
}

/**
* Returns the judge configuration referencing judges that may evaluate this config.
*
* @return the judge configuration, or {@code null} if none was specified
*/
public JudgeConfiguration getJudgeConfiguration() {
return judgeConfiguration;
}

/**
* Returns the root-level tools map keyed by tool name.
*
* @return an unmodifiable map of tools, or {@code null} if none were specified
*/
public Map<String, Tool> getTools() {
return tools;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.launchdarkly.sdk.server.ai;

import com.launchdarkly.sdk.server.ai.datamodel.LDAIConfigTypes.JudgeConfiguration;
import com.launchdarkly.sdk.server.ai.datamodel.LDAIConfigTypes.Tool;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

/**
* A caller-supplied default for {@link LDAIClient#agentConfig} (and {@link LDAIClient#agentConfigs}),
* returned (as an {@link AIAgentConfig}) when the flag is absent or cannot be evaluated.
* <p>
* Build instances with {@link #builder()}. Instances are immutable.
*/
public final class AIAgentConfigDefault extends AIConfigDefault {
private final String instructions;
private final JudgeConfiguration judgeConfiguration;
private final Map<String, Tool> tools;

private AIAgentConfigDefault(Builder builder) {
super(builder);
this.instructions = builder.instructions;
this.judgeConfiguration = builder.judgeConfiguration;
this.tools = builder.tools == null
? null : Collections.unmodifiableMap(new LinkedHashMap<>(builder.tools));
}

/**
* Returns the default agent instructions.
*
* @return the instructions, or {@code null} if none were specified
*/
public String getInstructions() {
return instructions;
}

/**
* Returns the default judge configuration.
*
* @return the judge configuration, or {@code null} if none was specified
*/
public JudgeConfiguration getJudgeConfiguration() {
return judgeConfiguration;
}

/**
* Returns the default root-level tools map.
*
* @return an unmodifiable map of tools, or {@code null} if none were specified
*/
public Map<String, Tool> getTools() {
return tools;
}

/**
* Creates a new builder.
*
* @return a new {@link Builder}
*/
public static Builder builder() {
return new Builder();
}

/**
* Returns a disabled default, suitable as a fallback that causes callers to skip the model.
*
* @return a disabled {@link AIAgentConfigDefault}
*/
public static AIAgentConfigDefault disabled() {
return builder().enabled(false).build();
}

/**
* Builder for {@link AIAgentConfigDefault}.
*/
public static final class Builder extends AbstractBuilder<Builder> {
private String instructions;
private JudgeConfiguration judgeConfiguration;
private Map<String, Tool> tools;

private Builder() {
}

@Override
protected Builder self() {
return this;
}

/**
* Sets the default agent instructions.
*
* @param instructions the instructions; may be {@code null}
* @return this builder
*/
public Builder instructions(String instructions) {
this.instructions = instructions;
return this;
}

/**
* Sets the default judge configuration.
*
* @param judgeConfiguration the judge configuration; may be {@code null}
* @return this builder
*/
public Builder judgeConfiguration(JudgeConfiguration judgeConfiguration) {
this.judgeConfiguration = judgeConfiguration;
return this;
}

/**
* Sets the default root-level tools map. The map is copied defensively.
*
* @param tools the tools; may be {@code null}
* @return this builder
*/
public Builder tools(Map<String, Tool> tools) {
this.tools = tools;
return this;
}

/**
* Builds the immutable {@link AIAgentConfigDefault}.
*
* @return a new {@link AIAgentConfigDefault}
*/
public AIAgentConfigDefault build() {
return new AIAgentConfigDefault(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.launchdarkly.sdk.server.ai;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
* A single agent request passed to {@link LDAIClient#agentConfigs}, pairing an agent key with its
* own default and interpolation variables.
* <p>
* Build instances with {@link #builder(String)}. Instances are immutable.
*/
public final class AIAgentConfigRequest {
private final String key;
private final AIAgentConfigDefault defaultValue;
private final Map<String, Object> variables;

private AIAgentConfigRequest(Builder builder) {
this.key = builder.key;
this.defaultValue = builder.defaultValue;
this.variables = builder.variables == null
? null : Collections.unmodifiableMap(new HashMap<>(builder.variables));
}

/**
* Returns the agent key to retrieve.
*
* @return the agent key, never {@code null}
*/
public String getKey() {
return key;
}

/**
* Returns the default for this agent.
*
* @return the default, or {@code null} if a disabled default should be used
*/
public AIAgentConfigDefault getDefaultValue() {
return defaultValue;
}

/**
* Returns the interpolation variables for this agent's instructions.
*
* @return an unmodifiable map of variables, or {@code null} if none were specified
*/
public Map<String, Object> getVariables() {
return variables;
}

/**
* Creates a new builder for a request with the given agent key.
*
* @param key the agent key; must not be {@code null}
* @return a new {@link Builder}
* @throws NullPointerException if {@code key} is {@code null}
*/
public static Builder builder(String key) {
return new Builder(Objects.requireNonNull(key, "key"));
}

/**
* Builder for {@link AIAgentConfigRequest}.
*/
public static final class Builder {
private final String key;
private AIAgentConfigDefault defaultValue;
private Map<String, Object> variables;

private Builder(String key) {
this.key = key;
}

/**
* Sets the default for this agent.
*
* @param defaultValue the default; may be {@code null}
* @return this builder
*/
public Builder defaultValue(AIAgentConfigDefault defaultValue) {
this.defaultValue = defaultValue;
return this;
}

/**
* Sets the interpolation variables for this agent's instructions. The map is copied defensively.
*
* @param variables the variables; may be {@code null}
* @return this builder
*/
public Builder variables(Map<String, Object> variables) {
this.variables = variables;
return this;
}

/**
* Builds the immutable {@link AIAgentConfigRequest}.
*
* @return a new {@link AIAgentConfigRequest}
*/
public AIAgentConfigRequest build() {
return new AIAgentConfigRequest(this);
}
}
}
Loading
Loading