mirror of
https://github.com/block/buzz.git
synced 2026-11-02 23:41:08 +00:00
fix(sidebar): gate working pill on NIP-OA ownership
Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
committed by
npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f
parent
86d6388e68
commit
07e14d25ad
@@ -1,10 +1,19 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
|
||||
import { resolveActiveWorkingChannelNames } from "./useActiveWorkingChannelsById.ts";
|
||||
import {
|
||||
getOwnedRelayWorkingAgents,
|
||||
mergeWorkingAgents,
|
||||
resolveActiveWorkingChannelNames,
|
||||
} from "./useActiveWorkingChannelsById.ts";
|
||||
|
||||
const VIEWER_PUBKEY =
|
||||
"80c5f18be5aafa62cf6198c6335963ba3306b595288117c8ea2f805fc9bdc94a";
|
||||
const OWNED_RELAY_AGENT_PUBKEY =
|
||||
"a1b2c3d4e5f60718293a4b5c6d7e8f90112233445566778899aabbccddeeff00";
|
||||
|
||||
describe("resolveActiveWorkingChannelNames", () => {
|
||||
it("resolves active agent pubkeys to managed agent names", () => {
|
||||
it("resolves active agent pubkeys to working agent names", () => {
|
||||
const resolved = resolveActiveWorkingChannelNames(
|
||||
{
|
||||
channelId: "chan-1",
|
||||
@@ -34,4 +43,82 @@ describe("resolveActiveWorkingChannelNames", () => {
|
||||
|
||||
assert.deepEqual(resolved.agentNames, ["Ned"]);
|
||||
});
|
||||
|
||||
it("resolves owned relay agent names", () => {
|
||||
const resolved = resolveActiveWorkingChannelNames(
|
||||
{
|
||||
channelId: "chan-1",
|
||||
anchorAt: 0,
|
||||
agentCount: 1,
|
||||
agentPubkeys: [OWNED_RELAY_AGENT_PUBKEY.toUpperCase()],
|
||||
},
|
||||
[{ pubkey: OWNED_RELAY_AGENT_PUBKEY, name: "nadia" }],
|
||||
);
|
||||
|
||||
assert.deepEqual(resolved.agentNames, ["nadia"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getOwnedRelayWorkingAgents", () => {
|
||||
it("keeps relay agents whose NIP-OA owner is the current viewer", () => {
|
||||
assert.deepEqual(
|
||||
getOwnedRelayWorkingAgents(
|
||||
[
|
||||
{ pubkey: OWNED_RELAY_AGENT_PUBKEY, name: "nadia" },
|
||||
{ pubkey: "other-agent", name: "nelson" },
|
||||
],
|
||||
{
|
||||
[OWNED_RELAY_AGENT_PUBKEY]: {
|
||||
displayName: "nadia",
|
||||
avatarUrl: null,
|
||||
nip05Handle: null,
|
||||
ownerPubkey: VIEWER_PUBKEY.toUpperCase(),
|
||||
isAgent: true,
|
||||
},
|
||||
"other-agent": {
|
||||
displayName: "nelson",
|
||||
avatarUrl: null,
|
||||
nip05Handle: null,
|
||||
ownerPubkey: "someone-else",
|
||||
isAgent: true,
|
||||
},
|
||||
},
|
||||
VIEWER_PUBKEY,
|
||||
),
|
||||
[{ pubkey: OWNED_RELAY_AGENT_PUBKEY, name: "nadia", status: "deployed" }],
|
||||
);
|
||||
});
|
||||
|
||||
it("returns no relay agents without a current viewer", () => {
|
||||
assert.deepEqual(
|
||||
getOwnedRelayWorkingAgents(
|
||||
[{ pubkey: OWNED_RELAY_AGENT_PUBKEY, name: "nadia" }],
|
||||
{},
|
||||
undefined,
|
||||
),
|
||||
[],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("mergeWorkingAgents", () => {
|
||||
it("dedupes owned relay agents behind locally managed agents", () => {
|
||||
assert.deepEqual(
|
||||
mergeWorkingAgents(
|
||||
[{ pubkey: "AAAA", name: "Ned", status: "running" }],
|
||||
[
|
||||
{ pubkey: "aaaa", name: "Relay Ned", status: "deployed" },
|
||||
{
|
||||
pubkey: OWNED_RELAY_AGENT_PUBKEY,
|
||||
name: "nadia",
|
||||
status: "deployed",
|
||||
},
|
||||
],
|
||||
),
|
||||
[
|
||||
{ pubkey: "AAAA", name: "Ned", status: "running" },
|
||||
{ pubkey: OWNED_RELAY_AGENT_PUBKEY, name: "nadia", status: "deployed" },
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,16 +5,32 @@ import {
|
||||
useActiveAgentTurnsBridge,
|
||||
useActiveAgentTurnsByChannel,
|
||||
} from "@/features/agents/activeAgentTurnsStore";
|
||||
import { useManagedAgentsQuery } from "@/features/agents/hooks";
|
||||
import {
|
||||
useManagedAgentsQuery,
|
||||
useRelayAgentsQuery,
|
||||
} from "@/features/agents/hooks";
|
||||
import { useManagedAgentObserverBridge } from "@/features/agents/observerRelayStore";
|
||||
import { useUsersBatchQuery } from "@/features/profile/hooks";
|
||||
import { useIdentityQuery } from "@/shared/api/hooks";
|
||||
import type {
|
||||
ManagedAgent,
|
||||
RelayAgent,
|
||||
UserProfileSummary,
|
||||
} from "@/shared/api/types";
|
||||
import { normalizePubkey } from "@/shared/lib/pubkey";
|
||||
|
||||
type WorkingAgentName = Pick<ManagedAgent, "pubkey" | "name">;
|
||||
type WorkingAgent = Pick<ManagedAgent, "pubkey" | "name" | "status">;
|
||||
type OwnedRelayWorkingAgent = Pick<RelayAgent, "pubkey" | "name"> & {
|
||||
status: "deployed";
|
||||
};
|
||||
|
||||
export function resolveActiveWorkingChannelNames(
|
||||
summary: ActiveChannelTurnSummary,
|
||||
managedAgents: readonly { pubkey: string; name: string }[],
|
||||
workingAgents: readonly WorkingAgentName[],
|
||||
): ActiveChannelTurnSummary {
|
||||
const namesByPubkey = new Map(
|
||||
managedAgents.map((agent) => [normalizePubkey(agent.pubkey), agent.name]),
|
||||
workingAgents.map((agent) => [normalizePubkey(agent.pubkey), agent.name]),
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -26,18 +42,81 @@ export function resolveActiveWorkingChannelNames(
|
||||
};
|
||||
}
|
||||
|
||||
export function getOwnedRelayWorkingAgents(
|
||||
relayAgents: readonly Pick<RelayAgent, "pubkey" | "name">[],
|
||||
profiles: Record<string, UserProfileSummary> | undefined,
|
||||
currentPubkey: string | undefined,
|
||||
): OwnedRelayWorkingAgent[] {
|
||||
if (!currentPubkey) return [];
|
||||
|
||||
const normalizedCurrentPubkey = normalizePubkey(currentPubkey);
|
||||
return relayAgents.flatMap((agent) => {
|
||||
const profile = profiles?.[normalizePubkey(agent.pubkey)];
|
||||
if (!profile?.ownerPubkey) return [];
|
||||
if (normalizePubkey(profile.ownerPubkey) !== normalizedCurrentPubkey) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [{ pubkey: agent.pubkey, name: agent.name, status: "deployed" }];
|
||||
});
|
||||
}
|
||||
|
||||
export function mergeWorkingAgents(
|
||||
managedAgents: readonly WorkingAgent[],
|
||||
ownedRelayAgents: readonly WorkingAgent[],
|
||||
): WorkingAgent[] {
|
||||
const seenPubkeys = new Set<string>();
|
||||
const merged: WorkingAgent[] = [];
|
||||
|
||||
for (const agent of [...managedAgents, ...ownedRelayAgents]) {
|
||||
const pubkey = normalizePubkey(agent.pubkey);
|
||||
if (seenPubkeys.has(pubkey)) continue;
|
||||
seenPubkeys.add(pubkey);
|
||||
merged.push(agent);
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function useActiveWorkingChannelsById(): ReadonlyMap<
|
||||
string,
|
||||
ActiveChannelTurnSummary
|
||||
> {
|
||||
const identityQuery = useIdentityQuery();
|
||||
const currentPubkey = identityQuery.data?.pubkey;
|
||||
const managedAgentsQuery = useManagedAgentsQuery();
|
||||
const managedAgents = React.useMemo(
|
||||
() => managedAgentsQuery.data ?? [],
|
||||
[managedAgentsQuery.data],
|
||||
);
|
||||
const relayAgentsQuery = useRelayAgentsQuery();
|
||||
const relayAgents = React.useMemo(
|
||||
() => relayAgentsQuery.data ?? [],
|
||||
[relayAgentsQuery.data],
|
||||
);
|
||||
const relayAgentPubkeys = React.useMemo(
|
||||
() => relayAgents.map((agent) => agent.pubkey),
|
||||
[relayAgents],
|
||||
);
|
||||
const relayAgentProfilesQuery = useUsersBatchQuery(relayAgentPubkeys, {
|
||||
enabled: relayAgentPubkeys.length > 0,
|
||||
});
|
||||
const ownedRelayAgents = React.useMemo(
|
||||
() =>
|
||||
getOwnedRelayWorkingAgents(
|
||||
relayAgents,
|
||||
relayAgentProfilesQuery.data?.profiles,
|
||||
currentPubkey,
|
||||
),
|
||||
[currentPubkey, relayAgentProfilesQuery.data?.profiles, relayAgents],
|
||||
);
|
||||
const workingAgents = React.useMemo(
|
||||
() => mergeWorkingAgents(managedAgents, ownedRelayAgents),
|
||||
[managedAgents, ownedRelayAgents],
|
||||
);
|
||||
|
||||
useManagedAgentObserverBridge(managedAgents);
|
||||
useActiveAgentTurnsBridge(managedAgents);
|
||||
useManagedAgentObserverBridge(workingAgents);
|
||||
useActiveAgentTurnsBridge(workingAgents);
|
||||
|
||||
const activeWorkingChannels = useActiveAgentTurnsByChannel();
|
||||
return React.useMemo(
|
||||
@@ -46,11 +125,11 @@ export function useActiveWorkingChannelsById(): ReadonlyMap<
|
||||
activeWorkingChannels.map((summary) => {
|
||||
const resolvedSummary = resolveActiveWorkingChannelNames(
|
||||
summary,
|
||||
managedAgents,
|
||||
workingAgents,
|
||||
);
|
||||
return [resolvedSummary.channelId, resolvedSummary];
|
||||
}),
|
||||
),
|
||||
[activeWorkingChannels, managedAgents],
|
||||
[activeWorkingChannels, workingAgents],
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user