Repository navigation
feat: add BreezeBlue TTS extension - #2379
TiagoAgora wants to merge 3 commits into
Conversation
|
[P1] Redact authentication headers before logging the configuration ai_agents/agents/ten_packages/extension/breezeblue_tts_python/config.py:120–124 Header-based authentication is explicitly supported by [P1] Attach the required guarder evidence before merging the new extension ai_agents/agents/ten_packages/extension/breezeblue_tts_python/manifest.json:1–4 This extension is absent from the merge base, so the new-extension guarder evidence gate applies. The PR body reports 52 passed / 19 skipped at the current HEAD, but no owner/workflow evidence comment supplies the required result screenshot or a downloadable PCM output. This is a merge blocker under [P2] Make cancellation interrupt requests awaiting response headers ai_agents/agents/ten_packages/extension/breezeblue_tts_python/breezeblue_tts.py:135–138 If a flush arrives while connecting or waiting for response headers, [P2] Put the flush test credentials inside params ai_agents/agents/ten_packages/extension/breezeblue_tts_python/tests/test_basic.py:335–338
[P2] Cover request ownership and abnormal completion in the local suite ai_agents/agents/ten_packages/extension/breezeblue_tts_python/tests/test_audio_end.py:211–213 The controlled-clock assertion covers success only; partial-error and no-audio tests omit |
|
Guarder evidence for breezeblue_tts_python:
|
|
Note on the guarder evidence above The guarder run was done at
|
|
[P1] Redact authentication headers before logging configuration ai_agents/agents/ten_packages/extension/breezeblue_tts_python/config.py:115–119 Header authentication is explicitly accepted by [P1] Refresh the guarder evidence for the current HEAD ai_agents/agents/ten_packages/extension/breezeblue_tts_python/manifest.json:1–4 The attached screenshot and downloadable PCM are accessible, and the archive contains a non-empty PCM file. However, they document [P2] Interrupt cancellation while waiting for response headers ai_agents/agents/ten_packages/extension/breezeblue_tts_python/breezeblue_tts.py:135–137 When a flush arrives during connection establishment or response-header wait, [P2] Initialize the flush test with valid nested credentials ai_agents/agents/ten_packages/extension/breezeblue_tts_python/tests/test_basic.py:335–338 These top-level credentials are ignored by the config model, leaving [P2] Cover abnormal completion and request ownership in adapter tests ai_agents/agents/ten_packages/extension/breezeblue_tts_python/tests/test_audio_end.py:211–213 The sole |
|
[P1] Redact credentials in header-based auth before logging the config [P1] Guarder evidence does not match the current PR HEAD [P2] Flush cannot interrupt a request still waiting for response headers [P2] No independent TTFB hook is registered for this extension |
|
[P1] Redact authentication headers before logging configuration ai_agents/agents/ten_packages/extension/breezeblue_tts_python/config.py:115–119
[P1] Refresh the required guarder evidence at the current HEAD ai_agents/agents/ten_packages/extension/breezeblue_tts_python/manifest.json:1–4 The owner's screenshot and downloadable archive are accessible, and the archive contains a non-empty PCM file, but both document [P2] Interrupt cancellation while waiting for response headers ai_agents/agents/ten_packages/extension/breezeblue_tts_python/breezeblue_tts.py:135–137 If a flush arrives during connection establishment or response-header wait, [P2] Initialize the flush test with valid nested credentials ai_agents/agents/ten_packages/extension/breezeblue_tts_python/tests/test_basic.py:335–338 These top-level credentials are ignored by the config model, leaving [P2] Complete the mandatory lifecycle and termination assertions ai_agents/agents/ten_packages/extension/breezeblue_tts_python/tests/test_audio_end.py:211–213 Only success asserts [P2] Register an independent TTFB observer for the HTTP transport ai_agents/agents/ten_packages/extension/breezeblue_tts_python/extension.py:17 The adapter uses HTTP streaming, but the guarder's |
Add breezeblue_tts_python (AsyncTTS2HttpExtension) for BreezeBlue's HTTP
streaming API (POST /v1/text-to-speech/{voice_id}/stream).
- stream raw PCM16 24 kHz mono straight through, holding back a trailing odd
byte so a sample is never split across chunks
- send only whitelisted request fields: the API rejects unknown ones with a
422, e.g. the playground's generic sample_rate
- split text over the 1000 char per-request cap at sentence boundaries, since
the base class does not chunk
- retry 502/503/504 before any audio; map 401/403 and malformed-key 422 to an
invalid-key error; reject non-audio 200 responses
- cancel() closes the in-flight response and ends the stream with a flush
- extension-local tests for config, client and adapter events (audio-end
accounting, errors, cancellation, metrics, state machine)
- document BREEZE_API_KEY and BREEZE_TTS_VOICE_ID, add the extension to the
guarder fixed-sample-rate list, and record the gotchas in docs/ai
pylint reads the pydantic Field attributes (params, headers) as FieldInfo and reports E1101, which fails the lint step of the agents CI. Replace the inline pragmas, which black moves off the flagged line, with one scoped disable per config method. No behaviour change.
1e698e3 to
06985c2
Compare
|
[P1] Redact authentication headers before logging configuration
[P1] Refresh the required guarder evidence at the current HEAD This is a new extension, so the current-HEAD guarder evidence gate is a merge blocker. The owner-provided run and attachments are for [P2] Interrupt cancellation while waiting for response headers During connect or response-header wait, [P2] Initialize the flush test with valid nested credentials These credentials are top-level fields, but the config reads them from [P2] Cover abnormal completion and request ownership in adapter tests The controlled-clock [P2] Register an independent HTTP TTFB observer The guarder has no BreezeBlue entry in its TTFB hook registry and its installer currently wraps WebSocket transports only, so this HTTP extension has no independent first-text/first-audio reference. The local metric test checks only a lower bound and cannot detect an incorrectly placed timer. Add and register an HTTP observer at the request and first non-empty PCM boundaries, with request-isolation tests and a reference-enabled live run. Subtitle alignment is not applicable because this adapter does not supply timestamps. |
…every stage - redact xi-api-key / Authorization headers (case-insensitive) in to_str(), so header-only authentication is not logged in clear at init - cancel() now interrupts a request that is still connecting or waiting for response headers, and wakes a retry back-off immediately; a flush no longer blocks the next utterance until the vendor answers or the 60 s timeout hits, and a flushed request is never reopened by a retry or a split-text piece - fix test_flush_logic, which passed credentials at the top level instead of params: init failed fatally and the test passed without exercising flush - add adapter-level lifecycle tests: exact audio-end duration and interval with a controlled clock on success, flush, partial-error, no-audio and empty-body paths; dump contents; request ownership for appended and interleaved ids; recovery after cancellation before audio starts
|
[P1] Refresh the required guarder evidence at the current HEAD This is a new extension, so a full passing guarder run at the current HEAD is a merge requirement. The owner-provided screenshot and PCM archive document [P2] Reject successful responses that are not raw PCM The content-type check rejects only [P2] Assert zero event interval when no audio starts The new no-audio tests explicitly expect request latency as [P2] Register an independent HTTP TTFB observer The guarder has no BreezeBlue TTFB hook registration, and its existing hooks observe WebSocket transports rather than this HTTP stream. Consequently the extension has no independent first-text/first-audio reference: the local metric test and guarder upper bound cannot verify the production timer boundary. Add and register an HTTP observer for request send and first non-empty PCM arrival, cover request isolation, and include a reference-enabled live run. Subtitle alignment is not applicable because this adapter does not supply timestamps. |

Summary
Adds
breezeblue_tts_python, a TTS extension for BreezeBlue built onAsyncTTS2HttpExtension. It uses the HTTP streaming endpoint (POST /v1/text-to-speech/{voice_id}/stream).sample_rate).max_text_lengthis configurable for accounts with a higher cap.cancel()closes the in-flight response and the stream ends with a flush.voice_id,model_id,language_code,instructions,speed,volume,guidance_scaleanduse_speaker_boost.Other changes:
.env.example:BREEZE_API_KEYandBREEZE_TTS_VOICE_ID.tests/bin/start: add the extension to the fixed-sample-rate list.docs/ai: gotchas for strict request schemas, unchunked text and PCM16 passthrough.Not in this PR
Test plan
Extension-local tests: 64 pass (config, client, and adapter-level events: audio-end accounting, errors, cancellation, metrics, state machine). A few deliberate client bugs were confirmed to fail the matching tests.
Real API: voice listing, English, Chinese, the multilingual model,
speed/volume, long text (split into two requests, onetts_audio_end).Full TTS guarder, default config, against the live API at commit
cc6fc4d4e:The skips are capability-based (connection status is WebSocket-only, no subtitle alignment, and checks for other vendors' hooks).
A guarder screenshot and the downloadable PCM output (24000 Hz, 16-bit signed little-endian, mono) will be attached in a comment on this PR.