Skip to content

React Getting Started

UClaw React hooks connect your UI to the managed agent runtime with browser-safe client tokens.

Installation

bash
npm install @uclaw/sdk

Authentication

WARNING

Never expose your UCLAW_API_KEY in client-side code.

By default, UClaw React hooks automatically fetch a short-lived client token from your backend at /api/uclaw/client-tokens.

To configure this endpoint, initialize AppClient with your API key on the server side and export the app.handler in your API route. For example, in Next.js App Router, create a catch-all route at app/api/uclaw/[...all]/route.ts:

typescript
import { AppClient } from "@uclaw/sdk";

const app = new AppClient({
  apiKey: process.env.UCLAW_API_KEY,
});

// Serves POST requests to /api/uclaw/client-tokens
export const POST = (request: Request) => app.handler(request);

App Directory

Use useApp to list and create agents.

tsx
import { useApp } from "@uclaw/sdk/react";
import { useState } from "react";

export function ChatApp() {
  const [activeAgentId, setActiveAgentId] = useState<string | null>(null);
  const { agents, createAgent, status } = useApp({});

  async function handleNewChat() {
    const agent = await createAgent({
      title: "Support assistant",
      config: {
        modelTier: "fast",
        instructions: "You are a friendly customer success assistant.",
      },
    });
    setActiveAgentId(agent.id);
  }

  return (
    <div>
      <p>Status: {status}</p>
      <button onClick={handleNewChat}>Start New Chat</button>
      <ul>
        {agents.map((agent) => (
          <li key={agent.id}>
            <button onClick={() => setActiveAgentId(agent.id)}>{agent.title}</button>
          </li>
        ))}
      </ul>
      {activeAgentId && <ChatWindow agentId={activeAgentId} />}
    </div>
  );
}

Agent Chat

Use useAgent for the active agent's chat connection.

tsx
import { useAgent } from "@uclaw/sdk/react";
import { useState } from "react";

export function ChatWindow({ agentId }: { agentId: string }) {
  const [input, setInput] = useState("");
  const { chat, status } = useAgent({ agentId });

  function handleSend(event: React.FormEvent) {
    event.preventDefault();
    if (!input.trim() || chat.isStreaming) return;

    chat.sendMessage({
      role: "user",
      parts: [{ type: "text", text: input.trim() }],
    });
    setInput("");
  }

  return (
    <div>
      <p>Connection: {status}</p>
      {chat.messages.map((message) => {
        const text = message.parts
          .filter((part) => part.type === "text")
          .map((part) => part.text)
          .join("");

        return <p key={message.id}>{text}</p>;
      })}
      <form onSubmit={handleSend}>
        <input value={input} onChange={(event) => setInput(event.target.value)} />
        <button type="submit" disabled={chat.isStreaming}>
          Send
        </button>
      </form>
    </div>
  );
}

Next Steps

Continue with the React examples or the App concept.