Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/asundar43/simpleclaw/llms.txt

Use this file to discover all available pages before exploring further.

Provider Plugins

Provider plugins extend SimpleClaw with custom LLM providers, memory systems, and specialized tools.

Provider Plugin Interface

import type {
  SimpleClawPluginService,
  SimpleClawPluginServiceContext,
  ProviderAuthContext,
  ProviderAuthResult,
} from "simpleclaw/plugin-sdk";

export interface SimpleClawPluginService {
  id: string;
  name?: string;
  version?: string;
  
  // Lifecycle
  init?(ctx: SimpleClawPluginServiceContext): Promise<void>;
  shutdown?(): Promise<void>;
  
  // Authentication
  auth?(ctx: ProviderAuthContext): Promise<ProviderAuthResult>;
  
  // Provider methods
  invoke?(ctx: any, request: any): Promise<any>;
  models?(): Promise<ModelInfo[]>;
  
  // HTTP routes
  routes?: PluginRoute[];
}

LLM Provider Example

import type {
  SimpleClawPluginService,
  SimpleClawPluginServiceContext,
} from "simpleclaw/plugin-sdk";

export const customLLMProvider: SimpleClawPluginService = {
  id: "custom-llm",
  name: "Custom LLM Provider",
  version: "1.0.0",
  
  async init(ctx: SimpleClawPluginServiceContext) {
    ctx.logger.info("Initializing Custom LLM provider");
    
    // Load API keys from config
    const config = await ctx.config.get("providers.customllm");
    this.apiKey = config?.apiKey;
  },
  
  async auth(ctx) {
    // OAuth flow or API key validation
    try {
      const response = await fetch("https://api.example.com/auth", {
        headers: {
          "Authorization": `Bearer ${this.apiKey}`,
        },
      });
      
      const profile = await response.json();
      
      return {
        success: true,
        profile: {
          id: profile.userId,
          name: profile.username,
          email: profile.email,
        },
      };
    } catch (error) {
      return {
        success: false,
        error: error.message,
      };
    }
  },
  
  async models() {
    return [
      {
        id: "custom-llm/gpt-ultra",
        name: "GPT Ultra",
        contextWindow: 200000,
        maxOutputTokens: 8192,
      },
      {
        id: "custom-llm/gpt-mini",
        name: "GPT Mini",
        contextWindow: 128000,
        maxOutputTokens: 4096,
      },
    ];
  },
  
  async invoke(ctx, request) {
    const { messages, model, temperature, maxTokens } = request;
    
    const response = await fetch("https://api.example.com/chat", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${this.apiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model,
        messages,
        temperature,
        max_tokens: maxTokens,
      }),
    });
    
    const data = await response.json();
    
    return {
      message: data.choices[0].message,
      usage: {
        promptTokens: data.usage.prompt_tokens,
        completionTokens: data.usage.completion_tokens,
        totalTokens: data.usage.total_tokens,
      },
    };
  },
};

Memory Provider Example

import type { SimpleClawPluginService } from "simpleclaw/plugin-sdk";

export const vectorMemoryProvider: SimpleClawPluginService = {
  id: "vector-memory",
  name: "Vector Memory Store",
  
  async init(ctx) {
    // Initialize vector database connection
    this.db = await connectToVectorDB(ctx.config.get("providers.vectormemory"));
  },
  
  async invoke(ctx, request) {
    const { action, params } = request;
    
    switch (action) {
      case "store":
        return await this.storeMemory(params);
      
      case "search":
        return await this.searchMemory(params);
      
      case "recall":
        return await this.recallContext(params);
      
      default:
        throw new Error(`Unknown action: ${action}`);
    }
  },
  
  async storeMemory(params) {
    const { sessionKey, text, embedding } = params;
    
    await this.db.insert({
      sessionKey,
      text,
      embedding,
      timestamp: Date.now(),
    });
    
    return { ok: true };
  },
  
  async searchMemory(params) {
    const { query, limit = 10 } = params;
    
    const results = await this.db.search({
      query,
      limit,
    });
    
    return {
      results: results.map(r => ({
        text: r.text,
        score: r.score,
        timestamp: r.timestamp,
      })),
    };
  },
};

Tool Provider Example

import type { SimpleClawPluginService, AnyAgentTool } from "simpleclaw/plugin-sdk";
import { Type } from "@sinclair/typebox";

export const customToolProvider: SimpleClawPluginService = {
  id: "custom-tools",
  name: "Custom Tool Provider",
  
  async init(ctx) {
    // Register custom tools
    ctx.registerTools([
      {
        name: "weather_get",
        description: "Get current weather for a location",
        input_schema: Type.Object({
          location: Type.String({ description: "City name or coordinates" }),
          units: Type.Optional(Type.Union([
            Type.Literal("celsius"),
            Type.Literal("fahrenheit"),
          ])),
        }),
        handler: async (input) => {
          const response = await fetch(
            `https://api.weather.example.com/current?location=${input.location}&units=${input.units || "celsius"}`
          );
          
          const data = await response.json();
          
          return {
            temperature: data.temp,
            conditions: data.conditions,
            humidity: data.humidity,
          };
        },
      },
      
      {
        name: "calendar_create_event",
        description: "Create a calendar event",
        input_schema: Type.Object({
          title: Type.String(),
          start: Type.String({ description: "ISO 8601 datetime" }),
          duration: Type.Number({ description: "Duration in minutes" }),
          description: Type.Optional(Type.String()),
        }),
        handler: async (input) => {
          const eventId = await createCalendarEvent({
            title: input.title,
            start: new Date(input.start),
            duration: input.duration,
            description: input.description,
          });
          
          return {
            eventId,
            url: `https://calendar.example.com/events/${eventId}`,
          };
        },
      },
    ]);
  },
};

HTTP Routes

Providers can expose HTTP endpoints:
import type { SimpleClawPluginService } from "simpleclaw/plugin-sdk";
import { registerPluginHttpRoute } from "simpleclaw/plugin-sdk";

export const webhookProvider: SimpleClawPluginService = {
  id: "custom-webhooks",
  
  async init(ctx) {
    // Register HTTP routes
    registerPluginHttpRoute({
      pluginId: "custom-webhooks",
      method: "POST",
      path: "/webhooks/custom",
      handler: async (req, res) => {
        const body = await req.json();
        
        // Process webhook
        await processWebhook(body);
        
        res.json({ ok: true });
      },
    });
  },
};

Configuration

Define provider config schema:
import { z } from "zod";
import { emptyPluginConfigSchema } from "simpleclaw/plugin-sdk";

export const CustomLLMConfigSchema = z.object({
  apiKey: z.string(),
  baseUrl: z.string().url().optional(),
  timeout: z.number().default(30000),
  retries: z.number().default(3),
});

// Export schema for validation
export const configSchema = {
  schema: CustomLLMConfigSchema.shape,
  uiHints: {
    apiKey: {
      label: "API Key",
      sensitive: true,
      help: "Get your API key from the provider dashboard",
    },
    timeout: {
      label: "Request Timeout (ms)",
      advanced: true,
    },
  },
};

Authentication Flow

Implement OAuth or API key auth:
import type {
  ProviderAuthContext,
  ProviderAuthResult,
} from "simpleclaw/plugin-sdk";
import { buildOauthProviderAuthResult } from "simpleclaw/plugin-sdk";

export async function auth(ctx: ProviderAuthContext): Promise<ProviderAuthResult> {
  const { code, redirectUri } = ctx;
  
  // Exchange code for access token
  const response = await fetch("https://api.example.com/oauth/token", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      code,
      client_id: process.env.CLIENT_ID,
      client_secret: process.env.CLIENT_SECRET,
      redirect_uri: redirectUri,
      grant_type: "authorization_code",
    }),
  });
  
  const data = await response.json();
  
  // Get user profile
  const profileResponse = await fetch("https://api.example.com/user", {
    headers: { "Authorization": `Bearer ${data.access_token}` },
  });
  
  const profile = await profileResponse.json();
  
  return buildOauthProviderAuthResult({
    accessToken: data.access_token,
    refreshToken: data.refresh_token,
    expiresAt: Date.now() + data.expires_in * 1000,
    profile: {
      id: profile.id,
      name: profile.name,
      email: profile.email,
    },
  });
}

Plugin Packaging

{
  "name": "@simpleclaw/provider-custom",
  "version": "1.0.0",
  "main": "dist/index.js",
  "simpleclaw": {
    "extensions": [
      {
        "type": "provider",
        "id": "custom-llm",
        "entry": "./dist/index.js"
      }
    ]
  },
  "dependencies": {
    "simpleclaw": "^2026.3.0",
    "@sinclair/typebox": "^0.32.0"
  }
}

Testing

import { describe, test, expect } from "vitest";
import { customLLMProvider } from "./index.js";

describe("Custom LLM provider", () => {
  test("authenticates successfully", async () => {
    const ctx = createMockAuthContext();
    const result = await customLLMProvider.auth(ctx);
    
    expect(result.success).toBe(true);
    expect(result.profile).toBeDefined();
  });
  
  test("invokes chat completion", async () => {
    const ctx = createMockContext();
    const response = await customLLMProvider.invoke(ctx, {
      model: "custom-llm/gpt-ultra",
      messages: [
        { role: "user", content: "Hello!" },
      ],
    });
    
    expect(response.message).toBeDefined();
    expect(response.usage.totalTokens).toBeGreaterThan(0);
  });
});

Next Steps

Channel Plugins

Build messaging platform integrations

Plugin SDK

Complete SDK reference