@aj-archipelago/cortex 1.4.31 → 1.4.33

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,8 +1,11 @@
1
1
  // sys_entity_agent.js
2
2
  // Agentic extension of the entity system that uses OpenAI's tool calling API
3
3
  const MAX_TOOL_CALLS = 50;
4
+ const TOOL_TIMEOUT_MS = 120000; // 2 minute timeout per tool call
5
+ const MAX_TOOL_RESULT_LENGTH = 50000; // Truncate oversized tool results to prevent context overflow
4
6
 
5
- import { callPathway, callTool, say, sendToolStart, sendToolFinish } from '../../../lib/pathwayTools.js';
7
+ import { callPathway, callTool, say, sendToolStart, sendToolFinish, withTimeout } from '../../../lib/pathwayTools.js';
8
+ import { publishRequestProgress } from '../../../lib/redisSubscription.js';
6
9
  import logger from '../../../lib/logger.js';
7
10
  import { config } from '../../../config.js';
8
11
  import { syncAndStripFilesFromChatHistory } from '../../../lib/fileUtils.js';
@@ -79,7 +82,13 @@ export default {
79
82
  entityId: ``,
80
83
  researchMode: false,
81
84
  userInfo: '',
82
- model: 'oai-gpt41'
85
+ model: 'oai-gpt41',
86
+ contextKey: ``,
87
+ clientSideTools: {
88
+ type: 'array',
89
+ items: { type: 'object' },
90
+ default: []
91
+ }
83
92
  },
84
93
  timeout: 600,
85
94
 
@@ -132,10 +141,13 @@ export default {
132
141
  // Create an isolated copy of messages for this tool
133
142
  const toolMessages = JSON.parse(JSON.stringify(preToolCallMessages));
134
143
 
135
- // Get the tool definition to check for icon
144
+ // Get the tool definition to check for icon and timeout
136
145
  const toolDefinition = entityTools[toolFunction]?.definition;
137
146
  const toolIcon = toolDefinition?.icon || '🛠️';
138
147
 
148
+ // Get timeout from tool definition or use default
149
+ const toolTimeout = toolDefinition?.timeout || TOOL_TIMEOUT_MS;
150
+
139
151
  // Get the user message for the tool
140
152
  const toolUserMessage = toolArgs.userMessage || `Executing tool: ${toolCall.function.name}`;
141
153
 
@@ -149,13 +161,19 @@ export default {
149
161
  // Continue execution even if start message fails
150
162
  }
151
163
 
152
- const toolResult = await callTool(toolFunction, {
153
- ...args,
154
- ...toolArgs,
155
- toolFunction,
156
- chatHistory: toolMessages,
157
- stream: false
158
- }, entityTools, pathwayResolver);
164
+ // Wrap tool call with timeout to prevent hanging
165
+ const toolResult = await withTimeout(
166
+ callTool(toolFunction, {
167
+ ...args,
168
+ ...toolArgs,
169
+ toolFunction,
170
+ chatHistory: toolMessages,
171
+ stream: false,
172
+ useMemory: false // Disable memory synthesis for tool calls
173
+ }, entityTools, pathwayResolver),
174
+ toolTimeout,
175
+ `Tool ${toolCall.function.name} timed out after ${toolTimeout / 1000}s`
176
+ );
159
177
 
160
178
  // Tool calls and results need to be paired together in the message history
161
179
  // Add the tool call to the isolated message history
@@ -305,7 +323,9 @@ export default {
305
323
  messages: toolMessages
306
324
  };
307
325
  } catch (error) {
308
- logger.error(`Error executing tool ${toolCall?.function?.name || 'unknown'}: ${error.message}`);
326
+ // Detect if this is a timeout error for clearer logging
327
+ const isTimeout = error.message?.includes('timed out');
328
+ logger.error(`${isTimeout ? 'Timeout' : 'Error'} executing tool ${toolCall?.function?.name || 'unknown'}: ${error.message}`);
309
329
 
310
330
  // Send tool finish message (error)
311
331
  // Get requestId and toolCallId if not already defined (in case error occurred before they were set)
@@ -406,7 +426,17 @@ export default {
406
426
  );
407
427
  }
408
428
 
409
- args.chatHistory = finalMessages;
429
+ // Truncate oversized tool results to prevent context overflow
430
+ args.chatHistory = finalMessages.map(msg => {
431
+ if (msg.role === 'tool' && msg.content && msg.content.length > MAX_TOOL_RESULT_LENGTH) {
432
+ logger.warn(`Truncating oversized tool result (${msg.content.length} chars) for ${msg.name || 'unknown tool'}`);
433
+ return {
434
+ ...msg,
435
+ content: msg.content.substring(0, MAX_TOOL_RESULT_LENGTH) + '\n\n[Content truncated due to length]'
436
+ };
437
+ }
438
+ return msg;
439
+ });
410
440
 
411
441
  // clear any accumulated pathwayResolver errors from the tools
412
442
  pathwayResolver.errors = [];
@@ -423,16 +453,27 @@ export default {
423
453
 
424
454
  // Check if promptAndParse returned null (model call failed)
425
455
  if (!result) {
426
- const errorMessage = pathwayResolver.errors.length > 0
456
+ const errorMessage = pathwayResolver.errors.length > 0
427
457
  ? pathwayResolver.errors.join(', ')
428
458
  : 'Model request failed - no response received';
429
459
  logger.error(`promptAndParse returned null during tool callback: ${errorMessage}`);
430
460
  const errorResponse = await generateErrorResponse(new Error(errorMessage), args, pathwayResolver);
431
461
  // Ensure errors are cleared before returning
432
462
  pathwayResolver.errors = [];
463
+
464
+ // In streaming mode, the toolCallback is invoked fire-and-forget by the plugin,
465
+ // so we must stream the error response directly to the client and close the stream
466
+ const requestId = pathwayResolver.rootRequestId || pathwayResolver.requestId;
467
+ publishRequestProgress({
468
+ requestId,
469
+ progress: 1,
470
+ data: JSON.stringify(errorResponse),
471
+ info: JSON.stringify(pathwayResolver.pathwayResultData || {}),
472
+ error: ''
473
+ });
433
474
  return errorResponse;
434
475
  }
435
-
476
+
436
477
  return result;
437
478
  } catch (parseError) {
438
479
  // If promptAndParse fails, generate error response instead of re-throwing
@@ -440,6 +481,17 @@ export default {
440
481
  const errorResponse = await generateErrorResponse(parseError, args, pathwayResolver);
441
482
  // Ensure errors are cleared before returning
442
483
  pathwayResolver.errors = [];
484
+
485
+ // In streaming mode, the toolCallback is invoked fire-and-forget by the plugin,
486
+ // so we must stream the error response directly to the client and close the stream
487
+ const requestId = pathwayResolver.rootRequestId || pathwayResolver.requestId;
488
+ publishRequestProgress({
489
+ requestId,
490
+ progress: 1,
491
+ data: JSON.stringify(errorResponse),
492
+ info: JSON.stringify(pathwayResolver.pathwayResultData || {}),
493
+ error: ''
494
+ });
443
495
  return errorResponse;
444
496
  }
445
497
  }
@@ -449,16 +501,48 @@ export default {
449
501
  let pathwayResolver = resolver;
450
502
 
451
503
  // Load input parameters and information into args
452
- const { entityId, voiceResponse, aiMemorySelfModify, chatId, researchMode } = { ...pathwayResolver.pathway.inputParameters, ...args };
504
+ let { entityId, voiceResponse, aiMemorySelfModify, chatId, researchMode, clientSideTools } = { ...pathwayResolver.pathway.inputParameters, ...args };
505
+
506
+ // Parse clientSideTools if it's a string (from GraphQL)
507
+ if (typeof clientSideTools === 'string') {
508
+ try {
509
+ clientSideTools = JSON.parse(clientSideTools);
510
+ } catch (e) {
511
+ logger.error(`Failed to parse clientSideTools: ${e.message}`);
512
+ clientSideTools = [];
513
+ }
514
+ }
453
515
 
454
516
  const entityConfig = loadEntityConfig(entityId);
455
- const { entityTools, entityToolsOpenAiFormat } = getToolsForEntity(entityConfig);
517
+ let { entityTools, entityToolsOpenAiFormat } = getToolsForEntity(entityConfig);
456
518
  const { name: entityName, instructions: entityInstructions } = entityConfig || {};
457
519
 
458
520
  // Determine useMemory: entityConfig.useMemory === false is a hard disable (entity can't use memory)
459
521
  // Otherwise args.useMemory can disable it, default true
460
522
  args.useMemory = entityConfig?.useMemory === false ? false : (args.useMemory ?? true);
461
523
 
524
+ // Add client-side tools from the caller
525
+ if (clientSideTools && Array.isArray(clientSideTools) && clientSideTools.length > 0) {
526
+ logger.info(`Adding ${clientSideTools.length} client-side tools from caller`);
527
+ clientSideTools.forEach(tool => {
528
+ const toolName = tool.function?.name?.toLowerCase();
529
+ if (toolName) {
530
+ // Mark as client-side tool and add to available tools
531
+ entityTools[toolName] = {
532
+ definition: {
533
+ ...tool,
534
+ clientSide: true, // Mark it as client-side
535
+ icon: tool.icon || '📱'
536
+ },
537
+ pathwayName: 'client_side_execution', // Placeholder pathway
538
+ clientSide: true
539
+ };
540
+ entityToolsOpenAiFormat.push(tool);
541
+ logger.info(`Registered client-side tool: ${toolName}`);
542
+ }
543
+ });
544
+ }
545
+
462
546
  // Initialize chat history if needed
463
547
  if (!args.chatHistory || args.chatHistory.length === 0) {
464
548
  args.chatHistory = [];
@@ -562,10 +646,10 @@ export default {
562
646
 
563
647
  // truncate the chat history in case there is really long content
564
648
  const truncatedChatHistory = resolver.modelExecutor.plugin.truncateMessagesToTargetLength(args.chatHistory, null, 1000);
565
-
649
+
566
650
  // Asynchronously manage memory for this context
567
651
  if (args.aiMemorySelfModify && args.useMemory) {
568
- callPathway('sys_memory_manager', { ...args, chatHistory: truncatedChatHistory, stream: false })
652
+ callPathway('sys_memory_manager', { ...args, chatHistory: truncatedChatHistory, stream: false })
569
653
  .catch(error => logger.error(error?.message || "Error in sys_memory_manager pathway"));
570
654
  }
571
655
 
@@ -594,6 +678,10 @@ export default {
594
678
  memoryLookupRequired = false;
595
679
  }
596
680
 
681
+ // Update pathwayResolver.args with stripped chatHistory
682
+ // This ensures toolCallback receives the processed history, not the original
683
+ pathwayResolver.args = {...args};
684
+
597
685
  try {
598
686
  let currentMessages = JSON.parse(JSON.stringify(args.chatHistory));
599
687
 
@@ -225,7 +225,7 @@ REMEMBER:
225
225
  .sort((a, b) => a.index - b.index)
226
226
  .map(item => item.result);
227
227
  } catch (error) {
228
- logger.error('Error processing chunks:', error);
228
+ logger.error(`Error processing chunks: ${error.message}`);
229
229
  throw error;
230
230
  }
231
231
  };
@@ -0,0 +1,241 @@
1
+ // clientToolCallbacks.js
2
+ // Storage and management for pending client-side tool callbacks
3
+
4
+ import logger from '../lib/logger.js';
5
+ import Redis from 'ioredis';
6
+ import { config } from '../config.js';
7
+
8
+ // Map to store pending client tool callbacks
9
+ // Key: toolCallbackId, Value: { resolve, reject, timeout, requestId }
10
+ const pendingCallbacks = new Map();
11
+
12
+ // Default timeout for client tool responses (5 minutes)
13
+ // Increased from 60s to 5min to accommodate longer operations like CreateApplet
14
+ const DEFAULT_TIMEOUT = 300000;
15
+
16
+ // Redis setup for cross-instance communication
17
+ const connectionString = config.get('storageConnectionString');
18
+ const clientToolCallbackChannel = 'clientToolCallbacks';
19
+
20
+ let subscriptionClient;
21
+ let publisherClient;
22
+
23
+ if (connectionString) {
24
+ logger.info(`Setting up Redis pub/sub for client tool callbacks on channel: ${clientToolCallbackChannel}`);
25
+
26
+ try {
27
+ subscriptionClient = new Redis(connectionString);
28
+ subscriptionClient.on('error', (error) => {
29
+ logger.error(`Redis subscriptionClient error (clientToolCallbacks): ${error}`);
30
+ });
31
+
32
+ subscriptionClient.on('connect', () => {
33
+ subscriptionClient.subscribe(clientToolCallbackChannel, (error) => {
34
+ if (error) {
35
+ logger.error(`Error subscribing to Redis channel ${clientToolCallbackChannel}: ${error}`);
36
+ } else {
37
+ logger.info(`Subscribed to client tool callback channel: ${clientToolCallbackChannel}`);
38
+ }
39
+ });
40
+ });
41
+
42
+ subscriptionClient.on('message', (channel, message) => {
43
+ if (channel === clientToolCallbackChannel) {
44
+ try {
45
+ const { toolCallbackId, result } = JSON.parse(message);
46
+ logger.debug(`Received client tool callback via Redis: ${toolCallbackId}`);
47
+
48
+ // Try to resolve it locally (will only work if this instance has the pending callback)
49
+ resolveClientToolCallbackLocal(toolCallbackId, result);
50
+ } catch (error) {
51
+ logger.error(`Error processing client tool callback from Redis: ${error}`);
52
+ }
53
+ }
54
+ });
55
+ } catch (error) {
56
+ logger.error(`Redis connection error (clientToolCallbacks): ${error}`);
57
+ }
58
+
59
+ try {
60
+ publisherClient = new Redis(connectionString);
61
+ publisherClient.on('error', (error) => {
62
+ logger.error(`Redis publisherClient error (clientToolCallbacks): ${error}`);
63
+ });
64
+ } catch (error) {
65
+ logger.error(`Redis connection error (clientToolCallbacks): ${error}`);
66
+ }
67
+ } else {
68
+ logger.info('No Redis connection configured. Client tool callbacks will only work on single instance.');
69
+ }
70
+
71
+ /**
72
+ * Register a pending client tool callback
73
+ * @param {string} toolCallbackId - Unique ID for this tool call
74
+ * @param {string} requestId - The request ID for logging/tracking
75
+ * @param {number} timeoutMs - Timeout in milliseconds
76
+ * @returns {Promise} Promise that resolves when client submits the result
77
+ */
78
+ export function waitForClientToolResult(toolCallbackId, requestId, timeoutMs = DEFAULT_TIMEOUT) {
79
+ return new Promise((resolve, reject) => {
80
+ // Set up timeout
81
+ const timeout = setTimeout(() => {
82
+ pendingCallbacks.delete(toolCallbackId);
83
+ logger.error(`Client tool callback timeout for ${toolCallbackId} (requestId: ${requestId})`);
84
+ reject(new Error(`Client tool execution timeout after ${timeoutMs}ms`));
85
+ }, timeoutMs);
86
+
87
+ // Store the callback
88
+ pendingCallbacks.set(toolCallbackId, {
89
+ resolve,
90
+ reject,
91
+ timeout,
92
+ requestId,
93
+ createdAt: Date.now()
94
+ });
95
+
96
+ logger.info(`Registered client tool callback: ${toolCallbackId} (requestId: ${requestId})`);
97
+ });
98
+ }
99
+
100
+ /**
101
+ * Resolve a pending client tool callback locally (internal use)
102
+ * @param {string} toolCallbackId - The tool callback ID
103
+ * @param {object} result - The result from the client
104
+ * @returns {boolean} True if callback was found and resolved
105
+ */
106
+ function resolveClientToolCallbackLocal(toolCallbackId, result) {
107
+ const callback = pendingCallbacks.get(toolCallbackId);
108
+
109
+ if (!callback) {
110
+ // This is normal in a multi-instance setup - the callback might be on another instance
111
+ logger.debug(`No pending callback found for toolCallbackId: ${toolCallbackId} (may be on another instance)`);
112
+ return false;
113
+ }
114
+
115
+ // Clear the timeout
116
+ clearTimeout(callback.timeout);
117
+
118
+ // Remove from pending
119
+ pendingCallbacks.delete(toolCallbackId);
120
+
121
+ logger.info(`Resolved client tool callback: ${toolCallbackId} (requestId: ${callback.requestId})`);
122
+
123
+ // Resolve the promise
124
+ callback.resolve(result);
125
+
126
+ return true;
127
+ }
128
+
129
+ /**
130
+ * Resolve a pending client tool callback with the result
131
+ * This function publishes to Redis so all instances can attempt to resolve
132
+ * @param {string} toolCallbackId - The tool callback ID
133
+ * @param {object} result - The result from the client
134
+ * @returns {Promise<boolean>} True if callback was published/resolved
135
+ */
136
+ export async function resolveClientToolCallback(toolCallbackId, result) {
137
+ if (publisherClient) {
138
+ // Publish to Redis so all instances can try to resolve
139
+ try {
140
+ const message = JSON.stringify({ toolCallbackId, result });
141
+ logger.debug(`Publishing client tool callback to Redis: ${toolCallbackId}`);
142
+ await publisherClient.publish(clientToolCallbackChannel, message);
143
+ return true;
144
+ } catch (error) {
145
+ logger.error(`Error publishing client tool callback to Redis: ${error}`);
146
+ // Fall back to local resolution
147
+ return resolveClientToolCallbackLocal(toolCallbackId, result);
148
+ }
149
+ } else {
150
+ // No Redis, resolve locally
151
+ return resolveClientToolCallbackLocal(toolCallbackId, result);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Reject a pending client tool callback locally (internal use)
157
+ * @param {string} toolCallbackId - The tool callback ID
158
+ * @param {Error} error - The error
159
+ * @returns {boolean} True if callback was found and rejected
160
+ */
161
+ function rejectClientToolCallbackLocal(toolCallbackId, error) {
162
+ const callback = pendingCallbacks.get(toolCallbackId);
163
+
164
+ if (!callback) {
165
+ logger.debug(`No pending callback found for toolCallbackId: ${toolCallbackId} (may be on another instance)`);
166
+ return false;
167
+ }
168
+
169
+ // Clear the timeout
170
+ clearTimeout(callback.timeout);
171
+
172
+ // Remove from pending
173
+ pendingCallbacks.delete(toolCallbackId);
174
+
175
+ logger.info(`Rejected client tool callback: ${toolCallbackId} (requestId: ${callback.requestId})`);
176
+
177
+ // Reject the promise
178
+ callback.reject(error);
179
+
180
+ return true;
181
+ }
182
+
183
+ /**
184
+ * Reject a pending client tool callback with an error
185
+ * This function publishes to Redis so all instances can attempt to reject
186
+ * @param {string} toolCallbackId - The tool callback ID
187
+ * @param {Error} error - The error
188
+ * @returns {Promise<boolean>} True if callback was published/rejected
189
+ */
190
+ export async function rejectClientToolCallback(toolCallbackId, error) {
191
+ if (publisherClient) {
192
+ // Publish to Redis so all instances can try to reject
193
+ try {
194
+ const message = JSON.stringify({
195
+ toolCallbackId,
196
+ result: { success: false, error: error.message || error.toString() }
197
+ });
198
+ logger.debug(`Publishing client tool callback rejection to Redis: ${toolCallbackId}`);
199
+ await publisherClient.publish(clientToolCallbackChannel, message);
200
+ return true;
201
+ } catch (publishError) {
202
+ logger.error(`Error publishing client tool callback rejection to Redis: ${publishError}`);
203
+ // Fall back to local rejection
204
+ return rejectClientToolCallbackLocal(toolCallbackId, error);
205
+ }
206
+ } else {
207
+ // No Redis, reject locally
208
+ return rejectClientToolCallbackLocal(toolCallbackId, error);
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Get count of pending callbacks (for monitoring)
214
+ */
215
+ export function getPendingCallbackCount() {
216
+ return pendingCallbacks.size;
217
+ }
218
+
219
+ /**
220
+ * Clean up old callbacks (for maintenance)
221
+ */
222
+ export function cleanupOldCallbacks(maxAgeMs = 120000) {
223
+ const now = Date.now();
224
+ let cleaned = 0;
225
+
226
+ for (const [id, callback] of pendingCallbacks.entries()) {
227
+ if (now - callback.createdAt > maxAgeMs) {
228
+ clearTimeout(callback.timeout);
229
+ pendingCallbacks.delete(id);
230
+ callback.reject(new Error('Callback expired during cleanup'));
231
+ cleaned++;
232
+ }
233
+ }
234
+
235
+ if (cleaned > 0) {
236
+ logger.info(`Cleaned up ${cleaned} old client tool callbacks`);
237
+ }
238
+
239
+ return cleaned;
240
+ }
241
+
@@ -80,6 +80,7 @@ const resolveAndAddFileContent = async (pathways, pathwayArgs, requestId, config
80
80
 
81
81
  // Helper function to execute pathway with cortex pathway name or fallback to legacy
82
82
  const executePathwayWithFallback = async (pathway, pathwayArgs, contextValue, info, requestId, originalPrompt = null, config) => {
83
+ // Extract cortexPathwayName from originalPrompt (could be original object or transformed Prompt object)
83
84
  const cortexPathwayName = (originalPrompt && typeof originalPrompt === 'object' && originalPrompt.cortexPathwayName)
84
85
  ? originalPrompt.cortexPathwayName
85
86
  : null;
@@ -100,6 +101,12 @@ const executePathwayWithFallback = async (pathway, pathwayArgs, contextValue, in
100
101
  // Remove old aiStyle parameter (no longer used)
101
102
  delete cortexArgs.aiStyle;
102
103
 
104
+ // Extract researchMode from originalPrompt if not already in pathwayArgs
105
+ // originalPrompt could be the original object from JSON or a transformed Prompt object
106
+ if (originalPrompt && typeof originalPrompt === 'object' && originalPrompt.researchMode !== undefined) {
107
+ cortexArgs.researchMode = originalPrompt.researchMode;
108
+ }
109
+
103
110
  // Transform context parameters to agentContext array format (only if agentContext not already provided)
104
111
  if (!cortexArgs.agentContext && (cortexArgs.contextId || cortexArgs.contextKey || cortexArgs.altContextId || cortexArgs.altContextKey)) {
105
112
  const agentContext = [];
package/server/graphql.js CHANGED
@@ -20,7 +20,7 @@ import logger from '../lib/logger.js';
20
20
  import { buildModelEndpoints } from '../lib/requestExecutor.js';
21
21
  import { startTestServer } from '../tests/helpers/server.js';
22
22
  import { requestState } from './requestState.js';
23
- import { cancelRequestResolver } from './resolver.js';
23
+ import { cancelRequestResolver, submitClientToolResultResolver } from './resolver.js';
24
24
  import subscriptions from './subscriptions.js';
25
25
  import { getMessageTypeDefs } from './typeDef.js';
26
26
  import { buildRestEndpoints } from './rest.js';
@@ -79,6 +79,7 @@ const getTypedefs = (pathways, pathwayManager) => {
79
79
 
80
80
  type Mutation {
81
81
  cancelRequest(requestId: String!): Boolean
82
+ submitClientToolResult(requestId: String!, toolCallbackId: String!, result: String!, success: Boolean!): Boolean
82
83
  }
83
84
 
84
85
  ${getExecuteWorkspaceTypeDefs()}
@@ -140,6 +141,7 @@ const getResolvers = (config, pathways, pathwayManager) => {
140
141
  },
141
142
  Mutation: {
142
143
  'cancelRequest': cancelRequestResolver,
144
+ 'submitClientToolResult': submitClientToolResultResolver,
143
145
  ...mutationResolvers,
144
146
  ...pathwayManagerResolvers.Mutation
145
147
  },
@@ -26,6 +26,7 @@ import Gemini3ImagePlugin from './plugins/gemini3ImagePlugin.js';
26
26
  import Gemini3ReasoningVisionPlugin from './plugins/gemini3ReasoningVisionPlugin.js';
27
27
  import Claude3VertexPlugin from './plugins/claude3VertexPlugin.js';
28
28
  import Claude4VertexPlugin from './plugins/claude4VertexPlugin.js';
29
+ import ClaudeAnthropicPlugin from './plugins/claudeAnthropicPlugin.js';
29
30
  import NeuralSpacePlugin from './plugins/neuralSpacePlugin.js';
30
31
  import RunwareAiPlugin from './plugins/runwareAiPlugin.js';
31
32
  import ReplicateApiPlugin from './plugins/replicateApiPlugin.js';
@@ -122,6 +123,9 @@ class ModelExecutor {
122
123
  case 'CLAUDE-4-VERTEX':
123
124
  plugin = new Claude4VertexPlugin(pathway, model);
124
125
  break;
126
+ case 'CLAUDE-ANTHROPIC':
127
+ plugin = new ClaudeAnthropicPlugin(pathway, model);
128
+ break;
125
129
  case 'RUNWARE-AI':
126
130
  plugin = new RunwareAiPlugin(pathway, model);
127
131
  break;