openai-api-mock 0.1.33 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2186,16 +2186,129 @@ function getImageResponce(requestBody) {
2186
2186
  data
2187
2187
  };
2188
2188
  }
2189
+ const RESPONSE_TEMPLATES = {
2190
+ SIMPLE_CHAT: {
2191
+ choices: [
2192
+ {
2193
+ finish_reason: "stop",
2194
+ index: 0,
2195
+ message: {
2196
+ content: "This is a consistent test response.",
2197
+ role: "assistant"
2198
+ },
2199
+ logprobs: null
2200
+ }
2201
+ ],
2202
+ created: 1640995200,
2203
+ id: "chatcmpl-test123456789",
2204
+ model: "gpt-3.5-mock",
2205
+ object: "chat.completion",
2206
+ usage: {
2207
+ completion_tokens: 10,
2208
+ prompt_tokens: 20,
2209
+ total_tokens: 30
2210
+ }
2211
+ },
2212
+ FUNCTION_CALL: {
2213
+ id: "chatcmpl-test123456789",
2214
+ object: "chat.completion",
2215
+ created: 1640995200,
2216
+ model: "gpt-3.5-mock",
2217
+ choices: [
2218
+ {
2219
+ index: 0,
2220
+ message: {
2221
+ role: "assistant",
2222
+ content: null,
2223
+ function_call: {
2224
+ name: "test_function",
2225
+ arguments: '{"param1": "test_value", "param2": 42}'
2226
+ }
2227
+ },
2228
+ finish_reason: "function_call"
2229
+ }
2230
+ ],
2231
+ usage: {
2232
+ prompt_tokens: 81,
2233
+ completion_tokens: 19,
2234
+ total_tokens: 100
2235
+ }
2236
+ },
2237
+ TOOL_CALL: {
2238
+ id: "chatcmpl-test123456789",
2239
+ object: "chat.completion",
2240
+ created: 1640995200,
2241
+ model: "gpt-3.5-mock",
2242
+ choices: [
2243
+ {
2244
+ index: 0,
2245
+ message: {
2246
+ role: "assistant",
2247
+ content: null,
2248
+ tool_calls: [
2249
+ {
2250
+ id: "call_test123456789",
2251
+ type: "function",
2252
+ function: {
2253
+ name: "test_function",
2254
+ arguments: '{"param1": "test_value", "param2": 42}'
2255
+ }
2256
+ }
2257
+ ]
2258
+ },
2259
+ finish_reason: "tool_calls"
2260
+ }
2261
+ ],
2262
+ usage: {
2263
+ prompt_tokens: 81,
2264
+ completion_tokens: 19,
2265
+ total_tokens: 100
2266
+ }
2267
+ },
2268
+ IMAGE_GENERATION: {
2269
+ created: 1640995200,
2270
+ data: [
2271
+ {
2272
+ url: "https://example.com/test-image.png"
2273
+ }
2274
+ ]
2275
+ }
2276
+ };
2277
+ function createResponseTemplate(templateType, overrides = {}) {
2278
+ const template = RESPONSE_TEMPLATES[templateType];
2279
+ if (!template) {
2280
+ throw new Error(`Unknown template type: ${templateType}`);
2281
+ }
2282
+ return deepMerge(template, overrides);
2283
+ }
2284
+ function deepMerge(target, source) {
2285
+ const result = { ...target };
2286
+ for (const key in source) {
2287
+ if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
2288
+ result[key] = deepMerge(result[key] || {}, source[key]);
2289
+ } else {
2290
+ result[key] = source[key];
2291
+ }
2292
+ }
2293
+ return result;
2294
+ }
2189
2295
  const OPEN_AI_BASE_URL = "https://api.openai.com";
2190
2296
  const CHAT_COMPLETIONS_ENDPOINT = "/v1/chat/completions";
2191
2297
  const IMAGE_GENERATIONS_ENDPOINT = "/v1/images/generations";
2192
- const customScopes = [];
2193
2298
  function mockOpenAIResponse(force = false, options = {}) {
2194
2299
  const {
2195
2300
  includeErrors = false,
2196
2301
  latency = 0,
2197
- logRequests = false
2302
+ logRequests = false,
2303
+ seed = null,
2304
+ useFixedResponses = false
2198
2305
  } = options;
2306
+ if (seed !== null) {
2307
+ f.seed(seed);
2308
+ if (logRequests) {
2309
+ console.log(`[openai-api-mock] Using seed for consistent outputs: ${seed}`);
2310
+ }
2311
+ }
2199
2312
  const env = process.env.NODE_ENV || "development";
2200
2313
  if (env !== "development" && !force) {
2201
2314
  return { isActive: false, stopMocking };
@@ -2216,12 +2329,21 @@ function mockOpenAIResponse(force = false, options = {}) {
2216
2329
  const stream = createChatStream(requestBody);
2217
2330
  return [200, stream];
2218
2331
  }
2332
+ if (useFixedResponses) {
2333
+ if (requestBody.tools) {
2334
+ return [200, createResponseTemplate("TOOL_CALL")];
2335
+ } else if (requestBody.functions) {
2336
+ return [200, createResponseTemplate("FUNCTION_CALL")];
2337
+ } else {
2338
+ return [200, createResponseTemplate("SIMPLE_CHAT")];
2339
+ }
2340
+ }
2219
2341
  return [200, getChatResponce(requestBody)];
2220
2342
  } catch (error) {
2221
2343
  console.error("[openai-api-mock] Error processing chat request:", error);
2222
2344
  return [500, { error: { message: "Internal server error in mock" } }];
2223
2345
  }
2224
- });
2346
+ }).persist();
2225
2347
  nock(OPEN_AI_BASE_URL).post(IMAGE_GENERATIONS_ENDPOINT).delay(latency).reply(function(uri, requestBody) {
2226
2348
  if (logRequests) {
2227
2349
  console.log(`[openai-api-mock] Image request:`, JSON.stringify(requestBody, null, 2));
@@ -2233,16 +2355,52 @@ function mockOpenAIResponse(force = false, options = {}) {
2233
2355
  if (includeErrors && Math.random() < 0.05) {
2234
2356
  return [400, { error: { message: "Your request was rejected as a result of our safety system." } }];
2235
2357
  }
2358
+ if (useFixedResponses) {
2359
+ return [200, createResponseTemplate("IMAGE_GENERATION")];
2360
+ }
2236
2361
  return [200, getImageResponce(requestBody)];
2237
2362
  } catch (error) {
2238
2363
  console.error("[openai-api-mock] Error processing image request:", error);
2239
2364
  return [500, { error: { message: "Internal server error in mock" } }];
2240
2365
  }
2241
- });
2366
+ }).persist();
2242
2367
  nock.enableNetConnect((host) => host !== "api.openai.com");
2243
2368
  return {
2244
2369
  isActive: true,
2245
2370
  stopMocking,
2371
+ /**
2372
+ * Resets the faker seed to ensure consistent outputs for subsequent requests
2373
+ * @param {number|string} newSeed - New seed value to use
2374
+ */
2375
+ setSeed(newSeed) {
2376
+ f.seed(newSeed);
2377
+ if (logRequests) {
2378
+ console.log(`[openai-api-mock] Seed updated to: ${newSeed}`);
2379
+ }
2380
+ },
2381
+ /**
2382
+ * Resets faker to use random values (removes deterministic behavior)
2383
+ */
2384
+ resetSeed() {
2385
+ f.seed();
2386
+ if (logRequests) {
2387
+ console.log(`[openai-api-mock] Seed reset - using random values`);
2388
+ }
2389
+ },
2390
+ /**
2391
+ * Get available response templates
2392
+ * @returns {Object} Available response templates
2393
+ */
2394
+ getResponseTemplates() {
2395
+ return RESPONSE_TEMPLATES;
2396
+ },
2397
+ /**
2398
+ * Create a custom response template
2399
+ * @param {string} templateType - Type of template to use
2400
+ * @param {Object} overrides - Values to override in the template
2401
+ * @returns {Object} Response template with overrides applied
2402
+ */
2403
+ createResponseTemplate,
2246
2404
  /**
2247
2405
  * Adds a custom endpoint mock
2248
2406
  * @param {string} method - HTTP method (e.g., 'GET', 'POST')
@@ -2251,14 +2409,12 @@ function mockOpenAIResponse(force = false, options = {}) {
2251
2409
  */
2252
2410
  addCustomEndpoint(method, path, handler) {
2253
2411
  const methodLower = method.toLowerCase();
2254
- const scope = nock(OPEN_AI_BASE_URL)[methodLower](path).reply(handler).persist();
2255
- customScopes.push(scope);
2412
+ nock(OPEN_AI_BASE_URL)[methodLower](path).reply(handler).persist();
2256
2413
  }
2257
2414
  };
2258
2415
  }
2259
2416
  function stopMocking() {
2260
2417
  nock.cleanAll();
2261
- customScopes.forEach((scope) => scope.persist(false));
2262
2418
  }
2263
2419
  export {
2264
2420
  mockOpenAIResponse,