Using AI Agents
Custom Skills
handler.js reference

This page is intended for developers who want to create custom agent skills for AnythingLLM.

Rules & Guidelines

  • The handler.js file must export a runtime object with a handler function.

  • The handler function must accept a single argument which is an object containing the parameters defined in the plugin.json entrypoint property, if any.

  • The handler function must return a string value, anything else may break the agent invocation or loop indefinitely.

  • You must use require to import any modules you need from the NodeJS standard library or any modules you have bundled with your custom agent skill.

  • You must use await when making any calls to external APIs or services.

  • You must wrap your entire custom agent skill in a try/catch block and return any error messages to the agent at invocation time.

Available runtime properties and methods

this.runtimeArgs

The this.runtimeArgs object contains the arguments that were passed to the setup_args from the plugin.json file.

You can access the value of a specific argument by using the propertyName as the key.

// plugin.json excerpt
// "setup_args": {
//     "OPEN_METEO_API_KEY": {
//       "type": "string",
//       "required": false,
//       "input": {
//         "type": "text",
//         "default": "YOUR_OPEN_METEO_API_KEY",
//         "placeholder": "sk-1234567890",
//         "hint": "The API key for the open-meteo API"
//       },
//       "value": "sk-key-for-service",
//     }
//   },
 
this.runtimeArgs["OPEN_METEO_API_KEY"]; // 'sk-key-for-service'

this.introspect

The this.introspect function is used to log "thoughts" or "observations" to the user interface while the agent is running.

this.introspect("Hello, world!"); // must be a string - will be shown to user

this.logger

The this.logger function is used to log messages to the console. This is useful for debugging your custom agent skill via logs.

this.logger("Hello, world!"); // must be a string - will be printed to console while the agent is running

this.config

The this.config object contains the configuration for your custom agent skill. Useful for when you need to know the name of your custom agent skill or the version or for logs.

this.config.name; // 'Get Weather'
this.config.hubId; // 'open-meteo-weather-api'
this.config.version; // '1.0.0'

Example handler.js

Objective: Get the weather for a given location latitude and longitude using the open-meteo API.

// handler.js
// NOT RECOMMENDED: We're using an external module here for demonstration purposes
// this would be a module we bundled with our custom agent skill and would be located in the same folder as our handler.js file
// Do not require modules outside of the plugin folder. It is recommended to use require within a function scope instead of the global scope.
// const _ExternalApiCaller = require('./external-api-caller.js');
 
module.exports.runtime = {
  handler: async function ({ latitude, longitude }) {
    const callerId = `${this.config.name}-v${this.config.version}`;
    try {
      this.introspect(
        `${callerId} called with lat:${latitude} long:${longitude}...`
      );
      const response = await fetch(
        `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current_weather=true&hourly=temperature_2m,relativehumidity_2m,windspeed_10m`
      );
      const data = await response.json();
      const averageTemperature = this._getAverage(data, "temperature_2m");
      const averageHumidity = this._getAverage(data, "relativehumidity_2m");
      const averageWindSpeed = this._getAverage(data, "windspeed_10m");
      return JSON.stringify({
        averageTemperature,
        averageHumidity,
        averageWindSpeed,
      });
    } catch (e) {
      this.introspect(
        `${callerId} failed to invoke with lat:${latitude} long:${longitude}. Reason: ${e.message}`
      );
      this.logger(
        `${callerId} failed to invoke with lat:${latitude} long:${longitude}`,
        e.message
      );
      return `The tool failed to run for some reason. Here is all we know ${e.message}`;
    }
  },
  // Helper function to get the average of an array of numbers!
  _getAverage(data, property) {
    return (
      data.hourly[property].reduce((a, b) => a + b, 0) /
      data.hourly[property].length
    );
  },
 
  // Recommended: Use this method to call external APIs or services
  // by requiring the module in the function scope and only if the code execution reaches that line
  // this is to prevent any unforseen issues with the global scope and module loading/unloading.
  // This file should be placed in the same folder as your handler.js file.
  _doExternalApiCall(myProp) {
    const _ScopedExternalCaller = require("./external-api-caller.js");
    return _ScopedExternalCaller.doSomething(myProp);
  },
};