feat(gateway): add compact action buttons - #82727
isolovyev77 wants to merge 2 commits into
Conversation
Related to #52252 and #52497. This PR implements a synchronous fixed-choice tool that waits for and returns a selected value; #52497 provides fire-and-forget action-menu infrastructure with a separate dispatch seam. These are overlapping approaches rather than duplicates; maintainer review should choose whether both primitives belong. |
|
Thanks for the triage note. That distinction matches my intent. I agree this overlaps with #52252 / #52497, but I see this PR as the synchronous fixed-choice subset rather than a competing fire-and-forget action-menu system:
If maintainers prefer one unified abstraction, I’m happy to adapt this PR in that direction. The part I’d like to preserve is the synchronous “wait for one of these fixed choices and return the selected value” contract, because it covers a different agent-flow shape than fire-and-forget action menus. |
feat(gateway): add compact action buttons
Summary
This PR adds a small fixed-choice interaction primitive,
action_buttons, for cases where Hermes needs compact buttons rather than a full clarify/free-text prompt.It adds:
action_buttonstool with 1-4 fixed choices;Problem
clarifyis intentionally general-purpose: it can show multiple choices and may include a free-textOtherpath. That is useful for open-ended clarification, but it is not ideal for Telegram workflows where:1,2,3;Otherbranch;Without a dedicated primitive, agents either duplicate long labels on Telegram buttons or fall back to plain numbered prose, which is easier to miss and harder to bind to a specific message.
Related work / duplicate check
I searched open issues and PRs before preparing this PR, per
CONTRIBUTING.md:repo:NousResearch/hermes-agent is:issue "action buttons"repo:NousResearch/hermes-agent is:issue "inline keyboard" "Telegram"repo:NousResearch/hermes-agent is:pr "action buttons"repo:NousResearch/hermes-agent is:pr "inline keyboard" "Telegram"repo:NousResearch/hermes-agent is:pr "Other" "clarify" "Telegram"Relevant existing threads:
clarifypresentation. This PR does not changeclarify; it adds a separate no-Other, fixed-choice primitive.So this is not intended as a competing broad action-menu proposal. It is a small, reviewable implementation of the fixed-choice subset that keeps the gateway callback path explicit and testable.
Why this is a tool, not a skill
CONTRIBUTING.mdsays most new capabilities should be skills and new tools are rare. I think this case fits the tool/gateway exception because it cannot be expressed reliably as instructions plus existing tools:1,2,3) and the semantic value (Deploy to production) must be separated server-side.Proposed behavior
The model/tool call provides full semantic choices:
{ "question": "Which deployment target?", "choices": ["Deploy to staging", "Deploy to production"] }Telegram renders the human-readable body with full options:
The inline keyboard shows compact buttons in one row:
When the user taps
2, the gateway resolves the tool response to:This keeps Telegram UI compact while preserving unambiguous semantic choice handling inside the agent flow.
Design notes
action_buttonsis deliberately separate fromclarify.Otherbranch.act:{action_id}:{idx}.tools.action_buttons_gateway, mirroring the existing gateway-mediated interaction pattern.Non-goals
clarify.Files touched
tools/action_buttons_tool.pytools/action_buttons_gateway.pytoolsets.pyagent/agent_init.pyagent/tool_executor.pyagent/agent_runtime_helpers.pyrun_agent.pygateway/run.pyplugins/platforms/telegram/adapter.pytests/gateway/test_telegram_action_buttons.pyValidation
Branch was rebased onto current
origin/mainbefore validation.Local branch state:
git rev-list --left-right --count origin/main...HEAD->0 24e4eb5a4d9 feat(gateway): add compact action buttonsa72015f776 fix(telegram): keep action buttons on one rowChecks run locally:
python3 -m py_compile agent/agent_init.py agent/tool_executor.py gateway/run.py plugins/platforms/telegram/adapter.py run_agent.py tools/action_buttons_gateway.py tools/action_buttons_tool.py tests/gateway/test_telegram_action_buttons.py toolsets.pypy_compile=okaction_buttons_contracts=okgit diff --check origin/main...HEAD-> okpytestcould not be run in this local worktree environment because the environment lacks pytest:python -m pytest tests/gateway/test_telegram_action_buttons.py -o 'addopts=' -qNo module named pytestLive validation on a Telegram gateway after applying the same layout fix locally:
[1] [2] [3]in one row;Platforms/environment checked:
6.8.0-124-genericx86_643.11.15a72015f7762446c8bb67Security policy check
This PR is not a security vulnerability report and does not cross the security-policy reporting threshold. It does not claim a sandbox/containment boundary, does not change the approval security model, and does not include credentials.
Security-relevant review points:
A simple changed-file scan for obvious credential strings was also run locally before PR preparation.
Maintainer review focus
The main design question is whether this should remain a separate fixed-choice primitive or be folded into
clarifyas a mode. I kept it separate because the UX contract is different: fixed actions, noOther, compact numeric labels, and full semantic resolution.If maintainers prefer a different naming or platform abstraction, the implementation is intentionally small and isolated enough to adapt.