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/reference/vendors.md
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ No constructor parameters. Use `FengmingSTT()`.
|---|---|---|---|---|
| `api_key` | `str` | Yes || OpenAI API key |
| `model` | `str` | No | `None` | Model (e.g., `gpt-4o-realtime-preview`) |
| `url` | `str` | No | `None` | Custom WebSocket URL |
| `url` | `str` | No | `wss://api.openai.com/v1/realtime` | OpenAI Realtime WebSocket URL |
| `greeting_message` | `str` | No | `None` | Greeting message |
| `failure_message` | `str` | No | `None` | Message played when the model call fails |
| `input_modalities` | `List[str]` | No | `None` | Input modalities |
Expand Down
8 changes: 5 additions & 3 deletions src/agora_agent/agentkit/vendors/mllm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ class OpenAIRealtime(BaseMLLM):
voice: Optional[str] = Field(default=None, description="Voice identifier")
instructions: Optional[str] = Field(default=None, description="System instructions")
input_audio_transcription: Optional[Dict[str, Any]] = Field(default=None, description="Audio transcription settings")
url: Optional[str] = Field(default=None, description="WebSocket URL")
url: str = Field(
default="wss://api.openai.com/v1/realtime",
description="OpenAI Realtime WebSocket URL",
)
greeting_message: Optional[str] = Field(default=None, description="Agent greeting message")
input_modalities: Optional[List[str]] = Field(default=None, description="Input modalities")
output_modalities: Optional[List[str]] = Field(default=None, description="Output modalities")
Expand All @@ -29,10 +32,9 @@ def to_config(self) -> Dict[str, Any]:
config: Dict[str, Any] = {
"vendor": "openai",
"api_key": self.api_key,
"url": self.url,
}

if self.url is not None:
config["url"] = self.url
if (
self.model is not None
or self.params is not None
Expand Down
20 changes: 20 additions & 0 deletions tests/custom/test_agentkit_vendors.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@ def test_xai_grok_serializes_v27_shape_without_style():
assert "style" not in config


def test_openai_realtime_uses_default_url_when_omitted():
config = OpenAIRealtime(api_key="openai-key").to_config()

assert config["url"] == "wss://api.openai.com/v1/realtime"


def test_openai_realtime_preserves_custom_url():
config = OpenAIRealtime(
api_key="openai-key",
url="wss://openai.example.com/v1/realtime",
).to_config()

assert config["url"] == "wss://openai.example.com/v1/realtime"


def test_openai_realtime_rejects_none_url():
with pytest.raises(ValidationError):
OpenAIRealtime(api_key="openai-key", url=None)


def test_xai_grok_emits_params_even_when_empty():
assert XaiGrok(api_key="xai-key").to_config()["params"] == {}

Expand Down
1 change: 1 addition & 0 deletions tests/custom/test_request_body.py
Original file line number Diff line number Diff line change
Expand Up @@ -1265,6 +1265,7 @@ def test_byok_openai_realtime_mllm_params() -> None:
props = build_properties(agent)
assert props["mllm"]["vendor"] == "openai"
assert props["mllm"]["api_key"] == "realtime-key"
assert props["mllm"]["url"] == "wss://api.openai.com/v1/realtime"
assert props["mllm"]["params"]["model"] == "gpt-4o-realtime-preview"
assert props["mllm"]["params"]["voice"] == "coral"

Expand Down
Loading