adp-openclaw 0.0.64 → 0.0.66

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adp-openclaw",
3
- "version": "0.0.64",
3
+ "version": "0.0.66",
4
4
  "description": "ADP-OpenClaw demo channel plugin (Go WebSocket backend)",
5
5
  "type": "module",
6
6
  "dependencies": {
package/src/monitor.ts CHANGED
@@ -5,6 +5,7 @@ import type { PluginLogger, ClawdbotConfig } from "openclaw/plugin-sdk";
5
5
  import { getAdpOpenclawRuntime, setActiveWebSocket } from "./runtime.js";
6
6
  import {
7
7
  getChatHistory,
8
+ getMergedChatHistory,
8
9
  listSessions,
9
10
  resolveSessionKey,
10
11
  type ChatHistoryResponse,
@@ -387,8 +388,29 @@ async function connectAndHandle(params: ConnectParams): Promise<void> {
387
388
  envelope: envelopeOptions,
388
389
  });
389
390
 
391
+ // Build delivery target for cron jobs
392
+ // Format: adp-openclaw:{userId} for direct delivery via this channel
393
+ const cronDeliveryTarget = `adp-openclaw:${userIdentifier}`;
394
+ const nowMs = Date.now();
395
+
396
+ // Build BodyForAgent with context info for cron jobs (like QQBot does)
397
+ // This tells AI how to set up cron job delivery parameters
398
+ const contextInfo = `你正在通过 ADP-OpenClaw 与用户对话。
399
+
400
+ 【会话上下文】
401
+ - 用户: ${inMsg.user?.username || inMsg.from} (${userIdentifier})
402
+ - 场景: 私聊
403
+ - 当前时间戳(ms): ${nowMs}
404
+ - 定时提醒投递地址: channel=adp-openclaw, to=${cronDeliveryTarget}`;
405
+
406
+ // If message is a command (starts with /), don't inject context
407
+ const agentBody = inMsg.text.startsWith("/")
408
+ ? inMsg.text
409
+ : `${contextInfo}\n\n${inMsg.text}`;
410
+
390
411
  const ctx = runtime.channel.reply.finalizeInboundContext({
391
412
  Body: formattedBody,
413
+ BodyForAgent: agentBody, // AI sees this context with cron delivery info
392
414
  RawBody: inMsg.text,
393
415
  CommandBody: inMsg.text,
394
416
  // User identity: format as "adp-openclaw:{tenantId}:{userId}" for multi-tenant support
@@ -767,18 +789,33 @@ async function connectAndHandle(params: ConnectParams): Promise<void> {
767
789
  try {
768
790
  const limit = historyPayload.limit ?? 200;
769
791
 
770
- // Resolve session key from various inputs
771
- let sessionKey = historyPayload.sessionKey || "main";
772
- if (!historyPayload.sessionKey && historyPayload.conversationId) {
773
- sessionKey = resolveSessionKey(historyPayload.conversationId);
792
+ let result: ChatHistoryResponse;
793
+
794
+ if (historyPayload.sessionKey) {
795
+ // If sessionKey is provided directly, use it as-is
796
+ log?.info(`[adp-openclaw] Using provided sessionKey: ${historyPayload.sessionKey}`);
797
+ result = await getChatHistory(historyPayload.sessionKey, {
798
+ limit,
799
+ log,
800
+ });
801
+ } else if (historyPayload.conversationId) {
802
+ // If conversationId is provided, merge old and new session histories
803
+ // Old format: agent:main:direct:{conversationId}
804
+ // New format: agent:main:adp-openclaw:direct:{conversationId}
805
+ log?.info(`[adp-openclaw] Merging old and new session histories for conversationId: ${historyPayload.conversationId}`);
806
+ result = await getMergedChatHistory(historyPayload.conversationId, {
807
+ limit,
808
+ log,
809
+ });
810
+ } else {
811
+ // Default to "main" session
812
+ log?.info(`[adp-openclaw] Using default session: main`);
813
+ result = await getChatHistory("main", {
814
+ limit,
815
+ log,
816
+ });
774
817
  }
775
818
 
776
- // Use CLI backend only
777
- const result: ChatHistoryResponse = await getChatHistory(sessionKey, {
778
- limit,
779
- log,
780
- });
781
-
782
819
  log?.info(`[adp-openclaw] Sending conv_response: ${result.messages.length} messages (backend=cli)`);
783
820
 
784
821
  // Send response back to GoServer
@@ -482,6 +482,85 @@ export async function getChatHistoryByConversationId(
482
482
  return getOpenClawChatHistory(sessionKey, options);
483
483
  }
484
484
 
485
+ /**
486
+ * Get merged chat history from both old and new sessionKey formats.
487
+ * Old format: agent:main:direct:{conversationId}
488
+ * New format: agent:main:adp-openclaw:direct:{conversationId}
489
+ *
490
+ * This function fetches history from both session keys and merges them by timestamp.
491
+ *
492
+ * @param conversationId - The conversation ID
493
+ * @param options - Optional parameters
494
+ * @returns Merged chat history sorted by timestamp
495
+ */
496
+ export async function getMergedChatHistory(
497
+ conversationId: string,
498
+ options?: {
499
+ limit?: number;
500
+ log?: PluginLogger;
501
+ },
502
+ ): Promise<ChatHistoryResponse> {
503
+ const { limit = 200, log } = options ?? {};
504
+
505
+ // Build both old and new session key formats
506
+ const oldSessionKey = `agent:main:direct:${conversationId}`;
507
+ const newSessionKey = `agent:main:adp-openclaw:direct:${conversationId}`;
508
+
509
+ log?.info?.(`[session-history] Fetching merged history for conversationId: ${conversationId}`);
510
+ log?.info?.(`[session-history] Old sessionKey: ${oldSessionKey}`);
511
+ log?.info?.(`[session-history] New sessionKey: ${newSessionKey}`);
512
+
513
+ // Fetch history from both session keys in parallel
514
+ const [oldResult, newResult] = await Promise.all([
515
+ getChatHistory(oldSessionKey, { limit, log }).catch((err) => {
516
+ log?.debug?.(`[session-history] Failed to fetch old session history: ${err}`);
517
+ return { sessionKey: oldSessionKey, messages: [], hasMore: false } as ChatHistoryResponse;
518
+ }),
519
+ getChatHistory(newSessionKey, { limit, log }).catch((err) => {
520
+ log?.debug?.(`[session-history] Failed to fetch new session history: ${err}`);
521
+ return { sessionKey: newSessionKey, messages: [], hasMore: false } as ChatHistoryResponse;
522
+ }),
523
+ ]);
524
+
525
+ log?.info?.(`[session-history] Old session messages: ${oldResult.messages.length}`);
526
+ log?.info?.(`[session-history] New session messages: ${newResult.messages.length}`);
527
+
528
+ // Merge messages from both sessions
529
+ const allMessages = [...oldResult.messages, ...newResult.messages];
530
+
531
+ // Sort by timestamp (ascending, oldest first)
532
+ allMessages.sort((a, b) => {
533
+ const timeA = a.timestamp ?? 0;
534
+ const timeB = b.timestamp ?? 0;
535
+ return timeA - timeB;
536
+ });
537
+
538
+ // Deduplicate by message id (if available) or content+timestamp
539
+ const seen = new Set<string>();
540
+ const dedupedMessages = allMessages.filter((msg) => {
541
+ // Create a unique key for deduplication
542
+ const key = msg.id || `${msg.role}:${msg.timestamp}:${msg.content.slice(0, 100)}`;
543
+ if (seen.has(key)) {
544
+ return false;
545
+ }
546
+ seen.add(key);
547
+ return true;
548
+ });
549
+
550
+ // Apply limit (return last N messages if exceeds limit)
551
+ const limitedMessages = dedupedMessages.length > limit
552
+ ? dedupedMessages.slice(-limit)
553
+ : dedupedMessages;
554
+
555
+ log?.info?.(`[session-history] Merged total: ${limitedMessages.length} messages`);
556
+
557
+ return {
558
+ sessionKey: newSessionKey, // Return new sessionKey as the primary
559
+ messages: limitedMessages,
560
+ hasMore: false,
561
+ };
562
+ }
563
+
485
564
  // ============================================================================
486
565
  // CLI-based Backend
487
566
  // ============================================================================