@aj-archipelago/cortex 1.2.0 → 1.3.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.
Files changed (81) hide show
  1. package/config.js +47 -11
  2. package/helper-apps/cortex-autogen/OAI_CONFIG_LIST +2 -1
  3. package/helper-apps/cortex-autogen/agents.py +387 -0
  4. package/helper-apps/cortex-autogen/agents_extra.py +14 -0
  5. package/helper-apps/cortex-autogen/config.py +18 -0
  6. package/helper-apps/cortex-autogen/data_operations.py +29 -0
  7. package/helper-apps/cortex-autogen/function_app.py +6 -3
  8. package/helper-apps/cortex-autogen/main.py +4 -4
  9. package/helper-apps/cortex-autogen/prompts.py +196 -0
  10. package/helper-apps/cortex-autogen/prompts_extra.py +5 -0
  11. package/helper-apps/cortex-autogen/requirements.txt +2 -1
  12. package/helper-apps/cortex-autogen/search.py +83 -0
  13. package/helper-apps/cortex-autogen/test.sh +40 -0
  14. package/helper-apps/cortex-autogen/utils.py +78 -0
  15. package/lib/handleBars.js +25 -0
  16. package/lib/logger.js +2 -0
  17. package/lib/util.js +3 -1
  18. package/package.json +1 -1
  19. package/pathways/chat_code.js +1 -1
  20. package/pathways/chat_context.js +1 -1
  21. package/pathways/chat_jarvis.js +1 -1
  22. package/pathways/chat_persist.js +1 -1
  23. package/pathways/chat_title.js +25 -0
  24. package/pathways/{flux_image.js → image_flux.js} +6 -2
  25. package/pathways/image_recraft.js +10 -0
  26. package/pathways/rag.js +1 -1
  27. package/pathways/rag_jarvis.js +1 -1
  28. package/pathways/rag_search_helper.js +1 -1
  29. package/pathways/system/entity/memory/sys_memory_manager.js +71 -0
  30. package/pathways/system/entity/memory/sys_memory_required.js +21 -0
  31. package/pathways/system/entity/memory/sys_memory_update.js +190 -0
  32. package/pathways/system/entity/memory/sys_read_memory.js +37 -0
  33. package/pathways/system/entity/memory/sys_save_memory.js +60 -0
  34. package/pathways/system/entity/shared/sys_entity_constants.js +24 -0
  35. package/pathways/system/entity/sys_entity_continue.js +57 -0
  36. package/pathways/system/entity/sys_entity_start.js +218 -0
  37. package/pathways/system/entity/sys_generator_error.js +20 -0
  38. package/pathways/system/entity/sys_generator_expert.js +26 -0
  39. package/pathways/system/entity/sys_generator_image.js +127 -0
  40. package/pathways/system/entity/sys_generator_quick.js +19 -0
  41. package/pathways/system/entity/sys_generator_reasoning.js +27 -0
  42. package/pathways/system/entity/sys_generator_results.js +304 -0
  43. package/pathways/system/entity/sys_generator_video_vision.js +27 -0
  44. package/pathways/system/entity/sys_image_prompt_builder.js +35 -0
  45. package/pathways/system/entity/sys_query_builder.js +101 -0
  46. package/pathways/system/entity/sys_router_code.js +37 -0
  47. package/pathways/system/entity/sys_router_tool.js +64 -0
  48. package/pathways/{sys_claude_35_sonnet.js → system/rest_streaming/sys_claude_35_sonnet.js} +1 -1
  49. package/pathways/{sys_claude_3_haiku.js → system/rest_streaming/sys_claude_3_haiku.js} +1 -1
  50. package/pathways/{sys_google_chat.js → system/rest_streaming/sys_google_chat.js} +1 -1
  51. package/pathways/{sys_google_code_chat.js → system/rest_streaming/sys_google_code_chat.js} +1 -1
  52. package/pathways/{sys_google_gemini_chat.js → system/rest_streaming/sys_google_gemini_chat.js} +1 -1
  53. package/pathways/{sys_openai_chat.js → system/rest_streaming/sys_openai_chat.js} +1 -1
  54. package/pathways/{sys_openai_chat_16.js → system/rest_streaming/sys_openai_chat_16.js} +1 -1
  55. package/pathways/{sys_openai_chat_gpt4.js → system/rest_streaming/sys_openai_chat_gpt4.js} +1 -1
  56. package/pathways/{sys_openai_chat_gpt4_32.js → system/rest_streaming/sys_openai_chat_gpt4_32.js} +1 -1
  57. package/pathways/{sys_openai_chat_gpt4_turbo.js → system/rest_streaming/sys_openai_chat_gpt4_turbo.js} +1 -1
  58. package/pathways/{sys_parse_numbered_object_list.js → system/sys_parse_numbered_object_list.js} +2 -2
  59. package/pathways/{sys_repair_json.js → system/sys_repair_json.js} +1 -1
  60. package/pathways/{run_claude35_sonnet.js → system/workspaces/run_claude35_sonnet.js} +1 -1
  61. package/pathways/{run_claude3_haiku.js → system/workspaces/run_claude3_haiku.js} +1 -1
  62. package/pathways/{run_gpt35turbo.js → system/workspaces/run_gpt35turbo.js} +1 -1
  63. package/pathways/{run_gpt4.js → system/workspaces/run_gpt4.js} +1 -1
  64. package/pathways/{run_gpt4_32.js → system/workspaces/run_gpt4_32.js} +1 -1
  65. package/server/parser.js +6 -1
  66. package/server/pathwayResolver.js +62 -10
  67. package/server/plugins/azureCognitivePlugin.js +14 -1
  68. package/server/plugins/claude3VertexPlugin.js +25 -15
  69. package/server/plugins/gemini15ChatPlugin.js +1 -1
  70. package/server/plugins/geminiChatPlugin.js +1 -1
  71. package/server/plugins/modelPlugin.js +10 -1
  72. package/server/plugins/openAiChatPlugin.js +4 -3
  73. package/server/plugins/openAiDallE3Plugin.js +12 -4
  74. package/server/plugins/openAiVisionPlugin.js +1 -2
  75. package/server/plugins/replicateApiPlugin.js +46 -12
  76. package/tests/multimodal_conversion.test.js +6 -8
  77. package/helper-apps/cortex-autogen/myautogen.py +0 -317
  78. package/helper-apps/cortex-autogen/prompt.txt +0 -0
  79. package/helper-apps/cortex-autogen/prompt_summary.txt +0 -37
  80. package/pathways/index.js +0 -152
  81. /package/pathways/{sys_openai_completion.js → system/rest_streaming/sys_openai_completion.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  // sys_openai_chat_gpt4.js
2
2
  // override handler for gpt-4
3
3
 
4
- import { Prompt } from '../server/prompt.js';
4
+ import { Prompt } from '../../../server/prompt.js';
5
5
 
6
6
  export default {
7
7
  prompt:
@@ -1,7 +1,7 @@
1
1
  // sys_openai_chat_gpt4_32.js
2
2
  // override handler for gpt-4-32
3
3
 
4
- import { Prompt } from '../server/prompt.js';
4
+ import { Prompt } from '../../../server/prompt.js';
5
5
 
6
6
  export default {
7
7
  prompt:
@@ -1,7 +1,7 @@
1
1
  // sys_openai_chat_gpt4_turbo.js
2
2
  // override handler for gpt-4-turbo
3
3
 
4
- import { Prompt } from '../server/prompt.js';
4
+ import { Prompt } from '../../../server/prompt.js';
5
5
 
6
6
  export default {
7
7
  prompt:
@@ -1,10 +1,10 @@
1
- import { Prompt } from '../server/prompt.js';
1
+ import { Prompt } from '../../server/prompt.js';
2
2
 
3
3
  export default {
4
4
  prompt: [
5
5
  new Prompt({
6
6
  messages: [
7
- { "role": "system", "content": "Assistant is a list parsing AI. When user posts text including a numbered list and a desired set of fields, assistant will carefully read the list and attempt to convert the list into a JSON object with the given fields. If there are extra fields, assistant will ignore them. If there are some missing fields, assistant will just skip the missing fields and return the rest. If the conversion is not at all possible, assistant will return an empty JSON array. Assistant will generate only the repaired JSON object in a directly parseable format with no markdown surrounding it and no other response or commentary." },
7
+ { "role": "system", "content": "Assistant is a list parsing AI. When user posts text including a numbered list and a desired set of fields, assistant will carefully read the list and attempt to convert the list into a JSON object with the given fields. If a field value is numeric, it should be returned as a number in the JSON object. If there are extra fields, assistant will ignore them. If there are some missing fields, assistant will just skip the missing fields and return the rest. If the conversion is not at all possible, assistant will return an empty JSON array. Assistant will generate only the repaired JSON object in a directly parseable format with no markdown surrounding it and no other response or commentary." },
8
8
  { "role": "user", "content": `Fields: {{{format}}}\nList: {{{text}}}`},
9
9
  ]
10
10
  })
@@ -1,4 +1,4 @@
1
- import { Prompt } from '../server/prompt.js';
1
+ import { Prompt } from '../../server/prompt.js';
2
2
 
3
3
  export default {
4
4
  prompt: [
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Import required modules
3
- import { Prompt } from '../server/prompt.js';
3
+ import { Prompt } from '../../../server/prompt.js';
4
4
 
5
5
  export default {
6
6
  prompt: [
@@ -1,5 +1,5 @@
1
1
  // Import required modules
2
- import { Prompt } from '../server/prompt.js';
2
+ import { Prompt } from '../../../server/prompt.js';
3
3
 
4
4
  export default {
5
5
  prompt: [
@@ -1,5 +1,5 @@
1
1
  // Import required modules
2
- import { Prompt } from "../server/prompt.js"
2
+ import { Prompt } from "../../../server/prompt.js"
3
3
 
4
4
  export default {
5
5
  prompt: [
@@ -1,5 +1,5 @@
1
1
  // Import required modules
2
- import { Prompt } from '../server/prompt.js';
2
+ import { Prompt } from '../../../server/prompt.js';
3
3
 
4
4
  export default {
5
5
  prompt: [
@@ -1,5 +1,5 @@
1
1
  // Import required modules
2
- import { Prompt } from '../server/prompt.js';
2
+ import { Prompt } from '../../../server/prompt.js';
3
3
 
4
4
  export default {
5
5
  prompt: [
package/server/parser.js CHANGED
@@ -40,7 +40,12 @@ const isNumberedList = (data) => {
40
40
 
41
41
  async function parseJson(str) {
42
42
  try {
43
- JSON.parse(str); // Validate JSON
43
+ // check for the common error case that the JSON is surrounded by markdown
44
+ const match = str.match(/```\s*(?:json)?(.*?)```/s);
45
+ if (match) {
46
+ str = match[1].trim();
47
+ }
48
+ JSON.parse(str);
44
49
  return str;
45
50
  } catch (error) {
46
51
  try {
@@ -221,15 +221,59 @@ class PathwayResolver {
221
221
  // Get saved context from contextId or change contextId if needed
222
222
  const { contextId } = args;
223
223
  this.savedContextId = contextId ? contextId : uuidv4();
224
- this.savedContext = contextId ? (getv && (await getv(contextId)) || {}) : {};
225
-
226
- // Save the context before processing the request
227
- const savedContextStr = JSON.stringify(this.savedContext);
224
+
225
+ const loadMemory = async () => {
226
+ // Load initial values
227
+ this.savedContext = (getv && await getv(contextId)) || {};
228
+ this.memorySelf = (getv && await getv(`${contextId}-memorySelf`)) || "";
229
+ this.memoryDirectives = (getv && await getv(`${contextId}-memoryDirectives`)) || "";
230
+ this.memoryTopics = (getv && await getv(`${contextId}-memoryTopics`)) || "";
231
+ this.memoryUser = (getv && await getv(`${contextId}-memoryUser`)) || "";
232
+
233
+ // Store initial state for comparison
234
+ this.initialState = {
235
+ savedContext: this.savedContext,
236
+ memorySelf: this.memorySelf,
237
+ memoryDirectives: this.memoryDirectives,
238
+ memoryTopics: this.memoryTopics,
239
+ memoryUser: this.memoryUser
240
+ };
241
+ };
242
+
243
+ const saveChangedMemory = async () => {
244
+ this.savedContextId = this.savedContextId || uuidv4();
245
+
246
+ const currentState = {
247
+ savedContext: this.savedContext,
248
+ memorySelf: this.memorySelf,
249
+ memoryDirectives: this.memoryDirectives,
250
+ memoryTopics: this.memoryTopics,
251
+ memoryUser: this.memoryUser
252
+ };
253
+
254
+ if (currentState.savedContext !== this.initialState.savedContext) {
255
+ setv && await setv(this.savedContextId, this.savedContext);
256
+ }
257
+ if (currentState.memorySelf !== this.initialState.memorySelf) {
258
+ setv && await setv(`${this.savedContextId}-memorySelf`, this.memorySelf);
259
+ }
260
+ if (currentState.memoryDirectives !== this.initialState.memoryDirectives) {
261
+ setv && await setv(`${this.savedContextId}-memoryDirectives`, this.memoryDirectives);
262
+ }
263
+ if (currentState.memoryTopics !== this.initialState.memoryTopics) {
264
+ setv && await setv(`${this.savedContextId}-memoryTopics`, this.memoryTopics);
265
+ }
266
+ if (currentState.memoryUser !== this.initialState.memoryUser) {
267
+ setv && await setv(`${this.savedContextId}-memoryUser`, this.memoryUser);
268
+ }
269
+ };
228
270
 
229
271
  const MAX_RETRIES = 3;
230
272
  let data = null;
231
273
 
232
274
  for (let retries = 0; retries < MAX_RETRIES; retries++) {
275
+ await loadMemory(); // Reset memory state on each retry
276
+
233
277
  data = await this.processRequest(args);
234
278
  if (!data) {
235
279
  break;
@@ -241,13 +285,10 @@ class PathwayResolver {
241
285
  }
242
286
 
243
287
  logger.warn(`Bad pathway result - retrying pathway. Attempt ${retries + 1} of ${MAX_RETRIES}`);
244
- this.savedContext = JSON.parse(savedContextStr);
245
288
  }
246
289
 
247
- // Update saved context if it has changed, generating a new contextId if necessary
248
- if (savedContextStr !== JSON.stringify(this.savedContext)) {
249
- this.savedContextId = this.savedContextId || uuidv4();
250
- setv && setv(this.savedContextId, this.savedContext);
290
+ if (data !== null) {
291
+ await saveChangedMemory();
251
292
  }
252
293
 
253
294
  return data;
@@ -419,7 +460,14 @@ class PathwayResolver {
419
460
 
420
461
  // If this text is empty, skip applying the prompt as it will likely be a nonsensical result
421
462
  if (!/^\s*$/.test(text) || parameters?.file || parameters?.inputVector || this?.modelName.includes('cognitive')) {
422
- result = await this.modelExecutor.execute(text, { ...parameters, ...this.savedContext }, prompt, this);
463
+ result = await this.modelExecutor.execute(text, {
464
+ ...parameters,
465
+ ...this.savedContext,
466
+ memorySelf: this.memorySelf,
467
+ memoryDirectives: this.memoryDirectives,
468
+ memoryTopics: this.memoryTopics,
469
+ memoryUser: this.memoryUser
470
+ }, prompt, this);
423
471
  } else {
424
472
  result = text;
425
473
  }
@@ -439,6 +487,10 @@ class PathwayResolver {
439
487
 
440
488
  // save the result to the context if requested and no errors
441
489
  if (prompt.saveResultTo && this.errors.length === 0) {
490
+ // Update memory property if it matches a known type
491
+ if (["memorySelf", "memoryUser", "memoryDirectives", "memoryTopics"].includes(prompt.saveResultTo)) {
492
+ this[prompt.saveResultTo] = result;
493
+ }
442
494
  this.savedContext[prompt.saveResultTo] = result;
443
495
  }
444
496
  return result;
@@ -55,7 +55,7 @@ class AzureCognitivePlugin extends ModelPlugin {
55
55
  { search: searchQuery,
56
56
  "searchMode": "all",
57
57
  "queryType": "full",
58
- select: 'id', top: TOP
58
+ select: 'id', top: TOP, skip: 0
59
59
  };
60
60
 
61
61
  const docsToDelete = JSON.parse(await this.executeRequest(cortexRequest));
@@ -115,6 +115,19 @@ class AzureCognitivePlugin extends ModelPlugin {
115
115
  ];
116
116
  } else {
117
117
  data.search = modelPromptText;
118
+ data.top = parameters.top || 50;
119
+ data.skip = 0;
120
+ if (parameters.titleOnly) {
121
+ switch(indexName){
122
+ case 'indexcortex':
123
+ case 'indexwires':
124
+ data.select = 'title,id';
125
+ break;
126
+ default:
127
+ data.select = 'title,id,url';
128
+ break;
129
+ }
130
+ }
118
131
  }
119
132
 
120
133
  filter && (data.filter = filter);
@@ -1,9 +1,10 @@
1
1
  import OpenAIVisionPlugin from "./openAiVisionPlugin.js";
2
2
  import logger from "../../lib/logger.js";
3
+ import axios from 'axios';
3
4
 
4
5
  const allowedMIMETypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
5
- async function convertContentItem(item) {
6
6
 
7
+ async function convertContentItem(item, maxImageSize) {
7
8
  let imageUrl = "";
8
9
 
9
10
  try {
@@ -27,6 +28,14 @@ async function convertContentItem(item) {
27
28
  try {
28
29
  const urlData = imageUrl.startsWith("data:") ? imageUrl : await fetchImageAsDataURL(imageUrl);
29
30
  if (!urlData) { return null; }
31
+
32
+ // Check base64 size
33
+ const base64Size = (urlData.length * 3) / 4;
34
+ if (base64Size > maxImageSize) {
35
+ logger.warn(`Image size ${base64Size} bytes exceeds maximum allowed size ${maxImageSize} - skipping image content.`);
36
+ return null;
37
+ }
38
+
30
39
  const [, mimeType = "image/jpeg"] = urlData.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/) || [];
31
40
  const base64Image = urlData.split(",")[1];
32
41
 
@@ -60,25 +69,26 @@ async function convertContentItem(item) {
60
69
  // Fetch image and convert to base 64 data URL
61
70
  async function fetchImageAsDataURL(imageUrl) {
62
71
  try {
63
- const response = await fetch(imageUrl, { method: 'HEAD' });
64
-
65
- if (!response.ok) {
66
- throw new Error(`HTTP error! status: ${response.status}`);
67
- }
72
+ // First check headers
73
+ const headResponse = await axios.head(imageUrl, {
74
+ timeout: 30000, // 30 second timeout
75
+ maxRedirects: 5
76
+ });
68
77
 
69
- const contentType = response.headers.get('content-type');
78
+ const contentType = headResponse.headers['content-type'];
70
79
  if (!contentType || !allowedMIMETypes.includes(contentType)) {
71
80
  logger.warn(`Unsupported image type: ${contentType} - skipping image content.`);
72
81
  return null;
73
82
  }
74
83
 
75
- const dataResponse = await fetch(imageUrl);
76
- if (!dataResponse.ok) {
77
- throw new Error(`HTTP error! status: ${dataResponse.status}`);
78
- }
84
+ // Then get the actual image data
85
+ const dataResponse = await axios.get(imageUrl, {
86
+ timeout: 30000,
87
+ responseType: 'arraybuffer',
88
+ maxRedirects: 5
89
+ });
79
90
 
80
- const buffer = await dataResponse.arrayBuffer();
81
- const base64Image = Buffer.from(buffer).toString("base64");
91
+ const base64Image = Buffer.from(dataResponse.data).toString('base64');
82
92
  return `data:${contentType};base64,${base64Image}`;
83
93
  }
84
94
  catch (e) {
@@ -151,7 +161,7 @@ class Claude3VertexPlugin extends OpenAIVisionPlugin {
151
161
  const claude3Messages = await Promise.all(
152
162
  finalMessages.map(async (message) => {
153
163
  const contentArray = Array.isArray(message.content) ? message.content : [message.content];
154
- const claude3Content = await Promise.all(contentArray.map(convertContentItem));
164
+ const claude3Content = await Promise.all(contentArray.map(item => convertContentItem(item, this.getModelMaxImageSize())));
155
165
  return {
156
166
  role: message.role,
157
167
  content: claude3Content.filter(Boolean),
@@ -301,7 +311,7 @@ class Claude3VertexPlugin extends OpenAIVisionPlugin {
301
311
 
302
312
  shortenContent(content, maxWords = 40) {
303
313
  const words = content.split(" ");
304
- if (words.length <= maxWords) {
314
+ if (words.length <= maxWords || logger.level === 'debug') {
305
315
  return content;
306
316
  }
307
317
  return words.slice(0, maxWords / 2).join(" ") +
@@ -200,7 +200,7 @@ class Gemini15ChatPlugin extends ModelPlugin {
200
200
  } else if (Array.isArray(responseData)) {
201
201
  const { mergedResult, safetyRatings } = mergeResults(responseData);
202
202
  if (safetyRatings?.length) {
203
- logger.warn(`!!! response was blocked because the input or response potentially violates policies`);
203
+ logger.warn(`response was blocked because the input or response potentially violates policies`);
204
204
  logger.verbose(`Safety Ratings: ${JSON.stringify(safetyRatings, null, 2)}`);
205
205
  }
206
206
  const { length, units } = this.getLength(mergedResult);
@@ -195,7 +195,7 @@ class GeminiChatPlugin extends ModelPlugin {
195
195
  } else if (Array.isArray(responseData)) {
196
196
  const { mergedResult, safetyRatings } = mergeResults(responseData);
197
197
  if (safetyRatings?.length) {
198
- logger.warn(`!!! response was blocked because the input or response potentially violates policies`);
198
+ logger.warn(`response was blocked because the input or response potentially violates policies`);
199
199
  logger.verbose(`Safety Ratings: ${JSON.stringify(safetyRatings, null, 2)}`);
200
200
  }
201
201
  const { length, units } = this.getLength(mergedResult);
@@ -9,6 +9,7 @@ import { config } from '../../config.js';
9
9
  const DEFAULT_MAX_TOKENS = 4096;
10
10
  const DEFAULT_MAX_RETURN_TOKENS = 256;
11
11
  const DEFAULT_PROMPT_TOKEN_RATIO = 0.5;
12
+ const DEFAULT_MAX_IMAGE_SIZE = 20 * 1024 * 1024; // 20MB default
12
13
 
13
14
  class ModelPlugin {
14
15
  constructor(pathway, model) {
@@ -249,7 +250,12 @@ class ModelPlugin {
249
250
  let length = 0;
250
251
  let units = isProd ? 'characters' : 'tokens';
251
252
  if (data) {
252
- length = isProd ? data.length : encode(data).length;
253
+ if (isProd || data.length > 5000) {
254
+ length = data.length;
255
+ units = 'characters';
256
+ } else {
257
+ length = encode(data).length;
258
+ }
253
259
  }
254
260
  return {length, units};
255
261
  }
@@ -341,6 +347,9 @@ class ModelPlugin {
341
347
  return requestProgress;
342
348
  }
343
349
 
350
+ getModelMaxImageSize() {
351
+ return (this.promptParameters.maxImageSize ?? this.model.maxImageSize ?? DEFAULT_MAX_IMAGE_SIZE);
352
+ }
344
353
 
345
354
  }
346
355
 
@@ -115,9 +115,10 @@ class OpenAIChatPlugin extends ModelPlugin {
115
115
  const content = message.content === undefined ? JSON.stringify(message) : (Array.isArray(message.content) ? message.content.map(item => JSON.stringify(item)).join(', ') : message.content);
116
116
  const words = content.split(" ");
117
117
  const { length, units } = this.getLength(content);
118
- const preview = words.length < 41 ? content : words.slice(0, 20).join(" ") + " ... " + words.slice(-20).join(" ");
119
-
120
- logger.verbose(`message ${index + 1}: role: ${message.role}, ${units}: ${length}, content: "${preview}"`);
118
+
119
+ const displayContent = logger.level === 'debug' ? content : (words.length < 41 ? content : words.slice(0, 20).join(" ") + " ... " + words.slice(-20).join(" "));
120
+
121
+ logger.verbose(`message ${index + 1}: role: ${message.role}, ${units}: ${length}, content: "${displayContent}"`);
121
122
  totalLength += length;
122
123
  totalUnits = units;
123
124
  });
@@ -52,14 +52,20 @@ class OpenAIDallE3Plugin extends ModelPlugin {
52
52
 
53
53
  requestPromise
54
54
  .then((response) => handleResponse(response))
55
- .catch((error) => handleResponse(error));
55
+ .catch((error) => handleResponse(error, true));
56
56
 
57
- function handleResponse(response) {
57
+ function handleResponse(response, isError = false) {
58
58
  let status = "succeeded";
59
- let data = JSON.stringify(response);
60
- if (response.data.error) {
59
+ let data;
60
+
61
+ if (isError) {
62
+ status = "failed";
63
+ data = JSON.stringify({ error: response.message || response });
64
+ } else if (response.data?.error) {
61
65
  status = "failed";
62
66
  data = JSON.stringify(response.data);
67
+ } else {
68
+ data = JSON.stringify(response);
63
69
  }
64
70
 
65
71
  const requestProgress = {
@@ -80,12 +86,14 @@ class OpenAIDallE3Plugin extends ModelPlugin {
80
86
  let progress =
81
87
  requestDurationEstimator.calculatePercentComplete(callid);
82
88
 
89
+ if (typeof progress === 'number' && !isNaN(progress) && progress >= 0 && progress <= 1) {
83
90
  await publishRequestProgress({
84
91
  requestId,
85
92
  status: "pending",
86
93
  progress,
87
94
  data,
88
95
  });
96
+ }
89
97
 
90
98
  if (state.status !== "pending") {
91
99
  break;
@@ -31,8 +31,7 @@ class OpenAIVisionPlugin extends OpenAIChatPlugin {
31
31
  }
32
32
 
33
33
  if (typeof parsedItem === 'object' && parsedItem !== null && parsedItem.type === 'image_url') {
34
- parsedItem.image_url.url = parsedItem.url || parsedItem.image_url.url;
35
- return parsedItem;
34
+ return {type: parsedItem.type, image_url: {url: parsedItem.url || parsedItem.image_url.url}};
36
35
  }
37
36
 
38
37
  return parsedItem;
@@ -16,19 +16,53 @@ class ReplicateApiPlugin extends ModelPlugin {
16
16
  prompt,
17
17
  );
18
18
 
19
- const requestParameters = {
20
- input: {
21
- aspect_ratio: "1:1",
22
- output_format: "webp",
23
- output_quality: 80,
24
- prompt: modelPromptText,
25
- //prompt_upsampling: false,
26
- //safety_tolerance: 5,
27
- go_fast: true,
28
- megapixels: "1",
29
- num_outputs: combinedParameters.numberResults,
30
- },
19
+ const isValidSchnellAspectRatio = (ratio) => {
20
+ const validRatios = [
21
+ '1:1', '16:9', '21:9', '3:2', '2:3', '4:5',
22
+ '5:4', '3:4', '4:3', '9:16', '9:21'
23
+ ];
24
+
25
+ return validRatios.includes(ratio);
31
26
  };
27
+
28
+ let requestParameters = {};
29
+
30
+ switch (combinedParameters.model) {
31
+ case "replicate-flux-11-pro":
32
+ requestParameters = {
33
+ input: {
34
+ aspect_ratio: combinedParameters.aspectRatio || "1:1",
35
+ output_format: combinedParameters.outputFormat || "webp",
36
+ output_quality: combinedParameters.outputQuality || 80,
37
+ prompt: modelPromptText,
38
+ prompt_upsampling: combinedParameters.promptUpsampling || false,
39
+ safety_tolerance: combinedParameters.safety_tolerance || 3,
40
+ go_fast: true,
41
+ megapixels: "1",
42
+ width: combinedParameters.width,
43
+ height: combinedParameters.height,
44
+ size: combinedParameters.size || "1024x1024",
45
+ style: combinedParameters.style || "realistic_image",
46
+ },
47
+ };
48
+ break;
49
+ case "replicate-flux-1-schnell":
50
+ requestParameters = {
51
+ input: {
52
+ aspect_ratio: isValidSchnellAspectRatio(combinedParameters.aspectRatio) ? combinedParameters.aspectRatio : "1:1",
53
+ output_format: combinedParameters.outputFormat || "webp",
54
+ output_quality: combinedParameters.outputQuality || 80,
55
+ prompt: modelPromptText,
56
+ go_fast: true,
57
+ megapixels: "1",
58
+ num_outputs: combinedParameters.numberResults,
59
+ num_inference_steps: combinedParameters.steps || 4,
60
+ disable_safety_checker: true,
61
+ },
62
+ };
63
+ break;
64
+
65
+ }
32
66
 
33
67
  return requestParameters;
34
68
  }
@@ -112,11 +112,10 @@ test('Cortex special properties conversion', async (t) => {
112
112
  ]}
113
113
  ];
114
114
 
115
- const parsedOpenAI = openai.tryParseMessages(cortexMessages);
116
- const { system: claudeSystem, modifiedMessages: claudeMessages } = await claude.convertMessagesToClaudeVertex(parsedOpenAI);
115
+ const { system: claudeSystem, modifiedMessages: claudeMessages } = await claude.convertMessagesToClaudeVertex(cortexMessages);
117
116
 
118
- const { modifiedMessages: geminiMessages } = gemini.convertMessagesToGemini(parsedOpenAI);
119
- const { modifiedMessages: geminiMessages15, system: geminiSystem15 } = gemini15.convertMessagesToGemini(parsedOpenAI);
117
+ const { modifiedMessages: geminiMessages } = gemini.convertMessagesToGemini(cortexMessages);
118
+ const { modifiedMessages: geminiMessages15, system: geminiSystem15 } = gemini15.convertMessagesToGemini(cortexMessages);
120
119
 
121
120
  // Check Claude conversion
122
121
  t.true(claudeMessages[0].content[1].source.data.startsWith('/9j/4AAQ'));
@@ -142,10 +141,9 @@ test('Mixed content types conversion', async (t) => {
142
141
  ]}
143
142
  ];
144
143
 
145
- const parsedOpenAI = openai.tryParseMessages(mixedMessages);
146
- const { system: claudeSystem, modifiedMessages: claudeMessages } = await claude.convertMessagesToClaudeVertex(parsedOpenAI);
147
- const { modifiedMessages } = gemini.convertMessagesToGemini(parsedOpenAI);
148
- const { modifiedMessages: modifiedMessages15, system: system15 } = gemini15.convertMessagesToGemini(parsedOpenAI);
144
+ const { system: claudeSystem, modifiedMessages: claudeMessages } = await claude.convertMessagesToClaudeVertex(mixedMessages);
145
+ const { modifiedMessages } = gemini.convertMessagesToGemini(mixedMessages);
146
+ const { modifiedMessages: modifiedMessages15, system: system15 } = gemini15.convertMessagesToGemini(mixedMessages);
149
147
 
150
148
  // Check Claude conversion
151
149
  t.is(claudeMessages.length, 3);