Framework Adapters
Mount the same agent receiver in Hono, Express, or another HTTP framework.
PAI framework adapters mount the framework-neutral HTTP receiver. They should only convert framework requests/responses and context into receiver route calls; they should not implement agent semantics.
Hono On Node
Install:
pnpm add @pai/hono hono @hono/node-serverimport { serve } from "@hono/node-server";
import { Hono } from "hono";
import { cors } from "hono/cors";
import { createPai } from "@pai/core";
import { createPaiHonoReceiver } from "@pai/hono";
import { assistantAgent } from "./server/assistant-agent";
const pai = createPai({
agents: { main: assistantAgent },
scopeKey: (identity) => identity.workspaceId,
});
const app = new Hono();
app.use("/api/*", cors({ origin: "http://localhost:5173" }));
app.route(
"/api/pai",
createPaiHonoReceiver({
pai,
resolveIdentity: async ({ request }) => ({
identity: { id: request.headers.get("x-user-id") ?? "anonymous", workspaceId: request.headers.get("x-workspace-id") ?? "default" },
}),
}),
);
serve({
fetch: app.fetch,
port: 3001,
});Express On Node
Install:
pnpm add @pai/express expressimport express from "express";
import { createPai } from "@pai/core";
import { createPaiExpressReceiver } from "@pai/express";
import { assistantAgent } from "./server/assistant-agent";
const pai = createPai({
agents: { main: assistantAgent },
scopeKey: (identity) => identity.workspaceId,
});
const app = express();
app.use(
"/api/pai",
createPaiExpressReceiver({
pai,
resolveIdentity: async ({ request }) => ({
identity: { id: request.headers.get("x-user-id") ?? "anonymous", workspaceId: request.headers.get("x-workspace-id") ?? "default" },
}),
}),
);
app.listen(3001);Custom Frameworks
If your framework can produce a Web Request and consume a Web Response, mount @pai/receiver-http routes directly and adapt route params plus optional host context at that boundary.
Keep authentication and scope resolution in resolveIdentity; do not duplicate them in each framework adapter.
Hono, Express, and direct @pai/receiver-http mounting expose the same
mapHttpError and onHttpError options. Use them to map receiver failures
into safe client details and report the original exception at the trusted
server boundary. See Error Handling.