openclaw-channel-xiaozhu 2.1.0 → 3.0.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.d.ts +183 -16
- package/dist/channel.d.ts.map +1 -1
- package/dist/channel.js +244 -25
- package/dist/channel.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/relay/client.d.ts.map +1 -1
- package/dist/relay/client.js +6 -2
- package/dist/relay/client.js.map +1 -1
- package/dist/server.d.ts +18 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +151 -2
- package/dist/server.js.map +1 -1
- package/dist/shared/inbound.js +1 -1
- package/dist/shared/inbound.js.map +1 -1
- package/dist/shared/security.d.ts +2 -1
- package/dist/shared/security.d.ts.map +1 -1
- package/dist/shared/security.js +3 -2
- package/dist/shared/security.js.map +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/openclaw-sessions.d.ts +79 -0
- package/dist/utils/openclaw-sessions.d.ts.map +1 -0
- package/dist/utils/openclaw-sessions.js +49 -0
- package/dist/utils/openclaw-sessions.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -1
- package/dist/utils/rate-limiter.js +2 -4
- package/dist/utils/rate-limiter.js.map +1 -1
- package/openclaw.plugin.json +138 -3
- package/package.json +8 -55
- package/skills/xiaozhu-cron-job/SKILL.md +6 -6
- package/LICENSE +0 -21
- package/README.md +0 -499
- package/demo/app.js +0 -350
- package/demo/index.html +0 -36
- package/demo/style.css +0 -249
- package/demo/think.css +0 -590
- package/demo/think.html +0 -92
- package/demo/think.js +0 -532
- package/dist/relay/cli.d.ts +0 -10
- package/dist/relay/cli.d.ts.map +0 -1
- package/dist/relay/cli.js +0 -28
- package/dist/relay/cli.js.map +0 -1
- package/dist/relay/server.d.ts +0 -16
- package/dist/relay/server.d.ts.map +0 -1
- package/dist/relay/server.js +0 -322
- package/dist/relay/server.js.map +0 -1
- package/dist/sdk/index.d.ts +0 -259
- package/dist/sdk/index.d.ts.map +0 -1
- package/dist/sdk/index.js +0 -415
- package/dist/sdk/index.js.map +0 -1
- package/dist/sdk/sse.d.ts +0 -18
- package/dist/sdk/sse.d.ts.map +0 -1
- package/dist/sdk/sse.js +0 -67
- package/dist/sdk/sse.js.map +0 -1
- package/dist/sdk/types.d.ts +0 -231
- package/dist/sdk/types.d.ts.map +0 -1
- package/dist/sdk/types.js +0 -5
- package/dist/sdk/types.js.map +0 -1
- package/dist/shared/errors.d.ts +0 -47
- package/dist/shared/errors.d.ts.map +0 -1
- package/dist/shared/errors.js +0 -52
- package/dist/shared/errors.js.map +0 -1
- package/dist/standalone/app.d.ts +0 -16
- package/dist/standalone/app.d.ts.map +0 -1
- package/dist/standalone/app.js +0 -194
- package/dist/standalone/app.js.map +0 -1
- package/dist/standalone/auth.d.ts +0 -19
- package/dist/standalone/auth.d.ts.map +0 -1
- package/dist/standalone/auth.js +0 -45
- package/dist/standalone/auth.js.map +0 -1
- package/dist/standalone/cli.d.ts +0 -10
- package/dist/standalone/cli.d.ts.map +0 -1
- package/dist/standalone/cli.js +0 -107
- package/dist/standalone/cli.js.map +0 -1
- package/dist/standalone/media-store.d.ts +0 -30
- package/dist/standalone/media-store.d.ts.map +0 -1
- package/dist/standalone/media-store.js +0 -150
- package/dist/standalone/media-store.js.map +0 -1
- package/dist/standalone/migrate-to-sqlite.d.ts +0 -10
- package/dist/standalone/migrate-to-sqlite.d.ts.map +0 -1
- package/dist/standalone/migrate-to-sqlite.js +0 -194
- package/dist/standalone/migrate-to-sqlite.js.map +0 -1
- package/dist/standalone/router.d.ts +0 -34
- package/dist/standalone/router.d.ts.map +0 -1
- package/dist/standalone/router.js +0 -94
- package/dist/standalone/router.js.map +0 -1
- package/dist/standalone/routes.d.ts +0 -12
- package/dist/standalone/routes.d.ts.map +0 -1
- package/dist/standalone/routes.js +0 -508
- package/dist/standalone/routes.js.map +0 -1
- package/dist/standalone/server-context.d.ts +0 -73
- package/dist/standalone/server-context.d.ts.map +0 -1
- package/dist/standalone/server-context.js +0 -38
- package/dist/standalone/server-context.js.map +0 -1
- package/dist/standalone/store.d.ts +0 -36
- package/dist/standalone/store.d.ts.map +0 -1
- package/dist/standalone/store.js +0 -163
- package/dist/standalone/store.js.map +0 -1
- package/dist/standalone/thought-db.d.ts +0 -92
- package/dist/standalone/thought-db.d.ts.map +0 -1
- package/dist/standalone/thought-db.js +0 -677
- package/dist/standalone/thought-db.js.map +0 -1
- package/dist/standalone/thought-processor.d.ts +0 -36
- package/dist/standalone/thought-processor.d.ts.map +0 -1
- package/dist/standalone/thought-processor.js +0 -352
- package/dist/standalone/thought-processor.js.map +0 -1
- package/dist/standalone/thought-routes.d.ts +0 -13
- package/dist/standalone/thought-routes.d.ts.map +0 -1
- package/dist/standalone/thought-routes.js +0 -326
- package/dist/standalone/thought-routes.js.map +0 -1
- package/dist/standalone/thought-store-factory.d.ts +0 -12
- package/dist/standalone/thought-store-factory.d.ts.map +0 -1
- package/dist/standalone/thought-store-factory.js +0 -20
- package/dist/standalone/thought-store-factory.js.map +0 -1
- package/dist/standalone/thought-store.d.ts +0 -103
- package/dist/standalone/thought-store.d.ts.map +0 -1
- package/dist/standalone/thought-store.js +0 -502
- package/dist/standalone/thought-store.js.map +0 -1
- package/dist/standalone/thought-types.d.ts +0 -169
- package/dist/standalone/thought-types.d.ts.map +0 -1
- package/dist/standalone/thought-types.js +0 -5
- package/dist/standalone/thought-types.js.map +0 -1
- package/dist/standalone/types.d.ts +0 -105
- package/dist/standalone/types.d.ts.map +0 -1
- package/dist/standalone/types.js +0 -5
- package/dist/standalone/types.js.map +0 -1
- package/dist/standalone/ws-handler.d.ts +0 -16
- package/dist/standalone/ws-handler.d.ts.map +0 -1
- package/dist/standalone/ws-handler.js +0 -183
- package/dist/standalone/ws-handler.js.map +0 -1
- package/docs/API.md +0 -1844
- package/docs/DEVELOPMENT.md +0 -299
- package/docs/MILESTONES.md +0 -135
- package/docs/RISKS.md +0 -179
- package/docs/ROADMAP.md +0 -144
package/dist/channel.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Channel 插件对象 — config / gateway / outbound / status
|
|
2
|
+
* Channel 插件对象 — 16 个适配器(config / gateway / outbound / status +
|
|
3
|
+
* messaging / groups / mentions / pairing / security / commands /
|
|
4
|
+
* streaming / threading / agentPrompt / directory / actions / heartbeat)
|
|
3
5
|
*/
|
|
4
6
|
import type { HttpApiAccount, PluginRuntime, ChannelConfig, GatewayContext } from "./types.js";
|
|
5
7
|
export declare function setRuntime(rt: PluginRuntime): void;
|
|
@@ -10,6 +12,7 @@ export declare const httpChannelPlugin: {
|
|
|
10
12
|
label: string;
|
|
11
13
|
selectionLabel: string;
|
|
12
14
|
blurb: string;
|
|
15
|
+
docsPath: string;
|
|
13
16
|
order: number;
|
|
14
17
|
aliases: string[];
|
|
15
18
|
};
|
|
@@ -20,17 +23,15 @@ export declare const httpChannelPlugin: {
|
|
|
20
23
|
media: boolean;
|
|
21
24
|
nativeCommands: boolean;
|
|
22
25
|
blockStreaming: boolean;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
heartbeat: boolean;
|
|
29
|
-
webhookSigning: boolean;
|
|
26
|
+
};
|
|
27
|
+
defaults: {
|
|
28
|
+
queue: {
|
|
29
|
+
debounceMs: number;
|
|
30
|
+
};
|
|
30
31
|
};
|
|
31
32
|
config: {
|
|
32
33
|
listAccountIds: (cfg: ChannelConfig) => string[];
|
|
33
|
-
resolveAccount: (cfg: ChannelConfig, accountId
|
|
34
|
+
resolveAccount: (cfg: ChannelConfig, accountId?: string | null) => HttpApiAccount;
|
|
34
35
|
defaultAccountId: (_cfg: ChannelConfig) => string;
|
|
35
36
|
isConfigured: (account: HttpApiAccount) => boolean;
|
|
36
37
|
describeAccount: (account: HttpApiAccount) => {
|
|
@@ -38,11 +39,6 @@ export declare const httpChannelPlugin: {
|
|
|
38
39
|
name: string;
|
|
39
40
|
enabled: boolean;
|
|
40
41
|
configured: boolean;
|
|
41
|
-
features: {
|
|
42
|
-
perIpRateLimit: boolean;
|
|
43
|
-
webhookSigning: boolean;
|
|
44
|
-
commands: boolean;
|
|
45
|
-
};
|
|
46
42
|
};
|
|
47
43
|
setAccountEnabled: ({ cfg, accountId, enabled }: {
|
|
48
44
|
cfg: ChannelConfig;
|
|
@@ -50,7 +46,7 @@ export declare const httpChannelPlugin: {
|
|
|
50
46
|
enabled: boolean;
|
|
51
47
|
}) => {
|
|
52
48
|
channels: {
|
|
53
|
-
"channel-xiaozhu": {
|
|
49
|
+
"openclaw-channel-xiaozhu": {
|
|
54
50
|
accounts: {
|
|
55
51
|
[x: string]: Record<string, unknown>;
|
|
56
52
|
};
|
|
@@ -58,7 +54,7 @@ export declare const httpChannelPlugin: {
|
|
|
58
54
|
};
|
|
59
55
|
} | {
|
|
60
56
|
channels: {
|
|
61
|
-
"channel-xiaozhu": {
|
|
57
|
+
"openclaw-channel-xiaozhu": {
|
|
62
58
|
enabled: boolean;
|
|
63
59
|
};
|
|
64
60
|
};
|
|
@@ -71,6 +67,16 @@ export declare const httpChannelPlugin: {
|
|
|
71
67
|
[x: string]: Record<string, unknown>;
|
|
72
68
|
};
|
|
73
69
|
};
|
|
70
|
+
resolveAllowFrom: ({ cfg, accountId }: {
|
|
71
|
+
cfg: ChannelConfig;
|
|
72
|
+
accountId?: string | null;
|
|
73
|
+
}) => string[] | undefined;
|
|
74
|
+
formatAllowFrom: ({ allowFrom }: {
|
|
75
|
+
cfg: ChannelConfig;
|
|
76
|
+
accountId?: string | null;
|
|
77
|
+
allowFrom: Array<string | number>;
|
|
78
|
+
}) => string[];
|
|
79
|
+
resolveDefaultTo: () => string | undefined;
|
|
74
80
|
};
|
|
75
81
|
gateway: {
|
|
76
82
|
startAccount: (ctx: GatewayContext) => Promise<void>;
|
|
@@ -78,6 +84,8 @@ export declare const httpChannelPlugin: {
|
|
|
78
84
|
outbound: {
|
|
79
85
|
deliveryMode: "direct";
|
|
80
86
|
textChunkLimit: number;
|
|
87
|
+
chunker: (text: string, limit: number) => string[];
|
|
88
|
+
chunkerMode: "markdown";
|
|
81
89
|
sendText: (opts: Record<string, unknown>) => Promise<{
|
|
82
90
|
channel: string;
|
|
83
91
|
ok: boolean;
|
|
@@ -96,6 +104,22 @@ export declare const httpChannelPlugin: {
|
|
|
96
104
|
ok: boolean;
|
|
97
105
|
error?: undefined;
|
|
98
106
|
}>;
|
|
107
|
+
sendPayload: (ctx: Record<string, unknown>) => Promise<{
|
|
108
|
+
channel: string;
|
|
109
|
+
ok: boolean;
|
|
110
|
+
error: Error;
|
|
111
|
+
messageId?: undefined;
|
|
112
|
+
} | {
|
|
113
|
+
channel: string;
|
|
114
|
+
ok: boolean;
|
|
115
|
+
error: Error;
|
|
116
|
+
messageId: string;
|
|
117
|
+
} | {
|
|
118
|
+
channel: string;
|
|
119
|
+
ok: boolean;
|
|
120
|
+
messageId: string;
|
|
121
|
+
error?: undefined;
|
|
122
|
+
}>;
|
|
99
123
|
};
|
|
100
124
|
status: {
|
|
101
125
|
defaultRuntime: {
|
|
@@ -103,7 +127,10 @@ export declare const httpChannelPlugin: {
|
|
|
103
127
|
running: boolean;
|
|
104
128
|
connected: boolean;
|
|
105
129
|
lastStartAt: null;
|
|
130
|
+
lastStopAt: null;
|
|
106
131
|
lastError: null;
|
|
132
|
+
lastInboundAt: null;
|
|
133
|
+
lastOutboundAt: null;
|
|
107
134
|
};
|
|
108
135
|
probeAccount: ({ account, timeoutMs }: {
|
|
109
136
|
account: HttpApiAccount;
|
|
@@ -112,6 +139,146 @@ export declare const httpChannelPlugin: {
|
|
|
112
139
|
ok: boolean;
|
|
113
140
|
latencyMs: number;
|
|
114
141
|
}>;
|
|
142
|
+
buildAccountSnapshot: ({ account, runtime }: {
|
|
143
|
+
account: HttpApiAccount;
|
|
144
|
+
cfg: ChannelConfig;
|
|
145
|
+
runtime?: Record<string, unknown>;
|
|
146
|
+
}) => {
|
|
147
|
+
accountId: string;
|
|
148
|
+
name: string;
|
|
149
|
+
enabled: boolean;
|
|
150
|
+
configured: boolean;
|
|
151
|
+
running: boolean;
|
|
152
|
+
connected: boolean;
|
|
153
|
+
lastStartAt: number | null;
|
|
154
|
+
lastStopAt: number | null;
|
|
155
|
+
lastError: string | null;
|
|
156
|
+
mode: "webhook" | "cloud";
|
|
157
|
+
lastInboundAt: number | null;
|
|
158
|
+
lastOutboundAt: number | null;
|
|
159
|
+
};
|
|
160
|
+
buildChannelSummary: ({ snapshot }: {
|
|
161
|
+
account: HttpApiAccount;
|
|
162
|
+
cfg: ChannelConfig;
|
|
163
|
+
defaultAccountId: string;
|
|
164
|
+
snapshot: Record<string, unknown>;
|
|
165
|
+
}) => {
|
|
166
|
+
configured: boolean;
|
|
167
|
+
running: boolean;
|
|
168
|
+
connected: boolean;
|
|
169
|
+
mode: string;
|
|
170
|
+
lastStartAt: {} | null;
|
|
171
|
+
lastStopAt: {} | null;
|
|
172
|
+
lastError: {} | null;
|
|
173
|
+
lastInboundAt: {} | null;
|
|
174
|
+
lastOutboundAt: {} | null;
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
messaging: {
|
|
178
|
+
normalizeTarget: (raw: string) => string | undefined;
|
|
179
|
+
targetResolver: {
|
|
180
|
+
looksLikeId: (raw: string) => boolean;
|
|
181
|
+
hint: string;
|
|
182
|
+
};
|
|
183
|
+
formatTargetDisplay: ({ target, display }: {
|
|
184
|
+
target: string;
|
|
185
|
+
display?: string;
|
|
186
|
+
kind?: string;
|
|
187
|
+
}) => string;
|
|
188
|
+
};
|
|
189
|
+
groups: {
|
|
190
|
+
resolveRequireMention: ({ cfg, accountId }: {
|
|
191
|
+
cfg: ChannelConfig;
|
|
192
|
+
accountId?: string | null;
|
|
193
|
+
}) => boolean | undefined;
|
|
194
|
+
resolveGroupIntroHint: ({ cfg, accountId }: {
|
|
195
|
+
cfg: ChannelConfig;
|
|
196
|
+
accountId?: string | null;
|
|
197
|
+
}) => string | undefined;
|
|
198
|
+
};
|
|
199
|
+
mentions: {
|
|
200
|
+
stripPatterns: () => string[];
|
|
201
|
+
stripMentions: ({ text }: {
|
|
202
|
+
text: string;
|
|
203
|
+
}) => string;
|
|
204
|
+
};
|
|
205
|
+
pairing: {
|
|
206
|
+
idLabel: string;
|
|
207
|
+
normalizeAllowEntry: (entry: string) => string;
|
|
208
|
+
notifyApproval: () => Promise<void>;
|
|
209
|
+
};
|
|
210
|
+
security: {
|
|
211
|
+
resolveDmPolicy: () => null;
|
|
212
|
+
collectWarnings: ({ account }: {
|
|
213
|
+
account: HttpApiAccount;
|
|
214
|
+
}) => string[];
|
|
215
|
+
};
|
|
216
|
+
commands: {
|
|
217
|
+
enforceOwnerForCommands: boolean;
|
|
218
|
+
skipWhenConfigEmpty: boolean;
|
|
219
|
+
};
|
|
220
|
+
streaming: {
|
|
221
|
+
blockStreamingCoalesceDefaults: {
|
|
222
|
+
minChars: number;
|
|
223
|
+
idleMs: number;
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
threading: {
|
|
227
|
+
resolveReplyToMode: ({ cfg, accountId }: {
|
|
228
|
+
cfg: ChannelConfig;
|
|
229
|
+
accountId?: string | null;
|
|
230
|
+
}) => "off" | "first" | "all";
|
|
231
|
+
allowExplicitReplyTagsWhenOff: boolean;
|
|
232
|
+
};
|
|
233
|
+
agentPrompt: {
|
|
234
|
+
messageToolHints: () => string[];
|
|
235
|
+
};
|
|
236
|
+
directory: {
|
|
237
|
+
self: ({ accountId }: {
|
|
238
|
+
accountId?: string;
|
|
239
|
+
}) => Promise<{
|
|
240
|
+
id: string;
|
|
241
|
+
name: string;
|
|
242
|
+
kind: string;
|
|
243
|
+
} | null>;
|
|
244
|
+
listPeers: ({ accountId }: {
|
|
245
|
+
accountId?: string;
|
|
246
|
+
}) => Promise<{
|
|
247
|
+
id: string;
|
|
248
|
+
name: string;
|
|
249
|
+
kind: string;
|
|
250
|
+
}[]>;
|
|
251
|
+
listGroups: ({ accountId }: {
|
|
252
|
+
accountId?: string;
|
|
253
|
+
}) => Promise<{
|
|
254
|
+
id: string;
|
|
255
|
+
name: string;
|
|
256
|
+
kind: string;
|
|
257
|
+
}[]>;
|
|
258
|
+
};
|
|
259
|
+
actions: {
|
|
260
|
+
listActions: () => string[];
|
|
261
|
+
supportsAction: ({ action }: {
|
|
262
|
+
action: string;
|
|
263
|
+
}) => boolean;
|
|
264
|
+
supportsButtons: () => boolean;
|
|
265
|
+
supportsCards: () => boolean;
|
|
266
|
+
};
|
|
267
|
+
heartbeat: {
|
|
268
|
+
checkReady: ({ cfg, accountId }: {
|
|
269
|
+
cfg: ChannelConfig;
|
|
270
|
+
accountId?: string | null;
|
|
271
|
+
}) => Promise<{
|
|
272
|
+
ok: boolean;
|
|
273
|
+
reason: string;
|
|
274
|
+
}>;
|
|
275
|
+
resolveRecipients: ({ cfg, accountId }: {
|
|
276
|
+
cfg: ChannelConfig;
|
|
277
|
+
accountId?: string | null;
|
|
278
|
+
}) => {
|
|
279
|
+
recipients: string[];
|
|
280
|
+
source: string;
|
|
281
|
+
};
|
|
115
282
|
};
|
|
116
283
|
};
|
|
117
284
|
//# sourceMappingURL=channel.d.ts.map
|
package/dist/channel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
|
package/dist/channel.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Channel 插件对象 — config / gateway / outbound / status
|
|
2
|
+
* Channel 插件对象 — 16 个适配器(config / gateway / outbound / status +
|
|
3
|
+
* messaging / groups / mentions / pairing / security / commands /
|
|
4
|
+
* streaming / threading / agentPrompt / directory / actions / heartbeat)
|
|
3
5
|
*/
|
|
4
|
-
import { startHttpServer, getRuntimeWebhookUrl } from "./server.js";
|
|
6
|
+
import { startHttpServer, getRuntimeWebhookUrl, getAccountState } from "./server.js";
|
|
5
7
|
import { startRelayClient } from "./relay/client.js";
|
|
6
8
|
import { sendWithRetry } from "./utils/webhook-sender.js";
|
|
7
9
|
import { chunkText } from "./utils/text-chunker.js";
|
|
8
|
-
const CHANNEL_ID = "channel-xiaozhu";
|
|
10
|
+
const CHANNEL_ID = "openclaw-channel-xiaozhu";
|
|
9
11
|
const DEFAULT_PORT = 18800;
|
|
10
12
|
const DEFAULT_RELAY_URL = "wss://relay.xiaozhu.ai/ws/bot";
|
|
11
13
|
let pluginRuntime = null;
|
|
@@ -46,15 +48,24 @@ function parseAccountFromRaw(raw, accountId) {
|
|
|
46
48
|
networkMode: raw.networkMode,
|
|
47
49
|
relayUrl: raw.relayUrl,
|
|
48
50
|
relayToken: raw.relayToken,
|
|
51
|
+
requireMention: raw.requireMention,
|
|
52
|
+
groupIntroHint: raw.groupIntroHint,
|
|
53
|
+
replyToMode: raw.replyToMode,
|
|
54
|
+
dmPolicy: raw.dmPolicy,
|
|
49
55
|
};
|
|
50
56
|
}
|
|
57
|
+
/** 解析账号的快捷方式(供多个适配器复用) */
|
|
58
|
+
function resolveAccount(cfg, accountId) {
|
|
59
|
+
return httpChannelPlugin.config.resolveAccount(cfg, accountId || "default");
|
|
60
|
+
}
|
|
51
61
|
export const httpChannelPlugin = {
|
|
52
62
|
id: CHANNEL_ID,
|
|
53
63
|
meta: {
|
|
54
64
|
id: CHANNEL_ID,
|
|
55
65
|
label: "小助",
|
|
56
|
-
selectionLabel: "小助",
|
|
66
|
+
selectionLabel: "小助 (HTTP/SSE)",
|
|
57
67
|
blurb: "通过 HTTP/SSE 接口接入对话的通用渠道",
|
|
68
|
+
docsPath: "/docs/channels/xiaozhu",
|
|
58
69
|
order: 90,
|
|
59
70
|
aliases: ["xiaozhu", "http", "api", "rest"],
|
|
60
71
|
},
|
|
@@ -65,13 +76,9 @@ export const httpChannelPlugin = {
|
|
|
65
76
|
media: true,
|
|
66
77
|
nativeCommands: true,
|
|
67
78
|
blockStreaming: true,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
tts: true,
|
|
72
|
-
typing: true,
|
|
73
|
-
heartbeat: true,
|
|
74
|
-
webhookSigning: true,
|
|
79
|
+
},
|
|
80
|
+
defaults: {
|
|
81
|
+
queue: { debounceMs: 300 },
|
|
75
82
|
},
|
|
76
83
|
// ── config 适配器 ──
|
|
77
84
|
config: {
|
|
@@ -90,14 +97,15 @@ export const httpChannelPlugin = {
|
|
|
90
97
|
},
|
|
91
98
|
resolveAccount: (cfg, accountId) => {
|
|
92
99
|
const ch = getChannelConfig(cfg) || {};
|
|
100
|
+
const id = accountId || "default";
|
|
93
101
|
// 多账号模式
|
|
94
102
|
if (ch.accounts && typeof ch.accounts === "object" && !Array.isArray(ch.accounts)) {
|
|
95
103
|
const accounts = ch.accounts;
|
|
96
|
-
const raw = accounts[
|
|
97
|
-
return parseAccountFromRaw(raw,
|
|
104
|
+
const raw = accounts[id] || {};
|
|
105
|
+
return parseAccountFromRaw(raw, id);
|
|
98
106
|
}
|
|
99
107
|
// 单账号模式
|
|
100
|
-
return parseAccountFromRaw(ch,
|
|
108
|
+
return parseAccountFromRaw(ch, id);
|
|
101
109
|
},
|
|
102
110
|
defaultAccountId: (_cfg) => "default",
|
|
103
111
|
isConfigured: (account) => {
|
|
@@ -108,36 +116,35 @@ export const httpChannelPlugin = {
|
|
|
108
116
|
name: `小助 :${account.port}`,
|
|
109
117
|
enabled: account.enabled,
|
|
110
118
|
configured: !!account.token,
|
|
111
|
-
features: {
|
|
112
|
-
perIpRateLimit: !!account.perIpRateLimit,
|
|
113
|
-
webhookSigning: !!account.webhookSecret,
|
|
114
|
-
commands: account.commandsEnabled !== false,
|
|
115
|
-
},
|
|
116
119
|
}),
|
|
117
120
|
setAccountEnabled: ({ cfg, accountId, enabled }) => {
|
|
118
121
|
const ch = getChannelConfig(cfg) || {};
|
|
119
|
-
// 多账号模式:设置具体账号的 enabled
|
|
120
122
|
if (ch.accounts && typeof ch.accounts === "object" && !Array.isArray(ch.accounts)) {
|
|
121
123
|
const accounts = { ...ch.accounts };
|
|
122
124
|
accounts[accountId] = { ...accounts[accountId], enabled };
|
|
123
125
|
return { ...cfg, channels: { ...cfg.channels, [CHANNEL_ID]: { ...ch, accounts } } };
|
|
124
126
|
}
|
|
125
|
-
// 单账号模式
|
|
126
127
|
return { ...cfg, channels: { ...cfg.channels, [CHANNEL_ID]: { ...ch, enabled } } };
|
|
127
128
|
},
|
|
128
129
|
deleteAccount: ({ cfg, accountId }) => {
|
|
129
130
|
const ch = getChannelConfig(cfg) || {};
|
|
130
|
-
// 多账号模式:只删除指定账号
|
|
131
131
|
if (ch.accounts && typeof ch.accounts === "object" && !Array.isArray(ch.accounts)) {
|
|
132
132
|
const accounts = { ...ch.accounts };
|
|
133
133
|
delete accounts[accountId];
|
|
134
134
|
return { ...cfg, channels: { ...cfg.channels, [CHANNEL_ID]: { ...ch, accounts } } };
|
|
135
135
|
}
|
|
136
|
-
// 单账号模式:删除整个渠道
|
|
137
136
|
const channels = { ...cfg.channels };
|
|
138
137
|
delete channels[CHANNEL_ID];
|
|
139
138
|
return { ...cfg, channels };
|
|
140
139
|
},
|
|
140
|
+
resolveAllowFrom: ({ cfg, accountId }) => {
|
|
141
|
+
const account = resolveAccount(cfg, accountId);
|
|
142
|
+
return account.allowFrom;
|
|
143
|
+
},
|
|
144
|
+
formatAllowFrom: ({ allowFrom }) => {
|
|
145
|
+
return allowFrom.map((e) => String(e).trim()).filter(Boolean);
|
|
146
|
+
},
|
|
147
|
+
resolveDefaultTo: () => undefined,
|
|
141
148
|
},
|
|
142
149
|
// ── gateway 适配器 ──
|
|
143
150
|
gateway: {
|
|
@@ -212,6 +219,8 @@ export const httpChannelPlugin = {
|
|
|
212
219
|
outbound: {
|
|
213
220
|
deliveryMode: "direct",
|
|
214
221
|
textChunkLimit: 4000,
|
|
222
|
+
chunker: (text, limit) => chunkText(text, { maxLength: limit }),
|
|
223
|
+
chunkerMode: "markdown",
|
|
215
224
|
sendText: async (opts) => {
|
|
216
225
|
const account = opts?.account;
|
|
217
226
|
const text = opts?.text || "";
|
|
@@ -223,7 +232,6 @@ export const httpChannelPlugin = {
|
|
|
223
232
|
if (!text) {
|
|
224
233
|
return { channel: CHANNEL_ID, ok: true };
|
|
225
234
|
}
|
|
226
|
-
// Fence-aware chunking for long messages
|
|
227
235
|
const chunks = chunkText(text, { maxLength: account?.textChunkLimit || 4000 });
|
|
228
236
|
for (const chunk of chunks) {
|
|
229
237
|
const result = await sendWithRetry({
|
|
@@ -264,6 +272,40 @@ export const httpChannelPlugin = {
|
|
|
264
272
|
}
|
|
265
273
|
return { channel: CHANNEL_ID, ok: true };
|
|
266
274
|
},
|
|
275
|
+
sendPayload: async (ctx) => {
|
|
276
|
+
const cfg = ctx.cfg;
|
|
277
|
+
const accountId = ctx.accountId;
|
|
278
|
+
const to = ctx.to;
|
|
279
|
+
const payload = ctx.payload;
|
|
280
|
+
const account = cfg ? resolveAccount(cfg, accountId) : undefined;
|
|
281
|
+
const webhookUrl = getRuntimeWebhookUrl(accountId) || account?.webhookUrl;
|
|
282
|
+
if (!webhookUrl) {
|
|
283
|
+
return { channel: CHANNEL_ID, ok: false, error: new Error("No webhookUrl configured for payload delivery") };
|
|
284
|
+
}
|
|
285
|
+
// 优先发送渠道专属数据(channelData.xiaozhu),回退到通用 text
|
|
286
|
+
const channelData = payload?.channelData?.xiaozhu;
|
|
287
|
+
const webhookPayload = channelData || {
|
|
288
|
+
type: "payload",
|
|
289
|
+
text: payload?.text || "",
|
|
290
|
+
session: to || "",
|
|
291
|
+
from: "openclaw",
|
|
292
|
+
channel: CHANNEL_ID,
|
|
293
|
+
timestamp: Date.now(),
|
|
294
|
+
...(payload?.mediaUrl ? { mediaUrl: payload.mediaUrl } : {}),
|
|
295
|
+
};
|
|
296
|
+
const result = await sendWithRetry({
|
|
297
|
+
url: webhookUrl,
|
|
298
|
+
payload: webhookPayload,
|
|
299
|
+
token: account?.token || "",
|
|
300
|
+
secret: account?.webhookSecret,
|
|
301
|
+
maxAttempts: account?.webhookRetry?.maxAttempts ?? 3,
|
|
302
|
+
baseDelayMs: account?.webhookRetry?.baseDelayMs ?? 1000,
|
|
303
|
+
});
|
|
304
|
+
if (!result.ok) {
|
|
305
|
+
return { channel: CHANNEL_ID, ok: false, error: result.error || new Error("Webhook payload failed"), messageId: "" };
|
|
306
|
+
}
|
|
307
|
+
return { channel: CHANNEL_ID, ok: true, messageId: "" };
|
|
308
|
+
},
|
|
267
309
|
},
|
|
268
310
|
// ── status 适配器 ──
|
|
269
311
|
status: {
|
|
@@ -272,12 +314,20 @@ export const httpChannelPlugin = {
|
|
|
272
314
|
running: false,
|
|
273
315
|
connected: false,
|
|
274
316
|
lastStartAt: null,
|
|
317
|
+
lastStopAt: null,
|
|
275
318
|
lastError: null,
|
|
319
|
+
lastInboundAt: null,
|
|
320
|
+
lastOutboundAt: null,
|
|
276
321
|
},
|
|
277
322
|
probeAccount: async ({ account, timeoutMs }) => {
|
|
278
323
|
const start = Date.now();
|
|
279
324
|
try {
|
|
280
|
-
const
|
|
325
|
+
const ctrl = new AbortController();
|
|
326
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs ?? 3000);
|
|
327
|
+
if (timer.unref)
|
|
328
|
+
timer.unref();
|
|
329
|
+
const res = await fetch(`http://127.0.0.1:${account.port}/api/health`, { signal: ctrl.signal });
|
|
330
|
+
clearTimeout(timer);
|
|
281
331
|
const latencyMs = Date.now() - start;
|
|
282
332
|
let data = null;
|
|
283
333
|
try {
|
|
@@ -290,6 +340,175 @@ export const httpChannelPlugin = {
|
|
|
290
340
|
return { ok: false, latencyMs: Date.now() - start };
|
|
291
341
|
}
|
|
292
342
|
},
|
|
343
|
+
buildAccountSnapshot: ({ account, runtime }) => ({
|
|
344
|
+
accountId: account.accountId,
|
|
345
|
+
name: `小助 :${account.port}`,
|
|
346
|
+
enabled: account.enabled,
|
|
347
|
+
configured: !!account.token,
|
|
348
|
+
running: runtime?.running ?? false,
|
|
349
|
+
connected: runtime?.connected ?? false,
|
|
350
|
+
lastStartAt: runtime?.lastStartAt ?? null,
|
|
351
|
+
lastStopAt: runtime?.lastStopAt ?? null,
|
|
352
|
+
lastError: runtime?.lastError ?? null,
|
|
353
|
+
mode: account.networkMode || "webhook",
|
|
354
|
+
lastInboundAt: runtime?.lastInboundAt ?? null,
|
|
355
|
+
lastOutboundAt: runtime?.lastOutboundAt ?? null,
|
|
356
|
+
}),
|
|
357
|
+
buildChannelSummary: ({ snapshot }) => ({
|
|
358
|
+
configured: snapshot.configured ?? false,
|
|
359
|
+
running: snapshot.running ?? false,
|
|
360
|
+
connected: snapshot.connected ?? false,
|
|
361
|
+
mode: snapshot.mode ?? "webhook",
|
|
362
|
+
lastStartAt: snapshot.lastStartAt ?? null,
|
|
363
|
+
lastStopAt: snapshot.lastStopAt ?? null,
|
|
364
|
+
lastError: snapshot.lastError ?? null,
|
|
365
|
+
lastInboundAt: snapshot.lastInboundAt ?? null,
|
|
366
|
+
lastOutboundAt: snapshot.lastOutboundAt ?? null,
|
|
367
|
+
}),
|
|
368
|
+
},
|
|
369
|
+
// ── messaging 适配器 ──
|
|
370
|
+
messaging: {
|
|
371
|
+
normalizeTarget: (raw) => {
|
|
372
|
+
const trimmed = raw.trim().toLowerCase();
|
|
373
|
+
return trimmed || undefined;
|
|
374
|
+
},
|
|
375
|
+
targetResolver: {
|
|
376
|
+
looksLikeId: (raw) => /^[\w.@:+\-]{1,128}$/.test(raw.trim()),
|
|
377
|
+
hint: "用户 ID(字母、数字、下划线、点、@、冒号、加号、减号)",
|
|
378
|
+
},
|
|
379
|
+
formatTargetDisplay: ({ target, display }) => {
|
|
380
|
+
return display || target;
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
// ── groups 适配器 ──
|
|
384
|
+
groups: {
|
|
385
|
+
resolveRequireMention: ({ cfg, accountId }) => {
|
|
386
|
+
const account = resolveAccount(cfg, accountId);
|
|
387
|
+
return account.requireMention;
|
|
388
|
+
},
|
|
389
|
+
resolveGroupIntroHint: ({ cfg, accountId }) => {
|
|
390
|
+
const account = resolveAccount(cfg, accountId);
|
|
391
|
+
return account.groupIntroHint;
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
// ── mentions 适配器 ──
|
|
395
|
+
mentions: {
|
|
396
|
+
stripPatterns: () => [
|
|
397
|
+
"^@小助\\s*",
|
|
398
|
+
"^@xiaozhu\\s*",
|
|
399
|
+
"^@bot\\s*",
|
|
400
|
+
],
|
|
401
|
+
stripMentions: ({ text }) => {
|
|
402
|
+
return text.replace(/^@(?:小助|xiaozhu|bot)\s*/i, "").trim();
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
// ── pairing 适配器 ──
|
|
406
|
+
pairing: {
|
|
407
|
+
idLabel: "用户 ID",
|
|
408
|
+
normalizeAllowEntry: (entry) => entry.trim().toLowerCase(),
|
|
409
|
+
notifyApproval: async () => {
|
|
410
|
+
// HTTP 渠道无原生推送通道,审批通知通过 webhook 推送(如已配置)
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
// ── security 适配器 ──
|
|
414
|
+
security: {
|
|
415
|
+
resolveDmPolicy: () => null, // 使用 OpenClaw 默认策略(HTTP 已有 token 鉴权)
|
|
416
|
+
collectWarnings: ({ account }) => {
|
|
417
|
+
const warnings = [];
|
|
418
|
+
if (!account.token)
|
|
419
|
+
warnings.push("未配置 token,服务不可用");
|
|
420
|
+
if (account.allowFrom?.includes("*"))
|
|
421
|
+
warnings.push("allowFrom 设为 *,任何人可发送消息");
|
|
422
|
+
if (!account.webhookUrl && account.networkMode !== "cloud") {
|
|
423
|
+
warnings.push("未配置 webhookUrl,outbound 消息无法推送");
|
|
424
|
+
}
|
|
425
|
+
return warnings;
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
// ── commands 适配器 ──
|
|
429
|
+
commands: {
|
|
430
|
+
enforceOwnerForCommands: false,
|
|
431
|
+
skipWhenConfigEmpty: false,
|
|
432
|
+
},
|
|
433
|
+
// ── streaming 适配器 ──
|
|
434
|
+
streaming: {
|
|
435
|
+
blockStreamingCoalesceDefaults: { minChars: 200, idleMs: 500 },
|
|
436
|
+
},
|
|
437
|
+
// ── threading 适配器 ──
|
|
438
|
+
threading: {
|
|
439
|
+
resolveReplyToMode: ({ cfg, accountId }) => {
|
|
440
|
+
if (!accountId)
|
|
441
|
+
return "off";
|
|
442
|
+
const account = resolveAccount(cfg, accountId);
|
|
443
|
+
return account.replyToMode || "off";
|
|
444
|
+
},
|
|
445
|
+
allowExplicitReplyTagsWhenOff: false,
|
|
446
|
+
},
|
|
447
|
+
// ── agentPrompt 适配器 ──
|
|
448
|
+
agentPrompt: {
|
|
449
|
+
messageToolHints: () => [
|
|
450
|
+
"用户通过 HTTP API 发送消息,支持文本、图片、文件和语音",
|
|
451
|
+
"回复支持 Markdown 格式,长回复会自动分块(围栏感知)",
|
|
452
|
+
],
|
|
453
|
+
},
|
|
454
|
+
// ── directory 适配器 ──
|
|
455
|
+
directory: {
|
|
456
|
+
self: async ({ accountId }) => {
|
|
457
|
+
return {
|
|
458
|
+
id: `${CHANNEL_ID}:${accountId || "default"}`,
|
|
459
|
+
name: `小助 (${accountId || "default"})`,
|
|
460
|
+
kind: "bot",
|
|
461
|
+
};
|
|
462
|
+
},
|
|
463
|
+
listPeers: async ({ accountId }) => {
|
|
464
|
+
const state = getAccountState(accountId);
|
|
465
|
+
if (!state)
|
|
466
|
+
return [];
|
|
467
|
+
const sessions = state.sessionStore.list({ accountId, chatType: "direct" });
|
|
468
|
+
const seen = new Set();
|
|
469
|
+
return sessions
|
|
470
|
+
.filter((s) => { if (seen.has(s.from))
|
|
471
|
+
return false; seen.add(s.from); return true; })
|
|
472
|
+
.map((s) => ({ id: s.from, name: s.from, kind: "user" }));
|
|
473
|
+
},
|
|
474
|
+
listGroups: async ({ accountId }) => {
|
|
475
|
+
const state = getAccountState(accountId);
|
|
476
|
+
if (!state)
|
|
477
|
+
return [];
|
|
478
|
+
return state.sessionStore.list({ accountId, chatType: "group" })
|
|
479
|
+
.map((s) => ({ id: s.session, name: s.session, kind: "group" }));
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
// ── actions 适配器 ──
|
|
483
|
+
actions: {
|
|
484
|
+
listActions: () => ["reply", "forward"],
|
|
485
|
+
supportsAction: ({ action }) => action === "reply" || action === "forward",
|
|
486
|
+
supportsButtons: () => false,
|
|
487
|
+
supportsCards: () => false,
|
|
488
|
+
},
|
|
489
|
+
// ── heartbeat 适配器 ──
|
|
490
|
+
heartbeat: {
|
|
491
|
+
checkReady: async ({ cfg, accountId }) => {
|
|
492
|
+
const account = resolveAccount(cfg, accountId);
|
|
493
|
+
try {
|
|
494
|
+
const ctrl = new AbortController();
|
|
495
|
+
const timer = setTimeout(() => ctrl.abort(), 3000);
|
|
496
|
+
if (timer.unref)
|
|
497
|
+
timer.unref();
|
|
498
|
+
const res = await fetch(`http://127.0.0.1:${account.port}/api/health`, { signal: ctrl.signal });
|
|
499
|
+
clearTimeout(timer);
|
|
500
|
+
const data = await res.json();
|
|
501
|
+
return { ok: data.ok === true, reason: data.ok ? "healthy" : "health check returned ok=false" };
|
|
502
|
+
}
|
|
503
|
+
catch (err) {
|
|
504
|
+
return { ok: false, reason: err instanceof Error ? err.message : "health check failed" };
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
resolveRecipients: ({ cfg, accountId }) => {
|
|
508
|
+
const account = resolveAccount(cfg, accountId);
|
|
509
|
+
const url = getRuntimeWebhookUrl(account.accountId) || account.webhookUrl;
|
|
510
|
+
return url ? { recipients: [url], source: "webhook" } : { recipients: [], source: "none" };
|
|
511
|
+
},
|
|
293
512
|
},
|
|
294
513
|
};
|
|
295
514
|
//# sourceMappingURL=channel.js.map
|