# simpleChatbot (/docs/recipes/simple-chatbot)



`simpleChatbot` is the smallest recipe in the package. It composes
only `@pleach/core` and returns a `Chatbot` wrapper around a real
`SessionRuntime`. The factory does not bundle a provider — you
register an `OrchestratorAdapter` ctor once at app boot and the
recipe forwards your `orchestratorConfig` through.

Best fit: **a SaaS adding chat**. Reach for this when you
want a working chatbot in under ten lines and don't yet need
retrieval, observability, or compliance scrubbing.

## Quickstart [#quickstart]

```ts
import { simpleChatbot } from "@pleach/recipes/chatbot";
import { setOrchestratorAdapterCtor } from "@pleach/core/runtime";
import { MyOrchestratorAdapter } from "./my-provider";

// Register the OrchestratorAdapter ctor once at app boot.
setOrchestratorAdapterCtor(MyOrchestratorAdapter);

const bot = simpleChatbot({
  systemPrompt: "You are a helpful assistant.",
  orchestratorConfig: {
    provider: "openai",
    model: "gpt-4o-mini",
    apiKey: process.env.OPENAI_API_KEY!,
  },
});

console.log(await bot.ask("hello"));
console.log(await bot.ask("what did I just say?"));
```

A single `bot` instance holds the session across `ask()` calls,
so the second turn sees the first turn's history. Call
`await bot.reset()` (or its alias `await bot.newSession()`) to
discard the memoized session id; the next `ask()` lazily
creates a fresh one.

## What it does [#what-it-does]

The factory constructs a `SessionRuntime` via
`createPleachRuntime(...)` and stores the
`orchestratorConfig` on `host.strategies.orchestratorConfig`.
On the first `ask()`, the runtime walks the registered adapter
ctor and binds your provider. Each subsequent `ask()` reuses
the same session id, so conversation state accumulates in the
underlying event log.

`ask()` returns the final assistant text. It collects the
`message.delta` and `message.complete` events from
`runtime.executeMessage()` and concatenates the deltas.
Streaming consumers should reach into `bot.runtime` directly.

## Config reference [#config-reference]

```ts
interface SimpleChatbotConfig {
  /** Optional system prompt prepended to every conversation. */
  systemPrompt?: string;
  /**
   * Provider/orchestrator config forwarded to the underlying
   * SessionRuntime. Wires the LLM provider (model id, API key,
   * etc.). When omitted, ask() returns the substrate placeholder.
   */
  orchestratorConfig?: Record<string, unknown>;
  // Plus the standard CreatePleachRuntimeConfig fields
  // (host, plugins, storage, etc.) from @pleach/core.
}

interface Chatbot {
  readonly runtime: SessionRuntime;
  ask(message: string): Promise<string>;
  newSession(): Promise<void>;
  reset(): Promise<void>;
}
```

## Common gotchas [#common-gotchas]

* **`setOrchestratorAdapterCtor` runs once per process.** It
  registers a module-level ctor inside
  `@pleach/core/runtime`. Call it at app boot, before any
  `simpleChatbot({orchestratorConfig: ...})`. Calling it again
  with a different ctor is a no-op after the first
  registration in v0.2.
* **Without `orchestratorConfig`, `ask()` returns a placeholder.**
  The string is `"This is a placeholder response from the
  harness runtime."` This is the documented no-provider
  contract — useful for shape tests, not for production.
* **`ChatStreamError` carries the original failure on `.cause`.**
  If the stream emits `{type: "error"}` or throws, `ask()`
  rejects with `ChatStreamError`. Branch on `error.cause` to
  distinguish provider errors from abort signals from network
  timeouts.
* **Subpath import is load-bearing.** Import from
  `@pleach/recipes/chatbot`, not the root barrel. The factory
  references `createPleachRuntime` from `@pleach/core/runtime`
  (the subpath the setter is also registered against). The
  top-level `@pleach/core` ESM bundle does not currently
  re-export the setter.

## See also [#see-also]

* [`@pleach/recipes` overview](/docs/recipes-pleach-recipes) —
  every recipe in one page.
* [`SessionRuntime`](/docs/session-runtime) — the substrate
  every recipe wraps.
* [`Adoption paths`](/docs/adoption-paths) — when to reach for
  `simpleChatbot` vs construct `SessionRuntime` directly.
