assistant-ui/skills

ink

Builds terminal chat UIs with @assistant-ui/react-ink and ANSI markdown with @assistant-ui/react-ink-markdown.

Vedi sorgente
Documento Skill originale

Contenuto dal repository con titoli, esempi, codice, tabelle, link e immagini preservati.

assistant-ui Ink

Always consult [assistant-ui.com/llms.txt](https://www.assistant-ui.com/llms.txt) for the latest API.

@assistant-ui/react-ink connects the assistant-ui runtime to Ink's terminal renderer. It shares runtime, tools, state, and AI SDK transport with web apps, but it has no DOM, CSS, or copied elements. Compose your screen from Ink's Box and Text plus the runtime aware primitives. @assistant-ui/react-ink-markdown renders assistant text as ANSI styled terminal markdown.

References

Start a terminal app

Scaffold the terminal example when starting fresh:

sh
npx assistant-ui@latest create --ink my-app
cd my-app

--ink resolves to the with-react-ink CLI example. The example inventory also contains with-react-ink-web, but it is not the --ink scaffold target.

For an existing Node project, install the runtime, terminal renderer, and AI SDK transport together:

sh
npm install @assistant-ui/react-ink @assistant-ui/react-ink-markdown ink react @assistant-ui/ai-sdk

The API route must run in a separate backend project. Unlike a browser app, a terminal process cannot use a relative /api/chat URL. Give AssistantChatTransport a complete URL that the process can reach.

tsx
import { AssistantRuntimeProvider } from "@assistant-ui/react-ink";
import { AssistantChatTransport, useChatRuntime } from "@assistant-ui/ai-sdk";
import { Box } from "ink";
import { TerminalThread } from "./components/terminal-thread.js";

const CHAT_API_URL = "http://localhost:3000/api/chat";

export function App() {
  const runtime = useChatRuntime({
    transport: new AssistantChatTransport({ api: CHAT_API_URL }),
  });

  return (
    <AssistantRuntimeProvider runtime={runtime}>
      <Box flexDirection="column">
        <TerminalThread />
      </Box>
    </AssistantRuntimeProvider>
  );
}

useChatRuntime and AssistantChatTransport come from @assistant-ui/ai-sdk. Its backend uses the AI SDK v7 UI message stream. See the runtime's AI SDK v7 guide for the route shape.

Compose a terminal thread

ThreadPrimitive.Messages creates the current message scope before each child runs. Read s.message inside the message component, then use Ink primitives rather than web elements. Use AuiIf for runtime state gates and LoadingPrimitive for the active run.

tsx
import { Box, Text } from "ink";
import {
  AuiIf,
  ComposerPrimitive,
  LoadingPrimitive,
  ThreadPrimitive,
  useAuiState,
} from "@assistant-ui/react-ink";
import { MarkdownText } from "@assistant-ui/react-ink-markdown";

function Message() {
  const message = useAuiState((s) => s.message);
  const text = message.content
    .filter((part) => part.type === "text")
    .map((part) => ("text" in part ? part.text : ""))
    .join("");

  if (message.role === "user") {
    return <Text color="green">You: {text}</Text>;
  }

  return (
    <Box flexDirection="column" marginBottom={1}>
      <Text color="blue">Assistant:</Text>
      <MarkdownText text={text} />
    </Box>
  );
}

export function TerminalThread() {
  return (
    <ThreadPrimitive.Root flexDirection="column">
      <AuiIf condition={(s) => s.thread.isEmpty}>
        <Text dimColor>Send a message to begin.</Text>
      </AuiIf>
      <ThreadPrimitive.Messages>{() => <Message />}</ThreadPrimitive.Messages>
      <LoadingPrimitive.Root gap={1}>
        <LoadingPrimitive.Spinner variant="bar" />
        <LoadingPrimitive.Text />
        <LoadingPrimitive.ElapsedTime />
      </LoadingPrimitive.Root>
      <Box borderStyle="round" borderColor="gray" paddingX={1}>
        <Text color="gray">{"> "}</Text>
        <ComposerPrimitive.Input submitOnEnter placeholder="Message..." autoFocus />
      </Box>
    </ThreadPrimitive.Root>
  );
}

The simple message example deliberately renders only text parts. Use MessagePrimitive.Parts when you need tool calls, attachments, data, sources, or reasoning. Its default terminal safe renderers handle those part types, and primitives shows the component map.

Terminal input behavior

ComposerPrimitive.Input is a composer bound TextInput. It is a controlled line editor, not Ink's nonexistent native input. submitOnEnter sends the current composer text. With multiLine, Enter inserts a newline unless submitOnEnter is enabled, in which case Shift Enter inserts a newline when the terminal distinguishes it. Ctrl J inserts a newline only in multiline mode and never submits a single line input.

  • Left, Right, Backspace, Delete, and Ctrl D operate on one grapheme, so an emoji, ZWJ sequence, combining character, or CJK ideograph is never split.
  • Home and End select the whole buffer in single line mode or the current line in multiline mode. Ctrl A and Ctrl E always select the current line boundary.
  • Up and Down navigate multiline rows while preserving the terminal display column, calculated from grapheme widths rather than UTF 16 offsets.
  • Ctrl W, Alt B, Alt F, and Alt D navigate or delete by Intl.Segmenter word boundaries. Ctrl U and Ctrl K kill to the current boundary. At multiline end of line, Ctrl K joins the next line.

Meta bindings need a terminal that emits Escape prefixed sequences. In macOS Terminal, enable “Use Option as Meta key” for the Alt bindings. Shift Enter requires CSI u support, including iTerm2 3.4 or newer, kitty, and foot. Other terminals treat it as Enter and use submitOnEnter behavior. See primitives for TextInput outside a composer.

Markdown in the terminal

Pass accumulated text to MarkdownText from @assistant-ui/react-ink-markdown. It produces terminal styled output rather than HTML or a React DOM tree. The package also exports MarkdownTextPrimitive, useShikiHighlighter, and theme types for a custom renderer, but start with MarkdownText unless you need to change its rendering pipeline.

tsx
import { MarkdownText } from "@assistant-ui/react-ink-markdown";

export function AssistantReply({ text }: { text: string }) {
  return <MarkdownText text={text} />;
}

Common Gotchas

The terminal app sends requests to its own process instead of the backend

  • AssistantChatTransport needs an absolute api URL such as http://localhost:3000/api/chat. Host the AI SDK route separately from the Ink process.

A web Thread or shadcn element renders nothing in the CLI

  • Browser elements require the DOM and CSS. Rebuild the surface with Ink Box, Text, and @assistant-ui/react-ink primitives.

A primitive or state hook throws about missing runtime context

  • Mount it under AssistantRuntimeProvider runtime={runtime}. ThreadPrimitive.Messages and MessagePrimitive.Parts also create the item scopes their children read.

Enter does not send or inserts a newline unexpectedly

  • submitOnEnter is false by default. Combine it with multiLine only when Enter should send and Shift Enter should insert a newline on capable terminals.

Emoji deletion corrupts the visible input or vertical navigation lands in the wrong place

  • Use ComposerPrimitive.Input or exported TextInput. Their buffer uses grapheme segmentation and terminal display widths. Do not substitute character index arithmetic.

Thread data disappears after restarting the CLI

  • useLocalRuntime is process memory. Use createFileStorageAdapter for one local process or a RemoteThreadListAdapter for backend owned metadata.

Markdown was imported from the web package

  • Import MarkdownText from @assistant-ui/react-ink-markdown, which emits terminal formatting. Web markdown renderers target the DOM.

Related Skills

  • setup -- CLI scaffolding, browser setup, and package installation
  • runtime -- shared assistant-ui runtime, state, threads, and transport design
  • primitives -- browser unstyled primitives when the target is not a terminal
  • tools -- toolkit definitions and tool call renderers that also work in Ink
  • markdown -- browser markdown renderers and source display
dallo stesso repository

Altri Skills

Tutti gli Skills
assistant-ui
Community

assistant-ui

Overview and router for assistant-ui, the React library for building AI chat interfaces from composable primitives and a styled elements catalog. Use for high-level, cross-cutting, or architecture questions: choosing packages, picking a runtime, or understanding the layers (elements, primitives, the aui client with AuiConfig and AuiProvider, the runtime, adapters) and the message model. Covers @assistant-ui/react 0.15.x, the framework-neutral @assistant-ui/ai-sdk integration for AI SDK v7 (useChatRuntime, AssistantChatTransport; @assistant-ui/react-ai-sdk re-exports it), @assistant-ui/core, @assistant-ui/store, assistant-stream, assistant-cloud, the adapters for LangGraph, LangChain, Google ADK, A2A, AG-UI, Eve, OpenCode, and Pi, and the platform bindings @assistant-ui/react-native and @assistant-ui/react-ink; AssistantRuntimeProvider; the primitives ThreadPrimitive, MessagePrimitive, ComposerPrimitive; the hooks useAui, useAuiState, useAuiEvent; and runtime selection across useChatRuntime, useExternalStoreRuntime, useLangGraphRuntime, useLocalRuntime. For a specific area route to a focused sibling instead: setup, elements, primitives, runtime, tools, generative-ui, streaming, cloud, thread-list, copilots, markdown, react-mcp, observability, react-native, ink, or update.

installazioni
1
GitHub Stars
26
Aggiornato
4 set
assistant-ui
Community

cloud

Adds AssistantCloud backed persistence, authorization, and telemetry to assistant-ui apps. Use when wiring cross-session thread and message history, multi-device chat, message feedback, file uploads, or auth: passing cloud to useChatRuntime from @assistant-ui/ai-sdk, AISDKThreads({ cloud }) for AuiConfig hosts, the standalone useCloudChat/useThreads hooks from @assistant-ui/cloud-ai-sdk, or cloud on useLangGraphRuntime. Covers constructing AssistantCloud with authToken (JWT), apiKey plus userId/workspaceId (server-side), or anonymous; direct provider integrations (Clerk, Auth0, Supabase, Firebase) and a backend token endpoint; and the client surface verified against source: cloud.threads.{list,get,create,update,delete}, cloud.threads.messages.{list,create,update,feedback}, cloud.files.{generatePresignedUploadUrl,pdfToImages}, cloud.runs.{stream,report}, cloud.projects.threads, cloud.auth.tokens.create, and cloud.telemetry. Also covers a custom ThreadHistoryAdapter built on CloudMessagePersistence/createFormattedPersistence, run telemetry (beforeReport, sub-agent tracking with wrapSamplingHandler), and the NEXTPUBLICASSISTANTBASEURL/ASSISTANTAPIKEY env vars. Route here for threads that do not persist, 401s against the cloud API, or feedback buttons that do not save. For the sidebar UI itself use thread-list; for the general RemoteThreadListAdapter/ThreadHistoryAdapter contract use runtime.

installazioni
1
GitHub Stars
26
Aggiornato
4 set
assistant-ui
Community

copilots

Grounding an assistant in your app with assistant-ui copilots (@assistant-ui/react). Use when steering assistant behavior with useAssistantInstructions, feeding lazy send-time app state through useAssistantContext({ getContext }), exposing rendered components to the assistant with makeAssistantVisible(Component, { clickable, editable }), giving the model two-way component state through interactables (unstableuseInteractable for app-scoped panels, unstableinteractableTool inside defineToolkit for thread-scoped artifacts, both mounted via AuiConfig({ unstableinteractables: unstableInteractables() })), registering instructions and tools together imperatively with aui.modelContext.register({ getModelContext }), or bridging model context across an iframe boundary with AssistantFrameProvider and useAssistantFrameHost. The legacy Interactables() scope, useAssistantInteractable, and useInteractableState are deprecated since 2026-06-14 and scheduled for removal on or after 2026-09-14; new code uses the unstable API. Reach for this when the assistant should read the current page, click or edit UI, read and update component state through auto-generated update{name} tools, or receive tools and instructions from a sandboxed iframe. For LLM tools and tool-call UI use the tools skill; for runtime and thread state use the runtime skill.

installazioni
1
GitHub Stars
26
Aggiornato
4 set
assistant-ui
Community

elements

Installs and customizes assistant-ui elements, the styled shadcn-style component catalog at assistant-ui.com/elements served from the r.assistant-ui.com registry through npx assistant-ui@latest add . Use when adding a prebuilt chat surface or widget (Thread, ThreadList, AssistantModal, AssistantSidebar, ToolFallback, ToolGroup, MarkdownText, Reasoning, Sources, Attachment, ModelSelector, Voice orb, McpConfig) or one of the 120 standalone elements (approval card, agent plan, code diff, data table, chart, trace waterfall, message queue, composer variants, and so on), choosing between runtime-connected .aui.tsx files and props-driven standalone files, overriding Thread slots through the components prop, editing the copied source under components/assistant-ui/elements/, using the shared surfaces.tsx tokens, or picking the Radix versus Base UI flavor through the style-aware registry URL in components.json. Route here when an import from @/components/assistant-ui/... fails, an element renders unstyled, or the CLI installs the wrong flavor. For unstyled building blocks use primitives; for the CLI scaffold itself use setup.

installazioni
1
GitHub Stars
26
Aggiornato
4 set