Build, refactor, and test LangBot platform adapters for the Event-Based Agents architecture. Use when adding or migrating Telegram, Discord, or other messaging platform adapters to the EBA adapter layout, validating unified event/message conversion, writing live adapter probes, or using standalone plugin runtime plus Computer Use for end-to-end platform testing.
73
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Use this skill when implementing or reviewing a LangBot platform adapter under the Event-Based Agents architecture.
Beyond writing code, you can drive a live LangBot instance over MCP — no raw
HTTP needed. Two MCP servers exist (both reuse existing API keys; see AGENTS.md):
http://<host>:5300/mcp (auth: web-UI lbk_ key or the
api.global_api_key from config.yaml). Manage bots, pipelines, models,
knowledge bases, and skills. See the langbot-mcp-ops skill.https://space.langbot.app/mcp (auth: Personal
Access Token). Search plugins / MCP servers / skills. See the
langbot-space-ops skill.Any change to an agent-accessible HTTP API endpoint must keep the matching MCP tool and these skills in sync.
Do not let platform-native event or message shapes leak into LangBot's common path. Each adapter must convert incoming SDK objects into unified EBA entities before dispatch:
langbot_plugin.api.entities.builtin.platform.eventslangbot_plugin.api.entities.builtin.platform.message.MessageChainlangbot_plugin.api.entities.builtin.platform.entitiessource_platform_object for debugging or platform-specific escape hatches.LangBot/docs/event-based-agents/.LangBot/docs/event-based-agents/adapters/acceptance-checklist.mdLangBot/src/langbot/pkg/platform/adapters/telegram/LangBot/docs/event-based-agents/adapters/telegram.mdLangBot/src/langbot/pkg/platform/sources/<platform>.pyLangBot/src/langbot/pkg/platform/sources/<platform>.yamllangbot-plugin-sdk/src/langbot_plugin/api/entities/builtin/platform/.Create one directory per adapter:
LangBot/src/langbot/pkg/platform/adapters/<platform>/
├── __init__.py
├── adapter.py
├── api_impl.py
├── event_converter.py
├── manifest.yaml
├── message_converter.py
├── platform_api.py
├── types.py
└── <platform>.svgAdd optional helpers such as voice.py only when the platform has a real domain-specific surface.
Ensure pyproject.toml package data includes adapter assets:
package-data = { "langbot" = ["templates/**", "pkg/platform/sources/*", "pkg/platform/adapters/**", ...] }manifest.yaml declares metadata.name, config schema, supported events, common APIs, and platform-specific APIs.adapter.py creates the platform client, subscribes to native events, filters self/bot loops where appropriate, calls event_converter.target2yiri(...), then dispatches the EBA event.event_converter.py maps native events to EBA event classes such as MessageReceivedEvent, MessageEditedEvent, MessageDeletedEvent, MessageReactionEvent, MemberJoinedEvent, BotInvitedToGroupEvent, and PlatformSpecificEvent.message_converter.py maps native messages to MessageChain, and maps MessageChain back to the platform send format.api_impl.py implements common EBA APIs: send, reply, edit, delete, forward, user/group/member lookup, moderation, upload/file URL, leave group.platform_api.py keeps platform-specific calls behind call_platform_api(action, params).NotSupportedError; do not silently no-op.For message events, the common shape should look like this regardless of platform:
platform_events.MessageReceivedEvent(
type="message.received",
adapter_name="<platform>",
message_id=<platform_message_id>,
message_chain=platform_message.MessageChain([...]),
sender=platform_entities.User(...),
chat_type=platform_entities.ChatType.PRIVATE or ChatType.GROUP,
chat_id=<conversation_or_channel_id>,
group=platform_entities.UserGroup(...) or None,
source_platform_object=<raw_object>,
)Message content should use common components:
Source for original message id/time when available.Plain for text.At / AtAll for mentions.Image, Voice, File for media.Forward only when the platform can represent or emulate it safely.If a platform event cannot cleanly map to a common event, emit PlatformSpecificEvent with a compact action and structured data.
Add focused tests under LangBot/tests/unit_tests/platform/test_<platform>_eba_adapter.py.
Cover at least:
supported_events().supported_apis().SourcePlainAtAtAllImageVoiceFileQuoteFaceForwardUnknownMessageResult.Run the existing reference adapter tests too:
cd LangBot
uv run pytest tests/unit_tests/platform/test_<platform>_eba_adapter.py tests/unit_tests/platform/test_telegram_eba_adapter.py
uv run python -m py_compile tests/e2e/live_<platform>_eba_probe.py
git diff --checkDirect adapter live probes are useful diagnostics, but they are not sufficient acceptance evidence for EBA. Treat tests/e2e/live_<platform>_eba_probe.py as an auxiliary tool only. The final adapter record must distinguish:
plugin-e2e-ui: real SDK plugin through standalone runtime, LangBot core, adapter, and a real/simulator UI action. This can mark an inbound UI item complete.plugin-e2e-protocol: real SDK plugin through standalone runtime, LangBot core, adapter, and a protocol-boundary injected event. This is useful evidence but must not be claimed as UI coverage.plugin-e2e-outbound: real SDK plugin calls an API and the bot output is visible in the real/simulator UI. This can mark send/API coverage complete.adapter-live: direct adapter probe connected to a real/simulator endpoint. This is auxiliary only.unit: mocked conversion/API-shape coverage. This is auxiliary only.not-supported: platform protocol or SDK has no equivalent. Must include the reason.blocked: intended capability could not be verified. This is not complete.Write a live probe in LangBot/tests/e2e/live_<platform>_eba_probe.py. It should:
LangBot/data/temp/.call_platform_api actions.Use Computer Use when the user asks for real platform end-to-end coverage. Actually send messages/click reactions in the platform UI or otherwise trigger real user-side events; do not replace that with unit tests.
For media/component acceptance, keep the direction and trigger source explicit:
send_message/adapter send conversion. It does not prove inbound conversion.plugin-e2e-protocol, but it must not be reported as UI-level end-to-end media upload.blocked with the exact client/simulator limitation.When validating the whole LangBot EBA path, test with the SDK standalone runtime and a real test plugin. This is the required acceptance path; direct adapter calls do not prove the EBA architecture path.
The required path is:
Real platform / simulator UI
-> platform SDK native event
-> adapter event converter
-> unified EBA event/entity/message types
-> LangBot core event dispatch
-> standalone SDK runtime
-> real test plugin listener
-> plugin calls platform APIs through SDK
-> LangBot core API dispatch
-> adapter API implementation
-> real platform / simulator UITypical shape:
# Terminal 1, SDK repo
cd langbot-plugin-sdk
uv run python -m langbot_plugin.cli.__init__ rt \
--debug-only \
--ws-control-port 5400 \
--ws-debug-port 5401 \
--skip-deps-check
# Terminal 2, LangBot repo
cd LangBot
export PYTHONPATH=/absolute/path/to/langbot-plugin-sdk/src:${PYTHONPATH:-}
uv run main.py --standalone-runtime
# Terminal 3, plugin directory
export DEBUG_RUNTIME_WS_URL=ws://127.0.0.1:5401/plugin/ws
export EBA_PROBE_LOG=/absolute/path/to/LangBot/data/temp/<platform>_eba_plugin_probe.jsonl
export EBA_PROBE_API=1
export EBA_PROBE_COMPONENT_SWEEP=1
export EBA_PROBE_PLATFORM_API=1
uv --project /absolute/path/to/langbot-plugin-sdk run python -m langbot_plugin.cli.__init__ runUse an EBA probe plugin that subscribes to all relevant EBA event classes and runs SDK API calls after the first MessageReceived.
The plugin evidence should be JSONL and include:
event.typebot_uuid and adapter_name, proving LangBot filled common routing fields before plugin dispatchmessage_chain component listFor full adapter acceptance, enable both probe sweeps:
EBA_PROBE_COMPONENT_SWEEP=1 sends the required outbound message components through send_message.EBA_PROBE_PLATFORM_API=1 calls common safe APIs plus selected call_platform_api actions for the adapter.The SDK must support plugin.call_platform_api(bot_uuid, action, params) for platform-specific acceptance. If the SDK cannot call a platform-specific action from the plugin, the adapter cannot be fully accepted even if direct adapter probes pass.
Before marking an adapter migrated, fill out an adapter record against LangBot/docs/event-based-agents/adapters/acceptance-checklist.md.
At minimum, the record must cover these categories:
plugin-e2e-ui: Source, Plain, At, AtAll, Image, Voice, File, Quote, Face, Forward, Unknown, and mixed chains where the platform supports them. Protocol-only receive evidence must be labelled plugin-e2e-protocol.plugin-e2e-outbound: Plain, At, AtAll, Image, Voice, File, Quote, Face, Forward, and mixed chains where the platform supports them.manifest.yaml -> spec.supported_events.manifest.yaml -> spec.supported_apis.required and optional.manifest.yaml -> spec.platform_specific_apis.source_platform_object reply/debug behavior.Do not declare an event or API in the manifest unless it has an implementation path and an acceptance entry. If a platform or simulator lacks a capability, document it as not-supported or blocked rather than silently omitting the test.
get_bots() may return bot dictionaries, not UUID strings. Probe plugins should select an enabled dict and pass bot["uuid"] to get_bot_info() and send_message().MessageDeleted subscription can make a working adapter look untested.message.received loops, but do not accidentally filter edit/delete events needed for bot-owned API probes.upload_file API may need to be NotSupportedError.leave_group is tested, run it last because the test bot will be removed from the server/group.Add or update LangBot/docs/event-based-agents/adapters/<platform>.md in the same style as Telegram:
call_platform_api action list.Be honest. Put untested or skipped APIs in the document with the reason. Do not imply full parity when a platform cannot provide the same information density.
git diff --check.7803d56
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.