mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-15 07:04:01 -06:00
fix: tighten Buzz mention disambiguation
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
const BOT_PUBLIC_KEY = "a".repeat(64);
|
||||
const ALICE_PUBLIC_KEY = "b".repeat(64);
|
||||
const SECOND_ALICE_PUBLIC_KEY = "c".repeat(64);
|
||||
const BOB_PUBLIC_KEY = "d".repeat(64);
|
||||
|
||||
function members(...values: BuzzMentionMember[]): BuzzMentionMember[] {
|
||||
return [{ publicKey: BOT_PUBLIC_KEY, displayName: "OpenClaw" }, ...values];
|
||||
@@ -82,6 +83,51 @@ describe("Buzz outbound mentions", () => {
|
||||
).toEqual([ALICE_PUBLIC_KEY]);
|
||||
});
|
||||
|
||||
it("requires explicit identities to resolve the named member they accompany", () => {
|
||||
const explicitBob = nip19.npubEncode(BOB_PUBLIC_KEY);
|
||||
const roomMembers = members(
|
||||
{ publicKey: ALICE_PUBLIC_KEY, displayName: "Alice" },
|
||||
{ publicKey: SECOND_ALICE_PUBLIC_KEY, displayName: "Alice" },
|
||||
{ publicKey: BOB_PUBLIC_KEY, displayName: "Bob" },
|
||||
);
|
||||
|
||||
expect(() =>
|
||||
resolveBuzzMessageMentions({
|
||||
text: `Hello @Missing (nostr:${explicitBob})`,
|
||||
members: roomMembers,
|
||||
senderPublicKey: BOT_PUBLIC_KEY,
|
||||
}),
|
||||
).toThrow('Buzz mention "@missing" does not match a current room member');
|
||||
|
||||
expect(() =>
|
||||
resolveBuzzMessageMentions({
|
||||
text: `Hello @Alice (nostr:${explicitBob})`,
|
||||
members: roomMembers,
|
||||
senderPublicKey: BOT_PUBLIC_KEY,
|
||||
}),
|
||||
).toThrow('Buzz mention "@alice" is ambiguous');
|
||||
});
|
||||
|
||||
it("bounds ambiguous-member guidance", () => {
|
||||
const duplicateMembers = Array.from({ length: 8 }, (_, index) => ({
|
||||
publicKey: (index + 1).toString(16).repeat(64),
|
||||
displayName: "Alice",
|
||||
}));
|
||||
|
||||
expect(() =>
|
||||
resolveBuzzMessageMentions({
|
||||
text: "Hello @Alice",
|
||||
members: members(...duplicateMembers),
|
||||
senderPublicKey: BOT_PUBLIC_KEY,
|
||||
}),
|
||||
).toThrow(
|
||||
`candidates: ${duplicateMembers
|
||||
.slice(0, 5)
|
||||
.map((member) => nip19.npubEncode(member.publicKey))
|
||||
.join(", ")}, and 3 more.`,
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects explicit identities outside the room and excludes the bot identity", () => {
|
||||
const outsider = "d".repeat(64);
|
||||
expect(() =>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { nip19 } from "nostr-tools";
|
||||
|
||||
export const BUZZ_MENTION_MAX_COUNT = 50;
|
||||
const BUZZ_AMBIGUITY_CANDIDATE_LIMIT = 5;
|
||||
|
||||
export type BuzzMentionMember = {
|
||||
publicKey: string;
|
||||
@@ -243,26 +244,30 @@ export function resolveBuzzMessageMentions(params: {
|
||||
.map((member) => member.displayName)
|
||||
.filter((name): name is string => Boolean(name)),
|
||||
);
|
||||
const hasExplicitMentions = explicitPublicKeys.length > 0;
|
||||
if (hasAtMentionCandidate(stripped) && names.length === 0 && !hasExplicitMentions) {
|
||||
if (hasAtMentionCandidate(stripped) && names.length === 0) {
|
||||
throw new Error(
|
||||
"Buzz mention does not match a current room member; use nostr:npub... for an explicit identity",
|
||||
);
|
||||
}
|
||||
for (const name of names) {
|
||||
const matches = namesToPublicKeys.get(name) ?? [];
|
||||
if (matches.length !== 1) {
|
||||
if (hasExplicitMentions) {
|
||||
if (matches.length === 0) {
|
||||
throw new Error(
|
||||
`Buzz mention "@${name}" does not match a current room member; use nostr:npub... for an explicit identity`,
|
||||
);
|
||||
}
|
||||
if (matches.length > 1) {
|
||||
if (matches.some((publicKey) => explicitPublicKeys.includes(publicKey))) {
|
||||
continue;
|
||||
}
|
||||
if (matches.length === 0) {
|
||||
throw new Error(
|
||||
`Buzz mention "@${name}" does not match a current room member; use nostr:npub... for an explicit identity`,
|
||||
);
|
||||
}
|
||||
const candidates = matches.map((publicKey) => nip19.npubEncode(publicKey)).join(", ");
|
||||
const visibleCandidates = matches
|
||||
.slice(0, BUZZ_AMBIGUITY_CANDIDATE_LIMIT)
|
||||
.map((publicKey) => nip19.npubEncode(publicKey))
|
||||
.join(", ");
|
||||
const hiddenCandidateCount = matches.length - BUZZ_AMBIGUITY_CANDIDATE_LIMIT;
|
||||
const candidateSuffix = hiddenCandidateCount > 0 ? `, and ${hiddenCandidateCount} more` : "";
|
||||
throw new Error(
|
||||
`Buzz mention "@${name}" is ambiguous; candidates: ${candidates}. Use nostr:npub... for an explicit identity`,
|
||||
`Buzz mention "@${name}" is ambiguous; candidates: ${visibleCandidates}${candidateSuffix}. Use nostr:npub... for an explicit identity`,
|
||||
);
|
||||
}
|
||||
const publicKey = matches[0];
|
||||
|
||||
Reference in New Issue
Block a user