@cxyhhhhh/openclaw-qqbot 2.0.0-dev.202607082305 → 2.0.0-dev.202607091556

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.cjs CHANGED
@@ -4819,7 +4819,7 @@ function evaluateMatchedGroupAccessForPolicy(params) {
4819
4819
  return { allowed: true, groupPolicy: params.groupPolicy, reason: "allowed" };
4820
4820
  }
4821
4821
  var DEFAULT_GROUP_POLICY = "open";
4822
- var DEFAULT_GROUP_HISTORY_LIMIT = 50;
4822
+ var DEFAULT_GROUP_HISTORY_LIMIT = 20;
4823
4823
  var DEFAULT_GROUP_CONFIG = {
4824
4824
  requireMention: true,
4825
4825
  ignoreOtherMentions: false,
@@ -9093,7 +9093,7 @@ var import_node_path2 = __toESM(require("path"), 1);
9093
9093
  var import_node_fs2 = __toESM(require("fs"), 1);
9094
9094
  var _cachedOpenclawVersion;
9095
9095
  function getPackageVersion() {
9096
- return true ? "2.0.0-dev.202607082305" : "unknown";
9096
+ return true ? "2.0.0-dev.202607091556" : "unknown";
9097
9097
  }
9098
9098
  function getOpenclawVersion(runtimeVersion) {
9099
9099
  if (_cachedOpenclawVersion) return _cachedOpenclawVersion;
@@ -9541,11 +9541,15 @@ function resolveRuntimeAdapters(rt, log4) {
9541
9541
  ]);
9542
9542
  const rawFinalizeContext = !rawBuildContext ? probeFunction(rt, [["channel", "reply", "finalizeInboundContext"]]) : null;
9543
9543
  const buildInboundContext = rawBuildContext ? (params) => rawBuildContext(params) : rawFinalizeContext ? (params) => {
9544
+ const isCommand = params.access?.commands?.authorized ?? false;
9544
9545
  const rawCtx = {
9545
9546
  Body: params.message.body,
9546
9547
  BodyForAgent: params.message.bodyForAgent,
9547
9548
  RawBody: params.message.rawBody,
9548
9549
  CommandBody: params.message.commandBody ?? params.message.rawBody,
9550
+ CommandSource: isCommand ? "text" : void 0,
9551
+ CommandTurn: params.command ?? void 0,
9552
+ CommandAuthorized: isCommand,
9549
9553
  From: params.from,
9550
9554
  To: params.reply.to,
9551
9555
  SessionKey: params.route.routeSessionKey,
@@ -9560,7 +9564,6 @@ function resolveRuntimeAdapters(rt, log4) {
9560
9564
  Timestamp: params.timestamp ?? Date.now(),
9561
9565
  OriginatingChannel: params.channel,
9562
9566
  OriginatingTo: params.reply.originatingTo ?? params.reply.to,
9563
- CommandAuthorized: false,
9564
9567
  ...params.extra
9565
9568
  };
9566
9569
  return rawFinalizeContext(rawCtx);
@@ -11712,10 +11715,13 @@ async function downloadMediaFile(url, filename, log4) {
11712
11715
  // src/dispatch/body-assembler.ts
11713
11716
  var QUOTE_BEGIN = "[Quoted message begins]";
11714
11717
  var QUOTE_END = "[Quoted message ends]";
11715
- var HISTORY_CTX_START = "[Chat messages since your last reply \u2014 CONTEXT ONLY]";
11716
- var HISTORY_CTX_END = "[CURRENT MESSAGE \u2014 reply to this]";
11717
- var MERGE_CTX_START = "[Merged messages \u2014 CONTEXT ONLY]";
11718
- var MERGE_CTX_END = "[CURRENT MESSAGE \u2014 reply to this one]";
11718
+ var REF_BEGIN = "[Reference message begins]";
11719
+ var REF_END = "[Reference message ends]";
11720
+ var HISTORY_BEGIN = "[Chat history begins]";
11721
+ var HISTORY_END = "[Chat history ends]";
11722
+ var MERGE_CTX_BEGIN = "[Merged messages begins]";
11723
+ var MERGE_CTX_END = "[Merged messages ends]";
11724
+ var CURRENT_MSG = "[Current message]";
11719
11725
  function assembleBody(ctx, msg, account, getRuntime) {
11720
11726
  const rawBody = msg.content ?? "";
11721
11727
  const isGroup = msg.kind === "group";
@@ -11728,7 +11734,7 @@ function assembleBody(ctx, msg, account, getRuntime) {
11728
11734
  const userContent = buildUserContent(ctx.message.content ?? "", processed);
11729
11735
  const quotePart = buildQuotePart(quote);
11730
11736
  const userMessage = mergedMessages && mergedMessages.length > 0 ? buildMergedUserMessage({ messages: mergedMessages, quotePart, isGroup, wasMentioned, getRuntime }) : buildUserMessage({ msg, userContent, quotePart, isGroup, wasMentioned });
11731
- const dynamicCtx = buildDynamicCtx(processed);
11737
+ const dynamicCtx = buildDynamicCtx(processed, msg, quote);
11732
11738
  const agentBody = buildAgentBody({
11733
11739
  userContent,
11734
11740
  base: dynamicCtx + userMessage,
@@ -11754,12 +11760,11 @@ ${voiceText}` : voiceText) + attachmentInfo;
11754
11760
  }
11755
11761
  function buildQuotePart(quote) {
11756
11762
  if (!quote) return "";
11757
- const sender = quote.entry?.senderName ? `${quote.entry.senderName} (${quote.entry.senderId})` : "";
11758
- const senderLine = sender ? `${sender}: ` : "";
11759
11763
  const text = quote.text || "Original content unavailable";
11760
11764
  return `${QUOTE_BEGIN}
11761
- ${senderLine}${text}
11765
+ ${text}
11762
11766
  ${QUOTE_END}
11767
+ ${CURRENT_MSG}
11763
11768
  `;
11764
11769
  }
11765
11770
  function buildUserMessage(input) {
@@ -11767,7 +11772,7 @@ function buildUserMessage(input) {
11767
11772
  const atYouTag = isGroup && wasMentioned ? " (@you)" : "";
11768
11773
  if (isGroup) {
11769
11774
  const senderLabel = formatSenderLabel(msg.senderName, msg.senderId);
11770
- return `[${senderLabel}] ${quotePart}${userContent}${atYouTag}`;
11775
+ return `${quotePart}[${senderLabel}] ${userContent}${atYouTag}`;
11771
11776
  }
11772
11777
  return `${quotePart}${userContent}`;
11773
11778
  }
@@ -11793,7 +11798,7 @@ function buildMergedUserMessage(input) {
11793
11798
  return lines.join("\n");
11794
11799
  }
11795
11800
  const last = lines.pop();
11796
- return [MERGE_CTX_START, ...lines, MERGE_CTX_END, last].join("\n");
11801
+ return [MERGE_CTX_BEGIN, ...lines, MERGE_CTX_END, CURRENT_MSG, last].join("\n");
11797
11802
  }
11798
11803
  function formatMergedLine(ctx, opts) {
11799
11804
  const m3 = ctx.message;
@@ -11814,13 +11819,12 @@ function allSameSender(messages) {
11814
11819
  const first = messages[0]?.message.senderId;
11815
11820
  return messages.every((c) => c.message.senderId === first);
11816
11821
  }
11817
- function buildDynamicCtx(processed) {
11818
- if (!processed) return "";
11822
+ function buildDynamicCtx(processed, msg, quote) {
11819
11823
  const lines = [];
11820
- if (processed.imageUrls.length > 0) {
11824
+ if (processed?.imageUrls.length) {
11821
11825
  lines.push(`- Images: ${processed.imageUrls.join(", ")}`);
11822
11826
  }
11823
- const transcripts = processed.transcripts ?? [];
11827
+ const transcripts = processed?.transcripts ?? [];
11824
11828
  const voiceRefs = unique([
11825
11829
  ...transcripts.map((t) => t.localPath).filter(isNonEmpty),
11826
11830
  ...transcripts.map((t) => t.remoteUrl).filter(isNonEmpty)
@@ -11834,10 +11838,35 @@ function buildDynamicCtx(processed) {
11834
11838
  if (asrTexts.length > 0) {
11835
11839
  lines.push(`- ASR: ${asrTexts.join(" | ")}`);
11836
11840
  }
11841
+ if (!quote) {
11842
+ const elementsCtx = buildMsgElementsContext(msg);
11843
+ if (elementsCtx.length > 0) {
11844
+ lines.push(REF_BEGIN, ...elementsCtx, REF_END);
11845
+ }
11846
+ }
11837
11847
  return lines.length > 0 ? `${lines.join("\n")}
11838
11848
 
11839
11849
  ` : "";
11840
11850
  }
11851
+ function buildMsgElementsContext(msg) {
11852
+ const elements = msg.msgElements;
11853
+ if (!elements || elements.length === 0) return [];
11854
+ const lines = [];
11855
+ let index = 0;
11856
+ for (const el of elements) {
11857
+ const content = el.content?.trim();
11858
+ if (!content) continue;
11859
+ index += 1;
11860
+ const author = el.author;
11861
+ const sender = author?.username ?? "\u672A\u77E5";
11862
+ lines.push(
11863
+ `=== \u6D88\u606F ${index} ===`,
11864
+ `[\u6D88\u606F\u5185\u5BB9] ${content}`,
11865
+ `[\u53D1\u9001\u8005] ${sender}`
11866
+ );
11867
+ }
11868
+ return lines;
11869
+ }
11841
11870
  function unique(arr) {
11842
11871
  return [...new Set(arr)];
11843
11872
  }
@@ -11854,7 +11883,7 @@ function buildAgentBody(input) {
11854
11883
  const label = formatSenderLabel(h2.senderName, h2.senderId);
11855
11884
  return `[${label}] ${h2.content}`;
11856
11885
  }).join("\n");
11857
- return [HISTORY_CTX_START, historyText, "", HISTORY_CTX_END, base].join("\n");
11886
+ return [HISTORY_BEGIN, historyText, "", HISTORY_END, CURRENT_MSG, base].join("\n");
11858
11887
  }
11859
11888
  return base;
11860
11889
  }
@@ -11921,8 +11950,11 @@ function getHistoryStore() {
11921
11950
  if (!_store) _store = new MemoryHistoryStore();
11922
11951
  return _store;
11923
11952
  }
11924
- function clearGroupHistory(groupId) {
11925
- _store?.clear?.(groupId);
11953
+ function historyGroupKey(accountId, groupId) {
11954
+ return `${accountId}:${groupId}`;
11955
+ }
11956
+ function clearGroupHistory(accountId, groupId) {
11957
+ _store?.clear?.(historyGroupKey(accountId, groupId));
11926
11958
  }
11927
11959
 
11928
11960
  // src/middleware/access-control.ts
@@ -12015,6 +12047,14 @@ function setupMiddlewares(bot, account, opts) {
12015
12047
  bot.use(errorHandler());
12016
12048
  bot.use(messageFilter({ skipSelfEcho: false }));
12017
12049
  bot.use(createPolicyInjector(account));
12050
+ bot.use(historyBuffer({
12051
+ store: getHistoryStore(),
12052
+ groupKey: (ctx) => {
12053
+ const gid = ctx.message.groupOpenid;
12054
+ if (ctx.message.kind !== "group" || !gid) return void 0;
12055
+ return historyGroupKey(account.accountId, gid);
12056
+ }
12057
+ }));
12018
12058
  bot.use(dynamicAccessControl({
12019
12059
  accountId: account.accountId,
12020
12060
  getRuntime: opts.getRuntime
@@ -12041,7 +12081,6 @@ function setupMiddlewares(bot, account, opts) {
12041
12081
  bot.use(quoteRef({
12042
12082
  store: getPersistedRefIndexStore(account.accountId)
12043
12083
  }));
12044
- bot.use(historyBuffer({ store: getHistoryStore() }));
12045
12084
  bot.use(attachmentProcessor({ getRuntime: opts.getRuntime }));
12046
12085
  bot.use(envelopeFormatter({
12047
12086
  format: (ctx) => {
@@ -12209,6 +12248,77 @@ async function handleVoiceIntent(text, ctx) {
12209
12248
  }
12210
12249
  }
12211
12250
 
12251
+ // src/dispatch/ctx-builder.ts
12252
+ function buildCtxPayload(params) {
12253
+ const { assembled, envelope, route, msg, ctx, adapters } = params;
12254
+ const isSlashCommand = /^\//.test(assembled.rawBody ?? "");
12255
+ const convKind = envelope.chatScope === "group" ? "group" : "direct";
12256
+ const peerId = convKind === "group" ? envelope.groupId ?? envelope.senderId : envelope.senderId;
12257
+ const groupId = convKind === "group" ? envelope.groupId : void 0;
12258
+ const processed = ctx.state.processedAttachments;
12259
+ const voicePaths = processed?.localMediaPaths?.filter((_2, i) => processed.localMediaTypes?.[i]?.startsWith("audio/")) ?? [];
12260
+ const voiceUrls = processed?.remoteMediaUrls?.filter((_2, i) => processed.remoteMediaUrls?.[i]?.startsWith?.("audio/")) ?? [];
12261
+ const msgTimestamp = msg.timestamp ?? msg.Timestamp;
12262
+ return adapters.buildInboundContext?.({
12263
+ channel: "qqbot",
12264
+ accountId: route.accountId,
12265
+ provider: "qqbot",
12266
+ surface: "qqbot",
12267
+ messageId: envelope.messageId,
12268
+ timestamp: msgTimestamp ? new Date(msgTimestamp).getTime() : Date.now(),
12269
+ from: envelope.targetId,
12270
+ sender: { id: envelope.senderId, name: envelope.senderName },
12271
+ conversation: {
12272
+ kind: convKind,
12273
+ id: peerId,
12274
+ label: assembled.systemPrompt
12275
+ },
12276
+ message: {
12277
+ body: assembled.webBody,
12278
+ bodyForAgent: assembled.agentBody,
12279
+ rawBody: assembled.rawBody,
12280
+ commandBody: assembled.rawBody
12281
+ },
12282
+ route: {
12283
+ agentId: route.agentId ?? "default",
12284
+ routeSessionKey: route.sessionKey,
12285
+ accountId: route.accountId
12286
+ },
12287
+ reply: {
12288
+ to: envelope.targetId,
12289
+ replyToId: envelope.messageId,
12290
+ originatingTo: envelope.targetId
12291
+ },
12292
+ access: {
12293
+ commands: { authorized: isSlashCommand }
12294
+ },
12295
+ command: isSlashCommand ? { kind: "text-slash", body: assembled.rawBody, authorized: true } : void 0,
12296
+ media: voicePaths.length > 0 ? voicePaths.map((p2, i) => ({
12297
+ contentType: processed?.localMediaTypes?.[i] ?? "audio/silk",
12298
+ localPath: p2,
12299
+ url: voiceUrls[i]
12300
+ })) : voiceUrls.length > 0 ? voiceUrls.map((u2) => ({ contentType: "audio/wav", url: u2 })) : void 0,
12301
+ supplemental: {
12302
+ quote: envelope.quote ? { id: envelope.messageId, body: envelope.quote.content, sender: envelope.quote.senderId } : void 0,
12303
+ groupSystemPrompt: envelope.systemPrompt
12304
+ },
12305
+ extra: {
12306
+ ...isSlashCommand ? { CommandSource: "text" } : {},
12307
+ ...groupId ? { QQGroupOpenid: groupId } : {},
12308
+ ...processed?.localMediaPaths?.length ? {
12309
+ MediaPaths: processed.localMediaPaths,
12310
+ MediaPath: processed.localMediaPaths[0],
12311
+ MediaTypes: processed.localMediaTypes,
12312
+ MediaType: processed.localMediaTypes?.[0]
12313
+ } : {},
12314
+ ...processed?.remoteMediaUrls?.length ? {
12315
+ MediaUrls: processed.remoteMediaUrls,
12316
+ MediaUrl: processed.remoteMediaUrls[0]
12317
+ } : {}
12318
+ }
12319
+ });
12320
+ }
12321
+
12212
12322
  // src/outbound/debounce.ts
12213
12323
  var DEFAULT_WINDOW_MS = 1500;
12214
12324
  var DEFAULT_MAX_WAIT_MS = 8e3;
@@ -12446,46 +12556,7 @@ async function dispatchToOpenClaw(ctx, msg, account, runtime2, log4) {
12446
12556
  const qualifiedTarget = envelope.targetId;
12447
12557
  const agentId = route.agentId ?? "default";
12448
12558
  const storePath = adapters.resolveStorePath?.(cfg?.session?.store, { agentId }) ?? "";
12449
- const ctxPayload = adapters.buildInboundContext?.({
12450
- channel: "qqbot",
12451
- accountId: route.accountId,
12452
- provider: "qqbot",
12453
- surface: "qqbot",
12454
- messageId: envelope.messageId,
12455
- timestamp: Date.now(),
12456
- from: envelope.targetId,
12457
- sender: { id: envelope.senderId, name: envelope.senderName },
12458
- conversation: {
12459
- kind: envelope.chatScope === "group" ? "group" : "direct",
12460
- label: assembled.systemPrompt
12461
- },
12462
- message: {
12463
- body: assembled.webBody,
12464
- bodyForAgent: assembled.agentBody,
12465
- rawBody: assembled.rawBody,
12466
- commandBody: assembled.rawBody
12467
- },
12468
- route: {
12469
- routeSessionKey: route.sessionKey,
12470
- accountId: route.accountId
12471
- },
12472
- reply: {
12473
- to: envelope.targetId,
12474
- replyToId: envelope.messageId,
12475
- originatingTo: envelope.targetId
12476
- }
12477
- });
12478
- const processed = ctx.state.processedAttachments;
12479
- if (processed?.localMediaPaths?.length) {
12480
- ctxPayload.MediaPaths = processed.localMediaPaths;
12481
- ctxPayload.MediaPath = processed.localMediaPaths[0];
12482
- ctxPayload.MediaTypes = processed.localMediaTypes;
12483
- ctxPayload.MediaType = processed.localMediaTypes?.[0];
12484
- }
12485
- if (processed?.remoteMediaUrls?.length) {
12486
- ctxPayload.MediaUrls = processed.remoteMediaUrls;
12487
- ctxPayload.MediaUrl = processed.remoteMediaUrls[0];
12488
- }
12559
+ const ctxPayload = buildCtxPayload({ assembled, envelope, route, msg, ctx, adapters });
12489
12560
  const ttsRuntime = runtime2?.tts ?? runtime2?.channel?.runtimeContexts?.get?.("tts");
12490
12561
  const debounceConfig = account.config?.deliverDebounce;
12491
12562
  const debouncer = debounceConfig?.enabled !== false ? new DeliverDebouncer(
@@ -12679,7 +12750,7 @@ async function dispatchToOpenClaw(ctx, msg, account, runtime2, log4) {
12679
12750
  }
12680
12751
  dlog?.debug(`inboundRun completed sessionKey=${route.sessionKey}`);
12681
12752
  if (envelope.chatScope === "group") {
12682
- clearGroupHistory(envelope.groupId ?? envelope.senderId);
12753
+ clearGroupHistory(account.accountId, envelope.groupId ?? envelope.senderId);
12683
12754
  }
12684
12755
  if (streamingController && !streamingController.isTerminal) {
12685
12756
  await streamingController.finalize();