Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f839c29
feat(gemini): migrate vertexai and google-generativeai to OTel GenAI …
avivhalfon Mar 22, 2026
c13d0e2
fix(google-generativeai): remove unused SpanAttributes import
avivhalfon Mar 23, 2026
a61054f
fix
OzBenSimhonTraceloop Mar 29, 2026
22c8e67
merge origin/main into ah/gemini-sem-conv
OzBenSimhonTraceloop Mar 29, 2026
8683440
last-fix
OzBenSimhonTraceloop Mar 29, 2026
3c24e3c
coderabbit
OzBenSimhonTraceloop Mar 29, 2026
8548ce2
Merge branch 'main' of github.com:traceloop/openllmetry into ah/gemin…
OzBenSimhonTraceloop Mar 30, 2026
3d67642
fix(google-generativeai, vertexai): OTel semconv compliance fixes
OzBenSimhonTraceloop Mar 30, 2026
0f352b3
revert: remove event emitter changes (pre-existing, not in branch scope)
OzBenSimhonTraceloop Mar 30, 2026
f58b77d
fix: revert BlobPart field name — OTel spec uses "content", not "data"
OzBenSimhonTraceloop Mar 30, 2026
e99a6eb
Merge branch 'main' of github.com:traceloop/openllmetry into ah/gemin…
OzBenSimhonTraceloop Mar 30, 2026
4a21396
wip
OzBenSimhonTraceloop Mar 31, 2026
ce00bb5
cleanup
OzBenSimhonTraceloop Mar 31, 2026
2a6da1a
more-test
OzBenSimhonTraceloop Mar 31, 2026
7d013af
empty
OzBenSimhonTraceloop Mar 31, 2026
63aa0a2
fix
OzBenSimhonTraceloop Mar 31, 2026
07d03cc
revert: remove vertex ai semconv changes from branch
OzBenSimhonTraceloop Apr 5, 2026
501e3b6
fix
OzBenSimhonTraceloop Apr 5, 2026
13ee5e9
gemini-sample-app-model
OzBenSimhonTraceloop Apr 6, 2026
2d7cd0b
dead-code
OzBenSimhonTraceloop Apr 6, 2026
723b8e6
Revert "dead-code"
OzBenSimhonTraceloop Apr 6, 2026
e809593
fix-async
OzBenSimhonTraceloop Apr 6, 2026
4b04b86
wip
OzBenSimhonTraceloop Apr 6, 2026
5106246
lint
OzBenSimhonTraceloop Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
)
from opentelemetry.semconv_ai import (
SUPPRESS_LANGUAGE_MODEL_INSTRUMENTATION_KEY,
LLMRequestTypeValues,
SpanAttributes,
Meters
)
Expand Down Expand Up @@ -205,8 +204,8 @@ async def _awrap(
name,
kind=SpanKind.CLIENT,
attributes={
GenAIAttributes.GEN_AI_SYSTEM: "Google",
SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.COMPLETION.value,
GenAIAttributes.GEN_AI_PROVIDER_NAME: "gcp.gen_ai",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cant you import from GenAiSystemValues.<gcp>.value?

GenAIAttributes.GEN_AI_OPERATION_NAME: "chat",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use GenAiOperationNameValues.TEXT_COMPLETION.value instead of hardcoded value, and why change to chat form completion? a mistake from the beginning?

},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
)
start_time = time.perf_counter()
Expand All @@ -224,7 +223,7 @@ async def _awrap(
duration_histogram.record(
duration,
attributes={
GenAIAttributes.GEN_AI_PROVIDER_NAME: "Google",
GenAIAttributes.GEN_AI_PROVIDER_NAME: "gcp.gen_ai",
GenAIAttributes.GEN_AI_RESPONSE_MODEL: llm_model,
},
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Expand Down Expand Up @@ -281,8 +280,8 @@ def _wrap(
name,
kind=SpanKind.CLIENT,
attributes={
GenAIAttributes.GEN_AI_SYSTEM: "Google",
SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.COMPLETION.value,
GenAIAttributes.GEN_AI_PROVIDER_NAME: "gcp.gen_ai",
GenAIAttributes.GEN_AI_OPERATION_NAME: "chat",
},
)

Expand All @@ -301,7 +300,7 @@ def _wrap(
duration_histogram.record(
duration,
attributes={
GenAIAttributes.GEN_AI_PROVIDER_NAME: "Google",
GenAIAttributes.GEN_AI_PROVIDER_NAME: "gcp.gen_ai",
GenAIAttributes.GEN_AI_RESPONSE_MODEL: llm_model,
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Roles(Enum):
VALID_MESSAGE_ROLES = {role.value for role in Roles}
"""The valid roles for naming the message event."""

EVENT_ATTRIBUTES = {GenAIAttributes.GEN_AI_SYSTEM: "gemini"}
EVENT_ATTRIBUTES = {GenAIAttributes.GEN_AI_PROVIDER_NAME: "gcp.gen_ai"}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
"""The attributes to be used for the event."""


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

logger = logging.getLogger(__name__)

GEN_AI_INPUT_MESSAGES = "gen_ai.input.messages"
GEN_AI_OUTPUT_MESSAGES = "gen_ai.output.messages"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import from
GenAIAttributes.GEN_AI_INPUT_MESSAGES



def _set_span_attribute(span, name, value):
if value is not None:
Expand Down Expand Up @@ -160,20 +163,6 @@ async def _process_content_part(part, span, part_index):
return {"type": "text", "text": str(part)}


def _set_prompt_attributes(span, prompt_index, processed_content, content_item):
"""Set span attributes for a processed prompt"""
_set_span_attribute(
span,
f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.content",
json.dumps(processed_content),
)
_set_span_attribute(
span,
f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.role",
getattr(content_item, "role", "user"),
)


async def _process_argument(argument, span):
"""Process a single argument from args list"""
processed_content = []
Expand Down Expand Up @@ -213,49 +202,36 @@ async def set_input_attributes(span, args, kwargs, llm_model):
if not should_send_prompts():
return

messages = []

if "contents" in kwargs:
contents = kwargs["contents"]
if isinstance(contents, str):
# Simple string content in OpenAI format
_set_span_attribute(
span,
f"{GenAIAttributes.GEN_AI_PROMPT}.0.content",
contents,
)
_set_span_attribute(
span,
f"{GenAIAttributes.GEN_AI_PROMPT}.0.role",
"user",
)
messages.append({"role": "user", "content": contents})
Comment thread
avivhalfon marked this conversation as resolved.
Outdated
elif isinstance(contents, list):
for prompt_index, content_item in enumerate(contents):
for content_item in contents:
processed_content = await _process_content_item(content_item, span)

if processed_content:
_set_prompt_attributes(span, prompt_index, processed_content, content_item)

messages.append({
"role": getattr(content_item, "role", "user"),
"content": json.dumps(processed_content),
})
elif args and len(args) > 0:
# Handle args - process each argument
for arg_index, argument in enumerate(args):
for argument in args:
processed_content = await _process_argument(argument, span)

if processed_content:
_set_span_attribute(
span,
f"{SpanAttributes.LLM_PROMPTS}.{arg_index}.content",
json.dumps(processed_content),
)
_set_span_attribute(
span,
f"{SpanAttributes.LLM_PROMPTS}.{arg_index}.role",
"user",
)
messages.append({
"role": "user",
"content": json.dumps(processed_content),
})
elif "prompt" in kwargs:
_set_span_attribute(
span, f"{SpanAttributes.LLM_PROMPTS}.0.content",
json.dumps([{"type": "text", "text": kwargs["prompt"]}])
)
_set_span_attribute(span, f"{SpanAttributes.LLM_PROMPTS}.0.role", "user")
messages.append({
"role": "user",
"content": json.dumps([{"type": "text", "text": kwargs["prompt"]}]),
})

if messages:
_set_span_attribute(span, GEN_AI_INPUT_MESSAGES, json.dumps(messages))

Comment thread
avivhalfon marked this conversation as resolved.

# Keep sync version for backward compatibility
Expand All @@ -268,27 +244,20 @@ def set_input_attributes_sync(span, args, kwargs, llm_model):
if not should_send_prompts():
return

messages = []

if "contents" in kwargs:
contents = kwargs["contents"]
if isinstance(contents, str):
# Simple string content in OpenAI format
_set_span_attribute(
span,
f"{GenAIAttributes.GEN_AI_PROMPT}.0.content",
json.dumps([{"type": "text", "text": contents}]),
)
_set_span_attribute(
span,
f"{GenAIAttributes.GEN_AI_PROMPT}.0.role",
"user",
)
messages.append({
"role": "user",
"content": json.dumps([{"type": "text", "text": contents}]),
})
elif isinstance(contents, list):
# Process content list - could be mixed text and Part objects
for i, content in enumerate(contents):
for content in contents:
processed_content = []

if hasattr(content, "parts"):
# Content with parts (Google GenAI Content object)
for j, part in enumerate(content.parts):
if hasattr(part, "text") and part.text:
processed_content.append({"type": "text", "text": part.text})
Expand All @@ -299,36 +268,25 @@ def set_input_attributes_sync(span, args, kwargs, llm_model):
if processed_image is not None:
processed_content.append(processed_image)
else:
# Other part types
processed_content.append({"type": "text", "text": str(part)})
elif isinstance(content, str):
# Direct string in the list
processed_content.append({"type": "text", "text": content})
elif _is_image_part(content):
# Direct Part object that's an image
processed_image = _process_image_part_sync(
content, span.context.trace_id, span.context.span_id, 0
)
if processed_image is not None:
processed_content.append(processed_image)
else:
# Other content types
processed_content.append({"type": "text", "text": str(content)})

if processed_content:
_set_span_attribute(
span,
f"{SpanAttributes.LLM_PROMPTS}.{i}.content",
json.dumps(processed_content),
)
_set_span_attribute(
span,
f"{SpanAttributes.LLM_PROMPTS}.{i}.role",
getattr(content, "role", "user"),
)
messages.append({
"role": getattr(content, "role", "user"),
"content": json.dumps(processed_content),
})
elif args and len(args) > 0:
# Handle args - process each argument
for i, arg in enumerate(args):
for arg in args:
processed_content = []

if isinstance(arg, str):
Expand All @@ -355,22 +313,18 @@ def set_input_attributes_sync(span, args, kwargs, llm_model):
processed_content.append({"type": "text", "text": str(arg)})

if processed_content:
_set_span_attribute(
span,
f"{SpanAttributes.LLM_PROMPTS}.{i}.content",
json.dumps(processed_content),
)
_set_span_attribute(
span,
f"{SpanAttributes.LLM_PROMPTS}.{i}.role",
"user",
)
messages.append({
"role": "user",
"content": json.dumps(processed_content),
})
elif "prompt" in kwargs:
_set_span_attribute(
span, f"{GenAIAttributes.GEN_AI_PROMPT}.0.content",
json.dumps([{"type": "text", "text": kwargs["prompt"]}])
)
_set_span_attribute(span, f"{GenAIAttributes.GEN_AI_PROMPT}.0.role", "user")
messages.append({
"role": "user",
"content": json.dumps([{"type": "text", "text": kwargs["prompt"]}]),
})

if messages:
_set_span_attribute(span, GEN_AI_INPUT_MESSAGES, json.dumps(messages))


def set_model_request_attributes(span, kwargs, llm_model):
Expand All @@ -386,18 +340,18 @@ def set_model_request_attributes(span, kwargs, llm_model):
_set_span_attribute(span, GenAIAttributes.GEN_AI_REQUEST_TOP_P, kwargs.get("top_p"))
_set_span_attribute(span, GenAIAttributes.GEN_AI_REQUEST_TOP_K, kwargs.get("top_k"))
_set_span_attribute(
span, SpanAttributes.LLM_PRESENCE_PENALTY, kwargs.get("presence_penalty")
span, GenAIAttributes.GEN_AI_REQUEST_PRESENCE_PENALTY, kwargs.get("presence_penalty")
)
_set_span_attribute(
span, SpanAttributes.LLM_FREQUENCY_PENALTY, kwargs.get("frequency_penalty")
span, GenAIAttributes.GEN_AI_REQUEST_FREQUENCY_PENALTY, kwargs.get("frequency_penalty")
)

generation_config = kwargs.get("generation_config")
if generation_config and hasattr(generation_config, "response_schema"):
try:
_set_span_attribute(
span,
SpanAttributes.LLM_REQUEST_STRUCTURED_OUTPUT_SCHEMA,
SpanAttributes.GEN_AI_REQUEST_STRUCTURED_OUTPUT_SCHEMA,
json.dumps(generation_config.response_schema),
)
except Exception:
Expand All @@ -407,7 +361,7 @@ def set_model_request_attributes(span, kwargs, llm_model):
try:
_set_span_attribute(
span,
SpanAttributes.LLM_REQUEST_STRUCTURED_OUTPUT_SCHEMA,
SpanAttributes.GEN_AI_REQUEST_STRUCTURED_OUTPUT_SCHEMA,
json.dumps(kwargs.get("response_schema")),
)
except Exception:
Expand All @@ -418,32 +372,24 @@ def set_model_request_attributes(span, kwargs, llm_model):
def set_response_attributes(span, response, llm_model):
if not should_send_prompts():
return

messages = []

if hasattr(response, "usage_metadata"):
if isinstance(response.text, list):
for index, item in enumerate(response):
prefix = f"{GenAIAttributes.GEN_AI_COMPLETION}.{index}"
_set_span_attribute(span, f"{prefix}.content", item.text)
_set_span_attribute(span, f"{prefix}.role", "assistant")
for item in response:
messages.append({"role": "assistant", "content": item.text})
elif isinstance(response.text, str):
_set_span_attribute(
span, f"{GenAIAttributes.GEN_AI_COMPLETION}.0.content", response.text
)
_set_span_attribute(
span, f"{GenAIAttributes.GEN_AI_COMPLETION}.0.role", "assistant"
)
messages.append({"role": "assistant", "content": response.text})
else:
if isinstance(response, list):
for index, item in enumerate(response):
prefix = f"{GenAIAttributes.GEN_AI_COMPLETION}.{index}"
_set_span_attribute(span, f"{prefix}.content", item)
_set_span_attribute(span, f"{prefix}.role", "assistant")
for item in response:
messages.append({"role": "assistant", "content": item})
elif isinstance(response, str):
_set_span_attribute(
span, f"{GenAIAttributes.GEN_AI_COMPLETION}.0.content", response
)
_set_span_attribute(
span, f"{GenAIAttributes.GEN_AI_COMPLETION}.0.role", "assistant"
)
messages.append({"role": "assistant", "content": response})

if messages:
_set_span_attribute(span, GEN_AI_OUTPUT_MESSAGES, json.dumps(messages))


def set_model_response_attributes(span, response, llm_model, token_histogram):
Expand All @@ -455,7 +401,7 @@ def set_model_response_attributes(span, response, llm_model, token_histogram):
if hasattr(response, "usage_metadata"):
_set_span_attribute(
span,
SpanAttributes.LLM_USAGE_TOTAL_TOKENS,
SpanAttributes.GEN_AI_USAGE_TOTAL_TOKENS,
response.usage_metadata.total_token_count,
)
_set_span_attribute(
Expand All @@ -473,18 +419,18 @@ def set_model_response_attributes(span, response, llm_model, token_histogram):
token_histogram.record(
response.usage_metadata.prompt_token_count,
attributes={
GenAIAttributes.GEN_AI_PROVIDER_NAME: "Google",
GenAIAttributes.GEN_AI_PROVIDER_NAME: "gcp.gen_ai",
GenAIAttributes.GEN_AI_TOKEN_TYPE: "input",
GenAIAttributes.GEN_AI_RESPONSE_MODEL: llm_model,
}
)
token_histogram.record(
response.usage_metadata.candidates_token_count,
attributes={
GenAIAttributes.GEN_AI_PROVIDER_NAME: "Google",
GenAIAttributes.GEN_AI_TOKEN_TYPE: "output",
GenAIAttributes.GEN_AI_RESPONSE_MODEL: llm_model,
},
)
response.usage_metadata.candidates_token_count,
attributes={
GenAIAttributes.GEN_AI_PROVIDER_NAME: "gcp.gen_ai",
GenAIAttributes.GEN_AI_TOKEN_TYPE: "output",
GenAIAttributes.GEN_AI_RESPONSE_MODEL: llm_model,
},
)
Comment on lines +745 to +765

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if there are any existing None guards for usage_metadata fields in the codebase
rg -n "prompt_token_count|candidates_token_count" --type=py -C2

Repository: traceloop/openllmetry

Length of output: 16250


🏁 Script executed:

# Find the import statement and type definitions for usage_metadata
rg -n "usage_metadata|UsageMetadata" packages/opentelemetry-instrumentation-google-generativeai/ --type=py -A2 -B2 | head -50

Repository: traceloop/openllmetry

Length of output: 813


🏁 Script executed:

# Check the type of um (usage_metadata) in the span_utils file context
rg -n "def.*um" packages/opentelemetry-instrumentation-google-generativeai/opentelemetry/instrumentation/google_generativeai/span_utils.py | head -20

Repository: traceloop/openllmetry

Length of output: 206


🏁 Script executed:

# Look at the function signature around line 641 to understand um type
sed -n '600,660p' packages/opentelemetry-instrumentation-google-generativeai/opentelemetry/instrumentation/google_generativeai/span_utils.py

Repository: traceloop/openllmetry

Length of output: 1977


🏁 Script executed:

# Check if there are any tests covering the histogram recording with None values
find packages/opentelemetry-instrumentation-google-generativeai/tests -name "*.py" -type f -exec grep -l "token_histogram\|prompt_token_count" {} \;

Repository: traceloop/openllmetry

Length of output: 47


🏁 Script executed:

# Check imports and type hints in the span_utils file
head -50 packages/opentelemetry-instrumentation-google-generativeai/opentelemetry/instrumentation/google_generativeai/span_utils.py | grep -E "^import|^from|typing"

Repository: traceloop/openllmetry

Length of output: 439


🏁 Script executed:

# Check histogram.record method - find its implementation
rg -n "histogram.record\|class.*Histogram" packages/opentelemetry-instrumentation-google-generativeai/ --type=py -B3 -A3

Repository: traceloop/openllmetry

Length of output: 47


🏁 Script executed:

# Check if google-generativeai is specified and what version
find packages/opentelemetry-instrumentation-google-generativeai -name "pyproject.toml" -o -name "setup.py" -o -name "requirements*.txt" | xargs cat 2>/dev/null | grep -A5 -B5 "google-generativeai"

Repository: traceloop/openllmetry

Length of output: 712


🏁 Script executed:

# Search the broader codebase for how histogram.record is used elsewhere and if None values are ever passed
rg -n "histogram\.record" --type=py -B5 -A2

Repository: traceloop/openllmetry

Length of output: 50377


🏁 Script executed:

# Search for type information about usage_metadata in the codebase
rg -n "from google" packages/opentelemetry-instrumentation-google-generativeai/ --type=py | head -20

Repository: traceloop/openllmetry

Length of output: 684


🏁 Script executed:

# Check if there are any error handling or try-catch blocks around histogram recording in google-generativeai
sed -n '630,670p' packages/opentelemetry-instrumentation-google-generativeai/opentelemetry/instrumentation/google_generativeai/span_utils.py | cat -n

Repository: traceloop/openllmetry

Length of output: 1286


🏁 Script executed:

# Check if there are any test failures or comments about None values in the tests
find packages/opentelemetry-instrumentation-google-generativeai/tests -type f -name "*.py" -exec cat {} \; | grep -i "none\|null\|token" | head -30

Repository: traceloop/openllmetry

Length of output: 959


🏁 Script executed:

# Check if google-genai is a stub or if we can find type hints for UsageMetadata
find . -name "*.pyi" -o -name "py.typed" | xargs grep -l "prompt_token_count" 2>/dev/null || echo "No type stubs found"

Repository: traceloop/openllmetry

Length of output: 84


🏁 Script executed:

# Look for the actual function that calls set_model_response_attributes to understand response handling
rg -n "set_model_response_attributes" packages/opentelemetry-instrumentation-google-generativeai/ --type=py -B5 -A2

Repository: traceloop/openllmetry

Length of output: 6377


🌐 Web query:

google-genai GenerateContentResponse usage_metadata prompt_token_count type

💡 Result:

In the Google GenAI SDK (google-genai Python package), GenerateContentResponse has an attribute usage_metadata which provides token usage details from the Gemini API response. prompt_token_count is an integer field within usage_metadata representing the number of tokens in the input prompt. Access it as: response.usage_metadata.prompt_token_count This is an optional field (may be None if not present), of type int when available. Example usage: from google import genai client = genai.Client response = client.models.generate_content(model='gemini-2.5-flash', contents='Your prompt here') if response.usage_metadata: print(response.usage_metadata.prompt_token_count) usage_metadata type is a Pydantic model (from google.genai.types) with fields like: - prompt_token_count: int (input tokens) - candidates_token_count: int (output tokens) - total_token_count: int - thoughts_token_count: int (for thinking models) - cached_content_token_count: int (if using caching) Confirmed in official Gemini API docs and SDK references. Vertex AI REST API equivalent is UsageMetadata with promptTokenCount (camelCase).

Citations:


Add None checks before recording token counts to histogram.

The fields um.prompt_token_count and um.candidates_token_count are optional and may be None. Passing None to histogram.record() could cause runtime errors. Other instrumentation packages in this codebase (ollama, groq, writer) validate token values before recording; apply the same pattern here.

Suggested fix
    if token_histogram and um is not None:
+        if um.prompt_token_count is not None:
             token_histogram.record(
                 um.prompt_token_count,
                 attributes={
                     GenAIAttributes.GEN_AI_PROVIDER_NAME: _GCP_GEN_AI,
                     GenAIAttributes.GEN_AI_TOKEN_TYPE: "input",
                     GenAIAttributes.GEN_AI_RESPONSE_MODEL: llm_model,
                 },
             )
+        if um.candidates_token_count is not None:
             token_histogram.record(
                 um.candidates_token_count,
                 attributes={
                     GenAIAttributes.GEN_AI_PROVIDER_NAME: _GCP_GEN_AI,
                     GenAIAttributes.GEN_AI_TOKEN_TYPE: "output",
                     GenAIAttributes.GEN_AI_RESPONSE_MODEL: llm_model,
                 },
             )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/opentelemetry-instrumentation-google-generativeai/opentelemetry/instrumentation/google_generativeai/span_utils.py`
around lines 641 - 657, The token counts um.prompt_token_count and
um.candidates_token_count may be None, so before calling
token_histogram.record(...) (inside the token_histogram and um is not None
block) validate each value is not None and only record when present;
specifically, check um.prompt_token_count is not None before the input-token
record and check um.candidates_token_count is not None before the output-token
record, keeping the same attributes
(GenAIAttributes.GEN_AI_PROVIDER_NAME/_GCP_GEN_AI,
GenAIAttributes.GEN_AI_TOKEN_TYPE,
GenAIAttributes.GEN_AI_RESPONSE_MODEL/llm_model).


span.set_status(Status(StatusCode.OK))
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ requires-python = ">=3.10,<4"
dependencies = [
"opentelemetry-api>=1.38.0,<2",
"opentelemetry-instrumentation>=0.59b0",
"opentelemetry-semantic-conventions-ai>=0.4.13,<0.5.0",
"opentelemetry-semantic-conventions-ai>=0.5.0,<0.6.0",
"opentelemetry-semantic-conventions>=0.59b0",
]

Expand Down
Loading
Loading