diff --git a/README.md b/README.md index bd59cb84c..14c3ac955 100644 --- a/README.md +++ b/README.md @@ -13,22 +13,22 @@ All instrumentations use [opentelemetry-util-genai](./util/opentelemetry-util-ge | Instrumentation | Supported Package | Version | | --------------- | ----------------- | ------- | -| [opentelemetry-instrumentation-genai-agno](./instrumentation/opentelemetry-instrumentation-genai-agno) | agno >= 2.0.0 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-agno/) | +| [opentelemetry-instrumentation-genai-agno](./instrumentation/opentelemetry-instrumentation-genai-agno) | agno >= 2.0.0, < 3 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-agno/) | | [opentelemetry-instrumentation-genai-anthropic](./instrumentation/opentelemetry-instrumentation-genai-anthropic) | anthropic >= 0.51.0, < 2 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-anthropic/) | -| [opentelemetry-instrumentation-genai-langchain](./instrumentation/opentelemetry-instrumentation-genai-langchain) | langchain >= 0.3.21 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-langchain/) | +| [opentelemetry-instrumentation-genai-langchain](./instrumentation/opentelemetry-instrumentation-genai-langchain) | langchain >= 0.3.21, < 2 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-langchain/) | | [opentelemetry-instrumentation-genai-openai](./instrumentation/opentelemetry-instrumentation-genai-openai) | openai >= 1.26.0, < 4 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-openai/) | -| [opentelemetry-instrumentation-genai-openai-agents](./instrumentation/opentelemetry-instrumentation-genai-openai-agents) | openai-agents >= 0.3.3 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-openai-agents/) | -| [opentelemetry-instrumentation-genai-qwen-agent](./instrumentation/opentelemetry-instrumentation-genai-qwen-agent) | qwen-agent >= 0.0.20 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-qwen-agent/) | -| [opentelemetry-instrumentation-genai-smolagents](./instrumentation/opentelemetry-instrumentation-genai-smolagents) | smolagents >= 1.24.0 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-smolagents/) | +| [opentelemetry-instrumentation-genai-openai-agents](./instrumentation/opentelemetry-instrumentation-genai-openai-agents) | openai-agents >= 0.3.3, < 1 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-openai-agents/) | +| [opentelemetry-instrumentation-genai-qwen-agent](./instrumentation/opentelemetry-instrumentation-genai-qwen-agent) | qwen-agent >= 0.0.20, < 1 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-qwen-agent/) | +| [opentelemetry-instrumentation-genai-smolagents](./instrumentation/opentelemetry-instrumentation-genai-smolagents) | smolagents >= 1.24.0, < 2 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-genai-smolagents/) | | [opentelemetry-instrumentation-google-genai](./instrumentation/opentelemetry-instrumentation-google-genai) | google-genai >= 1.32.0, <3 | [1.1b0](https://pypi.org/project/opentelemetry-instrumentation-google-genai/) | ## Unreleased Instrumentations | Instrumentation | Supported Package | Version | Status | | --------------- | ----------------- | ------- | ------ | -| [opentelemetry-instrumentation-genai-claude-agent-sdk](./instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk) | claude-agent-sdk >= 0.1.14 | 1.2b0.dev | skeleton | -| [opentelemetry-instrumentation-genai-crewai](./instrumentation/opentelemetry-instrumentation-genai-crewai) | crewai >= 1.10.1 | 1.2b0.dev | skeleton | -| [opentelemetry-instrumentation-genai-llama-index](./instrumentation/opentelemetry-instrumentation-genai-llama-index) | llama-index-core >= 0.14.19 | 1.2b0.dev | skeleton | +| [opentelemetry-instrumentation-genai-claude-agent-sdk](./instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk) | claude-agent-sdk >= 0.1.14, < 1 | 1.2b0.dev | skeleton | +| [opentelemetry-instrumentation-genai-crewai](./instrumentation/opentelemetry-instrumentation-genai-crewai) | crewai >= 1.10.1, < 2 | 1.2b0.dev | skeleton | +| [opentelemetry-instrumentation-genai-llama-index](./instrumentation/opentelemetry-instrumentation-genai-llama-index) | llama-index-core >= 0.14.19, < 1 | 1.2b0.dev | skeleton | | [opentelemetry-instrumentation-genai-weaviate-client](./instrumentation/opentelemetry-instrumentation-genai-weaviate-client) | weaviate-client >= 3.0.0, <5.0.0 | 1.2b0.dev | skeleton | diff --git a/instrumentation/opentelemetry-instrumentation-genai-agno/pyproject.toml b/instrumentation/opentelemetry-instrumentation-genai-agno/pyproject.toml index a4b53d926..059e13834 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-agno/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-genai-agno/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ ] [project.optional-dependencies] -instruments = ["agno >= 2.0.0"] +instruments = ["agno >= 2.0.0, < 3"] [project.entry-points.opentelemetry_instrumentor] agno = "opentelemetry.instrumentation.genai.agno:AgnoInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-genai-agno/src/opentelemetry/instrumentation/genai/agno/package.py b/instrumentation/opentelemetry-instrumentation-genai-agno/src/opentelemetry/instrumentation/genai/agno/package.py index 92dba2ee0..e1ea6266c 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-agno/src/opentelemetry/instrumentation/genai/agno/package.py +++ b/instrumentation/opentelemetry-instrumentation-genai-agno/src/opentelemetry/instrumentation/genai/agno/package.py @@ -1,4 +1,4 @@ # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 -_instruments = ("agno >= 2.0.0",) +_instruments = ("agno >= 2.0.0, < 3",) diff --git a/instrumentation/opentelemetry-instrumentation-genai-agno/tests/requirements.latest.txt b/instrumentation/opentelemetry-instrumentation-genai-agno/tests/requirements.latest.txt index 4706b0aeb..d8fe12fc1 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-agno/tests/requirements.latest.txt +++ b/instrumentation/opentelemetry-instrumentation-genai-agno/tests/requirements.latest.txt @@ -37,7 +37,7 @@ # This variant of the requirements aims to test the system using # the newest supported version of external dependencies. -agno +agno~=2.9.0 wrapt>=2.2.2 # test with the latest version of opentelemetry-api, sdk, semantic conventions, and instrumentation diff --git a/instrumentation/opentelemetry-instrumentation-genai-agno/tests/test_instrumentor.py b/instrumentation/opentelemetry-instrumentation-genai-agno/tests/test_instrumentor.py index d99055b3e..6c5187820 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-agno/tests/test_instrumentor.py +++ b/instrumentation/opentelemetry-instrumentation-genai-agno/tests/test_instrumentor.py @@ -24,7 +24,7 @@ def test_instrumentation_dependencies() -> None: assert dependencies is not None assert len(dependencies) > 0 - assert "agno >= 2.0.0" in dependencies + assert "agno >= 2.0.0, < 3" in dependencies def test_instrument_uninstrument_cycle( diff --git a/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/pyproject.toml b/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/pyproject.toml index 08375dc58..1dd7400d2 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/pyproject.toml @@ -31,7 +31,7 @@ dependencies = [ ] [project.optional-dependencies] -instruments = ["claude-agent-sdk >= 0.1.14"] +instruments = ["claude-agent-sdk >= 0.1.14, < 1"] [project.entry-points.opentelemetry_instrumentor] claude-agent-sdk = "opentelemetry.instrumentation.genai.claude_agent_sdk:ClaudeAgentSDKInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/src/opentelemetry/instrumentation/genai/claude_agent_sdk/package.py b/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/src/opentelemetry/instrumentation/genai/claude_agent_sdk/package.py index ef46f6e4b..16f084b69 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/src/opentelemetry/instrumentation/genai/claude_agent_sdk/package.py +++ b/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/src/opentelemetry/instrumentation/genai/claude_agent_sdk/package.py @@ -1,4 +1,4 @@ # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 -_instruments = ("claude-agent-sdk >= 0.1.14",) +_instruments = ("claude-agent-sdk >= 0.1.14, < 1",) diff --git a/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/tests/requirements.latest.txt b/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/tests/requirements.latest.txt index 1dbb4ecf3..19e55e942 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/tests/requirements.latest.txt +++ b/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/tests/requirements.latest.txt @@ -37,7 +37,7 @@ # This variant of the requirements aims to test the system using # the newest supported version of external dependencies. -claude-agent-sdk +claude-agent-sdk~=0.2.0 wrapt==2.2.2 # test with the latest version of opentelemetry-api, sdk, semantic conventions, and instrumentation diff --git a/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/tests/test_instrumentor.py b/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/tests/test_instrumentor.py index 56b3d4dfe..893f59ec0 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/tests/test_instrumentor.py +++ b/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/tests/test_instrumentor.py @@ -22,7 +22,7 @@ def test_instrumentation_dependencies(): assert dependencies is not None assert len(dependencies) > 0 - assert "claude-agent-sdk >= 0.1.14" in dependencies + assert "claude-agent-sdk >= 0.1.14, < 1" in dependencies def test_instrument_uninstrument_cycle( diff --git a/instrumentation/opentelemetry-instrumentation-genai-crewai/pyproject.toml b/instrumentation/opentelemetry-instrumentation-genai-crewai/pyproject.toml index 447561a84..527c5d67d 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-crewai/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-genai-crewai/pyproject.toml @@ -33,7 +33,7 @@ dependencies = [ [project.optional-dependencies] instruments = [ - "crewai >= 1.10.1", + "crewai >= 1.10.1, < 2", ] [project.entry-points.opentelemetry_instrumentor] diff --git a/instrumentation/opentelemetry-instrumentation-genai-crewai/src/opentelemetry/instrumentation/genai/crewai/package.py b/instrumentation/opentelemetry-instrumentation-genai-crewai/src/opentelemetry/instrumentation/genai/crewai/package.py index 0db470180..1dec38a96 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-crewai/src/opentelemetry/instrumentation/genai/crewai/package.py +++ b/instrumentation/opentelemetry-instrumentation-genai-crewai/src/opentelemetry/instrumentation/genai/crewai/package.py @@ -1,4 +1,4 @@ # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 -_instruments = ("crewai >= 1.10.1",) +_instruments = ("crewai >= 1.10.1, < 2",) diff --git a/instrumentation/opentelemetry-instrumentation-genai-crewai/tests/requirements.latest.txt b/instrumentation/opentelemetry-instrumentation-genai-crewai/tests/requirements.latest.txt index a943bf0d1..879462564 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-crewai/tests/requirements.latest.txt +++ b/instrumentation/opentelemetry-instrumentation-genai-crewai/tests/requirements.latest.txt @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 # Exercise the latest supported CrewAI release with workspace instrumentation. -crewai +crewai~=1.15.0 -e util/opentelemetry-util-genai -e instrumentation/opentelemetry-instrumentation-genai-crewai diff --git a/instrumentation/opentelemetry-instrumentation-genai-crewai/tests/test_instrumentor.py b/instrumentation/opentelemetry-instrumentation-genai-crewai/tests/test_instrumentor.py index db0c6080a..d8af3161a 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-crewai/tests/test_instrumentor.py +++ b/instrumentation/opentelemetry-instrumentation-genai-crewai/tests/test_instrumentor.py @@ -11,7 +11,7 @@ def test_instrumentation_dependencies() -> None: assert CrewAIInstrumentor().instrumentation_dependencies() == ( - "crewai >= 1.10.1", + "crewai >= 1.10.1, < 2", ) diff --git a/instrumentation/opentelemetry-instrumentation-genai-langchain/pyproject.toml b/instrumentation/opentelemetry-instrumentation-genai-langchain/pyproject.toml index ad4ab0331..8d897c4bf 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-langchain/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-genai-langchain/pyproject.toml @@ -31,7 +31,7 @@ dependencies = [ [project.optional-dependencies] instruments = [ - "langchain >= 0.3.21", + "langchain >= 0.3.21, < 2", ] [project.entry-points.opentelemetry_instrumentor] diff --git a/instrumentation/opentelemetry-instrumentation-genai-langchain/src/opentelemetry/instrumentation/genai/langchain/package.py b/instrumentation/opentelemetry-instrumentation-genai-langchain/src/opentelemetry/instrumentation/genai/langchain/package.py index b06cc0c50..74028c734 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-langchain/src/opentelemetry/instrumentation/genai/langchain/package.py +++ b/instrumentation/opentelemetry-instrumentation-genai-langchain/src/opentelemetry/instrumentation/genai/langchain/package.py @@ -2,4 +2,4 @@ # SPDX-License-Identifier: Apache-2.0 -_instruments = ("langchain >= 0.3.21",) +_instruments = ("langchain >= 0.3.21, < 2",) diff --git a/instrumentation/opentelemetry-instrumentation-genai-llama-index/pyproject.toml b/instrumentation/opentelemetry-instrumentation-genai-llama-index/pyproject.toml index 47bb2a27c..c45e3a7cc 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-llama-index/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-genai-llama-index/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ ] [project.optional-dependencies] -instruments = ["llama-index-core >= 0.14.19"] +instruments = ["llama-index-core >= 0.14.19, < 1"] [project.entry-points.opentelemetry_instrumentor] llama_index = "opentelemetry.instrumentation.genai.llama_index:LlamaIndexInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-genai-llama-index/src/opentelemetry/instrumentation/genai/llama_index/package.py b/instrumentation/opentelemetry-instrumentation-genai-llama-index/src/opentelemetry/instrumentation/genai/llama_index/package.py index 567b54fe0..e5f34c8fa 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-llama-index/src/opentelemetry/instrumentation/genai/llama_index/package.py +++ b/instrumentation/opentelemetry-instrumentation-genai-llama-index/src/opentelemetry/instrumentation/genai/llama_index/package.py @@ -1,4 +1,4 @@ # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 -_instruments = ("llama-index-core >= 0.14.19",) +_instruments = ("llama-index-core >= 0.14.19, < 1",) diff --git a/instrumentation/opentelemetry-instrumentation-genai-llama-index/tests/requirements.latest.txt b/instrumentation/opentelemetry-instrumentation-genai-llama-index/tests/requirements.latest.txt index 5b35542b1..c4172c1f8 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-llama-index/tests/requirements.latest.txt +++ b/instrumentation/opentelemetry-instrumentation-genai-llama-index/tests/requirements.latest.txt @@ -37,7 +37,7 @@ # This variant of the requirements aims to test the system using # the newest supported version of external dependencies. -llama-index-core +llama-index-core~=0.14.0 wrapt==2.2.2 # test with the latest version of opentelemetry-api, sdk, semantic conventions, and instrumentation diff --git a/instrumentation/opentelemetry-instrumentation-genai-openai-agents/pyproject.toml b/instrumentation/opentelemetry-instrumentation-genai-openai-agents/pyproject.toml index 41a304f43..e4bb62cf1 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-openai-agents/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-genai-openai-agents/pyproject.toml @@ -33,7 +33,7 @@ dependencies = [ [project.optional-dependencies] instruments = [ - "openai-agents >= 0.3.3", + "openai-agents >= 0.3.3, < 1", ] [project.entry-points.opentelemetry_instrumentor] diff --git a/instrumentation/opentelemetry-instrumentation-genai-openai-agents/src/opentelemetry/instrumentation/genai/openai_agents/package.py b/instrumentation/opentelemetry-instrumentation-genai-openai-agents/src/opentelemetry/instrumentation/genai/openai_agents/package.py index c5292e659..c3330beeb 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-openai-agents/src/opentelemetry/instrumentation/genai/openai_agents/package.py +++ b/instrumentation/opentelemetry-instrumentation-genai-openai-agents/src/opentelemetry/instrumentation/genai/openai_agents/package.py @@ -1,5 +1,5 @@ # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 -_instruments = ("openai-agents >= 0.3.3",) +_instruments = ("openai-agents >= 0.3.3, < 1",) _supports_metrics = False diff --git a/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/pyproject.toml b/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/pyproject.toml index 3bc66189b..82aca8d8e 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/pyproject.toml @@ -31,7 +31,7 @@ dependencies = [ ] [project.optional-dependencies] -instruments = ["qwen-agent >= 0.0.20"] +instruments = ["qwen-agent >= 0.0.20, < 1"] [project.entry-points.opentelemetry_instrumentor] qwen-agent = "opentelemetry.instrumentation.genai.qwen_agent:QwenAgentInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/src/opentelemetry/instrumentation/genai/qwen_agent/package.py b/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/src/opentelemetry/instrumentation/genai/qwen_agent/package.py index 6da1d31e5..6469f2eef 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/src/opentelemetry/instrumentation/genai/qwen_agent/package.py +++ b/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/src/opentelemetry/instrumentation/genai/qwen_agent/package.py @@ -1,4 +1,4 @@ # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 -_instruments = ("qwen-agent >= 0.0.20",) +_instruments = ("qwen-agent >= 0.0.20, < 1",) diff --git a/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/tests/test_instrumentor.py b/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/tests/test_instrumentor.py index 4e55f7943..8da64c93f 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/tests/test_instrumentor.py +++ b/instrumentation/opentelemetry-instrumentation-genai-qwen-agent/tests/test_instrumentor.py @@ -43,7 +43,7 @@ def fake_run(messages, **kwargs): def test_instrumentation_dependencies(): instrumentor = QwenAgentInstrumentor() dependencies = instrumentor.instrumentation_dependencies() - assert dependencies == ("qwen-agent >= 0.0.20",) + assert dependencies == ("qwen-agent >= 0.0.20, < 1",) def test_uninstrument_stops_span_creation( diff --git a/instrumentation/opentelemetry-instrumentation-genai-smolagents/pyproject.toml b/instrumentation/opentelemetry-instrumentation-genai-smolagents/pyproject.toml index 67140011a..3c8bd058d 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-smolagents/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-genai-smolagents/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ ] [project.optional-dependencies] -instruments = ["smolagents >= 1.24.0"] +instruments = ["smolagents >= 1.24.0, < 2"] [project.entry-points.opentelemetry_instrumentor] smolagents = "opentelemetry.instrumentation.genai.smolagents:SmolagentsInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-genai-smolagents/src/opentelemetry/instrumentation/genai/smolagents/package.py b/instrumentation/opentelemetry-instrumentation-genai-smolagents/src/opentelemetry/instrumentation/genai/smolagents/package.py index fa7223304..8a334a705 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-smolagents/src/opentelemetry/instrumentation/genai/smolagents/package.py +++ b/instrumentation/opentelemetry-instrumentation-genai-smolagents/src/opentelemetry/instrumentation/genai/smolagents/package.py @@ -1,6 +1,6 @@ # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 -_instruments = ("smolagents >= 1.24.0",) +_instruments = ("smolagents >= 1.24.0, < 2",) _supports_metrics = True diff --git a/instrumentation/opentelemetry-instrumentation-genai-smolagents/tests/requirements.latest.txt b/instrumentation/opentelemetry-instrumentation-genai-smolagents/tests/requirements.latest.txt index 3cdf75f33..70dbd3b38 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-smolagents/tests/requirements.latest.txt +++ b/instrumentation/opentelemetry-instrumentation-genai-smolagents/tests/requirements.latest.txt @@ -28,7 +28,7 @@ # The instrumented model classes run inference in this process and the tests stub # their runtimes, so no model backend extra is installed. -smolagents +smolagents~=1.26.0 wrapt>=2.2.2 -e util/opentelemetry-util-genai diff --git a/instrumentation/opentelemetry-instrumentation-genai-smolagents/tests/test_instrumentor.py b/instrumentation/opentelemetry-instrumentation-genai-smolagents/tests/test_instrumentor.py index c42d08d78..fcdaad6c3 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-smolagents/tests/test_instrumentor.py +++ b/instrumentation/opentelemetry-instrumentation-genai-smolagents/tests/test_instrumentor.py @@ -45,7 +45,7 @@ def test_entrypoint_loads_instrumentor() -> None: def test_instrumentation_dependencies() -> None: dependencies = SmolagentsInstrumentor().instrumentation_dependencies() - assert "smolagents >= 1.24.0" in dependencies + assert "smolagents >= 1.24.0, < 2" in dependencies def test_instrument_uninstrument_restores_originals( diff --git a/scripts/check_deps.py b/scripts/check_deps.py index 61b96e372..c5b0d3075 100755 --- a/scripts/check_deps.py +++ b/scripts/check_deps.py @@ -4,7 +4,13 @@ """Guard dependency invariants across packages. -1. Oldest dependency invariant: +1. Package runtime dependency specifier invariant: + Instrumentation packages declare their target library dependencies in [project.optional-dependencies] + `instruments` in pyproject.toml, and expose them at runtime via `_instruments` in `package.py`. + These two must match, and each dependency must declare both lower and upper bounds (e.g., `>= x.y.z, < (x+1)`) + to ensure version compatibility and prevent unbounded dependencies. + +2. Oldest dependency invariant: The oldest tox envs install the lowest versions of each package's *declared* deps straight from pyproject.toml via ``UV_RESOLUTION=lowest-direct`` (see AGENTS.md). pyproject.toml is therefore the single source of truth for those floors and running the env is what validates them. This script @@ -21,10 +27,10 @@ tests/requirements.oldest.txt must install it locally so tests can run against the local development version. -2. Package runtime dependency specifier invariant: - Instrumentation packages declare their target library dependencies in [project.optional-dependencies] - `instruments` in pyproject.toml, and expose them at runtime via `_instruments` in `package.py`. - These two must match to ensure runtime instrumentor compatibility checks and package metadata stay in sync. +3. Latest dependency pinning invariant: + Target library dependencies in tests/requirements.latest.txt must have upper bounds or pins + (e.g., `~= major.minor` or `== major.minor.patch`) to prevent newly released major versions from + breaking test runs unexpectedly. """ from __future__ import annotations @@ -240,21 +246,28 @@ def declared_dep_names(pyproject: dict) -> set[str]: } -def pinned_names(oldest_req_path: Path) -> set[str]: - """Canonical names of every pinned requirement in an oldest requirements file. - - Skips option lines (-e/-r/-c/--flag) and anything that isn't a parseable requirement. - """ - names: set[str] = set() - for raw in oldest_req_path.read_text(encoding="utf-8").splitlines(): +def parse_requirements_file(path: Path) -> list[Requirement]: + """Extract valid Requirements from a requirements file, skipping options and comments.""" + reqs: list[Requirement] = [] + for raw in path.read_text(encoding="utf-8").splitlines(): line = raw.split("#", 1)[0].strip() if not line or line.startswith("-"): continue try: - names.add(canonicalize_name(Requirement(line).name)) + reqs.append(Requirement(line)) except Exception: continue - return names + return reqs + + +def has_lower_bound(req: Requirement) -> bool: + """Check if requirement has a lower bound (>=, >, ~=, ==).""" + return any(s.operator in (">=", ">", "~=", "==") for s in req.specifier) + + +def has_upper_bound(req: Requirement) -> bool: + """Check if requirement has an upper bound (<, <=, ~=, ==).""" + return any(s.operator in ("<", "<=", "~=", "==") for s in req.specifier) def extract_instruments_from_package_py( @@ -355,6 +368,75 @@ def check_instruments_match(pkg_dir: Path, pyproject: dict) -> list[str]: f"does not match pyproject.toml instruments extra ({pyproject_instruments_raw})." ) + for req in sorted(pyproject_reqs, key=lambda r: str(r)): + if not has_lower_bound(req): + errors.append( + f"{pkg_dir.name}: requirement '{req}' in pyproject.toml instruments extra is missing a lower bound (e.g. '>= x.y.z')." + ) + if not has_upper_bound(req): + errors.append( + f"{pkg_dir.name}: requirement '{req}' in pyproject.toml instruments extra is missing an upper bound (e.g. '< 2')." + ) + + return errors + + +def check_oldest_requirements(pkg_dir: Path, pyproject: dict) -> list[str]: + """Check oldest requirements coverage and redundancy.""" + errors: list[str] = [] + oldest = pkg_dir / "tests" / "requirements.oldest.txt" + latest = pkg_dir / "tests" / "requirements.latest.txt" + + if not oldest.exists(): + if latest.exists(): + errors.append( + f"{pkg_dir.name}: has tests/requirements.latest.txt but no " + f"tests/requirements.oldest.txt - declared floors are never tested." + ) + return errors + + pinned = { + canonicalize_name(r.name) for r in parse_requirements_file(oldest) + } + redundant = declared_dep_names(pyproject) & pinned + for name in sorted(redundant): + errors.append( + f"{pkg_dir.name}: '{name}' is declared in pyproject.toml and also pinned in " + f"tests/requirements.oldest.txt. Remove the pin - the oldest env derives it from " + f"the pyproject.toml floor via UV_RESOLUTION=lowest-direct." + ) + + return errors + + +def check_latest_requirements(pkg_dir: Path, pyproject: dict) -> list[str]: + """Verify that target dependencies in tests/requirements.latest.txt have upper bounds / pins.""" + errors: list[str] = [] + latest_path = pkg_dir / "tests" / "requirements.latest.txt" + if not latest_path.exists(): + return errors + + instruments_raw = ( + pyproject.get("project", {}) + .get("optional-dependencies", {}) + .get("instruments", []) + ) + if not instruments_raw: + return errors + + instrumented_names = { + canonicalize_name(Requirement(r).name) for r in instruments_raw + } + + for req in parse_requirements_file(latest_path): + if canonicalize_name( + req.name + ) in instrumented_names and not has_upper_bound(req): + errors.append( + f"{pkg_dir.name}: target dependency '{req}' in tests/requirements.latest.txt " + f"is missing an upper bound or pin (use '~= major.minor' or '== major.minor.patch')." + ) + return errors @@ -370,33 +452,19 @@ def main() -> int: for pyproject_path in pyprojects: pkg_dir = pyproject_path.parent - oldest = pkg_dir / "tests" / "requirements.oldest.txt" - latest = pkg_dir / "tests" / "requirements.latest.txt" - pyproject = tomllib.loads(pyproject_path.read_text(encoding="utf-8")) # Check 1: instruments extra in pyproject.toml matches _instruments in package.py errors.extend(check_instruments_match(pkg_dir, pyproject)) # Check 2: oldest dependency coverage and redundancy - if not oldest.exists(): - # Only a gap if the package has an oldest tox factor, signalled by a latest file. - if latest.exists(): - errors.append( - f"{pkg_dir.name}: has tests/requirements.latest.txt but no " - f"tests/requirements.oldest.txt - declared floors are never tested." - ) - continue + errors.extend(check_oldest_requirements(pkg_dir, pyproject)) - redundant = declared_dep_names(pyproject) & pinned_names(oldest) - for name in sorted(redundant): - errors.append( - f"{pkg_dir.name}: '{name}' is declared in pyproject.toml and also pinned in " - f"tests/requirements.oldest.txt. Remove the pin - the oldest env derives it from " - f"the pyproject.toml floor via UV_RESOLUTION=lowest-direct." - ) + # Check 3: target dependencies in requirements.latest.txt are pinned / upper-bounded + errors.extend(check_latest_requirements(pkg_dir, pyproject)) - # Check 3: workspace dependencies floor and editable install validation + # Check 4: workspace dependencies floor and editable install validation + oldest = pkg_dir / "tests" / "requirements.oldest.txt" errors.extend( check_workspace_dependencies( pkg_dir, @@ -413,9 +481,7 @@ def main() -> int: print(f" [ERROR] {err}", file=sys.stderr) return 1 - print( - "Dependency checks passed: package.py matches pyproject.toml, no declared deps re-pinned, no missing coverage, workspace dependency floors validated." - ) + print("Dependency checks passed.") return 0 diff --git a/util/opentelemetry-util-genai/tests/test_check_deps.py b/util/opentelemetry-util-genai/tests/test_check_deps.py index baf1566e7..8cbf0ea11 100644 --- a/util/opentelemetry-util-genai/tests/test_check_deps.py +++ b/util/opentelemetry-util-genai/tests/test_check_deps.py @@ -11,7 +11,11 @@ scripts_dir = str(repo_root / "scripts") sys.path.insert(0, scripts_dir) try: - from check_deps import check_workspace_dependencies + from check_deps import ( + check_instruments_match, + check_latest_requirements, + check_workspace_dependencies, + ) finally: if scripts_dir in sys.path: sys.path.remove(scripts_dir) @@ -252,3 +256,117 @@ def test_extraneous_non_editable_local_path_fails(self): ) self.assertEqual(len(errors), 1) self.assertIn("is not permitted", errors[0]) + + +class TestCheckInstrumentsMatch(unittest.TestCase): + def setUp(self): + self.temp_dir = tempfile.TemporaryDirectory() + self.pkg_dir = Path(self.temp_dir.name) + self.src_dir = ( + self.pkg_dir + / "src" + / "opentelemetry" + / "instrumentation" + / "genai" + / "test_pkg" + ) + self.src_dir.mkdir(parents=True, exist_ok=True) + + def tearDown(self): + self.temp_dir.cleanup() + + def test_matching_with_bounds_passes(self): + (self.src_dir / "package.py").write_text( + '_instruments = ("some-pkg >= 1.0.0, < 2",)\n', + encoding="utf-8", + ) + pyproject = { + "project": { + "optional-dependencies": { + "instruments": ["some-pkg >= 1.0.0, < 2"] + } + } + } + errors = check_instruments_match(self.pkg_dir, pyproject) + self.assertEqual(errors, []) + + def test_missing_upper_bound_fails(self): + (self.src_dir / "package.py").write_text( + '_instruments = ("some-pkg >= 1.0.0",)\n', + encoding="utf-8", + ) + pyproject = { + "project": { + "optional-dependencies": {"instruments": ["some-pkg >= 1.0.0"]} + } + } + errors = check_instruments_match(self.pkg_dir, pyproject) + self.assertEqual(len(errors), 1) + self.assertIn("missing an upper bound", errors[0]) + + def test_missing_lower_bound_fails(self): + (self.src_dir / "package.py").write_text( + '_instruments = ("some-pkg < 2",)\n', + encoding="utf-8", + ) + pyproject = { + "project": { + "optional-dependencies": {"instruments": ["some-pkg < 2"]} + } + } + errors = check_instruments_match(self.pkg_dir, pyproject) + self.assertEqual(len(errors), 1) + self.assertIn("missing a lower bound", errors[0]) + + def test_mismatch_fails(self): + (self.src_dir / "package.py").write_text( + '_instruments = ("some-pkg >= 1.0.0, < 2",)\n', + encoding="utf-8", + ) + pyproject = { + "project": { + "optional-dependencies": { + "instruments": ["other-pkg >= 1.0.0, < 2"] + } + } + } + errors = check_instruments_match(self.pkg_dir, pyproject) + self.assertEqual(len(errors), 1) + self.assertIn("does not match", errors[0]) + + +class TestCheckLatestRequirements(unittest.TestCase): + def setUp(self): + self.temp_dir = tempfile.TemporaryDirectory() + self.pkg_dir = Path(self.temp_dir.name) + self.tests_dir = self.pkg_dir / "tests" + self.tests_dir.mkdir(parents=True, exist_ok=True) + self.latest_path = self.tests_dir / "requirements.latest.txt" + + def tearDown(self): + self.temp_dir.cleanup() + + def test_latest_pinned_passes(self): + self.latest_path.write_text("some-pkg ~= 1.0\n", encoding="utf-8") + pyproject = { + "project": { + "optional-dependencies": { + "instruments": ["some-pkg >= 1.0.0, < 2"] + } + } + } + errors = check_latest_requirements(self.pkg_dir, pyproject) + self.assertEqual(errors, []) + + def test_latest_unbounded_fails(self): + self.latest_path.write_text("some-pkg >= 1.0\n", encoding="utf-8") + pyproject = { + "project": { + "optional-dependencies": { + "instruments": ["some-pkg >= 1.0.0, < 2"] + } + } + } + errors = check_latest_requirements(self.pkg_dir, pyproject) + self.assertEqual(len(errors), 1) + self.assertIn("missing an upper bound or pin", errors[0]) diff --git a/uv.lock b/uv.lock index c3fa70a19..701ed135c 100644 --- a/uv.lock +++ b/uv.lock @@ -3342,7 +3342,7 @@ instruments = [ [package.metadata] requires-dist = [ - { name = "agno", marker = "extra == 'instruments'", specifier = ">=2.0.0" }, + { name = "agno", marker = "extra == 'instruments'", specifier = ">=2.0.0,<3" }, { name = "opentelemetry-api", specifier = "~=1.43" }, { name = "opentelemetry-instrumentation", specifier = ">=0.64b0,<1" }, { name = "opentelemetry-semantic-conventions", specifier = ">=0.64b0,<1" }, @@ -3392,7 +3392,7 @@ instruments = [ [package.metadata] requires-dist = [ - { name = "claude-agent-sdk", marker = "extra == 'instruments'", specifier = ">=0.1.14" }, + { name = "claude-agent-sdk", marker = "extra == 'instruments'", specifier = ">=0.1.14,<1" }, { name = "opentelemetry-api", specifier = "~=1.43" }, { name = "opentelemetry-instrumentation", specifier = ">=0.64b0,<1" }, { name = "opentelemetry-semantic-conventions", specifier = ">=0.64b0,<1" }, @@ -3417,7 +3417,7 @@ instruments = [ [package.metadata] requires-dist = [ - { name = "crewai", marker = "extra == 'instruments'", specifier = ">=1.10.1" }, + { name = "crewai", marker = "extra == 'instruments'", specifier = ">=1.10.1,<2" }, { name = "opentelemetry-api", specifier = "~=1.43" }, { name = "opentelemetry-instrumentation", specifier = ">=0.64b0,<1" }, { name = "opentelemetry-semantic-conventions", specifier = ">=0.64b0,<1" }, @@ -3440,7 +3440,7 @@ instruments = [ [package.metadata] requires-dist = [ - { name = "langchain", marker = "extra == 'instruments'", specifier = ">=0.3.21" }, + { name = "langchain", marker = "extra == 'instruments'", specifier = ">=0.3.21,<2" }, { name = "opentelemetry-instrumentation", specifier = ">=0.64b0,<1" }, { name = "opentelemetry-util-genai", editable = "util/opentelemetry-util-genai" }, ] @@ -3463,7 +3463,7 @@ instruments = [ [package.metadata] requires-dist = [ - { name = "llama-index-core", marker = "extra == 'instruments'", specifier = ">=0.14.19" }, + { name = "llama-index-core", marker = "extra == 'instruments'", specifier = ">=0.14.19,<1" }, { name = "opentelemetry-api", specifier = "~=1.43" }, { name = "opentelemetry-instrumentation", specifier = ">=0.64b0,<1" }, { name = "opentelemetry-semantic-conventions", specifier = ">=0.64b0,<1" }, @@ -3513,7 +3513,7 @@ instruments = [ [package.metadata] requires-dist = [ - { name = "openai-agents", marker = "extra == 'instruments'", specifier = ">=0.3.3" }, + { name = "openai-agents", marker = "extra == 'instruments'", specifier = ">=0.3.3,<1" }, { name = "opentelemetry-api", specifier = "~=1.43" }, { name = "opentelemetry-instrumentation", specifier = ">=0.64b0,<1" }, { name = "opentelemetry-semantic-conventions", specifier = ">=0.64b0,<1" }, @@ -3542,7 +3542,7 @@ requires-dist = [ { name = "opentelemetry-instrumentation", specifier = ">=0.64b0,<1" }, { name = "opentelemetry-semantic-conventions", specifier = ">=0.64b0,<1" }, { name = "opentelemetry-util-genai", editable = "util/opentelemetry-util-genai" }, - { name = "qwen-agent", marker = "extra == 'instruments'", specifier = ">=0.0.20" }, + { name = "qwen-agent", marker = "extra == 'instruments'", specifier = ">=0.0.20,<1" }, ] provides-extras = ["instruments"] @@ -3567,7 +3567,7 @@ requires-dist = [ { name = "opentelemetry-instrumentation", specifier = ">=0.64b0,<1" }, { name = "opentelemetry-semantic-conventions", specifier = ">=0.64b0,<1" }, { name = "opentelemetry-util-genai", editable = "util/opentelemetry-util-genai" }, - { name = "smolagents", marker = "extra == 'instruments'", specifier = ">=1.24.0" }, + { name = "smolagents", marker = "extra == 'instruments'", specifier = ">=1.24.0,<2" }, ] provides-extras = ["instruments"]