@sumeai/sumeclaw 1.1.19 → 1.2.0
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/channel-CAf407pr.d.ts +7 -0
- package/dist/chunk-RIUKFLMY.js +746 -0
- package/dist/chunk-RIUKFLMY.js.map +1 -0
- package/dist/index.d.ts +14 -3
- package/dist/index.js +83 -66
- package/dist/index.js.map +1 -1
- package/dist/setup-entry.d.ts +8 -3
- package/dist/setup-entry.js +10 -11
- package/dist/setup-entry.js.map +1 -1
- package/openclaw.plugin.json +101 -10
- package/package.json +37 -28
- package/readme.md +61 -0
- package/dist/index.d.ts.map +0 -1
- package/dist/setup-entry.d.ts.map +0 -1
- package/dist/src/channel.d.ts +0 -7
- package/dist/src/channel.d.ts.map +0 -1
- package/dist/src/channel.js +0 -162
- package/dist/src/channel.js.map +0 -1
- package/dist/src/gateway.d.ts +0 -46
- package/dist/src/gateway.d.ts.map +0 -1
- package/dist/src/gateway.js +0 -621
- package/dist/src/gateway.js.map +0 -1
- package/dist/src/runtime.d.ts +0 -3
- package/dist/src/runtime.d.ts.map +0 -1
- package/dist/src/runtime.js +0 -12
- package/dist/src/runtime.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime.ts","../src/gateway.ts","../src/channel.ts"],"sourcesContent":["let runtimeRef: any = null;\n\nexport function setSumeclawRuntime(runtime: any) {\n runtimeRef = runtime;\n}\n\nexport function tryGetSumeclawRuntime() {\n return runtimeRef;\n}\n","\n/**\n * 友虾名片 OpenClaw Channel 插件 — Gateway 层\n *\n * WebSocket 连接管理:\n * - 出站连接到 wss://api.gixin.cc/api/channel/{botToken}\n * - 心跳保活(30s 间隔)\n * - 断线自动重连(指数退避,最大 60s)\n * - 平台下发的消息注入 OpenClaw Agent\n * - Agent 回复通过 WS 推回平台\n */\n\nimport WebSocket from \"ws\";\nimport { dispatchInboundDirectDmWithRuntime } from \"openclaw/plugin-sdk/direct-dm\";\nimport { tryGetSumeclawRuntime } from \"./runtime.js\";\n\n/**\n * 全局 WS 管理\n */\nconst wsMap: Record<string, WebSocket> = {};\n\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { readFileSync } from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join } from \"path\";\n\n// const __filename = fileURLToPath(import.meta.url);\n// const __dirname = dirname(__filename);\n// const pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"..\", \"package.json\"), \"utf-8\"));\n\n// ─── 配置常量 ────────────────────────────────────────────────────────────────\n\nconst DEFAULT_PLATFORM_URL = \"wss://api.gixin.cc\";\nconst HEARTBEAT_MS = 30_000;\nconst MAX_RECONNECT_MS = 60_000;\nconst BASE_BACKOFF_MS = 1_000;\n\n// ─── 连接池 ──────────────────────────────────────────────────────────────────\n\n/** key: accountId → WebSocket */\nconst connections = new Map<string, WebSocket>();\nconst connectingAccounts = new Set<string>();\nconst pendingReplyContexts = new Map<\n string,\n {\n requestId?: string;\n sessionKey: string;\n stream?: boolean;\n accumulatedText: string;\n }\n>();\n\nfunction replyContextKey(accountId: string, userId: string): string {\n return `${accountId}:${userId}`;\n}\n\nexport function getWebSocket(accountId: string): WebSocket | undefined {\n return connections.get(accountId);\n}\n\nexport function rememberPendingReplyContext(params: {\n accountId: string;\n userId: string;\n requestId?: string;\n sessionKey: string;\n stream?: boolean;\n}) {\n const key = replyContextKey(params.accountId, params.userId);\n pendingReplyContexts.set(replyContextKey(params.accountId, params.userId), {\n requestId: params.requestId,\n sessionKey: params.sessionKey,\n stream: params.stream,\n accumulatedText: \"\",\n });\n}\n\nexport function getPendingReplyContext(accountId: string, userId: string) {\n return pendingReplyContexts.get(replyContextKey(accountId, userId));\n}\n\nexport function consumePendingReplyContext(accountId: string, userId: string) {\n const key = replyContextKey(accountId, userId);\n const ctx = pendingReplyContexts.get(key);\n pendingReplyContexts.delete(key);\n return ctx;\n}\n\nexport function appendPendingReplyText(accountId: string, userId: string, text: string) {\n const ctx = getPendingReplyContext(accountId, userId);\n if (!ctx) return \"\";\n\n if (!ctx.accumulatedText) {\n ctx.accumulatedText = text;\n } else if (text.startsWith(ctx.accumulatedText)) {\n ctx.accumulatedText = text;\n } else if (!ctx.accumulatedText.endsWith(text)) {\n ctx.accumulatedText += text;\n }\n\n return ctx.accumulatedText;\n}\n\n// ─── 连接逻辑 ────────────────────────────────────────────────────────────────\n\nexport interface MinicardAccount {\n botToken?: string;\n platformUrl?: string;\n enabled?: boolean;\n}\n\n\n\n\ntype ConnectOptions = {\n accountId: string;\n platformUrl?: string;\n botToken: string;\n defaultAgentId?: string;\n api: any;\n};\n\nexport function connectGateway(opts: ConnectOptions) {\n const { accountId, botToken, api } = opts;\n const platformUrl = opts.platformUrl || DEFAULT_PLATFORM_URL;\n const defaultAgentId = opts.defaultAgentId || \"main\";\n\n const existing = connections.get(accountId);\n if (\n existing &&\n (existing.readyState === WebSocket.OPEN ||\n existing.readyState === WebSocket.CONNECTING)\n ) {\n console.log(`[sumeclaw] ♻️ reuse existing connection: ${accountId}`);\n return;\n }\n\n if (connectingAccounts.has(accountId)) {\n console.log(`[sumeclaw] ♻️ connection already starting: ${accountId}`);\n return;\n }\n\n let ws: WebSocket | null = null;\n let heartbeatTimer: NodeJS.Timeout | null = null;\n let reconnectTimer: NodeJS.Timeout | null = null;\n\n const HEARTBEAT_INTERVAL = 30_000;\n const RECONNECT_DELAY = 5_000;\n\n function start() {\n \n const url = `${platformUrl.replace(/\\/$/, \"\")}/api/channel/${botToken}`;\n console.log(`[sumeclaw] 🌐 connecting -> ${url} (${accountId})`);\n\n connectingAccounts.add(accountId);\n ws = new WebSocket(url);\n connections.set(accountId, ws);\n \n\n ws.on(\"open\", () => {\n console.log(`[sumeclaw] ✅ connected: ${accountId}`);\n connectingAccounts.delete(accountId);\n connections.set(accountId, ws as WebSocket);\n\n // 🔐 上报本地插件/Agent 信息。平台端会据此刷新在线状态。\n ws?.send(\n JSON.stringify({\n type: \"register_info\",\n token: botToken,\n agentId: defaultAgentId,\n version: \"1.2.0\",\n })\n );\n\n // ❤️ 心跳\n heartbeatTimer = setInterval(() => {\n if (ws?.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"heartbeat\" }));\n }\n }, HEARTBEAT_INTERVAL);\n });\n\n ws.on(\"message\", (data) => {\n try {\n const msg = JSON.parse(data.toString());\n\n // 🔍 调试\n console.log(\"[sumeclaw] 📩 message:\", msg);\n\n handleMessage(msg).catch((err) => {\n console.error(\"[sumeclaw] ❌ handle message error\", err);\n });\n } catch (err) {\n console.error(\"[sumeclaw] ❌ parse message error\", err);\n }\n });\n\n ws.on(\"close\", (code, reasonBuffer) => {\n const reason = reasonBuffer.toString();\n console.warn(`[sumeclaw] ⚠️ disconnected: ${accountId}`, { code, reason });\n cleanup();\n if (code === 4000 || reason.includes(\"replaced by a newer OpenClaw plugin connection\")) {\n console.warn(`[sumeclaw] 🛑 connection replaced, stop reconnecting: ${accountId}`);\n return;\n }\n scheduleReconnect();\n });\n\n ws.on(\"error\", (err) => {\n console.error(`[sumeclaw] ❌ ws error: ${accountId}`, err);\n connectingAccounts.delete(accountId);\n ws?.close();\n });\n }\n\n async function handleMessage(msg: any) {\n switch (msg.type) {\n case \"heartbeat_ack\":\n // 心跳回应\n break;\n\n case \"hooks_agent\":\n await handleHooksAgent(msg.payload ?? msg);\n break;\n\n case \"message\":\n // 👉 这里接入 OpenClaw\n console.log(\"[sumeclaw] 💬 收到消息:\", msg);\n\n await dispatchToOpenClaw({\n agentId: msg.agentId || \"main\",\n message: msg.text || msg.message || \"\",\n messageId: msg.id || msg.messageId,\n sessionKey:\n msg.sessionKey ||\n `agent:${msg.agentId || \"main\"}:user:${msg.from || msg.userId || \"unknown\"}`,\n userId: msg.from || msg.userId || msg.senderId || \"unknown\",\n raw: msg,\n requestId: msg.requestId,\n stream: Boolean(msg.stream),\n });\n\n break;\n\n case \"registered\":\n console.log(`[sumeclaw] 🔐 注册成功: ${accountId}`);\n break;\n\n default:\n console.log(\"[sumeclaw] ❓ 未处理消息:\", msg);\n }\n }\n\n async function handleHooksAgent(payload: any) {\n const meta = payload?.meta ?? {};\n const userId = String(meta.user_id || payload.userId || payload.from || \"unknown\");\n const agentId = String(payload.agentId || meta.agent_id || \"main\");\n const text = String(payload.message || payload.text || \"\");\n const sessionKey =\n payload.sessionKey || `agent:${agentId}:user:${userId}`;\n\n console.log(\"[sumeclaw] 🧠 hooks_agent -> OpenClaw\", {\n accountId,\n agentId,\n sessionKey,\n userId,\n text: text.slice(0, 100),\n });\n\n rememberPendingReplyContext({\n accountId,\n userId,\n requestId: payload.requestId,\n sessionKey,\n stream: Boolean(payload.stream),\n });\n\n await dispatchToOpenClaw({\n agentId,\n message: text,\n messageId: payload.messageId || `${sessionKey}:${Date.now()}`,\n sessionKey,\n userId,\n raw: payload,\n requestId: payload.requestId,\n stream: Boolean(payload.stream),\n });\n }\n\n function sendAgentReply(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n text: string;\n ok?: boolean;\n messageId?: string;\n }) {\n const activeWs = connections.get(accountId) ?? ws;\n if (!activeWs || activeWs.readyState !== WebSocket.OPEN) {\n console.error(\"[sumeclaw] ❌ cannot send agent_reply, websocket is not open\", {\n accountId,\n requestId: input.requestId,\n readyState: activeWs?.readyState,\n });\n return false;\n }\n\n activeWs.send(\n JSON.stringify({\n type: \"agent_reply\",\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: input.text,\n messageId: input.messageId ?? `sumeclaw-${Date.now()}`,\n ok: input.ok ?? true,\n }),\n );\n console.log(\"[sumeclaw] 📤 agent_reply sent\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n textLength: input.text.length,\n });\n return true;\n }\n\n function sendAgentDelta(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n text: string;\n messageId?: string;\n }) {\n const activeWs = connections.get(accountId) ?? ws;\n if (!activeWs || activeWs.readyState !== WebSocket.OPEN) {\n console.error(\"[sumeclaw] ❌ cannot send agent_delta, websocket is not open\", {\n accountId,\n requestId: input.requestId,\n readyState: activeWs?.readyState,\n });\n return false;\n }\n\n activeWs.send(\n JSON.stringify({\n type: \"agent_delta\",\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: input.text,\n messageId: input.messageId ?? `sumeclaw-${Date.now()}`,\n }),\n );\n console.log(\"[sumeclaw] 📤 agent_delta sent\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n textLength: input.text.length,\n });\n return true;\n }\n\n function sendAgentDone(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n text: string;\n ok?: boolean;\n messageId?: string;\n }) {\n const activeWs = connections.get(accountId) ?? ws;\n if (!activeWs || activeWs.readyState !== WebSocket.OPEN) {\n console.error(\"[sumeclaw] ❌ cannot send agent_done, websocket is not open\", {\n accountId,\n requestId: input.requestId,\n readyState: activeWs?.readyState,\n });\n return false;\n }\n\n activeWs.send(\n JSON.stringify({\n type: \"agent_done\",\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: input.text,\n messageId: input.messageId ?? `sumeclaw-${Date.now()}`,\n ok: input.ok ?? true,\n }),\n );\n console.log(\"[sumeclaw] 📤 agent_done sent\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n textLength: input.text.length,\n });\n return true;\n }\n\n function finishStreamReply(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n ok?: boolean;\n }) {\n const latest = consumePendingReplyContext(accountId, input.userId);\n if (!latest) {\n console.warn(\"[sumeclaw] ⚠️ no pending stream context to finish\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n });\n return false;\n }\n\n return sendAgentDone({\n requestId: latest.requestId ?? input.requestId,\n userId: input.userId,\n sessionKey: latest.sessionKey ?? input.sessionKey,\n text: latest.accumulatedText,\n ok: input.ok,\n });\n }\n\n function finishBufferedReply(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n ok?: boolean;\n }) {\n const latest = consumePendingReplyContext(accountId, input.userId);\n if (!latest) {\n console.warn(\"[sumeclaw] ⚠️ no pending reply context to finish\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n });\n return false;\n }\n\n return sendAgentReply({\n requestId: latest.requestId ?? input.requestId,\n userId: input.userId,\n sessionKey: latest.sessionKey ?? input.sessionKey,\n text: latest.accumulatedText,\n ok: input.ok,\n });\n }\n\n async function dispatchToOpenClaw(input: {\n agentId: string;\n message: string;\n messageId?: string;\n sessionKey: string;\n userId: string;\n raw: any;\n requestId?: string;\n stream?: boolean;\n }) {\n const runtime = tryGetSumeclawRuntime() ?? api?.runtime;\n const turn = runtime?.channel?.turn;\n\n if (!turn?.run) {\n const directReplyDispatcher = runtime?.channel?.reply?.dispatchReplyWithBufferedBlockDispatcher;\n if (directReplyDispatcher) {\n await dispatchViaDirectDmRuntime(runtime, input);\n return;\n }\n\n console.error(\n \"[sumeclaw] ❌ 当前 OpenClaw runtime 不提供可用的 channel 入站分发能力\",\n );\n console.error(\"[sumeclaw] runtime debug:\", {\n hasStoredRuntime: Boolean(tryGetSumeclawRuntime()),\n apiKeys: api ? Object.keys(api) : [],\n runtimeKeys: runtime ? Object.keys(runtime) : [],\n channelKeys: runtime?.channel ? Object.keys(runtime.channel) : [],\n });\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw 插件未获得运行时分发能力,请升级插件入口后重启 OpenClaw Gateway。\",\n ok: false,\n });\n return;\n }\n\n const now = Date.now();\n const messageId = String(input.messageId || `${input.sessionKey}:${now}`);\n const senderLabel = `友虾用户 ${input.userId}`;\n\n try {\n const result = await turn.run({\n channel: \"sumeclaw\",\n accountId,\n raw: input.raw,\n adapter: {\n ingest() {\n return {\n id: messageId,\n timestamp: now,\n rawText: input.message,\n textForAgent: input.message,\n textForCommands: input.message,\n raw: input.raw,\n };\n },\n classify(turnInput: any) {\n return {\n kind: \"message\",\n canStartAgentTurn: Boolean(turnInput.rawText),\n };\n },\n resolveTurn(turnInput: any) {\n return {\n sender: {\n id: input.userId,\n name: senderLabel,\n displayLabel: senderLabel,\n isBot: false,\n isSelf: false,\n },\n conversation: {\n kind: \"direct\",\n id: input.userId,\n label: senderLabel,\n routePeer: input.userId,\n },\n route: {\n agentId: input.agentId,\n accountId,\n routeSessionKey: input.sessionKey,\n dispatchSessionKey: input.sessionKey,\n persistedSessionKey: input.sessionKey,\n mainSessionKey: input.sessionKey,\n createIfMissing: true,\n },\n reply: {\n to: input.userId,\n originatingTo: input.userId,\n replyTarget: input.userId,\n sourceReplyDeliveryMode: \"direct\",\n },\n access: {\n dm: {\n policy: \"open\",\n allowed: true,\n allowFrom: [],\n },\n group: {\n isGroup: false,\n routeAllowed: true,\n senderAllowed: true,\n requireMention: false,\n },\n commands: {\n authorized: true,\n },\n mentions: {\n canDetectMention: false,\n wasMentioned: true,\n },\n },\n message: {\n body: turnInput.rawText,\n rawBody: turnInput.rawText,\n bodyForAgent: turnInput.textForAgent,\n commandBody: turnInput.textForCommands,\n envelopeFrom: senderLabel,\n senderLabel,\n preview: turnInput.rawText.slice(0, 120),\n },\n delivery: {\n deliver: async (payload: any) => {\n const text = String(payload?.text || payload?.body || \"\");\n if (!text) return { visibleReplySent: false };\n const replyId = `sumeclaw-${Date.now()}`;\n if (input.stream) {\n appendPendingReplyText(accountId, input.userId, text);\n sendAgentDelta({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text,\n messageId: replyId,\n });\n } else {\n appendPendingReplyText(accountId, input.userId, text);\n }\n return {\n messageIds: [replyId],\n visibleReplySent: true,\n };\n },\n onError(err: unknown) {\n console.error(\"[sumeclaw] ❌ deliver error\", err);\n },\n },\n };\n },\n },\n });\n\n console.log(\"[sumeclaw] ✅ OpenClaw turn dispatched\", result?.admission ?? \"\");\n if (input.stream) {\n finishStreamReply(input);\n } else {\n finishBufferedReply(input);\n }\n } catch (err) {\n console.error(\"[sumeclaw] ❌ OpenClaw turn dispatch failed\", err);\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw 本地处理消息失败,请稍后再试。\",\n ok: false,\n });\n }\n }\n\n async function dispatchViaDirectDmRuntime(runtime: any, input: {\n agentId: string;\n message: string;\n messageId?: string;\n sessionKey: string;\n userId: string;\n raw: any;\n requestId?: string;\n stream?: boolean;\n }) {\n const now = Date.now();\n const messageId = String(input.messageId || `${input.sessionKey}:${now}`);\n const senderLabel = `友虾用户 ${input.userId}`;\n const baseCfg = api?.getConfig?.() ?? api?.config ?? runtime?.config ?? {};\n const cfg = input.stream\n ? {\n ...baseCfg,\n agents: {\n ...(baseCfg.agents ?? {}),\n defaults: {\n ...(baseCfg.agents?.defaults ?? {}),\n blockStreamingDefault: \"on\",\n blockStreamingBreak: \"text_end\",\n blockStreamingChunk: {\n minChars: 12,\n maxChars: 80,\n breakPreference: \"sentence\",\n ...(baseCfg.agents?.defaults?.blockStreamingChunk ?? {}),\n },\n },\n },\n channels: {\n ...(baseCfg.channels ?? {}),\n sumeclaw: {\n ...(baseCfg.channels?.sumeclaw ?? {}),\n blockStreaming: true,\n },\n },\n }\n : baseCfg;\n\n try {\n await dispatchInboundDirectDmWithRuntime({\n cfg,\n runtime,\n channel: \"sumeclaw\",\n channelLabel: \"友虾名片\",\n accountId,\n peer: {\n kind: \"direct\",\n id: input.userId,\n },\n senderId: input.userId,\n senderAddress: input.userId,\n recipientAddress: \"sumeclaw\",\n conversationLabel: senderLabel,\n rawBody: input.message,\n messageId,\n timestamp: now,\n bodyForAgent: input.message,\n commandBody: input.message,\n commandAuthorized: true,\n provider: \"sumeclaw\",\n surface: \"sumeclaw\",\n originatingChannel: \"sumeclaw\",\n originatingTo: input.userId,\n extraContext: {\n AccountId: accountId,\n RouteAgentId: input.agentId,\n RequestId: input.requestId,\n },\n deliver: async (payload: any) => {\n const text = String(payload?.text || payload?.body || \"\");\n if (!text) return { visibleReplySent: false };\n\n const replyId = `sumeclaw-${Date.now()}`;\n if (input.stream) {\n appendPendingReplyText(accountId, input.userId, text);\n sendAgentDelta({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text,\n messageId: replyId,\n });\n } else {\n appendPendingReplyText(accountId, input.userId, text);\n }\n\n return {\n messageIds: [replyId],\n visibleReplySent: true,\n };\n },\n onDispatchError: (err: unknown) => {\n console.error(\"[sumeclaw] ❌ Direct DM dispatch error\", err);\n },\n onRecordError: (err: unknown) => {\n console.error(\"[sumeclaw] ❌ Direct DM record error\", err);\n },\n });\n\n console.log(\"[sumeclaw] ✅ OpenClaw Direct DM dispatched\");\n if (input.stream) {\n finishStreamReply(input);\n } else {\n finishBufferedReply(input);\n }\n } catch (err) {\n console.error(\"[sumeclaw] ❌ Direct DM dispatch failed\", err);\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw 本地处理消息失败,请稍后再试。\",\n ok: false,\n });\n }\n }\n\n function cleanup() {\n connectingAccounts.delete(accountId);\n if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = null;\n }\n if (connections.get(accountId) === ws) {\n connections.delete(accountId);\n }\n }\n\n function scheduleReconnect() {\n if (reconnectTimer) return;\n\n console.log(`[sumeclaw] 🔁 reconnecting in ${RECONNECT_DELAY / 1000}s`);\n\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n start();\n }, RECONNECT_DELAY);\n }\n\n start();\n}\n","// @ts-nocheck\n/**\n * 友虾名片 ChannelPlugin 核心定义\n *\n * 基于新版 plugin-sdk(2026.3.22+)的 createChatChannelPlugin API。\n */\nimport {\n createChatChannelPlugin,\n createChannelPluginBase,\n} from \"openclaw/plugin-sdk/channel-core\";\nimport type { ChannelSetupWizard } from \"openclaw/plugin-sdk/channel-setup\";\nimport {\n appendPendingReplyText,\n consumePendingReplyContext,\n getPendingReplyContext,\n getWebSocket,\n} from \"./gateway.js\";\n\nexport interface SumelawAccount {\n botToken?: string;\n platformUrl?: string;\n enabled?: boolean;\n}\n\n/**\n * 安装/配置向导 — 交互式提示用户输入 botToken\n */\nconst channelKey = \"sumeclaw\";\n\nconst channelConfigAdapter = {\n listAccountIds(cfg: any) {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return Object.keys(accounts);\n },\n\n resolveAccount(cfg: any, accountId?: string) {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return (accounts[accountId ?? \"default\"] ?? {}) as SumelawAccount;\n },\n};\n\nconst setupWizard: ChannelSetupWizard = {\n channel: channelKey,\n\n /** 根据当前配置显示连接状态 */\n status: {\n configuredLabel: \"已连接友虾名片\",\n unconfiguredLabel: \"尚未配置\",\n resolveConfigured: ({ cfg }) => {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return Object.values(accounts).some((acct: any) => acct?.botToken);\n },\n },\n\n /** 交互式凭据收集 — 引导用户输入 botToken */\n credentials: [\n {\n inputKey: \"botToken\",\n credentialLabel: \"友虾连接码\",\n preferredEnvVar: \"SUMECLAW_BOT_TOKEN\",\n envPrompt: \"是否使用环境变量 SUMECLAW_BOT_TOKEN?\",\n keepPrompt: \"保留当前 botToken?\",\n inputPrompt: \"请输入从友虾小程序获取的 botToken:\",\n inspect: ({ cfg, accountId }) => {\n const token = (cfg.channels as any)?.[channelKey]?.accounts?.[\n accountId ?? \"default\"\n ]?.botToken;\n return {\n accountConfigured: Boolean(token),\n hasConfiguredValue: Boolean(token),\n };\n },\n },\n ],\n};\n\nexport const sumeclawPlugin = createChatChannelPlugin<SumelawAccount>({\n base: createChannelPluginBase({\n id: channelKey,\n setupWizard,\n setup: {\n /**\n * 从用户配置中解析账户信息\n */\n resolveAccount(cfg, accountId) {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return (accounts[accountId ?? \"default\"] ?? {}) as SumelawAccount;\n },\n\n /**\n * 检查账户配置状态\n */\n inspectAccount(cfg, accountId) {\n const account = (cfg.channels as any)?.[channelKey]?.accounts?.[\n accountId ?? \"default\"\n ];\n return {\n enabled: !!account?.botToken,\n configured: !!account?.botToken,\n };\n },\n },\n }),\n\n /**\n * 渠道配置适配器 (ChannelConfigAdapter)\n */\n config: channelConfigAdapter,\n\n /**\n * DM 安全策略\n *\n * 友虾名片场景下,所有通过名片访问的用户都允许对话。\n * 名片主可在小程序端管理黑名单(后续扩展)。\n */\n security: {\n dm: {\n channelKey: \"sumeclaw\",\n resolvePolicy: () => \"open\",\n defaultPolicy: \"open\",\n },\n },\n\n /**\n * 出站消息处理\n *\n * 当 OpenClaw Agent 生成回复后,通过 WebSocket 推回友虾名片平台。\n */\n outbound: {\n attachedResults: {\n sendText: async ({ text, to, accountId }) => {\n const resolvedAccountId = accountId ?? \"default\";\n const ws = getWebSocket(resolvedAccountId);\n if (!ws || ws.readyState !== 1) {\n throw new Error(\"WebSocket 未连接到友虾名片平台\");\n }\n\n const pending = getPendingReplyContext(resolvedAccountId, to);\n const messageId = `sumeclaw-${Date.now()}`;\n if (pending?.stream) {\n appendPendingReplyText(resolvedAccountId, to, text);\n ws.send(\n JSON.stringify({\n type: \"agent_delta\",\n requestId: pending.requestId,\n userId: to,\n sessionKey: pending.sessionKey,\n text,\n messageId,\n }),\n );\n console.log(\"[sumeclaw] 📤 outbound agent_delta sent\", {\n accountId: resolvedAccountId,\n requestId: pending.requestId,\n userId: to,\n textLength: text.length,\n });\n return { messageId };\n }\n\n if (pending && !pending.stream) {\n appendPendingReplyText(resolvedAccountId, to, text);\n console.log(\"[sumeclaw] 📥 outbound reply buffered\", {\n accountId: resolvedAccountId,\n requestId: pending.requestId,\n userId: to,\n textLength: text.length,\n });\n return { messageId };\n }\n\n const finalPending = consumePendingReplyContext(resolvedAccountId, to);\n ws.send(\n JSON.stringify({\n type: \"agent_reply\",\n requestId: finalPending?.requestId,\n userId: to,\n sessionKey: finalPending?.sessionKey,\n text,\n messageId,\n }),\n );\n console.log(\"[sumeclaw] 📤 outbound agent_reply sent\", {\n accountId: resolvedAccountId,\n requestId: finalPending?.requestId,\n userId: to,\n textLength: text.length,\n });\n\n return { messageId };\n },\n },\n },\n});\n\n// Some OpenClaw gateway health paths read plugin.config directly after the\n// SDK wrapper is created. Keep this explicit for compatibility across builds.\n(sumeclawPlugin as any).config ??= channelConfigAdapter;\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
import { S as SumelawAccount } from './channel-CAf407pr.js';
|
|
2
|
+
import * as openclaw_plugin_sdk from 'openclaw/plugin-sdk';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* @sumeai/sumeclaw — OpenClaw Channel 插件入口
|
|
3
6
|
*/
|
|
4
|
-
declare const entry:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
declare const entry: {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
configSchema: openclaw_plugin_sdk.ChannelConfigSchema;
|
|
12
|
+
register: (api: openclaw_plugin_sdk.OpenClawPluginApi) => void;
|
|
13
|
+
channelPlugin: openclaw_plugin_sdk.ChannelPlugin<SumelawAccount, unknown, unknown>;
|
|
14
|
+
setChannelRuntime?: (runtime: openclaw_plugin_sdk.PluginRuntime) => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export { entry as default };
|
package/dist/index.js
CHANGED
|
@@ -1,77 +1,94 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const runtime_js_1 = require("./src/runtime.js");
|
|
1
|
+
import {
|
|
2
|
+
connectGateway,
|
|
3
|
+
setSumeclawRuntime,
|
|
4
|
+
sumeclawPlugin
|
|
5
|
+
} from "./chunk-RIUKFLMY.js";
|
|
6
|
+
|
|
7
|
+
// index.ts
|
|
8
|
+
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";
|
|
10
9
|
function isPluginManagementCommand() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
].includes(subcommand);
|
|
10
|
+
const argv = process.argv.slice(2);
|
|
11
|
+
const pluginIndex = argv.findIndex((arg) => arg === "plugin" || arg === "plugins");
|
|
12
|
+
if (pluginIndex === -1) return false;
|
|
13
|
+
const subcommand = argv[pluginIndex + 1];
|
|
14
|
+
return [
|
|
15
|
+
"add",
|
|
16
|
+
"disable",
|
|
17
|
+
"enable",
|
|
18
|
+
"install",
|
|
19
|
+
"list",
|
|
20
|
+
"remove",
|
|
21
|
+
"uninstall",
|
|
22
|
+
"update"
|
|
23
|
+
].includes(subcommand);
|
|
26
24
|
}
|
|
27
25
|
function resolveAccounts(api) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
const cfg = api.getConfig?.() ?? api.config ?? {};
|
|
27
|
+
const channelConfig = cfg?.channels?.sumeclaw ?? {};
|
|
28
|
+
if (channelConfig.accounts && Object.keys(channelConfig.accounts).length > 0) {
|
|
29
|
+
return channelConfig.accounts;
|
|
30
|
+
}
|
|
31
|
+
if (channelConfig.botToken || channelConfig.token) {
|
|
32
|
+
return {
|
|
33
|
+
default: {
|
|
34
|
+
botToken: channelConfig.botToken ?? channelConfig.token,
|
|
35
|
+
platformUrl: channelConfig.platformUrl ?? channelConfig.wsUrl,
|
|
36
|
+
enabled: channelConfig.enabled,
|
|
37
|
+
defaultAgentId: channelConfig.defaultAgentId
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {};
|
|
32
42
|
}
|
|
33
43
|
function startGatewayConnections(api) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
console.log("[sumeclaw] \u{1F680} registerFull() called");
|
|
45
|
+
if (isPluginManagementCommand()) {
|
|
46
|
+
console.log("[sumeclaw] \u{1F4A4} plugin management command detected, skip gateway connection");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const accounts = resolveAccounts(api);
|
|
50
|
+
if (Object.keys(accounts).length === 0) {
|
|
51
|
+
console.warn("[sumeclaw] \u26A0\uFE0F \u6CA1\u6709\u914D\u7F6E accounts \u6216 botToken\uFF0C\u63D2\u4EF6\u7A7A\u8F6C");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
for (const [accountId, account] of Object.entries(accounts)) {
|
|
55
|
+
if (account?.enabled === false) {
|
|
56
|
+
console.log(`[sumeclaw] \u{1F4A4} account disabled: ${accountId}`);
|
|
57
|
+
continue;
|
|
38
58
|
}
|
|
39
|
-
const
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
const botToken = account?.botToken ?? account?.token;
|
|
60
|
+
if (!botToken) {
|
|
61
|
+
console.error(`[sumeclaw] \u274C account ${accountId} \u7F3A\u5C11 botToken`);
|
|
62
|
+
continue;
|
|
43
63
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
api,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
console.error("[sumeclaw] ❌ 连接失败:", err);
|
|
60
|
-
}
|
|
64
|
+
console.log(`[sumeclaw] \u{1F517} \u6B63\u5728\u8FDE\u63A5 account: ${accountId}`);
|
|
65
|
+
try {
|
|
66
|
+
connectGateway({
|
|
67
|
+
accountId,
|
|
68
|
+
platformUrl: account.platformUrl ?? account.wsUrl,
|
|
69
|
+
botToken,
|
|
70
|
+
defaultAgentId: account.defaultAgentId ?? account.agentId,
|
|
71
|
+
api
|
|
72
|
+
});
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.error("[sumeclaw] \u274C \u8FDE\u63A5\u5931\u8D25:", err);
|
|
61
75
|
}
|
|
76
|
+
}
|
|
62
77
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
var entry = defineChannelPluginEntry({
|
|
79
|
+
id: "sumeclaw",
|
|
80
|
+
name: "\u53CB\u867E\u540D\u7247",
|
|
81
|
+
description: "\u53CB\u867E\u540D\u7247 Channel",
|
|
82
|
+
plugin: sumeclawPlugin,
|
|
83
|
+
setRuntime(runtime) {
|
|
84
|
+
setSumeclawRuntime(runtime);
|
|
85
|
+
},
|
|
86
|
+
registerFull(api) {
|
|
87
|
+
startGatewayConnections(api);
|
|
88
|
+
}
|
|
74
89
|
});
|
|
75
|
-
|
|
76
|
-
|
|
90
|
+
var index_default = entry;
|
|
91
|
+
export {
|
|
92
|
+
index_default as default
|
|
93
|
+
};
|
|
77
94
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"sourcesContent":["/**\n * @sumeai/sumeclaw — OpenClaw Channel 插件入口\n */\n\nimport { defineChannelPluginEntry } from \"openclaw/plugin-sdk/channel-core\";\nimport { connectGateway } from \"./src/gateway.js\";\nimport { sumeclawPlugin } from \"./src/channel.js\";\nimport { setSumeclawRuntime } from \"./src/runtime.js\";\n\nfunction isPluginManagementCommand(): boolean {\n const argv = process.argv.slice(2);\n const pluginIndex = argv.findIndex((arg) => arg === \"plugin\" || arg === \"plugins\");\n if (pluginIndex === -1) return false;\n\n const subcommand = argv[pluginIndex + 1];\n return [\n \"add\",\n \"disable\",\n \"enable\",\n \"install\",\n \"list\",\n \"remove\",\n \"uninstall\",\n \"update\",\n ].includes(subcommand);\n}\n\nfunction resolveAccounts(api: any): Record<string, any> {\n const cfg = api.getConfig?.() ?? api.config ?? {};\n const channelConfig = cfg?.channels?.sumeclaw ?? {};\n\n if (channelConfig.accounts && Object.keys(channelConfig.accounts).length > 0) {\n return channelConfig.accounts;\n }\n\n if (channelConfig.botToken || channelConfig.token) {\n return {\n default: {\n botToken: channelConfig.botToken ?? channelConfig.token,\n platformUrl: channelConfig.platformUrl ?? channelConfig.wsUrl,\n enabled: channelConfig.enabled,\n defaultAgentId: channelConfig.defaultAgentId,\n },\n };\n }\n\n return {};\n}\n\nfunction startGatewayConnections(api: any) {\n console.log(\"[sumeclaw] 🚀 registerFull() called\");\n\n if (isPluginManagementCommand()) {\n console.log(\"[sumeclaw] 💤 plugin management command detected, skip gateway connection\");\n return;\n }\n\n const accounts = resolveAccounts(api);\n if (Object.keys(accounts).length === 0) {\n console.warn(\"[sumeclaw] ⚠️ 没有配置 accounts 或 botToken,插件空转\");\n return;\n }\n\n for (const [accountId, account] of Object.entries(accounts) as any) {\n if (account?.enabled === false) {\n console.log(`[sumeclaw] 💤 account disabled: ${accountId}`);\n continue;\n }\n\n const botToken = account?.botToken ?? account?.token;\n if (!botToken) {\n console.error(`[sumeclaw] ❌ account ${accountId} 缺少 botToken`);\n continue;\n }\n\n console.log(`[sumeclaw] 🔗 正在连接 account: ${accountId}`);\n\n try {\n connectGateway({\n accountId,\n platformUrl: account.platformUrl ?? account.wsUrl,\n botToken,\n defaultAgentId: account.defaultAgentId ?? account.agentId,\n api,\n });\n } catch (err) {\n console.error(\"[sumeclaw] ❌ 连接失败:\", err);\n }\n }\n}\n\nconst entry = defineChannelPluginEntry({\n id: \"sumeclaw\",\n name: \"友虾名片\",\n description: \"友虾名片 Channel\",\n plugin: sumeclawPlugin,\n setRuntime(runtime: any) {\n setSumeclawRuntime(runtime);\n },\n registerFull(api: any) {\n startGatewayConnections(api);\n },\n});\n\nexport default entry;\n"],"mappings":";;;;;;;AAIA,SAAS,gCAAgC;AAKzC,SAAS,4BAAqC;AAC5C,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,QAAM,cAAc,KAAK,UAAU,CAAC,QAAQ,QAAQ,YAAY,QAAQ,SAAS;AACjF,MAAI,gBAAgB,GAAI,QAAO;AAE/B,QAAM,aAAa,KAAK,cAAc,CAAC;AACvC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,SAAS,UAAU;AACvB;AAEA,SAAS,gBAAgB,KAA+B;AACtD,QAAM,MAAM,IAAI,YAAY,KAAK,IAAI,UAAU,CAAC;AAChD,QAAM,gBAAgB,KAAK,UAAU,YAAY,CAAC;AAElD,MAAI,cAAc,YAAY,OAAO,KAAK,cAAc,QAAQ,EAAE,SAAS,GAAG;AAC5E,WAAO,cAAc;AAAA,EACvB;AAEA,MAAI,cAAc,YAAY,cAAc,OAAO;AACjD,WAAO;AAAA,MACL,SAAS;AAAA,QACP,UAAU,cAAc,YAAY,cAAc;AAAA,QAClD,aAAa,cAAc,eAAe,cAAc;AAAA,QACxD,SAAS,cAAc;AAAA,QACvB,gBAAgB,cAAc;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,CAAC;AACV;AAEA,SAAS,wBAAwB,KAAU;AACzC,UAAQ,IAAI,4CAAqC;AAEjD,MAAI,0BAA0B,GAAG;AAC/B,YAAQ,IAAI,kFAA2E;AACvF;AAAA,EACF;AAEA,QAAM,WAAW,gBAAgB,GAAG;AACpC,MAAI,OAAO,KAAK,QAAQ,EAAE,WAAW,GAAG;AACtC,YAAQ,KAAK,yGAA6C;AAC1D;AAAA,EACF;AAEA,aAAW,CAAC,WAAW,OAAO,KAAK,OAAO,QAAQ,QAAQ,GAAU;AAClE,QAAI,SAAS,YAAY,OAAO;AAC9B,cAAQ,IAAI,0CAAmC,SAAS,EAAE;AAC1D;AAAA,IACF;AAEA,UAAM,WAAW,SAAS,YAAY,SAAS;AAC/C,QAAI,CAAC,UAAU;AACb,cAAQ,MAAM,6BAAwB,SAAS,wBAAc;AAC7D;AAAA,IACF;AAEA,YAAQ,IAAI,0DAA+B,SAAS,EAAE;AAEtD,QAAI;AACF,qBAAe;AAAA,QACb;AAAA,QACA,aAAa,QAAQ,eAAe,QAAQ;AAAA,QAC5C;AAAA,QACA,gBAAgB,QAAQ,kBAAkB,QAAQ;AAAA,QAClD;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,+CAAsB,GAAG;AAAA,IACzC;AAAA,EACF;AACF;AAEA,IAAM,QAAQ,yBAAyB;AAAA,EACrC,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,WAAW,SAAc;AACvB,uBAAmB,OAAO;AAAA,EAC5B;AAAA,EACA,aAAa,KAAU;AACrB,4BAAwB,GAAG;AAAA,EAC7B;AACF,CAAC;AAED,IAAO,gBAAQ;","names":[]}
|
package/dist/setup-entry.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import * as openclaw_plugin_sdk from 'openclaw/plugin-sdk';
|
|
2
|
+
import { S as SumelawAccount } from './channel-CAf407pr.js';
|
|
3
|
+
|
|
4
|
+
declare const _default: {
|
|
5
|
+
plugin: openclaw_plugin_sdk.ChannelPlugin<SumelawAccount, unknown, unknown>;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export { _default as default };
|
package/dist/setup-entry.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
exports.default = (0, channel_core_1.defineSetupPluginEntry)(channel_js_1.sumeclawPlugin);
|
|
1
|
+
import {
|
|
2
|
+
sumeclawPlugin
|
|
3
|
+
} from "./chunk-RIUKFLMY.js";
|
|
4
|
+
|
|
5
|
+
// setup-entry.ts
|
|
6
|
+
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";
|
|
7
|
+
var setup_entry_default = defineSetupPluginEntry(sumeclawPlugin);
|
|
8
|
+
export {
|
|
9
|
+
setup_entry_default as default
|
|
10
|
+
};
|
|
12
11
|
//# sourceMappingURL=setup-entry.js.map
|
package/dist/setup-entry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../setup-entry.ts"],"sourcesContent":["import { defineSetupPluginEntry } from \"openclaw/plugin-sdk/channel-core\";\nimport { sumeclawPlugin } from \"./src/channel.js\";\n\nexport default defineSetupPluginEntry(sumeclawPlugin);\n"],"mappings":";;;;;AAAA,SAAS,8BAA8B;AAGvC,IAAO,sBAAQ,uBAAuB,cAAc;","names":[]}
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://
|
|
2
|
+
"$schema": "https://openclaw.ai/schemas/openclaw.plugin.schema.json",
|
|
3
3
|
"id": "sumeclaw",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
4
|
+
"name": "友虾名片",
|
|
5
|
+
"description": "将 OpenClaw 连接到友虾名片平台,通过 AI 名片为客户提供服务。",
|
|
6
|
+
"activation": {
|
|
7
|
+
"onStartup": false,
|
|
8
|
+
"onChannels": [
|
|
9
|
+
"sumeclaw"
|
|
10
|
+
],
|
|
11
|
+
"onConfigPaths": [
|
|
12
|
+
"channels.sumeclaw"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"channels": [
|
|
16
|
+
"sumeclaw"
|
|
17
|
+
],
|
|
18
|
+
"channelEnvVars": {
|
|
19
|
+
"sumeclaw": [
|
|
20
|
+
"SUMECLAW_BOT_TOKEN"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
8
23
|
"configSchema": {
|
|
9
24
|
"type": "object",
|
|
10
|
-
"additionalProperties":
|
|
25
|
+
"additionalProperties": true,
|
|
11
26
|
"properties": {
|
|
12
|
-
"
|
|
27
|
+
"botToken": {
|
|
13
28
|
"type": "string",
|
|
14
|
-
"description": "
|
|
29
|
+
"description": "从友虾平台获取的连接码"
|
|
15
30
|
},
|
|
16
31
|
"platformUrl": {
|
|
17
32
|
"type": "string",
|
|
@@ -21,8 +36,84 @@
|
|
|
21
36
|
"type": "boolean",
|
|
22
37
|
"description": "是否启用此通道",
|
|
23
38
|
"default": true
|
|
39
|
+
},
|
|
40
|
+
"defaultAgentId": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "插件注册时上报的默认 OpenClaw 智能体 ID,实际对话以友虾后台 payload 中的 agentId 为准",
|
|
43
|
+
"default": "main"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"channelConfigs": {
|
|
48
|
+
"sumeclaw": {
|
|
49
|
+
"label": "友虾名片",
|
|
50
|
+
"description": "通过 WebSocket 连接友虾名片平台,接收客户消息并调用指定 OpenClaw 智能体回复",
|
|
51
|
+
"schema": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"additionalProperties": true,
|
|
54
|
+
"properties": {
|
|
55
|
+
"accounts": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"description": "多账号配置,key 为 OpenClaw 本地账号 ID",
|
|
58
|
+
"additionalProperties": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"additionalProperties": true,
|
|
61
|
+
"properties": {
|
|
62
|
+
"botToken": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"description": "从友虾平台获取的连接码"
|
|
65
|
+
},
|
|
66
|
+
"platformUrl": {
|
|
67
|
+
"type": "string",
|
|
68
|
+
"description": "友虾名片平台 WebSocket 地址,默认为 wss://api.gixin.cc"
|
|
69
|
+
},
|
|
70
|
+
"enabled": {
|
|
71
|
+
"type": "boolean",
|
|
72
|
+
"default": true
|
|
73
|
+
},
|
|
74
|
+
"defaultAgentId": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"default": "main"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"platformUrl": {
|
|
82
|
+
"type": "string",
|
|
83
|
+
"description": "友虾名片平台 WebSocket 地址"
|
|
84
|
+
},
|
|
85
|
+
"enabled": {
|
|
86
|
+
"type": "boolean",
|
|
87
|
+
"default": true
|
|
88
|
+
},
|
|
89
|
+
"defaultAgentId": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"default": "main"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"uiHints": {
|
|
96
|
+
"botToken": {
|
|
97
|
+
"label": "友虾连接码",
|
|
98
|
+
"placeholder": "从友虾小程序获取的 botToken",
|
|
99
|
+
"sensitive": true,
|
|
100
|
+
"help": "用于鉴权 WebSocket 连接,请妥善保管"
|
|
101
|
+
},
|
|
102
|
+
"platformUrl": {
|
|
103
|
+
"label": "友虾平台地址",
|
|
104
|
+
"placeholder": "wss://api.gixin.cc",
|
|
105
|
+
"advanced": true
|
|
106
|
+
},
|
|
107
|
+
"defaultAgentId": {
|
|
108
|
+
"label": "默认 OpenClaw 智能体 ID",
|
|
109
|
+
"placeholder": "main",
|
|
110
|
+
"advanced": true
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"commands": {
|
|
114
|
+
"nativeCommandsAutoEnabled": true,
|
|
115
|
+
"nativeSkillsAutoEnabled": true
|
|
24
116
|
}
|
|
25
|
-
}
|
|
26
|
-
"required": []
|
|
117
|
+
}
|
|
27
118
|
}
|
|
28
119
|
}
|
package/package.json
CHANGED
|
@@ -1,43 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sumeai/sumeclaw",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "友虾名片 OpenClaw Channel 插件 — 将 OpenClaw 连接到友虾名片平台,通过 AI 名片为客户提供服务",
|
|
5
|
-
"type": "
|
|
5
|
+
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist/**",
|
|
9
|
+
"openclaw.plugin.json",
|
|
10
|
+
"README.md",
|
|
11
|
+
"readme.md"
|
|
12
|
+
],
|
|
7
13
|
"scripts": {
|
|
8
|
-
"build": "
|
|
9
|
-
|
|
14
|
+
"build": "tsup"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"ws": "^8.18.3"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^22.18.8",
|
|
21
|
+
"@types/ws": "^8.18.1",
|
|
22
|
+
"openclaw": "^2026.6.8",
|
|
23
|
+
"tsup": "^8.5.1",
|
|
24
|
+
"typescript": "^6.0.3"
|
|
10
25
|
},
|
|
11
26
|
"openclaw": {
|
|
12
27
|
"extensions": [
|
|
13
|
-
"
|
|
28
|
+
"./index.ts"
|
|
29
|
+
],
|
|
30
|
+
"setupEntry": "./setup-entry.ts",
|
|
31
|
+
"runtimeExtensions": [
|
|
32
|
+
"./dist/index.js"
|
|
14
33
|
],
|
|
34
|
+
"runtimeSetupEntry": "./dist/setup-entry.js",
|
|
15
35
|
"channel": {
|
|
16
36
|
"id": "sumeclaw",
|
|
17
37
|
"label": "友虾名片",
|
|
18
|
-
"blurb": "将 OpenClaw 连接到友虾名片平台,通过 AI
|
|
38
|
+
"blurb": "将 OpenClaw 连接到友虾名片平台,通过 AI 名片为客户提供服务"
|
|
39
|
+
},
|
|
40
|
+
"compat": {
|
|
41
|
+
"pluginApi": ">=2026.6.8",
|
|
42
|
+
"minGatewayVersion": ">=2026.6.8"
|
|
43
|
+
},
|
|
44
|
+
"install": {
|
|
45
|
+
"npmSpec": "@sumeai/sumeclaw",
|
|
46
|
+
"minHostVersion": ">=2026.6.8"
|
|
47
|
+
},
|
|
48
|
+
"startup": {
|
|
49
|
+
"deferConfiguredChannelFullLoadUntilAfterListen": true
|
|
19
50
|
}
|
|
20
|
-
},
|
|
21
|
-
"dependencies": {
|
|
22
|
-
"ws": "^8.18.0"
|
|
23
|
-
},
|
|
24
|
-
"devDependencies": {
|
|
25
|
-
"typescript": "^5.7.0",
|
|
26
|
-
"@types/ws": "^8.5.0"
|
|
27
|
-
},
|
|
28
|
-
"engines": {
|
|
29
|
-
"openclaw": ">=2026.3.22"
|
|
30
|
-
},
|
|
31
|
-
"keywords": [
|
|
32
|
-
"openclaw",
|
|
33
|
-
"channel",
|
|
34
|
-
"minicard",
|
|
35
|
-
"友虾名片",
|
|
36
|
-
"ai-card"
|
|
37
|
-
],
|
|
38
|
-
"author": "sumeai",
|
|
39
|
-
"license": "MIT",
|
|
40
|
-
"publishConfig": {
|
|
41
|
-
"access": "public"
|
|
42
51
|
}
|
|
43
52
|
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @sumeai/sumeclaw
|
|
2
|
+
|
|
3
|
+
友虾名片 OpenClaw Channel 插件。该目录是新版 OpenClaw 插件骨架,运行协议迁移自已经调通的 `openclaw-plugin/`。
|
|
4
|
+
|
|
5
|
+
## 文件结构
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
@sumeai/sumeclaw/
|
|
9
|
+
├── index.ts # 完整运行入口:注册 channel,并按账号连接友虾后台
|
|
10
|
+
├── setup-entry.ts # 轻量 setup 入口:只暴露 channel plugin
|
|
11
|
+
├── src/
|
|
12
|
+
│ ├── channel.ts # createChatChannelPlugin 定义和 outbound 发送适配
|
|
13
|
+
│ ├── gateway.ts # WebSocket 隧道、hooks_agent 分发、agent_reply/delta/done 协议
|
|
14
|
+
│ └── runtime.ts # 保存 OpenClaw runtime 引用
|
|
15
|
+
├── package.json
|
|
16
|
+
├── tsup.config.ts
|
|
17
|
+
└── openclaw.plugin.json
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 关键协议
|
|
21
|
+
|
|
22
|
+
- 连接地址:`{platformUrl}/api/channel/{botToken}`,默认 `platformUrl` 为 `wss://api.gixin.cc`。
|
|
23
|
+
- 插件连接后发送 `register_info`,后台据此刷新在线状态。
|
|
24
|
+
- 后台下发 `hooks_agent`,payload 中的 `agentId` 决定本次请求路由到 OpenClaw 内的哪个智能体。
|
|
25
|
+
- 非流式回复会缓冲多个 OpenClaw outbound block,最终发送一条 `agent_reply`。
|
|
26
|
+
- 流式回复发送多条 `agent_delta`,OpenClaw Direct DM dispatch 完成后发送 `agent_done`。
|
|
27
|
+
|
|
28
|
+
## OpenClaw 2026.6 兼容点
|
|
29
|
+
|
|
30
|
+
- `package.json` 同时声明源码入口 `openclaw.extensions/setupEntry` 和运行时入口 `openclaw.runtimeExtensions/runtimeSetupEntry`。
|
|
31
|
+
- `openclaw.plugin.json` 使用新版顶层 `channels`、`channelConfigs`、`channelEnvVars` 字段。
|
|
32
|
+
- `tsup.config.ts` 将 `openclaw` 和 `ws` 标记为 external,避免把宿主 SDK 打进插件包。
|
|
33
|
+
|
|
34
|
+
## 配置示例
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"channels": {
|
|
39
|
+
"sumeclaw": {
|
|
40
|
+
"accounts": {
|
|
41
|
+
"default": {
|
|
42
|
+
"botToken": "YOUR_TOKEN",
|
|
43
|
+
"platformUrl": "wss://api.gixin.cc",
|
|
44
|
+
"defaultAgentId": "main",
|
|
45
|
+
"enabled": true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`defaultAgentId` 只用于插件注册上报;每次对话实际使用友虾后台 payload 中的 `agentId`。
|
|
54
|
+
|
|
55
|
+
## 构建
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm install
|
|
59
|
+
npm run build
|
|
60
|
+
npm pack --dry-run
|
|
61
|
+
```
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqEH,QAAA,MAAM,KAAK,KAWT,CAAC;AAEH,eAAe,KAAK,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"setup-entry.d.ts","sourceRoot":"","sources":["../setup-entry.ts"],"names":[],"mappings":";AASA,wBAAsD"}
|