Messenger Power

Manage Bot Accounts in Desktop and reliably route external conversations to Agent Sessions

Messenger Power is a channel runtime owned by City. It does not belong to an individual Agent and does not expose long-lived state through context.agent.chat.

Desktop workflow

Open Messengers to see every Bot Account in a dedicated Sidebar. Use the plus button in the Sidebar header and choose Telegram, Feishu/Lark, or QQ from the dropdown to create a Bot Account. You can add multiple bots for the same provider. Feishu/Lark defaults to scan sign-in, so you never have to paste an App ID or App Secret.

Selecting an Account lets you manage:

  • enabled state, credentials, connection tests, and reconnects
  • the default Agent for new Conversations
  • Access requests and grants for external identities
  • each Conversation's Agent, Channel Session, and paused state
  • Inbox and Outbox items that exceeded automatic retry limits
  • Activity records that exclude message bodies and secrets

Desktop applies Account saves immediately. It restarts only that Account's Connector, so Desktop, City, and other Bot Accounts do not need to restart. Credentials can be entered in Settings. Stored secrets are never echoed; leave a secret field empty to preserve its current value.

Account configuration

Account definitions and credentials have one source of truth: City Power Config.

{
  "accounts": [
    {
      "account_id": "support-telegram",
      "name": "Support Bot",
      "provider": "telegram",
      "enabled": true,
      "agent_id": "support",
      "bot_token": "<telegram-bot-token>"
    }
  ]
}

Feishu/Lark accounts use app_id, app_secret, and optional domain. QQ accounts use app_id, app_secret, and optional sandbox.

Adding a Feishu/Lark Channel in Desktop defaults to scan sign-in. Click Scan to create, scan the QR code with Feishu, and confirm on your phone; the App ID and App Secret are written automatically and the Account starts immediately, so nothing has to be copied from the Open Platform. The confirmation page is pre-filled with an app name and description, and pre-selects the scopes this channel needs together with the im.message.receive_v1 event.

Scan sign-in uses the OAuth 2.0 Device Authorization Grant (RFC 8628) and can only create a new app, so it never overwrites an existing app's configuration. QR code lifetime follows the platform response (currently about one hour), and you can regenerate it after it expires. When scanning is not possible, such as when the organization has not enabled developer access or you want to reuse an existing app, switch to Manual credentials on the same page.

Messages and Sessions

An allowed external message is persisted to Inbox, then routed through a Conversation to its own Channel Session (origin.type = "channel"). Each chat and thread under a Bot Account has a separate Session that subsequent messages reuse. Histories are separate from other chats and from the Agent's main conversation. Session Messages remain the only complete conversation history.

IM routing binds only an Agent and requires no Workspace selection. In Desktop, Channel Sessions and the Agent's main conversation default to the same main Workspace (agents/<agent_id>/main), with the same Workspace tools, Powers, custom Agent tools, and Session management tools. Histories remain separate. Files and Shell use the current Workspace; Session management tools can create project Work Sessions. SDK hosts supply the default main context through the Agent's workspace option. An unconfigured Agent is selected automatically only when City has exactly one Agent.

Changing a Conversation's Agent or resetting it creates a new Channel Session and preserves the previous Session. Existing IM Work Sessions are also preserved during upgrade; chats continue in newly created Channel Sessions. Received attachments live in Messenger storage; outgoing attachments may use that storage and the Session's current project directory.

Platform → Access → Inbox → Conversation → Channel Session
         → Outbox → Platform

Inbox deduplicates provider message IDs and prompts Session with a stable request_id. If the process exits after the User Message is committed, recovery does not append a second User Message. Agent results use stable Delivery IDs when entering Outbox, preventing duplicate jobs during recovery.

Outbox provides persistence, leases, bounded retries, and manual recovery. When a provider has no idempotent send protocol, external delivery is at-least-once: a crash after provider acceptance but before local acknowledgement can cause a repeated send.

Agent Actions

An Agent can only access Conversations it owns through strict actions:

  • context: read the current Chat Session route
  • list: list Conversations owned by the current Agent
  • history: read canonical Agent Session messages
  • send: persist text to the reliable Outbox
  • react: persist a Telegram message reaction to the reliable Outbox

SDK assembly

import { MessengerPower } from "@downcity/powers/messenger";

const city = new City({
  powers: [new MessengerPower()],
  workspaces: [workspace],
  power_host,
});

The City host provides Power Config, lifecycle Storage, and Agent Session capabilities. Connectors are restored during initialize() and closed together during dispose().

Feishu dependency

A host that enables a Feishu/Lark Account must install:

npm install @larksuiteoapi/node-sdk@^1.73.3

Scan sign-in relies on the SDK's registerApp and requires ^1.67.0 or later. On older versions the scan entry reports that an upgrade is needed, while manual credentials keep working.