@ascegu/teamily 1.0.12 → 1.0.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ascegu/teamily",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "OpenClaw Teamily channel plugin - Team instant messaging server integration",
5
5
  "keywords": [
6
6
  "channel",
package/src/channel.ts CHANGED
@@ -26,7 +26,7 @@ import { normalizeTeamilyTarget, normalizeTeamilyAllowEntry } from "./normalize.
26
26
  import { probeTeamily } from "./probe.js";
27
27
  import { getTeamilyRuntime } from "./runtime.js";
28
28
  import type { ResolvedTeamilyAccount } from "./types.js";
29
- import { SESSION_TYPES } from "./types.js";
29
+ import { isGroupSession } from "./types.js";
30
30
 
31
31
  const meta = {
32
32
  id: "teamily",
@@ -243,8 +243,18 @@ export const teamilyPlugin: ChannelPlugin<ResolvedTeamilyAccount> = {
243
243
  const rt = getTeamilyRuntime();
244
244
  const currentCfg = rt.config.loadConfig();
245
245
 
246
- const isGroup = message.sessionType === SESSION_TYPES.GROUP;
246
+ const isGroup = isGroupSession(message.sessionType);
247
247
  const from = message.sendID;
248
+
249
+ log?.info?.(
250
+ `[${accountId}] Incoming message: sessionType=${message.sessionType}, isGroup=${isGroup}, ` +
251
+ `from=${from}, recvID=${message.recvID}, isAtSelf=${message.isAtSelf ?? false}`,
252
+ );
253
+
254
+ // In group chats, all messages are dispatched to the agent for context,
255
+ // but only @-mentioned messages trigger a reply.
256
+ const shouldReply = !isGroup || !!message.isAtSelf;
257
+
248
258
  const text = message.content?.text || "";
249
259
  const sessionKey = isGroup ? `teamily:group:${message.recvID}` : `teamily:${from}`;
250
260
 
@@ -296,11 +306,13 @@ export const teamilyPlugin: ChannelPlugin<ResolvedTeamilyAccount> = {
296
306
  cfg: currentCfg,
297
307
  dispatcherOptions: {
298
308
  deliver: async (payload: { text?: string; body?: string }) => {
309
+ if (!shouldReply) return;
299
310
  const replyText = payload?.text ?? payload?.body;
300
311
  if (replyText) {
301
312
  const monitor = getTeamilyMonitor(accountId);
302
313
  if (!monitor) throw new Error(`Teamily monitor not running for account ${accountId}`);
303
314
  const replyTo = isGroup ? `group:${message.recvID}` : from;
315
+ log?.info?.(`[${accountId}] Sending reply to: ${replyTo} (isGroup=${isGroup})`);
304
316
  const target = normalizeTeamilyTarget(replyTo);
305
317
  await monitor.sendText(target, replyText);
306
318
  }
package/src/monitor.ts CHANGED
@@ -6,7 +6,7 @@ import type {
6
6
  TeamilyVideoContent,
7
7
  TeamilyAudioContent,
8
8
  } from "./types.js";
9
- import { CONTENT_TYPES, SESSION_TYPES } from "./types.js";
9
+ import { CONTENT_TYPES, SESSION_TYPES, isGroupSession } from "./types.js";
10
10
 
11
11
  export type TeamilyMessageHandler = (message: TeamilyMessage) => Promise<void> | void;
12
12
  export type TeamilyConnectionState = "connecting" | "connected" | "disconnected" | "error";
@@ -232,14 +232,21 @@ function convertSdkMessage(msg: MessageItem, selfUserID: string): TeamilyMessage
232
232
  return null;
233
233
  }
234
234
 
235
+ // Determine whether this message @-mentions the bot
236
+ const isAtSelf =
237
+ contentType === CONTENT_TYPES.AT_TEXT &&
238
+ (msg.atTextElem?.isAtSelf === true ||
239
+ (msg.atTextElem?.atUserList ?? []).includes(selfUserID));
240
+
235
241
  return {
236
242
  serverMsgID: msg.serverMsgID || msg.clientMsgID || `${Date.now()}_${Math.random()}`,
237
243
  sendID: msg.sendID || "unknown",
238
- recvID: sessionType === SESSION_TYPES.GROUP ? (msg.groupID || "") : (msg.recvID || selfUserID),
244
+ recvID: isGroupSession(sessionType) ? (msg.groupID || "") : (msg.recvID || selfUserID),
239
245
  content,
240
246
  contentType,
241
247
  sessionType,
242
248
  sendTime: msg.sendTime || Date.now(),
249
+ isAtSelf,
243
250
  };
244
251
  }
245
252
 
@@ -259,6 +266,10 @@ function parseSdkContent(msg: MessageItem, contentType: number): TeamilyMessage[
259
266
  return { video: msg.videoElem as unknown as TeamilyVideoContent };
260
267
  }
261
268
  return {};
269
+ case CONTENT_TYPES.AT_TEXT: {
270
+ const text = msg.atTextElem?.text ?? tryParseTextContent(msg.content);
271
+ return text ? { text } : {};
272
+ }
262
273
  case CONTENT_TYPES.VOICE:
263
274
  if (msg.soundElem?.sourceUrl) {
264
275
  return { audio: msg.soundElem as unknown as TeamilyAudioContent };
package/src/types.ts CHANGED
@@ -57,6 +57,8 @@ export interface TeamilyMessage {
57
57
  contentType: number;
58
58
  sessionType: number;
59
59
  sendTime: number;
60
+ /** True when the message is an @-mention that includes the bot's own userID. */
61
+ isAtSelf?: boolean;
60
62
  }
61
63
 
62
64
  export interface TeamilyPictureContent {
@@ -119,6 +121,12 @@ export const CONTENT_TYPES = {
119
121
  // Session type constants
120
122
  export const SESSION_TYPES = {
121
123
  SINGLE: 1,
124
+ SUPER_GROUP: 2,
122
125
  GROUP: 3,
123
126
  NOTIFICATION: 4,
124
127
  } as const;
128
+
129
+ /** Returns true when the session type represents any kind of group chat. */
130
+ export function isGroupSession(sessionType: number): boolean {
131
+ return sessionType === SESSION_TYPES.GROUP || sessionType === SESSION_TYPES.SUPER_GROUP;
132
+ }