From e0725ae97eae70aa5cec704db64655db0724ef37 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Jan 2026 19:09:44 +0000 Subject: [PATCH] fix: build proper q-tag with relay hint and author pubkey for replies When sending replies in NIP-29 and NIP-C7 adapters, now build the full q-tag format per NIP-C7 spec: ["q", eventId, relayUrl, pubkey] Previously only the event ID was included, making it harder for clients to fetch the referenced event. Now: - NIP-29: includes group relay URL and author pubkey - NIP-C7: includes seen relay hint and author pubkey https://claude.ai/code/session_01Jy51Ayk57fzaFuuFFm1j1K --- src/lib/chat/adapters/nip-29-adapter.ts | 13 +++++++++++-- src/lib/chat/adapters/nip-c7-adapter.ts | 17 ++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/lib/chat/adapters/nip-29-adapter.ts b/src/lib/chat/adapters/nip-29-adapter.ts index c2c9a99..79c7601 100644 --- a/src/lib/chat/adapters/nip-29-adapter.ts +++ b/src/lib/chat/adapters/nip-29-adapter.ts @@ -459,9 +459,18 @@ export class Nip29Adapter extends ChatProtocolAdapter { }, ); - // Add q-tag for replies (NIP-29 specific, not in blueprint yet) + // Add q-tag for replies (per NIP-C7 quote tag format) + // Format: ["q", eventId, relayUrl, pubkey] if (options?.replyTo) { - draft.tags.push(["q", options.replyTo]); + // Look up the event to get the author's pubkey for the q-tag + const replyEvent = eventStore.getEvent(options.replyTo); + if (replyEvent) { + // Full q-tag with relay hint and author pubkey + draft.tags.push(["q", options.replyTo, relayUrl, replyEvent.pubkey]); + } else { + // Fallback: at minimum include the relay hint since we know it + draft.tags.push(["q", options.replyTo, relayUrl]); + } } // Add NIP-92 imeta tags for blob attachments (not yet handled by applesauce) diff --git a/src/lib/chat/adapters/nip-c7-adapter.ts b/src/lib/chat/adapters/nip-c7-adapter.ts index ff16fdc..a45994c 100644 --- a/src/lib/chat/adapters/nip-c7-adapter.ts +++ b/src/lib/chat/adapters/nip-c7-adapter.ts @@ -20,6 +20,7 @@ import { isNip05, resolveNip05 } from "@/lib/nip05"; import { getDisplayName, getQuotePointer } from "@/lib/nostr-utils"; import { isValidHexPubkey } from "@/lib/nostr-validation"; import { getProfileContent } from "applesauce-core/helpers"; +import { getSeenRelays } from "applesauce-core/helpers/relays"; import { EventFactory } from "applesauce-core/event-factory"; import { ReactionBlueprint } from "applesauce-common/blueprints"; @@ -232,8 +233,22 @@ export class NipC7Adapter extends ChatProtocolAdapter { factory.setSigner(activeSigner); const tags: string[][] = [["p", partner.pubkey]]; + + // Add q-tag for replies (per NIP-C7 quote tag format) + // Format: ["q", eventId, relayUrl, pubkey] if (options?.replyTo) { - tags.push(["q", options.replyTo]); // NIP-C7 quote tag for threading + const replyEvent = eventStore.getEvent(options.replyTo); + if (replyEvent) { + // Get a relay hint from where we've seen this event + const seenRelays = getSeenRelays(replyEvent); + const relayHint = + seenRelays && seenRelays.size > 0 ? [...seenRelays][0] : ""; + // Full q-tag with relay hint and author pubkey + tags.push(["q", options.replyTo, relayHint, replyEvent.pubkey]); + } else { + // Fallback: just the event ID + tags.push(["q", options.replyTo]); + } } // Add NIP-30 emoji tags