@openclaw/feishu 2026.3.1 → 2026.3.7
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/index.ts +2 -2
- package/package.json +1 -1
- package/src/accounts.test.ts +268 -11
- package/src/accounts.ts +101 -14
- package/src/bitable.ts +40 -28
- package/src/bot.checkBotMentioned.test.ts +9 -1
- package/src/bot.stripBotMention.test.ts +118 -22
- package/src/bot.test.ts +945 -77
- package/src/bot.ts +492 -165
- package/src/card-action.ts +1 -1
- package/src/channel.test.ts +1 -1
- package/src/channel.ts +72 -68
- package/src/chat.test.ts +2 -2
- package/src/chat.ts +1 -1
- package/src/client.test.ts +221 -4
- package/src/client.ts +70 -5
- package/src/config-schema.test.ts +33 -6
- package/src/config-schema.ts +18 -10
- package/src/dedup.ts +47 -1
- package/src/directory.test.ts +40 -0
- package/src/directory.ts +29 -50
- package/src/doc-schema.ts +16 -22
- package/src/docx-batch-insert.test.ts +90 -0
- package/src/docx-batch-insert.ts +8 -11
- package/src/docx.account-selection.test.ts +10 -16
- package/src/docx.test.ts +41 -189
- package/src/docx.ts +1 -1
- package/src/drive.ts +13 -17
- package/src/dynamic-agent.ts +1 -1
- package/src/feishu-command-handler.ts +59 -0
- package/src/media.test.ts +164 -14
- package/src/media.ts +44 -10
- package/src/mention.ts +1 -1
- package/src/monitor.account.ts +284 -25
- package/src/monitor.reaction.test.ts +395 -46
- package/src/monitor.startup.test.ts +25 -8
- package/src/monitor.startup.ts +20 -7
- package/src/monitor.state.defaults.test.ts +46 -0
- package/src/monitor.state.ts +88 -9
- package/src/monitor.test-mocks.ts +45 -0
- package/src/monitor.transport.ts +4 -1
- package/src/monitor.ts +4 -4
- package/src/monitor.webhook-security.test.ts +13 -11
- package/src/onboarding.status.test.ts +25 -0
- package/src/onboarding.test.ts +143 -0
- package/src/onboarding.ts +213 -106
- package/src/outbound.test.ts +178 -0
- package/src/outbound.ts +39 -6
- package/src/perm.ts +11 -15
- package/src/policy.test.ts +40 -0
- package/src/policy.ts +9 -10
- package/src/probe.test.ts +54 -36
- package/src/probe.ts +57 -37
- package/src/reactions.ts +1 -1
- package/src/reply-dispatcher.test.ts +216 -0
- package/src/reply-dispatcher.ts +89 -22
- package/src/runtime.ts +1 -1
- package/src/secret-input.ts +13 -0
- package/src/send-message.ts +71 -0
- package/src/send-target.test.ts +74 -0
- package/src/send-target.ts +7 -3
- package/src/send.reply-fallback.test.ts +74 -0
- package/src/send.test.ts +1 -1
- package/src/send.ts +88 -49
- package/src/streaming-card.test.ts +54 -0
- package/src/streaming-card.ts +96 -28
- package/src/targets.test.ts +29 -0
- package/src/targets.ts +25 -1
- package/src/tool-account-routing.test.ts +3 -3
- package/src/tool-account.ts +1 -1
- package/src/tool-factory-test-harness.ts +1 -1
- package/src/tool-result.test.ts +32 -0
- package/src/tool-result.ts +14 -0
- package/src/types.ts +11 -4
- package/src/typing.ts +1 -1
- package/src/wiki.ts +15 -19
package/src/docx.test.ts
CHANGED
|
@@ -114,6 +114,29 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
114
114
|
scopeListMock.mockResolvedValue({ code: 0, data: { scopes: [] } });
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
+
function resolveFeishuDocTool(context: Record<string, unknown> = {}) {
|
|
118
|
+
const registerTool = vi.fn();
|
|
119
|
+
registerFeishuDocTools({
|
|
120
|
+
config: {
|
|
121
|
+
channels: {
|
|
122
|
+
feishu: {
|
|
123
|
+
appId: "app_id",
|
|
124
|
+
appSecret: "app_secret",
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
} as any,
|
|
128
|
+
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
129
|
+
registerTool,
|
|
130
|
+
} as any);
|
|
131
|
+
|
|
132
|
+
const tool = registerTool.mock.calls
|
|
133
|
+
.map((call) => call[0])
|
|
134
|
+
.map((candidate) => (typeof candidate === "function" ? candidate(context) : candidate))
|
|
135
|
+
.find((candidate) => candidate.name === "feishu_doc");
|
|
136
|
+
expect(tool).toBeDefined();
|
|
137
|
+
return tool as { execute: (callId: string, params: Record<string, unknown>) => Promise<any> };
|
|
138
|
+
}
|
|
139
|
+
|
|
117
140
|
it("inserts blocks sequentially to preserve document order", async () => {
|
|
118
141
|
const blocks = [
|
|
119
142
|
{ block_type: 3, block_id: "h1" },
|
|
@@ -135,22 +158,7 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
135
158
|
data: { children: [{ block_type: 3, block_id: "h1" }] },
|
|
136
159
|
});
|
|
137
160
|
|
|
138
|
-
const
|
|
139
|
-
registerFeishuDocTools({
|
|
140
|
-
config: {
|
|
141
|
-
channels: {
|
|
142
|
-
feishu: { appId: "app_id", appSecret: "app_secret" },
|
|
143
|
-
},
|
|
144
|
-
} as any,
|
|
145
|
-
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
146
|
-
registerTool,
|
|
147
|
-
} as any);
|
|
148
|
-
|
|
149
|
-
const feishuDocTool = registerTool.mock.calls
|
|
150
|
-
.map((call) => call[0])
|
|
151
|
-
.map((tool) => (typeof tool === "function" ? tool({}) : tool))
|
|
152
|
-
.find((tool) => tool.name === "feishu_doc");
|
|
153
|
-
expect(feishuDocTool).toBeDefined();
|
|
161
|
+
const feishuDocTool = resolveFeishuDocTool();
|
|
154
162
|
|
|
155
163
|
const result = await feishuDocTool.execute("tool-call", {
|
|
156
164
|
action: "append",
|
|
@@ -194,22 +202,7 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
194
202
|
},
|
|
195
203
|
}));
|
|
196
204
|
|
|
197
|
-
const
|
|
198
|
-
registerFeishuDocTools({
|
|
199
|
-
config: {
|
|
200
|
-
channels: {
|
|
201
|
-
feishu: { appId: "app_id", appSecret: "app_secret" },
|
|
202
|
-
},
|
|
203
|
-
} as any,
|
|
204
|
-
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
205
|
-
registerTool,
|
|
206
|
-
} as any);
|
|
207
|
-
|
|
208
|
-
const feishuDocTool = registerTool.mock.calls
|
|
209
|
-
.map((call) => call[0])
|
|
210
|
-
.map((tool) => (typeof tool === "function" ? tool({}) : tool))
|
|
211
|
-
.find((tool) => tool.name === "feishu_doc");
|
|
212
|
-
expect(feishuDocTool).toBeDefined();
|
|
205
|
+
const feishuDocTool = resolveFeishuDocTool();
|
|
213
206
|
|
|
214
207
|
const longMarkdown = Array.from(
|
|
215
208
|
{ length: 120 },
|
|
@@ -254,22 +247,7 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
254
247
|
data: { children: data.children },
|
|
255
248
|
}));
|
|
256
249
|
|
|
257
|
-
const
|
|
258
|
-
registerFeishuDocTools({
|
|
259
|
-
config: {
|
|
260
|
-
channels: {
|
|
261
|
-
feishu: { appId: "app_id", appSecret: "app_secret" },
|
|
262
|
-
},
|
|
263
|
-
} as any,
|
|
264
|
-
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
265
|
-
registerTool,
|
|
266
|
-
} as any);
|
|
267
|
-
|
|
268
|
-
const feishuDocTool = registerTool.mock.calls
|
|
269
|
-
.map((call) => call[0])
|
|
270
|
-
.map((tool) => (typeof tool === "function" ? tool({}) : tool))
|
|
271
|
-
.find((tool) => tool.name === "feishu_doc");
|
|
272
|
-
expect(feishuDocTool).toBeDefined();
|
|
250
|
+
const feishuDocTool = resolveFeishuDocTool();
|
|
273
251
|
|
|
274
252
|
const fencedMarkdown = [
|
|
275
253
|
"## Section",
|
|
@@ -306,25 +284,7 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
306
284
|
new Error("Blocked: resolves to private/internal IP address"),
|
|
307
285
|
);
|
|
308
286
|
|
|
309
|
-
const
|
|
310
|
-
registerFeishuDocTools({
|
|
311
|
-
config: {
|
|
312
|
-
channels: {
|
|
313
|
-
feishu: {
|
|
314
|
-
appId: "app_id",
|
|
315
|
-
appSecret: "app_secret",
|
|
316
|
-
},
|
|
317
|
-
},
|
|
318
|
-
} as any,
|
|
319
|
-
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
320
|
-
registerTool,
|
|
321
|
-
} as any);
|
|
322
|
-
|
|
323
|
-
const feishuDocTool = registerTool.mock.calls
|
|
324
|
-
.map((call) => call[0])
|
|
325
|
-
.map((tool) => (typeof tool === "function" ? tool({}) : tool))
|
|
326
|
-
.find((tool) => tool.name === "feishu_doc");
|
|
327
|
-
expect(feishuDocTool).toBeDefined();
|
|
287
|
+
const feishuDocTool = resolveFeishuDocTool();
|
|
328
288
|
|
|
329
289
|
const result = await feishuDocTool.execute("tool-call", {
|
|
330
290
|
action: "write",
|
|
@@ -341,29 +301,10 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
341
301
|
});
|
|
342
302
|
|
|
343
303
|
it("create grants permission only to trusted Feishu requester", async () => {
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
feishu: {
|
|
349
|
-
appId: "app_id",
|
|
350
|
-
appSecret: "app_secret",
|
|
351
|
-
},
|
|
352
|
-
},
|
|
353
|
-
} as any,
|
|
354
|
-
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
355
|
-
registerTool,
|
|
356
|
-
} as any);
|
|
357
|
-
|
|
358
|
-
const feishuDocTool = registerTool.mock.calls
|
|
359
|
-
.map((call) => call[0])
|
|
360
|
-
.map((tool) =>
|
|
361
|
-
typeof tool === "function"
|
|
362
|
-
? tool({ messageChannel: "feishu", requesterSenderId: "ou_123" })
|
|
363
|
-
: tool,
|
|
364
|
-
)
|
|
365
|
-
.find((tool) => tool.name === "feishu_doc");
|
|
366
|
-
expect(feishuDocTool).toBeDefined();
|
|
304
|
+
const feishuDocTool = resolveFeishuDocTool({
|
|
305
|
+
messageChannel: "feishu",
|
|
306
|
+
requesterSenderId: "ou_123",
|
|
307
|
+
});
|
|
367
308
|
|
|
368
309
|
const result = await feishuDocTool.execute("tool-call", {
|
|
369
310
|
action: "create",
|
|
@@ -386,25 +327,9 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
386
327
|
});
|
|
387
328
|
|
|
388
329
|
it("create skips requester grant when trusted requester identity is unavailable", async () => {
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
channels: {
|
|
393
|
-
feishu: {
|
|
394
|
-
appId: "app_id",
|
|
395
|
-
appSecret: "app_secret",
|
|
396
|
-
},
|
|
397
|
-
},
|
|
398
|
-
} as any,
|
|
399
|
-
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
400
|
-
registerTool,
|
|
401
|
-
} as any);
|
|
402
|
-
|
|
403
|
-
const feishuDocTool = registerTool.mock.calls
|
|
404
|
-
.map((call) => call[0])
|
|
405
|
-
.map((tool) => (typeof tool === "function" ? tool({ messageChannel: "feishu" }) : tool))
|
|
406
|
-
.find((tool) => tool.name === "feishu_doc");
|
|
407
|
-
expect(feishuDocTool).toBeDefined();
|
|
330
|
+
const feishuDocTool = resolveFeishuDocTool({
|
|
331
|
+
messageChannel: "feishu",
|
|
332
|
+
});
|
|
408
333
|
|
|
409
334
|
const result = await feishuDocTool.execute("tool-call", {
|
|
410
335
|
action: "create",
|
|
@@ -417,29 +342,10 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
417
342
|
});
|
|
418
343
|
|
|
419
344
|
it("create never grants permissions when grant_to_requester is false", async () => {
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
feishu: {
|
|
425
|
-
appId: "app_id",
|
|
426
|
-
appSecret: "app_secret",
|
|
427
|
-
},
|
|
428
|
-
},
|
|
429
|
-
} as any,
|
|
430
|
-
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
431
|
-
registerTool,
|
|
432
|
-
} as any);
|
|
433
|
-
|
|
434
|
-
const feishuDocTool = registerTool.mock.calls
|
|
435
|
-
.map((call) => call[0])
|
|
436
|
-
.map((tool) =>
|
|
437
|
-
typeof tool === "function"
|
|
438
|
-
? tool({ messageChannel: "feishu", requesterSenderId: "ou_123" })
|
|
439
|
-
: tool,
|
|
440
|
-
)
|
|
441
|
-
.find((tool) => tool.name === "feishu_doc");
|
|
442
|
-
expect(feishuDocTool).toBeDefined();
|
|
345
|
+
const feishuDocTool = resolveFeishuDocTool({
|
|
346
|
+
messageChannel: "feishu",
|
|
347
|
+
requesterSenderId: "ou_123",
|
|
348
|
+
});
|
|
443
349
|
|
|
444
350
|
const result = await feishuDocTool.execute("tool-call", {
|
|
445
351
|
action: "create",
|
|
@@ -457,25 +363,7 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
457
363
|
data: { document: { title: "Created Doc" } },
|
|
458
364
|
});
|
|
459
365
|
|
|
460
|
-
const
|
|
461
|
-
registerFeishuDocTools({
|
|
462
|
-
config: {
|
|
463
|
-
channels: {
|
|
464
|
-
feishu: {
|
|
465
|
-
appId: "app_id",
|
|
466
|
-
appSecret: "app_secret",
|
|
467
|
-
},
|
|
468
|
-
},
|
|
469
|
-
} as any,
|
|
470
|
-
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
471
|
-
registerTool,
|
|
472
|
-
} as any);
|
|
473
|
-
|
|
474
|
-
const feishuDocTool = registerTool.mock.calls
|
|
475
|
-
.map((call) => call[0])
|
|
476
|
-
.map((tool) => (typeof tool === "function" ? tool({}) : tool))
|
|
477
|
-
.find((tool) => tool.name === "feishu_doc");
|
|
478
|
-
expect(feishuDocTool).toBeDefined();
|
|
366
|
+
const feishuDocTool = resolveFeishuDocTool();
|
|
479
367
|
|
|
480
368
|
const result = await feishuDocTool.execute("tool-call", {
|
|
481
369
|
action: "create",
|
|
@@ -496,25 +384,7 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
496
384
|
const localPath = join(tmpdir(), `feishu-docx-upload-${Date.now()}.txt`);
|
|
497
385
|
await fs.writeFile(localPath, "hello from local file", "utf8");
|
|
498
386
|
|
|
499
|
-
const
|
|
500
|
-
registerFeishuDocTools({
|
|
501
|
-
config: {
|
|
502
|
-
channels: {
|
|
503
|
-
feishu: {
|
|
504
|
-
appId: "app_id",
|
|
505
|
-
appSecret: "app_secret",
|
|
506
|
-
},
|
|
507
|
-
},
|
|
508
|
-
} as any,
|
|
509
|
-
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
510
|
-
registerTool,
|
|
511
|
-
} as any);
|
|
512
|
-
|
|
513
|
-
const feishuDocTool = registerTool.mock.calls
|
|
514
|
-
.map((call) => call[0])
|
|
515
|
-
.map((tool) => (typeof tool === "function" ? tool({}) : tool))
|
|
516
|
-
.find((tool) => tool.name === "feishu_doc");
|
|
517
|
-
expect(feishuDocTool).toBeDefined();
|
|
387
|
+
const feishuDocTool = resolveFeishuDocTool();
|
|
518
388
|
|
|
519
389
|
const result = await feishuDocTool.execute("tool-call", {
|
|
520
390
|
action: "upload_file",
|
|
@@ -557,25 +427,7 @@ describe("feishu_doc image fetch hardening", () => {
|
|
|
557
427
|
await fs.writeFile(localPath, "hello from local file", "utf8");
|
|
558
428
|
|
|
559
429
|
try {
|
|
560
|
-
const
|
|
561
|
-
registerFeishuDocTools({
|
|
562
|
-
config: {
|
|
563
|
-
channels: {
|
|
564
|
-
feishu: {
|
|
565
|
-
appId: "app_id",
|
|
566
|
-
appSecret: "app_secret",
|
|
567
|
-
},
|
|
568
|
-
},
|
|
569
|
-
} as any,
|
|
570
|
-
logger: { debug: vi.fn(), info: vi.fn() } as any,
|
|
571
|
-
registerTool,
|
|
572
|
-
} as any);
|
|
573
|
-
|
|
574
|
-
const feishuDocTool = registerTool.mock.calls
|
|
575
|
-
.map((call) => call[0])
|
|
576
|
-
.map((tool) => (typeof tool === "function" ? tool({}) : tool))
|
|
577
|
-
.find((tool) => tool.name === "feishu_doc");
|
|
578
|
-
expect(feishuDocTool).toBeDefined();
|
|
430
|
+
const feishuDocTool = resolveFeishuDocTool();
|
|
579
431
|
|
|
580
432
|
const result = await feishuDocTool.execute("tool-call", {
|
|
581
433
|
action: "upload_file",
|
package/src/docx.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { isAbsolute } from "node:path";
|
|
|
4
4
|
import { basename } from "node:path";
|
|
5
5
|
import type * as Lark from "@larksuiteoapi/node-sdk";
|
|
6
6
|
import { Type } from "@sinclair/typebox";
|
|
7
|
-
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
7
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/feishu";
|
|
8
8
|
import { listEnabledFeishuAccounts } from "./accounts.js";
|
|
9
9
|
import { FeishuDocSchema, type FeishuDocParams } from "./doc-schema.js";
|
|
10
10
|
import { BATCH_SIZE, insertBlocksInBatches } from "./docx-batch-insert.js";
|
package/src/drive.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import type * as Lark from "@larksuiteoapi/node-sdk";
|
|
2
|
-
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/feishu";
|
|
3
3
|
import { listEnabledFeishuAccounts } from "./accounts.js";
|
|
4
4
|
import { FeishuDriveSchema, type FeishuDriveParams } from "./drive-schema.js";
|
|
5
5
|
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
|
|
12
|
-
details: data,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
6
|
+
import {
|
|
7
|
+
jsonToolResult,
|
|
8
|
+
toolExecutionErrorResult,
|
|
9
|
+
unknownToolActionResult,
|
|
10
|
+
} from "./tool-result.js";
|
|
15
11
|
|
|
16
12
|
// ============ Actions ============
|
|
17
13
|
|
|
@@ -206,21 +202,21 @@ export function registerFeishuDriveTools(api: OpenClawPluginApi) {
|
|
|
206
202
|
});
|
|
207
203
|
switch (p.action) {
|
|
208
204
|
case "list":
|
|
209
|
-
return
|
|
205
|
+
return jsonToolResult(await listFolder(client, p.folder_token));
|
|
210
206
|
case "info":
|
|
211
|
-
return
|
|
207
|
+
return jsonToolResult(await getFileInfo(client, p.file_token));
|
|
212
208
|
case "create_folder":
|
|
213
|
-
return
|
|
209
|
+
return jsonToolResult(await createFolder(client, p.name, p.folder_token));
|
|
214
210
|
case "move":
|
|
215
|
-
return
|
|
211
|
+
return jsonToolResult(await moveFile(client, p.file_token, p.type, p.folder_token));
|
|
216
212
|
case "delete":
|
|
217
|
-
return
|
|
213
|
+
return jsonToolResult(await deleteFile(client, p.file_token, p.type));
|
|
218
214
|
default:
|
|
219
215
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- exhaustive check fallback
|
|
220
|
-
return
|
|
216
|
+
return unknownToolActionResult((p as { action?: unknown }).action);
|
|
221
217
|
}
|
|
222
218
|
} catch (err) {
|
|
223
|
-
return
|
|
219
|
+
return toolExecutionErrorResult(err);
|
|
224
220
|
}
|
|
225
221
|
},
|
|
226
222
|
};
|
package/src/dynamic-agent.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk";
|
|
4
|
+
import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk/feishu";
|
|
5
5
|
import type { DynamicAgentCreationConfig } from "./types.js";
|
|
6
6
|
|
|
7
7
|
export type MaybeCreateDynamicAgentResult = {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const DEFAULT_RESET_TRIGGERS = ["/new", "/reset"] as const;
|
|
2
|
+
|
|
3
|
+
type FeishuBeforeResetContext = {
|
|
4
|
+
cfg: Record<string, unknown>;
|
|
5
|
+
sessionEntry: Record<string, unknown>;
|
|
6
|
+
previousSessionEntry?: Record<string, unknown>;
|
|
7
|
+
commandSource: string;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type FeishuBeforeResetEvent = {
|
|
12
|
+
type: "command";
|
|
13
|
+
action: "new" | "reset";
|
|
14
|
+
context: FeishuBeforeResetContext;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type FeishuBeforeResetRunner = {
|
|
18
|
+
runBeforeReset: (
|
|
19
|
+
event: FeishuBeforeResetEvent,
|
|
20
|
+
ctx: { agentId: string; sessionKey: string },
|
|
21
|
+
) => Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Handle Feishu command messages and trigger reset hooks.
|
|
26
|
+
*/
|
|
27
|
+
export async function handleFeishuCommand(
|
|
28
|
+
messageText: string,
|
|
29
|
+
sessionKey: string,
|
|
30
|
+
hookRunner: FeishuBeforeResetRunner,
|
|
31
|
+
context: FeishuBeforeResetContext,
|
|
32
|
+
): Promise<boolean> {
|
|
33
|
+
const trimmed = messageText.trim().toLowerCase();
|
|
34
|
+
const isResetCommand = DEFAULT_RESET_TRIGGERS.some(
|
|
35
|
+
(trigger) => trimmed === trigger || trimmed.startsWith(`${trigger} `),
|
|
36
|
+
);
|
|
37
|
+
if (!isResetCommand) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const command = trimmed.split(" ")[0];
|
|
42
|
+
const action: "new" | "reset" = command === "/new" ? "new" : "reset";
|
|
43
|
+
await hookRunner.runBeforeReset(
|
|
44
|
+
{
|
|
45
|
+
type: "command",
|
|
46
|
+
action,
|
|
47
|
+
context: {
|
|
48
|
+
...context,
|
|
49
|
+
commandSource: "feishu",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
agentId: "main",
|
|
54
|
+
sessionKey,
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return true;
|
|
59
|
+
}
|