import { type TimelineSearchTarget } from "./timeline-search.js"; import { type GenieLoadingOptions } from "../timeline/genie-loading.js"; import type { DraftTimelineAnnotation, SessionEvent, SessionStatus } from "@opengeni/sdk"; import { type ReactNode } from "react"; import { type RenderMessageSender } from "../timeline/message-sender.js"; import { type OlderHistoryLoader } from "../older-history.js"; import { type MarkdownProps } from "./markdown.js"; import { type OpenGeniLinkResolver } from "./open-geni-links.js"; import { type UserMessageDisclosureLabels } from "./user-message-body.js"; import { type AgentMessageItem, type AuthNeededItem, type TimelineGroup, type TimelineItem, type RetainedArtifactLoader, type RetainedScreenshotLoader, type VideoArtifactPlaybackLoader, type ToolRegistry, type TurnSummaryOptions, type UserMessageItem } from "../timeline/index.js"; import { type ResolveSessionTitle } from "../timeline/agent-identity.js"; import { type RenderAllowanceExhausted } from "../timeline/allowance-exhausted-row.js"; import type { AllowanceLabels } from "../usage/allowance-copy.js"; export type MessageTimelineProps = { /** Exact durable search hit; clearing it removes highlighting without moving the reader. */ searchTarget?: TimelineSearchTarget | null | undefined; /** * A durable event sequence to open on once (an inbox item's or notification's * moment): the timeline lands on the row that holds it, or the nearest row * before it, instead of the latest message. Load the window around it first. */ focusSequence?: number | null | undefined; /** Localized user-message disclosure actions, including custom UserMessageBody renderers. */ userMessageDisclosureLabels?: UserMessageDisclosureLabels | undefined; /** Raw session events (projected internally) … */ events?: SessionEvent[] | undefined; /** … or pre-projected items (e.g. from `useSessionEvents().timeline`). */ items?: TimelineItem[] | undefined; /** Current session status (reserved; tip "Working…" chrome removed for now). */ status?: SessionStatus | null | undefined; /** Host-owned controls beside Copy and the timestamp on settled message rows. */ renderMessageActions?: ((item: AgentMessageItem | UserMessageItem) => ReactNode) | undefined; /** * Who sent a person's message, drawn above its bubble. Called only for * messages that carry a sender; return null for the viewer's own messages * or when the host has no identity to show. Omit to show no senders. */ renderMessageSender?: RenderMessageSender | undefined; /** Plug a markdown renderer for message bodies (e.g. streamdown). */ renderMessageText?: ((text: string, item: AgentMessageItem | UserMessageItem, context: { searchTarget: TimelineSearchTarget | null; }) => ReactNode) | undefined; /** * Render assistant `opengeni-html` / `opengeni-site` fences in the default * message renderer (`SessionConversation` supplies the inline Site preview). */ renderInteractiveBlock?: MarkdownProps["renderInteractiveBlock"]; /** Drill into a spawned worker session. */ onOpenSession?: ((sessionId: string) => void) | undefined; /** * Name the agents this session spawns, messages, and hears from. Return the * current display title for a session id, or null when unknown; the * timeline falls back to the title given at spawn, then to generic copy. * Keep the function identity stable across renders. */ resolveSessionTitle?: ResolveSessionTitle | undefined; /** * Deep-link a memory row (a `memory.saved` / `memory.corrected` step) to its * record in the host's memory pane. Opt-in, exactly like `onReconnect`: the * library draws no "View in memory" affordance without a handler — the memory * row is then non-interactive rich content. This is the switch that makes the * deep-link a first-party Opengeni capability without other SDK consumers * opting into it. The app supplies it (it owns routing to the memory pane). */ onMemoryClick?: ((memoryId: string) => void) | undefined; /** * Start the reconnect flow when a tool needs its connection reauthorized. The * app supplies this (it owns the SDK client + workspace): it typically kicks * off `startConnectionOAuth` and redirects, or routes to credential entry. * Rejecting surfaces a calm inline error on the card; the library never draws * a Reconnect button without a handler to run it. */ onReconnect?: ((item: AuthNeededItem) => void | Promise) | undefined; /** Host-owned inline connection setup. Return undefined to use the default recovery card. */ renderAuthNeeded?: ((item: AuthNeededItem) => ReactNode | undefined) | undefined; /** * Replace the "usage limit reached" row shown when a workspace or member * usage allowance stops work (an `allowance_exhausted` refusal). Receives the * typed refusal (scope, reset time) and the default row; return undefined to * keep the default. Use it to point people at your own plan or admin page. */ renderAllowanceExhausted?: RenderAllowanceExhausted | undefined; /** Replace the words of the default "usage limit reached" row. */ allowanceExhaustedLabels?: Partial | undefined; /** * Decide which durable authentication notices this timeline presents. * Defaults to showing every notice. Embedded hosts can suppress notices for * credentials they manage elsewhere without discarding the underlying event. */ shouldRenderAuthNeeded?: ((item: AuthNeededItem) => boolean) | undefined; /** * Resolve a provider domain (from a reconnect card) to a logo URL the host * serves itself — the app maps it through its catalog + `catalogAssetUrl`. * Return null/undefined to fall back to a calm monogram. The library never * fetches an off-origin favicon (CSP + privacy); an unresolved logo is a * monogram, not an external image. */ resolveProviderLogo?: ((providerDomain: string) => string | null | undefined) | undefined; /** * The tool-renderer registry that resolves how each tool call is drawn. * Defaults to {@link defaultToolRegistry}; pass a registry from * `createDefaultToolRegistry({ entries })` to add custom tool renderers. */ toolRegistry?: ToolRegistry | undefined; /** * Open Opengeni object links the agent writes in replies and progress notes: * `artifact:`, `sandbox:`, editable artifacts, and Sites. Return * a host URL (`{ href }`) or action (`{ open }`); unhandled targets render as * unavailable text instead of a console link that 404s inside the host. * Applies to the default message renderer and to any `Markdown` a custom * `renderMessageText` renders. `SessionConversation` supplies file and * sandbox downloads by default. */ resolveLink?: OpenGeniLinkResolver | undefined; /** Resolve opaque retained screenshot receipts through the authenticated host SDK. */ loadRetainedScreenshot?: RetainedScreenshotLoader | undefined; /** Resolve permanent workspace image/file receipts through the authenticated host SDK. */ loadRetainedArtifact?: RetainedArtifactLoader | undefined; /** Mint short-lived native playback sources for retained generated videos. */ loadVideoArtifactPlayback?: VideoArtifactPlaybackLoader | undefined; /** * Display name of the session's active compute target (Connected Machine or * cloud sandbox). When set, exec_command collapsed previews prefix `on {label}`. */ computeLabel?: string | null | undefined; /** Customize collapsed turn facets for this timeline instance. */ genieLoading?: GenieLoadingOptions | undefined; turnSummary?: TurnSummaryOptions | undefined; /** Follow new events when pinned to the bottom. Defaults to true. */ autoFollow?: boolean | undefined; /** Capture a same-row text selection into the host's canonical composer draft. */ onAnnotate?: ((annotation: DraftTimelineAnnotation) => void) | undefined; /** * Hide the floating "Back to your message" pill while the timeline viewport * is shorter than this (px), e.g. a narrow embed above a decision card. * Defaults to 0 (always available). */ questionNavMinViewportHeight?: number | undefined; /** Composer draft quotes currently attached to the next send. */ draftAnnotations?: readonly DraftTimelineAnnotation[] | undefined; /** Open the composer review list for one numbered draft badge. */ onDraftAnnotationSelect?: ((id: string) => void) | undefined; /** Older durable history exists above the current window (see useSessionEvents). */ hasOlder?: boolean | undefined; /** An older window is being fetched; shows the quiet top shimmer. */ loadingOlder?: boolean | undefined; /** * Called when older history should backfill. Existing void, synchronous-value, * and arbitrary-promise callbacks remain supported. Receipt-aware loaders * preserve committed-page direction through wrappers and bounded windows. */ onLoadOlder?: OlderHistoryLoader | undefined; /** Jump to the durable session start (bounded oldest window, no middle). */ onJumpToStart?: (() => void | Promise) | undefined; /** True while the oldest window is loading. */ loadingOldest?: boolean | undefined; /** Newer durable history exists below the current (history) window. */ hasNewer?: boolean | undefined; /** A newer history page is being fetched. */ loadingNewer?: boolean | undefined; /** Page forward through history. Return the request promise to enable inline error/retry. */ onLoadNewer?: (() => unknown) | undefined; /** * Reload the live tip window. When omitted, Jump to latest only re-pins and * scrolls the in-memory window. */ onJumpToLatest?: (() => void | Promise) | undefined; /** @deprecated Retained for source compatibility; contextual prompt navigation * uses only mounted prompts and never invokes this global resolver. */ onJumpToLatestQuestion?: (() => Promise) | undefined; /** Host-owned content appended after timeline groups, such as startup progress. */ trailingState?: ReactNode | undefined; emptyState?: ReactNode | undefined; className?: string | undefined; }; /** * The session timeline: chat messages with streaming deltas, collapsed * activity clusters (reasoning, tool calls, sandbox work), spawned-worker * cards, goal markers, and status transitions. Owns stick-to-bottom scrolling * with a "jump to latest" affordance when the reader scrolls back. */ export declare function MessageTimeline({ resolveLink, renderInteractiveBlock, userMessageDisclosureLabels, searchTarget, focusSequence, events, items, status: _status, renderMessageActions, renderMessageSender, renderMessageText, onOpenSession, resolveSessionTitle, onMemoryClick, onReconnect, renderAuthNeeded, renderAllowanceExhausted, allowanceExhaustedLabels, shouldRenderAuthNeeded, resolveProviderLogo, toolRegistry, loadRetainedScreenshot, loadRetainedArtifact, loadVideoArtifactPlayback, computeLabel, genieLoading, turnSummary, autoFollow, onAnnotate, questionNavMinViewportHeight, draftAnnotations, onDraftAnnotationSelect, hasOlder, loadingOlder, onLoadOlder, onJumpToStart, loadingOldest, hasNewer, loadingNewer, onLoadNewer, onJumpToLatest, trailingState, emptyState, className, }: MessageTimelineProps): import("react").JSX.Element; /** * Settled turns lift the final agent answer out as a sibling group. Include it * in "Copy turn" when present so the chip copies the full assistant reply. * Fenced by turnId so the next turn's answer is never stolen. */ export declare function trailingAgentTextAfterTurn(group: TimelineGroup, next: TimelineGroup | undefined): string | undefined; /** * Render one non-activity timeline item (chat message, status divider, goal * landmark, notice). Exported so the component demo draws the EXACT same rows as * the live app — no forked bubble/goal markup. */ export declare function TimelineRow({ item, renderMessageActions, renderMessageText, onReconnect, renderAuthNeeded, resolveProviderLogo, onOpenSession, loadVideoArtifactPlayback, }: { item: TimelineItem; renderMessageActions?: ((item: AgentMessageItem | UserMessageItem) => ReactNode) | undefined; renderMessageText?: ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode) | undefined; onReconnect?: ((item: AuthNeededItem) => void | Promise) | undefined; /** Host-owned inline connection setup. Return undefined to use the default recovery card. */ renderAuthNeeded?: ((item: AuthNeededItem) => ReactNode | undefined) | undefined; resolveProviderLogo?: ((providerDomain: string) => string | null | undefined) | undefined; onOpenSession?: ((sessionId: string) => void) | undefined; loadVideoArtifactPlayback?: VideoArtifactPlaybackLoader | undefined; }): string | number | bigint | boolean | import("react").JSX.Element | Iterable | Promise | import("react").ReactElement> | import("react").ReactPortal | null | undefined> | null;