Commit Graph

21 Commits

Author SHA1 Message Date
Teknium f030c03970 Port from cline/cline#13329: normalize host-root Gemini base URLs to /v1beta
A GEMINI_BASE_URL (or tts.gemini.base_url / providers.gemini base_url) set
to a host root — https://generativelanguage.googleapis.com or a proxy root
like http://localhost:4000/gemini — produced native requests to
{base}/models/{model}:generateContent with no API version segment, a
guaranteed 404. Google's own google-genai client treats the base URL as a
host root and appends the version itself, so users reasonably configure it
that way.

normalize_gemini_base_url() appends /v1beta unless the URL already ends
with a version segment (v1, v1beta, v1alpha, ...). Applied at every native
request builder: GeminiNativeClient, probe_gemini_tier, Gemini TTS
(tts_tool.py), and streaming TTS (tts_streaming.py). /openai-suffixed
URLs are untouched (OpenAI-compat path).

Port of cline/cline#13329, which fixed the same bug class after their
ai-sdk migration.
2026-09-15 03:54:01 -07:00
teknium1 dd1baee0e4 refactor(secrets): drop scope-aware env shims; runtime_provider and the voice/xai tools read the canonical getters
hermes_cli/runtime_provider._getenv was a 4-line copy of get_secret(name,
default) or default; it becomes agent.secret_scope.get_secret_str (returns
default only when the secret is genuinely unset, still raises
UnscopedSecretError — a child's unscoped read is a spawn-site bug). The
runtime_provider_backends/_custom siblings call it directly instead of via
the origin module.

tools/tts_tool, tools/transcription_tools and tools/xai_http each carried an
identical get_env_value re-export kept "so tests can patch" it; the seam is
hermes_cli.config.get_env_value, read lazily at call time. Callers
(tts_streaming, tts_tool_providers, transcription_cloud, voice_client_config,
tools_config) go there directly; resolve_provider_secret already defaults to
it so the env_getter kwarg is gone. Tests repointed at the canonical; the two
tests that only proved the shim forwarded are deleted.

Behavior change: none.
2026-09-13 05:07:50 -07:00
Teknium e83816a4d1 review-fix(comments): restore lost #NNNN rationale comments across non-test source (mechanical sweep, condensed, code unchanged)
For each issue anchor present in BASE 63279301bc non-test .py and absent on HEAD, the BASE comment/docstring block was re-attached at the HEAD location of the code it explained (matched by the distinctive code line / enclosing def). Sentences already covered by an existing HEAD comment were deduped; the issue number always survives. Insert-only: no code lines changed.
2026-09-03 09:44:26 -07:00
Teknium ff44eca74f refactor(tools): compact STT module docstrings and section banners, keep every invariant 2026-09-03 01:13:03 -07:00
Teknium 198fe72a35 refactor(tools): compact TTS command/streaming/normalizer docstrings, keep every invariant 2026-09-03 01:02:21 -07:00
Teknium 412ddb6772 refactor(tools): drop unreachable legacy TTS strip fallback and duplicated streamer sample rates; STT/TTS config wrappers as partials 2026-09-03 00:57:29 -07:00
Teknium d85b86e97a refactor(tools): AST-neutral closer/bracket hug pass over STT/TTS modules 2026-09-03 00:53:14 -07:00
Teknium 67a6769c69 refactor(tools): fold streaming TTS provider bodies — inline single-use locals, drop async shim, squeeze import blanks 2026-09-03 00:40:27 -07:00
Teknium d257aa9335 refactor(tools): fold trivial spans, async comprehension in xAI streamer 2026-09-02 23:13:58 -07:00
Teknium 7ed48064db refactor(tools): compact STT/TTS docstrings and comments, keep every invariant 2026-09-02 23:11:57 -07:00
Teknium d34703fa86 refactor(tools): AST-neutral layout compaction of STT/TTS modules 2026-09-02 22:45:22 -07:00
Teknium 4d37eddc2f refactor(tools): unify STT/TTS command-provider config helpers, REST STT flow, dispatch tables 2026-09-02 22:41:57 -07:00
Teknium 93131b17a6 refactor(tts): drop re-export shims with no external consumers; siblings import from defining modules 2026-09-02 16:44:13 -07:00
Teknium 2ef1e8e4e0 refactor(tools/voice): extract tts delivery + wake_word engines; dedupe transcription/voice_mode helpers; compact tts providers 2026-09-02 14:45:15 -07:00
Teknium 7800bb1a29 fix(tts): route streaming-provider secrets through resolve_provider_secret; bound per-sentence stream bodies at 16 MiB
Follow-up integration for the #47588 salvage, aligning the new streamers
with the post-campaign invariants:

- All streaming key lookups go through _resolve_key -> tts_tool.
  _resolve_provider_key -> resolve_provider_secret (config > env/.env >
  credential pool, profile-scoped) — never bare get_env_value. xAI
  resolves via resolve_xai_http_credentials so OAuth users stream too.
- _capped(): every provider's chunk iterator is bounded at 16 MiB per
  sentence, mirroring _read_tts_response_bytes' bounded-upstream-body
  invariant on the sync paths.
- Tests updated for the resolver contract + new coverage for credential
  routing and the cap.
2026-07-28 22:31:40 -07:00
Carlos Diosdado bc4dcb1b02 feat(tts): Gemini SSE + xAI WebSocket streaming providers, tts.streaming.provider knob, docs + E2E tests
Salvaged from PR #47588 and rebased onto the post-campaign streaming core:
the StreamingTTSProvider ABC/registry and the ElevenLabs/OpenAI streamers
already live on main (tools/tts_streaming.py), so this ports the pieces
main lacked:

- GeminiStreamer: streamGenerateContent?alt=sse -> base64 PCM chunks
  (24 kHz mono int16), reusing main's DEFAULT_GEMINI_TTS_* constants.
- XAIStreamer: WebSocket wss://api.x.ai/v1/tts -> binary PCM frames,
  async->sync bridged via the _collect_async test seam.
- tts.streaming.provider config knob: pin one streamer, or 'auto' to
  walk the priority list elevenlabs -> gemini -> openai -> xai. Unset
  keeps the never-swap-the-user's-voice default.
- docs/streaming-tts.md: architecture, capability matrix, how to add
  a provider.
- Unit tests for the knob, SSE parsing, and the WS bridge; key-gated
  E2E tests (skipped without credentials).

Refs: #47588
2026-07-28 22:31:40 -07:00
Moeadham e5fc806ccc fix(tts): support configurable ElevenLabs URLs
Salvaged from PR #66311 (@moeadham), rebased onto the current streaming
registry. tts.elevenlabs.base_url (+ optional wss_url, derived from
base_url when omitted) routes both the sync ElevenLabs path and the
chunked ElevenLabsStreamer through an ElevenLabsEnvironment, matching
the STT side's ELEVENLABS_STT_BASE_URL/config override pattern.
2026-07-28 11:54:26 -07:00
Teknium 3356703d1f fix(tts): streaming path also honors tts.openai.api_key from config
Follow-up to salvaged PR #70307 (@aml1973): OpenAIStreamer now checks
tts.openai.api_key (config.yaml) ahead of the env resolver in both
available() and stream(), completing config parity between the sync
and streaming OpenAI TTS paths.
2026-07-28 11:54:26 -07:00
aml1973 861c2fecd2 fix(tts): honor OpenAI config for streaming
Use the shared OpenAI audio key resolver and prefer tts.openai.base_url over the global environment fallback in the Desktop streaming path. Add focused regression coverage for credential and endpoint propagation.
2026-07-28 11:54:26 -07:00
Brooklyn Nicholson 393c100a92 feat(voice): speech-interrupted latch in the TTS streaming core
mark_speech_interrupted() / take_speech_interrupted(): a one-shot,
TTL'd (120s) latch plus SPEECH_INTERRUPTED_NOTE. Barge-in paths mark
it when they cut live speech; the next turn's submit path pops it and
prepends the note to the model-bound message — API-call local, never
persisted, so history and prompt caching are untouched.
2026-07-22 17:53:06 -05:00
Brooklyn Nicholson 592effcb2a feat(tts): provider-agnostic streaming core with a shared sentence chunker
StreamingTTSProvider ABC + registry + resolve_streaming_provider() —
ElevenLabs (pcm_24000) and OpenAI (response_format=pcm) stream chunked
PCM; every other provider keeps its configured voice and falls back to
per-sentence sync synthesis. SentenceChunker is the one incremental
cutter every surface shares: sentence-boundary cuts on the delta
stream, <think> blocks stripped even when split across deltas, short
fragments merged forward so they never stall as tiny clips.
2026-07-22 17:46:55 -05:00