mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-29 18:46:59 +00:00
fix(voice-mode): make Termux:API detection robust against pm probe failures
\`pm list packages com.termux.api\` is the canonical way to detect the Termux:API Android app, but on some devices it gives a false negative even when the app is installed and \`termux-microphone-record\` runs fine — the symptom reported in #31015 (\`/voice on\` complaining "Termux:API Android app is not installed"). Replace the single probe with a graded strategy: 1. Try \`pm list packages com.termux.api\` (current behaviour). 2. If \`pm\` isn't on PATH or returns non-zero, fall back to \`cmd package list packages com.termux.api\` — the modern Android API 28+ equivalent that's present on devices where \`pm\` is gone. 3. If both probes are inconclusive (binary missing, permission denied, timeout, or non-zero exit) and \`termux-microphone-record\` is on PATH, trust the binary. The CLI ships in the \`termux-api\` package which is essentially only useful with the Android app installed; users who installed it deliberately almost always have the app too. Polarity matters: a false negative on this gate blocks \`/voice on\` entirely (the user-reported symptom), while a false positive only surfaces a precise runtime error from the binary itself when it tries to talk to the missing app — strictly more actionable. The clean-probe-but-no-package case still returns False, so the existing "Termux:API CLI installed without the app" warning still fires when the package manager *can* tell us the app is missing. Refs: NousResearch/hermes-agent#31015
This commit is contained in:
parent
0560f52047
commit
e3f4dc2103
1 changed files with 64 additions and 11 deletions
|
|
@ -83,21 +83,74 @@ def _termux_microphone_command() -> Optional[str]:
|
|||
|
||||
|
||||
|
||||
# Probes used to detect whether the Termux:API Android app is installed.
|
||||
# `pm list packages` is the canonical Android lookup but is unreliable on
|
||||
# some devices: on certain ROMs / Android API levels `pm` itself isn't on
|
||||
# Termux's PATH while `cmd package` is, on others `pm` returns nothing for
|
||||
# the calling user even when the app is present. We try both before
|
||||
# concluding that the app is genuinely missing (issue #31015).
|
||||
_TERMUX_API_PACKAGE_PROBES = (
|
||||
("pm", "list", "packages", "com.termux.api"),
|
||||
("cmd", "package", "list", "packages", "com.termux.api"),
|
||||
)
|
||||
|
||||
|
||||
def _termux_api_app_installed() -> bool:
|
||||
"""Return True iff the Termux:API Android app is installed.
|
||||
|
||||
Strategy (issue #31015):
|
||||
|
||||
1. Try each probe in ``_TERMUX_API_PACKAGE_PROBES`` and look for
|
||||
``package:com.termux.api`` in stdout. Any positive hit is
|
||||
authoritative — return True.
|
||||
2. If every probe is *inconclusive* (binary missing, permission
|
||||
denied, timeout, non-zero exit) we cannot honestly say the app
|
||||
is missing; fall back to trusting the ``termux-microphone-record``
|
||||
binary on PATH. The binary ships with the ``termux-api`` package
|
||||
and is only useful when the Android app is installed; users who
|
||||
installed the package deliberately almost always have the app
|
||||
too. A false negative on this gate blocks ``/voice on``
|
||||
outright (the symptom reported in #31015), while a false
|
||||
positive only surfaces a precise runtime error from the binary
|
||||
itself — strictly more actionable.
|
||||
3. If at least one probe ran cleanly and definitively did not
|
||||
mention the package, treat the app as missing and return False
|
||||
— that's the genuine "Termux:API CLI installed without the app"
|
||||
case the existing warning was written for.
|
||||
"""
|
||||
if not _is_termux_environment():
|
||||
return False
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["pm", "list", "packages", "com.termux.api"],
|
||||
capture_output=True,
|
||||
text=True, encoding='utf-8', errors='replace',
|
||||
timeout=5,
|
||||
check=False,
|
||||
stdin=subprocess.DEVNULL,
|
||||
|
||||
inconclusive = False
|
||||
for cmd in _TERMUX_API_PACKAGE_PROBES:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
list(cmd),
|
||||
capture_output=True,
|
||||
text=True, encoding='utf-8', errors='replace',
|
||||
timeout=5,
|
||||
check=False,
|
||||
stdin=subprocess.DEVNULL,
|
||||
)
|
||||
except (FileNotFoundError, PermissionError, OSError):
|
||||
inconclusive = True
|
||||
continue
|
||||
except subprocess.TimeoutExpired:
|
||||
inconclusive = True
|
||||
continue
|
||||
if result.returncode != 0:
|
||||
inconclusive = True
|
||||
continue
|
||||
if "package:com.termux.api" in (result.stdout or "").lower():
|
||||
return True
|
||||
|
||||
if inconclusive and shutil.which("termux-microphone-record") is not None:
|
||||
logger.debug(
|
||||
"Termux package-manager probes inconclusive; trusting "
|
||||
"termux-microphone-record binary on PATH (issue #31015)."
|
||||
)
|
||||
return "package:com.termux.api" in (result.stdout or "")
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _termux_voice_capture_available() -> bool:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue