# Agent Reach Transcribe Command: Groq Whisper to OpenAI Whisper Fallback Logic Explained

> Discover Agent Reach transcribe command's fallback logic. Learn how it uses Groq Whisper first and seamlessly switches to OpenAI Whisper upon failure for reliable audio transcription.

- Repository: [Pnant/Agent-Reach](https://github.com/Panniantong/Agent-Reach)
- Tags: how-to-guide
- Published: 2026-07-21

---

**The `transcribe` command in Agent Reach attempts audio transcription through Groq's Whisper API first and silently falls back to OpenAI's Whisper API only if Groq fails, exhausting every configured provider in order before raising an aggregated `TranscribeError`.**

The `transcribe` command in the open-source **Agent Reach** project provides a robust audio-to-text pipeline that prefers Groq's free-tier Whisper endpoint and degrades gracefully to OpenAI's Whisper when needed. Implemented primarily in [`agent_reach/transcribe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/transcribe.py), the transcription logic handles provider selection, audio preprocessing, and automatic fallback orchestration without requiring manual user intervention. This article breaks down the exact fallback chain between Groq Whisper and OpenAI Whisper as implemented in the Panniantong/Agent-Reach repository.

## Provider Configuration and Fallback Order

### The Provider Definition Table

In [`agent_reach/transcribe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/transcribe.py), the **`PROVIDERS`** dictionary (lines 30-41) maps logical names to concrete API details. For **Groq**, it points to `https://api.groq.com/openai/v1/audio/transcriptions` and specifies the model `whisper-large-v3`. For **OpenAI**, it points to `https://api.openai.com/v1/audio/transcriptions` with model `whisper-1`. Each entry also declares the configuration key that holds the respective API token, ensuring secrets are injected at runtime rather than hard-coded.

### Provider Selection and `_provider_order`

The helper **`_provider_order`** (lines 98-104) resolves which providers to attempt. When the caller passes `provider="auto"`, the function returns `["groq", "openai"]`. If a specific name is supplied, the list contains only that provider. This deterministic order is what creates the Groq-first, OpenAI-second fallback behavior.

## The Fallback Orchestration Loop

The heart of the resilience logic is **`_transcribe_with_fallback`** in [`agent_reach/transcribe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/transcribe.py) (lines 49-62). For each audio chunk, it iterates over the resolved provider order and performs the following steps:

- Checks whether the provider's API key is present in the `Config` object via `_provider_key`; if the key is missing, the provider is skipped.
- Calls **`transcribe_chunk`** to send the audio to the provider's endpoint.
- If `transcribe_chunk` succeeds, the loop immediately returns the transcript.
- If any exception—including a **`TranscribeError`**—is raised, the loop captures the failure and continues to the next provider.

If the loop exhausts every provider without success, it raises an aggregated error containing all captured failures.

## End-to-End Transcription Request Flow

The main **`transcribe`** function orchestrates the pipeline from download to final text. The exact sequence implemented in [`agent_reach/transcribe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/transcribe.py) is:

1. **Validation.** Before touching the audio, `transcribe` verifies that at least one provider in the resolved order has a configured API key (lines 20-25).

2. **Source handling.** The input can be a remote URL, which is downloaded with `download_audio` (powered by yt-dlp), or a local file path.

3. **Compression.** `compress_audio` re-encodes the source to a Whisper-compatible mono, 16 kHz, 32 kbps format (lines 101-108).

4. **Chunking.** If the compressed file exceeds the approximate 24 MiB limit, `chunk_audio` splits it into segments of up to 10 minutes each (lines 126-133).

5. **Per-chunk fallback.** For every segment, `transcribe` calls `_transcribe_with_fallback`, which applies the provider loop described above (lines 49-62).

6. **HTTP request.** Inside the loop, `transcribe_chunk` builds a multipart POST request: the provider-specific `<endpoint>`, an `Authorization: Bearer <api_key>` header, the audio file, and form data including `model` and `response_format=text` (lines 81-89).

7. **Error detection.** On HTTP 200, the raw text response is returned. Any non-2xx status causes `transcribe_chunk` to raise a `TranscribeError` (lines 94-96), signaling the outer loop to fall back to the next provider.

8. **Aggregation.** Successful transcripts are stripped and joined with newlines inside `transcribe` (lines 42-48) before the final string is returned.

## Groq to OpenAI Fallback in Practice

When `transcribe` is invoked with `provider="auto"` (the CLI default), the following runtime behavior occurs:

- **First attempt:** The request is sent to Groq's endpoint (`https://api.groq.com/openai/v1/audio/transcriptions`) using model `whisper-large-v3`. If Groq returns HTTP 200, the transcript is accepted and OpenAI is never contacted.
- **Silent fallback:** If Groq fails—whether due to an HTTP 429 rate limit, a network timeout, a missing API key, or any other error—the loop catches the exception and proceeds to OpenAI's endpoint (`https://api.openai.com/v1/audio/transcriptions`) with model `whisper-1`.
- **Final failure:** If OpenAI also fails, the aggregated `TranscribeError` is raised to the caller.

This behavior is codified in the unit-test suite in **[`tests/test_transcribe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_transcribe.py)**. The `TestFallback` class (lines 99-132) validates three critical scenarios:

- `test_groq_succeeds_no_openai_call` proves that a successful Groq response prevents any OpenAI traffic.
- `test_groq_429_falls_back_to_openai` verifies that an HTTP 429 from Groq triggers the OpenAI path.
- `test_skip_unconfigured_provider` confirms that providers missing API keys are skipped entirely.

## Code Examples

### Direct Script Usage

The public `transcribe` function accepts a source path or URL and a `Config` object that loads keys from the user's configuration file.

```python
from agent_reach import transcribe
from agent_reach.config import Config

# Load keys previously stored with `agent-reach configure`.

cfg = Config()

text = transcribe(
    "https://youtu.be/example",  # can also be a local .m4a path

    provider="auto",             # default: Groq to OpenAI fallback

    config=cfg,
)
print(text)

```

This call orchestrates the full pipeline, relying on `_provider_order` to set the fallback chain and `_transcribe_with_fallback` to switch providers automatically.

### Manual Provider Loop

For advanced use, you can invoke the fallback helper directly on a pre-generated audio chunk.

```python
from agent_reach import transcribe as tr
from pathlib import Path
from agent_reach.config import Config

cfg = Config()
chunk = Path("tmp/chunk_001.m4a")

order = ["groq", "openai"]
try:
    result = tr._transcribe_with_fallback(chunk, order, cfg)
    print("Transcribed via:", order[0] if result else "none")
except tr.TranscribeError as exc:
    print("All providers failed:", exc)

```

This example demonstrates the inner `_transcribe_with_fallback` loop that iterates over `order`, invoking `transcribe_chunk` for each provider until one succeeds.

### CLI Entry Point

The packaged CLI exposes the same logic without writing code:

```bash
agent-reach transcribe "https://youtu.be/example" --provider auto

```

Arguments are forwarded directly to the `transcribe` function, inheriting the identical Groq-to-OpenAI fallback semantics.

## Key Files and Functions

Understanding the transcription fallback logic requires familiarity with these source files:

- **[`agent_reach/transcribe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/transcribe.py)** — Core implementation containing `PROVIDERS`, `_provider_order`, `_transcribe_with_fallback`, `transcribe_chunk`, and the main `transcribe` orchestrator.
- **[`tests/test_transcribe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_transcribe.py)** — Test suite (including `TestFallback`) that validates provider routing, fallback on HTTP 429, and skipping unconfigured providers.
- **[`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py)** — Stores `groq_api_key` and `openai_api_key` and exposes the configuration object consumed by the transcriber.
- **[`agent_reach/channels/youtube.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/youtube.py)** — Example channel implementation that delegates its `transcribe` method to the core `transcribe` function.

## Summary

- Agent Reach's `transcribe` command in [`agent_reach/transcribe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/transcribe.py) implements a hardcoded provider order that places **Groq first** and **OpenAI second** when `provider="auto"` is selected.
- The **`_transcribe_with_fallback`** helper silently catches any failure from Groq—including rate limits, network errors, or missing keys—and retries the same chunk against OpenAI.
- Each provider is defined in the **`PROVIDERS`** table with its own endpoint, model name, and configuration key, keeping secrets isolated from the orchestration logic.
- Audio is automatically compressed, chunked if it exceeds the 24 MiB limit, and processed independently, with per-chunk fallback ensuring maximum resilience.
- The behavior is codified in **[`tests/test_transcribe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_transcribe.py)**, which explicitly asserts that OpenAI is never called when Groq succeeds and that fallback occurs on Groq HTTP 429 errors.

## Frequently Asked Questions

### What triggers the fallback from Groq to OpenAI Whisper?

Any failure during the Groq request triggers the fallback. According to `_transcribe_with_fallback` in [`agent_reach/transcribe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/transcribe.py), if `transcribe_chunk` raises an exception—such as an HTTP 429 rate limit, a network timeout, or a `TranscribeError` from a non-2xx response—the loop immediately proceeds to the next configured provider, which is OpenAI by default.

### Can I force the transcribe command to use only one provider?

Yes. Passing `provider="groq"` or `provider="openai"` to the `transcribe` function bypasses the automatic ordering. The `_provider_order` helper returns a single-element list containing only the requested provider, so no fallback occurs if that provider fails.

### How does Agent Reach handle audio files that exceed the Whisper size limit?

Before transcription, `compress_audio` re-encodes the source to a Whisper-compatible format. If the result still exceeds the approximate 24 MiB limit, `chunk_audio` splits the file into segments of up to 10 minutes. The main `transcribe` function then processes each segment independently through `_transcribe_with_fallback`, so a large file never prevents transcription.

### What happens if both Groq and OpenAI providers fail?

If every provider in the resolved order fails, `_transcribe_with_fallback` exhausts its loop and raises an aggregated `TranscribeError`. The caller receives a single exception that encapsulates all underlying failures, indicating that no configured provider could complete the transcription.