@m1heng-clawd/feishu 0.1.7 → 0.1.9
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 +180 -8
- package/package.json +3 -3
- package/src/accounts.ts +100 -13
- package/src/bot.ts +124 -28
- package/src/channel.ts +163 -53
- package/src/client.ts +83 -35
- package/src/config-schema.ts +73 -1
- package/src/directory.ts +15 -9
- package/src/docx.ts +16 -6
- package/src/drive.ts +12 -6
- package/src/dynamic-agent.ts +131 -0
- package/src/media.ts +43 -35
- package/src/monitor.ts +215 -70
- package/src/outbound.ts +7 -7
- package/src/perm.ts +12 -6
- package/src/probe.ts +6 -9
- package/src/reactions.ts +19 -16
- package/src/reply-dispatcher.ts +19 -11
- package/src/send.ts +49 -43
- package/src/types.ts +16 -2
- package/src/typing.ts +11 -9
- package/src/wiki.ts +12 -6
package/src/reactions.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClawdbotConfig } from "openclaw/plugin-sdk";
|
|
2
|
-
import type { FeishuConfig } from "./types.js";
|
|
3
2
|
import { createFeishuClient } from "./client.js";
|
|
3
|
+
import { resolveFeishuAccount } from "./accounts.js";
|
|
4
4
|
|
|
5
5
|
export type FeishuReaction = {
|
|
6
6
|
reactionId: string;
|
|
@@ -18,14 +18,15 @@ export async function addReactionFeishu(params: {
|
|
|
18
18
|
cfg: ClawdbotConfig;
|
|
19
19
|
messageId: string;
|
|
20
20
|
emojiType: string;
|
|
21
|
+
accountId?: string;
|
|
21
22
|
}): Promise<{ reactionId: string }> {
|
|
22
|
-
const { cfg, messageId, emojiType } = params;
|
|
23
|
-
const
|
|
24
|
-
if (!
|
|
25
|
-
throw new Error(
|
|
23
|
+
const { cfg, messageId, emojiType, accountId } = params;
|
|
24
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
25
|
+
if (!account.configured) {
|
|
26
|
+
throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
const client = createFeishuClient(
|
|
29
|
+
const client = createFeishuClient(account);
|
|
29
30
|
|
|
30
31
|
const response = (await client.im.messageReaction.create({
|
|
31
32
|
path: { message_id: messageId },
|
|
@@ -59,14 +60,15 @@ export async function removeReactionFeishu(params: {
|
|
|
59
60
|
cfg: ClawdbotConfig;
|
|
60
61
|
messageId: string;
|
|
61
62
|
reactionId: string;
|
|
63
|
+
accountId?: string;
|
|
62
64
|
}): Promise<void> {
|
|
63
|
-
const { cfg, messageId, reactionId } = params;
|
|
64
|
-
const
|
|
65
|
-
if (!
|
|
66
|
-
throw new Error(
|
|
65
|
+
const { cfg, messageId, reactionId, accountId } = params;
|
|
66
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
67
|
+
if (!account.configured) {
|
|
68
|
+
throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
const client = createFeishuClient(
|
|
71
|
+
const client = createFeishuClient(account);
|
|
70
72
|
|
|
71
73
|
const response = (await client.im.messageReaction.delete({
|
|
72
74
|
path: {
|
|
@@ -87,14 +89,15 @@ export async function listReactionsFeishu(params: {
|
|
|
87
89
|
cfg: ClawdbotConfig;
|
|
88
90
|
messageId: string;
|
|
89
91
|
emojiType?: string;
|
|
92
|
+
accountId?: string;
|
|
90
93
|
}): Promise<FeishuReaction[]> {
|
|
91
|
-
const { cfg, messageId, emojiType } = params;
|
|
92
|
-
const
|
|
93
|
-
if (!
|
|
94
|
-
throw new Error(
|
|
94
|
+
const { cfg, messageId, emojiType, accountId } = params;
|
|
95
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
96
|
+
if (!account.configured) {
|
|
97
|
+
throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
95
98
|
}
|
|
96
99
|
|
|
97
|
-
const client = createFeishuClient(
|
|
100
|
+
const client = createFeishuClient(account);
|
|
98
101
|
|
|
99
102
|
const response = (await client.im.messageReaction.list({
|
|
100
103
|
path: { message_id: messageId },
|
package/src/reply-dispatcher.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { getFeishuRuntime } from "./runtime.js";
|
|
|
10
10
|
import { sendMessageFeishu, sendMarkdownCardFeishu } from "./send.js";
|
|
11
11
|
import type { FeishuConfig } from "./types.js";
|
|
12
12
|
import type { MentionTarget } from "./mention.js";
|
|
13
|
+
import { resolveFeishuAccount } from "./accounts.js";
|
|
13
14
|
import {
|
|
14
15
|
addTypingIndicator,
|
|
15
16
|
removeTypingIndicator,
|
|
@@ -36,11 +37,16 @@ export type CreateFeishuReplyDispatcherParams = {
|
|
|
36
37
|
replyToMessageId?: string;
|
|
37
38
|
/** Mention targets, will be auto-included in replies */
|
|
38
39
|
mentionTargets?: MentionTarget[];
|
|
40
|
+
/** Account ID for multi-account support */
|
|
41
|
+
accountId?: string;
|
|
39
42
|
};
|
|
40
43
|
|
|
41
44
|
export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherParams) {
|
|
42
45
|
const core = getFeishuRuntime();
|
|
43
|
-
const { cfg, agentId, chatId, replyToMessageId, mentionTargets } = params;
|
|
46
|
+
const { cfg, agentId, chatId, replyToMessageId, mentionTargets, accountId } = params;
|
|
47
|
+
|
|
48
|
+
// Resolve account for config access
|
|
49
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
44
50
|
|
|
45
51
|
const prefixContext = createReplyPrefixContext({
|
|
46
52
|
cfg,
|
|
@@ -54,14 +60,14 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
|
|
|
54
60
|
const typingCallbacks = createTypingCallbacks({
|
|
55
61
|
start: async () => {
|
|
56
62
|
if (!replyToMessageId) return;
|
|
57
|
-
typingState = await addTypingIndicator({ cfg, messageId: replyToMessageId });
|
|
58
|
-
params.runtime.log?.(`feishu: added typing indicator reaction`);
|
|
63
|
+
typingState = await addTypingIndicator({ cfg, messageId: replyToMessageId, accountId });
|
|
64
|
+
params.runtime.log?.(`feishu[${account.accountId}]: added typing indicator reaction`);
|
|
59
65
|
},
|
|
60
66
|
stop: async () => {
|
|
61
67
|
if (!typingState) return;
|
|
62
|
-
await removeTypingIndicator({ cfg, state: typingState });
|
|
68
|
+
await removeTypingIndicator({ cfg, state: typingState, accountId });
|
|
63
69
|
typingState = null;
|
|
64
|
-
params.runtime.log?.(`feishu: removed typing indicator reaction`);
|
|
70
|
+
params.runtime.log?.(`feishu[${account.accountId}]: removed typing indicator reaction`);
|
|
65
71
|
},
|
|
66
72
|
onStartError: (err) => {
|
|
67
73
|
logTypingFailure({
|
|
@@ -99,15 +105,15 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
|
|
|
99
105
|
humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, agentId),
|
|
100
106
|
onReplyStart: typingCallbacks.onReplyStart,
|
|
101
107
|
deliver: async (payload: ReplyPayload) => {
|
|
102
|
-
params.runtime.log?.(`feishu deliver called: text=${payload.text?.slice(0, 100)}`);
|
|
108
|
+
params.runtime.log?.(`feishu[${account.accountId}] deliver called: text=${payload.text?.slice(0, 100)}`);
|
|
103
109
|
const text = payload.text ?? "";
|
|
104
110
|
if (!text.trim()) {
|
|
105
|
-
params.runtime.log?.(`feishu deliver: empty text, skipping`);
|
|
111
|
+
params.runtime.log?.(`feishu[${account.accountId}] deliver: empty text, skipping`);
|
|
106
112
|
return;
|
|
107
113
|
}
|
|
108
114
|
|
|
109
115
|
// Check render mode: auto (default), raw, or card
|
|
110
|
-
const feishuCfg =
|
|
116
|
+
const feishuCfg = account.config;
|
|
111
117
|
const renderMode = feishuCfg?.renderMode ?? "auto";
|
|
112
118
|
|
|
113
119
|
// Determine if we should use card for this message
|
|
@@ -120,7 +126,7 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
|
|
|
120
126
|
if (useCard) {
|
|
121
127
|
// Card mode: send as interactive card with markdown rendering
|
|
122
128
|
const chunks = core.channel.text.chunkTextWithMode(text, textChunkLimit, chunkMode);
|
|
123
|
-
params.runtime.log?.(`feishu deliver: sending ${chunks.length} card chunks to ${chatId}`);
|
|
129
|
+
params.runtime.log?.(`feishu[${account.accountId}] deliver: sending ${chunks.length} card chunks to ${chatId}`);
|
|
124
130
|
for (const chunk of chunks) {
|
|
125
131
|
await sendMarkdownCardFeishu({
|
|
126
132
|
cfg,
|
|
@@ -128,6 +134,7 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
|
|
|
128
134
|
text: chunk,
|
|
129
135
|
replyToMessageId,
|
|
130
136
|
mentions: isFirstChunk ? mentionTargets : undefined,
|
|
137
|
+
accountId,
|
|
131
138
|
});
|
|
132
139
|
isFirstChunk = false;
|
|
133
140
|
}
|
|
@@ -135,7 +142,7 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
|
|
|
135
142
|
// Raw mode: send as plain text with table conversion
|
|
136
143
|
const converted = core.channel.text.convertMarkdownTables(text, tableMode);
|
|
137
144
|
const chunks = core.channel.text.chunkTextWithMode(converted, textChunkLimit, chunkMode);
|
|
138
|
-
params.runtime.log?.(`feishu deliver: sending ${chunks.length} text chunks to ${chatId}`);
|
|
145
|
+
params.runtime.log?.(`feishu[${account.accountId}] deliver: sending ${chunks.length} text chunks to ${chatId}`);
|
|
139
146
|
for (const chunk of chunks) {
|
|
140
147
|
await sendMessageFeishu({
|
|
141
148
|
cfg,
|
|
@@ -143,13 +150,14 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
|
|
|
143
150
|
text: chunk,
|
|
144
151
|
replyToMessageId,
|
|
145
152
|
mentions: isFirstChunk ? mentionTargets : undefined,
|
|
153
|
+
accountId,
|
|
146
154
|
});
|
|
147
155
|
isFirstChunk = false;
|
|
148
156
|
}
|
|
149
157
|
}
|
|
150
158
|
},
|
|
151
159
|
onError: (err, info) => {
|
|
152
|
-
params.runtime.error?.(`feishu ${info.kind} reply failed: ${String(err)}`);
|
|
160
|
+
params.runtime.error?.(`feishu[${account.accountId}] ${info.kind} reply failed: ${String(err)}`);
|
|
153
161
|
typingCallbacks.onIdle?.();
|
|
154
162
|
},
|
|
155
163
|
onIdle: typingCallbacks.onIdle,
|
package/src/send.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ClawdbotConfig } from "openclaw/plugin-sdk";
|
|
2
|
-
import type {
|
|
2
|
+
import type { FeishuSendResult, ResolvedFeishuAccount } from "./types.js";
|
|
3
3
|
import type { MentionTarget } from "./mention.js";
|
|
4
4
|
import { buildMentionedMessage, buildMentionedCardContent } from "./mention.js";
|
|
5
5
|
import { createFeishuClient } from "./client.js";
|
|
6
6
|
import { resolveReceiveIdType, normalizeFeishuTarget } from "./targets.js";
|
|
7
7
|
import { getFeishuRuntime } from "./runtime.js";
|
|
8
|
+
import { resolveFeishuAccount } from "./accounts.js";
|
|
8
9
|
|
|
9
10
|
export type FeishuMessageInfo = {
|
|
10
11
|
messageId: string;
|
|
@@ -23,14 +24,15 @@ export type FeishuMessageInfo = {
|
|
|
23
24
|
export async function getMessageFeishu(params: {
|
|
24
25
|
cfg: ClawdbotConfig;
|
|
25
26
|
messageId: string;
|
|
27
|
+
accountId?: string;
|
|
26
28
|
}): Promise<FeishuMessageInfo | null> {
|
|
27
|
-
const { cfg, messageId } = params;
|
|
28
|
-
const
|
|
29
|
-
if (!
|
|
30
|
-
throw new Error(
|
|
29
|
+
const { cfg, messageId, accountId } = params;
|
|
30
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
31
|
+
if (!account.configured) {
|
|
32
|
+
throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
const client = createFeishuClient(
|
|
35
|
+
const client = createFeishuClient(account);
|
|
34
36
|
|
|
35
37
|
try {
|
|
36
38
|
const response = (await client.im.message.get({
|
|
@@ -95,9 +97,11 @@ export type SendFeishuMessageParams = {
|
|
|
95
97
|
replyToMessageId?: string;
|
|
96
98
|
/** Mention target users */
|
|
97
99
|
mentions?: MentionTarget[];
|
|
100
|
+
/** Account ID (optional, uses default if not specified) */
|
|
101
|
+
accountId?: string;
|
|
98
102
|
};
|
|
99
103
|
|
|
100
|
-
function buildFeishuPostMessagePayload(params: {
|
|
104
|
+
function buildFeishuPostMessagePayload(params: { messageText: string }): {
|
|
101
105
|
content: string;
|
|
102
106
|
msgType: string;
|
|
103
107
|
} {
|
|
@@ -120,13 +124,13 @@ function buildFeishuPostMessagePayload(params: { feishuCfg: FeishuConfig; messag
|
|
|
120
124
|
}
|
|
121
125
|
|
|
122
126
|
export async function sendMessageFeishu(params: SendFeishuMessageParams): Promise<FeishuSendResult> {
|
|
123
|
-
const { cfg, to, text, replyToMessageId, mentions } = params;
|
|
124
|
-
const
|
|
125
|
-
if (!
|
|
126
|
-
throw new Error(
|
|
127
|
+
const { cfg, to, text, replyToMessageId, mentions, accountId } = params;
|
|
128
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
129
|
+
if (!account.configured) {
|
|
130
|
+
throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
127
131
|
}
|
|
128
132
|
|
|
129
|
-
const client = createFeishuClient(
|
|
133
|
+
const client = createFeishuClient(account);
|
|
130
134
|
const receiveId = normalizeFeishuTarget(to);
|
|
131
135
|
if (!receiveId) {
|
|
132
136
|
throw new Error(`Invalid Feishu target: ${to}`);
|
|
@@ -145,10 +149,7 @@ export async function sendMessageFeishu(params: SendFeishuMessageParams): Promis
|
|
|
145
149
|
}
|
|
146
150
|
const messageText = getFeishuRuntime().channel.text.convertMarkdownTables(rawText, tableMode);
|
|
147
151
|
|
|
148
|
-
const { content, msgType } = buildFeishuPostMessagePayload({
|
|
149
|
-
feishuCfg,
|
|
150
|
-
messageText,
|
|
151
|
-
});
|
|
152
|
+
const { content, msgType } = buildFeishuPostMessagePayload({ messageText });
|
|
152
153
|
|
|
153
154
|
if (replyToMessageId) {
|
|
154
155
|
const response = await client.im.message.reply({
|
|
@@ -193,16 +194,17 @@ export type SendFeishuCardParams = {
|
|
|
193
194
|
to: string;
|
|
194
195
|
card: Record<string, unknown>;
|
|
195
196
|
replyToMessageId?: string;
|
|
197
|
+
accountId?: string;
|
|
196
198
|
};
|
|
197
199
|
|
|
198
200
|
export async function sendCardFeishu(params: SendFeishuCardParams): Promise<FeishuSendResult> {
|
|
199
|
-
const { cfg, to, card, replyToMessageId } = params;
|
|
200
|
-
const
|
|
201
|
-
if (!
|
|
202
|
-
throw new Error(
|
|
201
|
+
const { cfg, to, card, replyToMessageId, accountId } = params;
|
|
202
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
203
|
+
if (!account.configured) {
|
|
204
|
+
throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
203
205
|
}
|
|
204
206
|
|
|
205
|
-
const client = createFeishuClient(
|
|
207
|
+
const client = createFeishuClient(account);
|
|
206
208
|
const receiveId = normalizeFeishuTarget(to);
|
|
207
209
|
if (!receiveId) {
|
|
208
210
|
throw new Error(`Invalid Feishu target: ${to}`);
|
|
@@ -253,14 +255,15 @@ export async function updateCardFeishu(params: {
|
|
|
253
255
|
cfg: ClawdbotConfig;
|
|
254
256
|
messageId: string;
|
|
255
257
|
card: Record<string, unknown>;
|
|
258
|
+
accountId?: string;
|
|
256
259
|
}): Promise<void> {
|
|
257
|
-
const { cfg, messageId, card } = params;
|
|
258
|
-
const
|
|
259
|
-
if (!
|
|
260
|
-
throw new Error(
|
|
260
|
+
const { cfg, messageId, card, accountId } = params;
|
|
261
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
262
|
+
if (!account.configured) {
|
|
263
|
+
throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
261
264
|
}
|
|
262
265
|
|
|
263
|
-
const client = createFeishuClient(
|
|
266
|
+
const client = createFeishuClient(account);
|
|
264
267
|
const content = JSON.stringify(card);
|
|
265
268
|
|
|
266
269
|
const response = await client.im.message.patch({
|
|
@@ -276,18 +279,22 @@ export async function updateCardFeishu(params: {
|
|
|
276
279
|
/**
|
|
277
280
|
* Build a Feishu interactive card with markdown content.
|
|
278
281
|
* Cards render markdown properly (code blocks, tables, links, etc.)
|
|
282
|
+
* Uses schema 2.0 format for proper markdown rendering.
|
|
279
283
|
*/
|
|
280
284
|
export function buildMarkdownCard(text: string): Record<string, unknown> {
|
|
281
285
|
return {
|
|
286
|
+
schema: "2.0",
|
|
282
287
|
config: {
|
|
283
288
|
wide_screen_mode: true,
|
|
284
289
|
},
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
290
|
+
body: {
|
|
291
|
+
elements: [
|
|
292
|
+
{
|
|
293
|
+
tag: "markdown",
|
|
294
|
+
content: text,
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
},
|
|
291
298
|
};
|
|
292
299
|
}
|
|
293
300
|
|
|
@@ -302,15 +309,16 @@ export async function sendMarkdownCardFeishu(params: {
|
|
|
302
309
|
replyToMessageId?: string;
|
|
303
310
|
/** Mention target users */
|
|
304
311
|
mentions?: MentionTarget[];
|
|
312
|
+
accountId?: string;
|
|
305
313
|
}): Promise<FeishuSendResult> {
|
|
306
|
-
const { cfg, to, text, replyToMessageId, mentions } = params;
|
|
314
|
+
const { cfg, to, text, replyToMessageId, mentions, accountId } = params;
|
|
307
315
|
// Build message content (with @mention support)
|
|
308
316
|
let cardText = text;
|
|
309
317
|
if (mentions && mentions.length > 0) {
|
|
310
318
|
cardText = buildMentionedCardContent(mentions, text);
|
|
311
319
|
}
|
|
312
320
|
const card = buildMarkdownCard(cardText);
|
|
313
|
-
return sendCardFeishu({ cfg, to, card, replyToMessageId });
|
|
321
|
+
return sendCardFeishu({ cfg, to, card, replyToMessageId, accountId });
|
|
314
322
|
}
|
|
315
323
|
|
|
316
324
|
/**
|
|
@@ -321,24 +329,22 @@ export async function editMessageFeishu(params: {
|
|
|
321
329
|
cfg: ClawdbotConfig;
|
|
322
330
|
messageId: string;
|
|
323
331
|
text: string;
|
|
332
|
+
accountId?: string;
|
|
324
333
|
}): Promise<void> {
|
|
325
|
-
const { cfg, messageId, text } = params;
|
|
326
|
-
const
|
|
327
|
-
if (!
|
|
328
|
-
throw new Error(
|
|
334
|
+
const { cfg, messageId, text, accountId } = params;
|
|
335
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
336
|
+
if (!account.configured) {
|
|
337
|
+
throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
329
338
|
}
|
|
330
339
|
|
|
331
|
-
const client = createFeishuClient(
|
|
340
|
+
const client = createFeishuClient(account);
|
|
332
341
|
const tableMode = getFeishuRuntime().channel.text.resolveMarkdownTableMode({
|
|
333
342
|
cfg,
|
|
334
343
|
channel: "feishu",
|
|
335
344
|
});
|
|
336
345
|
const messageText = getFeishuRuntime().channel.text.convertMarkdownTables(text ?? "", tableMode);
|
|
337
346
|
|
|
338
|
-
const { content, msgType } = buildFeishuPostMessagePayload({
|
|
339
|
-
feishuCfg,
|
|
340
|
-
messageText,
|
|
341
|
-
});
|
|
347
|
+
const { content, msgType } = buildFeishuPostMessagePayload({ messageText });
|
|
342
348
|
|
|
343
349
|
const response = await client.im.message.update({
|
|
344
350
|
path: { message_id: messageId },
|
package/src/types.ts
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
|
-
import type { FeishuConfigSchema, FeishuGroupSchema, z } from "./config-schema.js";
|
|
1
|
+
import type { FeishuConfigSchema, FeishuGroupSchema, FeishuAccountConfigSchema, z } from "./config-schema.js";
|
|
2
2
|
import type { MentionTarget } from "./mention.js";
|
|
3
3
|
|
|
4
4
|
export type FeishuConfig = z.infer<typeof FeishuConfigSchema>;
|
|
5
5
|
export type FeishuGroupConfig = z.infer<typeof FeishuGroupSchema>;
|
|
6
|
+
export type FeishuAccountConfig = z.infer<typeof FeishuAccountConfigSchema>;
|
|
6
7
|
|
|
7
|
-
export type FeishuDomain = "feishu" | "lark";
|
|
8
|
+
export type FeishuDomain = "feishu" | "lark" | (string & {});
|
|
8
9
|
export type FeishuConnectionMode = "websocket" | "webhook";
|
|
9
10
|
|
|
10
11
|
export type ResolvedFeishuAccount = {
|
|
11
12
|
accountId: string;
|
|
12
13
|
enabled: boolean;
|
|
13
14
|
configured: boolean;
|
|
15
|
+
name?: string;
|
|
14
16
|
appId?: string;
|
|
17
|
+
appSecret?: string;
|
|
18
|
+
encryptKey?: string;
|
|
19
|
+
verificationToken?: string;
|
|
15
20
|
domain: FeishuDomain;
|
|
21
|
+
/** Merged config (top-level defaults + account-specific overrides) */
|
|
22
|
+
config: FeishuConfig;
|
|
16
23
|
};
|
|
17
24
|
|
|
18
25
|
export type FeishuIdType = "open_id" | "user_id" | "union_id" | "chat_id";
|
|
@@ -61,3 +68,10 @@ export type FeishuToolsConfig = {
|
|
|
61
68
|
perm?: boolean;
|
|
62
69
|
scopes?: boolean;
|
|
63
70
|
};
|
|
71
|
+
|
|
72
|
+
export type DynamicAgentCreationConfig = {
|
|
73
|
+
enabled?: boolean;
|
|
74
|
+
workspaceTemplate?: string;
|
|
75
|
+
agentDirTemplate?: string;
|
|
76
|
+
maxAgents?: number;
|
|
77
|
+
};
|
package/src/typing.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClawdbotConfig } from "openclaw/plugin-sdk";
|
|
2
|
-
import type { FeishuConfig } from "./types.js";
|
|
3
2
|
import { createFeishuClient } from "./client.js";
|
|
3
|
+
import { resolveFeishuAccount } from "./accounts.js";
|
|
4
4
|
|
|
5
5
|
// Feishu emoji types for typing indicator
|
|
6
6
|
// See: https://open.feishu.cn/document/server-docs/im-v1/message-reaction/emojis-introduce
|
|
@@ -18,14 +18,15 @@ export type TypingIndicatorState = {
|
|
|
18
18
|
export async function addTypingIndicator(params: {
|
|
19
19
|
cfg: ClawdbotConfig;
|
|
20
20
|
messageId: string;
|
|
21
|
+
accountId?: string;
|
|
21
22
|
}): Promise<TypingIndicatorState> {
|
|
22
|
-
const { cfg, messageId } = params;
|
|
23
|
-
const
|
|
24
|
-
if (!
|
|
23
|
+
const { cfg, messageId, accountId } = params;
|
|
24
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
25
|
+
if (!account.configured) {
|
|
25
26
|
return { messageId, reactionId: null };
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
const client = createFeishuClient(
|
|
29
|
+
const client = createFeishuClient(account);
|
|
29
30
|
|
|
30
31
|
try {
|
|
31
32
|
const response = await client.im.messageReaction.create({
|
|
@@ -50,14 +51,15 @@ export async function addTypingIndicator(params: {
|
|
|
50
51
|
export async function removeTypingIndicator(params: {
|
|
51
52
|
cfg: ClawdbotConfig;
|
|
52
53
|
state: TypingIndicatorState;
|
|
54
|
+
accountId?: string;
|
|
53
55
|
}): Promise<void> {
|
|
54
|
-
const { cfg, state } = params;
|
|
56
|
+
const { cfg, state, accountId } = params;
|
|
55
57
|
if (!state.reactionId) return;
|
|
56
58
|
|
|
57
|
-
const
|
|
58
|
-
if (!
|
|
59
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
60
|
+
if (!account.configured) return;
|
|
59
61
|
|
|
60
|
-
const client = createFeishuClient(
|
|
62
|
+
const client = createFeishuClient(account);
|
|
61
63
|
|
|
62
64
|
try {
|
|
63
65
|
await client.im.messageReaction.delete({
|
package/src/wiki.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
2
|
import { createFeishuClient } from "./client.js";
|
|
3
|
-
import
|
|
3
|
+
import { listEnabledFeishuAccounts } from "./accounts.js";
|
|
4
4
|
import type * as Lark from "@larksuiteoapi/node-sdk";
|
|
5
5
|
import { FeishuWikiSchema, type FeishuWikiParams } from "./wiki-schema.js";
|
|
6
6
|
import { resolveToolsConfig } from "./tools-config.js";
|
|
@@ -150,19 +150,25 @@ async function renameNode(
|
|
|
150
150
|
// ============ Tool Registration ============
|
|
151
151
|
|
|
152
152
|
export function registerFeishuWikiTools(api: OpenClawPluginApi) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
api.logger.debug?.("feishu_wiki: Feishu credentials not configured, skipping wiki tools");
|
|
153
|
+
if (!api.config) {
|
|
154
|
+
api.logger.debug?.("feishu_wiki: No config available, skipping wiki tools");
|
|
156
155
|
return;
|
|
157
156
|
}
|
|
158
157
|
|
|
159
|
-
const
|
|
158
|
+
const accounts = listEnabledFeishuAccounts(api.config);
|
|
159
|
+
if (accounts.length === 0) {
|
|
160
|
+
api.logger.debug?.("feishu_wiki: No Feishu accounts configured, skipping wiki tools");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const firstAccount = accounts[0];
|
|
165
|
+
const toolsCfg = resolveToolsConfig(firstAccount.config.tools);
|
|
160
166
|
if (!toolsCfg.wiki) {
|
|
161
167
|
api.logger.debug?.("feishu_wiki: wiki tool disabled in config");
|
|
162
168
|
return;
|
|
163
169
|
}
|
|
164
170
|
|
|
165
|
-
const getClient = () => createFeishuClient(
|
|
171
|
+
const getClient = () => createFeishuClient(firstAccount);
|
|
166
172
|
|
|
167
173
|
api.registerTool(
|
|
168
174
|
{
|