From 0d7e72400a0ccf89400df266f9e9cc89649adcf8 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Fri, 14 Nov 2025 12:29:47 +0800 Subject: [PATCH 1/9] Init dashscope instrumentation framework Change-Id: I50679c243a8cad7f63618d095708237f1c0fb257 Co-developed-by: Cursor --- .../CHANGELOG.md | 18 + .../LICENSE | 201 ++ .../README.rst | 89 + .../examples/basic_example.py | 98 + .../pyproject.toml | 55 + .../src/loongsuite/__init__.py | 15 + .../loongsuite/instrumentation/__init__.py | 15 + .../instrumentation/dashscope/__init__.py | 154 + .../instrumentation/dashscope/package.py | 15 + .../instrumentation/dashscope/patch.py | 135 + .../instrumentation/dashscope/version.py | 15 + .../test_aio_generation_call_basic.yaml | 72 + .../test_aio_generation_call_streaming.yaml | 94 + .../cassettes/test_generation_call_basic.yaml | 81 + .../test_generation_call_streaming.yaml | 103 + .../test_generation_call_with_messages.yaml | 86 + .../test_generation_call_with_parameters.yaml | 85 + .../cassettes/test_text_embedding_basic.yaml | 1618 +++++++++ .../cassettes/test_text_embedding_batch.yaml | 3160 +++++++++++++++++ .../test_text_embedding_with_text_type.yaml | 1620 +++++++++ .../cassettes/test_text_rerank_basic.yaml | 92 + .../test_text_rerank_return_documents.yaml | 95 + .../test_text_rerank_with_top_n.yaml | 91 + .../tests/conftest.py | 132 + .../tests/requirements.latest.txt | 47 + .../tests/requirements.oldest.txt | 31 + .../tests/test_embedding.py | 44 + .../tests/test_generation.py | 93 + .../tests/test_rerank.py | 62 + tox-loongsuite.ini | 14 +- 30 files changed, 8429 insertions(+), 1 deletion(-) create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/LICENSE create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/examples/basic_example.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/pyproject.toml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/__init__.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/__init__.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/package.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/version.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_basic.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_streaming.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_basic.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_streaming.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_messages.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_parameters.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_basic.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_batch.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_with_text_type.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_basic.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_return_documents.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_with_top_n.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md new file mode 100644 index 000000000..a6eccaedd --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md @@ -0,0 +1,18 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [Unreleased] + +### Added + +- Initial implementation of DashScope instrumentation +- Support for Generation.call (sync) +- Support for AioGeneration.call (async) +- Support for TextEmbedding.call +- Support for Completions.create (OpenAI-compatible) +- Support for TextReRank.call +- Support for streaming responses (sync and async) + diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/LICENSE b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst new file mode 100644 index 000000000..439b8b673 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst @@ -0,0 +1,89 @@ +LoongSuite Instrumentation for DashScope +======================================== + +|pypi| + +.. |pypi| image:: https://badge.fury.io/py/loongsuite-instrumentation-dashscope.svg + :target: https://pypi.org/project/loongsuite-instrumentation-dashscope/ + +This library allows tracing calls to Alibaba Cloud DashScope APIs. + +Installation +------------ + +:: + + pip install loongsuite-instrumentation-dashscope + + +Usage +----- + +.. code-block:: python + + from opentelemetry import trace + from opentelemetry.sdk.trace import TracerProvider + from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor + + from loongsuite.instrumentation.dashscope import DashScopeInstrumentor + + # Initialize tracing + trace.set_tracer_provider(TracerProvider()) + trace.get_tracer_provider().add_span_processor( + SimpleSpanProcessor(ConsoleSpanExporter()) + ) + + # Instrument DashScope + DashScopeInstrumentor().instrument() + + # Now use DashScope as normal + from dashscope import Generation + + response = Generation.call( + model="qwen-turbo", + prompt="Hello!" + ) + + +Supported APIs +-------------- + +* **Text Generation** + + * ``Generation.call`` (sync) + * ``AioGeneration.call`` (async) + * Streaming support for both sync and async + +* **Chat Completion** + + * ``Completions.create`` (OpenAI-compatible, sync) + * Streaming support + +* **Text Embedding** + + * ``TextEmbedding.call`` + +* **Text Rerank** + + * ``TextReRank.call`` + + +Configuration +------------- + +API Key +~~~~~~~ + +Set your DashScope API key via environment variable: + +:: + + export DASHSCOPE_API_KEY="your-api-key-here" + + +References +---------- + +* `OpenTelemetry Project `_ +* `DashScope SDK `_ + diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/examples/basic_example.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/examples/basic_example.py new file mode 100644 index 000000000..fc5e8e8cb --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/examples/basic_example.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +""" +Basic example of using LoongSuite DashScope instrumentation. + +Before running this example: +1. Set your DashScope API key: + export DASHSCOPE_API_KEY="your-api-key-here" + +2. Install the package: + pip install loongsuite-instrumentation-dashscope +""" + +import os + +from loongsuite.instrumentation.dashscope import DashScopeInstrumentor + +from opentelemetry import trace +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import ( + ConsoleSpanExporter, + SimpleSpanProcessor, +) + + +def main(): + """Run the basic example.""" + # Check API key + if not os.getenv("DASHSCOPE_API_KEY"): + print("Error: DASHSCOPE_API_KEY environment variable not set") + print("Please set it with: export DASHSCOPE_API_KEY='your-api-key'") + return + + # Initialize OpenTelemetry tracing + trace.set_tracer_provider(TracerProvider()) + trace.get_tracer_provider().add_span_processor( + SimpleSpanProcessor(ConsoleSpanExporter()) + ) + + # Instrument DashScope + print("Instrumenting DashScope SDK...") + DashScopeInstrumentor().instrument() + + # Now use DashScope as normal + print("\n" + "=" * 60) + print("Example 1: Text Generation (non-streaming)") + print("=" * 60) + + from dashscope import Generation + + response = Generation.call( + model="qwen-turbo", + prompt="Hello! Please introduce yourself in one sentence.", + ) + + if response.status_code == 200: + print(f"Response: {response.output.text}") + else: + print(f"Error: {response.message}") + + # Example 2: Streaming + print("\n" + "=" * 60) + print("Example 2: Text Generation (streaming)") + print("=" * 60) + + responses = Generation.call( + model="qwen-turbo", prompt="Count from 1 to 5", stream=True + ) + + for response in responses: + if response.status_code == 200: + print(response.output.text, end="", flush=True) + print() + + # Example 3: Text Embedding + print("\n" + "=" * 60) + print("Example 3: Text Embedding") + print("=" * 60) + + from dashscope import TextEmbedding + + response = TextEmbedding.call( + model="text-embedding-v1", input="Hello, world!" + ) + + if response.status_code == 200: + embeddings = response.output.embeddings + print(f"Generated {len(embeddings)} embedding(s)") + print(f"Embedding dimension: {len(embeddings[0].embedding)}") + else: + print(f"Error: {response.message}") + + print("\n" + "=" * 60) + print("Examples completed!") + print("=" * 60) + + +if __name__ == "__main__": + main() diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/pyproject.toml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/pyproject.toml new file mode 100644 index 000000000..cc8fa7131 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/pyproject.toml @@ -0,0 +1,55 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "loongsuite-instrumentation-dashscope" +dynamic = ["version"] +description = "LoongSuite DashScope instrumentation" +readme = "README.rst" +license = "Apache-2.0" +requires-python = ">=3.9" +authors = [ + { name = "LoongSuite Python Agent Authors", email = "qp467389@alibaba-inc.com" }, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] +dependencies = [ + "opentelemetry-api ~= 1.37", + "opentelemetry-instrumentation ~= 0.58b0", + "opentelemetry-semantic-conventions ~= 0.58b0", +] + +[project.optional-dependencies] +instruments = [ + "dashscope >= 1.0.0", +] + +[project.entry-points.opentelemetry_instrumentor] +dashscope = "loongsuite.instrumentation.dashscope:DashScopeInstrumentor" + +[project.urls] +Homepage = "https://github.com/alibaba/loongsuite-python-agent" + +[tool.hatch.version] +path = "src/loongsuite/instrumentation/dashscope/version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/src", + "/tests", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/loongsuite"] + diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/__init__.py new file mode 100644 index 000000000..175296eca --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/__init__.py @@ -0,0 +1,15 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +__path__ = __import__("pkgutil").extend_path(__path__, __name__) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/__init__.py new file mode 100644 index 000000000..175296eca --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/__init__.py @@ -0,0 +1,15 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +__path__ = __import__("pkgutil").extend_path(__path__, __name__) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py new file mode 100644 index 000000000..ed8687edb --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py @@ -0,0 +1,154 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +LoongSuite Instrumentation for Alibaba Cloud DashScope SDK. + +This instrumentation library provides automatic tracing for DashScope API calls, +including text generation, text embedding, and text reranking. + +Supported Operations: + - Text Generation (sync/async, streaming/non-streaming) + - Text Embedding + - Text Reranking + +Note: Chat Completion (OpenAI-compatible) is NOT supported due to a bug in +DashScope SDK where Completions.create references a non-existent attribute +'dashscope.base_compatible_api_url'. Use Generation.call instead for chat +completion functionality. + +Usage: + from loongsuite.instrumentation.dashscope import DashScopeInstrumentor + + DashScopeInstrumentor().instrument() + + # Now use DashScope SDK as normal + from dashscope import Generation + response = Generation.call(model="qwen-turbo", prompt="Hello!") +""" + +import logging +from typing import Collection + +from loongsuite.instrumentation.dashscope.package import _instruments +from loongsuite.instrumentation.dashscope.patch import ( + wrap_aio_generation_call, + wrap_generation_call, + wrap_text_embedding_call, + wrap_text_rerank_call, +) +from loongsuite.instrumentation.dashscope.version import __version__ +from wrapt import wrap_function_wrapper + +from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.utils import unwrap + +logger = logging.getLogger(__name__) + +_MODULE_GENERATION = "dashscope.aigc.generation" +_MODULE_TEXT_EMBEDDING = "dashscope.embeddings.text_embedding" +_MODULE_TEXT_RERANK = "dashscope.rerank.text_rerank" + + +class DashScopeInstrumentor(BaseInstrumentor): + """ + LoongSuite Instrumentor for Alibaba Cloud DashScope SDK. + + This instrumentor patches key DashScope SDK methods to provide automatic + OpenTelemetry tracing for LLM operations. + """ + + def instrumentation_dependencies(self) -> Collection[str]: + """Return the list of packages this instrumentor depends on. + + Returns: + Collection of package names required for instrumentation. + """ + return _instruments + + def _instrument(self, **kwargs): + """Instrument the DashScope SDK. + + This method patches all supported DashScope API methods to add + OpenTelemetry tracing. + + Args: + **kwargs: Optional configuration parameters. + """ + logger.info("Instrumenting DashScope SDK") + + # Instrument Generation.call (sync) + try: + wrap_function_wrapper( + module=_MODULE_GENERATION, + name="Generation.call", + wrapper=wrap_generation_call, + ) + logger.debug("Instrumented Generation.call") + except Exception as e: + logger.warning(f"Failed to instrument Generation.call: {e}") + + # Instrument AioGeneration.call (async) + try: + wrap_function_wrapper( + module=_MODULE_GENERATION, + name="AioGeneration.call", + wrapper=wrap_aio_generation_call, + ) + logger.debug("Instrumented AioGeneration.call") + except Exception as e: + logger.warning(f"Failed to instrument AioGeneration.call: {e}") + + # Instrument TextEmbedding.call + try: + wrap_function_wrapper( + module=_MODULE_TEXT_EMBEDDING, + name="TextEmbedding.call", + wrapper=wrap_text_embedding_call, + ) + logger.debug("Instrumented TextEmbedding.call") + except Exception as e: + logger.warning(f"Failed to instrument TextEmbedding.call: {e}") + + # Instrument TextReRank.call + try: + wrap_function_wrapper( + module=_MODULE_TEXT_RERANK, + name="TextReRank.call", + wrapper=wrap_text_rerank_call, + ) + logger.debug("Instrumented TextReRank.call") + except Exception as e: + logger.warning(f"Failed to instrument TextReRank.call: {e}") + + def _uninstrument(self, **kwargs): + """Uninstrument the DashScope SDK. + + This method removes the instrumentation patches from DashScope SDK. + + Args: + **kwargs: Optional configuration parameters. + """ + # pylint: disable=import-outside-toplevel + import dashscope.aigc.generation + import dashscope.embeddings.text_embedding + import dashscope.rerank.text_rerank + + unwrap(dashscope.aigc.generation.Generation, "call") + unwrap(dashscope.aigc.generation.AioGeneration, "call") + unwrap(dashscope.embeddings.text_embedding.TextEmbedding, "call") + unwrap(dashscope.rerank.text_rerank.TextReRank, "call") + + +__all__ = ["DashScopeInstrumentor", "__version__"] diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/package.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/package.py new file mode 100644 index 000000000..9a2973fbb --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/package.py @@ -0,0 +1,15 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +_instruments = ("dashscope",) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py new file mode 100644 index 000000000..42a6b9bec --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py @@ -0,0 +1,135 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Patch functions for DashScope instrumentation.""" + +import inspect +import logging + +logger = logging.getLogger(__name__) + + +def _is_streaming_response(result): + """Check if the result is a streaming response.""" + return inspect.isgenerator(result) or inspect.isasyncgen(result) + + +def wrap_generation_call(wrapped, instance, args, kwargs): + """Wrapper for Generation.call (sync).""" + print("[INSTRUMENTATION] Entering Generation.call") + print(f"[INSTRUMENTATION] Args count: {len(args)}") + print(f"[INSTRUMENTATION] Kwargs keys: {list(kwargs.keys())}") + + try: + result = wrapped(*args, **kwargs) + + if _is_streaming_response(result): + print("[INSTRUMENTATION] Detected streaming response (Generator)") + return _wrap_sync_generator(result) + else: + print("[INSTRUMENTATION] Call successful (non-streaming)") + return result + + except Exception as e: + print(f"[INSTRUMENTATION] Exception caught: {type(e).__name__}: {e}") + raise + + +def wrap_aio_generation_call(wrapped, instance, args, kwargs): + """Wrapper for AioGeneration.call (async).""" + + async def async_wrapper(): + print("[INSTRUMENTATION] Entering AioGeneration.call (async)") + print(f"[INSTRUMENTATION] Args count: {len(args)}") + print(f"[INSTRUMENTATION] Kwargs keys: {list(kwargs.keys())}") + + try: + result = await wrapped(*args, **kwargs) + + if _is_streaming_response(result): + print( + "[INSTRUMENTATION] Detected streaming response (AsyncGenerator)" + ) + return _wrap_async_generator(result) + else: + print("[INSTRUMENTATION] Call successful (non-streaming)") + return result + + except Exception as e: + print( + f"[INSTRUMENTATION] Exception caught: {type(e).__name__}: {e}" + ) + raise + + return async_wrapper() + + +def wrap_text_embedding_call(wrapped, instance, args, kwargs): + """Wrapper for TextEmbedding.call.""" + print("[INSTRUMENTATION] Entering TextEmbedding.call") + print(f"[INSTRUMENTATION] Args count: {len(args)}") + print(f"[INSTRUMENTATION] Kwargs keys: {list(kwargs.keys())}") + + try: + result = wrapped(*args, **kwargs) + print("[INSTRUMENTATION] Call successful") + return result + + except Exception as e: + print(f"[INSTRUMENTATION] Exception caught: {type(e).__name__}: {e}") + raise + + +def wrap_text_rerank_call(wrapped, instance, args, kwargs): + """Wrapper for TextReRank.call.""" + print("[INSTRUMENTATION] Entering TextReRank.call") + print(f"[INSTRUMENTATION] Args count: {len(args)}") + print(f"[INSTRUMENTATION] Kwargs keys: {list(kwargs.keys())}") + + try: + result = wrapped(*args, **kwargs) + print("[INSTRUMENTATION] Call successful") + return result + + except Exception as e: + print(f"[INSTRUMENTATION] Exception caught: {type(e).__name__}: {e}") + raise + + +def _wrap_sync_generator(generator): + """Wrap a synchronous generator to log each chunk.""" + try: + for chunk in generator: + print("[INSTRUMENTATION] Received streaming chunk") + yield chunk + print("[INSTRUMENTATION] Streaming completed") + except Exception as e: + print( + f"[INSTRUMENTATION] Streaming exception: {type(e).__name__}: {e}" + ) + raise + + +async def _wrap_async_generator(generator): + """Wrap an asynchronous generator to log each chunk.""" + try: + async for chunk in generator: + print("[INSTRUMENTATION] Received streaming chunk (async)") + yield chunk + print("[INSTRUMENTATION] Streaming completed (async)") + except Exception as e: + print( + f"[INSTRUMENTATION] Streaming exception: {type(e).__name__}: {e}" + ) + raise diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/version.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/version.py new file mode 100644 index 000000000..e7844f893 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/version.py @@ -0,0 +1,15 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +__version__ = "0.1.0.dev0" diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_basic.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_basic.yaml new file mode 100644 index 000000000..e18141913 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_basic.yaml @@ -0,0 +1,72 @@ +interactions: +- request: + body: + input: + prompt: Hello! + model: qwen-turbo + parameters: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "finish_reason": "stop", + "text": "Hello! How can I assist you today? \ud83d\ude0a" + }, + "usage": { + "input_tokens": 14, + "output_tokens": 11, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 25 + }, + "request_id": "a5641492-94a0-45dc-abd7-e365cfab23a3" + } + headers: + Content-Type: + - application/json + Date: + - Mon, 17 Nov 2025 08:31:28 GMT + Server: + - istio-envoy + Set-Cookie: + - acw_tc=a5641492-94a0-45dc-abd7-e365cfab23a35b73256ab7df37c2ffa21ba0ba30e4e0;path=/;HttpOnly;Max-Age=1800 + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + content-length: + - '245' + req-arrive-time: + - '1763368287781' + req-cost-time: + - '334' + resp-start-time: + - '1763368288115' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '327' + x-request-id: + - a5641492-94a0-45dc-abd7-e365cfab23a3 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_streaming.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_streaming.yaml new file mode 100644 index 000000000..934b73628 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_streaming.yaml @@ -0,0 +1,94 @@ +interactions: +- request: + body: + input: + prompt: Count from 1 to 5 + model: qwen-turbo + parameters: {} + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1"},"usage":{"total_tokens":20,"output_tokens":1,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ab7cd9ac-82e9-4209-87ef-6b219204d339"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1,"},"usage":{"total_tokens":21,"output_tokens":2,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ab7cd9ac-82e9-4209-87ef-6b219204d339"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1, "},"usage":{"total_tokens":22,"output_tokens":3,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ab7cd9ac-82e9-4209-87ef-6b219204d339"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1, 2"},"usage":{"total_tokens":23,"output_tokens":4,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ab7cd9ac-82e9-4209-87ef-6b219204d339"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1, 2, 3,"},"usage":{"total_tokens":27,"output_tokens":8,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ab7cd9ac-82e9-4209-87ef-6b219204d339"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1, 2, 3, 4, "},"usage":{"total_tokens":31,"output_tokens":12,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ab7cd9ac-82e9-4209-87ef-6b219204d339"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"stop","text":"1, 2, 3, 4, 5."},"usage":{"total_tokens":33,"output_tokens":14,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ab7cd9ac-82e9-4209-87ef-6b219204d339"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Mon, 17 Nov 2025 08:31:28 GMT + Server: + - istio-envoy + Set-Cookie: + - acw_tc=ab7cd9ac-82e9-4209-87ef-6b219204d3399c7a348d42d2e4e8d3e215b2e43ae3ef;path=/;HttpOnly;Max-Age=1800 + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1763368288256' + req-cost-time: + - '191' + resp-start-time: + - '1763368288448' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '187' + x-request-id: + - ab7cd9ac-82e9-4209-87ef-6b219204d339 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_basic.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_basic.yaml new file mode 100644 index 000000000..41c8685ff --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_basic.yaml @@ -0,0 +1,81 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": {}, + "input": { + "prompt": "Hello!" + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '72' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "finish_reason": "stop", + "text": "Hello! How can I assist you today? \ud83d\ude0a" + }, + "usage": { + "input_tokens": 14, + "output_tokens": 11, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 25 + }, + "request_id": "49323c4e-a33e-42be-a301-9abb5dd9e20a" + } + headers: + content-length: + - '245' + content-type: + - application/json + date: + - Mon, 17 Nov 2025 08:31:25 GMT + req-arrive-time: + - '1763368285426' + req-cost-time: + - '412' + resp-start-time: + - '1763368285839' + server: + - istio-envoy + set-cookie: + - acw_tc=49323c4e-a33e-42be-a301-9abb5dd9e20aa0d6517c3c9c70a156508fab80186b21;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '405' + x-request-id: + - 49323c4e-a33e-42be-a301-9abb5dd9e20a + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_streaming.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_streaming.yaml new file mode 100644 index 000000000..0d7aa97c6 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_streaming.yaml @@ -0,0 +1,103 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": {}, + "input": { + "prompt": "Count from 1 to 5" + } + } + headers: + Accept: + - text/event-stream + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '83' + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1"},"usage":{"total_tokens":20,"output_tokens":1,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"14b9983a-83d6-491f-9ea0-ada34f950fa1"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1,"},"usage":{"total_tokens":21,"output_tokens":2,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"14b9983a-83d6-491f-9ea0-ada34f950fa1"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1, "},"usage":{"total_tokens":22,"output_tokens":3,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"14b9983a-83d6-491f-9ea0-ada34f950fa1"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1, 2"},"usage":{"total_tokens":23,"output_tokens":4,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"14b9983a-83d6-491f-9ea0-ada34f950fa1"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1, 2, 3,"},"usage":{"total_tokens":27,"output_tokens":8,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"14b9983a-83d6-491f-9ea0-ada34f950fa1"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1, 2, 3, 4, "},"usage":{"total_tokens":31,"output_tokens":12,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"14b9983a-83d6-491f-9ea0-ada34f950fa1"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"stop","text":"1, 2, 3, 4, 5."},"usage":{"total_tokens":33,"output_tokens":14,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"14b9983a-83d6-491f-9ea0-ada34f950fa1"} + + headers: + content-type: + - text/event-stream;charset=UTF-8 + date: + - Mon, 17 Nov 2025 08:31:26 GMT + req-arrive-time: + - '1763368286471' + req-cost-time: + - '161' + resp-start-time: + - '1763368286632' + server: + - istio-envoy + set-cookie: + - acw_tc=14b9983a-83d6-491f-9ea0-ada34f950fa1de2057e4ab26dd4514a24a33b037b3de;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '154' + x-request-id: + - 14b9983a-83d6-491f-9ea0-ada34f950fa1 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_messages.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_messages.yaml new file mode 100644 index 000000000..e7cd3af31 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_messages.yaml @@ -0,0 +1,86 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": {}, + "input": { + "messages": [ + { + "role": "user", + "content": "Hello!" + } + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '105' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "finish_reason": "stop", + "text": "Hello! How can I assist you today? \ud83d\ude0a" + }, + "usage": { + "input_tokens": 14, + "output_tokens": 11, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 25 + }, + "request_id": "95386392-96f0-4464-badd-331cdbb37634" + } + headers: + content-length: + - '245' + content-type: + - application/json + date: + - Mon, 17 Nov 2025 08:31:25 GMT + req-arrive-time: + - '1763368285985' + req-cost-time: + - '308' + resp-start-time: + - '1763368286293' + server: + - istio-envoy + set-cookie: + - acw_tc=95386392-96f0-4464-badd-331cdbb37634fc4ecf63fbc9ddef4e9f1c5c573710e6;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '301' + x-request-id: + - 95386392-96f0-4464-badd-331cdbb37634 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_parameters.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_parameters.yaml new file mode 100644 index 000000000..648a4ea2e --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_parameters.yaml @@ -0,0 +1,85 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": { + "temperature": 0.8, + "top_p": 0.9, + "max_tokens": 100 + }, + "input": { + "prompt": "Write a short poem" + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '135' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "finish_reason": "stop", + "text": "Beneath the moon, the stars align, \nA whisper winds through the pine. \nThe night is soft, the world is still, \nAnd dreams begin where thoughts will." + }, + "usage": { + "input_tokens": 16, + "output_tokens": 37, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 53 + }, + "request_id": "ee8de668-5f8f-40e3-80f4-e3a0013967bb" + } + headers: + content-length: + - '360' + content-type: + - application/json + date: + - Mon, 17 Nov 2025 08:31:27 GMT + req-arrive-time: + - '1763368287002' + req-cost-time: + - '633' + resp-start-time: + - '1763368287636' + server: + - istio-envoy + set-cookie: + - acw_tc=ee8de668-5f8f-40e3-80f4-e3a0013967bbd5d31169b9fcbffc57c75542a5810acc;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '627' + x-request-id: + - ee8de668-5f8f-40e3-80f4-e3a0013967bb + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_basic.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_basic.yaml new file mode 100644 index 000000000..3d614100f --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_basic.yaml @@ -0,0 +1,1618 @@ +interactions: +- request: + body: |- + { + "model": "text-embedding-v1", + "parameters": {}, + "input": { + "texts": [ + "Hello, world!" + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '87' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/embeddings/text-embedding/text-embedding + response: + body: + string: |- + { + "output": { + "embeddings": [ + { + "embedding": [ + -2.3644089698791504, + 8.348400115966797, + 2.097400426864624, + -1.0467296838760376, + -1.2527087926864624, + 0.0425327830016613, + 0.3912527859210968, + -1.4500325918197632, + -1.0760498046875, + 0.2101992666721344, + -2.3206264972686768, + 3.7271206378936768, + 2.379696846008301, + -1.3252418041229248, + -2.1858956813812256, + -0.3906017541885376, + -3.511707067489624, + 4.319149971008301, + -0.5420735478401184, + 0.5006510615348816, + -1.1608537435531616, + 0.6392531394958496, + 0.1413399875164032, + -1.0370628833770752, + 0.8527134656906128, + 0.1985037624835968, + -1.7248361110687256, + -0.4842354953289032, + -0.1581915020942688, + -1.3892415761947632, + -0.8029610514640808, + -3.2586147785186768, + -3.167201519012451, + 0.364653080701828, + 2.7538132667541504, + -0.3536609411239624, + -0.5097888708114624, + -0.4561913013458252, + -1.7330322265625, + 1.6760603189468384, + 0.6422119140625, + -0.7685314416885376, + 0.3505452573299408, + -1.809337854385376, + -1.065929651260376, + -1.7091761827468872, + 3.1148273944854736, + 1.3470284938812256, + 0.1521809846162796, + -2.594996929168701, + 1.2496076822280884, + -0.6859654188156128, + -2.271338939666748, + -1.5138171911239624, + -1.0745166540145874, + -2.5738468170166016, + -3.053664445877075, + 1.0606369972229004, + -0.3481270968914032, + -0.2445882111787796, + 0.716668963432312, + -2.6781413555145264, + -1.1443220376968384, + 0.201078861951828, + 0.9033551812171936, + 1.237909197807312, + -0.5298781394958496, + 1.9127953052520752, + -2.6026320457458496, + 0.6795828938484192, + 0.5000523328781128, + -2.5301804542541504, + 0.1349748820066452, + -1.5820080041885376, + 1.7742105722427368, + -0.7659621238708496, + 3.172107458114624, + -0.2291841059923172, + 0.1726423054933548, + -0.880062997341156, + -0.7115478515625, + -1.2440824508666992, + 2.158017158508301, + -1.9456416368484497, + 0.7897832989692688, + 3.501674175262451, + -0.5041736364364624, + 0.7177501916885376, + 2.0924479961395264, + 1.204578161239624, + -2.6135051250457764, + -1.4023844003677368, + -0.948550283908844, + 0.9507649540901184, + 2.43743896484375, + 3.4669480323791504, + -3.2669155597686768, + 1.7118210792541504, + -1.299688458442688, + -2.5470378398895264, + 0.1276971697807312, + 1.0938546657562256, + -2.1124093532562256, + -2.3443081378936768, + 1.4197591543197632, + -2.103073835372925, + -0.061988465487957, + 0.8232243657112122, + 1.3082681894302368, + -0.32470703125, + -0.4158179759979248, + 1.6337890625, + -0.6632777452468872, + 2.641415596008301, + 3.6478328704833984, + -1.96063232421875, + 2.227585554122925, + 2.5348308086395264, + 0.3877418041229248, + -0.9308995008468628, + -0.8205217719078064, + -0.7171543836593628, + -3.2149832248687744, + 0.1238955557346344, + -2.750842809677124, + -0.5313429832458496, + 0.1223248541355133, + -4.042782783508301, + 0.534970223903656, + 1.2729142904281616, + 1.025390625, + -0.4880719780921936, + -2.2762742042541504, + -1.2745070457458496, + 1.022205114364624, + -2.2467970848083496, + -1.911993145942688, + -0.0312383733689785, + 2.324242115020752, + 3.466796875, + 1.7488490343093872, + -1.4303734302520752, + 2.9417543411254883, + -5.021042823791504, + -0.3707682192325592, + 2.385155200958252, + -2.245814800262451, + 2.070777416229248, + -3.794224262237549, + 1.716564416885376, + -0.38116455078125, + -0.247163325548172, + -2.1544015407562256, + -0.955621600151062, + 2.567336320877075, + 2.411156177520752, + 3.052525043487549, + 3.316127300262451, + -1.2475818395614624, + 1.3395589590072632, + -0.8995070457458496, + 3.6773507595062256, + 4.280282020568848, + 1.412841796875, + -1.4889206886291504, + -1.6233229637145996, + 0.8419364094734192, + 1.1152750253677368, + -1.6808035373687744, + -3.3175716400146484, + 2.5956332683563232, + -1.5513509511947632, + -0.5166829228401184, + 0.559756338596344, + -0.8132207989692688, + -2.2564175128936768, + -4.0888671875, + -2.225121021270752, + 0.8791196942329407, + -3.275088310241699, + 2.271275043487549, + 1.3703322410583496, + 1.8992745876312256, + -1.2126697301864624, + -1.3438408374786377, + 2.514183521270752, + -2.6771066188812256, + 0.7653111219406128, + -0.9755859375, + 3.2733676433563232, + 0.1212710440158844, + -2.419177770614624, + -0.0870535746216774, + 6.178013324737549, + 1.123865008354187, + -0.4238749146461487, + -0.7292248010635376, + 0.2359561026096344, + 4.840308666229248, + -0.8148236870765686, + -2.843796491622925, + 1.3535562753677368, + -0.7840750813484192, + -1.76318359375, + 0.645810067653656, + -2.200462818145752, + -0.629766583442688, + -1.8720121383666992, + 0.597476065158844, + 0.9882347583770752, + 0.868475079536438, + -2.7318406105041504, + -2.068150043487549, + 1.3249250650405884, + -1.293481707572937, + -3.2354679107666016, + -1.1557588577270508, + 1.6342308521270752, + 0.5199599266052246, + 2.5381557941436768, + 0.551427960395813, + -0.0951799675822258, + 0.2204938679933548, + 0.1849307119846344, + 1.6346784830093384, + 1.7246675491333008, + 1.1175246238708496, + -0.9251301884651184, + 2.9076335430145264, + -1.0483747720718384, + -1.0949445962905884, + -0.0956159308552742, + 0.7633841633796692, + -0.6463274359703064, + -1.7429701089859009, + -4.55410623550415, + -1.0886636972427368, + -0.4407261312007904, + 1.5462937355041504, + 0.291806161403656, + -3.136253833770752, + -0.0388997383415699, + 3.6954753398895264, + -2.925999164581299, + -0.2655785083770752, + -2.656482458114624, + 0.8409830927848816, + -0.7435084581375122, + -3.2907016277313232, + -2.27960205078125, + -0.8480814695358276, + 0.9958118200302124, + 0.0892392098903656, + -0.8820568323135376, + -0.950985848903656, + -1.004204511642456, + 0.8785109519958496, + 1.7008463144302368, + 0.4410865306854248, + 2.766066789627075, + -0.125441774725914, + -1.3818941116333008, + 0.6986803412437439, + -7.002476215362549, + -2.8547933101654053, + 0.3550851047039032, + -0.88555908203125, + -0.0173456110060215, + -0.8857421875, + -0.3068963885307312, + -0.1766183078289032, + 0.9981166124343872, + 0.1005975604057312, + -0.2137625515460968, + 0.42779541015625, + 0.3893694281578064, + -0.06884765625, + 5.982235908508301, + -1.060779333114624, + 0.099952332675457, + -3.340587854385376, + 2.3394253253936768, + 0.9077845811843872, + -0.550104022026062, + 0.2147449254989624, + -0.4830729067325592, + -0.271914541721344, + 1.651373028755188, + 0.5246117115020752, + -0.0332932248711586, + 3.1971027851104736, + 1.3466796875, + -0.6326482892036438, + -2.511989116668701, + 2.9210379123687744, + 10.145615577697754, + 1.1730724573135376, + 1.4595423936843872, + 0.20625431835651398, + 0.3898693323135376, + -0.5182175636291504, + 1.6884300708770752, + 1.3027780055999756, + 0.2667701244354248, + 0.2190755158662796, + -0.4350469708442688, + -2.6139090061187744, + 1.0701439380645752, + -4.072312355041504, + -1.4245082139968872, + 2.736607074737549, + -1.0172319412231445, + 1.1473156213760376, + -2.712204694747925, + 0.76971435546875, + -0.7286769151687622, + 2.048642158508301, + 0.8965076208114624, + 0.2541329562664032, + -1.371837854385376, + -4.416922569274902, + 3.052222728729248, + -0.1757114976644516, + -0.962762713432312, + 0.4635184109210968, + 1.5114396810531616, + 1.077020525932312, + 0.5488106608390808, + -0.4493640661239624, + 3.5396902561187744, + -3.591273307800293, + -0.3326183557510376, + 2.586135149002075, + -1.927001953125, + 2.7566730976104736, + -1.8287179470062256, + -0.957159161567688, + 0.983944833278656, + -0.4755801260471344, + 1.1645827293395996, + -3.514206647872925, + 1.7742513418197632, + 0.389346182346344, + -1.9777250289916992, + -1.7304280996322632, + -0.6190999150276184, + -1.999395489692688, + 1.3909679651260376, + 2.2452800273895264, + 2.423398017883301, + -2.4583566188812256, + -2.483142614364624, + 1.2218191623687744, + -2.5528273582458496, + 3.3501551151275635, + 1.3609328269958496, + -2.5067546367645264, + 3.269366979598999, + 0.8338913917541504, + 0.511724591255188, + -0.7465021014213562, + -1.2192033529281616, + 1.0968424081802368, + 0.8342168927192688, + -2.0520193576812744, + -0.7399786114692688, + 0.7810261845588684, + 0.6752638816833496, + -0.6409621238708496, + -2.1106364727020264, + -2.0662667751312256, + -2.1149089336395264, + -0.0795229971408844, + -0.4758417010307312, + -1.7017440795898438, + 2.431663990020752, + -2.8352863788604736, + -0.1171177476644516, + -1.9771902561187744, + 1.1388288736343384, + 4.496628761291504, + 1.3607468605041504, + 4.019984722137451, + 1.4455915689468384, + 1.6869187355041504, + -1.7653459310531616, + 0.6582547426223755, + -0.536923348903656, + 1.9129232168197632, + 1.1713693141937256, + -3.102771520614624, + 0.6308855414390564, + 0.9268043041229248, + 0.9299025535583496, + 1.2564523220062256, + 2.9861361980438232, + 0.7058788537979126, + -4.027878761291504, + 3.619873046875, + 1.2952706813812256, + 2.5843796730041504, + -4.99228048324585, + -3.7347469329833984, + -0.8114827275276184, + -1.275501012802124, + -1.1993582248687744, + -0.1656436026096344, + -1.7523897886276245, + 1.0548967123031616, + 2.054489850997925, + -2.1615047454833984, + 0.7817615270614624, + -0.1088227778673172, + 0.307710200548172, + 4.224330425262451, + 1.0543619394302368, + 2.8228933811187744, + -0.7669270634651184, + 3.1636672019958496, + 2.3579800128936768, + 1.8028738498687744, + -6.47256326675415, + 0.1218319833278656, + 0.4943731427192688, + -1.5901808738708496, + -2.4180362224578857, + 3.2227492332458496, + -0.7046363353729248, + -2.1535556316375732, + 0.3588750958442688, + -2.0572917461395264, + 3.121767997741699, + 0.6063057780265808, + -3.806582450866699, + 0.2797589898109436, + -0.563726544380188, + 2.8772785663604736, + 2.9538371562957764, + -2.3084542751312256, + 1.121454119682312, + 0.4231211245059967, + 0.9242931604385376, + 0.9237074851989746, + 2.127162456512451, + -2.2772274017333984, + -1.0973539352416992, + -4.550990581512451, + -0.3505626916885376, + 2.056018590927124, + 3.1640799045562744, + 5.975306987762451, + 2.2169742584228516, + -2.5257160663604736, + -1.7594575881958008, + 1.4456162452697754, + -0.4814685583114624, + 0.5288550853729248, + -2.0911922454833984, + -2.7852907180786133, + -0.1259867399930954, + -2.682492256164551, + 1.274530291557312, + -0.140212282538414, + -0.5564037561416626, + -1.2201218605041504, + 0.0173063725233078, + 2.3711867332458496, + 1.4970238208770752, + 0.9487072229385376, + -0.918218731880188, + 0.4788411557674408, + -0.6853957176208496, + 3.4996280670166016, + 0.6675269603729248, + -1.5422712564468384, + -0.6624058485031128, + 1.088750958442688, + -1.6589587926864624, + -0.8898809552192688, + -1.933117151260376, + 1.3687453269958496, + 0.2741350531578064, + 0.2345145046710968, + 0.3046351969242096, + 1.121832013130188, + 0.7152274250984192, + 0.3553844690322876, + -1.2605329751968384, + -1.4061744213104248, + 2.1021671295166016, + 1.6358236074447632, + -2.846447229385376, + 0.834344744682312, + 0.5837634801864624, + -0.6924525499343872, + -1.9964425563812256, + 4.665643692016602, + 2.031406879425049, + -0.3150111734867096, + 2.4888415336608887, + -0.8978562355041504, + 0.0199294313788414, + 2.8924386501312256, + -3.387718677520752, + -5.7142157554626465, + 0.98779296875, + 1.8582589626312256, + -0.2107660174369812, + 3.455333948135376, + 0.2661946713924408, + 0.3993442952632904, + -1.6158156394958496, + -0.2243681401014328, + 5.155552387237549, + 2.78857421875, + -2.359386682510376, + 2.5395216941833496, + -2.4046688079833984, + 2.585983991622925, + 2.206611156463623, + -0.186003178358078, + -0.1255580335855484, + 1.5553269386291504, + 1.8910318613052368, + -3.7432804107666016, + 0.8833937644958496, + -0.171433225274086, + 0.0216950923204422, + -1.7236095666885376, + 1.3008219003677368, + -1.035516619682312, + -1.0505545139312744, + -2.900204658508301, + 1.3283531665802002, + -1.8973679542541504, + -2.045398473739624, + 0.5425836443901062, + 1.1606532335281372, + -0.7099202275276184, + 1.3287179470062256, + -3.394019603729248, + -4.330821990966797, + 1.3423781394958496, + -1.9765218496322632, + 2.166015625, + -2.123012065887451, + -0.4435984194278717, + 3.5960285663604736, + 0.6068798303604126, + 0.3734668493270874, + 0.3968099057674408, + 2.865443706512451, + -1.7889854907989502, + 0.67041015625, + 0.629278302192688, + 0.8960949182510376, + -1.6464552879333496, + 4.188755512237549, + -2.509323835372925, + -1.5246232748031616, + 1.0910993814468384, + 1.068103551864624, + 0.6994512677192688, + 0.7347586750984192, + -1.261474609375, + -1.403985857963562, + -1.430279016494751, + 4.372256278991699, + -0.8328624963760376, + -0.483157217502594, + -2.670311450958252, + 2.2127277851104736, + 1.166009783744812, + 0.6137520670890808, + 1.1021322011947632, + -0.3893906772136688, + -0.6502510905265808, + -1.5413120985031128, + 0.8475516438484192, + -1.4995582103729248, + 1.769353985786438, + -3.0482265949249268, + 0.24951171875, + 1.1967076063156128, + 1.0028003454208374, + 0.3950892984867096, + -0.9737025499343872, + 1.502941370010376, + 5.829659461975098, + 0.1647367924451828, + 2.983933210372925, + -2.590053081512451, + -3.4691219329833984, + -0.0007900964701548219, + 1.0939127206802368, + 1.0850074291229248, + -1.075732946395874, + 0.8866373896598816, + 0.644170880317688, + -1.8892850875854492, + 1.8008161783218384, + 3.1016788482666016, + -2.33251953125, + -0.8591526746749878, + -0.1574474573135376, + 1.787713885307312, + -2.473911762237549, + 0.1741303950548172, + -0.9803757667541504, + 0.0323370061814785, + -1.7488839626312256, + 0.6590169072151184, + 1.4492769241333008, + 1.4521833658218384, + 2.010974645614624, + -0.1306849867105484, + 0.4085867702960968, + 1.434802770614624, + 0.5101550817489624, + -0.5400739312171936, + -0.4342389702796936, + 1.1499720811843872, + -0.6592575907707214, + 5.336146831512451, + -1.1819661855697632, + -4.885416507720947, + 1.3282907009124756, + 1.41357421875, + -1.445544958114624, + 3.101027727127075, + -1.3035714626312256, + 0.1830357164144516, + 1.9658668041229248, + 2.2354214191436768, + 2.676223039627075, + 2.612839460372925, + 0.871026873588562, + -0.9088919758796692, + -0.8327186107635498, + 3.344447612762451, + 1.2490001916885376, + 1.503912091255188, + 3.095923900604248, + 0.040771484375, + 1.9186197519302368, + 0.0215134397149086, + 1.6254621744155884, + 0.343534916639328, + -0.9873511791229248, + -0.6172541379928589, + 0.2068365216255188, + -1.1708170175552368, + 1.8122209310531616, + -1.825939416885376, + 0.5743001103401184, + -0.7070196270942688, + 0.9178552031517029, + 2.656528949737549, + -0.4136250913143158, + -0.956787109375, + 0.3823939859867096, + -2.3172664642333984, + -3.157273054122925, + 1.129876971244812, + 0.1795828640460968, + 1.5586867332458496, + -2.9426791667938232, + 1.717157244682312, + 2.1954054832458496, + -1.0418875217437744, + 0.0559547059237957, + -0.5893206000328064, + -0.8616071343421936, + 0.01422991044819355, + 1.60687255859375, + -1.334118127822876, + -0.6169084906578064, + 0.844296395778656, + 1.6326584815979004, + -4.101510047912598, + 0.4577694833278656, + -4.144693851470947, + 0.8202195167541504, + -1.2004743814468384, + -1.6608130931854248, + 2.101283550262451, + 1.2726236581802368, + 1.4511079788208008, + 1.3248697519302368, + -2.2406296730041504, + 0.6573195457458496, + -0.781622052192688, + -1.7567429542541504, + 2.201125383377075, + 0.5358073115348816, + -1.4015822410583496, + -1.6643575429916382, + 0.1222563236951828, + 0.073951356112957, + -0.2227608859539032, + 0.3194754421710968, + 1.9024076461791992, + 0.6451590657234192, + -1.2811918258666992, + 0.8215186595916748, + -2.552700996398926, + 2.306687116622925, + 3.5081584453582764, + -0.8518298864364624, + -3.7080078125, + -1.259668231010437, + 1.5614885091781616, + -4.940848350524902, + 3.0947265625, + 1.8330310583114624, + 0.868222177028656, + -1.2332850694656372, + -1.7700427770614624, + -2.250232458114624, + 2.638950824737549, + 0.377592533826828, + -0.7023518681526184, + -2.6805245876312256, + -0.4848284125328064, + 0.01593889482319355, + 2.386021137237549, + -4.34628438949585, + 0.80535888671875, + -0.5953892469406128, + 0.07200004905462265, + -2.4158012866973877, + -5.380650043487549, + 0.7778552770614624, + -6.638602256774902, + -0.3949730396270752, + 4.0624260902404785, + 1.9362211227416992, + 0.3960629403591156, + -0.0982622429728508, + 0.8816964030265808, + -2.353195905685425, + 0.9816821813583374, + 1.0030808448791504, + -0.4104468822479248, + -3.1797573566436768, + 0.4308079183101654, + -0.429838627576828, + 2.832007884979248, + -0.814511239528656, + 0.8206351399421692, + 2.526268482208252, + 1.1391862630844116, + 0.973965585231781, + 2.109076976776123, + -0.6471034288406372, + 0.6391136646270752, + -0.8195452094078064, + 3.2508370876312256, + 2.3595783710479736, + 1.6988931894302368, + -4.392113208770752, + 0.0994001105427742, + 0.3229486346244812, + 1.746404767036438, + -1.5265183448791504, + 1.604375958442688, + 0.249099001288414, + -3.0640335083007812, + 0.0067080543376505375, + -1.9424293041229248, + 4.140810966491699, + -3.537411689758301, + -0.5926281213760376, + 3.812046527862549, + -0.0005580357392318547, + -1.722412109375, + -1.1184431314468384, + -5.322428226470947, + 1.768182635307312, + -0.0067894347012043, + -0.8733345866203308, + -1.839715838432312, + 2.0568034648895264, + -3.0118234157562256, + -0.004002162255346775, + 5.937337398529053, + -5.186476707458496, + -2.192673444747925, + 0.2689964771270752, + -1.6687361001968384, + 0.768682599067688, + 0.6078869104385376, + 2.364490270614624, + -1.5765730142593384, + 3.032459020614624, + 2.6341726779937744, + 0.236769899725914, + -2.4805386066436768, + 1.891485333442688, + 2.663562536239624, + -1.0957961082458496, + 0.7866908311843872, + 1.4409419298171997, + 0.3268926739692688, + 1.420654296875, + 1.182012677192688, + 0.292085200548172, + 0.0203683041036129, + -1.6057826280593872, + 3.4831950664520264, + -3.7445590496063232, + -0.6719098687171936, + 1.1380091905593872, + 0.9125046730041504, + -1.8951880931854248, + -1.060933232307434, + 2.242600202560425, + 0.4206194281578064, + 0.414853036403656, + 1.1497046947479248, + -1.7508951425552368, + -0.6983467936515808, + -0.427461177110672, + 3.173537492752075, + 2.599597692489624, + -0.9331752061843872, + 0.4794166088104248, + -4.652064800262451, + -1.1448800563812256, + 0.6494140625, + -2.1709914207458496, + -1.384161114692688, + -0.8793073296546936, + 0.7139485478401184, + 0.1335216760635376, + -2.865757465362549, + -1.4832066297531128, + -0.4580543041229248, + 0.560116708278656, + -1.526355504989624, + 0.7525111436843872, + 0.629086434841156, + -0.9777948260307312, + 2.9934518337249756, + -0.5725744366645813, + -1.9465738534927368, + -0.6865234375, + 0.4393979012966156, + 1.346447229385376, + 0.015232631005346775, + 2.852074146270752, + -0.2486049085855484, + 1.4267141819000244, + 2.249558210372925, + 0.4023321270942688, + -0.2238420695066452, + -2.056429862976074, + -1.7075427770614624, + -1.6658296585083008, + -2.2136287689208984, + -0.7926316261291504, + 2.4517531394958496, + 2.5347378253936768, + -0.3218899667263031, + -1.382928729057312, + 1.5544201135635376, + 3.000744104385376, + -5.117739677429199, + -0.355712890625, + -1.9428361654281616, + 1.7631791830062866, + -1.696521520614624, + -1.661859393119812, + 0.3370768129825592, + -1.5527111291885376, + 1.1764206886291504, + 1.5777268409729004, + -0.9625418782234192, + 1.2859933376312256, + 1.2503255605697632, + 6.035435199737549, + 1.8481677770614624, + -1.7089000940322876, + 2.6567904949188232, + 1.1696195602416992, + 1.7485584020614624, + 0.1310453861951828, + 1.153454065322876, + -4.179361820220947, + -2.6123976707458496, + 1.7947213649749756, + -0.6537213921546936, + -1.6040736436843872, + -6.299339771270752, + -0.1156325563788414, + -4.517206192016602, + 0.8835856318473816, + 0.0385567806661129, + -1.0504964590072632, + 0.1015036478638649, + -1.4712378978729248, + -0.4662969708442688, + 0.7673096656799316, + 2.3467304706573486, + 1.8791853189468384, + 0.9479079246520996, + -1.737432599067688, + 1.8960890769958496, + 1.2717232704162598, + 1.9296642541885376, + -0.3081628680229187, + 0.4654366672039032, + 3.8032925128936768, + 0.6796584129333496, + 1.1200706958770752, + -0.8844401240348816, + -2.267392158508301, + -1.816906213760376, + 1.3306245803833008, + -0.6157051920890808, + 0.530517578125, + -0.0592215396463871, + 1.0465785264968872, + 1.0058943033218384, + 0.7565220594406128, + 4.7376532554626465, + -3.4979074001312256, + 2.924647808074951, + 0.8614909052848816, + -1.5947966575622559, + -0.9366019368171692, + -7.398065567016602, + 1.1715378761291504, + -0.8412243127822876, + -1.0724515914916992, + -1.7789480686187744, + -0.1473911851644516, + 0.9554268717765808, + -3.232142925262451, + -0.5623255968093872, + -2.1612956523895264, + 4.236514091491699, + 0.9475213885307312, + -0.201020747423172, + 0.4620768129825592, + 1.0322614908218384, + -0.5619515776634216, + 1.0764741897583008, + -1.3737211227416992, + -1.0516531467437744, + 2.0757534503936768, + 2.2359793186187744, + -4.117210865020752, + -5.0966796875, + -0.6387416124343872, + 1.9170619249343872, + 1.2573761940002441, + 0.135544553399086, + -3.6419734954833984, + 2.143298864364624, + -0.9724906086921692, + -2.4341678619384766, + 2.8367512226104736, + -0.2053774893283844, + 0.3136160671710968, + 2.6178386211395264, + 0.3419945240020752, + 1.4307105541229248, + 0.568057119846344, + -2.040947437286377, + -0.6492047905921936, + -0.2074032723903656, + -1.4479398727416992, + 4.316708564758301, + 0.84912109375, + 0.6699393391609192, + -0.4652564525604248, + 1.377063512802124, + 4.839960098266602, + -0.02008637972176075, + 5.208170413970947, + 1.843494176864624, + -2.999185085296631, + -2.985886335372925, + 1.010498046875, + -2.927966833114624, + 2.8939266204833984, + -5.718192100524902, + 0.6626383662223816, + 1.7331383228302002, + -0.5201125144958496, + -3.764880895614624, + 1.9500093460083008, + 1.9916120767593384, + 2.102341413497925, + -1.3442615270614624, + 0.5216587781906128, + -3.300868511199951, + -0.9966285228729248, + -0.3642461895942688, + 0.43735939264297485, + 1.0207315683364868, + 4.749814033508301, + -1.4948410987854004, + 1.3209228515625, + 1.3700590133666992, + -1.0886812210083008, + -8.0275297164917, + -0.0062197730876505375, + 3.169050693511963, + -1.2998918294906616, + -0.03078497014939785, + -2.836437463760376, + 0.5869605541229248, + 2.1944522857666016, + -1.5927908420562744, + 2.8204519748687744, + -0.00896344892680645, + -0.58740234375, + -0.9702933430671692, + -1.5561988353729248, + 0.991635262966156, + -0.0594540536403656, + -1.8147176504135132, + 0.532412588596344, + -0.7359619140625, + -0.1268310546875, + -3.2795701026916504, + 0.3123081624507904, + 2.597912073135376, + 3.4586617946624756, + -0.2213541716337204, + -5.854724884033203, + -0.3244120180606842, + 1.0697312355041504, + -0.9000999927520752, + -1.764415979385376, + -1.2431989908218384, + 2.3568899631500244, + 2.9845144748687744, + 11.118117332458496, + 0.079636350274086, + 0.8921828269958496, + 1.2745884656906128, + -2.2142624855041504, + -0.6816580891609192, + -1.5182756185531616, + -1.2685779333114624, + -1.7538365125656128, + 1.4817476272583008, + -0.334170401096344, + 0.3260962963104248, + -1.6263021230697632, + -2.723598003387451, + 0.6808515191078186, + 1.8016763925552368, + 0.861142098903656, + 2.718691825866699, + 6.245442867279053, + 2.308037281036377, + 1.4014369249343872, + -0.00772857666015625, + -2.0861496925354004, + -2.128953218460083, + -4.3868584632873535, + -0.557803213596344, + -0.195527583360672, + -0.3629324734210968, + 1.5075669288635254, + 1.7068685293197632, + 0.8290027379989624, + 0.7471051812171936, + 1.1012195348739624, + 1.215704083442688, + -1.1070847511291504, + -4.1085381507873535, + 4.165085792541504, + -1.0738990306854248, + 2.3118488788604736, + 4.398548126220703, + 0.5644631385803223, + -3.3761160373687744, + -2.686843156814575, + -2.341320276260376, + 0.3634905219078064, + 0.0870768204331398, + 0.7520264983177185, + 1.9031343460083008, + -1.1603844165802002, + -1.7050014734268188, + -3.780994176864624, + -0.098289854824543, + 1.241729736328125, + 0.126418337225914, + 0.7485584020614624, + -0.40079498291015625, + 1.6128162145614624, + -0.7204909324645996, + -1.042730450630188, + 2.3536550998687744, + 0.7622302770614624, + 3.0550129413604736, + 0.010358537547290325, + 0.2270536869764328, + 2.898391008377075, + 1.3043445348739624, + -2.1659457683563232, + 1.9405691623687744, + 0.0641421377658844, + 1.812744140625, + -1.3930431604385376, + -0.0488746277987957, + -0.2908412516117096, + -0.5325753092765808, + -0.6135384440422058, + 2.285458564758301, + 3.8053386211395264, + 2.2774715423583984, + -0.6852329969406128, + 2.5215890407562256, + 0.5063621997833252, + -0.912969708442688, + -1.0029296875, + -1.492919921875, + 0.206618532538414, + -0.8885788917541504, + -1.2186744213104248, + -2.0115559101104736, + -2.047805070877075, + 0.084007628262043, + -0.3573724627494812, + 2.6905109882354736, + 2.521926164627075, + -2.142357349395752, + 0.6171467900276184, + 3.4425456523895264, + 1.7161691188812256, + -1.5597214698791504, + -2.9109585285186768, + -2.307570695877075, + -0.4117082953453064, + 2.757056713104248, + 4.941429615020752, + -1.583124041557312, + 1.816540002822876, + 0.4769127368927002, + -1.9381510019302368, + -0.3262532651424408, + -0.9907342791557312, + -1.91552734375, + 0.6923363208770752, + 4.312128067016602, + -0.49151611328125, + -0.1331569105386734, + 0.7105189561843872, + 2.9299607276916504, + -1.8733724355697632, + 1.7488607168197632, + 0.9223516583442688, + 2.795154333114624, + -1.0608607530593872, + 3.669410228729248, + 0.8557477593421936, + 13.737815856933594, + 0.0650111585855484, + -1.3898054361343384, + -2.663132429122925, + -2.10233998298645, + -0.5996791124343872, + 0.1247442364692688, + -0.0612284354865551, + -1.6938127279281616, + 2.7924106121063232, + -1.203601598739624, + -0.2482793927192688, + -0.004253569059073925, + 0.0932297483086586, + 0.2328404039144516, + -0.2439633309841156, + -2.581728935241699, + -0.552734375, + 4.119365215301514, + -0.910342276096344, + 0.6861281394958496, + -1.6213728189468384, + -1.9677269458770752, + -0.9070870280265808, + 2.7165005207061768, + -1.649181604385376, + -1.0459507703781128, + -0.9472191333770752, + -2.2626953125, + 0.9804919958114624, + -0.5400517582893372, + -2.7049851417541504, + -0.3970424234867096, + 1.4640822410583496, + -0.1065964475274086, + 3.9159302711486816, + -0.0641159787774086, + 2.532505512237549, + -0.3606421947479248, + -1.9884498119354248, + -0.4455915093421936, + -1.5947542190551758, + 2.8155808448791504, + 1.460681676864624, + 0.787572979927063, + -2.7700893878936768, + -1.710613489151001, + -0.25464683771133423, + -0.5056036114692688, + 0.6232096552848816, + -2.279552698135376, + 0.6872809529304504, + -1.8815336227416992, + 0.102310910820961, + -0.3274681568145752, + 0.236113041639328, + 1.5462123155593872, + 2.802036762237549, + -1.347912073135376, + -1.4057384729385376, + 1.2983863353729248, + 0.6948009729385376, + -0.0399228036403656, + 1.201915979385376, + -1.8632042407989502, + -0.467866450548172, + 1.6931791305541992, + 1.7876688241958618, + -0.3617350161075592, + -1.3591773509979248, + 4.75710916519165, + -2.2508602142333984, + 0.7127569317817688, + 0.9460565447807312, + -1.8464704751968384, + -2.600562572479248, + 1.7840052843093872, + 3.3075735569000244, + 1.602405309677124, + -1.3504464626312256, + -5.516880512237549, + -2.4291062355041504, + -0.3665335476398468, + -0.8979375958442688, + -0.5668168067932129, + 1.6053640842437744, + 0.9861653447151184, + 4.472051620483398, + -1.3283109664916992, + 1.2012183666229248, + 1.792712926864624, + 2.2725741863250732, + 0.5454392433166504, + 2.101260185241699, + 0.5392833948135376, + 1.2630091905593872, + -2.5963308811187744, + 0.4639834463596344, + 0.6281752586364746, + -0.2898937463760376, + 1.6051185131072998, + -0.6773390769958496, + 0.2618001401424408, + -0.6475016474723816, + 0.1373814195394516, + -3.4120280742645264, + 3.100208044052124, + 0.1819894015789032, + -0.310639888048172, + -3.5144972801208496, + -0.8488309979438782, + -2.696568012237549, + 1.6153994798660278, + -4.879092216491699, + 2.2645437717437744, + 0.8698076605796814, + 0.150162473320961, + 0.8675246238708496, + -0.474667489528656, + -0.731847882270813, + -1.0864635705947876, + -3.529250383377075, + -0.7908063530921936, + -2.0580241680145264, + -0.2385951429605484, + -0.8751307725906372, + 1.2708275318145752, + 1.485723614692688, + 2.7529296875, + 1.3635951280593872, + -3.2782273292541504, + 2.349167585372925, + -1.6336205005645752, + -0.2049153596162796, + 0.28912025690078735, + 0.6291736364364624, + 0.0678885355591774, + 3.8587558269500732, + -0.2084793746471405, + 1.4928792715072632, + 1.4158761501312256, + 2.7266554832458496, + 1.2781285047531128, + -1.0845249891281128, + 1.4375944137573242, + 0.7710411548614502, + -1.3830958604812622, + 2.247267961502075, + -4.419378280639648, + 1.272594690322876, + -0.5320609211921692, + -2.740420341491699, + -0.3858875036239624, + -0.714117169380188, + 4.870936870574951, + 2.1019694805145264, + 1.2187209129333496, + 1.0261259078979492, + 1.6278250217437744, + -2.5981764793395996, + 0.7512555718421936, + 3.8927409648895264, + 1.8671060800552368, + -3.3280551433563232, + 1.060174822807312, + -1.4887230396270752, + 0.3156622052192688, + 1.6286039352416992, + -1.720422625541687, + -0.02909342385828495, + -0.295168936252594, + -0.4961169958114624, + 4.292910575866699, + 1.1348586082458496, + -1.9587751626968384, + 2.013485908508301, + -1.6122872829437256, + 1.6318126916885376, + -2.0703823566436768, + -4.4481024742126465, + 0.7110886573791504, + -0.0337553471326828, + 0.0873456671833992, + 2.181166887283325, + 4.4059624671936035, + 0.980654776096344, + 2.057783603668213, + 4.9925360679626465, + -0.9325474500656128, + 0.4560052752494812, + 1.3172200918197632, + -0.04277002066373825, + -1.7490931749343872, + 0.7110072374343872, + 0.1607607901096344, + 0.3605085015296936, + -1.2455531358718872, + 1.1545149087905884, + -0.8342459797859192, + 0.9775565266609192, + 0.9837471842765808, + -2.0616629123687744, + -2.111572265625, + 3.226016044616699, + -0.6067824363708496, + 0.2784106731414795, + -1.0451514720916748, + -0.5080043077468872, + 1.9294724464416504, + 0.5315173864364624, + -2.9388718605041504, + -0.7977702021598816, + -3.2931082248687744, + 1.4551130533218384, + 1.976330041885376, + -0.332272469997406, + -0.3480166494846344, + 0.882998526096344, + -1.6086193323135376, + 2.024181604385376, + 0.2140880823135376, + -0.7935267686843872, + -0.154203861951828, + 2.060105085372925, + -1.5383824110031128, + 1.5395042896270752, + 0.512454092502594, + -0.2208775132894516, + -0.1711251437664032, + 0.3434244692325592, + 0.4552118182182312, + -0.4803989827632904, + -3.960728168487549, + -0.4115862250328064, + 1.6047254800796509, + -0.9500209093093872, + 1.6055418252944946, + 2.061436176300049, + -1.0024302005767822, + -0.5639415979385376, + 2.719959020614624, + -2.9510788917541504, + 2.481747627258301, + -1.6947021484375, + -1.4765857458114624, + -2.2917306423187256, + -2.411327600479126, + 2.1026554107666016, + 3.3513009548187256, + 0.7086937427520752, + -0.293276846408844, + 1.591913104057312, + -2.788132429122925, + -3.893508195877075, + 0.7673514485359192, + -0.449521005153656, + -0.202241450548172, + -0.2815057635307312, + -0.3264508843421936, + -2.4775390625, + 1.8091285228729248, + 3.6573660373687744, + -0.0940638929605484, + -0.3987630307674408, + -1.8124070167541504, + 2.935105085372925, + 2.3059895038604736, + 0.00014597461267840117, + -0.0607561394572258, + -1.3252882957458496, + -1.2587425708770752, + -2.347182512283325, + 1.245128870010376, + -0.996820330619812, + 5.064871788024902, + -1.2862520217895508, + 1.6347423791885376, + 4.251960277557373, + -2.5990047454833984, + 3.4352214336395264, + -0.4777715802192688, + -0.4944894015789032, + -0.849307119846344, + -0.4931640625, + 1.2357410192489624, + 0.0034877231810241938, + 1.0851120948791504, + -2.1521809101104736, + -2.1413443088531494, + 0.6745387315750122, + -1.2703275680541992, + -2.7079379558563232, + 0.1128859743475914, + 0.1610630601644516, + 0.5646623969078064, + -4.069568634033203, + 4.344970703125, + 0.5476887822151184, + -0.0928431898355484, + 0.61669921875, + -1.8862769603729248, + 1.9824044704437256, + -0.7760300636291504, + -1.1389334201812744, + -3.988339424133301, + -0.3043619692325592, + -1.6863257884979248, + 0.879236102104187, + -1.9227585792541504, + -3.366001605987549, + -1.155389666557312, + 0.0557047538459301, + 4.887671947479248, + -1.8053617477416992, + -1.3906831741333008, + 4.137021064758301, + -3.019198417663574, + -0.9541712999343872, + 0.5850074291229248, + -0.4587809145450592, + -2.7059848308563232, + 0.0850568488240242, + 0.919805645942688, + -2.2991535663604736, + -1.053741455078125, + 0.705960214138031, + 1.2915620803833008, + -0.869384765625, + 0.9716099500656128, + -1.5106106996536255, + -1.2388392686843872, + 3.8610172271728516, + 1.6378812789916992, + -0.6462053656578064, + -0.1641264408826828, + 0.56982421875, + -0.069870725274086, + 2.807187080383301, + 2.623721122741699, + -2.243236780166626, + 0.0836704820394516, + -0.731259286403656, + 2.607933521270752, + -0.2189825177192688, + -0.6206345558166504, + -5.138113975524902, + 0.9742896556854248, + -0.0925176739692688, + -1.4239168167114258, + 0.1268833726644516, + 0.082443967461586, + 2.6575520038604736, + -4.223679542541504, + 1.327917218208313, + -1.7553943395614624, + 0.4875938892364502, + 1.521594762802124, + 2.7069790363311768, + -0.935918927192688, + -0.932675302028656, + -0.3442935049533844, + -3.0386905670166016, + 0.7318406105041504, + -0.199980229139328, + -4.26425313949585, + -0.0935407355427742, + -4.2249579429626465, + -0.856259286403656, + -0.620721697807312, + -2.3353214263916016, + -0.2492792010307312, + 0.8718029260635376, + -0.2770763635635376 + ], + "text_index": 0 + } + ] + }, + "usage": { + "total_tokens": 4 + }, + "request_id": "954841fa-daca-4ae9-abbd-319c25137097" + } + headers: + content-length: + - '29381' + content-type: + - application/json + date: + - Mon, 17 Nov 2025 08:31:24 GMT + req-arrive-time: + - '1763368284526' + req-cost-time: + - '80' + resp-start-time: + - '1763368284607' + server: + - istio-envoy + set-cookie: + - acw_tc=954841fa-daca-4ae9-abbd-319c251370977485c4b187653c927ff392af035ed8d8;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '74' + x-request-id: + - 954841fa-daca-4ae9-abbd-319c25137097 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_batch.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_batch.yaml new file mode 100644 index 000000000..cb7be807c --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_batch.yaml @@ -0,0 +1,3160 @@ +interactions: +- request: + body: |- + { + "model": "text-embedding-v1", + "parameters": {}, + "input": { + "texts": [ + "Hello", + "World" + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '88' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/embeddings/text-embedding/text-embedding + response: + body: + string: |- + { + "output": { + "embeddings": [ + { + "embedding": [ + -1.0437825918197632, + 5.208984375, + 3.0483806133270264, + -1.7897135019302368, + -2.0107421875, + -0.5939127802848816, + -0.6402180790901184, + -2.7659504413604736, + -0.4872232973575592, + -0.5003255009651184, + -2.3683269023895264, + 3.79296875, + 0.3487955629825592, + -1.0436197519302368, + -1.5984700918197632, + -1.6543782949447632, + -1.9565023183822632, + 1.1044921875, + -3.7015380859375, + 0.1591796875, + -0.7982584834098816, + 1.740234375, + 0.26715087890625, + -0.3363037109375, + -0.176025390625, + -1.6981405019760132, + -1.8727010488510132, + 0.50146484375, + 1.4395345449447632, + -1.0534261465072632, + -0.7273762822151184, + -2.8137614727020264, + -2.7665202617645264, + 0.2571614682674408, + 1.151123046875, + -0.3732096254825592, + -2.018310546875, + 1.9005635976791382, + -1.4200439453125, + 0.5047607421875, + 2.3299152851104736, + 0.20263671875, + 0.46600341796875, + -1.0908101797103882, + -0.7366536259651184, + -0.94683837890625, + 2.4463298320770264, + 1.54931640625, + 0.01171875, + -2.0797221660614014, + 1.8148294687271118, + -0.91552734375, + -2.0621745586395264, + -1.8029581308364868, + -1.78759765625, + -1.1920572519302368, + -2.6630046367645264, + 1.2800191640853882, + 0.9422200322151184, + -1.590087890625, + 0.02311197854578495, + -2.240234375, + -0.1511637419462204, + -0.0009562174673192203, + 2.196533203125, + -0.398681640625, + -0.2703450620174408, + 2.3843994140625, + -2.3636066913604736, + -0.5602620244026184, + 0.2176310271024704, + 0.5192057490348816, + -1.30908203125, + -1.4381510019302368, + 2.5067951679229736, + 0.0763346329331398, + 3.557373046875, + -1.8999837636947632, + 0.757568359375, + -1.11474609375, + -0.30706787109375, + -0.9635416865348816, + 0.01668294332921505, + 0.408203125, + 1.1787109375, + 3.0226237773895264, + -0.02164713479578495, + 1.3995767831802368, + 0.9200032353401184, + 1.9064127206802368, + -1.5211588144302368, + -0.81085205078125, + -1.1202799081802368, + 1.4695638418197632, + 2.0631511211395264, + 1.2824300527572632, + -2.2047932147979736, + 0.7141926884651184, + -0.081787109375, + -2.3951008319854736, + 0.3140462338924408, + 0.946533203125, + -2.1353352069854736, + -2.1199543476104736, + 0.3079427182674408, + -1.4871419668197632, + -0.1615397185087204, + -0.1338907927274704, + 1.4248046875, + -2.1759440898895264, + -0.6479288935661316, + 2.3179523944854736, + -0.351806640625, + 2.50244140625, + 2.87109375, + -2.7456157207489014, + 1.8252767324447632, + 2.8435871601104736, + 0.6106770634651184, + 0.755126953125, + 0.6344401240348816, + -0.3282063901424408, + -2.0535480976104736, + 0.7415364384651184, + -1.6216024160385132, + -0.5088908076286316, + -0.37805604934692383, + -3.8751628398895264, + -1.3352864980697632, + 1.4060872793197632, + 1.0225423574447632, + -0.4021809995174408, + -1.80712890625, + -0.2911376953125, + 0.3088785707950592, + -0.82574462890625, + -2.2967121601104736, + -1.5895589590072632, + 1.643310546875, + 2.9466145038604736, + 2.38037109375, + -0.845458984375, + 1.8376439809799194, + -2.670654296875, + 0.7732747197151184, + 0.6835123896598816, + -1.599853515625, + 1.4134114980697632, + -2.4401042461395264, + 2.3875324726104736, + -0.1285807341337204, + -1.3955078125, + -2.1788737773895264, + 0.3732096254825592, + 1.7733560800552368, + 3.9820148944854736, + 1.0907388925552368, + 3.5234375, + -0.4236043393611908, + 1.8657022714614868, + -0.9739888310432434, + 0.4479166567325592, + 3.0968730449676514, + 1.5779622793197632, + -0.4988199770450592, + -0.2865702211856842, + -0.390625, + 0.4572550356388092, + -2.046875, + -2.570648193359375, + 1.5114339590072632, + -0.3903096616268158, + -0.5442708134651184, + -0.0555013008415699, + -0.4124349057674408, + -3.646484375, + -2.2796223163604736, + -1.48779296875, + 0.2813924252986908, + -3.6014811992645264, + 1.9842122793197632, + 1.5662637948989868, + 2.5740559101104736, + -1.3502603769302368, + -0.07807668298482895, + 2.3487956523895264, + -1.5377603769302368, + 0.6429036259651184, + -0.3056233823299408, + 2.4908039569854736, + 1.3152261972427368, + -1.6622720956802368, + 0.8335774540901184, + 4.84765625, + -0.5217692255973816, + -0.8629820942878723, + -0.4986979067325592, + -0.3251139223575592, + 4.047200679779053, + -1.8084310293197632, + -1.08154296875, + 1.203125, + -1.3280843496322632, + -2.211669921875, + 0.7347005009651184, + -1.2334798574447632, + -0.308837890625, + -2.7638347148895264, + -0.7206013798713684, + -0.39208984375, + 1.5343729257583618, + -2.7534587383270264, + -0.6658528447151184, + 1.5018717050552368, + -2.296595335006714, + -3.6101887226104736, + -0.8375651240348816, + 0.847412109375, + 0.9769694209098816, + 1.1874593496322632, + -0.7069498896598816, + -0.1129557266831398, + 2.14501953125, + 0.2035725861787796, + 1.4856771230697632, + 0.514404296875, + 0.7357380986213684, + -0.9755859375, + 1.99267578125, + -1.0207926034927368, + 0.0732472762465477, + 0.6726887822151184, + 1.6357828378677368, + -0.4523417055606842, + -0.9366582036018372, + -2.0524089336395264, + -1.3291015625, + 0.1044108048081398, + 1.2189127206802368, + -0.81982421875, + -3.0128581523895264, + 0.79541015625, + 1.0281575918197632, + -2.2424418926239014, + -0.66571044921875, + -0.7776692509651184, + 1.8440755605697632, + 1.2608438730239868, + -4.218099117279053, + -2.1682941913604736, + -0.11611238867044449, + 0.22216796875, + 0.1201985701918602, + -0.9547932744026184, + -0.4632568359375, + -0.6932780146598816, + 1.4283040761947632, + 1.3046060800552368, + -0.2123209685087204, + 1.9138997793197632, + -0.2194010466337204, + 0.0540364570915699, + -0.5488001704216003, + -2.4475910663604736, + -1.5031331777572632, + -0.1033121719956398, + -0.02866617776453495, + 1.1187337636947632, + -3.4391276836395264, + -0.1357421875, + 0.3019205629825592, + 1.6315103769302368, + -0.7384440302848816, + -0.9801432490348816, + -0.8188679814338684, + 0.1777547150850296, + -1.6250814199447632, + 4.817708492279053, + -1.0948079824447632, + 1.2882486581802368, + -2.2350261211395264, + 2.1018879413604736, + 0.5813801884651184, + -1.9080301523208618, + 0.1796875, + -0.02339681051671505, + 0.8277485966682434, + 0.2884521484375, + -0.0065104165114462376, + 0.3547770082950592, + 2.167236328125, + 0.8970540165901184, + 0.8204600214958191, + -2.6949870586395264, + 2.4007160663604736, + 5.286020755767822, + 0.9459635615348816, + 0.440673828125, + 0.34619140625, + 1.1531168222427368, + -0.03240966796875, + 3.1873371601104736, + 2.6909892559051514, + -0.9205729365348816, + -1.1572265625, + -0.0061442055739462376, + -1.0853677988052368, + 2.4497478008270264, + -3.4275715351104736, + 0.5407511591911316, + 1.310302734375, + -0.6826985478401184, + 0.7346394658088684, + -2.0486652851104736, + -0.6996256709098816, + 0.4278615415096283, + 2.2882487773895264, + -1.3000894784927368, + 0.0357259102165699, + 0.2476399689912796, + -2.9003093242645264, + 0.6381022334098816, + 0.34375, + -0.1215413436293602, + 1.2150064706802368, + 1.48583984375, + 1.5438232421875, + 0.468017578125, + 0.1669514924287796, + 2.7672526836395264, + -2.460285186767578, + -0.4871012270450592, + 1.7548828125, + -1.10791015625, + 2.992431640625, + -0.235107421875, + -1.4713541269302368, + 1.9170328378677368, + 0.2747395932674408, + 0.8755289912223816, + -2.752197265625, + 0.8196614384651184, + -0.04638671875, + -2.23876953125, + -2.5696818828582764, + 1.042236328125, + -2.416015625, + 1.6056112051010132, + 1.0538736581802368, + 2.9086506366729736, + -1.7919921875, + 0.2552083432674408, + -0.5250651240348816, + 0.97216796875, + 2.422607421875, + 1.9771322011947632, + -0.643798828125, + 0.2064564973115921, + 0.5330403447151184, + -1.79376220703125, + 0.2486979216337204, + -0.59521484375, + 1.0850830078125, + -0.0496419258415699, + -0.0673421248793602, + -0.0604654960334301, + 0.5447590947151184, + 0.8350830078125, + -0.0343526192009449, + -0.68670654296875, + -2.1611328125, + 0.6564216613769531, + 0.943603515625, + -0.1202799454331398, + 0.5027377009391785, + -0.1613260954618454, + -2.58154296875, + 0.9064534306526184, + -0.1763509064912796, + 0.3727213442325592, + 3.069091796875, + 0.92724609375, + 1.4399007558822632, + -0.4454752504825592, + -0.1066080704331398, + -1.8095703125, + -0.16638438403606415, + 1.2962239980697632, + -0.28369140625, + -0.23486328125, + -2.07470703125, + 0.0453084297478199, + -1.9781900644302368, + 1.31060791015625, + 1.00537109375, + 2.7393391132354736, + -0.1718190461397171, + -3.7805988788604736, + 3.1531169414520264, + -0.24169921875, + 3.2096354961395264, + -4.31201171875, + -2.36669921875, + -0.4263509213924408, + -1.8436483144760132, + -0.9044596552848816, + 0.2061360627412796, + -2.4785969257354736, + 0.8951823115348816, + 0.9830729365348816, + -0.1327107697725296, + 0.0330810546875, + -0.5087483525276184, + -0.5981038212776184, + 3.93701171875, + 0.7850341796875, + 1.9814859628677368, + -2.8662109375, + 3.68316650390625, + 2.8590495586395264, + 0.0778401717543602, + -3.458984375, + -0.04718017578125, + 0.7032877802848816, + -1.8915201425552368, + 1.1765950918197632, + 1.208984375, + -0.0107421875, + -0.9217936396598816, + 0.7982177734375, + 0.249481201171875, + 2.3522136211395264, + 0.2554931640625, + -2.6689453125, + -1.65576171875, + -0.445037841796875, + 4.522623538970947, + 3.130096435546875, + -3.125, + 1.4228109121322632, + -1.9988123178482056, + 1.7047525644302368, + -0.4781900942325592, + 1.3216959238052368, + -0.9195963740348816, + -0.5480143427848816, + -3.2122395038604736, + -1.602294921875, + 3.0079753398895264, + 1.5639444589614868, + 2.630859375, + 2.719207763671875, + -0.1033528670668602, + 0.0784505233168602, + 0.2406819611787796, + 1.0623372793197632, + 0.318359375, + -1.5343831777572632, + -1.8002115488052368, + -0.58203125, + -1.1727193593978882, + 0.5474446415901184, + -0.03055826760828495, + -0.5785929560661316, + -0.3643798828125, + -0.5377604365348816, + 0.9501953125, + 0.286865234375, + -0.7921142578125, + -1.4527994394302368, + 1.2449544668197632, + -0.5137532353401184, + 2.7176921367645264, + 0.5640055537223816, + -1.78857421875, + -0.88079833984375, + 0.8000895380973816, + -1.8541666269302368, + 2.8084309101104736, + -1.3023275136947632, + 0.8399658203125, + 0.1149088516831398, + 1.16650390625, + -0.1254475861787796, + 0.438720703125, + 0.3162841796875, + -0.276153564453125, + -0.8234049677848816, + -0.1221110001206398, + 1.95068359375, + 1.6261392831802368, + -2.1534831523895264, + -0.66259765625, + 0.0627034530043602, + -1.2908529043197632, + 0.2274169921875, + 3.1360676288604736, + 0.681884765625, + 0.02002970315515995, + 0.8530349731445312, + -1.7496744394302368, + 0.14501953125, + 2.5872395038604736, + -1.353515625, + -3.7503254413604736, + 0.5338541865348816, + 0.6302083134651184, + -1.201171875, + 3.8274738788604736, + 0.160400390625, + -0.5589192509651184, + -2.0308430194854736, + -0.7666829228401184, + 2.8995769023895264, + 2.7725422382354736, + -0.9990641474723816, + 1.3033651113510132, + -1.9114583730697632, + 1.9081217050552368, + 0.7579701542854309, + 0.831787109375, + 1.4171549081802368, + 1.2594400644302368, + 0.80712890625, + -2.2040202617645264, + 1.31280517578125, + 1.3672689199447632, + -0.9171549677848816, + -1.5859375, + 1.1164144277572632, + -1.7374674081802368, + -0.7958170771598816, + -3.2200520038604736, + 0.2856241762638092, + -1.2498372793197632, + -1.65478515625, + -1.163909912109375, + -0.0711466446518898, + -1.059814453125, + 0.9320475459098816, + -2.1233723163604736, + -3.708984375, + 1.6126199960708618, + -0.3184610903263092, + -0.0383707694709301, + -1.7701822519302368, + -0.3790690004825592, + 1.7845052480697632, + 0.6000162959098816, + 0.399017333984375, + 0.2493082731962204, + 0.5345051884651184, + 0.724609375, + 1.9015299081802368, + 1.2054544687271118, + 1.5527547597885132, + -1.8077188730239868, + 2.0020344257354736, + -0.993408203125, + -0.1898600310087204, + -0.8453776240348816, + 1.96728515625, + 1.2574869394302368, + 0.0848795548081398, + 1.0167642831802368, + -0.85546875, + -1.27734375, + 4.586751461029053, + -0.370849609375, + 0.370574951171875, + -1.3370767831802368, + 3.11767578125, + 0.4466349184513092, + 1.202392578125, + 1.2933756113052368, + -1.3026357889175415, + 0.5472005009651184, + -1.0838826894760132, + -0.7659098505973816, + -1.2343343496322632, + 1.1088358163833618, + -2.6698505878448486, + 1.8351236581802368, + 0.752197265625, + -0.2366587370634079, + 0.75634765625, + -0.4410807192325592, + 0.1181233748793602, + 4.268880367279053, + -0.09674072265625, + 2.322998046875, + -1.3715006113052368, + -3.9664714336395264, + -0.000830789387691766, + -0.2488606721162796, + 0.5879719853401184, + -1.7414652109146118, + 0.2180989533662796, + 0.8269450068473816, + -2.9070942401885986, + 0.89923095703125, + 2.6533203125, + -1.3442789316177368, + -0.6842803955078125, + 0.9073893427848816, + 1.9412435293197632, + -2.1569011211395264, + 1.7236328125, + 0.7340494990348816, + 0.6562398076057434, + -1.6529947519302368, + 0.3235677182674408, + 1.0689290761947632, + 1.7105712890625, + -0.4869791567325592, + -1.0245767831802368, + -0.5927734375, + 1.3103841543197632, + -1.9886068105697632, + -0.909912109375, + -0.2805989682674408, + 1.6778970956802368, + -1.1116943359375, + 4.689615726470947, + -1.82373046875, + -4.615234375, + 0.30810546875, + 1.6267904043197632, + -0.7491047978401184, + 1.923583984375, + -1.9978841543197632, + -1.4158529043197632, + 1.86865234375, + -1.563720703125, + 1.1084798574447632, + 1.5581868886947632, + 1.1704915761947632, + -0.01798502542078495, + -1.4170175790786743, + 2.7340495586395264, + 1.4688314199447632, + 0.8686726689338684, + 3.7491862773895264, + -0.1181640625, + 3.064697265625, + 0.4446309506893158, + 1.5658365488052368, + -0.0502522774040699, + -2.5445148944854736, + 0.1055094376206398, + 0.380584716796875, + -0.5712077021598816, + 2.75537109375, + -0.5156453251838684, + 0.09423828125, + -0.5009765625, + 1.1736654043197632, + 5.020182132720947, + -0.02507527731359005, + -1.8588460683822632, + 0.4169209897518158, + -1.1244302988052368, + -1.5348306894302368, + 0.1017049178481102, + 1.4117838144302368, + 1.0595703125, + -0.6854451298713684, + 1.8494058847427368, + 0.5443115234375, + -0.364990234375, + -0.0056966147385537624, + -0.3805338442325592, + -1.0530599355697632, + -0.013020833022892475, + 0.2161458283662796, + -0.2816365659236908, + 0.6986287236213684, + 0.5379231572151184, + 1.060546875, + -3.3739421367645264, + -1.4661458730697632, + -2.0830078125, + 1.5794271230697632, + 0.7119140625, + -1.2521768808364868, + 0.6951497197151184, + 0.8185221552848816, + 0.7263997197151184, + 2.3624675273895264, + -1.77197265625, + 0.4767659604549408, + -0.303955078125, + -1.4813638925552368, + 0.1255696564912796, + 0.121307373046875, + -2.5044353008270264, + -0.1254018098115921, + 0.4052327573299408, + -1.0469564199447632, + -0.488525390625, + 0.5351969599723816, + 1.3267822265625, + 0.2099609375, + -1.306884765625, + 2.7389323711395264, + -1.0246835947036743, + 1.25244140625, + 1.6424764394760132, + -1.388671875, + -2.5428059101104736, + -2.0154876708984375, + 2.8704426288604736, + -1.8040364980697632, + 4.0166015625, + 0.0624593086540699, + 0.2607930600643158, + 0.2862955629825592, + -0.3961080014705658, + -2.2373859882354736, + 2.3089191913604736, + -0.2511393129825592, + -0.7165324091911316, + -2.131591796875, + -0.782470703125, + 2.0713703632354736, + 2.1123046875, + -3.5719807147979736, + -0.1931966096162796, + -0.1740315705537796, + -0.2099609375, + -0.6945393681526184, + -2.732666015625, + 0.3092447817325592, + -5.400634765625, + -0.06439208984375, + 3.1227214336395264, + 0.0583903007209301, + 1.5850015878677368, + -0.908721923828125, + -0.2467854768037796, + -2.24267578125, + 0.5954182744026184, + -0.7605794072151184, + 0.531982421875, + -1.8658853769302368, + 0.19091796875, + 0.1256510466337204, + 3.9253742694854736, + 0.34375, + 1.42626953125, + 0.26220703125, + 1.20703125, + 1.001220703125, + 1.6074371337890625, + -0.898895263671875, + 1.408203125, + 1.4804280996322632, + 3.3951823711395264, + 1.96490478515625, + 0.8626708984375, + -3.7301433086395264, + -1.2884927988052368, + -2.25439453125, + 1.79034423828125, + -1.0610758066177368, + 1.331298828125, + 0.22216796875, + -3.3813438415527344, + -0.5761311650276184, + -1.8743489980697632, + 2.486328125, + -2.15966796875, + -0.31884765625, + 1.6676839590072632, + 0.3129068911075592, + 0.9090983271598816, + 0.3746744692325592, + -3.5819499492645264, + 0.2115885466337204, + 1.1244302988052368, + -1.0380859375, + -1.5430908203125, + 0.73876953125, + -2.2578532695770264, + 2.0296223163604736, + 0.821044921875, + -3.3785808086395264, + -2.14306640625, + -0.4217936098575592, + -1.0262044668197632, + -0.1574300080537796, + -0.2648111879825592, + 1.5247396230697632, + -0.9878336787223816, + 2.5402019023895264, + 1.5361328125, + 1.480712890625, + -1.5904134511947632, + 1.2605794668197632, + -0.2682901918888092, + -1.7521158456802368, + 1.9033203125, + 1.87060546875, + 0.7194010615348816, + 1.1350911855697632, + 0.4208984375, + -0.2190755158662796, + -0.452880859375, + -1.4596353769302368, + 3.19769287109375, + -4.994140625, + -0.4820963442325592, + 1.3028564453125, + 2.9154460430145264, + -1.5428873300552368, + -0.5004571080207825, + 0.9153645634651184, + -0.0665690079331398, + 3.5384113788604736, + 2.7854816913604736, + -2.3937175273895264, + -2.0164794921875, + -1.6605631113052368, + 1.9773355722427368, + 1.9108072519302368, + 0.2122395783662796, + 1.2054647207260132, + -2.0472004413604736, + -0.6030070185661316, + 0.7823893427848816, + -1.3662109375, + -0.3574422299861908, + -0.172119140625, + 0.4182942807674408, + 1.151123046875, + -2.4373371601104736, + 1.0115762948989868, + -0.518646240234375, + 0.19927978515625, + -0.0916341170668602, + 1.9765625, + 1.62091064453125, + -1.578857421875, + 2.5843098163604736, + -0.6085205078125, + -0.3740437924861908, + -0.1893717497587204, + -0.1869303435087204, + 0.0027262370567768812, + -0.7706298828125, + 1.7317708730697632, + -0.79638671875, + 0.6396992802619934, + 3.178955078125, + -1.0211181640625, + -1.2320760488510132, + -0.6369984745979309, + -2.13623046875, + -1.82373046875, + -1.2451986074447632, + -0.4947102963924408, + 1.0501302480697632, + 2.0663654804229736, + 1.69677734375, + 0.2524566650390625, + -0.5750325322151184, + 2.7976887226104736, + -3.8816936016082764, + 1.5338134765625, + -1.7222900390625, + 2.001368284225464, + -0.84326171875, + -1.6532796621322632, + -0.6949869990348816, + -2.3616535663604736, + 1.3660074472427368, + 2.3185222148895264, + -0.7171223759651184, + 2.5414226055145264, + 0.7764485478401184, + 3.1259765625, + 2.31982421875, + -1.0426025390625, + 2.6793010234832764, + 1.0287271738052368, + 1.5795084238052368, + -0.17437744140625, + 1.072265625, + -1.60595703125, + -3.8697917461395264, + 1.1746419668197632, + -0.7988688349723816, + 0.5921223759651184, + -4.65869140625, + 0.26220703125, + -4.75537109375, + 2.9033203125, + 1.4641927480697632, + -0.510498046875, + 0.2890218198299408, + 0.2790934145450592, + -0.6401774287223816, + -0.08522924035787582, + 2.0354816913604736, + 0.9573567509651184, + -0.1905110627412796, + -3.0022785663604736, + 1.2254232168197632, + -1.4579263925552368, + 0.426025390625, + -0.4998372495174408, + -0.6013590693473816, + 4.194010257720947, + 0.7578125, + 0.5980224609375, + -0.3982747495174408, + 0.2145182341337204, + -0.9490559697151184, + 1.2006429433822632, + 0.81317138671875, + -0.6353861689567566, + -1.626708984375, + 1.3731282949447632, + 0.8265787959098816, + -0.3956705629825592, + 4.010823726654053, + -2.697265625, + 1.2669271230697632, + -0.1080729141831398, + -0.8262545466423035, + -1.1178792715072632, + -5.090494632720947, + -0.1152750626206398, + 0.6961262822151184, + -1.96630859375, + -0.560302734375, + 0.061279296875, + 0.4269205629825592, + -2.4959309101104736, + -0.2258707731962204, + -0.9126790165901184, + 2.3517253398895264, + -1.8975830078125, + -0.7316080927848816, + 0.8065592646598816, + 1.5955404043197632, + -0.1742451936006546, + 0.6259765625, + 0.7077229619026184, + 0.728759765625, + 1.6982421875, + 1.3357747793197632, + -3.643310546875, + -5.300130367279053, + 0.2361653596162796, + 1.7271322011947632, + 0.6884765625, + -1.6240234375, + -2.7005207538604736, + 0.8406575322151184, + -0.8248392939567566, + -2.1175129413604736, + 2.1979167461395264, + 0.1670430451631546, + 0.673583984375, + 4.198893070220947, + -0.7242431640625, + -1.7486978769302368, + 0.2232259064912796, + -0.6447398066520691, + 0.32177734375, + 0.3474934995174408, + -0.960205078125, + 3.3272297382354736, + 1.1473795175552368, + 2.5221354961395264, + -0.5245564579963684, + 1.208251953125, + 1.9794921875, + -1.2893880605697632, + 4.298583984375, + 0.8271484375, + -1.3666954040527344, + -2.3138020038604736, + 1.1731363534927368, + -3.1067707538604736, + 1.2347005605697632, + -5.502278804779053, + 0.6997477412223816, + 1.5725911855697632, + -0.407470703125, + -2.6214191913604736, + 0.4256184995174408, + 3.306396484375, + 2.3601481914520264, + -2.2877604961395264, + -0.02766927145421505, + -1.7822061777114868, + -1.1253255605697632, + -0.1564127653837204, + 0.4358724057674408, + 0.7373046875, + 4.5537109375, + 0.8257344365119934, + 1.1094970703125, + 0.7208659052848816, + 0.2884114682674408, + -4.852864742279053, + -0.4392496645450592, + 3.74743914604187, + -0.3536783754825592, + -0.7396647334098816, + -1.2325845956802368, + -0.2475178986787796, + 1.1541341543197632, + -2.29156494140625, + 0.6560872197151184, + 0.3343505859375, + -0.1653645783662796, + -0.274566650390625, + -0.9667155146598816, + 0.161865234375, + -0.0568440742790699, + -1.15625, + 0.5687662959098816, + -0.6761881709098816, + -0.5434773564338684, + -4.094400882720947, + -0.2001851350069046, + 1.2003580331802368, + 2.341156005859375, + 0.8033447265625, + -6.236979007720947, + 1.1416015625, + 0.8027750849723816, + 0.0077311196364462376, + -2.96728515625, + -1.5432943105697632, + 1.2284647226333618, + 2.1178386211395264, + 7.9990234375, + -0.45751953125, + 2.079833984375, + 1.0010579824447632, + -1.7339681386947632, + -0.2251790314912796, + -1.7307943105697632, + -0.6134440302848816, + -1.3745931386947632, + 0.5284830927848816, + -0.6815592646598816, + 0.7414347529411316, + -1.0572103261947632, + -2.0654704570770264, + 1.1826171875, + 0.7122395634651184, + 1.17333984375, + 2.5113525390625, + 5.738932132720947, + 0.8865610957145691, + 0.7584635615348816, + 0.3927408754825592, + -2.65625, + -1.5233154296875, + -4.887044429779053, + -1.9007161855697632, + -1.9679971933364868, + -4.0126953125, + 1.8024088144302368, + 2.5199382305145264, + -0.2877095639705658, + 0.8981119990348816, + 0.86859130859375, + 1.783935546875, + -0.0633951798081398, + -2.8722331523895264, + 0.9639485478401184, + -0.3280843198299408, + -0.4488932192325592, + 2.80328369140625, + 1.0680338144302368, + -1.3548177480697632, + -1.2504678964614868, + -1.0668538808822632, + 0.3219400942325592, + 2.1875813007354736, + 0.38253021240234375, + -1.4117838144302368, + -0.9586639404296875, + 0.7120768427848816, + -1.9462890625, + -0.333251953125, + 1.2964935302734375, + 0.5681965947151184, + 0.8936360478401184, + 2.2108561992645264, + 1.1758626699447632, + 0.2845458984375, + -0.3004557192325592, + 0.3618977963924408, + 0.234375, + 2.1199543476104736, + 0.20085017383098602, + -0.4558817446231842, + 2.1886394023895264, + -0.1282552033662796, + -1.7059732675552368, + 1.2328287363052368, + -0.5408121943473816, + 3.1536457538604736, + 0.1957600861787796, + -0.0984700545668602, + -0.5130208134651184, + 0.36376953125, + -0.3418019711971283, + 1.88427734375, + 2.05419921875, + 2.2529296875, + -0.8450520634651184, + 1.1310628652572632, + -0.3033345639705658, + -0.5384114384651184, + -0.8028971552848816, + -3.6324055194854736, + 0.50244140625, + 1.2470703125, + -0.33282470703125, + -1.243408203125, + -1.6170247793197632, + 0.0677897110581398, + -0.4815267026424408, + 3.1886394023895264, + 1.6232095956802368, + -1.3829345703125, + -0.5292561650276184, + 2.1648762226104736, + 2.277099609375, + -0.7683868408203125, + -1.4047037363052368, + -0.9195963740348816, + 0.84661865234375, + 1.4560140371322632, + 2.0504558086395264, + -1.5343424081802368, + 1.8603515625, + 0.140625, + -0.765625, + -0.262451171875, + -1.1022542715072632, + -1.408447265625, + 0.5013020634651184, + 2.8849284648895264, + -0.4423014223575592, + -0.0815633162856102, + 0.0908203125, + 1.13861083984375, + -1.28936767578125, + 2.6173503398895264, + 0.0370279960334301, + 1.2606607675552368, + 0.208984375, + 1.9405924081802368, + 0.69287109375, + 14.5625, + 1.2239583730697632, + 0.28662109375, + -1.3138021230697632, + -1.4525502920150757, + -0.7432047724723816, + -0.8411458134651184, + -1.2473958730697632, + -1.3426513671875, + 1.5040689706802368, + -2.1834309101104736, + -1.6722005605697632, + 0.4108377993106842, + 1.212127685546875, + 0.9342041015625, + -0.673858642578125, + -1.449951171875, + -1.04296875, + 2.4139530658721924, + -2.1127521991729736, + 1.279052734375, + -1.9855142831802368, + -1.4099935293197632, + -0.0739339217543602, + 2.2881877422332764, + -1.8453775644302368, + 0.6524658203125, + -0.9646809697151184, + -3.072265625, + 1.5819498300552368, + -0.4691568911075592, + -0.72998046875, + -1.0283203125, + 2.18841552734375, + -0.6009114384651184, + 3.1771914958953857, + -0.0915323868393898, + 1.6569010019302368, + -0.2998453676700592, + -0.87371826171875, + 0.2759297788143158, + -1.51904296875, + 1.2301839590072632, + 2.0265300273895264, + 0.2421671599149704, + -2.5589191913604736, + -1.349207878112793, + -0.8055827021598816, + -0.9986165165901184, + -0.3592122495174408, + -1.9230142831802368, + -0.09527587890625, + -3.435546875, + 0.2232411652803421, + -0.1467488557100296, + 0.6502278447151184, + -0.0965983048081398, + 2.2198894023895264, + -1.0568033456802368, + -0.7499186396598816, + 1.0361328125, + 0.4499918520450592, + 0.2298583984375, + 1.0234375, + -1.283935546875, + 0.8971354365348816, + 2.3628132343292236, + 0.4563191831111908, + 0.181640625, + -2.3194987773895264, + 4.122232913970947, + -2.233154296875, + 0.736083984375, + -0.1957194060087204, + -1.24896240234375, + -2.7161457538604736, + 0.0644938126206398, + 1.2127685546875, + 0.76873779296875, + -0.265625, + -2.9386394023895264, + -1.12109375, + -0.8196614384651184, + -1.6858316659927368, + -0.1387939453125, + -0.1307169646024704, + 2.0587565898895264, + 4.027018070220947, + -0.9947916865348816, + 0.3624674379825592, + -0.10546875, + 2.089202880859375, + -0.086181640625, + 1.9269205331802368, + 1.25146484375, + 0.0198974609375, + -2.0675456523895264, + 0.4357096254825592, + 1.9480794668197632, + -0.9580078125, + 0.0644887313246727, + 0.6841633915901184, + 0.5400593876838684, + -0.3794759213924408, + -0.0052490234375, + -2.5579426288604736, + 1.9994100332260132, + 0.6110432744026184, + 1.9547525644302368, + -2.8011066913604736, + -1.04052734375, + -3.5999348163604736, + 2.6137778759002686, + -3.11962890625, + 0.9368082880973816, + 0.8477122187614441, + -0.7838541865348816, + -0.3616536557674408, + 0.030517578125, + -1.3141275644302368, + -1.451507568359375, + -3.0333659648895264, + -2.0616862773895264, + -2.3932292461395264, + -0.8172200322151184, + 0.919189453125, + 0.5793864130973816, + 1.6997884511947632, + 2.7669270038604736, + 0.8114420771598816, + -1.7355142831802368, + 0.722412109375, + -1.0304158926010132, + -0.7116292119026184, + 1.7469888925552368, + 1.2528482675552368, + -0.71527099609375, + 3.341583251953125, + 0.45875295996665955, + 1.9313150644302368, + 1.93310546875, + 3.6925456523895264, + 0.9977009892463684, + -0.883056640625, + 2.80078125, + -0.2233123779296875, + 0.5556793212890625, + 0.55419921875, + -3.320037841796875, + -0.7768147587776184, + 0.23583984375, + -1.4163411855697632, + -0.598876953125, + -0.3929036557674408, + 3.38226318359375, + 2.0315349102020264, + 0.3389485776424408, + 2.5431315898895264, + 0.7686360478401184, + -0.4028727114200592, + 0.68212890625, + 5.153482913970947, + 1.2242838144302368, + -1.5044759511947632, + 0.7888590693473816, + -1.5934244394302368, + 0.5234375, + 0.4384765625, + -0.2710723876953125, + 0.01676432229578495, + -2.0953876972198486, + 0.9134114384651184, + 3.1267497539520264, + 1.0593668222427368, + -1.6353353261947632, + 3.5231120586395264, + -2.3819172382354736, + 1.108642578125, + -1.0930989980697632, + -3.2893879413604736, + 0.6260986328125, + -0.9296671748161316, + 1.3317056894302368, + 1.3350931406021118, + 3.4231464862823486, + -0.7701823115348816, + 2.8321940898895264, + 4.015299320220947, + 0.0050455727614462376, + 0.1435139924287796, + 1.4527994394302368, + -0.9206135869026184, + -1.5110677480697632, + -0.0638427734375, + 2.47998046875, + -0.2955220639705658, + -1.5840657949447632, + 0.6097819209098816, + -1.5342611074447632, + -0.3465779721736908, + 0.7701823115348816, + -1.9710286855697632, + -2.0731201171875, + 2.6271564960479736, + -1.8622640371322632, + 0.8784189224243164, + 0.8372395634651184, + 0.7748616337776184, + 1.9686483144760132, + 0.4084269106388092, + -3.161376953125, + -0.7157389521598816, + -2.2430012226104736, + 1.1867269277572632, + 2.3043620586395264, + 0.7374369502067566, + -0.6474609375, + 1.6048177480697632, + -0.5329996943473816, + 0.1266682893037796, + -0.7640787959098816, + -1.4488931894302368, + -0.928466796875, + 2.27783203125, + -1.8602091073989868, + 1.580810546875, + -0.8603515625, + 0.8955078125, + -0.8114216923713684, + -0.1944987028837204, + 0.2391459196805954, + -0.8686930537223816, + -1.804931640625, + 0.8975830078125, + 0.7810897827148438, + -0.014363606460392475, + 0.7579053044319153, + 1.8086141347885132, + -0.4706230163574219, + 1.1243489980697632, + 2.3466796875, + -2.5310871601104736, + 1.834228515625, + -0.67529296875, + -1.494873046875, + -0.9285685420036316, + -3.07958984375, + -0.00876617431640625, + 0.2875569760799408, + -0.434326171875, + 0.381103515625, + 0.0354410819709301, + -1.3751627206802368, + -1.041015625, + -0.7232258915901184, + 1.2014974355697632, + -0.1316731721162796, + 1.6656900644302368, + -0.4601236879825592, + -2.0, + 1.9532064199447632, + 1.1712239980697632, + -0.0294189453125, + -0.90771484375, + 0.7254231572151184, + 3.1236979961395264, + 1.4259033203125, + 0.000242372349021025, + 0.302978515625, + -0.2598470151424408, + 0.31365966796875, + -1.8043212890625, + 0.8234456181526184, + -1.6043294668197632, + 3.3134765625, + -1.0089111328125, + 2.0794270038604736, + 3.30126953125, + -2.2498371601104736, + 4.355794429779053, + -0.6466471552848816, + -0.948486328125, + -1.619873046875, + 0.25537109375, + 1.5762939453125, + -1.5616861581802368, + 1.2381795644760132, + -1.178466796875, + -3.566319704055786, + 0.144775390625, + -2.2115275859832764, + -2.363037109375, + 2.3971354961395264, + 0.95751953125, + 0.0382080078125, + -4.230143070220947, + 1.3733724355697632, + -0.9209797978401184, + 0.3843994140625, + 1.2259114980697632, + -2.1998698711395264, + 1.55078125, + -3.1217448711395264, + -0.5427653193473816, + -3.9243571758270264, + 0.03955078125, + -0.6126708984375, + 0.808349609375, + -0.7416178584098816, + -1.301025390625, + -1.691162109375, + 0.31878662109375, + 3.1605632305145264, + -1.5086263418197632, + -1.59375, + 2.5550944805145264, + -1.1651763916015625, + -2.125, + 0.4337565004825592, + -0.4171142578125, + -2.4868977069854736, + -0.60009765625, + 1.95068359375, + -1.0276693105697632, + -0.6745198369026184, + -0.3234049379825592, + -0.9936116337776184, + -1.1002197265625, + 2.587158203125, + 0.0981038436293602, + -1.3958333730697632, + 1.7902017831802368, + 1.4197591543197632, + 0.1495259553194046, + -0.4632161557674408, + 0.474853515625, + -0.6490885615348816, + 0.6792399287223816, + 2.6905109882354736, + 1.3945821523666382, + -0.1129557266831398, + -0.6642252802848816, + 2.791015625, + 0.00390625, + -0.5370686650276184, + -5.376302242279053, + -0.4007975161075592, + -0.7074381709098816, + -2.508056640625, + 0.2886556088924408, + -0.4637044370174408, + 2.7317707538604736, + -2.9388020038604736, + 0.4822591245174408, + -3.1368815898895264, + -0.8689982295036316, + 0.4457193911075592, + 2.4143879413604736, + -0.0890299454331398, + -1.5273030996322632, + 0.9338887333869934, + -2.2750651836395264, + -0.445068359375, + 0.1016438826918602, + 1.1897176504135132, + -0.7991536259651184, + -3.914794921875, + 0.0607096366584301, + 0.8125, + -1.1759847402572632, + 0.8174641728401184, + 1.0432943105697632, + -0.5885213017463684 + ], + "text_index": 0 + }, + { + "embedding": [ + -2.09619140625, + -1.8100992441177368, + -1.3253173828125, + 0.412506103515625, + 1.5400390625, + 2.15234375, + -0.2132161408662796, + 3.7063801288604736, + -0.71533203125, + 1.7438150644302368, + -1.52783203125, + 1.6175943613052368, + 2.6160480976104736, + -1.9007161855697632, + 0.3190511167049408, + 1.0920003652572632, + -2.085693359375, + 4.215738773345947, + 2.5715739727020264, + -2.0916340351104736, + 0.6534830927848816, + 0.3893636167049408, + -0.7942708134651184, + 0.403564453125, + 4.508951663970947, + 2.2747395038604736, + 0.65423583984375, + -1.63037109375, + -2.6028645038604736, + -0.27294921875, + -0.2384440153837204, + -2.1851806640625, + 0.0570475272834301, + -1.1279296875, + 3.0948078632354736, + -0.5179036259651184, + 1.2675985097885132, + -2.2226459980010986, + 1.8523355722427368, + 1.32666015625, + 0.0692545548081398, + -1.1324869394302368, + 0.6258952021598816, + -1.8687337636947632, + 0.65850830078125, + 0.3900960385799408, + 0.6061299443244934, + -0.0572408027946949, + 1.2294921875, + -0.87896728515625, + -0.324493408203125, + 0.3079427182674408, + -1.9827474355697632, + -1.36505126953125, + 0.5223388671875, + -0.1090494766831398, + -0.0440266914665699, + -0.9929301142692566, + -0.389404296875, + 0.7919108271598816, + 3.6555988788604736, + -1.0992025136947632, + -2.2902424335479736, + 0.84765625, + -2.12255859375, + 1.5164388418197632, + 0.6730855107307434, + -0.6036784052848816, + -3.2189128398895264, + -0.0362548828125, + 0.7600504755973816, + -1.17578125, + 1.7428385019302368, + 1.0100911855697632, + 1.0571695566177368, + -0.0551350899040699, + 0.7562662959098816, + 0.2642008364200592, + 0.9979655146598816, + 0.7236328125, + 0.10943603515625, + -0.4239095151424408, + 2.6251628398895264, + -3.3116047382354736, + -0.3605143129825592, + 2.8565266132354736, + 0.8728840947151184, + 1.2055460214614868, + 2.2652385234832764, + 2.1546223163604736, + -4.139974117279053, + 0.2967529296875, + -1.0728353261947632, + 1.3896484375, + 1.7239583730697632, + 1.6673583984375, + -1.4702554941177368, + -1.2291666269302368, + -2.5448405742645264, + -1.6783853769302368, + 0.2000834196805954, + 0.4754231870174408, + -1.1063232421875, + -0.2267252653837204, + 1.6335042715072632, + -2.4248046875, + -1.9032388925552368, + 1.0878702402114868, + 1.3844400644302368, + 1.6712239980697632, + -1.2265625, + -1.717041015625, + -1.070068359375, + -0.6559244990348816, + 3.826171875, + -0.9632161259651184, + -0.01619466207921505, + 0.5890299677848816, + -2.2356770038604736, + -1.9357095956802368, + -1.6891275644302368, + -0.7659505009651184, + -2.5618488788604736, + -0.4116872251033783, + -1.3818563222885132, + -1.5077718496322632, + -1.8666831254959106, + -0.9777018427848816, + -0.2189127653837204, + 0.5568034052848816, + 0.4855143129825592, + 1.7692056894302368, + -0.9444987177848816, + 1.2170816659927368, + 0.749755859375, + -1.26226806640625, + 0.349609375, + 1.3632405996322632, + 1.18359375, + 0.6246744990348816, + 0.6066080927848816, + -0.76953125, + 3.307373046875, + -3.5111491680145264, + -1.0465494394302368, + 0.2916666567325592, + -0.9545084834098816, + 1.7350260019302368, + 0.1172281876206398, + 1.31842041015625, + -0.9784749150276184, + -1.0751953125, + -2.7672526836395264, + -1.84521484375, + 0.611572265625, + -0.5892741084098816, + 3.2579753398895264, + 3.4156901836395264, + 1.4150390625, + 0.2162882536649704, + 0.04443359375, + 3.6263020038604736, + 4.308746337890625, + -0.1227925643324852, + -2.5987956523895264, + -2.794708251953125, + -0.6998291015625, + 0.87408447265625, + -0.16607666015625, + -3.5099384784698486, + 3.3311359882354736, + -1.6220804452896118, + 1.86376953125, + -0.2303059846162796, + -0.2418619841337204, + -0.8545735478401184, + -2.8811848163604736, + -0.9044596552848816, + 1.0498250722885132, + -2.547607421875, + 0.7955729365348816, + -1.25872802734375, + 1.1334024667739868, + 0.6598713994026184, + -0.7760416865348816, + 1.19244384765625, + -0.6354166865348816, + -1.2322591543197632, + -1.0817056894302368, + 1.7679849863052368, + -0.5873616337776184, + -2.7561848163604736, + -1.2742513418197632, + -0.3053385317325592, + 3.0089519023895264, + 1.797418236732483, + 1.5367025136947632, + 2.3473308086395264, + 3.9371745586395264, + 2.72662353515625, + -2.0343425273895264, + 1.4065755605697632, + 0.8284505009651184, + 0.8566080927848816, + -0.6022135615348816, + -1.1502279043197632, + -1.87060546875, + 1.6829427480697632, + 1.41912841796875, + 1.9773763418197632, + -0.4080912172794342, + 0.6032307744026184, + -0.61181640625, + 0.787353515625, + -0.2647298276424408, + -2.2852375507354736, + 1.14990234375, + 1.4422200918197632, + -0.5255534052848816, + 3.5906574726104736, + -0.6854248046875, + -0.9259440302848816, + -0.9778645634651184, + 0.0482177734375, + -0.10205078125, + 1.307373046875, + -0.0553995780646801, + -0.0423177070915699, + -0.47998046875, + -2.2927653789520264, + -2.4347026348114014, + -1.0247802734375, + -1.689453125, + -1.6605631113052368, + 1.3098958730697632, + -1.65771484375, + 1.02557373046875, + 1.3343505859375, + 1.1793619394302368, + -0.5428059697151184, + -0.508056640625, + 0.4534098207950592, + 3.1931965351104736, + -1.4896749258041382, + -0.4873860776424408, + -2.1433918476104736, + -2.3570964336395264, + -1.0824991464614868, + -1.7451986074447632, + -1.3580728769302368, + -0.7504475712776184, + -0.6541340947151184, + 0.557373046875, + 1.2037760019302368, + -3.1315510272979736, + -1.6735025644302368, + -1.1612955331802368, + 2.054443359375, + 0.2744954526424408, + 1.8616536855697632, + -0.206573486328125, + -1.3911947011947632, + -1.1735025644302368, + -9.047526359558105, + -1.2447916269302368, + 0.2674560546875, + -2.07025146484375, + 0.570556640625, + 0.3375650942325592, + -0.5703125, + -2.1722004413604736, + -0.6480305790901184, + 0.8385213017463684, + -0.6023762822151184, + 1.9796142578125, + -0.08544921875, + 1.047119140625, + 2.38134765625, + -0.0203857421875, + 0.4074300229549408, + -2.224609375, + 1.9953206777572632, + -0.252197265625, + 2.129241943359375, + 0.6168619990348816, + -2.5487060546875, + -0.9463704228401184, + 1.8801676034927368, + 0.21099853515625, + 1.541259765625, + -0.186279296875, + 2.7080078125, + -1.5823720693588257, + -0.8981119990348816, + 0.6232401728630066, + 4.662973880767822, + 1.6422525644302368, + 2.2477214336395264, + 2.302978515625, + -1.4416097402572632, + -1.61279296875, + -2.138671875, + 0.237213134765625, + 0.2044270783662796, + 0.6149088740348816, + 0.9734700322151184, + -2.1918132305145264, + 0.0064290366135537624, + -2.35009765625, + -1.56219482421875, + -1.3551025390625, + -1.6870931386947632, + 0.5120442509651184, + -0.5751953125, + 1.4899088144302368, + 0.6287078857421875, + -0.85693359375, + 4.113932132720947, + 0.5897623896598816, + -0.8948771357536316, + -3.865234375, + 1.4495443105697632, + 0.7547081112861633, + -0.7728627324104309, + -0.32275390625, + 0.5931396484375, + 0.2946370542049408, + 0.033935546875, + -1.1127523183822632, + -0.8016357421875, + -0.52508544921875, + 0.3133951723575592, + 0.5968424677848816, + -1.3444010019302368, + 0.9733073115348816, + -2.4528911113739014, + 1.5935872793197632, + 0.290985107421875, + 0.1147918701171875, + 1.1341552734375, + -1.9414876699447632, + 2.591796875, + -0.2242838591337204, + 1.2448323965072632, + -1.1545206308364868, + -1.9143880605697632, + -1.7509765625, + -1.5843302011489868, + 0.72412109375, + -1.4949951171875, + -2.6194660663604736, + 1.3483072519302368, + 0.3163248598575592, + -1.5322265625, + 2.6953125, + 0.2427571564912796, + 0.7998555302619934, + 2.868199586868286, + 1.0247396230697632, + 3.6189982891082764, + 0.97235107421875, + -1.9930419921875, + 2.07861328125, + 0.5362955927848816, + -2.2184245586395264, + 3.5319011211395264, + -0.0721028670668602, + 2.7213542461395264, + 1.2140401601791382, + -2.2636921405792236, + 2.4632160663604736, + -2.8684895038604736, + -3.2191569805145264, + -1.4830728769302368, + 2.4228515625, + 1.2694498300552368, + -1.8154296875, + -1.8636068105697632, + -2.1888020038604736, + 1.3444010019302368, + 2.8037922382354736, + 0.1494140625, + 2.1588542461395264, + 1.8336588144302368, + 3.5729167461395264, + -1.4986978769302368, + -0.12998707592487335, + 0.9309895634651184, + 3.6742351055145264, + -0.49169921875, + -1.4256185293197632, + 0.6732584834098816, + 3.75390625, + -1.3811849355697632, + 2.242919921875, + 1.3306478261947632, + -0.3748219907283783, + -0.9368489384651184, + 1.6610921621322632, + 1.2307943105697632, + -2.314697265625, + -3.4591472148895264, + -0.4794921875, + -0.7594401240348816, + 0.0860392227768898, + -1.4609375, + 1.2490234375, + 2.0630695819854736, + 1.5567626953125, + 1.888671875, + -1.1499837636947632, + 0.2256673127412796, + -0.7401530146598816, + 0.9720866084098816, + 1.11767578125, + 1.0919595956802368, + 1.7093505859375, + 0.5218505859375, + -0.8476765751838684, + 2.3304035663604736, + -0.011067708022892475, + 0.8955078125, + -0.24118168652057648, + -1.3779296875, + -2.2925617694854736, + -3.9825847148895264, + 0.7537434697151184, + 0.9615885615348816, + -4.039388179779053, + 0.85028076171875, + -0.6653645634651184, + 3.2760417461395264, + -0.035888671875, + -3.9912109375, + -1.3431802988052368, + 1.3472696542739868, + 1.8671875, + 0.286346435546875, + -0.0206298828125, + 1.9247232675552368, + 2.1835124492645264, + -1.9265950918197632, + 0.1418050080537796, + -0.348876953125, + -0.22524769604206085, + 0.0857747420668602, + -3.4723308086395264, + 0.1500447541475296, + 0.86767578125, + 1.24615478515625, + 2.5380859375, + -0.4653218686580658, + -2.9022624492645264, + 0.102294921875, + 2.5013835430145264, + -0.6622314453125, + -1.219970703125, + -1.2493896484375, + 0.4229329526424408, + -0.4001413881778717, + -1.930694580078125, + 1.5611978769302368, + -1.2815347909927368, + 1.0364990234375, + 0.5852457880973816, + -1.5162760019302368, + 2.7920734882354736, + 0.8634440302848816, + -2.0301105976104736, + -0.817138671875, + 1.2400716543197632, + 0.1709798127412796, + -0.3241373598575592, + 0.8723958134651184, + -0.2129414826631546, + -0.6522013545036316, + -0.0443115234375, + -0.4684855043888092, + -0.6458333134651184, + -0.9176432490348816, + 2.5149738788604736, + 0.2982991635799408, + 1.2071939706802368, + -0.0435384102165699, + -2.260498046875, + 2.3070068359375, + -0.3670450747013092, + -1.0382486581802368, + -0.0586751289665699, + 2.9482421875, + 1.1868489980697632, + -0.7194010615348816, + 1.35546875, + 2.3968505859375, + -1.4658203125, + -1.0332845449447632, + 0.9651692509651184, + 0.01177978515625, + 0.1150716170668602, + 0.0719401016831398, + -0.3218180239200592, + 0.0763753280043602, + 1.3870443105697632, + -2.6158854961395264, + -3.2184245586395264, + 0.1051025390625, + 3.9954426288604736, + 0.4596303403377533, + 1.2395833730697632, + 0.8777669072151184, + 1.9547525644302368, + -1.1503092050552368, + -0.1984456330537796, + 2.8015949726104736, + 1.0523275136947632, + -1.9296468496322632, + -0.0445353202521801, + 0.4562174379825592, + 0.4532063901424408, + -0.0065867104567587376, + -0.4684244692325592, + 1.1881510019302368, + 1.3935140371322632, + 0.72802734375, + -1.1194661855697632, + -0.9891357421875, + 0.87939453125, + 0.4903971254825592, + -0.6035969853401184, + 0.0418701171875, + 1.6463216543197632, + 0.5607096552848816, + -3.2513020038604736, + 2.3915812969207764, + 0.27183404564857483, + 2.21630859375, + 1.71142578125, + -0.49560546875, + 1.8067220449447632, + -0.63330078125, + -4.623046875, + -0.9208984375, + -1.1086934804916382, + 1.1123046875, + 1.16259765625, + -0.0682779923081398, + 0.9559733271598816, + 1.9519857168197632, + 1.3015950918197632, + 0.7791340947151184, + -3.5576171875, + 3.7076823711395264, + 0.7201334834098816, + -2.1150715351104736, + 2.6565754413604736, + 1.67254638671875, + -2.03851318359375, + 0.4087727963924408, + -2.3363444805145264, + -1.84814453125, + 2.822265625, + 0.65789794921875, + 0.1902669221162796, + 1.7410482168197632, + -0.3033854067325592, + -1.557861328125, + 0.591552734375, + 0.0395914725959301, + 0.1357421875, + -3.720458984375, + -3.7314453125, + 0.7846247553825378, + 0.53729248046875, + 1.475341796875, + 0.3721517026424408, + 1.6393228769302368, + -1.4797821044921875, + -2.5434367656707764, + -0.4669596254825592, + -0.91015625, + -0.3378194272518158, + -2.7567646503448486, + 1.2351888418197632, + -1.2392578125, + -0.00390625, + -1.1047567129135132, + -0.6695149540901184, + -0.8807780146598816, + 3.3206379413604736, + 1.7767740488052368, + 2.2285969257354736, + 0.3497721254825592, + -1.2629585266113281, + -0.0012503465404734015, + 2.6064453125, + 0.8617350459098816, + -0.9224650263786316, + -0.2042338103055954, + -0.304931640625, + 0.8513997197151184, + 0.23492431640625, + 1.7021484375, + -0.9699299931526184, + -1.0752512216567993, + -1.9724935293197632, + 0.0841471329331398, + 0.0107421875, + 0.1712239533662796, + -2.193389892578125, + 1.4798177480697632, + 0.4248860776424408, + 0.0388590507209301, + 2.5113933086395264, + 0.36383056640625, + 2.6248371601104736, + -1.3663736581802368, + 2.5489909648895264, + 1.8675130605697632, + 1.16796875, + -1.1785684823989868, + -2.7685546875, + -0.0646158829331398, + -0.6897379755973816, + 2.6131184101104736, + 1.2491861581802368, + -0.3531900942325592, + 0.196044921875, + -1.3160806894302368, + 1.3743489980697632, + 3.3440754413604736, + -1.3665364980697632, + 1.3430989980697632, + 1.8368326425552368, + -0.4982096254825592, + -0.1160481795668602, + 1.492919921875, + -0.409423828125, + -1.6082357168197632, + -2.1363525390625, + 0.054443359375, + 2.0389811992645264, + -0.2975057065486908, + 1.1373189687728882, + -1.5400390625, + 2.5643718242645264, + -1.3461099863052368, + -0.2083333283662796, + 1.8095296621322632, + -2.0074055194854736, + -1.2165933847427368, + 0.7480977177619934, + 0.2847493588924408, + -1.8191732168197632, + -2.1150920391082764, + 1.0529989004135132, + -1.6560872793197632, + -1.8994954824447632, + -1.8317056894302368, + -0.1051432266831398, + -0.0963083878159523, + -0.7768147587776184, + -1.7784017324447632, + -2.8313801288604736, + -0.92547607421875, + -0.1643880158662796, + 1.33544921875, + -1.9264119863510132, + 0.8584391474723816, + 3.1416015625, + -2.029296875, + 0.4337565004825592, + -0.7433268427848816, + -2.3548991680145264, + -1.2599283456802368, + 0.2317708283662796, + -1.4604085683822632, + 0.49169921875, + 1.5784505605697632, + 0.638671875, + -0.934326171875, + 1.6715494394302368, + -2.3116862773895264, + 0.4892578125, + -0.5608723759651184, + 0.4931233823299408, + 2.7151691913604736, + 0.8917643427848816, + 4.141275882720947, + -0.78955078125, + 1.5382486581802368, + 0.9822590947151184, + 1.6050618886947632, + 2.985107421875, + 1.2340494394302368, + -0.2134602814912796, + -0.0749715194106102, + -2.4208526611328125, + -3.658203125, + 0.1145833358168602, + -1.0316568613052368, + -0.7950846552848816, + -0.5806477665901184, + 1.6513671875, + -0.73980712890625, + -1.125244140625, + 0.0327707938849926, + -0.1689046174287796, + 3.343134641647339, + 0.4786783754825592, + -3.6751301288604736, + 1.5541738271713257, + 0.057861328125, + -8.992207527160645, + 0.2220865935087204, + 2.9583332538604736, + -0.8944600224494934, + -5.736165523529053, + -2.8837890625, + 0.8150227665901184, + 0.591796875, + 0.2422536164522171, + 0.079833984375, + -1.349365234375, + 1.6641439199447632, + 0.7635090947151184, + 0.34722900390625, + -1.34332275390625, + 2.4006550312042236, + -1.4342447519302368, + 0.3038533627986908, + -2.9453125, + -0.495361328125, + 1.1681874990463257, + -3.968017578125, + -1.0434774160385132, + 2.0052082538604736, + 1.6958414316177368, + 1.6723226308822632, + 1.746551513671875, + 0.859375, + -1.5462239980697632, + 0.4178059995174408, + 0.5416666865348816, + -0.2293294221162796, + -1.404296875, + 0.2339680939912796, + -1.7752279043197632, + 1.3369954824447632, + -1.629638671875, + -0.7325236201286316, + 3.2233073711395264, + 0.4695638120174408, + -0.9460042119026184, + 1.5243734121322632, + 0.026885986328125, + 0.84912109375, + 1.1715494394302368, + -0.3964029848575592, + 0.5387675166130066, + 0.2732747495174408, + -2.7125651836395264, + 2.9437663555145264, + 2.1226398944854736, + 0.4708048403263092, + 0.3010660707950592, + 1.552001953125, + 1.34521484375, + -1.1372846364974976, + 0.9451904296875, + -0.61846923828125, + 3.4235026836395264, + -2.3828125, + -2.1920573711395264, + 0.97216796875, + 0.1083984375, + -3.3492839336395264, + 0.1398518830537796, + -1.4639486074447632, + 1.9429525136947632, + -0.0323079414665699, + -3.39501953125, + -1.7146402597427368, + 1.1173502206802368, + 0.9099528193473816, + 0.984130859375, + 1.994384765625, + -3.0358073711395264, + -2.4183349609375, + 2.2569172382354736, + -1.8971353769302368, + 0.9176432490348816, + -0.4564615786075592, + 1.8268228769302368, + -2.1511027812957764, + 1.8889974355697632, + 0.7977803349494934, + -5.512451171875, + 0.9638671875, + 1.3252767324447632, + 3.66119384765625, + -0.010091145522892475, + -1.8444010019302368, + 0.7132161259651184, + -1.5284830331802368, + -0.013509114272892475, + -0.6204426884651184, + 2.5647785663604736, + 0.6241862177848816, + 0.5787760615348816, + 0.5329793095588684, + 0.7569172978401184, + -1.3273111581802368, + 0.3821614682674408, + 0.291015625, + 1.2490640878677368, + 0.331573486328125, + 3.2884113788604736, + 0.235595703125, + -0.6564992070198059, + 0.3218994140625, + 2.35791015625, + 0.49923577904701233, + -0.02726236917078495, + 1.10888671875, + 0.8653971552848816, + -0.3155924379825592, + -1.5879720449447632, + -4.689127445220947, + 0.03802490234375, + 0.725830078125, + -1.8206380605697632, + -0.37939453125, + 0.5372721552848816, + 1.49365234375, + -0.798095703125, + -2.2483723163604736, + -1.5538736581802368, + -0.1722819060087204, + 1.5791015625, + -1.3915201425552368, + -1.1359049081802368, + -1.5538736581802368, + 0.1238199844956398, + 1.8483072519302368, + -0.1799723356962204, + -2.6776325702667236, + -1.0615234375, + -0.4165445864200592, + -0.33740234375, + -0.322265625, + 2.9218342304229736, + 0.0077718100510537624, + 0.1774088591337204, + -1.1089681386947632, + 2.0506184101104736, + -0.66973876953125, + -1.0281575918197632, + 1.470703125, + -0.4384765625, + -2.1322429180145264, + -1.3209635019302368, + 3.38623046875, + 3.1963298320770264, + 1.2527669668197632, + -0.790283203125, + 0.79522705078125, + 0.2768961489200592, + -2.7858073711395264, + -1.0997720956802368, + -1.095947265625, + 0.6835174560546875, + -2.6002604961395264, + 0.1123453751206398, + 1.2776693105697632, + -0.2242838591337204, + -0.122528076171875, + 0.10589599609375, + 0.7897135615348816, + -1.750732421875, + -0.5782063603401184, + 4.220377445220947, + 0.7451985478401184, + -1.8246256113052368, + 1.6341348886489868, + 1.3125814199447632, + -0.1545206755399704, + -0.1410115510225296, + 1.0404052734375, + -3.4098308086395264, + 0.9134114384651184, + 1.906982421875, + -0.5768635869026184, + -1.4638671875, + -2.5758464336395264, + -0.2849833071231842, + -1.0201822519302368, + 1.0152994394302368, + -1.5415853261947632, + -3.0481770038604736, + -1.00927734375, + -0.1048787459731102, + 0.2804361879825592, + 1.4128990173339844, + 1.4973958730697632, + -0.8831380009651184, + 1.2892252206802368, + 2.2726237773895264, + -0.7734375, + 1.2915853261947632, + 1.93017578125, + 0.0716959610581398, + -0.5321248173713684, + 1.46240234375, + -0.98095703125, + -0.17742919921875, + -2.9093425273895264, + -2.4695637226104736, + 0.571533203125, + -0.84814453125, + -1.839111328125, + -0.1569010466337204, + -0.055908203125, + 1.2886148691177368, + -0.0008951823110692203, + -0.7034199833869934, + 2.549560546875, + -2.3255207538604736, + 4.857259273529053, + 0.014933268539607525, + -2.601806640625, + -1.4448648691177368, + -2.4925129413604736, + 0.02958170510828495, + -0.2969563901424408, + 0.8460286259651184, + -1.1808267831802368, + -4.426432132720947, + -0.2816568911075592, + -3.7086589336395264, + -0.9257405400276184, + 0.1471354216337204, + 4.13232421875, + -1.515625, + 2.3660480976104736, + 1.2700399160385132, + -0.124755859375, + -1.807708740234375, + 0.2140299528837204, + -3.756103515625, + -2.257568359375, + -0.0928243026137352, + -0.8312174677848816, + -3.5323078632354736, + -1.7146505117416382, + 0.07391357421875, + -0.0908203125, + 1.1600748300552368, + -0.7871907353401184, + -4.077799320220947, + 2.9041340351104736, + -0.73681640625, + 0.6585286259651184, + 4.366536617279053, + -0.588592529296875, + 0.401336669921875, + 4.374674320220947, + 1.0525308847427368, + 3.275390625, + -0.03857421875, + -0.1193084716796875, + -0.7635905146598816, + -1.8013916015625, + -1.042236328125, + 2.6299641132354736, + 0.2450764924287796, + -0.19580078125, + 0.6634928584098816, + 0.7049967646598816, + 3.9729816913604736, + 1.1180013418197632, + 3.2914226055145264, + 1.0978189706802368, + -0.4391237795352936, + -0.2926432192325592, + -0.39080810546875, + -0.2164713591337204, + 0.3955078125, + -2.8317058086395264, + 2.326904296875, + 3.1219074726104736, + 0.8622233271598816, + -1.822998046875, + 2.24951171875, + -1.5184732675552368, + 0.5463460087776184, + 2.0336101055145264, + 0.3321940004825592, + -2.2616984844207764, + -1.6188150644302368, + 0.11328125, + 1.898681640625, + 1.1153970956802368, + 1.0018717050552368, + -2.521759033203125, + 1.7585042715072632, + 1.13818359375, + -2.2228190898895264, + -0.7942708134651184, + 0.1765950471162796, + -0.08411916345357895, + -1.5333658456802368, + -0.1512858122587204, + -0.9982096552848816, + 1.4968668222427368, + 0.6732177734375, + 1.41888427734375, + 1.64501953125, + -1.7721353769302368, + 1.6678060293197632, + -1.0179086923599243, + -0.3212890625, + -1.70166015625, + -0.1394449919462204, + -0.8763020634651184, + 1.3196614980697632, + -0.9160969853401184, + 0.440185546875, + 0.1104329451918602, + 1.73077392578125, + 1.400390625, + 0.1427001953125, + 0.6784260869026184, + 0.3515625, + 1.32373046875, + 1.2958577871322632, + 2.5276691913604736, + 0.5099284052848816, + 0.49951171875, + 3.2388813495635986, + 1.2561849355697632, + 10.772135734558105, + -0.2556915283203125, + 1.007568359375, + 2.0451862812042236, + 0.028564453125, + -2.3819172382354736, + 0.5974934697151184, + -1.6593118906021118, + -1.175537109375, + -0.05908203125, + 0.0703938826918602, + 2.2663166522979736, + -0.064453125, + -2.61376953125, + -0.5758056640625, + 1.9386392831802368, + 1.5924478769302368, + 1.0437418222427368, + -1.1807861328125, + -2.199213743209839, + -0.0220947265625, + 0.2071940153837204, + -2.04150390625, + -0.9108073115348816, + 2.125, + 0.1009928360581398, + 1.3373514413833618, + 2.45361328125, + -1.3798421621322632, + 2.20361328125, + -0.778076171875, + 1.3055013418197632, + 0.3568115234375, + -1.648193359375, + -1.6309407949447632, + -2.8331706523895264, + 4.306233882904053, + -1.0001220703125, + 4.480062007904053, + 1.20562744140625, + 2.5581867694854736, + -2.1092121601104736, + -1.3080037832260132, + 0.1852620393037796, + -0.3489583432674408, + 0.3664347231388092, + 2.04663348197937, + 1.5680338144302368, + 0.6472117304801941, + -0.8837890625, + -4.371419429779053, + -1.6227213144302368, + -1.8953195810317993, + 0.84423828125, + -2.3544921875, + -1.7835286855697632, + 1.4291177988052368, + -0.2510172426700592, + -0.5826823115348816, + 1.917236328125, + -1.0144857168197632, + 4.7705078125, + 0.2622477114200592, + -0.252105712890625, + 2.896484375, + 1.024658203125, + 0.395751953125, + 0.4348958432674408, + 2.2120361328125, + 1.875, + -1.485595703125, + 0.6624348759651184, + 0.6827799677848816, + 0.5830078125, + 1.1817220449447632, + 2.3562824726104736, + 2.5047199726104736, + 1.783203125, + 2.5740559101104736, + 2.5890705585479736, + -0.9014689326286316, + 1.6150716543197632, + 2.912109375, + -0.1417643278837204, + 0.9757487177848816, + -1.8704427480697632, + 0.08349609375, + -1.9942220449447632, + -0.1832682341337204, + -0.02433268167078495, + -0.5817463994026184, + 2.0299479961395264, + 2.4982097148895264, + 0.2615966796875, + 0.98101806640625, + 2.58251953125, + 0.4861348569393158, + 1.3988037109375, + -1.0834146738052368, + 0.0509033203125, + -0.4882608950138092, + 0.833251953125, + 3.0107421875, + 0.0269775390625, + 0.8108723759651184, + 0.7636985778808594, + 4.108724117279053, + -1.2054849863052368, + -1.2194417715072632, + -0.7314656376838684, + 1.2483724355697632, + 1.9617513418197632, + 0.7349446415901184, + -0.6914265751838684, + 0.2303263396024704, + 0.9474995732307434, + -1.3307291269302368, + -1.5001627206802368, + -0.7984517216682434, + 1.07861328125, + -1.2994486093521118, + 3.1866862773895264, + 0.7723795771598816, + 18.83984375, + -0.8509928584098816, + -2.6712238788604736, + -3.2459309101104736, + -3.6233673095703125, + -0.3406982421875, + -0.0564778633415699, + -1.970703125, + -1.8923416137695312, + 0.4811197817325592, + -1.6803385019302368, + -2.6298420429229736, + 0.235626220703125, + 0.060638427734375, + -0.2432454377412796, + 1.6259765625, + -2.6006572246551514, + -1.4081217050552368, + 1.1985193490982056, + -0.3019256591796875, + -0.14990234375, + -1.0779622793197632, + 1.1309407949447632, + -0.79541015625, + 0.9602254033088684, + -0.5867512822151184, + -2.6527099609375, + -0.922119140625, + -0.74072265625, + -0.23779296875, + -1.4078775644302368, + -2.2432453632354736, + 1.4747110605239868, + -0.22271728515625, + 0.1983235627412796, + 0.3132591247558594, + 2.33929443359375, + -1.1996663808822632, + 0.1000162735581398, + 0.3671671450138092, + 1.4024251699447632, + -1.9474283456802368, + 3.0680744647979736, + -2.79150390625, + 0.8200480341911316, + -0.01761881448328495, + -1.0926975011825562, + 1.45849609375, + -0.7854817509651184, + -1.1433919668197632, + -4.145182132720947, + -0.9396159052848816, + -2.2932941913604736, + -0.3698526918888092, + -0.2927449643611908, + 1.2391153573989868, + 1.7755126953125, + 0.0065104165114462376, + -1.49951171875, + 0.663818359375, + 1.6972249746322632, + 1.5095621347427368, + -0.7831624150276184, + 0.0621337890625, + -0.9872029423713684, + -1.7977701425552368, + -0.9479777216911316, + 1.5780435800552368, + -1.8164876699447632, + 0.2696126401424408, + 2.25048828125, + -0.53155517578125, + 0.2231852263212204, + 2.2620441913604736, + -2.9888508319854736, + -1.0491536855697632, + 2.0878093242645264, + 4.0443115234375, + -1.7604166269302368, + -1.8644205331802368, + -3.9850261211395264, + -0.4436849057674408, + 1.518798828125, + 1.3152261972427368, + -1.0250650644302368, + 2.2629802227020264, + -1.4669595956802368, + 4.1123046875, + -1.8209635019302368, + 1.0439859628677368, + 0.70458984375, + 1.284515380859375, + 1.8240560293197632, + 1.81494140625, + 1.2306112051010132, + 0.2167154997587204, + -0.6197102665901184, + 1.0337728261947632, + -2.8126628398895264, + -1.5078125, + 2.333857297897339, + 0.982818603515625, + 0.25827279686927795, + -0.7666829228401184, + 1.779052734375, + -2.6233723163604736, + 3.7317707538604736, + -0.5817057490348816, + -0.8245442509651184, + -0.9445393681526184, + -1.4423013925552368, + -2.3430988788604736, + -2.329907178878784, + -2.4000651836395264, + 0.8738200068473816, + 0.3606923520565033, + 1.5721842050552368, + -0.2015787810087204, + 0.67333984375, + -0.99755859375, + 0.9217427372932434, + -0.81005859375, + -0.22491455078125, + -3.7389323711395264, + 1.7525228261947632, + -3.9227702617645264, + 1.7977294921875, + 1.114990234375, + 1.6966146230697632, + 4.681314945220947, + -1.6604818105697632, + 0.3708902895450592, + -1.52325439453125, + 0.8987630009651184, + -0.552734375, + -0.7547607421875, + -0.62396240234375, + -1.4214376211166382, + -0.7776692509651184, + 0.087158203125, + -0.3343099057674408, + 0.6204757690429688, + 1.9124349355697632, + -0.613525390625, + -3.6407878398895264, + 0.4544169008731842, + -1.6819101572036743, + 0.6672770380973816, + -0.581756591796875, + 0.4845377504825592, + 1.73291015625, + -1.732666015625, + 0.31817626953125, + 1.7181802988052368, + 0.3889668881893158, + -1.0836995840072632, + 1.2809244394302368, + -0.0887858048081398, + 2.0496418476104736, + -1.9827474355697632, + 1.1876627206802368, + 2.3361003398895264, + 2.908203125, + -2.7738444805145264, + -0.5850016474723816, + 1.7394205331802368, + 0.7486979365348816, + 2.6630859375, + -2.792393922805786, + 0.419921875, + -1.0244954824447632, + -0.586181640625, + 3.6827392578125, + -1.0915933847427368, + -0.8837890625, + 0.2080891877412796, + 1.5806478261947632, + -0.1995849609375, + -1.0963541269302368, + -4.398600101470947, + 2.2971599102020264, + -1.5209554433822632, + 1.3787027597427368, + 3.079071044921875, + 1.1709493398666382, + 1.0220845937728882, + -1.040283203125, + 1.60302734375, + -0.8799641728401184, + 0.5511881709098816, + 1.67529296875, + -0.8698018193244934, + -2.0431315898895264, + 0.037109375, + -0.9962565302848816, + -0.6471964716911316, + 0.4126790463924408, + 0.5076497197151184, + -0.7366536259651184, + 1.4136759042739868, + -0.9087117314338684, + -0.7564697265625, + -1.3844808340072632, + 4.203775882720947, + 1.5067952871322632, + -2.1744792461395264, + -2.849609375, + -1.2771810293197632, + -0.9972330927848816, + 1.968994140625, + -0.1642049103975296, + 1.4789224863052368, + -0.4573160707950592, + 0.6886393427848816, + 0.1548665314912796, + -0.256378173828125, + 0.1560872346162796, + -0.7893880009651184, + -1.2126871347427368, + 0.6887614130973816, + 0.6866862177848816, + 2.189453125, + -0.8851725459098816, + -0.1935221403837204, + -0.39813232421875, + 0.5118001103401184, + -0.9737955927848816, + -2.7506511211395264, + 1.059844970703125, + 0.2539469301700592, + 1.1459146738052368, + -1.57470703125, + -3.7796223163604736, + -1.0906575918197632, + -0.21874745190143585, + 0.6759440302848816, + 1.5114860534667969, + 2.1803386211395264, + 0.4873860776424408, + -3.0227863788604736, + 2.3800456523895264, + -1.0771484375, + -0.6803385615348816, + -0.8753255009651184, + -0.598876953125, + -2.4236857891082764, + -2.375218629837036, + 4.103353023529053, + 2.9113566875457764, + 4.13525390625, + -0.4652506411075592, + 1.6876627206802368, + 1.4339193105697632, + -2.955078125, + 0.2722981870174408, + -1.4026693105697632, + 2.16845703125, + -0.78515625, + 1.4890950918197632, + -3.0096027851104736, + 0.900634765625, + 5.226236820220947, + 1.4433389902114868, + -0.7727864384651184, + -1.5055338144302368, + 1.1857095956802368, + 2.6519775390625, + 0.0002389351575402543, + 1.3484293222427368, + 0.3469441831111908, + -3.076416015625, + -1.4461263418197632, + 1.9790445566177368, + -2.1004230976104736, + 1.8121744394302368, + -1.8677572011947632, + -1.6974283456802368, + 1.53271484375, + -0.2410481721162796, + -0.2111002653837204, + -0.2038981169462204, + 1.7911783456802368, + 1.06298828125, + -0.6372883915901184, + -0.0749104842543602, + 1.4015299081802368, + -1.3005574941635132, + -1.79150390625, + -3.066767454147339, + -0.2613118588924408, + -0.4057820737361908, + -2.0352375507354736, + -0.5450541377067566, + 0.4542032778263092, + 0.5933837890625, + -0.4602864682674408, + 2.7465007305145264, + 2.5859782695770264, + 1.0482991933822632, + -0.0378621406853199, + 0.7568359375, + 2.1891276836395264, + -2.7067058086395264, + 1.3174234628677368, + -0.8989664912223816, + 0.1448567658662796, + -1.6676839590072632, + -1.368896484375, + -1.8142904043197632, + -2.1465656757354736, + 0.2407633513212204, + -0.27374267578125, + 3.644287109375, + 1.5452474355697632, + 1.0079752206802368, + 2.533203125, + -1.1084798574447632, + -0.2120564728975296, + 0.3934732973575592, + 1.4373372793197632, + -1.3799642324447632, + 0.3859049379825592, + -3.3338215351104736, + -0.505859375, + 2.3883056640625, + 2.9002277851104736, + 2.7086181640625, + 0.0808512344956398, + -2.031494140625, + -1.0626627206802368, + 0.7711588740348816, + 3.58984375, + 1.2666829824447632, + -1.2333984375, + -1.2683919668197632, + 0.8298746943473816, + -1.52880859375, + 1.1899820566177368, + 1.1578775644302368, + -2.4142253398895264, + 1.3528646230697632, + -0.5823567509651184, + -0.17095947265625, + 1.2715657949447632, + 0.2917887270450592, + -0.1953125, + 0.9078776240348816, + -0.0353190116584301, + 1.8194173574447632, + -0.2478841096162796, + -0.3901265561580658, + -0.3663736879825592, + -5.0244140625, + 1.34228515625, + 1.3531494140625, + 0.73199462890625, + 0.54693603515625, + -1.3824869394302368, + -0.9347330927848816, + -0.9940999150276184, + -0.6984354853630066, + -2.3603515625, + 2.4237468242645264, + -0.8424479365348816, + -3.7097980976104736, + -0.2088216096162796, + -1.1927896738052368, + -1.8461099863052368, + -1.11474609375, + -1.3263345956802368, + 1.3188070058822632, + 0.0558268241584301, + -0.945068359375 + ], + "text_index": 1 + } + ] + }, + "usage": { + "total_tokens": 2 + }, + "request_id": "ebc4cec4-c040-470e-a978-76c61b2cfd4e" + } + headers: + content-length: + - '55733' + content-type: + - application/json + date: + - Mon, 17 Nov 2025 08:31:24 GMT + req-arrive-time: + - '1763368284785' + req-cost-time: + - '97' + resp-start-time: + - '1763368284883' + server: + - istio-envoy + set-cookie: + - acw_tc=ebc4cec4-c040-470e-a978-76c61b2cfd4eb120653c8c9de548428c8345df5bb0ce;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '90' + x-request-id: + - ebc4cec4-c040-470e-a978-76c61b2cfd4e + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_with_text_type.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_with_text_type.yaml new file mode 100644 index 000000000..4945b8e8b --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_with_text_type.yaml @@ -0,0 +1,1620 @@ +interactions: +- request: + body: |- + { + "model": "text-embedding-v1", + "parameters": { + "text_type": "query" + }, + "input": { + "texts": [ + "What is machine learning?" + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '119' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/embeddings/text-embedding/text-embedding + response: + body: + string: |- + { + "output": { + "embeddings": [ + { + "embedding": [ + 2.1375296115875244, + -6.5293145179748535, + -4.034493446350098, + -3.894618511199951, + 3.4332797527313232, + -0.6098284125328064, + 2.0916268825531006, + -4.937845706939697, + -2.156494140625, + -0.8754534125328064, + -2.6920077800750732, + -3.40771484375, + -1.9809396266937256, + 4.289760112762451, + -4.693882465362549, + -4.063773155212402, + 0.7239728569984436, + -1.3524343967437744, + -0.8136247992515564, + 0.1864842027425766, + -1.1068551540374756, + -0.8620082139968872, + 1.1569344997406006, + 3.485194683074951, + 0.6342903971672058, + -0.36746543645858765, + -1.2332502603530884, + -4.086314678192139, + 3.5325405597686768, + -0.6935076117515564, + -0.191680908203125, + -2.0415432453155518, + 3.3695461750030518, + -0.2020786851644516, + 0.1367274671792984, + -0.7586342692375183, + -1.3632943630218506, + -0.0565403513610363, + 2.15478515625, + -2.1436073780059814, + 0.9044995903968811, + 1.0549653768539429, + 3.8343331813812256, + 1.0354963541030884, + 0.2287183552980423, + 1.9636666774749756, + -0.0523856021463871, + 0.5218146443367004, + 0.6878880262374878, + 0.8506954908370972, + 2.1814138889312744, + 6.603602886199951, + 0.3145010769367218, + -1.6788504123687744, + 0.1237618550658226, + 1.1088343858718872, + -2.8131277561187744, + 0.9234095811843872, + 5.3878350257873535, + 2.4450509548187256, + -1.0289306640625, + 2.6168606281280518, + 0.7911028265953064, + -2.3602688312530518, + 1.1775076389312744, + 0.1741420179605484, + -4.4036126136779785, + -2.4402334690093994, + -4.801967144012451, + -1.1290035247802734, + 2.4569003582000732, + 0.7655988335609436, + 1.933877944946289, + 1.2957502603530884, + 0.3209598958492279, + -0.4575260579586029, + -0.1688276082277298, + -0.005401611328125, + -1.9399458169937134, + 1.3542044162750244, + -3.4416415691375732, + 1.4109236001968384, + 0.973388671875, + -4.167550086975098, + 1.1727426052093506, + 0.42697906494140625, + 3.495692729949951, + -0.7744925618171692, + 1.9979597330093384, + -3.5825793743133545, + -1.9404340982437134, + -0.3018319308757782, + 3.885986328125, + 1.4810791015625, + 1.80322265625, + 5.2593560218811035, + 4.153477191925049, + -0.035308837890625, + -1.8130580186843872, + 1.6898869276046753, + -3.763340473175049, + 0.561524510383606, + 2.441685199737549, + -0.00874982587993145, + 1.8267822265625, + 2.018064260482788, + -1.1352059841156006, + 2.147922992706299, + 0.7555890679359436, + -3.1452462673187256, + 3.1304147243499756, + -0.7668980360031128, + -1.7608468532562256, + -0.4225812554359436, + 3.328125, + 3.2211391925811768, + 1.92852783203125, + -2.1724140644073486, + -0.4925362765789032, + 3.2529995441436768, + 3.2902133464813232, + -2.9440219402313232, + 1.6653006076812744, + 0.6696515679359436, + 1.4289201498031616, + -1.7269657850265503, + -1.0915571451187134, + -0.8829258680343628, + 2.2410104274749756, + 3.4068245887756348, + 0.2289254367351532, + -2.4240024089813232, + 3.0498046875, + 1.4446498155593872, + 1.3464006185531616, + -0.7387825846672058, + 3.759983539581299, + -3.8986294269561768, + -2.378696918487549, + 0.02332414872944355, + 0.3500082790851593, + -2.964599609375, + 0.6631426215171814, + -4.724757671356201, + 1.2330496311187744, + -0.1544363796710968, + -0.4969089925289154, + 0.2353166788816452, + -2.326106548309326, + 1.7393428087234497, + -2.060703754425049, + -1.6600167751312256, + -5.4276123046875, + -0.4389866292476654, + -0.2649318277835846, + -2.3403003215789795, + -2.544677734375, + 3.0523159503936768, + 4.43377685546875, + 1.8801923990249634, + -2.2016122341156006, + 3.2888882160186768, + 4.032601356506348, + -1.3799612522125244, + -2.924442768096924, + -3.454868793487549, + 2.453464984893799, + -4.851522922515869, + -1.5787004232406616, + 0.3199288547039032, + -0.011775425635278225, + 2.232421875, + -1.6377650499343872, + -0.2505057156085968, + -2.6575942039489746, + 5.905094146728516, + -4.5711846351623535, + -4.401053428649902, + 0.3579799234867096, + 4.66262149810791, + 4.281895160675049, + 2.0933620929718018, + -3.3600027561187744, + -1.5951673984527588, + 2.628718852996826, + -3.1608364582061768, + -3.586549997329712, + 2.8580148220062256, + -2.7819302082061768, + -2.0972158908843994, + 4.988071918487549, + 1.0947091579437256, + -2.3569729328155518, + -4.9513115882873535, + 0.3114188015460968, + -1.3151124715805054, + 1.1587045192718506, + -0.9031873345375061, + 0.9916948676109314, + 0.203125, + 1.1025445461273193, + -0.9877801537513733, + 2.8643798828125, + -3.3734652996063232, + 1.7227609157562256, + -2.530186176300049, + -0.4235578179359436, + -1.9980686902999878, + -2.587131977081299, + 4.001552104949951, + -1.0069929361343384, + -0.4684012234210968, + -2.979038715362549, + -0.2800728976726532, + 0.7666277289390564, + 1.2223336696624756, + -1.2848074436187744, + 3.2053439617156982, + -3.0302734375, + 6.0831122398376465, + 3.478302001953125, + 6.762656211853027, + 1.1379830837249756, + 1.3667515516281128, + -0.4576764702796936, + -0.3387799859046936, + 2.3420584201812744, + -1.3727155923843384, + -1.3284214735031128, + 1.3559373617172241, + -1.4431806802749634, + 1.7971365451812744, + -0.7888096570968628, + -4.425589561462402, + -1.2996302843093872, + 0.3853411078453064, + 0.256317138671875, + -4.1953911781311035, + 0.0779244527220726, + -0.5972115397453308, + 0.4336896538734436, + 0.6705561876296997, + -6.5105414390563965, + -0.47606387734413147, + 0.3342633843421936, + -3.9678432941436768, + 0.2751552164554596, + 1.084348440170288, + 2.9657156467437744, + 2.5475552082061768, + 1.8753401041030884, + 0.2996586263179779, + 0.1906520277261734, + -2.5899569988250732, + -3.644374370574951, + 1.733734130859375, + 0.09927695244550705, + -0.5668236613273621, + -0.0398385189473629, + -5.249869346618652, + -0.6177411675453186, + 2.3356411457061768, + 2.186732769012451, + 1.44122314453125, + -0.28696659207344055, + -2.392242431640625, + 0.5046539306640625, + 2.063197612762451, + 2.3057339191436768, + 0.9334062933921814, + -2.1853201389312744, + -2.138279438018799, + -2.3449618816375732, + -4.8304266929626465, + 1.9618748426437378, + 0.2988978922367096, + 4.87933349609375, + -3.3549368381500244, + -1.8041731119155884, + 6.3717217445373535, + -3.124995708465576, + 1.8935896158218384, + -2.9679043292999268, + -1.4023503065109253, + 0.3222220242023468, + -2.5279018878936768, + 2.076106548309326, + -1.7865077257156372, + 0.16515132784843445, + -5.7167181968688965, + 6.149100303649902, + 4.595162391662598, + 1.9351632595062256, + 1.8263680934906006, + 3.94433856010437, + 3.03369140625, + 7.472006797790527, + -0.4753025472164154, + 0.0076234000734984875, + -0.8170035481452942, + -1.98602294921875, + -7.766058444976807, + 0.70654296875, + 1.8416239023208618, + 4.912575721740723, + 3.6810824871063232, + -2.2141735553741455, + -0.1201302632689476, + -1.9947683811187744, + 2.9040908813476562, + -1.0383998155593872, + 0.3135114312171936, + 0.2766897976398468, + -0.9174281358718872, + -0.7639857530593872, + -0.1883675754070282, + -2.303928852081299, + 0.5981160998344421, + -1.8953334093093872, + 2.1259765625, + 0.4820556640625, + 1.9256068468093872, + 2.9588100910186768, + -0.0965968519449234, + -1.192138433456421, + -2.0869784355163574, + -1.0321534872055054, + -0.7515345811843872, + 0.5130571722984314, + 2.289768695831299, + 0.7618233561515808, + -0.41845703125, + -2.3865444660186768, + 3.5261929035186768, + -1.4132864475250244, + 1.9641331434249878, + 0.2858974039554596, + -0.5408052802085876, + -2.095951557159424, + 2.1583364009857178, + -3.317714214324951, + 3.450770854949951, + 0.86920166015625, + -2.1241018772125244, + -0.1886858195066452, + 2.2923409938812256, + 0.4393136203289032, + -1.362784743309021, + -1.5936105251312256, + 2.9157192707061768, + 1.8537379503250122, + 2.1375210285186768, + -4.092476844787598, + -1.2331193685531616, + 4.518031597137451, + -0.6594586968421936, + -2.4734280109405518, + 4.555210590362549, + -0.9694595336914062, + -1.6297520399093628, + -6.5728278160095215, + -0.8339625597000122, + -1.4741384983062744, + -2.5888497829437256, + 2.19736909866333, + -2.6287753582000732, + 3.434326171875, + 4.0056610107421875, + -0.4630388617515564, + 0.30289188027381897, + -3.8343136310577393, + 2.140468120574951, + 0.5897391438484192, + 2.3519287109375, + -2.86541748046875, + -1.9627424478530884, + 2.390842914581299, + 1.7625732421875, + -2.9275949001312256, + -1.066650390625, + -5.4803948402404785, + 1.2911550998687744, + 2.1221139430999756, + 0.9118739366531372, + 1.5941969156265259, + 2.1779696941375732, + -1.3908865451812744, + 2.4691989421844482, + -4.846435546875, + 2.494838237762451, + 0.9417397379875183, + 1.2230290174484253, + 0.3013567328453064, + 1.3652909994125366, + 3.0397448539733887, + 0.7940711975097656, + 0.9835248589515686, + 0.4757428765296936, + 0.06768798828125, + 1.4157496690750122, + 2.18408203125, + 3.2998220920562744, + -1.2731454372406006, + -0.1948416531085968, + 2.288609027862549, + 1.5747941732406616, + 0.8217424750328064, + -1.1267482042312622, + 1.7484697103500366, + -2.874540090560913, + -0.1531415730714798, + 0.4018985331058502, + 7.026611328125, + -1.4974801540374756, + 1.24755859375, + 3.711728811264038, + -0.0931745246052742, + 0.5085710883140564, + 3.465846538543701, + 1.3356149196624756, + -3.284574270248413, + -6.027137756347656, + 0.3550851047039032, + 1.2354212999343872, + -2.4462368488311768, + -2.1966726779937744, + 0.8658055067062378, + -1.2992727756500244, + 2.532039165496826, + 5.336617469787598, + 1.3142439126968384, + -5.3718438148498535, + 2.3848354816436768, + 4.135646343231201, + 2.0424249172210693, + -1.906494140625, + -0.4313643276691437, + -1.7317155599594116, + -0.36670467257499695, + 0.9658464789390564, + 0.1560756117105484, + 3.0009591579437256, + -0.8124215006828308, + 3.5099050998687744, + 0.8709716796875, + -3.790492534637451, + 1.3209315538406372, + -0.3829694390296936, + -1.5876203775405884, + 6.051383018493652, + 0.2808314859867096, + -4.0669755935668945, + -0.5103324055671692, + -2.3386547565460205, + 0.2144339382648468, + -3.672794818878174, + 1.0191389322280884, + -3.192409038543701, + -2.3015310764312744, + 2.8034908771514893, + 0.9870430827140808, + -2.1388986110687256, + -0.7306780219078064, + -0.6955108642578125, + -1.7762451171875, + -0.4906725287437439, + -2.4522814750671387, + -1.9080679416656494, + -0.0995168685913086, + -0.3851318359375, + 0.4381452202796936, + -1.5603201389312744, + 0.3734523355960846, + 0.5503770709037781, + -1.4910653829574585, + -0.5791712999343872, + -1.5470359325408936, + -0.5796770453453064, + 0.944854736328125, + 0.813262939453125, + 1.2693917751312256, + -0.51617431640625, + 0.3793809115886688, + -0.6896187663078308, + 2.51214599609375, + 2.6653201580047607, + 3.808837890625, + 0.6829398274421692, + 0.0564073845744133, + 0.0516030453145504, + -3.9235317707061768, + -2.5921456813812256, + -0.6518772840499878, + -3.9789602756500244, + 4.990303993225098, + -2.604248046875, + 0.0614253468811512, + 1.4492361545562744, + -2.204014301300049, + 1.00494384765625, + 2.9113070964813232, + -0.8735150098800659, + 2.022648334503174, + -0.9508231282234192, + 0.7837001085281372, + 0.6094273328781128, + 5.939278602600098, + 1.5818284749984741, + -4.207301616668701, + 4.2608208656311035, + 3.6223843097686768, + -2.48736572265625, + 6.7954888343811035, + 0.4980120062828064, + -0.867156982421875, + 2.037929058074951, + 0.948883056640625, + -2.4902780055999756, + 1.1662309169769287, + -0.3741019070148468, + -3.1960971355438232, + 3.3795166015625, + -2.21856689453125, + -1.2414419651031494, + -0.8126765489578247, + 1.2127206325531006, + 2.5965793132781982, + 4.789498329162598, + 7.391366004943848, + 0.5566057562828064, + 0.4663652777671814, + -2.27178955078125, + 3.659397602081299, + -3.7866897583007812, + -0.9372645616531372, + -1.5754884481430054, + 0.1054164320230484, + 1.8176661729812622, + 1.1129673719406128, + 2.6809844970703125, + 6.292588233947754, + 1.5832064151763916, + 1.7920619249343872, + 0.5061470866203308, + 5.290195941925049, + 1.4132080078125, + -5.368015766143799, + 1.2044874429702759, + 2.6851632595062256, + 1.8340715169906616, + 0.0400565005838871, + -1.5770787000656128, + -1.1393868923187256, + -0.2893589437007904, + -0.695982813835144, + 2.803419828414917, + 4.255959510803223, + -4.429220199584961, + 0.1621006578207016, + 2.2174007892608643, + -2.428745746612549, + -0.6703926920890808, + -3.9337856769561768, + 6.6768622398376465, + 0.0905282124876976, + -1.0003138780593872, + -0.9847951531410217, + -2.9611117839813232, + 1.964447021484375, + -3.1552822589874268, + 2.642333984375, + -3.942760467529297, + 0.5914219617843628, + 0.9695914387702942, + -0.4436994194984436, + 0.33599853515625, + 1.974090576171875, + -5.0568976402282715, + -0.8407968878746033, + 1.2749197483062744, + 2.0372939109802246, + -0.0290200375020504, + 0.9805101752281189, + -0.0390712209045887, + -3.57659912109375, + 0.4219224154949188, + -1.290771484375, + -1.4426095485687256, + -2.346400737762451, + 0.6495143175125122, + -0.9244559407234192, + 0.1436723917722702, + 0.5493556261062622, + -0.00047268185880966485, + -0.38580322265625, + -2.0276401042938232, + 0.3259451687335968, + -1.140899658203125, + -0.4427402913570404, + 0.7604021430015564, + -2.6973876953125, + -0.2725830078125, + 1.0211257934570312, + 1.58648681640625, + -1.1715959310531616, + 0.47999900579452515, + 3.264575481414795, + -0.7882952094078064, + 1.4681320190429688, + -0.26202392578125, + -0.2220022976398468, + -0.2738734781742096, + 4.617362022399902, + -3.3258755207061768, + 4.853363037109375, + -2.0185546875, + 3.036686420440674, + -0.7491542100906372, + 0.5954829454421997, + 2.5955941677093506, + -0.4901340901851654, + 1.2397810220718384, + -1.777344822883606, + 3.3977487087249756, + 4.3242011070251465, + -1.3063615560531616, + 0.5362548828125, + -0.5241437554359436, + -0.45632824301719666, + 0.4122140109539032, + -4.027064800262451, + 1.5869489908218384, + -1.413785696029663, + 8.817522048950195, + -4.0587334632873535, + 1.4163644313812256, + 0.3885149359703064, + -4.066720008850098, + -1.4301583766937256, + -3.158482074737549, + 1.5628575086593628, + 2.808994770050049, + -2.80255126953125, + 1.941375732421875, + 0.8428606390953064, + -0.5626046061515808, + 1.1475639343261719, + 2.062037944793701, + 3.9326694011688232, + -2.0560085773468018, + 4.044558048248291, + 5.232514381408691, + 1.9842126369476318, + -1.4781275987625122, + -3.6718575954437256, + -3.4373257160186768, + -1.747835397720337, + -2.6795480251312256, + 2.13226318359375, + 4.011940956115723, + 2.206455707550049, + -2.0218942165374756, + 7.621512413024902, + -3.1015799045562744, + 0.24678584933280945, + -0.6747785210609436, + -0.5925162434577942, + -1.7643095254898071, + -1.8974969387054443, + -1.9707902669906616, + -0.7918701171875, + -3.6648471355438232, + 0.7567280530929565, + -0.4102042019367218, + 1.4129115343093872, + 3.0222909450531006, + 2.9901645183563232, + 2.5119030475616455, + -2.1601040363311768, + -0.3768397867679596, + 2.31463623046875, + -2.6044833660125732, + 3.2892630100250244, + -2.294102191925049, + -0.4244036078453064, + 2.4927456378936768, + 4.287872314453125, + -3.803309917449951, + -0.3823024332523346, + -0.7725743055343628, + -0.2628653347492218, + -0.3093501627445221, + -0.5239781141281128, + 0.4457659125328064, + 1.4033552408218384, + -0.3488704264163971, + -0.9200439453125, + 1.5038975477218628, + -2.676792621612549, + 0.2867431640625, + -0.7061200737953186, + -0.6572178602218628, + -1.2484785318374634, + -1.7076416015625, + 1.6321324110031128, + -2.3448050022125244, + 3.4040963649749756, + 2.1000192165374756, + -3.811366558074951, + -1.0888932943344116, + 3.079883575439453, + -2.823758840560913, + -3.4528286457061768, + 0.1943228542804718, + -3.2894766330718994, + -2.5227835178375244, + -1.26116943359375, + -0.47723388671875, + -1.6092529296875, + -2.1056430339813232, + 3.8322317600250244, + -0.4105050265789032, + 0.6403285264968872, + -1.5356184244155884, + -2.0515310764312744, + -0.9304722547531128, + 1.3384617567062378, + 1.6592538356781006, + 0.4066859781742096, + 0.4439522922039032, + 3.352170705795288, + -0.2837389409542084, + -1.3254307508468628, + 3.0477774143218994, + 3.879359722137451, + -1.2551072835922241, + -4.452126502990723, + -1.2330801486968994, + 2.0595180988311768, + -1.1048322916030884, + -0.0780203714966774, + -2.8144073486328125, + -2.134033203125, + 0.330963134765625, + 4.0418701171875, + -4.337820529937744, + -0.6972852349281311, + 1.9071742296218872, + -5.939300537109375, + -3.3386056423187256, + -0.7183685302734375, + 0.31341552734375, + -4.439095497131348, + 0.5805271863937378, + -1.472259521484375, + -1.1590982675552368, + 0.6640755534172058, + -0.33135986328125, + 1.6120344400405884, + -0.1640625, + 1.5002092123031616, + 0.3495047390460968, + 6.437613487243652, + -2.3212368488311768, + -5.176355838775635, + 0.0445360466837883, + 4.923828125, + 1.7235630750656128, + -1.0057945251464844, + -1.8986380100250244, + 0.6353411078453064, + 0.33729007840156555, + -0.2164219468832016, + 4.554280757904053, + -7.502162456512451, + 0.36627197265625, + 1.3106220960617065, + -4.6493353843688965, + 1.0084620714187622, + -3.1793301105499268, + 4.670924663543701, + -2.9158236980438232, + 0.7572457194328308, + 1.2476893663406372, + -0.5692662000656128, + 7.9892401695251465, + -1.446962594985962, + 2.3811068534851074, + 2.5153720378875732, + -1.9798823595046997, + -2.017482280731201, + 5.631344795227051, + -0.5245274305343628, + 0.6235697865486145, + 3.3435909748077393, + 1.584929347038269, + -4.6143622398376465, + -0.07636479288339615, + 5.107936382293701, + 0.1702924519777298, + -3.6516811847686768, + -0.7376708984375, + -0.1347242146730423, + 1.0738874673843384, + 1.8848005533218384, + -3.854588031768799, + -0.9905133843421936, + 2.8249685764312744, + -2.689335346221924, + -2.6949462890625, + -2.0685513019561768, + 2.6602957248687744, + -1.0869663953781128, + -5.67138671875, + 1.53564453125, + -1.2739475965499878, + -1.2475062608718872, + -0.143798828125, + -0.6201869249343872, + 3.2704379558563232, + 2.4666225910186768, + 2.9981689453125, + -1.2709437608718872, + 1.4060494899749756, + -0.47799354791641235, + -1.8392333984375, + 0.02756173349916935, + 4.250295162200928, + -2.9367849826812744, + -0.8990609049797058, + 2.0455148220062256, + 1.3570207357406616, + -0.024709701538085938, + -0.4285888671875, + -1.10040283203125, + -1.1257978677749634, + 1.9264603853225708, + 0.0894121453166008, + 2.551975727081299, + 3.6622488498687744, + -0.6528974175453186, + 0.5827168226242065, + 3.1056387424468994, + -0.020151138305664062, + -1.3859513998031616, + 2.6150805950164795, + -1.5079171657562256, + 1.2898472547531128, + -0.1682652086019516, + 1.9762312173843384, + 6.718662738800049, + 1.811126708984375, + 1.4780404567718506, + -1.9839433431625366, + 3.6940786838531494, + -0.1426740437746048, + -0.6556788682937622, + -0.2710658609867096, + 3.9547293186187744, + -2.1108005046844482, + 1.7706211805343628, + -0.46283531188964844, + 1.0127955675125122, + -4.676723003387451, + 3.651289701461792, + 1.9275599718093872, + 2.179530620574951, + 4.863045692443848, + -3.321986675262451, + -0.3150634765625, + 4.7969536781311035, + -2.5327847003936768, + 2.608982563018799, + 0.7298747301101685, + 0.7437657117843628, + -2.956913471221924, + 1.0065078735351562, + -1.8590611219406128, + 0.3723711371421814, + 2.1537301540374756, + 2.4896278381347656, + -0.0408237986266613, + 0.3526611328125, + -3.8848397731781006, + 3.7967441082000732, + 2.414707660675049, + 3.7031075954437256, + 0.4591413140296936, + -0.5923200249671936, + -4.066127300262451, + -3.464198589324951, + -1.4086564779281616, + 1.1073347330093384, + -0.9924992322921753, + -2.2574026584625244, + -2.907313823699951, + -1.375152587890625, + -0.8378644585609436, + -2.7907016277313232, + 3.6422119140625, + 0.5093933939933777, + -3.987168550491333, + -1.9286106824874878, + -0.006814139429479837, + 2.0064260959625244, + 1.6555873155593872, + -1.42962646484375, + -2.6393067836761475, + 0.9099208116531372, + 0.4663173258304596, + -0.1270228773355484, + -2.0259835720062256, + 0.0686383917927742, + 0.749358057975769, + 0.6595276594161987, + -3.0650722980499268, + -3.8828015327453613, + 2.5249111652374268, + 1.9178030490875244, + -1.1191362142562866, + -0.4246826171875, + -1.1708897352218628, + 1.660736083984375, + -1.7340087890625, + 0.7905622124671936, + -6.0444159507751465, + 1.1692941188812256, + -1.3775438070297241, + 3.2480697631835938, + -0.4786115288734436, + 5.159885883331299, + 1.19354248046875, + 1.7737884521484375, + 0.5370745062828064, + -2.078824758529663, + -1.1570521593093872, + -2.4249267578125, + 1.6660417318344116, + 2.1804111003875732, + 1.2808488607406616, + 2.0166451930999756, + -1.7680772542953491, + 4.025634765625, + -0.2934526801109314, + -3.914585590362549, + 2.8634426593780518, + -3.0558102130889893, + 3.3683297634124756, + 3.9997994899749756, + 1.1302076578140259, + 0.5125994086265564, + 4.800571918487549, + 0.33196476101875305, + -4.239833354949951, + -2.2975375652313232, + 3.1443045139312744, + 0.4264788031578064, + -0.7162562608718872, + 2.9398324489593506, + 0.2423226535320282, + 0.8018973469734192, + 0.64691162109375, + -0.8960135579109192, + -0.1400495320558548, + -0.4073747992515564, + 2.0458285808563232, + -0.7931910753250122, + 4.673514366149902, + -0.6442217230796814, + -0.2457624226808548, + 2.5390625, + -1.5981009006500244, + -1.1390119791030884, + 6.062783241271973, + 1.9049421548843384, + -6.163643836975098, + 4.073050498962402, + 5.4387383460998535, + -2.597568988800049, + -0.09765625, + 0.5084228515625, + -4.606436729431152, + -1.5000697374343872, + 1.2774505615234375, + -1.5986067056655884, + 4.9994940757751465, + -2.8123257160186768, + -1.4108303785324097, + -3.599576711654663, + -1.0500880479812622, + 2.429530620574951, + -2.517378568649292, + -3.8703744411468506, + -3.0473806858062744, + -2.695087432861328, + -0.4087175726890564, + -0.1339154988527298, + -1.1456037759780884, + -0.09965842217206955, + 1.6002775430679321, + 1.94140625, + 8.233572959899902, + 4.693812847137451, + 6.3188323974609375, + -0.4952545166015625, + -0.8119899034500122, + -2.377406597137451, + -7.476841449737549, + 0.2299019992351532, + 2.7160556316375732, + 0.2903616726398468, + 2.0174038410186768, + 1.1787109375, + 2.198268413543701, + -4.846077919006348, + 0.3393380343914032, + 1.8988473415374756, + -0.3318001925945282, + 0.2745928168296814, + 1.9130859375, + 0.4395403265953064, + -4.6340508460998535, + 1.3759765625, + -1.5748814344406128, + 1.2059870958328247, + -2.2642822265625, + 5.461043834686279, + -3.942775249481201, + 2.6172659397125244, + -4.580601215362549, + -3.5568759441375732, + 0.5423790812492371, + -4.971827983856201, + -0.1230643168091774, + 0.6335536241531372, + -3.1558837890625, + -5.4010186195373535, + -0.5534232258796692, + -1.2707879543304443, + -1.1486293077468872, + 0.7239292860031128, + 2.513218402862549, + -2.2966482639312744, + 0.6248822808265686, + 3.65435791015625, + -0.5299797058105469, + 1.0541120767593384, + -3.016573190689087, + 2.0666677951812744, + 4.152622699737549, + -0.2540479302406311, + -0.8368813395500183, + 0.2802734375, + -1.1994673013687134, + -5.669154644012451, + 0.1134556382894516, + -0.18515340983867645, + -2.50054931640625, + 3.530726909637451, + -0.9219709038734436, + 2.3984200954437256, + -2.8649990558624268, + -2.114382028579712, + -3.6568691730499268, + 2.385166645050049, + -1.4322248697280884, + 4.672202110290527, + -0.779541015625, + 1.5408499240875244, + -0.004002162255346775, + -0.2390659898519516, + -3.94508695602417, + -0.4465092122554779, + -3.7096340656280518, + -3.6876394748687744, + 0.5224522352218628, + -1.9935563802719116, + 0.6487535834312439, + -0.9660469889640808, + 2.0344297885894775, + 0.8233991265296936, + -3.0709927082061768, + -0.38507080078125, + -0.2372087687253952, + -0.7461460828781128, + 1.6504276990890503, + 0.2703050971031189, + 2.552793264389038, + 2.445207357406616, + 0.7831202745437622, + -0.19610269367694855, + 1.0334559679031372, + 2.933925151824951, + -0.6499895453453064, + 2.827915668487549, + 1.122711181640625, + -1.8489553928375244, + -1.1916722059249878, + -2.3153076171875, + -0.7563694715499878, + 0.02211870439350605, + 3.5200893878936768, + -1.5191389322280884, + -1.1582205295562744, + -1.9055306911468506, + 1.8487894535064697, + -3.007603168487549, + -0.4868861734867096, + 2.46527099609375, + -1.6679164171218872, + -6.355564594268799, + 0.7562779188156128, + -2.4683315753936768, + 3.670379638671875, + 1.3462060689926147, + -1.0164968967437744, + 2.3893344402313232, + 0.8046439290046692, + -0.5739931464195251, + -2.0212314128875732, + -1.9585626125335693, + 0.7328120470046997, + -1.269287109375, + -6.473835468292236, + -1.9984400272369385, + -0.6884242296218872, + -1.7994970083236694, + -0.0750143900513649, + 6.476387977600098, + -5.4557061195373535, + -2.2372524738311768, + 1.2079881429672241, + 1.4984130859375, + 2.274261474609375, + -0.52471923828125, + 0.6165074110031128, + -0.9286237359046936, + -0.9547489881515503, + 0.2556588351726532, + -0.1026436910033226, + 2.279083251953125, + 2.595458984375, + -4.25250768661499, + -2.526285409927368, + 3.5586721897125244, + -1.2940673828125, + -1.51239013671875, + 2.7676479816436768, + -0.4703717827796936, + 0.9642769694328308, + -0.978118896484375, + 0.1579197496175766, + 0.5453676581382751, + 2.0121371746063232, + 0.48870849609375, + -0.00390625, + 1.762939453125, + -3.1055908203125, + 0.6965767741203308, + -1.1516897678375244, + 0.0004817417648155242, + -1.0688127279281616, + -2.1599884033203125, + -1.9842005968093872, + -0.2986798882484436, + -4.0548577308654785, + -2.824921131134033, + 2.6216866970062256, + -1.8844691514968872, + 1.7264927625656128, + -3.0637032985687256, + 2.2265841960906982, + -2.218715190887451, + 3.039154052734375, + 5.182407855987549, + 2.942195415496826, + 4.307059288024902, + 1.5004185438156128, + 0.7890973687171936, + -2.261989116668701, + -3.488856792449951, + 1.3433663845062256, + -0.8201271891593933, + -2.850830078125, + 4.463675498962402, + -1.7456403970718384, + -0.3608049750328064, + -2.0317294597625732, + -1.735262155532837, + -2.20257568359375, + 1.9657135009765625, + -1.6853288412094116, + -1.4964120388031006, + 0.2956106960773468, + -2.052976369857788, + -1.3885672092437744, + -3.264857769012451, + 2.7808139324188232, + 1.5269601345062256, + 1.780332326889038, + -1.4784132242202759, + 2.6995675563812256, + 2.357269287109375, + 3.084930419921875, + -2.4311349391937256, + 0.6557693481445312, + -1.1486642360687256, + -0.78547203540802, + 0.23770032823085785, + -0.5923287272453308, + 3.761143207550049, + -0.03001839853823185, + 1.1218785047531128, + 2.6851840019226074, + 2.2459347248077393, + 4.791678428649902, + -2.555018901824951, + -0.5224784016609192, + -0.2398158460855484, + 0.5201612114906311, + 8.621651649475098, + 2.8963100910186768, + 2.3454525470733643, + 0.7978690266609192, + -0.9012102484703064, + -0.7099434733390808, + -1.2477689981460571, + -0.7323870062828064, + 0.4278564453125, + -1.5228837728500366, + 2.9183175563812256, + 4.0020928382873535, + -0.7804129719734192, + -0.7708457112312317, + 0.860107421875, + -0.8754708170890808, + -0.3006417453289032, + 2.1483328342437744, + 2.684321880340576, + -2.741389751434326, + -0.36939892172813416, + -0.0590253546833992, + 0.1510445773601532, + 1.7613176107406616, + -1.3697978258132935, + -0.2923235297203064, + 0.2717241644859314, + 1.5536760091781616, + -1.7830810546875, + 1.6547197103500366, + 5.470729351043701, + -0.47369384765625, + -0.22546277940273285, + -1.5008544921875, + -1.4559544324874878, + 0.9464896321296692, + 1.3801814317703247, + -1.4257594347000122, + -0.3030613362789154, + 2.965420961380005, + 0.01947457529604435, + -0.4109409749507904, + 0.9576655626296997, + 0.1030186265707016, + -2.1613857746124268, + 2.7289044857025146, + -3.6953375339508057, + -0.126922607421875, + 0.6342076063156128, + 3.1033236980438232, + 3.3047049045562744, + -5.704624652862549, + 6.028110980987549, + -5.307645320892334, + 4.102565288543701, + 1.9133039712905884, + -1.6960057020187378, + -2.427685260772705, + -4.556343078613281, + -0.2339346706867218, + 1.06988525390625, + 1.0178996324539185, + -1.80126953125, + -1.3583177328109741, + -1.1456364393234253, + -2.2298409938812256, + 1.3711117506027222, + 0.7803431749343872, + -1.196990966796875, + -0.991943359375, + 2.0536410808563232, + 1.0089852809906006, + -0.7884346842765808, + -0.0284249447286129, + -2.0309360027313232, + 0.8349097371101379, + -1.2636631727218628, + 0.3933977484703064, + 1.4408830404281616, + 4.38775634765625, + -0.0925707146525383, + 3.3398263454437256, + 1.0220489501953125, + 2.8581368923187256, + -2.587890625, + 1.3697630167007446, + -1.7764543294906616, + -5.972098350524902, + -2.994384765625, + -7.550506591796875, + -1.1597779989242554, + -5.220025062561035, + 3.20068359375, + 0.66375732421875, + 2.7993338108062744, + -0.48101043701171875, + -1.2462921142578125, + -5.985787391662598, + -1.9978572130203247, + 0.5049176812171936, + -0.0856672003865242, + -1.5113961696624756, + 0.0942034050822258, + -1.7921665906906128, + -2.9268100261688232, + 1.8959089517593384, + -1.1236441135406494, + -0.0261361263692379, + 6.358176231384277, + -1.3226877450942993, + -1.3770925998687744, + -2.008272886276245, + -0.4505963921546936, + 1.8686168193817139, + -1.0233328342437744, + -4.358799457550049, + 1.563218355178833, + -2.7014334201812744, + -1.5951200723648071, + 1.8484867811203003, + 1.7940237522125244, + 3.2277743816375732, + -2.0062460899353027, + 3.9614083766937256, + 1.44873046875, + -0.5828508734703064, + 1.03912353515625, + 0.4829624593257904, + 3.340549945831299, + -0.7958635687828064, + -1.1615513563156128, + -0.4519135653972626, + 0.8144269585609436, + 3.689113140106201, + -2.455531597137451, + -2.041416645050049, + 1.8581063747406006, + 0.4922659695148468, + -0.6444876790046692, + 0.7671421766281128, + -2.020420551300049, + -1.5093907117843628, + -1.3747732639312744, + 3.466517925262451, + 1.383994460105896, + 2.654078960418701, + -1.9217703342437744, + 1.6833409070968628, + 3.7947561740875244, + 3.5545828342437744, + 1.9172537326812744, + 1.1147547960281372, + -0.4618617594242096, + -0.9286237359046936, + 0.6039864420890808, + 1.3183244466781616, + -1.8655122518539429, + 2.295436382293701, + -2.389495849609375, + 0.2897208034992218, + 0.9426051378250122, + -6.543007850646973, + -3.006376028060913, + -0.7586146593093872, + -0.2526811957359314, + -1.668581247329712, + -0.3232770562171936, + -0.3178495764732361, + -1.3785051107406616, + 4.219762325286865, + -2.9140625, + -1.2475847005844116, + 2.095851421356201, + -2.130039691925049, + -2.7372000217437744, + 0.8013131022453308, + 1.91534423828125, + 3.645993947982788, + -1.3698643445968628, + 0.4743804931640625, + -4.808218955993652, + 0.462066650390625, + -3.305659770965576, + 1.9328504800796509, + 2.0606536865234375, + 4.579277038574219, + -0.8594796061515808, + -1.2377406358718872, + -0.40064311027526855, + 0.6194981336593628, + 0.0762786865234375, + 3.5010986328125, + 0.40171104669570923, + -1.4345289468765259, + 1.569610595703125, + 5.9007744789123535, + -1.039215087890625, + 4.1089606285095215, + -0.9690159559249878, + -1.6934030055999756, + 3.116664409637451, + -0.5489720106124878, + -0.2609470784664154, + -0.2662266194820404, + -1.8018101453781128, + 0.4893929660320282, + -3.279506206512451, + 0.7186518907546997, + 1.1187394857406616, + 0.7865491509437561, + -4.650226765079424e-05, + 3.1499722003936768, + -0.2437395304441452, + -1.5889674425125122, + 1.3650468587875366, + 0.9197779893875122, + -1.1214773654937744, + 0.08832890540361404, + -0.8578752875328064, + 0.6497410535812378, + 0.7487226128578186, + -0.3346775472164154, + 0.8508736491203308, + 2.7823398113250732, + 2.8160922527313232, + 3.06982421875, + -2.9759695529937744, + -0.4650791585445404, + -1.4983607530593872, + -1.6126011610031128, + -2.7795846462249756, + -0.5329982042312622, + -2.7370083332061768, + 0.8951939344406128, + -1.1967347860336304, + 4.558070659637451, + -6.969918251037598, + 0.3604213297367096, + 1.0040370225906372, + 1.7347466945648193, + 0.8167899250984192, + 6.347342491149902, + 0.2352120578289032, + 2.1756591796875, + -1.4914027452468872, + 1.9434117078781128, + 1.48541259765625, + -4.174063682556152, + 1.9909842014312744, + 0.9074257612228394, + 0.47116851806640625, + -3.6428048610687256, + 3.4024658203125, + -1.8097273111343384, + -0.2045636922121048, + 0.7781633734703064, + -0.0772705078125, + -0.2133004367351532, + 0.1756330281496048, + 0.5462559461593628, + -3.8938772678375244, + -1.5120108127593994, + -0.8203604817390442, + -1.1930105686187744, + 0.2724347710609436, + -3.760768413543701, + -1.3391549587249756, + -2.2182791233062744, + 2.3978593349456787, + -1.4353779554367065, + 1.5769827365875244, + -2.1671600341796875, + 1.6707392930984497, + 0.4929722249507904, + 0.0277535580098629, + -2.567592144012451, + 0.7108677625656128, + -1.5133165121078491, + 1.7804391384124756, + 0.9736426472663879, + -0.1215733140707016, + -1.0896472930908203, + -1.4830496311187744, + 0.7186453938484192, + 2.4641201496124268, + 3.3061065673828125, + 2.2020785808563232, + 0.4203338623046875, + 2.5191824436187744, + 1.0797151327133179, + -0.6837899088859558, + -2.0876290798187256, + 3.7735769748687744, + 0.3598763644695282, + 0.28899383544921875, + 1.932708740234375, + -0.2517612874507904, + -0.8035103678703308, + -2.433720111846924, + 0.3788321316242218, + 0.8296944499015808, + 1.7119489908218384, + 3.274568796157837, + 2.3084914684295654, + -2.946629047393799, + 0.9382367730140686, + 0.3939950168132782, + 2.4859182834625244, + 0.9344744086265564, + -2.8529269695281982, + -1.4195382595062256, + 5.299560546875, + -0.9681374430656433, + -2.6157705783843994, + -0.5132707953453064, + 1.9645951986312866 + ], + "text_index": 0 + } + ] + }, + "usage": { + "total_tokens": 5 + }, + "request_id": "d594927d-cab6-46e7-91c5-664bbc06080d" + } + headers: + content-length: + - '29287' + content-type: + - application/json + date: + - Mon, 17 Nov 2025 08:31:24 GMT + req-arrive-time: + - '1763368285134' + req-cost-time: + - '90' + resp-start-time: + - '1763368285224' + server: + - istio-envoy + set-cookie: + - acw_tc=d594927d-cab6-46e7-91c5-664bbc06080d4141135933d9a3e33f6262a700ddae91;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '82' + x-request-id: + - d594927d-cab6-46e7-91c5-664bbc06080d + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_basic.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_basic.yaml new file mode 100644 index 000000000..29405447e --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_basic.yaml @@ -0,0 +1,92 @@ +interactions: +- request: + body: |- + { + "model": "gte-rerank", + "parameters": {}, + "input": { + "query": "What is machine learning?", + "documents": [ + "Machine learning is a subset of artificial intelligence.", + "Python is a programming language.", + "Deep learning uses neural networks." + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '241' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/rerank/text-rerank/text-rerank + response: + body: + string: |- + { + "output": { + "results": [ + { + "index": 0, + "relevance_score": 0.7353844222560253 + }, + { + "index": 2, + "relevance_score": 0.13988489287145767 + }, + { + "index": 1, + "relevance_score": 0.021986675780920666 + } + ] + }, + "usage": { + "total_tokens": 54 + }, + "request_id": "1fe6281a-1b9f-47ce-b733-5f710de2deab" + } + headers: + content-length: + - '254' + content-type: + - application/json + date: + - Mon, 17 Nov 2025 08:31:28 GMT + req-arrive-time: + - '1763368288817' + req-cost-time: + - '78' + resp-start-time: + - '1763368288895' + server: + - istio-envoy + set-cookie: + - acw_tc=1fe6281a-1b9f-47ce-b733-5f710de2deab8061786fc0ca1d70dac9ba88583240a4;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '69' + x-request-id: + - 1fe6281a-1b9f-47ce-b733-5f710de2deab + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_return_documents.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_return_documents.yaml new file mode 100644 index 000000000..ac76faf95 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_return_documents.yaml @@ -0,0 +1,95 @@ +interactions: +- request: + body: |- + { + "model": "gte-rerank", + "parameters": { + "return_documents": true + }, + "input": { + "query": "What is machine learning?", + "documents": [ + "Machine learning is a subset of AI.", + "Python is a programming language." + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '205' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/rerank/text-rerank/text-rerank + response: + body: + string: |- + { + "output": { + "results": [ + { + "document": { + "text": "Machine learning is a subset of AI." + }, + "index": 0, + "relevance_score": 0.716894992759484 + }, + { + "document": { + "text": "Python is a programming language." + }, + "index": 1, + "relevance_score": 0.021986675780920666 + } + ] + }, + "usage": { + "total_tokens": 34 + }, + "request_id": "da989af2-d815-483d-a9f7-c56f1de234aa" + } + headers: + content-length: + - '317' + content-type: + - application/json + date: + - Mon, 17 Nov 2025 08:31:29 GMT + req-arrive-time: + - '1763368289400' + req-cost-time: + - '80' + resp-start-time: + - '1763368289480' + server: + - istio-envoy + set-cookie: + - acw_tc=da989af2-d815-483d-a9f7-c56f1de234aa5dd08dd94c3ca6f8ac8611868cc4af73;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '74' + x-request-id: + - da989af2-d815-483d-a9f7-c56f1de234aa + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_with_top_n.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_with_top_n.yaml new file mode 100644 index 000000000..8c9264b6f --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_with_top_n.yaml @@ -0,0 +1,91 @@ +interactions: +- request: + body: |- + { + "model": "gte-rerank", + "parameters": { + "top_n": 2 + }, + "input": { + "query": "What is machine learning?", + "documents": [ + "Machine learning is a subset of AI.", + "Python is a programming language.", + "Deep learning uses neural networks.", + "Data science involves statistics." + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '267' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/rerank/text-rerank/text-rerank + response: + body: + string: |- + { + "output": { + "results": [ + { + "index": 0, + "relevance_score": 0.716894992759484 + }, + { + "index": 2, + "relevance_score": 0.13988489287145767 + } + ] + }, + "usage": { + "total_tokens": 68 + }, + "request_id": "70658564-7725-4701-958f-d9f4dda431fe" + } + headers: + content-length: + - '202' + content-type: + - application/json + date: + - Mon, 17 Nov 2025 08:31:28 GMT + req-arrive-time: + - '1763368289072' + req-cost-time: + - '110' + resp-start-time: + - '1763368289182' + server: + - istio-envoy + set-cookie: + - acw_tc=70658564-7725-4701-958f-d9f4dda431fe58c484735d41b587a2cc39c10c1179a1;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '102' + x-request-id: + - 70658564-7725-4701-958f-d9f4dda431fe + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py new file mode 100644 index 000000000..9277ec6dd --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py @@ -0,0 +1,132 @@ +"""Unit tests configuration module.""" + +import json +import os + +import pytest +import yaml +from loongsuite.instrumentation.dashscope import DashScopeInstrumentor + +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import SimpleSpanProcessor +from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( + InMemorySpanExporter, +) + + +@pytest.fixture(scope="function", name="span_exporter") +def fixture_span_exporter(): + """Create an in-memory span exporter for testing.""" + exporter = InMemorySpanExporter() + yield exporter + + +@pytest.fixture(scope="function", name="tracer_provider") +def fixture_tracer_provider(span_exporter): + """Create a tracer provider with in-memory exporter.""" + provider = TracerProvider() + provider.add_span_processor(SimpleSpanProcessor(span_exporter)) + return provider + + +@pytest.fixture(autouse=True) +def environment(): + """Set up environment variables for testing.""" + if not os.getenv("DASHSCOPE_API_KEY"): + # Use the provided API key from environment or set a test value + os.environ["DASHSCOPE_API_KEY"] = os.getenv( + "DASHSCOPE_API_KEY", "test_dashscope_api_key" + ) + + +@pytest.fixture(scope="function") +def instrument(tracer_provider): + """Instrument DashScope SDK for testing.""" + instrumentor = DashScopeInstrumentor() + instrumentor.instrument(tracer_provider=tracer_provider) + + yield instrumentor + + instrumentor.uninstrument() + + +@pytest.fixture(scope="module") +def vcr_config(): + """Configure VCR for recording/replaying HTTP interactions.""" + return { + "filter_headers": [ + ("authorization", "Bearer test_dashscope_api_key"), + ("x-dashscope-api-key", "test_dashscope_api_key"), + ], + "decode_compressed_response": True, + "before_record_response": scrub_response_headers, + } + + +class LiteralBlockScalar(str): + """Formats the string as a literal block scalar.""" + + +def literal_block_scalar_presenter(dumper, data): + """Represents a scalar string as a literal block.""" + return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|") + + +yaml.add_representer(LiteralBlockScalar, literal_block_scalar_presenter) + + +def process_string_value(string_value): + """Pretty-prints JSON or returns long strings as a LiteralBlockScalar.""" + try: + json_data = json.loads(string_value) + return LiteralBlockScalar(json.dumps(json_data, indent=2)) + except (ValueError, TypeError): + if len(string_value) > 80: + return LiteralBlockScalar(string_value) + return string_value + + +def convert_body_to_literal(data): + """Searches the data for body strings, attempting to pretty-print JSON.""" + if isinstance(data, dict): + for key, value in data.items(): + if key == "body" and isinstance(value, dict) and "string" in value: + value["string"] = process_string_value(value["string"]) + elif key == "body" and isinstance(value, str): + data[key] = process_string_value(value) + else: + convert_body_to_literal(value) + elif isinstance(data, list): + for idx, choice in enumerate(data): + data[idx] = convert_body_to_literal(choice) + return data + + +class PrettyPrintJSONBody: + """Makes request and response body recordings more readable.""" + + @staticmethod + def serialize(cassette_dict): + cassette_dict = convert_body_to_literal(cassette_dict) + return yaml.dump( + cassette_dict, default_flow_style=False, allow_unicode=True + ) + + @staticmethod + def deserialize(cassette_string): + return yaml.load(cassette_string, Loader=yaml.Loader) + + +@pytest.fixture(scope="module", autouse=True) +def fixture_vcr(vcr): + """Register custom VCR serializer.""" + vcr.register_serializer("yaml", PrettyPrintJSONBody) + return vcr + + +def scrub_response_headers(response): + """Scrubs sensitive response headers.""" + # Add any sensitive headers to scrub from responses + if "x-dashscope-request-id" in response.get("headers", {}): + response["headers"]["x-dashscope-request-id"] = "test_request_id" + return response diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt new file mode 100644 index 000000000..e096614d4 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt @@ -0,0 +1,47 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# ******************************** +# WARNING: NOT HERMETIC !!!!!!!!!! +# ******************************** +# +# This "requirements.txt" is installed in conjunction +# with multiple other dependencies in the top-level "tox-loongsuite.ini" +# file. In particular, please see: +# +# dashscope-latest: {[testenv]test_deps} +# dashscope-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt +# +# This provides additional dependencies, namely: +# +# opentelemetry-api +# opentelemetry-sdk +# opentelemetry-semantic-conventions +# +# ... with a "dev" version based on the latest distribution. + +# This variant of the requirements aims to test the system using +# the newest supported version of external dependencies. + +dashscope>=1.0.0 +pytest==7.4.4 +pytest-asyncio==0.21.0 +pytest-vcr==1.0.2 +vcrpy>=4.2.0 +pyyaml>=6.0 +wrapt==1.16.0 + +-e opentelemetry-instrumentation +-e instrumentation-loongsuite/loongsuite-instrumentation-dashscope + diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt new file mode 100644 index 000000000..13b72244f --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt @@ -0,0 +1,31 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This variant of the requirements aims to test the system using +# the oldest supported version of external dependencies. + +dashscope>=1.0.0 +pytest==7.4.4 +pytest-asyncio==0.21.0 +pytest-vcr==1.0.2 +vcrpy>=4.2.0 +pyyaml>=6.0 +wrapt==1.16.0 +opentelemetry-exporter-otlp-proto-http~=1.30 +opentelemetry-api==1.37 +opentelemetry-sdk==1.37 +opentelemetry-semantic-conventions==0.58b0 + +-e instrumentation-loongsuite/loongsuite-instrumentation-dashscope + diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py new file mode 100644 index 000000000..9819d80db --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py @@ -0,0 +1,44 @@ +"""Tests for TextEmbedding instrumentation.""" + +import pytest + + +@pytest.mark.vcr() +def test_text_embedding_basic(instrument): + """Test basic text embedding call.""" + from dashscope import TextEmbedding + + response = TextEmbedding.call( + model="text-embedding-v1", input="Hello, world!" + ) + + assert response is not None + print("✓ TextEmbedding.call completed successfully") + + +@pytest.mark.vcr() +def test_text_embedding_batch(instrument): + """Test text embedding with batch input.""" + from dashscope import TextEmbedding + + response = TextEmbedding.call( + model="text-embedding-v1", input=["Hello", "World"] + ) + + assert response is not None + print("✓ TextEmbedding.call (batch) completed successfully") + + +@pytest.mark.vcr() +def test_text_embedding_with_text_type(instrument): + """Test text embedding with text_type parameter.""" + from dashscope import TextEmbedding + + response = TextEmbedding.call( + model="text-embedding-v1", + input="What is machine learning?", + text_type="query", + ) + + assert response is not None + print("✓ TextEmbedding.call (with text_type) completed successfully") diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py new file mode 100644 index 000000000..8103964af --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py @@ -0,0 +1,93 @@ +"""Tests for Generation instrumentation.""" + +import pytest + + +@pytest.mark.vcr() +def test_generation_call_basic(instrument): + """Test basic synchronous generation call.""" + from dashscope import Generation + + response = Generation.call(model="qwen-turbo", prompt="Hello!") + + assert response is not None + print("✓ Generation.call (basic) completed successfully") + + +@pytest.mark.vcr() +def test_generation_call_with_messages(instrument): + """Test generation call with messages parameter.""" + from dashscope import Generation + + response = Generation.call( + model="qwen-turbo", messages=[{"role": "user", "content": "Hello!"}] + ) + + assert response is not None + print("✓ Generation.call (with messages) completed successfully") + + +@pytest.mark.vcr() +def test_generation_call_streaming(instrument): + """Test synchronous generation with streaming.""" + from dashscope import Generation + + responses = Generation.call( + model="qwen-turbo", prompt="Count from 1 to 5", stream=True + ) + + chunk_count = 0 + for response in responses: + assert response is not None + chunk_count += 1 + + assert chunk_count > 0 + print(f"✓ Generation.call (streaming) received {chunk_count} chunks") + + +@pytest.mark.vcr() +def test_generation_call_with_parameters(instrument): + """Test generation call with various parameters.""" + from dashscope import Generation + + response = Generation.call( + model="qwen-turbo", + prompt="Write a short poem", + temperature=0.8, + top_p=0.9, + max_tokens=100, + ) + + assert response is not None + print("✓ Generation.call (with parameters) completed successfully") + + +@pytest.mark.asyncio +@pytest.mark.vcr() +async def test_aio_generation_call_basic(instrument): + """Test basic asynchronous generation call.""" + from dashscope import AioGeneration + + response = await AioGeneration.call(model="qwen-turbo", prompt="Hello!") + + assert response is not None + print("✓ AioGeneration.call (basic) completed successfully") + + +@pytest.mark.asyncio +@pytest.mark.vcr() +async def test_aio_generation_call_streaming(instrument): + """Test asynchronous generation with streaming.""" + from dashscope import AioGeneration + + responses = await AioGeneration.call( + model="qwen-turbo", prompt="Count from 1 to 5", stream=True + ) + + chunk_count = 0 + async for response in responses: + assert response is not None + chunk_count += 1 + + assert chunk_count > 0 + print(f"✓ AioGeneration.call (streaming) received {chunk_count} chunks") diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py new file mode 100644 index 000000000..c538e14a8 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py @@ -0,0 +1,62 @@ +"""Tests for TextReRank instrumentation.""" + +import pytest + + +@pytest.mark.vcr() +def test_text_rerank_basic(instrument): + """Test basic text rerank call.""" + from dashscope import TextReRank + + response = TextReRank.call( + model="gte-rerank", + query="What is machine learning?", + documents=[ + "Machine learning is a subset of artificial intelligence.", + "Python is a programming language.", + "Deep learning uses neural networks.", + ], + ) + + assert response is not None + print("✓ TextReRank.call (basic) completed successfully") + + +@pytest.mark.vcr() +def test_text_rerank_with_top_n(instrument): + """Test text rerank with top_n parameter.""" + from dashscope import TextReRank + + response = TextReRank.call( + model="gte-rerank", + query="What is machine learning?", + documents=[ + "Machine learning is a subset of AI.", + "Python is a programming language.", + "Deep learning uses neural networks.", + "Data science involves statistics.", + ], + top_n=2, + ) + + assert response is not None + print("✓ TextReRank.call (with top_n) completed successfully") + + +@pytest.mark.vcr() +def test_text_rerank_return_documents(instrument): + """Test text rerank with return_documents parameter.""" + from dashscope import TextReRank + + response = TextReRank.call( + model="gte-rerank", + query="What is machine learning?", + documents=[ + "Machine learning is a subset of AI.", + "Python is a programming language.", + ], + return_documents=True, + ) + + assert response is not None + print("✓ TextReRank.call (return_documents) completed successfully") diff --git a/tox-loongsuite.ini b/tox-loongsuite.ini index fe0efb26e..8679fb01f 100644 --- a/tox-loongsuite.ini +++ b/tox-loongsuite.ini @@ -20,6 +20,10 @@ envlist = ; py3{10,11,12,13}-test-loongsuite-instrumentation-agentscope-1 ; lint-loongsuite-instrumentation-agentscope + ; loongsuite-instrumentation-dashscope + py3{9,10,11,12,13}-test-loongsuite-instrumentation-dashscope-{oldest,latest} + lint-loongsuite-instrumentation-dashscope + ; ; loongsuite-instrumentation-agno ; py3{9,10,11,12,13}-test-loongsuite-instrumentation-agno ; lint-loongsuite-instrumentation-agno @@ -54,6 +58,11 @@ deps = loongsuite-agentscope: {[testenv]test_deps} loongsuite-agentscope-1: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/test-requirements-1.txt + dashscope-oldest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt + dashscope-latest: {[testenv]test_deps} + dashscope-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt + lint-loongsuite-instrumentation-dashscope: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt + loongsuite-agno: {[testenv]test_deps} loongsuite-agno: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-agno/test-requirements.txt @@ -81,7 +90,7 @@ setenv = ; i.e: CORE_REPO_SHA=dde62cebffe519c35875af6d06fae053b3be65ec tox -e CORE_REPO_SHA={env:CORE_REPO_SHA:main} CORE_REPO=git+https://github.com/open-telemetry/opentelemetry-python.git@{env:CORE_REPO_SHA} - UV_CONFIG_FILE={toxinidir}/tox-uv.toml + UV_CONFIG_FILE={toxinidir}/tox-uv.toml commands_pre = ; In order to get a health coverage report, @@ -92,6 +101,9 @@ commands = test-loongsuite-instrumentation-agentscope: pytest {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/tests {posargs} lint-loongsuite-instrumentation-agentscope: python -m ruff check {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-agentscope + test-loongsuite-instrumentation-dashscope: pytest {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests {posargs} + lint-loongsuite-instrumentation-dashscope: python -m ruff check {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-dashscope + test-loongsuite-instrumentation-agno: pytest {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-agno/tests {posargs} lint-loongsuite-instrumentation-agno: python -m ruff check {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-agno From 7d3e0c32461e5edfd79e6a5df2239a2235f98d80 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Tue, 18 Nov 2025 21:09:44 +0800 Subject: [PATCH 2/9] Add extended message parts Change-Id: Idfc66dd6ed64b65b1f3d5e31d2be9a357168376d Co-developed-by: Cursor --- util/opentelemetry-util-genai/README-loongsuite.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/util/opentelemetry-util-genai/README-loongsuite.rst b/util/opentelemetry-util-genai/README-loongsuite.rst index e49ed4e7a..850c4030f 100644 --- a/util/opentelemetry-util-genai/README-loongsuite.rst +++ b/util/opentelemetry-util-genai/README-loongsuite.rst @@ -614,6 +614,7 @@ Token 使用: 设计文档 -------- +<<<<<<< HEAD OpenTelemetry GenAI Utils 的设计文档: `Design Document `_ 参考资料 @@ -622,4 +623,10 @@ OpenTelemetry GenAI Utils 的设计文档: `Design Document `_ * `OpenTelemetry GenAI Semantic Conventions `_ * `LoongSuite OpenTelemetry Python Agent `_ +======= +- ``ExtendedTelemetryHandler`` 是 ``TelemetryHandler`` 的子类,完全兼容原有 API +- 可以安全地替换 ``get_telemetry_handler()`` 为 ``get_extended_telemetry_handler()`` +- 所有原有功能保持不变,只是增加了新的操作类型支持 +- Embedding 操作的 ``gen_ai.operation.name`` 应该是 ``"embeddings"`` (复数形式),符合语义规范 +>>>>>>> 3a90289e3 (Add extended message parts) From fe43dee423d2ebabbb534de16a1ae81a85266c59 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Tue, 18 Nov 2025 21:10:42 +0800 Subject: [PATCH 3/9] Capture input messages, output messages and tool definitions for dashscope Change-Id: I90fcb95206d3da49513015ad59849fe056a5c594 Co-developed-by: Cursor --- .../CHANGELOG.md | 8 +- .../README.rst | 87 +- .../pyproject.toml | 1 + .../instrumentation/dashscope/__init__.py | 50 +- .../instrumentation/dashscope/patch.py | 386 +++- .../instrumentation/dashscope/utils.py | 614 +++++++ ...ion_call_streaming_incremental_output.yaml | 100 + ...st_generation_call_no_content_capture.yaml | 86 + ...ion_call_streaming_incremental_output.yaml | 110 ++ ...t_generation_call_with_all_parameters.yaml | 93 + ..._generation_call_with_content_capture.yaml | 86 + ...tion_call_with_prompt_content_capture.yaml | 81 + ...th_tool_call_response_content_capture.yaml | 262 +++ ..._call_with_tool_calls_content_capture.yaml | 128 ++ ...ll_with_tool_calls_no_content_capture.yaml | 128 ++ .../test_text_embedding_with_dimension.yaml | 1621 +++++++++++++++++ .../test_text_rerank_error_handling.yaml | 70 + .../tests/conftest.py | 57 + .../tests/requirements.latest.txt | 1 + .../tests/requirements.oldest.txt | 1 + .../tests/test_embedding.py | 238 ++- .../tests/test_generation.py | 1128 +++++++++++- .../tests/test_rerank.py | 122 +- 23 files changed, 5368 insertions(+), 90 deletions(-) create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_streaming_incremental_output.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_no_content_capture.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_streaming_incremental_output.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_all_parameters.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_content_capture.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_prompt_content_capture.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_call_response_content_capture.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_calls_content_capture.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_calls_no_content_capture.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_with_dimension.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_error_handling.yaml diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md index a6eccaedd..0f9bb70d3 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md @@ -12,7 +12,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Support for Generation.call (sync) - Support for AioGeneration.call (async) - Support for TextEmbedding.call -- Support for Completions.create (OpenAI-compatible) - Support for TextReRank.call - Support for streaming responses (sync and async) +- Data extraction and telemetry collection using `opentelemetry-util-genai` +- Span attributes following OpenTelemetry GenAI Semantic Conventions: + - Operation name, provider name, model names + - Token usage (input/output tokens) + - Finish reasons + - Request parameters (temperature, top_p, max_tokens) + - Response ID diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst index 439b8b673..3307f6a9d 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst @@ -54,11 +54,6 @@ Supported APIs * ``AioGeneration.call`` (async) * Streaming support for both sync and async -* **Chat Completion** - - * ``Completions.create`` (OpenAI-compatible, sync) - * Streaming support - * **Text Embedding** * ``TextEmbedding.call`` @@ -68,6 +63,71 @@ Supported APIs * ``TextReRank.call`` +Captured Attributes +-------------------- + +This instrumentation follows the `OpenTelemetry GenAI Semantic Conventions `_ +and uses `opentelemetry-util-genai` for standardized telemetry collection. + +For **Text Generation** (Chat Completion) operations, the following attributes are captured: + +**Required Attributes:** +* ``gen_ai.operation.name`` - Operation type ("chat") +* ``gen_ai.provider.name`` - Provider name ("dashscope") + +**Conditionally Required Attributes:** +* ``gen_ai.request.model`` - Requested model name (if available) +* ``gen_ai.response.model`` - Actual model used (if different from request) +* ``gen_ai.response.id`` - Request ID from DashScope (if available) +* ``error.type`` - Error type (if operation ended in error) + +**Recommended Attributes:** +* ``gen_ai.response.finish_reasons`` - Finish reasons array (e.g., ["stop"], ["length"]) +* ``gen_ai.usage.input_tokens`` - Input token count +* ``gen_ai.usage.output_tokens`` - Output token count +* ``gen_ai.request.temperature`` - Temperature parameter (if provided) +* ``gen_ai.request.top_p`` - Top-p parameter (if provided) +* ``gen_ai.request.top_k`` - Top-k parameter (if provided) +* ``gen_ai.request.max_tokens`` - Max tokens parameter (if provided) + +**Opt-In Attributes** (require environment variable configuration): +* ``gen_ai.input.messages`` - Chat history provided to the model +* ``gen_ai.output.messages`` - Messages returned by the model + +To enable Opt-In attributes, set the environment variable: + +:: + + export OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental + export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=SPAN_ONLY + +For **Text Embedding** operations: + +**Required Attributes:** +* ``gen_ai.operation.name`` - Operation type ("embeddings", note: plural form) +* ``gen_ai.provider.name`` - Provider name ("dashscope") + +**Conditionally Required Attributes:** +* ``gen_ai.request.model`` - Requested model name (if available) +* ``error.type`` - Error type (if operation ended in error) + +**Recommended Attributes:** +* ``gen_ai.usage.input_tokens`` - Input token count (if available) +* ``gen_ai.embeddings.dimension.count`` - Number of dimensions (if available) +* ``gen_ai.request.encoding_formats`` - Encoding formats (if specified) + +For **Text Rerank** operations: + +**Note:** Rerank operations are not yet explicitly defined in GenAI semantic conventions. +This instrumentation follows the pattern of other GenAI operations. + +**Basic Attributes:** +* ``gen_ai.operation.name`` - Operation type ("rerank") +* ``gen_ai.provider.name`` - Provider name ("dashscope") +* ``gen_ai.request.model`` - Requested model name (if available) +* ``error.type`` - Error type (if operation ended in error) + + Configuration ------------- @@ -80,6 +140,23 @@ Set your DashScope API key via environment variable: export DASHSCOPE_API_KEY="your-api-key-here" +Message Content Capture +~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, message content (``gen_ai.input.messages`` and ``gen_ai.output.messages``) is not captured +to protect sensitive data. To enable content capture, set the following environment variables: + +:: + + export OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental + export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=SPAN_ONLY + +Options for ``OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT``: +* ``SPAN_ONLY`` - Capture content in span attributes only +* ``SPAN_AND_EVENT`` - Capture content in both spans and events +* ``EVENT_ONLY`` - Capture content in events only (not yet supported) +* ``NO_CONTENT`` - Do not capture content (default) + References ---------- diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/pyproject.toml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/pyproject.toml index cc8fa7131..7e762b9ae 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/pyproject.toml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/pyproject.toml @@ -28,6 +28,7 @@ dependencies = [ "opentelemetry-api ~= 1.37", "opentelemetry-instrumentation ~= 0.58b0", "opentelemetry-semantic-conventions ~= 0.58b0", + "opentelemetry-util-genai ~= 0.2b0", ] [project.optional-dependencies] diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py index ed8687edb..d6d99f5fa 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py @@ -53,6 +53,10 @@ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.utils import unwrap +from opentelemetry.util.genai.extended_handler import ( + ExtendedTelemetryHandler, + get_extended_telemetry_handler, +) logger = logging.getLogger(__name__) @@ -88,12 +92,50 @@ def _instrument(self, **kwargs): """ logger.info("Instrumenting DashScope SDK") + # Get tracer_provider from kwargs and create handler instance + tracer_provider = kwargs.get("tracer_provider") + if tracer_provider is not None: + # Create handler instance with provided tracer_provider + handler = ExtendedTelemetryHandler(tracer_provider=tracer_provider) + else: + # Use singleton handler + handler = get_extended_telemetry_handler() + + # Create wrapper functions with handler closure + def wrap_generation_call_with_provider( + wrapped, instance, args, kwargs + ): + return wrap_generation_call( + wrapped, instance, args, kwargs, handler=handler + ) + + def wrap_aio_generation_call_with_provider( + wrapped, instance, args, kwargs + ): + return wrap_aio_generation_call( + wrapped, instance, args, kwargs, handler=handler + ) + + def wrap_text_embedding_call_with_provider( + wrapped, instance, args, kwargs + ): + return wrap_text_embedding_call( + wrapped, instance, args, kwargs, handler=handler + ) + + def wrap_text_rerank_call_with_provider( + wrapped, instance, args, kwargs + ): + return wrap_text_rerank_call( + wrapped, instance, args, kwargs, handler=handler + ) + # Instrument Generation.call (sync) try: wrap_function_wrapper( module=_MODULE_GENERATION, name="Generation.call", - wrapper=wrap_generation_call, + wrapper=wrap_generation_call_with_provider, ) logger.debug("Instrumented Generation.call") except Exception as e: @@ -104,7 +146,7 @@ def _instrument(self, **kwargs): wrap_function_wrapper( module=_MODULE_GENERATION, name="AioGeneration.call", - wrapper=wrap_aio_generation_call, + wrapper=wrap_aio_generation_call_with_provider, ) logger.debug("Instrumented AioGeneration.call") except Exception as e: @@ -115,7 +157,7 @@ def _instrument(self, **kwargs): wrap_function_wrapper( module=_MODULE_TEXT_EMBEDDING, name="TextEmbedding.call", - wrapper=wrap_text_embedding_call, + wrapper=wrap_text_embedding_call_with_provider, ) logger.debug("Instrumented TextEmbedding.call") except Exception as e: @@ -126,7 +168,7 @@ def _instrument(self, **kwargs): wrap_function_wrapper( module=_MODULE_TEXT_RERANK, name="TextReRank.call", - wrapper=wrap_text_rerank_call, + wrapper=wrap_text_rerank_call_with_provider, ) logger.debug("Instrumented TextReRank.call") except Exception as e: diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py index 42a6b9bec..887c9d50a 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py @@ -17,6 +17,19 @@ import inspect import logging +from opentelemetry.util.genai.extended_types import ( + EmbeddingInvocation, + RerankInvocation, +) +from opentelemetry.util.genai.types import Error + +from .utils import ( + _create_accumulated_response, + _create_invocation_from_generation, + _get_parameter, + _update_invocation_from_response, +) + logger = logging.getLogger(__name__) @@ -25,111 +38,356 @@ def _is_streaming_response(result): return inspect.isgenerator(result) or inspect.isasyncgen(result) -def wrap_generation_call(wrapped, instance, args, kwargs): - """Wrapper for Generation.call (sync).""" - print("[INSTRUMENTATION] Entering Generation.call") - print(f"[INSTRUMENTATION] Args count: {len(args)}") - print(f"[INSTRUMENTATION] Kwargs keys: {list(kwargs.keys())}") +def wrap_generation_call(wrapped, instance, args, kwargs, handler=None): + """Wrapper for Generation.call (sync). + + Uses TelemetryHandler from opentelemetry-util-genai to manage span lifecycle. + + Args: + wrapped: The original function being wrapped + instance: The instance the method is bound to (if any) + args: Positional arguments + kwargs: Keyword arguments + handler: ExtendedTelemetryHandler instance (created during instrumentation) + """ + # Extract model from kwargs + model = kwargs.get("model") + if not model: + logger.warning("Model not found in kwargs, skipping instrumentation") + return wrapped(*args, **kwargs) + + if handler is None: + logger.warning("Handler not provided, skipping instrumentation") + return wrapped(*args, **kwargs) try: - result = wrapped(*args, **kwargs) + # Create invocation object + invocation = _create_invocation_from_generation(kwargs, model) + + # Start LLM invocation (creates span) + handler.start_llm(invocation) + + try: + # Execute the wrapped call + result = wrapped(*args, **kwargs) + + # Handle streaming response + if _is_streaming_response(result): + # Check incremental_output parameter (default is False, meaning full output) + incremental_output = _get_parameter( + kwargs, "incremental_output" + ) + return _wrap_sync_generator( + result, + handler, + invocation, + incremental_output=incremental_output, + ) - if _is_streaming_response(result): - print("[INSTRUMENTATION] Detected streaming response (Generator)") - return _wrap_sync_generator(result) - else: - print("[INSTRUMENTATION] Call successful (non-streaming)") + # Handle non-streaming response + _update_invocation_from_response(invocation, result) + handler.stop_llm(invocation) return result + except Exception as e: + error = Error(message=str(e), type=type(e)) + handler.fail_llm(invocation, error) + raise + except Exception as e: - print(f"[INSTRUMENTATION] Exception caught: {type(e).__name__}: {e}") - raise + logger.exception("Error in instrumentation wrapper: %s", e) + return wrapped(*args, **kwargs) + + +def wrap_aio_generation_call(wrapped, instance, args, kwargs, handler=None): + """Wrapper for AioGeneration.call (async). + Uses TelemetryHandler from opentelemetry-util-genai to manage span lifecycle. -def wrap_aio_generation_call(wrapped, instance, args, kwargs): - """Wrapper for AioGeneration.call (async).""" + Args: + wrapped: The original function being wrapped + instance: The instance the method is bound to (if any) + args: Positional arguments + kwargs: Keyword arguments + handler: ExtendedTelemetryHandler instance (created during instrumentation) + """ async def async_wrapper(): - print("[INSTRUMENTATION] Entering AioGeneration.call (async)") - print(f"[INSTRUMENTATION] Args count: {len(args)}") - print(f"[INSTRUMENTATION] Kwargs keys: {list(kwargs.keys())}") + # Extract model from kwargs + model = kwargs.get("model") + if not model: + logger.warning( + "Model not found in kwargs, skipping instrumentation" + ) + return await wrapped(*args, **kwargs) + + if handler is None: + logger.warning("Handler not provided, skipping instrumentation") + return await wrapped(*args, **kwargs) try: - result = await wrapped(*args, **kwargs) + # Create invocation object + invocation = _create_invocation_from_generation(kwargs, model) - if _is_streaming_response(result): - print( - "[INSTRUMENTATION] Detected streaming response (AsyncGenerator)" - ) - return _wrap_async_generator(result) - else: - print("[INSTRUMENTATION] Call successful (non-streaming)") + # Start LLM invocation (creates span) + handler.start_llm(invocation) + + try: + # Execute the wrapped call + result = await wrapped(*args, **kwargs) + + # Handle streaming response + if _is_streaming_response(result): + # Check incremental_output parameter (default is False, meaning full output) + incremental_output = _get_parameter( + kwargs, "incremental_output" + ) + return _wrap_async_generator( + result, + handler, + invocation, + incremental_output=incremental_output, + ) + + # Handle non-streaming response + _update_invocation_from_response(invocation, result) + handler.stop_llm(invocation) return result + except Exception as e: + error = Error(message=str(e), type=type(e)) + handler.fail_llm(invocation, error) + raise + except Exception as e: - print( - f"[INSTRUMENTATION] Exception caught: {type(e).__name__}: {e}" - ) - raise + logger.exception("Error in async instrumentation wrapper: %s", e) + return await wrapped(*args, **kwargs) return async_wrapper() -def wrap_text_embedding_call(wrapped, instance, args, kwargs): - """Wrapper for TextEmbedding.call.""" - print("[INSTRUMENTATION] Entering TextEmbedding.call") - print(f"[INSTRUMENTATION] Args count: {len(args)}") - print(f"[INSTRUMENTATION] Kwargs keys: {list(kwargs.keys())}") +def wrap_text_embedding_call(wrapped, instance, args, kwargs, handler=None): + """Wrapper for TextEmbedding.call. + + Uses ExtendedTelemetryHandler which supports embedding operations. + + Args: + wrapped: The original function being wrapped + instance: The instance the method is bound to (if any) + args: Positional arguments + kwargs: Keyword arguments + handler: ExtendedTelemetryHandler instance (created during instrumentation) + """ + # Extract model from kwargs + model = kwargs.get("model") + if not model: + logger.warning("Model not found in kwargs, skipping instrumentation") + return wrapped(*args, **kwargs) + + if handler is None: + logger.warning("Handler not provided, skipping instrumentation") + return wrapped(*args, **kwargs) try: - result = wrapped(*args, **kwargs) - print("[INSTRUMENTATION] Call successful") - return result + # Create embedding invocation object + invocation = EmbeddingInvocation(request_model=model) + invocation.provider = "dashscope" + + # Extract parameters from kwargs or kwargs["parameters"] dict + parameters = kwargs.get("parameters", {}) + if not isinstance(parameters, dict): + parameters = {} + + # Extract dimension count if specified + dimension = _get_parameter( + kwargs, "dimension", parameters + ) or _get_parameter(kwargs, "dimensions", parameters) + if dimension is not None: + invocation.dimension_count = dimension + + # Start embedding invocation (creates span) + handler.start_embedding(invocation) + + try: + # Execute the wrapped call + result = wrapped(*args, **kwargs) + + # Extract usage information and other attributes + # DashScope embedding response uses total_tokens (not input_tokens) + if result: + try: + usage = getattr(result, "usage", None) + if usage is not None and isinstance(usage, dict): + # For embedding, DashScope uses total_tokens instead of input_tokens + total_tokens = usage.get("total_tokens") + if total_tokens is not None: + invocation.input_tokens = total_tokens + except (KeyError, AttributeError): + # If usage extraction fails, continue without setting input_tokens + pass + + # Successfully complete (sets attributes and ends span) + handler.stop_embedding(invocation) + return result + + except Exception as e: + # Failure handling (sets error attributes and ends span) + error = Error(message=str(e), type=type(e)) + handler.fail_embedding(invocation, error) + raise except Exception as e: - print(f"[INSTRUMENTATION] Exception caught: {type(e).__name__}: {e}") - raise + logger.exception("Error in embedding instrumentation wrapper: %s", e) + return wrapped(*args, **kwargs) + + +def wrap_text_rerank_call(wrapped, instance, args, kwargs, handler=None): + """Wrapper for TextReRank.call. + Uses ExtendedTelemetryHandler which supports rerank operations. -def wrap_text_rerank_call(wrapped, instance, args, kwargs): - """Wrapper for TextReRank.call.""" - print("[INSTRUMENTATION] Entering TextReRank.call") - print(f"[INSTRUMENTATION] Args count: {len(args)}") - print(f"[INSTRUMENTATION] Kwargs keys: {list(kwargs.keys())}") + Args: + wrapped: The original function being wrapped + instance: The instance the method is bound to (if any) + args: Positional arguments + kwargs: Keyword arguments + handler: ExtendedTelemetryHandler instance (created during instrumentation) + """ + # Extract model from kwargs + model = kwargs.get("model") + if not model: + logger.warning("Model not found in kwargs, skipping instrumentation") + return wrapped(*args, **kwargs) + + if handler is None: + logger.warning("Handler not provided, skipping instrumentation") + return wrapped(*args, **kwargs) try: - result = wrapped(*args, **kwargs) - print("[INSTRUMENTATION] Call successful") - return result + # Create rerank invocation object + invocation = RerankInvocation(request_model=model) + invocation.provider = "dashscope" + + # Start rerank invocation (creates span) + handler.start_rerank(invocation) + + try: + # Execute the wrapped call + result = wrapped(*args, **kwargs) + + # Successfully complete (sets attributes and ends span) + handler.stop_rerank(invocation) + return result + + except Exception as e: + # Failure handling (sets error attributes and ends span) + error = Error(message=str(e), type=type(e)) + handler.fail_rerank(invocation, error) + raise except Exception as e: - print(f"[INSTRUMENTATION] Exception caught: {type(e).__name__}: {e}") - raise + logger.exception("Error in rerank instrumentation wrapper: %s", e) + return wrapped(*args, **kwargs) + + +def _wrap_sync_generator( + generator, handler, invocation, incremental_output=None +): + """Wrap a synchronous generator to collect data and set attributes. + Args: + generator: The generator to wrap + handler: TelemetryHandler instance + invocation: LLMInvocation object + incremental_output: If True, chunks contain only incremental text (need to accumulate). + If False or None (default), chunks contain full accumulated text. + """ + last_response = None + accumulated_text = "" -def _wrap_sync_generator(generator): - """Wrap a synchronous generator to log each chunk.""" try: for chunk in generator: - print("[INSTRUMENTATION] Received streaming chunk") + last_response = chunk + + # If incremental_output is True, accumulate text from each chunk + if incremental_output: + try: + # TODO check choice + output = getattr(chunk, "output", None) + if output: + chunk_text = getattr(output, "text", None) or getattr( + output, "content", None + ) + if chunk_text: + accumulated_text += chunk_text + except (KeyError, AttributeError): + pass + yield chunk - print("[INSTRUMENTATION] Streaming completed") + + # After generator completes, update invocation and set attributes + if last_response: + # If incremental_output is True, create a modified response with accumulated text + if incremental_output and accumulated_text: + last_response = _create_accumulated_response( + last_response, accumulated_text + ) + + _update_invocation_from_response(invocation, last_response) + handler.stop_llm(invocation) + except Exception as e: - print( - f"[INSTRUMENTATION] Streaming exception: {type(e).__name__}: {e}" - ) + error = Error(message=str(e), type=type(e)) + handler.fail_llm(invocation, error) raise -async def _wrap_async_generator(generator): - """Wrap an asynchronous generator to log each chunk.""" +async def _wrap_async_generator( + generator, handler, invocation, incremental_output=None +): + """Wrap an asynchronous generator to collect data and set attributes. + + Args: + generator: The async generator to wrap + handler: TelemetryHandler instance + invocation: LLMInvocation object + incremental_output: If True, chunks contain only incremental text (need to accumulate). + If False or None (default), chunks contain full accumulated text. + """ + last_response = None + accumulated_text = "" + try: async for chunk in generator: - print("[INSTRUMENTATION] Received streaming chunk (async)") + last_response = chunk + + # If incremental_output is True, accumulate text from each chunk + if incremental_output: + try: + output = getattr(chunk, "output", None) + if output: + chunk_text = getattr(output, "text", None) or getattr( + output, "content", None + ) + if chunk_text: + accumulated_text += chunk_text + except (KeyError, AttributeError): + pass + yield chunk - print("[INSTRUMENTATION] Streaming completed (async)") + + # After generator completes, update invocation and set attributes + if last_response: + # If incremental_output is True, create a modified response with accumulated text + if incremental_output and accumulated_text: + last_response = _create_accumulated_response( + last_response, accumulated_text + ) + + _update_invocation_from_response(invocation, last_response) + handler.stop_llm(invocation) + except Exception as e: - print( - f"[INSTRUMENTATION] Streaming exception: {type(e).__name__}: {e}" - ) + error = Error(message=str(e), type=type(e)) + handler.fail_llm(invocation, error) raise diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py new file mode 100644 index 000000000..243a3f89b --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py @@ -0,0 +1,614 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Utility functions for DashScope instrumentation.""" + +import json +from typing import Any, List, Optional + +from opentelemetry.util.genai.types import ( + FunctionToolDefinition, + InputMessage, + LLMInvocation, + OutputMessage, + Text, + ToolCall, + ToolCallResponse, + ToolDefinitions, +) + + +def _get_parameter(kwargs: dict, param_name: str, parameters: Optional[dict] = None) -> Optional[Any]: + """Get parameter from kwargs or parameters dict. + + Checks kwargs first (direct arguments), then kwargs["parameters"] if provided. + + Args: + kwargs: Method kwargs + param_name: Parameter name to extract + parameters: Optional parameters dict (if None, will extract from kwargs.get("parameters")) + + Returns: + Parameter value if found, None otherwise + """ + # Check kwargs first (direct arguments) + if param_name in kwargs: + return kwargs[param_name] + + # Check parameters dict if provided + if parameters is None: + parameters = kwargs.get("parameters", {}) + if isinstance(parameters, dict) and param_name in parameters: + return parameters[param_name] + + return None + + +def _extract_input_messages(kwargs: dict) -> List[InputMessage]: + """Extract input messages from DashScope API kwargs. + + DashScope supports both `prompt` (string) and `messages` (list) formats. + Also supports tool call responses in messages. + """ + input_messages = [] + + # Check for messages format (preferred) + if "messages" in kwargs and kwargs["messages"]: + for msg in kwargs["messages"]: + if isinstance(msg, dict): + role = msg.get("role", "user") + content = msg.get("content", "") + tool_call_id = msg.get("tool_call_id") + tool_calls = msg.get("tool_calls") + + parts = [] + + # Handle tool call response (role="tool") + if role == "tool": + # For tool role, use ToolCallResponse + parts.append( + ToolCallResponse( + response=content, + id=tool_call_id, + type="tool_call_response", + ) + ) + else: + # Add text content if present (for non-tool roles) + if content: + if isinstance(content, str): + parts.append(Text(content=content, type="text")) + elif isinstance(content, list): + # Handle multimodal content (qwen-vl) + for part in content: + if isinstance(part, dict): + if "text" in part: + parts.append(Text(content=part["text"], type="text")) + elif isinstance(part, str): + parts.append(Text(content=part, type="text")) + + # Add tool calls if present (for assistant messages with tool calls) + if tool_calls and isinstance(tool_calls, list): + for tool_call in tool_calls: + if isinstance(tool_call, dict): + tc_id = tool_call.get("id") + function = tool_call.get("function", {}) + tool_name = function.get("name") if isinstance(function, dict) else None + tool_args = function.get("arguments") if isinstance(function, dict) else None + + if tool_name: + parts.append( + ToolCall( + name=tool_name, + arguments=tool_args, + id=tc_id, + type="tool_call", + ) + ) + + if parts: + input_messages.append( + InputMessage( + role=role, + parts=parts, + ) + ) + elif content: # Fallback for text-only messages + input_messages.append( + InputMessage( + role=role, + parts=[Text(content=str(content), type="text")], + ) + ) + elif hasattr(msg, "role"): + # Handle message objects + role = getattr(msg, "role", "user") + content = getattr(msg, "content", "") + tool_call_id = getattr(msg, "tool_call_id", None) + tool_calls = getattr(msg, "tool_calls", None) + + parts = [] + + # Handle tool call response (role="tool") + if role == "tool" : + # For tool role, use ToolCallResponse + parts.append( + ToolCallResponse( + response=str(content), + id=tool_call_id, + type="tool_call_response", + ) + ) + else: + # Add text content if present (for non-tool roles) + if content: + if isinstance(content, str): + parts.append(Text(content=content, type="text")) + elif isinstance(content, list): + # TODO: Handle multimodal content + for part in content: + if isinstance(part, dict) and "text" in part: + parts.append(Text(content=part["text"], type="text")) + elif isinstance(part, str): + parts.append(Text(content=part, type="text")) + + # Add tool calls if present + if tool_calls: + for tool_call in tool_calls: + if hasattr(tool_call, "function"): + function = getattr(tool_call, "function", None) + if function: + tool_name = getattr(function, "name", None) + tool_args = getattr(function, "arguments", None) + tc_id = getattr(tool_call, "id", None) + + if tool_name: + parts.append( + ToolCall( + name=tool_name, + arguments=tool_args, + id=tc_id, + type="tool_call", + ) + ) + + if parts: + input_messages.append( + InputMessage( + role=role, + parts=parts, + ) + ) + elif content: + input_messages.append( + InputMessage( + role=role, + parts=[Text(content=str(content), type="text")], + ) + ) + + # Check for prompt format (legacy) + elif "prompt" in kwargs and kwargs["prompt"]: + prompt = kwargs["prompt"] + if isinstance(prompt, str): + input_messages.append( + InputMessage( + role="user", + parts=[Text(content=prompt, type="text")], + ) + ) + + return input_messages + + +def _extract_tool_definitions(kwargs: dict) -> ToolDefinitions: + """Extract tool definitions from DashScope API kwargs and convert to FunctionToolDefinition objects. + + DashScope supports both `tools` and `plugins` parameters for tool definitions. + - `tools`: Direct list of tool definitions (preferred) + - `plugins`: Can be a string (JSON) or a dict containing tools + + Args: + kwargs: Generation.call kwargs + + Returns: + List of FunctionToolDefinition objects, or empty list if not found + """ + tool_definitions: ToolDefinitions = [] + + # Check for tools parameter first (preferred) + tools = kwargs.get("tools") + if not tools: + # Check for plugins parameter + plugins = kwargs.get("plugins") + if plugins: + try: + # If plugins is a string, parse it as JSON + if isinstance(plugins, str): + plugins = json.loads(plugins) + + # If plugins is a dict, extract tools + if isinstance(plugins, dict): + # DashScope plugins format: {"tools": [...]} or direct list + if "tools" in plugins: + tools = plugins["tools"] + # Check if plugins itself is a list-like structure + elif isinstance(plugins, list): + tools = plugins + + # If plugins is already a list, use it + if isinstance(plugins, list): + tools = plugins + except (json.JSONDecodeError, TypeError, AttributeError): + # If parsing fails, return empty list + return tool_definitions + + # Convert tool definitions to FunctionToolDefinition objects + if tools and isinstance(tools, list): + for tool in tools: + if isinstance(tool, dict): + # Extract function definition (DashScope format: {"type": "function", "function": {...}}) + function = tool.get("function", {}) + if isinstance(function, dict): + tool_def = FunctionToolDefinition( + name=function.get("name", ""), + description=function.get("description"), + parameters=function.get("parameters"), + response=function.get("response"), + type="function", + ) + tool_definitions.append(tool_def) + # Handle case where tool itself is a function definition + elif "name" in tool: + tool_def = FunctionToolDefinition( + name=tool.get("name", ""), + description=tool.get("description"), + parameters=tool.get("parameters"), + response=tool.get("response"), + type="function", + ) + tool_definitions.append(tool_def) + elif isinstance(tool, FunctionToolDefinition): + # Already a FunctionToolDefinition, add directly + tool_definitions.append(tool) + + return tool_definitions + + +def _extract_output_messages(response: Any) -> List[OutputMessage]: + """Extract output messages from DashScope GenerationResponse. + + Supports both standard format (output.text) and qwen-vl format (output.choices). + + Args: + response: DashScope GenerationResponse object + + Returns: + List of OutputMessage objects + """ + output_messages = [] + + if not response: + return output_messages + + try: + # Use getattr with default None to safely access attributes + # DashScope response uses __getattr__ which raises KeyError for missing attributes + output = getattr(response, "output", None) + if not output: + return output_messages + + # Check for choices format (qwen-vl and some models) + choices = getattr(output, "choices", None) + if choices and isinstance(choices, list) and len(choices) > 0: + # Process each choice + for choice in choices: + if not choice: + continue + + # Extract message from choice + message = getattr(choice, "message", None) + if not message: + continue + + # Extract content and tool_calls + content = getattr(message, "content", None) + tool_calls = getattr(message, "tool_calls", None) + finish_reason = getattr(choice, "finish_reason", None) or getattr( + output, "finish_reason", "stop" + ) + + parts = [] + + # Add text content if present + if content: + if isinstance(content, str): + parts.append(Text(content=content, type="text")) + elif isinstance(content, list): + # Handle multimodal content (qwen-vl) + for part in content: + if isinstance(part, dict): + if "text" in part: + parts.append(Text(content=part["text"], type="text")) + elif isinstance(part, str): + parts.append(Text(content=part, type="text")) + + # Add tool calls if present + if tool_calls and isinstance(tool_calls, list): + for tool_call in tool_calls: + if isinstance(tool_call, dict): + tool_call_id = tool_call.get("id") + function = tool_call.get("function", {}) + tool_name = function.get("name") if isinstance(function, dict) else None + tool_args = function.get("arguments") if isinstance(function, dict) else None + + if tool_name: + parts.append( + ToolCall( + name=tool_name, + arguments=tool_args, + id=tool_call_id, + type="tool_call", + ) + ) + elif hasattr(tool_call, "function"): + # Handle tool call objects + function = getattr(tool_call, "function", None) + if function: + tool_name = getattr(function, "name", None) + tool_args = getattr(function, "arguments", None) + tool_call_id = getattr(tool_call, "id", None) + + if tool_name: + parts.append( + ToolCall( + name=tool_name, + arguments=tool_args, + id=tool_call_id, + type="tool_call", + ) + ) + + # Create output message if we have parts OR if finish_reason indicates tool_calls + # (even if content is empty, tool calls should be captured) + if parts or (finish_reason == "tool_calls" and tool_calls): + output_messages.append( + OutputMessage( + role="assistant", + parts=parts, + finish_reason=finish_reason or "stop", + ) + ) + else: + # Standard format: output.text + text = getattr(output, "text", None) or getattr(output, "content", None) + finish_reason = getattr(output, "finish_reason", "stop") + + if text: + output_messages.append( + OutputMessage( + role="assistant", + parts=[Text(content=text, type="text")], + finish_reason=finish_reason or "stop", + ) + ) + except (KeyError, AttributeError): + # If any attribute access fails, return empty list + return output_messages + + return output_messages + + +def _extract_usage(response: Any) -> tuple[Optional[int], Optional[int]]: + """Extract token usage from DashScope response. + + Args: + response: DashScope response object + + Returns: + Tuple of (input_tokens, output_tokens) + """ + if not response: + return None, None + + try: + # Use getattr with default None to safely access attributes + # DashScope response uses __getattr__ which raises KeyError for missing attributes + usage = getattr(response, "usage", None) + if not usage: + return None, None + + # Use getattr with default None for safe access + input_tokens = getattr(usage, "input_tokens", None) or getattr( + usage, "prompt_tokens", None + ) + output_tokens = getattr(usage, "output_tokens", None) or getattr( + usage, "completion_tokens", None + ) + + return input_tokens, output_tokens + except (KeyError, AttributeError): + # If any attribute access fails, return None for both tokens + return None, None + + +def _create_invocation_from_generation( + kwargs: dict, model: Optional[str] = None +) -> LLMInvocation: + """Create LLMInvocation from Generation.call kwargs. + + Args: + kwargs: Generation.call kwargs + model: Model name (if not in kwargs) + + Returns: + LLMInvocation object + """ + request_model = kwargs.get("model") or model + if not request_model: + raise ValueError("Model name is required") + + invocation = LLMInvocation(request_model=request_model) + invocation.provider = "dashscope" + invocation.input_messages = _extract_input_messages(kwargs) + + # Extract tool definitions and convert to FunctionToolDefinition objects + invocation.tool_definitions = _extract_tool_definitions(kwargs) + + # Extract parameters from kwargs or kwargs["parameters"] dict + # Parameters can be passed directly as kwargs (e.g., temperature=0.7) or + # explicitly in a parameters dict. Check kwargs first, then parameters dict. + parameters = kwargs.get("parameters", {}) + if not isinstance(parameters, dict): + parameters = {} + + # Temperature + temperature = _get_parameter(kwargs, "temperature", parameters) + if temperature is not None: + invocation.attributes["gen_ai.request.temperature"] = temperature + + # Top-p + top_p = _get_parameter(kwargs, "top_p", parameters) + if top_p is not None: + invocation.attributes["gen_ai.request.top_p"] = top_p + + # Top-k + top_k = _get_parameter(kwargs, "top_k", parameters) + if top_k is not None: + invocation.attributes["gen_ai.request.top_k"] = top_k + + # Max tokens + max_tokens = _get_parameter(kwargs, "max_tokens", parameters) + if max_tokens is not None: + invocation.attributes["gen_ai.request.max_tokens"] = max_tokens + + # Repetition penalty + repetition_penalty = _get_parameter(kwargs, "repetition_penalty", parameters) + if repetition_penalty is not None: + invocation.attributes["gen_ai.request.repetition_penalty"] = repetition_penalty + else: + # Fallback to frequency_penalty and presence_penalty if repetition_penalty not present + frequency_penalty = _get_parameter(kwargs, "frequency_penalty", parameters) + if frequency_penalty is not None: + invocation.attributes["gen_ai.request.frequency_penalty"] = frequency_penalty + + presence_penalty = _get_parameter(kwargs, "presence_penalty", parameters) + if presence_penalty is not None: + invocation.attributes["gen_ai.request.presence_penalty"] = presence_penalty + + # Stop sequences + stop_sequences = _get_parameter(kwargs, "stop", parameters) + if stop_sequences is not None: + if isinstance(stop_sequences, list): + invocation.attributes["gen_ai.request.stop_sequences"] = stop_sequences + elif isinstance(stop_sequences, str): + invocation.attributes["gen_ai.request.stop_sequences"] = [stop_sequences] + + # Seed + seed = _get_parameter(kwargs, "seed", parameters) + if seed is not None: + invocation.attributes["gen_ai.request.seed"] = seed + + return invocation + + +def _update_invocation_from_response( + invocation: LLMInvocation, response: Any +) -> None: + """Update LLMInvocation with response data. + + Args: + invocation: LLMInvocation to update + response: DashScope response object + """ + if not response: + return + + try: + # Extract output messages + invocation.output_messages = _extract_output_messages(response) + + # Extract token usage + input_tokens, output_tokens = _extract_usage(response) + invocation.input_tokens = input_tokens + invocation.output_tokens = output_tokens + + # Extract response model name (if available) + # Use try-except to safely access attributes + # DashScope response uses __getattr__ which raises KeyError for missing attributes + try: + response_model = getattr(response, "model", None) + if response_model: + invocation.response_model_name = response_model + except (KeyError, AttributeError): + pass + + # Extract request ID (if available) + try: + request_id = getattr(response, "request_id", None) + if request_id: + invocation.response_id = request_id + except (KeyError, AttributeError): + pass + except (KeyError, AttributeError): + # If any attribute access fails, silently continue with available data + pass + + +def _create_accumulated_response(original_response, accumulated_text): + """Create a response object with accumulated text for incremental output mode. + + Args: + original_response: The last chunk response object + accumulated_text: The accumulated text from all chunks + + Returns: + A response object with accumulated text, or original_response if modification fails + """ + try: + output = getattr(original_response, "output", None) + if output and hasattr(output, "text"): + # Try to set the accumulated text directly + try: + output.text = accumulated_text + return original_response + except (AttributeError, TypeError): + # If we can't modify, create a wrapper object + pass + + # Create wrapper objects with accumulated text + class AccumulatedOutput: + def __init__(self, original_output, accumulated_text): + self.text = accumulated_text + self.finish_reason = getattr(original_output, "finish_reason", "stop") + self.content = accumulated_text + + class AccumulatedResponse: + def __init__(self, original_response, accumulated_output): + self.output = accumulated_output + # Copy other attributes from original response + for attr in ["usage", "request_id", "model"]: + try: + value = getattr(original_response, attr, None) + if value is not None: + setattr(self, attr, value) + except (KeyError, AttributeError): + pass + + accumulated_output = AccumulatedOutput(output, accumulated_text) + return AccumulatedResponse(original_response, accumulated_output) + except (KeyError, AttributeError): + # If modification fails, return original response + return original_response + diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_streaming_incremental_output.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_streaming_incremental_output.yaml new file mode 100644 index 000000000..2dcb73078 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_aio_generation_call_streaming_incremental_output.yaml @@ -0,0 +1,100 @@ +interactions: +- request: + body: + input: + prompt: Count from 1 to 5 + model: qwen-turbo + parameters: + incremental_output: true + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1"},"usage":{"total_tokens":20,"output_tokens":1,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"4d60a29b-8806-4b60-a642-1a16323ba17e"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":","},"usage":{"total_tokens":21,"output_tokens":2,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"4d60a29b-8806-4b60-a642-1a16323ba17e"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":" "},"usage":{"total_tokens":22,"output_tokens":3,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"4d60a29b-8806-4b60-a642-1a16323ba17e"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"2"},"usage":{"total_tokens":23,"output_tokens":4,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"4d60a29b-8806-4b60-a642-1a16323ba17e"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":", 3,"},"usage":{"total_tokens":27,"output_tokens":8,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"4d60a29b-8806-4b60-a642-1a16323ba17e"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":" 4, "},"usage":{"total_tokens":31,"output_tokens":12,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"4d60a29b-8806-4b60-a642-1a16323ba17e"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"5."},"usage":{"total_tokens":33,"output_tokens":14,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"4d60a29b-8806-4b60-a642-1a16323ba17e"} + + id:8 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"stop","text":""},"usage":{"total_tokens":33,"output_tokens":14,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"4d60a29b-8806-4b60-a642-1a16323ba17e"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Tue, 18 Nov 2025 10:39:21 GMT + Server: + - istio-envoy + Set-Cookie: + - acw_tc=4d60a29b-8806-4b60-a642-1a16323ba17e08ba3d35df5f9a879c08a4007107554c;path=/;HttpOnly;Max-Age=1800 + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1763462361402' + req-cost-time: + - '182' + resp-start-time: + - '1763462361585' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '175' + x-request-id: + - 4d60a29b-8806-4b60-a642-1a16323ba17e + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_no_content_capture.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_no_content_capture.yaml new file mode 100644 index 000000000..577e3442f --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_no_content_capture.yaml @@ -0,0 +1,86 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": {}, + "input": { + "messages": [ + { + "role": "user", + "content": "Say this is a test" + } + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '117' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "finish_reason": "stop", + "text": "Hello! How can I assist you today?" + }, + "usage": { + "input_tokens": 17, + "output_tokens": 9, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 26 + }, + "request_id": "3b17f776-ca07-4079-b01f-b2bfa81edf56" + } + headers: + content-length: + - '239' + content-type: + - application/json + date: + - Tue, 18 Nov 2025 08:05:43 GMT + req-arrive-time: + - '1763453143340' + req-cost-time: + - '268' + resp-start-time: + - '1763453143609' + server: + - istio-envoy + set-cookie: + - acw_tc=3b17f776-ca07-4079-b01f-b2bfa81edf56433a2080c41a41abfbdf20b3f3de4d6d;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '259' + x-request-id: + - 3b17f776-ca07-4079-b01f-b2bfa81edf56 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_streaming_incremental_output.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_streaming_incremental_output.yaml new file mode 100644 index 000000000..0c7007f54 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_streaming_incremental_output.yaml @@ -0,0 +1,110 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": { + "incremental_output": true + }, + "input": { + "prompt": "Count from 1 to 5" + } + } + headers: + Accept: + - text/event-stream + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '109' + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"1"},"usage":{"total_tokens":20,"output_tokens":1,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"76895413-ba3a-4afc-9583-f7cc2d4c769d"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":","},"usage":{"total_tokens":21,"output_tokens":2,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"76895413-ba3a-4afc-9583-f7cc2d4c769d"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":" "},"usage":{"total_tokens":22,"output_tokens":3,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"76895413-ba3a-4afc-9583-f7cc2d4c769d"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"2"},"usage":{"total_tokens":23,"output_tokens":4,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"76895413-ba3a-4afc-9583-f7cc2d4c769d"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":", 3,"},"usage":{"total_tokens":27,"output_tokens":8,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"76895413-ba3a-4afc-9583-f7cc2d4c769d"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":" 4, "},"usage":{"total_tokens":31,"output_tokens":12,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"76895413-ba3a-4afc-9583-f7cc2d4c769d"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"null","text":"5."},"usage":{"total_tokens":33,"output_tokens":14,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"76895413-ba3a-4afc-9583-f7cc2d4c769d"} + + id:8 + event:result + :HTTP_STATUS/200 + data:{"output":{"finish_reason":"stop","text":""},"usage":{"total_tokens":33,"output_tokens":14,"input_tokens":19,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"76895413-ba3a-4afc-9583-f7cc2d4c769d"} + + headers: + content-type: + - text/event-stream;charset=UTF-8 + date: + - Tue, 18 Nov 2025 10:38:51 GMT + req-arrive-time: + - '1763462331328' + req-cost-time: + - '204' + resp-start-time: + - '1763462331533' + server: + - istio-envoy + set-cookie: + - acw_tc=76895413-ba3a-4afc-9583-f7cc2d4c769d1ecfe8be5224f3ce7d3d24034e84bcb2;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '198' + x-request-id: + - 76895413-ba3a-4afc-9583-f7cc2d4c769d + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_all_parameters.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_all_parameters.yaml new file mode 100644 index 000000000..a87e54aa9 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_all_parameters.yaml @@ -0,0 +1,93 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": { + "temperature": 0.7, + "top_p": 0.9, + "top_k": 50, + "max_tokens": 200, + "frequency_penalty": 0.5, + "presence_penalty": 0.5, + "stop": [ + "stop1", + "stop2" + ], + "seed": 42 + }, + "input": { + "prompt": "Test prompt" + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '232' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "finish_reason": "stop", + "text": "Sure! Please provide the prompt you'd like me to test, and let me know what specific aspects you'd like me to focus on (e.g., clarity, creativity, adherence to instructions, etc.). I'll do my best to analyze and respond accordingly." + }, + "usage": { + "input_tokens": 14, + "output_tokens": 52, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 66 + }, + "request_id": "261dbe28-018c-488b-a068-c712f1317418" + } + headers: + content-length: + - '438' + content-type: + - application/json + date: + - Tue, 18 Nov 2025 08:05:44 GMT + req-arrive-time: + - '1763453144255' + req-cost-time: + - '740' + resp-start-time: + - '1763453144996' + server: + - istio-envoy + set-cookie: + - acw_tc=261dbe28-018c-488b-a068-c712f1317418282eacdd84000de08c32b21198737dd0;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '732' + x-request-id: + - 261dbe28-018c-488b-a068-c712f1317418 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_content_capture.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_content_capture.yaml new file mode 100644 index 000000000..7d6afb8a3 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_content_capture.yaml @@ -0,0 +1,86 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": {}, + "input": { + "messages": [ + { + "role": "user", + "content": "Say this is a test" + } + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '117' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "finish_reason": "stop", + "text": "Hello! How can I assist you today?" + }, + "usage": { + "input_tokens": 17, + "output_tokens": 9, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 26 + }, + "request_id": "debfb7f5-2211-4b29-b0f2-258062dad715" + } + headers: + content-length: + - '239' + content-type: + - application/json + date: + - Tue, 18 Nov 2025 08:05:43 GMT + req-arrive-time: + - '1763453142950' + req-cost-time: + - '249' + resp-start-time: + - '1763453143200' + server: + - istio-envoy + set-cookie: + - acw_tc=debfb7f5-2211-4b29-b0f2-258062dad715901000f826af99afb84e47df680b7c4d;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '242' + x-request-id: + - debfb7f5-2211-4b29-b0f2-258062dad715 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_prompt_content_capture.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_prompt_content_capture.yaml new file mode 100644 index 000000000..32ef438a2 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_prompt_content_capture.yaml @@ -0,0 +1,81 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": {}, + "input": { + "prompt": "Hello, world!" + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '79' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.9.6; platform/macOS-15.3.2-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "finish_reason": "stop", + "text": "Hello! How can I assist you today? \ud83d\ude0a" + }, + "usage": { + "input_tokens": 16, + "output_tokens": 11, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 27 + }, + "request_id": "f202876d-4977-4937-beb6-46c46bc14a41" + } + headers: + content-length: + - '245' + content-type: + - application/json + date: + - Tue, 18 Nov 2025 08:05:43 GMT + req-arrive-time: + - '1763453143758' + req-cost-time: + - '320' + resp-start-time: + - '1763453144078' + server: + - istio-envoy + set-cookie: + - acw_tc=f202876d-4977-4937-beb6-46c46bc14a4140c925bb5fd1dfd3b782a2cd9398cb24;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '313' + x-request-id: + - f202876d-4977-4937-beb6-46c46bc14a41 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_call_response_content_capture.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_call_response_content_capture.yaml new file mode 100644 index 000000000..4ca34d435 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_call_response_content_capture.yaml @@ -0,0 +1,262 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": { + "tools": [ + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "Get the current weather in a given location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA" + } + }, + "required": [ + "location" + ] + } + } + } + ], + "result_format": "message" + }, + "input": { + "messages": [ + { + "role": "user", + "content": "What's the weather in Beijing?" + } + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '464' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "choices": [ + { + "finish_reason": "tool_calls", + "index": 0, + "message": { + "content": "", + "role": "assistant", + "tool_calls": [ + { + "function": { + "arguments": "{\"location\": \"Beijing\"}", + "name": "get_current_weather" + }, + "id": "call_9c0097983c9244429df063", + "index": 0, + "type": "function" + } + ] + } + } + ] + }, + "usage": { + "input_tokens": 177, + "output_tokens": 21, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 198 + }, + "request_id": "13a7f6ef-bdb2-452a-b226-31be1d4f5b1a" + } + headers: + content-length: + - '436' + content-type: + - application/json + date: + - Tue, 18 Nov 2025 11:35:47 GMT + req-arrive-time: + - '1763465747220' + req-cost-time: + - '411' + resp-start-time: + - '1763465747631' + server: + - istio-envoy + set-cookie: + - acw_tc=13a7f6ef-bdb2-452a-b226-31be1d4f5b1abfad552d3727aa20424cb967cf16c8d7;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '405' + x-request-id: + - 13a7f6ef-bdb2-452a-b226-31be1d4f5b1a + status: + code: 200 + message: OK +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": { + "tools": [ + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "Get the current weather in a given location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA" + } + }, + "required": [ + "location" + ] + } + } + } + ], + "result_format": "message" + }, + "input": { + "messages": [ + { + "role": "user", + "content": "What's the weather in Beijing?" + }, + { + "role": "assistant", + "content": "", + "tool_calls": [ + { + "id": "call_9c0097983c9244429df063", + "type": "function", + "function": { + "name": "get_current_weather", + "arguments": "{\"location\": \"Beijing\"}" + } + } + ] + }, + { + "role": "tool", + "content": "{\"temperature\": 20, \"condition\": \"sunny\"}", + "tool_call_id": "call_9c0097983c9244429df063" + } + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '793' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "choices": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "The current weather in Beijing is sunny with a temperature of 20 degrees.", + "role": "assistant" + } + } + ] + }, + "usage": { + "input_tokens": 225, + "output_tokens": 16, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 241 + }, + "request_id": "b450e3b6-6e33-4d56-b5f2-263e8ed8515e" + } + headers: + content-length: + - '339' + content-type: + - application/json + date: + - Tue, 18 Nov 2025 11:35:47 GMT + req-arrive-time: + - '1763465747967' + req-cost-time: + - '372' + resp-start-time: + - '1763465748339' + server: + - istio-envoy + set-cookie: + - acw_tc=b450e3b6-6e33-4d56-b5f2-263e8ed8515edfe1327d2241b3458eb0283aa914e11d;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '365' + x-request-id: + - b450e3b6-6e33-4d56-b5f2-263e8ed8515e + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_calls_content_capture.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_calls_content_capture.yaml new file mode 100644 index 000000000..1686f7787 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_calls_content_capture.yaml @@ -0,0 +1,128 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": { + "tools": [ + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "Get the current weather in a given location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA" + } + }, + "required": [ + "location" + ] + } + } + } + ], + "result_format": "message" + }, + "input": { + "messages": [ + { + "role": "user", + "content": "What's the weather in Beijing?" + } + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '464' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "choices": [ + { + "finish_reason": "tool_calls", + "index": 0, + "message": { + "content": "", + "role": "assistant", + "tool_calls": [ + { + "function": { + "arguments": "{\"location\": \"Beijing\"}", + "name": "get_current_weather" + }, + "id": "call_5d9df239235040eeb71f2a", + "index": 0, + "type": "function" + } + ] + } + } + ] + }, + "usage": { + "input_tokens": 177, + "output_tokens": 21, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 198 + }, + "request_id": "b115657b-aac4-4b43-8bfb-e374186c6183" + } + headers: + content-length: + - '436' + content-type: + - application/json + date: + - Tue, 18 Nov 2025 11:35:46 GMT + req-arrive-time: + - '1763465746157' + req-cost-time: + - '389' + resp-start-time: + - '1763465746547' + server: + - istio-envoy + set-cookie: + - acw_tc=b115657b-aac4-4b43-8bfb-e374186c6183d713cd608ed6084be0de5859a70a6776;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '381' + x-request-id: + - b115657b-aac4-4b43-8bfb-e374186c6183 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_calls_no_content_capture.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_calls_no_content_capture.yaml new file mode 100644 index 000000000..a1e075c74 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_generation_call_with_tool_calls_no_content_capture.yaml @@ -0,0 +1,128 @@ +interactions: +- request: + body: |- + { + "model": "qwen-turbo", + "parameters": { + "tools": [ + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "Get the current weather in a given location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA" + } + }, + "required": [ + "location" + ] + } + } + } + ], + "result_format": "message" + }, + "input": { + "messages": [ + { + "role": "user", + "content": "What's the weather in Beijing?" + } + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '464' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "choices": [ + { + "finish_reason": "tool_calls", + "index": 0, + "message": { + "content": "", + "role": "assistant", + "tool_calls": [ + { + "function": { + "arguments": "{\"location\": \"Beijing\"}", + "name": "get_current_weather" + }, + "id": "call_fde925828f0041d6aecf5d", + "index": 0, + "type": "function" + } + ] + } + } + ] + }, + "usage": { + "input_tokens": 177, + "output_tokens": 21, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 198 + }, + "request_id": "0cedf97d-813a-4879-87a7-12ee56422748" + } + headers: + content-length: + - '436' + content-type: + - application/json + date: + - Tue, 18 Nov 2025 11:35:46 GMT + req-arrive-time: + - '1763465746698' + req-cost-time: + - '414' + resp-start-time: + - '1763465747113' + server: + - istio-envoy + set-cookie: + - acw_tc=0cedf97d-813a-4879-87a7-12ee56422748cf61aa8e5ffc37fa0c7a26e536fe1b44;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '406' + x-request-id: + - 0cedf97d-813a-4879-87a7-12ee56422748 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_with_dimension.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_with_dimension.yaml new file mode 100644 index 000000000..a23dd2a21 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_embedding_with_dimension.yaml @@ -0,0 +1,1621 @@ +interactions: +- request: + body: |- + { + "model": "text-embedding-v1", + "parameters": { + "dimension": 512 + }, + "input": { + "texts": [ + "What is machine learning?" + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '115' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/embeddings/text-embedding/text-embedding + response: + body: + string: |- + { + "output": { + "embeddings": [ + { + "embedding": [ + 1.1934187412261963, + -2.633335590362549, + -2.5068249702453613, + -3.633335590362549, + 2.7716238498687744, + -1.1219831705093384, + 1.9419468641281128, + -4.5793280601501465, + -2.48089599609375, + 0.0372314453125, + -2.7471859455108643, + -0.9006260633468628, + -0.18060302734375, + 2.475795269012451, + -3.8375766277313232, + -2.2794156074523926, + -0.6405552625656128, + -0.9982975721359253, + -2.0245797634124756, + 0.1842128187417984, + -0.3433358371257782, + 0.5528444647789001, + 1.1940127611160278, + 2.6036202907562256, + 1.5391148328781128, + -0.1430576890707016, + -0.8287833333015442, + -2.388826608657837, + 1.9942626953125, + 0.2532784640789032, + -0.3290863037109375, + -2.0269687175750732, + 1.5087106227874756, + -0.3170166015625, + 1.0336827039718628, + -0.3218732476234436, + -0.8214634656906128, + -0.3800724446773529, + 2.4076974391937256, + -1.9413583278656006, + 1.6852155923843384, + 0.2910374104976654, + 2.5196011066436768, + -0.9134783148765564, + 0.6030665636062622, + 1.7124568223953247, + 0.3146187961101532, + 0.0570133738219738, + -0.2565700113773346, + -0.12874630093574524, + 2.128324270248413, + 3.5581753253936768, + -0.9682442545890808, + -1.6094774007797241, + 0.9844709038734436, + 1.2361276149749756, + -3.118408203125, + 0.5299748182296753, + 3.1893832683563232, + 1.7339564561843872, + -0.4676971435546875, + 1.0299072265625, + -0.2275782972574234, + -1.8679243326187134, + 1.3686610460281372, + 0.36492919921875, + -3.987758159637451, + -2.362422466278076, + -3.987583637237549, + -1.1657496690750122, + 2.0527822971343994, + 0.7410016655921936, + 1.4347326755523682, + 0.9822998046875, + -0.19693756103515625, + 0.0670732781291008, + 1.1323416233062744, + -0.8412998914718628, + 1.0006974935531616, + 0.32220569252967834, + -2.127925395965576, + 1.0313197374343872, + 1.2336033582687378, + -2.8837106227874756, + 0.8049665093421936, + 0.82281494140625, + 1.811767578125, + -0.2968924343585968, + 1.8265554904937744, + -2.198582172393799, + -2.0296645164489746, + 0.1624973863363266, + 1.3544572591781616, + 2.264583110809326, + 1.6646031141281128, + 4.8037543296813965, + 1.5792433023452759, + -0.5530831217765808, + -2.7884695529937744, + 0.1601911336183548, + -2.029660940170288, + -0.0073645454831421375, + 2.3185696601867676, + -0.02747453935444355, + 1.637939453125, + 0.5464695692062378, + -3.0401089191436768, + 1.430450439453125, + 0.5589424967765808, + -1.4839738607406616, + 2.27252197265625, + -1.9468994140625, + -2.5346505641937256, + -0.4209333062171936, + 3.7443149089813232, + 1.2143205404281616, + 0.8514388203620911, + -0.923492431640625, + -0.5230887532234192, + 3.3806850910186768, + 2.607421875, + -2.2418386936187744, + 0.7337995171546936, + 1.7778875827789307, + 1.091217041015625, + -1.8778076171875, + -1.8345390558242798, + -1.7399030923843384, + 0.7704729437828064, + 2.8196017742156982, + 1.5419224500656128, + 0.3095354437828064, + 1.9910017251968384, + 0.5853642225265503, + 1.5839277505874634, + -0.2136056125164032, + 2.3184292316436768, + -4.214111328125, + -0.9797886610031128, + 0.9782671332359314, + 0.1973680704832077, + -2.381870746612549, + 1.795503854751587, + -3.3900146484375, + 2.137241840362549, + -0.4964076578617096, + -0.1349836140871048, + 0.6176583170890808, + -2.4296765327453613, + 2.256162166595459, + -0.9877406358718872, + -0.7073451280593872, + -4.149100303649902, + -1.2352468967437744, + -0.2835955023765564, + -0.7322573065757751, + -1.9515206813812256, + 3.2264230251312256, + 3.912841796875, + 1.2454878091812134, + -1.3819078207015991, + 1.105224609375, + 4.584697246551514, + -1.2077287435531616, + -2.0765554904937744, + -3.152559518814087, + 0.3756016194820404, + -2.611201763153076, + -1.6274763345718384, + 0.5410134196281433, + 0.8379254937171936, + 1.1162174940109253, + -0.2044023722410202, + -0.8062220811843872, + -3.50006103515625, + 2.684844970703125, + -6.33837890625, + -4.2716240882873535, + -0.5978437066078186, + 2.8646414279937744, + 2.834716796875, + 1.2333766222000122, + -2.4817941188812256, + -2.116041898727417, + 2.6307504177093506, + -2.2882778644561768, + -2.69970703125, + 1.8249861001968384, + -2.692138671875, + -0.4066047668457031, + 3.12249755859375, + -0.4356863796710968, + -1.8252040147781372, + -2.0286691188812256, + 0.1699305921792984, + -0.8032152056694031, + 1.5906388759613037, + 0.309600293636322, + 1.7319772243499756, + 0.9537876844406128, + -0.4751543402671814, + -0.0905587300658226, + 1.2901785373687744, + -2.1005947589874268, + 1.5044816732406616, + -2.23388671875, + -1.6970388889312744, + -1.2761579751968384, + -1.5332859754562378, + 2.647007465362549, + -1.8652191162109375, + -0.3728289008140564, + -2.1853725910186768, + 0.5062604546546936, + 0.47210693359375, + 0.8627196550369263, + -1.3841726779937744, + 2.16802978515625, + -1.04486083984375, + 5.9896063804626465, + 2.131260395050049, + 4.970511436462402, + 1.1203787326812744, + 1.3886805772781372, + -0.5950753092765808, + 0.5181012749671936, + 1.5129438638687134, + -2.1092529296875, + -1.3703439235687256, + 0.9400585889816284, + -0.6193297505378723, + 1.0576084852218628, + -0.6723109483718872, + -3.410980224609375, + 0.007716587744653225, + 0.08978271484375, + 0.4731837809085846, + -2.292262554168701, + 0.1300702840089798, + -1.0310755968093872, + 0.6691545844078064, + 1.441713571548462, + -4.3099365234375, + 0.4585811197757721, + 0.2485177218914032, + -3.351283550262451, + 0.1053902730345726, + 1.29229736328125, + 2.080836772918701, + 1.1315830945968628, + 0.9563773274421692, + -0.5888715386390686, + -0.9143393635749817, + -1.2020155191421509, + -4.931509971618652, + 1.12939453125, + 0.0033220562618225813, + -0.1788896769285202, + -0.635498046875, + -4.3874688148498535, + -1.02398681640625, + 0.5999755859375, + 1.7728968858718872, + -0.5431889295578003, + 0.248443603515625, + -1.9606236219406128, + 0.0838056281208992, + 0.8829607367515564, + 2.0932443141937256, + 0.4504220187664032, + -2.612217426300049, + -1.1336212158203125, + -1.46185302734375, + -3.175258159637451, + 1.65802001953125, + 0.4192766547203064, + 2.6151645183563232, + -1.3134939670562744, + -0.3254132866859436, + 4.657383441925049, + -1.5838797092437744, + 0.8762555718421936, + -1.0106375217437744, + -0.9186379313468933, + -0.5425502061843872, + -1.4645559787750244, + 1.1376255750656128, + -0.2170933336019516, + -0.5379900336265564, + -3.2148916721343994, + 4.0147271156311035, + 2.8682949542999268, + 0.8756942749023438, + 1.5825539827346802, + 3.4019775390625, + -0.9410814642906189, + 6.775390625, + -0.4062107503414154, + -0.448394775390625, + -1.3747209310531616, + -1.5992692708969116, + -4.974672794342041, + 0.9998757243156433, + 0.8512549996376038, + 4.256591796875, + 2.6880581378936768, + -1.997650146484375, + -0.3623482882976532, + -1.7532435655593872, + 1.8635656833648682, + -1.0112817287445068, + -0.3056117594242096, + 0.8553990125656128, + -0.13360595703125, + -0.0801740363240242, + -0.46549659967422485, + -1.8879002332687378, + 1.6028878688812256, + -1.8681814670562744, + 0.5046735405921936, + -0.1952776163816452, + -0.7773262858390808, + 3.0601284503936768, + -0.16704000532627106, + -0.308013916015625, + -0.3589128851890564, + -0.8523210883140564, + 0.4982387125492096, + -0.9737761616706848, + 0.2457013875246048, + -1.6552037000656128, + -0.38834163546562195, + -2.102022409439087, + 1.94805908203125, + -1.7239292860031128, + 0.2482822984457016, + 0.6865549087524414, + 1.06488037109375, + -1.5893079042434692, + 2.254411220550537, + -2.1934139728546143, + 4.1905517578125, + 0.6429356336593628, + -1.2745579481124878, + -1.1687840223312378, + 1.1036289930343628, + 0.0663190558552742, + -1.0647103786468506, + -1.3712550401687622, + 2.621922016143799, + 0.9968894124031067, + 1.3043562173843384, + -3.3702218532562256, + -0.866455078125, + 3.3228237628936768, + 0.6576309204101562, + -1.3821934461593628, + 3.487199068069458, + -0.6668614149093628, + 0.0060904365964233875, + -5.3949151039123535, + -1.7265537977218628, + -0.6365007758140564, + -1.3018624782562256, + 2.0270450115203857, + -0.5887832641601562, + 1.9565298557281494, + 3.0379137992858887, + -0.2350921630859375, + 0.5897936224937439, + -4.1048760414123535, + 0.7223249077796936, + -2.072108745574951, + 2.1244418621063232, + -0.9838539958000183, + -1.5255126953125, + 0.93914794921875, + 0.7793927788734436, + -2.5659878253936768, + -1.1560145616531372, + -3.916721820831299, + 1.1339460611343384, + 2.0872890949249268, + 1.3297468423843384, + 2.3152291774749756, + 0.848388671875, + -1.7916526794433594, + 2.6583492755889893, + -2.9312744140625, + 0.6640276312828064, + 0.4601985514163971, + 0.4605778157711029, + -0.3607548177242279, + -0.1804112046957016, + 2.025416851043701, + 1.888974905014038, + 0.7976194024085999, + 0.7119925618171692, + 0.45550537109375, + 2.4492318630218506, + 0.22313253581523895, + 1.0207693576812744, + -1.0722395181655884, + -0.1584756076335907, + 1.2606070041656494, + 0.5076991319656372, + 0.1679818332195282, + -0.5238385796546936, + 2.468296527862549, + -1.41326904296875, + 0.6504952311515808, + -1.3437325954437256, + 4.2440009117126465, + -0.9742954969406128, + 0.9208287000656128, + 2.611607074737549, + 0.7371302843093872, + -0.9475882649421692, + 2.6696298122406006, + 1.3568049669265747, + -3.292872905731201, + -5.178699970245361, + 1.0345197916030884, + 0.7173200249671936, + -2.0879080295562744, + -1.647552490234375, + 0.3756975531578064, + -0.7596086859703064, + 0.8980124592781067, + 3.769749164581299, + 1.5449568033218384, + -3.45196533203125, + 2.0522634983062744, + 1.6304931640625, + 1.7596784830093384, + -0.5558122992515564, + 1.0070451498031616, + -2.3077197074890137, + -0.9387381672859192, + 1.6850106716156006, + -0.9266575574874878, + 1.2981654405593872, + -2.1019444465637207, + 3.491912841796875, + 1.3269392251968384, + -2.529331684112549, + -0.2633187472820282, + -0.8575788140296936, + -1.1915719509124756, + 4.975860595703125, + 1.2115652561187744, + -1.8567918539047241, + 0.6921038031578064, + -1.6023036241531372, + 1.1556919813156128, + -1.7865426540374756, + 0.6408953070640564, + -2.096278667449951, + -2.3782784938812256, + 2.22328519821167, + -0.3092803955078125, + -1.5355747938156128, + 0.3574480414390564, + -0.10873249918222427, + -1.1307722330093384, + 0.1937779039144516, + -1.4178597927093506, + -1.4312809705734253, + -2.090266704559326, + 0.7175641655921936, + -0.2400185763835907, + -1.0955079793930054, + 0.1119515523314476, + 2.0381381511688232, + -1.3739711046218872, + -0.630706787109375, + -0.6724330186843872, + -0.8262939453125, + 1.0138113498687744, + 0.3149615228176117, + 1.4399763345718384, + -1.9015676975250244, + 0.4419381320476532, + -0.4254421591758728, + 1.3742446899414062, + 2.829010009765625, + 1.2765415906906128, + 0.02686418779194355, + 1.1712172031402588, + 0.4464917778968811, + -1.5978829860687256, + -1.2040492296218872, + -0.3541259765625, + -2.412745952606201, + 2.8331124782562256, + -2.6009521484375, + -0.0603158138692379, + -0.9496983289718628, + -1.605712890625, + 0.43627166748046875, + 1.8390415906906128, + -0.709686279296875, + 1.7115304470062256, + -1.2025407552719116, + -0.1072474867105484, + 1.125732421875, + 3.6512973308563232, + 1.1037728786468506, + -1.09576416015625, + 2.625889301300049, + 1.9796316623687744, + -2.4574410915374756, + 3.0964279174804688, + 1.4265486001968384, + -0.0938611701130867, + -0.2416730672121048, + 1.609039306640625, + -1.4410661458969116, + 0.1818106472492218, + -1.0815963745117188, + -2.203944683074951, + 4.113002300262451, + -1.4246652126312256, + -1.0462515354156494, + -0.3206699788570404, + 1.319002389907837, + 1.3881388902664185, + 3.4891357421875, + 5.941475868225098, + 1.6458216905593872, + 0.5844334363937378, + -1.991088628768921, + -0.1697474867105484, + -2.9036104679107666, + 0.01068987138569355, + -0.6902422308921814, + 0.3337009847164154, + 1.3757063150405884, + 0.5929695963859558, + 1.0960649251937866, + 3.329860210418701, + 1.5779331922531128, + 1.0750274658203125, + -0.1139417365193367, + 4.191231727600098, + 0.01633235439658165, + -4.1435112953186035, + 0.985992431640625, + 3.3236606121063232, + 1.4992849826812744, + -0.8582066297531128, + 0.0464041568338871, + -0.2048165500164032, + 1.8107736110687256, + 0.8357521891593933, + 2.411503314971924, + 2.1007559299468994, + -3.0182058811187744, + -0.5954023003578186, + 0.6737496256828308, + -0.1013532355427742, + -0.1326904296875, + -3.259730815887451, + 5.758152484893799, + 0.49057552218437195, + -0.7415335774421692, + -0.9265027642250061, + -1.8501063585281372, + 1.1707327365875244, + -3.3354580402374268, + 1.4122227430343628, + -2.642299175262451, + 0.4798627495765686, + 1.5416957139968872, + -1.7748326063156128, + -0.8120291829109192, + 0.8731427788734436, + -4.660762310028076, + -1.2408970594406128, + 0.5704302191734314, + 1.7624053955078125, + -1.280702829360962, + 1.6293203830718994, + 0.1212986558675766, + -3.2371737957000732, + -0.2540239691734314, + -1.4751150608062744, + -2.6116421222686768, + 0.018463134765625, + 1.0476771593093872, + -0.4307512640953064, + 1.5347963571548462, + -1.7709263563156128, + -0.0014747892273589969, + -0.4685756266117096, + -1.6094273328781128, + 0.13116455078125, + -0.9825722575187683, + -0.5981968641281128, + 0.2728707492351532, + -1.4851466417312622, + 0.4167393147945404, + 0.5659092664718628, + 1.341431736946106, + -1.602264404296875, + 0.3358197808265686, + 2.2639291286468506, + -0.5502101182937622, + 0.1414533406496048, + -0.7337821125984192, + -0.5295323133468628, + -0.1802934855222702, + 3.78955078125, + -2.310389995574951, + 0.3308279812335968, + -2.1251046657562256, + 2.7004830837249756, + -0.3565848171710968, + -0.4010663628578186, + 0.9020734429359436, + 0.0846383199095726, + 0.1139395609498024, + -1.6981343030929565, + 2.1478445529937744, + 2.4258792400360107, + -0.6392198204994202, + 0.8815220594406128, + -0.23974609375, + -0.7637503743171692, + 1.6647862195968628, + -2.72021484375, + -3.363560199737549, + -1.5036447048187256, + 11.922990798950195, + -1.9940534830093384, + 1.2133615016937256, + -0.4509364664554596, + -1.7314976453781128, + -1.3848092555999756, + -2.3145828247070312, + 1.7557199001312256, + 2.5124728679656982, + -1.4515031576156616, + 2.098872661590576, + 2.7560513019561768, + -0.1605268269777298, + 0.8658534288406372, + 1.5775669813156128, + 2.0179531574249268, + -1.1532679796218872, + 2.6917572021484375, + 3.8744070529937744, + 1.7080165147781372, + -1.3093130588531494, + -1.0513392686843872, + -2.0872018337249756, + -1.4067862033843994, + -1.3409249782562256, + 0.7792391180992126, + 3.330836772918701, + 1.8161271810531616, + -1.1103689670562744, + 4.661411762237549, + -1.514129638671875, + 1.7250300645828247, + 1.3905171155929565, + 0.3382045328617096, + -1.1823670864105225, + -0.5813336968421936, + -2.4406869411468506, + -0.03826904296875, + -3.322291851043701, + 0.5750645399093628, + 0.24749374389648438, + 0.6388680338859558, + 0.5926600694656372, + 3.3460171222686768, + 2.5536715984344482, + -0.7493460774421692, + -0.2735595703125, + 1.6219308376312256, + -2.25030517578125, + 1.7120579481124878, + -1.1350271701812744, + 1.612062692642212, + 0.6128104329109192, + 3.8553292751312256, + -1.7265974283218384, + -0.0557120181620121, + -0.5445556640625, + -0.7223902940750122, + -0.45953369140625, + -0.3878871500492096, + 0.353118896484375, + 1.6406773328781128, + 0.4935128390789032, + -1.2809263467788696, + -0.2350115031003952, + -1.6566685438156128, + -0.5695975422859192, + -0.8458687663078308, + -0.4558694064617157, + -1.1508222818374634, + -0.6425694227218628, + 1.4680088758468628, + -2.5548672676086426, + 3.2126858234405518, + 2.8352181911468506, + -2.604771137237549, + -1.0158036947250366, + 2.5210299491882324, + -0.8108776807785034, + -8.896484375, + 1.530517578125, + -1.4675990343093872, + -1.3280900716781616, + -1.0273263454437256, + -1.0174168348312378, + -1.5240217447280884, + -1.6519383192062378, + 1.9431588649749756, + 0.5268946886062622, + 0.060791015625, + 0.3224051296710968, + -2.637263774871826, + 0.1749529093503952, + 2.0403964519500732, + 1.5983564853668213, + 0.2599399983882904, + 0.7330322265625, + 1.3701127767562866, + -1.3810163736343384, + -1.5376499891281128, + 0.4853253960609436, + 2.4578988552093506, + -0.3565412163734436, + -2.8030178546905518, + 0.84765625, + 2.3081576824188232, + -0.3297991156578064, + -1.0610177516937256, + -1.9636601209640503, + -1.4751760959625244, + 0.7712751030921936, + 3.70281982421875, + -2.9970571994781494, + -1.4642421007156372, + 2.8663628101348877, + -4.500095844268799, + -2.1786410808563232, + 0.1951904296875, + 0.3963274359703064, + -2.4403598308563232, + 1.05859375, + -2.4469103813171387, + -0.8403189778327942, + 0.9213126301765442, + -0.2702724039554596, + 2.297420024871826, + 0.8373369574546814, + 0.6496930718421936, + 0.4105050265789032, + 4.686276912689209, + -1.9467031955718994, + -3.4117867946624756, + 1.8794991970062256, + 3.5711495876312256, + 0.5326546430587769, + -0.266204833984375, + -1.9740644693374634, + 1.9325300455093384, + -0.7245134711265564, + -1.0605642795562744, + 2.31683349609375, + -2.2344448566436768, + 0.7663443684577942, + 0.4112570583820343, + -3.6320626735687256, + 0.4920305609703064, + -3.2435824871063232, + 2.5119454860687256, + -1.2104142904281616, + 0.3040945827960968, + 2.075465679168701, + -1.11102294921875, + 5.8176093101501465, + -4.501953125, + 2.0106968879699707, + 0.9168701171875, + -2.1564505100250244, + -1.3941682577133179, + 3.936981201171875, + 1.0334951877593994, + 0.1087450310587883, + 2.619663715362549, + 2.479461669921875, + -4.4517998695373535, + 0.6140376329421997, + 4.3243231773376465, + 0.20321109890937805, + 0.4886910617351532, + 1.0725533962249756, + 0.13841138780117035, + -0.2896205484867096, + 0.6351493000984192, + -2.6706979274749756, + -0.2441929429769516, + 2.439365863800049, + -2.2145297527313232, + -0.9605320692062378, + -1.0962437391281128, + 1.9635183811187744, + -0.5903581976890564, + -3.2536098957061768, + 1.7577253580093384, + -0.6600450873374939, + -0.6311296820640564, + -0.6047014594078064, + -1.6484287977218628, + 2.0060250759124756, + 3.9461669921875, + 2.32794189453125, + -2.5282680988311768, + 1.8945573568344116, + 0.2835453450679779, + -2.253901958465576, + 1.9136570692062378, + 3.5833346843719482, + -2.298396587371826, + -1.2814767360687256, + 0.5038800835609436, + 0.1162458136677742, + 0.7280622124671936, + 0.041717529296875, + 0.0721086785197258, + -0.7045964002609253, + 1.6515562534332275, + 0.2080364227294922, + 1.1045502424240112, + 3.499546527862549, + 0.2272077351808548, + -0.2656713128089905, + 1.6964677572250366, + 0.4083600640296936, + -1.4859095811843872, + 1.2517220973968506, + -2.3890902996063232, + 0.7312709093093872, + -1.8209577798843384, + 0.319857656955719, + 7.409816265106201, + -0.2671094536781311, + 1.5327584743499756, + -1.7328404188156128, + 3.7252449989318848, + 0.0368259958922863, + -0.21169035136699677, + 0.4586879312992096, + 2.2601492404937744, + -2.2436044216156006, + 0.9587653279304504, + 0.5246189832687378, + 1.1835153102874756, + -2.4358432292938232, + 1.2274388074874878, + 1.4860142469406128, + 3.0523681640625, + 2.8880178928375244, + -1.4942103624343872, + -0.9622802734375, + 1.9851820468902588, + -3.1096889972686768, + 2.8168857097625732, + 0.0655364990234375, + 2.652797222137451, + -2.3002841472625732, + 1.4236704111099243, + -3.9236538410186768, + -0.0332859568297863, + 2.6608364582061768, + 2.1145541667938232, + 1.2235586643218994, + -0.0882045179605484, + -2.8408334255218506, + 1.8745291233062744, + 1.9000418186187744, + 2.7818081378936768, + 1.5291748046875, + -1.7611204385757446, + -2.189174175262451, + -0.9589582085609436, + -1.1241891384124756, + 1.8611886501312256, + -1.154052734375, + -1.0527735948562622, + -2.624180316925049, + -0.6029183268547058, + -0.7690865397453308, + -1.8923165798187256, + 3.249027729034424, + 1.0764552354812622, + -2.6854159832000732, + -0.6386073231697083, + 0.2085396945476532, + 0.9693123698234558, + 1.8434361219406128, + -1.4066162109375, + -1.48773193359375, + 1.0506417751312256, + 0.1719970703125, + -0.4082379937171936, + -1.0556640625, + 0.6158970594406128, + -0.3049752414226532, + 0.7314976453781128, + -3.5477817058563232, + -2.7617602348327637, + 1.4670149087905884, + 0.4447021484375, + -1.902610182762146, + 0.223388671875, + -1.1249853372573853, + 1.5072239637374878, + -1.1072998046875, + 0.6433271169662476, + -3.1875522136688232, + 0.3396388590335846, + 0.4072134792804718, + 1.0943864583969116, + -1.2437852621078491, + 2.109348773956299, + 0.9053780436515808, + -0.1532745361328125, + 0.5022670030593872, + -1.3529402017593384, + -1.1584821939468384, + -2.6451938152313232, + 1.5977696180343628, + 2.1542184352874756, + 0.5862513780593872, + 1.7772216796875, + -1.4534651041030884, + 6.606026649475098, + 0.21600341796875, + -1.9503347873687744, + 1.7788957357406616, + -2.516725778579712, + 2.2723824977874756, + 2.3828823566436768, + 0.5202201008796692, + 0.6119471788406372, + 2.660609722137451, + -2.2399203777313232, + -4.1175537109375, + -0.60528564453125, + 1.4792306423187256, + 0.45538330078125, + -0.1676875501871109, + 1.9061115980148315, + 1.575592041015625, + 0.4328373372554779, + 0.1919991672039032, + 1.9935739040374756, + -0.9618791937828064, + -0.4520612359046936, + 3.6417062282562256, + -0.7726505994796753, + 2.964320659637451, + -1.0145481824874878, + -0.09645407646894455, + 2.3558523654937744, + -1.15057373046875, + -1.6997244358062744, + 5.077861309051514, + 1.2193342447280884, + -4.176217079162598, + 3.576747417449951, + 3.6868722438812256, + -1.077880859375, + -0.236724853515625, + 1.9953263998031616, + -2.7240426540374756, + -0.8137722015380859, + 0.3214460015296936, + -0.4152003824710846, + 2.205387592315674, + -1.6031668186187744, + -1.7613525390625, + -1.6751011610031128, + -0.2915823757648468, + 1.7537492513656616, + -1.1068551540374756, + -3.2679333686828613, + -1.1683523654937744, + -2.0974209308624268, + 0.25360107421875, + 0.6327427625656128, + -2.221065044403076, + 0.0291573666036129, + -0.2109113484621048, + 2.447474956512451, + 6.015206336975098, + 3.386622905731201, + 4.608684062957764, + 0.0679670050740242, + 0.2338474839925766, + -1.8882620334625244, + -8.150111198425293, + 0.0204620361328125, + 1.3738267421722412, + -1.1544625759124756, + 0.4168003499507904, + 0.6515949964523315, + 1.1292942762374878, + -4.483450889587402, + 0.1505170613527298, + 2.1479666233062744, + 1.1283046007156372, + 0.589079737663269, + 1.0892770290374756, + 0.6222670674324036, + -2.4373953342437744, + 1.6988002061843872, + -1.2602626085281372, + 1.2082977294921875, + -1.525634765625, + 3.829786539077759, + -2.629970073699951, + 3.885371685028076, + -2.987095355987549, + -2.34149169921875, + 1.1221891641616821, + -5.7519354820251465, + -0.4816196858882904, + 0.5717991590499878, + -3.0839321613311768, + -5.860177040100098, + -0.6404331922531128, + 0.5156598687171936, + 0.0780029296875, + 10.35906982421875, + 1.5701730251312256, + -0.0582536980509758, + 0.2236328125, + 1.931640625, + -0.0340990349650383, + 1.8818882703781128, + -2.2528774738311768, + 1.07952880859375, + 2.3342196941375732, + 0.225616455078125, + -0.44589123129844666, + 0.1133335679769516, + -0.6815577745437622, + -3.2251675128936768, + 0.9394792914390564, + 0.1392342746257782, + -2.2822890281677246, + 3.962001323699951, + -0.46197837591171265, + 1.8115670680999756, + -2.2587504386901855, + -2.16931414604187, + -2.022550344467163, + 1.1759556531906128, + -1.4052734375, + 2.3126437664031982, + -1.2828108072280884, + 0.0441850945353508, + 0.3129534125328064, + -0.0177001953125, + -3.7600936889648438, + -0.6085728406906128, + -2.8599679470062256, + -2.69000244140625, + -0.5668421983718872, + -0.7437831163406372, + 0.1207929328083992, + 0.0393872931599617, + 1.4381932020187378, + 1.0709315538406372, + -3.542850971221924, + 1.0975821018218994, + -0.0740618035197258, + -1.9108189344406128, + 1.1983642578125, + 0.7989856004714966, + 1.6282261610031128, + 2.019368886947632, + 0.14529092609882355, + -1.059114694595337, + 0.1689278781414032, + 1.4453572034835815, + 1.299560546875, + 0.8848615288734436, + -0.1204114630818367, + -0.5609130859375, + -1.1308070421218872, + -2.6471469402313232, + -1.6495100259780884, + -1.0816084146499634, + 3.2913296222686768, + -1.1719087362289429, + -0.7611498236656189, + -1.842529296875, + 1.4741036891937256, + -3.042203664779663, + -0.2465122789144516, + 2.462306499481201, + -0.6028355360031128, + -3.5039236545562744, + 1.1655970811843872, + -2.1389334201812744, + 3.656986713409424, + 0.5493687391281128, + -0.1292463093996048, + 2.0601632595062256, + 0.1530587375164032, + 0.24232809245586395, + -0.8716256022453308, + -2.3642871379852295, + 1.12384033203125, + -0.12185777723789215, + -4.484198570251465, + -0.04461779072880745, + -0.2014443576335907, + -0.7509678602218628, + -0.1820853054523468, + 4.787632465362549, + -3.9208548069000244, + -0.8847481608390808, + 0.6633061170578003, + 0.2730887234210968, + 0.9895564317703247, + -0.56671142578125, + 1.2743093967437744, + -1.3702741861343384, + 0.6104866862297058, + -0.9578857421875, + -0.004141671117395163, + 0.5953412652015686, + 1.70123291015625, + -2.749790668487549, + -0.560882568359375, + 2.8858554363250732, + -0.2888270914554596, + 0.1072038933634758, + 1.4080352783203125, + -0.7790440320968628, + 0.3952811062335968, + 0.6378609538078308, + 0.8895787000656128, + -0.10074778646230698, + 0.4141562283039093, + 0.2933175265789032, + 0.8925454020500183, + 0.1951381117105484, + -1.4686105251312256, + 0.7233363389968872, + -0.4075295627117157, + -0.1221051886677742, + 0.4696410000324249, + -0.7665056586265564, + 13.367963790893555, + -0.4526127278804779, + -3.881443500518799, + -2.7548129558563232, + -0.41308483481407166, + -1.8944876194000244, + 0.0939461812376976, + -2.7121756076812744, + 1.4558541774749756, + -1.2018519639968872, + 1.3314393758773804, + 5.986947059631348, + 2.047757863998413, + 2.8083343505859375, + 1.0055891275405884, + -0.3980364203453064, + -1.5522286891937256, + -1.6943359375, + 1.0649049282073975, + -1.5096086263656616, + -3.0205514430999756, + 2.8906924724578857, + -1.8912876844406128, + -0.5827375054359436, + -0.461944580078125, + -2.0692715644836426, + -1.9629429578781128, + 1.297943115234375, + -0.9365321397781372, + -0.5715528130531311, + -0.009953089989721775, + -1.9849679470062256, + -0.8142482042312622, + -0.918487548828125, + 1.7531040906906128, + 0.26195117831230164, + 2.1545443534851074, + -1.6571568250656128, + 2.1997592449188232, + 1.7621415853500366, + 2.473545551300049, + -1.9589974880218506, + 1.2381155490875244, + -0.4131382405757904, + -0.2451564222574234, + 0.8163800835609436, + -0.8390601873397827, + 4.615635395050049, + -0.3200465738773346, + -0.0607387013733387, + 0.5364772081375122, + 0.8879438042640686, + 2.548130512237549, + -1.63427734375, + -0.8756169080734253, + 0.8302263617515564, + -0.3636736273765564, + 6.463623046875, + 1.5562918186187744, + 1.4815499782562256, + 1.1454402208328247, + -1.6331961154937744, + -1.204892873764038, + 0.2536359429359436, + -0.0776105597615242, + -0.3990304172039032, + 0.8583853840827942, + 1.6802194118499756, + 2.595200777053833, + 0.4835205078125, + -0.9784327745437622, + -0.3042864203453064, + -0.6991490125656128, + 0.8763176798820496, + 0.4625069797039032, + 2.12343168258667, + -1.0865675210952759, + 0.7656337022781372, + 0.5002381205558777, + -1.1413748264312744, + -0.439178466796875, + -3.1210415363311768, + 0.2309439480304718, + -0.4777069091796875, + 2.4358303546905518, + -1.6940481662750244, + 0.6850798726081848, + 5.1607666015625, + -2.2297537326812744, + 0.6122698187828064, + -2.3580322265625, + -0.4100014865398407, + 2.6967685222625732, + 2.849208354949951, + 0.2623683512210846, + 0.1515720933675766, + 1.8030264377593994, + 0.3024204671382904, + -2.4949514865875244, + -0.742461085319519, + 0.02373286709189415, + -2.88519287109375, + 1.8059169054031372, + -3.6934335231781006, + 1.0424020290374756, + 0.135986328125, + 2.669712543487549, + 2.420166015625, + -1.48974609375, + 3.5104806423187256, + -4.020420551300049, + 1.9750453233718872, + 2.216417074203491, + -1.9784895181655884, + -1.7859846353530884, + -2.9841625690460205, + 0.662384033203125, + 0.3702043890953064, + 2.699462890625, + -1.4208155870437622, + -1.841275930404663, + -0.1602129191160202, + -1.5875244140625, + -0.20982034504413605, + 0.9456089735031128, + -1.2330671548843384, + -0.2874843180179596, + 2.7809360027313232, + 1.5674536228179932, + -0.7126246690750122, + -0.7820870280265808, + -1.6075865030288696, + 0.9546160101890564, + -0.6425955891609192, + 0.6084507703781128, + 1.3321359157562256, + 3.7956411838531494, + -0.3830675482749939, + 1.7229701280593872, + 0.22869873046875, + 1.9759172201156616, + 0.1586478054523468, + 2.599818706512451, + -2.7595388889312744, + -4.5491766929626465, + -1.8595155477523804, + -5.529006004333496, + -1.379364013671875, + -2.4507250785827637, + 2.0203683376312256, + 1.8219648599624634, + 1.4365931749343872, + -0.7098650336265564, + -1.950927734375, + -4.918086528778076, + -0.7828238606452942, + 1.1928361654281616, + 0.13806316256523132, + 0.2379935085773468, + 0.141357421875, + 2.590297222137451, + -1.2966657876968384, + 2.0448696613311768, + -0.4210902750492096, + -0.9813581109046936, + 3.5685348510742188, + -0.2146235853433609, + -0.4016287624835968, + -0.9071818590164185, + 0.0681174173951149, + 0.9730965495109558, + 1.4355905055999756, + -1.1852242946624756, + 1.06292724609375, + -3.3346383571624756, + -0.734619140625, + 1.6685093641281128, + 2.2988369464874268, + 1.361419677734375, + -2.8180453777313232, + 3.406101703643799, + 0.3515799343585968, + -0.5677490234375, + 1.3664137125015259, + 0.2549285888671875, + 2.8631198406219482, + -0.4593331515789032, + 0.2573416531085968, + -0.4566127359867096, + 0.3315865695476532, + 3.3454856872558594, + -3.217808246612549, + -1.7836477756500244, + 2.325840473175049, + 1.3374197483062744, + -1.0406407117843628, + 0.5006452202796936, + -1.5935581922531128, + -0.3957606852054596, + 0.1014447882771492, + 1.2917306423187256, + 0.9681025743484497, + 1.1634303331375122, + -0.4835139811038971, + 1.7758352756500244, + 3.2774722576141357, + 2.0785958766937256, + 1.5708357095718384, + -0.4820033609867096, + 0.1485246866941452, + -1.1517159938812256, + 0.3247418999671936, + 0.8624485731124878, + -1.02020263671875, + 2.6690847873687744, + -1.358701467514038, + 1.071012258529663, + 0.4656895101070404, + -5.4892144203186035, + -2.1302621364593506, + -1.4974114894866943, + -1.1552734375, + -1.925048828125, + -0.2410845011472702, + -0.4832022488117218, + 0.02059500478208065, + 1.7311488389968872, + -2.52459716796875, + -1.2413111925125122, + 2.9272067546844482, + -1.2433384656906128, + -2.948486328125, + -0.6197335124015808, + 1.5233938694000244, + 2.9555931091308594, + -0.7593645453453064, + 2.1311800479888916, + -2.77191162109375, + 1.2125593423843384, + -3.0979702472686768, + 1.3351266384124756, + 0.2152426540851593, + 2.9116733074188232, + 0.0757620707154274, + -1.6692068576812744, + -0.7286246418952942, + 0.472412109375, + 0.7524130940437317, + 4.6735968589782715, + 1.1888777017593384, + -1.2407357692718506, + 1.8169991970062256, + 6.753208637237549, + -0.7774239778518677, + 1.729280710220337, + -0.0212576724588871, + -0.85107421875, + 0.4701799750328064, + -0.6835588812828064, + -0.6068840026855469, + 0.2856576144695282, + -0.1885986328125, + 1.6770193576812744, + -2.1643764972686768, + 0.3896615207195282, + 1.4998081922531128, + 1.8190786838531494, + 0.0002590077347122133, + 1.5687953233718872, + 0.3949454128742218, + -0.7997174859046936, + 0.2268153578042984, + 1.0734797716140747, + -0.5819353461265564, + 1.3195451498031616, + 0.00980268232524395, + -0.13800048828125, + 0.9606061577796936, + -0.6348702311515808, + 1.3799002170562744, + 1.7923147678375244, + 2.046718120574951, + 1.1637300252914429, + -2.8466665744781494, + 0.24700927734375, + -1.6846662759780884, + -0.8908064961433411, + -2.401326894760132, + -0.860106348991394, + -1.3754075765609741, + -0.2192949503660202, + -2.0282418727874756, + 3.9208810329437256, + -3.260829448699951, + 0.4285926818847656, + 0.4982561469078064, + 1.8972429037094116, + 0.6202741265296936, + 5.353384971618652, + 0.6036028265953064, + 0.6764351725578308, + -0.01043701171875, + 0.6336234211921692, + 1.0939832925796509, + -2.689854145050049, + 0.6111188530921936, + 0.9509909749031067, + 0.1681780070066452, + -4.2801337242126465, + 2.0595614910125732, + -0.3785967230796814, + 0.5390101671218872, + 1.1465562582015991, + -0.9708077311515808, + 0.2675519585609436, + 0.4491184651851654, + -0.7215052843093872, + -2.174595355987549, + -1.2477155923843384, + -0.7468523383140564, + -0.2597307562828064, + -1.28076171875, + -2.8793509006500244, + -1.0522526502609253, + -1.6424124240875244, + 2.2510287761688232, + -0.5934949517250061, + 1.6262381076812744, + -1.74391770362854, + 1.2458059787750244, + 0.55804443359375, + -0.5949620008468628, + -1.7860281467437744, + -0.1238839253783226, + -1.1606597900390625, + 2.5270297527313232, + -0.5217045545578003, + 0.5452793836593628, + -0.7734854817390442, + -0.7354212999343872, + 1.5995222330093384, + 2.0993106365203857, + 1.9607980251312256, + 1.9813755750656128, + 0.8116226196289062, + 2.774204730987549, + 1.4095219373703003, + -1.3790959119796753, + -1.3811558485031128, + 2.7417166233062744, + 0.7493438720703125, + 0.0672781839966774, + 1.1699044704437256, + -0.7217668890953064, + -1.3136683702468872, + -1.8738272190093994, + 0.17877197265625, + 0.24462400376796722, + 0.9056221842765808, + 1.9134434461593628, + 1.3970271348953247, + -2.2090137004852295, + 1.0114572048187256, + 0.1649823933839798, + 1.9669712781906128, + 1.5833740234375, + -2.3901193141937256, + -1.9221147298812866, + 4.943490028381348, + -0.3347865641117096, + -0.6579328179359436, + -0.1434151828289032, + 1.3883187770843506 + ], + "text_index": 0 + } + ] + }, + "usage": { + "total_tokens": 5 + }, + "request_id": "91c2cd03-6b00-4e66-b9ee-1688d18d81a1" + } + headers: + content-length: + - '29390' + content-type: + - application/json + date: + - Tue, 18 Nov 2025 08:40:16 GMT + req-arrive-time: + - '1763455216384' + req-cost-time: + - '65' + resp-start-time: + - '1763455216450' + server: + - istio-envoy + set-cookie: + - acw_tc=91c2cd03-6b00-4e66-b9ee-1688d18d81a15ce45f79b2b83d89b7d35ade10b52185;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '58' + x-request-id: + - 91c2cd03-6b00-4e66-b9ee-1688d18d81a1 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_error_handling.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_error_handling.yaml new file mode 100644 index 000000000..707584fa1 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_text_rerank_error_handling.yaml @@ -0,0 +1,70 @@ +interactions: +- request: + body: |- + { + "model": "invalid-model-name", + "parameters": {}, + "input": { + "query": "test query", + "documents": [ + "test document" + ] + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '115' + Content-Type: + - application/json + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.1; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/rerank/text-rerank/text-rerank + response: + body: + string: |- + { + "code": "InvalidParameter", + "message": "Model not exist.", + "request_id": "d7859a78-9d8f-44f2-9cab-0222b87b74de" + } + headers: + content-length: + - '108' + content-type: + - application/json + date: + - Tue, 18 Nov 2025 06:18:34 GMT + req-arrive-time: + - '1763446714726' + req-cost-time: + - '6' + resp-start-time: + - '1763446714733' + server: + - istio-envoy + set-cookie: + - acw_tc=d7859a78-9d8f-44f2-9cab-0222b87b74de8151298923ee575bfa96bb9d5cc261b9;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '1' + x-request-id: + - d7859a78-9d8f-44f2-9cab-0222b87b74de + status: + code: 400 + message: Bad Request +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py index 9277ec6dd..7f55937e9 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py @@ -7,11 +7,18 @@ import yaml from loongsuite.instrumentation.dashscope import DashScopeInstrumentor +from opentelemetry.instrumentation._semconv import ( + OTEL_SEMCONV_STABILITY_OPT_IN, + _OpenTelemetrySemanticConventionStability, +) from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleSpanProcessor from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( InMemorySpanExporter, ) +from opentelemetry.util.genai.environment_variables import ( + OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT, +) @pytest.fixture(scope="function", name="span_exporter") @@ -50,6 +57,56 @@ def instrument(tracer_provider): instrumentor.uninstrument() +@pytest.fixture(scope="function") +def instrument_no_content(tracer_provider): + """Instrument DashScope SDK with message content capture disabled.""" + # Reset global state to allow environment variable changes to take effect + _OpenTelemetrySemanticConventionStability._initialized = False + + os.environ.update( + { + OTEL_SEMCONV_STABILITY_OPT_IN: "gen_ai_latest_experimental", + OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: "NO_CONTENT", + } + ) + + instrumentor = DashScopeInstrumentor() + instrumentor.instrument(tracer_provider=tracer_provider) + + yield instrumentor + + os.environ.pop(OTEL_SEMCONV_STABILITY_OPT_IN, None) + os.environ.pop(OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT, None) + instrumentor.uninstrument() + # Reset global state after test + _OpenTelemetrySemanticConventionStability._initialized = False + + +@pytest.fixture(scope="function") +def instrument_with_content(tracer_provider): + """Instrument DashScope SDK with message content capture enabled.""" + # Reset global state to allow environment variable changes to take effect + _OpenTelemetrySemanticConventionStability._initialized = False + + os.environ.update( + { + OTEL_SEMCONV_STABILITY_OPT_IN: "gen_ai_latest_experimental", + OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: "SPAN_ONLY", + } + ) + + instrumentor = DashScopeInstrumentor() + instrumentor.instrument(tracer_provider=tracer_provider) + + yield instrumentor + + os.environ.pop(OTEL_SEMCONV_STABILITY_OPT_IN, None) + os.environ.pop(OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT, None) + instrumentor.uninstrument() + # Reset global state after test + _OpenTelemetrySemanticConventionStability._initialized = False + + @pytest.fixture(scope="module") def vcr_config(): """Configure VCR for recording/replaying HTTP interactions.""" diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt index e096614d4..19cf6ccf5 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt @@ -44,4 +44,5 @@ wrapt==1.16.0 -e opentelemetry-instrumentation -e instrumentation-loongsuite/loongsuite-instrumentation-dashscope +-e util/opentelemetry-util-genai diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt index 13b72244f..a61f1f273 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt @@ -28,4 +28,5 @@ opentelemetry-sdk==1.37 opentelemetry-semantic-conventions==0.58b0 -e instrumentation-loongsuite/loongsuite-instrumentation-dashscope +-e util/opentelemetry-util-genai diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py index 9819d80db..9d9a48ae6 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py @@ -1,10 +1,126 @@ """Tests for TextEmbedding instrumentation.""" +from typing import Optional + import pytest +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) +from opentelemetry.semconv._incubating.attributes import ( + server_attributes as ServerAttributes, +) + + +def _assert_embedding_span_attributes( + span, + request_model: str, + response=None, + input_tokens: Optional[int] = None, + dimension_count: Optional[int] = None, + server_address: Optional[str] = None, + server_port: Optional[int] = None, +): + """Assert embedding span attributes according to GenAI semantic conventions. + + Args: + span: The span to assert + request_model: Expected model name + response: Optional response object to extract attributes from + input_tokens: Expected input token count (if available) + dimension_count: Expected embedding dimension count (if available) + server_address: Expected server address (if available) + server_port: Expected server port (if available) + """ + # Span name format is "{operation_name} {model}" per semantic conventions + # Operation name is "embeddings" (plural, not "embedding") + assert span.name == f"embeddings {request_model}" + + # Required attributes + assert ( + GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "embeddings" + ), f"Expected 'embeddings', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + + assert ( + GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" + assert span.attributes[GenAIAttributes.GEN_AI_PROVIDER_NAME] == "dashscope" + + # Conditionally required attributes + assert ( + GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == request_model + ) + + # Recommended attributes - check if available + if input_tokens is not None: + assert ( + GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS] + == input_tokens + ) + elif response: + # Try to extract from response if not provided + # DashScope embedding uses total_tokens instead of input_tokens + try: + usage = getattr(response, "usage", None) + if isinstance(usage, dict): + total_tokens = usage.get("total_tokens") + if total_tokens is not None: + assert ( + GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS + in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS}" + assert ( + span.attributes[ + GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS + ] + == total_tokens + ) + except (KeyError, AttributeError): + pass + + # Optional attributes - check if available + # Dimension count should only be set if it was specified in the request + if dimension_count is not None: + # If dimension_count was explicitly provided in the request, it must be set in span + assert ( + "gen_ai.embeddings.dimension.count" in span.attributes + ), "Missing gen_ai.embeddings.dimension.count" + assert ( + span.attributes["gen_ai.embeddings.dimension.count"] + == dimension_count + ) + else: + # If dimension_count was not provided in the request, it should not be set in span + assert ( + "gen_ai.embeddings.dimension.count" not in span.attributes + ), "gen_ai.embeddings.dimension.count should not be set when not specified in request" + + if server_address is not None: + assert ( + ServerAttributes.SERVER_ADDRESS in span.attributes + ), f"Missing {ServerAttributes.SERVER_ADDRESS}" + assert ( + span.attributes[ServerAttributes.SERVER_ADDRESS] == server_address + ) + + if server_port is not None: + assert ( + ServerAttributes.SERVER_PORT in span.attributes + ), f"Missing {ServerAttributes.SERVER_PORT}" + assert span.attributes[ServerAttributes.SERVER_PORT] == server_port + @pytest.mark.vcr() -def test_text_embedding_basic(instrument): +def test_text_embedding_basic(instrument, span_exporter): """Test basic text embedding call.""" from dashscope import TextEmbedding @@ -13,11 +129,36 @@ def test_text_embedding_basic(instrument): ) assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + + # Extract input tokens from response if available + # DashScope embedding uses total_tokens instead of input_tokens + input_tokens = None + try: + usage = getattr(response, "usage", None) + if usage: + input_tokens = getattr(usage, "total_tokens", None) + except (KeyError, AttributeError): + pass + + # Assert all span attributes + _assert_embedding_span_attributes( + span, + request_model="text-embedding-v1", + response=response, + input_tokens=input_tokens, + ) + print("✓ TextEmbedding.call completed successfully") @pytest.mark.vcr() -def test_text_embedding_batch(instrument): +def test_text_embedding_batch(instrument, span_exporter): """Test text embedding with batch input.""" from dashscope import TextEmbedding @@ -26,11 +167,36 @@ def test_text_embedding_batch(instrument): ) assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + + # Extract input tokens from response if available + # DashScope embedding uses total_tokens instead of input_tokens + input_tokens = None + try: + usage = getattr(response, "usage", None) + if usage: + input_tokens = getattr(usage, "total_tokens", None) + except (KeyError, AttributeError): + pass + + # Assert all span attributes + _assert_embedding_span_attributes( + span, + request_model="text-embedding-v1", + response=response, + input_tokens=input_tokens, + ) + print("✓ TextEmbedding.call (batch) completed successfully") @pytest.mark.vcr() -def test_text_embedding_with_text_type(instrument): +def test_text_embedding_with_text_type(instrument, span_exporter): """Test text embedding with text_type parameter.""" from dashscope import TextEmbedding @@ -41,4 +207,70 @@ def test_text_embedding_with_text_type(instrument): ) assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + + # Extract input tokens from response if available + # DashScope embedding uses total_tokens instead of input_tokens + input_tokens = None + try: + usage = getattr(response, "usage", None) + if usage: + input_tokens = getattr(usage, "total_tokens", None) + except (KeyError, AttributeError): + pass + + # Assert all span attributes + _assert_embedding_span_attributes( + span, + request_model="text-embedding-v1", + response=response, + input_tokens=input_tokens, + ) + print("✓ TextEmbedding.call (with text_type) completed successfully") + + +@pytest.mark.vcr() +def test_text_embedding_with_dimension(instrument, span_exporter): + """Test text embedding with dimension parameter.""" + from dashscope import TextEmbedding + + response = TextEmbedding.call( + model="text-embedding-v1", + input="What is machine learning?", + dimension=512, + ) + + assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + + # Extract input tokens from response if available + # DashScope embedding uses total_tokens instead of input_tokens + input_tokens = None + try: + usage = getattr(response, "usage", None) + if usage: + input_tokens = getattr(usage, "total_tokens", None) + except (KeyError, AttributeError): + pass + + # Assert all span attributes including dimension_count + _assert_embedding_span_attributes( + span, + request_model="text-embedding-v1", + response=response, + input_tokens=input_tokens, + dimension_count=512, # Should be captured from request + ) + + print("✓ TextEmbedding.call (with dimension) completed successfully") diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py index 8103964af..b730711f7 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py @@ -2,20 +2,248 @@ import pytest +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) + + +def _safe_getattr(obj, attr, default=None): + """Safely get attribute from DashScope response objects that may raise KeyError.""" + try: + return getattr(obj, attr, default) + except KeyError: + return default + + +def _assert_generation_span_attributes( + span, + request_model: str, + response_id: str = None, + response_model: str = None, + input_tokens: int = None, + output_tokens: int = None, + finish_reasons: list = None, + expect_input_messages: bool = False, + expect_output_messages: bool = False, + temperature: float = None, + max_tokens: int = None, + top_p: float = None, + top_k: float = None, + frequency_penalty: float = None, + presence_penalty: float = None, + stop_sequences: list = None, + seed: int = None, + choice_count: int = None, + output_type: str = None, +): + """Assert common generation span attributes.""" + # Span name format is "{operation_name} {model}" per semantic conventions + # Operation name is "chat" (not "gen_ai.chat") + assert span.name == f"chat {request_model}" + assert ( + GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "chat" + ), f"Expected 'chat', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + + assert ( + GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" + assert span.attributes[GenAIAttributes.GEN_AI_PROVIDER_NAME] == "dashscope" + + assert ( + GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == request_model + ) + + if response_model is not None: + assert ( + GenAIAttributes.GEN_AI_RESPONSE_MODEL in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_RESPONSE_MODEL}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_RESPONSE_MODEL] + == response_model + ) + # If response_model is None, don't assert it exists (it may not be available) + + if response_id is not None: + assert ( + GenAIAttributes.GEN_AI_RESPONSE_ID in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_RESPONSE_ID}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_RESPONSE_ID] == response_id + ) + # If response_id is None, don't assert it exists (it may not be available) + + if input_tokens is not None: + assert ( + GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS] + == input_tokens + ) + + if output_tokens is not None: + assert ( + GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS] + == output_tokens + ) + + # Assert finish reasons are present (if finish_reasons is provided) + if finish_reasons is not None: + assert ( + GenAIAttributes.GEN_AI_RESPONSE_FINISH_REASONS in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_RESPONSE_FINISH_REASONS}" + # Convert span attribute to list for comparison (it may be a tuple) + span_finish_reasons = span.attributes[ + GenAIAttributes.GEN_AI_RESPONSE_FINISH_REASONS + ] + if isinstance(span_finish_reasons, tuple): + span_finish_reasons = list(span_finish_reasons) + assert span_finish_reasons == finish_reasons + + # Assert input/output messages based on expectation + if expect_input_messages: + assert ( + GenAIAttributes.GEN_AI_INPUT_MESSAGES in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_INPUT_MESSAGES}" + else: + assert ( + GenAIAttributes.GEN_AI_INPUT_MESSAGES not in span.attributes + ), f"{GenAIAttributes.GEN_AI_INPUT_MESSAGES} should not be present" + + if expect_output_messages: + assert ( + GenAIAttributes.GEN_AI_OUTPUT_MESSAGES in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_OUTPUT_MESSAGES}" + else: + assert ( + GenAIAttributes.GEN_AI_OUTPUT_MESSAGES not in span.attributes + ), f"{GenAIAttributes.GEN_AI_OUTPUT_MESSAGES} should not be present" + + # Assert optional request parameters + if temperature is not None: + assert ( + "gen_ai.request.temperature" in span.attributes + ), "Missing gen_ai.request.temperature" + assert span.attributes["gen_ai.request.temperature"] == temperature + + if max_tokens is not None: + assert ( + "gen_ai.request.max_tokens" in span.attributes + ), "Missing gen_ai.request.max_tokens" + assert span.attributes["gen_ai.request.max_tokens"] == max_tokens + + if top_p is not None: + assert ( + "gen_ai.request.top_p" in span.attributes + ), "Missing gen_ai.request.top_p" + assert span.attributes["gen_ai.request.top_p"] == top_p + + if top_k is not None: + assert ( + "gen_ai.request.top_k" in span.attributes + ), "Missing gen_ai.request.top_k" + assert span.attributes["gen_ai.request.top_k"] == top_k + + if frequency_penalty is not None: + assert ( + "gen_ai.request.frequency_penalty" in span.attributes + ), "Missing gen_ai.request.frequency_penalty" + assert ( + span.attributes["gen_ai.request.frequency_penalty"] + == frequency_penalty + ) + + if presence_penalty is not None: + assert ( + "gen_ai.request.presence_penalty" in span.attributes + ), "Missing gen_ai.request.presence_penalty" + assert ( + span.attributes["gen_ai.request.presence_penalty"] + == presence_penalty + ) + + if stop_sequences is not None: + assert ( + "gen_ai.request.stop_sequences" in span.attributes + ), "Missing gen_ai.request.stop_sequences" + # Convert span attribute to list for comparison (it may be a tuple) + span_stop_sequences = span.attributes["gen_ai.request.stop_sequences"] + if isinstance(span_stop_sequences, tuple): + span_stop_sequences = list(span_stop_sequences) + assert span_stop_sequences == stop_sequences + + if seed is not None: + assert ( + "gen_ai.request.seed" in span.attributes + ), "Missing gen_ai.request.seed" + assert span.attributes["gen_ai.request.seed"] == seed + + if choice_count is not None and choice_count != 1: + assert ( + "gen_ai.request.choice.count" in span.attributes + ), "Missing gen_ai.request.choice.count" + assert span.attributes["gen_ai.request.choice.count"] == choice_count + + if output_type is not None: + assert ( + "gen_ai.output.type" in span.attributes + ), "Missing gen_ai.output.type" + assert span.attributes["gen_ai.output.type"] == output_type + @pytest.mark.vcr() -def test_generation_call_basic(instrument): +def test_generation_call_basic(instrument, span_exporter): """Test basic synchronous generation call.""" from dashscope import Generation response = Generation.call(model="qwen-turbo", prompt="Hello!") assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + # Note: request_id exists as a direct attribute, model may not exist + output = _safe_getattr(response, "output", None) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + usage = _safe_getattr(response, "usage", None) + request_id = _safe_getattr(response, "request_id", None) + response_model = _safe_getattr(response, "model", None) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + response_id=request_id, # May be None if not available + response_model=response_model, # May be None if not available + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + expect_input_messages=False, # Default: no content capture + expect_output_messages=False, # Default: no content capture + ) + print("✓ Generation.call (basic) completed successfully") @pytest.mark.vcr() -def test_generation_call_with_messages(instrument): +def test_generation_call_with_messages(instrument, span_exporter): """Test generation call with messages parameter.""" from dashscope import Generation @@ -24,12 +252,40 @@ def test_generation_call_with_messages(instrument): ) assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + output = _safe_getattr(response, "output", None) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + usage = _safe_getattr(response, "usage", None) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + response_id=_safe_getattr(response, "request_id", None), + response_model=_safe_getattr(response, "model", None), + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + expect_input_messages=False, + expect_output_messages=False, + ) + print("✓ Generation.call (with messages) completed successfully") @pytest.mark.vcr() -def test_generation_call_streaming(instrument): - """Test synchronous generation with streaming.""" +def test_generation_call_streaming(instrument, span_exporter): + """Test synchronous generation with streaming (default: full output mode).""" from dashscope import Generation responses = Generation.call( @@ -37,16 +293,97 @@ def test_generation_call_streaming(instrument): ) chunk_count = 0 + last_response = None for response in responses: assert response is not None chunk_count += 1 + last_response = response assert chunk_count > 0 - print(f"✓ Generation.call (streaming) received {chunk_count} chunks") + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + usage = ( + _safe_getattr(last_response, "usage", None) if last_response else None + ) + output = ( + _safe_getattr(last_response, "output", None) if last_response else None + ) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + ) + + +@pytest.mark.vcr() +def test_generation_call_streaming_incremental_output( + instrument, span_exporter +): + """Test synchronous generation with streaming in incremental output mode.""" + from dashscope import Generation + + responses = Generation.call( + model="qwen-turbo", + prompt="Count from 1 to 5", + stream=True, + incremental_output=True, + ) + + chunk_count = 0 + last_response = None + for response in responses: + assert response is not None + chunk_count += 1 + last_response = response + + assert chunk_count > 0 + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + usage = ( + _safe_getattr(last_response, "usage", None) if last_response else None + ) + output = ( + _safe_getattr(last_response, "output", None) if last_response else None + ) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + ) @pytest.mark.vcr() -def test_generation_call_with_parameters(instrument): +def test_generation_call_with_parameters(instrument, span_exporter): """Test generation call with various parameters.""" from dashscope import Generation @@ -59,25 +396,84 @@ def test_generation_call_with_parameters(instrument): ) assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + output = _safe_getattr(response, "output", None) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + usage = _safe_getattr(response, "usage", None) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + response_id=_safe_getattr(response, "request_id", None), + response_model=_safe_getattr(response, "model", None), + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + temperature=0.8, + max_tokens=100, + top_p=0.9, + expect_input_messages=False, + expect_output_messages=False, + ) + print("✓ Generation.call (with parameters) completed successfully") @pytest.mark.asyncio @pytest.mark.vcr() -async def test_aio_generation_call_basic(instrument): +async def test_aio_generation_call_basic(instrument, span_exporter): """Test basic asynchronous generation call.""" from dashscope import AioGeneration response = await AioGeneration.call(model="qwen-turbo", prompt="Hello!") assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + output = _safe_getattr(response, "output", None) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + usage = _safe_getattr(response, "usage", None) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + response_id=_safe_getattr(response, "request_id", None), + response_model=_safe_getattr(response, "model", None), + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + expect_input_messages=False, + expect_output_messages=False, + ) + print("✓ AioGeneration.call (basic) completed successfully") @pytest.mark.asyncio @pytest.mark.vcr() -async def test_aio_generation_call_streaming(instrument): - """Test asynchronous generation with streaming.""" +async def test_aio_generation_call_streaming(instrument, span_exporter): + """Test asynchronous generation with streaming (default: full output mode).""" from dashscope import AioGeneration responses = await AioGeneration.call( @@ -85,9 +481,721 @@ async def test_aio_generation_call_streaming(instrument): ) chunk_count = 0 + last_response = None + async for response in responses: + assert response is not None + chunk_count += 1 + last_response = response + + assert chunk_count > 0 + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + usage = ( + _safe_getattr(last_response, "usage", None) if last_response else None + ) + output = ( + _safe_getattr(last_response, "output", None) if last_response else None + ) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + ) + + +@pytest.mark.asyncio +@pytest.mark.vcr() +async def test_aio_generation_call_streaming_incremental_output( + instrument, span_exporter +): + """Test asynchronous generation with streaming in incremental output mode.""" + from dashscope import AioGeneration + + responses = await AioGeneration.call( + model="qwen-turbo", + prompt="Count from 1 to 5", + stream=True, + incremental_output=True, + ) + + chunk_count = 0 + last_response = None async for response in responses: assert response is not None chunk_count += 1 + last_response = response assert chunk_count > 0 - print(f"✓ AioGeneration.call (streaming) received {chunk_count} chunks") + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + usage = ( + _safe_getattr(last_response, "usage", None) if last_response else None + ) + output = ( + _safe_getattr(last_response, "output", None) if last_response else None + ) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + ) + + +@pytest.mark.vcr() +def test_generation_call_with_content_capture( + instrument_with_content, span_exporter +): + """Test generation call with message content capture enabled.""" + from dashscope import Generation + + messages = [{"role": "user", "content": "Say this is a test"}] + response = Generation.call(model="qwen-turbo", messages=messages) + + assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + output = _safe_getattr(response, "output", None) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + usage = _safe_getattr(response, "usage", None) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + response_id=_safe_getattr(response, "request_id", None), + response_model=_safe_getattr(response, "model", None), + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + expect_input_messages=True, # Content capture enabled + expect_output_messages=True, # Content capture enabled + ) + + print("✓ Generation.call (with content capture) completed successfully") + + +@pytest.mark.vcr() +def test_generation_call_no_content_capture( + instrument_no_content, span_exporter +): + """Test generation call with message content capture disabled.""" + from dashscope import Generation + + messages = [{"role": "user", "content": "Say this is a test"}] + response = Generation.call(model="qwen-turbo", messages=messages) + + assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + output = _safe_getattr(response, "output", None) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + usage = _safe_getattr(response, "usage", None) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + response_id=_safe_getattr(response, "request_id", None), + response_model=_safe_getattr(response, "model", None), + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + expect_input_messages=False, # Content capture disabled + expect_output_messages=False, # Content capture disabled + ) + + print("✓ Generation.call (no content capture) completed successfully") + + +@pytest.mark.vcr() +def test_generation_call_with_prompt_content_capture( + instrument_with_content, span_exporter +): + """Test generation call with prompt (string) and content capture enabled.""" + from dashscope import Generation + + response = Generation.call(model="qwen-turbo", prompt="Hello, world!") + + assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + output = _safe_getattr(response, "output", None) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + usage = _safe_getattr(response, "usage", None) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + response_id=_safe_getattr(response, "request_id", None), + response_model=_safe_getattr(response, "model", None), + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + expect_input_messages=True, # Content capture enabled, prompt should be captured + expect_output_messages=True, # Content capture enabled + ) + + print( + "✓ Generation.call (prompt with content capture) completed successfully" + ) + + +@pytest.mark.vcr() +def test_generation_call_with_all_parameters(instrument, span_exporter): + """Test generation call with all optional parameters.""" + from dashscope import Generation + + response = Generation.call( + model="qwen-turbo", + prompt="Test prompt", + temperature=0.7, + top_p=0.9, + top_k=50, + max_tokens=200, + frequency_penalty=0.5, + presence_penalty=0.5, + stop=["stop1", "stop2"], + seed=42, + ) + + assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + output = _safe_getattr(response, "output", None) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + usage = _safe_getattr(response, "usage", None) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + response_id=_safe_getattr(response, "request_id", None), + response_model=_safe_getattr(response, "model", None), + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + temperature=0.7, + top_p=0.9, + top_k=50, + max_tokens=200, + frequency_penalty=0.5, + presence_penalty=0.5, + stop_sequences=["stop1", "stop2"], + seed=42, + expect_input_messages=False, + expect_output_messages=False, + ) + + print("✓ Generation.call (with all parameters) completed successfully") + + +@pytest.mark.vcr() +def test_generation_call_with_tool_calls_content_capture( + instrument_with_content, span_exporter +): + """Test generation call with tool calls and content capture enabled.""" + from dashscope import Generation + + tools = [ + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "Get the current weather in a given location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA", + } + }, + "required": ["location"], + }, + }, + } + ] + + messages = [{"role": "user", "content": "What's the weather in Beijing?"}] + response = Generation.call( + model="qwen-turbo", + messages=messages, + tools=tools, + result_format="message", + ) + + assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + output = _safe_getattr(response, "output", None) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + usage = _safe_getattr(response, "usage", None) + + # Assert tool definitions are present + assert ( + "gen_ai.tool.definitions" in span.attributes + ), "Missing gen_ai.tool.definitions" + tool_definitions_str = span.attributes["gen_ai.tool.definitions"] + assert isinstance( + tool_definitions_str, str + ), "Tool definitions should be a JSON string" + # Parse JSON to verify content + import json + + tool_definitions = json.loads(tool_definitions_str) + assert isinstance( + tool_definitions, list + ), "Tool definitions should be a list after parsing" + assert len(tool_definitions) > 0, "Tool definitions should not be empty" + + # Verify full tool definition is recorded (content capture enabled) + tool_def = tool_definitions[0] + assert "name" in tool_def, "Tool definition should have 'name'" + assert "type" in tool_def, "Tool definition should have 'type'" + assert tool_def["name"] == "get_current_weather", "Tool name should match" + assert tool_def["type"] == "function", "Tool type should be 'function'" + # With content capture enabled, should have full definition + assert ( + "description" in tool_def + ), "Tool definition should have 'description' when content capture is enabled" + assert ( + "parameters" in tool_def + ), "Tool definition should have 'parameters' when content capture is enabled" + + # Assert input/output messages with tool calls (content capture enabled) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + response_id=_safe_getattr(response, "request_id", None), + response_model=_safe_getattr(response, "model", None), + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + expect_input_messages=True, # Content capture enabled + expect_output_messages=True, # Content capture enabled + ) + + # Verify tool calls in output messages if present + if GenAIAttributes.GEN_AI_OUTPUT_MESSAGES in span.attributes: + output_messages = span.attributes[ + GenAIAttributes.GEN_AI_OUTPUT_MESSAGES + ] + if output_messages: + # Check if any message contains tool calls + # Output messages are stored as JSON strings, parse them + import json + + if isinstance(output_messages, str): + output_messages = json.loads(output_messages) + + # Check if any message has tool calls + has_tool_calls = False + for msg in output_messages: + if isinstance(msg, dict): + parts = msg.get("parts", []) + for part in parts: + if ( + isinstance(part, dict) + and part.get("type") == "tool_call" + ): + has_tool_calls = True + break + if has_tool_calls: + break + + # If finish_reason is "tool_calls", we should have tool calls + if finish_reason == "tool_calls": + assert has_tool_calls, "Expected tool calls in output messages when finish_reason is tool_calls" + + print( + "✓ Generation.call (with tool calls, content capture) completed successfully" + ) + + +@pytest.mark.vcr() +def test_generation_call_with_tool_calls_no_content_capture( + instrument_no_content, span_exporter +): + """Test generation call with tool calls and content capture disabled.""" + from dashscope import Generation + + tools = [ + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "Get the current weather in a given location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA", + } + }, + "required": ["location"], + }, + }, + } + ] + + messages = [{"role": "user", "content": "What's the weather in Beijing?"}] + response = Generation.call( + model="qwen-turbo", + messages=messages, + tools=tools, + result_format="message", + ) + + assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + # Use safe getattr to access DashScope response attributes (may raise KeyError) + output = _safe_getattr(response, "output", None) + finish_reason = ( + _safe_getattr(output, "finish_reason", None) if output else None + ) + usage = _safe_getattr(response, "usage", None) + + # Assert tool definitions are present (should be present regardless of content capture) + assert ( + "gen_ai.tool.definitions" in span.attributes + ), "Missing gen_ai.tool.definitions" + tool_definitions_str = span.attributes["gen_ai.tool.definitions"] + assert isinstance( + tool_definitions_str, str + ), "Tool definitions should be a JSON string" + # Parse JSON to verify content + import json + + tool_definitions = json.loads(tool_definitions_str) + assert isinstance( + tool_definitions, list + ), "Tool definitions should be a list after parsing" + assert len(tool_definitions) > 0, "Tool definitions should not be empty" + + # Verify only type and name are recorded (content capture disabled) + tool_def = tool_definitions[0] + assert "name" in tool_def, "Tool definition should have 'name'" + assert "type" in tool_def, "Tool definition should have 'type'" + assert tool_def["name"] == "get_current_weather", "Tool name should match" + assert tool_def["type"] == "function", "Tool type should be 'function'" + # With content capture disabled, should only have name and type + assert ( + "description" not in tool_def + ), "Tool definition should NOT have 'description' when content capture is disabled" + assert ( + "parameters" not in tool_def + ), "Tool definition should NOT have 'parameters' when content capture is disabled" + + # Assert input/output messages are NOT present (content capture disabled) + _assert_generation_span_attributes( + span, + request_model="qwen-turbo", + response_id=_safe_getattr(response, "request_id", None), + response_model=_safe_getattr(response, "model", None), + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, + finish_reasons=[finish_reason] if finish_reason else None, + expect_input_messages=False, # Content capture disabled + expect_output_messages=False, # Content capture disabled + ) + + print( + "✓ Generation.call (with tool calls, no content capture) completed successfully" + ) + + +@pytest.mark.vcr() +def test_generation_call_with_tool_call_response_content_capture( + instrument_with_content, span_exporter +): + """Test generation call with tool call response in messages and content capture enabled.""" + from dashscope import Generation + + tools = [ + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "Get the current weather in a given location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA", + } + }, + "required": ["location"], + }, + }, + } + ] + + # First call: get tool call + messages = [{"role": "user", "content": "What's the weather in Beijing?"}] + response1 = Generation.call( + model="qwen-turbo", + messages=messages, + tools=tools, + result_format="message", + ) + + assert response1 is not None + + # Extract tool call from response (if present) + output1 = _safe_getattr(response1, "output", None) + tool_call_id = None + tool_call_name = None + + if output1: + choices = _safe_getattr(output1, "choices", None) + if choices and isinstance(choices, list) and len(choices) > 0: + choice = choices[0] + message = _safe_getattr(choice, "message", None) + if message: + tool_calls = _safe_getattr(message, "tool_calls", None) + if ( + tool_calls + and isinstance(tool_calls, list) + and len(tool_calls) > 0 + ): + tool_call = tool_calls[0] + if isinstance(tool_call, dict): + tool_call_id = tool_call.get("id") + function = tool_call.get("function", {}) + if isinstance(function, dict): + tool_call_name = function.get("name") + elif hasattr(tool_call, "id"): + tool_call_id = getattr(tool_call, "id", None) + function = getattr(tool_call, "function", None) + if function: + tool_call_name = getattr(function, "name", None) + + # Second call: provide tool call response + if tool_call_id: + messages_with_response = [ + {"role": "user", "content": "What's the weather in Beijing?"}, + { + "role": "assistant", + "content": "", + "tool_calls": [ + { + "id": tool_call_id, + "type": "function", + "function": { + "name": tool_call_name or "get_current_weather", + "arguments": '{"location": "Beijing"}', + }, + } + ], + }, + { + "role": "tool", + "content": '{"temperature": 20, "condition": "sunny"}', + "tool_call_id": tool_call_id, + }, + ] + + response2 = Generation.call( + model="qwen-turbo", + messages=messages_with_response, + tools=tools, + result_format="message", + ) + + assert response2 is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) >= 2, f"Expected at least 2 spans, got {len(spans)}" + + # Check the second span (tool call response) + span2 = spans[-1] + usage2 = _safe_getattr(response2, "usage", None) + output2 = _safe_getattr(response2, "output", None) + finish_reason2 = ( + _safe_getattr(output2, "finish_reason", None) if output2 else None + ) + + # Assert tool definitions are present + assert ( + "gen_ai.tool.definitions" in span2.attributes + ), "Missing gen_ai.tool.definitions" + tool_definitions_str = span2.attributes["gen_ai.tool.definitions"] + assert isinstance( + tool_definitions_str, str + ), "Tool definitions should be a JSON string" + import json + + tool_definitions = json.loads(tool_definitions_str) + assert isinstance( + tool_definitions, list + ), "Tool definitions should be a list after parsing" + assert ( + len(tool_definitions) > 0 + ), "Tool definitions should not be empty" + + # Verify full tool definition is recorded (content capture enabled) + tool_def = tool_definitions[0] + assert "name" in tool_def, "Tool definition should have 'name'" + assert "type" in tool_def, "Tool definition should have 'type'" + assert ( + tool_def["name"] == "get_current_weather" + ), "Tool name should match" + assert tool_def["type"] == "function", "Tool type should be 'function'" + # With content capture enabled, should have full definition + assert ( + "description" in tool_def + ), "Tool definition should have 'description' when content capture is enabled" + assert ( + "parameters" in tool_def + ), "Tool definition should have 'parameters' when content capture is enabled" + + # Check if response has output messages + # For tool call response scenario, output may be empty or have different format + # We check the span attributes to see if output messages were actually captured + has_output_messages = ( + GenAIAttributes.GEN_AI_OUTPUT_MESSAGES in span2.attributes + ) + + # Assert input/output messages with tool call response (content capture enabled) + # Note: output messages may not be present if response is empty + _assert_generation_span_attributes( + span2, + request_model="qwen-turbo", + response_id=_safe_getattr(response2, "request_id", None), + response_model=_safe_getattr(response2, "model", None), + input_tokens=_safe_getattr(usage2, "input_tokens", None) + if usage2 + else None, + output_tokens=_safe_getattr(usage2, "output_tokens", None) + if usage2 + else None, + finish_reasons=[finish_reason2] if finish_reason2 else None, + expect_input_messages=True, # Content capture enabled + expect_output_messages=has_output_messages, # Only if response has output messages + ) + + # Verify tool call response in input messages + if GenAIAttributes.GEN_AI_INPUT_MESSAGES in span2.attributes: + input_messages = span2.attributes[ + GenAIAttributes.GEN_AI_INPUT_MESSAGES + ] + if input_messages: + import json + + if isinstance(input_messages, str): + input_messages = json.loads(input_messages) + + # Check if any message has tool call response + has_tool_response = False + for msg in input_messages: + if isinstance(msg, dict): + role = msg.get("role") + parts = msg.get("parts", []) + if role == "tool": + for part in parts: + if ( + isinstance(part, dict) + and part.get("type") + == "tool_call_response" + ): + has_tool_response = True + break + if has_tool_response: + break + + assert ( + has_tool_response + ), "Expected tool call response in input messages" + + print( + "✓ Generation.call (with tool call response, content capture) completed successfully" + ) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py index c538e14a8..d9f951db5 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py @@ -2,9 +2,48 @@ import pytest +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) + + +def _assert_rerank_span_attributes(span, request_model: str): + """Assert rerank span attributes according to GenAI semantic conventions. + + Note: Rerank operation is not yet fully defined in GenAI semantic conventions, + but we follow the same pattern as other GenAI operations. + + Args: + span: The span to assert + request_model: Expected model name + """ + # Span name format is "{operation_name} {model}" per semantic conventions + # Operation name is "rerank" (custom value, waiting for semantic convention definition) + assert span.name == f"rerank {request_model}" + + # Required attributes (following GenAI pattern) + assert ( + GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "rerank" + ), f"Expected 'rerank', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + + assert ( + GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" + assert span.attributes[GenAIAttributes.GEN_AI_PROVIDER_NAME] == "dashscope" + + assert ( + GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == request_model + ) + @pytest.mark.vcr() -def test_text_rerank_basic(instrument): +def test_text_rerank_basic(instrument, span_exporter): """Test basic text rerank call.""" from dashscope import TextReRank @@ -19,11 +58,19 @@ def test_text_rerank_basic(instrument): ) assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + _assert_rerank_span_attributes(span, request_model="gte-rerank") + print("✓ TextReRank.call (basic) completed successfully") @pytest.mark.vcr() -def test_text_rerank_with_top_n(instrument): +def test_text_rerank_with_top_n(instrument, span_exporter): """Test text rerank with top_n parameter.""" from dashscope import TextReRank @@ -40,11 +87,19 @@ def test_text_rerank_with_top_n(instrument): ) assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + _assert_rerank_span_attributes(span, request_model="gte-rerank") + print("✓ TextReRank.call (with top_n) completed successfully") @pytest.mark.vcr() -def test_text_rerank_return_documents(instrument): +def test_text_rerank_return_documents(instrument, span_exporter): """Test text rerank with return_documents parameter.""" from dashscope import TextReRank @@ -59,4 +114,65 @@ def test_text_rerank_return_documents(instrument): ) assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + _assert_rerank_span_attributes(span, request_model="gte-rerank") + print("✓ TextReRank.call (return_documents) completed successfully") + + +@pytest.mark.vcr() +def test_text_rerank_error_handling(instrument, span_exporter): + """Test text rerank error handling. + + Note: This test verifies that errors are properly handled. + If an error occurs before the wrapper is called or if the API + returns an error response, a span should still be created with error status. + """ + from dashscope import TextReRank + + # Test with invalid model to trigger error + # Note: DashScope API may return an error response instead of raising an exception + try: + response = TextReRank.call( + model="invalid-model-name", + query="test query", + documents=["test document"], + ) + # If no error is raised, check that response is None or has error + if response is None: + # No response means error occurred before span creation + # This is acceptable - skip span assertion + print( + "✓ TextReRank.call (error handling) - no response, skipping span assertion" + ) + return + except Exception: + # Expected error - check if span was created + spans = span_exporter.get_finished_spans() + if len(spans) > 0: + # If span was created, verify it has error status + span = spans[0] + # Check that operation name is set even on error + if GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes: + assert ( + span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] + == "rerank" + ) + print("✓ TextReRank.call (error handling) - exception caught") + return + + # If we get here, check spans (may be error span or success span) + spans = span_exporter.get_finished_spans() + if len(spans) > 0: + span = spans[0] + # Check that operation name is set + assert ( + GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + + print("✓ TextReRank.call (error handling) completed successfully") From 63d420c2f8abb18c3267d006ea0a8207436bf097 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Sun, 7 Dec 2025 20:40:07 +0800 Subject: [PATCH 4/9] Add support for image synthesis Change-Id: Ib7a9bc46c390a237610d930bead35bf240a28a0c Co-developed-by: Cursor --- .../CHANGELOG.md | 3 + .../README.rst | 6 + .../instrumentation/dashscope/__init__.py | 67 +- .../instrumentation/dashscope/patch.py | 263 ++++ .../instrumentation/dashscope/utils.py | 413 ++++++- ...is_async_call_and_wait_separate_spans.yaml | 740 +++++++++++ ...test_image_synthesis_async_call_basic.yaml | 73 ++ .../test_image_synthesis_call_basic.yaml | 740 +++++++++++ ...age_synthesis_call_no_duplicate_spans.yaml | 740 +++++++++++ ..._image_synthesis_call_with_parameters.yaml | 738 +++++++++++ .../test_image_synthesis_wait_basic.yaml | 1084 +++++++++++++++++ .../tests/test_image_synthesis.py | 474 +++++++ .../src/opentelemetry/util/genai/handler.py | 9 +- 13 files changed, 5289 insertions(+), 61 deletions(-) create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_basic.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_basic.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_no_duplicate_spans.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md index 0f9bb70d3..9f50f0e76 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/CHANGELOG.md @@ -13,6 +13,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Support for AioGeneration.call (async) - Support for TextEmbedding.call - Support for TextReRank.call +- Support for ImageSynthesis.call (sync) +- Support for ImageSynthesis.async_call (async task submission) +- Support for ImageSynthesis.wait (async task waiting) - Support for streaming responses (sync and async) - Data extraction and telemetry collection using `opentelemetry-util-genai` - Span attributes following OpenTelemetry GenAI Semantic Conventions: diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst index 3307f6a9d..4636424e9 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.rst @@ -62,6 +62,12 @@ Supported APIs * ``TextReRank.call`` +* **Image Synthesis** + + * ``ImageSynthesis.call`` (sync) + * ``ImageSynthesis.async_call`` (async task submission) + * ``ImageSynthesis.wait`` (async task waiting) + Captured Attributes -------------------- diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py index d6d99f5fa..be62bd431 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py @@ -16,12 +16,13 @@ LoongSuite Instrumentation for Alibaba Cloud DashScope SDK. This instrumentation library provides automatic tracing for DashScope API calls, -including text generation, text embedding, and text reranking. +including text generation, text embedding, text reranking, and image synthesis. Supported Operations: - Text Generation (sync/async, streaming/non-streaming) - Text Embedding - Text Reranking + - Image Synthesis (sync/async) Note: Chat Completion (OpenAI-compatible) is NOT supported due to a bug in DashScope SDK where Completions.create references a non-existent attribute @@ -45,6 +46,9 @@ from loongsuite.instrumentation.dashscope.patch import ( wrap_aio_generation_call, wrap_generation_call, + wrap_image_synthesis_async_call, + wrap_image_synthesis_call, + wrap_image_synthesis_wait, wrap_text_embedding_call, wrap_text_rerank_call, ) @@ -61,6 +65,7 @@ logger = logging.getLogger(__name__) _MODULE_GENERATION = "dashscope.aigc.generation" +_MODULE_IMAGE_SYNTHESIS = "dashscope.aigc.image_synthesis" _MODULE_TEXT_EMBEDDING = "dashscope.embeddings.text_embedding" _MODULE_TEXT_RERANK = "dashscope.rerank.text_rerank" @@ -130,6 +135,27 @@ def wrap_text_rerank_call_with_provider( wrapped, instance, args, kwargs, handler=handler ) + def wrap_image_synthesis_call_with_provider( + wrapped, instance, args, kwargs + ): + return wrap_image_synthesis_call( + wrapped, instance, args, kwargs, handler=handler + ) + + def wrap_image_synthesis_async_call_with_provider( + wrapped, instance, args, kwargs + ): + return wrap_image_synthesis_async_call( + wrapped, instance, args, kwargs, handler=handler + ) + + def wrap_image_synthesis_wait_with_provider( + wrapped, instance, args, kwargs + ): + return wrap_image_synthesis_wait( + wrapped, instance, args, kwargs, handler=handler + ) + # Instrument Generation.call (sync) try: wrap_function_wrapper( @@ -174,6 +200,41 @@ def wrap_text_rerank_call_with_provider( except Exception as e: logger.warning(f"Failed to instrument TextReRank.call: {e}") + # Instrument ImageSynthesis.call (sync) + try: + wrap_function_wrapper( + module=_MODULE_IMAGE_SYNTHESIS, + name="ImageSynthesis.call", + wrapper=wrap_image_synthesis_call_with_provider, + ) + logger.debug("Instrumented ImageSynthesis.call") + except Exception as e: + logger.warning(f"Failed to instrument ImageSynthesis.call: {e}") + + # Instrument ImageSynthesis.async_call + try: + wrap_function_wrapper( + module=_MODULE_IMAGE_SYNTHESIS, + name="ImageSynthesis.async_call", + wrapper=wrap_image_synthesis_async_call_with_provider, + ) + logger.debug("Instrumented ImageSynthesis.async_call") + except Exception as e: + logger.warning( + f"Failed to instrument ImageSynthesis.async_call: {e}" + ) + + # Instrument ImageSynthesis.wait + try: + wrap_function_wrapper( + module=_MODULE_IMAGE_SYNTHESIS, + name="ImageSynthesis.wait", + wrapper=wrap_image_synthesis_wait_with_provider, + ) + logger.debug("Instrumented ImageSynthesis.wait") + except Exception as e: + logger.warning(f"Failed to instrument ImageSynthesis.wait: {e}") + def _uninstrument(self, **kwargs): """Uninstrument the DashScope SDK. @@ -184,11 +245,15 @@ def _uninstrument(self, **kwargs): """ # pylint: disable=import-outside-toplevel import dashscope.aigc.generation + import dashscope.aigc.image_synthesis import dashscope.embeddings.text_embedding import dashscope.rerank.text_rerank unwrap(dashscope.aigc.generation.Generation, "call") unwrap(dashscope.aigc.generation.AioGeneration, "call") + unwrap(dashscope.aigc.image_synthesis.ImageSynthesis, "call") + unwrap(dashscope.aigc.image_synthesis.ImageSynthesis, "async_call") + unwrap(dashscope.aigc.image_synthesis.ImageSynthesis, "wait") unwrap(dashscope.embeddings.text_embedding.TextEmbedding, "call") unwrap(dashscope.rerank.text_rerank.TextReRank, "call") diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py index 887c9d50a..0938f472a 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py @@ -17,6 +17,10 @@ import inspect import logging +from opentelemetry import context, trace +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) from opentelemetry.util.genai.extended_types import ( EmbeddingInvocation, RerankInvocation, @@ -26,7 +30,12 @@ from .utils import ( _create_accumulated_response, _create_invocation_from_generation, + _create_invocation_from_image_synthesis, + _extract_task_id, _get_parameter, + _SKIP_INSTRUMENTATION_KEY, + _update_invocation_from_image_synthesis_async_response, + _update_invocation_from_image_synthesis_response, _update_invocation_from_response, ) @@ -391,3 +400,257 @@ async def _wrap_async_generator( error = Error(message=str(e), type=type(e)) handler.fail_llm(invocation, error) raise + + +def wrap_image_synthesis_call(wrapped, instance, args, kwargs, handler=None): + """Wrapper for ImageSynthesis.call (sync). + + This wrapper tracks the complete synchronous call flow (async_call + wait). + Uses context flag to avoid duplicate span creation from async_call and wait. + + Args: + wrapped: The original function being wrapped + instance: The instance the method is bound to (if any) + args: Positional arguments + kwargs: Keyword arguments + handler: ExtendedTelemetryHandler instance (created during instrumentation) + """ + # Extract model from kwargs + model = kwargs.get("model") + if not model: + logger.warning("Model not found in kwargs, skipping instrumentation") + return wrapped(*args, **kwargs) + + if handler is None: + logger.warning("Handler not provided, skipping instrumentation") + return wrapped(*args, **kwargs) + + try: + # Create invocation object + invocation = _create_invocation_from_image_synthesis(kwargs, model) + + # Start LLM invocation (creates span) + handler.start_llm(invocation) + + # In sync call scenario, set a flag in context to skip span creation in async_call and wait + ctx = context.set_value(_SKIP_INSTRUMENTATION_KEY, True) + token = context.attach(ctx) + + try: + # Execute the wrapped call (internal will call async_call + wait) + result = wrapped(*args, **kwargs) + + # Update invocation with response data + _update_invocation_from_image_synthesis_response(invocation, result) + handler.stop_llm(invocation) + + # Manually update span name and operation name after stop_llm + # because _apply_common_span_attributes hardcodes "chat" + if invocation.span and invocation.span.is_recording(): + operation_name = invocation.attributes.get("gen_ai.operation.name") + if operation_name: + invocation.span.update_name( + f"{operation_name} {invocation.request_model}" + ) + invocation.span.set_attribute( + GenAIAttributes.GEN_AI_OPERATION_NAME, operation_name + ) + + return result + + except Exception as e: + error = Error(message=str(e), type=type(e)) + handler.fail_llm(invocation, error) + raise + finally: + # Restore context + if token is not None: + context.detach(token) + + except Exception as e: + logger.exception("Error in instrumentation wrapper: %s", e) + return wrapped(*args, **kwargs) + + +def wrap_image_synthesis_async_call( + wrapped, instance, args, kwargs, handler=None +): + """Wrapper for ImageSynthesis.async_call. + + This wrapper tracks the task submission phase. + If called within call() context, skips span creation. + Stores span context in response object for span linking with wait(). + + Args: + wrapped: The original function being wrapped + instance: The instance the method is bound to (if any) + args: Positional arguments + kwargs: Keyword arguments + handler: ExtendedTelemetryHandler instance (created during instrumentation) + """ + # Check if in call() context (sync call scenario) + if context.get_value(_SKIP_INSTRUMENTATION_KEY): + # In sync call scenario, skip span creation + return wrapped(*args, **kwargs) + + # Extract model from kwargs + model = kwargs.get("model") + if not model: + logger.warning("Model not found in kwargs, skipping instrumentation") + return wrapped(*args, **kwargs) + + if handler is None: + logger.warning("Handler not provided, skipping instrumentation") + return wrapped(*args, **kwargs) + + try: + # Create invocation object + invocation = _create_invocation_from_image_synthesis(kwargs, model) + invocation.attributes["gen_ai.request.async"] = True + + # Start LLM invocation (creates span) + handler.start_llm(invocation) + + try: + # Execute the wrapped call (submit task) + result = wrapped(*args, **kwargs) + + # Extract task_id and update invocation + task_id = None + if result and hasattr(result, "output"): + if hasattr(result.output, "get"): + task_id = result.output.get("task_id") + elif hasattr(result.output, "task_id"): + task_id = getattr(result.output, "task_id", None) + + if task_id: + invocation.attributes["gen_ai.response.id"] = task_id + invocation.attributes["dashscope.task_id"] = task_id + + # Get current span context and store in response object for span linking + current_span = trace.get_current_span() + if current_span and current_span.is_recording(): + span_context = current_span.get_span_context() + # Store span context in response object + if hasattr(result, "__dict__"): + result.__dict__["_otel_span_context"] = span_context + elif hasattr(result, "_otel_span_context"): + result._otel_span_context = span_context + + # Update invocation with async response data (task_id, task_status) + _update_invocation_from_image_synthesis_async_response( + invocation, result + ) + handler.stop_llm(invocation) + return result + + except Exception as e: + error = Error(message=str(e), type=type(e)) + handler.fail_llm(invocation, error) + raise + + except Exception as e: + logger.exception("Error in async_call instrumentation wrapper: %s", e) + return wrapped(*args, **kwargs) + + +def wrap_image_synthesis_wait(wrapped, instance, args, kwargs, handler=None): + """Wrapper for ImageSynthesis.wait. + + This wrapper tracks the task waiting and result retrieval phase. + If called within call() context, skips span creation. + Attempts to get span context from response object for span linking. + + Args: + wrapped: The original function being wrapped + instance: The instance the method is bound to (if any) + args: Positional arguments + kwargs: Keyword arguments + handler: ExtendedTelemetryHandler instance (created during instrumentation) + """ + # Check if in call() context (sync call scenario) + if context.get_value(_SKIP_INSTRUMENTATION_KEY): + # In sync call scenario, skip span creation + return wrapped(*args, **kwargs) + + if handler is None: + logger.warning("Handler not provided, skipping instrumentation") + return wrapped(*args, **kwargs) + + try: + # Extract task and task_id + task = args[0] if args else kwargs.get("task") + task_id = _extract_task_id(task) + + if not task_id: + # If cannot extract task_id, skip instrumentation + return wrapped(*args, **kwargs) + + # Try to get span context from response object for span linking + span_context = None + if task: + try: + # DashScope response objects use __getattr__ which raises KeyError + # Use getattr with default to safely check + if hasattr(task, "__dict__") and "_otel_span_context" in task.__dict__: + span_context = task.__dict__["_otel_span_context"] + elif hasattr(task, "_otel_span_context"): + # Try to get it, but catch KeyError if it doesn't exist + try: + span_context = getattr(task, "_otel_span_context", None) + except KeyError: + pass + except (KeyError, AttributeError): + pass + + # Create invocation object (wait phase doesn't know model, use "unknown") + invocation = _create_invocation_from_image_synthesis({}, "unknown") + invocation.attributes["gen_ai.operation.name"] = "generate_content" + invocation.attributes["gen_ai.request.async"] = True + invocation.attributes["gen_ai.response.id"] = task_id + invocation.attributes["dashscope.task_id"] = task_id + invocation.attributes["dashscope.operation"] = "wait" + + # Store span context for potential linking (if ExtendedTelemetryHandler supports it) + # Note: We don't store span_context in attributes as it's not a valid attribute type + # Span linking would need to be implemented differently if ExtendedTelemetryHandler supports it + + # Start LLM invocation (creates span) + handler.start_llm(invocation) + + # TODO: If ExtendedTelemetryHandler supports, add span link after span creation + # current_span = trace.get_current_span() + # if current_span and current_span.is_recording() and span_context: + # link = trace.Link(span_context) + # # Add link to span + + try: + # Execute the wrapped call (wait for task completion) + result = wrapped(*args, **kwargs) + + # Update invocation with response data + _update_invocation_from_image_synthesis_response(invocation, result) + handler.stop_llm(invocation) + + # Manually update span name and operation name after stop_llm + # because _apply_common_span_attributes hardcodes "chat" + if invocation.span and invocation.span.is_recording(): + operation_name = invocation.attributes.get("gen_ai.operation.name") + if operation_name: + invocation.span.update_name( + f"{operation_name} {invocation.request_model}" + ) + invocation.span.set_attribute( + GenAIAttributes.GEN_AI_OPERATION_NAME, operation_name + ) + + return result + + except Exception as e: + error = Error(message=str(e), type=type(e)) + handler.fail_llm(invocation, error) + raise + + except Exception as e: + logger.exception("Error in wait instrumentation wrapper: %s", e) + return wrapped(*args, **kwargs) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py index 243a3f89b..b1af2071a 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py @@ -29,7 +29,9 @@ ) -def _get_parameter(kwargs: dict, param_name: str, parameters: Optional[dict] = None) -> Optional[Any]: +def _get_parameter( + kwargs: dict, param_name: str, parameters: Optional[dict] = None +) -> Optional[Any]: """Get parameter from kwargs or parameters dict. Checks kwargs first (direct arguments), then kwargs["parameters"] if provided. @@ -71,9 +73,9 @@ def _extract_input_messages(kwargs: dict) -> List[InputMessage]: content = msg.get("content", "") tool_call_id = msg.get("tool_call_id") tool_calls = msg.get("tool_calls") - + parts = [] - + # Handle tool call response (role="tool") if role == "tool": # For tool role, use ToolCallResponse @@ -94,19 +96,34 @@ def _extract_input_messages(kwargs: dict) -> List[InputMessage]: for part in content: if isinstance(part, dict): if "text" in part: - parts.append(Text(content=part["text"], type="text")) + parts.append( + Text( + content=part["text"], + type="text", + ) + ) elif isinstance(part, str): - parts.append(Text(content=part, type="text")) - + parts.append( + Text(content=part, type="text") + ) + # Add tool calls if present (for assistant messages with tool calls) if tool_calls and isinstance(tool_calls, list): for tool_call in tool_calls: if isinstance(tool_call, dict): tc_id = tool_call.get("id") function = tool_call.get("function", {}) - tool_name = function.get("name") if isinstance(function, dict) else None - tool_args = function.get("arguments") if isinstance(function, dict) else None - + tool_name = ( + function.get("name") + if isinstance(function, dict) + else None + ) + tool_args = ( + function.get("arguments") + if isinstance(function, dict) + else None + ) + if tool_name: parts.append( ToolCall( @@ -116,7 +133,7 @@ def _extract_input_messages(kwargs: dict) -> List[InputMessage]: type="tool_call", ) ) - + if parts: input_messages.append( InputMessage( @@ -137,11 +154,11 @@ def _extract_input_messages(kwargs: dict) -> List[InputMessage]: content = getattr(msg, "content", "") tool_call_id = getattr(msg, "tool_call_id", None) tool_calls = getattr(msg, "tool_calls", None) - + parts = [] - + # Handle tool call response (role="tool") - if role == "tool" : + if role == "tool": # For tool role, use ToolCallResponse parts.append( ToolCallResponse( @@ -159,10 +176,14 @@ def _extract_input_messages(kwargs: dict) -> List[InputMessage]: # TODO: Handle multimodal content for part in content: if isinstance(part, dict) and "text" in part: - parts.append(Text(content=part["text"], type="text")) + parts.append( + Text(content=part["text"], type="text") + ) elif isinstance(part, str): - parts.append(Text(content=part, type="text")) - + parts.append( + Text(content=part, type="text") + ) + # Add tool calls if present if tool_calls: for tool_call in tool_calls: @@ -170,9 +191,11 @@ def _extract_input_messages(kwargs: dict) -> List[InputMessage]: function = getattr(tool_call, "function", None) if function: tool_name = getattr(function, "name", None) - tool_args = getattr(function, "arguments", None) + tool_args = getattr( + function, "arguments", None + ) tc_id = getattr(tool_call, "id", None) - + if tool_name: parts.append( ToolCall( @@ -182,7 +205,7 @@ def _extract_input_messages(kwargs: dict) -> List[InputMessage]: type="tool_call", ) ) - + if parts: input_messages.append( InputMessage( @@ -214,19 +237,19 @@ def _extract_input_messages(kwargs: dict) -> List[InputMessage]: def _extract_tool_definitions(kwargs: dict) -> ToolDefinitions: """Extract tool definitions from DashScope API kwargs and convert to FunctionToolDefinition objects. - + DashScope supports both `tools` and `plugins` parameters for tool definitions. - `tools`: Direct list of tool definitions (preferred) - `plugins`: Can be a string (JSON) or a dict containing tools - + Args: kwargs: Generation.call kwargs - + Returns: List of FunctionToolDefinition objects, or empty list if not found """ tool_definitions: ToolDefinitions = [] - + # Check for tools parameter first (preferred) tools = kwargs.get("tools") if not tools: @@ -237,7 +260,7 @@ def _extract_tool_definitions(kwargs: dict) -> ToolDefinitions: # If plugins is a string, parse it as JSON if isinstance(plugins, str): plugins = json.loads(plugins) - + # If plugins is a dict, extract tools if isinstance(plugins, dict): # DashScope plugins format: {"tools": [...]} or direct list @@ -246,14 +269,14 @@ def _extract_tool_definitions(kwargs: dict) -> ToolDefinitions: # Check if plugins itself is a list-like structure elif isinstance(plugins, list): tools = plugins - + # If plugins is already a list, use it if isinstance(plugins, list): tools = plugins except (json.JSONDecodeError, TypeError, AttributeError): # If parsing fails, return empty list return tool_definitions - + # Convert tool definitions to FunctionToolDefinition objects if tools and isinstance(tools, list): for tool in tools: @@ -282,7 +305,7 @@ def _extract_tool_definitions(kwargs: dict) -> ToolDefinitions: elif isinstance(tool, FunctionToolDefinition): # Already a FunctionToolDefinition, add directly tool_definitions.append(tool) - + return tool_definitions @@ -316,21 +339,21 @@ def _extract_output_messages(response: Any) -> List[OutputMessage]: for choice in choices: if not choice: continue - + # Extract message from choice message = getattr(choice, "message", None) if not message: continue - + # Extract content and tool_calls content = getattr(message, "content", None) tool_calls = getattr(message, "tool_calls", None) - finish_reason = getattr(choice, "finish_reason", None) or getattr( - output, "finish_reason", "stop" - ) - + finish_reason = getattr( + choice, "finish_reason", None + ) or getattr(output, "finish_reason", "stop") + parts = [] - + # Add text content if present if content: if isinstance(content, str): @@ -340,19 +363,29 @@ def _extract_output_messages(response: Any) -> List[OutputMessage]: for part in content: if isinstance(part, dict): if "text" in part: - parts.append(Text(content=part["text"], type="text")) + parts.append( + Text(content=part["text"], type="text") + ) elif isinstance(part, str): parts.append(Text(content=part, type="text")) - + # Add tool calls if present if tool_calls and isinstance(tool_calls, list): for tool_call in tool_calls: if isinstance(tool_call, dict): tool_call_id = tool_call.get("id") function = tool_call.get("function", {}) - tool_name = function.get("name") if isinstance(function, dict) else None - tool_args = function.get("arguments") if isinstance(function, dict) else None - + tool_name = ( + function.get("name") + if isinstance(function, dict) + else None + ) + tool_args = ( + function.get("arguments") + if isinstance(function, dict) + else None + ) + if tool_name: parts.append( ToolCall( @@ -367,9 +400,11 @@ def _extract_output_messages(response: Any) -> List[OutputMessage]: function = getattr(tool_call, "function", None) if function: tool_name = getattr(function, "name", None) - tool_args = getattr(function, "arguments", None) + tool_args = getattr( + function, "arguments", None + ) tool_call_id = getattr(tool_call, "id", None) - + if tool_name: parts.append( ToolCall( @@ -379,7 +414,7 @@ def _extract_output_messages(response: Any) -> List[OutputMessage]: type="tool_call", ) ) - + # Create output message if we have parts OR if finish_reason indicates tool_calls # (even if content is empty, tool calls should be captured) if parts or (finish_reason == "tool_calls" and tool_calls): @@ -392,7 +427,9 @@ def _extract_output_messages(response: Any) -> List[OutputMessage]: ) else: # Standard format: output.text - text = getattr(output, "text", None) or getattr(output, "content", None) + text = getattr(output, "text", None) or getattr( + output, "content", None + ) finish_reason = getattr(output, "finish_reason", "stop") if text: @@ -462,7 +499,7 @@ def _create_invocation_from_generation( invocation = LLMInvocation(request_model=request_model) invocation.provider = "dashscope" invocation.input_messages = _extract_input_messages(kwargs) - + # Extract tool definitions and convert to FunctionToolDefinition objects invocation.tool_definitions = _extract_tool_definitions(kwargs) @@ -472,7 +509,7 @@ def _create_invocation_from_generation( parameters = kwargs.get("parameters", {}) if not isinstance(parameters, dict): parameters = {} - + # Temperature temperature = _get_parameter(kwargs, "temperature", parameters) if temperature is not None: @@ -494,26 +531,42 @@ def _create_invocation_from_generation( invocation.attributes["gen_ai.request.max_tokens"] = max_tokens # Repetition penalty - repetition_penalty = _get_parameter(kwargs, "repetition_penalty", parameters) + repetition_penalty = _get_parameter( + kwargs, "repetition_penalty", parameters + ) if repetition_penalty is not None: - invocation.attributes["gen_ai.request.repetition_penalty"] = repetition_penalty + invocation.attributes["gen_ai.request.repetition_penalty"] = ( + repetition_penalty + ) else: # Fallback to frequency_penalty and presence_penalty if repetition_penalty not present - frequency_penalty = _get_parameter(kwargs, "frequency_penalty", parameters) + frequency_penalty = _get_parameter( + kwargs, "frequency_penalty", parameters + ) if frequency_penalty is not None: - invocation.attributes["gen_ai.request.frequency_penalty"] = frequency_penalty + invocation.attributes["gen_ai.request.frequency_penalty"] = ( + frequency_penalty + ) - presence_penalty = _get_parameter(kwargs, "presence_penalty", parameters) + presence_penalty = _get_parameter( + kwargs, "presence_penalty", parameters + ) if presence_penalty is not None: - invocation.attributes["gen_ai.request.presence_penalty"] = presence_penalty + invocation.attributes["gen_ai.request.presence_penalty"] = ( + presence_penalty + ) # Stop sequences stop_sequences = _get_parameter(kwargs, "stop", parameters) if stop_sequences is not None: if isinstance(stop_sequences, list): - invocation.attributes["gen_ai.request.stop_sequences"] = stop_sequences + invocation.attributes["gen_ai.request.stop_sequences"] = ( + stop_sequences + ) elif isinstance(stop_sequences, str): - invocation.attributes["gen_ai.request.stop_sequences"] = [stop_sequences] + invocation.attributes["gen_ai.request.stop_sequences"] = [ + stop_sequences + ] # Seed seed = _get_parameter(kwargs, "seed", parameters) @@ -568,11 +621,11 @@ def _update_invocation_from_response( def _create_accumulated_response(original_response, accumulated_text): """Create a response object with accumulated text for incremental output mode. - + Args: original_response: The last chunk response object accumulated_text: The accumulated text from all chunks - + Returns: A response object with accumulated text, or original_response if modification fails """ @@ -586,14 +639,16 @@ def _create_accumulated_response(original_response, accumulated_text): except (AttributeError, TypeError): # If we can't modify, create a wrapper object pass - + # Create wrapper objects with accumulated text class AccumulatedOutput: def __init__(self, original_output, accumulated_text): self.text = accumulated_text - self.finish_reason = getattr(original_output, "finish_reason", "stop") + self.finish_reason = getattr( + original_output, "finish_reason", "stop" + ) self.content = accumulated_text - + class AccumulatedResponse: def __init__(self, original_response, accumulated_output): self.output = accumulated_output @@ -605,10 +660,250 @@ def __init__(self, original_response, accumulated_output): setattr(self, attr, value) except (KeyError, AttributeError): pass - + accumulated_output = AccumulatedOutput(output, accumulated_text) return AccumulatedResponse(original_response, accumulated_output) except (KeyError, AttributeError): # If modification fails, return original response return original_response + +# Context key for skipping instrumentation in nested calls +_SKIP_INSTRUMENTATION_KEY = "dashscope.skip_instrumentation" + + +def _extract_task_id(task: Any) -> Optional[str]: + """Extract task_id from task parameter (can be str or ImageSynthesisResponse). + + Args: + task: Task parameter (str task_id or ImageSynthesisResponse object) + + Returns: + task_id string if found, None otherwise + """ + if not task: + return None + + if isinstance(task, str): + return task + + try: + # Try to get task_id from response object + if hasattr(task, "output") and hasattr(task.output, "get"): + task_id = task.output.get("task_id") + if task_id: + return task_id + except (KeyError, AttributeError): + pass + + return None + + +def _create_invocation_from_image_synthesis( + kwargs: dict, model: Optional[str] = None +) -> LLMInvocation: + """Create LLMInvocation from ImageSynthesis.call or async_call kwargs. + + Args: + kwargs: ImageSynthesis.call or async_call kwargs + model: Model name (if not in kwargs) + + Returns: + LLMInvocation object + """ + request_model = kwargs.get("model") or model + if not request_model: + raise ValueError("Model name is required") + + invocation = LLMInvocation(request_model=request_model) + invocation.provider = "dashscope" + invocation.attributes["gen_ai.operation.name"] = "generate_content" + + # Extract prompt as input message + prompt = kwargs.get("prompt") + if prompt: + if isinstance(prompt, str): + invocation.input_messages = [ + InputMessage( + role="user", + parts=[Text(content=prompt, type="text")], + ) + ] + elif isinstance(prompt, list): + # Handle list of prompts + parts = [] + for p in prompt: + if isinstance(p, str): + parts.append(Text(content=p, type="text")) + if parts: + invocation.input_messages = [ + InputMessage(role="user", parts=parts) + ] + + # Extract negative_prompt (as attribute) + negative_prompt = kwargs.get("negative_prompt") + if negative_prompt: + if isinstance(negative_prompt, str): + invocation.attributes["dashscope.negative_prompt"] = ( + negative_prompt + ) + + # Extract size (image dimensions) + size = kwargs.get("size") + if size: + invocation.attributes["dashscope.image.size"] = size + + # Extract n (number of images to generate) + n = kwargs.get("n") + if n is not None: + invocation.attributes["dashscope.image.n"] = n + + # Extract similarity parameter (if available) + similarity = kwargs.get("similarity") + if similarity is not None: + invocation.attributes["dashscope.image.similarity"] = similarity + + return invocation + + +def _update_invocation_from_image_synthesis_response( + invocation: LLMInvocation, response: Any +) -> None: + """Update LLMInvocation with ImageSynthesis response data (for call() and wait()). + + Args: + invocation: LLMInvocation to update + response: ImageSynthesisResponse object + """ + if not response: + return + + try: + # Extract token usage + input_tokens, output_tokens = _extract_usage(response) + invocation.input_tokens = input_tokens + invocation.output_tokens = output_tokens + + # Extract response model name (if available) + try: + response_model = getattr(response, "model", None) + if response_model: + invocation.response_model_name = response_model + except (KeyError, AttributeError): + pass + + # Extract request ID (if available) + # Note: For ImageSynthesis, request_id is the main identifier, not task_id + try: + request_id = getattr(response, "request_id", None) + if request_id: + invocation.response_id = request_id + except (KeyError, AttributeError): + pass + + # Extract task_id and task_status from output + try: + output = getattr(response, "output", None) + if output: + # Extract task_id + task_id = None + if hasattr(output, "get"): + task_id = output.get("task_id") + elif hasattr(output, "task_id"): + task_id = getattr(output, "task_id", None) + + if task_id: + # Store task_id in attributes + # Note: gen_ai.response.id should be request_id, not task_id + # task_id is stored separately in dashscope.task_id + invocation.attributes["dashscope.task_id"] = task_id + # Don't set gen_ai.response.id to task_id, as it should be request_id + # Only set response_id to task_id if request_id is not available + if not invocation.response_id: + invocation.response_id = task_id + invocation.attributes["gen_ai.response.id"] = task_id + + # Extract task_status + task_status = None + if hasattr(output, "get"): + task_status = output.get("task_status") + elif hasattr(output, "task_status"): + task_status = getattr(output, "task_status", None) + + if task_status: + invocation.attributes["dashscope.task_status"] = ( + task_status + ) + + # Extract image URLs from results + # TODO: If returned as files or binary data, handle accordingly + results = None + if hasattr(output, "get"): + results = output.get("results") + elif hasattr(output, "results"): + results = getattr(output, "results", None) + + if results and isinstance(results, list): + image_urls = [] + for result in results: + if isinstance(result, dict): + url = result.get("url") + if url: + image_urls.append(url) + elif hasattr(result, "url"): + url = getattr(result, "url", None) + if url: + image_urls.append(url) + if image_urls: + # Store first image URL as attribute (or all if needed) + invocation.attributes["dashscope.image.url"] = ( + image_urls[0] if len(image_urls) == 1 else str(image_urls) + ) + except (KeyError, AttributeError): + pass + except (KeyError, AttributeError): + # If any attribute access fails, silently continue with available data + pass + + +def _update_invocation_from_image_synthesis_async_response( + invocation: LLMInvocation, response: Any +) -> None: + """Update LLMInvocation with ImageSynthesis async_call response data. + + This is called when async_call() returns, before wait() is called. + Only extracts task_id and task_status (usually PENDING). + + Args: + invocation: LLMInvocation to update + response: ImageSynthesisResponse object from async_call() + """ + if not response: + return + + try: + # Extract task_id and task_status from output + output = getattr(response, "output", None) + if output: + # Extract task_id + task_id = None + if hasattr(output, "get"): + task_id = output.get("task_id") + elif hasattr(output, "task_id"): + task_id = getattr(output, "task_id", None) + + if task_id: + invocation.attributes["gen_ai.response.id"] = task_id + invocation.attributes["dashscope.task_id"] = task_id + + # Extract task_status (usually PENDING for async_call) + task_status = None + if hasattr(output, "get"): + task_status = output.get("task_status") + elif hasattr(output, "task_status"): + task_status = getattr(output, "task_status", None) + + if task_status: + invocation.attributes["dashscope.task_status"] = task_status + except (KeyError, AttributeError): + pass diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml new file mode 100644 index 000000000..c3889a373 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml @@ -0,0 +1,740 @@ +interactions: +- request: + body: |- + { + "model": "wanx-v1", + "parameters": {}, + "input": { + "prompt": "A test image for async" + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '85' + Content-Type: + - application/json + X-DashScope-Async: + - enable + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis + response: + body: + string: |- + { + "request_id": "14e94672-0b0a-4fe5-b472-a1c613416760", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "PENDING" + } + } + headers: + content-length: + - '137' + content-type: + - application/json + date: + - Sun, 07 Dec 2025 11:31:02 GMT + req-arrive-time: + - '1765107062821' + req-cost-time: + - '113' + resp-start-time: + - '1765107062934' + server: + - istio-envoy + set-cookie: + - acw_tc=14e94672-0b0a-4fe5-b472-a1c613416760fcc578913426bffaa53dc6cb8acfbc46;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '106' + x-request-id: + - 14e94672-0b0a-4fe5-b472-a1c613416760 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "5f758953-78ca-42f8-ba9f-a9ed071c141a", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:03 GMT + req-arrive-time: + - '1765107063046' + req-cost-time: + - '49' + resp-start-time: + - '1765107063095' + server: + - istio-envoy + set-cookie: + - acw_tc=5f758953-78ca-42f8-ba9f-a9ed071c141aec551f53f2f1e6ec5751235fc2265d38;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '41' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "f44ae63e-0530-4de4-97fc-7c09d2451b5e", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:04 GMT + req-arrive-time: + - '1765107064195' + req-cost-time: + - '39' + resp-start-time: + - '1765107064235' + server: + - istio-envoy + set-cookie: + - acw_tc=f44ae63e-0530-4de4-97fc-7c09d2451b5e582de241ea6e6cdb7b2f9533eea9b969;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '33' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "f98cb6c2-ccb1-48e7-878e-001ede225ab2", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:05 GMT + req-arrive-time: + - '1765107065345' + req-cost-time: + - '49' + resp-start-time: + - '1765107065395' + server: + - istio-envoy + set-cookie: + - acw_tc=f98cb6c2-ccb1-48e7-878e-001ede225ab282065eed3e3cf81d55d99590c8b5d6a9;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '42' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "a4da8bec-4e89-4949-93d6-5853af926886", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:07 GMT + req-arrive-time: + - '1765107067505' + req-cost-time: + - '62' + resp-start-time: + - '1765107067567' + server: + - istio-envoy + set-cookie: + - acw_tc=a4da8bec-4e89-4949-93d6-5853af926886bc68efbde583dac4378c55c6d97d22d7;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '54' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "af3cdc45-1970-4e2a-9721-9cae4364b25e", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:09 GMT + req-arrive-time: + - '1765107069702' + req-cost-time: + - '49' + resp-start-time: + - '1765107069751' + server: + - istio-envoy + set-cookie: + - acw_tc=af3cdc45-1970-4e2a-9721-9cae4364b25e6ebf92b34be7623e076a926faf2502bf;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '40' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "927fc47f-c8c4-48dc-b7db-9e14d5955c67", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:11 GMT + req-arrive-time: + - '1765107071887' + req-cost-time: + - '49' + resp-start-time: + - '1765107071936' + server: + - istio-envoy + set-cookie: + - acw_tc=927fc47f-c8c4-48dc-b7db-9e14d5955c6783a9be1204c40a04adea57fd1616e5e2;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '42' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "37f4d664-fbf1-4322-be4f-b428c4b62826", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:16 GMT + req-arrive-time: + - '1765107076040' + req-cost-time: + - '53' + resp-start-time: + - '1765107076094' + server: + - istio-envoy + set-cookie: + - acw_tc=37f4d664-fbf1-4322-be4f-b428c4b62826ed27e659ae5411e494f7707f9e6367bf;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '46' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "a5a15dfe-3bcf-4e42-a3c6-36a564c2f51c", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:20 GMT + req-arrive-time: + - '1765107080202' + req-cost-time: + - '47' + resp-start-time: + - '1765107080250' + server: + - istio-envoy + set-cookie: + - acw_tc=a5a15dfe-3bcf-4e42-a3c6-36a564c2f51cadfab69447927bc9728a5f67c5048056;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '40' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "4999648b-824a-4c5e-b204-4bc2fc49ef7c", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:24 GMT + req-arrive-time: + - '1765107084362' + req-cost-time: + - '49' + resp-start-time: + - '1765107084412' + server: + - istio-envoy + set-cookie: + - acw_tc=4999648b-824a-4c5e-b204-4bc2fc49ef7c1a58f1c7eab1942ddb059306fd918233;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '41' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "a8e37642-4dfd-4e99-b51f-07c6631dc472", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 1, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:29 GMT + req-arrive-time: + - '1765107089585' + req-cost-time: + - '50' + resp-start-time: + - '1765107089635' + server: + - istio-envoy + set-cookie: + - acw_tc=a8e37642-4dfd-4e99-b51f-07c6631dc472acf1db8ded7c3e0b834600162c91370d;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '43' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed + response: + body: + string: |- + { + "request_id": "61e1bb54-d241-4c5c-a4ff-b4239f923092", + "output": { + "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", + "task_status": "SUCCEEDED", + "submit_time": "2025-12-07 19:31:02.915", + "scheduled_time": "2025-12-07 19:31:02.961", + "end_time": "2025-12-07 19:31:31.825", + "results": [ + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/db/20251207/c70535fc/c4506c8d-2122-494f-a627-a847859df39a-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/77/20251207/c70535fc/8b07df98-cb21-4f16-a33c-ce9d1d898dea-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/ab/20251207/c70535fc/f52c0f1d-1c3d-4382-b629-90f381fb9c69-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/e3/20251207/c70535fc/4bf46851-e519-481f-b840-8f3d8b141bf7-1.png" + } + ], + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 4, + "FAILED": 0 + } + }, + "usage": { + "image_count": 4 + } + } + headers: + content-length: + - '1285' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:34 GMT + req-arrive-time: + - '1765107094738' + req-cost-time: + - '33' + resp-start-time: + - '1765107094772' + server: + - istio-envoy + set-cookie: + - acw_tc=61e1bb54-d241-4c5c-a4ff-b4239f92309269b4a1cfb6eaa31701293e5ef508b997;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '26' + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_basic.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_basic.yaml new file mode 100644 index 000000000..c403a5c06 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_basic.yaml @@ -0,0 +1,73 @@ +interactions: +- request: + body: |- + { + "model": "wanx-v1", + "parameters": {}, + "input": { + "prompt": "A mountain landscape" + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '83' + Content-Type: + - application/json + X-DashScope-Async: + - enable + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis + response: + body: + string: |- + { + "request_id": "bf2fdd62-dcc1-439b-afaa-a056505dc5ec", + "output": { + "task_id": "2d6b14cd-956b-47e8-b0b3-0afeb580f5dc", + "task_status": "PENDING" + } + } + headers: + content-length: + - '137' + content-type: + - application/json + date: + - Sun, 07 Dec 2025 11:29:27 GMT + req-arrive-time: + - '1765106967275' + req-cost-time: + - '132' + resp-start-time: + - '1765106967408' + server: + - istio-envoy + set-cookie: + - acw_tc=bf2fdd62-dcc1-439b-afaa-a056505dc5ec4cdc27ec633e66cc8e3c8f520583fc0e;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '124' + x-request-id: + - bf2fdd62-dcc1-439b-afaa-a056505dc5ec + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_basic.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_basic.yaml new file mode 100644 index 000000000..f1fa01c55 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_basic.yaml @@ -0,0 +1,740 @@ +interactions: +- request: + body: |- + { + "model": "wanx-v1", + "parameters": {}, + "input": { + "prompt": "A beautiful sunset over the ocean" + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '96' + Content-Type: + - application/json + X-DashScope-Async: + - enable + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis + response: + body: + string: |- + { + "request_id": "17db92e7-0688-4be2-9b52-39003f55902f", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "PENDING" + } + } + headers: + content-length: + - '137' + content-type: + - application/json + date: + - Sun, 07 Dec 2025 11:24:38 GMT + req-arrive-time: + - '1765106678634' + req-cost-time: + - '131' + resp-start-time: + - '1765106678765' + server: + - istio-envoy + set-cookie: + - acw_tc=17db92e7-0688-4be2-9b52-39003f55902f519f640e549bd6edb32e8865d2075316;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '124' + x-request-id: + - 17db92e7-0688-4be2-9b52-39003f55902f + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "cebc4355-1513-4249-abb1-847b0f4929b2", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:24:38 GMT + req-arrive-time: + - '1765106678864' + req-cost-time: + - '49' + resp-start-time: + - '1765106678913' + server: + - istio-envoy + set-cookie: + - acw_tc=cebc4355-1513-4249-abb1-847b0f4929b2bb1288a1bf246409768d1db861d57c6a;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '40' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "c99cc328-1e08-4ab6-bc6e-c6449a1109d2", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:24:40 GMT + req-arrive-time: + - '1765106680040' + req-cost-time: + - '46' + resp-start-time: + - '1765106680087' + server: + - istio-envoy + set-cookie: + - acw_tc=c99cc328-1e08-4ab6-bc6e-c6449a1109d21ab349448cabbb27c9fe62977a3edfdc;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '39' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "be1d8203-dec1-4033-9f8d-9aa67bc2dd96", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:24:41 GMT + req-arrive-time: + - '1765106681203' + req-cost-time: + - '50' + resp-start-time: + - '1765106681253' + server: + - istio-envoy + set-cookie: + - acw_tc=be1d8203-dec1-4033-9f8d-9aa67bc2dd96a8c26722f177f8736705655f3f2bcbec;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '43' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "d7708baa-71cb-4f11-8d3f-06190de89325", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:24:43 GMT + req-arrive-time: + - '1765106683372' + req-cost-time: + - '41' + resp-start-time: + - '1765106683414' + server: + - istio-envoy + set-cookie: + - acw_tc=d7708baa-71cb-4f11-8d3f-06190de8932585aa8cc6ebae0d492a878d934a0d7457;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '35' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "ca47154a-970e-40ff-bac7-790909a362e2", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:24:45 GMT + req-arrive-time: + - '1765106685517' + req-cost-time: + - '50' + resp-start-time: + - '1765106685567' + server: + - istio-envoy + set-cookie: + - acw_tc=ca47154a-970e-40ff-bac7-790909a362e2a1d9942b18128e5bb509c502766baf76;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '41' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "7de7997e-32e0-4b84-a10e-e1fc3cb1750e", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:24:47 GMT + req-arrive-time: + - '1765106687686' + req-cost-time: + - '46' + resp-start-time: + - '1765106687733' + server: + - istio-envoy + set-cookie: + - acw_tc=7de7997e-32e0-4b84-a10e-e1fc3cb1750ee02cf813a6532246d9bb1b970e4479db;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '40' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "daa90fc3-45bd-4709-9066-02454883c48e", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:24:51 GMT + req-arrive-time: + - '1765106691888' + req-cost-time: + - '46' + resp-start-time: + - '1765106691934' + server: + - istio-envoy + set-cookie: + - acw_tc=daa90fc3-45bd-4709-9066-02454883c48e5196c570e36a124cd5d56b3d513ccc03;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '39' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "29a2daf5-a308-4725-a60c-7b1c4f29b22e", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:24:56 GMT + req-arrive-time: + - '1765106696060' + req-cost-time: + - '53' + resp-start-time: + - '1765106696114' + server: + - istio-envoy + set-cookie: + - acw_tc=29a2daf5-a308-4725-a60c-7b1c4f29b22e35ef49a2ca3c8aa980836e010d98b0a1;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '47' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "197d8722-26d4-49f3-b6fe-d18af99c208e", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:25:00 GMT + req-arrive-time: + - '1765106700222' + req-cost-time: + - '53' + resp-start-time: + - '1765106700276' + server: + - istio-envoy + set-cookie: + - acw_tc=197d8722-26d4-49f3-b6fe-d18af99c208ebcf5e060a90527c28c5e34f0ccb29d98;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '45' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "eff3e6f5-32f2-4115-bfc4-80480f64a3f0", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:25:05 GMT + req-arrive-time: + - '1765106705373' + req-cost-time: + - '48' + resp-start-time: + - '1765106705421' + server: + - istio-envoy + set-cookie: + - acw_tc=eff3e6f5-32f2-4115-bfc4-80480f64a3f0a71c1efa9d6883e2ac27ec9229a81151;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '40' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e + response: + body: + string: |- + { + "request_id": "0bd66a7f-cb69-470c-a261-e61635e130ba", + "output": { + "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", + "task_status": "SUCCEEDED", + "submit_time": "2025-12-07 19:24:38.741", + "scheduled_time": "2025-12-07 19:24:38.774", + "end_time": "2025-12-07 19:25:08.298", + "results": [ + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/39/20251207/c70535fc/e202c746-c4bd-4152-b658-9411aee44b2e-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/a2/20251207/c70535fc/8728ca03-5f52-4302-a981-4c8a0a25d373-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/ad/20251207/c70535fc/40d9085f-8e8d-4b63-a9ec-733c8086684d-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/07/20251207/c70535fc/4a560d3b-73bc-414b-8006-e84adac96d78-1.png" + } + ], + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 4, + "FAILED": 0 + } + }, + "usage": { + "image_count": 4 + } + } + headers: + content-length: + - '1285' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:25:10 GMT + req-arrive-time: + - '1765106710537' + req-cost-time: + - '43' + resp-start-time: + - '1765106710581' + server: + - istio-envoy + set-cookie: + - acw_tc=0bd66a7f-cb69-470c-a261-e61635e130ba1eed509fd7897bc7bc4511b4eb47d2a5;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '37' + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_no_duplicate_spans.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_no_duplicate_spans.yaml new file mode 100644 index 000000000..eb464ed85 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_no_duplicate_spans.yaml @@ -0,0 +1,740 @@ +interactions: +- request: + body: |- + { + "model": "wanx-v1", + "parameters": {}, + "input": { + "prompt": "A test image" + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '75' + Content-Type: + - application/json + X-DashScope-Async: + - enable + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis + response: + body: + string: |- + { + "request_id": "00998cbb-2fe2-4605-b2f0-25dc5fd8e724", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "PENDING" + } + } + headers: + content-length: + - '137' + content-type: + - application/json + date: + - Sun, 07 Dec 2025 11:30:30 GMT + req-arrive-time: + - '1765107030753' + req-cost-time: + - '133' + resp-start-time: + - '1765107030886' + server: + - istio-envoy + set-cookie: + - acw_tc=00998cbb-2fe2-4605-b2f0-25dc5fd8e724852bd169ba779b424cca163f6e31dd4c;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '125' + x-request-id: + - 00998cbb-2fe2-4605-b2f0-25dc5fd8e724 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "efb7367c-35ab-4976-be6c-eff0d7dba67e", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:31 GMT + req-arrive-time: + - '1765107030990' + req-cost-time: + - '59' + resp-start-time: + - '1765107031049' + server: + - istio-envoy + set-cookie: + - acw_tc=efb7367c-35ab-4976-be6c-eff0d7dba67e325063a7b18c60ff95e9240a5c48f8fa;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '50' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "bf29ec08-604d-4596-81e2-1307de5da00f", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:32 GMT + req-arrive-time: + - '1765107032153' + req-cost-time: + - '50' + resp-start-time: + - '1765107032203' + server: + - istio-envoy + set-cookie: + - acw_tc=bf29ec08-604d-4596-81e2-1307de5da00f496e62da45205673ce9087259b10960c;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '43' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "26364d32-fe57-42ba-9d98-6dbcd86c2886", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:33 GMT + req-arrive-time: + - '1765107033312' + req-cost-time: + - '45' + resp-start-time: + - '1765107033358' + server: + - istio-envoy + set-cookie: + - acw_tc=26364d32-fe57-42ba-9d98-6dbcd86c2886679915233dc7cb23505dca1cc5fb58fd;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '39' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "9232d132-6c93-425c-bd72-b5055e88d794", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:35 GMT + req-arrive-time: + - '1765107035474' + req-cost-time: + - '43' + resp-start-time: + - '1765107035517' + server: + - istio-envoy + set-cookie: + - acw_tc=9232d132-6c93-425c-bd72-b5055e88d79456873d094bd70d5c4b2557ffc79d5a61;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '33' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "2a47a4e8-fff4-42c9-9b91-f3314920b9b1", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:37 GMT + req-arrive-time: + - '1765107037637' + req-cost-time: + - '50' + resp-start-time: + - '1765107037688' + server: + - istio-envoy + set-cookie: + - acw_tc=2a47a4e8-fff4-42c9-9b91-f3314920b9b163db2ccdfea00a2b437b2109afd719fe;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '42' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "63c1528c-310a-4432-b18f-b6661d632481", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:39 GMT + req-arrive-time: + - '1765107039798' + req-cost-time: + - '46' + resp-start-time: + - '1765107039845' + server: + - istio-envoy + set-cookie: + - acw_tc=63c1528c-310a-4432-b18f-b6661d632481ed90b81cbb28724da9d071eed2aa5246;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '43' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "8764cf7f-0221-45d2-bad4-233797764fc6", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:44 GMT + req-arrive-time: + - '1765107043950' + req-cost-time: + - '51' + resp-start-time: + - '1765107044002' + server: + - istio-envoy + set-cookie: + - acw_tc=8764cf7f-0221-45d2-bad4-233797764fc657e2a15a885d1e614f2f9930f335fb24;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '43' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "1298340b-1fe3-4ba1-98c5-361bfaa2ae28", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:48 GMT + req-arrive-time: + - '1765107048114' + req-cost-time: + - '42' + resp-start-time: + - '1765107048157' + server: + - istio-envoy + set-cookie: + - acw_tc=1298340b-1fe3-4ba1-98c5-361bfaa2ae28c3b8a38361d24bd395be9a30bde48414;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '34' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "5be3c0f1-cda3-4eb4-a2fd-100609a6919a", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:52 GMT + req-arrive-time: + - '1765107052291' + req-cost-time: + - '51' + resp-start-time: + - '1765107052343' + server: + - istio-envoy + set-cookie: + - acw_tc=5be3c0f1-cda3-4eb4-a2fd-100609a6919a9bd61b4e6d6e1c55a5502d133fdb6076;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '47' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "5801e7ab-2e42-4177-a70d-d8c3c04d96ad", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:57 GMT + req-arrive-time: + - '1765107057457' + req-cost-time: + - '42' + resp-start-time: + - '1765107057500' + server: + - istio-envoy + set-cookie: + - acw_tc=5801e7ab-2e42-4177-a70d-d8c3c04d96ad012bc92a8fa4e9a8f7fdd2fa8d863c4d;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '35' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f + response: + body: + string: |- + { + "request_id": "68736abf-6196-4cbf-8b19-93f13870280a", + "output": { + "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", + "task_status": "SUCCEEDED", + "submit_time": "2025-12-07 19:30:30.868", + "scheduled_time": "2025-12-07 19:30:30.895", + "end_time": "2025-12-07 19:30:59.383", + "results": [ + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/9b/20251207/c70535fc/bfd14230-a96e-49d0-999a-5f559c42faac-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/be/20251207/c70535fc/8ebbfca1-5710-40c7-b0c0-b373cf1c3971-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/57/20251207/c70535fc/75fe6abf-7214-452f-922c-b49f6b45e539-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/8b/20251207/c70535fc/dcfb1dcd-93c4-4aed-a7ad-3971f83ae548-1.png" + } + ], + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 4, + "FAILED": 0 + } + }, + "usage": { + "image_count": 4 + } + } + headers: + content-length: + - '1289' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:31:02 GMT + req-arrive-time: + - '1765107062624' + req-cost-time: + - '43' + resp-start-time: + - '1765107062667' + server: + - istio-envoy + set-cookie: + - acw_tc=68736abf-6196-4cbf-8b19-93f13870280a89f67e586a5f92c58bd5767293eb482a;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '36' + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml new file mode 100644 index 000000000..210908343 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml @@ -0,0 +1,738 @@ +interactions: +- request: + body: |- + { + "model": "wanx-v1", + "parameters": { + "n": 2, + "size": "1024*1024" + }, + "input": { + "prompt": "A cat sitting on a windowsill", + "negative_prompt": "blurry, low quality" + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '161' + Content-Type: + - application/json + X-DashScope-Async: + - enable + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis + response: + body: + string: |- + { + "request_id": "9cddf306-a08a-447e-900c-7622c1edc843", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "PENDING" + } + } + headers: + content-length: + - '137' + content-type: + - application/json + date: + - Sun, 07 Dec 2025 11:28:55 GMT + req-arrive-time: + - '1765106935225' + req-cost-time: + - '121' + resp-start-time: + - '1765106935346' + server: + - istio-envoy + set-cookie: + - acw_tc=9cddf306-a08a-447e-900c-7622c1edc8437072f536b981cbd1d4a65937fb8dced9;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '114' + x-request-id: + - 9cddf306-a08a-447e-900c-7622c1edc843 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "1b735bb9-763a-44ba-aeca-7d0a4d923083", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:28:55 GMT + req-arrive-time: + - '1765106935463' + req-cost-time: + - '56' + resp-start-time: + - '1765106935520' + server: + - istio-envoy + set-cookie: + - acw_tc=1b735bb9-763a-44ba-aeca-7d0a4d923083b60ccc5d65b873c0f6b18375417da088;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '48' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "09c6525b-f9fb-452e-9b3f-2346eaf25daf", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:28:56 GMT + req-arrive-time: + - '1765106936623' + req-cost-time: + - '49' + resp-start-time: + - '1765106936672' + server: + - istio-envoy + set-cookie: + - acw_tc=09c6525b-f9fb-452e-9b3f-2346eaf25daff3d1e10067e3e1242eb95a8f7d48c719;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '32' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "e033d8cd-785f-46f8-81f2-d281b8eee831", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:28:57 GMT + req-arrive-time: + - '1765106937774' + req-cost-time: + - '43' + resp-start-time: + - '1765106937818' + server: + - istio-envoy + set-cookie: + - acw_tc=e033d8cd-785f-46f8-81f2-d281b8eee831c9024b8462e6fa6f33e5f39d9e5c60cd;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '35' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "03154871-c1dd-49f5-9f40-6aa75bb1c667", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:28:59 GMT + req-arrive-time: + - '1765106939937' + req-cost-time: + - '58' + resp-start-time: + - '1765106939996' + server: + - istio-envoy + set-cookie: + - acw_tc=03154871-c1dd-49f5-9f40-6aa75bb1c667ff0ca143ceb206fbe220aa4653602fe6;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '49' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "d0dc1956-01d5-40ab-9925-73ca798eb4a8", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:02 GMT + req-arrive-time: + - '1765106942113' + req-cost-time: + - '45' + resp-start-time: + - '1765106942158' + server: + - istio-envoy + set-cookie: + - acw_tc=d0dc1956-01d5-40ab-9925-73ca798eb4a8f039e19e88232e2941220df7bb6366b6;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '37' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "1e068629-ee74-465b-a878-815f7e6e47be", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:04 GMT + req-arrive-time: + - '1765106944264' + req-cost-time: + - '50' + resp-start-time: + - '1765106944315' + server: + - istio-envoy + set-cookie: + - acw_tc=1e068629-ee74-465b-a878-815f7e6e47beb0f90332e05221ee7927d67ad4c88472;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '43' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "fd9dce87-424d-44b4-b07d-9ecf86fa425e", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:08 GMT + req-arrive-time: + - '1765106948430' + req-cost-time: + - '46' + resp-start-time: + - '1765106948476' + server: + - istio-envoy + set-cookie: + - acw_tc=fd9dce87-424d-44b4-b07d-9ecf86fa425e8319491a1488238de95afcbd1808d148;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '39' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "c237203a-0477-4f14-be72-be8bee5e6739", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:12 GMT + req-arrive-time: + - '1765106952622' + req-cost-time: + - '48' + resp-start-time: + - '1765106952670' + server: + - istio-envoy + set-cookie: + - acw_tc=c237203a-0477-4f14-be72-be8bee5e6739c5a95afd8428ed0850da87d909225c30;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '41' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "31748f34-b548-4d37-83e7-6b19f88b3b1c", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:16 GMT + req-arrive-time: + - '1765106956787' + req-cost-time: + - '47' + resp-start-time: + - '1765106956835' + server: + - istio-envoy + set-cookie: + - acw_tc=31748f34-b548-4d37-83e7-6b19f88b3b1cdf40cdae0347b4151324b7e3d1d97a91;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '40' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "4c3744d3-8294-40c1-a976-d388f90bad8e", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 1, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:21 GMT + req-arrive-time: + - '1765106961946' + req-cost-time: + - '43' + resp-start-time: + - '1765106961990' + server: + - istio-envoy + set-cookie: + - acw_tc=4c3744d3-8294-40c1-a976-d388f90bad8e1fa9401de66f0853e815d36cdc92abba;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '37' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 + response: + body: + string: |- + { + "request_id": "4faceb96-97a5-40d2-8620-2b32aaffa2a1", + "output": { + "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", + "task_status": "SUCCEEDED", + "submit_time": "2025-12-07 19:28:55.323", + "scheduled_time": "2025-12-07 19:28:55.359", + "end_time": "2025-12-07 19:29:22.754", + "results": [ + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/63/20251207/c70535fc/2fe0bf72-b5d9-4bfd-8eeb-f19e5bfc1bcd-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/d5/20251207/c70535fc/3c486265-854d-4b0e-8dbe-8148f0621274-1.png" + } + ], + "task_metrics": { + "TOTAL": 2, + "SUCCEEDED": 2, + "FAILED": 0 + } + }, + "usage": { + "image_count": 2 + } + } + headers: + content-length: + - '821' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:27 GMT + req-arrive-time: + - '1765106967102' + req-cost-time: + - '41' + resp-start-time: + - '1765106967144' + server: + - istio-envoy + set-cookie: + - acw_tc=4faceb96-97a5-40d2-8620-2b32aaffa2a1739636d6f2ea97299fea5513f552a91c;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '35' + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml new file mode 100644 index 000000000..2f843b8b9 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml @@ -0,0 +1,1084 @@ +interactions: +- request: + body: |- + { + "model": "wanx-v1", + "parameters": {}, + "input": { + "prompt": "A forest scene" + } + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '77' + Content-Type: + - application/json + X-DashScope-Async: + - enable + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis + response: + body: + string: |- + { + "request_id": "70bd308a-7a2c-413d-94c4-4ddbe7c192ae", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING" + } + } + headers: + content-length: + - '137' + content-type: + - application/json + date: + - Sun, 07 Dec 2025 11:29:27 GMT + req-arrive-time: + - '1765106967520' + req-cost-time: + - '132' + resp-start-time: + - '1765106967652' + server: + - istio-envoy + set-cookie: + - acw_tc=70bd308a-7a2c-413d-94c4-4ddbe7c192ae09fbf75bc1854f52d3e6efceee7b92bb;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '125' + x-request-id: + - 70bd308a-7a2c-413d-94c4-4ddbe7c192ae + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "175a5591-af0c-4030-b126-b7396a3b4a21", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:29:27.629", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '229' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:27 GMT + req-arrive-time: + - '1765106967817' + req-cost-time: + - '51' + resp-start-time: + - '1765106967868' + server: + - istio-envoy + set-cookie: + - acw_tc=175a5591-af0c-4030-b126-b7396a3b4a21e0972bc9c24702f2001accff5a326c22;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '44' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "99a9030b-ad71-4735-8af3-def55bf563ef", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:29:27.629", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '229' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:29 GMT + req-arrive-time: + - '1765106968986' + req-cost-time: + - '52' + resp-start-time: + - '1765106969038' + server: + - istio-envoy + set-cookie: + - acw_tc=99a9030b-ad71-4735-8af3-def55bf563ef3ea8cc71a468d8cb6082af15094b10ba;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '45' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "7917603d-cb76-46ac-90a1-baa41e8c16e7", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:29:27.629", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '229' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:30 GMT + req-arrive-time: + - '1765106970144' + req-cost-time: + - '50' + resp-start-time: + - '1765106970195' + server: + - istio-envoy + set-cookie: + - acw_tc=7917603d-cb76-46ac-90a1-baa41e8c16e791616d285ba2dc778d21b1af94c687b6;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '44' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "19a86183-0f26-4c04-ab53-afcac48d93d2", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:29:27.629", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '229' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:32 GMT + req-arrive-time: + - '1765106972319' + req-cost-time: + - '41' + resp-start-time: + - '1765106972361' + server: + - istio-envoy + set-cookie: + - acw_tc=19a86183-0f26-4c04-ab53-afcac48d93d27a44d99aaa70d2888b432c2dfdfc55dd;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '33' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "6aec9fa2-722f-480d-bdfd-e2c818802725", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:29:27.629", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '229' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:34 GMT + req-arrive-time: + - '1765106974467' + req-cost-time: + - '48' + resp-start-time: + - '1765106974516' + server: + - istio-envoy + set-cookie: + - acw_tc=6aec9fa2-722f-480d-bdfd-e2c818802725a6bae32cbd6fc53f3593adc60df7cb46;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '40' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "68740efb-8b57-4d48-87f2-a11f166cf814", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:29:27.629", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '229' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:36 GMT + req-arrive-time: + - '1765106976661' + req-cost-time: + - '58' + resp-start-time: + - '1765106976720' + server: + - istio-envoy + set-cookie: + - acw_tc=68740efb-8b57-4d48-87f2-a11f166cf8147799a2771275a2fbb8190dba0e2ea136;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '53' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "f0fb91c0-cd05-43a4-a3d2-50a2b34cbf4e", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:29:27.629", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '229' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:40 GMT + req-arrive-time: + - '1765106980831' + req-cost-time: + - '61' + resp-start-time: + - '1765106980893' + server: + - istio-envoy + set-cookie: + - acw_tc=f0fb91c0-cd05-43a4-a3d2-50a2b34cbf4e35bd2e45fffa1d16fae03499e5a82c90;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '41' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "dfe240f6-b896-4af1-ae32-d9f445189965", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:29:27.629", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '229' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:45 GMT + req-arrive-time: + - '1765106985016' + req-cost-time: + - '48' + resp-start-time: + - '1765106985065' + server: + - istio-envoy + set-cookie: + - acw_tc=dfe240f6-b896-4af1-ae32-d9f445189965b4ba50c5302fa1c71d0df8d0c9dc16f4;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '42' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "6273c926-02e4-4626-810f-c00f70f1fdf9", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:29:27.629", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '229' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:49 GMT + req-arrive-time: + - '1765106989168' + req-cost-time: + - '38' + resp-start-time: + - '1765106989207' + server: + - istio-envoy + set-cookie: + - acw_tc=6273c926-02e4-4626-810f-c00f70f1fdf9da45a206ba6d8b9e83b9f7971de13c44;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '33' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "247a0c1d-7aac-43d6-91ba-8f239a4f96f6", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "PENDING", + "submit_time": "2025-12-07 19:29:27.629", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '229' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:54 GMT + req-arrive-time: + - '1765106994351' + req-cost-time: + - '39' + resp-start-time: + - '1765106994390' + server: + - istio-envoy + set-cookie: + - acw_tc=247a0c1d-7aac-43d6-91ba-8f239a4f96f68fd4359ca10d046d26da87aa077e2753;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '32' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "8b64ebea-eb40-4659-9839-554ab6fd3b66", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:29:27.629", + "scheduled_time": "2025-12-07 19:29:58.354", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:29:59 GMT + req-arrive-time: + - '1765106999513' + req-cost-time: + - '51' + resp-start-time: + - '1765106999565' + server: + - istio-envoy + set-cookie: + - acw_tc=8b64ebea-eb40-4659-9839-554ab6fd3b66c0359ec13138a0accd1121f378980bb9;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '45' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "52e629ed-57cd-4a11-9c51-84b68710e581", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:29:27.629", + "scheduled_time": "2025-12-07 19:29:58.354", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:04 GMT + req-arrive-time: + - '1765107004674' + req-cost-time: + - '48' + resp-start-time: + - '1765107004722' + server: + - istio-envoy + set-cookie: + - acw_tc=52e629ed-57cd-4a11-9c51-84b68710e581cbb349cb3b6d9d1c615a0857ab61b2c3;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '40' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "280a5b3a-1d43-477a-89f2-56df8313226a", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:29:27.629", + "scheduled_time": "2025-12-07 19:29:58.354", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:09 GMT + req-arrive-time: + - '1765107009906' + req-cost-time: + - '46' + resp-start-time: + - '1765107009953' + server: + - istio-envoy + set-cookie: + - acw_tc=280a5b3a-1d43-477a-89f2-56df8313226aea22fc23459e3094c710b4a080c85eec;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '41' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "c9b54d6b-d8b5-4407-ad17-00a0286a9e75", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:29:27.629", + "scheduled_time": "2025-12-07 19:29:58.354", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:15 GMT + req-arrive-time: + - '1765107015057' + req-cost-time: + - '56' + resp-start-time: + - '1765107015113' + server: + - istio-envoy + set-cookie: + - acw_tc=c9b54d6b-d8b5-4407-ad17-00a0286a9e7537166bd5774a16a8c9a347e9e0da0bc0;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '49' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "d56fb4ce-53bf-4ae6-8bc1-7358b4b084fb", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:29:27.629", + "scheduled_time": "2025-12-07 19:29:58.354", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 0, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:20 GMT + req-arrive-time: + - '1765107020237' + req-cost-time: + - '46' + resp-start-time: + - '1765107020284' + server: + - istio-envoy + set-cookie: + - acw_tc=d56fb4ce-53bf-4ae6-8bc1-7358b4b084fb6fe4e014fce09c0b64450affd5b65a30;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '39' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "3f67f053-447f-4fb9-8f4c-b86520db3937", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "RUNNING", + "submit_time": "2025-12-07 19:29:27.629", + "scheduled_time": "2025-12-07 19:29:58.354", + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 2, + "FAILED": 0 + } + } + } + headers: + content-length: + - '272' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:25 GMT + req-arrive-time: + - '1765107025395' + req-cost-time: + - '42' + resp-start-time: + - '1765107025438' + server: + - istio-envoy + set-cookie: + - acw_tc=3f67f053-447f-4fb9-8f4c-b86520db3937dba674235c43eff41384010bbf35a090;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '37' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + authorization: + - Bearer test_dashscope_api_key + user-agent: + - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm + method: GET + uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c + response: + body: + string: |- + { + "request_id": "fb23ed7d-4a6a-4a67-b2e0-05e1a8023efb", + "output": { + "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", + "task_status": "SUCCEEDED", + "submit_time": "2025-12-07 19:29:27.629", + "scheduled_time": "2025-12-07 19:29:58.354", + "end_time": "2025-12-07 19:30:27.420", + "results": [ + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/e9/20251207/c70535fc/b08c952f-0030-488f-91f6-ee96f6dddfb6-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/11/20251207/c70535fc/c8c6ef00-bbe8-42aa-802c-6262d155d2b2-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/68/20251207/c70535fc/f3f7ddaf-decc-4ee3-88fb-51a1b8295393-1.png" + }, + { + "url": "https://dashscope-result-bj.oss-cn-beijing.aliyuncs.com/1d/0c/20251207/c70535fc/78ddb71f-afab-4147-9322-108045b9b43b-1.png" + } + ], + "task_metrics": { + "TOTAL": 4, + "SUCCEEDED": 4, + "FAILED": 0 + } + }, + "usage": { + "image_count": 4 + } + } + headers: + content-length: + - '1287' + content-type: + - application/json;charset=UTF-8 + date: + - Sun, 07 Dec 2025 11:30:30 GMT + req-arrive-time: + - '1765107030581' + req-cost-time: + - '45' + resp-start-time: + - '1765107030627' + server: + - istio-envoy + set-cookie: + - acw_tc=fb23ed7d-4a6a-4a67-b2e0-05e1a8023efb3f8635949db7b4865758f77b2ab876e5;path=/;HttpOnly;Max-Age=1800 + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-envoy-upstream-service-time: + - '37' + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py new file mode 100644 index 000000000..306e172a1 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py @@ -0,0 +1,474 @@ +"""Tests for ImageSynthesis instrumentation.""" + +import pytest + +from dashscope import ImageSynthesis +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) + + +def _safe_getattr(obj, attr, default=None): + """Safely get attribute from DashScope response objects that may raise KeyError.""" + try: + return getattr(obj, attr, default) + except KeyError: + return default + + +def _assert_image_synthesis_span_attributes( + span, + request_model: str, + response_id: str = None, + response_model: str = None, + input_tokens: int = None, + output_tokens: int = None, + task_id: str = None, + task_status: str = None, + image_url: str = None, + negative_prompt: str = None, + size: str = None, + n: int = None, + expect_input_messages: bool = False, +): + """Assert ImageSynthesis span attributes according to GenAI semantic conventions. + + Args: + span: The span to assert + request_model: Expected model name + response_id: Expected response ID (if available) + response_model: Expected response model name (if available) + input_tokens: Expected input token count (if available) + output_tokens: Expected output token count (if available) + task_id: Expected task ID (if available) + task_status: Expected task status (if available) + image_url: Expected image URL (if available) + negative_prompt: Expected negative prompt (if provided) + size: Expected image size (if provided) + n: Expected number of images (if provided) + expect_input_messages: Whether to expect input messages in span + """ + # Span name format is "{operation_name} {model}" per semantic conventions + # Operation name is "generate_content" + assert span.name == f"generate_content {request_model}" + + # Required attributes + assert ( + GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] + == "generate_content" + ), f"Expected 'generate_content', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + + assert ( + GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_PROVIDER_NAME] == "dashscope" + ) + + assert ( + GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == request_model + ) + + # Optional attributes + if response_model is not None: + assert ( + GenAIAttributes.GEN_AI_RESPONSE_MODEL in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_RESPONSE_MODEL}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_RESPONSE_MODEL] + == response_model + ) + + if response_id is not None: + assert ( + GenAIAttributes.GEN_AI_RESPONSE_ID in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_RESPONSE_ID}" + # response_id may vary between test runs (VCR recordings), so just check it exists + assert span.attributes[GenAIAttributes.GEN_AI_RESPONSE_ID] is not None + + if input_tokens is not None: + assert ( + GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS] + == input_tokens + ) + + if output_tokens is not None: + assert ( + GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS}" + assert ( + span.attributes[GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS] + == output_tokens + ) + + # DashScope-specific attributes + if task_id is not None: + assert ( + "dashscope.task_id" in span.attributes + ), "Missing dashscope.task_id" + assert span.attributes["dashscope.task_id"] == task_id + + if task_status is not None: + assert ( + "dashscope.task_status" in span.attributes + ), "Missing dashscope.task_status" + assert span.attributes["dashscope.task_status"] == task_status + + if image_url is not None: + assert ( + "dashscope.image.url" in span.attributes + ), "Missing dashscope.image.url" + # image_url might be a string or a list representation + span_url = span.attributes["dashscope.image.url"] + if isinstance(span_url, str) and image_url in span_url: + # If it's a list representation, check if image_url is in it + pass + else: + assert span_url == image_url + + if negative_prompt is not None: + assert ( + "dashscope.negative_prompt" in span.attributes + ), "Missing dashscope.negative_prompt" + assert ( + span.attributes["dashscope.negative_prompt"] == negative_prompt + ) + + if size is not None: + assert "dashscope.image.size" in span.attributes, "Missing dashscope.image.size" + assert span.attributes["dashscope.image.size"] == size + + if n is not None: + assert "dashscope.image.n" in span.attributes, "Missing dashscope.image.n" + assert span.attributes["dashscope.image.n"] == n + + # Assert input messages based on expectation + if expect_input_messages: + assert ( + GenAIAttributes.GEN_AI_INPUT_MESSAGES in span.attributes + ), f"Missing {GenAIAttributes.GEN_AI_INPUT_MESSAGES}" + else: + assert ( + GenAIAttributes.GEN_AI_INPUT_MESSAGES not in span.attributes + ), f"{GenAIAttributes.GEN_AI_INPUT_MESSAGES} should not be present" + + +@pytest.mark.vcr() +def test_image_synthesis_call_basic(instrument, span_exporter): + """Test synchronous ImageSynthesis.call can be instrumented.""" + response = ImageSynthesis.call( + model="wanx-v1", + prompt="A beautiful sunset over the ocean", + ) + assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + output = _safe_getattr(response, "output", None) + usage = _safe_getattr(response, "usage", None) + request_id = _safe_getattr(response, "request_id", None) + response_model = _safe_getattr(response, "model", None) + + # Extract task_id and task_status from output + task_id = None + task_status = None + image_url = None + if output: + if hasattr(output, "get"): + task_id = output.get("task_id") + task_status = output.get("task_status") + results = output.get("results") + if results and isinstance(results, list) and len(results) > 0: + first_result = results[0] + if isinstance(first_result, dict): + image_url = first_result.get("url") + elif hasattr(first_result, "url"): + image_url = getattr(first_result, "url", None) + + _assert_image_synthesis_span_attributes( + span, + request_model="wanx-v1", + response_id=request_id, + response_model=response_model, + input_tokens=_safe_getattr(usage, "input_tokens", None) if usage else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) if usage else None, + task_id=task_id, + task_status=task_status, + image_url=image_url, + expect_input_messages=False, # Default: no content capture + ) + + print("✓ ImageSynthesis.call (basic) completed successfully") + + +@pytest.mark.vcr() +def test_image_synthesis_call_with_parameters(instrument, span_exporter): + """Test ImageSynthesis.call with additional parameters.""" + response = ImageSynthesis.call( + model="wanx-v1", + prompt="A cat sitting on a windowsill", + negative_prompt="blurry, low quality", + n=2, + size="1024*1024", + ) + assert response is not None + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + output = _safe_getattr(response, "output", None) + usage = _safe_getattr(response, "usage", None) + request_id = _safe_getattr(response, "request_id", None) + response_model = _safe_getattr(response, "model", None) + + # Extract task_id and task_status from output + task_id = None + task_status = None + image_url = None + if output: + if hasattr(output, "get"): + task_id = output.get("task_id") + task_status = output.get("task_status") + results = output.get("results") + if results and isinstance(results, list) and len(results) > 0: + first_result = results[0] + if isinstance(first_result, dict): + image_url = first_result.get("url") + elif hasattr(first_result, "url"): + image_url = getattr(first_result, "url", None) + + _assert_image_synthesis_span_attributes( + span, + request_model="wanx-v1", + response_id=request_id, + response_model=response_model, + input_tokens=_safe_getattr(usage, "input_tokens", None) if usage else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) if usage else None, + task_id=task_id, + task_status=task_status, + image_url=image_url, + negative_prompt="blurry, low quality", + size="1024*1024", + n=2, + expect_input_messages=False, # Default: no content capture + ) + + print("✓ ImageSynthesis.call (with parameters) completed successfully") + + +@pytest.mark.vcr() +def test_image_synthesis_async_call_basic(instrument, span_exporter): + """Test ImageSynthesis.async_call can be instrumented.""" + response = ImageSynthesis.async_call( + model="wanx-v1", + prompt="A mountain landscape", + ) + assert response is not None + assert hasattr(response, "output") + + # Assert spans + spans = span_exporter.get_finished_spans() + assert len(spans) == 1, f"Expected 1 span, got {len(spans)}" + + span = spans[0] + output = _safe_getattr(response, "output", None) + request_id = _safe_getattr(response, "request_id", None) + response_model = _safe_getattr(response, "model", None) + + # Extract task_id and task_status from output + task_id = None + task_status = None + if output: + if hasattr(output, "get"): + task_id = output.get("task_id") + task_status = output.get("task_status") + + # Check async attribute + assert ( + "gen_ai.request.async" in span.attributes + ), "Missing gen_ai.request.async" + assert span.attributes["gen_ai.request.async"] is True + + _assert_image_synthesis_span_attributes( + span, + request_model="wanx-v1", + response_id=request_id, + response_model=response_model, + task_id=task_id, + task_status=task_status, + expect_input_messages=False, # Default: no content capture + ) + + print("✓ ImageSynthesis.async_call (basic) completed successfully") + + +@pytest.mark.vcr() +def test_image_synthesis_wait_basic(instrument, span_exporter): + """Test ImageSynthesis.wait can be instrumented.""" + # First submit a task + async_response = ImageSynthesis.async_call( + model="wanx-v1", + prompt="A forest scene", + ) + assert async_response is not None + + # Then wait for completion + response = ImageSynthesis.wait(async_response) + assert response is not None + + # Assert spans (should have 2: one for async_call, one for wait) + spans = span_exporter.get_finished_spans() + assert len(spans) == 2, f"Expected 2 spans, got {len(spans)}" + + # Find wait span (should have dashscope.operation = "wait") + wait_span = None + for span in spans: + if span.attributes.get("dashscope.operation") == "wait": + wait_span = span + break + + assert wait_span is not None, "Wait span not found" + + output = _safe_getattr(response, "output", None) + usage = _safe_getattr(response, "usage", None) + request_id = _safe_getattr(response, "request_id", None) + response_model = _safe_getattr(response, "model", None) + + # Extract task_id and task_status from output + task_id = None + task_status = None + image_url = None + if output: + if hasattr(output, "get"): + task_id = output.get("task_id") + task_status = output.get("task_status") + results = output.get("results") + if results and isinstance(results, list) and len(results) > 0: + first_result = results[0] + if isinstance(first_result, dict): + image_url = first_result.get("url") + elif hasattr(first_result, "url"): + image_url = getattr(first_result, "url", None) + + # Check async attribute + assert ( + "gen_ai.request.async" in wait_span.attributes + ), "Missing gen_ai.request.async" + assert wait_span.attributes["gen_ai.request.async"] is True + + # Wait span should have request_model="unknown" (we don't know model in wait phase) + # But we can check task_id and operation + assert ( + wait_span.attributes.get("dashscope.operation") == "wait" + ), "Missing dashscope.operation=wait" + + _assert_image_synthesis_span_attributes( + wait_span, + request_model="unknown", # Wait phase doesn't know model + response_id=request_id, + response_model=response_model, + input_tokens=_safe_getattr(usage, "input_tokens", None) if usage else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) if usage else None, + task_id=task_id, + task_status=task_status, + image_url=image_url, + expect_input_messages=False, # Default: no content capture + ) + + print("✓ ImageSynthesis.wait (basic) completed successfully") + + +@pytest.mark.vcr() +def test_image_synthesis_call_no_duplicate_spans(instrument, span_exporter): + """Test that call() does not create duplicate spans.""" + response = ImageSynthesis.call( + model="wanx-v1", + prompt="A test image", + ) + assert response is not None + + # Assert only 1 span is created (not 3: call, async_call, wait) + spans = span_exporter.get_finished_spans() + image_synthesis_spans = [ + span + for span in spans + if span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME) + == "generate_content" + ] + assert ( + len(image_synthesis_spans) == 1 + ), f"Expected 1 span, got {len(image_synthesis_spans)}. Spans: {[span.name for span in image_synthesis_spans]}" + + print("✓ ImageSynthesis.call does not create duplicate spans") + + +@pytest.mark.vcr() +def test_image_synthesis_async_call_and_wait_separate_spans( + instrument, span_exporter +): + """Test that async_call and wait create separate spans.""" + # Submit task + async_response = ImageSynthesis.async_call( + model="wanx-v1", + prompt="A test image for async", + ) + assert async_response is not None + + # Check spans after async_call (should have 1 span) + spans_after_async = span_exporter.get_finished_spans() + async_spans = [ + span + for span in spans_after_async + if span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME) + == "generate_content" + and span.attributes.get("gen_ai.request.async") is True + and span.attributes.get("dashscope.operation") != "wait" + ] + assert ( + len(async_spans) == 1 + ), f"Expected 1 span after async_call, got {len(async_spans)}" + + # Wait for completion + response = ImageSynthesis.wait(async_response) + assert response is not None + + # Check spans after wait (should have 2 spans: async_call + wait) + spans_after_wait = span_exporter.get_finished_spans() + wait_spans = [ + span + for span in spans_after_wait + if span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME) + == "generate_content" + ] + assert ( + len(wait_spans) == 2 + ), f"Expected 2 spans after wait, got {len(wait_spans)}. Spans: {[span.name for span in wait_spans]}" + + # Verify one span is for async_call and one is for wait + async_span = None + wait_span = None + for span in wait_spans: + if span.attributes.get("dashscope.operation") == "wait": + wait_span = span + else: + async_span = span + + assert async_span is not None, "Async span not found" + assert wait_span is not None, "Wait span not found" + + print("✓ ImageSynthesis.async_call and wait create separate spans") + diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py index 0725fe090..8fdc67eda 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py @@ -139,9 +139,16 @@ def start_llm( invocation: LLMInvocation, ) -> LLMInvocation: """Start an LLM invocation and create a pending span entry.""" + # Check if custom operation name is set in invocation.attributes + # This allows instrumentation to override the default "chat" operation name + operation_name = invocation.attributes.get("gen_ai.operation.name") + if operation_name: + span_name = f"{operation_name} {invocation.request_model}" + else: + span_name = f"{GenAI.GenAiOperationNameValues.CHAT.value} {invocation.request_model}" # Create a span and attach it as current; keep the token to detach later span = self._tracer.start_span( - name=f"{GenAI.GenAiOperationNameValues.CHAT.value} {invocation.request_model}", + name=span_name, kind=SpanKind.CLIENT, ) # Record a monotonic start timestamp (seconds) for duration From c7f60fab82f3bcf643bfbdfcc5947a9a017529f3 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Fri, 12 Dec 2025 20:44:05 +0800 Subject: [PATCH 5/9] Capture genai operations with genai-util Change-Id: If077c31ec7bfc6e93e57e38ec73346bff89e7943 Co-developed-by: Cursor --- .../instrumentation/dashscope/__init__.py | 4 +- .../instrumentation/dashscope/patch.py | 169 ++-- .../instrumentation/dashscope/utils.py | 10 +- ...is_async_call_and_wait_separate_spans.yaml | 478 +--------- .../test_image_synthesis_call_basic.yaml | 472 ---------- ...age_synthesis_call_no_duplicate_spans.yaml | 475 +--------- ..._image_synthesis_call_with_parameters.yaml | 478 +--------- .../test_image_synthesis_wait_basic.yaml | 841 +----------------- .../tests/conftest.py | 17 +- .../tests/test_rerank.py | 5 +- .../util/genai/extended_span_utils.py | 4 +- .../src/opentelemetry/util/genai/handler.py | 12 +- .../opentelemetry/util/genai/span_utils.py | 2 +- .../src/opentelemetry/util/genai/types.py | 6 + .../tests/test_extended_handler.py | 4 +- 15 files changed, 109 insertions(+), 2868 deletions(-) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py index be62bd431..c12b84127 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py @@ -114,10 +114,10 @@ def wrap_generation_call_with_provider( wrapped, instance, args, kwargs, handler=handler ) - def wrap_aio_generation_call_with_provider( + async def wrap_aio_generation_call_with_provider( wrapped, instance, args, kwargs ): - return wrap_aio_generation_call( + return await wrap_aio_generation_call( wrapped, instance, args, kwargs, handler=handler ) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py index 0938f472a..dfe11cfe1 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py @@ -17,14 +17,14 @@ import inspect import logging -from opentelemetry import context, trace -from opentelemetry.semconv._incubating.attributes import ( - gen_ai_attributes as GenAIAttributes, -) +from opentelemetry import context from opentelemetry.util.genai.extended_types import ( EmbeddingInvocation, RerankInvocation, ) +from opentelemetry.util.genai._extended_semconv.gen_ai_extended_attributes import ( + GenAiExtendedProviderNameValues as GenAI +) from opentelemetry.util.genai.types import Error from .utils import ( @@ -108,7 +108,7 @@ def wrap_generation_call(wrapped, instance, args, kwargs, handler=None): return wrapped(*args, **kwargs) -def wrap_aio_generation_call(wrapped, instance, args, kwargs, handler=None): +async def wrap_aio_generation_call(wrapped, instance, args, kwargs, handler=None): """Wrapper for AioGeneration.call (async). Uses TelemetryHandler from opentelemetry-util-genai to manage span lifecycle. @@ -120,59 +120,55 @@ def wrap_aio_generation_call(wrapped, instance, args, kwargs, handler=None): kwargs: Keyword arguments handler: ExtendedTelemetryHandler instance (created during instrumentation) """ + # Extract model from kwargs + model = kwargs.get("model") + if not model: + logger.warning( + "Model not found in kwargs, skipping instrumentation" + ) + return await wrapped(*args, **kwargs) - async def async_wrapper(): - # Extract model from kwargs - model = kwargs.get("model") - if not model: - logger.warning( - "Model not found in kwargs, skipping instrumentation" - ) - return await wrapped(*args, **kwargs) + if handler is None: + logger.warning("Handler not provided, skipping instrumentation") + return await wrapped(*args, **kwargs) + + try: + # Create invocation object + invocation = _create_invocation_from_generation(kwargs, model) - if handler is None: - logger.warning("Handler not provided, skipping instrumentation") - return await wrapped(*args, **kwargs) + # Start LLM invocation (creates span) + handler.start_llm(invocation) try: - # Create invocation object - invocation = _create_invocation_from_generation(kwargs, model) - - # Start LLM invocation (creates span) - handler.start_llm(invocation) - - try: - # Execute the wrapped call - result = await wrapped(*args, **kwargs) - - # Handle streaming response - if _is_streaming_response(result): - # Check incremental_output parameter (default is False, meaning full output) - incremental_output = _get_parameter( - kwargs, "incremental_output" - ) - return _wrap_async_generator( - result, - handler, - invocation, - incremental_output=incremental_output, - ) - - # Handle non-streaming response - _update_invocation_from_response(invocation, result) - handler.stop_llm(invocation) - return result - - except Exception as e: - error = Error(message=str(e), type=type(e)) - handler.fail_llm(invocation, error) - raise + # Execute the wrapped call + result = await wrapped(*args, **kwargs) + + # Handle streaming response + if _is_streaming_response(result): + # Check incremental_output parameter (default is False, meaning full output) + incremental_output = _get_parameter( + kwargs, "incremental_output" + ) + return _wrap_async_generator( + result, + handler, + invocation, + incremental_output=incremental_output, + ) + + # Handle non-streaming response + _update_invocation_from_response(invocation, result) + handler.stop_llm(invocation) + return result except Exception as e: - logger.exception("Error in async instrumentation wrapper: %s", e) - return await wrapped(*args, **kwargs) + error = Error(message=str(e), type=type(e)) + handler.fail_llm(invocation, error) + raise - return async_wrapper() + except Exception as e: + logger.exception("Error in async instrumentation wrapper: %s", e) + return await wrapped(*args, **kwargs) def wrap_text_embedding_call(wrapped, instance, args, kwargs, handler=None): @@ -274,7 +270,7 @@ def wrap_text_rerank_call(wrapped, instance, args, kwargs, handler=None): try: # Create rerank invocation object - invocation = RerankInvocation(request_model=model) + invocation = RerankInvocation(provider=GenAI.DASHSCOPE.value, request_model=model) invocation.provider = "dashscope" # Start rerank invocation (creates span) @@ -444,18 +440,6 @@ def wrap_image_synthesis_call(wrapped, instance, args, kwargs, handler=None): _update_invocation_from_image_synthesis_response(invocation, result) handler.stop_llm(invocation) - # Manually update span name and operation name after stop_llm - # because _apply_common_span_attributes hardcodes "chat" - if invocation.span and invocation.span.is_recording(): - operation_name = invocation.attributes.get("gen_ai.operation.name") - if operation_name: - invocation.span.update_name( - f"{operation_name} {invocation.request_model}" - ) - invocation.span.set_attribute( - GenAIAttributes.GEN_AI_OPERATION_NAME, operation_name - ) - return result except Exception as e: @@ -479,7 +463,6 @@ def wrap_image_synthesis_async_call( This wrapper tracks the task submission phase. If called within call() context, skips span creation. - Stores span context in response object for span linking with wait(). Args: wrapped: The original function being wrapped @@ -527,15 +510,9 @@ def wrap_image_synthesis_async_call( invocation.attributes["gen_ai.response.id"] = task_id invocation.attributes["dashscope.task_id"] = task_id - # Get current span context and store in response object for span linking - current_span = trace.get_current_span() - if current_span and current_span.is_recording(): - span_context = current_span.get_span_context() - # Store span context in response object - if hasattr(result, "__dict__"): - result.__dict__["_otel_span_context"] = span_context - elif hasattr(result, "_otel_span_context"): - result._otel_span_context = span_context + # Note: Span linking is not currently supported by ExtendedTelemetryHandler. + # If span linking is needed in the future, it should be implemented in the handler. + # For now, we skip storing span context for linking. # Update invocation with async response data (task_id, task_status) _update_invocation_from_image_synthesis_async_response( @@ -559,7 +536,6 @@ def wrap_image_synthesis_wait(wrapped, instance, args, kwargs, handler=None): This wrapper tracks the task waiting and result retrieval phase. If called within call() context, skips span creation. - Attempts to get span context from response object for span linking. Args: wrapped: The original function being wrapped @@ -586,44 +562,23 @@ def wrap_image_synthesis_wait(wrapped, instance, args, kwargs, handler=None): # If cannot extract task_id, skip instrumentation return wrapped(*args, **kwargs) - # Try to get span context from response object for span linking - span_context = None - if task: - try: - # DashScope response objects use __getattr__ which raises KeyError - # Use getattr with default to safely check - if hasattr(task, "__dict__") and "_otel_span_context" in task.__dict__: - span_context = task.__dict__["_otel_span_context"] - elif hasattr(task, "_otel_span_context"): - # Try to get it, but catch KeyError if it doesn't exist - try: - span_context = getattr(task, "_otel_span_context", None) - except KeyError: - pass - except (KeyError, AttributeError): - pass + # Note: Span linking is not currently supported by ExtendedTelemetryHandler. + # If span linking is needed in the future, it should be implemented in the handler. # Create invocation object (wait phase doesn't know model, use "unknown") invocation = _create_invocation_from_image_synthesis({}, "unknown") - invocation.attributes["gen_ai.operation.name"] = "generate_content" + invocation.operation_name = "generate_content" invocation.attributes["gen_ai.request.async"] = True invocation.attributes["gen_ai.response.id"] = task_id invocation.attributes["dashscope.task_id"] = task_id invocation.attributes["dashscope.operation"] = "wait" - # Store span context for potential linking (if ExtendedTelemetryHandler supports it) - # Note: We don't store span_context in attributes as it's not a valid attribute type - # Span linking would need to be implemented differently if ExtendedTelemetryHandler supports it + # Note: Span linking is not currently supported by ExtendedTelemetryHandler. + # If span linking is needed in the future, it should be implemented in the handler. # Start LLM invocation (creates span) handler.start_llm(invocation) - # TODO: If ExtendedTelemetryHandler supports, add span link after span creation - # current_span = trace.get_current_span() - # if current_span and current_span.is_recording() and span_context: - # link = trace.Link(span_context) - # # Add link to span - try: # Execute the wrapped call (wait for task completion) result = wrapped(*args, **kwargs) @@ -632,18 +587,6 @@ def wrap_image_synthesis_wait(wrapped, instance, args, kwargs, handler=None): _update_invocation_from_image_synthesis_response(invocation, result) handler.stop_llm(invocation) - # Manually update span name and operation name after stop_llm - # because _apply_common_span_attributes hardcodes "chat" - if invocation.span and invocation.span.is_recording(): - operation_name = invocation.attributes.get("gen_ai.operation.name") - if operation_name: - invocation.span.update_name( - f"{operation_name} {invocation.request_model}" - ) - invocation.span.set_attribute( - GenAIAttributes.GEN_AI_OPERATION_NAME, operation_name - ) - return result except Exception as e: diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py index b1af2071a..7d99cceae 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py @@ -25,7 +25,7 @@ Text, ToolCall, ToolCallResponse, - ToolDefinitions, + ToolDefinition, ) @@ -235,7 +235,7 @@ def _extract_input_messages(kwargs: dict) -> List[InputMessage]: return input_messages -def _extract_tool_definitions(kwargs: dict) -> ToolDefinitions: +def _extract_tool_definitions(kwargs: dict) -> list[ToolDefinition]: """Extract tool definitions from DashScope API kwargs and convert to FunctionToolDefinition objects. DashScope supports both `tools` and `plugins` parameters for tool definitions. @@ -248,7 +248,7 @@ def _extract_tool_definitions(kwargs: dict) -> ToolDefinitions: Returns: List of FunctionToolDefinition objects, or empty list if not found """ - tool_definitions: ToolDefinitions = [] + tool_definitions: list[ToolDefinition] = [] # Check for tools parameter first (preferred) tools = kwargs.get("tools") @@ -288,7 +288,6 @@ def _extract_tool_definitions(kwargs: dict) -> ToolDefinitions: name=function.get("name", ""), description=function.get("description"), parameters=function.get("parameters"), - response=function.get("response"), type="function", ) tool_definitions.append(tool_def) @@ -298,7 +297,6 @@ def _extract_tool_definitions(kwargs: dict) -> ToolDefinitions: name=tool.get("name", ""), description=tool.get("description"), parameters=tool.get("parameters"), - response=tool.get("response"), type="function", ) tool_definitions.append(tool_def) @@ -717,7 +715,7 @@ def _create_invocation_from_image_synthesis( invocation = LLMInvocation(request_model=request_model) invocation.provider = "dashscope" - invocation.attributes["gen_ai.operation.name"] = "generate_content" + invocation.operation_name = "generate_content" # Extract prompt as input message prompt = kwargs.get("prompt") diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml index c3889a373..d1251048e 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml @@ -1,6 +1,5 @@ interactions: -- request: - body: |- +body: |- { "model": "wanx-v1", "parameters": {}, @@ -70,6 +69,7 @@ interactions: status: code: 200 message: OK + - request: body: null headers: @@ -129,6 +129,7 @@ interactions: status: code: 200 message: OK + - request: body: null headers: @@ -188,478 +189,7 @@ interactions: status: code: 200 message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed - response: - body: - string: |- - { - "request_id": "f98cb6c2-ccb1-48e7-878e-001ede225ab2", - "output": { - "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:31:02.915", - "scheduled_time": "2025-12-07 19:31:02.961", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:31:05 GMT - req-arrive-time: - - '1765107065345' - req-cost-time: - - '49' - resp-start-time: - - '1765107065395' - server: - - istio-envoy - set-cookie: - - acw_tc=f98cb6c2-ccb1-48e7-878e-001ede225ab282065eed3e3cf81d55d99590c8b5d6a9;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '42' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed - response: - body: - string: |- - { - "request_id": "a4da8bec-4e89-4949-93d6-5853af926886", - "output": { - "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:31:02.915", - "scheduled_time": "2025-12-07 19:31:02.961", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:31:07 GMT - req-arrive-time: - - '1765107067505' - req-cost-time: - - '62' - resp-start-time: - - '1765107067567' - server: - - istio-envoy - set-cookie: - - acw_tc=a4da8bec-4e89-4949-93d6-5853af926886bc68efbde583dac4378c55c6d97d22d7;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '54' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed - response: - body: - string: |- - { - "request_id": "af3cdc45-1970-4e2a-9721-9cae4364b25e", - "output": { - "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:31:02.915", - "scheduled_time": "2025-12-07 19:31:02.961", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:31:09 GMT - req-arrive-time: - - '1765107069702' - req-cost-time: - - '49' - resp-start-time: - - '1765107069751' - server: - - istio-envoy - set-cookie: - - acw_tc=af3cdc45-1970-4e2a-9721-9cae4364b25e6ebf92b34be7623e076a926faf2502bf;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '40' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed - response: - body: - string: |- - { - "request_id": "927fc47f-c8c4-48dc-b7db-9e14d5955c67", - "output": { - "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:31:02.915", - "scheduled_time": "2025-12-07 19:31:02.961", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:31:11 GMT - req-arrive-time: - - '1765107071887' - req-cost-time: - - '49' - resp-start-time: - - '1765107071936' - server: - - istio-envoy - set-cookie: - - acw_tc=927fc47f-c8c4-48dc-b7db-9e14d5955c6783a9be1204c40a04adea57fd1616e5e2;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '42' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed - response: - body: - string: |- - { - "request_id": "37f4d664-fbf1-4322-be4f-b428c4b62826", - "output": { - "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:31:02.915", - "scheduled_time": "2025-12-07 19:31:02.961", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:31:16 GMT - req-arrive-time: - - '1765107076040' - req-cost-time: - - '53' - resp-start-time: - - '1765107076094' - server: - - istio-envoy - set-cookie: - - acw_tc=37f4d664-fbf1-4322-be4f-b428c4b62826ed27e659ae5411e494f7707f9e6367bf;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '46' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed - response: - body: - string: |- - { - "request_id": "a5a15dfe-3bcf-4e42-a3c6-36a564c2f51c", - "output": { - "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:31:02.915", - "scheduled_time": "2025-12-07 19:31:02.961", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:31:20 GMT - req-arrive-time: - - '1765107080202' - req-cost-time: - - '47' - resp-start-time: - - '1765107080250' - server: - - istio-envoy - set-cookie: - - acw_tc=a5a15dfe-3bcf-4e42-a3c6-36a564c2f51cadfab69447927bc9728a5f67c5048056;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '40' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed - response: - body: - string: |- - { - "request_id": "4999648b-824a-4c5e-b204-4bc2fc49ef7c", - "output": { - "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:31:02.915", - "scheduled_time": "2025-12-07 19:31:02.961", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:31:24 GMT - req-arrive-time: - - '1765107084362' - req-cost-time: - - '49' - resp-start-time: - - '1765107084412' - server: - - istio-envoy - set-cookie: - - acw_tc=4999648b-824a-4c5e-b204-4bc2fc49ef7c1a58f1c7eab1942ddb059306fd918233;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '41' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/98dd7f12-116c-499f-b7dd-02d66b9da2ed - response: - body: - string: |- - { - "request_id": "a8e37642-4dfd-4e99-b51f-07c6631dc472", - "output": { - "task_id": "98dd7f12-116c-499f-b7dd-02d66b9da2ed", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:31:02.915", - "scheduled_time": "2025-12-07 19:31:02.961", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 1, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:31:29 GMT - req-arrive-time: - - '1765107089585' - req-cost-time: - - '50' - resp-start-time: - - '1765107089635' - server: - - istio-envoy - set-cookie: - - acw_tc=a8e37642-4dfd-4e99-b51f-07c6631dc472acf1db8ded7c3e0b834600162c91370d;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '43' - status: - code: 200 - message: OK + - request: body: null headers: diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_basic.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_basic.yaml index f1fa01c55..5a6019486 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_basic.yaml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_basic.yaml @@ -188,478 +188,6 @@ interactions: status: code: 200 message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e - response: - body: - string: |- - { - "request_id": "be1d8203-dec1-4033-9f8d-9aa67bc2dd96", - "output": { - "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:24:38.741", - "scheduled_time": "2025-12-07 19:24:38.774", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:24:41 GMT - req-arrive-time: - - '1765106681203' - req-cost-time: - - '50' - resp-start-time: - - '1765106681253' - server: - - istio-envoy - set-cookie: - - acw_tc=be1d8203-dec1-4033-9f8d-9aa67bc2dd96a8c26722f177f8736705655f3f2bcbec;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '43' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e - response: - body: - string: |- - { - "request_id": "d7708baa-71cb-4f11-8d3f-06190de89325", - "output": { - "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:24:38.741", - "scheduled_time": "2025-12-07 19:24:38.774", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:24:43 GMT - req-arrive-time: - - '1765106683372' - req-cost-time: - - '41' - resp-start-time: - - '1765106683414' - server: - - istio-envoy - set-cookie: - - acw_tc=d7708baa-71cb-4f11-8d3f-06190de8932585aa8cc6ebae0d492a878d934a0d7457;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '35' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e - response: - body: - string: |- - { - "request_id": "ca47154a-970e-40ff-bac7-790909a362e2", - "output": { - "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:24:38.741", - "scheduled_time": "2025-12-07 19:24:38.774", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:24:45 GMT - req-arrive-time: - - '1765106685517' - req-cost-time: - - '50' - resp-start-time: - - '1765106685567' - server: - - istio-envoy - set-cookie: - - acw_tc=ca47154a-970e-40ff-bac7-790909a362e2a1d9942b18128e5bb509c502766baf76;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '41' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e - response: - body: - string: |- - { - "request_id": "7de7997e-32e0-4b84-a10e-e1fc3cb1750e", - "output": { - "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:24:38.741", - "scheduled_time": "2025-12-07 19:24:38.774", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:24:47 GMT - req-arrive-time: - - '1765106687686' - req-cost-time: - - '46' - resp-start-time: - - '1765106687733' - server: - - istio-envoy - set-cookie: - - acw_tc=7de7997e-32e0-4b84-a10e-e1fc3cb1750ee02cf813a6532246d9bb1b970e4479db;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '40' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e - response: - body: - string: |- - { - "request_id": "daa90fc3-45bd-4709-9066-02454883c48e", - "output": { - "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:24:38.741", - "scheduled_time": "2025-12-07 19:24:38.774", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:24:51 GMT - req-arrive-time: - - '1765106691888' - req-cost-time: - - '46' - resp-start-time: - - '1765106691934' - server: - - istio-envoy - set-cookie: - - acw_tc=daa90fc3-45bd-4709-9066-02454883c48e5196c570e36a124cd5d56b3d513ccc03;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '39' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e - response: - body: - string: |- - { - "request_id": "29a2daf5-a308-4725-a60c-7b1c4f29b22e", - "output": { - "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:24:38.741", - "scheduled_time": "2025-12-07 19:24:38.774", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:24:56 GMT - req-arrive-time: - - '1765106696060' - req-cost-time: - - '53' - resp-start-time: - - '1765106696114' - server: - - istio-envoy - set-cookie: - - acw_tc=29a2daf5-a308-4725-a60c-7b1c4f29b22e35ef49a2ca3c8aa980836e010d98b0a1;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '47' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e - response: - body: - string: |- - { - "request_id": "197d8722-26d4-49f3-b6fe-d18af99c208e", - "output": { - "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:24:38.741", - "scheduled_time": "2025-12-07 19:24:38.774", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:25:00 GMT - req-arrive-time: - - '1765106700222' - req-cost-time: - - '53' - resp-start-time: - - '1765106700276' - server: - - istio-envoy - set-cookie: - - acw_tc=197d8722-26d4-49f3-b6fe-d18af99c208ebcf5e060a90527c28c5e34f0ccb29d98;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '45' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/d44cb271-6fbe-4e90-9dad-2673de89221e - response: - body: - string: |- - { - "request_id": "eff3e6f5-32f2-4115-bfc4-80480f64a3f0", - "output": { - "task_id": "d44cb271-6fbe-4e90-9dad-2673de89221e", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:24:38.741", - "scheduled_time": "2025-12-07 19:24:38.774", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:25:05 GMT - req-arrive-time: - - '1765106705373' - req-cost-time: - - '48' - resp-start-time: - - '1765106705421' - server: - - istio-envoy - set-cookie: - - acw_tc=eff3e6f5-32f2-4115-bfc4-80480f64a3f0a71c1efa9d6883e2ac27ec9229a81151;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '40' - status: - code: 200 - message: OK - request: body: null headers: diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_no_duplicate_spans.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_no_duplicate_spans.yaml index eb464ed85..c0c44da99 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_no_duplicate_spans.yaml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_no_duplicate_spans.yaml @@ -70,6 +70,7 @@ interactions: status: code: 200 message: OK + - request: body: null headers: @@ -129,6 +130,7 @@ interactions: status: code: 200 message: OK + - request: body: null headers: @@ -188,478 +190,7 @@ interactions: status: code: 200 message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f - response: - body: - string: |- - { - "request_id": "26364d32-fe57-42ba-9d98-6dbcd86c2886", - "output": { - "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:30:30.868", - "scheduled_time": "2025-12-07 19:30:30.895", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:33 GMT - req-arrive-time: - - '1765107033312' - req-cost-time: - - '45' - resp-start-time: - - '1765107033358' - server: - - istio-envoy - set-cookie: - - acw_tc=26364d32-fe57-42ba-9d98-6dbcd86c2886679915233dc7cb23505dca1cc5fb58fd;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '39' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f - response: - body: - string: |- - { - "request_id": "9232d132-6c93-425c-bd72-b5055e88d794", - "output": { - "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:30:30.868", - "scheduled_time": "2025-12-07 19:30:30.895", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:35 GMT - req-arrive-time: - - '1765107035474' - req-cost-time: - - '43' - resp-start-time: - - '1765107035517' - server: - - istio-envoy - set-cookie: - - acw_tc=9232d132-6c93-425c-bd72-b5055e88d79456873d094bd70d5c4b2557ffc79d5a61;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '33' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f - response: - body: - string: |- - { - "request_id": "2a47a4e8-fff4-42c9-9b91-f3314920b9b1", - "output": { - "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:30:30.868", - "scheduled_time": "2025-12-07 19:30:30.895", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:37 GMT - req-arrive-time: - - '1765107037637' - req-cost-time: - - '50' - resp-start-time: - - '1765107037688' - server: - - istio-envoy - set-cookie: - - acw_tc=2a47a4e8-fff4-42c9-9b91-f3314920b9b163db2ccdfea00a2b437b2109afd719fe;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '42' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f - response: - body: - string: |- - { - "request_id": "63c1528c-310a-4432-b18f-b6661d632481", - "output": { - "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:30:30.868", - "scheduled_time": "2025-12-07 19:30:30.895", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:39 GMT - req-arrive-time: - - '1765107039798' - req-cost-time: - - '46' - resp-start-time: - - '1765107039845' - server: - - istio-envoy - set-cookie: - - acw_tc=63c1528c-310a-4432-b18f-b6661d632481ed90b81cbb28724da9d071eed2aa5246;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '43' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f - response: - body: - string: |- - { - "request_id": "8764cf7f-0221-45d2-bad4-233797764fc6", - "output": { - "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:30:30.868", - "scheduled_time": "2025-12-07 19:30:30.895", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:44 GMT - req-arrive-time: - - '1765107043950' - req-cost-time: - - '51' - resp-start-time: - - '1765107044002' - server: - - istio-envoy - set-cookie: - - acw_tc=8764cf7f-0221-45d2-bad4-233797764fc657e2a15a885d1e614f2f9930f335fb24;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '43' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f - response: - body: - string: |- - { - "request_id": "1298340b-1fe3-4ba1-98c5-361bfaa2ae28", - "output": { - "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:30:30.868", - "scheduled_time": "2025-12-07 19:30:30.895", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:48 GMT - req-arrive-time: - - '1765107048114' - req-cost-time: - - '42' - resp-start-time: - - '1765107048157' - server: - - istio-envoy - set-cookie: - - acw_tc=1298340b-1fe3-4ba1-98c5-361bfaa2ae28c3b8a38361d24bd395be9a30bde48414;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '34' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f - response: - body: - string: |- - { - "request_id": "5be3c0f1-cda3-4eb4-a2fd-100609a6919a", - "output": { - "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:30:30.868", - "scheduled_time": "2025-12-07 19:30:30.895", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:52 GMT - req-arrive-time: - - '1765107052291' - req-cost-time: - - '51' - resp-start-time: - - '1765107052343' - server: - - istio-envoy - set-cookie: - - acw_tc=5be3c0f1-cda3-4eb4-a2fd-100609a6919a9bd61b4e6d6e1c55a5502d133fdb6076;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '47' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/612dcd86-b0d5-41c1-bcfa-05514a9c2b5f - response: - body: - string: |- - { - "request_id": "5801e7ab-2e42-4177-a70d-d8c3c04d96ad", - "output": { - "task_id": "612dcd86-b0d5-41c1-bcfa-05514a9c2b5f", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:30:30.868", - "scheduled_time": "2025-12-07 19:30:30.895", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:57 GMT - req-arrive-time: - - '1765107057457' - req-cost-time: - - '42' - resp-start-time: - - '1765107057500' - server: - - istio-envoy - set-cookie: - - acw_tc=5801e7ab-2e42-4177-a70d-d8c3c04d96ad012bc92a8fa4e9a8f7fdd2fa8d863c4d;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '35' - status: - code: 200 - message: OK + - request: body: null headers: diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml index 210908343..81796881f 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml @@ -1,6 +1,5 @@ interactions: -- request: - body: |- +body: |- { "model": "wanx-v1", "parameters": { @@ -74,6 +73,7 @@ interactions: status: code: 200 message: OK + - request: body: null headers: @@ -133,6 +133,7 @@ interactions: status: code: 200 message: OK + - request: body: null headers: @@ -192,478 +193,7 @@ interactions: status: code: 200 message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 - response: - body: - string: |- - { - "request_id": "e033d8cd-785f-46f8-81f2-d281b8eee831", - "output": { - "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:28:55.323", - "scheduled_time": "2025-12-07 19:28:55.359", - "task_metrics": { - "TOTAL": 2, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:28:57 GMT - req-arrive-time: - - '1765106937774' - req-cost-time: - - '43' - resp-start-time: - - '1765106937818' - server: - - istio-envoy - set-cookie: - - acw_tc=e033d8cd-785f-46f8-81f2-d281b8eee831c9024b8462e6fa6f33e5f39d9e5c60cd;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '35' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 - response: - body: - string: |- - { - "request_id": "03154871-c1dd-49f5-9f40-6aa75bb1c667", - "output": { - "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:28:55.323", - "scheduled_time": "2025-12-07 19:28:55.359", - "task_metrics": { - "TOTAL": 2, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:28:59 GMT - req-arrive-time: - - '1765106939937' - req-cost-time: - - '58' - resp-start-time: - - '1765106939996' - server: - - istio-envoy - set-cookie: - - acw_tc=03154871-c1dd-49f5-9f40-6aa75bb1c667ff0ca143ceb206fbe220aa4653602fe6;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '49' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 - response: - body: - string: |- - { - "request_id": "d0dc1956-01d5-40ab-9925-73ca798eb4a8", - "output": { - "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:28:55.323", - "scheduled_time": "2025-12-07 19:28:55.359", - "task_metrics": { - "TOTAL": 2, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:02 GMT - req-arrive-time: - - '1765106942113' - req-cost-time: - - '45' - resp-start-time: - - '1765106942158' - server: - - istio-envoy - set-cookie: - - acw_tc=d0dc1956-01d5-40ab-9925-73ca798eb4a8f039e19e88232e2941220df7bb6366b6;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '37' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 - response: - body: - string: |- - { - "request_id": "1e068629-ee74-465b-a878-815f7e6e47be", - "output": { - "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:28:55.323", - "scheduled_time": "2025-12-07 19:28:55.359", - "task_metrics": { - "TOTAL": 2, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:04 GMT - req-arrive-time: - - '1765106944264' - req-cost-time: - - '50' - resp-start-time: - - '1765106944315' - server: - - istio-envoy - set-cookie: - - acw_tc=1e068629-ee74-465b-a878-815f7e6e47beb0f90332e05221ee7927d67ad4c88472;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '43' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 - response: - body: - string: |- - { - "request_id": "fd9dce87-424d-44b4-b07d-9ecf86fa425e", - "output": { - "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:28:55.323", - "scheduled_time": "2025-12-07 19:28:55.359", - "task_metrics": { - "TOTAL": 2, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:08 GMT - req-arrive-time: - - '1765106948430' - req-cost-time: - - '46' - resp-start-time: - - '1765106948476' - server: - - istio-envoy - set-cookie: - - acw_tc=fd9dce87-424d-44b4-b07d-9ecf86fa425e8319491a1488238de95afcbd1808d148;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '39' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 - response: - body: - string: |- - { - "request_id": "c237203a-0477-4f14-be72-be8bee5e6739", - "output": { - "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:28:55.323", - "scheduled_time": "2025-12-07 19:28:55.359", - "task_metrics": { - "TOTAL": 2, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:12 GMT - req-arrive-time: - - '1765106952622' - req-cost-time: - - '48' - resp-start-time: - - '1765106952670' - server: - - istio-envoy - set-cookie: - - acw_tc=c237203a-0477-4f14-be72-be8bee5e6739c5a95afd8428ed0850da87d909225c30;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '41' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 - response: - body: - string: |- - { - "request_id": "31748f34-b548-4d37-83e7-6b19f88b3b1c", - "output": { - "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:28:55.323", - "scheduled_time": "2025-12-07 19:28:55.359", - "task_metrics": { - "TOTAL": 2, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:16 GMT - req-arrive-time: - - '1765106956787' - req-cost-time: - - '47' - resp-start-time: - - '1765106956835' - server: - - istio-envoy - set-cookie: - - acw_tc=31748f34-b548-4d37-83e7-6b19f88b3b1cdf40cdae0347b4151324b7e3d1d97a91;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '40' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/ddb966af-0f66-4e23-92f0-bd1eab8e5ce4 - response: - body: - string: |- - { - "request_id": "4c3744d3-8294-40c1-a976-d388f90bad8e", - "output": { - "task_id": "ddb966af-0f66-4e23-92f0-bd1eab8e5ce4", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:28:55.323", - "scheduled_time": "2025-12-07 19:28:55.359", - "task_metrics": { - "TOTAL": 2, - "SUCCEEDED": 1, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:21 GMT - req-arrive-time: - - '1765106961946' - req-cost-time: - - '43' - resp-start-time: - - '1765106961990' - server: - - istio-envoy - set-cookie: - - acw_tc=4c3744d3-8294-40c1-a976-d388f90bad8e1fa9401de66f0853e815d36cdc92abba;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '37' - status: - code: 200 - message: OK + - request: body: null headers: diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml index 2f843b8b9..cbf06dae7 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml @@ -1,6 +1,5 @@ interactions: -- request: - body: |- +body: |- { "model": "wanx-v1", "parameters": {}, @@ -70,6 +69,7 @@ interactions: status: code: 200 message: OK + - request: body: null headers: @@ -128,6 +128,7 @@ interactions: status: code: 200 message: OK + - request: body: null headers: @@ -148,11 +149,12 @@ interactions: body: string: |- { - "request_id": "99a9030b-ad71-4735-8af3-def55bf563ef", + "request_id": "8b64ebea-eb40-4659-9839-554ab6fd3b66", "output": { "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "PENDING", + "task_status": "RUNNING", "submit_time": "2025-12-07 19:29:27.629", + "scheduled_time": "2025-12-07 19:29:58.354", "task_metrics": { "TOTAL": 4, "SUCCEEDED": 0, @@ -162,21 +164,21 @@ interactions: } headers: content-length: - - '229' + - '272' content-type: - application/json;charset=UTF-8 date: - - Sun, 07 Dec 2025 11:29:29 GMT + - Sun, 07 Dec 2025 11:29:59 GMT req-arrive-time: - - '1765106968986' + - '1765106999513' req-cost-time: - - '52' + - '51' resp-start-time: - - '1765106969038' + - '1765106999565' server: - istio-envoy set-cookie: - - acw_tc=99a9030b-ad71-4735-8af3-def55bf563ef3ea8cc71a468d8cb6082af15094b10ba;path=/;HttpOnly;Max-Age=1800 + - acw_tc=8b64ebea-eb40-4659-9839-554ab6fd3b66c0359ec13138a0accd1121f378980bb9;path=/;HttpOnly;Max-Age=1800 transfer-encoding: - chunked vary: @@ -186,824 +188,7 @@ interactions: status: code: 200 message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "7917603d-cb76-46ac-90a1-baa41e8c16e7", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "PENDING", - "submit_time": "2025-12-07 19:29:27.629", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '229' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:30 GMT - req-arrive-time: - - '1765106970144' - req-cost-time: - - '50' - resp-start-time: - - '1765106970195' - server: - - istio-envoy - set-cookie: - - acw_tc=7917603d-cb76-46ac-90a1-baa41e8c16e791616d285ba2dc778d21b1af94c687b6;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '44' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "19a86183-0f26-4c04-ab53-afcac48d93d2", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "PENDING", - "submit_time": "2025-12-07 19:29:27.629", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '229' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:32 GMT - req-arrive-time: - - '1765106972319' - req-cost-time: - - '41' - resp-start-time: - - '1765106972361' - server: - - istio-envoy - set-cookie: - - acw_tc=19a86183-0f26-4c04-ab53-afcac48d93d27a44d99aaa70d2888b432c2dfdfc55dd;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '33' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "6aec9fa2-722f-480d-bdfd-e2c818802725", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "PENDING", - "submit_time": "2025-12-07 19:29:27.629", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '229' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:34 GMT - req-arrive-time: - - '1765106974467' - req-cost-time: - - '48' - resp-start-time: - - '1765106974516' - server: - - istio-envoy - set-cookie: - - acw_tc=6aec9fa2-722f-480d-bdfd-e2c818802725a6bae32cbd6fc53f3593adc60df7cb46;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '40' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "68740efb-8b57-4d48-87f2-a11f166cf814", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "PENDING", - "submit_time": "2025-12-07 19:29:27.629", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '229' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:36 GMT - req-arrive-time: - - '1765106976661' - req-cost-time: - - '58' - resp-start-time: - - '1765106976720' - server: - - istio-envoy - set-cookie: - - acw_tc=68740efb-8b57-4d48-87f2-a11f166cf8147799a2771275a2fbb8190dba0e2ea136;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '53' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "f0fb91c0-cd05-43a4-a3d2-50a2b34cbf4e", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "PENDING", - "submit_time": "2025-12-07 19:29:27.629", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '229' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:40 GMT - req-arrive-time: - - '1765106980831' - req-cost-time: - - '61' - resp-start-time: - - '1765106980893' - server: - - istio-envoy - set-cookie: - - acw_tc=f0fb91c0-cd05-43a4-a3d2-50a2b34cbf4e35bd2e45fffa1d16fae03499e5a82c90;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '41' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "dfe240f6-b896-4af1-ae32-d9f445189965", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "PENDING", - "submit_time": "2025-12-07 19:29:27.629", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '229' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:45 GMT - req-arrive-time: - - '1765106985016' - req-cost-time: - - '48' - resp-start-time: - - '1765106985065' - server: - - istio-envoy - set-cookie: - - acw_tc=dfe240f6-b896-4af1-ae32-d9f445189965b4ba50c5302fa1c71d0df8d0c9dc16f4;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '42' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "6273c926-02e4-4626-810f-c00f70f1fdf9", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "PENDING", - "submit_time": "2025-12-07 19:29:27.629", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '229' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:49 GMT - req-arrive-time: - - '1765106989168' - req-cost-time: - - '38' - resp-start-time: - - '1765106989207' - server: - - istio-envoy - set-cookie: - - acw_tc=6273c926-02e4-4626-810f-c00f70f1fdf9da45a206ba6d8b9e83b9f7971de13c44;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '33' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "247a0c1d-7aac-43d6-91ba-8f239a4f96f6", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "PENDING", - "submit_time": "2025-12-07 19:29:27.629", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '229' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:54 GMT - req-arrive-time: - - '1765106994351' - req-cost-time: - - '39' - resp-start-time: - - '1765106994390' - server: - - istio-envoy - set-cookie: - - acw_tc=247a0c1d-7aac-43d6-91ba-8f239a4f96f68fd4359ca10d046d26da87aa077e2753;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '32' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "8b64ebea-eb40-4659-9839-554ab6fd3b66", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:29:27.629", - "scheduled_time": "2025-12-07 19:29:58.354", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:29:59 GMT - req-arrive-time: - - '1765106999513' - req-cost-time: - - '51' - resp-start-time: - - '1765106999565' - server: - - istio-envoy - set-cookie: - - acw_tc=8b64ebea-eb40-4659-9839-554ab6fd3b66c0359ec13138a0accd1121f378980bb9;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '45' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "52e629ed-57cd-4a11-9c51-84b68710e581", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:29:27.629", - "scheduled_time": "2025-12-07 19:29:58.354", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:04 GMT - req-arrive-time: - - '1765107004674' - req-cost-time: - - '48' - resp-start-time: - - '1765107004722' - server: - - istio-envoy - set-cookie: - - acw_tc=52e629ed-57cd-4a11-9c51-84b68710e581cbb349cb3b6d9d1c615a0857ab61b2c3;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '40' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "280a5b3a-1d43-477a-89f2-56df8313226a", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:29:27.629", - "scheduled_time": "2025-12-07 19:29:58.354", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:09 GMT - req-arrive-time: - - '1765107009906' - req-cost-time: - - '46' - resp-start-time: - - '1765107009953' - server: - - istio-envoy - set-cookie: - - acw_tc=280a5b3a-1d43-477a-89f2-56df8313226aea22fc23459e3094c710b4a080c85eec;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '41' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "c9b54d6b-d8b5-4407-ad17-00a0286a9e75", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:29:27.629", - "scheduled_time": "2025-12-07 19:29:58.354", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:15 GMT - req-arrive-time: - - '1765107015057' - req-cost-time: - - '56' - resp-start-time: - - '1765107015113' - server: - - istio-envoy - set-cookie: - - acw_tc=c9b54d6b-d8b5-4407-ad17-00a0286a9e7537166bd5774a16a8c9a347e9e0da0bc0;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '49' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "d56fb4ce-53bf-4ae6-8bc1-7358b4b084fb", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:29:27.629", - "scheduled_time": "2025-12-07 19:29:58.354", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 0, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:20 GMT - req-arrive-time: - - '1765107020237' - req-cost-time: - - '46' - resp-start-time: - - '1765107020284' - server: - - istio-envoy - set-cookie: - - acw_tc=d56fb4ce-53bf-4ae6-8bc1-7358b4b084fb6fe4e014fce09c0b64450affd5b65a30;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '39' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - authorization: - - Bearer test_dashscope_api_key - user-agent: - - dashscope/1.25.2; python/3.13.9; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; - processor/arm - method: GET - uri: https://dashscope.aliyuncs.com/api/v1/tasks/f4df5487-bab7-467d-857a-3ab2b3bc4e8c - response: - body: - string: |- - { - "request_id": "3f67f053-447f-4fb9-8f4c-b86520db3937", - "output": { - "task_id": "f4df5487-bab7-467d-857a-3ab2b3bc4e8c", - "task_status": "RUNNING", - "submit_time": "2025-12-07 19:29:27.629", - "scheduled_time": "2025-12-07 19:29:58.354", - "task_metrics": { - "TOTAL": 4, - "SUCCEEDED": 2, - "FAILED": 0 - } - } - } - headers: - content-length: - - '272' - content-type: - - application/json;charset=UTF-8 - date: - - Sun, 07 Dec 2025 11:30:25 GMT - req-arrive-time: - - '1765107025395' - req-cost-time: - - '42' - resp-start-time: - - '1765107025438' - server: - - istio-envoy - set-cookie: - - acw_tc=3f67f053-447f-4fb9-8f4c-b86520db3937dba674235c43eff41384010bbf35a090;path=/;HttpOnly;Max-Age=1800 - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '37' - status: - code: 200 - message: OK + - request: body: null headers: diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py index 7f55937e9..9d637511b 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/conftest.py @@ -5,6 +5,13 @@ import pytest import yaml + +# Set up DASHSCOPE_API_KEY environment variable BEFORE any dashscope modules are imported +# This is critical because dashscope SDK reads environment variables at module import time +# and caches them in module-level variables +if "DASHSCOPE_API_KEY" not in os.environ: + os.environ["DASHSCOPE_API_KEY"] = "test_dashscope_api_key" + from loongsuite.instrumentation.dashscope import DashScopeInstrumentor from opentelemetry.instrumentation._semconv import ( @@ -36,16 +43,6 @@ def fixture_tracer_provider(span_exporter): return provider -@pytest.fixture(autouse=True) -def environment(): - """Set up environment variables for testing.""" - if not os.getenv("DASHSCOPE_API_KEY"): - # Use the provided API key from environment or set a test value - os.environ["DASHSCOPE_API_KEY"] = os.getenv( - "DASHSCOPE_API_KEY", "test_dashscope_api_key" - ) - - @pytest.fixture(scope="function") def instrument(tracer_provider): """Instrument DashScope SDK for testing.""" diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py index d9f951db5..b3dc8348d 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py @@ -1,4 +1,5 @@ """Tests for TextReRank instrumentation.""" +import os import pytest @@ -19,14 +20,14 @@ def _assert_rerank_span_attributes(span, request_model: str): """ # Span name format is "{operation_name} {model}" per semantic conventions # Operation name is "rerank" (custom value, waiting for semantic convention definition) - assert span.name == f"rerank {request_model}" + assert span.name == f"rerank_documents {request_model}" # Required attributes (following GenAI pattern) assert ( GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" assert ( - span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "rerank" + span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "rerank_documents" ), f"Expected 'rerank', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" assert ( diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/extended_span_utils.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/extended_span_utils.py index c3e4fdc87..b4622109d 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/extended_span_utils.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/extended_span_utils.py @@ -571,7 +571,9 @@ def _apply_rerank_finish_attributes( # pylint: disable=too-many-branches span: Span, invocation: RerankInvocation ) -> None: """Apply attributes for rerank_documents operations.""" - span.update_name(GenAiExtendedOperationNameValues.RERANK_DOCUMENTS.value) + span.update_name( + f"{GenAiExtendedOperationNameValues.RERANK_DOCUMENTS.value} {invocation.request_model or ''}".strip() + ) # Build all attributes attributes: dict[str, Any] = {} diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py index 8fdc67eda..54e626dea 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py @@ -70,9 +70,6 @@ get_logger, ) from opentelemetry.metrics import MeterProvider, get_meter -from opentelemetry.semconv._incubating.attributes import ( - gen_ai_attributes as GenAI, -) from opentelemetry.semconv.schemas import Schemas from opentelemetry.trace import ( Span, @@ -139,16 +136,9 @@ def start_llm( invocation: LLMInvocation, ) -> LLMInvocation: """Start an LLM invocation and create a pending span entry.""" - # Check if custom operation name is set in invocation.attributes - # This allows instrumentation to override the default "chat" operation name - operation_name = invocation.attributes.get("gen_ai.operation.name") - if operation_name: - span_name = f"{operation_name} {invocation.request_model}" - else: - span_name = f"{GenAI.GenAiOperationNameValues.CHAT.value} {invocation.request_model}" # Create a span and attach it as current; keep the token to detach later span = self._tracer.start_span( - name=span_name, + name=f"{invocation.operation_name} {invocation.request_model}", kind=SpanKind.CLIENT, ) # Record a monotonic start timestamp (seconds) for duration diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py index 0c06194b4..eb31c762d 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py @@ -72,7 +72,7 @@ def _get_llm_common_attributes( def _get_llm_span_name(invocation: LLMInvocation) -> str: """Get the span name for an LLM invocation.""" - return f"{GenAI.GenAiOperationNameValues.CHAT.value} {invocation.request_model}".strip() + return f"{invocation.operation_name} {invocation.request_model}".strip() def _get_llm_messages_attributes_for_span( diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py index f12e41687..a3d936675 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py @@ -24,6 +24,10 @@ from opentelemetry.context import Context from opentelemetry.trace import Span +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAI, +) + ContextToken: TypeAlias = Token[Context] @@ -203,6 +207,8 @@ class LLMInvocation: """ request_model: str + # Chat by default + operation_name: str = GenAI.GenAiOperationNameValues.CHAT.value context_token: ContextToken | None = None span: Span | None = None input_messages: list[InputMessage] = field( diff --git a/util/opentelemetry-util-genai/tests/test_extended_handler.py b/util/opentelemetry-util-genai/tests/test_extended_handler.py index 7e2bdfc0c..a2c968782 100644 --- a/util/opentelemetry-util-genai/tests/test_extended_handler.py +++ b/util/opentelemetry-util-genai/tests/test_extended_handler.py @@ -892,7 +892,7 @@ def test_rerank_start_and_stop_creates_span(self): invocation.attributes = {"custom": "rerank_attr"} span = _get_single_span(self.span_exporter) - self.assertEqual(span.name, "rerank_documents") + self.assertEqual(span.name, "rerank_documents rerank-english-v2.0") self.assertEqual(span.kind, trace.SpanKind.INTERNAL) _assert_span_time_order(span) @@ -962,7 +962,7 @@ def test_rerank_manual_start_and_stop(self): self.telemetry_handler.stop_rerank(invocation) span = _get_single_span(self.span_exporter) - self.assertEqual(span.name, "rerank_documents") + self.assertEqual(span.name, "rerank_documents rerank-model") span_attrs = _get_span_attributes(span) _assert_span_attributes( span_attrs, From 63bc3d67cf000888248e9b0bbe0125bf57bb5e03 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Sun, 14 Dec 2025 15:18:34 +0800 Subject: [PATCH 6/9] Fix unit tests Change-Id: I7816571f221dbf8f20579236360ce38ef51aac1a Co-developed-by: Cursor --- .../examples/basic_example.py | 5 +- .../instrumentation/dashscope/__init__.py | 8 +- .../instrumentation/dashscope/patch.py | 28 +- .../instrumentation/dashscope/utils.py | 4 +- ...is_async_call_and_wait_separate_spans.yaml | 3 +- ..._image_synthesis_call_with_parameters.yaml | 3 +- .../test_image_synthesis_wait_basic.yaml | 3 +- .../tests/test_embedding.py | 57 ++-- .../tests/test_generation.py | 285 ++++++++---------- .../tests/test_image_synthesis.py | 159 +++++----- .../tests/test_rerank.py | 37 ++- .../opentelemetry/util/genai/span_utils.py | 4 +- .../src/opentelemetry/util/genai/types.py | 3 +- 13 files changed, 299 insertions(+), 300 deletions(-) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/examples/basic_example.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/examples/basic_example.py index fc5e8e8cb..34ff24110 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/examples/basic_example.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/examples/basic_example.py @@ -12,6 +12,7 @@ import os +from dashscope import Generation, TextEmbedding from loongsuite.instrumentation.dashscope import DashScopeInstrumentor from opentelemetry import trace @@ -45,8 +46,6 @@ def main(): print("Example 1: Text Generation (non-streaming)") print("=" * 60) - from dashscope import Generation - response = Generation.call( model="qwen-turbo", prompt="Hello! Please introduce yourself in one sentence.", @@ -76,8 +75,6 @@ def main(): print("Example 3: Text Embedding") print("=" * 60) - from dashscope import TextEmbedding - response = TextEmbedding.call( model="text-embedding-v1", input="Hello, world!" ) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py index c12b84127..9aa19ce44 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/__init__.py @@ -244,10 +244,10 @@ def _uninstrument(self, **kwargs): **kwargs: Optional configuration parameters. """ # pylint: disable=import-outside-toplevel - import dashscope.aigc.generation - import dashscope.aigc.image_synthesis - import dashscope.embeddings.text_embedding - import dashscope.rerank.text_rerank + import dashscope.aigc.generation # noqa: PLC0415 + import dashscope.aigc.image_synthesis # noqa: PLC0415 + import dashscope.embeddings.text_embedding # noqa: PLC0415 + import dashscope.rerank.text_rerank # noqa: PLC0415 unwrap(dashscope.aigc.generation.Generation, "call") unwrap(dashscope.aigc.generation.AioGeneration, "call") diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py index dfe11cfe1..dc4aa5707 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py @@ -18,22 +18,22 @@ import logging from opentelemetry import context +from opentelemetry.util.genai._extended_semconv.gen_ai_extended_attributes import ( + GenAiExtendedProviderNameValues as GenAI, +) from opentelemetry.util.genai.extended_types import ( EmbeddingInvocation, RerankInvocation, ) -from opentelemetry.util.genai._extended_semconv.gen_ai_extended_attributes import ( - GenAiExtendedProviderNameValues as GenAI -) from opentelemetry.util.genai.types import Error from .utils import ( + _SKIP_INSTRUMENTATION_KEY, _create_accumulated_response, _create_invocation_from_generation, _create_invocation_from_image_synthesis, _extract_task_id, _get_parameter, - _SKIP_INSTRUMENTATION_KEY, _update_invocation_from_image_synthesis_async_response, _update_invocation_from_image_synthesis_response, _update_invocation_from_response, @@ -108,7 +108,9 @@ def wrap_generation_call(wrapped, instance, args, kwargs, handler=None): return wrapped(*args, **kwargs) -async def wrap_aio_generation_call(wrapped, instance, args, kwargs, handler=None): +async def wrap_aio_generation_call( + wrapped, instance, args, kwargs, handler=None +): """Wrapper for AioGeneration.call (async). Uses TelemetryHandler from opentelemetry-util-genai to manage span lifecycle. @@ -123,9 +125,7 @@ async def wrap_aio_generation_call(wrapped, instance, args, kwargs, handler=None # Extract model from kwargs model = kwargs.get("model") if not model: - logger.warning( - "Model not found in kwargs, skipping instrumentation" - ) + logger.warning("Model not found in kwargs, skipping instrumentation") return await wrapped(*args, **kwargs) if handler is None: @@ -270,7 +270,9 @@ def wrap_text_rerank_call(wrapped, instance, args, kwargs, handler=None): try: # Create rerank invocation object - invocation = RerankInvocation(provider=GenAI.DASHSCOPE.value, request_model=model) + invocation = RerankInvocation( + provider=GenAI.DASHSCOPE.value, request_model=model + ) invocation.provider = "dashscope" # Start rerank invocation (creates span) @@ -437,7 +439,9 @@ def wrap_image_synthesis_call(wrapped, instance, args, kwargs, handler=None): result = wrapped(*args, **kwargs) # Update invocation with response data - _update_invocation_from_image_synthesis_response(invocation, result) + _update_invocation_from_image_synthesis_response( + invocation, result + ) handler.stop_llm(invocation) return result @@ -584,7 +588,9 @@ def wrap_image_synthesis_wait(wrapped, instance, args, kwargs, handler=None): result = wrapped(*args, **kwargs) # Update invocation with response data - _update_invocation_from_image_synthesis_response(invocation, result) + _update_invocation_from_image_synthesis_response( + invocation, result + ) handler.stop_llm(invocation) return result diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py index 7d99cceae..0c8473bdf 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py @@ -855,7 +855,9 @@ def _update_invocation_from_image_synthesis_response( if image_urls: # Store first image URL as attribute (or all if needed) invocation.attributes["dashscope.image.url"] = ( - image_urls[0] if len(image_urls) == 1 else str(image_urls) + image_urls[0] + if len(image_urls) == 1 + else str(image_urls) ) except (KeyError, AttributeError): pass diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml index d1251048e..1b3f49776 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_async_call_and_wait_separate_spans.yaml @@ -1,5 +1,6 @@ interactions: -body: |- +- request: + body: |- { "model": "wanx-v1", "parameters": {}, diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml index 81796881f..a9647b97e 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_call_with_parameters.yaml @@ -1,5 +1,6 @@ interactions: -body: |- +- request: + body: |- { "model": "wanx-v1", "parameters": { diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml index cbf06dae7..8540b91b6 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/cassettes/test_image_synthesis_wait_basic.yaml @@ -1,5 +1,6 @@ interactions: -body: |- +- request: + body: |- { "model": "wanx-v1", "parameters": {}, diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py index 9d9a48ae6..f171d2560 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_embedding.py @@ -3,6 +3,7 @@ from typing import Optional import pytest +from dashscope import TextEmbedding from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, @@ -37,31 +38,33 @@ def _assert_embedding_span_attributes( assert span.name == f"embeddings {request_model}" # Required attributes - assert ( - GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + assert GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "embeddings" - ), f"Expected 'embeddings', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + ), ( + f"Expected 'embeddings', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + ) - assert ( - GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" + assert GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" + ) assert span.attributes[GenAIAttributes.GEN_AI_PROVIDER_NAME] == "dashscope" # Conditionally required attributes - assert ( - GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + assert GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == request_model ) # Recommended attributes - check if available if input_tokens is not None: - assert ( - GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS}" + assert GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS] == input_tokens @@ -91,38 +94,37 @@ def _assert_embedding_span_attributes( # Dimension count should only be set if it was specified in the request if dimension_count is not None: # If dimension_count was explicitly provided in the request, it must be set in span - assert ( - "gen_ai.embeddings.dimension.count" in span.attributes - ), "Missing gen_ai.embeddings.dimension.count" + assert "gen_ai.embeddings.dimension.count" in span.attributes, ( + "Missing gen_ai.embeddings.dimension.count" + ) assert ( span.attributes["gen_ai.embeddings.dimension.count"] == dimension_count ) else: # If dimension_count was not provided in the request, it should not be set in span - assert ( - "gen_ai.embeddings.dimension.count" not in span.attributes - ), "gen_ai.embeddings.dimension.count should not be set when not specified in request" + assert "gen_ai.embeddings.dimension.count" not in span.attributes, ( + "gen_ai.embeddings.dimension.count should not be set when not specified in request" + ) if server_address is not None: - assert ( - ServerAttributes.SERVER_ADDRESS in span.attributes - ), f"Missing {ServerAttributes.SERVER_ADDRESS}" + assert ServerAttributes.SERVER_ADDRESS in span.attributes, ( + f"Missing {ServerAttributes.SERVER_ADDRESS}" + ) assert ( span.attributes[ServerAttributes.SERVER_ADDRESS] == server_address ) if server_port is not None: - assert ( - ServerAttributes.SERVER_PORT in span.attributes - ), f"Missing {ServerAttributes.SERVER_PORT}" + assert ServerAttributes.SERVER_PORT in span.attributes, ( + f"Missing {ServerAttributes.SERVER_PORT}" + ) assert span.attributes[ServerAttributes.SERVER_PORT] == server_port @pytest.mark.vcr() def test_text_embedding_basic(instrument, span_exporter): """Test basic text embedding call.""" - from dashscope import TextEmbedding response = TextEmbedding.call( model="text-embedding-v1", input="Hello, world!" @@ -160,7 +162,6 @@ def test_text_embedding_basic(instrument, span_exporter): @pytest.mark.vcr() def test_text_embedding_batch(instrument, span_exporter): """Test text embedding with batch input.""" - from dashscope import TextEmbedding response = TextEmbedding.call( model="text-embedding-v1", input=["Hello", "World"] @@ -198,7 +199,6 @@ def test_text_embedding_batch(instrument, span_exporter): @pytest.mark.vcr() def test_text_embedding_with_text_type(instrument, span_exporter): """Test text embedding with text_type parameter.""" - from dashscope import TextEmbedding response = TextEmbedding.call( model="text-embedding-v1", @@ -238,7 +238,6 @@ def test_text_embedding_with_text_type(instrument, span_exporter): @pytest.mark.vcr() def test_text_embedding_with_dimension(instrument, span_exporter): """Test text embedding with dimension parameter.""" - from dashscope import TextEmbedding response = TextEmbedding.call( model="text-embedding-v1", diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py index b730711f7..b1485a877 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_generation.py @@ -1,6 +1,9 @@ """Tests for Generation instrumentation.""" +import json as json_utils + import pytest +from dashscope import AioGeneration, Generation from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, @@ -40,29 +43,29 @@ def _assert_generation_span_attributes( # Span name format is "{operation_name} {model}" per semantic conventions # Operation name is "chat" (not "gen_ai.chat") assert span.name == f"chat {request_model}" - assert ( - GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" - assert ( - span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "chat" - ), f"Expected 'chat', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + assert GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + ) + assert span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "chat", ( + f"Expected 'chat', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + ) - assert ( - GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" + assert GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" + ) assert span.attributes[GenAIAttributes.GEN_AI_PROVIDER_NAME] == "dashscope" - assert ( - GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + assert GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == request_model ) if response_model is not None: - assert ( - GenAIAttributes.GEN_AI_RESPONSE_MODEL in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_RESPONSE_MODEL}" + assert GenAIAttributes.GEN_AI_RESPONSE_MODEL in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_RESPONSE_MODEL}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_RESPONSE_MODEL] == response_model @@ -70,27 +73,27 @@ def _assert_generation_span_attributes( # If response_model is None, don't assert it exists (it may not be available) if response_id is not None: - assert ( - GenAIAttributes.GEN_AI_RESPONSE_ID in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_RESPONSE_ID}" + assert GenAIAttributes.GEN_AI_RESPONSE_ID in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_RESPONSE_ID}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_RESPONSE_ID] == response_id ) # If response_id is None, don't assert it exists (it may not be available) if input_tokens is not None: - assert ( - GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS}" + assert GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS] == input_tokens ) if output_tokens is not None: - assert ( - GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS}" + assert GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS] == output_tokens @@ -111,70 +114,70 @@ def _assert_generation_span_attributes( # Assert input/output messages based on expectation if expect_input_messages: - assert ( - GenAIAttributes.GEN_AI_INPUT_MESSAGES in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_INPUT_MESSAGES}" + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_INPUT_MESSAGES}" + ) else: - assert ( - GenAIAttributes.GEN_AI_INPUT_MESSAGES not in span.attributes - ), f"{GenAIAttributes.GEN_AI_INPUT_MESSAGES} should not be present" + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES not in span.attributes, ( + f"{GenAIAttributes.GEN_AI_INPUT_MESSAGES} should not be present" + ) if expect_output_messages: - assert ( - GenAIAttributes.GEN_AI_OUTPUT_MESSAGES in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_OUTPUT_MESSAGES}" + assert GenAIAttributes.GEN_AI_OUTPUT_MESSAGES in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_OUTPUT_MESSAGES}" + ) else: - assert ( - GenAIAttributes.GEN_AI_OUTPUT_MESSAGES not in span.attributes - ), f"{GenAIAttributes.GEN_AI_OUTPUT_MESSAGES} should not be present" + assert GenAIAttributes.GEN_AI_OUTPUT_MESSAGES not in span.attributes, ( + f"{GenAIAttributes.GEN_AI_OUTPUT_MESSAGES} should not be present" + ) # Assert optional request parameters if temperature is not None: - assert ( - "gen_ai.request.temperature" in span.attributes - ), "Missing gen_ai.request.temperature" + assert "gen_ai.request.temperature" in span.attributes, ( + "Missing gen_ai.request.temperature" + ) assert span.attributes["gen_ai.request.temperature"] == temperature if max_tokens is not None: - assert ( - "gen_ai.request.max_tokens" in span.attributes - ), "Missing gen_ai.request.max_tokens" + assert "gen_ai.request.max_tokens" in span.attributes, ( + "Missing gen_ai.request.max_tokens" + ) assert span.attributes["gen_ai.request.max_tokens"] == max_tokens if top_p is not None: - assert ( - "gen_ai.request.top_p" in span.attributes - ), "Missing gen_ai.request.top_p" + assert "gen_ai.request.top_p" in span.attributes, ( + "Missing gen_ai.request.top_p" + ) assert span.attributes["gen_ai.request.top_p"] == top_p if top_k is not None: - assert ( - "gen_ai.request.top_k" in span.attributes - ), "Missing gen_ai.request.top_k" + assert "gen_ai.request.top_k" in span.attributes, ( + "Missing gen_ai.request.top_k" + ) assert span.attributes["gen_ai.request.top_k"] == top_k if frequency_penalty is not None: - assert ( - "gen_ai.request.frequency_penalty" in span.attributes - ), "Missing gen_ai.request.frequency_penalty" + assert "gen_ai.request.frequency_penalty" in span.attributes, ( + "Missing gen_ai.request.frequency_penalty" + ) assert ( span.attributes["gen_ai.request.frequency_penalty"] == frequency_penalty ) if presence_penalty is not None: - assert ( - "gen_ai.request.presence_penalty" in span.attributes - ), "Missing gen_ai.request.presence_penalty" + assert "gen_ai.request.presence_penalty" in span.attributes, ( + "Missing gen_ai.request.presence_penalty" + ) assert ( span.attributes["gen_ai.request.presence_penalty"] == presence_penalty ) if stop_sequences is not None: - assert ( - "gen_ai.request.stop_sequences" in span.attributes - ), "Missing gen_ai.request.stop_sequences" + assert "gen_ai.request.stop_sequences" in span.attributes, ( + "Missing gen_ai.request.stop_sequences" + ) # Convert span attribute to list for comparison (it may be a tuple) span_stop_sequences = span.attributes["gen_ai.request.stop_sequences"] if isinstance(span_stop_sequences, tuple): @@ -182,28 +185,27 @@ def _assert_generation_span_attributes( assert span_stop_sequences == stop_sequences if seed is not None: - assert ( - "gen_ai.request.seed" in span.attributes - ), "Missing gen_ai.request.seed" + assert "gen_ai.request.seed" in span.attributes, ( + "Missing gen_ai.request.seed" + ) assert span.attributes["gen_ai.request.seed"] == seed if choice_count is not None and choice_count != 1: - assert ( - "gen_ai.request.choice.count" in span.attributes - ), "Missing gen_ai.request.choice.count" + assert "gen_ai.request.choice.count" in span.attributes, ( + "Missing gen_ai.request.choice.count" + ) assert span.attributes["gen_ai.request.choice.count"] == choice_count if output_type is not None: - assert ( - "gen_ai.output.type" in span.attributes - ), "Missing gen_ai.output.type" + assert "gen_ai.output.type" in span.attributes, ( + "Missing gen_ai.output.type" + ) assert span.attributes["gen_ai.output.type"] == output_type @pytest.mark.vcr() def test_generation_call_basic(instrument, span_exporter): """Test basic synchronous generation call.""" - from dashscope import Generation response = Generation.call(model="qwen-turbo", prompt="Hello!") @@ -245,7 +247,6 @@ def test_generation_call_basic(instrument, span_exporter): @pytest.mark.vcr() def test_generation_call_with_messages(instrument, span_exporter): """Test generation call with messages parameter.""" - from dashscope import Generation response = Generation.call( model="qwen-turbo", messages=[{"role": "user", "content": "Hello!"}] @@ -286,7 +287,6 @@ def test_generation_call_with_messages(instrument, span_exporter): @pytest.mark.vcr() def test_generation_call_streaming(instrument, span_exporter): """Test synchronous generation with streaming (default: full output mode).""" - from dashscope import Generation responses = Generation.call( model="qwen-turbo", prompt="Count from 1 to 5", stream=True @@ -335,7 +335,6 @@ def test_generation_call_streaming_incremental_output( instrument, span_exporter ): """Test synchronous generation with streaming in incremental output mode.""" - from dashscope import Generation responses = Generation.call( model="qwen-turbo", @@ -385,7 +384,6 @@ def test_generation_call_streaming_incremental_output( @pytest.mark.vcr() def test_generation_call_with_parameters(instrument, span_exporter): """Test generation call with various parameters.""" - from dashscope import Generation response = Generation.call( model="qwen-turbo", @@ -434,7 +432,6 @@ def test_generation_call_with_parameters(instrument, span_exporter): @pytest.mark.vcr() async def test_aio_generation_call_basic(instrument, span_exporter): """Test basic asynchronous generation call.""" - from dashscope import AioGeneration response = await AioGeneration.call(model="qwen-turbo", prompt="Hello!") @@ -474,7 +471,6 @@ async def test_aio_generation_call_basic(instrument, span_exporter): @pytest.mark.vcr() async def test_aio_generation_call_streaming(instrument, span_exporter): """Test asynchronous generation with streaming (default: full output mode).""" - from dashscope import AioGeneration responses = await AioGeneration.call( model="qwen-turbo", prompt="Count from 1 to 5", stream=True @@ -523,7 +519,6 @@ async def test_aio_generation_call_streaming_incremental_output( instrument, span_exporter ): """Test asynchronous generation with streaming in incremental output mode.""" - from dashscope import AioGeneration responses = await AioGeneration.call( model="qwen-turbo", @@ -575,7 +570,6 @@ def test_generation_call_with_content_capture( instrument_with_content, span_exporter ): """Test generation call with message content capture enabled.""" - from dashscope import Generation messages = [{"role": "user", "content": "Say this is a test"}] response = Generation.call(model="qwen-turbo", messages=messages) @@ -617,7 +611,6 @@ def test_generation_call_no_content_capture( instrument_no_content, span_exporter ): """Test generation call with message content capture disabled.""" - from dashscope import Generation messages = [{"role": "user", "content": "Say this is a test"}] response = Generation.call(model="qwen-turbo", messages=messages) @@ -659,7 +652,6 @@ def test_generation_call_with_prompt_content_capture( instrument_with_content, span_exporter ): """Test generation call with prompt (string) and content capture enabled.""" - from dashscope import Generation response = Generation.call(model="qwen-turbo", prompt="Hello, world!") @@ -700,7 +692,6 @@ def test_generation_call_with_prompt_content_capture( @pytest.mark.vcr() def test_generation_call_with_all_parameters(instrument, span_exporter): """Test generation call with all optional parameters.""" - from dashscope import Generation response = Generation.call( model="qwen-turbo", @@ -760,7 +751,6 @@ def test_generation_call_with_tool_calls_content_capture( instrument_with_content, span_exporter ): """Test generation call with tool calls and content capture enabled.""" - from dashscope import Generation tools = [ { @@ -805,20 +795,19 @@ def test_generation_call_with_tool_calls_content_capture( usage = _safe_getattr(response, "usage", None) # Assert tool definitions are present - assert ( - "gen_ai.tool.definitions" in span.attributes - ), "Missing gen_ai.tool.definitions" + assert "gen_ai.tool.definitions" in span.attributes, ( + "Missing gen_ai.tool.definitions" + ) tool_definitions_str = span.attributes["gen_ai.tool.definitions"] - assert isinstance( - tool_definitions_str, str - ), "Tool definitions should be a JSON string" - # Parse JSON to verify content - import json + assert isinstance(tool_definitions_str, str), ( + "Tool definitions should be a JSON string" + ) - tool_definitions = json.loads(tool_definitions_str) - assert isinstance( - tool_definitions, list - ), "Tool definitions should be a list after parsing" + # Parse JSON to verify content + tool_definitions = json_utils.loads(tool_definitions_str) + assert isinstance(tool_definitions, list), ( + "Tool definitions should be a list after parsing" + ) assert len(tool_definitions) > 0, "Tool definitions should not be empty" # Verify full tool definition is recorded (content capture enabled) @@ -828,12 +817,12 @@ def test_generation_call_with_tool_calls_content_capture( assert tool_def["name"] == "get_current_weather", "Tool name should match" assert tool_def["type"] == "function", "Tool type should be 'function'" # With content capture enabled, should have full definition - assert ( - "description" in tool_def - ), "Tool definition should have 'description' when content capture is enabled" - assert ( - "parameters" in tool_def - ), "Tool definition should have 'parameters' when content capture is enabled" + assert "description" in tool_def, ( + "Tool definition should have 'description' when content capture is enabled" + ) + assert "parameters" in tool_def, ( + "Tool definition should have 'parameters' when content capture is enabled" + ) # Assert input/output messages with tool calls (content capture enabled) _assert_generation_span_attributes( @@ -860,10 +849,8 @@ def test_generation_call_with_tool_calls_content_capture( if output_messages: # Check if any message contains tool calls # Output messages are stored as JSON strings, parse them - import json - if isinstance(output_messages, str): - output_messages = json.loads(output_messages) + output_messages = json_utils.loads(output_messages) # Check if any message has tool calls has_tool_calls = False @@ -882,7 +869,9 @@ def test_generation_call_with_tool_calls_content_capture( # If finish_reason is "tool_calls", we should have tool calls if finish_reason == "tool_calls": - assert has_tool_calls, "Expected tool calls in output messages when finish_reason is tool_calls" + assert has_tool_calls, ( + "Expected tool calls in output messages when finish_reason is tool_calls" + ) print( "✓ Generation.call (with tool calls, content capture) completed successfully" @@ -894,7 +883,6 @@ def test_generation_call_with_tool_calls_no_content_capture( instrument_no_content, span_exporter ): """Test generation call with tool calls and content capture disabled.""" - from dashscope import Generation tools = [ { @@ -939,20 +927,19 @@ def test_generation_call_with_tool_calls_no_content_capture( usage = _safe_getattr(response, "usage", None) # Assert tool definitions are present (should be present regardless of content capture) - assert ( - "gen_ai.tool.definitions" in span.attributes - ), "Missing gen_ai.tool.definitions" + assert "gen_ai.tool.definitions" in span.attributes, ( + "Missing gen_ai.tool.definitions" + ) tool_definitions_str = span.attributes["gen_ai.tool.definitions"] - assert isinstance( - tool_definitions_str, str - ), "Tool definitions should be a JSON string" - # Parse JSON to verify content - import json + assert isinstance(tool_definitions_str, str), ( + "Tool definitions should be a JSON string" + ) - tool_definitions = json.loads(tool_definitions_str) - assert isinstance( - tool_definitions, list - ), "Tool definitions should be a list after parsing" + # Parse JSON to verify content + tool_definitions = json_utils.loads(tool_definitions_str) + assert isinstance(tool_definitions, list), ( + "Tool definitions should be a list after parsing" + ) assert len(tool_definitions) > 0, "Tool definitions should not be empty" # Verify only type and name are recorded (content capture disabled) @@ -962,12 +949,12 @@ def test_generation_call_with_tool_calls_no_content_capture( assert tool_def["name"] == "get_current_weather", "Tool name should match" assert tool_def["type"] == "function", "Tool type should be 'function'" # With content capture disabled, should only have name and type - assert ( - "description" not in tool_def - ), "Tool definition should NOT have 'description' when content capture is disabled" - assert ( - "parameters" not in tool_def - ), "Tool definition should NOT have 'parameters' when content capture is disabled" + assert "description" not in tool_def, ( + "Tool definition should NOT have 'description' when content capture is disabled" + ) + assert "parameters" not in tool_def, ( + "Tool definition should NOT have 'parameters' when content capture is disabled" + ) # Assert input/output messages are NOT present (content capture disabled) _assert_generation_span_attributes( @@ -996,7 +983,6 @@ def test_generation_call_with_tool_call_response_content_capture( instrument_with_content, span_exporter ): """Test generation call with tool call response in messages and content capture enabled.""" - from dashscope import Generation tools = [ { @@ -1105,38 +1091,37 @@ def test_generation_call_with_tool_call_response_content_capture( ) # Assert tool definitions are present - assert ( - "gen_ai.tool.definitions" in span2.attributes - ), "Missing gen_ai.tool.definitions" + assert "gen_ai.tool.definitions" in span2.attributes, ( + "Missing gen_ai.tool.definitions" + ) tool_definitions_str = span2.attributes["gen_ai.tool.definitions"] - assert isinstance( - tool_definitions_str, str - ), "Tool definitions should be a JSON string" - import json - - tool_definitions = json.loads(tool_definitions_str) - assert isinstance( - tool_definitions, list - ), "Tool definitions should be a list after parsing" - assert ( - len(tool_definitions) > 0 - ), "Tool definitions should not be empty" + assert isinstance(tool_definitions_str, str), ( + "Tool definitions should be a JSON string" + ) + + tool_definitions = json_utils.loads(tool_definitions_str) + assert isinstance(tool_definitions, list), ( + "Tool definitions should be a list after parsing" + ) + assert len(tool_definitions) > 0, ( + "Tool definitions should not be empty" + ) # Verify full tool definition is recorded (content capture enabled) tool_def = tool_definitions[0] assert "name" in tool_def, "Tool definition should have 'name'" assert "type" in tool_def, "Tool definition should have 'type'" - assert ( - tool_def["name"] == "get_current_weather" - ), "Tool name should match" + assert tool_def["name"] == "get_current_weather", ( + "Tool name should match" + ) assert tool_def["type"] == "function", "Tool type should be 'function'" # With content capture enabled, should have full definition - assert ( - "description" in tool_def - ), "Tool definition should have 'description' when content capture is enabled" - assert ( - "parameters" in tool_def - ), "Tool definition should have 'parameters' when content capture is enabled" + assert "description" in tool_def, ( + "Tool definition should have 'description' when content capture is enabled" + ) + assert "parameters" in tool_def, ( + "Tool definition should have 'parameters' when content capture is enabled" + ) # Check if response has output messages # For tool call response scenario, output may be empty or have different format @@ -1169,10 +1154,8 @@ def test_generation_call_with_tool_call_response_content_capture( GenAIAttributes.GEN_AI_INPUT_MESSAGES ] if input_messages: - import json - if isinstance(input_messages, str): - input_messages = json.loads(input_messages) + input_messages = json_utils.loads(input_messages) # Check if any message has tool call response has_tool_response = False @@ -1192,9 +1175,9 @@ def test_generation_call_with_tool_call_response_content_capture( if has_tool_response: break - assert ( - has_tool_response - ), "Expected tool call response in input messages" + assert has_tool_response, ( + "Expected tool call response in input messages" + ) print( "✓ Generation.call (with tool call response, content capture) completed successfully" diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py index 306e172a1..2df5c4061 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py @@ -1,8 +1,8 @@ """Tests for ImageSynthesis instrumentation.""" import pytest - from dashscope import ImageSynthesis + from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, ) @@ -53,58 +53,58 @@ def _assert_image_synthesis_span_attributes( assert span.name == f"generate_content {request_model}" # Required attributes - assert ( - GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + assert GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "generate_content" - ), f"Expected 'generate_content', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + ), ( + f"Expected 'generate_content', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + ) - assert ( - GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" - assert ( - span.attributes[GenAIAttributes.GEN_AI_PROVIDER_NAME] == "dashscope" + assert GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" ) + assert span.attributes[GenAIAttributes.GEN_AI_PROVIDER_NAME] == "dashscope" - assert ( - GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + assert GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == request_model ) # Optional attributes if response_model is not None: - assert ( - GenAIAttributes.GEN_AI_RESPONSE_MODEL in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_RESPONSE_MODEL}" + assert GenAIAttributes.GEN_AI_RESPONSE_MODEL in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_RESPONSE_MODEL}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_RESPONSE_MODEL] == response_model ) if response_id is not None: - assert ( - GenAIAttributes.GEN_AI_RESPONSE_ID in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_RESPONSE_ID}" + assert GenAIAttributes.GEN_AI_RESPONSE_ID in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_RESPONSE_ID}" + ) # response_id may vary between test runs (VCR recordings), so just check it exists assert span.attributes[GenAIAttributes.GEN_AI_RESPONSE_ID] is not None if input_tokens is not None: - assert ( - GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS}" + assert GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS] == input_tokens ) if output_tokens is not None: - assert ( - GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS}" + assert GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS] == output_tokens @@ -112,21 +112,21 @@ def _assert_image_synthesis_span_attributes( # DashScope-specific attributes if task_id is not None: - assert ( - "dashscope.task_id" in span.attributes - ), "Missing dashscope.task_id" + assert "dashscope.task_id" in span.attributes, ( + "Missing dashscope.task_id" + ) assert span.attributes["dashscope.task_id"] == task_id if task_status is not None: - assert ( - "dashscope.task_status" in span.attributes - ), "Missing dashscope.task_status" + assert "dashscope.task_status" in span.attributes, ( + "Missing dashscope.task_status" + ) assert span.attributes["dashscope.task_status"] == task_status if image_url is not None: - assert ( - "dashscope.image.url" in span.attributes - ), "Missing dashscope.image.url" + assert "dashscope.image.url" in span.attributes, ( + "Missing dashscope.image.url" + ) # image_url might be a string or a list representation span_url = span.attributes["dashscope.image.url"] if isinstance(span_url, str) and image_url in span_url: @@ -136,30 +136,32 @@ def _assert_image_synthesis_span_attributes( assert span_url == image_url if negative_prompt is not None: - assert ( - "dashscope.negative_prompt" in span.attributes - ), "Missing dashscope.negative_prompt" - assert ( - span.attributes["dashscope.negative_prompt"] == negative_prompt + assert "dashscope.negative_prompt" in span.attributes, ( + "Missing dashscope.negative_prompt" ) + assert span.attributes["dashscope.negative_prompt"] == negative_prompt if size is not None: - assert "dashscope.image.size" in span.attributes, "Missing dashscope.image.size" + assert "dashscope.image.size" in span.attributes, ( + "Missing dashscope.image.size" + ) assert span.attributes["dashscope.image.size"] == size if n is not None: - assert "dashscope.image.n" in span.attributes, "Missing dashscope.image.n" + assert "dashscope.image.n" in span.attributes, ( + "Missing dashscope.image.n" + ) assert span.attributes["dashscope.image.n"] == n # Assert input messages based on expectation if expect_input_messages: - assert ( - GenAIAttributes.GEN_AI_INPUT_MESSAGES in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_INPUT_MESSAGES}" + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_INPUT_MESSAGES}" + ) else: - assert ( - GenAIAttributes.GEN_AI_INPUT_MESSAGES not in span.attributes - ), f"{GenAIAttributes.GEN_AI_INPUT_MESSAGES} should not be present" + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES not in span.attributes, ( + f"{GenAIAttributes.GEN_AI_INPUT_MESSAGES} should not be present" + ) @pytest.mark.vcr() @@ -202,8 +204,12 @@ def test_image_synthesis_call_basic(instrument, span_exporter): request_model="wanx-v1", response_id=request_id, response_model=response_model, - input_tokens=_safe_getattr(usage, "input_tokens", None) if usage else None, - output_tokens=_safe_getattr(usage, "output_tokens", None) if usage else None, + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, task_id=task_id, task_status=task_status, image_url=image_url, @@ -256,8 +262,12 @@ def test_image_synthesis_call_with_parameters(instrument, span_exporter): request_model="wanx-v1", response_id=request_id, response_model=response_model, - input_tokens=_safe_getattr(usage, "input_tokens", None) if usage else None, - output_tokens=_safe_getattr(usage, "output_tokens", None) if usage else None, + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, task_id=task_id, task_status=task_status, image_url=image_url, @@ -298,9 +308,9 @@ def test_image_synthesis_async_call_basic(instrument, span_exporter): task_status = output.get("task_status") # Check async attribute - assert ( - "gen_ai.request.async" in span.attributes - ), "Missing gen_ai.request.async" + assert "gen_ai.request.async" in span.attributes, ( + "Missing gen_ai.request.async" + ) assert span.attributes["gen_ai.request.async"] is True _assert_image_synthesis_span_attributes( @@ -325,7 +335,7 @@ def test_image_synthesis_wait_basic(instrument, span_exporter): prompt="A forest scene", ) assert async_response is not None - + # Then wait for completion response = ImageSynthesis.wait(async_response) assert response is not None @@ -365,24 +375,28 @@ def test_image_synthesis_wait_basic(instrument, span_exporter): image_url = getattr(first_result, "url", None) # Check async attribute - assert ( - "gen_ai.request.async" in wait_span.attributes - ), "Missing gen_ai.request.async" + assert "gen_ai.request.async" in wait_span.attributes, ( + "Missing gen_ai.request.async" + ) assert wait_span.attributes["gen_ai.request.async"] is True # Wait span should have request_model="unknown" (we don't know model in wait phase) # But we can check task_id and operation - assert ( - wait_span.attributes.get("dashscope.operation") == "wait" - ), "Missing dashscope.operation=wait" + assert wait_span.attributes.get("dashscope.operation") == "wait", ( + "Missing dashscope.operation=wait" + ) _assert_image_synthesis_span_attributes( wait_span, request_model="unknown", # Wait phase doesn't know model response_id=request_id, response_model=response_model, - input_tokens=_safe_getattr(usage, "input_tokens", None) if usage else None, - output_tokens=_safe_getattr(usage, "output_tokens", None) if usage else None, + input_tokens=_safe_getattr(usage, "input_tokens", None) + if usage + else None, + output_tokens=_safe_getattr(usage, "output_tokens", None) + if usage + else None, task_id=task_id, task_status=task_status, image_url=image_url, @@ -409,9 +423,9 @@ def test_image_synthesis_call_no_duplicate_spans(instrument, span_exporter): if span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME) == "generate_content" ] - assert ( - len(image_synthesis_spans) == 1 - ), f"Expected 1 span, got {len(image_synthesis_spans)}. Spans: {[span.name for span in image_synthesis_spans]}" + assert len(image_synthesis_spans) == 1, ( + f"Expected 1 span, got {len(image_synthesis_spans)}. Spans: {[span.name for span in image_synthesis_spans]}" + ) print("✓ ImageSynthesis.call does not create duplicate spans") @@ -438,9 +452,9 @@ def test_image_synthesis_async_call_and_wait_separate_spans( and span.attributes.get("gen_ai.request.async") is True and span.attributes.get("dashscope.operation") != "wait" ] - assert ( - len(async_spans) == 1 - ), f"Expected 1 span after async_call, got {len(async_spans)}" + assert len(async_spans) == 1, ( + f"Expected 1 span after async_call, got {len(async_spans)}" + ) # Wait for completion response = ImageSynthesis.wait(async_response) @@ -454,9 +468,9 @@ def test_image_synthesis_async_call_and_wait_separate_spans( if span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME) == "generate_content" ] - assert ( - len(wait_spans) == 2 - ), f"Expected 2 spans after wait, got {len(wait_spans)}. Spans: {[span.name for span in wait_spans]}" + assert len(wait_spans) == 2, ( + f"Expected 2 spans after wait, got {len(wait_spans)}. Spans: {[span.name for span in wait_spans]}" + ) # Verify one span is for async_call and one is for wait async_span = None @@ -471,4 +485,3 @@ def test_image_synthesis_async_call_and_wait_separate_spans( assert wait_span is not None, "Wait span not found" print("✓ ImageSynthesis.async_call and wait create separate spans") - diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py index b3dc8348d..28b188f53 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_rerank.py @@ -1,7 +1,7 @@ """Tests for TextReRank instrumentation.""" -import os import pytest +from dashscope import TextReRank from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, @@ -23,21 +23,24 @@ def _assert_rerank_span_attributes(span, request_model: str): assert span.name == f"rerank_documents {request_model}" # Required attributes (following GenAI pattern) + assert GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + ) assert ( - GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" - assert ( - span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "rerank_documents" - ), f"Expected 'rerank', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] + == "rerank_documents" + ), ( + f"Expected 'rerank', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + ) - assert ( - GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" + assert GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" + ) assert span.attributes[GenAIAttributes.GEN_AI_PROVIDER_NAME] == "dashscope" - assert ( - GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + assert GenAIAttributes.GEN_AI_REQUEST_MODEL in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_REQUEST_MODEL}" + ) assert ( span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == request_model ) @@ -46,7 +49,6 @@ def _assert_rerank_span_attributes(span, request_model: str): @pytest.mark.vcr() def test_text_rerank_basic(instrument, span_exporter): """Test basic text rerank call.""" - from dashscope import TextReRank response = TextReRank.call( model="gte-rerank", @@ -73,7 +75,6 @@ def test_text_rerank_basic(instrument, span_exporter): @pytest.mark.vcr() def test_text_rerank_with_top_n(instrument, span_exporter): """Test text rerank with top_n parameter.""" - from dashscope import TextReRank response = TextReRank.call( model="gte-rerank", @@ -102,7 +103,6 @@ def test_text_rerank_with_top_n(instrument, span_exporter): @pytest.mark.vcr() def test_text_rerank_return_documents(instrument, span_exporter): """Test text rerank with return_documents parameter.""" - from dashscope import TextReRank response = TextReRank.call( model="gte-rerank", @@ -134,7 +134,6 @@ def test_text_rerank_error_handling(instrument, span_exporter): If an error occurs before the wrapper is called or if the API returns an error response, a span should still be created with error status. """ - from dashscope import TextReRank # Test with invalid model to trigger error # Note: DashScope API may return an error response instead of raising an exception @@ -172,8 +171,8 @@ def test_text_rerank_error_handling(instrument, span_exporter): if len(spans) > 0: span = spans[0] # Check that operation name is set - assert ( - GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes - ), f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + assert GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes, ( + f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" + ) print("✓ TextReRank.call (error handling) completed successfully") diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py index eb31c762d..ea426f0a7 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py @@ -59,9 +59,7 @@ def _get_llm_common_attributes( Returns a dictionary of attributes. """ attributes: dict[str, Any] = {} - attributes[GenAI.GEN_AI_OPERATION_NAME] = ( - GenAI.GenAiOperationNameValues.CHAT.value - ) + attributes[GenAI.GEN_AI_OPERATION_NAME] = invocation.operation_name if invocation.request_model: attributes[GenAI.GEN_AI_REQUEST_MODEL] = invocation.request_model if invocation.provider is not None: diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py index a3d936675..cfa978f19 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py @@ -22,11 +22,10 @@ from typing_extensions import TypeAlias from opentelemetry.context import Context -from opentelemetry.trace import Span - from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAI, ) +from opentelemetry.trace import Span ContextToken: TypeAlias = Token[Context] From 3cf1277a5f949c33703f875bee87ecbf1f4a7d24 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Sun, 14 Dec 2025 20:29:07 +0800 Subject: [PATCH 7/9] Fix tests for dashscope Change-Id: Ie958a04905738463e0d913816251142c1cf03d06 Co-developed-by: Cursor --- .../instrumentation/dashscope/patch.py | 40 ++-- .../instrumentation/dashscope/utils.py | 122 ++++------- .../tests/test_image_synthesis.py | 196 +++++------------- .../README-loongsuite.rst | 7 - 4 files changed, 111 insertions(+), 254 deletions(-) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py index dc4aa5707..4dc749b8e 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/patch.py @@ -502,23 +502,11 @@ def wrap_image_synthesis_async_call( # Execute the wrapped call (submit task) result = wrapped(*args, **kwargs) - # Extract task_id and update invocation - task_id = None - if result and hasattr(result, "output"): - if hasattr(result.output, "get"): - task_id = result.output.get("task_id") - elif hasattr(result.output, "task_id"): - task_id = getattr(result.output, "task_id", None) - - if task_id: - invocation.attributes["gen_ai.response.id"] = task_id - invocation.attributes["dashscope.task_id"] = task_id - - # Note: Span linking is not currently supported by ExtendedTelemetryHandler. - # If span linking is needed in the future, it should be implemented in the handler. - # For now, we skip storing span context for linking. - - # Update invocation with async response data (task_id, task_status) + # TODO: Implement span linking between async_call and wait spans. + # This would allow wait() span to be linked to async_call() span for better trace visualization. + # Consider using a task_id-based mapping to store span contexts across threads. + + # Update invocation with async response data (request_id, task_id) _update_invocation_from_image_synthesis_async_response( invocation, result ) @@ -566,19 +554,19 @@ def wrap_image_synthesis_wait(wrapped, instance, args, kwargs, handler=None): # If cannot extract task_id, skip instrumentation return wrapped(*args, **kwargs) - # Note: Span linking is not currently supported by ExtendedTelemetryHandler. - # If span linking is needed in the future, it should be implemented in the handler. + # TODO: Implement span linking between async_call and wait spans. + # This would allow wait() span to be linked to async_call() span for better trace visualization. + # Consider using a task_id-based mapping to store span contexts across threads. # Create invocation object (wait phase doesn't know model, use "unknown") + # Use "wait generate_content" as operation_name to make span name clearer invocation = _create_invocation_from_image_synthesis({}, "unknown") - invocation.operation_name = "generate_content" + # TODO: Add semantic conventions for wait operations + invocation.operation_name = "wait generate_content" invocation.attributes["gen_ai.request.async"] = True - invocation.attributes["gen_ai.response.id"] = task_id - invocation.attributes["dashscope.task_id"] = task_id - invocation.attributes["dashscope.operation"] = "wait" - - # Note: Span linking is not currently supported by ExtendedTelemetryHandler. - # If span linking is needed in the future, it should be implemented in the handler. + # Note: response_id will be set from response.output.task_id in _update_invocation_from_image_synthesis_response + # We set task_id here as a fallback + invocation.response_id = task_id # Start LLM invocation (creates span) handler.start_llm(invocation) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py index 0c8473bdf..069117432 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/loongsuite/instrumentation/dashscope/utils.py @@ -26,6 +26,7 @@ ToolCall, ToolCallResponse, ToolDefinition, + Uri, ) @@ -738,29 +739,6 @@ def _create_invocation_from_image_synthesis( InputMessage(role="user", parts=parts) ] - # Extract negative_prompt (as attribute) - negative_prompt = kwargs.get("negative_prompt") - if negative_prompt: - if isinstance(negative_prompt, str): - invocation.attributes["dashscope.negative_prompt"] = ( - negative_prompt - ) - - # Extract size (image dimensions) - size = kwargs.get("size") - if size: - invocation.attributes["dashscope.image.size"] = size - - # Extract n (number of images to generate) - n = kwargs.get("n") - if n is not None: - invocation.attributes["dashscope.image.n"] = n - - # Extract similarity parameter (if available) - similarity = kwargs.get("similarity") - if similarity is not None: - invocation.attributes["dashscope.image.similarity"] = similarity - return invocation @@ -790,16 +768,8 @@ def _update_invocation_from_image_synthesis_response( except (KeyError, AttributeError): pass - # Extract request ID (if available) - # Note: For ImageSynthesis, request_id is the main identifier, not task_id - try: - request_id = getattr(response, "request_id", None) - if request_id: - invocation.response_id = request_id - except (KeyError, AttributeError): - pass - - # Extract task_id and task_status from output + # Extract task_id from output and set as response_id + # Note: For ImageSynthesis, response_id should be task_id, not request_id try: output = getattr(response, "output", None) if output: @@ -811,30 +781,9 @@ def _update_invocation_from_image_synthesis_response( task_id = getattr(output, "task_id", None) if task_id: - # Store task_id in attributes - # Note: gen_ai.response.id should be request_id, not task_id - # task_id is stored separately in dashscope.task_id - invocation.attributes["dashscope.task_id"] = task_id - # Don't set gen_ai.response.id to task_id, as it should be request_id - # Only set response_id to task_id if request_id is not available - if not invocation.response_id: - invocation.response_id = task_id - invocation.attributes["gen_ai.response.id"] = task_id - - # Extract task_status - task_status = None - if hasattr(output, "get"): - task_status = output.get("task_status") - elif hasattr(output, "task_status"): - task_status = getattr(output, "task_status", None) - - if task_status: - invocation.attributes["dashscope.task_status"] = ( - task_status - ) + invocation.response_id = task_id - # Extract image URLs from results - # TODO: If returned as files or binary data, handle accordingly + # Extract image URLs from results and add as Uri MessageParts results = None if hasattr(output, "get"): results = output.get("results") @@ -842,23 +791,46 @@ def _update_invocation_from_image_synthesis_response( results = getattr(output, "results", None) if results and isinstance(results, list): - image_urls = [] + image_uris = [] for result in results: if isinstance(result, dict): url = result.get("url") if url: - image_urls.append(url) + image_uris.append( + Uri( + uri=url, + modality="image", + mime_type=None, + type="uri", + ) + ) elif hasattr(result, "url"): url = getattr(result, "url", None) if url: - image_urls.append(url) - if image_urls: - # Store first image URL as attribute (or all if needed) - invocation.attributes["dashscope.image.url"] = ( - image_urls[0] - if len(image_urls) == 1 - else str(image_urls) - ) + image_uris.append( + Uri( + uri=url, + modality="image", + mime_type=None, + type="uri", + ) + ) + if image_uris: + # Add image URIs to output messages + # If output_messages is empty, create a new one + if not invocation.output_messages: + invocation.output_messages = [ + OutputMessage( + role="assistant", + parts=image_uris, + finish_reason="stop", + ) + ] + else: + # Append URIs to the last output message + invocation.output_messages[-1].parts.extend( + image_uris + ) except (KeyError, AttributeError): pass except (KeyError, AttributeError): @@ -872,7 +844,7 @@ def _update_invocation_from_image_synthesis_async_response( """Update LLMInvocation with ImageSynthesis async_call response data. This is called when async_call() returns, before wait() is called. - Only extracts task_id and task_status (usually PENDING). + Extracts task_id and sets it as response_id. Args: invocation: LLMInvocation to update @@ -882,10 +854,9 @@ def _update_invocation_from_image_synthesis_async_response( return try: - # Extract task_id and task_status from output + # Extract task_id from output and set as response_id output = getattr(response, "output", None) if output: - # Extract task_id task_id = None if hasattr(output, "get"): task_id = output.get("task_id") @@ -893,17 +864,6 @@ def _update_invocation_from_image_synthesis_async_response( task_id = getattr(output, "task_id", None) if task_id: - invocation.attributes["gen_ai.response.id"] = task_id - invocation.attributes["dashscope.task_id"] = task_id - - # Extract task_status (usually PENDING for async_call) - task_status = None - if hasattr(output, "get"): - task_status = output.get("task_status") - elif hasattr(output, "task_status"): - task_status = getattr(output, "task_status", None) - - if task_status: - invocation.attributes["dashscope.task_status"] = task_status + invocation.response_id = task_id except (KeyError, AttributeError): pass diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py index 2df5c4061..dc2758f32 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/test_image_synthesis.py @@ -1,5 +1,7 @@ """Tests for ImageSynthesis instrumentation.""" +from typing import Optional + import pytest from dashscope import ImageSynthesis @@ -19,49 +21,51 @@ def _safe_getattr(obj, attr, default=None): def _assert_image_synthesis_span_attributes( span, request_model: str, - response_id: str = None, - response_model: str = None, - input_tokens: int = None, - output_tokens: int = None, - task_id: str = None, - task_status: str = None, - image_url: str = None, - negative_prompt: str = None, - size: str = None, - n: int = None, + response_model: Optional[str] = None, + input_tokens: Optional[int] = None, + output_tokens: Optional[int] = None, + task_id: Optional[str] = None, expect_input_messages: bool = False, + is_wait_span: bool = False, ): """Assert ImageSynthesis span attributes according to GenAI semantic conventions. Args: span: The span to assert request_model: Expected model name - response_id: Expected response ID (if available) response_model: Expected response model name (if available) input_tokens: Expected input token count (if available) output_tokens: Expected output token count (if available) - task_id: Expected task ID (if available) - task_status: Expected task status (if available) - image_url: Expected image URL (if available) - negative_prompt: Expected negative prompt (if provided) - size: Expected image size (if provided) - n: Expected number of images (if provided) + task_id: Expected task ID (if available) - used for response_id validation expect_input_messages: Whether to expect input messages in span + is_wait_span: Whether this is a wait span (span name will be "wait generate_content unknown") """ # Span name format is "{operation_name} {model}" per semantic conventions - # Operation name is "generate_content" - assert span.name == f"generate_content {request_model}" + # For wait spans, operation_name is "wait generate_content" + if is_wait_span: + assert span.name == f"wait generate_content {request_model}" + else: + # Operation name is "generate_content" + assert span.name == f"generate_content {request_model}" # Required attributes assert GenAIAttributes.GEN_AI_OPERATION_NAME in span.attributes, ( f"Missing {GenAIAttributes.GEN_AI_OPERATION_NAME}" ) - assert ( - span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] - == "generate_content" - ), ( - f"Expected 'generate_content', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" - ) + if is_wait_span: + assert ( + span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] + == "wait generate_content" + ), ( + f"Expected 'wait generate_content', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + ) + else: + assert ( + span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] + == "generate_content" + ), ( + f"Expected 'generate_content', got {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + ) assert GenAIAttributes.GEN_AI_PROVIDER_NAME in span.attributes, ( f"Missing {GenAIAttributes.GEN_AI_PROVIDER_NAME}" @@ -85,12 +89,14 @@ def _assert_image_synthesis_span_attributes( == response_model ) - if response_id is not None: + # response_id should be task_id for ImageSynthesis + # If task_id is provided, use it for response_id validation + if task_id is not None: assert GenAIAttributes.GEN_AI_RESPONSE_ID in span.attributes, ( f"Missing {GenAIAttributes.GEN_AI_RESPONSE_ID}" ) - # response_id may vary between test runs (VCR recordings), so just check it exists - assert span.attributes[GenAIAttributes.GEN_AI_RESPONSE_ID] is not None + # response_id should be task_id for ImageSynthesis + assert span.attributes[GenAIAttributes.GEN_AI_RESPONSE_ID] == task_id if input_tokens is not None: assert GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS in span.attributes, ( @@ -110,49 +116,6 @@ def _assert_image_synthesis_span_attributes( == output_tokens ) - # DashScope-specific attributes - if task_id is not None: - assert "dashscope.task_id" in span.attributes, ( - "Missing dashscope.task_id" - ) - assert span.attributes["dashscope.task_id"] == task_id - - if task_status is not None: - assert "dashscope.task_status" in span.attributes, ( - "Missing dashscope.task_status" - ) - assert span.attributes["dashscope.task_status"] == task_status - - if image_url is not None: - assert "dashscope.image.url" in span.attributes, ( - "Missing dashscope.image.url" - ) - # image_url might be a string or a list representation - span_url = span.attributes["dashscope.image.url"] - if isinstance(span_url, str) and image_url in span_url: - # If it's a list representation, check if image_url is in it - pass - else: - assert span_url == image_url - - if negative_prompt is not None: - assert "dashscope.negative_prompt" in span.attributes, ( - "Missing dashscope.negative_prompt" - ) - assert span.attributes["dashscope.negative_prompt"] == negative_prompt - - if size is not None: - assert "dashscope.image.size" in span.attributes, ( - "Missing dashscope.image.size" - ) - assert span.attributes["dashscope.image.size"] == size - - if n is not None: - assert "dashscope.image.n" in span.attributes, ( - "Missing dashscope.image.n" - ) - assert span.attributes["dashscope.image.n"] == n - # Assert input messages based on expectation if expect_input_messages: assert GenAIAttributes.GEN_AI_INPUT_MESSAGES in span.attributes, ( @@ -180,29 +143,19 @@ def test_image_synthesis_call_basic(instrument, span_exporter): span = spans[0] output = _safe_getattr(response, "output", None) usage = _safe_getattr(response, "usage", None) - request_id = _safe_getattr(response, "request_id", None) response_model = _safe_getattr(response, "model", None) - # Extract task_id and task_status from output + # Extract task_id from output task_id = None - task_status = None - image_url = None if output: if hasattr(output, "get"): task_id = output.get("task_id") - task_status = output.get("task_status") - results = output.get("results") - if results and isinstance(results, list) and len(results) > 0: - first_result = results[0] - if isinstance(first_result, dict): - image_url = first_result.get("url") - elif hasattr(first_result, "url"): - image_url = getattr(first_result, "url", None) + elif hasattr(output, "task_id"): + task_id = getattr(output, "task_id", None) _assert_image_synthesis_span_attributes( span, request_model="wanx-v1", - response_id=request_id, response_model=response_model, input_tokens=_safe_getattr(usage, "input_tokens", None) if usage @@ -210,9 +163,7 @@ def test_image_synthesis_call_basic(instrument, span_exporter): output_tokens=_safe_getattr(usage, "output_tokens", None) if usage else None, - task_id=task_id, - task_status=task_status, - image_url=image_url, + task_id=task_id, # Used for response_id validation expect_input_messages=False, # Default: no content capture ) @@ -238,29 +189,19 @@ def test_image_synthesis_call_with_parameters(instrument, span_exporter): span = spans[0] output = _safe_getattr(response, "output", None) usage = _safe_getattr(response, "usage", None) - request_id = _safe_getattr(response, "request_id", None) response_model = _safe_getattr(response, "model", None) - # Extract task_id and task_status from output + # Extract task_id from output task_id = None - task_status = None - image_url = None if output: if hasattr(output, "get"): task_id = output.get("task_id") - task_status = output.get("task_status") - results = output.get("results") - if results and isinstance(results, list) and len(results) > 0: - first_result = results[0] - if isinstance(first_result, dict): - image_url = first_result.get("url") - elif hasattr(first_result, "url"): - image_url = getattr(first_result, "url", None) + elif hasattr(output, "task_id"): + task_id = getattr(output, "task_id", None) _assert_image_synthesis_span_attributes( span, request_model="wanx-v1", - response_id=request_id, response_model=response_model, input_tokens=_safe_getattr(usage, "input_tokens", None) if usage @@ -268,12 +209,7 @@ def test_image_synthesis_call_with_parameters(instrument, span_exporter): output_tokens=_safe_getattr(usage, "output_tokens", None) if usage else None, - task_id=task_id, - task_status=task_status, - image_url=image_url, - negative_prompt="blurry, low quality", - size="1024*1024", - n=2, + task_id=task_id, # Used for response_id validation expect_input_messages=False, # Default: no content capture ) @@ -296,16 +232,15 @@ def test_image_synthesis_async_call_basic(instrument, span_exporter): span = spans[0] output = _safe_getattr(response, "output", None) - request_id = _safe_getattr(response, "request_id", None) response_model = _safe_getattr(response, "model", None) - # Extract task_id and task_status from output + # Extract task_id from output task_id = None - task_status = None if output: if hasattr(output, "get"): task_id = output.get("task_id") - task_status = output.get("task_status") + elif hasattr(output, "task_id"): + task_id = getattr(output, "task_id", None) # Check async attribute assert "gen_ai.request.async" in span.attributes, ( @@ -316,10 +251,8 @@ def test_image_synthesis_async_call_basic(instrument, span_exporter): _assert_image_synthesis_span_attributes( span, request_model="wanx-v1", - response_id=request_id, response_model=response_model, - task_id=task_id, - task_status=task_status, + task_id=task_id, # Used for response_id validation expect_input_messages=False, # Default: no content capture ) @@ -344,10 +277,10 @@ def test_image_synthesis_wait_basic(instrument, span_exporter): spans = span_exporter.get_finished_spans() assert len(spans) == 2, f"Expected 2 spans, got {len(spans)}" - # Find wait span (should have dashscope.operation = "wait") + # Find wait span (span name should be "wait generate_content unknown") wait_span = None for span in spans: - if span.attributes.get("dashscope.operation") == "wait": + if span.name == "wait generate_content unknown": wait_span = span break @@ -355,24 +288,15 @@ def test_image_synthesis_wait_basic(instrument, span_exporter): output = _safe_getattr(response, "output", None) usage = _safe_getattr(response, "usage", None) - request_id = _safe_getattr(response, "request_id", None) response_model = _safe_getattr(response, "model", None) - # Extract task_id and task_status from output + # Extract task_id from output task_id = None - task_status = None - image_url = None if output: if hasattr(output, "get"): task_id = output.get("task_id") - task_status = output.get("task_status") - results = output.get("results") - if results and isinstance(results, list) and len(results) > 0: - first_result = results[0] - if isinstance(first_result, dict): - image_url = first_result.get("url") - elif hasattr(first_result, "url"): - image_url = getattr(first_result, "url", None) + elif hasattr(output, "task_id"): + task_id = getattr(output, "task_id", None) # Check async attribute assert "gen_ai.request.async" in wait_span.attributes, ( @@ -380,16 +304,9 @@ def test_image_synthesis_wait_basic(instrument, span_exporter): ) assert wait_span.attributes["gen_ai.request.async"] is True - # Wait span should have request_model="unknown" (we don't know model in wait phase) - # But we can check task_id and operation - assert wait_span.attributes.get("dashscope.operation") == "wait", ( - "Missing dashscope.operation=wait" - ) - _assert_image_synthesis_span_attributes( wait_span, request_model="unknown", # Wait phase doesn't know model - response_id=request_id, response_model=response_model, input_tokens=_safe_getattr(usage, "input_tokens", None) if usage @@ -397,10 +314,9 @@ def test_image_synthesis_wait_basic(instrument, span_exporter): output_tokens=_safe_getattr(usage, "output_tokens", None) if usage else None, - task_id=task_id, - task_status=task_status, - image_url=image_url, + task_id=task_id, # Used for response_id validation expect_input_messages=False, # Default: no content capture + is_wait_span=True, # Mark as wait span for span name validation ) print("✓ ImageSynthesis.wait (basic) completed successfully") @@ -450,7 +366,7 @@ def test_image_synthesis_async_call_and_wait_separate_spans( if span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME) == "generate_content" and span.attributes.get("gen_ai.request.async") is True - and span.attributes.get("dashscope.operation") != "wait" + and not span.name.startswith("wait generate_content") ] assert len(async_spans) == 1, ( f"Expected 1 span after async_call, got {len(async_spans)}" @@ -466,7 +382,7 @@ def test_image_synthesis_async_call_and_wait_separate_spans( span for span in spans_after_wait if span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME) - == "generate_content" + in ("generate_content", "wait generate_content") ] assert len(wait_spans) == 2, ( f"Expected 2 spans after wait, got {len(wait_spans)}. Spans: {[span.name for span in wait_spans]}" @@ -476,7 +392,7 @@ def test_image_synthesis_async_call_and_wait_separate_spans( async_span = None wait_span = None for span in wait_spans: - if span.attributes.get("dashscope.operation") == "wait": + if span.name.startswith("wait generate_content"): wait_span = span else: async_span = span diff --git a/util/opentelemetry-util-genai/README-loongsuite.rst b/util/opentelemetry-util-genai/README-loongsuite.rst index 850c4030f..e49ed4e7a 100644 --- a/util/opentelemetry-util-genai/README-loongsuite.rst +++ b/util/opentelemetry-util-genai/README-loongsuite.rst @@ -614,7 +614,6 @@ Token 使用: 设计文档 -------- -<<<<<<< HEAD OpenTelemetry GenAI Utils 的设计文档: `Design Document `_ 参考资料 @@ -623,10 +622,4 @@ OpenTelemetry GenAI Utils 的设计文档: `Design Document `_ * `OpenTelemetry GenAI Semantic Conventions `_ * `LoongSuite OpenTelemetry Python Agent `_ -======= -- ``ExtendedTelemetryHandler`` 是 ``TelemetryHandler`` 的子类,完全兼容原有 API -- 可以安全地替换 ``get_telemetry_handler()`` 为 ``get_extended_telemetry_handler()`` -- 所有原有功能保持不变,只是增加了新的操作类型支持 -- Embedding 操作的 ``gen_ai.operation.name`` 应该是 ``"embeddings"`` (复数形式),符合语义规范 ->>>>>>> 3a90289e3 (Add extended message parts) From f74926c8b0865b8c9190ebab5606d263b83e999c Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Sun, 14 Dec 2025 21:17:42 +0800 Subject: [PATCH 8/9] Generate github ci Change-Id: I71bcb535bfd9078d8f2a0b50c6e5fab310044458 Co-developed-by: Cursor --- .github/workflows/loongsuite_lint_0.yml | 19 +++ .github/workflows/loongsuite_test_0.yml | 190 ++++++++++++++++++++++++ 2 files changed, 209 insertions(+) diff --git a/.github/workflows/loongsuite_lint_0.yml b/.github/workflows/loongsuite_lint_0.yml index 873318e80..a44c7d273 100644 --- a/.github/workflows/loongsuite_lint_0.yml +++ b/.github/workflows/loongsuite_lint_0.yml @@ -32,6 +32,25 @@ env: jobs: + lint-loongsuite-instrumentation-dashscope: + name: LoongSuite loongsuite-instrumentation-dashscope + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e lint-loongsuite-instrumentation-dashscope + lint-loongsuite-instrumentation-mem0: name: LoongSuite loongsuite-instrumentation-mem0 runs-on: ubuntu-latest diff --git a/.github/workflows/loongsuite_test_0.yml b/.github/workflows/loongsuite_test_0.yml index 1d4e6b387..05b727856 100644 --- a/.github/workflows/loongsuite_test_0.yml +++ b/.github/workflows/loongsuite_test_0.yml @@ -32,6 +32,196 @@ env: jobs: + py39-test-loongsuite-instrumentation-dashscope-oldest_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-dashscope-oldest 3.9 Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.9 + uses: actions/setup-python@v5 + with: + python-version: "3.9" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e py39-test-loongsuite-instrumentation-dashscope-oldest -- -ra + + py39-test-loongsuite-instrumentation-dashscope-latest_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-dashscope-latest 3.9 Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.9 + uses: actions/setup-python@v5 + with: + python-version: "3.9" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e py39-test-loongsuite-instrumentation-dashscope-latest -- -ra + + py310-test-loongsuite-instrumentation-dashscope-oldest_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-dashscope-oldest 3.10 Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e py310-test-loongsuite-instrumentation-dashscope-oldest -- -ra + + py310-test-loongsuite-instrumentation-dashscope-latest_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-dashscope-latest 3.10 Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e py310-test-loongsuite-instrumentation-dashscope-latest -- -ra + + py311-test-loongsuite-instrumentation-dashscope-oldest_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-dashscope-oldest 3.11 Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e py311-test-loongsuite-instrumentation-dashscope-oldest -- -ra + + py311-test-loongsuite-instrumentation-dashscope-latest_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-dashscope-latest 3.11 Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e py311-test-loongsuite-instrumentation-dashscope-latest -- -ra + + py312-test-loongsuite-instrumentation-dashscope-oldest_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-dashscope-oldest 3.12 Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e py312-test-loongsuite-instrumentation-dashscope-oldest -- -ra + + py312-test-loongsuite-instrumentation-dashscope-latest_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-dashscope-latest 3.12 Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e py312-test-loongsuite-instrumentation-dashscope-latest -- -ra + + py313-test-loongsuite-instrumentation-dashscope-oldest_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-dashscope-oldest 3.13 Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e py313-test-loongsuite-instrumentation-dashscope-oldest -- -ra + + py313-test-loongsuite-instrumentation-dashscope-latest_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-dashscope-latest 3.13 Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -c tox-loongsuite.ini -e py313-test-loongsuite-instrumentation-dashscope-latest -- -ra + py39-test-loongsuite-instrumentation-mem0-oldest_ubuntu-latest: name: LoongSuite loongsuite-instrumentation-mem0-oldest 3.9 Ubuntu runs-on: ubuntu-latest From 713e2b35f7c97a6b41e3eca807741df65acac7f9 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Mon, 15 Dec 2025 15:18:32 +0800 Subject: [PATCH 9/9] Fix test failure in python 3.11 & 3.12 Change-Id: I7a4c56eedc36a18dc6f793f563b0c28638946e2a Co-developed-by: Cursor --- .../tests/requirements.latest.txt | 2 +- .../tests/requirements.oldest.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt index 19cf6ccf5..7fcb001f5 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.latest.txt @@ -40,7 +40,7 @@ pytest-asyncio==0.21.0 pytest-vcr==1.0.2 vcrpy>=4.2.0 pyyaml>=6.0 -wrapt==1.16.0 +wrapt==1.17.3 -e opentelemetry-instrumentation -e instrumentation-loongsuite/loongsuite-instrumentation-dashscope diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt index a61f1f273..d9e065910 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-dashscope/tests/requirements.oldest.txt @@ -21,7 +21,7 @@ pytest-asyncio==0.21.0 pytest-vcr==1.0.2 vcrpy>=4.2.0 pyyaml>=6.0 -wrapt==1.16.0 +wrapt==1.17.3 opentelemetry-exporter-otlp-proto-http~=1.30 opentelemetry-api==1.37 opentelemetry-sdk==1.37