Skip to content

feat(gateway): bridge clarify tool to messaging platforms#23740

Closed
bladeJumper wants to merge 1 commit into
NousResearch:mainfrom
bladeJumper:feat/clarify-clean
Closed

feat(gateway): bridge clarify tool to messaging platforms#23740
bladeJumper wants to merge 1 commit into
NousResearch:mainfrom
bladeJumper:feat/clarify-clean

Conversation

@bladeJumper

Copy link
Copy Markdown

Problem

The clarify tool returns "Clarify tool is not available in this execution context." when running via the gateway — gateway/run.py never passes clarify_callback to AIAgent(), so the tool is completely non-functional on all messaging platforms.

Closes #12573
Closes #21032
Supersedes #12576
Related #18301, #21893, #503

Comparison with #12576

#12576 (by @tymrtn) wires the callback but only supports plain-text replies — the user must type their answer as a normal message, with no inline buttons or visual feedback. This PR extends that approach with:

  1. Interactive card rendering (Feishu implemented, other platforms follow the same pattern)
  2. Decoupled state management (clarify_state.py) — platform-agnostic, designed for reuse by Telegram/Discord adapters
  3. Free-form Other button — deferred resolution so the user can type a custom answer after tapping Other
  4. Comprehensive test coverage — 300-line test suite for state lifecycle

Changes

tools/clarify_state.py — new file, state management

  • ClarifyState dataclass: question, choices, session_key, resolve callback
  • set_gateway_clarify / resolve_gateway_clarify / cancel_gateway_clarify — gateway-side lifecycle
  • get_gateway_clarify — for gateway to check pending state
  • Platform-agnostic: any adapter can call these to bridge clarify

tools/clarify_tool.py — gateway-aware resolve

  • When gateway clarify is active (_gateway_live), yields control back to the gateway instead of blocking on stdin

gateway/run.py — bridge the clarify lifecycle

  • After each agent turn, check for pending gateway clarify state and render on the platform
  • Intercept user text as free-form clarify answer when _clarify_live is set
  • Move clarify_callback import to usage site (avoids circular dependency)

gateway/platforms/feishu.py — Feishu interactive card

  • send_clarify(): question + choice buttons as interactive card
  • _handle_clarify_card_action(): button click resolution
  • Other button: defers resolution, updates card prompting user to type

tests/tools/test_clarify_state.py — new file, 300 lines

  • State lifecycle: set, get, resolve, cancel
  • Gateway-aware resolution path
  • Edge cases: double-resolve, cancel without set, concurrent sessions

Testing

  • 300-line test suite for clarify_state
  • Manual testing on Feishu: card renders, button clicks resolve, Other + free text resolves, timeout cancels
  • Existing gateway tests pass

Adding Other Platforms

The clarify_state.py module is platform-agnostic. To add Telegram support:

  1. Add send_clarify() to the Telegram adapter (inline keyboard)
  2. Handle callback_query to call resolve_gateway_clarify()
  3. The gateway text interceptor in run.py already handles free-form input

Same pattern applies to Discord (reaction-based, per #21893).

Files Changed

  • tools/clarify_state.py — new file
  • tools/clarify_tool.py — gateway-aware resolve path
  • gateway/run.py — clarify lifecycle bridge + text interceptor
  • gateway/platforms/feishu.py — interactive card rendering + handler
  • tests/tools/test_clarify_state.py — new test file

Adds gateway-side infrastructure for the clarify tool, enabling
interactive questions with choice buttons on messaging platforms
(Feishu, extensible to Telegram/Discord).

Root cause: AIAgent() was constructed without clarify_callback in
gateway/run.py, so clarify_tool.py got callback=None and returned
an error JSON to the model.

Architecture mirrors the existing approval system:
- tools/clarify_state.py: core bridge with per-session blocking queue
- gateway/run.py: injects clarify_callback into AIAgent, adds
  clarify_notify_sync dispatcher (card-based with text fallback)
- gateway/platforms/feishu.py: send_clarify_prompt() sends interactive
  cards with choice buttons; _handle_clarify_card_action() resolves
  the blocked agent thread on button click

Key design decisions:
- Clarify cards use hermes_action=clarify_* namespace, routed separately
  from approval actions
- Multiple concurrent clarify prompts supported via clarify_id
- Other button defers resolution: card updates to prompt user to type
  their answer, then text-intercept logic in run.py resolves with the
  actual typed text (Feishu cards cannot present text input fields)
- Open-ended questions (no choices) show text hint, not buttons
- clarify_callback import moved to usage site to avoid potential
  circular dependency

Tests: 14 new tests in test_clarify_state.py, all passing.
@alt-glitch alt-glitch added type/feature New feature or request comp/gateway Gateway runner, session dispatch, delivery comp/tools Tool registry, model_tools, toolsets platform/feishu Feishu / Lark adapter P2 Medium — degraded but workaround exists labels May 11, 2026
bladeJumper added a commit to bladeJumper/hermes-agent that referenced this pull request May 21, 2026
Implements the clarify tool on Feishu with interactive card buttons,
mirroring the Telegram pattern from NousResearch#24199.

- send_clarify: renders question + choice buttons as Feishu interactive card
- _handle_clarify_card_action: routes button callbacks via hermes_clarify_action
  - choice: resolves immediately with choice text
  - other: flips to text-capture mode via mark_awaiting_text
- Already-resolved guard prevents double-click / stale-button issues
- Authorization check reuses _is_interactive_operator_authorized
- Choice text lookup: stored state → clarify entry → fallback index

Known limitation: Feishu shows both the tool-progress bubble (❓ clarify: ...)
and the interactive card because Feishu lacks delete_message support.
This can be revisited once Feishu implements message deletion.

Closes NousResearch#12573
Closes NousResearch#21032
Supersedes NousResearch#23740 (which included framework code now merged in NousResearch#24199)
Related NousResearch#24199, NousResearch#21893, NousResearch#503
@bladeJumper

Copy link
Copy Markdown
Author

Superseded by #29719 (cleaner implementation based on the merged #24199 framework).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/tools Tool registry, model_tools, toolsets P2 Medium — degraded but workaround exists platform/feishu Feishu / Lark adapter type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: gateway sessions expose clarify tool but never wire clarify_callback Clarify tool breaks in gateway/Telegram mode — missing callback wiring

2 participants