mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-07 10:34:44 +00:00
fix(diagnostics-otel): keep full model id on spans instead of collapsing to "unknown" (#89981)
* fix(diagnostics-otel): keep full model id on spans (was collapsing to "unknown") * test(diagnostics-otel): cover slash model span attribution --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
@@ -2120,7 +2120,7 @@ describe("diagnostics-otel service", () => {
|
||||
sessionKey: "session-key",
|
||||
sessionId: "session-id",
|
||||
provider: "anthropic",
|
||||
model: "claude-sonnet-4.6",
|
||||
model: "anthropic/claude-sonnet-4.6",
|
||||
usage: {
|
||||
input: 100,
|
||||
output: 40,
|
||||
@@ -2136,7 +2136,9 @@ describe("diagnostics-otel service", () => {
|
||||
const modelUsageOptions = startedSpanOptions("openclaw.model.usage");
|
||||
expect(modelUsageOptions?.attributes?.["gen_ai.operation.name"]).toBe("chat");
|
||||
expect(modelUsageOptions?.attributes?.["gen_ai.system"]).toBe("anthropic");
|
||||
expect(modelUsageOptions?.attributes?.["gen_ai.request.model"]).toBe("claude-sonnet-4.6");
|
||||
expect(modelUsageOptions?.attributes?.["gen_ai.request.model"]).toBe(
|
||||
"anthropic/claude-sonnet-4.6",
|
||||
);
|
||||
expect(modelUsageOptions?.attributes?.["gen_ai.usage.input_tokens"]).toBe(150);
|
||||
expect(modelUsageOptions?.attributes?.["gen_ai.usage.output_tokens"]).toBe(40);
|
||||
expect(modelUsageOptions?.attributes?.["gen_ai.usage.cache_read.input_tokens"]).toBe(30);
|
||||
@@ -2163,8 +2165,8 @@ describe("diagnostics-otel service", () => {
|
||||
runId: "run-1",
|
||||
callId: "call-1",
|
||||
sessionKey: "session-key",
|
||||
provider: "openai",
|
||||
model: "gpt-5.4",
|
||||
provider: "anthropic",
|
||||
model: "anthropic/claude-sonnet-4.6",
|
||||
api: "openai-completions",
|
||||
durationMs: 250,
|
||||
});
|
||||
@@ -2193,8 +2195,8 @@ describe("diagnostics-otel service", () => {
|
||||
expect(genAiOperationDuration?.record).toHaveBeenCalledTimes(2);
|
||||
expect(genAiOperationDuration?.record).toHaveBeenCalledWith(0.25, {
|
||||
"gen_ai.operation.name": "text_completion",
|
||||
"gen_ai.provider.name": "openai",
|
||||
"gen_ai.request.model": "gpt-5.4",
|
||||
"gen_ai.provider.name": "anthropic",
|
||||
"gen_ai.request.model": "unknown",
|
||||
});
|
||||
expect(genAiOperationDuration?.record).toHaveBeenCalledWith(1.25, {
|
||||
"gen_ai.operation.name": "generate_content",
|
||||
|
||||
@@ -468,7 +468,12 @@ function assignGenAiSpanIdentityAttrs(
|
||||
attrs["gen_ai.system"] = lowCardinalityAttr(input.provider);
|
||||
}
|
||||
if (input.model) {
|
||||
attrs["gen_ai.request.model"] = lowCardinalityAttr(input.model);
|
||||
// Span attributes carry the full model id; only metric labels need bounded cardinality
|
||||
// (the gen_ai metrics below still use lowCardinalityAttr). The low-cardinality allowlist
|
||||
// regex rejects "/", so provider-qualified ids like "anthropic/claude-sonnet-4.6" collapse
|
||||
// to "unknown" on the SPAN — breaking model attribution in trace backends (e.g. Langfuse
|
||||
// reads gen_ai.request.model). Keep the redacted raw model on the span.
|
||||
attrs["gen_ai.request.model"] = redactSensitiveText(input.model.trim());
|
||||
}
|
||||
attrs["gen_ai.operation.name"] = genAiOperationName(input.api);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user