Skip to content

feat: pluggable context engine slot + unified hermes plugins UI#7464

Merged
teknium1 merged 6 commits into
mainfrom
hermes/hermes-7e4c9931
Apr 11, 2026
Merged

feat: pluggable context engine slot + unified hermes plugins UI#7464
teknium1 merged 6 commits into
mainfrom
hermes/hermes-7e4c9931

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Salvages PR #6126 (which salvaged PR #5700 by @stephenschoettler) and adds the unified hermes plugins UI with provider plugin categories.

From PR #6126 / #5700 (cherry-picked, credit: @stephenschoettler)

  • agent/context_engine.py — ContextEngine ABC with lifecycle hooks, tool schemas, model switch support
  • agent/context_compressor.py — Now inherits from ContextEngine ABC, adds on_session_reset(), update_model(), name property
  • hermes_cli/plugins.pyregister_context_engine() on PluginContext, single-engine enforcement
  • hermes_cli/config.pycontext.engine in DEFAULT_CONFIG, "context" in _KNOWN_TOP_LEVEL
  • plugins/context_engine/__init__.py — Discovery module mirroring memory plugins
  • run_agent.py — Config-driven engine selection, tool injection/dispatch, ABC calls throughout, session lifecycle wiring
  • tests/agent/test_context_engine.py — 19 tests for ABC contract, plugin slot

Follow-up fixes (this PR adds)

No auto-activation (policy fix):
When context.engine is "compressor" (default), plugin-registered engines are NOT used. Users must explicitly set context.engine to a plugin's name in config.yaml to activate it. This prevents silently overriding the built-in compressor just by installing a plugin.

Unified hermes plugins UI:

  • curses_radiolist() in curses_ui.py — single-select radio picker with keyboard nav + text fallback
  • Composite cmd_toggle() screen combining:
    • Top section: General plugins with checkboxes (existing behavior preserved)
    • Bottom section: Provider plugin categories (Memory Provider, Context Engine) showing current selection inline. ENTER/SPACE drills into a radiolist sub-screen for single-select configuration.
  • Provider discovery helpers: _discover_memory_providers(), _discover_context_engines()
  • Config persistence: _save_memory_provider(), _save_context_engine()

Tests:

  • curses_radiolist non-TTY fallback
  • Provider config save/load (memory.provider, context.engine)
  • Discovery error handling
  • Auto-activation removal verification
  • All 1126 agent + plugin tests pass (1 pre-existing failure unrelated)

Subsumes

Closes #5701. Credit to @stephenschoettler for the original design and implementation.

stephenschoettler and others added 6 commits April 10, 2026 17:27
…om it

Introduces agent/context_engine.py — an abstract base class that defines
the pluggable context engine interface. ContextCompressor now inherits
from ContextEngine as the default implementation.

No behavior change. All 34 existing compressor tests pass.

This is the foundation for a context engine plugin slot, enabling
third-party engines like LCM (Lossless Context Management) to replace
the built-in compressor via the plugin system.
- PluginContext.register_context_engine() lets plugins replace the
  built-in ContextCompressor with a custom ContextEngine implementation
- PluginManager stores the registered engine; only one allowed
- run_agent.py checks for a plugin engine at init before falling back
  to the default ContextCompressor
- reset_session_state() now calls engine.on_session_reset() instead of
  poking internal attributes directly
- ContextCompressor.on_session_reset() handles its own internals
  (_context_probed, _previous_summary, etc.)
- 19 new tests covering ABC contract, defaults, plugin slot registration,
  rejection of duplicates/non-engines, and compressor reset behavior
- All 34 existing compressor tests pass unchanged
- Inject engine tool schemas into agent tool surface after compressor init
- Call on_session_start() with session_id, hermes_home, platform, model
- Dispatch engine tool calls (lcm_grep, etc.) before regular tool handler
- 55/55 tests pass
…very, ABC completeness

Follow-up fixes for the context engine plugin slot (PR #5700):

- Enhance ContextEngine ABC: add threshold_percent, protect_first_n,
  protect_last_n as class attributes; complete update_model() default
  with threshold recalculation; clarify on_session_end() lifecycle docs
- Add ContextCompressor.update_model() override for model/provider/
  base_url/api_key updates
- Replace all direct compressor internal access in run_agent.py with
  ABC interface: switch_model(), fallback restore, context probing
  all use update_model() now; _context_probed guarded with getattr/
  hasattr for plugin engine compatibility
- Create plugins/context_engine/ directory with discovery module
  (mirrors plugins/memory/ pattern) — discover_context_engines(),
  load_context_engine()
- Add context.engine config key to DEFAULT_CONFIG (default: compressor)
- Config-driven engine selection in run_agent.__init__: checks config,
  then plugins/context_engine/<name>/, then general plugin system,
  falls back to built-in ContextCompressor
- Wire on_session_end() in shutdown_memory_provider() at real session
  boundaries (CLI exit, /reset, gateway expiry)
…egories

- Remove auto-activation: when context.engine is 'compressor' (default),
  plugin-registered engines are NOT used. Users must explicitly set
  context.engine to a plugin name to activate it.

- Add curses_radiolist() to curses_ui.py: single-select radio picker
  with keyboard nav + text fallback, matching curses_checklist pattern.

- Rewrite cmd_toggle() as composite plugins UI:
  Top section: general plugins with checkboxes (existing behavior)
  Bottom section: provider plugin categories (Memory Provider, Context Engine)
  with current selection shown inline. ENTER/SPACE on a category opens
  a radiolist sub-screen for single-select configuration.

- Add provider discovery helpers: _discover_memory_providers(),
  _discover_context_engines(), config read/save for memory.provider
  and context.engine.

- Add tests: radiolist non-TTY fallback, provider config save/load,
  discovery error handling, auto-activation removal verification.
New page:
- developer-guide/context-engine-plugin.md — full guide for building
  context engine plugins (ABC contract, lifecycle, tools, registration)

Updated pages (11 files):
- plugins.md — plugin types table, composite UI documentation with
  screenshot-style example, provider plugin config format
- cli-commands.md — hermes plugins section rewritten for composite UI
  with provider plugin config keys documented
- context-compression-and-caching.md — new 'Pluggable Context Engine'
  section explaining the ABC, config-driven selection, resolution order
- configuration.md — new 'Context Engine' config section with examples
- architecture.md — context_engine.py and plugins/context_engine/ added
  to directory trees, plugin system description updated
- memory-provider-plugin.md — cross-reference tip to context engines
- memory-providers.md — hermes plugins as alternative setup path
- agent-loop.md — context_engine.py added to file reference table
- overview.md — plugins description expanded to cover all 3 types
- build-a-hermes-plugin.md — tip box linking to specialized plugin guides
- sidebars.ts — context-engine-plugin added to Extending category
@teknium1 teknium1 merged commit 79198eb into main Apr 11, 2026
3 of 7 checks passed
@SHL0MS SHL0MS mentioned this pull request Apr 11, 2026
2 tasks
@Tosko4

Tosko4 commented Apr 12, 2026

Copy link
Copy Markdown
Contributor

@teknium1 sorry to bother, but as this was cherry picked, I started working with it and some bugs I helped patching (which have been merged into Hermes-LCM repository by @stephenschoettler ), need some extra support from Hermes Agent. I know you are a very busy person, but would you be able to eyeball this PR quickly to help LCM a bit better? #8416

ccross2 added a commit to ccross2/hermes-agent that referenced this pull request Apr 14, 2026
Brings ccross2/hermes-agent up to NousResearch/hermes-agent@ac80bd61
(v0.9.0 release "the everywhere release").

Merge highlights from upstream:
- Pluggable Context Engine slot (NousResearch#7464)
- Local web dashboard, Termux/Android, iMessage/WeChat platforms
- Fast Mode (/fast) for OpenAI/Anthropic priority queues
- Background process monitoring (watch_patterns, NousResearch#7635)
- Comprehensive security hardening (Twilio signature, SSRF, path
  traversal, git injection, shell injection in sandbox writes)
- Dead code cleanup (1,784 lines across 77 files, NousResearch#9180)
- CANONICAL_PROVIDERS consolidation (NousResearch#9237)
- gateway /stop no longer resets session (NousResearch#9224)

Conflict resolution summary (7 hunks across 3 files):

1-4. cli.py _build_compact_banner — took upstream.
   Upstream added skin-aware colors + version label + tiny_line for
   narrow terminals. ccross2 had added word-wrapping for narrow
   terminals (commit 5b32504). The skin engine integration is
   foundational (affects several other surfaces); the word-wrapping
   improvement can be re-added as a follow-up on top of skin-aware.

5. cli.py _reset_stream_state — kept BOTH.
   ccross2 added _stream_in_code_fence; upstream added
   _deferred_content. Different features in the same reset hook,
   both needed.

6. tools/transcription_tools.py get_stt_model_from_config — took ccross2.
   ccross2 added provider-aware model resolution (local/groq/openai
   with per-provider model overrides). Upstream restructured but
   didn't provide an equivalent; the function coexists with upstream's
   _load_stt_config() which returns the raw dict.

7. tests/tools/test_transcription_tools.py — took ccross2.
   Tests for the provider-aware function we kept in (6).

Post-merge state: 5 local ccross2 commits preserved on top of
upstream 0.9. Backup of pre-merge state at
ccross2/cc-fusion-09-rebase-backup (Claude Code's rebase attempt
with 4 of the 5 patches, before this proper merge).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

Proposal: Pluggable context engines — enabling LCM as a plugin (like OpenClaw's lossless-claw)

3 participants