From 6a3be7d810056850552a652d1420f79b50bda780 Mon Sep 17 00:00:00 2001 From: seymourtang Date: Tue, 4 Aug 2026 11:54:13 +0800 Subject: [PATCH] fix: update Qwen Omni configuration requirements - Changed the `url` parameter from optional to required in the Qwen Omni vendor documentation and implementation. - Updated the `turn_detection` parameter to be optional in the Qwen Omni configuration. - Modified tests to reflect the new requirement for the `url` parameter and adjusted validation for `turn_detection`. --- docs/concepts/vendors.md | 2 +- docs/reference/vendors.md | 4 ++-- src/agora_agent/agentkit/vendors/cn.py | 10 ++++----- tests/custom/test_request_body.py | 31 +++++++++++++++++++++++--- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/docs/concepts/vendors.md b/docs/concepts/vendors.md index 28d2d0e..34e2970 100644 --- a/docs/concepts/vendors.md +++ b/docs/concepts/vendors.md @@ -156,7 +156,7 @@ Used with `agent.with_mllm()` for the [MLLM flow](../guides/mllm-flow.md). These | `GeminiLive` | Google Gemini Live API | Global | `api_key`, `model`; optional `turn_detection` | | `VertexAI` | Vertex AI (Gemini Live) | Global | `model`, `project_id`, `location`, `adc_credentials_string`; optional `turn_detection` | | `XaiGrok` | xAI Grok (`mllm.vendor`: `xai`) | Global | `api_key`; optional `voice`, `language`, `sample_rate`, `turn_detection` | -| `QwenOmni` | Alibaba Cloud Qwen Omni Realtime | CN | `api_key`, `turn_detection`; optional `url` | +| `QwenOmni` | Alibaba Cloud Qwen Omni Realtime | CN | `api_key`, `url`; optional `turn_detection` | ```python diff --git a/docs/reference/vendors.md b/docs/reference/vendors.md index 9ab2250..0ce84f3 100644 --- a/docs/reference/vendors.md +++ b/docs/reference/vendors.md @@ -830,7 +830,7 @@ CN Alibaba Cloud Qwen Omni Realtime vendor (`mllm.vendor`: `"qwen_omni"`). Impor | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `api_key` | `str` | Yes | — | Alibaba Cloud Model Studio API key | -| `url` | `str` | No | `None` | Qwen Omni Realtime WebSocket URL | +| `url` | `str` | Yes | — | Qwen Omni Realtime WebSocket URL | | `model` | `str` | No | `None` | Qwen Omni Realtime model name | | `voice` | `str` | No | `None` | Voice identifier | | `instructions` | `str` | No | `None` | System instructions | @@ -841,7 +841,7 @@ CN Alibaba Cloud Qwen Omni Realtime vendor (`mllm.vendor`: `"qwen_omni"`). Impor | `output_modalities` | `List[str]` | No | `None` | Output modalities | | `messages` | `List[Dict]` | No | `None` | Conversation messages | | `params` | `Dict[str, Any]` | No | `None` | Additional Qwen Omni parameters | -| `turn_detection` | `MllmTurnDetectionConfig` | Yes | — | Required MLLM turn detection configuration; overrides top-level `turn_detection` | +| `turn_detection` | `MllmTurnDetectionConfig` | No | `None` | MLLM turn detection configuration; overrides top-level `turn_detection` | ### `GeminiLive` diff --git a/src/agora_agent/agentkit/vendors/cn.py b/src/agora_agent/agentkit/vendors/cn.py index fbefa30..e336136 100644 --- a/src/agora_agent/agentkit/vendors/cn.py +++ b/src/agora_agent/agentkit/vendors/cn.py @@ -800,7 +800,7 @@ class QwenOmni(BaseMLLM): model_config = ConfigDict(extra="forbid") api_key: str = Field(..., description="Alibaba Cloud Model Studio API key") - url: Optional[str] = Field(default=None, description="Qwen Omni Realtime WebSocket URL") + url: str = Field(..., description="Qwen Omni Realtime WebSocket URL") model: Optional[str] = Field(default=None, description="Qwen Omni Realtime model name") voice: Optional[str] = Field(default=None, description="Voice identifier") instructions: Optional[str] = Field(default=None, description="System instructions") @@ -812,7 +812,7 @@ class QwenOmni(BaseMLLM): output_modalities: Optional[List[str]] = Field(default=None, description="Output modalities") messages: Optional[List[Dict[str, Any]]] = Field(default=None, description="Conversation messages") params: Optional[Dict[str, Any]] = Field(default=None, description="Additional Qwen Omni parameters") - turn_detection: MllmTurnDetection = Field(..., description="MLLM turn detection configuration") + turn_detection: Optional[MllmTurnDetection] = Field(default=None, description="MLLM turn detection configuration") failure_message: Optional[str] = Field(default=None, description="Message played on failure") def to_config(self) -> Dict[str, Any]: @@ -829,9 +829,8 @@ def to_config(self) -> Dict[str, Any]: config: Dict[str, Any] = { "vendor": "qwen_omni", "api_key": self.api_key, + "url": self.url, } - if self.url is not None: - config["url"] = self.url if inner_params: config["params"] = inner_params if self.greeting_message is not None: @@ -844,7 +843,8 @@ def to_config(self) -> Dict[str, Any]: config["messages"] = self.messages if self.failure_message is not None: config["failure_message"] = self.failure_message - config["turn_detection"] = self.turn_detection + if self.turn_detection is not None: + config["turn_detection"] = self.turn_detection return config diff --git a/tests/custom/test_request_body.py b/tests/custom/test_request_body.py index 4034ba3..f71fd5d 100644 --- a/tests/custom/test_request_body.py +++ b/tests/custom/test_request_body.py @@ -1326,18 +1326,42 @@ def test_azure_openai_realtime_rejects_input_modalities() -> None: ) -def test_azure_and_qwen_mllm_require_turn_detection() -> None: +def test_azure_mllm_requires_turn_detection_and_qwen_mllm_requires_url() -> None: with pytest.raises(ValidationError): AzureOpenAIRealtime(url="AZURE_URL", api_key="APIKEY") # type: ignore[call-arg] with pytest.raises(ValidationError): - QwenOmni(api_key="APIKEY") # type: ignore[call-arg] + QwenOmni( # type: ignore[call-arg] + api_key="APIKEY", + turn_detection={"mode": "server_vad"}, + ) + + +def test_byok_qwen_omni_mllm_allows_omitting_turn_detection() -> None: + agent = Agent(test_client(area=Area.CN)).with_mllm( + QwenOmni( + api_key="xxxxxxxx", + url="wss://dashscope.aliyuncs.com/api-ws/v1/realtime", + model="qwen3.5-omni-plus-realtime", + ) + ) + + props = build_properties(agent) + + assert props["mllm"] == { + "enable": True, + "vendor": "qwen_omni", + "url": "wss://dashscope.aliyuncs.com/api-ws/v1/realtime", + "api_key": "xxxxxxxx", + "params": {"model": "qwen3.5-omni-plus-realtime"}, + } -def test_byok_qwen_omni_mllm_requires_and_serializes_turn_detection() -> None: +def test_byok_qwen_omni_mllm_serializes_optional_turn_detection() -> None: agent = Agent(test_client(area=Area.CN)).with_mllm( QwenOmni( api_key="APIKEY", + url="QWEN_URL", turn_detection={"mode": "server_vad"}, ) ) @@ -1345,6 +1369,7 @@ def test_byok_qwen_omni_mllm_requires_and_serializes_turn_detection() -> None: props = build_properties(agent) assert props["mllm"]["vendor"] == "qwen_omni" + assert props["mllm"]["url"] == "QWEN_URL" assert props["mllm"]["turn_detection"] == {"mode": "server_vad"}