Skip to content

feat: add MiniMax TTS provider - #39

Open
octo-patch wants to merge 1 commit into
framerslab:masterfrom
octo-patch:octo/20260812-tts-tool-recvrXOhMnuC8R
Open

feat: add MiniMax TTS provider#39
octo-patch wants to merge 1 commit into
framerslab:masterfrom
octo-patch:octo/20260812-tts-tool-recvrXOhMnuC8R

Conversation

@octo-patch

@octo-patch octo-patch commented Aug 12, 2026

Copy link
Copy Markdown

Reason: add a MiniMax TTS provider to the existing speech registry with global and China endpoints, current speech models, HTTP, async, and WebSocket operations, request options, and audio response parsing

This adds an environment-backed speech provider with regional routing and the current model catalog. It supports synchronous HTTP synthesis, asynchronous task creation and querying, and the WebSocket start/continue/finish protocol while forwarding voice, pronunciation, audio, language, subtitle, and voice-modification options.

Checks:

  • pnpm exec vitest run src/io/speech/__tests__/MiniMaxTextToSpeechProvider.test.ts src/io/speech/__tests__/providerCatalog.test.ts src/io/speech/__tests__/SpeechRuntime.test.ts
  • pnpm exec tsc --noEmit --pretty false
  • pnpm exec eslint src/io/speech/providers/MiniMaxTextToSpeechProvider.ts src/io/speech/providerCatalog.ts src/io/speech/SpeechProviderResolver.ts src/io/speech/SpeechRuntime.ts src/io/speech/index.ts --no-warn-ignored
  • git diff --check
  • Secret scan on the changed files

Summary by Sourcery

Add a MiniMax text-to-speech provider with regional routing and full integration into the speech runtime and provider catalog.

New Features:

  • Introduce a MiniMax TTS provider supporting HTTP synthesis, asynchronous task APIs, and WebSocket streaming with configurable models, voices, and audio formats.

Enhancements:

  • Wire the MiniMax TTS provider into the speech runtime, resolver, and public speech module exports, making it discoverable like existing cloud TTS providers.
  • Document MiniMax TTS capabilities and requirements in the speech provider catalog, including default model and required environment variables.

Tests:

  • Add unit tests covering MiniMax HTTP synthesis, China-region URL-based audio retrieval, async task creation/query, WebSocket protocol handling, and invalid audio error cases.
  • Extend SpeechRuntime and provider catalog tests to assert MiniMax TTS registration and capability exposure when the corresponding environment variable is set.

Summary by CodeRabbit

  • New Features

    • Added MiniMax text-to-speech support.
    • Supports standard synthesis, asynchronous generation, and WebSocket streaming.
    • Added configurable regions, models, voices, audio formats, and speech settings.
    • MiniMax can be automatically registered when an API key is configured.
    • Added support for API key pooling and audio result metadata.
  • Tests

    • Added coverage for synthesis, streaming, regional endpoints, asynchronous tasks, and response validation.

@sourcery-ai

sourcery-ai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a MiniMax text-to-speech provider with regional (global/China) routing, HTTP sync, async task, and WebSocket streaming synthesis, wires it into the speech runtime, resolver, and provider catalog, and covers behavior with targeted tests.

Sequence diagram for MiniMax WebSocket TTS synthesis

sequenceDiagram
actor Client
participant SpeechRuntime
participant MiniMaxTextToSpeechProvider
participant MiniMaxWebSocket

Client->>SpeechRuntime: synthesizeWebSocket(text, options)
SpeechRuntime->>MiniMaxTextToSpeechProvider: synthesizeWebSocket(text, options)
MiniMaxTextToSpeechProvider->>MiniMaxWebSocket: new WebSocket(socketUrl, headers)
MiniMaxWebSocket-->>MiniMaxTextToSpeechProvider: event connected_success
MiniMaxTextToSpeechProvider->>MiniMaxWebSocket: send task_start(buildRequest(...))
MiniMaxWebSocket-->>MiniMaxTextToSpeechProvider: event task_started
MiniMaxTextToSpeechProvider->>MiniMaxWebSocket: send task_continue(text)
MiniMaxTextToSpeechProvider->>MiniMaxWebSocket: send task_finish()
MiniMaxWebSocket-->>MiniMaxTextToSpeechProvider: event task_continued(audio hex)
MiniMaxTextToSpeechProvider->>MiniMaxTextToSpeechProvider: decodeHexAudio(audio)
MiniMaxWebSocket-->>MiniMaxTextToSpeechProvider: event task_finished
MiniMaxTextToSpeechProvider->>MiniMaxTextToSpeechProvider: result(Buffer.concat(chunks), text, options, audioFormat)
MiniMaxTextToSpeechProvider-->>SpeechRuntime: SpeechSynthesisResult
SpeechRuntime-->>Client: SpeechSynthesisResult
Loading

File-Level Changes

Change Details Files
Introduce MiniMaxTextToSpeechProvider implementing HTTP, async, and WebSocket MiniMax TTS APIs with regional routing and audio response handling.
  • Define MiniMax-specific types, models, regions, audio formats, and MIME mappings.
  • Implement HTTP synthesis that builds MiniMax request payloads, supports provider-specific options, and decodes hex or URL-based audio responses.
  • Implement async task creation and query endpoints for long-running synthesis.
  • Implement WebSocket-based streaming synthesis with task_start/continue/finish protocol handling, incremental audio aggregation, and error handling.
  • Add shared request helper with ApiKeyPool-based auth, base URL selection from region, and MiniMax error/status-code validation.
  • Construct SpeechSynthesisResult objects that include duration, usage, model, region, and voice metadata.
src/io/speech/providers/MiniMaxTextToSpeechProvider.ts
Expose MiniMax TTS provider in public speech API, runtime wiring, provider resolver, and provider catalog with environment-backed configuration.
  • Register MiniMaxTextToSpeechProvider in SpeechRuntime when MINIMAX_API_KEY is present, using MINIMAX_REGION/MINIMAX_TTS_MODEL/MINIMAX_TTS_VOICE for configuration.
  • Add MiniMax TTS entry in SPEECH_PROVIDER_CATALOG with streaming, async, and WebSocket capabilities and default model.
  • Update SpeechProviderResolver built-in provider list to include minimax-tts keyed off MINIMAX_API_KEY.
  • Export MiniMaxTextToSpeechProvider from the speech index module for external usage.
src/io/speech/SpeechRuntime.ts
src/io/speech/providerCatalog.ts
src/io/speech/SpeechProviderResolver.ts
src/io/speech/index.ts
Add tests validating MiniMax provider behavior and integration into existing speech runtime and catalog.
  • Verify provider catalog exposes minimax-tts with correct kind, streaming flag, default model, env vars, and features.
  • Ensure SpeechRuntime hydrates minimax-tts when MINIMAX_API_KEY is present and that getProvider finds it.
  • Add unit tests for MiniMaxTextToSpeechProvider covering HTTP hex synthesis, China endpoint URL downloads, async task creation/query, WebSocket protocol flow, and invalid hex error handling.
src/io/speech/__tests__/providerCatalog.test.ts
src/io/speech/__tests__/SpeechRuntime.test.ts
src/io/speech/__tests__/MiniMaxTextToSpeechProvider.test.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Added the MiniMax text-to-speech provider with synchronous HTTP, asynchronous task, and WebSocket synthesis. Added regional configuration, audio decoding, runtime registration, catalog metadata, public exports, and Vitest coverage.

Changes

MiniMax TTS integration

Layer / File(s) Summary
Provider contracts and HTTP synthesis
src/io/speech/providers/MiniMaxTextToSpeechProvider.ts, src/io/speech/__tests__/MiniMaxTextToSpeechProvider.test.ts
The provider defines MiniMax options and response types. It supports regional HTTP synthesis, hex or URL audio, format validation, response validation, and synthesis metadata. Tests cover global and China endpoints and invalid hex audio.
Asynchronous and WebSocket synthesis
src/io/speech/providers/MiniMaxTextToSpeechProvider.ts, src/io/speech/__tests__/MiniMaxTextToSpeechProvider.test.ts
The provider creates and queries asynchronous tasks. It processes WebSocket task events and streamed audio chunks. Tests cover task requests and the WebSocket protocol.
Runtime registration and public exposure
src/io/speech/providerCatalog.ts, src/io/speech/SpeechProviderResolver.ts, src/io/speech/SpeechRuntime.ts, src/io/speech/index.ts, src/io/speech/__tests__/providerCatalog.test.ts, src/io/speech/__tests__/SpeechRuntime.test.ts
The catalog and resolver register minimax-tts with MINIMAX_API_KEY. The runtime configures region, model, and voice from environment variables. The speech barrel exports the provider. Tests verify catalog metadata and automatic registration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SpeechRuntime
  participant MiniMaxTextToSpeechProvider
  participant MiniMaxHTTPAPI
  participant MiniMaxWebSocket
  SpeechRuntime->>MiniMaxTextToSpeechProvider: register configured provider
  MiniMaxTextToSpeechProvider->>MiniMaxHTTPAPI: submit HTTP synthesis request
  MiniMaxHTTPAPI-->>MiniMaxTextToSpeechProvider: return audio or task response
  MiniMaxTextToSpeechProvider->>MiniMaxWebSocket: open streaming synthesis session
  MiniMaxWebSocket-->>MiniMaxTextToSpeechProvider: send task events and audio chunks
Loading

Suggested reviewers: jddunn, victor-evogor

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: adding the MiniMax TTS provider.
Description check ✅ Passed The description explains the change, motivation, implementation scope, and validation steps, but it omits the repository template headings and related issue field.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add MiniMax TTS provider with global/china routing, async, and WebSocket support

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Add MiniMax TTS provider supporting HTTP synthesis, async tasks, and WebSocket streaming.
• Wire MiniMax into runtime auto-registration, resolver availability checks, and provider catalog
 metadata.
• Add focused unit tests for endpoints, options mapping, and audio parsing error handling.
Diagram

graph TD
  env[("Env vars")]
  runtime["SpeechRuntime"]
  registry["SpeechRegistry"]
  provider["MiniMax TTS"]
  api{{"MiniMax API"}}
  catalog["providerCatalog"]
  resolver["SpeechProviderResolver"]

  env --> runtime --> registry --> provider --> api
  runtime --> resolver
  catalog --> resolver

  subgraph Legend
    direction LR
    _cfg[("Config/Env")] ~~~ _mod["Runtime/Module"] ~~~ _ext{{"External API"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Extract a shared "cloud TTS" transport helper (HTTP + WS + error parsing)
  • ➕ Reduces repeated request/response validation patterns across providers
  • ➕ Standardizes error handling, auth header injection, and fetch/websocket test fakes
  • ➖ Introduces a new abstraction that may be premature if MiniMax remains the only multi-protocol provider
  • ➖ Requires follow-up refactors of existing providers to realize the benefits
2. Limit initial scope to HTTP-only synthesis (defer async/WS)
  • ➕ Smaller surface area and simpler review/maintenance burden
  • ➕ Avoids committing to MiniMax WS protocol semantics early
  • ➖ Does not satisfy the stated need for async task APIs and WebSocket streaming
  • ➖ Would require another integration pass soon, increasing churn

Recommendation: Current approach is appropriate given the stated requirement to support HTTP, async task APIs, and WebSocket streaming from day one, and the PR includes targeted tests for each mode. Consider a follow-up refactor to extract shared transport/error-handling helpers if additional multi-protocol providers are added.

Files changed (8) +603 / -0

Enhancement (5) +371 / -0
SpeechProviderResolver.tsExpose MiniMax TTS requirements for resolver availability checks +1/-0

Expose MiniMax TTS requirements for resolver availability checks

• Adds minimax-tts to the resolver’s provider requirement list, gated by MINIMAX_API_KEY. This enables consistent availability reporting alongside other TTS providers.

src/io/speech/SpeechProviderResolver.ts

SpeechRuntime.tsAuto-register MiniMax TTS from environment configuration +13/-0

Auto-register MiniMax TTS from environment configuration

• Imports and conditionally instantiates MiniMaxTextToSpeechProvider when MINIMAX_API_KEY is present. Supports region routing (MINIMAX_REGION), model selection (MINIMAX_TTS_MODEL), and default voice (MINIMAX_TTS_VOICE).

src/io/speech/SpeechRuntime.ts

index.tsExport MiniMax TTS provider from speech module index +1/-0

Export MiniMax TTS provider from speech module index

• Re-exports MiniMaxTextToSpeechProvider to make the new provider available to external imports.

src/io/speech/index.ts

providerCatalog.tsAdd MiniMax TTS entry to the speech provider catalog +11/-0

Add MiniMax TTS entry to the speech provider catalog

• Registers minimax-tts with label, description, default model, env var requirements, and advertised features (streaming/websocket/async). Enables discoverability and UI/selection metadata.

src/io/speech/providerCatalog.ts

MiniMaxTextToSpeechProvider.tsImplement MiniMax TTS provider (HTTP sync, async tasks, WebSocket streaming) +345/-0

Implement MiniMax TTS provider (HTTP sync, async tasks, WebSocket streaming)

• Adds a new TextToSpeechProvider implementation with region-based host routing and model catalog, supporting HTTP synthesis (hex or URL audio), async task create/query endpoints, and the WebSocket task_start/continue/finish protocol. Includes request option mapping for voice/pronunciation/audio/language/subtitles/voice modifications and robust response/error parsing.

src/io/speech/providers/MiniMaxTextToSpeechProvider.ts

Tests (3) +232 / -0
MiniMaxTextToSpeechProvider.test.tsAdd MiniMax provider unit tests for HTTP, async, and WebSocket flows +219/-0

Add MiniMax provider unit tests for HTTP, async, and WebSocket flows

• Introduces coverage for global vs China endpoints, hex vs URL audio outputs, async task create/query calls, and the WebSocket start/continue/finish protocol. Also verifies invalid hex audio handling.

src/io/speech/tests/MiniMaxTextToSpeechProvider.test.ts

SpeechRuntime.test.tsVerify SpeechRuntime registers MiniMax when env var is present +2/-0

Verify SpeechRuntime registers MiniMax when env var is present

• Extends the runtime hydration test to include MINIMAX_API_KEY and asserts the minimax-tts provider is registered and retrievable.

src/io/speech/tests/SpeechRuntime.test.ts

providerCatalog.test.tsAssert provider catalog advertises MiniMax async + WebSocket capabilities +11/-0

Assert provider catalog advertises MiniMax async + WebSocket capabilities

• Adds a catalog test confirming minimax-tts default model, required env vars, streaming flag, and feature list includes async and websocket.

src/io/speech/tests/providerCatalog.test.ts

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The MINIMAX_SPEECH_MODELS constant is currently unused; consider either validating options.model/config.model against this list or removing it to avoid dead code.
  • The audioFormat resolution in audioFormat() uses options.outputFormat, which elsewhere represents HTTP/WebSocket output_format (hex vs url); consider separating transport output format from container/audio format to avoid semantic confusion and misconfiguration.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `MINIMAX_SPEECH_MODELS` constant is currently unused; consider either validating `options.model`/`config.model` against this list or removing it to avoid dead code.
- The `audioFormat` resolution in `audioFormat()` uses `options.outputFormat`, which elsewhere represents HTTP/WebSocket `output_format` (hex vs url); consider separating transport output format from container/audio format to avoid semantic confusion and misconfiguration.

## Individual Comments

### Comment 1
<location path="src/io/speech/providers/MiniMaxTextToSpeechProvider.ts" line_range="183-192" />
<code_context>
+          if (
</code_context>
<issue_to_address>
**suggestion:** Expose more detailed error information for WebSocket task failures.

For the `task_failed` event, the error is always reported as "MiniMax WebSocket synthesis failed." even though `base_resp` likely contains a `status_msg` (and possibly an error code) similar to the HTTP responses. Consider exposing these details so WebSocket errors are easier to debug and consistent with the HTTP error handling.

Suggested implementation:

```typescript
          if (
            message.base_resp?.status_code !== undefined &&
            message.base_resp.status_code !== 0
          ) {
            const { status_code, status_msg } = message.base_resp;

            const errorMessage = status_msg
              ? `MiniMax WebSocket synthesis failed: [${status_code}] ${status_msg}`
              : `MiniMax WebSocket synthesis failed with status code ${status_code}.`;

            const error = new Error(errorMessage);

            // Attach raw response details to the error object for easier debugging
            (error as any).status_code = status_code;
            (error as any).status_msg = status_msg;
            (error as any).base_resp = message.base_resp;

            fail(error);
            return;

```

To fully align WebSocket error handling with HTTP error handling:
1. If you have a dedicated MiniMax error type (e.g. `MiniMaxError` used for HTTP responses), consider constructing that instead of a plain `Error` and moving the status_code/status_msg/base_resp attachment into that class.
2. Ensure any upstream error handling that currently assumes a generic `Error` can also interpret the attached `status_code`, `status_msg`, or `base_resp` fields (or the dedicated error type) for richer logging or user-facing messages.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +183 to +192
if (
message.base_resp?.status_code &&
message.base_resp.status_code !== 0
) {
fail(
new Error(
message.base_resp.status_msg ??
"MiniMax WebSocket synthesis failed.",
),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Expose more detailed error information for WebSocket task failures.

For the task_failed event, the error is always reported as "MiniMax WebSocket synthesis failed." even though base_resp likely contains a status_msg (and possibly an error code) similar to the HTTP responses. Consider exposing these details so WebSocket errors are easier to debug and consistent with the HTTP error handling.

Suggested implementation:

          if (
            message.base_resp?.status_code !== undefined &&
            message.base_resp.status_code !== 0
          ) {
            const { status_code, status_msg } = message.base_resp;

            const errorMessage = status_msg
              ? `MiniMax WebSocket synthesis failed: [${status_code}] ${status_msg}`
              : `MiniMax WebSocket synthesis failed with status code ${status_code}.`;

            const error = new Error(errorMessage);

            // Attach raw response details to the error object for easier debugging
            (error as any).status_code = status_code;
            (error as any).status_msg = status_msg;
            (error as any).base_resp = message.base_resp;

            fail(error);
            return;

To fully align WebSocket error handling with HTTP error handling:

  1. If you have a dedicated MiniMax error type (e.g. MiniMaxError used for HTTP responses), consider constructing that instead of a plain Error and moving the status_code/status_msg/base_resp attachment into that class.
  2. Ensure any upstream error handling that currently assumes a generic Error can also interpret the attached status_code, status_msg, or base_resp fields (or the dedicated error type) for richer logging or user-facing messages.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 060833edad

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

}

async queryAsync(taskId: string): Promise<MiniMaxAsyncSpeechResponse> {
return this.request("/v1/query/t2a_async_query_v2", { task_id: taskId });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Query async task status with GET

For real MiniMax async status checks, this sends a JSON POST, but the official API documents GET /v1/query/t2a_async_query_v2 with task_id as a required query parameter (see https://platform.minimax.io/docs/api-reference/speech-t2a-async-query). As written, queryAsync() will not poll submitted tasks against the documented endpoint even though the unit test accepts the mocked POST.

Useful? React with 👍 / 👎.

Comment on lines +207 to +208
message.event === "task_continued" &&
message.data?.audio

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve documented audio chunks in WebSocket synthesis

When using the real WebSocket API, MiniMax's documented Task Continued receive payload contains data.audio/is_final but does not include an event field (https://platform.minimax.io/docs/api-reference/speech-t2a-websocket), so this branch ignores the audio chunks unless the server sends the extra field used by the test mock. In that scenario synthesizeWebSocket() resolves with an empty or incomplete buffer after task_finished.

Useful? React with 👍 / 👎.

Comment on lines +248 to +252
requested !== "mp3" &&
requested !== "wav" &&
requested !== "flac" &&
requested !== "pcm"
) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject PCM before sending MiniMax requests

This validation advertises and forwards pcm, but MiniMax's T2A docs list non-streaming output as mp3, wav, or flac and WebSocket streaming as mp3 only (https://platform.minimax.io/docs/api-reference/speech-t2a-http). A provider-agnostic caller that requests outputFormat: 'pcm' will get a remote parameter error from this provider instead of a correct local rejection or fallback format.

Useful? React with 👍 / 👎.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unvalidated audio URL fetch 🐞 Bug ⛨ Security
Description
MiniMaxTextToSpeechProvider.synthesize() will fetch and download whatever URL comes back in
data.audio when outputFormat === "url" without validating the URL or checking the download
response status, which can lead to unintended server-side requests and hard-to-debug failures. This
is triggered by provider-specific options (outputFormat: "url") and is new behavior in this PR.
Code

src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[R126-129]

+    const audioBuffer =
+      outputFormat === "url"
+        ? Buffer.from(await (await this.fetchImpl(audio)).arrayBuffer())
+        : decodeHexAudio(audio);
Evidence
The provider explicitly supports URL output and then performs a raw fetch(audio) to download
bytes; there is no URL validation, redirect control, or response.ok check on that second request.

src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[49-57]
src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[112-130]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When `providerSpecificOptions.outputFormat` is set to `"url"`, `MiniMaxTextToSpeechProvider.synthesize()` performs a second `fetch()` to download audio bytes from `response.data.audio` without validating the URL (scheme/host/private IPs/redirects) and without checking the download response status (`ok`). This can cause unintended outbound requests (SSRF-style behavior if the upstream response is untrusted/compromised) and yields confusing runtime errors when the download fails.

## Issue Context
- The secondary fetch target is controlled by the provider response (`data.audio`).
- `fetch()` follows redirects by default; even if you validate the initial URL, redirects can change the final destination unless constrained.

## Fix Focus Areas
- src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[106-131]
- src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[35-57]

## Suggested fix
- Parse `audio` via `new URL(audio)` and reject non-HTTPS URLs.
- Consider restricting to an allowlist (e.g., known MiniMax/CDN domains) and/or explicitly blocking localhost/private network destinations.
- Set `redirect: 'error'` (or `manual`) for the download fetch, or validate the final resolved URL before reading bytes.
- Check the download response (`if (!res.ok) throw ...`) before calling `arrayBuffer()` and include status/body snippet in the error for debuggability.
- (Optional) enforce a maximum download size to avoid unbounded memory use.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. WebSocket synthesize can hang 🐞 Bug ☼ Reliability
Description
MiniMaxTextToSpeechProvider.synthesizeWebSocket() has no handshake/overall timeout, so if the socket
stays open but the server never sends task_finished/task_failed, the returned Promise never
settles and callers can hang indefinitely. This can also leak the socket and event handlers until
process shutdown.
Code

src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[R166-169]

+    return new Promise<SpeechSynthesisResult>((resolve, reject) => {
+      const chunks: Buffer[] = [];
+      let settled = false;
+      const fail = (error: Error) => {
Evidence
The MiniMax WebSocket flow creates a Promise with message/error/close handlers but no timers, so it
cannot self-terminate on upstream stalls. A similar WebSocket provider in the repo uses explicit
timers and handles upgrade rejection details.

src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[153-231]
src/io/voice-pipeline/providers/DeepgramAuraStreamingTTS.ts[160-205]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`synthesizeWebSocket()` returns a Promise that only resolves/rejects on specific MiniMax events (`task_finished`, `task_failed`) or socket `error/close`. Without any timeout (connect, inactivity, or overall), the Promise can remain pending forever if the upstream stalls while keeping the connection open.

## Issue Context
Other WebSocket-based implementations in this repo add explicit timers to prevent “zombie” sessions (e.g., connect timeouts and handling of rejected upgrades).

## Fix Focus Areas
- src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[153-231]
- src/io/voice-pipeline/providers/DeepgramAuraStreamingTTS.ts[160-205]

## Suggested fix
- Add a connect/handshake timeout (e.g., fail if `connected_success` isn’t received within N ms).
- Add an overall or inactivity timeout that resets on each valid message; if it fires, close the socket and reject with a clear error.
- Ensure timers are cleared on settle.
- (Optional, but recommended) handle `unexpected-response` from `ws` to surface HTTP rejection details during upgrade (pattern used in DeepgramAuraStreamingTTS).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +126 to +129
const audioBuffer =
outputFormat === "url"
? Buffer.from(await (await this.fetchImpl(audio)).arrayBuffer())
: decodeHexAudio(audio);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Unvalidated audio url fetch 🐞 Bug ⛨ Security

MiniMaxTextToSpeechProvider.synthesize() will fetch and download whatever URL comes back in
data.audio when outputFormat === "url" without validating the URL or checking the download
response status, which can lead to unintended server-side requests and hard-to-debug failures. This
is triggered by provider-specific options (outputFormat: "url") and is new behavior in this PR.
Agent Prompt
## Issue description
When `providerSpecificOptions.outputFormat` is set to `"url"`, `MiniMaxTextToSpeechProvider.synthesize()` performs a second `fetch()` to download audio bytes from `response.data.audio` without validating the URL (scheme/host/private IPs/redirects) and without checking the download response status (`ok`). This can cause unintended outbound requests (SSRF-style behavior if the upstream response is untrusted/compromised) and yields confusing runtime errors when the download fails.

## Issue Context
- The secondary fetch target is controlled by the provider response (`data.audio`).
- `fetch()` follows redirects by default; even if you validate the initial URL, redirects can change the final destination unless constrained.

## Fix Focus Areas
- src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[106-131]
- src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[35-57]

## Suggested fix
- Parse `audio` via `new URL(audio)` and reject non-HTTPS URLs.
- Consider restricting to an allowlist (e.g., known MiniMax/CDN domains) and/or explicitly blocking localhost/private network destinations.
- Set `redirect: 'error'` (or `manual`) for the download fetch, or validate the final resolved URL before reading bytes.
- Check the download response (`if (!res.ok) throw ...`) before calling `arrayBuffer()` and include status/body snippet in the error for debuggability.
- (Optional) enforce a maximum download size to avoid unbounded memory use.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +166 to +169
return new Promise<SpeechSynthesisResult>((resolve, reject) => {
const chunks: Buffer[] = [];
let settled = false;
const fail = (error: Error) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Websocket synthesize can hang 🐞 Bug ☼ Reliability

MiniMaxTextToSpeechProvider.synthesizeWebSocket() has no handshake/overall timeout, so if the socket
stays open but the server never sends task_finished/task_failed, the returned Promise never
settles and callers can hang indefinitely. This can also leak the socket and event handlers until
process shutdown.
Agent Prompt
## Issue description
`synthesizeWebSocket()` returns a Promise that only resolves/rejects on specific MiniMax events (`task_finished`, `task_failed`) or socket `error/close`. Without any timeout (connect, inactivity, or overall), the Promise can remain pending forever if the upstream stalls while keeping the connection open.

## Issue Context
Other WebSocket-based implementations in this repo add explicit timers to prevent “zombie” sessions (e.g., connect timeouts and handling of rejected upgrades).

## Fix Focus Areas
- src/io/speech/providers/MiniMaxTextToSpeechProvider.ts[153-231]
- src/io/voice-pipeline/providers/DeepgramAuraStreamingTTS.ts[160-205]

## Suggested fix
- Add a connect/handshake timeout (e.g., fail if `connected_success` isn’t received within N ms).
- Add an overall or inactivity timeout that resets on each valid message; if it fires, close the socket and reject with a clear error.
- Ensure timers are cleared on settle.
- (Optional, but recommended) handle `unexpected-response` from `ws` to surface HTTP rejection details during upgrade (pattern used in DeepgramAuraStreamingTTS).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/io/speech/providers/MiniMaxTextToSpeechProvider.ts`:
- Around line 126-129: Update the URL branch in MiniMaxTextToSpeechProvider to
store the fetch response, validate its ok status before reading arrayBuffer(),
and handle unsuccessful downloads through the existing error path. Extend the
URL-output tests to cover both successful and non-successful response cases.
- Around line 149-150: Update MiniMaxTextToSpeechProvider.ts lines 149-150 in
queryAsync to call the request helper with GET, passing task_id as a query
parameter and no request body. Update the request implementation at lines
282-294 to support bodyless GET requests while preserving existing request
behavior, and update MiniMaxTextToSpeechProvider.test.ts lines 127-139 to assert
the GET method, query string, and absent body.

In `@src/io/speech/SpeechProviderResolver.ts`:
- Line 450: Update the resolver refresh logic around the MiniMax core entry in
SpeechProviderResolver so registering { id: 'minimax-tts', kind: 'tts' } cannot
overwrite an existing non-null provider with null; preserve the live
registration or supply the MiniMax provider factory before this entry is added.
Add a regression test that constructs SpeechRuntime, calls refresh(), and
verifies resolveTTS() still returns the registered MiniMax provider.

In `@src/io/speech/SpeechRuntime.ts`:
- Line 99: Update the region mapping in SpeechRuntime to normalize
MINIMAX_REGION and map both “cn” and “china” to the China endpoint, while
mapping only the supported global value to “global.” Reject unsupported or
missing values instead of silently defaulting to “global.”
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e7fd3bb4-8ea6-4d47-b0e6-cb71344f4f4b

📥 Commits

Reviewing files that changed from the base of the PR and between acd5c9b and 060833e.

📒 Files selected for processing (8)
  • src/io/speech/SpeechProviderResolver.ts
  • src/io/speech/SpeechRuntime.ts
  • src/io/speech/__tests__/MiniMaxTextToSpeechProvider.test.ts
  • src/io/speech/__tests__/SpeechRuntime.test.ts
  • src/io/speech/__tests__/providerCatalog.test.ts
  • src/io/speech/index.ts
  • src/io/speech/providerCatalog.ts
  • src/io/speech/providers/MiniMaxTextToSpeechProvider.ts

Comment on lines +126 to +129
const audioBuffer =
outputFormat === "url"
? Buffer.from(await (await this.fetchImpl(audio)).arrayBuffer())
: decodeHexAudio(audio);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- provider structure ---'
ast-grep outline src/io/speech/providers/MiniMaxTextToSpeechProvider.ts
printf '%s\n' '--- relevant provider code ---'
cat -n src/io/speech/providers/MiniMaxTextToSpeechProvider.ts | sed -n '1,190p'
printf '%s\n' '--- related tests ---'
rg -n -i -C 5 'MiniMax|outputFormat|arrayBuffer|download' . -g '*test*' -g '*spec*'

Repository: framerslab/agentos

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- MiniMax-related files ---'
fd -i 'minimax' .
printf '%s\n' '--- direct provider references ---'
rg -n -i -C 4 'MiniMaxTextToSpeechProvider|MiniMax TTS|t2a_v2' src tests --glob '!**/node_modules/**' --glob '!**/dist/**' | head -n 240

Repository: framerslab/agentos

Length of output: 15721


Validate the URL audio download response.

If the download response is not successful, check downloadResponse.ok before reading arrayBuffer(). Add successful and non-success response cases to the URL-output tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/io/speech/providers/MiniMaxTextToSpeechProvider.ts` around lines 126 -
129, Update the URL branch in MiniMaxTextToSpeechProvider to store the fetch
response, validate its ok status before reading arrayBuffer(), and handle
unsuccessful downloads through the existing error path. Extend the URL-output
tests to cover both successful and non-successful response cases.

Comment on lines +149 to +150
async queryAsync(taskId: string): Promise<MiniMaxAsyncSpeechResponse> {
return this.request("/v1/query/t2a_async_query_v2", { task_id: taskId });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- provider symbols ---'
rg -n -C 12 'queryAsync|private async request|t2a_async_query_v2' src/io/speech/providers/MiniMaxTextToSpeechProvider.ts
printf '%s\n' '--- related tests ---'
rg -n -C 18 'queryAsync|t2a_async_query_v2|fetchImpl.mock.calls' src/io/speech/__tests__/MiniMaxTextToSpeechProvider.test.ts
printf '%s\n' '--- MiniMax endpoint references ---'
rg -n -i -C 3 't2a_async_query_v2|async.?query|task_id' src/io/speech README.md package.json 2>/dev/null || true

Repository: framerslab/agentos

Length of output: 10502


🌐 Web query:

MiniMax platform API speech t2a async query t2a_async_query_v2 GET task_id

💡 Result:

The MiniMax t2a_async_query_v2 API endpoint is used to check the status of an asynchronous long-form text-to-speech (TTS) generation task [1][2]. Endpoint Details: Method: GET [1][2] Endpoint: /v1/query/t2a_async_query_v2 [1][2] Required Parameter: task_id (integer/int64) [1][3] Authentication: Bearer token (API Key) passed in the request header [2] Usage: After submitting a long-form TTS task via the Create Speech Generation Task API, you receive a task_id [2][4]. You must then poll the t2a_async_query_v2 endpoint using this task_id to monitor the task's progress [5][2]. Response States: The API returns the task status, which typically includes: - Processing: The task is currently being generated [1][3]. - Success: The task is finished. Upon success, the response includes a file_id, which you can use with the File Retrieve API to download the generated audio [1][3][4]. - Failed/Expired: The task encountered an error or the information is no longer available [3][6]. Important Notes: - The file_id (and the associated download URL) provided upon a successful status is valid for 9 hours (32,400 seconds) from the time it is generated [1][3][4]. - The MiniMax async TTS API supports processing up to 1 million characters per request [2][4].

Citations:


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
from pathlib import Path
import re

provider = Path("src/io/speech/providers/MiniMaxTextToSpeechProvider.ts").read_text()
calls = re.findall(r'\bthis\.request\((.*?)\);', provider, re.S)
print(f"request call count: {len(calls)}")
for i, call in enumerate(calls, 1):
    compact = " ".join(call.split())
    print(f"call {i}: {compact[:240]}")

helper = re.search(
    r'private async request<T>\(\s*path: string,\s*body: Record<string, unknown>,\s*\)\s*: Promise<T> \{\s*(.*?)\n\s*\}',
    provider,
    re.S,
)
if not helper:
    raise SystemExit("request helper not found")
body = helper.group(1)
print("helper fixes POST:", 'method: "POST"' in body)
print("helper always serializes body:", 'body: JSON.stringify(body)' in body)
PY

printf '%s\n' '--- direct documentation excerpt ---'
curl -L --max-time 15 -sS https://platform.minimax.io/docs/api-reference/speech-t2a-async-query \
  | tr '\n' ' ' \
  | grep -o -E '.{0,180}(GET|task_id|t2a_async_query_v2).{0,240}' \
  | head -n 8 || true

Repository: framerslab/agentos

Length of output: 3929


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
import html
import re
import urllib.request

url = "https://platform.minimax.io/docs/api-reference/speech-t2a-async-query"
raw = urllib.request.urlopen(url, timeout=15).read().decode("utf-8", "replace")
text = html.unescape(re.sub(r"<[^>]+>", " ", raw))
text = re.sub(r"\s+", " ", text)
for match in re.finditer(r"task[_ -]?id", text, re.I):
    start = max(0, match.start() - 300)
    end = min(len(text), match.end() + 500)
    print(text[start:end])
    print("---")
PY

printf '%s\n' '--- exact helper and all request calls ---'
sed -n '132,154p;280,300p' src/io/speech/providers/MiniMaxTextToSpeechProvider.ts
rg -n -C 4 'this\.request\(' src/io/speech/providers/MiniMaxTextToSpeechProvider.ts

Repository: framerslab/agentos

Length of output: 2442


🏁 Script executed:

#!/bin/bash
set +e
curl -k -L --max-time 15 -sS https://platform.minimax.io/docs/api-reference/speech-t2a-async-query > /tmp/minimax-doc.html
python3 - <<'PY'
import html
import re
from pathlib import Path

raw = Path("/tmp/minimax-doc.html").read_text(errors="replace")
text = html.unescape(re.sub(r"<[^>]+>", " ", raw))
text = re.sub(r"\s+", " ", text)
matches = list(re.finditer(r"task[_ -]?id", text, re.I))
print("documentation task_id occurrences:", len(matches))
for match in matches[:20]:
    print(text[max(0, match.start()-250):match.end()+450])
    print("---")
PY

printf '%s\n' '--- exact local implementation ---'
sed -n '132,154p;280,300p' src/io/speech/providers/MiniMaxTextToSpeechProvider.ts
printf '%s\n' '--- all request calls ---'
rg -n -C 4 'this\.request\(' src/io/speech/providers/MiniMaxTextToSpeechProvider.ts

Repository: framerslab/agentos

Length of output: 14831


Use GET for asynchronous task queries.

queryAsync currently sends POST with a JSON body. MiniMax requires GET with task_id as a query parameter. Update request to support bodyless GET requests and update the test to assert the method, query string, and absent body.

📍 Affects 2 files
  • src/io/speech/providers/MiniMaxTextToSpeechProvider.ts#L149-L150 (this comment)
  • src/io/speech/providers/MiniMaxTextToSpeechProvider.ts#L282-L294
  • src/io/speech/__tests__/MiniMaxTextToSpeechProvider.test.ts#L127-L139
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/io/speech/providers/MiniMaxTextToSpeechProvider.ts` around lines 149 -
150, Update MiniMaxTextToSpeechProvider.ts lines 149-150 in queryAsync to call
the request helper with GET, passing task_id as a query parameter and no request
body. Update the request implementation at lines 282-294 to support bodyless GET
requests while preserving existing request behavior, and update
MiniMaxTextToSpeechProvider.test.ts lines 127-139 to assert the GET method,
query string, and absent body.

{ id: 'openai-tts', kind: 'tts' as const, envVars: ['OPENAI_API_KEY'] },
{ id: 'elevenlabs', kind: 'tts' as const, envVars: ['ELEVENLABS_API_KEY'] },
{ id: 'deepgram-aura', kind: 'tts' as const, envVars: ['DEEPGRAM_API_KEY'] },
{ id: 'minimax-tts', kind: 'tts' as const, envVars: ['MINIMAX_API_KEY'] },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Preserve the live provider during resolver refresh.

After SpeechRuntime registers the real MiniMax provider, refresh() registers the same ID with provider: null. The existing registration is overwritten. resolveTTS() then returns null, and synthesis fails.

Preserve non-null registrations or add a MiniMax provider factory before adding this core entry. Add a refresh-after-construction regression test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/io/speech/SpeechProviderResolver.ts` at line 450, Update the resolver
refresh logic around the MiniMax core entry in SpeechProviderResolver so
registering { id: 'minimax-tts', kind: 'tts' } cannot overwrite an existing
non-null provider with null; preserve the live registration or supply the
MiniMax provider factory before this entry is added. Add a regression test that
constructs SpeechRuntime, calls refresh(), and verifies resolveTTS() still
returns the registered MiniMax provider.

if (miniMaxApiKey) {
const tts = new MiniMaxTextToSpeechProvider({
apiKey: miniMaxApiKey,
region: env['MINIMAX_REGION'] === 'china' ? 'china' : 'global',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,140p' src/io/speech/SpeechRuntime.ts
printf '\n-- region references --\n'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
  "MINIMAX_REGION|MiniMaxTextToSpeechProvider|region:.*china|region.*global" .
printf '\n-- documentation references --\n'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
  "MINIMAX_REGION|MiniMax|MiniMax.*region|minimax.*region" README.md docs .github 2>/dev/null || true

Repository: framerslab/agentos

Length of output: 7653


🏁 Script executed:

printf '%s\n' '-- provider implementation --'
sed -n '1,180p' src/io/speech/providers/MiniMaxTextToSpeechProvider.ts
printf '%s\n' '-- provider tests around region behavior --'
sed -n '1,120p' src/io/speech/__tests__/MiniMaxTextToSpeechProvider.test.ts
printf '%s\n' '-- all environment/config documentation files --'
git ls-files | rg -i '(^|/)(readme|docs|env|config)|minimax|speechruntime'

Repository: framerslab/agentos

Length of output: 14341


🌐 Web query:

MiniMax API documentation domestic region value cn global endpoint MiniMax TTS

💡 Result:

MiniMax API service regions are distinguished by the platform where your account and subscription were purchased, rather than a simple configuration parameter [1][2]. You must match your API Key to the correct regional base URL [1][2]. For MiniMax Text-to-Speech (TTS) and other API services, use the following endpoints: Global/International Region: Base URL: https://api.minimax.io [1][2] Platform: https://platform.minimax.io [1] Mainland China Region (cn): Base URL: https://api.minimaxi.com [1][2] Platform: https://platform.minimaxi.com [1] Key implementation details: 1. Authentication: A Global API Key will fail if used with the Mainland China host (and vice versa) [1][2]. Ensure your credentials correspond to the platform where they were generated [1]. 2. TTS Endpoints: Once you have selected the correct base URL for your region, TTS endpoints are accessed via standard paths such as /v1/t2a_v2 (for synchronous HTTP) or /ws/v1/t2a_v2 (for WebSocket) [3][4][5]. 3. Tooling: If using tools like the MiniMax CLI (mmx-cli), the region is often auto-detected from the API Key, but it can be manually configured if necessary using: mmx config set --key region --value global # For international services mmx config set --key region --value cn # For mainland China services [6][7]

Citations:


🏁 Script executed:

printf '%s\n' '-- SpeechRuntime tests --'
rg -n -A18 -B8 "MINIMAX|MiniMax|autoRegisterFromEnv|register.*Tts" \
  src/io/speech/__tests__/SpeechRuntime.test.ts

printf '%s\n' '-- deterministic mapping probe --'
python3 - <<'PY'
from pathlib import Path
import re

source = Path("src/io/speech/SpeechRuntime.ts").read_text()
match = re.search(
    r"region:\s*env\['MINIMAX_REGION'\]\s*===\s*'china'\s*\?\s*'china'\s*:\s*'global'",
    source,
)
if not match:
    raise SystemExit("mapping expression not found")

def current(value):
    return "china" if value == "china" else "global"

for value in ["china", "cn", "CN", " cn ", "global", "unsupported"]:
    print(f"{value!r} -> {current(value)!r}")
PY

Repository: framerslab/agentos

Length of output: 3882


Map MINIMAX_REGION=cn to the China endpoint.

MINIMAX_REGION='cn' currently selects global, so China credentials use https://api.minimax.io instead of https://api.minimaxi.com. Normalize the value and map both cn and china to china. Reject unsupported values instead of defaulting to global.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/io/speech/SpeechRuntime.ts` at line 99, Update the region mapping in
SpeechRuntime to normalize MINIMAX_REGION and map both “cn” and “china” to the
China endpoint, while mapping only the supported global value to “global.”
Reject unsupported or missing values instead of silently defaulting to “global.”

Source: MCP tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant