1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15+ import asyncio
1516import functools
1617import logging
1718import os
1819import time
19- from typing import AsyncIterator , Awaitable , Iterator , Optional , Union
20+ from typing import Any , AsyncIterator , Awaitable , Iterator , Optional , Union
2021
2122from google .genai .models import AsyncModels , Models
2223from google .genai .types import (
2930
3031from opentelemetry import trace
3132from opentelemetry .semconv ._incubating .attributes import gen_ai_attributes
33+ from opentelemetry .semconv ._incubating .attributes import code_attributes
3234from opentelemetry .semconv .attributes import error_attributes
3335
3436from .flags import is_content_recording_enabled
@@ -120,11 +122,11 @@ def _determine_genai_system(models_object: Union[Models, AsyncModels]):
120122
121123def _get_config_property (
122124 config : Optional [GenerateContentConfigOrDict ],
123- path : str ):
125+ path : str ) -> Any :
124126 if config is None :
125127 return None
126128 path_segments = path .split ("." )
127- current_context = config
129+ current_context : Any = config
128130 for path_segment in path_segments :
129131 if current_context is None :
130132 return None
@@ -186,11 +188,12 @@ def __init__(
186188 self ._output_tokens = 0
187189 self ._content_recording_enabled = is_content_recording_enabled ()
188190
189- def start_span_as_current_span (self , name ):
191+ def start_span_as_current_span (self , model_name , function_name ):
190192 return self ._otel_wrapper .start_as_current_span (
191- name ,
193+ f'generate_content [ { model_name } ]' ,
192194 start_time = self ._start_time ,
193195 attributes = {
196+ code_attributes .CODE_FUNCTION_NAME : function_name ,
194197 gen_ai_attributes .GEN_AI_SYSTEM : self ._genai_system ,
195198 gen_ai_attributes .GEN_AI_REQUEST_MODEL : self ._genai_request_model ,
196199 gen_ai_attributes .GEN_AI_OPERATION_NAME : "GenerateContent" ,
@@ -230,9 +233,9 @@ def finalize_processing(self):
230233 def _maybe_update_token_counts (self , response : GenerateContentResponse ):
231234 input_tokens = _get_response_property (response , "usage_metadata.prompt_token_count" )
232235 output_tokens = _get_response_property (response , "usage_metadata.candidates_token_count" )
233- if input_tokens :
236+ if input_tokens and isinstance ( input_tokens , int ) :
234237 self ._input_tokens += input_tokens
235- if output_tokens :
238+ if output_tokens and isinstance ( output_tokens , int ) :
236239 self ._output_tokens += output_tokens
237240
238241 def _maybe_update_error_type (self , response : GenerateContentResponse ):
@@ -331,7 +334,7 @@ def instrumented_generate_content(
331334 contents : Union [ContentListUnion , ContentListUnionDict ],
332335 config : Optional [GenerateContentConfigOrDict ] = None ) -> GenerateContentResponse :
333336 helper = _GenerateContentInstrumentationHelper (self , otel_wrapper , model )
334- with helper .start_span_as_current_span ("google.genai.Models.generate_content" ):
337+ with helper .start_span_as_current_span (model , "google.genai.Models.generate_content" ):
335338 helper .process_request (contents , config )
336339 try :
337340 response = wrapped_func (self , model = model , contents = contents , config = config )
@@ -360,7 +363,7 @@ def instrumented_generate_content_stream(
360363 contents : Union [ContentListUnion , ContentListUnionDict ],
361364 config : Optional [GenerateContentConfigOrDict ] = None ) -> Iterator [GenerateContentResponse ]:
362365 helper = _GenerateContentInstrumentationHelper (self , otel_wrapper , model )
363- with helper .start_span_as_current_span ("google.genai.Models.generate_content_stream" ):
366+ with helper .start_span_as_current_span (model , "google.genai.Models.generate_content_stream" ):
364367 helper .process_request (contents , config )
365368 try :
366369 for response in wrapped_func (self , model = model , contents = contents , config = config ):
@@ -389,7 +392,7 @@ async def instrumented_generate_content(
389392 contents : Union [ContentListUnion , ContentListUnionDict ],
390393 config : Optional [GenerateContentConfigOrDict ] = None ) -> GenerateContentResponse :
391394 helper = _GenerateContentInstrumentationHelper (self , otel_wrapper , model )
392- with helper .start_span_as_current_span ("google.genai.AsyncModels.generate_content" ):
395+ with helper .start_span_as_current_span (model , "google.genai.AsyncModels.generate_content" ):
393396 helper .process_request (contents , config )
394397 try :
395398 response = await wrapped_func (self , model = model , contents = contents , config = config )
@@ -403,7 +406,8 @@ async def instrumented_generate_content(
403406 return instrumented_generate_content
404407
405408
406- def _create_instrumented_async_generate_content_stream (
409+ # Disabling type checking because this is not yet implemented and tested fully.
410+ def _create_instrumented_async_generate_content_stream ( # pyright: ignore
407411 snapshot : _MethodsSnapshot ,
408412 otel_wrapper : OTelWrapper ):
409413 wrapped_func = snapshot .async_generate_content_stream
@@ -416,14 +420,14 @@ async def instrumented_generate_content_stream(
416420 * ,
417421 model : str ,
418422 contents : Union [ContentListUnion , ContentListUnionDict ],
419- config : Optional [GenerateContentConfigOrDict ] = None ) -> Awaitable [AsyncIterator [GenerateContentResponse ]]:
423+ config : Optional [GenerateContentConfigOrDict ] = None ) -> Awaitable [AsyncIterator [GenerateContentResponse ]]: # pyright: ignore
420424 helper = _GenerateContentInstrumentationHelper (self , otel_wrapper , model )
421- with helper .start_span_as_current_span ("google.genai.AsyncModels.generate_content_stream" ):
425+ with helper .start_span_as_current_span (model , "google.genai.AsyncModels.generate_content_stream" ):
422426 helper .process_request (contents , config )
423427 try :
424- async for response in wrapped_func (self , model = model , contents = contents , config = config ):
428+ async for response in await wrapped_func (self , model = model , contents = contents , config = config ): # pyright: ignore
425429 helper .process_response (response )
426- yield response
430+ yield response # pyright: ignore
427431 except Exception as error :
428432 helper .process_error (error )
429433 raise
0 commit comments