This guide explains how to create, configure, and integrate custom AI tools within the Discourse AI plugin, enabling administrators to extend the bot’s capabilities with user-defined JavaScript functions.
Required user level: Administrator
Tools are programmable functionalities that can be used by the AI bot to perform specific tasks or retrieve information beyond just text-based responses. These tools are scripts or integrations that allow the bot to interact with external APIs, manipulate data, or execute additional functions to extend its capabilities.
Summary
This documentation covers:
- Creating a new custom AI tool
- Configuring tool parameters and scripts
- Available APIs for tool scripts
- Integrating custom tools with AI personas
- Testing and troubleshooting custom tools
Creating a new custom AI tool
To create a new AI tool:
- Navigate to Admin Panel > Plugins > Discourse AI > Tools
- Click “New Tool” (you can use existing presets to learn about options)
- Fill in the following fields:
- Name: The name of the tool as presented to the LLM
- Description: The description of the tool as presented to the LLM
- Summary: Summary of what tool does to assist users (displayed in details)
- Parameters: Define the inputs your tool needs as presented to LLM
- Script: The JavaScript code that powers your tool
- Click “Save”
Configuring tool scripts
Available APIs
Your tool scripts have access to the following APIs:
-
HTTP Requests:
http.get(url, options) http.post(url, options) http.put(url, options) http.patch(url, options) http.delete(url, options)Use these to interact with external services. You can use
optionsto specify HTTP headers and body:http.get(url, { headers: { "Authorization": "Bearer key" } }) http.post(url, { headers: { "Content-Type": "application/json" }, body: { key: "value" } }) http.patch(url, { headers: { "Authorization": "Bearer key" }, body: "some body" }) http.delete(url, { headers: { "Authorization": "Bearer key" } }) http.put(url, { headers: { "Authorization": "Bearer key" }, body: "some body" })All HTTP methods return
{ status: number, body: string }. -
LLM (Language Model) Integration:
llm.truncate(text, length)Truncates text to a specified token length based on the configured LLM’s tokenizer.
llm.generate(prompt, options)Generates text using the configured LLM. The prompt can be a simple string or a structured object like
{ messages: [{ type: "system", content: "..." }, { type: "user", content: "..." }] }. Options includejson: trueto request and auto-parse JSON output, as well astemperature,top_p,max_tokens, andstop_sequences. -
Custom upload integration (RAG)
index.search(query, { filenames: ["file.pdf"], limit: 10 })Searches indexed RAG document fragments attached to this tool. Returns
Array<{ fragment: string, metadata: string | null }>ordered by relevance. Default limit is 10, max 200.index.getFile(filename)Retrieves the full content of an uploaded RAG file by its exact filename. Returns the complete text or
nullif not found. -
Upload support
upload.create(filename, base_64_content)Creates a new upload. Returns
{ id: number, url: string, short_url: string }.upload.getUrl(shortUrl)Given a short URL (e.g.
upload://12345), returns the full CDN-friendly URL.upload.getBase64(uploadIdOrShortUrl, maxPixels)Fetches the base64-encoded content of an existing upload. Accepts an upload ID (number) or short URL (string). Optional
maxPixelsparameter for automatic image resizing (default: 10,000,000). -
Execution chain control
chain.setCustomRaw(raw)Sets the final raw content of the bot’s post and stops the tool execution chain. Useful for tools that directly generate the full response (e.g., image generation tools).
-
Secrets management
secrets.get(alias)Returns the credential value bound to the given alias. Aliases are defined in the tool’s secret contracts configuration and bound to AI Secrets in the admin panel. Throws an error if the alias is undeclared, unbound, or the credential is missing.
const apiKey = secrets.get("my_api_key"); -
Discourse integration
Tools can interact directly with Discourse data:
discourse.baseUrl // The site's base URL discourse.search(params) // Perform a Discourse search discourse.getPost(post_id) // Get post details (includes raw content) discourse.getTopic(topic_id) // Get topic details (tags, category, etc.) discourse.getUser(id_or_username) // Get user details discourse.createTopic(params) // Create a new topic discourse.createPost(params) // Create a new post/reply discourse.editPost(post_id, raw, options) // Edit a post's content discourse.editTopic(topic_id, updates, options) // Edit topic properties (tags, category, visibility) discourse.createChatMessage(params) // Send a chat message discourse.createStagedUser(params) // Create a staged user discourse.getAgent(name) // Get another AI agent (with respondTo method) discourse.updateAgent(name, updates) // Update an AI agent's configuration discourse.getCustomField(type, id, key) // Read custom field on post/topic/user discourse.setCustomField(type, id, key, value) // Set custom field on post/topic/user -
Context object
The
contextobject provides information about where the tool is running:-
Bot conversation context:
context.post_id,context.topic_id,context.private_message,context.participants,context.username,context.user_id -
Chat context:
context.message_id,context.channel_id,context.username -
Automation context:
context.post_id,context.topic_id,context.username,context.user_id,context.feature_name,context.feature_context -
Common properties:
context.site_url,context.site_title,context.site_description
-
Bot conversation context:
Required functions
Your script must implement:
-
invoke(params): The main function that executes when the tool is called
It may optionally implement:
-
details(): Returns a string (can include basic HTML) describing the tool’s execution, displayed in the chat interface -
customSystemMessage(): Called during prompt assembly (not during tool invocation). Returns a string appended to the system prompt, ornull/undefinedto skip. Has access tocontext,discourse, andindexobjects.
Example script:
function invoke(params) {
let result = http.get("https://api.example.com/data?query=" + params.query);
return JSON.parse(result.body);
}
function details() {
return "Fetched data from Example API";
}
Limitations and security
-
Execution Timeout: Default timeout of 2000ms of script processing time. The timer pauses during external HTTP requests (
http.*) and LLM calls (llm.generate), so only the script’s own processing time counts. - Memory: Maximum 10MB V8 heap limit
- HTTP Requests: Maximum of 20 requests per tool execution
- Sandboxed Environment: Scripts run in a restricted V8 JavaScript environment (via MiniRacer). No access to browser globals, the host file system, or server-side libraries. Network requests are proxied through the Discourse backend.
Testing your tool
You should test any tool you build to ensure the results the LLM will be provided with match your expectations.
Integrating tools with AI personas
To add your custom tool to an AI Persona:
- Go to Admin Panel > Plugins > Discourse AI > Personas
- Edit an existing persona or create a new one
- In the “Tools” section, you’ll see your custom tools listed alongside built-in tools
- Select your custom tool to add it to the persona
Custom tools in action
Once you provide the custom tool to your LLM it can use it to enhance the conversation.
Troubleshooting
If your tool isn’t working as expected:
- Use the Test interface to ensure it behaves as expected for your inputs.
- Ensure your group is in
ai_bot_debugging_allowed_groups. Members of this group have full access to the bot transcripts; you can view the AI logs there. - If anything unexpected is happening, visit
https://SITENAME/logsto check for errors.
Additional resources
Last edited by @Saif 2025-03-17T19:29:43Z
Last checked by @hugh 2024-08-06T02:00:12Z
Check document
Perform check on document:





