/** * Builds the `HandlerCallback` the runtime invokes when an action wants to * publish a Farcaster cast — used both by the POST connector and by mention * replies. Attaches agent-generated media as cast embeds, honours * `FARCASTER_DRY_RUN`, sends via `FarcasterClient`, persists cast memories, and * routes success/failure to the supplied `onCompletion`/`onError` hooks. */ import type { Content, HandlerCallback, IAgentRuntime, Memory, UUID } from "@elizaos/core"; import type { Cast as NeynarCast } from "@neynar/nodejs-sdk/build/api"; import type { FarcasterClient } from "../client"; import type { CastId, FarcasterConfig } from "../types"; import { DEFAULT_FARCASTER_ACCOUNT_ID, normalizeFarcasterAccountId } from "./config"; import { createCastMemory, extractCastEmbedUrls, neynarCastToCast } from "./index"; export function standardCastHandlerCallback({ client, runtime, config, roomId, onCompletion, onError, inReplyTo, }: { inReplyTo?: CastId; client: FarcasterClient; runtime: IAgentRuntime; config: FarcasterConfig; roomId: UUID; onCompletion?: (casts: NeynarCast[], memories: Memory[]) => Promise; onError?: (error: unknown) => Promise; }): HandlerCallback { const callback: HandlerCallback = async (content: Content): Promise => { try { const accountId = normalizeFarcasterAccountId( (config as FarcasterConfig & { accountId?: string }).accountId ?? DEFAULT_FARCASTER_ACCOUNT_ID ); if (config.FARCASTER_DRY_RUN) { runtime.logger.info(`[Farcaster] Dry run: would have cast: ${content.text}`); return []; } // Attach agent-generated media as cast embeds so mention replies don't // silently drop attachments (the POST connector already does this) — #8990. const casts = await client.sendCast({ content, inReplyTo, embeds: extractCastEmbedUrls(content), }); if (casts.length === 0) { runtime.logger.warn("[Farcaster] No casts posted"); return []; } const memories: Memory[] = []; for (let i = 0; i < casts.length; i++) { const cast = casts[i]; runtime.logger.success(`[Farcaster] Published cast ${cast.hash}`); const memory = createCastMemory({ roomId, senderId: runtime.agentId, runtime, cast: neynarCastToCast(cast), accountId, }); if (i === 0) { memory.content.actions = content.actions; } await runtime.createMemory(memory, "messages"); memories.push(memory); } if (onCompletion) { await onCompletion(casts, memories); } return memories; } catch (error) { runtime.logger.error( "[Farcaster] Error posting cast:", typeof error === "string" ? error : (error as Error).message ); if (onError) { await onError(error); } return []; } }; return callback; }