PAIPAI

React Setup

Create a typed React binding and provide a client/thread.

Create one typed React root for your app contract and derive agent bindings from it.

// web/src/pai-react.ts
import { createPaiReact } from "@pai/react";
import type { AssistantPai } from "../../server/pai";

export const Pai = createPaiReact<AssistantPai>();
export const AssistantAI = Pai.agent("main");

Create a client:

// web/src/pai-client.ts
import { createPaiHttpClient } from "@pai/client-http";
import type { AssistantPai } from "../../server/pai";

export const paiClient = createPaiHttpClient<AssistantPai>({
  url: "http://localhost:3001/api/pai",
});

Wrap your UI:

import { paiClient } from "./pai-client";
import { AssistantAI, Pai } from "./pai-react";

export function AssistantPage({ threadId }: { threadId: string }) {
  return (
    <Pai.Provider client={paiClient}>
      <AssistantAI.ThreadProvider threadId={threadId}>
        <AssistantChat />
      </AssistantAI.ThreadProvider>
    </Pai.Provider>
  );
}

Pai.Provider owns the app client. ThreadProvider opens and observes one thread for the selected agent binding.

Existing Thread Object

If you already have a thread object:

<AssistantAI.ThreadProvider thread={thread}>
  <AssistantChat />
</AssistantAI.ThreadProvider>

Thread mode does not close the thread on unmount by default.

ThreadProvider can attach its live clientData and mounted client-tool snapshots to the handle itself only when it creates that handle from threadId. If you supply a Thread object, create it with a dynamic requestContext when pending-action or client-tool ToolData requests depend on changing frontend context:

const thread = client.thread(threadId, {
  requestContext: () => ({
    clientData: readCurrentClientData(),
    clientTools: readMountedClientToolSnapshots(),
  }),
});

The provider uses the supplied object as-is; it does not wrap or replace its request-context resolver. Prefer the threadId form unless the app needs to own the handle itself.

If your frontend cannot safely type-import from the server package, use Codegen to generate the contract type, HTTP client factory, and React binding into a client-safe folder.

On this page