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 @@ -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` |

<!-- snippet: executable -->
```python
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/vendors.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand All @@ -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`

Expand Down
10 changes: 5 additions & 5 deletions src/agora_agent/agentkit/vendors/cn.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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]:
Expand All @@ -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:
Expand All @@ -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


Expand Down
31 changes: 28 additions & 3 deletions tests/custom/test_request_body.py
Original file line number Diff line number Diff line change
Expand Up @@ -1326,25 +1326,50 @@ 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"},
)
)

props = build_properties(agent)

assert props["mllm"]["vendor"] == "qwen_omni"
assert props["mllm"]["url"] == "QWEN_URL"
assert props["mllm"]["turn_detection"] == {"mode": "server_vad"}


Expand Down
Loading