palz-connector 1.7.2 → 1.7.4-beta.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.7.2",
4
+ "version": "1.7.4-beta.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.7.2",
3
+ "version": "1.7.4-beta.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
  }
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "enabled": true,
3
- "streamUrl": "ws://claw-server:8787/ws/bot",
4
- "apiBaseUrl": "http://claw-server:8787/api",
3
+ "streamUrl": "ws://claw-server:8787/im-server/ws/bot",
4
+ "apiBaseUrl": "http://claw-server:8787/im-server/api",
5
5
  "clawGatewayUrl": "http://claw-gateway:8080",
6
6
  "activityReportEnabled": true,
7
7
  "sessionTimeout": 1800000,
8
8
  "groupContextCache": false,
9
9
  "showProcess": true,
10
+ "processLanguage": "en",
10
11
  "kbEngineUrl": "http://uniclaw-kb-engine:8070",
11
12
  "controlPort": 8008
12
13
  }
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "enabled": true,
3
- "streamUrl": "ws://claw-server:8787/ws/bot",
4
- "apiBaseUrl": "http://claw-server:8787/api",
3
+ "streamUrl": "ws://claw-server:8787/im-server/ws/bot",
4
+ "apiBaseUrl": "http://claw-server:8787/im-server/api",
5
5
  "clawGatewayUrl": "http://claw-gateway:8080",
6
6
  "activityReportEnabled": true,
7
7
  "sessionTimeout": 1800000,
8
8
  "groupContextCache": false,
9
9
  "showProcess": true,
10
+ "processLanguage": "en",
10
11
  "kbEngineUrl": "http://uniclaw-kb-engine:8070",
11
12
  "controlPort": 8008
12
13
  }
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "enabled": true,
3
- "streamUrl": "ws://claw-server:8787/ws/bot",
4
- "apiBaseUrl": "http://claw-server:8787/api",
3
+ "streamUrl": "ws://claw-server:8787/im-server/ws/bot",
4
+ "apiBaseUrl": "http://claw-server:8787/im-server/api",
5
5
  "clawGatewayUrl": "http://claw-gateway:8080",
6
6
  "activityReportEnabled": true,
7
7
  "sessionTimeout": 1800000,
8
8
  "groupContextCache": false,
9
9
  "showProcess": true,
10
+ "processLanguage": "en",
10
11
  "kbEngineUrl": "http://uniclaw-kb-engine:8070",
11
12
  "controlPort": 8008
12
13
  }
package/src/channel.js CHANGED
@@ -40,6 +40,7 @@ export const palzPlugin = {
40
40
  clawGatewayUrl: { type: "string" },
41
41
  activityReportEnabled: { type: "boolean" },
42
42
  sessionTimeout: { type: "integer", minimum: 0 },
43
+ processLanguage: { type: "string", enum: ["zh", "en"] },
43
44
  controlPort: { type: "integer", minimum: 0 },
44
45
  },
45
46
  },
package/src/config.js CHANGED
@@ -15,6 +15,7 @@ const __dirname = path.dirname(__filename);
15
15
  export const PALZ_MANAGER_ACCOUNT_ID = "palz-manager";
16
16
  const DEFAULT_SESSION_TIMEOUT = 30 * 60 * 1000;
17
17
  const DEFAULT_CONFIG_FILENAME = "palz-connector.config.json";
18
+ const DEFAULT_PROCESS_LANGUAGE = "zh";
18
19
  let _cachedFileConfig = null;
19
20
  let _configLoggedOnce = false;
20
21
  let _configAdapterLoggedOnce = false;
@@ -57,6 +58,7 @@ function loadConfigFile() {
57
58
  }
58
59
  export function resolvePalzConfig(_cfg, botId) {
59
60
  const file = loadConfigFile();
61
+ const processLanguage = file.processLanguage === "en" ? "en" : DEFAULT_PROCESS_LANGUAGE;
60
62
  const config = {
61
63
  enabled: file.enabled !== false,
62
64
  botId: botId ?? "",
@@ -67,6 +69,7 @@ export function resolvePalzConfig(_cfg, botId) {
67
69
  sessionTimeout: file.sessionTimeout ?? DEFAULT_SESSION_TIMEOUT,
68
70
  groupContextCache: file.groupContextCache !== false,
69
71
  showProcess: file.showProcess === true,
72
+ processLanguage,
70
73
  kbEngineUrl: file.kbEngineUrl || "",
71
74
  controlPort: file.controlPort,
72
75
  };
@@ -243,15 +243,16 @@ function modelResponseFromGatewayData(data) {
243
243
  return new Response(body, { status, headers: { "Content-Type": contentType } });
244
244
  }
245
245
  async function relayOpenClawRequest(input, url, init, relay) {
246
+ const inboundHeaders = headersFromFetchInput(input, init);
247
+ if (isGatewayOpenClawAgentRelayHop(inboundHeaders)) {
248
+ relay.log?.("[GATEWAY_RELAY] skip gateway-originated OpenClaw agent relay hop; continuing locator model fetch");
249
+ return null;
250
+ }
246
251
  const requestBody = await requestBodyFromFetchInput(input, init);
247
252
  if (!normalize(relay.relayUrl))
248
253
  throw new Error(gatewayRelayNotConfiguredError);
249
254
  if (!requestBody)
250
255
  throw new Error("failed to capture OpenClaw request body for palz gateway relay");
251
- const inboundHeaders = headersFromFetchInput(input, init);
252
- if (isGatewayOpenClawAgentRelayHop(inboundHeaders)) {
253
- throw new Error("palz gateway relay captured gateway-originated OpenClaw agent hop");
254
- }
255
256
  const headers = { "Content-Type": "application/json" };
256
257
  if (normalize(relay.apiKey))
257
258
  headers["X-API-Key"] = normalize(relay.apiKey);
@@ -300,7 +301,8 @@ async function relayOpenClawRequest(input, url, init, relay) {
300
301
  const parsed = parseGatewayRelayResponseText(raw);
301
302
  const data = parsed?.data ? parsed.data : parsed;
302
303
  if (data?.skippedInternalRelay) {
303
- throw new Error("gateway relay skipped internal shared OpenClaw loop");
304
+ relay.log?.(`[GATEWAY_RELAY] gateway relay skipped internal OpenClaw agent loop reason=${normalize(data.skipReason)}; continuing locator model fetch`);
305
+ return null;
304
306
  }
305
307
  if (!resp.ok || !data || data.ok === false) {
306
308
  throw new Error(`gateway relay failed status=${resp.status} body=${raw.slice(0, 500)}`);
@@ -324,7 +326,10 @@ export function installPalzGatewayRelayFetchPatch() {
324
326
  return originalFetch(input, init);
325
327
  }
326
328
  const nextInit = withLocatorHeaders(init, relay);
327
- return relayOpenClawRequest(input, requestURL(input), nextInit, relay);
329
+ const relayResponse = await relayOpenClawRequest(input, requestURL(input), nextInit, relay);
330
+ if (relayResponse)
331
+ return relayResponse;
332
+ return originalFetch(input, nextInit);
328
333
  };
329
334
  fetchPatched = true;
330
335
  }
@@ -27,6 +27,7 @@ export function createPalzReplyDispatcher(params) {
27
27
  const error = typeof runtime?.error === "function" ? runtime.error : console.error;
28
28
  const streamState = enableStreaming ? createStreamingState() : null;
29
29
  const tag = `palz[${accountId}]`;
30
+ const processLanguage = config.processLanguage;
30
31
  // 风控状态(dispatcher 实例级):当前正文回复(palzMsgType===undefined)命中腾讯
31
32
  // 内容风控(80001)时置位,rawError 保留原始错误文案供上层回灌给 agent 做规避指引。
32
33
  // 每个 dispatcher 实例对应一轮 dispatch,新实例自动重置。
@@ -114,14 +115,14 @@ export function createPalzReplyDispatcher(params) {
114
115
  const toolName = data.name ?? data.toolName;
115
116
  if (phase === "start") {
116
117
  const display = resolveToolDisplay(toolName, data.args);
117
- const text = formatToolStartText(toolName, data.args);
118
+ const text = formatToolStartText(toolName, data.args, processLanguage);
118
119
  log(`${tag}: [TOOL_EVENTS] tool_start name=${toolName} detail=${display.detail ?? "(none)"}`);
119
120
  enqueueIMSend(text, undefined, "tool_start", "tool_start");
120
121
  }
121
122
  if (phase === "result") {
122
123
  const isError = data.isError === true;
123
124
  const meta = typeof data.meta === "string" ? data.meta : undefined;
124
- const text = formatToolResultText(toolName, data.result, isError, meta);
125
+ const text = formatToolResultText(toolName, data.result, isError, meta, processLanguage);
125
126
  const resultSummary = isError ? "Error" : formatResultSummary(data.result);
126
127
  log(`${tag}: [TOOL_EVENTS] tool_result name=${toolName} is_error=${isError} summary=${resultSummary}`);
127
128
  enqueueIMSend(text, undefined, "tool_result", "tool_result");
@@ -4,6 +4,30 @@
4
4
  * 提供工具名到 emoji/title/detailKeys 的映射,以及生成纯文本摘要和结构化内容的辅助函数。
5
5
  * 参考 OpenClaw 的 tool-display-overrides.json 和 ui/tool-display.ts。
6
6
  */
7
+ const TOOL_DISPLAY_LABELS = {
8
+ zh: {
9
+ startSuffix: "开始调用",
10
+ argsLabel: "参数",
11
+ completedSuffix: "调用完成",
12
+ resultLabel: "调用结果",
13
+ successText: "成功",
14
+ failedText: "失败",
15
+ errorLabel: "错误信息",
16
+ summaryLabel: "结果摘要",
17
+ successFallbackSuffix: "执行成功",
18
+ },
19
+ en: {
20
+ startSuffix: "started",
21
+ argsLabel: "Arguments",
22
+ completedSuffix: "completed",
23
+ resultLabel: "Result",
24
+ successText: "success",
25
+ failedText: "failed",
26
+ errorLabel: "Error",
27
+ summaryLabel: "Summary",
28
+ successFallbackSuffix: "succeeded",
29
+ },
30
+ };
7
31
  const TOOL_DISPLAY_MAP = {
8
32
  web_search: { emoji: "🔎", title: "Web Search", detailKeys: ["query", "count"] },
9
33
  web_fetch: { emoji: "📄", title: "Web Fetch", detailKeys: ["url", "extractMode", "maxChars"] },
@@ -47,6 +71,9 @@ export function truncateText(text, headLen = 80, tailLen = 40) {
47
71
  return text;
48
72
  return `${text.slice(0, headLen)}...${text.slice(-tailLen)}`;
49
73
  }
74
+ function resolveLanguage(language) {
75
+ return language === "en" ? "en" : "zh";
76
+ }
50
77
  // ============ Detail 提取 ============
51
78
  function extractDetail(args, detailKeys) {
52
79
  if (!args || typeof args !== "object" || !detailKeys.length)
@@ -115,28 +142,30 @@ export function resolveToolDisplay(name, args) {
115
142
  return { emoji, title, detail };
116
143
  }
117
144
  // ============ 纯文本格式化 ============
118
- export function formatToolStartText(name, args) {
145
+ export function formatToolStartText(name, args, language) {
119
146
  const display = resolveToolDisplay(name, args);
120
- const lines = [`${display.emoji} ${display.title} 开始调用`];
147
+ const labels = TOOL_DISPLAY_LABELS[resolveLanguage(language)];
148
+ const lines = [`${display.emoji} ${display.title} ${labels.startSuffix}`];
121
149
  if (display.detail) {
122
- lines.push(`参数: ${display.detail}`);
150
+ lines.push(`${labels.argsLabel}: ${display.detail}`);
123
151
  }
124
152
  return lines.join("\n");
125
153
  }
126
- export function formatToolResultText(name, result, isError, meta) {
154
+ export function formatToolResultText(name, result, isError, meta, language) {
127
155
  const display = resolveToolDisplay(name);
128
- const lines = [`${display.emoji} ${display.title} 调用完成`];
156
+ const labels = TOOL_DISPLAY_LABELS[resolveLanguage(language)];
157
+ const lines = [`${display.emoji} ${display.title} ${labels.completedSuffix}`];
129
158
  if (isError) {
130
- lines.push("调用结果: 失败");
159
+ lines.push(`${labels.resultLabel}: ${labels.failedText}`);
131
160
  const errMsg = extractErrorMessage(result);
132
161
  if (errMsg) {
133
- lines.push(`错误信息: ${truncateText(errMsg, 80, 40)}`);
162
+ lines.push(`${labels.errorLabel}: ${truncateText(errMsg, 80, 40)}`);
134
163
  }
135
164
  }
136
165
  else {
137
- lines.push("调用结果: 成功");
138
- const resultMeta = meta ? truncateText(meta, 120, 40) : `${display.title}执行成功`;
139
- lines.push(`结果摘要: ${resultMeta}`);
166
+ lines.push(`${labels.resultLabel}: ${labels.successText}`);
167
+ const resultMeta = meta ? truncateText(meta, 120, 40) : `${display.title} ${labels.successFallbackSuffix}`;
168
+ lines.push(`${labels.summaryLabel}: ${resultMeta}`);
140
169
  }
141
170
  return lines.join("\n");
142
171
  }