← Back to Plugins
Tools

Lansenger Tools

lansenger-pm By lansenger-pm 👁 44 views ▲ 0 votes

Lansenger (蓝信) messaging tools plugin for OpenClaw — send text, Markdown, files, cards, manage groups

GitHub

Install

npm install
openclaw

Configuration Example

{ "filePath": "/absolute/path/to/file.pdf", "caption": "Report Q1", "to": "chat-id" }

README

[English](README.md) | [简体中文](README.zhHans.md) | [繁体中文](README.zhHant.md) | [繁体中文香港](README.zhHantHK.md) | [Français](README.fr.md)

# @lansenger-pm/openclaw-lansenger-tools

Lansenger (蓝信) messaging **tools plugin** for OpenClaw — provides 10 agent tools for sending text, Markdown, files, cards, and managing groups.

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
![TypeScript](https://img.shields.io/badge/TypeScript-6.0-blue)

## Why a separate tools plugin?

The [`@lansenger-pm/openclaw-lansenger-channel`](https://github.com/lansenger-pm/openclaw-lansenger-channel) plugin handles WebSocket inbound, HTTP outbound, and channel lifecycle. Tools registration was originally embedded in the channel plugin, but OpenClaw's plugin system requires **tools contracts** to be declared in a dedicated plugin's `openclaw.plugin.json`. This standalone tools plugin:

- Declares all 10 tool contracts and `configSignals` in its own `openclaw.plugin.json`
- Imports runtime state (`getRunningClient`, `getRunningAccount`, `getLastInboundChatId`) from the channel package at runtime — tools share the same LansengerClient instance
- Registers tools only in `full` registration mode (when the channel gateway is running)

## Tools

| Tool | msgType | Description | Key params |
|------|---------|-------------|------------|
| `lansenger_send_file` | file | Send local file attachment (any path) | `filePath`, `caption?`, `to?` |
| `lansenger_send_text` | text | Plain text with optional file + @mention | `content`, `filePath?`, `reminderAll?`, `reminderUserIds?`, `to?` |
| `lansenger_send_format_text` | formatText | Markdown text with optional @mention | `content`, `reminderAll?`, `reminderUserIds?`, `to?` |
| `lansenger_send_image_url` | image | Send image from URL | `imageUrl`, `caption?`, `to?` |
| `lansenger_send_link_card` | linkCard | Rich link preview card | `title`, `link`, `description?`, `to?` |
| `lansenger_send_app_articles` | appArticles | Multi-article card | `articles[]`, `to?` |
| `lansenger_send_app_card` | appCard | Rich/approval card (supports div-style) | `bodyTitle`, `isDynamic?`, `fields?`, `links?`, `to?` |
| `lansenger_update_dynamic_card` | dynamic | Update dynamic card status in-place | `msgId`, `headStatusInfo?`, `isLastUpdate?` |
| `lansenger_revoke_message` | — | Revoke previously sent messages | `messageIds[]`, `chatType?`, `senderId?` |
| `lansenger_query_groups` | — | Query bot's group list | `pageOffset?`, `pageSize?` |

## Message Type Capability Matrix

| msgType | Markdown | @mention | Attachments |
|---------|----------|----------|-------------|
| `text` | ✗ | ✓ | ✓ |
| `formatText` | ✓ | ✓ (reminder) | ✗ |

**Default strategy**: Write Markdown replies normally (auto-rendered). Use `lansenger_send_text` for file attachments. Use `lansenger_send_format_text` for explicit Markdown + @mention. For Markdown AND a file, send two separate messages.

## Installation

```bash
# Install both plugins (tools depends on channel for runtime state)
openclaw plugins install @lansenger-pm/openclaw-lansenger-channel
openclaw plugins install @lansenger-pm/openclaw-lansenger-tools

# Configure the channel (interactive wizard)
openclaw channels add

# Restart the gateway
openclaw gateway restart
```

The tools plugin auto-registers all 10 tools when the Lansenger channel is running. No separate configuration needed — tools read from the same channel config (`channels.lansenger`).

### Development install (linked)

```bash
cd /path/to/openclaw-lansenger-tools
npm install
openclaw plugins install --link
openclaw gateway restart
```

## Tool Details

### lansenger_send_file

Send a local file as an attachment. Any local path works — workspace, Documents, Desktop, `/tmp`, etc.

```json
{ "filePath": "/absolute/path/to/file.pdf", "caption": "Report Q1", "to": "chat-id" }
```

> ⚠️ Do NOT use `<media>` tags for files outside the workspace; they silently fail. Always use this tool.

### lansenger_send_text

Plain text (no Markdown). Supports optional file attachment and @mentions.

```json
{ "content": "Please review the attached file.", "filePath": "/path/to/file.pdf", "reminderAll": true, "to": "group-chat-id" }
```

> For Markdown replies, just write normally — it renders automatically. Use this tool only for text + file or text + @mention combos.

### lansenger_send_format_text

Markdown-formatted text with optional @mentions. No file attachments.

```json
{ "content": "## Summary\n- Item 1\n- Item 2", "reminderUserIds": ["user-id-1"], "to": "chat-id" }
```

### lansenger_send_image_url

Send an image from a URL. The gateway downloads and re-uploads it.

```json
{ "imageUrl": "https://example.com/image.png", "caption": "Screenshot", "to": "chat-id" }
```

### lansenger_send_link_card

Rich link preview card.

```json
{ "title": "OpenClaw Docs", "link": "https://opencode.ai", "description": "Documentation", "to": "chat-id" }
```

### lansenger_send_app_articles

Multi-article card (图文卡片). Each article requires `imgUrl`, `title`, `url`.

```json
{ "articles": [{ "imgUrl": "https://example.com/img.jpg", "title": "Article 1", "url": "https://example.com/1", "summary": "摘要" }], "to": "chat-id" }
```

> ⚠️ Use `summary` field (NOT `description` — that field is silently ignored by the API).

### lansenger_send_app_card

Rich formatted card (应用卡片). Supports div-style formatting for color, font-size, text-align.

```json
{
  "bodyTitle": "Approval Request",
  "isDynamic": true,
  "fields": [{ "key": "Amount", "value": "¥5,000" }],
  "links": [{ "title": "Approve", "url": "https://example.com/approve" }],
  "to": "chat-id"
}
```

> ⚠️ **font-size** MUST use `pt` units (12pt–36pt) — `px` causes "invalid bodyContent".
> ⚠️ **text-indent** MUST have units — bare `0` causes silent failure; use `0em`.
> ⚠️ **headStatusInfo**: `description` is status text (supports div-style, max 30 bytes), `colour` is the status dot color (hex). These are TWO different things — text color vs dot color.
> ⚠️ Group chat does NOT support appCard — falls back to plain text.

### lansenger_update_dynamic_card

Update a dynamic card's status in-place. The card must have been sent with `isDynamic=true`.

```json
{ "msgId": "msg-id-from-send-app-card", "headStatusInfo": { "description": "Approved", "colour": "#198754" }, "isLastUpdate": true }
```

### lansenger_revoke_message

Revoke previously sent messages. For group chat, `senderId` is required.

```json
{ "messageIds": ["msg-id-1", "msg-id-2"], "chatType": "group", "senderId": "sender-openid" }
```

### lansenger_query_groups

Query the bot's group list. Returns total count and group IDs.

```json
{ "pageOffset": 1, "pageSize": 100 }
```

> ⚠️ May return `errCode=10005` "API服务无权限" on enterprise deployments where `/v2/groups/fetch` is not authorized. Ask the user for group chatIds manually.

## Auto-target resolution

All tools with a `to` parameter auto-resolve the target:
- If `to` is provided → use it directly
- If `to` is omitted → use `getLastInboundChatId()` (the chat that triggered the current conversation)

This means in normal conversation flow, agents don't need to specify `to` — the tool automatically sends back to the current chat.

## configSignals

Each tool declares `configSignals` pointing to `channels.lansenger` with `required: ["appId", "appSecret"]`. OpenClaw uses this to show "configured" / "not running" status per tool in the GUI.

## Important Notes

- **Requires channel plugin** — tools import `getRunningClient`, `getRunningAccount`, `getLastInboundChatId` from the channel package at runtime
- **No separate config** — tools read the same Lansenger credentials as the channel plugin
- **appArticles** — uses `summary` (NOT `description`)
- **linkCard** — `description`, `iconLink`, `fromName`, `fromIconLink` are required (empty string defaults)
- **appCard div-style** — font-size in `pt` only; text-indent with units; headStatusInfo description vs colour
- **Revoke chatType** — only `bot` or `group`; no `staff` type
- **Group chat** — appCard falls back to plain text in group chats

## Development

### Build

```bash
npm install
npx tsc
```

### Typecheck

```bash
npx tsc --noEmit
```

### Project Structure

```
openclaw-lansenger-tools/
├── src/
│   └── tools.ts           # All 10 tool definitions + registerLansengerTools()
├── tools-entry.ts         # Plugin entry point (definePluginEntry)
├── dist/                  # Compiled JavaScript
├── openclaw.plugin.json   # Plugin metadata, contracts, configSignals
├── package.json
├── VERSION
└── tsconfig.json
```

## Changelog

- **v1.0.0** — Initial release: 10 tools (send_file, send_text, send_format_text, send_image_url, send_link_card, send_app_articles, send_app_card, update_dynamic_card, revoke_message, query_groups)

## License

MIT — see [LICENSE](LICENSE).
tools

Comments

Sign in to leave a comment

Loading comments...