Skip to content

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 /health answers 503 with SetupRequired.
  • 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.