Ir al contenido principal

Crear plugins personalizados

Crear plugins personalizados

Si necesitas rutas de API personalizadas o lógica en segundo plano, implementa un plugin de AppKit. La forma más rápida es usar la CLI:

# Interactivo
npx @databricks/appkit plugin create

# No interactivo
npx @databricks/appkit plugin create --placement in-repo --path plugins/my-plugin --name my-plugin --description "My plugin" --force

Para comprender mejor la estructura del plugin, continúa leyendo.

Ejemplo básico de plugin

Escribe el manifiesto en JSON, impórtalo y asócialo a una subclase de Plugin mediante static manifest. Expórtalo con toPlugin():

// my-plugin/manifest.json
{
  "$schema": "https://databricks.github.io/appkit/schemas/plugin-manifest.schema.json",
  "name": "my-plugin",
  "displayName": "My Plugin",
  "description": "A custom plugin",
  "resources": {
    "required": [
      {
        "type": "secret",
        "alias": "apiKey",
        "resourceKey": "api-key",
        "description": "API key for external service",
        "permission": "READ",
        "fields": {
          "scope": { "env": "MY_SECRET_SCOPE", "description": "Secret scope" },
          "key": { "env": "MY_API_KEY", "description": "Secret key name" }
        }
      }
    ],
    "optional": []
  }
}
// my-plugin/index.ts
import { Plugin, toPlugin, type PluginManifest } from "@databricks/appkit";
import manifest from "./manifest.json";

class MyPlugin extends Plugin {
  static manifest = manifest as PluginManifest<"my-plugin">;

  async setup() {
    // Inicializa tu plugin
  }

  myCustomMethod() {
    // Implementación
  }

  async shutdown() {
    // Libera los recursos
  }

  exports() {
    return {
      myCustomMethod: this.myCustomMethod
    }
  }
}

export const myPlugin = toPlugin(MyPlugin);

JSON es la superficie canónica de creación: es lo que lee appkit plugin sync al agregar los manifiestos de las templates. Para conocer el contrato completo del manifiesto v2.0 (recursos, descriptores de descubrimiento, reglas de scaffolding), consulta Manifiesto del plugin.

Recursos dependientes de la configuración

El manifiesto define los recursos como required (siempre necesarios) u optional (que pueden ser necesarios). Para los recursos que pasan a ser obligatorios según la configuración del plugin, implementa un método estático getResourceRequirements(config):

interface MyPluginConfig extends BasePluginConfig {
  enableCaching?: boolean;
}

class MyPlugin extends Plugin<MyPluginConfig> {
  static manifest = {
    name: "myPlugin",
    displayName: "My Plugin",
    description: "A plugin with optional caching",
    resources: {
      required: [
        { type: "sql_warehouse", alias: "warehouse", resourceKey: "sqlWarehouse", description: "Query execution", permission: "CAN_USE", fields: { id: { env: "DATABRICKS_WAREHOUSE_ID" } } }
      ],
      optional: [
        // Se declara como opcional en el manifiesto para el análisis estático
        { type: "database", alias: "cache", resourceKey: "cache", description: "Query result caching (if enabled)", permission: "CAN_CONNECT_AND_CREATE", fields: { instance_name: { env: "DATABRICKS_CACHE_INSTANCE" }, database_name: { env: "DATABRICKS_CACHE_DB" } } }
      ]
    }
  } satisfies PluginManifest<"myPlugin">;

  // Runtime: convierte los recursos opcionales en obligatorios según la configuración
  static getResourceRequirements(config: MyPluginConfig) {
    const resources = [];
    if (config.enableCaching) {
      // Cuando la caché está habilitada, Database pasa a ser obligatorio
      resources.push({
        type: "database",
        alias: "cache",
        resourceKey: "cache",
        description: "Query result caching",
        permission: "CAN_CONNECT_AND_CREATE",
        fields: {
          instance_name: { env: "DATABRICKS_CACHE_INSTANCE" },
          database_name: { env: "DATABRICKS_CACHE_DB" },
        },
        required: true  // Se marca como obligatorio en runtime
      });
    }
    return resources;
  }
}

Este patrón permite:

  • Que las herramientas estáticas (CLI, documentación) muestren todos los recursos posibles
  • Que la validation en runtime exija los recursos según la configuration real

Puntos de extensión clave

  • Inyección de rutas: implementa injectRoutes() para añadir endpoints personalizados mediante IAppRouter
  • Hooks de ciclo de vida: sobrescribe los métodos setup() y shutdown()
  • Servicios compartidos:
    • Gestión de caché: accede al servicio de caché mediante this.cache. Consulta CacheConfig para la configuración.
    • Telemetría: instrumenta tu plugin con trazas y métricas mediante this.telemetry. Consulta ITelemetry.
  • Interceptores de ejecución: usa execute() y executeStream() con StreamExecutionSettings para caché, reintentos y tiempos de espera automáticos, además de los atributos de span de telemetría (execution.context, caller.id)

Consumir tu plugin mediante código

Opcionalmente, puedes ofrecer una forma de consumir tu plugin mediante código usando el objeto AppKit. Para ello, tu plugin debe implementar el método exports y devolver un objeto con los métodos que quieras exponer. Partiendo del ejemplo anterior, el plugin podría consumirse así:

const AppKit = await createApp({
  plugins: [
    server({ port: 8000 }),
    analytics(),
    myPlugin(),
  ],
});

AppKit.myPlugin.myCustomMethod();

Consulta la referencia de la API de Plugin para ver la documentación completa.

Databricks Developer Hub

¿Todo listo para lanzar tu próxima aplicación basada en agentes en minutos?

Leer la documentación