import React__default, { ReactNode } from 'react'; import { AgUiStateMapping } from '@prometheus-ags/entity-graph-core'; export { AgUiStateMapping, ApplyAgUiOptions } from '@prometheus-ags/entity-graph-core'; /** * types.ts — Shared types for the a2ui-react component library. * * All A2UI components build on the AG-UI protocol: agents emit STATE_SNAPSHOT * and STATE_DELTA events, which are projected onto entity-graph-core via * applyAgUiSnapshot / applyAgUiDelta. Components subscribe to the resulting * graph state via useSyncExternalStore. * * MCP tool calling is a PROGRESSIVE ENHANCEMENT — components work without it. * Pass an EntityToolProvider to opt-in. */ type MessageRole = "user" | "assistant" | "system" | "tool"; interface ChatMessage { id: string; role: MessageRole; content: string; /** ISO-8601 timestamp */ createdAt: string; /** Optional name for multi-agent scenarios */ name?: string; /** Non-null when role === "tool" */ toolCallId?: string; /** Raw tool call requests emitted by the assistant */ toolCalls?: ToolCall[]; /** Whether the assistant is still streaming this message */ streaming?: boolean; } interface ToolCall { id: string; type: "function"; function: { name: string; /** JSON-encoded arguments */ arguments: string; }; } type StreamEventType = "MESSAGE_START" | "MESSAGE_DELTA" | "MESSAGE_END" | "TOOL_CALL_START" | "TOOL_CALL_DELTA" | "TOOL_CALL_END" | "STATE_SNAPSHOT" | "STATE_DELTA" | "ERROR" | "DONE"; interface StreamEvent { type: StreamEventType; messageId?: string; delta?: string; snapshot?: Record; patch?: Array<{ op: string; path: string; value?: unknown; }>; toolCallId?: string; toolName?: string; toolArgsDelta?: string; error?: string; } interface ToolDefinition { name: string; description: string; parameters: Record; } interface ToolCallRequest { toolCallId: string; name: string; arguments: Record; } interface ToolCallResult { toolCallId: string; result: unknown; error?: string; } /** * EntityToolProvider — pluggable tool execution layer. * Pass an implementation to enable MCP/function-calling. * When omitted, tool calls are surfaced as pending in the UI but not executed. */ interface EntityToolProvider { /** Return the tools available to the agent */ getTools(): Promise | ToolDefinition[]; /** Execute a single tool call */ executeTool(request: ToolCallRequest): Promise; } interface ChatSession { id: string; messages: ChatMessage[]; isLoading: boolean; error: string | null; /** AG-UI state mappings for entity projection */ mappings?: AgUiStateMapping[]; } type DiffOperation = "add" | "remove" | "replace" | "unchanged"; interface FieldDiff { field: string; op: DiffOperation; before: unknown; after: unknown; } interface EntityDiffResult { entityType: string; entityId: string; fields: FieldDiff[]; snapshotSeq?: number; } type ApprovalStatus = "pending" | "approved" | "rejected"; interface ApprovalRequest { id: string; entityType: string; entityId: string; proposedChanges: Record; status: ApprovalStatus; requestedAt: string; resolvedAt?: string; } type SendMessageFn = (content: string, opts?: { sessionId?: string; }) => Promise; /** * use-chat-session.ts — Core React hook that manages a chat session. * * Responsibilities: * - Maintains local message list (React state, not the entity graph) * - Processes incoming StreamEvents: appends / updates messages in place * - Ingests STATE_SNAPSHOT / STATE_DELTA events into entity-graph-core via * applyAgUiSnapshot / applyAgUiDelta * - Invokes the optional EntityToolProvider when the agent emits tool calls * * This hook is the shared foundation for EntityChat and EntityCopilot. * * Hook→Store layering: this hook calls applyAgUiSnapshot / applyAgUiDelta * (store writes). It never calls useGraphStore directly — that boundary is * maintained in the agent/ module of entity-graph-core. */ interface UseChatSessionOptions { /** Unique session id; defaults to a generated id. */ sessionId?: string; /** * Factory that returns an async-iterable (or ReadableStream) of StreamEvents * given the current messages. The library calls this on every sendMessage(). */ streamFactory: (messages: ChatMessage[]) => AsyncIterable | ReadableStream; /** AG-UI state mappings: project agent state onto entity-graph entities. */ mappings?: AgUiStateMapping[]; /** Optional tool provider for function-calling / MCP. */ toolProvider?: EntityToolProvider; /** Called when a full assistant message has been received. */ onMessage?: (message: ChatMessage) => void; /** Called on stream error. */ onError?: (error: Error) => void; } interface UseChatSessionReturn { session: ChatSession; sendMessage: (content: string) => Promise; clearMessages: () => void; } declare function useChatSession(opts: UseChatSessionOptions): UseChatSessionReturn; /** * entity-chat.tsx — EntityChat: a headless + minimal-shell chat component. * * Architecture: * - Delegates all session management to useChatSession (which calls * applyAgUiSnapshot / applyAgUiDelta — store writes — never directly). * - Renders a minimal but intentional chat UI: message list + input form. * - All styling is done via className overrides so consumers can bring Tailwind, * CSS modules, or any other styling layer. * * Layering: Component → useChatSession hook → applyAgUiSnapshot/Delta (store). * No direct store access from this file. */ interface EntityChatClassNames { root?: string; messageList?: string; message?: string; messageUser?: string; messageAssistant?: string; messageTool?: string; messageSystem?: string; messageContent?: string; inputRow?: string; input?: string; sendButton?: string; statusBar?: string; } interface EntityChatProps extends Omit { /** Required: factory producing a stream of StreamEvents for the given messages. */ streamFactory: UseChatSessionOptions["streamFactory"]; /** Optional render override for a single message. */ renderMessage?: (message: ChatMessage) => React__default.ReactNode; /** Optional render override for the typing indicator. */ renderTypingIndicator?: () => React__default.ReactNode; /** Optional placeholder for the textarea. */ placeholder?: string; /** Class name overrides for each structural slot. */ classNames?: EntityChatClassNames; /** Additional CSS class on the root container. */ className?: string; } /** * EntityChat — a full-page or embedded chat UI backed by entity-graph. * * @example * ```tsx * myAgentStream(messages)} * mappings={[{ entityType: "Order", pointer: "/order", kind: "single" }]} * toolProvider={myMcpProvider} * /> * ``` */ declare function EntityChat({ streamFactory, mappings, toolProvider, sessionId, onMessage, onError, renderMessage, renderTypingIndicator, placeholder, classNames, className, }: EntityChatProps): React__default.ReactElement; /** * entity-copilot.tsx — EntityCopilot: a compact "sidebar copilot" variant. * * Unlike EntityChat (which renders a full chat surface), EntityCopilot is * designed to be embedded inline — a floating panel, a slide-over, or an * editor drawer. It reuses useChatSession for the same entity-graph projection * while providing a narrower component API and a more compact default UI. * * Layering: Component → useChatSession hook → applyAgUiSnapshot/Delta (store). */ interface EntityCopilotProps extends Omit { streamFactory: UseChatSessionOptions["streamFactory"]; /** Title shown at the top of the copilot panel. */ title?: string; /** Placeholder text for the input. */ placeholder?: string; /** Whether the copilot panel is open. Controls visibility via CSS (display). */ open?: boolean; /** Called when the user requests closing (e.g. presses Escape or an X button). */ onClose?: () => void; /** Additional root CSS class. */ className?: string; /** Render override for a single suggestion bubble. */ renderSuggestion?: (message: ChatMessage, index: number) => React__default.ReactNode; /** Quick-reply prompts shown when the message list is empty. */ suggestions?: string[]; } /** * EntityCopilot — embedded AI copilot panel that streams agent responses and * projects them onto the entity graph. * * @example * ```tsx * setShowCopilot(false)} * title="Order Copilot" * streamFactory={(msgs) => agentStream(msgs)} * mappings={[{ entityType: "Order", pointer: "/order", kind: "single" }]} * suggestions={["Summarise this order", "What's the status?"]} * /> * ``` */ declare function EntityCopilot({ streamFactory, mappings, toolProvider, sessionId, onMessage, onError, title, placeholder, open, onClose, className, renderSuggestion, suggestions, }: EntityCopilotProps): React__default.ReactElement | null; /** * entity-stream.tsx — EntityStream: renders a live stream of agent events. * * EntityStream is the lowest-level primitive: it accepts an AsyncIterable of * StreamEvents and renders the raw token stream as it arrives. It is useful for * non-chat contexts — inline LLM completions, "generating..." surfaces, etc. * * STATE_SNAPSHOT / STATE_DELTA events are still projected into the entity graph * just as in EntityChat/EntityCopilot. * * Layering: Component → stores via applyAgUiSnapshot/Delta directly (no * intermediate hook because the component IS the hook surface here — it owns * stream consumption). Entity graph writes go through the core module. */ interface EntityStreamProps { /** The live event stream to consume. Changing this prop replaces the stream. */ stream: AsyncIterable | null | undefined; /** AG-UI mappings so STATE_* events project onto the entity graph. */ mappings?: AgUiStateMapping[]; /** Called with each token delta as it arrives. */ onDelta?: (token: string) => void; /** Called with the fully accumulated text when the stream ends. */ onComplete?: (text: string) => void; /** Called on stream error. */ onError?: (error: Error) => void; /** CSS class on the root element. */ className?: string; /** Render override for the accumulated content. */ renderContent?: (text: string, streaming: boolean) => React__default.ReactNode; /** Placeholder shown before the first token arrives. */ placeholder?: React__default.ReactNode; } /** * EntityStream — consumes a live async-iterable of StreamEvents and renders * the accumulating text in real time. * * @example * ```tsx * setGeneratedText(text)} * /> * ``` */ declare function EntityStream({ stream, mappings, onDelta, onComplete, onError, className, renderContent, placeholder, }: EntityStreamProps): React__default.ReactElement; /** * use-entity-diff.ts — Compute field-level diffs between entity graph states. * * Reuses core time-travel primitives: * - recordGraphSnapshot / restoreGraphSnapshot from devtools-time-travel * - useGraphStore for current live entity data * * This hook does NOT write to the store during diff computation. It reads two * states (a "before" snapshot and the current live graph) and computes a * declarative FieldDiff[] — the rendering is left to EntityDiff / EntityApproval. * * Hook→Store: reads via useGraphStore.getState() (not via React subscribe) so * diff snapshots are point-in-time and do not cause continuous re-renders. */ interface UseEntityDiffOptions { entityType: string; entityId: string; /** If true, include unchanged fields in the result (default: false). */ includeUnchanged?: boolean; } interface UseEntityDiffReturn { /** The computed diff for the entity. Null until a snapshot has been captured. */ diff: EntityDiffResult | null; /** Capture the current graph state as the "before" baseline. */ captureBaseline: () => number; /** The seq of the current baseline snapshot, or null. */ baselineSeq: number | null; /** Restore the graph to the baseline (time-travel rewind). */ restoreBaseline: () => boolean; /** Recompute the diff against the current live graph. */ recompute: () => void; } /** * useEntityDiff — compare the current live entity state against a captured baseline. * * @example * ```ts * const { diff, captureBaseline, restoreBaseline } = useEntityDiff({ * entityType: "Order", * entityId: "ord_123", * }); * * // Before the agent edits, capture the baseline: * captureBaseline(); * * // After the agent has made changes, diff is populated: * diff?.fields.filter(f => f.op !== "unchanged") * ``` */ declare function useEntityDiff({ entityType, entityId, includeUnchanged, }: UseEntityDiffOptions): UseEntityDiffReturn; /** * entity-diff.tsx — EntityDiff: renders a field-level diff of an entity. * * Supports two modes: * - Uncontrolled: manages its own useEntityDiff state (showControls=true default) * - Controlled: accepts an external diff result via the `diff` prop (used by * EntityApproval to share a single hook instance) * * Reuses core time-travel (recordGraphSnapshot / restoreGraphSnapshot) through * the useEntityDiff hook layer. */ interface EntityDiffClassNames { root?: string; table?: string; headerRow?: string; headerCell?: string; row?: string; rowAdd?: string; rowRemove?: string; rowReplace?: string; rowUnchanged?: string; cellField?: string; cellBefore?: string; cellAfter?: string; cellOp?: string; emptyState?: string; controls?: string; captureButton?: string; recomputeButton?: string; restoreButton?: string; } interface EntityDiffProps extends UseEntityDiffOptions { /** * Controlled mode: pass an external diff result (e.g. from a parent * EntityApproval that owns the hook). When provided, the component's internal * useEntityDiff hook is still created (hooks rules require unconditional calls) * but rendering uses the controlled diff. */ externalDiff?: EntityDiffResult | null; /** Whether to show control buttons (capture/recompute/restore). Default: true */ showControls?: boolean; /** Custom renderer for a single field diff row. */ renderRow?: (diff: FieldDiff, index: number) => React__default.ReactNode; /** Custom value formatter; defaults to JSON.stringify. */ formatValue?: (value: unknown) => string; classNames?: EntityDiffClassNames; className?: string; } /** * EntityDiff — renders a before/after field-level diff for a single entity. */ declare function EntityDiff({ entityType, entityId, includeUnchanged, externalDiff, showControls, renderRow, formatValue, classNames, className, }: EntityDiffProps): React__default.ReactElement; /** * entity-approval.tsx — EntityApproval: human-in-the-loop review of agent changes. * * Built on top of: * - useEntityDiff (which reuses recordGraphSnapshot / restoreGraphSnapshot) * - EntityDiff for the visual before/after diff table (controlled via externalDiff) * * Flow: * 1. Before the agent stream starts, `autoCapture` (default true) captures a * baseline on mount. * 2. After the stream completes, click "Refresh diff" to recompute. * 3. User approves → `onApprove(diff)` is called; graph keeps new state. * 4. User rejects → `onReject(diff)` is called; graph is restored to baseline. * * Layering: Component → useEntityDiff hook → recordGraphSnapshot / * restoreGraphSnapshot (store writes). No direct store access here. */ interface EntityApprovalProps { entityType: string; entityId: string; /** Automatically capture a baseline snapshot on mount. Default: true */ autoCapture?: boolean; /** Include unchanged fields in the diff view. Default: false */ includeUnchanged?: boolean; /** Called when the user approves; the entity graph keeps the new state. */ onApprove?: (diff: EntityDiffResult) => void; /** Called when the user rejects; the graph is rewound to the baseline. */ onReject?: (diff: EntityDiffResult) => void; /** Label for the approve button. Default: "Approve" */ approveLabel?: string; /** Label for the reject/restore button. Default: "Reject & Restore" */ rejectLabel?: string; /** Title heading. */ title?: string; /** Additional CSS class on the root element. */ className?: string; /** Render override for the diff section. */ renderDiff?: (diff: EntityDiffResult | null) => React__default.ReactNode; /** Render override for the action buttons. */ renderActions?: (opts: { onApprove: () => void; onReject: () => void; hasChanges: boolean; }) => React__default.ReactNode; } /** * EntityApproval — human-in-the-loop gate for agent-proposed entity changes. * * @example * ```tsx * console.log("Approved", diff)} * onReject={(diff) => console.log("Rejected, graph restored", diff)} * /> * ``` */ declare function EntityApproval({ entityType, entityId, autoCapture, includeUnchanged, onApprove, onReject, approveLabel, rejectLabel, title, className, renderDiff, renderActions, }: EntityApprovalProps): React__default.ReactElement; /** * entity-tool-provider.tsx — React context for EntityToolProvider injection. * * MCP / function-calling is a PROGRESSIVE ENHANCEMENT. Wrap your app (or a * subtree) with to enable tool execution. * When no provider is present, EntityChat / EntityCopilot still render but * tool calls appear as unexecuted in the message list. * * This module also exports useEntityToolProvider() which EntityChat and * EntityCopilot use to read the nearest provider. Passing a `toolProvider` * prop to those components overrides the context. */ interface EntityToolProviderProps { provider: EntityToolProvider; children: ReactNode; } /** * EntityToolProviderContext — wrap a subtree to make a tool provider available * to all EntityChat and EntityCopilot components underneath. * * @example * ```tsx * * * * ``` */ declare function EntityToolProviderContext({ provider, children, }: EntityToolProviderProps): React__default.ReactElement; /** * useEntityToolProvider — read the nearest injected EntityToolProvider. * Returns null when no provider has been injected (MCP is not available). */ declare function useEntityToolProvider(): EntityToolProvider | null; export { type ApprovalRequest, type ApprovalStatus, type ChatMessage, type ChatSession, type DiffOperation, EntityApproval, type EntityApprovalProps, EntityChat, type EntityChatClassNames, type EntityChatProps, EntityCopilot, type EntityCopilotProps, EntityDiff, type EntityDiffClassNames, type EntityDiffProps, type EntityDiffResult, EntityStream, type EntityStreamProps, type EntityToolProvider, EntityToolProviderContext, type EntityToolProviderProps, type FieldDiff, type MessageRole, type SendMessageFn, type StreamEvent, type StreamEventType, type ToolCall, type ToolCallRequest, type ToolCallResult, type ToolDefinition, type UseChatSessionOptions, type UseChatSessionReturn, type UseEntityDiffOptions, type UseEntityDiffReturn, useChatSession, useEntityDiff, useEntityToolProvider };