M57andM57 adde03a4de fix(chat): stop duplicating interim commentary before tool calls (issue #842) (#854)
* fix(chat): stop duplicating interim commentary before tool calls (issue #842)

Interim commentary the agent narrates before each tool call rendered
TWICE. Two mechanisms, both now covered:

1. The old tool.start orphan seal + message.complete's full text: when the
   complete payload repeats the commentary, the final bubble duplicated
   it. onMessageComplete now strips the sealed-orphan prefix (tracked in
   StreamingState) from the final text.

2. On-device capture + DB forensics (2026-08-08) exposed the real
   repeat offender: the app seals the RAW streamed text — which carries
   leading blank lines the model emits before its narration — while the
   backend persists a CLEANED copy (leading whitespace stripped). A
   transcript reload ~10s later merged the REST page, exact-content
   matching failed, and the cleaned REST copy rendered on top of the
   live bubble. sameLogicalMessage now compares trimmed content, so the
   sealed live bubble is covered by the REST row.

Also:
- session.interrupt seals the in-flight streaming message before
  clearing streaming state, so interrupting a commentary turn keeps the
  partial text
- regression tests cover both turn shapes (commentary in the final row →
  stripped; absent → kept) and the whitespace-drift reload case

* fix(chat): match tool rows by gateway call id, drop reasoning-echo dupes (#842)

REST transcript rows carry tool_call_id; live WS bubbles keep tool_id from
tool.start. Match tool rows on that 1:1 identity so MCP/web rows (stored as
raw <untrusted_tool_result> text with no JSON key) dedupe during the
post-turn transcript merge instead of ghosting after the final message.

reasoning.available echo (narration text == message body, sent ~40ms before
each tool.start) no longer overwrites the real reasoning trace, so narration
bubbles don't render their own text twice (body + Reasoning card).

Room v5 migration adds tool_call_id; regression tests use captured
on-device payload shapes.

* fix(chat): flush throttled tokens before orphan seal + prefix-safe dedupe (#842)

The tool.start seal raced the 33ms throttled token flush: deltas landing just
before the transition stayed in the buffer, so the sealed narration orphan came
out truncated (on-device capture: orphan ended '...chickpea', backend persisted
'...chickpea goodness:') and failed the logical-match against the clean REST
row — the commentary ghosted on the next transcript sync.

- ChatStreamingController.flushPendingTokens(): force-flushes the throttled
  TOKEN buffer on MessageStart/MessageComplete/MessageDone/ToolStart so the
  reducer seals the COMPLETE narration.
- sameLogicalMessage: accept prefix-covering (both sides >=40 chars) so a
  residual seal drift can never re-add a substantial narration.
- Regression tests: controller flush + truncated-orphan prefix match.

---------

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
2026-08-08 23:34:58 +03:00
2026-06-22 21:35:40 +03:00
2026-07-23 13:21:14 +03:00

Hermes Mobile

Native Android companion app for your Hermes AI agent.


Android Jetpack Compose Kotlin Material You

Latest Release CI minSdk 26 targetSdk 36


Overview

Hermes Mobile is the native Android client for Hermes Agent. It connects securely to your local Hermes gateway (REST API and WebSocket TUI Gateway) over LAN, giving you pocket control over your AI assistant.


Screenshots

Hermes Mobile chat screen Hermes Mobile cron jobs screen Hermes Mobile Kanban screen Hermes Mobile skills screen

Chat, automation, productivity, and agent configuration — from your phone.


Features

  • Real-Time Chat: Message your agent with Room-backed local database history and inline reply notifications.
  • System Config: Manage active profiles, installed skills, plugins, toolsets, and LLM model/provider selections.
  • Operations: Stream and filter live logs, manage cron jobs, edit environment keys, test webhooks, and monitor processes.
  • Gateway Status: Monitor WebSocket connection, MCP servers, messaging channels, and OAuth providers.
  • Productivity: View and manage tasks via integrated Kanban boards, track agent milestones, and browse session history.
  • Analytics & Billing: Usage analytics dashboard and billing/subscription management.
  • Theming: 6 built-in color presets (Default, Monochrome, Gruvbox, Catppuccin, AMOLED, Neon Noir) plus Material You dynamic colors on supported devices.
  • Modern UX: Native Material 3 design with pull-to-refresh, scroll-aware TopBar, and customizable bottom navigation.

Quick Start

Prerequisites

  • JDK 21+ (required for Kotlin compilation and the Gradle toolchain)
  • Android Studio (Ladybug+) or a Nix development environment

Build & Deploy

  1. Clone the repository:
    git clone https://github.com/Hy4ri/hermes-mobile.git
    cd hermes-mobile
    
  2. Build the debug APK:
    ./gradlew assembleDebug
    
  3. Install on your emulator/device:
    adb install app/build/outputs/apk/debug/app-debug.apk
    

Note: For release builds, ensure keystore environment variables (KEYSTORE_PATH, KEYSTORE_PASSWORD, KEY_ALIAS, KEY_PASSWORD) are configured, or let the GitHub Actions release workflow handle it on tag push (v*).


Authentication

Once the app is installed, you need to point it at your Hermes gateway. The app auto-detects which auth mode the dashboard is using — just fill in the fields it shows.

1. Start the dashboard

On your host machine, start the dashboard:

hermes dashboard                          # loopback (127.0.0.1:9119) — no auth needed
hermes dashboard --host 0.0.0.0           # LAN — requires auth

For LAN access, configure credentials in ~/.hermes/config.yaml:

dashboard:
  basic_auth:
    username: admin       # pick your own
    password: hermes      # pick your own

2. Connect the app

Tap Sign in on the landing screen and enter the dashboard host and port. The app probes the dashboard and reveals the fields you need:

Auth mode When What you fill
Token only Dashboard on same machine (loopback) Token — grab from ~/.hermes/dashboard-token.txt or ~/.hermes/.env (HERMES_DASHBOARD_SESSION_TOKEN). The app can also auto-extract it from the dashboard page
Basic auth Dashboard on LAN with password gate Username + Password (default admin / hermes). The app logs in, gets a session cookie, and mints a WebSocket ticket automatically

The app communicates over plain HTTP — it's designed for trusted local networks only. Do not expose your Hermes gateway to untrusted networks.

Connection profiles

Have multiple gateways? Switch between them in Settings → Connection profiles. Each profile stores its own host, port, and token — just tap to swap.

Pairing (admin)

The Pairing screen lets you approve or revoke agents and services that are trying to connect to your gateway, such as Telegram or Discord sessions.


Project Structure

app/src/main/java/com/m57/hermescontrol/
├── data/          # Local (Room, AuthManager), Remote (Retrofit, OkHttp), WS (WebSocket), Models
├── notification/  # Foreground service + inline reply for chat notifications
├── theme/         # Preset-based design system (6 themes), status colors, spacing, typography
├── ui/            # 28 Compose feature screens + common components (HermesScaffold, StateViews)
├── util/          # CronExpressionFormatter, LocaleContextWrapper
└── Navigation*.kt # Navigation3 wiring, keys, screen registry, controller

Tech Stack

  • Language: Kotlin 2.4.10 with KSP 2.3.10 compiler plugin
  • UI & Layout: Jetpack Compose (BOM 2026.03.01) & Material 3 / Material You
  • Navigation: Navigation3 (Compose-first Routing)
  • Networking: Retrofit 3.0.0, OkHttp 5.4.0, Kotlinx Serialization 1.11.0
  • Database: Room 2.7.1 with SQLCipher 4.17.0 encryption
  • Security: EncryptedSharedPreferences (AES256-GCM), DataStore
  • Theming: 6 built-in presets (Default, Monochrome, Gruvbox, Catppuccin, AMOLED, Neon Noir) + Material You dynamic colors
  • Image Loading: Coil 2.7.0
  • Testing: JUnit 5, MockK, Turbine, Espresso, Compose UI testing
  • Formatting: ktlint 1.2.1 style rules (checked automatically in CI)

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for our branch workflow, code style guidelines, and PR checklist.

For developer-specific details, code conventions, and project architecture notes, refer to AGENTS.md.


License

Copyright © 2026 M57 (Hy4ri).

This project is licensed under the Apache License, Version 2.0. See the LICENSE file for details.

S
Description
AITURK Mobil — Android companion for AITURK IDE (fork of Hy4ri/hermes-mobile, Apache-2.0)
Readme Apache-2.0
10 MiB
0 Stars 1 Watchers 0 Forks
Languages
Kotlin 99.9%