@youdu/openclaw-youdu 2026.7.3 → 2026.9.15

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.
Files changed (46) hide show
  1. package/README.md +130 -1
  2. package/dist/index.esm.js +8 -2
  3. package/dist/src/channel.d.ts +18 -1
  4. package/dist/src/channel.js +410 -231
  5. package/dist/src/const.d.ts +5 -11
  6. package/dist/src/const.js +8 -10
  7. package/dist/src/dm-policy.d.ts +1 -1
  8. package/dist/src/group-mention.d.ts +55 -0
  9. package/dist/src/group-mention.js +114 -0
  10. package/dist/src/group-policy.d.ts +1 -1
  11. package/dist/src/kb/cli-runner.d.ts +50 -0
  12. package/dist/src/kb/cli-runner.js +206 -0
  13. package/dist/src/kb/endpoint.d.ts +9 -0
  14. package/dist/src/kb/endpoint.js +53 -0
  15. package/dist/src/kb/protocol.d.ts +66 -0
  16. package/dist/src/kb/protocol.js +233 -0
  17. package/dist/src/kb/request-context.d.ts +15 -0
  18. package/dist/src/kb/run-context.d.ts +21 -0
  19. package/dist/src/kb/run-context.js +85 -0
  20. package/dist/src/kb/tool-policy.d.ts +7 -0
  21. package/dist/src/kb/tool-policy.js +90 -0
  22. package/dist/src/kb/tool.d.ts +48 -0
  23. package/dist/src/kb/tool.js +122 -0
  24. package/dist/src/media.d.ts +1 -1
  25. package/dist/src/message-sender.d.ts +21 -2
  26. package/dist/src/message-sender.js +54 -18
  27. package/dist/src/monitor.d.ts +8 -1
  28. package/dist/src/monitor.js +233 -85
  29. package/dist/src/onboarding.js +24 -6
  30. package/dist/src/sdk/types.d.ts +24 -0
  31. package/dist/src/sdk/ws-client.d.ts +13 -4
  32. package/dist/src/sdk/ws-client.js +15 -2
  33. package/dist/src/sdk/ws-manager.d.ts +47 -2
  34. package/dist/src/sdk/ws-manager.js +285 -30
  35. package/dist/src/sdk/ws-utils.d.ts +1 -1
  36. package/dist/src/state-manager.d.ts +9 -4
  37. package/dist/src/state-manager.js +17 -21
  38. package/dist/src/target-store.d.ts +51 -0
  39. package/dist/src/target-store.js +270 -0
  40. package/dist/src/tls.d.ts +1 -0
  41. package/dist/src/tls.js +30 -4
  42. package/dist/src/utils.d.ts +21 -4
  43. package/dist/src/utils.js +120 -14
  44. package/openclaw.plugin.json +12 -0
  45. package/package.json +15 -7
  46. package/skills/youdu-kb-tool/SKILL.md +89 -0
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  有度机器人接入插件,基于 WebSocket 长连接实现消息收发。
4
4
 
5
+ 知识库 Tool 需要 OpenClaw `2026.7.1-2` 或更高版本;旧版本不提供本插件所需的 Tool hook 参数调整能力。可信有度 IM 上下文由插件按 OpenClaw `runId` 短期保存,并在本轮 dispatch 结束时清理;插件不会在注册结束后调用注册期 API。
6
+
7
+ 安全边界:知识库调用的短期 `invocationToken` 只由插件 hook 注入并一次性消费,不进入 CLI 请求、stdin、Tool 返回值或插件日志。OpenClaw `2026.7.1-2` 会在进程内保存调整后的参数,并将其提供给 `after_tool_call`;同时完整调整参数可能出现在宿主受控的 private diagnostic payload 和 loop-tracking 内存中。该 token 不写入模型会话 transcript,也不作为模型工具 schema 字段。宿主诊断的可见范围由 OpenClaw 控制,部署时应按受控诊断数据处理。
8
+
5
9
  ## 功能特性
6
10
 
7
11
  - 🔗 WebSocket 长连接 — 基于 wss 建立持久连接(可通过配置自定义)
@@ -54,9 +58,99 @@ openclaw gateway restart
54
58
  | `channels.youdu.botId` | 有度机器人 ID | — | — |
55
59
  | `channels.youdu.secret` | 有度机器人密钥 | — | — |
56
60
  | `channels.youdu.enabled` | 启用频道 | true / false | false |
57
- | `channels.youdu.websocketUrl` | WebSocket 地址 | — | — |
61
+ | `channels.youdu.url` | 有度服务器地址(纯主机名) | — | — |
58
62
  | `channels.youdu.dmPolicy` | 私聊访问策略 | pairing / open / allowlist / disabled | pairing |
59
63
  | `channels.youdu.allowFrom` | 私聊允许列表 | — | [] |
64
+ | `channels.youdu.groups.<群ID>.requireMention` | 该群是否必须 @ 机器人 | true / false | true |
65
+ | `channels.youdu.groups."*".requireMention` | 所有群的默认 @ 要求 | true / false | true |
66
+ | `channels.youdu.historyLimit` | 未被 @ 的群消息保留条数(作为下次被 @ 时的上下文) | 数字,0 表示关闭 | 50 |
67
+ | `channels.youdu.defaultAccount` | 默认账号 ID | 任意账号 ID | — |
68
+ | `channels.youdu.accounts` | 多账号配置 | 账号 ID → 账号级字段的映射 | — |
69
+
70
+ ### 群聊 @ 回复(默认)
71
+
72
+ 从本版本起,**群聊里只有 @ 了机器人的消息才会触发回复**。行为对齐 OpenClaw 其它渠道的 mention gating:
73
+
74
+ - 判定依据是有度回调 `raw.decoded.atUser` 是否包含机器人自身的用户 ID(`gid`,来自认证应答);
75
+ 配置文件里的 `mentionPatterns` 同样计入。斜杠命令(`/new`、`/status` 等)不受 @ 限制,
76
+ 仍按现有命令权限执行。
77
+ - 送进模型前会剥掉消息里的 `@账号(显示名)` 包装,避免模型看到 @ 前缀。
78
+ - **未被 @ 的消息不会进入会话**:不研究、不下载附件、不发"思考中"占位消息。它们只按群进入一个
79
+ **内存中的 pending 窗口**(默认每个群保留最近 50 条,`channels.youdu.historyLimit` 可调,`0` 关闭;
80
+ 窗口在每次回复结束、以及进程重启后清空)。下一次被 @ 时,这些消息会以
81
+ `[Chat messages since your last reply - for context]` 的形式随当次请求一起注入,让机器人知道群里刚才说了什么。
82
+ - 判定能力缺失时(认证应答没有 `gid`,也没有配置 `mentionPatterns`)**宁可不回**:会记录一条错误日志并丢弃
83
+ 该消息,而不会退化成"群里全回"。
84
+ - 想让某个群恢复"全部回复",在该群配置里显式关闭即可:
85
+
86
+ ```bash
87
+ openclaw config set channels.youdu.groups.'{0798E01E-CD68-42BB-813C-EB51593BB0F5}'.requireMention false
88
+ ```
89
+
90
+ - 群访问仍然先由 `channels.youdu.groupPolicy`(open / allowlist / disabled)控制,@ 判定在其后。
91
+
92
+ ### 多账号配置
93
+
94
+ 插件支持配置多个有度机器人账号,每个账号可拥有独立的凭据和访问策略;账号级字段会覆盖顶层默认值。
95
+
96
+ **CLI 配置示例:**
97
+
98
+ ```bash
99
+ openclaw config set channels.youdu.accounts.bot-one.botId "<BOT_ID_1>"
100
+ openclaw config set channels.youdu.accounts.bot-one.secret "<BOT_SECRET_1>"
101
+ openclaw config set channels.youdu.accounts.bot-one.url "<HOST_1>"
102
+
103
+ openclaw config set channels.youdu.accounts.bot-two.botId "<BOT_ID_2>"
104
+ openclaw config set channels.youdu.accounts.bot-two.secret "<BOT_SECRET_2>"
105
+ openclaw config set channels.youdu.accounts.bot-two.url "<HOST_2>"
106
+
107
+ # 指定默认账号
108
+ openclaw config set channels.youdu.defaultAccount bot-one
109
+
110
+ openclaw gateway restart
111
+ ```
112
+
113
+ **等效的配置文件写法:**
114
+
115
+ ```json
116
+ {
117
+ "channels": {
118
+ "youdu": {
119
+ "enabled": true,
120
+ "dmPolicy": "pairing",
121
+ "defaultAccount": "bot-one",
122
+ "accounts": {
123
+ "bot-one": {
124
+ "botId": "<BOT_ID_1>",
125
+ "secret": "<BOT_SECRET_1>",
126
+ "url": "<HOST_1>"
127
+ },
128
+ "bot-two": {
129
+ "botId": "<BOT_ID_2>",
130
+ "secret": "<BOT_SECRET_2>",
131
+ "url": "<HOST_2>"
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ **规则说明:**
140
+
141
+ - `url` 只填主机名(如 `youdu.example.com`),不要带 `https://` 协议前缀或端口
142
+ - 顶层字段作为默认值:账号级未配置的字段(如 `dmPolicy`、`allowFrom`、`groupPolicy`)会继承顶层值
143
+ - `defaultAccount` 指定默认账号;未指定时优先使用 `default` 账号,否则取第一个账号
144
+ - 若顶层同时配置了 `botId`/`secret`/`url`,顶层凭据会作为一个独立的 `default` 账号保留(除非某个命名账号的 botId 与之重复)
145
+ - 账号级可用字段与顶层一致:`botId`、`secret`、`url`、`enabled`、`name`、`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`、`sendThinkingMessage`、`mediaMaxMb`、`mediaLocalRoots`
146
+ - 查看多账号运行状态:`openclaw channels status youdu`
147
+ - 仅配置顶层凭据(不配置 `accounts`)时行为与之前完全一致,即为单账号模式
148
+
149
+ ### 知识库工具授权
150
+
151
+ OpenClaw 的 `coding` 工具 profile 默认不包含插件工具。有度频道的 `botId`、`secret` 和 Host 配置完整后,插件会在 Gateway 启动或配置热加载时,将精确工具名 `youdu_kb` 追加到 `tools.alsoAllow`。有度 Channel 会在当前运行配置确认包含该授权后才建立连接;首次补齐配置时,本轮启动等待 OpenClaw 自动热加载或重启后再连接,因此首条有度消息不会早于工具授权。
152
+
153
+ 插件不会添加 `group:plugins`,也不会修改 `tools.profile`、`tools.allow`、`tools.deny` 或其他工具策略。`youdu_kb` 只在有度 IM 会话中挂载;它在 webchat 等其他频道不可见属于预期行为。用户额外配置的 agent、provider、sandbox 或 deny 策略仍可能进一步过滤该工具。
60
154
 
61
155
  ## 使用
62
156
 
@@ -71,6 +165,41 @@ openclaw status
71
165
  openclaw channels status youdu
72
166
  ```
73
167
 
168
+ ## 主动发送(Outbound)
169
+
170
+ 机器人可以在没有人先说话的情况下主动发消息(定时任务、告警、后台任务结果):
171
+
172
+ ```bash
173
+ # 私聊:数字 userId 直接可用(有度单聊的 chatId 就是对方 userId)
174
+ openclaw message send --channel youdu --to 6463894 --message "早上好"
175
+
176
+ # 私聊:用账号名(需该账号先私聊过机器人,插件会记住映射)
177
+ openclaw message send --channel youdu --to lewis.liu --message "早上好"
178
+
179
+ # 群聊:直接填群 ID,或显式声明类型
180
+ openclaw message send --channel youdu --to "group:{0798E01E-CD68-42BB-813C-EB51593BB0F5}" --message "群公告"
181
+ ```
182
+
183
+ 目标解析顺序(`src/message-sender.ts` 的 `resolveOutboundTarget`):
184
+
185
+ 1. 去掉 `youdu:` 前缀,以及可选的显式类型前缀 `group:` / `user:`(`single:` 亦可);
186
+ 2. 已学到的私聊账号名 → 该账号的 chatId(单聊);
187
+ 3. 已学到的群 ID,或形如 `{GUID}` 的群 ID → 群聊;
188
+ 4. 纯数字 → 单聊;
189
+ 5. 其余报错,并提示可用写法。
190
+
191
+ 学习与持久化(`src/target-store.ts`):
192
+
193
+ - 收到私聊消息时记录 `账号名 → chatId` 与昵称,收到群消息时记录群 ID;
194
+ - 记录写入 `~/.openclaw/youdu-targets.json`(权限 0600、先写临时文件再 rename、变更后去抖落盘),
195
+ **进程重启后仍然可用**;
196
+ - 账号从配置中移除时会一并清掉该账号的目标;
197
+ - `openclaw channels directory youdu`(`directory.listPeers` / `listGroups`)会列出这些已聊过的联系人与群,
198
+ 方便确认可投递目标;有度回调不下发群名,因此群只显示 ID。
199
+
200
+ > 注意:`send_msg` 必须带 `chatType`(`single`/`group`)。有度服务端只在 `chatType === 'group'`
201
+ > 时按群会话投递,其余值一律按单聊处理,漏传会把群 ID 当成用户 ID 发成私聊。
202
+
74
203
  ## 消息处理流程
75
204
 
76
205
  1. 插件通过 WebSocket 连接到有度服务
package/dist/index.esm.js CHANGED
@@ -1,7 +1,10 @@
1
- import { youduPlugin } from './src/channel.js';
1
+ import { createYouDuPlugin } from './src/channel.js';
2
2
  import { emptyPluginConfigSchema } from './src/openclaw-compat.js';
3
3
  import { setYouDuRuntime } from './src/runtime.js';
4
4
  import { CHANNEL_ID } from './src/const.js';
5
+ import { youduKbToolFactory } from './src/kb/tool.js';
6
+ import { registerYouDuKbRunContext } from './src/kb/run-context.js';
7
+ import { createYouDuKbToolPolicy } from './src/kb/tool-policy.js';
5
8
 
6
9
  /**
7
10
  * YouDu OpenClaw Plugin - 主入口
@@ -16,7 +19,10 @@ const plugin = {
16
19
  configSchema: emptyPluginConfigSchema(),
17
20
  register(api) {
18
21
  setYouDuRuntime(api.runtime);
19
- api.registerChannel({ plugin: youduPlugin });
22
+ registerYouDuKbRunContext(api);
23
+ const toolPolicy = createYouDuKbToolPolicy(api);
24
+ api.registerChannel({ plugin: createYouDuPlugin(toolPolicy) });
25
+ api.registerTool(youduKbToolFactory, { name: "youdu_kb", optional: false });
20
26
  /** 有度频道系统指令 — 条件→动作格式,便于 LLM 精确遵循 */
21
27
  const YOUDU_SYSTEM_CONTEXT_HINTS = [
22
28
  "## 有度频道输出约束",
@@ -1,3 +1,20 @@
1
1
  import { type ChannelPlugin } from "openclaw/plugin-sdk/core";
2
+ import { monitorYouDuProvider } from './monitor.js';
2
3
  import { type ResolvedYouDuAccount } from './utils.js';
3
- export declare const youduPlugin: ChannelPlugin<ResolvedYouDuAccount>;
4
+ import type { YouDuKbToolPolicy } from "./kb/tool-policy.js";
5
+ import type { WsConnectionSnapshot } from "./sdk/types.js";
6
+ export type YouDuProbeResult = WsConnectionSnapshot & {
7
+ ok: boolean;
8
+ status: number;
9
+ error?: string;
10
+ };
11
+ export type YouDuChannelLifecycleEvent = {
12
+ type: "gate-start" | "gate-result" | "gate-wait-start" | "gate-wait-abort" | "monitor-start" | "monitor-abort";
13
+ attemptId: string;
14
+ result?: Awaited<ReturnType<YouDuKbToolPolicy["ensureYouDuKbToolPolicy"]>>;
15
+ authorized: boolean;
16
+ profile?: string;
17
+ };
18
+ export type YouDuChannelLifecycleObserver = (event: YouDuChannelLifecycleEvent) => void | Promise<void>;
19
+ export declare function createYouDuPlugin(policy?: YouDuKbToolPolicy, monitor?: typeof monitorYouDuProvider, lifecycleObserver?: YouDuChannelLifecycleObserver): ChannelPlugin<ResolvedYouDuAccount, YouDuProbeResult>;
20
+ export declare const youduPlugin: ChannelPlugin<ResolvedYouDuAccount, YouDuProbeResult>;