@peopl-health/nexus 3.8.2 → 3.8.3

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.
@@ -7,7 +7,7 @@ const { Thread } = require('../models/threadModel');
7
7
  const { DefaultMemoryManager } = require('../memory/DefaultMemoryManager');
8
8
  const { OpenAIResponsesProvider } = require('../providers/OpenAIResponsesProvider');
9
9
  const { handleFunctionCalls } = require('../providers/OpenAIResponsesProviderTools');
10
- const { composePrompt } = require('../services/promptComposerService');
10
+ const { composePrompt, resolveTools } = require('../services/promptComposerService');
11
11
  const { getAssistantById } = require('../services/assistantResolver');
12
12
 
13
13
  const MAX_FUNCTION_ROUNDS = parseInt(process.env.MAX_FUNCTION_ROUNDS || '5', 10);
@@ -123,9 +123,17 @@ class EvalProvider {
123
123
  try {
124
124
  assistant = getAssistantById(assistantId, thread);
125
125
  toolSchemas = assistant.getToolSchemas?.() || [];
126
- if (assistant.tools?.size && !Object.keys(this.promptVersions).length) {
127
- const toolNames = Array.from(assistant.tools.keys()).join(', ');
126
+ if (assistant.tools?.size) {
127
+ const { toolIds, filtered } = await resolveTools({ promptId: assistantId, assistant });
128
+ const activeToolNames = filtered && toolIds.length > 0
129
+ ? toolIds
130
+ : Array.from(assistant.tools.keys());
131
+ const toolNames = activeToolNames.join(', ');
128
132
  devContent += `\n\nYou only have access to these tools: ${toolNames}. Do not call or reference any tools not listed here.`;
133
+
134
+ if (filtered && toolIds.length > 0) {
135
+ toolSchemas = toolSchemas.filter(s => toolIds.includes(s.function?.name));
136
+ }
129
137
  }
130
138
  } catch {
131
139
  logger.warn('[NexusEvalProvider] Failed to resolve assistant', { assistantId });
@@ -154,9 +162,7 @@ class EvalProvider {
154
162
  apiConfig.tool_choice = this.toolChoice;
155
163
  }
156
164
 
157
- // Only send local tool schemas if NOT using a stored prompt with version
158
- // (stored prompts have their own tool definitions on the platform)
159
- if (toolSchemas.length > 0 && !apiConfig.prompt?.version) {
165
+ if (toolSchemas.length > 0) {
160
166
  apiConfig.tools = toolSchemas.map(schema => {
161
167
  if (schema.type === 'function' && schema.function) {
162
168
  const { name, description, parameters, strict } = schema.function;
@@ -320,7 +320,9 @@ class OpenAIResponsesProvider {
320
320
  const { toolIds, filtered } = await resolveTools({ promptId: assistantId, assistant });
321
321
  let devContent = resolvedPrompt;
322
322
  if (assistant?.tools?.size) {
323
- const activeToolNames = filtered ? toolIds : Array.from(assistant.tools.keys());
323
+ const activeToolNames = filtered && toolIds.length > 0
324
+ ? toolIds
325
+ : Array.from(assistant.tools.keys());
324
326
  const toolNames = activeToolNames.join(', ');
325
327
  devContent += `\n\nYou only have access to these tools: ${toolNames}. Do not call or reference any tools not listed here.`;
326
328
  }
@@ -333,14 +335,31 @@ class OpenAIResponsesProvider {
333
335
  if (promptVariables) promptConfig.variables = promptVariables;
334
336
  if (promptVersion) promptConfig.version = String(promptVersion);
335
337
 
336
- const makeAPICall = (inputData) => retryWithBackoff(() =>
337
- this.client.responses.create({
338
- prompt: promptConfig,
339
- input: inputData,
340
- instructions: instructions || additionalInstructions || '',
341
- metadata,
342
- tool_choice: toolChoice
343
- }), { providerName: PROVIDER_NAME });
338
+ const toolSchemas = assistant?.getToolSchemas?.() || [];
339
+ const activeToolSchemas = filtered && toolIds.length > 0
340
+ ? toolSchemas.filter(s => toolIds.includes(s.function?.name))
341
+ : toolSchemas;
342
+
343
+ const apiCallConfig = {
344
+ prompt: promptConfig,
345
+ instructions: instructions || additionalInstructions || '',
346
+ metadata,
347
+ tool_choice: toolChoice
348
+ };
349
+ if (activeToolSchemas.length > 0) {
350
+ apiCallConfig.tools = activeToolSchemas.map(schema => {
351
+ if (schema.type === 'function' && schema.function) {
352
+ const { name, description, parameters, strict } = schema.function;
353
+ return { type: 'function', name, description, parameters, strict };
354
+ }
355
+ return schema;
356
+ });
357
+ }
358
+
359
+ const makeAPICall = (inputData) => retryWithBackoff(
360
+ () => this.client.responses.create({ input: inputData, ...apiCallConfig }),
361
+ { providerName: PROVIDER_NAME }
362
+ );
344
363
 
345
364
  const { result: response, retries } = await makeAPICall(input);
346
365
  totalRetries += retries;
@@ -38,7 +38,7 @@ async function fetchSnippets(promptId) {
38
38
  snippetCache.set(cacheKey, snippets);
39
39
  return snippets;
40
40
  } catch (error) {
41
- logger.warn('[promptComposer] Failed to fetch snippets, continuing without them', {
41
+ logger.error('[promptComposer] Failed to fetch snippets', {
42
42
  promptId, error: error.message,
43
43
  });
44
44
  return [];
@@ -60,6 +60,11 @@ function applyVariables(text, variables) {
60
60
 
61
61
  async function composePrompt({ promptId, variables = null, status = null }) {
62
62
  const baseRecord = await fetchBasePrompt(promptId);
63
+
64
+ if (!baseRecord) {
65
+ logger.error('[promptComposer] Base prompt not found in Airtable', { promptId });
66
+ }
67
+
63
68
  let baseContent = baseRecord?.content || '';
64
69
 
65
70
  const snippets = await fetchSnippets(promptId);
@@ -67,11 +72,11 @@ async function composePrompt({ promptId, variables = null, status = null }) {
67
72
  ? snippets.filter(s => !s.status || s.status === status)
68
73
  : snippets;
69
74
 
70
- const sorted = sortSnippets(activeSnippets);
71
- const snippetIds = sorted.map(s => s.snippet_id || s.name || 'unknown');
75
+ const sorted = sortSnippets(activeSnippets).filter(s => s.content);
76
+ const snippetIds = sorted.map(s => s.snippet_id);
72
77
 
73
78
  if (sorted.length > 0) {
74
- const snippetTexts = sorted.map(s => s.content).filter(Boolean);
79
+ const snippetTexts = sorted.map(s => s.content);
75
80
  baseContent = [baseContent, ...snippetTexts].join('\n\n');
76
81
  }
77
82
 
@@ -102,7 +107,7 @@ async function fetchToolMapping(promptId) {
102
107
  toolCache.set(cacheKey, tools);
103
108
  return tools;
104
109
  } catch (error) {
105
- logger.warn('[promptComposer] Failed to fetch tool mapping, using all registered tools', {
110
+ logger.warn('[promptComposer] Failed to fetch tool mapping, returning empty list', {
106
111
  promptId, error: error.message,
107
112
  });
108
113
  return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peopl-health/nexus",
3
- "version": "3.8.2",
3
+ "version": "3.8.3",
4
4
  "description": "Core messaging and assistant library for WhatsApp communication platforms",
5
5
  "keywords": [
6
6
  "whatsapp",