palz-connector 1.4.6 → 1.4.8
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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/bot.ts +8 -1
- package/src/monitor.ts +69 -57
- package/src/types.ts +4 -0
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/src/bot.ts
CHANGED
|
@@ -530,6 +530,7 @@ async function _dispatchPalzMessageInner(params: HandlePalzMessageParams): Promi
|
|
|
530
530
|
|
|
531
531
|
// 构建 UntrustedContext:将 IM 消息的关键字段注入到 AI agent 的上下文中
|
|
532
532
|
const untrustedContext: string[] = [
|
|
533
|
+
`msg_id: ${msg.msg_id}`,
|
|
533
534
|
`sender_id: ${msg.sender_id}`,
|
|
534
535
|
`sender_name: ${senderName}`,
|
|
535
536
|
`conversation_id: ${msg.conversation_id}`,
|
|
@@ -557,6 +558,12 @@ async function _dispatchPalzMessageInner(params: HandlePalzMessageParams): Promi
|
|
|
557
558
|
if (groupId) {
|
|
558
559
|
untrustedContext.push(`group_id: ${groupId}`);
|
|
559
560
|
}
|
|
561
|
+
if (msg.group_name) {
|
|
562
|
+
untrustedContext.push(`group_name: ${msg.group_name}`);
|
|
563
|
+
}
|
|
564
|
+
if (msg.group_owner_id) {
|
|
565
|
+
untrustedContext.push(`group_owner_id: ${msg.group_owner_id}`);
|
|
566
|
+
}
|
|
560
567
|
if (msg.owner_id) {
|
|
561
568
|
untrustedContext.push(`owner_id: ${msg.owner_id}`);
|
|
562
569
|
}
|
|
@@ -580,7 +587,7 @@ async function _dispatchPalzMessageInner(params: HandlePalzMessageParams): Promi
|
|
|
580
587
|
SessionKey: route.sessionKey,
|
|
581
588
|
AccountId: route.accountId,
|
|
582
589
|
ChatType: chatType,
|
|
583
|
-
GroupSubject: isGroup ? msg.conversation_id : undefined,
|
|
590
|
+
GroupSubject: isGroup ? (msg.group_name || msg.conversation_id) : undefined,
|
|
584
591
|
SenderId: msg.sender_id,
|
|
585
592
|
SenderName: senderName,
|
|
586
593
|
UntrustedContext: untrustedContext,
|
package/src/monitor.ts
CHANGED
|
@@ -40,6 +40,7 @@ export async function monitorPalzProvider(params: MonitorPalzParams): Promise<vo
|
|
|
40
40
|
let currentWs: WebSocket | null = null;
|
|
41
41
|
let consecutive4002 = 0;
|
|
42
42
|
const MAX_CONSECUTIVE_4002 = 10;
|
|
43
|
+
const MAX_RECONNECT_DELAY_MS = 16_000;
|
|
43
44
|
|
|
44
45
|
const cleanup = () => {
|
|
45
46
|
closed = true;
|
|
@@ -72,15 +73,28 @@ export async function monitorPalzProvider(params: MonitorPalzParams): Promise<vo
|
|
|
72
73
|
}
|
|
73
74
|
abortSignal?.addEventListener("abort", handleAbort, { once: true });
|
|
74
75
|
|
|
75
|
-
function scheduleReconnect() {
|
|
76
|
+
function scheduleReconnect(delay = reconnectDelay, advanceBackoff = true) {
|
|
76
77
|
if (closed) return;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
if (reconnectTimer) {
|
|
79
|
+
clearTimeout(reconnectTimer);
|
|
80
|
+
reconnectTimer = null;
|
|
81
|
+
}
|
|
82
|
+
log(`palz[${accountId}]: scheduling reconnect in ${delay}ms`);
|
|
83
|
+
reconnectTimer = setTimeout(() => {
|
|
84
|
+
reconnectTimer = null;
|
|
85
|
+
connect();
|
|
86
|
+
}, delay);
|
|
87
|
+
if (advanceBackoff) {
|
|
88
|
+
reconnectDelay = Math.min(reconnectDelay * 2, MAX_RECONNECT_DELAY_MS);
|
|
89
|
+
}
|
|
80
90
|
}
|
|
81
91
|
|
|
82
92
|
function connect() {
|
|
83
93
|
if (closed) return;
|
|
94
|
+
if (reconnectTimer) {
|
|
95
|
+
clearTimeout(reconnectTimer);
|
|
96
|
+
reconnectTimer = null;
|
|
97
|
+
}
|
|
84
98
|
|
|
85
99
|
let ws: WebSocket;
|
|
86
100
|
try {
|
|
@@ -94,7 +108,55 @@ export async function monitorPalzProvider(params: MonitorPalzParams): Promise<vo
|
|
|
94
108
|
let connectedAt = 0;
|
|
95
109
|
let pingInterval: ReturnType<typeof setInterval> | null = null;
|
|
96
110
|
let messageCount = 0;
|
|
97
|
-
let
|
|
111
|
+
let ended = false;
|
|
112
|
+
|
|
113
|
+
const handleSocketEnd = (code: number, reasonStr: string) => {
|
|
114
|
+
if (ended) return;
|
|
115
|
+
ended = true;
|
|
116
|
+
if (pingInterval) {
|
|
117
|
+
clearInterval(pingInterval);
|
|
118
|
+
pingInterval = null;
|
|
119
|
+
}
|
|
120
|
+
if (closed) return;
|
|
121
|
+
|
|
122
|
+
const wasConnected = connectedAt > 0;
|
|
123
|
+
const stableMs = wasConnected ? Date.now() - connectedAt : 0;
|
|
124
|
+
|
|
125
|
+
// 4002: 被新连接替代,带退避重试
|
|
126
|
+
if (code === 4002) {
|
|
127
|
+
consecutive4002++;
|
|
128
|
+
if (consecutive4002 >= MAX_CONSECUTIVE_4002) {
|
|
129
|
+
log(
|
|
130
|
+
`palz[${accountId}]: replaced ${consecutive4002} times (code=4002), giving up`,
|
|
131
|
+
);
|
|
132
|
+
cleanup();
|
|
133
|
+
resolve();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const jitter = Math.floor(Math.random() * 2000);
|
|
137
|
+
const delay = 3000 * consecutive4002 + jitter;
|
|
138
|
+
log(
|
|
139
|
+
`palz[${accountId}]: replaced (code=4002, attempt=${consecutive4002}), retry in ${delay}ms`,
|
|
140
|
+
);
|
|
141
|
+
scheduleReconnect(delay, false);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 4001: bot_id 缺失,不重连
|
|
146
|
+
if (code === 4001) {
|
|
147
|
+
error(`palz[${accountId}]: bot_id missing (code=4001), not reconnecting`);
|
|
148
|
+
cleanup();
|
|
149
|
+
resolve();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 其他断开:指数退避重连
|
|
154
|
+
if (wasConnected && stableMs > 10_000) reconnectDelay = 1000;
|
|
155
|
+
log(
|
|
156
|
+
`palz[${accountId}]: disconnected (code=${code}, reason=${reasonStr}, uptime=${Math.round(stableMs / 1000)}s, msgs=${messageCount}), reconnecting in ${reconnectDelay}ms`,
|
|
157
|
+
);
|
|
158
|
+
scheduleReconnect();
|
|
159
|
+
};
|
|
98
160
|
|
|
99
161
|
ws.on("open", () => {
|
|
100
162
|
connectedAt = Date.now();
|
|
@@ -145,62 +207,12 @@ export async function monitorPalzProvider(params: MonitorPalzParams): Promise<vo
|
|
|
145
207
|
});
|
|
146
208
|
|
|
147
209
|
ws.on("close", (code: number, reason: Buffer) => {
|
|
148
|
-
|
|
149
|
-
if (pingInterval) {
|
|
150
|
-
clearInterval(pingInterval);
|
|
151
|
-
pingInterval = null;
|
|
152
|
-
}
|
|
153
|
-
if (closed) return;
|
|
154
|
-
|
|
155
|
-
const stableMs = Date.now() - connectedAt;
|
|
156
|
-
const reasonStr = reason?.toString() || "";
|
|
157
|
-
|
|
158
|
-
// 4002: 被新连接替代,带退避重试
|
|
159
|
-
if (code === 4002) {
|
|
160
|
-
consecutive4002++;
|
|
161
|
-
if (consecutive4002 >= MAX_CONSECUTIVE_4002) {
|
|
162
|
-
log(
|
|
163
|
-
`palz[${accountId}]: replaced ${consecutive4002} times (code=4002), giving up`,
|
|
164
|
-
);
|
|
165
|
-
cleanup();
|
|
166
|
-
resolve();
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
const jitter = Math.floor(Math.random() * 2000);
|
|
170
|
-
const delay = 3000 * consecutive4002 + jitter;
|
|
171
|
-
log(
|
|
172
|
-
`palz[${accountId}]: replaced (code=4002, attempt=${consecutive4002}), retry in ${delay}ms`,
|
|
173
|
-
);
|
|
174
|
-
reconnectTimer = setTimeout(connect, delay);
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// 4001: bot_id 缺失,不重连
|
|
179
|
-
if (code === 4001) {
|
|
180
|
-
error(`palz[${accountId}]: bot_id missing (code=4001), not reconnecting`);
|
|
181
|
-
cleanup();
|
|
182
|
-
resolve();
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// 其他断开:指数退避重连
|
|
187
|
-
if (stableMs > 10_000) reconnectDelay = 1000;
|
|
188
|
-
log(
|
|
189
|
-
`palz[${accountId}]: disconnected (code=${code}, reason=${reasonStr}, uptime=${Math.round(stableMs / 1000)}s, msgs=${messageCount}), reconnecting in ${reconnectDelay}ms`,
|
|
190
|
-
);
|
|
191
|
-
scheduleReconnect();
|
|
210
|
+
handleSocketEnd(code, reason?.toString() || "");
|
|
192
211
|
});
|
|
193
212
|
|
|
194
213
|
ws.on("error", (err) => {
|
|
195
214
|
error(`palz[${accountId}]: WebSocket error: ${err.message}`);
|
|
196
|
-
|
|
197
|
-
closeFired = true;
|
|
198
|
-
if (pingInterval) {
|
|
199
|
-
clearInterval(pingInterval);
|
|
200
|
-
pingInterval = null;
|
|
201
|
-
}
|
|
202
|
-
scheduleReconnect();
|
|
203
|
-
}
|
|
215
|
+
handleSocketEnd(1006, err.message);
|
|
204
216
|
});
|
|
205
217
|
}
|
|
206
218
|
|
package/src/types.ts
CHANGED
|
@@ -37,6 +37,10 @@ export interface PalzMessageEvent {
|
|
|
37
37
|
owner_name?: string;
|
|
38
38
|
/** 群组 ID,群聊时 IM 可直接下发;若未提供则从 conversation_id 中解析 */
|
|
39
39
|
group_id?: string;
|
|
40
|
+
/** 群主用户 ID,群聊时由 IM 下发 */
|
|
41
|
+
group_owner_id?: string;
|
|
42
|
+
/** 群聊名称,群聊时由 IM 下发 */
|
|
43
|
+
group_name?: string;
|
|
40
44
|
/** Lobster ID,标识 agent 身份(IM 通过此字段区分不同 agent) */
|
|
41
45
|
lobster_id?: string;
|
|
42
46
|
/** 群组类型,由 IM 下发 */
|