From 7a7fe879d35a2fb92bf6a52e634013138691093f Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Wed, 1 Apr 2026 14:24:02 +0800 Subject: [PATCH 1/9] feat(copaw): initialize instrumentations of copaw Change-Id: I8d06200cd5339d346ab52a324936be397faf153d Co-developed-by: Cursor --- .../CHANGELOG.md | 23 ++++ .../README.md | 41 ++++++ .../examples/basic_example.py | 32 +++++ .../pyproject.toml | 59 +++++++++ .../instrumentation/copaw/__init__.py | 94 ++++++++++++++ .../instrumentation/copaw/_entry_utils.py | 119 ++++++++++++++++++ .../instrumentation/copaw/package.py | 15 +++ .../instrumentation/copaw/patch.py | 116 +++++++++++++++++ .../instrumentation/copaw/version.py | 15 +++ .../tests/conftest.py | 51 ++++++++ .../tests/requirements.latest.txt | 8 ++ .../tests/requirements.oldest.txt | 7 ++ .../tests/test_entry_span.py | 80 ++++++++++++ .../tests/test_entry_utils.py | 65 ++++++++++ .../tests/test_instrument_smoke.py | 74 +++++++++++ tox-loongsuite.ini | 10 ++ 16 files changed, 809 insertions(+) create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/_entry_utils.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/package.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/version.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/conftest.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.latest.txt create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_span.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_utils.py create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md new file mode 100644 index 000000000..b3060d1f4 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md @@ -0,0 +1,23 @@ +# 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/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +### Added + +- Entry telemetry for ``AgentRunner.query_handler`` using + ``opentelemetry-util-genai`` ``ExtendedTelemetryHandler``: span name + ``enter_ai_application_system``, session/user and streaming TTFT where + applicable, plus ``copaw.agent_id`` and ``copaw.channel``. +- Helpers in ``_entry_utils`` to build ``EntryInvocation`` from handler args and + stream items. + +### Changed + +- Instrumentor now requires ``opentelemetry-util-genai`` and forwards + ``tracer_provider`` / ``meter_provider`` / ``logger_provider`` to the extended + handler. diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md new file mode 100644 index 000000000..b3ddd1903 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md @@ -0,0 +1,41 @@ +# LoongSuite CoPaw Instrumentation + +LongSuite instrumentation for [CoPaw](https://github.com/agentscope-ai/CoPaw) +(personal assistant built on AgentScope). + +## Scope + +- **P0 hook**: ``copaw.app.runner.runner.AgentRunner.query_handler`` — wraps the + full CoPaw “turn” (approval, commands, or ``CoPawAgent`` run). Emits a single + **Entry** span via ``ExtendedTelemetryHandler`` (``enter_ai_application_system``, + ``gen_ai.operation.name=enter``, ``gen_ai.span.kind=ENTRY``). +- **Streaming**: records ``gen_ai.response.time_to_first_token`` (nanoseconds) + after the first yielded chunk. +- **Custom attributes**: ``copaw.agent_id`` (from ``runner.agent_id``), + ``copaw.channel`` (from ``request.channel`` when present). +- **Session / user**: ``gen_ai.session.id`` and ``gen_ai.user.id`` when present on + the request object. +- **Agent / Tool / LLM**: use existing AgentScope (and LiteLLM, etc.) + instrumentations; this package does not duplicate those spans. + +## Installation + +```bash +pip install loongsuite-instrumentation-copaw +pip install "copaw>=1.0.0" +``` + +## Usage + +```python +from opentelemetry.instrumentation.copaw import CoPawInstrumentor + +CoPawInstrumentor().instrument() +# start your CoPaw app +CoPawInstrumentor().uninstrument() +``` + +## See also + +- Point analysis: ``.cursor/memory/instrumentation-locations-CoPaw-2026-04-01.md`` +- Semconv / util-genai mapping: ``.cursor/memory/semconv-analysis-CoPaw-2026-04-01.md`` diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py new file mode 100644 index 000000000..345c0367c --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py @@ -0,0 +1,32 @@ +# 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. + +"""Example: enable CoPaw instrumentation before running the app.""" + +from __future__ import annotations + +import logging + +from opentelemetry.instrumentation.copaw import CoPawInstrumentor + + +def main() -> None: + logging.basicConfig(level=logging.INFO) + CoPawInstrumentor().instrument() + print("CoPaw instrumentation enabled (log-only phase). Run `copaw app` separately.") + CoPawInstrumentor().uninstrument() + + +if __name__ == "__main__": + main() diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml new file mode 100644 index 000000000..e242f9b99 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml @@ -0,0 +1,59 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "loongsuite-instrumentation-copaw" +dynamic = ["version"] +description = "LoongSuite CoPaw Instrumentation" +readme = "README.md" +license = "Apache-2.0" +requires-python = ">=3.10,<3.14" +authors = [ + { name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" }, +] +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.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", + "opentelemetry-util-genai", + "wrapt >= 1.17.3", +] + +[project.optional-dependencies] +instruments = [ + "copaw >= 1.0.0", +] + +[project.entry-points.opentelemetry_instrumentor] +copaw = "opentelemetry.instrumentation.copaw:CoPawInstrumentor" + +[project.urls] +Homepage = "https://github.com/alibaba/loongsuite-python-agent/tree/main/instrumentation-loongsuite/loongsuite-instrumentation-copaw" +Repository = "https://github.com/alibaba/loongsuite-python-agent" + +[tool.hatch.version] +path = "src/opentelemetry/instrumentation/copaw/version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/src", + "/tests", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/opentelemetry"] + +[tool.pytest.ini_options] +asyncio_mode = "auto" diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py new file mode 100644 index 000000000..ad16a44c6 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py @@ -0,0 +1,94 @@ +# 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. + +""" +LongSuite CoPaw instrumentation (``copaw >= 1.0.0``). + +Instruments ``AgentRunner.query_handler`` with ``ExtendedTelemetryHandler.entry`` +(``enter_ai_application_system``). Agent / tool / LLM spans come from AgentScope +and other instrumentations. + +Usage +----- +.. code:: python + + from opentelemetry.instrumentation.copaw import CoPawInstrumentor + + CoPawInstrumentor().instrument() + # ... run CoPaw app ... + CoPawInstrumentor().uninstrument() +""" + +from __future__ import annotations + +import logging +from typing import Any, Collection + +from wrapt import wrap_function_wrapper + +from opentelemetry.instrumentation.copaw.package import _instruments +from opentelemetry.instrumentation.copaw.patch import ( + _MODULE_RUNNER, + make_query_handler_wrapper, +) +from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.utils import unwrap +from opentelemetry.util.genai.extended_handler import ExtendedTelemetryHandler + +logger = logging.getLogger(__name__) + +__all__ = ["CoPawInstrumentor"] + + +class CoPawInstrumentor(BaseInstrumentor): + """LongSuite instrumentor for CoPaw (Entry on ``AgentRunner.query_handler``).""" + + def __init__(self) -> None: + super().__init__() + self._handler: ExtendedTelemetryHandler | None = None + + def instrumentation_dependencies(self) -> Collection[str]: + return _instruments + + def _instrument(self, **kwargs: Any) -> None: + tracer_provider = kwargs.get("tracer_provider") + meter_provider = kwargs.get("meter_provider") + logger_provider = kwargs.get("logger_provider") + + self._handler = ExtendedTelemetryHandler( + tracer_provider=tracer_provider, + meter_provider=meter_provider, + logger_provider=logger_provider, + ) + wrapper = make_query_handler_wrapper(self._handler) + wrap_function_wrapper( + _MODULE_RUNNER, + "AgentRunner.query_handler", + wrapper, + ) + logger.debug("Instrumented CoPaw AgentRunner.query_handler") + + def _uninstrument(self, **kwargs: Any) -> None: + del kwargs + self._handler = None + try: + import copaw.app.runner.runner as runner_module # noqa: PLC0415 + + unwrap(runner_module.AgentRunner, "query_handler") + logger.debug("Uninstrumented CoPaw AgentRunner.query_handler") + except Exception as exc: + logger.warning( + "Failed to uninstrument CoPaw AgentRunner.query_handler: %s", + exc, + ) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/_entry_utils.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/_entry_utils.py new file mode 100644 index 000000000..ee305e173 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/_entry_utils.py @@ -0,0 +1,119 @@ +# 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. + +"""Build ``EntryInvocation`` from ``AgentRunner.query_handler`` call arguments.""" + +from __future__ import annotations + +from typing import Any + +from opentelemetry.util.genai.extended_types import EntryInvocation +from opentelemetry.util.genai.types import InputMessage, OutputMessage, Text + + +def _non_empty_str(value: Any) -> str | None: + if value is None: + return None + s = str(value).strip() + return s if s else None + + +def parse_query_handler_call( + args: tuple[Any, ...], + kwargs: dict[str, Any], +) -> tuple[Any, Any]: + """Return ``(msgs, request)`` from ``query_handler`` positional/kwargs.""" + msgs: Any = None + request: Any = None + if args: + msgs = args[0] + if len(args) > 1: + request = args[1] + if msgs is None and "msgs" in kwargs: + msgs = kwargs["msgs"] + if request is None: + request = kwargs.get("request") + return msgs, request + + +def input_messages_from_msgs(msgs: Any) -> list[InputMessage]: + """Turn AgentScope / runtime message list into ``InputMessage`` entries.""" + if not msgs: + return [] + if not isinstance(msgs, (list, tuple)): + msgs = [msgs] + out: list[InputMessage] = [] + for m in msgs: + role = getattr(m, "role", None) or "user" + if hasattr(m, "get_text_content"): + text = m.get_text_content() + if text: + out.append( + InputMessage( + role=role, + parts=[Text(content=text)], + ) + ) + return out + + +def output_message_from_yield_item(item: Any) -> OutputMessage | None: + """If *item* is ``(Msg, last)`` with an assistant text message, map to output.""" + if not isinstance(item, tuple) or not item: + return None + msg = item[0] + if msg is None: + return None + if getattr(msg, "role", None) != "assistant": + return None + if not hasattr(msg, "get_text_content"): + return None + text = msg.get_text_content() + if not text: + return None + return OutputMessage( + role="assistant", + parts=[Text(content=text)], + finish_reason="stop", + ) + + +def build_entry_invocation( + instance: Any, + msgs: Any, + request: Any, +) -> EntryInvocation: + """Populate ``EntryInvocation`` from runner instance and query_handler args.""" + session_id = None + user_id = None + channel = None + if request is not None: + session_id = _non_empty_str(getattr(request, "session_id", None)) + user_id = _non_empty_str(getattr(request, "user_id", None)) + channel = _non_empty_str(getattr(request, "channel", None)) + + agent_id = _non_empty_str(getattr(instance, "agent_id", None)) + + extra_attrs: dict[str, Any] = {} + if agent_id: + extra_attrs["copaw.agent_id"] = agent_id + if channel: + extra_attrs["copaw.channel"] = channel + + return EntryInvocation( + session_id=session_id, + user_id=user_id, + input_messages=input_messages_from_msgs(msgs), + attributes=extra_attrs, + ) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/package.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/package.py new file mode 100644 index 000000000..114993add --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/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 = ("copaw >= 1.0.0",) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py new file mode 100644 index 000000000..6b666e2e9 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py @@ -0,0 +1,116 @@ +# 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. + +"""Wrap ``AgentRunner.query_handler`` with LongSuite Entry telemetry.""" + +from __future__ import annotations + +import logging +import timeit +from typing import Any, Callable + +from opentelemetry.util.genai.extended_handler import ExtendedTelemetryHandler +from opentelemetry.util.genai.types import Error + +from ._entry_utils import ( + build_entry_invocation, + output_message_from_yield_item, + parse_query_handler_call, +) + +logger = logging.getLogger(__name__) + +_MODULE_RUNNER = "copaw.app.runner.runner" +_PATCH_TARGET = "AgentRunner.query_handler" + + +def _arg_summary(value: Any) -> str | int: + if isinstance(value, (list, tuple, str, bytes, dict)): + return len(value) + return type(value).__name__ + + +def make_query_handler_wrapper( + handler: ExtendedTelemetryHandler, +) -> Callable[..., Any]: + """Factory for ``wrapt`` wrapper bound to *handler*.""" + + def query_handler_wrapper( + wrapped: Any, + instance: Any, + args: Any, + kwargs: Any, + ) -> Any: + async def _aiter(): + logger.info( + "[INSTRUMENTATION] Entering %s.%s agent_id=%r arg_summary=%s kwargs_keys=%s", + _MODULE_RUNNER, + _PATCH_TARGET, + getattr(instance, "agent_id", None), + [_arg_summary(a) for a in args], + sorted(kwargs.keys()), + ) + msgs, request = parse_query_handler_call(args, kwargs) + invocation = build_entry_invocation(instance, msgs, request) + handler.start_entry(invocation) + monotonic_start = timeit.default_timer() + saw_first_token = False + last_assistant = None + try: + agen = wrapped(*args, **kwargs) + async for item in agen: + if not saw_first_token: + invocation.response_time_to_first_token = int( + (timeit.default_timer() - monotonic_start) + * 1_000_000_000 + ) + saw_first_token = True + out = output_message_from_yield_item(item) + if out is not None: + last_assistant = out + logger.info( + "[INSTRUMENTATION] query_handler yield tuple_types=%s", + tuple(type(x).__name__ for x in item) + if isinstance(item, tuple) + else type(item).__name__, + ) + yield item + except BaseException as exc: + if isinstance(exc, GeneratorExit): + if last_assistant is not None: + invocation.output_messages = [last_assistant] + handler.stop_entry(invocation) + raise + handler.fail_entry( + invocation, + Error( + message=str(exc) or type(exc).__name__, + type=type(exc), + ), + ) + raise + else: + if last_assistant is not None: + invocation.output_messages = [last_assistant] + handler.stop_entry(invocation) + finally: + logger.info( + "[INSTRUMENTATION] Exiting %s.%s", + _MODULE_RUNNER, + _PATCH_TARGET, + ) + + return _aiter() + + return query_handler_wrapper diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/version.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/version.py new file mode 100644 index 000000000..4effd145c --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/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.dev" diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/conftest.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/conftest.py new file mode 100644 index 000000000..ad318d96e --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/conftest.py @@ -0,0 +1,51 @@ +# 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. + +# -*- coding: utf-8 -*- +"""CoPaw instrumentation test fixtures.""" + +from __future__ import annotations + +import os + +import pytest + +from opentelemetry.instrumentation.copaw import CoPawInstrumentor +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(name="span_exporter") +def fixture_span_exporter(): + return InMemorySpanExporter() + + +@pytest.fixture(name="tracer_provider") +def fixture_tracer_provider(span_exporter): + provider = TracerProvider() + provider.add_span_processor(SimpleSpanProcessor(span_exporter)) + return provider + + +@pytest.fixture +def instrument(tracer_provider): + """Enable CoPaw instrumentation for one test.""" + os.environ.setdefault("OTEL_SEMCONV_STABILITY_OPT_IN", "gen_ai_latest_experimental") + inst = CoPawInstrumentor() + inst.instrument(skip_dep_check=True, tracer_provider=tracer_provider) + yield inst + inst.uninstrument() diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.latest.txt new file mode 100644 index 000000000..0f1b65ceb --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.latest.txt @@ -0,0 +1,8 @@ +# CoPaw + OpenTelemetry resolved from PyPI (avoid repo-local dev pins). +copaw>=1.0.0 +pytest +pytest-asyncio +wrapt + +-e instrumentation-loongsuite/loongsuite-instrumentation-copaw +-e util/opentelemetry-util-genai diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt new file mode 100644 index 000000000..ba2c15ac3 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt @@ -0,0 +1,7 @@ +copaw==1.0.0 +pytest +pytest-asyncio +wrapt + +-e instrumentation-loongsuite/loongsuite-instrumentation-copaw +-e util/opentelemetry-util-genai diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_span.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_span.py new file mode 100644 index 000000000..1c77bd5b6 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_span.py @@ -0,0 +1,80 @@ +# 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. + +"""Assert Entry span attributes for CoPaw ``query_handler``.""" + +from __future__ import annotations + +from types import SimpleNamespace + +import pytest + +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAI, +) +from opentelemetry.util.genai.extended_semconv.gen_ai_extended_attributes import ( + GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, + GEN_AI_SESSION_ID, + GEN_AI_SPAN_KIND, + GEN_AI_USER_ID, + GenAiSpanKindValues, +) + +pytest.importorskip("copaw") +pytest.importorskip("agentscope.message") + +from agentscope.message import Msg, TextBlock # noqa: E402 + + +def _attrs(span): + return dict(span.attributes or {}) + + +@pytest.mark.asyncio +async def test_query_handler_emits_enter_ai_application_system_span( + instrument, + span_exporter, + monkeypatch, +): + from copaw.app.runner.runner import AgentRunner # noqa: PLC0415 + + async def fake_resolve(self, session_id, query): + del self, session_id, query + denial = Msg( + name="Friday", + role="assistant", + content=[TextBlock(type="text", text="hello-entry")], + ) + return (denial, True, None) + + monkeypatch.setattr(AgentRunner, "_resolve_pending_approval", fake_resolve) + + runner = AgentRunner(agent_id="entry-agent") + req = SimpleNamespace(session_id="sess-1", user_id="user-2", channel="console") + + async for _ in runner.query_handler([], req): + pass + + spans = span_exporter.get_finished_spans() + assert len(spans) == 1 + span = spans[0] + assert span.name == "enter_ai_application_system" + attrs = _attrs(span) + assert attrs[GenAI.GEN_AI_OPERATION_NAME] == "enter" + assert attrs[GEN_AI_SPAN_KIND] == GenAiSpanKindValues.ENTRY.value + assert attrs[GEN_AI_SESSION_ID] == "sess-1" + assert attrs[GEN_AI_USER_ID] == "user-2" + assert attrs["copaw.agent_id"] == "entry-agent" + assert attrs["copaw.channel"] == "console" + assert attrs.get(GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN) is not None diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_utils.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_utils.py new file mode 100644 index 000000000..ac6886653 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_utils.py @@ -0,0 +1,65 @@ +# 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. + +"""Unit tests for Entry argument parsing (no ``copaw`` required).""" + +from __future__ import annotations + +from types import SimpleNamespace + +import pytest + +from opentelemetry.instrumentation.copaw._entry_utils import ( + build_entry_invocation, + input_messages_from_msgs, + parse_query_handler_call, +) + + +def test_parse_query_handler_call_positional(): + msgs = [1] + req = SimpleNamespace(session_id="a") + m, r = parse_query_handler_call((msgs, req), {}) + assert m is msgs + assert r is req + + +def test_parse_query_handler_call_kwargs(): + msgs = [2] + req = SimpleNamespace(session_id="b") + m, r = parse_query_handler_call(tuple(), {"msgs": msgs, "request": req}) + assert m is msgs + assert r is req + + +def test_build_entry_invocation_custom_attributes(): + inst = SimpleNamespace(agent_id="aid") + req = SimpleNamespace(session_id="s", user_id="u", channel="feishu") + inv = build_entry_invocation(inst, [], req) + assert inv.session_id == "s" + assert inv.user_id == "u" + assert inv.attributes["copaw.agent_id"] == "aid" + assert inv.attributes["copaw.channel"] == "feishu" + + +def test_input_messages_from_agentscope_msg(): + pytest.importorskip("agentscope.message") + from agentscope.message import Msg, TextBlock # noqa: PLC0415 + + m = Msg(name="u", role="user", content=[TextBlock(type="text", text="hi")]) + ims = input_messages_from_msgs([m]) + assert len(ims) == 1 + assert ims[0].role == "user" + assert len(ims[0].parts) == 1 + assert ims[0].parts[0].content == "hi" diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py new file mode 100644 index 000000000..210adc9d7 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py @@ -0,0 +1,74 @@ +# 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. + +"""Smoke tests with real ``copaw`` (optional dependency in env).""" + +from __future__ import annotations + +import logging +from types import SimpleNamespace + +import pytest + +from opentelemetry.instrumentation.copaw import CoPawInstrumentor + +pytest.importorskip("copaw") +pytest.importorskip("agentscope.message") + +from agentscope.message import Msg, TextBlock # noqa: E402 + + +@pytest.mark.asyncio +async def test_instrumented_query_handler_logs( + instrument, + span_exporter, + monkeypatch, + caplog, +): + """Short-circuit ``query_handler``; logs + exactly one Entry span.""" + + from copaw.app.runner.runner import AgentRunner # noqa: PLC0415 + + async def fake_resolve(self, session_id, query): + del self, session_id, query + denial = Msg( + name="Friday", + role="assistant", + content=[TextBlock(type="text", text="ok")], + ) + # CoPaw >= 1.0.0.post2 unpacks three values from _resolve_pending_approval. + return (denial, True, None) + + monkeypatch.setattr(AgentRunner, "_resolve_pending_approval", fake_resolve) + + runner = AgentRunner(agent_id="smoke-test") + req = SimpleNamespace(session_id="s1", user_id="u1", channel="console") + + with caplog.at_level(logging.INFO, logger="opentelemetry.instrumentation.copaw.patch"): + chunks = [] + async for item in runner.query_handler([], req): + chunks.append(item) + + assert len(chunks) == 1 + texts = " ".join(r.message for r in caplog.records) + assert "[INSTRUMENTATION] Entering" in texts + assert "[INSTRUMENTATION] Exiting" in texts + assert len(span_exporter.get_finished_spans()) == 1 + + +def test_instrument_uninstrument_roundtrip(tracer_provider): + """Instrument then uninstrument completes without error.""" + inst = CoPawInstrumentor() + inst.instrument(skip_dep_check=True, tracer_provider=tracer_provider) + inst.uninstrument() diff --git a/tox-loongsuite.ini b/tox-loongsuite.ini index d146667fe..f010eb096 100644 --- a/tox-loongsuite.ini +++ b/tox-loongsuite.ini @@ -71,6 +71,10 @@ envlist = py3{10,11,12,13}-test-loongsuite-instrumentation-crewai lint-loongsuite-instrumentation-crewai + ; loongsuite-instrumentation-copaw + py3{10,11,12,13}-test-loongsuite-instrumentation-copaw-{oldest,latest} + lint-loongsuite-instrumentation-copaw + [testenv] test_deps = opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api @@ -136,6 +140,9 @@ deps = loongsuite-crewai: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-crewai/tests/test-requirements.txt + copaw-oldest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt + copaw-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.latest.txt + ; FIXME: add coverage testing allowlist_externals = sh @@ -193,6 +200,9 @@ commands = test-loongsuite-instrumentation-litellm: pytest {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-litellm/tests {posargs} lint-loongsuite-instrumentation-litellm: python -m ruff check {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-litellm + test-loongsuite-instrumentation-copaw: pytest {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests {posargs} + lint-loongsuite-instrumentation-copaw: python -m ruff check {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-copaw + ; TODO: add coverage commands ; coverage: {toxinidir}/scripts/coverage.sh From aeb21d7eb3019a48756fa043f2a1f9b0f6b96823 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Wed, 1 Apr 2026 17:05:01 +0800 Subject: [PATCH 2/9] add workflow for copaw instrumentation Change-Id: I8bdf89aaa10e11bc83905ef13a86d742ce129624 Co-developed-by: Cursor --- .github/workflows/loongsuite_lint_0.yml | 19 +++ .github/workflows/loongsuite_test_0.yml | 76 ++++++++++ dev-requirements.txt | 2 +- instrumentation-loongsuite/README.md | 4 + .../tests/requirements.latest.txt | 8 - .../tests/requirements.oldest.txt | 7 - .../tests/requirements.txt | 28 ++++ .../src/loongsuite/distro/bootstrap_gen.py | 142 ++++++++++-------- tox-loongsuite.ini | 7 +- 9 files changed, 210 insertions(+), 83 deletions(-) delete mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.latest.txt delete mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt diff --git a/.github/workflows/loongsuite_lint_0.yml b/.github/workflows/loongsuite_lint_0.yml index 083ba861b..8f17f4ed1 100644 --- a/.github/workflows/loongsuite_lint_0.yml +++ b/.github/workflows/loongsuite_lint_0.yml @@ -222,3 +222,22 @@ jobs: - name: Run tests run: tox -c tox-loongsuite.ini -e lint-loongsuite-instrumentation-crewai + lint-loongsuite-instrumentation-copaw: + name: LoongSuite loongsuite-instrumentation-copaw + 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-copaw + diff --git a/.github/workflows/loongsuite_test_0.yml b/.github/workflows/loongsuite_test_0.yml index bfe7c3f3a..778dc6c0e 100644 --- a/.github/workflows/loongsuite_test_0.yml +++ b/.github/workflows/loongsuite_test_0.yml @@ -1533,3 +1533,79 @@ jobs: - name: Run tests run: tox -c tox-loongsuite.ini -e py313-test-loongsuite-instrumentation-crewai -- -ra + py310-test-loongsuite-instrumentation-copaw_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-copaw 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-copaw -- -ra + + py311-test-loongsuite-instrumentation-copaw_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-copaw 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-copaw -- -ra + + py312-test-loongsuite-instrumentation-copaw_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-copaw 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-copaw -- -ra + + py313-test-loongsuite-instrumentation-copaw_ubuntu-latest: + name: LoongSuite loongsuite-instrumentation-copaw 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-copaw -- -ra + diff --git a/dev-requirements.txt b/dev-requirements.txt index b2de8cecf..a5bbb0a6b 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -10,7 +10,7 @@ readme-renderer==42.0 bleach==4.1.0 # transient dependency for readme-renderer markupsafe>=2.0.1 codespell==2.1.0 -requests==2.32.3 +requests>=2.32.3 # LoongSuite Extension: Copaw requires requests>=2.32.3 ruamel.yaml==0.17.21 flaky==3.7.0 pre-commit==3.7.0; python_version >= '3.9' diff --git a/instrumentation-loongsuite/README.md b/instrumentation-loongsuite/README.md index f05e47fe8..e1d1d0b90 100644 --- a/instrumentation-loongsuite/README.md +++ b/instrumentation-loongsuite/README.md @@ -4,9 +4,13 @@ | [loongsuite-instrumentation-agentscope](./loongsuite-instrumentation-agentscope) | agentscope >= 1.0.0 | No | development | [loongsuite-instrumentation-agno](./loongsuite-instrumentation-agno) | agno | No | development | [loongsuite-instrumentation-claude-agent-sdk](./loongsuite-instrumentation-claude-agent-sdk) | claude-agent-sdk >= 0.1.0 | No | development +| [loongsuite-instrumentation-copaw](./loongsuite-instrumentation-copaw) | copaw >= 1.0.0 | No | development +| [loongsuite-instrumentation-crewai](./loongsuite-instrumentation-crewai) | crewai >= 0.80.0 | No | development | [loongsuite-instrumentation-dashscope](./loongsuite-instrumentation-dashscope) | dashscope >= 1.0.0 | No | development | [loongsuite-instrumentation-dify](./loongsuite-instrumentation-dify) | dify | No | development | [loongsuite-instrumentation-google-adk](./loongsuite-instrumentation-google-adk) | google-adk >= 0.1.0 | No | development | [loongsuite-instrumentation-langchain](./loongsuite-instrumentation-langchain) | langchain_core >= 0.1.0 | No | development +| [loongsuite-instrumentation-langgraph](./loongsuite-instrumentation-langgraph) | langgraph >= 0.2 | No | development +| [loongsuite-instrumentation-litellm](./loongsuite-instrumentation-litellm) | litellm >= 1.0.0 | No | development | [loongsuite-instrumentation-mcp](./loongsuite-instrumentation-mcp) | mcp >= 1.3.0, <= 1.25.0 | No | development | [loongsuite-instrumentation-mem0](./loongsuite-instrumentation-mem0) | mem0ai >= 1.0.0 | No | development \ No newline at end of file diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.latest.txt deleted file mode 100644 index 0f1b65ceb..000000000 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.latest.txt +++ /dev/null @@ -1,8 +0,0 @@ -# CoPaw + OpenTelemetry resolved from PyPI (avoid repo-local dev pins). -copaw>=1.0.0 -pytest -pytest-asyncio -wrapt - --e instrumentation-loongsuite/loongsuite-instrumentation-copaw --e util/opentelemetry-util-genai diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt deleted file mode 100644 index ba2c15ac3..000000000 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt +++ /dev/null @@ -1,7 +0,0 @@ -copaw==1.0.0 -pytest -pytest-asyncio -wrapt - --e instrumentation-loongsuite/loongsuite-instrumentation-copaw --e util/opentelemetry-util-genai diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt new file mode 100644 index 000000000..5e9a4aef9 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt @@ -0,0 +1,28 @@ +# 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. + +copaw==1.0.0 +pytest +pytest-asyncio +wrapt +opentelemetry-api +opentelemetry-sdk +opentelemetry-semantic-conventions +opentelemetry-instrumentation + +-e instrumentation-loongsuite/loongsuite-instrumentation-copaw +-e util/opentelemetry-util-genai diff --git a/loongsuite-distro/src/loongsuite/distro/bootstrap_gen.py b/loongsuite-distro/src/loongsuite/distro/bootstrap_gen.py index cea6d2017..9efddecec 100644 --- a/loongsuite-distro/src/loongsuite/distro/bootstrap_gen.py +++ b/loongsuite-distro/src/loongsuite/distro/bootstrap_gen.py @@ -30,233 +30,249 @@ }, { "library": "aio_pika >= 7.2.0, < 10.0.0", - "instrumentation": "opentelemetry-instrumentation-aio-pika==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-aio-pika==0.62b0.dev", }, { "library": "aiohttp ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.62b0.dev", }, { "library": "aiohttp ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-aiohttp-server==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-aiohttp-server==0.62b0.dev", }, { "library": "aiokafka >= 0.8, < 1.0", - "instrumentation": "opentelemetry-instrumentation-aiokafka==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-aiokafka==0.62b0.dev", }, { "library": "aiopg >= 0.13.0, < 2.0.0", - "instrumentation": "opentelemetry-instrumentation-aiopg==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-aiopg==0.62b0.dev", }, { "library": "asgiref ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-asgi==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-asgi==0.62b0.dev", }, { "library": "asyncclick ~= 8.0", - "instrumentation": "opentelemetry-instrumentation-asyncclick==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-asyncclick==0.62b0.dev", }, { "library": "asyncpg >= 0.12.0", - "instrumentation": "opentelemetry-instrumentation-asyncpg==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-asyncpg==0.62b0.dev", }, { "library": "boto~=2.0", - "instrumentation": "opentelemetry-instrumentation-boto==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-boto==0.62b0.dev", }, { "library": "boto3 ~= 1.0", - "instrumentation": "opentelemetry-instrumentation-boto3sqs==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-boto3sqs==0.62b0.dev", }, { "library": "botocore ~= 1.0", - "instrumentation": "opentelemetry-instrumentation-botocore==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-botocore==0.62b0.dev", }, { "library": "cassandra-driver ~= 3.25", - "instrumentation": "opentelemetry-instrumentation-cassandra==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-cassandra==0.62b0.dev", }, { "library": "scylla-driver ~= 3.25", - "instrumentation": "opentelemetry-instrumentation-cassandra==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-cassandra==0.62b0.dev", }, { "library": "celery >= 4.0, < 6.0", - "instrumentation": "opentelemetry-instrumentation-celery==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-celery==0.62b0.dev", }, { "library": "click >= 8.1.3, < 9.0.0", - "instrumentation": "opentelemetry-instrumentation-click==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-click==0.62b0.dev", }, { "library": "confluent-kafka >= 1.8.2, <= 2.13.0", - "instrumentation": "opentelemetry-instrumentation-confluent-kafka==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-confluent-kafka==0.62b0.dev", }, { "library": "django >= 2.0", - "instrumentation": "opentelemetry-instrumentation-django==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-django==0.62b0.dev", }, { "library": "elasticsearch >= 6.0", - "instrumentation": "opentelemetry-instrumentation-elasticsearch==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-elasticsearch==0.62b0.dev", }, { "library": "falcon >= 1.4.1, < 5.0.0", - "instrumentation": "opentelemetry-instrumentation-falcon==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-falcon==0.62b0.dev", }, { "library": "fastapi ~= 0.92", - "instrumentation": "opentelemetry-instrumentation-fastapi==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-fastapi==0.62b0.dev", }, { "library": "flask >= 1.0", - "instrumentation": "opentelemetry-instrumentation-flask==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-flask==0.62b0.dev", }, { "library": "grpcio >= 1.42.0", - "instrumentation": "opentelemetry-instrumentation-grpc==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-grpc==0.62b0.dev", }, { "library": "httpx >= 0.18.0", - "instrumentation": "opentelemetry-instrumentation-httpx==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-httpx==0.62b0.dev", }, { "library": "jinja2 >= 2.7, < 4.0", - "instrumentation": "opentelemetry-instrumentation-jinja2==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-jinja2==0.62b0.dev", }, { "library": "kafka-python >= 2.0, < 3.0", - "instrumentation": "opentelemetry-instrumentation-kafka-python==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-kafka-python==0.62b0.dev", }, { "library": "kafka-python-ng >= 2.0, < 3.0", - "instrumentation": "opentelemetry-instrumentation-kafka-python==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-kafka-python==0.62b0.dev", }, { "library": "mysql-connector-python >= 8.0, < 10.0", - "instrumentation": "opentelemetry-instrumentation-mysql==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-mysql==0.62b0.dev", }, { "library": "mysqlclient < 3", - "instrumentation": "opentelemetry-instrumentation-mysqlclient==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-mysqlclient==0.62b0.dev", }, { "library": "pika >= 0.12.0", - "instrumentation": "opentelemetry-instrumentation-pika==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-pika==0.62b0.dev", }, { "library": "psycopg >= 3.1.0", - "instrumentation": "opentelemetry-instrumentation-psycopg==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-psycopg==0.62b0.dev", }, { "library": "psycopg2 >= 2.7.3.1", - "instrumentation": "opentelemetry-instrumentation-psycopg2==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-psycopg2==0.62b0.dev", }, { "library": "psycopg2-binary >= 2.7.3.1", - "instrumentation": "opentelemetry-instrumentation-psycopg2==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-psycopg2==0.62b0.dev", }, { "library": "pymemcache >= 1.3.5, < 5", - "instrumentation": "opentelemetry-instrumentation-pymemcache==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-pymemcache==0.62b0.dev", }, { "library": "pymongo >= 3.1, < 5.0", - "instrumentation": "opentelemetry-instrumentation-pymongo==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-pymongo==0.62b0.dev", }, { "library": "pymssql >= 2.1.5, < 3", - "instrumentation": "opentelemetry-instrumentation-pymssql==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-pymssql==0.62b0.dev", }, { "library": "PyMySQL < 2", - "instrumentation": "opentelemetry-instrumentation-pymysql==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-pymysql==0.62b0.dev", }, { "library": "pyramid >= 1.7", - "instrumentation": "opentelemetry-instrumentation-pyramid==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-pyramid==0.62b0.dev", }, { "library": "redis >= 2.6", - "instrumentation": "opentelemetry-instrumentation-redis==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-redis==0.62b0.dev", }, { "library": "remoulade >= 0.50", - "instrumentation": "opentelemetry-instrumentation-remoulade==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-remoulade==0.62b0.dev", }, { "library": "requests ~= 2.0", - "instrumentation": "opentelemetry-instrumentation-requests==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-requests==0.62b0.dev", }, { "library": "sqlalchemy >= 1.0.0, < 2.1.0", - "instrumentation": "opentelemetry-instrumentation-sqlalchemy==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-sqlalchemy==0.62b0.dev", }, { "library": "starlette >= 0.13", - "instrumentation": "opentelemetry-instrumentation-starlette==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-starlette==0.62b0.dev", }, { "library": "psutil >= 5", - "instrumentation": "opentelemetry-instrumentation-system-metrics==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-system-metrics==0.62b0.dev", }, { "library": "tornado >= 5.1.1", - "instrumentation": "opentelemetry-instrumentation-tornado==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-tornado==0.62b0.dev", }, { "library": "tortoise-orm >= 0.17.0", - "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.62b0.dev", }, { "library": "pydantic >= 1.10.2", - "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.62b0.dev", }, { "library": "urllib3 >= 1.0.0, < 3.0.0", - "instrumentation": "opentelemetry-instrumentation-urllib3==0.61b0.dev", + "instrumentation": "opentelemetry-instrumentation-urllib3==0.62b0.dev", }, { "library": "agentscope >= 1.0.0", - "instrumentation": "loongsuite-instrumentation-agentscope==0.1.0.dev", + "instrumentation": "loongsuite-instrumentation-agentscope==0.4.0.dev", }, { "library": "agno", - "instrumentation": "loongsuite-instrumentation-agno==0.1.0.dev", + "instrumentation": "loongsuite-instrumentation-agno==0.4.0.dev", }, { "library": "claude-agent-sdk >= 0.1.0", - "instrumentation": "loongsuite-instrumentation-claude-agent-sdk==0.1.0.dev", + "instrumentation": "loongsuite-instrumentation-claude-agent-sdk==0.4.0.dev", + }, + { + "library": "copaw >= 1.0.0", + "instrumentation": "loongsuite-instrumentation-copaw==0.1.0.dev", + }, + { + "library": "crewai >= 0.80.0", + "instrumentation": "loongsuite-instrumentation-crewai==0.4.0.dev", }, { "library": "dashscope >= 1.0.0", - "instrumentation": "loongsuite-instrumentation-dashscope==0.1.0.dev", + "instrumentation": "loongsuite-instrumentation-dashscope==0.4.0.dev", }, { "library": "google-adk >= 0.1.0", - "instrumentation": "loongsuite-instrumentation-google-adk==0.1.0.dev", + "instrumentation": "loongsuite-instrumentation-google-adk==0.4.0.dev", }, { "library": "langchain_core >= 0.1.0", - "instrumentation": "loongsuite-instrumentation-langchain==0.1.0.dev", + "instrumentation": "loongsuite-instrumentation-langchain==0.4.0.dev", + }, + { + "library": "langgraph >= 0.2", + "instrumentation": "loongsuite-instrumentation-langgraph==0.4.0.dev", + }, + { + "library": "litellm >= 1.0.0", + "instrumentation": "loongsuite-instrumentation-litellm==0.4.0.dev", }, { "library": "mcp >= 1.3.0, <= 1.25.0", - "instrumentation": "loongsuite-instrumentation-mcp==0.1.0.dev", + "instrumentation": "loongsuite-instrumentation-mcp==0.4.0.dev", }, { "library": "mem0ai >= 1.0.0", - "instrumentation": "loongsuite-instrumentation-mem0==0.1.0.dev", + "instrumentation": "loongsuite-instrumentation-mem0==0.4.0.dev", }, ] default_instrumentations = [ - "opentelemetry-instrumentation-asyncio==0.61b0.dev", - "opentelemetry-instrumentation-dbapi==0.61b0.dev", - "opentelemetry-instrumentation-logging==0.61b0.dev", - "opentelemetry-instrumentation-sqlite3==0.61b0.dev", - "opentelemetry-instrumentation-threading==0.61b0.dev", - "opentelemetry-instrumentation-urllib==0.61b0.dev", - "opentelemetry-instrumentation-wsgi==0.61b0.dev", - "loongsuite-instrumentation-dify==0.1.0.dev", + "opentelemetry-instrumentation-asyncio==0.62b0.dev", + "opentelemetry-instrumentation-dbapi==0.62b0.dev", + "opentelemetry-instrumentation-logging==0.62b0.dev", + "opentelemetry-instrumentation-sqlite3==0.62b0.dev", + "opentelemetry-instrumentation-threading==0.62b0.dev", + "opentelemetry-instrumentation-urllib==0.62b0.dev", + "opentelemetry-instrumentation-wsgi==0.62b0.dev", + "loongsuite-instrumentation-dify==0.4.0.dev", ] diff --git a/tox-loongsuite.ini b/tox-loongsuite.ini index f010eb096..705cedca7 100644 --- a/tox-loongsuite.ini +++ b/tox-loongsuite.ini @@ -72,7 +72,7 @@ envlist = lint-loongsuite-instrumentation-crewai ; loongsuite-instrumentation-copaw - py3{10,11,12,13}-test-loongsuite-instrumentation-copaw-{oldest,latest} + py3{10,11,12,13}-test-loongsuite-instrumentation-copaw lint-loongsuite-instrumentation-copaw [testenv] @@ -137,11 +137,10 @@ deps = loongsuite-litellm: {[testenv]test_deps} loongsuite-litellm: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-litellm/tests/test-requirements.txt - loongsuite-crewai: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-crewai/tests/test-requirements.txt - copaw-oldest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt - copaw-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.latest.txt + copaw: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt + lint-loongsuite-instrumentation-copaw: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt ; FIXME: add coverage testing allowlist_externals = From 7ec4ab349a98f9c759f16d1fef0c7c4b43cb55f1 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Wed, 1 Apr 2026 17:15:27 +0800 Subject: [PATCH 3/9] format test pipelines Change-Id: Id69b2e64718a2fff833b65f7719392a459245745 Co-developed-by: Cursor --- .../tests/requirements.latest.txt | 37 ++++++++++++- .../tests/requirements.oldest.txt | 18 +++++- .../tests/requirements.latest.txt | 19 +++++++ .../README.md | 2 +- .../examples/basic_example.py | 4 +- .../pyproject.toml | 3 +- .../instrumentation/copaw/__init__.py | 2 +- .../instrumentation/copaw/version.py | 2 +- .../tests/conftest.py | 4 +- .../tests/requirements.txt | 3 - .../tests/test_entry_span.py | 4 +- .../tests/test_instrument_smoke.py | 4 +- .../tests/requirements.latest.txt | 37 ++++++++++++- .../tests/requirements.oldest.txt | 18 +++++- .../tests/requirements.latest.txt | 37 ++++++++++++- .../tests/requirements.oldest.txt | 18 +++++- .../tests/test-requirements.txt | 1 - .../test-requirements-latest.txt | 20 ------- .../test-requirements-oldest.txt | 25 --------- .../tests/requirements.latest.txt | 55 +++++++++++++++++++ .../tests/requirements.oldest.txt | 41 ++++++++++++++ tox-loongsuite.ini | 4 +- 22 files changed, 293 insertions(+), 65 deletions(-) delete mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-mem0/test-requirements-latest.txt delete mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-mem0/test-requirements-oldest.txt create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.latest.txt create mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.oldest.txt diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/tests/requirements.latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/tests/requirements.latest.txt index 9ebe4b2ff..00932f0cf 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/tests/requirements.latest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/tests/requirements.latest.txt @@ -1,4 +1,39 @@ -# Test requirements for latest versions +# 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: +# +# agentscope-latest: {[testenv]test_deps} +# agentscope-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/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. + agentscope>=1.0.0 pytest pytest-asyncio diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/tests/requirements.oldest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/tests/requirements.oldest.txt index 878d5f15a..079f34165 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/tests/requirements.oldest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-agentscope/tests/requirements.oldest.txt @@ -1,4 +1,20 @@ -# Test requirements for latest versions +# 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. + agentscope>=1.0.0 pytest pytest-asyncio diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-claude-agent-sdk/tests/requirements.latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-claude-agent-sdk/tests/requirements.latest.txt index 24b0ae772..4a242f62d 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-claude-agent-sdk/tests/requirements.latest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-claude-agent-sdk/tests/requirements.latest.txt @@ -12,6 +12,25 @@ # 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: +# +# claude-agent-sdk-latest: {[testenv]test_deps} +# claude-agent-sdk-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-claude-agent-sdk/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. diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md index b3ddd1903..a4d95b1bc 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md @@ -22,7 +22,7 @@ LongSuite instrumentation for [CoPaw](https://github.com/agentscope-ai/CoPaw) ```bash pip install loongsuite-instrumentation-copaw -pip install "copaw>=1.0.0" +pip install "copaw>=0.1.0" ``` ## Usage diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py index 345c0367c..a12deb9b5 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py @@ -24,7 +24,9 @@ def main() -> None: logging.basicConfig(level=logging.INFO) CoPawInstrumentor().instrument() - print("CoPaw instrumentation enabled (log-only phase). Run `copaw app` separately.") + print( + "CoPaw instrumentation enabled (log-only phase). Run `copaw app` separately." + ) CoPawInstrumentor().uninstrument() diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml index e242f9b99..3d0fe5c94 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml @@ -10,6 +10,7 @@ readme = "README.md" license = "Apache-2.0" requires-python = ">=3.10,<3.14" authors = [ + { name = "Minghui Zhang", email = "zmh1625lumian@gmail.com" }, { name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" }, ] classifiers = [ @@ -33,7 +34,7 @@ dependencies = [ [project.optional-dependencies] instruments = [ - "copaw >= 1.0.0", + "copaw >= 0.1.0", ] [project.entry-points.opentelemetry_instrumentor] diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py index ad16a44c6..9b827021a 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py @@ -13,7 +13,7 @@ # limitations under the License. """ -LongSuite CoPaw instrumentation (``copaw >= 1.0.0``). +LongSuite CoPaw instrumentation (``copaw >= 0.1.0``). Instruments ``AgentRunner.query_handler`` with ``ExtendedTelemetryHandler.entry`` (``enter_ai_application_system``). Agent / tool / LLM spans come from AgentScope diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/version.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/version.py index 4effd145c..8afceb914 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/version.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.1.0.dev" +__version__ = "0.4.0.dev" diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/conftest.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/conftest.py index ad318d96e..c69dab9ca 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/conftest.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/conftest.py @@ -44,7 +44,9 @@ def fixture_tracer_provider(span_exporter): @pytest.fixture def instrument(tracer_provider): """Enable CoPaw instrumentation for one test.""" - os.environ.setdefault("OTEL_SEMCONV_STABILITY_OPT_IN", "gen_ai_latest_experimental") + os.environ.setdefault( + "OTEL_SEMCONV_STABILITY_OPT_IN", "gen_ai_latest_experimental" + ) inst = CoPawInstrumentor() inst.instrument(skip_dep_check=True, tracer_provider=tracer_provider) yield inst diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt index 5e9a4aef9..57eee6627 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt @@ -12,9 +12,6 @@ # 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. - copaw==1.0.0 pytest pytest-asyncio diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_span.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_span.py index 1c77bd5b6..e816090ba 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_span.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_entry_span.py @@ -61,7 +61,9 @@ async def fake_resolve(self, session_id, query): monkeypatch.setattr(AgentRunner, "_resolve_pending_approval", fake_resolve) runner = AgentRunner(agent_id="entry-agent") - req = SimpleNamespace(session_id="sess-1", user_id="user-2", channel="console") + req = SimpleNamespace( + session_id="sess-1", user_id="user-2", channel="console" + ) async for _ in runner.query_handler([], req): pass diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py index 210adc9d7..6ce356dec 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py @@ -55,7 +55,9 @@ async def fake_resolve(self, session_id, query): runner = AgentRunner(agent_id="smoke-test") req = SimpleNamespace(session_id="s1", user_id="u1", channel="console") - with caplog.at_level(logging.INFO, logger="opentelemetry.instrumentation.copaw.patch"): + with caplog.at_level( + logging.INFO, logger="opentelemetry.instrumentation.copaw.patch" + ): chunks = [] async for item in runner.query_handler([], req): chunks.append(item) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/tests/requirements.latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/tests/requirements.latest.txt index 4746b55c5..8a484bc5e 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/tests/requirements.latest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/tests/requirements.latest.txt @@ -1,4 +1,39 @@ -# Test requirements for latest versions +# 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: +# +# google-adk-latest: {[testenv]test_deps} +# google-adk-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/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. + google-adk>=0.1.0 litellm pytest diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/tests/requirements.oldest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/tests/requirements.oldest.txt index f6b6eee5f..96e460a2e 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/tests/requirements.oldest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/tests/requirements.oldest.txt @@ -1,4 +1,20 @@ -# Test requirements for oldest supported versions +# 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. + google-adk>=0.1.0 litellm pytest diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/tests/requirements.latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/tests/requirements.latest.txt index f3197c0dc..73b30f921 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/tests/requirements.latest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/tests/requirements.latest.txt @@ -1,4 +1,39 @@ -# Test requirements for latest versions +# 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: +# +# langgraph-latest: {[testenv]test_deps} +# langgraph-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/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. + langgraph langgraph-prebuilt langchain_core<1.0.0 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/tests/requirements.oldest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/tests/requirements.oldest.txt index 2d3757bab..29c28b07f 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/tests/requirements.oldest.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/tests/requirements.oldest.txt @@ -1,4 +1,20 @@ -# Test requirements for oldest supported versions +# 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. + langgraph>=0.2 langgraph-prebuilt langchain_core<1.0.0 diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-litellm/tests/test-requirements.txt b/instrumentation-loongsuite/loongsuite-instrumentation-litellm/tests/test-requirements.txt index 9ef7f7eb8..87020426d 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-litellm/tests/test-requirements.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-litellm/tests/test-requirements.txt @@ -20,7 +20,6 @@ # with multiple other dependencies in the top-level "tox-loongsuite.ini" # file. In particular, please see: # -# loongsuite-litellm: {[testenv]test_deps} # loongsuite-litellm: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-litellm/tests/test-requirements.txt # # This provides additional dependencies, namely: diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-mem0/test-requirements-latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-mem0/test-requirements-latest.txt deleted file mode 100644 index f00ead84a..000000000 --- a/instrumentation-loongsuite/loongsuite-instrumentation-mem0/test-requirements-latest.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Core testing (same versions as 0, but using OTEL from source where applicable) -pytest==7.4.4 -pytest-cov>=4.0.0 -pytest-asyncio==0.21.0 -pytest-vcr==1.0.2 -vcrpy>=7.0.0,<8.0.0 - -# Third-party libraries used in tests -pyyaml>=6.0.0 -mem0ai>=1.0.0 -wrapt==1.17.3 -# Mock and utilities -mock>=4.0.0 - -# Internal / OTEL from source --e opentelemetry-instrumentation --e instrumentation-loongsuite/loongsuite-instrumentation-mem0 --e util/opentelemetry-util-genai - - diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-mem0/test-requirements-oldest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-mem0/test-requirements-oldest.txt deleted file mode 100644 index c93bbd9bc..000000000 --- a/instrumentation-loongsuite/loongsuite-instrumentation-mem0/test-requirements-oldest.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Core testing (aligned with opentelemetry-instrumentation-openai-v2) -pytest==7.4.4 -pytest-cov>=4.0.0 -pytest-asyncio==0.21.0 -pytest-vcr==1.0.2 -vcrpy>=7.0.0,<8.0.0 - -# Third-party libraries used in tests -pyyaml>=6.0.0 -mem0ai>=1.0.0 -wrapt==1.17.3 -# OpenTelemetry SDK and testing utilities (pinned to stable versions) -opentelemetry-api==1.37 -opentelemetry-sdk==1.37 -opentelemetry-semantic-conventions==0.58b0 -opentelemetry-instrumentation-threading==0.58b0 - -# Mock and utilities -mock>=4.0.0 - -# Internal dependency (this package, editable install) --e instrumentation-loongsuite/loongsuite-instrumentation-mem0 --e util/opentelemetry-util-genai - - diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.latest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.latest.txt new file mode 100644 index 000000000..da5b884b3 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.latest.txt @@ -0,0 +1,55 @@ +# 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: +# +# mem0-latest: {[testenv]test_deps} +# mem0-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mem0/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. + +pytest==7.4.4 +pytest-cov>=4.0.0 +pytest-asyncio==0.21.0 +pytest-vcr==1.0.2 +vcrpy>=7.0.0,<8.0.0 + +# Third-party libraries used in tests +pyyaml>=6.0.0 +mem0ai>=1.0.0 +wrapt==1.17.3 +# Mock and utilities +mock>=4.0.0 + +# Internal / OTEL from source +-e opentelemetry-instrumentation +-e instrumentation-loongsuite/loongsuite-instrumentation-mem0 +-e util/opentelemetry-util-genai + + diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.oldest.txt b/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.oldest.txt new file mode 100644 index 000000000..2b1a4b866 --- /dev/null +++ b/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.oldest.txt @@ -0,0 +1,41 @@ +# 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. + +pytest==7.4.4 +pytest-cov>=4.0.0 +pytest-asyncio==0.21.0 +pytest-vcr==1.0.2 +vcrpy>=7.0.0,<8.0.0 + +# Third-party libraries used in tests +pyyaml>=6.0.0 +mem0ai>=1.0.0 +wrapt==1.17.3 +# OpenTelemetry SDK and testing utilities (pinned to stable versions) +opentelemetry-api==1.37 +opentelemetry-sdk==1.37 +opentelemetry-semantic-conventions==0.58b0 +opentelemetry-instrumentation-threading==0.58b0 + +# Mock and utilities +mock>=4.0.0 + +# Internal dependency (this package, editable install) +-e instrumentation-loongsuite/loongsuite-instrumentation-mem0 +-e util/opentelemetry-util-genai + + diff --git a/tox-loongsuite.ini b/tox-loongsuite.ini index 705cedca7..d750c5813 100644 --- a/tox-loongsuite.ini +++ b/tox-loongsuite.ini @@ -125,10 +125,10 @@ deps = loongsuite-mcp: {[testenv]test_deps} loongsuite-mcp: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mcp/test-requirements.txt - loongsuite-mem0-oldest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mem0/test-requirements-oldest.txt + loongsuite-mem0-oldest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.oldest.txt loongsuite-mem0-latest: {[testenv]test_deps} - loongsuite-mem0-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mem0/test-requirements-latest.txt + loongsuite-mem0-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.latest.txt util-genai: {[testenv]test_deps} util-genai: -r {toxinidir}/util/opentelemetry-util-genai/test-requirements.txt From 0acd7b5a2f090d7a89a00499c527ccf603200c01 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Wed, 1 Apr 2026 17:25:34 +0800 Subject: [PATCH 4/9] fix readme Change-Id: Id06932c4f84250a4eb9c7d9ad0737b738ce29fcb Co-developed-by: Cursor --- .../README.md | 141 ++++++++++++++---- 1 file changed, 115 insertions(+), 26 deletions(-) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md index a4d95b1bc..08344f03d 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md @@ -1,41 +1,130 @@ # LoongSuite CoPaw Instrumentation -LongSuite instrumentation for [CoPaw](https://github.com/agentscope-ai/CoPaw) +LoongSuite instrumentation for [CoPaw](https://github.com/agentscope-ai/CoPaw) (personal assistant built on AgentScope). -## Scope +## Getting Started -- **P0 hook**: ``copaw.app.runner.runner.AgentRunner.query_handler`` — wraps the - full CoPaw “turn” (approval, commands, or ``CoPawAgent`` run). Emits a single - **Entry** span via ``ExtendedTelemetryHandler`` (``enter_ai_application_system``, - ``gen_ai.operation.name=enter``, ``gen_ai.span.kind=ENTRY``). -- **Streaming**: records ``gen_ai.response.time_to_first_token`` (nanoseconds) - after the first yielded chunk. -- **Custom attributes**: ``copaw.agent_id`` (from ``runner.agent_id``), - ``copaw.channel`` (from ``request.channel`` when present). -- **Session / user**: ``gen_ai.session.id`` and ``gen_ai.user.id`` when present on - the request object. -- **Agent / Tool / LLM**: use existing AgentScope (and LiteLLM, etc.) - instrumentations; this package does not duplicate those spans. +CoPaw is started as its own app (CLI / process entrypoint), not as a library you +embed with a few lines of `python your_script.py`. The practical approach is to +install CoPaw, enable LoongSuite **Site-bootstrap** so instrumentation loads +before CoPaw imports run, then start CoPaw with `copaw app`. -## Installation +### Step 1 — Install CoPaw ```bash -pip install loongsuite-instrumentation-copaw -pip install "copaw>=0.1.0" +pip install copaw ``` -## Usage +### Step 2 — Site-bootstrap -```python -from opentelemetry.instrumentation.copaw import CoPawInstrumentor +**Site-bootstrap** installs a **`.pth` hook** under `site-packages` so a small +bootstrap module runs very early in the interpreter, before CoPaw’s imports. +That path applies the same OpenTelemetry **auto-instrumentation** as +`loongsuite-instrument` / `sitecustomize`, so you do **not** edit CoPaw source +or wrap `copaw app` in a custom launcher. Installing `loongsuite-site-bootstrap` +does **not** install instrumentations by itself; pair it with `loongsuite-bootstrap` +(or equivalent `pip install` of the packages you need). -CoPawInstrumentor().instrument() -# start your CoPaw app -CoPawInstrumentor().uninstrument() +**2.1 — Install `loongsuite-site-bootstrap`** + +```bash +pip install loongsuite-site-bootstrap +``` + +**2.2 — Install instrumentations (including this package)** + +```bash +pip install loongsuite-instrumentation-copaw loongsuite-instrumentation-agentscope +``` + +**2.3 — Enable the hook** + +In every shell or service manager that starts CoPaw, set: + +```bash +export LOONGSUITE_PYTHON_SITE_BOOTSTRAP=True +``` + +The value is treated case-insensitively as on/off (`True` enables). You can also +put `"LOONGSUITE_PYTHON_SITE_BOOTSTRAP": "true"` in `bootstrap-config.json` +(see below); environment variables take **precedence** over the file for any key +that is already set in the process. + +**2.4 — Configure export via `~/.loongsuite/bootstrap-config.json`** + +Create the directory and file if needed. The JSON root must be an object; string +keys; values are applied to `os.environ` with **`setdefault`** semantics so +**already-set environment variables are never overwritten** by the file. + +Example for **OTLP/gRPC** (adjust host, port, and service name): + +```json +{ + "OTEL_SERVICE_NAME": "copaw", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://127.0.0.1:4317", + "OTEL_TRACES_EXPORTER": "otlp", + "OTEL_METRICS_EXPORTER": "otlp" +} ``` -## See also +Example for quick local debugging with **console** exporters: + +```json +{ + "OTEL_SERVICE_NAME": "copaw", + "OTEL_TRACES_EXPORTER": "console", + "OTEL_METRICS_EXPORTER": "console" +} +``` + +After a successful run you should see a line on stdout such as: +`loongsuite-site-bootstrap: started successfully (OpenTelemetry auto-instrumentation initialized).` +Do not start Python with `python -S` (that disables `site` and `.pth` processing). + +> **Beta / scope:** With the hook enabled, **every** Python process in that +> environment that imports `site` may load the bootstrap—not only `copaw app`. +> Use a dedicated virtual environment for production if you need isolation. + +### Step 3 — Run CoPaw + +With Site-bootstrap enabled in the same shell/session, start CoPaw as usual: + +```bash +copaw app +``` + +Telemetry for `AgentRunner.query_handler` (Entry span) is then active without +modifying CoPaw source code. + +### Optional: programmatic hook + +If you control an embedding process and prefer not to use site-bootstrap, you +can call `CoPawInstrumentor().instrument()` (and `uninstrument()` when done) +before CoPaw runs in that process—the hook point is still +`AgentRunner.query_handler`. You must still configure the global +`TracerProvider` / export (for example via OpenTelemetry env vars) consistently +with the rest of your app. + +## What this package instruments + +When you enable LoongSuite for CoPaw, each user or channel “turn” that goes +through CoPaw’s conversation runner produces **one application Entry trace** for +that turn (span name `enter_ai_application_system`). It covers the full path on +the CoPaw side—approval, built-in commands, or a normal agent run—not only the +LLM call inside the agent. + +**Recorded on that span (when the data is available):** + +- **Operation**: entry into the AI application (`gen_ai.operation.name=enter`, + `gen_ai.span.kind=ENTRY`). +- **Streaming**: time from the start of the turn to the first streamed chunk + (`gen_ai.response.time_to_first_token`, in nanoseconds). +- **Identity / routing**: session id (`gen_ai.session.id`), user id + (`gen_ai.user.id`), CoPaw agent id (`copaw.agent_id`), channel + (`copaw.channel`). -- Point analysis: ``.cursor/memory/instrumentation-locations-CoPaw-2026-04-01.md`` -- Semconv / util-genai mapping: ``.cursor/memory/semconv-analysis-CoPaw-2026-04-01.md`` +Calls to models, tools, and other AgentScope primitives are **not** duplicated +here: use AgentScope (and your existing model client) instrumentations alongside +this package so they appear as child spans under this entry when configured. From e553e52b559906f588e6f964837bf63f60a5ba68 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Wed, 1 Apr 2026 17:26:59 +0800 Subject: [PATCH 5/9] modify changelog Change-Id: Id97f3af859508e8e49cc70901642b3e566ca1e98 Co-developed-by: Cursor --- .../loongsuite-instrumentation-copaw/CHANGELOG.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md index b3060d1f4..ada6f274f 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md @@ -9,15 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Entry telemetry for ``AgentRunner.query_handler`` using - ``opentelemetry-util-genai`` ``ExtendedTelemetryHandler``: span name - ``enter_ai_application_system``, session/user and streaming TTFT where - applicable, plus ``copaw.agent_id`` and ``copaw.channel``. -- Helpers in ``_entry_utils`` to build ``EntryInvocation`` from handler args and - stream items. +- **CoPaw instrumentation initialization**: ``CoPawInstrumentor`` registers + automatic instrumentation for CoPaw when ``instrument()`` is called (included + in LoongSuite distro automatic injection). ### Changed -- Instrumentor now requires ``opentelemetry-util-genai`` and forwards - ``tracer_provider`` / ``meter_provider`` / ``logger_provider`` to the extended - handler. +- Instrumentor depends on ``opentelemetry-util-genai`` and passes + ``tracer_provider``, ``meter_provider``, and ``logger_provider`` from + ``instrument()`` into the shared GenAI telemetry handler. From 4abcc7f8c799795b0b5ee69a47b392dc1d99f9d9 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Wed, 1 Apr 2026 17:34:53 +0800 Subject: [PATCH 6/9] add PR number Change-Id: I6a1d48bee3a171ed0301d48b699edd2a04f8c7d5 Co-developed-by: Cursor --- .../loongsuite-instrumentation-copaw/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md index ada6f274f..d8773f297 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/CHANGELOG.md @@ -12,9 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **CoPaw instrumentation initialization**: ``CoPawInstrumentor`` registers automatic instrumentation for CoPaw when ``instrument()`` is called (included in LoongSuite distro automatic injection). + ([#162](https://github.com/alibaba/loongsuite-python-agent/pull/162)) ### Changed - Instrumentor depends on ``opentelemetry-util-genai`` and passes ``tracer_provider``, ``meter_provider``, and ``logger_provider`` from ``instrument()`` into the shared GenAI telemetry handler. + ([#162](https://github.com/alibaba/loongsuite-python-agent/pull/162)) From 2ed2db1d655f69e16313196de97f4412cc1961a6 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Wed, 1 Apr 2026 17:56:39 +0800 Subject: [PATCH 7/9] fix Change-Id: I4fa0e0a5a5a9d179d59bb8dd536ff8f1f76732dd Co-developed-by: Cursor --- instrumentation-loongsuite/README.md | 2 +- .../examples/basic_example.py | 34 ------------------- .../instrumentation/copaw/package.py | 2 +- .../instrumentation/copaw/patch.py | 33 ++++-------------- .../tests/test_instrument_smoke.py | 18 +++------- .../src/loongsuite/distro/bootstrap_gen.py | 4 +-- 6 files changed, 16 insertions(+), 77 deletions(-) delete mode 100644 instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py diff --git a/instrumentation-loongsuite/README.md b/instrumentation-loongsuite/README.md index e1d1d0b90..972588d7a 100644 --- a/instrumentation-loongsuite/README.md +++ b/instrumentation-loongsuite/README.md @@ -4,7 +4,7 @@ | [loongsuite-instrumentation-agentscope](./loongsuite-instrumentation-agentscope) | agentscope >= 1.0.0 | No | development | [loongsuite-instrumentation-agno](./loongsuite-instrumentation-agno) | agno | No | development | [loongsuite-instrumentation-claude-agent-sdk](./loongsuite-instrumentation-claude-agent-sdk) | claude-agent-sdk >= 0.1.0 | No | development -| [loongsuite-instrumentation-copaw](./loongsuite-instrumentation-copaw) | copaw >= 1.0.0 | No | development +| [loongsuite-instrumentation-copaw](./loongsuite-instrumentation-copaw) | copaw >= 0.1.0 | No | development | [loongsuite-instrumentation-crewai](./loongsuite-instrumentation-crewai) | crewai >= 0.80.0 | No | development | [loongsuite-instrumentation-dashscope](./loongsuite-instrumentation-dashscope) | dashscope >= 1.0.0 | No | development | [loongsuite-instrumentation-dify](./loongsuite-instrumentation-dify) | dify | No | development diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py deleted file mode 100644 index a12deb9b5..000000000 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/examples/basic_example.py +++ /dev/null @@ -1,34 +0,0 @@ -# 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. - -"""Example: enable CoPaw instrumentation before running the app.""" - -from __future__ import annotations - -import logging - -from opentelemetry.instrumentation.copaw import CoPawInstrumentor - - -def main() -> None: - logging.basicConfig(level=logging.INFO) - CoPawInstrumentor().instrument() - print( - "CoPaw instrumentation enabled (log-only phase). Run `copaw app` separately." - ) - CoPawInstrumentor().uninstrument() - - -if __name__ == "__main__": - main() diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/package.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/package.py index 114993add..0d7a89013 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/package.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/package.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -_instruments = ("copaw >= 1.0.0",) +_instruments = ("copaw >= 0.1.0",) diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py index 6b666e2e9..700e24767 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py @@ -35,12 +35,6 @@ _PATCH_TARGET = "AgentRunner.query_handler" -def _arg_summary(value: Any) -> str | int: - if isinstance(value, (list, tuple, str, bytes, dict)): - return len(value) - return type(value).__name__ - - def make_query_handler_wrapper( handler: ExtendedTelemetryHandler, ) -> Callable[..., Any]: @@ -53,14 +47,6 @@ def query_handler_wrapper( kwargs: Any, ) -> Any: async def _aiter(): - logger.info( - "[INSTRUMENTATION] Entering %s.%s agent_id=%r arg_summary=%s kwargs_keys=%s", - _MODULE_RUNNER, - _PATCH_TARGET, - getattr(instance, "agent_id", None), - [_arg_summary(a) for a in args], - sorted(kwargs.keys()), - ) msgs, request = parse_query_handler_call(args, kwargs) invocation = build_entry_invocation(instance, msgs, request) handler.start_entry(invocation) @@ -79,12 +65,6 @@ async def _aiter(): out = output_message_from_yield_item(item) if out is not None: last_assistant = out - logger.info( - "[INSTRUMENTATION] query_handler yield tuple_types=%s", - tuple(type(x).__name__ for x in item) - if isinstance(item, tuple) - else type(item).__name__, - ) yield item except BaseException as exc: if isinstance(exc, GeneratorExit): @@ -92,6 +72,13 @@ async def _aiter(): invocation.output_messages = [last_assistant] handler.stop_entry(invocation) raise + logger.debug( + "%s.%s raised %s", + _MODULE_RUNNER, + _PATCH_TARGET, + type(exc).__name__, + exc_info=True, + ) handler.fail_entry( invocation, Error( @@ -104,12 +91,6 @@ async def _aiter(): if last_assistant is not None: invocation.output_messages = [last_assistant] handler.stop_entry(invocation) - finally: - logger.info( - "[INSTRUMENTATION] Exiting %s.%s", - _MODULE_RUNNER, - _PATCH_TARGET, - ) return _aiter() diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py index 6ce356dec..826501e60 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/test_instrument_smoke.py @@ -16,7 +16,6 @@ from __future__ import annotations -import logging from types import SimpleNamespace import pytest @@ -30,13 +29,12 @@ @pytest.mark.asyncio -async def test_instrumented_query_handler_logs( +async def test_instrumented_query_handler_emits_entry_span( instrument, span_exporter, monkeypatch, - caplog, ): - """Short-circuit ``query_handler``; logs + exactly one Entry span.""" + """Short-circuit ``query_handler``; expect exactly one finished Entry span.""" from copaw.app.runner.runner import AgentRunner # noqa: PLC0415 @@ -55,17 +53,11 @@ async def fake_resolve(self, session_id, query): runner = AgentRunner(agent_id="smoke-test") req = SimpleNamespace(session_id="s1", user_id="u1", channel="console") - with caplog.at_level( - logging.INFO, logger="opentelemetry.instrumentation.copaw.patch" - ): - chunks = [] - async for item in runner.query_handler([], req): - chunks.append(item) + chunks = [] + async for item in runner.query_handler([], req): + chunks.append(item) assert len(chunks) == 1 - texts = " ".join(r.message for r in caplog.records) - assert "[INSTRUMENTATION] Entering" in texts - assert "[INSTRUMENTATION] Exiting" in texts assert len(span_exporter.get_finished_spans()) == 1 diff --git a/loongsuite-distro/src/loongsuite/distro/bootstrap_gen.py b/loongsuite-distro/src/loongsuite/distro/bootstrap_gen.py index 9efddecec..3e5c72b9a 100644 --- a/loongsuite-distro/src/loongsuite/distro/bootstrap_gen.py +++ b/loongsuite-distro/src/loongsuite/distro/bootstrap_gen.py @@ -229,8 +229,8 @@ "instrumentation": "loongsuite-instrumentation-claude-agent-sdk==0.4.0.dev", }, { - "library": "copaw >= 1.0.0", - "instrumentation": "loongsuite-instrumentation-copaw==0.1.0.dev", + "library": "copaw >= 0.1.0", + "instrumentation": "loongsuite-instrumentation-copaw==0.4.0.dev", }, { "library": "crewai >= 0.80.0", From d54b4bf22810d36dd1be71438c5b07d3d80b3295 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Wed, 1 Apr 2026 18:10:39 +0800 Subject: [PATCH 8/9] add copaw into supported instrumentations list Change-Id: I82f811fac4c7a1665efd9f420545e187d4f27eb0 Co-developed-by: Cursor --- README-zh.md | 1 + README.md | 3 +++ 2 files changed, 4 insertions(+) diff --git a/README-zh.md b/README-zh.md index 5d0e02a8b..e33acd275 100644 --- a/README-zh.md +++ b/README-zh.md @@ -33,6 +33,7 @@ LoongSuite Python Agent 同时也是上游 [OTel Python Agent](https://github.co | [AgentScope](https://github.com/agentscope-ai/agentscope) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-agentscope/README.md) | [PyPI](https://pypi.org/project/loongsuite-instrumentation-agentscope/) | | [Agno](https://github.com/agno-agi/agno) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-agno/README.md) | in dev | | [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk-python) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-claude-agent-sdk/README.md) | [PyPI](https://pypi.org/project/loongsuite-instrumentation-claude-agent-sdk/) | +| [CoPaw](https://github.com/agentscope-ai/CoPaw) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md) | [PyPI](https://pypi.org/project/loongsuite-instrumentation-copaw/) | | [CrewAI](https://github.com/crewAIInc/crewAI) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-crewai/README.md) | [PyPI](https://pypi.org/project/loongsuite-instrumentation-crewai/) | | [DashScope](https://github.com/dashscope/dashscope-sdk-python) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.md) | [PyPI](https://pypi.org/project/loongsuite-instrumentation-dashscope/) | | [Dify](https://github.com/langgenius/dify) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-dify/README.md) | in dev | diff --git a/README.md b/README.md index b803ddbf9..d45ed7e08 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Source tree: [`instrumentation-loongsuite/`](instrumentation-loongsuite). | [AgentScope](https://github.com/agentscope-ai/agentscope) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-agentscope/README.md) | [PyPI](https://pypi.org/project/loongsuite-instrumentation-agentscope/) | | [Agno](https://github.com/agno-agi/agno) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-agno/README.md) | in dev | | [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk-python) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-claude-agent-sdk/README.md) | [PyPI](https://pypi.org/project/loongsuite-instrumentation-claude-agent-sdk/) | +| [CoPaw](https://github.com/agentscope-ai/CoPaw) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-copaw/README.md) | [PyPI](https://pypi.org/project/loongsuite-instrumentation-copaw/) | | [CrewAI](https://github.com/crewAIInc/crewAI) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-crewai/README.md) | [PyPI](https://pypi.org/project/loongsuite-instrumentation-crewai/) | | [DashScope](https://github.com/dashscope/dashscope-sdk-python) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-dashscope/README.md) | [PyPI](https://pypi.org/project/loongsuite-instrumentation-dashscope/) | | [Dify](https://github.com/langgenius/dify) | [GUIDE](instrumentation-loongsuite/loongsuite-instrumentation-dify/README.md) | in dev | @@ -535,6 +536,8 @@ our [DingTalk group](https://qr.dingtalk.com/action/joingroup?code=v1,k1,mexukXI |----|----| | | | + + ## Resources * AgentScope: https://github.com/modelscope/agentscope * Observability Community: https://observability.cn \ No newline at end of file From e1ba67f4b79c5d3e3b9ddeee2f78341890fd1765 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Fri, 3 Apr 2026 12:54:50 +0800 Subject: [PATCH 9/9] feedback Change-Id: I737fdd2812ecb26742175650a4ce76d2e880380e Co-developed-by: Cursor --- README.md | 4 +-- dev-requirements.txt | 2 +- .../pyproject.toml | 2 +- .../instrumentation/copaw/__init__.py | 4 +-- .../instrumentation/copaw/patch.py | 2 +- .../tests/requirements.txt | 3 +++ .../tests/test-requirements.txt | 8 +++--- .../instrumentation/langgraph/__init__.py | 2 +- tox-loongsuite.ini | 25 +++++++++---------- 9 files changed, 27 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index d45ed7e08..a765f43d4 100644 --- a/README.md +++ b/README.md @@ -536,8 +536,6 @@ our [DingTalk group](https://qr.dingtalk.com/action/joingroup?code=v1,k1,mexukXI |----|----| | | | - - ## Resources * AgentScope: https://github.com/modelscope/agentscope -* Observability Community: https://observability.cn \ No newline at end of file +* Observability Community: https://observability.cn diff --git a/dev-requirements.txt b/dev-requirements.txt index a5bbb0a6b..c542b54b7 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -10,7 +10,7 @@ readme-renderer==42.0 bleach==4.1.0 # transient dependency for readme-renderer markupsafe>=2.0.1 codespell==2.1.0 -requests>=2.32.3 # LoongSuite Extension: Copaw requires requests>=2.32.3 +requests==2.32.4 # LoongSuite Extension: Copaw requires requests>=2.32.4 ruamel.yaml==0.17.21 flaky==3.7.0 pre-commit==3.7.0; python_version >= '3.9' diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml index 3d0fe5c94..19bba98dc 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/pyproject.toml @@ -25,7 +25,7 @@ classifiers = [ "Programming Language :: Python :: 3.13", ] dependencies = [ - "opentelemetry-api >= 1.37", + "opentelemetry-api ~= 1.37", "opentelemetry-instrumentation >= 0.58b0", "opentelemetry-semantic-conventions >= 0.58b0", "opentelemetry-util-genai", diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py index 9b827021a..a9ab59112 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/__init__.py @@ -13,7 +13,7 @@ # limitations under the License. """ -LongSuite CoPaw instrumentation (``copaw >= 0.1.0``). +LoongSuite CoPaw instrumentation (``copaw >= 0.1.0``). Instruments ``AgentRunner.query_handler`` with ``ExtendedTelemetryHandler.entry`` (``enter_ai_application_system``). Agent / tool / LLM spans come from AgentScope @@ -52,7 +52,7 @@ class CoPawInstrumentor(BaseInstrumentor): - """LongSuite instrumentor for CoPaw (Entry on ``AgentRunner.query_handler``).""" + """LoongSuite instrumentor for CoPaw (Entry on ``AgentRunner.query_handler``).""" def __init__(self) -> None: super().__init__() diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py index 700e24767..4480a11f5 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/src/opentelemetry/instrumentation/copaw/patch.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Wrap ``AgentRunner.query_handler`` with LongSuite Entry telemetry.""" +"""Wrap ``AgentRunner.query_handler`` with LoongSuite Entry telemetry.""" from __future__ import annotations diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt index 57eee6627..4822bea92 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt @@ -12,6 +12,9 @@ # 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 copaw latest supported version of external dependencies. + copaw==1.0.0 pytest pytest-asyncio diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-crewai/tests/test-requirements.txt b/instrumentation-loongsuite/loongsuite-instrumentation-crewai/tests/test-requirements.txt index e5ef2de3c..fa4338095 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-crewai/tests/test-requirements.txt +++ b/instrumentation-loongsuite/loongsuite-instrumentation-crewai/tests/test-requirements.txt @@ -26,10 +26,8 @@ # (e.g. ~=1.34.0), so we do NOT use {[testenv]test_deps} here to avoid # conflicts with the dev version from git main. - # This variant of the requirements aims to test the system using -# the newest supported version of external dependencies. - +# the crewai latest supported version of external dependencies. crewai>=0.80.0 litellm>=1.79.0 @@ -39,6 +37,10 @@ pysqlite3 vcrpy>=6.0.0 opentelemetry-test-utils pytest-recording>=0.13.0 +opentelemetry-api +opentelemetry-sdk +opentelemetry-semantic-conventions +opentelemetry-instrumentation -e util/opentelemetry-util-http -e util/opentelemetry-util-genai diff --git a/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/src/opentelemetry/instrumentation/langgraph/__init__.py b/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/src/opentelemetry/instrumentation/langgraph/__init__.py index 8a31f129c..364b3e9d1 100644 --- a/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/src/opentelemetry/instrumentation/langgraph/__init__.py +++ b/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/src/opentelemetry/instrumentation/langgraph/__init__.py @@ -13,7 +13,7 @@ # limitations under the License. """ -LongSuite LangGraph instrumentation supporting ``langgraph >= 0.2``. +LoongSuite LangGraph instrumentation supporting ``langgraph >= 0.2``. Usage ----- diff --git a/tox-loongsuite.ini b/tox-loongsuite.ini index d750c5813..345ffbac8 100644 --- a/tox-loongsuite.ini +++ b/tox-loongsuite.ini @@ -106,11 +106,11 @@ deps = google-adk-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/tests/requirements.latest.txt lint-loongsuite-instrumentation-google-adk: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-google-adk/tests/requirements.oldest.txt - loongsuite-agno: {[testenv]test_deps} - loongsuite-agno: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-agno/test-requirements.txt + agno: {[testenv]test_deps} + agno: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-agno/test-requirements.txt - loongsuite-dify: {[testenv]test_deps} - loongsuite-dify: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-dify/test-requirements.txt + dify: {[testenv]test_deps} + dify: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-dify/test-requirements.txt langchain-oldest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-langchain/tests/requirements.oldest.txt langchain-latest: {[testenv]test_deps} @@ -122,25 +122,24 @@ deps = langgraph-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/tests/requirements.latest.txt lint-loongsuite-instrumentation-langgraph: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-langgraph/tests/requirements.oldest.txt - loongsuite-mcp: {[testenv]test_deps} - loongsuite-mcp: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mcp/test-requirements.txt + mcp: {[testenv]test_deps} + mcp: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mcp/test-requirements.txt - loongsuite-mem0-oldest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.oldest.txt + mem0-oldest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.oldest.txt - loongsuite-mem0-latest: {[testenv]test_deps} - loongsuite-mem0-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.latest.txt + mem0-latest: {[testenv]test_deps} + mem0-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mem0/tests/requirements.latest.txt util-genai: {[testenv]test_deps} util-genai: -r {toxinidir}/util/opentelemetry-util-genai/test-requirements.txt util-genai: {toxinidir}/util/opentelemetry-util-genai - loongsuite-litellm: {[testenv]test_deps} - loongsuite-litellm: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-litellm/tests/test-requirements.txt + litellm: {[testenv]test_deps} + litellm: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-litellm/tests/test-requirements.txt - loongsuite-crewai: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-crewai/tests/test-requirements.txt + crewai: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-crewai/tests/test-requirements.txt copaw: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.txt - lint-loongsuite-instrumentation-copaw: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-copaw/tests/requirements.oldest.txt ; FIXME: add coverage testing allowlist_externals =