palz-connector 1.6.9 → 1.7.1

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.6.9",
4
+ "version": "1.7.1",
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.6.9",
3
+ "version": "1.7.1",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "description": "Palz IM 接入 OpenClaw — 模块化架构,基于 OpenClaw Runtime 消息管道",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "enabled": true,
3
- "streamUrl": "ws://14.103.148.99:8090/ws/bot",
4
- "apiBaseUrl": "http://14.103.148.99:8090/api",
3
+ "streamUrl": "ws://claw-server:8787/ws/bot",
4
+ "apiBaseUrl": "http://claw-server:8787/api",
5
5
  "clawGatewayUrl": "http://claw-gateway:8080",
6
- "activityReportEnabled": false,
6
+ "activityReportEnabled": true,
7
7
  "sessionTimeout": 1800000,
8
8
  "groupContextCache": false,
9
9
  "showProcess": true,
10
- "kbEngineUrl": "http://127.0.0.1:8070",
10
+ "kbEngineUrl": "http://uniclaw-kb-engine:8070",
11
11
  "controlPort": 8008
12
12
  }
package/src/activity.js CHANGED
@@ -1,9 +1,10 @@
1
1
  /**
2
- * Palz IM 收到消息后的 claw-gateway 活动上报。
2
+ * Palz IM WebSocket 连接成功后的 claw-gateway 活动上报。
3
3
  */
4
4
  const ACTIVITY_REPORT_TIMEOUT_MS = 2000;
5
5
  const ACTIVITY_REPORT_PATH_PREFIX = "/openclaw-gateway/be/deployments";
6
6
  const warnedMissingConfig = new Set();
7
+ const SERVICE_NAME = process.env.OPENCLAW_WORKSPACE_POOL_SERVICE_NAME ?? "";
7
8
  function formatDateTimeWithOffset(date) {
8
9
  const pad = (n, width = 2) => String(n).padStart(width, "0");
9
10
  const offsetMinutes = -date.getTimezoneOffset();
@@ -23,7 +24,7 @@ function resolveActivityUrl(baseUrl, releaseName) {
23
24
  return `${normalizedBase}${ACTIVITY_REPORT_PATH_PREFIX}/${encodeURIComponent(releaseName)}/activity`;
24
25
  }
25
26
  export async function reportPalzActivity(params) {
26
- const { config, msg, receivedAt, runtime, accountId } = params;
27
+ const { config, connectedAt, runtime, accountId } = params;
27
28
  const log = typeof runtime?.log === "function" ? runtime.log : console.log;
28
29
  const error = typeof runtime?.error === "function" ? runtime.error : console.error;
29
30
  const tag = `palz[${accountId ?? config.botId ?? "default"}]`;
@@ -41,22 +42,17 @@ export async function reportPalzActivity(params) {
41
42
  }
42
43
  const payload = {
43
44
  source: "palz-connector",
44
- eventType: "im_message_received",
45
- messageId: msg.msg_id,
46
- conversationId: msg.conversation_id,
47
- conversationType: msg.conversation_type || "direct",
48
- userId: msg.owner_id ?? "",
49
- senderId: msg.sender_id,
50
- receivedAt: formatDateTimeWithOffset(receivedAt),
45
+ eventType: "ws_connected",
46
+ releaseName,
47
+ serviceName: SERVICE_NAME,
48
+ connectedAt: formatDateTimeWithOffset(connectedAt),
51
49
  };
52
- if (msg.traceparent) {
53
- payload.traceId = msg.traceparent;
54
- }
55
50
  const url = resolveActivityUrl(baseUrl, releaseName);
56
51
  const body = JSON.stringify(payload);
57
52
  const controller = new AbortController();
58
53
  const timeout = setTimeout(() => controller.abort(), ACTIVITY_REPORT_TIMEOUT_MS);
59
54
  const startMs = Date.now();
55
+ log(`${tag}: [ACTIVITY_REPORT] reporting eventType=ws_connected url=${url} body=${body}`);
60
56
  try {
61
57
  const response = await fetch(url, {
62
58
  method: "POST",
@@ -67,15 +63,15 @@ export async function reportPalzActivity(params) {
67
63
  const elapsedMs = Date.now() - startMs;
68
64
  const responseText = await response.text().catch(() => "");
69
65
  if (!response.ok) {
70
- error(`${tag}: [ACTIVITY_REPORT] failed status=${response.status} elapsed=${elapsedMs}ms msg_id=${msg.msg_id} response=${responseText.slice(0, 300)}`);
66
+ error(`${tag}: [ACTIVITY_REPORT] failed status=${response.status} elapsed=${elapsedMs}ms response=${responseText.slice(0, 300)}`);
71
67
  return;
72
68
  }
73
- log(`${tag}: [ACTIVITY_REPORT] ok status=${response.status} elapsed=${elapsedMs}ms msg_id=${msg.msg_id}`);
69
+ log(`${tag}: [ACTIVITY_REPORT] ok status=${response.status} elapsed=${elapsedMs}ms eventType=ws_connected`);
74
70
  }
75
71
  catch (err) {
76
72
  const elapsedMs = Date.now() - startMs;
77
73
  const reason = err?.name === "AbortError" ? `timeout ${ACTIVITY_REPORT_TIMEOUT_MS}ms` : (err?.message ?? String(err));
78
- error(`${tag}: [ACTIVITY_REPORT] error elapsed=${elapsedMs}ms msg_id=${msg.msg_id} reason=${reason}`);
74
+ error(`${tag}: [ACTIVITY_REPORT] error elapsed=${elapsedMs}ms reason=${reason}`);
79
75
  }
80
76
  finally {
81
77
  clearTimeout(timeout);
package/src/channel.js CHANGED
@@ -72,11 +72,10 @@ export const palzPlugin = {
72
72
  gateway: {
73
73
  startAccount: async (ctx) => {
74
74
  const log = typeof ctx.runtime?.log === "function" ? ctx.runtime.log : console.log;
75
- const logInfo = typeof ctx.log?.info === "function" ? ctx.log.info.bind(ctx.log) : log;
76
75
  const error = typeof ctx.runtime?.error === "function" ? ctx.runtime.error : console.error;
77
- logInfo("palz-gateway: [startAccount] 输入: accountId=" + JSON.stringify(ctx.accountId));
76
+ log("palz-gateway: [startAccount] 输入: accountId=" + JSON.stringify(ctx.accountId));
78
77
  if (ctx.accountId !== PALZ_MANAGER_ACCOUNT_ID) {
79
- logInfo("palz-gateway: [startAccount] non-manager account " + JSON.stringify(ctx.accountId) + ", returning abort-pending promise");
78
+ log("palz-gateway: [startAccount] non-manager account " + JSON.stringify(ctx.accountId) + ", returning abort-pending promise");
80
79
  return new Promise((resolve) => {
81
80
  if (ctx.abortSignal?.aborted) {
82
81
  resolve();
@@ -88,15 +87,17 @@ export const palzPlugin = {
88
87
  const baseConfig = resolvePalzConfig(ctx.cfg);
89
88
  if (!baseConfig.streamUrl || !baseConfig.apiBaseUrl) {
90
89
  const errMsg = "Palz manager not configured (missing streamUrl/apiBaseUrl)";
91
- logInfo("palz-gateway: [startAccount] 失败: " + errMsg);
90
+ log("palz-gateway: [startAccount] 失败: " + errMsg);
92
91
  throw new Error(errMsg);
93
92
  }
94
- logInfo("palz-gateway: [startAccount] 启动 manager, streamUrl=" + baseConfig.streamUrl);
93
+ log("palz-gateway: [startAccount] 启动 manager, streamUrl=" + baseConfig.streamUrl);
95
94
  const manager = new ConnectionManager({
96
95
  cfg: ctx.cfg,
97
96
  baseConfig,
98
97
  runtime: ctx.runtime,
99
- log: logInfo,
98
+ // 用 runtime.log(写文件),而非仅 stdout 的 ctx.log.info,
99
+ // 使连接生命周期日志(reconcile/add/remove/shutdown)落入 palz-*.log。
100
+ log,
100
101
  error,
101
102
  });
102
103
  const scanner = startUserDirScanner({
@@ -105,7 +106,7 @@ export const palzPlugin = {
105
106
  error("palz-gateway: reconcile error: " + String(err));
106
107
  });
107
108
  },
108
- log: logInfo,
109
+ log,
109
110
  error,
110
111
  });
111
112
  // Stop service: disconnect all WS connections and prevent scanner-triggered reconnects.
@@ -115,7 +116,7 @@ export const palzPlugin = {
115
116
  if (stopped)
116
117
  return;
117
118
  stopped = true;
118
- logInfo("palz-gateway: [doStop] stopping service, shutting down scanner + manager");
119
+ log("palz-gateway: [doStop] stopping service, shutting down scanner + manager");
119
120
  scanner.stop();
120
121
  manager.shutdown();
121
122
  };
@@ -133,13 +134,15 @@ export const palzPlugin = {
133
134
  },
134
135
  cfg: ctx.cfg,
135
136
  runtime: ctx.runtime,
136
- log: logInfo,
137
+ // 用 runtime.log(写入 palz-*.log 文件),而非 ctx.log.info(仅 stdout),
138
+ // 使 control-server 的回调日志与消息链路日志落到同一文件,便于排查。
139
+ log,
137
140
  error,
138
141
  });
139
142
  }
140
143
  return new Promise((resolve) => {
141
144
  const onAbort = () => {
142
- logInfo("palz-gateway: [startAccount] abort received, shutting down manager");
145
+ log("palz-gateway: [startAccount] abort received, shutting down manager");
143
146
  controlServer?.close();
144
147
  doStop();
145
148
  resolve();
package/src/monitor.js CHANGED
@@ -167,6 +167,14 @@ export async function monitorPalzProvider(params) {
167
167
  lastPongAt = connectedAt;
168
168
  consecutive4002 = 0;
169
169
  log(`palz[${accountId}]: WebSocket connected, bot_id=${config.botId}`);
170
+ reportPalzActivity({
171
+ config,
172
+ connectedAt: new Date(connectedAt),
173
+ runtime,
174
+ accountId,
175
+ }).catch((err) => {
176
+ error(`palz[${accountId}]: [ACTIVITY_REPORT] unhandled error: ${err.message ?? err}`);
177
+ });
170
178
  pingInterval = setInterval(() => {
171
179
  if (ws.readyState === WebSocket.OPEN) {
172
180
  const timeSinceLastPong = Date.now() - lastPongAt;
@@ -195,7 +203,6 @@ export async function monitorPalzProvider(params) {
195
203
  }
196
204
  });
197
205
  ws.on("message", (data) => {
198
- const receivedAt = new Date();
199
206
  const raw = data.toString();
200
207
  try {
201
208
  const msg = JSON.parse(raw);
@@ -209,15 +216,6 @@ export async function monitorPalzProvider(params) {
209
216
  try {
210
217
  span.setAttribute("raw_message", raw);
211
218
  log(`palz[${accountId}]: [WS_RECV] #${messageCount} full_message=${raw} traceId=${span.spanContext().traceId}`);
212
- reportPalzActivity({
213
- config,
214
- msg,
215
- receivedAt,
216
- runtime,
217
- accountId,
218
- }).catch((err) => {
219
- error(`palz[${accountId}]: [ACTIVITY_REPORT] unhandled error: ${err.message ?? err}`);
220
- });
221
219
  // agent_id:从消息中取,缺失/空时默认为 {userId}-main
222
220
  let messageAgentId = typeof msg.agent_id === "string" ? msg.agent_id.trim() : "";
223
221
  if (!messageAgentId) {