From 981650b9fd124d64c4e09ebde178cee0af33375a Mon Sep 17 00:00:00 2001 From: Ben Carr Date: Thu, 23 Jul 2026 14:13:40 +0100 Subject: [PATCH 1/5] Add AI avatar disclosure session option --- README.md | 12 ++++++++++++ src/anam/types.py | 5 +++++ tests/test_client.py | 9 +++++++++ 3 files changed, 26 insertions(+) diff --git a/README.md b/README.md index 72d34b4..e32f088 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,18 @@ async with client.connect(session_options=session_options) as session: Currently, only `"high"` or `"auto"` are supported `video_quality` values. +### AI avatar disclosure + +Anam applies the AI avatar disclosure automatically when required. To request it +explicitly for a session: + +```python +session_options = SessionOptions(show_ai_avatar_disclosure=True) +``` + +Eligible plans can set `show_ai_avatar_disclosure=False` when the application +provides its own disclosure. Leave it unset to use Anam's default. + ## Direct Egress (Daily) > [!WARNING] diff --git a/src/anam/types.py b/src/anam/types.py index b82444b..68c2ff9 100644 --- a/src/anam/types.py +++ b/src/anam/types.py @@ -207,6 +207,8 @@ class SessionOptions: video_quality: Video quality profile to pin the video quality. Supported values are "high" (default) and "auto". video_width: Requested video output width. Must be provided with video_height. video_height: Requested video output height. Must be provided with video_width. + show_ai_avatar_disclosure: Show the AI avatar disclosure at session start. + Omit to use Anam's default. Explicit False requires an eligible plan. egress: Optional direct egress to a third-party transport (e.g. Daily). See :class:`EgressOptions`. """ @@ -214,6 +216,7 @@ class SessionOptions: video_quality: Literal["high", "auto"] = "high" video_width: int | None = None video_height: int | None = None + show_ai_avatar_disclosure: bool | None = None egress: EgressOptions | None = None def __post_init__(self) -> None: @@ -241,6 +244,8 @@ def to_dict(self) -> dict[str, Any]: if self.video_width is not None and self.video_height is not None: result["videoWidth"] = self.video_width result["videoHeight"] = self.video_height + if self.show_ai_avatar_disclosure is not None: + result["showAiAvatarDisclosure"] = self.show_ai_avatar_disclosure if self.egress is not None: result["egress"] = self.egress.to_dict() return result diff --git a/tests/test_client.py b/tests/test_client.py index 4c88d2d..f9298be 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -283,6 +283,15 @@ def test_to_dict_with_video_dimensions(self) -> None: "videoHeight": 768, } + @pytest.mark.parametrize("value", [True, False]) + def test_to_dict_with_ai_avatar_disclosure(self, value: bool) -> None: + options = SessionOptions(show_ai_avatar_disclosure=value) + + assert options.to_dict()["showAiAvatarDisclosure"] is value + + def test_to_dict_omits_ai_avatar_disclosure_by_default(self) -> None: + assert "showAiAvatarDisclosure" not in SessionOptions().to_dict() + def test_invalid_video_quality_raises_value_error(self) -> None: with pytest.raises(ValueError, match='video_quality must be either "high" or "auto"'): SessionOptions(video_quality="medium") # type: ignore[arg-type] From ff36128ba72cd8b38b74b3bd76152b1962cdbbf7 Mon Sep 17 00:00:00 2001 From: Ben Carr Date: Thu, 23 Jul 2026 14:30:16 +0100 Subject: [PATCH 2/5] Preserve SessionOptions positional compatibility --- src/anam/types.py | 4 ++-- tests/test_client.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/anam/types.py b/src/anam/types.py index 68c2ff9..f5f5042 100644 --- a/src/anam/types.py +++ b/src/anam/types.py @@ -207,17 +207,17 @@ class SessionOptions: video_quality: Video quality profile to pin the video quality. Supported values are "high" (default) and "auto". video_width: Requested video output width. Must be provided with video_height. video_height: Requested video output height. Must be provided with video_width. + egress: Optional direct egress to a third-party transport (e.g. Daily). See :class:`EgressOptions`. show_ai_avatar_disclosure: Show the AI avatar disclosure at session start. Omit to use Anam's default. Explicit False requires an eligible plan. - egress: Optional direct egress to a third-party transport (e.g. Daily). See :class:`EgressOptions`. """ enable_session_replay: bool = True video_quality: Literal["high", "auto"] = "high" video_width: int | None = None video_height: int | None = None - show_ai_avatar_disclosure: bool | None = None egress: EgressOptions | None = None + show_ai_avatar_disclosure: bool | None = None def __post_init__(self) -> None: self._session_replay = SessionReplayOptions( diff --git a/tests/test_client.py b/tests/test_client.py index f9298be..af1b85d 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -12,6 +12,8 @@ AnamEvent, ClientOptions, DirectorNotes, + EgressDailyOptions, + EgressOptions, MessageRole, MessageStreamEvent, PersonaConfig, @@ -292,6 +294,17 @@ def test_to_dict_with_ai_avatar_disclosure(self, value: bool) -> None: def test_to_dict_omits_ai_avatar_disclosure_by_default(self) -> None: assert "showAiAvatarDisclosure" not in SessionOptions().to_dict() + def test_ai_avatar_disclosure_preserves_positional_egress_argument(self) -> None: + egress = EgressOptions( + mode="daily", + daily=EgressDailyOptions(room_url="https://example.daily.co/room"), + ) + options = SessionOptions(True, "high", None, None, egress) + + assert options.egress is egress + assert options.show_ai_avatar_disclosure is None + assert options.to_dict()["egress"]["mode"] == "daily" + def test_invalid_video_quality_raises_value_error(self) -> None: with pytest.raises(ValueError, match='video_quality must be either "high" or "auto"'): SessionOptions(video_quality="medium") # type: ignore[arg-type] From 2427e606500065bf4fd2a7909e3e57ec0df507d0 Mon Sep 17 00:00:00 2001 From: Ben Carr Date: Thu, 23 Jul 2026 17:51:15 +0100 Subject: [PATCH 3/5] Match session option serialization order --- src/anam/types.py | 4 ++-- tests/test_client.py | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/anam/types.py b/src/anam/types.py index f5f5042..b8f75c2 100644 --- a/src/anam/types.py +++ b/src/anam/types.py @@ -244,10 +244,10 @@ def to_dict(self) -> dict[str, Any]: if self.video_width is not None and self.video_height is not None: result["videoWidth"] = self.video_width result["videoHeight"] = self.video_height - if self.show_ai_avatar_disclosure is not None: - result["showAiAvatarDisclosure"] = self.show_ai_avatar_disclosure if self.egress is not None: result["egress"] = self.egress.to_dict() + if self.show_ai_avatar_disclosure is not None: + result["showAiAvatarDisclosure"] = self.show_ai_avatar_disclosure return result diff --git a/tests/test_client.py b/tests/test_client.py index af1b85d..4a3a4bc 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -299,11 +299,18 @@ def test_ai_avatar_disclosure_preserves_positional_egress_argument(self) -> None mode="daily", daily=EgressDailyOptions(room_url="https://example.daily.co/room"), ) - options = SessionOptions(True, "high", None, None, egress) + options = SessionOptions(True, "high", None, None, egress, True) assert options.egress is egress - assert options.show_ai_avatar_disclosure is None - assert options.to_dict()["egress"]["mode"] == "daily" + assert options.show_ai_avatar_disclosure is True + result = options.to_dict() + assert result["egress"]["mode"] == "daily" + assert list(result) == [ + "sessionReplay", + "videoQuality", + "egress", + "showAiAvatarDisclosure", + ] def test_invalid_video_quality_raises_value_error(self) -> None: with pytest.raises(ValueError, match='video_quality must be either "high" or "auto"'): From ab42deb48ca0e04007fd15859fbcd81fab50ed9f Mon Sep 17 00:00:00 2001 From: Ben Carr Date: Thu, 23 Jul 2026 18:00:03 +0100 Subject: [PATCH 4/5] Clarify persistent AI avatar disclosure --- README.md | 4 ++-- src/anam/types.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e32f088..f63b987 100644 --- a/README.md +++ b/README.md @@ -102,8 +102,8 @@ Currently, only `"high"` or `"auto"` are supported `video_quality` values. ### AI avatar disclosure -Anam applies the AI avatar disclosure automatically when required. To request it -explicitly for a session: +Anam applies the AI avatar disclosure automatically when required. When +enabled, it remains visible throughout the session. To request it explicitly: ```python session_options = SessionOptions(show_ai_avatar_disclosure=True) diff --git a/src/anam/types.py b/src/anam/types.py index b8f75c2..95eab74 100644 --- a/src/anam/types.py +++ b/src/anam/types.py @@ -208,7 +208,7 @@ class SessionOptions: video_width: Requested video output width. Must be provided with video_height. video_height: Requested video output height. Must be provided with video_width. egress: Optional direct egress to a third-party transport (e.g. Daily). See :class:`EgressOptions`. - show_ai_avatar_disclosure: Show the AI avatar disclosure at session start. + show_ai_avatar_disclosure: Show the AI avatar disclosure throughout the session. Omit to use Anam's default. Explicit False requires an eligible plan. """ From eba35f7233f0b0a1421ec8ccf6d9787babafc1dd Mon Sep 17 00:00:00 2001 From: sr-anam Date: Fri, 31 Jul 2026 10:25:10 +0100 Subject: [PATCH 5/5] fix variable name and eligible plan wording --- README.md | 4 ++-- src/anam/types.py | 4 ++-- tests/test_client.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f63b987..5b4a914 100644 --- a/README.md +++ b/README.md @@ -109,8 +109,8 @@ enabled, it remains visible throughout the session. To request it explicitly: session_options = SessionOptions(show_ai_avatar_disclosure=True) ``` -Eligible plans can set `show_ai_avatar_disclosure=False` when the application -provides its own disclosure. Leave it unset to use Anam's default. +Set `show_ai_avatar_disclosure=False` when the application provides its own +disclosure. Leave it unset to use Anam's default. ## Direct Egress (Daily) diff --git a/src/anam/types.py b/src/anam/types.py index 95eab74..a267230 100644 --- a/src/anam/types.py +++ b/src/anam/types.py @@ -209,7 +209,7 @@ class SessionOptions: video_height: Requested video output height. Must be provided with video_width. egress: Optional direct egress to a third-party transport (e.g. Daily). See :class:`EgressOptions`. show_ai_avatar_disclosure: Show the AI avatar disclosure throughout the session. - Omit to use Anam's default. Explicit False requires an eligible plan. + Omit to use Anam's default. """ enable_session_replay: bool = True @@ -247,7 +247,7 @@ def to_dict(self) -> dict[str, Any]: if self.egress is not None: result["egress"] = self.egress.to_dict() if self.show_ai_avatar_disclosure is not None: - result["showAiAvatarDisclosure"] = self.show_ai_avatar_disclosure + result["showAIAvatarDisclosure"] = self.show_ai_avatar_disclosure return result diff --git a/tests/test_client.py b/tests/test_client.py index 4a3a4bc..3933e70 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -289,10 +289,10 @@ def test_to_dict_with_video_dimensions(self) -> None: def test_to_dict_with_ai_avatar_disclosure(self, value: bool) -> None: options = SessionOptions(show_ai_avatar_disclosure=value) - assert options.to_dict()["showAiAvatarDisclosure"] is value + assert options.to_dict()["showAIAvatarDisclosure"] is value def test_to_dict_omits_ai_avatar_disclosure_by_default(self) -> None: - assert "showAiAvatarDisclosure" not in SessionOptions().to_dict() + assert "showAIAvatarDisclosure" not in SessionOptions().to_dict() def test_ai_avatar_disclosure_preserves_positional_egress_argument(self) -> None: egress = EgressOptions( @@ -309,7 +309,7 @@ def test_ai_avatar_disclosure_preserves_positional_egress_argument(self) -> None "sessionReplay", "videoQuality", "egress", - "showAiAvatarDisclosure", + "showAIAvatarDisclosure", ] def test_invalid_video_quality_raises_value_error(self) -> None: