Run from code
The openbot program covers most needs. When you need more, you can start OpenBot from your own program.
Then you can add your own models, tools, routes, and App Index sources.
OpenBot is built with Effect. You build it from Layers. A Layer is an Effect recipe that builds services. Making a Layer does not open the network or the database. That happens when you launch it.
The smallest program
This program does the same as openbot:
import { NodeRuntime } from "@effect/platform-node"import { EnvironmentConfiguration, Server } from "@openbot-build/openbot"import { Effect, Layer } from "effect"import { FetchHttpClient } from "effect/http"
NodeRuntime.runMain( Effect.gen(function* () { const settings = yield* EnvironmentConfiguration.load return yield* Layer.launch( Server.layer(settings).pipe(Layer.provide(FetchHttpClient.layer)), ) }),)EnvironmentConfiguration.load reads the variables in Configuration. It returns host, port, databaseUrl, secretKeys, and tls.
You can also write these values in code.
The program still needs a platform. Run the setup program once before people use it. See Platform.
What the package exports
| Export | What it is |
|---|---|
Server.layer(options) |
OpenBot with its own Node.js HTTP or HTTPS server. It reads sign-in from the platform settings. |
Server.layerFixed(options) |
OpenBot with one fixed sign-in configuration. For tests and the development server. |
Server.layerApi(options) |
Only the HTTP routes, for an HTTP server that you already have. |
OpenBot.layerShared(options) |
The services that live as long as the instance: the database pool, the secret keys, and the shared settings. |
OpenBot.layer(options) |
The services behind the routes: sign-in, tokens, permissions, storage, Sessions, and Apps. |
DatabasePostgres |
The database Layer and the migrate program. |
EnvironmentConfiguration |
Reads the instance settings from environment variables. |
Auth, Sessions, AppHost, AppPlugin, Configuration |
Service types for advanced setups. |
Options
Server.layer takes instance options and app options.
Instance options
| Option | Type | What it is |
|---|---|---|
host |
string |
Required. The address to listen on, such as 127.0.0.1. |
port |
number |
Required. The port to listen on, such as 3000. |
databaseUrl |
Redacted<string> |
Required. The PostgreSQL URL. |
secretKeys |
Redacted<string> |
Required. The secret key list. See Secret keys. |
tls |
object | Optional. { certFile, keyFile } paths to PEM files. OpenBot then serves HTTPS itself. |
Sign-in
Server.layer takes no sign-in options. It reads the public origin, the platform provider, and the sign-in secret from the platform settings.
- Before setup, every route except
/healthanswers503withSetupRequired. - When one of these settings changes, the server builds a new app with the new values. The new app takes requests first, and then the old app stops.
Server.layerFixed serves one fixed auth configuration instead, and never builds a new app. It also gives the app services to your program, so tests can use them. When the database has no platform settings, it writes them first, for the publicOrigin of auth. Tests and the development server use it.
App options
| Option | What it does |
|---|---|
sessions |
Tools and memory for Sessions. See below. |
builtinModels |
Models that every organization can use, given in code. See Models. |
routes |
A function that gets the sign-in configuration and returns a Layer with your own HTTP routes. |
discovery |
A Layer that finds Apps on the web. The default reads public Catalogs over the internet. |
indexSources |
More sources for the App Index search, next to the OpenBot Index. |
indexWork |
Timing of the App Index worker: { intervalMs, retryMs }. |
Some values were options before. They are settings in the database now, so every instance shares them:
| Old option | Setting |
|---|---|
appRestrictions |
appRestrictions in the platform settings. |
appReadRules |
appReadRules in the organization settings. |
agents.helperModel |
helperModel in the organization settings. |
agents.requestTimeout |
requestTimeoutMs in the organization settings. |
agents.memory |
agentMemory in the organization settings. |
appEncryptionKey |
The secretKeys instance option. |
Sessions
The sessions option sets how Sessions do their work.
| Field | What it does |
|---|---|
runtime |
The Agent definition: toolkit, plugin, providers, compaction, and more. |
layerExecution |
A function that builds extra services for each Turn, such as tool handlers. |
memory |
Learned memory: your own model and policy. |
Models come from the model providers in the database and from builtinModels. See Models.
The memory switches of a new Session come from memory in the organization settings. See Memory.
Add a tool
A tool is a function that the model can call. Make it with Effect AI, then give the toolkit and its handlers to OpenBot:
import { type Configuration, Server } from "@openbot-build/openbot"import { Effect, Layer, Schema } from "effect"import { Tool, Toolkit } from "effect/ai"
const CurrentTime = Tool.make("CurrentTime", { description: "Returns the current time on the server.", parameters: Schema.Struct({}), success: Schema.String,})const toolkit = Toolkit.make(CurrentTime)const handlers = toolkit.toLayer({ CurrentTime: () => Effect.sync(() => new Date().toISOString()),})
const server = (settings: Configuration.Settings) => Server.layer({ ...settings, sessions: { runtime: { toolkit }, layerExecution: () => handlers, }, }).pipe(Layer.provide(handlers))Add needsApproval: true to Tool.make when each call needs a decision. OpenBot then makes a tools.call request for it. See Requests.
Your own routes
routes adds HTTP routes to the same server. It is a function that gets the current sign-in configuration and returns a Layer. The Layer can use the Auth service to check the sign-in cookie.
import { HttpRouter, HttpServerResponse } from "effect/http"
const routes = HttpRouter.add( "GET", "/status", HttpServerResponse.text("ready"),)
Server.layer({ ...settings, routes: () => routes })Do not use paths under /auth/ or /v1/. OpenBot owns them.
Use your own HTTP server
Server.layerApp(options) returns a function. It gets one sign-in configuration and returns the OpenBot routes and services for it.
Server.layerApi({ publicOrigin }) gives only the OpenBot routes. It also adds error logging for failed requests.
Server.layer and Server.layerFixed start their own Node.js server.
To put OpenBot inside a server that you already have, build the same parts yourself. Read packages/openbot/src/app/Server.ts for how layerFixed serves one configuration, and packages/openbot/src/app/Supervisor.ts for how Server.layer builds a new app when the platform settings change.
Keep the sign-in secret in the platform settings, not in your own environment variable. Every instance must use the same one.
Migrate the database
DatabasePostgres.migrate applies the migrations. OpenBot.layerShared only checks that the tables exist, and fails if they do not.
Run migrations in their own program before you start the server:
import { NodeRuntime, NodeServices } from "@effect/platform-node"import { DatabasePostgres } from "@openbot-build/openbot"import { Config, Effect, Layer } from "effect"
NodeRuntime.runMain( DatabasePostgres.migrate.pipe( Effect.provide( Layer.unwrap( Effect.map(Config.Redacted("OPENBOT_DATABASE_URL"), (databaseUrl) => DatabasePostgres.layer({ databaseUrl }), ), ).pipe(Layer.provide(NodeServices.layer)), ), ),)Send error logs to your own service
OpenBot writes failures as error logs. Add your own Effect logger to send them to another service. See Error logs for what each log contains and a full example.