langbot-plugins

Activity, over time

Daily GitHub activity and social mentions.

Mentions

Daily posts linking to this repository

Loading mentions chart

Attention

Daily stars & forks

Loading attention chart

Star accumulation

Cumulative stars

Loading star accumulation chart

Pull requests

Daily opens & merges

Loading pull requests chart

Conversations

Daily issues & comments

Loading conversations chart

Community

Daily accounts & reviews

Loading community chart

Mentions

5posts · 30d
Nov 50 posts
  1. Zenn · · @rockchinq

    Three Telegram Bot Routes: Welcome, Q&A and Moderation Agents Scenario A Telegram community group has three chores — greet joiners with the two rules, answer "how do I configure this", deal with ad spam on the spot — and today all three ride one bot: one pipeline, one prompt. The welcome matters only at the instant someone joins; rules Q&A faces every ordinary message; kicking and banning never belonged to a Q&A assistant. Merged into one prompt, the model has to guess which situation it is in, and a wrong guess punishes the wrong person. How it works in 4.11 The processor layer gained an Agent option. On 4.10 a bot carried one pipeline, so "speak when someone joins" had to be decided inside it. 4.11 replaces that with event routing: rows of event pattern → processor, where a processor is a pipeline or an Agent. An Agent brings a runner (supplied by a plugin; here langbot-team/LocalAgent) plus a system prompt. Adapters declare which events they emit. Support depends on the adapter and platform — check the support matrix first. One event hits exactly one route. Rows are tried in order: enabled → pattern matches → filters pass → does the target declare support. The first row clearing all four wins and the rest are skipped (official docs docs/event-based-agents/04-event-routing.md §3). Measured 2026-10-16, check-route returned 目标处理器 | Agent · tg-welcome-agent | 命中规则 | 第 2 条路由 | 诊断步骤 | 第 1 条路由已跳过。事件与此路由不匹配。已选择第 2 条路由。第 3 条路由已跳过。事件与此路由不匹配。 — route 2 matched. The event scope decides three things: which events reach the Agent, what the debug dropdown offers, and whether the Agent can be picked as a route processor. Measured 2026-10-16: creating the group.member_joined route offered only tg-welcome-agent and dify-wecomcs-agent; tg-rules-agent and tg-moderation-agent were absent. What the adapter declares is what the menu holds. telegram-omni declares 11 event types, word for word with source LangBot/src/langbot/pkg/platform/adapters/telegram/adapter.py:168-180: message.received, message.edited, message.reaction, group.member_joined, group.member_left, group.member_banned, bot.invited_to_group, bot.removed_from_group, bot.muted, bot.unmuted, platform.specific. So the "add behavior" menu offers four presets (reply to messages, welcome new members, handle departures, handle group moderation) plus "configure another event"; the fifth preset, review friend requests (friend.request_received), is absent because this adapter declares no such event (source LangBot/web/src/app/home/bots/components/bot-form/EventBindingsEditor.tsx:1554-1559, presets at :194-230). The conclusion stops there: the menu follows the declared events, not our judgment about a platform. Hands-on steps Start a local demo instance: docker network create a4 docker run -d --name a4-core --network a4 --restart on-failure -e TZ=Asia/Shanghai \ -e BOXENABLED=false -e SPACEDISABLE_TELEMETRY=true -p 15800:5300 \ -v "$PWD/deploy/a4/data:/app/data" rockchin/langbot:v4.11.0 docker run -d --name a4-runtime --network a4 --network-alias langbot_plugin_runtime --restart on-failure \ -e TZ=Asia/Shanghai -e SPACEDISABLE_TELEMETRY=true -v "$PWD/deploy/a4/data/plugins:/app/data/plugins" \ rockchin/langbot:v4.11.0 uv run --no-sync -m langbot_plugin.cli.init__ rt Admin demo@langbot.local / LangBot411!demo (local demo value — replace with your own). Create the Telegram bot. Bots → New → platform Telegram, paste the BotFather token. This demo uses a placeholder (local demo value — replace with your own), so Telegram never connects; what is verified is where an event is delivered. Detail page /home/bots?id=<uuid> (source LangBot/web/src/app/home/bots/page.tsx:7-8). Read the adapter's event catalog. The panel reports 11 event types; those eleven names bound every menu below. Create three Agents, one event each. Runner LocalAgent (plugin:langbot-team/LocalAgent/default), model deepseek-chat, event scope a single event: tg-welcome-agent → group.member_joined, tg-rules-agent → message.received, tg-moderation-agent → group.member_banned. Prompt and tools for the welcome Agent. A greeting under 60 characters naming the two rules, with "reply to the current conversation" (event_reply) allowed. Run one debug round trip first. On tg-welcome-agent's debug page — its dropdown offers only the event it declares — run group.member_joined with {"member_name": "小林", "member_id": "10086", "group_id": "-1001234567890"}. Measured 2026-10-16: one tool call recorded, tool "reply to the current conversation event_reply", text verbatim: 欢迎语已通过「发送消息」工具发出(模拟投递,未真实调用平台 API): > 欢迎小林加入 LangBot 交流群!🎉 提问请带上 LangBot 版本号,禁止发广告。配置说明可在 GitHub 仓库 docs 目录查看。 (53 字,符合 60 字以内要求:包含欢迎、两条群规与 docs 目录提示。) Only the tools moderation needs. The events-and-tools page reports one event (member banned group.member_banned) and four tools enabled; of 14 platform tools only "kick group member" is checked — event_kick_member → kick_member, risk dangerous (source LangBot/src/langbot/pkg/agent/runner/platform_tools.py:99-203), labelled sensitive in the UI (read/write/dangerous = read-only/action/sensitive; source LangBot/web/src/i18n/locales/zh-Hans.ts:1368-1370). Create the three routes: message.received → tg-rules-agent, group.member_joined → tg-welcome-agent, group.member_banned → tg-moderation-agent. Verify The routes persist. Read back from bots.event_bindings (updated_at 2026-10-16 17:23:44); raw JSON in series/langbot-4.11-release/evidence/demo-test-records.md §8.3: # Event pattern Processor priority enabled route 1 message.received Agent · tg-rules-agent 0 true route 2 group.member_joined Agent · tg-welcome-agent 0 true route 3 group.member_banned Agent · tg-moderation-agent 0 true Dry-run one event. Check-route with "member joined group": target processor | Agent · tg-welcome-agent, matched rule | route 2, diagnostics route 1 skipped, route 2 selected, route 3 skipped. Each route accepts only its own event. Limits and caveats No real Telegram traffic. A local demo token (local demo value — replace with your own) means the verified result is "the configuration took effect and the event routed to the right Agent, which completed one model call", not delivery into a group. Platform tools run under Mock in the debug page, verbatim: "平台工具使用 Mock:Agent 真实调用工具,回复、发送等平台动作模拟执行,不发送真实消息。其他工具仍按实际配置执行。" and "未记录到工具调用;生成文本不代表消息已发送。" Confine dangerous tools. event_kick_member is enabled only for the moderation Agent; on a real platform a kick is immediate. Processor choice depends on the event. A pipeline target binds only message.received (official docs docs/event-based-agents/04-event-routing.md §3); join and ban events need an Agent or a plugin processor. Support depends on the adapter and platform — check the support matrix first. To confirm: one debug round trip was observed, not consecutive turns inside a group; tg-rules-agent's answer quality was not evaluated. [Inference] "two routes may both deliver one event" is outside the measurement — arbitration selects one row (route 2 matched; 1 and 3 skipped). For one event to reach two targets, use the separate plugin-processor path. Summary and next steps Three chores, three Agents, and the glue is rows of event pattern → processor: group.member_joined wakes the welcome Agent, message.received the rules Agent, group.member_banned the moderation Agent. Each scope is one event wide, so nothing else can wake it. Coming from 4.10, start at the v4.11.0 release page; matching details are in docs/event-based-agents/04-event-routing.md; runner plugins live in the langbot-plugins repository. Managed hosting at space.langbot.app is one other option, subject to your deployment constraints.

  2. DEV · · @rockchinq

    QQ friend requests and group invites: two approvals, one Agent Scenario A QQ bot mostly does not chat; it handles two requests: a stranger asks to add it as a friend, or it gets pulled into a group. A pipeline built for "message in → reply out" cannot catch them — they are not messages. On 4.10, OneBot v11 was a protocol adapter reaching protocol ends like NapCat or Lagrange, but every event landed in one pipeline — splitting by event meant writing that logic yourself. 4.11 promotes it to an event-driven adapter, where request events land on an Agent. How it works in 4.11 A new package. src/langbot/pkg/platform/adapters/aiocqhttp/ is a standalone adapter package added in v4.11.0. git diff --stat v4.10.11 v4.11.0 lists, verbatim (source): __init__.py (+5), adapter.py (+243), api_impl.py (+238), event_converter.py (+275), manifest.yaml (+149), message_converter.py (+285), onebot.png, platform_api.py (+84), transport.py (+125), types.py (+9) — eleven files with the old entry point, +1416 / -1. The old config is downgraded. The previous src/langbot/pkg/platform/sources/aiocqhttp.yaml changed by four lines: spec.legacy: true added, spec.categories going from [protocol] to [popular, protocol] (source). So the wizard now generates a reverse-WS URL instead. One event, one row. A bot stores rows of event pattern → processor (a pipeline, an Agent or a plugin processor). Rows are tried in order: enabled → pattern matches → filters pass → target declares the event; the first row clearing all four wins, the rest skipped (official docs docs/event-based-agents/04-event-routing.md §3). The event scope decides the tools. Only friend.request_received brings "处理好友请求", only bot.invited_to_group brings "处理入群邀请". Both carry an event trigger and risk dangerous (source LangBot/src/langbot/pkg/agent/runner/platform_tools.py:176-203). Both act immediately, so never hand them to an Agent that does not need them. Support depends on the adapter and platform — check the support matrix first. Hands-on steps Start a local demo instance: docker network create a4 docker run -d --name a4-core --network a4 --restart on-failure -e TZ=Asia/Shanghai \ -e BOX__ENABLED=false -e SPACE__DISABLE_TELEMETRY=true -p 15800:5300 \ -v "$PWD/deploy/a4/data:/app/data" rockchin/langbot:v4.11.0 docker run -d --name a4-runtime --network a4 --network-alias langbot_plugin_runtime --restart on-failure \ -e TZ=Asia/Shanghai -e SPACE__DISABLE_TELEMETRY=true -v "$PWD/deploy/a4/data/plugins:/app/data/plugins" \ rockchin/langbot:v4.11.0 uv run --no-sync -m langbot_plugin.cli.__init__ rt Admin demo@langbot.local / LangBot411!demo (local demo value — replace with your own). Demo bot QQ 演示机器人, adapter onebot-v11. 1. Step 2 of the wizard: pick OneBot v11. Its card reads, verbatim, "OneBot v11 适配器,用于接入 QQ 兼容协议端,支持事件驱动编排". !Wizard, platform step: OneBot v11 selected 2. Configure the adapter. Mode 反向 WS — 协议端连接 LangBot (protocol end dials LangBot); the protocol-end URL is generated on save; token demo-onebot-token-replace-me (local demo value — replace with your own); expected account 10001; 保存并启用 gives 保存成功 and badge 已启用. Put that URL and token into your own NapCat / Lagrange. !Adapter config: reverse WS, URL, token, expected account 3. Read the event catalog. The routing card reports "共 12 类" — "机器人状态 · 4", "好友 · 2", "群组 · 3", "消息 · 2" and one more; the full list is supported_events in the adapter's manifest.yaml. Support depends on the adapter and platform — check the support matrix first. !Event catalog: 12 event types 4. Route 1 uses the preset 审核好友请求. The "添加行为" menu offers six presets, 回复收到的消息 / 欢迎新成员 / 处理成员离群 / 审核好友请求 / 处理群管理事件 / 配置其他事件, intersected with the adapter's declared events (source LangBot/web/src/app/home/bots/components/bot-form/EventBindingsEditor.tsx:1554-1559), so the preset Telegram filters out survives here; the trigger is 收到好友请求 / friend.request_received. !Add-behavior menu: six presets, one being review friend request 5. Create the Agent inline. 创建新处理器, runner 本地 Agent (plugin:langbot-team/LocalAgent/default), name qq-approvals-agent; on submit, 创建成功, and route 1's processor becomes ⚙️ qq-approvals-agent. !Create-processor dialog: runner Local Agent, name qq-approvals-agent !Route 1: friend request received points at qq-approvals-agent 6. Route 2. 添加行为 → 配置其他事件 → 机器人被邀入群 (bot.invited_to_group), same processor ⚙️ qq-approvals-agent — only Agents declaring the event are offered. !Both routes saved side by side, both pointing at the Agent 7. Pin the Agent's event scope. It starts as one wildcard chip 全部事件 *; the two events replace the wildcard, the card reports "共 2 项", each with three tools: friend.request_received → 回复当前会话(操作)/ 查询事件发起者(只读)/ 处理好友请求(敏感) bot.invited_to_group → 查询事件发起者(只读)/ 查询当前群组(只读)/ 处理入群邀请(敏感) Other-tool counters on that page, verbatim: 平台工具14 沙盒0 MCP0 插件0 已选 0. !Agent event scope: two events, three available tools each Select a model first — this Agent's 模型 reads 请选择模型, so 保存 first pops 运行器配置待完善, then 保存成功. Verify Both rows persist. Read back from bots.event_bindings: | # | Event pattern | Processor | order | enabled | | --- | --- | --- | --- | --- | | route 1 | friend.request_received | Agent · qq-approvals-agent | 0 | true | | route 2 | bot.invited_to_group | Agent · qq-approvals-agent | 1 | true | Both target_uuid values are 69159ec4-3941-4a1a-994f-45c0b532d01d; the bot row has enable=1. Check-route hits twice. Measured 2026-10-16, 检查事件路由 with "收到好友请求": 已命中路由 | 目标处理器 | Agent · qq-approvals-agent | 命中规则 | 第 1 条路由 | 诊断步骤:已选择第 1 条路由。第 2 条路由已跳过。事件与此路由不匹配。 With "机器人被邀入群": 第 1 条路由已跳过。事件与此路由不匹配。已选择第 2 条路由。 Its listbox holds twelve entries, matching the adapter declaration. !Check route: friend request received hits route 1 !Check route: bot invited to group hits route 2 Scope and tools agree. The three tools in step 7 are the source's event-bound group: event_respond_friend_request bound only to friend.request_received, event_respond_group_invite only to bot.invited_to_group. Limits and caveats - No real QQ traffic, and 运行测试 was never run. The instance has no QQ protocol end (no NapCat, no Lagrange), the token is a local demo value (local demo value — replace with your own), and the Agent has no model, so a test run would prove nothing. - Platform tools run under Mock. The note hides in the tooltip of the 事件调试 card's info icon, verbatim: "平台工具使用 Mock:Agent 真实调用工具,回复、发送等平台动作模拟执行,不发送真实消息。其他工具仍按实际配置执行。" !Event-debug card: the platform-tools-use-Mock note as a tooltip - Select a model before saving, otherwise the save reports 运行器配置待完善. - Old config, new home. Reverse WS has the protocol end dial LangBot's main port, with no extra listener; HTTP is unsupported — old host/port config is the legacy adapter now. - A menu entry is not a capability. The menu renders from the adapter declaration — twelve types here, which is why the friend-request preset survives. Support depends on the adapter and platform — check the support matrix first (official docs docs/event-based-agents/01-event-system.md:453-476). - 待确认: verified at the config layer only; no real protocol end was attached, and the approve/reject policy is prompt and model behaviour that was not evaluated. - [Inference] "one event to two processors" was not measured; arbitration selects one row and skips the rest. Summary and next steps Wiring these two approvals is not about a longer prompt. It is two rows of event pattern → processor — friend.request_received and bot.invited_to_group wake the same qq-approvals-agent — and with the scope narrowed to those two, both sensitive tools live on that Agent alone. Coming from 4.10, start at the v4.11.0 release page; the migration map is docs/pipeline-migration-config-map.zh-CN.md; runner plugins live in the langbot-plugins repository. Managed hosting at space.langbot.app is another option.

  3. DEV · · @rockchinq

    One Telegram group, three event routes: welcome, rules Q&A and moderation each get their own Agent Scenario A Telegram community group has three chores — greet joiners with the two rules, answer "how do I configure this", deal with ad spam on the spot — and today all three ride one bot: one pipeline, one prompt. The welcome matters only at the instant someone joins; rules Q&A faces every ordinary message; kicking and banning never belonged to a Q&A assistant. Merged into one prompt, the model has to guess which situation it is in, and a wrong guess punishes the wrong person. How it works in 4.11 The processor layer gained an Agent option. On 4.10 a bot carried one pipeline, so "speak when someone joins" had to be decided inside it. 4.11 replaces that with event routing: rows of event pattern → processor, where a processor is a pipeline or an Agent. An Agent brings a runner (supplied by a plugin; here langbot-team/LocalAgent) plus a system prompt. Adapters declare which events they emit. Support depends on the adapter and platform — check the support matrix first. One event hits exactly one route. Rows are tried in order: enabled → pattern matches → filters pass → does the target declare support. The first row clearing all four wins and the rest are skipped (official docs docs/event-based-agents/04-event-routing.md §3). Measured 2026-10-16, check-route returned 目标处理器 | Agent · tg-welcome-agent | 命中规则 | 第 2 条路由 | 诊断步骤 | 第 1 条路由已跳过。事件与此路由不匹配。已选择第 2 条路由。第 3 条路由已跳过。事件与此路由不匹配。 — route 2 matched. The event scope decides three things: which events reach the Agent, what the debug dropdown offers, and whether the Agent can be picked as a route processor. Measured 2026-10-16: creating the group.member_joined route offered only tg-welcome-agent and dify-wecomcs-agent; tg-rules-agent and tg-moderation-agent were absent. What the adapter declares is what the menu holds. telegram-omni declares 11 event types, word for word with source LangBot/src/langbot/pkg/platform/adapters/telegram/adapter.py:168-180: message.received, message.edited, message.reaction, group.member_joined, group.member_left, group.member_banned, bot.invited_to_group, bot.removed_from_group, bot.muted, bot.unmuted, platform.specific. So the "add behavior" menu offers four presets (reply to messages, welcome new members, handle departures, handle group moderation) plus "configure another event"; the fifth preset, review friend requests (friend.request_received), is absent because this adapter declares no such event (source LangBot/web/src/app/home/bots/components/bot-form/EventBindingsEditor.tsx:1554-1559, presets at :194-230). The conclusion stops there: the menu follows the declared events, not our judgment about a platform. Hands-on steps Start a local demo instance: docker network create a4 docker run -d --name a4-core --network a4 --restart on-failure -e TZ=Asia/Shanghai \ -e BOX__ENABLED=false -e SPACE__DISABLE_TELEMETRY=true -p 15800:5300 \ -v "$PWD/deploy/a4/data:/app/data" rockchin/langbot:v4.11.0 docker run -d --name a4-runtime --network a4 --network-alias langbot_plugin_runtime --restart on-failure \ -e TZ=Asia/Shanghai -e SPACE__DISABLE_TELEMETRY=true -v "$PWD/deploy/a4/data/plugins:/app/data/plugins" \ rockchin/langbot:v4.11.0 uv run --no-sync -m langbot_plugin.cli.__init__ rt Admin demo@langbot.local / LangBot411!demo (local demo value — replace with your own). 1. Create the Telegram bot. Bots → New → platform Telegram, paste the BotFather token. This demo uses a placeholder (local demo value — replace with your own), so Telegram never connects; what is verified is where an event is delivered. Detail page /home/bots?id=<uuid> (source LangBot/web/src/app/home/bots/page.tsx:7-8). !Wizard, platform step: Telegram selected 2. Read the adapter's event catalog. The panel reports 11 event types; those eleven names bound every menu below. !Telegram adapter event catalog: 11 event types 3. Create three Agents, one event each. Runner LocalAgent (plugin:langbot-team/LocalAgent/default), model deepseek-chat, event scope a single event: tg-welcome-agent → group.member_joined, tg-rules-agent → message.received, tg-moderation-agent → group.member_banned. !Agent event scope picker: exactly one event checked 4. Prompt and tools for the welcome Agent. A greeting under 60 characters naming the two rules, with "reply to the current conversation" (event_reply) allowed. !Welcome Agent config: runner, main model and system prompt 5. Run one debug round trip first. On tg-welcome-agent's debug page — its dropdown offers only the event it declares — run group.member_joined with {"member_name": "小林", "member_id": "10086", "group_id": "-1001234567890"}. Measured 2026-10-16: one tool call recorded, tool "reply to the current conversation event_reply", text verbatim: 欢迎语已通过「发送消息」工具发出(模拟投递,未真实调用平台 API): > 欢迎小林加入 LangBot 交流群!🎉 提问请带上 LangBot 版本号,禁止发广告。配置说明可在 GitHub 仓库 docs 目录查看。 (53 字,符合 60 字以内要求:包含欢迎、两条群规与 docs 目录提示。) !Welcome Agent debug output: one tool call and the verbatim reply 6. Only the tools moderation needs. The events-and-tools page reports one event (member banned group.member_banned) and four tools enabled; of 14 platform tools only "kick group member" is checked — event_kick_member → kick_member, risk dangerous (source LangBot/src/langbot/pkg/agent/runner/platform_tools.py:99-203), labelled sensitive in the UI (read/write/dangerous = read-only/action/sensitive; source LangBot/web/src/i18n/locales/zh-Hans.ts:1368-1370). !Moderation Agent events and tools page: only "kick group member" checked 7. Create the three routes: message.received → tg-rules-agent, group.member_joined → tg-welcome-agent, group.member_banned → tg-moderation-agent. !"Add behavior" menu on Telegram: four presets plus "configure another event" Verify The routes persist. Read back from bots.event_bindings (updated_at 2026-10-16 17:23:44); raw JSON in series/langbot-4.11-release/evidence/demo-test-records.md §8.3: | # | Event pattern | Processor | priority | enabled | | --- | --- | --- | --- | --- | | route 1 | message.received | Agent · tg-rules-agent | 0 | true | | route 2 | group.member_joined | Agent · tg-welcome-agent | 0 | true | | route 3 | group.member_banned | Agent · tg-moderation-agent | 0 | true | Dry-run one event. Check-route with "member joined group": target processor | Agent · tg-welcome-agent, matched rule | route 2, diagnostics route 1 skipped, route 2 selected, route 3 skipped. Each route accepts only its own event. !Check route: group.member_joined matches route 2 and points at tg-welcome-agent Limits and caveats - No real Telegram traffic. A local demo token (local demo value — replace with your own) means the verified result is "the configuration took effect and the event routed to the right Agent, which completed one model call", not delivery into a group. - Platform tools run under Mock in the debug page, verbatim: "平台工具使用 Mock:Agent 真实调用工具,回复、发送等平台动作模拟执行,不发送真实消息。其他工具仍按实际配置执行。" and "未记录到工具调用;生成文本不代表消息已发送。" - Confine dangerous tools. event_kick_member is enabled only for the moderation Agent; on a real platform a kick is immediate. - Processor choice depends on the event. A pipeline target binds only message.received (official docs docs/event-based-agents/04-event-routing.md §3); join and ban events need an Agent or a plugin processor. Support depends on the adapter and platform — check the support matrix first. - To confirm: one debug round trip was observed, not consecutive turns inside a group; tg-rules-agent's answer quality was not evaluated. - [Inference] "two routes may both deliver one event" is outside the measurement — arbitration selects one row (route 2 matched; 1 and 3 skipped). For one event to reach two targets, use the separate plugin-processor path. Summary and next steps Three chores, three Agents, and the glue is rows of event pattern → processor: group.member_joined wakes the welcome Agent, message.received the rules Agent, group.member_banned the moderation Agent. Each scope is one event wide, so nothing else can wake it. Coming from 4.10, start at the v4.11.0 release page; matching details are in docs/event-based-agents/04-event-routing.md; runner plugins live in the langbot-plugins repository. Managed hosting at space.langbot.app is one other option, subject to your deployment constraints.

  4. DEV · · @rockchinq

    Upgrading from 4.10 to 4.11: Migrating After the Built-in Runners Were Removed Scenario A 4.10.11 instance runs one pipeline with the built-in local-agent Runner, reached by a bot through a legacy routing rule. Point the same data directory at 4.11.0: tables, data and the old pipeline survive, yet the pipeline is unusable — its Runner points at something 4.11 no longer has and the preview says it needs a plugin. One sentence carries this article: the upgrade has two different paths. The schema migrates automatically through Alembic at boot; Runner configuration moves only through a migration API that requires your explicit confirmation. !Before the upgrade: the 4.10.11 instance with its built-in-Runner pipeline "客服问答流水线" How it works in 4.11 Path one: the schema migrates automatically at boot 4.11 starts from the 4.10.11 data directory and migrates Alembic to head on boot. Measured (2026-10-16): alembic_version moved from 0023_bot_scoped_sessions to 0037_metadata_text — 14 revisions — and the table count became 50. Boot to the first HTTP 200 took about 80 seconds; slow is not stuck, so do not restart early. The key log sequence (measured (2026-10-16), data/logs/): [INFO] : Initializing database type: sqlite... [INFO] : Alembic migrations completed at head. [INFO] : Loading bots from db... [INFO] : Loading pipelines from db... [WARNING] : Pipeline stage ConversationMessageTruncator is not registered; skipping [INFO] : Loading knowledge bases from db... That WARNING is the line most easily misread as a failed migration: per source src/langbot/pkg/pipeline/pipelinemgr.py:838 the record carries a 4.10.11-era stage name that 4.11's registry lacks, so it is skipped and loading continues — startup is not blocked, and the pipeline still completes an end-to-end request (see Verify). Bot routing migrates automatically too: 4.11 drops use_pipeline_name / use_pipeline_uuid / pipeline_routing_rules from bots and adds event_bindings and plugin_processors. Per source src/langbot/pkg/persistence/alembic/versions/0009_migrate_event_bindings.py:1-5, bindings keep the original pipeline UUIDs and the migration never creates Agent rows or copies Pipeline runner configuration; .../0011_drop_legacy_bot_routing.py drops those columns, and .../0035_pipeline_received_only.py narrows message.* to message.received, as the live database shows. So: Alembic decides what tables and routes look like. It does not turn a built-in Runner into a plugin Runner. Path two: Runner configuration moves only with your confirmation The Runner path goes through a dedicated migration API, whose comment is blunt: """User-confirmed migration only; deliberately not API-key/MCP accessible.""" (source src/langbot/pkg/api/http/controller/groups/pipelines/migration.py:1) Both endpoints need USER_TOKEN: GET /api/v1/pipelines/_/migration/preview (Permission.RESOURCE_VIEW, migration.py:17) and POST /api/v1/pipelines/_/migration/execute (Permission.RESOURCE_MANAGE, migration.py:26). Measured preview (2026-10-16): one legacy pipeline, legacy_runner: "local-agent", state needs_plugin with blocker plugin_missing; target plugin langbot-team/LocalAgent 0.2.1 (target_runner_id: plugin:langbot-team/LocalAgent/default), planner_version: "5", changed_paths such as ai.runner.runner and ai.runner.id, and warnings including local.box_state_reset and migration.output_policy_copied (these are the ones recorded in the measurement; the API returns the full list). !Migration preview after upgrading: the legacy pipeline needs a plugin, target plugin langbot-team/LocalAgent 0.2.1 Confirmation is enforced in the protocol, not just the UI: an unconfirmed POST /execute {"items":[]} returns HTTP 400 confirmation_required (source src/langbot/pkg/api/http/service/pipeline_migration.py:131-133); only a request carrying confirmed gets through, for example {"all":true,"confirmed":true,"install_plugins":true} (.../pipeline_migration.py:420-429). Execution archives the old configuration: one row lands in pipeline_migration_snapshots holding the whole pre-migration config as source_snapshot, plus source_fingerprint / target_fingerprint (sha256) and state: active (measured (2026-10-16): 3053 bytes). Note: http_bot is not new in 4.11 (http_bot.py is byte-identical in 4.10.11 and 4.11.0, 27029 bytes), so receiving messages there is preservation, not a new feature. Hands-on steps 0. Copy the data directory The upgrade happens to the data directory; copy it and leave the original untouched: cp -a /path/to/410/data /path/to/411-upgrade/data 1. Start with the 4.11 images Two containers: core and a plugin runtime for Runner plugins. docker network create lang7-411 docker run -d --name lang7-411-core --network lang7-411 --restart on-failure -e TZ=Asia/Shanghai \ -e BOX__ENABLED=false -e SPACE__DISABLE_TELEMETRY=true -p 15400:5300 -p 15480-15485:2280-2285 \ -v "$PWD/deploy/411/data:/app/data" rockchin/langbot:v4.11.0 docker run -d --name lang7-411-runtime --network lang7-411 --network-alias langbot_plugin_runtime --restart on-failure \ -e TZ=Asia/Shanghai -e SPACE__DISABLE_TELEMETRY=true -v "$PWD/deploy/411/data/plugins:/app/data/plugins" \ rockchin/langbot:v4.11.0 uv run --no-sync -m langbot_plugin.cli.__init__ rt Point -v at your copy and adjust names/ports. Wait about 80 seconds after boot for Alembic. Admin admin@langbot.local / LangBot411!demo (local demo value — replace it with your own). 2. Preview, then execute with confirmation Unconfirmed first: {"items":[]} returns 400 confirmation_required. With confirmation, expect 200 carrying pipeline_uuids and task_id: curl -s -X POST -H "Authorization: Bearer <USER_TOKEN>" -H 'Content-Type: application/json' \ -d '{"all":true,"confirmed":true,"install_plugins":true}' \ http://127.0.0.1:15400/api/v1/pipelines/_/migration/execute !Task page after executing the migration: the target plugin is installed and the pipeline reaches its completed state 3. Confirm it landed Expect one row with state = active, planner_version = 5: sqlite3 /path/to/411-upgrade/data/langbot.db \ "select state, planner_version, length(source_snapshot) from pipeline_migration_snapshots;" Verify Prove the migrated pipeline works end to end: POST /bots/<uuid>/sync through the retained http_bot bot: {"query": "只回复两个字:收到"} Signed with HMAC-SHA256 over "{timestamp}." + raw_body_bytes, prefixed sha256=; secret legacy-inbound-secret (local demo value — replace it with your own). Expected response shape (measured (2026-10-16)): {"message":[{"text":"收到","type":"Plain"}],"reply_to":"in_ef4b42dcd79444368c420a053b30f00e"} 4.14 s, over: retained http_bot bot → event binding (message.received) → migrated pipeline (Runner plugin:langbot-team/LocalAgent/default) → local Ollama qwen3:0.6b. !The migrated pipeline's configuration page: the Runner now points at the plugin plugin:langbot-team/LocalAgent/default Re-check: alembic_version = 0037_metadata_text and pipeline_migration_snapshots holds one row with state = active. Limits and caveats - A snapshot is not a rollback button. source_snapshot only archives the pre-migration configuration — no public download, no restore UI (official docs docs/pipeline-migration-config-map.zh-CN.md) — export the database first. - Config migration is not lossless state migration. Remote sessions, history, Box files and form tokens are not imported; expect a state reset (official docs docs/pipeline-migration-config-map.zh-CN.md). - Post-upgrade operations are yours. GET /api/v1/system/info reports wizard_status: "none"; confirm workspace/account availability yourself (here the 4.10 credentials still logged in). - /reset's 500 is pre-existing on both versions, not a migration regression. POST /bots/<uuid>/reset returns HTTP 500 on 4.10.11 and 4.11.0 alike, at source src/langbot/pkg/platform/sources/http_bot.py:373 → :395 (AttributeError: 'HttpBotAdapter' object has no attribute 'ap', identical line numbers). /sync is unaffected. - /sync reply delivery varies by deployment. Here 4.10.11 sent replies as signed callbacks with an empty message array while 4.11 returned the reply in the /sync response — an observed difference whose cause we did not verify; go by your own responses. - The two certification records disagree, so both are reported. install_info._certification reads verification: "invalid" with admission_code: CERTIFIED_PLUGIN_OSS_UNTRUSTED_DEDICATED and certificate_id: null; the marketplace record for the same version reads certificate_status: "issued" with certificate_id: cert:86f25832.... We report the discrepancy and claim no validated signature. - The planner document contradicts itself ("planner v4" early, "relaxed migration rules (planner v5)" later); the preview returns planner_version: "5". - Plugin artifacts land inside the runtime container at /app/data/plugin-runtime/artifacts/sha256/<digest>/code/; the host-mounted plugins/ directory stays empty (measured (2026-10-16)). - Platform capabilities: Support depends on the adapter and platform — check the support matrix first. Summary and next steps Start with the pinned migration document pipeline-migration-config-map.zh-CN.md — where each field goes — and the v4.11.0 release page, covering v4.10.11 → v4.11.0. For how built-in Runners became plugins, continue with this series' Runner-plugins article. To skip self-hosting, check whether the cloud at space.langbot.app suits your scenario (availability depends on your deployment and account — check it yourself; no promise). Plugin sources: langbot-plugins.

  5. DEV · · @rockchinq

    Put Claude Code and Codex Inside WeChat, Lark and DingTalk with LangBot Runner Plugins Scenario A team already lives in Claude Code and Codex — repos, shell, MCP servers on their own machines. Colleagues should reach that same power from WeChat Work, Lark and DingTalk group chats, without a terminal. On 4.10 that was awkward — not inbound: 4.10.11 already ships openclaw_weixin, lark, dingtalk under src/langbot/pkg/platform/sources/. The processing side was the wall: nine built-in runners under src/langbot/pkg/provider/runners/ (localagent.py, difysvapi.py, … weknoraapi.py), so adding Claude Code meant patching LangBot or wrapping the CLI in an HTTP service outside the bot. 4.11 flips that: a Runner is a plugin, and the platform is only the event source. Support depends on the adapter and platform — check the support matrix first. !Runner plugins in the plugin marketplace How it works in 4.11 New in 4.11: the built-in runners are gone. src/langbot/pkg/provider/runners/ holds ten files at v4.10.11 and does not exist at v4.11.0; src/langbot/pkg/provider/ keeps only modelmgr/, session/, tools/ (git ls-tree, both revisions). A Runner is a plugin component. The runtime reports installed plugins' runners over LIST_RUNNERS; the host discovers and caches them in RunnerRegistry (src/langbot/pkg/agent/runner/registry.py:20,24,152), generating ids as plugin:author/plugin_name/runner_name (src/langbot/pkg/agent/runner/id.py:24-27) and rejecting anything without that prefix (id.py:52-57; PROTOCOL_V1.md §13). The manifest is the contract: id, name, label, description, capabilities, permissions, config_schema, metadata (§4.2); capabilities is a typed boolean model for UI and resource projection, not a permission grant, and permissions is the access ceiling, intersected with the binding policy. Official ids: plugin:langbot-team/ClaudeCodeAgent/default, plugin:langbot-team/CodexAgent/default (docs/agent-runner-pluginization/OFFICIAL_RUNNER_PLUGINS.md:33-34). New in 4.11: the adapter layer. src/langbot/pkg/platform/adapters/ is absent at v4.10.11; 4.11 splits it into twelve packages with manifest.yaml, adapter.py, event_converter.py, and the Lark manifest declares kind: MessagePlatformAdapter (src/langbot/pkg/platform/adapters/lark/manifest.yaml:1-4,13). The inbound file inventory is unchanged: between v4.10.11 and v4.11.0, all 22 files under src/langbot/pkg/platform/sources/ are modifications — no additions, no deletions — so no new platform arrived here. Where config lands: ai.runner.id stores the runner id and ai.runner_config[<runner_id>] its settings (src/langbot/templates/metadata/pipeline/ai.yaml:6-18), so switching runners keeps earlier settings. Hands-on steps Runner plugins execute in a separate plugin-runtime container, so this is a two-container setup (local demo values — replace them): docker network create lang7-411 docker run -d --name lang7-411-core --network lang7-411 -e BOX__ENABLED=false \ -p 15400:5300 -v "$PWD/deploy/411/data:/app/data" rockchin/langbot:v4.11.0 docker run -d --name lang7-411-runtime --network lang7-411 --network-alias langbot_plugin_runtime \ -v "$PWD/deploy/411/data/plugins:/app/data/plugins" \ rockchin/langbot:v4.11.0 uv run --no-sync -m langbot_plugin.cli.__init__ rt The admin account starts as admin@langbot.local; the password is a local demo value — replace it. Step 1 — install from the marketplace. UI: Extensions → Extension Marketplace (web/src/i18n/locales/zh-Hans.ts:337-341); CLI: POST /api/v1/plugins/install/marketplace with {plugin_author, plugin_name}, returning {task_id} for task plugin-install-marketplace; the record carries install_source=marketplace (src/langbot/pkg/api/http/controller/groups/plugins.py:923-960). Here we installed langbot-team/LocalAgent; the Claude Code and Codex plugins use the same door (repo langbot-plugins, Runner/claude-code-agent, Runner/codex-agent). Step 2 — confirm where it landed. The artifact is not in the mounted plugins/ directory but inside the runtime container at /app/data/plugin-runtime/artifacts/sha256/<digest>/code/ (manifest.yaml, main.py, pkg/, components/, CERTIFICATION.md), while the host-mounted plugins/ stays empty (observed 2026-10-16); <digest> is the recorded artifact_digest. Three checks: the API (GET /api/v1/plugins returns a {plugins: [...]} array containing it, plugins.py:387-397); the database (a plugin_settings row holding artifact_digest, runtime_revision, install_source, enabled, src/langbot/pkg/entity/persistence/plugin.py:12-35,46-51); and the logs — Mounting plugin langbot-team/LocalAgent... → Initializing Runner component: default → Component default initialized, instance type: DefaultRunner (observed 2026-10-16). The point: the runtime instantiates a component instance and the Runner capability hangs off it. Step 3 — pick the Runner in the pipeline. In the pipeline editor open AI capabilities (web/src/i18n/locales/zh-Hans.ts:1941) and find the stage card labelled "运行方式" (src/langbot/templates/metadata/pipeline/ai.yaml:7-9) with its required "运行器" dropdown (:14-18). The value is the full runner id, e.g. plugin:langbot-team/LocalAgent/default; for Claude Code, plugin:langbot-team/ClaudeCodeAgent/default. Here the LocalAgent block at ai.runner_config[<runner_id>] read timeout: 300, max-tool-iterations: 100 (observed 2026-10-16). Step 4 — connect the chat platform as an event source. Connect a WeChat Work, Lark or DingTalk adapter; events arrive, event bindings route them into a pipeline, and the selected Runner does the work — one bot, several pipelines, each free to use a different Runner. Claude Code and Codex settings come from their READMEs: command defaults to claude / codex, timeout to 300 / 1800 seconds, plus workspace, ssh-target, mcp-servers-json (Runner/claude-code-agent, Runner/codex-agent). !The plugin list after install: LocalAgent 0.2.1 !Runner selection in the pipeline editor Verify API: GET /api/v1/plugins contains langbot-team/LocalAgent with enabled true. Database: digest and revision persisted — values observed here: SELECT plugin_author, plugin_name, artifact_digest, runtime_revision, install_source, enabled FROM plugin_settings; -- langbot-team|LocalAgent|2d2ce17055d70dd7736e6902595be3262992fd1598a00bd9d79d19fef1c16329|1|marketplace|1 Runtime container: the same ls shows the files listed above while the host-mounted plugins/ stays empty; an empty result means the wrong layer. Pipeline: ai.runner.id must start with plugin: (web/src/app/home/pipelines/pipeline-config-safety.ts:7-25) and ai.runner_config must hold an object keyed by that id. Then send a real message and confirm the reply comes from the installed Runner. Limits and caveats - The platform is only an event source. The inbound src/langbot/pkg/platform/sources/ file set matches 4.10.11 — all 22 files are modifications, none added or removed — and what 4.11 adds is the platform/adapters/ event-adapter layer; the adapter plus the event binding decides whether a platform works, not the Runner. The support matrix in 01-event-system.md is a preliminary assessment, per the doc. - Marketplace installs need egress. The archive is fetched from {space_url}/api/v1/marketplace/plugins/download/{author}/{name}/{version} (src/langbot/pkg/plugin/connector.py:1795-1797); installs from GitHub or a local archive record github / local. - Artifacts are content-addressed. The marketplace-side digest need not equal your local one; compare with plugin_settings.artifact_digest — here the two LocalAgent 0.2.1 digests differ (observed 2026-10-16). - The external CLI runners are permissive by default. ClaudeCodeAgent defaults dangerously-skip-permissions to true (false restores Claude Code's own checks; LangBot has no interactive approval flow today) and CodexAgent to approval-policy=never / sandbox-mode=danger-full-access. Trusted workspaces only. - Interaction is not a hanging wait. Both CLI runners turn requests such as ask_user_question into interaction.requested for the adapter to render as a card; the CLI stops while the user answers, and the answer starts a new run resuming the same session. - The harness path is an MVP. The protocol doc states an external harness runner is currently an MVP / dev path: proof the protocol can be wired up, not a release-grade security boundary or finished Docker deployability (PROTOCOL_V1.md §13). - Certification fields can disagree. Here install_info._certification read verification: "invalid" with certificate_id: null, while the marketplace reported certificate_status: "issued" — do not assume local verification passed because a plugin is listed (see article 4). Summary and next steps In 4.11 a Runner is not shipped with LangBot but installed from the marketplace, configured in the app, selected per pipeline. The platform delivers the event; the Runner decides how it is processed — a local CLI agent (Claude Code, Codex, ACP) or a service runner such as Dify, Coze, n8n, Langflow or DeerFlow. Primary reference: the pinned migration doc pipeline-migration-config-map.zh-CN.md, which also lists the minimum Runner plugin versions the migrator requires; the v4.11.0 release page has the notes. Plugins are also listed in Runner/ in langbot-plugins. Next: if your instance was upgraded from 4.10, that old config landing in the new shape is article 3 — the migration touches ai.runner.runner, ai.runner.id and ai.runner_config together. For a hosted environment, Cloud is worth a separate look (https://space.langbot.app).

    5 reactions

Latest stargazers

The last 10 distinct accounts we observed this year.

Most active participants

PR, issue, comment & review events in the past year.

Packages

Scan pending.

Live mentions badge

Show how many posts mention your project in the last 30 days.

Live mentions · last 30 days
langbot-app/langbot-plugins mentions in the last 30 days