-
Notifications
You must be signed in to change notification settings - Fork 1k
[WIP] Adapt to the latest input and output semantic specifications #14613
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: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.incubator.semconv.genai.messages; | ||
|
||
import com.fasterxml.jackson.annotation.JsonClassDescription; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.annotation.JsonPropertyDescription; | ||
import com.google.auto.value.AutoValue; | ||
import java.util.Map; | ||
|
||
/** | ||
* Represents an arbitrary message part with any type and properties. This allows for extensibility | ||
* with custom message part types. | ||
*/ | ||
@AutoValue | ||
@JsonClassDescription("Generic part") | ||
public abstract class GenericPart implements MessagePart { | ||
|
||
@JsonProperty(required = true, value = "type") | ||
@JsonPropertyDescription("The type of the content captured in this part") | ||
public abstract String getType(); | ||
|
||
public static GenericPart create(String type) { | ||
return new AutoValue_GenericPart(type); | ||
} | ||
|
||
public static GenericPart create(String type, Map<String, Object> additionalProperties) { | ||
return new AutoValue_GenericPart(type); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.incubator.semconv.genai.messages; | ||
|
||
import com.fasterxml.jackson.annotation.JsonClassDescription; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.annotation.JsonPropertyDescription; | ||
import com.google.auto.value.AutoValue; | ||
import java.util.List; | ||
|
||
/** Represents an input message sent to the model. */ | ||
@AutoValue | ||
@JsonClassDescription("Input message") | ||
public abstract class InputMessage { | ||
|
||
@JsonProperty(required = true, value = "role") | ||
@JsonPropertyDescription("Role of the entity that created the message") | ||
public abstract String getRole(); | ||
|
||
@JsonProperty(required = true, value = "parts") | ||
@JsonPropertyDescription("List of message parts that make up the message content") | ||
public abstract List<MessagePart> getParts(); | ||
|
||
public static InputMessage create(String role, List<MessagePart> parts) { | ||
return new AutoValue_InputMessage(role, parts); | ||
} | ||
|
||
public static InputMessage create(Role role, List<MessagePart> parts) { | ||
return new AutoValue_InputMessage(role.getValue(), parts); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.incubator.semconv.genai.messages; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.google.auto.value.AutoValue; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
/** Represents a collection of input messages sent to the model. */ | ||
@AutoValue | ||
public abstract class InputMessages { | ||
|
||
public abstract List<InputMessage> getMessages(); | ||
|
||
public static InputMessages create() { | ||
return new AutoValue_InputMessages(new ArrayList<>()); | ||
} | ||
|
||
public static InputMessages create(List<InputMessage> messages) { | ||
return new AutoValue_InputMessages(new ArrayList<>(messages)); | ||
} | ||
|
||
public InputMessages append(InputMessage inputMessage) { | ||
List<InputMessage> messages = getMessages(); | ||
messages.add(inputMessage); | ||
return this; | ||
} | ||
|
||
public String toJsonString() { | ||
try { | ||
ObjectMapper mapper = new ObjectMapper(); | ||
return mapper.writeValueAsString(this); | ||
} catch (JsonProcessingException e) { | ||
throw new RuntimeException("Failed to serialize InputMessages to JSON", e); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.incubator.semconv.genai.messages; | ||
|
||
/** Interface for all message parts. */ | ||
public interface MessagePart { | ||
|
||
/** | ||
* Get the type of this message part. | ||
* | ||
* @return the type string | ||
*/ | ||
String getType(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.incubator.semconv.genai.messages; | ||
|
||
import com.fasterxml.jackson.annotation.JsonClassDescription; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.annotation.JsonPropertyDescription; | ||
import com.google.auto.value.AutoValue; | ||
import java.util.List; | ||
|
||
@AutoValue | ||
@JsonClassDescription("Output message") | ||
public abstract class OutputMessage { | ||
|
||
@JsonProperty(required = true, value = "role") | ||
@JsonPropertyDescription("Role of response") | ||
public abstract String getRole(); | ||
|
||
@JsonProperty(required = true, value = "parts") | ||
@JsonPropertyDescription("List of message parts that make up the message content") | ||
public abstract List<MessagePart> getParts(); | ||
|
||
@JsonProperty(required = true, value = "finish_reason") | ||
@JsonPropertyDescription("Reason for finishing the generation") | ||
public abstract String getFinishReason(); | ||
|
||
public static OutputMessage create(String role, List<MessagePart> parts, String finishReason) { | ||
return new AutoValue_OutputMessage(role, parts, finishReason); | ||
} | ||
|
||
public static OutputMessage create(Role role, List<MessagePart> parts, String finishReason) { | ||
return new AutoValue_OutputMessage(role.getValue(), parts, finishReason); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.incubator.semconv.genai.messages; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.google.auto.value.AutoValue; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
/** Represents a collection of output messages from the model. */ | ||
@AutoValue | ||
public abstract class OutputMessages { | ||
|
||
public abstract List<OutputMessage> getMessages(); | ||
|
||
public static OutputMessages create() { | ||
return new AutoValue_OutputMessages(new ArrayList<>()); | ||
} | ||
|
||
public static OutputMessages create(List<OutputMessage> messages) { | ||
return new AutoValue_OutputMessages(new ArrayList<>(messages)); | ||
} | ||
|
||
public OutputMessages append(OutputMessage outputMessage) { | ||
List<OutputMessage> currentMessages = new ArrayList<>(getMessages()); | ||
currentMessages.add(outputMessage); | ||
return new AutoValue_OutputMessages(currentMessages); | ||
} | ||
|
||
public String toJsonString() { | ||
try { | ||
ObjectMapper mapper = new ObjectMapper(); | ||
return mapper.writeValueAsString(this); | ||
} catch (JsonProcessingException e) { | ||
throw new RuntimeException("Failed to serialize OutputMessages to JSON", e); | ||
} | ||
} | ||
|
||
/** | ||
* Merges a chunk OutputMessage into the existing messages at the specified index. This method is | ||
* used for streaming responses where content is received in chunks. | ||
* | ||
* @param index the index of the message to merge into | ||
* @param chunkMessage the chunk message to append | ||
* @return a new OutputMessages instance with the merged content | ||
*/ | ||
public OutputMessages merge(int index, OutputMessage chunkMessage) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If possible, abstracting all How do you think about that? cc @anuraaga |
||
List<OutputMessage> currentMessages = new ArrayList<>(getMessages()); | ||
|
||
if (index < 0 || index >= currentMessages.size()) { | ||
throw new IllegalArgumentException( | ||
"Index " | ||
+ index | ||
+ " is out of bounds for messages list of size " | ||
+ currentMessages.size()); | ||
} | ||
|
||
OutputMessage existingMessage = currentMessages.get(index); | ||
|
||
// Merge the parts by appending text content from chunk to existing message | ||
List<MessagePart> mergedParts = new ArrayList<>(existingMessage.getParts()); | ||
|
||
// If the chunk message has text parts, append their content to the first text part of existing | ||
// message | ||
for (MessagePart chunkPart : chunkMessage.getParts()) { | ||
if (chunkPart instanceof TextPart) { | ||
TextPart chunkTextPart = (TextPart) chunkPart; | ||
|
||
// Find the first text part in existing message to append to | ||
boolean appended = false; | ||
for (int i = 0; i < mergedParts.size(); i++) { | ||
MessagePart existingPart = mergedParts.get(i); | ||
if (existingPart instanceof TextPart) { | ||
TextPart existingTextPart = (TextPart) existingPart; | ||
// Create a new TextPart with combined content | ||
TextPart mergedTextPart = | ||
TextPart.create(existingTextPart.getContent() + chunkTextPart.getContent()); | ||
mergedParts.set(i, mergedTextPart); | ||
appended = true; | ||
break; | ||
} | ||
} | ||
|
||
// If no existing text part found, add the chunk as a new part | ||
if (!appended) { | ||
mergedParts.add(chunkTextPart); | ||
} | ||
} else { | ||
// For non-text parts, add them as new parts | ||
mergedParts.add(chunkPart); | ||
} | ||
} | ||
|
||
// Create new OutputMessage with merged parts, using the chunk's finish reason if available | ||
String finalFinishReason = | ||
chunkMessage.getFinishReason() != null | ||
? chunkMessage.getFinishReason() | ||
: existingMessage.getFinishReason(); | ||
|
||
OutputMessage mergedMessage = | ||
OutputMessage.create(existingMessage.getRole(), mergedParts, finalFinishReason); | ||
|
||
// Replace the message at the specified index | ||
currentMessages.set(index, mergedMessage); | ||
|
||
return new AutoValue_OutputMessages(currentMessages); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.incubator.semconv.genai.messages; | ||
|
||
public enum Role { | ||
SYSTEM("system"), | ||
USER("user"), | ||
ASSISTANT("assistant"), | ||
TOOL("tool"), | ||
DEVELOPER("developer"); | ||
|
||
private final String value; | ||
|
||
public String getValue() { | ||
return value; | ||
} | ||
|
||
Role(String value) { | ||
this.value = value; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.incubator.semconv.genai.messages; | ||
|
||
import com.fasterxml.jackson.annotation.JsonClassDescription; | ||
import com.fasterxml.jackson.annotation.JsonPropertyDescription; | ||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.google.auto.value.AutoValue; | ||
import java.util.List; | ||
|
||
/** Represents the list of system instructions sent to the model. */ | ||
@AutoValue | ||
@JsonClassDescription("System instructions") | ||
public abstract class SystemInstructions { | ||
|
||
@JsonPropertyDescription("List of message parts that make up the system instructions") | ||
public abstract List<MessagePart> getParts(); | ||
|
||
public static SystemInstructions create(List<MessagePart> parts) { | ||
return new AutoValue_SystemInstructions(parts); | ||
} | ||
|
||
public String toJsonString() { | ||
try { | ||
ObjectMapper mapper = new ObjectMapper(); | ||
return mapper.writeValueAsString(this); | ||
} catch (JsonProcessingException e) { | ||
throw new RuntimeException("Failed to serialize SystemInstructions to JSON", e); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.api.incubator.semconv.genai.messages; | ||
|
||
import com.fasterxml.jackson.annotation.JsonClassDescription; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.annotation.JsonPropertyDescription; | ||
import com.google.auto.value.AutoValue; | ||
|
||
/** Represents text content sent to or received from the model. */ | ||
@AutoValue | ||
@JsonClassDescription("Text part") | ||
public abstract class TextPart implements MessagePart { | ||
|
||
@JsonProperty(required = true, value = "type") | ||
@JsonPropertyDescription("The type of the content captured in this part") | ||
public abstract String getType(); | ||
|
||
@JsonProperty(required = true, value = "content") | ||
@JsonPropertyDescription("Text content sent to or received from the model") | ||
public abstract String getContent(); | ||
|
||
public static TextPart create(String content) { | ||
return new AutoValue_TextPart("text", content); | ||
} | ||
} |
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.
jackson annotations or
io.opentelemetry.api.common.Value
?