@searchfe/openclaw-baiduapp 0.1.9-beta.1 → 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 +238 -151
- package/dist/index.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { spawnSync } from 'child_process';
|
|
|
2
2
|
import readline from 'readline';
|
|
3
3
|
import path2 from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
|
-
import
|
|
5
|
+
import crypto from 'crypto';
|
|
6
6
|
import { createRequire } from 'module';
|
|
7
7
|
import { lookup } from 'dns/promises';
|
|
8
8
|
import fs2 from 'fs/promises';
|
|
@@ -4334,7 +4334,7 @@ function createLogger(prefix, opts) {
|
|
|
4334
4334
|
};
|
|
4335
4335
|
}
|
|
4336
4336
|
function sha1Hex(input) {
|
|
4337
|
-
return
|
|
4337
|
+
return crypto.createHash("sha1").update(input).digest("hex");
|
|
4338
4338
|
}
|
|
4339
4339
|
function computeAKSKBearerToken(params) {
|
|
4340
4340
|
return sha1Hex(params.ak + params.sk + params.timestamp + params.nonce);
|
|
@@ -4349,19 +4349,22 @@ function verifyAKSKBearerToken(params) {
|
|
|
4349
4349
|
return expected === params.token;
|
|
4350
4350
|
}
|
|
4351
4351
|
function generateNonce() {
|
|
4352
|
-
return
|
|
4352
|
+
return crypto.randomBytes(8).toString("hex");
|
|
4353
4353
|
}
|
|
4354
4354
|
function buildAuthorizationHeader(params) {
|
|
4355
4355
|
const token = computeAKSKBearerToken(params);
|
|
4356
4356
|
return `Bearer ${token}`;
|
|
4357
4357
|
}
|
|
4358
|
+
|
|
4359
|
+
// src/types.ts
|
|
4360
|
+
var DEFAULT_BAIDU_APP_SESSION_ID = "agent:main:main";
|
|
4358
4361
|
var require2 = createRequire(import.meta.url);
|
|
4359
4362
|
var pkg = require2("../package.json");
|
|
4360
4363
|
var PLUGIN_VERSION = pkg.version;
|
|
4361
4364
|
|
|
4362
4365
|
// src/api.ts
|
|
4363
4366
|
var logger = createLogger("openclaw-baiduapp");
|
|
4364
|
-
var DEFAULT_sessionId =
|
|
4367
|
+
var DEFAULT_sessionId = DEFAULT_BAIDU_APP_SESSION_ID;
|
|
4365
4368
|
async function sendBaiduAppMessage(account, message, options) {
|
|
4366
4369
|
if (!account.canSendActive) {
|
|
4367
4370
|
logger.error("Account not configured for active sending (missing appKey or appSecret)");
|
|
@@ -4424,6 +4427,15 @@ async function sendBaiduAppMessage(account, message, options) {
|
|
|
4424
4427
|
logger.error(`request failed: ${errmsg}`);
|
|
4425
4428
|
return { ok: false, errcode: resp.status, errmsg };
|
|
4426
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
|
+
}
|
|
4427
4439
|
const result = {
|
|
4428
4440
|
ok: true
|
|
4429
4441
|
};
|
|
@@ -4769,92 +4781,122 @@ var require3 = createRequire(import.meta.url);
|
|
|
4769
4781
|
var BaiduCloudSdk = require3("@baiducloud/sdk");
|
|
4770
4782
|
var DefaultBosClient = BaiduCloudSdk.BosClient;
|
|
4771
4783
|
var MAX_DOWNLOAD_REDIRECTS = 5;
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
const
|
|
4787
|
-
const
|
|
4788
|
-
if (!
|
|
4789
|
-
throw new Error(
|
|
4790
|
-
}
|
|
4791
|
-
let payload;
|
|
4792
|
-
try {
|
|
4793
|
-
payload = await response.json();
|
|
4794
|
-
} catch (error) {
|
|
4795
|
-
throw new Error(`SKS response is not valid JSON: ${formatError(error)}`, { cause: error });
|
|
4796
|
-
}
|
|
4797
|
-
return parseSksCredentialsFromPayload(payload);
|
|
4798
|
-
}
|
|
4799
|
-
function parseSksCredentialsFromPayload(payload) {
|
|
4800
|
-
const parsed = parseSksResponse(payload);
|
|
4801
|
-
if (parsed.status !== 0) {
|
|
4802
|
-
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");
|
|
4803
4802
|
}
|
|
4804
|
-
|
|
4805
|
-
|
|
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 };
|
|
4806
4807
|
}
|
|
4807
4808
|
return {
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
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")
|
|
4814
4815
|
};
|
|
4815
4816
|
}
|
|
4816
|
-
function
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
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 };
|
|
4822
4843
|
}
|
|
4823
|
-
function createBosClient(
|
|
4844
|
+
function createBosClient(fileSts, deps = {}) {
|
|
4845
|
+
if (!fileSts.sts || !fileSts.bceUrl) {
|
|
4846
|
+
throw new Error("Cannot create BOS client without STS credentials");
|
|
4847
|
+
}
|
|
4824
4848
|
const BosClientCtor = deps.bosClientCtor ?? DefaultBosClient;
|
|
4825
4849
|
return new BosClientCtor({
|
|
4826
|
-
endpoint:
|
|
4827
|
-
sessionToken:
|
|
4850
|
+
endpoint: fileSts.bceUrl,
|
|
4851
|
+
sessionToken: fileSts.sts.token,
|
|
4828
4852
|
credentials: {
|
|
4829
|
-
ak:
|
|
4830
|
-
sk:
|
|
4853
|
+
ak: fileSts.sts.ak,
|
|
4854
|
+
sk: fileSts.sts.sk
|
|
4831
4855
|
}
|
|
4832
4856
|
});
|
|
4833
4857
|
}
|
|
4834
4858
|
async function uploadLocalFileToBos(options, deps = {}) {
|
|
4835
4859
|
const localFile = await assertUploadableLocalFile(options.filePath);
|
|
4836
|
-
const credentials = await fetchSksCredentials(options.account, deps);
|
|
4837
|
-
const client = createBosClient(credentials, deps);
|
|
4838
4860
|
const sourceName = options.fileName ?? path2.basename(localFile);
|
|
4839
|
-
const
|
|
4840
|
-
const
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
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
|
+
);
|
|
4852
4893
|
return {
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
fileName
|
|
4857
|
-
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
|
|
4858
4900
|
};
|
|
4859
4901
|
}
|
|
4860
4902
|
async function downloadInboundFileToTemp(options, deps = {}) {
|
|
@@ -4952,38 +4994,93 @@ async function pruneExpiredTempFiles(deps = {}) {
|
|
|
4952
4994
|
await walk(tempDir);
|
|
4953
4995
|
return { deletedFiles };
|
|
4954
4996
|
}
|
|
4955
|
-
function
|
|
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) {
|
|
4956
5030
|
if (!payload || typeof payload !== "object") {
|
|
4957
|
-
throw new Error(
|
|
5031
|
+
throw new Error(`${label} response must be an object`);
|
|
4958
5032
|
}
|
|
4959
5033
|
const record = payload;
|
|
4960
|
-
const
|
|
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
|
+
}
|
|
4961
5042
|
const data = record.data;
|
|
4962
5043
|
return {
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
sk: data.sk,
|
|
4967
|
-
token: data.token,
|
|
4968
|
-
bucketName: data.bucketName,
|
|
4969
|
-
preFixPath: data.preFixPath,
|
|
4970
|
-
bceUrl: data.bceUrl
|
|
4971
|
-
} : void 0
|
|
5044
|
+
code,
|
|
5045
|
+
msg: typeof record.msg === "string" ? record.msg : void 0,
|
|
5046
|
+
data: data && typeof data === "object" ? data : void 0
|
|
4972
5047
|
};
|
|
4973
5048
|
}
|
|
4974
|
-
function
|
|
4975
|
-
|
|
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
|
+
};
|
|
4976
5060
|
}
|
|
4977
|
-
function
|
|
4978
|
-
const
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
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
|
+
};
|
|
4985
5075
|
});
|
|
4986
|
-
|
|
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
|
+
}
|
|
4987
5084
|
}
|
|
4988
5085
|
function requireNonEmptyString(value, label) {
|
|
4989
5086
|
if (typeof value !== "string" || !value.trim()) {
|
|
@@ -4991,36 +5088,19 @@ function requireNonEmptyString(value, label) {
|
|
|
4991
5088
|
}
|
|
4992
5089
|
return value.trim();
|
|
4993
5090
|
}
|
|
4994
|
-
function
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
if (segments.length === 0) {
|
|
4998
|
-
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`);
|
|
4999
5094
|
}
|
|
5000
|
-
|
|
5001
|
-
if (segment === "." || segment === "..") {
|
|
5002
|
-
throw new Error("SKS data.preFixPath contains path traversal");
|
|
5003
|
-
}
|
|
5004
|
-
return sanitizeObjectKeySegment(segment);
|
|
5005
|
-
});
|
|
5006
|
-
return safeSegments.join("/");
|
|
5095
|
+
return value;
|
|
5007
5096
|
}
|
|
5008
|
-
function
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
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`);
|
|
5012
5100
|
}
|
|
5013
|
-
return
|
|
5101
|
+
return value;
|
|
5014
5102
|
}
|
|
5015
|
-
function
|
|
5016
|
-
assertSafeUntrustedFileName(fileName);
|
|
5017
|
-
const parsed = path2.parse(fileName.trim());
|
|
5018
|
-
const safeBase = parsed.name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
5019
|
-
const safeExt = parsed.ext.replace(/[^a-zA-Z0-9.]+/g, "").slice(0, 16);
|
|
5020
|
-
const baseName = safeBase || "file";
|
|
5021
|
-
return `${baseName.slice(0, 80)}${safeExt}`;
|
|
5022
|
-
}
|
|
5023
|
-
function assertSafeUntrustedFileName(fileName) {
|
|
5103
|
+
function requireSafeDisplayFileName(fileName) {
|
|
5024
5104
|
const trimmed = fileName.trim();
|
|
5025
5105
|
if (!trimmed) {
|
|
5026
5106
|
throw new Error("Filename cannot be empty");
|
|
@@ -5031,14 +5111,18 @@ function assertSafeUntrustedFileName(fileName) {
|
|
|
5031
5111
|
if (trimmed === "." || trimmed === "..") {
|
|
5032
5112
|
throw new Error(`Filename is not safe: ${fileName}`);
|
|
5033
5113
|
}
|
|
5114
|
+
return trimmed;
|
|
5034
5115
|
}
|
|
5035
|
-
function
|
|
5036
|
-
const
|
|
5037
|
-
|
|
5038
|
-
|
|
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;
|
|
5039
5122
|
}
|
|
5040
|
-
function
|
|
5041
|
-
|
|
5123
|
+
function inferOutboundFileType(fileName) {
|
|
5124
|
+
const extension = path2.extname(fileName).replace(/^\./, "").toLowerCase();
|
|
5125
|
+
return extension || "bin";
|
|
5042
5126
|
}
|
|
5043
5127
|
async function assertUploadableLocalFile(filePath) {
|
|
5044
5128
|
const resolvedPath = path2.resolve(filePath);
|
|
@@ -5163,11 +5247,11 @@ function parseContentDispositionFileName(contentDisposition) {
|
|
|
5163
5247
|
}
|
|
5164
5248
|
function resolveDownloadFileName(params) {
|
|
5165
5249
|
const candidate = params.explicitFileName ?? params.headerFileName ?? params.urlFileName ?? "file.bin";
|
|
5166
|
-
return
|
|
5250
|
+
return requireSafeDisplayFileName(candidate);
|
|
5167
5251
|
}
|
|
5168
5252
|
function buildTempFilePath(params) {
|
|
5169
5253
|
const timestamp = (params.now?.() ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
5170
|
-
return path2.join(params.tempDir, `${timestamp}-${
|
|
5254
|
+
return path2.join(params.tempDir, `${timestamp}-${crypto.randomUUID()}-${params.fileName}`);
|
|
5171
5255
|
}
|
|
5172
5256
|
async function ensurePluginTempDir(resolveTmpDir) {
|
|
5173
5257
|
const baseTmpDir = resolveTmpDir?.() ?? resolvePreferredOpenClawTmpDir();
|
|
@@ -5614,7 +5698,7 @@ function parseTextAndFilesFromList(list) {
|
|
|
5614
5698
|
const fileItems = list.filter((entry) => entry.type === "file");
|
|
5615
5699
|
const content = textItem?.type === "text" ? textItem.data.text.content : void 0;
|
|
5616
5700
|
const files = fileItems.map((file) => {
|
|
5617
|
-
const fileId = file.data.
|
|
5701
|
+
const fileId = file.data.file.fileId;
|
|
5618
5702
|
return typeof fileId === "string" && fileId.trim() ? { url: fileId, fileType: "file" } : null;
|
|
5619
5703
|
}).filter((file) => file != null);
|
|
5620
5704
|
return { content, files };
|
|
@@ -5715,7 +5799,7 @@ async function pollBaiduAppChatlistOnce(account, loggerOptions, requestOptions)
|
|
|
5715
5799
|
version: PLUGIN_VERSION
|
|
5716
5800
|
};
|
|
5717
5801
|
const body = JSON.stringify(payload);
|
|
5718
|
-
console.log("start poll");
|
|
5802
|
+
console.log("start poll", url);
|
|
5719
5803
|
const requestSignal = createAbortSignalController({
|
|
5720
5804
|
signal: requestOptions?.signal,
|
|
5721
5805
|
timeoutMs: requestOptions?.timeoutMs
|
|
@@ -5904,12 +5988,23 @@ function resolveOutboundLocalMediaPath(mediaUrl) {
|
|
|
5904
5988
|
}
|
|
5905
5989
|
return trimmed;
|
|
5906
5990
|
}
|
|
5907
|
-
function inferBaiduOutboundFileType(params) {
|
|
5908
|
-
const ext = path2.extname(params.mediaPath).toLowerCase();
|
|
5909
|
-
return ext.startsWith(".") ? ext.slice(1) : ext || "bin";
|
|
5910
|
-
}
|
|
5911
5991
|
function buildOutboundMediaPayload(params) {
|
|
5912
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
|
+
};
|
|
5913
6008
|
return {
|
|
5914
6009
|
list: [
|
|
5915
6010
|
...caption ? [{
|
|
@@ -5918,12 +6013,7 @@ function buildOutboundMediaPayload(params) {
|
|
|
5918
6013
|
text: { content: caption }
|
|
5919
6014
|
}
|
|
5920
6015
|
}] : [],
|
|
5921
|
-
|
|
5922
|
-
type: "file",
|
|
5923
|
-
data: {
|
|
5924
|
-
file_id: params.uploadedUrl
|
|
5925
|
-
}
|
|
5926
|
-
}
|
|
6016
|
+
mediaItem
|
|
5927
6017
|
]
|
|
5928
6018
|
};
|
|
5929
6019
|
}
|
|
@@ -6207,15 +6297,15 @@ var baiduAppPlugin = {
|
|
|
6207
6297
|
account,
|
|
6208
6298
|
buildOutboundMediaPayload({
|
|
6209
6299
|
caption: params.text,
|
|
6210
|
-
|
|
6211
|
-
fileType: inferBaiduOutboundFileType({ mediaPath: remoteUrl })
|
|
6300
|
+
externalUrl: remoteUrl
|
|
6212
6301
|
}),
|
|
6213
6302
|
{ agentid: account.accountId, isActive: true }
|
|
6214
6303
|
);
|
|
6215
6304
|
return {
|
|
6216
6305
|
channel: "openclaw-baiduapp",
|
|
6217
|
-
ok:
|
|
6218
|
-
messageId: result.msgid ?? ""
|
|
6306
|
+
ok: result.ok,
|
|
6307
|
+
messageId: result.msgid ?? "",
|
|
6308
|
+
error: result.ok ? void 0 : new Error(result.errmsg ?? "send failed")
|
|
6219
6309
|
};
|
|
6220
6310
|
} catch (err) {
|
|
6221
6311
|
return {
|
|
@@ -6248,10 +6338,7 @@ var baiduAppPlugin = {
|
|
|
6248
6338
|
account,
|
|
6249
6339
|
buildOutboundMediaPayload({
|
|
6250
6340
|
caption: params.text,
|
|
6251
|
-
|
|
6252
|
-
fileType: inferBaiduOutboundFileType({
|
|
6253
|
-
mediaPath: uploaded.fileName || localMediaPath
|
|
6254
|
-
})
|
|
6341
|
+
fileId: uploaded.fileId
|
|
6255
6342
|
}),
|
|
6256
6343
|
{ agentid: account.accountId, isActive: true }
|
|
6257
6344
|
);
|