---
title: Messengers
description: Receive and reply to Chat SDK messenger webhooks directly from a Think agent, including Telegram setup, routing, conversation targets, and recovery.
image: https://developers.cloudflare.com/dev-products-preview.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/agents/llms.txt  
> Use this file to discover all available pages before exploring further.

[Skip to content](#%5Ftop) 

# Messengers

Use messengers when a Think agent should receive and reply to Chat SDK webhooks directly. Think owns the webhook route, durable reply fiber, conversation routing, and streamed delivery back to the provider.

## Install

Install the Think package and the provider adapter you use:

Terminal window

```

npm install @cloudflare/think agents ai @chat-adapter/telegram


```

Provider adapters are exported from provider-specific subpaths so unused adapters are not bundled into your Worker.

## Telegram

* [  JavaScript ](#tab-panel-5016)
* [  TypeScript ](#tab-panel-5017)

JavaScript

```

import { Think } from "@cloudflare/think";

import {

  defineMessengers,

  ThinkMessengerStateAgent,

} from "@cloudflare/think/messengers";

import telegramMessenger from "@cloudflare/think/messengers/telegram";


export { ThinkMessengerStateAgent };


export class SupportAgent extends Think {

  getMessengers() {

    return defineMessengers({

      telegram: telegramMessenger({

        token: this.env.TELEGRAM_BOT_TOKEN,

        userName: "support_bot",

        secretToken: this.env.TELEGRAM_WEBHOOK_SECRET_TOKEN,

      }),

    });

  }

}


```

TypeScript

```

import { Think } from "@cloudflare/think";

import {

  defineMessengers,

  ThinkMessengerStateAgent,

} from "@cloudflare/think/messengers";

import telegramMessenger from "@cloudflare/think/messengers/telegram";


export { ThinkMessengerStateAgent };


export class SupportAgent extends Think<Env> {

  getMessengers() {

    return defineMessengers({

      telegram: telegramMessenger({

        token: this.env.TELEGRAM_BOT_TOKEN,

        userName: "support_bot",

        secretToken: this.env.TELEGRAM_WEBHOOK_SECRET_TOKEN,

      }),

    });

  }

}


```

With the default `telegram` key, register the Telegram webhook at:

```

https://<your-worker>/messengers/telegram/webhook


```

`telegramMessenger()` requires `secretToken` in webhook mode unless you pass a custom `verifyWebhook` function or explicitly opt out with `verifyWebhook: false`.

If one Think agent owns multiple Telegram bots, give each provider a distinct Chat SDK adapter name:

* [  JavaScript ](#tab-panel-5012)
* [  TypeScript ](#tab-panel-5013)

JavaScript

```

defineMessengers({

  support: telegramMessenger({

    adapterName: "support-telegram",

    token: this.env.SUPPORT_TELEGRAM_BOT_TOKEN,

    userName: "support_bot",

    secretToken: this.env.SUPPORT_TELEGRAM_WEBHOOK_SECRET_TOKEN,

  }),

  sales: telegramMessenger({

    adapterName: "sales-telegram",

    token: this.env.SALES_TELEGRAM_BOT_TOKEN,

    userName: "sales_bot",

    secretToken: this.env.SALES_TELEGRAM_WEBHOOK_SECRET_TOKEN,

  }),

});


```

TypeScript

```

defineMessengers({

  support: telegramMessenger({

    adapterName: "support-telegram",

    token: this.env.SUPPORT_TELEGRAM_BOT_TOKEN,

    userName: "support_bot",

    secretToken: this.env.SUPPORT_TELEGRAM_WEBHOOK_SECRET_TOKEN,

  }),

  sales: telegramMessenger({

    adapterName: "sales-telegram",

    token: this.env.SALES_TELEGRAM_BOT_TOKEN,

    userName: "sales_bot",

    secretToken: this.env.SALES_TELEGRAM_WEBHOOK_SECRET_TOKEN,

  }),

});


```

Duplicate adapter names fail during startup so providers cannot overwrite each other in the shared Chat SDK runtime.

## Routing

The root Think agent handles messenger webhook routes after framework sub-agent routing and Think internal routes, but before user-defined `onRequest` fallback. Messenger routes are root-only. Defining `getMessengers()` on a sub-agent class does not create webhook routes for that sub-agent.

By default, Think replies to direct messages and mentions. New mentions subscribe the Chat SDK thread so later mentions in the same thread are still observed, but ordinary subscribed-thread messages and button actions are ignored unless you opt in:

* [  JavaScript ](#tab-panel-5006)
* [  TypeScript ](#tab-panel-5007)

JavaScript

```

telegramMessenger({

  token: this.env.TELEGRAM_BOT_TOKEN,

  userName: "support_bot",

  secretToken: this.env.TELEGRAM_WEBHOOK_SECRET_TOKEN,

  respondTo: ["direct-message", "mention", "subscribed-thread", "action"],

});


```

TypeScript

```

telegramMessenger({

  token: this.env.TELEGRAM_BOT_TOKEN,

  userName: "support_bot",

  secretToken: this.env.TELEGRAM_WEBHOOK_SECRET_TOKEN,

  respondTo: ["direct-message", "mention", "subscribed-thread", "action"],

});


```

Action events are converted into Think user messages with the action id, value, source message id, and initiating user. Use `getMessengerContext()?.action` inside hooks or tools when you need provider-specific action details. Actions are opt-in so interactive cards do not accidentally trigger model turns.

## Conversation targets

The default conversation mode is one Think sub-agent per Chat SDK thread. This keeps group chats, direct messages, and channels from sharing memory accidentally.

Use the root agent as the conversation when all messenger traffic should share one Think session:

* [  JavaScript ](#tab-panel-5008)
* [  TypeScript ](#tab-panel-5009)

JavaScript

```

telegramMessenger({

  token: this.env.TELEGRAM_BOT_TOKEN,

  userName: "support_bot",

  secretToken: this.env.TELEGRAM_WEBHOOK_SECRET_TOKEN,

  conversation: "self",

});


```

TypeScript

```

telegramMessenger({

  token: this.env.TELEGRAM_BOT_TOKEN,

  userName: "support_bot",

  secretToken: this.env.TELEGRAM_WEBHOOK_SECRET_TOKEN,

  conversation: "self",

});


```

Use a resolver when routing depends on tenant, channel, thread, or user:

* [  JavaScript ](#tab-panel-5014)
* [  TypeScript ](#tab-panel-5015)

JavaScript

```

telegramMessenger({

  token: this.env.TELEGRAM_BOT_TOKEN,

  userName: "support_bot",

  secretToken: this.env.TELEGRAM_WEBHOOK_SECRET_TOKEN,

  conversation(event) {

    return {

      target: "subagent",

      name: `tenant:${event.thread.channelId ?? event.thread.id}`,

    };

  },

});


```

TypeScript

```

telegramMessenger({

  token: this.env.TELEGRAM_BOT_TOKEN,

  userName: "support_bot",

  secretToken: this.env.TELEGRAM_WEBHOOK_SECRET_TOKEN,

  conversation(event) {

    return {

      target: "subagent",

      name: `tenant:${event.thread.channelId ?? event.thread.id}`,

    };

  },

});


```

## State

Messenger state is backed by `agents/chat-sdk`. Export `ThinkMessengerStateAgent` from the Worker module so sub-agent routing can resolve it. Production applications do not need a separate Durable Object binding or migration for this facet-only state class. Test harnesses may still need explicit bindings.

## Delivery and recovery

Think replies with the streamed `chat()` path. The root agent starts an idempotent managed fiber, resolves the conversation target, calls `target.chat(message, callback)`, and lets the provider delivery policy post or edit visible messages.

Recovery snapshots store only serializable event and Chat SDK thread data. If a restart happens before streaming starts, Think can replay the answer. If a restart happens after streaming starts, Think posts the configured interruption message instead of risking a duplicate partial answer.

Delivery errors use a generic user-facing message by default so internal exception details are not posted into external chats. Override `delivery.errorResponseText` when you want a custom safe message.

## Messenger context

During a messenger turn, `getMessengerContext()` returns provider, thread, author, message, capabilities, and attachment metadata for the initiating event. Use it from prompts, tools, or hooks that need channel-specific behavior.

* [  JavaScript ](#tab-panel-5010)
* [  TypeScript ](#tab-panel-5011)

JavaScript

```

const messenger = this.getMessengerContext();

if (messenger?.thread.isDirectMessage === false) {

  // Adjust behavior for group chats.

}


```

TypeScript

```

const messenger = this.getMessengerContext();

if (messenger?.thread.isDirectMessage === false) {

  // Adjust behavior for group chats.

}


```

## Custom Chat SDK adapters

Use `chatSdkMessenger()` for providers that do not have a Think helper yet:

* [  JavaScript ](#tab-panel-5018)
* [  TypeScript ](#tab-panel-5019)

JavaScript

```

chatSdkMessenger({

  adapter,

  provider: "custom",

  userName: "custom_bot",

  verifyWebhook(request) {

    return request.headers.get("x-custom-signature") === expectedSignature;

  },

});


```

TypeScript

```

chatSdkMessenger({

  adapter,

  provider: "custom",

  userName: "custom_bot",

  verifyWebhook(request) {

    return request.headers.get("x-custom-signature") === expectedSignature;

  },

});


```

Every custom messenger must provide `verifyWebhook` or explicitly use `verifyWebhook: false`.

## Advanced manual ingress

The `examples/think-chat-sdk` example demonstrates the Think-native `getMessengers()` path with a small Vite dashboard that inspects the root Think conversation over the Agent WebSocket.

The `examples/chat-sdk-messenger` example demonstrates a larger manual ingress agent with an admin dashboard, menu handling, and application-owned reply fibers. Use `getMessengers()` for the simple Think-native path. Use the example when you need to own the Chat SDK runtime and control-plane UI yourself. Refer to [Chat SDK state](https://developers.cloudflare.com/agents/runtime/execution/chat-sdk/) for the underlying state adapter.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/agents/","name":"Agents"}},{"@type":"ListItem","position":3,"item":{"@id":"/agents/harnesses/","name":"Harnesses"}},{"@type":"ListItem","position":4,"item":{"@id":"/agents/harnesses/think/","name":"Think"}},{"@type":"ListItem","position":5,"item":{"@id":"/agents/harnesses/think/messengers/","name":"Messengers"}}]}
```
