@wecom/wecom-openclaw-plugin 2026.4.3 → 2026.4.7-beta.2
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/dist/src/const.d.ts +2 -0
- package/dist/src/const.js +2 -0
- package/dist/src/mcp/transport.js +64 -3
- package/dist/src/monitor.js +1 -1
- package/dist/src/runtime.d.ts +2 -2
- package/dist/src/runtime.js +3 -10
- package/dist/src/state-manager.js +3 -2
- package/package.json +1 -1
package/dist/src/const.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ export declare const MESSAGE_STATE_TTL_MS: number;
|
|
|
38
38
|
export declare const MESSAGE_STATE_CLEANUP_INTERVAL_MS = 60000;
|
|
39
39
|
/** messageStates Map 最大条目数 */
|
|
40
40
|
export declare const MESSAGE_STATE_MAX_SIZE = 500;
|
|
41
|
+
/** WebSocket 全局实例键 */
|
|
42
|
+
export declare const GLOBAL_WS_CLIENT_KEY: "__wecom_openclaw_ws_client_instances";
|
|
41
43
|
/** "思考中"流式消息占位内容 */
|
|
42
44
|
export declare const THINKING_MESSAGE = "<think></think>";
|
|
43
45
|
/** 仅包含图片时的消息占位符 */
|
package/dist/src/const.js
CHANGED
|
@@ -45,6 +45,8 @@ export const MESSAGE_STATE_TTL_MS = 10 * 60 * 1000;
|
|
|
45
45
|
export const MESSAGE_STATE_CLEANUP_INTERVAL_MS = 60_000;
|
|
46
46
|
/** messageStates Map 最大条目数 */
|
|
47
47
|
export const MESSAGE_STATE_MAX_SIZE = 500;
|
|
48
|
+
/** WebSocket 全局实例键 */
|
|
49
|
+
export const GLOBAL_WS_CLIENT_KEY = "__wecom_openclaw_ws_client_instances";
|
|
48
50
|
// ============================================================================
|
|
49
51
|
// 消息模板
|
|
50
52
|
// ============================================================================
|
|
@@ -15,6 +15,8 @@ import { getWeComWebSocket } from "../state-manager.js";
|
|
|
15
15
|
import { MCP_GET_CONFIG_CMD, MCP_CONFIG_FETCH_TIMEOUT_MS } from "../const.js";
|
|
16
16
|
import { withTimeout } from "../timeout.js";
|
|
17
17
|
import { PLUGIN_VERSION } from "../version.js";
|
|
18
|
+
import { getWeComRuntime } from "../runtime.js";
|
|
19
|
+
import { resolveDefaultWeComAccountId, listWeComAccountIds, resolveWeComAccountMulti, } from "../accounts.js";
|
|
18
20
|
// ============================================================================
|
|
19
21
|
// 内部状态
|
|
20
22
|
// ============================================================================
|
|
@@ -77,16 +79,75 @@ const inflightInitRequests = new Map();
|
|
|
77
79
|
// ============================================================================
|
|
78
80
|
// MCP 配置拉取与缓存
|
|
79
81
|
// ============================================================================
|
|
82
|
+
/**
|
|
83
|
+
* 判断账户是否为长连接机器人(通过 botId + secret 配置)
|
|
84
|
+
*/
|
|
85
|
+
function isWebSocketBot(cfg, accountId) {
|
|
86
|
+
const resolved = resolveWeComAccountMulti({ cfg, accountId });
|
|
87
|
+
return Boolean(resolved.botId?.trim() && resolved.secret?.trim());
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 解析用于 MCP 调用的账户 ID
|
|
91
|
+
*
|
|
92
|
+
* 优先级:
|
|
93
|
+
* 1. 默认账户(如果是长连接机器人)
|
|
94
|
+
* 2. 第一个长连接机器人账户
|
|
95
|
+
* 3. 无可用账户时返回 null
|
|
96
|
+
*/
|
|
97
|
+
function resolveMcpAccountId(cfg) {
|
|
98
|
+
const defaultAccountId = resolveDefaultWeComAccountId(cfg);
|
|
99
|
+
// 优先使用默认账户
|
|
100
|
+
if (isWebSocketBot(cfg, defaultAccountId)) {
|
|
101
|
+
return defaultAccountId;
|
|
102
|
+
}
|
|
103
|
+
// 默认账户非长连接,查找第一个长连接账户
|
|
104
|
+
const allIds = listWeComAccountIds(cfg);
|
|
105
|
+
for (const id of allIds) {
|
|
106
|
+
if (id !== defaultAccountId && isWebSocketBot(cfg, id)) {
|
|
107
|
+
console.log(`${LOG_TAG} 默认账户 "${defaultAccountId}" 非长连接模式,使用账户 "${id}" 获取 MCP 配置`);
|
|
108
|
+
return id;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 根据配置解析当前用于 MCP 的账户 ID
|
|
115
|
+
*
|
|
116
|
+
* 通过 PluginRuntime 读取全局配置,按以下优先级选择账户:
|
|
117
|
+
* 1. 默认账户(如果配置了 botId + secret)
|
|
118
|
+
* 2. 第一个配置了 botId + secret 的长连接账户
|
|
119
|
+
* 3. 无可用长连接账户时回退到默认账户(会导致后续 WSClient 获取失败)
|
|
120
|
+
*/
|
|
121
|
+
function resolveCurrentAccountId() {
|
|
122
|
+
try {
|
|
123
|
+
const core = getWeComRuntime();
|
|
124
|
+
const cfg = core.config.loadConfig();
|
|
125
|
+
const mcpAccountId = resolveMcpAccountId(cfg);
|
|
126
|
+
if (mcpAccountId) {
|
|
127
|
+
return mcpAccountId;
|
|
128
|
+
}
|
|
129
|
+
// 无长连接账户,给出友好提示
|
|
130
|
+
console.warn(`${LOG_TAG} 未找到长连接模式的机器人账户(需配置 botId + secret),MCP 功能不可用`);
|
|
131
|
+
return resolveDefaultWeComAccountId(cfg);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// runtime 未初始化时回退到 "default"
|
|
135
|
+
return DEFAULT_ACCOUNT_ID;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
80
138
|
/**
|
|
81
139
|
* 通过 WSClient 拉取指定 category 的 MCP 完整配置
|
|
82
140
|
*
|
|
141
|
+
* 自动根据 defaultAccount 配置获取对应账户的 WSClient,无需手动传入 accountId。
|
|
142
|
+
*
|
|
83
143
|
* @param category - MCP 品类名称,如 doc、contact
|
|
84
144
|
* @returns 完整的 response.body 配置对象(至少包含 url 字段)
|
|
85
145
|
*/
|
|
86
146
|
async function fetchMcpConfig(category) {
|
|
87
|
-
const
|
|
147
|
+
const accountId = resolveCurrentAccountId();
|
|
148
|
+
const wsClient = getWeComWebSocket(accountId);
|
|
88
149
|
if (!wsClient) {
|
|
89
|
-
throw new Error(
|
|
150
|
+
throw new Error(`WSClient 未连接 (accountId="${accountId}"),无法拉取 MCP 配置`);
|
|
90
151
|
}
|
|
91
152
|
const reqId = generateReqId("mcp_config");
|
|
92
153
|
const response = await withTimeout(wsClient.reply({ headers: { req_id: reqId } }, { biz_type: category, plugin_version: PLUGIN_VERSION }, MCP_GET_CONFIG_CMD), MCP_CONFIG_FETCH_TIMEOUT_MS, `MCP config fetch for "${category}" timed out after ${MCP_CONFIG_FETCH_TIMEOUT_MS}ms`);
|
|
@@ -99,7 +160,7 @@ async function fetchMcpConfig(category) {
|
|
|
99
160
|
if (!body?.url) {
|
|
100
161
|
throw new Error(`MCP 配置响应缺少 url 字段 (category="${category}")`);
|
|
101
162
|
}
|
|
102
|
-
console.log(`${LOG_TAG} 配置拉取成功 (category="${category}")`);
|
|
163
|
+
console.log(`${LOG_TAG} 配置拉取成功 (accountId="${accountId}", category="${category}")`);
|
|
103
164
|
return body;
|
|
104
165
|
}
|
|
105
166
|
/**
|
package/dist/src/monitor.js
CHANGED
|
@@ -353,7 +353,7 @@ async function routeAndDispatchMessage(params) {
|
|
|
353
353
|
}
|
|
354
354
|
},
|
|
355
355
|
deliver: async (payload, info) => {
|
|
356
|
-
runtime.log?.(`[openclaw -> plugin] kind=${info.kind}, text=${payload.text ?? ''}, mediaUrl=${payload.mediaUrl ?? ''}, mediaUrls=${JSON.stringify(payload.mediaUrls ?? [])}`);
|
|
356
|
+
runtime.log?.(`[openclaw -> plugin] kind=${info.kind}, text=${JSON.stringify(payload.text ?? '')}, mediaUrl=${payload.mediaUrl ?? ''}, mediaUrls=${JSON.stringify(payload.mediaUrls ?? [])}`);
|
|
357
357
|
// 累积文本
|
|
358
358
|
if (payload.text) {
|
|
359
359
|
state.accumulatedText += `${payload.text || ''}`;
|
package/dist/src/runtime.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { PluginRuntime } from "openclaw/plugin-sdk/core";
|
|
2
|
-
|
|
3
|
-
export
|
|
2
|
+
declare const setWeComRuntime: (next: PluginRuntime) => void, getWeComRuntime: () => PluginRuntime;
|
|
3
|
+
export { setWeComRuntime, getWeComRuntime };
|
package/dist/src/runtime.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
export function getWeComRuntime() {
|
|
6
|
-
if (!runtime) {
|
|
7
|
-
throw new Error("WeCom runtime not initialized - plugin not registered");
|
|
8
|
-
}
|
|
9
|
-
return runtime;
|
|
10
|
-
}
|
|
1
|
+
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
2
|
+
const { setRuntime: setWeComRuntime, getRuntime: getWeComRuntime } = createPluginRuntimeStore("WeCom runtime not initialized");
|
|
3
|
+
export { setWeComRuntime, getWeComRuntime };
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
* 解决全局 Map 的内存泄漏问题
|
|
6
6
|
*/
|
|
7
7
|
import { createPersistentReqIdStore } from "./reqid-store.js";
|
|
8
|
-
import { MESSAGE_STATE_TTL_MS, MESSAGE_STATE_CLEANUP_INTERVAL_MS, MESSAGE_STATE_MAX_SIZE, } from "./const.js";
|
|
8
|
+
import { MESSAGE_STATE_TTL_MS, MESSAGE_STATE_CLEANUP_INTERVAL_MS, MESSAGE_STATE_MAX_SIZE, GLOBAL_WS_CLIENT_KEY, } from "./const.js";
|
|
9
9
|
// ============================================================================
|
|
10
10
|
// WSClient 实例管理
|
|
11
11
|
// ============================================================================
|
|
12
12
|
/** WSClient 实例管理 */
|
|
13
|
-
const wsClientInstances =
|
|
13
|
+
const wsClientInstances = (globalThis[GLOBAL_WS_CLIENT_KEY]
|
|
14
|
+
?? (globalThis[GLOBAL_WS_CLIENT_KEY] = new Map()));
|
|
14
15
|
/**
|
|
15
16
|
* 获取指定账户的 WSClient 实例
|
|
16
17
|
*/
|