@aj-archipelago/cortex 1.3.64 → 1.3.65

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/README.md CHANGED
@@ -843,11 +843,60 @@ mutation DeletePathway($name: String!, $userId: String!, $secret: String!, $key:
843
843
  3. Executing a dynamic pathway:
844
844
 
845
845
  ```graphql
846
- query ExecuteWorkspace($userId: String!, $pathwayName: String!, $text: String!) {
846
+ query ExecuteWorkspace($userId: String!, $pathwayName: String!, $text: String, $promptNames: [String]) {
847
+ executeWorkspace(userId: $userId, pathwayName: $pathwayName, text: $text, promptNames: $promptNames) {
848
+ result
849
+ debug
850
+ resultData
851
+ previousResult
852
+ warnings
853
+ errors
854
+ contextId
855
+ tool
856
+ }
857
+ }
858
+ ```
859
+
860
+ **Parameters:**
861
+ - `userId`: The user identifier for the pathway
862
+ - `pathwayName`: The name of the pathway to execute
863
+ - `text`: Optional input text for the pathway
864
+ - `promptNames`: Optional array of specific prompt names to execute
865
+ - If omitted: executes prompts serially (default behavior)
866
+ - If specific names provided: executes only those prompts in parallel
867
+ - If `["*"]`: executes all prompts in parallel
868
+
869
+ **Response Formats:**
870
+ - **Serial execution**: Returns single result string in `result` field
871
+ - **Parallel execution**: Returns JSON stringified array in `result` field:
872
+ ```json
873
+ "[{\"result\": \"<prompt 1 result>\", \"promptName\": \"<prompt 1 name>\"}, {\"result\": \"<prompt 2 result>\", \"promptName\": \"<prompt 2 name>\"}]"
874
+ ```
875
+
876
+ **Note**: The `executeWorkspace` query returns a single `ExecuteWorkspaceResult` object (not an array). For parallel execution, multiple results are JSON-encoded within the `result` field of this single response object.
877
+
878
+ **Examples:**
879
+ ```graphql
880
+ # Execute serially (default)
881
+ query ExecuteWorkspace($userId: String!, $pathwayName: String!, $text: String) {
847
882
  executeWorkspace(userId: $userId, pathwayName: $pathwayName, text: $text) {
848
883
  result
849
884
  }
850
885
  }
886
+
887
+ # Execute specific prompts in parallel
888
+ query ExecuteWorkspace($userId: String!, $pathwayName: String!, $text: String, $promptNames: [String]) {
889
+ executeWorkspace(userId: $userId, pathwayName: $pathwayName, text: $text, promptNames: ["Grammar Check", "Tone Analysis"]) {
890
+ result
891
+ }
892
+ }
893
+
894
+ # Execute all prompts in parallel
895
+ query ExecuteWorkspace($userId: String!, $pathwayName: String!, $text: String, $promptNames: [String]) {
896
+ executeWorkspace(userId: $userId, pathwayName: $pathwayName, text: $text, promptNames: ["*"]) {
897
+ result
898
+ }
899
+ }
851
900
  ```
852
901
 
853
902
  ### Security
@@ -286,10 +286,88 @@ class PathwayManager {
286
286
  await this.storage.save(pathways);
287
287
  }
288
288
 
289
+ /**
290
+ * Checks if the prompts are in legacy format (array of strings) vs new format (array of objects).
291
+ * @param {string} userId - The user ID to look up pathways for.
292
+ * @param {string} pathwayName - The pathway name to examine prompts from.
293
+ * @returns {boolean} True if prompts are in legacy format (array of strings), false if new format (array of objects).
294
+ */
295
+ isLegacyPromptFormat(userId, pathwayName) {
296
+ if (!userId || typeof userId !== 'string') {
297
+ throw new Error('userId must be a non-empty string');
298
+ }
299
+
300
+ if (!pathwayName || typeof pathwayName !== 'string') {
301
+ throw new Error('pathwayName must be a non-empty string');
302
+ }
303
+
304
+ // Check if the pathway exists
305
+ if (!this.pathways[userId] || !this.pathways[userId][pathwayName]) {
306
+ throw new Error(`Pathway '${pathwayName}' not found for user '${userId}'`);
307
+ }
308
+
309
+ const prompts = this.pathways[userId][pathwayName].prompt;
310
+
311
+ if (!Array.isArray(prompts)) {
312
+ throw new Error('prompts must be an array');
313
+ }
314
+
315
+ if (prompts.length === 0) {
316
+ return false; // Empty array defaults to new format
317
+ }
318
+
319
+ // Check if all items are strings (legacy format)
320
+ const allStrings = prompts.every(prompt => typeof prompt === 'string');
321
+
322
+ // Check if all items are objects with required properties (new format)
323
+ const allObjects = prompts.every(prompt =>
324
+ typeof prompt === 'object' &&
325
+ prompt !== null &&
326
+ typeof prompt.prompt === 'string'
327
+ );
328
+
329
+ if (allStrings) {
330
+ return true; // Legacy format
331
+ } else if (allObjects) {
332
+ return false; // New format
333
+ } else {
334
+ // Mixed format - treat as legacy for backward compatibility
335
+ return true;
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Creates a Prompt object from a prompt item and system prompt.
341
+ * @param {(string|Object)} promptItem - The prompt item (string or {name, prompt} object).
342
+ * @param {string} systemPrompt - The system prompt to prepend.
343
+ * @param {string} [defaultName] - Default name to use if promptItem is a string or if the object doesn't have a name.
344
+ * @returns {Prompt} A new Prompt object.
345
+ */
346
+ _createPromptObject(promptItem, systemPrompt, defaultName = null) {
347
+ // Handle both old format (strings) and new format (objects with name and prompt)
348
+ const promptText = typeof promptItem === 'string' ? promptItem : promptItem.prompt;
349
+ const promptName = typeof promptItem === 'string' ? defaultName : (promptItem.name || defaultName);
350
+
351
+ const messages = [
352
+ // Add the original prompt as a user message
353
+ { "role": "user", "content": `{{text}}\n\n${promptText}` },
354
+ ];
355
+
356
+ // Only include system message if systemPrompt has content
357
+ if (systemPrompt && systemPrompt.trim() !== "") {
358
+ messages.unshift({ "role": "system", "content": systemPrompt });
359
+ }
360
+
361
+ return new Prompt({
362
+ name: promptName,
363
+ messages: messages
364
+ });
365
+ }
366
+
289
367
  /**
290
368
  * Transforms the prompts in a pathway to include the system prompt.
291
369
  * @param {Object} pathway - The pathway object to transform.
292
- * @param {string[]} pathway.prompt - Array of user prompts.
370
+ * @param {(string[]|Object[])} pathway.prompt - Array of user prompts (strings) or prompt objects with {name, prompt} properties.
293
371
  * @param {string} pathway.systemPrompt - The system prompt to prepend to each user prompt.
294
372
  * @returns {Object} A new pathway object with transformed prompts.
295
373
  */
@@ -299,16 +377,7 @@ class PathwayManager {
299
377
  const newPathway = { ...pathway };
300
378
 
301
379
  // Transform each prompt in the array
302
- newPathway.prompt = prompt.map(p => {
303
- return new Prompt({
304
- messages: [
305
- // Prepend the system prompt as a system message
306
- { "role": "system", "content": systemPrompt },
307
- // Add the original prompt as a user message
308
- { "role": "user", "content": `{{text}}\n\n${p}` },
309
- ]
310
- })
311
- });
380
+ newPathway.prompt = prompt.map(p => this._createPromptObject(p, systemPrompt));
312
381
 
313
382
  return newPathway;
314
383
  }
@@ -354,9 +423,13 @@ class PathwayManager {
354
423
  return `#graphql
355
424
  scalar JSONObject
356
425
 
426
+ input PromptInput {
427
+ name: String!
428
+ prompt: String!
429
+ }
357
430
 
358
431
  input PathwayInput {
359
- prompt: [String!]!
432
+ prompt: [PromptInput!]!
360
433
  systemPrompt: String
361
434
  inputParameters: JSONObject
362
435
  model: String
@@ -444,6 +517,61 @@ class PathwayManager {
444
517
 
445
518
  return this.transformPrompts(pathways[userId][pathwayName]);
446
519
  }
520
+
521
+ /**
522
+ * Returns n pathways, one for each prompt in the provided prompt array.
523
+ * Each pathway will contain a single prompt from the array.
524
+ * @param {Object} pathwayTemplate - The base pathway template to use for each generated pathway.
525
+ * @param {(string[]|Object[])} pathwayTemplate.prompt - Array of user prompts (strings) or prompt objects with {name, prompt} properties.
526
+ * @param {string} pathwayTemplate.systemPrompt - The system prompt to use for each pathway.
527
+ * @param {string[]} [promptNames] - Optional array of prompt names to filter by. If provided, only prompts with names in this list will be included.
528
+ * @returns {Object[]} Array of pathway objects, each containing a single prompt.
529
+ */
530
+ async getPathways(pathwayTemplate, promptNames = null) {
531
+ const { prompt, systemPrompt, ...otherProps } = pathwayTemplate;
532
+
533
+ if (!Array.isArray(prompt)) {
534
+ throw new Error('pathwayTemplate.prompt must be an array');
535
+ }
536
+
537
+ if (promptNames && !Array.isArray(promptNames)) {
538
+ throw new Error('promptNames must be an array if provided');
539
+ }
540
+
541
+ // Use a Map to track prompt names without modifying pathway objects
542
+ const pathwayNameMap = new Map();
543
+
544
+ // Create a pathway for each prompt in the array
545
+ const pathways = prompt.map((p, index) => {
546
+ // Handle both old format (strings) and new format (objects with name and prompt)
547
+ const promptName = typeof p === 'string' ? `prompt_${index}` : (p.name || `prompt_${index}`);
548
+
549
+ // Create a new pathway with a single prompt using the shared helper method
550
+ const singlePromptPathway = {
551
+ ...otherProps,
552
+ name: promptName,
553
+ systemPrompt: systemPrompt || "",
554
+ prompt: [this._createPromptObject(p, systemPrompt, promptName)]
555
+ };
556
+
557
+ // Map the pathway object to its prompt name for filtering
558
+ pathwayNameMap.set(singlePromptPathway, promptName);
559
+
560
+ return singlePromptPathway;
561
+ });
562
+
563
+ // Filter by promptNames if provided
564
+ if (promptNames && promptNames.length > 0) {
565
+ const promptNamesSet = new Set(promptNames);
566
+ return pathways.filter(pathway => {
567
+ const promptName = pathwayNameMap.get(pathway);
568
+ return promptNamesSet.has(promptName);
569
+ });
570
+ }
571
+
572
+ return pathways;
573
+ }
574
+
447
575
  }
448
576
 
449
577
  // Helper function to convert a readable stream to a string
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aj-archipelago/cortex",
3
- "version": "1.3.64",
3
+ "version": "1.3.65",
4
4
  "description": "Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.",
5
5
  "private": false,
6
6
  "repository": {
package/server/graphql.js CHANGED
@@ -15,6 +15,7 @@ import { WebSocketServer } from 'ws';
15
15
  import responseCachePlugin from '@apollo/server-plugin-response-cache';
16
16
  import { KeyvAdapter } from '@apollo/utils.keyvadapter';
17
17
  import cors from 'cors';
18
+ import { v4 as uuidv4 } from 'uuid';
18
19
  import { buildModels, buildPathways } from '../config.js';
19
20
  import logger from '../lib/logger.js';
20
21
  import { buildModelEndpoints } from '../lib/requestExecutor.js';
@@ -75,8 +76,19 @@ const getTypedefs = (pathways, pathwayManager) => {
75
76
 
76
77
  ${getPathwayTypeDef('ExecuteWorkspace', 'String')}
77
78
 
79
+ type ExecuteWorkspaceResult {
80
+ debug: String
81
+ result: String
82
+ resultData: String
83
+ previousResult: String
84
+ warnings: [String]
85
+ errors: [String]
86
+ contextId: String
87
+ tool: String
88
+ }
89
+
78
90
  extend type Query {
79
- executeWorkspace(userId: String!, pathwayName: String!, ${userPathwayInputParameters}): ExecuteWorkspace
91
+ executeWorkspace(userId: String!, pathwayName: String!, ${userPathwayInputParameters}): ExecuteWorkspaceResult
80
92
  }
81
93
 
82
94
  type RequestSubscription {
@@ -102,6 +114,7 @@ const getTypedefs = (pathways, pathwayManager) => {
102
114
  return typeDefs.join('\n');
103
115
  }
104
116
 
117
+
105
118
  // Resolvers for GraphQL
106
119
  const getResolvers = (config, pathways, pathwayManager) => {
107
120
  const resolverFunctions = {};
@@ -118,14 +131,164 @@ const getResolvers = (config, pathways, pathwayManager) => {
118
131
  const pathwayManagerResolvers = pathwayManager?.getResolvers() || {};
119
132
 
120
133
  const executeWorkspaceResolver = async (_, args, contextValue, info) => {
121
- const { userId, pathwayName, ...pathwayArgs } = args;
122
- const userPathway = await pathwayManager.getPathway(userId, pathwayName);
134
+ const startTime = Date.now();
135
+ const requestId = uuidv4();
136
+ const { userId, pathwayName, promptNames, ...pathwayArgs } = args;
123
137
 
124
- contextValue.pathway = userPathway;
125
- contextValue.config = config;
138
+ logger.info(`>>> [${requestId}] executeWorkspace started - userId: ${userId}, pathwayName: ${pathwayName}, promptNames: ${promptNames?.join(',') || 'none'}`);
126
139
 
127
- const result = await userPathway.rootResolver(null, pathwayArgs, contextValue, info);
128
- return result;
140
+ try {
141
+ contextValue.config = config;
142
+
143
+ // Get the base pathway from the user
144
+ const pathways = await pathwayManager.getLatestPathways();
145
+
146
+ if (!pathways[userId] || !pathways[userId][pathwayName]) {
147
+ const error = new Error(`Pathway '${pathwayName}' not found for user '${userId}'`);
148
+ logger.error(`!!! [${requestId}] ${error.message} - Available users: ${Object.keys(pathways).join(', ')}`);
149
+ throw error;
150
+ }
151
+
152
+ const basePathway = pathways[userId][pathwayName];
153
+ logger.debug(`[${requestId}] Found pathway: ${pathwayName} for user: ${userId}`);
154
+
155
+ // If promptNames is specified, use getPathways to get individual pathways and execute in parallel
156
+ if (promptNames && promptNames.length > 0) {
157
+
158
+ // Check if the prompts are in legacy format (array of strings)
159
+ // If so, we can't use promptNames filtering and need to ask user to republish
160
+ if (pathwayManager.isLegacyPromptFormat(userId, pathwayName)) {
161
+ const error = new Error(
162
+ `The pathway '${pathwayName}' uses legacy prompt format (array of strings) which doesn't support the promptNames parameter. ` +
163
+ `Please unpublish and republish your workspace to upgrade to the new format that supports named prompts.`
164
+ );
165
+ logger.error(`!!! [${requestId}] ${error.message}`);
166
+ throw error;
167
+ }
168
+
169
+ // Handle wildcard case - execute all prompts in parallel
170
+ if (promptNames.includes('*')) {
171
+ logger.info(`[${requestId}] Executing all prompts in parallel (wildcard specified)`);
172
+ const individualPathways = await pathwayManager.getPathways(basePathway);
173
+
174
+ if (individualPathways.length === 0) {
175
+ const error = new Error(`No prompts found in pathway '${pathwayName}'`);
176
+ logger.error(`!!! [${requestId}] ${error.message}`);
177
+ throw error;
178
+ }
179
+
180
+ // Execute all pathways in parallel
181
+ logger.debug(`[${requestId}] Executing ${individualPathways.length} pathways in parallel`);
182
+ const results = await Promise.all(
183
+ individualPathways.map(async (pathway, index) => {
184
+ try {
185
+ logger.debug(`[${requestId}] Starting pathway ${index + 1}/${individualPathways.length}: ${pathway.name || 'unnamed'}`);
186
+ const pathwayContext = { ...contextValue, pathway };
187
+ const result = await pathway.rootResolver(null, pathwayArgs, pathwayContext, info);
188
+ logger.debug(`[${requestId}] Completed pathway ${index + 1}/${individualPathways.length}: ${pathway.name || 'unnamed'}`);
189
+ return {
190
+ result: result.result,
191
+ promptName: pathway.name || `prompt_${index + 1}`
192
+ };
193
+ } catch (error) {
194
+ logger.error(`!!! [${requestId}] Error in pathway ${index + 1}/${individualPathways.length}: ${pathway.name || 'unnamed'} - ${error.message}`);
195
+ logger.debug(`[${requestId}] Error stack: ${error.stack}`);
196
+ throw error;
197
+ }
198
+ })
199
+ );
200
+
201
+ const duration = Date.now() - startTime;
202
+ logger.info(`<<< [${requestId}] executeWorkspace completed successfully in ${duration}ms - returned ${results.length} results`);
203
+
204
+ // Return a single result with JSON stringified array of results
205
+ return {
206
+ debug: `Executed ${results.length} prompts in parallel`,
207
+ result: JSON.stringify(results),
208
+ resultData: null,
209
+ previousResult: null,
210
+ warnings: [],
211
+ errors: [],
212
+ contextId: requestId,
213
+ tool: 'executeWorkspace'
214
+ };
215
+ } else {
216
+ // Handle specific prompt names
217
+ logger.info(`[${requestId}] Executing specific prompts: ${promptNames.join(', ')}`);
218
+ const individualPathways = await pathwayManager.getPathways(basePathway, promptNames);
219
+
220
+ if (individualPathways.length === 0) {
221
+ const error = new Error(`No prompts found matching the specified names: ${promptNames.join(', ')}`);
222
+ logger.error(`!!! [${requestId}] ${error.message}`);
223
+ throw error;
224
+ }
225
+
226
+ // Execute all pathways in parallel
227
+ logger.debug(`[${requestId}] Executing ${individualPathways.length} pathways in parallel`);
228
+ const results = await Promise.all(
229
+ individualPathways.map(async (pathway, index) => {
230
+ try {
231
+ logger.debug(`[${requestId}] Starting pathway ${index + 1}/${individualPathways.length}: ${pathway.name || 'unnamed'}`);
232
+ const pathwayContext = { ...contextValue, pathway };
233
+ const result = await pathway.rootResolver(null, pathwayArgs, pathwayContext, info);
234
+ logger.debug(`[${requestId}] Completed pathway ${index + 1}/${individualPathways.length}: ${pathway.name || 'unnamed'}`);
235
+ return {
236
+ result: result.result,
237
+ promptName: pathway.name || `prompt_${index + 1}`
238
+ };
239
+ } catch (error) {
240
+ logger.error(`!!! [${requestId}] Error in pathway ${index + 1}/${individualPathways.length}: ${pathway.name || 'unnamed'} - ${error.message}`);
241
+ logger.debug(`[${requestId}] Error stack: ${error.stack}`);
242
+ throw error;
243
+ }
244
+ })
245
+ );
246
+
247
+ const duration = Date.now() - startTime;
248
+ logger.info(`<<< [${requestId}] executeWorkspace completed successfully in ${duration}ms - returned ${results.length} results`);
249
+
250
+ // Return a single result with JSON stringified array of results (consistent with wildcard case)
251
+ return {
252
+ debug: `Executed ${results.length} specific prompts in parallel: ${promptNames.join(', ')}`,
253
+ result: JSON.stringify(results),
254
+ resultData: null,
255
+ previousResult: null,
256
+ warnings: [],
257
+ errors: [],
258
+ contextId: requestId,
259
+ tool: 'executeWorkspace'
260
+ };
261
+ }
262
+ }
263
+
264
+ // Default behavior: execute all prompts in sequence
265
+ logger.info(`[${requestId}] Executing prompts in sequence`);
266
+ const userPathway = await pathwayManager.getPathway(userId, pathwayName);
267
+ contextValue.pathway = userPathway;
268
+
269
+ const result = await userPathway.rootResolver(null, pathwayArgs, contextValue, info);
270
+ const duration = Date.now() - startTime;
271
+ logger.info(`<<< [${requestId}] executeWorkspace completed successfully in ${duration}ms - returned 1 result`);
272
+ return result; // Return single result directly
273
+
274
+ } catch (error) {
275
+ const duration = Date.now() - startTime;
276
+ logger.error(`!!! [${requestId}] executeWorkspace failed after ${duration}ms`);
277
+ logger.error(`!!! [${requestId}] Error type: ${error.constructor.name}`);
278
+ logger.error(`!!! [${requestId}] Error message: ${error.message}`);
279
+ logger.error(`!!! [${requestId}] Error stack: ${error.stack}`);
280
+
281
+ // Log additional context for debugging "memory access out of bounds" errors
282
+ if (error.message && error.message.includes('memory')) {
283
+ logger.error(`!!! [${requestId}] MEMORY ERROR DETECTED - Additional context:`);
284
+ logger.error(`!!! [${requestId}] - Node.js version: ${process.version}`);
285
+ logger.error(`!!! [${requestId}] - Memory usage: ${JSON.stringify(process.memoryUsage())}`);
286
+ logger.error(`!!! [${requestId}] - Args size estimate: ${JSON.stringify(args).length} chars`);
287
+ logger.error(`!!! [${requestId}] - PathwayArgs keys: ${Object.keys(pathwayArgs).join(', ')}`);
288
+ }
289
+
290
+ throw error;
291
+ }
129
292
  };
130
293
 
131
294
  const resolvers = {
@@ -276,5 +439,7 @@ const build = async (config) => {
276
439
 
277
440
 
278
441
  export {
279
- build
442
+ build,
443
+ getResolvers
280
444
  };
445
+
@@ -12,6 +12,7 @@ import { publishRequestProgress } from '../lib/redisSubscription.js';
12
12
  import logger from '../lib/logger.js';
13
13
  // eslint-disable-next-line import/no-extraneous-dependencies
14
14
  import { createParser } from 'eventsource-parser';
15
+ import CortexResponse from '../lib/cortexResponse.js';
15
16
 
16
17
  const modelTypesExcludedFromProgressUpdates = ['OPENAI-DALLE2', 'OPENAI-DALLE3'];
17
18
 
@@ -589,11 +590,15 @@ class PathwayResolver {
589
590
  // If the prompt doesn't contain {{text}} then we can skip the chunking, and also give that token space to the previous result
590
591
  if (!this.prompts[i].usesTextInput) {
591
592
  // Limit context to it's N + text's characters
592
- previousResult = this.truncate(previousResult, 2 * this.chunkMaxTokenLength);
593
+ if (previousResult) {
594
+ previousResult = this.truncate(previousResult, 2 * this.chunkMaxTokenLength);
595
+ }
593
596
  result = await this.applyPrompt(this.prompts[i], null, currentParameters);
594
597
  } else {
595
598
  // Limit context to N characters
596
- previousResult = this.truncate(previousResult, this.chunkMaxTokenLength);
599
+ if (previousResult) {
600
+ previousResult = this.truncate(previousResult, this.chunkMaxTokenLength);
601
+ }
597
602
  result = await Promise.all(chunks.map(chunk =>
598
603
  this.applyPrompt(this.prompts[i], chunk, currentParameters)));
599
604
 
@@ -607,6 +612,9 @@ class PathwayResolver {
607
612
  // If this is any prompt other than the last, use the result as the previous context
608
613
  if (i < this.prompts.length - 1) {
609
614
  previousResult = result;
615
+ if (result instanceof CortexResponse) {
616
+ previousResult = result.output_text;
617
+ }
610
618
  }
611
619
  }
612
620
  // store the previous result in the PathwayResolver
package/server/prompt.js CHANGED
@@ -3,12 +3,13 @@ class Prompt {
3
3
  if (typeof params === 'string' || params instanceof String) {
4
4
  this.prompt = params;
5
5
  } else {
6
- const { prompt, saveResultTo, messages, context, examples } = params;
6
+ const { prompt, saveResultTo, messages, context, examples, name } = params;
7
7
  this.prompt = prompt;
8
8
  this.saveResultTo = saveResultTo;
9
9
  this.messages = messages;
10
10
  this.context = context;
11
11
  this.examples = examples;
12
+ this.name = name;
12
13
  this.params = params;
13
14
  }
14
15
 
package/server/typeDef.js CHANGED
@@ -92,7 +92,7 @@ const typeDef = (pathway) => {
92
92
  return getPathwayTypeDefAndExtendQuery(pathway);
93
93
  };
94
94
 
95
- const userPathwayInputParameters = `text: String`;
95
+ const userPathwayInputParameters = `text: String, promptNames: [String]`;
96
96
 
97
97
 
98
98
  export {