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.