handleRequest
Expose an agent over HTTP with a single function. Handles session history, streaming, reconnection, and interruption automatically.
handleRequest creates an HTTP handler from your agent that routes incoming requests to the correct session operation. One function replaces four hand-written route handlers.
Quick Start
import { myAgent } from "@/agent";
import { handleRequest } from "experimental-agent";
const handler = handleRequest(myAgent);
export const GET = handler.fetch;
export const POST = handler.fetch;The folder name (my-agent) must match the name passed to agent("my-agent", ...). This gives you four endpoints automatically:
| Method | Path | What it does |
|---|---|---|
GET | /api/agents/my-agent/:sessionId | Fetch session message history |
POST | /api/agents/my-agent/:sessionId | Send a message |
GET | /api/agents/my-agent/:sessionId/reconnect | Reconnect to an active stream |
POST | /api/agents/my-agent/:sessionId/interrupt | Interrupt the running session |
The base path defaults to /api/agents/{name} derived from the agent's name.
With Workflow
For durable execution that survives crashes and timeouts, pass a workflow function:
import { myAgent } from "@/agent";
import { handleRequest, type SessionSendArgs } from "experimental-agent";
function workflow(sessionId: string, ...args: SessionSendArgs<typeof myAgent>) {
"use workflow";
return myAgent.session(sessionId).send(...args);
}
const handler = handleRequest(myAgent, { workflow });
export const GET = handler.fetch;
export const POST = handler.fetch;When workflow is provided, POST /:sessionId starts the workflow via start() from workflow/api and streams from its result. Without a workflow, send() runs in-process.
Overrides
Intercept any route to add auth, logging, or custom logic:
import { myAgent } from "@/agent";
import { handleRequest } from "experimental-agent";
const handler = handleRequest(myAgent, {
overrides: {
"session.get": async ({ params }, next) => {
console.log("loading history for", params.sessionId);
return await next();
},
"session.post": async ({ params, body }, next) => {
return await next();
},
"interrupt.post": async ({ params, body }, next) => {
return await next();
},
},
});
export const GET = handler.fetch;
export const POST = handler.fetch;Each override receives the parsed params/body and a next function that calls the default handler. Return the result of next() or your own response.
Available override keys:
| Key | Route |
|---|---|
session.get | GET /:sessionId |
session.post | POST /:sessionId |
reconnect.get | GET /:sessionId/reconnect |
interrupt.post | POST /:sessionId/interrupt |
Custom Base Path
Override the default /api/agents/{name} convention:
import { myAgent } from "@/agent";
import { handleRequest } from "experimental-agent";
const handler = handleRequest(myAgent, {
basePath: "/api/v2/chat",
});
export const GET = handler.fetch;
export const POST = handler.fetch;When using a custom base path, configure the client-side hooks to match — see React Hooks.
When to Use handleRequest vs. Manual Routes
Use handleRequest when you want convention-based routing with minimal setup. Use manual API routes when you need full control over each endpoint's request/response handling, or when your framework doesn't use a catch-all route pattern.
Next Steps
- React Hooks —
useAgent,useSessionHistory,useInterruptSession - API Routes — Manual route patterns for full control
- Streaming — Reconnection and status handling