@peopl-health/nexus 4.5.28 → 4.5.30

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.
@@ -1,12 +1,10 @@
1
- const { OpenAI } = require('openai');
2
-
3
1
  const { getCurrentMexicoDateTime } = require('../utils/dateUtils');
4
2
  const { retryWithBackoff } = require('../utils/retryUtils');
5
3
  const { logger } = require('../utils/logger');
6
4
  const { Thread } = require('../models/threadModel');
7
5
  const { DefaultMemoryManager } = require('../memory/DefaultMemoryManager');
8
6
  const { EnhancedMemoryManager } = require('../memory/EnhancedMemoryManager');
9
- const { OpenAIResponsesProvider } = require('../providers/OpenAIResponsesProvider');
7
+ const { PROVIDER_VARIANTS } = require('../providers/createLLMProvider');
10
8
  const { handleFunctionCalls } = require('../providers/OpenAIResponsesProviderTools');
11
9
  const { composePrompt, resolveTools } = require('../services/promptComposerService');
12
10
  const { getToolSchemas: getRegistrySchemas } = require('../services/toolRegistryService');
@@ -40,14 +38,20 @@ class EvalProvider {
40
38
  this.presetId = config.presetId || null;
41
39
  this.label = options.label || config.label || `nexus:${this.model}`;
42
40
 
43
- this.client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
44
41
  this.memoryManager = config.memoryManager || (
45
42
  config.memoryStrategy === 'enhanced' ? new EnhancedMemoryManager() : new DefaultMemoryManager()
46
43
  );
47
- this.provider = new OpenAIResponsesProvider({
48
- client: this.client,
44
+ const variant = (config.variant || process.env.VARIANT || 'responses').toString().toLowerCase();
45
+ const ProviderClass = PROVIDER_VARIANTS[variant];
46
+ if (!ProviderClass) {
47
+ throw new Error(`Invalid LLM provider variant for eval: '${variant}'. Available: ${Object.keys(PROVIDER_VARIANTS).join(', ')}`);
48
+ }
49
+ this.provider = new ProviderClass({
49
50
  defaultModels: { responseModel: this.model },
51
+ conversationManager: this.memoryManager,
50
52
  });
53
+ this.client = this.provider.getClient();
54
+ this.model = this.provider._mapModelConfig({ model: this.model }).model;
51
55
  this.phiProcessor = new PhiProcessor({
52
56
  encode: config.phi?.encode || false,
53
57
  ner: config.phi?.ner || null,
@@ -184,7 +188,7 @@ class EvalProvider {
184
188
  const input = [{ role: 'developer', content: devContent }, ...memoryMessage, ...convertedMessages];
185
189
  const apiConfig = { input, instructions: devContent || '' };
186
190
 
187
- if (assistantId) {
191
+ if (assistantId && this.provider.supportsPromptRegistry) {
188
192
  apiConfig.prompt = { id: assistantId, variables: promptVariables };
189
193
  const version = this.promptVersions[assistantId];
190
194
  if (version) apiConfig.prompt.version = String(version);
package/lib/index.js CHANGED
@@ -4,6 +4,7 @@ const { createStorage } = require('./storage/registry');
4
4
  const { MessageParser } = require('./core/MessageParser');
5
5
  const { createLLMProvider } = require('./providers/createLLMProvider');
6
6
  const { OpenAIResponsesProvider } = require('./providers/OpenAIResponsesProvider');
7
+ const { OpenRouterProvider } = require('./providers/OpenRouterProvider');
7
8
  const { logger } = require('./utils/logger');
8
9
  const runtimeConfig = require('./config/runtimeConfig');
9
10
  const llmConfigModule = require('./config/llmConfig');
@@ -197,6 +198,7 @@ module.exports = {
197
198
  MessageParser,
198
199
  createLLMProvider,
199
200
  OpenAIResponsesProvider,
201
+ OpenRouterProvider,
200
202
  BaseAssistant,
201
203
  registerAssistant,
202
204
  overrideGetAssistantById,
@@ -15,7 +15,6 @@ const MAX_ITEMS_ON_CREATE = 20;
15
15
  const MAX_ITEMS_PER_BATCH = 20;
16
16
  const DEFAULT_MAX_HISTORICAL_MESSAGES = parseInt(process.env.MAX_HISTORICAL_MESSAGES || '50', 10);
17
17
  const MAX_FUNCTION_ROUNDS = parseInt(process.env.MAX_FUNCTION_ROUNDS || '5', 10);
18
- const PROVIDER_NAME = 'OpenAIResponsesProvider';
19
18
 
20
19
  class OpenAIResponsesProvider extends BaseLLMProvider {
21
20
  constructor(options = {}) {
@@ -43,6 +42,7 @@ class OpenAIResponsesProvider extends BaseLLMProvider {
43
42
  };
44
43
 
45
44
  this.variant = 'responses';
45
+ this.supportsPromptRegistry = true;
46
46
 
47
47
  this.responses = this.client.responses;
48
48
  this.conversations = this.client.conversations;
@@ -84,7 +84,7 @@ class OpenAIResponsesProvider extends BaseLLMProvider {
84
84
  };
85
85
  const { result } = await retryWithBackoff(
86
86
  () => this.conversations.create(payload),
87
- { providerName: PROVIDER_NAME }
87
+ { providerName: this.constructor.name }
88
88
  );
89
89
  return result;
90
90
  }
@@ -97,7 +97,7 @@ class OpenAIResponsesProvider extends BaseLLMProvider {
97
97
  const batch = this._convertItemsToApiFormat(items.slice(i, i + batchSize));
98
98
  await retryWithBackoff(
99
99
  () => this.conversations.items.create(id, { items: batch }),
100
- { providerName: PROVIDER_NAME }
100
+ { providerName: this.constructor.name }
101
101
  );
102
102
  }
103
103
  logger.info(`[_addItemsInBatches] Added ${items.length} messages in ${Math.ceil(items.length / batchSize)} batches`);
@@ -211,13 +211,13 @@ class OpenAIResponsesProvider extends BaseLLMProvider {
211
211
  if (promptVersion) promptConfig.version = String(promptVersion);
212
212
 
213
213
  const apiCallConfig = {
214
- ...modelConfig,
214
+ ...this._mapModelConfig(modelConfig),
215
215
  instructions: instructions || additionalInstructions || devContent || '',
216
216
  metadata,
217
217
  tool_choice: prePromptResult?.toolChoice || toolChoice
218
218
  };
219
219
 
220
- if (!resolvedPresetId) {
220
+ if (!resolvedPresetId && this.supportsPromptRegistry) {
221
221
  apiCallConfig.prompt = promptConfig;
222
222
  }
223
223
  if (activeToolSchemas.length > 0) {
@@ -232,7 +232,7 @@ class OpenAIResponsesProvider extends BaseLLMProvider {
232
232
 
233
233
  const makeAPICall = (inputData) => retryWithBackoff(
234
234
  () => this.client.responses.create({ input: inputData, ...apiCallConfig }),
235
- { providerName: PROVIDER_NAME }
235
+ { providerName: this.constructor.name }
236
236
  );
237
237
 
238
238
  const { result: response, retries } = await makeAPICall(input);
@@ -280,6 +280,10 @@ class OpenAIResponsesProvider extends BaseLLMProvider {
280
280
  return result;
281
281
  }
282
282
 
283
+ _mapModelConfig(modelConfig) {
284
+ return modelConfig;
285
+ }
286
+
283
287
  async transcribeAudio({ file, model, language, responseFormat, temperature, prompt } = {}) {
284
288
  return this.client.audio.transcriptions.create({
285
289
  model: model || this.defaults.transcriptionModel,
@@ -0,0 +1,67 @@
1
+ const { OpenAI } = require('openai');
2
+
3
+ const { OpenAIResponsesProvider } = require('./OpenAIResponsesProvider');
4
+
5
+ const OPENROUTER_BASE_URL = 'https://openrouter.ai/api/v1';
6
+ const DEFAULT_MODEL_VENDOR = 'openai';
7
+
8
+ class OpenRouterProvider extends OpenAIResponsesProvider {
9
+ constructor(options = {}) {
10
+ const {
11
+ apiKey = process.env.OPENROUTER_API_KEY,
12
+ baseURL = OPENROUTER_BASE_URL,
13
+ client,
14
+ } = options;
15
+
16
+ if (!client && !apiKey) {
17
+ throw new Error('OpenRouterProvider requires an API key or a preconfigured client');
18
+ }
19
+
20
+ super({ ...options, client: client || new OpenAI({ apiKey, baseURL }) });
21
+
22
+ this.variant = 'openrouter';
23
+ this.supportsPromptRegistry = false;
24
+ this.transcriptionClient = null;
25
+ }
26
+
27
+ _mapModelConfig(modelConfig) {
28
+ const mapped = { ...modelConfig };
29
+ mapped.model = this._toOpenRouterModel(mapped.model || this.defaults.responseModel);
30
+ return mapped;
31
+ }
32
+
33
+ _toOpenRouterModel(model) {
34
+ if (!model || model.includes('/')) return model;
35
+ return `${DEFAULT_MODEL_VENDOR}/${model}`;
36
+ }
37
+
38
+ async transcribeAudio({ file, model, language, responseFormat, temperature, prompt } = {}) {
39
+ if (!this.transcriptionClient) {
40
+ const apiKey = process.env.OPENAI_API_KEY;
41
+ if (!apiKey) {
42
+ throw new Error('transcribeAudio requires OPENAI_API_KEY; OpenRouter does not offer audio transcription');
43
+ }
44
+ this.transcriptionClient = new OpenAI({ apiKey });
45
+ }
46
+ return this.transcriptionClient.audio.transcriptions.create({
47
+ model: model || this.defaults.transcriptionModel,
48
+ file, language, response_format: responseFormat, temperature, prompt,
49
+ });
50
+ }
51
+
52
+ async createConversation() {
53
+ throw new Error('createConversation is not supported by OpenRouterProvider');
54
+ }
55
+
56
+ async addMessage() {
57
+ throw new Error('addMessage is not supported by OpenRouterProvider');
58
+ }
59
+
60
+ async listMessages() {
61
+ throw new Error('listMessages is not supported by OpenRouterProvider');
62
+ }
63
+ }
64
+
65
+ module.exports = {
66
+ OpenRouterProvider,
67
+ };
@@ -4,9 +4,11 @@ const { EnhancedMemoryManager } = require('../memory/EnhancedMemoryManager');
4
4
  const { SessionManager } = require('../memory/SessionManager');
5
5
 
6
6
  const { OpenAIResponsesProvider } = require('./OpenAIResponsesProvider');
7
+ const { OpenRouterProvider } = require('./OpenRouterProvider');
7
8
 
8
9
  const PROVIDER_VARIANTS = {
9
10
  responses: OpenAIResponsesProvider,
11
+ openrouter: OpenRouterProvider,
10
12
  };
11
13
 
12
14
  function createLLMProvider(config = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peopl-health/nexus",
3
- "version": "4.5.28",
3
+ "version": "4.5.30",
4
4
  "description": "Core messaging and assistant library for WhatsApp communication platforms",
5
5
  "keywords": [
6
6
  "whatsapp",