Skip to main content
@personaai/runtime is the framework-agnostic runtime engine for the Persona Developer Platform — the shared engine every framework adapter (@personaai/express, @personaai/nextjs, …) is meant to be a thin translation layer over. It wraps @personaai/sdk and turns a plain {method, path, headers, query, body} request shape into the full set of end-user chat/thread/ file/memory routes plus an opt-in Project-admin surface, with SSE streaming, reconnect/resume, lifecycle hooks, and capability gating already built in.
Server-side only. Like the SDK it wraps, the credential this runtime holds is a server-side secret — never construct createRuntime() in a browser bundle or a Next.js Client Component.
v0.5.1, current release. Framework adapters are starting to ship: @personaai/express v0.1.0 is published and lets you mount this runtime as an Express Router. This page’s Quickstart section still shows the raw Node http bridge shipped in the package’s examples/ directory — useful for non-Express hosts and for smoke-testing the runtime end-to-end. See Not yet implemented & roadmap for what’s still missing.

Install

Peer/direct dependencies: @personaai/sdk and @ag-ui/core, both installed automatically. Node 18+ required (global fetch, FormData, ReadableStream).

The user resolver contract

Persona never authenticates end users — the runtime receives a request and asks you who it’s from:
resolveUser is the single point of contact between your auth world and Persona’s runtime world. Every route except GET /health calls it before doing anything else; a null return or a thrown error both produce a 401. This boundary is absolute — the runtime has no concept of sessions, cookies, or tokens of its own.

createRuntime() options

createRuntime() returns { handle(request): Promise<RuntimeResponse>, close(): void }. Call close() to stop the internal eviction timer if you construct runtimes repeatedly in a long-lived process (e.g. per-test-suite setup) — the timer is unref’d so it won’t itself keep a bare Node process alive, but accumulating many uncleaned timers is still wasteful.

Quickstart (raw Node http)

Prefer Express? Skip this section and use the @personaai/express adapter. For every other host (plain http, Fastify-style mounts, serverless wrappers) there’s no @personaai/node adapter yet, so the package ships a small, tested bridge at examples/node-handler.ts in the GitHub repo for running the runtime directly against Node’s http module — just enough to demo/smoke-test the runtime end-to-end until a real adapter ships. It also parses multipart file uploads via Node’s native Request/FormData (undici), no extra dependency.
examples/ is not published to npm and has no exports entry — package.json’s files only ships dist/, and exports only maps .. import ... from '@personaai/runtime/examples/...' fails with ERR_PACKAGE_PATH_NOT_EXPORTED after a real npm install. Copy the file into your own project instead — it’s plain TypeScript with no runtime-internal dependencies.

RuntimeRequest / RuntimeResponse

Every adapter (present or future) is responsible for translating its framework’s native request/response into this shape and back:
The runtime never touches raw request bytes or a specific multipart parser — for POST /files and POST /knowledge/:id/documents, a framework adapter parses the incoming multipart body and populates file/files plus puts any other form fields on body. See examples/node-handler.ts’s readMultipartBody for the reference approach.

Next steps