@rowger_go/chatu 0.1.3

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 (77) hide show
  1. package/.github/workflows/ci.yml +30 -0
  2. package/.github/workflows/publish.yml +55 -0
  3. package/INSTALL.md +285 -0
  4. package/INSTALL.zh.md +285 -0
  5. package/LICENSE +21 -0
  6. package/README.md +293 -0
  7. package/README.zh.md +293 -0
  8. package/dist/index.d.ts +96 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +1381 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/index.test.d.ts +5 -0
  13. package/dist/index.test.d.ts.map +1 -0
  14. package/dist/index.test.js +334 -0
  15. package/dist/index.test.js.map +1 -0
  16. package/dist/sdk/adapters/cache.d.ts +94 -0
  17. package/dist/sdk/adapters/cache.d.ts.map +1 -0
  18. package/dist/sdk/adapters/cache.js +158 -0
  19. package/dist/sdk/adapters/cache.js.map +1 -0
  20. package/dist/sdk/adapters/cache.test.d.ts +14 -0
  21. package/dist/sdk/adapters/cache.test.d.ts.map +1 -0
  22. package/dist/sdk/adapters/cache.test.js +178 -0
  23. package/dist/sdk/adapters/cache.test.js.map +1 -0
  24. package/dist/sdk/adapters/default.d.ts +24 -0
  25. package/dist/sdk/adapters/default.d.ts.map +1 -0
  26. package/dist/sdk/adapters/default.js +151 -0
  27. package/dist/sdk/adapters/default.js.map +1 -0
  28. package/dist/sdk/adapters/webhub.d.ts +336 -0
  29. package/dist/sdk/adapters/webhub.d.ts.map +1 -0
  30. package/dist/sdk/adapters/webhub.js +663 -0
  31. package/dist/sdk/adapters/webhub.js.map +1 -0
  32. package/dist/sdk/adapters/websocket.d.ts +133 -0
  33. package/dist/sdk/adapters/websocket.d.ts.map +1 -0
  34. package/dist/sdk/adapters/websocket.js +314 -0
  35. package/dist/sdk/adapters/websocket.js.map +1 -0
  36. package/dist/sdk/core/channel.d.ts +104 -0
  37. package/dist/sdk/core/channel.d.ts.map +1 -0
  38. package/dist/sdk/core/channel.js +158 -0
  39. package/dist/sdk/core/channel.js.map +1 -0
  40. package/dist/sdk/index.d.ts +27 -0
  41. package/dist/sdk/index.d.ts.map +1 -0
  42. package/dist/sdk/index.js +33 -0
  43. package/dist/sdk/index.js.map +1 -0
  44. package/dist/sdk/types/adapters.d.ts +128 -0
  45. package/dist/sdk/types/adapters.d.ts.map +1 -0
  46. package/dist/sdk/types/adapters.js +10 -0
  47. package/dist/sdk/types/adapters.js.map +1 -0
  48. package/dist/sdk/types/channel.d.ts +270 -0
  49. package/dist/sdk/types/channel.d.ts.map +1 -0
  50. package/dist/sdk/types/channel.js +36 -0
  51. package/dist/sdk/types/channel.js.map +1 -0
  52. package/docs/channel/01-overview.md +117 -0
  53. package/docs/channel/02-configuration.md +138 -0
  54. package/docs/channel/03-capabilities.md +86 -0
  55. package/docs/channel/04-api-reference.md +394 -0
  56. package/docs/channel/05-message-protocol.md +194 -0
  57. package/docs/channel/06-security.md +83 -0
  58. package/docs/channel/README.md +30 -0
  59. package/docs/sdk/README.md +13 -0
  60. package/docs/sdk/v2026.1.29-v2026.2.19.md +630 -0
  61. package/jest.config.js +19 -0
  62. package/openclaw.plugin.json +113 -0
  63. package/package.json +74 -0
  64. package/run-poll.mjs +209 -0
  65. package/scripts/reload-plugin.sh +78 -0
  66. package/src/index.test.ts +432 -0
  67. package/src/index.ts +1638 -0
  68. package/src/sdk/adapters/cache.test.ts +205 -0
  69. package/src/sdk/adapters/cache.ts +193 -0
  70. package/src/sdk/adapters/default.ts +196 -0
  71. package/src/sdk/adapters/webhub.ts +857 -0
  72. package/src/sdk/adapters/websocket.ts +378 -0
  73. package/src/sdk/core/channel.ts +230 -0
  74. package/src/sdk/index.ts +36 -0
  75. package/src/sdk/types/adapters.ts +169 -0
  76. package/src/sdk/types/channel.ts +346 -0
  77. package/tsconfig.json +31 -0
@@ -0,0 +1,630 @@
1
+ # OpenClaw Channel Plugin SDK 变更报告
2
+
3
+ **版本对比**:`v2026.1.29` → `v2026.2.19`
4
+ **生成日期**:2026-02-20
5
+ **分析范围**:Channel Plugin SDK 公共接口
6
+
7
+ ---
8
+
9
+ ## 概述
10
+
11
+ 本次版本升级是一次**纯增量式更新**,不含任何破坏性变更。主要新增了 6 个生命周期 Hook(包含 LLM 输入/输出观测、消息写入拦截、模型覆盖等能力),并在多个核心类型上补充了可选字段。`plugin-sdk/index.ts` 新增了大量工具函数导出(文件锁、Webhook 辅助、SSRF 防护等),大幅扩展了插件能力边界。整体变更规模较大,但对现有插件的升级代价极低。
12
+
13
+ ---
14
+
15
+ ## 破坏性变更(Breaking Changes)
16
+
17
+ > ✅ **本次版本间不存在任何破坏性变更。** 所有变更均为向后兼容的新增或可选字段扩充。
18
+
19
+ ---
20
+
21
+ ## 新增功能(New Features)
22
+
23
+ ### 1. `before_model_resolve` Hook
24
+
25
+ - **变更类型**:新增 Hook 及对应事件/结果类型
26
+ - **定义**:
27
+ ```typescript
28
+ // 新增事件类型
29
+ export type PluginHookBeforeModelResolveEvent = {
30
+ /** 本次运行的用户提示词,此阶段尚无会话消息 */
31
+ prompt: string;
32
+ };
33
+
34
+ export type PluginHookBeforeModelResolveResult = {
35
+ /** 覆盖本次 agent 运行使用的模型,如 "llama3.3:8b" */
36
+ modelOverride?: string;
37
+ /** 覆盖本次 agent 运行使用的 provider,如 "ollama" */
38
+ providerOverride?: string;
39
+ };
40
+ ```
41
+ - **用途说明**:在 agent 运行开始前、会话消息加载前触发,允许插件动态覆盖本次运行使用的模型或 provider。适用于按用户/渠道路由不同模型的场景。
42
+ - **注册方式**:
43
+ ```typescript
44
+ api.on("before_model_resolve", (event, ctx) => {
45
+ if (ctx.channelId === "telegram") {
46
+ return { modelOverride: "gpt-4o" };
47
+ }
48
+ });
49
+ ```
50
+
51
+ ---
52
+
53
+ ### 2. `before_prompt_build` Hook
54
+
55
+ - **变更类型**:新增 Hook 及对应事件/结果类型
56
+ - **定义**:
57
+ ```typescript
58
+ export type PluginHookBeforePromptBuildEvent = {
59
+ prompt: string;
60
+ /** 本次运行准备好的会话消息列表 */
61
+ messages: unknown[];
62
+ };
63
+
64
+ export type PluginHookBeforePromptBuildResult = {
65
+ systemPrompt?: string;
66
+ prependContext?: string;
67
+ };
68
+ ```
69
+ - **用途说明**:在 prompt 构建前触发,此阶段已可访问完整会话消息列表,可注入系统提示词或前置上下文。与旧版 `before_agent_start` 相比,信息更完整。
70
+
71
+ ---
72
+
73
+ ### 3. `llm_input` Hook
74
+
75
+ - **变更类型**:新增 Hook(只读观测)
76
+ - **定义**:
77
+ ```typescript
78
+ export type PluginHookLlmInputEvent = {
79
+ runId: string;
80
+ sessionId: string;
81
+ provider: string;
82
+ model: string;
83
+ systemPrompt: string;
84
+ prompt: string;
85
+ historyMessages: unknown[];
86
+ imagesCount: number;
87
+ };
88
+ ```
89
+ - **用途说明**:在每次向 LLM 发送请求前触发(只读),可用于日志记录、计量、审计等。返回值被忽略(`void`)。
90
+
91
+ ---
92
+
93
+ ### 4. `llm_output` Hook
94
+
95
+ - **变更类型**:新增 Hook(只读观测)
96
+ - **定义**:
97
+ ```typescript
98
+ export type PluginHookLlmOutputEvent = {
99
+ runId: string;
100
+ sessionId: string;
101
+ provider: string;
102
+ model: string;
103
+ assistantTexts: string[];
104
+ lastAssistant?: unknown;
105
+ usage?: {
106
+ input?: number;
107
+ output?: number;
108
+ cacheRead?: number;
109
+ cacheWrite?: number;
110
+ total?: number;
111
+ };
112
+ };
113
+ ```
114
+ - **用途说明**:在 LLM 返回结果后触发(只读),可获取 token 用量、输出文本等信息,适用于计费统计、内容监控场景。
115
+
116
+ ---
117
+
118
+ ### 5. `before_reset` Hook
119
+
120
+ - **变更类型**:新增 Hook
121
+ - **定义**:
122
+ ```typescript
123
+ export type PluginHookBeforeResetEvent = {
124
+ sessionFile?: string;
125
+ messages?: unknown[];
126
+ reason?: string;
127
+ };
128
+ ```
129
+ - **用途说明**:在用户执行 `/new` 或 `/reset` 清除会话时触发,插件可在会话被清除前读取会话内容(如存档、统计等)。
130
+
131
+ ---
132
+
133
+ ### 6. `before_message_write` Hook
134
+
135
+ - **变更类型**:新增 Hook(支持阻断)
136
+ - **定义**:
137
+ ```typescript
138
+ export type PluginHookBeforeMessageWriteEvent = {
139
+ message: AgentMessage;
140
+ sessionKey?: string;
141
+ agentId?: string;
142
+ };
143
+
144
+ export type PluginHookBeforeMessageWriteResult = {
145
+ block?: boolean; // true 则阻止该消息写入 JSONL
146
+ message?: AgentMessage; // 可选:写入修改后的消息
147
+ };
148
+ ```
149
+ - **注册签名**:
150
+ ```typescript
151
+ before_message_write: (
152
+ event: PluginHookBeforeMessageWriteEvent,
153
+ ctx: { agentId?: string; sessionKey?: string },
154
+ ) => PluginHookBeforeMessageWriteResult | void;
155
+ ```
156
+ - **用途说明**:在消息写入会话 JSONL 文件前触发,插件可阻止特定消息落盘(如过滤大型 tool result),或对消息内容进行修改后再写入。**注意:此 Hook 不支持异步,必须同步返回。**
157
+
158
+ ---
159
+
160
+ ### 7. 新增类型:`BaseProbeResult` 和 `BaseTokenResolution`(`types.core.ts`)
161
+
162
+ - **变更类型**:新增
163
+ - **定义**:
164
+ ```typescript
165
+ /** 所有 channel probe 结果的最小基类,channel 专用 probe 可继承此类型 */
166
+ export type BaseProbeResult<TError = string | null> = {
167
+ ok: boolean;
168
+ error?: TError;
169
+ };
170
+
171
+ /** token 解析结果的最小基类 */
172
+ export type BaseTokenResolution = {
173
+ token: string;
174
+ source: string;
175
+ };
176
+ ```
177
+ - **用途说明**:为各 channel 实现 probe/token 相关结果提供标准化的基础类型,便于统一处理和类型收窄。
178
+
179
+ ---
180
+
181
+ ### 8. `plugin-sdk/index.ts` 大量新增导出
182
+
183
+ 以下是本次新增的主要导出分类:
184
+
185
+ #### 文件锁 API
186
+ ```typescript
187
+ export type { FileLockHandle, FileLockOptions } from "./file-lock.js";
188
+ export { acquireFileLock, withFileLock } from "./file-lock.js";
189
+ ```
190
+
191
+ #### Webhook 辅助
192
+ ```typescript
193
+ export { normalizeWebhookPath, resolveWebhookPath } from "./webhook-path.js";
194
+ export {
195
+ registerWebhookTarget,
196
+ rejectNonPostWebhookRequest,
197
+ resolveWebhookTargets,
198
+ } from "./webhook-targets.js";
199
+ ```
200
+
201
+ #### Agent 媒体处理
202
+ ```typescript
203
+ export type { AgentMediaPayload } from "./agent-media-payload.js";
204
+ export { buildAgentMediaPayload } from "./agent-media-payload.js";
205
+ ```
206
+
207
+ #### Channel 状态辅助
208
+ ```typescript
209
+ export {
210
+ buildBaseChannelStatusSummary,
211
+ collectStatusIssuesFromLastError,
212
+ createDefaultChannelRuntimeState,
213
+ } from "./status-helpers.js";
214
+ ```
215
+
216
+ #### SSRF/网络防护
217
+ ```typescript
218
+ export { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
219
+ export {
220
+ SsrFBlockedError,
221
+ isBlockedHostname,
222
+ isBlockedHostnameOrIp,
223
+ isPrivateIpAddress,
224
+ } from "../infra/net/ssrf.js";
225
+ export type { LookupFn, SsrFPolicy } from "../infra/net/ssrf.js";
226
+ ```
227
+
228
+ #### HTTP 请求体处理
229
+ ```typescript
230
+ export {
231
+ DEFAULT_WEBHOOK_BODY_TIMEOUT_MS,
232
+ DEFAULT_WEBHOOK_MAX_BODY_BYTES,
233
+ RequestBodyLimitError,
234
+ installRequestBodyLimitGuard,
235
+ isRequestBodyLimitError,
236
+ readJsonBodyWithLimit,
237
+ readRequestBodyWithLimit,
238
+ requestBodyErrorToText,
239
+ } from "../infra/http-body.js";
240
+ ```
241
+
242
+ #### 去重缓存
243
+ ```typescript
244
+ export { createDedupeCache } from "../infra/dedupe.js";
245
+ export type { DedupeCache } from "../infra/dedupe.js";
246
+ ```
247
+
248
+ #### 设备配对
249
+ ```typescript
250
+ export {
251
+ approveDevicePairing,
252
+ listDevicePairing,
253
+ rejectDevicePairing,
254
+ } from "../infra/device-pairing.js";
255
+ ```
256
+
257
+ #### 工具函数
258
+ ```typescript
259
+ export { clamp, escapeRegExp, normalizeE164, safeParseJson, sleep } from "../utils.js";
260
+ export { stripAnsi } from "../terminal/ansi.js";
261
+ export { formatErrorMessage } from "../infra/errors.js";
262
+ export { isTruthyEnvValue } from "../infra/env.js";
263
+ export { isWSLSync, isWSL2Sync, isWSLEnv } from "../infra/wsl.js";
264
+ export { rawDataToString } from "../infra/ws.js";
265
+ ```
266
+
267
+ #### 平台特定工具函数(新增)
268
+ ```typescript
269
+ // iMessage 目标解析
270
+ export {
271
+ parseChatAllowTargetPrefixes,
272
+ parseChatTargetPrefixesOrThrow,
273
+ resolveServicePrefixedAllowTarget,
274
+ resolveServicePrefixedTarget,
275
+ } from "../imessage/target-parsing-helpers.js";
276
+
277
+ // Slack 消息 actions
278
+ export { extractSlackToolSend, listSlackMessageActions } from "../slack/message-actions.js";
279
+ export { handleSlackMessageAction } from "./slack-message-actions.js";
280
+
281
+ // Telegram 参数解析
282
+ export {
283
+ parseTelegramReplyToMessageId,
284
+ parseTelegramThreadId,
285
+ } from "../telegram/outbound-params.js";
286
+ export { type TelegramProbe } from "../telegram/probe.js";
287
+
288
+ // WhatsApp 出向目标
289
+ export { resolveWhatsAppOutboundTarget } from "../whatsapp/resolve-outbound-target.js";
290
+
291
+ // Discord
292
+ export { normalizeDiscordOutboundTarget } from "...";
293
+ ```
294
+
295
+ #### 其他新增
296
+ ```typescript
297
+ export { createAccountListHelpers } from "../channels/plugins/account-helpers.js";
298
+ export { buildOauthProviderAuthResult } from "./provider-auth-result.js";
299
+ export { createReplyPrefixOptions } from "../channels/reply-prefix.js"; // replaceFromOnly
300
+ export { resolveAllowlistMatchSimple } from "../channels/plugins/allowlist-match.js";
301
+ export { mergeAllowFromEntries } from "../channels/plugins/onboarding/helpers.js";
302
+ export { formatAllowFromLowercase, isAllowedParsedChatSender } from "./allow-from.js";
303
+ export { resolveSenderCommandAuthorization } from "./command-auth.js";
304
+ export { extractToolSend } from "./tool-send.js";
305
+ export { resolveChannelAccountConfigBasePath } from "./config-paths.js";
306
+ export { chunkTextForOutbound } from "./text-chunking.js";
307
+ export { readJsonFileWithFallback, writeJsonFileAtomically } from "./json-store.js";
308
+ export { buildRandomTempFilePath, withTempDownloadPath } from "./temp-path.js";
309
+
310
+ // 类型别名(向后兼容)
311
+ /** @deprecated Use OpenClawConfig instead */
312
+ export type { OpenClawConfig as ClawdbotConfig } from "../config/config.js";
313
+ /** @deprecated Use ChatType instead */
314
+ export type { RoutePeerKind } from "../routing/resolve-route.js";
315
+ export type { ChatType } from "../channels/chat-type.js";
316
+
317
+ // RuntimeLogger
318
+ export type { PluginRuntime, RuntimeLogger } from "../plugins/runtime/types.js";
319
+
320
+ // TTS Schema
321
+ export { TtsAutoSchema, TtsConfigSchema, TtsModeSchema, TtsProviderSchema };
322
+
323
+ // Provider Auth
324
+ export type { ProviderAuthContext, ProviderAuthResult };
325
+ export type { AnyAgentTool } from "../agents/tools/common.js";
326
+ ```
327
+
328
+ ---
329
+
330
+ ## 非破坏性变更(Non-Breaking Changes)
331
+
332
+ ### `PluginHookName`(`plugins/types.ts`)
333
+
334
+ - **变更类型**:Union 成员新增
335
+ - **说明**:新增 6 个 hook 名称(`before_model_resolve`、`before_prompt_build`、`llm_input`、`llm_output`、`before_reset`、`before_message_write`),现有代码引用原有名称不受影响。
336
+
337
+ ---
338
+
339
+ ### `PluginHookAgentContext`(`plugins/types.ts`)
340
+
341
+ - **变更类型**:字段新增(均为可选)
342
+ - **说明**:
343
+ ```typescript
344
+ // 新增字段(均为可选)
345
+ sessionId?: string; // 当前会话 ID
346
+ channelId?: ChannelId; // Provider 渠道 ID (如 "telegram")
347
+ from?: string; // 原始 "From" 值(渠道内 ID)
348
+ to?: string; // 原始 "To" 值(渠道内 ID)
349
+ accountId?: string; // 多账号渠道的账号 ID
350
+ messageThreadId?: number; // 线程/话题 ID(如有)
351
+ ```
352
+
353
+ ---
354
+
355
+ ### `PluginHookBeforeCompactionEvent`(`plugins/types.ts`)
356
+
357
+ - **变更类型**:字段新增(均为可选)
358
+ - **说明**:
359
+ ```typescript
360
+ compactingCount?: number; // 送入压缩 LLM 的消息数(经 history-limit 截断后)
361
+ messages?: unknown[]; // 当前会话全部消息
362
+ sessionFile?: string; // 会话 JSONL 文件路径(可异步读取)
363
+ ```
364
+
365
+ ---
366
+
367
+ ### `PluginHookAfterCompactionEvent`(`plugins/types.ts`)
368
+
369
+ - **变更类型**:字段新增(可选)
370
+ - **说明**:
371
+ ```typescript
372
+ sessionFile?: string; // 会话 JSONL 文件路径(压缩前所有消息均已落盘)
373
+ ```
374
+
375
+ ---
376
+
377
+ ### `PluginHookBeforeAgentStartResult`(`plugins/types.ts`)
378
+
379
+ - **变更类型**:类型定义扩展(交叉类型,非破坏性)
380
+ - **说明**:
381
+ ```typescript
382
+ // 旧定义(v2026.1.29)
383
+ export type PluginHookBeforeAgentStartResult = {
384
+ systemPrompt?: string;
385
+ prependContext?: string;
386
+ };
387
+
388
+ // 新定义(v2026.2.19)
389
+ export type PluginHookBeforeAgentStartResult =
390
+ PluginHookBeforePromptBuildResult & PluginHookBeforeModelResolveResult;
391
+ // 展开后等价于:
392
+ // { systemPrompt?: string; prependContext?: string; modelOverride?: string; providerOverride?: string; }
393
+ ```
394
+ 原有字段均保留,新增了 `modelOverride?` 和 `providerOverride?` 可选字段,现有实现无需修改。
395
+
396
+ ---
397
+
398
+ ### `ChannelAgentTool`(`types.core.ts`)
399
+
400
+ - **变更类型**:类型扩展(新增可选字段)
401
+ - **说明**:
402
+ ```typescript
403
+ // 旧定义
404
+ export type ChannelAgentTool = AgentTool<TSchema, unknown>;
405
+
406
+ // 新定义
407
+ export type ChannelAgentTool = AgentTool<TSchema, unknown> & {
408
+ ownerOnly?: boolean; // 若为 true,仅 owner 可调用此工具
409
+ };
410
+ ```
411
+
412
+ ---
413
+
414
+ ### `ChannelAccountSnapshot`(`types.core.ts`)
415
+
416
+ - **变更类型**:字段新增(均为可选)
417
+ - **说明**:新增以下可选字段,为更多 channel(如 LINE、公钥基础设施)提供通用快照存储:
418
+ ```typescript
419
+ secretSource?: string;
420
+ publicKey?: string | null;
421
+ profile?: unknown;
422
+ channelAccessToken?: string;
423
+ channelSecret?: string;
424
+ ```
425
+
426
+ ---
427
+
428
+ ### `ChannelCapabilities.chatTypes`(`types.core.ts`)
429
+
430
+ - **变更类型**:依赖类型重命名(非破坏性,运行时无影响)
431
+ - **说明**:
432
+ ```typescript
433
+ // 旧(v2026.1.29)
434
+ chatTypes: Array<NormalizedChatType | "thread">;
435
+
436
+ // 新(v2026.2.19)
437
+ chatTypes: Array<ChatType | "thread">;
438
+ ```
439
+ `NormalizedChatType` 被重命名为 `ChatType`(来自 `../channels/chat-type.js`),底层值不变。若插件代码直接使用了 `NormalizedChatType` 类型注解,需更新为 `ChatType`。
440
+
441
+ ---
442
+
443
+ ### `ChannelThreadingAdapter`(`types.core.ts`)
444
+
445
+ - **变更类型**:字段新增(可选)
446
+ - **说明**:
447
+ ```typescript
448
+ // 新增字段
449
+ allowExplicitReplyTagsWhenOff?: boolean;
450
+ // 同时:allowTagsWhenOff 被标注为 deprecated alias,但保留兼容性
451
+ ```
452
+
453
+ ---
454
+
455
+ ### `ChannelMessageActionContext`(`types.core.ts`)
456
+
457
+ - **变更类型**:字段新增(可选)
458
+ - **说明**:
459
+ ```typescript
460
+ /**
461
+ * Trusted sender id from inbound context. This is server-injected and must
462
+ * never be sourced from tool/model-controlled params.
463
+ */
464
+ requesterSenderId?: string | null;
465
+ ```
466
+
467
+ ---
468
+
469
+ ### `ChannelPollContext`(`types.core.ts`)
470
+
471
+ - **变更类型**:字段新增(均为可选)
472
+ - **说明**:
473
+ ```typescript
474
+ threadId?: string | null;
475
+ silent?: boolean;
476
+ isAnonymous?: boolean;
477
+ ```
478
+
479
+ ---
480
+
481
+ ### `ChannelPlugin<ResolvedAccount>`(`types.plugin.ts`)
482
+
483
+ - **变更类型**:泛型参数扩展(新增带默认值的泛型,非破坏性)
484
+ - **说明**:
485
+ ```typescript
486
+ // 旧定义
487
+ export type ChannelPlugin<ResolvedAccount = any> = { ... };
488
+
489
+ // 新定义
490
+ export type ChannelPlugin<ResolvedAccount = any, Probe = unknown, Audit = unknown> = { ... };
491
+ ```
492
+ 新增 `Probe` 和 `Audit` 泛型参数,均有默认值 `unknown`,现有代码无需修改。`status` 字段类型更新为 `ChannelStatusAdapter<ResolvedAccount, Probe, Audit>`。
493
+
494
+ ---
495
+
496
+ ### `ChannelStatusAdapter<ResolvedAccount>`(`types.adapters.ts`)
497
+
498
+ - **变更类型**:泛型参数扩展(新增带默认值的泛型,类型更精确)
499
+ - **说明**:
500
+ ```typescript
501
+ // 旧定义
502
+ export type ChannelStatusAdapter<ResolvedAccount> = {
503
+ probeAccount?: (...) => Promise<unknown>;
504
+ auditAccount?: (..., probe?: unknown) => Promise<unknown>;
505
+ buildAccountSnapshot?: (..., probe?: unknown, audit?: unknown) => ...;
506
+ };
507
+
508
+ // 新定义
509
+ export type ChannelStatusAdapter<ResolvedAccount, Probe = unknown, Audit = unknown> = {
510
+ probeAccount?: (...) => Promise<Probe>;
511
+ auditAccount?: (..., probe?: Probe) => Promise<Audit>;
512
+ buildAccountSnapshot?: (..., probe?: Probe, audit?: Audit) => ...;
513
+ };
514
+ ```
515
+ 默认值为 `unknown`,与旧版行为完全一致。类型参数允许 channel 实现提供更精确的类型推断。
516
+
517
+ ---
518
+
519
+ ### `ChannelOutboundContext`(`types.adapters.ts`)
520
+
521
+ - **变更类型**:字段新增(均为可选)
522
+ - **说明**:
523
+ ```typescript
524
+ mediaLocalRoots?: readonly string[]; // 媒体文件本地根路径列表
525
+ identity?: OutboundIdentity; // 发送身份信息
526
+ silent?: boolean; // 静默发送(不触发通知)
527
+ ```
528
+
529
+ ---
530
+
531
+ ## 导出变更(Export Changes)
532
+
533
+ | 导出名称 | 变更类型 | 说明 |
534
+ |----------|----------|------|
535
+ | `createAccountListHelpers` | 新增 | 账号列表辅助函数 |
536
+ | `BaseProbeResult` | 新增 | channel probe 结果基类型 |
537
+ | `BaseTokenResolution` | 新增 | token 解析结果基类型 |
538
+ | `AnyAgentTool` | 新增 | agent 工具的 any 联合类型 |
539
+ | `ProviderAuthContext` | 新增 | Provider 认证上下文 |
540
+ | `ProviderAuthResult` | 新增 | Provider 认证结果 |
541
+ | `RuntimeLogger` | 新增 | 运行时日志接口 |
542
+ | `ClawdbotConfig` | 新增(deprecated) | `OpenClawConfig` 的弃用别名 |
543
+ | `FileLockHandle` / `FileLockOptions` | 新增 | 文件锁类型 |
544
+ | `acquireFileLock` / `withFileLock` | 新增 | 文件锁 API |
545
+ | `normalizeWebhookPath` / `resolveWebhookPath` | 新增 | Webhook 路径辅助 |
546
+ | `registerWebhookTarget` 等 3 个函数 | 新增 | Webhook 目标注册 |
547
+ | `AgentMediaPayload` / `buildAgentMediaPayload` | 新增 | Agent 媒体载荷 |
548
+ | `buildBaseChannelStatusSummary` 等 3 个函数 | 新增 | Channel 状态辅助 |
549
+ | `buildOauthProviderAuthResult` | 新增 | OAuth Provider 认证结果构建 |
550
+ | `TtsAutoSchema` / `TtsConfigSchema` 等 | 新增 | TTS 配置 Schema |
551
+ | `formatAllowFromLowercase` / `isAllowedParsedChatSender` | 新增 | allowFrom 格式化与验证 |
552
+ | `resolveSenderCommandAuthorization` | 新增 | 命令发送方授权解析 |
553
+ | `handleSlackMessageAction` | 新增 | Slack 消息 action 处理 |
554
+ | `extractToolSend` | 新增 | 提取工具发送信息 |
555
+ | `resolveChannelAccountConfigBasePath` | 新增 | Channel 账号配置路径解析 |
556
+ | `chunkTextForOutbound` | 新增 | 出向文本分块 |
557
+ | `readJsonFileWithFallback` / `writeJsonFileAtomically` | 新增 | JSON 文件读写 |
558
+ | `buildRandomTempFilePath` / `withTempDownloadPath` | 新增 | 临时文件路径 |
559
+ | `ChatType` | 新增 | 聊天类型(替代 `NormalizedChatType`) |
560
+ | `RoutePeerKind` | 新增(deprecated) | `ChatType` 的弃用别名 |
561
+ | `createReplyPrefixOptions` | 新增 | reply prefix 选项创建(原有 `createReplyPrefixContext` 保留)|
562
+ | `resolveAllowlistMatchSimple` | 新增 | 简化版 allowlist 匹配 |
563
+ | `mergeAllowFromEntries` | 新增 | 合并 allowFrom 条目 |
564
+ | `clamp` / `escapeRegExp` / `safeParseJson` / `sleep` | 新增 | 通用工具函数(原有 `normalizeE164` 保留)|
565
+ | `stripAnsi` | 新增 | 去除 ANSI 转义字符 |
566
+ | `normalizeDiscordOutboundTarget` | 新增 | Discord 出向目标规范化 |
567
+ | `parseChatAllowTargetPrefixes` 等 4 个函数 | 新增 | iMessage 目标解析辅助 |
568
+ | `extractSlackToolSend` / `listSlackMessageActions` | 新增 | Slack 工具发送与 action 列表 |
569
+ | `parseTelegramReplyToMessageId` / `parseTelegramThreadId` | 新增 | Telegram 参数解析 |
570
+ | `TelegramProbe` | 新增 | Telegram probe 类型 |
571
+ | `resolveWhatsAppOutboundTarget` | 新增 | WhatsApp 出向目标解析 |
572
+ | `approveDevicePairing` 等 3 个函数 | 新增 | 设备配对管理 |
573
+ | `createDedupeCache` / `DedupeCache` | 新增 | 去重缓存 |
574
+ | `formatErrorMessage` | 新增 | 错误信息格式化 |
575
+ | 8 个 HTTP body 处理函数/类型 | 新增 | HTTP 请求体限制与解析 |
576
+ | `fetchWithSsrFGuard` | 新增 | 带 SSRF 防护的 fetch |
577
+ | `SsrFBlockedError` / `isBlockedHostname` 等 | 新增 | SSRF 防护 API |
578
+ | `rawDataToString` | 新增 | WebSocket 原始数据转字符串 |
579
+ | `isWSLSync` / `isWSL2Sync` / `isWSLEnv` | 新增 | WSL 环境检测 |
580
+ | `isTruthyEnvValue` | 新增 | 环境变量布尔值解析 |
581
+
582
+ ---
583
+
584
+ ## 对 `openclaw-web-hub-channel` 插件的影响
585
+
586
+ ### 影响评估
587
+
588
+ `openclaw-web-hub-channel` 插件(`src/index.ts`)目前使用 `api: any` 作为入参类型,**未直接导入 SDK 类型**,因此本次所有类型级变更对其**无直接影响**。
589
+
590
+ ### 需要修改的代码
591
+
592
+ | 文件 | 位置 | 原因 |
593
+ |------|------|------|
594
+ | 无需修改 | — | 插件使用 `api: any`,与 SDK 类型解耦 |
595
+
596
+ ### 可选优化建议(非必须)
597
+
598
+ 以下是可以利用新功能改善插件能力的可选项:
599
+
600
+ 1. **利用 `before_model_resolve` Hook**:如果插件需要按渠道路由不同模型,可使用此 Hook 动态覆盖模型。
601
+
602
+ 2. **利用 `llm_input` / `llm_output` Hook**:可用于记录 token 使用量、计费统计或内容审计日志。
603
+
604
+ 3. **利用 `before_message_write` Hook**:如需过滤大型 tool result 以减少存储,可使用此 Hook 在消息落盘前处理。
605
+
606
+ 4. **利用新增 webhook 辅助函数**:`registerWebhookTarget`、`normalizeWebhookPath` 等函数可简化 webhook 处理逻辑。
607
+
608
+ 5. **利用 SSRF 防护 API**:若插件接受用户输入的 URL 并发起请求,建议使用 `fetchWithSsrFGuard` 替代原生 `fetch`。
609
+
610
+ 6. **使用 `writeJsonFileAtomically`**:替代自定义的 JSON 文件写入逻辑,确保原子性。
611
+
612
+ ### 建议升级步骤
613
+
614
+ 1. 将插件中 `openclaw` 依赖版本更新至 `v2026.2.19`。
615
+ 2. 运行 `pnpm install` 更新依赖。
616
+ 3. 运行 `pnpm build`(或 `tsc --noEmit`)验证编译通过。
617
+ 4. 无需修改任何现有代码。
618
+ 5. 按需采纳可选优化建议。
619
+
620
+ ---
621
+
622
+ ## 变更摘要表
623
+
624
+ | 文件 | 新增 | 删除 | 修改 | 破坏性 |
625
+ |------|------|------|------|--------|
626
+ | `src/plugin-sdk/index.ts` | ~60+ 导出 | 0 | 3(路径/内容扩展) | 0 |
627
+ | `src/plugins/types.ts` | 9 个新类型,6 个新 Hook | 0 | 3(`PluginHookName` 扩展、`PluginHookBeforeAgentStartResult` 扩展、`PluginHookAgentContext` 新增字段) | 0 |
628
+ | `src/channels/plugins/types.core.ts` | 2 个新类型、多个可选字段 | 0 | 4(`ChannelAgentTool`、`ChannelAccountSnapshot`、`ChannelCapabilities`、`ChannelThreadingAdapter`、`ChannelMessageActionContext`、`ChannelPollContext`) | 0 |
629
+ | `src/channels/plugins/types.plugin.ts` | 0 | 0 | 1(`ChannelPlugin` 新增泛型参数) | 0 |
630
+ | `src/channels/plugins/types.adapters.ts` | 0 | 0 | 2(`ChannelStatusAdapter` 新增泛型参数、`ChannelOutboundContext` 新增字段) | 0 |
package/jest.config.js ADDED
@@ -0,0 +1,19 @@
1
+ /** @type {import('jest').Config} */
2
+ module.exports = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'node',
5
+ testMatch: ['**/*.test.ts'],
6
+ moduleNameMapper: {
7
+ '^openclaw/plugin-sdk$': '<rootDir>/node_modules/openclaw/dist/plugin-sdk/index',
8
+ },
9
+ globals: {
10
+ 'ts-jest': {
11
+ tsconfig: {
12
+ strict: true,
13
+ esModuleInterop: true,
14
+ moduleResolution: 'node',
15
+ paths: {},
16
+ },
17
+ },
18
+ },
19
+ };