CommunityRedacción y edicióngithub.com

Desarrollo de plugins para dsh

Habilidad de IA para desarrollar plugins de DeepSeek Harness (dsh), un framework de agentes basado en Cordis. Cubre la creación y publicación de herramientas, servicios, adaptadores LLM, listeners de eventos y más.

¿Qué es Desarrollo de plugins para dsh?

Esta habilidad de IA está diseñada para desarrolladores que trabajan con DeepSeek Harness (dsh), un framework de agentes basado en Cordis. Permite crear y publicar plugins escritos en TypeScript, los cuales exportan una función `apply(ctx: Context)` y se componen mediante `cordis.yml`. Cubre todos los tipos de capacidades que ofrece dsh: herramientas (tools), servicios (services), adaptadores LLM (LlmAdapter), listeners de eventos (events) y configuración tipada con Schema. Incluye guías rápidas sobre estructura de plugins, estados del ciclo de vida (Fiber States: PENDING → LOADING → ACTIVE → FAILED → DISPOSED), registro de herramientas con `defineTool`, diseño de tres capas (Definición → Proveedor → Consumidor), y publicación como paquete npm con manifiesto `dsh.bundle`. También soporta recarga en caliente (HMR) y diagnóstico de dependencias pendientes. Es útil para agentes como Claude Code, Cursor o Codex que necesiten extender las capacidades de un agente dsh con lógica personalizada.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add TrueHOOHA/dsh-plugin-dev-skill

Installed? Explore more Redacción y edición skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace Desarrollo de plugins para dsh?

Desarrolla plugins para DeepSeek Harness (dsh), un framework de agentes basado en Cordis. Los plugins son módulos TypeScript que exportan apply(ctx: Context), compuestos mediante cordis.yml.

Referencia rápida

Estructura del plugin

import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-plugin'
export function apply(ctx: Context) { /* registrar capacidades */ }

Tres formas: función (por defecto), objeto ({ name, inject, apply }), clase (extends Service — úsala solo cuando quieras proveer un servicio a otros plugins).

Dependencias: export const inject = ['tools', 'llm'] — el framework mantiene el plugin en estado PENDING hasta que todos los servicios inyectados estén listos.

Limpieza automática: Todo lo registrado a través de ctx es un efecto — se limpia automáticamente al descargar. Para recursos personalizados (temporizadores, conexiones), envuélvelos en ctx.effect(() => { ... return () => cleanup }).

Plugins hijos: const fiber = ctx.plugin(childPlugin) — los hijos heredan el contexto padre; await fiber.dispose() descarga recursivamente.

Estados de Fiber

PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED
                 ↘ FAILED

PENDING → falta una dependencia de servicio. FAILED → apply lanzó una excepción o la validación de configuración falló. La desaparición de un servicio en tiempo de ejecución descarga automáticamente a los dependientes.

Herramientas (Tools)

import { defineTool } from '@deepseek-ai/dsh-tools'
export const inject = ['tools']
export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'saludar', description: '...',
    parameters: { nombre: { type: 'string', required: true } },
    output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value }] },
    async execute(args) { return `¡Hola, ${args.nombre}!` },
  }))
}

defineTool convierte los parámetros a JSON Schema, valida argumentos y se da de baja automáticamente al descargar. Consulta references/basic/tool.md para más detalles.

Configuración

import Schema from '@deepseek-ai/schemastery'
export interface Config { saludo: string; maxReintentos: number }
export const Config: Schema<Config> = Schema.object({
  saludo: Schema.string().default('Hola'),
  maxReintentos: Schema.number().default(3),
})
export function apply(ctx: Context, config: Config) { /* configuración validada */ }

Debes exportar TANTO interface Config COMO const Config: Schema<Config>. Configuración inválida → estado FAILED con error claro. Usa !!js en YAML para valores dinámicos: config: { apiKey: !!js process.env.API_KEY }. Consulta references/basic/config.md.

Servicios

Proveer: class extends Service { constructor(ctx) { super(ctx, 'nombre') } }

  • declare module '@deepseek-ai/cordis' { interface Context { nombre: NombreService } }

Consumir: export const inject = ['nombre'] → ctx.nombre.metodo().

Opcional: ctx.get('nombre') → devuelve undefined cuando está ausente.

Aislamiento de servicios: group: true + isolate: { shell: true } le da a cada grupo su propia instancia del proveedor. Consulta references/framework/service.md.

Eventos

ModoLlamadaUso
emitctx.emit(n, ...args)Difusión síncrona, ignora valores de retorno
parallelawait ctx.parallel(n, ...args)Listeners concurrentes
serialawait ctx.serial(n, ...args)Secuencial, el primer no nulo gana
bailctx.bail(n, ...args)Serie síncrona
waterfallctx.waterfall(n, ...args, next)Cadena de middleware

Los listeners waterfall deben llamar a next() a menos que intencionalmente cortocircuiten. Eventos clave del harness: agent/step, tools/result, session/event. Consulta references/framework/events.md.

Adaptadores LLM

class MiAdaptador extends LlmAdapter {
  async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
    // Convertir → API del proveedor → yield StreamChunk
  }
}
ctx.llm.registerAdapter(['mi-proveedor'], adaptador)

Orden de StreamChunk por bloque: block-start → text-delta/tool-call-delta → block-end → usage → finish. Lanza LlmError con códigos estables. Consulta references/practice/llm-adapter.md.

Diseño de capacidades en tres capas

Definición (clase abstracta Service) → Proveedor (implementa) → Consumidor (herramienta)

Los tres comparten el mismo nombre de servicio mediante inject. Solo se dividen en paquetes separados cuando los roles necesitan evolución independiente. Consulta references/practice/index.md.

cordis.yml / Bundles

Desarrollo local: --patch ./cordis.patch.yml

- insert:
    - id: my-plugin
      name: '/ruta/absoluta/hacia/src/my-plugin.ts'
      config: { saludo: 'Hola' }

Distribución: paquete npm con manifiesto dsh.bundle + cordis.patch.yml. Instalación: dsh plugin --profile demo add ./hello-plugin. Orden de capas: bundles de perfil → parche de perfil → parche de home → superposiciones --patch. Las capas posteriores ganan por fila (sin fusión profunda). Consulta references/basic/publish.md.

HMR (Recarga en caliente)

Carga @deepseek-ai/cordis-plugin-hmr + @deepseek-ai/cordis-plugin-logger-console

  • @deepseek-ai/cordis-plugin-timer para recargar automáticamente al guardar archivos.

Diagnosticando PENDING

import { FiberState, type Context } from '@deepseek-ai/cordis'
for (const fiber of ctx.registry.values().flatMap(r => r.fibers))
  if (fiber.state === FiberState.PENDING)
    console.log(`${fiber.name} está PENDING`)

Documentación de referencia

Guías detalladas en el directorio references/:

RutaCubre
references/basic/Primer plugin, herramientas, configuración, publicación
references/framework/Ciclo de vida, servicios, eventos
references/practice/Diseño de tres capas, adaptadores LLM
references/cordis-tutorial/Tutorial paso a paso del framework Cordis

Skills relacionados