palz-connector 1.4.8 → 1.4.9
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/palz-connector.config.json +2 -0
- package/palz-connector.dev.config.json +2 -0
- package/palz-connector.prod.config.json +2 -0
- package/palz-connector.staging.config.json +2 -0
- package/src/activity.ts +102 -0
- package/src/channel.ts +2 -0
- package/src/config.ts +3 -1
- package/src/monitor.ts +18 -1
- package/src/types.ts +4 -0
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
"enabled": true,
|
|
3
3
|
"streamUrl": "ws://14.103.148.99:8090/ws/bot",
|
|
4
4
|
"apiBaseUrl": "http://14.103.148.99:8090/api",
|
|
5
|
+
"clawGatewayUrl": "http://claw-gateway:8080",
|
|
6
|
+
"activityReportEnabled": false,
|
|
5
7
|
"sessionTimeout": 1800000,
|
|
6
8
|
"groupContextCache": false,
|
|
7
9
|
"showProcess": true
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
"enabled": true,
|
|
3
3
|
"streamUrl": "wss://claw-server.csaiagent.com/ws/bot",
|
|
4
4
|
"apiBaseUrl": "https://claw-server.csaiagent.com/api",
|
|
5
|
+
"clawGatewayUrl": "http://claw-gateway:8080",
|
|
6
|
+
"activityReportEnabled": true,
|
|
5
7
|
"sessionTimeout": 1800000,
|
|
6
8
|
"groupContextCache": false,
|
|
7
9
|
"showProcess": true
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
"enabled": true,
|
|
3
3
|
"streamUrl": "wss://claw-server.csagentai.com/ws/bot",
|
|
4
4
|
"apiBaseUrl": "https://claw-server.csagentai.com/api",
|
|
5
|
+
"clawGatewayUrl": "http://claw-gateway:8080",
|
|
6
|
+
"activityReportEnabled": true,
|
|
5
7
|
"sessionTimeout": 1800000,
|
|
6
8
|
"groupContextCache": false,
|
|
7
9
|
"showProcess": true
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
"enabled": true,
|
|
3
3
|
"streamUrl": "wss://claw-server.csjkagent.com/ws/bot",
|
|
4
4
|
"apiBaseUrl": "https://claw-server.csjkagent.com/api",
|
|
5
|
+
"clawGatewayUrl": "https://claw-server.csjkagent.com/api",
|
|
6
|
+
"activityReportEnabled": true,
|
|
5
7
|
"sessionTimeout": 1800000,
|
|
6
8
|
"groupContextCache": false,
|
|
7
9
|
"showProcess": true
|
package/src/activity.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Palz IM 收到消息后的 claw-gateway 活动上报。
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { PalzConfig, PalzMessageEvent } from "./types.js";
|
|
6
|
+
|
|
7
|
+
const ACTIVITY_REPORT_TIMEOUT_MS = 2000;
|
|
8
|
+
const ACTIVITY_REPORT_PATH_PREFIX = "/openclaw-gateway/be/deployments";
|
|
9
|
+
|
|
10
|
+
const warnedMissingConfig = new Set<string>();
|
|
11
|
+
|
|
12
|
+
export interface ReportPalzActivityParams {
|
|
13
|
+
config: PalzConfig;
|
|
14
|
+
msg: PalzMessageEvent;
|
|
15
|
+
receivedAt: Date;
|
|
16
|
+
runtime?: any;
|
|
17
|
+
accountId?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function formatDateTimeWithOffset(date: Date): string {
|
|
21
|
+
const pad = (n: number, width = 2) => String(n).padStart(width, "0");
|
|
22
|
+
const offsetMinutes = -date.getTimezoneOffset();
|
|
23
|
+
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
24
|
+
const absOffset = Math.abs(offsetMinutes);
|
|
25
|
+
const offsetHours = Math.floor(absOffset / 60);
|
|
26
|
+
const offsetRestMinutes = absOffset % 60;
|
|
27
|
+
|
|
28
|
+
return [
|
|
29
|
+
`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`,
|
|
30
|
+
"T",
|
|
31
|
+
`${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`,
|
|
32
|
+
`${sign}${pad(offsetHours)}:${pad(offsetRestMinutes)}`,
|
|
33
|
+
].join("");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function resolveActivityUrl(baseUrl: string, releaseName: string): string {
|
|
37
|
+
const normalizedBase = baseUrl.replace(/\/+$/, "");
|
|
38
|
+
return `${normalizedBase}${ACTIVITY_REPORT_PATH_PREFIX}/${encodeURIComponent(releaseName)}/activity`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function reportPalzActivity(params: ReportPalzActivityParams): Promise<void> {
|
|
42
|
+
const { config, msg, receivedAt, runtime, accountId } = params;
|
|
43
|
+
const log = typeof runtime?.log === "function" ? runtime.log : console.log;
|
|
44
|
+
const error = typeof runtime?.error === "function" ? runtime.error : console.error;
|
|
45
|
+
const tag = `palz[${accountId ?? config.botId ?? "default"}]`;
|
|
46
|
+
|
|
47
|
+
if (config.activityReportEnabled !== true) return;
|
|
48
|
+
|
|
49
|
+
const baseUrl = config.clawGatewayUrl?.trim();
|
|
50
|
+
const releaseName = (process.env.botID || config.botId || "").trim();
|
|
51
|
+
if (!baseUrl || !releaseName) {
|
|
52
|
+
const warnKey = `${accountId ?? ""}:${baseUrl ? "hasBaseUrl" : "missingBaseUrl"}:${releaseName ? "hasRelease" : "missingRelease"}`;
|
|
53
|
+
if (!warnedMissingConfig.has(warnKey)) {
|
|
54
|
+
warnedMissingConfig.add(warnKey);
|
|
55
|
+
error(`${tag}: [ACTIVITY_REPORT] enabled but missing ${!baseUrl ? "clawGatewayUrl" : "botID/releaseName"}, skip`);
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const payload: Record<string, unknown> = {
|
|
61
|
+
source: "palz-connector",
|
|
62
|
+
eventType: "im_message_received",
|
|
63
|
+
messageId: msg.msg_id,
|
|
64
|
+
conversationId: msg.conversation_id,
|
|
65
|
+
conversationType: msg.conversation_type || "direct",
|
|
66
|
+
userId: msg.owner_id ?? "",
|
|
67
|
+
senderId: msg.sender_id,
|
|
68
|
+
receivedAt: formatDateTimeWithOffset(receivedAt),
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
if (msg.traceparent) {
|
|
72
|
+
payload.traceId = msg.traceparent;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const url = resolveActivityUrl(baseUrl, releaseName);
|
|
76
|
+
const body = JSON.stringify(payload);
|
|
77
|
+
const controller = new AbortController();
|
|
78
|
+
const timeout = setTimeout(() => controller.abort(), ACTIVITY_REPORT_TIMEOUT_MS);
|
|
79
|
+
const startMs = Date.now();
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const response = await fetch(url, {
|
|
83
|
+
method: "POST",
|
|
84
|
+
headers: { "Content-Type": "application/json" },
|
|
85
|
+
body,
|
|
86
|
+
signal: controller.signal,
|
|
87
|
+
});
|
|
88
|
+
const elapsedMs = Date.now() - startMs;
|
|
89
|
+
const responseText = await response.text().catch(() => "");
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
error(`${tag}: [ACTIVITY_REPORT] failed status=${response.status} elapsed=${elapsedMs}ms msg_id=${msg.msg_id} response=${responseText.slice(0, 300)}`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
log(`${tag}: [ACTIVITY_REPORT] ok status=${response.status} elapsed=${elapsedMs}ms msg_id=${msg.msg_id}`);
|
|
95
|
+
} catch (err: any) {
|
|
96
|
+
const elapsedMs = Date.now() - startMs;
|
|
97
|
+
const reason = err?.name === "AbortError" ? `timeout ${ACTIVITY_REPORT_TIMEOUT_MS}ms` : (err?.message ?? String(err));
|
|
98
|
+
error(`${tag}: [ACTIVITY_REPORT] error elapsed=${elapsedMs}ms msg_id=${msg.msg_id} reason=${reason}`);
|
|
99
|
+
} finally {
|
|
100
|
+
clearTimeout(timeout);
|
|
101
|
+
}
|
|
102
|
+
}
|
package/src/channel.ts
CHANGED
|
@@ -44,6 +44,8 @@ export const palzPlugin = {
|
|
|
44
44
|
enabled: { type: "boolean" },
|
|
45
45
|
streamUrl: { type: "string" },
|
|
46
46
|
apiBaseUrl: { type: "string" },
|
|
47
|
+
clawGatewayUrl: { type: "string" },
|
|
48
|
+
activityReportEnabled: { type: "boolean" },
|
|
47
49
|
sessionTimeout: { type: "integer", minimum: 0 },
|
|
48
50
|
},
|
|
49
51
|
},
|
package/src/config.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 配置来源:
|
|
5
5
|
* - botId: 仅从环境变量 botID 读取
|
|
6
|
-
* - streamUrl / apiBaseUrl / sessionTimeout: 从配置文件读取
|
|
6
|
+
* - streamUrl / apiBaseUrl / clawGatewayUrl / sessionTimeout: 从配置文件读取
|
|
7
7
|
* - 若环境变量 HELM_ENV 存在且非空,读取 palz-connector.{HELM_ENV}.config.json
|
|
8
8
|
* - 否则读取默认配置文件 palz-connector.config.json
|
|
9
9
|
*/
|
|
@@ -71,6 +71,8 @@ export function resolvePalzConfig(_cfg?: any): PalzConfig {
|
|
|
71
71
|
botId: process.env.botID || "",
|
|
72
72
|
streamUrl: file.streamUrl || "",
|
|
73
73
|
apiBaseUrl: file.apiBaseUrl || "",
|
|
74
|
+
clawGatewayUrl: file.clawGatewayUrl || "",
|
|
75
|
+
activityReportEnabled: file.activityReportEnabled === true,
|
|
74
76
|
sessionTimeout: file.sessionTimeout ?? DEFAULT_SESSION_TIMEOUT,
|
|
75
77
|
groupContextCache: file.groupContextCache !== false,
|
|
76
78
|
showProcess: file.showProcess === true,
|
package/src/monitor.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import WebSocket from "ws";
|
|
9
9
|
import { handlePalzMessage } from "./bot.js";
|
|
10
|
+
import { reportPalzActivity } from "./activity.js";
|
|
10
11
|
import { tracer, extractTraceparentContext, SpanStatusCode } from "./tracing.js";
|
|
11
12
|
import type { PalzConfig, PalzMessageEvent } from "./types.js";
|
|
12
13
|
|
|
@@ -173,6 +174,7 @@ export async function monitorPalzProvider(params: MonitorPalzParams): Promise<vo
|
|
|
173
174
|
});
|
|
174
175
|
|
|
175
176
|
ws.on("message", (data: Buffer) => {
|
|
177
|
+
const receivedAt = new Date();
|
|
176
178
|
const raw = data.toString();
|
|
177
179
|
try {
|
|
178
180
|
const msg = JSON.parse(raw) as PalzMessageEvent;
|
|
@@ -191,7 +193,22 @@ export async function monitorPalzProvider(params: MonitorPalzParams): Promise<vo
|
|
|
191
193
|
|
|
192
194
|
log(`palz[${accountId}]: [WS_RECV] #${messageCount} full_message=${raw.slice(0, 1000)} traceId=${span.spanContext().traceId}`);
|
|
193
195
|
|
|
194
|
-
|
|
196
|
+
reportPalzActivity({
|
|
197
|
+
config,
|
|
198
|
+
msg,
|
|
199
|
+
receivedAt,
|
|
200
|
+
runtime,
|
|
201
|
+
accountId,
|
|
202
|
+
}).catch((err: any) => {
|
|
203
|
+
error(`palz[${accountId}]: [ACTIVITY_REPORT] unhandled error: ${err.message ?? err}`);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
handlePalzMessage({
|
|
207
|
+
cfg,
|
|
208
|
+
msg,
|
|
209
|
+
runtime,
|
|
210
|
+
accountId,
|
|
211
|
+
}).catch((err: any) => {
|
|
195
212
|
error(`palz[${accountId}]: [WS_RECV] handlePalzMessage unhandled error: ${err.message ?? err}`);
|
|
196
213
|
});
|
|
197
214
|
} catch (e) {
|
package/src/types.ts
CHANGED
|
@@ -64,6 +64,10 @@ export interface PalzConfig {
|
|
|
64
64
|
botId?: string;
|
|
65
65
|
streamUrl?: string;
|
|
66
66
|
apiBaseUrl?: string;
|
|
67
|
+
/** claw-gateway 服务基础地址,例如 https://example.com */
|
|
68
|
+
clawGatewayUrl?: string;
|
|
69
|
+
/** 是否向 claw-gateway 上报 IM 消息接收事件,默认 false */
|
|
70
|
+
activityReportEnabled?: boolean;
|
|
67
71
|
sessionTimeout?: number;
|
|
68
72
|
/** 群聊上下文缓存开关:true=未@消息缓存为上下文(默认),false=所有群聊消息直接发送给AI */
|
|
69
73
|
groupContextCache?: boolean;
|