npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@agentbase-sdk/react

v0.1.4

Published

React hooks for Agentbase SDK - build conversational AI interfaces with ease

Readme

Agentbase React SDK

React hooks for building conversational AI interfaces with Agentbase. Simple, powerful, and focused.

Features

  • Simple API - Clean hook with just what you need: send, stop, clear
  • Streaming Support - Real-time streaming of agent responses
  • Multi-Agent Flows - Support for agent handoffs and transfers
  • Session Management - Automatic session tracking and continuation of previous conversations
  • TypeScript - Full TypeScript support with type definitions
  • Server-Side - Keep your API keys secure on the server

Installation

npm install @agentbase-sdk/react agentbase-sdk

Quick Start

1. Create a Server-Side API Route

The React SDK calls a server-side endpoint to keep your Agentbase API key secure. Here's an example using Next.js App Router:

// app/api/agent/route.ts
import Agentbase from "agentbase-sdk";
import { NextRequest } from "next/server";

// Initialize Agentbase client (reuse across requests)
const agentbase = new Agentbase({
  apiKey: process.env.AGENTBASE_API_KEY!,
});

export const runtime = "edge"; // Optional: Use Edge Runtime for better performance

export async function GET(req: NextRequest) {
  try {
    // Get session ID from query parameters
    const { searchParams } = new URL(req.url);
    const sessionId = searchParams.get("session");

    if (!sessionId) {
      return new Response("Session ID is required", { status: 400 });
    }

    // Fetch messages for the session
    const response = await fetch(
      `https://api.agentbase.sh/sessions/${sessionId}/messages`,
      {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${process.env.AGENTBASE_API_KEY}`,
        },
      }
    );

    if (!response.ok) {
      throw new Error(`Failed to fetch messages: ${response.status}`);
    }

    const data = await response.json();

    return new Response(JSON.stringify(data), {
      headers: {
        "Content-Type": "application/json",
      },
    });
  } catch (error) {
    console.error("Get messages error:", error);
    return new Response("Internal server error", { status: 500 });
  }
}

export async function POST(req: NextRequest) {
  try {
    // Parse request body
    const body = await req.json();
    const {
      message,
      session,
      system,
      mode = "fast",
      rules,
      mcp_servers,
      agents,
      streaming_tokens = false,
    } = body;

    // Validate required fields
    if (!message) {
      return new Response("Message is required", { status: 400 });
    }

    // Prepare Agentbase parameters
    const params: any = {
      message,
      mode,
      streaming_tokens,
    };

    if (session) params.session = session;
    if (system) params.system = system;
    if (rules) params.rules = rules;
    if (mcp_servers) params.mcp_servers = mcp_servers;
    if (agents) params.agents = agents;

    // Create a TransformStream to convert async iterator to ReadableStream
    const encoder = new TextEncoder();
    const stream = new TransformStream();
    const writer = stream.writable.getWriter();

    // Start streaming in the background
    (async () => {
      try {
        const responseStream = await agentbase.runAgent(params);

        for await (const response of responseStream) {
          // Format as Server-Sent Events
          const data = `data: ${JSON.stringify(response)}\n\n`;
          await writer.write(encoder.encode(data));
        }

        await writer.close();
      } catch (error) {
        console.error("Streaming error:", error);
        await writer.abort(error);
      }
    })();

    // Return the stream as SSE
    return new Response(stream.readable, {
      headers: {
        "Content-Type": "text/event-stream",
        "Cache-Control": "no-cache",
        Connection: "keep-alive",
      },
    });
  } catch (error) {
    console.error("Chat API error:", error);
    return new Response("Internal server error", { status: 500 });
  }
}

See examples/nextjs for the complete working example.

2. Use the useAgent Hook in Your Component

"use client";

import { useAgent } from "@agentbase-sdk/react";
import { useState } from "react";

export default function Chat() {
  const [input, setInput] = useState("");
  const { messages, send, stop, clear, isRunning, error, session } = useAgent({
    api: "/api/agent",
    system: "You are a helpful AI assistant. Be concise and friendly.",
    mode: "fast",
    onError: (error) => {
      console.error("Agent error:", error);
    },
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!input.trim() || isRunning) return;

    send(input);
    setInput("");
  };

  return (
    <div>
      {/* Session Info */}
      {session && <div>Session: {session.substring(0, 8)}...</div>}

      {/* Error Display */}
      {error && <div>Error: {error.message}</div>}

      {/* Messages */}
      <div>
        {messages.map((message, msgIndex) => (
          <div key={msgIndex}>
            <strong>{message.role === "user" ? "You" : "Assistant"}:</strong>

            {/* Render all content items */}
            {message.content.map((item, index) => (
              <div key={index}>
                {item.type === "text" && (
                  <div>{item.text}</div>
                )}
                {item.type === "thinking" && (
                  <div style={{ fontStyle: "italic", opacity: 0.7 }}>
                    💭 {item.text}
                  </div>
                )}
                {item.type === "tool_use" && (
                  <div>
                    <strong>🔧 Tool Use:</strong>
                    <pre>{item.text}</pre>
                  </div>
                )}
                {item.type === "tool_response" && (
                  <div>
                    <strong>✅ Tool Result:</strong>
                    <pre>{item.text}</pre>
                  </div>
                )}
                {item.type === "transfer" && (
                  <div>
                    🔄 Transferred to: {item.agent}
                    {item.context && <div>{item.context}</div>}
                  </div>
                )}
              </div>
            ))}
          </div>
        ))}

        {/* Loading indicator */}
        {isRunning && <div>...</div>}
      </div>

      {/* Controls */}
      <button onClick={clear} disabled={messages.length === 0}>
        Clear
      </button>

      {/* Input Form */}
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="Type your message..."
          disabled={isRunning}
        />
        {isRunning ? (
          <button type="button" onClick={stop}>
            Stop
          </button>
        ) : (
          <button type="submit" disabled={!input.trim()}>
            Send
          </button>
        )}
      </form>
    </div>
  );
}

API Reference

useAgent(options)

The main hook for building agent interfaces.

Options

interface UseAgentOptions {
  // Required: API endpoint to call
  api: string;

  // Optional: Session ID to continue a previous conversation
  // If provided, chat history will be fetched automatically
  sessionId?: string;

  // Optional: System prompt for the agent
  system?: string;

  // Optional: Agent mode (default: "fast")
  mode?: "flash" | "fast" | "max";

  // Optional: Rules for the agent
  rules?: string[];

  // Optional: MCP servers configuration
  mcpServers?: Array<{
    serverName: string;
    serverUrl: string;
  }>;

  // Optional: Agent handoffs for multi-agent flows
  agents?: Array<{
    name: string;
    description?: string;
  }>;

  // Optional: Stream tokens individually
  streamingTokens?: boolean;

  // Optional: Initial messages
  initialMessages?: Message[];

  // Optional: Error callback
  onError?: (error: Error) => void;

  // Optional: Custom headers and body
  headers?: Record<string, string>;
  body?: Record<string, any>;
}

Returns

interface UseAgentReturn {
  // Message history
  messages: Message[];

  // Send a message to the agent
  send: (message: string) => Promise<void>;

  // Stop the current agent run
  stop: () => void;

  // Clear all messages (locally and on server)
  clear: () => Promise<void>;

  // State
  isRunning: boolean;
  error: Error | null;
  session: string | null;
}

Examples

Continuing a Previous Session

Pass a sessionId to the useAgent hook to continue a previous conversation. The hook will automatically:

  1. Fetch the chat history from your API's GET endpoint
  2. Display all previous messages
  3. Continue the conversation in the same session when you send new messages
"use client";

import { useAgent } from "@agentbase-sdk/react";
import { useState } from "react";

function ContinueSessionChat() {
  const [input, setInput] = useState("");
  const [sessionInput, setSessionInput] = useState("");
  const [currentSessionId, setCurrentSessionId] = useState<string | undefined>();

  const { messages, send, isRunning, session } = useAgent({
    api: "/api/agent",
    sessionId: currentSessionId, // Pass the session ID to continue
    system: "You are a helpful assistant.",
  });

  const handleLoadSession = () => {
    if (sessionInput.trim()) {
      setCurrentSessionId(sessionInput.trim());
    }
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!input.trim() || isRunning) return;
    send(input);
    setInput("");
  };

  return (
    <div>
      {/* Load Session */}
      <div>
        <input
          value={sessionInput}
          onChange={(e) => setSessionInput(e.target.value)}
          placeholder="Enter session ID to continue..."
        />
        <button onClick={handleLoadSession}>Load Session</button>
      </div>

      {/* Current Session */}
      {session && <div>Current Session: {session}</div>}

      {/* Messages */}
      <div>
        {messages.map((msg, idx) => (
          <div key={idx}>
            <strong>{msg.role}:</strong>
            {msg.content.map((item, i) => (
              <div key={i}>
                {item.type === "text" && <span>{item.text}</span>}
              </div>
            ))}
          </div>
        ))}
      </div>

      {/* Input */}
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          disabled={isRunning}
          placeholder="Type your message..."
        />
        <button type="submit" disabled={isRunning || !input.trim()}>
          Send
        </button>
      </form>
    </div>
  );
}

Basic Chat

"use client";

import { useAgent } from "@agentbase-sdk/react";
import { useState } from "react";

function BasicChat() {
  const [input, setInput] = useState("");
  const { messages, send, isRunning } = useAgent({
    api: "/api/agent",
    system: "You are a helpful assistant.",
  });

  return (
    <div>
      {messages.map((msg, idx) => (
        <div key={idx}>
          <strong>{msg.role}:</strong>
          {msg.content.map((item, i) => (
            <div key={i}>
              {item.type === "text" && <span>{item.text}</span>}
            </div>
          ))}
        </div>
      ))}
      <form
        onSubmit={(e) => {
          e.preventDefault();
          if (!input.trim() || isRunning) return;
          send(input);
          setInput("");
        }}
      >
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          disabled={isRunning}
        />
        <button type="submit" disabled={isRunning || !input.trim()}>
          Send
        </button>
      </form>
    </div>
  );
}

Advanced Features

"use client";

import { useAgent } from "@agentbase-sdk/react";
import { useState } from "react";

function AdvancedChat() {
  const [input, setInput] = useState("");
  const { messages, send, stop, clear, isRunning, error, session } = useAgent({
    api: "/api/agent",
    system: "You are a helpful assistant.",
    mode: "fast",
    onError: (error) => console.error("Error:", error),
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!input.trim() || isRunning) return;
    send(input);
    setInput("");
  };

  return (
    <div>
      {/* Session Info */}
      {session && <div>Session: {session.substring(0, 8)}...</div>}

      {/* Error Display */}
      {error && <div style={{ color: "red" }}>Error: {error.message}</div>}

      {/* Messages */}
      <div>
        {messages.map((msg, idx) => (
          <div key={idx}>
            <strong>{msg.role}:</strong>
            {msg.content.map((item, i) => (
              <div key={i}>
                {item.type === "text" && <div>{item.text}</div>}
                {item.type === "thinking" && (
                  <div style={{ fontStyle: "italic", opacity: 0.7 }}>
                    💭 {item.text}
                  </div>
                )}
                {item.type === "tool_use" && (
                  <div>
                    <strong>🔧 Tool:</strong>
                    <pre>{item.text}</pre>
                  </div>
                )}
              </div>
            ))}
          </div>
        ))}
      </div>

      {/* Controls */}
      <div>
        <button onClick={clear} disabled={messages.length === 0}>
          Clear
        </button>
        {isRunning && <button onClick={stop}>Stop</button>}
      </div>

      {/* Input */}
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          disabled={isRunning}
          placeholder="Type your message..."
        />
        <button type="submit" disabled={isRunning || !input.trim()}>
          Send
        </button>
      </form>
    </div>
  );
}

Multi-Agent Flow

"use client";

import { useAgent } from "@agentbase-sdk/react";
import { useState } from "react";

function MultiAgentChat() {
  const [input, setInput] = useState("");
  const { messages, send, isRunning } = useAgent({
    api: "/api/agent",
    system: "You classify products and route to specialized agents.",
    mode: "fast",
    agents: [
      {
        name: "Personal Care Agent",
        description: "Handles personal care products",
      },
      {
        name: "Cosmetics Agent",
        description: "Handles makeup and cosmetics",
      },
    ],
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!input.trim() || isRunning) return;
    send(input);
    setInput("");
  };

  return (
    <div>
      {messages.map((msg, idx) => (
        <div key={idx}>
          <strong>{msg.role}:</strong>
          {msg.content.map((item, i) => (
            <div key={i}>
              {item.type === "text" && <div>{item.text}</div>}
              {item.type === "transfer" && (
                <div style={{ background: "#f0f0f0", padding: "8px" }}>
                  🔄 Transferred to: <strong>{item.agent}</strong>
                  {item.context && <div>Context: {item.context}</div>}
                </div>
              )}
            </div>
          ))}
        </div>
      ))}
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          disabled={isRunning}
          placeholder="Type your message..."
        />
        <button type="submit" disabled={isRunning || !input.trim()}>
          Send
        </button>
      </form>
    </div>
  );
}

Message Structure

Messages have the following structure:

interface Message {
  role: "user" | "assistant";
  content: MessageContent;
  createdAt: Date;
}

type MessageContent = MessageContentItem[];

interface MessageContentItem {
  type: "text" | "thinking" | "tool_use" | "tool_response" | "transfer";
  text: string;
  agent?: string; // For transfer events
  context?: string; // For transfer events
}

Full Example

Check out the examples/nextjs directory for a complete Next.js project with:

  • Next.js 14 App Router
  • TypeScript
  • Tailwind CSS
  • Server-side API route
  • Full chat interface with all features

TypeScript

The library is written in TypeScript and includes full type definitions. All types are exported:

import type {
  UseAgentOptions,
  UseAgentReturn,
  Message,
  MessageContent,
  MessageContentItem,
  AgentResponse,
} from "@agentbase-sdk/react";

Development

See DEVELOPMENT.md for detailed development instructions.

# Install dependencies
npm install

# Build the library
npm run build

# Watch mode for development
npm run dev

# Type checking
npm run typecheck

License

MIT

Links

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.