Chat Plugin
Manage Bot Accounts in Desktop and reliably route external conversations to Agent Sessions
Chat Plugin
Chat Plugin 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 Channels 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 Channel. 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 and Workspace for new Conversations
- Access requests and grants for external identities
- each Conversation's Agent, Workspace, 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 Plugin Config.
{
"accounts": [
{
"account_id": "support-telegram",
"name": "Support Bot",
"provider": "telegram",
"enabled": true,
"agent_id": "support",
"workspace_id": "support-workspace",
"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 a real Agent Session. Session Messages remain the only complete conversation history; the Chat database does not duplicate it.
Platform → Access → Inbox → Conversation → Agent Session
→ Outbox → PlatformInbox 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 routelist: list Conversations owned by the current Agenthistory: read canonical Agent Session messagessend: persist text to the reliable Outboxreact: persist a Telegram message reaction to the reliable Outbox
SDK assembly
import { ChatPlugin } from "@downcity/plugins/chat";
const city = new City({
plugins: [new ChatPlugin()],
workspaces: [workspace],
plugin_host,
});The City host provides Plugin Config, lifecycle Storage, and Agent/Workspace lookup. 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.3Scan 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.