diff --git a/lib/actions.ts b/lib/actions.ts index d99b0ff8..cf0a64d5 100644 --- a/lib/actions.ts +++ b/lib/actions.ts @@ -111,10 +111,15 @@ export async function getFullUserProfile( // Detect if this address is the agent OWNER (not the agent itself). // When true, the profile should display human identity, not agent identity. + // Direct agents (agent_type='direct') are the agent themselves — isAgentOwner stays false. + // OWS-linked writers (agent_type='ows-writer') have a separate human owner — isAgentOwner is true. + // Legacy rows (agent_type=null) fall back to the old wallet-null heuristic for backward compat. const normalized = address.toLowerCase(); - const isAgentOwner = agentMeta !== null - && agentMeta.owner?.toLowerCase() === normalized - && (dbUser?.agent_wallet == null || dbUser.agent_wallet.toLowerCase() !== normalized); + const isOwner = agentMeta !== null && agentMeta.owner?.toLowerCase() === normalized; + const isAgentOwner = isOwner + && (dbUser?.agent_type === "ows-writer" + || (dbUser?.agent_type == null + && (dbUser?.agent_wallet == null || dbUser.agent_wallet.toLowerCase() !== normalized))); return { dbUser, fcProfile, agentMeta, isAgentOwner }; } @@ -289,12 +294,17 @@ 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), + // If the queried address is an OWS-linked owner (not the agent itself), // this address belongs to the human owner — not an agent. + // Direct agents (agent_type='direct') are the agent themselves and should not be excluded. + // Legacy rows (agent_type=null) fall back to the old wallet-null heuristic. const normalized = writerAddress.toLowerCase(); const isOwnerAddress = agentUser.agent_owner?.toLowerCase() === normalized; const isAgentWallet = agentUser.agent_wallet?.toLowerCase() === normalized; - if (isOwnerAddress && !isAgentWallet) return null; + const isLinkedOwner = isOwnerAddress + && (agentUser.agent_type === "ows-writer" + || (agentUser.agent_type == null && !isAgentWallet)); + if (isLinkedOwner) return null; const ownerProfile = agentUser.agent_owner ? await getFarcasterProfile(agentUser.agent_owner) diff --git a/lib/supabase.ts b/lib/supabase.ts index 42ede9e9..8d5170d9 100644 --- a/lib/supabase.ts +++ b/lib/supabase.ts @@ -435,6 +435,7 @@ export interface Database { agent_llm_model: string | null; agent_wallet: string | null; agent_owner: string | null; + agent_type: string | null; agent_registered_at: string | null; stats_fetched_at: string | null; steemhunt_fetched_at: string | null; @@ -478,6 +479,7 @@ export interface Database { agent_llm_model?: string | null; agent_wallet?: string | null; agent_owner?: string | null; + agent_type?: string | null; agent_registered_at?: string | null; stats_fetched_at?: string | null; steemhunt_fetched_at?: string | null; @@ -521,6 +523,7 @@ export interface Database { agent_llm_model?: string | null; agent_wallet?: string | null; agent_owner?: string | null; + agent_type?: string | null; agent_registered_at?: string | null; stats_fetched_at?: string | null; steemhunt_fetched_at?: string | null; diff --git a/package.json b/package.json index 41932f40..a61a0560 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plotlink", - "version": "0.1.23", + "version": "0.1.24", "private": true, "workspaces": [ "packages/*" diff --git a/src/app/api/user/agent-register/route.ts b/src/app/api/user/agent-register/route.ts index 6e1c38fc..b655bb36 100644 --- a/src/app/api/user/agent-register/route.ts +++ b/src/app/api/user/agent-register/route.ts @@ -8,12 +8,15 @@ import { createServiceRoleClient } from "../../../../../lib/supabase"; export async function POST(request: NextRequest) { try { const body = await request.json(); - const { walletAddress, agentId, name, description, genre, llmModel, agentWallet, agentOwner } = body; + const { walletAddress, agentId, name, description, genre, llmModel, agentWallet, agentOwner, agentType } = body; if (!walletAddress || typeof walletAddress !== "string" || !agentId) { return NextResponse.json({ error: "walletAddress and agentId are required" }, { status: 400 }); } + const VALID_AGENT_TYPES = ["direct", "ows-writer"] as const; + const validatedAgentType = VALID_AGENT_TYPES.includes(agentType) ? agentType : null; + const supabase = createServiceRoleClient(); if (!supabase) { return NextResponse.json({ error: "Database not configured" }, { status: 500 }); @@ -57,6 +60,7 @@ export async function POST(request: NextRequest) { agent_llm_model: llmModel || null, agent_wallet: agentWallet?.toLowerCase() || null, agent_owner: (agentOwner || walletAddress).toLowerCase(), + agent_type: validatedAgentType, agent_registered_at: new Date().toISOString(), }; diff --git a/src/components/AgentRegister.tsx b/src/components/AgentRegister.tsx index 5d1d55d2..e10a07b4 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, + agentType: "ows-writer", }), }); if (!cacheRes.ok) { @@ -362,6 +363,7 @@ function DirectRegister() { genre: meta.genre, llmModel: meta.llmModel, agentOwner: address, + agentType: "direct", }), }); if (!cacheRes.ok) { diff --git a/supabase/migrations/00032_users_agent_type.sql b/supabase/migrations/00032_users_agent_type.sql new file mode 100644 index 00000000..5ccb1e3a --- /dev/null +++ b/supabase/migrations/00032_users_agent_type.sql @@ -0,0 +1,4 @@ +-- Distinguish direct agent registrations from linked OWS writer owners. +-- 'direct' = owner IS the agent (show agent profile) +-- 'ows-writer' = owner linked an OWS writer (show human profile with linked AI card) +ALTER TABLE users ADD COLUMN IF NOT EXISTS agent_type TEXT;