Skip to content

Hybrid Langfuse Prompt Management Integration #3926

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

Open
wants to merge 9 commits into
base: feature/prompt
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;

import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
Expand All @@ -24,29 +25,40 @@
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;

/**
* MLPrompt is the class to store prompt information.
*/
@Getter
@Setter
@EqualsAndHashCode
public class MLPrompt implements ToXContentObject, Writeable {

// fields
public static final String PROMPT_ID_FIELD = "prompt_id";
public static final String NAME_FIELD = "name";
public static final String DESCRIPTION_FIELD = "description";
public static final String VERSION_FIELD = "version";
public static final String PROMPT_FIELD = "prompt";
public static final String PROMPT_MANAGEMENT_TYPE_FIELD = "prompt_management_type"; // prompt management type -> MLPrompt or Langfuse
public static final String TAGS_FIELD = "tags";
public static final String PROMPT_EXTRA_CONFIG_FIELD = "extra_config";
public static final String CREATE_TIME_FIELD = "create_time";
public static final String LAST_UPDATE_TIME_FIELD = "last_update_time";

// prompt management type
public static final String LANGFUSE = "LANGFUSE";
public static final String MLPROMPT = "MLPROMPT";

private String promptId;
private String name;
private String description;
private String version;
private Map<String, String> prompt;
private String promptManagementType;
private List<String> tags;
private PromptExtraConfig promptExtraConfig;
private String tenantId;
private Instant createTime;
private Instant lastUpdateTime;
Expand All @@ -71,7 +83,9 @@ public MLPrompt(
String description,
String version,
Map<String, String> prompt,
String promptManagementType,
List<String> tags,
PromptExtraConfig promptExtraConfig,
String tenantId,
Instant createTime,
Instant lastUpdateTime
Expand All @@ -81,7 +95,9 @@ public MLPrompt(
this.description = description;
this.version = version;
this.prompt = prompt;
this.promptManagementType = promptManagementType;
this.tags = tags;
this.promptExtraConfig = promptExtraConfig;
this.tenantId = tenantId;
this.createTime = createTime;
this.lastUpdateTime = lastUpdateTime;
Expand All @@ -99,7 +115,9 @@ public MLPrompt(StreamInput input) throws IOException {
this.description = input.readOptionalString();
this.version = input.readOptionalString();
this.prompt = input.readMap(s -> s.readString(), s -> s.readString());
this.promptManagementType = input.readOptionalString();
this.tags = input.readList(StreamInput::readString);
this.promptExtraConfig = new PromptExtraConfig(input);
this.tenantId = input.readOptionalString();
this.createTime = input.readOptionalInstant();
this.lastUpdateTime = input.readOptionalInstant();
Expand All @@ -118,7 +136,9 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeOptionalString(description);
out.writeOptionalString(version);
out.writeMap(prompt, StreamOutput::writeString, StreamOutput::writeString);
out.writeOptionalString(promptManagementType);
out.writeCollection(tags, StreamOutput::writeString);
promptExtraConfig.writeTo(out);
out.writeOptionalString(tenantId);
out.writeOptionalInstant(createTime);
out.writeOptionalInstant(lastUpdateTime);
Expand Down Expand Up @@ -150,9 +170,15 @@ public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params
if (prompt != null) {
builder.field(PROMPT_FIELD, prompt);
}
if (promptManagementType != null) {
builder.field(PROMPT_MANAGEMENT_TYPE_FIELD, promptManagementType);
}
if (tags != null) {
builder.field(TAGS_FIELD, tags);
}
if (promptExtraConfig != null) {
builder.field(PROMPT_EXTRA_CONFIG_FIELD, promptExtraConfig);
}
if (tenantId != null) {
builder.field(TENANT_ID_FIELD, tenantId);
}
Expand Down Expand Up @@ -189,7 +215,9 @@ public static MLPrompt parse(XContentParser parser) throws IOException {
String description = null;
String version = null;
Map<String, String> prompt = null;
String promptManagementType = null;
List<String> tags = null;
PromptExtraConfig promptExtraConfig = null;
String tenantId = null;
Instant createTime = null;
Instant lastUpdateTime = null;
Expand All @@ -214,13 +242,19 @@ public static MLPrompt parse(XContentParser parser) throws IOException {
case PROMPT_FIELD:
prompt = parser.mapStrings();
break;
case PROMPT_MANAGEMENT_TYPE_FIELD:
promptManagementType = parser.text();
break;
case TAGS_FIELD:
tags = new ArrayList<>();
ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.currentToken(), parser);
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
tags.add(parser.text());
}
break;
case PROMPT_EXTRA_CONFIG_FIELD:
promptExtraConfig = PromptExtraConfig.parse(parser);
break;
case TENANT_ID_FIELD:
tenantId = parser.text();
break;
Expand All @@ -242,10 +276,40 @@ public static MLPrompt parse(XContentParser parser) throws IOException {
.description(description)
.version(version)
.prompt(prompt)
.promptManagementType(promptManagementType)
.tags(tags)
.promptExtraConfig(promptExtraConfig)
.tenantId(tenantId)
.createTime(createTime)
.lastUpdateTime(lastUpdateTime)
.build();
}

public void encrypt(String promptManagementType, BiFunction<String, String, String> function, String tenantId) {
if (promptManagementType.equalsIgnoreCase(LANGFUSE)) {
PromptExtraConfig promptExtraConfig = this.getPromptExtraConfig();
String publicKey = promptExtraConfig.getPublicKey();
String accessKey = this.getPromptExtraConfig().getAccessKey();

promptExtraConfig.setPublicKey(function.apply(publicKey, tenantId));
promptExtraConfig.setAccessKey(function.apply(accessKey, tenantId));

this.setPromptExtraConfig(promptExtraConfig);
}
// add other prompt management client case here, if needed
}

public void decrypt(String promptManagementType, BiFunction<String, String, String> function, String tenantId) {
if (promptManagementType.equalsIgnoreCase(LANGFUSE)) {
PromptExtraConfig promptExtraConfig = this.getPromptExtraConfig();
String publicKey = promptExtraConfig.getPublicKey();
String accessKey = this.getPromptExtraConfig().getAccessKey();

promptExtraConfig.setPublicKey(function.apply(publicKey, tenantId));
promptExtraConfig.setAccessKey(function.apply(accessKey, tenantId));

this.setPromptExtraConfig(promptExtraConfig);
}
// add other prompt management client case here, if needed
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.ml.common.prompt;

import static org.opensearch.core.xcontent.XContentParserUtils.ensureExpectedToken;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.core.common.io.stream.Writeable;
import org.opensearch.core.xcontent.ToXContentObject;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.core.xcontent.XContentParser;

import lombok.Builder;
import lombok.Data;

@Data
public class PromptExtraConfig implements ToXContentObject, Writeable {

public static final String LANGFUSE_PROMPT_TYPE_FIELD = "type";
public static final String LANGFUSE_PROMPT_PUBLIC_KEY_FIELD = "public_key";
public static final String LANGFUSE_PROMPT_ACCESS_KEY_FIELD = "access_key";
public static final String LANGFUSE_PROMPT_LABELS_FIELD = "labels";

private String type; // required
private String publicKey; // required
private String accessKey; // required
private List<String> labels; // optional

@Builder(toBuilder = true)
public PromptExtraConfig(String type, String publicKey, String accessKey, List<String> labels) {
this.type = type;
this.publicKey = publicKey;
this.accessKey = accessKey;
this.labels = labels;
}

public PromptExtraConfig(StreamInput input) throws IOException {
this.type = input.readOptionalString();
this.publicKey = input.readOptionalString();
this.accessKey = input.readOptionalString();
this.labels = input.readList(StreamInput::readString);
}

@Override
public void writeTo(StreamOutput output) throws IOException {
output.writeOptionalString(type);
output.writeOptionalString(publicKey);
output.writeOptionalString(accessKey);
output.writeCollection(labels, StreamOutput::writeString);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
if (type != null) {
builder.field(LANGFUSE_PROMPT_TYPE_FIELD, type);
}
if (publicKey != null) {
builder.field(LANGFUSE_PROMPT_PUBLIC_KEY_FIELD, publicKey);
}
if (accessKey != null) {
builder.field(LANGFUSE_PROMPT_ACCESS_KEY_FIELD, accessKey);
}
if (labels != null) {
builder.field(LANGFUSE_PROMPT_LABELS_FIELD, labels);
}
return builder.endObject();
}

public static PromptExtraConfig parse(XContentParser parser) throws IOException {
String type = null;
String publicKey = null;
String accessKey = null;
List<String> labels = null;

ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser);
while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
String fieldName = parser.currentName();
parser.nextToken();
switch (fieldName) {
case LANGFUSE_PROMPT_TYPE_FIELD:
type = parser.text();
break;
case LANGFUSE_PROMPT_PUBLIC_KEY_FIELD:
publicKey = parser.text();
break;
case LANGFUSE_PROMPT_ACCESS_KEY_FIELD:
accessKey = parser.text();
break;
case LANGFUSE_PROMPT_LABELS_FIELD:
labels = new ArrayList<>();
ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.currentToken(), parser);
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
labels.add(parser.text());
}
break;
default:
parser.skipChildren();
break;
}
}
return PromptExtraConfig.builder().type(type).publicKey(publicKey).accessKey(accessKey).labels(labels).build();
}
}
Loading
Loading