@dariomvg/create
anthropicchatnextjsstreamingintegracion

Anthropic Chat — Configuración

Módulo de chat listo para integrar en Next.js App Router usando la API de Anthropic. Es independiente del módulo Text Generation: usalo cuando necesites conversaciones con historial, no generaciones de una sola respuesta.

Qué incluye

  • Chat completion (sin streaming)
  • Chat con streaming
  • Historial de conversaciones y mensajes
  • Historial de chat persistente (mediante un store intercambiable)
  • Múltiples conversaciones
  • Gestión de conversaciones (crear, renombrar, eliminar, listar)
  • Gestión de contexto (recorte automático de mensajes antiguos usando el endpoint real de conteo de tokens)

No incluido a propósito: speech-to-text y text-to-speech, ya que la API de Anthropic no los ofrece de forma nativa. Si necesitás voz, integrá un proveedor aparte (por ejemplo Whisper o ElevenLabs) y pasale el texto resultante a sendMessage / streamMessage.

Dependencias

Este módulo usa:

No se instala automáticamente: agregalo al package.json de tu proyecto como lo hacés normalmente.

Mapa de archivos

ArchivoSe ejecuta enPara qué sirve
types.tsambosTipos compartidos, valores por defecto y formatos de error
store.tsservidorContrato de persistencia (ChatStore) + implementación en memoria por defecto
service.tsservidorLlamadas internas al SDK de Anthropic, gestión de contexto y normalización de errores
actions.tsservidorServer Actions: importalas en server components
client.tsclienteStreaming del lado del cliente: importalo en client components
stream/handler.tsservidorHandler interno de las requests de streaming
stream/route.tsservidorCopialo a app/api/anthropic/chat/stream/route.ts
.env.local—Variables de entorno

Configuración

  1. Copiá todos los archivos a tu proyecto (ubicación sugerida: lib/ai/anthropic/chat/).
  2. Copiá stream/route.ts a app/api/anthropic/chat/stream/route.ts, junto con una copia de stream/handler.ts (o dejá handler.ts en tu carpeta lib e importalo desde ahí, solo actualizá el import relativo en route.ts).
  3. Agregá tu clave en .env.local:
    ANTHROPIC_API_KEY=sk-ant-...
    
  4. Asegurate de que @anthropic-ai/sdk esté en tus dependencias.
  5. (Opcional) El módulo funciona de entrada con un store en memoria, que se pierde al reiniciar y no se comparte entre instancias del servidor. Para producción, implementá ChatStore (definido en store.ts) contra tu propia base de datos y registralo una sola vez al iniciar:
    import { setChatStore } from "@/lib/ai/anthropic/chat/store";
    import { PostgresChatStore } from "./postgres-chat-store";
    
    setChatStore(new PostgresChatStore(db));
    

Uso

Crear una conversación y enviar un mensaje (server component / server action)

import { createConversation, sendMessage } from "@/lib/ai/anthropic/chat/actions";

const conversation = await createConversation("Trip planning");

const result = await sendMessage(conversation.id, "Suggest a 5-day itinerary for Japan", {
  systemPrompt: "You are a helpful travel assistant.",
});

if (result.error) {
  // result.error.code, result.error.message
} else {
  console.log(result.data.message.content);
}

Listar y gestionar conversaciones (server component / server action)

import {
  listConversations,
  getConversation,
  renameConversation,
  deleteConversation,
} from "@/lib/ai/anthropic/chat/actions";

const conversations = await listConversations();
const full = await getConversation(conversations[0].id); // includes messages
await renameConversation(conversations[0].id, "Japan trip");
await deleteConversation(conversations[0].id);

Chat con streaming (client component)

"use client";

import { useState } from "react";
import { streamMessage } from "@/lib/ai/anthropic/chat/client";

export function ChatWindow({ conversationId }: { conversationId: string }) {
  const [reply, setReply] = useState("");
  const [isStreaming, setIsStreaming] = useState(false);
  const [error, setError] = useState<string | null>(null);

  function handleSend(content: string) {
    setReply("");
    setError(null);
    setIsStreaming(true);

    streamMessage(conversationId, content, undefined, {
      onChunk: (text) => setReply((prev) => prev + text),
      onError: (err) => setError(err.message),
      onDone: () => setIsStreaming(false),
    });
  }

  return (
    <div>
      <p>{reply}</p>
      {error && <p role="alert">{error}</p>}
    </div>
  );
}

Manejo de errores

Usa el mismo formato normalizado que el módulo Text Generation, más "not_found" para operaciones sobre una conversación que no existe:

type AIErrorCode =
  | "invalid_request"
  | "authentication_error"
  | "rate_limited"
  | "overloaded"
  | "network_error"
  | "not_found"
  | "unknown_error";

interface AIError {
  code: AIErrorCode;
  message: string;
  retryAfter?: number; // present when code === "rate_limited"
}

Gestión de contexto

Cada request verifica la cantidad de tokens de la conversación con anthropic.messages.countTokens() y recorta los mensajes más antiguos hasta que entre dentro de DEFAULT_MAX_CONTEXT_TOKENS (150.000, se puede sobrescribir en cada llamada con options.maxContextTokens). El recorte solo afecta lo que se envía al modelo: el historial completo se mantiene persistido en tu store.