Skip to content

Commit 3cf1277

Browse files
committed
Fix tests for dashscope
Change-Id: Ie958a04905738463e0d913816251142c1cf03d06 Co-developed-by: Cursor <[email protected]>
1 parent 63bc3d6 commit 3cf1277

File tree

4 files changed

+111
-254
lines changed

4 files changed

+111
-254
lines changed

instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -502,23 +502,11 @@ def wrap_image_synthesis_async_call(
502502
# Execute the wrapped call (submit task)
503503
result = wrapped(*args, **kwargs)
504504

505-
# Extract task_id and update invocation
506-
task_id = None
507-
if result and hasattr(result, "output"):
508-
if hasattr(result.output, "get"):
509-
task_id = result.output.get("task_id")
510-
elif hasattr(result.output, "task_id"):
511-
task_id = getattr(result.output, "task_id", None)
512-
513-
if task_id:
514-
invocation.attributes["gen_ai.response.id"] = task_id
515-
invocation.attributes["dashscope.task_id"] = task_id
516-
517-
# Note: Span linking is not currently supported by ExtendedTelemetryHandler.
518-
# If span linking is needed in the future, it should be implemented in the handler.
519-
# For now, we skip storing span context for linking.
520-
521-
# Update invocation with async response data (task_id, task_status)
505+
# TODO: Implement span linking between async_call and wait spans.
506+
# This would allow wait() span to be linked to async_call() span for better trace visualization.
507+
# Consider using a task_id-based mapping to store span contexts across threads.
508+
509+
# Update invocation with async response data (request_id, task_id)
522510
_update_invocation_from_image_synthesis_async_response(
523511
invocation, result
524512
)
@@ -566,19 +554,19 @@ def wrap_image_synthesis_wait(wrapped, instance, args, kwargs, handler=None):
566554
# If cannot extract task_id, skip instrumentation
567555
return wrapped(*args, **kwargs)
568556

569-
# Note: Span linking is not currently supported by ExtendedTelemetryHandler.
570-
# If span linking is needed in the future, it should be implemented in the handler.
557+
# TODO: Implement span linking between async_call and wait spans.
558+
# This would allow wait() span to be linked to async_call() span for better trace visualization.
559+
# Consider using a task_id-based mapping to store span contexts across threads.
571560

572561
# Create invocation object (wait phase doesn't know model, use "unknown")
562+
# Use "wait generate_content" as operation_name to make span name clearer
573563
invocation = _create_invocation_from_image_synthesis({}, "unknown")
574-
invocation.operation_name = "generate_content"
564+
# TODO: Add semantic conventions for wait operations
565+
invocation.operation_name = "wait generate_content"
575566
invocation.attributes["gen_ai.request.async"] = True
576-
invocation.attributes["gen_ai.response.id"] = task_id
577-
invocation.attributes["dashscope.task_id"] = task_id
578-
invocation.attributes["dashscope.operation"] = "wait"
579-
580-
# Note: Span linking is not currently supported by ExtendedTelemetryHandler.
581-
# If span linking is needed in the future, it should be implemented in the handler.
567+
# Note: response_id will be set from response.output.task_id in _update_invocation_from_image_synthesis_response
568+
# We set task_id here as a fallback
569+
invocation.response_id = task_id
582570

583571
# Start LLM invocation (creates span)
584572
handler.start_llm(invocation)

instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py

Lines changed: 41 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
ToolCall,
2727
ToolCallResponse,
2828
ToolDefinition,
29+
Uri,
2930
)
3031

3132

@@ -738,29 +739,6 @@ def _create_invocation_from_image_synthesis(
738739
InputMessage(role="user", parts=parts)
739740
]
740741

741-
# Extract negative_prompt (as attribute)
742-
negative_prompt = kwargs.get("negative_prompt")
743-
if negative_prompt:
744-
if isinstance(negative_prompt, str):
745-
invocation.attributes["dashscope.negative_prompt"] = (
746-
negative_prompt
747-
)
748-
749-
# Extract size (image dimensions)
750-
size = kwargs.get("size")
751-
if size:
752-
invocation.attributes["dashscope.image.size"] = size
753-
754-
# Extract n (number of images to generate)
755-
n = kwargs.get("n")
756-
if n is not None:
757-
invocation.attributes["dashscope.image.n"] = n
758-
759-
# Extract similarity parameter (if available)
760-
similarity = kwargs.get("similarity")
761-
if similarity is not None:
762-
invocation.attributes["dashscope.image.similarity"] = similarity
763-
764742
return invocation
765743

766744

@@ -790,16 +768,8 @@ def _update_invocation_from_image_synthesis_response(
790768
except (KeyError, AttributeError):
791769
pass
792770

793-
# Extract request ID (if available)
794-
# Note: For ImageSynthesis, request_id is the main identifier, not task_id
795-
try:
796-
request_id = getattr(response, "request_id", None)
797-
if request_id:
798-
invocation.response_id = request_id
799-
except (KeyError, AttributeError):
800-
pass
801-
802-
# Extract task_id and task_status from output
771+
# Extract task_id from output and set as response_id
772+
# Note: For ImageSynthesis, response_id should be task_id, not request_id
803773
try:
804774
output = getattr(response, "output", None)
805775
if output:
@@ -811,54 +781,56 @@ def _update_invocation_from_image_synthesis_response(
811781
task_id = getattr(output, "task_id", None)
812782

813783
if task_id:
814-
# Store task_id in attributes
815-
# Note: gen_ai.response.id should be request_id, not task_id
816-
# task_id is stored separately in dashscope.task_id
817-
invocation.attributes["dashscope.task_id"] = task_id
818-
# Don't set gen_ai.response.id to task_id, as it should be request_id
819-
# Only set response_id to task_id if request_id is not available
820-
if not invocation.response_id:
821-
invocation.response_id = task_id
822-
invocation.attributes["gen_ai.response.id"] = task_id
823-
824-
# Extract task_status
825-
task_status = None
826-
if hasattr(output, "get"):
827-
task_status = output.get("task_status")
828-
elif hasattr(output, "task_status"):
829-
task_status = getattr(output, "task_status", None)
830-
831-
if task_status:
832-
invocation.attributes["dashscope.task_status"] = (
833-
task_status
834-
)
784+
invocation.response_id = task_id
835785

836-
# Extract image URLs from results
837-
# TODO: If returned as files or binary data, handle accordingly
786+
# Extract image URLs from results and add as Uri MessageParts
838787
results = None
839788
if hasattr(output, "get"):
840789
results = output.get("results")
841790
elif hasattr(output, "results"):
842791
results = getattr(output, "results", None)
843792

844793
if results and isinstance(results, list):
845-
image_urls = []
794+
image_uris = []
846795
for result in results:
847796
if isinstance(result, dict):
848797
url = result.get("url")
849798
if url:
850-
image_urls.append(url)
799+
image_uris.append(
800+
Uri(
801+
uri=url,
802+
modality="image",
803+
mime_type=None,
804+
type="uri",
805+
)
806+
)
851807
elif hasattr(result, "url"):
852808
url = getattr(result, "url", None)
853809
if url:
854-
image_urls.append(url)
855-
if image_urls:
856-
# Store first image URL as attribute (or all if needed)
857-
invocation.attributes["dashscope.image.url"] = (
858-
image_urls[0]
859-
if len(image_urls) == 1
860-
else str(image_urls)
861-
)
810+
image_uris.append(
811+
Uri(
812+
uri=url,
813+
modality="image",
814+
mime_type=None,
815+
type="uri",
816+
)
817+
)
818+
if image_uris:
819+
# Add image URIs to output messages
820+
# If output_messages is empty, create a new one
821+
if not invocation.output_messages:
822+
invocation.output_messages = [
823+
OutputMessage(
824+
role="assistant",
825+
parts=image_uris,
826+
finish_reason="stop",
827+
)
828+
]
829+
else:
830+
# Append URIs to the last output message
831+
invocation.output_messages[-1].parts.extend(
832+
image_uris
833+
)
862834
except (KeyError, AttributeError):
863835
pass
864836
except (KeyError, AttributeError):
@@ -872,7 +844,7 @@ def _update_invocation_from_image_synthesis_async_response(
872844
"""Update LLMInvocation with ImageSynthesis async_call response data.
873845
874846
This is called when async_call() returns, before wait() is called.
875-
Only extracts task_id and task_status (usually PENDING).
847+
Extracts task_id and sets it as response_id.
876848
877849
Args:
878850
invocation: LLMInvocation to update
@@ -882,28 +854,16 @@ def _update_invocation_from_image_synthesis_async_response(
882854
return
883855

884856
try:
885-
# Extract task_id and task_status from output
857+
# Extract task_id from output and set as response_id
886858
output = getattr(response, "output", None)
887859
if output:
888-
# Extract task_id
889860
task_id = None
890861
if hasattr(output, "get"):
891862
task_id = output.get("task_id")
892863
elif hasattr(output, "task_id"):
893864
task_id = getattr(output, "task_id", None)
894865

895866
if task_id:
896-
invocation.attributes["gen_ai.response.id"] = task_id
897-
invocation.attributes["dashscope.task_id"] = task_id
898-
899-
# Extract task_status (usually PENDING for async_call)
900-
task_status = None
901-
if hasattr(output, "get"):
902-
task_status = output.get("task_status")
903-
elif hasattr(output, "task_status"):
904-
task_status = getattr(output, "task_status", None)
905-
906-
if task_status:
907-
invocation.attributes["dashscope.task_status"] = task_status
867+
invocation.response_id = task_id
908868
except (KeyError, AttributeError):
909869
pass

0 commit comments

Comments
 (0)