palz-connector 1.2.6 → 1.2.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "palz-connector",
3
3
  "name": "Palz Connector Channel",
4
- "version": "1.2.6",
4
+ "version": "1.2.7",
5
5
  "description": "Palz IM 接入 OpenClaw",
6
6
  "channels": [
7
7
  "palz-connector"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "palz-connector",
3
- "version": "1.2.6",
3
+ "version": "1.2.7",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "description": "Palz IM 接入 OpenClaw — 模块化架构,基于 OpenClaw Runtime 消息管道",
@@ -2,5 +2,6 @@
2
2
  "enabled": true,
3
3
  "streamUrl": "ws://14.103.148.99:9090/ws/bot",
4
4
  "apiBaseUrl": "http://14.103.148.99:9090/api",
5
- "sessionTimeout": 1800000
5
+ "sessionTimeout": 1800000,
6
+ "groupContextCache": false
6
7
  }
@@ -2,5 +2,6 @@
2
2
  "enabled": true,
3
3
  "streamUrl": "wss://claw-server.csaiagent.com/ws/bot",
4
4
  "apiBaseUrl": "https://claw-server.csaiagent.com/api",
5
- "sessionTimeout": 1800000
5
+ "sessionTimeout": 1800000,
6
+ "groupContextCache": false
6
7
  }
@@ -2,5 +2,6 @@
2
2
  "enabled": true,
3
3
  "streamUrl": "wss://claw-server.csagentai.com/ws/bot",
4
4
  "apiBaseUrl": "https://claw-server.csagentai.com/api",
5
- "sessionTimeout": 1800000
5
+ "sessionTimeout": 1800000,
6
+ "groupContextCache": false
6
7
  }
@@ -2,5 +2,6 @@
2
2
  "enabled": true,
3
3
  "streamUrl": "wss://claw-server.csjkagent.com/ws/bot",
4
4
  "apiBaseUrl": "https://claw-server.csjkagent.com/api",
5
- "sessionTimeout": 1800000
5
+ "sessionTimeout": 1800000,
6
+ "groupContextCache": false
6
7
  }
package/src/bot.ts CHANGED
@@ -17,6 +17,18 @@ import { createPalzReplyDispatcher } from "./reply-dispatcher.js";
17
17
  import { resolvePalzMediaList } from "./media.js";
18
18
  import type { PalzMessageEvent, OpenAIContent, ContentPart, TextContentPart, PalzMediaInfo } from "./types.js";
19
19
 
20
+ // ============ group_id 解析 ============
21
+
22
+ /** 从 conversation_id 中解析 group_id,格式: user_{userID}_lobster_{lobsterID}_group_{groupID}_release_{releaseName} */
23
+ const GROUP_ID_RE = /_group_([^_]+)_release_/;
24
+
25
+ function resolveGroupId(msg: PalzMessageEvent): string | undefined {
26
+ if (msg.group_id) return msg.group_id;
27
+ if (msg.conversation_type !== "group") return undefined;
28
+ const m = GROUP_ID_RE.exec(msg.conversation_id);
29
+ return m ? m[1] : undefined;
30
+ }
31
+
20
32
  // ============ 文本提取工具 ============
21
33
 
22
34
  function extractPlainText(content: OpenAIContent): string {
@@ -194,7 +206,11 @@ export async function handlePalzMessage(params: HandlePalzMessageParams): Promis
194
206
 
195
207
  // 群聊 @提及检测
196
208
  const wasMentioned = isGroup ? (msg.mentioned_bot === true) : true;
197
- if (isGroup && !wasMentioned) {
209
+ // 群聊上下文缓存:groupContextCache=true(默认)时,未@消息仅缓存不发送;
210
+ // groupContextCache=false 时,所有群聊消息都发送给AI
211
+ const account = resolvePalzAccount({ cfg, accountId });
212
+ const groupContextCacheEnabled = account.config.groupContextCache !== false;
213
+ if (isGroup && !wasMentioned && groupContextCacheEnabled) {
198
214
  // 未@机器人:记录到群聊历史(含媒体),下次被@时作为上下文
199
215
  const historyKey = `${effectiveAgentId}:${msg.conversation_id}`;
200
216
  const senderName = msg.sender_name || msg.sender_id;
@@ -220,6 +236,9 @@ export async function handlePalzMessage(params: HandlePalzMessageParams): Promis
220
236
  log(`${tag}: [STEP 1 跳过] 原因=群聊中未@机器人, 已记录到历史 historyKey=${historyKey} mediaCount=${historyMediaList.length}`);
221
237
  return;
222
238
  }
239
+ if (isGroup && !wasMentioned && !groupContextCacheEnabled) {
240
+ log(`${tag}: [STEP 1 群聊直通] groupContextCache=false, 未@消息也将发送给AI mentioned_bot=${msg.mentioned_bot}`);
241
+ }
223
242
 
224
243
  // 去重(按 agentId + conversationId 隔离,同群多 bot 场景)
225
244
  const claimed = tryClaimMessage(msg.msg_id, effectiveAgentId, msg.conversation_id);
@@ -255,6 +274,10 @@ async function dispatchPalzMessage(params: HandlePalzMessageParams): Promise<voi
255
274
  const plainText = extractPlainText(msg.content).trim();
256
275
  const useStream = msg.stream === true;
257
276
  const senderName = msg.sender_name || msg.sender_id;
277
+ const groupId = resolveGroupId(msg);
278
+ if (isGroup) {
279
+ log(`${tag}: [group_id] resolved=${groupId ?? "(none)"} from_msg=${msg.group_id ?? "(none)"} conv=${msg.conversation_id}`);
280
+ }
258
281
 
259
282
  // 群聊:peerId = chat:conversation_id(整群共享 session,与 palzTo 格式一致)
260
283
  // DM:peerId = sender_id:conversation_id(每用户每会话独立 session)
@@ -324,10 +347,11 @@ async function dispatchPalzMessage(params: HandlePalzMessageParams): Promise<voi
324
347
 
325
348
  const chatType = isGroup ? "group" : "direct";
326
349
 
327
- // 群聊历史:将积攒的未@消息拼入 Body 上下文
328
- const historyKey = isGroup ? `${effectiveAgentId}:${msg.conversation_id}` : undefined;
350
+ // 群聊历史:将积攒的未@消息拼入 Body 上下文(仅 groupContextCache=true 时生效)
351
+ const groupContextCacheEnabled = account.config.groupContextCache !== false;
352
+ const historyKey = isGroup && groupContextCacheEnabled ? `${effectiveAgentId}:${msg.conversation_id}` : undefined;
329
353
  let combinedBody = body;
330
- if (isGroup && historyKey) {
354
+ if (isGroup && historyKey && groupContextCacheEnabled) {
331
355
  log(`${tag}: [STEP 6b 群聊历史] 开始构建, historyKey=${historyKey} bodyLen=${body.length}`);
332
356
  combinedBody = buildGroupHistoryContext({
333
357
  historyKey,
@@ -357,7 +381,7 @@ async function dispatchPalzMessage(params: HandlePalzMessageParams): Promise<voi
357
381
 
358
382
  // 构建 InboundHistory(结构化历史数据,Runtime 会注入到系统提示中)
359
383
  const inboundHistory =
360
- isGroup && historyKey
384
+ isGroup && historyKey && groupContextCacheEnabled
361
385
  ? (chatHistories.get(historyKey) ?? []).map((entry) => ({
362
386
  sender: entry.sender,
363
387
  body: entry.body,
@@ -366,6 +390,25 @@ async function dispatchPalzMessage(params: HandlePalzMessageParams): Promise<voi
366
390
  : undefined;
367
391
  log(`${tag}: [STEP 6b InboundHistory] count=${inboundHistory?.length ?? 0}`);
368
392
 
393
+ // 构建 UntrustedContext:将 IM 消息的关键字段注入到 AI agent 的上下文中
394
+ const untrustedContext: string[] = [
395
+ `sender_id: ${msg.sender_id}`,
396
+ `sender_name: ${senderName}`,
397
+ `conversation_id: ${msg.conversation_id}`,
398
+ `conversation_type: ${msg.conversation_type || "direct"}`,
399
+ `mentioned_bot: ${wasMentioned}`,
400
+ ];
401
+ if (groupId) {
402
+ untrustedContext.push(`group_id: ${groupId}`);
403
+ }
404
+ if (msg.owner_id) {
405
+ untrustedContext.push(`owner_id: ${msg.owner_id}`);
406
+ }
407
+ if (msg.owner_name) {
408
+ untrustedContext.push(`owner_name: ${msg.owner_name}`);
409
+ }
410
+ log(`${tag}: [STEP 6b UntrustedContext] entries=${untrustedContext.length} values=${JSON.stringify(untrustedContext)}`);
411
+
369
412
  const ctx = core.channel.reply.finalizeInboundContext({
370
413
  Body: combinedBody,
371
414
  BodyForAgent: messageBody,
@@ -380,6 +423,7 @@ async function dispatchPalzMessage(params: HandlePalzMessageParams): Promise<voi
380
423
  GroupSubject: isGroup ? msg.conversation_id : undefined,
381
424
  SenderId: msg.sender_id,
382
425
  SenderName: senderName,
426
+ UntrustedContext: untrustedContext,
383
427
  Provider: "palz-connector",
384
428
  Surface: "palz-connector",
385
429
  MessageSid: msg.msg_id,
@@ -418,6 +462,7 @@ async function dispatchPalzMessage(params: HandlePalzMessageParams): Promise<voi
418
462
  enableStreaming: useStream,
419
463
  msgId: msg.msg_id,
420
464
  msgType: msg.msg_type,
465
+ groupId,
421
466
  });
422
467
 
423
468
  // STEP 6d: 分发消息给 AI
@@ -439,7 +484,7 @@ async function dispatchPalzMessage(params: HandlePalzMessageParams): Promise<voi
439
484
  });
440
485
 
441
486
  // AI 回复完成后清空群聊历史(已拼入上下文,避免下次重复)
442
- if (isGroup && historyKey) {
487
+ if (isGroup && historyKey && groupContextCacheEnabled) {
443
488
  clearGroupHistory(historyKey, log);
444
489
  }
445
490
 
package/src/config.ts CHANGED
@@ -72,6 +72,7 @@ export function resolvePalzConfig(_cfg?: any): PalzConfig {
72
72
  streamUrl: file.streamUrl || "",
73
73
  apiBaseUrl: file.apiBaseUrl || "",
74
74
  sessionTimeout: file.sessionTimeout ?? DEFAULT_SESSION_TIMEOUT,
75
+ groupContextCache: file.groupContextCache !== false,
75
76
  };
76
77
  if (!_configLoggedOnce) {
77
78
  _configLoggedOnce = true;
@@ -42,6 +42,7 @@ export interface CreatePalzReplyDispatcherParams {
42
42
  enableStreaming: boolean;
43
43
  msgId: string;
44
44
  msgType?: string;
45
+ groupId?: string;
45
46
  }
46
47
 
47
48
  export function createPalzReplyDispatcher(params: CreatePalzReplyDispatcherParams) {
@@ -57,6 +58,7 @@ export function createPalzReplyDispatcher(params: CreatePalzReplyDispatcherParam
57
58
  enableStreaming,
58
59
  msgId,
59
60
  msgType,
61
+ groupId,
60
62
  } = params;
61
63
 
62
64
  const log = typeof runtime?.log === "function" ? runtime.log : console.log;
@@ -87,6 +89,7 @@ export function createPalzReplyDispatcher(params: CreatePalzReplyDispatcherParam
87
89
  senderId,
88
90
  stream: streamOpts,
89
91
  msgType,
92
+ groupId,
90
93
  });
91
94
  log(`${tag}: [DISPATCHER←sendToIM] 输出: ${JSON.stringify(result)}`);
92
95
  return result;
package/src/send.ts CHANGED
@@ -14,7 +14,7 @@ function nextMsgId(): string {
14
14
  }
15
15
 
16
16
  export async function sendToPalzIM(params: SendToIMParams): Promise<any> {
17
- const { config, conversationId, content, conversationType, msgId, senderId, stream, msgType } = params;
17
+ const { config, conversationId, content, conversationType, msgId, senderId, stream, msgType, groupId } = params;
18
18
  const url = `${config.apiBaseUrl}/bot/send`;
19
19
  const resolvedMsgId = msgId || nextMsgId();
20
20
 
@@ -34,6 +34,10 @@ export async function sendToPalzIM(params: SendToIMParams): Promise<any> {
34
34
  reqBody.msg_type = msgType;
35
35
  }
36
36
 
37
+ if (groupId) {
38
+ reqBody.group_id = groupId;
39
+ }
40
+
37
41
  if (stream) {
38
42
  reqBody.stream_id = stream.streamId;
39
43
  reqBody.seq = stream.seq;
package/src/types.ts CHANGED
@@ -31,6 +31,12 @@ export interface PalzMessageEvent {
31
31
  mentioned_bot?: boolean;
32
32
  /** 可选,IM 下发的消息类型,回复时原样透传 */
33
33
  msg_type?: string;
34
+ /** Bot 所属用户的 ID */
35
+ owner_id?: string;
36
+ /** Bot 所属用户的用户名 */
37
+ owner_name?: string;
38
+ /** 群组 ID,群聊时 IM 可直接下发;若未提供则从 conversation_id 中解析 */
39
+ group_id?: string;
34
40
  }
35
41
 
36
42
  // ============ 配置 ============
@@ -41,6 +47,8 @@ export interface PalzConfig {
41
47
  streamUrl?: string;
42
48
  apiBaseUrl?: string;
43
49
  sessionTimeout?: number;
50
+ /** 群聊上下文缓存开关:true=未@消息缓存为上下文(默认),false=所有群聊消息直接发送给AI */
51
+ groupContextCache?: boolean;
44
52
  }
45
53
 
46
54
  export interface ResolvedPalzAccount {
@@ -78,4 +86,6 @@ export interface SendToIMParams {
78
86
  stream?: StreamChunkOpts;
79
87
  /** IM 下发的消息类型,回复时原样透传 */
80
88
  msgType?: string;
89
+ /** 群组 ID,群聊时透传 */
90
+ groupId?: string;
81
91
  }