npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

openclaw-agent-relay

v3.1.0

Published

Send messages to agents in their existing sessions via gateway WebSocket RPC. The response is delivered to the user (Telegram, etc), not webchat.

Readme

openclaw-agent-relay

Wake agents in their existing sessions via gateway WebSocket RPC. The agent sees your message with full conversation history and responds to the user through their channel (Telegram, Discord, etc).

Think of it as sessions_send that actually delivers the response to the user, not to webchat.

Why

Multi-agent setups need agents to talk to each other: a broker sends a reminder, a scheduler triggers a follow-up, a cron wakes an agent to check on a client. OpenClaw has sessions_send for this — but it doesn't solve the last mile: getting the response to the user.

The sessions_send problem

sessions_send injects a message into another agent's session and preserves conversation history. But the agent's response goes to channel=webchat — an internal channel. The user on Telegram never sees it. #13374 (closed NOT_PLANNED).

Worse, sessions_send can corrupt the target session's delivery context, flipping it from telegram to webchat for all subsequent messages (#44153, #31671).

Known workarounds and why they're fragile

Workaround 1: agent calls message tool explicitly. The target agent sends the response via message with channel: "telegram" and an explicit to/threadId, then returns ANNOUNCE_SKIP. This is the most common community workaround (#47971, #44153, #28603). But it has two problems: you have to embed delivery instructions in every sessions_send payload, and the agent tends to forget to use it. From the agent's perspective, it just received a message and is responding normally — it doesn't know its reply won't reach the user. So it writes a perfectly good response that goes straight to webchat. You can prompt it to call the message tool every time, but it drifts, especially in longer sessions.

Workaround 2: rely on announce step. When sessions_send uses timeout=0, the target agent gets an announce step where it can write a response that gets delivered to Telegram. This technically works — but in practice the model tends to return ANNOUNCE_SKIP instead of writing the actual message. Even with explicit instructions, it "forgets" and skips the announce area. This is a known LLM behavior pattern (#43295) — models generate responses first and check rules second, if at all. You can fight this with very short prompts or runtime enforcement (recallBeforeResponse), but it remains unreliable.

On top of that, announce delivery itself has issues:

  • Drops threadId for Telegram topics (#47971, #45878)
  • Silently fails with multi-channel setups (#47524)
  • ANNOUNCE_SKIP text can leak to the user's Telegram (#45084)

What this plugin does instead

openclaw-agent-relay bypasses sessions_send and announce entirely. It uses the same gateway RPC mechanism as subagent announce (callGateway({ method: "agent" })) to run an agent turn in the existing session with deliver: true. The agent responds normally — no special instructions, no ANNOUNCE_SKIP, no message tool workarounds — and the response goes straight to Telegram.

Install

openclaw plugins install openclaw-agent-relay

Configure

Add to openclaw.json:

{
  plugins: {
    entries: {
      "openclaw-agent-relay": {
        enabled: true,
        config: {
          authToken: "your-secret-token",      // for HTTP endpoint auth
          gatewayToken: "copy-from-gateway.auth.token", // from your openclaw.json
          // port: 18790,        // HTTP endpoint port (default: 18790)
          // gatewayPort: 18789, // gateway WS port (default: 18789)
        }
      }
    }
  }
}

gatewayToken is the same token from gateway.auth.token in your openclaw.json.

Restrict who can wake whom

Use allowedTargets to limit which agents can target which sessions:

{
  plugins: {
    entries: {
      "openclaw-agent-relay": {
        enabled: true,
        config: {
          authToken: "your-secret-token",
          gatewayToken: "copy-from-gateway.auth.token",
          allowedTargets: {
            // wamm can only wake the broker
            "wamm-survey-agent": ["agent:broker:*"],
            // broker can only wake wamm
            "broker": ["agent:wamm-survey-agent:*"]
          }
        }
      }
    }
  }
}

Patterns support trailing :* wildcards. Omit allowedTargets to allow all agents to wake any session.

Usage

Tool: notify_agent

Any agent can call notify_agent as a native tool:

notify_agent({
  sessionKey: "agent:my-agent:telegram:direct:123456",
  message: "Hey, remind the client about the contract"
})

The target agent wakes up in their session, sees the message with full dialogue history, and responds to the user via Telegram.

HTTP: POST /notify

For cron jobs, scripts, or external systems:

curl -X POST http://127.0.0.1:18790/notify \
  -H "Authorization: Bearer your-secret-token" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionKey": "agent:my-agent:telegram:direct:123456",
    "message": "Reminder: client asked for the contract"
  }'

Parameters

| Field | Required | Description | |-------|----------|-------------| | sessionKey | Yes | Target session key (agent:<agentId>:<channel>:<type>:<peerId>) | | message | Yes | Message text (agent sees it as a user message) | | channel | No | Override delivery channel | | to | No | Override delivery recipient |

Example: what happens inside

Broker wakes another agent via tool call

👤 USER (to broker)
"Remind the WAMM client about the rental contract"

🤖 BROKER → tool call
notify_agent({
  sessionKey: "agent:wamm-survey:telegram:direct:647960541",
  message: "Remind the client they requested a rental contract. Ask when is convenient to send it."
})

⚙️ TOOL RESULT
"Agent woken in session agent:wamm-survey:telegram:direct:647960541.
 They will see your message and respond to the user via their channel."

🤖 BROKER
"Done! WAMM agent will remind the client about the contract."

Meanwhile, in the WAMM agent's session (with full conversation history):

... (previous dialogue with client about documents) ...

👤 [injected by relay — agent sees this as a user message]
"Remind the client they requested a rental contract. Ask when is convenient to send it."

🤖 WAMM AGENT → responds in Telegram
"Здравствуйте! Напоминаю — вы просили договор аренды.
 Когда вам удобно его получить? Могу отправить прямо сейчас."

The client sees the message from the WAMM bot in Telegram — not from the broker, not from webchat.

External trigger via HTTP

# Cron job at 9:00 AM
curl -X POST http://127.0.0.1:18790/notify \
  -H "Authorization: Bearer relay-notify-2026" \
  -d '{"sessionKey":"agent:support:telegram:direct:123456",
       "message":"Morning check: any pending tickets from yesterday?"}'

# Response:
{"ok": true, "method": "gateway-rpc"}

# The support agent wakes up in their Telegram session and responds to the user

How it works

  1. Plugin generates an Ed25519 device identity at startup
  2. On /notify or notify_agent call, connects to gateway via WebSocket
  3. Authenticates with challenge-response (device signature + shared token)
  4. Calls method: "agent" with sessionKey, message, deliver: true
  5. Gateway runs an agent turn in the existing session (not isolated)
  6. Agent sees the message with full conversation history
  7. Response is delivered to the user via the session's channel

Falls back to enqueueSystemEvent + requestHeartbeatNow if gateway WebSocket is unavailable.

Comparison

| | sessions_send | notify_agent | |---|---|---| | Agent sees message | Yes | Yes | | Session context preserved | Yes | Yes | | Response to Telegram | No (webchat) | Yes | | Agent formulates response | Yes | Yes | | Available as tool | Yes (built-in) | Yes (plugin) |

License

MIT