@kognitivedev/ui
v0.2.29
Published
Provider-agnostic React runtime, primitives, shell, and tool UIs for Kognitive chat products
Maintainers
Readme
@kognitivedev/ui
Composable React UI primitives and default components for Kognitive chat experiences.
@kognitivedev/ui is designed as a runtime-aware UI layer, not a locked design system. The package now ships:
- headless-ish primitives for thread, message, composer, and thread-list state
- style-agnostic default components that do not assume Tailwind
- a slot-based
ChatShell - Tool UI registration for rich structured outputs
- a source-based attachment system for product-specific composer flows
Design goals
The package should support apps like product/kognitiv-chat without forcing product visuals into the package.
That means:
- runtime and state live in the package
- shell layout wiring lives in the package
- branding and product-specific navigation stay app-owned
- charts, tables, cards, and citations are rendered through Tool UI
- attachment acquisition is extensible through registered sources
- threads can run in remote or local shell mode
- thread summaries can carry app-owned metadata
Installation
bun add @kognitivedev/ui react react-dom zodCore pieces
Provider
Use KognitiveUI to wire the runtime, thread management, suggestions, local tools, Tool UI registrations, and attachment sources.
import {
KognitiveUI,
createLocalFileAttachmentSource,
} from "@kognitivedev/ui";
export function App() {
return (
<KognitiveUI
agentName="assistant"
threads
attachmentSources={[
createLocalFileAttachmentSource({ label: "Upload file" }),
]}
>
{/* App-owned shell or ChatShell regions go here */}
</KognitiveUI>
);
}Shell
ChatShell is now a structural/runtime composition layer, not a prebuilt final page.
It provides shell state plus reusable layout regions:
- sidebar
- top bar
- hero state
- thread region
- context rail
- composer region
Core pieces:
ChatShelluseChatShellChatShell.RootChatShell.SidebarChatShell.MainChatShell.TopBarChatShell.BodyChatShell.HeroChatShell.ThreadRegionChatShell.ComposerRegionChatShell.ContextRail
Example:
import { ChatShell } from "@kognitivedev/ui";
export function ProductShell() {
return (
<ChatShell>
<ChatShell.Root>
<ChatShell.Sidebar>
{({ threadGroups }) => <MyExactSidebar threadGroups={threadGroups} />}
</ChatShell.Sidebar>
<ChatShell.Main>
<ChatShell.TopBar>
{({ activeThread }) => <MyExactTopBar thread={activeThread} />}
</ChatShell.TopBar>
<ChatShell.Hero>
{({ isEmpty }) => (isEmpty ? <MyExactHero /> : null)}
</ChatShell.Hero>
<ChatShell.ThreadRegion>
{() => <MyExactThreadArea />}
</ChatShell.ThreadRegion>
<ChatShell.ComposerRegion>
{() => <MyExactComposer />}
</ChatShell.ComposerRegion>
</ChatShell.Main>
<ChatShell.ContextRail>
{() => <MyExactContextRail />}
</ChatShell.ContextRail>
</ChatShell.Root>
</ChatShell>
);
}Local thread mode and metadata
When a product does not yet have a live thread backend, KognitiveUI can run threads in local shell mode.
Thread summaries also support app-owned metadata for presentation needs such as:
- pinned state
- display grouping
- custom badges
- product-specific sidebar hints
import { KognitiveUI, type ThreadSummary } from "@kognitivedev/ui";
const seedThreads: ThreadSummary[] = [
{
sessionDbId: "local-c1",
sessionId: "c1",
title: "Q3 revenue summary",
status: "idle",
updatedAt: new Date().toISOString(),
messageCount: 0,
lastUserPreview: "",
lastAssistantPreview: "",
metadata: { pinned: true, group: "Today", time: "2m" },
},
];
export function App() {
return (
<KognitiveUI
agentName="assistant"
threads={{
mode: "local",
initialThreads: seedThreads,
initialActiveSessionId: "c1",
createThread: async (input) => ({
sessionDbId: `local-${crypto.randomUUID()}`,
sessionId: crypto.randomUUID(),
title: input?.title ?? "",
status: "idle",
updatedAt: new Date().toISOString(),
messageCount: 0,
lastUserPreview: "",
lastAssistantPreview: "",
metadata: input?.metadata ?? null,
}),
}}
>
{/* app shell */}
</KognitiveUI>
);
}Default components
The package includes default Thread, ThreadList, Composer, Message, ToolInvocation, and AttachmentPreview components.
These defaults:
- are not Tailwind-based
- use inline styles plus slot overrides
- are intended to be replaceable
First-party message actions
@kognitivedev/ui also ships first-party message actions through ActionBarPrimitive.
Copycopies the current message textFeedbackrenders thumbs-up / thumbs-down UI for assistant messagesRetryregenerates the selected assistant turn by replaying the immediately preceding user messageReloadis a compatibility alias for the same retry behaviorEditenters inline edit mode for user messagesStopstops the current stream
When the current backend thread adapter supports message feedback, feedback state is persisted with thread messages and hydrates back into the UI on reload.
Attachment system
The attachment system is source-based rather than file-picker-only.
Concepts
AttachmentDraft
Represents a composer attachment before or after it is ready to send.
Supported states:
pendinguploadingreadyfailed
AttachmentSource
Represents a way to acquire attachments for the composer.
Examples:
- local files
- URL import
- workspace files
- screenshots
- cloud providers
AttachmentSourceRegistry
Used to register and order sources for the default composer and shell.
Built-in source
The package automatically provides a local file source when none is configured explicitly.
You can also create one directly:
import { createLocalFileAttachmentSource } from "@kognitivedev/ui";
const localFiles = createLocalFileAttachmentSource({
label: "Upload file",
accept: "image/*,.pdf,.txt,.csv",
});Custom sources
Custom sources can acquire drafts asynchronously.
import {
KognitiveUI,
createAttachmentDraft,
createLocalFileAttachmentSource,
type AttachmentSource,
} from "@kognitivedev/ui";
const urlSource: AttachmentSource = {
id: "url-import",
label: "Add URL",
kind: "url",
mode: "custom",
async acquire({ createDraft }) {
return [
createDraft({
sourceId: "url-import",
kind: "url",
name: "Quarterly report",
status: "ready",
externalUrl: "https://example.com/report",
metadata: { url: "https://example.com/report" },
}),
];
},
};
export function App() {
return (
<KognitiveUI
agentName="assistant"
attachmentSources={[
createLocalFileAttachmentSource(),
urlSource,
]}
>
{/* App-owned shell or ChatShell regions go here */}
</KognitiveUI>
);
}Composer attachment APIs
The default Composer supports:
attachmentSourcesrenderAttachmentSourceMenurenderAttachmentPreview
Legacy attachmentMenu is still supported for compatibility, but the structured source APIs are the preferred path.
Tool UI
Rich structured outputs should be rendered through Tool UI, not hardcoded into the shell.
Use Tool UI for:
- charts
- tables
- source cards
- KPI summaries
- action/result cards
Relevant exports:
makeToolUItoolkitToolUIRegistry
Styling and overrides
The default components expose slot-based style and class overrides.
This keeps the package:
- easy to theme from the app
- independent of Tailwind
- reusable across multiple products
The slot helpers are exported from:
SlotOverridesSlotStylesSlotClassNames
Main exports
Components
ChatShellChatShell.RootChatShell.SidebarChatShell.MainChatShell.TopBarChatShell.BodyChatShell.HeroChatShell.ThreadRegionChatShell.ComposerRegionChatShell.ContextRailThreadThreadListComposerMessageAttachmentPreview
Primitives
ThreadPrimitiveMessagePrimitiveComposerPrimitiveThreadListPrimitive
Runtime and hooks
KognitiveUIuseChatShelluseKognitiveChatuseKognitiveuseKognitiveRuntimeuseComposer
Attachment APIs
AttachmentSourceRegistryAttachmentDraftAttachmentSourcecreateAttachmentDraftattachmentDraftFromFilePartcreateLocalFileAttachmentSourceresolveAttachmentFile
Thread APIs
ThreadSummaryThreadCreateInputThreadMetadata
Development
Run package tests:
cd packages/ui
bun run test
bun run test:coverageCurrent coverage thresholds are focused on the maintained default shell layer rather than untouched legacy internals.
Backend adapters
@kognitivedev/ui now requires a backend adapter.
import { KognitiveUI } from "@kognitivedev/ui";
import { createKognitiveUIChatBackend } from "@kognitivedev/adapter-chat-kognitive";
const backend = createKognitiveUIChatBackend();
<KognitiveUI
backend={backend}
agentName="assistant"
threads={{
autoCreate: true,
title: {
source: { mode: "last-n-turns", count: 2 },
trigger: { mode: "first-message" },
},
}}
/>First-party adapters:
@kognitivedev/adapter-chat-kognitive@kognitivedev/adapter-chat-self-hosted@kognitivedev/adapter-chat-local
