Channel プラグイン SDK
Channel Plugin SDK (@elftia/channel-sdk) は、Channel プラグインが従う必要のあるすべてのインターフェースと型を定義します。ソースコードは packages/channel-sdk/src/ にあります。
ChannelPlugin インターフェース
すべての Channel プラグインは ChannelPlugin インターフェースを実装する必要があります。
interface ChannelPlugin {
/** Unique Channel type identifier, e.g. 'discord', 'telegram' */
readonly type: string;
// ─── Lifecycle (required) ───────────────────
/** Establish connection with decrypted credentials */
connect(
credentials: Record<string, string>,
options?: Record<string, unknown>,
): Promise<void>;
/** Disconnect and release resources */
disconnect(): Promise<void>;
/** Whether currently connected */
isConnected(): boolean;
// ─── Message Sending (required) ─────────────
/** Send text message to specified chat */
sendMessage(
chatId: string,
text: string,
options?: SendOptions,
): Promise<void>;
// ─── Optional Capabilities ──────────────────
/** Send typing indicator */
sendTyping?(chatId: string): Promise<void>;
/** Get list of available chats/channels */
getChats?(): Promise<ChatInfo[]>;
/** Send file attachment */
sendAttachment?(
chatId: string,
attachment: AttachmentInput,
): Promise<void>;
/** Validate credential validity (without establishing persistent connection) */
validateCredentials?(
credentials: Record<string, string>,
): Promise<{ valid: boolean; error?: string }>;
/** Dispose plugin instance and release all resources */
dispose?(): Promise<void>;
// ─── AI Context Injection ───────────────────
/**
* Return Channel-specific system prompt fragment.
* When a message comes from this Channel, the returned text will be appended
* to the Agent's base system prompt.
*/
getSystemPrompt?(
context: SystemPromptContext,
): string | undefined;
}
ChannelPluginFactory
プラグインのデフォルトエクスポートはファクトリー関数でなければなりません。
type ChannelPluginFactory = (context: ChannelPluginContext) => ChannelPlugin;
Elftia は Channel インスタンスを作成するときにこの関数を呼び出し、ChannelPluginContext を渡します。プラグインは Context を通じてコアシステムと通信します。
ChannelPluginContext
Context は、プラグインと Elftia コアの間にある唯一の通信ブリッジです。
interface ChannelPluginContext {
/** Channel instance ID */
readonly channelId: string;
/** Channel display name */
readonly displayName: string;
// ─── Message Reporting ──────────────────────
/** Report received inbound message */
emitMessage(msg: InboundMessage): void;
/** Report connection status change */
emitStatusChange(status: ChannelStatus): void;
/** Report error */
emitError(error: Error): void;
/** Send custom event to frontend (e.g. QR code pairing) */
emitEvent(eventType: string, data: unknown): void;
// ─── Logging ────────────────────────────────
/** Structured logging */
log: PluginLogger;
// ─── Storage ────────────────────────────────
/** Plugin-level K-V persistent storage */
storage: PluginStorage;
// ─── File System ─────────────────────────────
/**
* Plugin-specific data directory (persistent across sessions).
* Framework automatically creates it. Plugin can use for file downloads,
* caching, temporary files, etc.
* Example path: {userData}/channel-data/{channelId}/
*/
readonly dataDir: string;
}
PluginLogger
interface PluginLogger {
info(msg: string, meta?: Record<string, unknown>): void;
warn(msg: string, meta?: Record<string, unknown>): void;
error(msg: string, error?: Error): void;
debug(msg: string, meta?: Record<string, unknown>): void;
}
ログ出力には自動的に [Channel:{channelId}] プレフィックスが付加され、Elftia のメインログシステムと統合されます。
PluginStorage
interface PluginStorage {
get<T = unknown>(key: string): Promise<T | null>;
set(key: string, value: unknown): Promise<void>;
delete(key: string): Promise<void>;
}
下位層では SQLite データベースを使用して永続化し、読み取りを高速化するためにインメモリキャッシュを備えています。値は JSON シリアライズ済みとして保存されます。
InboundMessage
プラグインが context.emitMessage() 経由で報告する受信メッセージ形式です。
interface InboundMessage {
/** Message unique ID (platform's original ID) */
id: string;
/** Chat/channel ID */
chatId: string;
/** Sender's platform ID */
senderId: string;
/** Sender's display name */
senderName: string;
/** Message text content */
content: string;
/** ISO 8601 timestamp */
timestamp: string;
/** Whether it is a message from the bot itself */
isFromMe: boolean;
/** Whether it is a group message */
isGroup: boolean;
/** ID of message being replied to */
replyToId?: string;
/** Attachment list */
attachments?: ChannelAttachment[];
/** Platform-specific metadata */
metadata?: Record<string, unknown>;
}
SendOptions
メッセージ送信時の任意パラメーターです。
interface SendOptions {
/** Reply to specified message */
replyToId?: string;
/** Message format */
format?: 'text' | 'markdown' | 'html';
/** Forum post/thread ID */
threadId?: string;
/** Send silently (no notification) */
silent?: boolean;
/** Caption text for media attachments */
caption?: string;
/** Platform-specific reply markup (inline keyboard, etc.) */
replyMarkup?: unknown;
}
AttachmentInput
添付ファイル送信用の入力形式です。
interface AttachmentInput {
type: 'image' | 'file' | 'audio' | 'video';
/** Attachment content: Buffer or URL string */
data: Buffer | string;
/** File name */
name: string;
/** MIME type */
mimeType?: string;
}
SystemPromptContext
getSystemPrompt() に渡される Context です。
interface SystemPromptContext {
/** Chat type (e.g. 'group', 'dm') */
chatType: string;
/** Chat ID */
chatId: string;
/** Sender ID */
senderId: string;
/** Sender name */
senderName: string;
/** Whether it is a group */
isGroup: boolean;
/** Platform-specific metadata */
metadata?: Record<string, unknown>;
}
マニフェストファイル (elftia-channel.json)
すべてのプラグインは、ルートディレクトリに elftia-channel.json マニフェストファイルを含める必要があります。
{
"name": "@elftia/channel-discord",
"type": "discord",
"displayName": "Discord",
"version": "1.0.0",
"description": "Discord bot integration for Elftia",
"author": "Elftia Team",
"icon": "icon.svg",
"entry": "dist/index.cjs",
"credentials": [
{
"key": "botToken",
"label": "Bot Token",
"type": "password",
"required": true,
"placeholder": "MTA...",
"helpText": "Get from Discord Developer Portal",
"helpUrl": "https://discord.com/developers/applications"
}
],
"options": [
{
"key": "autoReconnect",
"label": "Auto Reconnect",
"type": "toggle",
"default": true,
"helpText": "Automatically try to reconnect when connection is lost"
}
],
"capabilities": {
"typing": true,
"reactions": true,
"attachments": true,
"threads": true,
"groupChat": true,
"sendOnly": false
},
"maxMessageLength": 2000,
"platformUrl": "https://discord.com",
"minElftiaVersion": "0.5.0"
}
マニフェストフィールド
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
name | string | はい | npm パッケージ名 (識別と重複排除に使用) |
type | string | はい | Channel タイプ識別子 (例: discord) |
displayName | string | はい | 人間が読めるプラットフォーム名 |
version | string | はい | セマンティックバージョン |
description | string | いいえ | プラグインの説明 |
author | string | いいえ | 作者名 |
icon | string | いいえ | アイコンパス (プラグインディレクトリからの相対パス) または SVG 文字列 |
entry | string | はい | エントリーファイルパス (プラグインディレクトリからの相対パス) |
credentials | CredentialField[] | はい | クレデンシャルフィールド定義 (UI フォームのレンダリング用) |
options | OptionField[] | いいえ | クレデンシャル以外の設定オプション (トグルスイッチなど) |
capabilities | ChannelCapabilities | いいえ | プラットフォーム機能の宣言 |
maxMessageLength | number | いいえ | プラットフォームのメッセージ長制限 |
platformUrl | string | いいえ | プラットフォームの公式 Web サイト |
minElftiaVersion | string | いいえ | 必要な最小 Elftia バージョン |
CredentialField
interface CredentialField {
key: string; // Field key name
label: string; // Display label
type: 'text' | 'password' | 'textarea';
required: boolean;
placeholder?: string;
helpText?: string; // Input hint
helpUrl?: string; // Help link
}
OptionField
interface OptionField {
key: string;
label: string;
type: 'toggle'; // Currently only toggle type supported
default?: boolean;
helpText?: string;
}
ChannelCapabilities
interface ChannelCapabilities {
typing?: boolean; // Typing indicator
reactions?: boolean; // Emoji reactions
attachments?: boolean; // File attachments
threads?: boolean; // Posts/threads
groupChat?: boolean; // Group chat
sendOnly?: boolean; // Send-only (no inbound messages)
}
sendOnly は、Webhooks をホストできないデスクトップアプリ向けです。プラグインは能動的にメッセージを送信することだけができ、受信メッセージは受け取れません。
次のステップ
- メッセージルーティングとセキュリティパイプライン — プラグインから Agent までの完全な処理フロー
- Channel プラグインの作成 — Channel プラグインをゼロから実装する