npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@optilogic/chat

v1.5.0

Published

Chat UI components for Optilogic - AgentResponse and related components for LLM interactions

Readme

@optilogic/chat

Chat UI components for opti-ui - Components for displaying LLM/AI agent interactions.

Installation

npm install @optilogic/chat @optilogic/core @optilogic/editor slate slate-react slate-history

Setup

Make sure you have configured @optilogic/core with the Tailwind preset and CSS variables.

Usage

AgentResponse

Display AI agent responses with thinking indicators, tool calls, and feedback actions:

import { AgentResponse, useAgentResponseAccumulator, type FeedbackValue } from '@optilogic/chat';
import { useState } from 'react';

function ChatView({ socket }) {
  const { state, handleMessage } = useAgentResponseAccumulator();
  const [feedback, setFeedback] = useState<FeedbackValue>(null);

  socket.onmessage = (e) => handleMessage(JSON.parse(e.data));

  return (
    <AgentResponse
      state={state}
      feedback={feedback}
      onFeedbackChange={setFeedback}
      onResponseCopy={(response) => console.log('Copied:', response)}
    />
  );
}

Feedback follow-up (thumbs up/down)

The action bar always renders thumbs up/down controls, and by default a thumbs-down opens our follow-up popover (category + free-text) — this works out of the box with no state wiring, because vote and popover state are uncontrolled by default. To use the default, just hook up persistence:

// Thumbs + follow-up popover work as-is; wire only what you want to store.
<AgentResponse
  state={state}
  onFeedbackChange={(vote) => saveVote(vote)}
  onFeedbackDetailsSubmit={(details) => saveFeedbackDetails(details)}
/>

Turn the follow-up off with feedbackPrompt="none", or customize it via feedbackCategories, feedbackPromptTitle, etc. Take control of any piece by passing its controlled prop (feedback, feedbackDetails, feedbackPromptOpen). A vote records instantly and is never blocked on the follow-up. The library owns the UI and accessibility; persistence and any "send to support" routing stay with you via typed callbacks.

import {
  AgentResponse,
  emptyFeedbackDetails,
  type FeedbackValue,
  type FeedbackDetails,
  type SupportFeedbackPayload,
} from '@optilogic/chat';
import { useState } from 'react';

function ResponseWithFeedback({ state, messageId, conversationId }) {
  const [feedback, setFeedback] = useState<FeedbackValue>(null);
  const [details, setDetails] = useState<FeedbackDetails>(emptyFeedbackDetails);

  return (
    <AgentResponse
      state={state}
      feedback={feedback}
      onFeedbackChange={(vote) => {
        setFeedback(vote);
        // Attribute to your account/message/conversation and upsert (not insert)
        // so vote changes update the same record.
        void saveVote({ messageId, conversationId, vote });
      }}
      // "down" (default) | "up" | "both" | "none"
      feedbackPrompt="down"
      feedbackPromptTitle="Help us improve Ada — what went wrong?"
      feedbackDetails={details}
      onFeedbackDetailsChange={setDetails}
      onFeedbackDetailsSubmit={(d) => {
        void saveFeedbackDetails({ messageId, conversationId, ...d });
      }}
      // Opt-in: render a "send to support" checkbox. Its state is returned in
      // FeedbackDetails.sendToSupport — you assemble + route the payload.
      sendToSupportLabel="Also send this to Support"
    />
  );
}

SupportFeedbackPayload is exported as the recommended shape for routing feedback to a support system. The library only fills vote, category, and comment; the context (conversation URL, message/conversation IDs, user environment details) is yours to supply, since only your app knows its own routing and environment:

function toSupportPayload(
  vote: FeedbackValue,
  details: FeedbackDetails,
  conversationUrl: string,
): SupportFeedbackPayload {
  return {
    vote,
    category: details.category,
    comment: details.comment,
    context: { conversationUrl, env: collectEnvironmentDetails() },
  };
}

Feedback state is controlled-or-uncontrolled throughout: omit feedbackDetails / feedbackPromptOpen to let the component manage them, or pass them to take full control. Categories default to a built-in set (defaultFeedbackCategories) and can be replaced via feedbackCategories.

UserPrompt

Display user messages in the chat:

import { UserPrompt } from '@optilogic/chat';

function ChatMessage() {
  return (
    <UserPrompt
      content="What is the weather today?"
      timestamp={new Date()}
    />
  );
}

UserPromptInput

Input component for user messages:

import { UserPromptInput } from '@optilogic/chat';

function ChatInput() {
  return (
    <UserPromptInput
      onSubmit={(text) => console.log('Submitted:', text)}
      placeholder="Type your message..."
    />
  );
}

HITLQuestionPanel

Display an interactive panel for human-in-the-loop clarifying questions. Replaces the input area when the agent needs user clarification:

import { HITLQuestionPanel, type HITLQuestion } from '@optilogic/chat';

const question: HITLQuestion = {
  reason: "I need clarification before proceeding with the data mapping.",
  questions: [
    "Which table should I load the shipment data into?",
    "Should I overwrite existing rows or append?",
  ],
  options: {
    "Which table should I load the shipment data into?": ["Customers", "Demand", "Shipments"],
    "Should I overwrite existing rows or append?": ["Overwrite", "Append"],
  },
  context: "Source file has 1,200 rows with columns: origin, destination, quantity, date",
  timeoutSeconds: 300,
  receivedAt: Date.now(),
};

function ChatInput() {
  return (
    <HITLQuestionPanel
      question={question}
      onSubmit={(response) => console.log('Response:', response)}
      onStop={() => console.log('Agent stopped')}
    />
  );
}

HITLInteractionRecord

Display a completed HITL Q&A interaction in the chat history:

import { HITLInteractionRecord, type HITLInteraction } from '@optilogic/chat';

const interaction: HITLInteraction = {
  question: { /* HITLQuestion object */ },
  response: "Q: Which table?\nA: Shipments",
  respondedAt: Date.now(),
};

function CompletedInteraction() {
  return <HITLInteractionRecord interaction={interaction} />;
}

AgentResponse with HITL Interactions

HITL interactions can also be displayed as a collapsible section within AgentResponse:

import { AgentResponse, type HITLInteraction } from '@optilogic/chat';

function ChatView() {
  const hitlInteractions: HITLInteraction[] = [/* completed interactions */];

  return (
    <AgentResponse
      state={state}
      hitlInteractions={hitlInteractions}
      defaultHITLExpanded={false}
    />
  );
}

AgentResponse with Status Content

Display ephemeral status messages in the metadata row during agent processing:

import { AgentResponse, TruncatedMessage } from '@optilogic/chat';

function ChatView() {
  const [statusMessage, setStatusMessage] = useState<string>();

  // Parent controls when to show/clear status content
  // e.g., set during processing, clear on completion

  return (
    <AgentResponse
      state={state}
      statusContent={
        statusMessage
          ? <TruncatedMessage message={statusMessage} />
          : undefined
      }
    />
  );
}

TruncatedMessage

Standalone component that renders a single-line string with CSS-based truncation:

import { TruncatedMessage } from '@optilogic/chat';

<TruncatedMessage message="Searching the knowledge base for relevant documents..." />

Components

AgentResponse

Main component for displaying AI agent responses with:

  • Streaming content support
  • Thinking/reasoning indicators
  • Tool call visualization
  • Copy and feedback actions
  • Metadata display (tokens, timing)
  • Ephemeral status content slot in metadata row
  • Optional collapsible HITL interaction history

UserPrompt

Component for displaying user messages in the chat interface.

UserPromptInput

Input component for composing user messages with tag support.

HITLQuestionPanel

Interactive panel for displaying agent clarifying questions with:

  • Predefined option buttons (toggleable selection)
  • Free-form text input
  • Countdown timer with visual warning state
  • Keyboard support (Enter to submit, Shift+Enter for newlines)

HITLInteractionRecord

Read-only display of a completed HITL Q&A interaction with:

  • Per-question inline answers
  • Context display
  • Fallback for non-structured response formats

HITLSection

Collapsible sub-component for rendering HITL interactions within AgentResponse. Follows the same expand/collapse pattern as ThinkingSection.

TruncatedMessage

Standalone utility component for single-line text truncation with:

  • CSS-based ellipsis truncation
  • Native title tooltip for full text on hover
  • Designed for use in MetadataRow status slot or anywhere else

Hooks

useAgentResponseAccumulator

Manages state for streaming agent responses, handling incremental updates and message accumulation.

useThinkingTimer

Tracks elapsed time during agent thinking phases.

Utilities

buildResponseString

Combines selected options and free-form text into a single formatted string for the backend. Used internally by HITLQuestionPanel and can be used to construct responses programmatically.

License

MIT