From cd26b9ab5ffda5ba52130d66ecb6c187fcd7b459 Mon Sep 17 00:00:00 2001 From: gary-huang Date: Wed, 5 Nov 2025 15:33:26 -0500 Subject: [PATCH 1/3] set unified service tags on llm obs span start --- .../datadog/trace/llmobs/LLMObsSystem.java | 65 ++++++++++++++----- .../trace/llmobs/domain/DDLLMObsSpan.java | 14 +++- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/LLMObsSystem.java b/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/LLMObsSystem.java index 00a04e5e59d..a57dd858b45 100644 --- a/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/LLMObsSystem.java +++ b/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/LLMObsSystem.java @@ -2,6 +2,7 @@ import datadog.communication.ddagent.SharedCommunicationObjects; import datadog.trace.api.Config; +import datadog.trace.api.WellKnownTags; import datadog.trace.api.llmobs.LLMObs; import datadog.trace.api.llmobs.LLMObsSpan; import datadog.trace.api.llmobs.LLMObsTags; @@ -31,12 +32,9 @@ public static void start(Instrumentation inst, SharedCommunicationObjects sco) { sco.createRemaining(config); - LLMObsInternal.setLLMObsSpanFactory( - new LLMObsManualSpanFactory(config.getLlmObsMlApp(), config.getServiceName())); - String mlApp = config.getLlmObsMlApp(); - LLMObsInternal.setLLMObsSpanFactory( - new LLMObsManualSpanFactory(mlApp, config.getServiceName())); + WellKnownTags wellKnownTags = config.getWellKnownTags(); + LLMObsInternal.setLLMObsSpanFactory(new LLMObsManualSpanFactory(mlApp, wellKnownTags)); LLMObsInternal.setLLMObsEvalProcessor(new LLMObsCustomEvalProcessor(mlApp, sco, config)); } @@ -129,12 +127,14 @@ public void SubmitEvaluation( private static class LLMObsManualSpanFactory implements LLMObs.LLMObsSpanFactory { - private final String serviceName; private final String defaultMLApp; + private final String serviceName; + private final WellKnownTags wellKnownTags; - public LLMObsManualSpanFactory(String defaultMLApp, String serviceName) { + public LLMObsManualSpanFactory(String defaultMLApp, WellKnownTags wellKnownTags) { this.defaultMLApp = defaultMLApp; - this.serviceName = serviceName; + this.serviceName = wellKnownTags.getService().toString(); + this.wellKnownTags = wellKnownTags; } @Override @@ -147,7 +147,12 @@ public LLMObsSpan startLLMSpan( DDLLMObsSpan span = new DDLLMObsSpan( - Tags.LLMOBS_LLM_SPAN_KIND, spanName, getMLApp(mlApp), sessionId, serviceName); + Tags.LLMOBS_LLM_SPAN_KIND, + spanName, + getMLApp(mlApp), + sessionId, + serviceName, + wellKnownTags); if (modelName == null || modelName.isEmpty()) { modelName = CUSTOM_MODEL_VAL; @@ -165,28 +170,48 @@ public LLMObsSpan startLLMSpan( public LLMObsSpan startAgentSpan( String spanName, @Nullable String mlApp, @Nullable String sessionId) { return new DDLLMObsSpan( - Tags.LLMOBS_AGENT_SPAN_KIND, spanName, getMLApp(mlApp), sessionId, serviceName); + Tags.LLMOBS_AGENT_SPAN_KIND, + spanName, + getMLApp(mlApp), + sessionId, + serviceName, + wellKnownTags); } @Override public LLMObsSpan startToolSpan( String spanName, @Nullable String mlApp, @Nullable String sessionId) { return new DDLLMObsSpan( - Tags.LLMOBS_TOOL_SPAN_KIND, spanName, getMLApp(mlApp), sessionId, serviceName); + Tags.LLMOBS_TOOL_SPAN_KIND, + spanName, + getMLApp(mlApp), + sessionId, + serviceName, + wellKnownTags); } @Override public LLMObsSpan startTaskSpan( String spanName, @Nullable String mlApp, @Nullable String sessionId) { return new DDLLMObsSpan( - Tags.LLMOBS_TASK_SPAN_KIND, spanName, getMLApp(mlApp), sessionId, serviceName); + Tags.LLMOBS_TASK_SPAN_KIND, + spanName, + getMLApp(mlApp), + sessionId, + serviceName, + wellKnownTags); } @Override public LLMObsSpan startWorkflowSpan( String spanName, @Nullable String mlApp, @Nullable String sessionId) { return new DDLLMObsSpan( - Tags.LLMOBS_WORKFLOW_SPAN_KIND, spanName, getMLApp(mlApp), sessionId, serviceName); + Tags.LLMOBS_WORKFLOW_SPAN_KIND, + spanName, + getMLApp(mlApp), + sessionId, + serviceName, + wellKnownTags); } @Override @@ -201,7 +226,12 @@ public LLMObsSpan startEmbeddingSpan( } DDLLMObsSpan embeddingSpan = new DDLLMObsSpan( - Tags.LLMOBS_EMBEDDING_SPAN_KIND, spanName, getMLApp(mlApp), sessionId, serviceName); + Tags.LLMOBS_EMBEDDING_SPAN_KIND, + spanName, + getMLApp(mlApp), + sessionId, + serviceName, + wellKnownTags); embeddingSpan.setTag(LLMObsTags.MODEL_PROVIDER, modelProvider); embeddingSpan.setTag(LLMObsTags.MODEL_NAME, modelName); return embeddingSpan; @@ -210,7 +240,12 @@ public LLMObsSpan startEmbeddingSpan( public LLMObsSpan startRetrievalSpan( String spanName, @Nullable String mlApp, @Nullable String sessionId) { return new DDLLMObsSpan( - Tags.LLMOBS_RETRIEVAL_SPAN_KIND, spanName, getMLApp(mlApp), sessionId, serviceName); + Tags.LLMOBS_RETRIEVAL_SPAN_KIND, + spanName, + getMLApp(mlApp), + sessionId, + serviceName, + wellKnownTags); } private String getMLApp(String mlApp) { diff --git a/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java b/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java index 71d13596090..b3f1642fd5d 100644 --- a/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java +++ b/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java @@ -3,6 +3,7 @@ import datadog.context.ContextScope; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTraceId; +import datadog.trace.api.WellKnownTags; import datadog.trace.api.llmobs.LLMObs; import datadog.trace.api.llmobs.LLMObsSpan; import datadog.trace.api.llmobs.LLMObsTags; @@ -34,6 +35,10 @@ public class DDLLMObsSpan implements LLMObsSpan { private static final String METADATA = LLMOBS_TAG_PREFIX + LLMObsTags.METADATA; private static final String PARENT_ID_TAG_INTERNAL = "parent_id"; + private static final String SERVICE = LLMOBS_TAG_PREFIX + "service"; + private static final String VERSION = LLMOBS_TAG_PREFIX + "version"; + private static final String ENV = LLMOBS_TAG_PREFIX + "env"; + private static final String LLM_OBS_INSTRUMENTATION_NAME = "llmobs"; private static final Logger LOGGER = LoggerFactory.getLogger(DDLLMObsSpan.class); @@ -49,7 +54,8 @@ public DDLLMObsSpan( String spanName, @Nonnull String mlApp, String sessionId, - @Nonnull String serviceName) { + @Nonnull String serviceName, + WellKnownTags wellKnownTags) { if (null == spanName || spanName.isEmpty()) { spanName = kind; @@ -62,6 +68,12 @@ public DDLLMObsSpan( .withSpanType(DDSpanTypes.LLMOBS); this.span = spanBuilder.start(); + + // set UST + this.span.setTag(ENV, wellKnownTags.getEnv()); + this.span.setTag(SERVICE, wellKnownTags.getService()); + this.span.setTag(VERSION, wellKnownTags.getVersion()); + this.span.setTag(SPAN_KIND, kind); this.spanKind = kind; this.span.setTag(LLMOBS_TAG_PREFIX + LLMObsTags.ML_APP, mlApp); From 859ad016be76fda420cd28a7a87d72d8b0b0ed91 Mon Sep 17 00:00:00 2001 From: gary-huang Date: Wed, 12 Nov 2025 14:47:12 -0500 Subject: [PATCH 2/3] tests and clarify comment --- .../trace/llmobs/domain/DDLLMObsSpan.java | 2 +- .../llmobs/domain/DDLLMObsSpanTest.groovy | 66 ++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java b/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java index b3f1642fd5d..aa1332489a6 100644 --- a/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java +++ b/dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/domain/DDLLMObsSpan.java @@ -69,7 +69,7 @@ public DDLLMObsSpan( this.span = spanBuilder.start(); - // set UST + // set UST (unified service tags, env, service, version) this.span.setTag(ENV, wellKnownTags.getEnv()); this.span.setTag(SERVICE, wellKnownTags.getService()); this.span.setTag(VERSION, wellKnownTags.getVersion()); diff --git a/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy b/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy index a6c8534be2b..e0997984c64 100644 --- a/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy +++ b/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy @@ -3,12 +3,14 @@ package datadog.trace.llmobs.domain import datadog.trace.agent.tooling.TracerInstaller import datadog.trace.api.DDTags import datadog.trace.api.IdGenerationStrategy +import datadog.trace.api.WellKnownTags import datadog.trace.api.llmobs.LLMObs import datadog.trace.api.llmobs.LLMObsSpan import datadog.trace.api.llmobs.LLMObsTags import datadog.trace.bootstrap.instrumentation.api.AgentSpan import datadog.trace.bootstrap.instrumentation.api.AgentTracer import datadog.trace.bootstrap.instrumentation.api.Tags +import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString import datadog.trace.core.CoreTracer import datadog.trace.test.util.DDSpecification import org.apache.groovy.util.Maps @@ -114,6 +116,21 @@ class DDLLMObsSpanTest extends DDSpecification{ assert innerSpan.isError() assert innerSpan.getTag(DDTags.ERROR_MSG) instanceof String assert errMsg.equals(innerSpan.getTag(DDTags.ERROR_MSG)) + + assert null == innerSpan.getTag("env") + def tagEnv = innerSpan.getTag(LLMOBS_TAG_PREFIX + "env") + assert tagEnv instanceof UTF8BytesString + assert "test-env" == tagEnv.toString() + + assert null == innerSpan.getTag("service") + def tagSvc = innerSpan.getTag(LLMOBS_TAG_PREFIX + "service") + assert tagSvc instanceof UTF8BytesString + assert "test-svc" == tagSvc.toString() + + assert null == innerSpan.getTag("version") + def tagVersion = innerSpan.getTag(LLMOBS_TAG_PREFIX + "version") + assert tagVersion instanceof UTF8BytesString + assert "v1" == tagVersion.toString() } def "test span with overwrites"() { @@ -183,6 +200,22 @@ class DDLLMObsSpanTest extends DDSpecification{ assert throwableMsg.equals(innerSpan.getTag(DDTags.ERROR_MSG)) assert innerSpan.getTag(DDTags.ERROR_STACK) instanceof String assert ((String)innerSpan.getTag(DDTags.ERROR_STACK)).contains(throwableMsg) + + + assert null == innerSpan.getTag("env") + def tagEnv = innerSpan.getTag(LLMOBS_TAG_PREFIX + "env") + assert tagEnv instanceof UTF8BytesString + assert "test-env" == tagEnv.toString() + + assert null == innerSpan.getTag("service") + def tagSvc = innerSpan.getTag(LLMOBS_TAG_PREFIX + "service") + assert tagSvc instanceof UTF8BytesString + assert "test-svc" == tagSvc.toString() + + assert null == innerSpan.getTag("version") + def tagVersion = innerSpan.getTag(LLMOBS_TAG_PREFIX + "version") + assert tagVersion instanceof UTF8BytesString + assert "v1" == tagVersion.toString() } def "test llm span string input formatted to messages"() { @@ -218,6 +251,22 @@ class DDLLMObsSpanTest extends DDSpecification{ assert expectedOutputMsg.getContent().equals(output) assert expectedOutputMsg.getRole().equals("unknown") assert expectedOutputMsg.getToolCalls().equals(null) + + + assert null == innerSpan.getTag("env") + def tagEnv = innerSpan.getTag(LLMOBS_TAG_PREFIX + "env") + assert tagEnv instanceof UTF8BytesString + assert "test-env" == tagEnv.toString() + + assert null == innerSpan.getTag("service") + def tagSvc = innerSpan.getTag(LLMOBS_TAG_PREFIX + "service") + assert tagSvc instanceof UTF8BytesString + assert "test-svc" == tagSvc.toString() + + assert null == innerSpan.getTag("version") + def tagVersion = innerSpan.getTag(LLMOBS_TAG_PREFIX + "version") + assert tagVersion instanceof UTF8BytesString + assert "v1" == tagVersion.toString() } def "test llm span with messages"() { @@ -259,9 +308,24 @@ class DDLLMObsSpanTest extends DDSpecification{ assert toolCall.getToolId().equals("6176241000") def expectedToolArgs = Maps.of("location", "paris") assert toolCall.getArguments().equals(expectedToolArgs) + + assert null == innerSpan.getTag("env") + def tagEnv = innerSpan.getTag(LLMOBS_TAG_PREFIX + "env") + assert tagEnv instanceof UTF8BytesString + assert "test-env" == tagEnv.toString() + + assert null == innerSpan.getTag("service") + def tagSvc = innerSpan.getTag(LLMOBS_TAG_PREFIX + "service") + assert tagSvc instanceof UTF8BytesString + assert "test-svc" == tagSvc.toString() + + assert null == innerSpan.getTag("version") + def tagVersion = innerSpan.getTag(LLMOBS_TAG_PREFIX + "version") + assert tagVersion instanceof UTF8BytesString + assert "v1" == tagVersion.toString() } private LLMObsSpan givenALLMObsSpan(String kind, name){ - new DDLLMObsSpan(kind, name, "test-ml-app", null, "test-svc") + new DDLLMObsSpan(kind, name, "test-ml-app", null, "test-svc", new WellKnownTags("test-runtime-1", "host-1", "test-env", "test-svc", "v1", "java")) } } From 4569fd72066f631fb82840cdba8ae883b98cfb7c Mon Sep 17 00:00:00 2001 From: gary-huang Date: Wed, 12 Nov 2025 15:54:26 -0500 Subject: [PATCH 3/3] dont need asserts in then --- .../llmobs/domain/DDLLMObsSpanTest.groovy | 228 +++++++++--------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy b/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy index e0997984c64..7595b51e82a 100644 --- a/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy +++ b/dd-java-agent/agent-llmobs/src/test/groovy/datadog/trace/llmobs/domain/DDLLMObsSpanTest.groovy @@ -78,59 +78,59 @@ class DDLLMObsSpanTest extends DDSpecification{ then: def innerSpan = (AgentSpan)test.span - assert Tags.LLMOBS_WORKFLOW_SPAN_KIND.equals(innerSpan.getTag(LLMOBS_TAG_PREFIX + "span.kind")) + Tags.LLMOBS_WORKFLOW_SPAN_KIND.equals(innerSpan.getTag(LLMOBS_TAG_PREFIX + "span.kind")) - assert null == innerSpan.getTag("input") - assert input.equals(innerSpan.getTag(INPUT)) - assert null == innerSpan.getTag("output") - assert output.equals(innerSpan.getTag(OUTPUT)) + null == innerSpan.getTag("input") + input.equals(innerSpan.getTag(INPUT)) + null == innerSpan.getTag("output") + output.equals(innerSpan.getTag(OUTPUT)) - assert null == innerSpan.getTag("metadata") + null == innerSpan.getTag("metadata") def expectedMetadata = Maps.of("sport", "baseball", "price_data", Maps.of("gpt4", 100)) - assert expectedMetadata.equals(innerSpan.getTag(METADATA)) + expectedMetadata.equals(innerSpan.getTag(METADATA)) - assert null == innerSpan.getTag("rank") + null == innerSpan.getTag("rank") def rankMetric = innerSpan.getTag(LLMOBS_METRIC_PREFIX + "rank") - assert rankMetric instanceof Number && 1 == (int)rankMetric + rankMetric instanceof Number && 1 == (int)rankMetric - assert null == innerSpan.getTag("likelihood") + null == innerSpan.getTag("likelihood") def likelihoodMetric = innerSpan.getTag(LLMOBS_METRIC_PREFIX + "likelihood") - assert likelihoodMetric instanceof Number - assert 0.1 == (double)likelihoodMetric + likelihoodMetric instanceof Number + 0.1 == (double)likelihoodMetric - assert null == innerSpan.getTag("DOMAIN") + null == innerSpan.getTag("DOMAIN") def domain = innerSpan.getTag(LLMOBS_TAG_PREFIX + "DOMAIN") - assert domain instanceof String - assert "north-america".equals((String)domain) + domain instanceof String + "north-america".equals((String)domain) - assert null == innerSpan.getTag("bulk1") + null == innerSpan.getTag("bulk1") def tagBulk1 = innerSpan.getTag(LLMOBS_TAG_PREFIX + "bulk1") - assert tagBulk1 instanceof Number - assert 1 == ((int)tagBulk1) + tagBulk1 instanceof Number + 1 == ((int)tagBulk1) - assert null == innerSpan.getTag("bulk2") + null == innerSpan.getTag("bulk2") def tagBulk2 = innerSpan.getTag(LLMOBS_TAG_PREFIX + "bulk2") - assert tagBulk2 instanceof String - assert "2".equals((String)tagBulk2) + tagBulk2 instanceof String + "2".equals((String)tagBulk2) - assert innerSpan.isError() - assert innerSpan.getTag(DDTags.ERROR_MSG) instanceof String - assert errMsg.equals(innerSpan.getTag(DDTags.ERROR_MSG)) + innerSpan.isError() + innerSpan.getTag(DDTags.ERROR_MSG) instanceof String + errMsg.equals(innerSpan.getTag(DDTags.ERROR_MSG)) - assert null == innerSpan.getTag("env") + null == innerSpan.getTag("env") def tagEnv = innerSpan.getTag(LLMOBS_TAG_PREFIX + "env") - assert tagEnv instanceof UTF8BytesString - assert "test-env" == tagEnv.toString() + tagEnv instanceof UTF8BytesString + "test-env" == tagEnv.toString() - assert null == innerSpan.getTag("service") + null == innerSpan.getTag("service") def tagSvc = innerSpan.getTag(LLMOBS_TAG_PREFIX + "service") - assert tagSvc instanceof UTF8BytesString - assert "test-svc" == tagSvc.toString() + tagSvc instanceof UTF8BytesString + "test-svc" == tagSvc.toString() - assert null == innerSpan.getTag("version") + null == innerSpan.getTag("version") def tagVersion = innerSpan.getTag(LLMOBS_TAG_PREFIX + "version") - assert tagVersion instanceof UTF8BytesString - assert "v1" == tagVersion.toString() + tagVersion instanceof UTF8BytesString + "v1" == tagVersion.toString() } def "test span with overwrites"() { @@ -170,52 +170,52 @@ class DDLLMObsSpanTest extends DDSpecification{ then: def innerSpan = (AgentSpan)test.span - assert Tags.LLMOBS_AGENT_SPAN_KIND.equals(innerSpan.getTag(LLMOBS_TAG_PREFIX + "span.kind")) + Tags.LLMOBS_AGENT_SPAN_KIND.equals(innerSpan.getTag(LLMOBS_TAG_PREFIX + "span.kind")) - assert null == innerSpan.getTag("input") - assert input.equals(innerSpan.getTag(INPUT)) - assert null == innerSpan.getTag("output") - assert expectedOutput.equals(innerSpan.getTag(OUTPUT)) + null == innerSpan.getTag("input") + input.equals(innerSpan.getTag(INPUT)) + null == innerSpan.getTag("output") + expectedOutput.equals(innerSpan.getTag(OUTPUT)) - assert null == innerSpan.getTag("metadata") + null == innerSpan.getTag("metadata") def expectedMetadata = Maps.of("sport", "hockey", "price_data", Maps.of("gpt4", 100), "temperature", 30) - assert expectedMetadata.equals(innerSpan.getTag(METADATA)) + expectedMetadata.equals(innerSpan.getTag(METADATA)) - assert null == innerSpan.getTag("rank") + null == innerSpan.getTag("rank") def rankMetric = innerSpan.getTag(LLMOBS_METRIC_PREFIX + "rank") - assert rankMetric instanceof Number && 10 == (int)rankMetric + rankMetric instanceof Number && 10 == (int)rankMetric - assert null == innerSpan.getTag("DOMAIN") + null == innerSpan.getTag("DOMAIN") def domain = innerSpan.getTag(LLMOBS_TAG_PREFIX + "DOMAIN") - assert domain instanceof String - assert "europe".equals((String)domain) + domain instanceof String + "europe".equals((String)domain) - assert null == innerSpan.getTag("bulk1") + null == innerSpan.getTag("bulk1") def tagBulk1 = innerSpan.getTag(LLMOBS_TAG_PREFIX + "bulk1") - assert tagBulk1 instanceof Number - assert 1 == ((int)tagBulk1) + tagBulk1 instanceof Number + 1 == ((int)tagBulk1) - assert !innerSpan.isError() - assert innerSpan.getTag(DDTags.ERROR_MSG) instanceof String - assert throwableMsg.equals(innerSpan.getTag(DDTags.ERROR_MSG)) - assert innerSpan.getTag(DDTags.ERROR_STACK) instanceof String - assert ((String)innerSpan.getTag(DDTags.ERROR_STACK)).contains(throwableMsg) + !innerSpan.isError() + innerSpan.getTag(DDTags.ERROR_MSG) instanceof String + throwableMsg.equals(innerSpan.getTag(DDTags.ERROR_MSG)) + innerSpan.getTag(DDTags.ERROR_STACK) instanceof String + ((String)innerSpan.getTag(DDTags.ERROR_STACK)).contains(throwableMsg) - assert null == innerSpan.getTag("env") + null == innerSpan.getTag("env") def tagEnv = innerSpan.getTag(LLMOBS_TAG_PREFIX + "env") - assert tagEnv instanceof UTF8BytesString - assert "test-env" == tagEnv.toString() + tagEnv instanceof UTF8BytesString + "test-env" == tagEnv.toString() - assert null == innerSpan.getTag("service") + null == innerSpan.getTag("service") def tagSvc = innerSpan.getTag(LLMOBS_TAG_PREFIX + "service") - assert tagSvc instanceof UTF8BytesString - assert "test-svc" == tagSvc.toString() + tagSvc instanceof UTF8BytesString + "test-svc" == tagSvc.toString() - assert null == innerSpan.getTag("version") + null == innerSpan.getTag("version") def tagVersion = innerSpan.getTag(LLMOBS_TAG_PREFIX + "version") - assert tagVersion instanceof UTF8BytesString - assert "v1" == tagVersion.toString() + tagVersion instanceof UTF8BytesString + "v1" == tagVersion.toString() } def "test llm span string input formatted to messages"() { @@ -230,43 +230,43 @@ class DDLLMObsSpanTest extends DDSpecification{ then: def innerSpan = (AgentSpan)test.span - assert Tags.LLMOBS_LLM_SPAN_KIND.equals(innerSpan.getTag(LLMOBS_TAG_PREFIX + "span.kind")) + Tags.LLMOBS_LLM_SPAN_KIND.equals(innerSpan.getTag(LLMOBS_TAG_PREFIX + "span.kind")) - assert null == innerSpan.getTag("input") + null == innerSpan.getTag("input") def spanInput = innerSpan.getTag(INPUT) - assert spanInput instanceof List - assert ((List)spanInput).size() == 1 - assert spanInput.get(0) instanceof LLMObs.LLMMessage + spanInput instanceof List + ((List)spanInput).size() == 1 + spanInput.get(0) instanceof LLMObs.LLMMessage def expectedInputMsg = LLMObs.LLMMessage.from("unknown", input) - assert expectedInputMsg.getContent().equals(input) - assert expectedInputMsg.getRole().equals("unknown") - assert expectedInputMsg.getToolCalls().equals(null) + expectedInputMsg.getContent().equals(input) + expectedInputMsg.getRole().equals("unknown") + expectedInputMsg.getToolCalls().equals(null) - assert null == innerSpan.getTag("output") + null == innerSpan.getTag("output") def spanOutput = innerSpan.getTag(OUTPUT) - assert spanOutput instanceof List - assert ((List)spanOutput).size() == 1 - assert spanOutput.get(0) instanceof LLMObs.LLMMessage + spanOutput instanceof List + ((List)spanOutput).size() == 1 + spanOutput.get(0) instanceof LLMObs.LLMMessage def expectedOutputMsg = LLMObs.LLMMessage.from("unknown", output) - assert expectedOutputMsg.getContent().equals(output) - assert expectedOutputMsg.getRole().equals("unknown") - assert expectedOutputMsg.getToolCalls().equals(null) + expectedOutputMsg.getContent().equals(output) + expectedOutputMsg.getRole().equals("unknown") + expectedOutputMsg.getToolCalls().equals(null) - assert null == innerSpan.getTag("env") + null == innerSpan.getTag("env") def tagEnv = innerSpan.getTag(LLMOBS_TAG_PREFIX + "env") - assert tagEnv instanceof UTF8BytesString - assert "test-env" == tagEnv.toString() + tagEnv instanceof UTF8BytesString + "test-env" == tagEnv.toString() - assert null == innerSpan.getTag("service") + null == innerSpan.getTag("service") def tagSvc = innerSpan.getTag(LLMOBS_TAG_PREFIX + "service") - assert tagSvc instanceof UTF8BytesString - assert "test-svc" == tagSvc.toString() + tagSvc instanceof UTF8BytesString + "test-svc" == tagSvc.toString() - assert null == innerSpan.getTag("version") + null == innerSpan.getTag("version") def tagVersion = innerSpan.getTag(LLMOBS_TAG_PREFIX + "version") - assert tagVersion instanceof UTF8BytesString - assert "v1" == tagVersion.toString() + tagVersion instanceof UTF8BytesString + "v1" == tagVersion.toString() } def "test llm span with messages"() { @@ -281,48 +281,48 @@ class DDLLMObsSpanTest extends DDSpecification{ then: def innerSpan = (AgentSpan)test.span - assert Tags.LLMOBS_LLM_SPAN_KIND.equals(innerSpan.getTag(LLMOBS_TAG_PREFIX + "span.kind")) + Tags.LLMOBS_LLM_SPAN_KIND.equals(innerSpan.getTag(LLMOBS_TAG_PREFIX + "span.kind")) - assert null == innerSpan.getTag("input") + null == innerSpan.getTag("input") def spanInput = innerSpan.getTag(INPUT) - assert spanInput instanceof List - assert ((List)spanInput).size() == 1 + spanInput instanceof List + ((List)spanInput).size() == 1 def spanInputMsg = spanInput.get(0) - assert spanInputMsg instanceof LLMObs.LLMMessage - assert spanInputMsg.getContent().equals(inputMsg.getContent()) - assert spanInputMsg.getRole().equals("user") - assert spanInputMsg.getToolCalls().equals(null) + spanInputMsg instanceof LLMObs.LLMMessage + spanInputMsg.getContent().equals(inputMsg.getContent()) + spanInputMsg.getRole().equals("user") + spanInputMsg.getToolCalls().equals(null) - assert null == innerSpan.getTag("output") + null == innerSpan.getTag("output") def spanOutput = innerSpan.getTag(OUTPUT) - assert spanOutput instanceof List - assert ((List)spanOutput).size() == 1 + spanOutput instanceof List + ((List)spanOutput).size() == 1 def spanOutputMsg = spanOutput.get(0) - assert spanOutputMsg instanceof LLMObs.LLMMessage - assert spanOutputMsg.getContent().equals(outputMsg.getContent()) - assert spanOutputMsg.getRole().equals("assistant") - assert spanOutputMsg.getToolCalls().size() == 1 + spanOutputMsg instanceof LLMObs.LLMMessage + spanOutputMsg.getContent().equals(outputMsg.getContent()) + spanOutputMsg.getRole().equals("assistant") + spanOutputMsg.getToolCalls().size() == 1 def toolCall = spanOutputMsg.getToolCalls().get(0) - assert toolCall.getName().equals("weather-tool") - assert toolCall.getType().equals("function") - assert toolCall.getToolId().equals("6176241000") + toolCall.getName().equals("weather-tool") + toolCall.getType().equals("function") + toolCall.getToolId().equals("6176241000") def expectedToolArgs = Maps.of("location", "paris") - assert toolCall.getArguments().equals(expectedToolArgs) + toolCall.getArguments().equals(expectedToolArgs) - assert null == innerSpan.getTag("env") + null == innerSpan.getTag("env") def tagEnv = innerSpan.getTag(LLMOBS_TAG_PREFIX + "env") - assert tagEnv instanceof UTF8BytesString - assert "test-env" == tagEnv.toString() + tagEnv instanceof UTF8BytesString + "test-env" == tagEnv.toString() - assert null == innerSpan.getTag("service") + null == innerSpan.getTag("service") def tagSvc = innerSpan.getTag(LLMOBS_TAG_PREFIX + "service") - assert tagSvc instanceof UTF8BytesString - assert "test-svc" == tagSvc.toString() + tagSvc instanceof UTF8BytesString + "test-svc" == tagSvc.toString() - assert null == innerSpan.getTag("version") + null == innerSpan.getTag("version") def tagVersion = innerSpan.getTag(LLMOBS_TAG_PREFIX + "version") - assert tagVersion instanceof UTF8BytesString - assert "v1" == tagVersion.toString() + tagVersion instanceof UTF8BytesString + "v1" == tagVersion.toString() } private LLMObsSpan givenALLMObsSpan(String kind, name){