UNPKG

@botpress/adk-cli

Version:

Command-line interface for the Botpress Agent Development Kit (ADK)

495 lines (379 loc) 12.8 kB
# Configuration Configure your bot's behavior, integration aliases, and global state through the unified `agent.config.ts` file. Installed integration and plugin state is managed through Botpress Cloud dependency snapshots, not through `agent.config.ts`. ## agent.config.ts The main configuration file defines your bot's core settings, AI models, integration aliases, and state schemas. ### Configuration Example ```typescript import { defineConfig, z } from '@botpress/runtime' export default defineConfig({ name: 'customer-support-bot', description: 'Customer support assistant with knowledge base', // AI Model Configuration defaultModels: { autonomous: 'openai:gpt-4o', // For execute() function zai: 'openai:gpt-4o-mini', // For zai operations }, // User State Schema user: { state: z.object({ preferredLanguage: z.enum(['en', 'es', 'fr', 'de']).default('en'), timezone: z.string().default('UTC'), name: z.string().optional(), email: z.string().email().optional(), notificationsEnabled: z.boolean().default(true), accountTier: z.enum(['free', 'pro', 'enterprise']).default('free'), metadata: z.object({}).passthrough().default({}), }), }, // Bot Global State Schema bot: { state: z.object({ version: z.number().default(1), maintenanceMode: z.boolean().default(false), // Feature flags features: z .object({ advancedSearch: z.boolean().default(false), multiLanguage: z.boolean().default(true), }) .default({}), // Analytics totalConversations: z.number().default(0), totalUsers: z.number().default(0), }), }, secrets: { OPENAI_API_KEY: { description: 'OpenAI API key used by custom model calls', }, OPTIONAL_WEBHOOK_SECRET: { optional: true, description: 'Shared secret for optional webhook verification', }, }, // Cloud is the source of truth; .adk/dependencies/ stores generated snapshots. // Use `adk integrations add/remove/configure` to manage them — see integrations.md }) ``` ### Additional Configuration Fields #### Tags Tags are key-value pairs for categorizing entities. All entities (`user`, `bot`, `conversation`, `message`, `workflow`) support tags. See **[Tags](./tags.md)** for complete documentation. #### Bot Configuration Schema Define a custom configuration schema for bot-level settings accessible via the Context API: ```typescript export default defineConfig({ name: 'my-bot', configuration: { schema: z.object({ maxRetries: z.number().default(3), apiEndpoint: z.string(), featureFlags: z.object({ enableBetaFeatures: z.boolean().default(false), }), }), }, }) ``` Access via direct import from `@botpress/runtime`: ```typescript import { configuration } from '@botpress/runtime' if (configuration.featureFlags.enableBetaFeatures) { // Use beta features } ``` See **[Context API](./context-api.md)** for details on accessing other runtime values. #### Secrets Declare secret names in `agent.config.ts`, then read values at runtime with the typed `secrets` proxy: ```typescript import { secrets } from '@botpress/runtime' const apiKey = secrets.OPENAI_API_KEY ``` Secret names must be `SCREAMING_SNAKE_CASE` and cannot use reserved prefixes such as `SECRET_`, `BP_`, or `BOTPRESS_`. Values are set separately with `adk secret:set <KEY> <value>` for dev or `adk secret:set <KEY> <value> --prod` for prod. Dev values live in `.adk/secrets.json`. Prod values live on the remote bot and are write-only; ADK can show set/unset status, but cannot read values back. ### Model Configuration **Default Models:** If you don't specify `defaultModels`, the ADK uses these defaults: - `zai`: `"openai:gpt-4.1-2025-04-14"` - `autonomous`: `"openai:gpt-4.1-mini-2025-04-14"` **Available Models:** ```typescript // OpenAI 'openai:gpt-4o' 'openai:gpt-4o-mini' 'openai:gpt-4-turbo' 'openai:gpt-4.1-2025-04-14' 'openai:gpt-4.1-mini-2025-04-14' // Anthropic 'anthropic:claude-3-5-sonnet' 'anthropic:claude-3-opus' 'anthropic:claude-3-haiku' // Google 'google:gemini-1.5-pro' 'google:gemini-1.5-flash' ``` **Model Fallback Arrays:** You can specify multiple models as fallbacks: ```typescript defaultModels: { autonomous: [ "openai:gpt-4o", "anthropic:claude-3-5-sonnet", "openai:gpt-4o-mini" ], zai: "openai:gpt-4o-mini" } ``` ### Accessing Configuration ```typescript import { bot, user } from '@botpress/runtime' // In any handler (action, workflow, conversation) // Access bot state const version = bot.state.version const maintenanceMode = bot.state.maintenanceMode // Modify bot state bot.state.totalConversations += 1 bot.state.features.advancedSearch = true // Access user state const language = user.state.preferredLanguage const tier = user.state.accountTier // Modify user state user.state.lastActiveDate = new Date() user.state.metadata.lastQuery = 'product pricing' ``` ## Dependencies (Integrations, Plugins, Interfaces) Integration and plugin state lives in Botpress Cloud, not in `agent.config.ts`. The ADK writes generated per-environment snapshots under `.adk/dependencies/` for fast/offline reads: - `.adk/dependencies/dev.json` — development environment snapshot - `.adk/dependencies/prod.json` — production environment snapshot - `.adk/dependencies/migration.json` — one-way legacy migration marker Cloud is the source of truth. Snapshots are refreshed after dependency mutations and Cloud reads. Never edit dependency snapshots by hand. > **Migration:** Projects with a legacy `dependencies` block in `agent.config.ts` or legacy `dependencies.<env>.lock.json` files are auto-migrated on the first CLI command. If the target Cloud bot has no dependency state, legacy state is imported to Cloud automatically, including prod. The migration is one-shot and is skipped whenever `.adk/dependencies/migration.json` exists; the marker contents are informational, so even a corrupt marker still counts as migrated. Use `adk dependencies export` / `adk dependencies import` only for explicit dependency-only backup or transfer artifacts. These JSON files are not the generated local snapshots and should not become a new source of truth. ### Managing Dependencies Use the `adk integrations` CLI subcommands. See **[CLI Reference](./cli.md)** and **[Integrations](./integrations.md)** for full details: ```bash adk integrations search <query> # Search for integrations adk integrations add <name>@<version> # Add integration adk integrations configure <alias> --set key=value # Configure adk integrations enable <alias> # Enable adk integrations remove <alias> # Remove adk integrations upgrade <alias> # Upgrade adk integrations list # List installed adk integrations status # Show availability/remediation ``` ### Using Integration Actions See **[Integration Actions](./integration-actions.md)** for calling integration functionality from your code. ## Environment Variables ### .env File ```bash # Bot Configuration BOT_NAME=customer-support-bot NODE_ENV=development # API Keys OPENAI_API_KEY=sk-... ANTHROPIC_API_KEY=sk-ant-... # Integration Tokens SLACK_BOT_TOKEN=xoxb-... LINEAR_API_KEY=lin_api_... # ADK Development (CLI-specific) ADK_DEV_PORT=3000 # Bot port (default: 3000) ADK_CONSOLE_PORT=3001 # UI console port (default: 3001) DEBUG=adk:* # Enable ADK debug logs # Feature Flags (optional) ENABLE_ADVANCED_SEARCH=true # External Services (optional) WEBHOOK_URL=https://api.example.com/webhooks ``` ### Accessing Environment Variables ```typescript // In configuration export default defineConfig({ name: process.env.BOT_NAME || 'my-bot', defaultModels: { autonomous: process.env.AI_MODEL || 'openai:gpt-4o', }, }) // In handlers export const myAction = new Action({ async handler({ input }) { const apiKey = process.env.EXTERNAL_API_KEY if (!apiKey) { throw new Error('EXTERNAL_API_KEY not configured') } // Use the API key const response = await fetch('https://api.example.com', { headers: { Authorization: `Bearer ${apiKey}` }, }) }, }) ``` ## State Management Patterns ### User State Patterns ```typescript // Progressive profile building export const Chat = new Conversation({ async handler({ message, conversation, execute }) { // Collect user info progressively if (!user.state.name && message?.type === 'text') { user.state.name = extractName(message.payload.text) } if (!user.state.email) { // Ask for email if needed await conversation.send({ type: 'text', payload: { text: "What's your email address?" }, }) } // Use preferences const language = user.state.preferredLanguage await execute({ instructions: `Respond in ${language}`, }) }, }) ``` ### Bot State Patterns ```typescript export const Chat = new Conversation({ async handler({ conversation }) { // Feature flag checking if (bot.state.features.advancedSearch) { // Use advanced search const results = await advancedSearch(query) } else { // Use basic search const results = await basicSearch(query) } // Maintenance mode if (bot.state.maintenanceMode) { await conversation.send({ type: 'text', payload: { text: 'The bot is currently under maintenance. Please try again later.', }, }) return } // Business hours check (example) const supportHours = '9:00 AM to 5:00 PM EST' await conversation.send({ type: 'text', payload: { text: `Our support hours are ${supportHours}` }, }) }, }) ``` ## Best Practices ### 1. Use Declared Secrets for Runtime Credentials ```typescript // ❌ Bad - hardcoded secrets config: { apiKey: 'sk-abc123def456' } // ✅ Good - declared in agent.config.ts secrets: { OPENAI_API_KEY: { description: 'OpenAI API key' } } // ✅ Good - read in runtime code import { secrets } from '@botpress/runtime' const apiKey = secrets.OPENAI_API_KEY ``` Use `${env:VAR_NAME}` only for integration or plugin configuration values that the CLI applies to Cloud. For credentials read by bot code, declare a secret and access it through `secrets.KEY`. ### 2. Validate Configuration ```typescript export default defineConfig({ name: validateBotName(process.env.BOT_NAME), user: { state: z.object({ // Use strict validation email: z.string().email(), age: z.number().int().min(0).max(150), }), }, }) ``` ### 3. Provide Defaults ```typescript user: { state: z.object({ // Always provide sensible defaults language: z.string().default('en'), notifications: z.boolean().default(true), theme: z.enum(['light', 'dark']).default('light'), }) } ``` ### 4. Document State Schema ```typescript bot: { state: z.object({ /** * Current version of the bot configuration * Increment when making breaking changes */ version: z.number().default(1), /** * Feature flags for gradual rollout * @example { "newUI": true, "betaFeatures": false } */ features: z.record(z.boolean()).default({}), }) } ``` ### 5. Separate Concerns ```typescript // Separate configuration by domain const userConfig = { state: userStateSchema, } const botConfig = { state: botStateSchema, } const integrationConfig = { slack: slackConfig, discord: discordConfig, } export default defineConfig({ ...baseConfig, user: userConfig, bot: botConfig, }) ``` ## Project Files ### agent.json The `agent.json` file stores the shared production bot and workspace IDs for deployment. This file is created by `adk link`. ```json { "botId": "bot_abc123", "workspaceId": "ws_xyz789" } ``` **Fields:** - `botId` - Production bot ID (used by `adk deploy`) - `workspaceId` - Workspace ID The development bot ID is stored in `agent.local.json`: ```json { "devId": "bot_dev_123" } ``` **Important:** - Add `agent.json` to `.gitignore` if you do not want environment-specific IDs committed - Each developer/environment can have a different local `devId` - `agent.json` is created by `adk link`; `agent.local.json` is written by local dev flows - Current scaffolds do not add `agent.json` to `.gitignore` automatically ### package.json Standard Node.js package file with ADK-specific scripts. ```json { "scripts": { "dev": "adk dev", "build": "adk build", "deploy": "adk deploy" }, "dependencies": { "@botpress/runtime": "workspace:*" } } ``` See **[CLI Reference](./cli.md)** for complete command documentation.