DeepSeek Harness: Configuração de Plugin

Última atualização: 2026-08-31

Configuração é o "botão de controle" de um plugin — chaves de API, timeouts, toggles de funcionalidade, esses parâmetros específicos do ambiente não devem ser hardcoded mas externalizados através de um sistema de configuração. Schemastery é o framework de configuração declarativa do Cordis: defina uma vez, automaticamente obtenha segurança de tipo, formulários UI, validação e documentação.

💡 Dica: A filosofia central do Schemastery é "declaração como documentação" — você define a estrutura de configuração com Schema, e o framework auto-gera formulários na Web UI e lógica de validação. Alterar configuração não requer alterar código.

📋 Pré-requisitos: Ter completado 15-define-tool.md, capaz de escrever ferramentas básicas

1. O Que Você Vai Aprender

Hot Reload de Config


2. Configuração Declarativa Schemastery

(1) Conceito Básico

▶ Exemplo 1: Config com Schemastery

Schemastery é a biblioteca de definição de Schema built-in do Cordis, inspirada em Zod e JSON Schema, mas projetada especificamente para configuração interativa.

TYPESCRIPT
import { Schema } from '@deepseek-ai/cordis'

export const Config = Schema.object({
  apiKey: Schema.string().required().description('Chave de API para o serviço'),
  maxRetries: Schema.number().default(3).description('Número máximo de tentativas'),
  debug: Schema.boolean().default(false).description('Habilitar logging de depuração')
})

(2) Comparação com JSON Schema

Dimensão Schemastery JSON Schema
Sintaxe API encadeável Objeto JSON
Inferência de tipo ✅ Automática ❌ Manual
Formulários UI ✅ Auto-gerados ❌ Ferramentas extras necessárias
Valores padrão .default() Campo default
Descrições .description() Campo description
Validação Validadores encadeáveis pattern/min/max etc.

(3) Uso em Plugin

▶ Exemplo 2: Config em um Plugin

TYPESCRIPT
export const Config = Schema.object({
  apiKey: Schema.string().required(),
  maxRetries: Schema.number().default(3)
})

export const name = 'my-plugin'

export function apply(ctx: Context) {
  // Tipo de ctx.config é automaticamente inferido
  ctx.logger.info(`Chave de API: ${ctx.config.apiKey}`)
  ctx.logger.info(`Máx. tentativas: ${ctx.config.maxRetries}`)
}

O framework valida os valores de configuração fornecidos pelo usuário e os injeta em ctx.config.


3. Tipos de Schema

(1) Schema.string

TYPESCRIPT
Schema.string()                           // Qualquer string
Schema.string().required()                // Obrigatório
Schema.string().default('hello')          // Valor padrão
Schema.string().description('Seu nome')  // Descrição
Schema.string().pattern(/^[a-z]+$/)       // Validação regex
Schema.string().min(1).max(100)           // Limites de comprimento

(2) Schema.number

TYPESCRIPT
Schema.number()                    // Qualquer número
Schema.number().default(0)         // Valor padrão
Schema.number().min(0).max(100)    // Limites de faixa
Schema.number().step(1)            // Passo (para sliders UI)
Schema.integer()                   // Inteiro

(3) Schema.boolean

TYPESCRIPT
Schema.boolean()                   // Booleano
Schema.boolean().default(false)    // Padrão false

(4) Schema.object

TYPESCRIPT
Schema.object({
  host: Schema.string().default('localhost'),
  port: Schema.number().default(5432),
  ssl: Schema.boolean().default(false)
})

(5) Schema.array

TYPESCRIPT
Schema.array(Schema.string())                          // Array de strings
Schema.array(Schema.string()).default([])              // Padrão array vazio
Schema.array(Schema.object({                           // Array de objetos
  name: Schema.string().required(),
  url: Schema.string().required()
}))

(6) Schema.union / Schema.const

TYPESCRIPT
// Valores enum
Schema.union(['read', 'write', 'execute'])

// Constante
Schema.const('fixed-value')

// Enum com descrições
Schema.union([
  Schema.const('read').description('Acesso somente leitura'),
  Schema.const('write').description('Acesso de leitura e escrita'),
  Schema.const('execute').description('Acesso total')
])

(7) Schema.dict

TYPESCRIPT
// Tipo dicionário
Schema.dict(
  Schema.string(),           // Tipo do valor
  Schema.string()            // Tipo da chave (opcional)
)

4. Modificadores Encadeáveis

(1) .required()

Marca como obrigatório. Quando o usuário não fornece, o framework reporta erro e bloqueia o carregamento.

TYPESCRIPT
apiKey: Schema.string().required()

(2) .default(value)

Define um valor padrão. Quando o usuário não fornece, o padrão é usado sem erro.

TYPESCRIPT
maxRetries: Schema.number().default(3)
timeout: Schema.number().default(30000)

(3) .description(text)

Adiciona uma descrição a um item de configuração, exibida na Web UI como texto de dica para rótulos de formulário.

TYPESCRIPT
apiKey: Schema.string().required()
  .description('Chave de API obtida no painel do serviço')

(4) .min() / .max()

Limites de faixa numérica ou comprimento de string:

TYPESCRIPT
port: Schema.number().min(1).max(65535).default(8080)
name: Schema.string().min(1).max(50)

(5) .pattern()

Validação regex:

TYPESCRIPT
email: Schema.string().pattern(/^[^@]+@[^@]+\.[^@]+$/)
  .description('Endereço de email válido')

(6) .step()

Passo numérico, afeta a precisão do slider na UI:

TYPESCRIPT
timeout: Schema.number().min(1000).max(300000).step(1000).default(30000)

(7) Uso Combinado

▶ Exemplo 3: Config Completa com Múltiplos Modificadores

TYPESCRIPT
const Config = Schema.object({
  apiKey: Schema.string()
    .required()
    .pattern(/^sk-[a-zA-Z0-9]+$/)
    .description('Chave de API DeepSeek (começa com sk-)'),
  
  maxTokens: Schema.number()
    .min(1).max(32768)
    .default(4096)
    .description('Máximo de tokens por requisição'),
  
  model: Schema.union(['deepseek-chat', 'deepseek-reasoner'])
    .default('deepseek-chat')
    .description('Modelo a usar'),
  
  temperature: Schema.number()
    .min(0).max(2).step(0.1)
    .default(0.7)
    .description('Temperatura de amostragem')
})

5. Configuração Aninhada

(1) Objetos Aninhados

TYPESCRIPT
const Config = Schema.object({
  database: Schema.object({
    host: Schema.string().default('localhost'),
    port: Schema.number().default(5432),
    name: Schema.string().required(),
    ssl: Schema.boolean().default(false)
  }).default({ host: 'localhost', port: 5432, ssl: false }),

  cache: Schema.object({
    enabled: Schema.boolean().default(true),
    ttl: Schema.number().default(3600).description('TTL do cache em segundos')
  }).default({ enabled: true, ttl: 3600 })
})

(2) Aninhamento Profundo

TYPESCRIPT
const Config = Schema.object({
  llm: Schema.object({
    provider: Schema.union(['deepseek', 'openai']).default('deepseek'),
    deepseek: Schema.object({
      apiKey: Schema.string().required(),
      model: Schema.string().default('deepseek-chat')
    }),
    openai: Schema.object({
      apiKey: Schema.string(),
      endpoint: Schema.string().default('https://api.openai.com/v1')
    })
  })
})

(3) Schema Reutilizável

TYPESCRIPT
const ConnectionSchema = Schema.object({
  host: Schema.string().default('localhost'),
  port: Schema.number().default(5432),
  timeout: Schema.number().default(5000)
})

const Config = Schema.object({
  primary: ConnectionSchema.description('Conexão primária'),
  replica: ConnectionSchema.description('Conexão réplica')
})

6. Exibição de Configuração na Página de Configurações da Web UI

(1) Geração Automática de Formulários

Config definida com Schemastery automaticamente gera formulários na página de configurações da Web UI:

Tipo Schema Controle UI
Schema.string() Campo de texto
Schema.number() Campo numérico / slider
Schema.boolean() Switch toggle
Schema.union() Select dropdown
Schema.array() Editor de lista
Schema.object() Painel agrupado
Schema.dict() Editor chave-valor

(2) Exibição de Descrição

A .description() de cada campo aparece como texto de dica abaixo do input:

TEXT 📖 Somente leitura
┌─────────────────────────────────────────┐
│ Chave de API                             │
│ [sk-xxxxxxxxxxxxxxx                   ] │
│ Chave de API DeepSeek (começa com sk-)   │
├─────────────────────────────────────────┤
│ Máx. Tokens                              │
│ [4096                                 ] │
│ Máximo de tokens por requisição          │
└─────────────────────────────────────────┘

(3) Feedback de Validação

Quando o input do usuário não corresponde ao Schema, a UI mostra feedback imediato:

TEXT 📖 Somente leitura
┌─────────────────────────────────────────┐
│ Chave de API                             │
│ [invalid-key                          ] │
│ ❌ Deve corresponder ao padrão: /^sk-[a-zA-Z0-9]+$/ │
└─────────────────────────────────────────┘

7. Validação de Configuração e Mensagens de Erro

(1) Validação na Inicialização

Quando um plugin carrega, o framework automaticamente valida sua configuração:

TYPESCRIPT
const Config = Schema.object({
  port: Schema.number().min(1).max(65535)
})

// Config do usuário: port: -1
// → Erro: Config inválida para plugin my-plugin:
//   port: deve ser >= 1

Quando a validação falha, o plugin não é carregado e o erro é exibido no terminal.

(2) Segurança de Tipo

TypeScript automaticamente infere o tipo de ctx.config a partir da definição Config:

TYPESCRIPT
const Config = Schema.object({
  apiKey: Schema.string().required(),
  maxRetries: Schema.number().default(3)
})

export function apply(ctx: Context) {
  ctx.config.apiKey     // string ✅
  ctx.config.maxRetries // number ✅
  ctx.config.unknown    // Erro de tipo ❌
}

(3) Validação Customizada

TYPESCRIPT
const Config = Schema.object({
  startDate: Schema.string().required(),
  endDate: Schema.string().required()
}).validate((value) => {
  if (new Date(value.startDate) > new Date(value.endDate)) {
    throw new Error('startDate deve ser anterior a endDate')
  }
  return value
})

8. Atualizações Dinâmicas de Configuração

(1) Escuta de Mudanças de Configuração

TYPESCRIPT
export function apply(ctx: Context) {
  ctx.on('config/updated', (newConfig) => {
    ctx.logger.info('config atualizada:', newConfig)
    // Ajustar comportamento com base na nova config
  })
}

(2) Fluxo de Atualização a Quente

100%
graph LR
    UI[Usuário modifica config] --> VALID[Validação Schema]
    VALID --> APPLY[Aplicar nova config]
    APPLY --> EMIT[Emitir config/updated]
    EMIT --> RELOAD[Plugin responde à atualização]

(3) Configs Que Requerem Reinicialização

Algumas mudanças de configuração (como números de porta ou injeção de dependência) requerem reinicialização:

TYPESCRIPT
export function apply(ctx: Context) {
  ctx.on('config/updated', (config) => {
    if (config.port !== ctx.config.port) {
      ctx.logger.warn('mudança de porta requer reinicialização')
    }
  })
}

❓ Perguntas Frequentes

P Config deve ser exportada com o nome Config?
R Sim, a convenção do framework procura por export const Config. Outros nomes não serão reconhecidos.
P Posso adicionar itens de configuração dinamicamente em runtime?
R Não recomendado. Config deve ser definida antes do carregamento do plugin. Se precisar de comportamento dinâmico, use ctx.on('config/updated') para responder a mudanças de configuração.
P Como organizar muitos itens de configuração?
R Use Schema.object aninhado para agrupamento, cada grupo com uma descrição clara. A Web UI renderiza objetos aninhados como painéis colapsáveis.
P Como proteger informações sensíveis como chaves de API?
R Schemastery suporta o modificador .hidden(), que exibe um campo de senha na UI: typescript apiKey: Schema.string().required().hidden()
P Valores de configuração podem ser funções?
R Não. Configuração deve ser valores serializáveis em JSON (string/number/boolean/object/array). Comportamento de função deve ser implementado em apply.
P Configurações de múltiplos plugins entrarão em conflito?
R Não. Cada plugin tem um namespace de configuração independente plugins.plugin-name.config, isolado entre si.

📖 Resumo


📝 Exercícios

1. ⭐ Básico: Adicione Config à ferramenta file_count com defaultPath (string, padrão diretório atual) e maxDepth (number, padrão 10). Verifique a geração do formulário na página de configurações da Web UI.

2. ⭐⭐ Intermediário: Escreva um plugin de configuração de múltiplas conexões. Config contém connections (array de objetos, cada um com host/port/username/password), definido com Schema.object aninhado. Verifique: erros quando campos obrigatórios estão ausentes, valores padrão preenchem corretamente.

3. ⭐⭐⭐ Desafio: Crie uma configuração com validação customizada: startDate e endDate devem satisfazer startDate < endDate; maxRetries deve ser um inteiro positivo. Teste: insira valores inválidos e confirme que as mensagens de erro de validação são exibidas corretamente na Web UI.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%