@searchfe/openclaw-baiduapp 0.1.8 → 0.1.9-beta.2

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/index.js CHANGED
@@ -1,6 +1,8 @@
1
+ import { spawnSync } from 'child_process';
2
+ import readline from 'readline';
1
3
  import path2 from 'path';
2
4
  import { fileURLToPath } from 'url';
3
- import crypto3 from 'crypto';
5
+ import crypto from 'crypto';
4
6
  import { createRequire } from 'module';
5
7
  import { lookup } from 'dns/promises';
6
8
  import fs2 from 'fs/promises';
@@ -9,11 +11,120 @@ import fs from 'fs';
9
11
  import { tmpdir } from 'os';
10
12
 
11
13
  var __defProp = Object.defineProperty;
14
+ var __getOwnPropNames = Object.getOwnPropertyNames;
15
+ var __esm = (fn, res) => function __init() {
16
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
17
+ };
12
18
  var __export = (target, all) => {
13
19
  for (var name in all)
14
20
  __defProp(target, name, { get: all[name], enumerable: true });
15
21
  };
16
22
 
23
+ // src/auth/login.ts
24
+ var login_exports = {};
25
+ __export(login_exports, {
26
+ loginBaiduApp: () => loginBaiduApp
27
+ });
28
+ function createTerminalPrompter() {
29
+ const rl = readline.createInterface({
30
+ input: process.stdin,
31
+ output: process.stdout
32
+ });
33
+ const question = (message) => new Promise((resolve) => {
34
+ rl.question(message, (answer) => resolve(answer));
35
+ });
36
+ return {
37
+ select: async (message, choices) => {
38
+ while (true) {
39
+ process.stdout.write(`${message}
40
+ `);
41
+ for (const [index, choice] of choices.entries()) {
42
+ process.stdout.write(`${index + 1}. ${choice}
43
+ `);
44
+ }
45
+ const answer = (await question("\u8BF7\u9009\u62E9\u5E8F\u53F7: ")).trim();
46
+ const choiceIndex = Number(answer);
47
+ if (Number.isInteger(choiceIndex) && choiceIndex >= 1 && choiceIndex <= choices.length) {
48
+ return choices[choiceIndex - 1];
49
+ }
50
+ process.stdout.write(`\u8BF7\u8F93\u5165 1-${choices.length} \u4E4B\u95F4\u7684\u5E8F\u53F7\u3002
51
+ `);
52
+ }
53
+ },
54
+ text: async (message, opts) => {
55
+ while (true) {
56
+ const answer = (await question(`${message}: `)).trim();
57
+ if (!opts?.required || answer) {
58
+ return answer;
59
+ }
60
+ process.stdout.write("\u8BE5\u9879\u4E3A\u5FC5\u586B\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165\u3002\n");
61
+ }
62
+ },
63
+ close: () => {
64
+ rl.close();
65
+ }
66
+ };
67
+ }
68
+ function redactValue(value, opts) {
69
+ if (!value) {
70
+ return "(empty)";
71
+ }
72
+ const keepStart = opts?.keepStart ?? 2;
73
+ const keepEnd = opts?.keepEnd ?? 2;
74
+ if (value.length <= keepStart + keepEnd) {
75
+ return "*".repeat(value.length);
76
+ }
77
+ return `${value.slice(0, keepStart)}***${value.slice(-keepEnd)}`;
78
+ }
79
+ function setConfigValue(key, value) {
80
+ const args = ["config", "set", key, String(value)];
81
+ const result = spawnSync("openclaw", args, {
82
+ stdio: ["ignore", "pipe", "pipe"],
83
+ encoding: "utf8",
84
+ timeout: 15e3
85
+ });
86
+ if (result.status !== 0) {
87
+ const stderr = (result.stderr ?? "").trim();
88
+ throw new Error(`openclaw config set failed: ${stderr || `exit code ${result.status}`}`);
89
+ }
90
+ }
91
+ async function loginBaiduApp(params) {
92
+ void params.cfg;
93
+ void params.verbose;
94
+ const agentId = params.accountId?.trim() || "main";
95
+ const prompter = createTerminalPrompter();
96
+ try {
97
+ const mode = await prompter.select("\u8BF7\u9009\u62E9\u767E\u5EA6 App \u914D\u7F6E\u65B9\u5F0F", [
98
+ "\u624B\u52A8\u586B\u5199",
99
+ "\u626B\u7801\u914D\u7F6E\uFF08\u5373\u5C06\u652F\u6301\uFF09"
100
+ ]);
101
+ if (mode === "\u626B\u7801\u914D\u7F6E\uFF08\u5373\u5C06\u652F\u6301\uFF09") {
102
+ params.runtime.log("\u23F3 \u626B\u7801\u914D\u7F6E\u529F\u80FD\u6B63\u5728\u5F00\u53D1\u4E2D\uFF0C\u656C\u8BF7\u671F\u5F85...");
103
+ params.runtime.log("\u8BF7\u5148\u4F7F\u7528\u624B\u52A8\u586B\u5199\u65B9\u5F0F\u5B8C\u6210\u914D\u7F6E\u3002");
104
+ return;
105
+ }
106
+ const appKey = await prompter.text("App Key", { required: true });
107
+ const appSecret = await prompter.text("App Secret", { required: true });
108
+ const accountKeyPrefix = `channels.openclaw-baiduapp.accounts.${agentId}`;
109
+ setConfigValue(`${accountKeyPrefix}.appKey`, appKey);
110
+ setConfigValue(`${accountKeyPrefix}.appSecret`, appSecret);
111
+ setConfigValue(`${accountKeyPrefix}.enabled`, true);
112
+ params.runtime.log(`\u2705 openclaw-baiduapp \u5DF2\u5B8C\u6210\u914D\u7F6E\uFF08account: ${agentId}\uFF09`);
113
+ params.runtime.log(`- appKey: ${redactValue(appKey, { keepStart: 3, keepEnd: 3 })}`);
114
+ params.runtime.log(`- appSecret: ${redactValue(appSecret, { keepStart: 3, keepEnd: 3 })}`);
115
+ } catch (error) {
116
+ const message = error instanceof Error ? error.message : String(error);
117
+ params.runtime.error(`openclaw-baiduapp \u767B\u5F55\u914D\u7F6E\u5931\u8D25\uFF1A${message}`);
118
+ throw error;
119
+ } finally {
120
+ prompter.close();
121
+ }
122
+ }
123
+ var init_login = __esm({
124
+ "src/auth/login.ts"() {
125
+ }
126
+ });
127
+
17
128
  // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
18
129
  var external_exports = {};
19
130
  __export(external_exports, {
@@ -4056,14 +4167,13 @@ var NEVER = INVALID;
4056
4167
 
4057
4168
  // src/config.ts
4058
4169
  var DEFAULT_ACCOUNT_ID = "default";
4170
+ var DEFAULT_AGENT_ID = "main";
4059
4171
  var DEFAULT_API_BASE = "https://claw.baidu.com";
4060
4172
  var BaiduAppAccountSchema = external_exports.object({
4061
4173
  name: external_exports.string().optional(),
4062
4174
  enabled: external_exports.boolean().optional(),
4063
4175
  pollingEnabled: external_exports.boolean().optional(),
4064
4176
  webhookPath: external_exports.string().optional(),
4065
- token: external_exports.string().optional(),
4066
- encodingAESKey: external_exports.string().optional(),
4067
4177
  appKey: external_exports.string().optional(),
4068
4178
  appSecret: external_exports.string().optional(),
4069
4179
  apiBase: external_exports.string().optional(),
@@ -4082,8 +4192,6 @@ var BaiduAppConfigJsonSchema = {
4082
4192
  enabled: { type: "boolean" },
4083
4193
  pollingEnabled: { type: "boolean" },
4084
4194
  webhookPath: { type: "string" },
4085
- token: { type: "string" },
4086
- encodingAESKey: { type: "string" },
4087
4195
  appKey: { type: "string" },
4088
4196
  appSecret: { type: "string" },
4089
4197
  apiBase: { type: "string" },
@@ -4099,8 +4207,6 @@ var BaiduAppConfigJsonSchema = {
4099
4207
  enabled: { type: "boolean" },
4100
4208
  pollingEnabled: { type: "boolean" },
4101
4209
  webhookPath: { type: "string" },
4102
- token: { type: "string" },
4103
- encodingAESKey: { type: "string" },
4104
4210
  appKey: { type: "string" },
4105
4211
  appSecret: { type: "string" },
4106
4212
  apiBase: { type: "string" },
@@ -4115,6 +4221,10 @@ function normalizeAccountId(raw) {
4115
4221
  const trimmed = String(raw ?? "").trim();
4116
4222
  return trimmed || DEFAULT_ACCOUNT_ID;
4117
4223
  }
4224
+ function extractAgentId(msg) {
4225
+ const raw = msg.agentid ?? "";
4226
+ return raw.trim() || DEFAULT_AGENT_ID;
4227
+ }
4118
4228
  function listConfiguredAccountIds(cfg) {
4119
4229
  const accounts = cfg.channels?.["openclaw-baiduapp"]?.accounts;
4120
4230
  if (!accounts || typeof accounts !== "object") {
@@ -4162,12 +4272,10 @@ function resolveBaiduAppAccount(params) {
4162
4272
  const merged = mergeBaiduAppAccountConfig(params.cfg, accountId);
4163
4273
  const enabled = baseEnabled && merged.enabled !== false;
4164
4274
  const isDefaultAccount = accountId === DEFAULT_ACCOUNT_ID;
4165
- const token = merged.token?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_TOKEN?.trim() : void 0) || void 0;
4166
- const encodingAESKey = merged.encodingAESKey?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_ENCODING_AES_KEY?.trim() : void 0) || void 0;
4167
4275
  const appKey = merged.appKey?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_KEY?.trim() : void 0) || void 0;
4168
4276
  const appSecret = merged.appSecret?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_SECRET?.trim() : void 0) || void 0;
4169
- const configured = Boolean(token && encodingAESKey);
4170
- const canSendActive = Boolean(appKey && appSecret && token && encodingAESKey);
4277
+ const configured = Boolean(appKey && appSecret);
4278
+ const canSendActive = Boolean(appKey && appSecret);
4171
4279
  const rawApiBase = merged.apiBase?.trim() || (isDefaultAccount ? process.env.BAIDU_API_BASE?.trim() : void 0) || void 0;
4172
4280
  const apiBase = (rawApiBase || DEFAULT_API_BASE).replace(/\/+$/, "");
4173
4281
  return {
@@ -4175,8 +4283,6 @@ function resolveBaiduAppAccount(params) {
4175
4283
  name: merged.name?.trim() || void 0,
4176
4284
  enabled,
4177
4285
  configured,
4178
- token,
4179
- encodingAESKey,
4180
4286
  appKey,
4181
4287
  appSecret,
4182
4288
  apiBase,
@@ -4184,6 +4290,37 @@ function resolveBaiduAppAccount(params) {
4184
4290
  config: merged
4185
4291
  };
4186
4292
  }
4293
+ function resolveAgentField(agentCfg, mainCfg, baseAccount, field) {
4294
+ return agentCfg?.[field]?.trim() || mainCfg?.[field]?.trim() || baseAccount[field];
4295
+ }
4296
+ function resolveAgentAccount(params) {
4297
+ const { baseAccount, cfg, agentId } = params;
4298
+ if (agentId === baseAccount.accountId) {
4299
+ return baseAccount;
4300
+ }
4301
+ const accounts = cfg.channels?.["openclaw-baiduapp"]?.accounts;
4302
+ const agentCfg = accounts?.[agentId] && typeof accounts[agentId] === "object" ? accounts[agentId] : void 0;
4303
+ const mainCfg = agentId !== DEFAULT_AGENT_ID && accounts?.[DEFAULT_AGENT_ID] && typeof accounts[DEFAULT_AGENT_ID] === "object" ? accounts[DEFAULT_AGENT_ID] : void 0;
4304
+ const appKey = resolveAgentField(agentCfg, mainCfg, baseAccount, "appKey");
4305
+ const appSecret = resolveAgentField(agentCfg, mainCfg, baseAccount, "appSecret");
4306
+ const apiBase = baseAccount.apiBase;
4307
+ const name = resolveAgentField(agentCfg, mainCfg, baseAccount, "name");
4308
+ const configured = Boolean(appKey && appSecret);
4309
+ const canSendActive = Boolean(appKey && appSecret);
4310
+ const agentEnabled = agentCfg?.enabled !== false;
4311
+ return {
4312
+ ...baseAccount,
4313
+ accountId: agentId,
4314
+ name: name || baseAccount.name,
4315
+ enabled: agentEnabled && baseAccount.enabled,
4316
+ configured,
4317
+ appKey,
4318
+ appSecret,
4319
+ apiBase,
4320
+ canSendActive,
4321
+ config: { ...baseAccount.config, ...mainCfg ?? {}, ...agentCfg ?? {} }
4322
+ };
4323
+ }
4187
4324
 
4188
4325
  // src/shared/logger.ts
4189
4326
  function createLogger(prefix, opts) {
@@ -4196,135 +4333,85 @@ function createLogger(prefix, opts) {
4196
4333
  error: (msg) => errorFn(`[${prefix}] [ERROR] ${msg}`)
4197
4334
  };
4198
4335
  }
4199
- function decodeEncodingAESKey(encodingAESKey) {
4200
- const trimmed = encodingAESKey.trim();
4201
- if (!trimmed) {
4202
- throw new Error("encodingAESKey missing");
4203
- }
4204
- const withPadding = trimmed.endsWith("=") ? trimmed : `${trimmed}=`;
4205
- const key = Buffer.from(withPadding, "base64");
4206
- if (key.length !== 32) {
4207
- throw new Error(`invalid encodingAESKey (expected 32 bytes after base64 decode, got ${key.length})`);
4208
- }
4209
- return key;
4210
- }
4211
- var PKCS7_BLOCK_SIZE = 32;
4212
- function pkcs7Pad(buf, blockSize) {
4213
- const mod = buf.length % blockSize;
4214
- const pad = mod === 0 ? blockSize : blockSize - mod;
4215
- return Buffer.concat([buf, Buffer.alloc(pad, pad)]);
4216
- }
4217
- function pkcs7Unpad(buf, blockSize) {
4218
- if (buf.length === 0) {
4219
- throw new Error("invalid pkcs7 payload");
4220
- }
4221
- const pad = buf[buf.length - 1];
4222
- if (!pad || pad < 1 || pad > blockSize || pad > buf.length) {
4223
- throw new Error("invalid pkcs7 padding");
4224
- }
4225
- for (let i = 1; i <= pad; i += 1) {
4226
- if (buf[buf.length - i] !== pad) {
4227
- throw new Error("invalid pkcs7 padding");
4228
- }
4229
- }
4230
- return buf.subarray(0, buf.length - pad);
4231
- }
4232
4336
  function sha1Hex(input) {
4233
- return crypto3.createHash("sha1").update(input).digest("hex");
4337
+ return crypto.createHash("sha1").update(input).digest("hex");
4234
4338
  }
4235
- function computeBaiduAppMsgSignature(params) {
4236
- const parts = [params.token, params.timestamp, params.nonce, params.encrypt].map((value) => String(value ?? "")).sort();
4237
- return sha1Hex(parts.join(""));
4339
+ function computeAKSKBearerToken(params) {
4340
+ return sha1Hex(params.ak + params.sk + params.timestamp + params.nonce);
4238
4341
  }
4239
- function verifyBaiduAppSignature(params) {
4240
- const expected = computeBaiduAppMsgSignature({
4241
- token: params.token,
4342
+ function verifyAKSKBearerToken(params) {
4343
+ const expected = computeAKSKBearerToken({
4344
+ ak: params.ak,
4345
+ sk: params.sk,
4242
4346
  timestamp: params.timestamp,
4243
- nonce: params.nonce,
4244
- encrypt: params.encrypt
4347
+ nonce: params.nonce
4245
4348
  });
4246
- return expected === params.signature;
4349
+ return expected === params.token;
4247
4350
  }
4248
- function decryptBaiduAppEncrypted(params) {
4249
- const aesKey = decodeEncodingAESKey(params.encodingAESKey);
4250
- const iv = aesKey.subarray(0, 16);
4251
- const decipher = crypto3.createDecipheriv("aes-256-cbc", aesKey, iv);
4252
- decipher.setAutoPadding(false);
4253
- const decryptedPadded = Buffer.concat([decipher.update(Buffer.from(params.encrypt, "base64")), decipher.final()]);
4254
- const decrypted = pkcs7Unpad(decryptedPadded, PKCS7_BLOCK_SIZE);
4255
- if (decrypted.length < 20) {
4256
- throw new Error(`invalid decrypted payload (expected at least 20 bytes, got ${decrypted.length})`);
4257
- }
4258
- const msgLen = decrypted.readUInt32BE(16);
4259
- const msgStart = 20;
4260
- const msgEnd = msgStart + msgLen;
4261
- if (msgEnd > decrypted.length) {
4262
- throw new Error(`invalid decrypted msg length (msgEnd=${msgEnd}, payloadLength=${decrypted.length})`);
4263
- }
4264
- return decrypted.subarray(msgStart, msgEnd).toString("utf8");
4351
+ function generateNonce() {
4352
+ return crypto.randomBytes(8).toString("hex");
4265
4353
  }
4266
- function encryptBaiduAppPlaintext(params) {
4267
- const aesKey = decodeEncodingAESKey(params.encodingAESKey);
4268
- const iv = aesKey.subarray(0, 16);
4269
- const random16 = crypto3.randomBytes(16);
4270
- const msg = Buffer.from(params.plaintext ?? "", "utf8");
4271
- const msgLen = Buffer.alloc(4);
4272
- msgLen.writeUInt32BE(msg.length, 0);
4273
- const raw = Buffer.concat([random16, msgLen, msg]);
4274
- const padded = pkcs7Pad(raw, PKCS7_BLOCK_SIZE);
4275
- const cipher = crypto3.createCipheriv("aes-256-cbc", aesKey, iv);
4276
- cipher.setAutoPadding(false);
4277
- const encrypted = Buffer.concat([cipher.update(padded), cipher.final()]);
4278
- return encrypted.toString("base64");
4354
+ function buildAuthorizationHeader(params) {
4355
+ const token = computeAKSKBearerToken(params);
4356
+ return `Bearer ${token}`;
4279
4357
  }
4358
+
4359
+ // src/types.ts
4360
+ var DEFAULT_BAIDU_APP_SESSION_ID = "agent:main:main";
4280
4361
  var require2 = createRequire(import.meta.url);
4281
4362
  var pkg = require2("../package.json");
4282
4363
  var PLUGIN_VERSION = pkg.version;
4283
4364
 
4284
4365
  // src/api.ts
4285
4366
  var logger = createLogger("openclaw-baiduapp");
4367
+ var DEFAULT_sessionId = DEFAULT_BAIDU_APP_SESSION_ID;
4286
4368
  async function sendBaiduAppMessage(account, message, options) {
4287
4369
  if (!account.canSendActive) {
4288
- logger.error("Account not configured for active sending (missing appKey, token, or encodingAESKey)");
4370
+ logger.error("Account not configured for active sending (missing appKey or appSecret)");
4289
4371
  return {
4290
4372
  ok: false,
4291
4373
  errcode: -1,
4292
- errmsg: "Account not configured for active sending (missing appKey, token, or encodingAESKey)"
4374
+ errmsg: "Account not configured for active sending (missing appKey or appSecret)"
4293
4375
  };
4294
4376
  }
4295
4377
  const normalizedPayload = typeof message === "string" ? {
4296
- msgtype: "text",
4297
- text: { content: message }
4378
+ list: [{
4379
+ type: "text",
4380
+ data: {
4381
+ text: { content: message }
4382
+ }
4383
+ }]
4298
4384
  } : message;
4299
- const payload = {
4300
- ...normalizedPayload,
4385
+ const sessionId = options?.sessionId ?? DEFAULT_sessionId;
4386
+ const callbackBody = {
4387
+ sessionId,
4388
+ list: normalizedPayload.list,
4301
4389
  version: PLUGIN_VERSION,
4302
- ...options?.msgid != null ? { msgid: options.msgid } : {},
4303
- ...options?.streamId != null ? { streamId: options.streamId } : {},
4304
- ...options?.chunkKey != null ? { chunkKey: options.chunkKey } : {}
4390
+ isActive: options?.isActive || false,
4391
+ ...options?.agentid ? { agentid: options.agentid } : {},
4392
+ ...options?.chunkKey != null ? { chunkKey: options.chunkKey } : {},
4393
+ ...options?.replyToMsgId ? { replyToMsgId: options.replyToMsgId } : {}
4305
4394
  };
4306
- const plaintext = JSON.stringify(payload);
4307
- const encrypt = encryptBaiduAppPlaintext({
4308
- encodingAESKey: account.encodingAESKey ?? "",
4309
- plaintext
4310
- });
4311
4395
  const timestamp = String(Math.floor(Date.now() / 1e3));
4312
- const nonce = crypto3.randomBytes(8).toString("hex");
4313
- const msgSignature = computeBaiduAppMsgSignature({
4314
- token: account.token ?? "",
4396
+ const nonce = generateNonce();
4397
+ const authorization = buildAuthorizationHeader({
4398
+ ak: account.appKey ?? "",
4399
+ sk: account.appSecret ?? "",
4315
4400
  timestamp,
4316
- nonce,
4317
- encrypt
4401
+ nonce
4318
4402
  });
4319
- const sendMessageUrl = `${account.apiBase}/chat/openclaw/callback`;
4320
- const url = `${sendMessageUrl}?timestamp=${encodeURIComponent(timestamp)}&ak=${encodeURIComponent(account.appKey ?? "")}&nonce=${encodeURIComponent(nonce)}&msg_signature=${encodeURIComponent(msgSignature)}`;
4321
- const body = JSON.stringify({ encrypt });
4403
+ const sendMessageUrl = `${account.apiBase}/channel/msg/callback`;
4404
+ const url = `${sendMessageUrl}?timestamp=${encodeURIComponent(timestamp)}&ak=${encodeURIComponent(account.appKey ?? "")}&nonce=${encodeURIComponent(nonce)}`;
4405
+ const body = JSON.stringify(callbackBody);
4322
4406
  logger.info(`POST ${url}`);
4323
4407
  logger.debug(`request body: ${body}`);
4324
4408
  const resp = await fetch(url, {
4325
4409
  method: "POST",
4326
4410
  body,
4327
- headers: { "Content-Type": "application/json" }
4411
+ headers: {
4412
+ "Authorization": authorization,
4413
+ "Content-Type": "application/json"
4414
+ }
4328
4415
  });
4329
4416
  const text = await resp.text();
4330
4417
  if (!text) {
@@ -4340,6 +4427,15 @@ async function sendBaiduAppMessage(account, message, options) {
4340
4427
  logger.error(`request failed: ${errmsg}`);
4341
4428
  return { ok: false, errcode: resp.status, errmsg };
4342
4429
  }
4430
+ if (data.code !== 0) {
4431
+ const errmsg = data.msg ?? `channel callback failed with code ${String(data.code)}`;
4432
+ logger.error(`request failed: ${errmsg}`);
4433
+ return {
4434
+ ok: false,
4435
+ errcode: data.code,
4436
+ errmsg
4437
+ };
4438
+ }
4343
4439
  const result = {
4344
4440
  ok: true
4345
4441
  };
@@ -4365,21 +4461,21 @@ function buildMediaPayload(mediaList, opts) {
4365
4461
 
4366
4462
  // src/bot.ts
4367
4463
  function extractBaiduAppTextContent(msg) {
4368
- const msgtype = String(msg.msgtype ?? msg.MsgType ?? "").toLowerCase();
4464
+ const msgtype = String(msg.msgtype ?? "").toLowerCase();
4369
4465
  if (msgtype === "text") {
4370
- const content = msg.text?.content ?? msg.Content;
4466
+ const content = msg.text?.content;
4371
4467
  return typeof content === "string" ? content : "";
4372
4468
  }
4373
4469
  if (msgtype === "event") {
4374
4470
  const eventtype = String(
4375
- msg.event?.eventtype ?? msg.Event ?? ""
4471
+ msg.event?.eventtype ?? ""
4376
4472
  ).trim();
4377
4473
  return eventtype ? `[event] ${eventtype}` : "[event]";
4378
4474
  }
4379
4475
  return msgtype ? `[${msgtype}]` : "";
4380
4476
  }
4381
4477
  function canDispatchBaiduAppInboundMessage(msg) {
4382
- const msgtype = String(msg.msgtype ?? msg.MsgType ?? "").toLowerCase();
4478
+ const msgtype = String(msg.msgtype ?? "").toLowerCase();
4383
4479
  if (msgtype === "text") {
4384
4480
  if (extractBaiduAppTextContent(msg)) {
4385
4481
  return true;
@@ -4449,7 +4545,7 @@ async function dispatchBaiduAppMessage(params) {
4449
4545
  cfg: safeCfg,
4450
4546
  channel: "openclaw-baiduapp",
4451
4547
  accountId: account.accountId,
4452
- peer: { kind: "dm", id: "default" }
4548
+ peer: { kind: "dm", id: account.accountId || DEFAULT_AGENT_ID }
4453
4549
  });
4454
4550
  logger3.info(`SessionKey: ${route.sessionKey}`);
4455
4551
  logger3.info(
@@ -4479,7 +4575,7 @@ async function dispatchBaiduAppMessage(params) {
4479
4575
  envelope: envelopeOptions,
4480
4576
  body: rawBody
4481
4577
  }) : rawBody;
4482
- const msgid = msg.msgid ?? msg.MsgId ?? void 0;
4578
+ const msgid = msg.msgid ?? void 0;
4483
4579
  const ctxPayload = channel.reply?.finalizeInboundContext ? channel.reply.finalizeInboundContext({
4484
4580
  Body: body,
4485
4581
  RawBody: rawBody,
@@ -4685,92 +4781,122 @@ var require3 = createRequire(import.meta.url);
4685
4781
  var BaiduCloudSdk = require3("@baiducloud/sdk");
4686
4782
  var DefaultBosClient = BaiduCloudSdk.BosClient;
4687
4783
  var MAX_DOWNLOAD_REDIRECTS = 5;
4688
- var EMPTY_QUERY_MD5 = crypto3.createHash("md5").update("").digest("hex");
4689
- var SKS_BASE_TOKEN_POSITIONS = [12, 37, 5, 23, 48, 15, 62, 33];
4690
- async function fetchSksCredentials(account, deps = {}) {
4691
- if (!account.appKey?.trim()) {
4692
- throw new Error("Cannot fetch SKS credentials without account.appKey");
4693
- }
4694
- if (!account.appSecret?.trim()) {
4695
- throw new Error("Cannot fetch SKS credentials without account.appSecret");
4696
- }
4697
- const fetchImpl = deps.fetchImpl ?? fetch;
4698
- const apiBase = account.apiBase.replace(/\/+$/, "");
4699
- const pageLid = deps.createPageLid?.() ?? generateSksPageLid();
4700
- const timestamp = String((deps.now?.() ?? /* @__PURE__ */ new Date()).getTime());
4701
- const token = createSksRequestToken({ pageLid, timestamp });
4702
- const url = `${apiBase}/file/sts?ak=${encodeURIComponent(account.appKey)}&sk=${encodeURIComponent(account.appSecret)}&tk=${encodeURIComponent(token)}`;
4703
- const response = await fetchImpl(url, { method: "POST" });
4704
- if (!response.ok) {
4705
- throw new Error(`SKS request failed with HTTP ${response.status}`);
4706
- }
4707
- let payload;
4708
- try {
4709
- payload = await response.json();
4710
- } catch (error) {
4711
- throw new Error(`SKS response is not valid JSON: ${formatError(error)}`, { cause: error });
4712
- }
4713
- return parseSksCredentialsFromPayload(payload);
4714
- }
4715
- function parseSksCredentialsFromPayload(payload) {
4716
- const parsed = parseSksResponse(payload);
4717
- if (parsed.status !== 0) {
4718
- throw new Error(`SKS request failed with status ${parsed.status}`);
4784
+ async function fetchFileUploadSts(options, deps = {}) {
4785
+ assertAccountCanUseChannelApi(options.account);
4786
+ const responsePayload = await postAuthenticatedChannelJson(
4787
+ options.account,
4788
+ "/channel/file/sts",
4789
+ {
4790
+ sessionId: options.sessionId ?? DEFAULT_BAIDU_APP_SESSION_ID,
4791
+ filename: requireSafeDisplayFileName(options.filename),
4792
+ fileSize: options.fileSize,
4793
+ fileType: normalizeOutboundFileType(options.fileType),
4794
+ ...options.md5 ? { md5: options.md5 } : {}
4795
+ },
4796
+ deps
4797
+ );
4798
+ const envelope = parseChannelEnvelope(responsePayload, "file STS");
4799
+ const data = envelope.data;
4800
+ if (!data) {
4801
+ throw new Error("file STS response missing data");
4719
4802
  }
4720
- if (!parsed.data) {
4721
- throw new Error("SKS response missing data");
4803
+ const fileId = requireNonEmptyString(data.fileId, "file STS data.fileId");
4804
+ const reuse = requireBoolean(data.reuse, "file STS data.reuse");
4805
+ if (reuse) {
4806
+ return { fileId, reuse };
4722
4807
  }
4723
4808
  return {
4724
- ak: requireNonEmptyString(parsed.data.ak, "SKS data.ak"),
4725
- sk: requireNonEmptyString(parsed.data.sk, "SKS data.sk"),
4726
- sessionToken: requireNonEmptyString(parsed.data.token, "SKS data.token"),
4727
- bucketName: requireNonEmptyString(parsed.data.bucketName, "SKS data.bucketName"),
4728
- prefixPath: sanitizeObjectKeyPrefix(requireNonEmptyString(parsed.data.preFixPath, "SKS data.preFixPath")),
4729
- endpoint: requireNonEmptyString(parsed.data.bceUrl, "SKS data.bceUrl")
4809
+ fileId,
4810
+ reuse,
4811
+ sts: parseFileUploadStsCredentials(data.sts),
4812
+ bceUrl: requireNonEmptyString(data.bceUrl, "file STS data.bceUrl"),
4813
+ bucket: requireNonEmptyString(data.bucket, "file STS data.bucket"),
4814
+ bosName: requireNonEmptyString(data.bosName, "file STS data.bosName")
4730
4815
  };
4731
4816
  }
4732
- function createSksRequestToken(params) {
4733
- const pageLid = requireNonEmptyString(params.pageLid, "SKS pageLid");
4734
- const timestamp = requireNonEmptyString(params.timestamp, "SKS timestamp");
4735
- const baseToken = createSksBaseToken(pageLid);
4736
- const payload = `${baseToken}|${EMPTY_QUERY_MD5}|${timestamp}|${pageLid}`;
4737
- return `${Buffer.from(payload, "utf8").toString("base64")}-${pageLid}-3`;
4817
+ async function notifyFileUploadComplete(options, deps = {}) {
4818
+ assertAccountCanUseChannelApi(options.account);
4819
+ if (options.fileIds.length === 0) {
4820
+ throw new Error("file complete requires at least one fileId");
4821
+ }
4822
+ const responsePayload = await postAuthenticatedChannelJson(
4823
+ options.account,
4824
+ "/channel/file/complete",
4825
+ {
4826
+ sessionId: options.sessionId ?? DEFAULT_BAIDU_APP_SESSION_ID,
4827
+ fileIds: options.fileIds
4828
+ },
4829
+ deps
4830
+ );
4831
+ const envelope = parseChannelEnvelope(responsePayload, "file complete");
4832
+ const files = extractCompleteFiles(envelope.data);
4833
+ const fileIds = new Set(options.fileIds);
4834
+ for (const file of files) {
4835
+ if (!fileIds.has(file.fileId)) {
4836
+ continue;
4837
+ }
4838
+ if (file.status === -1) {
4839
+ throw new Error(`file complete failed for fileId ${file.fileId}`);
4840
+ }
4841
+ }
4842
+ return { files };
4738
4843
  }
4739
- function createBosClient(credentials, deps = {}) {
4844
+ function createBosClient(fileSts, deps = {}) {
4845
+ if (!fileSts.sts || !fileSts.bceUrl) {
4846
+ throw new Error("Cannot create BOS client without STS credentials");
4847
+ }
4740
4848
  const BosClientCtor = deps.bosClientCtor ?? DefaultBosClient;
4741
4849
  return new BosClientCtor({
4742
- endpoint: credentials.endpoint,
4743
- sessionToken: credentials.sessionToken,
4850
+ endpoint: fileSts.bceUrl,
4851
+ sessionToken: fileSts.sts.token,
4744
4852
  credentials: {
4745
- ak: credentials.ak,
4746
- sk: credentials.sk
4853
+ ak: fileSts.sts.ak,
4854
+ sk: fileSts.sts.sk
4747
4855
  }
4748
4856
  });
4749
4857
  }
4750
4858
  async function uploadLocalFileToBos(options, deps = {}) {
4751
4859
  const localFile = await assertUploadableLocalFile(options.filePath);
4752
- const credentials = await fetchSksCredentials(options.account, deps);
4753
- const client = createBosClient(credentials, deps);
4754
4860
  const sourceName = options.fileName ?? path2.basename(localFile);
4755
- const sanitizedFileName = sanitizeFileName(sourceName);
4756
- const key = buildBosObjectKey({
4757
- prefixPath: credentials.prefixPath,
4758
- fileName: sanitizedFileName,
4759
- now: deps.now
4760
- });
4761
- const uploadOptions = options.contentType?.trim() ? {
4762
- "Content-Type": options.contentType.trim()
4763
- } : void 0;
4764
- const [, fileStat] = await Promise.all([
4765
- client.putObjectFromFile(credentials.bucketName, key, localFile, uploadOptions),
4766
- fs2.stat(localFile)
4767
- ]);
4861
+ const fileName = requireSafeDisplayFileName(sourceName);
4862
+ const [fileBuffer, fileStat] = await Promise.all([fs2.readFile(localFile), fs2.stat(localFile)]);
4863
+ const md5 = crypto.createHash("md5").update(fileBuffer).digest("hex");
4864
+ const fileType = inferOutboundFileType(fileName);
4865
+ const fileSts = await fetchFileUploadSts(
4866
+ {
4867
+ account: options.account,
4868
+ sessionId: options.sessionId,
4869
+ filename: fileName,
4870
+ fileSize: fileStat.size,
4871
+ fileType,
4872
+ md5
4873
+ },
4874
+ deps
4875
+ );
4876
+ if (!fileSts.reuse) {
4877
+ const bucketName = requireNonEmptyString(fileSts.bucket, "file STS bucket");
4878
+ const key = requireNonEmptyString(fileSts.bosName, "file STS bosName");
4879
+ const client = createBosClient(fileSts, deps);
4880
+ const uploadOptions = options.contentType?.trim() ? {
4881
+ "Content-Type": options.contentType.trim()
4882
+ } : void 0;
4883
+ await client.putObjectFromFile(bucketName, key, localFile, uploadOptions);
4884
+ }
4885
+ await notifyFileUploadComplete(
4886
+ {
4887
+ account: options.account,
4888
+ sessionId: options.sessionId,
4889
+ fileIds: [fileSts.fileId]
4890
+ },
4891
+ deps
4892
+ );
4768
4893
  return {
4769
- bucketName: credentials.bucketName,
4770
- key,
4771
- url: client.generateUrl(credentials.bucketName, key),
4772
- fileName: sanitizedFileName,
4773
- fileSize: fileStat.size
4894
+ fileId: fileSts.fileId,
4895
+ bucketName: fileSts.bucket,
4896
+ key: fileSts.bosName,
4897
+ fileName,
4898
+ fileSize: fileStat.size,
4899
+ reuse: fileSts.reuse
4774
4900
  };
4775
4901
  }
4776
4902
  async function downloadInboundFileToTemp(options, deps = {}) {
@@ -4868,38 +4994,93 @@ async function pruneExpiredTempFiles(deps = {}) {
4868
4994
  await walk(tempDir);
4869
4995
  return { deletedFiles };
4870
4996
  }
4871
- function parseSksResponse(payload) {
4997
+ async function postAuthenticatedChannelJson(account, pathname, bodyPayload, deps) {
4998
+ const fetchImpl = deps.fetchImpl ?? fetch;
4999
+ const now = deps.now?.() ?? /* @__PURE__ */ new Date();
5000
+ const timestamp = String(Math.floor(now.getTime() / 1e3));
5001
+ const nonce = (deps.generateNonceImpl ?? generateNonce)();
5002
+ const authorization = buildAuthorizationHeader({
5003
+ ak: account.appKey ?? "",
5004
+ sk: account.appSecret ?? "",
5005
+ timestamp,
5006
+ nonce
5007
+ });
5008
+ const url = new URL(`${account.apiBase.replace(/\/+$/, "")}${pathname}`);
5009
+ url.searchParams.set("ak", account.appKey ?? "");
5010
+ url.searchParams.set("timestamp", timestamp);
5011
+ url.searchParams.set("nonce", nonce);
5012
+ const response = await fetchImpl(url.toString(), {
5013
+ method: "POST",
5014
+ headers: {
5015
+ "Authorization": authorization,
5016
+ "Content-Type": "application/json"
5017
+ },
5018
+ body: JSON.stringify(bodyPayload)
5019
+ });
5020
+ if (!response.ok) {
5021
+ throw new Error(`channel request failed with HTTP ${response.status}`);
5022
+ }
5023
+ try {
5024
+ return await response.json();
5025
+ } catch (error) {
5026
+ throw new Error(`channel response is not valid JSON: ${formatError(error)}`, { cause: error });
5027
+ }
5028
+ }
5029
+ function parseChannelEnvelope(payload, label) {
4872
5030
  if (!payload || typeof payload !== "object") {
4873
- throw new Error("SKS response must be an object");
5031
+ throw new Error(`${label} response must be an object`);
4874
5032
  }
4875
5033
  const record = payload;
4876
- const status = typeof record.code === "number" ? record.code : typeof record.status === "number" ? record.status : void 0;
5034
+ const code = record.code;
5035
+ if (typeof code !== "number") {
5036
+ throw new Error(`${label} response missing numeric code`);
5037
+ }
5038
+ if (code !== 0) {
5039
+ const msg = typeof record.msg === "string" ? record.msg : "unknown error";
5040
+ throw new Error(`${label} request failed with code ${code}: ${msg}`);
5041
+ }
4877
5042
  const data = record.data;
4878
5043
  return {
4879
- status,
4880
- data: data && typeof data === "object" ? {
4881
- ak: data.ak,
4882
- sk: data.sk,
4883
- token: data.token,
4884
- bucketName: data.bucketName,
4885
- preFixPath: data.preFixPath,
4886
- bceUrl: data.bceUrl
4887
- } : void 0
5044
+ code,
5045
+ msg: typeof record.msg === "string" ? record.msg : void 0,
5046
+ data: data && typeof data === "object" ? data : void 0
4888
5047
  };
4889
5048
  }
4890
- function generateSksPageLid() {
4891
- return crypto3.randomBytes(16).toString("hex");
5049
+ function parseFileUploadStsCredentials(payload) {
5050
+ if (!payload || typeof payload !== "object") {
5051
+ throw new Error("file STS data.sts is required");
5052
+ }
5053
+ const record = payload;
5054
+ return {
5055
+ ak: requireNonEmptyString(record.ak, "file STS data.sts.ak"),
5056
+ sk: requireNonEmptyString(record.sk, "file STS data.sts.sk"),
5057
+ token: requireNonEmptyString(record.token, "file STS data.sts.token"),
5058
+ expireAt: requireNumber(record.expireAt, "file STS data.sts.expireAt")
5059
+ };
4892
5060
  }
4893
- function createSksBaseToken(pageLid) {
4894
- const pageLidHash = crypto3.createHash("sha256").update(pageLid).digest("hex");
4895
- const characters = SKS_BASE_TOKEN_POSITIONS.map((position) => {
4896
- const character = pageLidHash[position];
4897
- if (!character) {
4898
- throw new Error(`SKS base token position is out of range: ${position}`);
4899
- }
4900
- return character;
5061
+ function extractCompleteFiles(payload) {
5062
+ const files = payload?.files;
5063
+ if (!Array.isArray(files)) {
5064
+ return [];
5065
+ }
5066
+ return files.map((file, index) => {
5067
+ if (!file || typeof file !== "object") {
5068
+ throw new Error(`file complete data.files[${index}] must be an object`);
5069
+ }
5070
+ const record = file;
5071
+ return {
5072
+ fileId: requireNonEmptyString(record.fileId, `file complete data.files[${index}].fileId`),
5073
+ status: requireNumber(record.status, `file complete data.files[${index}].status`)
5074
+ };
4901
5075
  });
4902
- return characters.join("");
5076
+ }
5077
+ function assertAccountCanUseChannelApi(account) {
5078
+ if (!account.appKey?.trim()) {
5079
+ throw new Error("Cannot call channel API without account.appKey");
5080
+ }
5081
+ if (!account.appSecret?.trim()) {
5082
+ throw new Error("Cannot call channel API without account.appSecret");
5083
+ }
4903
5084
  }
4904
5085
  function requireNonEmptyString(value, label) {
4905
5086
  if (typeof value !== "string" || !value.trim()) {
@@ -4907,36 +5088,19 @@ function requireNonEmptyString(value, label) {
4907
5088
  }
4908
5089
  return value.trim();
4909
5090
  }
4910
- function sanitizeObjectKeyPrefix(prefixPath) {
4911
- const normalized = prefixPath.replace(/\\/g, "/").trim();
4912
- const segments = normalized.split("/").map((segment) => segment.trim()).filter(Boolean);
4913
- if (segments.length === 0) {
4914
- throw new Error("SKS data.preFixPath must contain at least one safe path segment");
5091
+ function requireBoolean(value, label) {
5092
+ if (typeof value !== "boolean") {
5093
+ throw new Error(`${label} must be a boolean`);
4915
5094
  }
4916
- const safeSegments = segments.map((segment) => {
4917
- if (segment === "." || segment === "..") {
4918
- throw new Error("SKS data.preFixPath contains path traversal");
4919
- }
4920
- return sanitizeObjectKeySegment(segment);
4921
- });
4922
- return safeSegments.join("/");
5095
+ return value;
4923
5096
  }
4924
- function sanitizeObjectKeySegment(segment) {
4925
- const sanitized = segment.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
4926
- if (!sanitized) {
4927
- throw new Error(`Object key segment is not safe: ${segment}`);
5097
+ function requireNumber(value, label) {
5098
+ if (typeof value !== "number" || !Number.isFinite(value)) {
5099
+ throw new Error(`${label} must be a finite number`);
4928
5100
  }
4929
- return sanitized.slice(0, 80);
4930
- }
4931
- function sanitizeFileName(fileName) {
4932
- assertSafeUntrustedFileName(fileName);
4933
- const parsed = path2.parse(fileName.trim());
4934
- const safeBase = parsed.name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
4935
- const safeExt = parsed.ext.replace(/[^a-zA-Z0-9.]+/g, "").slice(0, 16);
4936
- const baseName = safeBase || "file";
4937
- return `${baseName.slice(0, 80)}${safeExt}`;
5101
+ return value;
4938
5102
  }
4939
- function assertSafeUntrustedFileName(fileName) {
5103
+ function requireSafeDisplayFileName(fileName) {
4940
5104
  const trimmed = fileName.trim();
4941
5105
  if (!trimmed) {
4942
5106
  throw new Error("Filename cannot be empty");
@@ -4947,14 +5111,18 @@ function assertSafeUntrustedFileName(fileName) {
4947
5111
  if (trimmed === "." || trimmed === "..") {
4948
5112
  throw new Error(`Filename is not safe: ${fileName}`);
4949
5113
  }
5114
+ return trimmed;
4950
5115
  }
4951
- function buildBosObjectKey(params) {
4952
- const timestamp = formatUtcDate(params.now?.() ?? /* @__PURE__ */ new Date());
4953
- const uniqueId = crypto3.randomUUID();
4954
- return `${params.prefixPath}/${timestamp}/${uniqueId}-${params.fileName}`;
5116
+ function normalizeOutboundFileType(fileType) {
5117
+ const normalized = fileType.trim().replace(/^\.+/, "").toLowerCase();
5118
+ if (!normalized) {
5119
+ throw new Error("fileType is required");
5120
+ }
5121
+ return normalized;
4955
5122
  }
4956
- function formatUtcDate(date) {
4957
- return date.toISOString().slice(0, 10);
5123
+ function inferOutboundFileType(fileName) {
5124
+ const extension = path2.extname(fileName).replace(/^\./, "").toLowerCase();
5125
+ return extension || "bin";
4958
5126
  }
4959
5127
  async function assertUploadableLocalFile(filePath) {
4960
5128
  const resolvedPath = path2.resolve(filePath);
@@ -5079,11 +5247,11 @@ function parseContentDispositionFileName(contentDisposition) {
5079
5247
  }
5080
5248
  function resolveDownloadFileName(params) {
5081
5249
  const candidate = params.explicitFileName ?? params.headerFileName ?? params.urlFileName ?? "file.bin";
5082
- return sanitizeFileName(candidate);
5250
+ return requireSafeDisplayFileName(candidate);
5083
5251
  }
5084
5252
  function buildTempFilePath(params) {
5085
5253
  const timestamp = (params.now?.() ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
5086
- return path2.join(params.tempDir, `${timestamp}-${crypto3.randomUUID()}-${params.fileName}`);
5254
+ return path2.join(params.tempDir, `${timestamp}-${crypto.randomUUID()}-${params.fileName}`);
5087
5255
  }
5088
5256
  async function ensurePluginTempDir(resolveTmpDir) {
5089
5257
  const baseTmpDir = resolveTmpDir?.() ?? resolvePreferredOpenClawTmpDir();
@@ -5144,12 +5312,12 @@ function normalizeWebhookPath(raw) {
5144
5312
  function jsonOk(res, body) {
5145
5313
  res.statusCode = 200;
5146
5314
  res.setHeader("Content-Type", "application/json; charset=utf-8");
5147
- res.end(JSON.stringify({ status: 0, data: body }));
5315
+ res.end(JSON.stringify({ code: 0, msg: "success", data: body }));
5148
5316
  }
5149
5317
  function jsonError(res, message, statusCode = 200) {
5150
5318
  res.statusCode = statusCode;
5151
5319
  res.setHeader("Content-Type", "application/json; charset=utf-8");
5152
- res.end(JSON.stringify({ status: -1, message }));
5320
+ res.end(JSON.stringify({ code: -1, msg: message, data: {} }));
5153
5321
  }
5154
5322
  async function readRawBody(req, maxBytes) {
5155
5323
  const chunks = [];
@@ -5181,47 +5349,6 @@ async function readRawBody(req, maxBytes) {
5181
5349
  });
5182
5350
  });
5183
5351
  }
5184
- function parseXmlBody(xml) {
5185
- const result = {};
5186
- const cdataRegex = /<(\w+)><!\[CDATA\[([\s\S]*?)\]\]><\/\1>/g;
5187
- let match;
5188
- while ((match = cdataRegex.exec(xml)) !== null) {
5189
- const [, key = "", value = ""] = match;
5190
- result[key] = value;
5191
- }
5192
- const simpleRegex = /<(\w+)>([^<]*)<\/\1>/g;
5193
- while ((match = simpleRegex.exec(xml)) !== null) {
5194
- const [, key = "", value = ""] = match;
5195
- if (!result[key]) {
5196
- result[key] = value;
5197
- }
5198
- }
5199
- return result;
5200
- }
5201
- function isXmlFormat(raw) {
5202
- const trimmed = raw.trim();
5203
- return trimmed.startsWith("<") && trimmed.endsWith(">");
5204
- }
5205
- function buildEncryptedJsonReply(params) {
5206
- const base = params.plaintextJson != null && typeof params.plaintextJson === "object" ? params.plaintextJson : {};
5207
- const plaintext = JSON.stringify({ ...base, version: PLUGIN_VERSION });
5208
- const encrypt = encryptBaiduAppPlaintext({
5209
- encodingAESKey: params.account.encodingAESKey ?? "",
5210
- plaintext
5211
- });
5212
- const msgsignature = computeBaiduAppMsgSignature({
5213
- token: params.account.token ?? "",
5214
- timestamp: params.timestamp,
5215
- nonce: params.nonce,
5216
- encrypt
5217
- });
5218
- return {
5219
- encrypt,
5220
- msgsignature,
5221
- timestamp: params.timestamp,
5222
- nonce: params.nonce
5223
- };
5224
- }
5225
5352
  function resolveQueryParams(req) {
5226
5353
  const url = new URL(req.url ?? "/", "http://localhost");
5227
5354
  return url.searchParams;
@@ -5230,8 +5357,16 @@ function resolvePath(req) {
5230
5357
  const url = new URL(req.url ?? "/", "http://localhost");
5231
5358
  return normalizeWebhookPath(url.pathname || "/");
5232
5359
  }
5233
- function resolveSignatureParam(params) {
5234
- return params.get("msg_signature") ?? params.get("msgsignature") ?? params.get("signature") ?? "";
5360
+ function resolveBearerToken(req) {
5361
+ const authorization = req.headers.authorization ?? req.headers.Authorization;
5362
+ if (Array.isArray(authorization)) {
5363
+ return "";
5364
+ }
5365
+ const value = typeof authorization === "string" ? authorization.trim() : "";
5366
+ if (!value.toLowerCase().startsWith("bearer ")) {
5367
+ return "";
5368
+ }
5369
+ return value.slice(7).trim();
5235
5370
  }
5236
5371
  function buildLogger(target) {
5237
5372
  return createLogger("openclaw-baiduapp", {
@@ -5299,50 +5434,49 @@ async function downloadInboundFiles(params) {
5299
5434
  }
5300
5435
  };
5301
5436
  }
5302
- function parseBaiduAppPlainMessage(raw) {
5303
- const trimmed = raw.trim();
5304
- if (trimmed.startsWith("<") && trimmed.endsWith(">")) {
5305
- const xmlData = parseXmlBody(trimmed);
5306
- return {
5307
- msgtype: xmlData.MsgType,
5308
- MsgType: xmlData.MsgType,
5309
- msgid: xmlData.MsgId,
5310
- MsgId: xmlData.MsgId,
5311
- content: xmlData.Content,
5312
- Content: xmlData.Content,
5313
- from: xmlData.FromUserName ? { appkey: xmlData.FromUserName } : void 0,
5314
- ToUserName: xmlData.ToUserName,
5315
- CreateTime: xmlData.CreateTime ? Number(xmlData.CreateTime) : void 0,
5316
- BotID: xmlData.BotID ? Number(xmlData.BotID) : void 0,
5317
- Event: xmlData.Event
5318
- };
5319
- }
5437
+ function parseV2MsgToInbound(inner, outer) {
5438
+ const list = Array.isArray(inner.list) ? inner.list : [];
5439
+ const textItem = list.find(
5440
+ (item) => item && typeof item === "object" && item.type === "text"
5441
+ );
5442
+ const fileItems = list.filter(
5443
+ (item) => item && typeof item === "object" && item.type === "file"
5444
+ );
5445
+ const textContent = textItem?.data?.text?.content ?? "";
5446
+ const files = fileItems.map((f) => ({ url: f.data.file_id, fileType: "file" }));
5447
+ return {
5448
+ msgtype: "text",
5449
+ msgid: typeof outer.msgid === "string" ? outer.msgid : void 0,
5450
+ agentid: typeof outer.agentid === "string" ? outer.agentid : void 0,
5451
+ text: textContent ? { content: textContent } : void 0,
5452
+ ...files.length > 0 ? { files } : {}
5453
+ };
5454
+ }
5455
+ function parseBaiduAppCandidates(params) {
5456
+ const results = [];
5457
+ let outer = {};
5320
5458
  try {
5321
- const parsed = JSON.parse(trimmed);
5322
- if (!parsed || typeof parsed !== "object") {
5323
- return {};
5459
+ const parsed = JSON.parse(params.raw);
5460
+ if (parsed && typeof parsed === "object") {
5461
+ outer = parsed;
5324
5462
  }
5325
- return parsed;
5326
5463
  } catch {
5327
- return {};
5464
+ outer = {};
5328
5465
  }
5329
- }
5330
- function decryptBaiduAppCandidates(params) {
5331
- const results = [];
5332
- for (const candidate of params.candidates) {
5333
- if (!candidate.account.encodingAESKey) {
5334
- continue;
5335
- }
5466
+ let inner = {};
5467
+ if (typeof outer.msg === "string") {
5336
5468
  try {
5337
- const plaintext = decryptBaiduAppEncrypted({
5338
- encodingAESKey: candidate.account.encodingAESKey,
5339
- encrypt: params.encrypt
5340
- });
5341
- const msg = parseBaiduAppPlainMessage(plaintext);
5342
- results.push({ target: candidate, plaintext, msg });
5469
+ const parsedInner = JSON.parse(outer.msg);
5470
+ if (parsedInner && typeof parsedInner === "object") {
5471
+ inner = parsedInner;
5472
+ }
5343
5473
  } catch {
5474
+ inner = {};
5344
5475
  }
5345
5476
  }
5477
+ for (const candidate of params.candidates) {
5478
+ results.push({ target: candidate, msg: parseV2MsgToInbound(inner, outer) });
5479
+ }
5346
5480
  return results;
5347
5481
  }
5348
5482
  function selectDecryptedTarget(params) {
@@ -5359,8 +5493,9 @@ async function processBaiduAppInboundMessage(params) {
5359
5493
  const { target, msg } = params;
5360
5494
  const logger3 = buildLogger(target);
5361
5495
  target.statusSink?.({ lastInboundAt: Date.now() });
5362
- const msgtype = String(msg.msgtype ?? msg.MsgType ?? "").toLowerCase();
5363
- const msgid = msg.msgid ?? msg.MsgId ? String(msg.msgid ?? msg.MsgId) : void 0;
5496
+ const msgtype = String(msg.msgtype ?? "").toLowerCase();
5497
+ const msgid = msg.msgid ? String(msg.msgid) : void 0;
5498
+ const agentId = extractAgentId(msg);
5364
5499
  logger3.info(`inbound: type=${msgtype || "unknown"} msgid=${msgid ?? "none"} account=${target.account.accountId}`);
5365
5500
  if (!canDispatchBaiduAppInboundMessage(msg)) {
5366
5501
  logger3.warn(`inbound message skipped: type=${msgtype || "unknown"} reason=no-dispatchable-content`);
@@ -5368,6 +5503,11 @@ async function processBaiduAppInboundMessage(params) {
5368
5503
  }
5369
5504
  const inboundFileResult = msgtype === "text" ? await downloadInboundFiles({ msg, logger: logger3, runtime: target.runtime }) : { localFiles: [], diagnostic: {} };
5370
5505
  const inboundMediaFiles = inboundFileResult.localFiles;
5506
+ const agentAccount = resolveAgentAccount({
5507
+ baseAccount: target.account,
5508
+ cfg: target.config,
5509
+ agentId
5510
+ });
5371
5511
  const core = tryGetBaiduAppRuntime();
5372
5512
  if (core) {
5373
5513
  logger3.info(`agent dispatch started: canSendActive=${target.account.canSendActive}`);
@@ -5380,8 +5520,9 @@ async function processBaiduAppInboundMessage(params) {
5380
5520
  );
5381
5521
  target.statusSink?.({ lastOutboundAt: Date.now() });
5382
5522
  if (target.account.canSendActive) {
5383
- sendBaiduAppMessage(target.account, text, {
5384
- msgid,
5523
+ sendBaiduAppMessage(agentAccount, text, {
5524
+ replyToMsgId: msgid,
5525
+ agentid: agentId,
5385
5526
  chunkKey: currentChunkKey
5386
5527
  }).then((result) => {
5387
5528
  if (!result.ok) {
@@ -5404,7 +5545,7 @@ async function processBaiduAppInboundMessage(params) {
5404
5545
  };
5405
5546
  dispatchBaiduAppMessage({
5406
5547
  cfg: target.config,
5407
- account: target.account,
5548
+ account: agentAccount,
5408
5549
  msg,
5409
5550
  core,
5410
5551
  hooks,
@@ -5446,53 +5587,43 @@ async function handleBaiduAppWebhookRequest(req, res) {
5446
5587
  const query = resolveQueryParams(req);
5447
5588
  const timestamp = query.get("timestamp") ?? "";
5448
5589
  const nonce = query.get("nonce") ?? "";
5449
- const signature = resolveSignatureParam(query);
5590
+ const ak = query.get("ak") ?? "";
5591
+ const token = resolveBearerToken(req);
5450
5592
  const primary = targets[0];
5451
5593
  const logger3 = buildLogger(primary);
5452
5594
  if (req.method === "GET") {
5453
5595
  const echostr = query.get("echostr") ?? "";
5454
- if (!timestamp || !nonce || !signature || !echostr) {
5596
+ if (!ak || !timestamp || !nonce || !token || !echostr) {
5455
5597
  jsonError(res, "missing query params", 400);
5456
5598
  return true;
5457
5599
  }
5458
- const signatureMatched2 = targets.filter((candidate) => {
5459
- if (!candidate.account.token) {
5600
+ const tokenMatched2 = targets.filter((candidate) => {
5601
+ if (!candidate.account.appKey || !candidate.account.appSecret) {
5460
5602
  return false;
5461
5603
  }
5462
- return verifyBaiduAppSignature({
5463
- token: candidate.account.token,
5604
+ if (candidate.account.appKey !== ak) {
5605
+ return false;
5606
+ }
5607
+ return verifyAKSKBearerToken({
5608
+ ak: candidate.account.appKey,
5609
+ sk: candidate.account.appSecret,
5464
5610
  timestamp,
5465
5611
  nonce,
5466
- encrypt: echostr,
5467
- signature
5612
+ token
5468
5613
  });
5469
5614
  });
5470
- if (signatureMatched2.length === 0) {
5615
+ if (tokenMatched2.length === 0) {
5471
5616
  jsonError(res, "unauthorized");
5472
5617
  return true;
5473
5618
  }
5474
- const decryptable2 = signatureMatched2.filter((candidate) => Boolean(candidate.account.encodingAESKey));
5475
- if (decryptable2.length === 0) {
5476
- jsonError(res, "unauthorized");
5477
- return true;
5478
- }
5479
- const decryptedCandidates2 = decryptBaiduAppCandidates({
5480
- candidates: decryptable2,
5481
- encrypt: echostr
5482
- });
5483
- if (decryptedCandidates2.length === 0) {
5484
- jsonError(res, "decrypt failed");
5485
- return true;
5486
- }
5487
- const selected2 = selectDecryptedTarget({ candidates: decryptedCandidates2, logger: logger3 });
5488
- jsonOk(res, selected2.plaintext);
5619
+ jsonOk(res, echostr);
5489
5620
  return true;
5490
5621
  }
5491
5622
  if (req.method !== "POST") {
5492
5623
  jsonError(res, "Method Not Allowed", 405);
5493
5624
  return true;
5494
5625
  }
5495
- if (!timestamp || !nonce || !signature) {
5626
+ if (!ak || !timestamp || !nonce || !token) {
5496
5627
  jsonError(res, "missing query params");
5497
5628
  return true;
5498
5629
  }
@@ -5502,90 +5633,56 @@ async function handleBaiduAppWebhookRequest(req, res) {
5502
5633
  return true;
5503
5634
  }
5504
5635
  const rawBody = body.raw;
5505
- let encrypt = "";
5506
- let msgSignature = signature;
5507
- let msgTimestamp = timestamp;
5508
- let msgNonce = nonce;
5509
- if (isXmlFormat(rawBody)) {
5510
- const xmlData = parseXmlBody(rawBody);
5511
- encrypt = xmlData.Encrypt ?? "";
5512
- msgSignature = xmlData.MsgSignature ?? signature;
5513
- msgTimestamp = xmlData.TimeStamp ?? timestamp;
5514
- msgNonce = xmlData.Nonce ?? nonce;
5515
- logger3.info(`inbound xml parsed: hasEncrypt=${Boolean(encrypt)}, msg_signature=${msgSignature ? "yes" : "no"}`);
5516
- } else {
5517
- try {
5518
- const record = JSON.parse(rawBody);
5519
- encrypt = String(record.encrypt ?? record.Encrypt ?? "");
5520
- logger3.info(`inbound json parsed: hasEncrypt=${Boolean(encrypt)}`);
5521
- } catch {
5522
- logger3.warn(`inbound payload parse failed: not valid xml or json`);
5523
- jsonError(res, "invalid payload format");
5524
- return true;
5525
- }
5526
- }
5527
- if (!encrypt) {
5528
- jsonError(res, "missing encrypt");
5636
+ try {
5637
+ JSON.parse(rawBody);
5638
+ logger3.info("inbound json parsed");
5639
+ } catch {
5640
+ logger3.warn("inbound payload parse failed: not valid json");
5641
+ jsonError(res, "invalid payload format");
5529
5642
  return true;
5530
5643
  }
5531
- const signatureMatched = targets.filter((candidate) => {
5532
- if (!candidate.account.token) {
5644
+ const tokenMatched = targets.filter((candidate) => {
5645
+ if (!candidate.account.appKey || !candidate.account.appSecret) {
5646
+ return false;
5647
+ }
5648
+ if (candidate.account.appKey !== ak) {
5533
5649
  return false;
5534
5650
  }
5535
- return verifyBaiduAppSignature({
5536
- token: candidate.account.token,
5537
- timestamp: msgTimestamp,
5538
- nonce: msgNonce,
5539
- encrypt,
5540
- signature: msgSignature
5651
+ return verifyAKSKBearerToken({
5652
+ ak: candidate.account.appKey,
5653
+ sk: candidate.account.appSecret,
5654
+ timestamp,
5655
+ nonce,
5656
+ token
5541
5657
  });
5542
5658
  });
5543
- if (signatureMatched.length === 0) {
5544
- logger3.warn(`signature verification failed: checked ${targets.length} account(s), none matched`);
5659
+ if (tokenMatched.length === 0) {
5660
+ logger3.warn(`bearer token verification failed: checked ${targets.length} account(s), none matched`);
5545
5661
  jsonError(res, "unauthorized");
5546
5662
  return true;
5547
5663
  }
5548
- logger3.debug(`signature verified: ${signatureMatched.length} account(s) matched`);
5549
- const decryptable = signatureMatched.filter((candidate) => Boolean(candidate.account.encodingAESKey));
5550
- if (decryptable.length === 0) {
5551
- logger3.warn(`no account has encodingAESKey configured`);
5552
- jsonError(res, "openclaw-baiduapp not configured");
5553
- return true;
5554
- }
5555
- const decryptedCandidates = decryptBaiduAppCandidates({
5556
- candidates: decryptable,
5557
- encrypt
5664
+ logger3.debug(`bearer token verified: ${tokenMatched.length} account(s) matched`);
5665
+ const decryptedCandidates = parseBaiduAppCandidates({
5666
+ candidates: tokenMatched,
5667
+ raw: rawBody
5558
5668
  });
5559
- if (decryptedCandidates.length === 0) {
5560
- logger3.warn(`decrypt failed for all ${decryptable.length} candidate account(s)`);
5561
- jsonError(res, "decrypt failed");
5562
- return true;
5563
- }
5564
5669
  const selected = selectDecryptedTarget({ candidates: decryptedCandidates, logger: logger3 });
5565
5670
  const target = selected.target;
5566
- if (!target.account.configured || !target.account.token || !target.account.encodingAESKey) {
5671
+ if (!target.account.configured || !target.account.appKey || !target.account.appSecret) {
5567
5672
  logger3.warn(`selected account ${target.account.accountId} not fully configured`);
5568
5673
  jsonError(res, "openclaw-baiduapp not configured");
5569
5674
  return true;
5570
5675
  }
5571
- const reply = await processBaiduAppInboundMessage({
5676
+ await processBaiduAppInboundMessage({
5572
5677
  target,
5573
5678
  msg: selected.msg
5574
5679
  });
5575
- jsonOk(
5576
- res,
5577
- buildEncryptedJsonReply({
5578
- account: target.account,
5579
- plaintextJson: reply,
5580
- nonce: msgNonce,
5581
- timestamp: msgTimestamp
5582
- })
5583
- );
5680
+ jsonOk(res, {});
5584
5681
  return true;
5585
5682
  }
5586
5683
 
5587
5684
  // src/poller.ts
5588
- var DEFAULT_POLL_INTERVAL_MS = 1e3;
5685
+ var DEFAULT_POLL_INTERVAL_MS = 3e3;
5589
5686
  var DEFAULT_POLL_REQUEST_TIMEOUT_MS = 1e4;
5590
5687
  var accountPollers = /* @__PURE__ */ new Map();
5591
5688
  function buildPollingTextInboundMessage(content) {
@@ -5596,21 +5693,36 @@ function buildPollingTextInboundMessage(content) {
5596
5693
  }
5597
5694
  };
5598
5695
  }
5696
+ function parseTextAndFilesFromList(list) {
5697
+ const textItem = list.find((entry) => entry.type === "text");
5698
+ const fileItems = list.filter((entry) => entry.type === "file");
5699
+ const content = textItem?.type === "text" ? textItem.data.text.content : void 0;
5700
+ const files = fileItems.map((file) => {
5701
+ const fileId = file.data.file.fileId;
5702
+ return typeof fileId === "string" && fileId.trim() ? { url: fileId, fileType: "file" } : null;
5703
+ }).filter((file) => file != null);
5704
+ return { content, files };
5705
+ }
5599
5706
  async function dispatchPendingPollingMessages(data, target) {
5707
+ console.log(data);
5600
5708
  if (!target || data.length === 0) {
5601
5709
  return;
5602
5710
  }
5603
5711
  for (const item of data) {
5604
- if (String(item.msgtype).toLowerCase() !== "text") {
5605
- continue;
5606
- }
5607
- const content = item.data?.content;
5608
- if (typeof content !== "string" || content.length === 0) {
5712
+ const list = Array.isArray(item.list) ? item.list : [];
5713
+ const { content, files } = parseTextAndFilesFromList(list);
5714
+ console.log({ content, files });
5715
+ if (typeof content !== "string" && files.length === 0) {
5609
5716
  continue;
5610
5717
  }
5611
5718
  await processBaiduAppInboundMessage({
5612
5719
  target,
5613
- msg: buildPollingTextInboundMessage(content)
5720
+ msg: {
5721
+ ...buildPollingTextInboundMessage(typeof content === "string" ? content : ""),
5722
+ msgid: typeof item.msgId === "string" ? item.msgId : void 0,
5723
+ agentid: typeof item.agentId === "string" ? item.agentId : void 0,
5724
+ ...files.length > 0 ? { files } : {}
5725
+ }
5614
5726
  });
5615
5727
  }
5616
5728
  }
@@ -5665,12 +5777,29 @@ function createAbortSignalController(params) {
5665
5777
  };
5666
5778
  }
5667
5779
  async function pollBaiduAppChatlistOnce(account, loggerOptions, requestOptions) {
5668
- const endpoint = `${account.apiBase}/chat/demo/chatlist`;
5780
+ const endpoint = `${account.apiBase}/channel/msg/poll`;
5781
+ const logger3 = createLogger("openclaw-baiduapp:poller", loggerOptions);
5782
+ const timestamp = String(Math.floor(Date.now() / 1e3));
5783
+ const nonce = generateNonce();
5784
+ const authorization = buildAuthorizationHeader({
5785
+ ak: account.appKey ?? "",
5786
+ sk: account.appSecret ?? "",
5787
+ timestamp,
5788
+ nonce
5789
+ });
5669
5790
  const query = new URLSearchParams({
5670
5791
  ak: account.appKey ?? "",
5671
- sk: account.appSecret ?? ""
5792
+ timestamp,
5793
+ nonce
5672
5794
  });
5673
5795
  const url = `${endpoint}?${query.toString()}`;
5796
+ const payload = {
5797
+ sessionId: "agent:main:main",
5798
+ num: 5,
5799
+ version: PLUGIN_VERSION
5800
+ };
5801
+ const body = JSON.stringify(payload);
5802
+ console.log("start poll", url);
5674
5803
  const requestSignal = createAbortSignalController({
5675
5804
  signal: requestOptions?.signal,
5676
5805
  timeoutMs: requestOptions?.timeoutMs
@@ -5678,8 +5807,13 @@ async function pollBaiduAppChatlistOnce(account, loggerOptions, requestOptions)
5678
5807
  let response;
5679
5808
  try {
5680
5809
  response = await (requestOptions?.fetchImpl ?? fetch)(url, {
5681
- method: "GET",
5682
- signal: requestSignal.signal
5810
+ method: "POST",
5811
+ body,
5812
+ signal: requestSignal.signal,
5813
+ headers: {
5814
+ "Authorization": authorization,
5815
+ "Content-Type": "application/json"
5816
+ }
5683
5817
  });
5684
5818
  } catch (error) {
5685
5819
  requestSignal.cleanup();
@@ -5732,10 +5866,13 @@ async function pollBaiduAppChatlistOnce(account, loggerOptions, requestOptions)
5732
5866
  }
5733
5867
  });
5734
5868
  }
5735
- const data = Array.isArray(parsed.data) ? parsed.data : [];
5869
+ if (parsed.code !== 0) {
5870
+ logger3.debug(`Baidu poll returned non-zero code=${String(parsed.code)}, message=${parsed.message}`);
5871
+ }
5872
+ const msgList = Array.isArray(parsed.data?.msgList) ? parsed.data.msgList : [];
5736
5873
  return buildPollResult({
5737
5874
  ok: true,
5738
- data
5875
+ data: msgList
5739
5876
  });
5740
5877
  }
5741
5878
  function scheduleNextPoll(account, state) {
@@ -5851,16 +5988,33 @@ function resolveOutboundLocalMediaPath(mediaUrl) {
5851
5988
  }
5852
5989
  return trimmed;
5853
5990
  }
5854
- function inferBaiduOutboundFileType(params) {
5855
- const ext = path2.extname(params.mediaPath).toLowerCase();
5856
- return ext.startsWith(".") ? ext.slice(1) : ext || "bin";
5857
- }
5858
5991
  function buildOutboundMediaPayload(params) {
5859
5992
  const caption = params.caption?.trim();
5993
+ const mediaItem = params.externalUrl ? {
5994
+ type: "external_url",
5995
+ data: {
5996
+ externalUrl: {
5997
+ url: params.externalUrl
5998
+ }
5999
+ }
6000
+ } : {
6001
+ type: "file",
6002
+ data: {
6003
+ file: {
6004
+ fileId: params.fileId ?? ""
6005
+ }
6006
+ }
6007
+ };
5860
6008
  return {
5861
- msgtype: "text",
5862
- ...caption ? { text: { content: caption } } : {},
5863
- files: [{ url: params.uploadedUrl, fileType: params.fileType }]
6009
+ list: [
6010
+ ...caption ? [{
6011
+ type: "text",
6012
+ data: {
6013
+ text: { content: caption }
6014
+ }
6015
+ }] : [],
6016
+ mediaItem
6017
+ ]
5864
6018
  };
5865
6019
  }
5866
6020
  function resolveDirectOutboundFiles(files) {
@@ -6097,7 +6251,10 @@ var baiduAppPlugin = {
6097
6251
  };
6098
6252
  }
6099
6253
  try {
6100
- const result = await sendBaiduAppMessage(account, params.text);
6254
+ const result = await sendBaiduAppMessage(account, params.text, {
6255
+ agentid: account.accountId,
6256
+ isActive: true
6257
+ });
6101
6258
  return {
6102
6259
  channel: "openclaw-baiduapp",
6103
6260
  ok: result.ok,
@@ -6140,14 +6297,15 @@ var baiduAppPlugin = {
6140
6297
  account,
6141
6298
  buildOutboundMediaPayload({
6142
6299
  caption: params.text,
6143
- uploadedUrl: remoteUrl,
6144
- fileType: inferBaiduOutboundFileType({ mediaPath: remoteUrl })
6145
- })
6300
+ externalUrl: remoteUrl
6301
+ }),
6302
+ { agentid: account.accountId, isActive: true }
6146
6303
  );
6147
6304
  return {
6148
6305
  channel: "openclaw-baiduapp",
6149
- ok: true,
6150
- messageId: result.msgid ?? ""
6306
+ ok: result.ok,
6307
+ messageId: result.msgid ?? "",
6308
+ error: result.ok ? void 0 : new Error(result.errmsg ?? "send failed")
6151
6309
  };
6152
6310
  } catch (err) {
6153
6311
  return {
@@ -6180,11 +6338,9 @@ var baiduAppPlugin = {
6180
6338
  account,
6181
6339
  buildOutboundMediaPayload({
6182
6340
  caption: params.text,
6183
- uploadedUrl: uploaded.url,
6184
- fileType: inferBaiduOutboundFileType({
6185
- mediaPath: uploaded.fileName || localMediaPath
6186
- })
6187
- })
6341
+ fileId: uploaded.fileId
6342
+ }),
6343
+ { agentid: account.accountId, isActive: true }
6188
6344
  );
6189
6345
  return {
6190
6346
  channel: "openclaw-baiduapp",
@@ -6206,6 +6362,18 @@ var baiduAppPlugin = {
6206
6362
  }
6207
6363
  }
6208
6364
  },
6365
+ auth: {
6366
+ login: async (params) => {
6367
+ void params.channelInput;
6368
+ const { loginBaiduApp: loginBaiduApp2 } = await Promise.resolve().then(() => (init_login(), login_exports));
6369
+ await loginBaiduApp2({
6370
+ cfg: params.cfg,
6371
+ accountId: params.accountId,
6372
+ runtime: params.runtime,
6373
+ verbose: params.verbose
6374
+ });
6375
+ }
6376
+ },
6209
6377
  gateway: {
6210
6378
  startAccount: async (ctx) => {
6211
6379
  ctx.setStatus?.({ accountId: ctx.accountId });
@@ -6243,21 +6411,19 @@ var baiduAppPlugin = {
6243
6411
  existing();
6244
6412
  }
6245
6413
  unregisterHooks.set(ctx.accountId, unregister);
6246
- if (account.config.pollingEnabled === true) {
6247
- startAccountPolling({
6414
+ startAccountPolling({
6415
+ account,
6416
+ dispatchTarget: {
6248
6417
  account,
6249
- dispatchTarget: {
6250
- account,
6251
- config: ctx.cfg ?? {},
6252
- runtime: runtime2,
6253
- statusSink: (patch) => ctx.setStatus?.({ accountId: ctx.accountId, ...patch })
6254
- },
6255
- onError: (error) => {
6256
- const message = error instanceof Error ? error.message : String(error);
6257
- ctx.log?.error(`[openclaw-baiduapp] polling failed for account ${ctx.accountId}: ${message}`);
6258
- }
6259
- });
6260
- }
6418
+ config: ctx.cfg ?? {},
6419
+ runtime: runtime2,
6420
+ statusSink: (patch) => ctx.setStatus?.({ accountId: ctx.accountId, ...patch })
6421
+ },
6422
+ onError: (error) => {
6423
+ const message = error instanceof Error ? error.message : String(error);
6424
+ ctx.log?.error(`[openclaw-baiduapp] polling failed for account ${ctx.accountId}: ${message}`);
6425
+ }
6426
+ });
6261
6427
  ctx.log?.info(
6262
6428
  `[openclaw-baiduapp] webhook registered at ${path4} for account ${ctx.accountId} (canSendActive=${account.canSendActive})`
6263
6429
  );
@@ -6309,7 +6475,7 @@ async function sendMessage(account, options) {
6309
6475
  };
6310
6476
  }
6311
6477
  try {
6312
- const textResult = await sendBaiduAppMessage(account, options.text);
6478
+ const textResult = await sendBaiduAppMessage(account, options.text, { isActive: true });
6313
6479
  return {
6314
6480
  ok: textResult.ok,
6315
6481
  msgid: textResult.msgid,