palz-connector 1.3.3 → 1.3.4

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.3.3",
4
+ "version": "1.3.4",
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.3.3",
3
+ "version": "1.3.4",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "description": "Palz IM 接入 OpenClaw — 模块化架构,基于 OpenClaw Runtime 消息管道",
@@ -4,5 +4,5 @@
4
4
  "apiBaseUrl": "http://14.103.148.99:8090/api",
5
5
  "sessionTimeout": 1800000,
6
6
  "groupContextCache": true,
7
- "showProcess":true
7
+ "showProcess": true
8
8
  }
@@ -4,5 +4,5 @@
4
4
  "apiBaseUrl": "https://claw-server.csaiagent.com/api",
5
5
  "sessionTimeout": 1800000,
6
6
  "groupContextCache": true,
7
- "showProcess":true
7
+ "showProcess": true
8
8
  }
@@ -4,5 +4,5 @@
4
4
  "apiBaseUrl": "https://claw-server.csagentai.com/api",
5
5
  "sessionTimeout": 1800000,
6
6
  "groupContextCache": true,
7
- "showProcess":true
7
+ "showProcess": true
8
8
  }
@@ -4,5 +4,5 @@
4
4
  "apiBaseUrl": "https://claw-server.csjkagent.com/api",
5
5
  "sessionTimeout": 1800000,
6
6
  "groupContextCache": true,
7
- "showProcess":true
7
+ "showProcess": true
8
8
  }
@@ -72,6 +72,22 @@ export function createPalzReplyDispatcher(params: CreatePalzReplyDispatcherParam
72
72
  const streamState = enableStreaming ? createStreamingState() : null;
73
73
  const tag = `palz[${accountId}]`;
74
74
 
75
+ // 会话级串行队列:保证同一会话内 IM 消息按入队顺序到达
76
+ // (不同 dispatcher 实例对应不同会话,天然隔离)
77
+ let imSendQueue: Promise<unknown> = Promise.resolve();
78
+ const enqueueIMSend = (
79
+ content: OpenAIContent,
80
+ streamOpts: StreamChunkOpts | undefined,
81
+ palzMsgType: string | undefined,
82
+ label: string,
83
+ ): Promise<unknown> => {
84
+ const next = imSendQueue.then(() => sendToIM(content, streamOpts, palzMsgType)).catch((err: any) => {
85
+ error(`${tag}: [IM_QUEUE] ${label} 发送失败: ${err?.message ?? String(err)}`);
86
+ });
87
+ imSendQueue = next;
88
+ return next;
89
+ };
90
+
75
91
  log(
76
92
  `${tag}: [DISPATCHER 创建] conv=${conversationId} sender=${senderId} streaming=${enableStreaming}${streamState ? ` streamId=${streamState.streamId}` : ""}`,
77
93
  );
@@ -131,9 +147,7 @@ export function createPalzReplyDispatcher(params: CreatePalzReplyDispatcherParam
131
147
  const display = resolveToolDisplay(toolName, data.args);
132
148
  const text = formatToolStartText(toolName, data.args);
133
149
  log(`${tag}: [TOOL_EVENTS] tool_start name=${toolName} detail=${display.detail ?? "(none)"}`);
134
- sendToIM(text, undefined, "tool_start").catch((err: any) => {
135
- error(`${tag}: [TOOL_EVENTS] tool_start 发送失败: ${err.message}`);
136
- });
150
+ enqueueIMSend(text, undefined, "tool_start", "tool_start");
137
151
  }
138
152
 
139
153
  if (phase === "result") {
@@ -142,9 +156,7 @@ export function createPalzReplyDispatcher(params: CreatePalzReplyDispatcherParam
142
156
  const text = formatToolResultText(toolName, data.result, isError, meta);
143
157
  const resultSummary = isError ? "Error" : formatResultSummary(data.result);
144
158
  log(`${tag}: [TOOL_EVENTS] tool_result name=${toolName} is_error=${isError} summary=${resultSummary}`);
145
- sendToIM(text, undefined, "tool_result").catch((err: any) => {
146
- error(`${tag}: [TOOL_EVENTS] tool_result 发送失败: ${err.message}`);
147
- });
159
+ enqueueIMSend(text, undefined, "tool_result", "tool_result");
148
160
  }
149
161
  }
150
162
  });
@@ -201,18 +213,24 @@ export function createPalzReplyDispatcher(params: CreatePalzReplyDispatcherParam
201
213
 
202
214
  if (streamState && kind === "final" && typeof content === "string") {
203
215
  const delta = content.slice(streamState.lastSentLength);
216
+ const seq = streamState.seq++;
204
217
  log(
205
- `${tag}: [DELIVER 流式最终] seq=${streamState.seq} totalLen=${content.length} deltaLen=${delta.length} delta="${delta.slice(0, 120)}"`,
218
+ `${tag}: [DELIVER 流式最终] seq=${seq} totalLen=${content.length} deltaLen=${delta.length} delta="${delta.slice(0, 120)}"`,
219
+ );
220
+ await enqueueIMSend(
221
+ content,
222
+ {
223
+ streamId: streamState.streamId,
224
+ seq,
225
+ isFinal: true,
226
+ delta,
227
+ },
228
+ undefined,
229
+ `final seq=${seq}`,
206
230
  );
207
- await sendToIM(content, {
208
- streamId: streamState.streamId,
209
- seq: streamState.seq++,
210
- isFinal: true,
211
- delta,
212
- });
213
231
  } else {
214
232
  log(`${tag}: [DELIVER 非流式] contentType=${typeof content === "string" ? "string" : "array"}`);
215
- await sendToIM(content);
233
+ await enqueueIMSend(content, undefined, undefined, "deliver");
216
234
  }
217
235
 
218
236
  log(`${tag}: [DELIVER 完成] kind=${kind}`);
@@ -260,14 +278,17 @@ export function createPalzReplyDispatcher(params: CreatePalzReplyDispatcherParam
260
278
  `${tag}: [PARTIAL 输出] seq=${seq} totalLen=${text.length} deltaLen=${delta.length} delta="${delta.slice(0, 120)}" elapsed=${elapsed}ms`,
261
279
  );
262
280
 
263
- sendToIM(text, {
264
- streamId: streamState.streamId,
265
- seq,
266
- isFinal: false,
267
- delta,
268
- }).catch((err: any) => {
269
- error(`${tag}: [PARTIAL 发送失败] seq=${seq} error=${err.message}`);
270
- });
281
+ enqueueIMSend(
282
+ text,
283
+ {
284
+ streamId: streamState.streamId,
285
+ seq,
286
+ isFinal: false,
287
+ delta,
288
+ },
289
+ undefined,
290
+ `partial seq=${seq}`,
291
+ );
271
292
  }
272
293
  : undefined,
273
294
  onReasoningStream: showProcess
@@ -287,9 +308,7 @@ export function createPalzReplyDispatcher(params: CreatePalzReplyDispatcherParam
287
308
  text = text.replace(/^Reasoning:\n/, "");
288
309
  text = text.replace(/^_|_$/gm, "");
289
310
  log(`${tag}: [THINKING] 思考完成, len=${text.length}`);
290
- sendToIM(text, undefined, "thinking").catch((err: any) => {
291
- error(`${tag}: [THINKING] 发送失败: ${err.message}`);
292
- });
311
+ enqueueIMSend(text, undefined, "thinking", "thinking");
293
312
  }
294
313
  : undefined,
295
314
  };