JSPM

  • Created
  • Published
  • Downloads 4618
  • Score
    100M100P100Q133035F
  • License MIT

UI components for the Agenttic framework

Package Exports

  • @automattic/agenttic-ui
  • @automattic/agenttic-ui/index.css

Readme

@automattic/agenttic-ui

React UI components for AI agent chat interfaces. A pure UI layer designed to work seamlessly with @automattic/agenttic-client hooks or any agent communication system.

Installation

npm install @automattic/agenttic-ui

Key Features

  • Pure UI components with no agent communication logic
  • Floating and embedded chat variants
  • Smooth animations and drag-and-drop positioning
  • Message actions and markdown rendering
  • TypeScript support with comprehensive types
  • Storybook component documentation
  • Modular component architecture for custom layouts

Quick Start

Complete Chat Interface

import { useAgentChat } from '@automattic/agenttic-client';
import { AgentUI } from '@automattic/agenttic-ui';

function ChatApplication() {
  const {
    messages,
    isProcessing,
    error,
    onSubmit,
    suggestions,
    clearSuggestions,
    messageRenderer
  } = useAgentChat({
    agentId: 'big-sky',
    sessionId: 'my-session'
  });

  return (
    <AgentUI
      messages={messages}
      isProcessing={isProcessing}
      error={error}
      onSubmit={onSubmit}
      suggestions={suggestions}
      clearSuggestions={clearSuggestions}
      messageRenderer={messageRenderer}
      variant="floating"
      placeholder="Ask me anything..."
    />
  );
}

Embedded Chat

<AgentUI
  messages={messages}
  isProcessing={isProcessing}
  error={error}
  onSubmit={onSubmit}
  variant="embedded"
  placeholder="How can I help you?"
/>

Core Components

AgentUI

The main component that provides a complete chat interface.

interface AgentUIProps {
  // Core chat data
  messages: Message[];
  isProcessing: boolean;
  error?: string | null;
  onSubmit: (message: string) => void;

  // UI configuration
  variant?: 'floating' | 'embedded';
  placeholder?: string;
  triggerIcon?: React.ReactNode;
  notice?: NoticeConfig;
  emptyView?: React.ReactNode;

  // Chat state management (floating variant)
  floatingChatState?: ChatState;
  onOpen?: () => void;
  onExpand?: () => void;
  onClose?: () => void;

  // Suggestions
  suggestions?: Suggestion[];
  clearSuggestions?: () => void;

  // Message rendering
  messageRenderer?: ComponentType<{ children: string }>;

  // Styling
  className?: string;
  style?: React.CSSProperties;
}

Variants:

  • floating - Draggable chat widget with collapsed/compact/expanded states
  • embedded - Fixed chat interface for integration in existing layouts

Individual Components

For custom chat layouts, use individual components:

import {
  Chat,
  Messages,
  Message,
  ChatInput,
  Suggestions
} from '@automattic/agenttic-ui';

function CustomChat() {
  return (
    <div className="my-chat-container">
      <Messages messages={messages} messageRenderer={messageRenderer} />
      <Suggestions 
        suggestions={suggestions} 
        onSuggestionClick={onSubmit}
        onClear={clearSuggestions}
      />
      <ChatInput
        value={inputValue}
        onChange={setInputValue}
        onSubmit={onSubmit}
        placeholder="Type a message..."
        isProcessing={isProcessing}
      />
    </div>
  );
}

Component APIs

Chat

Main chat component supporting both floating and embedded variants.

<Chat
  messages={messages}
  isProcessing={isProcessing}
  error={error}
  onSubmit={onSubmit}
  variant="floating"
  placeholder="Ask anything..."
  suggestions={suggestions}
  clearSuggestions={clearSuggestions}
  messageRenderer={messageRenderer}
/>

Messages

Container for displaying message history.

<Messages 
  messages={messages}
  messageRenderer={messageRenderer}
  emptyView={<div>No messages yet</div>}
/>

Message

Individual message component with action support.

<Message
  message={message}
  messageRenderer={messageRenderer}
  showIcon={true}
/>

ChatInput

Text input with auto-resize and submit handling.

<ChatInput
  value={value}
  onChange={setValue}
  onSubmit={handleSubmit}
  onKeyDown={handleKeyDown}
  placeholder="Type a message..."
  isProcessing={false}
  textareaRef={textareaRef}
/>

Suggestions

Quick action suggestions for users.

<Suggestions
  suggestions={[
    { id: '1', label: 'Help me code', prompt: 'Can you help me write code?' },
    { id: '2', label: 'Explain concept', prompt: 'Explain this concept to me' }
  ]}
  onSuggestionClick={onSubmit}
  onClear={clearSuggestions}
/>

Hooks

useChat

Manages chat state for floating variant.

const {
  state,        // 'collapsed' | 'compact' | 'expanded'
  setState,
  isOpen,       // boolean
  open,         // () => void
  close,        // () => void
  toggle        // () => void
} = useChat(initialState);

useInput

Manages text input state with auto-resize and keyboard handling.

const {
  value,
  setValue,
  clear,
  textareaRef,
  handleKeyDown,
  adjustHeight
} = useInput({
  value: inputValue,
  setValue: setInputValue,
  onSubmit: handleSubmit,
  isProcessing: false
});

Icons

Pre-built icon components for consistent UI:

import {
  ThumbsUpIcon,
  ThumbsDownIcon,
  CopyIcon,
  StopIcon,
  ArrowUpIcon,
  XIcon,
  BigSkyIcon,
  StylesIcon
} from '@automattic/agenttic-ui';

Type Definitions

interface Message {
  id: string;
  role: 'user' | 'agent';
  content: Array<{
    type: 'text' | 'image_url' | 'component';
    text?: string;
    image_url?: string;
    component?: React.ComponentType;
    componentProps?: any;
  }>;
  timestamp: number;
  archived: boolean;
  showIcon: boolean;
  icon?: string;
  actions?: MessageAction[];
}

interface MessageAction {
  id: string;
  icon: React.ReactNode;
  label: string;
  onClick: (message: Message) => void | Promise<void>;
  tooltip?: string;
  disabled?: boolean;
}

interface Suggestion {
  id: string;
  label: string;
  prompt: string;
}

interface NoticeConfig {
  icon?: React.ReactNode;
  message: string;
  action?: {
    label: string;
    onClick: () => void;
  };
  dismissible?: boolean;
  onDismiss?: () => void;
}

type ChatState = 'collapsed' | 'compact' | 'expanded';

Styling

CSS Import

Components automatically import their styles. For manual control:

/* In your CSS */
@import '@automattic/agenttic-ui/index.css';
// In JavaScript/TypeScript
import '@automattic/agenttic-ui/index.css';

CSS Scoping

All AgentUI styles are scoped to the .agenttic class to prevent conflicts with host applications. This ensures that the component styles don't interfere with your existing styles.

Customization

Override CSS custom properties to theme the entire chat or specific areas:

/* Global theming */
.agenttic {
  --color-primary: #your-brand-color;
  --color-background: #ffffff;
  --color-foreground: #000000;
  /* ...other custom properties as needed. */
}

/* Target specific UI areas, e.g. the chat footer as seen in Big Sky embedded site spec. */
.agenttic [data-slot="chat-footer"] {
  --color-background: oklch(1 0 0);
  --color-foreground: oklch(0.241 0 0);
  --color-primary: #your-brand-color;
  --color-primary-foreground: oklch(1 0 0);
  --color-muted: oklch(0.925 0 0);
  --color-muted-foreground: oklch(0.6 0 0);
}

This approach allows granular theming of specific areas without affecting other parts of the application.

Advanced Usage

Custom Message Renderer

Provide a custom markdown renderer:

import { ReactMarkdown } from 'react-markdown';

const customRenderer = ({ children }: { children: string }) => (
  <ReactMarkdown 
    remarkPlugins={[remarkGfm]}
    components={{
      code: ({ children }) => <code className="custom-code">{children}</code>
    }}
  >
    {children}
  </ReactMarkdown>
);

<AgentUI
  messages={messages}
  messageRenderer={customRenderer}
  // ... other props
/>

Message Actions

Messages can include interactive actions:

const messagesWithActions = messages.map(message => ({
  ...message,
  actions: message.role === 'agent' ? [
    {
      id: 'copy',
      icon: <CopyIcon />,
      label: 'Copy',
      onClick: () => navigator.clipboard.writeText(message.content[0].text)
    },
    {
      id: 'feedback',
      icon: <ThumbsUpIcon />,
      label: 'Good response',
      onClick: () => console.log('Positive feedback')
    }
  ] : []
}));

Controlled Chat State

For floating variant, control the chat state externally:

const [chatState, setChatState] = useState<ChatState>('collapsed');

<AgentUI
  variant="floating"
  floatingChatState={chatState}
  onOpen={() => setChatState('compact')}
  onExpand={() => setChatState('expanded')}
  onClose={() => setChatState('collapsed')}
  // ... other props
/>

Custom Empty View

Provide custom content when there are no messages:

<AgentUI
  messages={[]}
  emptyView={
    <div className="welcome-message">
      <h3>Welcome to AI Assistant</h3>
      <p>I'm here to help you with any questions.</p>
    </div>
  }
  // ... other props
/>

Development

# Build the package
pnpm build

# Run in development mode
pnpm dev

# Run tests
pnpm test

# Type checking
pnpm type-check

# Start Storybook
pnpm storybook

Storybook Documentation

Interactive component documentation is available via Storybook:

pnpm storybook

Visit http://localhost:6006 to explore component examples and documentation.

Integration with agenttic-client

This UI package is designed to work seamlessly with @automattic/agenttic-client:

import { useAgentChat } from '@automattic/agenttic-client';
import { AgentUI } from '@automattic/agenttic-ui';

function App() {
  const agentProps = useAgentChat({
    agentId: 'big-sky',
    // ... configuration
  });

  return <AgentUI {...agentProps} variant="floating" />;
}

The useAgentChat hook returns props that match the AgentUI interface perfectly, making integration seamless.