Add MiniMax text-to-audio connector - #14324
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new Python connector under semantic_kernel.connectors.ai.minimax to call MiniMax’s T2A v2 endpoint and return AudioContent, wired via environment-backed settings and exposed through the connectors package README.
Changes:
- Introduces
MiniMaxTextToAudioservice client with environment-based configuration (MiniMaxSettings) and request execution settings (MiniMaxTextToAudioExecutionSettings). - Adds unit tests for settings serialization and environment initialization.
- Updates the AI connectors README to list the new MiniMax connector.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| python/semantic_kernel/connectors/ai/minimax/services/minimax_text_to_audio.py | New MiniMax T2A v2 client implementation (HTTP request + response decoding). |
| python/semantic_kernel/connectors/ai/minimax/prompt_execution_settings/minimax_text_to_audio_execution_settings.py | Defines MiniMax T2A request fields and serialization aliases. |
| python/semantic_kernel/connectors/ai/minimax/settings/minimax_settings.py | Adds env-backed settings for API key, default model id, and base URL. |
| python/semantic_kernel/connectors/ai/minimax/init.py | Exposes MiniMax public API surface (MiniMaxSettings, MiniMaxTextToAudio, settings class). |
| python/semantic_kernel/connectors/ai/minimax/services/init.py | Package export for the MiniMax service client. |
| python/semantic_kernel/connectors/ai/minimax/prompt_execution_settings/init.py | Package export for MiniMax execution settings. |
| python/semantic_kernel/connectors/ai/minimax/settings/init.py | Package export for MiniMax settings. |
| python/semantic_kernel/connectors/ai/README.md | Documents the new MiniMax connector in the connectors index. |
| python/tests/unit/connectors/ai/minimax/test_minimax_text_to_audio.py | Adds initial unit tests for settings dict serialization + env initialization. |
| python/tests/unit/connectors/ai/minimax/init.py | Marks the new MiniMax unit test package. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| audio = base64.b64decode(encoded) | ||
| return [AudioContent(ai_model_id=request.ai_model_id, data=audio, data_format="base64", inner_content=body)] | ||
| except Exception as ex: | ||
| raise ServiceResponseException(f"{type(self)} service failed to generate audio", ex) from ex |
| body = await response.json(content_type=None) | ||
| response.raise_for_status() |
| def test_text_to_audio_from_environment(monkeypatch) -> None: | ||
| monkeypatch.setenv("MINIMAX_API_KEY", "test-key") | ||
| monkeypatch.setenv("MINIMAX_TEXT_TO_AUDIO_MODEL_ID", "speech-2.8-hd") | ||
|
|
||
| service = MiniMaxTextToAudio() |
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: Findings reported
Scope: full PR (1 commit(s)): 8b2aea144fc6
Model: claude-opus-4.8
Overview
This PR adds a self-contained MiniMax T2A v2 text-to-audio connector (settings, execution
settings, HTTP service, docs, and two unit tests). It is purely additive, mirrors the OpenAI
connector's AudioContent(data=<raw bytes>, data_format="base64") construction, correctly
aliases the payload to the MiniMax API shape via prepare_settings_dict, and guards
initialization with ServiceInitializationError. Two concerns established below constitute the
residual risk: the service stores the raw API key as a serializable pydantic model field
(exposed in repr/model_dump/model_dump_json), diverging from every other connector in the
repo; and the request path calls raise_for_status() before inspecting MiniMax's own error
body, so the provider's descriptive status_msg is discarded on non-2xx responses.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
2 verified findings remained after source verification (1 high, 1 medium) across 1 file. Details are attached to the affected lines below.
Affected areas: python/semantic_kernel/connectors/ai/minimax/services/minimax_text_to_audio.py
| class MiniMaxTextToAudio(TextToAudioClientBase): | ||
| """MiniMax speech-2.x text-to-audio HTTP service.""" | ||
|
|
||
| api_key: str |
There was a problem hiding this comment.
api_key is declared as a bare field on this KernelBaseModel subclass and is populated with the
unwrapped secret (api_key=settings.api_key.get_secret_value() at line 56). Because the client is a
Pydantic model, the plaintext key is then included in repr(self), model_dump(), and
model_dump_json():
DUMP: {'ai_model_id': 'speech-2.8-hd', 'service_id': '', 'api_key': 'SECRET-abc123', ...}
Any diagnostic logging, str(service) in a stack trace, or serialization of the service object
writes the raw MiniMax key in cleartext. Every other connector avoids this by handing the secret to
an SDK client rather than storing it as a model field, and MiniMaxSettings.api_key is already a
SecretStr whose protection is discarded here. Store the credential as a SecretStr or a
PrivateAttr (or mark it Field(exclude=True, repr=False)) so it is not exposed via repr/dump.
| session.post(self.base_url, json=payload) as response, | ||
| ): | ||
| body = await response.json(content_type=None) | ||
| response.raise_for_status() |
There was a problem hiding this comment.
On any non-2xx response, response.raise_for_status() raises before the base_resp.status_code /
status_msg inspection a few lines below, so MiniMax's descriptive error message is discarded and
the caller only sees the bare HTTP status. Additionally, when an error response has an empty or
non-JSON body, response.json() on the preceding line raises JSONDecodeError first, masking the
real status entirely. Both cases collapse into a generic ServiceResponseException, making auth,
quota, and validation failures hard to diagnose. Inspect the parsed base_resp (and surface its
status_msg) before calling raise_for_status(), and guard the JSON parse so a non-JSON error body
still yields the HTTP status.
Reason: Add MiniMax text-to-audio connector support.
Implemented the MiniMax T2A v2 client, request settings, environment configuration, endpoint handling, and audio response decoding. Added connector documentation and focused unit coverage.
Checks: