Skip to content

Latest commit

 

History

History
499 lines (413 loc) · 13.2 KB

File metadata and controls

499 lines (413 loc) · 13.2 KB
layout default
title Chapter 6: Plugin Development
nav_order 6
has_children false
parent LobeChat AI Platform

Chapter 6: Plugin Development

Welcome to Chapter 6: Plugin Development. In this part of LobeChat AI Platform: Deep Dive Tutorial, you will build an intuitive mental model first, then move into concrete implementation details and practical production tradeoffs.

Building custom plugins to extend LobeChat's capabilities with Function Calling

🎯 Learning Objectives

By the end of this chapter, you'll understand:

  • LobeChat's plugin architecture and SDK
  • Building plugins with Function Calling
  • Plugin manifest structure and API design
  • Testing and publishing custom plugins
  • Integration with external services

Plugin Architecture Overview

LobeChat uses a Function Calling-based plugin system. Plugins expose API endpoints that the LLM can invoke during conversation, enabling real-time data access and external service integration.

graph TB
    subgraph Chat["Chat Flow"]
        USER[User Message]
        LLM[LLM with FC]
        RESP[Response]
    end

    subgraph Plugin["Plugin System"]
        MANIFEST[Plugin Manifest]
        API[Plugin API]
        RENDER[UI Renderer]
    end

    USER --> LLM
    LLM -->|Function Call| API
    API -->|Result| LLM
    LLM --> RESP
    MANIFEST --> LLM
    API --> RENDER
Loading

Plugin Manifest

Every plugin defines a manifest describing its capabilities:

{
  "identifier": "weather-plugin",
  "name": "Weather",
  "description": "Get current weather and forecasts for any location",
  "author": "your-name",
  "version": "1.0.0",
  "homepage": "https://github.com/your-name/weather-plugin",
  "openapi": "https://your-plugin.vercel.app/openapi.json",
  "api": [
    {
      "name": "getWeather",
      "description": "Get current weather for a location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "City name or coordinates"
          },
          "units": {
            "type": "string",
            "enum": ["metric", "imperial"],
            "default": "metric"
          }
        },
        "required": ["location"]
      }
    },
    {
      "name": "getForecast",
      "description": "Get weather forecast for the next 5 days",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "City name or coordinates"
          },
          "days": {
            "type": "number",
            "default": 5,
            "maximum": 10
          }
        },
        "required": ["location"]
      }
    }
  ],
  "ui": {
    "url": "https://your-plugin.vercel.app",
    "height": 400
  },
  "settings": {
    "type": "object",
    "properties": {
      "apiKey": {
        "type": "string",
        "title": "API Key",
        "description": "Your weather API key"
      }
    }
  }
}

Building a Plugin

Project Setup

# Use the LobeChat plugin template
npx create-lobe-plugin my-plugin
cd my-plugin

# Or scaffold manually
mkdir my-plugin && cd my-plugin
npm init -y
npm install @lobehub/chat-plugin-sdk

Plugin Structure

my-plugin/
├── src/
│   ├── api/               # API route handlers
│   │   ├── getWeather.ts
│   │   └── getForecast.ts
│   ├── components/        # UI components (optional)
│   │   └── WeatherCard.tsx
│   └── index.ts           # Plugin entry
├── public/
│   ├── manifest.json      # Plugin manifest
│   └── openapi.json       # OpenAPI specification
├── package.json
└── vercel.json            # Deployment config

API Implementation

// src/api/getWeather.ts
import { PluginServerConfig } from "@lobehub/chat-plugin-sdk";

export const config: PluginServerConfig = {
  runtime: "edge",
};

interface WeatherParams {
  location: string;
  units?: "metric" | "imperial";
}

export default async function handler(req: Request) {
  const params: WeatherParams = await req.json();

  // Fetch weather data from external API
  const response = await fetch(
    `https://api.openweathermap.org/data/2.5/weather?` +
    `q=${encodeURIComponent(params.location)}` +
    `&units=${params.units || "metric"}` +
    `&appid=${process.env.WEATHER_API_KEY}`
  );

  const data = await response.json();

  // Return structured data for the LLM
  return Response.json({
    location: data.name,
    country: data.sys?.country,
    temperature: data.main?.temp,
    feels_like: data.main?.feels_like,
    humidity: data.main?.humidity,
    description: data.weather?.[0]?.description,
    wind_speed: data.wind?.speed,
    icon: data.weather?.[0]?.icon,
  });
}

Custom UI Rendering

Plugins can render custom UI in the chat:

// src/components/WeatherCard.tsx
import { memo } from "react";

interface WeatherData {
  location: string;
  temperature: number;
  description: string;
  humidity: number;
  icon: string;
}

const WeatherCard = memo<{ data: WeatherData }>(({ data }) => {
  return (
    <div style={{
      padding: "16px",
      borderRadius: "12px",
      background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
      color: "white",
      fontFamily: "system-ui",
    }}>
      <div style={{ fontSize: "18px", fontWeight: 600 }}>
        📍 {data.location}
      </div>
      <div style={{ fontSize: "48px", fontWeight: 700, margin: "8px 0" }}>
        {Math.round(data.temperature)}°
      </div>
      <div style={{ fontSize: "14px", opacity: 0.9 }}>
        {data.description}  Humidity: {data.humidity}%
      </div>
    </div>
  );
});

export default WeatherCard;

Function Calling Integration

LobeChat uses the LLM's Function Calling capability to invoke plugins:

// How LobeChat processes plugin calls internally
class PluginExecutor {
  async execute(
    functionCall: FunctionCall,
    pluginManifest: PluginManifest
  ): Promise<FunctionResult> {
    const api = pluginManifest.api.find(
      a => a.name === functionCall.name
    );

    if (!api) {
      throw new Error(`API not found: ${functionCall.name}`);
    }

    // Call the plugin's API endpoint
    const response = await fetch(pluginManifest.openapi, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        apiName: functionCall.name,
        arguments: JSON.parse(functionCall.arguments),
      }),
    });

    const result = await response.json();

    return {
      name: functionCall.name,
      content: JSON.stringify(result),
    };
  }
}

OpenAPI Specification

Plugins expose an OpenAPI schema for discovery:

{
  "openapi": "3.0.0",
  "info": {
    "title": "Weather Plugin",
    "version": "1.0.0"
  },
  "servers": [
    { "url": "https://your-plugin.vercel.app" }
  ],
  "paths": {
    "/api/getWeather": {
      "post": {
        "operationId": "getWeather",
        "summary": "Get current weather for a location",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "location": { "type": "string" },
                  "units": { "type": "string" }
                },
                "required": ["location"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Weather data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "location": { "type": "string" },
                    "temperature": { "type": "number" },
                    "description": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Plugin SDK Features

The @lobehub/chat-plugin-sdk provides utilities:

import {
  createHeadersWithPluginSettings,
  getPluginSettingsFromRequest,
  PluginErrorType,
  createErrorResponse,
} from "@lobehub/chat-plugin-sdk";

// Access plugin settings (API keys, etc.)
export default async function handler(req: Request) {
  const settings = getPluginSettingsFromRequest(req);
  const apiKey = settings?.apiKey;

  if (!apiKey) {
    return createErrorResponse(
      PluginErrorType.PluginSettingsInvalid,
      "API key is required"
    );
  }

  // Use the API key for external service calls
  const result = await fetchExternalService(apiKey);
  return Response.json(result);
}

Testing Plugins

// __tests__/getWeather.test.ts
import handler from "../src/api/getWeather";

describe("getWeather", () => {
  it("returns weather data for a valid location", async () => {
    const req = new Request("http://localhost/api/getWeather", {
      method: "POST",
      body: JSON.stringify({ location: "New York" }),
    });

    const response = await handler(req);
    const data = await response.json();

    expect(data).toHaveProperty("location");
    expect(data).toHaveProperty("temperature");
    expect(typeof data.temperature).toBe("number");
  });
});

Deploying Plugins

Vercel (Recommended)

// vercel.json
{
  "rewrites": [
    { "source": "/api/:path*", "destination": "/api/:path*" }
  ],
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Access-Control-Allow-Origin", "value": "*" },
        { "key": "Access-Control-Allow-Methods", "value": "GET,POST" }
      ]
    }
  ]
}
# Deploy to Vercel
vercel --prod

Docker

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]

Publishing to the Plugin Index

Submit your plugin to the LobeChat Plugin Index:

# Fork https://github.com/lobehub/lobe-chat-plugins
# Add your plugin manifest to plugins/your-plugin/manifest.json
# Submit a pull request

Summary

Concept Key Takeaway
Plugin Manifest JSON definition of capabilities, API endpoints, and UI
Function Calling LLM invokes plugin APIs during conversation via FC
API Routes Edge-compatible serverless functions for plugin logic
Custom UI React components rendered inline in chat messages
OpenAPI Standard schema for plugin discovery and validation
SDK @lobehub/chat-plugin-sdk for settings, errors, headers
Deployment Vercel or Docker; plugins are standalone services

Next Steps: Chapter 7: Advanced Customization — Explore LobeChat's theme engine, i18n system, monorepo architecture, and component customization.


Built with insights from the LobeChat repository and community documentation.

What Problem Does This Solve?

Most teams struggle here because the hard part is not writing more code, but deciding clear boundaries for plugin, location, json so behavior stays predictable as complexity grows.

In practical terms, this chapter helps you avoid three common failures:

  • coupling core logic too tightly to one implementation path
  • missing the handoff boundaries between setup, execution, and validation
  • shipping changes without clear rollback or observability strategy

After working through this chapter, you should be able to reason about Chapter 6: Plugin Development as an operating subsystem inside LobeChat AI Platform: Deep Dive Tutorial, with explicit contracts for inputs, state transitions, and outputs.

Use the implementation notes around name, weather, description as your checklist when adapting these patterns to your own repository.

How it Works Under the Hood

Under the hood, Chapter 6: Plugin Development usually follows a repeatable control path:

  1. Context bootstrap: initialize runtime config and prerequisites for plugin.
  2. Input normalization: shape incoming data so location receives stable contracts.
  3. Core execution: run the main logic branch and propagate intermediate state through json.
  4. Policy and safety checks: enforce limits, auth scopes, and failure boundaries.
  5. Output composition: return canonical result payloads for downstream consumers.
  6. Operational telemetry: emit logs/metrics needed for debugging and performance tuning.

When debugging, walk this sequence in order and confirm each stage has explicit success/failure conditions.

Source Walkthrough

Use the following upstream sources to verify implementation details while reading this chapter:

  • LobeChat Why it matters: authoritative reference on LobeChat (github.com).

Suggested trace strategy:

  • search upstream code for plugin and location to map concrete implementation paths
  • compare docs claims against actual runtime/config code before reusing patterns in production

Chapter Connections