# Context API Reference Access runtime services like the Botpress client and citations manager within your ADK handlers. ## Quick Start ```typescript import { context } from "@botpress/runtime"; // Get Botpress client const client = context.get("client"); // Get citations manager const citations = context.get("citations"); // Use services const { passages } = await client.searchFiles({ query: "search term", withContext: true, }); ``` ## Overview The `context` API provides access to runtime services within your ADK handlers (actions, tools, workflows, conversations, triggers). The ADK automatically sets up context for you - you just need to call `context.get()` to access services. **Available in:** - Action handlers - Tool handlers - Workflow handlers - Conversation handlers - Trigger handlers ## Primary Context Keys These are the context keys you'll commonly use as an ADK developer: ### client The Botpress API client for your bot. Use this to interact with Botpress services like files, tables, messages, etc. ```typescript const client = context.get("client"); // Search files/knowledge base const { passages } = await client.searchFiles({ query: "search query", tags: { type: "knowledge" }, withContext: true }); // Create message await client.createMessage({ conversationId, type: "text", payload: { text: "Hello!" } }); // Query tables (low-level client API) const { rows } = await client.tables.findMany({ table: "users", filter: { email: { eq: "user@example.com" } } }); ``` > **Note:** For table operations, prefer using the direct Table class methods (e.g., `UsersTable.findRows()`) over `client.tables.*`. The Table class provides better type safety and a cleaner API. See [Tables documentation](./tables.md) for details. **Type:** `BotSpecificClient` ### citations Citation manager for tracking sources in AI responses. Essential for RAG implementations. ```typescript const citations = context.get("citations"); // Register a source const { tag } = citations.registerSource({ url: "https://docs.example.com/page", title: "Documentation Page", favicon: "https://docs.example.com/favicon.ico" }); // Use in response const response = `According to the documentation${tag}, the answer is...`; ``` **Type:** `CitationsManager` See **[Knowledge Bases](./knowledge-bases.md)** for complete citation examples with RAG. ## Optional Context Keys These keys may or may not be available depending on the handler context. Always use `{ optional: true }` when accessing them. ### user Current user object (available in conversation handlers). ```typescript const user = context.get("user", { optional: true }); if (user) { console.log(user.id); console.log(user.name); console.log(user.tags); } ``` **Type:** `User | null` ### conversation Current conversation object. Available optionally in Actions, Tools, and Triggers when they are invoked within a conversation context. > **Note:** In `Conversation` handlers, the `conversation` object is already provided as a handler parameter — use that directly instead of `context.get("conversation")`. ```typescript // In Actions, Tools, or Triggers — use context.get() with { optional: true } const conversation = context.get("conversation", { optional: true }); if (conversation) { console.log(conversation.id); console.log(conversation.tags); } // In Conversation handlers — use the handler parameter directly // async handler({ conversation }) { ... } ``` **Type:** `Conversation | null` ### message Incoming message (when triggered by a message event). ```typescript const message = context.get("message", { optional: true }); if (message?.type === "text") { console.log(message.payload.text); } ``` **Type:** `AnyIncomingMessage | null` ### event Incoming event (available in trigger handlers). ```typescript const event = context.get("event", { optional: true }); if (event) { console.log(`Event type: ${event.type}`); console.log(event.payload); } ``` **Type:** `AnyIncomingEvent | null` See **[Triggers](./triggers.md)** for event handling examples. ### workflow Current workflow instance (available in workflow handlers). ```typescript const workflow = context.get("workflow", { optional: true }); if (workflow) { console.log(`Workflow ID: ${workflow.id}`); console.log(`Conversation ID: ${workflow.conversationId}`); } ``` **Type:** `Workflow | null` See **[Workflows](./workflows.md)** for workflow context examples. ### workflowControlContext Workflow control operations (available in workflow handlers). ```typescript const control = context.get("workflowControlContext", { optional: true }); if (control) { // Access workflow controls await control.ack(); control.complete({ result: "success" }); } ``` **Type:** `WorkflowControlContext | null` ### chat Chat instance for accessing conversation transcripts (available in conversation handlers). ```typescript const chat = context.get("chat", { optional: true }); if (chat) { // Fetch conversation transcript const transcript = await chat.fetchTranscript(); console.log(`Messages: ${transcript.length}`); } ``` **Type:** `BotpressChat | null` See **[Conversations](./conversations.md)** for chat context examples. ## Less Common Keys These are available but less frequently needed: ### cognitive AI model client for direct LLM operations. Most of the time you'll use `execute()` instead. ```typescript const cognitive = context.get("cognitive"); const response = await cognitive.generateText({ model: "openai:gpt-4o", messages: [{ role: "user", content: "Hello" }] }); ``` **Type:** `Cognitive` **Note:** Usually you'll use `execute()` for AI interactions rather than calling cognitive directly. ### logger Structured logger for the current bot. ```typescript const logger = context.get("logger"); logger.info("Processing request"); logger.error("Failed to process", { error }); logger.debug("Debug info", { data }); ``` **Type:** `BotLogger` ### botId Current bot identifier. ```typescript const botId = context.get("botId"); console.log(`Running in bot: ${botId}`); ``` **Type:** `string` ## Using context.get() ### Basic Syntax ```typescript context.get( key: T, opts?: { optional?: boolean } ): Required[T] ``` ### Required Keys ```typescript // Will throw if not available (use for keys that should always exist) const client = context.get("client"); const citations = context.get("citations"); ``` ### Optional Keys ```typescript // Returns null if not available (use for conditional keys) const user = context.get("user", { optional: true }); const conversation = context.get("conversation", { optional: true }); if (user && conversation) { // Both available } else { // Handle missing context } ``` ## Common Patterns ### Conditional User Context ```typescript export const myAction = new Action({ async handler({ input }) { const client = context.get("client"); const user = context.get("user", { optional: true }); if (user) { // Personalized response console.log(`Processing for user ${user.id}`); } else { // Generic response console.log("Processing without user context"); } return await client.doSomething(); } }); ``` ### Using Context Across Handler Types The `context.get()` syntax is identical across all handler types (Actions, Tools, Workflows, Conversations, Triggers): ```typescript // Same pattern everywhere const client = context.get("client"); const citations = context.get("citations"); const user = context.get("user", { optional: true }); ``` See individual documentation for handler-specific examples: **[Actions](./actions.md)**, **[Tools](./tools.md)**, **[Workflows](./workflows.md)**, **[Conversations](./conversations.md)**. ## Error Handling ### Required Keys ```typescript // ❌ WRONG - Will throw if key doesn't exist try { const user = context.get("user"); } catch (error) { // Hard to handle gracefully } // ✅ CORRECT - Use optional for conditional keys const user = context.get("user", { optional: true }); if (!user) { console.log("No user context available"); return defaultResponse; } ``` ### Always-Available Keys Keys like `client`, `citations` should always be available. If they're not, it's a framework error: ```typescript // These should never throw in normal operation const client = context.get("client"); const citations = context.get("citations"); ``` ## Best Practices ### 1. Know Which Keys Are Always Available **Always available:** - `client` - Botpress API client - `citations` - Citation manager - `cognitive` - AI model client - `logger` - Structured logger - `botId` - Current bot ID **Conditionally available (use `{ optional: true }`):** - `user` - Only in conversation context - `conversation` - Only in conversation context - `message` - Only when triggered by message - `event` - Only in trigger handlers - `workflow` - Only in workflow handlers - `workflowControlContext` - Only in workflow handlers - `chat` - Only in conversation handlers ### 2. Access Context at Call Time ```typescript // ✅ GOOD - Get context when needed export const myAction = new Action({ async handler({ input }) { const client = context.get("client"); // Get when you need it const result = await client.searchFiles({ query: input.query }); return result; } }); // ❌ BAD - Don't store context globally let globalClient; // Don't do this! export const badAction = new Action({ async handler({ input }) { globalClient = context.get("client"); // Context might change } }); ``` ### 3. Use TypeScript's Type Safety ```typescript // TypeScript knows the types const client = context.get("client"); // client is typed as BotSpecificClient const user = context.get("user", { optional: true }); // user is typed as User | null ``` ## Direct Imports vs Context API For `bot`, `user`, and `adk`, you can use direct imports instead of `context.get()`: ```typescript import { bot, user, adk } from "@botpress/runtime"; bot.state.version; // Instead of context.get("bot").state user.state.preferredLanguage; // Instead of context.get("user").state ``` See **[Actions](./actions.md)** for comparison of both approaches. ## Troubleshooting ### "Context key not found" Error ```typescript // Error: Context key "user" not found const user = context.get("user"); ``` **Solution:** Use `{ optional: true }` for conditional keys: ```typescript const user = context.get("user", { optional: true }); ``` ### "Cannot read property of undefined" ```typescript // Error: Cannot read property 'id' of undefined const userId = context.get("user", { optional: true }).id; ``` **Solution:** Check if key exists before accessing properties: ```typescript const user = context.get("user", { optional: true }); if (user) { const userId = user.id; } ``` ## See Also - **[Actions](./actions.md)** - Using context in actions - **[Tools](./tools.md)** - Using context in tools - **[Integration Actions](./integration-actions.md)** - Using the client for integration actions - **[Workflows](./workflows.md)** - Workflow context - **[Conversations](./conversations.md)** - Conversation context - **[Knowledge Bases](./knowledge-bases.md)** - Using citations for RAG