Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/concepts/vendors.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Used with `agent.with_avatar()` in the cascading ASR + LLM + TTS pipeline. Some
| `AkoolAvatar` | Akool | `api_key` | 16000 Hz |
| `AnamAvatar` | Anam | `api_key` | None |
| `GenericAvatar` | Generic Avatar | `api_key`, `api_base_url`, `avatar_id`, `agora_uid` | None |
| `SenseTimeAvatar` | SenseTime (CN) | `agora_uid`, `app_key`, `sceneList` | None |
| `SenseTimeAvatar` | SenseTime (CN) | `agora_uid`, `app_key` | None |
| `SpatiusAvatar` | Spatius (CN) | `spatius_api_key`, `spatius_app_id`, `spatius_avatar_id`, `agora_uid` | Optional avatar-declared sample rate |

<!-- snippet: executable -->
Expand Down
4 changes: 2 additions & 2 deletions docs/guides/avatars.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ agent = agent.with_avatar(GenericAvatar(

## SenseTime Avatar (CN)

`SenseTimeAvatar` is available for `Area.CN` sessions. Provide `agora_uid`, `app_key`, and `sceneList` when constructing the avatar. `agora_token` is optional and is generated at session start when omitted, like LiveAvatar and Generic avatars.
`SenseTimeAvatar` is available for `Area.CN` sessions. Provide `agora_uid` and `app_key` when constructing the avatar. `sceneList` is optional. `agora_token` is optional and is generated at session start when omitted, like LiveAvatar and Generic avatars.

```python
from agora_agent import Agora, Area, CNAgent, MiniMaxCNTTS, SenseTimeAvatar, TencentSTT
Expand Down Expand Up @@ -276,7 +276,7 @@ If you call `with_avatar()` before `with_tts()`, the sample rate check is deferr
| `agora_token` | `str` | No | Avatar publisher RTC token; generated at session start when omitted |
| `agora_uid` | `str` | Yes | Avatar publisher RTC UID |
| `app_key` | `str` | Yes | SenseTime application key |
| `sceneList` | `List[Dict[str, Any]]` | Yes | SenseTime scene configuration list |
| `sceneList` | `List[Dict[str, Any]]` | No | SenseTime scene configuration list |
| `appId` | `str` | No | SenseTime application ID |
| `enable` | `bool` | No | Whether to enable the avatar |
| `additional_params` | `Dict[str, Any]` | No | Additional SenseTime avatar parameters |
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/vendors.md
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ No constructor parameters. Use `FengmingSTT()`.
| `agora_uid` | `str` | Yes | — | Avatar RTC publisher uid |
| `appId` | `str` | No | `None` | SenseTime app id |
| `app_key` | `str` | Yes | — | SenseTime app key |
| `sceneList` | `List[Dict[str, Any]]` | Yes | | SenseTime scene list |
| `sceneList` | `List[Dict[str, Any]]` | No | `None` | SenseTime scene list |
| `enable` | `bool` | No | `None` | Whether to enable the avatar |
| `additional_params` | `Dict[str, Any]` | No | `None` | Additional SenseTime avatar parameters |

Expand Down
3 changes: 0 additions & 3 deletions src/agora_agent/agentkit/avatar_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,6 @@ def validate_avatar_config(
params = config.get("params", {})
if not params.get("app_key"):
raise ValueError("SenseTime avatar requires app_key")
scene_list = params.get("sceneList")
if not scene_list:
raise ValueError("SenseTime avatar requires sceneList")
if not params.get("agora_uid"):
raise ValueError("SenseTime avatar requires agora_uid")
if require_session_fields and not params.get("agora_token"):
Expand Down
5 changes: 3 additions & 2 deletions src/agora_agent/agentkit/vendors/cn.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ class SenseTimeAvatarOptions(BaseModel):
agora_uid: str = Field(..., description="Avatar RTC publisher uid")
app_id: Optional[str] = Field(default=None, alias="appId", description="SenseTime app id")
app_key: str = Field(..., description="SenseTime app key")
scene_list: List[Dict[str, Any]] = Field(..., alias="sceneList", description="SenseTime scene list")
scene_list: Optional[List[Dict[str, Any]]] = Field(default=None, alias="sceneList", description="SenseTime scene list")
enable: Optional[bool] = Field(default=None)
additional_params: Optional[Dict[str, Any]] = Field(default=None)

Expand All @@ -573,12 +573,13 @@ def to_config(self) -> Dict[str, Any]:
params: Dict[str, Any] = {
"agora_uid": self.options.agora_uid,
"app_key": self.options.app_key,
"sceneList": self.options.scene_list,
}
if self.options.agora_token is not None:
params["agora_token"] = self.options.agora_token
if self.options.app_id is not None:
params["appId"] = self.options.app_id
if self.options.scene_list is not None:
params["sceneList"] = self.options.scene_list
if self.options.additional_params is not None:
params = {**self.options.additional_params, **params}

Expand Down
47 changes: 43 additions & 4 deletions tests/custom/test_sensetime_avatar.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,20 @@ def test_sensetime_avatar_to_config_omits_token_when_not_provided() -> None:
assert config["params"]["agora_uid"] == "2"


def test_sensetime_avatar_to_config_omits_scene_list_when_not_provided() -> None:
config = SenseTimeAvatar(
agora_uid="2",
app_key="sensetime-app-key",
).to_config()

assert "sceneList" not in config["params"]
assert config["params"]["agora_uid"] == "2"


@pytest.mark.parametrize(
("params", "message"),
[
({}, "SenseTime avatar requires app_key"),
(
{"app_key": "key", "agora_uid": "2"},
"SenseTime avatar requires sceneList",
),
(
{"app_key": "key", "sceneList": _scene_list()},
"SenseTime avatar requires agora_uid",
Expand Down Expand Up @@ -110,6 +116,18 @@ def test_validate_avatar_config_requires_agora_token_at_session_time() -> None:
)


def test_validate_avatar_config_allows_missing_scene_list() -> None:
validate_avatar_config(
{
"vendor": "sensetime",
"params": {
"app_key": "key",
"agora_uid": "2",
},
}
)


def test_sensetime_avatar_session_validation_and_token_passthrough() -> None:
agent = Agent(test_client()).with_avatar(
SenseTimeAvatar(
Expand Down Expand Up @@ -173,3 +191,24 @@ def test_sensetime_avatar_user_token_is_not_overwritten() -> None:
)

assert properties["avatar"]["params"]["agora_token"] == "user-token"


def test_sensetime_avatar_enrichment_without_scene_list() -> None:
agent = Agent(test_client()).with_avatar(
SenseTimeAvatar(
agora_uid="2",
app_key="sensetime-app-key",
)
)
session = _session(agent)

properties = session._build_start_properties( # noqa: SLF001
{"app_id": APP_ID, "app_certificate": APP_CERTIFICATE},
skip_vendor_validation_categories=set(),
allow_missing_vendor_categories={"tts", "llm", "asr"},
)

params = properties["avatar"]["params"]
assert "sceneList" not in params
assert params["agora_uid"] == "2"
assert params["agora_token"]
Loading