duclaw-cli 1.5.0 → 1.7.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/README.md CHANGED
@@ -132,3 +132,11 @@ pnpm build
132
132
  ## License
133
133
 
134
134
  Private
135
+
136
+ ## 打赏
137
+
138
+ 如果 Duclaw 对你有帮助,欢迎请作者喝杯咖啡 ☕
139
+
140
+ <p align="center">
141
+ <img src="https://raw.githubusercontent.com/DZCD/agent-template-ts/main/docs/a26aee81e6e5ba739ebb7abfd9dadfad.jpg" alt="打赏二维码" width="300">
142
+ </p>
package/dist/bundle.js CHANGED
@@ -30242,7 +30242,7 @@ function printHelp() {
30242
30242
  `);
30243
30243
  }
30244
30244
  function printVersion() {
30245
- console.log(`duclaw-cli v${true ? "1.5.0" : "unknown"}`);
30245
+ console.log(`duclaw-cli v${true ? "1.7.0" : "unknown"}`);
30246
30246
  }
30247
30247
  function getDuclawTemplate() {
30248
30248
  return {
@@ -35445,7 +35445,40 @@ var getMessages = async (storage, userId, limit = 100, date, cronTitle) => {
35445
35445
  start = later;
35446
35446
  }
35447
35447
  }
35448
- return data.slice(start);
35448
+ return sanitizeMessages(data.slice(start));
35449
+ };
35450
+ var sanitizeMessages = (messages) => {
35451
+ if (messages.length === 0) return messages;
35452
+ const result = [];
35453
+ for (let i = 0; i < messages.length; i++) {
35454
+ const msg = messages[i];
35455
+ if (!msg.content || msg.content.length === 0) continue;
35456
+ if (msg.role === "assistant") {
35457
+ const toolUses = msg.content.filter((b) => b.type === "tool_use");
35458
+ if (toolUses.length > 0) {
35459
+ const next = messages[i + 1];
35460
+ if (!next || next.role !== "user") {
35461
+ console.warn(`[sanitize] \u53D1\u73B0 assistant tool_use \u65E0\u5BF9\u5E94 tool_result\uFF0C\u622A\u65AD\u6D88\u606F\u5386\u53F2\uFF08index=${i}\uFF09`);
35462
+ break;
35463
+ }
35464
+ const resultIds = new Set(
35465
+ next.content.filter((b) => b.type === "tool_result").map((b) => b.tool_use_id)
35466
+ );
35467
+ const allMatched = toolUses.every((tu) => resultIds.has(tu.id));
35468
+ if (!allMatched) {
35469
+ console.warn(`[sanitize] tool_use/tool_result id \u4E0D\u5339\u914D\uFF0C\u622A\u65AD\u6D88\u606F\u5386\u53F2\uFF08index=${i}\uFF09`);
35470
+ break;
35471
+ }
35472
+ }
35473
+ }
35474
+ const prev = result[result.length - 1];
35475
+ if (prev && prev.role === msg.role) {
35476
+ prev.content = [...prev.content, ...msg.content];
35477
+ } else {
35478
+ result.push({ ...msg, content: [...msg.content] });
35479
+ }
35480
+ }
35481
+ return result;
35449
35482
  };
35450
35483
  var addMessage = async (storage, userId, message, date, cronTitle) => {
35451
35484
  let key = `mem:${userId}`;
@@ -41794,10 +41827,18 @@ var RedisMessageDeduplication = class {
41794
41827
  }
41795
41828
  };
41796
41829
 
41830
+ // src/channels/feishu/MessageProcess.ts
41831
+ var import_node_path10 = require("node:path");
41832
+ var import_node_os4 = require("node:os");
41833
+ var import_node_fs5 = require("node:fs");
41834
+
41797
41835
  // src/oss/AliyunOSSClient.ts
41798
41836
  var import_ali_oss = __toESM(require("ali-oss"));
41799
41837
  loadEnv();
41800
41838
  var aliyunOssClient = void 0;
41839
+ var isOssConfigured = () => {
41840
+ return !!(process.env.OSS_ACCESS_KEY_ID && process.env.OSS_ACCESS_KEY_SECRET && process.env.OSS_ENDPOINT && process.env.OSS_BUCKET);
41841
+ };
41801
41842
  var createAliyunOssClient = () => {
41802
41843
  const key = process.env.OSS_ACCESS_KEY_ID;
41803
41844
  const secret = process.env.OSS_ACCESS_KEY_SECRET;
@@ -41825,6 +41866,26 @@ var createAliyunOssClient = () => {
41825
41866
  };
41826
41867
 
41827
41868
  // src/channels/feishu/MessageProcess.ts
41869
+ var saveToLocal = (userId, subDir, fileName, buffer) => {
41870
+ const dir = (0, import_node_path10.join)((0, import_node_os4.homedir)(), ".duclaw", "workspace", userId, subDir);
41871
+ (0, import_node_fs5.mkdirSync)(dir, { recursive: true });
41872
+ const filePath = (0, import_node_path10.join)(dir, fileName);
41873
+ (0, import_node_fs5.writeFileSync)(filePath, buffer);
41874
+ return filePath;
41875
+ };
41876
+ var tryUploadToOss = async (ossPath, buffer) => {
41877
+ if (!isOssConfigured()) return null;
41878
+ try {
41879
+ const ossClient = createAliyunOssClient();
41880
+ await ossClient.put(ossPath, buffer);
41881
+ const url = await ossClient.signatureUrlV4("GET", 3600, void 0, ossPath);
41882
+ console.log(`[MessageProcess] OSS \u4E0A\u4F20\u6210\u529F\uFF0C\u4E34\u65F6\u8BBF\u95EE\u94FE\u63A5: ${url}`);
41883
+ return url;
41884
+ } catch (err) {
41885
+ console.warn(`[MessageProcess] OSS \u4E0A\u4F20\u5931\u8D25\uFF0C\u4F7F\u7528\u672C\u5730\u8DEF\u5F84: ${err}`);
41886
+ return null;
41887
+ }
41888
+ };
41828
41889
  var processImageMsg = async (userRequest) => {
41829
41890
  if (!userRequest.metadata) {
41830
41891
  throw new Error(`[MessageProcess] \u98DE\u4E66\u56FE\u7247\u6D88\u606F\u5E94\u8981\u6709metadata,\u5F53\u524D:${userRequest.metadata}`);
@@ -41839,30 +41900,13 @@ var processImageMsg = async (userRequest) => {
41839
41900
  if (!image_key) {
41840
41901
  throw new Error(`[MessageProcess] \u98DE\u4E66\u56FE\u7247\u6D88\u606F\u5E94\u8981\u6709image_key`);
41841
41902
  }
41842
- const ossClient = createAliyunOssClient();
41843
- try {
41844
- const buffer = await downloadMessageImage(message.message_id, image_key);
41845
- const result = await ossClient.put(
41846
- `${userRequest.userId}/images/${image_key}`,
41847
- buffer
41848
- );
41849
- console.log("\u6587\u4EF6\u4E0A\u4F20oss\u5B8C\u6210:", result);
41850
- const publicReadableUrl = await ossClient.signatureUrlV4(
41851
- `GET`,
41852
- 3600,
41853
- // 过期时间(秒),1小时
41854
- void 0,
41855
- // 不需要额外的 headers/queries
41856
- `${userRequest.userId}/images/${image_key}`
41857
- // obj name
41858
- );
41859
- console.log(`[MessageProcess] \u4E34\u65F6\u8BBF\u95EE\u94FE\u63A5: ${publicReadableUrl}\uFF0C\u6709\u6548\u65F6\u957F: 1h`);
41860
- userRequest.metadata.imageUrl = publicReadableUrl;
41861
- userRequest.content = `<system-reminder>\u63A5\u6536\u5230\u7528\u6237\u53D1\u6765\u7684\u56FE\u7247\u6D88\u606F,\u56FE\u7247\u5DF2\u5B58\u50A8\u5728\u4E0A\u4E0B\u6587\u4E2D,\u8BF7\u4F7F\u7528image_understand\u5DE5\u5177\u5206\u6790\u56FE\u7247(\u4E0D\u9700\u8981\u4F20image_url\u53C2\u6570,\u5DE5\u5177\u4F1A\u81EA\u52A8\u83B7\u53D6\u56FE\u7247)</system-reminder>`;
41862
- return userRequest;
41863
- } catch (err) {
41864
- throw new Error(`[MessageProcess] \u4E0A\u4F20\u56FE\u7247\u5230\u963F\u91CC\u4E91oss\u5931\u8D25:${err}`);
41865
- }
41903
+ const buffer = await downloadMessageImage(message.message_id, image_key);
41904
+ const localPath = saveToLocal(userRequest.userId, "images", `${image_key}.png`, buffer);
41905
+ console.log(`[MessageProcess] \u56FE\u7247\u5DF2\u4FDD\u5B58\u5230\u672C\u5730: ${localPath}`);
41906
+ const ossUrl = await tryUploadToOss(`${userRequest.userId}/images/${image_key}`, buffer);
41907
+ userRequest.metadata.imageUrl = ossUrl || localPath;
41908
+ userRequest.content = `<system-reminder>\u63A5\u6536\u5230\u7528\u6237\u53D1\u6765\u7684\u56FE\u7247\u6D88\u606F,\u56FE\u7247\u5DF2\u5B58\u50A8\u5728\u4E0A\u4E0B\u6587\u4E2D,\u8BF7\u4F7F\u7528image_understand\u5DE5\u5177\u5206\u6790\u56FE\u7247(\u4E0D\u9700\u8981\u4F20image_url\u53C2\u6570,\u5DE5\u5177\u4F1A\u81EA\u52A8\u83B7\u53D6\u56FE\u7247)</system-reminder>`;
41909
+ return userRequest;
41866
41910
  };
41867
41911
  var processFileMsg = async (userRequest) => {
41868
41912
  const metadata = userRequest.metadata;
@@ -41875,31 +41919,22 @@ var processFileMsg = async (userRequest) => {
41875
41919
  if (!messageId || !fileKey || !fileName) {
41876
41920
  throw new Error(`[MessageProcess] \u98DE\u4E66\u6587\u4EF6\u6D88\u606F\u7F3A\u5C11 message_id/file_key/file_name`);
41877
41921
  }
41878
- const ossClient = createAliyunOssClient();
41879
- try {
41880
- const buffer = await downloadMessageFile(messageId, fileKey);
41881
- console.log(`[MessageProcess] \u6587\u4EF6\u4E0B\u8F7D\u5B8C\u6210: ${fileName}, \u5927\u5C0F: ${buffer.length} bytes`);
41882
- const ossPath = `${userRequest.userId}/files/${fileKey}_${fileName}`;
41883
- const result = await ossClient.put(ossPath, buffer);
41884
- console.log("[MessageProcess] \u6587\u4EF6\u4E0A\u4F20oss\u5B8C\u6210:", result);
41885
- const publicReadableUrl = await ossClient.signatureUrlV4(
41886
- `GET`,
41887
- 3600,
41888
- void 0,
41889
- ossPath
41890
- );
41891
- console.log(`[MessageProcess] \u6587\u4EF6\u4E34\u65F6\u8BBF\u95EE\u94FE\u63A5: ${publicReadableUrl}\uFF0C\u6709\u6548\u65F6\u957F: 1h`);
41892
- userRequest.metadata.fileUrl = publicReadableUrl;
41893
- userRequest.content = [
41894
- `\u7528\u6237\u901A\u8FC7\u98DE\u4E66\u53D1\u9001\u4E86\u4E00\u4E2A\u6587\u4EF6\u3002`,
41895
- `\u6587\u4EF6\u540D: ${fileName}`,
41896
- `\u6587\u4EF6\u5DF2\u4E0A\u4F20\u81F3\u4E91\u5B58\u50A8\uFF0C\u53EF\u901A\u8FC7\u4EE5\u4E0B URL \u8BBF\u95EE\uFF081\u5C0F\u65F6\u6709\u6548\uFF09:`,
41897
- publicReadableUrl
41898
- ].join("\n");
41899
- return userRequest;
41900
- } catch (err) {
41901
- throw new Error(`[MessageProcess] \u4E0A\u4F20\u6587\u4EF6\u5230\u963F\u91CC\u4E91oss\u5931\u8D25:${err}`);
41902
- }
41922
+ const buffer = await downloadMessageFile(messageId, fileKey);
41923
+ console.log(`[MessageProcess] \u6587\u4EF6\u4E0B\u8F7D\u5B8C\u6210: ${fileName}, \u5927\u5C0F: ${buffer.length} bytes`);
41924
+ const localPath = saveToLocal(userRequest.userId, "files", fileName, buffer);
41925
+ console.log(`[MessageProcess] \u6587\u4EF6\u5DF2\u4FDD\u5B58\u5230\u672C\u5730: ${localPath}`);
41926
+ const ossPath = `${userRequest.userId}/files/${fileKey}_${fileName}`;
41927
+ const ossUrl = await tryUploadToOss(ossPath, buffer);
41928
+ const fileLocation = ossUrl || localPath;
41929
+ userRequest.metadata.fileUrl = fileLocation;
41930
+ userRequest.content = [
41931
+ `\u7528\u6237\u901A\u8FC7\u98DE\u4E66\u53D1\u9001\u4E86\u4E00\u4E2A\u6587\u4EF6\u3002`,
41932
+ `\u6587\u4EF6\u540D: ${fileName}`,
41933
+ ossUrl ? `\u6587\u4EF6\u5DF2\u4E0A\u4F20\u81F3\u4E91\u5B58\u50A8\uFF0C\u53EF\u901A\u8FC7\u4EE5\u4E0B URL \u8BBF\u95EE\uFF081\u5C0F\u65F6\u6709\u6548\uFF09:
41934
+ ${ossUrl}` : `\u6587\u4EF6\u5DF2\u4FDD\u5B58\u5230\u672C\u5730\u8DEF\u5F84:
41935
+ ${localPath}`
41936
+ ].join("\n");
41937
+ return userRequest;
41903
41938
  };
41904
41939
 
41905
41940
  // src/channels/feishu/feishuChannelsPlugin.ts
@@ -42279,9 +42314,23 @@ ${content}
42279
42314
  teamAgentId: "",
42280
42315
  content: replyContent
42281
42316
  };
42282
- const mainAgent = createAgent();
42317
+ const config2 = getDefaultAgentConfig();
42318
+ const mainAgent = createAgent(config2);
42283
42319
  const result = await mainAgent(request);
42284
42320
  console.log(`[mailbox] \u4E3B agent \u5904\u7406\u5B8C ${fromMailboxId} \u7684\u56DE\u4FE1, alreadySent=${result.alreadySent}`);
42321
+ if (!result.alreadySent && result.content && config2.channelPlugin) {
42322
+ try {
42323
+ await config2.channelPlugin.outbound.sendText({
42324
+ cfg: {},
42325
+ to: origin.originUserId,
42326
+ text: result.content,
42327
+ accountId: replyMsg.id
42328
+ });
42329
+ console.log(`[mailbox] \u4E3B agent \u672A\u4E3B\u52A8\u53D1\u9001\uFF0C\u5DF2\u901A\u8FC7\u6E20\u9053\u8865\u53D1\u7ED3\u679C\u7ED9\u7528\u6237 ${origin.originUserId}`);
42330
+ } catch (sendErr) {
42331
+ console.error(`[mailbox] \u8865\u53D1\u6D88\u606F\u5931\u8D25:`, sendErr);
42332
+ }
42333
+ }
42285
42334
  };
42286
42335
  var wakeTeamAgent = async (mailboxId, msgIds) => {
42287
42336
  try {
@@ -46294,7 +46343,7 @@ var systemRoutes = new Hono2();
46294
46343
  var startTime = Date.now();
46295
46344
  systemRoutes.get("/system/info", (c) => {
46296
46345
  return c.json({
46297
- version: true ? "1.5.0" : "unknown",
46346
+ version: true ? "1.7.0" : "unknown",
46298
46347
  uptime: Math.floor((Date.now() - startTime) / 1e3),
46299
46348
  env: process.env.NODE_ENV || "development",
46300
46349
  nodeVersion: process.version