这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions pages/agent/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,14 @@
"pagination": true,
"toc": true
}
},
"custom": {
"title": "Custom Skills",
"theme": {
"breadcrumb": true,
"footer": true,
"pagination": true,
"toc": true
}
}
}
38 changes: 38 additions & 0 deletions pages/agent/custom/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"introduction": {
"title": "Introduction",
"theme": {
"breadcrumb": true,
"footer": true,
"pagination": true,
"toc": true
}
},
"developer-guide": {
"title": "Developer Guide",
"theme": {
"breadcrumb": true,
"footer": true,
"pagination": true,
"toc": true
}
},
"plugin-json": {
"title": "plugin.json reference",
"theme": {
"breadcrumb": true,
"footer": true,
"pagination": true,
"toc": true
}
},
"handler-js": {
"title": "handler.js reference",
"theme": {
"breadcrumb": true,
"footer": true,
"pagination": true,
"toc": true
}
}
}
97 changes: 97 additions & 0 deletions pages/agent/custom/developer-guide.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
title: "Developer Guide"
description: "How to create custom agent skills for developers"
---

import { Cards, Callout } from "nextra/components";
import Image from "next/image";

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

# How to develop custom agent skills

## Prerequisites

1. NodeJS 18+
2. Yarn
3. AnythingLLM running in some supported environment see [here](./introduction.mdx) for more information.

## Guidelines for creation of custom agent skills

1. Custom agent skills must be written in JavaScript and will execute within a NodeJS environment.
2. You can bundle any NodeJS package you want within your custom agent skill, but it must be present in the folder structure of your custom agent skill.
3. All functions must return a string value, anything else may break the agent invocation.
4. You _should_ provide a `README.md` file at the root of your custom agent skill with a description, any additional requirements and how to use the custom agent skill.
5. You _must_ define your plugin with an associated `plugin.json` file at the root of your custom agent skill folder.
6. The _must_ define your entry point of your custom agent skill as a `handler.js` file.
7. You _must_ wrap your entire custom agent skill in a folder with the same `name` property that is defined in the `plugin.json` file.

## Hot loading of custom agent skills

<Callout type="info" emoji="️💡" >
If you are in an active agent invocation when you make changes to your custom agent skill, you will need to `/exit` the current session for the changes to take effect.

If you just added a new custom agent skill you will need to revisit or reload the page for the new skill to be shown in the UI.

</Callout>

AnythingLLM supports hot loading of custom agent skills. This means that you can make changes to your custom agent skill and see the changes without having to restart the agent or the instance of AnythingLLM.

## Where to place your custom agent skill code

All agents skills must be placed in the appropriate folder in your AnythingLLM storage directory folder. This can be found in multiple locations depending on the environment you are running AnythingLLM in.
In all versions you are looking for the matching folder of the `STORAGE_DIR` environment variable.

<Callout type="info" emoji="️💡">
Your entire custom agent skill folder should be wrapped in a folder with the
same `hubId` property as the associated `plugin.json` file.
</Callout>
### Docker

Your storage directory should be mounted as a volume in your Docker container startup command - [which can be found here](../../installation/self-hosted/local-docker.mdx).
This will be the value of the `STORAGE_LOCATION` command variable.

Then you will need to create this subfolder within the storage directory:
`plugins/agent-skills`

### Local Development

When running AnythingLLM locally, your storage directory is likely mounted in the `server/storage` directory.

Then you will need to create this subfolder within the storage directory:
`plugins/agent-skills`

### Desktop

When running AnythingLLM on Desktop, your storage directory can be [found using this guide](../../installation/desktop/general.mdx#where-is-my-data-located).

Then you will need to create this subfolder within the storage directory:
`plugins/agent-skills`

## File structure

Your custom agent skill should be wrapped in a folder with the same `hubId` property that is defined in the `plugin.json` file.

_See the plugin.json [reference](./plugin-json.mdx) for more information on the plugin.json file, its properties and how to use them._

```js
// example plugin.json
{
"name": "This is my human readable name",
"hubId": "my-custom-agent-skill" // THIS MUST BE THE SAME AS THE parent folder name. Can be any string.
}
```

Folder structure for associated agent skill:
NOTE: The folder name must match the `hubId` property in the `plugin.json` file.

```text
plugins/agent-skills/my-custom-agent-skill
|-- plugin.json
|-- handler.js
|-- // You can add any additional files you want to the folder and reference them in the handler.js file!
```

## Plugin.json Reference

See [here](./plugin-json.mdx) for more information on the plugin.json file, its properties and how to use them.
149 changes: 149 additions & 0 deletions pages/agent/custom/handler-js.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
title: "handler.js reference"
description: "An example of what the handler.js file should look like."
---

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

## Rules & Guidelines

<ul className="nx-list-disc nx-list-inside nx-flex nx-flex-col nx-gap-2 nx-mt-2">
<li>
The `handler.js` file must export a `runtime` object with a `handler`
function.
</li>
<li>
The `handler` function must accept a single argument which is an object
containing the parameters defined in the `plugin.json` `entrypoint`
property, if any.
</li>
<li>
The `handler` function must return a string value, anything else may break
the agent invocation or loop indefinitely.
</li>
<li>
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.
</li>
<li>
You must use `await` when making any calls to external APIs or services.
</li>
<li>
You must wrap your entire custom agent skill in a `try`/`catch` block and
return any error messages to the agent at invocation time.
</li>
</ul>

## 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.

```js
// 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.

```js
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.

```js
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.

```js
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.

```js
// 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);
},
};
```
77 changes: 77 additions & 0 deletions pages/agent/custom/introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
title: ""
description: "How to create custom agent skills"
---

import { Cards, Callout } from "nextra/components";
import Image from "next/image";

<Callout type="error" emoji="⚠️">
**Warning:** Only run custom agent skills you trust.

Custom agent skills are a powerful feature of AnythingLLM, but they can also be dangerous if misused.

Always make sure to test your skills thoroughly before using them in a production environment & never install untrusted code on any machine.

</Callout>

# Introduction to custom agent skills

AnythingLLM allows you to create custom agent skills that can be used to extend the capabilities of your `@agent` invocations. These skills can be anything you want from a simple API call to even operating-system invocations.

The sky is the limit! Depending on how you run AnythingLLM, you can create custom agent skills that can run extra processes like running a local Python script or, on Desktop, even operating-system invocations.

If it can be done in NodeJS, it can likely be done in AnythingLLM.

## The current state of custom agent skills

<Callout type="info" emoji="️💡">
Custom agent skills are newly supported in AnythingLLM and may have some bugs, quirks, missing features, unsupported features, etc.

Please report any feature requests or bugs you find to the [GitHub repository](https://github.com/Mintplex-Labs/anything-llm).

</Callout>

1. NodeJS programming experience is required to create custom agent skills. Go to the [developer guide](./developer-guide.mdx) to get started.
2. Custom agent skills must _exactly_ match the requirements listed on this help page.
3. There are built in functions and utilities to help you log data or thoughts for an agent.
4. There is currently no established tooling for creating custom agent skills - so follow this guide if developing skills for AnythingLLM.
5. All skills must return a `string` type response - anything else may break the agent invocation.

## Availability

Custom agent skills are currently available in the AnythingLLM Docker image.

Support in AnythingLLM Desktop should be live in version 1.6.5.

Custom agent skills are **not** available in the AnythingLLM Cloud offering.

## View loaded custom agent skills

You can view the loaded custom agent skills by opening the `Agent Skills` tab in the settings of AnythingLLM.

Any valid custom agent skills loaded into AnythingLLM will be displayed here.

See [where to place your custom agent skills](./developer-guide.mdx#where-to-place-your-custom-agent-skill-code) for more information.

<Image
src="/images/guides/custom-skills/sidebar.png"
height={1080}
width={1920}
quality={100}
style={{ borderRadius: "10px" }}
/>

## Dynamic UI of custom agent skills

Custom agent skills can also have a dynamic UI inputs associated with them. This is useful for providing runtime arguments to your custom agent skills or configurable properties of them.

See [how the dynamic UI for a custom agent skill](./plugin-json.mdx#setup_args) is setup via the `plugin.json` file.

<Image
src="/images/guides/custom-skills/dynamic-ui.png"
height={1080}
width={1920}
quality={100}
style={{ borderRadius: "10px" }}
/>
Loading