@53ai/53ai-openclaw 1.0.6 → 1.0.8

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.esm.js CHANGED
@@ -310,7 +310,7 @@ function parseMessageContent(msg) {
310
310
  }
311
311
 
312
312
  async function sendReply(params) {
313
- const { wsClient, text, toChatId, replyToMsgId, runtime, finish, streamId, isError, errorCode, errorDetails } = params;
313
+ const { wsClient, text, toChatId, replyToMsgId, runtime, finish, streamId, isError, errorCode, errorDetails, isThinking } = params;
314
314
  const reqId = replyToMsgId || streamId;
315
315
  runtime.log?.(`[53aihub] sendReply START: reqId=${reqId}, finish=${finish}, isError=${isError}, textLen=${text?.length || 0}, wsReadyState=${wsClient.readyState}`);
316
316
  if (wsClient.readyState !== 1) {
@@ -371,7 +371,7 @@ async function sendReply(params) {
371
371
  const payload = {
372
372
  req_id: reqId,
373
373
  action: "chat",
374
- status: finish ? "done" : "streaming",
374
+ status: finish ? "done" : isThinking ? "thinking" : "streaming",
375
375
  data: chunk,
376
376
  };
377
377
  const jsonStr = JSON.stringify(payload);
@@ -949,7 +949,6 @@ async function processMessage(params) {
949
949
  cfg: config,
950
950
  dispatcherOptions: {
951
951
  deliver: async (payload, info) => {
952
- state.accumulatedText += payload.text;
953
952
  runtime.log?.(`[53aihub] deliver: kind=${info.kind}, textLen=${payload.text?.length || 0}, accumulatedLen=${state.accumulatedText.length}, isError=${payload.isError}`);
954
953
  if (payload.isError) {
955
954
  const errorMsg = payload.text || "Unknown error";
@@ -969,6 +968,23 @@ async function processMessage(params) {
969
968
  });
970
969
  return;
971
970
  }
971
+ const isCompaction = payload.text?.startsWith("🧹 Compacting context") ||
972
+ state.accumulatedText.startsWith("🧹 Compacting context");
973
+ if (isCompaction && info.kind !== "final") {
974
+ runtime.log?.(`[53aihub] deliver COMPACTION: text preview=${payload.text?.substring(0, 50)}...`);
975
+ await sendReply({
976
+ wsClient,
977
+ text: payload.text || "",
978
+ toChatId: chatId,
979
+ replyToMsgId: body.msgId,
980
+ runtime,
981
+ finish: false,
982
+ streamId: state.streamId,
983
+ isThinking: true,
984
+ });
985
+ return;
986
+ }
987
+ state.accumulatedText += payload.text;
972
988
  if (info.kind !== "final") {
973
989
  runtime.log?.(`[53aihub] deliver STREAMING: accumulatedText preview=${state.accumulatedText.substring(0, 50)}...`);
974
990
  await sendReply({
@@ -1084,7 +1100,7 @@ async function monitorProvider(options) {
1084
1100
  if (isAborted)
1085
1101
  return;
1086
1102
  // 安全: 不在 URL 中传递敏感信息,仅通过 headers 传递认证
1087
- const wsUrl = account.websocketUrl;
1103
+ const wsUrl = account.WSUrl;
1088
1104
  const botId = account.botId || account.config.botId;
1089
1105
  const secret = account.secret || account.token || account.config.secret || account.config.token;
1090
1106
  // 日志输出时隐藏敏感信息
@@ -1183,7 +1199,7 @@ function resolveAccount(cfg, accountId = DEFAULT_ACCOUNT_ID) {
1183
1199
  accountId,
1184
1200
  name: config.name ?? "53AIHub",
1185
1201
  enabled: config.enabled !== false,
1186
- websocketUrl: config.websocketUrl || DEFAULT_WS_URL,
1202
+ WSUrl: config.WSUrl || DEFAULT_WS_URL,
1187
1203
  botId: config.botId ?? config.userId ?? "",
1188
1204
  secret: config.secret ?? config.token ?? "",
1189
1205
  token: config.token ?? config.secret ?? "",
@@ -1204,8 +1220,8 @@ function setAccount(cfg, account) {
1204
1220
  allowFrom: account.allowFrom ?? existing.allowFrom,
1205
1221
  accessPolicy: account.accessPolicy ?? existing.accessPolicy,
1206
1222
  sendThinkingMessage: account.sendThinkingMessage ?? existing.sendThinkingMessage,
1207
- ...(account.websocketUrl || existing.websocketUrl
1208
- ? { websocketUrl: account.websocketUrl ?? existing.websocketUrl }
1223
+ ...(account.WSUrl || existing.WSUrl
1224
+ ? { WSUrl: account.WSUrl ?? existing.WSUrl }
1209
1225
  : {}),
1210
1226
  ...(account.name || existing.name
1211
1227
  ? { name: account.name ?? existing.name }
@@ -1243,10 +1259,10 @@ async function promptSecret(prompter, account) {
1243
1259
  validate: (value) => (value?.trim() ? undefined : "必填"),
1244
1260
  })).trim();
1245
1261
  }
1246
- async function promptWebsocketUrl(prompter, account) {
1262
+ async function promptWSUrl(prompter, account) {
1247
1263
  return String(await prompter.text({
1248
1264
  message: "WebSocket URL (例如: ws://localhost:8080/ws)",
1249
- initialValue: account?.websocketUrl ?? "",
1265
+ initialValue: account?.WSUrl ?? "",
1250
1266
  validate: (value) => {
1251
1267
  const trimmed = value?.trim();
1252
1268
  if (!trimmed)
@@ -1316,11 +1332,11 @@ const aiHubOnboardingAdapter = {
1316
1332
  }
1317
1333
  const botId = await promptBotId(prompter, account);
1318
1334
  const secret = await promptSecret(prompter, account);
1319
- const websocketUrl = await promptWebsocketUrl(prompter, account);
1335
+ const WSUrl = await promptWSUrl(prompter, account);
1320
1336
  const cfgWithAccount = setAccount(cfg, {
1321
1337
  botId,
1322
1338
  secret,
1323
- websocketUrl: websocketUrl || undefined,
1339
+ WSUrl: WSUrl || undefined,
1324
1340
  enabled: true,
1325
1341
  accessPolicy: account.config.accessPolicy ?? "open",
1326
1342
  allowFrom: account.config.allowFrom ?? [],
@@ -1399,7 +1415,7 @@ const aiHubPlugin = {
1399
1415
  enabled: account.enabled,
1400
1416
  configured: Boolean(account.botId?.trim() || account.token?.trim()),
1401
1417
  botId: account.botId,
1402
- websocketUrl: account.websocketUrl,
1418
+ WSUrl: account.WSUrl,
1403
1419
  accessPolicy: account.config.accessPolicy ?? "open",
1404
1420
  }),
1405
1421
  resolveAllowFrom: ({ cfg }) => {
@@ -1568,6 +1584,67 @@ const aiHubPlugin = {
1568
1584
  },
1569
1585
  };
1570
1586
 
1587
+ const compactionSessions = new Map();
1588
+ /**
1589
+ * 从 sessionKey 中解析 chatId
1590
+ * sessionKey 格式: agent:{agentId}:{channel}:direct:{chatId}
1591
+ * 例如: agent:main:53aihub:direct:user123 -> user123
1592
+ */
1593
+ function parseChatIdFromSessionKey(sessionKey) {
1594
+ if (!sessionKey)
1595
+ return null;
1596
+ const parts = sessionKey.split(":");
1597
+ // 格式: agent:{agentId}:{channel}:direct:{chatId}
1598
+ // parts: [0]agent, [1]agentId, [2]channel, [3]direct, [4]chatId
1599
+ if (parts.length >= 5 && parts[2] === CHANNEL_ID && parts[3] === "direct") {
1600
+ return parts[4];
1601
+ }
1602
+ return null;
1603
+ }
1604
+ async function handleBeforeCompaction(event, ctx) {
1605
+ const runtime = getRuntime();
1606
+ const logger = runtime.logging.getChildLogger({ component: "53aihub-compaction" });
1607
+ const log = (msg) => logger.info(msg);
1608
+ log(`before_compaction: sessionKey=${ctx.sessionKey}, channelId=${ctx.channelId}, messageCount=${event.messageCount}`);
1609
+ const sessionKey = ctx.sessionKey || "";
1610
+ if (!sessionKey.startsWith(`${CHANNEL_ID}:`) && !sessionKey.includes(`:${CHANNEL_ID}:`)) {
1611
+ log(`Skipping compaction hook for non-53aihub session: ${sessionKey}`);
1612
+ return;
1613
+ }
1614
+ const chatId = parseChatIdFromSessionKey(sessionKey);
1615
+ if (!chatId) {
1616
+ logger.error(`Cannot parse chatId from sessionKey: ${sessionKey}`);
1617
+ return;
1618
+ }
1619
+ compactionSessions.set(sessionKey, {
1620
+ startTime: Date.now(),
1621
+ messageCount: event.messageCount,
1622
+ });
1623
+ log(`Compaction started for chatId=${chatId}`);
1624
+ }
1625
+ async function handleAfterCompaction(event, ctx) {
1626
+ const runtime = getRuntime();
1627
+ const logger = runtime.logging.getChildLogger({ component: "53aihub-compaction" });
1628
+ const log = (msg) => logger.info(msg);
1629
+ log(`after_compaction: sessionKey=${ctx.sessionKey}, channelId=${ctx.channelId}, messageCount=${event.messageCount}, compactedCount=${event.compactedCount}`);
1630
+ const sessionKey = ctx.sessionKey || "";
1631
+ if (!sessionKey.startsWith(`${CHANNEL_ID}:`) && !sessionKey.includes(`:${CHANNEL_ID}:`)) {
1632
+ log(`Skipping compaction hook for non-53aihub session: ${sessionKey}`);
1633
+ return;
1634
+ }
1635
+ const chatId = parseChatIdFromSessionKey(sessionKey);
1636
+ if (!chatId) {
1637
+ logger.error(`Cannot parse chatId from sessionKey: ${sessionKey}`);
1638
+ return;
1639
+ }
1640
+ const sessionInfo = compactionSessions.get(sessionKey);
1641
+ compactionSessions.delete(sessionKey);
1642
+ if (sessionInfo) {
1643
+ const duration = Date.now() - sessionInfo.startTime;
1644
+ log(`Compaction completed: chatId=${chatId}, duration=${duration}ms, messagesBefore=${sessionInfo.messageCount}, messagesAfter=${event.messageCount}, compacted=${event.compactedCount}`);
1645
+ }
1646
+ }
1647
+
1571
1648
  const plugin = {
1572
1649
  id: "53ai-openclaw",
1573
1650
  name: "53AI OpenClaw",
@@ -1576,6 +1653,8 @@ const plugin = {
1576
1653
  register(api) {
1577
1654
  setRuntime(api.runtime);
1578
1655
  api.registerChannel({ plugin: aiHubPlugin });
1656
+ api.on("before_compaction", handleBeforeCompaction);
1657
+ api.on("after_compaction", handleAfterCompaction);
1579
1658
  },
1580
1659
  };
1581
1660