mirror of https://github.com/openclaw/openclaw.git
193 lines
5.6 KiB
TypeScript
193 lines
5.6 KiB
TypeScript
import type * as Lark from "@larksuiteoapi/node-sdk";
|
|
import type { OpenClawPluginApi } from "../runtime-api.js";
|
|
import { listEnabledFeishuAccounts } from "./accounts.js";
|
|
import { FeishuChatSchema, type FeishuChatParams } from "./chat-schema.js";
|
|
import { createFeishuClient } from "./client.js";
|
|
import { resolveToolsConfig } from "./tools-config.js";
|
|
|
|
function json(data: unknown) {
|
|
return {
|
|
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
|
|
details: data,
|
|
};
|
|
}
|
|
|
|
export async function getChatInfo(client: Lark.Client, chatId: string) {
|
|
const res = await client.im.chat.get({ path: { chat_id: chatId } });
|
|
if (res.code !== 0) {
|
|
throw new Error(res.msg);
|
|
}
|
|
|
|
const chat = res.data;
|
|
return {
|
|
chat_id: chatId,
|
|
name: chat?.name,
|
|
description: chat?.description,
|
|
owner_id: chat?.owner_id,
|
|
tenant_key: chat?.tenant_key,
|
|
user_count: chat?.user_count,
|
|
chat_mode: chat?.chat_mode,
|
|
chat_type: chat?.chat_type,
|
|
join_message_visibility: chat?.join_message_visibility,
|
|
leave_message_visibility: chat?.leave_message_visibility,
|
|
membership_approval: chat?.membership_approval,
|
|
moderation_permission: chat?.moderation_permission,
|
|
avatar: chat?.avatar,
|
|
};
|
|
}
|
|
|
|
export async function getChatMembers(
|
|
client: Lark.Client,
|
|
chatId: string,
|
|
pageSize?: number,
|
|
pageToken?: string,
|
|
memberIdType?: "open_id" | "user_id" | "union_id",
|
|
) {
|
|
const page_size = pageSize ? Math.max(1, Math.min(100, pageSize)) : 50;
|
|
const res = await client.im.chatMembers.get({
|
|
path: { chat_id: chatId },
|
|
params: {
|
|
page_size,
|
|
page_token: pageToken,
|
|
member_id_type: memberIdType ?? "open_id",
|
|
},
|
|
});
|
|
|
|
if (res.code !== 0) {
|
|
throw new Error(res.msg);
|
|
}
|
|
|
|
return {
|
|
chat_id: chatId,
|
|
has_more: res.data?.has_more,
|
|
page_token: res.data?.page_token,
|
|
members:
|
|
res.data?.items?.map((item) => ({
|
|
member_id: item.member_id,
|
|
name: item.name,
|
|
tenant_key: item.tenant_key,
|
|
member_id_type: item.member_id_type,
|
|
})) ?? [],
|
|
};
|
|
}
|
|
|
|
export async function getFeishuMemberInfo(
|
|
client: Lark.Client,
|
|
memberId: string,
|
|
memberIdType: "open_id" | "user_id" | "union_id" = "open_id",
|
|
) {
|
|
const res = await client.contact.user.get({
|
|
path: { user_id: memberId },
|
|
params: {
|
|
user_id_type: memberIdType,
|
|
department_id_type: "open_department_id",
|
|
},
|
|
});
|
|
|
|
if (res.code !== 0) {
|
|
throw new Error(res.msg);
|
|
}
|
|
|
|
const user = res.data?.user;
|
|
return {
|
|
member_id: memberId,
|
|
member_id_type: memberIdType,
|
|
open_id: user?.open_id,
|
|
user_id: user?.user_id,
|
|
union_id: user?.union_id,
|
|
name: user?.name,
|
|
en_name: user?.en_name,
|
|
nickname: user?.nickname,
|
|
email: user?.email,
|
|
enterprise_email: user?.enterprise_email,
|
|
mobile: user?.mobile,
|
|
mobile_visible: user?.mobile_visible,
|
|
status: user?.status,
|
|
avatar: user?.avatar,
|
|
department_ids: user?.department_ids,
|
|
department_path: user?.department_path,
|
|
leader_user_id: user?.leader_user_id,
|
|
city: user?.city,
|
|
country: user?.country,
|
|
work_station: user?.work_station,
|
|
join_time: user?.join_time,
|
|
is_tenant_manager: user?.is_tenant_manager,
|
|
employee_no: user?.employee_no,
|
|
employee_type: user?.employee_type,
|
|
description: user?.description,
|
|
job_title: user?.job_title,
|
|
geo: user?.geo,
|
|
};
|
|
}
|
|
|
|
export function registerFeishuChatTools(api: OpenClawPluginApi) {
|
|
if (!api.config) {
|
|
api.logger.debug?.("feishu_chat: No config available, skipping chat tools");
|
|
return;
|
|
}
|
|
|
|
const accounts = listEnabledFeishuAccounts(api.config);
|
|
if (accounts.length === 0) {
|
|
api.logger.debug?.("feishu_chat: No Feishu accounts configured, skipping chat tools");
|
|
return;
|
|
}
|
|
|
|
const firstAccount = accounts[0];
|
|
const toolsCfg = resolveToolsConfig(firstAccount.config.tools);
|
|
if (!toolsCfg.chat) {
|
|
api.logger.debug?.("feishu_chat: chat tool disabled in config");
|
|
return;
|
|
}
|
|
|
|
const getClient = () => createFeishuClient(firstAccount);
|
|
|
|
api.registerTool(
|
|
{
|
|
name: "feishu_chat",
|
|
label: "Feishu Chat",
|
|
description: "Feishu chat operations. Actions: members, info, member_info",
|
|
parameters: FeishuChatSchema,
|
|
async execute(_toolCallId, params) {
|
|
const p = params as FeishuChatParams;
|
|
try {
|
|
const client = getClient();
|
|
switch (p.action) {
|
|
case "members":
|
|
if (!p.chat_id) {
|
|
return json({ error: "chat_id is required for action members" });
|
|
}
|
|
return json(
|
|
await getChatMembers(
|
|
client,
|
|
p.chat_id,
|
|
p.page_size,
|
|
p.page_token,
|
|
p.member_id_type,
|
|
),
|
|
);
|
|
case "info":
|
|
if (!p.chat_id) {
|
|
return json({ error: "chat_id is required for action info" });
|
|
}
|
|
return json(await getChatInfo(client, p.chat_id));
|
|
case "member_info":
|
|
if (!p.member_id) {
|
|
return json({ error: "member_id is required for action member_info" });
|
|
}
|
|
return json(
|
|
await getFeishuMemberInfo(client, p.member_id, p.member_id_type ?? "open_id"),
|
|
);
|
|
default:
|
|
return json({ error: `Unknown action: ${String(p.action)}` });
|
|
}
|
|
} catch (err) {
|
|
return json({ error: err instanceof Error ? err.message : String(err) });
|
|
}
|
|
},
|
|
},
|
|
{ name: "feishu_chat" },
|
|
);
|
|
|
|
api.logger.info?.("feishu_chat: Registered feishu_chat tool");
|
|
}
|