mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-26 12:26:38 -06:00
d8ebe85c24
* refactor(line): replace nine-marker prompt DSL with typed rich messages Delete the LINE plugin's double-bracket marker language (quick_replies, location, confirm, buttons, media_player, event, agenda, device, appletv_remote) and its parser. Portable interactions now flow through the existing presentation-block seam (renderPresentation, matching Discord and Feishu); LINE-specific cards ride closed channelData.line schemas mapped to the existing Flex renderers. Prompt section shrinks to four capability lines and explicitly de-fangs marker text. Removes the stale assertion-safety baseline entry for the deleted parser. Production LOC net -69, tests net -433. Suite: 510/510 green. * fix(line): declare rich message schema dependency * fix(line): satisfy rich message type checks * docs(line): mark card fragments as partial
296 lines
9.7 KiB
Markdown
296 lines
9.7 KiB
Markdown
---
|
|
summary: "LINE Messaging API plugin setup, config, and usage"
|
|
read_when:
|
|
- You want to connect OpenClaw to LINE
|
|
- You need LINE webhook + credential setup
|
|
- You want LINE-specific message options
|
|
title: LINE
|
|
---
|
|
|
|
LINE connects to OpenClaw via the LINE Messaging API. The plugin runs as a webhook
|
|
receiver on the Gateway and uses your channel access token + channel secret for
|
|
authentication.
|
|
|
|
Status: official plugin, installed separately. Direct messages, group chats, media,
|
|
locations, Flex messages, template messages, and quick replies are supported.
|
|
Reactions and threads are not supported.
|
|
|
|
## Install
|
|
|
|
Install LINE before configuring the channel:
|
|
|
|
```bash
|
|
openclaw plugins install @openclaw/line
|
|
```
|
|
|
|
Local checkout (when running from a git repo):
|
|
|
|
```bash
|
|
openclaw plugins install ./path/to/local/line-plugin
|
|
```
|
|
|
|
## Setup
|
|
|
|
1. Create a LINE Developers account and open the Console:
|
|
[https://developers.line.biz/console/](https://developers.line.biz/console/)
|
|
2. Create (or pick) a Provider and add a **Messaging API** channel.
|
|
3. Copy the **Channel access token** and **Channel secret** from the channel settings.
|
|
4. Enable **Use webhook** in the Messaging API settings.
|
|
5. Set the webhook URL to your gateway endpoint (HTTPS required):
|
|
|
|
```text
|
|
https://gateway-host/line/webhook
|
|
```
|
|
|
|
The Gateway answers LINE's webhook verification (GET). For signed inbound events
|
|
(POST), it writes each event to the durable ingress queue before returning `200`;
|
|
agent processing continues asynchronously. Failed delivery is retried from the
|
|
queue, including after a Gateway restart, and poison events become failed queue
|
|
records after bounded retries. If durable persistence fails, the request returns
|
|
`500` instead of acknowledging an event that could be lost.
|
|
Delivery is at least once across the queue-to-agent boundary: a Gateway shutdown or
|
|
crash during an active delivery can replay the turn. Message events deduplicate by
|
|
LINE message ID; other event types use `webhookEventId`. Retained completion records
|
|
suppress ordinary duplicate webhooks, but handlers that perform external side effects
|
|
should still be idempotent.
|
|
If you need a custom path, set `channels.line.webhookPath` or
|
|
`channels.line.accounts.<id>.webhookPath` and update the URL accordingly.
|
|
|
|
Security notes:
|
|
|
|
- LINE signature verification is body-dependent (HMAC over the raw body), so OpenClaw applies a strict pre-auth body limit (64 KB) and read timeout before verification.
|
|
- OpenClaw processes webhook events from the verified raw request bytes. Upstream middleware-transformed `req.body` values are ignored for signature-integrity safety.
|
|
|
|
## Configure
|
|
|
|
Minimal config:
|
|
|
|
```json5
|
|
{
|
|
channels: {
|
|
line: {
|
|
enabled: true,
|
|
channelAccessToken: "LINE_CHANNEL_ACCESS_TOKEN",
|
|
channelSecret: "LINE_CHANNEL_SECRET",
|
|
dmPolicy: "pairing",
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Public DM config:
|
|
|
|
```json5
|
|
{
|
|
channels: {
|
|
line: {
|
|
enabled: true,
|
|
channelAccessToken: "LINE_CHANNEL_ACCESS_TOKEN",
|
|
channelSecret: "LINE_CHANNEL_SECRET",
|
|
dmPolicy: "open",
|
|
allowFrom: ["*"],
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Env vars (default account only):
|
|
|
|
- `LINE_CHANNEL_ACCESS_TOKEN`
|
|
- `LINE_CHANNEL_SECRET`
|
|
|
|
Token/secret files:
|
|
|
|
```json5
|
|
{
|
|
channels: {
|
|
line: {
|
|
tokenFile: "/path/to/line-token.txt",
|
|
secretFile: "/path/to/line-secret.txt",
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
`tokenFile` and `secretFile` must point to regular files. Symlinks are rejected.
|
|
Inline config values win over files; env vars are the last fallback for the default account.
|
|
|
|
Multiple accounts:
|
|
|
|
```json5
|
|
{
|
|
channels: {
|
|
line: {
|
|
accounts: {
|
|
marketing: {
|
|
channelAccessToken: "...",
|
|
channelSecret: "...",
|
|
webhookPath: "/line/marketing",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
## Access control
|
|
|
|
Direct messages default to pairing. Unknown senders get a pairing code and their
|
|
messages are ignored until approved:
|
|
|
|
```bash
|
|
openclaw pairing list line
|
|
openclaw pairing approve line <CODE>
|
|
```
|
|
|
|
Allowlists and policies:
|
|
|
|
- `channels.line.dmPolicy`: `pairing | allowlist | open | disabled` (default `pairing`)
|
|
- `channels.line.allowFrom`: allowlisted LINE user IDs for DMs; `dmPolicy: "open"` requires `["*"]`
|
|
- `channels.line.groupPolicy`: `allowlist | open | disabled` (default `allowlist`)
|
|
- `channels.line.groupAllowFrom`: allowlisted LINE user IDs for groups; DM `allowFrom` entries do not admit group senders
|
|
- Per-group overrides: `channels.line.groups.<groupId>.allowFrom` (plus `enabled`, `requireMention`, `systemPrompt`, `skills`). With
|
|
`groupPolicy: "allowlist"`, set `groupAllowFrom` or the per-group `allowFrom`; an empty group allowlist blocks group messages even when DMs are open.
|
|
- Static sender access groups can be referenced from `allowFrom`, `groupAllowFrom`, and per-group `allowFrom` with `accessGroup:<name>`; see [Access groups](/channels/access-groups).
|
|
- Runtime note: if `channels.line` is completely missing, runtime falls back to `groupPolicy="allowlist"` for group checks (even if `channels.defaults.groupPolicy` is set).
|
|
|
|
LINE IDs are case-sensitive. Valid IDs look like:
|
|
|
|
- User: `U` + 32 hex chars
|
|
- Group: `C` + 32 hex chars
|
|
- Room: `R` + 32 hex chars
|
|
|
|
## Message behavior
|
|
|
|
- Text is chunked at 5000 characters.
|
|
- Markdown formatting is stripped; code blocks and tables are converted into Flex
|
|
cards when possible.
|
|
- Streaming responses are buffered; LINE receives full chunks with a loading
|
|
animation while the agent works.
|
|
- Media downloads are capped by `channels.line.mediaMaxMb` (default 10).
|
|
- Inbound media is saved under `~/.openclaw/media/inbound/` before it is passed
|
|
to the agent, matching the shared media store used by other channel plugins.
|
|
|
|
## Structured rich messages
|
|
|
|
Use the shared message presentation fields for portable choices. LINE renders
|
|
`buttons` blocks as Flex controls and `select` blocks as quick replies. A two-button
|
|
block is the portable confirm-style form.
|
|
|
|
```json5
|
|
{
|
|
action: "send",
|
|
message: "Choose an action",
|
|
presentation: {
|
|
title: "Menu",
|
|
blocks: [
|
|
{
|
|
type: "buttons",
|
|
buttons: [
|
|
{ label: "Status", action: { type: "command", command: "/status" } },
|
|
{ label: "Website", action: { type: "url", url: "https://example.com" } },
|
|
],
|
|
},
|
|
{
|
|
type: "select",
|
|
placeholder: "Pick one",
|
|
options: [
|
|
{ label: "Alpha", action: { type: "callback", value: "alpha" } },
|
|
{ label: "Help", action: { type: "command", command: "/help" } },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
}
|
|
```
|
|
|
|
LINE-only output uses the schema-validated `channelData.line` fields on
|
|
`message(action="send")`. Send one location and/or one `card`. The supported card
|
|
types are `media_player`, `event`, `agenda`, `device`, and `appletv_remote`.
|
|
|
|
```json5
|
|
{
|
|
action: "send",
|
|
message: "Here you go",
|
|
channelData: {
|
|
line: {
|
|
location: {
|
|
title: "Office",
|
|
address: "123 Main St",
|
|
latitude: 35.681236,
|
|
longitude: 139.767125,
|
|
},
|
|
card: {
|
|
type: "event",
|
|
title: "Team meeting",
|
|
date: "2026-08-18",
|
|
time: "10:00",
|
|
location: "Conference room",
|
|
description: "Weekly planning",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Other card shapes:
|
|
|
|
```json5 validate=false
|
|
{ type: "media_player", title: "Song", artist: "Artist", source: "Living Room", status: "playing", imageUrl: "https://example.com/cover.jpg" }
|
|
{ type: "agenda", title: "Today", events: [{ title: "Standup", time: "09:00", location: "Online" }] }
|
|
{ type: "device", name: "TV", deviceType: "Streaming box", status: "Playing", controls: [{ label: "Pause", action: "pause" }] }
|
|
{ type: "appletv_remote", name: "Living Room", status: "Playing" }
|
|
```
|
|
|
|
Double-bracket strings such as `[[buttons: ...]]` are plain text and are not
|
|
interpreted as rich-message instructions.
|
|
|
|
The LINE plugin also ships a `/card` command for Flex message presets:
|
|
|
|
```text
|
|
/card info "Welcome" "Thanks for joining!"
|
|
```
|
|
|
|
## ACP support
|
|
|
|
LINE supports ACP (Agent Communication Protocol) conversation bindings:
|
|
|
|
- `/acp spawn <agent> --bind here` binds the current LINE chat to an ACP session without creating a child thread.
|
|
- Configured ACP bindings and active conversation-bound ACP sessions work on LINE like other conversation channels.
|
|
|
|
See [ACP agents](/tools/acp-agents) for details.
|
|
|
|
## Outbound media
|
|
|
|
The LINE plugin sends images, videos, and audio through the agent message tool:
|
|
|
|
- **Images**: sent as LINE image messages; the preview image defaults to the media URL.
|
|
- **Videos**: require a preview image; set `channelData.line.previewImageUrl` to an image URL.
|
|
- **Audio**: sent as LINE audio messages; duration defaults to 60 seconds unless `channelData.line.durationMs` is set.
|
|
|
|
The media kind is taken from `channelData.line.mediaKind` when set, otherwise inferred
|
|
from the other LINE options or the URL file suffix, with image as the fallback.
|
|
|
|
Outbound media URLs must be public HTTPS URLs of at most 2000 characters. OpenClaw
|
|
validates the target hostname before handing the URL to LINE and rejects loopback,
|
|
link-local, and private-network targets.
|
|
|
|
Generic media sends without LINE-specific options use the image route.
|
|
|
|
## Troubleshooting
|
|
|
|
- **Webhook verification fails:** ensure the webhook URL is HTTPS and the
|
|
`channelSecret` matches the LINE console.
|
|
- **No inbound events:** confirm the webhook path matches `channels.line.webhookPath`
|
|
and that the gateway is reachable from LINE.
|
|
- **Media download errors:** raise `channels.line.mediaMaxMb` if media exceeds the
|
|
default limit.
|
|
|
|
## Related
|
|
|
|
- [Channels Overview](/channels) — all supported channels
|
|
- [Pairing](/channels/pairing) — DM authentication and pairing flow
|
|
- [Groups](/channels/groups) — group chat behavior and mention gating
|
|
- [Channel Routing](/channels/channel-routing) — session routing for messages
|
|
- [Security](/gateway/security) — access model and hardening
|