Telegram distinguishes three kinds of audio payloads:
- message.voice → Opus/OGG voice messages → STT pipeline ✓
- message.audio → audio file attachments → bypasses STT ← was broken
- message.document (audio mime) → generic file route
**Root cause** — the inbound message routing block in gateway/run.py
matched both MessageType.VOICE *and* MessageType.AUDIO into audio_paths,
which were then fed unconditionally to _enrich_message_with_transcription.
Audio file attachments (.mp3, .m4a, etc.) were therefore auto-transcribed
instead of being treated as files, making the transcribe skill unusable
from Telegram because the path it needed was never surfaced.
**Fix**
- Introduce a new audio_file_paths list populated exclusively by
MessageType.AUDIO events.
- Narrow the audio_paths selector to MessageType.VOICE (and bare
audio/ mime-type events that are not explicitly AUDIO or DOCUMENT).
- After the STT block, inject a document-style context note for each
audio_file_path, giving the agent the file path and asking what to do
with it (consistent with how plain documents are handled).
**Tests** — 5 new tests in test_telegram_audio_vs_voice.py:
- voice message still transcribed (regression guard)
- audio attachment skips STT (core fix)
- audio attachment context note format
- STT disabled still produces file note (not STT-disabled notice)
- MessageType.AUDIO != MessageType.VOICE sanity check
Fixes#24870
Salvages #23302 by @Bartok9. Four independent one-area fixes:
1. kanban boards delete alias now hard-deletes (not archives) — the
alias didn't carry --delete, so getattr(args, 'delete', False)
returned False. Detect boards_action=='delete' explicitly.
2. Gateway auto-title failures no longer leak as user-visible
warnings — debug-log only since they're not actionable.
3. Background process completion notification snaps truncation to
the next newline boundary, prepends a marker when content is
dropped.
4. _cprint() schedules the run_in_terminal coroutine via
asyncio.ensure_future so output isn't silently dropped from
background threads (fixes#23185 Bug A). Skips the
double-print fallback that would fire for mock paths.
Wrap existing box-drawing diagrams with ascii-guard markers so docs-site checks pass when website docs are touched.
Co-authored-by: Cursor <cursoragent@cursor.com>
display: null or display: <non-dict> in config.yaml crashed skin init
with AttributeError. Now falls back to default skin gracefully.
Cherry-picked from #10867 by @Bartok9. Consolidates #10876 by @cola-runner.
Co-authored-by: cola-runner <cola-runner@users.noreply.github.com>
Bump connect retry attempts from 3 to 8 and cap exponential backoff at
15 seconds. Old budget: 3 attempts, 1+2+4=7s total — insufficient for
cold boot on slow networks or embedded devices. New budget: 8 attempts,
1+2+4+8+15+15+15=~60s total.
Inspired by PR #5770 by @Bartok9 (re-implemented against current main
since original was 913 commits stale with conflicts).
The openai SDK's SyncAPIClient.is_closed is a method, not a property.
getattr(client, 'is_closed', False) returned the bound method object,
which is always truthy — causing _is_openai_client_closed() to report
all clients as closed and triggering unnecessary client recreation
(~100-200ms TCP+TLS overhead per API call).
Fix: check if is_closed is callable and call it, otherwise treat as bool.
Fixes#4377
Co-authored-by: Bartok9 <Bartok9@users.noreply.github.com>
MiniMax APIs (global and China) don't support /v1/models, causing
hermes doctor to always show HTTP 404 even with valid API keys.
Skip the HTTP check for these providers and show '(key configured)'
when the API key is present.
Cherry-picked from PR #822 by Bartok9, rebased onto current main.
Fixes#811
Co-authored-by: Bartok9 <259807879+Bartok9@users.noreply.github.com>
Fixes#160
The issue was that MEDIA tags were being extracted from ALL messages
in the conversation history, not just messages from the current turn.
This caused TTS voice messages generated in earlier turns to be
re-attached to every subsequent reply.
The fix:
- Track history_len before calling run_conversation
- Only scan messages AFTER history_len for MEDIA tags
- Add comprehensive tests to prevent regression
This ensures each voice message is sent exactly once, when it's
generated, not on every subsequent message in the session.