All files mineflayer-chatgpt.js

100% Statements 156/156
95.83% Branches 23/24
100% Functions 3/3
100% Lines 156/156

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 1571x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 15x 15x 15x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 1x 1x 12x 12x 12x 12x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 13x 1x 1x 10x 13x 2x 2x 2x 25x 25x 1x 1x 1x 1x 1x 1x  
"use strict";
import MessageClient from "./message-client.js";
import ModerationClient from "./moderation-client.js";
import Memory from "./memory.js";
import moderator from "./moderator.js";
import {
  validateCoolDownInSeconds,
  validateEnableMessageLogging,
  validateEnableModeration,
  validateEnableSecurityInstructions,
  validateFallbackMessage,
  validateJailbreakConfidenceScore,
  validateReplyConfidenceScore,
} from "./validator.js";
 
const DEFAULT_ENABLE_MODERATION = true;
const DEFAULT_ENABLE_MESSAGE_LOGGING = false;
const DEFAULT_MINIMUM_REPLY_CONFIDENCE_SCORE = 0.9;
const DEFAULT_MINIMUM_JAILBREAK_CONFIDENCE_SCORE = 0.7;
const DEFAULT_COOL_DOWN_IN_SECONDS = 15;
const DEFAULT_FALLBACK_MESSAGE =
  "Sorry, I cannot provide a response to that message.";
const DEFAULT_ENABLE_SECURITY_INSTRUCTIONS = true;
 
let memory;
 
/**
 * Register the Mineflayer ChatGPT plugin on a bot instance.
 *
 * @param {object} bot - Mineflayer bot instance.
 */
function chatgpt(bot) {
  let messageClient;
  let moderationClient;
  let enableModeration;
  let enableMessageLogging;
  let minimumReplyConfidenceScore;
  let minimumJailbreakConfidenceScore;
  let coolDownInSeconds;
  let fallbackMessage;
 
  bot.chatgpt = {};
 
  /**
   * Configure the plugin instance.
   *
   * @param {object} [opts={}] - Plugin options.
   * @param {string} opts.messageApiKey - API key for the chat completion endpoint. Can be a placeholder value when `messageBaseURL` points at a local LLM server (e.g. vMLX) that doesn't require authentication.
   * @param {string} [opts.model='gpt-5.6'] - Chat completion model. The minimum supported OpenAI model is GPT-5.6.
   * @param {string} [opts.moderationApiKey] - OpenAI API key used for moderation and jailbreak detection. Required when `enableModeration` is `true`.
   * @param {string} [opts.messageBaseURL] - Base URL of the chat completion endpoint. Set this to use a local OpenAI-compatible LLM server (e.g. vMLX) instead of OpenAI.
   * @param {number} [opts.minimumReplyConfidenceScore=0.9] - Minimum confidence required to accept a model reply.
   * @param {number} [opts.minimumJailbreakConfidenceScore=0.7] - Minimum OpenAI Guardrails confidence required to flag a jailbreak attempt.
   */
  bot.chatgpt.setConfig = (opts) => {
    opts = opts || {};
    enableModeration =
      opts.enableModeration === undefined
        ? DEFAULT_ENABLE_MODERATION
        : opts.enableModeration;
    validateEnableModeration(enableModeration);
    enableMessageLogging =
      opts.enableMessageLogging === undefined
        ? DEFAULT_ENABLE_MESSAGE_LOGGING
        : opts.enableMessageLogging;
    validateEnableMessageLogging(enableMessageLogging);
    minimumReplyConfidenceScore =
      opts.minimumReplyConfidenceScore ??
      DEFAULT_MINIMUM_REPLY_CONFIDENCE_SCORE;
    validateReplyConfidenceScore(minimumReplyConfidenceScore);
    minimumJailbreakConfidenceScore =
      opts.minimumJailbreakConfidenceScore ??
      DEFAULT_MINIMUM_JAILBREAK_CONFIDENCE_SCORE;
    validateJailbreakConfidenceScore(minimumJailbreakConfidenceScore);
    coolDownInSeconds =
      opts.coolDownInSeconds === undefined
        ? DEFAULT_COOL_DOWN_IN_SECONDS
        : opts.coolDownInSeconds;
    validateCoolDownInSeconds(coolDownInSeconds);
    fallbackMessage =
      opts.fallbackMessage === undefined
        ? DEFAULT_FALLBACK_MESSAGE
        : opts.fallbackMessage;
    validateFallbackMessage(fallbackMessage);
    opts.enableSecurityInstructions =
      opts.enableSecurityInstructions === undefined
        ? DEFAULT_ENABLE_SECURITY_INSTRUCTIONS
        : opts.enableSecurityInstructions;
    validateEnableSecurityInstructions(opts.enableSecurityInstructions);
    messageClient = new MessageClient(opts.messageApiKey, {
      model: opts.model,
      instructions: opts.instructions,
      enableSecurityInstructions: opts.enableSecurityInstructions,
      baseURL: opts.messageBaseURL,
    });
    if (enableModeration === true) {
      moderationClient = new ModerationClient(opts.moderationApiKey);
    }
    memory = new Memory(opts.historySize);
  };
 
  /**
   * Send a message through the plugin and return the final reply.
   *
   * @param {string} player - Player name or id.
   * @param {string} message - Message to send.
   * @returns {Promise<string>} Final reply text.
   */
  bot.chatgpt.sendMessage = async (player, message) => {
    try {
      if (enableModeration === true) {
        const moderatedOutbound = await moderator.moderateOutboundMessage(
          moderationClient,
          memory,
          player,
          message,
          fallbackMessage,
          coolDownInSeconds,
          minimumJailbreakConfidenceScore,
        );
        if (moderatedOutbound.flagged) {
          return moderatedOutbound.message;
        }
        message = moderatedOutbound.message;
      }
 
      const chatResult = await messageClient.chat(memory, player, message);
      let reply = chatResult.reply;
      const confidenceScore = chatResult.confidenceScore;
 
      if (enableModeration === true) {
        const moderatedInbound = await moderator.moderateInboundReply(
          moderationClient,
          reply,
          fallbackMessage,
          confidenceScore,
          minimumReplyConfidenceScore,
        );
        reply = moderatedInbound.reply;
      }
      if (enableMessageLogging === true) {
        console.log(`Player ${player} received a reply from ChatGPT: ${reply}`);
      }
      return reply;
    } catch (error) {
      console.error(`An unexpected error has occurred: ${error.message}`);
      throw error;
    }
  };
}
 
const exports = {
  chatgpt: chatgpt,
};
 
export { exports as default };