-
Notifications
You must be signed in to change notification settings - Fork 7
chore: Convert JSON LDValue into the AiConfig Object #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: lc/SDK-1192/AI-config-feature-branch
Are you sure you want to change the base?
chore: Convert JSON LDValue into the AiConfig Object #61
Conversation
I just realized I also need to copy the .github file from another project in this mono-repo to have the test run in CI. I am running the test locally via |
|
||
import java.util.List; | ||
|
||
public class AiConfig { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All concrete public classes should be final.
@@ -15,14 +30,151 @@ public class LDAiClient implements LDAiClientInterface { | |||
/** | |||
* Creates a {@link LDAiClient} | |||
* | |||
* @param client LaunchDarkly Java Server SDK | |||
* @param client LaunchDarkly Java Server SDK | |||
*/ | |||
public LDAiClient(LDClientInterface client) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment on AI config. Should be final.
* | ||
* Currently, I am doing this in a mutable way, just to verify the logic convert | ||
* LDValue into AiConfig. | ||
* It is possible we need a builder to create immutable version of this for ease |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, AI config should be immutable with a builder. Because the customer will need to make default values and we will need them to be immutable. Imagine we are writing the value into the default value for an event while the customer is mutating the AI config.
|
||
// Convert the _meta JSON object into Meta | ||
LDValue valueMeta = value.get("_ldMeta"); | ||
if (valueMeta == LDValue.ofNull() || valueMeta.getType() != LDValueType.OBJECT) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type of a null LDValue is LDValueType null. So, valueMeta.getType() == LDValueType.OBJECT, then you know it is an object and not null. You don't need the extra checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would probably re-arrange things into type guards, logging when there is a problem, but never really throwing.
if(check(logger, value, LDValueType.ARRAY, "message must be a JSON array")) { // it is an array }
Then do things with the array when it is, and something gets logged when it isn't. Or something similar.
} | ||
|
||
List<Message> messages = new ArrayList<Message>(); | ||
for (LDValue valueMessage : valueMessages.values()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LDValue provides a valuesAs
method, which turns allows you to convert an array functional style using a converter functor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LDValue valueMessages = LDValue.arrayOf(
LDValue.buildObject().put("content", "the user content").put("role", "user").build(),
LDValue.buildObject().put("content", "the system content").put("role", "system").build()
);
Iterable<Message> messages = valueMessages.valuesAs(new Message.MessageConverter());
Assuming this message implementation:
import com.launchdarkly.sdk.LDValue;
public class Message {
static class MessageConverter extends LDValue.Converter<Message> {
@Override
public LDValue fromType(Message message) {
return LDValue.buildObject()
.put("content", message.getContent())
.put("role", message.getRole().toString())
.build();
}
@Override
public Message toType(LDValue ldValue) {
return new Message(ldValue.get("content").stringValue(), Role.getRole(ldValue.get("role").stringValue()));
}
}
Message(String content, Role role) {
this.content = content;
this.role = role;
}
private String content;
private Role role;
public String getContent() {
return content;
}
public Role getRole() {
return role;
}
}
And this role implementation:
public enum Role {
USER("user"),
SYSTEM("system"),
ASSISTANT("assistant");
private final String role;
private Role(String role) {
this.role = role;
}
public static Role getRole(String role) {
switch (role) {
case "user":
return USER;
case "system":
return SYSTEM;
case "assistant":
return ASSISTANT;
default:
return null;
}
}
@Override
public String toString() {
return role;
}
}
You could, of course, add some validation as well, but this is the structure that makes this composable .
import com.launchdarkly.sdk.server.ai.datamodel.Meta; | ||
import com.launchdarkly.sdk.server.ai.datamodel.Model; | ||
import com.launchdarkly.sdk.server.ai.datamodel.Provider; | ||
import com.launchdarkly.sdk.server.ai.datamodel.Role; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is role missing from the PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestions in comments.
For ease of discussion, implement only the conversion logic from LDValue (that we will get back from the Feature Flag SDK) to the AiConfig DataModel.
This uses the exception-based short circuiting (similar to https://github.com/launchdarkly/dotnet-core/blob/6774539af1a2f87b96ae3e647fdcdc5663c791ab/pkgs/sdk/server-ai/src/LdAiClient.cs#L180) and LDValue reading logic similar to https://github.com/launchdarkly/python-server-sdk-ai/blob/main/ldai/client.py#L134