Chat
A chat panel component with message list, streaming text, tool call display, and text input. Uses ACP-aligned types for interoperability with agent protocols.
Terminal
Installation
npx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/chat.jsonnpx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/chat.jsonpnpm dlx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/chat.jsonbunx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/chat.jsonUsage
"use client";
import dynamic from "next/dynamic";
const Terminal = dynamic(() => import("./terminal"), {
ssr: false,
});
export default function Home() {
return <Terminal />;
}"use client";
import { useState } from "react";
import { Box } from "ink";
import { InkXterm } from "ink-web";
import { ChatPanel } from '@/components/ui/chat'
import type { ChatMessage } from '@/components/ui/chat'
import "ink-web/css";
import "@xterm/xterm/css/xterm.css";
export default function Terminal() {
const [messages, setMessages] = useState<ChatMessage[]>([]);
const handleSend = (text: string) => {
setMessages((prev) => [
...prev,
{ id: String(Date.now()), role: 'user', content: text },
]);
// Connect to your AI backend here
};
return (
<InkXterm focus>
<Box flexDirection="column">
<ChatPanel
messages={messages}
onSendMessage={handleSend}
/>
</Box>
</InkXterm>
)
}ChatPanel Props
| Prop | Type | Default | Description |
|---|---|---|---|
messages | ChatMessage[] | - | Array of chat messages to display |
streamingText | string | "" | Text currently being streamed from assistant |
isLoading | boolean | false | Show loading indicator |
activeToolCalls | ToolCallInfo[] | [] | Active tool calls to display |
onSendMessage | (text: string) => void | - | Called when user submits a message |
onCancel | () => void | - | Called when user cancels |
placeholder | string | "Type a message..." | Input placeholder text |
promptChar | string | "> " | Prompt character before input |
promptColor | string | "green" | Color of the prompt |
userColor | string | "green" | Color of user message prefix |
assistantColor | string | "blue" | Color of assistant message prefix |
loadingText | string | "Thinking..." | Text shown while loading |
Types
ChatMessage
interface ChatMessage {
id: string
role: 'user' | 'assistant'
content: string
toolCalls?: ToolCallInfo[]
}ToolCallInfo
Uses ACP-aligned status states:
interface ToolCallInfo {
id: string
title: string
status: 'pending' | 'in_progress' | 'completed' | 'failed'
result?: string
}Examples
Basic Chat
<ChatPanel
messages={messages}
onSendMessage={(text) => console.log(text)}
/>With Streaming
<ChatPanel
messages={messages}
streamingText="The assistant is typing..."
onSendMessage={handleSend}
/>With Tool Calls
const toolCalls: ToolCallInfo[] = [
{ id: '1', title: 'get_portfolio', status: 'completed' },
{ id: '2', title: 'calculate_trades', status: 'in_progress' },
];
<ChatPanel
messages={messages}
activeToolCalls={toolCalls}
onSendMessage={handleSend}
/>Inside a Modal
import { ChatPanel } from '@/components/ui/chat'
import { Modal } from '@/components/ui/modal'
<Modal title="AI Chat" onClose={() => setOpen(false)}>
<ChatPanel
messages={messages}
streamingText={streaming}
isLoading={loading}
activeToolCalls={toolCalls}
onSendMessage={handleSend}
/>
</Modal>Custom Colors
<ChatPanel
messages={messages}
onSendMessage={handleSend}
userColor="cyan"
assistantColor="magenta"
promptColor="yellow"
promptChar="$ "
/>