mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-31 04:45:23 +08:00
299 lines
7.5 KiB
Markdown
299 lines
7.5 KiB
Markdown
# Plugin Development Tutorial
|
|
|
|
This tutorial will guide you through the process of developing a plugin for LangBot.
|
|
|
|
## Plugin Structure
|
|
|
|
A LangBot plugin consists of the following components:
|
|
|
|
1. A main Python file that contains the plugin logic
|
|
2. A `manifest.yaml` file that describes the plugin
|
|
3. Optional additional files for resources, templates, etc.
|
|
|
|
## Creating a Basic Plugin
|
|
|
|
Let's create a simple "Hello World" plugin that responds to a specific command.
|
|
|
|
### Step 1: Create the Plugin Directory
|
|
|
|
Create a directory for your plugin in the `data/plugins` directory:
|
|
|
|
```bash
|
|
mkdir -p data/plugins/hello-plugin
|
|
```
|
|
|
|
### Step 2: Create the Manifest File
|
|
|
|
Create a `manifest.yaml` file in your plugin directory:
|
|
|
|
```yaml
|
|
name: HelloPlugin
|
|
version: 1.0.0
|
|
description: A simple hello world plugin
|
|
author: Your Name
|
|
entry: hello.py
|
|
requirements:
|
|
- requests>=2.28.0
|
|
```
|
|
|
|
### Step 3: Create the Plugin Code
|
|
|
|
Create a `hello.py` file in your plugin directory:
|
|
|
|
```python
|
|
from langbot.plugin import Plugin, handler
|
|
from langbot.event import PersonNormalMessageReceived
|
|
from langbot.api import APIHost
|
|
|
|
class HelloPlugin(Plugin):
|
|
def __init__(self, api_host: APIHost):
|
|
super().__init__(api_host)
|
|
self.api = api_host
|
|
|
|
@handler(PersonNormalMessageReceived)
|
|
def on_person_message(self, ctx):
|
|
# Get the message content
|
|
message = ctx.event.message.content
|
|
|
|
# Check if the message is the command we want to handle
|
|
if message == "!hello":
|
|
# Prevent the default handling (don't send to LLM)
|
|
ctx.prevent_default()
|
|
|
|
# Send a response
|
|
self.api.send_message(
|
|
ctx.event.message.source,
|
|
"Hello, World! This is my first LangBot plugin."
|
|
)
|
|
```
|
|
|
|
### Step 4: Install and Test the Plugin
|
|
|
|
1. Restart LangBot or use the `!plugin reload` command
|
|
2. Send the `!hello` command to your bot
|
|
3. The bot should respond with "Hello, World! This is my first LangBot plugin."
|
|
|
|
## Event Handling
|
|
|
|
LangBot uses an event-driven architecture. Plugins can register handlers for various events:
|
|
|
|
```python
|
|
@handler(PersonNormalMessageReceived)
|
|
def on_person_message(self, ctx):
|
|
# Handle the event
|
|
pass
|
|
```
|
|
|
|
Common events include:
|
|
|
|
- `PersonNormalMessageReceived`: Received a message from a person
|
|
- `GroupNormalMessageReceived`: Received a message in a group
|
|
- `GroupInvitationReceived`: Received an invitation to join a group
|
|
- `FriendRequestReceived`: Received a friend request
|
|
|
|
The `ctx` parameter provides access to:
|
|
|
|
- `ctx.event`: The event that triggered the handler
|
|
- `ctx.prevent_default()`: Prevents the default handling of the event
|
|
- `ctx.add_return(key, value)`: Adds a return value to the event
|
|
|
|
## API Access
|
|
|
|
The `APIHost` provides access to LangBot's API:
|
|
|
|
```python
|
|
# Send a message
|
|
self.api.send_message(source, content)
|
|
|
|
# Get user information
|
|
user_info = self.api.get_user_info(user_id)
|
|
|
|
# Get group information
|
|
group_info = self.api.get_group_info(group_id)
|
|
|
|
# Call the LLM
|
|
response = self.api.call_llm(prompt, model="gpt-3.5-turbo")
|
|
```
|
|
|
|
## LLM Function Registration
|
|
|
|
Plugins can register functions that can be called by the LLM during conversations:
|
|
|
|
```python
|
|
import requests
|
|
from langbot.plugin import Plugin, llm_func
|
|
from langbot.api import APIHost
|
|
|
|
class WebSearchPlugin(Plugin):
|
|
def __init__(self, api_host: APIHost):
|
|
super().__init__(api_host)
|
|
self.api = api_host
|
|
|
|
@llm_func(name="search_the_web")
|
|
def search_web(self, query: str) -> str:
|
|
"""
|
|
Search the web for information.
|
|
|
|
Args:
|
|
query: The search query
|
|
|
|
Returns:
|
|
The search results
|
|
"""
|
|
# Implement web search logic
|
|
response = requests.get(
|
|
"https://api.search.com/search",
|
|
params={"q": query}
|
|
)
|
|
return response.json()["results"]
|
|
```
|
|
|
|
The LLM can then call this function during conversations:
|
|
|
|
```
|
|
User: What's the weather in New York?
|
|
Bot: Let me check that for you.
|
|
[Function call: search_the_web("weather in New York")]
|
|
The current weather in New York is 72°F and sunny.
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Plugins can have configuration options that users can set:
|
|
|
|
```python
|
|
from langbot.plugin import Plugin, config_field
|
|
from langbot.api import APIHost
|
|
|
|
class WeatherPlugin(Plugin):
|
|
def __init__(self, api_host: APIHost):
|
|
super().__init__(api_host)
|
|
self.api = api_host
|
|
|
|
@config_field(name="api_key", description="API key for the weather service")
|
|
def set_api_key(self, api_key: str):
|
|
self.api_key = api_key
|
|
```
|
|
|
|
Users can set these options using the WebUI or the `!plugin config` command:
|
|
|
|
```
|
|
!plugin config WeatherPlugin api_key=your-api-key
|
|
```
|
|
|
|
## Persistent Storage
|
|
|
|
Plugins can store data persistently:
|
|
|
|
```python
|
|
# Store data
|
|
self.api.storage.set("key", "value")
|
|
|
|
# Retrieve data
|
|
value = self.api.storage.get("key")
|
|
|
|
# Check if a key exists
|
|
exists = self.api.storage.has("key")
|
|
|
|
# Delete a key
|
|
self.api.storage.delete("key")
|
|
```
|
|
|
|
## Advanced Features
|
|
|
|
### Command Registration
|
|
|
|
Plugins can register commands that users can use:
|
|
|
|
```python
|
|
from langbot.plugin import Plugin, command
|
|
from langbot.api import APIHost
|
|
|
|
class EchoPlugin(Plugin):
|
|
def __init__(self, api_host: APIHost):
|
|
super().__init__(api_host)
|
|
self.api = api_host
|
|
|
|
@command(name="echo", description="Echo a message")
|
|
def echo_command(self, args: str) -> str:
|
|
"""
|
|
Echo the provided message.
|
|
|
|
Usage: !echo <message>
|
|
"""
|
|
return args
|
|
```
|
|
|
|
Users can then use the command:
|
|
|
|
```
|
|
!echo Hello, World!
|
|
```
|
|
|
|
### Event Return Values
|
|
|
|
Handlers can add return values to events:
|
|
|
|
```python
|
|
@handler(PersonNormalMessageReceived)
|
|
def on_person_message(self, ctx):
|
|
# Add a return value
|
|
ctx.add_return("reply", ["This is a reply"])
|
|
```
|
|
|
|
### Component Extension
|
|
|
|
Plugins can extend LangBot's core components:
|
|
|
|
```python
|
|
from langbot.plugin import Plugin, component_extension
|
|
from langbot.api import APIHost
|
|
|
|
class CustomTriggerPlugin(Plugin):
|
|
def __init__(self, api_host: APIHost):
|
|
super().__init__(api_host)
|
|
self.api = api_host
|
|
|
|
@component_extension("trigger")
|
|
def custom_trigger(self, component, message):
|
|
# Implement custom trigger logic
|
|
if message.content.startswith("custom:"):
|
|
return True
|
|
return None # Let the default trigger handle it
|
|
```
|
|
|
|
## Publishing Your Plugin
|
|
|
|
To publish your plugin:
|
|
|
|
1. Create a GitHub repository for your plugin
|
|
2. Add a README.md file with installation and usage instructions
|
|
3. Add your plugin to the [LangBot Plugin Market](https://plugins.langbot.app)
|
|
|
|
## Best Practices
|
|
|
|
- Keep your plugin focused on a specific functionality
|
|
- Handle errors gracefully
|
|
- Provide clear documentation
|
|
- Follow Python best practices
|
|
- Test your plugin thoroughly
|
|
- Keep dependencies minimal
|
|
|
|
## Example Plugins
|
|
|
|
Check out these example plugins for inspiration:
|
|
|
|
- [WebSearch](https://github.com/RockChinQ/WebSearch): Search the web for information
|
|
- [ImageGen](https://github.com/RockChinQ/ImageGen): Generate images using AI
|
|
- [Schedule](https://github.com/RockChinQ/Schedule): Schedule messages to be sent at specific times
|
|
|
|
## Troubleshooting
|
|
|
|
If you encounter issues with your plugin:
|
|
|
|
1. Check the logs for error messages
|
|
2. Verify that your plugin is correctly installed
|
|
3. Make sure your plugin's dependencies are installed
|
|
4. Test your plugin with simple functionality first
|
|
5. Ask for help in the [community chat](https://qm.qq.com/q/Nnz7Vbj8OU)
|