"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.ensureDynamicAgentListed = ensureDynamicAgentListed;exports.generateAgentId = generateAgentId;exports.getDynamicAgentConfig = getDynamicAgentConfig;exports.resetEnsuredCache = resetEnsuredCache;exports.shouldUseDynamicAgent = shouldUseDynamicAgent; /** * **动态 Agent 路由模块** * * 为每个用户/群组自动生成独立的 Agent ID,实现会话隔离。 * 参考: openclaw-plugin-wecom/dynamic-agent.js */ /** * **getDynamicAgentConfig (读取动态 Agent 配置)** * * 从全局配置中读取动态 Agent 配置,提供默认值。 */ function getDynamicAgentConfig(config) { const dynamicAgents = config?.channels?.wecom?.dynamicAgents; return { enabled: dynamicAgents?.enabled ?? false, dmCreateAgent: dynamicAgents?.dmCreateAgent ?? true, groupEnabled: dynamicAgents?.groupEnabled ?? true, adminUsers: dynamicAgents?.adminUsers ?? [] }; } function sanitizeDynamicIdPart(value) { return String(value). trim(). toLowerCase(). replace(/[^a-z0-9_-]/g, "_"); } /** * **generateAgentId (生成动态 Agent ID)** * * 根据账号 + 聊天类型 + 对端 ID 生成确定性的 Agent ID,避免多账号串会话。 * 格式: wecom-{accountId}-{type}-{sanitizedPeerId} */ function generateAgentId(chatType, peerId, accountId) { const sanitizedPeer = sanitizeDynamicIdPart(peerId) || "unknown"; const sanitizedAccountId = sanitizeDynamicIdPart(accountId ?? "default") || "default"; return `wecom-${sanitizedAccountId}-${chatType}-${sanitizedPeer}`; } /** * **shouldUseDynamicAgent (检查是否使用动态 Agent)** * * 根据配置和发送者信息判断是否应使用动态 Agent。 * 管理员(adminUsers)始终绕过动态路由,使用主 Agent。 */ function shouldUseDynamicAgent(params) { const { chatType, senderId, config } = params; const dynamicConfig = getDynamicAgentConfig(config); if (!dynamicConfig.enabled) { return false; } // 管理员绕过动态路由 const sender = String(senderId).trim().toLowerCase(); const isAdmin = dynamicConfig.adminUsers.some( (admin) => admin.trim().toLowerCase() === sender ); if (isAdmin) { return false; } if (chatType === "group") { return dynamicConfig.groupEnabled; } return dynamicConfig.dmCreateAgent; } /** * 内存中已确保的 Agent ID(避免重复写入) */ const ensuredDynamicAgentIds = new Set(); /** * 写入队列(避免并发冲突) */ let ensureDynamicAgentWriteQueue = Promise.resolve(); /** * 将 Agent ID 插入 agents.list(如果不存在) */ function upsertAgentIdOnlyEntry(cfg, agentId) { if (!cfg.agents || typeof cfg.agents !== "object") { cfg.agents = {}; } const agentsObj = cfg.agents; const currentList = Array.isArray(agentsObj.list) ? agentsObj.list : []; const existingIds = new Set( currentList. map((entry) => entry?.id?.trim().toLowerCase()). filter((id) => Boolean(id)) ); let changed = false; const nextList = [...currentList]; // 首次创建时保留 main 作为默认 if (nextList.length === 0) { nextList.push({ id: "main" }); existingIds.add("main"); changed = true; } if (!existingIds.has(agentId.toLowerCase())) { nextList.push({ id: agentId }); changed = true; } if (changed) { agentsObj.list = nextList; } return changed; } /** * **ensureDynamicAgentListed (确保动态 Agent 已添加到 agents.list)** * * 将动态生成的 Agent ID 添加到 OpenClaw 配置中的 agents.list。 * 特性: * - 幂等:使用内存 Set 避免重复写入 * - 串行:使用 Promise 队列避免并发冲突 * - 异步:不阻塞消息处理流程 */ // eslint-disable-next-line @typescript-eslint/no-explicit-any async function ensureDynamicAgentListed(agentId, runtime) { const normalizedId = String(agentId).trim().toLowerCase(); if (!normalizedId) return; if (ensuredDynamicAgentIds.has(normalizedId)) return; const configRuntime = runtime?.config; if (!configRuntime?.loadConfig || !configRuntime?.writeConfigFile) return; ensureDynamicAgentWriteQueue = ensureDynamicAgentWriteQueue. then(async () => { if (ensuredDynamicAgentIds.has(normalizedId)) return; const latestConfig = configRuntime.loadConfig(); if (!latestConfig || typeof latestConfig !== "object") return; const changed = upsertAgentIdOnlyEntry(latestConfig, normalizedId); if (changed) { await configRuntime.writeConfigFile(latestConfig); } ensuredDynamicAgentIds.add(normalizedId); }). catch((err) => { console.warn(`[wecom] 动态 Agent 添加失败: ${normalizedId}`, err); }); await ensureDynamicAgentWriteQueue; } /** * **resetEnsuredCache (重置已确保缓存)** * * 主要用于测试场景,重置内存中的缓存状态。 */ function resetEnsuredCache() { ensuredDynamicAgentIds.clear(); } /* v9-3b4c502a9d666743 */