Elements

43 / 122 · Knowledge

Memory

What it now remembers about you, written during the turn and removable.

memory
Prefers TypeScriptWorks in a pnpm monorepo

Installation

npx shadcn@latest add "@assistant-ui/elements-memory-chips"

Usage

import { MemoryChips } from "@/components/elements/memory-chips";

<MemoryChips chips={chips} onForget={forget} />

Props

MemoryChips

chips*MemoryChip[]What is remembered. Anything not marked existing is counted as new this turn and tinted.
onForget(id: string) => voidCalled to drop a fact. Every chip is removable, including ones it just learned.
classNamestringExtra classes merged onto the root.

MemoryChip

id*stringStable identity, reported back by onForget.
text*stringThe remembered fact, in the assistant's words.
change*"added" | "updated" | "existing"existing is neutral; added and updated are tinted and counted in the header.

Source

memory-chips.tsx
"use client";

import { BrainIcon, XIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { field, ghostButton, mono } from "./surfaces";

export type MemoryChange = "added" | "updated" | "existing";

export interface MemoryChip {
  id: string;
  text: string;
  change: MemoryChange;
}

export function MemoryChips({
  chips,
  onForget,
  className,
}: {
  chips: readonly MemoryChip[];
  onForget?: (id: string) => void;
  className?: string;
}) {
  const fresh = chips.filter((chip) => chip.change !== "existing").length;

  return (
    <div className={cn("flex w-full max-w-sm flex-col gap-2", className)}>
      <div className="flex items-center gap-1.5">
        <BrainIcon className="text-foreground/30 size-3.5" />
        <span className={cn(mono, "text-foreground/35")}>
          {fresh > 0 ? `remembered ${fresh}` : "memory"}
        </span>
      </div>

      <div className="flex flex-wrap gap-1.5">
        {chips.map((chip) => (
          <span
            key={chip.id}
            className={cn(
              "fade-in zoom-in-95 animate-in fill-mode-both group flex items-center gap-1 rounded-full py-1 pr-1 pl-2.5 text-xs duration-300",
              chip.change === "existing"
                ? cn(field, "text-foreground/55")
                : "bg-blue-500/12 text-blue-700 dark:bg-blue-400/15 dark:text-blue-300",
            )}
          >
            {chip.text}
            <button
              type="button"
              aria-label={`Forget "${chip.text}"`}
              onClick={() => onForget?.(chip.id)}
              className={cn(ghostButton, "size-4")}
            >
              <XIcon className="size-2.5" />
            </button>
          </span>
        ))}
      </div>
    </div>
  );
}