diff --git a/.github/workflows/build_deploy.yml b/.github/workflows/build_deploy.yml
index bc6a8b0b3d2..1a13a751d29 100644
--- a/.github/workflows/build_deploy.yml
+++ b/.github/workflows/build_deploy.yml
@@ -11,6 +11,8 @@ on:
- build_deploy*
- 'upgrade-latest-*'
- 'mq-working-branch**'
+ # TODO: Remove this after 3.x work is done
+ - 3.x-staging
pull_request:
release:
types:
diff --git a/.riot/requirements/1460efe.txt b/.riot/requirements/1460efe.txt
new file mode 100644
index 00000000000..88d3edb3c68
--- /dev/null
+++ b/.riot/requirements/1460efe.txt
@@ -0,0 +1,47 @@
+#
+# This file is autogenerated by pip-compile with Python 3.10
+# by the following command:
+#
+# pip-compile --allow-unsafe --no-annotate .riot/requirements/1460efe.in
+#
+attrs==25.1.0
+boto3==1.36.10
+botocore==1.36.10
+bytecode==0.16.1
+certifi==2024.12.14
+charset-normalizer==3.4.1
+coverage[toml]==7.6.10
+datadog==0.51.0
+datadog-lambda==6.105.0
+ddtrace==2.20.0
+deprecated==1.2.18
+envier==0.5.2
+exceptiongroup==1.2.2
+hypothesis==6.45.0
+idna==3.10
+importlib-metadata==8.5.0
+iniconfig==2.0.0
+jmespath==1.0.1
+mock==5.1.0
+opentelemetry-api==1.29.0
+opentracing==2.4.0
+packaging==24.2
+pluggy==1.5.0
+protobuf==5.29.3
+pytest==8.3.4
+pytest-asyncio==0.21.1
+pytest-cov==6.0.0
+pytest-mock==3.14.0
+pytest-randomly==3.16.0
+python-dateutil==2.9.0.post0
+requests==2.32.3
+s3transfer==0.11.2
+six==1.17.0
+sortedcontainers==2.4.0
+tomli==2.2.1
+typing-extensions==4.12.2
+ujson==5.10.0
+urllib3==2.3.0
+wrapt==1.17.2
+xmltodict==0.14.2
+zipp==3.21.0
diff --git a/.riot/requirements/16af7e0.txt b/.riot/requirements/16af7e0.txt
index df479a84c64..8ade9c10320 100644
--- a/.riot/requirements/16af7e0.txt
+++ b/.riot/requirements/16af7e0.txt
@@ -12,10 +12,10 @@ cattrs==23.2.3
certifi==2024.7.4
charset-normalizer==3.3.2
coverage[toml]==7.5.4
-datadog==0.49.1
-datadog-lambda==6.96.0
+datadog==0.51.0
+datadog-lambda==6.105.0
ddsketch==3.0.1
-ddtrace==2.9.2
+ddtrace==2.20.0
deprecated==1.2.14
envier==0.5.2
exceptiongroup==1.2.1
diff --git a/.riot/requirements/1965d6b.txt b/.riot/requirements/1965d6b.txt
new file mode 100644
index 00000000000..71a4f91d8cf
--- /dev/null
+++ b/.riot/requirements/1965d6b.txt
@@ -0,0 +1,45 @@
+#
+# This file is autogenerated by pip-compile with Python 3.12
+# by the following command:
+#
+# pip-compile --allow-unsafe --no-annotate .riot/requirements/1965d6b.in
+#
+attrs==25.1.0
+boto3==1.36.10
+botocore==1.36.10
+bytecode==0.16.1
+certifi==2024.12.14
+charset-normalizer==3.4.1
+coverage[toml]==7.6.10
+datadog==0.51.0
+datadog-lambda==6.105.0
+ddtrace==2.20.0
+deprecated==1.2.18
+envier==0.5.2
+hypothesis==6.45.0
+idna==3.10
+importlib-metadata==8.5.0
+iniconfig==2.0.0
+jmespath==1.0.1
+mock==5.1.0
+opentelemetry-api==1.29.0
+opentracing==2.4.0
+packaging==24.2
+pluggy==1.5.0
+protobuf==5.29.3
+pytest==8.3.4
+pytest-asyncio==0.21.1
+pytest-cov==6.0.0
+pytest-mock==3.14.0
+pytest-randomly==3.16.0
+python-dateutil==2.9.0.post0
+requests==2.32.3
+s3transfer==0.11.2
+six==1.17.0
+sortedcontainers==2.4.0
+typing-extensions==4.12.2
+ujson==5.10.0
+urllib3==2.3.0
+wrapt==1.17.2
+xmltodict==0.14.2
+zipp==3.21.0
diff --git a/.riot/requirements/1aaf6f6.txt b/.riot/requirements/1aaf6f6.txt
deleted file mode 100644
index 5c36c6f9871..00000000000
--- a/.riot/requirements/1aaf6f6.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# This file is autogenerated by pip-compile with Python 3.8
-# by the following command:
-#
-# pip-compile --no-annotate --resolver=backtracking .riot/requirements/1aaf6f6.in
-#
-attrs==23.2.0
-boto3==1.34.139
-botocore==1.34.139
-bytecode==0.15.1
-cattrs==23.2.3
-certifi==2024.7.4
-charset-normalizer==3.3.2
-coverage[toml]==7.5.4
-datadog==0.49.1
-datadog-lambda==6.96.0
-ddsketch==3.0.1
-ddtrace==2.9.2
-deprecated==1.2.14
-envier==0.5.2
-exceptiongroup==1.2.1
-hypothesis==6.45.0
-idna==3.7
-importlib-metadata==7.1.0
-iniconfig==2.0.0
-jmespath==1.0.1
-mock==5.1.0
-opentelemetry-api==1.26.0
-opentracing==2.4.0
-packaging==24.1
-pluggy==1.5.0
-protobuf==5.27.2
-pytest==8.2.2
-pytest-asyncio==0.21.1
-pytest-cov==5.0.0
-pytest-mock==3.14.0
-pytest-randomly==3.15.0
-python-dateutil==2.9.0.post0
-requests==2.32.3
-s3transfer==0.10.2
-six==1.16.0
-sortedcontainers==2.4.0
-tomli==2.0.1
-typing-extensions==4.12.2
-ujson==5.10.0
-urllib3==1.26.19
-wrapt==1.16.0
-xmltodict==0.13.0
-zipp==3.19.2
diff --git a/.riot/requirements/1aec773.txt b/.riot/requirements/1aec773.txt
new file mode 100644
index 00000000000..813b6aa028c
--- /dev/null
+++ b/.riot/requirements/1aec773.txt
@@ -0,0 +1,45 @@
+#
+# This file is autogenerated by pip-compile with Python 3.11
+# by the following command:
+#
+# pip-compile --allow-unsafe --no-annotate .riot/requirements/1aec773.in
+#
+attrs==25.1.0
+boto3==1.36.10
+botocore==1.36.10
+bytecode==0.16.1
+certifi==2024.12.14
+charset-normalizer==3.4.1
+coverage[toml]==7.6.10
+datadog==0.51.0
+datadog-lambda==6.105.0
+ddtrace==2.20.0
+deprecated==1.2.18
+envier==0.5.2
+hypothesis==6.45.0
+idna==3.10
+importlib-metadata==8.5.0
+iniconfig==2.0.0
+jmespath==1.0.1
+mock==5.1.0
+opentelemetry-api==1.29.0
+opentracing==2.4.0
+packaging==24.2
+pluggy==1.5.0
+protobuf==5.29.3
+pytest==8.3.4
+pytest-asyncio==0.21.1
+pytest-cov==6.0.0
+pytest-mock==3.14.0
+pytest-randomly==3.16.0
+python-dateutil==2.9.0.post0
+requests==2.32.3
+s3transfer==0.11.2
+six==1.17.0
+sortedcontainers==2.4.0
+typing-extensions==4.12.2
+ujson==5.10.0
+urllib3==2.3.0
+wrapt==1.17.2
+xmltodict==0.14.2
+zipp==3.21.0
diff --git a/.riot/requirements/1ecfbd7.txt b/.riot/requirements/1ecfbd7.txt
new file mode 100644
index 00000000000..165bdc2dde6
--- /dev/null
+++ b/.riot/requirements/1ecfbd7.txt
@@ -0,0 +1,46 @@
+#
+# This file is autogenerated by pip-compile with Python 3.13
+# by the following command:
+#
+# pip-compile --allow-unsafe --no-annotate .riot/requirements/1ecfbd7.in
+#
+attrs==25.1.0
+boto3==1.36.10
+botocore==1.36.10
+bytecode==0.16.1
+certifi==2024.12.14
+charset-normalizer==3.4.1
+coverage[toml]==7.6.10
+datadog==0.51.0
+datadog-lambda==6.105.0
+ddtrace==2.20.0
+deprecated==1.2.18
+envier==0.5.2
+hypothesis==6.45.0
+idna==3.10
+importlib-metadata==8.5.0
+iniconfig==2.0.0
+jmespath==1.0.1
+legacy-cgi==2.6.2
+mock==5.1.0
+opentelemetry-api==1.29.0
+opentracing==2.4.0
+packaging==24.2
+pluggy==1.5.0
+protobuf==5.29.3
+pytest==8.3.4
+pytest-asyncio==0.21.1
+pytest-cov==6.0.0
+pytest-mock==3.14.0
+pytest-randomly==3.16.0
+python-dateutil==2.9.0.post0
+requests==2.32.3
+s3transfer==0.11.2
+six==1.17.0
+sortedcontainers==2.4.0
+typing-extensions==4.12.2
+ujson==5.10.0
+urllib3==2.3.0
+wrapt==1.17.2
+xmltodict==0.14.2
+zipp==3.21.0
diff --git a/.riot/requirements/1fa807e.txt b/.riot/requirements/1fa807e.txt
index ca1c67d95b6..445f66032c8 100644
--- a/.riot/requirements/1fa807e.txt
+++ b/.riot/requirements/1fa807e.txt
@@ -12,10 +12,10 @@ cattrs==23.2.3
certifi==2024.7.4
charset-normalizer==3.3.2
coverage[toml]==7.5.4
-datadog==0.49.1
-datadog-lambda==6.96.0
+datadog==0.51.0
+datadog-lambda==6.105.0
ddsketch==3.0.1
-ddtrace==2.9.2
+ddtrace==2.20.0
deprecated==1.2.14
envier==0.5.2
exceptiongroup==1.2.1
diff --git a/.riot/requirements/6824c99.txt b/.riot/requirements/6824c99.txt
new file mode 100644
index 00000000000..d4bb270d8d0
--- /dev/null
+++ b/.riot/requirements/6824c99.txt
@@ -0,0 +1,47 @@
+#
+# This file is autogenerated by pip-compile with Python 3.8
+# by the following command:
+#
+# pip-compile --allow-unsafe --no-annotate .riot/requirements/6824c99.in
+#
+attrs==25.1.0
+boto3==1.36.10
+botocore==1.36.10
+bytecode==0.16.1
+certifi==2024.12.14
+charset-normalizer==3.4.1
+coverage[toml]==7.6.1
+datadog==0.51.0
+datadog-lambda==6.105.0
+ddtrace==2.20.0
+deprecated==1.2.18
+envier==0.5.2
+exceptiongroup==1.2.2
+hypothesis==6.45.0
+idna==3.10
+importlib-metadata==8.5.0
+iniconfig==2.0.0
+jmespath==1.0.1
+mock==5.1.0
+opentelemetry-api==1.29.0
+opentracing==2.4.0
+packaging==24.2
+pluggy==1.5.0
+protobuf==5.29.3
+pytest==8.3.4
+pytest-asyncio==0.21.1
+pytest-cov==5.0.0
+pytest-mock==3.14.0
+pytest-randomly==3.15.0
+python-dateutil==2.9.0.post0
+requests==2.32.3
+s3transfer==0.11.2
+six==1.17.0
+sortedcontainers==2.4.0
+tomli==2.2.1
+typing-extensions==4.12.2
+ujson==5.10.0
+urllib3==1.26.20
+wrapt==1.17.2
+xmltodict==0.14.2
+zipp==3.20.2
diff --git a/.riot/requirements/7cf5b29.txt b/.riot/requirements/7cf5b29.txt
new file mode 100644
index 00000000000..071c7d7fd7e
--- /dev/null
+++ b/.riot/requirements/7cf5b29.txt
@@ -0,0 +1,47 @@
+#
+# This file is autogenerated by pip-compile with Python 3.10
+# by the following command:
+#
+# pip-compile --allow-unsafe --no-annotate .riot/requirements/7cf5b29.in
+#
+attrs==25.1.0
+boto3==1.36.10
+botocore==1.36.10
+bytecode==0.16.1
+certifi==2024.12.14
+charset-normalizer==3.4.1
+coverage[toml]==7.6.10
+datadog==0.51.0
+datadog-lambda==6.105.0
+ddtrace==2.20.0
+deprecated==1.2.18
+envier==0.5.2
+exceptiongroup==1.2.2
+hypothesis==6.45.0
+idna==3.10
+importlib-metadata==8.5.0
+iniconfig==2.0.0
+jmespath==1.0.1
+mock==5.1.0
+opentelemetry-api==1.29.0
+opentracing==2.4.0
+packaging==24.2
+pluggy==1.5.0
+protobuf==5.29.3
+pytest==8.3.4
+pytest-asyncio==0.21.1
+pytest-cov==6.0.0
+pytest-mock==3.14.0
+pytest-randomly==3.16.0
+python-dateutil==2.9.0.post0
+requests==2.32.3
+s3transfer==0.11.2
+six==1.17.0
+sortedcontainers==2.4.0
+tomli==2.2.1
+typing-extensions==4.12.2
+ujson==5.10.0
+urllib3==2.3.0
+wrapt==1.17.2
+xmltodict==0.14.2
+zipp==3.21.0
diff --git a/.riot/requirements/b0f80c7.txt b/.riot/requirements/b0f80c7.txt
new file mode 100644
index 00000000000..6e1f4faa53d
--- /dev/null
+++ b/.riot/requirements/b0f80c7.txt
@@ -0,0 +1,45 @@
+#
+# This file is autogenerated by pip-compile with Python 3.11
+# by the following command:
+#
+# pip-compile --allow-unsafe --no-annotate .riot/requirements/b0f80c7.in
+#
+attrs==25.1.0
+boto3==1.36.10
+botocore==1.36.10
+bytecode==0.16.1
+certifi==2024.12.14
+charset-normalizer==3.4.1
+coverage[toml]==7.6.10
+datadog==0.51.0
+datadog-lambda==6.105.0
+ddtrace==2.20.0
+deprecated==1.2.18
+envier==0.5.2
+hypothesis==6.45.0
+idna==3.10
+importlib-metadata==8.5.0
+iniconfig==2.0.0
+jmespath==1.0.1
+mock==5.1.0
+opentelemetry-api==1.29.0
+opentracing==2.4.0
+packaging==24.2
+pluggy==1.5.0
+protobuf==5.29.3
+pytest==8.3.4
+pytest-asyncio==0.21.1
+pytest-cov==6.0.0
+pytest-mock==3.14.0
+pytest-randomly==3.16.0
+python-dateutil==2.9.0.post0
+requests==2.32.3
+s3transfer==0.11.2
+six==1.17.0
+sortedcontainers==2.4.0
+typing-extensions==4.12.2
+ujson==5.10.0
+urllib3==2.3.0
+wrapt==1.17.2
+xmltodict==0.14.2
+zipp==3.21.0
diff --git a/.riot/requirements/bc071f4.txt b/.riot/requirements/bc071f4.txt
new file mode 100644
index 00000000000..5292c276c7e
--- /dev/null
+++ b/.riot/requirements/bc071f4.txt
@@ -0,0 +1,47 @@
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+# pip-compile --allow-unsafe --no-annotate .riot/requirements/bc071f4.in
+#
+attrs==25.1.0
+boto3==1.36.10
+botocore==1.36.10
+bytecode==0.16.1
+certifi==2024.12.14
+charset-normalizer==3.4.1
+coverage[toml]==7.6.10
+datadog==0.51.0
+datadog-lambda==6.105.0
+ddtrace==2.20.0
+deprecated==1.2.18
+envier==0.5.2
+exceptiongroup==1.2.2
+hypothesis==6.45.0
+idna==3.10
+importlib-metadata==8.5.0
+iniconfig==2.0.0
+jmespath==1.0.1
+mock==5.1.0
+opentelemetry-api==1.29.0
+opentracing==2.4.0
+packaging==24.2
+pluggy==1.5.0
+protobuf==5.29.3
+pytest==8.3.4
+pytest-asyncio==0.21.1
+pytest-cov==6.0.0
+pytest-mock==3.14.0
+pytest-randomly==3.16.0
+python-dateutil==2.9.0.post0
+requests==2.32.3
+s3transfer==0.11.2
+six==1.17.0
+sortedcontainers==2.4.0
+tomli==2.2.1
+typing-extensions==4.12.2
+ujson==5.10.0
+urllib3==1.26.20
+wrapt==1.17.2
+xmltodict==0.14.2
+zipp==3.21.0
diff --git a/.riot/requirements/ce0b0e6.txt b/.riot/requirements/ce0b0e6.txt
new file mode 100644
index 00000000000..02c1978a081
--- /dev/null
+++ b/.riot/requirements/ce0b0e6.txt
@@ -0,0 +1,45 @@
+#
+# This file is autogenerated by pip-compile with Python 3.12
+# by the following command:
+#
+# pip-compile --allow-unsafe --no-annotate .riot/requirements/ce0b0e6.in
+#
+attrs==25.1.0
+boto3==1.36.10
+botocore==1.36.10
+bytecode==0.16.1
+certifi==2024.12.14
+charset-normalizer==3.4.1
+coverage[toml]==7.6.10
+datadog==0.51.0
+datadog-lambda==6.105.0
+ddtrace==2.20.0
+deprecated==1.2.18
+envier==0.5.2
+hypothesis==6.45.0
+idna==3.10
+importlib-metadata==8.5.0
+iniconfig==2.0.0
+jmespath==1.0.1
+mock==5.1.0
+opentelemetry-api==1.29.0
+opentracing==2.4.0
+packaging==24.2
+pluggy==1.5.0
+protobuf==5.29.3
+pytest==8.3.4
+pytest-asyncio==0.21.1
+pytest-cov==6.0.0
+pytest-mock==3.14.0
+pytest-randomly==3.16.0
+python-dateutil==2.9.0.post0
+requests==2.32.3
+s3transfer==0.11.2
+six==1.17.0
+sortedcontainers==2.4.0
+typing-extensions==4.12.2
+ujson==5.10.0
+urllib3==2.3.0
+wrapt==1.17.2
+xmltodict==0.14.2
+zipp==3.21.0
diff --git a/.riot/requirements/d3868d9.txt b/.riot/requirements/d3868d9.txt
new file mode 100644
index 00000000000..d369ff90575
--- /dev/null
+++ b/.riot/requirements/d3868d9.txt
@@ -0,0 +1,46 @@
+#
+# This file is autogenerated by pip-compile with Python 3.13
+# by the following command:
+#
+# pip-compile --allow-unsafe --no-annotate .riot/requirements/d3868d9.in
+#
+attrs==25.1.0
+boto3==1.36.10
+botocore==1.36.10
+bytecode==0.16.1
+certifi==2024.12.14
+charset-normalizer==3.4.1
+coverage[toml]==7.6.10
+datadog==0.51.0
+datadog-lambda==6.105.0
+ddtrace==2.20.0
+deprecated==1.2.18
+envier==0.5.2
+hypothesis==6.45.0
+idna==3.10
+importlib-metadata==8.5.0
+iniconfig==2.0.0
+jmespath==1.0.1
+legacy-cgi==2.6.2
+mock==5.1.0
+opentelemetry-api==1.29.0
+opentracing==2.4.0
+packaging==24.2
+pluggy==1.5.0
+protobuf==5.29.3
+pytest==8.3.4
+pytest-asyncio==0.21.1
+pytest-cov==6.0.0
+pytest-mock==3.14.0
+pytest-randomly==3.16.0
+python-dateutil==2.9.0.post0
+requests==2.32.3
+s3transfer==0.11.2
+six==1.17.0
+sortedcontainers==2.4.0
+typing-extensions==4.12.2
+ujson==5.10.0
+urllib3==2.3.0
+wrapt==1.17.2
+xmltodict==0.14.2
+zipp==3.21.0
diff --git a/.riot/requirements/dd525d9.txt b/.riot/requirements/dd525d9.txt
deleted file mode 100644
index 03c376f19df..00000000000
--- a/.riot/requirements/dd525d9.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# This file is autogenerated by pip-compile with Python 3.9
-# by the following command:
-#
-# pip-compile --no-annotate --resolver=backtracking .riot/requirements/dd525d9.in
-#
-attrs==23.2.0
-boto3==1.34.139
-botocore==1.34.139
-bytecode==0.15.1
-cattrs==23.2.3
-certifi==2024.7.4
-charset-normalizer==3.3.2
-coverage[toml]==7.5.4
-datadog==0.49.1
-datadog-lambda==6.96.0
-ddsketch==3.0.1
-ddtrace==2.9.2
-deprecated==1.2.14
-envier==0.5.2
-exceptiongroup==1.2.1
-hypothesis==6.45.0
-idna==3.7
-importlib-metadata==7.1.0
-iniconfig==2.0.0
-jmespath==1.0.1
-mock==5.1.0
-opentelemetry-api==1.26.0
-opentracing==2.4.0
-packaging==24.1
-pluggy==1.5.0
-protobuf==5.27.2
-pytest==8.2.2
-pytest-asyncio==0.21.1
-pytest-cov==5.0.0
-pytest-mock==3.14.0
-pytest-randomly==3.15.0
-python-dateutil==2.9.0.post0
-requests==2.32.3
-s3transfer==0.10.2
-six==1.16.0
-sortedcontainers==2.4.0
-tomli==2.0.1
-typing-extensions==4.12.2
-ujson==5.10.0
-urllib3==1.26.19
-wrapt==1.16.0
-xmltodict==0.13.0
-zipp==3.19.2
diff --git a/.riot/requirements/e39f833.txt b/.riot/requirements/e39f833.txt
deleted file mode 100644
index e71709e9da3..00000000000
--- a/.riot/requirements/e39f833.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# This file is autogenerated by pip-compile with Python 3.7
-# by the following command:
-#
-# pip-compile --no-annotate --resolver=backtracking .riot/requirements/e39f833.in
-#
-attrs==23.2.0
-boto3==1.33.13
-botocore==1.33.13
-bytecode==0.13.0
-cattrs==23.1.2
-certifi==2024.7.4
-charset-normalizer==3.3.2
-coverage[toml]==7.2.7
-datadog==0.49.1
-datadog-lambda==5.85.0
-ddsketch==3.0.1
-ddtrace==2.9.2
-deprecated==1.2.14
-envier==0.5.2
-exceptiongroup==1.2.1
-hypothesis==6.45.0
-idna==3.7
-importlib-metadata==6.5.0
-iniconfig==2.0.0
-jmespath==1.0.1
-mock==5.1.0
-opentelemetry-api==1.22.0
-opentracing==2.4.0
-packaging==24.0
-pluggy==1.2.0
-protobuf==4.24.4
-pytest==7.4.4
-pytest-asyncio==0.21.1
-pytest-cov==4.1.0
-pytest-mock==3.11.1
-pytest-randomly==3.12.0
-python-dateutil==2.9.0.post0
-requests==2.31.0
-s3transfer==0.8.2
-six==1.16.0
-sortedcontainers==2.4.0
-tomli==2.0.1
-typing-extensions==4.7.1
-urllib3==1.26.19
-wrapt==1.16.0
-xmltodict==0.13.0
-zipp==3.15.0
diff --git a/.riot/requirements/edb39c1.txt b/.riot/requirements/edb39c1.txt
deleted file mode 100644
index 667e74f25cd..00000000000
--- a/.riot/requirements/edb39c1.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# This file is autogenerated by pip-compile with Python 3.7
-# by the following command:
-#
-# pip-compile --no-annotate --resolver=backtracking .riot/requirements/edb39c1.in
-#
-attrs==23.2.0
-boto3==1.33.13
-botocore==1.33.13
-bytecode==0.13.0
-cattrs==23.1.2
-certifi==2024.7.4
-charset-normalizer==3.3.2
-coverage[toml]==7.2.7
-datadog==0.49.1
-datadog-lambda==5.85.0
-ddsketch==3.0.1
-ddtrace==2.9.2
-deprecated==1.2.14
-envier==0.5.2
-exceptiongroup==1.2.1
-hypothesis==6.45.0
-idna==3.7
-importlib-metadata==6.5.0
-iniconfig==2.0.0
-jmespath==1.0.1
-mock==5.1.0
-opentelemetry-api==1.22.0
-opentracing==2.4.0
-packaging==24.0
-pluggy==1.2.0
-protobuf==4.24.4
-pytest==7.4.4
-pytest-asyncio==0.21.1
-pytest-cov==4.1.0
-pytest-mock==3.11.1
-pytest-randomly==3.12.0
-python-dateutil==2.9.0.post0
-requests==2.31.0
-s3transfer==0.8.2
-six==1.16.0
-sortedcontainers==2.4.0
-tomli==2.0.1
-typing-extensions==4.7.1
-urllib3==1.26.19
-wrapt==1.16.0
-xmltodict==0.13.0
-zipp==3.15.0
diff --git a/ddtrace/llmobs/_evaluators/runner.py b/ddtrace/llmobs/_evaluators/runner.py
index 5e0ab2737f4..780293563d8 100644
--- a/ddtrace/llmobs/_evaluators/runner.py
+++ b/ddtrace/llmobs/_evaluators/runner.py
@@ -32,6 +32,8 @@ class EvaluatorRunner(PeriodicService):
2. triggers evaluator runs over buffered finished spans on each `periodic` call
"""
+ EVALUATORS_ENV_VAR = "DD_LLMOBS_EVALUATORS"
+
def __init__(self, interval: float, llmobs_service=None, evaluators=None):
super(EvaluatorRunner, self).__init__(interval=interval)
self._lock = forksafe.RLock()
@@ -46,7 +48,7 @@ def __init__(self, interval: float, llmobs_service=None, evaluators=None):
if len(self.evaluators) > 0:
return
- evaluator_str = os.getenv("_DD_LLMOBS_EVALUATORS")
+ evaluator_str = os.getenv(self.EVALUATORS_ENV_VAR)
if evaluator_str is None:
return
diff --git a/ddtrace/llmobs/_evaluators/sampler.py b/ddtrace/llmobs/_evaluators/sampler.py
index 3598e90f7f3..524af217f83 100644
--- a/ddtrace/llmobs/_evaluators/sampler.py
+++ b/ddtrace/llmobs/_evaluators/sampler.py
@@ -46,7 +46,7 @@ def __repr__(self):
class EvaluatorRunnerSampler:
- SAMPLING_RULES_ENV_VAR = "_DD_LLMOBS_EVALUATOR_SAMPLING_RULES"
+ SAMPLING_RULES_ENV_VAR = "DD_LLMOBS_EVALUATOR_SAMPLING_RULES"
def __init__(self):
self.rules = self.parse_rules()
@@ -59,8 +59,9 @@ def sample(self, evaluator_label, span):
def parse_rules(self) -> List[EvaluatorRunnerSamplingRule]:
rules = []
+
sampling_rules_str = os.getenv(self.SAMPLING_RULES_ENV_VAR)
- telemetry_writer.add_configuration("_DD_LLMOBS_EVALUATOR_SAMPLING_RULES", sampling_rules_str, origin="env")
+ telemetry_writer.add_configuration(self.SAMPLING_RULES_ENV_VAR, sampling_rules_str, origin="env")
def parsing_failed_because(msg, maybe_throw_this):
telemetry_writer.add_log(
diff --git a/lib-injection/sources/min_compatible_versions.csv b/lib-injection/sources/min_compatible_versions.csv
index 4537863f24c..c7366036a89 100644
--- a/lib-injection/sources/min_compatible_versions.csv
+++ b/lib-injection/sources/min_compatible_versions.csv
@@ -42,7 +42,7 @@ coverage,0
cryptography,<39
daphne,0
databases,0
-datadog-lambda,>=4.66.0
+datadog-lambda,>=6.105.0
django,>=2.2
django-pylibmc,>=0.6
django-q,0
diff --git a/min_compatible_versions.csv b/min_compatible_versions.csv
index 4537863f24c..c7366036a89 100644
--- a/min_compatible_versions.csv
+++ b/min_compatible_versions.csv
@@ -42,7 +42,7 @@ coverage,0
cryptography,<39
daphne,0
databases,0
-datadog-lambda,>=4.66.0
+datadog-lambda,>=6.105.0
django,>=2.2
django-pylibmc,>=0.6
django-q,0
diff --git a/releasenotes/notes/ragas-integration-a81b696757c0e7a5.yaml b/releasenotes/notes/ragas-integration-a81b696757c0e7a5.yaml
new file mode 100644
index 00000000000..7963f891661
--- /dev/null
+++ b/releasenotes/notes/ragas-integration-a81b696757c0e7a5.yaml
@@ -0,0 +1,21 @@
+---
+features:
+ - |
+ LLM Observability: This introduces an integration with the `RAGAS `_ evaluation framework to continuously monitor
+ the performance of context-augmented LLM generations in production.
+
+ The integration supports evaluating LLM inferences with the following RAGAS metrics:
+ - `Faithfulness `_: measures if the LLM response is faithful to the provided context.
+ - `Answer Relevancy `_: measures how relevant the LLM response is to the user input.
+ - `Context Precision `_: measures how effectively the context is used in the generated response.
+
+ To learn more, see the `LLM Observability evaluations guide `_.
+deprecations:
+ - |
+ LLM Observability: The `_DD_LLMOBS_EVALUATORS` environment variable is deprecated and will be removed in ddtrace 3.0.0.
+ As an alternative to `_DD_LLMOBS_EVALUATORS`, you can use `DD_LLMOBS_EVALUATORS` instead.
+ To migrate, replace `_DD_LLMOBS_EVALUATORS` with `DD_LLMOBS_EVALUATORS`.
+ - |
+ LLM Observability: The `_DD_LLMOBS_EVALUATOR_SAMPLING_RULES` environment variable is deprecated and will be removed in ddtrace 3.0.0.
+ As an alternative to `_DD_LLMOBS_EVALUATOR_SAMPLING_RULES`, you can use `DD_LLMOBS_EVALUATOR_SAMPLING_RULES` instead.
+ To migrate, replace `_DD_LLMOBS_EVALUATOR_SAMPLING_RULES` with `DD_LLMOBS_EVALUATOR_SAMPLING_RULES`.
\ No newline at end of file
diff --git a/releasenotes/notes/upgrade-min-aws-lambda-f9d9d31cf1f8685f.yaml b/releasenotes/notes/upgrade-min-aws-lambda-f9d9d31cf1f8685f.yaml
new file mode 100644
index 00000000000..1d632ce8988
--- /dev/null
+++ b/releasenotes/notes/upgrade-min-aws-lambda-f9d9d31cf1f8685f.yaml
@@ -0,0 +1,4 @@
+---
+upgrade:
+ - |
+ aws_lambda: Drops support for ``aws_lambda<=6.105.0``.
\ No newline at end of file
diff --git a/riotfile.py b/riotfile.py
index d6fd8a1e89b..dac8b01fc0c 100644
--- a/riotfile.py
+++ b/riotfile.py
@@ -2857,10 +2857,10 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT
Venv(
name="aws_lambda",
command="pytest --no-ddtrace {cmdargs} tests/contrib/aws_lambda",
- pys=select_pys(min_version="3.7", max_version="3.9"),
+ pys=select_pys(min_version="3.8", max_version="3.13"),
pkgs={
"boto3": latest,
- "datadog-lambda": [">=4.66.0", latest],
+ "datadog-lambda": [">=6.105.0", latest],
"pytest-asyncio": "==0.21.1",
"pytest-randomly": latest,
"envier": "==0.5.2",
diff --git a/tests/llmobs/test_llmobs_evaluator_runner.py b/tests/llmobs/test_llmobs_evaluator_runner.py
index a2c4278297c..1c941c52d83 100644
--- a/tests/llmobs/test_llmobs_evaluator_runner.py
+++ b/tests/llmobs/test_llmobs_evaluator_runner.py
@@ -120,7 +120,7 @@ def test_evaluator_runner_on_exit(mock_writer_logs, run_python_code_in_subproces
def test_evaluator_runner_unsupported_evaluator():
- with override_env({"_DD_LLMOBS_EVALUATORS": "unsupported"}):
+ with override_env({EvaluatorRunner.EVALUATORS_ENV_VAR: "unsupported"}):
with pytest.raises(ValueError):
EvaluatorRunner(interval=0.01, llmobs_service=mock.MagicMock())
diff --git a/tests/llmobs/test_llmobs_ragas_evaluators.py b/tests/llmobs/test_llmobs_ragas_evaluators.py
index 9766c18c1e5..c46dce740c2 100644
--- a/tests/llmobs/test_llmobs_ragas_evaluators.py
+++ b/tests/llmobs/test_llmobs_ragas_evaluators.py
@@ -6,7 +6,8 @@
from ddtrace.llmobs._evaluators.ragas.answer_relevancy import RagasAnswerRelevancyEvaluator
from ddtrace.llmobs._evaluators.ragas.context_precision import RagasContextPrecisionEvaluator
from ddtrace.llmobs._evaluators.ragas.faithfulness import RagasFaithfulnessEvaluator
-from ddtrace.trace import Span
+from ddtrace.llmobs._evaluators.runner import EvaluatorRunner
+from ddtrace.span import Span
from tests.llmobs._utils import _expected_llmobs_llm_span_event
from tests.llmobs._utils import _expected_ragas_answer_relevancy_spans
from tests.llmobs._utils import _expected_ragas_context_precision_spans
@@ -235,7 +236,7 @@ def test_llmobs_with_faithfulness_emits_traces_and_evals_on_exit(mock_writer_log
"PYTHONPATH": ":".join(pypath),
"OPENAI_API_KEY": os.getenv("OPENAI_API_KEY", "dummy-openai-api-key"),
"_DD_LLMOBS_EVALUATOR_INTERVAL": "5",
- "_DD_LLMOBS_EVALUATORS": "ragas_faithfulness",
+ EvaluatorRunner.EVALUATORS_ENV_VAR: "ragas_faithfulness",
"DD_TRACE_ENABLED": "0",
}
)
diff --git a/tests/llmobs/test_llmobs_service.py b/tests/llmobs/test_llmobs_service.py
index ff099ae3f71..2fe3e1fbfab 100644
--- a/tests/llmobs/test_llmobs_service.py
+++ b/tests/llmobs/test_llmobs_service.py
@@ -1384,7 +1384,7 @@ def test_llmobs_fork_recreates_and_restarts_eval_metric_writer():
def test_llmobs_fork_recreates_and_restarts_evaluator_runner(mock_ragas_evaluator):
"""Test that forking a process correctly recreates and restarts the EvaluatorRunner."""
pytest.importorskip("ragas")
- with override_env(dict(_DD_LLMOBS_EVALUATORS="ragas_faithfulness")):
+ with override_env(dict(DD_LLMOBS_EVALUATORS="ragas_faithfulness")):
with mock.patch("ddtrace.llmobs._evaluators.runner.EvaluatorRunner.periodic"):
llmobs_service.enable(_tracer=DummyTracer(), ml_app="test_app")
original_pid = llmobs_service._instance.tracer._pid
@@ -1464,9 +1464,9 @@ def test_llmobs_fork_submit_evaluation(monkeypatch):
def test_llmobs_fork_evaluator_runner_run(monkeypatch):
"""Test that forking a process correctly encodes new spans created in each process."""
- monkeypatch.setenv("_DD_LLMOBS_EVALUATOR_INTERVAL", 5.0)
+ monkeypatch.setenv("DD_LLMOBS_EVALUATOR_INTERVAL", 5.0)
pytest.importorskip("ragas")
- monkeypatch.setenv("_DD_LLMOBS_EVALUATORS", "ragas_faithfulness")
+ monkeypatch.setenv("DD_LLMOBS_EVALUATORS", "ragas_faithfulness")
with mock.patch("ddtrace.llmobs._evaluators.runner.EvaluatorRunner.periodic"):
llmobs_service.enable(_tracer=DummyTracer(), ml_app="test_app", api_key="test_api_key")
pid = os.fork()
@@ -1757,7 +1757,7 @@ async def test_annotation_context_async_nested(llmobs):
def test_service_enable_starts_evaluator_runner_when_evaluators_exist():
pytest.importorskip("ragas")
with override_global_config(dict(_dd_api_key="", _llmobs_ml_app="")):
- with override_env(dict(_DD_LLMOBS_EVALUATORS="ragas_faithfulness")):
+ with override_env(dict(DD_LLMOBS_EVALUATORS="ragas_faithfulness")):
dummy_tracer = DummyTracer()
llmobs_service.enable(_tracer=dummy_tracer)
llmobs_instance = llmobs_service._instance