Skip to content

feat: natural-language abort triggers#2911

Open
Glucksberg wants to merge 1 commit intoNousResearch:mainfrom
Glucksberg:feature/abort-triggers
Open

feat: natural-language abort triggers#2911
Glucksberg wants to merge 1 commit intoNousResearch:mainfrom
Glucksberg:feature/abort-triggers

Conversation

@Glucksberg
Copy link

@Glucksberg Glucksberg commented Mar 25, 2026

Summary

  • Detect plain-text abort requests and immediately abort the running agent — no slash command required
  • Intercept abort triggers at both the adapter level (base.py) and the gateway runner (run.py) — the adapter-level check is critical because the active-session handler short-circuits before messages reach the gateway runner
  • Kill background processes and clear pending message queues on abort
  • Reply with 🚫 Agent aborted.

Background

On 2026-02-23 an AI agent (OpenClaw) deleted a user's entire Gmail inbox after context compaction discarded the "confirm before acting" instruction. The user typed "STOP" in the chat but the agent kept going because only the /stop slash command was recognised. This patch ensures that will never happen in Hermes.

Trigger list

Single-word: stop, abort, cancel, halt, quit

Multi-word: stop hermes, stop agent, stop please, stop now, stop it, stop that, stop action, stop run, stop everything, stop all

All matching is exact after normalization (lowercase, strip trailing punctuation, collapse spaces). Partial matches like "when you stop hermes from doing that task..." are NOT caught.

Implementation

File Change
tools/abort_triggers.py New — trigger detection module: ABORT_TRIGGERS (single-word), ABORT_TRIGGER_PHRASES (multi-word), _normalize(), is_abort_request()
gateway/platforms/base.py Intercept abort in BasePlatformAdapter._handle_message() before the message is enqueued as a pending interrupt — this is the primary intercept point for Telegram/Discord/etc.
gateway/run.py Intercept abort in GatewayRunner priority handler (fallback for other code paths)
cli.py Intercept abort in the CLI interrupt queue monitor loop
tests/test_abort_triggers.py 41 tests, 100% line coverage

Why the adapter-level check matters

When an agent is actively running, base.py's active-session handler intercepts incoming messages and enqueues them as priority interrupts — the message never reaches the gateway runner. Without the adapter-level check, "stop hermes" was queued as a pending message and processed as normal input after the agent finished its turn.

Test plan

  • 41 pytest tests passing (100% coverage on tools/abort_triggers.py)
  • Manual test: send "stop hermes" on Telegram while agent is running — agent aborted, got 🚫 reply
  • Manual test: send a sentence containing "stop hermes" as substring — correctly NOT caught
  • Manual test: verify normal messages are not caught as false positives

🤖 Generated with Claude Code

@Glucksberg Glucksberg force-pushed the feature/abort-triggers branch from 1b00408 to 9923d68 Compare March 25, 2026 04:23
@Glucksberg
Copy link
Author

human note: manually tested it. it works. and it helps a lot when my qwen 9b goes nuts.

@Glucksberg Glucksberg force-pushed the feature/abort-triggers branch from 9868324 to fd65205 Compare March 25, 2026 05:46
Detect plain-text abort requests ("stop", "stop hermes", etc.) and
immediately abort the running agent — no slash command required.

On 2026-02-23 an AI agent deleted a user's entire Gmail inbox because
context compaction discarded the "confirm before acting" instruction.
The user typed "STOP" but only /stop was recognised. This ensures
plain-text abort requests are caught in Hermes.

Implementation:
- tools/abort_triggers.py: trigger sets, normalization, is_abort_request()
- gateway/platforms/base.py: intercept abort at adapter level before
  message is enqueued (critical — without this, abort triggers were
  queued as pending messages and only processed after the agent finished)
- gateway/run.py: intercept abort in gateway runner (fallback path)
- cli.py: intercept abort in the CLI interrupt queue

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Glucksberg Glucksberg force-pushed the feature/abort-triggers branch from fd65205 to 7d2720d Compare March 25, 2026 05:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant