Skip to content

fix(voice): mirror Web UI STT provider into the Hermes Agent profile config - #2258

Closed
twuijri wants to merge 1 commit into
EKKOLearnAI:mainfrom
twuijri:stt-config-sync
Closed

fix(voice): mirror Web UI STT provider into the Hermes Agent profile config#2258
twuijri wants to merge 1 commit into
EKKOLearnAI:mainfrom
twuijri:stt-config-sync

Conversation

@twuijri

@twuijri twuijri commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Fixes #2257.

Voice was the only settings group that stopped at the Studio DB: it served POST /api/hermes/stt/transcribe (browser only), while Hermes Agent gateway platforms read a separate stt: block from the profile config.yaml plus credentials from the profile .env. A provider configured in Settings → Voice therefore never reached Telegram, Discord or any other gateway platform, and Hermes kept resolving stt.provider to local.

What this does

New service packages/server/src/services/hermes/voice-config-sync.ts, called from saveSettings in controllers/hermes/stt.ts:

  • .env ← the credential under the env var Hermes reads (GROQ_API_KEY), via the existing saveEnvValueForProfile
  • config.yamlstt.enabled: true and stt.provider, via the existing updateConfigYamlForProfile

Key names follow the Hermes Agent reference (website/docs/user-guide/features/voice-mode.md).

This is the same pattern Studio already uses elsewhere — providers.ts:302-369 (model providers → custom_providers + API key in .env), config.ts:438-456 (proxy → .env), config.ts:636-691 (platform credentials → .env).

Deliberate constraints

  • Groq only for the first pass. resolveHermesSttTarget matches on host, so a generic OpenAI-compatible endpoint is never silently relabelled as a Hermes provider. Adding providers later is one table entry each.
  • Look-alike hosts rejectedapi.groq.com.evil.test does not match (covered by a test).
  • Stored-secret placeholder ignored[stored] never overwrites a real key in .env.
  • User keys preserved — existing stt.local.model, stt.groq.language, etc. are kept; only enabled and provider are set.
  • Never fails the request — a write error is logged and the settings response is unchanged.
  • Browser path untouched — Web UI transcription keeps reading the Web UI settings store.
  • No gateway restart — left out on purpose; happy to add restartGatewayForProfile if you prefer the change to apply without a manual restart.

Verification

  • tests/server/voice-config-sync.test.ts — 10 new tests (host mapping, look-alike rejection, malformed input, placeholder secret, stt: block creation/merge/replacement, unrelated config untouched): all pass
  • tsc --noEmit -p packages/server/tsconfig.json clean
  • npm run harness:check passes
  • tests/server suite: 1877 passed, 11 failures in studio-mcp-autoinject that are pre-existing on main and unrelated to this change

Open question

AGENTS.md says "Keep Hermes Agent state separate from Web UI state." I read that as forbidding Web UI state stored inside Hermes, not writing Hermes' own configuration — which Studio already does in the three places above. If you read it more strictly, I'll move the mirror behind an explicit opt-in (a toggle, or an "Apply to Hermes Agent" action) instead of running on save; say the word and I'll push that instead.

…config

Voice settings saved in the Web UI only served /api/hermes/stt/transcribe,
which is the browser path. Hermes Agent gateway platforms read a separate
stt: block from the profile config.yaml plus credentials from the profile
.env, so a provider configured in Settings -> Voice never reached Telegram,
Discord or any other gateway platform and Hermes kept resolving
stt.provider to local.

Saving an STT provider whose base URL maps unambiguously to a Hermes
provider now mirrors the credential into the profile .env and writes
stt.enabled / stt.provider into the profile config.yaml, following the
pattern already used for model providers (providers.ts), proxy settings and
platform credentials (config.ts).

Scoped to Groq for now so a generic OpenAI-compatible endpoint is never
silently relabelled. User-written keys under stt: are preserved, and a
write failure is logged instead of failing the settings request.

Fixes EKKOLearnAI#2257
@EKKOLearnAI

Copy link
Copy Markdown
Owner

#2260

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.

Web UI voice settings are not mirrored to the Hermes Agent profile, so gateway platforms never use the configured STT provider

2 participants