Commit graph

244 commits

Author SHA1 Message Date
Teknium
7de33cc57e
Merge pull request #64536 from victor-kyriazakos/feat/gateway-health-diagnostics
feat(monitoring): gateway health & diagnostics OTLP export
2026-07-29 08:58:33 -07:00
Teknium
707f316687 chore: map contributor email shag@agentmail.to -> sg-shag 2026-07-29 08:42:16 -07:00
victor-kyriazakos
1773752c8c Merge remote-tracking branch 'origin/main' into feat/gateway-health-diagnostics-monitoring
# Conflicts:
#	uv.lock
2026-07-29 15:37:14 +00:00
Teknium
b0734b0aa5 chore: contributor mapping for beardedeagle (#71083 salvage) 2026-07-29 08:24:00 -07:00
kshitijk4poor
97fa2603d9 chore: map ezell.matt@gmail.com -> mattezell for contributor attribution 2026-07-29 19:43:43 +05:00
kshitijk4poor
9d6b9f44f2 chore: map megusta52@proton.me -> DonutsDelivery for attribution audit 2026-07-29 17:11:30 +05:30
Teknium
c892ca25e0 fix(doctor): resolve managed/legacy agent-browser dirs PATHEXT-aware
Follow-up on the #53205 salvage: replace bare is_file() probes of the
managed (~/.hermes/node[/bin]) and legacy (node_modules/.bin) locations
with shutil.which(..., path=dir) so Windows resolves the executable
.cmd shim instead of the extensionless POSIX script — the same miss
class fixed for _has_agent_browser() in #73932. Also covers the
Windows managed layout where the binary sits in node/ directly.
2026-07-29 00:16:21 -07:00
Teknium
4de9e53f10 chore: contributor email mappings for #47588/#73358 salvage 2026-07-28 22:31:40 -07:00
kshitijk4poor
02eff547a8 chore: add AUTHOR_MAP entry for kingrubic (nnqbao@gmail.com) 2026-07-29 10:56:19 +05:30
Teknium
dcace573da fix(photon): rework zombie-stream watchdog for spectrum-ts 8 with strict probe semantics
Maintainer rework of #45580 (issue #54036) on top of the contributor's
cherry-pick, which targeted spectrum-ts 3.1.0 while main pins 8.0.0:

Sidecar (primary detection, new):
- stream-staleness.mjs: pure decision rules, executable under node.
  * classifyProbeRejection: only a not-found-shaped rejection of the
    synthetic-id read counts as a completed round-trip (ALIVE); any other
    rejection is INCONCLUSIVE — never alive. The original /probe treated
    ANY rejection as alive, which was too loose.
  * shouldProbe: probe only after 10+ min of stream silence (configurable
    via PHOTON_STREAM_SILENCE_PROBE_MS; <=0 disables) with a cooldown.
  * isZombieSuspect: zombie only on silence past threshold AND a
    probe-proven live channel. Silence alone NEVER degrades (shared lines
    can be quiet for hours); inconclusive probes NEVER degrade (network
    may be down — the iterator will throw and the re-subscribe loop
    recovers on its own).
- index.mjs: track last inbound-iterator yield (noteInboundYield), run a
  30s watchdog tick, and on a confirmed zombie feed markStreamDegraded ->
  the existing exit-75 restart path. /healthz gains a stream.staleness
  block (silentForMs, threshold, lastProbeOutcome, zombieSuspected).
  /probe reworked to strict semantics: 200 only on a proven round-trip,
  503 with outcome hung|inconclusive otherwise.

Adapter (second layer, reworked):
- _probe_once returns tri-state alive|hung|inconclusive; only a hung
  sidecar HTTP call counts toward the respawn counter — inconclusive
  resets nothing and triggers nothing.
- default probe_interval_seconds 60 -> 600 (conservative; avoid restart
  storms on quiet lines).
- _monitor_sidecar_health surfaces zombieSuspected from /healthz as a
  warning; the fatal UPSTREAM_STREAM_DEGRADED path is unchanged and fires
  when the sidecar escalates.

Tests: test_zombie_stream_watchdog.py executes the real node decision
module and drives the adapter against mocked /healthz responses;
test_presence_watchdog.py updated for the tri-state probe.

Also adds contributor mappings for nickkarhan (#53283) and vaibhavjnf
(#45580).
2026-07-28 22:22:42 -07:00
huntsyea
cf550c0863 feat(photon): support rich link previews 2026-07-28 22:10:57 -07:00
vaibhavjnf
fe95194c59 feat(photon): render multiple-choice clarify as a native iMessage poll
The `clarify` tool's multiple-choice prompts flattened to a numbered text
list on Photon/iMessage, even though iMessage has a native poll bubble and
spectrum-ts already exposes it via the `poll()` content builder. Two gaps
caused the flattening:

  * Outbound: the sidecar only had `/send` (text); there was no way to send
    a poll, so the base adapter's numbered-text fallback was used.
  * Inbound: `normalizeContent()` handled only text/attachment/voice, so a
    poll vote (`poll_option`) was dropped on the floor ("[Photon content
    type not handled: poll_option]") and never resolved the clarify.

Fix, end to end:

  * Sidecar: import `poll` from spectrum-ts; add a `/send-poll` route
    (`space.send(poll(title, ...options))`); serialize inbound `poll_option`
    (the vote: chosen title + selected bool) and `poll` content in
    `normalizeContent()`.
  * Adapter: override `send_clarify` — for choices, send a native poll via
    `_sidecar_send_poll` and call `mark_awaiting_text` so the gateway's
    existing pending-clarify text-intercept resolves the answer; open-ended
    clarifies keep the plain-text path. Inbound `poll_option` selections are
    dispatched as a plain-text MessageEvent carrying the chosen option
    (deselections / empty votes are dropped). If the poll send fails (an
    older sidecar without `/send-poll`, or a send error) it falls back to the
    numbered-text clarify, so nothing regresses on a half-upgraded restart.

No new model tool, no new env var, no core change — the capability lives at
the platform edge. The poll vote reuses the existing clarify text-intercept
resolution path, so no new gateway resolution mechanism is introduced.

Tests: tests/plugins/platforms/photon/test_poll_clarify.py — inbound vote ->
choice text, deselection/empty-vote dropped, send_clarify sends a poll +
enables text-capture, open-ended stays text, and poll-failure falls back to
the text list. Full photon suite green.

Contributed by Vaibhav Sharma (X: @vabbyshabby).
2026-07-28 22:10:57 -07:00
Hermes Agent
077c583c75 feat(photon): add native poll sending 2026-07-28 22:10:57 -07:00
Teknium
ed02df6ddc chore: add contributor mappings for photon lifecycle salvage train 2026-07-28 21:45:52 -07:00
Teknium
07e931fcb4 feat(buzz): WebSocket inbound transport — NIP-42 auth, live DM discovery, poll fallback
Consolidates the native-transport half of PR #73636 by @ScaleLeanChris
onto the merged adapter: persistent NIP-42-authenticated Nostr WebSocket
subscription as the default inbound path (transport=auto|websocket|poll),
kind-44100 membership events for live DM discovery, since-timestamp
resume on reconnect with bounded exponential backoff, and automatic
fallback to CLI polling when the WS can't be established. Events route
through the same _handle_event() pipeline as the poll loop, so de-dupe,
mention gating, p-tag DM latching, and allow-lists behave identically on
both transports. Outbound stays on the CLI (one-shot sends never race a
WS auth handshake — his design).

E2E verified against a real in-process websockets relay: NIP-42
challenge -> signed kind-22242 AUTH (event id re-derived server-side) ->
REQ subscription -> EVENT dispatch -> clean disconnect.

Co-authored-by: ScaleLeanChris <chris@scalelean.com>
2026-07-28 21:45:34 -07:00
Teknium
4f65f56279 chore: contributor mappings for DI404N and JoaoMarcos44 2026-07-28 18:20:06 -07:00
Teknium
f65cde9fd5 chore: map contributor email for Bounty13 2026-07-28 18:19:12 -07:00
kelsia14
fd4f756492 fix(photon): ignore iMessage media placeholders
Cherry-picked from PR #54514; dropped frozen AUTHOR_MAP hunk in scripts/release.py, contributor mapping added instead.
2026-07-28 18:17:52 -07:00
Teknium
7e7f7d3059
Merge pull request #70509 from NousResearch/hermes/hermes-29661bf6
feat(voice): on-device wake words with open-vocabulary phrases and multi-profile voice routing
2026-07-28 17:58:33 -07:00
Teknium
1b9377b1fd fix(buzz): scoped identity lock, negative name caching, sidebar registration
Follow-up on the salvaged #71610 commits:
- acquire/release a scoped lock on relay_url+pubkey in connect/disconnect
  (IRC pattern) so two profiles can't drive one Buzz identity — duplicate
  replies and split de-dupe state; +2 tests
- negative-cache _resolve_user_name failures so a profile-less pubkey
  doesn't re-hit 'users get' every poll sweep (flagged by @jethac on the PR)
- register user-guide/messaging/buzz in website/sidebars.ts (page was
  unreachable — the #63359 trap)
2026-07-28 17:57:48 -07:00
Teknium
82ed4dee36 docs(acp): verify Buzz relay-bridge docs against buzz source, cross-link modes, add zh-Hans
Follow-up on the salvaged #69915 commits:
- verified env vars against block/buzz crates/buzz-acp/src/config.rs
  (BUZZ_RELAY_URL, BUZZ_PRIVATE_KEY, BUZZ_API_TOKEN, BUZZ_ACP_AGENT_COMMAND/
  ARGS, BUZZ_ACP_RELAY_OBSERVER, BUZZ_ACP_AGENT_OWNER) and kind 24200
  observer frames against docs/nips/NIP-AO.md
- dropped unverifiable claims: docs/hermes-agent-acp.md link (404 upstream),
  relay-directory profile publication / External-agents card walkthrough,
  'bot role' membership phrasing
- replaced key provisioning with the actual buzz-admin generate-key /
  add-member flow from the buzz-acp README
- retitled the section 'Buzz channels (relay bridge)' and cross-linked it
  with the Buzz Desktop managed-runtime section both ways; permission
  paragraph now points at the owner-only warning instead of duplicating it
- zh-Hans translation of the new section + retitle to ACP 宿主集成
2026-07-28 17:57:37 -07:00
Teknium
42091a83b9 chore: map william.reed@acquia.com -> wreed4 for salvaged #68090 2026-07-28 14:07:21 -07:00
Teknium
c911a5f10f chore: contributor email mappings for voice-platform-inbound salvage 2026-07-28 14:06:56 -07:00
Teknium
2cf656f23d chore: map contributor email for AtakanGs
Unblocks check-attribution on the 15 open AtakanGs PRs (atakan1705@hotmail.com).
2026-07-28 13:56:39 -07:00
LunarNexus
8c12fa7cf0 fix(lmstudio): respect applied runtime context 2026-07-29 02:19:13 +05:30
kshitijk4poor
09f7e6cb5b chore: map Enough1122@users.noreply.github.com -> Enough1122
Bare-login noreply emails (no NNN+ numeric prefix) do not match the
check-attribution auto-resolve rule, so they need an explicit
contributors/emails/ file. Unblocks PR #73592.
2026-07-29 00:54:47 +05:00
Teknium
0cf58de85e
Merge remote-tracking branch 'origin/main' into wake-toggle-config
# Conflicts:
#	tests/test_tui_gateway_server.py
#	tui_gateway/server.py
2026-07-28 12:37:35 -07:00
Teknium
097f0d0167 chore: contributor email mappings for voice-desktop salvage 2026-07-28 11:58:03 -07:00
Teknium
ae697db19c chore: map salvage contributors (voice CLI/TUI UX batch) 2026-07-28 11:57:37 -07:00
Teknium
ea80b557ae fix: route busy-steer voice through the shared out-of-band STT choke point
Follow-up for salvaged #65023/#53020: _prepare_busy_steer_text now calls
_transcribe_and_echo_pending_voice (the same helper the interrupt monitor
and pending-drain paths use) instead of a private transcription+echo copy,
so out-of-band voice pays one STT call per platform message and the echo
respects the count-based ledger from #67281. can_steer now accepts events
whose attachments are all STT-eligible voice media, completing the steer
half of #58780. Adds extract_media gating tests for #44826 and the
contributor mapping for chefboyrdave21.
2026-07-28 11:57:11 -07:00
Teknium
b8c38a451a chore: add contributor email mappings for voice salvage PR 2026-07-28 11:56:37 -07:00
Teknium
f440a44753 chore: mappings for bare-noreply contributor emails 2026-07-28 11:55:48 -07:00
Teknium
4d9dcf152a chore: contributor email mappings for salvaged voice-delivery commits 2026-07-28 11:55:48 -07:00
55nx954gn6-debug
28adb86891 fix(gateway): honor global voice.auto_tts in runner voice-reply gate
Salvaged from PR #51196 (@55nx954gn6-debug). _should_send_voice_reply only
consulted the runner's _voice_mode dict (/voice on|voice_only|all), so the
global voice.auto_tts config default — which is synced into each adapter's
_auto_tts_default on gateway connect — was invisible to the runner path.
Net effect: with streaming enabled and only global auto-TTS configured
(no per-chat /voice opt-in), the streamed reply consumed the text, the
base adapter's auto-TTS got text_content=None, and no voice reply was
ever sent (#51867/#23983 remainder).

The runner now also asks the adapter's _should_auto_tts_for_chat(chat_id)
(which encodes per-chat /voice on|off overrides over the global default);
an explicit /voice off chat mode remains a hard override.

Refs #51867 #23983 #51282 #13126
2026-07-28 11:55:48 -07:00
Teknium
4aac89b429 fix(tts): unify TTS text preprocessing behind one shared cleaner
Consolidates all TTS text-preparation paths onto
tools/tts_text_normalize.prepare_spoken_text:

- strip_nonspoken_blocks: removes <think> reasoning blocks (#34213,
  incl. unterminated streaming blocks) and the end-of-turn
  file-mutation verifier footer emitted by run_agent.py (#40772).
- flatten_newlines_for_payload: collapses newlines into sentence
  breaks so newline-sensitive OpenAI-compatible providers (Kokoro)
  speak the whole script instead of truncating at the first newline
  (#9004).
- tools/tts_tool._strip_markdown_for_tts (voice-mode streaming + web
  dashboard path) now delegates to the shared cleaner, with the legacy
  regex pipeline kept as a best-effort fallback.
- hermes_cli/voice.py speak_text and cli.py _voice_speak_response now
  use the shared cleaner instead of their own duplicated regex
  pipelines.
- gateway auto-TTS fallback also strips think blocks.

Tests: tests/tools/test_tts_prepare_spoken.py covers think blocks,
verifier footer, emoji, newline flattening, and the shared-cleaner
wiring on the tool/streaming/gateway paths. Updated the header
expectation in test_voice_cli_integration.py for the heading-fold
behavior of the shared cleaner.

Closes #34213, #9004, #40772
2026-07-28 11:55:01 -07:00
Teknium
fdc24a975e chore: map contributor email reneisaipa@gmail.com -> IvanMiao 2026-07-28 11:54:46 -07:00
Teknium
f3cc2bc022 chore: map moeadham and Vissirexa contributor emails 2026-07-28 11:54:26 -07:00
Teknium
a54067a6fd chore(contributors): map tobiassafaie@MacBook-Air-von-Tobias-3.local 2026-07-28 11:54:01 -07:00
Ben Sheridan-Edwards
ff279649e1 chore(contributors): map bensheridanedwards@gmail.com 2026-07-28 11:54:01 -07:00
Teknium
ce57e9fa85 chore: add contributor email mappings for salvaged STT commits 2026-07-28 11:53:36 -07:00
Teknium
26f50e2f1a chore: map salvaged contributor emails 2026-07-28 11:52:44 -07:00
Alex Fournier
b1a5d67e71 Merge upstream main into fix/hermes-relay-anthropic-context
Signed-off-by: Alex Fournier <afournier@nvidia.com>
2026-07-28 08:10:58 -07:00
Hermes Agent
dcc26fa28a
chore: map contributor omid3098@gmail.com -> omid3098 2026-07-28 07:58:16 -07:00
kshitijk4poor
092f76753b chore(contributors): map tutors1997@outlook.com -> Stoltemberg for PR #56081 salvage 2026-07-28 20:04:58 +05:30
Victor Kyriazakos
6a174e9967 Merge origin/main into feat/gateway-health-diagnostics
# Conflicts:
#	cron/executions.py
#	cron/jobs.py
2026-07-28 13:09:17 +00:00
kshitij
9d9a472171
Merge pull request #73321 from kshitijk4poor/chore/author-map-maff-t2b
chore: add contributor mapping for maff-t2b
2026-07-28 17:45:33 +05:30
kshitijk4poor
8ed80b6987 chore: add contributor mapping for maff-t2b
Needed for PR #70340 attribution check.
2026-07-28 17:10:05 +05:00
Alex Fournier
14bed44c8c Reapply "feat(observability): integrate NeMo Relay runtime and shared metrics"
Signed-off-by: Alex Fournier <afournier@nvidia.com>
2026-07-27 21:10:51 -07:00
Teknium
a10bd49ddd feat(stt): unify language resolution across all STT providers
Class-level fix for the 'STT transcribes the wrong language' issue family
(#55551, #50181 and siblings). Previously language handling was per-provider
chaos: local honoured stt.local.language, Groq/OpenAI/Mistral/DeepInfra sent
no language hint at all, xAI silently forced 'en', ElevenLabs used its own
language_code key, and there was no global setting.

- New _resolve_stt_language() helper: stt.<provider>.language >
  stt.language (new global key) > HERMES_LOCAL_STT_LANGUAGE > auto-detect.
- Threaded through ALL providers: local, local_command, groq, openai,
  mistral, xai, elevenlabs, deepinfra (shared OpenAI handler), command
  providers, and plugin dispatch.
- xAI no longer forces English when nothing is configured (auto-detect).
- Mistral Voxtral now receives a language hint when configured.
- stt.groq.model is now honoured from config (previously env-only).
- DEFAULT_CONFIG gains stt.language, stt.groq, stt.xai, stt.mistral.language.
- Tests: tests/tools/test_stt_language_resolution.py (11 tests, sabotage-
  verified) + full transcription suite green (236 passed).

Builds on cherry-picked contributor work from #19786 (@zombopanda),
#23161 (@materemias), #50684 (@BlackishGreen33).
2026-07-27 20:28:31 -07:00
Hermes Agent
725c7ba534 refactor: single owner for empty-content wire repair (class fix)
The concept 'never send a turn that strict wire validation rejects as
empty' was forked across four sites, each with its own predicate and its
own blind spots:

1. build_assistant_message write-time ' ' pad — broke codex commentary
   turns (content:'' is a designed state), and a DB-side pad can't
   survive _rows_to_conversation's whitespace strip anyway. REMOVED.
2. conversation_loop send-time ' ' pad — main-loop only (summary path
   uncovered), ordering-fragile (had to run after whitespace
   normalization), assistant-only. REMOVED.
3. stream-stub '[response interrupted]' substitution — defeated the
   loop's empty-stub guard (the stub no longer looked empty, entered
   history, and the placeholder leaked into the stitched final
   response via truncated_response_parts). REMOVED.
4. repair_empty_non_final_messages in sanitize_api_messages — the
   unconditional pre-send chokepoint shared by the main loop AND the
   summary path, covers user and assistant turns, non-final only,
   copy-on-write. This is now the SINGLE OWNER.

The owner's payload predicate (_msg_has_payload) is extended to treat
codex_message_items / codex_reasoning_items as payload, so
designed-empty codex commentary turns are never rewritten on any
api_mode — the failure shape that broke site 1 in CI is encoded in the
owner, not special-cased at a call site.

Tests updated to pin the new contracts: builder stores textless turns
as-is; the empty stream stub stays recognizably empty for the loop
guard; poisoned resumed histories are repaired to the placeholder at
the send boundary; codex item carriers are never rewritten.
Sabotage-verified: unwiring the owner fails 3 regression tests.
2026-07-27 20:27:56 -07:00