/** * Opportunity Presenter Agent * * Generates personalized, second-person explanations of why an opportunity * matters to the viewing user. Uses full opportunity data (interpretation, * actors, profiles, intents, index) to produce headline, personalizedSummary, * and suggestedAction for chat tools and user-facing surfaces. */ import { z } from "zod"; import type { Opportunity } from "../../shared/interfaces/database.interface.js"; import type { ChatGraphCompositeDatabase } from "../../shared/interfaces/database.interface.js"; import type { NegotiationContext } from "./negotiation-context.loader.js"; /** * Minimal database interface required by gatherPresenterContext. * Any database adapter that implements these three methods can be passed. */ export type PresenterDatabase = Pick; declare const PresentationSchema: z.ZodObject<{ headline: z.ZodString; personalizedSummary: z.ZodString; suggestedAction: z.ZodString; greeting: z.ZodString; }, "strip", z.ZodTypeAny, { headline: string; personalizedSummary: string; suggestedAction: string; greeting: string; }, { headline: string; personalizedSummary: string; suggestedAction: string; greeting: string; }>; export type OpportunityPresentationResult = z.infer & { /** True when any output field used resilience fallback copy. */ isFallback?: boolean; /** Diagnostic category; never changes production fallback policy. */ fallbackReason?: "timeout" | "error" | "sanitization"; }; /** Input for card presenter call; extends PresenterInput with optional mutual intent count. */ export interface CardPresenterInput extends PresenterInput { /** Number of overlapping intents (for generating mutualIntentsLabel). */ mutualIntentCount?: number; /** * Snapshot of the opportunity's negotiation, if one exists. When status is * `negotiating`, the presenter returns a templated chip without invoking * the LLM. For `pending`/`stalled`/`accepted`/`rejected`, the full * transcript and outcome ground the LLM's explanation. */ negotiationContext?: NegotiationContext; } /** LLM-generated fields for card presentation (buttons are hardcoded by callers, not LLM-generated). */ export declare const CardLLMSchema: z.ZodObject<{ headline: z.ZodString; personalizedSummary: z.ZodString; digestSummary: z.ZodString; suggestedAction: z.ZodString; narratorRemark: z.ZodString; mutualIntentsLabel: z.ZodString; greeting: z.ZodString; }, "strip", z.ZodTypeAny, { headline: string; mutualIntentsLabel: string; personalizedSummary: string; suggestedAction: string; greeting: string; digestSummary: string; narratorRemark: string; }, { headline: string; mutualIntentsLabel: string; personalizedSummary: string; suggestedAction: string; greeting: string; digestSummary: string; narratorRemark: string; }>; /** LLM-generated result from presentCard (callers append button labels from opportunity.constants). */ export type CardLLMResult = z.infer & { /** * True when the LLM call failed and this is fallback-shaped copy built from * raw match reasoning. Callers with strict quality requirements (digests, * long-lived caches) should check this before sending/persisting — fallback * output is otherwise indistinguishable from genuine LLM output. */ isFallback?: boolean; }; /** Full card display contract including hardcoded button labels (assembled by callers). */ export type CardPresentationResult = CardLLMResult & { primaryActionLabel: string; secondaryActionLabel: string; }; /** Input for a single presenter call (all context pre-assembled). */ export interface PresenterInput { viewerContext: string; otherPartyContext: string; matchReasoning: string; category: string; confidence: number; signalsSummary: string; indexName: string; viewerRole: string; opportunityStatus?: string; /** True when this opportunity was created via an explicit introduction (not automatic discovery). */ isIntroduction?: boolean; /** Name of the person who made the introduction, if applicable. */ introducerName?: string; } export declare class OpportunityPresenter { private model; private homeCardModel; constructor(); private invokeWithTimeout; /** * Generate personalized presentation for a single opportunity. */ present(input: PresenterInput, options?: { signal?: AbortSignal; }): Promise; /** * Generate LLM-powered card content (headline, body, narrator remark, mutual-intent label). * Callers append button labels from opportunity.constants. * * When `negotiationContext.status === 'negotiating'`, returns a templated * chip synchronously without invoking the LLM — the card just reflects * "negotiation in progress" at that point. */ presentCard(input: CardPresenterInput): Promise; /** * Process multiple opportunities in parallel with bounded concurrency. */ presentBatch(inputs: PresenterInput[], options?: { concurrency?: number; }): Promise; /** * Process multiple opportunities as cards in parallel with bounded concurrency. * Returns full card display contracts (headline, body, narrator remark, action labels, mutual-intent label). */ presentCardBatch(inputs: CardPresenterInput[], options?: { concurrency?: number; }): Promise; } /** * Build the LLM-facing signal summary while excluding pool adjustments. Pool * disposition is rendered deterministically by the card chip; asking the * presenter to interpret it could turn a demotion into a positive rationale. */ export declare function summarizeSignalsForPresenter(signals: Opportunity['interpretation']['signals']): string; /** * Gather all context needed for the presenter from the database. * Fetches viewer profile, viewer intents, other party profile(s), and index in parallel. * * @param displayCounterpartUserId - When set (e.g. for a radar card), only this counterpart is included in otherPartyContext so the presenter writes about the person on the card. Omitted for introducer view (card shows both parties). */ export declare function gatherPresenterContext(database: PresenterDatabase, opportunity: Opportunity, viewerId: string, displayCounterpartUserId?: string): Promise; export {};