# Documentation ## Introduction URL: /docs A TypeScript framework for building typed, event-driven, framework-agnostic agent apps. Introduction Better Agent is a TypeScript framework for building typed, composable and durable agent apps. It gives you a composable runtime for tools, memory, storage, auth context, interrupts, resumable runs, plugins, and a typed client across frameworks. Why It Exists - Agent apps should be typed end-to-end, from definitions to client calls. - The framework should fit into your existing stack, including your application, database, and auth. - Reusable behavior should be easy to package and share as plugins. - Durable conversations, resumable runs, and interrupted work should be easy to build. How It Fits Better Agent sits inside your existing application stack. Use it with your framework, database, auth system, provider SDKs, and UI. Next - Get Started - Agent - Events --- ## Concepts URL: /docs/concepts Core Better Agent concepts. --- ## Agent URL: /docs/concepts/agent The fundamental building block of Better Agent. Agent An agent is a defineAgent config: name, model, instruction, tools, memory, access, output, and hooks. The name is a string literal type used to retrieve the agent with app.agent("support"). Instruction Use a string for static behavior. Use a function for request-aware behavior. The function receives typed context and can be async. Context schema contextSchema types the per-request context passed at runtime. The schema can be Zod, any Standard Schema, or plain JSON Schema. The inferred type flows through instructions, tool execute calls, and hooks. Pass context when running the agent: Tools tools can include local defineTool tools, provider tool configs, or a tool source such as mcpTools. Use toolChoice when the model must call a specific tool or mode: See Tools for tool types and approvals, and MCP for remote tool servers. Memory Memory loads previous thread messages for an agent. Configure it per agent with createMemory, or set it at the app level. Set memory: false to opt an agent out of app-level memory. Use lastMessages to limit loaded history. Use scope to isolate storage by tenant, user, or another derived key. See Memory for setup. Access control access controls who can invoke an agent over HTTP. | Value | Behavior | | ------------------ | -------------------------------------------------------- | | "public" | Anyone can call the agent. | | "authenticated" | Requires a non-null auth context. | | (ctx) => boolean | Custom function receives { auth, agentName, request }. | When the app has an auth resolver and the agent does not set access, it defaults to "authenticated". For app-level auth setup, see Auth. Structured output output.schema validates the final response and exposes typed data on result.structured. See Structured output for schema formats, runtime overrides, typing, and provider behavior. Lifecycle hooks Hooks observe and control the runtime loop at the agent level. onStep Runs before each model call. Use it to update messages, filter active tools, or patch state. setActiveTools restricts which tools the model sees for that step. It does not remove them from the agent. Other loop controls: | Option | Use | | -------------- | ----------------------------------------------------------- | | onStepFinish | Observe each step result, token usage, and tool call count. | | onState | React to state.set() and state.patch(). | | stopWhen | Stop early when a predicate returns true. | | maxSteps | Set a hard ceiling on loop iterations. | For streamed runtime events, see Events. Running an agent Register agents in a betterAgent app, then call .run() or .stream() on the handle. See Client for browser usage. .run() returns a RunResult. .stream() returns events and a final promise that resolves to a RunResult. Interrupted runs can be resumed. See Human in the Loop. Type inference Agent names, context, tools, hooks, and output are inferred from the definition. app.agent("name") returns a typed handle. See TypeScript for the broader typing model. --- ## Auth URL: /docs/concepts/auth Resolve request identity for agents, memory, and plugins. Auth Auth identifies the caller for each HTTP request. Better Agent uses that identity for agent access, memory scope, plugin guards, and plugin endpoints. Add auth Set auth on the app. Return null when the request is not authenticated. Auth context The resolver returns: | Field | Use | | --- | --- | | subject | Required user, account, or API-client id. | | tenant | Optional workspace, organization, or tenant id. | | scopes | Optional permissions for access checks. | | claims | Optional extra data from your auth system. | Better Agent does not own your auth provider. The resolver can call Better Auth, Auth.js, Clerk, your session store, JWT verification, or any other auth system. It can also verify an Agent Auth Protocol request and map the verified agent session into the same auth context. Agent access access controls who can call an agent over HTTP. Access options: | Value | Behavior | | --- | --- | | "public" | Anyone can call the agent. | | "authenticated" | Requires a non-null auth context. | | (ctx) => boolean | Custom check with { auth, agentName, request }. | When app auth is configured and an agent does not set access, it defaults to "authenticated". Without app auth, agents default to "public". Public agents Set access: "public" for agents that should be callable without identity. Memory scope When app auth is configured, remote memory routes only expose threads in the request's scope. By default, the scope is based on subject and tenant. See Memory for thread setup. Plugins Plugin guards and endpoints receive the resolved auth context. See Plugins for guards and endpoints. Agent Auth Protocol Agent Auth Protocol gives each runtime agent its own identity, key-backed authentication, capability grants, and lifecycle. Use it when external agents or agent hosts need scoped access to your service. Better Agent does not require Agent Auth. For most apps, regular user/session auth is enough. If you use an Agent Auth implementation, verify the incoming agent request in auth and map active capability grants into scopes. Then use access to require a capability before a caller can run an agent. Agent Auth implementations still own the protocol endpoints for discovery, host registration, agent registration, approval, capability grants, and lifecycle. Better Agent consumes the verified identity and capabilities through auth. Errors Missing identity returns 401 Unauthorized when authentication is required. Failed custom access checks return 403 Forbidden. Examples Your resolver can call any auth system. Return null when no valid session exists. Better Auth Custom --- ## Client URL: /docs/concepts/client Call agents from your frontend. Client The client connects your frontend to the Better Agent HTTP handler. Pass your server app type to keep agent names, context, memory helpers, and client tool handlers aligned with the backend. Create a client baseURL should point to the route where your app handler is mounted. Run an agent Use client.agent("name") to call a specific agent. Use stream when you want events as the run progresses. See Events for AG-UI event details. React Use the React hook for chat state, streaming, and interrupts. The hook returns messages, state, status, isRunning, sendMessage, stop, resume, and interrupt helpers. Framework hooks Framework adapters are available from sub-paths: | Framework | Import | | --- | --- | | React | @better-agent/client/react | | Vue | @better-agent/client/vue | | Svelte | @better-agent/client/svelte | | Solid | @better-agent/client/solid | | Preact | @better-agent/client/preact | Each adapter exposes framework-native state for messages, streaming, state, threads, and interrupts. Auth Use headers for bearer tokens or API keys. Use credentials: "include" for cookie-based auth. Use prepareRequest when you need to rewrite the request before fetch. See Auth for server-side identity resolution. Client tools Client tool handlers run in the user's app. When a matching handler exists, the hook resolves the client tool and resumes the run automatically. Without a handler, pendingClientTools lets your UI show what input is waiting for a handler. See Tools for client tools. Approvals The hook exposes pending approval interrupts. Use rejectToolCall to deny a pending approval. See Human in the Loop for approval setup. Memory Pass threadId to continue a saved conversation. When memory is configured, the client exposes thread and message helpers. See Memory for setup. Runs Abort an active run from the client. Resume a stored stream by run id. Stream resume requires storage for run and stream records. See Storage for setup and Drizzle, Kysely, Prisma, or Redis for production adapters. --- ## Errors URL: /docs/concepts/errors Handle run, HTTP, stream, and validation errors. Errors Better Agent uses structured errors across server APIs, HTTP routes, streams, and client hooks. Error shape HTTP errors return problem details. Use status for transport handling, code for app logic, and detail for the message. Common codes | Code | Meaning | | ------------------- | --------------------------------- | | BAD_REQUEST | The request is malformed. | | VALIDATION_FAILED | Input or output schema failed. | | UNAUTHORIZED | No valid caller identity. | | FORBIDDEN | The caller is not allowed. | | NOT_FOUND | Agent, run, or thread missing. | | CONFLICT | The request conflicts with state. | | RATE_LIMITED | Too many requests. | | TIMEOUT | The operation timed out. | | ABORTED | The run was stopped. | | UPSTREAM_FAILED | A provider or upstream failed. | | INTERNAL | Unexpected server failure. | Server errors Server run calls throw BetterAgentError when the failure is known. Check code and status before deciding what to show or retry. Client errors The browser client throws BetterAgentClientError for failed HTTP requests and failed stream frames. React errors Framework hooks expose the latest error and accept onError. Streaming errors Streaming runs emit AG-UI RUN_ERROR events when a run fails. Client streams also throw BetterAgentClientError when the HTTP stream itself fails. See Events for stream events. Validation errors Schema failures use VALIDATION_FAILED and may include issues. Validation can come from agent context, tool input, resume input, or structured output. See Agent, Tools, and Structured Output for schema setup. Retry | Usually retry | Do not blindly retry | | ------------------------------ | --------------------------------------------------------- | | RATELIMITED | BADREQUEST | | TIMEOUT | VALIDATION_FAILED | | UPSTREAMFAILED | UNAUTHORIZED, FORBIDDEN, NOTFOUND, CONFLICT | --- ## Events URL: /docs/concepts/events Stream AG-UI events from agent runs. Events Better Agent streams AG-UI events from every streaming run. The client SDK and framework hooks apply the common UI updates for you. Use events directly when you need custom logging, analytics, tracing, or product-specific side effects. Use onEvent when your app needs to observe the stream directly. Stream events Call .stream() to receive events as they happen. Await final when you need the finished run result. React Use onEvent for observability or custom UI behavior. See AG-UI Events for the event protocol and AG-UI Interrupts for interrupt semantics. --- ## Human in the Loop URL: /docs/concepts/hil Pause runs for human approval and user input. Human in the Loop Use human in the loop when an agent should pause before continuing. Common cases are approving a sensitive server tool or collecting input from the user's app. Better Agent represents these pauses as AG-UI interrupts. Interrupts have stable ids, so your UI can show a pending decision, keep it durable with the run, and resume later. Human in the loop requires Storage to be configured for runs to store interrupted runs and resume later. Require approval Add approval to a server tool when it needs a human decision before execution. When the model calls refund for more than 50, the run pauses before execute runs. The raw interrupt includes an id, reason, tool call id, optional metadata, and any expiry. Client hooks turn that into a pending approval with the tool name and parsed input. Handle approvals in React The React hook exposes pending approvals and resumes automatically after you approve or reject them. If there are multiple pending approvals, answer each one. The hook continues the run when no undecided approvals remain. Approve from the server Without the client hook, resume the same thread with a resume entry. Manual resume requires a threadId and Storage. Approving lets the tool execute. Denying sends a denied tool result back to the model so it can respond to the user. Use status: "cancelled" when you want to cancel the pending action instead. Approval metadata resolve can return metadata for your approval UI. When the user answers, you can send response metadata too. Timeouts Set a timeout when an approval should expire. The interrupt includes expiresAt. Use it to render a countdown or hide stale approval actions. Client tools Client tools are another kind of pause. They run in the user's app instead of on the server. If a matching client handler is registered, the client resolves the tool automatically. If not, the UI can read pendingClientTools and render its own pending-tool UI. See Tools for client tool examples. How it works 1. The model calls a tool. 2. The runtime checks whether approval or client-side input is needed. 3. If yes, the run returns with outcome: "interrupt". 4. Your UI or server resolves the interrupt. 5. The run resumes from the same thread. Important fields: | Field | Use | | ---------------- | --------------------------------------------------------- | | id | The interrupt id. Pass it as interruptId when resuming. | | reason | Why the run paused, such as toolapprovalpending. | | toolCallId | The tool call that created the pause. | | responseSchema | The expected shape of the resume payload. | | metadata | Extra context for your UI. | | expiresAt | When the pending decision expires. | --- ## MCP URL: /docs/concepts/mcp Connect agents to MCP servers. MCP Better Agent can connect to Model Context Protocol servers and expose their tools to agents. Use mcpTools when you want an agent to call tools from GitHub, local files, databases, internal services, or any MCP-compatible server. Add MCP tools Create an MCP tool source, then pass it to the agent's tools option. MCP tools are discovered on first use and cached. They run as server tools, so the agent can call them during the normal tool loop. Local servers Use stdio for MCP servers that run as local processes. Set cwd, env, or stderr when the local process needs a working directory, environment variables, or custom stderr handling. Multiple servers Pass multiple servers when an agent needs tools from more than one source. Tool names must be unique. Use prefix to avoid collisions. A tool named search becomes ghsearch or fssearch. For full control, use mapToolName. Mix with local tools MCP sources can be combined with local tools and provider tools by using a tools function. See Tools for local tools and provider tools. Refresh and shutdown Call reload() when the MCP server changes and you want to fetch its tools again. Call dispose() during server shutdown to close MCP connections and stop local stdio processes. Existing clients If you already created and connected an MCP Client, pass it as client. Advanced API mcpTools covers most apps. For lower-level control, import createMCPClient, listAllMCPTools, and convertMCPTools from @better-agent/core/mcp. --- ## Memory URL: /docs/concepts/memory Let agents remember conversations across runs. Memory Memory lets an agent continue a conversation. When you pass the same threadId to later runs, Better Agent loads previous messages from that thread before the new input. Memory needs storage to survive across requests and deploys. Add memory Configure memory with createMemory. Use a threadId when you run the agent. The second run includes recent messages from thread_123. Storage Memory stores threads and messages in the app's storage. createInMemoryStorage() is useful for local development and tests. For production, use a database adapter. See Storage for runtime storage. For production adapters, see Drizzle, Kysely, Prisma, or Redis. You can also bind storage directly to a memory instance. Agent memory App-level memory applies to every agent. Set memory on an agent when it needs a different history window. Use memory: false when an agent should ignore app-level memory. History window lastMessages controls how many previous messages are loaded into the next run. It must be a positive integer. Use a smaller window for fast classifiers and a larger window for chat agents. Memory options createMemory accepts: | Option | Use | | --- | --- | | storage | Bind this memory instance to a specific storage adapter. | | lastMessages | Limit how many previous messages are loaded. | | scope | Isolate remote thread access by tenant, user, or another key. | | generateId | Customize thread and stored message ids. | Thread scope Use scope to isolate thread access for authenticated HTTP requests. When app auth is configured, remote thread endpoints only expose threads in the resolved scope. If you do not provide scope, Better Agent uses the authenticated subject and tenant. Custom ids Use generateId when thread or message record ids need to follow your own format. Manage threads Agent handles expose memory helpers when memory is configured. Delete a thread when the conversation should be removed. Fork a thread to branch a conversation. Pass a transform to copy only the messages you want. --- ## Plugins URL: /docs/concepts/plugins Add app-wide behavior to every agent. Plugins Plugins add behavior at the app level. Register them once and they apply to every agent in the app. Use plugins for cross-agent concerns: request guards, logging, analytics, shared tools, custom endpoints, and model/tool/event hooks. Create a plugin Use definePlugin when behavior should apply across agents. Each plugin needs a unique id. Guards Guards run before app requests. Return null to allow the request, or return a Response to stop it. The guard context includes agentName, parsed input, the raw request, and resolved auth. See Auth for request identity. Lifecycle hooks Plugins can observe or adjust the agent loop. Use onStep to adjust messages or active tools before a step. Use onStepFinish to observe the step result after it finishes. Model hooks Model hooks run around provider calls. onBeforeModelCall can update messages, tools, tool choice, provider tools, and provider options. onAfterModelCall observes the provider response. Tool hooks Tool hooks run around tool calls. onBeforeToolCall can update tool input or skip execution. onAfterToolCall can update the tool result, status, or error. Event middleware Event middleware can transform or drop streamed events before they reach the client. Use subscribe to limit which event types middleware receives. Return next(event) to continue, or return null to drop the event. Event observation Use onEvent when you only need to observe events. See Events for the app-level event stream. Plugin tools Plugins can add tools that are available to agents. See Tools for tool targets, approvals, MCP tools, and provider tools. Endpoints Plugins can add HTTP routes to the Better Agent handler. Endpoint paths must start with /. Methods can be GET, POST, PUT, PATCH, DELETE, OPTIONS, or an array of those methods. Error behavior Guards can stop a request by returning a Response. If a guard throws, the request fails. Other plugin hooks are logged on failure and the run continues. --- ## State URL: /docs/concepts/state Track working data during a run. State State is working data for a run or thread. Use it for progress, workflow status, selected records, drafts, and UI state that should change while the agent runs. | Concept | Use it for | | ------- | ----------------------------------------------- | | State | Current run or thread working data. | | Memory | Previous conversation messages and threads. | | Storage | Where runtime records are saved. | Initial state Pass state when you start a run. result.state contains the final state. Update state Hooks receive state helpers. Use patch for targeted updates. patch uses JSON Patch operations. Tools Server tools can read and update state from the execution context. See Tools for tool configuration. Streaming State updates stream as AG-UI events: | Event | When it appears | | ---------------- | ---------------------------------- | | STATE_SNAPSHOT | State was replaced with set. | | STATE_DELTA | State was updated with patch. | See Events for event handling and AG-UI State for the state model. Client state Framework hooks expose the latest state. The hook updates agent.state as state events arrive. See Client for frontend usage. Threads When memory and threadId are used, Better Agent stores the thread state and uses it on later runs. Passing a new state overrides the stored thread state for that run. See Memory for threads and conversation history. --- ## Storage URL: /docs/concepts/storage Persist runtime data for memory, runs, and streams. Storage Storage is the durable backing layer for Better Agent runtime data. Memory decides what conversation history to load. Storage decides where records are saved. Better Agent only calls the storage methods. Your adapter decides how those records map to tables, collections, keys, or another backing store. The names below are the storage areas Better Agent passes to get, set, delete, and list. Add storage Configure storage at the app level. createInMemoryStorage() is useful for local development and tests. Use a database adapter in production. Storage areas | Area | Used for | | ---------------- | ------------------------------------------------- | | memoryThreads | Thread metadata and access scope. | | memoryMessages | Stored conversation messages. | | runs | Run status, aborts, resume, and interrupted runs. | | streams | Stream lifecycle records. | | streamEvents | Stream replay and resume. | Adapters Production adapters live in the database docs. Database adapters document the schema shape they need. Drizzle and Prisma also include generators. | Adapter | Package | Generate command | | --------------------------------- | ----------------------- | ------------------------------------ | | Drizzle | @better-agent/drizzle | npx @better-agent/drizzle generate | | Prisma | @better-agent/prisma | npx @better-agent/prisma generate | | Kysely | @better-agent/kysely | - | | Redis | @better-agent/redis | - | See Drizzle, Kysely, Prisma, or Redis for setup. Custom storage Storage is a small interface. Implement it when you already have your own storage layer or want to map Better Agent records into your own schema. list supports where, orderBy, and take. Composite storage Use composite storage when different runtime data should go to different backends. Domains group related storage areas: | Domain | Areas | | --------- | --------------------------------- | | memory | memoryThreads, memoryMessages | | runs | runs | | streams | streams, streamEvents | Route a single storage area when you need finer control. Use omit to disable a storage domain. Features that need an omitted area will behave as if that storage area is not configured. --- ## Structured Output URL: /docs/concepts/structured-output Return validated data from an agent. Structured Output Structured output tells the model to return data that matches a schema. Better Agent validates the final response and exposes it as result.structured. Add an output schema Set output.schema on the agent. The shape of result.structured is inferred from the schema. Output config output accepts: | Field | Use | | --- | --- | | schema | The schema the final response must match. | | name | Optional schema name passed to the provider. | | description | Optional schema description passed to the provider. | Override per run Pass output to .run() or .stream() when one agent needs different result shapes for different requests. Run-level output overrides agent-level output. Schema formats Schemas can be Zod, any Standard Schema compatible library, or plain JSON Schema. Use as const with plain JSON Schema when you want narrower TypeScript types. Validation Structured output requires a model that supports structured responses. If the model does not support them, the run fails before generation. After generation, Better Agent validates the final structured value: | Case | Result | | --- | --- | | No structured value returned | VALIDATION_FAILED | | Schema validation fails | VALIDATION_FAILED | | Schema validation passes | result.structured is returned | See OpenAI and Vercel AI SDK for provider-specific model capabilities. With tools Structured output works with tools. The model can call tools during the run, and Better Agent validates only the final response. --- ## Tools URL: /docs/concepts/tools Let agents call functions during a run. Tools A tool is a function the model can call during a run. Create local tools with defineTool, then add them to an agent's tools array. Server tools Server tools run in your backend. Set target: "server" and provide an execute function. execute receives validated input and a context object with run metadata, abort signal, and state helpers. Client tools Client tools run in the user's app. They do not define execute. The run pauses until the client returns a result. Client tools requires Storage to be configured for runs to store interrupted runs and resume later. Client tool pauses use AG-UI interrupts. Each interrupt has an id and response schema, so it can be stored, rendered later, and resumed across requests. When the model calls a client tool, the run returns an interrupt. Manual resume requires a threadId and Storage. In React, useAgent can handle client tools automatically with toolHandlers: When no handler is registered, the hook exposes pendingClientTools so you can render custom UI for the pending tool. Input and output schemas Every tool needs an inputSchema. It can be Zod, any Standard Schema, or plain JSON Schema. Use outputSchema when the tool result should be validated too. Other schema options: | Option | Use | | --------------- | ---------------------------------------------------------------- | | strict | Ask supported providers to produce only valid tool arguments. | | toModelOutput | Send a smaller or safer version of the result back to the model. | Approval Use approval when a tool needs human confirmation before it runs. Use resolve for conditional approval: See Human in the Loop for approvals, timeouts, and resuming runs. Error handling By default, tool errors are returned to the model as tool results. Use toolErrorMode: "throw" when a tool failure should abort the run. Dynamic tools An agent's tools option can be a function. Use it to choose tools from request context. The function can be async. See Agent for the full agent definition. MCP tools mcpTools connects to one or more Model Context Protocol servers and exposes their tools to an agent. See MCP for transports, namespacing, and reloads. Provider tools Some providers expose built-in tools, such as web search. Add them to tools with the provider helper. See OpenAI for provider tool setup. --- ## TypeScript URL: /docs/concepts/typescript Share agent types across server and client. TypeScript Better Agent infers types from your agents, schemas, tools, memory, and app registration. You do not need generated client types. Agent names Registered agent names become valid handles on the app. The same name checking works in the browser when the client uses the server app type. Context contextSchema defines the context shape for runs, streams, instructions, tools, and hooks. See Agent for agent configuration. Tools Tool schemas infer the input type passed to server tools. Client tool handlers infer the input for each matching client tool. See Tools for server tools, client tools, approvals, MCP tools, and provider tools. Structured output output.schema infers result.structured. See Structured Output for schema formats and per-run output. Client type sharing Export your server app and pass its type to the client. The client now knows agent names, context, memory helpers, and client tool handlers. See Client for browser usage. Schema types Schemas can be Zod, any Standard Schema, or plain JSON Schema. Use as const with plain JSON Schema when you want narrower inferred types. Helper types | Type | Package | Use it for | | ---------------------- | ---------------------- | --------------------------------------- | | AgentContextOf | @better-agent/core | Get the context type from an agent. | | InferSchemaInput | @better-agent/core | Infer input from a schema. | | InferSchemaOutput | @better-agent/core | Infer output from a schema. | | BetterAgentApp | @better-agent/core | Type an app when exporting helpers. | | BetterAgentErrorCode | @better-agent/core | Type error-code handling. | | AgentNameOf | @better-agent/client | Get valid agent names from an app type. | | AgentContextFor | @better-agent/client | Get client context for one agent. | | ToolHandlersFor | @better-agent/client | Type client tool handlers. | --- ## Databases URL: /docs/database Storage adapters for durable Better Agent data. --- ## Drizzle URL: /docs/database/drizzle Drizzle ORM adapter for Better Agent. Drizzle Use Drizzle as the storage adapter for memory, runs, and streams. Install Generate schema Generate the Better Agent tables into your Drizzle schema. Supported dialects: pg, mysql, and sqlite. Use --only when you only want some storage areas. Setup Add the generated schema to your Drizzle schema object, then pass the Drizzle database to drizzleStorage. Options | Option | Description | | --------- | ------------------------------------------- | | db | Existing Drizzle database instance. | | dialect | postgres, mysql, or sqlite. | Pass the Drizzle db instance you already use in your app. Notes Run your normal Drizzle migration flow after adding the generated schema. See Storage for what Better Agent stores. Powered by Farming Labs ORM. --- ## Kysely URL: /docs/database/kysely Kysely adapter for Better Agent. Kysely Use Kysely as the storage adapter for memory, runs, and streams. Install Setup Pass your Kysely database to kyselyStorage. Schema The Kysely adapter expects the Better Agent storage tables below. It does not include a generator, so create these tables in your own migration system before using kyselyStorage. This Postgres migration shows the required shape. For MySQL or SQLite, keep the same table names, column names, nullability, and constraints, and translate jsonb and timestamptz to your dialect's JSON and datetime types. If you need different physical table names or a different schema layout, use a custom Storage implementation instead of kyselyStorage. Options | Option | Description | | --------- | --------------------------- | | db | Existing Kysely database. | | dialect | postgres, mysql, or sqlite. | Notes Use Kysely when your app already owns SQL migrations and database types. See Storage for what Better Agent stores. Powered by Farming Labs ORM. --- ## Prisma URL: /docs/database/prisma Prisma adapter for Better Agent. Prisma Use Prisma as the storage adapter for memory, runs, and streams. Install Generate schema Add the Better Agent models to your Prisma schema. Supported providers: postgresql, mysql, and sqlite. Use --only when you only want some storage areas. Migrate Run Prisma migration and client generation after updating the schema. Setup Pass your Prisma client to prismaStorage. Options | Option | Description | | -------- | ------------------------------- | | client | Existing Prisma client instance. | Notes The generator updates your Prisma schema. Prisma still owns migrations, database connection settings, and client generation. See Storage for what Better Agent stores. Powered by Farming Labs ORM. --- ## Redis URL: /docs/database/redis Redis adapter for Better Agent. Redis Use Redis as the storage adapter for memory, runs, and streams. Install Setup Pass a connected Redis client to redisStorage. Options | Option | Description | | ------------ | ------------------------------------------------ | | client | Connected Redis client. | | base | Base key namespace. | | prefixes | Per-model key prefixes. | | transforms | Per-field encode and decode hooks for stored data. | Notes Redis works well for run resume and stream replay when Redis durability is enabled. The adapter can use redis or @upstash/redis. For Upstash, install @upstash/redis instead of redis. See Storage for what Better Agent stores. Powered by Farming Labs ORM. --- ## Get Started URL: /docs/get-started Install Better Agent, define your first agent, and run it. Get Started Create a Better Agent app, define one agent, and run it locally. Install Install the core package and a provider: Use the CLI when you want a full framework scaffold: Create an agent An agent is a name, a model, and an instruction. betterAgent() wires agents into a typed app. Run it Serve over HTTP app.handler is a standard Request to Response function. Mount it in any framework route. See Integrations for framework-specific routes. Next - Agent for the full agent config. - Tools when your agent needs to take actions. - Client when calling agents from a frontend. --- ## Integrations URL: /docs/integrations Framework integrations. --- ## Astro URL: /docs/integrations/astro Use Better Agent with Astro. Astro Use Better Agent in Astro with an API route and a hydrated React island. Server Route If your Astro site prerenders by default, disable prerendering for this API route. Client Basic chat Mount the island from an Astro page. Threads Context Client tools Approvals Events Finish and errors Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## Elysia URL: /docs/integrations/elysia Use Better Agent with Elysia. Elysia Elysia exposes a web Request, so you can call app.handler directly. Server Route Client Auth and headers Headers from the web Request are forwarded to Better Agent. Use Auth to resolve identity from cookies, bearer tokens, or API keys. Features The mounted route supports runs, streams, threads, interrupts, client tools, and approvals. Use Client from your frontend to call it. Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## Express URL: /docs/integrations/express Use Better Agent with Express. Express Use the Express adapter to mount Better Agent, then connect from any frontend with the same client. Install Server Route Mount the adapter under the same path your client uses. The adapter converts Express request and response objects to Better Agent's web handler. Body parsing The adapter can forward Express body parser output. Mount JSON middleware before the Better Agent route if other middleware expects parsed JSON. CORS If your frontend runs on a different origin, add CORS before the Better Agent route. Client Use an absolute URL when the frontend is served from another origin. Auth and headers Headers from the Express request are forwarded to Better Agent. Use Auth to resolve identity from cookies, bearer tokens, or API keys. Features The mounted route supports runs, streams, threads, interrupts, client tools, and approvals. Use Client from your frontend to call it. Next See Client, Tools, Human in the Loop, Memory, Events, Auth, and Storage. --- ## Fastify URL: /docs/integrations/fastify Use Better Agent with Fastify. Fastify Use the Fastify adapter to mount Better Agent, then connect from any frontend. Install Server Route CORS If your frontend runs on a different origin, register CORS before the Better Agent route. Client Auth and headers Headers from the Fastify request are forwarded to Better Agent. Use Auth to resolve identity from cookies, bearer tokens, or API keys. Features The mounted route supports runs, streams, threads, interrupts, client tools, and approvals. Use Client from your frontend to call it. Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## Hono URL: /docs/integrations/hono Use Better Agent with Hono. Hono Hono exposes a web Request, so you can call app.handler directly. Server Route CORS Register CORS before the Better Agent route. Client Auth and headers Headers from c.req.raw are forwarded to Better Agent. Use Auth to resolve identity from cookies, bearer tokens, or API keys. Features The mounted route supports runs, streams, threads, interrupts, client tools, and approvals. Use Client from your frontend to call it. Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## NestJS URL: /docs/integrations/nestjs Use Better Agent with NestJS. NestJS Mount Better Agent through Nest's underlying HTTP adapter. This example uses Nest with Express. Install Service Bootstrap Module Client Auth and headers Headers from the underlying Express request are forwarded to Better Agent. Use Auth to resolve identity from cookies, bearer tokens, or API keys. Features The mounted route supports runs, streams, threads, interrupts, client tools, and approvals. Use Client from your frontend to call it. Fastify If your Nest app uses Fastify, mount Better Agent with toFastifyHandler instead. Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## Next.js URL: /docs/integrations/nextjs Use Better Agent with Next.js App Router. Next.js Use Better Agent in a Next.js App Router app with the React useAgent hook. Server Route Create a catch-all route and forward every method to app.handler. Client Keep basePath, the route path, and baseURL aligned. Basic chat useAgent gives you messages, status, errors, send, stop, and resume helpers. Threads Pass threadId to continue a saved conversation. Memory needs storage to survive reloads and deploys. Load messages Memory-enabled agents expose helpers for loading and switching threads. Context Use context for stable per-chat values. You can also pass context per message. Client tools Register handlers for tools that run in the browser. Matching client tools resolve and resume automatically. When no handler exists, use pendingClientTools to render your own UI. Approvals When a server tool waits for approval, render pendingToolApprovals. Events Use onEvent for progress UI, logging, analytics, or custom event handling. Finish and errors Use lifecycle callbacks for final messages, interrupts, aborts, and errors. Resume Use resume when you have a saved run cursor. Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## Nuxt URL: /docs/integrations/nuxt Use Better Agent with Nuxt. Nuxt Use Better Agent in Nuxt with a server route and the Vue useAgent hook. Server Route Client Basic chat Threads Context Client tools Approvals Events Finish and errors Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## Remix URL: /docs/integrations/remix Use Better Agent with Remix. Remix Use Better Agent in Remix with a resource route and the React useAgent hook. Server Route For cross-origin clients, handle CORS and preflight at your Remix server or deployment. Client Basic chat Threads Context Client tools Approvals Events Finish and errors Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## SolidStart URL: /docs/integrations/solidstart Use Better Agent with SolidStart. SolidStart Use Better Agent in SolidStart with an API route and the Solid useAgent hook. Server Route Client Basic chat Threads Context Client tools Approvals Events Finish and errors Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## SvelteKit URL: /docs/integrations/sveltekit Use Better Agent with SvelteKit. SvelteKit Use Better Agent in a SvelteKit app with the Svelte createAgentChat store. Server Route Create a rest endpoint and forward every method to app.handler. Client Keep basePath, the route path, and baseURL aligned. Basic chat createAgentChat gives you a Svelte store plus actions. Threads Pass threadId to continue a saved conversation. Memory needs storage to survive reloads and deploys. Load messages Memory-enabled agents expose helpers for loading and switching threads. Context Use context for stable per-chat values. You can also pass context per message. Client tools Register handlers for tools that run in the browser. Matching client tools resolve and resume automatically. When no handler exists, use pendingClientTools to render your own UI. Approvals When a server tool waits for approval, render pendingToolApprovals. Events Use onEvent for progress UI, logging, analytics, or custom event handling. Finish and errors Use lifecycle callbacks for final messages, interrupts, aborts, and errors. Resume Use resume when you have a saved run cursor. Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## TanStack Start URL: /docs/integrations/tanstack-start Use Better Agent with TanStack Start. TanStack Start Use Better Agent in TanStack Start with a server route and the React useAgent hook. Server Route Client Basic chat Threads Context Client tools Approvals Events Finish and errors Next See Client, Tools, Human in the Loop, Memory, Events, and Storage. --- ## Plugins URL: /docs/plugins Available plugins. --- ## IP Allowlist URL: /docs/plugins/ip-allowlist IP and CIDR allowlist plugin. IP Allowlist IP Allowlist blocks requests unless they come from an allowed IP or CIDR range. Basic usage By default, the plugin reads direct client IP headers like x-real-ip and cf-connecting-ip. CIDR ranges Use CIDR ranges to allow a subnet. Exact IPs and IPv4 or IPv6 CIDR ranges are supported. Trusted proxies Use trustProxy only when your app is behind a proxy you trust to set x-forwarded-for. When enabled, the plugin uses the first valid IP from x-forwarded-for. Custom IP resolution Use getIp when your platform exposes the client IP somewhere else. Denied response If the request IP is missing or not allowed, the plugin returns 403 Forbidden. Use onDenied to return your own response. --- ## Logging URL: /docs/plugins/logging Structured runtime logging plugin. Logging Logging emits structured runtime logs for requests, events, steps, model calls, tool calls, and errors. Basic usage By default, logs go to the console, every logging group is enabled, and the minimum level is info. Custom logger Use logger to send entries to your own logging system. Include only what you need Use include to reduce noise. Redact sensitive data Sensitive headers like authorization, cookie, set-cookie, and x-api-key are redacted by default. Add more headers with redactHeaders, or rewrite logged bodies with redactBody. redactBody receives phase as request, response, tool_args, or tool_result. Format output Use format to shape each log entry before it is written. Levels Log levels are debug, info, warn, and error. Use level: "debug" to include debug-only entries like model and tool call details. --- ## Rate Limit URL: /docs/plugins/rate-limit Windowed request rate limiting plugin. Rate Limit Rate Limit blocks requests after a configured number of calls in a time window. Basic usage By default, each agent gets one global bucket. Limit by user or tenant Use key to decide which requests share a bucket. Shared storage The default in-memory store is fine for local development or one server instance. Use storage when limits need to be shared across instances. write uses compare-and-set semantics. Return false when another request updated the bucket first. Store errors If storage fails, onStoreError decides what to do. By default, the plugin allows the request. Return "allow", "deny", or a custom Response. Retries Use casRetries to control how many times the plugin retries a conflicting storage write. A conflict happens when storage.write returns false, usually because another request updated the same bucket first. The default is 8. Blocked response Blocked requests return 429 Too Many Requests with rate-limit headers. | Header | Description | | ----------------------- | ------------------------------------- | | retry-after | Seconds until the window resets | | x-ratelimit-limit | Max requests allowed | | x-ratelimit-remaining | Remaining requests | | x-ratelimit-reset | Unix timestamp when the window resets | --- ## Sandbox URL: /docs/plugins/sandbox Sandbox workspace tools for agents. Sandbox Sandbox gives agents a real workspace for commands, files, directories, and preview URLs. Built-in clients are available for E2B and Daytona. Install the provider SDK you use. E2B Daytona Tools By default, the plugin adds these tools: | Tool | Use it for | | --------------------- | -------------------------- | | sandbox_create | Create or reuse a sandbox | | sandbox_exec | Run a command | | sandboxreadfile | Read a file | | sandboxwritefile | Write a file | | sandboxlistfiles | List files | | sandboxmakedir | Create a directory | | sandboxremovepath | Remove a file or directory | | sandboxgethost | Get a public preview URL | | sandbox_kill | Stop the sandbox | Use prefix to change tool names. This creates tools like workspacecreate, workspaceexec, and workspacewritefile. Sandbox creation Use createConfig for fixed creation settings that model overrides cannot change. Use createDefaults for fallback settings. Precedence is createConfig, model override, then createDefaults. | Field | E2B | Daytona | | -------------------------- | ------------- | ------------- | | template | Supported | Supported | | startupTimeoutMs | Not supported | Supported | | envs | Supported | Supported | | metadata | Supported | Supported | | lifecycle.ttlMs | Supported | Not supported | | lifecycle.idleStopMs | Not supported | Supported | | lifecycle.archiveAfterMs | Not supported | Supported | | lifecycle.deleteAfterMs | Not supported | Supported | Unsupported provider fields throw a validation error. Reuse By default, the plugin reuses one sandbox per threadId. Without a threadId, the plugin does not automatically reuse a sandbox. Use sessionKey to control reuse. Return a non-empty string to reuse a sandbox under that key. Return null or undefined to disable reuse for that call. Shared store The default session store is in-memory. Use store when sandbox reuse needs to work across workers or instances. Approvals Sandbox tools can run commands and modify files. Use approvals for risky tools. See Human in the Loop for approval handling. Preview URLs Use sandboxgethost when the agent starts a server inside the sandbox and needs a public preview URL. Providers may return a plain URL or a URL plus an access token. --- ## Providers URL: /docs/providers Supported AI providers. --- ## Vercel AI SDK URL: /docs/providers/ai-sdk Use AI SDK-compatible models. Vercel AI SDK Use this adapter when you already have an AI SDK model or want to use a provider that does not have a dedicated Better Agent package. Install Install the AI SDK provider package you use. The examples below use @ai-sdk/openai. Agent model Wrap an AI SDK language model with aiSdkModel. Model types Use aiSdkModel(...) as the agent model in defineAgent. Use aiSdkTextModel(...), aiSdkEmbeddingModel(...), aiSdkImageModel(...), and the other generation wrappers when your app or a tool needs a direct model call outside the agent loop. Hosted tools AI SDK provider tools can be passed through Better Agent as provider tool configs. Generation Use the generation wrappers when you need text, embeddings, images, video, speech, or transcription outside the agent loop. A common pattern is calling a generation model from a server tool. Other generation wrappers: Capabilities Capabilities are declared by the wrapper you create. Set only what the model actually supports. Agent models must include text output support. | Feature | Support | | ----------------- | ----------------------- | | Text agents | Depends on model | | Streaming | Depends on model | | Structured output | Depends on model | | Hosted tools | Depends on provider | | Generation models | Text, embeddings, media | --- ## Anthropic URL: /docs/providers/anthropic Use Anthropic Claude models and hosted tools. Anthropic Install Agent model Configure Hosted tools Anthropic hosted tools are available on anthropic.tools. See Tools for local tools, client tools, approvals, MCP, and hosted provider tools. Direct generation Use generation models when a tool needs a focused model call without running an agent. Model types anthropic("claude-sonnet-4-5") is an agent model for defineAgent. Agent models need text for messages, tool decisions, and streaming. They can support more than text depending on the model. anthropic.text(...) is a generation model for direct text calls from app code or tools. It does not run the agent loop. Provider options Pass Anthropic options at run time with the anthropic provider key. Capabilities | Feature | Support | | ----------------- | ------- | | Agent model | Yes | | Text generation | Yes | | Streaming | Yes | | Structured output | Yes | | Hosted tools | Yes | | Embeddings | No | | Images | No | | Audio | No | Source: built on @ai-sdk/anthropic. --- ## Gemini URL: /docs/providers/gemini Use Google Gemini models and hosted tools. Gemini Install Agent model Configure Hosted tools Gemini hosted tools are available on gemini.tools. See Tools for local tools, client tools, approvals, MCP, and hosted provider tools. Direct generation Use generation models when a tool needs a focused model call without running an agent. Other generation helpers: Model types gemini("gemini-2.5-flash") is an agent model for defineAgent. Agent models need text for messages, tool decisions, and streaming. They can support more than text depending on the model. gemini.text(...), gemini.embedding(...), and the other helpers are generation models for direct calls from app code or tools. They do not run the agent loop. Provider options Pass Gemini options at run time with the google provider key. Capabilities | Feature | Support | | ----------------- | ------- | | Agent model | Yes | | Text generation | Yes | | Streaming | Yes | | Structured output | Yes | | Hosted tools | Yes | | Embeddings | Yes | | Images | Yes | | Video | Yes | | Audio | No | Source: built on @ai-sdk/google. --- ## Ollama URL: /docs/providers/ollama Run local models with Ollama. Ollama Install Agent model Configure Use createOllama when your Ollama server is not at the default location. Hosted tools Ollama does not expose hosted provider tools. Use Better Agent tools for server tools, client tools, approvals, and MCP. Direct generation Use generation models when a tool needs a focused local model call without running an agent. Other generation helpers: Model types ollama("llama3.2") is an agent model for defineAgent. Agent models need text for messages, tool decisions, and streaming. They can support more than text depending on the local model. ollama.text(...) and ollama.embedding(...) are generation models for direct calls from app code or tools. They do not run the agent loop. Provider options Pass Ollama provider options at run time with the ollama provider key. Pass model parameters, such as num_predict, when creating the model. Capabilities | Feature | Support | | ----------------- | ----------------- | | Agent model | Yes | | Text generation | Yes | | Streaming | Yes | | Structured output | Yes | | Hosted tools | No hosted tools | | Embeddings | Yes | | Images | No | | Audio | No | Source: built on ai-sdk-ollama. --- ## OpenAI URL: /docs/providers/openai Use OpenAI models and hosted tools. OpenAI Install Agent model Configure Use createOpenAI when you need custom provider settings. Hosted tools OpenAI hosted tools are available on openai.tools. See Tools for local tools, client tools, approvals, MCP, and hosted provider tools. Direct generation Use generation models when a tool needs a focused model call without running an agent. Other generation helpers: Model types openai("gpt-5.5") is an agent model for defineAgent. Agent models need text for messages, tool decisions, and streaming. They can support more than text depending on the model. openai.text(...), openai.embedding(...), and the other helpers are generation models for direct calls from app code or tools. They do not run the agent loop. Provider options Pass OpenAI options at run time with the openai provider key. Capabilities | Feature | Support | | ----------------- | ------- | | Agent model | Yes | | Text generation | Yes | | Streaming | Yes | | Structured output | Yes | | Hosted tools | Yes | | Embeddings | Yes | | Images | Yes | | Speech | Yes | | Transcription | Yes | Source: built on @ai-sdk/openai. --- ## OpenRouter URL: /docs/providers/openrouter Use OpenRouter models. OpenRouter Install Agent model Configure Use createOpenRouter for API keys, headers, or a custom OpenRouter-compatible base URL. Hosted tools OpenRouter does not expose a hosted tools helper on this provider wrapper. Use another provider wrapper when the agent needs tool calls. Direct generation Use generation models when a tool needs a focused model call without running an agent. Other generation helpers: Model types openrouter("openai/gpt-5.5") is an agent model for defineAgent. Agent models need text for messages and streaming. They can support more than text depending on the selected model. openrouter.text(...), openrouter.embedding(...), and the other helpers are generation models for direct calls from app code or tools. They do not run the agent loop. Provider options Pass OpenRouter options at run time with the openrouter provider key. Capabilities | Feature | Support | | ----------------- | ------------------- | | Agent model | Yes | | Text generation | Yes | | Streaming | Yes | | Structured output | No | | Tool calls | No | | Hosted tools | No wrapper helper | | Embeddings | Yes | | Images | Yes | | Audio | No | Source: built on @ai-sdk/openai-compatible. --- ## Workers AI URL: /docs/providers/workers-ai Use Cloudflare Workers AI models. Workers AI Install Agent model Configure the binding in Wrangler: Configure Inside Cloudflare Workers, the binding is recommended and needs no API key. Outside Workers, use API credentials from environment variables. Route calls through AI Gateway when you want Cloudflare caching, rate limits, or observability. Hosted tools Workers AI does not expose a hosted tools helper on this provider wrapper. Use Better Agent tools for server tools, client tools, approvals, and MCP. Direct generation Use generation models when a tool needs a focused model call without running an agent. Other generation helpers: Model types workersAI("@cf/moonshotai/kimi-k2.5") is an agent model for defineAgent. Agent models need text for messages, tool decisions, and streaming. They can support more than text depending on the model. workersAI.text(...), workersAI.embedding(...), and the other helpers are generation models for direct calls from app code or tools. They do not run the agent loop. Provider options Pass Workers AI options at run time with the workers-ai provider key. Capabilities | Feature | Support | | ----------------- | ----------------- | | Agent model | Yes | | Text generation | Yes | | Streaming | Yes | | Structured output | Yes | | Hosted tools | No wrapper helper | | Embeddings | Yes | | Images | Yes | | Speech | Yes | | Transcription | Yes | Source: built on workers-ai-provider. --- ## xAI URL: /docs/providers/xai Use xAI models and hosted tools. xAI Install Agent model Configure Hosted tools xAI hosted tools are available on xai.tools. See Tools for local tools, client tools, approvals, MCP, and hosted provider tools. Direct generation Use generation models when a tool needs a focused model call without running an agent. Other generation helpers: Model types xai("grok-4") is an agent model for defineAgent. Agent models need text for messages, tool decisions, and streaming. They can support more than text depending on the model. xai.text(...), xai.image(...), and xai.video(...) are generation models for direct calls from app code or tools. They do not run the agent loop. Provider options Pass xAI options at run time with the xai provider key. Capabilities | Feature | Support | | ----------------- | ------- | | Agent model | Yes | | Text generation | Yes | | Streaming | Yes | | Structured output | Yes | | Hosted tools | Yes | | Embeddings | No | | Images | Yes | | Video | Yes | | Audio | No | Source: built on @ai-sdk/xai. ---