@elizaos/plugin-feishu 2.0.0-alpha.7 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -0
- package/auto-enable.ts +21 -0
- package/dist/accounts.d.ts.map +1 -1
- package/dist/actions/index.d.ts +1 -1
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/connector-account-provider.d.ts +16 -0
- package/dist/connector-account-provider.d.ts.map +1 -0
- package/dist/environment.d.ts.map +1 -1
- package/dist/formatting.d.ts.map +1 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +502 -306
- package/dist/index.js.map +13 -13
- package/dist/messageManager.d.ts.map +1 -1
- package/dist/providers/index.d.ts +3 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/service.d.ts +3 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow-credential-provider.d.ts +21 -0
- package/dist/workflow-credential-provider.d.ts.map +1 -0
- package/package.json +19 -10
- package/dist/actions/sendMessage.d.ts +0 -4
- package/dist/actions/sendMessage.d.ts.map +0 -1
- package/dist/providers/chatState.d.ts +0 -7
- package/dist/providers/chatState.d.ts.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/
|
|
3
|
+
"sources": ["../src/index.ts", "../src/accounts.ts", "../src/connector-account-provider.ts", "../src/constants.ts", "../src/messageManager.ts", "../src/environment.ts", "../src/types.ts", "../src/service.ts", "../src/workflow-credential-provider.ts", "../src/formatting.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"
|
|
6
|
-
"import type {\n Action,\n ActionExample,\n ActionResult,\n HandlerCallback,\n HandlerOptions,\n IAgentRuntime,\n Memory,\n State,\n} from \"@elizaos/core\";\nimport { FEISHU_SERVICE_NAME } from \"../constants\";\nimport type { FeishuService } from \"../service\";\n\nexport const SEND_MESSAGE_ACTION = \"SEND_FEISHU_MESSAGE\";\n\nexport const sendMessageAction: Action = {\n name: SEND_MESSAGE_ACTION,\n similes: [\n \"FEISHU_SEND_MESSAGE\",\n \"FEISHU_REPLY\",\n \"FEISHU_MESSAGE\",\n \"SEND_FEISHU\",\n \"REPLY_FEISHU\",\n \"LARK_SEND_MESSAGE\",\n \"LARK_REPLY\",\n \"SEND_LARK\",\n ],\n description: \"Send a message to a Feishu/Lark chat\",\n\n validate: async (\n _runtime: IAgentRuntime,\n message: Memory,\n ): Promise<boolean> => {\n const textRaw =\n typeof message.content?.text === \"string\" ? message.content.text : \"\";\n const text = textRaw.toLowerCase();\n const sourceOk = message.content?.source === \"feishu\";\n const keywordOk =\n text.includes(\"send\") ||\n text.includes(\"message\") ||\n text.includes(\"reply\") ||\n text.includes(\"feishu\") ||\n text.includes(\"lark\") ||\n sourceOk;\n const regexOk =\n /\\b(?:send|message|reply|feishu|lark)\\b/i.test(textRaw) || sourceOk;\n const inputOk =\n textRaw.trim().length > 0 ||\n Boolean(message.content?.chatId || message.content?.messageId) ||\n sourceOk;\n return sourceOk && keywordOk && regexOk && inputOk;\n },\n\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State | undefined,\n _options?: HandlerOptions,\n callback?: HandlerCallback,\n ): Promise<ActionResult> => {\n const feishuService = runtime.getService(FEISHU_SERVICE_NAME) as unknown as\n | FeishuService\n | undefined;\n\n if (!feishuService) {\n if (callback) {\n await callback({\n text: \"Feishu service not available\",\n });\n }\n return { success: false, error: \"Feishu service not initialized\" };\n }\n\n const currentState = state ?? (await runtime.composeState(message));\n const responseText = currentState.values?.response?.toString() || \"\";\n const chatId = message.content?.chatId as string | undefined;\n\n if (!chatId) {\n if (callback) {\n await callback({\n text: \"No chat ID available\",\n });\n }\n return { success: false, error: \"Missing chat ID\" };\n }\n\n if (callback) {\n await callback({\n text: responseText,\n action: SEND_MESSAGE_ACTION,\n });\n }\n\n return {\n success: true,\n data: {\n action: SEND_MESSAGE_ACTION,\n chatId,\n text: responseText,\n replyToMessageId: message.content?.messageId,\n },\n };\n },\n\n examples: [\n [\n {\n name: \"{{name1}}\",\n content: {\n text: \"Send a message to this Feishu chat\",\n },\n },\n {\n name: \"{{agentName}}\",\n content: {\n text: \"I'll send a message to this chat now.\",\n actions: [SEND_MESSAGE_ACTION],\n },\n },\n ],\n ] as ActionExample[][],\n};\n",
|
|
7
|
-
"import {\n ChannelType,\n createUniqueUuid,\n EventType,\n type IAgentRuntime,\n logger,\n type Memory,\n type UUID,\n} from \"@elizaos/core\";\nimport type * as lark from \"@larksuiteoapi/node-sdk\";\nimport { MAX_MESSAGE_LENGTH } from \"./constants\";\nimport type { FeishuConfig } from \"./environment\";\nimport { isChatAllowed } from \"./environment\";\nimport type {\n FeishuChat,\n FeishuChatType,\n FeishuEventData,\n FeishuMessage,\n FeishuMessageContent,\n FeishuMessageReceivedPayload,\n FeishuUser,\n} from \"./types\";\nimport { FeishuEventTypes } from \"./types\";\n\n/**\n * Manages message handling for the Feishu service.\n */\nexport class MessageManager {\n private client: lark.Client;\n private runtime: IAgentRuntime;\n private config: FeishuConfig;\n private processedMessages: Set<string> = new Set();\n private botOpenId: string | null = null;\n\n constructor(\n client: lark.Client,\n runtime: IAgentRuntime,\n config: FeishuConfig,\n ) {\n this.client = client;\n this.runtime = runtime;\n this.config = config;\n }\n\n /**\n * Sets the bot's open ID for mention detection.\n */\n setBotOpenId(openId: string): void {\n this.botOpenId = openId;\n }\n\n /**\n * Handles incoming message events.\n */\n async handleMessage(event: FeishuEventData): Promise<void> {\n try {\n const message = event.event?.message as FeishuMessage | undefined;\n if (!message) {\n return;\n }\n\n // Deduplicate messages\n if (this.processedMessages.has(message.messageId)) {\n return;\n }\n this.processedMessages.add(message.messageId);\n\n // Limit cache size\n if (this.processedMessages.size > 1000) {\n const firstKey = this.processedMessages.values().next().value as string;\n this.processedMessages.delete(firstKey);\n }\n\n const chatId = message.chatId;\n const chatType = (event.event?.chat_type || \"p2p\") as FeishuChatType;\n\n // Check if chat is allowed\n if (!isChatAllowed(this.config, chatId)) {\n logger.debug(`[Feishu] Chat ${chatId} not authorized, skipping`);\n return;\n }\n\n // Parse sender information\n const sender = this.parseSender(event);\n\n // Ignore bot messages if configured\n if (this.config.shouldIgnoreBotMessages && sender.isBot) {\n logger.debug(\"[Feishu] Ignoring bot message\");\n return;\n }\n\n // Check for mentions if configured\n if (this.config.shouldRespondOnlyToMentions && chatType !== \"p2p\") {\n if (!this.isBotMentioned(message)) {\n logger.debug(\"[Feishu] Bot not mentioned, skipping\");\n return;\n }\n }\n\n // Parse message content\n const text = this.parseMessageContent(message);\n\n // Build chat info\n const chat: FeishuChat = {\n chatId,\n chatType: chatType as FeishuChatType,\n name: (event.event?.chat_name as string | undefined) || undefined,\n };\n\n // Create room and entity IDs\n const roomId = createUniqueUuid(this.runtime, chatId) as UUID;\n const entityId = createUniqueUuid(this.runtime, sender.openId) as UUID;\n const worldId = createUniqueUuid(this.runtime, chatId) as UUID;\n\n // Ensure connection exists\n await this.runtime.ensureConnection({\n entityId,\n roomId,\n userName: sender.name,\n userId: sender.openId as UUID,\n name: sender.name || \"Unknown User\",\n source: \"feishu\",\n channelId: chatId,\n messageServerId: worldId,\n type: chatType === \"p2p\" ? ChannelType.DM : ChannelType.GROUP,\n worldId,\n });\n\n // Create memory for the message\n const memory: Memory = {\n id: createUniqueUuid(this.runtime, message.messageId) as UUID,\n entityId,\n roomId,\n agentId: this.runtime.agentId,\n content: {\n text,\n source: \"feishu\",\n chatId,\n messageId: message.messageId,\n },\n createdAt: Number.parseInt(message.createTime, 10),\n };\n\n // Emit message received event\n const payload: FeishuMessageReceivedPayload = {\n runtime: this.runtime,\n message: memory,\n source: \"feishu\",\n originalMessage: message,\n chat,\n sender,\n };\n\n this.runtime.emitEvent(FeishuEventTypes.MESSAGE_RECEIVED, payload);\n this.runtime.emitEvent(EventType.MESSAGE_RECEIVED, payload);\n } catch (error) {\n logger.error(\n `[Feishu] Error handling message: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n /**\n * Sends a message to a chat.\n */\n async sendMessage(\n chatId: string,\n content: FeishuMessageContent,\n ): Promise<string[]> {\n const messageIds: string[] = [];\n\n try {\n const text = content.text || \"\";\n\n // Handle card messages\n if (content.card) {\n const response = await this.client.im.message.create({\n params: { receive_id_type: \"chat_id\" },\n data: {\n receive_id: chatId,\n msg_type: \"interactive\",\n content: JSON.stringify(content.card),\n },\n });\n if (response.data?.message_id) {\n messageIds.push(response.data.message_id);\n }\n return messageIds;\n }\n\n // Handle image messages\n if (content.imageKey) {\n const response = await this.client.im.message.create({\n params: { receive_id_type: \"chat_id\" },\n data: {\n receive_id: chatId,\n msg_type: \"image\",\n content: JSON.stringify({ image_key: content.imageKey }),\n },\n });\n if (response.data?.message_id) {\n messageIds.push(response.data.message_id);\n }\n return messageIds;\n }\n\n // Split long messages\n const parts = this.splitMessage(text);\n\n for (const part of parts) {\n const response = await this.client.im.message.create({\n params: { receive_id_type: \"chat_id\" },\n data: {\n receive_id: chatId,\n msg_type: \"text\",\n content: JSON.stringify({ text: part }),\n },\n });\n if (response.data?.message_id) {\n messageIds.push(response.data.message_id);\n }\n }\n\n return messageIds;\n } catch (error) {\n logger.error(\n `[Feishu] Error sending message: ${error instanceof Error ? error.message : String(error)}`,\n );\n throw error;\n }\n }\n\n /**\n * Replies to a specific message.\n */\n async replyToMessage(\n messageId: string,\n content: FeishuMessageContent,\n ): Promise<string[]> {\n const messageIds: string[] = [];\n\n try {\n const text = content.text || \"\";\n const parts = this.splitMessage(text);\n\n for (const part of parts) {\n const response = await this.client.im.message.reply({\n path: { message_id: messageId },\n data: {\n msg_type: \"text\",\n content: JSON.stringify({ text: part }),\n },\n });\n if (response.data?.message_id) {\n messageIds.push(response.data.message_id);\n }\n }\n\n return messageIds;\n } catch (error) {\n logger.error(\n `[Feishu] Error replying to message: ${error instanceof Error ? error.message : String(error)}`,\n );\n throw error;\n }\n }\n\n /**\n * Parses sender information from an event.\n */\n private parseSender(event: FeishuEventData): FeishuUser {\n const sender = event.event?.sender as\n | {\n sender_id?: {\n open_id?: string;\n union_id?: string;\n user_id?: string;\n };\n sender_type?: string;\n }\n | undefined;\n\n const isBot = sender?.sender_type === \"app\";\n const openId = sender?.sender_id?.open_id || \"\";\n\n return {\n openId,\n unionId: sender?.sender_id?.union_id,\n userId: sender?.sender_id?.user_id,\n isBot,\n };\n }\n\n /**\n * Parses message content to extract text.\n */\n private parseMessageContent(message: FeishuMessage): string {\n try {\n const content = JSON.parse(message.content);\n\n switch (message.msgType) {\n case \"text\":\n return content.text || \"\";\n\n case \"post\":\n // Rich text - extract plain text\n return this.extractTextFromPost(content);\n\n case \"image\":\n case \"file\":\n case \"audio\":\n case \"video\":\n case \"sticker\":\n return `[${message.msgType}]`;\n\n case \"interactive\":\n return \"[interactive card]\";\n\n default:\n return content.text || \"\";\n }\n } catch {\n return \"\";\n }\n }\n\n /**\n * Extracts plain text from a rich text (post) message.\n */\n private extractTextFromPost(content: {\n title?: string;\n content?: { tag: string; text?: string }[][];\n }): string {\n const parts: string[] = [];\n\n if (content.title) {\n parts.push(content.title);\n }\n\n if (content.content && Array.isArray(content.content)) {\n for (const line of content.content) {\n if (Array.isArray(line)) {\n const lineText = line\n .filter((elem) => elem.tag === \"text\" && elem.text)\n .map((elem) => elem.text)\n .join(\"\");\n if (lineText) {\n parts.push(lineText);\n }\n }\n }\n }\n\n return parts.join(\"\\n\");\n }\n\n /**\n * Checks if the bot is mentioned in the message.\n */\n private isBotMentioned(message: FeishuMessage): boolean {\n if (!this.botOpenId || !message.mentions) {\n return false;\n }\n\n return message.mentions.some((mention) => mention.id === this.botOpenId);\n }\n\n /**\n * Splits a long message into chunks.\n */\n private splitMessage(content: string): string[] {\n if (content.length <= MAX_MESSAGE_LENGTH) {\n return [content];\n }\n\n const parts: string[] = [];\n let current = \"\";\n\n for (const line of content.split(\"\\n\")) {\n const lineWithNewline = current ? `\\n${line}` : line;\n\n if (current.length + lineWithNewline.length > MAX_MESSAGE_LENGTH) {\n if (current) {\n parts.push(current);\n current = \"\";\n }\n\n if (line.length > MAX_MESSAGE_LENGTH) {\n // Split very long lines by words\n const words = line.split(/\\s+/);\n for (const word of words) {\n const wordWithSpace = current ? ` ${word}` : word;\n if (current.length + wordWithSpace.length > MAX_MESSAGE_LENGTH) {\n if (current) {\n parts.push(current);\n current = \"\";\n }\n if (word.length > MAX_MESSAGE_LENGTH) {\n // Split very long words\n for (let i = 0; i < word.length; i += MAX_MESSAGE_LENGTH) {\n parts.push(word.slice(i, i + MAX_MESSAGE_LENGTH));\n }\n } else {\n current = word;\n }\n } else {\n current += wordWithSpace;\n }\n }\n } else {\n current = line;\n }\n } else {\n current += lineWithNewline;\n }\n }\n\n if (current) {\n parts.push(current);\n }\n\n return parts;\n }\n}\n",
|
|
8
|
-
"
|
|
9
|
-
"import type {\n Content,\n EntityPayload,\n MessagePayload,\n WorldPayload,\n} from \"@elizaos/core\";\n\n/**\n * Feishu event data structure (local type since lark SDK doesn't export it)\n */\nexport interface FeishuEventData {\n event?: Record<string, unknown>;\n header?: {\n event_id?: string;\n token?: string;\n create_time?: string;\n event_type?: string;\n tenant_key?: string;\n app_id?: string;\n };\n}\n\n/**\n * Base content type for Feishu messages (extends Content for compatibility).\n * Note: Do not add FeishuCard directly to this interface as it conflicts with Content's index signature.\n */\nexport interface FeishuContent extends Content {\n /** Image key for image messages */\n feishuImageKey?: string;\n /** File key for file messages */\n feishuFileKey?: string;\n}\n\n/**\n * Internal type for Feishu-specific content with card support (not exported to Content).\n * This type is used internally for message sending/receiving.\n */\nexport interface FeishuMessageContent {\n text?: string;\n /** Interactive card content */\n card?: FeishuCard;\n /** Image key for image messages */\n imageKey?: string;\n /** File key for file messages */\n fileKey?: string;\n}\n\n/**\n * Helper type for accessing Feishu-specific card content (internal use)\n */\nexport type FeishuCardContent = {\n card?: FeishuCard;\n imageKey?: string;\n fileKey?: string;\n};\n\n/**\n * Feishu interactive card structure.\n */\nexport interface FeishuCard {\n /** Card configuration */\n config?: {\n wideScreenMode?: boolean;\n enableForward?: boolean;\n };\n /** Card header */\n header?: {\n title?: {\n tag: string;\n content: string;\n };\n template?: string;\n };\n /** Card elements */\n elements?: FeishuCardElement[];\n}\n\n/**\n * Card element types.\n */\nexport type FeishuCardElement =\n | { tag: \"div\"; text: { tag: string; content: string } }\n | { tag: \"action\"; actions: FeishuCardAction[] }\n | { tag: \"hr\" }\n | { tag: \"note\"; elements: { tag: string; content: string }[] };\n\n/**\n * Card action types.\n */\nexport interface FeishuCardAction {\n tag: \"button\";\n text: { tag: string; content: string };\n type?: \"default\" | \"primary\" | \"danger\";\n url?: string;\n value?: Record<string, string>;\n}\n\n/**\n * Event types emitted by the Feishu plugin.\n */\nexport enum FeishuEventTypes {\n WORLD_JOINED = \"FEISHU_WORLD_JOINED\",\n WORLD_CONNECTED = \"FEISHU_WORLD_CONNECTED\",\n WORLD_LEFT = \"FEISHU_WORLD_LEFT\",\n ENTITY_JOINED = \"FEISHU_ENTITY_JOINED\",\n ENTITY_LEFT = \"FEISHU_ENTITY_LEFT\",\n ENTITY_UPDATED = \"FEISHU_ENTITY_UPDATED\",\n MESSAGE_RECEIVED = \"FEISHU_MESSAGE_RECEIVED\",\n MESSAGE_SENT = \"FEISHU_MESSAGE_SENT\",\n REACTION_RECEIVED = \"FEISHU_REACTION_RECEIVED\",\n INTERACTION_RECEIVED = \"FEISHU_INTERACTION_RECEIVED\",\n SLASH_START = \"FEISHU_SLASH_START\",\n}\n\n/**\n * Map of event types to their payload types.\n */\nexport interface FeishuEventPayloadMap {\n [FeishuEventTypes.MESSAGE_RECEIVED]: FeishuMessageReceivedPayload;\n [FeishuEventTypes.MESSAGE_SENT]: FeishuMessageSentPayload;\n [FeishuEventTypes.REACTION_RECEIVED]: FeishuReactionReceivedPayload;\n [FeishuEventTypes.WORLD_JOINED]: FeishuWorldPayload;\n [FeishuEventTypes.WORLD_CONNECTED]: FeishuWorldPayload;\n [FeishuEventTypes.WORLD_LEFT]: FeishuWorldPayload;\n [FeishuEventTypes.SLASH_START]: { chatId: string };\n [FeishuEventTypes.ENTITY_JOINED]: FeishuEntityPayload;\n [FeishuEventTypes.ENTITY_LEFT]: FeishuEntityPayload;\n [FeishuEventTypes.ENTITY_UPDATED]: FeishuEntityPayload;\n [FeishuEventTypes.INTERACTION_RECEIVED]: FeishuInteractionPayload;\n}\n\n/**\n * Feishu chat types.\n */\nexport enum FeishuChatType {\n /** Private one-on-one chat */\n P2P = \"p2p\",\n /** Group chat */\n GROUP = \"group\",\n}\n\n/**\n * Feishu user information.\n */\nexport interface FeishuUser {\n /** Open ID (user identifier) */\n openId: string;\n /** Union ID (cross-app identifier) */\n unionId?: string;\n /** User ID (tenant-level identifier) */\n userId?: string;\n /** User's display name */\n name?: string;\n /** User's avatar URL */\n avatarUrl?: string;\n /** Whether the user is a bot */\n isBot?: boolean;\n}\n\n/**\n * Feishu chat information.\n */\nexport interface FeishuChat {\n /** Chat ID */\n chatId: string;\n /** Chat type */\n chatType: FeishuChatType;\n /** Chat name/title */\n name?: string;\n /** Chat owner's open ID */\n ownerOpenId?: string;\n /** Chat description */\n description?: string;\n /** Tenant key */\n tenantKey?: string;\n}\n\n/**\n * Feishu message information.\n */\nexport interface FeishuMessage {\n /** Message ID */\n messageId: string;\n /** Root message ID (for threads) */\n rootId?: string;\n /** Parent message ID (for replies) */\n parentId?: string;\n /** Message type */\n msgType: string;\n /** Message content (JSON string) */\n content: string;\n /** Create time (Unix timestamp in milliseconds) */\n createTime: string;\n /** Update time (Unix timestamp in milliseconds) */\n updateTime?: string;\n /** Whether the message is deleted */\n deleted?: boolean;\n /** Chat ID */\n chatId: string;\n /** Sender information */\n sender: {\n id: string;\n idType: string;\n senderType: string;\n tenantKey?: string;\n };\n /** Mentions in the message */\n mentions?: FeishuMention[];\n}\n\n/**\n * Mention information in a message.\n */\nexport interface FeishuMention {\n /** Mention key in the message */\n key: string;\n /** Mentioned user's ID */\n id: string;\n /** ID type */\n idType: string;\n /** Mentioned user's name */\n name: string;\n /** Tenant key */\n tenantKey?: string;\n}\n\n/**\n * Payload for received messages.\n */\nexport interface FeishuMessageReceivedPayload extends MessagePayload {\n /** Original Feishu message */\n originalMessage: FeishuMessage;\n /** Chat information */\n chat: FeishuChat;\n /** Sender information */\n sender: FeishuUser;\n}\n\n/**\n * Payload for sent messages.\n */\nexport interface FeishuMessageSentPayload extends MessagePayload {\n /** Message IDs of sent messages */\n messageIds: string[];\n /** Chat ID */\n chatId: string;\n}\n\n/**\n * Payload for reaction events.\n */\nexport interface FeishuReactionReceivedPayload\n extends FeishuMessageReceivedPayload {\n /** Reaction type/emoji */\n reactionType: string;\n}\n\n/**\n * Payload for world/chat events.\n */\nexport interface FeishuWorldPayload extends WorldPayload {\n /** Chat information */\n chat: FeishuChat;\n /** Bot's open ID */\n botOpenId?: string;\n}\n\n/**\n * Payload for entity (user) events.\n */\nexport interface FeishuEntityPayload extends EntityPayload {\n /** Feishu user information */\n feishuUser: FeishuUser;\n /** Chat where the event occurred */\n chat: FeishuChat;\n}\n\n/**\n * Payload for interaction events (card actions, etc.).\n */\nexport interface FeishuInteractionPayload {\n /** Interaction type */\n type: string;\n /** Action data */\n action: {\n tag: string;\n value?: Record<string, string>;\n };\n /** User who triggered the interaction */\n user: FeishuUser;\n /** Chat where the interaction occurred */\n chat?: FeishuChat;\n /** Token for responding to the interaction */\n token?: string;\n}\n",
|
|
10
|
-
"import type {
|
|
11
|
-
"import {\n ChannelType,\n type Content,\n createUniqueUuid,\n type EventPayload,\n EventType,\n type IAgentRuntime,\n logger,\n type Room,\n Service,\n type TargetInfo,\n type UUID,\n type World,\n} from \"@elizaos/core\";\nimport * as lark from \"@larksuiteoapi/node-sdk\";\nimport { FEISHU_SERVICE_NAME } from \"./constants\";\nimport {\n type FeishuConfig,\n getFeishuConfig,\n validateConfig,\n} from \"./environment\";\nimport { MessageManager } from \"./messageManager\";\nimport type {\n FeishuChat,\n FeishuEventData,\n FeishuMessageContent,\n FeishuWorldPayload,\n} from \"./types\";\nimport { FeishuChatType, FeishuEventTypes } from \"./types\";\n\n/**\n * Feishu service for ElizaOS.\n */\nexport class FeishuService extends Service {\n static serviceType = FEISHU_SERVICE_NAME;\n capabilityDescription =\n \"The agent is able to send and receive messages on Feishu/Lark\";\n\n private client: lark.Client | null = null;\n private wsClient: lark.WSClient | null = null;\n public messageManager: MessageManager | null = null;\n private feishuConfig: FeishuConfig | null = null;\n private botOpenId: string | null = null;\n private knownChats: Map<string, FeishuChat> = new Map();\n\n constructor(runtime?: IAgentRuntime) {\n super(runtime);\n\n if (!runtime) {\n return;\n }\n\n const config = getFeishuConfig(runtime);\n if (!config) {\n logger.warn(\n \"[Feishu] App ID or App Secret not provided - Feishu functionality will be unavailable\",\n );\n return;\n }\n\n const validation = validateConfig(config);\n if (!validation.valid) {\n logger.warn(`[Feishu] Invalid configuration: ${validation.error}`);\n return;\n }\n\n this.feishuConfig = config;\n\n // Initialize Lark SDK client\n this.client = new lark.Client({\n appId: config.appId,\n appSecret: config.appSecret,\n domain: config.domain === \"lark\" ? lark.Domain.Lark : lark.Domain.Feishu,\n loggerLevel: lark.LoggerLevel.warn,\n });\n\n this.messageManager = new MessageManager(this.client, runtime, config);\n }\n\n static async start(runtime: IAgentRuntime): Promise<Service> {\n const service = new FeishuService(runtime);\n\n if (!service.client || !service.feishuConfig) {\n logger.warn(\n \"[Feishu] Service started without client - no credentials provided\",\n );\n return service;\n }\n\n const maxRetries = 5;\n let retryCount = 0;\n let lastError: Error | null = null;\n\n while (retryCount < maxRetries) {\n try {\n logger.info(\n `[Feishu] Starting service for character ${runtime.character.name}`,\n );\n\n await service.initializeBot();\n await service.setupWebSocket();\n\n logger.success(`[Feishu] Service started successfully`);\n return service;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n logger.error(\n `[Feishu] Initialization attempt ${retryCount + 1} failed: ${lastError.message}`,\n );\n retryCount++;\n\n if (retryCount < maxRetries) {\n const delay = 2 ** retryCount * 1000;\n logger.info(`[Feishu] Retrying in ${delay / 1000} seconds...`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n logger.error(\n `[Feishu] Initialization failed after ${maxRetries} attempts. Last error: ${lastError?.message}`,\n );\n\n return service;\n }\n\n static async stop(runtime: IAgentRuntime): Promise<void> {\n const service = runtime.getService(FEISHU_SERVICE_NAME) as unknown as\n | FeishuService\n | undefined;\n if (service) {\n await service.stop();\n }\n }\n\n async stop(): Promise<void> {\n logger.info(\"[Feishu] Stopping service...\");\n\n if (this.wsClient) {\n try {\n // WSClient may not have a stop method in newer SDK versions\n const wsClientWithStop = this.wsClient as unknown as {\n stop?: () => Promise<void>;\n };\n if (typeof wsClientWithStop.stop === \"function\") {\n await wsClientWithStop.stop();\n }\n } catch (error) {\n logger.error(\n `[Feishu] Error stopping WebSocket client: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n this.wsClient = null;\n }\n\n this.client = null;\n logger.info(\"[Feishu] Service stopped\");\n }\n\n /**\n * Initializes the bot and fetches bot information.\n */\n private async initializeBot(): Promise<void> {\n if (!this.client) {\n throw new Error(\"Client not initialized\");\n }\n\n // Get bot info - the API path may vary by SDK version\n try {\n // Try to get bot info via the contact API\n const client = this.client as unknown as {\n bot?: {\n botInfo?: {\n get: (params: Record<string, unknown>) => Promise<{\n data?: { bot?: { open_id?: string; app_name?: string } };\n }>;\n };\n };\n contact?: {\n user?: {\n me?: (params: Record<string, unknown>) => Promise<{\n data?: { user?: { open_id?: string; name?: string } };\n }>;\n };\n };\n };\n\n if (client.bot?.botInfo?.get) {\n const botInfo = await client.bot.botInfo.get({});\n this.botOpenId = botInfo.data?.bot?.open_id || null;\n\n if (this.botOpenId && this.messageManager) {\n this.messageManager.setBotOpenId(this.botOpenId);\n }\n\n logger.info(\n `[Feishu] Bot initialized: ${botInfo.data?.bot?.app_name || \"Unknown\"}`,\n );\n } else {\n logger.warn(\n \"[Feishu] Bot info API not available, some features may not work\",\n );\n }\n } catch (error) {\n logger.error(\n `[Feishu] Failed to get bot info: ${error instanceof Error ? error.message : String(error)}`,\n );\n throw error;\n }\n }\n\n /**\n * Sets up WebSocket connection for receiving events.\n */\n private async setupWebSocket(): Promise<void> {\n if (!this.client || !this.feishuConfig || !this.runtime) {\n throw new Error(\"Client not initialized\");\n }\n\n const eventDispatcher = new lark.EventDispatcher({}).register({\n \"im.message.receive_v1\": async (data: unknown) => {\n await this.handleMessageEvent(data as FeishuEventData);\n return {};\n },\n \"im.chat.member.bot.added_v1\": async (data: unknown) => {\n await this.handleBotAddedEvent(data as FeishuEventData);\n return {};\n },\n \"im.chat.member.bot.deleted_v1\": async (data: unknown) => {\n await this.handleBotRemovedEvent(data as FeishuEventData);\n return {};\n },\n \"im.chat.member.user.added_v1\": async (data: unknown) => {\n await this.handleUserAddedEvent(data as FeishuEventData);\n return {};\n },\n \"im.chat.member.user.deleted_v1\": async (data: unknown) => {\n await this.handleUserRemovedEvent(data as FeishuEventData);\n return {};\n },\n });\n\n this.wsClient = new lark.WSClient({\n appId: this.feishuConfig.appId,\n appSecret: this.feishuConfig.appSecret,\n domain:\n this.feishuConfig.domain === \"lark\"\n ? lark.Domain.Lark\n : lark.Domain.Feishu,\n loggerLevel: lark.LoggerLevel.warn,\n });\n\n await this.wsClient.start({ eventDispatcher });\n\n // Emit connected event\n this.runtime.emitEvent(FeishuEventTypes.WORLD_CONNECTED, {\n runtime: this.runtime,\n source: \"feishu\",\n botOpenId: this.botOpenId,\n } as EventPayload);\n }\n\n /**\n * Handles incoming message events.\n */\n private async handleMessageEvent(event: FeishuEventData): Promise<void> {\n if (!this.messageManager) return;\n await this.messageManager.handleMessage(event);\n }\n\n /**\n * Handles bot added to chat events.\n */\n private async handleBotAddedEvent(event: FeishuEventData): Promise<void> {\n if (!this.runtime) return;\n\n try {\n const chatId = event.event?.chat_id as string | undefined;\n if (!chatId) return;\n\n const chat: FeishuChat = {\n chatId,\n chatType: FeishuChatType.GROUP,\n name: event.event?.chat_name as string | undefined,\n };\n\n this.knownChats.set(chatId, chat);\n\n // Create world and room\n const worldId = createUniqueUuid(this.runtime, chatId) as UUID;\n const roomId = createUniqueUuid(this.runtime, chatId) as UUID;\n\n const world: World = {\n id: worldId,\n name: chat.name || `Feishu Chat ${chatId}`,\n agentId: this.runtime.agentId,\n messageServerId: worldId,\n metadata: {\n extra: {\n chatType: chat.chatType,\n },\n },\n };\n\n await this.runtime.ensureWorldExists(world);\n\n const room: Room = {\n id: roomId,\n name: chat.name || `Feishu Chat ${chatId}`,\n source: \"feishu\",\n type: ChannelType.GROUP,\n channelId: chatId,\n messageServerId: worldId,\n worldId,\n };\n\n await this.runtime.ensureRoomExists(room);\n\n const payload: FeishuWorldPayload = {\n runtime: this.runtime,\n world,\n rooms: [room],\n entities: [],\n source: \"feishu\",\n chat,\n botOpenId: this.botOpenId || undefined,\n };\n\n this.runtime.emitEvent(\n FeishuEventTypes.WORLD_JOINED,\n payload as EventPayload,\n );\n this.runtime.emitEvent(EventType.WORLD_JOINED, {\n runtime: this.runtime,\n world,\n rooms: [room],\n entities: [],\n source: \"feishu\",\n } as EventPayload);\n\n logger.info(`[Feishu] Bot added to chat: ${chat.name || chatId}`);\n } catch (error) {\n logger.error(\n `[Feishu] Error handling bot added event: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n /**\n * Handles bot removed from chat events.\n */\n private async handleBotRemovedEvent(event: FeishuEventData): Promise<void> {\n if (!this.runtime) return;\n\n try {\n const chatId = event.event?.chat_id as string | undefined;\n if (!chatId) return;\n\n const chat = this.knownChats.get(chatId) || {\n chatId,\n chatType: FeishuChatType.GROUP,\n };\n\n this.knownChats.delete(chatId);\n\n this.runtime.emitEvent(FeishuEventTypes.WORLD_LEFT, {\n runtime: this.runtime,\n source: \"feishu\",\n chat,\n botOpenId: this.botOpenId,\n } as EventPayload);\n\n logger.info(`[Feishu] Bot removed from chat: ${chatId}`);\n } catch (error) {\n logger.error(\n `[Feishu] Error handling bot removed event: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n /**\n * Handles user added to chat events.\n */\n private async handleUserAddedEvent(event: FeishuEventData): Promise<void> {\n if (!this.runtime) return;\n\n try {\n const chatId = event.event?.chat_id as string | undefined;\n const users = event.event?.users as\n | Array<{ user_id?: { open_id?: string }; name?: string }>\n | undefined;\n\n if (!chatId || !users) return;\n\n for (const user of users) {\n const openId = user.user_id?.open_id;\n if (!openId) continue;\n\n this.runtime.emitEvent(FeishuEventTypes.ENTITY_JOINED, {\n runtime: this.runtime,\n source: \"feishu\",\n feishuUser: {\n openId,\n name: user.name,\n },\n chat: this.knownChats.get(chatId) || {\n chatId,\n chatType: FeishuChatType.GROUP,\n },\n } as EventPayload);\n }\n } catch (error) {\n logger.error(\n `[Feishu] Error handling user added event: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n /**\n * Handles user removed from chat events.\n */\n private async handleUserRemovedEvent(event: FeishuEventData): Promise<void> {\n if (!this.runtime) return;\n\n try {\n const chatId = event.event?.chat_id as string | undefined;\n const users = event.event?.users as\n | Array<{ user_id?: { open_id?: string }; name?: string }>\n | undefined;\n\n if (!chatId || !users) return;\n\n for (const user of users) {\n const openId = user.user_id?.open_id;\n if (!openId) continue;\n\n this.runtime.emitEvent(FeishuEventTypes.ENTITY_LEFT, {\n runtime: this.runtime,\n source: \"feishu\",\n feishuUser: {\n openId,\n name: user.name,\n },\n chat: this.knownChats.get(chatId) || {\n chatId,\n chatType: FeishuChatType.GROUP,\n },\n } as EventPayload);\n }\n } catch (error) {\n logger.error(\n `[Feishu] Error handling user removed event: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n /**\n * Registers send handlers for the service.\n */\n static registerSendHandlers(\n runtime: IAgentRuntime,\n serviceInstance: FeishuService,\n ): void {\n if (serviceInstance?.client && serviceInstance?.messageManager) {\n runtime.registerSendHandler(\n \"feishu\",\n serviceInstance.handleSendMessage.bind(serviceInstance),\n );\n logger.info(\"[Feishu] Registered send handler\");\n } else {\n logger.warn(\n \"[Feishu] Cannot register send handler - client not initialized\",\n );\n }\n }\n\n /**\n * Handles sending messages through the service.\n */\n async handleSendMessage(\n runtime: IAgentRuntime,\n target: TargetInfo,\n content: Content,\n ): Promise<void> {\n if (!this.messageManager) {\n logger.error(\"[Feishu] Message manager not initialized\");\n throw new Error(\"Feishu message manager is not initialized\");\n }\n\n let chatId: string | undefined;\n\n if (target.channelId) {\n chatId = target.channelId;\n } else if (target.roomId) {\n const room = await runtime.getRoom(target.roomId);\n chatId = room?.channelId;\n if (!chatId) {\n throw new Error(\n `Could not resolve Feishu chat ID from roomId ${target.roomId}`,\n );\n }\n } else {\n throw new Error(\"Feishu SendHandler requires channelId or roomId\");\n }\n\n if (!chatId) {\n throw new Error(\n `Could not determine target Feishu chat ID for target: ${JSON.stringify(target)}`,\n );\n }\n\n // Build Feishu content from the base content\n const feishuContent: FeishuMessageContent = {\n text: content.text || \"\",\n };\n\n // Copy over Feishu-specific fields if present\n // Card can be passed via data.card or metadata\n const contentData = content.data as Record<string, unknown> | undefined;\n if (contentData?.card) {\n feishuContent.card = contentData.card as FeishuMessageContent[\"card\"];\n }\n if (contentData?.imageKey) {\n feishuContent.imageKey = contentData.imageKey as string;\n }\n if (contentData?.fileKey) {\n feishuContent.fileKey = contentData.fileKey as string;\n }\n\n await this.messageManager.sendMessage(chatId, feishuContent);\n logger.info(`[Feishu] Message sent to chat ID: ${chatId}`);\n }\n}\n",
|
|
12
|
-
"import type { IAgentRuntime } from \"@elizaos/core\";\n\n/**\n * Default account identifier used when no specific account is configured\n */\nexport const DEFAULT_ACCOUNT_ID = \"default\";\n\n/**\n * Token source indicator\n */\nexport type FeishuTokenSource = \"config\" | \"env\" | \"character\" | \"none\";\n\n/**\n * Group-specific configuration\n */\nexport interface FeishuGroupConfig {\n /** If false, ignore messages from this group */\n enabled?: boolean;\n /** Allowlist for users in this group */\n allowFrom?: Array<string | number>;\n /** Require bot mention to respond */\n requireMention?: boolean;\n /** Custom system prompt for this group */\n systemPrompt?: string;\n /** Skills enabled for this group */\n skills?: string[];\n}\n\n/**\n * Configuration for a single Feishu account\n */\nexport interface FeishuAccountConfig {\n /** Optional display name for this account */\n name?: string;\n /** Bot display name */\n botName?: string;\n /** If false, do not start this Feishu account */\n enabled?: boolean;\n /** Feishu App ID */\n appId?: string;\n /** Feishu App Secret */\n appSecret?: string;\n /** Path to file containing app secret */\n appSecretFile?: string;\n /** Encrypt key for event callback */\n encryptKey?: string;\n /** Verification token for event callback */\n verificationToken?: string;\n /** Base API URL (for self-hosted Feishu) */\n apiUrl?: string;\n /** Allowlist for DM senders */\n allowFrom?: Array<string | number>;\n /** Allowlist for groups */\n groupAllowFrom?: Array<string | number>;\n /** DM access policy */\n dmPolicy?: \"open\" | \"allowlist\" | \"pairing\" | \"disabled\";\n /** Group message access policy */\n groupPolicy?: \"open\" | \"allowlist\" | \"disabled\";\n /** Max media size in MB */\n mediaMaxMb?: number;\n /** Text chunk limit for messages */\n textChunkLimit?: number;\n /** Webhook path for event callbacks */\n webhookPath?: string;\n /** Group-specific configurations */\n groups?: Record<string, FeishuGroupConfig>;\n}\n\n/**\n * Multi-account Feishu configuration structure\n */\nexport interface FeishuMultiAccountConfig {\n /** Default/base configuration applied to all accounts */\n enabled?: boolean;\n appId?: string;\n appSecret?: string;\n appSecretFile?: string;\n encryptKey?: string;\n verificationToken?: string;\n apiUrl?: string;\n dmPolicy?: \"open\" | \"allowlist\" | \"pairing\" | \"disabled\";\n groupPolicy?: \"open\" | \"allowlist\" | \"disabled\";\n mediaMaxMb?: number;\n textChunkLimit?: number;\n webhookPath?: string;\n /** Per-account configuration overrides */\n accounts?: Record<string, FeishuAccountConfig>;\n /** Group configurations at base level */\n groups?: Record<string, FeishuGroupConfig>;\n}\n\n/**\n * Resolved Feishu account with all configuration merged\n */\nexport interface ResolvedFeishuAccount {\n accountId: string;\n enabled: boolean;\n name?: string;\n appId: string;\n appSecret: string;\n tokenSource: FeishuTokenSource;\n configured: boolean;\n config: FeishuAccountConfig;\n}\n\n/**\n * Normalizes an account ID, returning the default if not provided\n */\nexport function normalizeAccountId(accountId?: string | null): string {\n if (!accountId || typeof accountId !== \"string\") {\n return DEFAULT_ACCOUNT_ID;\n }\n const trimmed = accountId.trim().toLowerCase();\n if (!trimmed || trimmed === \"default\") {\n return DEFAULT_ACCOUNT_ID;\n }\n return trimmed;\n}\n\n/**\n * Gets the multi-account configuration from runtime settings\n */\nexport function getMultiAccountConfig(\n runtime: IAgentRuntime,\n): FeishuMultiAccountConfig {\n const characterFeishu = runtime.character?.settings?.feishu as\n | FeishuMultiAccountConfig\n | undefined;\n\n return {\n enabled: characterFeishu?.enabled,\n appId: characterFeishu?.appId,\n appSecret: characterFeishu?.appSecret,\n appSecretFile: characterFeishu?.appSecretFile,\n encryptKey: characterFeishu?.encryptKey,\n verificationToken: characterFeishu?.verificationToken,\n apiUrl: characterFeishu?.apiUrl,\n dmPolicy: characterFeishu?.dmPolicy,\n groupPolicy: characterFeishu?.groupPolicy,\n mediaMaxMb: characterFeishu?.mediaMaxMb,\n textChunkLimit: characterFeishu?.textChunkLimit,\n webhookPath: characterFeishu?.webhookPath,\n accounts: characterFeishu?.accounts,\n groups: characterFeishu?.groups,\n };\n}\n\n/**\n * Lists all configured account IDs\n */\nexport function listFeishuAccountIds(runtime: IAgentRuntime): string[] {\n const config = getMultiAccountConfig(runtime);\n const accounts = config.accounts;\n const ids = new Set<string>();\n\n // Check if default account is configured\n const envAppId = runtime.getSetting(\"FEISHU_APP_ID\") as string | undefined;\n const envAppSecret = runtime.getSetting(\"FEISHU_APP_SECRET\") as\n | string\n | undefined;\n\n const baseConfigured = Boolean(\n config.appId?.trim() && (config.appSecret?.trim() || config.appSecretFile),\n );\n const envConfigured = Boolean(envAppId?.trim() && envAppSecret?.trim());\n\n if (baseConfigured || envConfigured) {\n ids.add(DEFAULT_ACCOUNT_ID);\n }\n\n // Add named accounts\n if (accounts && typeof accounts === \"object\") {\n for (const id of Object.keys(accounts)) {\n if (id) {\n ids.add(normalizeAccountId(id));\n }\n }\n }\n\n const result = Array.from(ids);\n if (result.length === 0) {\n return [DEFAULT_ACCOUNT_ID];\n }\n\n return result.toSorted((a, b) => a.localeCompare(b));\n}\n\n/**\n * Resolves the default account ID to use\n */\nexport function resolveDefaultFeishuAccountId(runtime: IAgentRuntime): string {\n const ids = listFeishuAccountIds(runtime);\n if (ids.includes(DEFAULT_ACCOUNT_ID)) {\n return DEFAULT_ACCOUNT_ID;\n }\n return ids[0] ?? DEFAULT_ACCOUNT_ID;\n}\n\n/**\n * Gets the account-specific configuration\n */\nfunction getAccountConfig(\n runtime: IAgentRuntime,\n accountId: string,\n): FeishuAccountConfig | undefined {\n const config = getMultiAccountConfig(runtime);\n const accounts = config.accounts;\n\n if (!accounts || typeof accounts !== \"object\") {\n return undefined;\n }\n\n // Try direct match first\n const direct = accounts[accountId];\n if (direct) {\n return direct;\n }\n\n // Try normalized match\n const normalized = normalizeAccountId(accountId);\n const matchKey = Object.keys(accounts).find(\n (key) => normalizeAccountId(key) === normalized,\n );\n return matchKey ? accounts[matchKey] : undefined;\n}\n\n/**\n * Merges base configuration with account-specific overrides\n */\nfunction mergeFeishuAccountConfig(\n runtime: IAgentRuntime,\n accountId: string,\n): FeishuAccountConfig {\n const multiConfig = getMultiAccountConfig(runtime);\n const { accounts: _ignored, ...baseConfig } = multiConfig;\n const accountConfig = getAccountConfig(runtime, accountId) ?? {};\n\n // Get environment/runtime settings for the base config\n const envAppId = runtime.getSetting(\"FEISHU_APP_ID\") as string | undefined;\n const envAppSecret = runtime.getSetting(\"FEISHU_APP_SECRET\") as\n | string\n | undefined;\n const envEncryptKey = runtime.getSetting(\"FEISHU_ENCRYPT_KEY\") as\n | string\n | undefined;\n const envVerificationToken = runtime.getSetting(\n \"FEISHU_VERIFICATION_TOKEN\",\n ) as string | undefined;\n const envDmPolicy = runtime.getSetting(\"FEISHU_DM_POLICY\") as\n | string\n | undefined;\n const envGroupPolicy = runtime.getSetting(\"FEISHU_GROUP_POLICY\") as\n | string\n | undefined;\n\n const envConfig: FeishuAccountConfig = {\n appId: envAppId || undefined,\n appSecret: envAppSecret || undefined,\n encryptKey: envEncryptKey || undefined,\n verificationToken: envVerificationToken || undefined,\n dmPolicy: envDmPolicy as FeishuAccountConfig[\"dmPolicy\"] | undefined,\n groupPolicy: envGroupPolicy as\n | FeishuAccountConfig[\"groupPolicy\"]\n | undefined,\n };\n\n // Merge order: env defaults < base config < account config\n return {\n ...envConfig,\n ...baseConfig,\n ...accountConfig,\n };\n}\n\n/**\n * Resolves a complete Feishu account configuration\n */\nexport function resolveFeishuAccount(\n runtime: IAgentRuntime,\n accountId?: string | null,\n): ResolvedFeishuAccount {\n const normalizedAccountId = normalizeAccountId(accountId);\n const multiConfig = getMultiAccountConfig(runtime);\n\n const baseEnabled = multiConfig.enabled !== false;\n const merged = mergeFeishuAccountConfig(runtime, normalizedAccountId);\n const accountEnabled = merged.enabled !== false;\n const enabled = baseEnabled && accountEnabled;\n\n const appId = merged.appId?.trim() || \"\";\n const appSecret = merged.appSecret?.trim() || \"\";\n\n // Determine token source\n let tokenSource: FeishuTokenSource = \"none\";\n if (merged.appSecret?.trim()) {\n tokenSource = \"config\";\n } else {\n const envAppSecret = runtime.getSetting(\"FEISHU_APP_SECRET\") as\n | string\n | undefined;\n if (envAppSecret?.trim()) {\n tokenSource = \"env\";\n }\n }\n\n if (!appId || !appSecret) {\n tokenSource = \"none\";\n }\n\n // Determine if this account is actually configured\n const configured = Boolean(appId && appSecret);\n\n const name = merged.name?.trim() || merged.botName?.trim() || undefined;\n\n return {\n accountId: normalizedAccountId,\n enabled,\n name,\n appId,\n appSecret,\n tokenSource,\n configured,\n config: merged,\n };\n}\n\n/**\n * Lists all enabled Feishu accounts\n */\nexport function listEnabledFeishuAccounts(\n runtime: IAgentRuntime,\n): ResolvedFeishuAccount[] {\n return listFeishuAccountIds(runtime)\n .map((accountId) => resolveFeishuAccount(runtime, accountId))\n .filter((account) => account.enabled && account.configured);\n}\n\n/**\n * Checks if multi-account mode is enabled\n */\nexport function isMultiAccountEnabled(runtime: IAgentRuntime): boolean {\n const accounts = listEnabledFeishuAccounts(runtime);\n return accounts.length > 1;\n}\n\n/**\n * Resolves group configuration for a specific group\n */\nexport function resolveFeishuGroupConfig(\n runtime: IAgentRuntime,\n accountId: string,\n groupId: string,\n): FeishuGroupConfig | undefined {\n const multiConfig = getMultiAccountConfig(runtime);\n const accountConfig = getAccountConfig(runtime, accountId);\n\n // Check account-level groups first\n const accountGroup = accountConfig?.groups?.[groupId];\n if (accountGroup) {\n return accountGroup;\n }\n\n // Fall back to base-level groups\n return multiConfig.groups?.[groupId];\n}\n\n/**\n * Checks if a user is allowed based on policy and allowlist\n */\nexport function isFeishuUserAllowed(params: {\n userId: string;\n accountConfig: FeishuAccountConfig;\n isGroup: boolean;\n groupId?: string;\n groupConfig?: FeishuGroupConfig;\n}): boolean {\n const { userId, accountConfig, isGroup, groupConfig } = params;\n\n if (isGroup) {\n const policy = accountConfig.groupPolicy ?? \"allowlist\";\n if (policy === \"disabled\") {\n return false;\n }\n\n if (policy === \"open\") {\n return true;\n }\n\n // Check group-specific allowlist first\n if (groupConfig?.allowFrom?.length) {\n return groupConfig.allowFrom.some(\n (allowed) => String(allowed) === userId,\n );\n }\n\n // Check account-level group allowlist\n if (accountConfig.groupAllowFrom?.length) {\n return accountConfig.groupAllowFrom.some(\n (allowed) => String(allowed) === userId,\n );\n }\n\n return policy !== \"allowlist\";\n }\n\n // DM handling\n const policy = accountConfig.dmPolicy ?? \"pairing\";\n if (policy === \"disabled\") {\n return false;\n }\n\n if (policy === \"open\") {\n return true;\n }\n\n if (policy === \"pairing\") {\n return true;\n }\n\n // Allowlist policy\n if (accountConfig.allowFrom?.length) {\n return accountConfig.allowFrom.some(\n (allowed) => String(allowed) === userId,\n );\n }\n\n return false;\n}\n\n/**\n * Checks if mention is required in a group\n */\nexport function isFeishuMentionRequired(params: {\n accountConfig: FeishuAccountConfig;\n groupConfig?: FeishuGroupConfig;\n}): boolean {\n const { groupConfig } = params;\n return groupConfig?.requireMention ?? false;\n}\n",
|
|
13
|
-
"/**\n * Feishu text chunk limit\n */\nexport const FEISHU_TEXT_CHUNK_LIMIT = 4000;\n\n/**\n * Feishu Post (rich text) element types\n */\nexport type FeishuPostElement =\n | { tag: \"text\"; text: string; style?: string[] }\n | { tag: \"a\"; text: string; href: string; style?: string[] }\n | { tag: \"at\"; user_id: string }\n | { tag: \"img\"; image_key: string }\n | { tag: \"media\"; file_key: string }\n | { tag: \"emotion\"; emoji_type: string };\n\n/**\n * A line of Feishu Post content\n */\nexport type FeishuPostLine = FeishuPostElement[];\n\n/**\n * Feishu Post content structure\n */\nexport interface FeishuPostContent {\n zh_cn?: {\n title?: string;\n content: FeishuPostLine[];\n };\n en_us?: {\n title?: string;\n content: FeishuPostLine[];\n };\n}\n\n/**\n * Result of formatting markdown for Feishu\n */\nexport interface FeishuFormattedChunk {\n post: FeishuPostContent;\n text: string;\n}\n\n/**\n * Style state for text formatting\n */\ninterface StyleState {\n bold: boolean;\n italic: boolean;\n strikethrough: boolean;\n code: boolean;\n}\n\n/**\n * Link span information\n */\ninterface LinkSpan {\n start: number;\n end: number;\n href: string;\n text: string;\n}\n\n/**\n * Style span information\n */\ninterface StyleSpan {\n start: number;\n end: number;\n style: \"bold\" | \"italic\" | \"strikethrough\" | \"code\";\n}\n\n/**\n * Intermediate representation of parsed markdown\n */\ninterface MarkdownIR {\n text: string;\n styles: StyleSpan[];\n links: LinkSpan[];\n}\n\n/**\n * Options for text chunking\n */\nexport interface ChunkFeishuTextOpts {\n limit?: number;\n}\n\n/**\n * Parse markdown to intermediate representation\n */\nfunction parseMarkdownToIR(markdown: string): MarkdownIR {\n const styles: StyleSpan[] = [];\n const links: LinkSpan[] = [];\n let text = markdown;\n\n // Process links first [text](url)\n const linkRegex = /\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\n const linkReplacements: {\n start: number;\n end: number;\n text: string;\n href: string;\n }[] = [];\n\n let linkMatch = linkRegex.exec(markdown);\n while (linkMatch !== null) {\n linkReplacements.push({\n start: linkMatch.index,\n end: linkMatch.index + linkMatch[0].length,\n text: linkMatch[1],\n href: linkMatch[2],\n });\n linkMatch = linkRegex.exec(markdown);\n }\n\n // Apply link replacements in reverse order\n let offset = 0;\n for (const repl of linkReplacements) {\n const before = text.slice(0, repl.start + offset);\n const after = text.slice(repl.end + offset);\n text = before + repl.text + after;\n\n links.push({\n start: repl.start + offset,\n end: repl.start + offset + repl.text.length,\n href: repl.href,\n text: repl.text,\n });\n\n offset += repl.text.length - (repl.end - repl.start);\n }\n\n // Process bold **text** or __text__\n text = processStyle(text, /\\*\\*([^*]+)\\*\\*/g, \"bold\", styles);\n text = processStyle(text, /__([^_]+)__/g, \"bold\", styles);\n\n // Process italic *text* or _text_\n text = processStyle(\n text,\n /(?<!\\*)\\*(?!\\*)([^*]+)(?<!\\*)\\*(?!\\*)/g,\n \"italic\",\n styles,\n );\n text = processStyle(\n text,\n /(?<!_)_(?!_)([^_]+)(?<!_)_(?!_)/g,\n \"italic\",\n styles,\n );\n\n // Process strikethrough ~~text~~\n text = processStyle(text, /~~([^~]+)~~/g, \"strikethrough\", styles);\n\n // Process inline code `text`\n text = processStyle(text, /`([^`]+)`/g, \"code\", styles);\n\n // Process code blocks ```text```\n text = text.replace(/```(\\w*)\\n?([\\s\\S]*?)```/g, (_, _lang, code) => {\n const start = text.indexOf(_);\n const trimmedCode = code.trim();\n styles.push({\n start,\n end: start + trimmedCode.length,\n style: \"code\",\n });\n return trimmedCode;\n });\n\n // Remove markdown headers\n text = text.replace(/^#{1,6}\\s+/gm, \"\");\n\n // Remove blockquote markers\n text = text.replace(/^>\\s?/gm, \"| \");\n\n // Clean up\n text = text.replace(/\\n{3,}/g, \"\\n\\n\").trim();\n\n return { text, styles, links };\n}\n\n/**\n * Process a style pattern and update the text and styles\n */\nfunction processStyle(\n text: string,\n pattern: RegExp,\n style: StyleSpan[\"style\"],\n styles: StyleSpan[],\n): string {\n let result = text;\n const matches: { index: number; fullLength: number; content: string }[] = [];\n\n let match = pattern.exec(text);\n while (match !== null) {\n matches.push({\n index: match.index,\n fullLength: match[0].length,\n content: match[1],\n });\n match = pattern.exec(text);\n }\n\n // Process in reverse to maintain indices\n let offset = 0;\n for (const m of matches) {\n const before = result.slice(0, m.index + offset);\n const after = result.slice(m.index + offset + m.fullLength);\n result = before + m.content + after;\n\n styles.push({\n start: m.index + offset,\n end: m.index + offset + m.content.length,\n style,\n });\n\n offset += m.content.length - m.fullLength;\n }\n\n return result;\n}\n\n/**\n * Build style ranges for quick lookup\n */\nfunction buildStyleRanges(\n styles: StyleSpan[],\n textLength: number,\n): StyleState[] {\n const ranges: StyleState[] = Array(textLength)\n .fill(null)\n .map(() => ({\n bold: false,\n italic: false,\n strikethrough: false,\n code: false,\n }));\n\n for (const span of styles) {\n for (let i = span.start; i < span.end && i < textLength; i++) {\n switch (span.style) {\n case \"bold\":\n ranges[i].bold = true;\n break;\n case \"italic\":\n ranges[i].italic = true;\n break;\n case \"strikethrough\":\n ranges[i].strikethrough = true;\n break;\n case \"code\":\n ranges[i].code = true;\n break;\n }\n }\n }\n\n return ranges;\n}\n\n/**\n * Build link map for quick lookup\n */\nfunction buildLinkMap(links: LinkSpan[]): Map<number, string> {\n const map = new Map<number, string>();\n for (const link of links) {\n for (let i = link.start; i < link.end; i++) {\n map.set(i, link.href);\n }\n }\n return map;\n}\n\n/**\n * Get styles at a specific position\n */\nfunction getStylesAt(ranges: StyleState[], pos: number): StyleState {\n return (\n ranges[pos] ?? {\n bold: false,\n italic: false,\n strikethrough: false,\n code: false,\n }\n );\n}\n\n/**\n * Get link at a specific position\n */\nfunction getLinkAt(\n linkMap: Map<number, string>,\n pos: number,\n): string | undefined {\n return linkMap.get(pos);\n}\n\n/**\n * Check if two style states are equal\n */\nfunction stylesEqual(a: StyleState, b: StyleState): boolean {\n return (\n a.bold === b.bold &&\n a.italic === b.italic &&\n a.strikethrough === b.strikethrough &&\n a.code === b.code\n );\n}\n\n/**\n * Create a Feishu Post element\n */\nfunction createPostElement(\n text: string,\n styles: StyleState,\n link?: string,\n): FeishuPostElement {\n const styleArray: string[] = [];\n\n if (styles.bold) {\n styleArray.push(\"bold\");\n }\n if (styles.italic) {\n styleArray.push(\"italic\");\n }\n if (styles.strikethrough) {\n styleArray.push(\"lineThrough\");\n }\n if (styles.code) {\n styleArray.push(\"code\");\n }\n\n if (link) {\n return {\n tag: \"a\",\n text,\n href: link,\n ...(styleArray.length > 0 ? { style: styleArray } : {}),\n };\n }\n\n return {\n tag: \"text\",\n text,\n ...(styleArray.length > 0 ? { style: styleArray } : {}),\n };\n}\n\n/**\n * Render markdown IR to Feishu Post format\n */\nfunction renderFeishuPost(ir: MarkdownIR): FeishuPostContent {\n const lines: FeishuPostLine[] = [];\n const text = ir.text;\n\n if (!text) {\n return { zh_cn: { content: [[{ tag: \"text\", text: \"\" }]] } };\n }\n\n const styleRanges = buildStyleRanges(ir.styles, text.length);\n const linkMap = buildLinkMap(ir.links);\n\n const textLines = text.split(\"\\n\");\n let charIndex = 0;\n\n for (const line of textLines) {\n const lineElements: FeishuPostElement[] = [];\n\n if (line.length === 0) {\n lineElements.push({ tag: \"text\", text: \"\" });\n } else {\n let segmentStart = charIndex;\n let currentStyles = getStylesAt(styleRanges, segmentStart);\n let currentLink = getLinkAt(linkMap, segmentStart);\n\n for (let i = 0; i < line.length; i++) {\n const pos = charIndex + i;\n const newStyles = getStylesAt(styleRanges, pos);\n const newLink = getLinkAt(linkMap, pos);\n\n const stylesChanged = !stylesEqual(currentStyles, newStyles);\n const linkChanged = currentLink !== newLink;\n\n if (stylesChanged || linkChanged) {\n const segmentText = text.slice(segmentStart, pos);\n if (segmentText) {\n lineElements.push(\n createPostElement(segmentText, currentStyles, currentLink),\n );\n }\n segmentStart = pos;\n currentStyles = newStyles;\n currentLink = newLink;\n }\n }\n\n const finalText = text.slice(segmentStart, charIndex + line.length);\n if (finalText) {\n lineElements.push(\n createPostElement(finalText, currentStyles, currentLink),\n );\n }\n }\n\n lines.push(\n lineElements.length > 0 ? lineElements : [{ tag: \"text\", text: \"\" }],\n );\n charIndex += line.length + 1;\n }\n\n return {\n zh_cn: {\n content: lines,\n },\n };\n}\n\n/**\n * Convert markdown to Feishu Post format\n */\nexport function markdownToFeishuPost(markdown: string): FeishuPostContent {\n const ir = parseMarkdownToIR(markdown ?? \"\");\n return renderFeishuPost(ir);\n}\n\n/**\n * Splits text at the last safe break point within the limit\n */\nfunction splitAtBreakPoint(\n text: string,\n limit: number,\n): { chunk: string; remainder: string } {\n if (text.length <= limit) {\n return { chunk: text, remainder: \"\" };\n }\n\n const searchArea = text.slice(0, limit);\n\n // Prefer double newlines (paragraph breaks)\n const doubleNewline = searchArea.lastIndexOf(\"\\n\\n\");\n if (doubleNewline > limit * 0.5) {\n return {\n chunk: text.slice(0, doubleNewline).trimEnd(),\n remainder: text.slice(doubleNewline + 2).trimStart(),\n };\n }\n\n // Try single newlines\n const singleNewline = searchArea.lastIndexOf(\"\\n\");\n if (singleNewline > limit * 0.5) {\n return {\n chunk: text.slice(0, singleNewline).trimEnd(),\n remainder: text.slice(singleNewline + 1).trimStart(),\n };\n }\n\n // Try sentence boundaries\n const sentenceEnd = Math.max(\n searchArea.lastIndexOf(\". \"),\n searchArea.lastIndexOf(\"! \"),\n searchArea.lastIndexOf(\"? \"),\n );\n if (sentenceEnd > limit * 0.5) {\n return {\n chunk: text.slice(0, sentenceEnd + 1).trimEnd(),\n remainder: text.slice(sentenceEnd + 2).trimStart(),\n };\n }\n\n // Try word boundaries\n const space = searchArea.lastIndexOf(\" \");\n if (space > limit * 0.5) {\n return {\n chunk: text.slice(0, space).trimEnd(),\n remainder: text.slice(space + 1).trimStart(),\n };\n }\n\n // Hard break at limit\n return {\n chunk: text.slice(0, limit),\n remainder: text.slice(limit),\n };\n}\n\n/**\n * Chunk text for Feishu messages\n */\nexport function chunkFeishuText(\n text: string,\n opts: ChunkFeishuTextOpts = {},\n): string[] {\n const limit = opts.limit ?? FEISHU_TEXT_CHUNK_LIMIT;\n\n if (!text?.trim()) {\n return [];\n }\n\n const normalizedText = text.trim();\n if (normalizedText.length <= limit) {\n return [normalizedText];\n }\n\n const chunks: string[] = [];\n let remaining = normalizedText;\n\n while (remaining.length > 0) {\n const { chunk, remainder } = splitAtBreakPoint(remaining, limit);\n if (chunk) {\n chunks.push(chunk);\n }\n remaining = remainder;\n }\n\n return chunks.filter((c) => c.length > 0);\n}\n\n/**\n * Convert markdown to Feishu Post chunks\n */\nexport function markdownToFeishuChunks(\n markdown: string,\n limit: number = FEISHU_TEXT_CHUNK_LIMIT,\n): FeishuFormattedChunk[] {\n const textChunks = chunkFeishuText(markdown, { limit });\n return textChunks.map((chunk) => ({\n post: markdownToFeishuPost(chunk),\n text: chunk,\n }));\n}\n\n/**\n * Check if text contains markdown formatting\n */\nexport function containsMarkdown(text: string): boolean {\n if (!text) {\n return false;\n }\n const markdownPatterns = [\n /\\*\\*[^*]+\\*\\*/,\n /\\*[^*]+\\*/,\n /~~[^~]+~~/,\n /`[^`]+`/,\n /```[\\s\\S]*```/,\n /\\[.+\\]\\(.+\\)/,\n /^#{1,6}\\s/m,\n /^[-*]\\s/m,\n /^\\d+\\.\\s/m,\n ];\n return markdownPatterns.some((pattern) => pattern.test(text));\n}\n\n/**\n * Strip markdown formatting from text\n */\nexport function stripMarkdown(text: string): string {\n let result = text;\n\n // Remove bold\n result = result.replace(/\\*\\*(.+?)\\*\\*/g, \"$1\");\n result = result.replace(/__(.+?)__/g, \"$1\");\n\n // Remove italic\n result = result.replace(/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, \"$1\");\n result = result.replace(/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g, \"$1\");\n\n // Remove strikethrough\n result = result.replace(/~~(.+?)~~/g, \"$1\");\n\n // Remove headers\n result = result.replace(/^#{1,6}\\s+(.+)$/gm, \"$1\");\n\n // Remove blockquotes\n result = result.replace(/^>\\s?(.*)$/gm, \"$1\");\n\n // Remove code blocks\n result = result.replace(/```(\\w*)\\n?([\\s\\S]*?)```/g, \"$2\");\n\n // Remove inline code\n result = result.replace(/`([^`]+)`/g, \"$1\");\n\n // Remove links - keep text\n result = result.replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, \"$1\");\n\n // Clean up\n result = result.replace(/\\n{3,}/g, \"\\n\\n\");\n result = result.trim();\n\n return result;\n}\n\n/**\n * Format Feishu user mention\n */\nexport function formatFeishuUserMention(userId: string): string {\n return `<at user_id=\"${userId}\"></at>`;\n}\n\n/**\n * Format Feishu user mention for all users\n */\nexport function formatFeishuAtAll(): string {\n return '<at user_id=\"all\"></at>';\n}\n\n/**\n * Truncate text to a maximum length\n */\nexport function truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) {\n return text;\n }\n if (maxLength <= 3) {\n return \"...\".slice(0, maxLength);\n }\n return `${text.slice(0, maxLength - 3)}...`;\n}\n\n/**\n * Resolve system location for logging\n */\nexport function resolveFeishuSystemLocation(params: {\n chatType: \"p2p\" | \"group\";\n chatId: string;\n chatName?: string;\n}): string {\n const { chatType, chatId, chatName } = params;\n const name = chatName || chatId.slice(0, 8);\n return `Feishu ${chatType}:${name}`;\n}\n\n/**\n * Check if chat is a group chat\n */\nexport function isGroupChat(chatType: string): boolean {\n return chatType === \"group\";\n}\n",
|
|
14
|
-
"import type { Plugin } from \"@elizaos/core\";\nimport { SEND_MESSAGE_ACTION, sendMessageAction } from \"./actions\";\nimport { FEISHU_SERVICE_NAME } from \"./constants\";\nimport { MessageManager } from \"./messageManager\";\nimport { CHAT_STATE_PROVIDER, chatStateProvider } from \"./providers\";\nimport { FeishuService } from \"./service\";\n\nconst feishuPlugin: Plugin = {\n name: FEISHU_SERVICE_NAME,\n description: \"Feishu/Lark client plugin for elizaOS\",\n services: [FeishuService],\n actions: [sendMessageAction],\n providers: [chatStateProvider],\n tests: [],\n};\n\nexport {\n FeishuService,\n MessageManager,\n sendMessageAction,\n SEND_MESSAGE_ACTION,\n chatStateProvider,\n CHAT_STATE_PROVIDER,\n FEISHU_SERVICE_NAME,\n};\n\n// Account management exports\nexport {\n DEFAULT_ACCOUNT_ID,\n type FeishuAccountConfig,\n type FeishuGroupConfig,\n type FeishuMultiAccountConfig,\n type FeishuTokenSource,\n isFeishuMentionRequired,\n isFeishuUserAllowed,\n isMultiAccountEnabled,\n listEnabledFeishuAccounts,\n listFeishuAccountIds,\n normalizeAccountId,\n type ResolvedFeishuAccount,\n resolveDefaultFeishuAccountId,\n resolveFeishuAccount,\n resolveFeishuGroupConfig,\n} from \"./accounts\";\nexport * from \"./constants\";\nexport * from \"./environment\";\n// Formatting exports\nexport {\n type ChunkFeishuTextOpts,\n chunkFeishuText,\n containsMarkdown,\n FEISHU_TEXT_CHUNK_LIMIT,\n type FeishuFormattedChunk,\n type FeishuPostContent,\n type FeishuPostElement,\n type FeishuPostLine,\n formatFeishuAtAll,\n formatFeishuUserMention,\n isGroupChat,\n markdownToFeishuChunks,\n markdownToFeishuPost,\n resolveFeishuSystemLocation,\n stripMarkdown,\n truncateText,\n} from \"./formatting\";\nexport * from \"./types\";\n\nexport default feishuPlugin;\n\n// Channel configuration types\nexport type {\n FeishuActionConfig,\n FeishuConfig,\n FeishuReactionNotificationMode,\n} from \"./config\";\n"
|
|
5
|
+
"import type { IAgentRuntime, Plugin } from \"@elizaos/core\";\nimport { getConnectorAccountManager, logger } from \"@elizaos/core\";\nimport { createFeishuConnectorAccountProvider } from \"./connector-account-provider\";\nimport { FEISHU_SERVICE_NAME } from \"./constants\";\nimport { MessageManager } from \"./messageManager\";\nimport { FeishuService } from \"./service\";\nimport { FeishuWorkflowCredentialProvider } from \"./workflow-credential-provider\";\n\nconst feishuPlugin: Plugin = {\n\tname: FEISHU_SERVICE_NAME,\n\tdescription: \"Feishu/Lark client plugin for elizaOS\",\n\tservices: [FeishuService, FeishuWorkflowCredentialProvider],\n\tactions: [],\n\tproviders: [],\n\ttests: [],\n\t// Self-declared auto-enable: activate when the \"feishu\" connector is\n\t// configured under config.connectors. The hardcoded CONNECTOR_PLUGINS map\n\t// in plugin-auto-enable-engine.ts still serves as a fallback.\n\tautoEnable: {\n\t\tconnectorKeys: [\"feishu\"],\n\t},\n\tinit: async (\n\t\t_config: Record<string, string>,\n\t\truntime: IAgentRuntime,\n\t): Promise<void> => {\n\t\ttry {\n\t\t\tconst manager = getConnectorAccountManager(runtime);\n\t\t\tmanager.registerProvider(createFeishuConnectorAccountProvider(runtime));\n\t\t} catch (err) {\n\t\t\tlogger.warn(\n\t\t\t\t{\n\t\t\t\t\tsrc: \"plugin:feishu\",\n\t\t\t\t\terr: err instanceof Error ? err.message : String(err),\n\t\t\t\t},\n\t\t\t\t\"Failed to register Feishu provider with ConnectorAccountManager\",\n\t\t\t);\n\t\t}\n\t},\n};\n\n// Account management exports\nexport {\n\tDEFAULT_ACCOUNT_ID,\n\ttype FeishuAccountConfig,\n\ttype FeishuGroupConfig,\n\ttype FeishuMultiAccountConfig,\n\ttype FeishuTokenSource,\n\tisFeishuMentionRequired,\n\tisFeishuUserAllowed,\n\tisMultiAccountEnabled,\n\tlistEnabledFeishuAccounts,\n\tlistFeishuAccountIds,\n\tnormalizeAccountId,\n\ttype ResolvedFeishuAccount,\n\tresolveDefaultFeishuAccountId,\n\tresolveFeishuAccount,\n\tresolveFeishuGroupConfig,\n} from \"./accounts\";\nexport * from \"./constants\";\nexport * from \"./environment\";\n// Formatting exports\nexport {\n\ttype ChunkFeishuTextOpts,\n\tchunkFeishuText,\n\tcontainsMarkdown,\n\tFEISHU_TEXT_CHUNK_LIMIT,\n\ttype FeishuFormattedChunk,\n\ttype FeishuPostContent,\n\ttype FeishuPostElement,\n\ttype FeishuPostLine,\n\tformatFeishuAtAll,\n\tformatFeishuUserMention,\n\tisGroupChat,\n\tmarkdownToFeishuChunks,\n\tmarkdownToFeishuPost,\n\tresolveFeishuSystemLocation,\n\tstripMarkdown,\n\ttruncateText,\n} from \"./formatting\";\nexport * from \"./types\";\nexport { FEISHU_SERVICE_NAME, FeishuService, MessageManager };\n\nexport default feishuPlugin;\n\n// Channel configuration types\nexport type {\n\tFeishuActionConfig,\n\tFeishuConfig,\n\tFeishuReactionNotificationMode,\n} from \"./config\";\n",
|
|
6
|
+
"import type { IAgentRuntime } from \"@elizaos/core\";\n\n/**\n * Default account identifier used when no specific account is configured\n */\nexport const DEFAULT_ACCOUNT_ID = \"default\";\n\n/**\n * Token source indicator\n */\nexport type FeishuTokenSource = \"config\" | \"env\" | \"character\" | \"none\";\n\n/**\n * Group-specific configuration\n */\nexport interface FeishuGroupConfig {\n\t/** If false, ignore messages from this group */\n\tenabled?: boolean;\n\t/** Allowlist for users in this group */\n\tallowFrom?: Array<string | number>;\n\t/** Require bot mention to respond */\n\trequireMention?: boolean;\n\t/** Custom system prompt for this group */\n\tsystemPrompt?: string;\n\t/** Skills enabled for this group */\n\tskills?: string[];\n}\n\n/**\n * Configuration for a single Feishu account\n */\nexport interface FeishuAccountConfig {\n\t/** Optional display name for this account */\n\tname?: string;\n\t/** Bot display name */\n\tbotName?: string;\n\t/** If false, do not start this Feishu account */\n\tenabled?: boolean;\n\t/** Feishu App ID */\n\tappId?: string;\n\t/** Feishu App Secret */\n\tappSecret?: string;\n\t/** Path to file containing app secret */\n\tappSecretFile?: string;\n\t/** Encrypt key for event callback */\n\tencryptKey?: string;\n\t/** Verification token for event callback */\n\tverificationToken?: string;\n\t/** Base API URL (for self-hosted Feishu) */\n\tapiUrl?: string;\n\t/** Allowlist for DM senders */\n\tallowFrom?: Array<string | number>;\n\t/** Allowlist for groups */\n\tgroupAllowFrom?: Array<string | number>;\n\t/** DM access policy */\n\tdmPolicy?: \"open\" | \"allowlist\" | \"pairing\" | \"disabled\";\n\t/** Group message access policy */\n\tgroupPolicy?: \"open\" | \"allowlist\" | \"disabled\";\n\t/** Max media size in MB */\n\tmediaMaxMb?: number;\n\t/** Text chunk limit for messages */\n\ttextChunkLimit?: number;\n\t/** Webhook path for event callbacks */\n\twebhookPath?: string;\n\t/** Group-specific configurations */\n\tgroups?: Record<string, FeishuGroupConfig>;\n}\n\n/**\n * Multi-account Feishu configuration structure\n */\nexport interface FeishuMultiAccountConfig {\n\t/** Default/base configuration applied to all accounts */\n\tenabled?: boolean;\n\tappId?: string;\n\tappSecret?: string;\n\tappSecretFile?: string;\n\tencryptKey?: string;\n\tverificationToken?: string;\n\tapiUrl?: string;\n\tdmPolicy?: \"open\" | \"allowlist\" | \"pairing\" | \"disabled\";\n\tgroupPolicy?: \"open\" | \"allowlist\" | \"disabled\";\n\tmediaMaxMb?: number;\n\ttextChunkLimit?: number;\n\twebhookPath?: string;\n\t/** Per-account configuration overrides */\n\taccounts?: Record<string, FeishuAccountConfig>;\n\t/** Group configurations at base level */\n\tgroups?: Record<string, FeishuGroupConfig>;\n}\n\n/**\n * Resolved Feishu account with all configuration merged\n */\nexport interface ResolvedFeishuAccount {\n\taccountId: string;\n\tenabled: boolean;\n\tname?: string;\n\tappId: string;\n\tappSecret: string;\n\ttokenSource: FeishuTokenSource;\n\tconfigured: boolean;\n\tconfig: FeishuAccountConfig;\n}\n\n/**\n * Normalizes an account ID, returning the default if not provided\n */\nexport function normalizeAccountId(accountId?: string | null): string {\n\tif (!accountId || typeof accountId !== \"string\") {\n\t\treturn DEFAULT_ACCOUNT_ID;\n\t}\n\tconst trimmed = accountId.trim().toLowerCase();\n\tif (!trimmed || trimmed === \"default\") {\n\t\treturn DEFAULT_ACCOUNT_ID;\n\t}\n\treturn trimmed;\n}\n\n/**\n * Gets the multi-account configuration from runtime settings\n */\nexport function getMultiAccountConfig(\n\truntime: IAgentRuntime,\n): FeishuMultiAccountConfig {\n\tconst characterFeishu = runtime.character?.settings?.feishu as\n\t\t| FeishuMultiAccountConfig\n\t\t| undefined;\n\n\treturn {\n\t\tenabled: characterFeishu?.enabled,\n\t\tappId: characterFeishu?.appId,\n\t\tappSecret: characterFeishu?.appSecret,\n\t\tappSecretFile: characterFeishu?.appSecretFile,\n\t\tencryptKey: characterFeishu?.encryptKey,\n\t\tverificationToken: characterFeishu?.verificationToken,\n\t\tapiUrl: characterFeishu?.apiUrl,\n\t\tdmPolicy: characterFeishu?.dmPolicy,\n\t\tgroupPolicy: characterFeishu?.groupPolicy,\n\t\tmediaMaxMb: characterFeishu?.mediaMaxMb,\n\t\ttextChunkLimit: characterFeishu?.textChunkLimit,\n\t\twebhookPath: characterFeishu?.webhookPath,\n\t\taccounts: characterFeishu?.accounts,\n\t\tgroups: characterFeishu?.groups,\n\t};\n}\n\n/**\n * Lists all configured account IDs\n */\nexport function listFeishuAccountIds(runtime: IAgentRuntime): string[] {\n\tconst config = getMultiAccountConfig(runtime);\n\tconst accounts = config.accounts;\n\tconst ids = new Set<string>();\n\n\t// Check if default account is configured\n\tconst envAppId = runtime.getSetting(\"FEISHU_APP_ID\") as string | undefined;\n\tconst envAppSecret = runtime.getSetting(\"FEISHU_APP_SECRET\") as\n\t\t| string\n\t\t| undefined;\n\n\tconst baseConfigured = Boolean(\n\t\tconfig.appId?.trim() && (config.appSecret?.trim() || config.appSecretFile),\n\t);\n\tconst envConfigured = Boolean(envAppId?.trim() && envAppSecret?.trim());\n\n\tif (baseConfigured || envConfigured) {\n\t\tids.add(DEFAULT_ACCOUNT_ID);\n\t}\n\n\t// Add named accounts\n\tif (accounts && typeof accounts === \"object\") {\n\t\tfor (const id of Object.keys(accounts)) {\n\t\t\tif (id) {\n\t\t\t\tids.add(normalizeAccountId(id));\n\t\t\t}\n\t\t}\n\t}\n\n\tconst result = Array.from(ids);\n\tif (result.length === 0) {\n\t\treturn [DEFAULT_ACCOUNT_ID];\n\t}\n\n\treturn result.toSorted((a, b) => a.localeCompare(b));\n}\n\n/**\n * Resolves the default account ID to use\n */\nexport function resolveDefaultFeishuAccountId(runtime: IAgentRuntime): string {\n\tconst ids = listFeishuAccountIds(runtime);\n\tif (ids.includes(DEFAULT_ACCOUNT_ID)) {\n\t\treturn DEFAULT_ACCOUNT_ID;\n\t}\n\treturn ids[0] ?? DEFAULT_ACCOUNT_ID;\n}\n\n/**\n * Gets the account-specific configuration\n */\nfunction getAccountConfig(\n\truntime: IAgentRuntime,\n\taccountId: string,\n): FeishuAccountConfig | undefined {\n\tconst config = getMultiAccountConfig(runtime);\n\tconst accounts = config.accounts;\n\n\tif (!accounts || typeof accounts !== \"object\") {\n\t\treturn undefined;\n\t}\n\n\t// Try direct match first\n\tconst direct = accounts[accountId];\n\tif (direct) {\n\t\treturn direct;\n\t}\n\n\t// Try normalized match\n\tconst normalized = normalizeAccountId(accountId);\n\tconst matchKey = Object.keys(accounts).find(\n\t\t(key) => normalizeAccountId(key) === normalized,\n\t);\n\treturn matchKey ? accounts[matchKey] : undefined;\n}\n\n/**\n * Merges base configuration with account-specific overrides\n */\nfunction mergeFeishuAccountConfig(\n\truntime: IAgentRuntime,\n\taccountId: string,\n): FeishuAccountConfig {\n\tconst multiConfig = getMultiAccountConfig(runtime);\n\tconst { accounts: _ignored, ...baseConfig } = multiConfig;\n\tconst accountConfig = getAccountConfig(runtime, accountId) ?? {};\n\n\t// Get environment/runtime settings for the base config\n\tconst envAppId = runtime.getSetting(\"FEISHU_APP_ID\") as string | undefined;\n\tconst envAppSecret = runtime.getSetting(\"FEISHU_APP_SECRET\") as\n\t\t| string\n\t\t| undefined;\n\tconst envEncryptKey = runtime.getSetting(\"FEISHU_ENCRYPT_KEY\") as\n\t\t| string\n\t\t| undefined;\n\tconst envVerificationToken = runtime.getSetting(\n\t\t\"FEISHU_VERIFICATION_TOKEN\",\n\t) as string | undefined;\n\tconst envDmPolicy = runtime.getSetting(\"FEISHU_DM_POLICY\") as\n\t\t| string\n\t\t| undefined;\n\tconst envGroupPolicy = runtime.getSetting(\"FEISHU_GROUP_POLICY\") as\n\t\t| string\n\t\t| undefined;\n\n\tconst envConfig: FeishuAccountConfig = {\n\t\tappId: envAppId || undefined,\n\t\tappSecret: envAppSecret || undefined,\n\t\tencryptKey: envEncryptKey || undefined,\n\t\tverificationToken: envVerificationToken || undefined,\n\t\tdmPolicy: envDmPolicy as FeishuAccountConfig[\"dmPolicy\"] | undefined,\n\t\tgroupPolicy: envGroupPolicy as\n\t\t\t| FeishuAccountConfig[\"groupPolicy\"]\n\t\t\t| undefined,\n\t};\n\n\t// Merge order: env defaults < base config < account config\n\treturn {\n\t\t...envConfig,\n\t\t...baseConfig,\n\t\t...accountConfig,\n\t};\n}\n\n/**\n * Resolves a complete Feishu account configuration\n */\nexport function resolveFeishuAccount(\n\truntime: IAgentRuntime,\n\taccountId?: string | null,\n): ResolvedFeishuAccount {\n\tconst normalizedAccountId = normalizeAccountId(accountId);\n\tconst multiConfig = getMultiAccountConfig(runtime);\n\n\tconst baseEnabled = multiConfig.enabled !== false;\n\tconst merged = mergeFeishuAccountConfig(runtime, normalizedAccountId);\n\tconst accountEnabled = merged.enabled !== false;\n\tconst enabled = baseEnabled && accountEnabled;\n\n\tconst appId = merged.appId?.trim() || \"\";\n\tconst appSecret = merged.appSecret?.trim() || \"\";\n\n\t// Determine token source\n\tlet tokenSource: FeishuTokenSource = \"none\";\n\tif (merged.appSecret?.trim()) {\n\t\ttokenSource = \"config\";\n\t} else {\n\t\tconst envAppSecret = runtime.getSetting(\"FEISHU_APP_SECRET\") as\n\t\t\t| string\n\t\t\t| undefined;\n\t\tif (envAppSecret?.trim()) {\n\t\t\ttokenSource = \"env\";\n\t\t}\n\t}\n\n\tif (!appId || !appSecret) {\n\t\ttokenSource = \"none\";\n\t}\n\n\t// Determine if this account is actually configured\n\tconst configured = Boolean(appId && appSecret);\n\n\tconst name = merged.name?.trim() || merged.botName?.trim() || undefined;\n\n\treturn {\n\t\taccountId: normalizedAccountId,\n\t\tenabled,\n\t\tname,\n\t\tappId,\n\t\tappSecret,\n\t\ttokenSource,\n\t\tconfigured,\n\t\tconfig: merged,\n\t};\n}\n\n/**\n * Lists all enabled Feishu accounts\n */\nexport function listEnabledFeishuAccounts(\n\truntime: IAgentRuntime,\n): ResolvedFeishuAccount[] {\n\treturn listFeishuAccountIds(runtime)\n\t\t.map((accountId) => resolveFeishuAccount(runtime, accountId))\n\t\t.filter((account) => account.enabled && account.configured);\n}\n\n/**\n * Checks if multi-account mode is enabled\n */\nexport function isMultiAccountEnabled(runtime: IAgentRuntime): boolean {\n\tconst accounts = listEnabledFeishuAccounts(runtime);\n\treturn accounts.length > 1;\n}\n\n/**\n * Resolves group configuration for a specific group\n */\nexport function resolveFeishuGroupConfig(\n\truntime: IAgentRuntime,\n\taccountId: string,\n\tgroupId: string,\n): FeishuGroupConfig | undefined {\n\tconst multiConfig = getMultiAccountConfig(runtime);\n\tconst accountConfig = getAccountConfig(runtime, accountId);\n\n\t// Check account-level groups first\n\tconst accountGroup = accountConfig?.groups?.[groupId];\n\tif (accountGroup) {\n\t\treturn accountGroup;\n\t}\n\n\t// Fall back to base-level groups\n\treturn multiConfig.groups?.[groupId];\n}\n\n/**\n * Checks if a user is allowed based on policy and allowlist\n */\nexport function isFeishuUserAllowed(params: {\n\tuserId: string;\n\taccountConfig: FeishuAccountConfig;\n\tisGroup: boolean;\n\tgroupId?: string;\n\tgroupConfig?: FeishuGroupConfig;\n}): boolean {\n\tconst { userId, accountConfig, isGroup, groupConfig } = params;\n\n\tif (isGroup) {\n\t\tconst policy = accountConfig.groupPolicy ?? \"allowlist\";\n\t\tif (policy === \"disabled\") {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (policy === \"open\") {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check group-specific allowlist first\n\t\tif (groupConfig?.allowFrom?.length) {\n\t\t\treturn groupConfig.allowFrom.some(\n\t\t\t\t(allowed) => String(allowed) === userId,\n\t\t\t);\n\t\t}\n\n\t\t// Check account-level group allowlist\n\t\tif (accountConfig.groupAllowFrom?.length) {\n\t\t\treturn accountConfig.groupAllowFrom.some(\n\t\t\t\t(allowed) => String(allowed) === userId,\n\t\t\t);\n\t\t}\n\n\t\treturn policy !== \"allowlist\";\n\t}\n\n\t// DM handling\n\tconst policy = accountConfig.dmPolicy ?? \"pairing\";\n\tif (policy === \"disabled\") {\n\t\treturn false;\n\t}\n\n\tif (policy === \"open\") {\n\t\treturn true;\n\t}\n\n\tif (policy === \"pairing\") {\n\t\treturn true;\n\t}\n\n\t// Allowlist policy\n\tif (accountConfig.allowFrom?.length) {\n\t\treturn accountConfig.allowFrom.some(\n\t\t\t(allowed) => String(allowed) === userId,\n\t\t);\n\t}\n\n\treturn false;\n}\n\n/**\n * Checks if mention is required in a group\n */\nexport function isFeishuMentionRequired(params: {\n\taccountConfig: FeishuAccountConfig;\n\tgroupConfig?: FeishuGroupConfig;\n}): boolean {\n\tconst { groupConfig } = params;\n\treturn groupConfig?.requireMention ?? false;\n}\n",
|
|
7
|
+
"/**\n * Feishu ConnectorAccountManager provider.\n *\n * Adapts the multi-account scaffolding in `accounts.ts` to the\n * `ConnectorAccountProvider` contract from\n * `@elizaos/core/connectors/account-manager`.\n *\n * Source of truth for accounts is character settings (`character.settings.feishu`)\n * plus env-var fallbacks (FEISHU_APP_ID, FEISHU_APP_SECRET). `listAccounts`\n * enumerates all configured/enabled accounts; single-account env-only\n * deployments still surface as a `default` account. AccountKey is the appId.\n */\n\nimport type {\n\tConnectorAccount,\n\tConnectorAccountManager,\n\tConnectorAccountPatch,\n\tConnectorAccountProvider,\n\tIAgentRuntime,\n} from \"@elizaos/core\";\nimport {\n\tDEFAULT_ACCOUNT_ID,\n\tlistEnabledFeishuAccounts,\n\tnormalizeAccountId,\n\ttype ResolvedFeishuAccount,\n\tresolveFeishuAccount,\n} from \"./accounts.js\";\n\nexport const FEISHU_PROVIDER_ID = \"feishu\";\n\nfunction purposeForAccount(_account: ResolvedFeishuAccount): string[] {\n\treturn [\"messaging\"];\n}\n\nfunction accessGateForAccount(account: ResolvedFeishuAccount): string {\n\tconst dmPolicy = account.config?.dmPolicy;\n\tif (dmPolicy === \"pairing\") return \"pairing\";\n\tif (dmPolicy === \"disabled\") return \"disabled\";\n\treturn \"open\";\n}\n\nfunction toConnectorAccount(account: ResolvedFeishuAccount): ConnectorAccount {\n\tconst now = Date.now();\n\treturn {\n\t\tid: normalizeAccountId(account.accountId),\n\t\tprovider: FEISHU_PROVIDER_ID,\n\t\tlabel: account.name ?? account.accountId,\n\t\trole: \"AGENT\",\n\t\tpurpose: purposeForAccount(account),\n\t\taccessGate: accessGateForAccount(account),\n\t\tstatus: account.enabled && account.configured ? \"connected\" : \"disabled\",\n\t\texternalId: account.appId || undefined,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t\tmetadata: {\n\t\t\ttokenSource: account.tokenSource,\n\t\t\tdmPolicy: account.config?.dmPolicy ?? \"open\",\n\t\t\tgroupPolicy: account.config?.groupPolicy ?? \"allowlist\",\n\t\t\tappId: account.appId || \"\",\n\t\t},\n\t};\n}\n\nexport function createFeishuConnectorAccountProvider(\n\truntime: IAgentRuntime,\n): ConnectorAccountProvider {\n\treturn {\n\t\tprovider: FEISHU_PROVIDER_ID,\n\t\tlabel: \"Feishu\",\n\t\tlistAccounts: async (\n\t\t\t_manager: ConnectorAccountManager,\n\t\t): Promise<ConnectorAccount[]> => {\n\t\t\tconst enabled = listEnabledFeishuAccounts(runtime);\n\t\t\tif (enabled.length > 0) {\n\t\t\t\treturn enabled.map(toConnectorAccount);\n\t\t\t}\n\t\t\tconst fallback = resolveFeishuAccount(runtime, DEFAULT_ACCOUNT_ID);\n\t\t\treturn [toConnectorAccount(fallback)];\n\t\t},\n\t\tcreateAccount: async (\n\t\t\tinput: ConnectorAccountPatch,\n\t\t\t_manager: ConnectorAccountManager,\n\t\t) => {\n\t\t\treturn {\n\t\t\t\t...input,\n\t\t\t\tprovider: FEISHU_PROVIDER_ID,\n\t\t\t\trole: input.role ?? \"AGENT\",\n\t\t\t\tpurpose: input.purpose ?? [\"messaging\"],\n\t\t\t\taccessGate: input.accessGate ?? \"open\",\n\t\t\t\tstatus: input.status ?? \"pending\",\n\t\t\t};\n\t\t},\n\t\tpatchAccount: async (\n\t\t\t_accountId: string,\n\t\t\tpatch: ConnectorAccountPatch,\n\t\t\t_manager: ConnectorAccountManager,\n\t\t) => {\n\t\t\treturn { ...patch, provider: FEISHU_PROVIDER_ID };\n\t\t},\n\t\tdeleteAccount: async (\n\t\t\t_accountId: string,\n\t\t\t_manager: ConnectorAccountManager,\n\t\t) => {\n\t\t\t// No-op at provider layer — runtime credentials live in character\n\t\t\t// settings; deletion of those is out of band.\n\t\t},\n\t};\n}\n",
|
|
8
|
+
"/**\n * Service name used to register and retrieve the Feishu service.\n */\nexport const FEISHU_SERVICE_NAME = \"feishu\";\n\n/**\n * Default API domains for Feishu and Lark.\n */\nexport const FEISHU_DOMAINS = {\n\tfeishu: \"https://open.feishu.cn\",\n\tlark: \"https://open.larksuite.com\",\n} as const;\n\n/**\n * Maximum message length for Feishu text messages.\n */\nexport const MAX_MESSAGE_LENGTH = 4000;\n\n/**\n * Default timeout for API requests in milliseconds.\n */\nexport const DEFAULT_TIMEOUT_MS = 30000;\n",
|
|
9
|
+
"import {\n\tChannelType,\n\tcreateUniqueUuid,\n\tEventType,\n\ttype IAgentRuntime,\n\tlogger,\n\ttype Memory,\n\ttype UUID,\n} from \"@elizaos/core\";\nimport type * as lark from \"@larksuiteoapi/node-sdk\";\nimport { MAX_MESSAGE_LENGTH } from \"./constants\";\nimport type { FeishuConfig } from \"./environment\";\nimport { isChatAllowed } from \"./environment\";\nimport type {\n\tFeishuChat,\n\tFeishuChatType,\n\tFeishuEventData,\n\tFeishuMessage,\n\tFeishuMessageContent,\n\tFeishuMessageReceivedPayload,\n\tFeishuUser,\n} from \"./types\";\nimport { FeishuEventTypes } from \"./types\";\n\n/**\n * Manages message handling for the Feishu service.\n */\nexport class MessageManager {\n\tprivate client: lark.Client;\n\tprivate runtime: IAgentRuntime;\n\tprivate config: FeishuConfig;\n\tprivate processedMessages: Set<string> = new Set();\n\tprivate botOpenId: string | null = null;\n\n\tconstructor(\n\t\tclient: lark.Client,\n\t\truntime: IAgentRuntime,\n\t\tconfig: FeishuConfig,\n\t) {\n\t\tthis.client = client;\n\t\tthis.runtime = runtime;\n\t\tthis.config = config;\n\t}\n\n\t/**\n\t * Sets the bot's open ID for mention detection.\n\t */\n\tsetBotOpenId(openId: string): void {\n\t\tthis.botOpenId = openId;\n\t}\n\n\t/**\n\t * Handles incoming message events.\n\t */\n\tasync handleMessage(event: FeishuEventData): Promise<void> {\n\t\ttry {\n\t\t\tconst message = event.event?.message as FeishuMessage | undefined;\n\t\t\tif (!message) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Deduplicate messages\n\t\t\tif (this.processedMessages.has(message.messageId)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.processedMessages.add(message.messageId);\n\n\t\t\t// Limit cache size\n\t\t\tif (this.processedMessages.size > 1000) {\n\t\t\t\tconst firstKey = this.processedMessages.values().next().value as string;\n\t\t\t\tthis.processedMessages.delete(firstKey);\n\t\t\t}\n\n\t\t\tconst chatId = message.chatId;\n\t\t\tconst chatType = (event.event?.chat_type || \"p2p\") as FeishuChatType;\n\n\t\t\t// Check if chat is allowed\n\t\t\tif (!isChatAllowed(this.config, chatId)) {\n\t\t\t\tlogger.debug(`[Feishu] Chat ${chatId} not authorized, skipping`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Parse sender information\n\t\t\tconst sender = this.parseSender(event);\n\n\t\t\t// Ignore bot messages if configured\n\t\t\tif (this.config.shouldIgnoreBotMessages && sender.isBot) {\n\t\t\t\tlogger.debug(\"[Feishu] Ignoring bot message\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Check for mentions if configured\n\t\t\tif (this.config.shouldRespondOnlyToMentions && chatType !== \"p2p\") {\n\t\t\t\tif (!this.isBotMentioned(message)) {\n\t\t\t\t\tlogger.debug(\"[Feishu] Bot not mentioned, skipping\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Parse message content\n\t\t\tconst text = this.parseMessageContent(message);\n\n\t\t\t// Build chat info\n\t\t\tconst chat: FeishuChat = {\n\t\t\t\tchatId,\n\t\t\t\tchatType: chatType as FeishuChatType,\n\t\t\t\tname: (event.event?.chat_name as string | undefined) || undefined,\n\t\t\t};\n\n\t\t\t// Create room and entity IDs\n\t\t\tconst roomId = createUniqueUuid(this.runtime, chatId) as UUID;\n\t\t\tconst entityId = createUniqueUuid(this.runtime, sender.openId) as UUID;\n\t\t\tconst worldId = createUniqueUuid(this.runtime, chatId) as UUID;\n\n\t\t\t// Ensure connection exists\n\t\t\tawait this.runtime.ensureConnection({\n\t\t\t\tentityId,\n\t\t\t\troomId,\n\t\t\t\tuserName: sender.name,\n\t\t\t\tuserId: sender.openId as UUID,\n\t\t\t\tname: sender.name || \"Unknown User\",\n\t\t\t\tsource: \"feishu\",\n\t\t\t\tchannelId: chatId,\n\t\t\t\tmessageServerId: worldId,\n\t\t\t\ttype: chatType === \"p2p\" ? ChannelType.DM : ChannelType.GROUP,\n\t\t\t\tworldId,\n\t\t\t});\n\n\t\t\t// Create memory for the message\n\t\t\tconst memory: Memory = {\n\t\t\t\tid: createUniqueUuid(this.runtime, message.messageId) as UUID,\n\t\t\t\tentityId,\n\t\t\t\troomId,\n\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\tcontent: {\n\t\t\t\t\ttext,\n\t\t\t\t\tsource: \"feishu\",\n\t\t\t\t\tchatId,\n\t\t\t\t\tmessageId: message.messageId,\n\t\t\t\t},\n\t\t\t\tcreatedAt: Number.parseInt(message.createTime, 10),\n\t\t\t};\n\n\t\t\t// Emit message received event\n\t\t\tconst payload: FeishuMessageReceivedPayload = {\n\t\t\t\truntime: this.runtime,\n\t\t\t\tmessage: memory,\n\t\t\t\tsource: \"feishu\",\n\t\t\t\toriginalMessage: message,\n\t\t\t\tchat,\n\t\t\t\tsender,\n\t\t\t};\n\n\t\t\tthis.runtime.emitEvent(FeishuEventTypes.MESSAGE_RECEIVED, payload);\n\t\t\tthis.runtime.emitEvent(EventType.MESSAGE_RECEIVED, payload);\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`[Feishu] Error handling message: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Sends a message to a chat.\n\t */\n\tasync sendMessage(\n\t\tchatId: string,\n\t\tcontent: FeishuMessageContent,\n\t): Promise<string[]> {\n\t\tconst messageIds: string[] = [];\n\n\t\ttry {\n\t\t\tconst text = content.text || \"\";\n\n\t\t\t// Handle card messages\n\t\t\tif (content.card) {\n\t\t\t\tconst response = await this.client.im.message.create({\n\t\t\t\t\tparams: { receive_id_type: \"chat_id\" },\n\t\t\t\t\tdata: {\n\t\t\t\t\t\treceive_id: chatId,\n\t\t\t\t\t\tmsg_type: \"interactive\",\n\t\t\t\t\t\tcontent: JSON.stringify(content.card),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tif (response.data?.message_id) {\n\t\t\t\t\tmessageIds.push(response.data.message_id);\n\t\t\t\t}\n\t\t\t\treturn messageIds;\n\t\t\t}\n\n\t\t\t// Handle image messages\n\t\t\tif (content.imageKey) {\n\t\t\t\tconst response = await this.client.im.message.create({\n\t\t\t\t\tparams: { receive_id_type: \"chat_id\" },\n\t\t\t\t\tdata: {\n\t\t\t\t\t\treceive_id: chatId,\n\t\t\t\t\t\tmsg_type: \"image\",\n\t\t\t\t\t\tcontent: JSON.stringify({ image_key: content.imageKey }),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tif (response.data?.message_id) {\n\t\t\t\t\tmessageIds.push(response.data.message_id);\n\t\t\t\t}\n\t\t\t\treturn messageIds;\n\t\t\t}\n\n\t\t\t// Split long messages\n\t\t\tconst parts = this.splitMessage(text);\n\n\t\t\tfor (const part of parts) {\n\t\t\t\tconst response = await this.client.im.message.create({\n\t\t\t\t\tparams: { receive_id_type: \"chat_id\" },\n\t\t\t\t\tdata: {\n\t\t\t\t\t\treceive_id: chatId,\n\t\t\t\t\t\tmsg_type: \"text\",\n\t\t\t\t\t\tcontent: JSON.stringify({ text: part }),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tif (response.data?.message_id) {\n\t\t\t\t\tmessageIds.push(response.data.message_id);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn messageIds;\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`[Feishu] Error sending message: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Replies to a specific message.\n\t */\n\tasync replyToMessage(\n\t\tmessageId: string,\n\t\tcontent: FeishuMessageContent,\n\t): Promise<string[]> {\n\t\tconst messageIds: string[] = [];\n\n\t\ttry {\n\t\t\tconst text = content.text || \"\";\n\t\t\tconst parts = this.splitMessage(text);\n\n\t\t\tfor (const part of parts) {\n\t\t\t\tconst response = await this.client.im.message.reply({\n\t\t\t\t\tpath: { message_id: messageId },\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tmsg_type: \"text\",\n\t\t\t\t\t\tcontent: JSON.stringify({ text: part }),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tif (response.data?.message_id) {\n\t\t\t\t\tmessageIds.push(response.data.message_id);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn messageIds;\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`[Feishu] Error replying to message: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Parses sender information from an event.\n\t */\n\tprivate parseSender(event: FeishuEventData): FeishuUser {\n\t\tconst sender = event.event?.sender as\n\t\t\t| {\n\t\t\t\t\tsender_id?: {\n\t\t\t\t\t\topen_id?: string;\n\t\t\t\t\t\tunion_id?: string;\n\t\t\t\t\t\tuser_id?: string;\n\t\t\t\t\t};\n\t\t\t\t\tsender_type?: string;\n\t\t\t }\n\t\t\t| undefined;\n\n\t\tconst isBot = sender?.sender_type === \"app\";\n\t\tconst openId = sender?.sender_id?.open_id || \"\";\n\n\t\treturn {\n\t\t\topenId,\n\t\t\tunionId: sender?.sender_id?.union_id,\n\t\t\tuserId: sender?.sender_id?.user_id,\n\t\t\tisBot,\n\t\t};\n\t}\n\n\t/**\n\t * Parses message content to extract text.\n\t */\n\tprivate parseMessageContent(message: FeishuMessage): string {\n\t\ttry {\n\t\t\tconst content = JSON.parse(message.content);\n\n\t\t\tswitch (message.msgType) {\n\t\t\t\tcase \"text\":\n\t\t\t\t\treturn content.text || \"\";\n\n\t\t\t\tcase \"post\":\n\t\t\t\t\t// Rich text - extract plain text\n\t\t\t\t\treturn this.extractTextFromPost(content);\n\n\t\t\t\tcase \"image\":\n\t\t\t\tcase \"file\":\n\t\t\t\tcase \"audio\":\n\t\t\t\tcase \"video\":\n\t\t\t\tcase \"sticker\":\n\t\t\t\t\treturn `[${message.msgType}]`;\n\n\t\t\t\tcase \"interactive\":\n\t\t\t\t\treturn \"[interactive card]\";\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn content.text || \"\";\n\t\t\t}\n\t\t} catch {\n\t\t\treturn \"\";\n\t\t}\n\t}\n\n\t/**\n\t * Extracts plain text from a rich text (post) message.\n\t */\n\tprivate extractTextFromPost(content: {\n\t\ttitle?: string;\n\t\tcontent?: { tag: string; text?: string }[][];\n\t}): string {\n\t\tconst parts: string[] = [];\n\n\t\tif (content.title) {\n\t\t\tparts.push(content.title);\n\t\t}\n\n\t\tif (content.content && Array.isArray(content.content)) {\n\t\t\tfor (const line of content.content) {\n\t\t\t\tif (Array.isArray(line)) {\n\t\t\t\t\tconst lineText = line\n\t\t\t\t\t\t.filter((elem) => elem.tag === \"text\" && elem.text)\n\t\t\t\t\t\t.map((elem) => elem.text)\n\t\t\t\t\t\t.join(\"\");\n\t\t\t\t\tif (lineText) {\n\t\t\t\t\t\tparts.push(lineText);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn parts.join(\"\\n\");\n\t}\n\n\t/**\n\t * Checks if the bot is mentioned in the message.\n\t */\n\tprivate isBotMentioned(message: FeishuMessage): boolean {\n\t\tif (!this.botOpenId || !message.mentions) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn message.mentions.some((mention) => mention.id === this.botOpenId);\n\t}\n\n\t/**\n\t * Splits a long message into chunks.\n\t */\n\tprivate splitMessage(content: string): string[] {\n\t\tif (content.length <= MAX_MESSAGE_LENGTH) {\n\t\t\treturn [content];\n\t\t}\n\n\t\tconst parts: string[] = [];\n\t\tlet current = \"\";\n\n\t\tfor (const line of content.split(\"\\n\")) {\n\t\t\tconst lineWithNewline = current ? `\\n${line}` : line;\n\n\t\t\tif (current.length + lineWithNewline.length > MAX_MESSAGE_LENGTH) {\n\t\t\t\tif (current) {\n\t\t\t\t\tparts.push(current);\n\t\t\t\t\tcurrent = \"\";\n\t\t\t\t}\n\n\t\t\t\tif (line.length > MAX_MESSAGE_LENGTH) {\n\t\t\t\t\t// Split very long lines by words\n\t\t\t\t\tconst words = line.split(/\\s+/);\n\t\t\t\t\tfor (const word of words) {\n\t\t\t\t\t\tconst wordWithSpace = current ? ` ${word}` : word;\n\t\t\t\t\t\tif (current.length + wordWithSpace.length > MAX_MESSAGE_LENGTH) {\n\t\t\t\t\t\t\tif (current) {\n\t\t\t\t\t\t\t\tparts.push(current);\n\t\t\t\t\t\t\t\tcurrent = \"\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (word.length > MAX_MESSAGE_LENGTH) {\n\t\t\t\t\t\t\t\t// Split very long words\n\t\t\t\t\t\t\t\tfor (let i = 0; i < word.length; i += MAX_MESSAGE_LENGTH) {\n\t\t\t\t\t\t\t\t\tparts.push(word.slice(i, i + MAX_MESSAGE_LENGTH));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcurrent = word;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcurrent += wordWithSpace;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tcurrent = line;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcurrent += lineWithNewline;\n\t\t\t}\n\t\t}\n\n\t\tif (current) {\n\t\t\tparts.push(current);\n\t\t}\n\n\t\treturn parts;\n\t}\n}\n",
|
|
10
|
+
"import type { IAgentRuntime } from \"@elizaos/core\";\nimport { FEISHU_DOMAINS } from \"./constants\";\n\n/**\n * Configuration for the Feishu service.\n */\nexport interface FeishuConfig {\n\t/** Application ID (cli_xxx format) */\n\tappId: string;\n\t/** Application secret */\n\tappSecret: string;\n\t/** Domain: 'feishu' for China or 'lark' for global */\n\tdomain: \"feishu\" | \"lark\";\n\t/** API base URL */\n\tapiRoot: string;\n\t/** Allowed chat IDs (empty means all allowed) */\n\tallowedChatIds: string[];\n\t/** Test chat ID for testing */\n\ttestChatId?: string;\n\t/** Whether to ignore bot messages */\n\tshouldIgnoreBotMessages: boolean;\n\t/** Whether to respond only to mentions */\n\tshouldRespondOnlyToMentions: boolean;\n}\n\n/**\n * Validates and returns the Feishu configuration from runtime settings.\n */\nexport function getFeishuConfig(runtime: IAgentRuntime): FeishuConfig | null {\n\tconst appId = runtime.getSetting(\"FEISHU_APP_ID\") as string | undefined;\n\tconst appSecret = runtime.getSetting(\"FEISHU_APP_SECRET\") as\n\t\t| string\n\t\t| undefined;\n\n\tif (!appId || !appSecret) {\n\t\treturn null;\n\t}\n\n\tconst domainSetting = (\n\t\truntime.getSetting(\"FEISHU_DOMAIN\") as string | undefined\n\t)?.toLowerCase();\n\tconst domain: \"feishu\" | \"lark\" =\n\t\tdomainSetting === \"lark\" ? \"lark\" : \"feishu\";\n\n\tconst apiRoot = FEISHU_DOMAINS[domain];\n\n\tlet allowedChatIds: string[] = [];\n\tconst allowedChatsRaw = runtime.getSetting(\"FEISHU_ALLOWED_CHATS\") as\n\t\t| string\n\t\t| undefined;\n\tif (allowedChatsRaw) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(allowedChatsRaw);\n\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\tallowedChatIds = parsed.map(String);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Invalid JSON, ignore\n\t\t}\n\t}\n\n\tconst testChatId = runtime.getSetting(\"FEISHU_TEST_CHAT_ID\") as\n\t\t| string\n\t\t| undefined;\n\n\tconst shouldIgnoreBotMessages =\n\t\t(\n\t\t\truntime.getSetting(\"FEISHU_IGNORE_BOT_MESSAGES\") as string\n\t\t)?.toLowerCase() !== \"false\";\n\n\tconst shouldRespondOnlyToMentions =\n\t\t(\n\t\t\truntime.getSetting(\"FEISHU_RESPOND_ONLY_TO_MENTIONS\") as string\n\t\t)?.toLowerCase() === \"true\";\n\n\treturn {\n\t\tappId,\n\t\tappSecret,\n\t\tdomain,\n\t\tapiRoot,\n\t\tallowedChatIds,\n\t\ttestChatId,\n\t\tshouldIgnoreBotMessages,\n\t\tshouldRespondOnlyToMentions,\n\t};\n}\n\n/**\n * Validates the Feishu configuration.\n */\nexport function validateConfig(config: FeishuConfig): {\n\tvalid: boolean;\n\terror?: string;\n} {\n\tif (!config.appId) {\n\t\treturn { valid: false, error: \"FEISHU_APP_ID is required\" };\n\t}\n\n\tif (!config.appId.startsWith(\"cli_\")) {\n\t\treturn { valid: false, error: \"FEISHU_APP_ID should start with 'cli_'\" };\n\t}\n\n\tif (!config.appSecret) {\n\t\treturn { valid: false, error: \"FEISHU_APP_SECRET is required\" };\n\t}\n\n\treturn { valid: true };\n}\n\n/**\n * Checks if a chat is allowed based on configuration.\n */\nexport function isChatAllowed(config: FeishuConfig, chatId: string): boolean {\n\tif (config.allowedChatIds.length === 0) {\n\t\treturn true;\n\t}\n\treturn config.allowedChatIds.includes(chatId);\n}\n",
|
|
11
|
+
"import type {\n\tContent,\n\tEntityPayload,\n\tMessagePayload,\n\tWorldPayload,\n} from \"@elizaos/core\";\n\n/**\n * Feishu event data structure (local type since lark SDK doesn't export it)\n */\nexport interface FeishuEventData {\n\tevent?: Record<string, unknown>;\n\theader?: {\n\t\tevent_id?: string;\n\t\ttoken?: string;\n\t\tcreate_time?: string;\n\t\tevent_type?: string;\n\t\ttenant_key?: string;\n\t\tapp_id?: string;\n\t};\n}\n\n/**\n * Base content type for Feishu messages (extends Content for compatibility).\n * Note: Do not add FeishuCard directly to this interface as it conflicts with Content's index signature.\n */\nexport interface FeishuContent extends Content {\n\t/** Image key for image messages */\n\tfeishuImageKey?: string;\n\t/** File key for file messages */\n\tfeishuFileKey?: string;\n}\n\n/**\n * Internal type for Feishu-specific content with card support (not exported to Content).\n * This type is used internally for message sending/receiving.\n */\nexport interface FeishuMessageContent {\n\ttext?: string;\n\t/** Interactive card content */\n\tcard?: FeishuCard;\n\t/** Image key for image messages */\n\timageKey?: string;\n\t/** File key for file messages */\n\tfileKey?: string;\n}\n\n/**\n * Helper type for accessing Feishu-specific card content (internal use)\n */\nexport type FeishuCardContent = {\n\tcard?: FeishuCard;\n\timageKey?: string;\n\tfileKey?: string;\n};\n\n/**\n * Feishu interactive card structure.\n */\nexport interface FeishuCard {\n\t/** Card configuration */\n\tconfig?: {\n\t\twideScreenMode?: boolean;\n\t\tenableForward?: boolean;\n\t};\n\t/** Card header */\n\theader?: {\n\t\ttitle?: {\n\t\t\ttag: string;\n\t\t\tcontent: string;\n\t\t};\n\t\ttemplate?: string;\n\t};\n\t/** Card elements */\n\telements?: FeishuCardElement[];\n}\n\n/**\n * Card element types.\n */\nexport type FeishuCardElement =\n\t| { tag: \"div\"; text: { tag: string; content: string } }\n\t| { tag: \"action\"; actions: FeishuCardAction[] }\n\t| { tag: \"hr\" }\n\t| { tag: \"note\"; elements: { tag: string; content: string }[] };\n\n/**\n * Card action types.\n */\nexport interface FeishuCardAction {\n\ttag: \"button\";\n\ttext: { tag: string; content: string };\n\ttype?: \"default\" | \"primary\" | \"danger\";\n\turl?: string;\n\tvalue?: Record<string, string>;\n}\n\n/**\n * Event types emitted by the Feishu plugin.\n */\nexport enum FeishuEventTypes {\n\tWORLD_JOINED = \"FEISHU_WORLD_JOINED\",\n\tWORLD_CONNECTED = \"FEISHU_WORLD_CONNECTED\",\n\tWORLD_LEFT = \"FEISHU_WORLD_LEFT\",\n\tENTITY_JOINED = \"FEISHU_ENTITY_JOINED\",\n\tENTITY_LEFT = \"FEISHU_ENTITY_LEFT\",\n\tENTITY_UPDATED = \"FEISHU_ENTITY_UPDATED\",\n\tMESSAGE_RECEIVED = \"FEISHU_MESSAGE_RECEIVED\",\n\tMESSAGE_SENT = \"FEISHU_MESSAGE_SENT\",\n\tREACTION_RECEIVED = \"FEISHU_REACTION_RECEIVED\",\n\tINTERACTION_RECEIVED = \"FEISHU_INTERACTION_RECEIVED\",\n\tSLASH_START = \"FEISHU_SLASH_START\",\n}\n\n/**\n * Map of event types to their payload types.\n */\nexport interface FeishuEventPayloadMap {\n\t[FeishuEventTypes.MESSAGE_RECEIVED]: FeishuMessageReceivedPayload;\n\t[FeishuEventTypes.MESSAGE_SENT]: FeishuMessageSentPayload;\n\t[FeishuEventTypes.REACTION_RECEIVED]: FeishuReactionReceivedPayload;\n\t[FeishuEventTypes.WORLD_JOINED]: FeishuWorldPayload;\n\t[FeishuEventTypes.WORLD_CONNECTED]: FeishuWorldPayload;\n\t[FeishuEventTypes.WORLD_LEFT]: FeishuWorldPayload;\n\t[FeishuEventTypes.SLASH_START]: { chatId: string };\n\t[FeishuEventTypes.ENTITY_JOINED]: FeishuEntityPayload;\n\t[FeishuEventTypes.ENTITY_LEFT]: FeishuEntityPayload;\n\t[FeishuEventTypes.ENTITY_UPDATED]: FeishuEntityPayload;\n\t[FeishuEventTypes.INTERACTION_RECEIVED]: FeishuInteractionPayload;\n}\n\n/**\n * Feishu chat types.\n */\nexport enum FeishuChatType {\n\t/** Private one-on-one chat */\n\tP2P = \"p2p\",\n\t/** Group chat */\n\tGROUP = \"group\",\n}\n\n/**\n * Feishu user information.\n */\nexport interface FeishuUser {\n\t/** Open ID (user identifier) */\n\topenId: string;\n\t/** Union ID (cross-app identifier) */\n\tunionId?: string;\n\t/** User ID (tenant-level identifier) */\n\tuserId?: string;\n\t/** User's display name */\n\tname?: string;\n\t/** User's avatar URL */\n\tavatarUrl?: string;\n\t/** Whether the user is a bot */\n\tisBot?: boolean;\n}\n\n/**\n * Feishu chat information.\n */\nexport interface FeishuChat {\n\t/** Chat ID */\n\tchatId: string;\n\t/** Chat type */\n\tchatType: FeishuChatType;\n\t/** Chat name/title */\n\tname?: string;\n\t/** Chat owner's open ID */\n\townerOpenId?: string;\n\t/** Chat description */\n\tdescription?: string;\n\t/** Tenant key */\n\ttenantKey?: string;\n}\n\n/**\n * Feishu message information.\n */\nexport interface FeishuMessage {\n\t/** Message ID */\n\tmessageId: string;\n\t/** Root message ID (for threads) */\n\trootId?: string;\n\t/** Parent message ID (for replies) */\n\tparentId?: string;\n\t/** Message type */\n\tmsgType: string;\n\t/** Message content (JSON string) */\n\tcontent: string;\n\t/** Create time (Unix timestamp in milliseconds) */\n\tcreateTime: string;\n\t/** Update time (Unix timestamp in milliseconds) */\n\tupdateTime?: string;\n\t/** Whether the message is deleted */\n\tdeleted?: boolean;\n\t/** Chat ID */\n\tchatId: string;\n\t/** Sender information */\n\tsender: {\n\t\tid: string;\n\t\tidType: string;\n\t\tsenderType: string;\n\t\ttenantKey?: string;\n\t};\n\t/** Mentions in the message */\n\tmentions?: FeishuMention[];\n}\n\n/**\n * Mention information in a message.\n */\nexport interface FeishuMention {\n\t/** Mention key in the message */\n\tkey: string;\n\t/** Mentioned user's ID */\n\tid: string;\n\t/** ID type */\n\tidType: string;\n\t/** Mentioned user's name */\n\tname: string;\n\t/** Tenant key */\n\ttenantKey?: string;\n}\n\n/**\n * Payload for received messages.\n */\nexport interface FeishuMessageReceivedPayload extends MessagePayload {\n\t/** Original Feishu message */\n\toriginalMessage: FeishuMessage;\n\t/** Chat information */\n\tchat: FeishuChat;\n\t/** Sender information */\n\tsender: FeishuUser;\n}\n\n/**\n * Payload for sent messages.\n */\nexport interface FeishuMessageSentPayload extends MessagePayload {\n\t/** Message IDs of sent messages */\n\tmessageIds: string[];\n\t/** Chat ID */\n\tchatId: string;\n}\n\n/**\n * Payload for reaction events.\n */\nexport interface FeishuReactionReceivedPayload\n\textends FeishuMessageReceivedPayload {\n\t/** Reaction type/emoji */\n\treactionType: string;\n}\n\n/**\n * Payload for world/chat events.\n */\nexport interface FeishuWorldPayload extends WorldPayload {\n\t/** Chat information */\n\tchat: FeishuChat;\n\t/** Bot's open ID */\n\tbotOpenId?: string;\n}\n\n/**\n * Payload for entity (user) events.\n */\nexport interface FeishuEntityPayload extends EntityPayload {\n\t/** Feishu user information */\n\tfeishuUser: FeishuUser;\n\t/** Chat where the event occurred */\n\tchat: FeishuChat;\n}\n\n/**\n * Payload for interaction events (card actions, etc.).\n */\nexport interface FeishuInteractionPayload {\n\t/** Interaction type */\n\ttype: string;\n\t/** Action data */\n\taction: {\n\t\ttag: string;\n\t\tvalue?: Record<string, string>;\n\t};\n\t/** User who triggered the interaction */\n\tuser: FeishuUser;\n\t/** Chat where the interaction occurred */\n\tchat?: FeishuChat;\n\t/** Token for responding to the interaction */\n\ttoken?: string;\n}\n",
|
|
12
|
+
"import {\n\tChannelType,\n\ttype Content,\n\tcreateUniqueUuid,\n\ttype Entity,\n\ttype EventPayload,\n\tEventType,\n\ttype IAgentRuntime,\n\tlogger,\n\ttype Memory,\n\ttype MessageConnectorChatContext,\n\ttype MessageConnectorTarget,\n\ttype MessageConnectorUserContext,\n\ttype Room,\n\tService,\n\ttype TargetInfo,\n\ttype UUID,\n\ttype World,\n} from \"@elizaos/core\";\nimport * as lark from \"@larksuiteoapi/node-sdk\";\nimport { FEISHU_SERVICE_NAME } from \"./constants\";\nimport {\n\ttype FeishuConfig,\n\tgetFeishuConfig,\n\tvalidateConfig,\n} from \"./environment\";\nimport { MessageManager } from \"./messageManager\";\nimport type {\n\tFeishuChat,\n\tFeishuEventData,\n\tFeishuMessageContent,\n\tFeishuWorldPayload,\n} from \"./types\";\nimport { FeishuChatType, FeishuEventTypes } from \"./types\";\n\nfunction normalizeFeishuQuery(query: string): string {\n\treturn query.trim().toLowerCase();\n}\n\nfunction scoreFeishuCandidate(\n\tvalues: Array<string | undefined>,\n\tquery: string,\n): number {\n\tconst normalized = normalizeFeishuQuery(query);\n\tif (!normalized) {\n\t\treturn 0.45;\n\t}\n\tconst candidates = values\n\t\t.filter(\n\t\t\t(value): value is string =>\n\t\t\t\ttypeof value === \"string\" && value.trim().length > 0,\n\t\t)\n\t\t.map((value) => value.trim().toLowerCase());\n\tif (candidates.some((candidate) => candidate === normalized)) {\n\t\treturn 1;\n\t}\n\treturn candidates.some((candidate) => candidate.includes(normalized))\n\t\t? 0.8\n\t\t: 0;\n}\n\nfunction feishuChatToConnectorTarget(\n\tchat: FeishuChat,\n\tscore = 0.55,\n\troomId?: UUID,\n): MessageConnectorTarget {\n\treturn {\n\t\ttarget: {\n\t\t\tsource: FEISHU_SERVICE_NAME,\n\t\t\tchannelId: chat.chatId,\n\t\t\troomId,\n\t\t},\n\t\tlabel: chat.name || chat.chatId,\n\t\tkind: chat.chatType === FeishuChatType.P2P ? \"user\" : \"group\",\n\t\tdescription: chat.description || \"Feishu/Lark chat\",\n\t\tscore,\n\t\tcontexts: [\"social\", \"connectors\"],\n\t\tmetadata: {\n\t\t\tchatType: chat.chatType,\n\t\t\townerOpenId: chat.ownerOpenId,\n\t\t\ttenantKey: chat.tenantKey,\n\t\t},\n\t};\n}\n\ntype ConnectorHookContext = {\n\truntime: IAgentRuntime;\n\troomId?: UUID;\n\ttarget?: TargetInfo;\n};\n\ntype ConnectorReadParams = {\n\ttarget?: TargetInfo;\n\tlimit?: number;\n\tquery?: string;\n};\n\ntype ConnectorUserLookupParams = {\n\tentityId?: UUID | string;\n\tuserId?: string;\n\tusername?: string;\n\thandle?: string;\n\ttarget?: TargetInfo;\n};\n\ntype AdditiveMessageConnectorHooks = {\n\tfetchMessages?: (\n\t\tcontext: ConnectorHookContext,\n\t\tparams?: ConnectorReadParams,\n\t) => Promise<Memory[]>;\n\tsearchMessages?: (\n\t\tcontext: ConnectorHookContext,\n\t\tparams: ConnectorReadParams & { query: string },\n\t) => Promise<Memory[]>;\n\tgetUser?: (\n\t\truntime: IAgentRuntime,\n\t\tparams: ConnectorUserLookupParams,\n\t) => Promise<Entity | null>;\n};\n\ntype ExtendedMessageConnectorRegistration = Parameters<\n\tIAgentRuntime[\"registerMessageConnector\"]\n>[0] &\n\tAdditiveMessageConnectorHooks;\n\nfunction normalizeConnectorLimit(\n\tlimit: number | undefined,\n\tfallback = 50,\n): number {\n\tif (!Number.isFinite(limit) || !limit || limit <= 0) {\n\t\treturn fallback;\n\t}\n\treturn Math.min(Math.floor(limit), 200);\n}\n\nasync function readStoredMessageMemories(\n\truntime: IAgentRuntime,\n\troomId: UUID,\n\tlimit: number,\n): Promise<Memory[]> {\n\treturn runtime.getMemories({\n\t\ttableName: \"messages\",\n\t\troomId,\n\t\tlimit,\n\t\torderBy: \"createdAt\",\n\t\torderDirection: \"desc\",\n\t});\n}\n\nasync function readStoredMessagesForTargets(\n\truntime: IAgentRuntime,\n\ttargets: MessageConnectorTarget[],\n\tlimit: number,\n): Promise<Memory[]> {\n\tconst roomIds = Array.from(\n\t\tnew Set(\n\t\t\ttargets\n\t\t\t\t.map((target) => target.target.roomId)\n\t\t\t\t.filter((id): id is UUID => Boolean(id)),\n\t\t),\n\t);\n\tconst chunks = await Promise.all(\n\t\troomIds.map((roomId) => readStoredMessageMemories(runtime, roomId, limit)),\n\t);\n\treturn chunks\n\t\t.flat()\n\t\t.sort((left, right) => (right.createdAt ?? 0) - (left.createdAt ?? 0))\n\t\t.slice(0, limit);\n}\n\nfunction filterMemoriesByQuery(\n\tmemories: Memory[],\n\tquery: string,\n\tlimit: number,\n): Memory[] {\n\tconst normalized = query.trim().toLowerCase();\n\tif (!normalized) {\n\t\treturn memories.slice(0, limit);\n\t}\n\treturn memories\n\t\t.filter((memory) => {\n\t\t\tconst text =\n\t\t\t\ttypeof memory.content?.text === \"string\" ? memory.content.text : \"\";\n\t\t\treturn text.toLowerCase().includes(normalized);\n\t\t})\n\t\t.slice(0, limit);\n}\n\n/**\n * Feishu service for ElizaOS.\n */\nexport class FeishuService extends Service {\n\tstatic serviceType = FEISHU_SERVICE_NAME;\n\tcapabilityDescription =\n\t\t\"The agent is able to send and receive messages on Feishu/Lark\";\n\n\tprivate client: lark.Client | null = null;\n\tprivate wsClient: lark.WSClient | null = null;\n\tpublic messageManager: MessageManager | null = null;\n\tprivate feishuConfig: FeishuConfig | null = null;\n\tprivate botOpenId: string | null = null;\n\tprivate knownChats: Map<string, FeishuChat> = new Map();\n\n\tconstructor(runtime?: IAgentRuntime) {\n\t\tsuper(runtime);\n\n\t\tif (!runtime) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst config = getFeishuConfig(runtime);\n\t\tif (!config) {\n\t\t\tlogger.warn(\n\t\t\t\t\"[Feishu] App ID or App Secret not provided - Feishu functionality will be unavailable\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst validation = validateConfig(config);\n\t\tif (!validation.valid) {\n\t\t\tlogger.warn(`[Feishu] Invalid configuration: ${validation.error}`);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.feishuConfig = config;\n\n\t\t// Initialize Lark SDK client\n\t\tthis.client = new lark.Client({\n\t\t\tappId: config.appId,\n\t\t\tappSecret: config.appSecret,\n\t\t\tdomain: config.domain === \"lark\" ? lark.Domain.Lark : lark.Domain.Feishu,\n\t\t\tloggerLevel: lark.LoggerLevel.warn,\n\t\t});\n\n\t\tthis.messageManager = new MessageManager(this.client, runtime, config);\n\t}\n\n\tstatic async start(runtime: IAgentRuntime): Promise<Service> {\n\t\tconst service = new FeishuService(runtime);\n\n\t\tif (!service.client || !service.feishuConfig) {\n\t\t\tlogger.warn(\n\t\t\t\t\"[Feishu] Service started without client - no credentials provided\",\n\t\t\t);\n\t\t\treturn service;\n\t\t}\n\n\t\tconst maxRetries = 5;\n\t\tlet retryCount = 0;\n\t\tlet lastError: Error | null = null;\n\n\t\twhile (retryCount < maxRetries) {\n\t\t\ttry {\n\t\t\t\tlogger.info(\n\t\t\t\t\t`[Feishu] Starting service for character ${runtime.character.name}`,\n\t\t\t\t);\n\n\t\t\t\tawait service.initializeBot();\n\t\t\t\tawait service.setupWebSocket();\n\n\t\t\t\tlogger.success(`[Feishu] Service started successfully`);\n\t\t\t\treturn service;\n\t\t\t} catch (error) {\n\t\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tlogger.error(\n\t\t\t\t\t`[Feishu] Initialization attempt ${retryCount + 1} failed: ${lastError.message}`,\n\t\t\t\t);\n\t\t\t\tretryCount++;\n\n\t\t\t\tif (retryCount < maxRetries) {\n\t\t\t\t\tconst delay = 2 ** retryCount * 1000;\n\t\t\t\t\tlogger.info(`[Feishu] Retrying in ${delay / 1000} seconds...`);\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlogger.error(\n\t\t\t`[Feishu] Initialization failed after ${maxRetries} attempts. Last error: ${lastError?.message}`,\n\t\t);\n\n\t\treturn service;\n\t}\n\n\tstatic async stop(runtime: IAgentRuntime): Promise<void> {\n\t\tconst service = runtime.getService(FEISHU_SERVICE_NAME) as\n\t\t\t| FeishuService\n\t\t\t| undefined;\n\t\tif (service) {\n\t\t\tawait service.stop();\n\t\t}\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tlogger.info(\"[Feishu] Stopping service...\");\n\n\t\tif (this.wsClient) {\n\t\t\ttry {\n\t\t\t\t// WSClient may not have a stop method in newer SDK versions\n\t\t\t\tconst wsClientWithStop = this.wsClient as {\n\t\t\t\t\tstop?: () => Promise<void>;\n\t\t\t\t};\n\t\t\t\tif (typeof wsClientWithStop.stop === \"function\") {\n\t\t\t\t\tawait wsClientWithStop.stop();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t`[Feishu] Error stopping WebSocket client: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.wsClient = null;\n\t\t}\n\n\t\tthis.client = null;\n\t\tlogger.info(\"[Feishu] Service stopped\");\n\t}\n\n\t/**\n\t * Initializes the bot and fetches bot information.\n\t */\n\tprivate async initializeBot(): Promise<void> {\n\t\tif (!this.client) {\n\t\t\tthrow new Error(\"Client not initialized\");\n\t\t}\n\n\t\t// Get bot info - the API path may vary by SDK version\n\t\ttry {\n\t\t\t// Try to get bot info via the contact API\n\t\t\tconst client = this.client as {\n\t\t\t\tbot?: {\n\t\t\t\t\tbotInfo?: {\n\t\t\t\t\t\tget: (params: Record<string, unknown>) => Promise<{\n\t\t\t\t\t\t\tdata?: { bot?: { open_id?: string; app_name?: string } };\n\t\t\t\t\t\t}>;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t\tcontact?: {\n\t\t\t\t\tuser?: {\n\t\t\t\t\t\tme?: (params: Record<string, unknown>) => Promise<{\n\t\t\t\t\t\t\tdata?: { user?: { open_id?: string; name?: string } };\n\t\t\t\t\t\t}>;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\n\t\t\tif (client.bot?.botInfo?.get) {\n\t\t\t\tconst botInfo = await client.bot.botInfo.get({});\n\t\t\t\tthis.botOpenId = botInfo.data?.bot?.open_id || null;\n\n\t\t\t\tif (this.botOpenId && this.messageManager) {\n\t\t\t\t\tthis.messageManager.setBotOpenId(this.botOpenId);\n\t\t\t\t}\n\n\t\t\t\tlogger.info(\n\t\t\t\t\t`[Feishu] Bot initialized: ${botInfo.data?.bot?.app_name || \"Unknown\"}`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t\"[Feishu] Bot info API not available, some features may not work\",\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`[Feishu] Failed to get bot info: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Sets up WebSocket connection for receiving events.\n\t */\n\tprivate async setupWebSocket(): Promise<void> {\n\t\tif (!this.client || !this.feishuConfig || !this.runtime) {\n\t\t\tthrow new Error(\"Client not initialized\");\n\t\t}\n\n\t\tconst eventDispatcher = new lark.EventDispatcher({}).register({\n\t\t\t\"im.message.receive_v1\": async (data: unknown) => {\n\t\t\t\tawait this.handleMessageEvent(data as FeishuEventData);\n\t\t\t\treturn {};\n\t\t\t},\n\t\t\t\"im.chat.member.bot.added_v1\": async (data: unknown) => {\n\t\t\t\tawait this.handleBotAddedEvent(data as FeishuEventData);\n\t\t\t\treturn {};\n\t\t\t},\n\t\t\t\"im.chat.member.bot.deleted_v1\": async (data: unknown) => {\n\t\t\t\tawait this.handleBotRemovedEvent(data as FeishuEventData);\n\t\t\t\treturn {};\n\t\t\t},\n\t\t\t\"im.chat.member.user.added_v1\": async (data: unknown) => {\n\t\t\t\tawait this.handleUserAddedEvent(data as FeishuEventData);\n\t\t\t\treturn {};\n\t\t\t},\n\t\t\t\"im.chat.member.user.deleted_v1\": async (data: unknown) => {\n\t\t\t\tawait this.handleUserRemovedEvent(data as FeishuEventData);\n\t\t\t\treturn {};\n\t\t\t},\n\t\t});\n\n\t\tthis.wsClient = new lark.WSClient({\n\t\t\tappId: this.feishuConfig.appId,\n\t\t\tappSecret: this.feishuConfig.appSecret,\n\t\t\tdomain:\n\t\t\t\tthis.feishuConfig.domain === \"lark\"\n\t\t\t\t\t? lark.Domain.Lark\n\t\t\t\t\t: lark.Domain.Feishu,\n\t\t\tloggerLevel: lark.LoggerLevel.warn,\n\t\t});\n\n\t\tawait this.wsClient.start({ eventDispatcher });\n\n\t\t// Emit connected event\n\t\tthis.runtime.emitEvent(FeishuEventTypes.WORLD_CONNECTED, {\n\t\t\truntime: this.runtime,\n\t\t\tsource: \"feishu\",\n\t\t\tbotOpenId: this.botOpenId,\n\t\t} as EventPayload);\n\t}\n\n\t/**\n\t * Handles incoming message events.\n\t */\n\tprivate async handleMessageEvent(event: FeishuEventData): Promise<void> {\n\t\tif (!this.messageManager) return;\n\t\tawait this.messageManager.handleMessage(event);\n\t}\n\n\t/**\n\t * Handles bot added to chat events.\n\t */\n\tprivate async handleBotAddedEvent(event: FeishuEventData): Promise<void> {\n\t\tif (!this.runtime) return;\n\n\t\ttry {\n\t\t\tconst chatId = event.event?.chat_id as string | undefined;\n\t\t\tif (!chatId) return;\n\n\t\t\tconst chat: FeishuChat = {\n\t\t\t\tchatId,\n\t\t\t\tchatType: FeishuChatType.GROUP,\n\t\t\t\tname: event.event?.chat_name as string | undefined,\n\t\t\t};\n\n\t\t\tthis.knownChats.set(chatId, chat);\n\n\t\t\t// Create world and room\n\t\t\tconst worldId = createUniqueUuid(this.runtime, chatId) as UUID;\n\t\t\tconst roomId = createUniqueUuid(this.runtime, chatId) as UUID;\n\n\t\t\tconst world: World = {\n\t\t\t\tid: worldId,\n\t\t\t\tname: chat.name || `Feishu Chat ${chatId}`,\n\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\tmessageServerId: worldId,\n\t\t\t\tmetadata: {\n\t\t\t\t\textra: {\n\t\t\t\t\t\tchatType: chat.chatType,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tawait this.runtime.ensureWorldExists(world);\n\n\t\t\tconst room: Room = {\n\t\t\t\tid: roomId,\n\t\t\t\tname: chat.name || `Feishu Chat ${chatId}`,\n\t\t\t\tsource: \"feishu\",\n\t\t\t\ttype: ChannelType.GROUP,\n\t\t\t\tchannelId: chatId,\n\t\t\t\tmessageServerId: worldId,\n\t\t\t\tworldId,\n\t\t\t};\n\n\t\t\tawait this.runtime.ensureRoomExists(room);\n\n\t\t\tconst payload: FeishuWorldPayload = {\n\t\t\t\truntime: this.runtime,\n\t\t\t\tworld,\n\t\t\t\trooms: [room],\n\t\t\t\tentities: [],\n\t\t\t\tsource: \"feishu\",\n\t\t\t\tchat,\n\t\t\t\tbotOpenId: this.botOpenId || undefined,\n\t\t\t};\n\n\t\t\tthis.runtime.emitEvent(\n\t\t\t\tFeishuEventTypes.WORLD_JOINED,\n\t\t\t\tpayload as EventPayload,\n\t\t\t);\n\t\t\tthis.runtime.emitEvent(EventType.WORLD_JOINED, {\n\t\t\t\truntime: this.runtime,\n\t\t\t\tworld,\n\t\t\t\trooms: [room],\n\t\t\t\tentities: [],\n\t\t\t\tsource: \"feishu\",\n\t\t\t} as EventPayload);\n\n\t\t\tlogger.info(`[Feishu] Bot added to chat: ${chat.name || chatId}`);\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`[Feishu] Error handling bot added event: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Handles bot removed from chat events.\n\t */\n\tprivate async handleBotRemovedEvent(event: FeishuEventData): Promise<void> {\n\t\tif (!this.runtime) return;\n\n\t\ttry {\n\t\t\tconst chatId = event.event?.chat_id as string | undefined;\n\t\t\tif (!chatId) return;\n\n\t\t\tconst chat = this.knownChats.get(chatId) || {\n\t\t\t\tchatId,\n\t\t\t\tchatType: FeishuChatType.GROUP,\n\t\t\t};\n\n\t\t\tthis.knownChats.delete(chatId);\n\n\t\t\tthis.runtime.emitEvent(FeishuEventTypes.WORLD_LEFT, {\n\t\t\t\truntime: this.runtime,\n\t\t\t\tsource: \"feishu\",\n\t\t\t\tchat,\n\t\t\t\tbotOpenId: this.botOpenId,\n\t\t\t} as EventPayload);\n\n\t\t\tlogger.info(`[Feishu] Bot removed from chat: ${chatId}`);\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`[Feishu] Error handling bot removed event: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Handles user added to chat events.\n\t */\n\tprivate async handleUserAddedEvent(event: FeishuEventData): Promise<void> {\n\t\tif (!this.runtime) return;\n\n\t\ttry {\n\t\t\tconst chatId = event.event?.chat_id as string | undefined;\n\t\t\tconst users = event.event?.users as\n\t\t\t\t| Array<{ user_id?: { open_id?: string }; name?: string }>\n\t\t\t\t| undefined;\n\n\t\t\tif (!chatId || !users) return;\n\n\t\t\tfor (const user of users) {\n\t\t\t\tconst openId = user.user_id?.open_id;\n\t\t\t\tif (!openId) continue;\n\n\t\t\t\tthis.runtime.emitEvent(FeishuEventTypes.ENTITY_JOINED, {\n\t\t\t\t\truntime: this.runtime,\n\t\t\t\t\tsource: \"feishu\",\n\t\t\t\t\tfeishuUser: {\n\t\t\t\t\t\topenId,\n\t\t\t\t\t\tname: user.name,\n\t\t\t\t\t},\n\t\t\t\t\tchat: this.knownChats.get(chatId) || {\n\t\t\t\t\t\tchatId,\n\t\t\t\t\t\tchatType: FeishuChatType.GROUP,\n\t\t\t\t\t},\n\t\t\t\t} as EventPayload);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`[Feishu] Error handling user added event: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Handles user removed from chat events.\n\t */\n\tprivate async handleUserRemovedEvent(event: FeishuEventData): Promise<void> {\n\t\tif (!this.runtime) return;\n\n\t\ttry {\n\t\t\tconst chatId = event.event?.chat_id as string | undefined;\n\t\t\tconst users = event.event?.users as\n\t\t\t\t| Array<{ user_id?: { open_id?: string }; name?: string }>\n\t\t\t\t| undefined;\n\n\t\t\tif (!chatId || !users) return;\n\n\t\t\tfor (const user of users) {\n\t\t\t\tconst openId = user.user_id?.open_id;\n\t\t\t\tif (!openId) continue;\n\n\t\t\t\tthis.runtime.emitEvent(FeishuEventTypes.ENTITY_LEFT, {\n\t\t\t\t\truntime: this.runtime,\n\t\t\t\t\tsource: \"feishu\",\n\t\t\t\t\tfeishuUser: {\n\t\t\t\t\t\topenId,\n\t\t\t\t\t\tname: user.name,\n\t\t\t\t\t},\n\t\t\t\t\tchat: this.knownChats.get(chatId) || {\n\t\t\t\t\t\tchatId,\n\t\t\t\t\t\tchatType: FeishuChatType.GROUP,\n\t\t\t\t\t},\n\t\t\t\t} as EventPayload);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`[Feishu] Error handling user removed event: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Registers send handlers for the service.\n\t */\n\tstatic registerSendHandlers(\n\t\truntime: IAgentRuntime,\n\t\tserviceInstance: FeishuService,\n\t): void {\n\t\tif (serviceInstance?.client && serviceInstance?.messageManager) {\n\t\t\tconst sendHandler = async (\n\t\t\t\thandlerRuntime: IAgentRuntime,\n\t\t\t\ttarget: TargetInfo,\n\t\t\t\tcontent: Content,\n\t\t\t): Promise<Memory | undefined> => {\n\t\t\t\tawait serviceInstance.handleSendMessage(\n\t\t\t\t\thandlerRuntime,\n\t\t\t\t\ttarget,\n\t\t\t\t\tcontent,\n\t\t\t\t);\n\t\t\t\treturn undefined;\n\t\t\t};\n\n\t\t\tif (typeof runtime.registerMessageConnector === \"function\") {\n\t\t\t\tconst registration = {\n\t\t\t\t\tsource: FEISHU_SERVICE_NAME,\n\t\t\t\t\tlabel: \"Feishu/Lark\",\n\t\t\t\t\tcapabilities: [\n\t\t\t\t\t\t\"send_message\",\n\t\t\t\t\t\t\"send_card\",\n\t\t\t\t\t\t\"send_image\",\n\t\t\t\t\t\t\"send_file\",\n\t\t\t\t\t],\n\t\t\t\t\tsupportedTargetKinds: [\"group\", \"room\", \"user\", \"channel\"],\n\t\t\t\t\tcontexts: [\"social\", \"connectors\"],\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Send Feishu/Lark text, card, image, and file messages to known chats.\",\n\t\t\t\t\tsendHandler,\n\t\t\t\t\tresolveTargets: async (query, context) => {\n\t\t\t\t\t\tconst chats = await serviceInstance.listConnectorChats(\n\t\t\t\t\t\t\tcontext.runtime,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn chats\n\t\t\t\t\t\t\t.map(({ chat, roomId }) => ({\n\t\t\t\t\t\t\t\tchat,\n\t\t\t\t\t\t\t\troomId,\n\t\t\t\t\t\t\t\tscore: scoreFeishuCandidate(\n\t\t\t\t\t\t\t\t\t[chat.chatId, chat.name, chat.description, chat.ownerOpenId],\n\t\t\t\t\t\t\t\t\tquery,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t\t.filter(({ score }) => score > 0)\n\t\t\t\t\t\t\t.sort((left, right) => right.score - left.score)\n\t\t\t\t\t\t\t.slice(0, 10)\n\t\t\t\t\t\t\t.map(({ chat, score, roomId }) =>\n\t\t\t\t\t\t\t\tfeishuChatToConnectorTarget(chat, score, roomId),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\tlistRecentTargets: async (context) =>\n\t\t\t\t\t\t(await serviceInstance.listConnectorChats(context.runtime))\n\t\t\t\t\t\t\t.slice(0, 10)\n\t\t\t\t\t\t\t.map(({ chat, roomId }) =>\n\t\t\t\t\t\t\t\tfeishuChatToConnectorTarget(chat, 0.55, roomId),\n\t\t\t\t\t\t\t),\n\t\t\t\t\tlistRooms: async (context) =>\n\t\t\t\t\t\t(await serviceInstance.listConnectorChats(context.runtime)).map(\n\t\t\t\t\t\t\t({ chat, roomId }) =>\n\t\t\t\t\t\t\t\tfeishuChatToConnectorTarget(chat, 0.55, roomId),\n\t\t\t\t\t\t),\n\t\t\t\t\tfetchMessages: async (context, params) => {\n\t\t\t\t\t\tconst limit = normalizeConnectorLimit(params?.limit);\n\t\t\t\t\t\tconst target = params?.target ?? context.target;\n\t\t\t\t\t\tif (target?.roomId) {\n\t\t\t\t\t\t\treturn readStoredMessageMemories(\n\t\t\t\t\t\t\t\tcontext.runtime,\n\t\t\t\t\t\t\t\ttarget.roomId,\n\t\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst targets = (\n\t\t\t\t\t\t\tawait serviceInstance.listConnectorChats(context.runtime)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.slice(0, 10)\n\t\t\t\t\t\t\t.map(({ chat, roomId }) =>\n\t\t\t\t\t\t\t\tfeishuChatToConnectorTarget(chat, 0.55, roomId),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn readStoredMessagesForTargets(\n\t\t\t\t\t\t\tcontext.runtime,\n\t\t\t\t\t\t\ttargets,\n\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\tsearchMessages: async (context, params) => {\n\t\t\t\t\t\tconst limit = normalizeConnectorLimit(params?.limit);\n\t\t\t\t\t\tconst target = params?.target ?? context.target;\n\t\t\t\t\t\tconst messages = target?.roomId\n\t\t\t\t\t\t\t? await readStoredMessageMemories(\n\t\t\t\t\t\t\t\t\tcontext.runtime,\n\t\t\t\t\t\t\t\t\ttarget.roomId,\n\t\t\t\t\t\t\t\t\tMath.max(limit, 100),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: await readStoredMessagesForTargets(\n\t\t\t\t\t\t\t\t\tcontext.runtime,\n\t\t\t\t\t\t\t\t\t(await serviceInstance.listConnectorChats(context.runtime))\n\t\t\t\t\t\t\t\t\t\t.slice(0, 10)\n\t\t\t\t\t\t\t\t\t\t.map(({ chat, roomId }) =>\n\t\t\t\t\t\t\t\t\t\t\tfeishuChatToConnectorTarget(chat, 0.55, roomId),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tMath.max(limit, 100),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn filterMemoriesByQuery(messages, params.query, limit);\n\t\t\t\t\t},\n\t\t\t\t\tgetChatContext: async (target, context) => {\n\t\t\t\t\t\tconst room = target.roomId\n\t\t\t\t\t\t\t? await context.runtime.getRoom(target.roomId)\n\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\tconst chatId = String(\n\t\t\t\t\t\t\ttarget.channelId ?? room?.channelId ?? \"\",\n\t\t\t\t\t\t).trim();\n\t\t\t\t\t\tif (!chatId) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst chat =\n\t\t\t\t\t\t\tserviceInstance.knownChats.get(chatId) ||\n\t\t\t\t\t\t\t({\n\t\t\t\t\t\t\t\tchatId,\n\t\t\t\t\t\t\t\tchatType:\n\t\t\t\t\t\t\t\t\troom?.type === ChannelType.DM\n\t\t\t\t\t\t\t\t\t\t? FeishuChatType.P2P\n\t\t\t\t\t\t\t\t\t\t: FeishuChatType.GROUP,\n\t\t\t\t\t\t\t\tname: room?.name,\n\t\t\t\t\t\t\t} satisfies FeishuChat);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttarget: {\n\t\t\t\t\t\t\t\tsource: FEISHU_SERVICE_NAME,\n\t\t\t\t\t\t\t\troomId: target.roomId,\n\t\t\t\t\t\t\t\tchannelId: chatId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tlabel: chat.name || chat.chatId,\n\t\t\t\t\t\t\tsummary:\n\t\t\t\t\t\t\t\tchat.chatType === FeishuChatType.P2P\n\t\t\t\t\t\t\t\t\t? \"Feishu/Lark direct chat\"\n\t\t\t\t\t\t\t\t\t: \"Feishu/Lark group chat\",\n\t\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\t\tchatType: chat.chatType,\n\t\t\t\t\t\t\t\townerOpenId: chat.ownerOpenId,\n\t\t\t\t\t\t\t\ttenantKey: chat.tenantKey,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t} satisfies MessageConnectorChatContext;\n\t\t\t\t\t},\n\t\t\t\t\tgetUserContext: async (entityId, context) => {\n\t\t\t\t\t\tconst entity =\n\t\t\t\t\t\t\ttypeof context.runtime.getEntityById === \"function\"\n\t\t\t\t\t\t\t\t? await context.runtime.getEntityById(String(entityId) as UUID)\n\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\tif (!entity) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tentityId,\n\t\t\t\t\t\t\tlabel: entity.names?.[0],\n\t\t\t\t\t\t\taliases: entity.names,\n\t\t\t\t\t\t\thandles: {},\n\t\t\t\t\t\t\tmetadata: entity.metadata,\n\t\t\t\t\t\t} satisfies MessageConnectorUserContext;\n\t\t\t\t\t},\n\t\t\t\t\tgetUser: async (handlerRuntime, params) => {\n\t\t\t\t\t\tconst lookupParams = params as ConnectorUserLookupParams;\n\t\t\t\t\t\tconst entityId = String(\n\t\t\t\t\t\t\tlookupParams.entityId ??\n\t\t\t\t\t\t\t\tparams.userId ??\n\t\t\t\t\t\t\t\tparams.username ??\n\t\t\t\t\t\t\t\tparams.handle ??\n\t\t\t\t\t\t\t\tparams.target?.entityId ??\n\t\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t).trim();\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!entityId ||\n\t\t\t\t\t\t\ttypeof handlerRuntime.getEntityById !== \"function\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst entity = await handlerRuntime\n\t\t\t\t\t\t\t.getEntityById(entityId as UUID)\n\t\t\t\t\t\t\t.catch(() => null);\n\t\t\t\t\t\treturn entity;\n\t\t\t\t\t},\n\t\t\t\t} as ExtendedMessageConnectorRegistration;\n\t\t\t\truntime.registerMessageConnector(registration);\n\t\t\t} else {\n\t\t\t\truntime.registerSendHandler(FEISHU_SERVICE_NAME, sendHandler);\n\t\t\t}\n\t\t\tlogger.info(\"[Feishu] Registered message connector\");\n\t\t} else {\n\t\t\tlogger.warn(\n\t\t\t\t\"[Feishu] Cannot register send handler - client not initialized\",\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Handles sending messages through the service.\n\t */\n\tasync handleSendMessage(\n\t\truntime: IAgentRuntime,\n\t\ttarget: TargetInfo,\n\t\tcontent: Content,\n\t): Promise<void> {\n\t\tif (!this.messageManager) {\n\t\t\tlogger.error(\"[Feishu] Message manager not initialized\");\n\t\t\tthrow new Error(\"Feishu message manager is not initialized\");\n\t\t}\n\n\t\tlet chatId: string | undefined;\n\n\t\tif (target.channelId) {\n\t\t\tchatId = target.channelId;\n\t\t} else if (target.roomId) {\n\t\t\tconst room = await runtime.getRoom(target.roomId);\n\t\t\tchatId = room?.channelId;\n\t\t\tif (!chatId) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Could not resolve Feishu chat ID from roomId ${target.roomId}`,\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new Error(\"Feishu SendHandler requires channelId or roomId\");\n\t\t}\n\n\t\tif (!chatId) {\n\t\t\tthrow new Error(\n\t\t\t\t`Could not determine target Feishu chat ID for target: ${JSON.stringify(target)}`,\n\t\t\t);\n\t\t}\n\n\t\t// Build Feishu content from the base content\n\t\tconst feishuContent: FeishuMessageContent = {\n\t\t\ttext: content.text || \"\",\n\t\t};\n\n\t\t// Copy over Feishu-specific fields if present\n\t\t// Card can be passed via data.card or metadata\n\t\tconst contentData = content.data as Record<string, unknown> | undefined;\n\t\tconst feishuData = (\n\t\t\tcontentData?.feishu && typeof contentData.feishu === \"object\"\n\t\t\t\t? contentData.feishu\n\t\t\t\t: contentData\n\t\t) as Record<string, unknown> | undefined;\n\t\tif (feishuData?.card) {\n\t\t\tfeishuContent.card = feishuData.card as FeishuMessageContent[\"card\"];\n\t\t}\n\t\tif (feishuData?.imageKey) {\n\t\t\tfeishuContent.imageKey = feishuData.imageKey as string;\n\t\t}\n\t\tif (feishuData?.fileKey) {\n\t\t\tfeishuContent.fileKey = feishuData.fileKey as string;\n\t\t}\n\n\t\tawait this.messageManager.sendMessage(chatId, feishuContent);\n\t\tlogger.info(`[Feishu] Message sent to chat ID: ${chatId}`);\n\t}\n\n\tasync sendRoomMessage(target: string, content: Content): Promise<void> {\n\t\tawait this.handleSendMessage(\n\t\t\tthis.runtime,\n\t\t\t{ source: FEISHU_SERVICE_NAME, channelId: target } as TargetInfo,\n\t\t\tcontent,\n\t\t);\n\t}\n\n\tasync sendDirectMessage(target: string, content: Content): Promise<void> {\n\t\tawait this.sendRoomMessage(target, content);\n\t}\n\n\tprivate async listConnectorChats(\n\t\truntime: IAgentRuntime,\n\t): Promise<Array<{ chat: FeishuChat; roomId?: UUID }>> {\n\t\tconst chats = new Map<string, { chat: FeishuChat; roomId?: UUID }>();\n\t\tfor (const chat of this.knownChats.values()) {\n\t\t\tchats.set(chat.chatId, { chat });\n\t\t}\n\n\t\tif (typeof runtime.getRoomsForParticipant !== \"function\") {\n\t\t\treturn Array.from(chats.values());\n\t\t}\n\n\t\tconst roomIds = await runtime\n\t\t\t.getRoomsForParticipant(runtime.agentId)\n\t\t\t.catch(() => [] as UUID[]);\n\t\tfor (const roomId of roomIds) {\n\t\t\tconst room = await runtime.getRoom(roomId).catch(() => null);\n\t\t\tif (room?.source !== FEISHU_SERVICE_NAME || !room.channelId) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst known = chats.get(room.channelId)?.chat;\n\t\t\tchats.set(room.channelId, {\n\t\t\t\tchat:\n\t\t\t\t\tknown ||\n\t\t\t\t\t({\n\t\t\t\t\t\tchatId: room.channelId,\n\t\t\t\t\t\tchatType:\n\t\t\t\t\t\t\troom.type === ChannelType.DM\n\t\t\t\t\t\t\t\t? FeishuChatType.P2P\n\t\t\t\t\t\t\t\t: FeishuChatType.GROUP,\n\t\t\t\t\t\tname: room.name,\n\t\t\t\t\t} satisfies FeishuChat),\n\t\t\t\troomId,\n\t\t\t});\n\t\t}\n\n\t\treturn Array.from(chats.values());\n\t}\n}\n",
|
|
13
|
+
"import { type IAgentRuntime, Service } from \"@elizaos/core\";\n\n// Inlined to avoid adding @elizaos/plugin-workflow as a compile-time dependency.\n// The runtime duck-types the service — only the serviceType string and resolve() shape matter.\nconst WORKFLOW_CREDENTIAL_PROVIDER_TYPE = \"workflow_credential_provider\";\ntype CredentialProviderResult =\n\t| { status: \"credential_data\"; data: Record<string, unknown> }\n\t| { status: \"needs_auth\"; authUrl: string }\n\t| null;\n\n// Feishu has no dedicated workflow node. Use HTTP Request node with httpHeaderAuth.\n// The Feishu service manages token refresh internally; we surface the app credentials.\nconst SUPPORTED = [\"httpHeaderAuth\"];\n\nexport class FeishuWorkflowCredentialProvider extends Service {\n\tstatic override readonly serviceType = WORKFLOW_CREDENTIAL_PROVIDER_TYPE;\n\toverride capabilityDescription =\n\t\t\"Supplies Feishu/Lark credentials to the workflow plugin.\";\n\n\tstatic async start(\n\t\truntime: IAgentRuntime,\n\t): Promise<FeishuWorkflowCredentialProvider> {\n\t\treturn new FeishuWorkflowCredentialProvider(runtime);\n\t}\n\n\tasync stop(): Promise<void> {}\n\n\tasync resolve(\n\t\t_userId: string,\n\t\tcredType: string,\n\t): Promise<CredentialProviderResult> {\n\t\tif (credType !== \"httpHeaderAuth\") return null;\n\t\tconst appId = this.runtime.getSetting(\"FEISHU_APP_ID\") as\n\t\t\t| string\n\t\t\t| undefined;\n\t\tconst appSecret = this.runtime.getSetting(\"FEISHU_APP_SECRET\") as\n\t\t\t| string\n\t\t\t| undefined;\n\t\tif (!appId?.trim() || !appSecret?.trim()) return null;\n\t\t// Surface app credentials; workflows call the Feishu auth API to get a tenant_access_token.\n\t\treturn {\n\t\t\tstatus: \"credential_data\",\n\t\t\tdata: {\n\t\t\t\tname: \"X-Feishu-App-Id\",\n\t\t\t\tvalue: appId.trim(),\n\t\t\t\tappSecret: appSecret.trim(),\n\t\t\t},\n\t\t};\n\t}\n\n\tcheckCredentialTypes(credTypes: string[]): {\n\t\tsupported: string[];\n\t\tunsupported: string[];\n\t} {\n\t\treturn {\n\t\t\tsupported: credTypes.filter((t) => SUPPORTED.includes(t)),\n\t\t\tunsupported: credTypes.filter((t) => !SUPPORTED.includes(t)),\n\t\t};\n\t}\n}\n",
|
|
14
|
+
"/**\n * Feishu text chunk limit\n */\nexport const FEISHU_TEXT_CHUNK_LIMIT = 4000;\n\n/**\n * Feishu Post (rich text) element types\n */\nexport type FeishuPostElement =\n\t| { tag: \"text\"; text: string; style?: string[] }\n\t| { tag: \"a\"; text: string; href: string; style?: string[] }\n\t| { tag: \"at\"; user_id: string }\n\t| { tag: \"img\"; image_key: string }\n\t| { tag: \"media\"; file_key: string }\n\t| { tag: \"emotion\"; emoji_type: string };\n\n/**\n * A line of Feishu Post content\n */\nexport type FeishuPostLine = FeishuPostElement[];\n\n/**\n * Feishu Post content structure\n */\nexport interface FeishuPostContent {\n\tzh_cn?: {\n\t\ttitle?: string;\n\t\tcontent: FeishuPostLine[];\n\t};\n\ten_us?: {\n\t\ttitle?: string;\n\t\tcontent: FeishuPostLine[];\n\t};\n}\n\n/**\n * Result of formatting markdown for Feishu\n */\nexport interface FeishuFormattedChunk {\n\tpost: FeishuPostContent;\n\ttext: string;\n}\n\n/**\n * Style state for text formatting\n */\ninterface StyleState {\n\tbold: boolean;\n\titalic: boolean;\n\tstrikethrough: boolean;\n\tcode: boolean;\n}\n\n/**\n * Link span information\n */\ninterface LinkSpan {\n\tstart: number;\n\tend: number;\n\thref: string;\n\ttext: string;\n}\n\n/**\n * Style span information\n */\ninterface StyleSpan {\n\tstart: number;\n\tend: number;\n\tstyle: \"bold\" | \"italic\" | \"strikethrough\" | \"code\";\n}\n\n/**\n * Intermediate representation of parsed markdown\n */\ninterface MarkdownIR {\n\ttext: string;\n\tstyles: StyleSpan[];\n\tlinks: LinkSpan[];\n}\n\n/**\n * Options for text chunking\n */\nexport interface ChunkFeishuTextOpts {\n\tlimit?: number;\n}\n\n/**\n * Parse markdown to intermediate representation\n */\nfunction parseMarkdownToIR(markdown: string): MarkdownIR {\n\tconst styles: StyleSpan[] = [];\n\tconst links: LinkSpan[] = [];\n\tlet text = markdown;\n\n\t// Process links first [text](url)\n\tconst linkRegex = /\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\n\tconst linkReplacements: {\n\t\tstart: number;\n\t\tend: number;\n\t\ttext: string;\n\t\thref: string;\n\t}[] = [];\n\n\tlet linkMatch = linkRegex.exec(markdown);\n\twhile (linkMatch !== null) {\n\t\tlinkReplacements.push({\n\t\t\tstart: linkMatch.index,\n\t\t\tend: linkMatch.index + linkMatch[0].length,\n\t\t\ttext: linkMatch[1],\n\t\t\thref: linkMatch[2],\n\t\t});\n\t\tlinkMatch = linkRegex.exec(markdown);\n\t}\n\n\t// Apply link replacements in reverse order\n\tlet offset = 0;\n\tfor (const repl of linkReplacements) {\n\t\tconst before = text.slice(0, repl.start + offset);\n\t\tconst after = text.slice(repl.end + offset);\n\t\ttext = before + repl.text + after;\n\n\t\tlinks.push({\n\t\t\tstart: repl.start + offset,\n\t\t\tend: repl.start + offset + repl.text.length,\n\t\t\thref: repl.href,\n\t\t\ttext: repl.text,\n\t\t});\n\n\t\toffset += repl.text.length - (repl.end - repl.start);\n\t}\n\n\t// Process bold **text** or __text__\n\ttext = processStyle(text, /\\*\\*([^*]+)\\*\\*/g, \"bold\", styles);\n\ttext = processStyle(text, /__([^_]+)__/g, \"bold\", styles);\n\n\t// Process italic *text* or _text_\n\ttext = processStyle(\n\t\ttext,\n\t\t/(?<!\\*)\\*(?!\\*)([^*]+)(?<!\\*)\\*(?!\\*)/g,\n\t\t\"italic\",\n\t\tstyles,\n\t);\n\ttext = processStyle(\n\t\ttext,\n\t\t/(?<!_)_(?!_)([^_]+)(?<!_)_(?!_)/g,\n\t\t\"italic\",\n\t\tstyles,\n\t);\n\n\t// Process strikethrough ~~text~~\n\ttext = processStyle(text, /~~([^~]+)~~/g, \"strikethrough\", styles);\n\n\t// Process inline code `text`\n\ttext = processStyle(text, /`([^`]+)`/g, \"code\", styles);\n\n\t// Process code blocks ```text```\n\ttext = text.replace(/```(\\w*)\\n?([\\s\\S]*?)```/g, (_, _lang, code) => {\n\t\tconst start = text.indexOf(_);\n\t\tconst trimmedCode = code.trim();\n\t\tstyles.push({\n\t\t\tstart,\n\t\t\tend: start + trimmedCode.length,\n\t\t\tstyle: \"code\",\n\t\t});\n\t\treturn trimmedCode;\n\t});\n\n\t// Remove markdown headers\n\ttext = text.replace(/^#{1,6}\\s+/gm, \"\");\n\n\t// Remove blockquote markers\n\ttext = text.replace(/^>\\s?/gm, \"| \");\n\n\t// Clean up\n\ttext = text.replace(/\\n{3,}/g, \"\\n\\n\").trim();\n\n\treturn { text, styles, links };\n}\n\n/**\n * Process a style pattern and update the text and styles\n */\nfunction processStyle(\n\ttext: string,\n\tpattern: RegExp,\n\tstyle: StyleSpan[\"style\"],\n\tstyles: StyleSpan[],\n): string {\n\tlet result = text;\n\tconst matches: { index: number; fullLength: number; content: string }[] = [];\n\n\tlet match = pattern.exec(text);\n\twhile (match !== null) {\n\t\tmatches.push({\n\t\t\tindex: match.index,\n\t\t\tfullLength: match[0].length,\n\t\t\tcontent: match[1],\n\t\t});\n\t\tmatch = pattern.exec(text);\n\t}\n\n\t// Process in reverse to maintain indices\n\tlet offset = 0;\n\tfor (const m of matches) {\n\t\tconst before = result.slice(0, m.index + offset);\n\t\tconst after = result.slice(m.index + offset + m.fullLength);\n\t\tresult = before + m.content + after;\n\n\t\tstyles.push({\n\t\t\tstart: m.index + offset,\n\t\t\tend: m.index + offset + m.content.length,\n\t\t\tstyle,\n\t\t});\n\n\t\toffset += m.content.length - m.fullLength;\n\t}\n\n\treturn result;\n}\n\n/**\n * Build style ranges for quick lookup\n */\nfunction buildStyleRanges(\n\tstyles: StyleSpan[],\n\ttextLength: number,\n): StyleState[] {\n\tconst ranges: StyleState[] = Array(textLength)\n\t\t.fill(null)\n\t\t.map(() => ({\n\t\t\tbold: false,\n\t\t\titalic: false,\n\t\t\tstrikethrough: false,\n\t\t\tcode: false,\n\t\t}));\n\n\tfor (const span of styles) {\n\t\tfor (let i = span.start; i < span.end && i < textLength; i++) {\n\t\t\tswitch (span.style) {\n\t\t\t\tcase \"bold\":\n\t\t\t\t\tranges[i].bold = true;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"italic\":\n\t\t\t\t\tranges[i].italic = true;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"strikethrough\":\n\t\t\t\t\tranges[i].strikethrough = true;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"code\":\n\t\t\t\t\tranges[i].code = true;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ranges;\n}\n\n/**\n * Build link map for quick lookup\n */\nfunction buildLinkMap(links: LinkSpan[]): Map<number, string> {\n\tconst map = new Map<number, string>();\n\tfor (const link of links) {\n\t\tfor (let i = link.start; i < link.end; i++) {\n\t\t\tmap.set(i, link.href);\n\t\t}\n\t}\n\treturn map;\n}\n\n/**\n * Get styles at a specific position\n */\nfunction getStylesAt(ranges: StyleState[], pos: number): StyleState {\n\treturn (\n\t\tranges[pos] ?? {\n\t\t\tbold: false,\n\t\t\titalic: false,\n\t\t\tstrikethrough: false,\n\t\t\tcode: false,\n\t\t}\n\t);\n}\n\n/**\n * Get link at a specific position\n */\nfunction getLinkAt(\n\tlinkMap: Map<number, string>,\n\tpos: number,\n): string | undefined {\n\treturn linkMap.get(pos);\n}\n\n/**\n * Check if two style states are equal\n */\nfunction stylesEqual(a: StyleState, b: StyleState): boolean {\n\treturn (\n\t\ta.bold === b.bold &&\n\t\ta.italic === b.italic &&\n\t\ta.strikethrough === b.strikethrough &&\n\t\ta.code === b.code\n\t);\n}\n\n/**\n * Create a Feishu Post element\n */\nfunction createPostElement(\n\ttext: string,\n\tstyles: StyleState,\n\tlink?: string,\n): FeishuPostElement {\n\tconst styleArray: string[] = [];\n\n\tif (styles.bold) {\n\t\tstyleArray.push(\"bold\");\n\t}\n\tif (styles.italic) {\n\t\tstyleArray.push(\"italic\");\n\t}\n\tif (styles.strikethrough) {\n\t\tstyleArray.push(\"lineThrough\");\n\t}\n\tif (styles.code) {\n\t\tstyleArray.push(\"code\");\n\t}\n\n\tif (link) {\n\t\treturn {\n\t\t\ttag: \"a\",\n\t\t\ttext,\n\t\t\thref: link,\n\t\t\t...(styleArray.length > 0 ? { style: styleArray } : {}),\n\t\t};\n\t}\n\n\treturn {\n\t\ttag: \"text\",\n\t\ttext,\n\t\t...(styleArray.length > 0 ? { style: styleArray } : {}),\n\t};\n}\n\n/**\n * Render markdown IR to Feishu Post format\n */\nfunction renderFeishuPost(ir: MarkdownIR): FeishuPostContent {\n\tconst lines: FeishuPostLine[] = [];\n\tconst text = ir.text;\n\n\tif (!text) {\n\t\treturn { zh_cn: { content: [[{ tag: \"text\", text: \"\" }]] } };\n\t}\n\n\tconst styleRanges = buildStyleRanges(ir.styles, text.length);\n\tconst linkMap = buildLinkMap(ir.links);\n\n\tconst textLines = text.split(\"\\n\");\n\tlet charIndex = 0;\n\n\tfor (const line of textLines) {\n\t\tconst lineElements: FeishuPostElement[] = [];\n\n\t\tif (line.length === 0) {\n\t\t\tlineElements.push({ tag: \"text\", text: \"\" });\n\t\t} else {\n\t\t\tlet segmentStart = charIndex;\n\t\t\tlet currentStyles = getStylesAt(styleRanges, segmentStart);\n\t\t\tlet currentLink = getLinkAt(linkMap, segmentStart);\n\n\t\t\tfor (let i = 0; i < line.length; i++) {\n\t\t\t\tconst pos = charIndex + i;\n\t\t\t\tconst newStyles = getStylesAt(styleRanges, pos);\n\t\t\t\tconst newLink = getLinkAt(linkMap, pos);\n\n\t\t\t\tconst stylesChanged = !stylesEqual(currentStyles, newStyles);\n\t\t\t\tconst linkChanged = currentLink !== newLink;\n\n\t\t\t\tif (stylesChanged || linkChanged) {\n\t\t\t\t\tconst segmentText = text.slice(segmentStart, pos);\n\t\t\t\t\tif (segmentText) {\n\t\t\t\t\t\tlineElements.push(\n\t\t\t\t\t\t\tcreatePostElement(segmentText, currentStyles, currentLink),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tsegmentStart = pos;\n\t\t\t\t\tcurrentStyles = newStyles;\n\t\t\t\t\tcurrentLink = newLink;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst finalText = text.slice(segmentStart, charIndex + line.length);\n\t\t\tif (finalText) {\n\t\t\t\tlineElements.push(\n\t\t\t\t\tcreatePostElement(finalText, currentStyles, currentLink),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tlines.push(\n\t\t\tlineElements.length > 0 ? lineElements : [{ tag: \"text\", text: \"\" }],\n\t\t);\n\t\tcharIndex += line.length + 1;\n\t}\n\n\treturn {\n\t\tzh_cn: {\n\t\t\tcontent: lines,\n\t\t},\n\t};\n}\n\n/**\n * Convert markdown to Feishu Post format\n */\nexport function markdownToFeishuPost(markdown: string): FeishuPostContent {\n\tconst ir = parseMarkdownToIR(markdown ?? \"\");\n\treturn renderFeishuPost(ir);\n}\n\n/**\n * Splits text at the last safe break point within the limit\n */\nfunction splitAtBreakPoint(\n\ttext: string,\n\tlimit: number,\n): { chunk: string; remainder: string } {\n\tif (text.length <= limit) {\n\t\treturn { chunk: text, remainder: \"\" };\n\t}\n\n\tconst searchArea = text.slice(0, limit);\n\n\t// Prefer double newlines (paragraph breaks)\n\tconst doubleNewline = searchArea.lastIndexOf(\"\\n\\n\");\n\tif (doubleNewline > limit * 0.5) {\n\t\treturn {\n\t\t\tchunk: text.slice(0, doubleNewline).trimEnd(),\n\t\t\tremainder: text.slice(doubleNewline + 2).trimStart(),\n\t\t};\n\t}\n\n\t// Try single newlines\n\tconst singleNewline = searchArea.lastIndexOf(\"\\n\");\n\tif (singleNewline > limit * 0.5) {\n\t\treturn {\n\t\t\tchunk: text.slice(0, singleNewline).trimEnd(),\n\t\t\tremainder: text.slice(singleNewline + 1).trimStart(),\n\t\t};\n\t}\n\n\t// Try sentence boundaries\n\tconst sentenceEnd = Math.max(\n\t\tsearchArea.lastIndexOf(\". \"),\n\t\tsearchArea.lastIndexOf(\"! \"),\n\t\tsearchArea.lastIndexOf(\"? \"),\n\t);\n\tif (sentenceEnd > limit * 0.5) {\n\t\treturn {\n\t\t\tchunk: text.slice(0, sentenceEnd + 1).trimEnd(),\n\t\t\tremainder: text.slice(sentenceEnd + 2).trimStart(),\n\t\t};\n\t}\n\n\t// Try word boundaries\n\tconst space = searchArea.lastIndexOf(\" \");\n\tif (space > limit * 0.5) {\n\t\treturn {\n\t\t\tchunk: text.slice(0, space).trimEnd(),\n\t\t\tremainder: text.slice(space + 1).trimStart(),\n\t\t};\n\t}\n\n\t// Hard break at limit\n\treturn {\n\t\tchunk: text.slice(0, limit),\n\t\tremainder: text.slice(limit),\n\t};\n}\n\n/**\n * Chunk text for Feishu messages\n */\nexport function chunkFeishuText(\n\ttext: string,\n\topts: ChunkFeishuTextOpts = {},\n): string[] {\n\tconst limit = opts.limit ?? FEISHU_TEXT_CHUNK_LIMIT;\n\n\tif (!text?.trim()) {\n\t\treturn [];\n\t}\n\n\tconst normalizedText = text.trim();\n\tif (normalizedText.length <= limit) {\n\t\treturn [normalizedText];\n\t}\n\n\tconst chunks: string[] = [];\n\tlet remaining = normalizedText;\n\n\twhile (remaining.length > 0) {\n\t\tconst { chunk, remainder } = splitAtBreakPoint(remaining, limit);\n\t\tif (chunk) {\n\t\t\tchunks.push(chunk);\n\t\t}\n\t\tremaining = remainder;\n\t}\n\n\treturn chunks.filter((c) => c.length > 0);\n}\n\n/**\n * Convert markdown to Feishu Post chunks\n */\nexport function markdownToFeishuChunks(\n\tmarkdown: string,\n\tlimit: number = FEISHU_TEXT_CHUNK_LIMIT,\n): FeishuFormattedChunk[] {\n\tconst textChunks = chunkFeishuText(markdown, { limit });\n\treturn textChunks.map((chunk) => ({\n\t\tpost: markdownToFeishuPost(chunk),\n\t\ttext: chunk,\n\t}));\n}\n\n/**\n * Check if text contains markdown formatting\n */\nexport function containsMarkdown(text: string): boolean {\n\tif (!text) {\n\t\treturn false;\n\t}\n\tconst markdownPatterns = [\n\t\t/\\*\\*[^*]+\\*\\*/,\n\t\t/\\*[^*]+\\*/,\n\t\t/~~[^~]+~~/,\n\t\t/`[^`]+`/,\n\t\t/```[\\s\\S]*```/,\n\t\t/\\[.+\\]\\(.+\\)/,\n\t\t/^#{1,6}\\s/m,\n\t\t/^[-*]\\s/m,\n\t\t/^\\d+\\.\\s/m,\n\t];\n\treturn markdownPatterns.some((pattern) => pattern.test(text));\n}\n\n/**\n * Strip markdown formatting from text\n */\nexport function stripMarkdown(text: string): string {\n\tlet result = text;\n\n\t// Remove bold\n\tresult = result.replace(/\\*\\*(.+?)\\*\\*/g, \"$1\");\n\tresult = result.replace(/__(.+?)__/g, \"$1\");\n\n\t// Remove italic\n\tresult = result.replace(/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, \"$1\");\n\tresult = result.replace(/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g, \"$1\");\n\n\t// Remove strikethrough\n\tresult = result.replace(/~~(.+?)~~/g, \"$1\");\n\n\t// Remove headers\n\tresult = result.replace(/^#{1,6}\\s+(.+)$/gm, \"$1\");\n\n\t// Remove blockquotes\n\tresult = result.replace(/^>\\s?(.*)$/gm, \"$1\");\n\n\t// Remove code blocks\n\tresult = result.replace(/```(\\w*)\\n?([\\s\\S]*?)```/g, \"$2\");\n\n\t// Remove inline code\n\tresult = result.replace(/`([^`]+)`/g, \"$1\");\n\n\t// Remove links - keep text\n\tresult = result.replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, \"$1\");\n\n\t// Clean up\n\tresult = result.replace(/\\n{3,}/g, \"\\n\\n\");\n\tresult = result.trim();\n\n\treturn result;\n}\n\n/**\n * Format Feishu user mention\n */\nexport function formatFeishuUserMention(userId: string): string {\n\treturn `<at user_id=\"${userId}\"></at>`;\n}\n\n/**\n * Format Feishu user mention for all users\n */\nexport function formatFeishuAtAll(): string {\n\treturn '<at user_id=\"all\"></at>';\n}\n\n/**\n * Truncate text to a maximum length\n */\nexport function truncateText(text: string, maxLength: number): string {\n\tif (text.length <= maxLength) {\n\t\treturn text;\n\t}\n\tif (maxLength <= 3) {\n\t\treturn \"...\".slice(0, maxLength);\n\t}\n\treturn `${text.slice(0, maxLength - 3)}...`;\n}\n\n/**\n * Resolve system location for logging\n */\nexport function resolveFeishuSystemLocation(params: {\n\tchatType: \"p2p\" | \"group\";\n\tchatId: string;\n\tchatName?: string;\n}): string {\n\tconst { chatType, chatId, chatName } = params;\n\tconst name = chatName || chatId.slice(0, 8);\n\treturn `Feishu ${chatType}:${name}`;\n}\n\n/**\n * Check if chat is a group chat\n */\nexport function isGroupChat(chatType: string): boolean {\n\treturn chatType === \"group\";\n}\n"
|
|
15
15
|
],
|
|
16
|
-
"mappings": "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",
|
|
17
|
-
"debugId": "
|
|
16
|
+
"mappings": "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",
|
|
17
|
+
"debugId": "A7228C401E12666064756E2164756E21",
|
|
18
18
|
"names": []
|
|
19
19
|
}
|