Install
pnpm add @kestrel-agents/next@0.8.5 @kestrel-agents/sdk@0.8.5Create the agent in a server-only module using the kestrel profile, as in
the first Build step. Resolve the actor and tenant from the authenticated server
session for each request.
Resolve server-owned identity
Authenticate before parsing identity-bearing request fields. The server owns tenant, actor, provider authority, approval context, and runner credentials; the browser may supply only validated user intent and resource identifiers it is authorized to access.
JSON route
Create app/api/agent/run/route.ts:
import { createJsonRunRouteHandler } from "@kestrel-agents/next";
import { agent } from "@/lib/kestrel-agent";
import { resolveKestrelContext } from "@/lib/auth";
export const POST = createJsonRunRouteHandler({
agent,
resolveContext: resolveKestrelContext,
});The default request body is:
{
"sessionId": "kestrel-session-001",
"message": "Summarize the current project."
}The handler validates the body, runs the agent, returns the terminal event as
JSON, and adds x-kestrel-request-id and x-kestrel-correlation-id.
Streaming route
import { createStreamRunRouteHandler } from "@kestrel-agents/next";
import { agent } from "@/lib/kestrel-agent";
import { resolveKestrelContext } from "@/lib/auth";
export const POST = createStreamRunRouteHandler({
agent,
resolveContext: resolveKestrelContext,
});This handler returns server-sent events and passes request.signal to the SDK.
Closing the response cancels the exact upstream run.
Webhook route
Use a webhook helper when the incoming payload does not already have the Kestrel turn shape:
import { createWebhookRunRouteHandler } from "@kestrel-agents/next";
import { agent } from "@/lib/kestrel-agent";
import { resolveKestrelContext } from "@/lib/auth";
export const POST = createWebhookRunRouteHandler<{
conversationId: string;
prompt: string;
}>({
agent,
resolveContext: resolveKestrelContext,
mapPayload(payload) {
return {
sessionId: payload.conversationId,
message: payload.prompt,
};
},
});Authenticate and validate the webhook before treating its fields as actor, tenant, session, or approval context.
Correlation ownership
The Next.js helpers read x-request-id and x-correlation-id, generate missing
values, and return x-kestrel-request-id and
x-kestrel-correlation-id. Session and run headers belong to upstream
OpenAI-compatible responses; they are not generated by these route helpers.
Failure handling
Return safe, distinct failures for authentication, invalid input, unreachable runner, interrupted stream, and terminal failure. A waiting or cancelled terminal result is not a generic HTTP success message and must remain visible to the client as runtime state.
Verify
Exercise the JSON, streaming, and webhook routes outside the browser trust boundary. Confirm forged actor headers are ignored, disconnect cancels the exact stream, webhook retries are idempotent, and request/correlation identifiers reach the terminal result.
Use the route cookbook for request and response details or OpenAI-compatible HTTP for an existing OpenAI client.