Skip to content

Explore declarative registration for specialized providers #22

Description

@offendingcommit

Problem

hermes-plugin-kit gives tools, hooks, middleware, and commands declarative decorators that register_plugin() discovers from a module. Specialized providers use a separate explicit path:

return register_plugin(
    ctx,
    tools,
    memory_providers=(MyMemoryProvider(),),
)

That path is correct for Hermes' lifecycle, but it creates an asymmetry for plugins that combine model-facing tools with a memory provider. The plugin author must maintain decorated module declarations plus a separate provider tuple in register().

The concrete example is hermes-plugin-mempalace: all model-facing operations use @tool, while its private-only MemoryProvider is manually instantiated and passed to register_plugin(). The realm gate also has to be repeated at registration time.

Research

Proposal to explore

Add an optional class-level declaration for specialized providers, while retaining the current instance tuple as the stable low-level API. For example:

@memory_provider(enabled=lambda: not realm_policy().read_only)
class MemPalaceMemoryProvider(MemoryProvider):
    ...

return register_plugin(ctx, module)

The decorator would mark a provider class or factory for discovery. It would not wrap prefetch, sync_turn, shutdown, generate, or any other provider method. register_plugin() would instantiate the declaration only after its activation predicate passes and would still forward the resulting instance through Hermes' specialized registry.

This should be evaluated against two simpler alternatives:

  1. Keep the existing explicit tuples and document them as intentionally different from general decorated surfaces.
  2. Add a typed plugin_provider(...) declaration/factory rather than a Python decorator, avoiding implicit class construction.

Required boundaries

  • Do not expose provider lifecycle methods as model-callable tools.
  • Preserve the Hermes MemoryProvider, ImageGenProvider, and VideoGenProvider ABC contracts.
  • Preserve one stateful provider instance per registration.
  • Allow runtime activation gates without constructing disabled providers.
  • Fail clearly when the active Hermes context does not support that provider kind.
  • Detect duplicate provider names across explicit and discovered declarations.
  • Keep memory_providers=, image_gen_providers=, and video_gen_providers= backward compatible.
  • Include registration receipts in RegistrationSummary exactly as the current instance path does.

Definition of done

  • Decide whether declarative provider discovery is materially clearer than the explicit tuple contract.
  • If accepted, define construction/factory semantics and activation timing before implementation.
  • Add tests for enabled/disabled declarations, duplicate names, unsupported contexts, constructor failures, and coexistence with explicit provider tuples.
  • Update the specialized-provider guidance without weakening the rule against decorating provider methods as general plugin surfaces.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions