@coze-arch/cli 0.0.15-alpha.a0f5b9 → 0.0.15-alpha.dfd4c4

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.
Files changed (103) hide show
  1. package/lib/__templates__/expo/.coze +1 -0
  2. package/lib/__templates__/expo/.cozeproj/scripts/validate.sh +8 -0
  3. package/lib/__templates__/expo/package.json +2 -1
  4. package/lib/__templates__/nextjs/.coze +1 -0
  5. package/lib/__templates__/nextjs/package.json +3 -1
  6. package/lib/__templates__/nextjs/scripts/validate.sh +10 -0
  7. package/lib/__templates__/nuxt-vue/.coze +1 -0
  8. package/lib/__templates__/nuxt-vue/eslint.config.mjs +25 -0
  9. package/lib/__templates__/nuxt-vue/package.json +9 -2
  10. package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +790 -10
  11. package/lib/__templates__/nuxt-vue/scripts/validate.sh +10 -0
  12. package/lib/__templates__/taro/.coze +1 -0
  13. package/lib/__templates__/taro/.cozeproj/scripts/validate.sh +8 -0
  14. package/lib/__templates__/taro/package.json +1 -1
  15. package/lib/__templates__/templates.json +0 -24
  16. package/lib/__templates__/vite/.coze +1 -0
  17. package/lib/__templates__/vite/package.json +3 -1
  18. package/lib/__templates__/vite/scripts/validate.sh +10 -0
  19. package/lib/cli.js +330 -97
  20. package/package.json +1 -1
  21. package/lib/__templates__/pi-agent/.coze +0 -10
  22. package/lib/__templates__/pi-agent/AGENTS.md +0 -140
  23. package/lib/__templates__/pi-agent/README.md +0 -172
  24. package/lib/__templates__/pi-agent/_gitignore +0 -3
  25. package/lib/__templates__/pi-agent/_npmrc +0 -23
  26. package/lib/__templates__/pi-agent/docs/project-overview.md +0 -356
  27. package/lib/__templates__/pi-agent/docs/user/getting-started.md +0 -47
  28. package/lib/__templates__/pi-agent/package.json +0 -60
  29. package/lib/__templates__/pi-agent/pi-resources/SYSTEM.md +0 -15
  30. package/lib/__templates__/pi-agent/pi-resources/extensions/preference-memory/index.ts +0 -355
  31. package/lib/__templates__/pi-agent/pi-resources/extensions/test-ping.ts +0 -19
  32. package/lib/__templates__/pi-agent/pi-resources/prompts/test-prompt.md +0 -11
  33. package/lib/__templates__/pi-agent/pi-resources/skills/coze-asr/SKILL.md +0 -36
  34. package/lib/__templates__/pi-agent/pi-resources/skills/coze-asr/scripts/asr.mjs +0 -9
  35. package/lib/__templates__/pi-agent/pi-resources/skills/coze-image-gen/SKILL.md +0 -41
  36. package/lib/__templates__/pi-agent/pi-resources/skills/coze-image-gen/scripts/gen.mjs +0 -9
  37. package/lib/__templates__/pi-agent/pi-resources/skills/coze-tts/SKILL.md +0 -85
  38. package/lib/__templates__/pi-agent/pi-resources/skills/coze-tts/scripts/tts.mjs +0 -9
  39. package/lib/__templates__/pi-agent/pi-resources/skills/coze-video-gen/SKILL.md +0 -53
  40. package/lib/__templates__/pi-agent/pi-resources/skills/coze-video-gen/scripts/gen.mjs +0 -9
  41. package/lib/__templates__/pi-agent/pnpm-lock.yaml +0 -8285
  42. package/lib/__templates__/pi-agent/scripts/dev.sh +0 -14
  43. package/lib/__templates__/pi-agent/scripts/prepare.sh +0 -2
  44. package/lib/__templates__/pi-agent/src/agent.ts +0 -363
  45. package/lib/__templates__/pi-agent/src/channels/feishu/index.ts +0 -760
  46. package/lib/__templates__/pi-agent/src/channels/feishu/streaming-card.ts +0 -297
  47. package/lib/__templates__/pi-agent/src/channels/wechat/index.ts +0 -171
  48. package/lib/__templates__/pi-agent/src/config.ts +0 -596
  49. package/lib/__templates__/pi-agent/src/core.ts +0 -218
  50. package/lib/__templates__/pi-agent/src/dashboard/api/channels.ts +0 -148
  51. package/lib/__templates__/pi-agent/src/dashboard/api/docs.ts +0 -204
  52. package/lib/__templates__/pi-agent/src/dashboard/api/models.ts +0 -141
  53. package/lib/__templates__/pi-agent/src/dashboard/api/overview.ts +0 -33
  54. package/lib/__templates__/pi-agent/src/dashboard/config-store.ts +0 -64
  55. package/lib/__templates__/pi-agent/src/dashboard/index.ts +0 -39
  56. package/lib/__templates__/pi-agent/src/dashboard/server.ts +0 -622
  57. package/lib/__templates__/pi-agent/src/dashboard/types.ts +0 -25
  58. package/lib/__templates__/pi-agent/src/dashboard/web/index.html +0 -13
  59. package/lib/__templates__/pi-agent/src/dashboard/web/postcss.config.cjs +0 -7
  60. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/app-layout.tsx +0 -186
  61. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/page-title.tsx +0 -17
  62. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/alert.tsx +0 -22
  63. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/badge.tsx +0 -25
  64. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/button.tsx +0 -40
  65. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/card.tsx +0 -29
  66. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/input.tsx +0 -18
  67. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/label.tsx +0 -8
  68. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/select.tsx +0 -80
  69. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/separator.tsx +0 -23
  70. package/lib/__templates__/pi-agent/src/dashboard/web/src/hooks/use-fetch.ts +0 -32
  71. package/lib/__templates__/pi-agent/src/dashboard/web/src/hooks/use-local-storage-state.ts +0 -23
  72. package/lib/__templates__/pi-agent/src/dashboard/web/src/main.tsx +0 -30
  73. package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/channels-page.tsx +0 -188
  74. package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/chat-page.tsx +0 -451
  75. package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/docs-page.tsx +0 -65
  76. package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/models-page.tsx +0 -122
  77. package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/overview-page.tsx +0 -134
  78. package/lib/__templates__/pi-agent/src/dashboard/web/src/services/chat-ws-service.ts +0 -167
  79. package/lib/__templates__/pi-agent/src/dashboard/web/src/styles.css +0 -294
  80. package/lib/__templates__/pi-agent/src/dashboard/web/src/utils/index.ts +0 -11
  81. package/lib/__templates__/pi-agent/src/dashboard/web/tsconfig.json +0 -13
  82. package/lib/__templates__/pi-agent/src/dashboard/web/vite.config.ts +0 -17
  83. package/lib/__templates__/pi-agent/src/index.ts +0 -123
  84. package/lib/__templates__/pi-agent/src/pi-resources.ts +0 -125
  85. package/lib/__templates__/pi-agent/src/session-store.ts +0 -223
  86. package/lib/__templates__/pi-agent/src/tools/common/format-coze-error.ts +0 -12
  87. package/lib/__templates__/pi-agent/src/tools/index.ts +0 -2
  88. package/lib/__templates__/pi-agent/src/tools/web-fetch/index.ts +0 -195
  89. package/lib/__templates__/pi-agent/src/tools/web-search/index.ts +0 -206
  90. package/lib/__templates__/pi-agent/template.config.js +0 -45
  91. package/lib/__templates__/pi-agent/tests/config.test.ts +0 -315
  92. package/lib/__templates__/pi-agent/tests/dashboard-docs-api.test.ts +0 -125
  93. package/lib/__templates__/pi-agent/tests/dashboard-models-api.test.ts +0 -171
  94. package/lib/__templates__/pi-agent/tests/feishu-channel.test.ts +0 -149
  95. package/lib/__templates__/pi-agent/tests/feishu-streaming-card.test.ts +0 -15
  96. package/lib/__templates__/pi-agent/tests/pi-resources.test.ts +0 -73
  97. package/lib/__templates__/pi-agent/tests/preference-memory.test.ts +0 -43
  98. package/lib/__templates__/pi-agent/tests/session-store.test.ts +0 -61
  99. package/lib/__templates__/pi-agent/tests/smoke/run-smoke.ts +0 -275
  100. package/lib/__templates__/pi-agent/tests/web-fetch.test.ts +0 -157
  101. package/lib/__templates__/pi-agent/tests/web-search.test.ts +0 -208
  102. package/lib/__templates__/pi-agent/tsconfig.json +0 -21
  103. package/lib/__templates__/pi-agent/types/larksuiteoapi-node-sdk.d.ts +0 -113
@@ -1,297 +0,0 @@
1
- import type { Client } from "@larksuiteoapi/node-sdk";
2
-
3
- type FeishuDomain = string | undefined;
4
-
5
- type Credentials = {
6
- appId: string;
7
- appSecret: string;
8
- domain?: FeishuDomain;
9
- };
10
-
11
- type CardState = {
12
- cardId: string;
13
- messageId: string;
14
- sequence: number;
15
- currentText: string;
16
- };
17
-
18
- type StreamingStartOptions = {
19
- replyToMessageId: string;
20
- replyInThread?: boolean;
21
- };
22
-
23
- const tokenCache = new Map<string, { token: string; expiresAt: number }>();
24
-
25
- function resolveApiBase(domain?: FeishuDomain): string {
26
- if (domain === "lark") {
27
- return "https://open.larksuite.com/open-apis";
28
- }
29
- if (domain && domain !== "feishu" && domain.startsWith("http")) {
30
- return `${domain.replace(/\/+$/, "")}/open-apis`;
31
- }
32
- return "https://open.feishu.cn/open-apis";
33
- }
34
-
35
- async function getToken(creds: Credentials): Promise<string> {
36
- const key = `${creds.domain ?? "feishu"}|${creds.appId}`;
37
- const cached = tokenCache.get(key);
38
- if (cached && cached.expiresAt > Date.now() + 60_000) {
39
- return cached.token;
40
- }
41
-
42
- const response = await fetch(`${resolveApiBase(creds.domain)}/auth/v3/tenant_access_token/internal`, {
43
- method: "POST",
44
- headers: { "Content-Type": "application/json" },
45
- body: JSON.stringify({ app_id: creds.appId, app_secret: creds.appSecret }),
46
- });
47
- if (!response.ok) {
48
- throw new Error(`Token request failed with HTTP ${response.status}`);
49
- }
50
-
51
- const data = (await response.json()) as {
52
- code: number;
53
- msg: string;
54
- tenant_access_token?: string;
55
- expire?: number;
56
- };
57
- if (data.code !== 0 || !data.tenant_access_token) {
58
- throw new Error(`Token error: ${data.msg}`);
59
- }
60
-
61
- tokenCache.set(key, {
62
- token: data.tenant_access_token,
63
- expiresAt: Date.now() + (data.expire ?? 7200) * 1000,
64
- });
65
- return data.tenant_access_token;
66
- }
67
-
68
- async function readResponseBodySafe(response: Response): Promise<string> {
69
- try {
70
- const text = await response.text();
71
- return text.trim();
72
- } catch {
73
- return "";
74
- }
75
- }
76
-
77
- function truncateSummary(text: string, max = 50): string {
78
- const clean = text.replace(/\n/g, " ").trim();
79
- return clean.length <= max ? clean : `${clean.slice(0, max - 3)}...`;
80
- }
81
-
82
- export function mergeStreamingText(previousText: string | undefined, nextText: string | undefined): string {
83
- const previous = typeof previousText === "string" ? previousText : "";
84
- const next = typeof nextText === "string" ? nextText : "";
85
- if (!next) return previous;
86
- if (!previous || next === previous) return next;
87
- if (next.startsWith(previous)) return next;
88
- if (previous.startsWith(next)) return previous;
89
- if (next.includes(previous)) return next;
90
- if (previous.includes(next)) return previous;
91
-
92
- const maxOverlap = Math.min(previous.length, next.length);
93
- for (let overlap = maxOverlap; overlap > 0; overlap -= 1) {
94
- if (previous.slice(-overlap) === next.slice(0, overlap)) {
95
- return `${previous}${next.slice(overlap)}`;
96
- }
97
- }
98
- return `${previous}${next}`;
99
- }
100
-
101
- export class FeishuStreamingCardSession {
102
- private state: CardState | null = null;
103
- private queue: Promise<void> = Promise.resolve();
104
- private closed = false;
105
- private pendingText: string | null = null;
106
- private flushTimer: ReturnType<typeof setTimeout> | null = null;
107
- private lastUpdateTime = 0;
108
- private readonly updateThrottleMs = 100;
109
-
110
- constructor(
111
- private readonly client: Client,
112
- private readonly creds: Credentials,
113
- private readonly log?: (message: string, fields?: Record<string, unknown>) => void,
114
- ) {}
115
-
116
- async start(
117
- _receiveId: string,
118
- _receiveIdType: "open_id" | "user_id" | "union_id" | "email" | "chat_id" = "chat_id",
119
- options?: StreamingStartOptions,
120
- ): Promise<void> {
121
- if (this.state) return;
122
- if (!options?.replyToMessageId) {
123
- throw new Error("replyToMessageId is required for feishu streaming card replies");
124
- }
125
-
126
- const cardJson = {
127
- schema: "2.0",
128
- config: {
129
- streaming_mode: true,
130
- summary: { content: "[Generating...]" },
131
- streaming_config: { print_frequency_ms: { default: 50 }, print_step: { default: 1 } },
132
- },
133
- body: {
134
- elements: [{ tag: "markdown", content: "⏳ Thinking...", element_id: "content" }],
135
- },
136
- };
137
-
138
- const token = await getToken(this.creds);
139
- const createRes = await fetch(`${resolveApiBase(this.creds.domain)}/cardkit/v1/cards`, {
140
- method: "POST",
141
- headers: {
142
- Authorization: `Bearer ${token}`,
143
- "Content-Type": "application/json",
144
- },
145
- body: JSON.stringify({ type: "card_json", data: JSON.stringify(cardJson) }),
146
- });
147
- if (!createRes.ok) {
148
- const body = await readResponseBodySafe(createRes);
149
- throw new Error(
150
- `Create card request failed with HTTP ${createRes.status}${body ? `: ${body}` : ""}`,
151
- );
152
- }
153
-
154
- const createData = (await createRes.json()) as {
155
- code: number;
156
- msg: string;
157
- data?: { card_id: string };
158
- };
159
- if (createData.code !== 0 || !createData.data?.card_id) {
160
- throw new Error(`Create card failed (code=${createData.code}): ${createData.msg}`);
161
- }
162
-
163
- const cardId = createData.data.card_id;
164
- const cardContent = JSON.stringify({ type: "card", data: { card_id: cardId } });
165
- const sendRes = (await this.client.im.message.reply({
166
- path: { message_id: options.replyToMessageId },
167
- data: {
168
- msg_type: "interactive",
169
- content: cardContent,
170
- ...(options.replyInThread ? { reply_in_thread: true } : {}),
171
- },
172
- })) as {
173
- code?: number;
174
- msg?: string;
175
- data?: { message_id?: string };
176
- };
177
-
178
- if (sendRes.code !== 0 || !sendRes.data?.message_id) {
179
- throw new Error(`Send card failed: ${sendRes.msg}`);
180
- }
181
- this.log?.("stream start", { cardId, messageId: sendRes.data.message_id });
182
-
183
- this.state = {
184
- cardId,
185
- messageId: sendRes.data.message_id,
186
- sequence: 1,
187
- currentText: "",
188
- };
189
- }
190
-
191
- private async updateCardContent(text: string): Promise<void> {
192
- if (!this.state) return;
193
- this.state.sequence += 1;
194
- const token = await getToken(this.creds);
195
- const response = await fetch(
196
- `${resolveApiBase(this.creds.domain)}/cardkit/v1/cards/${this.state.cardId}/elements/content/content`,
197
- {
198
- method: "PUT",
199
- headers: {
200
- Authorization: `Bearer ${token}`,
201
- "Content-Type": "application/json",
202
- },
203
- body: JSON.stringify({
204
- content: text,
205
- sequence: this.state.sequence,
206
- uuid: `s_${this.state.cardId}_${this.state.sequence}`,
207
- }),
208
- },
209
- );
210
- if (!response.ok) {
211
- const body = await readResponseBodySafe(response);
212
- throw new Error(
213
- `Update card request failed with HTTP ${response.status}${body ? `: ${body}` : ""}`,
214
- );
215
- }
216
- }
217
-
218
- async update(text: string): Promise<void> {
219
- if (!this.state || this.closed) return;
220
- const mergedInput = mergeStreamingText(this.pendingText ?? this.state.currentText, text);
221
- if (!mergedInput || mergedInput === this.state.currentText) return;
222
-
223
- const now = Date.now();
224
- if (now - this.lastUpdateTime < this.updateThrottleMs) {
225
- this.pendingText = mergedInput;
226
- if (!this.flushTimer) {
227
- this.flushTimer = setTimeout(() => {
228
- this.flushTimer = null;
229
- const pending = this.pendingText;
230
- this.pendingText = null;
231
- if (pending) {
232
- void this.update(pending).catch((error) => this.log?.("stream update failed", { error: String(error) }));
233
- }
234
- }, this.updateThrottleMs);
235
- }
236
- return;
237
- }
238
-
239
- this.pendingText = null;
240
- this.lastUpdateTime = now;
241
- this.queue = this.queue.then(async () => {
242
- if (!this.state || this.closed) return;
243
- const mergedText = mergeStreamingText(this.state.currentText, mergedInput);
244
- if (!mergedText || mergedText === this.state.currentText) return;
245
- this.state.currentText = mergedText;
246
- this.log?.("stream update", { text: mergedText });
247
- await this.updateCardContent(mergedText);
248
- });
249
- await this.queue;
250
- }
251
-
252
- async close(finalText?: string): Promise<void> {
253
- if (!this.state || this.closed) return;
254
- this.closed = true;
255
- if (this.flushTimer) {
256
- clearTimeout(this.flushTimer);
257
- this.flushTimer = null;
258
- }
259
- await this.queue;
260
-
261
- const text = finalText ? mergeStreamingText(this.state.currentText, finalText) : this.state.currentText;
262
- if (text && text !== this.state.currentText) {
263
- await this.updateCardContent(text);
264
- this.state.currentText = text;
265
- }
266
-
267
- this.state.sequence += 1;
268
- const token = await getToken(this.creds);
269
- const response = await fetch(`${resolveApiBase(this.creds.domain)}/cardkit/v1/cards/${this.state.cardId}/settings`, {
270
- method: "PATCH",
271
- headers: {
272
- Authorization: `Bearer ${token}`,
273
- "Content-Type": "application/json; charset=utf-8",
274
- },
275
- body: JSON.stringify({
276
- settings: JSON.stringify({
277
- config: { streaming_mode: false, summary: { content: truncateSummary(this.state.currentText) } },
278
- }),
279
- sequence: this.state.sequence,
280
- uuid: `c_${this.state.cardId}_${this.state.sequence}`,
281
- }),
282
- });
283
- if (!response.ok) {
284
- const body = await readResponseBodySafe(response);
285
- throw new Error(
286
- `Close card request failed with HTTP ${response.status}${body ? `: ${body}` : ""}`,
287
- );
288
- }
289
-
290
- this.state = null;
291
- this.pendingText = null;
292
- }
293
-
294
- isActive(): boolean {
295
- return this.state !== null && !this.closed;
296
- }
297
- }
@@ -1,171 +0,0 @@
1
- import {
2
- type BotMessage,
3
- type BotReply,
4
- type ChannelHandler,
5
- type ChannelInstance,
6
- type ChannelTransport,
7
- createBotMessage,
8
- normalizeReply,
9
- shouldHandleGroupMessage
10
- } from "../../core.js";
11
-
12
- export interface WechatIncomingEvent {
13
- message?: WechatIncomingEvent;
14
- messageId?: string;
15
- fromUser?: string;
16
- roomId?: string;
17
- conversationId?: string;
18
- senderId?: string;
19
- text?: string;
20
- mentions?: string[];
21
- threadId?: string;
22
- }
23
-
24
- export interface WechatOutgoingMessage extends BotReply {
25
- channel: "wechat";
26
- conversationId: string;
27
- replyToMessageId: string;
28
- }
29
-
30
- export interface WechatChannelConfig {
31
- routing?: {
32
- groupRequireMention?: boolean;
33
- };
34
- transport?: ChannelTransport<WechatOutgoingMessage>;
35
- }
36
-
37
- export interface WechatHandleResult {
38
- handled: boolean;
39
- reason?: "ignored" | "filtered";
40
- message?: BotMessage;
41
- reply?: WechatOutgoingMessage | null;
42
- }
43
-
44
- export interface WechatChannel extends ChannelInstance {
45
- name: "wechat";
46
- isStarted(): boolean;
47
- getSentMessages(): WechatOutgoingMessage[];
48
- handleEvent(event: WechatIncomingEvent): Promise<WechatHandleResult>;
49
- simulateIncomingText(input: {
50
- text: string;
51
- senderId?: string;
52
- conversationId?: string;
53
- isDirectMessage?: boolean;
54
- mentions?: string[];
55
- }): Promise<WechatHandleResult>;
56
- }
57
-
58
- function unwrapSource(event: WechatIncomingEvent): WechatIncomingEvent {
59
- return event.message ?? event;
60
- }
61
-
62
- export function normalizeWechatEvent(event: WechatIncomingEvent): BotMessage | null {
63
- const source = unwrapSource(event);
64
- const roomId = source.roomId ?? source.conversationId;
65
- const senderId = source.fromUser ?? source.senderId;
66
- const text = source.text;
67
-
68
- if (!senderId || typeof text !== "string") {
69
- return null;
70
- }
71
-
72
- return createBotMessage({
73
- channel: "wechat",
74
- conversationId: roomId ?? senderId,
75
- senderId,
76
- messageId: source.messageId ?? `wechat-${Date.now()}`,
77
- text,
78
- isDirectMessage: !roomId,
79
- mentions: source.mentions ?? [],
80
- threadId: source.threadId,
81
- raw: event
82
- });
83
- }
84
-
85
- function createOutgoingMessage(message: BotMessage, reply: BotReply): WechatOutgoingMessage {
86
- return {
87
- channel: "wechat",
88
- conversationId: message.conversationId,
89
- replyToMessageId: message.messageId,
90
- text: reply.text
91
- };
92
- }
93
-
94
- export function createWechatChannel(
95
- config: WechatChannelConfig = {},
96
- handler: ChannelHandler = {}
97
- ): WechatChannel {
98
- const sentMessages: WechatOutgoingMessage[] = [];
99
- let started = false;
100
-
101
- async function sendReply(
102
- message: BotMessage,
103
- reply: string | BotReply | null | void
104
- ): Promise<WechatOutgoingMessage | null> {
105
- const normalizedReply = normalizeReply(reply);
106
- if (!normalizedReply) return null;
107
-
108
- const outgoingMessage = createOutgoingMessage(message, normalizedReply);
109
- sentMessages.push(outgoingMessage);
110
-
111
- await config.transport?.send?.(outgoingMessage);
112
- return outgoingMessage;
113
- }
114
-
115
- return {
116
- name: "wechat",
117
- async start() {
118
- started = true;
119
- await config.transport?.start?.();
120
- },
121
- async stop() {
122
- started = false;
123
- await config.transport?.stop?.();
124
- },
125
- isStarted() {
126
- return started;
127
- },
128
- getSentMessages() {
129
- return [...sentMessages];
130
- },
131
- async handleEvent(event) {
132
- const message = normalizeWechatEvent(event);
133
- if (!message) {
134
- return { handled: false, reason: "ignored" };
135
- }
136
-
137
- const shouldHandle = shouldHandleGroupMessage(message, {
138
- requireMention: config.routing?.groupRequireMention ?? false
139
- });
140
-
141
- if (!shouldHandle) {
142
- return { handled: false, reason: "filtered", message };
143
- }
144
-
145
- const reply = await handler.onMessage?.(message);
146
- const outgoingMessage = await sendReply(message, reply);
147
-
148
- return {
149
- handled: true,
150
- message,
151
- reply: outgoingMessage
152
- };
153
- },
154
- async simulateIncomingText({
155
- text,
156
- senderId = "wechat-user",
157
- conversationId = "wechat-chat",
158
- isDirectMessage = true,
159
- mentions = []
160
- }) {
161
- return this.handleEvent({
162
- messageId: `wechat-${Date.now()}`,
163
- fromUser: senderId,
164
- roomId: isDirectMessage ? undefined : conversationId,
165
- conversationId,
166
- text,
167
- mentions
168
- });
169
- }
170
- };
171
- }