From f503a4ff7c84336cf5a33b44c553faef279ce841 Mon Sep 17 00:00:00 2001 From: Theo van Kraay Date: Tue, 7 Jul 2026 21:14:03 +0100 Subject: [PATCH 1/4] Add cadence_thresholds passthrough to clients Consumers can now set per-turn processing cadence (fact extraction, dedup, thread/user summary frequency) in-process via a cadence_thresholds mapping on CosmosMemoryClient and AsyncCosmosMemoryClient, instead of only through os.environ. The auto-trigger already accepted a thresholds override; the clients now forward it. None preserves the env-only behavior and missing keys fall back to env/defaults, so this is backward compatible. --- CHANGELOG.md | 11 ++++++ .../agent_memory/aio/cosmos_memory_client.py | 16 +++++++- .../agent_memory/cosmos_memory_client.py | 16 +++++++- tests/unit/aio/test_auto_trigger.py | 38 ++++++++++++++++++- tests/unit/test_cosmos_memory_client.py | 28 ++++++++++++++ 5 files changed, 104 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f9f74c..5b92c76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ ## Release History +## [Unreleased] + +#### Features Added +* Per-turn processing cadence can now be set in-process via the new + `cadence_thresholds` constructor argument on `CosmosMemoryClient` and + `AsyncCosmosMemoryClient`, instead of only through environment variables. Pass a + mapping keyed by the same names as the env vars (e.g. `FACT_EXTRACTION_EVERY_N`, + `DEDUP_EVERY_N`, `THREAD_SUMMARY_EVERY_N`, `USER_SUMMARY_EVERY_N`); any key not + present falls back to the environment/defaults, and `None` preserves today's + env-only behavior. + ## [0.2.0b2] (2026-07-01) #### Features Added diff --git a/azure/cosmos/agent_memory/aio/cosmos_memory_client.py b/azure/cosmos/agent_memory/aio/cosmos_memory_client.py index 7caa832..7f5d060 100644 --- a/azure/cosmos/agent_memory/aio/cosmos_memory_client.py +++ b/azure/cosmos/agent_memory/aio/cosmos_memory_client.py @@ -4,7 +4,7 @@ import asyncio from datetime import datetime -from typing import TYPE_CHECKING, Any, Iterable, Optional +from typing import TYPE_CHECKING, Any, Iterable, Mapping, Optional from azure.cosmos.agent_memory._base import _BaseMemoryClient from azure.cosmos.agent_memory._base.base_client import is_transient_tail_step_error @@ -90,6 +90,7 @@ def __init__( chat_client: Optional[Any] = None, processor: Optional[AsyncMemoryProcessor] = None, transcript_metadata_keys: Optional[Iterable[str]] = None, + cadence_thresholds: Optional[Mapping[str, int]] = None, ) -> None: self._init_base_config( cosmos_endpoint=cosmos_endpoint, @@ -146,6 +147,12 @@ def __init__( self._processor: Optional[AsyncMemoryProcessor] = processor self._processor_explicit = processor is not None self._transcript_metadata_keys: Optional[tuple[str, ...]] = _normalize_metadata_keys(transcript_metadata_keys) + # Optional per-turn cadence override, keyed by the same names as the env vars (e.g. + # ``FACT_EXTRACTION_EVERY_N``, ``DEDUP_EVERY_N``, ``THREAD_SUMMARY_EVERY_N``, + # ``USER_SUMMARY_EVERY_N``). When provided, the auto-trigger uses these values instead of + # reading ``os.environ``; any key not present falls back to the environment/defaults. + # ``None`` preserves the env-only behavior. + self._cadence_thresholds: Optional[Mapping[str, int]] = cadence_thresholds logger.info("AsyncCosmosMemoryClient initialized") async def __aenter__(self) -> "AsyncCosmosMemoryClient": @@ -539,7 +546,12 @@ def _get_counter_container(self) -> Any: async def _maybe_auto_trigger(self, turn_counts: dict[tuple[str, str], int]) -> None: if not turn_counts: return - await maybe_trigger_steps(self._get_processor(), self._get_counter_container(), turn_counts) + await maybe_trigger_steps( + self._get_processor(), + self._get_counter_container(), + turn_counts, + thresholds=self._cadence_thresholds, + ) def _container_for_type(self, memory_type: str) -> Any: """Return the Cosmos container client that owns ``memory_type``.""" diff --git a/azure/cosmos/agent_memory/cosmos_memory_client.py b/azure/cosmos/agent_memory/cosmos_memory_client.py index 4bd03a6..bbf38f0 100644 --- a/azure/cosmos/agent_memory/cosmos_memory_client.py +++ b/azure/cosmos/agent_memory/cosmos_memory_client.py @@ -3,7 +3,7 @@ from __future__ import annotations from datetime import datetime -from typing import TYPE_CHECKING, Any, Iterable, Optional +from typing import TYPE_CHECKING, Any, Iterable, Mapping, Optional from azure.cosmos.agent_memory.logging import get_logger @@ -85,6 +85,7 @@ def __init__( chat_client: Optional[Any] = None, processor: Optional[MemoryProcessor] = None, transcript_metadata_keys: Optional[Iterable[str]] = None, + cadence_thresholds: Optional[Mapping[str, int]] = None, ) -> None: self._init_base_config( cosmos_endpoint=cosmos_endpoint, @@ -138,6 +139,12 @@ def __init__( self._processor: Optional[MemoryProcessor] = processor self._processor_explicit = processor is not None self._transcript_metadata_keys: Optional[tuple[str, ...]] = _normalize_metadata_keys(transcript_metadata_keys) + # Optional per-turn cadence override, keyed by the same names as the env vars (e.g. + # ``FACT_EXTRACTION_EVERY_N``, ``DEDUP_EVERY_N``, ``THREAD_SUMMARY_EVERY_N``, + # ``USER_SUMMARY_EVERY_N``). When provided, the auto-trigger uses these values instead of + # reading ``os.environ``; any key not present falls back to the environment/defaults. + # ``None`` preserves the env-only behavior. + self._cadence_thresholds: Optional[Mapping[str, int]] = cadence_thresholds if self._cosmos_endpoint: self.create_memory_store() logger.info("CosmosMemoryClient initialized") @@ -494,7 +501,12 @@ def _get_counter_container(self) -> Any: def _maybe_auto_trigger(self, turn_counts: dict[tuple[str, str], int]) -> None: if not turn_counts: return - maybe_trigger_steps(self._get_processor(), self._get_counter_container(), turn_counts) + maybe_trigger_steps( + self._get_processor(), + self._get_counter_container(), + turn_counts, + thresholds=self._cadence_thresholds, + ) def _container_for_type(self, memory_type: str) -> Any: """Return the Cosmos container client that owns ``memory_type``.""" diff --git a/tests/unit/aio/test_auto_trigger.py b/tests/unit/aio/test_auto_trigger.py index edcf382..085265a 100644 --- a/tests/unit/aio/test_auto_trigger.py +++ b/tests/unit/aio/test_auto_trigger.py @@ -8,7 +8,7 @@ from __future__ import annotations import asyncio -from unittest.mock import MagicMock, patch +from unittest.mock import AsyncMock, MagicMock, patch import pytest @@ -145,3 +145,39 @@ async def capture(turn_counts): await client.push_to_cosmos() await asyncio.gather(*list(client._background_tasks), return_exceptions=True) assert captured == [{("u1", "t1"): 1}] + + +class TestCadenceThresholdsForwarding: + """A ``cadence_thresholds`` mapping on the client is forwarded to the auto-trigger, so + callers can set per-turn cadence in-process instead of mutating ``os.environ``.""" + + @pytest.mark.asyncio + async def test_cadence_thresholds_forwarded(self): + thresholds = {"FACT_EXTRACTION_EVERY_N": 3, "DEDUP_EVERY_N": 2} + client = AsyncCosmosMemoryClient(use_default_credential=False, cadence_thresholds=thresholds) + client._get_processor = MagicMock(return_value=MagicMock()) + client._get_counter_container = MagicMock(return_value=MagicMock()) + + with patch( + "azure.cosmos.agent_memory.aio.cosmos_memory_client.maybe_trigger_steps", + new=AsyncMock(), + ) as mock_trigger: + await client._maybe_auto_trigger({("u1", "t1"): 1}) + + mock_trigger.assert_awaited_once() + assert mock_trigger.await_args.kwargs["thresholds"] is thresholds + + @pytest.mark.asyncio + async def test_defaults_to_none_when_unset(self): + client = AsyncCosmosMemoryClient(use_default_credential=False) + client._get_processor = MagicMock(return_value=MagicMock()) + client._get_counter_container = MagicMock(return_value=MagicMock()) + + with patch( + "azure.cosmos.agent_memory.aio.cosmos_memory_client.maybe_trigger_steps", + new=AsyncMock(), + ) as mock_trigger: + await client._maybe_auto_trigger({("u1", "t1"): 1}) + + # None preserves the env-only behavior (the auto-trigger treats None as defaults). + assert mock_trigger.await_args.kwargs["thresholds"] is None diff --git a/tests/unit/test_cosmos_memory_client.py b/tests/unit/test_cosmos_memory_client.py index f84277d..f734d2e 100644 --- a/tests/unit/test_cosmos_memory_client.py +++ b/tests/unit/test_cosmos_memory_client.py @@ -997,3 +997,31 @@ def test_list_tags_delegates_to_store(): kwargs = container.query_items.call_args.kwargs assert "SELECT VALUE c.tags" in kwargs["query"] assert kwargs["parameters"] == [{"name": "@user_id", "value": "u1"}] + + +class TestSyncCadenceThresholdsForwarding: + """A ``cadence_thresholds`` mapping on the sync client is forwarded to the auto-trigger, so + callers can set per-turn cadence in-process instead of mutating ``os.environ``.""" + + def test_cadence_thresholds_forwarded(self): + thresholds = {"FACT_EXTRACTION_EVERY_N": 3, "DEDUP_EVERY_N": 2} + mem = CosmosMemoryClient(use_default_credential=False, cadence_thresholds=thresholds) + mem._get_processor = MagicMock(return_value=MagicMock()) + mem._get_counter_container = MagicMock(return_value=MagicMock()) + + with patch("azure.cosmos.agent_memory.cosmos_memory_client.maybe_trigger_steps") as mock_trigger: + mem._maybe_auto_trigger({("u1", "t1"): 1}) + + mock_trigger.assert_called_once() + assert mock_trigger.call_args.kwargs["thresholds"] is thresholds + + def test_defaults_to_none_when_unset(self): + mem = CosmosMemoryClient(use_default_credential=False) + mem._get_processor = MagicMock(return_value=MagicMock()) + mem._get_counter_container = MagicMock(return_value=MagicMock()) + + with patch("azure.cosmos.agent_memory.cosmos_memory_client.maybe_trigger_steps") as mock_trigger: + mem._maybe_auto_trigger({("u1", "t1"): 1}) + + # None preserves the env-only behavior (the auto-trigger treats None as defaults). + assert mock_trigger.call_args.kwargs["thresholds"] is None From 2eed03c8d48718404ad07061cf18e9b1d914d9cb Mon Sep 17 00:00:00 2001 From: Theo van Kraay Date: Wed, 8 Jul 2026 14:59:41 +0100 Subject: [PATCH 2/4] Address review: assert equality and wrap test docstrings --- tests/unit/aio/test_auto_trigger.py | 8 +++++--- tests/unit/test_cosmos_memory_client.py | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/unit/aio/test_auto_trigger.py b/tests/unit/aio/test_auto_trigger.py index 085265a..0cdaacf 100644 --- a/tests/unit/aio/test_auto_trigger.py +++ b/tests/unit/aio/test_auto_trigger.py @@ -148,8 +148,10 @@ async def capture(turn_counts): class TestCadenceThresholdsForwarding: - """A ``cadence_thresholds`` mapping on the client is forwarded to the auto-trigger, so - callers can set per-turn cadence in-process instead of mutating ``os.environ``.""" + """A ``cadence_thresholds`` mapping on the client is forwarded to the auto-trigger. + + This lets callers set per-turn cadence in-process instead of mutating ``os.environ``. + """ @pytest.mark.asyncio async def test_cadence_thresholds_forwarded(self): @@ -165,7 +167,7 @@ async def test_cadence_thresholds_forwarded(self): await client._maybe_auto_trigger({("u1", "t1"): 1}) mock_trigger.assert_awaited_once() - assert mock_trigger.await_args.kwargs["thresholds"] is thresholds + assert mock_trigger.await_args.kwargs["thresholds"] == thresholds @pytest.mark.asyncio async def test_defaults_to_none_when_unset(self): diff --git a/tests/unit/test_cosmos_memory_client.py b/tests/unit/test_cosmos_memory_client.py index f734d2e..bd2c58c 100644 --- a/tests/unit/test_cosmos_memory_client.py +++ b/tests/unit/test_cosmos_memory_client.py @@ -1000,8 +1000,10 @@ def test_list_tags_delegates_to_store(): class TestSyncCadenceThresholdsForwarding: - """A ``cadence_thresholds`` mapping on the sync client is forwarded to the auto-trigger, so - callers can set per-turn cadence in-process instead of mutating ``os.environ``.""" + """A ``cadence_thresholds`` mapping on the sync client is forwarded to the auto-trigger. + + This lets callers set per-turn cadence in-process instead of mutating ``os.environ``. + """ def test_cadence_thresholds_forwarded(self): thresholds = {"FACT_EXTRACTION_EVERY_N": 3, "DEDUP_EVERY_N": 2} @@ -1013,7 +1015,7 @@ def test_cadence_thresholds_forwarded(self): mem._maybe_auto_trigger({("u1", "t1"): 1}) mock_trigger.assert_called_once() - assert mock_trigger.call_args.kwargs["thresholds"] is thresholds + assert mock_trigger.call_args.kwargs["thresholds"] == thresholds def test_defaults_to_none_when_unset(self): mem = CosmosMemoryClient(use_default_credential=False) From 8458c347530b94082451153f8123e5f9983f8f10 Mon Sep 17 00:00:00 2001 From: Theo van Kraay Date: Wed, 8 Jul 2026 16:22:13 +0100 Subject: [PATCH 3/4] Validate and defensively copy cadence_thresholds at construction --- CHANGELOG.md | 4 ++- .../agent_memory/aio/cosmos_memory_client.py | 11 +++++-- .../agent_memory/cosmos_memory_client.py | 8 +++-- .../services/_pipeline_helpers.py | 33 ++++++++++++++++++- tests/unit/aio/test_auto_trigger.py | 26 +++++++++++++++ tests/unit/test_cosmos_memory_client.py | 26 +++++++++++++++ 6 files changed, 100 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b92c76..7bc3f45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,9 @@ mapping keyed by the same names as the env vars (e.g. `FACT_EXTRACTION_EVERY_N`, `DEDUP_EVERY_N`, `THREAD_SUMMARY_EVERY_N`, `USER_SUMMARY_EVERY_N`); any key not present falls back to the environment/defaults, and `None` preserves today's - env-only behavior. + env-only behavior. The mapping is validated and defensively copied at + construction: values are coerced to `int`, negatives are rejected (`0` disables + a step), and later mutation of the caller's mapping cannot change client behavior. ## [0.2.0b2] (2026-07-01) diff --git a/azure/cosmos/agent_memory/aio/cosmos_memory_client.py b/azure/cosmos/agent_memory/aio/cosmos_memory_client.py index 7f5d060..75b8aff 100644 --- a/azure/cosmos/agent_memory/aio/cosmos_memory_client.py +++ b/azure/cosmos/agent_memory/aio/cosmos_memory_client.py @@ -29,7 +29,10 @@ from azure.cosmos.agent_memory.aio.store import AsyncMemoryStore from azure.cosmos.agent_memory.exceptions import CosmosNotConnectedError, CosmosOperationError, ValidationError from azure.cosmos.agent_memory.logging import get_logger -from azure.cosmos.agent_memory.services._pipeline_helpers import _normalize_metadata_keys +from azure.cosmos.agent_memory.services._pipeline_helpers import ( + _normalize_cadence_thresholds, + _normalize_metadata_keys, +) from azure.cosmos.agent_memory.thresholds import DEFAULT_TTL_BY_TYPE if TYPE_CHECKING: # pragma: no cover - typing-only import @@ -151,8 +154,10 @@ def __init__( # ``FACT_EXTRACTION_EVERY_N``, ``DEDUP_EVERY_N``, ``THREAD_SUMMARY_EVERY_N``, # ``USER_SUMMARY_EVERY_N``). When provided, the auto-trigger uses these values instead of # reading ``os.environ``; any key not present falls back to the environment/defaults. - # ``None`` preserves the env-only behavior. - self._cadence_thresholds: Optional[Mapping[str, int]] = cadence_thresholds + # ``None`` preserves the env-only behavior. Normalized to a defensive ``dict[str, int]`` + # so later mutation of the caller's mapping cannot change client behavior, and invalid + # values fail fast at construction rather than deep inside the trigger path. + self._cadence_thresholds: Optional[dict[str, int]] = _normalize_cadence_thresholds(cadence_thresholds) logger.info("AsyncCosmosMemoryClient initialized") async def __aenter__(self) -> "AsyncCosmosMemoryClient": diff --git a/azure/cosmos/agent_memory/cosmos_memory_client.py b/azure/cosmos/agent_memory/cosmos_memory_client.py index bbf38f0..71a5670 100644 --- a/azure/cosmos/agent_memory/cosmos_memory_client.py +++ b/azure/cosmos/agent_memory/cosmos_memory_client.py @@ -27,7 +27,7 @@ from .embeddings import EmbeddingsClient from .exceptions import CosmosOperationError, ValidationError from .processors import InProcessProcessor, MemoryProcessor -from .services._pipeline_helpers import _normalize_metadata_keys +from .services._pipeline_helpers import _normalize_cadence_thresholds, _normalize_metadata_keys from .services.pipeline import PipelineService from .store import MemoryStore from .thresholds import DEFAULT_TTL_BY_TYPE @@ -143,8 +143,10 @@ def __init__( # ``FACT_EXTRACTION_EVERY_N``, ``DEDUP_EVERY_N``, ``THREAD_SUMMARY_EVERY_N``, # ``USER_SUMMARY_EVERY_N``). When provided, the auto-trigger uses these values instead of # reading ``os.environ``; any key not present falls back to the environment/defaults. - # ``None`` preserves the env-only behavior. - self._cadence_thresholds: Optional[Mapping[str, int]] = cadence_thresholds + # ``None`` preserves the env-only behavior. Normalized to a defensive ``dict[str, int]`` + # so later mutation of the caller's mapping cannot change client behavior, and invalid + # values fail fast at construction rather than deep inside the trigger path. + self._cadence_thresholds: Optional[dict[str, int]] = _normalize_cadence_thresholds(cadence_thresholds) if self._cosmos_endpoint: self.create_memory_store() logger.info("CosmosMemoryClient initialized") diff --git a/azure/cosmos/agent_memory/services/_pipeline_helpers.py b/azure/cosmos/agent_memory/services/_pipeline_helpers.py index 9748168..5540e4b 100644 --- a/azure/cosmos/agent_memory/services/_pipeline_helpers.py +++ b/azure/cosmos/agent_memory/services/_pipeline_helpers.py @@ -14,7 +14,7 @@ import re from collections import defaultdict from pathlib import Path -from typing import Any, Iterable, Optional +from typing import Any, Iterable, Mapping, Optional from azure.cosmos.agent_memory.exceptions import LLMError @@ -202,6 +202,37 @@ def _normalize_metadata_keys( return keys or None +def _normalize_cadence_thresholds( + value: Optional[Mapping[str, int]], +) -> Optional[dict[str, int]]: + """Validate + defensively copy a ``cadence_thresholds`` argument. + + Coerces each value to ``int`` and rejects negatives (``0`` disables the + corresponding step). Returns a new ``dict`` so later mutation of the + caller's mapping cannot change client behavior. Returns ``None`` for + missing or empty input. + """ + if value is None: + return None + if not isinstance(value, Mapping): + raise TypeError( + "cadence_thresholds must be a mapping of env-var name to int " + f"(e.g. {{'FACT_EXTRACTION_EVERY_N': 5}}), not {type(value).__name__}." + ) + normalized: dict[str, int] = {} + for key, raw in value.items(): + try: + coerced = int(raw) + except (TypeError, ValueError) as exc: + raise ValueError(f"cadence_thresholds[{key!r}] must be an int, got {raw!r}.") from exc + if coerced < 0: + raise ValueError( + f"cadence_thresholds[{key!r}] must be >= 0 (0 disables the step), got {coerced}." + ) + normalized[str(key)] = coerced + return normalized or None + + def _format_metadata_segment( metadata: Any, metadata_keys: Optional[tuple[str, ...]], diff --git a/tests/unit/aio/test_auto_trigger.py b/tests/unit/aio/test_auto_trigger.py index 0cdaacf..f244563 100644 --- a/tests/unit/aio/test_auto_trigger.py +++ b/tests/unit/aio/test_auto_trigger.py @@ -183,3 +183,29 @@ async def test_defaults_to_none_when_unset(self): # None preserves the env-only behavior (the auto-trigger treats None as defaults). assert mock_trigger.await_args.kwargs["thresholds"] is None + + +class TestCadenceThresholdsNormalization: + """The async client normalizes ``cadence_thresholds`` at construction time.""" + + def test_defensive_copy_isolates_later_mutation(self): + thresholds = {"FACT_EXTRACTION_EVERY_N": 3} + client = AsyncCosmosMemoryClient(use_default_credential=False, cadence_thresholds=thresholds) + thresholds["FACT_EXTRACTION_EVERY_N"] = 99 + assert client._cadence_thresholds == {"FACT_EXTRACTION_EVERY_N": 3} + + def test_string_values_are_coerced_to_int(self): + client = AsyncCosmosMemoryClient(use_default_credential=False, cadence_thresholds={"DEDUP_EVERY_N": "5"}) + assert client._cadence_thresholds == {"DEDUP_EVERY_N": 5} + + def test_negative_value_rejected(self): + with pytest.raises(ValueError): + AsyncCosmosMemoryClient(use_default_credential=False, cadence_thresholds={"DEDUP_EVERY_N": -1}) + + def test_non_int_value_rejected(self): + with pytest.raises(ValueError): + AsyncCosmosMemoryClient(use_default_credential=False, cadence_thresholds={"DEDUP_EVERY_N": "x"}) + + def test_non_mapping_rejected(self): + with pytest.raises(TypeError): + AsyncCosmosMemoryClient(use_default_credential=False, cadence_thresholds=[("DEDUP_EVERY_N", 5)]) diff --git a/tests/unit/test_cosmos_memory_client.py b/tests/unit/test_cosmos_memory_client.py index bd2c58c..c50e6af 100644 --- a/tests/unit/test_cosmos_memory_client.py +++ b/tests/unit/test_cosmos_memory_client.py @@ -1027,3 +1027,29 @@ def test_defaults_to_none_when_unset(self): # None preserves the env-only behavior (the auto-trigger treats None as defaults). assert mock_trigger.call_args.kwargs["thresholds"] is None + + +class TestSyncCadenceThresholdsNormalization: + """The sync client normalizes ``cadence_thresholds`` at construction time.""" + + def test_defensive_copy_isolates_later_mutation(self): + thresholds = {"FACT_EXTRACTION_EVERY_N": 3} + mem = CosmosMemoryClient(use_default_credential=False, cadence_thresholds=thresholds) + thresholds["FACT_EXTRACTION_EVERY_N"] = 99 + assert mem._cadence_thresholds == {"FACT_EXTRACTION_EVERY_N": 3} + + def test_string_values_are_coerced_to_int(self): + mem = CosmosMemoryClient(use_default_credential=False, cadence_thresholds={"DEDUP_EVERY_N": "5"}) + assert mem._cadence_thresholds == {"DEDUP_EVERY_N": 5} + + def test_negative_value_rejected(self): + with pytest.raises(ValueError): + CosmosMemoryClient(use_default_credential=False, cadence_thresholds={"DEDUP_EVERY_N": -1}) + + def test_non_int_value_rejected(self): + with pytest.raises(ValueError): + CosmosMemoryClient(use_default_credential=False, cadence_thresholds={"DEDUP_EVERY_N": "x"}) + + def test_non_mapping_rejected(self): + with pytest.raises(TypeError): + CosmosMemoryClient(use_default_credential=False, cadence_thresholds=[("DEDUP_EVERY_N", 5)]) From 6783c90c0a9c41632065f56fc9e0a30fbb280864 Mon Sep 17 00:00:00 2001 From: Theo van Kraay Date: Wed, 8 Jul 2026 16:33:12 +0100 Subject: [PATCH 4/4] Apply ruff format to cadence normalization helper --- azure/cosmos/agent_memory/services/_pipeline_helpers.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/azure/cosmos/agent_memory/services/_pipeline_helpers.py b/azure/cosmos/agent_memory/services/_pipeline_helpers.py index 5540e4b..14ddf8f 100644 --- a/azure/cosmos/agent_memory/services/_pipeline_helpers.py +++ b/azure/cosmos/agent_memory/services/_pipeline_helpers.py @@ -226,9 +226,7 @@ def _normalize_cadence_thresholds( except (TypeError, ValueError) as exc: raise ValueError(f"cadence_thresholds[{key!r}] must be an int, got {raw!r}.") from exc if coerced < 0: - raise ValueError( - f"cadence_thresholds[{key!r}] must be >= 0 (0 disables the step), got {coerced}." - ) + raise ValueError(f"cadence_thresholds[{key!r}] must be >= 0 (0 disables the step), got {coerced}.") normalized[str(key)] = coerced return normalized or None