UNPKG

openai-mock-api

Version:

A mock OpenAI API server for testing LLM applications

108 lines 4.98 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ConfigLoader = void 0; const fs_1 = require("fs"); const yaml_1 = __importDefault(require("yaml")); class ConfigLoader { constructor(logger) { this.logger = logger; } async load(configPath) { try { let fileContent; if (configPath === '-') { this.logger.debug('Loading configuration from stdin'); fileContent = await this.readFromStdin(); } else { this.logger.debug(`Loading configuration from ${configPath}`); fileContent = (0, fs_1.readFileSync)(configPath, 'utf-8'); } const config = yaml_1.default.parse(fileContent); this.validateConfig(config); this.logger.debug('Configuration loaded successfully', { responseCount: config.responses.length, port: config.port, }); return config; } catch (error) { this.logger.error(`Failed to load configuration: ${error}`); const source = configPath === '-' ? 'stdin' : configPath; throw new Error(`Failed to load configuration from ${source}: ${error}`); } } readFromStdin() { return new Promise((resolve, reject) => { let data = ''; process.stdin.setEncoding('utf8'); process.stdin.on('data', (chunk) => { data += chunk; }); process.stdin.on('end', () => { resolve(data); }); process.stdin.on('error', (err) => { reject(err); }); // Start reading process.stdin.resume(); }); } validateConfig(config) { if (!config.apiKey) { throw new Error('Configuration must include an apiKey'); } if (!config.responses || !Array.isArray(config.responses)) { throw new Error('Configuration must include a responses array'); } if (config.responses.length === 0) { throw new Error('Configuration must include at least one response'); } for (const [index, response] of config.responses.entries()) { if (!response.id) { throw new Error(`Response at index ${index} must have an id`); } if (!response.messages || !Array.isArray(response.messages)) { throw new Error(`Response ${response.id} must have a messages array`); } if (response.messages.length === 0) { throw new Error(`Response ${response.id} must have at least one message`); } for (const [msgIndex, message] of response.messages.entries()) { if (!['system', 'user', 'assistant', 'tool'].includes(message.role)) { throw new Error(`Response ${response.id} message ${msgIndex} role must be 'system', 'user', 'assistant', or 'tool'`); } if (message.matcher && !['exact', 'fuzzy', 'regex', 'contains', 'any'].includes(message.matcher)) { throw new Error(`Response ${response.id} message ${msgIndex} matcher type must be 'exact', 'fuzzy', 'regex', 'contains', or 'any'`); } if (message.matcher === 'fuzzy' && typeof message.threshold !== 'number') { throw new Error(`Response ${response.id} message ${msgIndex} fuzzy matcher must have a threshold number`); } if (message.matcher === 'any' && message.content !== undefined) { throw new Error(`Response ${response.id} message ${msgIndex} with 'any' matcher should not have content`); } if (message.matcher !== 'any' && message.role !== 'assistant' && !message.content && !message.tool_calls) { throw new Error(`Response ${response.id} message ${msgIndex} must have content or tool_calls`); } if (message.role === 'tool' && !message.tool_call_id) { throw new Error(`Response ${response.id} message ${msgIndex} with role 'tool' must have tool_call_id`); } } // Validate that there's at least one assistant message to use as response const assistantMessages = response.messages.filter((msg) => msg.role === 'assistant'); if (assistantMessages.length === 0) { throw new Error(`Response ${response.id} must have at least one assistant message`); } } } } exports.ConfigLoader = ConfigLoader; //# sourceMappingURL=config.js.map