Skip to content

Anthropic

Use GistUI with Claude through Anthropic's Messages API, with plain fetch or the official SDK.

Updated View as Markdown

With the Messages API the system prompt is its own field, system, not a message.

npm i @gistui/catalog @gistui/server

With fetch

api/answer.tsts
import { prompt } from "@gistui/catalog";
import { textDeltas, toReadable } from "@gistui/server";

export async function POST(req: Request) {
  const { messages } = await req.json();

  const res = await fetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: {
      "x-api-key": process.env.ANTHROPIC_API_KEY!,
      "anthropic-version": "2023-06-01",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "claude-sonnet-5-5",
      max_tokens: 4096,
      stream: true,
      system: prompt().text,
      messages,
    }),
  });

  if (!res.ok) return new Response(await res.text(), { status: res.status });
  return new Response(toReadable(textDeltas(res, "anthropic")));
}

With @anthropic-ai/sdk

api/answer.tsts
import Anthropic from "@anthropic-ai/sdk";
import { prompt } from "@gistui/catalog";
import { toReadable } from "@gistui/server";

const client = new Anthropic();

export async function POST(req: Request) {
  const { messages } = await req.json();

  const stream = client.messages.stream({
    model: "claude-sonnet-5-5",
    max_tokens: 4096,
    system: prompt().text,
    messages,
  });

  async function* text() {
    for await (const event of stream) {
      if (event.type === "content_block_delta" && event.delta.type === "text_delta") yield event.delta.text;
    }
  }
  return new Response(toReadable(text()));
}

Prompt caching

GistUI’s prompt is byte-stable, so it is a good cache target. Mark it as cacheable and put anything that changes per request (the tool list, the user’s context) after it.

system: [{ type: "text", text: prompt().text, cache_control: { type: "ephemeral" } }],

Render it

import "@gistui/styles/styles.css";
import { GistUI } from "@gistui/react";
import { ui } from "@gistui/react/ui";

const res = await fetch("/api/answer", { method: "POST", body: JSON.stringify({ messages }) });
<GistUI library={ui} stream={res.body} onAction={handle} />;

In a chat

import { anthropic, createChat } from "@gistui/chat";

// url: your own endpoint that forwards to Anthropic and adds the key and the system prompt.
const store = createChat({ adapter: anthropic({ model: "claude-sonnet-5-5", url: "/api/chat" }) });
Navigation

Type to search…

↑↓ navigate↵ selectEsc close