chatwoot-develop/skills/creating-jasmine-tools/SKILL.md
2026-01-19 19:26:23 -03:00

4.0 KiB

name description
creating-jasmine-tools Defines the standard for creating Tools compatible with Jasmine (Captain AI) and the Agents gem. Use when the user needs to create a new Ruby tool class.

Objetivo

Padronizar a criação de ferramentas no escopo Captain::Tools para garantir compatibilidade com Agents::Tool, RubyLLM e o sistema de injeção de dependência da Jasmine.

Caminhos Padrão

  • Local principal: enterprise/lib/captain/tools/
  • Alternativo (se service-heavy): enterprise/app/services/captain/tools/

Template Base

module Captain
  module Tools
    class NomeDaSuaTool < Captain::Tools::BasePublicTool
      # Definir tool_name se for diferente do nome da classe (Opcional)
      # def name
      #   'nome_da_tool'
      # end

      def description
        'Descrição curta e objetiva do que a ferramenta faz. Isso é visível para a IA.'
      end

      # Definição de Parâmetros (DSL da gem Agents)
      param :parametro_um, type: 'string', desc: 'Descrição do parâmetro', required: true
      param :parametro_dois, type: 'integer', desc: 'Descrição do parâmetro opcional', required: false

      # Método principal de execução
      # tool_context: Objeto de contexto (pode conter estado da conversa)
      # kwargs: Argumentos passados pela IA já normalizados
      def perform(tool_context, **kwargs)
        # 1. Logging Inicial Padronizado
        Rails.logger.info "[#{self.class.name}] Iniciando execução. Params: #{kwargs.inspect}"

        # 2. Resolução de Dependências (Conversa/Contato)
        # O BasePublicTool já tenta popular @conversation e @user no initialize,
        # mas podemos garantir reload ou fallback aqui.
        ensure_context!(tool_context)

        return "Erro: Conversa não identificada." unless @conversation

        # 3. Lógica da Ferramenta
        parametro_um = kwargs[:parametro_um]

        result = executa_logica(parametro_um)

        # 4. Retorno
        # Sempre retornar String ou Hash serializável (JSON friendly)
        result
      rescue StandardError => e
        handle_error(e)
      end

      private

      def ensure_context!(tool_context)
        # Se @conversation não veio no initialize, tenta extrair do contexto
        if @conversation.nil? && tool_context.present?
             state = resolve_context(tool_context)
             @conversation = find_conversation(state)
        end
      end

      def executa_logica(dado)
        # Implementação...
        "Sucesso: #{dado}"
      end

      def handle_error(exception)
        Rails.logger.error "[#{self.class.name}] Erro: #{exception.message}"
        Rails.logger.error exception.backtrace.first(5).join("\n")
        "Ocorreu um erro técnico ao processar sua solicitação: #{exception.message}"
      end
    end
  end
end

Checklist de Verificação

  1. Herança: A classe herda de Captain::Tools::BasePublicTool (para tools públicas) ou Captain::Tools::BaseTool?
  2. Método perform: Está implementando perform ao invés de apenas execute (para compatibilidade total com Agents)?
  3. Parâmetros: Os parâmetros estão definidos com param :nome, type: ...? Isso ajuda a gerar o esquema JSON automaticamente para a LLM.
  4. Logging: Existe log no início (info) e no rescue (error) com prefixo [NomeClass]?
  5. Contexto: A ferramenta lida com o fato de @conversation poder ser nulo (ex: uso fora do fluxo web)?
  6. Retorno: O retorno é texto ou JSON string (algo que a LLM possa ler)?

Boas Práticas

  • Snake Case: Nomes de arquivo em snake_case (ex: check_availability_tool.rb).
  • Nomes Claros: O método name (ou o nome da classe inferido) deve ser claro (ex: consultar_saldo é melhor que acao_banco).
  • Idempotência: Se possível, a ferramenta deve ser segura de rodar múltiplas vezes (ex: checar disponibilidade não altera estado, reservar altera - cuidado).
  • Tratamento de Erros: Nunca deixe uma exception explodir para a LLM. Capture StandardError e retorne uma mensagem amigável de erro.