nexo-poller 0.2.0

Generic polling runtime: cron schedules, retries, ack semantics.
Documentation

nexo-poller

Generic polling runtime for Nexo — cron-style schedules, durable cursors, retry/DLQ semantics, single-instance leases. Powers gmail / rss / webhook / google-calendar / agent_turn built-ins plus extension-loaded pollers.

This crate is part of Nexo — a multi-agent Rust framework with a NATS event bus, pluggable LLM providers (MiniMax, Anthropic, OpenAI-compat, Gemini, DeepSeek), per-agent credentials, MCP support, and channel plugins for WhatsApp, Telegram, Email, and Browser (CDP).

What this crate does

  • Cron-style scheduler — each job has a cron expression + jitter; the runtime ticks every minute and dispatches due jobs to their declared poller.
  • Durable cursors — every successful tick persists a per- job cursor (timestamp, history-id, message-id, etc.) so a restart resumes from where it left off.
  • Single-instance lease — cross-process SQLite lease prevents two daemons from double-ticking the same job.
  • Retry / DLQ classification — poller responses with error_kind: "transient" retry with exponential backoff; permanent go to a per-job DLQ; skipped count as successful no-ops.
  • Built-in pollers:
    • gmail — Gmail history sync via Google API
    • rss — Atom + RSS feed polling with feed-aware caching
    • webhook_poll — GET-and-classify against a webhook
    • google_calendar — calendar event watching
    • agent_turn (Phase 20) — synthetic LLM turn delivered to a channel on cron schedule
  • Extension hooknexo-poller-ext lets third-party extensions register their own poller kinds via the capabilities.pollers manifest field.
  • PollContext.llm_* — every poller has access to the agent's LLM client + tool registry so it can compose agent-driven reactions (e.g. agent_turn).

Public API

pub trait Poller: Send + Sync {
    fn kind(&self) -> &'static str;
    async fn tick(&self, ctx: &PollContext) -> Result<TickOutcome, PollerError>;
}

pub struct PollerRunner { /**/ }

impl PollerRunner {
    pub fn new(state: Arc<dyn PollerStore>) -> Self;
    pub fn register(&self, poller: Arc<dyn Poller>);
    pub fn registered_kinds(&self) -> Vec<&'static str>;
    pub async fn run(&self, cfg: &PollersConfig);
}

Configuration

# config/pollers.yaml
pollers:
  jobs:
    - id: kate-rss-news
      kind: rss
      cron: "*/15 * * * *"
      enabled: true
      args:
        urls: ["https://example.com/rss"]
      delivery:
        agent: kate
        channel: whatsapp
        instance: primary

Install

[dependencies]
nexo-poller = "0.1"

Documentation for this crate

License

Licensed under either of:

at your option.