From ebe134fa87a2bed943d57a92a5b2e1c7c5e04976 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Sun, 12 Apr 2026 10:37:16 +0100 Subject: [PATCH 1/2] [#862] Fix linked OWS writer replacing owner profile identity When a user links an OWS wallet as their AI Writer, the agent columns (agent_id, agent_name) are stored on the owner's user row. This caused the owner's profile to display as "AI Writer" with an "AI Agent" badge instead of their own Farcaster identity. Three fixes: - getFullUserProfile: detect when address is agent owner (not agent itself) via isAgentOwner flag - Profile page: use isAgentOwner to show Human badge, FC displayName, FC bio, and relabel agent card as "Linked AI Writer" - getAgentOwnerProfile: return null when queried address is the owner (not the agent wallet), preventing writer listings from showing the owner as "{owner}'s AI Writer" - LinkAIWriter: pass agentWallet at registration time so the owner/agent distinction is available immediately Fixes #862 Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/actions.ts | 18 +++++++++++++++++- src/app/profile/[address]/page.tsx | 26 +++++++++++++++++++------- src/components/AgentRegister.tsx | 1 + 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/lib/actions.ts b/lib/actions.ts index 63b77e80..d99b0ff8 100644 --- a/lib/actions.ts +++ b/lib/actions.ts @@ -101,13 +101,22 @@ export async function getFullUserProfile( dbUser: User | null; fcProfile: FarcasterProfile | null; agentMeta: AgentMetadata | null; + isAgentOwner: boolean; }> { const dbUser = await getUserFromDB(address); const [fcProfile, agentMeta] = await Promise.all([ getFarcasterProfile(address, dbUser), fetchAgentMetadata(address, dbUser), ]); - return { dbUser, fcProfile, agentMeta }; + + // Detect if this address is the agent OWNER (not the agent itself). + // When true, the profile should display human identity, not agent identity. + const normalized = address.toLowerCase(); + const isAgentOwner = agentMeta !== null + && agentMeta.owner?.toLowerCase() === normalized + && (dbUser?.agent_wallet == null || dbUser.agent_wallet.toLowerCase() !== normalized); + + return { dbUser, fcProfile, agentMeta, isAgentOwner }; } /** @@ -280,6 +289,13 @@ export async function getAgentOwnerProfile( const agentUser = await getAgentUserFromDB(writerAddress); if (!agentUser?.agent_id) return null; + // If the queried address IS the agent owner (not the agent wallet), + // this address belongs to the human owner — not an agent. + const normalized = writerAddress.toLowerCase(); + const isOwnerAddress = agentUser.agent_owner?.toLowerCase() === normalized; + const isAgentWallet = agentUser.agent_wallet?.toLowerCase() === normalized; + if (isOwnerAddress && !isAgentWallet) return null; + const ownerProfile = agentUser.agent_owner ? await getFarcasterProfile(agentUser.agent_owner) : null; diff --git a/src/app/profile/[address]/page.tsx b/src/app/profile/[address]/page.tsx index 9ca2b541..d8719516 100644 --- a/src/app/profile/[address]/page.tsx +++ b/src/app/profile/[address]/page.tsx @@ -51,7 +51,9 @@ export default function ProfilePage() { const fcLoading = profileLoading; const agentMeta = fullProfile?.agentMeta ?? null; const agentLoading = profileLoading; - const isAgent = !profileLoading && agentMeta !== null && agentMeta !== undefined; + // Owner of an agent is not an agent themselves — show human identity + const isAgentOwner = fullProfile?.isAgentOwner ?? false; + const isAgent = !profileLoading && agentMeta !== null && !isAgentOwner; // Cumulative claimed royalties (on-chain) const { data: claimedRoyalties } = useQuery({ @@ -146,6 +148,7 @@ export default function ProfilePage() { agentMeta={agentMeta ?? null} agentLoading={agentLoading} isAgent={isAgent} + isAgentOwner={isAgentOwner} claimedRoyalties={claimedRoyalties ?? null} plotBalance={plotBalance ?? null} plotUsdPrice={plotUsdPrice ?? null} @@ -209,6 +212,7 @@ function ProfileHeader({ agentMeta, agentLoading, isAgent, + isAgentOwner, claimedRoyalties, plotBalance, plotUsdPrice, @@ -226,6 +230,7 @@ function ProfileHeader({ agentMeta: AgentMetadata | null; agentLoading: boolean; isAgent: boolean; + isAgentOwner: boolean; claimedRoyalties: bigint | null; plotBalance: bigint | null; plotUsdPrice: number | null; @@ -246,7 +251,10 @@ function ProfileHeader({ enabled: hasOwner, }); - const displayName = agentMeta?.name ?? fcProfile?.displayName ?? null; + // Agent owners should show their own FC name, not the agent name + const displayName = isAgentOwner + ? fcProfile?.displayName ?? null + : agentMeta?.name ?? fcProfile?.displayName ?? null; const hasFarcaster = dbUser?.fid != null && dbUser?.username != null; const hasX = dbUser?.twitter != null; const hasQuotient = dbUser?.quotient_score != null; @@ -293,8 +301,10 @@ function ProfileHeader({ {isOwnProfile && } - {/* Bio */} - {agentMeta?.description ? ( + {/* Bio — agent owners show their own FC bio, not the agent description */} + {isAgentOwner ? ( + fcProfile?.bio ?

{fcProfile.bio}

: null + ) : agentMeta?.description ? (

{agentMeta.description}

) : fcProfile?.bio ? (

{fcProfile.bio}

@@ -401,11 +411,13 @@ function ProfileHeader({ )} - {/* Agent Identity card — shown for registered agents */} - {isAgent && agentMeta && ( + {/* Agent Identity card — shown for registered agents and agent owners */} + {(isAgent || isAgentOwner) && agentMeta && (
- Agent Identity + + {isAgentOwner ? "Linked AI Writer" : "Agent Identity"} + ERC-8004
diff --git a/src/components/AgentRegister.tsx b/src/components/AgentRegister.tsx index 5d1d55d2..1e1c6f07 100644 --- a/src/components/AgentRegister.tsx +++ b/src/components/AgentRegister.tsx @@ -128,6 +128,7 @@ function LinkAIWriter() { name: "AI Writer", description: "AI fiction writer linked via PlotLink OWS", agentOwner: address, + agentWallet: owsWallet.toLowerCase(), }), }); if (!cacheRes.ok) { From ec5a7c25e0623ad9b4e1645c5465c3216cfc5332 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Sun, 12 Apr 2026 10:44:04 +0100 Subject: [PATCH 2/2] [#862] Revert premature agentWallet write in LinkAIWriter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove agentWallet from agent-register call — agent_wallet should only be persisted after the on-chain setAgentWallet tx succeeds (which already happens in handleWalletBind). The isAgentOwner detection in getFullUserProfile already handles agent_wallet=null correctly by treating the address as the owner. Addresses @re1 review feedback on PR #863. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/AgentRegister.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/AgentRegister.tsx b/src/components/AgentRegister.tsx index 1e1c6f07..5d1d55d2 100644 --- a/src/components/AgentRegister.tsx +++ b/src/components/AgentRegister.tsx @@ -128,7 +128,6 @@ function LinkAIWriter() { name: "AI Writer", description: "AI fiction writer linked via PlotLink OWS", agentOwner: address, - agentWallet: owsWallet.toLowerCase(), }), }); if (!cacheRes.ok) {