Skip to content
Draft
36 changes: 20 additions & 16 deletions adk/conversations/custom-components.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
title: Use custom components
description: Build and render custom React UI inside webchat.
description: Build and render custom React UI inside Webchat.
---

Custom components let you render your own React UI inside webchat. Instead of being limited to text, images, and carousels, you can build any visual element and have either your code or the LLM send it to users.
Custom components let you render your own React UI inside [Webchat](/webchat/get-started/introduction). Instead of being limited to text, images, and carousels, you can build any visual element and have either your code or the LLM send it to users.

There are two ways to use them:
There are two ways to use custom components:

1. **Direct send** - your handler explicitly sends the component
2. **LLM-driven** - the LLM decides when to render the component during `execute()`
Expand Down Expand Up @@ -66,11 +66,12 @@ export const TicketCardComponent = new CustomComponent(component)

The component is now discoverable by `adk dev` and `adk deploy`. The component name is derived from the React function name (`TicketCard` in this case).

## Sending components directly

## Sending components manually

Send a custom component like any other message:

```typescript
```typescript highlight={7-18}
import { Conversation } from "@botpress/runtime"
import { TicketCardComponent } from "../components/TicketCard"

Expand Down Expand Up @@ -101,10 +102,9 @@ To let the LLM decide when to render your component, add LLM metadata and list i

### Add LLM metadata

The second argument to `CustomComponent` tells the LLM what the component does:
The `description` field tells the LLM what the component does:

```typescript
// src/components/TicketCard.ts
```typescript title="TicketCard.ts" highlight={5-6}
import { CustomComponent, z } from "@botpress/runtime"
import component from "./TicketCard.bp.tsx"

Expand All @@ -129,9 +129,11 @@ export const TicketCardComponent = new CustomComponent(component, {
| `props` | Yes | Zod schema defining the component's props. Use `.describe()` on each field. |
| `exampleValues` | Yes | Array of example prop objects. Converted to JSX examples in the LLM prompt. |

### List it in the conversation
### Provide the component to the LLM

```typescript
To provide the component to your agent's LLM, pass it into the `execute()` function's `components` field:

```typescript highlight={6}
import { Conversation } from "@botpress/runtime"
import { TicketCardComponent } from "../components/TicketCard"

Expand All @@ -149,7 +151,9 @@ export default new Conversation({

The LLM now knows about `<TicketCard>` and will render it when appropriate during `execute()`.

If you list a component in `components` that was created without LLM metadata, the Conversation constructor throws immediately.
<Note>
If you list a component in `components` that was created without LLM metadata, the `Conversation` constructor throws immediately.
</Note>

## Combining both approaches

Expand Down Expand Up @@ -184,11 +188,11 @@ export default new Conversation({

## Build pipeline

During `adk dev` and `adk deploy`, custom components go through this pipeline:
During `adk dev` and `adk deploy`, custom components go through the following pipeline:

1. **Discover** - scans `src/` for `.ts` files that export `CustomComponent` instances
2. **Resolve** - finds the `.bp.tsx` import in each wrapper
3. **Bundle** - esbuild bundles the `.bp.tsx` into standalone ESM (`react` and `react-dom` are externalized)
3. **Bundle** - `esbuild` bundles the `.bp.tsx` into standalone ESM (`react` and `react-dom` are externalized)
4. **Upload** - the bundle is uploaded to Botpress as a public file
5. **Wire** - the component URL is injected so `conversation.send()` works

Expand All @@ -205,7 +209,7 @@ During `adk dev`, the file watcher rebuilds only changed components incrementall

## Limitations

- **Webchat only.** Custom components only render in the Botpress webchat widget. Other channels don't support them.
- **Webchat only.** Custom components only render in Webchat. Other channels don't support them.
- **No global stylesheets.** You can import `.css` files in your component, but your project's global styles are not available.
- **React 18.** React 19 features are not available.
- **No server-side rendering.** Components are client-rendered in the browser.
Expand All @@ -215,8 +219,8 @@ During `adk dev`, the file watcher rebuilds only changed components incrementall
| Problem | Cause | Fix |
|---------|-------|-----|
| `Component "X" not deployed. Run "adk deploy".` | Component URL not set | Re-run `adk dev` to build and upload |
| Component doesn't appear in webchat | Wrapper doesn't export a `CustomComponent` | Check the `.ts` file imports the `.bp.tsx` and exports `new CustomComponent(...)` |
| Component doesn't appear in Webchat | Wrapper doesn't export a `CustomComponent` | Check the `.ts` file imports the `.bp.tsx` and exports `new CustomComponent(...)` |
| LLM never uses the component | Missing metadata or not in `components` array | Add `{ description, props, exampleValues }` and list in `components` |
| Styles look wrong | Using CSS classes | Switch to inline styles |
| A prop is `undefined` | Reserved prop name (e.g., `status`) | Rename to something specific (e.g., `ticketStatus`) |
| TypeScript errors on `.bp.tsx` | Missing tsconfig settings | Add `"jsx": "react"`, `"allowImportingTsExtensions": true`, and `"noEmit": true` |
| TypeScript errors on `.bp.tsx` | Missing `tsconfig` settings | Add `"jsx": "react"`, `"allowImportingTsExtensions": true`, and `"noEmit": true` |
8 changes: 4 additions & 4 deletions adk/conversations/lifecycle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Lifecycle management adds idle nudges and session expiration to your conversatio

Add a `lifecycle` prop to your conversation:

```typescript
```typescript highlight={10-13}
import { Conversation } from "@botpress/runtime"
import { z } from "@botpress/sdk"

Expand Down Expand Up @@ -77,7 +77,7 @@ A session is a single period of activity within a conversation. One conversation
| `lastActivityAt` | `string` | ISO timestamp of the last user message. |
| `nudgeCount` | `number` | How many nudges have fired in this session. Resets on new activity and on session renewal. |

Access it via `conversation.session`:
You can access the current session via `conversation.session`:

```typescript
const session = props.conversation.session
Expand All @@ -87,7 +87,7 @@ if (session) {
}
```

The session object is read-only. It returns `undefined` for conversations without lifecycle configured.
The `session` object is read-only. It returns `undefined` for conversations without lifecycle configured.

## What happens when a conversation expires

Expand All @@ -112,7 +112,7 @@ Lifecycle durations use `ms`-compatible strings:
| `'24h'` | 24 hours |
| `'2d'` | 2 days |

Durations are validated at construction time. Invalid or non-positive values throw immediately.
Durations are validated at construction time. Invalid or non-positive values throw an error immediately.

## Common patterns

Expand Down
8 changes: 5 additions & 3 deletions adk/conversations/messages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ await conversation.send({

## Message types

The available message types depend on the channel. For webchat, the following types are supported:
The available message types depend on which channel your agent is deployed on. For [Webchat](/webchat/get-started/introduction), the following types are supported:

| Type | Payload | Description |
|------|---------|-------------|
Expand All @@ -35,7 +35,7 @@ The available message types depend on the channel. For webchat, the following ty
| `custom` | `{ url, name, data? }` | Raw custom message referencing a bundled component by URL |
| `customComponent` | `{ component, props }` | Send a [custom component](/adk/conversations/custom-components) directly. The runtime rewrites this into a `custom` message under the hood, so you get type-checked props instead of a raw URL |

Other channels (Slack, WhatsApp, Telegram) support different subsets. When you specify a channel on your conversation, TypeScript will only allow the message types that channel supports.
Other channels (Slack, WhatsApp, Telegram) may support different message types. When you specify a channel on your conversation, TypeScript will only allow the message types that channel supports.

## Examples

Expand Down Expand Up @@ -129,7 +129,9 @@ conversation.tags.priority = "high"
conversation.tags.category = "billing"
```

Tags must be declared in `agent.config.ts` under `conversation.tags`. See [Agent Configuration](/adk/setup/configuration#tags).
<Note>
Tags must be declared in `agent.config.ts` under `conversation.tags`. Check out our guide to [configuration your agent](/adk/setup/configuration#tags) for more information.
</Note>

## Loading a conversation by ID

Expand Down
24 changes: 12 additions & 12 deletions adk/conversations/state.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Manage states
title: Manage state
description: Store and reuse data across conversations, users, and the entire bot.
---

Expand All @@ -17,9 +17,9 @@ State lets your agent persist data between handler calls. The ADK provides three

### Bot and user state

Define these in `agent.config.ts`:
Define bot and user state in `agent.config.ts`:

```typescript
```typescript highlight={6-10, 12-18}
import { z, defineConfig } from "@botpress/runtime"

export default defineConfig({
Expand All @@ -45,9 +45,9 @@ Use `.default()` to set initial values and `.describe()` to document what each f

### Conversation state

Defined on each conversation using the `state` prop:
Define conversation state on a `Conversation` using the `state` prop:

```typescript
```typescript highlight={5-8}
import { Conversation, z } from "@botpress/runtime"

export default new Conversation({
Expand All @@ -68,11 +68,11 @@ export default new Conversation({

## Reading and writing state

State changes are saved automatically. You don't need to call a save method.
State objects are mutable and can be modified directly. Your changes are saved automatically—you don't need to call a save method.

### Bot state
## Bot state

Available anywhere in your agent (conversations, actions, tools, workflows):
You can access bot state anywhere in your agent (conversations, actions, tools, workflows):

```typescript
import { bot } from "@botpress/runtime"
Expand All @@ -83,7 +83,7 @@ bot.state.ticketCounter = counter + 1

### User state

Available anywhere the current user context exists:
You can access user state anywhere the current user context exists:

```typescript
import { user } from "@botpress/runtime"
Expand All @@ -94,7 +94,7 @@ user.state.visitCount = (user.state.visitCount || 0) + 1

### Conversation state

Accessed via the `state` parameter in the handler:
You can access conversation state via the `state` parameter in the conversation handler:

```typescript
handler: async ({ state, execute }) => {
Expand Down Expand Up @@ -151,7 +151,7 @@ export default new Conversation({

## Tags

Tags are string key-value pairs you can attach to bots, users, conversations, messages, and workflows. They are useful for categorization, filtering, and querying.
Tags are string key-value pairs you can attach to bots, users, conversations, messages, and workflows. They're useful for categorization, filtering, and querying.

### Defining tags

Expand Down Expand Up @@ -190,7 +190,7 @@ bot.tags.environment = "production"
user.tags.role = "admin"
```

Conversation tags are accessed via the conversation instance:
You can access conversation tags via the `conversation` instance:

```typescript
handler: async ({ conversation }) => {
Expand Down
4 changes: 3 additions & 1 deletion adk/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ title: Introduction to the ADK
description: TypeScript framework for building AI agents on Botpress.
---

The Agent Development Kit (ADK) is a **CLI tool and development framework for building AI agents on Botpress**. Write your agent as TypeScript: conversations, workflows, tools, and actions all live as code, with hot reload and type-safe APIs. Botpress handles hosting, scaling, and channel delivery.
The Agent Development Kit (ADK) is a **CLI tool and development framework for building AI agents on Botpress**. It provides a streamlined development experience with TypeScript support, hot reloading, and type-safe APIs for creating AI applications.

You write conversations, workflows, tools, and actions as code. Botpress handles hosting, scaling, and channel delivery.

<Frame>
<img alt="Botpress ADK" className="block dark:hidden" src="./assets/welcome.png" />
Expand Down
20 changes: 19 additions & 1 deletion adk/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ By the end of this guide, you'll have a working AI agent that responds to messag

* A [Botpress account](https://sso.botpress.cloud)
* [Node.js](https://nodejs.org/en) (v22.0.0 or higher)
* A supported package manager: [bun](https://bun.sh), [pnpm](https://pnpm.io), [yarn](https://yarnpkg.com), or [npm](https://www.npmjs.com)
* A supported package manager[bun](https://bun.sh), [pnpm](https://pnpm.io), [yarn](https://yarnpkg.com) or [npm](https://www.npmjs.com)
</Info>

## Installation
Expand Down Expand Up @@ -65,6 +65,8 @@ cd my-agent

## Test your agent

Now, you’re ready to test your agent.

### Start the development server

Start the development server with hot reloading:
Expand Down Expand Up @@ -95,6 +97,22 @@ Go to the **Chat** page and send a message to test your agent:

The dev server watches your files and rebuilds on every change.

### Chat in the terminal

Alternatively, open a new terminal window and start a conversation with your agent from the command line:

```bash
adk chat
```

```txt
Botpress Chat
Type "exit" or press ESC key to quit
👤 Hey!
🤖 Hello! How can I assist you today?
>>
```

## Deploy your agent

When you're ready to go live:
Expand Down
59 changes: 46 additions & 13 deletions adk/setup/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,52 @@ description: Understand your project structure and how to configure your agent.

## Project structure

After running `adk init`, these are the core files and folders of an ADK project:

| Path | Purpose |
|------|---------|
| `agent.config.ts` | Agent configuration: models, state, dependencies, secrets |
| `src/conversations/` | Message handlers for user interactions |
| `src/workflows/` | Long-running background processes |
| `src/actions/` | Reusable logic callable from anywhere |
| `src/tools/` | Functions the AI model can call |
| `src/tables/` | Database table schemas |
| `src/knowledge/` | RAG knowledge base sources |
| `src/triggers/` | Event-based handlers |
| `evals/` | Automated conversation tests |
Here's a breakdown of the key files in your project after running `adk init`:

<Tree>
<Tree.Folder name="src" defaultOpen>
<Tree.Folder name="actions">
<Tree.File name="index.ts" />
</Tree.Folder>

<Tree.Folder name="conversations">
<Tree.File name="index.ts" />
</Tree.Folder>

<Tree.Folder name="evals">
<Tree.File name="index.ts" />
</Tree.Folder>

<Tree.Folder name="knowledge">
<Tree.File name="index.ts" />
</Tree.Folder>

<Tree.Folder name="tables">
<Tree.File name="index.ts" />
</Tree.Folder>

<Tree.Folder name="triggers">
<Tree.File name="index.ts" />
</Tree.Folder>

<Tree.Folder name="workflows">
<Tree.File name="index.ts" />
</Tree.Folder>
</Tree.Folder>

<Tree.File name=".mcp.json" />

<Tree.File name="agent.config.ts" />

<Tree.File name="agent.json" />

<Tree.File name="agent.local.json" />

<Tree.File name="AGENTS.md" />

<Tree.File name="CLAUDE.md" />

</Tree>

The ADK scans `src/` and discovers primitives automatically. Each file exports a primitive (a `Conversation`, `Workflow`, `Action`, etc.) and the framework registers it at build time.

Expand Down
Loading
Loading