import { default as React } from 'react'; import { AICFOChatSubmissionSource } from '@zeniai/client-analytics'; import { AiCfoQuestionWithAnswer, AiCfoViewSelector, ID, Skill, SkillDetail, SkillDraft, SkillVersion, SkillVisibility, SyntheticAiCfoAnswer, User } from '@zeniai/client-epic-state'; import { AiCfoChatHeaderProps } from './components/AiCfoChatHeader'; import { FileAttachment } from './components/AiCfoInput'; import { AiCfoQuestionAnswerProps } from './components/AiCfoQuestionAnswer'; import { SkillMenuItem } from './components/AiCfoSkillMenu'; import { ResolvedSyntheticAiCfoCard, ResolvedSyntheticAiCfoPolicy } from './components/SyntheticAiCfoAnswerView'; export declare const uniqueFormName: (formId: ID) => `${string}_form`; /** * Desktop viewport (`medium-regular`+): suggested-question **loading** skeleton width in AI CFO * **side panel** only. Explore, dashboard card, and insights use {@link suggestedQuestionTileMaxWidthPct}. */ export declare const AI_CFO_SIDE_PANEL_LOADING_SKELETON_DESKTOP_WIDTH_PERCENTAGE = 75; /** Options for {@link getSampleQuestions} (Explore, side panel, dashboard card). */ export interface GetSampleQuestionsOptions { chipsJustify?: "center" | "flex-start"; /** * When true (default), chips beyond {@link SAMPLE_QUESTION_CHIPS_INITIAL_VISIBLE_COUNT} use * “Show N more” (AI CFO side panel + mobile). When false, all chips show (desktop Explore, dashboard). */ collapseExtraSuggestions?: boolean; isSuggestedQuestionsLoading?: boolean; /** * Desktop viewports only: one row of equal-width loading skeleton pills. No effect on mobile/tablet. */ loadingSkeletonDesktopSingleRow?: boolean; /** Side panel: wider desktop loading skeletons only. */ loadingSkeletonDesktopWidthPct?: number; narrowMobileLoadingSkeleton?: boolean; skeletonPlaceholderCount?: number; } export declare const getSampleQuestions: (isMobile: boolean, onSampleQuestionClick: (input: string, index: number) => void, questionsList?: readonly string[], options?: GetSampleQuestionsOptions) => JSX.Element; /** * Returns true when the most recent answer payload in the session is an * interactive-form visualization AND the user has not yet submitted it * (no synthetic "creating…" / "created…" bubble has been appended for * the latest Q/A). Once the user submits the form, a synthetic bubble * is appended via `appendSyntheticAiCfoAnswer` keyed by the source * `questionAnswerId`; from that point the form is no longer the * primary action surface and the composer should reappear so the user * can keep chatting without having to wait for the next BE answer. * * We peek the last QA pair's `answer` response and inspect * `content.visualization?.type` for `'interactive_form'` — using a * runtime check (rather than the npm-typed union) so this layer doesn't * need to import the new InteractiveFormVisualization shape. */ export declare const isLatestAnswerVisualizationInteractiveForm: (questionAnswers: AiCfoQuestionWithAnswer[] | undefined, syntheticAnswerByQuestionAnswerId: Record) => boolean; export interface AiCfoPageProps { aiCfoView: AiCfoViewSelector; isFullView: boolean; isNewChatSession: boolean; showSampleQuestions: boolean; tableDownloadEndPoint: string; /** * Tenant-wide users surfaced for any interactive-form variant whose schema * needs an owner picker (today: AI Card Creation). Optional so the prop is * harmless for screens that never render an interactive form. */ allUsers?: User[]; autoSubmitEmailLinkQuestion?: boolean; /** Forwarded to the AI Card Policy form (Step 2 search options). */ cardPolicyCategorySearchOptions?: AiCfoQuestionAnswerProps["cardPolicyCategorySearchOptions"]; /** * Forwarded to the AI Card Policy form (`upload` variant, inline * error rendered when the extract call fails). */ cardPolicyDocumentUploadErrorMessage?: AiCfoQuestionAnswerProps["cardPolicyDocumentUploadErrorMessage"]; /** * Forwarded to the AI Card Policy form (`upload` variant, Step 1 * upload pill state). Owners typically wire this to the * `getPolicyDocumentExtractionFetchState` selector. */ cardPolicyDocumentUploadState?: AiCfoQuestionAnswerProps["cardPolicyDocumentUploadState"]; /** CES-owned `aiCardPolicyFormDraft`; forwarded to the card-policy form. */ cardPolicyFormDraft?: AiCfoQuestionAnswerProps["cardPolicyFormDraft"]; /** * Forwarded to the AI Card Policy form — `true` while the * `fetchCardPolicyVendorOptions` request is in flight. Drives the * vendor search dropdown's spinner row. */ cardPolicyIsVendorSearchLoading?: AiCfoQuestionAnswerProps["cardPolicyIsVendorSearchLoading"]; /** Forwarded to the AI Card Policy form (Step 4 toggleable limit rows). */ cardPolicyLimitRowsConfig?: AiCfoQuestionAnswerProps["cardPolicyLimitRowsConfig"]; /** * Forwarded to the AI Card Policy form (`upload` variant, name of * the file shown in the success pill). */ cardPolicyUploadedFileName?: AiCfoQuestionAnswerProps["cardPolicyUploadedFileName"]; /** Forwarded to the AI Card Policy form (Step 1 search options). */ cardPolicyVendorSearchOptions?: AiCfoQuestionAnswerProps["cardPolicyVendorSearchOptions"]; /** CES-owned `aiCardCreationFormDraft`; forwarded to the cards-creation form. */ cardsCreationFormDraft?: AiCfoQuestionAnswerProps["cardsCreationFormDraft"]; /** Credit-account cap for AI card-creation limit fields. */ cardsCreationMaxLimitAmount?: AiCfoQuestionAnswerProps["cardsCreationMaxLimitAmount"]; /** * Optional sticky chat header pinned to the top of the scroll container. * Host screens (e.g. `CardsAiCfoScreen`) supply the agent name + a short * "what I'm doing" subtitle. When omitted the page renders without the * header, preserving the previous layout. */ chatHeader?: AiCfoChatHeaderProps; customPageTitle?: string; emailLinkQuestion?: string; /** * Host-resolved Explore sample chips (API → dynamic config → locale), e.g. from * {@link useAiCfoDashboardSuggestedQuestionsChips}. When unset, falls back to * {@link exploreSuggestedQuestionsOverride} and local dynamic config / locale. */ exploreSuggestedPromptQuestions?: readonly string[]; /** Skeleton chips until {@link exploreSuggestedPromptQuestions} is ready (host fetch settled). */ exploreSuggestedPromptQuestionsLoading?: boolean; /** * Legacy: completed Redux suggested questions only. Prefer {@link exploreSuggestedPromptQuestions}. */ exploreSuggestedQuestionsOverride?: readonly string[]; /** Chat-service export endpoint; absent means no download section is offered. */ exportDownloadEndPoint?: string; /** Seeds uploading file chips in the input (e.g. Storybook). Not submitted. */ initialUploadingFiles?: FileAttachment[]; isFileUploadEnabled?: boolean; /** True while the create-cards mutation is in flight; disables the form CTA. */ isInteractiveFormSubmitting?: boolean; /** Replaces the chat body with the Skills browser. Driven by the left-rail entry. */ isSkillsOpen?: boolean; isUploadPromoVisible?: boolean; /** Debounced (300ms) flush of the card-policy RHF watch subscription. */ onCardPolicyFormChange?: AiCfoQuestionAnswerProps["onCardPolicyFormChange"]; /** Submission handler for the AI Card Policy interactive form. */ onCardPolicyFormSubmit?: AiCfoQuestionAnswerProps["onCardPolicyFormSubmit"]; /** * Forwarded to the AI Card Policy form (`upload` variant). Fired * when the user clears the uploaded document via the × button — owners * should dispatch `clearPolicyDocumentExtraction`. */ onCardPolicyRemoveDocument?: AiCfoQuestionAnswerProps["onCardPolicyRemoveDocument"]; /** * Forwarded to the AI Card Policy form (`upload` variant). Fired * when the user picks a file in Step 1's drop zone — owners should * dispatch `extractPolicyDocument(files)`. */ onCardPolicyUploadDocument?: AiCfoQuestionAnswerProps["onCardPolicyUploadDocument"]; /** * Forwarded to the AI Card Policy form — fired on every keystroke in * the vendor chip picker's search input. The screen owner debounces + * dispatches `fetchCardPolicyVendorOptions(text)`. */ onCardPolicyVendorSearchTextChange?: AiCfoQuestionAnswerProps["onCardPolicyVendorSearchTextChange"]; /** Debounced cards-creation watch flush → `updateAiCardCreationFormDraft`. */ onCardsCreationFormChange?: AiCfoQuestionAnswerProps["onCardsCreationFormChange"]; /** Submission handler for the AI Card Creation interactive form. */ onCardsCreationFormSubmit?: AiCfoQuestionAnswerProps["onCardsCreationFormSubmit"]; /** When question came from navigation (e.g. dashboard), overrides default `email_link` submit source. */ routedInitialQuestionSource?: AICFOChatSubmissionSource; /** Suggestion chip index when the routed question came from a sample chip (e.g. `question_card` or `dashboard_card`). */ routedInitialQuestionSuggestionIndex?: number; skillDetail?: SkillDetail; skillDetailError?: boolean; skillDetailLoading?: boolean; skillRestoreBody?: { macroId: string; version: number; error?: boolean; instructions?: string; loading?: boolean; }; /** Chat-visible skills for the `/` menu (from getSkills). */ skills?: SkillMenuItem[]; /** Authoring. Absent leaves the Skills browser read-only. */ skillSaveError?: boolean; skillSaving?: boolean; /** * Whether the signed-in user may publish a skill tenant-wide. Optional, defaulting to * withheld: a host that has not wired it shows no publish control rather than a button * the API refuses. */ skillsCanPublish?: boolean; /** Full skill list for the browser — richer than the `/` menu's {@link skills}. */ skillsList?: Skill[]; skillsListError?: boolean; skillsListLoading?: boolean; /** * A skill's history and a restore's pinned body, each WITH the identity it belongs to. * * Grouped rather than split into value-plus-key props: the key is not optional relative * to the data, and when they were separate a host could pass one and forget the other — * which shipped, and left history hidden and Restore hanging. The type now refuses it. */ skillVersionHistory?: { macroId: string; versions: SkillVersion[]; error?: boolean; loading?: boolean; }; style?: React.CSSProperties; /** * Client-synthesized "Creating…" / "Created" bubbles for the active * chat session, in chronological order. Rendered after the streamed * Q&A pairs. Defaults to an empty list. */ syntheticAnswers?: SyntheticAiCfoAnswer[]; onCloseClick: () => void; onCopy: (content: string) => void; onNewChatClick: () => void; onStopSubmit: () => void; onSubmit: (input: string, source: AICFOChatSubmissionSource, files?: File[], index?: number, /** Skill reference when the turn came from the `/` menu; chat expands it to instructions. */ macroId?: string) => void; onThumbsDown: (questionAnswerId: ID) => void; onThumbsUp: (questionAnswerId: ID) => void; onToggleCotCollapsed: (questionAnswerId: ID, isCollapsed: boolean) => void; onUpdateScrollYOffset: (scrollYOffset: number) => void; openOnboardingPage: () => void; togglePageView: () => void; updateCurrentInput: (input: string) => void; /** Called when the user first types `/` so the container can fetch skills. */ onCloseSkillDetail?: () => void; onDeleteSkill?: (macroId: string) => void; onEmailLinkQuestionProcessed?: () => void; onFetchSkills?: () => void; onFetchSkillVersionBody?: (macroId: string, version: number) => void; onMenuClick?: () => void; onOpenSkill?: (macroId: string) => void; onRunSkill?: (macroId: string, label: string) => void; onSaveSkill?: (draft: SkillDraft, macroId: string | undefined) => void; /** Publish or unpublish in place. Absent withholds the control. */ onSetSkillVisibility?: (macroId: string, visibility: SkillVisibility) => void; onUploadPromoClose?: () => void; /** * Resolves a newly-created card id to a `{ title, subtitle? }` tile. * Used by the synthetic "Created cards" answer bubble rendered after a * successful AI CFO cards bulk create. */ resolveSyntheticAnswerCardTile?: (cardId: ID) => ResolvedSyntheticAiCfoCard | undefined; /** * Resolves a newly-created card policy template id to a tile. Used by * the synthetic "Created policy" answer bubble. */ resolveSyntheticAnswerPolicyTile?: (templateId: ID) => ResolvedSyntheticAiCfoPolicy | undefined; } declare const AiCfoPage: React.FC; export default AiCfoPage;