@unicitylabs/openclaw-unicity 0.3.2 → 0.3.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/channel.ts +25 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unicitylabs/openclaw-unicity",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Unicity wallet identity and encrypted DMs for OpenClaw agents — powered by Sphere SDK",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/channel.ts CHANGED
@@ -453,6 +453,25 @@ export const unicityChannelPlugin = {
453
453
  replyToId?: string;
454
454
  };
455
455
 
456
+ // Nostr pubkey for self-message detection and reply-to-self detection.
457
+ // Group messages use the 32-byte x-only Nostr pubkey (event.pubkey),
458
+ // NOT the 33-byte compressed chainPubkey.
459
+ const myNostrPubkey = sphere.groupChat?.getMyPublicKey?.() ?? null;
460
+
461
+ // Detect if a group message is a reply to one of the agent's own messages.
462
+ // Used to set WasMentioned so the mention gate treats replies-to-self as
463
+ // implicit mentions (same pattern Discord uses for thread replies).
464
+ function isReplyToSelf(msg: GroupMsg): boolean {
465
+ if (!msg.replyToId || !myNostrPubkey) return false;
466
+ try {
467
+ const messages = sphere.groupChat?.getMessages?.(msg.groupId) ?? [];
468
+ const repliedTo = messages.find((m: { id: string }) => m.id === msg.replyToId);
469
+ return repliedTo?.senderPubkey === myNostrPubkey;
470
+ } catch {
471
+ return false;
472
+ }
473
+ }
474
+
456
475
  function dispatchGroupMessage(msg: GroupMsg): void {
457
476
  const senderName = msg.senderNametag ?? msg.senderPubkey.slice(0, 12);
458
477
  const groupData = sphere.groupChat?.getGroup?.(msg.groupId);
@@ -461,6 +480,10 @@ export const unicityChannelPlugin = {
461
480
  const metadataHeader = `[SenderName: ${senderName} | SenderId: ${msg.senderPubkey} | GroupId: ${msg.groupId} | GroupName: ${groupName} | IsOwner: ${isOwner} | CommandAuthorized: ${isOwner}]`;
462
481
  const sanitizedContent = msg.content.replace(/\[(?:SenderName|SenderId|IsOwner|CommandAuthorized|GroupId|GroupName)\s*:/gi, "[BLOCKED:");
463
482
 
483
+ // Treat replies to the agent's own messages as implicit mentions,
484
+ // so the mention gate doesn't skip them (mirrors Discord's behavior).
485
+ const wasMentioned = isReplyToSelf(msg) || undefined;
486
+
464
487
  ctx.log?.info(`[${ctx.account.accountId}] Group message from ${senderName} in ${groupName}: ${msg.content.slice(0, 80)}`);
465
488
 
466
489
  const inboundCtx = runtime.channel.reply.finalizeInboundContext({
@@ -479,6 +502,7 @@ export const unicityChannelPlugin = {
479
502
  SenderId: msg.senderPubkey,
480
503
  IsOwner: isOwner,
481
504
  CommandAuthorized: isOwner,
505
+ WasMentioned: wasMentioned,
482
506
  });
483
507
 
484
508
  runtime.channel.reply
@@ -490,7 +514,7 @@ export const unicityChannelPlugin = {
490
514
  const text = payload.text;
491
515
  if (!text) return;
492
516
  try {
493
- await sphere.groupChat.sendMessage(msg.groupId, text);
517
+ await sphere.groupChat.sendMessage(msg.groupId, text, msg.id);
494
518
  ctx.log?.info(`[${ctx.account.accountId}] Group message sent to ${groupName}: ${text.slice(0, 80)}`);
495
519
  } catch (err) {
496
520
  ctx.log?.error(`[${ctx.account.accountId}] Failed to send group message to ${groupName}: ${err}`);
@@ -509,11 +533,6 @@ export const unicityChannelPlugin = {
509
533
  });
510
534
  }
511
535
 
512
- // Nostr pubkey for self-message detection. Group messages use the 32-byte
513
- // x-only Nostr pubkey (event.pubkey), NOT the 33-byte compressed chainPubkey.
514
- // sphere.groupChat.getMyPublicKey() returns the correct Nostr-format key.
515
- const myNostrPubkey = sphere.groupChat?.getMyPublicKey?.() ?? null;
516
-
517
536
  // Per-group backfill state: buffer messages during the initial burst, then
518
537
  // switch to live dispatch once the burst settles.
519
538
  const groupBackfillStates = new Map<string, GroupBackfillState>();