diff --git a/.vale/styles/config/ignore/ignore.txt b/.vale/styles/config/ignore/ignore.txt index 99e22cce..b5c87aa2 100644 --- a/.vale/styles/config/ignore/ignore.txt +++ b/.vale/styles/config/ignore/ignore.txt @@ -36,4 +36,6 @@ dev lookups micropatch recrawling -resync \ No newline at end of file +resync +deduplication +monorepos \ No newline at end of file diff --git a/docs.json b/docs.json index 723e62ad..7ade69a3 100644 --- a/docs.json +++ b/docs.json @@ -403,7 +403,13 @@ "group": "Concepts", "pages": [ "for-developers/adk/concepts/conversations", - "for-developers/adk/concepts/workflows", + { + "group": "Workflows", + "pages": [ + "for-developers/adk/concepts/workflows/overview", + "for-developers/adk/concepts/workflows/steps" + ] + }, "for-developers/adk/concepts/actions", "for-developers/adk/concepts/tables", "for-developers/adk/concepts/triggers", diff --git a/for-developers/adk/cli-reference.mdx b/for-developers/adk/cli-reference.mdx index dfcc0951..b2e0abbe 100644 --- a/for-developers/adk/cli-reference.mdx +++ b/for-developers/adk/cli-reference.mdx @@ -92,6 +92,7 @@ adk deploy --env production | Flag | Description | Default | |------|-------------|---------| | `-e, --env` | Deployment environment | `production` | +| `-y, --yes` | Auto-approve preflight changes without prompting | `false` | --- @@ -139,6 +140,46 @@ Run `adk dev` first to create a development bot if you don't have a `devId` in y --- +### `adk mcp` + +Start an MCP (Model Context Protocol) server for AI assistant integration. This allows AI coding assistants like Claude Code and Cursor to interact with your ADK agent. + +**Usage:** +```bash +adk mcp +adk mcp --cwd ./my-agent +``` + +**Flags:** + +| Flag | Description | +|------|-------------| +| `--cwd` | Working directory for MCP operations | + +#### `adk mcp:init` + +Generate MCP configuration files for AI assistants. + +**Usage:** +```bash +adk mcp:init --tool cursor +adk mcp:init --tool claude-code --tool vscode +adk mcp:init --all +adk mcp:init --all --force +adk mcp:init --tool cursor --project-dir ./bot +``` + +**Flags:** + +| Flag | Description | +|------|-------------| +| `--tool` | Specific tool(s) to configure: `claude-code`, `vscode`, `cursor` | +| `--all` | Generate configuration for all supported tools | +| `--force` | Overwrite existing ADK configuration | +| `--project-dir` | ADK project subdirectory (for monorepos, e.g., `./bot`) | + +--- + ### `adk login` Authenticate with your Botpress account. @@ -325,6 +366,8 @@ adk link --workspace --bot --dev | `--workspace` | Workspace ID | | `--bot` | Bot ID to link to | | `--dev` | Dev bot ID (optional) | +| `--api-url` | Botpress API URL (e.g., `https://api.botpress.cloud`) | +| `-f, --force` | Overwrite existing `agent.json` if present | --- @@ -403,6 +446,122 @@ adk assets pull --- +### `adk config` + +Configure agent settings interactively or manage specific configuration values. + +**Usage:** +```bash +adk config +adk config --prod +``` + +**Flags:** + +| Flag | Description | +|------|-------------| +| `--prod` | Use production configuration | + +#### `adk config:get` + +Get a specific configuration value. + +**Usage:** +```bash +adk config:get +adk config:get myKey --prod +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `key` | Configuration key to retrieve | + +**Flags:** + +| Flag | Description | +|------|-------------| +| `--prod` | Use production configuration | + +#### `adk config:set` + +Set a specific configuration value. + +**Usage:** +```bash +adk config:set +adk config:set myKey myValue --prod +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `key` | Configuration key to set | +| `value` | Configuration value | + +**Flags:** + +| Flag | Description | +|------|-------------| +| `--prod` | Use production configuration | + +--- + +### `adk kb` + +Manage knowledge bases and synchronization. + +#### `adk kb sync` + +Synchronize knowledge bases with Botpress. + +**Usage:** +```bash +adk kb sync --dev +adk kb sync --prod +adk kb sync --dev --dry-run +adk kb sync --prod --force --yes +``` + +**Flags:** + +| Flag | Description | +|------|-------------| +| `--dev` | Sync with development bot | +| `--prod` | Sync with production bot | +| `--dry-run` | Preview changes without applying them | +| `-y, --yes` | Skip confirmation prompts | +| `--force` | Force re-sync all knowledge bases | + + +Either `--dev` or `--prod` is required when running `adk kb sync`. + + +--- + +### `adk telemetry` + +Manage telemetry preferences. + +**Usage:** +```bash +adk telemetry --status +adk telemetry --enable +adk telemetry --disable +``` + +**Flags:** + +| Flag | Description | +|------|-------------| +| `--status` | Show current telemetry status | +| `--enable` | Enable telemetry | +| `--disable` | Disable telemetry | + +--- + ## Project scripts The ADK also provides npm scripts that you can use in your `package.json`: diff --git a/for-developers/adk/concepts/conversations.mdx b/for-developers/adk/concepts/conversations.mdx index 4321fc05..556e5292 100644 --- a/for-developers/adk/concepts/conversations.mdx +++ b/for-developers/adk/concepts/conversations.mdx @@ -116,6 +116,58 @@ export default new Conversation({ }); ``` +## Conversation instance + +The `handler` receives a `conversation` object that provides methods to interact with the current conversation: + +### Sending messages + +Send a message to the conversation: + +```typescript +await conversation.send({ + type: "text", + payload: { text: "Hello!" }, +}); +``` + +### Typing indicators + +Control typing indicators: + +```typescript +await conversation.startTyping(); +// ... do some work ... +await conversation.stopTyping(); +``` + +### Conversation tags + +Access and modify conversation tags: + +```typescript +// Read tags +const priority = conversation.tags.priority; + +// Set tags +conversation.tags.priority = "high"; +``` + +### Trigger subscriptions + +Subscribe a conversation to triggers: + +```typescript +// Subscribe to a trigger +await conversation.subscribeToTrigger("myTrigger"); + +// Subscribe with a key for filtered triggers +await conversation.subscribeToTrigger("myTrigger", "specific-key"); + +// Unsubscribe +await conversation.unsubscribeFromTrigger("myTrigger"); +``` + ## Multiple conversations You can create multiple conversation handlers for different channels or use cases: diff --git a/for-developers/adk/concepts/knowledge.mdx b/for-developers/adk/concepts/knowledge.mdx index d847de48..5e718d31 100644 --- a/for-developers/adk/concepts/knowledge.mdx +++ b/for-developers/adk/concepts/knowledge.mdx @@ -26,15 +26,43 @@ You can add knowledge from several different data sources: ### Website source -Index a website using a sitemap: +There are multiple ways to index websites: + +#### From a sitemap + +Index a website using a sitemap XML file: ```typescript -import { DataSource } from "@botpress/runtime"; +import { Knowledge, DataSource } from "@botpress/runtime"; const WebsiteSource = DataSource.Website.fromSitemap( "https://example.com/sitemap.xml", { filter: ({ url }) => !url.includes("/admin"), + maxPages: 1000, + maxDepth: 10, + } +); + +export default new Knowledge({ + name: "website-docs", + sources: [WebsiteSource], +}); +``` + +#### From a base URL + +Crawl a website starting from a base URL (requires the Browser integration): + +```typescript +import { Knowledge, DataSource } from "@botpress/runtime"; + +const WebsiteSource = DataSource.Website.fromWebsite( + "https://example.com", + { + filter: ({ url }) => !url.includes("/admin"), + maxPages: 500, + maxDepth: 5, } ); @@ -44,9 +72,55 @@ export default new Knowledge({ }); ``` +#### From `llms.txt` + +Index pages referenced in an `llms.txt` file: + +```typescript +import { Knowledge, DataSource } from "@botpress/runtime"; + +const WebsiteSource = DataSource.Website.fromLlmsTxt( + "https://example.com/llms.txt" +); + +export default new Knowledge({ + name: "website-docs", + sources: [WebsiteSource], +}); +``` + +#### From specific URLs + +Index a specific list of URLs: + +```typescript +import { Knowledge, DataSource } from "@botpress/runtime"; + +const WebsiteSource = DataSource.Website.fromUrls([ + "https://example.com/page1", + "https://example.com/page2", + "https://example.com/page3", +]); + +export default new Knowledge({ + name: "website-docs", + sources: [WebsiteSource], +}); +``` + +#### Website source options + +| Option | Type | Description | +|--------|------|-------------| +| `id` | `string` | Optional unique identifier for the source | +| `filter` | `(ctx) => boolean` | Filter function receiving `{ url, lastmod?, changefreq?, priority? }` | +| `fetch` | `string \| function` | Fetch strategy: `'node:fetch'` (default), `'integration:browser'`, or custom function | +| `maxPages` | `number` | Maximum pages to index (1-50000, default: 50000) | +| `maxDepth` | `number` | Maximum sitemap depth (1-20, default: 20) | + ### File source -Index files from a directory: +Index files from a local directory (development only): ```typescript const FileSource = DataSource.Directory.fromPath("./docs", { @@ -59,13 +133,24 @@ export default new Knowledge({ }); ``` + + Directory sources only work during development (`adk dev`). For production, use website sources or upload files to Botpress Cloud. + + +#### Directory source options + +| Option | Type | Description | +|--------|------|-------------| +| `id` | `string` | Optional unique identifier for the source | +| `filter` | `(filePath: string) => boolean` | Filter function to include/exclude files | + ### Table source Index data from a table: ```typescript -import { DataSource } from "@botpress/runtime"; -import { OrderTable } from "../tables/OrderTable"; +import { Knowledge, DataSource } from "@botpress/runtime"; +import OrderTable from "../tables/OrderTable"; const TableSource = DataSource.Table.fromTable(OrderTable, { id: "orders", @@ -104,7 +189,7 @@ Refresh knowledge bases to update their content: ```typescript highlight={6, 8} import { Workflow } from "@botpress/runtime"; -import { WebsiteKB } from "..knowledge/docs" +import WebsiteKB from "../knowledge/docs" export default new Workflow({ name: "refresh-knowledge", @@ -115,6 +200,22 @@ export default new Workflow({ }); ``` +### Force refresh + +Force re-indexing of all content even if unchanged: + +```typescript +await WebsiteKB.refresh({ force: true }); +``` + +### Refresh a specific source + +Refresh a single data source within a knowledge base: + +```typescript +await WebsiteKB.refreshSource("my-source-id", { force: true }); +``` + ## Reference ### Knowledge props diff --git a/for-developers/adk/concepts/tables.mdx b/for-developers/adk/concepts/tables.mdx index 368e10c8..d82e036a 100644 --- a/for-developers/adk/concepts/tables.mdx +++ b/for-developers/adk/concepts/tables.mdx @@ -75,18 +75,32 @@ Check out the [column options](#table-props) in the Table props reference for a ## Using tables -Tables are automatically created and synced when you deploy. Access them using the Botpress client: +Tables are automatically created and synced when you deploy. You can import them and interact with them directly using the table instance methods, which provide type-safe operations: + +```ts src/workflows/create-order.ts highlight={8-10, 13-18, 21-23} +import { Workflow } from "@botpress/runtime"; +import OrderTable from "../tables/order-table"; -```ts highlight={4-9} export default new Workflow({ name: "createOrder", - handler: async ({ client }) => { - await client.upsertTableRows({ - table: "OrderTable", - rows: [{ - // Order data - }] - }) + handler: async ({ step }) => { + // Create rows + const { rows } = await OrderTable.createRows({ + rows: [{ userId: "user123", total: 99.99, status: "pending" }], + }); + + // Find rows with filters + const { rows: orders } = await OrderTable.findRows({ + filter: { status: "pending" }, + orderBy: "createdAt", + orderDirection: "desc", + limit: 10, + }); + + // Update rows + await OrderTable.updateRows({ + rows: [{ id: orders[0].id, status: "completed" }], + }); }, }); ``` diff --git a/for-developers/adk/concepts/tools.mdx b/for-developers/adk/concepts/tools.mdx index fa9e8426..2c0719a1 100644 --- a/for-developers/adk/concepts/tools.mdx +++ b/for-developers/adk/concepts/tools.mdx @@ -9,8 +9,7 @@ Tools are functions that can be called by the AI model during conversations. The Create a tool in `src/tools/`: ```typescript -import { Autonomous } from "@botpress/runtime"; -import { z } from "@botpress/sdk"; +import { Autonomous, z } from "@botpress/runtime"; export default new Autonomous.Tool({ name: "myTool", @@ -29,8 +28,7 @@ export default new Autonomous.Tool({ Define input and output schemas using Zod schemas. The AI model uses these schemas to understand when and how to call your tool: ```typescript highlight={7-14} -import { Autonomous } from "@botpress/runtime"; -import { z } from "@botpress/sdk"; +import { Autonomous, z } from "@botpress/runtime"; export default new Autonomous.Tool({ name: "getWeather", @@ -117,8 +115,7 @@ The handler function receives the input parameters and executes the tool's logic ```ts Basic handler highlight={10-13} -import { Autonomous } from "@botpress/runtime"; -import { z } from "@botpress/sdk"; +import { Autonomous, z } from "@botpress/runtime"; export default new Autonomous.Tool({ name: "searchDatabase", @@ -134,8 +131,7 @@ export default new Autonomous.Tool({ ``` ```ts Calling actions highlight={1, 10-13} -import { Autonomous, actions } from "@botpress/runtime"; -import { z } from "@botpress/sdk"; +import { Autonomous, actions, z } from "@botpress/runtime"; export default new Autonomous.Tool({ name: "processOrder", @@ -193,6 +189,34 @@ export default new Autonomous.Tool({ }); ``` +## Signals + +Tools can throw special signals to influence the AI's behavior: + +### ThinkSignal + +Throw a `ThinkSignal` to provide additional context to the AI without returning a result: + +```typescript highlight={9-12} +import { Autonomous } from "@botpress/runtime"; + +export default new Autonomous.Tool({ + name: "searchDatabase", + handler: async ({ query }) => { + const results = await search(query); + + if (results.length === 0) { + throw new Autonomous.ThinkSignal( + "No results found", + "No results were found. Try a different search query." + ); + } + + return results; + }, +}); +``` + ## Best practices - Write clear, descriptive tool names and descriptions diff --git a/for-developers/adk/concepts/workflows.mdx b/for-developers/adk/concepts/workflows/overview.mdx similarity index 60% rename from for-developers/adk/concepts/workflows.mdx rename to for-developers/adk/concepts/workflows/overview.mdx index 3f9423c7..44fb7317 100644 --- a/for-developers/adk/concepts/workflows.mdx +++ b/for-developers/adk/concepts/workflows/overview.mdx @@ -1,5 +1,6 @@ --- title: Workflows +sidebarTitle: Overview --- Workflows are long-running processes that handle complex, multi-step operations or scheduled tasks. Unlike [conversations](/for-developers/adk/concepts/conversations), workflows can run independently on a schedule or be triggered by events. @@ -41,9 +42,9 @@ export default new Workflow({ }); ``` -## Workflow steps +## Steps -Use the `step` function to create checkpoints in long-running workflows: +By default, workflows time out after 2 minutes—if you need to run a workflow for longer, you should use the `step` function. This lets you break the workflow up into a series of steps that each take only a few seconds to run individually: ```typescript highlight={4-17} export default new Workflow({ @@ -67,7 +68,69 @@ export default new Workflow({ }); ``` -Steps are persisted, so if a workflow is interrupted, it can resume from the last completed step. +Steps are *persisted*—if a workflow is interrupted, it can resume from the last completed step. This provides better handling when errors occur in complex, long-running workflows. + + + You can nest steps inside other steps—each step will complete when each of its sub-steps complete. + + +### Reference + +The `step` object also provides many additional methods for workflow control: + + + Learn about all available step methods + + +### Handling failing steps + +If a step (or a [step method](/for-developers/adk/concepts/workflows/steps#methods)) fails, it'll throw a rejected promise. This will fail not only the current step, but the *entire workflow*. + +To avoid this, make sure you catch errors gracefully: + +```ts +try { + await step.request("orderId", "Please provide the order ID."); +} catch (err) { + console.log(err); +} +``` + +If the method you're using has an `options.maxAttempts` field, it'll throw an error after the maximum number of retries has been exceeded. You can track the retries using the `attempt` parameter and catch any errors: + +```ts highlight={5, 8, 10-12} +try { + await step( + "data-processing", + async ({ attempt }) => { + console.log(`Trying step: attempt #${attempt}`); + // Your code here + }, + { maxAttempts: 10 } + ); +} catch (err) { + console.log(err); +} +``` + +## Output + +Workflows can return an output that matches the output schema: + +```typescript highlight={10} +export default new Workflow({ + name: "calculate-totals", + input: z.object({ orderId: z.string() }), + output: z.object({ total: z.number() }), + handler: async ({ input, step }) => { + const order = await step("fetch-order", async () => { + return await fetchOrder(input.orderId); + }); + + return { total: order.total }; + }, +}); +``` ## Reference @@ -165,6 +228,13 @@ The handler function receives workflow context and provides step management: > Botpress client for making API calls (tables, events, etc.). + + An abort signal that indicates when the workflow should stop execution. + + +## Methods + +Workflows can be started and managed programmatically: + +### `workflow.start()` + +Start a new workflow instance: + +```typescript +import ProcessingWorkflow from "../workflows/processing"; + +const instance = await ProcessingWorkflow.start({ orderId: "12345" }); +console.log("Started workflow:", instance.id); +``` + +### `workflow.getOrCreate()` + +Get an existing workflow or create a new one with deduplication: + +```typescript +const instance = await ProcessingWorkflow.getOrCreate({ + key: "order-12345", // Unique key for deduplication + input: { orderId: "12345" }, + statuses: ["pending", "in_progress"], // Only match workflows with these statuses +}); +``` + +### `workflow.asTool()` + +Convert a workflow into a tool for use with `execute()`: + +```typescript highlight={2, 9} +import { Conversation } from "@botpress/runtime"; +import ProcessingWorkflow from "../workflows/processing"; + +export default new Conversation({ + channel: "*", + handler: async ({ execute }) => { + await execute({ + instructions: "You are a helpful assistant.", + tools: [ProcessingWorkflow.asTool()], + }); + }, +}); +``` + +### `workflow.provide()` + +Provide data in response to a workflow data request (used with `step.request()`): + +```typescript highlight={1, 6-9} +import { isWorkflowDataRequest } from "@botpress/runtime"; +import OrderWorkflow from "../workflows/order"; + +export default new Conversation({ + channel: "*", + handler: async ({ type, request }) => { + if (type === "workflow_request") { + await OrderWorkflow.provide(request, { orderId: "12345" }); + } + }, +}); +``` + +## Helper functions + +### `isWorkflowDataRequest()` + +Check if an event is a workflow data request: + +```typescript +import { isWorkflowDataRequest } from "@botpress/runtime"; + +if (isWorkflowDataRequest(event)) { + // Handle the workflow data request +} +``` + +### `isWorkflowCallback()` + +Check if an event is a workflow callback: + +```typescript +import { isWorkflowCallback } from "@botpress/runtime"; + +if (isWorkflowCallback(event)) { + // Handle the workflow callback +} +``` + diff --git a/for-developers/adk/concepts/workflows/steps.mdx b/for-developers/adk/concepts/workflows/steps.mdx new file mode 100644 index 00000000..86070b95 --- /dev/null +++ b/for-developers/adk/concepts/workflows/steps.mdx @@ -0,0 +1,336 @@ +This page contains a full reference for the [`step` function](/for-developers/adk/concepts/workflows/overview#steps). + +```typescript +const data = await step("fetch-data", async () => { + return await fetchDataFromAPI(); +}); +``` + +## Parameters + + + Unique identifier for this step within the workflow. + + + Make sure you set a unique identifier for each step. Otherwise, the second step won't execute and will reuse the output of the first step. + + + + + Function to execute. Receives the current attempt number. + + + Optional configuration object. + + + Maximum number of retry attempts if the step fails. Defaults to 5. + + + + +--- + +## Methods + +The following methods are available on each step: + +### `listen` + +Put the workflow into listening mode, waiting for external events to resume: + +```typescript +await step.listen("wait-for-approval"); +// Workflow pauses here until triggered +``` + +**Parameters**: + + + The name of the step. + + +--- + +### `sleep` + +Pause workflow execution for a specified duration: + +```typescript +// Sleep for 5 minutes +await step.sleep("wait-5-min", 5 * 60 * 1000); +``` + +**Parameters**: + + + The name of the step. + + + Duration to sleep in milliseconds. + + +--- + +### `sleepUntil` + +Sleep until a specific date: + +```typescript +await step.sleepUntil("wait-until-noon", new Date("2025-01-15T12:00:00Z")); +``` + +**Parameters**: + + + The name of the step. + + + The date to sleep until. + + +--- + +### `fail` + +Mark the workflow as failed and stop execution: + +```typescript +if (!user.isVerified) { + await step.fail("User verification required"); +} +``` + +**Parameters**: + + + Description of why the workflow failed. + + +--- + +### `abort` + +Immediately abort the workflow execution without marking it as failed: + +```typescript +if (shouldPause) { + step.abort(); +} +``` + +**Parameters**: + +No parameters. + +--- + +### `progress` + +Record a progress checkpoint without performing any action: + +```typescript +await step.progress("Started processing"); +// ... do work ... +await step.progress("Finished processing"); +``` + +**Parameters**: + + + The name of the progress checkpoint. + + +--- + +### `waitForWorkflow` + +Wait for another workflow to complete before continuing: + +```typescript +const childWorkflow = await childWorkflowInstance.start({}); +const result = await step.waitForWorkflow("wait-for-child", childWorkflow.id); +``` + +**Parameters**: + + + The name of the step. + + + ID of the workflow to wait for. + + +--- + +### `executeWorkflow` + +Start another workflow and wait for it to complete: + +```typescript +import ProcessingWorkflow from "../workflows/processing"; + +const result = await step.executeWorkflow( + "process-data", + ProcessingWorkflow, + { data: inputData } +); +``` + +**Parameters**: + + + The name of the step. + + + The workflow instance to execute. + + + Input data for the workflow (typed based on workflow's input schema). + + +--- + +### `map` + +Process an array of items in parallel with controlled concurrency: + +```typescript +const results = await step.map( + "process-users", + users, + async (user, { i }) => await processUser(user), + { concurrency: 5, maxAttempts: 3 } +); +``` + +**Parameters**: + + + The name of the map operation. + + + Array of items to process. + + + Function to process each item. Receives the item and its index. + + + Optional configuration object. + + + Maximum retry attempts per item. Defaults to 5. + + + Maximum number of concurrent operations. Defaults to 1. + + + + +--- + +### `forEach` + +Process an array of items without collecting results: + +```typescript +await step.forEach( + "notify-users", + users, + async (user) => await sendNotification(user), + { concurrency: 10 } +); +``` + +**Parameters**: + + + The name of the forEach operation. + + + Array of items to process. + + + Function to process each item. Receives the item and its index. + + + Optional configuration object. + + + Maximum retry attempts per item. Defaults to 5. + + + Maximum number of concurrent operations. Defaults to 1. + + + + +--- + +### `batch` + +Process items in sequential batches: + +```typescript +await step.batch( + "bulk-insert", + records, + async (batch) => await database.bulkInsert(batch), + { batchSize: 100 } +); +``` + +**Parameters**: + + + The name of the batch operation. + + + Array of items to process. + + + Function to process each batch. Receives the batch array and starting index. + + + Optional configuration object. + + + Number of items per batch. Defaults to 20. + + + Maximum retry attempts per batch. Defaults to 5. + + + + +--- + +### `request` + +Request data from a conversation and wait for a response. Requires defining `requests` in the workflow: + +```typescript +export default new Workflow({ + name: "order-workflow", + requests: { + orderId: z.object({ + orderId: z.string(), + }), + }, + handler: async ({ step }) => { + const data = await step.request("orderId", "Please provide the order ID"); + // data is typed based on the request schema + }, +}); +``` + +**Parameters**: + + + The name of the request (must be defined in workflow's `requests` field). + + + Message to display to the user describing what data is needed. + + + Optional custom name for the step. Defaults to the request name. + diff --git a/for-developers/adk/managing-integrations.mdx b/for-developers/adk/managing-integrations.mdx index a7aa67ad..b570cdfd 100644 --- a/for-developers/adk/managing-integrations.mdx +++ b/for-developers/adk/managing-integrations.mdx @@ -16,6 +16,14 @@ adk add slack@latest adk add my-workspace/custom-integration@1.0.0 ``` +### Using an alias + +Add an integration with a custom alias: + +```bash +adk add webchat --alias custom-webchat +``` + This automatically: - Adds the integration to `agent.config.ts` - Generates TypeScript types for the integration @@ -98,7 +106,7 @@ To update an integration: ### Using the CLI ``` -adk update +adk upgrade ``` ### Manually @@ -123,7 +131,17 @@ You can also update the version it manually: ## Removing integrations -Remove an integration by deleting it from `agent.config.ts`: +### Using the CLI + +Remove an integration using the `adk remove` command: + +```bash +adk remove +``` + +### Manually + +You can also remove an integration by deleting it from `agent.config.ts`: ```typescript dependencies: { diff --git a/for-developers/adk/project-structure.mdx b/for-developers/adk/project-structure.mdx index 236e22de..18584012 100644 --- a/for-developers/adk/project-structure.mdx +++ b/for-developers/adk/project-structure.mdx @@ -9,6 +9,7 @@ ADK projects follow a consistent structure that organizes your agent's code, con + @@ -23,9 +24,9 @@ ADK projects follow a consistent structure that organizes your agent's code, con ### `agent.config.ts` -The main agent configuration file. Defines your agent's name, description, default models, state schemas, and integration dependencies. +The main agent configuration file. Defines your agent's name, description, default models, state schemas, tags, configuration schema, and integration dependencies. -```typescript +```typescript expandable import { z, defineConfig } from "@botpress/runtime"; export default defineConfig({ @@ -39,13 +40,44 @@ export default defineConfig({ bot: { state: z.object({ - // Bot-level state + // Bot-level state accessible via `bot.state` }), + tags: { + // Bot-level tags + }, }, user: { state: z.object({ - // User-level state + // User-level state accessible via `user.state` + }), + tags: { + // User-level tags + }, + }, + + conversation: { + tags: { + // Conversation-level tags + }, + }, + + message: { + tags: { + // Message-level tags + }, + }, + + workflow: { + tags: { + // Workflow-level tags + }, + }, + + configuration: { + schema: z.object({ + // Configuration schema for your agent + // Accessible via `configuration` export }), }, @@ -183,7 +215,24 @@ export default new Action({ return { message: "This is your action's output." }; }, }); +``` + +### `src/tools/` + +Tools that the AI model can call during conversations. Tools are provided to the `execute()` function. +```typescript +import { Autonomous, z } from "@botpress/runtime"; + +export default new Autonomous.Tool({ + name: "myTool", + description: "A tool that does something useful", + input: z.object({ query: z.string() }), + output: z.object({ result: z.string() }), + handler: async ({ query }) => { + return { result: "Tool output" }; + }, +}); ``` ### `src/tables/` @@ -241,6 +290,54 @@ export const WebsiteKB = new Knowledge({ }); ``` +## Global state and configuration + +The ADK provides exports for accessing global state and configuration throughout your agent. + +### Bot state + +Access and modify bot-level state that persists across all conversations: + +```typescript +import { bot } from "@botpress/runtime"; + +// Read bot state +const currentValue = bot.state.someField; + +// Update bot state +bot.state.someField = "new value"; +``` + +### User state + +Access and modify user-level state that persists for each user: + +```typescript +import { user } from "@botpress/runtime"; + +// Read user state +const preferences = user.state.preferences; + +// Update user state +user.state.visitCount = (user.state.visitCount || 0) + 1; +``` + +### Configuration + +Access your agent's configuration values (defined in `agent.config.ts`): + +```typescript +import { configuration } from "@botpress/runtime"; + +// Access configuration values +const apiKey = configuration.apiKey; +const maxRetries = configuration.maxRetries; +``` + + + State schemas are defined in `agent.config.ts` under `bot.state` and `user.state`. The configuration schema is defined under `configuration.schema`. + + ## Generated files The ADK generates TypeScript types in `.adk/bot/.botpress`: